Skip to main content

aether_core/events/
user_message.rs

1use llm::{ChatMessage, ContentBlock, MessageId, ReasoningEffort, StreamingModelProvider, ToolDefinition};
2
3/// The unified command type sent to the agent input channel.
4///
5/// Wraps both user-facing actions ([`UserCommand`]) and runtime-internal
6/// operations ([`AgentCommand`]).
7#[derive(Debug)]
8pub enum Command {
9    UserCommand(UserCommand),
10    AgentCommand(AgentCommand),
11}
12
13impl Command {
14    pub fn text(text: impl Into<String>) -> Self {
15        Self::with_content(vec![ContentBlock::text(text)])
16    }
17
18    pub fn with_content(content: Vec<ContentBlock>) -> Self {
19        Self::with_message_id(MessageId::new(), content)
20    }
21
22    pub fn with_message_id(message_id: MessageId, content: Vec<ContentBlock>) -> Self {
23        Self::UserCommand(UserCommand::Text { message_id, content })
24    }
25
26    pub fn cancel() -> Self {
27        Self::UserCommand(UserCommand::Cancel)
28    }
29
30    pub fn clear_context() -> Self {
31        Self::UserCommand(UserCommand::ClearContext)
32    }
33
34    pub fn agent(command: AgentCommand) -> Self {
35        Self::AgentCommand(command)
36    }
37}
38
39/// User-initiated actions that the agent processes as part of normal interaction.
40pub enum UserCommand {
41    Text { message_id: MessageId, content: Vec<ContentBlock> },
42    Cancel,
43    ClearContext,
44}
45
46impl std::fmt::Debug for UserCommand {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        match self {
49            UserCommand::Text { content, .. } => {
50                f.debug_struct("Text").field("content_blocks", &content.len()).finish()
51            }
52            UserCommand::Cancel => write!(f, "Cancel"),
53            UserCommand::ClearContext => write!(f, "ClearContext"),
54        }
55    }
56}
57
58/// Runtime-internal operations that modify agent state without user interaction.
59///
60/// These are sent by the runtime controller or MCP event pumps to update
61/// tools, model, instructions, or to sync conversation history across
62/// agent runtimes.
63pub enum AgentCommand {
64    SwitchModel(Box<dyn StreamingModelProvider>),
65    UpdateTools(Vec<ToolDefinition>),
66    UpdateMcpInstructions { server: String, body: Option<String> },
67    SetReasoningEffort(Option<ReasoningEffort>),
68    ReplaceConversation(Vec<ChatMessage>),
69}
70
71impl std::fmt::Debug for AgentCommand {
72    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73        match self {
74            AgentCommand::SwitchModel(provider) => {
75                f.debug_tuple("SwitchModel").field(&provider.display_name()).finish()
76            }
77            AgentCommand::UpdateTools(tools) => f.debug_tuple("UpdateTools").field(&tools.len()).finish(),
78            AgentCommand::UpdateMcpInstructions { server, body } => f
79                .debug_struct("UpdateMcpInstructions")
80                .field("server", server)
81                .field("body_len", &body.as_ref().map(String::len))
82                .finish(),
83            AgentCommand::SetReasoningEffort(effort) => f.debug_tuple("SetReasoningEffort").field(effort).finish(),
84            AgentCommand::ReplaceConversation(messages) => {
85                f.debug_tuple("ReplaceConversation").field(&messages.len()).finish()
86            }
87        }
88    }
89}