Skip to main content

agent_base/llm/
mod.rs

1use async_trait::async_trait;
2use futures_core::Stream;
3use serde_json::Value;
4use std::pin::Pin;
5
6use crate::types::{AgentResult, ChatMessage, ResponseFormat};
7
8mod anthropic;
9mod openai;
10mod registry;
11
12pub use anthropic::AnthropicClient;
13pub use openai::{LlmClientConfig, OpenAiClient};
14pub use registry::{LlmClientBuilder, LlmProvider};
15
16#[derive(Clone, Debug)]
17pub enum StreamChunk {
18    Text(String),
19    Thought(String),
20    ToolCall(Value),
21    Usage(UsageInfo),
22    Stop,
23}
24
25#[derive(Clone, Debug, Default)]
26pub struct UsageInfo {
27    pub prompt_tokens: Option<u32>,
28    pub completion_tokens: Option<u32>,
29    pub total_tokens: Option<u32>,
30}
31
32#[derive(Clone, Debug, Default)]
33pub struct LlmCapabilities {
34    pub supports_streaming: bool,
35    pub supports_tools: bool,
36    pub supports_vision: bool,
37    pub supports_thinking: bool,
38    pub max_context_tokens: Option<u32>,
39    pub max_output_tokens: Option<u32>,
40}
41
42/// Reasoning/thinking configuration, unifying reasoning/thinking parameters across vendors.
43#[derive(Debug, Clone, Default)]
44pub struct ReasoningConfig {
45    /// Whether to enable reasoning/thinking process
46    pub enabled: Option<bool>,
47    /// Thinking budget (token count limit)
48    pub budget_tokens: Option<u64>,
49    /// Reasoning intensity/depth (semantics vary by vendor)
50    pub effort: Option<ReasoningEffort>,
51}
52
53/// Reasoning intensity/depth enumeration.
54#[derive(Debug, Clone, Default)]
55pub enum ReasoningEffort {
56    #[default]
57    None,
58    Low,
59    Medium,
60    High,
61    XHigh,
62}
63
64#[async_trait]
65pub trait LlmClient: Send + Sync {
66    async fn chat(
67        &self,
68        messages: &[ChatMessage],
69        tools: &[Value],
70        reasoning: Option<&ReasoningConfig>,
71        response_format: Option<&ResponseFormat>,
72    ) -> AgentResult<Value>;
73
74    async fn chat_stream(
75        &self,
76        messages: &[ChatMessage],
77        tools: &[Value],
78        reasoning: Option<&ReasoningConfig>,
79        response_format: Option<&ResponseFormat>,
80    ) -> AgentResult<Pin<Box<dyn Stream<Item = AgentResult<StreamChunk>> + Send>>>;
81
82    fn capabilities(&self) -> LlmCapabilities;
83
84    /// The model name used by this client (e.g. "claude-sonnet", "gpt-4o").
85    /// Default: "unknown".
86    fn model_name(&self) -> &str {
87        "unknown"
88    }
89}