2 releases
new 0.1.1 | May 9, 2025 |
---|---|
0.1.0 | May 9, 2025 |
#382 in Procedural macros
Used in yart
18KB
239 lines
YART (Yet Another Rig Tool)
YART is a Rust library suite for creating tools with the rig::tool::Tool
trait, providing a flexible procedural macro (#[rig_tool]
) for generating tool implementations with JSON schema support. It is designed for the rig
framework, enabling async tool definitions with optional context and arguments.
Structure
YART is split into three crates to adhere to Rust’s proc-macro restrictions and provide a clean API:
yart-shared
: Contains shared types (ToolError
,ToolOutput
) and utilities (derive_parameters
) used by generated code and consumers.yart-macro
: A proc-macro crate exporting the#[rig_tool]
macro, which generatesrig::tool::Tool
implementations.yart
: A wrapper crate that re-exports the#[rig_tool]
macro fromyart_macro
and types/functions fromyart_shared
, offering a unified interface.
This structure mirrors conventions like serde
/serde_derive
, ensuring compatibility and modularity.
Features
- Flexible Macro:
#[rig_tool]
supports 0-2 arguments (optional context, optional args).- Attributes:
description
(required),name
(optional, defaults to function name).
- Generated Code:
- Creates a struct implementing
rig::tool::Tool
withnew
,name
,definition
, andcall
methods. - Generates JSON schemas for arguments using
schemars
.
- Creates a struct implementing
- Async Support: Wraps async functions with
Result
returns, handling errors viaToolError
. - Unified API: Import everything via
yart
(e.g.,use yart::*
).
Installation
[dependencies]
yart = "0.1.1"
The yart
crate depends on yart-shared
and yart-macro
, so you only need to include yart
.
Usage
Define a tool using the #[rig_tool]
macro, specifying a description
and optional name
. The macro generates a struct implementing rig::tool::Tool
.
Example
use std::sync::Arc;
use yart::{ToolError, ToolOutput};
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;
// Define argument type
#[derive(Deserialize, Serialize, JsonSchema)]
struct TestArgs {
input: String,
}
// Define output type
#[derive(Deserialize, Serialize)]
struct TestOutput {
result: String,
}
// Tool without context
#[yart::rig_tool(description = "Echoes input")]
async fn echo_tool(args: TestArgs) -> anyhow::Result<TestOutput, ToolError> {
Ok(TestOutput { result: args.input })
}
// Tool with context
#[derive(Clone)]
struct TestContext {
value: String,
}
#[yart::rig_tool(name = "context_tool", description = "Echoes input with context")]
async fn context_tool(
ctx: Arc<TestContext>,
args: TestArgs,
) -> anyhow::Result<TestOutput, ToolError> {
Ok(TestOutput {
result: format!("{}: {}", ctx.value, args.input),
})
}
#[tokio::main]
async fn main() {
// Use tool without context
let tool = EchoTool::new();
let args = TestArgs { input: "hello".to_string() };
let result = tool.call(args).await.unwrap();
let output: TestOutput = serde_json::from_value(result.result).unwrap();
println!("Output: {}", output.result); // Output: hello
// Use tool with context
let ctx = Arc::new(TestContext { value: "test".to_string() });
let tool = ContextTool::new(ctx);
let args = TestArgs { input: "world".to_string() };
let result = tool.call(args).await.unwrap();
let output: TestOutput = serde_json::from_value(result.result).unwrap();
println!("Output: {}", output.result); // Output: test: world
}
Project Structure
yart/
├── libs/
│ ├── yart/ # Wrapper crate
│ │ ├── src/lib.rs # Re-exports yart-macro and yart-shared
│ │ └── Cargo.toml
│ ├── yart-macro/ # Proc-macro crate
│ │ ├── src/lib.rs # Defines #[rig_tool] macro
│ │ └── Cargo.toml
│ └── yart-shared/ # Shared types and utilities
│ ├── src/lib.rs # Defines ToolError, ToolOutput, derive_parameters
│ └── Cargo.toml
├── README.md
└── Cargo.toml
Testing
Run tests for each crate:
# Test yart-shared
cd libs/yart-shared
cargo test
# Test yart-macro
cd libs/yart-macro
cargo test
# Test yart (integration tests)
cd libs/yart
cargo test
Limitations
- The
description
attribute is required; enforced at compile-time but tested manually due to proc-macro testing constraints. - Consider using
trybuild
for robust macro testing inyart-macro
.
Contributing
Contributions are welcome! Please submit pull requests or open issues on the project repository.
License
MIT
Dependencies
~8–24MB
~243K SLoC