@newsails/veil-cli 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/.veil/agents/analyst/AGENT.md +21 -0
  2. package/.veil/agents/analyst/agent.json +23 -0
  3. package/.veil/agents/assistant/AGENT.md +15 -0
  4. package/.veil/agents/assistant/agent.json +19 -0
  5. package/.veil/agents/coder/AGENT.md +18 -0
  6. package/.veil/agents/coder/agent.json +19 -0
  7. package/.veil/agents/hello/AGENT.md +5 -0
  8. package/.veil/agents/hello/agent.json +13 -0
  9. package/.veil/agents/writer/AGENT.md +12 -0
  10. package/.veil/agents/writer/agent.json +17 -0
  11. package/.veil/memory/MEMORY.md +343 -0
  12. package/.veil/memory/agents/analyst/MEMORY.md +55 -0
  13. package/.veil/memory/agents/hello/MEMORY.md +12 -0
  14. package/.veil/runtime.pid +1 -0
  15. package/.veil/settings.json +10 -0
  16. package/.veil-studio/studio.db +0 -0
  17. package/.veil-studio/studio.db-shm +0 -0
  18. package/.veil-studio/studio.db-wal +0 -0
  19. package/PLAN/01-vision.md +26 -0
  20. package/PLAN/02-tech-stack.md +94 -0
  21. package/PLAN/03-agents.md +232 -0
  22. package/PLAN/04-runtime.md +171 -0
  23. package/PLAN/05-tools.md +211 -0
  24. package/PLAN/06-communication.md +243 -0
  25. package/PLAN/07-storage.md +218 -0
  26. package/PLAN/08-api-cli.md +153 -0
  27. package/PLAN/09-permissions.md +108 -0
  28. package/PLAN/10-ably.md +105 -0
  29. package/PLAN/11-file-formats.md +442 -0
  30. package/PLAN/12-folder-structure.md +205 -0
  31. package/PLAN/13-operations.md +212 -0
  32. package/PLAN/README.md +23 -0
  33. package/README.md +128 -0
  34. package/REPORT.md +174 -0
  35. package/TODO.md +45 -0
  36. package/ai-tests/FRONTEND_PROMPT.md +220 -0
  37. package/ai-tests/Research & Planning.md +814 -0
  38. package/ai-tests/prompt-001-basic-api.md +230 -0
  39. package/ai-tests/prompt-002-basic-flows.md +230 -0
  40. package/ai-tests/prompt-003-agent-behaviors.md +220 -0
  41. package/api/middleware.js +60 -0
  42. package/api/routes/agents.js +193 -0
  43. package/api/routes/chat.js +93 -0
  44. package/api/routes/completions.js +122 -0
  45. package/api/routes/daemons.js +80 -0
  46. package/api/routes/memory.js +169 -0
  47. package/api/routes/models.js +40 -0
  48. package/api/routes/remote-methods.js +74 -0
  49. package/api/routes/sessions.js +208 -0
  50. package/api/routes/settings.js +108 -0
  51. package/api/routes/system.js +50 -0
  52. package/api/routes/tasks.js +270 -0
  53. package/api/server.js +120 -0
  54. package/cli/formatter.js +70 -0
  55. package/cli/index.js +443 -0
  56. package/cli/parser.js +113 -0
  57. package/config/config.json +10 -0
  58. package/config/models.json +6826 -0
  59. package/core/agent.js +329 -0
  60. package/core/cancel.js +38 -0
  61. package/core/compaction.js +176 -0
  62. package/core/events.js +13 -0
  63. package/core/loop.js +564 -0
  64. package/core/memory.js +51 -0
  65. package/core/prompt.js +185 -0
  66. package/core/queue.js +96 -0
  67. package/core/registry.js +291 -0
  68. package/core/remote-methods.js +124 -0
  69. package/core/router.js +386 -0
  70. package/core/running-sessions.js +18 -0
  71. package/docs/api/01-system.md +84 -0
  72. package/docs/api/02-agents.md +374 -0
  73. package/docs/api/03-chat.md +269 -0
  74. package/docs/api/04-tasks.md +470 -0
  75. package/docs/api/05-sessions.md +444 -0
  76. package/docs/api/06-daemons.md +142 -0
  77. package/docs/api/07-memory.md +186 -0
  78. package/docs/api/08-settings.md +133 -0
  79. package/docs/api/09-models.md +119 -0
  80. package/docs/api/09-websocket.md +350 -0
  81. package/docs/api/10-completions.md +134 -0
  82. package/docs/api/README.md +116 -0
  83. package/docs/guide/01-quickstart.md +220 -0
  84. package/docs/guide/02-folder-structure.md +185 -0
  85. package/docs/guide/03-configuration.md +252 -0
  86. package/docs/guide/04-agents.md +267 -0
  87. package/docs/guide/05-cli.md +290 -0
  88. package/docs/guide/06-tools.md +643 -0
  89. package/docs/guide/07-permissions.md +236 -0
  90. package/docs/guide/08-memory.md +139 -0
  91. package/docs/guide/09-multi-agent.md +271 -0
  92. package/docs/guide/10-daemons.md +226 -0
  93. package/docs/guide/README.md +53 -0
  94. package/docs/index.html +623 -0
  95. package/examples/README.md +151 -0
  96. package/examples/agents/assistant/AGENT.md +31 -0
  97. package/examples/agents/assistant/SOUL.md +9 -0
  98. package/examples/agents/assistant/agent.json +74 -0
  99. package/examples/agents/hello/AGENT.md +15 -0
  100. package/examples/agents/hello/agent.json +14 -0
  101. package/examples/agents/monitor/AGENT.md +51 -0
  102. package/examples/agents/monitor/agent.json +33 -0
  103. package/examples/agents/monitor/heartbeats/monitor.md +24 -0
  104. package/examples/agents/orchestrator/AGENT.md +70 -0
  105. package/examples/agents/orchestrator/agent.json +30 -0
  106. package/examples/agents/researcher/AGENT.md +52 -0
  107. package/examples/agents/researcher/agent.json +49 -0
  108. package/examples/agents/researcher/skills/web-research.md +28 -0
  109. package/examples/skills/code-review.md +72 -0
  110. package/examples/skills/summarise.md +59 -0
  111. package/examples/skills/web-research.md +42 -0
  112. package/examples/tools/word-count/index.js +27 -0
  113. package/examples/tools/word-count/tool.json +18 -0
  114. package/infrastructure/database.js +563 -0
  115. package/infrastructure/scheduler.js +122 -0
  116. package/llm/client.js +206 -0
  117. package/migrations/001-initial.sql +121 -0
  118. package/migrations/002-debuggability.sql +13 -0
  119. package/migrations/003-drop-orphaned-columns.sql +72 -0
  120. package/migrations/004-session-message-token-fields.sql +78 -0
  121. package/migrations/005-session-thinking.sql +5 -0
  122. package/package.json +30 -0
  123. package/schemas/agent.json +143 -0
  124. package/schemas/settings.json +111 -0
  125. package/scripts/fetch-models.js +93 -0
  126. package/session-debug-scenario.md +248 -0
  127. package/settings/fields.js +52 -0
  128. package/system-prompts/base-core.md +7 -0
  129. package/system-prompts/environment.md +13 -0
  130. package/system-prompts/reminders/anti-drift.md +6 -0
  131. package/system-prompts/reminders/stall-recovery.md +10 -0
  132. package/system-prompts/safety-rules.md +25 -0
  133. package/system-prompts/task-heuristics.md +27 -0
  134. package/test/client.js +71 -0
  135. package/test/integration/01-health.test.js +25 -0
  136. package/test/integration/02-agents.test.js +80 -0
  137. package/test/integration/03-chat-hello.test.js +48 -0
  138. package/test/integration/04-chat-multiturn.test.js +61 -0
  139. package/test/integration/05-chat-writer.test.js +48 -0
  140. package/test/integration/06-task-basic.test.js +68 -0
  141. package/test/integration/07-task-tools.test.js +74 -0
  142. package/test/integration/08-task-code-analysis.test.js +69 -0
  143. package/test/integration/09-memory-analyst.test.js +63 -0
  144. package/test/integration/10-task-advanced.test.js +85 -0
  145. package/test/integration/11-sessions-advanced.test.js +84 -0
  146. package/test/integration/12-assistant-chat-tools.test.js +75 -0
  147. package/test/integration/13-edge-cases.test.js +99 -0
  148. package/test/integration/14-cancel.test.js +62 -0
  149. package/test/integration/15-debug.test.js +106 -0
  150. package/test/integration/16-memory-api.test.js +83 -0
  151. package/test/integration/17-settings-api.test.js +41 -0
  152. package/test/integration/18-tool-search-activation.test.js +119 -0
  153. package/test/results/.gitkeep +0 -0
  154. package/test/runner.js +206 -0
  155. package/test/smoke.js +216 -0
  156. package/tools/agent_message.js +85 -0
  157. package/tools/agent_send.js +80 -0
  158. package/tools/agent_spawn.js +44 -0
  159. package/tools/bash.js +49 -0
  160. package/tools/edit_file.js +41 -0
  161. package/tools/glob.js +64 -0
  162. package/tools/grep.js +82 -0
  163. package/tools/list_dir.js +63 -0
  164. package/tools/log_write.js +31 -0
  165. package/tools/memory_read.js +38 -0
  166. package/tools/memory_search.js +65 -0
  167. package/tools/memory_write.js +42 -0
  168. package/tools/read_file.js +48 -0
  169. package/tools/sleep.js +22 -0
  170. package/tools/task_create.js +41 -0
  171. package/tools/task_respond.js +37 -0
  172. package/tools/task_spawn.js +64 -0
  173. package/tools/task_status.js +39 -0
  174. package/tools/task_subscribe.js +37 -0
  175. package/tools/todo_read.js +26 -0
  176. package/tools/todo_write.js +38 -0
  177. package/tools/tool_activate.js +24 -0
  178. package/tools/tool_search.js +24 -0
  179. package/tools/web_fetch.js +50 -0
  180. package/tools/web_search.js +52 -0
  181. package/tools/write_file.js +28 -0
  182. package/ui/api.js +190 -0
  183. package/ui/app.js +281 -0
  184. package/ui/index.html +382 -0
  185. package/ui/views/agents.js +377 -0
  186. package/ui/views/chat.js +610 -0
  187. package/ui/views/connection.js +96 -0
  188. package/ui/views/daemons.js +129 -0
  189. package/ui/views/feed.js +194 -0
  190. package/ui/views/memory.js +263 -0
  191. package/ui/views/models.js +146 -0
  192. package/ui/views/sessions.js +314 -0
  193. package/ui/views/settings.js +142 -0
  194. package/ui/views/tasks.js +415 -0
  195. package/utils/context.js +49 -0
  196. package/utils/id.js +16 -0
  197. package/utils/models.js +88 -0
  198. package/utils/paths.js +213 -0
  199. package/utils/settings.js +172 -0
