Skip to main content

talos_session/
turn_outcome.rs

1use serde::{Deserialize, Serialize};
2
3pub(crate) const TURN_TRANSCRIPT_OUTCOME_PREFIX: &str = "__TALOS_TURN_TRANSCRIPT_OUTCOME__:";
4
5/// Durable proof of the terminal transcript outcome for one runtime Turn.
6///
7/// This marker is appended only after every transcript message for the outcome
8/// has been written. Startup recovery must not infer Success from ordinary or
9/// partial transcript entries alone.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(rename_all = "snake_case")]
12pub enum TurnTranscriptOutcome {
13    Success,
14    Cancelled,
15    Error,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct TurnTranscriptOutcomeRecord {
20    pub version: u8,
21    pub turn_id: String,
22    pub outcome: TurnTranscriptOutcome,
23}
24
25impl TurnTranscriptOutcomeRecord {
26    #[must_use]
27    pub fn new(turn_id: impl Into<String>, outcome: TurnTranscriptOutcome) -> Self {
28        Self {
29            version: 1,
30            turn_id: turn_id.into(),
31            outcome,
32        }
33    }
34}
35
36pub(crate) fn encode_turn_transcript_outcome(
37    outcome: &TurnTranscriptOutcomeRecord,
38) -> Result<String, serde_json::Error> {
39    serde_json::to_string(outcome)
40        .map(|encoded| format!("{TURN_TRANSCRIPT_OUTCOME_PREFIX}{encoded}"))
41}
42
43pub(crate) fn decode_turn_transcript_outcome(content: &str) -> Option<TurnTranscriptOutcomeRecord> {
44    content
45        .strip_prefix(TURN_TRANSCRIPT_OUTCOME_PREFIX)
46        .and_then(|encoded| serde_json::from_str(encoded).ok())
47}
48
49pub(crate) fn is_turn_transcript_outcome_content(content: &str) -> bool {
50    content.starts_with(TURN_TRANSCRIPT_OUTCOME_PREFIX)
51}