Skip to main content

j_agent/
protocol.rs

1//! WebSocket 远程控制协议类型定义
2
3use serde::{Deserialize, Serialize};
4
5// Re-export SessionMeta from storage to avoid duplication
6pub use crate::storage::SessionMeta;
7
8/// 客户端 → 服务端 消息
9#[derive(Debug, Deserialize)]
10#[serde(tag = "type")]
11pub enum WsInbound {
12    /// 发送聊天消息
13    #[serde(rename = "send_message")]
14    SendMessage { content: String },
15    /// 工具确认(allow / allow_always / reject / reject_with_reason)
16    #[serde(rename = "tool_confirm")]
17    ToolConfirm {
18        action: String,
19        #[serde(default)]
20        reason: Option<String>,
21    },
22    /// Ask 工具回答
23    #[serde(rename = "ask_response")]
24    AskResponse {
25        /// 问题文本 → 用户答案(选项 label 或自由文本)
26        answers: std::collections::HashMap<String, String>,
27    },
28    /// 取消当前流式请求
29    #[serde(rename = "cancel")]
30    Cancel,
31    /// 请求全量状态同步
32    #[serde(rename = "sync")]
33    Sync,
34    /// ECDH 密钥交换(客户端发送公钥)
35    #[serde(rename = "key_exchange")]
36    KeyExchange { client_pk: String },
37    /// 心跳 ping
38    #[serde(rename = "ping")]
39    Ping,
40    /// 请求会话列表
41    #[serde(rename = "list_sessions")]
42    ListSessions,
43    /// 切换到指定会话
44    #[serde(rename = "switch_session")]
45    SwitchSession { session_id: String },
46    /// 新建会话
47    #[serde(rename = "new_session")]
48    NewSession,
49    /// 选择模型(按索引)
50    #[serde(rename = "select_model")]
51    SelectModel { index: usize },
52    /// 选择主题(按索引)
53    #[serde(rename = "select_theme")]
54    SelectTheme { index: usize },
55    /// 请求配置数据
56    #[serde(rename = "request_config")]
57    RequestConfig { tab: String },
58    /// 配置编辑提交
59    #[serde(rename = "config_edit_submit")]
60    ConfigEditSubmit { value: String },
61    /// 配置项切换(toggle enabled/disabled)
62    #[serde(rename = "config_toggle")]
63    ConfigToggle { index: usize },
64    /// 开始归档确认
65    #[serde(rename = "start_archive")]
66    StartArchive,
67    /// 使用默认名称归档
68    #[serde(rename = "archive_with_default")]
69    ArchiveWithDefault,
70    /// 使用自定义名称归档
71    #[serde(rename = "archive_with_custom")]
72    ArchiveWithCustom { name: String },
73    /// 不归档,直接清空会话
74    #[serde(rename = "clear_session")]
75    ClearSession,
76    /// 请求归档列表
77    #[serde(rename = "start_archive_list")]
78    StartArchiveList,
79    /// 恢复归档(按索引)
80    #[serde(rename = "restore_archive")]
81    RestoreArchive { index: usize },
82    /// 删除归档(按索引)
83    #[serde(rename = "delete_archive")]
84    DeleteArchive { index: usize },
85    /// 删除会话(按索引,在会话列表中)
86    #[serde(rename = "delete_session")]
87    DeleteSession { index: usize },
88    /// Agent 权限确认
89    #[serde(rename = "agent_perm_confirm")]
90    AgentPermConfirm { approve: bool },
91    /// Plan 审批
92    #[serde(rename = "plan_approval")]
93    PlanApproval {
94        approve: bool,
95        #[serde(default)]
96        content: Option<String>,
97    },
98    /// 切换自动审批
99    #[serde(rename = "toggle_auto_approve")]
100    ToggleAutoApprove,
101    // ── 文件操作 ──
102    /// 列出目录内容
103    #[serde(rename = "file_list")]
104    FileList { path: String },
105    /// 读取文件内容
106    #[serde(rename = "file_read")]
107    FileRead { path: String },
108    /// 写入文件内容
109    #[serde(rename = "file_write")]
110    FileWrite { path: String, content: String },
111    // ── 终端操作 ──
112    /// 执行终端命令
113    #[serde(rename = "terminal_exec")]
114    TerminalExec { command: String },
115    /// 终端中断 (Ctrl-C)
116    #[serde(rename = "terminal_interrupt")]
117    TerminalInterrupt,
118}
119
120/// 服务端 → 客户端 消息
121#[derive(Debug, Clone, Serialize)]
122#[serde(tag = "type")]
123#[allow(dead_code)]
124pub enum WsOutbound {
125    /// 流式文本块
126    #[serde(rename = "stream_chunk")]
127    StreamChunk { content: String },
128    /// 完整消息(流结束后或用户消息)
129    #[serde(rename = "message")]
130    Message { role: String, content: String },
131    /// 工具确认请求
132    #[serde(rename = "tool_confirm_request")]
133    ToolConfirmRequest { tools: Vec<ToolConfirmInfo> },
134    /// Ask 工具提问请求
135    #[serde(rename = "ask_request")]
136    AskRequest { questions: Vec<AskQuestionInfo> },
137    /// 工具开始执行
138    #[serde(rename = "tool_call")]
139    ToolCall {
140        id: String,
141        name: String,
142        arguments: String,
143    },
144    /// 工具执行结果
145    #[serde(rename = "tool_result")]
146    ToolResult {
147        id: String,
148        name: String,
149        output: String,
150        is_error: bool,
151    },
152    /// 状态变化
153    #[serde(rename = "status")]
154    Status { state: String },
155    /// 全量状态同步
156    #[serde(rename = "session_sync")]
157    SessionSync {
158        messages: Vec<SyncMessage>,
159        status: String,
160        model: String,
161        #[serde(default)]
162        context_tokens: usize,
163        #[serde(default)]
164        message_count: usize,
165        #[serde(default)]
166        auto_approve: bool,
167    },
168    /// 心跳 pong
169    #[serde(rename = "pong")]
170    Pong,
171    /// ECDH 密钥协商:服务端发送公钥
172    #[serde(rename = "server_hello")]
173    ServerHello { server_pk: String },
174    /// ECDH 密钥协商成功确认
175    #[serde(rename = "key_exchange_ok")]
176    KeyExchangeOk,
177    /// 错误消息
178    #[serde(rename = "error")]
179    Error { message: String },
180    /// 会话列表
181    #[serde(rename = "session_list")]
182    SessionList { sessions: Vec<SessionMeta> },
183    /// 会话已切换
184    #[serde(rename = "session_switched")]
185    SessionSwitched { session_id: String },
186    /// 模型列表
187    #[serde(rename = "model_list")]
188    ModelList {
189        models: Vec<ModelInfo>,
190        active_index: usize,
191    },
192    /// 主题列表
193    #[serde(rename = "theme_list")]
194    ThemeList {
195        themes: Vec<ThemeInfo>,
196        active_index: usize,
197    },
198    /// 配置数据
199    #[serde(rename = "config_data")]
200    ConfigData {
201        tab: String,
202        fields: Vec<ConfigField>,
203    },
204    /// 归档列表
205    #[serde(rename = "archive_list")]
206    ArchiveList { archives: Vec<ArchiveInfo> },
207    /// Agent 权限确认请求
208    #[serde(rename = "agent_perm_request")]
209    AgentPermRequest {
210        agent_name: String,
211        tool_name: String,
212        arguments: String,
213    },
214    /// Plan 审批请求
215    #[serde(rename = "plan_approval_request")]
216    PlanApprovalRequest {
217        agent_name: String,
218        plan_summary: String,
219    },
220    // ── 文件操作 ──
221    /// 目录列表结果
222    #[serde(rename = "file_list_result")]
223    FileListResult {
224        path: String,
225        entries: Vec<FileEntry>,
226    },
227    /// 文件内容结果
228    #[serde(rename = "file_read_result")]
229    FileReadResult {
230        path: String,
231        content: String,
232        #[serde(default)]
233        error: Option<String>,
234    },
235    /// 文件写入结果
236    #[serde(rename = "file_write_result")]
237    FileWriteResult {
238        path: String,
239        success: bool,
240        #[serde(default)]
241        error: Option<String>,
242    },
243    // ── 终端操作 ──
244    /// 终端命令输出
245    #[serde(rename = "terminal_output")]
246    TerminalOutput {
247        output: String,
248        exit_code: Option<i32>,
249    },
250}
251
252/// 工具确认信息
253#[derive(Debug, Clone, Serialize)]
254pub struct ToolConfirmInfo {
255    pub id: String,
256    pub name: String,
257    pub arguments: String,
258    pub confirm_message: String,
259}
260
261/// Ask 工具问题信息
262#[derive(Debug, Clone, Serialize)]
263pub struct AskQuestionInfo {
264    pub question: String,
265    pub header: String,
266    pub options: Vec<AskOptionInfo>,
267    pub multi_select: bool,
268}
269
270/// Ask 工具选项信息
271#[derive(Debug, Clone, Serialize)]
272pub struct AskOptionInfo {
273    pub label: String,
274    pub description: String,
275}
276
277/// 同步工具调用信息
278#[derive(Debug, Clone, Serialize)]
279pub struct SyncToolCall {
280    pub id: String,
281    pub name: String,
282    pub arguments: String,
283}
284
285/// 同步消息(完整版 ChatMessage)
286#[derive(Debug, Clone, Serialize)]
287pub struct SyncMessage {
288    pub role: String,
289    #[serde(default)]
290    pub content: String,
291    #[serde(skip_serializing_if = "Option::is_none")]
292    pub tool_calls: Option<Vec<SyncToolCall>>,
293    #[serde(skip_serializing_if = "Option::is_none")]
294    pub tool_call_id: Option<String>,
295}
296
297/// 模型信息
298#[derive(Debug, Clone, Serialize)]
299pub struct ModelInfo {
300    pub name: String,
301    pub model: String,
302    pub provider: String,
303    pub supports_vision: bool,
304}
305
306/// 主题信息
307#[derive(Debug, Clone, Serialize)]
308pub struct ThemeInfo {
309    pub name: String,
310    pub display_name: String,
311}
312
313/// 配置字段
314#[derive(Debug, Clone, Serialize)]
315pub struct ConfigField {
316    pub key: String,
317    pub label: String,
318    pub value: String,
319    /// "text" | "bool" | "select" | "action"
320    pub field_type: String,
321    pub editable: bool,
322    /// select 类型的选项列表
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub options: Option<Vec<String>>,
325}
326
327/// 归档信息
328#[derive(Debug, Clone, Serialize)]
329pub struct ArchiveInfo {
330    pub name: String,
331    pub created_at: String,
332    pub message_count: usize,
333}
334
335/// 文件条目
336#[derive(Debug, Clone, Serialize)]
337pub struct FileEntry {
338    pub name: String,
339    pub is_dir: bool,
340    pub size: u64,
341    pub modified: String,
342}