1use std::sync::Arc;
4
5use async_trait::async_trait;
6use thiserror::Error;
7use tokio_util::sync::CancellationToken;
8
9use crate::{Message, ToolCall, ToolSpec};
10
11#[derive(Debug, Clone, Default, PartialEq, Eq)]
13pub struct Usage {
14 pub input_tokens: Option<u64>,
15 pub output_tokens: Option<u64>,
16}
17
18impl Usage {
19 pub(crate) fn add(&mut self, other: &Self) {
20 self.input_tokens = add_optional(self.input_tokens, other.input_tokens);
21 self.output_tokens = add_optional(self.output_tokens, other.output_tokens);
22 }
23}
24
25fn add_optional(left: Option<u64>, right: Option<u64>) -> Option<u64> {
26 match (left, right) {
27 (None, None) => None,
28 (left, right) => Some(left.unwrap_or(0).saturating_add(right.unwrap_or(0))),
29 }
30}
31
32#[derive(Debug, Clone)]
34pub struct ProviderRequest {
35 pub system_prompt: String,
36 pub messages: Vec<Message>,
37 pub tools: Vec<ToolSpec>,
38}
39
40#[derive(Debug, Clone)]
42pub struct AssistantResponse {
43 pub content: String,
44 pub tool_calls: Vec<ToolCall>,
45 pub usage: Usage,
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum ProviderErrorKind {
52 Provider,
53 ResponseLimit,
54 ToolLimit,
55 Cancelled,
56}
57
58#[derive(Debug, Error)]
59#[error("{message}")]
60pub struct ProviderError {
61 pub kind: ProviderErrorKind,
62 pub message: String,
63}
64
65impl ProviderError {
66 pub fn new(kind: ProviderErrorKind, message: impl Into<String>) -> Self {
67 Self {
68 kind,
69 message: message.into(),
70 }
71 }
72}
73
74#[async_trait]
78pub trait TextDeltaSink: Send + Sync {
79 async fn push(&self, delta: &str) -> Result<(), ProviderError>;
80}
81
82#[async_trait]
86pub trait Provider: Send + Sync {
87 fn model(&self) -> &str;
89
90 async fn complete(
91 &self,
92 request: ProviderRequest,
93 deltas: Arc<dyn TextDeltaSink>,
94 cancellation: CancellationToken,
95 ) -> Result<AssistantResponse, ProviderError>;
96}