You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
摘要
#887 报告子代理(subagent spawn)会话中工具调用确定性失败:
tool/call事件里 name 与 callId 为空串,执行报unknown tool "",而同一环境下主循环工具调用完全正常。源码核查结论:子代理没有任何独立的流式传输或工具调用装配路径——spawn 提供器(dsh-subagent-spawn-in-process)与主循环共用startInProcessRun→ 同一 agent factory → 同一dsh-llm-deepseekSSE 装配器;tool/call事件的 name/callId 直接取自装配器的 block(dsh-agent-loopL120-128、L293-304,无子代理分支)。因此丢失只能发生在共享装配点——即dsh-llm-deepseek/lib/index.jsL321-322 的!== void 0守卫允许空字符串 delta 覆盖首块 id/name 的缺陷(#885 已定位)。子代理独有的触发面:子代理请求携带的工具集更大(常规工具 +structured_output捕获工具),兼容网关在多工具 delta 流中更容易以空串占位续块,覆盖行为在子代理流中确定性触发;主循环单工具流恰好不触发。复现步骤
tool/call事件:name=""、callId="";执行结果unknown tool ""(子代理会话的流式工具调用丢失 name 与 callId,执行报 unknown tool "" #887:三次复现确定性失败)。根因(源码定位,rc.6)
dsh-subagent-spawn-in-process/lib/index.jsL33-35start()→startInProcessRun(request, {})(与 fork 提供器同一驱动);驱动内部parent.ctx.agents.create(...)创建子 agent,LLM 适配器与主循环相同——不存在子代理专属的流式/装配代码。dsh-agent-loop/lib/index.jsL120-128exec = { callId: block.id, name: block.name }、L293-304session.append("tool/call", { ..., callId: block.id, name: block.name })——事件里的空值必然来自装配器产出的 block,而非事件层丢失。dsh-llm-deepseek/lib/index.jsL321-322:!== void 0不排除空串:续块若带id:""/name:""([Bug Report] llm-deepseek SSE 装配用 `!== void 0` 判空:空字符串 delta 覆盖首块 tool_calls id/name,工具调用整体崩溃为 `unknown tool ""` #885 已证实的兼容网关行为),会覆盖首块值。structured_output,见dsh-subagent-in-process-driverL49-53 的注册),多工具 delta 流的网关分块模式不同(续块对工具 0 发空串占位),覆盖必然发生;主循环单工具流首块即带 id/name 且无
续块覆盖,恰好不触发。这也解释了 子代理会话的流式工具调用丢失 name 与 callId,执行报 unknown tool "" #887"主循环正常、子代理必失败"的对照。
建议修复
方案 A(推荐)· 修共享装配守卫(同 #885 方案 A):空串视为缺失:
一处修复同时覆盖主循环与子代理两条触发面(#885/#887 同源)。
方案 B · 装配后校验 + 明确报错:块结束时若 callId/name 为空,抛出带网关与
块索引的明确错误(而不是静默产出空名工具调用),便于定位网关问题。
方案 C(子代理侧兜底)· 事件层防御:
tool/call发射前若 name/callId 为空,记录 warn 并跳过该调用(避免把空名请求打进工具注册表)——防御性,不替代 A。
影响
表现为误导性的
unknown tool ""环境
dsh-subagent-spawn-in-process、dsh-subagent-in-process-driver、dsh-agent-loopL293-304、dsh-llm-deepseekL321-322;Node v24.16.0,Windows 11)验证材料
(agent-loop L120-128/L293-304)、装配守卫(llm-deepseek L321-322)、子代理
多工具流差异(driver L49-53)
同源呼应;修复方案 A 一处覆盖两报告
First source-located analysis of discussion #887 (sibling of #885). Happy to open a PR with fix option A covering both.
All reactions