wasm-agent 0.2.0

A ReAct and native tool-calling agent loop with no I/O, for WASM, edge workers and plugins: parse model replies, dispatch tools, keep history
Documentation
//! Tools whose input is a Rust type: the JSON Schema is generated, the input
//! is parsed before your function runs, and bad input goes back to the model
//! as an error it can fix.
//!
//! Run with `cargo run --example typed_tools --features schemars`.

use schemars::JsonSchema;
use serde::Deserialize;
use wasm_agent::{AgentConfig, LoopRunner, ToolRegistry};

/// Convert an amount between currencies.
#[derive(Deserialize, JsonSchema)]
struct Convert {
    /// Amount to convert.
    amount: f64,
    /// ISO code to convert from, for example "EUR".
    from: String,
    /// ISO code to convert to.
    to: String,
}

fn main() -> Result<(), wasm_agent::AgentError> {
    let mut tools = ToolRegistry::new();
    tools.register_typed("convert", "Convert money between currencies", |c: Convert| {
        let rate = match (c.from.as_str(), c.to.as_str()) {
            ("EUR", "USD") => 1.08,
            ("USD", "EUR") => 0.93,
            _ => return Err(format!("no rate for {} to {}", c.from, c.to)),
        };
        Ok(format!("{:.2} {}", c.amount * rate, c.to))
    })?;
    println!("schema sent to the model: {}", tools.openai_tools()?[0]["function"]["parameters"]);

    let config = AgentConfig::default();
    let mut runner = LoopRunner::new(&config, &tools).with_system_prompt();
    runner.ask("How much is 100 euros in dollars?");
    runner.step(r#"Action: convert({"amount": "a hundred", "from": "EUR", "to": "USD"})"#)?; // wrong type
    runner.step(r#"Action: convert({"amount": 100, "from": "EUR", "to": "USD"})"#)?;
    runner.step("Final Answer: about 108 US dollars")?;
    print!("{}", runner.transcript());
    Ok(())
}