Skip to main content

objectiveai_sdk/agent/
continuation.rs

1use base64::Engine;
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4
5/// Continuation state for multi-turn agent completions.
6///
7/// Returned in the final streaming chunk and in unary responses.
8/// Pass it back in the next request to continue the conversation.
9/// Serialized as base64-encoded JSON.
10#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
11#[serde(untagged)]
12#[schemars(rename = "agent.Continuation")]
13pub enum Continuation {
14    #[schemars(title = "Openrouter")]
15    Openrouter(super::openrouter::Continuation),
16    #[schemars(title = "ClaudeAgentSdk")]
17    ClaudeAgentSdk(super::claude_agent_sdk::Continuation),
18    #[schemars(title = "CodexSdk")]
19    CodexSdk(super::codex_sdk::Continuation),
20    #[schemars(title = "Mock")]
21    Mock(super::mock::Continuation),
22    #[schemars(title = "Script")]
23    Script(super::script::Continuation),
24}
25
26impl From<super::openrouter::Continuation> for Continuation {
27    fn from(inner: super::openrouter::Continuation) -> Self {
28        Self::Openrouter(inner)
29    }
30}
31
32impl From<super::claude_agent_sdk::Continuation> for Continuation {
33    fn from(inner: super::claude_agent_sdk::Continuation) -> Self {
34        Self::ClaudeAgentSdk(inner)
35    }
36}
37
38impl From<super::codex_sdk::Continuation> for Continuation {
39    fn from(inner: super::codex_sdk::Continuation) -> Self {
40        Self::CodexSdk(inner)
41    }
42}
43
44impl From<super::mock::Continuation> for Continuation {
45    fn from(inner: super::mock::Continuation) -> Self {
46        Self::Mock(inner)
47    }
48}
49
50impl From<super::script::Continuation> for Continuation {
51    fn from(inner: super::script::Continuation) -> Self {
52        Self::Script(inner)
53    }
54}
55
56impl Continuation {
57    /// Full slash-separated lineage of the agent this continuation
58    /// belongs to. See per-upstream struct docs for the semantic.
59    /// Empty string if the continuation was minted before this field
60    /// existed (pre-field tokens deserialize the default).
61    pub fn agent_instance_hierarchy(&self) -> &str {
62        match self {
63            Self::Openrouter(c) => c.agent_instance_hierarchy.as_str(),
64            Self::ClaudeAgentSdk(c) => c.agent_instance_hierarchy.as_str(),
65            Self::CodexSdk(c) => c.agent_instance_hierarchy.as_str(),
66            Self::Mock(c) => c.agent_instance_hierarchy.as_str(),
67            Self::Script(c) => c.agent_instance_hierarchy.as_str(),
68        }
69    }
70
71    /// Stamps `agent_instance_hierarchy` on the outgoing continuation.
72    /// The api server calls this just before returning the wire
73    /// continuation so the next round inherits the same lineage.
74    pub fn set_agent_instance_hierarchy(&mut self, id: String) {
75        match self {
76            Self::Openrouter(c) => c.agent_instance_hierarchy = id,
77            Self::ClaudeAgentSdk(c) => c.agent_instance_hierarchy = id,
78            Self::CodexSdk(c) => c.agent_instance_hierarchy = id,
79            Self::Mock(c) => c.agent_instance_hierarchy = id,
80            Self::Script(c) => c.agent_instance_hierarchy = id,
81        }
82    }
83
84    /// Returns the upstream type for this continuation.
85    pub fn upstream(&self) -> super::Upstream {
86        match self {
87            Self::Openrouter(_) => super::Upstream::Openrouter,
88            Self::ClaudeAgentSdk(_) => super::Upstream::ClaudeAgentSdk,
89            Self::CodexSdk(_) => super::Upstream::CodexSdk,
90            Self::Mock(_) => super::Upstream::Mock,
91            Self::Script(_) => super::Upstream::Script,
92        }
93    }
94
95    /// Serializes the continuation to a base64-encoded string.
96    pub fn to_string(&self) -> String {
97        let json = serde_json::to_string(self).unwrap();
98        base64::engine::general_purpose::STANDARD.encode(json)
99    }
100
101    /// Attempts to deserialize a continuation from a base64-encoded string.
102    pub fn try_from_string(s: &str) -> Option<Self> {
103        let json = base64::engine::general_purpose::STANDARD.decode(s).ok()?;
104        let continuation = serde_json::from_slice(&json).ok()?;
105        Some(continuation)
106    }
107}