1use crate::{Context, error::ModelError};
2use async_trait::async_trait;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ModelInfo {
12 pub handle: String,
13 pub provider: String,
14 pub model: String,
15 pub context_window: u32,
16 pub input_cost_usd_per_million_tokens: Option<f64>,
17 pub output_cost_usd_per_million_tokens: Option<f64>,
18 pub supports_tool_use: bool,
19 pub supports_streaming: bool,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct ModelOutput {
24 pub text: Option<String>,
25 pub tool_calls: Vec<ToolCall>,
26 pub usage: Usage,
27 pub stop_reason: StopReason,
28 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub reasoning: Option<String>,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct ToolCall {
37 pub id: String,
38 pub name: String,
39 pub args: serde_json::Value,
40}
41
42#[derive(Debug, Clone, Default, Serialize, Deserialize)]
43pub struct Usage {
44 pub input_tokens: u32,
45 pub output_tokens: u32,
46 pub cached_input_tokens: u32,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
50#[serde(rename_all = "snake_case")]
51#[non_exhaustive]
52pub enum StopReason {
53 EndTurn,
54 ToolUse,
55 MaxTokens,
56 StopSequence,
57 Other,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
62#[non_exhaustive]
63pub enum ModelDelta {
64 Text(String),
65 ToolCallStart { id: String, name: String },
66 ToolCallArgs { id: String, partial_json: String },
67 ToolCallEnd { id: String },
68 Usage(Usage),
69 Stop(StopReason),
70}
71
72#[async_trait]
73pub trait Model: Send + Sync + 'static {
74 async fn complete(&self, ctx: &Context) -> Result<ModelOutput, ModelError>;
75
76 async fn stream(
78 &self,
79 ctx: &Context,
80 ) -> Result<futures::stream::BoxStream<'static, Result<ModelDelta, ModelError>>, ModelError>
81 {
82 let out = self.complete(ctx).await?;
83 let deltas: Vec<Result<ModelDelta, ModelError>> = out
84 .text
85 .into_iter()
86 .map(|t| Ok(ModelDelta::Text(t)))
87 .chain(std::iter::once(Ok(ModelDelta::Stop(out.stop_reason))))
88 .collect();
89 Ok(Box::pin(futures::stream::iter(deltas)))
90 }
91
92 fn info(&self) -> ModelInfo;
93}