Repository navigation
Description
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
- 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").
- In Claude Code, select a routed model such as claude-ocx-kiro--claude-opus-5[1m].
- Start a long-running turn (multi-tool work, background bash, etc.).
- 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).
- 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.
- 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
github-actions commentedon Jul 27, 2026
Automated translation bookkeeping — detected language: English.
Ingwannu commentedon Jul 27, 2026
Thanks for the careful redaction. I checked the current Claude inbound translator, and the transcript evidence does not yet establish an OpenCodex drop.
queued_commandis a Claude Code local transcript/SDK replay attachment. OpenCodex never reads that JSONL; it can only translate the actual HTTPPOST /v1/messagesbody. 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 aqueued_commandblock (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:/v1/messagesrequest after the queue is removed, provide a redacted structural excerpt of the final user message: roles and content-blocktypevalues, plus whether the serialized request containsOCX_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_commandwire 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-infoand leaving this open; no speculative code change was made.VXNCXNX commentedon Jul 27, 2026
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:
So this is not “Claude Code never delivers mid-turn queue.” Same client version, same queue UX:
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-captureI cannot attach the raw
POST /v1/messagesbody from the original session: with default settings OpenCodex does not persist the inbound Anthropic Messages payload (/api/debugshowsenabled/claude: false;usage-debug.jsonlonly 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_commandtoken). 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.jsonlshows continuedsurface: claude200s, and the model never acknowledged any of the three steer strings. The liveOCX_QUEUE_543capture 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:
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.:
D. usage.jsonl
Immediately after each
remove, furthersurface: claude/provider: kirorequests 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:
queued_command.promptresponses-stateuser/input_text itemsSo under your decision tree:
queued_commandontoPOST /v1/messagesonly whenANTHROPIC_BASE_URLpoints 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/debugclaude logging, or a flag to log redacted inboundmessages[].content[].typeonly).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:
claude-ocx-kiro--claude-opus-5[1m]OCX_QUEUE_543/v1/messagesafterremove(roles + content-blocktypes + booleanbody 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.
VXNCXNX commentedon Jul 27, 2026
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.kiro/claude-opus-4.8(claude-ocx-kiro--claude-opus-4.8[1m])kiro/claude-opus-5(claude-ocx-kiro--claude-opus-5[1m], original report)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:
kiro/claude-opus-5does not honor (or does not effectively surface) mid-turn steers the waykiro/claude-opus-4.8does, even though post-queue turns still return HTTP 200.It does not look like:
Still open for a hard wire proof on Opus 5
I have not yet done a live
OCX_QUEUE_543capture on opus-5 only (inboundPOST /v1/messagesstructure + 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: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-5vsclaude-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.
[-]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[/+]Ingwannu commentedon Jul 27, 2026
Thanks — the same-proxy
opus-4.8control 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 Kiroclaude-opus-5route (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: whetherOCX_QUEUE_543is present in the next inbound/v1/messagesbody. 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.docs(devlog): record owner decision ledger for open issues and PRs
docs(devlog): correct the decision ledger against an independent audit
lidge-jun commentedon Jul 29, 2026
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: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
buildKiroPayloadfor both models on the tail Claude Code produces. Two things came out of that:conversationState.currentMessage.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:
output_config.effort, the only other model-conditional field we emit, and needs no special instrumentation.OCX_QUEUE_543style 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.
fix(kiro): stop proxy filler from preceding a mid-turn steer
chore(devlog): advance the plan submodule to bb30ba6
fix(kiro): stop proxy filler from preceding a mid-turn steer
chore(devlog): advance the plan submodule to bb30ba6