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 types;
13pub mod zhipu;
14
15// Re-export public types
16pub use anthropic::AnthropicClient;
17pub(crate) use error::non_retryable_llm_error_message;
18pub use error::NonRetryableLlmError;
19pub use factory::{create_client_with_config, LlmConfig};
20pub use http::{
21    clear_http_metrics_callback, default_http_client, set_http_metrics_callback, HttpClient,
22    HttpMetricsCallback, HttpMetricsRecord, HttpResponse, StreamingHttpResponse,
23};
24pub use openai::OpenAiClient;
25pub use types::*;
26pub use zhipu::ZhipuClient;
27
28use anyhow::Result;
29use async_trait::async_trait;
30use tokio::sync::mpsc;
31use tokio_util::sync::CancellationToken;
32
33/// LLM client trait
34#[async_trait]
35pub trait LlmClient: Send + Sync {
36    /// Complete a conversation (non-streaming)
37    async fn complete(
38        &self,
39        messages: &[Message],
40        system: Option<&str>,
41        tools: &[ToolDefinition],
42    ) -> Result<LlmResponse>;
43
44    /// Complete a conversation with streaming
45    /// Returns a receiver for streaming events.
46    /// The cancel_token is checked during the HTTP request; if cancelled, the request is aborted.
47    async fn complete_streaming(
48        &self,
49        messages: &[Message],
50        system: Option<&str>,
51        tools: &[ToolDefinition],
52        cancel_token: CancellationToken,
53    ) -> Result<mpsc::Receiver<StreamEvent>>;
54
55    /// Report the strongest provider-native structured-output enforcement this
56    /// client supports. Used by [`structured`] to decide whether to force a
57    /// tool call, request a native `response_format`, or fall back to
58    /// prompt-and-parse. Defaults to no native support.
59    fn native_structured_support(&self) -> structured::NativeStructuredSupport {
60        structured::NativeStructuredSupport::None
61    }
62
63    /// Complete a conversation while honoring a structured-output directive
64    /// (forced `tool_choice` and/or native `response_format`).
65    ///
66    /// The default implementation ignores the directive and behaves exactly
67    /// like [`LlmClient::complete`], so existing clients keep working unchanged;
68    /// providers that support native structured output override this.
69    async fn complete_structured(
70        &self,
71        messages: &[Message],
72        system: Option<&str>,
73        tools: &[ToolDefinition],
74        _directive: &structured::StructuredDirective,
75    ) -> Result<LlmResponse> {
76        self.complete(messages, system, tools).await
77    }
78
79    /// Streaming counterpart of [`LlmClient::complete_structured`]. Defaults to
80    /// [`LlmClient::complete_streaming`], ignoring the directive.
81    async fn complete_streaming_structured(
82        &self,
83        messages: &[Message],
84        system: Option<&str>,
85        tools: &[ToolDefinition],
86        _directive: &structured::StructuredDirective,
87        cancel_token: CancellationToken,
88    ) -> Result<mpsc::Receiver<StreamEvent>> {
89        self.complete_streaming(messages, system, tools, cancel_token)
90            .await
91    }
92}
93
94// Include test modules — these reference internal types via crate paths
95#[cfg(test)]
96#[path = "tests.rs"]
97mod tests_file;