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 Pending,
73 InProgress,
75 Completed,
77 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}