llmist 2.6.0 → 3.0.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.
@@ -301,13 +301,13 @@ var init_prompt_config = __esm({
301
301
  });
302
302
 
303
303
  // src/core/messages.ts
304
- function normalizeContent(content) {
304
+ function normalizeMessageContent(content) {
305
305
  if (typeof content === "string") {
306
306
  return [{ type: "text", text: content }];
307
307
  }
308
308
  return content;
309
309
  }
310
- function extractText(content) {
310
+ function extractMessageText(content) {
311
311
  if (typeof content === "string") {
312
312
  return content;
313
313
  }
@@ -667,7 +667,17 @@ Produces: { "items": ["first", "second"] }`);
667
667
  this.messages.push({ role: "user", content: parts });
668
668
  return this;
669
669
  }
670
- addGadgetCall(gadget, parameters, result, media, mediaIds) {
670
+ /**
671
+ * Record a gadget execution result in the message history.
672
+ * Creates an assistant message with the gadget invocation and a user message with the result.
673
+ *
674
+ * @param gadget - Name of the gadget that was executed
675
+ * @param parameters - Parameters that were passed to the gadget
676
+ * @param result - Text result from the gadget execution
677
+ * @param media - Optional media outputs from the gadget
678
+ * @param mediaIds - Optional IDs for the media outputs
679
+ */
680
+ addGadgetCallResult(gadget, parameters, result, media, mediaIds) {
671
681
  const paramStr = this.formatBlockParameters(parameters, "");
672
682
  this.messages.push({
673
683
  role: "assistant",
@@ -1232,21 +1242,21 @@ var init_media_store = __esm({
1232
1242
  });
1233
1243
 
1234
1244
  // src/gadgets/exceptions.ts
1235
- var BreakLoopException, HumanInputException, TimeoutException, AbortError;
1245
+ var TaskCompletionSignal, HumanInputRequiredException, TimeoutException, AbortException;
1236
1246
  var init_exceptions = __esm({
1237
1247
  "src/gadgets/exceptions.ts"() {
1238
1248
  "use strict";
1239
- BreakLoopException = class extends Error {
1249
+ TaskCompletionSignal = class extends Error {
1240
1250
  constructor(message) {
1241
1251
  super(message ?? "Agent loop terminated by gadget");
1242
- this.name = "BreakLoopException";
1252
+ this.name = "TaskCompletionSignal";
1243
1253
  }
1244
1254
  };
1245
- HumanInputException = class extends Error {
1255
+ HumanInputRequiredException = class extends Error {
1246
1256
  question;
1247
1257
  constructor(question) {
1248
1258
  super(`Human input required: ${question}`);
1249
- this.name = "HumanInputException";
1259
+ this.name = "HumanInputRequiredException";
1250
1260
  this.question = question;
1251
1261
  }
1252
1262
  };
@@ -1260,10 +1270,10 @@ var init_exceptions = __esm({
1260
1270
  this.timeoutMs = timeoutMs;
1261
1271
  }
1262
1272
  };
1263
- AbortError = class extends Error {
1273
+ AbortException = class extends Error {
1264
1274
  constructor(message) {
1265
1275
  super(message || "Gadget execution was aborted");
1266
- this.name = "AbortError";
1276
+ this.name = "AbortException";
1267
1277
  }
1268
1278
  };
1269
1279
  }
@@ -1353,7 +1363,7 @@ var init_schema_to_json = __esm({
1353
1363
  });
1354
1364
 
1355
1365
  // src/gadgets/gadget.ts
1356
- function formatParamsAsBlock(params, prefix = "", argPrefix = GADGET_ARG_PREFIX) {
1366
+ function formatParamsForBlockExample(params, prefix = "", argPrefix = GADGET_ARG_PREFIX) {
1357
1367
  const lines = [];
1358
1368
  for (const [key, value] of Object.entries(params)) {
1359
1369
  const fullPath = prefix ? `${prefix}/${key}` : key;
@@ -1361,14 +1371,14 @@ function formatParamsAsBlock(params, prefix = "", argPrefix = GADGET_ARG_PREFIX)
1361
1371
  value.forEach((item, index) => {
1362
1372
  const itemPath = `${fullPath}/${index}`;
1363
1373
  if (typeof item === "object" && item !== null) {
1364
- lines.push(formatParamsAsBlock(item, itemPath, argPrefix));
1374
+ lines.push(formatParamsForBlockExample(item, itemPath, argPrefix));
1365
1375
  } else {
1366
1376
  lines.push(`${argPrefix}${itemPath}`);
1367
1377
  lines.push(String(item));
1368
1378
  }
1369
1379
  });
1370
1380
  } else if (typeof value === "object" && value !== null) {
1371
- lines.push(formatParamsAsBlock(value, fullPath, argPrefix));
1381
+ lines.push(formatParamsForBlockExample(value, fullPath, argPrefix));
1372
1382
  } else {
1373
1383
  lines.push(`${argPrefix}${fullPath}`);
1374
1384
  lines.push(String(value));
@@ -1457,7 +1467,7 @@ function formatSchemaAsPlainText(schema, indent = "", atRoot = true) {
1457
1467
  }
1458
1468
  return lines.join("\n");
1459
1469
  }
1460
- var BaseGadget;
1470
+ var AbstractGadget;
1461
1471
  var init_gadget = __esm({
1462
1472
  "src/gadgets/gadget.ts"() {
1463
1473
  "use strict";
@@ -1465,7 +1475,7 @@ var init_gadget = __esm({
1465
1475
  init_exceptions();
1466
1476
  init_schema_to_json();
1467
1477
  init_schema_validator();
1468
- BaseGadget = class {
1478
+ AbstractGadget = class {
1469
1479
  /**
1470
1480
  * The name of the gadget. Used for identification when LLM calls it.
1471
1481
  * If not provided, defaults to the class name.
@@ -1493,14 +1503,14 @@ var init_gadget = __esm({
1493
1503
  */
1494
1504
  examples;
1495
1505
  /**
1496
- * Throws an AbortError if the execution has been aborted.
1506
+ * Throws an AbortException if the execution has been aborted.
1497
1507
  *
1498
1508
  * Call this at key checkpoints in long-running gadgets to allow early exit
1499
1509
  * when the gadget has been cancelled (e.g., due to timeout). This enables
1500
1510
  * resource cleanup and prevents unnecessary work after cancellation.
1501
1511
  *
1502
1512
  * @param ctx - The execution context containing the abort signal
1503
- * @throws AbortError if ctx.signal.aborted is true
1513
+ * @throws AbortException if ctx.signal.aborted is true
1504
1514
  *
1505
1515
  * @example
1506
1516
  * ```typescript
@@ -1525,7 +1535,7 @@ var init_gadget = __esm({
1525
1535
  */
1526
1536
  throwIfAborted(ctx) {
1527
1537
  if (ctx?.signal?.aborted) {
1528
- throw new AbortError();
1538
+ throw new AbortException();
1529
1539
  }
1530
1540
  }
1531
1541
  /**
@@ -1667,7 +1677,7 @@ var init_gadget = __esm({
1667
1677
  }
1668
1678
  parts.push(`${effectiveStartPrefix}${gadgetName}`);
1669
1679
  parts.push(
1670
- formatParamsAsBlock(example.params, "", effectiveArgPrefix)
1680
+ formatParamsForBlockExample(example.params, "", effectiveArgPrefix)
1671
1681
  );
1672
1682
  parts.push(effectiveEndPrefix);
1673
1683
  if (example.output !== void 0) {
@@ -1685,7 +1695,7 @@ var init_gadget = __esm({
1685
1695
 
1686
1696
  // src/gadgets/create-gadget.ts
1687
1697
  function createGadget(config) {
1688
- class DynamicGadget extends BaseGadget {
1698
+ class DynamicGadget extends AbstractGadget {
1689
1699
  name = config.name;
1690
1700
  description = config.description;
1691
1701
  parameterSchema = config.schema;
@@ -2323,8 +2333,8 @@ var init_conversation_manager = __esm({
2323
2333
  addAssistantMessage(content) {
2324
2334
  this.historyBuilder.addAssistant(content);
2325
2335
  }
2326
- addGadgetCall(gadgetName, parameters, result, media, mediaIds) {
2327
- this.historyBuilder.addGadgetCall(gadgetName, parameters, result, media, mediaIds);
2336
+ addGadgetCallResult(gadgetName, parameters, result, media, mediaIds) {
2337
+ this.historyBuilder.addGadgetCallResult(gadgetName, parameters, result, media, mediaIds);
2328
2338
  }
2329
2339
  getMessages() {
2330
2340
  return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];
@@ -2344,7 +2354,7 @@ var init_conversation_manager = __esm({
2344
2354
  if (msg.role === "user") {
2345
2355
  this.historyBuilder.addUser(msg.content);
2346
2356
  } else if (msg.role === "assistant") {
2347
- this.historyBuilder.addAssistant(extractText(msg.content));
2357
+ this.historyBuilder.addAssistant(extractMessageText(msg.content));
2348
2358
  }
2349
2359
  }
2350
2360
  }
@@ -3194,12 +3204,12 @@ var init_cost_reporting_client = __esm({
3194
3204
  });
3195
3205
 
3196
3206
  // src/gadgets/error-formatter.ts
3197
- var GadgetErrorFormatter;
3207
+ var GadgetExecutionErrorFormatter;
3198
3208
  var init_error_formatter = __esm({
3199
3209
  "src/gadgets/error-formatter.ts"() {
3200
3210
  "use strict";
3201
3211
  init_constants();
3202
- GadgetErrorFormatter = class {
3212
+ GadgetExecutionErrorFormatter = class {
3203
3213
  argPrefix;
3204
3214
  startPrefix;
3205
3215
  endPrefix;
@@ -3285,16 +3295,16 @@ function stripMarkdownFences(content) {
3285
3295
  cleaned = cleaned.replace(closingFence, "");
3286
3296
  return cleaned.trim();
3287
3297
  }
3288
- var globalInvocationCounter, StreamParser;
3298
+ var globalInvocationCounter, GadgetCallParser;
3289
3299
  var init_parser = __esm({
3290
3300
  "src/gadgets/parser.ts"() {
3291
3301
  "use strict";
3292
3302
  init_constants();
3293
3303
  init_block_params();
3294
3304
  globalInvocationCounter = 0;
3295
- StreamParser = class {
3305
+ GadgetCallParser = class {
3296
3306
  buffer = "";
3297
- lastReportedTextLength = 0;
3307
+ lastEmittedTextOffset = 0;
3298
3308
  startPrefix;
3299
3309
  endPrefix;
3300
3310
  argPrefix;
@@ -3303,16 +3313,20 @@ var init_parser = __esm({
3303
3313
  this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
3304
3314
  this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
3305
3315
  }
3306
- takeTextUntil(index) {
3307
- if (index <= this.lastReportedTextLength) {
3316
+ /**
3317
+ * Extract and consume text up to the given index.
3318
+ * Returns undefined if no meaningful text to emit.
3319
+ */
3320
+ extractTextSegment(index) {
3321
+ if (index <= this.lastEmittedTextOffset) {
3308
3322
  return void 0;
3309
3323
  }
3310
- const segment = this.buffer.slice(this.lastReportedTextLength, index);
3311
- this.lastReportedTextLength = index;
3324
+ const segment = this.buffer.slice(this.lastEmittedTextOffset, index);
3325
+ this.lastEmittedTextOffset = index;
3312
3326
  return segment.trim().length > 0 ? segment : void 0;
3313
3327
  }
3314
3328
  /**
3315
- * Parse gadget name with optional invocation ID and dependencies.
3329
+ * Parse gadget invocation metadata from the header line.
3316
3330
  *
3317
3331
  * Supported formats:
3318
3332
  * - `GadgetName` - Auto-generate ID, no dependencies
@@ -3321,24 +3335,24 @@ var init_parser = __esm({
3321
3335
  *
3322
3336
  * Dependencies must be comma-separated invocation IDs.
3323
3337
  */
3324
- parseGadgetName(gadgetName) {
3325
- const parts = gadgetName.split(":");
3338
+ parseInvocationMetadata(headerLine) {
3339
+ const parts = headerLine.split(":");
3326
3340
  if (parts.length === 1) {
3327
3341
  return {
3328
- actualName: parts[0],
3342
+ gadgetName: parts[0],
3329
3343
  invocationId: `gadget_${++globalInvocationCounter}`,
3330
3344
  dependencies: []
3331
3345
  };
3332
3346
  } else if (parts.length === 2) {
3333
3347
  return {
3334
- actualName: parts[0],
3348
+ gadgetName: parts[0],
3335
3349
  invocationId: parts[1].trim(),
3336
3350
  dependencies: []
3337
3351
  };
3338
3352
  } else {
3339
3353
  const deps = parts[2].split(",").map((d) => d.trim()).filter((d) => d.length > 0);
3340
3354
  return {
3341
- actualName: parts[0],
3355
+ gadgetName: parts[0],
3342
3356
  invocationId: parts[1].trim(),
3343
3357
  dependencies: deps
3344
3358
  };
@@ -3370,19 +3384,15 @@ var init_parser = __esm({
3370
3384
  while (true) {
3371
3385
  const partStartIndex = this.buffer.indexOf(this.startPrefix, startIndex);
3372
3386
  if (partStartIndex === -1) break;
3373
- const textBefore = this.takeTextUntil(partStartIndex);
3387
+ const textBefore = this.extractTextSegment(partStartIndex);
3374
3388
  if (textBefore !== void 0) {
3375
3389
  yield { type: "text", content: textBefore };
3376
3390
  }
3377
3391
  const metadataStartIndex = partStartIndex + this.startPrefix.length;
3378
3392
  const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
3379
3393
  if (metadataEndIndex === -1) break;
3380
- const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
3381
- const {
3382
- actualName: actualGadgetName,
3383
- invocationId,
3384
- dependencies
3385
- } = this.parseGadgetName(gadgetName);
3394
+ const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
3395
+ const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
3386
3396
  const contentStartIndex = metadataEndIndex + 1;
3387
3397
  let partEndIndex;
3388
3398
  let endMarkerLength = 0;
@@ -3402,7 +3412,7 @@ var init_parser = __esm({
3402
3412
  yield {
3403
3413
  type: "gadget_call",
3404
3414
  call: {
3405
- gadgetName: actualGadgetName,
3415
+ gadgetName,
3406
3416
  invocationId,
3407
3417
  parametersRaw,
3408
3418
  parameters,
@@ -3411,37 +3421,33 @@ var init_parser = __esm({
3411
3421
  }
3412
3422
  };
3413
3423
  startIndex = partEndIndex + endMarkerLength;
3414
- this.lastReportedTextLength = startIndex;
3424
+ this.lastEmittedTextOffset = startIndex;
3415
3425
  }
3416
3426
  if (startIndex > 0) {
3417
3427
  this.buffer = this.buffer.substring(startIndex);
3418
- this.lastReportedTextLength = 0;
3428
+ this.lastEmittedTextOffset = 0;
3419
3429
  }
3420
3430
  }
3421
3431
  // Finalize parsing and return remaining text or incomplete gadgets
3422
3432
  *finalize() {
3423
- const startIndex = this.buffer.indexOf(this.startPrefix, this.lastReportedTextLength);
3433
+ const startIndex = this.buffer.indexOf(this.startPrefix, this.lastEmittedTextOffset);
3424
3434
  if (startIndex !== -1) {
3425
- const textBefore = this.takeTextUntil(startIndex);
3435
+ const textBefore = this.extractTextSegment(startIndex);
3426
3436
  if (textBefore !== void 0) {
3427
3437
  yield { type: "text", content: textBefore };
3428
3438
  }
3429
3439
  const metadataStartIndex = startIndex + this.startPrefix.length;
3430
3440
  const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
3431
3441
  if (metadataEndIndex !== -1) {
3432
- const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
3433
- const {
3434
- actualName: actualGadgetName,
3435
- invocationId,
3436
- dependencies
3437
- } = this.parseGadgetName(gadgetName);
3442
+ const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
3443
+ const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);
3438
3444
  const contentStartIndex = metadataEndIndex + 1;
3439
3445
  const parametersRaw = this.buffer.substring(contentStartIndex).trim();
3440
3446
  const { parameters, parseError } = this.parseParameters(parametersRaw);
3441
3447
  yield {
3442
3448
  type: "gadget_call",
3443
3449
  call: {
3444
- gadgetName: actualGadgetName,
3450
+ gadgetName,
3445
3451
  invocationId,
3446
3452
  parametersRaw,
3447
3453
  parameters,
@@ -3452,7 +3458,7 @@ var init_parser = __esm({
3452
3458
  return;
3453
3459
  }
3454
3460
  }
3455
- const remainingText = this.takeTextUntil(this.buffer.length);
3461
+ const remainingText = this.extractTextSegment(this.buffer.length);
3456
3462
  if (remainingText !== void 0) {
3457
3463
  yield { type: "text", content: remainingText };
3458
3464
  }
@@ -3460,7 +3466,7 @@ var init_parser = __esm({
3460
3466
  // Reset parser state (note: global invocation counter is NOT reset to ensure unique IDs)
3461
3467
  reset() {
3462
3468
  this.buffer = "";
3463
- this.lastReportedTextLength = 0;
3469
+ this.lastEmittedTextOffset = 0;
3464
3470
  }
3465
3471
  };
3466
3472
  }
@@ -3479,14 +3485,16 @@ var init_executor = __esm({
3479
3485
  init_exceptions();
3480
3486
  init_parser();
3481
3487
  GadgetExecutor = class {
3482
- constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore) {
3488
+ constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig) {
3483
3489
  this.registry = registry;
3484
- this.onHumanInputRequired = onHumanInputRequired;
3490
+ this.requestHumanInput = requestHumanInput;
3485
3491
  this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
3486
3492
  this.client = client;
3487
3493
  this.mediaStore = mediaStore;
3494
+ this.agentConfig = agentConfig;
3495
+ this.subagentConfig = subagentConfig;
3488
3496
  this.logger = logger ?? createLogger({ name: "llmist:executor" });
3489
- this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
3497
+ this.errorFormatter = new GadgetExecutionErrorFormatter(errorFormatterOptions);
3490
3498
  this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
3491
3499
  }
3492
3500
  logger;
@@ -3506,11 +3514,11 @@ var init_executor = __esm({
3506
3514
  });
3507
3515
  }
3508
3516
  /**
3509
- * Normalizes gadget execute result to consistent format.
3517
+ * Unify gadget execute result to consistent internal format.
3510
3518
  * Handles string returns (backwards compat), object returns with cost,
3511
3519
  * and object returns with media.
3512
3520
  */
3513
- normalizeExecuteResult(raw) {
3521
+ unifyExecuteResult(raw) {
3514
3522
  if (typeof raw === "string") {
3515
3523
  return { result: raw, cost: 0 };
3516
3524
  }
@@ -3628,7 +3636,9 @@ var init_executor = __esm({
3628
3636
  const ctx = {
3629
3637
  reportCost,
3630
3638
  llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
3631
- signal: abortController.signal
3639
+ signal: abortController.signal,
3640
+ agentConfig: this.agentConfig,
3641
+ subagentConfig: this.subagentConfig
3632
3642
  };
3633
3643
  let rawResult;
3634
3644
  if (timeoutMs && timeoutMs > 0) {
@@ -3643,7 +3653,7 @@ var init_executor = __esm({
3643
3653
  } else {
3644
3654
  rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));
3645
3655
  }
3646
- const { result, media, cost: returnCost } = this.normalizeExecuteResult(rawResult);
3656
+ const { result, media, cost: returnCost } = this.unifyExecuteResult(rawResult);
3647
3657
  const totalCost = callbackCost + returnCost;
3648
3658
  let mediaIds;
3649
3659
  let storedMedia;
@@ -3689,7 +3699,7 @@ var init_executor = __esm({
3689
3699
  storedMedia
3690
3700
  };
3691
3701
  } catch (error) {
3692
- if (error instanceof BreakLoopException) {
3702
+ if (error instanceof TaskCompletionSignal) {
3693
3703
  this.logger.info("Gadget requested loop termination", {
3694
3704
  gadgetName: call.gadgetName,
3695
3705
  message: error.message
@@ -3717,7 +3727,7 @@ var init_executor = __esm({
3717
3727
  executionTimeMs: Date.now() - startTime
3718
3728
  };
3719
3729
  }
3720
- if (error instanceof AbortError) {
3730
+ if (error instanceof AbortException) {
3721
3731
  this.logger.info("Gadget execution was aborted", {
3722
3732
  gadgetName: call.gadgetName,
3723
3733
  executionTimeMs: Date.now() - startTime
@@ -3730,14 +3740,14 @@ var init_executor = __esm({
3730
3740
  executionTimeMs: Date.now() - startTime
3731
3741
  };
3732
3742
  }
3733
- if (error instanceof HumanInputException) {
3743
+ if (error instanceof HumanInputRequiredException) {
3734
3744
  this.logger.info("Gadget requested human input", {
3735
3745
  gadgetName: call.gadgetName,
3736
3746
  question: error.question
3737
3747
  });
3738
- if (this.onHumanInputRequired) {
3748
+ if (this.requestHumanInput) {
3739
3749
  try {
3740
- const answer = await this.onHumanInputRequired(error.question);
3750
+ const answer = await this.requestHumanInput(error.question);
3741
3751
  this.logger.debug("Human input received", {
3742
3752
  gadgetName: call.gadgetName,
3743
3753
  answerLength: answer.length
@@ -3835,13 +3845,13 @@ var init_stream_processor = __esm({
3835
3845
  parser;
3836
3846
  executor;
3837
3847
  stopOnGadgetError;
3838
- shouldContinueAfterError;
3839
- accumulatedText = "";
3840
- shouldStopExecution = false;
3848
+ canRecoverFromGadgetError;
3849
+ responseText = "";
3850
+ executionHalted = false;
3841
3851
  observerFailureCount = 0;
3842
3852
  // Dependency tracking for gadget execution DAG
3843
3853
  /** Gadgets waiting for their dependencies to complete */
3844
- pendingGadgets = /* @__PURE__ */ new Map();
3854
+ gadgetsAwaitingDependencies = /* @__PURE__ */ new Map();
3845
3855
  /** Completed gadget results, keyed by invocation ID */
3846
3856
  completedResults = /* @__PURE__ */ new Map();
3847
3857
  /** Invocation IDs of gadgets that have failed (error or skipped due to dependency) */
@@ -3852,20 +3862,22 @@ var init_stream_processor = __esm({
3852
3862
  this.hooks = options.hooks ?? {};
3853
3863
  this.logger = options.logger ?? createLogger({ name: "llmist:stream-processor" });
3854
3864
  this.stopOnGadgetError = options.stopOnGadgetError ?? true;
3855
- this.shouldContinueAfterError = options.shouldContinueAfterError;
3856
- this.parser = new StreamParser({
3865
+ this.canRecoverFromGadgetError = options.canRecoverFromGadgetError;
3866
+ this.parser = new GadgetCallParser({
3857
3867
  startPrefix: options.gadgetStartPrefix,
3858
3868
  endPrefix: options.gadgetEndPrefix,
3859
3869
  argPrefix: options.gadgetArgPrefix
3860
3870
  });
3861
3871
  this.executor = new GadgetExecutor(
3862
3872
  options.registry,
3863
- options.onHumanInputRequired,
3873
+ options.requestHumanInput,
3864
3874
  this.logger.getSubLogger({ name: "executor" }),
3865
3875
  options.defaultGadgetTimeoutMs,
3866
3876
  { argPrefix: options.gadgetArgPrefix },
3867
3877
  options.client,
3868
- options.mediaStore
3878
+ options.mediaStore,
3879
+ options.agentConfig,
3880
+ options.subagentConfig
3869
3881
  );
3870
3882
  }
3871
3883
  /**
@@ -3886,7 +3898,7 @@ var init_stream_processor = __esm({
3886
3898
  if (this.hooks.interceptors?.interceptRawChunk) {
3887
3899
  const context = {
3888
3900
  iteration: this.iteration,
3889
- accumulatedText: this.accumulatedText,
3901
+ accumulatedText: this.responseText,
3890
3902
  logger: this.logger
3891
3903
  };
3892
3904
  const intercepted = this.hooks.interceptors.interceptRawChunk(processedChunk, context);
@@ -3897,7 +3909,7 @@ var init_stream_processor = __esm({
3897
3909
  }
3898
3910
  }
3899
3911
  if (processedChunk) {
3900
- this.accumulatedText += processedChunk;
3912
+ this.responseText += processedChunk;
3901
3913
  }
3902
3914
  }
3903
3915
  if (this.hooks.observers?.onStreamChunk && (processedChunk || chunk.usage)) {
@@ -3906,7 +3918,7 @@ var init_stream_processor = __esm({
3906
3918
  const context = {
3907
3919
  iteration: this.iteration,
3908
3920
  rawChunk: processedChunk,
3909
- accumulatedText: this.accumulatedText,
3921
+ accumulatedText: this.responseText,
3910
3922
  usage,
3911
3923
  logger: this.logger
3912
3924
  };
@@ -3929,12 +3941,12 @@ var init_stream_processor = __esm({
3929
3941
  }
3930
3942
  }
3931
3943
  }
3932
- if (this.shouldStopExecution) {
3944
+ if (this.executionHalted) {
3933
3945
  this.logger.info("Breaking from LLM stream due to gadget error");
3934
3946
  break;
3935
3947
  }
3936
3948
  }
3937
- if (!this.shouldStopExecution) {
3949
+ if (!this.executionHalted) {
3938
3950
  for (const event of this.parser.finalize()) {
3939
3951
  const processedEvents = await this.processEvent(event);
3940
3952
  outputs.push(...processedEvents);
@@ -3958,11 +3970,11 @@ var init_stream_processor = __esm({
3958
3970
  }
3959
3971
  }
3960
3972
  }
3961
- let finalMessage = this.accumulatedText;
3973
+ let finalMessage = this.responseText;
3962
3974
  if (this.hooks.interceptors?.interceptAssistantMessage) {
3963
3975
  const context = {
3964
3976
  iteration: this.iteration,
3965
- rawResponse: this.accumulatedText,
3977
+ rawResponse: this.responseText,
3966
3978
  logger: this.logger
3967
3979
  };
3968
3980
  finalMessage = this.hooks.interceptors.interceptAssistantMessage(finalMessage, context);
@@ -3973,7 +3985,7 @@ var init_stream_processor = __esm({
3973
3985
  didExecuteGadgets,
3974
3986
  finishReason,
3975
3987
  usage,
3976
- rawResponse: this.accumulatedText,
3988
+ rawResponse: this.responseText,
3977
3989
  finalMessage
3978
3990
  };
3979
3991
  }
@@ -3996,7 +4008,7 @@ var init_stream_processor = __esm({
3996
4008
  if (this.hooks.interceptors?.interceptTextChunk) {
3997
4009
  const context = {
3998
4010
  iteration: this.iteration,
3999
- accumulatedText: this.accumulatedText,
4011
+ accumulatedText: this.responseText,
4000
4012
  logger: this.logger
4001
4013
  };
4002
4014
  const intercepted = this.hooks.interceptors.interceptTextChunk(content, context);
@@ -4015,7 +4027,7 @@ var init_stream_processor = __esm({
4015
4027
  * After each execution, pending gadgets are checked to see if they can now run.
4016
4028
  */
4017
4029
  async processGadgetCall(call) {
4018
- if (this.shouldStopExecution) {
4030
+ if (this.executionHalted) {
4019
4031
  this.logger.debug("Skipping gadget execution due to previous error", {
4020
4032
  gadgetName: call.gadgetName
4021
4033
  });
@@ -4054,7 +4066,7 @@ var init_stream_processor = __esm({
4054
4066
  invocationId: call.invocationId,
4055
4067
  waitingOn: unsatisfied
4056
4068
  });
4057
- this.pendingGadgets.set(call.invocationId, call);
4069
+ this.gadgetsAwaitingDependencies.set(call.invocationId, call);
4058
4070
  return events;
4059
4071
  }
4060
4072
  }
@@ -4076,14 +4088,14 @@ var init_stream_processor = __esm({
4076
4088
  error: call.parseError,
4077
4089
  rawParameters: call.parametersRaw
4078
4090
  });
4079
- const shouldContinue = await this.checkContinueAfterError(
4091
+ const shouldContinue = await this.checkCanRecoverFromError(
4080
4092
  call.parseError,
4081
4093
  call.gadgetName,
4082
4094
  "parse",
4083
4095
  call.parameters
4084
4096
  );
4085
4097
  if (!shouldContinue) {
4086
- this.shouldStopExecution = true;
4098
+ this.executionHalted = true;
4087
4099
  }
4088
4100
  }
4089
4101
  let parameters = call.parameters ?? {};
@@ -4207,14 +4219,14 @@ var init_stream_processor = __esm({
4207
4219
  events.push({ type: "gadget_result", result });
4208
4220
  if (result.error) {
4209
4221
  const errorType = this.determineErrorType(call, result);
4210
- const shouldContinue = await this.checkContinueAfterError(
4222
+ const shouldContinue = await this.checkCanRecoverFromError(
4211
4223
  result.error,
4212
4224
  result.gadgetName,
4213
4225
  errorType,
4214
4226
  result.parameters
4215
4227
  );
4216
4228
  if (!shouldContinue) {
4217
- this.shouldStopExecution = true;
4229
+ this.executionHalted = true;
4218
4230
  }
4219
4231
  }
4220
4232
  return events;
@@ -4301,11 +4313,11 @@ var init_stream_processor = __esm({
4301
4313
  async processPendingGadgets() {
4302
4314
  const events = [];
4303
4315
  let progress = true;
4304
- while (progress && this.pendingGadgets.size > 0) {
4316
+ while (progress && this.gadgetsAwaitingDependencies.size > 0) {
4305
4317
  progress = false;
4306
4318
  const readyToExecute = [];
4307
4319
  const readyToSkip = [];
4308
- for (const [invocationId, call] of this.pendingGadgets) {
4320
+ for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
4309
4321
  const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
4310
4322
  if (failedDep) {
4311
4323
  readyToSkip.push({ call, failedDep });
@@ -4317,7 +4329,7 @@ var init_stream_processor = __esm({
4317
4329
  }
4318
4330
  }
4319
4331
  for (const { call, failedDep } of readyToSkip) {
4320
- this.pendingGadgets.delete(call.invocationId);
4332
+ this.gadgetsAwaitingDependencies.delete(call.invocationId);
4321
4333
  const skipEvents = await this.handleFailedDependency(call, failedDep);
4322
4334
  events.push(...skipEvents);
4323
4335
  progress = true;
@@ -4328,7 +4340,7 @@ var init_stream_processor = __esm({
4328
4340
  invocationIds: readyToExecute.map((c) => c.invocationId)
4329
4341
  });
4330
4342
  for (const call of readyToExecute) {
4331
- this.pendingGadgets.delete(call.invocationId);
4343
+ this.gadgetsAwaitingDependencies.delete(call.invocationId);
4332
4344
  }
4333
4345
  const executePromises = readyToExecute.map((call) => this.executeGadgetWithHooks(call));
4334
4346
  const results = await Promise.all(executePromises);
@@ -4338,9 +4350,9 @@ var init_stream_processor = __esm({
4338
4350
  progress = true;
4339
4351
  }
4340
4352
  }
4341
- if (this.pendingGadgets.size > 0) {
4342
- const pendingIds = new Set(this.pendingGadgets.keys());
4343
- for (const [invocationId, call] of this.pendingGadgets) {
4353
+ if (this.gadgetsAwaitingDependencies.size > 0) {
4354
+ const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());
4355
+ for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
4344
4356
  const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));
4345
4357
  const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));
4346
4358
  const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));
@@ -4371,7 +4383,7 @@ var init_stream_processor = __esm({
4371
4383
  };
4372
4384
  events.push(skipEvent);
4373
4385
  }
4374
- this.pendingGadgets.clear();
4386
+ this.gadgetsAwaitingDependencies.clear();
4375
4387
  }
4376
4388
  return events;
4377
4389
  }
@@ -4401,19 +4413,19 @@ var init_stream_processor = __esm({
4401
4413
  );
4402
4414
  }
4403
4415
  /**
4404
- * Check if execution should continue after an error.
4416
+ * Check if execution can recover from an error.
4405
4417
  *
4406
4418
  * Returns true if we should continue processing subsequent gadgets, false if we should stop.
4407
4419
  *
4408
4420
  * Logic:
4409
- * - If custom shouldContinueAfterError is provided, use it
4421
+ * - If custom canRecoverFromGadgetError is provided, use it
4410
4422
  * - Otherwise, use stopOnGadgetError config:
4411
4423
  * - stopOnGadgetError=true → return false (stop execution)
4412
4424
  * - stopOnGadgetError=false → return true (continue execution)
4413
4425
  */
4414
- async checkContinueAfterError(error, gadgetName, errorType, parameters) {
4415
- if (this.shouldContinueAfterError) {
4416
- return await this.shouldContinueAfterError({
4426
+ async checkCanRecoverFromError(error, gadgetName, errorType, parameters) {
4427
+ if (this.canRecoverFromGadgetError) {
4428
+ return await this.canRecoverFromGadgetError({
4417
4429
  error,
4418
4430
  gadgetName,
4419
4431
  errorType,
@@ -4476,14 +4488,14 @@ var init_agent = __esm({
4476
4488
  gadgetStartPrefix;
4477
4489
  gadgetEndPrefix;
4478
4490
  gadgetArgPrefix;
4479
- onHumanInputRequired;
4491
+ requestHumanInput;
4480
4492
  textOnlyHandler;
4481
4493
  textWithGadgetsHandler;
4482
4494
  stopOnGadgetError;
4483
- shouldContinueAfterError;
4495
+ canRecoverFromGadgetError;
4484
4496
  defaultGadgetTimeoutMs;
4485
4497
  defaultMaxTokens;
4486
- userPromptProvided;
4498
+ hasUserPrompt;
4487
4499
  // Gadget output limiting
4488
4500
  outputStore;
4489
4501
  outputLimitEnabled;
@@ -4494,6 +4506,9 @@ var init_agent = __esm({
4494
4506
  mediaStore;
4495
4507
  // Cancellation
4496
4508
  signal;
4509
+ // Subagent configuration
4510
+ agentContextConfig;
4511
+ subagentConfig;
4497
4512
  /**
4498
4513
  * Creates a new Agent instance.
4499
4514
  * @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
@@ -4513,11 +4528,11 @@ var init_agent = __esm({
4513
4528
  this.gadgetStartPrefix = options.gadgetStartPrefix;
4514
4529
  this.gadgetEndPrefix = options.gadgetEndPrefix;
4515
4530
  this.gadgetArgPrefix = options.gadgetArgPrefix;
4516
- this.onHumanInputRequired = options.onHumanInputRequired;
4531
+ this.requestHumanInput = options.requestHumanInput;
4517
4532
  this.textOnlyHandler = options.textOnlyHandler ?? "terminate";
4518
4533
  this.textWithGadgetsHandler = options.textWithGadgetsHandler;
4519
4534
  this.stopOnGadgetError = options.stopOnGadgetError ?? true;
4520
- this.shouldContinueAfterError = options.shouldContinueAfterError;
4535
+ this.canRecoverFromGadgetError = options.canRecoverFromGadgetError;
4521
4536
  this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
4522
4537
  this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);
4523
4538
  this.outputLimitEnabled = options.gadgetOutputLimit ?? DEFAULT_GADGET_OUTPUT_LIMIT;
@@ -4533,7 +4548,7 @@ var init_agent = __esm({
4533
4548
  createGadgetOutputViewer(this.outputStore, this.outputLimitCharLimit)
4534
4549
  );
4535
4550
  }
4536
- this.hooks = this.mergeOutputLimiterHook(options.hooks);
4551
+ this.hooks = this.chainOutputLimiterWithUserHooks(options.hooks);
4537
4552
  const baseBuilder = new LLMMessageBuilder(options.promptConfig);
4538
4553
  if (options.systemPrompt) {
4539
4554
  baseBuilder.addSystem(options.systemPrompt);
@@ -4553,7 +4568,7 @@ var init_agent = __esm({
4553
4568
  endPrefix: options.gadgetEndPrefix,
4554
4569
  argPrefix: options.gadgetArgPrefix
4555
4570
  });
4556
- this.userPromptProvided = !!options.userPrompt;
4571
+ this.hasUserPrompt = !!options.userPrompt;
4557
4572
  if (options.userPrompt) {
4558
4573
  this.conversation.addUserMessage(options.userPrompt);
4559
4574
  }
@@ -4566,6 +4581,11 @@ var init_agent = __esm({
4566
4581
  );
4567
4582
  }
4568
4583
  this.signal = options.signal;
4584
+ this.agentContextConfig = {
4585
+ model: this.model,
4586
+ temperature: this.temperature
4587
+ };
4588
+ this.subagentConfig = options.subagentConfig;
4569
4589
  }
4570
4590
  /**
4571
4591
  * Get the gadget registry for this agent.
@@ -4672,7 +4692,7 @@ var init_agent = __esm({
4672
4692
  * @throws {Error} If no user prompt was provided (when using build() without ask())
4673
4693
  */
4674
4694
  async *run() {
4675
- if (!this.userPromptProvided) {
4695
+ if (!this.hasUserPrompt) {
4676
4696
  throw new Error(
4677
4697
  "No user prompt provided. Use .ask(prompt) instead of .build(), or call agent.run() after providing a prompt."
4678
4698
  );
@@ -4789,12 +4809,14 @@ var init_agent = __esm({
4789
4809
  gadgetArgPrefix: this.gadgetArgPrefix,
4790
4810
  hooks: this.hooks,
4791
4811
  logger: this.logger.getSubLogger({ name: "stream-processor" }),
4792
- onHumanInputRequired: this.onHumanInputRequired,
4812
+ requestHumanInput: this.requestHumanInput,
4793
4813
  stopOnGadgetError: this.stopOnGadgetError,
4794
- shouldContinueAfterError: this.shouldContinueAfterError,
4814
+ canRecoverFromGadgetError: this.canRecoverFromGadgetError,
4795
4815
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
4796
4816
  client: this.client,
4797
- mediaStore: this.mediaStore
4817
+ mediaStore: this.mediaStore,
4818
+ agentConfig: this.agentContextConfig,
4819
+ subagentConfig: this.subagentConfig
4798
4820
  });
4799
4821
  const result = await processor.process(stream2);
4800
4822
  for (const output of result.outputs) {
@@ -4847,9 +4869,9 @@ var init_agent = __esm({
4847
4869
  if (msg.role === "user") {
4848
4870
  this.conversation.addUserMessage(msg.content);
4849
4871
  } else if (msg.role === "assistant") {
4850
- this.conversation.addAssistantMessage(extractText(msg.content));
4872
+ this.conversation.addAssistantMessage(extractMessageText(msg.content));
4851
4873
  } else if (msg.role === "system") {
4852
- this.conversation.addUserMessage(`[System] ${extractText(msg.content)}`);
4874
+ this.conversation.addUserMessage(`[System] ${extractMessageText(msg.content)}`);
4853
4875
  }
4854
4876
  }
4855
4877
  }
@@ -4861,7 +4883,7 @@ var init_agent = __esm({
4861
4883
  ).map((output) => output.content).join("");
4862
4884
  if (textContent.trim()) {
4863
4885
  const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
4864
- this.conversation.addGadgetCall(
4886
+ this.conversation.addGadgetCallResult(
4865
4887
  gadgetName,
4866
4888
  parameterMapping(textContent),
4867
4889
  resultMapping ? resultMapping(textContent) : textContent
@@ -4871,7 +4893,7 @@ var init_agent = __esm({
4871
4893
  for (const output of result.outputs) {
4872
4894
  if (output.type === "gadget_result") {
4873
4895
  const gadgetResult = output.result;
4874
- this.conversation.addGadgetCall(
4896
+ this.conversation.addGadgetCallResult(
4875
4897
  gadgetResult.gadgetName,
4876
4898
  gadgetResult.parameters,
4877
4899
  gadgetResult.error ?? gadgetResult.result ?? "",
@@ -4882,7 +4904,7 @@ var init_agent = __esm({
4882
4904
  }
4883
4905
  } else {
4884
4906
  if (finalMessage.trim()) {
4885
- this.conversation.addGadgetCall(
4907
+ this.conversation.addGadgetCallResult(
4886
4908
  "TellUser",
4887
4909
  { message: finalMessage, done: false, type: "info" },
4888
4910
  `\u2139\uFE0F ${finalMessage}`
@@ -5008,10 +5030,10 @@ var init_agent = __esm({
5008
5030
  return this.client.modelRegistry.getModelLimits(unprefixedModelId)?.maxOutputTokens;
5009
5031
  }
5010
5032
  /**
5011
- * Merge the output limiter interceptor into user-provided hooks.
5033
+ * Chain the output limiter interceptor with user-provided hooks.
5012
5034
  * The limiter runs first, then chains to any user interceptor.
5013
5035
  */
5014
- mergeOutputLimiterHook(userHooks) {
5036
+ chainOutputLimiterWithUserHooks(userHooks) {
5015
5037
  if (!this.outputLimitEnabled) {
5016
5038
  return userHooks ?? {};
5017
5039
  }
@@ -5090,20 +5112,21 @@ var init_builder = __esm({
5090
5112
  promptConfig;
5091
5113
  gadgets = [];
5092
5114
  initialMessages = [];
5093
- onHumanInputRequired;
5115
+ requestHumanInput;
5094
5116
  gadgetStartPrefix;
5095
5117
  gadgetEndPrefix;
5096
5118
  gadgetArgPrefix;
5097
5119
  textOnlyHandler;
5098
5120
  textWithGadgetsHandler;
5099
5121
  stopOnGadgetError;
5100
- shouldContinueAfterError;
5122
+ canRecoverFromGadgetError;
5101
5123
  defaultGadgetTimeoutMs;
5102
5124
  gadgetOutputLimit;
5103
5125
  gadgetOutputLimitPercent;
5104
5126
  compactionConfig;
5105
5127
  signal;
5106
5128
  trailingMessage;
5129
+ subagentConfig;
5107
5130
  constructor(client) {
5108
5131
  this.client = client;
5109
5132
  }
@@ -5194,13 +5217,13 @@ var init_builder = __esm({
5194
5217
  *
5195
5218
  * @example
5196
5219
  * ```typescript
5197
- * .withPromptConfig({
5220
+ * .withPromptTemplateConfig({
5198
5221
  * mainInstruction: "Use the gadget markers below:",
5199
5222
  * rules: ["Always use markers", "Never use function calling"]
5200
5223
  * })
5201
5224
  * ```
5202
5225
  */
5203
- withPromptConfig(config) {
5226
+ withPromptTemplateConfig(config) {
5204
5227
  this.promptConfig = config;
5205
5228
  return this;
5206
5229
  }
@@ -5280,7 +5303,7 @@ var init_builder = __esm({
5280
5303
  * ```
5281
5304
  */
5282
5305
  onHumanInput(handler) {
5283
- this.onHumanInputRequired = handler;
5306
+ this.requestHumanInput = handler;
5284
5307
  return this;
5285
5308
  }
5286
5309
  /**
@@ -5415,9 +5438,9 @@ var init_builder = __esm({
5415
5438
  * Provides fine-grained control over whether to continue after different types of errors.
5416
5439
  * Overrides `stopOnGadgetError` when provided.
5417
5440
  *
5418
- * **Note:** This builder method configures the underlying `shouldContinueAfterError` option
5441
+ * **Note:** This builder method configures the underlying `canRecoverFromGadgetError` option
5419
5442
  * in `AgentOptions`. The method is named `withErrorHandler` for better developer experience,
5420
- * but maps to the `shouldContinueAfterError` property internally.
5443
+ * but maps to the `canRecoverFromGadgetError` property internally.
5421
5444
  *
5422
5445
  * @param handler - Function that decides whether to continue after an error.
5423
5446
  * Return `true` to continue execution, `false` to stop.
@@ -5438,7 +5461,7 @@ var init_builder = __esm({
5438
5461
  * ```
5439
5462
  */
5440
5463
  withErrorHandler(handler) {
5441
- this.shouldContinueAfterError = handler;
5464
+ this.canRecoverFromGadgetError = handler;
5442
5465
  return this;
5443
5466
  }
5444
5467
  /**
@@ -5579,6 +5602,27 @@ var init_builder = __esm({
5579
5602
  this.signal = signal;
5580
5603
  return this;
5581
5604
  }
5605
+ /**
5606
+ * Set subagent configuration overrides.
5607
+ *
5608
+ * Subagent gadgets (like BrowseWeb) can read these settings from ExecutionContext
5609
+ * to inherit model and other options from the CLI configuration.
5610
+ *
5611
+ * @param config - Subagent configuration map keyed by gadget name
5612
+ * @returns This builder for chaining
5613
+ *
5614
+ * @example
5615
+ * ```typescript
5616
+ * .withSubagentConfig({
5617
+ * BrowseWeb: { model: "inherit", maxIterations: 20, headless: true },
5618
+ * CodeAnalyzer: { model: "sonnet", maxIterations: 10 }
5619
+ * })
5620
+ * ```
5621
+ */
5622
+ withSubagentConfig(config) {
5623
+ this.subagentConfig = config;
5624
+ return this;
5625
+ }
5582
5626
  /**
5583
5627
  * Add an ephemeral trailing message that appears at the end of each LLM request.
5584
5628
  *
@@ -5743,19 +5787,20 @@ ${endPrefix}`
5743
5787
  hooks: this.composeHooks(),
5744
5788
  promptConfig: this.promptConfig,
5745
5789
  initialMessages: this.initialMessages,
5746
- onHumanInputRequired: this.onHumanInputRequired,
5790
+ requestHumanInput: this.requestHumanInput,
5747
5791
  gadgetStartPrefix: this.gadgetStartPrefix,
5748
5792
  gadgetEndPrefix: this.gadgetEndPrefix,
5749
5793
  gadgetArgPrefix: this.gadgetArgPrefix,
5750
5794
  textOnlyHandler: this.textOnlyHandler,
5751
5795
  textWithGadgetsHandler: this.textWithGadgetsHandler,
5752
5796
  stopOnGadgetError: this.stopOnGadgetError,
5753
- shouldContinueAfterError: this.shouldContinueAfterError,
5797
+ canRecoverFromGadgetError: this.canRecoverFromGadgetError,
5754
5798
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
5755
5799
  gadgetOutputLimit: this.gadgetOutputLimit,
5756
5800
  gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
5757
5801
  compactionConfig: this.compactionConfig,
5758
- signal: this.signal
5802
+ signal: this.signal,
5803
+ subagentConfig: this.subagentConfig
5759
5804
  };
5760
5805
  }
5761
5806
  ask(userPrompt) {
@@ -5924,19 +5969,20 @@ ${endPrefix}`
5924
5969
  hooks: this.composeHooks(),
5925
5970
  promptConfig: this.promptConfig,
5926
5971
  initialMessages: this.initialMessages,
5927
- onHumanInputRequired: this.onHumanInputRequired,
5972
+ requestHumanInput: this.requestHumanInput,
5928
5973
  gadgetStartPrefix: this.gadgetStartPrefix,
5929
5974
  gadgetEndPrefix: this.gadgetEndPrefix,
5930
5975
  gadgetArgPrefix: this.gadgetArgPrefix,
5931
5976
  textOnlyHandler: this.textOnlyHandler,
5932
5977
  textWithGadgetsHandler: this.textWithGadgetsHandler,
5933
5978
  stopOnGadgetError: this.stopOnGadgetError,
5934
- shouldContinueAfterError: this.shouldContinueAfterError,
5979
+ canRecoverFromGadgetError: this.canRecoverFromGadgetError,
5935
5980
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
5936
5981
  gadgetOutputLimit: this.gadgetOutputLimit,
5937
5982
  gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
5938
5983
  compactionConfig: this.compactionConfig,
5939
- signal: this.signal
5984
+ signal: this.signal,
5985
+ subagentConfig: this.subagentConfig
5940
5986
  };
5941
5987
  return new Agent(AGENT_INTERNAL_KEY, options);
5942
5988
  }
@@ -6242,9 +6288,9 @@ var init_base_provider = __esm({
6242
6288
  */
6243
6289
  async *stream(options, descriptor, spec) {
6244
6290
  const preparedMessages = this.prepareMessages(options.messages);
6245
- const payload = this.buildRequestPayload(options, descriptor, spec, preparedMessages);
6291
+ const payload = this.buildApiRequest(options, descriptor, spec, preparedMessages);
6246
6292
  const rawStream = await this.executeStreamRequest(payload, options.signal);
6247
- yield* this.wrapStream(rawStream);
6293
+ yield* this.normalizeProviderStream(rawStream);
6248
6294
  }
6249
6295
  /**
6250
6296
  * Prepare messages for the request.
@@ -6344,11 +6390,11 @@ var init_anthropic = __esm({
6344
6390
  "Anthropic does not support speech generation. Use OpenAI (TTS) or Google Gemini (TTS) instead."
6345
6391
  );
6346
6392
  }
6347
- buildRequestPayload(options, descriptor, spec, messages) {
6393
+ buildApiRequest(options, descriptor, spec, messages) {
6348
6394
  const systemMessages = messages.filter((message) => message.role === "system");
6349
6395
  const system = systemMessages.length > 0 ? systemMessages.map((m, index) => ({
6350
6396
  type: "text",
6351
- text: extractText(m.content),
6397
+ text: extractMessageText(m.content),
6352
6398
  // Add cache_control to the LAST system message block
6353
6399
  ...index === systemMessages.length - 1 ? { cache_control: { type: "ephemeral" } } : {}
6354
6400
  })) : void 0;
@@ -6385,7 +6431,7 @@ var init_anthropic = __esm({
6385
6431
  * Handles text, images (base64 only), and applies cache_control.
6386
6432
  */
6387
6433
  convertToAnthropicContent(content, addCacheControl) {
6388
- const parts = normalizeContent(content);
6434
+ const parts = normalizeMessageContent(content);
6389
6435
  return parts.map((part, index) => {
6390
6436
  const isLastPart = index === parts.length - 1;
6391
6437
  const cacheControl = addCacheControl && isLastPart ? { cache_control: { type: "ephemeral" } } : {};
@@ -6431,7 +6477,7 @@ var init_anthropic = __esm({
6431
6477
  const stream2 = await client.messages.create(payload, signal ? { signal } : void 0);
6432
6478
  return stream2;
6433
6479
  }
6434
- async *wrapStream(iterable) {
6480
+ async *normalizeProviderStream(iterable) {
6435
6481
  const stream2 = iterable;
6436
6482
  let inputTokens = 0;
6437
6483
  let cachedInputTokens = 0;
@@ -6508,7 +6554,7 @@ var init_anthropic = __esm({
6508
6554
  async countTokens(messages, descriptor, _spec) {
6509
6555
  const client = this.client;
6510
6556
  const systemMessages = messages.filter((message) => message.role === "system");
6511
- const system = systemMessages.length > 0 ? systemMessages.map((m) => extractText(m.content)).join("\n\n") : void 0;
6557
+ const system = systemMessages.length > 0 ? systemMessages.map((m) => extractMessageText(m.content)).join("\n\n") : void 0;
6512
6558
  const conversation = messages.filter(
6513
6559
  (message) => message.role !== "system"
6514
6560
  ).map((message) => ({
@@ -6530,7 +6576,7 @@ var init_anthropic = __esm({
6530
6576
  let totalChars = 0;
6531
6577
  let imageCount = 0;
6532
6578
  for (const msg of messages) {
6533
- const parts = normalizeContent(msg.content);
6579
+ const parts = normalizeMessageContent(msg.content);
6534
6580
  for (const part of parts) {
6535
6581
  if (part.type === "text") {
6536
6582
  totalChars += part.text.length;
@@ -7221,7 +7267,7 @@ var init_gemini = __esm({
7221
7267
  format: spec?.defaultFormat ?? "wav"
7222
7268
  };
7223
7269
  }
7224
- buildRequestPayload(options, descriptor, _spec, messages) {
7270
+ buildApiRequest(options, descriptor, _spec, messages) {
7225
7271
  const contents = this.convertMessagesToContents(messages);
7226
7272
  const generationConfig = this.buildGenerationConfig(options);
7227
7273
  const config = {
@@ -7273,7 +7319,7 @@ var init_gemini = __esm({
7273
7319
  if (message.role === "system") {
7274
7320
  expandedMessages.push({
7275
7321
  role: "user",
7276
- content: extractText(message.content)
7322
+ content: extractMessageText(message.content)
7277
7323
  });
7278
7324
  expandedMessages.push({
7279
7325
  role: "assistant",
@@ -7323,7 +7369,7 @@ var init_gemini = __esm({
7323
7369
  * Handles text, images, and audio (Gemini supports all three).
7324
7370
  */
7325
7371
  convertToGeminiParts(content) {
7326
- const parts = normalizeContent(content);
7372
+ const parts = normalizeMessageContent(content);
7327
7373
  return parts.map((part) => {
7328
7374
  if (part.type === "text") {
7329
7375
  return { text: part.text };
@@ -7368,10 +7414,10 @@ var init_gemini = __esm({
7368
7414
  }
7369
7415
  return Object.keys(config).length > 0 ? config : null;
7370
7416
  }
7371
- async *wrapStream(iterable) {
7417
+ async *normalizeProviderStream(iterable) {
7372
7418
  const stream2 = iterable;
7373
7419
  for await (const chunk of stream2) {
7374
- const text3 = this.extractText(chunk);
7420
+ const text3 = this.extractMessageText(chunk);
7375
7421
  if (text3) {
7376
7422
  yield { text: text3, rawEvent: chunk };
7377
7423
  }
@@ -7382,7 +7428,7 @@ var init_gemini = __esm({
7382
7428
  }
7383
7429
  }
7384
7430
  }
7385
- extractText(chunk) {
7431
+ extractMessageText(chunk) {
7386
7432
  if (!chunk?.candidates) {
7387
7433
  return "";
7388
7434
  }
@@ -7447,7 +7493,7 @@ var init_gemini = __esm({
7447
7493
  let totalChars = 0;
7448
7494
  let mediaCount = 0;
7449
7495
  for (const msg of messages) {
7450
- const parts = normalizeContent(msg.content);
7496
+ const parts = normalizeMessageContent(msg.content);
7451
7497
  for (const part of parts) {
7452
7498
  if (part.type === "text") {
7453
7499
  totalChars += part.text.length;
@@ -8193,7 +8239,7 @@ var init_openai = __esm({
8193
8239
  format
8194
8240
  };
8195
8241
  }
8196
- buildRequestPayload(options, descriptor, spec, messages) {
8242
+ buildApiRequest(options, descriptor, spec, messages) {
8197
8243
  const { maxTokens, temperature, topP, stopSequences, extra } = options;
8198
8244
  const supportsTemperature = spec?.metadata?.supportsTemperature !== false;
8199
8245
  const shouldIncludeTemperature = typeof temperature === "number" && supportsTemperature;
@@ -8228,7 +8274,7 @@ var init_openai = __esm({
8228
8274
  ...message.name ? { name: message.name } : {}
8229
8275
  };
8230
8276
  }
8231
- const textContent = typeof message.content === "string" ? message.content : extractText(message.content);
8277
+ const textContent = typeof message.content === "string" ? message.content : extractMessageText(message.content);
8232
8278
  if (role === "system") {
8233
8279
  return {
8234
8280
  role: "system",
@@ -8288,7 +8334,7 @@ var init_openai = __esm({
8288
8334
  const stream2 = await client.chat.completions.create(payload, signal ? { signal } : void 0);
8289
8335
  return stream2;
8290
8336
  }
8291
- async *wrapStream(iterable) {
8337
+ async *normalizeProviderStream(iterable) {
8292
8338
  const stream2 = iterable;
8293
8339
  for await (const chunk of stream2) {
8294
8340
  const text3 = chunk.choices.map((choice) => choice.delta?.content ?? "").join("");
@@ -8346,9 +8392,9 @@ var init_openai = __esm({
8346
8392
  tokenCount += OPENAI_MESSAGE_OVERHEAD_TOKENS;
8347
8393
  const roleText = ROLE_MAP[message.role];
8348
8394
  tokenCount += encoding.encode(roleText).length;
8349
- const textContent = extractText(message.content);
8395
+ const textContent = extractMessageText(message.content);
8350
8396
  tokenCount += encoding.encode(textContent).length;
8351
- const parts = normalizeContent(message.content);
8397
+ const parts = normalizeMessageContent(message.content);
8352
8398
  for (const part of parts) {
8353
8399
  if (part.type === "image") {
8354
8400
  imageCount++;
@@ -8373,7 +8419,7 @@ var init_openai = __esm({
8373
8419
  let totalChars = 0;
8374
8420
  let imageCount = 0;
8375
8421
  for (const msg of messages) {
8376
- const parts = normalizeContent(msg.content);
8422
+ const parts = normalizeMessageContent(msg.content);
8377
8423
  for (const part of parts) {
8378
8424
  if (part.type === "text") {
8379
8425
  totalChars += part.text.length;
@@ -10106,7 +10152,7 @@ var MockBuilder = class {
10106
10152
  whenMessageContains(text3) {
10107
10153
  this.matchers.push(
10108
10154
  (ctx) => ctx.messages.some(
10109
- (msg) => extractText(msg.content).toLowerCase().includes(text3.toLowerCase())
10155
+ (msg) => extractMessageText(msg.content).toLowerCase().includes(text3.toLowerCase())
10110
10156
  )
10111
10157
  );
10112
10158
  return this;
@@ -10121,7 +10167,7 @@ var MockBuilder = class {
10121
10167
  this.matchers.push((ctx) => {
10122
10168
  const lastMsg = ctx.messages[ctx.messages.length - 1];
10123
10169
  if (!lastMsg) return false;
10124
- return extractText(lastMsg.content).toLowerCase().includes(text3.toLowerCase());
10170
+ return extractMessageText(lastMsg.content).toLowerCase().includes(text3.toLowerCase());
10125
10171
  });
10126
10172
  return this;
10127
10173
  }
@@ -10132,7 +10178,7 @@ var MockBuilder = class {
10132
10178
  * mockLLM().whenMessageMatches(/calculate \d+/)
10133
10179
  */
10134
10180
  whenMessageMatches(regex) {
10135
- this.matchers.push((ctx) => ctx.messages.some((msg) => regex.test(extractText(msg.content))));
10181
+ this.matchers.push((ctx) => ctx.messages.some((msg) => regex.test(extractMessageText(msg.content))));
10136
10182
  return this;
10137
10183
  }
10138
10184
  /**
@@ -10144,7 +10190,7 @@ var MockBuilder = class {
10144
10190
  whenRoleContains(role, text3) {
10145
10191
  this.matchers.push(
10146
10192
  (ctx) => ctx.messages.some(
10147
- (msg) => msg.role === role && extractText(msg.content).toLowerCase().includes(text3.toLowerCase())
10193
+ (msg) => msg.role === role && extractMessageText(msg.content).toLowerCase().includes(text3.toLowerCase())
10148
10194
  )
10149
10195
  );
10150
10196
  return this;
@@ -10566,7 +10612,7 @@ var MockConversationManager = class {
10566
10612
  this.history.push(msg);
10567
10613
  this.addedMessages.push(msg);
10568
10614
  }
10569
- addGadgetCall(gadgetName, parameters, result) {
10615
+ addGadgetCallResult(gadgetName, parameters, result) {
10570
10616
  const assistantMsg = {
10571
10617
  role: "assistant",
10572
10618
  content: `!!!GADGET_START:${gadgetName}
@@ -10676,7 +10722,7 @@ function createMockConversationManager(turnCount, baseMessages = []) {
10676
10722
 
10677
10723
  // src/testing/mock-gadget.ts
10678
10724
  init_gadget();
10679
- var MockGadgetImpl = class extends BaseGadget {
10725
+ var MockGadgetImpl = class extends AbstractGadget {
10680
10726
  name;
10681
10727
  description;
10682
10728
  parameterSchema;