[Bug] Responses API rejects requests when a developer/hook message sits between function_call and its function_call_output ("No tool output found for tool call …")
环境
- 客户端:Codex desktop(
originator=codex_work_desktop,cli_version 0.148.0-alpha.9)
- 模型:
deepseek-v4-pro,model_provider 配置 base_url=https://api.deepseek.com/(直连官方接口)
- 平台:macOS
- 触发条件:任意 PostToolUse hook 返回
hookSpecificOutput.additionalContext(本案例为 Codex 插件 Context Guard)
现象
当一次工具调用完成后,PostToolUse hook 注入一条 additionalContext(在会话中成为 role: developer 的消息),且这条消息落在该工具的 function_call 与 function_call_output 之间时,下一轮请求被 /responses 以 HTTP 400 拒绝:
{"error":{"message":"No tool output found for tool call call_00_ET_...","type":"invalid_request_error","param":null,"code":"invalid_request_error"}}
关键点:该 function_call_output 实际存在,且 call_id 完全匹配,只是中间隔了一条 developer 消息。
稳定复现证据(本机 2026-08-17,两次独立会话,100% 复现)
| 会话 |
触发调用 |
报错时间 (UTC) |
call_id |
01a00fff-710a-7602-9d0d-9908bbe0009f |
exec_command → register-proof |
14:02:21 |
call_00_ET_SpXxxavgyEWZu15ec5Tb1552 |
01a01010-7603-7270-b86e-d7d5c425b4ca |
exec_command → register-proof |
14:48:57 |
call_00_ET_TFdb2XvunUqN3AbLMbKD0761 |
两次的事件顺序完全一致(同一毫秒内):function_call → developer 消息(hook 的 additionalContext)→ function_call_output → 下一次请求即 400。
影响
报错后该会话被"毒化":后续所有续接请求都因为同一个孤儿 call_id 被 400 拒绝,线程无法继续,只能新建会话。例如 01a00fff 在 14:04:09 的续接 turn 仅约 1 秒即失败,错误中的 call_id 与 14:02:21 完全一致。
根因判断
DeepSeek 的 /responses 似乎要求 function_call_output 紧跟 function_call(只匹配相邻项),而 OpenAI 的 /responses 按 call_id 配对、允许中间夹带 context 消息(据我们的使用观察与社区报告)。Codex 默认在 PostToolUse hook 注入 additionalContext,因此直连 DeepSeek 时触发。
期望
- 与 OpenAI 语义对齐:按
call_id 匹配 function_call_output,容忍其间的 developer/context 消息;或
- 若该顺序确实非法,请在 API 文档中明确写出顺序约束,并给出客户端可采用的规范化建议(如将 output 重新排序到 call 之后)。
相关社区报告
[Bug] Responses API rejects requests when a developer/hook message sits between
function_calland itsfunction_call_output("No tool output found for tool call …")环境
originator=codex_work_desktop,cli_version 0.148.0-alpha.9)deepseek-v4-pro,model_provider配置base_url=https://api.deepseek.com/(直连官方接口)hookSpecificOutput.additionalContext(本案例为 Codex 插件 Context Guard)现象
当一次工具调用完成后,PostToolUse hook 注入一条 additionalContext(在会话中成为
role: developer的消息),且这条消息落在该工具的function_call与function_call_output之间时,下一轮请求被/responses以 HTTP 400 拒绝:{"error":{"message":"No tool output found for tool call call_00_ET_...","type":"invalid_request_error","param":null,"code":"invalid_request_error"}}关键点:该
function_call_output实际存在,且call_id完全匹配,只是中间隔了一条 developer 消息。稳定复现证据(本机 2026-08-17,两次独立会话,100% 复现)
01a00fff-710a-7602-9d0d-9908bbe0009fexec_command→register-proofcall_00_ET_SpXxxavgyEWZu15ec5Tb155201a01010-7603-7270-b86e-d7d5c425b4caexec_command→register-proofcall_00_ET_TFdb2XvunUqN3AbLMbKD0761两次的事件顺序完全一致(同一毫秒内):
function_call→ developer 消息(hook 的 additionalContext)→function_call_output→ 下一次请求即 400。影响
报错后该会话被"毒化":后续所有续接请求都因为同一个孤儿 call_id 被 400 拒绝,线程无法继续,只能新建会话。例如
01a00fff在 14:04:09 的续接 turn 仅约 1 秒即失败,错误中的 call_id 与 14:02:21 完全一致。根因判断
DeepSeek 的
/responses似乎要求function_call_output紧跟function_call(只匹配相邻项),而 OpenAI 的/responses按 call_id 配对、允许中间夹带 context 消息(据我们的使用观察与社区报告)。Codex 默认在 PostToolUse hook 注入 additionalContext,因此直连 DeepSeek 时触发。期望
call_id匹配function_call_output,容忍其间的 developer/context 消息;或相关社区报告