Skip to main content

rig_core/tool/
portable.rs

1//! Context-free tool authoring contracts.
2//!
3//! Portable tools receive owned, deserialized arguments only. Runtime identity,
4//! authorization, mutable context, capability state, and lifecycle metadata
5//! remain outside the typed portable call boundary.
6//!
7//! ```
8//! use rig_core::tool::{PortableTool, tool_definition};
9//!
10//! struct Echo;
11//!
12//! impl PortableTool for Echo {
13//!     const NAME: &'static str = "echo";
14//!     type Args = serde_json::Value;
15//!     type Output = serde_json::Value;
16//!     type Error = std::convert::Infallible;
17//!
18//!     fn description(&self) -> String {
19//!         "Echo JSON".to_string()
20//!     }
21//!
22//!     fn parameters(&self) -> serde_json::Value {
23//!         serde_json::json!({"type": "object"})
24//!     }
25//!
26//!     async fn call(&self, arguments: Self::Args) -> Result<Self::Output, Self::Error> {
27//!         Ok(arguments)
28//!     }
29//! }
30//!
31//! assert_eq!(tool_definition(&Echo).name, "echo");
32//! ```
33
34use serde::{Deserialize, Serialize};
35
36use crate::wasm_compat::{WasmCompatSend, WasmCompatSync};
37
38use super::{IntoToolOutput, ToolExecutionError};
39
40/// A context-free typed tool that can be executed by any Rig runtime.
41pub trait PortableTool: Sized + WasmCompatSend + WasmCompatSync {
42    /// Unique registration and provider-facing name.
43    const NAME: &'static str;
44    /// Owned JSON arguments.
45    type Args: for<'de> Deserialize<'de> + WasmCompatSend + WasmCompatSync;
46    /// Canonical model-visible output.
47    type Output: IntoToolOutput + WasmCompatSend;
48    /// Concrete author-facing failure.
49    type Error: std::error::Error + WasmCompatSend + WasmCompatSync + 'static;
50
51    /// Model-facing description.
52    fn description(&self) -> String;
53
54    /// JSON Schema for arguments.
55    fn parameters(&self) -> serde_json::Value;
56
57    /// Normalize a concrete failure at the runtime effect boundary.
58    fn map_error(&self, error: Self::Error) -> ToolExecutionError {
59        ToolExecutionError::from_error(error)
60    }
61
62    /// Execute one owned invocation without runtime access.
63    fn call(
64        &self,
65        arguments: Self::Args,
66    ) -> impl Future<Output = Result<Self::Output, Self::Error>> + WasmCompatSend;
67}
68
69/// A portable tool that can be embedded and reconstructed for discovery.
70pub trait PortableToolEmbedding: PortableTool {
71    /// Failure returned while reconstructing the typed implementation.
72    type InitError: std::error::Error + WasmCompatSend + WasmCompatSync + 'static;
73    /// Serializable reconstruction data.
74    type Context: for<'de> Deserialize<'de> + Serialize;
75    /// Runtime initialization state supplied by the authoring integration.
76    type State: WasmCompatSend;
77
78    /// Documents used by a discovery implementation.
79    fn embedding_docs(&self) -> Vec<String>;
80    /// Serializable reconstruction data.
81    fn context(&self) -> Self::Context;
82    /// Reconstruct the typed implementation.
83    fn init(state: Self::State, context: Self::Context) -> Result<Self, Self::InitError>;
84}
85
86#[cfg(test)]
87mod tests;