llmist 2.6.0 → 3.1.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 +10 -1
- package/dist/{chunk-364PEMVT.js → chunk-JCFPJMRQ.js} +754 -218
- package/dist/chunk-JCFPJMRQ.js.map +1 -0
- package/dist/{chunk-4IHLIYW5.js → chunk-LFI4WQVV.js} +6 -6
- package/dist/chunk-LFI4WQVV.js.map +1 -0
- package/dist/cli.cjs +1458 -279
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +702 -58
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +763 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +139 -54
- package/dist/index.d.ts +139 -54
- package/dist/index.js +20 -18
- package/dist/{mock-stream-Jgg5u6Uf.d.cts → mock-stream-CTLm00_q.d.cts} +344 -56
- package/dist/{mock-stream-Jgg5u6Uf.d.ts → mock-stream-CTLm00_q.d.ts} +344 -56
- package/dist/testing/index.cjs +745 -210
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +6 -6
- package/dist/testing/index.d.ts +6 -6
- package/dist/testing/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-364PEMVT.js.map +0 -1
- package/dist/chunk-4IHLIYW5.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -566,13 +566,13 @@ var init_prompt_config = __esm({
|
|
|
566
566
|
});
|
|
567
567
|
|
|
568
568
|
// src/core/messages.ts
|
|
569
|
-
function
|
|
569
|
+
function normalizeMessageContent(content) {
|
|
570
570
|
if (typeof content === "string") {
|
|
571
571
|
return [{ type: "text", text: content }];
|
|
572
572
|
}
|
|
573
573
|
return content;
|
|
574
574
|
}
|
|
575
|
-
function
|
|
575
|
+
function extractMessageText(content) {
|
|
576
576
|
if (typeof content === "string") {
|
|
577
577
|
return content;
|
|
578
578
|
}
|
|
@@ -932,7 +932,17 @@ Produces: { "items": ["first", "second"] }`);
|
|
|
932
932
|
this.messages.push({ role: "user", content: parts });
|
|
933
933
|
return this;
|
|
934
934
|
}
|
|
935
|
-
|
|
935
|
+
/**
|
|
936
|
+
* Record a gadget execution result in the message history.
|
|
937
|
+
* Creates an assistant message with the gadget invocation and a user message with the result.
|
|
938
|
+
*
|
|
939
|
+
* @param gadget - Name of the gadget that was executed
|
|
940
|
+
* @param parameters - Parameters that were passed to the gadget
|
|
941
|
+
* @param result - Text result from the gadget execution
|
|
942
|
+
* @param media - Optional media outputs from the gadget
|
|
943
|
+
* @param mediaIds - Optional IDs for the media outputs
|
|
944
|
+
*/
|
|
945
|
+
addGadgetCallResult(gadget, parameters, result, media, mediaIds) {
|
|
936
946
|
const paramStr = this.formatBlockParameters(parameters, "");
|
|
937
947
|
this.messages.push({
|
|
938
948
|
role: "assistant",
|
|
@@ -1200,21 +1210,21 @@ var init_media_store = __esm({
|
|
|
1200
1210
|
});
|
|
1201
1211
|
|
|
1202
1212
|
// src/gadgets/exceptions.ts
|
|
1203
|
-
var
|
|
1213
|
+
var TaskCompletionSignal, HumanInputRequiredException, TimeoutException, AbortException;
|
|
1204
1214
|
var init_exceptions = __esm({
|
|
1205
1215
|
"src/gadgets/exceptions.ts"() {
|
|
1206
1216
|
"use strict";
|
|
1207
|
-
|
|
1217
|
+
TaskCompletionSignal = class extends Error {
|
|
1208
1218
|
constructor(message) {
|
|
1209
1219
|
super(message ?? "Agent loop terminated by gadget");
|
|
1210
|
-
this.name = "
|
|
1220
|
+
this.name = "TaskCompletionSignal";
|
|
1211
1221
|
}
|
|
1212
1222
|
};
|
|
1213
|
-
|
|
1223
|
+
HumanInputRequiredException = class extends Error {
|
|
1214
1224
|
question;
|
|
1215
1225
|
constructor(question) {
|
|
1216
1226
|
super(`Human input required: ${question}`);
|
|
1217
|
-
this.name = "
|
|
1227
|
+
this.name = "HumanInputRequiredException";
|
|
1218
1228
|
this.question = question;
|
|
1219
1229
|
}
|
|
1220
1230
|
};
|
|
@@ -1228,10 +1238,10 @@ var init_exceptions = __esm({
|
|
|
1228
1238
|
this.timeoutMs = timeoutMs;
|
|
1229
1239
|
}
|
|
1230
1240
|
};
|
|
1231
|
-
|
|
1241
|
+
AbortException = class extends Error {
|
|
1232
1242
|
constructor(message) {
|
|
1233
1243
|
super(message || "Gadget execution was aborted");
|
|
1234
|
-
this.name = "
|
|
1244
|
+
this.name = "AbortException";
|
|
1235
1245
|
}
|
|
1236
1246
|
};
|
|
1237
1247
|
}
|
|
@@ -1400,7 +1410,7 @@ var init_schema_to_json = __esm({
|
|
|
1400
1410
|
});
|
|
1401
1411
|
|
|
1402
1412
|
// src/gadgets/gadget.ts
|
|
1403
|
-
function
|
|
1413
|
+
function formatParamsForBlockExample(params, prefix = "", argPrefix = GADGET_ARG_PREFIX) {
|
|
1404
1414
|
const lines = [];
|
|
1405
1415
|
for (const [key, value] of Object.entries(params)) {
|
|
1406
1416
|
const fullPath = prefix ? `${prefix}/${key}` : key;
|
|
@@ -1408,14 +1418,14 @@ function formatParamsAsBlock(params, prefix = "", argPrefix = GADGET_ARG_PREFIX)
|
|
|
1408
1418
|
value.forEach((item, index) => {
|
|
1409
1419
|
const itemPath = `${fullPath}/${index}`;
|
|
1410
1420
|
if (typeof item === "object" && item !== null) {
|
|
1411
|
-
lines.push(
|
|
1421
|
+
lines.push(formatParamsForBlockExample(item, itemPath, argPrefix));
|
|
1412
1422
|
} else {
|
|
1413
1423
|
lines.push(`${argPrefix}${itemPath}`);
|
|
1414
1424
|
lines.push(String(item));
|
|
1415
1425
|
}
|
|
1416
1426
|
});
|
|
1417
1427
|
} else if (typeof value === "object" && value !== null) {
|
|
1418
|
-
lines.push(
|
|
1428
|
+
lines.push(formatParamsForBlockExample(value, fullPath, argPrefix));
|
|
1419
1429
|
} else {
|
|
1420
1430
|
lines.push(`${argPrefix}${fullPath}`);
|
|
1421
1431
|
lines.push(String(value));
|
|
@@ -1504,7 +1514,7 @@ function formatSchemaAsPlainText(schema, indent = "", atRoot = true) {
|
|
|
1504
1514
|
}
|
|
1505
1515
|
return lines.join("\n");
|
|
1506
1516
|
}
|
|
1507
|
-
var
|
|
1517
|
+
var AbstractGadget;
|
|
1508
1518
|
var init_gadget = __esm({
|
|
1509
1519
|
"src/gadgets/gadget.ts"() {
|
|
1510
1520
|
"use strict";
|
|
@@ -1512,7 +1522,7 @@ var init_gadget = __esm({
|
|
|
1512
1522
|
init_exceptions();
|
|
1513
1523
|
init_schema_to_json();
|
|
1514
1524
|
init_schema_validator();
|
|
1515
|
-
|
|
1525
|
+
AbstractGadget = class {
|
|
1516
1526
|
/**
|
|
1517
1527
|
* The name of the gadget. Used for identification when LLM calls it.
|
|
1518
1528
|
* If not provided, defaults to the class name.
|
|
@@ -1540,14 +1550,14 @@ var init_gadget = __esm({
|
|
|
1540
1550
|
*/
|
|
1541
1551
|
examples;
|
|
1542
1552
|
/**
|
|
1543
|
-
* Throws an
|
|
1553
|
+
* Throws an AbortException if the execution has been aborted.
|
|
1544
1554
|
*
|
|
1545
1555
|
* Call this at key checkpoints in long-running gadgets to allow early exit
|
|
1546
1556
|
* when the gadget has been cancelled (e.g., due to timeout). This enables
|
|
1547
1557
|
* resource cleanup and prevents unnecessary work after cancellation.
|
|
1548
1558
|
*
|
|
1549
1559
|
* @param ctx - The execution context containing the abort signal
|
|
1550
|
-
* @throws
|
|
1560
|
+
* @throws AbortException if ctx.signal.aborted is true
|
|
1551
1561
|
*
|
|
1552
1562
|
* @example
|
|
1553
1563
|
* ```typescript
|
|
@@ -1572,7 +1582,7 @@ var init_gadget = __esm({
|
|
|
1572
1582
|
*/
|
|
1573
1583
|
throwIfAborted(ctx) {
|
|
1574
1584
|
if (ctx?.signal?.aborted) {
|
|
1575
|
-
throw new
|
|
1585
|
+
throw new AbortException();
|
|
1576
1586
|
}
|
|
1577
1587
|
}
|
|
1578
1588
|
/**
|
|
@@ -1714,7 +1724,7 @@ var init_gadget = __esm({
|
|
|
1714
1724
|
}
|
|
1715
1725
|
parts.push(`${effectiveStartPrefix}${gadgetName}`);
|
|
1716
1726
|
parts.push(
|
|
1717
|
-
|
|
1727
|
+
formatParamsForBlockExample(example.params, "", effectiveArgPrefix)
|
|
1718
1728
|
);
|
|
1719
1729
|
parts.push(effectiveEndPrefix);
|
|
1720
1730
|
if (example.output !== void 0) {
|
|
@@ -1732,7 +1742,7 @@ var init_gadget = __esm({
|
|
|
1732
1742
|
|
|
1733
1743
|
// src/gadgets/create-gadget.ts
|
|
1734
1744
|
function createGadget(config) {
|
|
1735
|
-
class DynamicGadget extends
|
|
1745
|
+
class DynamicGadget extends AbstractGadget {
|
|
1736
1746
|
name = config.name;
|
|
1737
1747
|
description = config.description;
|
|
1738
1748
|
parameterSchema = config.schema;
|
|
@@ -2370,8 +2380,8 @@ var init_conversation_manager = __esm({
|
|
|
2370
2380
|
addAssistantMessage(content) {
|
|
2371
2381
|
this.historyBuilder.addAssistant(content);
|
|
2372
2382
|
}
|
|
2373
|
-
|
|
2374
|
-
this.historyBuilder.
|
|
2383
|
+
addGadgetCallResult(gadgetName, parameters, result, media, mediaIds) {
|
|
2384
|
+
this.historyBuilder.addGadgetCallResult(gadgetName, parameters, result, media, mediaIds);
|
|
2375
2385
|
}
|
|
2376
2386
|
getMessages() {
|
|
2377
2387
|
return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];
|
|
@@ -2391,7 +2401,7 @@ var init_conversation_manager = __esm({
|
|
|
2391
2401
|
if (msg.role === "user") {
|
|
2392
2402
|
this.historyBuilder.addUser(msg.content);
|
|
2393
2403
|
} else if (msg.role === "assistant") {
|
|
2394
|
-
this.historyBuilder.addAssistant(
|
|
2404
|
+
this.historyBuilder.addAssistant(extractMessageText(msg.content));
|
|
2395
2405
|
}
|
|
2396
2406
|
}
|
|
2397
2407
|
}
|
|
@@ -3271,12 +3281,12 @@ var init_cost_reporting_client = __esm({
|
|
|
3271
3281
|
});
|
|
3272
3282
|
|
|
3273
3283
|
// src/gadgets/error-formatter.ts
|
|
3274
|
-
var
|
|
3284
|
+
var GadgetExecutionErrorFormatter;
|
|
3275
3285
|
var init_error_formatter = __esm({
|
|
3276
3286
|
"src/gadgets/error-formatter.ts"() {
|
|
3277
3287
|
"use strict";
|
|
3278
3288
|
init_constants();
|
|
3279
|
-
|
|
3289
|
+
GadgetExecutionErrorFormatter = class {
|
|
3280
3290
|
argPrefix;
|
|
3281
3291
|
startPrefix;
|
|
3282
3292
|
endPrefix;
|
|
@@ -3362,16 +3372,16 @@ function stripMarkdownFences(content) {
|
|
|
3362
3372
|
cleaned = cleaned.replace(closingFence, "");
|
|
3363
3373
|
return cleaned.trim();
|
|
3364
3374
|
}
|
|
3365
|
-
var globalInvocationCounter,
|
|
3375
|
+
var globalInvocationCounter, GadgetCallParser;
|
|
3366
3376
|
var init_parser = __esm({
|
|
3367
3377
|
"src/gadgets/parser.ts"() {
|
|
3368
3378
|
"use strict";
|
|
3369
3379
|
init_constants();
|
|
3370
3380
|
init_block_params();
|
|
3371
3381
|
globalInvocationCounter = 0;
|
|
3372
|
-
|
|
3382
|
+
GadgetCallParser = class {
|
|
3373
3383
|
buffer = "";
|
|
3374
|
-
|
|
3384
|
+
lastEmittedTextOffset = 0;
|
|
3375
3385
|
startPrefix;
|
|
3376
3386
|
endPrefix;
|
|
3377
3387
|
argPrefix;
|
|
@@ -3380,16 +3390,20 @@ var init_parser = __esm({
|
|
|
3380
3390
|
this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
|
|
3381
3391
|
this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
|
|
3382
3392
|
}
|
|
3383
|
-
|
|
3384
|
-
|
|
3393
|
+
/**
|
|
3394
|
+
* Extract and consume text up to the given index.
|
|
3395
|
+
* Returns undefined if no meaningful text to emit.
|
|
3396
|
+
*/
|
|
3397
|
+
extractTextSegment(index) {
|
|
3398
|
+
if (index <= this.lastEmittedTextOffset) {
|
|
3385
3399
|
return void 0;
|
|
3386
3400
|
}
|
|
3387
|
-
const segment = this.buffer.slice(this.
|
|
3388
|
-
this.
|
|
3401
|
+
const segment = this.buffer.slice(this.lastEmittedTextOffset, index);
|
|
3402
|
+
this.lastEmittedTextOffset = index;
|
|
3389
3403
|
return segment.trim().length > 0 ? segment : void 0;
|
|
3390
3404
|
}
|
|
3391
3405
|
/**
|
|
3392
|
-
* Parse gadget
|
|
3406
|
+
* Parse gadget invocation metadata from the header line.
|
|
3393
3407
|
*
|
|
3394
3408
|
* Supported formats:
|
|
3395
3409
|
* - `GadgetName` - Auto-generate ID, no dependencies
|
|
@@ -3398,24 +3412,24 @@ var init_parser = __esm({
|
|
|
3398
3412
|
*
|
|
3399
3413
|
* Dependencies must be comma-separated invocation IDs.
|
|
3400
3414
|
*/
|
|
3401
|
-
|
|
3402
|
-
const parts =
|
|
3415
|
+
parseInvocationMetadata(headerLine) {
|
|
3416
|
+
const parts = headerLine.split(":");
|
|
3403
3417
|
if (parts.length === 1) {
|
|
3404
3418
|
return {
|
|
3405
|
-
|
|
3419
|
+
gadgetName: parts[0],
|
|
3406
3420
|
invocationId: `gadget_${++globalInvocationCounter}`,
|
|
3407
3421
|
dependencies: []
|
|
3408
3422
|
};
|
|
3409
3423
|
} else if (parts.length === 2) {
|
|
3410
3424
|
return {
|
|
3411
|
-
|
|
3425
|
+
gadgetName: parts[0],
|
|
3412
3426
|
invocationId: parts[1].trim(),
|
|
3413
3427
|
dependencies: []
|
|
3414
3428
|
};
|
|
3415
3429
|
} else {
|
|
3416
3430
|
const deps = parts[2].split(",").map((d) => d.trim()).filter((d) => d.length > 0);
|
|
3417
3431
|
return {
|
|
3418
|
-
|
|
3432
|
+
gadgetName: parts[0],
|
|
3419
3433
|
invocationId: parts[1].trim(),
|
|
3420
3434
|
dependencies: deps
|
|
3421
3435
|
};
|
|
@@ -3447,19 +3461,15 @@ var init_parser = __esm({
|
|
|
3447
3461
|
while (true) {
|
|
3448
3462
|
const partStartIndex = this.buffer.indexOf(this.startPrefix, startIndex);
|
|
3449
3463
|
if (partStartIndex === -1) break;
|
|
3450
|
-
const textBefore = this.
|
|
3464
|
+
const textBefore = this.extractTextSegment(partStartIndex);
|
|
3451
3465
|
if (textBefore !== void 0) {
|
|
3452
3466
|
yield { type: "text", content: textBefore };
|
|
3453
3467
|
}
|
|
3454
3468
|
const metadataStartIndex = partStartIndex + this.startPrefix.length;
|
|
3455
3469
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
3456
3470
|
if (metadataEndIndex === -1) break;
|
|
3457
|
-
const
|
|
3458
|
-
const {
|
|
3459
|
-
actualName: actualGadgetName,
|
|
3460
|
-
invocationId,
|
|
3461
|
-
dependencies
|
|
3462
|
-
} = this.parseGadgetName(gadgetName);
|
|
3471
|
+
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
3472
|
+
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
3463
3473
|
const contentStartIndex = metadataEndIndex + 1;
|
|
3464
3474
|
let partEndIndex;
|
|
3465
3475
|
let endMarkerLength = 0;
|
|
@@ -3479,7 +3489,7 @@ var init_parser = __esm({
|
|
|
3479
3489
|
yield {
|
|
3480
3490
|
type: "gadget_call",
|
|
3481
3491
|
call: {
|
|
3482
|
-
gadgetName
|
|
3492
|
+
gadgetName,
|
|
3483
3493
|
invocationId,
|
|
3484
3494
|
parametersRaw,
|
|
3485
3495
|
parameters,
|
|
@@ -3488,37 +3498,33 @@ var init_parser = __esm({
|
|
|
3488
3498
|
}
|
|
3489
3499
|
};
|
|
3490
3500
|
startIndex = partEndIndex + endMarkerLength;
|
|
3491
|
-
this.
|
|
3501
|
+
this.lastEmittedTextOffset = startIndex;
|
|
3492
3502
|
}
|
|
3493
3503
|
if (startIndex > 0) {
|
|
3494
3504
|
this.buffer = this.buffer.substring(startIndex);
|
|
3495
|
-
this.
|
|
3505
|
+
this.lastEmittedTextOffset = 0;
|
|
3496
3506
|
}
|
|
3497
3507
|
}
|
|
3498
3508
|
// Finalize parsing and return remaining text or incomplete gadgets
|
|
3499
3509
|
*finalize() {
|
|
3500
|
-
const startIndex = this.buffer.indexOf(this.startPrefix, this.
|
|
3510
|
+
const startIndex = this.buffer.indexOf(this.startPrefix, this.lastEmittedTextOffset);
|
|
3501
3511
|
if (startIndex !== -1) {
|
|
3502
|
-
const textBefore = this.
|
|
3512
|
+
const textBefore = this.extractTextSegment(startIndex);
|
|
3503
3513
|
if (textBefore !== void 0) {
|
|
3504
3514
|
yield { type: "text", content: textBefore };
|
|
3505
3515
|
}
|
|
3506
3516
|
const metadataStartIndex = startIndex + this.startPrefix.length;
|
|
3507
3517
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
3508
3518
|
if (metadataEndIndex !== -1) {
|
|
3509
|
-
const
|
|
3510
|
-
const {
|
|
3511
|
-
actualName: actualGadgetName,
|
|
3512
|
-
invocationId,
|
|
3513
|
-
dependencies
|
|
3514
|
-
} = this.parseGadgetName(gadgetName);
|
|
3519
|
+
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
3520
|
+
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
3515
3521
|
const contentStartIndex = metadataEndIndex + 1;
|
|
3516
3522
|
const parametersRaw = this.buffer.substring(contentStartIndex).trim();
|
|
3517
3523
|
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
3518
3524
|
yield {
|
|
3519
3525
|
type: "gadget_call",
|
|
3520
3526
|
call: {
|
|
3521
|
-
gadgetName
|
|
3527
|
+
gadgetName,
|
|
3522
3528
|
invocationId,
|
|
3523
3529
|
parametersRaw,
|
|
3524
3530
|
parameters,
|
|
@@ -3529,7 +3535,7 @@ var init_parser = __esm({
|
|
|
3529
3535
|
return;
|
|
3530
3536
|
}
|
|
3531
3537
|
}
|
|
3532
|
-
const remainingText = this.
|
|
3538
|
+
const remainingText = this.extractTextSegment(this.buffer.length);
|
|
3533
3539
|
if (remainingText !== void 0) {
|
|
3534
3540
|
yield { type: "text", content: remainingText };
|
|
3535
3541
|
}
|
|
@@ -3537,7 +3543,7 @@ var init_parser = __esm({
|
|
|
3537
3543
|
// Reset parser state (note: global invocation counter is NOT reset to ensure unique IDs)
|
|
3538
3544
|
reset() {
|
|
3539
3545
|
this.buffer = "";
|
|
3540
|
-
this.
|
|
3546
|
+
this.lastEmittedTextOffset = 0;
|
|
3541
3547
|
}
|
|
3542
3548
|
};
|
|
3543
3549
|
}
|
|
@@ -3556,14 +3562,17 @@ var init_executor = __esm({
|
|
|
3556
3562
|
init_exceptions();
|
|
3557
3563
|
init_parser();
|
|
3558
3564
|
GadgetExecutor = class {
|
|
3559
|
-
constructor(registry,
|
|
3565
|
+
constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig, onNestedEvent) {
|
|
3560
3566
|
this.registry = registry;
|
|
3561
|
-
this.
|
|
3567
|
+
this.requestHumanInput = requestHumanInput;
|
|
3562
3568
|
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
3563
3569
|
this.client = client;
|
|
3564
3570
|
this.mediaStore = mediaStore;
|
|
3571
|
+
this.agentConfig = agentConfig;
|
|
3572
|
+
this.subagentConfig = subagentConfig;
|
|
3573
|
+
this.onNestedEvent = onNestedEvent;
|
|
3565
3574
|
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
3566
|
-
this.errorFormatter = new
|
|
3575
|
+
this.errorFormatter = new GadgetExecutionErrorFormatter(errorFormatterOptions);
|
|
3567
3576
|
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
3568
3577
|
}
|
|
3569
3578
|
logger;
|
|
@@ -3583,11 +3592,11 @@ var init_executor = __esm({
|
|
|
3583
3592
|
});
|
|
3584
3593
|
}
|
|
3585
3594
|
/**
|
|
3586
|
-
*
|
|
3595
|
+
* Unify gadget execute result to consistent internal format.
|
|
3587
3596
|
* Handles string returns (backwards compat), object returns with cost,
|
|
3588
3597
|
* and object returns with media.
|
|
3589
3598
|
*/
|
|
3590
|
-
|
|
3599
|
+
unifyExecuteResult(raw) {
|
|
3591
3600
|
if (typeof raw === "string") {
|
|
3592
3601
|
return { result: raw, cost: 0 };
|
|
3593
3602
|
}
|
|
@@ -3705,7 +3714,11 @@ var init_executor = __esm({
|
|
|
3705
3714
|
const ctx = {
|
|
3706
3715
|
reportCost,
|
|
3707
3716
|
llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
|
|
3708
|
-
signal: abortController.signal
|
|
3717
|
+
signal: abortController.signal,
|
|
3718
|
+
agentConfig: this.agentConfig,
|
|
3719
|
+
subagentConfig: this.subagentConfig,
|
|
3720
|
+
invocationId: call.invocationId,
|
|
3721
|
+
onNestedEvent: this.onNestedEvent
|
|
3709
3722
|
};
|
|
3710
3723
|
let rawResult;
|
|
3711
3724
|
if (timeoutMs && timeoutMs > 0) {
|
|
@@ -3720,7 +3733,7 @@ var init_executor = __esm({
|
|
|
3720
3733
|
} else {
|
|
3721
3734
|
rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
|
|
3722
3735
|
}
|
|
3723
|
-
const { result, media, cost: returnCost } = this.
|
|
3736
|
+
const { result, media, cost: returnCost } = this.unifyExecuteResult(rawResult);
|
|
3724
3737
|
const totalCost = callbackCost + returnCost;
|
|
3725
3738
|
let mediaIds;
|
|
3726
3739
|
let storedMedia;
|
|
@@ -3766,7 +3779,7 @@ var init_executor = __esm({
|
|
|
3766
3779
|
storedMedia
|
|
3767
3780
|
};
|
|
3768
3781
|
} catch (error) {
|
|
3769
|
-
if (error instanceof
|
|
3782
|
+
if (error instanceof TaskCompletionSignal) {
|
|
3770
3783
|
this.logger.info("Gadget requested loop termination", {
|
|
3771
3784
|
gadgetName: call.gadgetName,
|
|
3772
3785
|
message: error.message
|
|
@@ -3794,7 +3807,7 @@ var init_executor = __esm({
|
|
|
3794
3807
|
executionTimeMs: Date.now() - startTime
|
|
3795
3808
|
};
|
|
3796
3809
|
}
|
|
3797
|
-
if (error instanceof
|
|
3810
|
+
if (error instanceof AbortException) {
|
|
3798
3811
|
this.logger.info("Gadget execution was aborted", {
|
|
3799
3812
|
gadgetName: call.gadgetName,
|
|
3800
3813
|
executionTimeMs: Date.now() - startTime
|
|
@@ -3807,14 +3820,14 @@ var init_executor = __esm({
|
|
|
3807
3820
|
executionTimeMs: Date.now() - startTime
|
|
3808
3821
|
};
|
|
3809
3822
|
}
|
|
3810
|
-
if (error instanceof
|
|
3823
|
+
if (error instanceof HumanInputRequiredException) {
|
|
3811
3824
|
this.logger.info("Gadget requested human input", {
|
|
3812
3825
|
gadgetName: call.gadgetName,
|
|
3813
3826
|
question: error.question
|
|
3814
3827
|
});
|
|
3815
|
-
if (this.
|
|
3828
|
+
if (this.requestHumanInput) {
|
|
3816
3829
|
try {
|
|
3817
|
-
const answer = await this.
|
|
3830
|
+
const answer = await this.requestHumanInput(error.question);
|
|
3818
3831
|
this.logger.debug("Human input received", {
|
|
3819
3832
|
gadgetName: call.gadgetName,
|
|
3820
3833
|
answerLength: answer.length
|
|
@@ -3912,13 +3925,13 @@ var init_stream_processor = __esm({
|
|
|
3912
3925
|
parser;
|
|
3913
3926
|
executor;
|
|
3914
3927
|
stopOnGadgetError;
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3928
|
+
canRecoverFromGadgetError;
|
|
3929
|
+
responseText = "";
|
|
3930
|
+
executionHalted = false;
|
|
3918
3931
|
observerFailureCount = 0;
|
|
3919
3932
|
// Dependency tracking for gadget execution DAG
|
|
3920
3933
|
/** Gadgets waiting for their dependencies to complete */
|
|
3921
|
-
|
|
3934
|
+
gadgetsAwaitingDependencies = /* @__PURE__ */ new Map();
|
|
3922
3935
|
/** Completed gadget results, keyed by invocation ID */
|
|
3923
3936
|
completedResults = /* @__PURE__ */ new Map();
|
|
3924
3937
|
/** Invocation IDs of gadgets that have failed (error or skipped due to dependency) */
|
|
@@ -3929,27 +3942,36 @@ var init_stream_processor = __esm({
|
|
|
3929
3942
|
this.hooks = options.hooks ?? {};
|
|
3930
3943
|
this.logger = options.logger ?? createLogger({ name: "llmist:stream-processor" });
|
|
3931
3944
|
this.stopOnGadgetError = options.stopOnGadgetError ?? true;
|
|
3932
|
-
this.
|
|
3933
|
-
this.parser = new
|
|
3945
|
+
this.canRecoverFromGadgetError = options.canRecoverFromGadgetError;
|
|
3946
|
+
this.parser = new GadgetCallParser({
|
|
3934
3947
|
startPrefix: options.gadgetStartPrefix,
|
|
3935
3948
|
endPrefix: options.gadgetEndPrefix,
|
|
3936
3949
|
argPrefix: options.gadgetArgPrefix
|
|
3937
3950
|
});
|
|
3938
3951
|
this.executor = new GadgetExecutor(
|
|
3939
3952
|
options.registry,
|
|
3940
|
-
options.
|
|
3953
|
+
options.requestHumanInput,
|
|
3941
3954
|
this.logger.getSubLogger({ name: "executor" }),
|
|
3942
3955
|
options.defaultGadgetTimeoutMs,
|
|
3943
3956
|
{ argPrefix: options.gadgetArgPrefix },
|
|
3944
3957
|
options.client,
|
|
3945
|
-
options.mediaStore
|
|
3958
|
+
options.mediaStore,
|
|
3959
|
+
options.agentConfig,
|
|
3960
|
+
options.subagentConfig,
|
|
3961
|
+
options.onNestedEvent
|
|
3946
3962
|
);
|
|
3947
3963
|
}
|
|
3948
3964
|
/**
|
|
3949
|
-
* Process an LLM stream and
|
|
3965
|
+
* Process an LLM stream and yield events in real-time.
|
|
3966
|
+
*
|
|
3967
|
+
* This is an async generator that yields events immediately as they occur:
|
|
3968
|
+
* - Text events are yielded as text is streamed from the LLM
|
|
3969
|
+
* - gadget_call events are yielded immediately when a gadget call is parsed
|
|
3970
|
+
* - gadget_result events are yielded when gadget execution completes
|
|
3971
|
+
*
|
|
3972
|
+
* The final event is always a StreamCompletionEvent containing metadata.
|
|
3950
3973
|
*/
|
|
3951
|
-
async process(stream2) {
|
|
3952
|
-
const outputs = [];
|
|
3974
|
+
async *process(stream2) {
|
|
3953
3975
|
let finishReason = null;
|
|
3954
3976
|
let usage;
|
|
3955
3977
|
let didExecuteGadgets = false;
|
|
@@ -3963,7 +3985,7 @@ var init_stream_processor = __esm({
|
|
|
3963
3985
|
if (this.hooks.interceptors?.interceptRawChunk) {
|
|
3964
3986
|
const context = {
|
|
3965
3987
|
iteration: this.iteration,
|
|
3966
|
-
accumulatedText: this.
|
|
3988
|
+
accumulatedText: this.responseText,
|
|
3967
3989
|
logger: this.logger
|
|
3968
3990
|
};
|
|
3969
3991
|
const intercepted = this.hooks.interceptors.interceptRawChunk(processedChunk, context);
|
|
@@ -3974,7 +3996,7 @@ var init_stream_processor = __esm({
|
|
|
3974
3996
|
}
|
|
3975
3997
|
}
|
|
3976
3998
|
if (processedChunk) {
|
|
3977
|
-
this.
|
|
3999
|
+
this.responseText += processedChunk;
|
|
3978
4000
|
}
|
|
3979
4001
|
}
|
|
3980
4002
|
if (this.hooks.observers?.onStreamChunk && (processedChunk || chunk.usage)) {
|
|
@@ -3983,7 +4005,7 @@ var init_stream_processor = __esm({
|
|
|
3983
4005
|
const context = {
|
|
3984
4006
|
iteration: this.iteration,
|
|
3985
4007
|
rawChunk: processedChunk,
|
|
3986
|
-
accumulatedText: this.
|
|
4008
|
+
accumulatedText: this.responseText,
|
|
3987
4009
|
usage,
|
|
3988
4010
|
logger: this.logger
|
|
3989
4011
|
};
|
|
@@ -3995,67 +4017,66 @@ var init_stream_processor = __esm({
|
|
|
3995
4017
|
continue;
|
|
3996
4018
|
}
|
|
3997
4019
|
for (const event of this.parser.feed(processedChunk)) {
|
|
3998
|
-
const
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
shouldBreakLoop = true;
|
|
4020
|
+
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
4021
|
+
yield processedEvent;
|
|
4022
|
+
if (processedEvent.type === "gadget_result") {
|
|
4023
|
+
didExecuteGadgets = true;
|
|
4024
|
+
if (processedEvent.result.breaksLoop) {
|
|
4025
|
+
shouldBreakLoop = true;
|
|
4026
|
+
}
|
|
4006
4027
|
}
|
|
4007
4028
|
}
|
|
4008
4029
|
}
|
|
4009
|
-
if (this.
|
|
4030
|
+
if (this.executionHalted) {
|
|
4010
4031
|
this.logger.info("Breaking from LLM stream due to gadget error");
|
|
4011
4032
|
break;
|
|
4012
4033
|
}
|
|
4013
4034
|
}
|
|
4014
|
-
if (!this.
|
|
4035
|
+
if (!this.executionHalted) {
|
|
4015
4036
|
for (const event of this.parser.finalize()) {
|
|
4016
|
-
const
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
shouldBreakLoop = true;
|
|
4037
|
+
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
4038
|
+
yield processedEvent;
|
|
4039
|
+
if (processedEvent.type === "gadget_result") {
|
|
4040
|
+
didExecuteGadgets = true;
|
|
4041
|
+
if (processedEvent.result.breaksLoop) {
|
|
4042
|
+
shouldBreakLoop = true;
|
|
4043
|
+
}
|
|
4024
4044
|
}
|
|
4025
4045
|
}
|
|
4026
4046
|
}
|
|
4027
|
-
const
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
shouldBreakLoop = true;
|
|
4047
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4048
|
+
yield evt;
|
|
4049
|
+
if (evt.type === "gadget_result") {
|
|
4050
|
+
didExecuteGadgets = true;
|
|
4051
|
+
if (evt.result.breaksLoop) {
|
|
4052
|
+
shouldBreakLoop = true;
|
|
4053
|
+
}
|
|
4035
4054
|
}
|
|
4036
4055
|
}
|
|
4037
4056
|
}
|
|
4038
|
-
let finalMessage = this.
|
|
4057
|
+
let finalMessage = this.responseText;
|
|
4039
4058
|
if (this.hooks.interceptors?.interceptAssistantMessage) {
|
|
4040
4059
|
const context = {
|
|
4041
4060
|
iteration: this.iteration,
|
|
4042
|
-
rawResponse: this.
|
|
4061
|
+
rawResponse: this.responseText,
|
|
4043
4062
|
logger: this.logger
|
|
4044
4063
|
};
|
|
4045
4064
|
finalMessage = this.hooks.interceptors.interceptAssistantMessage(finalMessage, context);
|
|
4046
4065
|
}
|
|
4047
|
-
|
|
4048
|
-
|
|
4066
|
+
const completionEvent = {
|
|
4067
|
+
type: "stream_complete",
|
|
4049
4068
|
shouldBreakLoop,
|
|
4050
4069
|
didExecuteGadgets,
|
|
4051
4070
|
finishReason,
|
|
4052
4071
|
usage,
|
|
4053
|
-
rawResponse: this.
|
|
4072
|
+
rawResponse: this.responseText,
|
|
4054
4073
|
finalMessage
|
|
4055
4074
|
};
|
|
4075
|
+
yield completionEvent;
|
|
4056
4076
|
}
|
|
4057
4077
|
/**
|
|
4058
4078
|
* Process a single parsed event (text or gadget call).
|
|
4079
|
+
* @deprecated Use processEventGenerator for real-time streaming
|
|
4059
4080
|
*/
|
|
4060
4081
|
async processEvent(event) {
|
|
4061
4082
|
if (event.type === "text") {
|
|
@@ -4065,6 +4086,23 @@ var init_stream_processor = __esm({
|
|
|
4065
4086
|
}
|
|
4066
4087
|
return [event];
|
|
4067
4088
|
}
|
|
4089
|
+
/**
|
|
4090
|
+
* Process a single parsed event, yielding events in real-time.
|
|
4091
|
+
* Generator version of processEvent for streaming support.
|
|
4092
|
+
*/
|
|
4093
|
+
async *processEventGenerator(event) {
|
|
4094
|
+
if (event.type === "text") {
|
|
4095
|
+
for (const e of await this.processTextEvent(event)) {
|
|
4096
|
+
yield e;
|
|
4097
|
+
}
|
|
4098
|
+
} else if (event.type === "gadget_call") {
|
|
4099
|
+
for await (const e of this.processGadgetCallGenerator(event.call)) {
|
|
4100
|
+
yield e;
|
|
4101
|
+
}
|
|
4102
|
+
} else {
|
|
4103
|
+
yield event;
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4068
4106
|
/**
|
|
4069
4107
|
* Process a text event through interceptors.
|
|
4070
4108
|
*/
|
|
@@ -4073,7 +4111,7 @@ var init_stream_processor = __esm({
|
|
|
4073
4111
|
if (this.hooks.interceptors?.interceptTextChunk) {
|
|
4074
4112
|
const context = {
|
|
4075
4113
|
iteration: this.iteration,
|
|
4076
|
-
accumulatedText: this.
|
|
4114
|
+
accumulatedText: this.responseText,
|
|
4077
4115
|
logger: this.logger
|
|
4078
4116
|
};
|
|
4079
4117
|
const intercepted = this.hooks.interceptors.interceptTextChunk(content, context);
|
|
@@ -4092,7 +4130,7 @@ var init_stream_processor = __esm({
|
|
|
4092
4130
|
* After each execution, pending gadgets are checked to see if they can now run.
|
|
4093
4131
|
*/
|
|
4094
4132
|
async processGadgetCall(call) {
|
|
4095
|
-
if (this.
|
|
4133
|
+
if (this.executionHalted) {
|
|
4096
4134
|
this.logger.debug("Skipping gadget execution due to previous error", {
|
|
4097
4135
|
gadgetName: call.gadgetName
|
|
4098
4136
|
});
|
|
@@ -4131,7 +4169,7 @@ var init_stream_processor = __esm({
|
|
|
4131
4169
|
invocationId: call.invocationId,
|
|
4132
4170
|
waitingOn: unsatisfied
|
|
4133
4171
|
});
|
|
4134
|
-
this.
|
|
4172
|
+
this.gadgetsAwaitingDependencies.set(call.invocationId, call);
|
|
4135
4173
|
return events;
|
|
4136
4174
|
}
|
|
4137
4175
|
}
|
|
@@ -4141,9 +4179,68 @@ var init_stream_processor = __esm({
|
|
|
4141
4179
|
events.push(...triggeredEvents);
|
|
4142
4180
|
return events;
|
|
4143
4181
|
}
|
|
4182
|
+
/**
|
|
4183
|
+
* Process a gadget call, yielding events in real-time.
|
|
4184
|
+
*
|
|
4185
|
+
* Key difference from processGadgetCall: yields gadget_call event IMMEDIATELY
|
|
4186
|
+
* when parsed (before execution), enabling real-time UI feedback.
|
|
4187
|
+
*/
|
|
4188
|
+
async *processGadgetCallGenerator(call) {
|
|
4189
|
+
if (this.executionHalted) {
|
|
4190
|
+
this.logger.debug("Skipping gadget execution due to previous error", {
|
|
4191
|
+
gadgetName: call.gadgetName
|
|
4192
|
+
});
|
|
4193
|
+
return;
|
|
4194
|
+
}
|
|
4195
|
+
yield { type: "gadget_call", call };
|
|
4196
|
+
if (call.dependencies.length > 0) {
|
|
4197
|
+
if (call.dependencies.includes(call.invocationId)) {
|
|
4198
|
+
this.logger.warn("Gadget has self-referential dependency (depends on itself)", {
|
|
4199
|
+
gadgetName: call.gadgetName,
|
|
4200
|
+
invocationId: call.invocationId
|
|
4201
|
+
});
|
|
4202
|
+
this.failedInvocations.add(call.invocationId);
|
|
4203
|
+
const skipEvent = {
|
|
4204
|
+
type: "gadget_skipped",
|
|
4205
|
+
gadgetName: call.gadgetName,
|
|
4206
|
+
invocationId: call.invocationId,
|
|
4207
|
+
parameters: call.parameters ?? {},
|
|
4208
|
+
failedDependency: call.invocationId,
|
|
4209
|
+
failedDependencyError: `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`
|
|
4210
|
+
};
|
|
4211
|
+
yield skipEvent;
|
|
4212
|
+
return;
|
|
4213
|
+
}
|
|
4214
|
+
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4215
|
+
if (failedDep) {
|
|
4216
|
+
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4217
|
+
for (const evt of skipEvents) {
|
|
4218
|
+
yield evt;
|
|
4219
|
+
}
|
|
4220
|
+
return;
|
|
4221
|
+
}
|
|
4222
|
+
const unsatisfied = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4223
|
+
if (unsatisfied.length > 0) {
|
|
4224
|
+
this.logger.debug("Queueing gadget for later - waiting on dependencies", {
|
|
4225
|
+
gadgetName: call.gadgetName,
|
|
4226
|
+
invocationId: call.invocationId,
|
|
4227
|
+
waitingOn: unsatisfied
|
|
4228
|
+
});
|
|
4229
|
+
this.gadgetsAwaitingDependencies.set(call.invocationId, call);
|
|
4230
|
+
return;
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4234
|
+
yield evt;
|
|
4235
|
+
}
|
|
4236
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4237
|
+
yield evt;
|
|
4238
|
+
}
|
|
4239
|
+
}
|
|
4144
4240
|
/**
|
|
4145
4241
|
* Execute a gadget through the full hook lifecycle.
|
|
4146
4242
|
* This is the core execution logic, extracted from processGadgetCall.
|
|
4243
|
+
* @deprecated Use executeGadgetGenerator for real-time streaming
|
|
4147
4244
|
*/
|
|
4148
4245
|
async executeGadgetWithHooks(call) {
|
|
4149
4246
|
const events = [];
|
|
@@ -4153,14 +4250,14 @@ var init_stream_processor = __esm({
|
|
|
4153
4250
|
error: call.parseError,
|
|
4154
4251
|
rawParameters: call.parametersRaw
|
|
4155
4252
|
});
|
|
4156
|
-
const shouldContinue = await this.
|
|
4253
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4157
4254
|
call.parseError,
|
|
4158
4255
|
call.gadgetName,
|
|
4159
4256
|
"parse",
|
|
4160
4257
|
call.parameters
|
|
4161
4258
|
);
|
|
4162
4259
|
if (!shouldContinue) {
|
|
4163
|
-
this.
|
|
4260
|
+
this.executionHalted = true;
|
|
4164
4261
|
}
|
|
4165
4262
|
}
|
|
4166
4263
|
let parameters = call.parameters ?? {};
|
|
@@ -4284,18 +4381,171 @@ var init_stream_processor = __esm({
|
|
|
4284
4381
|
events.push({ type: "gadget_result", result });
|
|
4285
4382
|
if (result.error) {
|
|
4286
4383
|
const errorType = this.determineErrorType(call, result);
|
|
4287
|
-
const shouldContinue = await this.
|
|
4384
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4288
4385
|
result.error,
|
|
4289
4386
|
result.gadgetName,
|
|
4290
4387
|
errorType,
|
|
4291
4388
|
result.parameters
|
|
4292
4389
|
);
|
|
4293
4390
|
if (!shouldContinue) {
|
|
4294
|
-
this.
|
|
4391
|
+
this.executionHalted = true;
|
|
4295
4392
|
}
|
|
4296
4393
|
}
|
|
4297
4394
|
return events;
|
|
4298
4395
|
}
|
|
4396
|
+
/**
|
|
4397
|
+
* Execute a gadget and yield the result event.
|
|
4398
|
+
* Generator version that yields gadget_result immediately when execution completes.
|
|
4399
|
+
*/
|
|
4400
|
+
async *executeGadgetGenerator(call) {
|
|
4401
|
+
if (call.parseError) {
|
|
4402
|
+
this.logger.warn("Gadget has parse error", {
|
|
4403
|
+
gadgetName: call.gadgetName,
|
|
4404
|
+
error: call.parseError,
|
|
4405
|
+
rawParameters: call.parametersRaw
|
|
4406
|
+
});
|
|
4407
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4408
|
+
call.parseError,
|
|
4409
|
+
call.gadgetName,
|
|
4410
|
+
"parse",
|
|
4411
|
+
call.parameters
|
|
4412
|
+
);
|
|
4413
|
+
if (!shouldContinue) {
|
|
4414
|
+
this.executionHalted = true;
|
|
4415
|
+
}
|
|
4416
|
+
}
|
|
4417
|
+
let parameters = call.parameters ?? {};
|
|
4418
|
+
if (this.hooks.interceptors?.interceptGadgetParameters) {
|
|
4419
|
+
const context = {
|
|
4420
|
+
iteration: this.iteration,
|
|
4421
|
+
gadgetName: call.gadgetName,
|
|
4422
|
+
invocationId: call.invocationId,
|
|
4423
|
+
logger: this.logger
|
|
4424
|
+
};
|
|
4425
|
+
parameters = this.hooks.interceptors.interceptGadgetParameters(parameters, context);
|
|
4426
|
+
}
|
|
4427
|
+
call.parameters = parameters;
|
|
4428
|
+
let shouldSkip = false;
|
|
4429
|
+
let syntheticResult;
|
|
4430
|
+
if (this.hooks.controllers?.beforeGadgetExecution) {
|
|
4431
|
+
const context = {
|
|
4432
|
+
iteration: this.iteration,
|
|
4433
|
+
gadgetName: call.gadgetName,
|
|
4434
|
+
invocationId: call.invocationId,
|
|
4435
|
+
parameters,
|
|
4436
|
+
logger: this.logger
|
|
4437
|
+
};
|
|
4438
|
+
const action = await this.hooks.controllers.beforeGadgetExecution(context);
|
|
4439
|
+
validateBeforeGadgetExecutionAction(action);
|
|
4440
|
+
if (action.action === "skip") {
|
|
4441
|
+
shouldSkip = true;
|
|
4442
|
+
syntheticResult = action.syntheticResult;
|
|
4443
|
+
this.logger.info("Controller skipped gadget execution", {
|
|
4444
|
+
gadgetName: call.gadgetName
|
|
4445
|
+
});
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4448
|
+
const startObservers = [];
|
|
4449
|
+
if (this.hooks.observers?.onGadgetExecutionStart) {
|
|
4450
|
+
startObservers.push(async () => {
|
|
4451
|
+
const context = {
|
|
4452
|
+
iteration: this.iteration,
|
|
4453
|
+
gadgetName: call.gadgetName,
|
|
4454
|
+
invocationId: call.invocationId,
|
|
4455
|
+
parameters,
|
|
4456
|
+
logger: this.logger
|
|
4457
|
+
};
|
|
4458
|
+
await this.hooks.observers.onGadgetExecutionStart(context);
|
|
4459
|
+
});
|
|
4460
|
+
}
|
|
4461
|
+
await this.runObserversInParallel(startObservers);
|
|
4462
|
+
let result;
|
|
4463
|
+
if (shouldSkip) {
|
|
4464
|
+
result = {
|
|
4465
|
+
gadgetName: call.gadgetName,
|
|
4466
|
+
invocationId: call.invocationId,
|
|
4467
|
+
parameters,
|
|
4468
|
+
result: syntheticResult ?? "Execution skipped",
|
|
4469
|
+
executionTimeMs: 0
|
|
4470
|
+
};
|
|
4471
|
+
} else {
|
|
4472
|
+
result = await this.executor.execute(call);
|
|
4473
|
+
}
|
|
4474
|
+
const originalResult = result.result;
|
|
4475
|
+
if (result.result && this.hooks.interceptors?.interceptGadgetResult) {
|
|
4476
|
+
const context = {
|
|
4477
|
+
iteration: this.iteration,
|
|
4478
|
+
gadgetName: result.gadgetName,
|
|
4479
|
+
invocationId: result.invocationId,
|
|
4480
|
+
parameters,
|
|
4481
|
+
executionTimeMs: result.executionTimeMs,
|
|
4482
|
+
logger: this.logger
|
|
4483
|
+
};
|
|
4484
|
+
result.result = this.hooks.interceptors.interceptGadgetResult(result.result, context);
|
|
4485
|
+
}
|
|
4486
|
+
if (this.hooks.controllers?.afterGadgetExecution) {
|
|
4487
|
+
const context = {
|
|
4488
|
+
iteration: this.iteration,
|
|
4489
|
+
gadgetName: result.gadgetName,
|
|
4490
|
+
invocationId: result.invocationId,
|
|
4491
|
+
parameters,
|
|
4492
|
+
result: result.result,
|
|
4493
|
+
error: result.error,
|
|
4494
|
+
executionTimeMs: result.executionTimeMs,
|
|
4495
|
+
logger: this.logger
|
|
4496
|
+
};
|
|
4497
|
+
const action = await this.hooks.controllers.afterGadgetExecution(context);
|
|
4498
|
+
validateAfterGadgetExecutionAction(action);
|
|
4499
|
+
if (action.action === "recover" && result.error) {
|
|
4500
|
+
this.logger.info("Controller recovered from gadget error", {
|
|
4501
|
+
gadgetName: result.gadgetName,
|
|
4502
|
+
originalError: result.error
|
|
4503
|
+
});
|
|
4504
|
+
result = {
|
|
4505
|
+
...result,
|
|
4506
|
+
error: void 0,
|
|
4507
|
+
result: action.fallbackResult
|
|
4508
|
+
};
|
|
4509
|
+
}
|
|
4510
|
+
}
|
|
4511
|
+
const completeObservers = [];
|
|
4512
|
+
if (this.hooks.observers?.onGadgetExecutionComplete) {
|
|
4513
|
+
completeObservers.push(async () => {
|
|
4514
|
+
const context = {
|
|
4515
|
+
iteration: this.iteration,
|
|
4516
|
+
gadgetName: result.gadgetName,
|
|
4517
|
+
invocationId: result.invocationId,
|
|
4518
|
+
parameters,
|
|
4519
|
+
originalResult,
|
|
4520
|
+
finalResult: result.result,
|
|
4521
|
+
error: result.error,
|
|
4522
|
+
executionTimeMs: result.executionTimeMs,
|
|
4523
|
+
breaksLoop: result.breaksLoop,
|
|
4524
|
+
cost: result.cost,
|
|
4525
|
+
logger: this.logger
|
|
4526
|
+
};
|
|
4527
|
+
await this.hooks.observers.onGadgetExecutionComplete(context);
|
|
4528
|
+
});
|
|
4529
|
+
}
|
|
4530
|
+
await this.runObserversInParallel(completeObservers);
|
|
4531
|
+
this.completedResults.set(result.invocationId, result);
|
|
4532
|
+
if (result.error) {
|
|
4533
|
+
this.failedInvocations.add(result.invocationId);
|
|
4534
|
+
}
|
|
4535
|
+
yield { type: "gadget_result", result };
|
|
4536
|
+
if (result.error) {
|
|
4537
|
+
const errorType = this.determineErrorType(call, result);
|
|
4538
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4539
|
+
result.error,
|
|
4540
|
+
result.gadgetName,
|
|
4541
|
+
errorType,
|
|
4542
|
+
result.parameters
|
|
4543
|
+
);
|
|
4544
|
+
if (!shouldContinue) {
|
|
4545
|
+
this.executionHalted = true;
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4299
4549
|
/**
|
|
4300
4550
|
* Handle a gadget that cannot execute because a dependency failed.
|
|
4301
4551
|
* Calls the onDependencySkipped controller to allow customization.
|
|
@@ -4378,11 +4628,11 @@ var init_stream_processor = __esm({
|
|
|
4378
4628
|
async processPendingGadgets() {
|
|
4379
4629
|
const events = [];
|
|
4380
4630
|
let progress = true;
|
|
4381
|
-
while (progress && this.
|
|
4631
|
+
while (progress && this.gadgetsAwaitingDependencies.size > 0) {
|
|
4382
4632
|
progress = false;
|
|
4383
4633
|
const readyToExecute = [];
|
|
4384
4634
|
const readyToSkip = [];
|
|
4385
|
-
for (const [invocationId, call] of this.
|
|
4635
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4386
4636
|
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4387
4637
|
if (failedDep) {
|
|
4388
4638
|
readyToSkip.push({ call, failedDep });
|
|
@@ -4394,7 +4644,7 @@ var init_stream_processor = __esm({
|
|
|
4394
4644
|
}
|
|
4395
4645
|
}
|
|
4396
4646
|
for (const { call, failedDep } of readyToSkip) {
|
|
4397
|
-
this.
|
|
4647
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4398
4648
|
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4399
4649
|
events.push(...skipEvents);
|
|
4400
4650
|
progress = true;
|
|
@@ -4405,7 +4655,7 @@ var init_stream_processor = __esm({
|
|
|
4405
4655
|
invocationIds: readyToExecute.map((c) => c.invocationId)
|
|
4406
4656
|
});
|
|
4407
4657
|
for (const call of readyToExecute) {
|
|
4408
|
-
this.
|
|
4658
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4409
4659
|
}
|
|
4410
4660
|
const executePromises = readyToExecute.map((call) => this.executeGadgetWithHooks(call));
|
|
4411
4661
|
const results = await Promise.all(executePromises);
|
|
@@ -4415,9 +4665,9 @@ var init_stream_processor = __esm({
|
|
|
4415
4665
|
progress = true;
|
|
4416
4666
|
}
|
|
4417
4667
|
}
|
|
4418
|
-
if (this.
|
|
4419
|
-
const pendingIds = new Set(this.
|
|
4420
|
-
for (const [invocationId, call] of this.
|
|
4668
|
+
if (this.gadgetsAwaitingDependencies.size > 0) {
|
|
4669
|
+
const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());
|
|
4670
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4421
4671
|
const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4422
4672
|
const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));
|
|
4423
4673
|
const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));
|
|
@@ -4448,10 +4698,103 @@ var init_stream_processor = __esm({
|
|
|
4448
4698
|
};
|
|
4449
4699
|
events.push(skipEvent);
|
|
4450
4700
|
}
|
|
4451
|
-
this.
|
|
4701
|
+
this.gadgetsAwaitingDependencies.clear();
|
|
4452
4702
|
}
|
|
4453
4703
|
return events;
|
|
4454
4704
|
}
|
|
4705
|
+
/**
|
|
4706
|
+
* Process pending gadgets, yielding events in real-time.
|
|
4707
|
+
* Generator version that yields events as gadgets complete.
|
|
4708
|
+
*
|
|
4709
|
+
* Note: Gadgets are still executed in parallel for efficiency,
|
|
4710
|
+
* but results are yielded as they become available.
|
|
4711
|
+
*/
|
|
4712
|
+
async *processPendingGadgetsGenerator() {
|
|
4713
|
+
let progress = true;
|
|
4714
|
+
while (progress && this.gadgetsAwaitingDependencies.size > 0) {
|
|
4715
|
+
progress = false;
|
|
4716
|
+
const readyToExecute = [];
|
|
4717
|
+
const readyToSkip = [];
|
|
4718
|
+
for (const [_invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4719
|
+
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4720
|
+
if (failedDep) {
|
|
4721
|
+
readyToSkip.push({ call, failedDep });
|
|
4722
|
+
continue;
|
|
4723
|
+
}
|
|
4724
|
+
const allSatisfied = call.dependencies.every((dep) => this.completedResults.has(dep));
|
|
4725
|
+
if (allSatisfied) {
|
|
4726
|
+
readyToExecute.push(call);
|
|
4727
|
+
}
|
|
4728
|
+
}
|
|
4729
|
+
for (const { call, failedDep } of readyToSkip) {
|
|
4730
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4731
|
+
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4732
|
+
for (const evt of skipEvents) {
|
|
4733
|
+
yield evt;
|
|
4734
|
+
}
|
|
4735
|
+
progress = true;
|
|
4736
|
+
}
|
|
4737
|
+
if (readyToExecute.length > 0) {
|
|
4738
|
+
this.logger.debug("Executing ready gadgets in parallel", {
|
|
4739
|
+
count: readyToExecute.length,
|
|
4740
|
+
invocationIds: readyToExecute.map((c) => c.invocationId)
|
|
4741
|
+
});
|
|
4742
|
+
for (const call of readyToExecute) {
|
|
4743
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4744
|
+
}
|
|
4745
|
+
const eventSets = await Promise.all(
|
|
4746
|
+
readyToExecute.map(async (call) => {
|
|
4747
|
+
const events = [];
|
|
4748
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4749
|
+
events.push(evt);
|
|
4750
|
+
}
|
|
4751
|
+
return events;
|
|
4752
|
+
})
|
|
4753
|
+
);
|
|
4754
|
+
for (const events of eventSets) {
|
|
4755
|
+
for (const evt of events) {
|
|
4756
|
+
yield evt;
|
|
4757
|
+
}
|
|
4758
|
+
}
|
|
4759
|
+
progress = true;
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
if (this.gadgetsAwaitingDependencies.size > 0) {
|
|
4763
|
+
const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());
|
|
4764
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4765
|
+
const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4766
|
+
const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));
|
|
4767
|
+
const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));
|
|
4768
|
+
let errorMessage;
|
|
4769
|
+
let logLevel = "warn";
|
|
4770
|
+
if (circularDeps.length > 0 && trulyMissingDeps.length > 0) {
|
|
4771
|
+
errorMessage = `Dependencies unresolvable: circular=[${circularDeps.join(", ")}], missing=[${trulyMissingDeps.join(", ")}]`;
|
|
4772
|
+
logLevel = "error";
|
|
4773
|
+
} else if (circularDeps.length > 0) {
|
|
4774
|
+
errorMessage = `Circular dependency detected: "${invocationId}" depends on "${circularDeps[0]}" which also depends on "${invocationId}" (directly or indirectly)`;
|
|
4775
|
+
} else {
|
|
4776
|
+
errorMessage = `Dependency "${missingDeps[0]}" was never executed - check that the invocation ID exists and is spelled correctly`;
|
|
4777
|
+
}
|
|
4778
|
+
this.logger[logLevel]("Gadget has unresolvable dependencies", {
|
|
4779
|
+
gadgetName: call.gadgetName,
|
|
4780
|
+
invocationId,
|
|
4781
|
+
circularDependencies: circularDeps,
|
|
4782
|
+
missingDependencies: trulyMissingDeps
|
|
4783
|
+
});
|
|
4784
|
+
this.failedInvocations.add(invocationId);
|
|
4785
|
+
const skipEvent = {
|
|
4786
|
+
type: "gadget_skipped",
|
|
4787
|
+
gadgetName: call.gadgetName,
|
|
4788
|
+
invocationId,
|
|
4789
|
+
parameters: call.parameters ?? {},
|
|
4790
|
+
failedDependency: missingDeps[0],
|
|
4791
|
+
failedDependencyError: errorMessage
|
|
4792
|
+
};
|
|
4793
|
+
yield skipEvent;
|
|
4794
|
+
}
|
|
4795
|
+
this.gadgetsAwaitingDependencies.clear();
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4455
4798
|
/**
|
|
4456
4799
|
* Safely execute an observer, catching and logging any errors.
|
|
4457
4800
|
* Observers are non-critical, so errors are logged but don't crash the system.
|
|
@@ -4478,19 +4821,19 @@ var init_stream_processor = __esm({
|
|
|
4478
4821
|
);
|
|
4479
4822
|
}
|
|
4480
4823
|
/**
|
|
4481
|
-
* Check if execution
|
|
4824
|
+
* Check if execution can recover from an error.
|
|
4482
4825
|
*
|
|
4483
4826
|
* Returns true if we should continue processing subsequent gadgets, false if we should stop.
|
|
4484
4827
|
*
|
|
4485
4828
|
* Logic:
|
|
4486
|
-
* - If custom
|
|
4829
|
+
* - If custom canRecoverFromGadgetError is provided, use it
|
|
4487
4830
|
* - Otherwise, use stopOnGadgetError config:
|
|
4488
4831
|
* - stopOnGadgetError=true → return false (stop execution)
|
|
4489
4832
|
* - stopOnGadgetError=false → return true (continue execution)
|
|
4490
4833
|
*/
|
|
4491
|
-
async
|
|
4492
|
-
if (this.
|
|
4493
|
-
return await this.
|
|
4834
|
+
async checkCanRecoverFromError(error, gadgetName, errorType, parameters) {
|
|
4835
|
+
if (this.canRecoverFromGadgetError) {
|
|
4836
|
+
return await this.canRecoverFromGadgetError({
|
|
4494
4837
|
error,
|
|
4495
4838
|
gadgetName,
|
|
4496
4839
|
errorType,
|
|
@@ -4553,14 +4896,14 @@ var init_agent = __esm({
|
|
|
4553
4896
|
gadgetStartPrefix;
|
|
4554
4897
|
gadgetEndPrefix;
|
|
4555
4898
|
gadgetArgPrefix;
|
|
4556
|
-
|
|
4899
|
+
requestHumanInput;
|
|
4557
4900
|
textOnlyHandler;
|
|
4558
4901
|
textWithGadgetsHandler;
|
|
4559
4902
|
stopOnGadgetError;
|
|
4560
|
-
|
|
4903
|
+
canRecoverFromGadgetError;
|
|
4561
4904
|
defaultGadgetTimeoutMs;
|
|
4562
4905
|
defaultMaxTokens;
|
|
4563
|
-
|
|
4906
|
+
hasUserPrompt;
|
|
4564
4907
|
// Gadget output limiting
|
|
4565
4908
|
outputStore;
|
|
4566
4909
|
outputLimitEnabled;
|
|
@@ -4571,6 +4914,11 @@ var init_agent = __esm({
|
|
|
4571
4914
|
mediaStore;
|
|
4572
4915
|
// Cancellation
|
|
4573
4916
|
signal;
|
|
4917
|
+
// Subagent configuration
|
|
4918
|
+
agentContextConfig;
|
|
4919
|
+
subagentConfig;
|
|
4920
|
+
// Nested event callback for subagent gadgets
|
|
4921
|
+
onNestedEvent;
|
|
4574
4922
|
/**
|
|
4575
4923
|
* Creates a new Agent instance.
|
|
4576
4924
|
* @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
|
|
@@ -4590,11 +4938,11 @@ var init_agent = __esm({
|
|
|
4590
4938
|
this.gadgetStartPrefix = options.gadgetStartPrefix;
|
|
4591
4939
|
this.gadgetEndPrefix = options.gadgetEndPrefix;
|
|
4592
4940
|
this.gadgetArgPrefix = options.gadgetArgPrefix;
|
|
4593
|
-
this.
|
|
4941
|
+
this.requestHumanInput = options.requestHumanInput;
|
|
4594
4942
|
this.textOnlyHandler = options.textOnlyHandler ?? "terminate";
|
|
4595
4943
|
this.textWithGadgetsHandler = options.textWithGadgetsHandler;
|
|
4596
4944
|
this.stopOnGadgetError = options.stopOnGadgetError ?? true;
|
|
4597
|
-
this.
|
|
4945
|
+
this.canRecoverFromGadgetError = options.canRecoverFromGadgetError;
|
|
4598
4946
|
this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
|
|
4599
4947
|
this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
|
|
4600
4948
|
this.outputLimitEnabled = options.gadgetOutputLimit ?? DEFAULT_GADGET_OUTPUT_LIMIT;
|
|
@@ -4610,7 +4958,7 @@ var init_agent = __esm({
|
|
|
4610
4958
|
createGadgetOutputViewer(this.outputStore, this.outputLimitCharLimit)
|
|
4611
4959
|
);
|
|
4612
4960
|
}
|
|
4613
|
-
this.hooks = this.
|
|
4961
|
+
this.hooks = this.chainOutputLimiterWithUserHooks(options.hooks);
|
|
4614
4962
|
const baseBuilder = new LLMMessageBuilder(options.promptConfig);
|
|
4615
4963
|
if (options.systemPrompt) {
|
|
4616
4964
|
baseBuilder.addSystem(options.systemPrompt);
|
|
@@ -4630,7 +4978,7 @@ var init_agent = __esm({
|
|
|
4630
4978
|
endPrefix: options.gadgetEndPrefix,
|
|
4631
4979
|
argPrefix: options.gadgetArgPrefix
|
|
4632
4980
|
});
|
|
4633
|
-
this.
|
|
4981
|
+
this.hasUserPrompt = !!options.userPrompt;
|
|
4634
4982
|
if (options.userPrompt) {
|
|
4635
4983
|
this.conversation.addUserMessage(options.userPrompt);
|
|
4636
4984
|
}
|
|
@@ -4643,6 +4991,12 @@ var init_agent = __esm({
|
|
|
4643
4991
|
);
|
|
4644
4992
|
}
|
|
4645
4993
|
this.signal = options.signal;
|
|
4994
|
+
this.agentContextConfig = {
|
|
4995
|
+
model: this.model,
|
|
4996
|
+
temperature: this.temperature
|
|
4997
|
+
};
|
|
4998
|
+
this.subagentConfig = options.subagentConfig;
|
|
4999
|
+
this.onNestedEvent = options.onNestedEvent;
|
|
4646
5000
|
}
|
|
4647
5001
|
/**
|
|
4648
5002
|
* Get the gadget registry for this agent.
|
|
@@ -4749,7 +5103,7 @@ var init_agent = __esm({
|
|
|
4749
5103
|
* @throws {Error} If no user prompt was provided (when using build() without ask())
|
|
4750
5104
|
*/
|
|
4751
5105
|
async *run() {
|
|
4752
|
-
if (!this.
|
|
5106
|
+
if (!this.hasUserPrompt) {
|
|
4753
5107
|
throw new Error(
|
|
4754
5108
|
"No user prompt provided. Use .ask(prompt) instead of .build(), or call agent.run() after providing a prompt."
|
|
4755
5109
|
);
|
|
@@ -4866,17 +5220,37 @@ var init_agent = __esm({
|
|
|
4866
5220
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
4867
5221
|
hooks: this.hooks,
|
|
4868
5222
|
logger: this.logger.getSubLogger({ name: "stream-processor" }),
|
|
4869
|
-
|
|
5223
|
+
requestHumanInput: this.requestHumanInput,
|
|
4870
5224
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
4871
|
-
|
|
5225
|
+
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
4872
5226
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
4873
5227
|
client: this.client,
|
|
4874
|
-
mediaStore: this.mediaStore
|
|
5228
|
+
mediaStore: this.mediaStore,
|
|
5229
|
+
agentConfig: this.agentContextConfig,
|
|
5230
|
+
subagentConfig: this.subagentConfig,
|
|
5231
|
+
onNestedEvent: this.onNestedEvent
|
|
4875
5232
|
});
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
5233
|
+
let streamMetadata = null;
|
|
5234
|
+
let gadgetCallCount = 0;
|
|
5235
|
+
const textOutputs = [];
|
|
5236
|
+
const gadgetResults = [];
|
|
5237
|
+
for await (const event of processor.process(stream2)) {
|
|
5238
|
+
if (event.type === "stream_complete") {
|
|
5239
|
+
streamMetadata = event;
|
|
5240
|
+
continue;
|
|
5241
|
+
}
|
|
5242
|
+
if (event.type === "text") {
|
|
5243
|
+
textOutputs.push(event.content);
|
|
5244
|
+
} else if (event.type === "gadget_result") {
|
|
5245
|
+
gadgetCallCount++;
|
|
5246
|
+
gadgetResults.push(event);
|
|
5247
|
+
}
|
|
5248
|
+
yield event;
|
|
4879
5249
|
}
|
|
5250
|
+
if (!streamMetadata) {
|
|
5251
|
+
throw new Error("Stream processing completed without metadata event");
|
|
5252
|
+
}
|
|
5253
|
+
const result = streamMetadata;
|
|
4880
5254
|
this.logger.info("LLM response completed", {
|
|
4881
5255
|
finishReason: result.finishReason,
|
|
4882
5256
|
usage: result.usage,
|
|
@@ -4901,9 +5275,6 @@ var init_agent = __esm({
|
|
|
4901
5275
|
});
|
|
4902
5276
|
let finalMessage = result.finalMessage;
|
|
4903
5277
|
if (this.hooks.controllers?.afterLLMCall) {
|
|
4904
|
-
const gadgetCallCount = result.outputs.filter(
|
|
4905
|
-
(output) => output.type === "gadget_result"
|
|
4906
|
-
).length;
|
|
4907
5278
|
const context = {
|
|
4908
5279
|
iteration: currentIteration,
|
|
4909
5280
|
maxIterations: this.maxIterations,
|
|
@@ -4924,31 +5295,29 @@ var init_agent = __esm({
|
|
|
4924
5295
|
if (msg.role === "user") {
|
|
4925
5296
|
this.conversation.addUserMessage(msg.content);
|
|
4926
5297
|
} else if (msg.role === "assistant") {
|
|
4927
|
-
this.conversation.addAssistantMessage(
|
|
5298
|
+
this.conversation.addAssistantMessage(extractMessageText(msg.content));
|
|
4928
5299
|
} else if (msg.role === "system") {
|
|
4929
|
-
this.conversation.addUserMessage(`[System] ${
|
|
5300
|
+
this.conversation.addUserMessage(`[System] ${extractMessageText(msg.content)}`);
|
|
4930
5301
|
}
|
|
4931
5302
|
}
|
|
4932
5303
|
}
|
|
4933
5304
|
}
|
|
4934
5305
|
if (result.didExecuteGadgets) {
|
|
4935
5306
|
if (this.textWithGadgetsHandler) {
|
|
4936
|
-
const textContent =
|
|
4937
|
-
(output) => output.type === "text"
|
|
4938
|
-
).map((output) => output.content).join("");
|
|
5307
|
+
const textContent = textOutputs.join("");
|
|
4939
5308
|
if (textContent.trim()) {
|
|
4940
5309
|
const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
|
|
4941
|
-
this.conversation.
|
|
5310
|
+
this.conversation.addGadgetCallResult(
|
|
4942
5311
|
gadgetName,
|
|
4943
5312
|
parameterMapping(textContent),
|
|
4944
5313
|
resultMapping ? resultMapping(textContent) : textContent
|
|
4945
5314
|
);
|
|
4946
5315
|
}
|
|
4947
5316
|
}
|
|
4948
|
-
for (const output of
|
|
5317
|
+
for (const output of gadgetResults) {
|
|
4949
5318
|
if (output.type === "gadget_result") {
|
|
4950
5319
|
const gadgetResult = output.result;
|
|
4951
|
-
this.conversation.
|
|
5320
|
+
this.conversation.addGadgetCallResult(
|
|
4952
5321
|
gadgetResult.gadgetName,
|
|
4953
5322
|
gadgetResult.parameters,
|
|
4954
5323
|
gadgetResult.error ?? gadgetResult.result ?? "",
|
|
@@ -4959,7 +5328,7 @@ var init_agent = __esm({
|
|
|
4959
5328
|
}
|
|
4960
5329
|
} else {
|
|
4961
5330
|
if (finalMessage.trim()) {
|
|
4962
|
-
this.conversation.
|
|
5331
|
+
this.conversation.addGadgetCallResult(
|
|
4963
5332
|
"TellUser",
|
|
4964
5333
|
{ message: finalMessage, done: false, type: "info" },
|
|
4965
5334
|
`\u2139\uFE0F ${finalMessage}`
|
|
@@ -5085,10 +5454,10 @@ var init_agent = __esm({
|
|
|
5085
5454
|
return this.client.modelRegistry.getModelLimits(unprefixedModelId)?.maxOutputTokens;
|
|
5086
5455
|
}
|
|
5087
5456
|
/**
|
|
5088
|
-
*
|
|
5457
|
+
* Chain the output limiter interceptor with user-provided hooks.
|
|
5089
5458
|
* The limiter runs first, then chains to any user interceptor.
|
|
5090
5459
|
*/
|
|
5091
|
-
|
|
5460
|
+
chainOutputLimiterWithUserHooks(userHooks) {
|
|
5092
5461
|
if (!this.outputLimitEnabled) {
|
|
5093
5462
|
return userHooks ?? {};
|
|
5094
5463
|
}
|
|
@@ -5442,9 +5811,9 @@ var init_base_provider = __esm({
|
|
|
5442
5811
|
*/
|
|
5443
5812
|
async *stream(options, descriptor, spec) {
|
|
5444
5813
|
const preparedMessages = this.prepareMessages(options.messages);
|
|
5445
|
-
const payload = this.
|
|
5814
|
+
const payload = this.buildApiRequest(options, descriptor, spec, preparedMessages);
|
|
5446
5815
|
const rawStream = await this.executeStreamRequest(payload, options.signal);
|
|
5447
|
-
yield* this.
|
|
5816
|
+
yield* this.normalizeProviderStream(rawStream);
|
|
5448
5817
|
}
|
|
5449
5818
|
/**
|
|
5450
5819
|
* Prepare messages for the request.
|
|
@@ -5544,11 +5913,11 @@ var init_anthropic = __esm({
|
|
|
5544
5913
|
"Anthropic does not support speech generation. Use OpenAI (TTS) or Google Gemini (TTS) instead."
|
|
5545
5914
|
);
|
|
5546
5915
|
}
|
|
5547
|
-
|
|
5916
|
+
buildApiRequest(options, descriptor, spec, messages) {
|
|
5548
5917
|
const systemMessages = messages.filter((message) => message.role === "system");
|
|
5549
5918
|
const system = systemMessages.length > 0 ? systemMessages.map((m, index) => ({
|
|
5550
5919
|
type: "text",
|
|
5551
|
-
text:
|
|
5920
|
+
text: extractMessageText(m.content),
|
|
5552
5921
|
// Add cache_control to the LAST system message block
|
|
5553
5922
|
...index === systemMessages.length - 1 ? { cache_control: { type: "ephemeral" } } : {}
|
|
5554
5923
|
})) : void 0;
|
|
@@ -5585,7 +5954,7 @@ var init_anthropic = __esm({
|
|
|
5585
5954
|
* Handles text, images (base64 only), and applies cache_control.
|
|
5586
5955
|
*/
|
|
5587
5956
|
convertToAnthropicContent(content, addCacheControl) {
|
|
5588
|
-
const parts =
|
|
5957
|
+
const parts = normalizeMessageContent(content);
|
|
5589
5958
|
return parts.map((part, index) => {
|
|
5590
5959
|
const isLastPart = index === parts.length - 1;
|
|
5591
5960
|
const cacheControl = addCacheControl && isLastPart ? { cache_control: { type: "ephemeral" } } : {};
|
|
@@ -5631,7 +6000,7 @@ var init_anthropic = __esm({
|
|
|
5631
6000
|
const stream2 = await client.messages.create(payload, signal ? { signal } : void 0);
|
|
5632
6001
|
return stream2;
|
|
5633
6002
|
}
|
|
5634
|
-
async *
|
|
6003
|
+
async *normalizeProviderStream(iterable) {
|
|
5635
6004
|
const stream2 = iterable;
|
|
5636
6005
|
let inputTokens = 0;
|
|
5637
6006
|
let cachedInputTokens = 0;
|
|
@@ -5708,7 +6077,7 @@ var init_anthropic = __esm({
|
|
|
5708
6077
|
async countTokens(messages, descriptor, _spec) {
|
|
5709
6078
|
const client = this.client;
|
|
5710
6079
|
const systemMessages = messages.filter((message) => message.role === "system");
|
|
5711
|
-
const system = systemMessages.length > 0 ? systemMessages.map((m) =>
|
|
6080
|
+
const system = systemMessages.length > 0 ? systemMessages.map((m) => extractMessageText(m.content)).join("\n\n") : void 0;
|
|
5712
6081
|
const conversation = messages.filter(
|
|
5713
6082
|
(message) => message.role !== "system"
|
|
5714
6083
|
).map((message) => ({
|
|
@@ -5730,7 +6099,7 @@ var init_anthropic = __esm({
|
|
|
5730
6099
|
let totalChars = 0;
|
|
5731
6100
|
let imageCount = 0;
|
|
5732
6101
|
for (const msg of messages) {
|
|
5733
|
-
const parts =
|
|
6102
|
+
const parts = normalizeMessageContent(msg.content);
|
|
5734
6103
|
for (const part of parts) {
|
|
5735
6104
|
if (part.type === "text") {
|
|
5736
6105
|
totalChars += part.text.length;
|
|
@@ -6421,7 +6790,7 @@ var init_gemini = __esm({
|
|
|
6421
6790
|
format: spec?.defaultFormat ?? "wav"
|
|
6422
6791
|
};
|
|
6423
6792
|
}
|
|
6424
|
-
|
|
6793
|
+
buildApiRequest(options, descriptor, _spec, messages) {
|
|
6425
6794
|
const contents = this.convertMessagesToContents(messages);
|
|
6426
6795
|
const generationConfig = this.buildGenerationConfig(options);
|
|
6427
6796
|
const config = {
|
|
@@ -6473,7 +6842,7 @@ var init_gemini = __esm({
|
|
|
6473
6842
|
if (message.role === "system") {
|
|
6474
6843
|
expandedMessages.push({
|
|
6475
6844
|
role: "user",
|
|
6476
|
-
content:
|
|
6845
|
+
content: extractMessageText(message.content)
|
|
6477
6846
|
});
|
|
6478
6847
|
expandedMessages.push({
|
|
6479
6848
|
role: "assistant",
|
|
@@ -6523,7 +6892,7 @@ var init_gemini = __esm({
|
|
|
6523
6892
|
* Handles text, images, and audio (Gemini supports all three).
|
|
6524
6893
|
*/
|
|
6525
6894
|
convertToGeminiParts(content) {
|
|
6526
|
-
const parts =
|
|
6895
|
+
const parts = normalizeMessageContent(content);
|
|
6527
6896
|
return parts.map((part) => {
|
|
6528
6897
|
if (part.type === "text") {
|
|
6529
6898
|
return { text: part.text };
|
|
@@ -6568,10 +6937,10 @@ var init_gemini = __esm({
|
|
|
6568
6937
|
}
|
|
6569
6938
|
return Object.keys(config).length > 0 ? config : null;
|
|
6570
6939
|
}
|
|
6571
|
-
async *
|
|
6940
|
+
async *normalizeProviderStream(iterable) {
|
|
6572
6941
|
const stream2 = iterable;
|
|
6573
6942
|
for await (const chunk of stream2) {
|
|
6574
|
-
const text3 = this.
|
|
6943
|
+
const text3 = this.extractMessageText(chunk);
|
|
6575
6944
|
if (text3) {
|
|
6576
6945
|
yield { text: text3, rawEvent: chunk };
|
|
6577
6946
|
}
|
|
@@ -6582,7 +6951,7 @@ var init_gemini = __esm({
|
|
|
6582
6951
|
}
|
|
6583
6952
|
}
|
|
6584
6953
|
}
|
|
6585
|
-
|
|
6954
|
+
extractMessageText(chunk) {
|
|
6586
6955
|
if (!chunk?.candidates) {
|
|
6587
6956
|
return "";
|
|
6588
6957
|
}
|
|
@@ -6647,7 +7016,7 @@ var init_gemini = __esm({
|
|
|
6647
7016
|
let totalChars = 0;
|
|
6648
7017
|
let mediaCount = 0;
|
|
6649
7018
|
for (const msg of messages) {
|
|
6650
|
-
const parts =
|
|
7019
|
+
const parts = normalizeMessageContent(msg.content);
|
|
6651
7020
|
for (const part of parts) {
|
|
6652
7021
|
if (part.type === "text") {
|
|
6653
7022
|
totalChars += part.text.length;
|
|
@@ -7393,7 +7762,7 @@ var init_openai = __esm({
|
|
|
7393
7762
|
format
|
|
7394
7763
|
};
|
|
7395
7764
|
}
|
|
7396
|
-
|
|
7765
|
+
buildApiRequest(options, descriptor, spec, messages) {
|
|
7397
7766
|
const { maxTokens, temperature, topP, stopSequences, extra } = options;
|
|
7398
7767
|
const supportsTemperature = spec?.metadata?.supportsTemperature !== false;
|
|
7399
7768
|
const shouldIncludeTemperature = typeof temperature === "number" && supportsTemperature;
|
|
@@ -7428,7 +7797,7 @@ var init_openai = __esm({
|
|
|
7428
7797
|
...message.name ? { name: message.name } : {}
|
|
7429
7798
|
};
|
|
7430
7799
|
}
|
|
7431
|
-
const textContent = typeof message.content === "string" ? message.content :
|
|
7800
|
+
const textContent = typeof message.content === "string" ? message.content : extractMessageText(message.content);
|
|
7432
7801
|
if (role === "system") {
|
|
7433
7802
|
return {
|
|
7434
7803
|
role: "system",
|
|
@@ -7488,7 +7857,7 @@ var init_openai = __esm({
|
|
|
7488
7857
|
const stream2 = await client.chat.completions.create(payload, signal ? { signal } : void 0);
|
|
7489
7858
|
return stream2;
|
|
7490
7859
|
}
|
|
7491
|
-
async *
|
|
7860
|
+
async *normalizeProviderStream(iterable) {
|
|
7492
7861
|
const stream2 = iterable;
|
|
7493
7862
|
for await (const chunk of stream2) {
|
|
7494
7863
|
const text3 = chunk.choices.map((choice) => choice.delta?.content ?? "").join("");
|
|
@@ -7546,9 +7915,9 @@ var init_openai = __esm({
|
|
|
7546
7915
|
tokenCount += OPENAI_MESSAGE_OVERHEAD_TOKENS;
|
|
7547
7916
|
const roleText = ROLE_MAP[message.role];
|
|
7548
7917
|
tokenCount += encoding.encode(roleText).length;
|
|
7549
|
-
const textContent =
|
|
7918
|
+
const textContent = extractMessageText(message.content);
|
|
7550
7919
|
tokenCount += encoding.encode(textContent).length;
|
|
7551
|
-
const parts =
|
|
7920
|
+
const parts = normalizeMessageContent(message.content);
|
|
7552
7921
|
for (const part of parts) {
|
|
7553
7922
|
if (part.type === "image") {
|
|
7554
7923
|
imageCount++;
|
|
@@ -7573,7 +7942,7 @@ var init_openai = __esm({
|
|
|
7573
7942
|
let totalChars = 0;
|
|
7574
7943
|
let imageCount = 0;
|
|
7575
7944
|
for (const msg of messages) {
|
|
7576
|
-
const parts =
|
|
7945
|
+
const parts = normalizeMessageContent(msg.content);
|
|
7577
7946
|
for (const part of parts) {
|
|
7578
7947
|
if (part.type === "text") {
|
|
7579
7948
|
totalChars += part.text.length;
|
|
@@ -8438,20 +8807,23 @@ var init_builder = __esm({
|
|
|
8438
8807
|
promptConfig;
|
|
8439
8808
|
gadgets = [];
|
|
8440
8809
|
initialMessages = [];
|
|
8441
|
-
|
|
8810
|
+
requestHumanInput;
|
|
8442
8811
|
gadgetStartPrefix;
|
|
8443
8812
|
gadgetEndPrefix;
|
|
8444
8813
|
gadgetArgPrefix;
|
|
8445
8814
|
textOnlyHandler;
|
|
8446
8815
|
textWithGadgetsHandler;
|
|
8447
8816
|
stopOnGadgetError;
|
|
8448
|
-
|
|
8817
|
+
canRecoverFromGadgetError;
|
|
8449
8818
|
defaultGadgetTimeoutMs;
|
|
8450
8819
|
gadgetOutputLimit;
|
|
8451
8820
|
gadgetOutputLimitPercent;
|
|
8452
8821
|
compactionConfig;
|
|
8453
8822
|
signal;
|
|
8454
8823
|
trailingMessage;
|
|
8824
|
+
subagentConfig;
|
|
8825
|
+
nestedEventCallback;
|
|
8826
|
+
parentContext;
|
|
8455
8827
|
constructor(client) {
|
|
8456
8828
|
this.client = client;
|
|
8457
8829
|
}
|
|
@@ -8542,13 +8914,13 @@ var init_builder = __esm({
|
|
|
8542
8914
|
*
|
|
8543
8915
|
* @example
|
|
8544
8916
|
* ```typescript
|
|
8545
|
-
* .
|
|
8917
|
+
* .withPromptTemplateConfig({
|
|
8546
8918
|
* mainInstruction: "Use the gadget markers below:",
|
|
8547
8919
|
* rules: ["Always use markers", "Never use function calling"]
|
|
8548
8920
|
* })
|
|
8549
8921
|
* ```
|
|
8550
8922
|
*/
|
|
8551
|
-
|
|
8923
|
+
withPromptTemplateConfig(config) {
|
|
8552
8924
|
this.promptConfig = config;
|
|
8553
8925
|
return this;
|
|
8554
8926
|
}
|
|
@@ -8628,7 +9000,7 @@ var init_builder = __esm({
|
|
|
8628
9000
|
* ```
|
|
8629
9001
|
*/
|
|
8630
9002
|
onHumanInput(handler) {
|
|
8631
|
-
this.
|
|
9003
|
+
this.requestHumanInput = handler;
|
|
8632
9004
|
return this;
|
|
8633
9005
|
}
|
|
8634
9006
|
/**
|
|
@@ -8763,9 +9135,9 @@ var init_builder = __esm({
|
|
|
8763
9135
|
* Provides fine-grained control over whether to continue after different types of errors.
|
|
8764
9136
|
* Overrides `stopOnGadgetError` when provided.
|
|
8765
9137
|
*
|
|
8766
|
-
* **Note:** This builder method configures the underlying `
|
|
9138
|
+
* **Note:** This builder method configures the underlying `canRecoverFromGadgetError` option
|
|
8767
9139
|
* in `AgentOptions`. The method is named `withErrorHandler` for better developer experience,
|
|
8768
|
-
* but maps to the `
|
|
9140
|
+
* but maps to the `canRecoverFromGadgetError` property internally.
|
|
8769
9141
|
*
|
|
8770
9142
|
* @param handler - Function that decides whether to continue after an error.
|
|
8771
9143
|
* Return `true` to continue execution, `false` to stop.
|
|
@@ -8786,7 +9158,7 @@ var init_builder = __esm({
|
|
|
8786
9158
|
* ```
|
|
8787
9159
|
*/
|
|
8788
9160
|
withErrorHandler(handler) {
|
|
8789
|
-
this.
|
|
9161
|
+
this.canRecoverFromGadgetError = handler;
|
|
8790
9162
|
return this;
|
|
8791
9163
|
}
|
|
8792
9164
|
/**
|
|
@@ -8927,6 +9299,95 @@ var init_builder = __esm({
|
|
|
8927
9299
|
this.signal = signal;
|
|
8928
9300
|
return this;
|
|
8929
9301
|
}
|
|
9302
|
+
/**
|
|
9303
|
+
* Set subagent configuration overrides.
|
|
9304
|
+
*
|
|
9305
|
+
* Subagent gadgets (like BrowseWeb) can read these settings from ExecutionContext
|
|
9306
|
+
* to inherit model and other options from the CLI configuration.
|
|
9307
|
+
*
|
|
9308
|
+
* @param config - Subagent configuration map keyed by gadget name
|
|
9309
|
+
* @returns This builder for chaining
|
|
9310
|
+
*
|
|
9311
|
+
* @example
|
|
9312
|
+
* ```typescript
|
|
9313
|
+
* .withSubagentConfig({
|
|
9314
|
+
* BrowseWeb: { model: "inherit", maxIterations: 20, headless: true },
|
|
9315
|
+
* CodeAnalyzer: { model: "sonnet", maxIterations: 10 }
|
|
9316
|
+
* })
|
|
9317
|
+
* ```
|
|
9318
|
+
*/
|
|
9319
|
+
withSubagentConfig(config) {
|
|
9320
|
+
this.subagentConfig = config;
|
|
9321
|
+
return this;
|
|
9322
|
+
}
|
|
9323
|
+
/**
|
|
9324
|
+
* Set the callback for nested subagent events.
|
|
9325
|
+
*
|
|
9326
|
+
* Subagent gadgets (like BrowseWeb) can use ExecutionContext.onNestedEvent
|
|
9327
|
+
* to report their internal LLM calls and gadget executions in real-time.
|
|
9328
|
+
* This callback receives those events, enabling hierarchical progress display.
|
|
9329
|
+
*
|
|
9330
|
+
* @param callback - Function to handle nested agent events
|
|
9331
|
+
* @returns This builder for chaining
|
|
9332
|
+
*
|
|
9333
|
+
* @example
|
|
9334
|
+
* ```typescript
|
|
9335
|
+
* .withNestedEventCallback((event) => {
|
|
9336
|
+
* if (event.type === "llm_call_start") {
|
|
9337
|
+
* console.log(` Nested LLM #${event.event.iteration} starting...`);
|
|
9338
|
+
* } else if (event.type === "gadget_call") {
|
|
9339
|
+
* console.log(` ⏵ ${event.event.call.gadgetName}...`);
|
|
9340
|
+
* }
|
|
9341
|
+
* })
|
|
9342
|
+
* ```
|
|
9343
|
+
*/
|
|
9344
|
+
withNestedEventCallback(callback) {
|
|
9345
|
+
this.nestedEventCallback = callback;
|
|
9346
|
+
return this;
|
|
9347
|
+
}
|
|
9348
|
+
/**
|
|
9349
|
+
* Enable automatic nested event forwarding to parent agent.
|
|
9350
|
+
*
|
|
9351
|
+
* When building a subagent inside a gadget, call this method to automatically
|
|
9352
|
+
* forward all LLM calls and gadget events to the parent agent. This enables
|
|
9353
|
+
* hierarchical progress display without any manual event handling.
|
|
9354
|
+
*
|
|
9355
|
+
* The method extracts `invocationId` and `onNestedEvent` from the execution
|
|
9356
|
+
* context and sets up automatic forwarding via hooks and event wrapping.
|
|
9357
|
+
*
|
|
9358
|
+
* @param ctx - ExecutionContext passed to the gadget's execute() method
|
|
9359
|
+
* @param depth - Nesting depth (default: 1 for direct child)
|
|
9360
|
+
* @returns This builder for chaining
|
|
9361
|
+
*
|
|
9362
|
+
* @example
|
|
9363
|
+
* ```typescript
|
|
9364
|
+
* // In a subagent gadget like BrowseWeb - ONE LINE enables auto-forwarding:
|
|
9365
|
+
* execute: async (params, ctx) => {
|
|
9366
|
+
* const agent = new AgentBuilder(client)
|
|
9367
|
+
* .withModel(model)
|
|
9368
|
+
* .withGadgets(Navigate, Click, Screenshot)
|
|
9369
|
+
* .withParentContext(ctx) // <-- This is all you need!
|
|
9370
|
+
* .ask(params.task);
|
|
9371
|
+
*
|
|
9372
|
+
* for await (const event of agent.run()) {
|
|
9373
|
+
* // Events automatically forwarded - just process normally
|
|
9374
|
+
* if (event.type === "text") {
|
|
9375
|
+
* result = event.content;
|
|
9376
|
+
* }
|
|
9377
|
+
* }
|
|
9378
|
+
* }
|
|
9379
|
+
* ```
|
|
9380
|
+
*/
|
|
9381
|
+
withParentContext(ctx, depth = 1) {
|
|
9382
|
+
if (ctx.onNestedEvent && ctx.invocationId) {
|
|
9383
|
+
this.parentContext = {
|
|
9384
|
+
invocationId: ctx.invocationId,
|
|
9385
|
+
onNestedEvent: ctx.onNestedEvent,
|
|
9386
|
+
depth
|
|
9387
|
+
};
|
|
9388
|
+
}
|
|
9389
|
+
return this;
|
|
9390
|
+
}
|
|
8930
9391
|
/**
|
|
8931
9392
|
* Add an ephemeral trailing message that appears at the end of each LLM request.
|
|
8932
9393
|
*
|
|
@@ -8994,14 +9455,58 @@ ${endPrefix}`
|
|
|
8994
9455
|
return this;
|
|
8995
9456
|
}
|
|
8996
9457
|
/**
|
|
8997
|
-
* Compose the final hooks, including
|
|
9458
|
+
* Compose the final hooks, including:
|
|
9459
|
+
* - Trailing message injection (if configured)
|
|
9460
|
+
* - Nested event forwarding for LLM calls (if parentContext is set)
|
|
8998
9461
|
*/
|
|
8999
9462
|
composeHooks() {
|
|
9463
|
+
let hooks = this.hooks;
|
|
9464
|
+
if (this.parentContext) {
|
|
9465
|
+
const { invocationId, onNestedEvent, depth } = this.parentContext;
|
|
9466
|
+
const existingOnLLMCallStart = hooks?.observers?.onLLMCallStart;
|
|
9467
|
+
const existingOnLLMCallComplete = hooks?.observers?.onLLMCallComplete;
|
|
9468
|
+
hooks = {
|
|
9469
|
+
...hooks,
|
|
9470
|
+
observers: {
|
|
9471
|
+
...hooks?.observers,
|
|
9472
|
+
onLLMCallStart: async (context) => {
|
|
9473
|
+
onNestedEvent({
|
|
9474
|
+
type: "llm_call_start",
|
|
9475
|
+
gadgetInvocationId: invocationId,
|
|
9476
|
+
depth,
|
|
9477
|
+
event: {
|
|
9478
|
+
iteration: context.iteration,
|
|
9479
|
+
model: context.options.model
|
|
9480
|
+
}
|
|
9481
|
+
});
|
|
9482
|
+
if (existingOnLLMCallStart) {
|
|
9483
|
+
await existingOnLLMCallStart(context);
|
|
9484
|
+
}
|
|
9485
|
+
},
|
|
9486
|
+
onLLMCallComplete: async (context) => {
|
|
9487
|
+
onNestedEvent({
|
|
9488
|
+
type: "llm_call_end",
|
|
9489
|
+
gadgetInvocationId: invocationId,
|
|
9490
|
+
depth,
|
|
9491
|
+
event: {
|
|
9492
|
+
iteration: context.iteration,
|
|
9493
|
+
model: context.options.model,
|
|
9494
|
+
outputTokens: context.usage?.outputTokens,
|
|
9495
|
+
finishReason: context.finishReason
|
|
9496
|
+
}
|
|
9497
|
+
});
|
|
9498
|
+
if (existingOnLLMCallComplete) {
|
|
9499
|
+
await existingOnLLMCallComplete(context);
|
|
9500
|
+
}
|
|
9501
|
+
}
|
|
9502
|
+
}
|
|
9503
|
+
};
|
|
9504
|
+
}
|
|
9000
9505
|
if (!this.trailingMessage) {
|
|
9001
|
-
return
|
|
9506
|
+
return hooks;
|
|
9002
9507
|
}
|
|
9003
9508
|
const trailingMsg = this.trailingMessage;
|
|
9004
|
-
const existingBeforeLLMCall =
|
|
9509
|
+
const existingBeforeLLMCall = hooks?.controllers?.beforeLLMCall;
|
|
9005
9510
|
const trailingMessageController = async (ctx) => {
|
|
9006
9511
|
const result = existingBeforeLLMCall ? await existingBeforeLLMCall(ctx) : { action: "proceed" };
|
|
9007
9512
|
if (result.action === "skip") {
|
|
@@ -9016,9 +9521,9 @@ ${endPrefix}`
|
|
|
9016
9521
|
};
|
|
9017
9522
|
};
|
|
9018
9523
|
return {
|
|
9019
|
-
...
|
|
9524
|
+
...hooks,
|
|
9020
9525
|
controllers: {
|
|
9021
|
-
...
|
|
9526
|
+
...hooks?.controllers,
|
|
9022
9527
|
beforeLLMCall: trailingMessageController
|
|
9023
9528
|
}
|
|
9024
9529
|
};
|
|
@@ -9079,6 +9584,19 @@ ${endPrefix}`
|
|
|
9079
9584
|
this.client = new LLMistClass();
|
|
9080
9585
|
}
|
|
9081
9586
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
9587
|
+
let onNestedEvent = this.nestedEventCallback;
|
|
9588
|
+
if (this.parentContext) {
|
|
9589
|
+
const { invocationId, onNestedEvent: parentCallback, depth } = this.parentContext;
|
|
9590
|
+
const existingCallback = this.nestedEventCallback;
|
|
9591
|
+
onNestedEvent = (event) => {
|
|
9592
|
+
parentCallback({
|
|
9593
|
+
...event,
|
|
9594
|
+
gadgetInvocationId: invocationId,
|
|
9595
|
+
depth: event.depth + depth
|
|
9596
|
+
});
|
|
9597
|
+
existingCallback?.(event);
|
|
9598
|
+
};
|
|
9599
|
+
}
|
|
9082
9600
|
return {
|
|
9083
9601
|
client: this.client,
|
|
9084
9602
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -9091,19 +9609,21 @@ ${endPrefix}`
|
|
|
9091
9609
|
hooks: this.composeHooks(),
|
|
9092
9610
|
promptConfig: this.promptConfig,
|
|
9093
9611
|
initialMessages: this.initialMessages,
|
|
9094
|
-
|
|
9612
|
+
requestHumanInput: this.requestHumanInput,
|
|
9095
9613
|
gadgetStartPrefix: this.gadgetStartPrefix,
|
|
9096
9614
|
gadgetEndPrefix: this.gadgetEndPrefix,
|
|
9097
9615
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
9098
9616
|
textOnlyHandler: this.textOnlyHandler,
|
|
9099
9617
|
textWithGadgetsHandler: this.textWithGadgetsHandler,
|
|
9100
9618
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
9101
|
-
|
|
9619
|
+
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
9102
9620
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
9103
9621
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
9104
9622
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
9105
9623
|
compactionConfig: this.compactionConfig,
|
|
9106
|
-
signal: this.signal
|
|
9624
|
+
signal: this.signal,
|
|
9625
|
+
subagentConfig: this.subagentConfig,
|
|
9626
|
+
onNestedEvent
|
|
9107
9627
|
};
|
|
9108
9628
|
}
|
|
9109
9629
|
ask(userPrompt) {
|
|
@@ -9260,6 +9780,19 @@ ${endPrefix}`
|
|
|
9260
9780
|
this.client = new LLMistClass();
|
|
9261
9781
|
}
|
|
9262
9782
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
9783
|
+
let onNestedEvent = this.nestedEventCallback;
|
|
9784
|
+
if (this.parentContext) {
|
|
9785
|
+
const { invocationId, onNestedEvent: parentCallback, depth } = this.parentContext;
|
|
9786
|
+
const existingCallback = this.nestedEventCallback;
|
|
9787
|
+
onNestedEvent = (event) => {
|
|
9788
|
+
parentCallback({
|
|
9789
|
+
...event,
|
|
9790
|
+
gadgetInvocationId: invocationId,
|
|
9791
|
+
depth: event.depth + depth
|
|
9792
|
+
});
|
|
9793
|
+
existingCallback?.(event);
|
|
9794
|
+
};
|
|
9795
|
+
}
|
|
9263
9796
|
const options = {
|
|
9264
9797
|
client: this.client,
|
|
9265
9798
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -9272,19 +9805,21 @@ ${endPrefix}`
|
|
|
9272
9805
|
hooks: this.composeHooks(),
|
|
9273
9806
|
promptConfig: this.promptConfig,
|
|
9274
9807
|
initialMessages: this.initialMessages,
|
|
9275
|
-
|
|
9808
|
+
requestHumanInput: this.requestHumanInput,
|
|
9276
9809
|
gadgetStartPrefix: this.gadgetStartPrefix,
|
|
9277
9810
|
gadgetEndPrefix: this.gadgetEndPrefix,
|
|
9278
9811
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
9279
9812
|
textOnlyHandler: this.textOnlyHandler,
|
|
9280
9813
|
textWithGadgetsHandler: this.textWithGadgetsHandler,
|
|
9281
9814
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
9282
|
-
|
|
9815
|
+
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
9283
9816
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
9284
9817
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
9285
9818
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
9286
9819
|
compactionConfig: this.compactionConfig,
|
|
9287
|
-
signal: this.signal
|
|
9820
|
+
signal: this.signal,
|
|
9821
|
+
subagentConfig: this.subagentConfig,
|
|
9822
|
+
onNestedEvent
|
|
9288
9823
|
};
|
|
9289
9824
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
9290
9825
|
}
|
|
@@ -9295,11 +9830,10 @@ ${endPrefix}`
|
|
|
9295
9830
|
// src/index.ts
|
|
9296
9831
|
var index_exports = {};
|
|
9297
9832
|
__export(index_exports, {
|
|
9298
|
-
|
|
9833
|
+
AbortException: () => AbortException,
|
|
9834
|
+
AbstractGadget: () => AbstractGadget,
|
|
9299
9835
|
AgentBuilder: () => AgentBuilder,
|
|
9300
9836
|
AnthropicMessagesProvider: () => AnthropicMessagesProvider,
|
|
9301
|
-
BaseGadget: () => BaseGadget,
|
|
9302
|
-
BreakLoopException: () => BreakLoopException,
|
|
9303
9837
|
CompactionManager: () => CompactionManager,
|
|
9304
9838
|
ConversationManager: () => ConversationManager,
|
|
9305
9839
|
DEFAULT_COMPACTION_CONFIG: () => DEFAULT_COMPACTION_CONFIG,
|
|
@@ -9307,12 +9841,13 @@ __export(index_exports, {
|
|
|
9307
9841
|
DEFAULT_PROMPTS: () => DEFAULT_PROMPTS,
|
|
9308
9842
|
DEFAULT_SUMMARIZATION_PROMPT: () => DEFAULT_SUMMARIZATION_PROMPT,
|
|
9309
9843
|
Gadget: () => Gadget,
|
|
9844
|
+
GadgetCallParser: () => GadgetCallParser,
|
|
9310
9845
|
GadgetExecutor: () => GadgetExecutor,
|
|
9311
9846
|
GadgetOutputStore: () => GadgetOutputStore,
|
|
9312
9847
|
GadgetRegistry: () => GadgetRegistry,
|
|
9313
9848
|
GeminiGenerativeProvider: () => GeminiGenerativeProvider,
|
|
9314
9849
|
HookPresets: () => HookPresets,
|
|
9315
|
-
|
|
9850
|
+
HumanInputRequiredException: () => HumanInputRequiredException,
|
|
9316
9851
|
HybridStrategy: () => HybridStrategy,
|
|
9317
9852
|
LLMMessageBuilder: () => LLMMessageBuilder,
|
|
9318
9853
|
LLMist: () => LLMist,
|
|
@@ -9325,9 +9860,10 @@ __export(index_exports, {
|
|
|
9325
9860
|
ModelRegistry: () => ModelRegistry,
|
|
9326
9861
|
OpenAIChatProvider: () => OpenAIChatProvider,
|
|
9327
9862
|
SlidingWindowStrategy: () => SlidingWindowStrategy,
|
|
9328
|
-
StreamParser: () => StreamParser,
|
|
9329
9863
|
StreamProcessor: () => StreamProcessor,
|
|
9330
9864
|
SummarizationStrategy: () => SummarizationStrategy,
|
|
9865
|
+
TaskCompletionSignal: () => TaskCompletionSignal,
|
|
9866
|
+
TimeoutException: () => TimeoutException,
|
|
9331
9867
|
audioFromBase64: () => audioFromBase64,
|
|
9332
9868
|
audioFromBuffer: () => audioFromBuffer,
|
|
9333
9869
|
collectEvents: () => collectEvents,
|
|
@@ -9339,7 +9875,7 @@ __export(index_exports, {
|
|
|
9339
9875
|
createGeminiProviderFromEnv: () => createGeminiProviderFromEnv,
|
|
9340
9876
|
createHints: () => createHints,
|
|
9341
9877
|
createLogger: () => createLogger,
|
|
9342
|
-
|
|
9878
|
+
createMediaOutput: () => createMediaOutput,
|
|
9343
9879
|
createMockAdapter: () => createMockAdapter,
|
|
9344
9880
|
createMockClient: () => createMockClient,
|
|
9345
9881
|
createMockStream: () => createMockStream,
|
|
@@ -9349,7 +9885,7 @@ __export(index_exports, {
|
|
|
9349
9885
|
detectAudioMimeType: () => detectAudioMimeType,
|
|
9350
9886
|
detectImageMimeType: () => detectImageMimeType,
|
|
9351
9887
|
discoverProviderAdapters: () => discoverProviderAdapters,
|
|
9352
|
-
|
|
9888
|
+
extractMessageText: () => extractMessageText,
|
|
9353
9889
|
getMockManager: () => getMockManager,
|
|
9354
9890
|
getModelId: () => getModelId,
|
|
9355
9891
|
getProvider: () => getProvider,
|
|
@@ -9363,7 +9899,7 @@ __export(index_exports, {
|
|
|
9363
9899
|
isTextPart: () => isTextPart,
|
|
9364
9900
|
iterationProgressHint: () => iterationProgressHint,
|
|
9365
9901
|
mockLLM: () => mockLLM,
|
|
9366
|
-
|
|
9902
|
+
normalizeMessageContent: () => normalizeMessageContent,
|
|
9367
9903
|
parallelGadgetHint: () => parallelGadgetHint,
|
|
9368
9904
|
parseDataUrl: () => parseDataUrl,
|
|
9369
9905
|
resolveHintTemplate: () => resolveHintTemplate,
|
|
@@ -10293,7 +10829,7 @@ init_registry();
|
|
|
10293
10829
|
// src/gadgets/typed-gadget.ts
|
|
10294
10830
|
init_gadget();
|
|
10295
10831
|
function Gadget(config) {
|
|
10296
|
-
class GadgetBase extends
|
|
10832
|
+
class GadgetBase extends AbstractGadget {
|
|
10297
10833
|
description = config.description;
|
|
10298
10834
|
parameterSchema = config.schema;
|
|
10299
10835
|
name = config.name;
|
|
@@ -10313,7 +10849,7 @@ function Gadget(config) {
|
|
|
10313
10849
|
|
|
10314
10850
|
// src/gadgets/helpers.ts
|
|
10315
10851
|
init_input_content();
|
|
10316
|
-
function
|
|
10852
|
+
function createMediaOutput(kind, data, mimeType, options) {
|
|
10317
10853
|
const buffer = data instanceof Buffer ? data : Buffer.from(data);
|
|
10318
10854
|
return {
|
|
10319
10855
|
kind,
|
|
@@ -11017,7 +11553,7 @@ var MockBuilder = class {
|
|
|
11017
11553
|
whenMessageContains(text3) {
|
|
11018
11554
|
this.matchers.push(
|
|
11019
11555
|
(ctx) => ctx.messages.some(
|
|
11020
|
-
(msg) =>
|
|
11556
|
+
(msg) => extractMessageText(msg.content).toLowerCase().includes(text3.toLowerCase())
|
|
11021
11557
|
)
|
|
11022
11558
|
);
|
|
11023
11559
|
return this;
|
|
@@ -11032,7 +11568,7 @@ var MockBuilder = class {
|
|
|
11032
11568
|
this.matchers.push((ctx) => {
|
|
11033
11569
|
const lastMsg = ctx.messages[ctx.messages.length - 1];
|
|
11034
11570
|
if (!lastMsg) return false;
|
|
11035
|
-
return
|
|
11571
|
+
return extractMessageText(lastMsg.content).toLowerCase().includes(text3.toLowerCase());
|
|
11036
11572
|
});
|
|
11037
11573
|
return this;
|
|
11038
11574
|
}
|
|
@@ -11043,7 +11579,7 @@ var MockBuilder = class {
|
|
|
11043
11579
|
* mockLLM().whenMessageMatches(/calculate \d+/)
|
|
11044
11580
|
*/
|
|
11045
11581
|
whenMessageMatches(regex) {
|
|
11046
|
-
this.matchers.push((ctx) => ctx.messages.some((msg) => regex.test(
|
|
11582
|
+
this.matchers.push((ctx) => ctx.messages.some((msg) => regex.test(extractMessageText(msg.content))));
|
|
11047
11583
|
return this;
|
|
11048
11584
|
}
|
|
11049
11585
|
/**
|
|
@@ -11055,7 +11591,7 @@ var MockBuilder = class {
|
|
|
11055
11591
|
whenRoleContains(role, text3) {
|
|
11056
11592
|
this.matchers.push(
|
|
11057
11593
|
(ctx) => ctx.messages.some(
|
|
11058
|
-
(msg) => msg.role === role &&
|
|
11594
|
+
(msg) => msg.role === role && extractMessageText(msg.content).toLowerCase().includes(text3.toLowerCase())
|
|
11059
11595
|
)
|
|
11060
11596
|
);
|
|
11061
11597
|
return this;
|
|
@@ -11460,11 +11996,10 @@ function createMockClient(options) {
|
|
|
11460
11996
|
init_gadget();
|
|
11461
11997
|
// Annotate the CommonJS export names for ESM import in node:
|
|
11462
11998
|
0 && (module.exports = {
|
|
11463
|
-
|
|
11999
|
+
AbortException,
|
|
12000
|
+
AbstractGadget,
|
|
11464
12001
|
AgentBuilder,
|
|
11465
12002
|
AnthropicMessagesProvider,
|
|
11466
|
-
BaseGadget,
|
|
11467
|
-
BreakLoopException,
|
|
11468
12003
|
CompactionManager,
|
|
11469
12004
|
ConversationManager,
|
|
11470
12005
|
DEFAULT_COMPACTION_CONFIG,
|
|
@@ -11472,12 +12007,13 @@ init_gadget();
|
|
|
11472
12007
|
DEFAULT_PROMPTS,
|
|
11473
12008
|
DEFAULT_SUMMARIZATION_PROMPT,
|
|
11474
12009
|
Gadget,
|
|
12010
|
+
GadgetCallParser,
|
|
11475
12011
|
GadgetExecutor,
|
|
11476
12012
|
GadgetOutputStore,
|
|
11477
12013
|
GadgetRegistry,
|
|
11478
12014
|
GeminiGenerativeProvider,
|
|
11479
12015
|
HookPresets,
|
|
11480
|
-
|
|
12016
|
+
HumanInputRequiredException,
|
|
11481
12017
|
HybridStrategy,
|
|
11482
12018
|
LLMMessageBuilder,
|
|
11483
12019
|
LLMist,
|
|
@@ -11490,9 +12026,10 @@ init_gadget();
|
|
|
11490
12026
|
ModelRegistry,
|
|
11491
12027
|
OpenAIChatProvider,
|
|
11492
12028
|
SlidingWindowStrategy,
|
|
11493
|
-
StreamParser,
|
|
11494
12029
|
StreamProcessor,
|
|
11495
12030
|
SummarizationStrategy,
|
|
12031
|
+
TaskCompletionSignal,
|
|
12032
|
+
TimeoutException,
|
|
11496
12033
|
audioFromBase64,
|
|
11497
12034
|
audioFromBuffer,
|
|
11498
12035
|
collectEvents,
|
|
@@ -11504,7 +12041,7 @@ init_gadget();
|
|
|
11504
12041
|
createGeminiProviderFromEnv,
|
|
11505
12042
|
createHints,
|
|
11506
12043
|
createLogger,
|
|
11507
|
-
|
|
12044
|
+
createMediaOutput,
|
|
11508
12045
|
createMockAdapter,
|
|
11509
12046
|
createMockClient,
|
|
11510
12047
|
createMockStream,
|
|
@@ -11514,7 +12051,7 @@ init_gadget();
|
|
|
11514
12051
|
detectAudioMimeType,
|
|
11515
12052
|
detectImageMimeType,
|
|
11516
12053
|
discoverProviderAdapters,
|
|
11517
|
-
|
|
12054
|
+
extractMessageText,
|
|
11518
12055
|
getMockManager,
|
|
11519
12056
|
getModelId,
|
|
11520
12057
|
getProvider,
|
|
@@ -11528,7 +12065,7 @@ init_gadget();
|
|
|
11528
12065
|
isTextPart,
|
|
11529
12066
|
iterationProgressHint,
|
|
11530
12067
|
mockLLM,
|
|
11531
|
-
|
|
12068
|
+
normalizeMessageContent,
|
|
11532
12069
|
parallelGadgetHint,
|
|
11533
12070
|
parseDataUrl,
|
|
11534
12071
|
resolveHintTemplate,
|