Add examples

This commit is contained in:
Collin Brittain 2025-04-07 11:20:59 -05:00
parent 0a9bbe52b7
commit 1fe55ad1dd
7 changed files with 315 additions and 0 deletions

1
Cargo.lock generated
View File

@ -8685,6 +8685,7 @@ dependencies = [
"serde_json",
"syn 2.0.100",
"tokio",
"tracing-subscriber",
]
[[package]]

View File

@ -17,3 +17,4 @@ schemars = "0.8.22"
rig-core = { path = "../rig-core" }
serde = "1.0"
tokio = { version = "1.44.0", features = ["full"] }
tracing-subscriber = "0.3.0"

View File

@ -0,0 +1,56 @@
# Rig Tool Macro Examples
This directory contains examples demonstrating different ways to use the `rig_tool` macro with a rig Agent.
## Examples
### 1. Simple Example (`simple.rs`)
Demonstrates the most basic usage of the macro without any attributes. Shows how to create a simple tool that adds two numbers and use it with a rig Agent.
### 2. With Description (`with_description.rs`)
Shows how to add a description to your tool using the `description` attribute. Implements a calculator that can perform basic arithmetic operations and uses it with a rig Agent.
### 3. Full Attributes (`full.rs`)
Demonstrates using all available attributes including parameter descriptions. Implements a string processor that can perform various string operations and uses it with a rig Agent.
### 4. Error Handling (`error_handling.rs`)
Shows how to handle errors in your tools, including:
- Domain-specific errors (e.g., square root of negative numbers)
- Parameter validation errors
- Missing parameter errors
- Type conversion errors
### 5. Async Tool (`async_tool.rs`)
Demonstrates how to create and use async tools with a rig Agent, including:
- Basic async operation
- Error handling in async context
## Running the Examples
To run any example, use:
```bash
cargo run --example <example_name>
```
For example:
```bash
cargo run --example simple
cargo run --example with_description
cargo run --example full
cargo run --example error_handling
cargo run --example async_tool
```
## Features Demonstrated
- Basic tool creation
- Optional attributes
- Parameter descriptions
- Error handling
- Async support
- Static tool instances
- Parameter validation
- Integration with rig Agent
- Natural language interaction with tools
- Tool definitions and schemas

View File

@ -0,0 +1,59 @@
use rig::completion::Prompt;
use rig::providers;
use rig::tool::Tool;
use rig_macros::rig_tool;
use std::time::Duration;
use tracing_subscriber;
// Example demonstrating async tool usage
#[rig_tool(
description = "A tool that simulates an async operation",
params(
input = "Input value to process",
delay_ms = "Delay in milliseconds before returning result"
)
)]
async fn async_operation(input: String, delay_ms: u64) -> Result<String, rig::tool::ToolError> {
// Simulate some async work
tokio::time::sleep(Duration::from_millis(delay_ms)).await;
// Process the input
Ok(format!(
"Processed after {}ms: {}",
delay_ms,
input.to_uppercase()
))
}
#[tokio::main]
async fn main() {
// Initialize tracing
tracing_subscriber::fmt().pretty().init();
// Create an agent with the ASYNCOPERATION tool
let async_agent = providers::openai::Client::from_env()
.agent(providers::openai::GPT_4O)
.preamble("You are an agent with tools access, always use the tools")
.max_tokens(1024)
.tool(AsyncOperation)
.build();
// Print out the tool definition to verify
println!("Tool definition:");
println!(
"ASYNCOPERATION: {}",
serde_json::to_string_pretty(&AsyncOperation.definition(String::default()).await).unwrap()
);
// Test prompts
for prompt in [
"What tools do you have?",
"Process the text 'hello world' with a delay of 1000ms",
"Process the text 'async operation' with a delay of 500ms",
"Process the text 'concurrent calls' with a delay of 200ms",
"Process the text 'error handling' with a delay of 'not a number'",
] {
println!("User: {}", prompt);
println!("Agent: {}", async_agent.prompt(prompt).await.unwrap());
}
}

View File

