Skip to content

feat(rollout): persist TurnItems for paginated thread rollouts - #30188

Merged
owenlin0 merged 3 commits into
mainfrom
owen/update_rollout_items2
Jul 9, 2026
Merged

feat(rollout): persist TurnItems for paginated thread rollouts#30188
owenlin0 merged 3 commits into
mainfrom
owen/update_rollout_items2

Conversation

@owenlin0

@owenlin0 owenlin0 commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Description

This PR makes new threads with history_mode = "paginated" persist ItemCompleted(item: <turn_item>) in their rollout JSONL file.

Legacy threads keep persisting the existing legacy events. Because the format is selected per thread, a rollout is either legacy or paginated; we do not need to support mixed rollouts containing both representations.

This PR depends on #31473.

Why

Paginated thread history needs stable turn/item IDs and completed item snapshots so the later SQLite projector can materialize appended rollout JSONL without rebuilding the whole thread.

Keeping the legacy persistence policy unchanged avoids changing historical rollouts or the readers that still consume them.

What changed

  • Made rollout filtering history-mode aware. Paginated threads keep completed canonical ItemCompleted events and drop their redundant legacy projections; legacy threads keep the existing event set.
  • Made forks inherit the source thread history mode, so copied legacy history is never filtered as paginated.
  • Made paginated threads assign IDs to locally-created response items even when Feature::ItemIds is off, and reject streamed output items that arrive without server IDs.
  • Updated legacy turn replay, rollout list/search, and SQLite metadata extraction to understand completed canonical user-message items.

