实现行为树执行器、任务协调和技能接口

This commit is contained in:
2026-09-20 12:18:52 +08:00
commit 492676344a
143 changed files with 13010 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
"""Advisory temporal state only; never supplies manipulation completion proof."""
import math,statistics
from collections import deque
class ProgressMonitor:
def __init__(self,run_id,subtask_id,capture_after,max_age=2.,stall_seconds=10.,regression=.15):
if not run_id or not subtask_id or any(not math.isfinite(x) for x in (capture_after,max_age,stall_seconds,regression)) or min(max_age,stall_seconds,regression)<=0:raise ValueError('invalid monitor policy')
self.run_id=run_id;self.subtask_id=subtask_id;self.capture_after=capture_after;self.max_age=max_age;self.stall_seconds=stall_seconds;self.regression=regression
self.sequence=0;self.last_stamp=None;self.samples=deque(maxlen=3);self.peak=None;self.improved=None;self.filtered=None;self.regressions=0;self.last=None
def unknown(self,reason):return dict(state='UNKNOWN',reason=reason,completion_authority=False,run_id=self.run_id,subtask_id=self.subtask_id)
def update(self,s,now):
value=s.get('progress');stamp=s.get('stamp');seq=s.get('sequence')
if s.get('run_id')!=self.run_id or s.get('subtask_id')!=self.subtask_id:return self.unknown('identity mismatch')
if type(seq) is not int or seq<=self.sequence or type(value) not in (int,float) or not math.isfinite(value) or not 0<=value<=1:return self.unknown('invalid progress/sequence')
if type(stamp) not in (int,float) or not math.isfinite(stamp) or not math.isfinite(now) or not self.capture_after<=stamp<=now or now-stamp>self.max_age or (self.last_stamp is not None and stamp<=self.last_stamp):return self.unknown('stale or nonmonotonic observation')
if self.last_stamp is not None and stamp-self.last_stamp>self.max_age:
self.samples.clear();self.filtered=None;self.peak=None;self.improved=None;self.regressions=0
self.sequence=seq;self.last_stamp=stamp;self.samples.append(value)
median=statistics.median(self.samples);self.filtered=median if self.filtered is None else .5*median+.5*self.filtered
if self.peak is None or self.filtered>=self.peak+.02:self.peak=self.filtered;self.improved=stamp
self.regressions=self.regressions+1 if self.peak-self.filtered>=self.regression else 0
state='REGRESSED' if self.regressions>=2 else 'STALLED' if stamp-self.improved>=self.stall_seconds else 'RUNNING'
self.last=dict(state=state,run_id=self.run_id,subtask_id=self.subtask_id,sequence=seq,stamp=stamp,raw_progress=value,progress=self.filtered,hop=s.get('hop'),completion_authority=False)
return dict(self.last)
def snapshot(self,now):
if self.last_stamp is None or now<self.last_stamp or now-self.last_stamp>self.max_age:return self.unknown('feedback unavailable')
return dict(self.last)