1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4#[doc = include_str!("docs/tools.md")]
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
6pub struct ToolDefinition {
7 pub name: String,
8 pub description: String,
9 pub parameters: serde_json::Value,
10 pub server: Option<String>,
11 #[serde(default, skip_serializing_if = "Option::is_none")]
12 pub annotations: Option<ToolAnnotations>,
13}
14
15#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
16#[serde(rename_all = "camelCase")]
17pub struct ToolAnnotations {
18 pub title: Option<String>,
19 pub read_only_hint: Option<bool>,
20 pub destructive_hint: Option<bool>,
21 pub idempotent_hint: Option<bool>,
22 pub open_world_hint: Option<bool>,
23}
24
25impl ToolDefinition {
26 pub fn new(name: impl Into<String>, description: impl Into<String>, parameters: serde_json::Value) -> Self {
27 Self { name: name.into(), description: description.into(), parameters, server: None, annotations: None }
28 }
29
30 pub fn with_server(mut self, server: impl Into<String>) -> Self {
31 self.server = Some(server.into());
32 self
33 }
34
35 pub fn with_annotations(mut self, annotations: impl Into<Option<ToolAnnotations>>) -> Self {
36 self.annotations = annotations.into();
37 self
38 }
39}
40
41impl ToolAnnotations {
42 pub fn read_only() -> Self {
43 Self { read_only_hint: Some(true), ..Self::default() }
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
49pub struct ToolCallRequest {
50 pub id: String,
51 pub name: String,
52 pub arguments: String,
53}
54
55#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
57pub struct ToolCallResult {
58 pub id: String,
59 pub name: String,
60 pub arguments: String,
61 pub result: String,
62}
63
64#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
66pub struct ToolCallError {
67 pub id: String,
68 pub name: String,
69 pub arguments: Option<String>,
70 pub error: String,
71}
72
73impl ToolCallRequest {
74 pub(crate) fn input_json(&self) -> serde_json::Value {
75 serde_json::from_str(&self.arguments).unwrap_or_else(|_| serde_json::json!({}))
76 }
77}
78
79pub(crate) fn tool_result_parts(result: &Result<ToolCallResult, ToolCallError>) -> (&str, &str, bool) {
80 match result {
81 Ok(result) => (&result.id, &result.result, false),
82 Err(error) => (&error.id, &error.error, true),
83 }
84}
85
86pub(crate) fn tool_result_request(result: &Result<ToolCallResult, ToolCallError>) -> ToolCallRequest {
87 match result {
88 Ok(result) => {
89 ToolCallRequest { id: result.id.clone(), name: result.name.clone(), arguments: result.arguments.clone() }
90 }
91 Err(error) => ToolCallRequest {
92 id: error.id.clone(),
93 name: error.name.clone(),
94 arguments: error.arguments.clone().unwrap_or_default(),
95 },
96 }
97}
98
99impl ToolCallError {
100 pub fn from_request(request: &ToolCallRequest, error: impl Into<String>) -> Self {
101 Self {
102 id: request.id.clone(),
103 name: request.name.clone(),
104 arguments: Some(request.arguments.clone()),
105 error: error.into(),
106 }
107 }
108}