Skip to content

Kiro claude-opus-5 ignores Claude Code mid-turn queued messages while opus-4.8 works #543

Closed

Description

@VXNCXNX

Client or integration

Claude Code

Area

Provider adapter

Summary

When Claude Code is launched through opencodex (ocx claude / claudeCode.authMode: "proxy") on a routed kiro model, messages typed while the agent is working are queued by Claude Code but never steer the agent.

Claude Code does register them client-side (queue-operation: enqueue → remove → attachment: queued_command with origin.kind: "human"), and opencodex continues to serve successful surface: claude 200s on the next turns. But the model keeps the previous trajectory and never acknowledges or follows the queued prompt. The same instruction works immediately when sent as a normal user turn after the agent is idle.

Effect: impossible to redirect mid-task (change model for a sub-review, cancel a planned edit, request parallel work). Looks like “messages while running are not registered”; transcript shows they are registered as queue attachments and then ignored.

Reproduced 3/3 human mid-turn queues in one session (all ignored). One subsequent full user turn in the same session was obeyed.

Not a Codex App/CLI issue. Not a missing HTTP request. Not a 502/stream-close.

Reproduction

  1. Configure kiro (adapter: "kiro", authMode: "oauth", baseUrl: "https://runtime.us-east-1.kiro.dev") and enable Claude Code via the dashboard / ocx claude (claudeCode.authMode: "proxy").
  2. In Claude Code, select a routed model such as claude-ocx-kiro--claude-opus-5[1m].
  3. Start a long-running turn (multi-tool work, background bash, etc.).
  4. While it is working, type a short steering message and submit (e.g. try model kiro/gpt-5.6-sol or do not change X).
  5. Observe:
  • Claude Code records queue-operation enqueue/remove and an attachment of type queued_command.
  • opencodex logs further surface: claude requests with status 200.
  • The assistant does not act on the queued text; it continues the prior plan.
  1. After the agent is idle, send the same request as a normal user message → it is followed.
    Deterministic in session 0443eb2d-c61e-47d4-97bc-04cfc7248e75 (Claude Code 2.1.220, 2026-07-27): three human queues, three ignores; one real user turn, obeyed.

Version

2.7.41

Operating system

macOS 26.5.2 (arm64), Node 22.23.1, Claude Code 2.1.220

Provider and model

kiro / claude-opus-5

Logs or error output

Claude Code session transcript (local jsonl), version 2.1.220
Prompt text redacted to minimal repro strings. No paths / project ids.

--- Human mid-turn queue #1 ---
{"type":"queue-operation","operation":"enqueue","content":"<redacted: stop-doing-X instruction>"}
{"type":"queued_command","prompt":"<redacted>","commandMode":"prompt","origin":{"kind":"human"}}
# then: queue-operation remove
# next assistant: continued prior plan and did the work the queue asked NOT to do

--- Human mid-turn queue #2 ---
{"type":"queue-operation","operation":"enqueue","content":"try model kiro/gpt-5.6-sol"}
{"type":"queued_command","prompt":"try model kiro/gpt-5.6-sol","commandMode":"prompt","origin":{"kind":"human"}}
# next assistant (paraphrase): announced a different model via the proxy and started a long
# background review on that other model — never used kiro/gpt-5.6-sol as instructed

--- Human mid-turn queue #3 ---
{"type":"queue-operation","operation":"enqueue","content":"<redacted: create-skill while background work runs>"}
{"type":"queued_command","prompt":"<redacted>","commandMode":"prompt","origin":{"kind":"human"}}
# next assistant (paraphrase): "Backgrounded. Let me check progress." then more polling
# zero work on the requested skill

--- Same session: REAL user turn works ---
# type=user (normal turn, not queue): restated the model-choice complaint
# assistant then correctly explained and re-ran on kiro/gpt-5.6-sol

--- Background task-notification (same queue type), sometimes ignored ---
{"type":"queue-operation","operation":"enqueue","content":"<task-notification><status>completed</status><summary>Background command completed (exit code 0)</summary></task-notification>"}
{"type":"queued_command","commandMode":"task-notification","origin":null}
# one completed job left a multi-KB findings file on disk
# next assistant turns: pre-planned edit streak; never opened that output
# other task-notifications in the same session were partially consumed (mixed)

--- opencodex usage.jsonl around the queues (anonymized) ---
# surface=claude  provider=kiro  model=claude-opus-5  status=200
# multiple turns fire immediately after each queue
# no client_cancel / 499 in that window (not an abort-path bug)

