1use crate::{ToolCall, ToolResult, ToolSchema};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ToolMetadata {
10 pub name: String,
11 pub description: String,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub category: Option<String>,
14 #[serde(default, skip_serializing_if = "Vec::is_empty")]
15 pub tags: Vec<String>,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub version: Option<String>,
18 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
19 pub extra: HashMap<String, serde_json::Value>,
20}
21
22impl ToolMetadata {
23 pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
24 Self {
25 name: name.into(),
26 description: description.into(),
27 category: None,
28 tags: Vec::new(),
29 version: None,
30 extra: HashMap::new(),
31 }
32 }
33
34 pub fn with_category(mut self, category: impl Into<String>) -> Self {
35 self.category = Some(category.into());
36 self
37 }
38
39 pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
40 self.tags.push(tag.into());
41 self
42 }
43
44 pub fn with_tags<I, S>(mut self, tags: I) -> Self
45 where
46 I: IntoIterator<Item = S>,
47 S: Into<String>,
48 {
49 self.tags.extend(tags.into_iter().map(|t| t.into()));
50 self
51 }
52
53 pub fn with_version(mut self, version: impl Into<String>) -> Self {
54 self.version = Some(version.into());
55 self
56 }
57}
58
59pub trait Tool: Send + Sync {
61 fn metadata(&self) -> ToolMetadata;
62 fn schema(&self) -> ToolSchema;
63 fn name(&self) -> &str {
64 "unknown"
65 }
66}
67
68pub trait FromToolCall: Tool + Sized {
70 fn from_tool_call(call: &ToolCall) -> ToolResult<Self>;
71}