@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.
- package/README.md +33 -17
- package/dist/chunk-2O4MCSQS.js +780 -0
- package/dist/chunk-2TTOLHBT.js +198 -0
- package/dist/chunk-5FMSGQVX.js +281 -0
- package/dist/chunk-5NVVNXPQ.js +288 -0
- package/dist/{chunk-CAA7FHIH.js → chunk-6HZBHFOL.js} +3 -103
- package/dist/chunk-CJI7PVS2.js +58 -0
- package/dist/{chunk-N6HWIEEA.js → chunk-CMYN2RCB.js} +278 -61
- package/dist/chunk-FII65CN7.js +117 -0
- package/dist/{chunk-IVUJDISU.js → chunk-GFTW23FV.js} +5 -14
- package/dist/chunk-I6PKJ7XQ.js +292 -0
- package/dist/{chunk-BDBZ3SLK.js → chunk-ICZ66572.js} +48 -4
- package/dist/chunk-KYLPMBHD.js +316 -0
- package/dist/chunk-MXAP4UG6.js +2956 -0
- package/dist/{chunk-RZITT45F.js → chunk-N3VX7FEE.js} +39 -6
- package/dist/{chunk-YSLSEQ6B.js → chunk-NDZWXCBZ.js} +218 -95
- package/dist/{chunk-P6YF7USR.js → chunk-Q742PSH3.js} +23 -38
- package/dist/chunk-QAL3OMI3.js +943 -0
- package/dist/{chunk-RFEKJKTO.js → chunk-RN6WZEUF.js} +330 -280
- package/dist/{chunk-ZXAKHMWH.js → chunk-ROTGCYDW.js} +22 -84
- package/dist/chunk-SPBFQXOT.js +0 -0
- package/dist/{chunk-LRHOS4ZN.js → chunk-SPILYYDF.js} +3 -2
- package/dist/chunk-SSFBF3US.js +602 -0
- package/dist/chunk-SZ2XBPTW.js +8 -0
- package/dist/chunk-T4UIX5D7.js +115 -0
- package/dist/chunk-TIHPYVAJ.js +102 -0
- package/dist/{chunk-YUUJK53A.js → chunk-TOTDGK3P.js} +1 -1
- package/dist/chunk-V4RFNEET.js +563 -0
- package/dist/chunk-VOUEJSW6.js +0 -0
- package/dist/{chunk-4BDA7DQY.js → chunk-WBPOZ7CL.js} +673 -273
- package/dist/chunk-X4VN4GIJ.js +185 -0
- package/dist/dispatch/index.d.ts +93 -0
- package/dist/dispatch/index.js +37 -0
- package/dist/events/index.d.ts +93 -0
- package/dist/events/index.js +6 -0
- package/dist/{runtime → execution}/index.d.ts +120 -34
- package/dist/{runtime → execution}/index.js +18 -13
- package/dist/index-BCqEGzBj.d.ts +251 -0
- package/dist/index.d.ts +490 -122
- package/dist/index.js +2104 -615
- package/dist/{errors → inference/errors}/index.d.ts +2 -2
- package/dist/{errors → inference/errors}/index.js +1 -1
- package/dist/inference/index.d.ts +16 -23
- package/dist/inference/index.js +45 -16
- package/dist/instance-BqV2D5pc.d.ts +5723 -0
- package/dist/logger/index.d.ts +50 -0
- package/dist/logger/index.js +11 -0
- package/dist/mcp/index.d.ts +5 -9
- package/dist/mcp/index.js +2 -3
- package/dist/middleware/index.d.ts +10 -149
- package/dist/middleware/index.js +11 -3
- package/dist/model-messages-B4nK9D1-.d.ts +13 -0
- package/dist/models/index.d.ts +23 -18
- package/dist/models/index.js +48 -11
- package/dist/models/reasoning/index.d.ts +4 -0
- package/dist/{reasoning → models/reasoning}/index.js +3 -3
- package/dist/plugin/index.d.ts +458 -0
- package/dist/plugin/index.js +32 -0
- package/dist/profiles/index.d.ts +55 -0
- package/dist/profiles/index.js +30 -0
- package/dist/prompt/index.d.ts +8 -12
- package/dist/prompt/index.js +3 -2
- package/dist/safety/index.d.ts +109 -14
- package/dist/safety/index.js +59 -3
- package/dist/sandbox/index.d.ts +81 -0
- package/dist/sandbox/index.js +1 -0
- package/dist/skill/index.d.ts +10 -8
- package/dist/skill/index.js +3 -3
- package/dist/storage/index.d.ts +12 -4
- package/dist/storage/index.js +1 -1
- package/dist/subagents/index.d.ts +177 -0
- package/dist/subagents/index.js +78 -0
- package/dist/team/index.d.ts +544 -0
- package/dist/team/index.js +41 -0
- package/dist/tool/host/index.d.ts +41 -0
- package/dist/tool/host/index.js +10 -0
- package/dist/tool/index.d.ts +125 -21
- package/dist/tool/index.js +20 -13
- package/dist/{types-VQgymC1N.d.ts → types-Bj_J8u_W.d.ts} +44 -64
- package/dist/{types-CHiPh8U2.d.ts → types-C_LCeYNg.d.ts} +7 -7
- package/dist/types-RSCv7nQ4.d.ts +59 -0
- package/package.json +58 -53
- package/dist/builder-UpOWQMW3.d.ts +0 -34
- package/dist/chunk-7MUFEN4K.js +0 -559
- package/dist/chunk-7VKQ4WPB.js +0 -73
- package/dist/chunk-BFM2YHNM.js +0 -222
- package/dist/chunk-DWYX7ASF.js +0 -26
- package/dist/chunk-KUVSERLJ.js +0 -50
- package/dist/chunk-N7P4PN3O.js +0 -84
- package/dist/chunk-SDSBEQXG.js +0 -157
- package/dist/chunk-SQU2AJHO.js +0 -305
- package/dist/chunk-VBWWUHWI.js +0 -724
- package/dist/chunk-VEKUXUVF.js +0 -41
- package/dist/chunk-VNQBHPCT.js +0 -398
- package/dist/chunk-WWYYNWEW.js +0 -259
- package/dist/context/index.d.ts +0 -259
- package/dist/context/index.js +0 -26
- package/dist/events-CE72w8W4.d.ts +0 -149
- package/dist/host/index.d.ts +0 -45
- package/dist/host/index.js +0 -8
- package/dist/index-CWSchSql.d.ts +0 -1058
- package/dist/messages-BYWGn8TY.d.ts +0 -110
- package/dist/presets/index.d.ts +0 -53
- package/dist/presets/index.js +0 -28
- package/dist/reasoning/index.d.ts +0 -116
- package/dist/registry-DwYqsQkX.d.ts +0 -164
- package/dist/runner-e2YRcUoX.d.ts +0 -786
- package/dist/scope/index.d.ts +0 -10
- package/dist/scope/index.js +0 -14
- package/dist/session-manager-B_CWGTsl.d.ts +0 -274
- package/dist/signal/index.d.ts +0 -28
- package/dist/signal/index.js +0 -6
- package/dist/sub-agent/index.d.ts +0 -23
- package/dist/sub-agent/index.js +0 -15
- package/dist/tool-BHbyUAy3.d.ts +0 -150
- package/dist/tool-DLXAR9Ce.d.ts +0 -145
- package/dist/tracker-DClqYqTj.d.ts +0 -96
- package/dist/tracking/index.d.ts +0 -111
- package/dist/tracking/index.js +0 -20
- package/dist/types-BfNpU8NS.d.ts +0 -270
- package/dist/types-BnpEOYV-.d.ts +0 -50
- package/dist/types-CQL-SvTn.d.ts +0 -29
- package/dist/types-CWm-7rvB.d.ts +0 -55
- package/dist/types-KKDrdU9Y.d.ts +0 -325
- package/dist/types-QA4WhEfz.d.ts +0 -138
- package/dist/types-QKHHQLLq.d.ts +0 -336
- 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
|
+
};
|