--- Hypothesis for maintainers ---
Claude Code injects mid-turn steers as attachment type queued_command (not as a full
type=user text bubble). That content must be folded into the next Anthropic Messages
request. Through opencodex's Claude /v1/messages path to kiro, either:
  (A) the queued_command content is dropped / not mapped into the wire messages, or
  (B) it is sent in a shape the kiro adapter / upstream does not surface as a user
      instruction, so the model continues the prior tool loop.
Contrast: a normal user message in the same session is obeyed.

Please verify what the Claude surface puts on the wire for a turn that has a pending
queued_command attachment (message roles, system blocks, tool_result interleaving).

Screenshots and supporting files

No response

Redacted configuration

{
  "port": 10100,
  "defaultProvider": "openai",
  "websockets": false,
  "claudeCode": {
    "enabled": true,
    "authMode": "proxy",
    "systemEnv": false
  },
  "providers": {
    "kiro": {
      "adapter": "kiro",
      "authMode": "oauth",
      "baseUrl": "https://runtime.us-east-1.kiro.dev",
      "defaultModel": "claude-opus-5"
    }
  }
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. github-actions commented on Jul 27, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: English.

  2. Ingwannu commented on Jul 27, 2026

    @Ingwannu
    Owner

    Thanks for the careful redaction. I checked the current Claude inbound translator, and the transcript evidence does not yet establish an OpenCodex drop.

    queued_command is a Claude Code local transcript/SDK replay attachment. OpenCodex never reads that JSONL; it can only translate the actual HTTP POST /v1/messages body. In the current translator, standard user strings/text blocks, images, and tool results are all preserved into Responses input. Unknown content-block types are ignored, but the report does not show that Claude Code actually placed a queued_command block (or its prompt text) on the Anthropic wire.

    There is also an upstream Claude Code report for the same native symptom: anthropics/claude-code#1124. That makes a native-vs-proxy control necessary before changing the bridge.

    Please provide these two minimal data points using a unique harmless marker such as OCX_QUEUE_543:

    1. On Claude Code 2.1.220, does the same mid-turn queue work when using a native Anthropic/Claude subscription route instead of OpenCodex/Kiro?
    2. For the first /v1/messages request after the queue is removed, provide a redacted structural excerpt of the final user message: roles and content-block type values, plus whether the serialized request contains OCX_QUEUE_543. Other text can be replaced with <redacted>; no headers, tokens, IDs, paths, or full prompts are needed.

    If the marker is absent from the HTTP body, this is upstream Claude Code queue delivery and cannot be recovered by the proxy. If it is present in a standard text/tool-result block but missing after translation, I can add the exact fixture and fix the translator. If it arrives as a private queued_command wire block, we need that precise shape before supporting it so we do not duplicate prompts when Claude Code also promotes the attachment to a normal user message.

    Marking needs-info and leaving this open; no speculative code change was made.

  3. VXNCXNX commented on Jul 27, 2026

    @VXNCXNX
    ContributorAuthor

    Thanks for the careful read — happy to close the loop on the two asks.

    1) Native Claude Code control (no OpenCodex / no Kiro)

    Yes — mid-turn queue works perfectly on native Claude Code 2.1.220 (normal Anthropic / subscription route, not through OpenCodex, not via Kiro).

    Concrete behavior on a native session:

    • I type while the agent is still working
    • Claude Code queues the message
    • The agent receives it and acts on it (steers / follows the instruction)
    • It is not ignored

    So this is not “Claude Code never delivers mid-turn queue.” Same client version, same queue UX:

    Route Mid-turn queue
    Native Claude Code (no proxy) works perfectly
    Claude Code → OpenCodex → Kiro ignored (this report)

    That is why I opened it here rather than only on anthropics/claude-code#1124 (which may still describe a related class of bugs for other setups, but does not match my native control).

    2) Wire shape after queue-operation remove — what I can recover without a live re-capture

    I cannot attach the raw POST /v1/messages body from the original session: with default settings OpenCodex does not persist the inbound Anthropic Messages payload (/api/debug shows enabled/claude: false; usage-debug.jsonl only samples upstream response SSE, not the client request).

    What I can show from local state after the same proxy session:

    A. Claude Code transcript (local JSONL only — as before)
    For each mid-turn steer: queue-operation: enqueue → remove → attachment: queued_command (commandMode: "prompt", origin.kind: "human"). Three human steers, all ignored by the agent.

    B. OpenCodex post-translation conversation state (responses-state.json)
    I grepped the stored Responses-format items for the three mid-turn prompt strings (and for any queued_command token). Zero hits.

    Caveat: that file only retains a bounded recent window of response states, so a pure “not in file” result could in theory mean the older turns rotated out rather than never arriving. Still consistent with the rest of the evidence: after those queues, usage.jsonl shows continued surface: claude 200s, and the model never acknowledged any of the three steer strings. The live OCX_QUEUE_543 capture below is what settles wire presence for good.

    The later full user turn (the one that did steer — restating the model complaint as a normal message) is present in that state, as a normal user message, content-block types like:

    role: user
    content blocks:
      - type: input_text   # human message
      - type: input_image  # optional paste
      - type: input_text   # (any trailing text)
    

    C. Turns that continue after a mid-turn queue is “removed”
    While the agent keeps working, the post-translation user turns look like tool-loop traffic only, e.g.:

    role: user
    content blocks:
      - type: input_text   # <system-reminder> / hook context only
    # plus function_call_output items for tool results
    # NO human steer text from the queued_command prompt
    

    D. usage.jsonl
    Immediately after each remove, further surface: claude / provider: kiro requests still return status 200 (so the proxy is not failing the turn; the model is answering something, just not the queued steer).

    Marker test (OCX_QUEUE_543) — structural implication from (B)+(C)

    I did not re-run a live capture with the marker string yet (happy to if you still need the exact raw body). From the original three steers:

    Where Mid-turn queued text present?
    Claude Code transcript queued_command.prompt yes
    OpenCodex translated responses-state user/input_text items no
    Later normal user turn text yes (and agent obeyed)

    So under your decision tree:

    • If Claude Code put the steer on the wire as a normal text / tool-result block, OpenCodex’s translator (or pre-state path) is dropping it before / at Responses state — fixture + fix belongs here.
    • If Claude Code never serializes queued_command onto POST /v1/messages only when ANTHROPIC_BASE_URL points at the proxy, that is still a proxy-path interaction (native works), and the raw body would show marker absent. I can capture that next with debug / a one-shot dump if you tell me the preferred switch (e.g. enable /api/debug claude logging, or a flag to log redacted inbound messages[].content[].type only).

    I am not claiming OpenCodex should parse the local JSONL. The claim is: same client, native mid-turn queue is honored; through opencodex→kiro the same client records a queue that never appears in the proxy’s translated conversation and never steers the model.

    Optional next capture (if you want the exact body)

    I can re-run a minimal session:

    1. Proxy on, model claude-ocx-kiro--claude-opus-5[1m]
    2. Start a long tool loop
    3. Mid-turn submit exactly: OCX_QUEUE_543
    4. Dump redacted structure of the first inbound /v1/messages after remove (roles + content-block types + boolean body includes OCX_QUEUE_543)

    Tell me if you already have a supported way to log redacted inbound message shapes; otherwise I will use a local capture on 127.0.0.1:10100.

    Happy to add any extra field you need.

  4. VXNCXNX commented on Jul 27, 2026

    @VXNCXNX
    ContributorAuthor

    Update: same proxy, different model — mid-turn queue works on Opus 4.8

    After the earlier reply (native control + post-translation state notes), I kept running the same OpenCodex setup (Claude Code → proxy → Kiro, claudeCode.authMode: "proxy") and switched only the model.

    Route Mid-turn queue (type while agent is working)
    Native Claude Code (no OpenCodex) works
    OpenCodex + kiro/claude-opus-4.8 (claude-ocx-kiro--claude-opus-4.8[1m]) works — agent receives and acts on the queued message
    OpenCodex + kiro/claude-opus-5 (claude-ocx-kiro--claude-opus-5[1m], original report) ignored — queue recorded client-side, model keeps prior trajectory

    There has been no OpenCodex upgrade/fix on my side between the failing Opus 5 session and the working Opus 4.8 sessions. Same proxy version 2.7.41, same Claude Code 2.1.220, same machine.

    What this changes for the diagnosis

    This makes a blanket “OpenCodex drops every queued_command” story much less likely. If the Claude inbound translator systematically stripped mid-turn steers, Opus 4.8 on the same bridge would fail the same way.

    More consistent with the evidence so far:

    1. Model / provider-path specific — kiro/claude-opus-5 does not honor (or does not effectively surface) mid-turn steers the way kiro/claude-opus-4.8 does, even though post-queue turns still return HTTP 200.
    2. Or a narrow path difference for the opus-5 catalog entry (1M / effort / translation) — less likely, but still on the Kiro+opus-5 side rather than “all Claude surface traffic.”

    It does not look like:

    • Codex App/CLI
    • “Claude Code never queues mid-turn at all” (native works; proxy+4.8 works)
    • A general proxy outage (4.8 mid-turn steers are clearly applied in the same setup)

    Still open for a hard wire proof on Opus 5

    I have not yet done a live OCX_QUEUE_543 capture on opus-5 only (inbound POST /v1/messages structure + marker present/absent). Happy to run that next if useful. Given 4.8 works on the same proxy, the interesting question is no longer “does any queue survive the bridge?” but:

    • On opus-5, is the marker present on the wire and ignored by the model/upstream, or
    • Absent only for that model id (path-specific drop)?

    Practical takeaway for me / other reporters

    Workaround that already works: stay on kiro/claude-opus-4.8 (or native) when mid-turn steering matters. Failures to reproduce should pin exact model id (claude-opus-5 vs claude-opus-4.8), not only “Claude Code + OpenCodex.”

    Happy to re-label / retitle toward provider-compatibility / kiro opus-5 if that matches how you want to track it.

  5. changed the title [-]Claude Code mid-turn queued messages (`queued_command`) are ignored when routed through opencodex/kiro, only full user turns steer the agent[/-] [+]Kiro claude-opus-5 ignores Claude Code mid-turn queued messages while opus-4.8 works[/+] on Jul 27, 2026
  6. Ingwannu commented on Jul 27, 2026

    @Ingwannu
    Owner

    Thanks — the same-proxy opus-4.8 control materially narrows this. It rules out the original general claim that OpenCodex drops every Claude Code mid-turn queue: the bridge can carry the steer, and the failure is currently specific to the Kiro claude-opus-5 route (or its catalog/1M path).

    I have narrowed the title accordingly and am keeping provider-compatibility / needs-info. No proxy-wide translation change is justified from the current evidence. The remaining decisive artifact is the proposed Opus 5 wire capture: whether OCX_QUEUE_543 is present in the next inbound /v1/messages body. Present means upstream/model-path behavior; absent means a narrow client/proxy path we can fix. The working workaround remains Kiro Opus 4.8 or native when mid-turn steering is required.

  7. assigned and unassigned on Jul 27, 2026
  8. lidge-jun commented on Jul 29, 2026

    @lidge-jun
    Owner

    Fixed on our side, so I'm closing this. Thanks for sticking with it — your Opus 4.8 control is what made the report tractable, and it correctly ruled out the original "the proxy drops every queued_command" reading.

    What was wrong

    Claude Code delivers a mid-turn steer as text riding the same user turn as the pending tool_result. The Kiro adapter merges adjacent user content, and the tool-result branch was pushing its placeholder sentence first, so the assembled current turn read:

    The requested tool result is attached.
    
    <your steering instruction>
    

    That placeholder exists only so a tool-result turn with no other text isn't sent with blank content. It was never meant as a prefix, and putting it ahead of the newest human intent buried your instruction behind proxy boilerplate on the opening line of the current turn.

    Tool results now carry empty content and the placeholder is backfilled only for turns that still have no text, so a mid-turn steer arrives as just your instruction, with the tool result still attached structurally in userInputMessageContext.toolResults. Nothing is lost.

    What we verified along the way

    I reconstructed your scenario directly against the request builder rather than reasoning about it, invoking buildKiroPayload for both models on the tail Claude Code produces. Two things came out of that:

    • The steering text was always reaching Kiro as the current turn — it was never dropped or pushed into history. Inbound preserves block order, the adapter merges adjacent user content, and that merged turn becomes conversationState.currentMessage.
    • Request construction is otherwise the same for both models on this path. The only differences are the model identifier and Opus 5's native output_config.effort. Completion mode depends only on whether tools are present, the tool-catalog nudge takes no model argument, both are 1M-context entries, and the CLI-vs-IDE request shape depends on token type rather than model. Opus 4.8's emulated-thinking injection is also skipped whenever the current turn carries tool results, so neither model gets extra instruction text in this exact situation.

    Regression tests now pin both behaviors: that a mid-turn steer is the entire current content with no placeholder filler, and that Opus 5 and Opus 4.8 receive identical request content apart from the native effort field. A future model-conditional regression on this path fails in CI instead of in someone's session.

    If it comes back

    To be straight about scope: the ordering fix is a targeted change, and I can't prove from this side that it was the whole story. It's plausible Opus 5 weights the opening sentence of the current turn more heavily than 4.8 does, which would make this exactly the cause — but that stays a hypothesis.

    So if you still see mid-turn steers ignored on Opus 5 once this is in your build, please reopen or file a follow-up. Two things would help most:

    1. Whether the same scenario behaves differently with reasoning effort lowered or disabled. That isolates output_config.effort, the only other model-conditional field we emit, and needs no special instrumentation.
    2. The OCX_QUEUE_543 style capture you offered, if you still have the appetite for it. Worth noting the existing Claude inbound debug ring captures scalars only and not message structure, so it won't answer this on its own.

    Also happy to hear about anything else you hit — the level of detail in this report made it much easier to work with than most.

  9. removed
    needs-infoWaiting on reporter for a concrete spec or reproduction
    on Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingprovider-compatibilityProvider compatibility reports

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions