1use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use thiserror::Error;
6
7#[derive(Debug, Error)]
10pub enum ModelError {
11 #[error("provider API error ({status}): {body}")]
12 Api { status: u16, body: String },
13
14 #[error("rate limited — retry after {retry_after_secs}s")]
15 RateLimited { retry_after_secs: u64 },
16
17 #[error("context window exceeded: {input_tokens} tokens > {limit} limit")]
18 ContextWindowExceeded { input_tokens: u64, limit: u64 },
19
20 #[error("network error: {0}")]
21 Network(String),
22
23 #[error("serialization error: {0}")]
24 Serialization(String),
25
26 #[error("timeout")]
27 Timeout,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
33#[serde(rename_all = "lowercase")]
34pub enum ChatRole {
35 System,
36 User,
37 Assistant,
38 Tool,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct ChatMessage {
43 pub role: ChatRole,
44 pub content: String,
45}
46
47impl ChatMessage {
48 pub fn system(content: impl Into<String>) -> Self {
49 Self {
50 role: ChatRole::System,
51 content: content.into(),
52 }
53 }
54 pub fn user(content: impl Into<String>) -> Self {
55 Self {
56 role: ChatRole::User,
57 content: content.into(),
58 }
59 }
60 pub fn assistant(content: impl Into<String>) -> Self {
61 Self {
62 role: ChatRole::Assistant,
63 content: content.into(),
64 }
65 }
66}
67
68#[derive(Debug, Clone, Default, Serialize, Deserialize)]
70pub struct ModelConfig {
71 pub model: Option<String>,
73 pub max_tokens: Option<u32>,
75 pub temperature: Option<f32>,
77 pub system_prompt: Option<String>,
79 pub stop_sequences: Option<Vec<String>>,
81}
82
83#[derive(Debug, Clone)]
85pub struct ModelRequest {
86 pub messages: Vec<ChatMessage>,
87 pub config: ModelConfig,
88}
89
90impl ModelRequest {
91 pub fn new(messages: Vec<ChatMessage>) -> Self {
92 Self {
93 messages,
94 config: ModelConfig::default(),
95 }
96 }
97
98 pub fn with_config(mut self, config: ModelConfig) -> Self {
99 self.config = config;
100 self
101 }
102}
103
104#[derive(Debug, Clone)]
106pub struct StructuredRequest {
107 pub messages: Vec<ChatMessage>,
108 pub config: ModelConfig,
109 pub output_schema: serde_json::Value,
111}
112
113#[derive(Debug, Clone)]
115pub struct ModelResponse {
116 pub content: String,
118 pub model: String,
120 pub finish_reason: String,
122 pub input_tokens: u64,
124 pub output_tokens: u64,
126 pub structured: Option<serde_json::Value>,
128}
129
130#[async_trait]
138pub trait ModelAdapter: Send + Sync {
139 fn system_name(&self) -> &'static str;
141
142 fn default_model(&self) -> &str;
144
145 async fn chat(&self, request: ModelRequest) -> Result<ModelResponse, ModelError>;
147
148 async fn structured_output(
152 &self,
153 request: StructuredRequest,
154 ) -> Result<ModelResponse, ModelError>;
155}