Skip to main content

vtcode_core/tools/registry/
harness_facade.rs

1//! Harness context accessors for ToolRegistry.
2
3use std::sync::Arc;
4
5use anyhow::Result;
6use serde_json::Value;
7
8use super::HarnessContextSnapshot;
9use super::ToolRegistry;
10use crate::config::constants::tools;
11
12impl ToolRegistry {
13    /// Begin a genuine request, optionally restoring adoption from its persisted
14    /// history or explicit continuation. Internal turns must not reset this latch.
15    pub fn begin_tracker_request(&self, adopted: bool) {
16        self.execution_history.begin_tracker_request();
17        if !adopted {
18            self.set_required_completion_verifiers(Vec::new());
19        }
20        self.harness_context
21            .tracker_adopted
22            .store(adopted, std::sync::atomic::Ordering::Relaxed);
23    }
24
25    /// Successful current-request adoption is independent of compactable history.
26    pub fn tracker_adopted_for_request(&self) -> bool {
27        self.harness_context.tracker_adopted.load(std::sync::atomic::Ordering::Relaxed)
28    }
29
30    /// Attach the canonical queue barrier used by public decision recording.
31    pub fn set_decision_evidence_validator(&self, validator: crate::core::agent::events::DecisionEvidenceValidator) {
32        *self.harness_context.decision_validator.write() = Some(validator);
33    }
34    async fn process_harness_command_session_output(&self, value: Value) -> Result<Value> {
35        let processed = self
36            .process_tool_output(
37                tools::UNIFIED_EXEC,
38                value,
39                false,
40                vtcode_utility_tool_specs::DEFAULT_MAX_OUTPUT_TOKENS,
41            )
42            .await;
43        Ok(super::normalize_tool_output(processed))
44    }
45
46    /// Update harness session identifier used for structured tool telemetry
47    pub fn set_harness_session(&self, session_id: impl Into<String>) {
48        self.harness_context.set_session_id(session_id);
49    }
50
51    /// Update current task identifier used for structured tool telemetry
52    pub fn set_harness_task(&self, task_id: Option<String>) {
53        self.harness_context.set_task_id(task_id);
54    }
55
56    /// Snapshot harness context metadata.
57    pub fn harness_context_snapshot(&self) -> HarnessContextSnapshot {
58        self.harness_context.snapshot()
59    }
60
61    /// Attach the runloop's shared per-tool circuit breaker.
62    pub fn set_shared_circuit_breaker(&self, circuit_breaker: Arc<crate::tools::circuit_breaker::CircuitBreaker>) {
63        if let Ok(mut slot) = self.shared_circuit_breaker.write() {
64            *slot = Some(circuit_breaker);
65        }
66    }
67
68    /// Return the shared per-tool circuit breaker when configured.
69    pub fn shared_circuit_breaker(&self) -> Option<Arc<crate::tools::circuit_breaker::CircuitBreaker>> {
70        self.shared_circuit_breaker.read().unwrap_or_else(|e| e.into_inner()).clone()
71    }
72
73    /// Grant an exact, single-use inspection exemption for a command supplied
74    /// directly by a trusted user. Model tool approval must never call this.
75    pub fn trusted_user_command_exemption(
76        &self,
77        args: &Value,
78    ) -> Result<crate::tools::source_inspection::TrustedCommandExemption> {
79        let cwd = self
80            .pty_manager()
81            .working_dir_candidate(crate::tools::command_args::working_dir_text(args))?;
82        Ok(self
83            .edited_file_monitor_ref()
84            .source_inspection()
85            .scoped_user_command(args, &cwd))
86    }
87
88    /// Execute a harness-owned verification command through the same exec/sandbox
89    /// runtime used by the public `command_session` tool while bypassing the
90    /// model-facing full-auto allow-list gate.
91    pub async fn execute_harness_command_session(&self, args: Value) -> Result<Value> {
92        let value = self.execute_command_session(args).await?;
93        self.process_harness_command_session_output(value).await
94    }
95
96    /// Start a harness-owned PTY command session while retaining the session metadata even when
97    /// the command exits immediately. ACP terminal sessions use explicit release semantics.
98    pub async fn execute_harness_command_session_terminal_run(&self, args: Value) -> Result<Value> {
99        let launch = self.begin_completion_verifier(&args);
100        let result = self.execute_harness_command_session_terminal_run_raw(args.clone()).await;
101        self.observe_completion_verifier(launch, &args, &result);
102        let value = result?;
103        self.observe_completion_mutation(tools::EXEC_COMMAND, &args, &value);
104        self.process_harness_command_session_output(value).await
105    }
106
107    pub async fn read_harness_exec_session_output(&self, session_id: &str, drain: bool) -> Result<Option<String>> {
108        self.exec_sessions.read_session_output(session_id, drain).await
109    }
110
111    /// Observe the owned native terminal session's actual exit for runtime verification.
112    pub async fn harness_exec_session_completed(&self, session_id: &str) -> Result<Option<i32>> {
113        let result = self.exec_sessions.is_session_completed(session_id).await;
114        if let Ok(Some(exit_code)) = result {
115            self.observe_completion_verifier(
116                None,
117                &serde_json::json!({"action":"wait", "session_id":session_id}),
118                &Ok(serde_json::json!({"exit_code":exit_code})),
119            );
120        }
121        result
122    }
123
124    /// Terminate an owned session and retire any active mutation boundary.
125    pub async fn terminate_harness_exec_session(&self, session_id: &str) -> Result<()> {
126        let result = self.exec_sessions.terminate_session(session_id).await;
127        if result.is_ok() {
128            self.observe_completion_verifier(
129                None,
130                &serde_json::json!({"action":"close", "session_id":session_id}),
131                &Ok(serde_json::json!({"success":true})),
132            );
133        }
134        result
135    }
136
137    pub async fn close_harness_exec_session(&self, session_id: &str) -> Result<()> {
138        self.close_exec_session(session_id).await?;
139        self.observe_completion_verifier(
140            None,
141            &serde_json::json!({"action":"close", "session_id":session_id}),
142            &Ok(serde_json::json!({"success":true})),
143        );
144        Ok(())
145    }
146
147    /// Bounded snapshot of all exec sessions still running for turn-end
148    /// diagnostics and telemetry. Newest first; capped by the caller.
149    pub async fn in_progress_exec_sessions(&self, cap: usize) -> Vec<crate::tools::types::VTCodeExecSession> {
150        self.exec_sessions.in_progress_exec_sessions(cap).await
151    }
152
153    pub async fn in_progress_foreground_exec_sessions(
154        &self,
155        cap: usize,
156    ) -> Vec<crate::tools::types::VTCodeExecSession> {
157        self.exec_sessions.in_progress_foreground_exec_sessions(cap).await
158    }
159}