@owenlin0
owenlin0 changed the base branch from main to owen/add_thread_history_mode June 26, 2026 05:47
@owenlin0
owenlin0 force-pushed the owen/add_thread_history_mode branch from 4d6ed79 to c80f9bc Compare June 26, 2026 15:49
Base automatically changed from owen/add_thread_history_mode to main June 26, 2026 16:12
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch 2 times, most recently from ea6d2f0 to 909898e Compare June 26, 2026 19:45
@owenlin0 owenlin0 changed the title Owen/update rollout items2 feat(rollout): persist canonical items for paginated threads Jun 26, 2026
@owenlin0
owenlin0 changed the base branch from main to owen/emit_canonical_turn_item_lifecycle June 26, 2026 19:46
@owenlin0
owenlin0 force-pushed the owen/emit_canonical_turn_item_lifecycle branch from 35c6ad7 to ee54284 Compare June 26, 2026 20:50
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from 909898e to aab46a2 Compare June 26, 2026 20:50
@owenlin0
owenlin0 force-pushed the owen/emit_canonical_turn_item_lifecycle branch from ee54284 to d581108 Compare June 26, 2026 21:13
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch 2 times, most recently from 30f1e4e to 334ca60 Compare June 26, 2026 21:18
@owenlin0
owenlin0 force-pushed the owen/emit_canonical_turn_item_lifecycle branch from d581108 to e9d6a09 Compare June 26, 2026 21:18
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from 334ca60 to dbb8f8f Compare June 26, 2026 21:22
@owenlin0
owenlin0 force-pushed the owen/emit_canonical_turn_item_lifecycle branch 2 times, most recently from 232e33c to a6f98df Compare June 26, 2026 21:43
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch 3 times, most recently from 84244e6 to 9400737 Compare June 26, 2026 22:32
@owenlin0
owenlin0 force-pushed the owen/emit_canonical_turn_item_lifecycle branch 2 times, most recently from acec956 to f691f27 Compare June 26, 2026 22:50
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from 9400737 to 22e61fc Compare June 26, 2026 22:50
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from 22e61fc to 5d24df7 Compare June 26, 2026 23:19
@owenlin0
owenlin0 force-pushed the owen/emit_canonical_turn_item_lifecycle branch from 9fd1ae2 to 9f2d003 Compare June 26, 2026 23:19
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from 5d24df7 to ae5828a Compare June 26, 2026 23:29
@owenlin0
owenlin0 force-pushed the owen/emit_canonical_turn_item_lifecycle branch from d3204c7 to 3041d21 Compare June 26, 2026 23:32
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from ae5828a to f3fdff2 Compare June 26, 2026 23:32
@owenlin0
owenlin0 force-pushed the owen/emit_canonical_turn_item_lifecycle branch from 3041d21 to 5d4da6f Compare June 26, 2026 23:47
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from f3fdff2 to 20eca18 Compare June 26, 2026 23:47

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b5a2836e9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread codex-rs/app-server/src/request_processors.rs
Comment thread codex-rs/core/src/event_mapping.rs Outdated
Comment thread codex-rs/rollout/src/policy.rs Outdated
Comment thread codex-rs/rollout/src/policy.rs Outdated
@owenlin0 owenlin0 changed the title feat(rollout): persist canonical items for paginated threads feat(rollout): persist TurnItems for paginated thread rollouts Jul 7, 2026
@owenlin0
owenlin0 force-pushed the owen/canonical-collab-wait-items branch 3 times, most recently from 2b0d949 to 0a7db2f Compare July 7, 2026 20:21
owenlin0 added a commit that referenced this pull request Jul 7, 2026
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from 3a00fe8 to 2f22bf2 Compare July 7, 2026 20:24
@owenlin0
owenlin0 force-pushed the owen/canonical-collab-wait-items branch from 0a7db2f to 252ff86 Compare July 7, 2026 20:39
owenlin0 added a commit that referenced this pull request Jul 7, 2026
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from 2f22bf2 to 04d8fb3 Compare July 7, 2026 20:39
owenlin0 added a commit that referenced this pull request Jul 7, 2026
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from 04d8fb3 to a8564eb Compare July 7, 2026 20:45
@owenlin0
owenlin0 changed the base branch from owen/canonical-collab-wait-items to main July 7, 2026 20:45
owenlin0 added a commit that referenced this pull request Jul 7, 2026
This PR depends on [#31296](#31296)
for the canonical-to-legacy event mappings.

## Description

This PR makes the v1 and v2 wait paths emit canonical
`TurnItem::CollabAgentToolCall` lifecycle instead of
`CollabWaitingBegin` / `CollabWaitingEnd` directly.

Both paths already used the same legacy waiting events before this PR.
The v1 item carries receiver metadata and final agent statuses for its
target agents; v2 waits for mailbox activity rather than specific
agents, so it keeps those fields empty, matching the existing v2 legacy
payload.

App-server v2 consumes the canonical item directly and ignores the
mapped legacy wait events.

## Why

Wait is separate from the other collab tools because it is multi-target
and has distinct timeout/status behavior. Keeping it last also lets this
PR remove the old helper that only existed to shape legacy wait status
entries in core.

## What changed

- Emit canonical collab wait items from both v1 and v2 wait handlers.
- Preserve receiver metadata and agent status snapshots on completed
wait items.
- Remove the old core helper for building legacy wait status entries.

## Follow-up

The next stack PR, [#30188](#30188),
writes canonical `TurnItem` values to paginated rollout files.
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch from e5549ae to 3932937 Compare July 7, 2026 21:43
@owenlin0
owenlin0 changed the base branch from main to owen/stable-review-event-ids July 7, 2026 21:44
@owenlin0
owenlin0 force-pushed the owen/stable-review-event-ids branch from ec3e03c to 089106f Compare July 7, 2026 21:54
@owenlin0
owenlin0 force-pushed the owen/update_rollout_items2 branch 2 times, most recently from 6e5adfb to 4beb4f0 Compare July 7, 2026 22:17
@owenlin0
owenlin0 force-pushed the owen/stable-review-event-ids branch from 089106f to 9aad937 Compare July 7, 2026 22:41

@wiltzius-openai wiltzius-openai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thread store changes look OK

we have been discussing whether we should move the metadata update back into the thread store implementations though, @miz-openai may wanna do that but this doesn't make it any easier/harder

Comment thread codex-rs/core/src/session/turn.rs Outdated
match event {
ResponseEvent::Created => {}
ResponseEvent::OutputItemDone(item) => {
if let Err(err) = validate_streamed_response_item_id(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a pretty brutal error to return from the agent loop

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that's fair. updated so that we generate an ID and assign it ourselves if missing

if let Some(preview) = event_msg_preview(&ev) {
let is_user_message = match &ev {
EventMsg::UserMessage(_) => true,
EventMsg::ItemCompleted(event) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't EventMsg::ItemCompleted always emited? can we leave only it ?

@owenlin0 owenlin0 Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately not yet, it's one or the other atm (between legacy and paginated mode). will have to migrate legacy threads first before we can remove

|| matches!(event.item, TurnItem::Plan(_) | TurnItem::Sleep(_))
}
EventMsg::TokenCount(_)
| EventMsg::ThreadGoalUpdated(_)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prob should be an item

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah... have to think about this one a bit. looks like turn_id can be none for this event

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filed a ticket to look into it

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants