bamboo_domain/session/
terminal_runtime.rs1use super::Session;
5use crate::{AgentRuntimeState, AgentStatusState};
6
7const HOST_RUN_ID: &str = "runtime.host_run_id";
8
9impl Session {
10 pub fn host_run_id(&self) -> Option<&str> {
11 self.metadata.get(HOST_RUN_ID).map(String::as_str)
12 }
13
14 pub fn set_host_run_id(&mut self, run_id: &str) {
15 self.metadata.insert(HOST_RUN_ID.into(), run_id.into());
16 self.metadata.insert(
17 "runtime.host_launch_generation".into(),
18 self.child_launch_generation().to_string(),
19 );
20 if self.agent_runtime_state.is_none() {
23 self.agent_runtime_state = self
24 .metadata
25 .get("agent.runtime.state")
26 .and_then(|raw| serde_json::from_str(raw).ok());
27 }
28 if !self.has_runtime_wait() {
29 let state = self
30 .agent_runtime_state
31 .get_or_insert_with(|| AgentRuntimeState::new(&self.id));
32 state.status = AgentStatusState::Initializing;
33 if let Ok(raw) = serde_json::to_string(state) {
34 self.metadata.insert("agent.runtime.state".into(), raw);
35 }
36 }
37 }
38
39 pub fn host_run_matches_launch(&self) -> bool {
40 match self.metadata.get("runtime.host_launch_generation") {
41 Some(value) => value.parse::<u64>().ok() == Some(self.child_launch_generation()),
42 None => self.host_run_id().is_none(),
43 }
44 }
45
46 pub fn has_runtime_wait(&self) -> bool {
49 let legacy = self
50 .metadata
51 .get("agent.runtime.state")
52 .and_then(|raw| serde_json::from_str::<AgentRuntimeState>(raw).ok());
53 self.pending_question.is_some()
54 || self
55 .metadata
56 .get("runtime.suspend_reason")
57 .is_some_and(|s| !s.trim().is_empty())
58 || self
59 .agent_runtime_state
60 .as_ref()
61 .or(legacy.as_ref())
62 .is_some_and(|state| {
63 state.status == AgentStatusState::Suspended
64 || state.suspension.is_some()
65 || state.waiting_for_children.is_some()
66 || state.waiting_for_bash.is_some()
67 || state.plan_mode.as_ref().is_some_and(|plan| {
68 plan.status == crate::PlanModeStatus::AwaitingApproval
69 })
70 })
71 }
72
73 pub fn synchronize_terminal_runtime_status(&mut self) {
76 if self.has_runtime_wait() {
77 return;
78 }
79 let status = match self.last_run_status().as_deref() {
80 Some("completed" | "skipped") => AgentStatusState::Completed,
81 Some("cancelled") => AgentStatusState::Cancelled,
82 Some("error" | "failed" | "timeout") => AgentStatusState::Failed,
83 _ => return,
84 };
85 if self.agent_runtime_state.is_none() {
86 self.agent_runtime_state = self
87 .metadata
88 .get("agent.runtime.state")
89 .and_then(|raw| serde_json::from_str::<AgentRuntimeState>(raw).ok());
90 }
91 if self.agent_runtime_state.is_none()
94 && self
95 .metadata
96 .contains_key("runtime.child_completion_source_v1")
97 {
98 return;
99 }
100 let state = self
101 .agent_runtime_state
102 .get_or_insert_with(|| AgentRuntimeState::new(&self.id));
103 state.status = status;
104 state.tools.active_tool_calls = 0;
105 if let Ok(raw) = serde_json::to_string(state) {
106 self.metadata.insert("agent.runtime.state".into(), raw);
107 }
108 }
109}