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 Pending,
78 InProgress,
80 Completed,
82 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}