Expose and persist turn lineage across the app server (#51415)

## Why

Clients starting delegated work need to attribute descendant turns to the original turn and retain that attribution through completion and history reads.

## What changed

- Accept optional `parentTurnId` and `rootTurnId` in `turn/start`, and expose `rootTurnId` on returned turns and lifecycle notifications.
- Default new turns to their own root when none is supplied. Preserve the active turn's root when steering, ignoring incoming lineage fields.
- Carry root IDs through completion, interruption, recovery, and fork boundaries, and persist them for paginated history reads. Leave unknown roots null in older history.
- Update protocol schemas and generated TypeScript and Python bindings.

## Testing

Extend coverage for default and explicit roots, steering without changing lineage, interrupted and recovered turns, history reads after restart in both history modes, nested fork pagination, and compatibility with older database writers.

GitOrigin-RevId: f1a570a12bd11742929fd2e8b017e5d35aa07dcb
This commit is contained in:
Eddie Chen
2026-10-06 16:56:39 +00:00
committed by copyberry
parent ff9ab4aed9
commit cfc946f4e1
149 changed files with 896 additions and 135 deletions
+14 -4
View File
@@ -208,16 +208,23 @@ pub struct TurnStartOptions {
///
/// Started and Steered only mean Core accepted the input for turn processing. They
/// do not wait for user-prompt hooks, updating the in-memory model context,
/// rollout persistence, or sampling.
/// rollout persistence, or sampling. The returned root is the accepted turn's
/// resolved causal root, including when steering preserves an existing turn.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TurnInputSubmission {
/// Core started a turn. Persistent thread settings and start options were applied.
Started { turn_id: String },
Started {
turn_id: String,
root_turn_id: String,
},
/// Core steered an active turn. Persistent thread settings were applied for
/// subsequent turns. No new turn was created, so lineage metadata was not
/// recorded. If the request included `final_output_json_schema`, the active
/// turn already used the same schema.
Steered { turn_id: String },
Steered {
turn_id: String,
root_turn_id: String,
},
/// Core rejected the input without applying settings or start options.
NotSubmitted { reason: NotSubmittedReason },
}
@@ -226,7 +233,10 @@ pub enum TurnInputSubmission {
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum StartIfIdleSubmission {
/// Core started a turn. Persistent thread settings and start options were applied.
Started { turn_id: String },
Started {
turn_id: String,
root_turn_id: String,
},
/// Core rejected the input without applying settings or start options.
NotSubmitted { reason: NotSubmittedReason },
}