pub mod anthropic; pub mod openai; pub mod openai_compat; pub mod registry; use std::pin::Pin; use futures_core::Stream; use serde::{Deserialize, Serialize}; use crate::llm::error::LlmError; use crate::llm::types::request_v2::MessageRequest; use crate::llm::types::response_v2::{MessageResponse, StreamEvent}; /// Provider 类型枚举 —— `create_provider()` 在编译期 exhaustive match 中使用。 /// /// 设计依据(见 `docs/10-llm-provider-refinement.md` §2.5 Decision-05): /// 当前协议数量(5 种以内)完全可控,enum 的编译期安全检查优于运行时的 `HashMap::get()`。 /// 未来如果扩展到 15+ 种以上,再改为注册表模式。 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ProviderType { /// OpenAI Chat Completions API(兼容 DeepSeek / Qwen 等 `/chat/completions` 端点)。 OpenaiChat, /// OpenAI Response API。 OpenaiResponse, /// Anthropic Messages API。 Anthropic, /// DeepSeek(OpenAI-compatible `/chat/completions`)。 DeepSeek, /// Qwen / 阿里云百炼(OpenAI-compatible `/chat/completions`)。 Qwen, } impl std::str::FromStr for ProviderType { type Err = String; fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { "openai" | "openai-chat" | "openai_chat" => Ok(ProviderType::OpenaiChat), "openai-response" | "openai_response" | "response" => Ok(ProviderType::OpenaiResponse), "anthropic" | "claude" => Ok(ProviderType::Anthropic), "deepseek" => Ok(ProviderType::DeepSeek), "qwen" | "dashscope" | "tongyi" => Ok(ProviderType::Qwen), _ => Err(format!("未知的 Provider 类型: {s}")), } } } /// Provider 构造参数 —— 通用 base_url + api_key + model。 pub struct ProviderConfig { pub base_url: String, pub api_key: String, pub model: String, } /// Provider 工厂 —— exhaustive match 在编译期保证新 Provider 被注册。 pub fn create_provider( provider_type: ProviderType, config: ProviderConfig, ) -> Result, LlmError> { match provider_type { ProviderType::OpenaiChat => Ok(Box::new(openai::OpenaiChatProvider::new( config.base_url, config.api_key, config.model, ))), ProviderType::OpenaiResponse => Err(LlmError::Other( "OpenaiResponse Provider 在 Phase 1 暂不实现;请使用 OpenaiChat".into(), )), ProviderType::Anthropic => Ok(Box::new(anthropic::AnthropicProvider::new( config.base_url, config.api_key, config.model, ))), ProviderType::DeepSeek => Ok(Box::new(openai_compat::DeepSeekProvider::new( config.base_url, config.api_key, config.model, ))), ProviderType::Qwen => Ok(Box::new(openai_compat::QwenProvider::new( config.base_url, config.api_key, config.model, ))), } } /// Provider 能力描述 —— 静态元信息,调用方据此决定可用特性。 /// /// 设计依据(见 `docs/10-llm-provider-refinement.md` §4 任务 6 决策): /// `ProviderCapabilities` 与 trait 同文件(`provider.rs`),不分散到类型目录。 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProviderCapabilities { /// 人类可读的 Provider 名(如 `"openai"` / `"anthropic"`)。 pub provider_name: &'static str, /// 支持的模型列表(`None` 表示"未列举全部")。 pub supported_models: Option>, /// 详细功能开关。 pub features: ProviderFeatures, } /// Provider 功能开关集合。 #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct ProviderFeatures { /// 是否支持流式响应。 pub streaming: bool, /// 是否支持 thinking / 推理。 pub thinking: bool, /// 是否支持图片输入。 pub vision: bool, /// 是否支持音频输入。 pub audio_input: bool, /// 是否支持工具调用。 pub tool_use: bool, /// 是否支持并行工具调用。 pub parallel_tool_calls: bool, /// system prompt 是否放在 messages 中(`true`)还是顶层 `system` 字段(`false`)。 pub system_prompt_in_messages: bool, /// 模型上下文窗口(tokens);`0` 表示未知。 pub max_context_window: u32, } /// LLM Provider 抽象接口。 /// /// 所有具体的 LLM 后端实现(OpenAI、Anthropic、DeepSeek、Qwen 等) /// 均需实现此 trait,以实现可插拔替换。 /// /// 修订(Phase 0):签名由 `chat(ChatRequest) → ChatResponse` 切换为 /// `chat(MessageRequest) → MessageResponse`,`chat_stream` 返回新 `StreamEvent` 流, /// 新增 `capabilities()` 方法。 #[async_trait::async_trait] pub trait LlmProvider: Send + Sync { /// 发送聊天请求并返回完整响应。 async fn chat(&self, request: MessageRequest) -> Result; /// 流式聊天请求 —— 返回新 IR `StreamEvent` 流。 async fn chat_stream( &self, request: MessageRequest, ) -> Result> + Send>>, LlmError>; /// 返回 Provider 静态能力描述。 fn capabilities(&self) -> ProviderCapabilities; }