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
{{ message }}
Repository navigation
[Bug]: A commentary draft a Codex steer cuts off becomes the turn's answer and the real answer folds under "Worked for …" #18652
I searched existing issues and did not find a duplicate.
I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
Use Codex (seen with gpt-6.1-sol) and send a prompt that makes the agent start a commentary message.
While that first commentary is still streaming, before it finishes its first paragraph, send a Steer.
Let the agent finish the turn with a full final answer.
Look at the settled thread.
Expected behavior
The cut-off commentary sits where it started, before the steer, and the final answer stays visible below the "Worked for …" fold.
Actual behavior
The cut-off commentary (one unfinished sentence) shows up as the turn's answer, below the steer. The real final answer is hidden inside "Worked for …". It looks like the agent said half a sentence and stopped.
Projected turn items for the affected run (statuses all completed):
ordinal
item
written at
1000001
user prompt
12:25:34.982
1000003
steer
12:25:45.319
1000004–1000012
commentary and tool calls
12:25:52 – 12:26:42
1000013
final answer (802 chars)
12:27:08.740
1000014
cut-off commentary (59 chars)
12:27:08.760
The cut-off item's item/started came at 12:25:44.271 (phase: "commentary"), before the steer at 12:25:45.327. It never got item/completed. Codex dropped it from its rollout.
Cause
makeAssistantStreamingFilter (apps/server/src/orchestration-v2/assistantStreaming.ts) holds streaming assistant text until a paragraph boundary. The draft never reached one, so every streaming turn_item.updated for it was dropped in RunExecutionService. Its first write came from the Codex adapter's flushTurn at turn/completed. TurnItemPositionStore.allocate gives an ordinal on first write, so the draft landed after the final answer. deriveTerminalAssistantMessageIds then picked it as the run's last assistant message, and deriveTurnFolds folded the real answer.
This is separate from #15279 / #15421 (fold placement around steers) and from #17761 (superseded attempts under interrupt-and-restart steering). Codex steers within the same attempt.
Possible fix
Reserve a held turn item's position the first time it appears, even when the filter holds back its text. allocate is already ON CONFLICT DO NOTHING, so the later real write keeps the reserved ordinal. I have a small patch with a regression test in a fork, if it helps: devuterian@e487de7163
Impact
Major degradation or frequent failure
Version or commit
Reproduced on a build from nightly v0.0.46-nightly.20261009. The same code path is unchanged on main at 5753207.
Environment
macOS desktop app, Codex provider, gpt-6.1-sol, response streaming on.
I've confirmed in code on main that this is a bug. When a streaming assistant item is held back and never streams, it gets its position only when it's first written, and that first write is the end-of-turn flush.
makeAssistantStreamingFilter (apps/server/src/orchestration-v2/assistantStreaming.ts) returns null while splitBufferedAssistantText has no ready text. A draft that never reaches a paragraph boundary is never written while it streams.
TurnItemPositionStore.allocate assigns the ordinal on the first insert (ON CONFLICT DO NOTHING). The Codex flush at turn/completed therefore puts the draft after the final answer.
deriveTerminalAssistantMessageIds (apps/web/.../MessagesTimeline.logic.ts) keeps the last assistant message per run, so the cut-off draft becomes the answer and the real one gets folded.
Codex dropping the item without item/completed sets this off, but the ordering problem is ours. It's separate from #15279, #15421, #17761 and #8879.
Workaround for now: expand "Worked for …" to read the real answer.
Reserving the position when a held item first appears looks like the right direction. If you open a PR against this repo with the regression test, we'll review it there. We didn't look at the external fork link.
Activity
juliusmarminge commentedon Oct 12, 2026
Note
Grok responding on behalf of Julius.
I've confirmed in code on
mainthat this is a bug. When a streaming assistant item is held back and never streams, it gets its position only when it's first written, and that first write is the end-of-turn flush.makeAssistantStreamingFilter(apps/server/src/orchestration-v2/assistantStreaming.ts) returnsnullwhilesplitBufferedAssistantTexthas noreadytext. A draft that never reaches a paragraph boundary is never written while it streams.TurnItemPositionStore.allocateassigns the ordinal on the first insert (ON CONFLICT DO NOTHING). The Codex flush atturn/completedtherefore puts the draft after the final answer.deriveTerminalAssistantMessageIds(apps/web/.../MessagesTimeline.logic.ts) keeps the last assistant message per run, so the cut-off draft becomes the answer and the real one gets folded.Codex dropping the item without
item/completedsets this off, but the ordering problem is ours. It's separate from #15279, #15421, #17761 and #8879.Workaround for now: expand "Worked for …" to read the real answer.
Reserving the position when a held item first appears looks like the right direction. If you open a PR against this repo with the regression test, we'll review it there. We didn't look at the external fork link.
fixfon commentedon Oct 13, 2026
Opened #19023 for this.