a3s_code_core/agent_api/
governance_facade.rs1use super::*;
2
3impl AgentSession {
4 pub fn set_budget_guard(
14 &self,
15 guard: Option<Arc<dyn crate::budget::BudgetGuard>>,
16 ) -> crate::error::Result<()> {
17 self.close_handle.mutate_immediate(|| {
18 let mut slot = self
19 .runtime_budget_guard
20 .lock()
21 .unwrap_or_else(|p| p.into_inner());
22 *slot = guard;
23 drop(slot);
24 self.refresh_task_delegation_tools();
29 self.refresh_skill_tools();
30 })
31 }
32
33 pub fn record_outcome(
37 &self,
38 outcome: crate::outcome_memory::OutcomeKind,
39 change_digest: &str,
40 constraint: &str,
41 ) -> crate::error::Result<bool> {
42 self.close_handle.mutate_immediate(|| {
43 let mut slot = self
44 .runtime_outcome_ledger
45 .lock()
46 .unwrap_or_else(|poisoned| poisoned.into_inner());
47 let mut ledger = slot
48 .clone()
49 .unwrap_or_else(|| self.config.outcome_ledger.clone());
50 let stored = match outcome {
51 crate::outcome_memory::OutcomeKind::Accept => {
52 ledger.accept(change_digest, constraint)
53 }
54 crate::outcome_memory::OutcomeKind::Revert => {
55 ledger.revert(change_digest, constraint)
56 }
57 crate::outcome_memory::OutcomeKind::Reject => {
58 ledger.reject(change_digest, constraint)
59 }
60 };
61 if stored {
62 *slot = Some(ledger);
63 }
64 stored
65 })
66 }
67
68 pub fn note_promoted_digest(&self, digest: &str) -> crate::error::Result<bool> {
70 self.close_handle.mutate_immediate(|| {
71 let mut slot = self
72 .runtime_outcome_ledger
73 .lock()
74 .unwrap_or_else(|poisoned| poisoned.into_inner());
75 let mut ledger = slot
76 .clone()
77 .unwrap_or_else(|| self.config.outcome_ledger.clone());
78 let stored = ledger.note_promoted(digest);
79 if stored {
80 *slot = Some(ledger);
81 }
82 stored
83 })
84 }
85
86 pub fn outcome_ledger_snapshot(&self) -> crate::outcome_memory::OutcomeLedger {
89 self.runtime_outcome_ledger
90 .lock()
91 .unwrap_or_else(|poisoned| poisoned.into_inner())
92 .clone()
93 .unwrap_or_else(|| self.config.outcome_ledger.clone())
94 }
95
96 pub(crate) fn outcome_ledger_override(&self) -> Option<crate::outcome_memory::OutcomeLedger> {
97 self.runtime_outcome_ledger
98 .lock()
99 .unwrap_or_else(|poisoned| poisoned.into_inner())
100 .clone()
101 }
102
103 pub fn budget_guard(&self) -> Option<Arc<dyn crate::budget::BudgetGuard>> {
106 self.runtime_budget_guard
107 .lock()
108 .unwrap_or_else(|p| p.into_inner())
109 .clone()
110 }
111
112 pub fn set_agent_style(
117 &self,
118 style: Option<crate::prompts::AgentStyle>,
119 ) -> crate::error::Result<()> {
120 self.close_handle.mutate_immediate(|| {
121 let mut slot = self
122 .runtime_agent_style
123 .lock()
124 .unwrap_or_else(|p| p.into_inner());
125 *slot = Some(style);
126 Ok(())
127 })?
128 }
129
130 pub fn set_planning_mode(
135 &self,
136 mode: crate::prompts::PlanningMode,
137 ) -> crate::error::Result<()> {
138 self.close_handle.mutate_immediate(|| {
139 let mut slot = self
140 .runtime_planning_mode
141 .lock()
142 .unwrap_or_else(|p| p.into_inner());
143 *slot = Some(mode);
144 Ok(())
145 })?
146 }
147
148 pub fn clear_planning_mode_override(&self) -> crate::error::Result<()> {
151 self.close_handle.mutate_immediate(|| {
152 let mut slot = self
153 .runtime_planning_mode
154 .lock()
155 .unwrap_or_else(|p| p.into_inner());
156 *slot = None;
157 Ok(())
158 })?
159 }
160
161 pub fn set_output_language(
166 &self,
167 language: Option<impl Into<String>>,
168 ) -> crate::error::Result<()> {
169 let language = language.map(Into::into).and_then(|value| {
170 let trimmed = value.trim();
171 (!trimmed.is_empty()).then(|| trimmed.to_string())
172 });
173 self.close_handle.mutate_immediate(|| {
174 let mut slot = self
175 .runtime_output_language
176 .lock()
177 .unwrap_or_else(|p| p.into_inner());
178 *slot = Some(language);
179 Ok(())
180 })?
181 }
182
183 pub(crate) fn runtime_agent_style_override(
186 &self,
187 ) -> Option<Option<crate::prompts::AgentStyle>> {
188 *self
189 .runtime_agent_style
190 .lock()
191 .unwrap_or_else(|p| p.into_inner())
192 }
193
194 pub(crate) fn runtime_planning_mode_override(&self) -> Option<crate::prompts::PlanningMode> {
196 *self
197 .runtime_planning_mode
198 .lock()
199 .unwrap_or_else(|p| p.into_inner())
200 }
201
202 pub(crate) fn runtime_output_language_override(&self) -> Option<Option<String>> {
205 self.runtime_output_language
206 .lock()
207 .unwrap_or_else(|p| p.into_inner())
208 .clone()
209 }
210
211 pub fn set_session_checkpoint_export_sink(
217 &self,
218 sink: Option<Arc<dyn crate::session_checkpoint::SessionCheckpointExportSink>>,
219 ) -> crate::error::Result<()> {
220 self.close_handle.mutate_immediate(|| {
221 let mut slot = self
222 .runtime_session_checkpoint_export_sink
223 .lock()
224 .unwrap_or_else(|p| p.into_inner());
225 *slot = sink;
226 })
227 }
228
229 pub fn session_checkpoint_export_sink(
231 &self,
232 ) -> Option<Arc<dyn crate::session_checkpoint::SessionCheckpointExportSink>> {
233 self.runtime_session_checkpoint_export_sink
234 .lock()
235 .unwrap_or_else(|p| p.into_inner())
236 .clone()
237 }
238
239 pub async fn pending_confirmations(&self) -> Vec<PendingConfirmationInfo> {
241 HitlControl::from_session(self)
242 .pending_confirmations()
243 .await
244 }
245
246 pub async fn confirm_tool_use(
251 &self,
252 tool_id: &str,
253 approved: bool,
254 reason: Option<String>,
255 ) -> Result<bool> {
256 if let Some(manager) = &self.config.confirmation_manager {
257 if manager
258 .confirm(tool_id, approved, reason.clone())
259 .await
260 .map_err(crate::error::CodeError::Session)?
261 {
262 return Ok(true);
263 }
264 }
265 let run = super::conversation_runtime::FactSession::from(self).open()?;
266 Ok(run.confirm_if_pending(tool_id, approved).await?)
267 }
268
269 pub async fn cancel_confirmations(&self) -> usize {
271 HitlControl::from_session(self).cancel_confirmations().await
272 }
273
274 pub fn verification_reports(&self) -> Vec<crate::verification::VerificationReport> {
276 VerificationRuntime::from_session(self).reports()
277 }
278
279 pub fn verification_summary(&self) -> crate::verification::VerificationSummary {
281 VerificationRuntime::from_session(self).summary()
282 }
283
284 pub fn verification_summary_text(&self) -> String {
286 VerificationRuntime::from_session(self).summary_text()
287 }
288
289 pub fn record_verification_reports(
291 &self,
292 reports: impl IntoIterator<Item = crate::verification::VerificationReport>,
293 ) {
294 VerificationRuntime::from_session(self).record(reports);
295 }
296
297 pub fn register_hook(&self, hook: crate::hooks::Hook) -> crate::error::Result<()> {
299 self.close_handle.mutate_immediate(|| {
300 self.ensure_compatibility_name_available(
301 crate::capability::CapabilityKind::Hook,
302 &hook.id,
303 )?;
304 HookControl::from_session(self).register_hook(hook);
305 Ok(())
306 })?
307 }
308
309 pub fn unregister_hook(
311 &self,
312 hook_id: &str,
313 ) -> crate::error::Result<Option<crate::hooks::Hook>> {
314 self.close_handle.mutate_immediate(|| {
315 self.ensure_compatibility_name_available(
316 crate::capability::CapabilityKind::Hook,
317 hook_id,
318 )?;
319 Ok(HookControl::from_session(self).unregister_hook(hook_id))
320 })?
321 }
322
323 pub fn register_hook_handler(
325 &self,
326 hook_id: &str,
327 handler: Arc<dyn crate::hooks::HookHandler>,
328 ) -> crate::error::Result<()> {
329 let mut pending_handler = Some(handler);
330 let retired = self.close_handle.mutate_immediate(|| {
331 self.ensure_compatibility_name_available(
332 crate::capability::CapabilityKind::Hook,
333 hook_id,
334 )?;
335 let handler = pending_handler.take().ok_or_else(|| {
336 crate::error::CodeError::Capability(
337 crate::capability::CapabilityRuntimeError::RuntimeValueInvalid {
338 kind: crate::capability::CapabilityKind::Hook,
339 public_name: hook_id.to_owned(),
340 message: "Hook handler mutation was already consumed".to_owned(),
341 },
342 )
343 })?;
344 Ok::<_, crate::error::CodeError>(
345 HookControl::from_session(self).register_hook_handler(hook_id, handler),
346 )
347 })??;
348 drop(retired);
349 Ok(())
350 }
351
352 pub fn unregister_hook_handler(&self, hook_id: &str) -> crate::error::Result<()> {
354 let retired = self.close_handle.mutate_immediate(|| {
355 self.ensure_compatibility_name_available(
356 crate::capability::CapabilityKind::Hook,
357 hook_id,
358 )?;
359 Ok::<_, crate::error::CodeError>(
360 HookControl::from_session(self).unregister_hook_handler(hook_id),
361 )
362 })??;
363 drop(retired);
364 Ok(())
365 }
366
367 pub fn register_hook_registration(
373 &self,
374 hook: crate::hooks::Hook,
375 handler: Option<Arc<dyn crate::hooks::HookHandler>>,
376 ) -> crate::error::Result<()> {
377 let mut pending_handler = Some(handler);
378 let retired = self.close_handle.mutate_immediate(|| {
379 self.ensure_compatibility_name_available(
380 crate::capability::CapabilityKind::Hook,
381 &hook.id,
382 )?;
383 let handler = pending_handler.take().ok_or_else(|| {
384 crate::error::CodeError::Capability(
385 crate::capability::CapabilityRuntimeError::RuntimeValueInvalid {
386 kind: crate::capability::CapabilityKind::Hook,
387 public_name: hook.id.clone(),
388 message: "Hook registration was already consumed".to_owned(),
389 },
390 )
391 })?;
392 Ok::<_, crate::error::CodeError>(
393 HookControl::from_session(self).register_hook_registration(hook, handler),
394 )
395 })??;
396 drop(retired);
397 Ok(())
398 }
399
400 pub fn unregister_hook_registration(
402 &self,
403 hook_id: &str,
404 ) -> crate::error::Result<Option<crate::hooks::Hook>> {
405 let (retired_hook, retired_handler) = self.close_handle.mutate_immediate(|| {
406 self.ensure_compatibility_name_available(
407 crate::capability::CapabilityKind::Hook,
408 hook_id,
409 )?;
410 Ok::<_, crate::error::CodeError>(
411 HookControl::from_session(self).unregister_hook_registration(hook_id),
412 )
413 })??;
414 let removed = retired_hook.as_deref().cloned();
415 drop((retired_hook, retired_handler));
416 Ok(removed)
417 }
418
419 pub fn hook_count(&self) -> usize {
421 HookControl::from_session(self).hook_count()
422 }
423
424 pub async fn verify_commands(
426 &self,
427 subject: &str,
428 commands: &[crate::verification::VerificationCommand],
429 ) -> Result<crate::verification::VerificationReport> {
430 VerificationRuntime::from_session(self)
431 .verify_commands(subject, commands)
432 .await
433 }
434
435 pub fn verification_presets(&self) -> Vec<crate::verification::VerificationPreset> {
437 VerificationRuntime::from_session(self).presets()
438 }
439}