@cuylabs/agent-core 0.8.0 → 0.10.0

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 (127) hide show
  1. package/README.md +33 -17
  2. package/dist/chunk-2O4MCSQS.js +780 -0
  3. package/dist/chunk-2TTOLHBT.js +198 -0
  4. package/dist/chunk-5FMSGQVX.js +281 -0
  5. package/dist/chunk-5NVVNXPQ.js +288 -0
  6. package/dist/{chunk-CAA7FHIH.js → chunk-6HZBHFOL.js} +3 -103
  7. package/dist/chunk-CJI7PVS2.js +58 -0
  8. package/dist/{chunk-N6HWIEEA.js → chunk-CMYN2RCB.js} +278 -61
  9. package/dist/chunk-FII65CN7.js +117 -0
  10. package/dist/{chunk-IVUJDISU.js → chunk-GFTW23FV.js} +5 -14
  11. package/dist/chunk-I6PKJ7XQ.js +292 -0
  12. package/dist/{chunk-BDBZ3SLK.js → chunk-ICZ66572.js} +48 -4
  13. package/dist/chunk-KYLPMBHD.js +316 -0
  14. package/dist/chunk-MXAP4UG6.js +2956 -0
  15. package/dist/{chunk-RZITT45F.js → chunk-N3VX7FEE.js} +39 -6
  16. package/dist/{chunk-YSLSEQ6B.js → chunk-NDZWXCBZ.js} +218 -95
  17. package/dist/{chunk-P6YF7USR.js → chunk-Q742PSH3.js} +23 -38
  18. package/dist/chunk-QAL3OMI3.js +943 -0
  19. package/dist/{chunk-RFEKJKTO.js → chunk-RN6WZEUF.js} +330 -280
  20. package/dist/{chunk-ZXAKHMWH.js → chunk-ROTGCYDW.js} +22 -84
  21. package/dist/chunk-SPBFQXOT.js +0 -0
  22. package/dist/{chunk-LRHOS4ZN.js → chunk-SPILYYDF.js} +3 -2
  23. package/dist/chunk-SSFBF3US.js +602 -0
  24. package/dist/chunk-SZ2XBPTW.js +8 -0
  25. package/dist/chunk-T4UIX5D7.js +115 -0
  26. package/dist/chunk-TIHPYVAJ.js +102 -0
  27. package/dist/{chunk-YUUJK53A.js → chunk-TOTDGK3P.js} +1 -1
  28. package/dist/chunk-V4RFNEET.js +563 -0
  29. package/dist/chunk-VOUEJSW6.js +0 -0
  30. package/dist/{chunk-4BDA7DQY.js → chunk-WBPOZ7CL.js} +673 -273
  31. package/dist/chunk-X4VN4GIJ.js +185 -0
  32. package/dist/dispatch/index.d.ts +93 -0
  33. package/dist/dispatch/index.js +37 -0
  34. package/dist/events/index.d.ts +93 -0
  35. package/dist/events/index.js +6 -0
  36. package/dist/{runtime → execution}/index.d.ts +120 -34
  37. package/dist/{runtime → execution}/index.js +18 -13
  38. package/dist/index-BCqEGzBj.d.ts +251 -0
  39. package/dist/index.d.ts +490 -122
  40. package/dist/index.js +2104 -615
  41. package/dist/{errors → inference/errors}/index.d.ts +2 -2
  42. package/dist/{errors → inference/errors}/index.js +1 -1
  43. package/dist/inference/index.d.ts +16 -23
  44. package/dist/inference/index.js +45 -16
  45. package/dist/instance-BqV2D5pc.d.ts +5723 -0
  46. package/dist/logger/index.d.ts +50 -0
  47. package/dist/logger/index.js +11 -0
  48. package/dist/mcp/index.d.ts +5 -9
  49. package/dist/mcp/index.js +2 -3
  50. package/dist/middleware/index.d.ts +10 -149
  51. package/dist/middleware/index.js +11 -3
  52. package/dist/model-messages-B4nK9D1-.d.ts +13 -0
  53. package/dist/models/index.d.ts +23 -18
  54. package/dist/models/index.js +48 -11
  55. package/dist/models/reasoning/index.d.ts +4 -0
  56. package/dist/{reasoning → models/reasoning}/index.js +3 -3
  57. package/dist/plugin/index.d.ts +458 -0
  58. package/dist/plugin/index.js +32 -0
  59. package/dist/profiles/index.d.ts +55 -0
  60. package/dist/profiles/index.js +30 -0
  61. package/dist/prompt/index.d.ts +8 -12
  62. package/dist/prompt/index.js +3 -2
  63. package/dist/safety/index.d.ts +109 -14
  64. package/dist/safety/index.js +59 -3
  65. package/dist/sandbox/index.d.ts +81 -0
  66. package/dist/sandbox/index.js +1 -0
  67. package/dist/skill/index.d.ts +10 -8
  68. package/dist/skill/index.js +3 -3
  69. package/dist/storage/index.d.ts +12 -4
  70. package/dist/storage/index.js +1 -1
  71. package/dist/subagents/index.d.ts +177 -0
  72. package/dist/subagents/index.js +78 -0
  73. package/dist/team/index.d.ts +544 -0
  74. package/dist/team/index.js +41 -0
  75. package/dist/tool/host/index.d.ts +41 -0
  76. package/dist/tool/host/index.js +10 -0
  77. package/dist/tool/index.d.ts +125 -21
  78. package/dist/tool/index.js +20 -13
  79. package/dist/{types-VQgymC1N.d.ts → types-Bj_J8u_W.d.ts} +44 -64
  80. package/dist/{types-CHiPh8U2.d.ts → types-C_LCeYNg.d.ts} +7 -7
  81. package/dist/types-RSCv7nQ4.d.ts +59 -0
  82. package/package.json +58 -53
  83. package/dist/builder-UpOWQMW3.d.ts +0 -34
  84. package/dist/chunk-7MUFEN4K.js +0 -559
  85. package/dist/chunk-7VKQ4WPB.js +0 -73
  86. package/dist/chunk-BFM2YHNM.js +0 -222
  87. package/dist/chunk-DWYX7ASF.js +0 -26
  88. package/dist/chunk-KUVSERLJ.js +0 -50
  89. package/dist/chunk-N7P4PN3O.js +0 -84
  90. package/dist/chunk-SDSBEQXG.js +0 -157
  91. package/dist/chunk-SQU2AJHO.js +0 -305
  92. package/dist/chunk-VBWWUHWI.js +0 -724
  93. package/dist/chunk-VEKUXUVF.js +0 -41
  94. package/dist/chunk-VNQBHPCT.js +0 -398
  95. package/dist/chunk-WWYYNWEW.js +0 -259
  96. package/dist/context/index.d.ts +0 -259
  97. package/dist/context/index.js +0 -26
  98. package/dist/events-CE72w8W4.d.ts +0 -149
  99. package/dist/host/index.d.ts +0 -45
  100. package/dist/host/index.js +0 -8
  101. package/dist/index-CWSchSql.d.ts +0 -1058
  102. package/dist/messages-BYWGn8TY.d.ts +0 -110
  103. package/dist/presets/index.d.ts +0 -53
  104. package/dist/presets/index.js +0 -28
  105. package/dist/reasoning/index.d.ts +0 -116
  106. package/dist/registry-DwYqsQkX.d.ts +0 -164
  107. package/dist/runner-e2YRcUoX.d.ts +0 -786
  108. package/dist/scope/index.d.ts +0 -10
  109. package/dist/scope/index.js +0 -14
  110. package/dist/session-manager-B_CWGTsl.d.ts +0 -274
  111. package/dist/signal/index.d.ts +0 -28
  112. package/dist/signal/index.js +0 -6
  113. package/dist/sub-agent/index.d.ts +0 -23
  114. package/dist/sub-agent/index.js +0 -15
  115. package/dist/tool-BHbyUAy3.d.ts +0 -150
  116. package/dist/tool-DLXAR9Ce.d.ts +0 -145
  117. package/dist/tracker-DClqYqTj.d.ts +0 -96
  118. package/dist/tracking/index.d.ts +0 -111
  119. package/dist/tracking/index.js +0 -20
  120. package/dist/types-BfNpU8NS.d.ts +0 -270
  121. package/dist/types-BnpEOYV-.d.ts +0 -50
  122. package/dist/types-CQL-SvTn.d.ts +0 -29
  123. package/dist/types-CWm-7rvB.d.ts +0 -55
  124. package/dist/types-KKDrdU9Y.d.ts +0 -325
  125. package/dist/types-QA4WhEfz.d.ts +0 -138
  126. package/dist/types-QKHHQLLq.d.ts +0 -336
  127. package/dist/types-YuWV4ag7.d.ts +0 -72
