Skip to main content

va_ai_api_bridge/providers/
mod.rs

1mod dashscope;
2mod deepseek;
3mod kimi;
4mod mimo;
5mod minimax;
6mod reasoning_blob;
7mod xai;
8mod zai;
9
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12
13use crate::{UniversalEvent, WireProtocol};
14
15pub use dashscope::DashScopeBridgeAdapter;
16pub use deepseek::DeepSeekBridgeAdapter;
17pub use kimi::KimiBridgeAdapter;
18pub use mimo::MimoBridgeAdapter;
19pub use minimax::MiniMaxBridgeAdapter;
20pub use xai::XaiBridgeAdapter;
21pub use zai::ZaiBridgeAdapter;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "kebab-case")]
25pub enum ProviderRequestSource {
26    OpenAiResponses,
27    OpenAiChat,
28    AnthropicMessages,
29    GeminiGenerateContent,
30}
31
32impl ProviderRequestSource {
33    pub fn from_protocol(protocol: WireProtocol) -> Self {
34        match protocol {
35            WireProtocol::OpenAiResponses => Self::OpenAiResponses,
36            WireProtocol::OpenAiChat => Self::OpenAiChat,
37            WireProtocol::AnthropicMessages => Self::AnthropicMessages,
38            WireProtocol::GeminiGenerateContent => Self::GeminiGenerateContent,
39        }
40    }
41
42    pub(crate) fn supports_deepseek_reasoning_replay(self) -> bool {
43        matches!(
44            self,
45            Self::OpenAiResponses | Self::AnthropicMessages | Self::GeminiGenerateContent
46        )
47    }
48}
49
50#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52pub struct DeepSeekBridgeSettings {
53    #[serde(default, skip_serializing_if = "is_false")]
54    pub thinking: bool,
55    #[serde(default, skip_serializing_if = "is_false")]
56    pub replay_reasoning_content: bool,
57}
58
59impl DeepSeekBridgeSettings {
60    pub fn is_empty(&self) -> bool {
61        !self.thinking && !self.replay_reasoning_content
62    }
63}
64
65#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(rename_all = "camelCase")]
67pub struct ProviderBridgeAdapterConfig {
68    #[serde(default, skip_serializing_if = "DeepSeekBridgeSettings::is_empty")]
69    pub deepseek: DeepSeekBridgeSettings,
70    #[serde(default, skip_serializing_if = "Option::is_none")]
71    pub thinking_enabled: Option<bool>,
72}
73
74#[derive(Debug, Clone)]
75pub enum ProviderBridgeAdapter {
76    None,
77    DeepSeek(DeepSeekBridgeAdapter),
78    Kimi(KimiBridgeAdapter),
79    Mimo(MimoBridgeAdapter),
80    MiniMax(MiniMaxBridgeAdapter),
81    DashScope(DashScopeBridgeAdapter),
82    Xai(XaiBridgeAdapter),
83    Zai(ZaiBridgeAdapter),
84}
85
86impl ProviderBridgeAdapter {
87    pub fn for_provider(
88        provider_id: &str,
89        _target_protocol: WireProtocol,
90        config: ProviderBridgeAdapterConfig,
91    ) -> Self {
92        match provider_id {
93            "deepseek" => Self::DeepSeek(DeepSeekBridgeAdapter::new(config.deepseek)),
94            "kimi" => Self::Kimi(KimiBridgeAdapter::default()),
95            "mimo" => Self::Mimo(MimoBridgeAdapter),
96            "minimax" => Self::MiniMax(MiniMaxBridgeAdapter::default()),
97            "dashscope" | "qwen" => {
98                Self::DashScope(DashScopeBridgeAdapter::new(config.thinking_enabled))
99            }
100            "xai" => Self::Xai(XaiBridgeAdapter),
101            "zai" => Self::Zai(ZaiBridgeAdapter::new(config.thinking_enabled)),
102            _ => Self::None,
103        }
104    }
105
106    pub fn prepare_responses_request(&mut self, request: &mut Value) {
107        match self {
108            Self::None => {}
109            Self::DeepSeek(_) => {}
110            Self::Kimi(_) => {}
111            Self::Mimo(_) => {}
112            Self::MiniMax(_) => {}
113            Self::DashScope(_) => {}
114            Self::Xai(adapter) => adapter.prepare_responses_request(request),
115            Self::Zai(_) => {}
116        }
117    }
118
119    pub fn prepare_chat_request(
120        &mut self,
121        source: ProviderRequestSource,
122        original_request: &Value,
123        chat_request: &mut Value,
124    ) {
125        match self {
126            Self::None => {}
127            Self::DeepSeek(adapter) => {
128                adapter.prepare_chat_request(source, original_request, chat_request)
129            }
130            Self::Kimi(_) => {}
131            Self::Mimo(adapter) => {
132                adapter.prepare_chat_request(source, original_request, chat_request)
133            }
134            Self::MiniMax(adapter) => adapter.prepare_chat_request(chat_request),
135            Self::DashScope(adapter) => {
136                adapter.prepare_chat_request(original_request, chat_request)
137            }
138            Self::Xai(_) => {}
139            Self::Zai(adapter) => adapter.prepare_chat_request(original_request, chat_request),
140        }
141    }
142
143    pub fn prepare_anthropic_request(
144        &mut self,
145        source: ProviderRequestSource,
146        request: &mut Value,
147    ) {
148        match self {
149            Self::None => {}
150            Self::DeepSeek(adapter) => adapter.prepare_anthropic_request(source, request),
151            Self::Kimi(adapter) => adapter.prepare_anthropic_request(request),
152            Self::Mimo(_) => {}
153            Self::MiniMax(_) => {}
154            Self::DashScope(_) => {}
155            Self::Xai(_) => {}
156            Self::Zai(_) => {}
157        }
158    }
159
160    pub fn normalize_chat_response(&mut self, response: &mut Value) {
161        match self {
162            Self::None => {}
163            Self::DeepSeek(_) => {}
164            Self::Kimi(_) => {}
165            Self::Mimo(adapter) => adapter.normalize_chat_response(response),
166            Self::MiniMax(_) => {}
167            Self::DashScope(_) => {}
168            Self::Xai(_) => {}
169            Self::Zai(_) => {}
170        }
171    }
172
173    pub fn transform_upstream_events(&mut self, events: &mut Vec<UniversalEvent>) {
174        match self {
175            Self::None => {}
176            Self::DeepSeek(_) => {}
177            Self::Kimi(adapter) => adapter.transform_upstream_events(events),
178            Self::Mimo(_) => {}
179            Self::MiniMax(adapter) => adapter.transform_upstream_events(events),
180            Self::DashScope(_) => {}
181            Self::Xai(_) => {}
182            Self::Zai(_) => {}
183        }
184    }
185}
186
187fn is_false(value: &bool) -> bool {
188    !*value
189}