Commit Graph

3 Commits

Author SHA1 Message Date
cb32032f76 feat(scheduler)!: 中断/排队两类别模型 + 插件声明 L1-L3、L4 内核独占
用户澄清推翻了早期设计的三处前提,本提交按新模型重做调度核心(行为有意变化):

1) 类别由注入 API 决定,与通道名无关
   - InjectInterrupt*                      -> TaskInterrupt(带级别,可被严格更高级中断打断)
   - InjectText*/InjectInputSync*/内核自循环 -> TaskQueued(无级别,可被任何中断打断)
   - 删除按通道名推断的 taskLevel():qq 走 InjectInterruptTextOpts,本就是中断

2) 级别只属于中断
   - 插件在 InjectOptions.Priority 声明 L1-L3(空/非法降级 L1,声明 L4 夹到 L3)
   - L4 内核独占:新增 raiseKernelInterrupt(panic / selfip);requestKernelPreempt 不夹取
   - panic 现在产生一条带 kernel 标记的 L4 中断;L4 自身 panic 不再产生新 L4(防自我放大)

3) 选择结构:四容器固定次序,删除统一比较器
   - immediate(抢占者立即运行)-> 中断队列 L4..L1 -> 栈顶(与队头比级别) -> 排队 FIFO
   - 删除 pickTaskIndex/taskBefore 与“同级 pending 优先”补丁(根因是抢占者进了队列)
   - 中断栈上界改为结构推论 = 4(= 中断级数);删除“超限转 pendingInterrupts”降级

公开 SDK(feature 分支有意新增,纯追加):InjectOptions.Priority + PriorityL1/2/3;
内核 io / proc 桥 / 插件模板同步透传。

设计稿 §2/§3/§4.1/§6.3/§9/§11/§12/§13/§15 按新模型重写。

验收:go build/vet 干净;go test ./... 37 包 ok 0 FAIL;-race 全绿;
e2e(抢占-挂起-恢复)+ 压力(200 排队 + 50 中断,L1/L2/L3 轮转)通过。
2026-09-13 07:00:51 +08:00
d4764e3682 fix(scheduler)!: D1 更正为「中断从上一个任务之前的完整状态开始」,并实现现场合回
用户明确语义(我此前对 D1 的解析就是错的——当时回答里的“A”指的是 git 选项,
D1 实际要的是方案 B):

  中断打断时,上个任务到达以来的所有上下文现场被保护(含 toolcall),
  然后中断在「上个任务前的那个完整状态」上开始运行;
  中断结束后再把被挂起的任务与其上下文现场加载回中断任务之上,并继续运行。

实现:
- 删除 SeedMsgs 与 D1=A 的“只读前缀”机制:中断任务不再继承被打断任务的任何内容,
  它就是普通新任务,正常走完整 prepare(system prompt + timeline + 自己的输入)
- TaskFrame 新增 PrefixLen(基础前缀长度)与 InputBlocks;
  stepPrepare 在 buildMessages 之后记录 PrefixLen
- 新增 rebaseFramePrefix:恢复时重建基础前缀(中断已提交进 a.context,
  重建的 timeline 含中断效果=“加载回中断之上”),再把本任务自己的尾部
  (Stage 上下文 + 工具轮产物 + 占位)接回;并补回 IsInterrupt 标记与多模态块
- resumeTask 在 runTaskSteps 之前调用 rebaseFramePrefix
- 设计稿 §5.3 改写为「已定:D1=B」并写明实现对应;§6.2 补“重建前缀→接回尾部”;
  §12 的 D1 行更新

测试:
- TestPreempt_HigherPreemptsAndResumes 改为断言「中断不继承、恢复后看得见中断内容」
- 新增 TestPreempt_ResumeRebaseRestoresTailDecorations(前缀重建后尾部装饰补回)
- 原 TestPreempt_SeedPathDoesNotLeakInterruptFlag 随之删除(机制已不存在)

验收:agent 全量 + -race;全仓 build/vet 通过
2026-09-13 06:24:20 +08:00
a971fc8877 feat(scheduler): M5 饥饿防护(抢占计数提升有效级 + 抢占冷却)
设计依据 docs/zh/input-scheduler-design.md §9、§11.5(G1/G2)。

- Task 增加 PreemptCount / LastPreemptAt;effectiveLevel(t) =
  min(L4, Level + min(PreemptCount, 2)):被抢占越多越“值钱”,
  逐步追上抢占它的流,但封顶 L4 因而抢不过真正的紧急输入
- 选择函数 taskBefore 改用有效级;requestPreempt 与 preemptGrantedFor
  同样以有效级比较
- 抢占冷却 preemptCooldown=2s:刚被抢占的任务期内不再被抢占,
  避免同一任务被反复打断到永不完结
- 新增 scheduler_starvation_test.go 4 项:提升与封顶、冷却期内不得再抢占、
  提升后同级不得抢占而更高可、选择函数确实用有效级
- 验收:agent 全量 + -race;全仓 build/vet 通过
2026-09-13 00:38:30 +08:00