reson-agentic

Crates.ioreson-agentic
lib.rsreson-agentic
version0.2.0
created_at2025-12-06 19:44:03.426906+00
updated_at2026-01-25 10:30:56.474967+00
descriptionAgents are just functions - production-grade LLM agent framework
homepagehttps://github.com/iantbutler01/reson
repositoryhttps://github.com/iantbutler01/reson
max_upload_size
id1970645
size906,614
Ian Butler (iantbutler01)

documentation

https://docs.rs/reson-agentic

README

reson-agentic

Agents are just functions - production-grade LLM agent framework for Rust.

Features

  • Multi-provider support: Anthropic, OpenAI, Google Gemini, OpenRouter, AWS Bedrock
  • Native tool calling with structured outputs via #[derive(Tool)]
  • Agent macro for ergonomic agent definitions with #[agentic]
  • Streaming responses with reasoning/thinking support
  • OpenAI/OpenRouter Responses API support (openai:resp:*, openrouter:resp:*)
  • Google File API for video/large media uploads
  • Retry with exponential backoff
  • Clone-friendly clients for use in async contexts

Installation

[dependencies]
reson-agentic = "0.1"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }

Quick Start

Basic Chat

use reson_agentic::providers::{GoogleGenAIClient, GenerationConfig, InferenceClient};
use reson_agentic::types::ChatMessage;
use reson_agentic::utils::ConversationMessage;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = GoogleGenAIClient::new("your-api-key", "gemini-2.0-flash");

    let messages = vec![
        ConversationMessage::Chat(ChatMessage::user("Hello!"))
    ];

    let config = GenerationConfig::new("gemini-2.0-flash");
    let response = client.get_generation(&messages, &config).await?;

    println!("{}", response.content);
    Ok(())
}

Tool Definitions with #[derive(Tool)]

Define type-safe tools that automatically generate JSON schemas for LLM function calling:

use reson_agentic::Tool;
use serde::{Deserialize, Serialize};

/// Search the web for information
#[derive(Tool, Serialize, Deserialize, Debug)]
struct WebSearch {
    /// The search query to execute
    query: String,
    /// Maximum number of results to return
    max_results: Option<u32>,
}

/// Get weather for a location
#[derive(Tool, Serialize, Deserialize, Debug)]
struct GetWeather {
    /// City name or coordinates
    location: String,
    /// Temperature unit: "celsius" or "fahrenheit"
    unit: Option<String>,
}

// Access generated schema
let schema = WebSearch::schema();       // JSON Schema object
let name = WebSearch::tool_name();      // "web_search"
let desc = WebSearch::description();    // "Search the web for information"

The #[derive(Tool)] macro:

  • Converts struct name to snake_case for the tool name
  • Uses doc comments as descriptions (struct doc -> tool description, field docs -> parameter descriptions)
  • Generates proper JSON Schema with types, required fields, and array items
  • Supports String, bool, i32/i64/u32/u64, f32/f64, Vec<T>, and Option<T>

Agent Functions with #[agentic]

The #[agentic] macro transforms an async function into an agent. It:

  1. Creates a Runtime automatically and injects it into the function
  2. Validates that runtime.run() or runtime.run_stream() is called
  3. Configures the model from the macro attribute
use reson_agentic::agentic;
use reson_agentic::runtime::{Runtime, ToolFunction};
use reson_agentic::error::Result;

/// Analyze text and answer questions
#[agentic(model = "gemini:gemini-2.0-flash")]
async fn analyze_text(
    text: String,
    question: String,
    runtime: Runtime,  // Injected by macro - callers don't pass this
) -> Result<serde_json::Value> {
    // Register tools with the runtime
    runtime.register_tool_with_schema(
        WebSearch::tool_name(),
        WebSearch::description(),
        WebSearch::schema(),
        ToolFunction::Sync(Box::new(|args| {
            let query = args["query"].as_str().unwrap_or("");
            Ok(format!("Search results for: {}", query))
        })),
    ).await?;

    // Run the agent - runtime is mutable internally
    runtime.run(
        Some(&format!("Text: {}\n\nQuestion: {}", text, question)),
        Some("You are a helpful assistant. Use tools when needed."),
        None,  // history
        None,  // output_type
        None,  // temperature
        None,  // top_p
        None,  // max_tokens
        None,  // model override
        None,  // api_key override
    ).await
}

// Call the agent - runtime parameter is NOT passed by caller
let result = analyze_text(
    "The quick brown fox...".to_string(),
    "What animal is mentioned?".to_string(),
).await?;

Video/Media Upload (Google Gemini)

Upload and analyze videos using Google's File API:

use reson_agentic::providers::{GoogleGenAIClient, FileState};
use reson_agentic::types::{ChatRole, MediaPart, MediaSource, MultimodalMessage};

let client = GoogleGenAIClient::new(api_key, "gemini-2.0-flash");

// Upload video
let video_bytes = std::fs::read("video.mp4")?;
let uploaded = client.upload_file(&video_bytes, "video/mp4", Some("my-video")).await?;

// Wait for processing (required for videos)
if uploaded.state == FileState::Processing {
    client.wait_for_file_processing(&uploaded.name, Some(120)).await?;
}

// Create multimodal message
let message = MultimodalMessage {
    role: ChatRole::User,
    parts: vec![
        MediaPart::Video {
            source: MediaSource::FileUri {
                uri: uploaded.uri.clone(),
                mime_type: Some("video/mp4".to_string()),
            },
            metadata: None,
        },
        MediaPart::Text { text: "Describe this video".to_string() },
    ],
    cache_marker: None,
};

// Clean up when done
client.delete_file(&uploaded.name).await?;

Supported Media Types

Type Formats Max Size
Video MP4, MOV, AVI, WebM, MKV, FLV, 3GP 2GB
Image JPEG, PNG, GIF, WebP, HEIC 20MB inline
Audio MP3, WAV, FLAC, AAC, OGG, M4A 2GB
Document PDF, TXT, HTML, CSS, JS, etc. Varies

Providers

Provider Client Model Format
Google Gemini GoogleGenAIClient gemini-2.0-flash
Anthropic AnthropicClient claude-sonnet-4-20250514
OpenAI OAIClient gpt-4o
OpenRouter OpenRouterClient anthropic/claude-sonnet-4
AWS Bedrock BedrockClient anthropic.claude-sonnet-4-20250514-v1:0
Vertex AI (Claude)* GoogleAnthropicClient claude-sonnet-4@20250514

*Requires google-adc feature: reson-agentic = { version = "0.1", features = ["google-adc"] }

All clients implement Clone for easy use in async contexts.

Examples

See the examples directory:

  • video_upload.rs - Video analysis with Google Gemini and #[agentic] macro
  • simple_tools.rs - Basic tool registration and execution
  • tool_call_chain.rs - Multi-turn tool calling
  • dynamic_tool_parsing.rs - Type-safe tool parsing with Deserializable
  • templating_example.rs - Prompt templates with minijinja
  • store_usage.rs - Context storage patterns

Run examples with:

GOOGLE_GEMINI_API_KEY=your_key cargo run --example video_upload -- video.mp4

Feature Flags

[dependencies]
reson-agentic = { version = "0.1", features = ["full"] }
Feature Description
full All features enabled
storage Redis + SQLx storage backends
bedrock AWS Bedrock support
templating Minijinja prompt templates
telemetry OpenTelemetry tracing
google-adc Google Application Default Credentials (Vertex AI)

License

Apache-2.0

Commit count: 85

cargo fmt