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
+19 -5
View File
@@ -4512,7 +4512,9 @@ async fn open_thread_persistence(session: &mut Session) -> PathBuf {
async fn attach_thread_persistence(session: &mut Session) -> PathBuf {
let rollout_path = open_thread_persistence(session).await;
session.ensure_rollout_materialized().await;
session
.ensure_rollout_materialized(PersistContext::Standard)
.await;
session
.flush_rollout()
.await
@@ -9655,7 +9657,9 @@ async fn record_context_updates_and_set_reference_context_item_persists_baseline
serde_json::to_value(Some(turn_context.to_turn_context_item()))
.expect("serialize expected context item")
);
session.ensure_rollout_materialized().await;
session
.ensure_rollout_materialized(PersistContext::Standard)
.await;
session.flush_rollout().await.expect("rollout should flush");
let InitialHistory::Resumed(resumed) = RolloutRecorder::get_rollout_history(&rollout_path)
@@ -9698,7 +9702,9 @@ async fn record_context_updates_and_set_reference_context_item_persists_split_fi
.record_context_updates_and_set_reference_context_item(&step_context)
.await
.expect("world state should build");
session.ensure_rollout_materialized().await;
session
.ensure_rollout_materialized(PersistContext::Standard)
.await;
session.flush_rollout().await.expect("rollout should flush");
let InitialHistory::Resumed(resumed) = RolloutRecorder::get_rollout_history(&rollout_path)
@@ -9786,7 +9792,9 @@ async fn record_context_updates_and_set_reference_context_item_persists_full_rei
.record_context_updates_and_set_reference_context_item(&step_context)
.await
.expect("world state should build");
session.ensure_rollout_materialized().await;
session
.ensure_rollout_materialized(PersistContext::Standard)
.await;
session.flush_rollout().await.expect("rollout should flush");
let InitialHistory::Resumed(resumed) = RolloutRecorder::get_rollout_history(&rollout_path)
@@ -10007,7 +10015,13 @@ async fn failed_user_message_persistence_stops_turn_processing() {
];
assert!(
super::turn::run_hooks_and_record_inputs(&session, &turn_context, &input).await,
super::turn::run_hooks_and_record_inputs(
&session,
&turn_context,
&input,
PersistContext::Standard,
)
.await,
"a rollout flush failure should stop turn processing"
);
assert!(matches!(