Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/src/syntax.rs

12.4 KiB, 1 run

created by r2519314175:963, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! Daimond chat protocol syntax — command definitions for the
2//! `/chat` WebSocket endpoint.
3//!
4//! Daimond owns its syntax independently of Steel. Steel routes
5//! WebSocket connections with path `/chat` to the Daimond handler;
6//! Daimond then creates and uses its own `SyntaxRef` for parsing
7//! incoming commands and constructing outgoing responses.
8//!
9//! Command categories:
10//!
11//! - **Daimond** — session management and chat (`session_new`, `chat`, …)
12//! - **Response** — server-to-client responses (`data`, `text`, `done`, …)
13//!
14//! The `data`, `error`, and `info` commands are general-purpose
15//! response commands also found in Steel's syntax. They are
16//! duplicated here so Daimond is self-contained and does not depend
17//! on Steel's syntax definitions.
18
19use oxedyne_fe2o3_core::prelude::*;
20use oxedyne_fe2o3_jdat::{
21 prelude::*,
22 version::SemVer,
23};
24use oxedyne_fe2o3_syntax::{
25 cmd::{
26 Cmd,
27 CmdConfig,
28 },
29 core::{
30 Syntax,
31 SyntaxRef,
32 },
33};
34
35/// Build the Daimond chat protocol syntax.
36///
37/// Defines all commands the Daimond WS handler can receive from the
38/// client and all commands it can send back. The version should
39/// be bumped when the protocol changes incompatibly.
40pub fn build_syntax()
41 -> Outcome<SyntaxRef>
42{
43 let mut s = Syntax::new("daimond-chat")
44 .ver(SemVer::new(0, 1, 0))
45 .about("Daimond AI agent chat protocol");
46 s = res!(s.with_default_help_cmd());
47
48 // ┌───────────────────────┐
49 // │ RED — SESSION MGMT │
50 // └───────────────────────┘
51
52 // ----------------------------------------------------------------
53 // Command: session_new
54 // ----------------------------------------------------------------
55 let cmd = Cmd::from(CmdConfig {
56 name: fmt!("session_new"),
57 help: Some(fmt!("Create a new chat session.")),
58 vals: vec![
59 (Kind::Str, fmt!("Session name (optional)")),
60 (Kind::Str, fmt!("Model (optional)")),
61 ],
62 cat: fmt!("Daimond"),
63 ..Default::default()
64 });
65 s = res!(s.add_cmd(cmd));
66
67 // ----------------------------------------------------------------
68 // Command: session_list
69 // ----------------------------------------------------------------
70 let cmd = Cmd::from(CmdConfig {
71 name: fmt!("session_list"),
72 help: Some(fmt!("List all chat sessions for the current user.")),
73 cat: fmt!("Daimond"),
74 ..Default::default()
75 });
76 s = res!(s.add_cmd(cmd));
77
78 // ----------------------------------------------------------------
79 // Command: session_switch
80 // ----------------------------------------------------------------
81 let cmd = Cmd::from(CmdConfig {
82 name: fmt!("session_switch"),
83 help: Some(fmt!("Switch to a session by ID.")),
84 vals: vec![(Kind::Str, fmt!("Session ID"))],
85 cat: fmt!("Daimond"),
86 ..Default::default()
87 });
88 s = res!(s.add_cmd(cmd));
89
90 // ----------------------------------------------------------------
91 // Command: session_close
92 // ----------------------------------------------------------------
93 let cmd = Cmd::from(CmdConfig {
94 name: fmt!("session_close"),
95 help: Some(fmt!("Delete a session by ID.")),
96 vals: vec![(Kind::Str, fmt!("Session ID"))],
97 cat: fmt!("Daimond"),
98 ..Default::default()
99 });
100 s = res!(s.add_cmd(cmd));
101
102 // ----------------------------------------------------------------
103 // Command: session_rename
104 // ----------------------------------------------------------------
105 let cmd = Cmd::from(CmdConfig {
106 name: fmt!("session_rename"),
107 help: Some(fmt!("Rename a session.")),
108 vals: vec![
109 (Kind::Str, fmt!("Session ID")),
110 (Kind::Str, fmt!("New name")),
111 ],
112 cat: fmt!("Daimond"),
113 ..Default::default()
114 });
115 s = res!(s.add_cmd(cmd));
116
117 // ----------------------------------------------------------------
118 // Command: chat
119 // ----------------------------------------------------------------
120 let cmd = Cmd::from(CmdConfig {
121 name: fmt!("chat"),
122 help: Some(fmt!("Send a message to the current session's agent.")),
123 vals: vec![(Kind::Str, fmt!("Message content"))],
124 cat: fmt!("Daimond"),
125 ..Default::default()
126 });
127 s = res!(s.add_cmd(cmd));
128
129 // ----------------------------------------------------------------
130 // Commands: fs_list / fs_read / fs_delete / fs_write (file browser)
131 // ----------------------------------------------------------------
132 let cmd = Cmd::from(CmdConfig {
133 name: fmt!("fs_list"),
134 help: Some(fmt!("List a workspace directory.")),
135 vals: vec![(Kind::Str, fmt!("Directory path"))],
136 cat: fmt!("Daimond"),
137 ..Default::default()
138 });
139 s = res!(s.add_cmd(cmd));
140
141 let cmd = Cmd::from(CmdConfig {
142 name: fmt!("fs_read"),
143 help: Some(fmt!("Read a workspace text file.")),
144 vals: vec![(Kind::Str, fmt!("File path"))],
145 cat: fmt!("Daimond"),
146 ..Default::default()
147 });
148 s = res!(s.add_cmd(cmd));
149
150 let cmd = Cmd::from(CmdConfig {
151 name: fmt!("fs_delete"),
152 help: Some(fmt!("Delete a workspace file.")),
153 vals: vec![(Kind::Str, fmt!("File path"))],
154 cat: fmt!("Daimond"),
155 ..Default::default()
156 });
157 s = res!(s.add_cmd(cmd));
158
159 let cmd = Cmd::from(CmdConfig {
160 name: fmt!("fs_write"),
161 help: Some(fmt!("Create or overwrite a workspace file.")),
162 vals: vec![
163 (Kind::Str, fmt!("File path")),
164 (Kind::Str, fmt!("Content")),
165 ],
166 cat: fmt!("Daimond"),
167 ..Default::default()
168 });
169 s = res!(s.add_cmd(cmd));
170
171 // ┌───────────────────────┐
172 // │ RESPONSE │
173 // └───────────────────────┘
174
175 // ----------------------------------------------------------------
176 // Command: data (server → client: structured data)
177 // ----------------------------------------------------------------
178 let cmd = Cmd::from(CmdConfig {
179 name: fmt!("data"),
180 help: Some(fmt!("Data payload (JSON or structured).")),
181 vals: vec![(Kind::Unknown, fmt!("Data"))],
182 cat: fmt!("Response"),
183 ..Default::default()
184 });
185 s = res!(s.add_cmd(cmd));
186
187 // ----------------------------------------------------------------
188 // Command: text (server → client: streamed LLM token)
189 // ----------------------------------------------------------------
190 let cmd = Cmd::from(CmdConfig {
191 name: fmt!("text"),
192 help: Some(fmt!("Streamed text token from the LLM.")),
193 vals: vec![(Kind::Str, fmt!("Text content"))],
194 cat: fmt!("Response"),
195 ..Default::default()
196 });
197 s = res!(s.add_cmd(cmd));
198
199 // ----------------------------------------------------------------
200 // Command: tool_call (server → client: agent is invoking a tool)
201 // ----------------------------------------------------------------
202 let cmd = Cmd::from(CmdConfig {
203 name: fmt!("tool_call"),
204 help: Some(fmt!("The agent is invoking a tool.")),
205 vals: vec![
206 (Kind::Str, fmt!("Tool name")),
207 (Kind::Str, fmt!("JSON arguments")),
208 ],
209 cat: fmt!("Response"),
210 ..Default::default()
211 });
212 s = res!(s.add_cmd(cmd));
213
214 // ----------------------------------------------------------------
215 // Command: tool_result (server → client: a tool returned)
216 // ----------------------------------------------------------------
217 let cmd = Cmd::from(CmdConfig {
218 name: fmt!("tool_result"),
219 help: Some(fmt!("A tool returned its result.")),
220 vals: vec![
221 (Kind::Str, fmt!("Tool name")),
222 (Kind::Str, fmt!("Result text")),
223 ],
224 cat: fmt!("Response"),
225 ..Default::default()
226 });
227 s = res!(s.add_cmd(cmd));
228
229 // ----------------------------------------------------------------
230 // Command: fs_tree (server → client: directory listing JSON)
231 // ----------------------------------------------------------------
232 let cmd = Cmd::from(CmdConfig {
233 name: fmt!("fs_tree"),
234 help: Some(fmt!("Workspace directory listing (JSON).")),
235 vals: vec![(Kind::Str, fmt!("JSON entries"))],
236 cat: fmt!("Response"),
237 ..Default::default()
238 });
239 s = res!(s.add_cmd(cmd));
240
241 // ----------------------------------------------------------------
242 // Command: fs_content (server → client: file contents)
243 // ----------------------------------------------------------------
244 let cmd = Cmd::from(CmdConfig {
245 name: fmt!("fs_content"),
246 help: Some(fmt!("Workspace file contents.")),
247 vals: vec![
248 (Kind::Str, fmt!("File path")),
249 (Kind::Str, fmt!("Content")),
250 ],
251 cat: fmt!("Response"),
252 ..Default::default()
253 });
254 s = res!(s.add_cmd(cmd));
255
256 // ----------------------------------------------------------------
257 // Command: compacted (server → client: the history was folded)
258 // ----------------------------------------------------------------
259 let cmd = Cmd::from(CmdConfig {
260 name: fmt!("compacted"),
261 help: Some(fmt!("The conversation was folded to fit the context window.")),
262 vals: vec![
263 (Kind::U64, fmt!("Messages folded")),
264 (Kind::U64, fmt!("Messages kept")),
265 (Kind::Str, fmt!("What the fold did")),
266 ],
267 cat: fmt!("Response"),
268 ..Default::default()
269 });
270 s = res!(s.add_cmd(cmd));
271
272 // ----------------------------------------------------------------
273 // Command: truncated (server → client: the reply hit the output limit)
274 // ----------------------------------------------------------------
275 let cmd = Cmd::from(CmdConfig {
276 name: fmt!("truncated"),
277 help: Some(fmt!("The reply stopped at the model's output limit.")),
278 cat: fmt!("Response"),
279 ..Default::default()
280 });
281 s = res!(s.add_cmd(cmd));
282
283 // ----------------------------------------------------------------
284 // Command: interjected (server → client: a mid-turn steer landed)
285 // ----------------------------------------------------------------
286 //
287 // Emitted by `event_to_ws` since the interjection feature landed and never
288 // declared here, so on the native path every interjection reached the
289 // browser as `error "internal"` -- the user's own correction, lost.
290 let cmd = Cmd::from(CmdConfig {
291 name: fmt!("interjected"),
292 help: Some(fmt!("What the user said mid-turn, now in the conversation.")),
293 vals: vec![(Kind::Str, fmt!("What was said"))],
294 cat: fmt!("Response"),
295 ..Default::default()
296 });
297 s = res!(s.add_cmd(cmd));
298
299 // ----------------------------------------------------------------
300 // Command: done (server → client: agent turn complete)
301 // ----------------------------------------------------------------
302 let cmd = Cmd::from(CmdConfig {
303 name: fmt!("done"),
304 help: Some(fmt!("Agent turn complete.")),
305 cat: fmt!("Response"),
306 ..Default::default()
307 });
308 s = res!(s.add_cmd(cmd));
309
310 // ----------------------------------------------------------------
311 // Command: info (server → client: informational message)
312 // ----------------------------------------------------------------
313 let cmd = Cmd::from(CmdConfig {
314 name: fmt!("info"),
315 help: Some(fmt!("Informational message.")),
316 vals: vec![(Kind::Str, fmt!("Information message"))],
317 cat: fmt!("Response"),
318 ..Default::default()
319 });
320 s = res!(s.add_cmd(cmd));
321
322 // ----------------------------------------------------------------
323 // Command: error (server → client: error message)
324 // ----------------------------------------------------------------
325 let cmd = Cmd::from(CmdConfig {
326 name: fmt!("error"),
327 help: Some(fmt!("Error message.")),
328 vals: vec![(Kind::Str, fmt!("Error message"))],
329 cat: fmt!("Response"),
330 ..Default::default()
331 });
332 s = res!(s.add_cmd(cmd));
333
334 Ok(SyntaxRef::new(s))
335}