Skip to main content

tokitai_core/
lib.rs

1//! # Tokitai Core
2//!
3//! **Core types for Tokitai - Compile-time tool definitions with zero runtime dependencies**
4//!
5//! This crate provides the fundamental types and traits for the Tokitai AI tool integration system.
6//! All tool information is generated at compile time, ensuring zero runtime overhead and maximum
7//! type safety.
8//!
9//! ## 🎯 Key Features
10//!
11//! - **Zero Runtime Dependencies** - Core types have minimal dependencies
12//! - **`no_std` Support** - Works in embedded environments (when `serde` feature is disabled)
13//! - **Type Safety** - Compile-time tool definitions prevent runtime errors
14//! - **Serde Integration** - Optional serialization support via the `serde` feature
15//!
16//! ## Core Types
17//!
18//! - [`ToolDefinition`] - Tool definition containing name, description, and input schema
19//! - [`ToolParameter`] - Parameter definition for tools
20//! - [`ParamType`] - JSON Schema type enumeration
21//! - [`ToolError`] - Error type for tool invocation failures
22//! - [`ToolErrorKind`] - Classification of tool errors
23//! - [`ToolProvider`] - Trait for tool providers (auto-implemented by `#[tool]` macro)
24//!
25//! ## Usage Example
26//!
27//! ```rust
28//! use tokitai_core::ToolDefinition;
29//!
30//! // Create a tool definition
31//! let tool = ToolDefinition::new(
32//!     "add",
33//!     "Add two numbers together",
34//!     r#"{"type":"object","properties":{"a":{"type":"integer"},"b":{"type":"integer"}},"required":["a","b"]}"#
35//! );
36//!
37//! assert_eq!(tool.name, "add");
38//! assert_eq!(tool.description, "Add two numbers together");
39//!
40//! // With serde feature enabled, convert to JSON
41//! #[cfg(feature = "serde")]
42//! {
43//!     let json = tool.to_json().unwrap();
44//!     assert!(json.contains("\"name\":\"add\""));
45//! }
46//! ```
47//!
48//! ## No-Std Support
49//!
50//! This crate supports `no_std` environments when the `serde` feature is disabled:
51//!
52//! ```toml
53//! [dependencies]
54//! tokitai-core = { version = "0.4.0", default-features = false }
55//! ```
56//!
57//! ## Type Mapping
58//!
59//! The [`ParamType`] enum maps Rust types to JSON Schema types:
60//!
61//! | Rust Type | JSON Schema Type | `ParamType` Variant |
62//! |-----------|------------------|---------------------|
63//! | `String`, `&str` | `string` | `ParamType::String` |
64//! | `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64` | `integer` | `ParamType::Integer` |
65//! | `f32`, `f64` | `number` | `ParamType::Number` |
66//! | `bool` | `boolean` | `ParamType::Boolean` |
67//! | `Vec<T>` | `array` | `ParamType::Array` |
68//! | Custom structs | `object` | `ParamType::Object` |
69//!
70//! ```rust
71//! use tokitai_core::ParamType;
72//!
73//! assert_eq!(ParamType::from_rust_type("String"), Some(ParamType::String));
74//! assert_eq!(ParamType::from_rust_type("i32"), Some(ParamType::Integer));
75//! assert_eq!(ParamType::from_rust_type("f64"), Some(ParamType::Number));
76//! assert_eq!(ParamType::from_rust_type("bool"), Some(ParamType::Boolean));
77//! assert_eq!(ParamType::from_rust_type("Vec<i32>"), Some(ParamType::Array));
78//! ```
79//!
80//! ## Error Handling
81//!
82//! The [`ToolError`] type provides structured error handling for tool invocations:
83//!
84//! ```rust
85//! use tokitai_core::{ToolError, ToolErrorKind};
86//!
87//! // Create different error types
88//! let validation_err = ToolError::validation_error("Missing required parameter 'city'");
89//! assert_eq!(validation_err.kind, ToolErrorKind::ValidationError);
90//!
91//! let not_found_err = ToolError::not_found("Tool 'unknown_tool' not found");
92//! assert_eq!(not_found_err.kind, ToolErrorKind::NotFound);
93//!
94//! let internal_err = ToolError::internal_error("Connection timeout");
95//! assert_eq!(internal_err.kind, ToolErrorKind::InternalError);
96//! ```
97//!
98//! ## Tool Provider Trait
99//!
100//! The [`ToolProvider`] trait is automatically implemented by the `#[tool]` macro:
101//!
102//! ```rust
103//! use tokitai_core::ToolProvider;
104//!
105//! // After using #[tool] macro on your type:
106//! // struct Calculator;
107//! // #[tool] impl Calculator { ... }
108//!
109//! // Get all tool definitions
110//! // let tools = Calculator::tool_definitions();
111//!
112//! // Get tool count
113//! // let count = Calculator::tool_count();
114//!
115//! // Find a specific tool
116//! // let tool = Calculator::find_tool("add");
117//! ```
118//!
119//! ## JSON Schema Macro
120//!
121//! The `json_schema!` macro helps generate JSON Schema strings at compile time:
122//!
123//! ```rust,ignore
124//! use tokitai_core::json_schema;
125//!
126//! const SCHEMA: &str = json_schema!({
127//!     "city": {
128//!         type: String,
129//!         description: "Name of the city",
130//!         required: true,
131//!     }
132//! });
133//! ```
134//!
135//! ## Features
136//!
137//! | Feature | Description |
138//! |---------|-------------|
139//! | `serde` (default) | Enable serde serialization and JSON support |
140//!
141//! ## Requirements
142//!
143//! - **Rust Version**: 1.70+
144//! - **Edition**: 2021
145//!
146//! ## License
147//!
148//! Licensed under either of:
149//!
150//! - Apache License, Version 2.0 ([LICENSE-APACHE](https://github.com/silverenternal/tokitai/blob/main/LICENSE))
151//! - MIT License ([LICENSE-MIT](https://github.com/silverenternal/tokitai/blob/main/LICENSE))
152//!
153//! at your option.
154//!
155//! ## Contributing
156//!
157//! Unless you explicitly state otherwise, any contribution intentionally submitted
158//! for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be
159//! dual licensed as above, without any additional terms or conditions.
160//!
161//! ## See Also
162//!
163//! - [`tokitai`](https://crates.io/crates/tokitai) - Main crate with runtime support
164//! - [`tokitai-macros`](https://crates.io/crates/tokitai-macros) - Procedural macros
165
166#![cfg_attr(not(feature = "serde"), no_std)]
167#![allow(dead_code)]
168
169#[cfg(feature = "serde")]
170extern crate serde;
171
172#[cfg(feature = "serde")]
173extern crate alloc;
174
175#[cfg(feature = "serde")]
176pub use serde_types::*;
177
178#[cfg(feature = "serde")]
179pub use config::{ToolConfig, ToolConfigRegistry, GLOBAL_CONFIG_REGISTRY};
180
181/// # Tool Definition
182///
183/// Represents a tool that can be called by an AI system.
184///
185/// This struct is typically generated automatically by the `#[tool]` macro,
186/// so manual creation is rarely needed.
187///
188/// ## Fields
189///
190/// - `name` - The tool identifier used for AI recognition
191/// - `description` - Human-readable description helping AI understand the tool's purpose
192/// - `input_schema` - JSON Schema string for parameter validation
193///
194/// ## Example
195///
196/// ```rust
197/// use tokitai_core::ToolDefinition;
198///
199/// let tool = ToolDefinition::new("add", "Add two numbers", r#"{"type":"object"}"#);
200/// assert_eq!(tool.name, "add");
201/// ```
202#[derive(Debug, Clone)]
203#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
204pub struct ToolDefinition {
205    /// Tool name used for identification during AI calls
206    #[cfg(feature = "serde")]
207    pub name: alloc::string::String,
208    #[cfg(not(feature = "serde"))]
209    pub name: &'static str,
210    /// Tool description helping AI understand its purpose
211    #[cfg(feature = "serde")]
212    pub description: alloc::string::String,
213    #[cfg(not(feature = "serde"))]
214    pub description: &'static str,
215    /// Input parameter JSON Schema (compile-time generated string)
216    #[cfg(feature = "serde")]
217    pub input_schema: alloc::string::String,
218    #[cfg(not(feature = "serde"))]
219    pub input_schema: &'static str,
220    /// Tool version (optional)
221    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
222    #[cfg(feature = "serde")]
223    pub version: Option<alloc::string::String>,
224    #[cfg(not(feature = "serde"))]
225    pub version: Option<&'static str>,
226    /// Version since when the tool is deprecated (optional)
227    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
228    #[cfg(feature = "serde")]
229    pub deprecated_since: Option<alloc::string::String>,
230    #[cfg(not(feature = "serde"))]
231    pub deprecated_since: Option<&'static str>,
232    /// Version when the tool will be removed (optional)
233    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
234    #[cfg(feature = "serde")]
235    pub remove_in: Option<alloc::string::String>,
236    #[cfg(not(feature = "serde"))]
237    pub remove_in: Option<&'static str>,
238    /// Tool that replaces this deprecated tool (optional)
239    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
240    #[cfg(feature = "serde")]
241    pub replaced_by: Option<alloc::string::String>,
242    #[cfg(not(feature = "serde"))]
243    pub replaced_by: Option<&'static str>,
244}
245
246/// Internal struct for compile-time tool definition data
247///
248/// This is used to store tool definitions as `&'static str` at compile time,
249/// then convert to `ToolDefinition` at runtime with zero allocation.
250#[doc(hidden)]
251pub struct ToolDefinitionConst {
252    pub name: &'static str,
253    pub description: &'static str,
254    pub input_schema: &'static str,
255}
256
257impl ToolDefinition {
258    /// Create a new tool definition from compile-time constants
259    ///
260    /// This is optimized for compile-time generated code where all strings
261    /// are `'static`. The conversion to `ToolDefinition` happens at runtime
262    /// but with zero allocation since we're just copying references.
263    ///
264    /// # Parameters
265    ///
266    /// - `name` - Tool name
267    /// - `description` - Tool description
268    /// - `input_schema` - JSON Schema string
269    ///
270    /// # Example
271    ///
272    /// ```rust
273    /// use tokitai_core::{ToolDefinition, ToolDefinitionConst};
274    ///
275    /// const TOOL_DATA: ToolDefinitionConst = ToolDefinitionConst {
276    ///     name: "get_weather",
277    ///     description: "Get weather information for a specified city",
278    ///     input_schema: r#"{"type":"object"}"#,
279    /// };
280    ///
281    /// let tool = ToolDefinition::from_const(TOOL_DATA);
282    /// ```
283    #[inline(always)]
284    pub fn from_const(data: ToolDefinitionConst) -> Self {
285        Self {
286            #[cfg(feature = "serde")]
287            name: data.name.into(),
288            #[cfg(not(feature = "serde"))]
289            name: data.name,
290            #[cfg(feature = "serde")]
291            description: data.description.into(),
292            #[cfg(not(feature = "serde"))]
293            description: data.description,
294            #[cfg(feature = "serde")]
295            input_schema: data.input_schema.into(),
296            #[cfg(not(feature = "serde"))]
297            input_schema: data.input_schema,
298            version: None,
299            deprecated_since: None,
300            remove_in: None,
301            replaced_by: None,
302        }
303    }
304
305    /// Create a new tool definition (runtime version)
306    ///
307    /// # Parameters
308    ///
309    /// - `name` - Tool name
310    /// - `description` - Tool description
311    /// - `input_schema` - JSON Schema string
312    ///
313    /// # Example
314    ///
315    /// ```rust
316    /// use tokitai_core::ToolDefinition;
317    ///
318    /// let tool = ToolDefinition::new(
319    ///     "get_weather",
320    ///     "Get weather information for a specified city",
321    ///     r#"{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}"#
322    /// );
323    /// ```
324    #[cfg(feature = "serde")]
325    pub fn new(
326        name: impl Into<alloc::string::String>,
327        description: impl Into<alloc::string::String>,
328        input_schema: impl Into<alloc::string::String>,
329    ) -> Self {
330        Self {
331            name: name.into(),
332            description: description.into(),
333            input_schema: input_schema.into(),
334            version: None,
335            deprecated_since: None,
336            remove_in: None,
337            replaced_by: None,
338        }
339    }
340
341    /// Create a new tool definition (no_std version)
342    #[cfg(not(feature = "serde"))]
343    pub fn new(
344        name: &'static str,
345        description: &'static str,
346        input_schema: &'static str,
347    ) -> Self {
348        Self {
349            name,
350            description,
351            input_schema,
352            version: None,
353            deprecated_since: None,
354            remove_in: None,
355            replaced_by: None,
356        }
357    }
358
359    /// Set the tool version
360    #[cfg(feature = "serde")]
361    pub fn with_version(mut self, version: impl Into<alloc::string::String>) -> Self {
362        self.version = Some(version.into());
363        self
364    }
365
366    /// Set the tool version (no_std version)
367    #[cfg(not(feature = "serde"))]
368    pub fn with_version(mut self, version: &'static str) -> Self {
369        self.version = Some(version);
370        self
371    }
372
373    /// Set deprecation information
374    #[cfg(feature = "serde")]
375    pub fn with_deprecated(
376        mut self,
377        deprecated_since: impl Into<alloc::string::String>,
378        remove_in: impl Into<alloc::string::String>,
379        replaced_by: impl Into<alloc::string::String>,
380    ) -> Self {
381        self.deprecated_since = Some(deprecated_since.into());
382        self.remove_in = Some(remove_in.into());
383        self.replaced_by = Some(replaced_by.into());
384        self
385    }
386
387    /// Set deprecation information (no_std version)
388    #[cfg(not(feature = "serde"))]
389    pub fn with_deprecated(
390        mut self,
391        deprecated_since: &'static str,
392        remove_in: &'static str,
393        replaced_by: &'static str,
394    ) -> Self {
395        self.deprecated_since = Some(deprecated_since);
396        self.remove_in = Some(remove_in);
397        self.replaced_by = Some(replaced_by);
398        self
399    }
400
401    /// Convert to JSON string (requires `serde` feature)
402    #[cfg(feature = "serde")]
403    pub fn to_json(&self) -> Result<String, serde_json::Error> {
404        serde_json::to_string(self)
405    }
406
407    /// Convert to JSON Value (requires `serde` feature)
408    #[cfg(feature = "serde")]
409    pub fn to_value(&self) -> Result<serde_json::Value, serde_json::Error> {
410        serde_json::to_value(self)
411    }
412
413    /// Get input schema as pretty-printed JSON string (requires `serde` feature)
414    #[cfg(feature = "serde")]
415    pub fn input_schema_pretty(&self) -> Result<String, serde_json::Error> {
416        let value: serde_json::Value = serde_json::from_str(&self.input_schema)?;
417        serde_json::to_string_pretty(&value)
418    }
419
420    /// Get input schema as JSON Value (requires `serde` feature)
421    #[cfg(feature = "serde")]
422    pub fn input_schema_value(&self) -> Result<serde_json::Value, serde_json::Error> {
423        serde_json::from_str(&self.input_schema)
424    }
425
426    /// Apply configurations to this tool definition.
427    ///
428    /// This method is used by the configuration system to apply runtime
429    /// configurations to tool definitions generated at compile time.
430    ///
431    /// # Parameters
432    ///
433    /// - `configs` - Slice of configuration items to apply
434    ///
435    /// # Example
436    ///
437    /// ```rust
438    /// use tokitai_core::{ToolDefinition, ToolConfig};
439    ///
440    /// let mut tool = ToolDefinition::new("test", "Original description", "{}");
441    /// tool.apply_configs(&[
442    ///     ToolConfig::Desc("Overridden description".to_string()),
443    /// ]);
444    /// assert_eq!(tool.description, "Overridden description");
445    /// ```
446    #[cfg(feature = "serde")]
447    pub fn apply_configs(&mut self, configs: &[ToolConfig]) {
448        for config in configs {
449            match config {
450                ToolConfig::Desc(desc) => {
451                    self.description = desc.clone();
452                }
453                ToolConfig::Tags(tags) => {
454                    // Add tags to the schema
455                    if let Ok(mut schema) =
456                        serde_json::from_str::<serde_json::Value>(&self.input_schema)
457                    {
458                        if let Some(obj) = schema.as_object_mut() {
459                            obj.insert("tags".to_string(), serde_json::json!(tags));
460                        }
461                        self.input_schema = schema.to_string();
462                    }
463                }
464                ToolConfig::ParamDesc { name, desc } => {
465                    self.apply_param_desc(name, desc);
466                }
467                ToolConfig::ParamExample { name, example } => {
468                    self.apply_param_example(name, example);
469                }
470                ToolConfig::ParamDefault { name, default } => {
471                    self.apply_param_default(name, default);
472                }
473                ToolConfig::ParamRequired { name, required } => {
474                    self.apply_param_required(name, *required);
475                }
476                ToolConfig::ParamMin { name, min } => {
477                    self.apply_param_constraint(name, "minimum", serde_json::json!(min));
478                }
479                ToolConfig::ParamMax { name, max } => {
480                    self.apply_param_constraint(name, "maximum", serde_json::json!(max));
481                }
482                ToolConfig::ParamMinLength { name, min_length } => {
483                    self.apply_param_constraint(name, "minLength", serde_json::json!(min_length));
484                }
485                ToolConfig::ParamMaxLength { name, max_length } => {
486                    self.apply_param_constraint(name, "maxLength", serde_json::json!(max_length));
487                }
488                ToolConfig::ParamPattern { name, pattern } => {
489                    self.apply_param_constraint(name, "pattern", serde_json::json!(pattern));
490                }
491                ToolConfig::ParamMinItems { name, min_items } => {
492                    self.apply_param_constraint(name, "minItems", serde_json::json!(min_items));
493                }
494                ToolConfig::ParamMaxItems { name, max_items } => {
495                    self.apply_param_constraint(name, "maxItems", serde_json::json!(max_items));
496                }
497                ToolConfig::ParamMultipleOf { name, multiple_of } => {
498                    self.apply_param_constraint(name, "multipleOf", serde_json::json!(multiple_of));
499                }
500            }
501        }
502    }
503
504    /// Apply parameter description to the schema.
505    #[cfg(feature = "serde")]
506    fn apply_param_desc(&mut self, name: &str, desc: &str) {
507        if let Ok(mut schema) = serde_json::from_str::<serde_json::Value>(&self.input_schema) {
508            if let Some(obj) = schema.as_object_mut() {
509                if let Some(props) = obj.get_mut("properties").and_then(|v| v.as_object_mut()) {
510                    if let Some(param) = props.get_mut(name).and_then(|v| v.as_object_mut()) {
511                        param.insert("description".to_string(), serde_json::json!(desc));
512                    }
513                }
514            }
515            self.input_schema = schema.to_string();
516        }
517    }
518
519    /// Apply parameter example to the schema.
520    #[cfg(feature = "serde")]
521    fn apply_param_example(&mut self, name: &str, example: &serde_json::Value) {
522        if let Ok(mut schema) = serde_json::from_str::<serde_json::Value>(&self.input_schema) {
523            if let Some(obj) = schema.as_object_mut() {
524                if let Some(props) = obj.get_mut("properties").and_then(|v| v.as_object_mut()) {
525                    if let Some(param) = props.get_mut(name).and_then(|v| v.as_object_mut()) {
526                        param.insert("example".to_string(), example.clone());
527                    }
528                }
529            }
530            self.input_schema = schema.to_string();
531        }
532    }
533
534    /// Apply parameter default to the schema.
535    #[cfg(feature = "serde")]
536    fn apply_param_default(&mut self, name: &str, default: &serde_json::Value) {
537        if let Ok(mut schema) = serde_json::from_str::<serde_json::Value>(&self.input_schema) {
538            if let Some(obj) = schema.as_object_mut() {
539                if let Some(props) = obj.get_mut("properties").and_then(|v| v.as_object_mut()) {
540                    if let Some(param) = props.get_mut(name).and_then(|v| v.as_object_mut()) {
541                        param.insert("default".to_string(), default.clone());
542                    }
543                }
544            }
545            self.input_schema = schema.to_string();
546        }
547    }
548
549    /// Apply parameter required flag to the schema.
550    #[cfg(feature = "serde")]
551    fn apply_param_required(&mut self, name: &str, required: bool) {
552        if let Ok(mut schema) = serde_json::from_str::<serde_json::Value>(&self.input_schema) {
553            if let Some(obj) = schema.as_object_mut() {
554                // Update required array
555                let required_arr = obj
556                    .entry("required".to_string())
557                    .or_insert_with(|| serde_json::json!([]))
558                    .as_array_mut();
559
560                if let Some(req_arr) = required_arr {
561                    let name_json = serde_json::json!(name);
562                    if required && !req_arr.contains(&name_json) {
563                        req_arr.push(name_json);
564                    } else if !required {
565                        req_arr.retain(|v| v != &name_json);
566                    }
567                }
568
569                // Also update parameter schema
570                if let Some(props) = obj.get_mut("properties").and_then(|v| v.as_object_mut()) {
571                    if let Some(param) = props.get_mut(name).and_then(|v| v.as_object_mut()) {
572                        // Note: individual param "required" is not standard JSON Schema
573                        // but we can add it for documentation purposes
574                        param.insert("required".to_string(), serde_json::json!(required));
575                    }
576                }
577            }
578            self.input_schema = schema.to_string();
579        }
580    }
581
582    /// Apply a constraint to a parameter in the schema.
583    #[cfg(feature = "serde")]
584    fn apply_param_constraint(
585        &mut self,
586        name: &str,
587        constraint_key: &str,
588        value: serde_json::Value,
589    ) {
590        if let Ok(mut schema) = serde_json::from_str::<serde_json::Value>(&self.input_schema) {
591            if let Some(obj) = schema.as_object_mut() {
592                if let Some(props) = obj.get_mut("properties").and_then(|v| v.as_object_mut()) {
593                    if let Some(param) = props.get_mut(name).and_then(|v| v.as_object_mut()) {
594                        param.insert(constraint_key.to_string(), value);
595                    }
596                }
597            }
598            self.input_schema = schema.to_string();
599        }
600    }
601}
602
603impl core::fmt::Display for ToolDefinition {
604    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
605        write!(f, "{}: {}", self.name, self.description)
606    }
607}
608
609/// # Parameter Type
610///
611/// Represents JSON Schema types for tool parameters.
612///
613/// ## Example
614///
615/// ```rust
616/// use tokitai_core::ParamType;
617///
618/// assert_eq!(ParamType::from_rust_type("String"), Some(ParamType::String));
619/// assert_eq!(ParamType::from_rust_type("i32"), Some(ParamType::Integer));
620/// assert_eq!(ParamType::Integer.as_str(), "integer");
621/// ```
622#[derive(Debug, Clone, Copy, PartialEq, Eq)]
623#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
624#[repr(u8)]
625pub enum ParamType {
626    /// String type
627    String = 0,
628    /// Integer type
629    Integer = 1,
630    /// Number type (floating point)
631    Number = 2,
632    /// Boolean type
633    Boolean = 3,
634    /// Array type
635    Array = 4,
636    /// Object type
637    Object = 5,
638}
639
640impl ParamType {
641    /// Get the JSON Schema type string
642    ///
643    /// # Example
644    ///
645    /// ```rust
646    /// use tokitai_core::ParamType;
647    ///
648    /// assert_eq!(ParamType::String.as_str(), "string");
649    /// assert_eq!(ParamType::Integer.as_str(), "integer");
650    /// ```
651    pub fn as_str(&self) -> &'static str {
652        match self {
653            ParamType::String => "string",
654            ParamType::Integer => "integer",
655            ParamType::Number => "number",
656            ParamType::Boolean => "boolean",
657            ParamType::Array => "array",
658            ParamType::Object => "object",
659        }
660    }
661
662    /// Infer parameter type from Rust type name
663    ///
664    /// # Parameters
665    ///
666    /// - `type_name` - Rust type name (e.g., `"String"`, `"i32"`, `"Vec<i32>"`)
667    ///
668    /// # Example
669    ///
670    /// ```rust
671    /// use tokitai_core::ParamType;
672    ///
673    /// assert_eq!(ParamType::from_rust_type("String"), Some(ParamType::String));
674    /// assert_eq!(ParamType::from_rust_type("i32"), Some(ParamType::Integer));
675    /// assert_eq!(ParamType::from_rust_type("f64"), Some(ParamType::Number));
676    /// assert_eq!(ParamType::from_rust_type("bool"), Some(ParamType::Boolean));
677    /// assert_eq!(ParamType::from_rust_type("Vec<i32>"), Some(ParamType::Array));
678    /// ```
679    pub fn from_rust_type(type_name: &str) -> Option<Self> {
680        match type_name {
681            "String" | "str" => Some(ParamType::String),
682            "i8" | "i16" | "i32" | "i64" | "i128" | "u8" | "u16" | "u32" | "u64" | "u128"
683            | "usize" | "isize" => Some(ParamType::Integer),
684            "f32" | "f64" => Some(ParamType::Number),
685            "bool" => Some(ParamType::Boolean),
686            _ => {
687                if type_name.starts_with("Vec<") {
688                    Some(ParamType::Array)
689                } else if type_name.starts_with("Option<") {
690                    None
691                } else {
692                    Some(ParamType::Object)
693                }
694            }
695        }
696    }
697}
698
699/// # Tool Parameter
700///
701/// Represents a single parameter definition for a tool.
702///
703/// ## Example
704///
705/// ```rust
706/// use tokitai_core::{ToolParameter, ParamType};
707///
708/// let param = ToolParameter::new(
709///     "city",
710///     ParamType::String,
711///     "Name of the city",
712///     true, // Required parameter
713/// );
714/// ```
715#[derive(Debug, Clone)]
716#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
717pub struct ToolParameter {
718    /// Parameter name
719    pub name: &'static str,
720    /// Parameter type
721    #[cfg_attr(feature = "serde", serde(rename = "type"))]
722    pub param_type: ParamType,
723    /// Parameter description
724    pub description: &'static str,
725    /// Whether the parameter is required
726    pub required: bool,
727}
728
729impl ToolParameter {
730    /// Create a new parameter definition
731    ///
732    /// # Parameters
733    ///
734    /// - `name` - Parameter name
735    /// - `param_type` - Parameter type
736    /// - `description` - Parameter description
737    /// - `required` - Whether the parameter is required
738    ///
739    /// # Example
740    ///
741    /// ```rust
742    /// use tokitai_core::{ToolParameter, ParamType};
743    ///
744    /// let param = ToolParameter::new("limit", ParamType::Integer, "Number of results to return", false);
745    /// ```
746    pub fn new(
747        name: &'static str,
748        param_type: ParamType,
749        description: &'static str,
750        required: bool,
751    ) -> Self {
752        Self {
753            name,
754            param_type,
755            description,
756            required,
757        }
758    }
759}
760
761/// # Tool Error
762///
763/// Represents errors that can occur during tool invocation.
764///
765/// ## Example
766///
767/// ```rust
768/// use tokitai_core::{ToolError, ToolErrorKind};
769///
770/// let error = ToolError::validation_error("Missing required parameter 'city'");
771/// assert_eq!(error.kind, ToolErrorKind::ValidationError);
772/// ```
773#[derive(Debug, Clone)]
774#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
775pub struct ToolError {
776    /// Error type classification
777    pub kind: ToolErrorKind,
778    /// Error message
779    #[cfg(feature = "serde")]
780    pub message: crate::serde_types::String,
781    #[cfg(not(feature = "serde"))]
782    pub message: &'static str,
783}
784
785#[cfg(feature = "serde")]
786impl std::error::Error for ToolError {}
787
788#[cfg(feature = "serde")]
789impl std::fmt::Display for ToolError {
790    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
791        write!(f, "ToolError: {:?} - {}", self.kind, self.message)
792    }
793}
794
795#[cfg(not(feature = "serde"))]
796impl ToolError {
797    /// Create a new error
798    pub fn new(kind: ToolErrorKind, message: &'static str) -> Self {
799        Self { kind, message }
800    }
801
802    /// Create a validation error
803    pub fn validation_error(message: &'static str) -> Self {
804        Self {
805            kind: ToolErrorKind::ValidationError,
806            message,
807        }
808    }
809
810    /// Create a not found error
811    pub fn not_found(message: &'static str) -> Self {
812        Self {
813            kind: ToolErrorKind::NotFound,
814            message,
815        }
816    }
817
818    /// Create an internal error
819    pub fn internal_error(message: &'static str) -> Self {
820        Self {
821            kind: ToolErrorKind::InternalError,
822            message,
823        }
824    }
825}
826
827#[cfg(feature = "serde")]
828impl ToolError {
829    /// Create a new error
830    pub fn new(kind: ToolErrorKind, message: impl Into<crate::serde_types::String>) -> Self {
831        Self {
832            kind,
833            message: message.into(),
834        }
835    }
836
837    /// Create a validation error
838    pub fn validation_error(message: impl Into<crate::serde_types::String>) -> Self {
839        Self {
840            kind: ToolErrorKind::ValidationError,
841            message: message.into(),
842        }
843    }
844
845    /// Create a not found error
846    pub fn not_found(message: impl Into<crate::serde_types::String>) -> Self {
847        Self {
848            kind: ToolErrorKind::NotFound,
849            message: message.into(),
850        }
851    }
852
853    /// Create an internal error
854    pub fn internal_error(message: impl Into<crate::serde_types::String>) -> Self {
855        Self {
856            kind: ToolErrorKind::InternalError,
857            message: message.into(),
858        }
859    }
860}
861
862/// # Error Kind
863///
864/// Classification of tool errors for structured error handling.
865#[derive(Debug, Clone, Copy, PartialEq, Eq)]
866#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
867#[repr(u8)]
868pub enum ToolErrorKind {
869    /// Validation error - parameter validation failed
870    ValidationError = 0,
871    /// Not found - requested tool does not exist
872    NotFound = 1,
873    /// Internal error - tool execution failed
874    InternalError = 2,
875    /// Type error - parameter type mismatch
876    TypeError = 3,
877}
878
879/// # Compile-time Tool Registry Trait
880///
881/// Automatically implemented by the `#[tool]` macro, providing tool definitions
882/// and invocation interface.
883///
884/// ## Example
885///
886/// ```rust
887/// use tokitai_core::ToolProvider;
888///
889/// // After using #[tool] macro on your type:
890/// // struct Calculator;
891/// // #[tool] impl Calculator { ... }
892///
893/// // Get all tool definitions
894/// // let tools = Calculator::tool_definitions();
895///
896/// // Get tool count
897/// // let count = Calculator::tool_count();
898///
899/// // Find a specific tool
900/// // let tool = Calculator::find_tool("add");
901/// ```
902pub trait ToolProvider {
903    /// Get all tool definitions
904    fn tool_definitions() -> &'static [ToolDefinition];
905
906    /// Get the number of tools
907    fn tool_count() -> usize {
908        Self::tool_definitions().len()
909    }
910
911    /// Find a tool definition by name
912    fn find_tool(name: &str) -> Option<&'static ToolDefinition> {
913        Self::tool_definitions().iter().find(|t| t.name == name)
914    }
915}
916
917/// # Tool Caller Trait
918///
919/// Provides runtime tool invocation capability.
920/// Automatically implemented by the `#[tool]` macro for all tool types.
921///
922/// ## Example
923///
924/// ```rust,ignore
925/// use tokitai_core::{ToolProvider, ToolCaller};
926/// use serde_json::json;
927///
928/// // After using #[tool] macro on your type:
929/// // struct Calculator;
930/// // #[tool] impl Calculator { ... }
931///
932/// let calc = Calculator;
933/// let result = calc.call_tool("add", &json!({"a": 10, "b": 20})).unwrap();
934/// assert_eq!(result, json!(30));
935/// ```
936#[cfg(feature = "serde")]
937pub trait ToolCaller {
938    /// Call a tool by name with JSON arguments
939    ///
940    /// # Parameters
941    ///
942    /// - `name` - Tool name to call
943    /// - `args` - JSON arguments for the tool
944    ///
945    /// # Returns
946    ///
947    /// - `Ok(Value)` - Tool execution result
948    /// - `Err(ToolError)` - Tool execution failed
949    fn call_tool(
950        &self,
951        name: &str,
952        args: &crate::serde_types::Value,
953    ) -> Result<crate::serde_types::Value, ToolError>;
954}
955
956/// # From Json Value Trait (P0 优化)
957///
958/// Trait for parsing JSON values into Rust types.
959/// This trait is implemented for common types and used by the `#[tool]` macro
960/// to parse tool parameters from JSON arguments.
961///
962/// ## Design Goals
963///
964/// - **Zero code duplication**: Implemented once per type, not per tool method
965/// - **Compile-time monomorphization**: Generic over types for optimal performance
966/// - **Clear error messages**: Type-specific error handling
967///
968/// ## Example
969///
970/// ```rust
971/// use tokitai_core::{FromJsonValue, ToolError};
972/// use serde_json::json;
973///
974/// let args = json!({"count": 42, "name": "test"});
975/// let count = i64::from_json_value(&args, "count").unwrap();
976/// let name = String::from_json_value(&args, "name").unwrap();
977/// assert_eq!(count, 42);
978/// assert_eq!(name, "test");
979/// ```
980#[cfg(feature = "serde")]
981pub trait FromJsonValue: Sized {
982    /// Parse a value from JSON arguments
983    ///
984    /// # Parameters
985    ///
986    /// - `args` - JSON arguments object
987    /// - `key` - Parameter name to extract
988    ///
989    /// # Returns
990    ///
991    /// - `Ok(Self)` - Successfully parsed value
992    /// - `Err(ToolError)` - Parsing failed (missing key or type mismatch)
993    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError>;
994
995    /// Parse an optional value from JSON arguments
996    ///
997    /// # Parameters
998    ///
999    /// - `args` - JSON arguments object
1000    /// - `key` - Parameter name to extract
1001    ///
1002    /// # Returns
1003    ///
1004    /// - `Some(Self)` - Successfully parsed value
1005    /// - `None` - Key does not exist or type mismatch
1006    fn from_json_value_opt(args: &crate::serde_types::Value, key: &str) -> Option<Self> {
1007        Self::from_json_value(args, key).ok()
1008    }
1009}
1010
1011// ============== 基本类型实现 ==============
1012
1013#[cfg(feature = "serde")]
1014impl FromJsonValue for i64 {
1015    #[inline(always)]
1016    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1017        args.get(key)
1018            .ok_or_else(|| ToolError::validation_error(format!("缺少必需参数 '{}'", key)))?
1019            .as_i64()
1020            .ok_or_else(|| ToolError::validation_error(format!("参数 '{}' 类型错误,期望 integer", key)))
1021    }
1022}
1023
1024#[cfg(feature = "serde")]
1025impl FromJsonValue for i32 {
1026    #[inline(always)]
1027    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1028        args.get(key)
1029            .ok_or_else(|| ToolError::validation_error(format!("缺少必需参数 '{}'", key)))?
1030            .as_i64()
1031            .map(|v| v as i32)
1032            .ok_or_else(|| ToolError::validation_error(format!("参数 '{}' 类型错误,期望 integer", key)))
1033    }
1034}
1035
1036#[cfg(feature = "serde")]
1037impl FromJsonValue for u64 {
1038    #[inline(always)]
1039    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1040        args.get(key)
1041            .ok_or_else(|| ToolError::validation_error(format!("缺少必需参数 '{}'", key)))?
1042            .as_u64()
1043            .ok_or_else(|| ToolError::validation_error(format!("参数 '{}' 类型错误,期望 unsigned integer", key)))
1044    }
1045}
1046
1047#[cfg(feature = "serde")]
1048impl FromJsonValue for u32 {
1049    #[inline(always)]
1050    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1051        args.get(key)
1052            .ok_or_else(|| ToolError::validation_error(format!("缺少必需参数 '{}'", key)))?
1053            .as_u64()
1054            .map(|v| v as u32)
1055            .ok_or_else(|| ToolError::validation_error(format!("参数 '{}' 类型错误,期望 unsigned integer", key)))
1056    }
1057}
1058
1059#[cfg(feature = "serde")]
1060impl FromJsonValue for f64 {
1061    #[inline(always)]
1062    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1063        args.get(key)
1064            .ok_or_else(|| ToolError::validation_error(format!("缺少必需参数 '{}'", key)))?
1065            .as_f64()
1066            .ok_or_else(|| ToolError::validation_error(format!("参数 '{}' 类型错误,期望 number", key)))
1067    }
1068}
1069
1070#[cfg(feature = "serde")]
1071impl FromJsonValue for f32 {
1072    #[inline(always)]
1073    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1074        args.get(key)
1075            .ok_or_else(|| ToolError::validation_error(format!("缺少必需参数 '{}'", key)))?
1076            .as_f64()
1077            .map(|v| v as f32)
1078            .ok_or_else(|| ToolError::validation_error(format!("参数 '{}' 类型错误,期望 number", key)))
1079    }
1080}
1081
1082#[cfg(feature = "serde")]
1083impl FromJsonValue for bool {
1084    #[inline(always)]
1085    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1086        args.get(key)
1087            .ok_or_else(|| ToolError::validation_error(format!("缺少必需参数 '{}'", key)))?
1088            .as_bool()
1089            .ok_or_else(|| ToolError::validation_error(format!("参数 '{}' 类型错误,期望 boolean", key)))
1090    }
1091}
1092
1093#[cfg(feature = "serde")]
1094impl FromJsonValue for String {
1095    #[inline(always)]
1096    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1097        args.get(key)
1098            .ok_or_else(|| ToolError::validation_error(format!("缺少必需参数 '{}'", key)))?
1099            .as_str()
1100            .map(|s| s.to_string())
1101            .ok_or_else(|| ToolError::validation_error(format!("参数 '{}' 类型错误,期望 string", key)))
1102    }
1103}
1104
1105// ============== &str 零拷贝支持 ==============
1106// 特殊处理:需要生命周期,使用单独函数
1107#[cfg(feature = "serde")]
1108#[inline(always)]
1109pub fn from_json_value_str<'a>(
1110    args: &'a crate::serde_types::Value,
1111    key: &str,
1112) -> Result<&'a str, ToolError> {
1113    args.get(key)
1114        .ok_or_else(|| ToolError::validation_error(format!("Missing required parameter '{}'", key)))?
1115        .as_str()
1116        .ok_or_else(|| ToolError::validation_error(format!("Parameter '{}' type error, expected string", key)))
1117}
1118
1119// ============== Option 实现 ==============
1120
1121#[cfg(feature = "serde")]
1122impl<T: FromJsonValue> FromJsonValue for Option<T> {
1123    #[inline(always)]
1124    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1125        Ok(T::from_json_value_opt(args, key))
1126    }
1127}
1128
1129// ============== Vec 实现 ==============
1130
1131#[cfg(feature = "serde")]
1132impl<T: serde::de::DeserializeOwned> FromJsonValue for Vec<T> {
1133    #[inline(always)]
1134    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1135        let value = args.get(key)
1136            .ok_or_else(|| ToolError::validation_error(format!("缺少必需参数 '{}'", key)))?;
1137        serde_json::from_value(value.clone())
1138            .map_err(|e| ToolError::validation_error(format!("参数 '{}' 类型错误:{}", key, e)))
1139    }
1140}
1141
1142// ============== 辅助函数:解析任意 DeserializeOwned 类型 ==============
1143// 对于不支持的自定义类型,用户可以在方法内部手动反序列化
1144
1145#[cfg(feature = "serde")]
1146#[inline(always)]
1147pub fn from_json_value_generic<T: serde::de::DeserializeOwned>(
1148    args: &crate::serde_types::Value,
1149    key: &str,
1150) -> Result<T, ToolError> {
1151    let value = args.get(key)
1152        .ok_or_else(|| ToolError::validation_error(format!("Missing required parameter '{}'", key)))?;
1153    serde_json::from_value(value.clone())
1154        .map_err(|e| ToolError::validation_error(format!("Parameter '{}' type error: {}", key, e)))
1155}
1156
1157// ============== HashMap 实现 ==============
1158#[cfg(feature = "serde")]
1159impl<V: serde::de::DeserializeOwned> FromJsonValue for std::collections::HashMap<String, V> {
1160    #[inline(always)]
1161    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1162        let value = args.get(key)
1163            .ok_or_else(|| ToolError::validation_error(format!("Missing required parameter '{}'", key)))?;
1164        serde_json::from_value(value.clone())
1165            .map_err(|e| ToolError::validation_error(format!("Parameter '{}' type error: {}", key, e)))
1166    }
1167}
1168
1169// ============== BTreeMap 实现 ==============
1170#[cfg(feature = "serde")]
1171impl<V: serde::de::DeserializeOwned> FromJsonValue for std::collections::BTreeMap<String, V> {
1172    #[inline(always)]
1173    fn from_json_value(args: &crate::serde_types::Value, key: &str) -> Result<Self, ToolError> {
1174        let value = args.get(key)
1175            .ok_or_else(|| ToolError::validation_error(format!("Missing required parameter '{}'", key)))?;
1176        serde_json::from_value(value.clone())
1177            .map_err(|e| ToolError::validation_error(format!("Parameter '{}' type error: {}", key, e)))
1178    }
1179}
1180
1181/// Tool configuration types for runtime customization.
1182#[cfg(feature = "serde")]
1183pub mod config;
1184
1185#[cfg(feature = "serde")]
1186pub mod serde_types {
1187    //! Serde type aliases
1188    //!
1189    //! This module is available when the `serde` feature is enabled.
1190
1191    pub use alloc::string::String;
1192    pub use serde_json::Value;
1193}
1194
1195/// # JSON Schema Macro (Compile-time)
1196///
1197/// Helper macro for generating JSON Schema strings at compile time,
1198/// avoiding runtime overhead.
1199///
1200/// ## Example
1201///
1202/// ```rust,ignore
1203/// // Note: This macro generates strings at compile time, syntax is special
1204/// use tokitai_core::json_schema;
1205///
1206/// const SCHEMA: &str = json_schema!({
1207///     "city": {
1208///         type: String,
1209///         description: "Name of the city",
1210///         required: true,
1211///     }
1212/// });
1213/// ```
1214#[macro_export]
1215macro_rules! json_schema {
1216    (
1217        {
1218            $($param_name:literal: {
1219                type: $param_type:ident,
1220                description: $description:literal,
1221                required: $required:literal $(,)?
1222            }),*
1223            $(,)?
1224        }
1225    ) => {{
1226        const SCHEMA: &str = concat!(
1227            "{\"type\":\"object\",\"properties\":{",
1228            $({
1229                concat!(
1230                    "\"", $param_name, "\":",
1231                    "{\"type\":\"", $crate::ParamType::$param_type.as_str(), "\",\"description\":\"", $description, "\"}"
1232                )
1233            },)*
1234            "},\"required\":[",
1235            $({
1236                if $required { concat!("\"", $param_name, "\"") } else { "" }
1237            },)*
1238            "]}"
1239        );
1240        SCHEMA
1241    }};
1242}
1243
1244#[cfg(test)]
1245mod tests {
1246    use super::*;
1247
1248    #[test]
1249    fn test_param_type_from_rust_type() {
1250        assert_eq!(ParamType::from_rust_type("String"), Some(ParamType::String));
1251        assert_eq!(ParamType::from_rust_type("i32"), Some(ParamType::Integer));
1252        assert_eq!(ParamType::from_rust_type("f64"), Some(ParamType::Number));
1253        assert_eq!(ParamType::from_rust_type("bool"), Some(ParamType::Boolean));
1254        assert_eq!(
1255            ParamType::from_rust_type("Vec<i32>"),
1256            Some(ParamType::Array)
1257        );
1258    }
1259
1260    #[test]
1261    fn test_tool_definition_const() {
1262        let tool = ToolDefinition::new("test", "A test tool", "{}");
1263        assert_eq!(tool.name, "test");
1264        assert_eq!(tool.description, "A test tool");
1265    }
1266
1267    #[cfg(feature = "serde")]
1268    #[test]
1269    fn test_tool_definition_to_json() {
1270        let tool = ToolDefinition::new("test", "A test tool", r#"{"type":"object"}"#);
1271        let json = tool.to_json().unwrap();
1272        assert!(json.contains(r#""name":"test""#));
1273    }
1274}