use std::collections::BTreeMap;
use std::pin::Pin;
use async_trait::async_trait;
use futures::stream::Stream;
use serde::{Deserialize, Serialize};
use crate::error::Result;
use crate::message::AgentMessage;
use crate::thinking::ThinkingLevel;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Model {
pub id: String,
}
impl Model {
#[must_use]
pub fn new(id: impl Into<String>) -> Self {
Self { id: id.into() }
}
#[must_use]
pub fn provider(&self) -> &str {
self.id.split('/').next().unwrap_or("")
}
}
#[derive(Debug, Clone)]
pub struct ModelRequest {
pub model: Model,
pub messages: Vec<AgentMessage>,
pub tools: Vec<crate::tool::ToolDefinition>,
pub thinking: ThinkingLevel,
pub params: BTreeMap<String, serde_json::Value>,
}
#[derive(Debug, Clone)]
pub enum StreamEvent {
TextDelta(String),
ToolCall(crate::tool::ToolCall),
ThinkingDelta(String),
Done,
}
pub type StreamEventStream = Pin<Box<dyn Stream<Item = Result<StreamEvent>> + Send>>;
#[derive(Debug, Clone)]
pub struct ModelResponse {
pub messages: Vec<AgentMessage>,
}
impl ModelResponse {
#[must_use]
pub fn empty() -> Self {
Self {
messages: Vec::new(),
}
}
}
#[async_trait]
pub trait ModelProvider: Send + Sync {
async fn invoke(&self, request: ModelRequest) -> Result<ModelResponse>;
fn stream(&self, request: ModelRequest) -> StreamEventStream {
Box::pin(futures::stream::once(async move {
let _ = request;
Ok(StreamEvent::Done)
}))
}
}