Skip to content

[Bug]: AgentRouter 400 content-blocked still affects openai-chat adapter (AGR-OAI) — apply language framing on Chat/Responses #2415

Closed as not planned

Description

@rrmlima

Summary

#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:

{"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:

  • Host exact match on agentrouter.org / *.agentrouter.org (never substring — same rationale as fix(anthropic): frame the opening turn so AgentRouter stops blocking non-English #2162's comment about notagentrouter.example).
  • 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 200, answer in PT
AGR-OAI EN (no frame needed) 200, no double frame
AGR-CLA (anthropic) unchanged (#2074 already handles it)
Non-AGR openai-chat providers (e.g. OpenAI, command-code, Z.AI) byte-for-byte unchanged — no framing
Retry/replay of a framed turn single marker, no stacking
Subsequent non-English messages after the first unchanged (only first user turn framed)
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.

References: #2074 (closed, anthropic-only), #2162 (merged PR), #1804 (correlation research), #1689 (closed by research).

Activity

  1. coderabbitai commented on Aug 22, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #2082 - [WRONG BRANCH] fix(adapters): frame AgentRouter first messages to pass the language filter [open]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. github-actions commented on Aug 22, 2026

    @github-actions
    Contributor

    Issue closed: insufficient detail

    Thanks for taking the time to submit this issue. It was closed automatically because the structured report is missing information needed to evaluate or reproduce it.

    • Reproduction is empty.

    Please edit the issue to add:

    • List the exact steps to reproduce the problem.

    See the Contributing guide for details.

    Once the report passes the automated checks, it will be reopened automatically unless a maintainer has changed its state.

  3. rrmlima commented on Aug 24, 2026

    @rrmlima
    ContributorAuthor

    New evidence: the filter scores non-English volume across the WHOLE conversation

    The framing-only-the-first-turn mitigation (both upstream applyAgentRouterLanguageFraming and any first-turn-only patch) is insufficient for real multi-turn sessions. Empirical evidence from production traffic (Command Code session, 2026-08-22/24), all against claude-opus-5 via /v1/messages, spaced calls to avoid #1689 burst interference:

    # Payload (identical structure, ~1.0k input tokens) Result
    1 Long PT history + marker framed on first user turn only 400 content-blocked
    2 Identical payload fully in EN 200
    3 Short PT history (2 turns) + framing 200
    4 Long PT history + marker on EVERY user turn (block form) 200 once, then 400 on re-test
    5 Long PT history + marker on every turn (string form) 400
    6 Long PT history, no marker at all 400
    7 Re-run of #2 (EN long) minutes after #4-#6 200

    Conclusions

    1. The gateway's language scoring is not "first message only" — it accumulates non-English volume across the conversation.
    2. The per-turn framing mitigates but does not guarantee: test Add Codex autostart shim #4 passed once and failed on re-test with only marker-form differing (Fix stale Codex autostart shim repair #5). The threshold appears dynamic (score-based, possibly time/usage-dependent), so a deterministic client-side fix is not achievable by framing alone.
    3. EN control passes consistently before and after — this is not [Bug]: AgentRouter 400 content-blocked under burst traffic; characterize pacing/retry mitigation #1689 burst behavior (calls were spaced minutes apart; failures are pre-execution, usageStatus: unreported).

    Impact for harness users

    Any coding-agent session in PT/ES longer than a couple of turns hits 400 content-blocked mid-conversation regardless of adapter (anthropic and openai-chat both affected) and regardless of first-turn framing.

    Ask

    Upstream options worth considering:

    • Provider-level config to cap or translate outbound non-English history for AgentRouter-class gateways;
    • Documented gateway contract from AgentRouter (what exactly is scored, what the threshold is);
    • Or an official statement that long non-English conversations are unsupported on these models, so clients can fail fast instead of failing mid-session.

    Happy to provide request IDs and raw payloads (secrets redacted) if useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions