//! Local LLM driver (Ollama, LM Studio, vLLM, etc.) use async_trait::async_trait; use futures::Stream; use reqwest::Client; use std::pin::Pin; use zclaw_types::{Result, ZclawError}; use super::{CompletionRequest, CompletionResponse, ContentBlock, LlmDriver, StopReason}; use crate::stream::StreamChunk; /// Local LLM driver for Ollama, LM Studio, vLLM, etc. pub struct LocalDriver { client: Client, base_url: String, } impl LocalDriver { pub fn new(base_url: impl Into) -> Self { Self { client: Client::new(), base_url: base_url.into(), } } pub fn ollama() -> Self { Self::new("http://localhost:11434/v1") } pub fn lm_studio() -> Self { Self::new("http://localhost:1234/v1") } pub fn vllm() -> Self { Self::new("http://localhost:8000/v1") } } #[async_trait] impl LlmDriver for LocalDriver { fn provider(&self) -> &str { "local" } fn is_configured(&self) -> bool { // Local drivers don't require API keys true } async fn complete(&self, request: CompletionRequest) -> Result { // TODO: Implement actual API call (OpenAI-compatible) Ok(CompletionResponse { content: vec![ContentBlock::Text { text: "Local driver not yet implemented".to_string(), }], model: request.model, input_tokens: 0, output_tokens: 0, stop_reason: StopReason::EndTurn, }) } fn stream( &self, _request: CompletionRequest, ) -> Pin> + Send + '_>> { // Placeholder - return error stream Box::pin(futures::stream::once(async { Err(ZclawError::LlmError("Local driver streaming not yet implemented".to_string())) })) } }