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
73pub(crate) fn tool_result_parts(result: &Result<ToolCallResult, ToolCallError>) -> (&str, &str, bool) {
74 match result {
75 Ok(result) => (&result.id, &result.result, false),
76 Err(error) => (&error.id, &error.error, true),
77 }
78}
79
80impl ToolCallError {
81 pub fn from_request(request: &ToolCallRequest, error: impl Into<String>) -> Self {
82 Self {
83 id: request.id.clone(),
84 name: request.name.clone(),
85 arguments: Some(request.arguments.clone()),
86 error: error.into(),
87 }
88 }
89}