[Bug] 工具调用 name 被空字符串覆盖,导致 "unknown tool \"\"" 和 HTTP 400 INVALID_REQUEST #2987
Programmer-Red
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
现象
模型发起了工具调用,但 dsh 最终拿到的工具名是空字符串,于是工具执行报
Error: unknown tool "";紧接着下一轮请求被 DeepSeek API 拒绝,报DeepSeek API error (HTTP 400) INVALID_REQUEST。关键日志
{"type":"assistant/chunk","seq":64,"time":1786931762091,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_fd8873c8cfe64b3783d426f9","name":"str_replace_editor","argumentsDelta":""}}} {"type":"tool-call-chunks","seq0":65,"time0":1786931762169,"data":{"turn":1,"step":1,"index":1,"dt":[115,23,18,6],"id":"call_00_repair65","name":"","args":["{","\"command\": \"view\"",", \"path\": \"/Users","/ak","ared"]}} {"type":"tool-call-chunks","seq0":70,"time0":1786931763466,"data":{"turn":1,"step":1,"index":1,"dt":[2,1,0],"id":"call_00_repair70","name":"","args":["/tools/d","eepseek","-h","arness\"}"]}} {"type":"assistant/chunk","seq":74,"time":1786931763496,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user is asking about a warning message they see when running `pnpm dsh web`. The warning says:\n\n```\n(node:66598) ExperimentalWarning: SQLite is an experimental feature and might change at any time\n```\n\nThis is a Node.js warning about the built-in SQLite module being experimental. Let me look at the codebase to understand if this is something we should address or suppress.\n\nLet me first check the structure of the project."}}}} {"type":"assistant/chunk","seq":75,"time":1786931763497,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_repair75","name":"","arguments":"{\"command\": \"view\", \"path\": \"/Users/***/tools/deepseek-harness\"}"}}}} {"type":"assistant/chunk","seq":76,"time":1786931763497,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":5699,"outputTokens":166,"cacheReadTokens":0,"reasoningTokens":91}}}} {"type":"assistant/chunk","seq":77,"time":1786931763498,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":78,"time":1786931763501,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"reasoning","text":"The user is asking about a warning message they see when running `pnpm dsh web`. The warning says:\n\n```\n(node:66598) ExperimentalWarning: SQLite is an experimental feature and might change at any time\n```\n\nThis is a Node.js warning about the built-in SQLite module being experimental. Let me look at the codebase to understand if this is something we should address or suppress.\n\nLet me first check the structure of the project."},{"type":"tool-call","id":"call_00_repair79","name":"unknown","arguments":"{\"command\": \"view\", \"path\": \"/Users/***/tools/deepseek-harness\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"c3670df2-20d8-4728-9af1-bc98ae08cb71"},"usage":{"inputTokens":5699,"outputTokens":166,"cacheReadTokens":0,"reasoningTokens":91}},"sourceEventSeqs":[13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77],"surfaceOp":"append"} {"type":"tool/call","seq":79,"time":1786931763508,"data":{"turn":1,"step":1,"callId":"call_00_repair79","name":"unknown","arguments":"{\"command\": \"view\", \"path\": \"/Users/***/tools/deepseek-harness\"}"}} {"type":"tool/result","seq":80,"time":1786931763575,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"call_00_repair79"},"content":[{"type":"tool-result","toolCallId":"call_00_repair79","content":[{"type":"text","text":"Error: unknown tool \"\""}],"isError":true}],"role":"user","id":"c2364d5b-c311-4e9b-94bb-360615439a54"},"error":{"name":"ToolNotFoundError","code":"UNKNOWN_TOOL"}},"sourceEventSeqs":[79],"surfaceOp":"append"} {"type":"step/end","seq":81,"time":1786931763576,"data":{"turn":1,"step":1}} {"type":"step/start","seq":82,"time":1786931763584,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":83,"time":1786931763761,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"error","failure":{"message":"DeepSeek API error (HTTP 400)","code":"INVALID_REQUEST","status":400}}}}}原因
packages/llm/llm-deepseek/src/translate.ts第 160 行:这个判断只排除
undefined(不存在),不排除空字符串""。本日志中:seq 64:DeepSeek 流式返回第一句,name = "str_replace_editor",正确;seq 65+:后续分句携带name = ""(空字符串),它不是undefined,于是这行代码用空字符串覆盖了第一句存下的正确工具名;seq 75:工具调用块组装完成,name = "";seq 80报Error: unknown tool "";serialize.ts把这个name:""的 assistant 消息原样发回 DeepSeek,服务端校验失败,seq 83报HTTP 400 INVALID_REQUEST。建议修复
在
translate.ts中只在工具名是非空字符串时才覆盖:同时在
serialize.ts序列化时过滤/拒绝name为空的工具调用块All reactions