[amazon-bedrock] Streaming emits cumulative snapshots as duplicate agent_message items (Mantle/Responses)
Summary
With the built-in amazon-bedrock provider (Mantle Responses API), a single assistant turn emits many agent_message item.completed events whose text is the monotonically-growing cumulative snapshot of the same final message. The client persists each streaming snapshot as a separate completed message item instead of coalescing deltas.
Environment
- codex-cli 0.142.0 (latest stable) AND 0.143.0-alpha.9 — both affected
- Provider:
amazon-bedrock(built-in, Mantle Responses path) - Region:
us-east-2, modelopenai.gpt-5.5 - macOS (Apple Silicon)
Repro
codex exec --json --skip-git-repo-check "<long prompt yielding a multi-chunk response>"
Observed
A single turn emits N agent_message item.completed events; text length grows monotonically (same final message repeated as ever-longer prefixes):
- 0.142.0: 31 items, text length 189 -> 4049
- 0.143.0-alpha.9: 16 items, text length 295 -> 3386 (same pathological pattern)
Short single-chunk responses emit only 1 item, which masks the bug (a one-line "OK_ONCE" test looks fine).
In the TUI this renders the answer repeatedly/growing; the rollout jsonl also stores the duplicate message items (distinct ids) for one turn.
Expected
One agent_message item per assistant turn (output_text deltas/snapshots coalesced), as on the OpenAI-hosted Responses path.
Notes
- Not reproduced on the OpenAI-hosted Responses path; appears specific to the Bedrock Mantle streaming adapter.
model_reasoning_effort(xhigh/high/medium) has no effect — duplicate count tracks response length, not effort.- The built-in
amazon-bedrockprovider ignores stream tuning knobs (stream_idle_timeout_ms,stream_max_retries,wire_api), so there is no user-side config workaround.
2 Comments
Thanks for the detailed repro. This lines up with #30072 and likely belongs in the same failure class: completed Bedrock/Mantle stream snapshots are being treated as separate assistant items instead of being coalesced before history storage.
The narrow fix I would aim for is in the client path just before completed assistant
response.output_item.doneitems are persisted, not in the generic SSE parser. The SSE layer currently maps eachresponse.output_item.donedirectly intoResponseEvent::OutputItemDone, whilesession/turn.rsstill has the active item / streaming UI context needed to decide whether consecutive assistant messages are snapshots of the same output.I would keep the coalescing conservative:
item.id: replace earlier assistant snapshot with the later one;response.failed, since #27185 looks like a separate retry/reconnect lifecycle issue that should remain diagnosable.Regression coverage I would expect: cumulative same-id snapshots collapse to one persisted final message; distinct-id monotonic snapshots like this issue collapse to one final message; non-prefix assistant messages remain separate; a tool/reasoning boundary flushes any pending assistant snapshot; and a
response.failed/retry fixture proves this does not mask terminal/retry behavior. I also would not claim this fixes mid-task stop cases such as #26860 unless a trace shows the same cumulative snapshot pattern there.Additional repro — confirms the cumulative-snapshot mechanism, and it is much worse with CJK (Korean) output
Hitting the same bug on Codex CLI 0.142.3,
model_provider = amazon-bedrock, modelopenai.gpt-5.5. Wanted to add a clean repro that I think directly confirms the root-cause hypothesis in this thread (and likely ties #29755 ↔ #26305 together).Environment
0.142.3amazon-bedrock(built-in), modelopenai.gpt-5.5Symptom
A single assistant turn is rendered/persisted as ~17 separate assistant messages, each one a longer superset of the previous (the earlier text is a strict prefix of the next). Visible to the user as the same answer printed over and over, each time slightly longer.
Evidence (from the session rollout
.jsonl)Within one sampling request I see the assistant text persisted repeatedly with monotonically increasing length — i.e. cumulative stream snapshots stored as distinct
agent_messageitems instead of being coalesced:Each item's text is a strict prefix of the following item's text. This matches the maintainer's description in this thread exactly: completed Bedrock/Mantle stream snapshots are mapped 1:1 from
response.output_item.doneintoOutputItemDoneand never coalesced before history storage.CJK angle (link to #26305)
This reproduces consistently with Korean output. An equivalent English-language turn does not blow up the same way, which lines up with #26305 ("streamed Chinese/CJK output is duplicated into history → runaway token growth"). Because every duplicated snapshot is fed back into history, prompt tokens grow turn-over-turn and can exceed the model maximum.
Why it matters
Happy to share a redacted slice of the rollout
.jsonl(lengths + item ids, no payload) if that helps reproduce. Glad to provide further traces.