llmist 12.2.3 → 12.3.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.cjs CHANGED
@@ -1423,6 +1423,137 @@ var init_model_shortcuts = __esm({
1423
1423
  }
1424
1424
  });
1425
1425
 
1426
+ // src/core/retry.ts
1427
+ function resolveRetryConfig(config) {
1428
+ if (!config) {
1429
+ return { ...DEFAULT_RETRY_CONFIG };
1430
+ }
1431
+ return {
1432
+ enabled: config.enabled ?? DEFAULT_RETRY_CONFIG.enabled,
1433
+ retries: config.retries ?? DEFAULT_RETRY_CONFIG.retries,
1434
+ minTimeout: config.minTimeout ?? DEFAULT_RETRY_CONFIG.minTimeout,
1435
+ maxTimeout: config.maxTimeout ?? DEFAULT_RETRY_CONFIG.maxTimeout,
1436
+ factor: config.factor ?? DEFAULT_RETRY_CONFIG.factor,
1437
+ randomize: config.randomize ?? DEFAULT_RETRY_CONFIG.randomize,
1438
+ onRetry: config.onRetry,
1439
+ onRetriesExhausted: config.onRetriesExhausted,
1440
+ shouldRetry: config.shouldRetry
1441
+ };
1442
+ }
1443
+ function isRetryableError(error) {
1444
+ const message = error.message.toLowerCase();
1445
+ const name = error.name;
1446
+ if (message.includes("429") || message.includes("rate limit") || message.includes("rate_limit")) {
1447
+ return true;
1448
+ }
1449
+ if (message.includes("500") || message.includes("502") || message.includes("503") || message.includes("504") || message.includes("internal server error") || message.includes("bad gateway") || message.includes("service unavailable") || message.includes("gateway timeout")) {
1450
+ return true;
1451
+ }
1452
+ if (message.includes("timeout") || message.includes("etimedout") || message.includes("timed out")) {
1453
+ return true;
1454
+ }
1455
+ if (message.includes("econnreset") || message.includes("econnrefused") || message.includes("enotfound") || message.includes("connection") || message.includes("network")) {
1456
+ return true;
1457
+ }
1458
+ if (name === "APIConnectionError" || name === "RateLimitError" || name === "InternalServerError" || name === "ServiceUnavailableError" || name === "APITimeoutError") {
1459
+ return true;
1460
+ }
1461
+ if (message.includes("overloaded") || message.includes("capacity")) {
1462
+ return true;
1463
+ }
1464
+ if (message.includes("401") || message.includes("403") || message.includes("400") || message.includes("404") || message.includes("authentication") || message.includes("unauthorized") || message.includes("forbidden") || message.includes("invalid") || message.includes("content policy") || name === "AuthenticationError" || name === "BadRequestError" || name === "NotFoundError" || name === "PermissionDeniedError") {
1465
+ return false;
1466
+ }
1467
+ return false;
1468
+ }
1469
+ function formatLLMError(error) {
1470
+ const message = error.message;
1471
+ const name = error.name;
1472
+ if (message.includes("RESOURCE_EXHAUSTED") || message.includes("429")) {
1473
+ return "Rate limit exceeded (429) - retry after a few seconds";
1474
+ }
1475
+ if (message.toLowerCase().includes("rate limit") || message.toLowerCase().includes("rate_limit")) {
1476
+ return "Rate limit exceeded - retry after a few seconds";
1477
+ }
1478
+ if (message.toLowerCase().includes("overloaded") || message.toLowerCase().includes("capacity")) {
1479
+ return "API overloaded - retry later";
1480
+ }
1481
+ if (message.includes("500") || message.toLowerCase().includes("internal server error")) {
1482
+ return "Internal server error (500) - the API is experiencing issues";
1483
+ }
1484
+ if (message.includes("502") || message.toLowerCase().includes("bad gateway")) {
1485
+ return "Bad gateway (502) - the API is temporarily unavailable";
1486
+ }
1487
+ if (message.includes("503") || message.toLowerCase().includes("service unavailable")) {
1488
+ return "Service unavailable (503) - the API is temporarily down";
1489
+ }
1490
+ if (message.includes("504") || message.toLowerCase().includes("gateway timeout")) {
1491
+ return "Gateway timeout (504) - the request took too long";
1492
+ }
1493
+ if (message.toLowerCase().includes("timeout") || message.toLowerCase().includes("timed out")) {
1494
+ return "Request timed out - the API took too long to respond";
1495
+ }
1496
+ if (message.toLowerCase().includes("econnrefused")) {
1497
+ return "Connection refused - unable to reach the API";
1498
+ }
1499
+ if (message.toLowerCase().includes("econnreset")) {
1500
+ return "Connection reset - the API closed the connection";
1501
+ }
1502
+ if (message.toLowerCase().includes("enotfound")) {
1503
+ return "DNS error - unable to resolve API hostname";
1504
+ }
1505
+ if (message.includes("401") || message.toLowerCase().includes("unauthorized") || name === "AuthenticationError") {
1506
+ return "Authentication failed - check your API key";
1507
+ }
1508
+ if (message.includes("403") || message.toLowerCase().includes("forbidden") || name === "PermissionDeniedError") {
1509
+ return "Permission denied - your API key lacks required permissions";
1510
+ }
1511
+ if (message.includes("400") || name === "BadRequestError") {
1512
+ const match = message.match(/message['":\s]+['"]?([^'"}\]]+)/i);
1513
+ if (match) {
1514
+ return `Bad request: ${match[1].trim()}`;
1515
+ }
1516
+ return "Bad request - check your input parameters";
1517
+ }
1518
+ if (message.toLowerCase().includes("content policy") || message.toLowerCase().includes("safety")) {
1519
+ return "Content policy violation - the request was blocked";
1520
+ }
1521
+ try {
1522
+ const parsed = JSON.parse(message);
1523
+ const extractedMessage = parsed?.error?.message || parsed?.message;
1524
+ if (typeof extractedMessage === "string" && extractedMessage.length > 0) {
1525
+ return extractedMessage.trim();
1526
+ }
1527
+ } catch {
1528
+ }
1529
+ const jsonMatch = message.match(/["']?message["']?\s*[:=]\s*["']([^"']+)["']/i);
1530
+ if (jsonMatch) {
1531
+ return jsonMatch[1].trim();
1532
+ }
1533
+ if (message.length > 200) {
1534
+ const firstPart = message.split(/[.!?\n]/)[0];
1535
+ if (firstPart && firstPart.length > 10 && firstPart.length < 150) {
1536
+ return firstPart.trim();
1537
+ }
1538
+ return message.slice(0, 150).trim() + "...";
1539
+ }
1540
+ return message;
1541
+ }
1542
+ var DEFAULT_RETRY_CONFIG;
1543
+ var init_retry = __esm({
1544
+ "src/core/retry.ts"() {
1545
+ "use strict";
1546
+ DEFAULT_RETRY_CONFIG = {
1547
+ enabled: true,
1548
+ retries: 3,
1549
+ minTimeout: 1e3,
1550
+ maxTimeout: 3e4,
1551
+ factor: 2,
1552
+ randomize: true
1553
+ };
1554
+ }
1555
+ });
1556
+
1426
1557
  // src/gadgets/media-store.ts
1427
1558
  function getLlmistTmpDir() {
1428
1559
  return (0, import_node_path.join)((0, import_node_os.homedir)(), ".llmist", "tmp");
@@ -2503,137 +2634,6 @@ var init_agent_internal_key = __esm({
2503
2634
  }
2504
2635
  });
2505
2636
 
2506
- // src/core/retry.ts
2507
- function resolveRetryConfig(config) {
2508
- if (!config) {
2509
- return { ...DEFAULT_RETRY_CONFIG };
2510
- }
2511
- return {
2512
- enabled: config.enabled ?? DEFAULT_RETRY_CONFIG.enabled,
2513
- retries: config.retries ?? DEFAULT_RETRY_CONFIG.retries,
2514
- minTimeout: config.minTimeout ?? DEFAULT_RETRY_CONFIG.minTimeout,
2515
- maxTimeout: config.maxTimeout ?? DEFAULT_RETRY_CONFIG.maxTimeout,
2516
- factor: config.factor ?? DEFAULT_RETRY_CONFIG.factor,
2517
- randomize: config.randomize ?? DEFAULT_RETRY_CONFIG.randomize,
2518
- onRetry: config.onRetry,
2519
- onRetriesExhausted: config.onRetriesExhausted,
2520
- shouldRetry: config.shouldRetry
2521
- };
2522
- }
2523
- function isRetryableError(error) {
2524
- const message = error.message.toLowerCase();
2525
- const name = error.name;
2526
- if (message.includes("429") || message.includes("rate limit") || message.includes("rate_limit")) {
2527
- return true;
2528
- }
2529
- if (message.includes("500") || message.includes("502") || message.includes("503") || message.includes("504") || message.includes("internal server error") || message.includes("bad gateway") || message.includes("service unavailable") || message.includes("gateway timeout")) {
2530
- return true;
2531
- }
2532
- if (message.includes("timeout") || message.includes("etimedout") || message.includes("timed out")) {
2533
- return true;
2534
- }
2535
- if (message.includes("econnreset") || message.includes("econnrefused") || message.includes("enotfound") || message.includes("connection") || message.includes("network")) {
2536
- return true;
2537
- }
2538
- if (name === "APIConnectionError" || name === "RateLimitError" || name === "InternalServerError" || name === "ServiceUnavailableError" || name === "APITimeoutError") {
2539
- return true;
2540
- }
2541
- if (message.includes("overloaded") || message.includes("capacity")) {
2542
- return true;
2543
- }
2544
- if (message.includes("401") || message.includes("403") || message.includes("400") || message.includes("404") || message.includes("authentication") || message.includes("unauthorized") || message.includes("forbidden") || message.includes("invalid") || message.includes("content policy") || name === "AuthenticationError" || name === "BadRequestError" || name === "NotFoundError" || name === "PermissionDeniedError") {
2545
- return false;
2546
- }
2547
- return false;
2548
- }
2549
- function formatLLMError(error) {
2550
- const message = error.message;
2551
- const name = error.name;
2552
- if (message.includes("RESOURCE_EXHAUSTED") || message.includes("429")) {
2553
- return "Rate limit exceeded (429) - retry after a few seconds";
2554
- }
2555
- if (message.toLowerCase().includes("rate limit") || message.toLowerCase().includes("rate_limit")) {
2556
- return "Rate limit exceeded - retry after a few seconds";
2557
- }
2558
- if (message.toLowerCase().includes("overloaded") || message.toLowerCase().includes("capacity")) {
2559
- return "API overloaded - retry later";
2560
- }
2561
- if (message.includes("500") || message.toLowerCase().includes("internal server error")) {
2562
- return "Internal server error (500) - the API is experiencing issues";
2563
- }
2564
- if (message.includes("502") || message.toLowerCase().includes("bad gateway")) {
2565
- return "Bad gateway (502) - the API is temporarily unavailable";
2566
- }
2567
- if (message.includes("503") || message.toLowerCase().includes("service unavailable")) {
2568
- return "Service unavailable (503) - the API is temporarily down";
2569
- }
2570
- if (message.includes("504") || message.toLowerCase().includes("gateway timeout")) {
2571
- return "Gateway timeout (504) - the request took too long";
2572
- }
2573
- if (message.toLowerCase().includes("timeout") || message.toLowerCase().includes("timed out")) {
2574
- return "Request timed out - the API took too long to respond";
2575
- }
2576
- if (message.toLowerCase().includes("econnrefused")) {
2577
- return "Connection refused - unable to reach the API";
2578
- }
2579
- if (message.toLowerCase().includes("econnreset")) {
2580
- return "Connection reset - the API closed the connection";
2581
- }
2582
- if (message.toLowerCase().includes("enotfound")) {
2583
- return "DNS error - unable to resolve API hostname";
2584
- }
2585
- if (message.includes("401") || message.toLowerCase().includes("unauthorized") || name === "AuthenticationError") {
2586
- return "Authentication failed - check your API key";
2587
- }
2588
- if (message.includes("403") || message.toLowerCase().includes("forbidden") || name === "PermissionDeniedError") {
2589
- return "Permission denied - your API key lacks required permissions";
2590
- }
2591
- if (message.includes("400") || name === "BadRequestError") {
2592
- const match = message.match(/message['":\s]+['"]?([^'"}\]]+)/i);
2593
- if (match) {
2594
- return `Bad request: ${match[1].trim()}`;
2595
- }
2596
- return "Bad request - check your input parameters";
2597
- }
2598
- if (message.toLowerCase().includes("content policy") || message.toLowerCase().includes("safety")) {
2599
- return "Content policy violation - the request was blocked";
2600
- }
2601
- try {
2602
- const parsed = JSON.parse(message);
2603
- const extractedMessage = parsed?.error?.message || parsed?.message;
2604
- if (typeof extractedMessage === "string" && extractedMessage.length > 0) {
2605
- return extractedMessage.trim();
2606
- }
2607
- } catch {
2608
- }
2609
- const jsonMatch = message.match(/["']?message["']?\s*[:=]\s*["']([^"']+)["']/i);
2610
- if (jsonMatch) {
2611
- return jsonMatch[1].trim();
2612
- }
2613
- if (message.length > 200) {
2614
- const firstPart = message.split(/[.!?\n]/)[0];
2615
- if (firstPart && firstPart.length > 10 && firstPart.length < 150) {
2616
- return firstPart.trim();
2617
- }
2618
- return message.slice(0, 150).trim() + "...";
2619
- }
2620
- return message;
2621
- }
2622
- var DEFAULT_RETRY_CONFIG;
2623
- var init_retry = __esm({
2624
- "src/core/retry.ts"() {
2625
- "use strict";
2626
- DEFAULT_RETRY_CONFIG = {
2627
- enabled: true,
2628
- retries: 3,
2629
- minTimeout: 1e3,
2630
- maxTimeout: 3e4,
2631
- factor: 2,
2632
- randomize: true
2633
- };
2634
- }
2635
- });
2636
-
2637
2637
  // src/agent/compaction/config.ts
2638
2638
  function resolveCompactionConfig(config = {}) {
2639
2639
  const trigger = config.triggerThresholdPercent ?? DEFAULT_COMPACTION_CONFIG.triggerThresholdPercent;
@@ -8086,6 +8086,10 @@ var init_builder = __esm({
8086
8086
  // Tree context for subagent support - enables shared tree model
8087
8087
  // When a gadget calls withParentContext(ctx), it shares the parent's tree
8088
8088
  parentContext;
8089
+ // Parent observer hooks for subagent visibility
8090
+ // When a gadget calls withParentContext(ctx), these observers are
8091
+ // also called for gadget events in the subagent
8092
+ parentObservers;
8089
8093
  constructor(client) {
8090
8094
  this.client = client;
8091
8095
  }
@@ -8693,6 +8697,9 @@ var init_builder = __esm({
8693
8697
  if (ctx.logger && !this.logger) {
8694
8698
  this.logger = ctx.logger;
8695
8699
  }
8700
+ if (ctx.parentObservers && !this.parentObservers) {
8701
+ this.parentObservers = ctx.parentObservers;
8702
+ }
8696
8703
  return this;
8697
8704
  }
8698
8705
  /**
@@ -9068,7 +9075,9 @@ ${endPrefix}`
9068
9075
  // Tree context for shared tree model (subagents share parent's tree)
9069
9076
  parentTree: this.parentContext?.tree,
9070
9077
  parentNodeId: this.parentContext?.nodeId,
9071
- baseDepth: this.parentContext ? (this.parentContext.depth ?? 0) + 1 : 0
9078
+ baseDepth: this.parentContext ? (this.parentContext.depth ?? 0) + 1 : 0,
9079
+ // Parent observer hooks for subagent visibility
9080
+ parentObservers: this.parentObservers
9072
9081
  };
9073
9082
  return new Agent(AGENT_INTERNAL_KEY, options);
9074
9083
  }
@@ -9951,7 +9960,7 @@ var init_executor = __esm({
9951
9960
  init_parser();
9952
9961
  init_typed_gadget();
9953
9962
  GadgetExecutor = class {
9954
- constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig, tree, parentNodeId, baseDepth) {
9963
+ constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig, tree, parentNodeId, baseDepth, parentObservers) {
9955
9964
  this.registry = registry;
9956
9965
  this.requestHumanInput = requestHumanInput;
9957
9966
  this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
@@ -9962,6 +9971,7 @@ var init_executor = __esm({
9962
9971
  this.tree = tree;
9963
9972
  this.parentNodeId = parentNodeId;
9964
9973
  this.baseDepth = baseDepth;
9974
+ this.parentObservers = parentObservers;
9965
9975
  this.logger = logger ?? createLogger({ name: "llmist:executor" });
9966
9976
  this.errorFormatter = new GadgetExecutionErrorFormatter(errorFormatterOptions);
9967
9977
  this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
@@ -10127,7 +10137,11 @@ var init_executor = __esm({
10127
10137
  // Logger for structured logging (respects CLI's log level/file config)
10128
10138
  logger: this.logger,
10129
10139
  // Human input callback for subagents to bubble up input requests
10130
- requestHumanInput: this.requestHumanInput
10140
+ requestHumanInput: this.requestHumanInput,
10141
+ // Parent observer hooks for subagent visibility
10142
+ // When a subagent uses withParentContext(ctx), it will receive these
10143
+ // and call them for gadget events in addition to its own hooks
10144
+ parentObservers: this.parentObservers
10131
10145
  };
10132
10146
  let rawResult;
10133
10147
  if (timeoutMs && timeoutMs > 0) {
@@ -10480,6 +10494,8 @@ var init_stream_processor = __esm({
10480
10494
  priorCompletedInvocations;
10481
10495
  /** Invocation IDs that failed in previous iterations (read-only reference from Agent) */
10482
10496
  priorFailedInvocations;
10497
+ // Parent observer hooks for subagent visibility
10498
+ parentObservers;
10483
10499
  constructor(options) {
10484
10500
  this.iteration = options.iteration;
10485
10501
  this.registry = options.registry;
@@ -10491,6 +10507,7 @@ var init_stream_processor = __esm({
10491
10507
  this.priorCompletedInvocations = options.priorCompletedInvocations ?? /* @__PURE__ */ new Set();
10492
10508
  this.priorFailedInvocations = options.priorFailedInvocations ?? /* @__PURE__ */ new Set();
10493
10509
  this.subagentConfig = options.subagentConfig;
10510
+ this.parentObservers = options.parentObservers;
10494
10511
  this.parser = new GadgetCallParser({
10495
10512
  startPrefix: options.gadgetStartPrefix,
10496
10513
  endPrefix: options.gadgetEndPrefix,
@@ -10509,7 +10526,9 @@ var init_stream_processor = __esm({
10509
10526
  // Tree context for gadget execution
10510
10527
  options.tree,
10511
10528
  options.parentNodeId,
10512
- options.baseDepth
10529
+ options.baseDepth,
10530
+ // Parent observer hooks for subagent visibility
10531
+ options.parentObservers
10513
10532
  );
10514
10533
  }
10515
10534
  /**
@@ -10715,9 +10734,9 @@ var init_stream_processor = __esm({
10715
10734
  failedDependencyError: errorMessage
10716
10735
  };
10717
10736
  yield skipEvent;
10737
+ const skippedGadgetNode = this.tree?.getNodeByInvocationId(call.invocationId);
10738
+ const skippedSubagentContext = this.tree && skippedGadgetNode ? getSubagentContextForNode(this.tree, skippedGadgetNode.id) : void 0;
10718
10739
  if (this.hooks.observers?.onGadgetSkipped) {
10719
- const gadgetNode = this.tree?.getNodeByInvocationId(call.invocationId);
10720
- const subagentContext = this.tree && gadgetNode ? getSubagentContextForNode(this.tree, gadgetNode.id) : void 0;
10721
10740
  const context = {
10722
10741
  iteration: this.iteration,
10723
10742
  gadgetName: call.gadgetName,
@@ -10726,10 +10745,23 @@ var init_stream_processor = __esm({
10726
10745
  failedDependency: call.invocationId,
10727
10746
  failedDependencyError: errorMessage,
10728
10747
  logger: this.logger,
10729
- subagentContext
10748
+ subagentContext: skippedSubagentContext
10730
10749
  };
10731
10750
  await this.safeObserve(() => this.hooks.observers.onGadgetSkipped(context));
10732
10751
  }
10752
+ if (this.parentObservers?.onGadgetSkipped) {
10753
+ const context = {
10754
+ iteration: this.iteration,
10755
+ gadgetName: call.gadgetName,
10756
+ invocationId: call.invocationId,
10757
+ parameters: call.parameters ?? {},
10758
+ failedDependency: call.invocationId,
10759
+ failedDependencyError: errorMessage,
10760
+ logger: this.logger,
10761
+ subagentContext: skippedSubagentContext
10762
+ };
10763
+ await this.safeObserve(() => this.parentObservers.onGadgetSkipped(context));
10764
+ }
10733
10765
  return;
10734
10766
  }
10735
10767
  const failedDep = call.dependencies.find(
@@ -10872,19 +10904,30 @@ var init_stream_processor = __esm({
10872
10904
  this.tree.startGadget(gadgetNode.id);
10873
10905
  }
10874
10906
  }
10907
+ const gadgetStartNode = this.tree?.getNodeByInvocationId(call.invocationId);
10908
+ const gadgetStartSubagentContext = this.tree && gadgetStartNode ? getSubagentContextForNode(this.tree, gadgetStartNode.id) : void 0;
10875
10909
  if (this.hooks.observers?.onGadgetExecutionStart) {
10876
- const gadgetNode = this.tree?.getNodeByInvocationId(call.invocationId);
10877
- const subagentContext = this.tree && gadgetNode ? getSubagentContextForNode(this.tree, gadgetNode.id) : void 0;
10878
10910
  const context = {
10879
10911
  iteration: this.iteration,
10880
10912
  gadgetName: call.gadgetName,
10881
10913
  invocationId: call.invocationId,
10882
10914
  parameters,
10883
10915
  logger: this.logger,
10884
- subagentContext
10916
+ subagentContext: gadgetStartSubagentContext
10885
10917
  };
10886
10918
  await this.safeObserve(() => this.hooks.observers.onGadgetExecutionStart(context));
10887
10919
  }
10920
+ if (this.parentObservers?.onGadgetExecutionStart) {
10921
+ const context = {
10922
+ iteration: this.iteration,
10923
+ gadgetName: call.gadgetName,
10924
+ invocationId: call.invocationId,
10925
+ parameters,
10926
+ logger: this.logger,
10927
+ subagentContext: gadgetStartSubagentContext
10928
+ };
10929
+ await this.safeObserve(() => this.parentObservers.onGadgetExecutionStart(context));
10930
+ }
10888
10931
  let result;
10889
10932
  if (shouldSkip) {
10890
10933
  result = {
@@ -10952,9 +10995,9 @@ var init_stream_processor = __esm({
10952
10995
  }
10953
10996
  }
10954
10997
  }
10998
+ const gadgetCompleteNode = this.tree?.getNodeByInvocationId(result.invocationId);
10999
+ const gadgetCompleteSubagentContext = this.tree && gadgetCompleteNode ? getSubagentContextForNode(this.tree, gadgetCompleteNode.id) : void 0;
10955
11000
  if (this.hooks.observers?.onGadgetExecutionComplete) {
10956
- const gadgetNode = this.tree?.getNodeByInvocationId(result.invocationId);
10957
- const subagentContext = this.tree && gadgetNode ? getSubagentContextForNode(this.tree, gadgetNode.id) : void 0;
10958
11001
  const context = {
10959
11002
  iteration: this.iteration,
10960
11003
  gadgetName: result.gadgetName,
@@ -10965,10 +11008,25 @@ var init_stream_processor = __esm({
10965
11008
  executionTimeMs: result.executionTimeMs,
10966
11009
  cost: result.cost,
10967
11010
  logger: this.logger,
10968
- subagentContext
11011
+ subagentContext: gadgetCompleteSubagentContext
10969
11012
  };
10970
11013
  await this.safeObserve(() => this.hooks.observers.onGadgetExecutionComplete(context));
10971
11014
  }
11015
+ if (this.parentObservers?.onGadgetExecutionComplete) {
11016
+ const context = {
11017
+ iteration: this.iteration,
11018
+ gadgetName: result.gadgetName,
11019
+ invocationId: result.invocationId,
11020
+ parameters,
11021
+ finalResult: result.result,
11022
+ error: result.error,
11023
+ executionTimeMs: result.executionTimeMs,
11024
+ cost: result.cost,
11025
+ logger: this.logger,
11026
+ subagentContext: gadgetCompleteSubagentContext
11027
+ };
11028
+ await this.safeObserve(() => this.parentObservers.onGadgetExecutionComplete(context));
11029
+ }
10972
11030
  this.completedResults.set(result.invocationId, result);
10973
11031
  if (result.error) {
10974
11032
  this.failedInvocations.add(result.invocationId);
@@ -11094,9 +11152,9 @@ var init_stream_processor = __esm({
11094
11152
  failedDependencyError: depError
11095
11153
  };
11096
11154
  events.push(skipEvent);
11155
+ const gadgetNodeForSkip = this.tree?.getNodeByInvocationId(call.invocationId);
11156
+ const skipSubagentContext = this.tree && gadgetNodeForSkip ? getSubagentContextForNode(this.tree, gadgetNodeForSkip.id) : void 0;
11097
11157
  if (this.hooks.observers?.onGadgetSkipped) {
11098
- const gadgetNode = this.tree?.getNodeByInvocationId(call.invocationId);
11099
- const subagentContext = this.tree && gadgetNode ? getSubagentContextForNode(this.tree, gadgetNode.id) : void 0;
11100
11158
  const context = {
11101
11159
  iteration: this.iteration,
11102
11160
  gadgetName: call.gadgetName,
@@ -11105,10 +11163,23 @@ var init_stream_processor = __esm({
11105
11163
  failedDependency: failedDep,
11106
11164
  failedDependencyError: depError,
11107
11165
  logger: this.logger,
11108
- subagentContext
11166
+ subagentContext: skipSubagentContext
11109
11167
  };
11110
11168
  await this.safeObserve(() => this.hooks.observers.onGadgetSkipped(context));
11111
11169
  }
11170
+ if (this.parentObservers?.onGadgetSkipped) {
11171
+ const context = {
11172
+ iteration: this.iteration,
11173
+ gadgetName: call.gadgetName,
11174
+ invocationId: call.invocationId,
11175
+ parameters: call.parameters ?? {},
11176
+ failedDependency: failedDep,
11177
+ failedDependencyError: depError,
11178
+ logger: this.logger,
11179
+ subagentContext: skipSubagentContext
11180
+ };
11181
+ await this.safeObserve(() => this.parentObservers.onGadgetSkipped(context));
11182
+ }
11112
11183
  this.logger.info("Gadget skipped due to failed dependency", {
11113
11184
  gadgetName: call.gadgetName,
11114
11185
  invocationId: call.invocationId,
@@ -11236,9 +11307,9 @@ var init_stream_processor = __esm({
11236
11307
  failedDependencyError: errorMessage
11237
11308
  };
11238
11309
  yield skipEvent;
11310
+ const gadgetNodeForTimeout = this.tree?.getNodeByInvocationId(invocationId);
11311
+ const timeoutSubagentContext = this.tree && gadgetNodeForTimeout ? getSubagentContextForNode(this.tree, gadgetNodeForTimeout.id) : void 0;
11239
11312
  if (this.hooks.observers?.onGadgetSkipped) {
11240
- const gadgetNode = this.tree?.getNodeByInvocationId(invocationId);
11241
- const subagentContext = this.tree && gadgetNode ? getSubagentContextForNode(this.tree, gadgetNode.id) : void 0;
11242
11313
  const context = {
11243
11314
  iteration: this.iteration,
11244
11315
  gadgetName: call.gadgetName,
@@ -11247,10 +11318,23 @@ var init_stream_processor = __esm({
11247
11318
  failedDependency: missingDeps[0],
11248
11319
  failedDependencyError: errorMessage,
11249
11320
  logger: this.logger,
11250
- subagentContext
11321
+ subagentContext: timeoutSubagentContext
11251
11322
  };
11252
11323
  await this.safeObserve(() => this.hooks.observers.onGadgetSkipped(context));
11253
11324
  }
11325
+ if (this.parentObservers?.onGadgetSkipped) {
11326
+ const context = {
11327
+ iteration: this.iteration,
11328
+ gadgetName: call.gadgetName,
11329
+ invocationId,
11330
+ parameters: call.parameters ?? {},
11331
+ failedDependency: missingDeps[0],
11332
+ failedDependencyError: errorMessage,
11333
+ logger: this.logger,
11334
+ subagentContext: timeoutSubagentContext
11335
+ };
11336
+ await this.safeObserve(() => this.parentObservers.onGadgetSkipped(context));
11337
+ }
11254
11338
  }
11255
11339
  this.gadgetsAwaitingDependencies.clear();
11256
11340
  }
@@ -11304,16 +11388,16 @@ var import_p_retry, Agent;
11304
11388
  var init_agent = __esm({
11305
11389
  "src/agent/agent.ts"() {
11306
11390
  "use strict";
11391
+ import_p_retry = __toESM(require("p-retry"), 1);
11307
11392
  init_constants();
11308
11393
  init_execution_tree();
11309
11394
  init_messages();
11310
11395
  init_model_shortcuts();
11396
+ init_retry();
11311
11397
  init_media_store();
11312
11398
  init_output_viewer();
11313
11399
  init_logger();
11314
11400
  init_agent_internal_key();
11315
- init_retry();
11316
- import_p_retry = __toESM(require("p-retry"), 1);
11317
11401
  init_manager();
11318
11402
  init_conversation_manager();
11319
11403
  init_event_handlers();
@@ -11365,6 +11449,8 @@ var init_agent = __esm({
11365
11449
  tree;
11366
11450
  parentNodeId;
11367
11451
  baseDepth;
11452
+ // Parent observer hooks for subagent visibility
11453
+ parentObservers;
11368
11454
  /**
11369
11455
  * Creates a new Agent instance.
11370
11456
  * @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
@@ -11444,6 +11530,7 @@ var init_agent = __esm({
11444
11530
  this.tree = options.parentTree ?? new ExecutionTree();
11445
11531
  this.parentNodeId = options.parentNodeId ?? null;
11446
11532
  this.baseDepth = options.baseDepth ?? 0;
11533
+ this.parentObservers = options.parentObservers;
11447
11534
  }
11448
11535
  /**
11449
11536
  * Get the gadget registry for this agent.
@@ -11708,7 +11795,9 @@ var init_agent = __esm({
11708
11795
  baseDepth: this.baseDepth,
11709
11796
  // Cross-iteration dependency tracking
11710
11797
  priorCompletedInvocations: this.completedInvocationIds,
11711
- priorFailedInvocations: this.failedInvocationIds
11798
+ priorFailedInvocations: this.failedInvocationIds,
11799
+ // Parent observer hooks for subagent visibility
11800
+ parentObservers: this.parentObservers
11712
11801
  });
11713
11802
  let streamMetadata = null;
11714
11803
  let gadgetCallCount = 0;
@@ -11825,11 +11914,23 @@ var init_agent = __esm({
11825
11914
  if (!this.retryConfig.enabled) {
11826
11915
  return this.client.stream(llmOptions);
11827
11916
  }
11828
- const { retries, minTimeout, maxTimeout, factor, randomize, onRetry, onRetriesExhausted, shouldRetry } = this.retryConfig;
11917
+ const {
11918
+ retries,
11919
+ minTimeout,
11920
+ maxTimeout,
11921
+ factor,
11922
+ randomize,
11923
+ onRetry,
11924
+ onRetriesExhausted,
11925
+ shouldRetry
11926
+ } = this.retryConfig;
11829
11927
  try {
11830
11928
  return await (0, import_p_retry.default)(
11831
11929
  async (attemptNumber) => {
11832
- this.logger.debug("Creating LLM stream", { attempt: attemptNumber, maxAttempts: retries + 1 });
11930
+ this.logger.debug("Creating LLM stream", {
11931
+ attempt: attemptNumber,
11932
+ maxAttempts: retries + 1
11933
+ });
11833
11934
  return this.client.stream(llmOptions);
11834
11935
  },
11835
11936
  {
@@ -12076,7 +12177,11 @@ var init_agent = __esm({
12076
12177
  validateBeforeLLMCallAction(action);
12077
12178
  if (action.action === "skip") {
12078
12179
  this.logger.info("Controller skipped LLM call, using synthetic response");
12079
- return { options: llmOptions, llmNodeId: llmNode.id, skipWithSynthetic: action.syntheticResponse };
12180
+ return {
12181
+ options: llmOptions,
12182
+ llmNodeId: llmNode.id,
12183
+ skipWithSynthetic: action.syntheticResponse
12184
+ };
12080
12185
  } else if (action.action === "proceed" && action.modifiedOptions) {
12081
12186
  llmOptions = { ...llmOptions, ...action.modifiedOptions };
12082
12187
  }