Skip to main content

vtcode_llm/providers/merge_gateway/
mod.rs

1//! Merge Gateway provider.
2
3use crate::error_display;
4use crate::http_client::HttpClientFactory;
5use crate::provider::{
6    FinishReason, LLMError, LLMNormalizedStream, LLMProvider, LLMRequest, LLMResponse, LLMStream, LLMStreamEvent,
7    Message, NormalizedStreamEvent, ToolCall, ToolChoice, ToolDefinition, Usage,
8};
9use crate::providers::common::{
10    override_base_url, resolve_model, serialize_message_content_openai_for_model, validate_request_common,
11};
12use crate::providers::error_handling::{format_network_error, format_parse_error};
13use crate::providers::gemini::sanitize_function_parameters;
14use crate::providers::openai_compat::{OpenAiCompatCore, OpenAiCompatSpec};
15use crate::providers::shared::{
16    RESPONSES_COMPLETION_TOKEN_KEYS, RESPONSES_PROMPT_TOKEN_KEYS, Utf8StreamDecoder, extract_data_payload,
17    function_output_value_from_message_content, generate_tool_call_id, next_sse_event,
18    parse_cache_write_tokens_from_usage, parse_cached_prompt_tokens_from_usage, usage_u32_from_keys,
19};
20use async_stream::try_stream;
21use async_trait::async_trait;
22use futures::StreamExt;
23use reqwest::{Client as HttpClient, StatusCode};
24use serde_json::{Map, Value, json};
25use std::collections::{HashMap, HashSet};
26use std::sync::{Arc, Mutex};
27use vtcode_config::TimeoutsConfig;
28use vtcode_config::constants::{env_vars, models, urls};
29use vtcode_config::core::{AnthropicConfig, ModelConfig, PromptCachingConfig};
30
31/// Static provider metadata shared by native and explicit legacy routes.
32
33#[derive(Debug)]
34struct NativeMergeGatewayCore {
35    api_key: String,
36    http_client: HttpClient,
37    base_url: String,
38    model: String,
39    model_behavior: Option<ModelConfig>,
40}
41
42pub struct MergeGatewayProvider {
43    native: NativeMergeGatewayCore,
44    legacy_core: Option<OpenAiCompatCore<MergeGatewaySpec>>,
45    /// Models that already failed a non-streaming tool request with
46    /// `capability_unavailable`: no vendor serves tools for them, so further
47    /// tool turns fail fast without burning calls. Session-scoped (like the
48    /// OpenAI tier-unsupported cache): a fresh session re-probes in case
49    /// vendors onboarded, and tool-free requests always bypass the cache.
50    no_tool_vendor_cache: Mutex<HashSet<String>>,
51}
52
53use classification::*;
54use spec::*;
55use stream_state::*;
56
57mod classification;
58mod provider_impl;
59mod spec;
60mod stream_state;
61
62#[cfg(test)]
63mod tests;