use crate::abort::AbortSignal;
use crate::types::{
AssistantMessage, AssistantMessagePart, JsonObject, MessageId, MessageStatus, RunConfig,
ThreadMessage, ThreadStep,
};
use futures_core::Stream;
use serde_json::Value;
use std::collections::BTreeMap;
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ToolDefinition {
pub description: Option<String>,
pub parameters: Value,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ModelContext {
pub system: Option<String>,
pub tools: BTreeMap<String, ToolDefinition>,
pub call_settings: JsonObject,
pub config: JsonObject,
}
#[derive(Clone, Debug)]
pub struct ChatModelRunOptions {
pub messages: Arc<[Arc<ThreadMessage>]>,
pub run_config: RunConfig,
pub abort_signal: AbortSignal,
pub context: ModelContext,
pub assistant_message_id: MessageId,
pub thread_id: Option<String>,
pub parent_id: Option<MessageId>,
pub message: AssistantMessage,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct RunResultMetadata {
pub state: Option<Value>,
pub annotations: Option<Vec<Value>>,
pub data: Option<Vec<Value>>,
pub steps: Option<Vec<ThreadStep>>,
pub timing: Option<Value>,
pub custom: Option<JsonObject>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ChatModelRunResult {
pub content: Option<Vec<AssistantMessagePart>>,
pub status: Option<MessageStatus>,
pub metadata: Option<RunResultMetadata>,
}
impl ChatModelRunResult {
pub fn content(content: Vec<AssistantMessagePart>) -> Self {
Self {
content: Some(content),
..Self::default()
}
}
pub fn text(text: impl Into<String>) -> Self {
Self::content(vec![AssistantMessagePart::text(text)])
}
pub fn with_status(mut self, status: MessageStatus) -> Self {
self.status = Some(status);
self
}
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum RunError {
Aborted,
Failed {
message: String,
error: Option<Value>,
},
}
impl RunError {
pub fn failed(message: impl Into<String>) -> Self {
Self::Failed {
message: message.into(),
error: None,
}
}
pub fn status_error(&self) -> Option<Value> {
match self {
Self::Aborted => None,
Self::Failed { message, error } => Some(
error
.clone()
.unwrap_or_else(|| Value::String(message.clone())),
),
}
}
}
impl fmt::Display for RunError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Aborted => f.write_str("run aborted"),
Self::Failed { message, .. } => f.write_str(message),
}
}
}
impl std::error::Error for RunError {}
pub type RunStream = Pin<Box<dyn Stream<Item = Result<ChatModelRunResult, RunError>>>>;
pub trait ChatModelAdapter {
fn run(&self, options: ChatModelRunOptions) -> RunStream;
}
impl<F> ChatModelAdapter for F
where
F: Fn(ChatModelRunOptions) -> RunStream,
{
fn run(&self, options: ChatModelRunOptions) -> RunStream {
self(options)
}
}
pub fn once<F>(future: F) -> RunStream
where
F: Future<Output = Result<ChatModelRunResult, RunError>> + 'static,
{
Box::pin(Once {
future: Some(Box::pin(future)),
})
}
pub fn from_results(
results: impl IntoIterator<Item = Result<ChatModelRunResult, RunError>>,
) -> RunStream {
Box::pin(Iter {
items: results.into_iter().collect::<Vec<_>>().into_iter(),
})
}
type ResultFuture = Pin<Box<dyn Future<Output = Result<ChatModelRunResult, RunError>>>>;
struct Once {
future: Option<ResultFuture>,
}
impl Stream for Once {
type Item = Result<ChatModelRunResult, RunError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let Some(future) = self.future.as_mut() else {
return Poll::Ready(None);
};
match future.as_mut().poll(cx) {
Poll::Ready(result) => {
self.future = None;
Poll::Ready(Some(result))
}
Poll::Pending => Poll::Pending,
}
}
}
struct Iter {
items: std::vec::IntoIter<Result<ChatModelRunResult, RunError>>,
}
impl Stream for Iter {
type Item = Result<ChatModelRunResult, RunError>;
fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Ready(self.items.next())
}
}