Skip to main content

talos_session/
durable_recovery.rs

1use crate::{DurableSession, SessionError};
2
3impl DurableSession {
4    /// Returns transcript evidence associated with one Turn.
5    ///
6    /// Model-visible entry IDs are returned when present. A hidden terminal
7    /// outcome marker contributes one synthetic evidence token so the Actor's
8    /// existing startup path invokes the journal classifier even for an Error,
9    /// Cancelled, or empty successful Turn. The pending journal then maps the
10    /// authoritative outcome to Committed, TerminalError, or TerminalCancelled.
11    /// No message or outcome evidence returns an empty vector and remains frozen.
12    pub fn committed_turn_entry_ids(&self, turn_id: &str) -> Result<Vec<String>, SessionError> {
13        if turn_id.is_empty() {
14            return Err(SessionError::DurableTurn(
15                "turn_id must not be empty".into(),
16            ));
17        }
18
19        let mut cursor: Option<String> = None;
20        let mut evidence = Vec::new();
21        loop {
22            let page = self.transcript(cursor.as_deref(), 200)?;
23            if page.is_empty() {
24                break;
25            }
26            cursor = page.last().map(|entry| entry.entry_id.clone());
27            evidence.extend(
28                page.into_iter()
29                    .filter(|entry| entry.turn_id.as_deref() == Some(turn_id))
30                    .map(|entry| entry.entry_id),
31            );
32        }
33        if self
34            .session()
35            .read_turn_transcript_outcomes()?
36            .into_iter()
37            .any(|record| record.turn_id == turn_id)
38            && evidence.is_empty()
39        {
40            evidence.push(format!("terminal-outcome:{turn_id}"));
41        }
42        Ok(evidence)
43    }
44}