fix(agent): 恢复流式工具参数截断检测 + 空参数告警,强化 execute_code 描述 - #560
Conversation
…ol args Two server-side fixes for tool-call argument handling, follow-up to the research-paper-writing SKILL.md doc fix. Both address the "No code supplied" failure class where the model's tool-call arguments go missing. 1. Re-enable streaming truncation detection (the "third option" from mateaix#557). sanitizeToolCallArguments previously replaced ANY invalid/blank arguments with "{}" at the stream-aggregation point (buildFinalToolCalls). Because "{}" is valid JSON, the tool executor's truncation detector (ToolExecutionExecutor JSON pre-validation -> "shorten and retry" guidance) never fired on the streaming path — it was dead code, and the model only ever saw a generic per-tool "missing argument" error. Now the two call sites behave differently: - Stream aggregation (buildFinalToolCalls): a truncated/invalid fragment is passed through verbatim so the executor detects the truncation and returns the model actionable "shorten and retry" guidance. Blank args still become "{}" but are now logged (previously silent — an observation blind spot). - Outbound chokepoint (normalizeToolCallArguments): unchanged — history tool calls are still harmonized to "{}" before every provider request, so strict providers (aliyun-codingplan) never get HTTP 400. The persisted fragment is re-normalized on the next send, so history stays protected. 2. Strengthen the execute_code tool description so coding-plan models stop omitting the required "code" parameter (the 80% model-side root cause in mateaix#557's production-log analysis): an explicit IMPORTANT warning in the @tool description plus a stronger "code" parameter description. Tests: updated the aggregation truncation test to expect raw pass-through, and added a chokepoint test locking in that replayed truncated args still normalize to "{}". All 6 NodeStreamingChatHelperToolCallArgsTest cases pass; CodeExecuteTool and SkillScriptExecutionService code tests unaffected. Refs: mateaix#557
评审:实现正确,可合;一条非阻塞备注按 #557 评论中「第三选项」的四个验证面逐点核查: 1. 行为分离正确 ✅
2. 架构前提成立 ✅ 3. 安全声明属实 ✅
4. 测试迁移完整 ✅ 非阻塞备注:截断指引的模式匹配有覆盖缺口
上线后建议按 #557 的三条验收标准回看同窗口日志。 |
…d) JSON Address PR mateaix#560 review note (non-blocking): the JSON pre-validation gate in ToolExecutionExecutor.execute relied on normalizeToolExecutionError, which pattern-matches the parser message to detect truncation. A mid-token cut hits "Unexpected end-of-input" (covered), but a malformed fragment like {"a":} produces "Unexpected character ..." which is NOT in the pattern table — so the model got a generic error instead of the actionable "shorten and retry" guidance. Since that gate wraps only readTree(arguments), ANY exception reaching it is a JSON parse failure whose remedy is always "re-emit the call". So: - Extract the guidance into a TRUNCATED_ARGS_GUIDANCE constant. - The pre-validation gate now returns it unconditionally (no message guessing), closing the gap for every malformation phrasing. - normalizeToolExecutionError keeps pattern-matching for the genuine tool-execution error sites (parallel/single-tool catch blocks), which have many unrelated causes; it now reuses the same constant. Made package-private static for direct unit testing (same style as capToolCalls). Add ToolExecutionExecutorTruncationGuidanceTest: guidance is actionable, the gate covers malformed fragments the pattern table misses, and pattern regression for the other call sites (covered messages, generic fall-through, workspace path violation, null handling). Refs: mateaix#557
非阻塞备注已落实(commit
|
背景
#557 的后续修复(服务端参数处理 + 模型引导),与文档修复 PR #559 分离为独立关注点。
#557 的生产日志定性显示
No code supplied失败有两个并列根因:code(如{"language":"python"}){}本 PR 同时针对这两点。
改动
1. 恢复流式截断检测(#557 评论里的「第三选项」)
sanitizeToolCallArguments此前在流式聚合点(buildFinalToolCalls)把任何非法/空白参数都替换成{}。由于{}是合法 JSON,工具执行器的截断检测(ToolExecutionExecutorJSON 预校验 → 「缩短重发」指引)在流式路径上从不触发——是死代码,模型只能收到笼统的「缺参数」错误。现在两个调用点行为分离:
buildFinalToolCalls,aggregationPoint=true){}但新增 WARN(此前静默,是观测盲区)normalizeToolCallArguments,aggregationPoint=false){},aliyun-codingplan 等严格 provider 不会 HTTP 400。持久化的片段在下次出站时被重新归一,历史保护不变安全性(已核实):执行器在 ToolGuard 与实际执行之前就拦下非法 JSON,透传的片段永远不会被执行;
cacheReasoningContent/ConversationWindowManager/ToolLoopGuard等下游消费者只用id或带 try/catch,不受影响。2. 强化
execute_code工具描述(治 80% 模型端诱因)coding-plan 类模型对长
code参数有省略倾向。在@Tooldescription 追加显式IMPORTANT警告,并强化code参数说明(schema 层@JsonPropertyDescription同步),直接干预模型行为。测试
{}){}(保护不变)NodeStreamingChatHelperToolCallArgsTest6 例全过;CodeExecuteTool*Test、SkillScriptExecutionServiceCodeTest不受影响验收标准(上线后同窗口日志)
No code supplied频次显著下降{}——每次参数异常都有带 toolName 的 WARN 可查execute_code失败样本中「有 language 缺 code」占比下降改动范围
关联文档修复:#559