Distinguish turn-start thread persistence (#37926)

## What changed

- Add `PersistContext` to the thread-store persistence contract so stores can
  identify persistence requested immediately before model sampling. A
  `TurnStart` request may be enqueued in the background when later flush and
  shutdown operations fence it and report any failure; all other persistence
  remains synchronous.
- Use the turn-start context only for the initial input of a regular turn, while
  admission acknowledgments, steered input, and other persistence paths keep
  the standard durability behavior.
- Flush pending metadata before turn-start persistence and ensure shutdown is
  still attempted if that metadata update fails.

## Testing

- Verify that developer instructions and user input are persisted before the
  model request completes for a default paginated-history thread.

GitOrigin-RevId: 162f0ec796a61aebe66ca0b909fbcccec3047b85
This commit is contained in:
Bryan Ashley
2026-08-11 03:35:45 +00:00
committed by copyberry
parent f8821d85eb
commit 722784e936
24 changed files with 289 additions and 75 deletions
+5
View File
@@ -38,6 +38,7 @@ use codex_protocol::protocol::HookStartedEvent;
use codex_protocol::protocol::SessionSource;
use codex_protocol::protocol::SubAgentSource;
use codex_protocol::protocol::WarningEvent;
use codex_thread_store::PersistContext;
use codex_thread_store::ReadThreadParams;
use serde_json::Value;
use tracing::instrument;
@@ -582,6 +583,7 @@ pub(crate) async fn record_pending_input(
turn_context: &Arc<TurnContext>,
pending_input: TurnInput,
additional_contexts: Vec<String>,
persist_context: PersistContext,
) -> Result<(), TryStartTurnIfIdleRejectionReason> {
match pending_input {
TurnInput::UserInput { content, client_id } => {
@@ -596,10 +598,12 @@ pub(crate) async fn record_pending_input(
.filter(|task| Arc::ptr_eq(&task.turn_context, turn_context))
.and_then(|task| task.input_persisted.take());
if awaiting_admission || input_persisted.is_some() {
// An admission acknowledgment always requires synchronous persistence.
sess.record_user_prompt_and_emit_turn_item(
turn_context.as_ref(),
content.as_slice(),
client_id.clone(),
PersistContext::Standard,
)
.await;
record_additional_contexts(sess, turn_context, additional_contexts).await;
@@ -640,6 +644,7 @@ pub(crate) async fn record_pending_input(
turn_context.as_ref(),
content.as_slice(),
client_id,
persist_context,
)
.await;
}