Skip to main content

magic_coder_types/protocol/
types.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use uuid::Uuid;
4
5#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
6pub enum Role {
7    Assistant,
8    User,
9}
10
11#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
12pub enum RuntimeMode {
13    Agent,
14    Plan,
15}
16
17#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
18pub enum ToolExecutionTarget {
19    Unspecified,
20    /// Tool must be executed by a connected client (TUI/VS Code).
21    ClientLocal,
22    /// Tool is executed server-side (agents/MCP/etc). Clients must not provide outputs.
23    ServerAgents,
24}
25
26#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
27pub enum ToolCallApproval {
28    Unspecified,
29    Pending,
30    Approved,
31    AutoApproved,
32    Rejected,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct ToolCallOutput {
37    /// Tool call id
38    pub id: String,
39
40    pub is_error: bool,
41    pub output: String,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub duration_seconds: Option<i32>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub enum ClientMessage {
48    HelloMath {
49        /// Random per-client-instance id (generated on client startup).
50        ///
51        /// Used for multi-client tool-call claiming/coordination. Not derived from auth token.
52        client_instance_id: String,
53        /// Client version.
54        version: String,
55        /// Minimum supported server version (the client can work with any server >= this).
56        min_supported_version: String,
57    },
58    /// Send a user message.
59    ///
60    /// If `thread_id` is `None`, the server creates a new thread and returns it in `SendMessageAck`.
61    /// `request_id` is a client-generated correlation id for 1:1 request↔response mapping.
62    SendMessage {
63        request_id: Uuid,
64        thread_id: Option<Uuid>,
65        text: String,
66    },
67    /// Update/refresh auth token without reconnecting the WebSocket.
68    UpdateAuthToken {
69        token: String,
70    },
71    /// Update the client's workspace roots / default root (used for prompt context + validations).
72    ///
73    /// Sent separately from `HelloMath` so roots can be updated without reconnecting.
74    UpdateWorkspaceRoots {
75        default_root: String,
76        workspace_roots: Vec<String>,
77    },
78    /// Set runtime mode for a thread.
79    SetRuntimeMode {
80        thread_id: Uuid,
81        mode: RuntimeMode,
82    },
83    RejectToolCall {
84        id: String,
85        #[serde(default, skip_serializing_if = "Option::is_none")]
86        reason: Option<String>,
87    },
88    AcceptToolCall {
89        id: String,
90    },
91    ToolCallOutputs {
92        outputs: Vec<ToolCallOutput>,
93    },
94    /// Cancel the current in-progress generation for a specific assistant message.
95    CancelGeneration {
96        message_id: Uuid,
97    },
98}
99
100#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
101pub struct Usage {
102    pub input_tokens: i32,
103    pub output_tokens: i32,
104}
105
106#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
107pub enum MessageStatus {
108    Completed,
109    /// The agent is waiting for the client/user to provide more input (e.g. tool outputs / approvals)
110    /// before it can continue generation.
111    WaitingForUser,
112    Failed,
113    Cancelled,
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub enum ServerMessage {
118    HelloMagic {
119        version: String,
120        min_supported_version: String,
121    },
122    VersionMismatch {
123        server_version: String,
124        server_min_supported_version: String,
125    },
126    Goodbye {
127        reconnect: bool,
128    },
129    SendMessageAck {
130        request_id: Uuid,
131        thread_id: Uuid,
132        user_message_id: Uuid,
133    },
134    AuthUpdated,
135    RuntimeModeUpdated {
136        thread_id: Uuid,
137        mode: RuntimeMode,
138        #[serde(default, skip_serializing_if = "Option::is_none")]
139        changed_by_client_instance_id: Option<String>,
140    },
141    MessageHeader {
142        message_id: Uuid,
143        thread_id: Uuid,
144        role: Role,
145        #[serde(default, skip_serializing_if = "Option::is_none")]
146        request_id: Option<Uuid>,
147    },
148    ReasoningDelta {
149        message_id: Uuid,
150        content: String,
151    },
152    TextDelta {
153        message_id: Uuid,
154        content: String,
155    },
156    ToolCallHeader {
157        message_id: Uuid,
158        tool_call_id: String,
159        name: String,
160        execution_target: ToolExecutionTarget,
161        approval: ToolCallApproval,
162    },
163    ToolCallArgumentsDelta {
164        message_id: Uuid,
165        tool_call_id: String,
166        delta: String,
167    },
168    ToolCall {
169        message_id: Uuid,
170        tool_call_id: String,
171        args: Value,
172    },
173    ToolCallClaimed {
174        message_id: Uuid,
175        tool_call_id: String,
176        claimed_by_client_instance_id: String,
177    },
178    ToolCallApprovalUpdated {
179        message_id: Uuid,
180        tool_call_id: String,
181        approval: ToolCallApproval,
182    },
183    MessageDone {
184        message_id: Uuid,
185        #[serde(default, skip_serializing_if = "Option::is_none")]
186        usage: Option<Usage>,
187        status: MessageStatus,
188    },
189    Error {
190        #[serde(default, skip_serializing_if = "Option::is_none")]
191        request_id: Option<Uuid>,
192        #[serde(default, skip_serializing_if = "Option::is_none")]
193        message_id: Option<Uuid>,
194        code: String,
195        message: String,
196    },
197}