Skip to content

fix: 修复 Agent 流式 tool_call arguments 拼接错误及并行工具调用串扰问题#1355

Open
cyfung1031 wants to merge 9 commits intorelease/v1.4-agentfrom
v1.4-agent-fix-arguments
Open

fix: 修复 Agent 流式 tool_call arguments 拼接错误及并行工具调用串扰问题#1355
cyfung1031 wants to merge 9 commits intorelease/v1.4-agentfrom
v1.4-agent-fix-arguments

Conversation

@cyfung1031
Copy link
Copy Markdown
Collaborator

问题描述

在 Agent Chat 界面中,工具调用的参数(arguments)显示异常,开头出现多余的 {} 前缀,例如:

{}{"description":"Research Bahamut Anime...","prompt":"...","type":"researcher"}

根本原因有两处:

问题一:parseOpenAIStreamif/else if 互斥逻辑(providers/openai.ts

// 原始代码:name 和 arguments 互斥,首个 chunk 若同时携带两者,arguments 被塞进 start 而非 delta
if (tc.function?.name) {
  onEvent({ type: "tool_call_start", toolCall: { arguments: tc.function.arguments || "" } });
} else if (tc.function?.arguments) {
  onEvent({ type: "tool_call_delta", ... });
}

部分 API 网关(OpenRouter、Azure 某些部署、本地 vllm)在首个 chunk 中会同时携带 namearguments: "{}"(占位符)。tool_call_start 携带 "{}" 后,后续真实 JSON 通过 tool_call_delta 追加,最终 "{}" + '{"description":...}' = '{}{...}',与截图完全吻合。

问题二:tool_call_deltalength-1 匹配(多处 consumer)

background_session_manager.tsChatArea.tsxsub_agent_service.ts 中处理 tool_call_delta 时,均使用 toolCalls[toolCalls.length - 1] 来找目标工具,而非按 id 配对。OpenAI 并行返回多个 tool_call 时(用 index 区分),交错到达的 delta 会被写入错误的工具。

另外,Anthropic parser 的 tool_call_delta 固定 emit id: "",导致按 id 配对完全失效。


变更内容

src/app/service/agent/core/types.ts

  • LLMStreamEventtool_call_delta 新增可选字段 index?: number,用于并行工具调用的精确匹配

src/app/service/agent/core/providers/openai.ts

  • if/else if 改为两个独立的 iftool_call_startarguments 永远为空字符串
  • 首个 chunk 携带的 arguments 同样作为 tool_call_delta 发出
  • tool_call_delta 透传 tc.index,供 consumer 精确匹配

src/app/service/agent/core/providers/anthropic.ts

  • 新增 toolUseByIndex: Map<number, { id: string }> 追踪每个 content_block 的 index 与 id 对应关系
  • input_json_delta 发出的 tool_call_delta 现在携带正确的 idindex(原来 id 固定为 ""
  • content_block_stop 时清理对应 index 条目

src/app/service/agent/service_worker/background_session_manager.ts

  • tool_call_delta 匹配逻辑改为:按 id 精确匹配 → 按 index 匹配 → fallback 最近 status=running 的工具

src/pages/options/routes/AgentChat/ChatArea.tsx

  • 子代理 tool_call_delta 分支采用相同的三级匹配逻辑,替换原 length-1 写法

src/app/service/agent/service_worker/sub_agent_service.ts

  • runSubAgentCoretool_call_delta 分支同上,采用三级匹配逻辑

测试更新

  • openai.test.ts:新增并行 tool_call 按 index 分派测试;更新两个因 parser 行为变更而需调整断言的旧测试(event 数量 +1,tool_call_start.arguments 改为断言空字符串)
  • anthropic.test.ts:新增 input_json_delta 携带正确 id 和 index 的测试
  • background.test.ts:新增并行 tool_call 交错 delta 按 index 正确分派的测试

不受影响的文件

  • src/types/scriptcat.d.ts / scriptcat.zh-CN.d.ts:公开给 userscript 的 StreamChunk 接口不含 tool_call_delta,无需修改
  • src/app/service/content/gm_api/cat_agent.tsprocessStream 不处理 tool_call_delta 事件,无需修改
  • 持久化数据结构(ToolCall 类型)不变

cyfung1031 and others added 9 commits April 8, 2026 10:07
* 删除 uint8Array 重复封装

* 添加 ResourceService.loadByUrl 单元测试

---------

Co-authored-by: 王一之 <yz@ggnb.top>
…避免 supply chain 攻击) (#1341)

* pnpm cooldown: 不抓取一星期内最新版

* pnpm: 提升至 10.33.0 以使用 minimumReleaseAge 避免 supply chain 攻击

* minimumReleaseAge 延长至 30 天(43200 分钟)

---------

Co-authored-by: 王一之 <yz@ggnb.top>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant