llmist 16.0.4 → 16.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/dist/index.d.ts CHANGED
@@ -632,8 +632,6 @@ interface CompleteGadgetParams {
632
632
  storedMedia?: StoredMedia[];
633
633
  }
634
634
 
635
- /** Event listener function type */
636
- type EventListener = (event: ExecutionEvent) => void;
637
635
  /**
638
636
  * The Execution Tree - single source of truth for all execution state.
639
637
  *
@@ -668,12 +666,9 @@ type EventListener = (event: ExecutionEvent) => void;
668
666
  declare class ExecutionTree {
669
667
  private nodes;
670
668
  private rootIds;
671
- private eventListeners;
672
- private eventIdCounter;
673
669
  private invocationIdToNodeId;
674
- private eventQueue;
675
- private eventWaiters;
676
- private isCompleted;
670
+ private emitter;
671
+ private aggregator;
677
672
  /**
678
673
  * Base depth for all nodes in this tree.
679
674
  * Used when this tree is a subagent's view into a parent tree.
@@ -831,11 +826,11 @@ declare class ExecutionTree {
831
826
  * });
832
827
  * ```
833
828
  */
834
- on(type: ExecutionEventType, listener: EventListener): () => void;
829
+ on(type: ExecutionEventType, listener: (event: ExecutionEvent) => void): () => void;
835
830
  /**
836
831
  * Subscribe to all events.
837
832
  */
838
- onAll(listener: EventListener): () => void;
833
+ onAll(listener: (event: ExecutionEvent) => void): () => void;
839
834
  /**
840
835
  * Get async iterable of all events.
841
836
  * Events are yielded as they occur.
@@ -843,6 +838,7 @@ declare class ExecutionTree {
843
838
  events(): AsyncGenerator<ExecutionEvent>;
844
839
  /**
845
840
  * Mark the tree as complete (no more events will be emitted).
841
+ * Wakes up any consumers waiting in the events() async generator.
846
842
  */
847
843
  complete(): void;
848
844
  /**
@@ -1127,7 +1123,6 @@ declare function Gadget<TSchema extends ZodType>(config: GadgetConfig<TSchema>):
1127
1123
  throwIfAborted(ctx?: ExecutionContext): void;
1128
1124
  onAbort(ctx: ExecutionContext | undefined, cleanup: () => void | Promise<void>): void;
1129
1125
  createLinkedAbortController(ctx?: ExecutionContext): AbortController;
1130
- get instruction(): string;
1131
1126
  getInstruction(optionsOrArgPrefix?: string | {
1132
1127
  argPrefix?: string;
1133
1128
  startPrefix?: string;
@@ -1138,6 +1133,253 @@ declare function Gadget<TSchema extends ZodType>(config: GadgetConfig<TSchema>):
1138
1133
  };
1139
1134
  };
1140
1135
 
1136
+ /**
1137
+ * Proactive rate limiting for LLM API calls.
1138
+ *
1139
+ * Tracks request and token usage in sliding windows to prevent rate limit errors
1140
+ * before they occur. Works in conjunction with reactive backoff (retry.ts) for
1141
+ * comprehensive rate limit handling.
1142
+ */
1143
+ /**
1144
+ * Configuration for proactive rate limiting.
1145
+ *
1146
+ * Set these values based on your API tier to prevent rate limit errors.
1147
+ * When limits are approached, requests will be automatically delayed.
1148
+ *
1149
+ * @example
1150
+ * ```typescript
1151
+ * // Gemini free tier limits
1152
+ * const agent = LLMist.createAgent()
1153
+ * .withRateLimits({
1154
+ * requestsPerMinute: 15,
1155
+ * tokensPerMinute: 1_000_000,
1156
+ * safetyMargin: 0.8,
1157
+ * });
1158
+ *
1159
+ * // OpenAI Tier 1 limits
1160
+ * const agent = LLMist.createAgent()
1161
+ * .withRateLimits({
1162
+ * requestsPerMinute: 500,
1163
+ * tokensPerMinute: 200_000,
1164
+ * });
1165
+ * ```
1166
+ */
1167
+ interface RateLimitConfig {
1168
+ /**
1169
+ * Maximum requests per minute.
1170
+ * Set based on your API tier. If not set, RPM limiting is disabled.
1171
+ */
1172
+ requestsPerMinute?: number;
1173
+ /**
1174
+ * Maximum tokens per minute (input + output combined).
1175
+ * Set based on your API tier. If not set, TPM limiting is disabled.
1176
+ */
1177
+ tokensPerMinute?: number;
1178
+ /**
1179
+ * Maximum tokens per day (optional).
1180
+ * Useful for Gemini free tier which has daily limits.
1181
+ * If not set, daily limiting is disabled.
1182
+ */
1183
+ tokensPerDay?: number;
1184
+ /**
1185
+ * Safety margin - start throttling at this percentage of limit.
1186
+ * A value of 0.9 means throttling starts at 90% of the limit.
1187
+ * Lower values provide more safety but may reduce throughput.
1188
+ * @default 0.9
1189
+ */
1190
+ safetyMargin?: number;
1191
+ /**
1192
+ * Whether proactive rate limiting is enabled.
1193
+ * @default true (when any limit is configured)
1194
+ */
1195
+ enabled?: boolean;
1196
+ }
1197
+ /**
1198
+ * Resolved rate limit configuration with all defaults applied.
1199
+ */
1200
+ interface ResolvedRateLimitConfig {
1201
+ requestsPerMinute?: number;
1202
+ tokensPerMinute?: number;
1203
+ tokensPerDay?: number;
1204
+ safetyMargin: number;
1205
+ enabled: boolean;
1206
+ }
1207
+ /**
1208
+ * Default rate limit configuration values.
1209
+ */
1210
+ declare const DEFAULT_RATE_LIMIT_CONFIG: Pick<ResolvedRateLimitConfig, "safetyMargin" | "enabled">;
1211
+ /**
1212
+ * Resolves a partial rate limit configuration by applying defaults.
1213
+ *
1214
+ * @param config - Partial configuration (optional)
1215
+ * @returns Fully resolved configuration
1216
+ */
1217
+ declare function resolveRateLimitConfig(config?: RateLimitConfig): ResolvedRateLimitConfig;
1218
+ /**
1219
+ * Information about a triggered rate limit.
1220
+ */
1221
+ interface TriggeredLimitInfo {
1222
+ /** Current usage value */
1223
+ current: number;
1224
+ /** Configured limit value */
1225
+ limit: number;
1226
+ /** Effective limit after safety margin (limit × safetyMargin) */
1227
+ effectiveLimit: number;
1228
+ }
1229
+ /**
1230
+ * Usage statistics from the rate limit tracker.
1231
+ */
1232
+ interface RateLimitStats {
1233
+ /** Current requests per minute */
1234
+ rpm: number;
1235
+ /** Current tokens per minute */
1236
+ tpm: number;
1237
+ /** Tokens used today (UTC) */
1238
+ dailyTokens: number;
1239
+ /** Whether any limit is currently being approached */
1240
+ isApproachingLimit: boolean;
1241
+ /** Delay required before next request (0 if none) */
1242
+ requiredDelayMs: number;
1243
+ /** Which limit(s) triggered throttling, if any (present when requiredDelayMs > 0) */
1244
+ triggeredBy?: {
1245
+ rpm?: TriggeredLimitInfo;
1246
+ tpm?: TriggeredLimitInfo;
1247
+ daily?: TriggeredLimitInfo;
1248
+ };
1249
+ }
1250
+ /**
1251
+ * Tracks API usage and calculates required delays for proactive rate limiting.
1252
+ *
1253
+ * Uses sliding windows to track requests and token usage, automatically
1254
+ * calculating delays needed to stay within configured limits.
1255
+ *
1256
+ * @example
1257
+ * ```typescript
1258
+ * const tracker = new RateLimitTracker({
1259
+ * requestsPerMinute: 60,
1260
+ * tokensPerMinute: 100000,
1261
+ * });
1262
+ *
1263
+ * // Before each request
1264
+ * const delay = tracker.getRequiredDelayMs();
1265
+ * if (delay > 0) {
1266
+ * await sleep(delay);
1267
+ * }
1268
+ *
1269
+ * // After each request
1270
+ * tracker.recordUsage(inputTokens, outputTokens);
1271
+ * ```
1272
+ */
1273
+ declare class RateLimitTracker {
1274
+ private config;
1275
+ /** Timestamps of requests in the current minute window */
1276
+ private requestTimestamps;
1277
+ /** Token usage entries in the current minute window */
1278
+ private tokenUsage;
1279
+ /** Daily token count */
1280
+ private dailyTokens;
1281
+ /** Date string (YYYY-MM-DD UTC) for daily reset tracking */
1282
+ private dailyResetDate;
1283
+ /** Count of pending reservations (for backward compatibility) */
1284
+ private pendingReservations;
1285
+ constructor(config?: RateLimitConfig);
1286
+ /**
1287
+ * Record a completed request with its token usage.
1288
+ *
1289
+ * If reserveRequest() was called before the LLM call (recommended for concurrent
1290
+ * scenarios), the request timestamp was already recorded. Otherwise, this method
1291
+ * will add it for backward compatibility.
1292
+ *
1293
+ * @param inputTokens - Number of input tokens used
1294
+ * @param outputTokens - Number of output tokens generated
1295
+ */
1296
+ recordUsage(inputTokens: number, outputTokens: number): void;
1297
+ /**
1298
+ * Calculate the delay needed before the next request.
1299
+ *
1300
+ * Returns 0 if no delay is needed, otherwise returns the number of
1301
+ * milliseconds to wait to stay within rate limits.
1302
+ *
1303
+ * @returns Delay in milliseconds (0 if none needed)
1304
+ */
1305
+ getRequiredDelayMs(): number;
1306
+ /**
1307
+ * Check if we're approaching any configured limits.
1308
+ *
1309
+ * @returns true if any limit is at or above the safety margin threshold
1310
+ */
1311
+ isApproachingLimit(): boolean;
1312
+ /**
1313
+ * Get current usage statistics.
1314
+ *
1315
+ * @returns Current usage stats for monitoring/logging
1316
+ */
1317
+ getUsageStats(): RateLimitStats;
1318
+ /**
1319
+ * Reset all tracking state.
1320
+ * Useful for testing or when switching API keys/tiers.
1321
+ */
1322
+ reset(): void;
1323
+ /**
1324
+ * Update configuration dynamically.
1325
+ * Useful when API tier changes or for testing.
1326
+ *
1327
+ * @param config - New configuration to apply
1328
+ */
1329
+ updateConfig(config: RateLimitConfig): void;
1330
+ /**
1331
+ * Reserve a request slot before making an LLM call.
1332
+ *
1333
+ * This is critical for concurrent subagents sharing a rate limiter.
1334
+ * Without reservation, multiple subagents checking getRequiredDelayMs()
1335
+ * simultaneously would all see zero usage and proceed, causing rate limit errors.
1336
+ *
1337
+ * Call this AFTER waiting for getRequiredDelayMs() but BEFORE making the LLM call.
1338
+ * The reservation ensures subsequent concurrent checks see the pending request.
1339
+ *
1340
+ * @example
1341
+ * ```typescript
1342
+ * // Proactive rate limiting with reservation
1343
+ * const delay = tracker.getRequiredDelayMs();
1344
+ * if (delay > 0) await sleep(delay);
1345
+ *
1346
+ * tracker.reserveRequest(); // Claim slot BEFORE making call
1347
+ * try {
1348
+ * const result = await llm.call();
1349
+ * tracker.recordUsage(result.inputTokens, result.outputTokens);
1350
+ * } catch (error) {
1351
+ * // Request already reserved; recordUsage updates token count
1352
+ * throw error;
1353
+ * }
1354
+ * ```
1355
+ */
1356
+ reserveRequest(): void;
1357
+ /**
1358
+ * Calculate delay needed based on RPM limit.
1359
+ */
1360
+ private calculateRpmDelay;
1361
+ /**
1362
+ * Calculate delay needed based on TPM limit.
1363
+ */
1364
+ private calculateTpmDelay;
1365
+ /**
1366
+ * Remove entries older than 1 minute from the sliding window.
1367
+ */
1368
+ private pruneOldEntries;
1369
+ /**
1370
+ * Check if the day has changed (UTC) and reset daily counters.
1371
+ */
1372
+ private checkDailyReset;
1373
+ /**
1374
+ * Get current date in YYYY-MM-DD format (UTC).
1375
+ */
1376
+ private getCurrentDateUTC;
1377
+ /**
1378
+ * Calculate milliseconds until midnight UTC.
1379
+ */
1380
+ private getTimeUntilMidnightUTC;
1381
+ }
1382
+
1141
1383
  /**
1142
1384
  * Model Catalog Types
1143
1385
  *
@@ -1457,255 +1699,8 @@ interface ResolvedCompactionConfig {
1457
1699
  }
1458
1700
 
1459
1701
  /**
1460
- * Proactive rate limiting for LLM API calls.
1461
- *
1462
- * Tracks request and token usage in sliding windows to prevent rate limit errors
1463
- * before they occur. Works in conjunction with reactive backoff (retry.ts) for
1464
- * comprehensive rate limit handling.
1465
- */
1466
- /**
1467
- * Configuration for proactive rate limiting.
1468
- *
1469
- * Set these values based on your API tier to prevent rate limit errors.
1470
- * When limits are approached, requests will be automatically delayed.
1471
- *
1472
- * @example
1473
- * ```typescript
1474
- * // Gemini free tier limits
1475
- * const agent = LLMist.createAgent()
1476
- * .withRateLimits({
1477
- * requestsPerMinute: 15,
1478
- * tokensPerMinute: 1_000_000,
1479
- * safetyMargin: 0.8,
1480
- * });
1481
- *
1482
- * // OpenAI Tier 1 limits
1483
- * const agent = LLMist.createAgent()
1484
- * .withRateLimits({
1485
- * requestsPerMinute: 500,
1486
- * tokensPerMinute: 200_000,
1487
- * });
1488
- * ```
1489
- */
1490
- interface RateLimitConfig {
1491
- /**
1492
- * Maximum requests per minute.
1493
- * Set based on your API tier. If not set, RPM limiting is disabled.
1494
- */
1495
- requestsPerMinute?: number;
1496
- /**
1497
- * Maximum tokens per minute (input + output combined).
1498
- * Set based on your API tier. If not set, TPM limiting is disabled.
1499
- */
1500
- tokensPerMinute?: number;
1501
- /**
1502
- * Maximum tokens per day (optional).
1503
- * Useful for Gemini free tier which has daily limits.
1504
- * If not set, daily limiting is disabled.
1505
- */
1506
- tokensPerDay?: number;
1507
- /**
1508
- * Safety margin - start throttling at this percentage of limit.
1509
- * A value of 0.9 means throttling starts at 90% of the limit.
1510
- * Lower values provide more safety but may reduce throughput.
1511
- * @default 0.9
1512
- */
1513
- safetyMargin?: number;
1514
- /**
1515
- * Whether proactive rate limiting is enabled.
1516
- * @default true (when any limit is configured)
1517
- */
1518
- enabled?: boolean;
1519
- }
1520
- /**
1521
- * Resolved rate limit configuration with all defaults applied.
1522
- */
1523
- interface ResolvedRateLimitConfig {
1524
- requestsPerMinute?: number;
1525
- tokensPerMinute?: number;
1526
- tokensPerDay?: number;
1527
- safetyMargin: number;
1528
- enabled: boolean;
1529
- }
1530
- /**
1531
- * Default rate limit configuration values.
1532
- */
1533
- declare const DEFAULT_RATE_LIMIT_CONFIG: Pick<ResolvedRateLimitConfig, "safetyMargin" | "enabled">;
1534
- /**
1535
- * Resolves a partial rate limit configuration by applying defaults.
1536
- *
1537
- * @param config - Partial configuration (optional)
1538
- * @returns Fully resolved configuration
1539
- */
1540
- declare function resolveRateLimitConfig(config?: RateLimitConfig): ResolvedRateLimitConfig;
1541
- /**
1542
- * Information about a triggered rate limit.
1543
- */
1544
- interface TriggeredLimitInfo {
1545
- /** Current usage value */
1546
- current: number;
1547
- /** Configured limit value */
1548
- limit: number;
1549
- /** Effective limit after safety margin (limit × safetyMargin) */
1550
- effectiveLimit: number;
1551
- }
1552
- /**
1553
- * Usage statistics from the rate limit tracker.
1554
- */
1555
- interface RateLimitStats {
1556
- /** Current requests per minute */
1557
- rpm: number;
1558
- /** Current tokens per minute */
1559
- tpm: number;
1560
- /** Tokens used today (UTC) */
1561
- dailyTokens: number;
1562
- /** Whether any limit is currently being approached */
1563
- isApproachingLimit: boolean;
1564
- /** Delay required before next request (0 if none) */
1565
- requiredDelayMs: number;
1566
- /** Which limit(s) triggered throttling, if any (present when requiredDelayMs > 0) */
1567
- triggeredBy?: {
1568
- rpm?: TriggeredLimitInfo;
1569
- tpm?: TriggeredLimitInfo;
1570
- daily?: TriggeredLimitInfo;
1571
- };
1572
- }
1573
- /**
1574
- * Tracks API usage and calculates required delays for proactive rate limiting.
1575
- *
1576
- * Uses sliding windows to track requests and token usage, automatically
1577
- * calculating delays needed to stay within configured limits.
1578
- *
1579
- * @example
1580
- * ```typescript
1581
- * const tracker = new RateLimitTracker({
1582
- * requestsPerMinute: 60,
1583
- * tokensPerMinute: 100000,
1584
- * });
1585
- *
1586
- * // Before each request
1587
- * const delay = tracker.getRequiredDelayMs();
1588
- * if (delay > 0) {
1589
- * await sleep(delay);
1590
- * }
1591
- *
1592
- * // After each request
1593
- * tracker.recordUsage(inputTokens, outputTokens);
1594
- * ```
1595
- */
1596
- declare class RateLimitTracker {
1597
- private config;
1598
- /** Timestamps of requests in the current minute window */
1599
- private requestTimestamps;
1600
- /** Token usage entries in the current minute window */
1601
- private tokenUsage;
1602
- /** Daily token count */
1603
- private dailyTokens;
1604
- /** Date string (YYYY-MM-DD UTC) for daily reset tracking */
1605
- private dailyResetDate;
1606
- /** Count of pending reservations (for backward compatibility) */
1607
- private pendingReservations;
1608
- constructor(config?: RateLimitConfig);
1609
- /**
1610
- * Record a completed request with its token usage.
1611
- *
1612
- * If reserveRequest() was called before the LLM call (recommended for concurrent
1613
- * scenarios), the request timestamp was already recorded. Otherwise, this method
1614
- * will add it for backward compatibility.
1615
- *
1616
- * @param inputTokens - Number of input tokens used
1617
- * @param outputTokens - Number of output tokens generated
1618
- */
1619
- recordUsage(inputTokens: number, outputTokens: number): void;
1620
- /**
1621
- * Calculate the delay needed before the next request.
1622
- *
1623
- * Returns 0 if no delay is needed, otherwise returns the number of
1624
- * milliseconds to wait to stay within rate limits.
1625
- *
1626
- * @returns Delay in milliseconds (0 if none needed)
1627
- */
1628
- getRequiredDelayMs(): number;
1629
- /**
1630
- * Check if we're approaching any configured limits.
1631
- *
1632
- * @returns true if any limit is at or above the safety margin threshold
1633
- */
1634
- isApproachingLimit(): boolean;
1635
- /**
1636
- * Get current usage statistics.
1637
- *
1638
- * @returns Current usage stats for monitoring/logging
1639
- */
1640
- getUsageStats(): RateLimitStats;
1641
- /**
1642
- * Reset all tracking state.
1643
- * Useful for testing or when switching API keys/tiers.
1644
- */
1645
- reset(): void;
1646
- /**
1647
- * Update configuration dynamically.
1648
- * Useful when API tier changes or for testing.
1649
- *
1650
- * @param config - New configuration to apply
1651
- */
1652
- updateConfig(config: RateLimitConfig): void;
1653
- /**
1654
- * Reserve a request slot before making an LLM call.
1655
- *
1656
- * This is critical for concurrent subagents sharing a rate limiter.
1657
- * Without reservation, multiple subagents checking getRequiredDelayMs()
1658
- * simultaneously would all see zero usage and proceed, causing rate limit errors.
1659
- *
1660
- * Call this AFTER waiting for getRequiredDelayMs() but BEFORE making the LLM call.
1661
- * The reservation ensures subsequent concurrent checks see the pending request.
1662
- *
1663
- * @example
1664
- * ```typescript
1665
- * // Proactive rate limiting with reservation
1666
- * const delay = tracker.getRequiredDelayMs();
1667
- * if (delay > 0) await sleep(delay);
1668
- *
1669
- * tracker.reserveRequest(); // Claim slot BEFORE making call
1670
- * try {
1671
- * const result = await llm.call();
1672
- * tracker.recordUsage(result.inputTokens, result.outputTokens);
1673
- * } catch (error) {
1674
- * // Request already reserved; recordUsage updates token count
1675
- * throw error;
1676
- * }
1677
- * ```
1678
- */
1679
- reserveRequest(): void;
1680
- /**
1681
- * Calculate delay needed based on RPM limit.
1682
- */
1683
- private calculateRpmDelay;
1684
- /**
1685
- * Calculate delay needed based on TPM limit.
1686
- */
1687
- private calculateTpmDelay;
1688
- /**
1689
- * Remove entries older than 1 minute from the sliding window.
1690
- */
1691
- private pruneOldEntries;
1692
- /**
1693
- * Check if the day has changed (UTC) and reset daily counters.
1694
- */
1695
- private checkDailyReset;
1696
- /**
1697
- * Get current date in YYYY-MM-DD format (UTC).
1698
- */
1699
- private getCurrentDateUTC;
1700
- /**
1701
- * Calculate milliseconds until midnight UTC.
1702
- */
1703
- private getTimeUntilMidnightUTC;
1704
- }
1705
-
1706
- /**
1707
- * Metadata present when an event originates from a subagent.
1708
- * Undefined for top-level agent events.
1702
+ * Metadata present when an event originates from a subagent.
1703
+ * Undefined for top-level agent events.
1709
1704
  *
1710
1705
  * When using subagent gadgets (like BrowseWeb), hook observers receive events
1711
1706
  * from both the main agent AND subagents. Check this context to distinguish.
@@ -1823,13 +1818,6 @@ interface ObserveGadgetCompleteContext {
1823
1818
  gadgetName: string;
1824
1819
  invocationId: string;
1825
1820
  parameters: Readonly<Record<string, unknown>>;
1826
- /**
1827
- * Original result before interceptors.
1828
- * @deprecated No longer populated. Use `finalResult` instead.
1829
- * With the unified event architecture, observers receive the final (post-interceptor)
1830
- * result from the ExecutionTree.
1831
- */
1832
- originalResult?: string;
1833
1821
  /** Final result after interceptors (the value stored in ExecutionTree) */
