delegate task用asyncio.shield保护in-flight工具调用不被取消打断(issue #189 grill定案) #189
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
来源
全量32条ADR设计合理性对抗审查(评估侧内部执行,2026-08-21,组G)grill定案。完整推理链条见 ADR-0020 2026-08-21(issue #189 grill)更新节。
结论
用
asyncio.shield()保护正在执行中的工具调用,不被task.cancel()从中打断。核实确认:
DelegatedTaskRegistry.cancel()(delegate_task.py:75)调用真正的asyncio.Task.cancel(),可在subagent.py::run_delegated_task循环体内任意 await 点(含call_host_tool工具调用执行中途)抛出CancelledError,没有协作式检查点。子智能体工具集完全由host通过get_tools注入,零host接入意味着当前实际工具集是空集,ADR-0019"给用户加道具"这类副作用工具目前纯属假设性举例——但 issue #188(已合并)新增的"真人活跃"自动抢占大概率复用同一条取消路径,且不经模型识别、drive_tick周期性运行暴露窗口更大,"取消撞上工具调用执行中"这个场景的触发概率会实质性上升——现在就把保护机制设计好,不等真实副作用工具出现。What to build
subagent.py::run_delegated_task第145行:改为:
task.cancel()触发时,CancelledError在这个await点仍会立刻传给外层循环(循环/任务整体正确识别取消、停止继续),但被shield保护的call_host_tool(...)协程本身会在后台跑完,不会被从中打断——确保副作用(若有)完整生效而非半途而废。取消发生时该次工具调用的返回值不会被写入context/不影响蒸馏结果,只保护副作用执行完整,不保证结果被使用。核心收益:不需要host配合(工具不需要标记"是否有副作用",与
tool_port.py"core不理解工具语义"的既有哲学一致),也不需要重新设计取消入口(cancel_delegate_task与 issue #188 的自动触发都不用改)。Acceptance criteria
subagent.py::run_delegated_task的call_host_tool调用改用asyncio.shield()包裹task.cancel()打断,断言该工具调用本身完整跑完(不是被中途abort),但外层run_delegated_task正确抛出/传播CancelledError、不再继续下一轮llm_client.complete()调用期间)时行为不变(不需要shield保护,因为那里没有外部副作用)call_host_tool内部若真实抛出非取消类异常(工具调用失败),asyncio.shield不影响既有"失败即一次普通tool_response"的处理逻辑(回归测试)Not in scope
llm_client.complete()两处)的取消行为——那两处没有外部副作用,不需要保护asyncio.shield对全部工具调用一视同仁,不需要区分cancel_delegate_task工具本身或 issue #188 的自动抢占触发逻辑——本票只改工具调用被中断时的行为,不改"何时触发取消"占位标题-稍后回填-11to 评估:task.cancel()可能中断已生效副作用工具调用(ADR-0019/0020,全ADR对抗审查组G⑥)评估:task.cancel()可能中断已生效副作用工具调用(ADR-0019/0020,全ADR对抗审查组G⑥)to delegate task用asyncio.shield保护in-flight工具调用不被取消打断(issue #189 grill定案)