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
|
@@ -320,13 +320,13 @@ var init_prompt_config = __esm({
|
|
|
320
320
|
});
|
|
321
321
|
|
|
322
322
|
// src/core/messages.ts
|
|
323
|
-
function
|
|
323
|
+
function normalizeMessageContent(content) {
|
|
324
324
|
if (typeof content === "string") {
|
|
325
325
|
return [{ type: "text", text: content }];
|
|
326
326
|
}
|
|
327
327
|
return content;
|
|
328
328
|
}
|
|
329
|
-
function
|
|
329
|
+
function extractMessageText(content) {
|
|
330
330
|
if (typeof content === "string") {
|
|
331
331
|
return content;
|
|
332
332
|
}
|
|
@@ -686,7 +686,17 @@ Produces: { "items": ["first", "second"] }`);
|
|
|
686
686
|
this.messages.push({ role: "user", content: parts });
|
|
687
687
|
return this;
|
|
688
688
|
}
|
|
689
|
-
|
|
689
|
+
/**
|
|
690
|
+
* Record a gadget execution result in the message history.
|
|
691
|
+
* Creates an assistant message with the gadget invocation and a user message with the result.
|
|
692
|
+
*
|
|
693
|
+
* @param gadget - Name of the gadget that was executed
|
|
694
|
+
* @param parameters - Parameters that were passed to the gadget
|
|
695
|
+
* @param result - Text result from the gadget execution
|
|
696
|
+
* @param media - Optional media outputs from the gadget
|
|
697
|
+
* @param mediaIds - Optional IDs for the media outputs
|
|
698
|
+
*/
|
|
699
|
+
addGadgetCallResult(gadget, parameters, result, media, mediaIds) {
|
|
690
700
|
const paramStr = this.formatBlockParameters(parameters, "");
|
|
691
701
|
this.messages.push({
|
|
692
702
|
role: "assistant",
|
|
@@ -1267,21 +1277,21 @@ var init_media_store = __esm({
|
|
|
1267
1277
|
});
|
|
1268
1278
|
|
|
1269
1279
|
// src/gadgets/exceptions.ts
|
|
1270
|
-
var
|
|
1280
|
+
var TaskCompletionSignal, HumanInputRequiredException, TimeoutException, AbortException;
|
|
1271
1281
|
var init_exceptions = __esm({
|
|
1272
1282
|
"src/gadgets/exceptions.ts"() {
|
|
1273
1283
|
"use strict";
|
|
1274
|
-
|
|
1284
|
+
TaskCompletionSignal = class extends Error {
|
|
1275
1285
|
constructor(message) {
|
|
1276
1286
|
super(message ?? "Agent loop terminated by gadget");
|
|
1277
|
-
this.name = "
|
|
1287
|
+
this.name = "TaskCompletionSignal";
|
|
1278
1288
|
}
|
|
1279
1289
|
};
|
|
1280
|
-
|
|
1290
|
+
HumanInputRequiredException = class extends Error {
|
|
1281
1291
|
question;
|
|
1282
1292
|
constructor(question) {
|
|
1283
1293
|
super(`Human input required: ${question}`);
|
|
1284
|
-
this.name = "
|
|
1294
|
+
this.name = "HumanInputRequiredException";
|
|
1285
1295
|
this.question = question;
|
|
1286
1296
|
}
|
|
1287
1297
|
};
|
|
@@ -1295,10 +1305,10 @@ var init_exceptions = __esm({
|
|
|
1295
1305
|
this.timeoutMs = timeoutMs;
|
|
1296
1306
|
}
|
|
1297
1307
|
};
|
|
1298
|
-
|
|
1308
|
+
AbortException = class extends Error {
|
|
1299
1309
|
constructor(message) {
|
|
1300
1310
|
super(message || "Gadget execution was aborted");
|
|
1301
|
-
this.name = "
|
|
1311
|
+
this.name = "AbortException";
|
|
1302
1312
|
}
|
|
1303
1313
|
};
|
|
1304
1314
|
}
|
|
@@ -1387,7 +1397,7 @@ var init_schema_to_json = __esm({
|
|
|
1387
1397
|
});
|
|
1388
1398
|
|
|
1389
1399
|
// src/gadgets/gadget.ts
|
|
1390
|
-
function
|
|
1400
|
+
function formatParamsForBlockExample(params, prefix = "", argPrefix = GADGET_ARG_PREFIX) {
|
|
1391
1401
|
const lines = [];
|
|
1392
1402
|
for (const [key, value] of Object.entries(params)) {
|
|
1393
1403
|
const fullPath = prefix ? `${prefix}/${key}` : key;
|
|
@@ -1395,14 +1405,14 @@ function formatParamsAsBlock(params, prefix = "", argPrefix = GADGET_ARG_PREFIX)
|
|
|
1395
1405
|
value.forEach((item, index) => {
|
|
1396
1406
|
const itemPath = `${fullPath}/${index}`;
|
|
1397
1407
|
if (typeof item === "object" && item !== null) {
|
|
1398
|
-
lines.push(
|
|
1408
|
+
lines.push(formatParamsForBlockExample(item, itemPath, argPrefix));
|
|
1399
1409
|
} else {
|
|
1400
1410
|
lines.push(`${argPrefix}${itemPath}`);
|
|
1401
1411
|
lines.push(String(item));
|
|
1402
1412
|
}
|
|
1403
1413
|
});
|
|
1404
1414
|
} else if (typeof value === "object" && value !== null) {
|
|
1405
|
-
lines.push(
|
|
1415
|
+
lines.push(formatParamsForBlockExample(value, fullPath, argPrefix));
|
|
1406
1416
|
} else {
|
|
1407
1417
|
lines.push(`${argPrefix}${fullPath}`);
|
|
1408
1418
|
lines.push(String(value));
|
|
@@ -1491,7 +1501,7 @@ function formatSchemaAsPlainText(schema, indent = "", atRoot = true) {
|
|
|
1491
1501
|
}
|
|
1492
1502
|
return lines.join("\n");
|
|
1493
1503
|
}
|
|
1494
|
-
var
|
|
1504
|
+
var AbstractGadget;
|
|
1495
1505
|
var init_gadget = __esm({
|
|
1496
1506
|
"src/gadgets/gadget.ts"() {
|
|
1497
1507
|
"use strict";
|
|
@@ -1499,7 +1509,7 @@ var init_gadget = __esm({
|
|
|
1499
1509
|
init_exceptions();
|
|
1500
1510
|
init_schema_to_json();
|
|
1501
1511
|
init_schema_validator();
|
|
1502
|
-
|
|
1512
|
+
AbstractGadget = class {
|
|
1503
1513
|
/**
|
|
1504
1514
|
* The name of the gadget. Used for identification when LLM calls it.
|
|
1505
1515
|
* If not provided, defaults to the class name.
|
|
@@ -1527,14 +1537,14 @@ var init_gadget = __esm({
|
|
|
1527
1537
|
*/
|
|
1528
1538
|
examples;
|
|
1529
1539
|
/**
|
|
1530
|
-
* Throws an
|
|
1540
|
+
* Throws an AbortException if the execution has been aborted.
|
|
1531
1541
|
*
|
|
1532
1542
|
* Call this at key checkpoints in long-running gadgets to allow early exit
|
|
1533
1543
|
* when the gadget has been cancelled (e.g., due to timeout). This enables
|
|
1534
1544
|
* resource cleanup and prevents unnecessary work after cancellation.
|
|
1535
1545
|
*
|
|
1536
1546
|
* @param ctx - The execution context containing the abort signal
|
|
1537
|
-
* @throws
|
|
1547
|
+
* @throws AbortException if ctx.signal.aborted is true
|
|
1538
1548
|
*
|
|
1539
1549
|
* @example
|
|
1540
1550
|
* ```typescript
|
|
@@ -1559,7 +1569,7 @@ var init_gadget = __esm({
|
|
|
1559
1569
|
*/
|
|
1560
1570
|
throwIfAborted(ctx) {
|
|
1561
1571
|
if (ctx?.signal?.aborted) {
|
|
1562
|
-
throw new
|
|
1572
|
+
throw new AbortException();
|
|
1563
1573
|
}
|
|
1564
1574
|
}
|
|
1565
1575
|
/**
|
|
@@ -1701,7 +1711,7 @@ var init_gadget = __esm({
|
|
|
1701
1711
|
}
|
|
1702
1712
|
parts.push(`${effectiveStartPrefix}${gadgetName}`);
|
|
1703
1713
|
parts.push(
|
|
1704
|
-
|
|
1714
|
+
formatParamsForBlockExample(example.params, "", effectiveArgPrefix)
|
|
1705
1715
|
);
|
|
1706
1716
|
parts.push(effectiveEndPrefix);
|
|
1707
1717
|
if (example.output !== void 0) {
|
|
@@ -1719,7 +1729,7 @@ var init_gadget = __esm({
|
|
|
1719
1729
|
|
|
1720
1730
|
// src/gadgets/create-gadget.ts
|
|
1721
1731
|
function createGadget(config) {
|
|
1722
|
-
class DynamicGadget extends
|
|
1732
|
+
class DynamicGadget extends AbstractGadget {
|
|
1723
1733
|
name = config.name;
|
|
1724
1734
|
description = config.description;
|
|
1725
1735
|
parameterSchema = config.schema;
|
|
@@ -2357,8 +2367,8 @@ var init_conversation_manager = __esm({
|
|
|
2357
2367
|
addAssistantMessage(content) {
|
|
2358
2368
|
this.historyBuilder.addAssistant(content);
|
|
2359
2369
|
}
|
|
2360
|
-
|
|
2361
|
-
this.historyBuilder.
|
|
2370
|
+
addGadgetCallResult(gadgetName, parameters, result, media, mediaIds) {
|
|
2371
|
+
this.historyBuilder.addGadgetCallResult(gadgetName, parameters, result, media, mediaIds);
|
|
2362
2372
|
}
|
|
2363
2373
|
getMessages() {
|
|
2364
2374
|
return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];
|
|
@@ -2378,7 +2388,7 @@ var init_conversation_manager = __esm({
|
|
|
2378
2388
|
if (msg.role === "user") {
|
|
2379
2389
|
this.historyBuilder.addUser(msg.content);
|
|
2380
2390
|
} else if (msg.role === "assistant") {
|
|
2381
|
-
this.historyBuilder.addAssistant(
|
|
2391
|
+
this.historyBuilder.addAssistant(extractMessageText(msg.content));
|
|
2382
2392
|
}
|
|
2383
2393
|
}
|
|
2384
2394
|
}
|
|
@@ -3258,12 +3268,12 @@ var init_cost_reporting_client = __esm({
|
|
|
3258
3268
|
});
|
|
3259
3269
|
|
|
3260
3270
|
// src/gadgets/error-formatter.ts
|
|
3261
|
-
var
|
|
3271
|
+
var GadgetExecutionErrorFormatter;
|
|
3262
3272
|
var init_error_formatter = __esm({
|
|
3263
3273
|
"src/gadgets/error-formatter.ts"() {
|
|
3264
3274
|
"use strict";
|
|
3265
3275
|
init_constants();
|
|
3266
|
-
|
|
3276
|
+
GadgetExecutionErrorFormatter = class {
|
|
3267
3277
|
argPrefix;
|
|
3268
3278
|
startPrefix;
|
|
3269
3279
|
endPrefix;
|
|
@@ -3349,16 +3359,16 @@ function stripMarkdownFences(content) {
|
|
|
3349
3359
|
cleaned = cleaned.replace(closingFence, "");
|
|
3350
3360
|
return cleaned.trim();
|
|
3351
3361
|
}
|
|
3352
|
-
var globalInvocationCounter,
|
|
3362
|
+
var globalInvocationCounter, GadgetCallParser;
|
|
3353
3363
|
var init_parser = __esm({
|
|
3354
3364
|
"src/gadgets/parser.ts"() {
|
|
3355
3365
|
"use strict";
|
|
3356
3366
|
init_constants();
|
|
3357
3367
|
init_block_params();
|
|
3358
3368
|
globalInvocationCounter = 0;
|
|
3359
|
-
|
|
3369
|
+
GadgetCallParser = class {
|
|
3360
3370
|
buffer = "";
|
|
3361
|
-
|
|
3371
|
+
lastEmittedTextOffset = 0;
|
|
3362
3372
|
startPrefix;
|
|
3363
3373
|
endPrefix;
|
|
3364
3374
|
argPrefix;
|
|
@@ -3367,16 +3377,20 @@ var init_parser = __esm({
|
|
|
3367
3377
|
this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
|
|
3368
3378
|
this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
|
|
3369
3379
|
}
|
|
3370
|
-
|
|
3371
|
-
|
|
3380
|
+
/**
|
|
3381
|
+
* Extract and consume text up to the given index.
|
|
3382
|
+
* Returns undefined if no meaningful text to emit.
|
|
3383
|
+
*/
|
|
3384
|
+
extractTextSegment(index) {
|
|
3385
|
+
if (index <= this.lastEmittedTextOffset) {
|
|
3372
3386
|
return void 0;
|
|
3373
3387
|
}
|
|
3374
|
-
const segment = this.buffer.slice(this.
|
|
3375
|
-
this.
|
|
3388
|
+
const segment = this.buffer.slice(this.lastEmittedTextOffset, index);
|
|
3389
|
+
this.lastEmittedTextOffset = index;
|
|
3376
3390
|
return segment.trim().length > 0 ? segment : void 0;
|
|
3377
3391
|
}
|
|
3378
3392
|
/**
|
|
3379
|
-
* Parse gadget
|
|
3393
|
+
* Parse gadget invocation metadata from the header line.
|
|
3380
3394
|
*
|
|
3381
3395
|
* Supported formats:
|
|
3382
3396
|
* - `GadgetName` - Auto-generate ID, no dependencies
|
|
@@ -3385,24 +3399,24 @@ var init_parser = __esm({
|
|
|
3385
3399
|
*
|
|
3386
3400
|
* Dependencies must be comma-separated invocation IDs.
|
|
3387
3401
|
*/
|
|
3388
|
-
|
|
3389
|
-
const parts =
|
|
3402
|
+
parseInvocationMetadata(headerLine) {
|
|
3403
|
+
const parts = headerLine.split(":");
|
|
3390
3404
|
if (parts.length === 1) {
|
|
3391
3405
|
return {
|
|
3392
|
-
|
|
3406
|
+
gadgetName: parts[0],
|
|
3393
3407
|
invocationId: `gadget_${++globalInvocationCounter}`,
|
|
3394
3408
|
dependencies: []
|
|
3395
3409
|
};
|
|
3396
3410
|
} else if (parts.length === 2) {
|
|
3397
3411
|
return {
|
|
3398
|
-
|
|
3412
|
+
gadgetName: parts[0],
|
|
3399
3413
|
invocationId: parts[1].trim(),
|
|
3400
3414
|
dependencies: []
|
|
3401
3415
|
};
|
|
3402
3416
|
} else {
|
|
3403
3417
|
const deps = parts[2].split(",").map((d) => d.trim()).filter((d) => d.length > 0);
|
|
3404
3418
|
return {
|
|
3405
|
-
|
|
3419
|
+
gadgetName: parts[0],
|
|
3406
3420
|
invocationId: parts[1].trim(),
|
|
3407
3421
|
dependencies: deps
|
|
3408
3422
|
};
|
|
@@ -3434,19 +3448,15 @@ var init_parser = __esm({
|
|
|
3434
3448
|
while (true) {
|
|
3435
3449
|
const partStartIndex = this.buffer.indexOf(this.startPrefix, startIndex);
|
|
3436
3450
|
if (partStartIndex === -1) break;
|
|
3437
|
-
const textBefore = this.
|
|
3451
|
+
const textBefore = this.extractTextSegment(partStartIndex);
|
|
3438
3452
|
if (textBefore !== void 0) {
|
|
3439
3453
|
yield { type: "text", content: textBefore };
|
|
3440
3454
|
}
|
|
3441
3455
|
const metadataStartIndex = partStartIndex + this.startPrefix.length;
|
|
3442
3456
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
3443
3457
|
if (metadataEndIndex === -1) break;
|
|
3444
|
-
const
|
|
3445
|
-
const {
|
|
3446
|
-
actualName: actualGadgetName,
|
|
3447
|
-
invocationId,
|
|
3448
|
-
dependencies
|
|
3449
|
-
} = this.parseGadgetName(gadgetName);
|
|
3458
|
+
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
3459
|
+
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
3450
3460
|
const contentStartIndex = metadataEndIndex + 1;
|
|
3451
3461
|
let partEndIndex;
|
|
3452
3462
|
let endMarkerLength = 0;
|
|
@@ -3466,7 +3476,7 @@ var init_parser = __esm({
|
|
|
3466
3476
|
yield {
|
|
3467
3477
|
type: "gadget_call",
|
|
3468
3478
|
call: {
|
|
3469
|
-
gadgetName
|
|
3479
|
+
gadgetName,
|
|
3470
3480
|
invocationId,
|
|
3471
3481
|
parametersRaw,
|
|
3472
3482
|
parameters,
|
|
@@ -3475,37 +3485,33 @@ var init_parser = __esm({
|
|
|
3475
3485
|
}
|
|
3476
3486
|
};
|
|
3477
3487
|
startIndex = partEndIndex + endMarkerLength;
|
|
3478
|
-
this.
|
|
3488
|
+
this.lastEmittedTextOffset = startIndex;
|
|
3479
3489
|
}
|
|
3480
3490
|
if (startIndex > 0) {
|
|
3481
3491
|
this.buffer = this.buffer.substring(startIndex);
|
|
3482
|
-
this.
|
|
3492
|
+
this.lastEmittedTextOffset = 0;
|
|
3483
3493
|
}
|
|
3484
3494
|
}
|
|
3485
3495
|
// Finalize parsing and return remaining text or incomplete gadgets
|
|
3486
3496
|
*finalize() {
|
|
3487
|
-
const startIndex = this.buffer.indexOf(this.startPrefix, this.
|
|
3497
|
+
const startIndex = this.buffer.indexOf(this.startPrefix, this.lastEmittedTextOffset);
|
|
3488
3498
|
if (startIndex !== -1) {
|
|
3489
|
-
const textBefore = this.
|
|
3499
|
+
const textBefore = this.extractTextSegment(startIndex);
|
|
3490
3500
|
if (textBefore !== void 0) {
|
|
3491
3501
|
yield { type: "text", content: textBefore };
|
|
3492
3502
|
}
|
|
3493
3503
|
const metadataStartIndex = startIndex + this.startPrefix.length;
|
|
3494
3504
|
const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
|
|
3495
3505
|
if (metadataEndIndex !== -1) {
|
|
3496
|
-
const
|
|
3497
|
-
const {
|
|
3498
|
-
actualName: actualGadgetName,
|
|
3499
|
-
invocationId,
|
|
3500
|
-
dependencies
|
|
3501
|
-
} = this.parseGadgetName(gadgetName);
|
|
3506
|
+
const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
|
|
3507
|
+
const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
|
|
3502
3508
|
const contentStartIndex = metadataEndIndex + 1;
|
|
3503
3509
|
const parametersRaw = this.buffer.substring(contentStartIndex).trim();
|
|
3504
3510
|
const { parameters, parseError } = this.parseParameters(parametersRaw);
|
|
3505
3511
|
yield {
|
|
3506
3512
|
type: "gadget_call",
|
|
3507
3513
|
call: {
|
|
3508
|
-
gadgetName
|
|
3514
|
+
gadgetName,
|
|
3509
3515
|
invocationId,
|
|
3510
3516
|
parametersRaw,
|
|
3511
3517
|
parameters,
|
|
@@ -3516,7 +3522,7 @@ var init_parser = __esm({
|
|
|
3516
3522
|
return;
|
|
3517
3523
|
}
|
|
3518
3524
|
}
|
|
3519
|
-
const remainingText = this.
|
|
3525
|
+
const remainingText = this.extractTextSegment(this.buffer.length);
|
|
3520
3526
|
if (remainingText !== void 0) {
|
|
3521
3527
|
yield { type: "text", content: remainingText };
|
|
3522
3528
|
}
|
|
@@ -3524,7 +3530,7 @@ var init_parser = __esm({
|
|
|
3524
3530
|
// Reset parser state (note: global invocation counter is NOT reset to ensure unique IDs)
|
|
3525
3531
|
reset() {
|
|
3526
3532
|
this.buffer = "";
|
|
3527
|
-
this.
|
|
3533
|
+
this.lastEmittedTextOffset = 0;
|
|
3528
3534
|
}
|
|
3529
3535
|
};
|
|
3530
3536
|
}
|
|
@@ -3543,14 +3549,17 @@ var init_executor = __esm({
|
|
|
3543
3549
|
init_exceptions();
|
|
3544
3550
|
init_parser();
|
|
3545
3551
|
GadgetExecutor = class {
|
|
3546
|
-
constructor(registry,
|
|
3552
|
+
constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig, onNestedEvent) {
|
|
3547
3553
|
this.registry = registry;
|
|
3548
|
-
this.
|
|
3554
|
+
this.requestHumanInput = requestHumanInput;
|
|
3549
3555
|
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
3550
3556
|
this.client = client;
|
|
3551
3557
|
this.mediaStore = mediaStore;
|
|
3558
|
+
this.agentConfig = agentConfig;
|
|
3559
|
+
this.subagentConfig = subagentConfig;
|
|
3560
|
+
this.onNestedEvent = onNestedEvent;
|
|
3552
3561
|
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
3553
|
-
this.errorFormatter = new
|
|
3562
|
+
this.errorFormatter = new GadgetExecutionErrorFormatter(errorFormatterOptions);
|
|
3554
3563
|
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
3555
3564
|
}
|
|
3556
3565
|
logger;
|
|
@@ -3570,11 +3579,11 @@ var init_executor = __esm({
|
|
|
3570
3579
|
});
|
|
3571
3580
|
}
|
|
3572
3581
|
/**
|
|
3573
|
-
*
|
|
3582
|
+
* Unify gadget execute result to consistent internal format.
|
|
3574
3583
|
* Handles string returns (backwards compat), object returns with cost,
|
|
3575
3584
|
* and object returns with media.
|
|
3576
3585
|
*/
|
|
3577
|
-
|
|
3586
|
+
unifyExecuteResult(raw) {
|
|
3578
3587
|
if (typeof raw === "string") {
|
|
3579
3588
|
return { result: raw, cost: 0 };
|
|
3580
3589
|
}
|
|
@@ -3692,7 +3701,11 @@ var init_executor = __esm({
|
|
|
3692
3701
|
const ctx = {
|
|
3693
3702
|
reportCost,
|
|
3694
3703
|
llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
|
|
3695
|
-
signal: abortController.signal
|
|
3704
|
+
signal: abortController.signal,
|
|
3705
|
+
agentConfig: this.agentConfig,
|
|
3706
|
+
subagentConfig: this.subagentConfig,
|
|
3707
|
+
invocationId: call.invocationId,
|
|
3708
|
+
onNestedEvent: this.onNestedEvent
|
|
3696
3709
|
};
|
|
3697
3710
|
let rawResult;
|
|
3698
3711
|
if (timeoutMs && timeoutMs > 0) {
|
|
@@ -3707,7 +3720,7 @@ var init_executor = __esm({
|
|
|
3707
3720
|
} else {
|
|
3708
3721
|
rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
|
|
3709
3722
|
}
|
|
3710
|
-
const { result, media, cost: returnCost } = this.
|
|
3723
|
+
const { result, media, cost: returnCost } = this.unifyExecuteResult(rawResult);
|
|
3711
3724
|
const totalCost = callbackCost + returnCost;
|
|
3712
3725
|
let mediaIds;
|
|
3713
3726
|
let storedMedia;
|
|
@@ -3753,7 +3766,7 @@ var init_executor = __esm({
|
|
|
3753
3766
|
storedMedia
|
|
3754
3767
|
};
|
|
3755
3768
|
} catch (error) {
|
|
3756
|
-
if (error instanceof
|
|
3769
|
+
if (error instanceof TaskCompletionSignal) {
|
|
3757
3770
|
this.logger.info("Gadget requested loop termination", {
|
|
3758
3771
|
gadgetName: call.gadgetName,
|
|
3759
3772
|
message: error.message
|
|
@@ -3781,7 +3794,7 @@ var init_executor = __esm({
|
|
|
3781
3794
|
executionTimeMs: Date.now() - startTime
|
|
3782
3795
|
};
|
|
3783
3796
|
}
|
|
3784
|
-
if (error instanceof
|
|
3797
|
+
if (error instanceof AbortException) {
|
|
3785
3798
|
this.logger.info("Gadget execution was aborted", {
|
|
3786
3799
|
gadgetName: call.gadgetName,
|
|
3787
3800
|
executionTimeMs: Date.now() - startTime
|
|
@@ -3794,14 +3807,14 @@ var init_executor = __esm({
|
|
|
3794
3807
|
executionTimeMs: Date.now() - startTime
|
|
3795
3808
|
};
|
|
3796
3809
|
}
|
|
3797
|
-
if (error instanceof
|
|
3810
|
+
if (error instanceof HumanInputRequiredException) {
|
|
3798
3811
|
this.logger.info("Gadget requested human input", {
|
|
3799
3812
|
gadgetName: call.gadgetName,
|
|
3800
3813
|
question: error.question
|
|
3801
3814
|
});
|
|
3802
|
-
if (this.
|
|
3815
|
+
if (this.requestHumanInput) {
|
|
3803
3816
|
try {
|
|
3804
|
-
const answer = await this.
|
|
3817
|
+
const answer = await this.requestHumanInput(error.question);
|
|
3805
3818
|
this.logger.debug("Human input received", {
|
|
3806
3819
|
gadgetName: call.gadgetName,
|
|
3807
3820
|
answerLength: answer.length
|
|
@@ -3899,13 +3912,13 @@ var init_stream_processor = __esm({
|
|
|
3899
3912
|
parser;
|
|
3900
3913
|
executor;
|
|
3901
3914
|
stopOnGadgetError;
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3915
|
+
canRecoverFromGadgetError;
|
|
3916
|
+
responseText = "";
|
|
3917
|
+
executionHalted = false;
|
|
3905
3918
|
observerFailureCount = 0;
|
|
3906
3919
|
// Dependency tracking for gadget execution DAG
|
|
3907
3920
|
/** Gadgets waiting for their dependencies to complete */
|
|
3908
|
-
|
|
3921
|
+
gadgetsAwaitingDependencies = /* @__PURE__ */ new Map();
|
|
3909
3922
|
/** Completed gadget results, keyed by invocation ID */
|
|
3910
3923
|
completedResults = /* @__PURE__ */ new Map();
|
|
3911
3924
|
/** Invocation IDs of gadgets that have failed (error or skipped due to dependency) */
|
|
@@ -3916,27 +3929,36 @@ var init_stream_processor = __esm({
|
|
|
3916
3929
|
this.hooks = options.hooks ?? {};
|
|
3917
3930
|
this.logger = options.logger ?? createLogger({ name: "llmist:stream-processor" });
|
|
3918
3931
|
this.stopOnGadgetError = options.stopOnGadgetError ?? true;
|
|
3919
|
-
this.
|
|
3920
|
-
this.parser = new
|
|
3932
|
+
this.canRecoverFromGadgetError = options.canRecoverFromGadgetError;
|
|
3933
|
+
this.parser = new GadgetCallParser({
|
|
3921
3934
|
startPrefix: options.gadgetStartPrefix,
|
|
3922
3935
|
endPrefix: options.gadgetEndPrefix,
|
|
3923
3936
|
argPrefix: options.gadgetArgPrefix
|
|
3924
3937
|
});
|
|
3925
3938
|
this.executor = new GadgetExecutor(
|
|
3926
3939
|
options.registry,
|
|
3927
|
-
options.
|
|
3940
|
+
options.requestHumanInput,
|
|
3928
3941
|
this.logger.getSubLogger({ name: "executor" }),
|
|
3929
3942
|
options.defaultGadgetTimeoutMs,
|
|
3930
3943
|
{ argPrefix: options.gadgetArgPrefix },
|
|
3931
3944
|
options.client,
|
|
3932
|
-
options.mediaStore
|
|
3945
|
+
options.mediaStore,
|
|
3946
|
+
options.agentConfig,
|
|
3947
|
+
options.subagentConfig,
|
|
3948
|
+
options.onNestedEvent
|
|
3933
3949
|
);
|
|
3934
3950
|
}
|
|
3935
3951
|
/**
|
|
3936
|
-
* Process an LLM stream and
|
|
3952
|
+
* Process an LLM stream and yield events in real-time.
|
|
3953
|
+
*
|
|
3954
|
+
* This is an async generator that yields events immediately as they occur:
|
|
3955
|
+
* - Text events are yielded as text is streamed from the LLM
|
|
3956
|
+
* - gadget_call events are yielded immediately when a gadget call is parsed
|
|
3957
|
+
* - gadget_result events are yielded when gadget execution completes
|
|
3958
|
+
*
|
|
3959
|
+
* The final event is always a StreamCompletionEvent containing metadata.
|
|
3937
3960
|
*/
|
|
3938
|
-
async process(stream2) {
|
|
3939
|
-
const outputs = [];
|
|
3961
|
+
async *process(stream2) {
|
|
3940
3962
|
let finishReason = null;
|
|
3941
3963
|
let usage;
|
|
3942
3964
|
let didExecuteGadgets = false;
|
|
@@ -3950,7 +3972,7 @@ var init_stream_processor = __esm({
|
|
|
3950
3972
|
if (this.hooks.interceptors?.interceptRawChunk) {
|
|
3951
3973
|
const context = {
|
|
3952
3974
|
iteration: this.iteration,
|
|
3953
|
-
accumulatedText: this.
|
|
3975
|
+
accumulatedText: this.responseText,
|
|
3954
3976
|
logger: this.logger
|
|
3955
3977
|
};
|
|
3956
3978
|
const intercepted = this.hooks.interceptors.interceptRawChunk(processedChunk, context);
|
|
@@ -3961,7 +3983,7 @@ var init_stream_processor = __esm({
|
|
|
3961
3983
|
}
|
|
3962
3984
|
}
|
|
3963
3985
|
if (processedChunk) {
|
|
3964
|
-
this.
|
|
3986
|
+
this.responseText += processedChunk;
|
|
3965
3987
|
}
|
|
3966
3988
|
}
|
|
3967
3989
|
if (this.hooks.observers?.onStreamChunk && (processedChunk || chunk.usage)) {
|
|
@@ -3970,7 +3992,7 @@ var init_stream_processor = __esm({
|
|
|
3970
3992
|
const context = {
|
|
3971
3993
|
iteration: this.iteration,
|
|
3972
3994
|
rawChunk: processedChunk,
|
|
3973
|
-
accumulatedText: this.
|
|
3995
|
+
accumulatedText: this.responseText,
|
|
3974
3996
|
usage,
|
|
3975
3997
|
logger: this.logger
|
|
3976
3998
|
};
|
|
@@ -3982,67 +4004,66 @@ var init_stream_processor = __esm({
|
|
|
3982
4004
|
continue;
|
|
3983
4005
|
}
|
|
3984
4006
|
for (const event of this.parser.feed(processedChunk)) {
|
|
3985
|
-
const
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
shouldBreakLoop = true;
|
|
4007
|
+
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
4008
|
+
yield processedEvent;
|
|
4009
|
+
if (processedEvent.type === "gadget_result") {
|
|
4010
|
+
didExecuteGadgets = true;
|
|
4011
|
+
if (processedEvent.result.breaksLoop) {
|
|
4012
|
+
shouldBreakLoop = true;
|
|
4013
|
+
}
|
|
3993
4014
|
}
|
|
3994
4015
|
}
|
|
3995
4016
|
}
|
|
3996
|
-
if (this.
|
|
4017
|
+
if (this.executionHalted) {
|
|
3997
4018
|
this.logger.info("Breaking from LLM stream due to gadget error");
|
|
3998
4019
|
break;
|
|
3999
4020
|
}
|
|
4000
4021
|
}
|
|
4001
|
-
if (!this.
|
|
4022
|
+
if (!this.executionHalted) {
|
|
4002
4023
|
for (const event of this.parser.finalize()) {
|
|
4003
|
-
const
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
shouldBreakLoop = true;
|
|
4024
|
+
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
4025
|
+
yield processedEvent;
|
|
4026
|
+
if (processedEvent.type === "gadget_result") {
|
|
4027
|
+
didExecuteGadgets = true;
|
|
4028
|
+
if (processedEvent.result.breaksLoop) {
|
|
4029
|
+
shouldBreakLoop = true;
|
|
4030
|
+
}
|
|
4011
4031
|
}
|
|
4012
4032
|
}
|
|
4013
4033
|
}
|
|
4014
|
-
const
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
shouldBreakLoop = true;
|
|
4034
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4035
|
+
yield evt;
|
|
4036
|
+
if (evt.type === "gadget_result") {
|
|
4037
|
+
didExecuteGadgets = true;
|
|
4038
|
+
if (evt.result.breaksLoop) {
|
|
4039
|
+
shouldBreakLoop = true;
|
|
4040
|
+
}
|
|
4022
4041
|
}
|
|
4023
4042
|
}
|
|
4024
4043
|
}
|
|
4025
|
-
let finalMessage = this.
|
|
4044
|
+
let finalMessage = this.responseText;
|
|
4026
4045
|
if (this.hooks.interceptors?.interceptAssistantMessage) {
|
|
4027
4046
|
const context = {
|
|
4028
4047
|
iteration: this.iteration,
|
|
4029
|
-
rawResponse: this.
|
|
4048
|
+
rawResponse: this.responseText,
|
|
4030
4049
|
logger: this.logger
|
|
4031
4050
|
};
|
|
4032
4051
|
finalMessage = this.hooks.interceptors.interceptAssistantMessage(finalMessage, context);
|
|
4033
4052
|
}
|
|
4034
|
-
|
|
4035
|
-
|
|
4053
|
+
const completionEvent = {
|
|
4054
|
+
type: "stream_complete",
|
|
4036
4055
|
shouldBreakLoop,
|
|
4037
4056
|
didExecuteGadgets,
|
|
4038
4057
|
finishReason,
|
|
4039
4058
|
usage,
|
|
4040
|
-
rawResponse: this.
|
|
4059
|
+
rawResponse: this.responseText,
|
|
4041
4060
|
finalMessage
|
|
4042
4061
|
};
|
|
4062
|
+
yield completionEvent;
|
|
4043
4063
|
}
|
|
4044
4064
|
/**
|
|
4045
4065
|
* Process a single parsed event (text or gadget call).
|
|
4066
|
+
* @deprecated Use processEventGenerator for real-time streaming
|
|
4046
4067
|
*/
|
|
4047
4068
|
async processEvent(event) {
|
|
4048
4069
|
if (event.type === "text") {
|
|
@@ -4052,6 +4073,23 @@ var init_stream_processor = __esm({
|
|
|
4052
4073
|
}
|
|
4053
4074
|
return [event];
|
|
4054
4075
|
}
|
|
4076
|
+
/**
|
|
4077
|
+
* Process a single parsed event, yielding events in real-time.
|
|
4078
|
+
* Generator version of processEvent for streaming support.
|
|
4079
|
+
*/
|
|
4080
|
+
async *processEventGenerator(event) {
|
|
4081
|
+
if (event.type === "text") {
|
|
4082
|
+
for (const e of await this.processTextEvent(event)) {
|
|
4083
|
+
yield e;
|
|
4084
|
+
}
|
|
4085
|
+
} else if (event.type === "gadget_call") {
|
|
4086
|
+
for await (const e of this.processGadgetCallGenerator(event.call)) {
|
|
4087
|
+
yield e;
|
|
4088
|
+
}
|
|
4089
|
+
} else {
|
|
4090
|
+
yield event;
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4055
4093
|
/**
|
|
4056
4094
|
* Process a text event through interceptors.
|
|
4057
4095
|
*/
|
|
@@ -4060,7 +4098,7 @@ var init_stream_processor = __esm({
|
|
|
4060
4098
|
if (this.hooks.interceptors?.interceptTextChunk) {
|
|
4061
4099
|
const context = {
|
|
4062
4100
|
iteration: this.iteration,
|
|
4063
|
-
accumulatedText: this.
|
|
4101
|
+
accumulatedText: this.responseText,
|
|
4064
4102
|
logger: this.logger
|
|
4065
4103
|
};
|
|
4066
4104
|
const intercepted = this.hooks.interceptors.interceptTextChunk(content, context);
|
|
@@ -4079,7 +4117,7 @@ var init_stream_processor = __esm({
|
|
|
4079
4117
|
* After each execution, pending gadgets are checked to see if they can now run.
|
|
4080
4118
|
*/
|
|
4081
4119
|
async processGadgetCall(call) {
|
|
4082
|
-
if (this.
|
|
4120
|
+
if (this.executionHalted) {
|
|
4083
4121
|
this.logger.debug("Skipping gadget execution due to previous error", {
|
|
4084
4122
|
gadgetName: call.gadgetName
|
|
4085
4123
|
});
|
|
@@ -4118,7 +4156,7 @@ var init_stream_processor = __esm({
|
|
|
4118
4156
|
invocationId: call.invocationId,
|
|
4119
4157
|
waitingOn: unsatisfied
|
|
4120
4158
|
});
|
|
4121
|
-
this.
|
|
4159
|
+
this.gadgetsAwaitingDependencies.set(call.invocationId, call);
|
|
4122
4160
|
return events;
|
|
4123
4161
|
}
|
|
4124
4162
|
}
|
|
@@ -4128,9 +4166,68 @@ var init_stream_processor = __esm({
|
|
|
4128
4166
|
events.push(...triggeredEvents);
|
|
4129
4167
|
return events;
|
|
4130
4168
|
}
|
|
4169
|
+
/**
|
|
4170
|
+
* Process a gadget call, yielding events in real-time.
|
|
4171
|
+
*
|
|
4172
|
+
* Key difference from processGadgetCall: yields gadget_call event IMMEDIATELY
|
|
4173
|
+
* when parsed (before execution), enabling real-time UI feedback.
|
|
4174
|
+
*/
|
|
4175
|
+
async *processGadgetCallGenerator(call) {
|
|
4176
|
+
if (this.executionHalted) {
|
|
4177
|
+
this.logger.debug("Skipping gadget execution due to previous error", {
|
|
4178
|
+
gadgetName: call.gadgetName
|
|
4179
|
+
});
|
|
4180
|
+
return;
|
|
4181
|
+
}
|
|
4182
|
+
yield { type: "gadget_call", call };
|
|
4183
|
+
if (call.dependencies.length > 0) {
|
|
4184
|
+
if (call.dependencies.includes(call.invocationId)) {
|
|
4185
|
+
this.logger.warn("Gadget has self-referential dependency (depends on itself)", {
|
|
4186
|
+
gadgetName: call.gadgetName,
|
|
4187
|
+
invocationId: call.invocationId
|
|
4188
|
+
});
|
|
4189
|
+
this.failedInvocations.add(call.invocationId);
|
|
4190
|
+
const skipEvent = {
|
|
4191
|
+
type: "gadget_skipped",
|
|
4192
|
+
gadgetName: call.gadgetName,
|
|
4193
|
+
invocationId: call.invocationId,
|
|
4194
|
+
parameters: call.parameters ?? {},
|
|
4195
|
+
failedDependency: call.invocationId,
|
|
4196
|
+
failedDependencyError: `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`
|
|
4197
|
+
};
|
|
4198
|
+
yield skipEvent;
|
|
4199
|
+
return;
|
|
4200
|
+
}
|
|
4201
|
+
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4202
|
+
if (failedDep) {
|
|
4203
|
+
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4204
|
+
for (const evt of skipEvents) {
|
|
4205
|
+
yield evt;
|
|
4206
|
+
}
|
|
4207
|
+
return;
|
|
4208
|
+
}
|
|
4209
|
+
const unsatisfied = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4210
|
+
if (unsatisfied.length > 0) {
|
|
4211
|
+
this.logger.debug("Queueing gadget for later - waiting on dependencies", {
|
|
4212
|
+
gadgetName: call.gadgetName,
|
|
4213
|
+
invocationId: call.invocationId,
|
|
4214
|
+
waitingOn: unsatisfied
|
|
4215
|
+
});
|
|
4216
|
+
this.gadgetsAwaitingDependencies.set(call.invocationId, call);
|
|
4217
|
+
return;
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4221
|
+
yield evt;
|
|
4222
|
+
}
|
|
4223
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4224
|
+
yield evt;
|
|
4225
|
+
}
|
|
4226
|
+
}
|
|
4131
4227
|
/**
|
|
4132
4228
|
* Execute a gadget through the full hook lifecycle.
|
|
4133
4229
|
* This is the core execution logic, extracted from processGadgetCall.
|
|
4230
|
+
* @deprecated Use executeGadgetGenerator for real-time streaming
|
|
4134
4231
|
*/
|
|
4135
4232
|
async executeGadgetWithHooks(call) {
|
|
4136
4233
|
const events = [];
|
|
@@ -4140,14 +4237,14 @@ var init_stream_processor = __esm({
|
|
|
4140
4237
|
error: call.parseError,
|
|
4141
4238
|
rawParameters: call.parametersRaw
|
|
4142
4239
|
});
|
|
4143
|
-
const shouldContinue = await this.
|
|
4240
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4144
4241
|
call.parseError,
|
|
4145
4242
|
call.gadgetName,
|
|
4146
4243
|
"parse",
|
|
4147
4244
|
call.parameters
|
|
4148
4245
|
);
|
|
4149
4246
|
if (!shouldContinue) {
|
|
4150
|
-
this.
|
|
4247
|
+
this.executionHalted = true;
|
|
4151
4248
|
}
|
|
4152
4249
|
}
|
|
4153
4250
|
let parameters = call.parameters ?? {};
|
|
@@ -4271,18 +4368,171 @@ var init_stream_processor = __esm({
|
|
|
4271
4368
|
events.push({ type: "gadget_result", result });
|
|
4272
4369
|
if (result.error) {
|
|
4273
4370
|
const errorType = this.determineErrorType(call, result);
|
|
4274
|
-
const shouldContinue = await this.
|
|
4371
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4275
4372
|
result.error,
|
|
4276
4373
|
result.gadgetName,
|
|
4277
4374
|
errorType,
|
|
4278
4375
|
result.parameters
|
|
4279
4376
|
);
|
|
4280
4377
|
if (!shouldContinue) {
|
|
4281
|
-
this.
|
|
4378
|
+
this.executionHalted = true;
|
|
4282
4379
|
}
|
|
4283
4380
|
}
|
|
4284
4381
|
return events;
|
|
4285
4382
|
}
|
|
4383
|
+
/**
|
|
4384
|
+
* Execute a gadget and yield the result event.
|
|
4385
|
+
* Generator version that yields gadget_result immediately when execution completes.
|
|
4386
|
+
*/
|
|
4387
|
+
async *executeGadgetGenerator(call) {
|
|
4388
|
+
if (call.parseError) {
|
|
4389
|
+
this.logger.warn("Gadget has parse error", {
|
|
4390
|
+
gadgetName: call.gadgetName,
|
|
4391
|
+
error: call.parseError,
|
|
4392
|
+
rawParameters: call.parametersRaw
|
|
4393
|
+
});
|
|
4394
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4395
|
+
call.parseError,
|
|
4396
|
+
call.gadgetName,
|
|
4397
|
+
"parse",
|
|
4398
|
+
call.parameters
|
|
4399
|
+
);
|
|
4400
|
+
if (!shouldContinue) {
|
|
4401
|
+
this.executionHalted = true;
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4404
|
+
let parameters = call.parameters ?? {};
|
|
4405
|
+
if (this.hooks.interceptors?.interceptGadgetParameters) {
|
|
4406
|
+
const context = {
|
|
4407
|
+
iteration: this.iteration,
|
|
4408
|
+
gadgetName: call.gadgetName,
|
|
4409
|
+
invocationId: call.invocationId,
|
|
4410
|
+
logger: this.logger
|
|
4411
|
+
};
|
|
4412
|
+
parameters = this.hooks.interceptors.interceptGadgetParameters(parameters, context);
|
|
4413
|
+
}
|
|
4414
|
+
call.parameters = parameters;
|
|
4415
|
+
let shouldSkip = false;
|
|
4416
|
+
let syntheticResult;
|
|
4417
|
+
if (this.hooks.controllers?.beforeGadgetExecution) {
|
|
4418
|
+
const context = {
|
|
4419
|
+
iteration: this.iteration,
|
|
4420
|
+
gadgetName: call.gadgetName,
|
|
4421
|
+
invocationId: call.invocationId,
|
|
4422
|
+
parameters,
|
|
4423
|
+
logger: this.logger
|
|
4424
|
+
};
|
|
4425
|
+
const action = await this.hooks.controllers.beforeGadgetExecution(context);
|
|
4426
|
+
validateBeforeGadgetExecutionAction(action);
|
|
4427
|
+
if (action.action === "skip") {
|
|
4428
|
+
shouldSkip = true;
|
|
4429
|
+
syntheticResult = action.syntheticResult;
|
|
4430
|
+
this.logger.info("Controller skipped gadget execution", {
|
|
4431
|
+
gadgetName: call.gadgetName
|
|
4432
|
+
});
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
const startObservers = [];
|
|
4436
|
+
if (this.hooks.observers?.onGadgetExecutionStart) {
|
|
4437
|
+
startObservers.push(async () => {
|
|
4438
|
+
const context = {
|
|
4439
|
+
iteration: this.iteration,
|
|
4440
|
+
gadgetName: call.gadgetName,
|
|
4441
|
+
invocationId: call.invocationId,
|
|
4442
|
+
parameters,
|
|
4443
|
+
logger: this.logger
|
|
4444
|
+
};
|
|
4445
|
+
await this.hooks.observers.onGadgetExecutionStart(context);
|
|
4446
|
+
});
|
|
4447
|
+
}
|
|
4448
|
+
await this.runObserversInParallel(startObservers);
|
|
4449
|
+
let result;
|
|
4450
|
+
if (shouldSkip) {
|
|
4451
|
+
result = {
|
|
4452
|
+
gadgetName: call.gadgetName,
|
|
4453
|
+
invocationId: call.invocationId,
|
|
4454
|
+
parameters,
|
|
4455
|
+
result: syntheticResult ?? "Execution skipped",
|
|
4456
|
+
executionTimeMs: 0
|
|
4457
|
+
};
|
|
4458
|
+
} else {
|
|
4459
|
+
result = await this.executor.execute(call);
|
|
4460
|
+
}
|
|
4461
|
+
const originalResult = result.result;
|
|
4462
|
+
if (result.result && this.hooks.interceptors?.interceptGadgetResult) {
|
|
4463
|
+
const context = {
|
|
4464
|
+
iteration: this.iteration,
|
|
4465
|
+
gadgetName: result.gadgetName,
|
|
4466
|
+
invocationId: result.invocationId,
|
|
4467
|
+
parameters,
|
|
4468
|
+
executionTimeMs: result.executionTimeMs,
|
|
4469
|
+
logger: this.logger
|
|
4470
|
+
};
|
|
4471
|
+
result.result = this.hooks.interceptors.interceptGadgetResult(result.result, context);
|
|
4472
|
+
}
|
|
4473
|
+
if (this.hooks.controllers?.afterGadgetExecution) {
|
|
4474
|
+
const context = {
|
|
4475
|
+
iteration: this.iteration,
|
|
4476
|
+
gadgetName: result.gadgetName,
|
|
4477
|
+
invocationId: result.invocationId,
|
|
4478
|
+
parameters,
|
|
4479
|
+
result: result.result,
|
|
4480
|
+
error: result.error,
|
|
4481
|
+
executionTimeMs: result.executionTimeMs,
|
|
4482
|
+
logger: this.logger
|
|
4483
|
+
};
|
|
4484
|
+
const action = await this.hooks.controllers.afterGadgetExecution(context);
|
|
4485
|
+
validateAfterGadgetExecutionAction(action);
|
|
4486
|
+
if (action.action === "recover" && result.error) {
|
|
4487
|
+
this.logger.info("Controller recovered from gadget error", {
|
|
4488
|
+
gadgetName: result.gadgetName,
|
|
4489
|
+
originalError: result.error
|
|
4490
|
+
});
|
|
4491
|
+
result = {
|
|
4492
|
+
...result,
|
|
4493
|
+
error: void 0,
|
|
4494
|
+
result: action.fallbackResult
|
|
4495
|
+
};
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4498
|
+
const completeObservers = [];
|
|
4499
|
+
if (this.hooks.observers?.onGadgetExecutionComplete) {
|
|
4500
|
+
completeObservers.push(async () => {
|
|
4501
|
+
const context = {
|
|
4502
|
+
iteration: this.iteration,
|
|
4503
|
+
gadgetName: result.gadgetName,
|
|
4504
|
+
invocationId: result.invocationId,
|
|
4505
|
+
parameters,
|
|
4506
|
+
originalResult,
|
|
4507
|
+
finalResult: result.result,
|
|
4508
|
+
error: result.error,
|
|
4509
|
+
executionTimeMs: result.executionTimeMs,
|
|
4510
|
+
breaksLoop: result.breaksLoop,
|
|
4511
|
+
cost: result.cost,
|
|
4512
|
+
logger: this.logger
|
|
4513
|
+
};
|
|
4514
|
+
await this.hooks.observers.onGadgetExecutionComplete(context);
|
|
4515
|
+
});
|
|
4516
|
+
}
|
|
4517
|
+
await this.runObserversInParallel(completeObservers);
|
|
4518
|
+
this.completedResults.set(result.invocationId, result);
|
|
4519
|
+
if (result.error) {
|
|
4520
|
+
this.failedInvocations.add(result.invocationId);
|
|
4521
|
+
}
|
|
4522
|
+
yield { type: "gadget_result", result };
|
|
4523
|
+
if (result.error) {
|
|
4524
|
+
const errorType = this.determineErrorType(call, result);
|
|
4525
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4526
|
+
result.error,
|
|
4527
|
+
result.gadgetName,
|
|
4528
|
+
errorType,
|
|
4529
|
+
result.parameters
|
|
4530
|
+
);
|
|
4531
|
+
if (!shouldContinue) {
|
|
4532
|
+
this.executionHalted = true;
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4286
4536
|
/**
|
|
4287
4537
|
* Handle a gadget that cannot execute because a dependency failed.
|
|
4288
4538
|
* Calls the onDependencySkipped controller to allow customization.
|
|
@@ -4365,11 +4615,11 @@ var init_stream_processor = __esm({
|
|
|
4365
4615
|
async processPendingGadgets() {
|
|
4366
4616
|
const events = [];
|
|
4367
4617
|
let progress = true;
|
|
4368
|
-
while (progress && this.
|
|
4618
|
+
while (progress && this.gadgetsAwaitingDependencies.size > 0) {
|
|
4369
4619
|
progress = false;
|
|
4370
4620
|
const readyToExecute = [];
|
|
4371
4621
|
const readyToSkip = [];
|
|
4372
|
-
for (const [invocationId, call] of this.
|
|
4622
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4373
4623
|
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4374
4624
|
if (failedDep) {
|
|
4375
4625
|
readyToSkip.push({ call, failedDep });
|
|
@@ -4381,7 +4631,7 @@ var init_stream_processor = __esm({
|
|
|
4381
4631
|
}
|
|
4382
4632
|
}
|
|
4383
4633
|
for (const { call, failedDep } of readyToSkip) {
|
|
4384
|
-
this.
|
|
4634
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4385
4635
|
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4386
4636
|
events.push(...skipEvents);
|
|
4387
4637
|
progress = true;
|
|
@@ -4392,7 +4642,7 @@ var init_stream_processor = __esm({
|
|
|
4392
4642
|
invocationIds: readyToExecute.map((c) => c.invocationId)
|
|
4393
4643
|
});
|
|
4394
4644
|
for (const call of readyToExecute) {
|
|
4395
|
-
this.
|
|
4645
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4396
4646
|
}
|
|
4397
4647
|
const executePromises = readyToExecute.map((call) => this.executeGadgetWithHooks(call));
|
|
4398
4648
|
const results = await Promise.all(executePromises);
|
|
@@ -4402,9 +4652,9 @@ var init_stream_processor = __esm({
|
|
|
4402
4652
|
progress = true;
|
|
4403
4653
|
}
|
|
4404
4654
|
}
|
|
4405
|
-
if (this.
|
|
4406
|
-
const pendingIds = new Set(this.
|
|
4407
|
-
for (const [invocationId, call] of this.
|
|
4655
|
+
if (this.gadgetsAwaitingDependencies.size > 0) {
|
|
4656
|
+
const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());
|
|
4657
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4408
4658
|
const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4409
4659
|
const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));
|
|
4410
4660
|
const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));
|
|
@@ -4435,10 +4685,103 @@ var init_stream_processor = __esm({
|
|
|
4435
4685
|
};
|
|
4436
4686
|
events.push(skipEvent);
|
|
4437
4687
|
}
|
|
4438
|
-
this.
|
|
4688
|
+
this.gadgetsAwaitingDependencies.clear();
|
|
4439
4689
|
}
|
|
4440
4690
|
return events;
|
|
4441
4691
|
}
|
|
4692
|
+
/**
|
|
4693
|
+
* Process pending gadgets, yielding events in real-time.
|
|
4694
|
+
* Generator version that yields events as gadgets complete.
|
|
4695
|
+
*
|
|
4696
|
+
* Note: Gadgets are still executed in parallel for efficiency,
|
|
4697
|
+
* but results are yielded as they become available.
|
|
4698
|
+
*/
|
|
4699
|
+
async *processPendingGadgetsGenerator() {
|
|
4700
|
+
let progress = true;
|
|
4701
|
+
while (progress && this.gadgetsAwaitingDependencies.size > 0) {
|
|
4702
|
+
progress = false;
|
|
4703
|
+
const readyToExecute = [];
|
|
4704
|
+
const readyToSkip = [];
|
|
4705
|
+
for (const [_invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4706
|
+
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4707
|
+
if (failedDep) {
|
|
4708
|
+
readyToSkip.push({ call, failedDep });
|
|
4709
|
+
continue;
|
|
4710
|
+
}
|
|
4711
|
+
const allSatisfied = call.dependencies.every((dep) => this.completedResults.has(dep));
|
|
4712
|
+
if (allSatisfied) {
|
|
4713
|
+
readyToExecute.push(call);
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4716
|
+
for (const { call, failedDep } of readyToSkip) {
|
|
4717
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4718
|
+
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4719
|
+
for (const evt of skipEvents) {
|
|
4720
|
+
yield evt;
|
|
4721
|
+
}
|
|
4722
|
+
progress = true;
|
|
4723
|
+
}
|
|
4724
|
+
if (readyToExecute.length > 0) {
|
|
4725
|
+
this.logger.debug("Executing ready gadgets in parallel", {
|
|
4726
|
+
count: readyToExecute.length,
|
|
4727
|
+
invocationIds: readyToExecute.map((c) => c.invocationId)
|
|
4728
|
+
});
|
|
4729
|
+
for (const call of readyToExecute) {
|
|
4730
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4731
|
+
}
|
|
4732
|
+
const eventSets = await Promise.all(
|
|
4733
|
+
readyToExecute.map(async (call) => {
|
|
4734
|
+
const events = [];
|
|
4735
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4736
|
+
events.push(evt);
|
|
4737
|
+
}
|
|
4738
|
+
return events;
|
|
4739
|
+
})
|
|
4740
|
+
);
|
|
4741
|
+
for (const events of eventSets) {
|
|
4742
|
+
for (const evt of events) {
|
|
4743
|
+
yield evt;
|
|
4744
|
+
}
|
|
4745
|
+
}
|
|
4746
|
+
progress = true;
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
if (this.gadgetsAwaitingDependencies.size > 0) {
|
|
4750
|
+
const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());
|
|
4751
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4752
|
+
const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4753
|
+
const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));
|
|
4754
|
+
const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));
|
|
4755
|
+
let errorMessage;
|
|
4756
|
+
let logLevel = "warn";
|
|
4757
|
+
if (circularDeps.length > 0 && trulyMissingDeps.length > 0) {
|
|
4758
|
+
errorMessage = `Dependencies unresolvable: circular=[${circularDeps.join(", ")}], missing=[${trulyMissingDeps.join(", ")}]`;
|
|
4759
|
+
logLevel = "error";
|
|
4760
|
+
} else if (circularDeps.length > 0) {
|
|
4761
|
+
errorMessage = `Circular dependency detected: "${invocationId}" depends on "${circularDeps[0]}" which also depends on "${invocationId}" (directly or indirectly)`;
|
|
4762
|
+
} else {
|
|
4763
|
+
errorMessage = `Dependency "${missingDeps[0]}" was never executed - check that the invocation ID exists and is spelled correctly`;
|
|
4764
|
+
}
|
|
4765
|
+
this.logger[logLevel]("Gadget has unresolvable dependencies", {
|
|
4766
|
+
gadgetName: call.gadgetName,
|
|
4767
|
+
invocationId,
|
|
4768
|
+
circularDependencies: circularDeps,
|
|
4769
|
+
missingDependencies: trulyMissingDeps
|
|
4770
|
+
});
|
|
4771
|
+
this.failedInvocations.add(invocationId);
|
|
4772
|
+
const skipEvent = {
|
|
4773
|
+
type: "gadget_skipped",
|
|
4774
|
+
gadgetName: call.gadgetName,
|
|
4775
|
+
invocationId,
|
|
4776
|
+
parameters: call.parameters ?? {},
|
|
4777
|
+
failedDependency: missingDeps[0],
|
|
4778
|
+
failedDependencyError: errorMessage
|
|
4779
|
+
};
|
|
4780
|
+
yield skipEvent;
|
|
4781
|
+
}
|
|
4782
|
+
this.gadgetsAwaitingDependencies.clear();
|
|
4783
|
+
}
|
|
4784
|
+
}
|
|
4442
4785
|
/**
|
|
4443
4786
|
* Safely execute an observer, catching and logging any errors.
|
|
4444
4787
|
* Observers are non-critical, so errors are logged but don't crash the system.
|
|
@@ -4465,19 +4808,19 @@ var init_stream_processor = __esm({
|
|
|
4465
4808
|
);
|
|
4466
4809
|
}
|
|
4467
4810
|
/**
|
|
4468
|
-
* Check if execution
|
|
4811
|
+
* Check if execution can recover from an error.
|
|
4469
4812
|
*
|
|
4470
4813
|
* Returns true if we should continue processing subsequent gadgets, false if we should stop.
|
|
4471
4814
|
*
|
|
4472
4815
|
* Logic:
|
|
4473
|
-
* - If custom
|
|
4816
|
+
* - If custom canRecoverFromGadgetError is provided, use it
|
|
4474
4817
|
* - Otherwise, use stopOnGadgetError config:
|
|
4475
4818
|
* - stopOnGadgetError=true → return false (stop execution)
|
|
4476
4819
|
* - stopOnGadgetError=false → return true (continue execution)
|
|
4477
4820
|
*/
|
|
4478
|
-
async
|
|
4479
|
-
if (this.
|
|
4480
|
-
return await this.
|
|
4821
|
+
async checkCanRecoverFromError(error, gadgetName, errorType, parameters) {
|
|
4822
|
+
if (this.canRecoverFromGadgetError) {
|
|
4823
|
+
return await this.canRecoverFromGadgetError({
|
|
4481
4824
|
error,
|
|
4482
4825
|
gadgetName,
|
|
4483
4826
|
errorType,
|
|
@@ -4540,14 +4883,14 @@ var init_agent = __esm({
|
|
|
4540
4883
|
gadgetStartPrefix;
|
|
4541
4884
|
gadgetEndPrefix;
|
|
4542
4885
|
gadgetArgPrefix;
|
|
4543
|
-
|
|
4886
|
+
requestHumanInput;
|
|
4544
4887
|
textOnlyHandler;
|
|
4545
4888
|
textWithGadgetsHandler;
|
|
4546
4889
|
stopOnGadgetError;
|
|
4547
|
-
|
|
4890
|
+
canRecoverFromGadgetError;
|
|
4548
4891
|
defaultGadgetTimeoutMs;
|
|
4549
4892
|
defaultMaxTokens;
|
|
4550
|
-
|
|
4893
|
+
hasUserPrompt;
|
|
4551
4894
|
// Gadget output limiting
|
|
4552
4895
|
outputStore;
|
|
4553
4896
|
outputLimitEnabled;
|
|
@@ -4558,6 +4901,11 @@ var init_agent = __esm({
|
|
|
4558
4901
|
mediaStore;
|
|
4559
4902
|
// Cancellation
|
|
4560
4903
|
signal;
|
|
4904
|
+
// Subagent configuration
|
|
4905
|
+
agentContextConfig;
|
|
4906
|
+
subagentConfig;
|
|
4907
|
+
// Nested event callback for subagent gadgets
|
|
4908
|
+
onNestedEvent;
|
|
4561
4909
|
/**
|
|
4562
4910
|
* Creates a new Agent instance.
|
|
4563
4911
|
* @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
|
|
@@ -4577,11 +4925,11 @@ var init_agent = __esm({
|
|
|
4577
4925
|
this.gadgetStartPrefix = options.gadgetStartPrefix;
|
|
4578
4926
|
this.gadgetEndPrefix = options.gadgetEndPrefix;
|
|
4579
4927
|
this.gadgetArgPrefix = options.gadgetArgPrefix;
|
|
4580
|
-
this.
|
|
4928
|
+
this.requestHumanInput = options.requestHumanInput;
|
|
4581
4929
|
this.textOnlyHandler = options.textOnlyHandler ?? "terminate";
|
|
4582
4930
|
this.textWithGadgetsHandler = options.textWithGadgetsHandler;
|
|
4583
4931
|
this.stopOnGadgetError = options.stopOnGadgetError ?? true;
|
|
4584
|
-
this.
|
|
4932
|
+
this.canRecoverFromGadgetError = options.canRecoverFromGadgetError;
|
|
4585
4933
|
this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
|
|
4586
4934
|
this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
|
|
4587
4935
|
this.outputLimitEnabled = options.gadgetOutputLimit ?? DEFAULT_GADGET_OUTPUT_LIMIT;
|
|
@@ -4597,7 +4945,7 @@ var init_agent = __esm({
|
|
|
4597
4945
|
createGadgetOutputViewer(this.outputStore, this.outputLimitCharLimit)
|
|
4598
4946
|
);
|
|
4599
4947
|
}
|
|
4600
|
-
this.hooks = this.
|
|
4948
|
+
this.hooks = this.chainOutputLimiterWithUserHooks(options.hooks);
|
|
4601
4949
|
const baseBuilder = new LLMMessageBuilder(options.promptConfig);
|
|
4602
4950
|
if (options.systemPrompt) {
|
|
4603
4951
|
baseBuilder.addSystem(options.systemPrompt);
|
|
@@ -4617,7 +4965,7 @@ var init_agent = __esm({
|
|
|
4617
4965
|
endPrefix: options.gadgetEndPrefix,
|
|
4618
4966
|
argPrefix: options.gadgetArgPrefix
|
|
4619
4967
|
});
|
|
4620
|
-
this.
|
|
4968
|
+
this.hasUserPrompt = !!options.userPrompt;
|
|
4621
4969
|
if (options.userPrompt) {
|
|
4622
4970
|
this.conversation.addUserMessage(options.userPrompt);
|
|
4623
4971
|
}
|
|
@@ -4630,6 +4978,12 @@ var init_agent = __esm({
|
|
|
4630
4978
|
);
|
|
4631
4979
|
}
|
|
4632
4980
|
this.signal = options.signal;
|
|
4981
|
+
this.agentContextConfig = {
|
|
4982
|
+
model: this.model,
|
|
4983
|
+
temperature: this.temperature
|
|
4984
|
+
};
|
|
4985
|
+
this.subagentConfig = options.subagentConfig;
|
|
4986
|
+
this.onNestedEvent = options.onNestedEvent;
|
|
4633
4987
|
}
|
|
4634
4988
|
/**
|
|
4635
4989
|
* Get the gadget registry for this agent.
|
|
@@ -4736,7 +5090,7 @@ var init_agent = __esm({
|
|
|
4736
5090
|
* @throws {Error} If no user prompt was provided (when using build() without ask())
|
|
4737
5091
|
*/
|
|
4738
5092
|
async *run() {
|
|
4739
|
-
if (!this.
|
|
5093
|
+
if (!this.hasUserPrompt) {
|
|
4740
5094
|
throw new Error(
|
|
4741
5095
|
"No user prompt provided. Use .ask(prompt) instead of .build(), or call agent.run() after providing a prompt."
|
|
4742
5096
|
);
|
|
@@ -4853,17 +5207,37 @@ var init_agent = __esm({
|
|
|
4853
5207
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
4854
5208
|
hooks: this.hooks,
|
|
4855
5209
|
logger: this.logger.getSubLogger({ name: "stream-processor" }),
|
|
4856
|
-
|
|
5210
|
+
requestHumanInput: this.requestHumanInput,
|
|
4857
5211
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
4858
|
-
|
|
5212
|
+
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
4859
5213
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
4860
5214
|
client: this.client,
|
|
4861
|
-
mediaStore: this.mediaStore
|
|
5215
|
+
mediaStore: this.mediaStore,
|
|
5216
|
+
agentConfig: this.agentContextConfig,
|
|
5217
|
+
subagentConfig: this.subagentConfig,
|
|
5218
|
+
onNestedEvent: this.onNestedEvent
|
|
4862
5219
|
});
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
5220
|
+
let streamMetadata = null;
|
|
5221
|
+
let gadgetCallCount = 0;
|
|
5222
|
+
const textOutputs = [];
|
|
5223
|
+
const gadgetResults = [];
|
|
5224
|
+
for await (const event of processor.process(stream2)) {
|
|
5225
|
+
if (event.type === "stream_complete") {
|
|
5226
|
+
streamMetadata = event;
|
|
5227
|
+
continue;
|
|
5228
|
+
}
|
|
5229
|
+
if (event.type === "text") {
|
|
5230
|
+
textOutputs.push(event.content);
|
|
5231
|
+
} else if (event.type === "gadget_result") {
|
|
5232
|
+
gadgetCallCount++;
|
|
5233
|
+
gadgetResults.push(event);
|
|
5234
|
+
}
|
|
5235
|
+
yield event;
|
|
4866
5236
|
}
|
|
5237
|
+
if (!streamMetadata) {
|
|
5238
|
+
throw new Error("Stream processing completed without metadata event");
|
|
5239
|
+
}
|
|
5240
|
+
const result = streamMetadata;
|
|
4867
5241
|
this.logger.info("LLM response completed", {
|
|
4868
5242
|
finishReason: result.finishReason,
|
|
4869
5243
|
usage: result.usage,
|
|
@@ -4888,9 +5262,6 @@ var init_agent = __esm({
|
|
|
4888
5262
|
});
|
|
4889
5263
|
let finalMessage = result.finalMessage;
|
|
4890
5264
|
if (this.hooks.controllers?.afterLLMCall) {
|
|
4891
|
-
const gadgetCallCount = result.outputs.filter(
|
|
4892
|
-
(output) => output.type === "gadget_result"
|
|
4893
|
-
).length;
|
|
4894
5265
|
const context = {
|
|
4895
5266
|
iteration: currentIteration,
|
|
4896
5267
|
maxIterations: this.maxIterations,
|
|
@@ -4911,31 +5282,29 @@ var init_agent = __esm({
|
|
|
4911
5282
|
if (msg.role === "user") {
|
|
4912
5283
|
this.conversation.addUserMessage(msg.content);
|
|
4913
5284
|
} else if (msg.role === "assistant") {
|
|
4914
|
-
this.conversation.addAssistantMessage(
|
|
5285
|
+
this.conversation.addAssistantMessage(extractMessageText(msg.content));
|
|
4915
5286
|
} else if (msg.role === "system") {
|
|
4916
|
-
this.conversation.addUserMessage(`[System] ${
|
|
5287
|
+
this.conversation.addUserMessage(`[System] ${extractMessageText(msg.content)}`);
|
|
4917
5288
|
}
|
|
4918
5289
|
}
|
|
4919
5290
|
}
|
|
4920
5291
|
}
|
|
4921
5292
|
if (result.didExecuteGadgets) {
|
|
4922
5293
|
if (this.textWithGadgetsHandler) {
|
|
4923
|
-
const textContent =
|
|
4924
|
-
(output) => output.type === "text"
|
|
4925
|
-
).map((output) => output.content).join("");
|
|
5294
|
+
const textContent = textOutputs.join("");
|
|
4926
5295
|
if (textContent.trim()) {
|
|
4927
5296
|
const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
|
|
4928
|
-
this.conversation.
|
|
5297
|
+
this.conversation.addGadgetCallResult(
|
|
4929
5298
|
gadgetName,
|
|
4930
5299
|
parameterMapping(textContent),
|
|
4931
5300
|
resultMapping ? resultMapping(textContent) : textContent
|
|
4932
5301
|
);
|
|
4933
5302
|
}
|
|
4934
5303
|
}
|
|
4935
|
-
for (const output of
|
|
5304
|
+
for (const output of gadgetResults) {
|
|
4936
5305
|
if (output.type === "gadget_result") {
|
|
4937
5306
|
const gadgetResult = output.result;
|
|
4938
|
-
this.conversation.
|
|
5307
|
+
this.conversation.addGadgetCallResult(
|
|
4939
5308
|
gadgetResult.gadgetName,
|
|
4940
5309
|
gadgetResult.parameters,
|
|
4941
5310
|
gadgetResult.error ?? gadgetResult.result ?? "",
|
|
@@ -4946,7 +5315,7 @@ var init_agent = __esm({
|
|
|
4946
5315
|
}
|
|
4947
5316
|
} else {
|
|
4948
5317
|
if (finalMessage.trim()) {
|
|
4949
|
-
this.conversation.
|
|
5318
|
+
this.conversation.addGadgetCallResult(
|
|
4950
5319
|
"TellUser",
|
|
4951
5320
|
{ message: finalMessage, done: false, type: "info" },
|
|
4952
5321
|
`\u2139\uFE0F ${finalMessage}`
|
|
@@ -5072,10 +5441,10 @@ var init_agent = __esm({
|
|
|
5072
5441
|
return this.client.modelRegistry.getModelLimits(unprefixedModelId)?.maxOutputTokens;
|
|
5073
5442
|
}
|
|
5074
5443
|
/**
|
|
5075
|
-
*
|
|
5444
|
+
* Chain the output limiter interceptor with user-provided hooks.
|
|
5076
5445
|
* The limiter runs first, then chains to any user interceptor.
|
|
5077
5446
|
*/
|
|
5078
|
-
|
|
5447
|
+
chainOutputLimiterWithUserHooks(userHooks) {
|
|
5079
5448
|
if (!this.outputLimitEnabled) {
|
|
5080
5449
|
return userHooks ?? {};
|
|
5081
5450
|
}
|
|
@@ -5154,20 +5523,23 @@ var init_builder = __esm({
|
|
|
5154
5523
|
promptConfig;
|
|
5155
5524
|
gadgets = [];
|
|
5156
5525
|
initialMessages = [];
|
|
5157
|
-
|
|
5526
|
+
requestHumanInput;
|
|
5158
5527
|
gadgetStartPrefix;
|
|
5159
5528
|
gadgetEndPrefix;
|
|
5160
5529
|
gadgetArgPrefix;
|
|
5161
5530
|
textOnlyHandler;
|
|
5162
5531
|
textWithGadgetsHandler;
|
|
5163
5532
|
stopOnGadgetError;
|
|
5164
|
-
|
|
5533
|
+
canRecoverFromGadgetError;
|
|
5165
5534
|
defaultGadgetTimeoutMs;
|
|
5166
5535
|
gadgetOutputLimit;
|
|
5167
5536
|
gadgetOutputLimitPercent;
|
|
5168
5537
|
compactionConfig;
|
|
5169
5538
|
signal;
|
|
5170
5539
|
trailingMessage;
|
|
5540
|
+
subagentConfig;
|
|
5541
|
+
nestedEventCallback;
|
|
5542
|
+
parentContext;
|
|
5171
5543
|
constructor(client) {
|
|
5172
5544
|
this.client = client;
|
|
5173
5545
|
}
|
|
@@ -5258,13 +5630,13 @@ var init_builder = __esm({
|
|
|
5258
5630
|
*
|
|
5259
5631
|
* @example
|
|
5260
5632
|
* ```typescript
|
|
5261
|
-
* .
|
|
5633
|
+
* .withPromptTemplateConfig({
|
|
5262
5634
|
* mainInstruction: "Use the gadget markers below:",
|
|
5263
5635
|
* rules: ["Always use markers", "Never use function calling"]
|
|
5264
5636
|
* })
|
|
5265
5637
|
* ```
|
|
5266
5638
|
*/
|
|
5267
|
-
|
|
5639
|
+
withPromptTemplateConfig(config) {
|
|
5268
5640
|
this.promptConfig = config;
|
|
5269
5641
|
return this;
|
|
5270
5642
|
}
|
|
@@ -5344,7 +5716,7 @@ var init_builder = __esm({
|
|
|
5344
5716
|
* ```
|
|
5345
5717
|
*/
|
|
5346
5718
|
onHumanInput(handler) {
|
|
5347
|
-
this.
|
|
5719
|
+
this.requestHumanInput = handler;
|
|
5348
5720
|
return this;
|
|
5349
5721
|
}
|
|
5350
5722
|
/**
|
|
@@ -5479,9 +5851,9 @@ var init_builder = __esm({
|
|
|
5479
5851
|
* Provides fine-grained control over whether to continue after different types of errors.
|
|
5480
5852
|
* Overrides `stopOnGadgetError` when provided.
|
|
5481
5853
|
*
|
|
5482
|
-
* **Note:** This builder method configures the underlying `
|
|
5854
|
+
* **Note:** This builder method configures the underlying `canRecoverFromGadgetError` option
|
|
5483
5855
|
* in `AgentOptions`. The method is named `withErrorHandler` for better developer experience,
|
|
5484
|
-
* but maps to the `
|
|
5856
|
+
* but maps to the `canRecoverFromGadgetError` property internally.
|
|
5485
5857
|
*
|
|
5486
5858
|
* @param handler - Function that decides whether to continue after an error.
|
|
5487
5859
|
* Return `true` to continue execution, `false` to stop.
|
|
@@ -5502,7 +5874,7 @@ var init_builder = __esm({
|
|
|
5502
5874
|
* ```
|
|
5503
5875
|
*/
|
|
5504
5876
|
withErrorHandler(handler) {
|
|
5505
|
-
this.
|
|
5877
|
+
this.canRecoverFromGadgetError = handler;
|
|
5506
5878
|
return this;
|
|
5507
5879
|
}
|
|
5508
5880
|
/**
|
|
@@ -5643,6 +6015,95 @@ var init_builder = __esm({
|
|
|
5643
6015
|
this.signal = signal;
|
|
5644
6016
|
return this;
|
|
5645
6017
|
}
|
|
6018
|
+
/**
|
|
6019
|
+
* Set subagent configuration overrides.
|
|
6020
|
+
*
|
|
6021
|
+
* Subagent gadgets (like BrowseWeb) can read these settings from ExecutionContext
|
|
6022
|
+
* to inherit model and other options from the CLI configuration.
|
|
6023
|
+
*
|
|
6024
|
+
* @param config - Subagent configuration map keyed by gadget name
|
|
6025
|
+
* @returns This builder for chaining
|
|
6026
|
+
*
|
|
6027
|
+
* @example
|
|
6028
|
+
* ```typescript
|
|
6029
|
+
* .withSubagentConfig({
|
|
6030
|
+
* BrowseWeb: { model: "inherit", maxIterations: 20, headless: true },
|
|
6031
|
+
* CodeAnalyzer: { model: "sonnet", maxIterations: 10 }
|
|
6032
|
+
* })
|
|
6033
|
+
* ```
|
|
6034
|
+
*/
|
|
6035
|
+
withSubagentConfig(config) {
|
|
6036
|
+
this.subagentConfig = config;
|
|
6037
|
+
return this;
|
|
6038
|
+
}
|
|
6039
|
+
/**
|
|
6040
|
+
* Set the callback for nested subagent events.
|
|
6041
|
+
*
|
|
6042
|
+
* Subagent gadgets (like BrowseWeb) can use ExecutionContext.onNestedEvent
|
|
6043
|
+
* to report their internal LLM calls and gadget executions in real-time.
|
|
6044
|
+
* This callback receives those events, enabling hierarchical progress display.
|
|
6045
|
+
*
|
|
6046
|
+
* @param callback - Function to handle nested agent events
|
|
6047
|
+
* @returns This builder for chaining
|
|
6048
|
+
*
|
|
6049
|
+
* @example
|
|
6050
|
+
* ```typescript
|
|
6051
|
+
* .withNestedEventCallback((event) => {
|
|
6052
|
+
* if (event.type === "llm_call_start") {
|
|
6053
|
+
* console.log(` Nested LLM #${event.event.iteration} starting...`);
|
|
6054
|
+
* } else if (event.type === "gadget_call") {
|
|
6055
|
+
* console.log(` ⏵ ${event.event.call.gadgetName}...`);
|
|
6056
|
+
* }
|
|
6057
|
+
* })
|
|
6058
|
+
* ```
|
|
6059
|
+
*/
|
|
6060
|
+
withNestedEventCallback(callback) {
|
|
6061
|
+
this.nestedEventCallback = callback;
|
|
6062
|
+
return this;
|
|
6063
|
+
}
|
|
6064
|
+
/**
|
|
6065
|
+
* Enable automatic nested event forwarding to parent agent.
|
|
6066
|
+
*
|
|
6067
|
+
* When building a subagent inside a gadget, call this method to automatically
|
|
6068
|
+
* forward all LLM calls and gadget events to the parent agent. This enables
|
|
6069
|
+
* hierarchical progress display without any manual event handling.
|
|
6070
|
+
*
|
|
6071
|
+
* The method extracts `invocationId` and `onNestedEvent` from the execution
|
|
6072
|
+
* context and sets up automatic forwarding via hooks and event wrapping.
|
|
6073
|
+
*
|
|
6074
|
+
* @param ctx - ExecutionContext passed to the gadget's execute() method
|
|
6075
|
+
* @param depth - Nesting depth (default: 1 for direct child)
|
|
6076
|
+
* @returns This builder for chaining
|
|
6077
|
+
*
|
|
6078
|
+
* @example
|
|
6079
|
+
* ```typescript
|
|
6080
|
+
* // In a subagent gadget like BrowseWeb - ONE LINE enables auto-forwarding:
|
|
6081
|
+
* execute: async (params, ctx) => {
|
|
6082
|
+
* const agent = new AgentBuilder(client)
|
|
6083
|
+
* .withModel(model)
|
|
6084
|
+
* .withGadgets(Navigate, Click, Screenshot)
|
|
6085
|
+
* .withParentContext(ctx) // <-- This is all you need!
|
|
6086
|
+
* .ask(params.task);
|
|
6087
|
+
*
|
|
6088
|
+
* for await (const event of agent.run()) {
|
|
6089
|
+
* // Events automatically forwarded - just process normally
|
|
6090
|
+
* if (event.type === "text") {
|
|
6091
|
+
* result = event.content;
|
|
6092
|
+
* }
|
|
6093
|
+
* }
|
|
6094
|
+
* }
|
|
6095
|
+
* ```
|
|
6096
|
+
*/
|
|
6097
|
+
withParentContext(ctx, depth = 1) {
|
|
6098
|
+
if (ctx.onNestedEvent && ctx.invocationId) {
|
|
6099
|
+
this.parentContext = {
|
|
6100
|
+
invocationId: ctx.invocationId,
|
|
6101
|
+
onNestedEvent: ctx.onNestedEvent,
|
|
6102
|
+
depth
|
|
6103
|
+
};
|
|
6104
|
+
}
|
|
6105
|
+
return this;
|
|
6106
|
+
}
|
|
5646
6107
|
/**
|
|
5647
6108
|
* Add an ephemeral trailing message that appears at the end of each LLM request.
|
|
5648
6109
|
*
|
|
@@ -5710,14 +6171,58 @@ ${endPrefix}`
|
|
|
5710
6171
|
return this;
|
|
5711
6172
|
}
|
|
5712
6173
|
/**
|
|
5713
|
-
* Compose the final hooks, including
|
|
6174
|
+
* Compose the final hooks, including:
|
|
6175
|
+
* - Trailing message injection (if configured)
|
|
6176
|
+
* - Nested event forwarding for LLM calls (if parentContext is set)
|
|
5714
6177
|
*/
|
|
5715
6178
|
composeHooks() {
|
|
6179
|
+
let hooks = this.hooks;
|
|
6180
|
+
if (this.parentContext) {
|
|
6181
|
+
const { invocationId, onNestedEvent, depth } = this.parentContext;
|
|
6182
|
+
const existingOnLLMCallStart = hooks?.observers?.onLLMCallStart;
|
|
6183
|
+
const existingOnLLMCallComplete = hooks?.observers?.onLLMCallComplete;
|
|
6184
|
+
hooks = {
|
|
6185
|
+
...hooks,
|
|
6186
|
+
observers: {
|
|
6187
|
+
...hooks?.observers,
|
|
6188
|
+
onLLMCallStart: async (context) => {
|
|
6189
|
+
onNestedEvent({
|
|
6190
|
+
type: "llm_call_start",
|
|
6191
|
+
gadgetInvocationId: invocationId,
|
|
6192
|
+
depth,
|
|
6193
|
+
event: {
|
|
6194
|
+
iteration: context.iteration,
|
|
6195
|
+
model: context.options.model
|
|
6196
|
+
}
|
|
6197
|
+
});
|
|
6198
|
+
if (existingOnLLMCallStart) {
|
|
6199
|
+
await existingOnLLMCallStart(context);
|
|
6200
|
+
}
|
|
6201
|
+
},
|
|
6202
|
+
onLLMCallComplete: async (context) => {
|
|
6203
|
+
onNestedEvent({
|
|
6204
|
+
type: "llm_call_end",
|
|
6205
|
+
gadgetInvocationId: invocationId,
|
|
6206
|
+
depth,
|
|
6207
|
+
event: {
|
|
6208
|
+
iteration: context.iteration,
|
|
6209
|
+
model: context.options.model,
|
|
6210
|
+
outputTokens: context.usage?.outputTokens,
|
|
6211
|
+
finishReason: context.finishReason
|
|
6212
|
+
}
|
|
6213
|
+
});
|
|
6214
|
+
if (existingOnLLMCallComplete) {
|
|
6215
|
+
await existingOnLLMCallComplete(context);
|
|
6216
|
+
}
|
|
6217
|
+
}
|
|
6218
|
+
}
|
|
6219
|
+
};
|
|
6220
|
+
}
|
|
5716
6221
|
if (!this.trailingMessage) {
|
|
5717
|
-
return
|
|
6222
|
+
return hooks;
|
|
5718
6223
|
}
|
|
5719
6224
|
const trailingMsg = this.trailingMessage;
|
|
5720
|
-
const existingBeforeLLMCall =
|
|
6225
|
+
const existingBeforeLLMCall = hooks?.controllers?.beforeLLMCall;
|
|
5721
6226
|
const trailingMessageController = async (ctx) => {
|
|
5722
6227
|
const result = existingBeforeLLMCall ? await existingBeforeLLMCall(ctx) : { action: "proceed" };
|
|
5723
6228
|
if (result.action === "skip") {
|
|
@@ -5732,9 +6237,9 @@ ${endPrefix}`
|
|
|
5732
6237
|
};
|
|
5733
6238
|
};
|
|
5734
6239
|
return {
|
|
5735
|
-
...
|
|
6240
|
+
...hooks,
|
|
5736
6241
|
controllers: {
|
|
5737
|
-
...
|
|
6242
|
+
...hooks?.controllers,
|
|
5738
6243
|
beforeLLMCall: trailingMessageController
|
|
5739
6244
|
}
|
|
5740
6245
|
};
|
|
@@ -5795,6 +6300,19 @@ ${endPrefix}`
|
|
|
5795
6300
|
this.client = new LLMistClass();
|
|
5796
6301
|
}
|
|
5797
6302
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
6303
|
+
let onNestedEvent = this.nestedEventCallback;
|
|
6304
|
+
if (this.parentContext) {
|
|
6305
|
+
const { invocationId, onNestedEvent: parentCallback, depth } = this.parentContext;
|
|
6306
|
+
const existingCallback = this.nestedEventCallback;
|
|
6307
|
+
onNestedEvent = (event) => {
|
|
6308
|
+
parentCallback({
|
|
6309
|
+
...event,
|
|
6310
|
+
gadgetInvocationId: invocationId,
|
|
6311
|
+
depth: event.depth + depth
|
|
6312
|
+
});
|
|
6313
|
+
existingCallback?.(event);
|
|
6314
|
+
};
|
|
6315
|
+
}
|
|
5798
6316
|
return {
|
|
5799
6317
|
client: this.client,
|
|
5800
6318
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -5807,19 +6325,21 @@ ${endPrefix}`
|
|
|
5807
6325
|
hooks: this.composeHooks(),
|
|
5808
6326
|
promptConfig: this.promptConfig,
|
|
5809
6327
|
initialMessages: this.initialMessages,
|
|
5810
|
-
|
|
6328
|
+
requestHumanInput: this.requestHumanInput,
|
|
5811
6329
|
gadgetStartPrefix: this.gadgetStartPrefix,
|
|
5812
6330
|
gadgetEndPrefix: this.gadgetEndPrefix,
|
|
5813
6331
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
5814
6332
|
textOnlyHandler: this.textOnlyHandler,
|
|
5815
6333
|
textWithGadgetsHandler: this.textWithGadgetsHandler,
|
|
5816
6334
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
5817
|
-
|
|
6335
|
+
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
5818
6336
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
5819
6337
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
5820
6338
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
5821
6339
|
compactionConfig: this.compactionConfig,
|
|
5822
|
-
signal: this.signal
|
|
6340
|
+
signal: this.signal,
|
|
6341
|
+
subagentConfig: this.subagentConfig,
|
|
6342
|
+
onNestedEvent
|
|
5823
6343
|
};
|
|
5824
6344
|
}
|
|
5825
6345
|
ask(userPrompt) {
|
|
@@ -5976,6 +6496,19 @@ ${endPrefix}`
|
|
|
5976
6496
|
this.client = new LLMistClass();
|
|
5977
6497
|
}
|
|
5978
6498
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
6499
|
+
let onNestedEvent = this.nestedEventCallback;
|
|
6500
|
+
if (this.parentContext) {
|
|
6501
|
+
const { invocationId, onNestedEvent: parentCallback, depth } = this.parentContext;
|
|
6502
|
+
const existingCallback = this.nestedEventCallback;
|
|
6503
|
+
onNestedEvent = (event) => {
|
|
6504
|
+
parentCallback({
|
|
6505
|
+
...event,
|
|
6506
|
+
gadgetInvocationId: invocationId,
|
|
6507
|
+
depth: event.depth + depth
|
|
6508
|
+
});
|
|
6509
|
+
existingCallback?.(event);
|
|
6510
|
+
};
|
|
6511
|
+
}
|
|
5979
6512
|
const options = {
|
|
5980
6513
|
client: this.client,
|
|
5981
6514
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -5988,19 +6521,21 @@ ${endPrefix}`
|
|
|
5988
6521
|
hooks: this.composeHooks(),
|
|
5989
6522
|
promptConfig: this.promptConfig,
|
|
5990
6523
|
initialMessages: this.initialMessages,
|
|
5991
|
-
|
|
6524
|
+
requestHumanInput: this.requestHumanInput,
|
|
5992
6525
|
gadgetStartPrefix: this.gadgetStartPrefix,
|
|
5993
6526
|
gadgetEndPrefix: this.gadgetEndPrefix,
|
|
5994
6527
|
gadgetArgPrefix: this.gadgetArgPrefix,
|
|
5995
6528
|
textOnlyHandler: this.textOnlyHandler,
|
|
5996
6529
|
textWithGadgetsHandler: this.textWithGadgetsHandler,
|
|
5997
6530
|
stopOnGadgetError: this.stopOnGadgetError,
|
|
5998
|
-
|
|
6531
|
+
canRecoverFromGadgetError: this.canRecoverFromGadgetError,
|
|
5999
6532
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
6000
6533
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
6001
6534
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
6002
6535
|
compactionConfig: this.compactionConfig,
|
|
6003
|
-
signal: this.signal
|
|
6536
|
+
signal: this.signal,
|
|
6537
|
+
subagentConfig: this.subagentConfig,
|
|
6538
|
+
onNestedEvent
|
|
6004
6539
|
};
|
|
6005
6540
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
6006
6541
|
}
|
|
@@ -6306,9 +6841,9 @@ var init_base_provider = __esm({
|
|
|
6306
6841
|
*/
|
|
6307
6842
|
async *stream(options, descriptor, spec) {
|
|
6308
6843
|
const preparedMessages = this.prepareMessages(options.messages);
|
|
6309
|
-
const payload = this.
|
|
6844
|
+
const payload = this.buildApiRequest(options, descriptor, spec, preparedMessages);
|
|
6310
6845
|
const rawStream = await this.executeStreamRequest(payload, options.signal);
|
|
6311
|
-
yield* this.
|
|
6846
|
+
yield* this.normalizeProviderStream(rawStream);
|
|
6312
6847
|
}
|
|
6313
6848
|
/**
|
|
6314
6849
|
* Prepare messages for the request.
|
|
@@ -6408,11 +6943,11 @@ var init_anthropic = __esm({
|
|
|
6408
6943
|
"Anthropic does not support speech generation. Use OpenAI (TTS) or Google Gemini (TTS) instead."
|
|
6409
6944
|
);
|
|
6410
6945
|
}
|
|
6411
|
-
|
|
6946
|
+
buildApiRequest(options, descriptor, spec, messages) {
|
|
6412
6947
|
const systemMessages = messages.filter((message) => message.role === "system");
|
|
6413
6948
|
const system = systemMessages.length > 0 ? systemMessages.map((m, index) => ({
|
|
6414
6949
|
type: "text",
|
|
6415
|
-
text:
|
|
6950
|
+
text: extractMessageText(m.content),
|
|
6416
6951
|
// Add cache_control to the LAST system message block
|
|
6417
6952
|
...index === systemMessages.length - 1 ? { cache_control: { type: "ephemeral" } } : {}
|
|
6418
6953
|
})) : void 0;
|
|
@@ -6449,7 +6984,7 @@ var init_anthropic = __esm({
|
|
|
6449
6984
|
* Handles text, images (base64 only), and applies cache_control.
|
|
6450
6985
|
*/
|
|
6451
6986
|
convertToAnthropicContent(content, addCacheControl) {
|
|
6452
|
-
const parts =
|
|
6987
|
+
const parts = normalizeMessageContent(content);
|
|
6453
6988
|
return parts.map((part, index) => {
|
|
6454
6989
|
const isLastPart = index === parts.length - 1;
|
|
6455
6990
|
const cacheControl = addCacheControl && isLastPart ? { cache_control: { type: "ephemeral" } } : {};
|
|
@@ -6495,7 +7030,7 @@ var init_anthropic = __esm({
|
|
|
6495
7030
|
const stream2 = await client.messages.create(payload, signal ? { signal } : void 0);
|
|
6496
7031
|
return stream2;
|
|
6497
7032
|
}
|
|
6498
|
-
async *
|
|
7033
|
+
async *normalizeProviderStream(iterable) {
|
|
6499
7034
|
const stream2 = iterable;
|
|
6500
7035
|
let inputTokens = 0;
|
|
6501
7036
|
let cachedInputTokens = 0;
|
|
@@ -6572,7 +7107,7 @@ var init_anthropic = __esm({
|
|
|
6572
7107
|
async countTokens(messages, descriptor, _spec) {
|
|
6573
7108
|
const client = this.client;
|
|
6574
7109
|
const systemMessages = messages.filter((message) => message.role === "system");
|
|
6575
|
-
const system = systemMessages.length > 0 ? systemMessages.map((m) =>
|
|
7110
|
+
const system = systemMessages.length > 0 ? systemMessages.map((m) => extractMessageText(m.content)).join("\n\n") : void 0;
|
|
6576
7111
|
const conversation = messages.filter(
|
|
6577
7112
|
(message) => message.role !== "system"
|
|
6578
7113
|
).map((message) => ({
|
|
@@ -6594,7 +7129,7 @@ var init_anthropic = __esm({
|
|
|
6594
7129
|
let totalChars = 0;
|
|
6595
7130
|
let imageCount = 0;
|
|
6596
7131
|
for (const msg of messages) {
|
|
6597
|
-
const parts =
|
|
7132
|
+
const parts = normalizeMessageContent(msg.content);
|
|
6598
7133
|
for (const part of parts) {
|
|
6599
7134
|
if (part.type === "text") {
|
|
6600
7135
|
totalChars += part.text.length;
|
|
@@ -7285,7 +7820,7 @@ var init_gemini = __esm({
|
|
|
7285
7820
|
format: spec?.defaultFormat ?? "wav"
|
|
7286
7821
|
};
|
|
7287
7822
|
}
|
|
7288
|
-
|
|
7823
|
+
buildApiRequest(options, descriptor, _spec, messages) {
|
|
7289
7824
|
const contents = this.convertMessagesToContents(messages);
|
|
7290
7825
|
const generationConfig = this.buildGenerationConfig(options);
|
|
7291
7826
|
const config = {
|
|
@@ -7337,7 +7872,7 @@ var init_gemini = __esm({
|
|
|
7337
7872
|
if (message.role === "system") {
|
|
7338
7873
|
expandedMessages.push({
|
|
7339
7874
|
role: "user",
|
|
7340
|
-
content:
|
|
7875
|
+
content: extractMessageText(message.content)
|
|
7341
7876
|
});
|
|
7342
7877
|
expandedMessages.push({
|
|
7343
7878
|
role: "assistant",
|
|
@@ -7387,7 +7922,7 @@ var init_gemini = __esm({
|
|
|
7387
7922
|
* Handles text, images, and audio (Gemini supports all three).
|
|
7388
7923
|
*/
|
|
7389
7924
|
convertToGeminiParts(content) {
|
|
7390
|
-
const parts =
|
|
7925
|
+
const parts = normalizeMessageContent(content);
|
|
7391
7926
|
return parts.map((part) => {
|
|
7392
7927
|
if (part.type === "text") {
|
|
7393
7928
|
return { text: part.text };
|
|
@@ -7432,10 +7967,10 @@ var init_gemini = __esm({
|
|
|
7432
7967
|
}
|
|
7433
7968
|
return Object.keys(config).length > 0 ? config : null;
|
|
7434
7969
|
}
|
|
7435
|
-
async *
|
|
7970
|
+
async *normalizeProviderStream(iterable) {
|
|
7436
7971
|
const stream2 = iterable;
|
|
7437
7972
|
for await (const chunk of stream2) {
|
|
7438
|
-
const text3 = this.
|
|
7973
|
+
const text3 = this.extractMessageText(chunk);
|
|
7439
7974
|
if (text3) {
|
|
7440
7975
|
yield { text: text3, rawEvent: chunk };
|
|
7441
7976
|
}
|
|
@@ -7446,7 +7981,7 @@ var init_gemini = __esm({
|
|
|
7446
7981
|
}
|
|
7447
7982
|
}
|
|
7448
7983
|
}
|
|
7449
|
-
|
|
7984
|
+
extractMessageText(chunk) {
|
|
7450
7985
|
if (!chunk?.candidates) {
|
|
7451
7986
|
return "";
|
|
7452
7987
|
}
|
|
@@ -7511,7 +8046,7 @@ var init_gemini = __esm({
|
|
|
7511
8046
|
let totalChars = 0;
|
|
7512
8047
|
let mediaCount = 0;
|
|
7513
8048
|
for (const msg of messages) {
|
|
7514
|
-
const parts =
|
|
8049
|
+
const parts = normalizeMessageContent(msg.content);
|
|
7515
8050
|
for (const part of parts) {
|
|
7516
8051
|
if (part.type === "text") {
|
|
7517
8052
|
totalChars += part.text.length;
|
|
@@ -8257,7 +8792,7 @@ var init_openai = __esm({
|
|
|
8257
8792
|
format
|
|
8258
8793
|
};
|
|
8259
8794
|
}
|
|
8260
|
-
|
|
8795
|
+
buildApiRequest(options, descriptor, spec, messages) {
|
|
8261
8796
|
const { maxTokens, temperature, topP, stopSequences, extra } = options;
|
|
8262
8797
|
const supportsTemperature = spec?.metadata?.supportsTemperature !== false;
|
|
8263
8798
|
const shouldIncludeTemperature = typeof temperature === "number" && supportsTemperature;
|
|
@@ -8292,7 +8827,7 @@ var init_openai = __esm({
|
|
|
8292
8827
|
...message.name ? { name: message.name } : {}
|
|
8293
8828
|
};
|
|
8294
8829
|
}
|
|
8295
|
-
const textContent = typeof message.content === "string" ? message.content :
|
|
8830
|
+
const textContent = typeof message.content === "string" ? message.content : extractMessageText(message.content);
|
|
8296
8831
|
if (role === "system") {
|
|
8297
8832
|
return {
|
|
8298
8833
|
role: "system",
|
|
@@ -8352,7 +8887,7 @@ var init_openai = __esm({
|
|
|
8352
8887
|
const stream2 = await client.chat.completions.create(payload, signal ? { signal } : void 0);
|
|
8353
8888
|
return stream2;
|
|
8354
8889
|
}
|
|
8355
|
-
async *
|
|
8890
|
+
async *normalizeProviderStream(iterable) {
|
|
8356
8891
|
const stream2 = iterable;
|
|
8357
8892
|
for await (const chunk of stream2) {
|
|
8358
8893
|
const text3 = chunk.choices.map((choice) => choice.delta?.content ?? "").join("");
|
|
@@ -8410,9 +8945,9 @@ var init_openai = __esm({
|
|
|
8410
8945
|
tokenCount += OPENAI_MESSAGE_OVERHEAD_TOKENS;
|
|
8411
8946
|
const roleText = ROLE_MAP[message.role];
|
|
8412
8947
|
tokenCount += encoding.encode(roleText).length;
|
|
8413
|
-
const textContent =
|
|
8948
|
+
const textContent = extractMessageText(message.content);
|
|
8414
8949
|
tokenCount += encoding.encode(textContent).length;
|
|
8415
|
-
const parts =
|
|
8950
|
+
const parts = normalizeMessageContent(message.content);
|
|
8416
8951
|
for (const part of parts) {
|
|
8417
8952
|
if (part.type === "image") {
|
|
8418
8953
|
imageCount++;
|
|
@@ -8437,7 +8972,7 @@ var init_openai = __esm({
|
|
|
8437
8972
|
let totalChars = 0;
|
|
8438
8973
|
let imageCount = 0;
|
|
8439
8974
|
for (const msg of messages) {
|
|
8440
|
-
const parts =
|
|
8975
|
+
const parts = normalizeMessageContent(msg.content);
|
|
8441
8976
|
for (const part of parts) {
|
|
8442
8977
|
if (part.type === "text") {
|
|
8443
8978
|
totalChars += part.text.length;
|
|
@@ -10125,7 +10660,7 @@ var MockBuilder = class {
|
|
|
10125
10660
|
whenMessageContains(text3) {
|
|
10126
10661
|
this.matchers.push(
|
|
10127
10662
|
(ctx) => ctx.messages.some(
|
|
10128
|
-
(msg) =>
|
|
10663
|
+
(msg) => extractMessageText(msg.content).toLowerCase().includes(text3.toLowerCase())
|
|
10129
10664
|
)
|
|
10130
10665
|
);
|
|
10131
10666
|
return this;
|
|
@@ -10140,7 +10675,7 @@ var MockBuilder = class {
|
|
|
10140
10675
|
this.matchers.push((ctx) => {
|
|
10141
10676
|
const lastMsg = ctx.messages[ctx.messages.length - 1];
|
|
10142
10677
|
if (!lastMsg) return false;
|
|
10143
|
-
return
|
|
10678
|
+
return extractMessageText(lastMsg.content).toLowerCase().includes(text3.toLowerCase());
|
|
10144
10679
|
});
|
|
10145
10680
|
return this;
|
|
10146
10681
|
}
|
|
@@ -10151,7 +10686,7 @@ var MockBuilder = class {
|
|
|
10151
10686
|
* mockLLM().whenMessageMatches(/calculate \d+/)
|
|
10152
10687
|
*/
|
|
10153
10688
|
whenMessageMatches(regex) {
|
|
10154
|
-
this.matchers.push((ctx) => ctx.messages.some((msg) => regex.test(
|
|
10689
|
+
this.matchers.push((ctx) => ctx.messages.some((msg) => regex.test(extractMessageText(msg.content))));
|
|
10155
10690
|
return this;
|
|
10156
10691
|
}
|
|
10157
10692
|
/**
|
|
@@ -10163,7 +10698,7 @@ var MockBuilder = class {
|
|
|
10163
10698
|
whenRoleContains(role, text3) {
|
|
10164
10699
|
this.matchers.push(
|
|
10165
10700
|
(ctx) => ctx.messages.some(
|
|
10166
|
-
(msg) => msg.role === role &&
|
|
10701
|
+
(msg) => msg.role === role && extractMessageText(msg.content).toLowerCase().includes(text3.toLowerCase())
|
|
10167
10702
|
)
|
|
10168
10703
|
);
|
|
10169
10704
|
return this;
|
|
@@ -10585,7 +11120,7 @@ var MockConversationManager = class {
|
|
|
10585
11120
|
this.history.push(msg);
|
|
10586
11121
|
this.addedMessages.push(msg);
|
|
10587
11122
|
}
|
|
10588
|
-
|
|
11123
|
+
addGadgetCallResult(gadgetName, parameters, result) {
|
|
10589
11124
|
const assistantMsg = {
|
|
10590
11125
|
role: "assistant",
|
|
10591
11126
|
content: `!!!GADGET_START:${gadgetName}
|
|
@@ -10695,7 +11230,7 @@ function createMockConversationManager(turnCount, baseMessages = []) {
|
|
|
10695
11230
|
|
|
10696
11231
|
// src/testing/mock-gadget.ts
|
|
10697
11232
|
init_gadget();
|
|
10698
|
-
var MockGadgetImpl = class extends
|
|
11233
|
+
var MockGadgetImpl = class extends AbstractGadget {
|
|
10699
11234
|
name;
|
|
10700
11235
|
description;
|
|
10701
11236
|
parameterSchema;
|
|
@@ -10948,22 +11483,23 @@ export {
|
|
|
10948
11483
|
resolveRulesTemplate,
|
|
10949
11484
|
resolveHintTemplate,
|
|
10950
11485
|
init_prompt_config,
|
|
10951
|
-
|
|
10952
|
-
|
|
11486
|
+
normalizeMessageContent,
|
|
11487
|
+
extractMessageText,
|
|
10953
11488
|
LLMMessageBuilder,
|
|
10954
11489
|
init_messages,
|
|
10955
11490
|
MediaStore,
|
|
10956
11491
|
init_media_store,
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
11492
|
+
TaskCompletionSignal,
|
|
11493
|
+
HumanInputRequiredException,
|
|
11494
|
+
TimeoutException,
|
|
11495
|
+
AbortException,
|
|
10960
11496
|
init_exceptions,
|
|
10961
11497
|
createLogger,
|
|
10962
11498
|
defaultLogger,
|
|
10963
11499
|
init_logger,
|
|
10964
11500
|
schemaToJSONSchema,
|
|
10965
11501
|
init_schema_to_json,
|
|
10966
|
-
|
|
11502
|
+
AbstractGadget,
|
|
10967
11503
|
init_gadget,
|
|
10968
11504
|
createGadget,
|
|
10969
11505
|
init_create_gadget,
|
|
@@ -10987,7 +11523,7 @@ export {
|
|
|
10987
11523
|
init_event_handlers,
|
|
10988
11524
|
GadgetOutputStore,
|
|
10989
11525
|
init_gadget_output_store,
|
|
10990
|
-
|
|
11526
|
+
GadgetCallParser,
|
|
10991
11527
|
init_parser,
|
|
10992
11528
|
GadgetExecutor,
|
|
10993
11529
|
init_executor,
|
|
@@ -11059,4 +11595,4 @@ export {
|
|
|
11059
11595
|
createEmptyStream,
|
|
11060
11596
|
createErrorStream
|
|
11061
11597
|
};
|
|
11062
|
-
//# sourceMappingURL=chunk-
|
|
11598
|
+
//# sourceMappingURL=chunk-JCFPJMRQ.js.map
|