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}
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 title: 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 = "snake_case")]
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 = "snake_case")]
70pub enum ToolCallStatus {
71 Pending,
74 InProgress,
76 Completed,
78 Failed,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
83#[serde(tag = "type", rename_all = "snake_case")]
84pub enum ToolCallContent {
85 Content {
86 content: ContentBlock,
87 },
88 Diff {
89 #[serde(flatten)]
90 diff: Diff,
91 },
92}
93
94impl<T: Into<ContentBlock>> From<T> for ToolCallContent {
95 fn from(content: T) -> Self {
96 ToolCallContent::Content {
97 content: content.into(),
98 }
99 }
100}
101
102impl From<Diff> for ToolCallContent {
103 fn from(diff: Diff) -> Self {
104 ToolCallContent::Diff { diff }
105 }
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
109#[serde(rename_all = "camelCase")]
110pub struct Diff {
111 pub path: PathBuf,
112 pub old_text: Option<String>,
113 pub new_text: String,
114}
115
116#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
117#[serde(tag = "type", rename_all = "camelCase")]
118pub struct ToolCallLocation {
119 pub path: PathBuf,
120 #[serde(default, skip_serializing_if = "Option::is_none")]
121 pub line: Option<u32>,
122}