Skip to main content

vtcode_core/tools/registry/
harness_facade.rs

1//! Harness context accessors for ToolRegistry.
2
3use std::future::Future;
4use std::sync::Arc;
5
6use anyhow::Result;
7use serde_json::Value;
8
9use super::HarnessContextSnapshot;
10use super::ToolRegistry;
11use crate::config::constants::tools;
12
13impl ToolRegistry {
14    /// Begin a genuine request, optionally restoring adoption from its persisted
15    /// history or explicit continuation. Internal turns must not reset this latch.
16    pub fn begin_tracker_request(&self, adopted: bool) {
17        self.harness_context
18            .tracker_adopted
19            .store(adopted, std::sync::atomic::Ordering::Relaxed);
20    }
21
22    /// Successful current-request adoption is independent of compactable history.
23    pub fn tracker_adopted_for_request(&self) -> bool {
24        self.harness_context.tracker_adopted.load(std::sync::atomic::Ordering::Relaxed)
25    }
26
27    /// Attach the canonical queue barrier used by public decision recording.
28    pub fn set_decision_evidence_validator(&self, validator: crate::core::agent::events::DecisionEvidenceValidator) {
29        *self.harness_context.decision_validator.write() = Some(validator);
30    }
31    async fn process_harness_command_session_output(&self, value: Value) -> Result<Value> {
32        let processed = self
33            .process_tool_output(
34                tools::UNIFIED_EXEC,
35                value,
36                false,
37                vtcode_utility_tool_specs::DEFAULT_MAX_OUTPUT_TOKENS,
38            )
39            .await;
40        Ok(super::normalize_tool_output(processed))
41    }
42
43    /// Update harness session identifier used for structured tool telemetry
44    pub fn set_harness_session(&self, session_id: impl Into<String>) {
45        self.harness_context.set_session_id(session_id);
46    }
47
48    /// Update current task identifier used for structured tool telemetry
49    pub fn set_harness_task(&self, task_id: Option<String>) {
50        self.harness_context.set_task_id(task_id);
51    }
52
53    /// Snapshot harness context metadata.
54    pub fn harness_context_snapshot(&self) -> HarnessContextSnapshot {
55        self.harness_context.snapshot()
56    }
57
58    /// Attach the runloop's shared per-tool circuit breaker.
59    pub fn set_shared_circuit_breaker(&self, circuit_breaker: Arc<crate::tools::circuit_breaker::CircuitBreaker>) {
60        if let Ok(mut slot) = self.shared_circuit_breaker.write() {
61            *slot = Some(circuit_breaker);
62        }
63    }
64
65    /// Return the shared per-tool circuit breaker when configured.
66    pub fn shared_circuit_breaker(&self) -> Option<Arc<crate::tools::circuit_breaker::CircuitBreaker>> {
67        self.shared_circuit_breaker.read().unwrap_or_else(|e| e.into_inner()).clone()
68    }
69
70    /// Execute a harness-owned verification command through the same exec/sandbox
71    /// runtime used by the public `command_session` tool while bypassing the
72    /// model-facing full-auto allow-list gate.
73    pub async fn execute_harness_command_session(&self, args: Value) -> Result<Value> {
74        let value = self.execute_command_session(args).await?;
75        self.process_harness_command_session_output(value).await
76    }
77
78    /// Start a harness-owned PTY command session while retaining the session metadata even when
79    /// the command exits immediately. ACP terminal sessions use explicit release semantics.
80    pub async fn execute_harness_command_session_terminal_run(&self, args: Value) -> Result<Value> {
81        let value = self.execute_harness_command_session_terminal_run_raw(args).await?;
82        self.process_harness_command_session_output(value).await
83    }
84
85    pub async fn read_harness_exec_session_output(&self, session_id: &str, drain: bool) -> Result<Option<String>> {
86        self.exec_sessions.read_session_output(session_id, drain).await
87    }
88
89    /// Inline-delegating wrapper over
90    /// [`Self::harness_exec_session_completed`].
91    /// Returns the inner future directly (audit section 16).
92    pub fn harness_exec_session_completed<'a>(
93        &'a self,
94        session_id: &'a str,
95    ) -> impl Future<Output = Result<Option<i32>>> + 'a {
96        self.exec_sessions.is_session_completed(session_id)
97    }
98
99    /// Inline-delegating wrapper over
100    /// [`Self::terminate_harness_exec_session`].
101    pub fn terminate_harness_exec_session<'a>(&'a self, session_id: &'a str) -> impl Future<Output = Result<()>> + 'a {
102        self.exec_sessions.terminate_session(session_id)
103    }
104
105    pub async fn close_harness_exec_session(&self, session_id: &str) -> Result<()> {
106        self.close_exec_session(session_id).await?;
107        Ok(())
108    }
109
110    /// Bounded snapshot of all exec sessions still running for turn-end
111    /// diagnostics and telemetry. Newest first; capped by the caller.
112    pub async fn in_progress_exec_sessions(&self, cap: usize) -> Vec<crate::tools::types::VTCodeExecSession> {
113        self.exec_sessions.in_progress_exec_sessions(cap).await
114    }
115
116    pub async fn in_progress_foreground_exec_sessions(
117        &self,
118        cap: usize,
119    ) -> Vec<crate::tools::types::VTCodeExecSession> {
120        self.exec_sessions.in_progress_foreground_exec_sessions(cap).await
121    }
122}