tiny-agent-rs 0.1.0

A lightweight, type-safe Rust agent library for LLM tool calling
Documentation
use std::any::{type_name, TypeId};

use serde_json::Value;

use crate::{
    error::{AgentError, Result},
    schemas::{CompletionSchema, SchemaHandle},
};

#[derive(Clone, Debug)]
pub struct StructuredPayload {
    schema: SchemaHandle,
    value: Value,
}

impl StructuredPayload {
    pub fn new(schema: SchemaHandle, value: Value) -> Self {
        Self { schema, value }
    }

    pub fn schema(&self) -> &SchemaHandle {
        &self.schema
    }

    pub fn value(&self) -> &Value {
        &self.value
    }

    pub fn into_inner(self) -> (SchemaHandle, Value) {
        (self.schema, self.value)
    }

    pub fn deserialize<T>(&self) -> Result<T>
    where
        T: CompletionSchema,
    {
        deserialize_structured_response::<T>(&self.value, &self.schema)
    }
}

pub fn deserialize_structured_response<T>(payload: &Value, schema: &SchemaHandle) -> Result<T>
where
    T: CompletionSchema,
{
    ensure_schema_matches::<T>(schema)?;

    let raw = payload.to_string();
    let mut deserializer = serde_json::Deserializer::from_str(&raw);
    let value = serde_path_to_error::deserialize(&mut deserializer).map_err(|err| {
        let path = err.path().to_string();
        let location = if path.is_empty() {
            "<root>".to_string()
        } else {
            path
        };
        AgentError::Validation(format!(
            "failed to deserialize `{}` at {}: {}",
            schema.schema_name(),
            location,
            err
        ))
    })?;

    Ok(value)
}

fn ensure_schema_matches<T: 'static>(schema: &SchemaHandle) -> Result<()> {
    let expected = TypeId::of::<T>();
    if schema.type_id() != expected {
        return Err(AgentError::Validation(format!(
            "schema `{}` does not match target type `{}`",
            schema.schema_name(),
            type_name::<T>(),
        )));
    }
    Ok(())
}