Skip to content

fix(console): drop non-function tools when converting Responses to chat completions - #42231

Closed
miups wants to merge 1 commit into
anomalyco:devfrom
miups:fix/zen-web-search-tool-conversion
Closed

fix(console): drop non-function tools when converting Responses to chat completions#42231
miups wants to merge 1 commit into
anomalyco:devfrom
miups:fix/zen-web-search-tool-conversion

Conversation

@miups

@miups miups commented Aug 13, 2026

Copy link
Copy Markdown

What

Fixes the tools[N].function: missing field "name" 400 that Codex hits on
/v1/responses (OpenCode Go / Zen) when the upstream model speaks chat
completions instead of native Responses (e.g. deepseek-v4-pro).

Why

Codex always sends a web_search tool on /v1/responses:

{"type":"web_search","external_web_access":true}

It has no name field. toOaCompatibleRequest mapped every tool into
{"type":"function","function":{...}}, so web_search produced an undefined
function.name, which the upstream (DeepSeek) serde rejects with
tools[N].function: missing field "name" and 400s the whole request before
the model even runs.

Reproduced with the real Codex CLI (0.147.0, wire_api = "responses"):
the identical request body succeeds for deepseek-v4-flash (paid tier is
routed to DeepSeek's native /v1/responses) and fails for
deepseek-v4-pro (goes through the chat-completions conversion).

Changes

  • toOaCompatibleRequest: filter out non-function tools (web_search,
    namespaces, ...) before converting to chat completions, since
    chat-completions upstreams have no equivalent for them.
  • Read the function name/description/parameters from both Responses-style
    tools (name at the top level, which Codex actually sends) and
    chat-style tools (name nested under function).
  • Add regression tests using the real Codex /v1/responses tool shape
    (top-level name + namespace + web_search).

Related

…at completions

Codex always sends a web_search tool on /v1/responses, and that tool has no
name field. The oa-compat converter mapped every tool into
{"type":"function","function":{...}}, so web_search produced an undefined
function.name, which upstream serde rejects with
`tools[N].function: missing field "name"` and 400s the whole request (e.g.
deepseek-v4-pro via OpenCode Go). Filter out non-function tools before
converting, and read the function name from either Responses-style
(top-level) or chat-style (nested) tools.

Complements the SSE-lifecycle work in anomalyco#40210.
Copilot AI lite review requested due to automatic review settings August 13, 2026 03:04
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Aug 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Related PRs Found

#40210 - fix(console): emit complete Responses-API SSE lifecycle for converted streams

#41130 - fix(console): preserve anthropic tool names

  • Why related: Addresses tool name handling in a similar context within the console conversion logic.

These are complementary fixes to the same tools conversion system, not duplicates. PR #42231 builds on the existing work to handle additional tool shapes and edge cases that weren't covered before.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the OA-compat (chat-completions) request conversion in packages/console to avoid upstream 400s when /v1/responses-style requests include non-function tool types (notably Codex’s web_search), and adds regression coverage for the real Codex tool shapes.

Changes:

  • Filter out non-type:"function" tools when converting a Responses-shaped request to chat-completions upstream format.
  • Support both Responses-style tool shapes (top-level name/description/parameters) and chat-completions-style tool shapes (function.{name,description,parameters}).
  • Add tests covering Codex’s mixed tool list (function + namespace + web_search) and the “no tools” case.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
packages/console/app/src/routes/zen/util/provider/openai-compatible.ts Filters/normalizes tool conversion for OA-compat chat-completions upstreams.
packages/console/app/test/openaiCompatibleRequest.test.ts Regression tests for Codex /v1/responses tool shapes and tool filtering behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 205 to +209
const tools = Array.isArray(body.tools)
? body.tools.map((tool: any) => ({
type: "function",
function: {
name: tool.name,
description: tool.description,
parameters: tool.parameters,
},
}))
? body.tools
.filter((tool: any) => tool && typeof tool === "object" && tool.type === "function")
.map((tool: any) => ({
type: "function",
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window.

Feel free to open a new pull request that follows our guidelines.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Aug 13, 2026
@github-actions github-actions Bot closed this Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants