rune-chain-core 0.1.2

Core traits and types for the rune-chain LLM orchestration framework
Documentation
use std::pin::Pin;

use async_trait::async_trait;
use futures::Stream;

use crate::{FunctionDefinition, GenerateResult, LlmError, Message, StreamData, ToolChoice};

/// An async interface to a large language model.
///
/// Implementors wrap a specific provider (OpenAI, Anthropic, Ollama, …) and
/// translate a slice of [`Message`]s into a [`GenerateResult`].
///
/// All methods have default implementations so providers only need to override
/// what they support. The minimum required method is [`generate`](Llm::generate).
#[async_trait]
pub trait Llm: Sync + Send {
    /// Send a slice of messages and return the model's complete response.
    async fn generate(&self, messages: &[Message]) -> Result<GenerateResult, LlmError>;

    /// Send messages together with tool definitions for native function calling.
    ///
    /// When the model decides to call a tool, the returned [`GenerateResult`]
    /// will have [`tool_calls`](GenerateResult::tool_calls) populated. The
    /// caller should execute those tools and feed results back as
    /// [`Message::tool_result`] turns before calling again.
    ///
    /// Providers that do not support function calling return
    /// [`LlmError::ToolUseNotSupported`] by default.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// use rune_chain_core::{Llm, Message, FunctionDefinition};
    /// use serde_json::json;
    ///
    /// let tools = vec![
    ///     FunctionDefinition::single_input("upper_case", "Converts text to upper case."),
    /// ];
    /// let result = llm.generate_with_tools(&messages, &tools, None).await?;
    /// if result.wants_tool_calls() {
    ///     // execute tools and loop
    /// }
    /// ```
    async fn generate_with_tools(
        &self,
        _messages: &[Message],
        _tools: &[FunctionDefinition],
        _tool_choice: Option<ToolChoice>,
    ) -> Result<GenerateResult, LlmError> {
        Err(LlmError::ToolUseNotSupported(
            "this provider does not support native function calling".into(),
        ))
    }

    /// Stream tokens from the model as they are produced.
    ///
    /// Providers that do not support streaming return [`LlmError::Other`] by default.
    async fn stream(
        &self,
        _messages: &[Message],
    ) -> Result<Pin<Box<dyn Stream<Item = Result<StreamData, LlmError>> + Send>>, LlmError> {
        Err(LlmError::Other(
            "streaming is not supported by this LLM provider".into(),
        ))
    }
}