Skip to main content

vtcode_core/llm/
client.rs

1use super::provider::LLMError;
2use super::types::LLMResponse;
3use crate::config::models::ModelId;
4use async_trait::async_trait;
5
6/// Unified LLM client trait.
7///
8/// Note: `backend_kind()` lives on [`LLMProvider`](super::provider::LLMProvider)
9/// rather than here, following the **single responsibility** principle — the
10/// provider knows its own backend identity.
11#[async_trait]
12pub trait LLMClient: Send + Sync {
13    /// Send a prompt to the LLM and return the response.
14    async fn generate(&mut self, prompt: &str) -> Result<LLMResponse, LLMError>;
15    /// Return the model identifier this client is connected to.
16    fn model_id(&self) -> &str;
17}
18
19/// Type-erased LLM client
20pub type AnyClient = Box<dyn LLMClient>;
21
22/// Create a client based on the model ID
23/// Uses the existing factory pattern from factory.rs
24pub fn make_client(api_key: String, model: ModelId) -> Result<AnyClient, LLMError> {
25    let model_id = model.to_string();
26    // Use factory to create provider
27    let provider = super::factory::create_provider_for_model(&model_id, api_key, None, None)?;
28
29    // Wrap in a simple client adapter
30    Ok(Box::new(ProviderClientAdapter { provider, model_id }))
31}
32
33/// Adapter to use LLMProvider as LLMClient
34///
35/// This allows using the provider interface through the simpler client trait.
36pub struct ProviderClientAdapter {
37    provider: Box<dyn super::provider::LLMProvider>,
38    model_id: String,
39}
40
41impl ProviderClientAdapter {
42    /// Create a new adapter wrapping an LLMProvider
43    pub fn new(provider: Box<dyn super::provider::LLMProvider>, model_id: String) -> Self {
44        Self { provider, model_id }
45    }
46}
47
48#[async_trait]
49impl LLMClient for ProviderClientAdapter {
50    async fn generate(&mut self, prompt: &str) -> Result<LLMResponse, LLMError> {
51        use super::provider::{LLMRequest, Message};
52        let request = LLMRequest {
53            messages: std::sync::Arc::new(vec![Message::user(prompt.to_string())]),
54            model: self.model_id.clone(),
55            ..Default::default()
56        };
57        Ok(self.provider.generate(request).await?)
58    }
59
60    fn model_id(&self) -> &str {
61        &self.model_id
62    }
63}