use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum UserInput {
Text(String),
Parts(Vec<ContentPart>),
}
impl From<String> for UserInput {
fn from(value: String) -> Self {
UserInput::Text(value)
}
}
impl From<&str> for UserInput {
fn from(value: &str) -> Self {
UserInput::Text(value.to_string())
}
}
impl From<Vec<ContentPart>> for UserInput {
fn from(value: Vec<ContentPart>) -> Self {
UserInput::Parts(value)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ContentPart {
Text(TextPart),
Think(ThinkPart),
#[serde(rename = "image_url")]
ImageUrl(ImageUrlPart),
#[serde(rename = "audio_url")]
AudioUrl(AudioUrlPart),
#[serde(rename = "video_url")]
VideoUrl(VideoUrlPart),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TextPart {
pub text: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ThinkPart {
pub think: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub encrypted: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ImageUrlPart {
pub image_url: MediaUrl,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AudioUrlPart {
pub audio_url: MediaUrl,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct VideoUrlPart {
pub video_url: MediaUrl,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MediaUrl {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DisplayBlock {
#[serde(rename = "type")]
pub block_type: DisplayBlockType,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub old_text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub items: Option<Vec<TodoDisplayItem>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub command: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum DisplayBlockType {
Brief,
Diff,
Todo,
Shell,
#[serde(rename = "unknown")]
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TodoDisplayItem {
pub title: String,
pub status: TodoStatus,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum TodoStatus {
Pending,
InProgress,
Done,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ToolReturnValue {
pub is_error: bool,
pub output: ToolOutput,
pub message: String,
pub display: Vec<DisplayBlock>,
#[serde(skip_serializing_if = "Option::is_none")]
pub extras: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum ToolOutput {
Text(String),
Parts(Vec<ContentPart>),
}
impl From<String> for ToolOutput {
fn from(value: String) -> Self {
ToolOutput::Text(value)
}
}
impl From<&str> for ToolOutput {
fn from(value: &str) -> Self {
ToolOutput::Text(value.to_string())
}
}
impl From<Vec<ContentPart>> for ToolOutput {
fn from(value: Vec<ContentPart>) -> Self {
ToolOutput::Parts(value)
}
}