#![allow(clippy::expect_used)]
use rig::tool::{PortableTool, Tool, ToolContext, ToolExecutionError, ToolSet};
use serde::Deserialize;
use serde_json::{Value, json};
#[derive(Deserialize)]
struct Amount {
x: i32,
}
#[derive(Default)]
struct ContextualAdder;
impl Tool for ContextualAdder {
const NAME: &'static str = "contextual_adder";
type Args = Amount;
type Output = i32;
type Error = ToolExecutionError;
fn description(&self) -> String {
"adds one".to_string()
}
fn parameters(&self) -> Value {
json!({ "type": "object" })
}
async fn call(
&self,
_context: &mut ToolContext,
args: Self::Args,
) -> Result<Self::Output, Self::Error> {
Ok(args.x + 1)
}
}
#[derive(Default)]
struct PortableAdder;
impl PortableTool for PortableAdder {
const NAME: &'static str = "portable_adder";
type Args = Amount;
type Output = i32;
type Error = ToolExecutionError;
fn description(&self) -> String {
"adds two".to_string()
}
fn parameters(&self) -> Value {
json!({ "type": "object" })
}
async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
Ok(args.x + 2)
}
}
#[test]
fn classic_contextual_tool_impls_facade_tool() {
fn assert_tool<T: Tool>() {}
assert_tool::<ContextualAdder>();
}
#[test]
fn portable_tool_impls_facade_portable_tool() {
fn assert_portable<T: PortableTool>() {}
assert_portable::<PortableAdder>();
}
#[test]
fn portable_tool_registers_with_classic_toolset() {
let set: ToolSet = ToolSet::builder().static_tool(PortableAdder).build();
let names: Vec<String> = set
.get_tool_definitions()
.into_iter()
.map(|definition| definition.name)
.collect();
assert!(names.iter().any(|name| name == "portable_adder"));
}
#[test]
fn portable_contract_paths_resolve() {
fn assert_portable<T: rig_core::tool::PortableTool>() {}
assert_portable::<PortableAdder>();
fn assert_portable_facade<T: rig::tool::portable::PortableTool>() {}
assert_portable_facade::<PortableAdder>();
}
#[test]
fn completion_client_single_import_surface() {
use rig::prelude::*;
#[derive(serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
struct Extracted {
value: String,
}
let client = rig::providers::openai::Client::new("test-key").expect("client builds");
let _model = client.completion_model("gpt-4o");
let _agent = client.agent("gpt-4o").build();
let _extractor = client.extractor::<Extracted>("gpt-4o").build();
}
#[test]
fn completion_client_explicit_facade_import_surface() {
use rig::client::{AgentClientExt, CompletionClient};
#[derive(serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
struct Extracted {
value: String,
}
let client = rig::providers::openai::Client::new("test-key").expect("client builds");
let _model = client.completion_model("gpt-4o"); let _agent = client.agent("gpt-4o").build(); let _extractor = client.extractor::<Extracted>("gpt-4o").build(); }
mod prelude_regression {
use rig::prelude::*;
use serde::Deserialize;
#[derive(Deserialize)]
struct Args {
n: i32,
}
struct PreludeTool;
impl Tool for PreludeTool {
const NAME: &'static str = "prelude_tool";
type Args = Args;
type Output = i32;
type Error = rig::tool::ToolExecutionError;
fn description(&self) -> String {
"prelude".to_string()
}
fn parameters(&self) -> serde_json::Value {
serde_json::json!({ "type": "object" })
}
async fn call(
&self,
_context: &mut ToolContext,
args: Self::Args,
) -> Result<Self::Output, Self::Error> {
Ok(args.n)
}
}
#[test]
fn prelude_exposes_classic_tool() {
fn assert_tool<T: Tool>() {}
assert_tool::<PreludeTool>();
}
}