1834
1822
  finalResult?: string;
1835
1823
  error?: string;
@@ -2942,302 +2930,113 @@ declare function parseRetryAfterHeader(value: string): number | null;
2942
2930
  declare function extractRetryAfterMs(error: Error): number | null;
2943
2931
 
2944
2932
  /**
2945
- * Example of gadget usage to help LLMs understand proper invocation.
2946
- *
2947
- * Examples are rendered alongside the schema in `getInstruction()` to provide
2948
- * concrete usage patterns for the LLM.
2933
+ * Subagent configuration types.
2949
2934
  *
2950
- * @template TParams - Inferred parameter type from Zod schema (defaults to Record<string, unknown>)
2935
+ * Simple config shapes passed to gadgets for subagent configuration.
2936
+ * No external dependencies — self-contained data shapes.
2951
2937
  *
2952
- * @example
2953
- * ```typescript
2954
- * const calculator = createGadget({
2955
- * schema: z.object({ a: z.number(), b: z.number() }),
2956
- * examples: [
2957
- * { params: { a: 5, b: 3 }, output: "8", comment: "Addition example" }
2958
- * ],
2959
- * // ...
2960
- * });
2961
- * ```
2962
- */
2963
- interface GadgetExample<TParams = Record<string, unknown>> {
2964
- /** Example parameter values (typed to match schema) */
2965
- params: TParams;
2966
- /** Optional expected output/result string */
2967
- output?: string;
2968
- /** Optional description explaining what this example demonstrates */
2969
- comment?: string;
2970
- }
2971
- /**
2972
- * Supported media types for gadget output.
2973
- * Extensible via union - add new types as needed.
2938
+ * @module
2974
2939
  */
2975
- type MediaKind = "image" | "audio" | "video" | "file";
2976
2940
  /**
2977
- * Type-specific metadata for media outputs.
2978
- * Extensible via index signature for future media types.
2941
+ * Parent agent configuration passed to gadgets.
2942
+ * Contains settings that subagents can inherit.
2979
2943
  */
