use std::time::Duration;
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc;
use crate::types::{Step, UsageMetadata};
#[derive(Debug, Clone)]
pub struct ChatResult {
pub(super) text: String,
pub(super) usage: Option<UsageMetadata>,
pub(super) structured_output: Option<serde_json::Value>,
}
impl ChatResult {
#[must_use]
pub fn text(&self) -> &str {
&self.text
}
#[must_use]
pub fn into_string(self) -> String {
self.text
}
#[must_use]
pub fn usage(&self) -> Option<&UsageMetadata> {
self.usage.as_ref()
}
#[must_use]
pub fn structured_output(&self) -> Option<&serde_json::Value> {
self.structured_output.as_ref()
}
}
impl std::ops::Deref for ChatResult {
type Target = str;
fn deref(&self) -> &str {
&self.text
}
}
impl PartialEq<&str> for ChatResult {
fn eq(&self, other: &&str) -> bool {
self.text == *other
}
}
impl PartialEq<String> for ChatResult {
fn eq(&self, other: &String) -> bool {
self.text == *other
}
}
impl std::fmt::Display for ChatResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.text)
}
}
impl From<ChatResult> for String {
fn from(result: ChatResult) -> Self {
result.text
}
}
pub(crate) const ERROR_DRAIN_TIMEOUT: Duration = Duration::from_millis(50);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCallEvent {
pub name: String,
pub args: serde_json::Value,
pub id: Option<String>,
#[serde(default)]
pub canonical_path: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamError {
pub message: String,
}
impl std::fmt::Display for StreamError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "stream error: {}", self.message)
}
}
impl std::error::Error for StreamError {}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ResponseEvent {
TextChunk(String),
ThoughtChunk(String),
ToolCall(ToolCallEvent),
ToolResult(crate::types::ToolResult),
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StreamChunk {
Text(String),
Thought(String),
ToolCall(ToolCallEvent),
}
#[doc(hidden)]
#[derive(Debug, Default)]
pub struct ChatResponseSharedState {
pub usage: Option<UsageMetadata>,
pub structured_output: Option<serde_json::Value>,
}
#[derive(Debug)]
pub(crate) struct StreamReceivers {
pub(super) text: Option<mpsc::Receiver<String>>,
pub(super) thought: Option<mpsc::Receiver<String>>,
pub(super) tool_call: Option<mpsc::Receiver<ToolCallEvent>>,
pub(super) error: Option<mpsc::Receiver<StreamError>>,
pub(super) event: Option<mpsc::Receiver<ResponseEvent>>,
pub(super) step: Option<mpsc::Receiver<Step>>,
pub(super) chunk: Option<mpsc::Receiver<StreamChunk>>,
}
impl StreamReceivers {
pub(super) fn new(
text: mpsc::Receiver<String>,
thought: mpsc::Receiver<String>,
tool_call: mpsc::Receiver<ToolCallEvent>,
error: mpsc::Receiver<StreamError>,
event: mpsc::Receiver<ResponseEvent>,
step: mpsc::Receiver<Step>,
chunk: mpsc::Receiver<StreamChunk>,
) -> Self {
Self {
text: Some(text),
thought: Some(thought),
tool_call: Some(tool_call),
error: Some(error),
event: Some(event),
step: Some(step),
chunk: Some(chunk),
}
}
}