Skip to main content

robit_agent/
event.rs

1//! Agent event and message types for Frontend <-> Agent communication.
2
3use crate::tool::ToolResult;
4
5/// Unique session identifier (UUID v4).
6pub type SessionId = String;
7
8/// Create a new random session ID.
9pub fn new_session_id() -> SessionId {
10    uuid::Uuid::new_v4().to_string()
11}
12
13/// A media attachment (image, file, etc.) included in a user message.
14#[derive(Debug, Clone)]
15pub struct MediaAttachment {
16    /// MIME type (e.g. "image/jpeg", "application/pdf").
17    pub content_type: String,
18    /// URL to access the media.
19    pub url: String,
20    /// Original filename if available.
21    pub filename: Option<String>,
22    /// File size in bytes if available.
23    pub size: Option<u64>,
24    /// Image width in pixels if available.
25    pub width: Option<u32>,
26    /// Image height in pixels if available.
27    pub height: Option<u32>,
28}
29
30impl MediaAttachment {
31    /// Whether this attachment is an image.
32    pub fn is_image(&self) -> bool {
33        self.content_type.starts_with("image/")
34    }
35
36    /// A human-readable description for the LLM.
37    pub fn describe(&self) -> String {
38        let filename = self.filename.as_deref().unwrap_or("unknown");
39        let type_desc = if self.is_image() { "图片" } else { "文件" };
40        let size_str = self
41            .size
42            .map(|s| format!(" ({:.1}KB)", s as f64 / 1024.0))
43            .unwrap_or_default();
44        format!("[用户发送了{}: {}{}]", type_desc, filename, size_str)
45    }
46}
47
48/// Events pushed from Agent to Frontend.
49#[derive(Debug)]
50pub enum AgentEvent {
51    /// Streaming text delta from LLM response.
52    TextDelta(String),
53
54    /// LLM requested a tool call. Frontend should display and optionally wait for confirmation.
55    ToolCallRequested {
56        tool_call_id: String,
57        name: String,
58        arguments: String,
59    },
60
61    /// Tool execution completed with result.
62    ToolCallResult {
63        tool_call_id: String,
64        result: ToolResult,
65    },
66
67    /// Current turn is complete (LLM finished responding, no more tool calls).
68    TurnComplete,
69
70    /// An error occurred during agent execution.
71    Error(crate::error::AgentError),
72
73    /// A skill was triggered. Frontend can display this as a system notice.
74    SkillTriggered { name: String, description: String },
75}
76
77/// Messages sent from Frontend to Agent.
78#[derive(Debug)]
79pub enum FrontendMessage {
80    /// User typed a new message with optional media attachments.
81    UserInput {
82        text: String,
83        attachments: Vec<MediaAttachment>,
84    },
85
86    /// User wants to cancel the current operation.
87    Cancel,
88
89    /// User responded to a tool confirmation request.
90    ConfirmationResponse {
91        tool_call_id: String,
92        approved: bool,
93    },
94}
95
96// Keep backward compatibility: from String to UserInput with no attachments.
97impl From<String> for FrontendMessage {
98    fn from(text: String) -> Self {
99        Self::UserInput {
100            text,
101            attachments: vec![],
102        }
103    }
104}
105
106// Also support &str for convenience.
107impl From<&str> for FrontendMessage {
108    fn from(text: &str) -> Self {
109        Self::UserInput {
110            text: text.to_string(),
111            attachments: vec![],
112        }
113    }
114}