@@ -0,0 +1,374 @@
1
+ # Agents
2
+
3
+ ---
4
+
5
+ ## POST /agents
6
+
7
+ Create a new agent at the project or global level.
8
+
9
+ **Request body**
10
+
11
+ | Field | Type | Required | Description |
12
+ |-------|------|----------|-------------|
13
+ | `name` | string | ✓ | Agent identifier — letters, numbers, hyphens, underscores only |
14
+ | `level` | string | | `"project"` (default) or `"global"` |
15
+ | `config` | object | ✓ | Agent configuration (must satisfy the agent schema — `model` required) |
16
+ | `agentMd` | string | | Content for `AGENT.md` (system prompt / instructions) |
17
+
18
+ **Request example**
19
+ ```json
20
+ {
21
+ "name": "researcher",
22
+ "level": "project",
23
+ "config": {
24
+ "model": "anthropic/claude-sonnet-4-5",
25
+ "description": "Deep research agent",
26
+ "modes": {
27
+ "task": { "enabled": true, "tools": ["bash", "read_file", "write_file"] }
28
+ }
29
+ },
30
+ "agentMd": "You are a research assistant. Be thorough and cite sources."
31
+ }
32
+ ```
33
+
34
+ **Response** `201 Created`
35
+ ```json
36
+ {
37
+ "agent": {
38
+ "name": "researcher",
39
+ "level": "project",
40
+ "folder": "/home/user/workspace/.veil/agents/researcher"
41
+ }
42
+ }
43
+ ```
44
+
45
+ **Error responses**
46
+
47
+ | Code | Condition |
48
+ |------|-----------|
49
+ | `409 AGENT_EXISTS` | An agent with that name already exists at any level (project, global, or bundled) |
50
+ | `400 INVALID_NAME` | Name contains invalid characters |
51
+ | `400 INVALID_CONFIG` | Config fails schema validation (error details included) |
52
+ | `400 VALIDATION_ERROR` | Missing required body fields or invalid `level` |
53
+
54
+ **Example**
55
+ ```bash
56
+ curl -X POST http://localhost:5050/agents \
57
+ -H "Content-Type: application/json" \
58
+ -d '{"name":"researcher","config":{"model":"anthropic/claude-sonnet-4-5"}}'
59
+ ```
60
+
61
+ ---
62
+
63
+ ## GET /agents
64
+
65
+ Returns all agents discovered in the workspace's `.veil/agents/` directory (and the global cache if configured).
66
+
67
+ **Query parameters** — none
68
+
69
+ **Response**
70
+ ```json
71
+ {
72
+ "agents": [
73
+ {
74
+ "name": "hello",
75
+ "description": "A simple conversational agent",
76
+ "model": "moonshotai/kimi-k2.5",
77
+ "modes": ["chat", "task"],
78
+ "source": "project"
79
+ }
80
+ ]
81
+ }
82
+ ```
83
+
84
+ | Field | Type | Description |
85
+ |-------|------|-------------|
86
+ | `name` | string | Agent identifier (folder name) |
87
+ | `description` | string | From `agent.json` |
88
+ | `model` | string | LLM model identifier |
89
+ | `modes` | string[] | Enabled modes: `"chat"`, `"task"`, `"daemon"`, `"subagent"` |
90
+ | `source` | string | `"project"` or `"global"` or `"bundled"` |
91
+
92
+ **Example**
93
+ ```bash
94
+ curl http://localhost:5050/agents
95
+ ```
96
+
97
+ ---
98
+
99
+ ## GET /agents/:name
100
+
101
+ Returns the full configuration for a single agent.
102
+
103
+ **Path parameters**
104
+
105
+ | Param | Description |
106
+ |-------|-------------|
107
+ | `name` | Agent name (must match a folder in `.veil/agents/`) |
108
+
109
+ **Response**
110
+ ```json
111
+ {
112
+ "agent": {
113
+ "name": "assistant",
114
+ "description": "General-purpose agent with file and shell access",
115
+ "model": "moonshotai/kimi-k2.5",
116
+ "temperature": 0.7,
117
+ "reasoning": "medium",
118
+ "modes": {
119
+ "chat": { "enabled": true },
120
+ "task": {
121
+ "enabled": true,
122
+ "maxIterations": 20,
123
+ "maxDurationSeconds": 120,
124
+ "tools": ["read_file", "list_dir", "bash", "write_file"],
125
+ "permissions": {
126
+ "deny": ["bash(rm *)", "bash(sudo *)", "write_file(/etc/*)"]
127
+ }
128
+ }
129
+ },
130
+ "skillDiscovery": false,
131
+ "memory": { "enabled": false },
132
+ "agentFolder": "/home/user/workspace/.veil/agents/assistant",
133
+ "source": "project",
134
+ "agentMd": "You are a general-purpose assistant with file and shell access."
135
+ }
136
+ }
137
+ ```
138
+
139
+ | Field | Type | Description |
140
+ |-------|------|-------------|
141
+ | `name` | string | Agent identifier |
142
+ | `description` | string | Human-readable description |
143
+ | `model` | string | LLM model string |
144
+ | `temperature` | number | 0–2, sampling temperature |
145
+ | `reasoning` | string | Reasoning level: "minimal", "low", "medium", "high" |
146
+ | `modes` | object | Full mode configs (see [Agent Configuration](../guide/04-agents.md)) |
147
+ | `skillDiscovery` | boolean | Whether the agent auto-discovers skills |
148
+ | `memory` | object | `{ enabled, maxLines }` |
149
+ | `agentFolder` | string | Absolute path to the agent's folder |
150
+ | `source` | string | Where the agent was loaded from: `"project"`, `"global"`, or `"bundled"` |
151
+ | `agentMd` | string | Full content of the agent's `AGENT.md` system prompt file |
152
+
153
+ **Error responses**
154
+
155
+ | Code | Condition |
156
+ |------|-----------|
157
+ | `404 AGENT_NOT_FOUND` | No agent with that name exists |
158
+
159
+ **Example**
160
+ ```bash
161
+ curl http://localhost:5050/agents/assistant
162
+ ```
163
+
164
+ ---
165
+
166
+ ## POST /agents/:name/reload
167
+
168
+ Hot-reload an agent's configuration from disk. Since `loadAgent` always reads from disk, this endpoint simply forces a fresh load and returns the current config. Useful for confirming that config file edits have taken effect, or for programmatically verifying the agent is valid after an update.
169
+
170
+ **Path parameters**
171
+
172
+ | Param | Description |
173
+ |-------|-------------|
174
+ | `name` | Agent name |
175
+
176
+ **Response**
177
+ ```json
178
+ {
179
+ "reloaded": true,
180
+ "agent": {
181
+ "name": "assistant",
182
+ "model": "anthropic/claude-sonnet-4-5",
183
+ "description": "General-purpose assistant",
184
+ "modes": { "chat": { "enabled": true } }
185
+ }
186
+ }
187
+ ```
188
+
189
+ **Error responses**
190
+
191
+ | Code | Condition |
192
+ |------|-----------|
193
+ | `404 AGENT_NOT_FOUND` | No agent with that name exists |
194
+
195
+ **Example**
196
+ ```bash
197
+ curl -X POST http://localhost:5050/agents/assistant/reload
198
+ ```
199
+
200
+ ---
201
+
202
+ ## PUT /agents/:name
203
+
204
+ Update an existing agent's configuration and/or `AGENT.md`. Only project-level and global agents can be updated — bundled agents are read-only.
205
+
206
+ At least one of `config` or `agentMd` must be provided. Config fields are **shallow-merged** with the current `agent.json` (top-level keys are replaced).
207
+
208
+ **Path parameters**
209
+
210
+ | Param | Description |
211
+ |-------|-------------|
212
+ | `name` | Agent name |
213
+
214
+ **Request body**
215
+
216
+ | Field | Type | Required | Description |
217
+ |-------|------|----------|-------------|
218
+ | `config` | object | | Partial or full agent config — merged over current `agent.json` |
219
+ | `agentMd` | string | | New content for `AGENT.md` — fully replaces existing content |
220
+
221
+ **Request example** — update model and add a tool
222
+ ```json
223
+ {
224
+ "config": {
225
+ "model": "anthropic/claude-opus-4-5",
226
+ "modes": {
227
+ "chat": { "enabled": true, "tools": ["read_file", "bash"] }
228
+ }
229
+ }
230
+ }
231
+ ```
232
+
233
+ **Response**
234
+ ```json
235
+ {
236
+ "agent": {
237
+ "name": "researcher",
238
+ "level": "project",
239
+ "folder": "/home/user/workspace/.veil/agents/researcher"
240
+ }
241
+ }
242
+ ```
243
+
244
+ **Error responses**
245
+
246
+ | Code | Condition |
247
+ |------|-----------|
248
+ | `404 AGENT_NOT_FOUND` | No agent with that name exists |
249
+ | `403 AGENT_READ_ONLY` | Agent is bundled and cannot be modified |
250
+ | `400 INVALID_CONFIG` | Merged config fails schema validation |
251
+ | `400 VALIDATION_ERROR` | Neither `config` nor `agentMd` provided |
252
+
253
+ **Example**
254
+ ```bash
255
+ curl -X PUT http://localhost:5050/agents/researcher \
256
+ -H "Content-Type: application/json" \
257
+ -d '{"config":{"model":"anthropic/claude-opus-4-5"}}'
258
+ ```
259
+
260
+ ---
261
+
262
+ ## DELETE /agents/:name
263
+
264
+ Delete an agent folder and all its contents (config, AGENT.md, skills, etc.). Only project-level and global agents can be deleted — bundled agents are read-only.
265
+
266
+ > **Warning:** This is irreversible. The agent folder is permanently removed from disk.
267
+
268
+ **Path parameters**
269
+
270
+ | Param | Description |
271
+ |-------|-------------|
272
+ | `name` | Agent name |
273
+
274
+ **Response**
275
+ ```json
276
+ {
277
+ "deleted": true,
278
+ "agent": {
279
+ "name": "researcher",
280
+ "level": "project",
281
+ "folder": "/home/user/workspace/.veil/agents/researcher"
282
+ }
283
+ }
284
+ ```
285
+
286
+ **Error responses**
287
+
288
+ | Code | Condition |
289
+ |------|-----------|
290
+ | `404 AGENT_NOT_FOUND` | No agent with that name exists |
291
+ | `403 AGENT_READ_ONLY` | Agent is bundled and cannot be deleted |
292
+
293
+ **Example**
294
+ ```bash
295
+ curl -X DELETE http://localhost:5050/agents/researcher
296
+ ```
297
+
298
+ ---
299
+
300
+ ## GET /agents/:name/sessions
301
+
302
+ List sessions for a specific agent. This is a convenience alias for `GET /sessions?agentName=:name`.
303
+
304
+ **Query parameters**
305
+
306
+ | Param | Type | Description |
307
+ |-------|------|-------------|
308
+ | `status` | string | Filter by `active` or `closed` |
309
+ | `limit` | integer | Max results (default: 20) |
310
+ | `cursor` | string | Pagination cursor |
311
+
312
+ **Response**
313
+ ```json
314
+ {
315
+ "agentName": "assistant",
316
+ "sessions": [
317
+ { "id": "sess_...", "mode": "chat", "status": "active", ... }
318
+ ]
319
+ }
320
+ ```
321
+
322
+ ---
323
+
324
+ ## GET /agents/:name/tasks
325
+
326
+ List tasks for a specific agent. This is a convenience alias for `GET /tasks?agentName=:name`.
327
+
328
+ **Query parameters**
329
+
330
+ | Param | Type | Description |
331
+ |-------|------|-------------|
332
+ | `status` | string | Filter by status |
333
+ | `priority` | string | Filter by priority |
334
+ | `limit` | integer | Max results (default: 20) |
335
+ | `cursor` | string | Pagination cursor |
336
+
337
+ **Response**
338
+ ```json
339
+ {
340
+ "agentName": "assistant",
341
+ "tasks": [
342
+ { "id": "task_...", "status": "finished", ... }
343
+ ]
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ## GET /agents/:name/skills
350
+
351
+ List skills configured for an agent and their load status.
352
+
353
+ **Response**
354
+ ```json
355
+ {
356
+ "agentName": "assistant",
357
+ "skills": [
358
+ { "name": "web-search", "loaded": true, "source": "project", "path": "/.../.veil/skills/web-search.md" },
359
+ { "name": "missing-skill", "loaded": false, "error": "File not found" }
360
+ ],
361
+ "customTools": [
362
+ { "name": "my_tool", "source": "project" }
363
+ ]
364
+ }
365
+ ```
366
+
367
+ | Field | Type | Description |
368
+ |-------|------|-------------|
369
+ | `skills[].name` | string | Skill name from agent config |
370
+ | `skills[].loaded` | boolean | Whether the skill file was found |
371
+ | `skills[].source` | string | `"agent"` or `"project"` |
372
+ | `skills[].path` | string | Absolute path (if loaded) |
373
+ | `skills[].error` | string | Error message (if not loaded) |
374
+ | `customTools` | array | Custom tools discovered for this agent |
@@ -0,0 +1,269 @@
1
+ # Chat
2
+
3
+ The chat endpoint enables multi-turn conversations with an agent. Each call is synchronous — it blocks until the agent finishes its response (including any tool calls).
4
+
5
+ ---
6
+
7
+ ## POST /agents/:name/chat
8
+
9
+ Send a message to an agent and receive a reply.
10
+
11
+ **Path parameters**
12
+
13
+ | Param | Description |
14
+ |-------|-------------|
15
+ | `name` | Agent name |
16
+
17
+ **Request body**
18
+
19
+ ```json
20
+ {
21
+ "message": "What files are in the current directory?",
22
+ "sessionId": "sess_abc123"
23
+ }
24
+ ```
25
+
26
+ | Field | Type | Required | Description |
27
+ |-------|------|----------|-------------|
28
+ | `message` | string | ✓ | User message content |
29
+ | `sessionId` | string | | Existing session ID to continue a conversation. Omit to start a new session. |
30
+ | `sse` | boolean | | `true` to enable SSE streaming — the response is `text/event-stream` instead of JSON. |
31
+
32
+ **Response**
33
+
34
+ ```json
35
+ {
36
+ "sessionId": "sess_4f3a1b9c2d8e7f01",
37
+ "message": {
38
+ "role": "assistant",
39
+ "content": "Here are the files in the current directory:\n- README.md\n- package.json\n..."
40
+ },
41
+ "tokenUsage": {
42
+ "input": 1240,
43
+ "output": 183,
44
+ "cache": 0,
45
+ "cost": 0.0021
46
+ },
47
+ "toolCalls": [
48
+ { "name": "list_dir", "durationMs": 12, "success": true },
49
+ { "name": "read_file", "durationMs": 8, "success": true }
50
+ ]
51
+ }
52
+ ```
53
+
54
+ | Field | Type | Description |
55
+ |-------|------|-------------|
56
+ | `sessionId` | string | Session ID (pass this back for multi-turn) |
57
+ | `message.role` | string | Always `"assistant"` |
58
+ | `message.content` | string | Agent reply text (last iteration's response) |
59
+ | `tokenUsage.input` | integer | Total input tokens for this turn |
60
+ | `tokenUsage.output` | integer | Total output tokens for this turn |
61
+ | `tokenUsage.cache` | integer | Cached tokens (if provider supports it) |
62
+ | `tokenUsage.cost` | number | Estimated cost in USD |
63
+ | `toolCalls` | array | Summary of tools called: `{ name, durationMs, success }` |
64
+
65
+ **Error responses**
66
+
67
+ | Code | Condition |
68
+ |------|-----------|
69
+ | `400 VALIDATION_ERROR` | `message` is missing or not a string |
70
+ | `400 MODE_NOT_SUPPORTED` | Agent does not have `chat.enabled: true` |
71
+ | `400 SESSION_CLOSED` | The provided `sessionId` belongs to a closed session |
72
+ | `404 AGENT_NOT_FOUND` | No agent with that name |
73
+
74
+ ---
75
+
76
+ ## SSE Streaming Mode
77
+
78
+ Set `"sse": true` in the request body to receive a real-time `text/event-stream` response. The connection stays open across all LLM iterations (including tool call rounds) and closes only when the full turn is complete.
79
+
80
+ **Design principle:** Events are split into two categories — _inference_ events carry transient streaming data not needed for state; _message_ events carry the exact schema returned by `GET /sessions/:id/messages` so clients can update their local state directly without any conversion.
81
+
82
+ **Event types**
83
+
84
+ | Event | Category | Description |
85
+ |-------|----------|-------------|
86
+ | `inference.chunk` | Inference | One streaming token fragment from the current LLM call |
87
+ | `inference.tool` | Inference | Tool name detected in stream before arguments are complete — lets UI show a loading indicator early |
88
+ | `message` | State | An assistant or tool message, identical to the session messages API schema |
89
+ | `done` | State | Turn complete — includes the updated session record and turn-level stats |
90
+ | `error` | — | Emitted instead of `done` if the run fails |
91
+
92
+ ---
93
+
94
+ **`inference.chunk`**
95
+ ```json
96
+ { "content": "Here are the" }
97
+ ```
98
+
99
+ **`inference.tool`** — fires once per tool call as soon as the tool name appears in the stream (before arguments are complete)
100
+ ```json
101
+ { "name": "sleep" }
102
+ ```
103
+
104
+ ---
105
+
106
+ **`message`** — session-API-compatible message object, augmented with inference metadata for assistant turns
107
+
108
+ *Assistant turn (text only):*
109
+ ```json
110
+ {
111
+ "id": 5,
112
+ "session_id": "sess_4f3a1b9c2d8e7f01",
113
+ "role": "assistant",
114
+ "content": "Here are the files:\n- README.md",
115
+ "tool_calls": null,
116
+ "tool_call_id": null,
117
+ "created_at": "2025-03-02T10:00:04.000Z",
118
+ "finishReason": "stop",
119
+ "iteration": 1,
120
+ "tokenUsage": { "input": 1240, "output": 38, "cache": 0, "cost": 0.0003 }
121
+ }
122
+ ```
123
+
124
+ *Assistant turn (with tool calls):*
125
+ ```json
126
+ {
127
+ "id": 3,
128
+ "session_id": "sess_4f3a1b9c2d8e7f01",
129
+ "role": "assistant",
130
+ "content": null,
131
+ "tool_calls": [{ "id": "call_abc", "type": "function", "function": { "name": "list_dir", "arguments": "{\"dir\": \".\"}" } }],
132
+ "tool_call_id": null,
133
+ "created_at": "2025-03-02T10:00:02.000Z",
134
+ "finishReason": "tool_calls",
135
+ "iteration": 1,
136
+ "tokenUsage": { "input": 980, "output": 22, "cache": 0, "cost": 0.0002 }
137
+ }
138
+ ```
139
+
140
+ *Tool result:*
141
+ ```json
142
+ {
143
+ "id": 4,
144
+ "session_id": "sess_4f3a1b9c2d8e7f01",
145
+ "role": "tool",
146
+ "content": "README.md (1.2KB)\npackage.json (544B)",
147
+ "tool_calls": null,
148
+ "tool_call_id": "call_abc",
149
+ "created_at": "2025-03-02T10:00:03.000Z"
150
+ }
151
+ ```
152
+
153
+ `finishReason` on assistant turns: `"stop"` = no tools followed | `"tool_calls"` = continued with tool use | `"length"` = token limit hit
154
+
155
+ ---
156
+
157
+ **`done`**
158
+ ```json
159
+ {
160
+ "session": {
161
+ "id": "sess_4f3a1b9c2d8e7f01",
162
+ "agent_name": "assistant",
163
+ "mode": "chat",
164
+ "status": "active",
165
+ "model": "claude-3-5-sonnet",
166
+ "total_input_tokens": 6842,
167
+ "total_output_tokens": 124,
168
+ "cost": 0.0089,
169
+ "message_count": 5,
170
+ "created_at": "2025-03-02T10:00:00.000Z",
171
+ "updated_at": "2025-03-02T10:00:05.000Z"
172
+ },
173
+ "agentName": "assistant",
174
+ "model": "claude-3-5-sonnet",
175
+ "iterations": 3,
176
+ "durationMs": 4210,
177
+ "tokenUsage": { "input": 6842, "output": 124, "cache": 0, "cost": 0.0089 },
178
+ "toolCalls": [
179
+ { "name": "sleep", "durationMs": 1003, "success": true }
180
+ ]
181
+ }
182
+ ```
183
+
184
+ **`error`**
185
+ ```json
186
+ { "error": "LLM API error 429: rate limit", "code": "INTERNAL_ERROR" }
187
+ ```
188
+
189
+ ---
190
+
191
+ **Behavior notes**
192
+ - `inference.chunk` fires for every LLM iteration across the full turn — all chunks are streamed in order.
193
+ - `inference.tool` fires during streaming as soon as the tool name is known, before arguments finish — use this for tool loading indicators.
194
+ - Each `message` event (role `assistant` or `tool`) matches what `GET /sessions/:id/messages` returns, so clients can append them directly to local state without schema conversion.
195
+ - `done.session` is a snapshot of the session record after the turn — clients can use it to update session state without a separate `GET /sessions/:id` call.
196
+ - The response `Content-Type` is `text/event-stream`; use `EventSource` or an SSE client library.
197
+
198
+ **JavaScript example**
199
+ ```js
200
+ const response = await fetch('http://localhost:5050/agents/assistant/chat', {
201
+ method: 'POST',
202
+ headers: { 'Content-Type': 'application/json' },
203
+ body: JSON.stringify({ message: 'List files', sse: true }),
204
+ });
205
+
206
+ const messages = [];
207
+ const reader = response.body.getReader();
208
+ const decoder = new TextDecoder();
209
+ let buffer = '';
210
+ let pendingEvent = null;
211
+
212
+ while (true) {
213
+ const { done, value } = await reader.read();
214
+ if (done) break;
215
+ buffer += decoder.decode(value, { stream: true });
216
+ const lines = buffer.split('\n');
217
+ buffer = lines.pop();
218
+ for (const line of lines) {
219
+ if (line.startsWith('event: ')) { pendingEvent = line.slice(7).trim(); continue; }
220
+ if (line.startsWith('data: ') && pendingEvent) {
221
+ const data = JSON.parse(line.slice(6));
222
+ if (pendingEvent === 'inference.chunk') process.stdout.write(data.content);
223
+ if (pendingEvent === 'inference.tool') console.log(`[tool] ${data.name}…`);
224
+ if (pendingEvent === 'message') messages.push(data); // directly usable
225
+ if (pendingEvent === 'done') console.log('session:', data.session);
226
+ pendingEvent = null;
227
+ }
228
+ }
229
+ }
230
+ ```
231
+
232
+ **curl example**
233
+ ```bash
234
+ curl -X POST http://localhost:5050/agents/assistant/chat \
235
+ -H "Content-Type: application/json" \
236
+ -d '{"message": "List files", "sse": true}' \
237
+ --no-buffer
238
+ ```
239
+
240
+ ---
241
+
242
+ ## Multi-turn Conversation Example
243
+
244
+ Start a new conversation, then continue it:
245
+
246
+ ```bash
247
+ # Turn 1 — new session
248
+ curl -X POST http://localhost:5050/agents/assistant/chat \
249
+ -H "Content-Type: application/json" \
250
+ -d '{"message": "My name is Alice."}'
251
+
252
+ # Response includes sessionId, e.g. "sess_4f3a1b9c2d8e7f01"
253
+
254
+ # Turn 2 — continue the same session
255
+ curl -X POST http://localhost:5050/agents/assistant/chat \
256
+ -H "Content-Type: application/json" \
257
+ -d '{"message": "What is my name?", "sessionId": "sess_4f3a1b9c2d8e7f01"}'
258
+
259
+ # Agent remembers: "Your name is Alice."
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Notes
265
+
266
+ - The agent's full message history (including tool call messages) is persisted in SQLite and replayed on each turn.
267
+ - If the agent uses tools (e.g. `read_file`, `bash`), those calls happen **before** the reply is returned — the response always contains the final text response.
268
+ - To inspect which tools were called during a chat turn, fetch the session messages after the call: `GET /sessions/:id/messages`.
269
+ - Sessions are scoped to a workspace (`instanceFolder`). A `sessionId` from one server instance will not be found by another.