use anyhow::Result; use async_trait::async_trait; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum Role { System, User, Assistant, Tool, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Message { pub role: Role, pub content: String, #[serde(skip_serializing_if = "Option::is_none")] pub tool_calls: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub tool_call_id: Option, } impl Message { pub fn system(content: impl Into) -> Self { Self { role: Role::System, content: content.into(), tool_calls: None, tool_call_id: None, } } pub fn user(content: impl Into) -> Self { Self { role: Role::User, content: content.into(), tool_calls: None, tool_call_id: None, } } pub fn assistant(content: impl Into) -> Self { Self { role: Role::Assistant, content: content.into(), tool_calls: None, tool_call_id: None, } } pub fn tool(content: impl Into, tool_call_id: String) -> Self { Self { role: Role::Tool, content: content.into(), tool_calls: None, tool_call_id: Some(tool_call_id), } } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ToolCall { pub id: String, #[serde(rename = "type")] pub call_type: String, pub function: FunctionCall, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FunctionCall { pub name: String, pub arguments: String, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ToolDefinition { #[serde(rename = "type")] pub tool_type: String, pub function: FunctionDefinition, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FunctionDefinition { pub name: String, pub description: String, pub parameters: serde_json::Value, } #[derive(Debug)] pub struct ChatResponse { pub content: String, pub tool_calls: Option>, pub finish_reason: String, } #[async_trait] pub trait LLMProvider: Send + Sync { /// Send a chat completion request async fn chat(&self, messages: Vec, tools: Option>) -> Result; /// Get the model name fn model_name(&self) -> &str; }