llmist 9.7.0 → 10.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.cjs CHANGED
@@ -8331,6 +8331,13 @@ var init_stream_processor = __esm({
8331
8331
  inFlightExecutions = /* @__PURE__ */ new Map();
8332
8332
  /** Queue of completed gadget results ready to be yielded (for real-time streaming) */
8333
8333
  completedResultsQueue = [];
8334
+ // Concurrency limiting
8335
+ /** Subagent configuration map for checking maxConcurrent limits */
8336
+ subagentConfig;
8337
+ /** Track active execution count per gadget name */
8338
+ activeCountByGadget = /* @__PURE__ */ new Map();
8339
+ /** Queue of gadgets waiting for a concurrency slot (per gadget name) */
8340
+ concurrencyQueue = /* @__PURE__ */ new Map();
8334
8341
  // Cross-iteration dependency tracking
8335
8342
  /** Invocation IDs completed in previous iterations (read-only reference from Agent) */
8336
8343
  priorCompletedInvocations;
@@ -8346,6 +8353,7 @@ var init_stream_processor = __esm({
8346
8353
  this.baseDepth = options.baseDepth ?? 0;
8347
8354
  this.priorCompletedInvocations = options.priorCompletedInvocations ?? /* @__PURE__ */ new Set();
8348
8355
  this.priorFailedInvocations = options.priorFailedInvocations ?? /* @__PURE__ */ new Set();
8356
+ this.subagentConfig = options.subagentConfig;
8349
8357
  this.parser = new GadgetCallParser({
8350
8358
  startPrefix: options.gadgetStartPrefix,
8351
8359
  endPrefix: options.gadgetEndPrefix,
@@ -8609,9 +8617,63 @@ var init_stream_processor = __esm({
8609
8617
  }
8610
8618
  return;
8611
8619
  }
8612
- const executionPromise = this.executeGadgetAndCollect(call);
8620
+ const limit = this.getConcurrencyLimit(call.gadgetName);
8621
+ const activeCount = this.activeCountByGadget.get(call.gadgetName) ?? 0;
8622
+ if (limit > 0 && activeCount >= limit) {
8623
+ this.logger.debug("Gadget queued due to concurrency limit", {
8624
+ gadgetName: call.gadgetName,
8625
+ invocationId: call.invocationId,
8626
+ activeCount,
8627
+ limit
8628
+ });
8629
+ const queue = this.concurrencyQueue.get(call.gadgetName) ?? [];
8630
+ queue.push(call);
8631
+ this.concurrencyQueue.set(call.gadgetName, queue);
8632
+ return;
8633
+ }
8634
+ this.startGadgetWithConcurrencyTracking(call);
8635
+ }
8636
+ /**
8637
+ * Get the concurrency limit for a gadget from subagent config.
8638
+ * Returns 0 if no limit is set (unlimited).
8639
+ */
8640
+ getConcurrencyLimit(gadgetName) {
8641
+ const config = this.subagentConfig?.[gadgetName];
8642
+ return config?.maxConcurrent ?? 0;
8643
+ }
8644
+ /**
8645
+ * Start a gadget execution with concurrency tracking.
8646
+ * Increments active count, starts execution, and schedules queue processing on completion.
8647
+ */
8648
+ startGadgetWithConcurrencyTracking(call) {
8649
+ const gadgetName = call.gadgetName;
8650
+ const currentCount = this.activeCountByGadget.get(gadgetName) ?? 0;
8651
+ this.activeCountByGadget.set(gadgetName, currentCount + 1);
8652
+ const executionPromise = this.executeGadgetAndCollect(call).finally(() => {
8653
+ const newCount = (this.activeCountByGadget.get(gadgetName) ?? 1) - 1;
8654
+ this.activeCountByGadget.set(gadgetName, newCount);
8655
+ this.processQueuedGadget(gadgetName);
8656
+ });
8613
8657
  this.inFlightExecutions.set(call.invocationId, executionPromise);
8614
8658
  }
8659
+ /**
8660
+ * Process the next queued gadget for a given gadget name if a slot is available.
8661
+ */
8662
+ processQueuedGadget(gadgetName) {
8663
+ const queue = this.concurrencyQueue.get(gadgetName);
8664
+ if (!queue || queue.length === 0) return;
8665
+ const limit = this.getConcurrencyLimit(gadgetName);
8666
+ const activeCount = this.activeCountByGadget.get(gadgetName) ?? 0;
8667
+ if (limit === 0 || activeCount < limit) {
8668
+ const nextCall = queue.shift();
8669
+ this.logger.debug("Processing queued gadget", {
8670
+ gadgetName,
8671
+ invocationId: nextCall.invocationId,
8672
+ remainingInQueue: queue.length
8673
+ });
8674
+ this.startGadgetWithConcurrencyTracking(nextCall);
8675
+ }
8676
+ }
8615
8677
  /**
8616
8678
  * Execute a gadget through the full hook lifecycle and yield events.
8617
8679
  * Handles parameter interception, before/after controllers, observers,
@@ -8799,27 +8861,58 @@ var init_stream_processor = __esm({
8799
8861
  * Clears the inFlightExecutions map after all gadgets complete.
8800
8862
  */
8801
8863
  async *waitForInFlightExecutions() {
8802
- if (this.inFlightExecutions.size === 0) {
8864
+ if (this.inFlightExecutions.size === 0 && !this.hasQueuedGadgets()) {
8803
8865
  return;
8804
8866
  }
8805
8867
  this.logger.debug("Waiting for in-flight gadget executions", {
8806
8868
  count: this.inFlightExecutions.size,
8807
- invocationIds: Array.from(this.inFlightExecutions.keys())
8869
+ invocationIds: Array.from(this.inFlightExecutions.keys()),
8870
+ queuedCount: this.getQueuedGadgetCount()
8808
8871
  });
8809
- const allDone = Promise.all(this.inFlightExecutions.values()).then(() => "done");
8810
8872
  const POLL_INTERVAL_MS = 100;
8811
- while (true) {
8873
+ while (this.inFlightExecutions.size > 0 || this.hasQueuedGadgets()) {
8874
+ const allDone = this.inFlightExecutions.size > 0 ? Promise.all(this.inFlightExecutions.values()).then(() => "done") : Promise.resolve("done");
8812
8875
  const result = await Promise.race([
8813
8876
  allDone,
8814
8877
  new Promise((resolve) => setTimeout(() => resolve("poll"), POLL_INTERVAL_MS))
8815
8878
  ]);
8816
8879
  yield* this.drainCompletedResults();
8817
- if (result === "done") {
8880
+ if (result === "done" && this.getTotalActiveGadgetCount() === 0 && !this.hasQueuedGadgets()) {
8818
8881
  break;
8819
8882
  }
8820
8883
  }
8821
8884
  this.inFlightExecutions.clear();
8822
8885
  }
8886
+ /**
8887
+ * Check if there are any gadgets waiting in concurrency queues.
8888
+ */
8889
+ hasQueuedGadgets() {
8890
+ for (const queue of this.concurrencyQueue.values()) {
8891
+ if (queue.length > 0) return true;
8892
+ }
8893
+ return false;
8894
+ }
8895
+ /**
8896
+ * Get total count of queued gadgets across all queues.
8897
+ */
8898
+ getQueuedGadgetCount() {
8899
+ let count = 0;
8900
+ for (const queue of this.concurrencyQueue.values()) {
8901
+ count += queue.length;
8902
+ }
8903
+ return count;
8904
+ }
8905
+ /**
8906
+ * Get total count of actively executing gadgets across all types.
8907
+ * Used to know when all work is truly complete (not just when allDone resolves).
8908
+ */
8909
+ getTotalActiveGadgetCount() {
8910
+ let total = 0;
8911
+ for (const count of this.activeCountByGadget.values()) {
8912
+ total += count;
8913
+ }
8914
+ return total;
8915
+ }
8823
8916
  /**
8824
8917
  * Handle a gadget that cannot execute because a dependency failed.
8825
8918
  * Calls the onDependencySkipped controller to allow customization.
@@ -10649,6 +10742,9 @@ var init_builder = __esm({
10649
10742
  * **Signal Forwarding** - When parent context includes a signal, it's automatically
10650
10743
  * forwarded to the subagent for proper cancellation propagation.
10651
10744
  *
10745
+ * **Logger Inheritance** - When parent context includes a logger, it's inherited
10746
+ * by the subagent for consistent structured logging.
10747
+ *
10652
10748
  * @param ctx - ExecutionContext passed to the gadget's execute() method
10653
10749
  * @param depth - Nesting depth (default: 1 for direct child)
10654
10750
  * @returns This builder for chaining
@@ -10688,6 +10784,9 @@ var init_builder = __esm({
10688
10784
  if (ctx.signal && !this.signal) {
10689
10785
  this.signal = ctx.signal;
10690
10786
  }
10787
+ if (ctx.logger && !this.logger) {
10788
+ this.logger = ctx.logger;
10789
+ }
10691
10790
  return this;
10692
10791
  }
10693
10792
  /**