feat(scheduler): M2 调度器骨架(就绪队列 + 选择函数 + 快照 + 任务级 panic 隔离)

设计依据 docs/zh/input-scheduler-design.md §14 M2。

- 新增 scheduler.go:四级 Level 常量(默认 L1,显式才是特权)、
  Task/TaskKind、scheduler(有界队列/running/统计)、纯函数 pickTaskIndex
  (排序键 -Level → EnqueuedAt → ID)、schedulerLoop/pumpInbox/executeTask、
  DumpScheduler 原子快照
- eventLoop 退场,职责由 schedulerLoop 承担;M2 全部任务为 L1,
  因而行为等价于原先的 channel FIFO
- 每任务 panic 隔离(不变量 I6):panic 只失败该任务,调度器存活,
  取代原先「重启整个循环」
- Start() 改起 schedulerLoop;interceptLoop 暂不动(M3 重写)
- 新增 scheduler_test.go:Q1 排序 4 组、Q4 背压、生命周期、K1 panic 隔离、
  O1 快照一致性、Level 取值契约
- 验收:agent 全量 + -race 通过
This commit is contained in:
JianFeeeee
2026-09-12 23:49:55 +08:00
parent 11e5aed3f2
commit d39e8d8746
4 changed files with 514 additions and 20 deletions

View File

@ -109,6 +109,10 @@ type Agent struct {
// 高优先级打断通道:interceptLoop 注入,process() 在工具循环轮次间非阻塞读取
interceptCh chan *agentIO.InputEvent
// 输入调度器:就绪队列、任务抽象与快照(见 scheduler.go)。
// M2 起取代 eventLoop 的隐式 channel 排队。
sched *scheduler
// 进行中的 LLM 请求取消函数,interceptLoop 可调用以在请求中打断
cancelLLM context.CancelFunc
llmMu sync.Mutex
@ -298,6 +302,7 @@ func New(cfg AgentConfig) *Agent {
selfInputCh: make(chan selfInputMsg, 64),
childTasks: make(map[string]*childTaskState),
interceptCh: make(chan *agentIO.InputEvent, 64),
sched: newScheduler(256),
pluginHealth: newPluginHealthTracker(),
thinkingEnabled: cfg.ThinkingEnabled,
inputCfg: cfg.InputProcessing,
@ -315,7 +320,7 @@ func New(cfg AgentConfig) *Agent {
func (a *Agent) SetSkillIndexProvider(p SkillIndexProvider) { a.skillIndex = p }
func (a *Agent) Start() {
go a.eventLoop()
go a.schedulerLoop()
go a.interceptLoop()
go a.distillLoop()
go a.archiveLoop()