chainlesschain 0.45.12 → 0.45.20

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 (78) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AppLayout-BfLjLMsm.js → AppLayout-B00RARl2.js} +1 -1
  3. package/src/assets/web-panel/assets/{Chat-DP7PO9Li.js → Chat-DXtvKoM0.js} +1 -1
  4. package/src/assets/web-panel/assets/{Cron-DyQF-7R1.js → Cron-BJ4ODHOy.js} +1 -1
  5. package/src/assets/web-panel/assets/Dashboard-3iIpp3zd.js +3 -0
  6. package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +1 -0
  7. package/src/assets/web-panel/assets/{Logs-BOii-AoO.js → Logs-CSeKZEG_.js} +1 -1
  8. package/src/assets/web-panel/assets/{McpTools-DmiJtJYr.js → McpTools-BYQAK11r.js} +1 -1
  9. package/src/assets/web-panel/assets/{Memory-CDRMMobU.js → Memory-gkUAPyuZ.js} +1 -1
  10. package/src/assets/web-panel/assets/{Notes-CVhqqoS1.js → Notes-bjNrQgAo.js} +1 -1
  11. package/src/assets/web-panel/assets/{Providers-Dkt7021l.js → Providers-Dbf57Tbv.js} +1 -1
  12. package/src/assets/web-panel/assets/{Services-DUDL_UGb.js → Services-CS0oMdxh.js} +1 -1
  13. package/src/assets/web-panel/assets/{Skills-DXXELJc3.js → Skills-B2fgruv8.js} +1 -1
  14. package/src/assets/web-panel/assets/Tasks-BJjN_YEm.css +1 -0
  15. package/src/assets/web-panel/assets/Tasks-qULws8pc.js +1 -0
  16. package/src/assets/web-panel/assets/chat-DnH09sSR.js +1 -0
  17. package/src/assets/web-panel/assets/{index-vW799KpE.js → index-CF2CqPYX.js} +2 -2
  18. package/src/assets/web-panel/assets/ws-DjelKkD6.js +1 -0
  19. package/src/assets/web-panel/index.html +1 -1
  20. package/src/commands/agent.js +7 -8
  21. package/src/commands/chat.js +9 -11
  22. package/src/commands/serve.js +11 -106
  23. package/src/commands/session.js +101 -0
  24. package/src/commands/ui.js +10 -151
  25. package/src/gateways/repl/agent-repl.js +1 -0
  26. package/src/gateways/repl/chat-repl.js +1 -0
  27. package/src/gateways/ui/web-ui-server.js +1 -0
  28. package/src/gateways/ws/action-protocol.js +83 -0
  29. package/src/gateways/ws/message-dispatcher.js +73 -0
  30. package/src/gateways/ws/session-protocol.js +396 -0
  31. package/src/gateways/ws/task-protocol.js +55 -0
  32. package/src/gateways/ws/worktree-protocol.js +315 -0
  33. package/src/gateways/ws/ws-server.js +4 -0
  34. package/src/gateways/ws/ws-session-gateway.js +1 -0
  35. package/src/harness/background-task-manager.js +506 -0
  36. package/src/harness/background-task-worker.js +48 -0
  37. package/src/harness/compression-telemetry.js +214 -0
  38. package/src/harness/feature-flags.js +157 -0
  39. package/src/harness/jsonl-session-store.js +452 -0
  40. package/src/harness/prompt-compressor.js +416 -0
  41. package/src/harness/worktree-isolator.js +845 -0
  42. package/src/lib/agent-core.js +246 -45
  43. package/src/lib/background-task-manager.js +1 -305
  44. package/src/lib/background-task-worker.js +1 -50
  45. package/src/lib/compression-telemetry.js +5 -0
  46. package/src/lib/feature-flags.js +7 -182
  47. package/src/lib/interaction-adapter.js +32 -6
  48. package/src/lib/jsonl-session-store.js +21 -237
  49. package/src/lib/prompt-compressor.js +10 -481
  50. package/src/lib/sub-agent-context.js +21 -1
  51. package/src/lib/worktree-isolator.js +13 -231
  52. package/src/lib/ws-agent-handler.js +1 -0
  53. package/src/lib/ws-server.js +138 -387
  54. package/src/lib/ws-session-manager.js +82 -1
  55. package/src/repl/agent-repl.js +11 -0
  56. package/src/runtime/agent-runtime.js +417 -0
  57. package/src/runtime/contracts/agent-turn.js +11 -0
  58. package/src/runtime/contracts/session-record.js +31 -0
  59. package/src/runtime/contracts/task-record.js +18 -0
  60. package/src/runtime/contracts/telemetry-record.js +23 -0
  61. package/src/runtime/contracts/worktree-record.js +14 -0
  62. package/src/runtime/index.js +13 -0
  63. package/src/runtime/policies/agent-policy.js +45 -0
  64. package/src/runtime/runtime-context.js +14 -0
  65. package/src/runtime/runtime-events.js +37 -0
  66. package/src/runtime/runtime-factory.js +50 -0
  67. package/src/tools/index.js +22 -0
  68. package/src/tools/legacy-agent-tools.js +171 -0
  69. package/src/tools/registry.js +141 -0
  70. package/src/tools/tool-context.js +28 -0
  71. package/src/tools/tool-permissions.js +28 -0
  72. package/src/tools/tool-telemetry.js +39 -0
  73. package/src/assets/web-panel/assets/Dashboard-BGGdnr6t.js +0 -3
  74. package/src/assets/web-panel/assets/Dashboard-CRFnDUFh.css +0 -1
  75. package/src/assets/web-panel/assets/Tasks-BwZ63-mq.js +0 -1
  76. package/src/assets/web-panel/assets/Tasks-Cr_XXNyQ.css +0 -1
  77. package/src/assets/web-panel/assets/chat-C_hu-qNs.js +0 -1
  78. package/src/assets/web-panel/assets/ws-DwluTqT5.js +0 -1