2980
- interface MediaMetadata {
2981
- /** Width in pixels (images, video) */
2982
- width?: number;
2983
- /** Height in pixels (images, video) */
2984
- height?: number;
2985
- /** Duration in milliseconds (audio, video) */
2986
- durationMs?: number;
2987
- /** Allow additional metadata for future extensions */
2988
- [key: string]: unknown;
2944
+ interface AgentContextConfig {
2945
+ /** Model identifier used by the parent agent */
2946
+ model: string;
2947
+ /** Temperature setting used by the parent agent */
2948
+ temperature?: number;
2989
2949
  }
2990
2950
  /**
2991
- * Media output from a gadget execution.
2992
- * Supports images, audio, video, and arbitrary files.
2951
+ * Configuration for a single subagent.
2952
+ * Can be defined globally in `[subagents.Name]` or per-profile in `[profile.subagents.Name]`.
2993
2953
  *
2994
2954
  * @example
2995
- * ```typescript
2996
- * // Image output
2997
- * const imageOutput: GadgetMediaOutput = {
2998
- * kind: "image",
2999
- * data: base64EncodedPng,
3000
- * mimeType: "image/png",
3001
- * description: "Screenshot of webpage",
3002
- * metadata: { width: 1920, height: 1080 }
3003
- * };
2955
+ * ```toml
2956
+ * [subagents.BrowseWeb]
2957
+ * model = "inherit" # Use parent agent's model
2958
+ * maxIterations = 20
2959
+ * headless = true
3004
2960
  * ```
3005
2961
  */
3006
- interface GadgetMediaOutput {
3007
- /** Type of media (discriminator for type-specific handling) */
3008
- kind: MediaKind;
3009
- /** Base64-encoded media data */
3010
- data: string;
3011
- /** Full MIME type (e.g., "image/png", "audio/mp3", "video/mp4") */
3012
- mimeType: string;
3013
- /** Human-readable description of the media */
3014
- description?: string;
3015
- /** Type-specific metadata */
3016
- metadata?: MediaMetadata;
3017
- /** Optional filename to use when saving (if not provided, auto-generated) */
3018
- fileName?: string;
2962
+ interface SubagentConfig {
2963
+ /**
2964
+ * Model to use for this subagent.
2965
+ * - "inherit": Use parent agent's model (default behavior)
2966
+ * - Any model ID: Use specific model (e.g., "sonnet", "haiku", "gpt-4o")
2967
+ */
2968
+ model?: string;
2969
+ /** Maximum iterations for the subagent loop */
2970
+ maxIterations?: number;
2971
+ /** Budget limit in USD for the subagent */
2972
+ budget?: number;
2973
+ /**
2974
+ * Timeout for the subagent gadget execution in milliseconds.
2975
+ * Overrides the gadget's hardcoded timeoutMs when set.
2976
+ * Set to 0 to disable timeout for this gadget.
2977
+ */
2978
+ timeoutMs?: number;
2979
+ /**
2980
+ * Maximum number of concurrent executions allowed for this gadget.
2981
+ * When the limit is reached, additional calls are queued and processed
2982
+ * as earlier executions complete (FIFO order).
2983
+ * Set to 0 or omit to allow unlimited concurrent executions (default).
2984
+ */
2985
+ maxConcurrent?: number;
2986
+ /** Additional subagent-specific options */
2987
+ [key: string]: unknown;
3019
2988
  }
3020
2989
  /**
3021
- * Stored media item with metadata and file path.
3022
- *
3023
- * Created by MediaStore when a gadget returns media outputs.
3024
- * Contains the abstract ID, file path, and metadata for display.
2990
+ * Map of subagent names to their configurations.
3025
2991
  */
3026
- interface StoredMedia {
3027
- /** Unique ID for this media item (e.g., "media_a1b2c3") */
3028
- id: string;
3029
- /** Type of media */
3030
- kind: MediaKind;
3031
- /** Actual file path on disk (internal use) */
3032
- path: string;
3033
- /** MIME type */
3034
- mimeType: string;
3035
- /** File size in bytes */
3036
- sizeBytes: number;
3037
- /** Human-readable description */
3038
- description?: string;
3039
- /** Type-specific metadata */
3040
- metadata?: MediaMetadata;
3041
- /** Name of the gadget that created this media */
3042
- gadgetName: string;
3043
- /** When the media was stored */
3044
- createdAt: Date;
3045
- }
3046
- interface GadgetExecutionResult {
3047
- gadgetName: string;
3048
- invocationId: string;
3049
- parameters: Record<string, unknown>;
3050
- result?: string;
3051
- error?: string;
3052
- executionTimeMs: number;
3053
- breaksLoop?: boolean;
3054
- /** Cost of gadget execution in USD. Defaults to 0 if not provided by gadget. */
3055
- cost?: number;
3056
- /** Media outputs from the gadget (images, audio, video, files) */
3057
- media?: GadgetMediaOutput[];
3058
- /** Abstract IDs for media outputs (e.g., ["media_a1b2c3"]) */
3059
- mediaIds?: string[];
3060
- /** Stored media with paths (for CLI display) */
3061
- storedMedia?: StoredMedia[];
3062
- }
2992
+ type SubagentConfigMap = Record<string, SubagentConfig>;
3063
2993
  /**
3064
- * Result returned by gadget execute() method.
3065
- * Can be a simple string or an object with result and optional cost.
2994
+ * Gadget execution mode controlling how multiple gadgets are executed.
3066
2995
  *
3067
- * @example
3068
- * ```typescript
3069
- * // Simple string return (free gadget)
3070
- * execute: () => "result"
2996
+ * - `'parallel'` (default): Gadgets without dependencies execute concurrently (fire-and-forget).
2997
+ * This maximizes throughput but gadgets may complete in any order.
3071
2998
  *
3072
- * // Object return with cost
3073
- * execute: () => ({ result: "data", cost: 0.001 })
3074
- * ```
3075
- */
3076
- interface GadgetExecuteResult {
3077
- /** The execution result as a string */
3078
- result: string;
3079
- /** Optional cost in USD (e.g., 0.001 for $0.001) */
3080
- cost?: number;
3081
- }
3082
- /**
3083
- * Extended result type with media support.
3084
- * Use this when gadget returns images, audio, video, or files.
2999
+ * - `'sequential'`: Gadgets execute one at a time, each awaiting completion before the next starts.
3000
+ * Useful for:
3001
+ * - Gadgets with implicit ordering dependencies (e.g., file operations)
3002
+ * - Debugging and tracing execution flow
3003
+ * - Resource-constrained environments
3004
+ * - Ensuring deterministic execution order
3005
+ *
3006
+ * Note: Explicit `dependsOn` relationships are always respected regardless of mode.
3007
+ * Sequential mode effectively enforces a global `maxConcurrent: 1` for all gadgets.
3085
3008
  *
3086
3009
  * @example
3087
3010
  * ```typescript
3088
- * // Return with image
3089
- * execute: () => ({
3090
- * result: "Screenshot captured",
3091
- * media: [{
3092
- * kind: "image",
3093
- * data: base64EncodedPng,
3094
- * mimeType: "image/png",
3095
- * description: "Screenshot"
3096
- * }],
3097
- * cost: 0.001
3098
- * })
3011
+ * const agent = LLMist.createAgent()
3012
+ * .withModel("sonnet")
3013
+ * .withGadgets(FileReader, FileWriter)
3014
+ * .withGadgetExecutionMode('sequential') // Execute one at a time
3015
+ * .ask("Process files in order");
3099
3016
  * ```
3100
3017
  */
3101
- interface GadgetExecuteResultWithMedia {
3102
- /** The execution result as a string */
3103
- result: string;
3104
- /** Media outputs (images, audio, video, files) */
3105
- media?: GadgetMediaOutput[];
3106
- /** Optional cost in USD (e.g., 0.001 for $0.001) */
3107
- cost?: number;
3108
- }
3109
- /**
3110
- * Union type for backwards-compatible execute() return type.
3111
- * Gadgets can return:
3112
- * - string (legacy, cost = 0)
3113
- * - GadgetExecuteResult (result + optional cost)
3114
- * - GadgetExecuteResultWithMedia (result + optional media + optional cost)
3115
- */
3116
- type GadgetExecuteReturn = string | GadgetExecuteResult | GadgetExecuteResultWithMedia;
3117
- interface ParsedGadgetCall {
3118
- gadgetName: string;
3119
- invocationId: string;
3120
- parametersRaw: string;
3121
- parameters?: Record<string, unknown>;
3122
- parseError?: string;
3123
- /** List of invocation IDs this gadget depends on. Empty array if no dependencies. */
3124
- dependencies: string[];
3125
- }
3126
-
3127
- /** Event emitted when a gadget is skipped due to a failed dependency */
3128
- interface GadgetSkippedEvent {
3129
- type: "gadget_skipped";
3130
- gadgetName: string;
3131
- invocationId: string;
3132
- parameters: Record<string, unknown>;
3133
- /** The invocation ID of the dependency that failed */
3134
- failedDependency: string;
3135
- /** The error message from the failed dependency */
3136
- failedDependencyError: string;
3137
- }
3138
- /**
3139
- * Event emitted when stream processing completes, containing metadata.
3140
- * This allows the async generator to "return" metadata while still yielding events.
3141
- */
3142
- interface StreamCompletionEvent {
3143
- type: "stream_complete";
3144
- /** The reason the LLM stopped generating (e.g., "stop", "tool_use") */
3145
- finishReason: string | null;
3146
- /** Token usage statistics from the LLM call */
3147
- usage?: TokenUsage;
3148
- /** Raw response text from the LLM */
3149
- rawResponse: string;
3150
- /** Final message after all interceptors applied */
3151
- finalMessage: string;
3152
- /** Whether any gadgets were executed during this iteration */
3153
- didExecuteGadgets: boolean;
3154
- /** Whether to break the agent loop (e.g., TaskComplete was called) */
3155
- shouldBreakLoop: boolean;
3156
- /** Accumulated thinking/reasoning content from reasoning models */
3157
- thinkingContent?: string;
3158
- }
3159
- type StreamEvent = {
3160
- type: "text";
3161
- content: string;
3162
- } | {
3163
- type: "thinking";
3164
- content: string;
3165
- thinkingType: "thinking" | "redacted";
3166
- } | {
3167
- type: "gadget_call";
3168
- call: ParsedGadgetCall;
3169
- } | {
3170
- type: "gadget_result";
3171
- result: GadgetExecutionResult;
3172
- } | GadgetSkippedEvent | {
3173
- type: "human_input_required";
3174
- question: string;
3175
- gadgetName: string;
3176
- invocationId: string;
3177
- } | {
3178
- type: "compaction";
3179
- event: CompactionEvent;
3180
- } | {
3181
- type: "llm_response_end";
3182
- finishReason: string | null;
3183
- usage?: TokenUsage;
3184
- } | StreamCompletionEvent;
3018
+ type GadgetExecutionMode = "parallel" | "sequential";
3185
3019
 
3186
- type TextOnlyHandler = TextOnlyStrategy | TextOnlyGadgetConfig | TextOnlyCustomHandler;
3187
- /**
3188
- * Simple strategies for common cases
3189
- * - 'terminate': End the loop (default behavior)
3190
- * - 'acknowledge': Continue to next iteration
3191
- * - 'wait_for_input': Request human input
3192
- */
3193
- type TextOnlyStrategy = "terminate" | "acknowledge" | "wait_for_input";
3194
3020
  /**
3195
- * Configuration for triggering a gadget when receiving text-only response
3021
+ * Image generation namespace with automatic cost reporting.
3196
3022
  */
3197
- interface TextOnlyGadgetConfig {
3198
- type: "gadget";
3199
- name: string;
3023
+ interface CostReportingImageNamespace {
3200
3024
  /**
3201
- * Optional function to map text to gadget parameters.
3202
- * If not provided, text will be passed as { text: string }
3025
+ * Generate images from a text prompt.
3026
+ * Costs are automatically reported to the execution context.
3203
3027
  */
3204
- parameterMapping?: (text: string) => Record<string, unknown>;
3205
- }
3206
- /**
3207
- * Custom handler for complex text-only response scenarios
3208
- */
3209
- interface TextOnlyCustomHandler {
3210
- type: "custom";
3211
- handler: (context: TextOnlyContext) => Promise<TextOnlyAction> | TextOnlyAction;
3028
+ generate(options: ImageGenerationOptions): Promise<ImageGenerationResult>;
3212
3029
  }
3213
3030
  /**
3214
- * Context provided to custom text-only handlers
3031
+ * Speech generation namespace with automatic cost reporting.
3215
3032
  */
3216
- interface TextOnlyContext {
3217
- /** The complete text response from the LLM */
3218
- text: string;
3219
- /** Current iteration number */
3220
- iteration: number;
3221
- /** Full conversation history */
3222
- conversation: LLMMessage[];
3223
- /** Logger instance */
3224
- logger: Logger<ILogObj>;
3033
+ interface CostReportingSpeechNamespace {
3034
+ /**
3035
+ * Generate speech audio from text.
3036
+ * Costs are automatically reported to the execution context.
3037
+ */
3038
+ generate(options: SpeechGenerationOptions): Promise<SpeechGenerationResult>;
3225
3039
  }
3226
- /**
3227
- * Actions that can be returned by text-only handlers
3228
- */
3229
- type TextOnlyAction = {
3230
- action: "continue";
3231
- } | {
3232
- action: "terminate";
3233
- } | {
3234
- action: "wait_for_input";
3235
- question?: string;
3236
- } | {
3237
- action: "trigger_gadget";
3238
- name: string;
3239
- parameters: Record<string, unknown>;
3240
- };
3241
3040
  /**
3242
3041
  * LLMist client interface for use within gadgets.
3243
3042
  *
@@ -3256,26 +3055,6 @@ type TextOnlyAction = {
3256
3055
  * }
3257
3056
  * ```
3258
3057
  */
3259
- /**
3260
- * Image generation namespace with automatic cost reporting.
3261
- */
3262
- interface CostReportingImageNamespace {
3263
- /**
3264
- * Generate images from a text prompt.
3265
- * Costs are automatically reported to the execution context.
3266
- */
3267
- generate(options: ImageGenerationOptions): Promise<ImageGenerationResult>;
3268
- }
3269
- /**
3270
- * Speech generation namespace with automatic cost reporting.
3271
- */
3272
- interface CostReportingSpeechNamespace {
3273
- /**
3274
- * Generate speech audio from text.
3275
- * Costs are automatically reported to the execution context.
3276
- */
3277
- generate(options: SpeechGenerationOptions): Promise<SpeechGenerationResult>;
3278
- }
3279
3058
  interface CostReportingLLMist {
3280
3059
  /**
3281
3060
  * Quick completion - returns final text response.
@@ -3739,105 +3518,360 @@ interface ExecutionContext {
3739
3518
  retryConfig?: ResolvedRetryConfig;
3740
3519
  }
3741
3520
  /**
3742
- * Host llmist exports provided to external gadgets via ExecutionContext.
3521
+ * Host llmist exports provided to external gadgets via ExecutionContext.
3522
+ *
3523
+ * This ensures external gadgets use the same class instances as the host CLI,
3524
+ * enabling proper tree sharing and avoiding the "dual-package problem" where
3525
+ * different versions of llmist have incompatible classes.
3526
+ */
3527
+ interface HostExports {
3528
+ /** AgentBuilder for creating subagents with proper tree sharing */
3529
+ AgentBuilder: typeof AgentBuilder;
3530
+ /** Gadget factory for defining gadgets */
3531
+ Gadget: typeof Gadget;
3532
+ /** createGadget for functional gadget definitions */
3533
+ createGadget: typeof createGadget;
3534
+ /** ExecutionTree for tree operations */
3535
+ ExecutionTree: typeof ExecutionTree;
3536
+ /** LLMist client */
3537
+ LLMist: typeof LLMist;
3538
+ /** Zod schema builder */
3539
+ z: typeof zod.z;
3540
+ }
3541
+
3542
+ /**
3543
+ * Media output types for gadgets returning images, audio, video, or files.
3544
+ *
3545
+ * This module contains pure data shapes with zero cross-module dependencies.
3546
+ * Imported by execution result types, stream event types, and execution context types.
3547
+ *
3548
+ * @module
3549
+ */
3550
+ /**
3551
+ * Supported media types for gadget output.
3552
+ * Extensible via union - add new types as needed.
3553
+ */
3554
+ type MediaKind = "image" | "audio" | "video" | "file";
3555
+ /**
3556
+ * Type-specific metadata for media outputs.
3557
+ * Extensible via index signature for future media types.
3558
+ */
3559
+ interface MediaMetadata {
3560
+ /** Width in pixels (images, video) */
3561
+ width?: number;
3562
+ /** Height in pixels (images, video) */
3563
+ height?: number;
3564
+ /** Duration in milliseconds (audio, video) */
3565
+ durationMs?: number;
3566
+ /** Allow additional metadata for future extensions */
3567
+ [key: string]: unknown;
3568
+ }
3569
+ /**
3570
+ * Media output from a gadget execution.
3571
+ * Supports images, audio, video, and arbitrary files.
3572
+ *
3573
+ * @example
3574
+ * ```typescript
3575
+ * // Image output
3576
+ * const imageOutput: GadgetMediaOutput = {
3577
+ * kind: "image",
3578
+ * data: base64EncodedPng,
3579
+ * mimeType: "image/png",
3580
+ * description: "Screenshot of webpage",
3581
+ * metadata: { width: 1920, height: 1080 }
3582
+ * };
3583
+ * ```
3584
+ */
3585
+ interface GadgetMediaOutput {
3586
+ /** Type of media (discriminator for type-specific handling) */
3587
+ kind: MediaKind;
3588
+ /** Base64-encoded media data */
3589
+ data: string;
3590
+ /** Full MIME type (e.g., "image/png", "audio/mp3", "video/mp4") */
3591
+ mimeType: string;
3592
+ /** Human-readable description of the media */
3593
+ description?: string;
3594
+ /** Type-specific metadata */
3595
+ metadata?: MediaMetadata;
3596
+ /** Optional filename to use when saving (if not provided, auto-generated) */
3597
+ fileName?: string;
3598
+ }
3599
+ /**
3600
+ * Stored media item with metadata and file path.
3601
+ *
3602
+ * Created by MediaStore when a gadget returns media outputs.
3603
+ * Contains the abstract ID, file path, and metadata for display.
3604
+ */
3605
+ interface StoredMedia {
3606
+ /** Unique ID for this media item (e.g., "media_a1b2c3") */
3607
+ id: string;
3608
+ /** Type of media */
3609
+ kind: MediaKind;
3610
+ /** Actual file path on disk (internal use) */
3611
+ path: string;
3612
+ /** MIME type */
3613
+ mimeType: string;
3614
+ /** File size in bytes */
3615
+ sizeBytes: number;
3616
+ /** Human-readable description */
3617
+ description?: string;
3618
+ /** Type-specific metadata */
3619
+ metadata?: MediaMetadata;
3620
+ /** Name of the gadget that created this media */
3621
+ gadgetName: string;
3622
+ /** When the media was stored */
3623
+ createdAt: Date;
3624
+ }
3625
+ /**
3626
+ * Example of gadget usage to help LLMs understand proper invocation.
3627
+ *
3628
+ * Examples are rendered alongside the schema in `getInstruction()` to provide
3629
+ * concrete usage patterns for the LLM.
3630
+ *
3631
+ * @template TParams - Inferred parameter type from Zod schema (defaults to Record<string, unknown>)
3632
+ *
3633
+ * @example
3634
+ * ```typescript
3635
+ * const calculator = createGadget({
3636
+ * schema: z.object({ a: z.number(), b: z.number() }),
3637
+ * examples: [
3638
+ * { params: { a: 5, b: 3 }, output: "8", comment: "Addition example" }
3639
+ * ],
3640
+ * // ...
3641
+ * });
3642
+ * ```
3643
+ */
3644
+ interface GadgetExample<TParams = Record<string, unknown>> {
3645
+ /** Example parameter values (typed to match schema) */
3646
+ params: TParams;
3647
+ /** Optional expected output/result string */
3648
+ output?: string;
3649
+ /** Optional description explaining what this example demonstrates */
3650
+ comment?: string;
3651
+ }
3652
+
3653
+ /**
3654
+ * Execution result types for gadget calls.
3655
+ *
3656
+ * Contains result types returned by gadget `execute()` methods and the
3657
+ * internal result type used after execution completes.
3658
+ *
3659
+ * @module
3660
+ */
3661
+
3662
+ interface GadgetExecutionResult {
3663
+ gadgetName: string;
3664
+ invocationId: string;
3665
+ parameters: Record<string, unknown>;
3666
+ result?: string;
3667
+ error?: string;
3668
+ executionTimeMs: number;
3669
+ breaksLoop?: boolean;
3670
+ /** Cost of gadget execution in USD. Defaults to 0 if not provided by gadget. */
3671
+ cost?: number;
3672
+ /** Media outputs from the gadget (images, audio, video, files) */
3673
+ media?: GadgetMediaOutput[];
3674
+ /** Abstract IDs for media outputs (e.g., ["media_a1b2c3"]) */
3675
+ mediaIds?: string[];
3676
+ /** Stored media with paths (for CLI display) */
3677
+ storedMedia?: StoredMedia[];
3678
+ }
3679
+ /**
3680
+ * Result returned by gadget execute() method.
3681
+ * Can be a simple string or an object with result and optional cost.
3682
+ *
3683
+ * @example
3684
+ * ```typescript
3685
+ * // Simple string return (free gadget)
3686
+ * execute: () => "result"
3687
+ *
3688
+ * // Object return with cost
3689
+ * execute: () => ({ result: "data", cost: 0.001 })
3690
+ * ```
3691
+ */
3692
+ interface GadgetExecuteResult {
3693
+ /** The execution result as a string */
3694
+ result: string;
3695
+ /** Optional cost in USD (e.g., 0.001 for $0.001) */
3696
+ cost?: number;
3697
+ }
3698
+ /**
3699
+ * Extended result type with media support.
3700
+ * Use this when gadget returns images, audio, video, or files.
3701
+ *
3702
+ * @example
3703
+ * ```typescript
3704
+ * // Return with image
3705
+ * execute: () => ({
3706
+ * result: "Screenshot captured",
3707
+ * media: [{
3708
+ * kind: "image",
3709
+ * data: base64EncodedPng,
3710
+ * mimeType: "image/png",
3711
+ * description: "Screenshot"
3712
+ * }],
3713
+ * cost: 0.001
3714
+ * })
3715
+ * ```
3716
+ */
3717
+ interface GadgetExecuteResultWithMedia {
3718
+ /** The execution result as a string */
3719
+ result: string;
3720
+ /** Media outputs (images, audio, video, files) */
3721
+ media?: GadgetMediaOutput[];
3722
+ /** Optional cost in USD (e.g., 0.001 for $0.001) */
3723
+ cost?: number;
3724
+ }
3725
+ /**
3726
+ * Union type for backwards-compatible execute() return type.
3727
+ * Gadgets can return:
3728
+ * - string (legacy, cost = 0)
3729
+ * - GadgetExecuteResult (result + optional cost)
3730
+ * - GadgetExecuteResultWithMedia (result + optional media + optional cost)
3731
+ */
3732
+ type GadgetExecuteReturn = string | GadgetExecuteResult | GadgetExecuteResultWithMedia;
3733
+ interface ParsedGadgetCall {
3734
+ gadgetName: string;
3735
+ invocationId: string;
3736
+ parametersRaw: string;
3737
+ parameters?: Record<string, unknown>;
3738
+ parseError?: string;
3739
+ /** List of invocation IDs this gadget depends on. Empty array if no dependencies. */
3740
+ dependencies: string[];
3741
+ }
3742
+
3743
+ /**
3744
+ * Stream event types emitted during agent execution.
3745
+ *
3746
+ * Contains all discriminated union members for `StreamEvent`, plus
3747
+ * `StreamCompletionEvent` and `GadgetSkippedEvent`.
3748
+ *
3749
+ * @module
3750
+ */
3751
+
3752
+ /** Event emitted when a gadget is skipped due to a failed dependency */
3753
+ interface GadgetSkippedEvent {
3754
+ type: "gadget_skipped";
3755
+ gadgetName: string;
3756
+ invocationId: string;
3757
+ parameters: Record<string, unknown>;
3758
+ /** The invocation ID of the dependency that failed */
3759
+ failedDependency: string;
3760
+ /** The error message from the failed dependency */
3761
+ failedDependencyError: string;
3762
+ }
3763
+ /**
3764
+ * Event emitted when stream processing completes, containing metadata.
3765
+ * This allows the async generator to "return" metadata while still yielding events.
3766
+ */
3767
+ interface StreamCompletionEvent {
3768
+ type: "stream_complete";
3769
+ /** The reason the LLM stopped generating (e.g., "stop", "tool_use") */
3770
+ finishReason: string | null;
3771
+ /** Token usage statistics from the LLM call */
3772
+ usage?: TokenUsage;
3773
+ /** Raw response text from the LLM */
3774
+ rawResponse: string;
3775
+ /** Final message after all interceptors applied */
3776
+ finalMessage: string;
3777
+ /** Whether any gadgets were executed during this iteration */
3778
+ didExecuteGadgets: boolean;
3779
+ /** Whether to break the agent loop (e.g., TaskComplete was called) */
3780
+ shouldBreakLoop: boolean;
3781
+ /** Accumulated thinking/reasoning content from reasoning models */
3782
+ thinkingContent?: string;
3783
+ }
3784
+ type StreamEvent = {
3785
+ type: "text";
3786
+ content: string;
3787
+ } | {
3788
+ type: "thinking";
3789
+ content: string;
3790
+ thinkingType: "thinking" | "redacted";
3791
+ } | {
3792
+ type: "gadget_call";
3793
+ call: ParsedGadgetCall;
3794
+ } | {
3795
+ type: "gadget_result";
3796
+ result: GadgetExecutionResult;
3797
+ } | GadgetSkippedEvent | {
3798
+ type: "human_input_required";
3799
+ question: string;
3800
+ gadgetName: string;
3801
+ invocationId: string;
3802
+ } | {
3803
+ type: "compaction";
3804
+ event: CompactionEvent;
3805
+ } | {
3806
+ type: "llm_response_end";
3807
+ finishReason: string | null;
3808
+ usage?: TokenUsage;
3809
+ } | StreamCompletionEvent;
3810
+
3811
+ /**
3812
+ * Text-only response handler types.
3743
3813
  *
3744
- * This ensures external gadgets use the same class instances as the host CLI,
3745
- * enabling proper tree sharing and avoiding the "dual-package problem" where
3746
- * different versions of llmist have incompatible classes.
3814
+ * Defines the handler configuration for when the LLM returns a text-only response
3815
+ * (no gadget calls). Supports simple strategies, gadget triggers, and custom handlers.
3816
+ *
3817
+ * @module
3747
3818
  */
3748
- interface HostExports {
3749
- /** AgentBuilder for creating subagents with proper tree sharing */
3750
- AgentBuilder: typeof AgentBuilder;
3751
- /** Gadget factory for defining gadgets */
3752
- Gadget: typeof Gadget;
3753
- /** createGadget for functional gadget definitions */
3754
- createGadget: typeof createGadget;
3755
- /** ExecutionTree for tree operations */
3756
- ExecutionTree: typeof ExecutionTree;
3757
- /** LLMist client */
3758
- LLMist: typeof LLMist;
3759
- /** Zod schema builder */
3760
- z: typeof zod.z;
3761
- }
3819
+
3820
+ type TextOnlyHandler = TextOnlyStrategy | TextOnlyGadgetConfig | TextOnlyCustomHandler;
3762
3821
  /**
3763
- * Parent agent configuration passed to gadgets.
3764
- * Contains settings that subagents can inherit.
3822
+ * Simple strategies for common cases
3823
+ * - 'terminate': End the loop (default behavior)
3824
+ * - 'acknowledge': Continue to next iteration
3825
+ * - 'wait_for_input': Request human input
3765
3826
  */
3766
- interface AgentContextConfig {
3767
- /** Model identifier used by the parent agent */
3768
- model: string;
3769
- /** Temperature setting used by the parent agent */
3770
- temperature?: number;
3771
- }
3827
+ type TextOnlyStrategy = "terminate" | "acknowledge" | "wait_for_input";
3772
3828
  /**
3773
- * Configuration for a single subagent.
3774
- * Can be defined globally in `[subagents.Name]` or per-profile in `[profile.subagents.Name]`.
3775
- *
3776
- * @example
3777
- * ```toml
3778
- * [subagents.BrowseWeb]
3779
- * model = "inherit" # Use parent agent's model
3780
- * maxIterations = 20
3781
- * headless = true
3782
- * ```
3829
+ * Configuration for triggering a gadget when receiving text-only response
3783
3830
  */
3784
- interface SubagentConfig {
3785
- /**
3786
- * Model to use for this subagent.
3787
- * - "inherit": Use parent agent's model (default behavior)
3788
- * - Any model ID: Use specific model (e.g., "sonnet", "haiku", "gpt-4o")
3789
- */
3790
- model?: string;
3791
- /** Maximum iterations for the subagent loop */
3792
- maxIterations?: number;
3793
- /** Budget limit in USD for the subagent */
3794
- budget?: number;
3795
- /**
3796
- * Timeout for the subagent gadget execution in milliseconds.
3797
- * Overrides the gadget's hardcoded timeoutMs when set.
3798
- * Set to 0 to disable timeout for this gadget.
3799
- */
3800
- timeoutMs?: number;
3831
+ interface TextOnlyGadgetConfig {
3832
+ type: "gadget";
3833
+ name: string;
3801
3834
  /**
3802
- * Maximum number of concurrent executions allowed for this gadget.
3803
- * When the limit is reached, additional calls are queued and processed
3804
- * as earlier executions complete (FIFO order).
3805
- * Set to 0 or omit to allow unlimited concurrent executions (default).
3835
+ * Optional function to map text to gadget parameters.
3836
+ * If not provided, text will be passed as { text: string }
3806
3837
  */
3807
- maxConcurrent?: number;
3808
- /** Additional subagent-specific options */
3809
- [key: string]: unknown;
3838
+ parameterMapping?: (text: string) => Record<string, unknown>;
3810
3839
  }
3811
3840
  /**
3812
- * Map of subagent names to their configurations.
3841
+ * Custom handler for complex text-only response scenarios
3813
3842
  */
3814
- type SubagentConfigMap = Record<string, SubagentConfig>;
3843
+ interface TextOnlyCustomHandler {
3844
+ type: "custom";
3845
+ handler: (context: TextOnlyContext) => Promise<TextOnlyAction> | TextOnlyAction;
3846
+ }
3815
3847
  /**
3816
- * Gadget execution mode controlling how multiple gadgets are executed.
3817
- *
3818
- * - `'parallel'` (default): Gadgets without dependencies execute concurrently (fire-and-forget).
3819
- * This maximizes throughput but gadgets may complete in any order.
3820
- *
3821
- * - `'sequential'`: Gadgets execute one at a time, each awaiting completion before the next starts.
3822
- * Useful for:
3823
- * - Gadgets with implicit ordering dependencies (e.g., file operations)
3824
- * - Debugging and tracing execution flow
3825
- * - Resource-constrained environments
3826
- * - Ensuring deterministic execution order
3827
- *
3828
- * Note: Explicit `dependsOn` relationships are always respected regardless of mode.
3829
- * Sequential mode effectively enforces a global `maxConcurrent: 1` for all gadgets.
3830
- *
3831
- * @example
3832
- * ```typescript
3833
- * const agent = LLMist.createAgent()
3834
- * .withModel("sonnet")
3835
- * .withGadgets(FileReader, FileWriter)
3836
- * .withGadgetExecutionMode('sequential') // Execute one at a time
3837
- * .ask("Process files in order");
3838
- * ```
3848
+ * Context provided to custom text-only handlers
3839
3849
  */
3840
- type GadgetExecutionMode = "parallel" | "sequential";
3850
+ interface TextOnlyContext {
3851
+ /** The complete text response from the LLM */
3852
+ text: string;
3853
+ /** Current iteration number */
3854
+ iteration: number;
3855
+ /** Full conversation history */
3856
+ conversation: LLMMessage[];
3857
+ /** Logger instance */
3858
+ logger: Logger<ILogObj>;
3859
+ }
3860
+ /**
3861
+ * Actions that can be returned by text-only handlers
3862
+ */
3863
+ type TextOnlyAction = {
3864
+ action: "continue";
3865
+ } | {
3866
+ action: "terminate";
3867
+ } | {
3868
+ action: "wait_for_input";
3869
+ question?: string;
3870
+ } | {
3871
+ action: "trigger_gadget";
3872
+ name: string;
3873
+ parameters: Record<string, unknown>;
3874
+ };
3841
3875
 
3842
3876
  /**
3843
3877
  * Abstract base class for gadgets. Most users should use the `Gadget()` factory
@@ -4041,12 +4075,6 @@ declare abstract class AbstractGadget {
4041
4075
  * ```
4042
4076
  */
4043
4077
  createLinkedAbortController(ctx?: ExecutionContext): AbortController;
4044
- /**
4045
- * Auto-generated instruction text for the LLM.
4046
- * Combines name, description, and parameter schema into a formatted instruction.
4047
- * @deprecated Use getInstruction() instead
4048
- */
4049
- get instruction(): string;
4050
4078
  /**
4051
4079
  * Generate instruction text for the LLM.
4052
4080
  * Combines name, description, and parameter schema into a formatted instruction.
@@ -4570,6 +4598,29 @@ declare class GadgetRegistry {
4570
4598
  clear(): void;
4571
4599
  }
4572
4600
 
4601
+ /**
4602
+ * Context available to trailing message functions.
4603
+ * Provides iteration information for dynamic message generation.
4604
+ */
4605
+ type TrailingMessageContext = Pick<LLMCallControllerContext, "iteration" | "maxIterations" | "budget" | "totalCost">;
4606
+ /**
4607
+ * Trailing message can be a static string or a function that generates the message.
4608
+ * The function receives context about the current iteration.
4609
+ */
4610
+ type TrailingMessage = string | ((ctx: TrailingMessageContext) => string);
4611
+
4612
+ /**
4613
+ * Message for conversation history.
4614
+ * User messages can be text (string) or multimodal (ContentPart[]).
4615
+ */
4616
+ type HistoryMessage = {
4617
+ user: string | ContentPart[];
4618
+ } | {
4619
+ assistant: string;
4620
+ } | {
4621
+ system: string;
4622
+ };
4623
+
4573
4624
  /**
4574
4625
  * Event handler sugar for cleaner event processing.
4575
4626
  *
@@ -4681,43 +4732,8 @@ declare function collectText(agentGenerator: AsyncGenerator<StreamEvent>): Promi
4681
4732
 
4682
4733
  /**
4683
4734
  * Fluent builder for creating agents with delightful DX.
4684
- *
4685
- * @example
4686
- * ```typescript
4687
- * const agent = await LLMist.createAgent()
4688
- * .withModel("sonnet")
4689
- * .withSystem("You are a helpful assistant")
4690
- * .withGadgets(Calculator, Weather)
4691
- * .withMaxIterations(10)
4692
- * .ask("What's the weather in Paris?");
4693
- *
4694
- * for await (const event of agent.run()) {
4695
- * // process events
4696
- * }
4697
- * ```
4698
4735
  */
4699
4736
 
4700
- /**
4701
- * Message for conversation history.
4702
- * User messages can be text (string) or multimodal (ContentPart[]).
4703
- */
4704
- type HistoryMessage = {
4705
- user: string | ContentPart[];
4706
- } | {
4707
- assistant: string;
4708
- } | {
4709
- system: string;
4710
- };
4711
- /**
4712
- * Context available to trailing message functions.
4713
- * Provides iteration information for dynamic message generation.
4714
- */
4715
- type TrailingMessageContext = Pick<LLMCallControllerContext, "iteration" | "maxIterations" | "budget" | "totalCost">;
4716
- /**
4717
- * Trailing message can be a static string or a function that generates the message.
4718
- * The function receives context about the current iteration.
4719
- */
4720
- type TrailingMessage = string | ((ctx: TrailingMessageContext) => string);
4721
4737
  /**
4722
4738
  * Fluent builder for creating agents.
4723
4739
  *
@@ -4725,921 +4741,105 @@ type TrailingMessage = string | ((ctx: TrailingMessageContext) => string);
4725
4741
  * making the code more expressive and easier to read.
4726
4742
  */
4727
4743
  declare class AgentBuilder {
4728
- private client?;
4729
- private model?;
4730
- private systemPrompt?;
4731
- private temperature?;
4732
- private maxIterations?;
4733
- private budget?;
4734
- private logger?;
4735
- private hooks?;
4736
- private promptConfig?;
4744
+ private core;
4737
4745
  private gadgets;
4738
- private initialMessages;
4739
- private requestHumanInput?;
4740
- private gadgetStartPrefix?;
4741
- private gadgetEndPrefix?;
4742
- private gadgetArgPrefix?;
4743
- private textOnlyHandler?;
4744
- private textWithGadgetsHandler?;
4745
- private defaultGadgetTimeoutMs?;
4746
- private gadgetExecutionMode?;
4747
- private maxGadgetsPerResponse?;
4748
- private gadgetOutputLimit?;
4749
- private gadgetOutputLimitPercent?;
4750
- private compactionConfig?;
4751
- private retryConfig?;
4752
- private rateLimitConfig?;
4753
- private signal?;
4754
- private trailingMessage?;
4755
- private subagentConfig?;
4756
- private parentContext?;
4757
- private parentObservers?;
4758
- private sharedRateLimitTracker?;
4759
- private sharedRetryConfig?;
4760
- private reasoningConfig?;
4761
- private cachingConfig?;
4762
- constructor(client?: LLMist);
4763
- /**
4764
- * Set the model to use.
4765
- * Supports aliases like "gpt4", "sonnet", "flash".
4766
- *
4767
- * @param model - Model name or alias
4768
- * @returns This builder for chaining
4769
- *
4770
- * @example
4771
- * ```typescript
4772
- * .withModel("sonnet") // Alias
4773
- * .withModel("gpt-5-nano") // Auto-detects provider
4774
- * .withModel("openai:gpt-5") // Explicit provider
4775
- * ```
4776
- */
4777
- withModel(model: string): this;
4778
- /**
4779
- * Set the system prompt.
4780
- *
4781
- * @param prompt - System prompt
4782
- * @returns This builder for chaining
4783
- */
4784
- withSystem(prompt: string): this;
4785
- /**
4786
- * Set the temperature (0-1).
4787
- *
4788
- * @param temperature - Temperature value
4789
- * @returns This builder for chaining
4790
- */
4791
- withTemperature(temperature: number): this;
4792
- /**
4793
- * Set maximum iterations.
4794
- *
4795
- * @param max - Maximum number of iterations
4796
- * @returns This builder for chaining
4797
- */
4798
- withMaxIterations(max: number): this;
4799
- /**
4800
- * Set the budget limit in USD.
4801
- * The agent loop stops when cumulative cost reaches this limit.
4802
- *
4803
- * @param amountUSD - Maximum spend in USD
4804
- * @returns This builder for chaining
4805
- *
4806
- * @example
4807
- * ```typescript
4808
- * .withBudget(0.50) // Stop after $0.50 spent
4809
- * ```
4810
- */
4811
- withBudget(amountUSD: number): this;
4812
- /**
4813
- * Set logger instance.
4814
- *
4815
- * @param logger - Logger instance
4816
- * @returns This builder for chaining
4817
- */
4818
- withLogger(logger: Logger<ILogObj>): this;
4819
- /**
4820
- * Add hooks for agent lifecycle events.
4821
- *
4822
- * @param hooks - Agent hooks configuration
4823
- * @returns This builder for chaining
4824
- *
4825
- * @example
4826
- * ```typescript
4827
- * import { HookPresets } from 'llmist/hooks';
4828
- *
4829
- * .withHooks(HookPresets.logging())
4830
- * .withHooks(HookPresets.merge(
4831
- * HookPresets.logging(),
4832
- * HookPresets.timing()
4833
- * ))
4834
- * ```
4835
- */
4746
+ private retry;
4747
+ private subagents;
4748
+ private policies;
4749
+ constructor(client?: LLMist);
4750
+ /** Set the model to use. Supports aliases like "sonnet", "flash". */
4751
+ withModel(model: string): this;
4752
+ /** Set the system prompt. */
4753
+ withSystem(prompt: string): this;
4754
+ /** Set the temperature (0-1). */
4755
+ withTemperature(temperature: number): this;
4756
+ /** Set maximum iterations. */
4757
+ withMaxIterations(max: number): this;
4758
+ /** Set the budget limit in USD. */
4759
+ withBudget(amountUSD: number): this;
4760
+ /** Set logger instance. */
4761
+ withLogger(logger: Logger<ILogObj>): this;
4762
+ /** Add hooks for agent lifecycle events. */
4836
4763
  withHooks(hooks: AgentHooks): this;
4837
- /**
4838
- * Configure custom prompts for gadget system messages.
4839
- *
4840
- * @param config - Prompt configuration object
4841
- * @returns This builder for chaining
4842
- *
4843
- * @example
4844
- * ```typescript
4845
- * .withPromptTemplateConfig({
4846
- * mainInstruction: "Use the gadget markers below:",
4847
- * rules: ["Always use markers", "Never use function calling"]
4848
- * })
4849
- * ```
4850
- */
4764
+ /** Configure custom prompts for gadget system messages. */
4851
4765
  withPromptTemplateConfig(config: PromptTemplateConfig): this;
4852
- /**
4853
- * Add gadgets (classes or instances).
4854
- * Can be called multiple times to add more gadgets.
4855
- *
4856
- * @param gadgets - Gadget classes or instances
4857
- * @returns This builder for chaining
4858
- *
4859
- * @example
4860
- * ```typescript
4861
- * .withGadgets(Calculator, Weather, Email)
4862
- * .withGadgets(new Calculator(), new Weather())
4863
- * .withGadgets(createGadget({ ... }))
4864
- * ```
4865
- */
4766
+ /** Add gadgets (classes or instances). */
4866
4767
  withGadgets(...gadgets: GadgetOrClass[]): this;
4867
- /**
4868
- * Add conversation history messages.
4869
- * Useful for continuing previous conversations.
4870
- *
4871
- * @param messages - Array of history messages
4872
- * @returns This builder for chaining
4873
- *
4874
- * @example
4875
- * ```typescript
4876
- * .withHistory([
4877
- * { user: "Hello" },
4878
- * { assistant: "Hi there!" },
4879
- * { user: "How are you?" },
4880
- * { assistant: "I'm doing well, thanks!" }
4881
- * ])
4882
- * ```
4883
- */
4768
+ /** Add conversation history messages. */
4884
4769
  withHistory(messages: HistoryMessage[]): this;
4885
- /**
4886
- * Add a single message to the conversation history.
4887
- *
4888
- * @param message - Single history message
4889
- * @returns This builder for chaining
4890
- *
4891
- * @example
4892
- * ```typescript
4893
- * .addMessage({ user: "Hello" })
4894
- * .addMessage({ assistant: "Hi there!" })
4895
- * ```
4896
- */
4770
+ /** Add a single message to the conversation history. */
4897
4771
  addMessage(message: HistoryMessage): this;
4898
- /**
4899
- * Clear any previously set conversation history.
4900
- * Used before setting new cumulative history in REPL mode.
4901
- *
4902
- * @returns This builder for chaining
4903
- *
4904
- * @example
4905
- * ```typescript
4906
- * // Reset history before setting new cumulative history
4907
- * builder.clearHistory().withHistory(cumulativeHistory);
4908
- * ```
4909
- */
4772
+ /** Clear any previously set conversation history. */
4910
4773
  clearHistory(): this;
4911
- /**
4912
- * Continue conversation from a previous agent's history.
4913
- * Extracts full conversation history and sets it as initial messages.
4914
- *
4915
- * This is the recommended way to implement REPL session continuation.
4916
- * It automatically handles history extraction and format conversion.
4917
- *
4918
- * @param agent - The previous agent to continue from
4919
- * @returns This builder for chaining
4920
- *
4921
- * @example
4922
- * ```typescript
4923
- * // REPL loop with session continuity
4924
- * let previousAgent: Agent | null = null;
4925
- *
4926
- * while (true) {
4927
- * if (previousAgent) {
4928
- * builder.continueFrom(previousAgent);
4929
- * }
4930
- * const agent = builder.ask(prompt);
4931
- * await runAgent(agent);
4932
- * previousAgent = agent;
4933
- * }
4934
- * ```
4935
- */
4774
+ /** Continue conversation from a previous agent's history. */
4936
4775
  continueFrom(agent: Agent): this;
4937
- /**
4938
- * Set the human input handler for interactive conversations.
4939
- *
4940
- * @param handler - Function to handle human input requests
4941
- * @returns This builder for chaining
4942
- *
4943
- * @example
4944
- * ```typescript
4945
- * .onHumanInput(async (question) => {
4946
- * return await promptUser(question);
4947
- * })
4948
- * ```
4949
- */
4776
+ /** Set the human input handler for interactive conversations. */
4950
4777
  onHumanInput(handler: (question: string) => Promise<string>): this;
4951
- /**
4952
- * Set custom gadget marker prefix.
4953
- *
4954
- * @param prefix - Custom start prefix for gadget markers
4955
- * @returns This builder for chaining
4956
- *
4957
- * @example
4958
- * ```typescript
4959
- * .withGadgetStartPrefix("<<GADGET_START>>")
4960
- * ```
4961
- */
4778
+ /** Set custom gadget marker prefix. */
4962
4779
  withGadgetStartPrefix(prefix: string): this;
4963
- /**
4964
- * Set custom gadget marker suffix.
4965
- *
4966
- * @param suffix - Custom end suffix for gadget markers
4967
- * @returns This builder for chaining
4968
- *
4969
- * @example
4970
- * ```typescript
4971
- * .withGadgetEndPrefix("<<GADGET_END>>")
4972
- * ```
4973
- */
4780
+ /** Set custom gadget marker suffix. */
4974
4781
  withGadgetEndPrefix(suffix: string): this;
4975
- /**
4976
- * Set custom argument prefix for block format parameters.
4977
- *
4978
- * @param prefix - Custom prefix for argument markers (default: "!!!ARG:")
4979
- * @returns This builder for chaining
4980
- *
4981
- * @example
4982
- * ```typescript
4983
- * .withGadgetArgPrefix("<<ARG>>")
4984
- * ```
4985
- */
4782
+ /** Set custom argument prefix for block format parameters. */
4986
4783
  withGadgetArgPrefix(prefix: string): this;
4987
- /**
4988
- * Set the text-only handler strategy.
4989
- *
4990
- * Controls what happens when the LLM returns text without calling any gadgets:
4991
- * - "terminate": End the agent loop (default)
4992
- * - "acknowledge": Continue the loop for another iteration
4993
- * - "wait_for_input": Wait for human input
4994
- * - Custom handler: Provide a function for dynamic behavior
4995
- *
4996
- * @param handler - Text-only handler strategy or custom handler
4997
- * @returns This builder for chaining
4998
- *
4999
- * @example
5000
- * ```typescript
5001
- * // Simple strategy
5002
- * .withTextOnlyHandler("acknowledge")
5003
- *
5004
- * // Custom handler
5005
- * .withTextOnlyHandler({
5006
- * type: "custom",
5007
- * handler: async (context) => {
5008
- * if (context.text.includes("?")) {
5009
- * return { action: "wait_for_input", question: context.text };
5010
- * }
5011
- * return { action: "continue" };
5012
- * }
5013
- * })
5014
- * ```
5015
- */
4784
+ /** Set the text-only handler strategy. */
5016
4785
  withTextOnlyHandler(handler: TextOnlyHandler): this;
5017
- /**
5018
- * Set the handler for text content that appears alongside gadget calls.
5019
- *
5020
- * When set, text accompanying gadget responses will be wrapped as a
5021
- * synthetic gadget call before the actual gadget results in the
5022
- * conversation history.
5023
- *
5024
- * @param handler - Configuration for wrapping text
5025
- * @returns This builder for chaining
5026
- *
5027
- * @example
5028
- * ```typescript
5029
- * // Wrap text as TellUser gadget
5030
- * .withTextWithGadgetsHandler({
5031
- * gadgetName: "TellUser",
5032
- * parameterMapping: (text) => ({ message: text, done: false, type: "info" }),
5033
- * resultMapping: (text) => `ℹ️ ${text}`,
5034
- * })
5035
- * ```
5036
- */
4786
+ /** Set the handler for text content that appears alongside gadget calls. */
5037
4787
  withTextWithGadgetsHandler(handler: {
5038
4788
  gadgetName: string;
5039
4789
  parameterMapping: (text: string) => Record<string, unknown>;
5040
4790
  resultMapping?: (text: string) => string;
5041
4791
  }): this;
5042
- /**
5043
- * Set default timeout for gadget execution.
5044
- *
5045
- * @param timeoutMs - Timeout in milliseconds (must be non-negative)
5046
- * @returns This builder for chaining
5047
- * @throws {Error} If timeout is negative
5048
- *
5049
- * @example
5050
- * ```typescript
5051
- * .withDefaultGadgetTimeout(5000) // 5 second timeout
5052
- * ```
5053
- */
4792
+ /** Set default timeout for gadget execution. */
5054
4793
  withDefaultGadgetTimeout(timeoutMs: number): this;
5055
- /**
5056
- * Set the gadget execution mode.
5057
- *
5058
- * Controls how multiple gadgets are executed when the LLM calls them:
5059
- * - `'parallel'` (default): Gadgets without dependencies execute concurrently
5060
- * - `'sequential'`: Gadgets execute one at a time, each awaiting completion
5061
- *
5062
- * @param mode - Execution mode ('parallel' or 'sequential')
5063
- * @returns This builder for chaining
5064
- *
5065
- * @example
5066
- * ```typescript
5067
- * // Sequential execution for ordered file operations
5068
- * .withGadgetExecutionMode('sequential')
5069
- *
5070
- * // Parallel execution (default) for independent operations
5071
- * .withGadgetExecutionMode('parallel')
5072
- * ```
5073
- */
4794
+ /** Set the gadget execution mode ('parallel' or 'sequential'). */
5074
4795
  withGadgetExecutionMode(mode: GadgetExecutionMode): this;
5075
- /**
5076
- * Set the maximum number of gadgets to execute per LLM response.
5077
- *
5078
- * When the limit is reached, remaining gadgets are skipped with an informative
5079
- * message visible to the LLM, allowing it to adjust on the next iteration.
5080
- * Gadgets already in-flight (executing in parallel) are allowed to complete.
5081
- *
5082
- * @param max - Maximum gadgets per response (0 = unlimited, default)
5083
- * @returns This builder for chaining
5084
- * @throws {Error} If max is negative or non-integer
5085
- *
5086
- * @example
5087
- * ```typescript
5088
- * // Limit to 5 gadgets per response
5089
- * LLMist.createAgent()
5090
- * .withModel("sonnet")
5091
- * .withGadgets(ReadFile, WriteFile, Search)
5092
- * .withMaxGadgetsPerResponse(5)
5093
- * .ask("Process these files...");
5094
- * ```
5095
- */
4796
+ /** Set the maximum number of gadgets to execute per LLM response. */
5096
4797
  withMaxGadgetsPerResponse(max: number): this;
5097
- /**
5098
- * Enable or disable gadget output limiting.
5099
- *
5100
- * When enabled, gadget outputs exceeding the configured limit are stored
5101
- * and can be browsed using the GadgetOutputViewer gadget.
5102
- *
5103
- * @param enabled - Whether to enable output limiting (default: true)
5104
- * @returns This builder for chaining
5105
- *
5106
- * @example
5107
- * ```typescript
5108
- * .withGadgetOutputLimit(false) // Disable output limiting
5109
- * ```
5110
- */
4798
+ /** Enable or disable gadget output limiting. */
5111
4799
  withGadgetOutputLimit(enabled: boolean): this;
5112
- /**
5113
- * Set the maximum gadget output as a percentage of the model's context window.
5114
- *
5115
- * Outputs exceeding this limit are stored for later browsing with GadgetOutputViewer.
5116
- *
5117
- * @param percent - Percentage of context window (1-100, default: 15)
5118
- * @returns This builder for chaining
5119
- * @throws {Error} If percent is not between 1 and 100
5120
- *
5121
- * @example
5122
- * ```typescript
5123
- * .withGadgetOutputLimitPercent(25) // 25% of context window
5124
- * ```
5125
- */
4800
+ /** Set the maximum gadget output as a percentage of the context window. */
5126
4801
  withGadgetOutputLimitPercent(percent: number): this;
5127
- /**
5128
- * Configure context compaction.
5129
- *
5130
- * Context compaction automatically manages conversation history to prevent
5131
- * context window overflow in long-running agent conversations.
5132
- *
5133
- * @param config - Compaction configuration options
5134
- * @returns This builder for chaining
5135
- *
5136
- * @example
5137
- * ```typescript
5138
- * // Custom thresholds
5139
- * .withCompaction({
5140
- * triggerThresholdPercent: 70,
5141
- * targetPercent: 40,
5142
- * preserveRecentTurns: 10,
5143
- * })
5144
- *
5145
- * // Different strategy
5146
- * .withCompaction({
5147
- * strategy: 'sliding-window',
5148
- * })
5149
- *
5150
- * // With callback
5151
- * .withCompaction({
5152
- * onCompaction: (event) => {
5153
- * console.log(`Saved ${event.tokensBefore - event.tokensAfter} tokens`);
5154
- * }
5155
- * })
5156
- * ```
5157
- */
4802
+ /** Configure context compaction. */
5158
4803
  withCompaction(config: CompactionConfig): this;
5159
- /**
5160
- * Disable context compaction.
5161
- *
5162
- * By default, compaction is enabled. Use this method to explicitly disable it.
5163
- *
5164
- * @returns This builder for chaining
5165
- *
5166
- * @example
5167
- * ```typescript
5168
- * .withoutCompaction() // Disable automatic compaction
5169
- * ```
5170
- */
4804
+ /** Disable context compaction. */
5171
4805
  withoutCompaction(): this;
5172
- /**
5173
- * Configure retry behavior for LLM API calls.
5174
- *
5175
- * Retry is enabled by default with conservative settings (3 retries, exponential backoff).
5176
- * Use this method to customize retry behavior for rate limits, timeouts, and transient errors.
5177
- *
5178
- * @param config - Retry configuration options
5179
- * @returns This builder for chaining
5180
- *
5181
- * @example
5182
- * ```typescript
5183
- * // Custom retry configuration
5184
- * .withRetry({
5185
- * retries: 5,
5186
- * minTimeout: 2000,
5187
- * maxTimeout: 60000,
5188
- * })
5189
- *
5190
- * // With monitoring callbacks
5191
- * .withRetry({
5192
- * onRetry: (error, attempt) => {
5193
- * console.log(`Retry ${attempt}: ${error.message}`);
5194
- * },
5195
- * onRetriesExhausted: (error, attempts) => {
5196
- * alerting.warn(`Failed after ${attempts} attempts`);
5197
- * }
5198
- * })
5199
- *
5200
- * // Custom retry logic
5201
- * .withRetry({
5202
- * shouldRetry: (error) => error.message.includes('429'),
5203
- * })
5204
- * ```
5205
- */
4806
+ /** Configure retry behavior for LLM API calls. */
5206
4807
  withRetry(config: RetryConfig): this;
5207
- /**
5208
- * Disable automatic retry for LLM API calls.
5209
- *
5210
- * By default, retry is enabled. Use this method to explicitly disable it.
5211
- *
5212
- * @returns This builder for chaining
5213
- *
5214
- * @example
5215
- * ```typescript
5216
- * .withoutRetry() // Disable automatic retry
5217
- * ```
5218
- */
4808
+ /** Disable automatic retry for LLM API calls. */
5219
4809
  withoutRetry(): this;
5220
- /**
5221
- * Configure proactive rate limiting to prevent rate limit errors.
5222
- *
5223
- * Set limits based on your API tier to automatically throttle requests
5224
- * before hitting provider limits. Works in conjunction with reactive
5225
- * retry/backoff for comprehensive rate limit handling.
5226
- *
5227
- * @param config - Rate limit configuration
5228
- * @returns This builder for chaining
5229
- *
5230
- * @example
5231
- * ```typescript
5232
- * // Gemini free tier limits
5233
- * .withRateLimits({
5234
- * requestsPerMinute: 15,
5235
- * tokensPerMinute: 1_000_000,
5236
- * safetyMargin: 0.8, // Start throttling at 80%
5237
- * })
5238
- *
5239
- * // OpenAI Tier 1 limits
5240
- * .withRateLimits({
5241
- * requestsPerMinute: 500,
5242
- * tokensPerMinute: 200_000,
5243
- * })
5244
- *
5245
- * // With daily limit (Gemini free tier)
5246
- * .withRateLimits({
5247
- * requestsPerMinute: 15,
5248
- * tokensPerDay: 1_500_000,
5249
- * })
5250
- * ```
5251
- */
4810
+ /** Configure proactive rate limiting to prevent rate limit errors. */
5252
4811
  withRateLimits(config: RateLimitConfig): this;
5253
- /**
5254
- * Set an abort signal for cancelling requests mid-flight.
5255
- *
5256
- * When the signal is aborted, the current LLM request will be cancelled
5257
- * and the agent loop will exit gracefully.
5258
- *
5259
- * @param signal - AbortSignal from an AbortController
5260
- * @returns This builder for chaining
5261
- *
5262
- * @example
5263
- * ```typescript
5264
- * const controller = new AbortController();
5265
- *
5266
- * // Cancel after 30 seconds
5267
- * setTimeout(() => controller.abort(), 30000);
5268
- *
5269
- * const agent = LLMist.createAgent()
5270
- * .withModel("sonnet")
5271
- * .withSignal(controller.signal)
5272
- * .ask("Write a long story");
5273
- *
5274
- * // Or cancel on user action
5275
- * document.getElementById("cancel").onclick = () => controller.abort();
5276
- * ```
5277
- */
4812
+ /** Set an abort signal for cancelling requests mid-flight. */
5278
4813
  withSignal(signal: AbortSignal): this;
5279
- /**
5280
- * Enable reasoning/thinking mode for reasoning-capable models.
5281
- *
5282
- * Can be called with:
5283
- * - No args: enables reasoning at "medium" effort
5284
- * - A string effort level: `withReasoning("high")`
5285
- * - A full config object: `withReasoning({ enabled: true, budgetTokens: 10000 })`
5286
- *
5287
- * @param config - Optional effort level or full reasoning config
5288
- * @returns This builder for chaining
5289
- *
5290
- * @example
5291
- * ```typescript
5292
- * // Simple — medium effort
5293
- * LLMist.createAgent()
5294
- * .withModel("o3")
5295
- * .withReasoning()
5296
- * .ask("Solve this logic puzzle...");
5297
- *
5298
- * // Explicit effort level
5299
- * LLMist.createAgent()
5300
- * .withModel("anthropic:claude-4-opus")
5301
- * .withReasoning("high")
5302
- * .ask("Analyze this complex problem");
5303
- *
5304
- * // Full config with explicit token budget
5305
- * LLMist.createAgent()
5306
- * .withModel("anthropic:claude-4-opus")
5307
- * .withReasoning({ enabled: true, budgetTokens: 16000 })
5308
- * .ask("Step through this proof");
5309
- * ```
5310
- */
4814
+ /** Enable reasoning/thinking mode for reasoning-capable models. */
5311
4815
  withReasoning(config?: ReasoningConfig | ReasoningEffort): this;
5312
- /**
5313
- * Explicitly disable reasoning for this agent, even if the model supports it.
5314
- *
5315
- * By default, reasoning is auto-enabled at "medium" effort for models with
5316
- * `features.reasoning: true`. Use this to opt out.
5317
- *
5318
- * @returns This builder for chaining
5319
- */
4816
+ /** Explicitly disable reasoning for this agent. */
5320
4817
  withoutReasoning(): this;
5321
- /**
5322
- * Enable context caching for supported providers.
5323
- *
5324
- * Can be called with:
5325
- * - No args: enables caching with defaults (`{ enabled: true }`)
5326
- * - A full config object: `withCaching({ enabled: true, scope: "system", ttl: "7200s" })`
5327
- *
5328
- * Provider behavior:
5329
- * - **Anthropic**: Caching is always-on by default via `cache_control` markers.
5330
- * Calling `withCaching()` explicitly is a no-op (it's already enabled).
5331
- * - **Gemini**: Creates an explicit cache via `caches.create()` for the configured scope.
5332
- * - **OpenAI**: Server-side automatic caching (no-op).
5333
- *
5334
- * @param config - Optional caching configuration
5335
- * @returns This builder for chaining
5336
- *
5337
- * @example
5338
- * ```typescript
5339
- * // Simple — enable with defaults
5340
- * LLMist.createAgent()
5341
- * .withModel("gemini:gemini-2.5-flash")
5342
- * .withCaching()
5343
- * .ask("Analyze this large codebase...");
5344
- *
5345
- * // Cache only system prompt with longer TTL
5346
- * LLMist.createAgent()
5347
- * .withModel("gemini:gemini-2.5-pro")
5348
- * .withCaching({ enabled: true, scope: "system", ttl: "7200s" })
5349
- * .ask("...");
5350
- * ```
5351
- */
4818
+ /** Enable context caching for supported providers. */
5352
4819
  withCaching(config?: CachingConfig): this;
5353
- /**
5354
- * Explicitly disable context caching.
5355
- *
5356
- * For Anthropic, this removes `cache_control` markers from requests,
5357
- * opting out of prompt caching entirely.
5358
- *
5359
- * @returns This builder for chaining
5360
- *
5361
- * @example
5362
- * ```typescript
5363
- * // Disable Anthropic's automatic caching
5364
- * LLMist.createAgent()
5365
- * .withModel("sonnet")
5366
- * .withoutCaching()
5367
- * .ask("...");
5368
- * ```
5369
- */
5370
- withoutCaching(): this;
5371
- /**
5372
- * Set subagent configuration overrides.
5373
- *
5374
- * Subagent gadgets (like BrowseWeb) can read these settings from ExecutionContext
5375
- * to inherit model and other options from the CLI configuration.
5376
- *
5377
- * @param config - Subagent configuration map keyed by gadget name
5378
- * @returns This builder for chaining
5379
- *
5380
- * @example
5381
- * ```typescript
5382
- * .withSubagentConfig({
5383
- * BrowseWeb: { model: "inherit", maxIterations: 20, headless: true },
5384
- * CodeAnalyzer: { model: "sonnet", maxIterations: 10 }
5385
- * })
5386
- * ```
5387
- */
4820
+ /** Explicitly disable context caching. */
4821
+ withoutCaching(): this;
4822
+ /** Set subagent configuration overrides. */
5388
4823
  withSubagentConfig(config: SubagentConfigMap): this;
5389
- /**
5390
- * Share parent agent's ExecutionTree for unified event visibility.
5391
- *
5392
- * When building a subagent inside a gadget, call this method to share the
5393
- * parent's ExecutionTree. This is the **single source of truth** for all
5394
- * execution events, enabling:
5395
- *
5396
- * - **Unified cost tracking** - All nested agent costs aggregate automatically
5397
- * - **Real-time visibility** - Parent's `tree.onAll()` subscribers see all events
5398
- * - **Depth tracking** - Events have correct `depth` (1 for child, 2 for grandchild, etc.)
5399
- * - **Parent linking** - Events have `parentId` pointing to spawning gadget
5400
- * - **Media aggregation** - Use `tree.getSubtreeMedia(nodeId)` after completion
5401
- *
5402
- * **Signal Forwarding** - When parent context includes a signal, it's automatically
5403
- * forwarded to the subagent for proper cancellation propagation.
5404
- *
5405
- * **Logger Inheritance** - When parent context includes a logger, it's inherited
5406
- * by the subagent for consistent structured logging.
5407
- *
5408
- * @param ctx - ExecutionContext passed to the gadget's execute() method
5409
- * @param depth - Nesting depth (default: 1 for direct child)
5410
- * @returns This builder for chaining
5411
- *
5412
- * @example
5413
- * ```typescript
5414
- * // In a subagent gadget like BrowseWeb:
5415
- * execute: async (params, ctx) => {
5416
- * const agent = new AgentBuilder(client)
5417
- * .withModel(model)
5418
- * .withGadgets(Navigate, Click, Screenshot)
5419
- * .withParentContext(ctx) // <-- Shares parent's tree
5420
- * .ask(params.task);
5421
- *
5422
- * for await (const event of agent.run()) {
5423
- * // Events automatically flow through shared tree
5424
- * if (event.type === "text") {
5425
- * result = event.content;
5426
- * }
5427
- * }
5428
- *
5429
- * // After subagent completes, access aggregated data:
5430
- * const totalCost = ctx.tree?.getSubtreeCost(ctx.nodeId!);
5431
- * const allMedia = ctx.tree?.getSubtreeMedia(ctx.nodeId!);
5432
- * }
5433
- * ```
5434
- */
4824
+ /** Share parent agent's ExecutionTree for unified event visibility. */
5435
4825
  withParentContext(ctx: ExecutionContext, depth?: number): this;
5436
- /**
5437
- * Add an ephemeral trailing message that appears at the end of each LLM request.
5438
- *
5439
- * The message is NOT persisted to conversation history - it only appears in the
5440
- * current LLM call. This is useful for injecting context-specific instructions
5441
- * or reminders without polluting the conversation history.
5442
- *
5443
- * @param message - Static string or function that generates the message
5444
- * @returns This builder for chaining
5445
- *
5446
- * @example
5447
- * ```typescript
5448
- * // Static message
5449
- * .withTrailingMessage("Always respond in JSON format.")
5450
- *
5451
- * // Dynamic message based on iteration
5452
- * .withTrailingMessage((ctx) =>
5453
- * `[Iteration ${ctx.iteration}/${ctx.maxIterations}] Stay focused on the task.`
5454
- * )
5455
- * ```
5456
- */
4826
+ /** Add an ephemeral trailing message that appears at the end of each LLM request. */
5457
4827
  withTrailingMessage(message: TrailingMessage): this;
5458
- /**
5459
- * Add a synthetic gadget call to the conversation history.
5460
- *
5461
- * This is useful for in-context learning - showing the LLM what "past self"
5462
- * did correctly so it mimics the pattern. The call is formatted with proper
5463
- * markers and parameter format, including the invocation ID so the LLM can
5464
- * reference previous calls when building dependencies.
5465
- *
5466
- * @param gadgetName - Name of the gadget
5467
- * @param parameters - Parameters passed to the gadget
5468
- * @param result - Result returned by the gadget
5469
- * @param invocationId - Invocation ID (shown to LLM so it can reference for dependencies)
5470
- * @returns This builder for chaining
5471
- *
5472
- * @example
5473
- * ```typescript
5474
- * .withSyntheticGadgetCall(
5475
- * 'TellUser',
5476
- * {
5477
- * message: '👋 Hello!\n\nHere\'s what I can do:\n- Analyze code\n- Run commands',
5478
- * done: false,
5479
- * type: 'info'
5480
- * },
5481
- * 'ℹ️ 👋 Hello!\n\nHere\'s what I can do:\n- Analyze code\n- Run commands',
5482
- * 'gc_1'
5483
- * )
5484
- * ```
5485
- */
4828
+ /** Add a synthetic gadget call to the conversation history for in-context learning. */
5486
4829
  withSyntheticGadgetCall(gadgetName: string, parameters: Record<string, unknown>, result: string, invocationId: string): this;
5487
- /**
5488
- * Compose the final hooks, including trailing message injection if configured.
5489
- *
5490
- * Note: Subagent event visibility is now handled entirely by the ExecutionTree.
5491
- * When a subagent uses withParentContext(ctx), it shares the parent's tree,
5492
- * and all events are automatically visible to tree subscribers (like the TUI).
5493
- *
5494
- * Environment-based file logging (via LLMIST_LOG_RAW_DIRECTORY) is automatically
5495
- * injected if the env var is set. User-provided hooks take precedence.
5496
- */
5497
4830
  private composeHooks;
5498
- /**
5499
- * Format parameters as block format with JSON Pointer paths.
5500
- */
5501
- private formatBlockParameters;
5502
- /**
5503
- * Build and create the agent with the given user prompt.
5504
- * Returns the Agent instance ready to run.
5505
- *
5506
- * @param userPrompt - User's question or request
5507
- * @returns Configured Agent instance
5508
- *
5509
- * @example
5510
- * ```typescript
5511
- * const agent = await LLMist.createAgent()
5512
- * .withModel("sonnet")
5513
- * .withGadgets(Calculator)
5514
- * .ask("What is 2+2?");
5515
- *
5516
- * for await (const event of agent.run()) {
5517
- * // handle events
5518
- * }
5519
- * ```
5520
- */
5521
- /**
5522
- * Build AgentOptions with the given user prompt.
5523
- * Centralizes options construction for ask(), askWithImage(), askWithContent(), and build().
5524
- *
5525
- * @param userPrompt - Optional user prompt (omitted for build() which has no prompt)
5526
- */
5527
4831
  private buildAgentOptions;
4832
+ /** Create agent and start with a user prompt. */
5528
4833
  ask(userPrompt: string): Agent;
5529
- /**
5530
- * Build and create the agent with a multimodal user prompt (text + image).
5531
- * Returns the Agent instance ready to run.
5532
- *
5533
- * @param textPrompt - Text prompt describing what to do with the image
5534
- * @param imageData - Image data (Buffer, Uint8Array, or base64 string)
5535
- * @param mimeType - Optional MIME type (auto-detected if not provided)
5536
- * @returns Configured Agent instance
5537
- *
5538
- * @example
5539
- * ```typescript
5540
- * const agent = LLMist.createAgent()
5541
- * .withModel("gpt-4o")
5542
- * .withSystem("You analyze images")
5543
- * .askWithImage(
5544
- * "What's in this image?",
5545
- * await fs.readFile("photo.jpg")
5546
- * );
5547
- *
5548
- * for await (const event of agent.run()) {
5549
- * // handle events
5550
- * }
5551
- * ```
5552
- */
4834
+ /** Create agent with multimodal input (text + image). */
5553
4835
  askWithImage(textPrompt: string, imageData: Buffer | Uint8Array | string, mimeType?: ImageMimeType): Agent;
5554
- /**
5555
- * Build and return an Agent configured with multimodal content.
5556
- * More flexible than askWithImage - accepts any combination of content parts.
5557
- *
5558
- * @param content - Array of content parts (text, images, audio)
5559
- * @returns A configured Agent ready for execution
5560
- *
5561
- * @example
5562
- * ```typescript
5563
- * import { text, imageFromBuffer, audioFromBuffer } from "llmist";
5564
- *
5565
- * const agent = LLMist.createAgent()
5566
- * .withModel("gemini:gemini-2.5-flash")
5567
- * .askWithContent([
5568
- * text("Describe this image and transcribe the audio:"),
5569
- * imageFromBuffer(imageData),
5570
- * audioFromBuffer(audioData),
5571
- * ]);
5572
- *
5573
- * for await (const event of agent.run()) {
5574
- * // handle events
5575
- * }
5576
- * ```
5577
- */
4836
+ /** Create agent with flexible multimodal content parts. */
5578
4837
  askWithContent(content: ContentPart[]): Agent;
5579
- /**
5580
- * Build, run, and collect only the text response.
5581
- * Convenient for simple queries where you just want the final answer.
5582
- *
5583
- * @param userPrompt - User's question or request
5584
- * @returns Promise resolving to the complete text response
5585
- *
5586
- * @example
5587
- * ```typescript
5588
- * const answer = await LLMist.createAgent()
5589
- * .withModel("gpt4-mini")
5590
- * .withGadgets(Calculator)
5591
- * .askAndCollect("What is 42 * 7?");
5592
- *
5593
- * console.log(answer); // "294"
5594
- * ```
5595
- */
4838
+ /** Run agent and collect text response. */
5596
4839
  askAndCollect(userPrompt: string): Promise<string>;
5597
- /**
5598
- * Build and run with event handlers.
5599
- * Combines agent creation and event handling in one call.
5600
- *
5601
- * @param userPrompt - User's question or request
5602
- * @param handlers - Event handlers
5603
- *
5604
- * @example
5605
- * ```typescript
5606
- * await LLMist.createAgent()
5607
- * .withModel("sonnet")
5608
- * .withGadgets(Calculator)
5609
- * .askWith("What is 2+2?", {
5610
- * onText: (text) => console.log("LLM:", text),
5611
- * onGadgetResult: (result) => console.log("Result:", result.result),
5612
- * });
5613
- * ```
5614
- */
4840
+ /** Run agent with event handlers. */
5615
4841
  askWith(userPrompt: string, handlers: EventHandlers): Promise<void>;
5616
- /**
5617
- * Build the agent without a user prompt.
5618
- *
5619
- * Returns an Agent instance that can be inspected (e.g., check registered gadgets)
5620
- * but cannot be run without first calling .ask(prompt).
5621
- *
5622
- * This is useful for:
5623
- * - Testing: Inspect the registry, configuration, etc.
5624
- * - Advanced use cases: Build agent configuration separately from execution
5625
- *
5626
- * @returns Configured Agent instance (without user prompt)
5627
- *
5628
- * @example
5629
- * ```typescript
5630
- * // Build agent for inspection
5631
- * const agent = new AgentBuilder()
5632
- * .withModel("sonnet")
5633
- * .withGadgets(Calculator, Weather)
5634
- * .build();
5635
- *
5636
- * // Inspect registered gadgets
5637
- * console.log(agent.getRegistry().getNames()); // ['Calculator', 'Weather']
5638
- *
5639
- * // Note: Calling agent.run() will throw an error
5640
- * // Use .ask(prompt) instead if you want to run the agent
5641
- * ```
5642
- */
4842
+ /** Build agent without a prompt (useful for testing/inspection). */
5643
4843
  build(): Agent;
5644
4844
  }
5645
4845
 
@@ -6233,38 +5433,181 @@ interface IConversationManager {
6233
5433
  */
6234
5434
  getMessages(): LLMMessage[];
6235
5435
  /**
6236
- * Gets only the conversation history messages (excludes base messages).
6237
- * Used by compaction to determine what can be compressed.
5436
+ * Gets only the conversation history messages (excludes base messages).
5437
+ * Used by compaction to determine what can be compressed.
5438
+ */
5439
+ getHistoryMessages(): LLMMessage[];
5440
+ /**
5441
+ * Gets the base messages (system prompts, gadget instructions).
5442
+ * These are never compacted and always included at the start.
5443
+ */
5444
+ getBaseMessages(): LLMMessage[];
5445
+ /**
5446
+ * Replaces the conversation history with new messages.
5447
+ * Used by compaction to update history after compression.
5448
+ * @param newHistory - The compacted history messages to replace with
5449
+ */
5450
+ replaceHistory(newHistory: LLMMessage[]): void;
5451
+ /**
5452
+ * Gets full conversation history including initial messages and runtime history.
5453
+ * Used for REPL session continuation - returns everything except base (system) messages.
5454
+ * This combines:
5455
+ * - initialMessages: History from previous sessions (set via withHistory())
5456
+ * - historyBuilder: Messages from the current session
5457
+ */
5458
+ getConversationHistory(): LLMMessage[];
5459
+ }
5460
+
5461
+ /**
5462
+ * Storage for large gadget outputs that exceed the configured limit.
5463
+ *
5464
+ * When a gadget returns more data than the configured limit, the output
5465
+ * is stored here and can be browsed later using GadgetOutputViewer.
5466
+ */
5467
+ /**
5468
+ * Metadata and content for a stored gadget output.
5469
+ */
5470
+ interface StoredOutput {
5471
+ /** Unique identifier (e.g., "Search_d34db33f") */
5472
+ id: string;
5473
+ /** Name of the gadget that produced this output */
5474
+ gadgetName: string;
5475
+ /** Full output content */
5476
+ content: string;
5477
+ /** Size in bytes */
5478
+ byteSize: number;
5479
+ /** Number of lines */
5480
+ lineCount: number;
5481
+ /** When the output was stored */
5482
+ timestamp: Date;
5483
+ }
5484
+ /**
5485
+ * In-memory store for large gadget outputs.
5486
+ *
5487
+ * Outputs are stored with generated IDs in the format `{GadgetName}_{hex8}`.
5488
+ * The store is tied to an agent run and cleared when the agent completes.
5489
+ *
5490
+ * @example
5491
+ * ```typescript
5492
+ * const store = new GadgetOutputStore();
5493
+ * const id = store.store("Search", largeOutput);
5494
+ * // id = "Search_a1b2c3d4"
5495
+ *
5496
+ * const stored = store.get(id);
5497
+ * console.log(stored?.lineCount); // 4200
5498
+ * ```
5499
+ */
5500
+ declare class GadgetOutputStore {
5501
+ private outputs;
5502
+ /**
5503
+ * Store a gadget output and return its ID.
5504
+ *
5505
+ * @param gadgetName - Name of the gadget that produced the output
5506
+ * @param content - Full output content to store
5507
+ * @returns Generated ID for retrieving the output later
5508
+ */
5509
+ store(gadgetName: string, content: string): string;
5510
+ /**
5511
+ * Retrieve a stored output by ID.
5512
+ *
5513
+ * @param id - The output ID (e.g., "Search_d34db33f")
5514
+ * @returns The stored output or undefined if not found
5515
+ */
5516
+ get(id: string): StoredOutput | undefined;
5517
+ /**
5518
+ * Check if an output exists.
5519
+ *
5520
+ * @param id - The output ID to check
5521
+ * @returns True if the output exists
5522
+ */
5523
+ has(id: string): boolean;
5524
+ /**
5525
+ * Get all stored output IDs.
5526
+ *
5527
+ * @returns Array of output IDs
5528
+ */
5529
+ getIds(): string[];
5530
+ /**
5531
+ * Get the number of stored outputs.
5532
+ */
5533
+ get size(): number;
5534
+ /**
5535
+ * Clear all stored outputs.
5536
+ * Called when the agent run completes.
5537
+ */
5538
+ clear(): void;
5539
+ /**
5540
+ * Generate a unique ID for a stored output.
5541
+ * Format: {GadgetName}_{8 hex chars}
5542
+ */
5543
+ private generateId;
5544
+ }
5545
+
5546
+ /**
5547
+ * OutputLimitManager - Manages gadget output size limiting.
5548
+ *
5549
+ * Calculates character limits from model context windows, registers
5550
+ * GadgetOutputViewer when enabled, and chains the output limiter
5551
+ * interceptor with user-provided hooks.
5552
+ */
5553
+
5554
+ /**
5555
+ * Configuration for output limiting.
5556
+ */
5557
+ interface OutputLimitConfig {
5558
+ /** Whether output limiting is enabled (default: true) */
5559
+ enabled?: boolean;
5560
+ /** Max gadget output as % of model context window (default: 15) */
5561
+ limitPercent?: number;
5562
+ }
5563
+
5564
+ /**
5565
+ * Agent: Lean orchestrator using the clean hooks architecture.
5566
+ *
5567
+ * The Agent delegates ALL stream processing and hook coordination to StreamProcessor,
5568
+ * making it a simple loop orchestrator with clear responsibilities.
5569
+ */
5570
+
5571
+ /**
5572
+ * Configuration for the execution tree context (shared tree model with subagents).
5573
+ */
5574
+ interface TreeConfig {
5575
+ /**
5576
+ * Shared execution tree for tracking all LLM calls and gadget executions.
5577
+ * If provided (by a parent subagent), nodes are added to this tree.
5578
+ * If not provided, the Agent creates its own tree.
6238
5579
  */
6239
- getHistoryMessages(): LLMMessage[];
5580
+ tree?: ExecutionTree;
6240
5581
  /**
6241
- * Gets the base messages (system prompts, gadget instructions).
6242
- * These are never compacted and always included at the start.
5582
+ * Parent node ID in the tree (when this agent is a subagent).
5583
+ * Used to set parentId on all nodes created by this agent.
6243
5584
  */
6244
- getBaseMessages(): LLMMessage[];
5585
+ parentNodeId?: NodeId;
6245
5586
  /**
6246
- * Replaces the conversation history with new messages.
6247
- * Used by compaction to update history after compression.
6248
- * @param newHistory - The compacted history messages to replace with
5587
+ * Base depth for nodes created by this agent.
5588
+ * Root agents use 0; subagents use (parentDepth + 1).
6249
5589
  */
6250
- replaceHistory(newHistory: LLMMessage[]): void;
5590
+ baseDepth?: number;
6251
5591
  /**
6252
- * Gets full conversation history including initial messages and runtime history.
6253
- * Used for REPL session continuation - returns everything except base (system) messages.
6254
- * This combines:
6255
- * - initialMessages: History from previous sessions (set via withHistory())
6256
- * - historyBuilder: Messages from the current session
5592
+ * Parent agent's observer hooks for subagent visibility.
5593
+ *
5594
+ * When a subagent is created with withParentContext(ctx), these observers
5595
+ * are also called for gadget events (in addition to the subagent's own hooks),
5596
+ * enabling the parent to observe subagent gadget activity.
6257
5597
  */
6258
- getConversationHistory(): LLMMessage[];
5598
+ parentObservers?: Observers;
6259
5599
  }
6260
-
6261
5600
  /**
6262
- * Agent: Lean orchestrator using the clean hooks architecture.
6263
- *
6264
- * The Agent delegates ALL stream processing and hook coordination to StreamProcessor,
6265
- * making it a simple loop orchestrator with clear responsibilities.
5601
+ * Configuration for custom gadget block format prefixes.
6266
5602
  */
6267
-
5603
+ interface PrefixConfig {
5604
+ /** Custom gadget start prefix */
5605
+ gadgetStartPrefix?: string;
5606
+ /** Custom gadget end prefix */
5607
+ gadgetEndPrefix?: string;
5608
+ /** Custom gadget argument prefix for block format parameters */
5609
+ gadgetArgPrefix?: string;
5610
+ }
6268
5611
  /**
6269
5612
  * Configuration options for the Agent.
6270
5613
  */
@@ -6291,12 +5634,10 @@ interface AgentOptions {
6291
5634
  hooks?: AgentHooks;
6292
5635
  /** Callback for requesting human input during execution */
6293
5636
  requestHumanInput?: (question: string) => Promise<string>;
6294
- /** Custom gadget start prefix */
6295
- gadgetStartPrefix?: string;
6296
- /** Custom gadget end prefix */
6297
- gadgetEndPrefix?: string;
6298
- /** Custom gadget argument prefix for block format parameters */
6299
- gadgetArgPrefix?: string;
5637
+ /**
5638
+ * Gadget prefix configuration (start/end/arg prefixes for block format).
5639
+ */
5640
+ prefixConfig?: PrefixConfig;
6300
5641
  /** Initial messages. User messages support multimodal content. */
6301
5642
  initialMessages?: Array<{
6302
5643
  role: "system" | "user" | "assistant";
@@ -6322,10 +5663,10 @@ interface AgentOptions {
6322
5663
  gadgetExecutionMode?: GadgetExecutionMode;
6323
5664
  /** Custom prompt configuration for gadget system prompts */
6324
5665
  promptConfig?: PromptTemplateConfig;
6325
- /** Enable gadget output limiting (default: true) */
6326
- gadgetOutputLimit?: boolean;
6327
- /** Max gadget output as % of model context window (default: 15) */
6328
- gadgetOutputLimitPercent?: number;
5666
+ /**
5667
+ * Gadget output limit configuration.
5668
+ */
5669
+ outputLimitConfig?: OutputLimitConfig;
6329
5670
  /** Context compaction configuration (enabled by default) */
6330
5671
  compactionConfig?: CompactionConfig;
6331
5672
  /** Retry configuration for LLM API calls (enabled by default) */
@@ -6343,29 +5684,9 @@ interface AgentOptions {
6343
5684
  /** Maximum gadgets to execute per LLM response (0 = unlimited) */
6344
5685
  maxGadgetsPerResponse?: number;
6345
5686
  /**
6346
- * Shared execution tree for tracking all LLM calls and gadget executions.
6347
- * If provided (by a parent subagent), nodes are added to this tree.
6348
- * If not provided, the Agent creates its own tree.
6349
- */
6350
- parentTree?: ExecutionTree;
6351
- /**
6352
- * Parent node ID in the tree (when this agent is a subagent).
6353
- * Used to set parentId on all nodes created by this agent.
6354
- */
6355
- parentNodeId?: NodeId;
6356
- /**
6357
- * Base depth for nodes created by this agent.
6358
- * Root agents use 0; subagents use (parentDepth + 1).
6359
- */
6360
- baseDepth?: number;
6361
- /**
6362
- * Parent agent's observer hooks for subagent visibility.
6363
- *
6364
- * When a subagent is created with withParentContext(ctx), these observers
6365
- * are also called for gadget events (in addition to the subagent's own hooks),
6366
- * enabling the parent to observe subagent gadget activity.
5687
+ * Execution tree configuration (shared tree model with subagents).
6367
5688
  */
6368
- parentObservers?: Observers;
5689
+ treeConfig?: TreeConfig;
6369
5690
  /**
6370
5691
  * Shared rate limit tracker from parent agent.
6371
5692
  *
@@ -6406,19 +5727,11 @@ declare class Agent {
6406
5727
  private readonly hooks;
6407
5728
  private readonly conversation;
6408
5729
  private readonly registry;
6409
- private readonly gadgetStartPrefix?;
6410
- private readonly gadgetEndPrefix?;
6411
- private readonly gadgetArgPrefix?;
6412
- private readonly requestHumanInput?;
6413
- private readonly textOnlyHandler;
6414
- private readonly textWithGadgetsHandler?;
6415
- private readonly defaultGadgetTimeoutMs?;
6416
- private readonly gadgetExecutionMode;
5730
+ private readonly prefixConfig?;
5731
+ private readonly conversationUpdater;
6417
5732
  private readonly defaultMaxTokens?;
6418
5733
  private hasUserPrompt;
6419
- private readonly outputStore;
6420
- private readonly outputLimitEnabled;
6421
- private readonly outputLimitCharLimit;
5734
+ private readonly outputLimitManager;
6422
5735
  private readonly compactionManager?;
6423
5736
  private readonly mediaStore;
6424
5737
  private readonly signal?;
@@ -6426,17 +5739,13 @@ declare class Agent {
6426
5739
  private readonly caching?;
6427
5740
  private readonly retryConfig;
6428
5741
  private readonly rateLimitTracker?;
6429
- private readonly agentContextConfig;
6430
- private readonly subagentConfig?;
6431
- private readonly maxGadgetsPerResponse;
6432
- private syntheticInvocationCounter;
6433
5742
  private readonly completedInvocationIds;
6434
5743
  private readonly failedInvocationIds;
6435
5744
  private readonly pendingUserMessages;
6436
5745
  private readonly tree;
6437
5746
  private readonly parentNodeId;
6438
- private readonly baseDepth;
6439
- private readonly parentObservers?;
5747
+ private readonly streamProcessorFactory;
5748
+ private readonly llmCallLifecycle;
6440
5749
  /**
6441
5750
  * Creates a new Agent instance.
6442
5751
  * @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
@@ -6617,6 +5926,16 @@ declare class Agent {
6617
5926
  * @throws {Error} If no user prompt was provided (when using build() without ask())
6618
5927
  */
6619
5928
  run(): AsyncGenerator<StreamEvent>;
5929
+ /**
5930
+ * Execute a single LLM call attempt with full retry orchestration.
5931
+ *
5932
+ * Delegates all retry logic to RetryOrchestrator, then propagates the accumulated
5933
+ * invocation IDs back to the agent's cross-iteration tracking sets.
5934
+ *
5935
+ * Yields stream events in real-time and returns the final stream completion metadata
5936
+ * along with accumulated tracking state from the final successful attempt only.
5937
+ */
5938
+ private executeWithRetry;
6620
5939
  /**
6621
5940
  * Create LLM stream with proactive rate limit protection.
6622
5941
  *
@@ -6625,26 +5944,20 @@ declare class Agent {
6625
5944
  */
6626
5945
  private createStream;
6627
5946
  /**
6628
- * Simple sleep utility for rate limit delays.
6629
- */
6630
- private sleep;
6631
- /**
6632
- * Handle LLM error through controller.
5947
+ * Factory method for constructing a StreamProcessor for a given iteration.
5948
+ *
5949
+ * Delegates to StreamProcessorFactory, which encapsulates all static
5950
+ * StreamProcessor configuration. Cross-iteration mutable state is passed here.
6633
5951
  */
6634
- private handleLLMError;
5952
+ private createStreamProcessor;
6635
5953
  /**
6636
- * Handle text-only response (no gadgets called).
5954
+ * Simple sleep utility for rate limit delays.
6637
5955
  */
6638
- private handleTextOnlyResponse;
5956
+ private sleep;
6639
5957
  /**
6640
5958
  * Resolve max tokens from model catalog.
6641
5959
  */
6642
5960
  private resolveMaxTokensFromCatalog;
6643
- /**
6644
- * Chain the output limiter interceptor with user-provided hooks.
6645
- * The limiter runs first, then chains to any user interceptor.
6646
- */
6647
- private chainOutputLimiterWithUserHooks;
6648
5961
  /**
6649
5962
  * Check abort signal and notify observers if aborted.
6650
5963
  * @returns true if agent should terminate
@@ -6655,43 +5968,6 @@ declare class Agent {
6655
5968
  * @returns compaction stream event if compaction occurred, null otherwise
6656
5969
  */
6657
5970
  private checkAndPerformCompaction;
6658
- /**
6659
- * Resolve reasoning configuration with auto-enable logic.
6660
- *
6661
- * Priority: explicit config > auto-enable for reasoning models > undefined
6662
- * When a model has `features.reasoning: true` and no explicit config is set,
6663
- * reasoning is automatically enabled at "medium" effort.
6664
- */
6665
- private resolveReasoningConfig;
6666
- /**
6667
- * Resolve caching configuration.
6668
- *
6669
- * Priority: explicit config > default enabled (preserves Anthropic's existing behavior)
6670
- * Default is `{ enabled: true }` which means:
6671
- * - Anthropic: `cache_control` markers are added (existing behavior preserved)
6672
- * - Gemini: Cache manager is consulted but skips if no explicit config was set
6673
- * - OpenAI: No-op (server-side automatic)
6674
- */
6675
- private resolveCachingConfig;
6676
- /**
6677
- * Prepare LLM call options, create tree node, and process beforeLLMCall controller.
6678
- * @returns options, node ID, and optional skipWithSynthetic response if controller wants to skip
6679
- */
6680
- private prepareLLMCall;
6681
- /**
6682
- * Calculate cost and complete LLM call in execution tree.
6683
- * Also records usage to rate limit tracker for proactive throttling.
6684
- */
6685
- private completeLLMCallInTree;
6686
- /**
6687
- * Process afterLLMCall controller and return modified final message.
6688
- */
6689
- private processAfterLLMCallController;
6690
- /**
6691
- * Update conversation history with gadget results or text-only response.
6692
- * @returns true if loop should break (text-only handler requested termination)
6693
- */
6694
- private updateConversationWithResults;
6695
5971
  /**
6696
5972
  * Run agent with named event handlers (syntactic sugar).
6697
5973
  *
@@ -7851,91 +7127,6 @@ declare class ConversationManager implements IConversationManager {
7851
7127
  getConversationHistory(): LLMMessage[];
7852
7128
  }
7853
7129
 
7854
- /**
7855
- * Storage for large gadget outputs that exceed the configured limit.
7856
- *
7857
- * When a gadget returns more data than the configured limit, the output
7858
- * is stored here and can be browsed later using GadgetOutputViewer.
7859
- */
7860
- /**
7861
- * Metadata and content for a stored gadget output.
7862
- */
7863
- interface StoredOutput {
7864
- /** Unique identifier (e.g., "Search_d34db33f") */
7865
- id: string;
7866
- /** Name of the gadget that produced this output */
7867
- gadgetName: string;
7868
- /** Full output content */
7869
- content: string;
7870
- /** Size in bytes */
7871
- byteSize: number;
7872
- /** Number of lines */
7873
- lineCount: number;
7874
- /** When the output was stored */
7875
- timestamp: Date;
7876
- }
7877
- /**
7878
- * In-memory store for large gadget outputs.
7879
- *
7880
- * Outputs are stored with generated IDs in the format `{GadgetName}_{hex8}`.
7881
- * The store is tied to an agent run and cleared when the agent completes.
7882
- *
7883
- * @example
7884
- * ```typescript
7885
- * const store = new GadgetOutputStore();
7886
- * const id = store.store("Search", largeOutput);
7887
- * // id = "Search_a1b2c3d4"
7888
- *
7889
- * const stored = store.get(id);
7890
- * console.log(stored?.lineCount); // 4200
7891
- * ```
7892
- */
7893
- declare class GadgetOutputStore {
7894
- private outputs;
7895
- /**
7896
- * Store a gadget output and return its ID.
7897
- *
7898
- * @param gadgetName - Name of the gadget that produced the output
7899
- * @param content - Full output content to store
7900
- * @returns Generated ID for retrieving the output later
7901
- */
7902
- store(gadgetName: string, content: string): string;
7903
- /**
7904
- * Retrieve a stored output by ID.
7905
- *
7906
- * @param id - The output ID (e.g., "Search_d34db33f")
7907
- * @returns The stored output or undefined if not found
7908
- */
7909
- get(id: string): StoredOutput | undefined;
7910
- /**
7911
- * Check if an output exists.
7912
- *
7913
- * @param id - The output ID to check
7914
- * @returns True if the output exists
7915
- */
7916
- has(id: string): boolean;
7917
- /**
7918
- * Get all stored output IDs.
7919
- *
7920
- * @returns Array of output IDs
7921
- */
7922
- getIds(): string[];
7923
- /**
7924
- * Get the number of stored outputs.
7925
- */
7926
- get size(): number;
7927
- /**
7928
- * Clear all stored outputs.
7929
- * Called when the agent run completes.
7930
- */
7931
- clear(): void;
7932
- /**
7933
- * Generate a unique ID for a stored output.
7934
- * Format: {GadgetName}_{8 hex chars}
7935
- */
7936
- private generateId;
7937
- }
7938
-
7939
7130
  /**
7940
7131
  * LLM Assistance Hints System
7941
7132
  *
@@ -8114,6 +7305,18 @@ declare function createHints(config: HintsConfig): AgentHooks;
8114
7305
  *
8115
7306
  * Replaces the complex wiring between Agent, ResponseProcessor, and GadgetRuntime.
8116
7307
  * Owns ALL stream processing and hook coordination with a clean, predictable flow.
7308
+ *
7309
+ * After refactoring, StreamProcessor is a thin orchestrator (~300 lines) that:
7310
+ * - Iterates over raw LLM stream chunks
7311
+ * - Applies raw-chunk and text-chunk interceptors
7312
+ * - Delegates gadget dispatch to GadgetDispatcher
7313
+ * - Yields events in real-time
7314
+ * - Applies the final assistant-message interceptor
7315
+ *
7316
+ * Extracted classes:
7317
+ * - GadgetLimitGuard — maxGadgetsPerResponse enforcement
7318
+ * - GadgetHookLifecycle — full hook sequence for a single gadget
7319
+ * - GadgetDispatcher — dispatch decision tree + concurrency + dependency
8117
7320
  */
8118
7321
 
8119
7322
  /**
@@ -8181,6 +7384,11 @@ interface StreamProcessorOptions {
8181
7384
  }
8182
7385
  /**
8183
7386
  * Result of stream processing.
7387
+ *
7388
+ * @deprecated StreamProcessor.process() is now an async generator that yields
7389
+ * StreamEvent items directly. Use StreamCompletionEvent (the final yielded event)
7390
+ * to obtain the metadata formerly returned in this type. This interface is retained
7391
+ * for backward compatibility but is not used internally.
8184
7392
  */
8185
7393
  interface StreamProcessingResult {
8186
7394
  /** All emitted events */
@@ -8199,21 +7407,14 @@ interface StreamProcessingResult {
8199
7407
  finalMessage: string;
8200
7408
  }
8201
7409
  /**
8202
- * StreamProcessor: Coordinates all stream processing and hook execution.
7410
+ * StreamProcessor: Thin orchestrator for stream processing and hook coordination.
8203
7411
  *
8204
7412
  * Execution order:
8205
7413
  * 1. Raw chunk arrives from LLM
8206
7414
  * 2. Interceptor: interceptRawChunk (transform raw text)
8207
7415
  * 3. Observer: onStreamChunk (logging)
8208
7416
  * 4. Parse for gadgets
8209
- * 5. If gadget found:
8210
- * a. Interceptor: interceptGadgetParameters (transform params)
8211
- * b. Controller: beforeGadgetExecution (can skip)
8212
- * c. Observer: onGadgetExecutionStart
8213
- * d. Execute gadget
8214
- * e. Interceptor: interceptGadgetResult (transform result)
8215
- * f. Controller: afterGadgetExecution (can provide fallback)
8216
- * g. Observer: onGadgetExecutionComplete
7417
+ * 5. If gadget found → delegate to GadgetDispatcher
8217
7418
  * 6. If text chunk:
8218
7419
  * a. Interceptor: interceptTextChunk (transform display text)
8219
7420
  * b. Yield to user
@@ -8225,20 +7426,13 @@ declare class StreamProcessor {
8225
7426
  private readonly hooks;
8226
7427
  private readonly logger;
8227
7428
  private readonly parser;
8228
- private readonly executor;
8229
7429
  private readonly tree?;
8230
- private readonly parentNodeId;
8231
- private readonly baseDepth;
8232
- private readonly gadgetExecutionMode;
8233
7430
  private responseText;
8234
7431
  private readonly dependencyResolver;
8235
- private readonly concurrencyManager;
8236
7432
  /** Queue of completed gadget results ready to be yielded (for real-time streaming) */
8237
7433
  private completedResultsQueue;
8238
- private readonly parentObservers?;
8239
- private readonly maxGadgetsPerResponse;
8240
- private gadgetStartedCount;
8241
- private limitExceeded;
7434
+ private readonly dispatcher;
7435
+ private readonly limitGuard;
8242
7436
  constructor(options: StreamProcessorOptions);
8243
7437
  /**
8244
7438
  * Process an LLM stream and yield events in real-time.
@@ -8259,30 +7453,6 @@ declare class StreamProcessor {
8259
7453
  * Process a text event through interceptors.
8260
7454
  */
8261
7455
  private processTextEvent;
8262
- /**
8263
- * Process a gadget call, yielding events in real-time.
8264
- *
8265
- * Yields gadget_call event IMMEDIATELY when parsed (before execution),
8266
- * enabling real-time UI feedback.
8267
- */
8268
- private processGadgetCallGenerator;
8269
- /**
8270
- * Start a gadget execution with concurrency tracking.
8271
- * Delegates tracking to GadgetConcurrencyManager; schedules queue processing on completion.
8272
- */
8273
- private startGadgetWithConcurrencyTracking;
8274
- /**
8275
- * Execute a gadget through the full hook lifecycle and yield events.
8276
- * Handles parameter interception, before/after controllers, observers,
8277
- * execution, result interception, and tree tracking.
8278
- */
8279
- private executeGadgetGenerator;
8280
- /**
8281
- * Execute a gadget and push events to the completed results queue (non-blocking).
8282
- * Used for fire-and-forget parallel execution of independent gadgets.
8283
- * Results are pushed to completedResultsQueue for real-time streaming to the caller.
8284
- */
8285
- private executeGadgetAndCollect;
8286
7456
  /**
8287
7457
  * Drain all completed results from the queue.
8288
7458
  * Used to yield results as they complete during stream processing.
@@ -8290,35 +7460,14 @@ declare class StreamProcessor {
8290
7460
  */
8291
7461
  private drainCompletedResults;
8292
7462
  /**
8293
- * Wait for all in-flight gadget executions to complete, yielding events in real-time.
8294
- * Called at stream end to ensure all parallel executions finish.
8295
- * Results and subagent events are pushed to completedResultsQueue during execution.
8296
- * This generator yields queued events while polling, enabling real-time display
8297
- * of subagent activity (LLM calls, nested gadgets) during long-running gadgets.
8298
- * Clears the inFlightExecutions map after all gadgets complete.
8299
- */
8300
- private waitForInFlightExecutions;
8301
- /**
8302
- * Handle a gadget that cannot execute because a dependency failed.
8303
- * Calls the onDependencySkipped controller to allow customization.
8304
- */
8305
- private handleFailedDependency;
8306
- /**
8307
- * Check if gadget execution should be skipped due to maxGadgetsPerResponse limit.
8308
- * If limit is exceeded, yields skip events and returns true.
8309
- * If execution can proceed, increments counter and returns false.
8310
- *
8311
- * @returns true if gadget should be skipped, false if execution can proceed
8312
- */
8313
- private checkGadgetLimitExceeded;
8314
- /**
8315
- * Process pending gadgets whose dependencies are now satisfied.
8316
- * Yields events in real-time as gadgets complete.
7463
+ * Update gadget result tracking flags based on a stream event.
7464
+ * Checks if the event is a gadget_result and, if so, marks gadgets as executed
7465
+ * and sets the break-loop flag when the result requests it.
8317
7466
  *
8318
- * Gadgets are executed in parallel for efficiency,
8319
- * but results are yielded as they become available.
7467
+ * @param evt - The stream event to inspect
7468
+ * @param state - Mutable state object holding the tracking flags
8320
7469
  */
8321
- private processPendingGadgetsGenerator;
7470
+ private trackGadgetResult;
8322
7471
  /**
8323
7472
  * Execute multiple observers in parallel.
8324
7473
  * All observers run concurrently and failures are tracked but don't crash.
@@ -8492,6 +7641,26 @@ declare function getProvider(model: string): string | undefined;
8492
7641
  * ```
8493
7642
  */
8494
7643
  declare function getModelId(model: string): string;
7644
+ /**
7645
+ * Strip the provider prefix from a model string.
7646
+ *
7647
+ * Identical to {@link getModelId}: removes the `provider:` portion and returns
7648
+ * just the model ID. If there is no prefix, the original string is returned.
7649
+ *
7650
+ * Use this when you need the bare model ID (e.g. for a cost-registry lookup)
7651
+ * and the input may or may not carry a provider prefix.
7652
+ *
7653
+ * @param modelId - Full model string, optionally with provider prefix
7654
+ * @returns Model ID without provider prefix
7655
+ *
7656
+ * @example
7657
+ * ```typescript
7658
+ * stripProviderPrefix('openai:gpt-4o') // → 'gpt-4o'
7659
+ * stripProviderPrefix('anthropic:claude-sonnet') // → 'claude-sonnet'
7660
+ * stripProviderPrefix('gpt-4o') // → 'gpt-4o' (no prefix — returned as-is)
7661
+ * ```
7662
+ */
7663
+ declare function stripProviderPrefix(modelId: string): string;
8495
7664
 
8496
7665
  /**
8497
7666
  * Signal that a gadget throws to indicate task completion and agent termination.
@@ -8656,6 +7825,51 @@ interface ErrorFormatterOptions {
8656
7825
  endPrefix?: string;
8657
7826
  }
8658
7827
 
7828
+ /**
7829
+ * Options for constructing a GadgetExecutor.
7830
+ */
7831
+ interface GadgetExecutorOptions {
7832
+ /** Gadget registry used to look up and execute gadgets */
7833
+ registry: GadgetRegistry;
7834
+ /** Optional callback to request human input during gadget execution */
7835
+ requestHumanInput?: (question: string) => Promise<string>;
7836
+ /** Logger instance; defaults to a new "llmist:executor" logger if omitted */
7837
+ logger?: Logger<ILogObj>;
7838
+ /** Default timeout in milliseconds applied to all gadgets without an explicit timeout */
7839
+ defaultGadgetTimeoutMs?: number;
7840
+ /** Options for formatting gadget execution errors */
7841
+ errorFormatterOptions?: ErrorFormatterOptions;
7842
+ /** LLMist client made available to gadgets via ExecutionContext.llmist */
7843
+ client?: LLMist;
7844
+ /** Media store for persisting gadget media outputs */
7845
+ mediaStore?: MediaStore;
7846
+ /** Parent agent configuration inherited by subagents */
7847
+ agentConfig?: AgentContextConfig;
7848
+ /** Per-gadget configuration overrides (e.g., timeoutMs, model) */
7849
+ subagentConfig?: SubagentConfigMap;
7850
+ /** Execution tree for tracking LLM calls and gadget executions */
7851
+ tree?: ExecutionTree;
7852
+ /** Parent node ID in the execution tree */
7853
+ parentNodeId?: NodeId | null;
7854
+ /** Base depth for nodes created during execution */
7855
+ baseDepth?: number;
7856
+ /**
7857
+ * Parent agent's observer hooks for subagent visibility.
7858
+ * When a subagent uses withParentContext(ctx), these observers are also called
7859
+ * for gadget events in addition to the subagent's own hooks.
7860
+ */
7861
+ parentObservers?: Observers;
7862
+ /**
7863
+ * Current agent's observers.
7864
+ * Passed to ExecutionContext.parentObservers so gadgets creating subagents
7865
+ * can inherit them via withParentContext(ctx).
7866
+ */
7867
+ currentObservers?: Observers;
7868
+ /** Shared rate limit tracker for coordinated throttling across subagents */
7869
+ rateLimitTracker?: RateLimitTracker;
7870
+ /** Shared retry config for consistent backoff behavior across subagents */
7871
+ retryConfig?: ResolvedRetryConfig;
7872
+ }
8659
7873
  declare class GadgetExecutor {
8660
7874
  private readonly registry;
8661
7875
  private readonly requestHumanInput?;
@@ -8674,7 +7888,7 @@ declare class GadgetExecutor {
8674
7888
  private readonly logger;
8675
7889
  private readonly errorFormatter;
8676
7890
  private readonly argPrefix;
8677
- constructor(registry: GadgetRegistry, requestHumanInput?: ((question: string) => Promise<string>) | undefined, logger?: Logger<ILogObj>, defaultGadgetTimeoutMs?: number | undefined, errorFormatterOptions?: ErrorFormatterOptions, client?: LLMist | undefined, mediaStore?: MediaStore | undefined, agentConfig?: AgentContextConfig | undefined, subagentConfig?: SubagentConfigMap | undefined, tree?: ExecutionTree | undefined, parentNodeId?: (NodeId | null) | undefined, baseDepth?: number | undefined, parentObservers?: Observers | undefined, currentObservers?: Observers | undefined, rateLimitTracker?: RateLimitTracker | undefined, retryConfig?: ResolvedRetryConfig | undefined);
7891
+ constructor(options: GadgetExecutorOptions);
8678
7892
  /**
8679
7893
  * Creates a promise that rejects with a TimeoutException after the specified timeout.
8680
7894
  * Aborts the provided AbortController before rejecting, allowing gadgets to clean up.
@@ -8688,7 +7902,6 @@ declare class GadgetExecutor {
8688
7902
  */
8689
7903
  private unifyExecuteResult;
8690
7904
  execute(call: ParsedGadgetCall): Promise<GadgetExecutionResult>;
8691
- executeAll(calls: ParsedGadgetCall[]): Promise<GadgetExecutionResult[]>;
8692
7905
  }
8693
7906
 
8694
7907
  /**
@@ -10869,4 +10082,4 @@ declare const timing: {
10869
10082
  */
10870
10083
  declare function getHostExports(ctx: ExecutionContext): HostExports;
10871
10084
 
10872
- export { AbortException, AbstractGadget, type AddGadgetParams, type AddLLMCallParams, type AfterGadgetExecutionAction, type AfterGadgetExecutionControllerContext, type AfterLLMCallAction, type AfterLLMCallControllerContext, type AfterLLMErrorAction, Agent, AgentBuilder, type AgentHooks, type AgentOptions, AnthropicMessagesProvider, type AudioContentPart, type AudioMimeType, type AudioSource, type BaseExecutionEvent, BaseSessionManager, type BeforeGadgetExecutionAction, type BeforeLLMCallAction, BudgetPricingUnavailableError, type CachingConfig, type CachingScope, type ChunkInterceptorContext, type CompactionConfig, type CompactionContext, type CompactionEvent, CompactionManager, type CompactionResult, type CompactionStats, type CompactionStrategy, type CompleteGadgetParams, type CompleteLLMCallParams, type ContentPart, type Controllers, ConversationManager, type CostEstimate, type CostReportingLLMist, type CreateGadgetConfig, DEFAULT_COMPACTION_CONFIG, DEFAULT_HINTS, DEFAULT_PROMPTS, DEFAULT_RATE_LIMIT_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_SUMMARIZATION_PROMPT, type EventHandlers, type ExecutionContext, type ExecutionEvent, type ExecutionEventType, type ExecutionNode, type ExecutionNodeType, ExecutionTree, FALLBACK_CHARS_PER_TOKEN, type FileLoggingOptions, type FileLoggingState, type FileWrittenInfo, type FormatLLMErrorContext, GADGET_ARG_PREFIX, GADGET_END_PREFIX, GADGET_START_PREFIX, Gadget, type GadgetCallEvent, GadgetCallParser, type GadgetClass, type GadgetCompleteEvent, type GadgetConfig, type GadgetErrorEvent, type GadgetEvent, type GadgetExample, type GadgetExecuteResult, type GadgetExecuteResultWithMedia, type GadgetExecuteReturn, type GadgetExecutionControllerContext, type GadgetExecutionMode, type GadgetExecutionResult, GadgetExecutor, type GadgetFactoryExports, type GadgetMediaOutput, type GadgetNode, type GadgetOrClass, GadgetOutputStore, type GadgetParameterInterceptorContext, GadgetRegistry, type GadgetResultInterceptorContext, type GadgetSkippedEvent, type GadgetStartEvent, type GadgetState, GeminiGenerativeProvider, type HintContext, type HintTemplate, type HintsConfig, type HistoryMessage, HookPresets, type HostExports, HuggingFaceProvider, type HumanInputRequiredEvent, HumanInputRequiredException, HybridStrategy, type IConversationManager, type ISessionManager, type ImageBase64Source, type ImageContentPart, type ImageGenerationOptions, type ImageGenerationResult, type ImageMimeType, type ImageModelSpec, type ImageSource, type ImageUrlSource, type Interceptors, type IterationHintOptions, type LLMCallCompleteEvent, type LLMCallControllerContext, type LLMCallErrorEvent, type LLMCallNode, type LLMCallStartEvent, type LLMCallStreamEvent, type LLMErrorControllerContext, type LLMEvent, type LLMGenerationOptions, type LLMMessage, LLMMessageBuilder, type LLMResponseEndEvent, type LLMStream, type LLMStreamChunk, LLMist, type LLMistOptions, type LLMistPackageManifest, type LoggerOptions, type LoggingOptions, MODEL_ALIASES, type MediaKind, type MediaMetadata, MediaStore, type MessageContent, type MessageInterceptorContext, type MessageRole, type MessageTurn, type ModelDescriptor, type ModelFeatures, ModelIdentifierParser, type ModelLimits, type ModelPricing, ModelRegistry, type ModelSpec, type NodeId, type ObserveChunkContext, type ObserveCompactionContext, type ObserveGadgetCompleteContext, type ObserveGadgetStartContext, type ObserveLLMCallContext, type ObserveLLMCompleteContext, type ObserveLLMErrorContext, type ObserveRateLimitThrottleContext, type ObserveRetryAttemptContext, type Observers, OpenAIChatProvider, type OpenAICompatibleConfig, OpenAICompatibleProvider, type OpenRouterConfig, OpenRouterProvider, type OpenRouterRouting, type ParallelGadgetHintOptions, type ParsedGadgetCall, type PresetDefinition, type PromptContext, type PromptTemplate, type PromptTemplateConfig, type ProviderAdapter, type ProviderIdentifier, type RateLimitConfig, type RateLimitStats, RateLimitTracker, type ReasoningConfig, type ReasoningEffort, type ResolveValueOptions, type ResolvedCompactionConfig, type ResolvedRateLimitConfig, type ResolvedRetryConfig, type RetryConfig, type RetryOptions, type SessionManifestEntry, SimpleSessionManager, SlidingWindowStrategy, type SpeechGenerationOptions, type SpeechGenerationResult, type SpeechModelSpec, type StoredMedia, type StoredOutput, type StreamCompleteEvent, type StreamEvent, type StreamProcessingResult, StreamProcessor, type StreamProcessorOptions, type SubagentConfig, type SubagentConfigMap, type SubagentContext, type SubagentManifestEntry, type SubagentOptions, SummarizationStrategy, TaskCompletionSignal, type TextContentPart, type TextEvent, type TextGenerationOptions, type TextOnlyAction, type TextOnlyContext, type TextOnlyCustomHandler, type TextOnlyGadgetConfig, type TextOnlyHandler, type TextOnlyStrategy, type ThinkingChunk, type ThinkingEvent, TimeoutException, type TokenUsage, type TrailingMessage, type TrailingMessageContext, type CompactionEvent$1 as TreeCompactionEvent, type GadgetSkippedEvent$1 as TreeGadgetSkippedEvent, type TriggeredLimitInfo, type ValidationIssue, type ValidationResult, type VisionAnalyzeOptions, type VisionAnalyzeResult, audioFromBase64, audioFromBuffer, collectEvents, collectText, complete, createAnthropicProviderFromEnv, createFileLoggingState, createGadget, createGadgetOutputViewer, createGeminiProviderFromEnv, createHints, createHuggingFaceProviderFromEnv, createLogger, createMediaOutput, createOpenAIProviderFromEnv, createOpenRouterProviderFromEnv, createSubagent, defaultLogger, detectAudioMimeType, detectImageMimeType, discoverProviderAdapters, extractMessageText, extractRetryAfterMs, filterByDepth, filterByParent, filterRootEvents, format, formatBytes, formatCallNumber, formatDate, formatDuration, formatLLMError, formatLlmRequest, gadgetError, gadgetSuccess, getErrorMessage, getHostExports, getModelId, getPresetGadgets, getProvider, getSubagent, groupByParent, hasHostExports, hasPreset, hasProviderPrefix, hasSubagents, humanDelay, imageFromBase64, imageFromBuffer, imageFromUrl, isAbortError, isAudioPart, isDataUrl, isGadgetEvent, isImagePart, isLLMEvent, isRetryableError, isRootEvent, isSubagentEvent, isTextPart, iterationProgressHint, listPresets, listSubagents, normalizeMessageContent, parallelGadgetHint, parseDataUrl, parseManifest, parseRetryAfterHeader, randomDelay, resetFileLoggingState, resolveConfig, resolveHintTemplate, resolveModel, resolvePromptTemplate, resolveRateLimitConfig, resolveRetryConfig, resolveRulesTemplate, resolveSubagentModel, resolveSubagentTimeout, resolveValue, resultWithAudio, resultWithFile, resultWithImage, resultWithImages, resultWithMedia, runWithHandlers, schemaToJSONSchema, stream, text, timing, toBase64, truncate, validateAndApplyDefaults, validateGadgetParams, validateGadgetSchema, withErrorHandling, withRetry, withTimeout };
10085
+ export { AbortException, AbstractGadget, type AddGadgetParams, type AddLLMCallParams, type AfterGadgetExecutionAction, type AfterGadgetExecutionControllerContext, type AfterLLMCallAction, type AfterLLMCallControllerContext, type AfterLLMErrorAction, Agent, AgentBuilder, type AgentHooks, type AgentOptions, AnthropicMessagesProvider, type AudioContentPart, type AudioMimeType, type AudioSource, type BaseExecutionEvent, BaseSessionManager, type BeforeGadgetExecutionAction, type BeforeLLMCallAction, BudgetPricingUnavailableError, type CachingConfig, type CachingScope, type ChunkInterceptorContext, type CompactionConfig, type CompactionContext, type CompactionEvent, CompactionManager, type CompactionResult, type CompactionStats, type CompactionStrategy, type CompleteGadgetParams, type CompleteLLMCallParams, type ContentPart, type Controllers, ConversationManager, type CostEstimate, type CostReportingLLMist, type CreateGadgetConfig, DEFAULT_COMPACTION_CONFIG, DEFAULT_HINTS, DEFAULT_PROMPTS, DEFAULT_RATE_LIMIT_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_SUMMARIZATION_PROMPT, type EventHandlers, type ExecutionContext, type ExecutionEvent, type ExecutionEventType, type ExecutionNode, type ExecutionNodeType, ExecutionTree, FALLBACK_CHARS_PER_TOKEN, type FileLoggingOptions, type FileLoggingState, type FileWrittenInfo, type FormatLLMErrorContext, GADGET_ARG_PREFIX, GADGET_END_PREFIX, GADGET_START_PREFIX, Gadget, type GadgetCallEvent, GadgetCallParser, type GadgetClass, type GadgetCompleteEvent, type GadgetConfig, type GadgetErrorEvent, type GadgetEvent, type GadgetExample, type GadgetExecuteResult, type GadgetExecuteResultWithMedia, type GadgetExecuteReturn, type GadgetExecutionControllerContext, type GadgetExecutionMode, type GadgetExecutionResult, GadgetExecutor, type GadgetExecutorOptions, type GadgetFactoryExports, type GadgetMediaOutput, type GadgetNode, type GadgetOrClass, GadgetOutputStore, type GadgetParameterInterceptorContext, GadgetRegistry, type GadgetResultInterceptorContext, type GadgetSkippedEvent, type GadgetStartEvent, type GadgetState, GeminiGenerativeProvider, type HintContext, type HintTemplate, type HintsConfig, type HistoryMessage, HookPresets, type HostExports, HuggingFaceProvider, type HumanInputRequiredEvent, HumanInputRequiredException, HybridStrategy, type IConversationManager, type ISessionManager, type ImageBase64Source, type ImageContentPart, type ImageGenerationOptions, type ImageGenerationResult, type ImageMimeType, type ImageModelSpec, type ImageSource, type ImageUrlSource, type Interceptors, type IterationHintOptions, type LLMCallCompleteEvent, type LLMCallControllerContext, type LLMCallErrorEvent, type LLMCallNode, type LLMCallStartEvent, type LLMCallStreamEvent, type LLMErrorControllerContext, type LLMEvent, type LLMGenerationOptions, type LLMMessage, LLMMessageBuilder, type LLMResponseEndEvent, type LLMStream, type LLMStreamChunk, LLMist, type LLMistOptions, type LLMistPackageManifest, type LoggerOptions, type LoggingOptions, MODEL_ALIASES, type MediaKind, type MediaMetadata, MediaStore, type MessageContent, type MessageInterceptorContext, type MessageRole, type MessageTurn, type ModelDescriptor, type ModelFeatures, ModelIdentifierParser, type ModelLimits, type ModelPricing, ModelRegistry, type ModelSpec, type NodeId, type ObserveChunkContext, type ObserveCompactionContext, type ObserveGadgetCompleteContext, type ObserveGadgetStartContext, type ObserveLLMCallContext, type ObserveLLMCompleteContext, type ObserveLLMErrorContext, type ObserveRateLimitThrottleContext, type ObserveRetryAttemptContext, type Observers, OpenAIChatProvider, type OpenAICompatibleConfig, OpenAICompatibleProvider, type OpenRouterConfig, OpenRouterProvider, type OpenRouterRouting, type OutputLimitConfig, type ParallelGadgetHintOptions, type ParsedGadgetCall, type PrefixConfig, type PresetDefinition, type PromptContext, type PromptTemplate, type PromptTemplateConfig, type ProviderAdapter, type ProviderIdentifier, type RateLimitConfig, type RateLimitStats, RateLimitTracker, type ReasoningConfig, type ReasoningEffort, type ResolveValueOptions, type ResolvedCompactionConfig, type ResolvedRateLimitConfig, type ResolvedRetryConfig, type RetryConfig, type RetryOptions, type SessionManifestEntry, SimpleSessionManager, SlidingWindowStrategy, type SpeechGenerationOptions, type SpeechGenerationResult, type SpeechModelSpec, type StoredMedia, type StoredOutput, type StreamCompleteEvent, type StreamEvent, type StreamProcessingResult, StreamProcessor, type StreamProcessorOptions, type SubagentConfig, type SubagentConfigMap, type SubagentContext, type SubagentManifestEntry, type SubagentOptions, SummarizationStrategy, TaskCompletionSignal, type TextContentPart, type TextEvent, type TextGenerationOptions, type TextOnlyAction, type TextOnlyContext, type TextOnlyCustomHandler, type TextOnlyGadgetConfig, type TextOnlyHandler, type TextOnlyStrategy, type ThinkingChunk, type ThinkingEvent, TimeoutException, type TokenUsage, type TrailingMessage, type TrailingMessageContext, type CompactionEvent$1 as TreeCompactionEvent, type TreeConfig, type GadgetSkippedEvent$1 as TreeGadgetSkippedEvent, type TriggeredLimitInfo, type ValidationIssue, type ValidationResult, type VisionAnalyzeOptions, type VisionAnalyzeResult, audioFromBase64, audioFromBuffer, collectEvents, collectText, complete, createAnthropicProviderFromEnv, createFileLoggingState, createGadget, createGadgetOutputViewer, createGeminiProviderFromEnv, createHints, createHuggingFaceProviderFromEnv, createLogger, createMediaOutput, createOpenAIProviderFromEnv, createOpenRouterProviderFromEnv, createSubagent, defaultLogger, detectAudioMimeType, detectImageMimeType, discoverProviderAdapters, extractMessageText, extractRetryAfterMs, filterByDepth, filterByParent, filterRootEvents, format, formatBytes, formatCallNumber, formatDate, formatDuration, formatLLMError, formatLlmRequest, gadgetError, gadgetSuccess, getErrorMessage, getHostExports, getModelId, getPresetGadgets, getProvider, getSubagent, groupByParent, hasHostExports, hasPreset, hasProviderPrefix, hasSubagents, humanDelay, imageFromBase64, imageFromBuffer, imageFromUrl, isAbortError, isAudioPart, isDataUrl, isGadgetEvent, isImagePart, isLLMEvent, isRetryableError, isRootEvent, isSubagentEvent, isTextPart, iterationProgressHint, listPresets, listSubagents, normalizeMessageContent, parallelGadgetHint, parseDataUrl, parseManifest, parseRetryAfterHeader, randomDelay, resetFileLoggingState, resolveConfig, resolveHintTemplate, resolveModel, resolvePromptTemplate, resolveRateLimitConfig, resolveRetryConfig, resolveRulesTemplate, resolveSubagentModel, resolveSubagentTimeout, resolveValue, resultWithAudio, resultWithFile, resultWithImage, resultWithImages, resultWithMedia, runWithHandlers, schemaToJSONSchema, stream, stripProviderPrefix, text, timing, toBase64, truncate, validateAndApplyDefaults, validateGadgetParams, validateGadgetSchema, withErrorHandling, withRetry, withTimeout };