@@ -0,0 +1,602 @@
1
+ import {
2
+ Tool
3
+ } from "./chunk-Q742PSH3.js";
4
+ import {
5
+ buildEntryPath,
6
+ deserializeMessage
7
+ } from "./chunk-ICZ66572.js";
8
+
9
+ // src/agent/session.ts
10
+ async function ensureSessionLoaded(options) {
11
+ const { sessionId, sessions, cwd } = options;
12
+ if (sessions.getSessionId() === sessionId) {
13
+ return;
14
+ }
15
+ const exists = await sessions.sessionExists(sessionId);
16
+ if (exists) {
17
+ await sessions.load(sessionId);
18
+ } else {
19
+ await sessions.create({ id: sessionId, cwd });
20
+ }
21
+ }
22
+ async function repairOrphanedToolCalls(sessions) {
23
+ const messages = sessions.getMessages();
24
+ const pendingCallIds = /* @__PURE__ */ new Map();
25
+ for (const message of messages) {
26
+ if (message.role === "assistant" && message.toolCalls) {
27
+ for (const toolCall of message.toolCalls) {
28
+ pendingCallIds.set(toolCall.toolCallId, { toolName: toolCall.toolName });
29
+ }
30
+ }
31
+ if (message.role === "tool" && message.toolCallId) {
32
+ pendingCallIds.delete(message.toolCallId);
33
+ }
34
+ }
35
+ for (const [toolCallId, { toolName }] of pendingCallIds) {
36
+ const toolMessage = {
37
+ id: crypto.randomUUID(),
38
+ role: "tool",
39
+ content: "Error: tool execution failed (result was not recorded)",
40
+ toolCallId,
41
+ toolName,
42
+ result: "Error: tool execution failed (result was not recorded)",
43
+ createdAt: /* @__PURE__ */ new Date()
44
+ };
45
+ await sessions.addMessage(toolMessage);
46
+ }
47
+ }
48
+ async function createSubAgentRunSession(options) {
49
+ const sessionId = options.parentSessionId ? `${options.parentSessionId}:sub:${crypto.randomUUID().slice(0, 8)}` : `sub:${crypto.randomUUID().slice(0, 8)}`;
50
+ await options.sessions.create({
51
+ id: sessionId,
52
+ cwd: options.cwd,
53
+ title: options.title ?? "Sub-agent task",
54
+ parentSessionId: options.parentSessionId
55
+ });
56
+ return sessionId;
57
+ }
58
+ function getVisibleSessionMessages(sessions) {
59
+ const leafId = sessions.getLeafId();
60
+ if (!leafId) {
61
+ return [];
62
+ }
63
+ const path = buildEntryPath(
64
+ sessions.getEntries(),
65
+ leafId
66
+ );
67
+ const visible = [];
68
+ let skipUntilId;
69
+ for (const entry of path) {
70
+ if (entry.type === "compaction") {
71
+ visible.push({
72
+ id: entry.id,
73
+ role: "system",
74
+ content: `## Previous Conversation Summary
75
+
76
+ ${entry.summary}`,
77
+ createdAt: new Date(entry.timestamp)
78
+ });
79
+ skipUntilId = entry.firstKeptEntryId !== entry.id ? entry.firstKeptEntryId : void 0;
80
+ continue;
81
+ }
82
+ if (skipUntilId && entry.id !== skipUntilId) {
83
+ continue;
84
+ }
85
+ if (entry.id === skipUntilId) {
86
+ skipUntilId = void 0;
87
+ }
88
+ if (entry.type === "message") {
89
+ visible.push(deserializeMessage(entry.message));
90
+ }
91
+ }
92
+ return visible;
93
+ }
94
+
95
+ // src/dispatch/types.ts
96
+ var DISPATCH_STATES = [
97
+ "running",
98
+ "completed",
99
+ "failed",
100
+ "cancelled"
101
+ ];
102
+ var DEFAULT_DISPATCH_TOOL_IDS = [
103
+ "start_dispatch",
104
+ "check_dispatch",
105
+ "redirect_dispatch",
106
+ "cancel_dispatch",
107
+ "list_dispatches"
108
+ ];
109
+ var DEFAULT_LOCAL_DISPATCH_CONCURRENCY = 6;
110
+ var DEFAULT_LOCAL_DISPATCH_DEPTH = 2;
111
+ var DEFAULT_LOCAL_DISPATCH_TITLE_PREFIX = "Dispatch";
112
+
113
+ // src/dispatch/tool-factories.ts
114
+ import { z } from "zod";
115
+
116
+ // src/dispatch/results.ts
117
+ function formatStatus(record) {
118
+ const parts = [
119
+ `ID: ${record.id}`,
120
+ `Target: ${record.targetType}`,
121
+ `Status: ${record.status}`
122
+ ];
123
+ if (record.title) {
124
+ parts.push(`Title: ${record.title}`);
125
+ }
126
+ if (record.sessionId) {
127
+ parts.push(`Session: ${record.sessionId}`);
128
+ }
129
+ if (record.redirectCount > 0) {
130
+ parts.push(`Redirects: ${record.redirectCount}`);
131
+ }
132
+ if (record.result) {
133
+ parts.push(`Response: ${record.result.response}`);
134
+ }
135
+ if (record.error) {
136
+ parts.push(`Error: ${record.error}`);
137
+ }
138
+ return parts.join("\n");
139
+ }
140
+ function formatDispatchStarted(record) {
141
+ return {
142
+ title: `Dispatch started: ${record.targetType}`,
143
+ output: `Dispatch started successfully.
144
+
145
+ ` + formatStatus(record) + `
146
+
147
+ Use \`check_dispatch\` with ID "${record.id}" to monitor progress.`,
148
+ metadata: {
149
+ dispatchId: record.id,
150
+ targetType: record.targetType,
151
+ sessionId: record.sessionId
152
+ }
153
+ };
154
+ }
155
+ function formatDispatchChecked(record) {
156
+ return {
157
+ title: `Dispatch ${record.status}: ${record.targetType}`,
158
+ output: formatStatus(record),
159
+ metadata: {
160
+ dispatchId: record.id,
161
+ targetType: record.targetType,
162
+ status: record.status
163
+ }
164
+ };
165
+ }
166
+ function formatDispatchRedirected(record) {
167
+ return {
168
+ title: `Dispatch redirected: ${record.targetType}`,
169
+ output: `Dispatch "${record.id}" has been redirected.
170
+
171
+ ` + formatStatus(record),
172
+ metadata: {
173
+ dispatchId: record.id,
174
+ targetType: record.targetType,
175
+ redirectCount: record.redirectCount
176
+ }
177
+ };
178
+ }
179
+ function formatDispatchCancelled(record) {
180
+ return {
181
+ title: `Dispatch cancelled: ${record.targetType}`,
182
+ output: `Dispatch "${record.id}" has been cancelled.
183
+
184
+ ` + formatStatus(record),
185
+ metadata: {
186
+ dispatchId: record.id,
187
+ targetType: record.targetType
188
+ }
189
+ };
190
+ }
191
+ function formatDispatchList(records) {
192
+ if (records.length === 0) {
193
+ return {
194
+ title: "No dispatches",
195
+ output: "No dispatches match the given criteria.",
196
+ metadata: { count: 0 }
197
+ };
198
+ }
199
+ const lines = records.map(
200
+ (record) => `- ${record.id} [${record.status}] ${record.targetType}: ${record.title || record.brief}`
201
+ );
202
+ return {
203
+ title: `${records.length} dispatch(es)`,
204
+ output: lines.join("\n"),
205
+ metadata: { count: records.length }
206
+ };
207
+ }
208
+ function formatDispatchError(label, error) {
209
+ return {
210
+ title: "Dispatch error",
211
+ output: `${label}: ` + (error instanceof Error ? error.message : String(error)),
212
+ metadata: { error: true }
213
+ };
214
+ }
215
+
216
+ // src/dispatch/tool-factories.ts
217
+ function buildTargetDescription(targets) {
218
+ const list = targets.map((target) => ` - "${target.name}": ${target.description}`).join("\n");
219
+ return `Available targets:
220
+ ${list}`;
221
+ }
222
+ function createDispatchStartTool(runtime) {
223
+ const targets = runtime.describeTargets();
224
+ const targetNames = targets.map((target) => target.name);
225
+ return Tool.define("start_dispatch", {
226
+ description: `Start a new background dispatch.
227
+
228
+ ` + buildTargetDescription(targets) + `
229
+
230
+ Use \`check_dispatch\` to monitor progress after starting.`,
231
+ parameters: z.object({
232
+ targetType: z.string().describe(
233
+ `The target to dispatch to. Must be one of: ${targetNames.join(", ")}`
234
+ ),
235
+ brief: z.string().describe("Detailed instructions for the dispatch target."),
236
+ title: z.string().optional().describe("Short title for tracking."),
237
+ parentSessionId: z.string().optional().describe("Parent session ID for context linking.")
238
+ }),
239
+ execute: async (params) => {
240
+ try {
241
+ const record = await runtime.start({
242
+ targetType: params.targetType,
243
+ brief: params.brief,
244
+ title: params.title,
245
+ parentSessionId: params.parentSessionId
246
+ });
247
+ return formatDispatchStarted(record);
248
+ } catch (error) {
249
+ return formatDispatchError("Failed to start dispatch", error);
250
+ }
251
+ }
252
+ });
253
+ }
254
+ function createDispatchCheckTool(runtime) {
255
+ return Tool.define("check_dispatch", {
256
+ description: "Check the status of a running dispatch. Returns current status, and result or error if completed or failed.",
257
+ parameters: z.object({
258
+ id: z.string().describe("The dispatch ID to check."),
259
+ waitMs: z.number().optional().describe("Optional time to wait for completion (milliseconds).")
260
+ }),
261
+ execute: async (params) => {
262
+ try {
263
+ const record = await runtime.check(params.id, {
264
+ waitMs: params.waitMs
265
+ });
266
+ if (!record) {
267
+ return formatDispatchError(
268
+ "Dispatch not found",
269
+ new Error(`No dispatch with ID "${params.id}".`)
270
+ );
271
+ }
272
+ return formatDispatchChecked(record);
273
+ } catch (error) {
274
+ return formatDispatchError("Failed to inspect dispatch", error);
275
+ }
276
+ }
277
+ });
278
+ }
279
+ function createDispatchRedirectTool(runtime) {
280
+ return Tool.define("redirect_dispatch", {
281
+ description: "Send a steering message to a running dispatch. Use this to narrow scope, add context, or change direction mid-run.",
282
+ parameters: z.object({
283
+ id: z.string().describe("The dispatch ID to redirect."),
284
+ message: z.string().describe("The steering message.")
285
+ }),
286
+ execute: async (params) => {
287
+ try {
288
+ const record = await runtime.redirect(params.id, params.message);
289
+ return formatDispatchRedirected(record);
290
+ } catch (error) {
291
+ return formatDispatchError("Failed to redirect dispatch", error);
292
+ }
293
+ }
294
+ });
295
+ }
296
+ function createDispatchCancelTool(runtime) {
297
+ return Tool.define("cancel_dispatch", {
298
+ description: "Cancel a running dispatch. Use when the result is no longer needed.",
299
+ parameters: z.object({
300
+ id: z.string().describe("The dispatch ID to cancel."),
301
+ reason: z.string().optional().describe("Reason for cancellation.")
302
+ }),
303
+ execute: async (params) => {
304
+ try {
305
+ const record = await runtime.cancel(params.id, params.reason);
306
+ return formatDispatchCancelled(record);
307
+ } catch (error) {
308
+ return formatDispatchError("Failed to cancel dispatch", error);
309
+ }
310
+ }
311
+ });
312
+ }
313
+ function createDispatchListTool(runtime) {
314
+ return Tool.define("list_dispatches", {
315
+ description: "List dispatches, optionally filtered by status, target type, or parent session.",
316
+ parameters: z.object({
317
+ status: z.string().optional().describe(
318
+ 'Filter by status: "running", "completed", "failed", "cancelled".'
319
+ ),
320
+ targetType: z.string().optional().describe("Filter by target type."),
321
+ parentSessionId: z.string().optional().describe("Filter by parent session.")
322
+ }),
323
+ execute: async (params) => {
324
+ try {
325
+ const records = await runtime.list({
326
+ status: params.status,
327
+ targetType: params.targetType,
328
+ parentSessionId: params.parentSessionId
329
+ });
330
+ return formatDispatchList(records);
331
+ } catch (error) {
332
+ return formatDispatchError("Failed to list dispatches", error);
333
+ }
334
+ }
335
+ });
336
+ }
337
+
338
+ // src/dispatch/tools.ts
339
+ function createDispatchTools(runtime) {
340
+ return [
341
+ createDispatchStartTool(runtime),
342
+ createDispatchCheckTool(runtime),
343
+ createDispatchRedirectTool(runtime),
344
+ createDispatchCancelTool(runtime),
345
+ createDispatchListTool(runtime)
346
+ ];
347
+ }
348
+
349
+ // src/dispatch/runtime.ts
350
+ import { randomUUID } from "crypto";
351
+ function allowsFurtherDispatch(role) {
352
+ return role.allowFurtherDispatch ?? false;
353
+ }
354
+ function buildRoleChild(parent, role) {
355
+ const forkOptions = {};
356
+ if (role.profile) {
357
+ forkOptions.profile = role.profile;
358
+ }
359
+ if (role.systemPrompt) {
360
+ forkOptions.systemPrompt = role.systemPrompt;
361
+ }
362
+ if (role.model) {
363
+ forkOptions.model = role.model;
364
+ }
365
+ if (role.maxSteps) {
366
+ forkOptions.maxSteps = role.maxSteps;
367
+ }
368
+ if (role.additionalMiddleware) {
369
+ forkOptions.additionalMiddleware = role.additionalMiddleware;
370
+ }
371
+ if (role.additionalTools && role.additionalTools.length > 0) {
372
+ const profileChild = parent.fork(forkOptions);
373
+ forkOptions.tools = [...profileChild.getTools(), ...role.additionalTools];
374
+ return parent.fork(forkOptions);
375
+ }
376
+ return parent.fork(forkOptions);
377
+ }
378
+ function createLocalDispatchRuntime(options) {
379
+ const {
380
+ parent,
381
+ roles,
382
+ maxConcurrent = DEFAULT_LOCAL_DISPATCH_CONCURRENCY,
383
+ maxDepth = DEFAULT_LOCAL_DISPATCH_DEPTH,
384
+ currentDepth = 0,
385
+ sessionTitlePrefix = DEFAULT_LOCAL_DISPATCH_TITLE_PREFIX,
386
+ now = () => (/* @__PURE__ */ new Date()).toISOString(),
387
+ createId = () => randomUUID(),
388
+ childToolIds = DEFAULT_DISPATCH_TOOL_IDS,
389
+ createChildTools = createDispatchTools,
390
+ buildChild: customBuildChild
391
+ } = options;
392
+ const dispatches = /* @__PURE__ */ new Map();
393
+ const roleIndex = new Map(roles.map((role) => [role.name, role]));
394
+ function buildChild(role) {
395
+ const child = customBuildChild ? customBuildChild(parent, role) : buildRoleChild(parent, role);
396
+ for (const toolId of childToolIds) {
397
+ child.removeTool?.(toolId);
398
+ }
399
+ if (allowsFurtherDispatch(role) && currentDepth + 1 < maxDepth) {
400
+ const childRuntime = createLocalDispatchRuntime({
401
+ parent: child,
402
+ roles,
403
+ maxConcurrent,
404
+ maxDepth,
405
+ currentDepth: currentDepth + 1,
406
+ sessionTitlePrefix,
407
+ now,
408
+ createId,
409
+ childToolIds,
410
+ createChildTools,
411
+ buildChild: customBuildChild
412
+ });
413
+ for (const tool of createChildTools(childRuntime)) {
414
+ child.addTool(tool);
415
+ }
416
+ }
417
+ return child;
418
+ }
419
+ function describeTargets() {
420
+ return roles.map((role) => ({
421
+ name: role.name,
422
+ description: role.description
423
+ }));
424
+ }
425
+ async function start(input) {
426
+ const role = roleIndex.get(input.targetType);
427
+ if (!role) {
428
+ throw new Error(
429
+ `Unknown dispatch target "${input.targetType}". Available: ${[...roleIndex.keys()].join(", ")}`
430
+ );
431
+ }
432
+ if (currentDepth >= maxDepth) {
433
+ throw new Error(
434
+ `Dispatch depth limit reached (${currentDepth}/${maxDepth}). Cannot create further child dispatches.`
435
+ );
436
+ }
437
+ const runningCount = [...dispatches.values()].filter(
438
+ (d) => d.record.status === "running"
439
+ ).length;
440
+ if (runningCount >= maxConcurrent) {
441
+ throw new Error(
442
+ `Concurrency limit reached (${runningCount}/${maxConcurrent}). Cancel or wait for running dispatches.`
443
+ );
444
+ }
445
+ const id = createId();
446
+ const child = buildChild(role);
447
+ const abort = new AbortController();
448
+ const timestamp = now();
449
+ const title = input.title ?? `${sessionTitlePrefix}: ${role.name}`;
450
+ if (input.abort) {
451
+ if (input.abort.aborted) {
452
+ abort.abort(input.abort.reason);
453
+ } else {
454
+ input.abort.addEventListener(
455
+ "abort",
456
+ () => abort.abort(input.abort?.reason),
457
+ { once: true }
458
+ );
459
+ }
460
+ }
461
+ const sessionId = await createSubAgentRunSession({
462
+ sessions: child.getSessionManager(),
463
+ cwd: child.cwd,
464
+ parentSessionId: input.parentSessionId,
465
+ title
466
+ });
467
+ const record = {
468
+ id,
469
+ targetType: input.targetType,
470
+ title,
471
+ brief: input.brief,
472
+ status: "running",
473
+ createdAt: timestamp,
474
+ updatedAt: timestamp,
475
+ parentSessionId: input.parentSessionId,
476
+ sessionId,
477
+ executionId: id,
478
+ redirectCount: 0
479
+ };
480
+ const promise = (async () => {
481
+ try {
482
+ const result = await child.send(sessionId, input.brief, {
483
+ abort: abort.signal
484
+ });
485
+ const active = dispatches.get(id);
486
+ if (active && active.record.status === "running") {
487
+ active.record.status = "completed";
488
+ active.record.updatedAt = now();
489
+ active.record.result = {
490
+ response: result.response,
491
+ usage: {
492
+ inputTokens: result.usage?.inputTokens ?? 0,
493
+ outputTokens: result.usage?.outputTokens ?? 0,
494
+ totalTokens: result.usage?.totalTokens ?? 0
495
+ },
496
+ toolCalls: result.toolCalls ?? []
497
+ };
498
+ }
499
+ } catch (error) {
500
+ const active = dispatches.get(id);
501
+ if (active && active.record.status === "running") {
502
+ if (abort.signal.aborted) {
503
+ active.record.status = "cancelled";
504
+ } else {
505
+ active.record.status = "failed";
506
+ active.record.error = error instanceof Error ? error.message : String(error);
507
+ }
508
+ active.record.updatedAt = now();
509
+ }
510
+ }
511
+ })();
512
+ dispatches.set(id, { record, child, abort, promise });
513
+ return { ...record };
514
+ }
515
+ async function check(id, options2) {
516
+ const active = dispatches.get(id);
517
+ if (!active) {
518
+ return void 0;
519
+ }
520
+ if (active.record.status === "running" && options2?.waitMs) {
521
+ await Promise.race([
522
+ active.promise,
523
+ new Promise(
524
+ (resolve) => setTimeout(resolve, options2.waitMs)
525
+ )
526
+ ]);
527
+ }
528
+ return { ...active.record };
529
+ }
530
+ async function redirect(id, message) {
531
+ const active = dispatches.get(id);
532
+ if (!active) {
533
+ throw new Error(`No dispatch with ID "${id}".`);
534
+ }
535
+ if (active.record.status !== "running") {
536
+ throw new Error(
537
+ `Cannot redirect dispatch "${id}" \u2014 status is "${active.record.status}".`
538
+ );
539
+ }
540
+ active.child.intervene(message);
541
+ active.record.redirectCount += 1;
542
+ active.record.lastRedirect = message;
543
+ active.record.updatedAt = now();
544
+ return { ...active.record };
545
+ }
546
+ async function cancel(id, reason) {
547
+ const active = dispatches.get(id);
548
+ if (!active) {
549
+ throw new Error(`No dispatch with ID "${id}".`);
550
+ }
551
+ if (active.record.status !== "running") {
552
+ return { ...active.record };
553
+ }
554
+ active.abort.abort(reason ?? "Cancelled");
555
+ active.record.status = "cancelled";
556
+ active.record.updatedAt = now();
557
+ if (reason) {
558
+ active.record.error = reason;
559
+ }
560
+ return { ...active.record };
561
+ }
562
+ async function list(options2) {
563
+ let records = [...dispatches.values()].map((d) => ({ ...d.record }));
564
+ if (options2?.status) {
565
+ const statuses = Array.isArray(options2.status) ? options2.status : [options2.status];
566
+ records = records.filter(
567
+ (r) => statuses.includes(r.status)
568
+ );
569
+ }
570
+ if (options2?.targetType) {
571
+ records = records.filter((r) => r.targetType === options2.targetType);
572
+ }
573
+ if (options2?.parentSessionId) {
574
+ records = records.filter(
575
+ (r) => r.parentSessionId === options2.parentSessionId
576
+ );
577
+ }
578
+ return records;
579
+ }
580
+ return {
581
+ describeTargets,
582
+ start,
583
+ check,
584
+ redirect,
585
+ cancel,
586
+ list
587
+ };
588
+ }
589
+
590
+ export {
591
+ ensureSessionLoaded,
592
+ repairOrphanedToolCalls,
593
+ createSubAgentRunSession,
594
+ getVisibleSessionMessages,
595
+ DISPATCH_STATES,
596
+ DEFAULT_DISPATCH_TOOL_IDS,
597
+ DEFAULT_LOCAL_DISPATCH_CONCURRENCY,
598
+ DEFAULT_LOCAL_DISPATCH_DEPTH,
599
+ DEFAULT_LOCAL_DISPATCH_TITLE_PREFIX,
600
+ createDispatchTools,
601
+ createLocalDispatchRuntime
602
+ };
@@ -0,0 +1,8 @@
1
+ // src/utils/sleep.ts
2
+ function sleep(ms) {
3
+ return new Promise((resolve) => setTimeout(resolve, ms));
4
+ }
5
+
6
+ export {
7
+ sleep
8
+ };