Skip to content

fix: preserve Codex Responses-Lite tools (#5103) - #5158

Closed
devonpmack wants to merge 2 commits into
maximhq:mainfrom
devonpmack:dm/fix-codex-responses-lite
Closed

fix: preserve Codex Responses-Lite tools (#5103)#5158
devonpmack wants to merge 2 commits into
maximhq:mainfrom
devonpmack:dm/fix-codex-responses-lite

Conversation

@devonpmack

@devonpmack devonpmack commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Backports the core Codex compatibility fix from #5103 to main, where the release branch still lacks it. This preserves Codex 0.144's additional_tools Responses input item across Bifrost's OpenAI conversion; without it, Bifrost decodes the nested Responses tool union as MCP list-tools data and strips required type discriminators before forwarding the request.

Changes

  • Treat additional_tools like existing Codex tool_search extensions and round-trip it as an opaque Responses item
  • Preserve opaque item bytes when deep-copying Responses messages
  • Add a regression test based on a captured Codex 0.144 request with custom and collaboration namespace tools

Reproduction proof

A request captured directly from @openai/codex@0.144.0 contains this Responses-Lite item:

{
  "type": "additional_tools",
  "role": "developer",
  "tools": [
    { "type": "custom", "name": "exec", "format": { "type": "grammar", "syntax": "lark" } },
    { "type": "namespace", "name": "collaboration", "tools": [{ "type": "function", "name": "spawn_agent" }] }
  ]
}

Before the fix, the regression test reproduced the production failure: Bifrost forwarded those entries as {"name":"exec","input_schema":null} and {"name":"collaboration","input_schema":null}, dropping every required type discriminator. OpenAI then rejected the request with:

Missing required parameter: input[0].tools[0].type

After the fix, the captured item survives Bifrost's Sonic HTTP parser, inbound conversion, deep-copy path, outbound conversion, and provider JSON encoder with the custom, namespace, nested function, and Lark grammar fields intact:

$ go test ./providers/openai -run TestCodexResponsesLiteAdditionalToolsRoundTrip -count=1
ok  github.com/maximhq/bifrost/core/providers/openai  0.402s

Real Codex acceptance test

Built bifrost-http from this branch using the local Go workspace, then ran Codex 0.144 against it with the bundled gpt-5.6-sol catalog metadata (Responses-Lite, tool mode, and multi-agent enabled). The local gateway's OpenAI provider used an upstream raw passthrough endpoint so this branch was the only Bifrost conversion layer.

$ npx -y @openai/codex@0.144.0 exec ... -m gpt-5.6-sol \
    'Review main.go. You must use the collaboration tools to spawn one sub-agent ...'
...
The independent review found the same issue and no others. No files were modified.
tokens used: 11,480
exit status: 0

The run exercised the custom exec grammar, collaboration namespace, sub-agent spawn/wait, streaming responses, and multi-turn collaboration history. The gateway recorded eight POST /openai/v1/responses requests, all HTTP 200, with no parse errors.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

cd core
go test ./schemas ./providers/openai
go test ./schemas -run 'TestResponsesMessageToolCallArguments' -count=1
go test ./providers/openai -run 'TestCodexResponsesLiteAdditionalToolsRoundTrip|TestResponsesInputRoundTripsToolSearchItems' -count=1

The broad go test ./... reaches unrelated MCP integration tests that require generated examples/mcps/test-tools-server/dist/index.js; the packages changed by this PR pass.

Screenshots/Recordings

Not applicable.

Breaking changes

  • Yes
  • No

Related issues

Backports the core fix from #5103, which is already merged on the dev branch. This main backport also covers the opaque-item deep-copy and exact gateway JSON path.

Reproduced from a Codex 0.144 request rejected upstream with Missing required parameter: input[0].tools[0].type.

Security considerations

No auth, secret, or PII changes. The fix preserves an OpenAI-native request extension instead of partially decoding and rewriting it.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Codex 0.144 sends its additional_tools input item through the Responses-Lite path. Preserve that opaque extension across Bifrost request conversion so nested tool discriminators and grammars reach OpenAI unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

ResponsesMessage now preserves Codex opaque items, including additional_tools, through JSON unmarshalling, marshalling, and deep copies. A provider test validates nested tool fields across request conversion.

Changes

Opaque Responses Item Preservation

Layer / File(s) Summary
Opaque item contract and decoding
core/schemas/responses.go
Adds the additional_tools response item type and preserves raw JSON for additional_tools and tool_search_* items while clearing stale receiver state.
Encoding and copy preservation
core/schemas/responses.go, core/schemas/utils.go
Re-emits preserved opaque JSON verbatim and deep-copies the stored raw bytes.
Nested additional_tools round-trip validation
core/providers/openai/codexresponseslite_test.go, core/schemas/responses_test.go
Validates nested tool fields after request conversion and corrects the related opaque-item test comment.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: akshaydeo, danpiths, tejasghatte, roroghost17

Sequence Diagram(s)

sequenceDiagram
  participant OpenAIResponsesRequest
  participant bifrostRequest
  participant DeepCopyResponsesMessage
  OpenAIResponsesRequest->>bifrostRequest: Convert request with additional_tools
  bifrostRequest->>DeepCopyResponsesMessage: Deep-copy input messages
  DeepCopyResponsesMessage-->>bifrostRequest: Return copied opaque item bytes
  bifrostRequest->>OpenAIResponsesRequest: Convert request back
  OpenAIResponsesRequest-->>OpenAIResponsesRequest: Marshal and inspect nested tool fields
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main fix: preserving Codex Responses-Lite tools.
Description check ✅ Passed The description covers summary, changes, testing, impact, related issue context, security, and checklist items, matching the template well.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devonpmack
devonpmack marked this pull request as ready for review July 13, 2026 21:10
@greptile-apps

greptile-apps Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
core/schemas/responses.go Generalizes raw Responses item preservation so additional_tools round-trips with the same opaque handling as Codex tool-search items.
core/schemas/utils.go Copies preserved opaque item bytes when deep-copying Responses messages.
core/providers/openai/codexresponseslite_test.go Adds a round-trip test for a Codex Responses-Lite request with nested custom and namespace tools.
core/schemas/responses_test.go Updates the test comment to match the renamed opaque item storage.

Reviews (2): Last reviewed commit: "tests: exercise Codex gateway JSON path" | Re-trigger Greptile

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 13, 2026
Use the same Sonic parser and sorted provider encoder as the HTTP gateway so the Responses-Lite regression covers the production serialization path.

Co-authored-by: Cursor <cursoragent@cursor.com>
@devonpmack devonpmack changed the title fix: preserve Codex Responses-Lite tools fix: preserve Codex Responses-Lite tools (#5103) Jul 13, 2026
@devonpmack devonpmack closed this Jul 13, 2026
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