Skip to main content

vtcode_acp/
reports.rs

1use crate::acp;
2use serde_json::{Value, json};
3use std::path::PathBuf;
4
5pub const TOOL_FAILURE_PREFIX: &str = "Tool execution failed";
6pub const TOOL_SUCCESS_LABEL: &str = "success";
7pub const TOOL_ERROR_LABEL: &str = "error";
8pub const TOOL_RESPONSE_KEY_STATUS: &str = "status";
9pub const TOOL_RESPONSE_KEY_TOOL: &str = "tool";
10pub const TOOL_RESPONSE_KEY_PATH: &str = "path";
11pub const TOOL_RESPONSE_KEY_CONTENT: &str = "content";
12pub const TOOL_RESPONSE_KEY_TRUNCATED: &str = "truncated";
13pub const TOOL_RESPONSE_KEY_MESSAGE: &str = "message";
14
15pub const TOOL_EXECUTION_CANCELLED_MESSAGE: &str =
16    "Tool execution cancelled at the client's request";
17pub const TOOL_PERMISSION_ALLOW_OPTION_ID: &str = "allow-once";
18pub const TOOL_PERMISSION_ALLOW_ALWAYS_OPTION_ID: &str = "allow-always";
19pub const TOOL_PERMISSION_DENY_OPTION_ID: &str = "reject-once";
20pub const TOOL_PERMISSION_DENY_ALWAYS_OPTION_ID: &str = "reject-always";
21pub const TOOL_PERMISSION_ALLOW_PREFIX: &str = "Allow";
22pub const TOOL_PERMISSION_DENY_PREFIX: &str = "Deny";
23pub const TOOL_PERMISSION_DENIED_MESSAGE: &str =
24    "Tool execution cancelled: permission denied by the user";
25pub const TOOL_PERMISSION_CANCELLED_MESSAGE: &str =
26    "Tool execution cancelled: permission request interrupted";
27pub const TOOL_PERMISSION_REQUEST_FAILURE_LOG: &str =
28    "Failed to request ACP tool permission, cancelling the tool invocation";
29pub const TOOL_PERMISSION_UNKNOWN_OPTION_LOG: &str =
30    "Received unsupported ACP permission option selection";
31pub const TOOL_PERMISSION_REQUEST_FAILURE_MESSAGE: &str =
32    "Tool execution cancelled: permission request failed";
33
34pub struct ToolExecutionReport {
35    pub status: acp::ToolCallStatus,
36    pub llm_response: String,
37    pub content: Vec<acp::ToolCallContent>,
38    pub locations: Vec<acp::ToolCallLocation>,
39    pub raw_output: Option<Value>,
40}
41
42impl ToolExecutionReport {
43    pub fn success(
44        content: Vec<acp::ToolCallContent>,
45        locations: Vec<acp::ToolCallLocation>,
46        payload: Value,
47    ) -> Self {
48        Self {
49            status: acp::ToolCallStatus::Completed,
50            llm_response: payload.to_string(),
51            content,
52            locations,
53            raw_output: Some(payload),
54        }
55    }
56
57    pub fn failure(tool_name: &str, message: &str) -> Self {
58        let payload = json!({
59            TOOL_RESPONSE_KEY_STATUS: TOOL_ERROR_LABEL,
60            TOOL_RESPONSE_KEY_TOOL: tool_name,
61            TOOL_RESPONSE_KEY_MESSAGE: message,
62        });
63        Self {
64            status: acp::ToolCallStatus::Failed,
65            llm_response: payload.to_string(),
66            content: vec![acp::ToolCallContent::from(format!(
67                "{TOOL_FAILURE_PREFIX}: {message}"
68            ))],
69            locations: Vec::new(),
70            raw_output: Some(payload),
71        }
72    }
73
74    pub fn cancelled(tool_name: &str) -> Self {
75        Self::failure(tool_name, TOOL_EXECUTION_CANCELLED_MESSAGE)
76    }
77}
78
79pub fn create_diff_content(
80    path: &str,
81    old_text: Option<&str>,
82    new_text: &str,
83) -> acp::ToolCallContent {
84    acp::ToolCallContent::Diff(
85        acp::Diff::new(PathBuf::from(path), new_text.to_string())
86            .old_text(old_text.map(|s| s.to_string())),
87    )
88}