1use std::sync::Arc;
2
3use crate::plugin::PluginError;
4
5#[derive(Clone)]
6pub struct ToolSessionProcessAdmin<'run> {
7 pub(super) session_id: String,
8 pub(super) agent_frame_id: crate::AgentFrameId,
9 pub(super) processes: Arc<dyn crate::ProcessService>,
10 pub(super) process_cancel_ability: Arc<dyn crate::ProcessCancelAbility>,
11 pub(super) effect_controller: crate::runtime::RuntimeEffectControllerHandle<'run>,
12 pub(super) parent_invocation: Option<crate::RuntimeInvocation>,
13 pub(super) tool_call_id: Option<String>,
14 pub(super) execution_env_spec: crate::ProcessExecutionEnvSpec,
15}
16
17impl ToolSessionProcessAdmin<'_> {
18 fn process_scope(&self) -> crate::ProcessOpScope<'_> {
19 crate::ProcessOpScope::new(self.effect_controller.scoped())
20 .with_parent_invocation(self.parent_invocation.clone())
21 .with_agent_frame_id(Some(self.agent_frame_id.clone()))
22 }
23
24 pub async fn start(
30 &self,
31 mut request: crate::ProcessStartRequest,
32 ) -> Result<crate::ProcessHandleSummary, PluginError> {
33 if request.env_spec.is_none()
34 && matches!(
35 &request.input,
36 crate::ProcessInput::ToolCall { .. } | crate::ProcessInput::Engine { .. }
37 )
38 {
39 request.env_spec = Some(self.execution_env_spec.clone());
40 }
41 self.processes
42 .start_from_request(&self.session_id, request, self.process_scope())
43 .await
44 }
45
46 pub async fn complete_external(
52 &self,
53 process_id: &str,
54 await_output: crate::ProcessAwaitOutput,
55 ) -> Result<crate::ProcessRecord, PluginError> {
56 self.processes
57 .complete_external(
58 &self.session_id,
59 process_id,
60 await_output,
61 self.process_scope(),
62 )
63 .await
64 }
65
66 pub async fn await_process(
68 &self,
69 process_id: &str,
70 ) -> Result<crate::ProcessAwaitOutput, PluginError> {
71 self.processes
72 .await_process(process_id, self.process_scope())
73 .await
74 }
75
76 pub async fn list_handles(&self) -> Result<Vec<crate::ProcessHandleSummary>, PluginError> {
77 Ok(self
78 .processes
79 .list_visible(
80 &self.session_id,
81 crate::ProcessListMode::Live,
82 self.process_scope(),
83 )
84 .await?
85 .into_iter()
86 .map(crate::ProcessHandleSummary::from)
87 .collect())
88 }
89
90 pub async fn list_all_handles(&self) -> Result<Vec<crate::ProcessHandleSummary>, PluginError> {
91 Ok(self
92 .processes
93 .list_visible(
94 &self.session_id,
95 crate::ProcessListMode::All,
96 self.process_scope(),
97 )
98 .await?
99 .into_iter()
100 .map(crate::ProcessHandleSummary::from)
101 .collect())
102 }
103
104 pub async fn list_handles_filtered(
105 &self,
106 filter: &crate::ProcessListFilter,
107 ) -> Result<Vec<crate::ProcessHandleSummary>, PluginError> {
108 Ok(self
109 .processes
110 .list_visible(&self.session_id, filter.list_mode(), self.process_scope())
111 .await?
112 .into_iter()
113 .filter(|entry| filter.matches_entry(entry))
114 .map(crate::ProcessHandleSummary::from)
115 .collect())
116 }
117
118 pub async fn validate_handles(&self, handle_ids: &[String]) -> Result<(), PluginError> {
119 self.processes
120 .validate_visible(&self.session_id, handle_ids, self.process_scope())
121 .await
122 }
123
124 pub async fn cancel(
125 &self,
126 process_id: &str,
127 ) -> Result<crate::ProcessCancelSummary, PluginError> {
128 let request = crate::ProcessCancelRequest::new(
129 &self.session_id,
130 process_id,
131 self.process_scope(),
132 crate::ProcessCancelSource::Tool,
133 )
134 .with_reason("requested by tool");
135 self.process_cancel_ability
136 .cancel_summary(self.processes.as_ref(), request)
137 .await
138 }
139
140 pub async fn signal(
141 &self,
142 process_id: &str,
143 signal_name: &str,
144 payload: serde_json::Value,
145 ) -> Result<crate::ProcessEvent, PluginError> {
146 let signal_id = self
147 .tool_call_id
148 .clone()
149 .unwrap_or_else(|| format!("adhoc-{}", uuid::Uuid::new_v4()));
150 self.processes
151 .signal(
152 &self.session_id,
153 process_id,
154 signal_name.to_string(),
155 signal_id,
156 payload,
157 self.process_scope(),
158 )
159 .await
160 }
161
162 pub async fn cancel_all(&self) -> Result<Vec<crate::ProcessCancelSummary>, PluginError> {
163 self.process_cancel_ability
164 .cancel_all_visible(
165 self.processes.as_ref(),
166 crate::ProcessCancelAllRequest::new(
167 &self.session_id,
168 self.process_scope(),
169 crate::ProcessCancelSource::Tool,
170 )
171 .with_reason("requested by tool"),
172 )
173 .await
174 }
175
176 pub async fn transfer_handles(
177 &self,
178 to_session_id: &str,
179 process_ids: Vec<String>,
180 ) -> Result<(), PluginError> {
181 self.processes
182 .transfer(
183 &self.session_id,
184 to_session_id,
185 process_ids,
186 self.process_scope(),
187 )
188 .await
189 }
190
191 pub async fn transfer_handles_to_frame(
192 &self,
193 to_agent_frame_id: &str,
194 process_ids: Vec<String>,
195 ) -> Result<(), PluginError> {
196 self.processes
197 .transfer(
198 &self.session_id,
199 &self.session_id,
200 process_ids,
201 self.process_scope()
202 .with_target_agent_frame_id(Some(to_agent_frame_id.to_string())),
203 )
204 .await
205 }
206
207 pub async fn cancel_unreferenced_handles(
208 &self,
209 keep_process_ids: Vec<String>,
210 ) -> Result<Vec<crate::ProcessCancelSummary>, PluginError> {
211 Ok(self
212 .processes
213 .cancel_unreferenced(&self.session_id, keep_process_ids, self.process_scope())
214 .await?
215 .into_iter()
216 .map(crate::ProcessCancelSummary::from_record)
217 .collect())
218 }
219}