feat(core): emit canonical review mode items (#31473)

## Description

This PR moves review-mode markers onto canonical `TurnItem` lifecycle:

- `TurnItem::EnteredReviewMode`
- `TurnItem::ExitedReviewMode`

Core now emits `ItemStarted` / `ItemCompleted` for both. The completed
items map back into the existing `EnteredReviewMode` /
`ExitedReviewMode` events, so raw core event consumers and legacy
rollout persistence keep seeing the old events.

This is the compatibility layer needed before paginated rollouts persist
review markers as `ItemCompleted(TurnItem)`.

## Why

Review markers were one of the remaining app-server thread items created
directly from legacy events. Giving them canonical items lets paginated
history persist stable turn/item IDs without changing legacy rollouts.

## What changed

- Added canonical review-mode `TurnItem`s and switched review flow to
emit their lifecycle.
- Added completed-item → legacy review event mappings with stable
turn/item IDs.
- Switched app-server live notifications to the generic canonical item
path and kept legacy replay compatible with old payloads.
- Updated `ThreadHistoryBuilder` to replay canonical review items even
though review turns still do not emit `TurnStarted`.
This commit is contained in:
Owen Lin authored and GitHub committed 2026-07-08 09:59:50 -07:00
1 parent a219b6fdb4
commit 23aac925e7
17 files changed
+458 -153

No files matched your search

@@ -10,6 +10,7 @@ use super::UserInput;
use super::shared::v2_enum_from_core;
use crate::protocol::item_builders::command_actions_for_path_uri;
use crate::protocol::item_builders::convert_patch_changes;
use crate::protocol::item_builders::review_output_text;
use codex_experimental_api_macros::ExperimentalApi;
use codex_extension_items::ExtensionItem;
pub use codex_extension_items::image_generation::ImageGenerationItem;
@@ -923,6 +924,14 @@ impl From<CoreTurnItem> for ThreadItem {
saved_path: image.saved_path,
})
}
CoreTurnItem::EnteredReviewMode(review) => ThreadItem::EnteredReviewMode {
id: review.id,
review: review.user_facing_hint,
},
CoreTurnItem::ExitedReviewMode(review) => ThreadItem::ExitedReviewMode {
id: review.id,
review: review_output_text(review.review_output.as_ref()),
},
CoreTurnItem::FileChange(file_change) => ThreadItem::FileChange {
id: file_change.id,
changes: convert_patch_changes(&file_change.changes),