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
122
123
124
125
126
127
128
129
130
131
132
133
//! 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 output = async {
//! let mut handler = toolset.tool_handler(name).await?;
//! handler
//! .step(ToolHandlerInput::Invoke(ToolInvocation {
//! call_id: Some("call-1".to_owned()),
//! arguments: serde_json::json!({}),
//! }))
//! .await
//! }.await;
//! let cleanup = toolset.shutdown().await;
//! if let Err(error) = &cleanup {
//! eprintln!("Cleanup failed: {error}");
//! }
//! 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 result = async {
/// let mut handler = tools.tool_handler(ToolName::new("double")?).await?;
/// handler.step(ToolHandlerInput::Invoke(ToolInvocation {
/// call_id: None, arguments: serde_json::json!(3),
/// })).await
/// }.await;
/// let cleanup = tools.shutdown().await;
/// if let Err(error) = &cleanup {
/// eprintln!("Cleanup failed: {error}");
/// }
/// let ToolHandlerOutput::Completed(result) = result? else { panic!("completion expected") };
/// assert_eq!(result.structured_content, Some(serde_json::json!(6)));
/// cleanup?;
/// # Ok(())
/// # }
/// ```