llmist 6.0.0 → 6.2.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/dist/{chunk-EIE5VRSI.js → chunk-36YSBSGB.js} +967 -396
- package/dist/chunk-36YSBSGB.js.map +1 -0
- package/dist/{chunk-F62X5W2G.js → chunk-EJEP5MHQ.js} +108 -25
- package/dist/chunk-EJEP5MHQ.js.map +1 -0
- package/dist/cli.cjs +11874 -9401
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3008 -1101
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +6589 -5923
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +184 -311
- package/dist/index.d.ts +184 -311
- package/dist/index.js +29 -3
- package/dist/{mock-stream-CAY53Q6u.d.cts → mock-stream-DG4wF-NH.d.cts} +1161 -161
- package/dist/{mock-stream-CAY53Q6u.d.ts → mock-stream-DG4wF-NH.d.ts} +1161 -161
- package/dist/testing/index.cjs +956 -389
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-EIE5VRSI.js.map +0 -1
- package/dist/chunk-F62X5W2G.js.map +0 -1
|
@@ -690,23 +690,26 @@ Produces: { "items": ["first", "second"] }`);
|
|
|
690
690
|
* Record a gadget execution result in the message history.
|
|
691
691
|
* Creates an assistant message with the gadget invocation and a user message with the result.
|
|
692
692
|
*
|
|
693
|
+
* The invocationId is shown to the LLM so it can reference previous calls when building dependencies.
|
|
694
|
+
*
|
|
693
695
|
* @param gadget - Name of the gadget that was executed
|
|
694
696
|
* @param parameters - Parameters that were passed to the gadget
|
|
695
697
|
* @param result - Text result from the gadget execution
|
|
698
|
+
* @param invocationId - Invocation ID (shown to LLM so it can reference for dependencies)
|
|
696
699
|
* @param media - Optional media outputs from the gadget
|
|
697
700
|
* @param mediaIds - Optional IDs for the media outputs
|
|
698
701
|
*/
|
|
699
|
-
addGadgetCallResult(gadget, parameters, result, media, mediaIds) {
|
|
702
|
+
addGadgetCallResult(gadget, parameters, result, invocationId, media, mediaIds) {
|
|
700
703
|
const paramStr = this.formatBlockParameters(parameters, "");
|
|
701
704
|
this.messages.push({
|
|
702
705
|
role: "assistant",
|
|
703
|
-
content: `${this.startPrefix}${gadget}
|
|
706
|
+
content: `${this.startPrefix}${gadget}:${invocationId}
|
|
704
707
|
${paramStr}
|
|
705
708
|
${this.endPrefix}`
|
|
706
709
|
});
|
|
707
710
|
if (media && media.length > 0 && mediaIds && mediaIds.length > 0) {
|
|
708
711
|
const idRefs = media.map((m, i) => `[Media: ${mediaIds[i]} (${m.kind})]`).join("\n");
|
|
709
|
-
const textWithIds = `Result: ${result}
|
|
712
|
+
const textWithIds = `Result (${invocationId}): ${result}
|
|
710
713
|
${idRefs}`;
|
|
711
714
|
const parts = [text(textWithIds)];
|
|
712
715
|
for (const item of media) {
|
|
@@ -720,7 +723,7 @@ ${idRefs}`;
|
|
|
720
723
|
} else {
|
|
721
724
|
this.messages.push({
|
|
722
725
|
role: "user",
|
|
723
|
-
content: `Result: ${result}`
|
|
726
|
+
content: `Result (${invocationId}): ${result}`
|
|
724
727
|
});
|
|
725
728
|
}
|
|
726
729
|
return this;
|
|
@@ -1072,6 +1075,611 @@ var init_registry = __esm({
|
|
|
1072
1075
|
}
|
|
1073
1076
|
});
|
|
1074
1077
|
|
|
1078
|
+
// src/core/execution-tree.ts
|
|
1079
|
+
var ExecutionTree;
|
|
1080
|
+
var init_execution_tree = __esm({
|
|
1081
|
+
"src/core/execution-tree.ts"() {
|
|
1082
|
+
"use strict";
|
|
1083
|
+
ExecutionTree = class {
|
|
1084
|
+
nodes = /* @__PURE__ */ new Map();
|
|
1085
|
+
rootIds = [];
|
|
1086
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
1087
|
+
eventIdCounter = 0;
|
|
1088
|
+
invocationIdToNodeId = /* @__PURE__ */ new Map();
|
|
1089
|
+
// For async event streaming
|
|
1090
|
+
eventQueue = [];
|
|
1091
|
+
eventWaiters = [];
|
|
1092
|
+
isCompleted = false;
|
|
1093
|
+
/**
|
|
1094
|
+
* Base depth for all nodes in this tree.
|
|
1095
|
+
* Used when this tree is a subagent's view into a parent tree.
|
|
1096
|
+
*/
|
|
1097
|
+
baseDepth;
|
|
1098
|
+
/**
|
|
1099
|
+
* Parent node ID for subagent trees.
|
|
1100
|
+
* All root nodes in this tree will have this as their parentId.
|
|
1101
|
+
*/
|
|
1102
|
+
parentNodeId;
|
|
1103
|
+
constructor(options) {
|
|
1104
|
+
this.baseDepth = options?.baseDepth ?? 0;
|
|
1105
|
+
this.parentNodeId = options?.parentNodeId ?? null;
|
|
1106
|
+
}
|
|
1107
|
+
// ===========================================================================
|
|
1108
|
+
// Node ID Generation
|
|
1109
|
+
// ===========================================================================
|
|
1110
|
+
generateLLMCallId(iteration, parentId) {
|
|
1111
|
+
if (parentId) {
|
|
1112
|
+
return `llm_${parentId}_${iteration}`;
|
|
1113
|
+
}
|
|
1114
|
+
return `llm_${iteration}`;
|
|
1115
|
+
}
|
|
1116
|
+
gadgetIdCounter = 0;
|
|
1117
|
+
generateGadgetId(invocationId) {
|
|
1118
|
+
return `gadget_${invocationId}_${++this.gadgetIdCounter}`;
|
|
1119
|
+
}
|
|
1120
|
+
// ===========================================================================
|
|
1121
|
+
// Event Emission
|
|
1122
|
+
// ===========================================================================
|
|
1123
|
+
emit(event) {
|
|
1124
|
+
const listeners = this.eventListeners.get(event.type);
|
|
1125
|
+
if (listeners) {
|
|
1126
|
+
for (const listener of listeners) {
|
|
1127
|
+
try {
|
|
1128
|
+
listener(event);
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
console.error(`Error in event listener for ${event.type}:`, error);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
const allListeners = this.eventListeners.get("*");
|
|
1135
|
+
if (allListeners) {
|
|
1136
|
+
for (const listener of allListeners) {
|
|
1137
|
+
try {
|
|
1138
|
+
listener(event);
|
|
1139
|
+
} catch (error) {
|
|
1140
|
+
console.error("Error in wildcard event listener:", error);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
if (this.eventWaiters.length > 0) {
|
|
1145
|
+
const waiter = this.eventWaiters.shift();
|
|
1146
|
+
if (waiter) waiter(event);
|
|
1147
|
+
} else {
|
|
1148
|
+
this.eventQueue.push(event);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
createBaseEventProps(node) {
|
|
1152
|
+
return {
|
|
1153
|
+
eventId: ++this.eventIdCounter,
|
|
1154
|
+
timestamp: Date.now(),
|
|
1155
|
+
nodeId: node.id,
|
|
1156
|
+
parentId: node.parentId,
|
|
1157
|
+
depth: node.depth,
|
|
1158
|
+
path: node.path
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
// ===========================================================================
|
|
1162
|
+
// Node Creation
|
|
1163
|
+
// ===========================================================================
|
|
1164
|
+
/**
|
|
1165
|
+
* Add a new LLM call node to the tree.
|
|
1166
|
+
*/
|
|
1167
|
+
addLLMCall(params) {
|
|
1168
|
+
const parentId = params.parentId ?? this.parentNodeId;
|
|
1169
|
+
const parent = parentId ? this.nodes.get(parentId) : null;
|
|
1170
|
+
const depth = parent ? parent.depth + 1 : this.baseDepth;
|
|
1171
|
+
const path = parent ? [...parent.path] : [];
|
|
1172
|
+
const id = this.generateLLMCallId(params.iteration, parentId);
|
|
1173
|
+
path.push(id);
|
|
1174
|
+
const node = {
|
|
1175
|
+
id,
|
|
1176
|
+
type: "llm_call",
|
|
1177
|
+
parentId,
|
|
1178
|
+
depth,
|
|
1179
|
+
path,
|
|
1180
|
+
createdAt: Date.now(),
|
|
1181
|
+
completedAt: null,
|
|
1182
|
+
iteration: params.iteration,
|
|
1183
|
+
model: params.model,
|
|
1184
|
+
request: params.request,
|
|
1185
|
+
response: "",
|
|
1186
|
+
children: []
|
|
1187
|
+
};
|
|
1188
|
+
this.nodes.set(id, node);
|
|
1189
|
+
if (!parentId) {
|
|
1190
|
+
this.rootIds.push(id);
|
|
1191
|
+
} else if (parent) {
|
|
1192
|
+
parent.children.push(id);
|
|
1193
|
+
}
|
|
1194
|
+
this.emit({
|
|
1195
|
+
type: "llm_call_start",
|
|
1196
|
+
...this.createBaseEventProps(node),
|
|
1197
|
+
iteration: node.iteration,
|
|
1198
|
+
model: node.model,
|
|
1199
|
+
request: node.request
|
|
1200
|
+
});
|
|
1201
|
+
return node;
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Add text to an LLM call's response (for streaming).
|
|
1205
|
+
*/
|
|
1206
|
+
appendLLMResponse(nodeId, chunk) {
|
|
1207
|
+
const node = this.nodes.get(nodeId);
|
|
1208
|
+
if (!node || node.type !== "llm_call") {
|
|
1209
|
+
throw new Error(`LLM call node not found: ${nodeId}`);
|
|
1210
|
+
}
|
|
1211
|
+
node.response += chunk;
|
|
1212
|
+
this.emit({
|
|
1213
|
+
type: "llm_call_stream",
|
|
1214
|
+
...this.createBaseEventProps(node),
|
|
1215
|
+
chunk
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Complete an LLM call node.
|
|
1220
|
+
*/
|
|
1221
|
+
completeLLMCall(nodeId, params) {
|
|
1222
|
+
const node = this.nodes.get(nodeId);
|
|
1223
|
+
if (!node || node.type !== "llm_call") {
|
|
1224
|
+
throw new Error(`LLM call node not found: ${nodeId}`);
|
|
1225
|
+
}
|
|
1226
|
+
const llmNode = node;
|
|
1227
|
+
llmNode.completedAt = Date.now();
|
|
1228
|
+
if (params.response !== void 0) llmNode.response = params.response;
|
|
1229
|
+
if (params.usage) llmNode.usage = params.usage;
|
|
1230
|
+
if (params.finishReason !== void 0) llmNode.finishReason = params.finishReason;
|
|
1231
|
+
if (params.cost !== void 0) llmNode.cost = params.cost;
|
|
1232
|
+
this.emit({
|
|
1233
|
+
type: "llm_call_complete",
|
|
1234
|
+
...this.createBaseEventProps(node),
|
|
1235
|
+
response: llmNode.response,
|
|
1236
|
+
usage: llmNode.usage,
|
|
1237
|
+
finishReason: llmNode.finishReason,
|
|
1238
|
+
cost: llmNode.cost
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Mark an LLM call as failed.
|
|
1243
|
+
*/
|
|
1244
|
+
failLLMCall(nodeId, error, recovered) {
|
|
1245
|
+
const node = this.nodes.get(nodeId);
|
|
1246
|
+
if (!node || node.type !== "llm_call") {
|
|
1247
|
+
throw new Error(`LLM call node not found: ${nodeId}`);
|
|
1248
|
+
}
|
|
1249
|
+
const llmNode = node;
|
|
1250
|
+
llmNode.completedAt = Date.now();
|
|
1251
|
+
this.emit({
|
|
1252
|
+
type: "llm_call_error",
|
|
1253
|
+
...this.createBaseEventProps(node),
|
|
1254
|
+
error,
|
|
1255
|
+
recovered
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Add a new gadget node to the tree.
|
|
1260
|
+
*/
|
|
1261
|
+
addGadget(params) {
|
|
1262
|
+
const parentId = params.parentId ?? this.getCurrentLLMCallId() ?? this.parentNodeId;
|
|
1263
|
+
const parent = parentId ? this.nodes.get(parentId) : null;
|
|
1264
|
+
const depth = parent ? parent.depth + 1 : this.baseDepth;
|
|
1265
|
+
const path = parent ? [...parent.path] : [];
|
|
1266
|
+
const id = this.generateGadgetId(params.invocationId);
|
|
1267
|
+
path.push(id);
|
|
1268
|
+
const node = {
|
|
1269
|
+
id,
|
|
1270
|
+
type: "gadget",
|
|
1271
|
+
parentId,
|
|
1272
|
+
depth,
|
|
1273
|
+
path,
|
|
1274
|
+
createdAt: Date.now(),
|
|
1275
|
+
completedAt: null,
|
|
1276
|
+
invocationId: params.invocationId,
|
|
1277
|
+
name: params.name,
|
|
1278
|
+
parameters: params.parameters,
|
|
1279
|
+
dependencies: params.dependencies ?? [],
|
|
1280
|
+
state: "pending",
|
|
1281
|
+
children: [],
|
|
1282
|
+
isSubagent: false
|
|
1283
|
+
};
|
|
1284
|
+
this.nodes.set(id, node);
|
|
1285
|
+
this.invocationIdToNodeId.set(params.invocationId, id);
|
|
1286
|
+
if (parent) {
|
|
1287
|
+
parent.children.push(id);
|
|
1288
|
+
}
|
|
1289
|
+
this.emit({
|
|
1290
|
+
type: "gadget_call",
|
|
1291
|
+
...this.createBaseEventProps(node),
|
|
1292
|
+
invocationId: node.invocationId,
|
|
1293
|
+
name: node.name,
|
|
1294
|
+
parameters: node.parameters,
|
|
1295
|
+
dependencies: node.dependencies
|
|
1296
|
+
});
|
|
1297
|
+
return node;
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Mark a gadget as started (running).
|
|
1301
|
+
*/
|
|
1302
|
+
startGadget(nodeId) {
|
|
1303
|
+
const node = this.nodes.get(nodeId);
|
|
1304
|
+
if (!node || node.type !== "gadget") {
|
|
1305
|
+
throw new Error(`Gadget node not found: ${nodeId}`);
|
|
1306
|
+
}
|
|
1307
|
+
const gadgetNode = node;
|
|
1308
|
+
gadgetNode.state = "running";
|
|
1309
|
+
this.emit({
|
|
1310
|
+
type: "gadget_start",
|
|
1311
|
+
...this.createBaseEventProps(node),
|
|
1312
|
+
invocationId: gadgetNode.invocationId,
|
|
1313
|
+
name: gadgetNode.name
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Complete a gadget node successfully.
|
|
1318
|
+
*/
|
|
1319
|
+
completeGadget(nodeId, params) {
|
|
1320
|
+
const node = this.nodes.get(nodeId);
|
|
1321
|
+
if (!node || node.type !== "gadget") {
|
|
1322
|
+
throw new Error(`Gadget node not found: ${nodeId}`);
|
|
1323
|
+
}
|
|
1324
|
+
const gadgetNode = node;
|
|
1325
|
+
gadgetNode.completedAt = Date.now();
|
|
1326
|
+
gadgetNode.state = params.error ? "failed" : "completed";
|
|
1327
|
+
if (params.result !== void 0) gadgetNode.result = params.result;
|
|
1328
|
+
if (params.error) gadgetNode.error = params.error;
|
|
1329
|
+
if (params.executionTimeMs !== void 0) gadgetNode.executionTimeMs = params.executionTimeMs;
|
|
1330
|
+
if (params.cost !== void 0) gadgetNode.cost = params.cost;
|
|
1331
|
+
if (params.media) gadgetNode.media = params.media;
|
|
1332
|
+
gadgetNode.isSubagent = gadgetNode.children.some((childId) => {
|
|
1333
|
+
const child = this.nodes.get(childId);
|
|
1334
|
+
return child?.type === "llm_call";
|
|
1335
|
+
});
|
|
1336
|
+
if (params.error) {
|
|
1337
|
+
this.emit({
|
|
1338
|
+
type: "gadget_error",
|
|
1339
|
+
...this.createBaseEventProps(node),
|
|
1340
|
+
invocationId: gadgetNode.invocationId,
|
|
1341
|
+
name: gadgetNode.name,
|
|
1342
|
+
error: params.error,
|
|
1343
|
+
executionTimeMs: params.executionTimeMs ?? 0
|
|
1344
|
+
});
|
|
1345
|
+
} else {
|
|
1346
|
+
this.emit({
|
|
1347
|
+
type: "gadget_complete",
|
|
1348
|
+
...this.createBaseEventProps(node),
|
|
1349
|
+
invocationId: gadgetNode.invocationId,
|
|
1350
|
+
name: gadgetNode.name,
|
|
1351
|
+
result: params.result ?? "",
|
|
1352
|
+
executionTimeMs: params.executionTimeMs ?? 0,
|
|
1353
|
+
cost: params.cost,
|
|
1354
|
+
media: params.media
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Mark a gadget as skipped due to dependency failure.
|
|
1360
|
+
*/
|
|
1361
|
+
skipGadget(nodeId, failedDependency, failedDependencyError, reason) {
|
|
1362
|
+
const node = this.nodes.get(nodeId);
|
|
1363
|
+
if (!node || node.type !== "gadget") {
|
|
1364
|
+
throw new Error(`Gadget node not found: ${nodeId}`);
|
|
1365
|
+
}
|
|
1366
|
+
const gadgetNode = node;
|
|
1367
|
+
gadgetNode.completedAt = Date.now();
|
|
1368
|
+
gadgetNode.state = "skipped";
|
|
1369
|
+
gadgetNode.failedDependency = failedDependency;
|
|
1370
|
+
gadgetNode.error = failedDependencyError;
|
|
1371
|
+
const error = reason === "controller_skip" ? "Skipped by controller" : `Dependency ${failedDependency} failed: ${failedDependencyError}`;
|
|
1372
|
+
this.emit({
|
|
1373
|
+
type: "gadget_skipped",
|
|
1374
|
+
...this.createBaseEventProps(node),
|
|
1375
|
+
invocationId: gadgetNode.invocationId,
|
|
1376
|
+
name: gadgetNode.name,
|
|
1377
|
+
reason,
|
|
1378
|
+
error,
|
|
1379
|
+
failedDependency,
|
|
1380
|
+
failedDependencyError
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
// ===========================================================================
|
|
1384
|
+
// Text Events (pure notifications, not tree nodes)
|
|
1385
|
+
// ===========================================================================
|
|
1386
|
+
/**
|
|
1387
|
+
* Emit a text event (notification only, not stored in tree).
|
|
1388
|
+
*/
|
|
1389
|
+
emitText(content, llmCallNodeId) {
|
|
1390
|
+
const node = this.nodes.get(llmCallNodeId);
|
|
1391
|
+
if (!node) {
|
|
1392
|
+
throw new Error(`Node not found: ${llmCallNodeId}`);
|
|
1393
|
+
}
|
|
1394
|
+
this.emit({
|
|
1395
|
+
type: "text",
|
|
1396
|
+
...this.createBaseEventProps(node),
|
|
1397
|
+
content
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
// ===========================================================================
|
|
1401
|
+
// Query Methods
|
|
1402
|
+
// ===========================================================================
|
|
1403
|
+
/**
|
|
1404
|
+
* Get a node by ID.
|
|
1405
|
+
*/
|
|
1406
|
+
getNode(id) {
|
|
1407
|
+
return this.nodes.get(id);
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Get a gadget node by invocation ID.
|
|
1411
|
+
*/
|
|
1412
|
+
getNodeByInvocationId(invocationId) {
|
|
1413
|
+
const nodeId = this.invocationIdToNodeId.get(invocationId);
|
|
1414
|
+
if (!nodeId) return void 0;
|
|
1415
|
+
const node = this.nodes.get(nodeId);
|
|
1416
|
+
return node?.type === "gadget" ? node : void 0;
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Get all root nodes (depth 0 for this tree).
|
|
1420
|
+
*/
|
|
1421
|
+
getRoots() {
|
|
1422
|
+
return this.rootIds.map((id) => this.nodes.get(id)).filter((node) => node !== void 0);
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Get children of a node.
|
|
1426
|
+
*/
|
|
1427
|
+
getChildren(id) {
|
|
1428
|
+
const node = this.nodes.get(id);
|
|
1429
|
+
if (!node) return [];
|
|
1430
|
+
return node.children.map((childId) => this.nodes.get(childId)).filter((child) => child !== void 0);
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* Get ancestors of a node (from root to parent).
|
|
1434
|
+
*/
|
|
1435
|
+
getAncestors(id) {
|
|
1436
|
+
const node = this.nodes.get(id);
|
|
1437
|
+
if (!node) return [];
|
|
1438
|
+
const ancestors = [];
|
|
1439
|
+
let currentId = node.parentId;
|
|
1440
|
+
while (currentId) {
|
|
1441
|
+
const ancestor = this.nodes.get(currentId);
|
|
1442
|
+
if (ancestor) {
|
|
1443
|
+
ancestors.unshift(ancestor);
|
|
1444
|
+
currentId = ancestor.parentId;
|
|
1445
|
+
} else {
|
|
1446
|
+
break;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
return ancestors;
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Get all descendants of a node.
|
|
1453
|
+
*/
|
|
1454
|
+
getDescendants(id, type) {
|
|
1455
|
+
const node = this.nodes.get(id);
|
|
1456
|
+
if (!node) return [];
|
|
1457
|
+
const descendants = [];
|
|
1458
|
+
const stack = [...node.children];
|
|
1459
|
+
while (stack.length > 0) {
|
|
1460
|
+
const childId = stack.pop();
|
|
1461
|
+
const child = this.nodes.get(childId);
|
|
1462
|
+
if (child) {
|
|
1463
|
+
if (!type || child.type === type) {
|
|
1464
|
+
descendants.push(child);
|
|
1465
|
+
}
|
|
1466
|
+
stack.push(...child.children);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
return descendants;
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* Get the current (most recent incomplete) LLM call node.
|
|
1473
|
+
*/
|
|
1474
|
+
getCurrentLLMCallId() {
|
|
1475
|
+
for (let i = this.rootIds.length - 1; i >= 0; i--) {
|
|
1476
|
+
const node = this.nodes.get(this.rootIds[i]);
|
|
1477
|
+
if (node?.type === "llm_call" && !node.completedAt) {
|
|
1478
|
+
return node.id;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
return void 0;
|
|
1482
|
+
}
|
|
1483
|
+
// ===========================================================================
|
|
1484
|
+
// Aggregation Methods (for subagent support)
|
|
1485
|
+
// ===========================================================================
|
|
1486
|
+
/**
|
|
1487
|
+
* Get total cost for entire tree.
|
|
1488
|
+
*/
|
|
1489
|
+
getTotalCost() {
|
|
1490
|
+
let total = 0;
|
|
1491
|
+
for (const node of this.nodes.values()) {
|
|
1492
|
+
if (node.type === "llm_call" && node.cost) {
|
|
1493
|
+
total += node.cost;
|
|
1494
|
+
} else if (node.type === "gadget" && node.cost) {
|
|
1495
|
+
total += node.cost;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
return total;
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* Get total cost for a subtree (node and all descendants).
|
|
1502
|
+
*/
|
|
1503
|
+
getSubtreeCost(nodeId) {
|
|
1504
|
+
const node = this.nodes.get(nodeId);
|
|
1505
|
+
if (!node) return 0;
|
|
1506
|
+
let total = 0;
|
|
1507
|
+
if (node.type === "llm_call" && node.cost) {
|
|
1508
|
+
total += node.cost;
|
|
1509
|
+
} else if (node.type === "gadget" && node.cost) {
|
|
1510
|
+
total += node.cost;
|
|
1511
|
+
}
|
|
1512
|
+
for (const descendant of this.getDescendants(nodeId)) {
|
|
1513
|
+
if (descendant.type === "llm_call" && descendant.cost) {
|
|
1514
|
+
total += descendant.cost;
|
|
1515
|
+
} else if (descendant.type === "gadget" && descendant.cost) {
|
|
1516
|
+
total += descendant.cost;
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
return total;
|
|
1520
|
+
}
|
|
1521
|
+
/**
|
|
1522
|
+
* Get token usage for entire tree.
|
|
1523
|
+
*/
|
|
1524
|
+
getTotalTokens() {
|
|
1525
|
+
let input = 0;
|
|
1526
|
+
let output = 0;
|
|
1527
|
+
let cached = 0;
|
|
1528
|
+
for (const node of this.nodes.values()) {
|
|
1529
|
+
if (node.type === "llm_call") {
|
|
1530
|
+
const llmNode = node;
|
|
1531
|
+
if (llmNode.usage) {
|
|
1532
|
+
input += llmNode.usage.inputTokens;
|
|
1533
|
+
output += llmNode.usage.outputTokens;
|
|
1534
|
+
cached += llmNode.usage.cachedInputTokens ?? 0;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
return { input, output, cached };
|
|
1539
|
+
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Get token usage for a subtree.
|
|
1542
|
+
*/
|
|
1543
|
+
getSubtreeTokens(nodeId) {
|
|
1544
|
+
const node = this.nodes.get(nodeId);
|
|
1545
|
+
if (!node) return { input: 0, output: 0, cached: 0 };
|
|
1546
|
+
let input = 0;
|
|
1547
|
+
let output = 0;
|
|
1548
|
+
let cached = 0;
|
|
1549
|
+
const nodesToProcess = [node, ...this.getDescendants(nodeId)];
|
|
1550
|
+
for (const n of nodesToProcess) {
|
|
1551
|
+
if (n.type === "llm_call") {
|
|
1552
|
+
const llmNode = n;
|
|
1553
|
+
if (llmNode.usage) {
|
|
1554
|
+
input += llmNode.usage.inputTokens;
|
|
1555
|
+
output += llmNode.usage.outputTokens;
|
|
1556
|
+
cached += llmNode.usage.cachedInputTokens ?? 0;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
return { input, output, cached };
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Collect all media from a subtree.
|
|
1564
|
+
*/
|
|
1565
|
+
getSubtreeMedia(nodeId) {
|
|
1566
|
+
const node = this.nodes.get(nodeId);
|
|
1567
|
+
if (!node) return [];
|
|
1568
|
+
const media = [];
|
|
1569
|
+
const nodesToProcess = node.type === "gadget" ? [node] : [];
|
|
1570
|
+
nodesToProcess.push(...this.getDescendants(nodeId, "gadget"));
|
|
1571
|
+
for (const n of nodesToProcess) {
|
|
1572
|
+
if (n.type === "gadget") {
|
|
1573
|
+
const gadgetNode = n;
|
|
1574
|
+
if (gadgetNode.media) {
|
|
1575
|
+
media.push(...gadgetNode.media);
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
return media;
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Check if a subtree is complete (all nodes finished).
|
|
1583
|
+
*/
|
|
1584
|
+
isSubtreeComplete(nodeId) {
|
|
1585
|
+
const node = this.nodes.get(nodeId);
|
|
1586
|
+
if (!node) return true;
|
|
1587
|
+
if (!node.completedAt) return false;
|
|
1588
|
+
for (const descendant of this.getDescendants(nodeId)) {
|
|
1589
|
+
if (!descendant.completedAt) return false;
|
|
1590
|
+
}
|
|
1591
|
+
return true;
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* Get node counts.
|
|
1595
|
+
*/
|
|
1596
|
+
getNodeCount() {
|
|
1597
|
+
let llmCalls = 0;
|
|
1598
|
+
let gadgets = 0;
|
|
1599
|
+
for (const node of this.nodes.values()) {
|
|
1600
|
+
if (node.type === "llm_call") llmCalls++;
|
|
1601
|
+
else if (node.type === "gadget") gadgets++;
|
|
1602
|
+
}
|
|
1603
|
+
return { llmCalls, gadgets };
|
|
1604
|
+
}
|
|
1605
|
+
// ===========================================================================
|
|
1606
|
+
// Event Subscription
|
|
1607
|
+
// ===========================================================================
|
|
1608
|
+
/**
|
|
1609
|
+
* Subscribe to events of a specific type.
|
|
1610
|
+
* Returns unsubscribe function.
|
|
1611
|
+
*
|
|
1612
|
+
* @param type - Event type to subscribe to (use "*" for all events)
|
|
1613
|
+
* @param listener - Callback function that receives matching events
|
|
1614
|
+
* @returns Unsubscribe function
|
|
1615
|
+
*
|
|
1616
|
+
* @example
|
|
1617
|
+
* ```typescript
|
|
1618
|
+
* const unsubscribe = tree.on("gadget_complete", (event) => {
|
|
1619
|
+
* if (event.type === "gadget_complete") {
|
|
1620
|
+
* console.log(`Gadget ${event.name} completed`);
|
|
1621
|
+
* }
|
|
1622
|
+
* });
|
|
1623
|
+
* ```
|
|
1624
|
+
*/
|
|
1625
|
+
on(type, listener) {
|
|
1626
|
+
if (!this.eventListeners.has(type)) {
|
|
1627
|
+
this.eventListeners.set(type, /* @__PURE__ */ new Set());
|
|
1628
|
+
}
|
|
1629
|
+
const listeners = this.eventListeners.get(type);
|
|
1630
|
+
listeners.add(listener);
|
|
1631
|
+
return () => {
|
|
1632
|
+
listeners.delete(listener);
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* Subscribe to all events.
|
|
1637
|
+
*/
|
|
1638
|
+
onAll(listener) {
|
|
1639
|
+
return this.on("*", listener);
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* Get async iterable of all events.
|
|
1643
|
+
* Events are yielded as they occur.
|
|
1644
|
+
*/
|
|
1645
|
+
async *events() {
|
|
1646
|
+
while (!this.isCompleted) {
|
|
1647
|
+
while (this.eventQueue.length > 0) {
|
|
1648
|
+
yield this.eventQueue.shift();
|
|
1649
|
+
}
|
|
1650
|
+
if (this.isCompleted) break;
|
|
1651
|
+
const event = await new Promise((resolve) => {
|
|
1652
|
+
if (this.eventQueue.length > 0) {
|
|
1653
|
+
resolve(this.eventQueue.shift());
|
|
1654
|
+
} else {
|
|
1655
|
+
this.eventWaiters.push(resolve);
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
yield event;
|
|
1659
|
+
}
|
|
1660
|
+
while (this.eventQueue.length > 0) {
|
|
1661
|
+
yield this.eventQueue.shift();
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Mark the tree as complete (no more events will be emitted).
|
|
1666
|
+
*/
|
|
1667
|
+
complete() {
|
|
1668
|
+
this.isCompleted = true;
|
|
1669
|
+
for (const waiter of this.eventWaiters) {
|
|
1670
|
+
}
|
|
1671
|
+
this.eventWaiters = [];
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* Check if the tree is complete.
|
|
1675
|
+
*/
|
|
1676
|
+
isComplete() {
|
|
1677
|
+
return this.isCompleted;
|
|
1678
|
+
}
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
});
|
|
1682
|
+
|
|
1075
1683
|
// src/gadgets/media-store.ts
|
|
1076
1684
|
import { randomBytes } from "node:crypto";
|
|
1077
1685
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
@@ -2367,8 +2975,8 @@ var init_conversation_manager = __esm({
|
|
|
2367
2975
|
addAssistantMessage(content) {
|
|
2368
2976
|
this.historyBuilder.addAssistant(content);
|
|
2369
2977
|
}
|
|
2370
|
-
addGadgetCallResult(gadgetName, parameters, result, media, mediaIds) {
|
|
2371
|
-
this.historyBuilder.addGadgetCallResult(gadgetName, parameters, result, media, mediaIds);
|
|
2978
|
+
addGadgetCallResult(gadgetName, parameters, result, invocationId, media, mediaIds) {
|
|
2979
|
+
this.historyBuilder.addGadgetCallResult(gadgetName, parameters, result, invocationId, media, mediaIds);
|
|
2372
2980
|
}
|
|
2373
2981
|
getMessages() {
|
|
2374
2982
|
return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];
|
|
@@ -3536,20 +4144,65 @@ var init_parser = __esm({
|
|
|
3536
4144
|
}
|
|
3537
4145
|
});
|
|
3538
4146
|
|
|
4147
|
+
// src/gadgets/typed-gadget.ts
|
|
4148
|
+
function Gadget(config) {
|
|
4149
|
+
class GadgetBase extends AbstractGadget {
|
|
4150
|
+
description = config.description;
|
|
4151
|
+
parameterSchema = config.schema;
|
|
4152
|
+
name = config.name;
|
|
4153
|
+
timeoutMs = config.timeoutMs;
|
|
4154
|
+
examples = config.examples;
|
|
4155
|
+
/**
|
|
4156
|
+
* Type helper property for accessing inferred parameter type.
|
|
4157
|
+
* This is used in the execute method signature: `execute(params: this['params'])`
|
|
4158
|
+
*
|
|
4159
|
+
* Note: This is just for type inference - the actual params in execute()
|
|
4160
|
+
* will be Record<string, unknown> which you can safely cast to this['params']
|
|
4161
|
+
*/
|
|
4162
|
+
params;
|
|
4163
|
+
}
|
|
4164
|
+
return GadgetBase;
|
|
4165
|
+
}
|
|
4166
|
+
var init_typed_gadget = __esm({
|
|
4167
|
+
"src/gadgets/typed-gadget.ts"() {
|
|
4168
|
+
"use strict";
|
|
4169
|
+
init_gadget();
|
|
4170
|
+
}
|
|
4171
|
+
});
|
|
4172
|
+
|
|
3539
4173
|
// src/gadgets/executor.ts
|
|
3540
|
-
|
|
4174
|
+
import { z as z4 } from "zod";
|
|
4175
|
+
function getHostExportsInternal() {
|
|
4176
|
+
if (!cachedHostExports) {
|
|
4177
|
+
cachedHostExports = {
|
|
4178
|
+
AgentBuilder,
|
|
4179
|
+
Gadget,
|
|
4180
|
+
createGadget,
|
|
4181
|
+
ExecutionTree,
|
|
4182
|
+
LLMist,
|
|
4183
|
+
z: z4
|
|
4184
|
+
};
|
|
4185
|
+
}
|
|
4186
|
+
return cachedHostExports;
|
|
4187
|
+
}
|
|
4188
|
+
var cachedHostExports, GadgetExecutor;
|
|
3541
4189
|
var init_executor = __esm({
|
|
3542
4190
|
"src/gadgets/executor.ts"() {
|
|
3543
4191
|
"use strict";
|
|
4192
|
+
init_builder();
|
|
4193
|
+
init_client();
|
|
3544
4194
|
init_constants();
|
|
4195
|
+
init_execution_tree();
|
|
3545
4196
|
init_logger();
|
|
3546
4197
|
init_block_params();
|
|
3547
4198
|
init_cost_reporting_client();
|
|
4199
|
+
init_create_gadget();
|
|
3548
4200
|
init_error_formatter();
|
|
3549
4201
|
init_exceptions();
|
|
3550
4202
|
init_parser();
|
|
4203
|
+
init_typed_gadget();
|
|
3551
4204
|
GadgetExecutor = class {
|
|
3552
|
-
constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig, onSubagentEvent) {
|
|
4205
|
+
constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig, onSubagentEvent, tree, parentNodeId, baseDepth) {
|
|
3553
4206
|
this.registry = registry;
|
|
3554
4207
|
this.requestHumanInput = requestHumanInput;
|
|
3555
4208
|
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
@@ -3558,6 +4211,9 @@ var init_executor = __esm({
|
|
|
3558
4211
|
this.agentConfig = agentConfig;
|
|
3559
4212
|
this.subagentConfig = subagentConfig;
|
|
3560
4213
|
this.onSubagentEvent = onSubagentEvent;
|
|
4214
|
+
this.tree = tree;
|
|
4215
|
+
this.parentNodeId = parentNodeId;
|
|
4216
|
+
this.baseDepth = baseDepth;
|
|
3561
4217
|
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
3562
4218
|
this.errorFormatter = new GadgetExecutionErrorFormatter(errorFormatterOptions);
|
|
3563
4219
|
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
@@ -3568,15 +4224,21 @@ var init_executor = __esm({
|
|
|
3568
4224
|
/**
|
|
3569
4225
|
* Creates a promise that rejects with a TimeoutException after the specified timeout.
|
|
3570
4226
|
* Aborts the provided AbortController before rejecting, allowing gadgets to clean up.
|
|
4227
|
+
* Returns both the promise and a cancel function to clear the timeout when no longer needed.
|
|
3571
4228
|
*/
|
|
3572
4229
|
createTimeoutPromise(gadgetName, timeoutMs, abortController) {
|
|
3573
|
-
|
|
3574
|
-
|
|
4230
|
+
let timeoutId;
|
|
4231
|
+
const promise = new Promise((_, reject) => {
|
|
4232
|
+
timeoutId = setTimeout(() => {
|
|
3575
4233
|
const timeoutError = new TimeoutException(gadgetName, timeoutMs);
|
|
3576
4234
|
abortController.abort(timeoutError.message);
|
|
3577
4235
|
reject(timeoutError);
|
|
3578
4236
|
}, timeoutMs);
|
|
3579
4237
|
});
|
|
4238
|
+
return {
|
|
4239
|
+
promise,
|
|
4240
|
+
cancel: () => clearTimeout(timeoutId)
|
|
4241
|
+
};
|
|
3580
4242
|
}
|
|
3581
4243
|
/**
|
|
3582
4244
|
* Unify gadget execute result to consistent internal format.
|
|
@@ -3698,6 +4360,8 @@ var init_executor = __esm({
|
|
|
3698
4360
|
});
|
|
3699
4361
|
}
|
|
3700
4362
|
};
|
|
4363
|
+
const gadgetNodeId = this.tree?.getNodeByInvocationId(call.invocationId)?.id;
|
|
4364
|
+
const gadgetDepth = gadgetNodeId ? this.tree?.getNode(gadgetNodeId)?.depth ?? this.baseDepth : this.baseDepth;
|
|
3701
4365
|
const ctx = {
|
|
3702
4366
|
reportCost,
|
|
3703
4367
|
llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
|
|
@@ -3705,7 +4369,13 @@ var init_executor = __esm({
|
|
|
3705
4369
|
agentConfig: this.agentConfig,
|
|
3706
4370
|
subagentConfig: this.subagentConfig,
|
|
3707
4371
|
invocationId: call.invocationId,
|
|
3708
|
-
onSubagentEvent: this.onSubagentEvent
|
|
4372
|
+
onSubagentEvent: this.onSubagentEvent,
|
|
4373
|
+
// Tree context for subagent support - use gadget's own node ID
|
|
4374
|
+
tree: this.tree,
|
|
4375
|
+
nodeId: gadgetNodeId,
|
|
4376
|
+
depth: gadgetDepth,
|
|
4377
|
+
// Host exports for external gadgets to use host's llmist classes
|
|
4378
|
+
hostExports: getHostExportsInternal()
|
|
3709
4379
|
};
|
|
3710
4380
|
let rawResult;
|
|
3711
4381
|
if (timeoutMs && timeoutMs > 0) {
|
|
@@ -3713,10 +4383,15 @@ var init_executor = __esm({
|
|
|
3713
4383
|
gadgetName: call.gadgetName,
|
|
3714
4384
|
timeoutMs
|
|
3715
4385
|
});
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
4386
|
+
const timeout = this.createTimeoutPromise(call.gadgetName, timeoutMs, abortController);
|
|
4387
|
+
try {
|
|
4388
|
+
rawResult = await Promise.race([
|
|
4389
|
+
Promise.resolve(gadget.execute(validatedParameters, ctx)),
|
|
4390
|
+
timeout.promise
|
|
4391
|
+
]);
|
|
4392
|
+
} finally {
|
|
4393
|
+
timeout.cancel();
|
|
4394
|
+
}
|
|
3720
4395
|
} else {
|
|
3721
4396
|
rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
|
|
3722
4397
|
}
|
|
@@ -3911,10 +4586,11 @@ var init_stream_processor = __esm({
|
|
|
3911
4586
|
logger;
|
|
3912
4587
|
parser;
|
|
3913
4588
|
executor;
|
|
3914
|
-
|
|
3915
|
-
|
|
4589
|
+
// Execution Tree context
|
|
4590
|
+
tree;
|
|
4591
|
+
parentNodeId;
|
|
4592
|
+
baseDepth;
|
|
3916
4593
|
responseText = "";
|
|
3917
|
-
executionHalted = false;
|
|
3918
4594
|
observerFailureCount = 0;
|
|
3919
4595
|
// Dependency tracking for gadget execution DAG
|
|
3920
4596
|
/** Gadgets waiting for their dependencies to complete */
|
|
@@ -3925,18 +4601,28 @@ var init_stream_processor = __esm({
|
|
|
3925
4601
|
failedInvocations = /* @__PURE__ */ new Set();
|
|
3926
4602
|
/** Promises for independent gadgets currently executing (fire-and-forget) */
|
|
3927
4603
|
inFlightExecutions = /* @__PURE__ */ new Map();
|
|
4604
|
+
/** Queue of completed gadget results ready to be yielded (for real-time streaming) */
|
|
4605
|
+
completedResultsQueue = [];
|
|
3928
4606
|
constructor(options) {
|
|
3929
4607
|
this.iteration = options.iteration;
|
|
3930
4608
|
this.registry = options.registry;
|
|
3931
4609
|
this.hooks = options.hooks ?? {};
|
|
3932
4610
|
this.logger = options.logger ?? createLogger({ name: "llmist:stream-processor" });
|
|
3933
|
-
this.
|
|
3934
|
-
this.
|
|
4611
|
+
this.tree = options.tree;
|
|
4612
|
+
this.parentNodeId = options.parentNodeId ?? null;
|
|
4613
|
+
this.baseDepth = options.baseDepth ?? 0;
|
|
3935
4614
|
this.parser = new GadgetCallParser({
|
|
3936
4615
|
startPrefix: options.gadgetStartPrefix,
|
|
3937
4616
|
endPrefix: options.gadgetEndPrefix,
|
|
3938
4617
|
argPrefix: options.gadgetArgPrefix
|
|
3939
4618
|
});
|
|
4619
|
+
const wrappedOnSubagentEvent = options.onSubagentEvent ? (event) => {
|
|
4620
|
+
this.completedResultsQueue.push({
|
|
4621
|
+
type: "subagent_event",
|
|
4622
|
+
subagentEvent: event
|
|
4623
|
+
});
|
|
4624
|
+
options.onSubagentEvent?.(event);
|
|
4625
|
+
} : void 0;
|
|
3940
4626
|
this.executor = new GadgetExecutor(
|
|
3941
4627
|
options.registry,
|
|
3942
4628
|
options.requestHumanInput,
|
|
@@ -3947,7 +4633,11 @@ var init_stream_processor = __esm({
|
|
|
3947
4633
|
options.mediaStore,
|
|
3948
4634
|
options.agentConfig,
|
|
3949
4635
|
options.subagentConfig,
|
|
3950
|
-
|
|
4636
|
+
wrappedOnSubagentEvent,
|
|
4637
|
+
// Tree context for gadget execution
|
|
4638
|
+
options.tree,
|
|
4639
|
+
options.parentNodeId,
|
|
4640
|
+
options.baseDepth
|
|
3951
4641
|
);
|
|
3952
4642
|
}
|
|
3953
4643
|
/**
|
|
@@ -3998,7 +4688,7 @@ var init_stream_processor = __esm({
|
|
|
3998
4688
|
usage,
|
|
3999
4689
|
logger: this.logger
|
|
4000
4690
|
};
|
|
4001
|
-
await this.hooks.observers
|
|
4691
|
+
await this.hooks.observers?.onStreamChunk?.(context);
|
|
4002
4692
|
});
|
|
4003
4693
|
await this.runObserversInParallel(chunkObservers);
|
|
4004
4694
|
}
|
|
@@ -4016,25 +4706,7 @@ var init_stream_processor = __esm({
|
|
|
4016
4706
|
}
|
|
4017
4707
|
}
|
|
4018
4708
|
}
|
|
4019
|
-
|
|
4020
|
-
this.logger.info("Breaking from LLM stream due to gadget error");
|
|
4021
|
-
break;
|
|
4022
|
-
}
|
|
4023
|
-
}
|
|
4024
|
-
if (!this.executionHalted) {
|
|
4025
|
-
for (const event of this.parser.finalize()) {
|
|
4026
|
-
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
4027
|
-
yield processedEvent;
|
|
4028
|
-
if (processedEvent.type === "gadget_result") {
|
|
4029
|
-
didExecuteGadgets = true;
|
|
4030
|
-
if (processedEvent.result.breaksLoop) {
|
|
4031
|
-
shouldBreakLoop = true;
|
|
4032
|
-
}
|
|
4033
|
-
}
|
|
4034
|
-
}
|
|
4035
|
-
}
|
|
4036
|
-
const inFlightResults = await this.collectInFlightResults();
|
|
4037
|
-
for (const evt of inFlightResults) {
|
|
4709
|
+
for (const evt of this.drainCompletedResults()) {
|
|
4038
4710
|
yield evt;
|
|
4039
4711
|
if (evt.type === "gadget_result") {
|
|
4040
4712
|
didExecuteGadgets = true;
|
|
@@ -4043,16 +4715,45 @@ var init_stream_processor = __esm({
|
|
|
4043
4715
|
}
|
|
4044
4716
|
}
|
|
4045
4717
|
}
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4718
|
+
}
|
|
4719
|
+
for (const event of this.parser.finalize()) {
|
|
4720
|
+
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
4721
|
+
yield processedEvent;
|
|
4722
|
+
if (processedEvent.type === "gadget_result") {
|
|
4049
4723
|
didExecuteGadgets = true;
|
|
4050
|
-
if (
|
|
4724
|
+
if (processedEvent.result.breaksLoop) {
|
|
4051
4725
|
shouldBreakLoop = true;
|
|
4052
4726
|
}
|
|
4053
4727
|
}
|
|
4054
4728
|
}
|
|
4055
4729
|
}
|
|
4730
|
+
for await (const evt of this.waitForInFlightExecutions()) {
|
|
4731
|
+
yield evt;
|
|
4732
|
+
if (evt.type === "gadget_result") {
|
|
4733
|
+
didExecuteGadgets = true;
|
|
4734
|
+
if (evt.result.breaksLoop) {
|
|
4735
|
+
shouldBreakLoop = true;
|
|
4736
|
+
}
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
for (const evt of this.drainCompletedResults()) {
|
|
4740
|
+
yield evt;
|
|
4741
|
+
if (evt.type === "gadget_result") {
|
|
4742
|
+
didExecuteGadgets = true;
|
|
4743
|
+
if (evt.result.breaksLoop) {
|
|
4744
|
+
shouldBreakLoop = true;
|
|
4745
|
+
}
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4749
|
+
yield evt;
|
|
4750
|
+
if (evt.type === "gadget_result") {
|
|
4751
|
+
didExecuteGadgets = true;
|
|
4752
|
+
if (evt.result.breaksLoop) {
|
|
4753
|
+
shouldBreakLoop = true;
|
|
4754
|
+
}
|
|
4755
|
+
}
|
|
4756
|
+
}
|
|
4056
4757
|
let finalMessage = this.responseText;
|
|
4057
4758
|
if (this.hooks.interceptors?.interceptAssistantMessage) {
|
|
4058
4759
|
const context = {
|
|
@@ -4073,21 +4774,8 @@ var init_stream_processor = __esm({
|
|
|
4073
4774
|
};
|
|
4074
4775
|
yield completionEvent;
|
|
4075
4776
|
}
|
|
4076
|
-
/**
|
|
4077
|
-
* Process a single parsed event (text or gadget call).
|
|
4078
|
-
* @deprecated Use processEventGenerator for real-time streaming
|
|
4079
|
-
*/
|
|
4080
|
-
async processEvent(event) {
|
|
4081
|
-
if (event.type === "text") {
|
|
4082
|
-
return this.processTextEvent(event);
|
|
4083
|
-
} else if (event.type === "gadget_call") {
|
|
4084
|
-
return this.processGadgetCall(event.call);
|
|
4085
|
-
}
|
|
4086
|
-
return [event];
|
|
4087
|
-
}
|
|
4088
4777
|
/**
|
|
4089
4778
|
* Process a single parsed event, yielding events in real-time.
|
|
4090
|
-
* Generator version of processEvent for streaming support.
|
|
4091
4779
|
*/
|
|
4092
4780
|
async *processEventGenerator(event) {
|
|
4093
4781
|
if (event.type === "text") {
|
|
@@ -4129,12 +4817,6 @@ var init_stream_processor = __esm({
|
|
|
4129
4817
|
* After each execution, pending gadgets are checked to see if they can now run.
|
|
4130
4818
|
*/
|
|
4131
4819
|
async processGadgetCall(call) {
|
|
4132
|
-
if (this.executionHalted) {
|
|
4133
|
-
this.logger.debug("Skipping gadget execution due to previous error", {
|
|
4134
|
-
gadgetName: call.gadgetName
|
|
4135
|
-
});
|
|
4136
|
-
return [];
|
|
4137
|
-
}
|
|
4138
4820
|
const events = [];
|
|
4139
4821
|
events.push({ type: "gadget_call", call });
|
|
4140
4822
|
if (call.dependencies.length > 0) {
|
|
@@ -4185,13 +4867,16 @@ var init_stream_processor = __esm({
|
|
|
4185
4867
|
* when parsed (before execution), enabling real-time UI feedback.
|
|
4186
4868
|
*/
|
|
4187
4869
|
async *processGadgetCallGenerator(call) {
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4870
|
+
yield { type: "gadget_call", call };
|
|
4871
|
+
if (this.tree) {
|
|
4872
|
+
this.tree.addGadget({
|
|
4873
|
+
invocationId: call.invocationId,
|
|
4874
|
+
name: call.gadgetName,
|
|
4875
|
+
parameters: call.parameters ?? {},
|
|
4876
|
+
dependencies: call.dependencies,
|
|
4877
|
+
parentId: this.parentNodeId
|
|
4191
4878
|
});
|
|
4192
|
-
return;
|
|
4193
4879
|
}
|
|
4194
|
-
yield { type: "gadget_call", call };
|
|
4195
4880
|
if (call.dependencies.length > 0) {
|
|
4196
4881
|
if (call.dependencies.includes(call.invocationId)) {
|
|
4197
4882
|
this.logger.warn("Gadget has self-referential dependency (depends on itself)", {
|
|
@@ -4236,17 +4921,8 @@ var init_stream_processor = __esm({
|
|
|
4236
4921
|
}
|
|
4237
4922
|
return;
|
|
4238
4923
|
}
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
yield evt;
|
|
4242
|
-
}
|
|
4243
|
-
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4244
|
-
yield evt;
|
|
4245
|
-
}
|
|
4246
|
-
} else {
|
|
4247
|
-
const executionPromise = this.executeGadgetAndCollect(call);
|
|
4248
|
-
this.inFlightExecutions.set(call.invocationId, executionPromise);
|
|
4249
|
-
}
|
|
4924
|
+
const executionPromise = this.executeGadgetAndCollect(call);
|
|
4925
|
+
this.inFlightExecutions.set(call.invocationId, executionPromise);
|
|
4250
4926
|
}
|
|
4251
4927
|
/**
|
|
4252
4928
|
* Execute a gadget through the full hook lifecycle.
|
|
@@ -4261,15 +4937,6 @@ var init_stream_processor = __esm({
|
|
|
4261
4937
|
error: call.parseError,
|
|
4262
4938
|
rawParameters: call.parametersRaw
|
|
4263
4939
|
});
|
|
4264
|
-
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4265
|
-
call.parseError,
|
|
4266
|
-
call.gadgetName,
|
|
4267
|
-
"parse",
|
|
4268
|
-
call.parameters
|
|
4269
|
-
);
|
|
4270
|
-
if (!shouldContinue) {
|
|
4271
|
-
this.executionHalted = true;
|
|
4272
|
-
}
|
|
4273
4940
|
}
|
|
4274
4941
|
let parameters = call.parameters ?? {};
|
|
4275
4942
|
if (this.hooks.interceptors?.interceptGadgetParameters) {
|
|
@@ -4312,7 +4979,7 @@ var init_stream_processor = __esm({
|
|
|
4312
4979
|
parameters,
|
|
4313
4980
|
logger: this.logger
|
|
4314
4981
|
};
|
|
4315
|
-
await this.hooks.observers
|
|
4982
|
+
await this.hooks.observers?.onGadgetExecutionStart?.(context);
|
|
4316
4983
|
});
|
|
4317
4984
|
}
|
|
4318
4985
|
await this.runObserversInParallel(startObservers);
|
|
@@ -4381,7 +5048,7 @@ var init_stream_processor = __esm({
|
|
|
4381
5048
|
cost: result.cost,
|
|
4382
5049
|
logger: this.logger
|
|
4383
5050
|
};
|
|
4384
|
-
await this.hooks.observers
|
|
5051
|
+
await this.hooks.observers?.onGadgetExecutionComplete?.(context);
|
|
4385
5052
|
});
|
|
4386
5053
|
}
|
|
4387
5054
|
await this.runObserversInParallel(completeObservers);
|
|
@@ -4390,18 +5057,6 @@ var init_stream_processor = __esm({
|
|
|
4390
5057
|
this.failedInvocations.add(result.invocationId);
|
|
4391
5058
|
}
|
|
4392
5059
|
events.push({ type: "gadget_result", result });
|
|
4393
|
-
if (result.error) {
|
|
4394
|
-
const errorType = this.determineErrorType(call, result);
|
|
4395
|
-
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4396
|
-
result.error,
|
|
4397
|
-
result.gadgetName,
|
|
4398
|
-
errorType,
|
|
4399
|
-
result.parameters
|
|
4400
|
-
);
|
|
4401
|
-
if (!shouldContinue) {
|
|
4402
|
-
this.executionHalted = true;
|
|
4403
|
-
}
|
|
4404
|
-
}
|
|
4405
5060
|
return events;
|
|
4406
5061
|
}
|
|
4407
5062
|
/**
|
|
@@ -4415,15 +5070,6 @@ var init_stream_processor = __esm({
|
|
|
4415
5070
|
error: call.parseError,
|
|
4416
5071
|
rawParameters: call.parametersRaw
|
|
4417
5072
|
});
|
|
4418
|
-
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4419
|
-
call.parseError,
|
|
4420
|
-
call.gadgetName,
|
|
4421
|
-
"parse",
|
|
4422
|
-
call.parameters
|
|
4423
|
-
);
|
|
4424
|
-
if (!shouldContinue) {
|
|
4425
|
-
this.executionHalted = true;
|
|
4426
|
-
}
|
|
4427
5073
|
}
|
|
4428
5074
|
let parameters = call.parameters ?? {};
|
|
4429
5075
|
if (this.hooks.interceptors?.interceptGadgetParameters) {
|
|
@@ -4466,10 +5112,16 @@ var init_stream_processor = __esm({
|
|
|
4466
5112
|
parameters,
|
|
4467
5113
|
logger: this.logger
|
|
4468
5114
|
};
|
|
4469
|
-
await this.hooks.observers
|
|
5115
|
+
await this.hooks.observers?.onGadgetExecutionStart?.(context);
|
|
4470
5116
|
});
|
|
4471
5117
|
}
|
|
4472
5118
|
await this.runObserversInParallel(startObservers);
|
|
5119
|
+
if (this.tree) {
|
|
5120
|
+
const gadgetNode = this.tree.getNodeByInvocationId(call.invocationId);
|
|
5121
|
+
if (gadgetNode) {
|
|
5122
|
+
this.tree.startGadget(gadgetNode.id);
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
4473
5125
|
let result;
|
|
4474
5126
|
if (shouldSkip) {
|
|
4475
5127
|
result = {
|
|
@@ -4535,57 +5187,84 @@ var init_stream_processor = __esm({
|
|
|
4535
5187
|
cost: result.cost,
|
|
4536
5188
|
logger: this.logger
|
|
4537
5189
|
};
|
|
4538
|
-
await this.hooks.observers
|
|
5190
|
+
await this.hooks.observers?.onGadgetExecutionComplete?.(context);
|
|
4539
5191
|
});
|
|
4540
5192
|
}
|
|
4541
5193
|
await this.runObserversInParallel(completeObservers);
|
|
5194
|
+
if (this.tree) {
|
|
5195
|
+
const gadgetNode = this.tree.getNodeByInvocationId(result.invocationId);
|
|
5196
|
+
if (gadgetNode) {
|
|
5197
|
+
if (result.error) {
|
|
5198
|
+
this.tree.completeGadget(gadgetNode.id, {
|
|
5199
|
+
error: result.error,
|
|
5200
|
+
executionTimeMs: result.executionTimeMs,
|
|
5201
|
+
cost: result.cost
|
|
5202
|
+
});
|
|
5203
|
+
} else {
|
|
5204
|
+
this.tree.completeGadget(gadgetNode.id, {
|
|
5205
|
+
result: result.result,
|
|
5206
|
+
executionTimeMs: result.executionTimeMs,
|
|
5207
|
+
cost: result.cost,
|
|
5208
|
+
media: result.media
|
|
5209
|
+
});
|
|
5210
|
+
}
|
|
5211
|
+
}
|
|
5212
|
+
}
|
|
4542
5213
|
this.completedResults.set(result.invocationId, result);
|
|
4543
5214
|
if (result.error) {
|
|
4544
5215
|
this.failedInvocations.add(result.invocationId);
|
|
4545
5216
|
}
|
|
4546
5217
|
yield { type: "gadget_result", result };
|
|
4547
|
-
if (result.error) {
|
|
4548
|
-
const errorType = this.determineErrorType(call, result);
|
|
4549
|
-
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4550
|
-
result.error,
|
|
4551
|
-
result.gadgetName,
|
|
4552
|
-
errorType,
|
|
4553
|
-
result.parameters
|
|
4554
|
-
);
|
|
4555
|
-
if (!shouldContinue) {
|
|
4556
|
-
this.executionHalted = true;
|
|
4557
|
-
}
|
|
4558
|
-
}
|
|
4559
5218
|
}
|
|
4560
5219
|
/**
|
|
4561
|
-
* Execute a gadget and
|
|
5220
|
+
* Execute a gadget and push events to the completed results queue (non-blocking).
|
|
4562
5221
|
* Used for fire-and-forget parallel execution of independent gadgets.
|
|
5222
|
+
* Results are pushed to completedResultsQueue for real-time streaming to the caller.
|
|
4563
5223
|
*/
|
|
4564
5224
|
async executeGadgetAndCollect(call) {
|
|
4565
|
-
const events = [];
|
|
4566
5225
|
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4567
|
-
|
|
5226
|
+
this.completedResultsQueue.push(evt);
|
|
5227
|
+
}
|
|
5228
|
+
}
|
|
5229
|
+
/**
|
|
5230
|
+
* Drain all completed results from the queue.
|
|
5231
|
+
* Used to yield results as they complete during stream processing.
|
|
5232
|
+
* @returns Generator that yields all events currently in the queue
|
|
5233
|
+
*/
|
|
5234
|
+
*drainCompletedResults() {
|
|
5235
|
+
while (this.completedResultsQueue.length > 0) {
|
|
5236
|
+
yield this.completedResultsQueue.shift();
|
|
4568
5237
|
}
|
|
4569
|
-
return events;
|
|
4570
5238
|
}
|
|
4571
5239
|
/**
|
|
4572
|
-
*
|
|
4573
|
-
* Called at stream end to
|
|
4574
|
-
*
|
|
4575
|
-
*
|
|
5240
|
+
* Wait for all in-flight gadget executions to complete, yielding events in real-time.
|
|
5241
|
+
* Called at stream end to ensure all parallel executions finish.
|
|
5242
|
+
* Results and subagent events are pushed to completedResultsQueue during execution.
|
|
5243
|
+
* This generator yields queued events while polling, enabling real-time display
|
|
5244
|
+
* of subagent activity (LLM calls, nested gadgets) during long-running gadgets.
|
|
5245
|
+
* Clears the inFlightExecutions map after all gadgets complete.
|
|
4576
5246
|
*/
|
|
4577
|
-
async
|
|
5247
|
+
async *waitForInFlightExecutions() {
|
|
4578
5248
|
if (this.inFlightExecutions.size === 0) {
|
|
4579
|
-
return
|
|
5249
|
+
return;
|
|
4580
5250
|
}
|
|
4581
|
-
this.logger.debug("
|
|
5251
|
+
this.logger.debug("Waiting for in-flight gadget executions", {
|
|
4582
5252
|
count: this.inFlightExecutions.size,
|
|
4583
5253
|
invocationIds: Array.from(this.inFlightExecutions.keys())
|
|
4584
5254
|
});
|
|
4585
|
-
const
|
|
4586
|
-
const
|
|
5255
|
+
const allDone = Promise.all(this.inFlightExecutions.values()).then(() => "done");
|
|
5256
|
+
const POLL_INTERVAL_MS = 100;
|
|
5257
|
+
while (true) {
|
|
5258
|
+
const result = await Promise.race([
|
|
5259
|
+
allDone,
|
|
5260
|
+
new Promise((resolve) => setTimeout(() => resolve("poll"), POLL_INTERVAL_MS))
|
|
5261
|
+
]);
|
|
5262
|
+
yield* this.drainCompletedResults();
|
|
5263
|
+
if (result === "done") {
|
|
5264
|
+
break;
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
4587
5267
|
this.inFlightExecutions.clear();
|
|
4588
|
-
return results.flat();
|
|
4589
5268
|
}
|
|
4590
5269
|
/**
|
|
4591
5270
|
* Handle a gadget that cannot execute because a dependency failed.
|
|
@@ -4610,6 +5289,12 @@ var init_stream_processor = __esm({
|
|
|
4610
5289
|
}
|
|
4611
5290
|
if (action.action === "skip") {
|
|
4612
5291
|
this.failedInvocations.add(call.invocationId);
|
|
5292
|
+
if (this.tree) {
|
|
5293
|
+
const gadgetNode = this.tree.getNodeByInvocationId(call.invocationId);
|
|
5294
|
+
if (gadgetNode) {
|
|
5295
|
+
this.tree.skipGadget(gadgetNode.id, failedDep, depError, "dependency_failed");
|
|
5296
|
+
}
|
|
5297
|
+
}
|
|
4613
5298
|
const skipEvent = {
|
|
4614
5299
|
type: "gadget_skipped",
|
|
4615
5300
|
gadgetName: call.gadgetName,
|
|
@@ -4629,7 +5314,7 @@ var init_stream_processor = __esm({
|
|
|
4629
5314
|
failedDependencyError: depError,
|
|
4630
5315
|
logger: this.logger
|
|
4631
5316
|
};
|
|
4632
|
-
await this.safeObserve(() => this.hooks.observers
|
|
5317
|
+
await this.safeObserve(() => this.hooks.observers?.onGadgetSkipped?.(observeContext));
|
|
4633
5318
|
}
|
|
4634
5319
|
this.logger.info("Gadget skipped due to failed dependency", {
|
|
4635
5320
|
gadgetName: call.gadgetName,
|
|
@@ -4861,48 +5546,6 @@ var init_stream_processor = __esm({
|
|
|
4861
5546
|
observers.map((observer) => this.safeObserve(observer))
|
|
4862
5547
|
);
|
|
4863
5548
|
}
|
|
4864
|
-
/**
|
|
4865
|
-
* Check if execution can recover from an error.
|
|
4866
|
-
*
|
|
4867
|
-
* Returns true if we should continue processing subsequent gadgets, false if we should stop.
|
|
4868
|
-
*
|
|
4869
|
-
* Logic:
|
|
4870
|
-
* - If custom canRecoverFromGadgetError is provided, use it
|
|
4871
|
-
* - Otherwise, use stopOnGadgetError config:
|
|
4872
|
-
* - stopOnGadgetError=true → return false (stop execution)
|
|
4873
|
-
* - stopOnGadgetError=false → return true (continue execution)
|
|
4874
|
-
*/
|
|
4875
|
-
async checkCanRecoverFromError(error, gadgetName, errorType, parameters) {
|
|
4876
|
-
if (this.canRecoverFromGadgetError) {
|
|
4877
|
-
return await this.canRecoverFromGadgetError({
|
|
4878
|
-
error,
|
|
4879
|
-
gadgetName,
|
|
4880
|
-
errorType,
|
|
4881
|
-
parameters
|
|
4882
|
-
});
|
|
4883
|
-
}
|
|
4884
|
-
const shouldContinue = !this.stopOnGadgetError;
|
|
4885
|
-
this.logger.debug("Checking if should continue after error", {
|
|
4886
|
-
error,
|
|
4887
|
-
gadgetName,
|
|
4888
|
-
errorType,
|
|
4889
|
-
stopOnGadgetError: this.stopOnGadgetError,
|
|
4890
|
-
shouldContinue
|
|
4891
|
-
});
|
|
4892
|
-
return shouldContinue;
|
|
4893
|
-
}
|
|
4894
|
-
/**
|
|
4895
|
-
* Determine the type of error from a gadget execution.
|
|
4896
|
-
*/
|
|
4897
|
-
determineErrorType(call, result) {
|
|
4898
|
-
if (call.parseError) {
|
|
4899
|
-
return "parse";
|
|
4900
|
-
}
|
|
4901
|
-
if (result.error?.includes("Invalid parameters:")) {
|
|
4902
|
-
return "validation";
|
|
4903
|
-
}
|
|
4904
|
-
return "execution";
|
|
4905
|
-
}
|
|
4906
5549
|
};
|
|
4907
5550
|
}
|
|
4908
5551
|
});
|
|
@@ -4913,6 +5556,7 @@ var init_agent = __esm({
|
|
|
4913
5556
|
"src/agent/agent.ts"() {
|
|
4914
5557
|
"use strict";
|
|
4915
5558
|
init_constants();
|
|
5559
|
+
init_execution_tree();
|
|
4916
5560
|
init_messages();
|
|
4917
5561
|
init_model_shortcuts();
|
|
4918
5562
|
init_media_store();
|
|
@@ -4940,8 +5584,6 @@ var init_agent = __esm({
|
|
|
4940
5584
|
requestHumanInput;
|
|
4941
5585
|
textOnlyHandler;
|
|
4942
5586
|
textWithGadgetsHandler;
|
|
4943
|
-
stopOnGadgetError;
|
|
4944
|
-
canRecoverFromGadgetError;
|
|
4945
5587
|
defaultGadgetTimeoutMs;
|
|
4946
5588
|
defaultMaxTokens;
|
|
4947
5589
|
hasUserPrompt;
|
|
@@ -4964,6 +5606,12 @@ var init_agent = __esm({
|
|
|
4964
5606
|
pendingSubagentEvents = [];
|
|
4965
5607
|
// Combined callback that queues events AND calls user callback
|
|
4966
5608
|
onSubagentEvent;
|
|
5609
|
+
// Counter for generating synthetic invocation IDs for wrapped text content
|
|
5610
|
+
syntheticInvocationCounter = 0;
|
|
5611
|
+
// Execution Tree - first-class model for nested subagent support
|
|
5612
|
+
tree;
|
|
5613
|
+
parentNodeId;
|
|
5614
|
+
baseDepth;
|
|
4967
5615
|
/**
|
|
4968
5616
|
* Creates a new Agent instance.
|
|
4969
5617
|
* @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
|
|
@@ -4986,8 +5634,6 @@ var init_agent = __esm({
|
|
|
4986
5634
|
this.requestHumanInput = options.requestHumanInput;
|
|
4987
5635
|
this.textOnlyHandler = options.textOnlyHandler ?? "terminate";
|
|
4988
5636
|
this.textWithGadgetsHandler = options.textWithGadgetsHandler;
|
|
4989
|
-
this.stopOnGadgetError = options.stopOnGadgetError ?? true;
|
|
4990
|
-
this.canRecoverFromGadgetError = options.canRecoverFromGadgetError;
|
|
4991
5637
|
this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
|
|
4992
5638
|
this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
|
|
4993
5639
|
this.outputLimitEnabled = options.gadgetOutputLimit ?? DEFAULT_GADGET_OUTPUT_LIMIT;
|
|
@@ -5041,6 +5687,9 @@ var init_agent = __esm({
|
|
|
5041
5687
|
temperature: this.temperature
|
|
5042
5688
|
};
|
|
5043
5689
|
this.subagentConfig = options.subagentConfig;
|
|
5690
|
+
this.tree = options.parentTree ?? new ExecutionTree();
|
|
5691
|
+
this.parentNodeId = options.parentNodeId ?? null;
|
|
5692
|
+
this.baseDepth = options.baseDepth ?? 0;
|
|
5044
5693
|
this.userSubagentEventCallback = options.onSubagentEvent;
|
|
5045
5694
|
this.onSubagentEvent = (event) => {
|
|
5046
5695
|
this.pendingSubagentEvents.push(event);
|
|
@@ -5105,7 +5754,9 @@ var init_agent = __esm({
|
|
|
5105
5754
|
*flushPendingSubagentEvents() {
|
|
5106
5755
|
while (this.pendingSubagentEvents.length > 0) {
|
|
5107
5756
|
const event = this.pendingSubagentEvents.shift();
|
|
5108
|
-
|
|
5757
|
+
if (event) {
|
|
5758
|
+
yield { type: "subagent_event", subagentEvent: event };
|
|
5759
|
+
}
|
|
5109
5760
|
}
|
|
5110
5761
|
}
|
|
5111
5762
|
/**
|
|
@@ -5159,6 +5810,48 @@ var init_agent = __esm({
|
|
|
5159
5810
|
getMediaStore() {
|
|
5160
5811
|
return this.mediaStore;
|
|
5161
5812
|
}
|
|
5813
|
+
/**
|
|
5814
|
+
* Get the execution tree for this agent.
|
|
5815
|
+
*
|
|
5816
|
+
* The execution tree provides a first-class model of all LLM calls and gadget executions,
|
|
5817
|
+
* including nested subagent activity. Use this to:
|
|
5818
|
+
* - Query execution state: `tree.getNode(id)`
|
|
5819
|
+
* - Get total cost: `tree.getTotalCost()`
|
|
5820
|
+
* - Get subtree cost/media/tokens: `tree.getSubtreeCost(nodeId)`
|
|
5821
|
+
* - Subscribe to events: `tree.on("llm_call_complete", handler)`
|
|
5822
|
+
* - Stream all events: `for await (const event of tree.events())`
|
|
5823
|
+
*
|
|
5824
|
+
* For subagents (created with `withParentContext`), the tree is shared with the parent,
|
|
5825
|
+
* enabling unified tracking and real-time visibility across all nesting levels.
|
|
5826
|
+
*
|
|
5827
|
+
* @returns The ExecutionTree instance
|
|
5828
|
+
*
|
|
5829
|
+
* @example
|
|
5830
|
+
* ```typescript
|
|
5831
|
+
* const agent = LLMist.createAgent()
|
|
5832
|
+
* .withModel("sonnet")
|
|
5833
|
+
* .withGadgets(BrowseWeb)
|
|
5834
|
+
* .ask("Research topic X");
|
|
5835
|
+
*
|
|
5836
|
+
* for await (const event of agent.run()) {
|
|
5837
|
+
* // Process events...
|
|
5838
|
+
* }
|
|
5839
|
+
*
|
|
5840
|
+
* // After execution, query the tree
|
|
5841
|
+
* const tree = agent.getTree();
|
|
5842
|
+
* console.log(`Total cost: $${tree.getTotalCost().toFixed(4)}`);
|
|
5843
|
+
*
|
|
5844
|
+
* // Inspect all LLM calls
|
|
5845
|
+
* for (const node of tree.getAllNodes()) {
|
|
5846
|
+
* if (node.type === "llm_call") {
|
|
5847
|
+
* console.log(`LLM #${node.iteration}: ${node.model}`);
|
|
5848
|
+
* }
|
|
5849
|
+
* }
|
|
5850
|
+
* ```
|
|
5851
|
+
*/
|
|
5852
|
+
getTree() {
|
|
5853
|
+
return this.tree;
|
|
5854
|
+
}
|
|
5162
5855
|
/**
|
|
5163
5856
|
* Manually trigger context compaction.
|
|
5164
5857
|
*
|
|
@@ -5260,6 +5953,7 @@ var init_agent = __esm({
|
|
|
5260
5953
|
await this.hooks.observers.onCompaction({
|
|
5261
5954
|
iteration: currentIteration,
|
|
5262
5955
|
event: compactionEvent,
|
|
5956
|
+
// biome-ignore lint/style/noNonNullAssertion: compactionManager exists if compactionEvent is truthy
|
|
5263
5957
|
stats: this.compactionManager.getStats(),
|
|
5264
5958
|
logger: this.logger
|
|
5265
5959
|
});
|
|
@@ -5321,6 +6015,13 @@ var init_agent = __esm({
|
|
|
5321
6015
|
messageCount: llmOptions.messages.length,
|
|
5322
6016
|
messages: llmOptions.messages
|
|
5323
6017
|
});
|
|
6018
|
+
const llmNode = this.tree.addLLMCall({
|
|
6019
|
+
iteration: currentIteration,
|
|
6020
|
+
model: llmOptions.model,
|
|
6021
|
+
parentId: this.parentNodeId,
|
|
6022
|
+
request: llmOptions.messages
|
|
6023
|
+
});
|
|
6024
|
+
const currentLLMNodeId = llmNode.id;
|
|
5324
6025
|
const stream2 = this.client.stream(llmOptions);
|
|
5325
6026
|
const processor = new StreamProcessor({
|
|
5326
6027
|
iteration: currentIteration,
|
|
@@ -5331,14 +6032,17 @@ var init_agent = __esm({
|
|
|
5331
6032
|
hooks: this.hooks,
|
|
5332
6033
|
logger: this.logger.getSubLogger({ name: "stream-processor" }),
|
|
5333
6034
|
requestHumanInput: this.requestHumanInput,
|
|
5334
|
-
stopOnGadgetError: this.stopOnGadgetError,
|
|
5335
|
-
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
5336
6035
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
5337
6036
|
client: this.client,
|
|
5338
6037
|
mediaStore: this.mediaStore,
|
|
5339
6038
|
agentConfig: this.agentContextConfig,
|
|
5340
6039
|
subagentConfig: this.subagentConfig,
|
|
5341
|
-
onSubagentEvent: this.onSubagentEvent
|
|
6040
|
+
onSubagentEvent: this.onSubagentEvent,
|
|
6041
|
+
// Tree context for execution tracking
|
|
6042
|
+
tree: this.tree,
|
|
6043
|
+
parentNodeId: currentLLMNodeId,
|
|
6044
|
+
// Gadgets are children of this LLM call
|
|
6045
|
+
baseDepth: this.baseDepth
|
|
5342
6046
|
});
|
|
5343
6047
|
let streamMetadata = null;
|
|
5344
6048
|
let gadgetCallCount = 0;
|
|
@@ -5384,6 +6088,11 @@ var init_agent = __esm({
|
|
|
5384
6088
|
await this.hooks.observers.onLLMCallComplete(context);
|
|
5385
6089
|
}
|
|
5386
6090
|
});
|
|
6091
|
+
this.tree.completeLLMCall(currentLLMNodeId, {
|
|
6092
|
+
response: result.rawResponse,
|
|
6093
|
+
usage: result.usage,
|
|
6094
|
+
finishReason: result.finishReason
|
|
6095
|
+
});
|
|
5387
6096
|
let finalMessage = result.finalMessage;
|
|
5388
6097
|
if (this.hooks.controllers?.afterLLMCall) {
|
|
5389
6098
|
const context = {
|
|
@@ -5418,10 +6127,12 @@ var init_agent = __esm({
|
|
|
5418
6127
|
const textContent = textOutputs.join("");
|
|
5419
6128
|
if (textContent.trim()) {
|
|
5420
6129
|
const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
|
|
6130
|
+
const syntheticId = `gc_text_${++this.syntheticInvocationCounter}`;
|
|
5421
6131
|
this.conversation.addGadgetCallResult(
|
|
5422
6132
|
gadgetName,
|
|
5423
6133
|
parameterMapping(textContent),
|
|
5424
|
-
resultMapping ? resultMapping(textContent) : textContent
|
|
6134
|
+
resultMapping ? resultMapping(textContent) : textContent,
|
|
6135
|
+
syntheticId
|
|
5425
6136
|
);
|
|
5426
6137
|
}
|
|
5427
6138
|
}
|
|
@@ -5432,6 +6143,7 @@ var init_agent = __esm({
|
|
|
5432
6143
|
gadgetResult.gadgetName,
|
|
5433
6144
|
gadgetResult.parameters,
|
|
5434
6145
|
gadgetResult.error ?? gadgetResult.result ?? "",
|
|
6146
|
+
gadgetResult.invocationId,
|
|
5435
6147
|
gadgetResult.media,
|
|
5436
6148
|
gadgetResult.mediaIds
|
|
5437
6149
|
);
|
|
@@ -5439,10 +6151,12 @@ var init_agent = __esm({
|
|
|
5439
6151
|
}
|
|
5440
6152
|
} else {
|
|
5441
6153
|
if (finalMessage.trim()) {
|
|
6154
|
+
const syntheticId = `gc_tell_${++this.syntheticInvocationCounter}`;
|
|
5442
6155
|
this.conversation.addGadgetCallResult(
|
|
5443
6156
|
"TellUser",
|
|
5444
6157
|
{ message: finalMessage, done: false, type: "info" },
|
|
5445
|
-
`\u2139\uFE0F ${finalMessage}
|
|
6158
|
+
`\u2139\uFE0F ${finalMessage}`,
|
|
6159
|
+
syntheticId
|
|
5446
6160
|
);
|
|
5447
6161
|
}
|
|
5448
6162
|
const shouldBreak = await this.handleTextOnlyResponse(finalMessage);
|
|
@@ -5653,8 +6367,6 @@ var init_builder = __esm({
|
|
|
5653
6367
|
gadgetArgPrefix;
|
|
5654
6368
|
textOnlyHandler;
|
|
5655
6369
|
textWithGadgetsHandler;
|
|
5656
|
-
stopOnGadgetError;
|
|
5657
|
-
canRecoverFromGadgetError;
|
|
5658
6370
|
defaultGadgetTimeoutMs;
|
|
5659
6371
|
gadgetOutputLimit;
|
|
5660
6372
|
gadgetOutputLimitPercent;
|
|
@@ -5663,6 +6375,8 @@ var init_builder = __esm({
|
|
|
5663
6375
|
trailingMessage;
|
|
5664
6376
|
subagentConfig;
|
|
5665
6377
|
subagentEventCallback;
|
|
6378
|
+
// Tree context for subagent support - enables shared tree model
|
|
6379
|
+
// When a gadget calls withParentContext(ctx), it shares the parent's tree
|
|
5666
6380
|
parentContext;
|
|
5667
6381
|
constructor(client) {
|
|
5668
6382
|
this.client = client;
|
|
@@ -5945,62 +6659,6 @@ var init_builder = __esm({
|
|
|
5945
6659
|
this.textWithGadgetsHandler = handler;
|
|
5946
6660
|
return this;
|
|
5947
6661
|
}
|
|
5948
|
-
/**
|
|
5949
|
-
* Set whether to stop gadget execution on first error.
|
|
5950
|
-
*
|
|
5951
|
-
* When true (default), if a gadget fails:
|
|
5952
|
-
* - Subsequent gadgets in the same response are skipped
|
|
5953
|
-
* - LLM stream is cancelled to save costs
|
|
5954
|
-
* - Agent loop continues with error in context
|
|
5955
|
-
*
|
|
5956
|
-
* When false:
|
|
5957
|
-
* - All gadgets in the response still execute
|
|
5958
|
-
* - LLM stream continues to completion
|
|
5959
|
-
*
|
|
5960
|
-
* @param stop - Whether to stop on gadget error
|
|
5961
|
-
* @returns This builder for chaining
|
|
5962
|
-
*
|
|
5963
|
-
* @example
|
|
5964
|
-
* ```typescript
|
|
5965
|
-
* .withStopOnGadgetError(false)
|
|
5966
|
-
* ```
|
|
5967
|
-
*/
|
|
5968
|
-
withStopOnGadgetError(stop) {
|
|
5969
|
-
this.stopOnGadgetError = stop;
|
|
5970
|
-
return this;
|
|
5971
|
-
}
|
|
5972
|
-
/**
|
|
5973
|
-
* Set custom error handling logic.
|
|
5974
|
-
*
|
|
5975
|
-
* Provides fine-grained control over whether to continue after different types of errors.
|
|
5976
|
-
* Overrides `stopOnGadgetError` when provided.
|
|
5977
|
-
*
|
|
5978
|
-
* **Note:** This builder method configures the underlying `canRecoverFromGadgetError` option
|
|
5979
|
-
* in `AgentOptions`. The method is named `withErrorHandler` for better developer experience,
|
|
5980
|
-
* but maps to the `canRecoverFromGadgetError` property internally.
|
|
5981
|
-
*
|
|
5982
|
-
* @param handler - Function that decides whether to continue after an error.
|
|
5983
|
-
* Return `true` to continue execution, `false` to stop.
|
|
5984
|
-
* @returns This builder for chaining
|
|
5985
|
-
*
|
|
5986
|
-
* @example
|
|
5987
|
-
* ```typescript
|
|
5988
|
-
* .withErrorHandler((context) => {
|
|
5989
|
-
* // Stop on parse errors, continue on validation/execution errors
|
|
5990
|
-
* if (context.errorType === "parse") {
|
|
5991
|
-
* return false;
|
|
5992
|
-
* }
|
|
5993
|
-
* if (context.error.includes("CRITICAL")) {
|
|
5994
|
-
* return false;
|
|
5995
|
-
* }
|
|
5996
|
-
* return true;
|
|
5997
|
-
* })
|
|
5998
|
-
* ```
|
|
5999
|
-
*/
|
|
6000
|
-
withErrorHandler(handler) {
|
|
6001
|
-
this.canRecoverFromGadgetError = handler;
|
|
6002
|
-
return this;
|
|
6003
|
-
}
|
|
6004
6662
|
/**
|
|
6005
6663
|
* Set default timeout for gadget execution.
|
|
6006
6664
|
*
|
|
@@ -6195,6 +6853,15 @@ var init_builder = __esm({
|
|
|
6195
6853
|
* The method extracts `invocationId` and `onSubagentEvent` from the execution
|
|
6196
6854
|
* context and sets up automatic forwarding via hooks and event wrapping.
|
|
6197
6855
|
*
|
|
6856
|
+
* **NEW: Shared Tree Model** - When the parent provides an ExecutionTree via context,
|
|
6857
|
+
* the subagent shares that tree instead of creating its own. This enables:
|
|
6858
|
+
* - Unified cost tracking across all nesting levels
|
|
6859
|
+
* - Automatic media aggregation via `tree.getSubtreeMedia(nodeId)`
|
|
6860
|
+
* - Real-time visibility of nested execution in the parent
|
|
6861
|
+
*
|
|
6862
|
+
* **Signal Forwarding** - When parent context includes a signal, it's automatically
|
|
6863
|
+
* forwarded to the subagent for proper cancellation propagation.
|
|
6864
|
+
*
|
|
6198
6865
|
* @param ctx - ExecutionContext passed to the gadget's execute() method
|
|
6199
6866
|
* @param depth - Nesting depth (default: 1 for direct child)
|
|
6200
6867
|
* @returns This builder for chaining
|
|
@@ -6215,17 +6882,25 @@ var init_builder = __esm({
|
|
|
6215
6882
|
* result = event.content;
|
|
6216
6883
|
* }
|
|
6217
6884
|
* }
|
|
6885
|
+
*
|
|
6886
|
+
* // After subagent completes, costs are automatically aggregated
|
|
6887
|
+
* // No manual tracking needed - use tree methods:
|
|
6888
|
+
* const totalCost = ctx.tree?.getSubtreeCost(ctx.nodeId!);
|
|
6889
|
+
* const allMedia = ctx.tree?.getSubtreeMedia(ctx.nodeId!);
|
|
6218
6890
|
* }
|
|
6219
6891
|
* ```
|
|
6220
6892
|
*/
|
|
6221
6893
|
withParentContext(ctx, depth = 1) {
|
|
6222
|
-
if (ctx.
|
|
6894
|
+
if (ctx.tree) {
|
|
6223
6895
|
this.parentContext = {
|
|
6224
|
-
|
|
6225
|
-
|
|
6896
|
+
tree: ctx.tree,
|
|
6897
|
+
nodeId: ctx.nodeId,
|
|
6226
6898
|
depth
|
|
6227
6899
|
};
|
|
6228
6900
|
}
|
|
6901
|
+
if (ctx.signal && !this.signal) {
|
|
6902
|
+
this.signal = ctx.signal;
|
|
6903
|
+
}
|
|
6229
6904
|
return this;
|
|
6230
6905
|
}
|
|
6231
6906
|
/**
|
|
@@ -6258,11 +6933,13 @@ var init_builder = __esm({
|
|
|
6258
6933
|
*
|
|
6259
6934
|
* This is useful for in-context learning - showing the LLM what "past self"
|
|
6260
6935
|
* did correctly so it mimics the pattern. The call is formatted with proper
|
|
6261
|
-
* markers and parameter format
|
|
6936
|
+
* markers and parameter format, including the invocation ID so the LLM can
|
|
6937
|
+
* reference previous calls when building dependencies.
|
|
6262
6938
|
*
|
|
6263
6939
|
* @param gadgetName - Name of the gadget
|
|
6264
6940
|
* @param parameters - Parameters passed to the gadget
|
|
6265
6941
|
* @param result - Result returned by the gadget
|
|
6942
|
+
* @param invocationId - Invocation ID (shown to LLM so it can reference for dependencies)
|
|
6266
6943
|
* @returns This builder for chaining
|
|
6267
6944
|
*
|
|
6268
6945
|
* @example
|
|
@@ -6274,124 +6951,36 @@ var init_builder = __esm({
|
|
|
6274
6951
|
* done: false,
|
|
6275
6952
|
* type: 'info'
|
|
6276
6953
|
* },
|
|
6277
|
-
* 'ℹ️ 👋 Hello!\n\nHere\'s what I can do:\n- Analyze code\n- Run commands'
|
|
6954
|
+
* 'ℹ️ 👋 Hello!\n\nHere\'s what I can do:\n- Analyze code\n- Run commands',
|
|
6955
|
+
* 'gc_1'
|
|
6278
6956
|
* )
|
|
6279
6957
|
* ```
|
|
6280
6958
|
*/
|
|
6281
|
-
withSyntheticGadgetCall(gadgetName, parameters, result) {
|
|
6959
|
+
withSyntheticGadgetCall(gadgetName, parameters, result, invocationId) {
|
|
6282
6960
|
const startPrefix = this.gadgetStartPrefix ?? GADGET_START_PREFIX;
|
|
6283
6961
|
const endPrefix = this.gadgetEndPrefix ?? GADGET_END_PREFIX;
|
|
6284
6962
|
const paramStr = this.formatBlockParameters(parameters, "");
|
|
6285
6963
|
this.initialMessages.push({
|
|
6286
6964
|
role: "assistant",
|
|
6287
|
-
content: `${startPrefix}${gadgetName}
|
|
6965
|
+
content: `${startPrefix}${gadgetName}:${invocationId}
|
|
6288
6966
|
${paramStr}
|
|
6289
6967
|
${endPrefix}`
|
|
6290
6968
|
});
|
|
6291
6969
|
this.initialMessages.push({
|
|
6292
6970
|
role: "user",
|
|
6293
|
-
content: `Result: ${result}`
|
|
6971
|
+
content: `Result (${invocationId}): ${result}`
|
|
6294
6972
|
});
|
|
6295
6973
|
return this;
|
|
6296
6974
|
}
|
|
6297
6975
|
/**
|
|
6298
|
-
* Compose the final hooks, including
|
|
6299
|
-
*
|
|
6300
|
-
*
|
|
6976
|
+
* Compose the final hooks, including trailing message injection if configured.
|
|
6977
|
+
*
|
|
6978
|
+
* Note: Subagent event visibility is now handled entirely by the ExecutionTree.
|
|
6979
|
+
* When a subagent uses withParentContext(ctx), it shares the parent's tree,
|
|
6980
|
+
* and all events are automatically visible to tree subscribers (like the TUI).
|
|
6301
6981
|
*/
|
|
6302
6982
|
composeHooks() {
|
|
6303
|
-
|
|
6304
|
-
if (this.parentContext) {
|
|
6305
|
-
const { invocationId, onSubagentEvent, depth } = this.parentContext;
|
|
6306
|
-
const existingOnLLMCallStart = hooks?.observers?.onLLMCallStart;
|
|
6307
|
-
const existingOnLLMCallComplete = hooks?.observers?.onLLMCallComplete;
|
|
6308
|
-
const existingOnGadgetExecutionStart = hooks?.observers?.onGadgetExecutionStart;
|
|
6309
|
-
const existingOnGadgetExecutionComplete = hooks?.observers?.onGadgetExecutionComplete;
|
|
6310
|
-
hooks = {
|
|
6311
|
-
...hooks,
|
|
6312
|
-
observers: {
|
|
6313
|
-
...hooks?.observers,
|
|
6314
|
-
onLLMCallStart: async (context) => {
|
|
6315
|
-
let inputTokens;
|
|
6316
|
-
try {
|
|
6317
|
-
if (this.client) {
|
|
6318
|
-
inputTokens = await this.client.countTokens(
|
|
6319
|
-
context.options.model,
|
|
6320
|
-
context.options.messages
|
|
6321
|
-
);
|
|
6322
|
-
}
|
|
6323
|
-
} catch {
|
|
6324
|
-
}
|
|
6325
|
-
onSubagentEvent({
|
|
6326
|
-
type: "llm_call_start",
|
|
6327
|
-
gadgetInvocationId: invocationId,
|
|
6328
|
-
depth,
|
|
6329
|
-
event: {
|
|
6330
|
-
iteration: context.iteration,
|
|
6331
|
-
model: context.options.model,
|
|
6332
|
-
inputTokens
|
|
6333
|
-
}
|
|
6334
|
-
});
|
|
6335
|
-
if (existingOnLLMCallStart) {
|
|
6336
|
-
await existingOnLLMCallStart(context);
|
|
6337
|
-
}
|
|
6338
|
-
},
|
|
6339
|
-
onLLMCallComplete: async (context) => {
|
|
6340
|
-
onSubagentEvent({
|
|
6341
|
-
type: "llm_call_end",
|
|
6342
|
-
gadgetInvocationId: invocationId,
|
|
6343
|
-
depth,
|
|
6344
|
-
event: {
|
|
6345
|
-
iteration: context.iteration,
|
|
6346
|
-
model: context.options.model,
|
|
6347
|
-
// Backward compat fields
|
|
6348
|
-
inputTokens: context.usage?.inputTokens,
|
|
6349
|
-
outputTokens: context.usage?.outputTokens,
|
|
6350
|
-
finishReason: context.finishReason ?? void 0,
|
|
6351
|
-
// Full usage object with cache details (for first-class display)
|
|
6352
|
-
usage: context.usage
|
|
6353
|
-
// Cost will be calculated by parent if it has model registry
|
|
6354
|
-
}
|
|
6355
|
-
});
|
|
6356
|
-
if (existingOnLLMCallComplete) {
|
|
6357
|
-
await existingOnLLMCallComplete(context);
|
|
6358
|
-
}
|
|
6359
|
-
},
|
|
6360
|
-
onGadgetExecutionStart: async (context) => {
|
|
6361
|
-
onSubagentEvent({
|
|
6362
|
-
type: "gadget_call",
|
|
6363
|
-
gadgetInvocationId: invocationId,
|
|
6364
|
-
depth,
|
|
6365
|
-
event: {
|
|
6366
|
-
call: {
|
|
6367
|
-
invocationId: context.invocationId,
|
|
6368
|
-
gadgetName: context.gadgetName,
|
|
6369
|
-
parameters: context.parameters
|
|
6370
|
-
}
|
|
6371
|
-
}
|
|
6372
|
-
});
|
|
6373
|
-
if (existingOnGadgetExecutionStart) {
|
|
6374
|
-
await existingOnGadgetExecutionStart(context);
|
|
6375
|
-
}
|
|
6376
|
-
},
|
|
6377
|
-
onGadgetExecutionComplete: async (context) => {
|
|
6378
|
-
onSubagentEvent({
|
|
6379
|
-
type: "gadget_result",
|
|
6380
|
-
gadgetInvocationId: invocationId,
|
|
6381
|
-
depth,
|
|
6382
|
-
event: {
|
|
6383
|
-
result: {
|
|
6384
|
-
invocationId: context.invocationId
|
|
6385
|
-
}
|
|
6386
|
-
}
|
|
6387
|
-
});
|
|
6388
|
-
if (existingOnGadgetExecutionComplete) {
|
|
6389
|
-
await existingOnGadgetExecutionComplete(context);
|
|
6390
|
-
}
|
|
6391
|
-
}
|
|
6392
|
-
}
|
|
6393
|
-
};
|
|
6394
|
-
}
|
|
6983
|
+
const hooks = this.hooks;
|
|
6395
6984
|
if (!this.trailingMessage) {
|
|
6396
6985
|
return hooks;
|
|
6397
6986
|
}
|
|
@@ -6474,19 +7063,6 @@ ${endPrefix}`
|
|
|
6474
7063
|
this.client = new LLMistClass();
|
|
6475
7064
|
}
|
|
6476
7065
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
6477
|
-
let onSubagentEvent = this.subagentEventCallback;
|
|
6478
|
-
if (this.parentContext) {
|
|
6479
|
-
const { invocationId, onSubagentEvent: parentCallback, depth } = this.parentContext;
|
|
6480
|
-
const existingCallback = this.subagentEventCallback;
|
|
6481
|
-
onSubagentEvent = (event) => {
|
|
6482
|
-
parentCallback({
|
|
6483
|
-
...event,
|
|
6484
|
-
gadgetInvocationId: invocationId,
|
|
6485
|
-
depth: event.depth + depth
|
|
6486
|
-
});
|
|
6487
|
-
existingCallback?.(event);
|
|
6488
|
-
};
|
|
6489
|
-
}
|
|
6490
7066
|
return {
|
|
6491
7067
|
client: this.client,
|
|
6492
7068
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -6505,15 +7081,17 @@ ${endPrefix}`
|
|
|
6505
7081
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
6506
7082
|
textOnlyHandler: this.textOnlyHandler,
|
|
6507
7083
|
textWithGadgetsHandler: this.textWithGadgetsHandler,
|
|
6508
|
-
stopOnGadgetError: this.stopOnGadgetError,
|
|
6509
|
-
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
6510
7084
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
6511
7085
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
6512
7086
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
6513
7087
|
compactionConfig: this.compactionConfig,
|
|
6514
7088
|
signal: this.signal,
|
|
6515
7089
|
subagentConfig: this.subagentConfig,
|
|
6516
|
-
onSubagentEvent
|
|
7090
|
+
onSubagentEvent: this.subagentEventCallback,
|
|
7091
|
+
// Tree context for shared tree model (subagents share parent's tree)
|
|
7092
|
+
parentTree: this.parentContext?.tree,
|
|
7093
|
+
parentNodeId: this.parentContext?.nodeId,
|
|
7094
|
+
baseDepth: this.parentContext ? (this.parentContext.depth ?? 0) + 1 : 0
|
|
6517
7095
|
};
|
|
6518
7096
|
}
|
|
6519
7097
|
ask(userPrompt) {
|
|
@@ -6670,19 +7248,6 @@ ${endPrefix}`
|
|
|
6670
7248
|
this.client = new LLMistClass();
|
|
6671
7249
|
}
|
|
6672
7250
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
6673
|
-
let onSubagentEvent = this.subagentEventCallback;
|
|
6674
|
-
if (this.parentContext) {
|
|
6675
|
-
const { invocationId, onSubagentEvent: parentCallback, depth } = this.parentContext;
|
|
6676
|
-
const existingCallback = this.subagentEventCallback;
|
|
6677
|
-
onSubagentEvent = (event) => {
|
|
6678
|
-
parentCallback({
|
|
6679
|
-
...event,
|
|
6680
|
-
gadgetInvocationId: invocationId,
|
|
6681
|
-
depth: event.depth + depth
|
|
6682
|
-
});
|
|
6683
|
-
existingCallback?.(event);
|
|
6684
|
-
};
|
|
6685
|
-
}
|
|
6686
7251
|
const options = {
|
|
6687
7252
|
client: this.client,
|
|
6688
7253
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -6701,15 +7266,17 @@ ${endPrefix}`
|
|
|
6701
7266
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
6702
7267
|
textOnlyHandler: this.textOnlyHandler,
|
|
6703
7268
|
textWithGadgetsHandler: this.textWithGadgetsHandler,
|
|
6704
|
-
stopOnGadgetError: this.stopOnGadgetError,
|
|
6705
|
-
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
6706
7269
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
6707
7270
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
6708
7271
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
6709
7272
|
compactionConfig: this.compactionConfig,
|
|
6710
7273
|
signal: this.signal,
|
|
6711
7274
|
subagentConfig: this.subagentConfig,
|
|
6712
|
-
onSubagentEvent
|
|
7275
|
+
onSubagentEvent: this.subagentEventCallback,
|
|
7276
|
+
// Tree context for shared tree model (subagents share parent's tree)
|
|
7277
|
+
parentTree: this.parentContext?.tree,
|
|
7278
|
+
parentNodeId: this.parentContext?.nodeId,
|
|
7279
|
+
baseDepth: this.parentContext ? (this.parentContext.depth ?? 0) + 1 : 0
|
|
6713
7280
|
};
|
|
6714
7281
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
6715
7282
|
}
|
|
@@ -11297,16 +11864,16 @@ var MockConversationManager = class {
|
|
|
11297
11864
|
this.history.push(msg);
|
|
11298
11865
|
this.addedMessages.push(msg);
|
|
11299
11866
|
}
|
|
11300
|
-
addGadgetCallResult(gadgetName, parameters, result) {
|
|
11867
|
+
addGadgetCallResult(gadgetName, parameters, result, invocationId) {
|
|
11301
11868
|
const assistantMsg = {
|
|
11302
11869
|
role: "assistant",
|
|
11303
|
-
content: `!!!GADGET_START:${gadgetName}
|
|
11870
|
+
content: `!!!GADGET_START:${gadgetName}:${invocationId}
|
|
11304
11871
|
${JSON.stringify(parameters)}
|
|
11305
11872
|
!!!GADGET_END`
|
|
11306
11873
|
};
|
|
11307
11874
|
const resultMsg = {
|
|
11308
11875
|
role: "user",
|
|
11309
|
-
content: `Result: ${result}`
|
|
11876
|
+
content: `Result (${invocationId}): ${result}`
|
|
11310
11877
|
};
|
|
11311
11878
|
this.history.push(assistantMsg);
|
|
11312
11879
|
this.history.push(resultMsg);
|
|
@@ -11654,6 +12221,8 @@ export {
|
|
|
11654
12221
|
init_schema_validator,
|
|
11655
12222
|
GadgetRegistry,
|
|
11656
12223
|
init_registry,
|
|
12224
|
+
ExecutionTree,
|
|
12225
|
+
init_execution_tree,
|
|
11657
12226
|
DEFAULT_HINTS,
|
|
11658
12227
|
DEFAULT_PROMPTS,
|
|
11659
12228
|
resolvePromptTemplate,
|
|
@@ -11700,12 +12269,6 @@ export {
|
|
|
11700
12269
|
init_event_handlers,
|
|
11701
12270
|
GadgetOutputStore,
|
|
11702
12271
|
init_gadget_output_store,
|
|
11703
|
-
GadgetCallParser,
|
|
11704
|
-
init_parser,
|
|
11705
|
-
GadgetExecutor,
|
|
11706
|
-
init_executor,
|
|
11707
|
-
StreamProcessor,
|
|
11708
|
-
init_stream_processor,
|
|
11709
12272
|
FALLBACK_CHARS_PER_TOKEN,
|
|
11710
12273
|
init_constants2 as init_constants,
|
|
11711
12274
|
AnthropicMessagesProvider,
|
|
@@ -11728,6 +12291,14 @@ export {
|
|
|
11728
12291
|
init_options,
|
|
11729
12292
|
LLMist,
|
|
11730
12293
|
init_client,
|
|
12294
|
+
GadgetCallParser,
|
|
12295
|
+
init_parser,
|
|
12296
|
+
Gadget,
|
|
12297
|
+
init_typed_gadget,
|
|
12298
|
+
GadgetExecutor,
|
|
12299
|
+
init_executor,
|
|
12300
|
+
StreamProcessor,
|
|
12301
|
+
init_stream_processor,
|
|
11731
12302
|
AgentBuilder,
|
|
11732
12303
|
init_builder,
|
|
11733
12304
|
validateAndApplyDefaults,
|
|
@@ -11772,4 +12343,4 @@ export {
|
|
|
11772
12343
|
createEmptyStream,
|
|
11773
12344
|
createErrorStream
|
|
11774
12345
|
};
|
|
11775
|
-
//# sourceMappingURL=chunk-
|
|
12346
|
+
//# sourceMappingURL=chunk-36YSBSGB.js.map
|