Skip to main content

a3s_code_core/llm/
mod.rs

1//! LLM client abstraction layer
2//!
3//! Provides a unified interface for interacting with LLM providers
4//! (Anthropic Claude, OpenAI, Zhipu AI GLM, and OpenAI-compatible providers).
5
6pub mod anthropic;
7mod error;
8pub mod factory;
9pub mod http;
10pub mod openai;
11pub mod structured;
12mod token_estimation;
13mod types;
14pub mod zhipu;
15
16// Re-export public types
17pub use anthropic::AnthropicClient;
18pub(crate) use error::non_retryable_llm_error_message;
19pub use error::NonRetryableLlmError;
20pub use factory::{create_client_with_config, LlmConfig};
21pub use http::{
22    clear_http_metrics_callback, default_http_client, set_http_metrics_callback, HttpClient,
23    HttpMetricsCallback, HttpMetricsRecord, HttpResponse, StreamingHttpResponse,
24};
25pub use openai::OpenAiClient;
26pub(crate) use token_estimation::{estimate_message_tokens, estimate_prompt_tokens};
27pub use types::*;
28pub use zhipu::ZhipuClient;
29
30use anyhow::Result;
31use async_trait::async_trait;
32use tokio::sync::mpsc;
33use tokio_util::sync::CancellationToken;
34
35/// LLM client trait
36#[async_trait]
37pub trait LlmClient: Send + Sync {
38    /// Derive a provider client bound to one logical agent session.
39    ///
40    /// Stateless providers can keep the default and share the existing client.
41    /// Account-backed providers whose transport uses a live session identity
42    /// should return an independent client so parallel child agents do not
43    /// contend for the parent's active operation.
44    fn fork_for_session(&self, _session_id: &str) -> Option<std::sync::Arc<dyn LlmClient>> {
45        None
46    }
47
48    /// Complete a conversation (non-streaming)
49    async fn complete(
50        &self,
51        messages: &[Message],
52        system: Option<&str>,
53        tools: &[ToolDefinition],
54    ) -> Result<LlmResponse>;
55
56    /// Complete a conversation with streaming
57    /// Returns a receiver for streaming events.
58    /// The cancel_token is checked during the HTTP request; if cancelled, the request is aborted.
59    async fn complete_streaming(
60        &self,
61        messages: &[Message],
62        system: Option<&str>,
63        tools: &[ToolDefinition],
64        cancel_token: CancellationToken,
65    ) -> Result<mpsc::Receiver<StreamEvent>>;
66
67    /// Report the strongest provider-native structured-output enforcement this
68    /// client supports. Used by [`structured`] to decide whether to force a
69    /// tool call, request a native `response_format`, or fall back to
70    /// prompt-and-parse. Defaults to no native support.
71    fn native_structured_support(&self) -> structured::NativeStructuredSupport {
72        structured::NativeStructuredSupport::None
73    }
74
75    /// Complete a conversation while honoring a structured-output directive
76    /// (forced `tool_choice` and/or native `response_format`).
77    ///
78    /// The default implementation ignores the directive and behaves exactly
79    /// like [`LlmClient::complete`], so existing clients keep working unchanged;
80    /// providers that support native structured output override this.
81    async fn complete_structured(
82        &self,
83        messages: &[Message],
84        system: Option<&str>,
85        tools: &[ToolDefinition],
86        _directive: &structured::StructuredDirective,
87    ) -> Result<LlmResponse> {
88        self.complete(messages, system, tools).await
89    }
90
91    /// Streaming counterpart of [`LlmClient::complete_structured`]. Defaults to
92    /// [`LlmClient::complete_streaming`], ignoring the directive.
93    async fn complete_streaming_structured(
94        &self,
95        messages: &[Message],
96        system: Option<&str>,
97        tools: &[ToolDefinition],
98        _directive: &structured::StructuredDirective,
99        cancel_token: CancellationToken,
100    ) -> Result<mpsc::Receiver<StreamEvent>> {
101        self.complete_streaming(messages, system, tools, cancel_token)
102            .await
103    }
104}
105
106// Include test modules — these reference internal types via crate paths
107#[cfg(test)]
108#[path = "tests.rs"]
109mod tests_file;