You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
dev@849ab5e35fdacddb4d47416c00a315111c78f97e (inspected on 2026-08-12)
Endpoint or capability
POST /v1/responses, model-specific wire selection, streaming terminal delivery, function-tool calls, and tool-result continuations for opencode-go/gpt-5.6-luna.
Current behaviour
OpenCode Go documents a model-specific protocol matrix. GPT 5.6 Luna is assigned to https://opencode.ai/zen/go/v1/responses with @ai-sdk/openai, while the same provider exposes other models through Chat Completions or Anthropic Messages.
At the inspected dev commit, however, OpenCodex's built-in opencode-go registry entry is provider-wide adapter: "openai-chat" and has no modelWireDefaults entry for gpt-5.6-luna. Unless a user adds an explicit modelAdapters override, the built-in route therefore selects the Chat Completions adapter and posts to /chat/completions instead of Luna's documented OpenCode Go Responses endpoint.
There is a second, distinct compatibility gap after correcting that mapping. The motivating reproduction registered the same OpenCode Go origin as a custom openai-responses provider and selected gpt-5.6-luna. In affected rich-history/tool turns:
the upstream request returned HTTP 200;
OpenCodex observed response.completed and reported usage within a few seconds;
Native Codex did not commit a usable terminal event;
the same logical turn was sampled again near the 300-second stream-idle boundary or was manually interrupted.
The failure was conditional: fresh minimal turns and some function-call continuations could complete. A control path in which Native Codex connected directly to the same OpenCode Go Responses upstream, without OpenCodex or the deployment relay, completed consecutive turns and tool round-trips.
The two gaps should therefore remain separate in diagnosis:
the built-in opencode-go preset selects the wrong wire for Luna;
once Luna is correctly routed through Responses, OpenCodex's streaming relay/client-delivery path can still fail to deliver a terminal that Native Codex commits.
This report does not claim that OpenAI's GPT-5.6 Luna universally lacks Chat Completions support. Official OpenAI documentation lists both Chat Completions and Responses. The provider-specific mismatch is that OpenCode Go itself documents its Luna route as Responses, and official OpenAI model guidance recommends Responses for reasoning, tool-calling, and multi-turn workflows.
Expected behaviour
Built-in opencode-go/gpt-5.6-luna selects the OpenAI Responses wire and reaches /zen/go/v1/responses.
Other OpenCode Go models retain their documented existing wires.
An explicit user modelAdapters override retains the current precedence and remains able to opt out.
Function and custom tool calls preserve response IDs, item IDs, call_id, names, argument strings, usage, and the matching function_call_output continuation.
A client stream:true request always receives a valid terminal Responses lifecycle that Native Codex can commit.
OpenCodex does not replay a model request, switch to another wire after dispatch, or execute a tool more than once.
Malformed, oversized, stalled, or protocol-mismatched upstream responses fail closed.
Minimal redacted request or reproduction
# OpenCodex listens on loopback. The OpenCode Go key is configured through the# normal provider credential flow and is intentionally omitted here.
curl --no-buffer http://127.0.0.1:10100/v1/responses \
-H 'content-type: application/json' \
--data-binary '{ "model": "opencode-go/gpt-5.6-luna", "store": false, "stream": true, "input": [{ "role": "user", "content": [{ "type": "input_text", "text": "Call diagnostic_echo exactly once with marker LUNA_RESPONSES_TOOL_42." }] }], "tools": [{ "type": "function", "name": "diagnostic_echo", "description": "Return the marker unchanged.", "parameters": { "type": "object", "properties": { "marker": { "type": "string" } }, "required": ["marker"], "additionalProperties": false } }], "tool_choice": "required" }'# Capture the returned response id and function call_id, execute the tool once,# then submit the result through the same conversation. Native Codex normally# performs this continuation automatically.
curl --no-buffer http://127.0.0.1:10100/v1/responses \
-H 'content-type: application/json' \
--data-binary '{ "model": "opencode-go/gpt-5.6-luna", "store": false, "stream": true, "previous_response_id": "<REDACTED_RESPONSE_ID>", "input": [{ "type": "function_call_output", "call_id": "<SAME_REDACTED_CALL_ID>", "output": "LUNA_RESPONSES_TOOL_42" }] }'# Static route check on the current built-in preset:# expected upstream path for Luna: /zen/go/v1/responses# current preset path without an explicit override: /zen/go/v1/chat/completions
For the original client-level reproduction, run the equivalent request in one persistent Native Codex conversation for four turns, including one forced tool turn and one later turn that references both prior text and the tool result.
Actual response or error
# Redacted OpenCodex-side outcome from an affected rich-history turn:
HTTP status: 200
upstream terminal: completed
usage: reported
upstream duration: approximately 2-7 seconds
# Client-side outcome:
committed terminal: not observed
next sampling/retry: approximately 302-304 seconds later
final result: retried, remained pending, or was manually interrupted
No prompt body, model output, API key, Authorization header, account identifier, host name, request ID, conversation ID, or exact timestamp is included.
The control path completed four consecutive Native Codex turns against the same OpenCode Go Responses upstream without OpenCodex. The external compatibility relay described below also completed local and external four-turn/tool scenarios without an extra request or duplicate tool execution. These controls narrow the failure boundary but do not prove one specific Bun primitive as the sole root cause.
This should use the existing mixed-wire resolution contract. It must not change the provider-wide default for Grok, GLM, Kimi, DeepSeek, MiMo, MiniMax, or Qwen models, and an explicit allowed modelAdapters entry must continue to win.
Strongly recommended initial compatibility policy
Correcting only the endpoint exposes Luna to the Responses relay path where the conditional terminal-delivery failure was observed. For the initial built-in rollout, connect Luna to the existing bounded upstream policy:
OpenCodex already has the relevant primitives on current dev:
resolve the effective per-model Responses policy;
preserve the client's original stream:true intent;
send the upstream Responses request once with stream:false;
read the completed JSON through the existing total-size and stall bounds;
validate and apply existing client-facing item/model repairs;
reframe it as canonical client SSE:
response.created -> response.output_item.done* ->
response.completed | response.failed | response.incomplete -> [DONE];
provide the equivalent event framing for Responses WebSocket clients.
This is structurally the same workaround proven in the deployment-specific Go relay:
exact Luna policy
-> client stream:true
-> one upstream Responses request with stream:false
-> bounded capture
-> strict completed-JSON validation
-> canonical terminal SSE
-> Native Codex
The Go relay also enforced no model-request replay, no automatic local/external fallback, exact-model opt-in, bounded request/response storage, and exact preservation of tool identifiers and arguments. Its local and external four-turn canaries both produced the expected logical request sequence 1 -> 2 -> 4 -> 5, one tool execution, zero retries, one terminal per logical request, and idle resource counters afterward. This is supporting compatibility evidence, not an upstream merge requirement.
The web-search/tool iteration path fixed in #1143 must continue to honor the same effective upstream-streaming decision. A hosted tool loop must not reintroduce stream:true after the model policy selected bounded JSON.
Acceptance criteria
Built-in Luna reaches /responses and never /chat/completions unless the user explicitly overrides the model adapter.
Other OpenCode Go models remain unchanged.
HTTP/SSE and Responses WebSocket both terminate correctly.
A four-turn persistent conversation preserves prior text and tool results.
A forced function call executes exactly once and its function_call_output continues with the same call_id.
Native Codex retry count is zero and exactly one terminal event is emitted per logical request.
Hosted web search preserves the bounded upstream decision.
Unexpected SSE after stream:false, invalid JSON, unknown terminal status, oversize, timeout, and cancellation fail once without replay or alternate-wire fallback.
After a protocol-safe one-reader streaming path has been qualified for this provider/runtime, maintainers can reconsider whether the bounded policy should remain the default. That later optimization should not block correcting the documented wire now.
Additional context and attachments
Related diagnostic and implementation draft by the same reporter: feat(responses): add an opt-in bounded JSON fallback for custom providers #1367. It proposed an opt-in custom-provider bounded fallback and contains the original cross-platform analysis. It is related evidence, not a claim that this built-in preset issue is already fixed.
No current-dev live canary is claimed in this issue. The current-dev mapping finding is static source evidence; the terminal-delivery and relay acceptance evidence comes from the earlier isolated live paths described above.
Checks
I searched existing provider and compatibility issues.
The request and response were redacted.
The expected behaviour is based on an upstream specification or a concrete client requirement.
Client or integration
Codex CLI
Provider or upstream service
OpenCode Go
OpenCodex version
dev@849ab5e35fdacddb4d47416c00a315111c78f97e (inspected on 2026-08-12)
Endpoint or capability
POST /v1/responses, model-specific wire selection, streaming terminal delivery, function-tool calls, and tool-result continuations for opencode-go/gpt-5.6-luna.
Current behaviour
OpenCode Go documents a model-specific protocol matrix. GPT 5.6 Luna is assigned to https://opencode.ai/zen/go/v1/responses with @ai-sdk/openai, while the same provider exposes other models through Chat Completions or Anthropic Messages.
At the inspected dev commit, however, OpenCodex's built-in opencode-go registry entry is provider-wide adapter: "openai-chat" and has no modelWireDefaults entry for gpt-5.6-luna. Unless a user adds an explicit modelAdapters override, the built-in route therefore selects the Chat Completions adapter and posts to /chat/completions instead of Luna's documented OpenCode Go Responses endpoint.
There is a second, distinct compatibility gap after correcting that mapping. The motivating reproduction registered the same OpenCode Go origin as a custom openai-responses provider and selected gpt-5.6-luna. In affected rich-history/tool turns:
The failure was conditional: fresh minimal turns and some function-call continuations could complete. A control path in which Native Codex connected directly to the same OpenCode Go Responses upstream, without OpenCodex or the deployment relay, completed consecutive turns and tool round-trips.
The two gaps should therefore remain separate in diagnosis:
This report does not claim that OpenAI's GPT-5.6 Luna universally lacks Chat Completions support. Official OpenAI documentation lists both Chat Completions and Responses. The provider-specific mismatch is that OpenCode Go itself documents its Luna route as Responses, and official OpenAI model guidance recommends Responses for reasoning, tool-calling, and multi-turn workflows.
Expected behaviour
Minimal redacted request or reproduction
For the original client-level reproduction, run the equivalent request in one persistent Native Codex conversation for four turns, including one forced tool turn and one later turn that references both prior text and the tool result.
Actual response or error
No prompt body, model output, API key, Authorization header, account identifier, host name, request ID, conversation ID, or exact timestamp is included.
The control path completed four consecutive Native Codex turns against the same OpenCode Go Responses upstream without OpenCodex. The external compatibility relay described below also completed local and external four-turn/tool scenarios without an extra request or duplicate tool execution. These controls narrow the failure boundary but do not prove one specific Bun primitive as the sole root cause.
Upstream documentation
Suggested mapping or implementation notes
Required: correct the built-in model wire
The smallest model-specific registry correction is:
This should use the existing mixed-wire resolution contract. It must not change the provider-wide default for Grok, GLM, Kimi, DeepSeek, MiMo, MiniMax, or Qwen models, and an explicit allowed modelAdapters entry must continue to win.
Strongly recommended initial compatibility policy
Correcting only the endpoint exposes Luna to the Responses relay path where the conditional terminal-delivery failure was observed. For the initial built-in rollout, connect Luna to the existing bounded upstream policy:
OpenCodex already has the relevant primitives on current dev:
response.created -> response.output_item.done* ->
response.completed | response.failed | response.incomplete -> [DONE];
This is structurally the same workaround proven in the deployment-specific Go relay:
The Go relay also enforced no model-request replay, no automatic local/external fallback, exact-model opt-in, bounded request/response storage, and exact preservation of tool identifiers and arguments. Its local and external four-turn canaries both produced the expected logical request sequence 1 -> 2 -> 4 -> 5, one tool execution, zero retries, one terminal per logical request, and idle resource counters afterward. This is supporting compatibility evidence, not an upstream merge requirement.
The web-search/tool iteration path fixed in #1143 must continue to honor the same effective upstream-streaming decision. A hosted tool loop must not reintroduce stream:true after the model policy selected bounded JSON.
Acceptance criteria
After a protocol-safe one-reader streaming path has been qualified for this provider/runtime, maintainers can reconsider whether the bounded policy should remain the default. That later optimization should not block correcting the documented wire now.
Additional context and attachments
https://github.com/lidge-jun/opencodex/blob/849ab5e35fdacddb4d47416c00a315111c78f97e/src/providers/registry.ts
opencodex/src/server/responses/core.ts
Lines 958 to 979 in 849ab5e
opencodex/src/server/responses/core.ts
Lines 2516 to 2564 in 849ab5e
No current-dev live canary is claimed in this issue. The current-dev mapping finding is static source evidence; the terminal-delivery and relay acceptance evidence comes from the earlier isolated live paths described above.
Checks