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    async fn process_harness_unified_exec_output(&self, value: Value) -> Result<Value> {
15        let processed = self
16            .process_tool_output(tools::UNIFIED_EXEC, value, false)
17            .await;
18        Ok(super::normalize_tool_output(processed))
19    }
20
21    /// Update harness session identifier used for structured tool telemetry
22    pub fn set_harness_session(&self, session_id: impl Into<String>) {
23        self.harness_context.set_session_id(session_id);
24    }
25
26    /// Update current task identifier used for structured tool telemetry
27    pub fn set_harness_task(&self, task_id: Option<String>) {
28        self.harness_context.set_task_id(task_id);
29    }
30
31    /// Snapshot harness context metadata.
32    pub fn harness_context_snapshot(&self) -> HarnessContextSnapshot {
33        self.harness_context.snapshot()
34    }
35
36    /// Attach the runloop's shared per-tool circuit breaker.
37    pub fn set_shared_circuit_breaker(
38        &self,
39        circuit_breaker: Arc<crate::tools::circuit_breaker::CircuitBreaker>,
40    ) {
41        if let Ok(mut slot) = self.shared_circuit_breaker.write() {
42            *slot = Some(circuit_breaker);
43        }
44    }
45
46    /// Return the shared per-tool circuit breaker when configured.
47    pub fn shared_circuit_breaker(
48        &self,
49    ) -> Option<Arc<crate::tools::circuit_breaker::CircuitBreaker>> {
50        self.shared_circuit_breaker
51            .read()
52            .ok()
53            .and_then(|g| g.clone())
54    }
55
56    /// Execute a harness-owned verification command through the same exec/sandbox
57    /// runtime used by the public `unified_exec` tool while bypassing the
58    /// model-facing full-auto allow-list gate.
59    pub async fn execute_harness_unified_exec(&self, args: Value) -> Result<Value> {
60        let value = self.execute_unified_exec(args).await?;
61        self.process_harness_unified_exec_output(value).await
62    }
63
64    /// Start a harness-owned PTY command session while retaining the session metadata even when
65    /// the command exits immediately. ACP terminal sessions use explicit release semantics.
66    pub async fn execute_harness_unified_exec_terminal_run(&self, args: Value) -> Result<Value> {
67        let value = self
68            .execute_harness_unified_exec_terminal_run_raw(args)
69            .await?;
70        self.process_harness_unified_exec_output(value).await
71    }
72
73    pub async fn read_harness_exec_session_output(
74        &self,
75        session_id: &str,
76        drain: bool,
77    ) -> Result<Option<String>> {
78        self.exec_sessions
79            .read_session_output(session_id, drain)
80            .await
81    }
82
83    /// Inline-delegating wrapper over
84    /// [`Self::harness_exec_session_completed`].
85    /// Returns the inner future directly (audit section 16).
86    pub fn harness_exec_session_completed<'a>(
87        &'a self,
88        session_id: &'a str,
89    ) -> impl Future<Output = Result<Option<i32>>> + 'a {
90        self.exec_sessions.is_session_completed(session_id)
91    }
92
93    /// Inline-delegating wrapper over
94    /// [`Self::terminate_harness_exec_session`].
95    pub fn terminate_harness_exec_session<'a>(
96        &'a self,
97        session_id: &'a str,
98    ) -> impl Future<Output = Result<()>> + 'a {
99        self.exec_sessions.terminate_session(session_id)
100    }
101
102    pub async fn close_harness_exec_session(&self, session_id: &str) -> Result<()> {
103        self.close_exec_session(session_id).await?;
104        Ok(())
105    }
106}