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