llmkit-core 0.1.0

Core traits, types, and errors for llmkit-rs — no I/O, runtime-agnostic
Documentation
//! Tool/function-calling types, normalised across providers.

use serde::{Deserialize, Serialize};
use serde_json::Value;

/// A tool the model may call, defined by a name, description, and JSON Schema.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Tool {
    /// Tool name the model uses to invoke it.
    pub name: String,
    /// Human-readable description guiding when to use the tool.
    #[serde(default)]
    pub description: String,
    /// JSON Schema for the tool's input object.
    pub input_schema: Value,
}

impl Tool {
    /// Build a tool from its parts.
    pub fn new(
        name: impl Into<String>,
        description: impl Into<String>,
        input_schema: Value,
    ) -> Self {
        Self { name: name.into(), description: description.into(), input_schema }
    }

    /// Build a tool from any type implementing [`ToolSchema`] (e.g. via the
    /// `#[derive(ToolSchema)]` macro).
    pub fn from_schema<T: ToolSchema>() -> Self {
        Self {
            name: T::tool_name().to_string(),
            description: T::tool_description().to_string(),
            input_schema: T::input_schema(),
        }
    }
}

/// How the model should choose among available tools.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolChoice {
    /// Model decides whether and which tool to call.
    #[default]
    Auto,
    /// Model must call at least one tool.
    Any,
    /// Model must not call any tool.
    None,
    /// Model must call the named tool.
    Tool(String),
}

/// A tool invocation requested by the model.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToolCall {
    /// Provider-assigned id, echoed back when returning the result.
    pub id: String,
    /// Name of the tool to invoke.
    pub name: String,
    /// Parsed JSON arguments.
    pub input: Value,
}

impl ToolCall {
    /// Construct a tool call.
    pub fn new(id: impl Into<String>, name: impl Into<String>, input: Value) -> Self {
        Self { id: id.into(), name: name.into(), input }
    }
}

/// The result of executing a [`ToolCall`], returned to the model.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToolResult {
    /// Id of the originating [`ToolCall`].
    pub tool_use_id: String,
    /// String content of the result.
    pub content: String,
    /// Whether the tool errored.
    #[serde(default)]
    pub is_error: bool,
}

impl ToolResult {
    /// A successful tool result.
    pub fn ok(tool_use_id: impl Into<String>, content: impl Into<String>) -> Self {
        Self { tool_use_id: tool_use_id.into(), content: content.into(), is_error: false }
    }

    /// An errored tool result.
    pub fn error(tool_use_id: impl Into<String>, content: impl Into<String>) -> Self {
        Self { tool_use_id: tool_use_id.into(), content: content.into(), is_error: true }
    }
}

/// Implemented by tool input structs to expose name, description, and schema.
///
/// Derive it with `#[derive(ToolSchema)]` from `llmkit-macros`.
pub trait ToolSchema {
    /// The tool's name.
    fn tool_name() -> &'static str;
    /// The tool's description.
    fn tool_description() -> &'static str;
    /// The JSON Schema for the tool's input.
    fn input_schema() -> Value;
}