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 title: 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    #[serde(default, skip_serializing_if = "Option::is_none")]
23    pub raw_output: Option<serde_json::Value>,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
27#[serde(rename_all = "camelCase")]
28pub struct ToolCallUpdate {
29    #[serde(rename = "toolCallId")]
30    pub id: ToolCallId,
31    #[serde(flatten)]
32    pub fields: ToolCallUpdateFields,
33}
34
35#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
36#[serde(rename_all = "camelCase")]
37pub struct ToolCallUpdateFields {
38    #[serde(default, skip_serializing_if = "Option::is_none")]
39    pub kind: Option<ToolKind>,
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    pub status: Option<ToolCallStatus>,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub title: Option<String>,
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub content: Option<Vec<ToolCallContent>>,
46    #[serde(default, skip_serializing_if = "Option::is_none")]
47    pub locations: Option<Vec<ToolCallLocation>>,
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    pub raw_input: Option<serde_json::Value>,
50    #[serde(default, skip_serializing_if = "Option::is_none")]
51    pub raw_output: Option<serde_json::Value>,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
55#[serde(transparent)]
56pub struct ToolCallId(pub Arc<str>);
57
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
59#[serde(rename_all = "snake_case")]
60pub enum ToolKind {
61    Read,
62    Edit,
63    Delete,
64    Move,
65    Search,
66    Execute,
67    Think,
68    Fetch,
69    Other,
70}
71
72#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
73#[serde(rename_all = "snake_case")]
74pub enum ToolCallStatus {
75    /// The tool call hasn't started running yet because the input is either
76    /// streaming or we're awaiting approval.
77    Pending,
78    /// The tool call is currently running.
79    InProgress,
80    /// The tool call completed successfully.
81    Completed,
82    /// The tool call failed.
83    Failed,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
87#[serde(tag = "type", rename_all = "snake_case")]
88pub enum ToolCallContent {
89    Content {
90        content: ContentBlock,
91    },
92    Diff {
93        #[serde(flatten)]
94        diff: Diff,
95    },
96}
97
98impl<T: Into<ContentBlock>> From<T> for ToolCallContent {
99    fn from(content: T) -> Self {
100        ToolCallContent::Content {
101            content: content.into(),
102        }
103    }
104}
105
106impl From<Diff> for ToolCallContent {
107    fn from(diff: Diff) -> Self {
108        ToolCallContent::Diff { diff }
109    }
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
113#[serde(rename_all = "camelCase")]
114pub struct Diff {
115    pub path: PathBuf,
116    pub old_text: Option<String>,
117    pub new_text: String,
118}
119
120#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
121#[serde(tag = "type", rename_all = "camelCase")]
122pub struct ToolCallLocation {
123    pub path: PathBuf,
124    #[serde(default, skip_serializing_if = "Option::is_none")]
125    pub line: Option<u32>,
126}