fix(console): drop non-function tools when converting Responses to chat completions - #42231
fix(console): drop non-function tools when converting Responses to chat completions#42231miups wants to merge 1 commit into
Conversation
…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.
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
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. |
|
The following comment was made by an LLM, it may be inaccurate: Related PRs Found#40210 -
#41130 -
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. |
There was a problem hiding this comment.
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.
| 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", |
|
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. |
What
Fixes the
tools[N].function: missing field "name"400 that Codex hits on/v1/responses(OpenCode Go / Zen) when the upstream model speaks chatcompletions instead of native Responses (e.g.
deepseek-v4-pro).Why
Codex always sends a
web_searchtool on/v1/responses:{"type":"web_search","external_web_access":true}It has no
namefield.toOaCompatibleRequestmapped every tool into{"type":"function","function":{...}}, soweb_searchproduced an undefinedfunction.name, which the upstream (DeepSeek) serde rejects withtools[N].function: missing field "name"and 400s the whole request beforethe 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 isrouted to DeepSeek's native
/v1/responses) and fails fordeepseek-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.
tools (
nameat the top level, which Codex actually sends) andchat-style tools (
namenested underfunction)./v1/responsestool shape(top-level name + namespace +
web_search).Related
tool.function?.name, this also handles the Responses-style top-levelnamethat Codex sends, and adds tests with the real shape)