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
#2074 fixed the non-English content-blocked 400 for the anthropic adapter only. The openai-chat adapter (AGR-OAI provider with adapter: "openai-chat") still 400s on non-English first user messages on every wire — /v1/responses, /v1/chat/completions, and even a raw Anthropic-format call to the gateway.
Affected: gpt-5.6-sol (and any OpenAI-format model routed through AgentRouter) used by Codex CLI (wire_api = "responses") and chat-style clients. The model is listed in subagentModels, so subagent turns in PT fail hard.
Reproduction (verified against agentrouter.org with a real key)
All requests use model: "gpt-5.6-sol" (endpoint support: ["openai"] only per /v1/models), base https://agentrouter.org:
#
Wire
First message
Result
1
/v1/chat/completions (via proxy)
"What is the capital of Brazil?" (EN)
200
2
/v1/chat/completions (via proxy)
"Qual a capital do Brasil?" (PT)
400 content-blocked
3
/v1/responses (via proxy)
"Qual a capital do Brasil?" (PT)
400 content-blocked
4
Anthropic /v1/messages direct with claude-cli headers
PT, no framing
400 content-blocked
5
Anthropic /v1/messages direct with claude-cli headers
PT + [Instruction: ...] framing
200
6
/v1/chat/completions direct with all claude-cli/X-Stainless headers
PT, no framing
400 content-blocked (headers do NOT bypass the filter)
7
/v1/responses via proxy + local framing (patch)
PT
200
So: the gateway validates the opening user turn language on all wires, regardless of adapter, endpoint, or client headers. See #1804 for the original correlation research.
Note on the "model is openai-only" fact
GET /v1/models (with recognized User-Agent) reports:
A raw Anthropic-format call does work for it today (test #4/#5), but that is undocumented/unofficial behavior — the supported surface is OpenAI-compatible. So the fix must live on the openai-chat path, not by re-routing users to the anthropic adapter.
Proposed fix
Extend the framing from #2074 to the openai-chat adapter. Mirror the existing applyAgentRouterLanguageFraming (src/adapters/anthropic.ts) with:
Idempotent: keyed on the leading block/content being exactly the marker, not includes() (a user quoting the marker later in their prompt must not suppress the frame, and retries/replays must not stack frames).
Frame as its own text block (or prefix for string content) — the user's original text survives byte-for-byte.
Hook points: messagesToChatFormat() result in buildRequest() for the translated Chat path, and buildOpenAIChatPassthroughRequest() for /v1/chat/completions passthrough — both are needed; patching only one leaves the other wire 400ing.
Only the first user role message is framed (the gateway inspects the opening turn; system/developer prefixes do not help — verified: a system EN + user PT request still 400s).
Test matrix
Case
Expected
AGR-OAI PT via /v1/responses and /v1/chat/completions
String content AND content-part arrays (Claude Code style)
covered
Alternative considered
Shipping a provider-level flag (e.g. languagePreamble: true) instead of host-derived detection. Rejected for scope: the transform is safe, idempotent, and host-scoped, matching the #2074 decision; a flag adds config surface for no behavioral benefit.
Summary
#2074 fixed the non-English
content-blocked400 for the anthropic adapter only. The openai-chat adapter (AGR-OAIprovider withadapter: "openai-chat") still 400s on non-English first user messages on every wire —/v1/responses,/v1/chat/completions, and even a raw Anthropic-format call to the gateway.Affected:
gpt-5.6-sol(and any OpenAI-format model routed through AgentRouter) used by Codex CLI (wire_api = "responses") and chat-style clients. The model is listed insubagentModels, so subagent turns in PT fail hard.Reproduction (verified against agentrouter.org with a real key)
All requests use
model: "gpt-5.6-sol"(endpoint support:["openai"]only per/v1/models), basehttps://agentrouter.org:/v1/chat/completions(via proxy)"What is the capital of Brazil?"(EN)/v1/chat/completions(via proxy)"Qual a capital do Brasil?"(PT)/v1/responses(via proxy)"Qual a capital do Brasil?"(PT)/v1/messagesdirect with claude-cli headers/v1/messagesdirect with claude-cli headers[Instruction: ...]framing/v1/chat/completionsdirect with all claude-cli/X-Stainless headers/v1/responsesvia proxy + local framing (patch)So: the gateway validates the opening user turn language on all wires, regardless of adapter, endpoint, or client headers. See #1804 for the original correlation research.
Note on the "model is openai-only" fact
GET /v1/models(with recognized User-Agent) reports:{"id":"gpt-5.6-sol","model":"gpt-5.6-sol","supported_endpoint_types":["openai"]}A raw Anthropic-format call does work for it today (test #4/#5), but that is undocumented/unofficial behavior — the supported surface is OpenAI-compatible. So the fix must live on the openai-chat path, not by re-routing users to the anthropic adapter.
Proposed fix
Extend the framing from #2074 to the openai-chat adapter. Mirror the existing
applyAgentRouterLanguageFraming(src/adapters/anthropic.ts) with:agentrouter.org/*.agentrouter.org(never substring — same rationale as fix(anthropic): frame the opening turn so AgentRouter stops blocking non-English #2162's comment aboutnotagentrouter.example).includes()(a user quoting the marker later in their prompt must not suppress the frame, and retries/replays must not stack frames).messagesToChatFormat()result inbuildRequest()for the translated Chat path, andbuildOpenAIChatPassthroughRequest()for/v1/chat/completionspassthrough — both are needed; patching only one leaves the other wire 400ing.userrole message is framed (the gateway inspects the opening turn;system/developerprefixes do not help — verified: asystemEN + user PT request still 400s).Test matrix
/v1/responsesand/v1/chat/completionsAlternative considered
Shipping a provider-level flag (e.g.
languagePreamble: true) instead of host-derived detection. Rejected for scope: the transform is safe, idempotent, and host-scoped, matching the #2074 decision; a flag adds config surface for no behavioral benefit.References: #2074 (closed, anthropic-only), #2162 (merged PR), #1804 (correlation research), #1689 (closed by research).