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 | |
| 19 | use oxedyne_fe2o3_core::prelude::*; |
| 20 | use oxedyne_fe2o3_jdat::{ |
| 21 | prelude::*, |
| 22 | version::SemVer, |
| 23 | }; |
| 24 | use 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. |
| 40 | pub 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 | } |