agent_client_protocol/
tool_call.rs

1use std::{path::PathBuf, sync::Arc};
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use crate::ContentBlock;
7
8#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
9#[serde(rename_all = "camelCase")]
10pub struct ToolCall {
11    #[serde(rename = "toolCallId")]
12    pub id: ToolCallId,
13    pub label: String,
14    pub kind: ToolKind,
15    pub status: ToolCallStatus,
16    #[serde(default, skip_serializing_if = "Vec::is_empty")]
17    pub content: Vec<ToolCallContent>,
18    #[serde(default, skip_serializing_if = "Vec::is_empty")]
19    pub locations: Vec<ToolCallLocation>,
20    #[serde(default, skip_serializing_if = "Option::is_none")]
21    pub raw_input: Option<serde_json::Value>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
25#[serde(rename_all = "camelCase")]
26pub struct ToolCallUpdate {
27    #[serde(rename = "toolCallId")]
28    pub id: ToolCallId,
29    #[serde(flatten)]
30    pub fields: ToolCallUpdateFields,
31}
32
33#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
34#[serde(rename_all = "camelCase")]
35pub struct ToolCallUpdateFields {
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub kind: Option<ToolKind>,
38    #[serde(default, skip_serializing_if = "Option::is_none")]
39    pub status: Option<ToolCallStatus>,
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    pub label: Option<String>,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub content: Option<Vec<ToolCallContent>>,
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub locations: Option<Vec<ToolCallLocation>>,
46    #[serde(default, skip_serializing_if = "Option::is_none")]
47    pub raw_input: Option<serde_json::Value>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
51#[serde(transparent)]
52pub struct ToolCallId(pub Arc<str>);
53
54#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
55#[serde(rename_all = "camelCase")]
56pub enum ToolKind {
57    Read,
58    Edit,
59    Delete,
60    Move,
61    Search,
62    Execute,
63    Think,
64    Fetch,
65    Other,
66}
67
68#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
69#[serde(rename_all = "camelCase")]
70pub enum ToolCallStatus {
71    /// The tool call is currently running
72    Pending,
73    /// The tool call is currently running
74    InProgress,
75    /// The tool call completed successfully
76    Completed,
77    /// The tool call failed
78    Failed,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
82#[serde(tag = "type", rename_all = "camelCase")]
83pub enum ToolCallContent {
84    Content {
85        content: ContentBlock,
86    },
87    Diff {
88        #[serde(flatten)]
89        diff: Diff,
90    },
91}
92
93impl<T: Into<ContentBlock>> From<T> for ToolCallContent {
94    fn from(content: T) -> Self {
95        ToolCallContent::Content {
96            content: content.into(),
97        }
98    }
99}
100
101impl From<Diff> for ToolCallContent {
102    fn from(diff: Diff) -> Self {
103        ToolCallContent::Diff { diff }
104    }
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
108#[serde(rename_all = "camelCase")]
109pub struct Diff {
110    pub path: PathBuf,
111    pub old_text: Option<String>,
112    pub new_text: String,
113}
114
115#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
116#[serde(tag = "type", rename_all = "camelCase")]
117pub struct ToolCallLocation {
118    pub path: PathBuf,
119    #[serde(default, skip_serializing_if = "Option::is_none")]
120    pub line: Option<u32>,
121}