a3s_code_core/agent_api/run_facade.rs
1use super::*;
2
3impl AgentSession {
4 /// Submit a user direction to the active run. The request is applied by
5 /// the execution loop at its next safe point and never starts a second
6 /// conversation operation.
7 pub async fn steer(
8 &self,
9 request: crate::run_control::SteerRequest,
10 ) -> crate::error::Result<crate::run_control::RunControlReceipt> {
11 if self.is_closed() {
12 return Err(crate::error::CodeError::SessionClosed {
13 session_id: self.session_id.clone(),
14 });
15 }
16 RunControl::from_session(self).steer(request).await
17 }
18
19 /// Cooperatively interrupt the active run. Cleanup, checkpoint and
20 /// single-flight settlement still happen through the normal lifecycle.
21 pub async fn interrupt(
22 &self,
23 request: crate::run_control::InterruptRequest,
24 ) -> crate::error::Result<crate::run_control::RunControlReceipt> {
25 if self.is_closed() {
26 return Err(crate::error::CodeError::SessionClosed {
27 session_id: self.session_id.clone(),
28 });
29 }
30 RunControl::from_session(self).interrupt(request).await
31 }
32
33 /// Return the optimistic-concurrency state of the active run's control
34 /// inbox, if a run is currently executing.
35 pub async fn run_control_snapshot(&self) -> Option<crate::run_control::RunControlSnapshot> {
36 RunControl::from_session(self).run_control_snapshot().await
37 }
38
39 /// Cancel a specific run only if it is still the active run.
40 ///
41 /// This is useful for SDK callers that hold a previously observed run ID:
42 /// stale run IDs will not cancel a newer operation.
43 pub async fn cancel_run(&self, run_id: &str) -> bool {
44 RunControl::from_session(self).cancel_run(run_id).await
45 }
46
47 /// Return snapshots for runs recorded by this session.
48 pub async fn runs(&self) -> Vec<crate::run::RunSnapshot> {
49 RunControl::from_session(self).runs().await
50 }
51
52 /// Return a snapshot for a recorded run.
53 pub async fn run_snapshot(&self, run_id: &str) -> Option<crate::run::RunSnapshot> {
54 RunControl::from_session(self).run_snapshot(run_id).await
55 }
56
57 /// Return recorded runtime events for a run.
58 pub async fn run_events(&self, run_id: &str) -> Vec<crate::run::RunEventRecord> {
59 RunControl::from_session(self).run_events(run_id).await
60 }
61
62 /// Return a cursor-based page from the run's retained event window.
63 ///
64 /// `after_sequence` is exclusive. The result is `None` for an unknown run;
65 /// a known run with no retained events returns an empty page. Inspect
66 /// `retention_gap` before treating the page as complete history.
67 pub async fn run_event_page(
68 &self,
69 run_id: &str,
70 after_sequence: Option<usize>,
71 limit: usize,
72 ) -> Option<crate::run::RunEventPage> {
73 RunControl::from_session(self)
74 .run_event_page(run_id, after_sequence, limit)
75 .await
76 }
77
78 /// Return one internally consistent snapshot and event page generation.
79 pub(crate) async fn run_event_observation(
80 &self,
81 run_id: &str,
82 after_sequence: Option<usize>,
83 limit: usize,
84 ) -> Option<crate::run::RunEventObservation> {
85 RunControl::from_session(self)
86 .run_event_observation(run_id, after_sequence, limit)
87 .await
88 }
89
90 /// Return a handle for the currently running operation, if any.
91 pub async fn current_run(&self) -> Option<crate::run::RunHandle> {
92 RunControl::from_session(self).current_run().await
93 }
94
95 /// Return active tool calls observed for the currently running operation.
96 pub async fn active_tools(&self) -> Vec<crate::run::ActiveToolSnapshot> {
97 SessionView::from_session(self).active_tools().await
98 }
99
100 /// Look up a delegated subagent task by id. Returns `None` if no such task
101 /// has been observed in this session.
102 pub async fn subagent_task(
103 &self,
104 task_id: &str,
105 ) -> Option<crate::subagent_task_tracker::SubagentTaskSnapshot> {
106 self.subagent_tasks.get(task_id).await
107 }
108
109 /// Return snapshots of every delegated subagent task observed in this
110 /// session (including completed and failed ones), oldest first.
111 pub async fn subagent_tasks(&self) -> Vec<crate::subagent_task_tracker::SubagentTaskSnapshot> {
112 self.subagent_tasks.list_for_parent(&self.session_id).await
113 }
114
115 /// Return snapshots of subagent tasks still in `Running` state.
116 pub async fn pending_subagent_tasks(
117 &self,
118 ) -> Vec<crate::subagent_task_tracker::SubagentTaskSnapshot> {
119 use crate::subagent_task_tracker::SubagentStatus;
120 self.subagent_tasks
121 .list_for_parent(&self.session_id)
122 .await
123 .into_iter()
124 .filter(|task| task.status == SubagentStatus::Running)
125 .collect()
126 }
127
128 /// Cancel an in-flight delegated subagent task by id. Returns `true`
129 /// when a cancellation token was found and fired, `false` when the
130 /// task id is unknown or the task has already finished. The eventual
131 /// `SubagentEnd` from the cancelled child loop won't downgrade the
132 /// terminal status — it stays `Cancelled`.
133 pub async fn cancel_subagent_task(&self, task_id: &str) -> bool {
134 self.subagent_tasks.cancel(task_id).await
135 }
136
137 /// Return a shared handle to the session's subagent task tracker.
138 ///
139 /// Advanced: embedders implementing a custom subagent execution path
140 /// (i.e. spawning child loops outside the built-in `task` tool) can use
141 /// this to register cancellation tokens and feed `AgentEvent`s into the
142 /// tracker so the standard
143 /// [`subagent_task`](Self::subagent_task) / [`pending_subagent_tasks`](Self::pending_subagent_tasks) /
144 /// [`cancel_subagent_task`](Self::cancel_subagent_task) APIs and
145 /// [`close`](Self::close) keep working uniformly across execution paths.
146 pub fn subagent_tracker(
147 &self,
148 ) -> Arc<crate::subagent_task_tracker::InMemorySubagentTaskTracker> {
149 Arc::clone(&self.subagent_tasks)
150 }
151}