@ -0,0 +1,65 @@
use rig::completion::Prompt;
use rig::providers;
use rig::tool::Tool;
use rig_macros::rig_tool;
use tracing_subscriber;
// Example with full attributes including parameter descriptions
#[rig_tool(
description = "A tool that performs string operations",
params(
text = "The input text to process",
operation = "The operation to perform (uppercase, lowercase, reverse)",
)
)]
fn string_processor(
text: String,
operation: String,
) -> Result<String, rig::tool::ToolError> {
let result = match operation.as_str() {
"uppercase" => text.to_uppercase(),
"lowercase" => text.to_lowercase(),
"reverse" => text.chars().rev().collect(),
_ => {
return Err(rig::tool::ToolError::ToolCallError(
format!("Unknown operation: {}", operation).into(),
))
}
};
Ok(result)
}
#[tokio::main]
async fn main() {
// Initialize tracing
tracing_subscriber::fmt().pretty().init();
// Create an agent with the STRINGPROCESSOR tool
let string_agent = providers::openai::Client::from_env()
.agent(providers::openai::GPT_4O)
.preamble("You are an agent with tools access, always use the tools")
.max_tokens(1024)
.tool(StringProcessor)
.build();
// Print out the tool definition to verify
println!("Tool definition:");
println!(
"STRINGPROCESSOR: {}",
serde_json::to_string_pretty(&StringProcessor.definition(String::default()).await).unwrap()
);
// Test prompts
for prompt in [
"What tools do you have?",
"Convert 'hello world' to uppercase",
"Convert 'HELLO WORLD' to lowercase",
"Reverse the string 'hello world'",
"Convert 'hello world' to uppercase and repeat it 3 times",
"Perform an invalid operation on 'hello world'",
] {
println!("User: {}", prompt);
println!("Agent: {}", string_agent.prompt(prompt).await.unwrap());
}
}

View File

@ -0,0 +1,72 @@
use rig_macros::rig_tool;
use rig::completion::Prompt;
use rig::providers;
use tracing_subscriber;
// Simple example with no attributes
#[rig_tool]
fn add(a: i32, b: i32) -> Result<i32, rig::tool::ToolError> {
Ok(a + b)
}
#[rig_tool]
fn subtract(a: i32, b: i32) -> Result<i32, rig::tool::ToolError> {
Ok(a - b)
}
#[rig_tool]
fn multiply(a: i32, b: i32) -> Result<i32, rig::tool::ToolError> {
Ok(a * b)
}
#[rig_tool]
fn divide(a: i32, b: i32) -> Result<i32, rig::tool::ToolError> {
if b == 0 {
Err(rig::tool::ToolError::ToolCallError("Division by zero".into()))
} else {
Ok(a / b)
}
}
#[rig_tool]
fn answer_secret_question() -> Result<(bool, bool, bool, bool, bool), rig::tool::ToolError> {
Ok((false, false, true, false, false))
}
#[rig_tool]
fn how_many_rs(s: String) -> Result<usize, rig::tool::ToolError> {
Ok(s.chars()
.filter(|c| *c == 'r' || *c == 'R')
.collect::<Vec<_>>()
.len())
}
#[rig_tool]
fn sum_numbers(numbers: Vec<i64>) -> Result<i64, rig::tool::ToolError> {
Ok(numbers.iter().sum())
}
#[tokio::main]
async fn main() {
// Initialize tracing
tracing_subscriber::fmt().pretty().init();
// Create an agent with the ADD tool
let calculator_agent = providers::openai::Client::from_env()
.agent(providers::openai::GPT_4O)
.preamble("You are an agent with tools access, always use the tools")
.max_tokens(1024)
.tool(Add)
.build();
// Test prompts
for prompt in [
"What tools do you have?",
"Calculate 5 + 3",
"What is 10 + 20?",
"Add 100 and 200",
] {
println!("User: {}", prompt);
println!("Agent: {}", calculator_agent.prompt(prompt).await.unwrap());
}
}

View File

@ -0,0 +1,61 @@
use rig::completion::Prompt;
use rig::providers;
use rig::tool::Tool;
use rig_macros::rig_tool;
use tracing_subscriber;
// Example with description attribute
#[rig_tool(description = "Perform basic arithmetic operations")]
fn calculator(x: i32, y: i32, operation: String) -> Result<i32, rig::tool::ToolError> {
match operation.as_str() {
"add" => Ok(x + y),
"subtract" => Ok(x - y),
"multiply" => Ok(x * y),
"divide" => {
if y == 0 {
Err(rig::tool::ToolError::ToolCallError(
"Division by zero".into(),
))
} else {
Ok(x / y)
}
}
_ => Err(rig::tool::ToolError::ToolCallError(
format!("Unknown operation: {}", operation).into(),
)),
}
}
#[tokio::main]
async fn main() {
// Initialize tracing
tracing_subscriber::fmt().pretty().init();
// Create an agent with the CALCULATOR tool
let calculator_agent = providers::openai::Client::from_env()
.agent(providers::openai::GPT_4O)
.preamble("You are an agent with tools access, always use the tools")
.max_tokens(1024)
.tool(Calculator)
.build();
// Print out the tool definition to verify
println!("Tool definition:");
println!(
"CALCULATOR: {}",
serde_json::to_string_pretty(&CALCULATOR.definition(String::default()).await).unwrap()
);
// Test prompts
for prompt in [
"What tools do you have?",
"Calculate 5 + 3",
"What is 10 - 4?",
"Multiply 6 and 7",
"Divide 20 by 5",
"What is 10 / 0?",
] {
println!("User: {}", prompt);
println!("Agent: {}", calculator_agent.prompt(prompt).await.unwrap());
}
}