fix(tools): single ordered driver lane for the sub-dispatch scheduler; validate the cap
Responding to ds-review-bot round 2 on #658 (three critical findings, one warning — all rooted in the pump/commit split racing ordered stages): - ONE driver lane now owns every ordered stage: the start append, prepare (pre-execute/guards), and the head-of-line commit (post-execute, context deferral, settle append). start() is awaited before the next entry can start, so concurrent submissions can no longer run pre-execute pipelines concurrently; only the around-dispatch/body stage overlaps, matching the native loop's fillPool sequencing. - An exclusive call's barrier now holds through its COMMIT: later starts wait for the exclusive pipeline (post-execute included) to finish, the native exclusive-group semantics. - drainDispatches() awaits the driver run itself, so a commit already mid-flight when the program returns is drained before run_code closes the turn — the settle event and deferred contexts land inside it. - maxParallelSubCalls is resolved and validated at construction (positive integer), so direct construction can no longer wedge the pool with 0. New tests: overlapping-submission ordered-prepare, barrier-through-commit, drain-mid-commit, cap rejection. 96 keyless snapshots replay unchanged; Agent Note updated (both languages).
This commit is contained in:
@@ -15,7 +15,7 @@ Status: implemented
|
||||
**一对生命周期事件,一份调度契约,与原生共用。**
|
||||
|
||||
- **事件对**:`tool/code-dispatch-start`(父/子 id、名称、规范化参数)在调度器真正启动某个调用时才追加,而非在提交时,因此因 run 结算而被放弃的排队调用不会留下任何日志。既有的 `tool/code-dispatch` 结算该事件对(`subCallId` 相同);每个已启动的调用恰好结算一次(中止也会作为 `isError` 结果经由流水线结算)。计时即这两个事件的 `time` 字段。两个事件都保持仅日志;模型上下文不受影响;格式保持 v0。
|
||||
- **桥接层调度器**:已提交的调用在提交那一刻就经 `registry.executionMode` 分类(与 loop 所用完全相同的 fail-closed `isConcurrencySafe` 契约),并严格按提交顺序启动。连续被分类为可并行的调用可以重叠执行,上限为 `maxParallelSubCalls`(经校验的注册表 `Config` 字段,默认值 10,即 loop 调度器自身的默认值;设为 `1` 即恢复串行分发);独占调用则先排空池、独自运行,并阻挡其后的调用。这是把 loop 的分组语义适配到另一种场景:调用随时间陆续到达,而非作为单个已解析的批次一次性到达。run 结算时会中止仍在运行的分发,并放弃已排队未启动的分发(绑定调用被拒绝,不产生事件),随后排空到完全停稳,之后外层结果才结束该轮次。
|
||||
- **桥接层调度器**:已提交的调用在启动那一刻经 `registry.executionMode` 分类(与 loop 所用完全相同的 fail-closed `isConcurrencySafe` 契约),并严格按提交顺序启动。所有有序阶段——start 事件追加、`prepare`(pre-execute/守卫)、队首 `finalize`/`finish` 提交(post-execute + 上下文延迟提交 + settle 事件追加)——由单一驱动车道独占执行,因此有序策略阶段彼此绝不重叠,只有 around-dispatch/工具体阶段并发运行,与原生 loop 的时序完全一致(`fillPool` 先 await `startCall` 再 `commitReady`)。连续被分类为可并行的调用可以重叠执行,上限为 `maxParallelSubCalls`(`Config` 字段,Loader schema 校验之外直接构造时也重新校验,默认值 10,即 loop 调度器自身的默认值;设为 `1` 即恢复串行分发);独占调用则先排空池、独自运行,且其屏障保持到自身提交(含 post-execute)完成为止,与原生独占分组一致。run 结算时会中止仍在运行的分发,并放弃已排队未启动的分发(绑定调用被拒绝,不产生事件),随后排空到完全停稳——包括程序返回时已在途的提交——之后外层结果才结束该轮次。
|
||||
- **client 侧**:`CodeSubCall` 拓宽为 `RunningToolCall | ToolResultNode`:start 事件把运行中形状写入分发索引(行组件从该形状推导出运行指示环,与原生运行中的调用处理完全一致),其结算事件则原位替换该条目,即使并行完成也保持启动顺序不变,并把 start 事件的 `time` 作为 `callTime`(时长来源)带入。未观察到对应 start 的结算事件(窗口切在事件对中间,或日志录制于 start 事件引入之前)会直接追加,因此旧日志仍能照常渲染。
|
||||
- **SDK 提示词**:面向模型的「调用按顺序执行」一句替换为真实契约(相互独立的安全调用可以在 `Promise.all` 下重叠执行;相互依赖的工作以 `await` 顺序衔接);这是模型可见的变更,每一份 code-mode 快照都已重新录制。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user