Skip to main content

vtcode_core/tools/registry/
execution_request.rs

1use serde_json::Value;
2use std::time::Duration;
3use vtcode_commons::ErrorCategory;
4
5use super::ToolExecutionError;
6
7/// Controls how unified exec calls should settle before returning to the caller.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9pub enum ExecSettlementMode {
10    /// Return on the first yield boundary and require explicit follow-up poll/continue calls.
11    #[default]
12    Manual,
13    /// Keep polling pipe-backed sessions until they reach a terminal state.
14    SettleNonInteractive,
15}
16
17impl ExecSettlementMode {
18    #[must_use]
19    pub fn settle_noninteractive(self) -> bool {
20        matches!(self, Self::SettleNonInteractive)
21    }
22}
23
24/// Runtime execution policy snapshot for a single tool call.
25#[derive(Debug, Clone)]
26pub struct ExecutionPolicySnapshot {
27    /// Maximum retry attempts after the initial attempt.
28    pub max_retries: usize,
29    /// Base exponential backoff delay.
30    pub retry_base_delay: Duration,
31    /// Maximum retry backoff delay.
32    pub retry_max_delay: Duration,
33    /// Retry backoff multiplier.
34    pub retry_multiplier: f64,
35    /// Retry jitter ratio in [0.0, 1.0].
36    pub retry_jitter: f64,
37    /// When true, caller already ran preflight validation.
38    pub prevalidated: bool,
39    /// Optional invocation id for cross-surface correlation.
40    pub invocation_id: Option<String>,
41    /// How command_session should settle before returning.
42    pub exec_settlement_mode: ExecSettlementMode,
43    /// Whether caller already completed safety gateway admission.
44    pub safety_prevalidated: bool,
45}
46
47impl Default for ExecutionPolicySnapshot {
48    fn default() -> Self {
49        Self {
50            max_retries: 0,
51            retry_base_delay: Duration::from_millis(200),
52            retry_max_delay: Duration::from_secs(2),
53            retry_multiplier: 2.0,
54            retry_jitter: 0.0,
55            prevalidated: false,
56            invocation_id: None,
57            exec_settlement_mode: ExecSettlementMode::Manual,
58            safety_prevalidated: false,
59        }
60    }
61}
62
63impl ExecutionPolicySnapshot {
64    #[must_use]
65    pub fn with_max_retries(mut self, max_retries: usize) -> Self {
66        self.max_retries = max_retries;
67        self
68    }
69
70    #[must_use]
71    pub fn with_prevalidated(mut self, prevalidated: bool) -> Self {
72        self.prevalidated = prevalidated;
73        self
74    }
75
76    #[must_use]
77    pub fn with_invocation_id(mut self, invocation_id: Option<String>) -> Self {
78        self.invocation_id = invocation_id;
79        self
80    }
81
82    #[must_use]
83    pub fn with_exec_settlement_mode(mut self, mode: ExecSettlementMode) -> Self {
84        self.exec_settlement_mode = mode;
85        self
86    }
87
88    #[must_use]
89    pub fn with_safety_prevalidated(mut self, safety_prevalidated: bool) -> Self {
90        self.safety_prevalidated = safety_prevalidated;
91        self
92    }
93}
94
95/// Canonical tool execution request routed through ToolRegistry kernel.
96#[derive(Debug, Clone)]
97pub struct ToolExecutionRequest {
98    pub tool_name: String,
99    pub args: Value,
100    pub policy: ExecutionPolicySnapshot,
101}
102
103impl ToolExecutionRequest {
104    #[must_use]
105    pub fn new(tool_name: impl Into<String>, args: Value) -> Self {
106        Self {
107            tool_name: tool_name.into(),
108            args,
109            policy: ExecutionPolicySnapshot::default(),
110        }
111    }
112
113    #[must_use]
114    pub fn with_policy(mut self, policy: ExecutionPolicySnapshot) -> Self {
115        self.policy = policy;
116        self
117    }
118}
119
120/// Canonical execution result for shared runtime adapters.
121#[derive(Debug, Clone)]
122pub struct ToolExecutionOutcome {
123    pub tool_name: String,
124    pub attempts: u32,
125    pub total_duration: Duration,
126    pub last_error_category: Option<ErrorCategory>,
127    pub output: Option<Value>,
128    pub error: Option<ToolExecutionError>,
129}
130
131impl ToolExecutionOutcome {
132    #[must_use]
133    pub fn success(tool_name: impl Into<String>, attempts: u32, output: Value) -> Self {
134        Self {
135            tool_name: tool_name.into(),
136            attempts,
137            total_duration: Duration::ZERO,
138            last_error_category: None,
139            output: Some(output),
140            error: None,
141        }
142    }
143
144    #[must_use]
145    pub fn failure(tool_name: impl Into<String>, attempts: u32, error: ToolExecutionError) -> Self {
146        let last_error_category = Some(error.category);
147        Self {
148            tool_name: tool_name.into(),
149            attempts,
150            total_duration: Duration::ZERO,
151            last_error_category,
152            output: None,
153            error: Some(error),
154        }
155    }
156
157    #[must_use]
158    pub fn with_execution_metadata(
159        mut self,
160        total_duration: Duration,
161        last_error_category: Option<ErrorCategory>,
162    ) -> Self {
163        self.total_duration = total_duration;
164        if last_error_category.is_some() {
165            self.last_error_category = last_error_category;
166        }
167        self
168    }
169
170    #[must_use]
171    pub fn is_success(&self) -> bool {
172        self.error.is_none()
173    }
174}