1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Executable Local and MCP tools.
//!
//! The public hierarchy is [`Toolset`] → [`ToolHandler`]. Toolset is cloneable
//! and owns shared source lifecycle; each ToolHandler is a unique resumable
//! invocation state machine. Callers implement [`ToolsetBackend`] directly and
//! retain its exact associated handler. [`Toolset::from_backend`] optionally
//! normalizes that hierarchy into supplied handles at the sole public root seam.
//!
//! Supporting API is grouped under [`declaration`], [`execution`],
//! [`interaction`], [`local`], [`mcp`], and [`schema`].
//!
//! ```
//! use tools_kit::{
//! ToolHandlerBackend, Toolset, ToolsetBackend,
//! declaration::{ToolInfo, ToolName},
//! execution::{ToolHandlerInput, ToolHandlerOutput, ToolInvocation, ToolResult},
//! local::ToolRegistration,
//! schema::JsonSchema,
//! };
//!
//! # #[tokio::main(flavor = "current_thread")]
//! # async fn main() -> Result<(), tools_kit::ToolError> {
//! let name = ToolName::new("ping")?;
//! let info = ToolInfo::new(
//! name.clone(),
//! JsonSchema::strict(serde_json::json!({"type": "object"})),
//! );
//! let toolset = Toolset::local(vec![ToolRegistration::function(
//! info,
//! |_invocation| async { Ok(ToolResult::text("pong")) },
//! )])?;
//! let mut handler = toolset.tool_handler(name).await?;
//! let output = handler
//! .step(ToolHandlerInput::Invoke(ToolInvocation {
//! call_id: Some("call-1".to_owned()),
//! arguments: serde_json::json!({}),
//! }))
//! .await;
//! let cleanup = toolset.shutdown().await;
//! let ToolHandlerOutput::Completed(result) = output? else { panic!("completion expected") };
//! assert!(!result.is_error);
//! assert!(matches!(result.content.as_slice(), [tools_kit::execution::ToolContent::Text { text, .. }] if text == "pong"));
//! cleanup?;
//! # Ok(())
//! # }
//! ```
//!
//! # Choose a workflow
//!
//! | Audience | Start here |
//! | --- | --- |
//! | Application builders | [Local registration and caller interactions](local), [terminal results and failures](execution), [configured MCP clients and servers](mcp) |
//! | Custom-backend implementers | Complete executable [`ToolsetBackend`] example, then the optional [`Toolset::from_backend`] normalization seam |
//!
//! Local construction performs no network request. Configuring an MCP connection is
//! passive, but connecting or serving requires its external transport. The optional
//! `mcp-server` feature adds a separately owned server; stopping it never shuts down
//! the shared executable Toolset. No Handler normalization constructor exists.
/// Tool names and source-neutral executable declarations.
/// Invocation, continuation, and completed-result values.
/// Portable caller interactions requested during execution.
/// In-process tool registration and interaction context.
/// MCP client configuration and optional independent server support.
/// JSON Schema values and validation diagnostics.
pub use crate::;
/// Builds a typed local registration.
///
/// The macro is intentionally limited to typed-handler ergonomics. It does
/// not generate dispatch, routing, or lifecycle code.
///
/// ```
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), tools_kit::ToolError> {
/// use tools_kit::{Toolset, ToolsetBackend, ToolHandlerBackend};
/// use tools_kit::declaration::ToolName;
/// use tools_kit::execution::{ToolHandlerInput, ToolHandlerOutput, ToolInvocation};
/// let registration = tools_kit::tool!("double", |value: i64| async move { Ok(value * 2) })?;
/// let tools = Toolset::local(vec![registration])?;
/// let mut handler = tools.tool_handler(ToolName::new("double")?).await?;
/// let result = handler.step(ToolHandlerInput::Invoke(ToolInvocation {
/// call_id: None, arguments: serde_json::json!(3),
/// })).await;
/// let cleanup = tools.shutdown().await;
/// let ToolHandlerOutput::Completed(result) = result? else { panic!("completion expected") };
/// assert_eq!(result.structured_content, Some(serde_json::json!(6)));
/// cleanup?;
/// # Ok(())
/// # }
/// ```