1pub mod anthropic;
2pub mod openai;
3
4use std::{future::Future, pin::Pin};
5
6use serde::{Deserialize, Serialize};
7use tokio::sync::mpsc::UnboundedReceiver;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Message {
11 pub role: Role,
12 pub content: Vec<ContentBlock>,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "lowercase")]
17pub enum Role {
18 User,
19 Assistant,
20 System,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24#[serde(tag = "type", rename_all = "snake_case")]
25pub enum ContentBlock {
26 Text(String),
27 Image {
28 media_type: String,
29 data: String,
30 },
31 ToolUse {
32 id: String,
33 name: String,
34 input: serde_json::Value,
35 },
36 ToolResult {
37 tool_use_id: String,
38 content: String,
39 is_error: bool,
40 },
41 Thinking {
42 thinking: String,
43 signature: String,
44 },
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct ToolDefinition {
49 pub name: String,
50 pub description: String,
51 pub input_schema: serde_json::Value,
52}
53
54#[derive(Debug, Clone)]
55pub struct StreamEvent {
56 pub event_type: StreamEventType,
57}
58
59#[derive(Debug, Clone)]
60pub enum StreamEventType {
61 TextDelta(String),
62 ThinkingDelta(String),
63 ThinkingComplete {
64 thinking: String,
65 signature: String,
66 },
67 ToolUseStart {
68 id: String,
69 name: String,
70 },
71 ToolUseInputDelta(String),
72 ToolUseEnd,
73 MessageStart,
74 MessageEnd {
75 stop_reason: StopReason,
76 usage: Usage,
77 },
78 Error(String),
79}
80
81#[derive(Debug, Clone)]
82pub enum StopReason {
83 EndTurn,
84 MaxTokens,
85 ToolUse,
86 StopSequence,
87}
88
89#[derive(Debug, Clone, Default)]
90pub struct Usage {
91 pub input_tokens: u32,
92 pub output_tokens: u32,
93 pub cache_read_tokens: u32,
94 pub cache_write_tokens: u32,
95}
96
97pub trait Provider: Send + Sync {
98 fn name(&self) -> &str;
99 fn model(&self) -> &str;
100 fn set_model(&mut self, model: String);
101 fn available_models(&self) -> Vec<String>;
102 fn supports_vision(&self) -> bool {
103 true
104 }
105 fn fetch_models(
106 &self,
107 ) -> Pin<Box<dyn Future<Output = anyhow::Result<Vec<String>>> + Send + '_>>;
108 fn stream(
109 &self,
110 messages: &[Message],
111 system: Option<&str>,
112 tools: &[ToolDefinition],
113 max_tokens: u32,
114 thinking_budget: u32,
115 ) -> Pin<Box<dyn Future<Output = anyhow::Result<UnboundedReceiver<StreamEvent>>> + Send + '_>>;
116}