Skip to content

[Bug]: A commentary draft a Codex steer cuts off becomes the turn's answer and the real answer folds under "Worked for …" #18652

Open

Description

@devuterian

Before submitting

  • 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

  1. Use Codex (seen with gpt-6.1-sol) and send a prompt that makes the agent start a commentary message.
  2. While that first commentary is still streaming, before it finishes its first paragraph, send a Steer.
  3. Let the agent finish the turn with a full final answer.
  4. 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.

Workaround

Expand "Worked for …" to read the real answer.

Activity

  1. juliusmarminge commented on Oct 12, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    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.

  2. added
    acceptedfeature request accepted
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 12, 2026
  3. fixfon commented on Oct 13, 2026

    @fixfon
    Contributor

    Opened #19023 for this.

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

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions