1use crate::abort::AbortSignal;
10use crate::types::{
11 AssistantMessage, AssistantMessagePart, JsonObject, MessageId, MessageStatus, RunConfig,
12 ThreadMessage, ThreadStep,
13};
14use futures_core::Stream;
15use serde_json::Value;
16use std::collections::BTreeMap;
17use std::fmt;
18use std::future::Future;
19use std::pin::Pin;
20use std::sync::Arc;
21use std::task::{Context, Poll};
22
23#[derive(Clone, Debug, Default, PartialEq)]
26pub struct ToolDefinition {
27 pub description: Option<String>,
29 pub parameters: Value,
31}
32
33#[derive(Clone, Debug, Default, PartialEq)]
35pub struct ModelContext {
36 pub system: Option<String>,
38 pub tools: BTreeMap<String, ToolDefinition>,
40 pub call_settings: JsonObject,
42 pub config: JsonObject,
44}
45
46#[derive(Clone, Debug)]
48pub struct ChatModelRunOptions {
49 pub messages: Arc<[Arc<ThreadMessage>]>,
51 pub run_config: RunConfig,
53 pub abort_signal: AbortSignal,
55 pub context: ModelContext,
57 pub assistant_message_id: MessageId,
59 pub thread_id: Option<String>,
61 pub parent_id: Option<MessageId>,
63 pub message: AssistantMessage,
67}
68
69#[derive(Clone, Debug, Default, PartialEq)]
72pub struct RunResultMetadata {
73 pub state: Option<Value>,
75 pub annotations: Option<Vec<Value>>,
77 pub data: Option<Vec<Value>>,
79 pub steps: Option<Vec<ThreadStep>>,
81 pub timing: Option<Value>,
83 pub custom: Option<JsonObject>,
85}
86
87#[derive(Clone, Debug, Default, PartialEq)]
89pub struct ChatModelRunResult {
90 pub content: Option<Vec<AssistantMessagePart>>,
92 pub status: Option<MessageStatus>,
94 pub metadata: Option<RunResultMetadata>,
96}
97
98impl ChatModelRunResult {
99 pub fn content(content: Vec<AssistantMessagePart>) -> Self {
101 Self {
102 content: Some(content),
103 ..Self::default()
104 }
105 }
106 pub fn text(text: impl Into<String>) -> Self {
108 Self::content(vec![AssistantMessagePart::text(text)])
109 }
110 pub fn with_status(mut self, status: MessageStatus) -> Self {
112 self.status = Some(status);
113 self
114 }
115}
116
117#[derive(Clone, Debug, PartialEq)]
119#[non_exhaustive]
120pub enum RunError {
121 Aborted,
123 Failed {
126 message: String,
128 error: Option<Value>,
130 },
131}
132
133impl RunError {
134 pub fn failed(message: impl Into<String>) -> Self {
136 Self::Failed {
137 message: message.into(),
138 error: None,
139 }
140 }
141 pub fn status_error(&self) -> Option<Value> {
143 match self {
144 Self::Aborted => None,
145 Self::Failed { message, error } => Some(
146 error
147 .clone()
148 .unwrap_or_else(|| Value::String(message.clone())),
149 ),
150 }
151 }
152}
153
154impl fmt::Display for RunError {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 match self {
157 Self::Aborted => f.write_str("run aborted"),
158 Self::Failed { message, .. } => f.write_str(message),
159 }
160 }
161}
162impl std::error::Error for RunError {}
163
164pub type RunStream = Pin<Box<dyn Stream<Item = Result<ChatModelRunResult, RunError>>>>;
166
167pub trait ChatModelAdapter {
169 fn run(&self, options: ChatModelRunOptions) -> RunStream;
171}
172
173impl<F> ChatModelAdapter for F
174where
175 F: Fn(ChatModelRunOptions) -> RunStream,
176{
177 fn run(&self, options: ChatModelRunOptions) -> RunStream {
178 self(options)
179 }
180}
181
182pub fn once<F>(future: F) -> RunStream
184where
185 F: Future<Output = Result<ChatModelRunResult, RunError>> + 'static,
186{
187 Box::pin(Once {
188 future: Some(Box::pin(future)),
189 })
190}
191
192pub fn from_results(
194 results: impl IntoIterator<Item = Result<ChatModelRunResult, RunError>>,
195) -> RunStream {
196 Box::pin(Iter {
197 items: results.into_iter().collect::<Vec<_>>().into_iter(),
198 })
199}
200
201type ResultFuture = Pin<Box<dyn Future<Output = Result<ChatModelRunResult, RunError>>>>;
202
203struct Once {
204 future: Option<ResultFuture>,
205}
206
207impl Stream for Once {
208 type Item = Result<ChatModelRunResult, RunError>;
209 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
210 let Some(future) = self.future.as_mut() else {
211 return Poll::Ready(None);
212 };
213 match future.as_mut().poll(cx) {
214 Poll::Ready(result) => {
215 self.future = None;
216 Poll::Ready(Some(result))
217 }
218 Poll::Pending => Poll::Pending,
219 }
220 }
221}
222
223struct Iter {
224 items: std::vec::IntoIter<Result<ChatModelRunResult, RunError>>,
225}
226
227impl Stream for Iter {
228 type Item = Result<ChatModelRunResult, RunError>;
229 fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
230 Poll::Ready(self.items.next())
231 }
232}