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    /// Cancel the current in-progress generation for a specific assistant message.
82    CancelGeneration {
83        message_id: Uuid,
84    },
85}
86
87#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
88pub struct Usage {
89    pub input_tokens: i32,
90    pub output_tokens: i32,
91}
92
93#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
94pub enum MessageStatus {
95    Completed,
96    /// The agent is waiting for the client/user to provide more input (e.g. tool outputs / approvals)
97    /// before it can continue generation.
98    WaitingForUser,
99    Failed,
100    Cancelled,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub enum ServerMessage {
105    HelloMagic {
106        version: String,
107        min_supported_version: String,
108    },
109    VersionMismatch {
110        server_version: String,
111        server_min_supported_version: String,
112    },
113    Goodbye {
114        reconnect: bool,
115    },
116    SendMessageAck {
117        request_id: Uuid,
118        thread_id: Uuid,
119        user_message_id: Uuid,
120    },
121    AuthUpdated,
122    MessageHeader {
123        message_id: Uuid,
124        thread_id: Uuid,
125        role: Role,
126        #[serde(default, skip_serializing_if = "Option::is_none")]
127        request_id: Option<Uuid>,
128    },
129    ReasoningDelta {
130        message_id: Uuid,
131        content: String,
132    },
133    TextDelta {
134        message_id: Uuid,
135        content: String,
136    },
137    ToolCallHeader {
138        message_id: Uuid,
139        tool_call_id: String,
140        name: String,
141        execution_target: ToolExecutionTarget,
142        approval: ToolCallApproval,
143    },
144    ToolCallArgumentsDelta {
145        message_id: Uuid,
146        tool_call_id: String,
147        delta: String,
148    },
149    ToolCall {
150        message_id: Uuid,
151        tool_call_id: String,
152        args: Value,
153    },
154    ToolCallClaimed {
155        message_id: Uuid,
156        tool_call_id: String,
157        claimed_by_client_instance_id: String,
158    },
159    MessageDone {
160        message_id: Uuid,
161        #[serde(default, skip_serializing_if = "Option::is_none")]
162        usage: Option<Usage>,
163        status: MessageStatus,
164    },
165    Error {
166        #[serde(default, skip_serializing_if = "Option::is_none")]
167        request_id: Option<Uuid>,
168        #[serde(default, skip_serializing_if = "Option::is_none")]
169        message_id: Option<Uuid>,
170        code: String,
171        message: String,
172    },
173}
174