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