@@ -0,0 +1,396 @@
1
+ import {
2
+ RUNTIME_EVENTS,
3
+ createRuntimeEvent,
4
+ } from "../../runtime/runtime-events.js";
5
+ import { createSessionRecord } from "../../runtime/contracts/session-record.js";
6
+
7
+ async function ensureSessionHandler(server, ws, session) {
8
+ if (server.sessionHandlers.has(session.id)) {
9
+ return server.sessionHandlers.get(session.id);
10
+ }
11
+
12
+ const { WebSocketInteractionAdapter } =
13
+ await import("../../lib/interaction-adapter.js");
14
+ session.interaction = new WebSocketInteractionAdapter(ws, session.id);
15
+
16
+ let handler;
17
+ if (session.type === "chat") {
18
+ const { WSChatHandler } = await import("../../lib/ws-chat-handler.js");
19
+ handler = new WSChatHandler({
20
+ session,
21
+ interaction: session.interaction,
22
+ });
23
+ } else {
24
+ const { WSAgentHandler } = await import("../../lib/ws-agent-handler.js");
25
+ handler = new WSAgentHandler({
26
+ session,
27
+ interaction: session.interaction,
28
+ db: server.sessionManager.db,
29
+ });
30
+ }
31
+
32
+ server.sessionHandlers.set(session.id, handler);
33
+ return handler;
34
+ }
35
+
36
+ export async function handleSessionCreate(server, id, ws, message) {
37
+ if (!server.sessionManager) {
38
+ server._send(ws, {
39
+ id,
40
+ type: "error",
41
+ code: "NO_SESSION_SUPPORT",
42
+ message: "Session support not configured on this server",
43
+ });
44
+ return;
45
+ }
46
+
47
+ const {
48
+ sessionType,
49
+ provider,
50
+ model,
51
+ apiKey,
52
+ baseUrl,
53
+ projectRoot,
54
+ hostManagedToolPolicy,
55
+ worktreeIsolation,
56
+ } = message;
57
+
58
+ try {
59
+ const { sessionId } = server.sessionManager.createSession({
60
+ type: sessionType || "agent",
61
+ provider,
62
+ model,
63
+ apiKey,
64
+ baseUrl,
65
+ projectRoot,
66
+ hostManagedToolPolicy,
67
+ worktreeIsolation,
68
+ });
69
+
70
+ const session = server.sessionManager.getSession(sessionId);
71
+ const record = createSessionRecord(session, {
72
+ sessionId,
73
+ sessionType: sessionType || "agent",
74
+ provider,
75
+ model,
76
+ projectRoot: projectRoot || null,
77
+ baseProjectRoot: session?.baseProjectRoot || projectRoot || null,
78
+ worktreeIsolation: worktreeIsolation === true,
79
+ worktree: session?.worktree || null,
80
+ status: "created",
81
+ });
82
+
83
+ try {
84
+ await ensureSessionHandler(server, ws, session);
85
+ } catch (_err) {
86
+ // Session exists even if handler bootstrapping fails.
87
+ }
88
+
89
+ server.emit("session:create", { sessionId, type: sessionType || "agent" });
90
+ server.emit(
91
+ RUNTIME_EVENTS.SESSION_START,
92
+ createRuntimeEvent(
93
+ RUNTIME_EVENTS.SESSION_START,
94
+ {
95
+ sessionId,
96
+ sessionType: sessionType || "agent",
97
+ provider,
98
+ model,
99
+ projectRoot: projectRoot || null,
100
+ record,
101
+ },
102
+ { kind: "server", sessionId },
103
+ ),
104
+ );
105
+
106
+ server._send(ws, {
107
+ id,
108
+ type: "session-created",
109
+ sessionId,
110
+ sessionType: sessionType || "agent",
111
+ record,
112
+ });
113
+ } catch (err) {
114
+ server._send(ws, {
115
+ id,
116
+ type: "error",
117
+ code: "SESSION_CREATE_FAILED",
118
+ message: err.message,
119
+ });
120
+ }
121
+ }
122
+
123
+ export async function handleSessionResume(server, id, ws, message) {
124
+ if (!server.sessionManager) {
125
+ server._send(ws, {
126
+ id,
127
+ type: "error",
128
+ code: "NO_SESSION_SUPPORT",
129
+ message: "Session support not configured",
130
+ });
131
+ return;
132
+ }
133
+
134
+ const { sessionId } = message;
135
+ const session = server.sessionManager.resumeSession(sessionId);
136
+
137
+ if (!session) {
138
+ server._send(ws, {
139
+ id,
140
+ type: "error",
141
+ code: "SESSION_NOT_FOUND",
142
+ message: `Session not found: ${sessionId}`,
143
+ });
144
+ return;
145
+ }
146
+
147
+ if (!server.sessionHandlers.has(sessionId)) {
148
+ try {
149
+ await ensureSessionHandler(server, ws, session);
150
+ } catch (_err) {
151
+ // Session resumed without live handler.
152
+ }
153
+ }
154
+
155
+ const history = (session.messages || []).filter((m) => m.role !== "system");
156
+ const record = createSessionRecord(session, {
157
+ history,
158
+ messageCount: history.length,
159
+ status: "resumed",
160
+ });
161
+
162
+ server.emit(
163
+ RUNTIME_EVENTS.SESSION_RESUME,
164
+ createRuntimeEvent(
165
+ RUNTIME_EVENTS.SESSION_RESUME,
166
+ {
167
+ sessionId: session.id,
168
+ historyCount: history.length,
169
+ sessionType: session.type || null,
170
+ record,
171
+ },
172
+ { kind: "server", sessionId: session.id },
173
+ ),
174
+ );
175
+
176
+ server._send(ws, {
177
+ id,
178
+ type: "session-resumed",
179
+ sessionId: session.id,
180
+ history,
181
+ record,
182
+ });
183
+ }
184
+
185
+ export function handleSessionMessage(server, id, ws, message) {
186
+ const { sessionId, content } = message;
187
+ const handler = server.sessionHandlers.get(sessionId);
188
+
189
+ if (!handler) {
190
+ server._send(ws, {
191
+ id,
192
+ type: "error",
193
+ code: "SESSION_NOT_FOUND",
194
+ message: `No active session handler for: ${sessionId}`,
195
+ });
196
+ return;
197
+ }
198
+
199
+ server.emit(
200
+ RUNTIME_EVENTS.SESSION_MESSAGE,
201
+ createRuntimeEvent(
202
+ RUNTIME_EVENTS.SESSION_MESSAGE,
203
+ {
204
+ sessionId,
205
+ messageId: id,
206
+ content,
207
+ },
208
+ { kind: "server", sessionId },
209
+ ),
210
+ );
211
+
212
+ handler
213
+ .handleMessage(content, id)
214
+ .then(() => {
215
+ if (server.sessionManager) {
216
+ try {
217
+ server.sessionManager.persistMessages(sessionId);
218
+ } catch (_err) {
219
+ // Non-critical.
220
+ }
221
+ }
222
+ })
223
+ .catch((err) => {
224
+ server._send(ws, {
225
+ id,
226
+ type: "error",
227
+ code: "MESSAGE_FAILED",
228
+ message: err.message,
229
+ });
230
+ });
231
+ }
232
+
233
+ export function handleSessionPolicyUpdate(server, id, ws, message) {
234
+ const { sessionId, hostManagedToolPolicy } = message;
235
+
236
+ if (!server.sessionManager) {
237
+ server._send(ws, {
238
+ id,
239
+ type: "error",
240
+ code: "NO_SESSION_SUPPORT",
241
+ message: "Session support not configured",
242
+ });
243
+ return;
244
+ }
245
+
246
+ const session = server.sessionManager.updateSessionPolicy
247
+ ? server.sessionManager.updateSessionPolicy(
248
+ sessionId,
249
+ hostManagedToolPolicy,
250
+ )
251
+ : null;
252
+
253
+ if (!session) {
254
+ server._send(ws, {
255
+ id,
256
+ type: "error",
257
+ code: "SESSION_NOT_FOUND",
258
+ message: `Session not found: ${sessionId}`,
259
+ });
260
+ return;
261
+ }
262
+
263
+ server._send(ws, {
264
+ id,
265
+ type: "session-policy-updated",
266
+ success: true,
267
+ sessionId,
268
+ });
269
+ }
270
+
271
+ export function handleSessionList(server, id, ws) {
272
+ if (!server.sessionManager) {
273
+ server._send(ws, {
274
+ id,
275
+ type: "error",
276
+ code: "NO_SESSION_SUPPORT",
277
+ message: "Session support not configured",
278
+ });
279
+ return;
280
+ }
281
+
282
+ const sessions = server.sessionManager.listSessions().map((session) => ({
283
+ ...session,
284
+ record: createSessionRecord(session, {
285
+ sessionId: session.id,
286
+ sessionType: session.type || null,
287
+ status: session.status || "listed",
288
+ history: Array.isArray(session.messages)
289
+ ? session.messages.filter((item) => item.role !== "system")
290
+ : [],
291
+ }),
292
+ }));
293
+ server._send(ws, {
294
+ id,
295
+ type: "session-list-result",
296
+ sessions,
297
+ });
298
+ }
299
+
300
+ export function handleSessionClose(server, id, ws, message) {
301
+ const { sessionId } = message;
302
+
303
+ const handler = server.sessionHandlers.get(sessionId);
304
+ if (handler && handler.destroy) {
305
+ handler.destroy();
306
+ }
307
+ server.sessionHandlers.delete(sessionId);
308
+
309
+ if (server.sessionManager) {
310
+ try {
311
+ server.sessionManager.closeSession(sessionId);
312
+ } catch (_err) {
313
+ // Non-critical.
314
+ }
315
+ }
316
+
317
+ server.emit("session:close", { sessionId });
318
+ server.emit(
319
+ RUNTIME_EVENTS.SESSION_END,
320
+ createRuntimeEvent(
321
+ RUNTIME_EVENTS.SESSION_END,
322
+ {
323
+ sessionId,
324
+ record: createSessionRecord(
325
+ { id: sessionId, type: null },
326
+ { sessionId, status: "closed", history: [], messageCount: 0 },
327
+ ),
328
+ },
329
+ { kind: "server", sessionId },
330
+ ),
331
+ );
332
+
333
+ server._send(ws, {
334
+ id,
335
+ type: "result",
336
+ success: true,
337
+ sessionId,
338
+ });
339
+ }
340
+
341
+ export function handleSessionAnswer(server, id, ws, message) {
342
+ const { sessionId, requestId, answer } = message;
343
+
344
+ if (!server.sessionManager) {
345
+ server._send(ws, {
346
+ id,
347
+ type: "error",
348
+ code: "NO_SESSION_SUPPORT",
349
+ message: "Session support not configured",
350
+ });
351
+ return;
352
+ }
353
+
354
+ const session = server.sessionManager.getSession(sessionId);
355
+ if (session && session.interaction && session.interaction.resolveAnswer) {
356
+ session.interaction.resolveAnswer(requestId, answer);
357
+ }
358
+
359
+ server._send(ws, { id, type: "result", success: true });
360
+ }
361
+
362
+ export function handleHostToolResult(server, id, ws, message) {
363
+ const { sessionId, requestId, success, result, error, toolName } = message;
364
+
365
+ if (!server.sessionManager) {
366
+ server._send(ws, {
367
+ id,
368
+ type: "error",
369
+ code: "NO_SESSION_SUPPORT",
370
+ message: "Session support not configured",
371
+ });
372
+ return;
373
+ }
374
+
375
+ const session = server.sessionManager.getSession(sessionId);
376
+ if (!session || !session.interaction) {
377
+ server._send(ws, {
378
+ id,
379
+ type: "error",
380
+ code: "SESSION_NOT_FOUND",
381
+ message: `Session not found: ${sessionId}`,
382
+ });
383
+ return;
384
+ }
385
+
386
+ if (typeof session.interaction.resolveHostTool === "function") {
387
+ session.interaction.resolveHostTool(requestId, {
388
+ success: success !== false,
389
+ result,
390
+ error: error || null,
391
+ toolName: toolName || null,
392
+ });
393
+ }
394
+
395
+ server._send(ws, { id, type: "result", success: true });
396
+ }
@@ -0,0 +1,55 @@
1
+ export async function handleTaskDetail(server, id, ws, message) {
2
+ try {
3
+ await server._ensureTaskManager();
4
+ if (!message.taskId) {
5
+ server._send(ws, {
6
+ id,
7
+ type: "error",
8
+ code: "NO_TASK",
9
+ message: "taskId required",
10
+ });
11
+ return;
12
+ }
13
+ const task = server._taskManager.getDetails(message.taskId);
14
+ server._send(ws, { id, type: "tasks-detail", task });
15
+ } catch (err) {
16
+ server._send(ws, {
17
+ id,
18
+ type: "error",
19
+ code: "TASK_DETAIL_FAILED",
20
+ message: err.message,
21
+ });
22
+ }
23
+ }
24
+
25
+ export async function handleTaskHistory(server, id, ws, message) {
26
+ try {
27
+ await server._ensureTaskManager();
28
+ if (!message.taskId) {
29
+ server._send(ws, {
30
+ id,
31
+ type: "error",
32
+ code: "NO_TASK",
33
+ message: "taskId required",
34
+ });
35
+ return;
36
+ }
37
+ const history = server._taskManager.getHistory(message.taskId, {
38
+ limit: message.limit,
39
+ offset: message.offset,
40
+ });
41
+ server._send(ws, {
42
+ id,
43
+ type: "tasks-history",
44
+ taskId: message.taskId,
45
+ history,
46
+ });
47
+ } catch (err) {
48
+ server._send(ws, {
49
+ id,
50
+ type: "error",
51
+ code: "TASK_HISTORY_FAILED",
52
+ message: err.message,
53
+ });
54
+ }
55
+ }