llmist 16.2.0 → 16.2.2

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.cts CHANGED
@@ -7676,6 +7676,8 @@ interface StreamProcessorOptions {
7676
7676
  requestHumanInput?: (question: string) => Promise<string>;
7677
7677
  /** Default gadget timeout */
7678
7678
  defaultGadgetTimeoutMs?: number;
7679
+ /** Maximum time (ms) to wait for in-flight gadgets to complete. Default: 300s. */
7680
+ inFlightTimeoutMs?: number;
7679
7681
  /** Gadget execution mode ('parallel' | 'sequential') */
7680
7682
  gadgetExecutionMode?: GadgetExecutionMode;
7681
7683
  /** LLMist client for ExecutionContext.llmist */
@@ -8570,8 +8572,9 @@ declare class GadgetCallParser {
8570
8572
  * - `GadgetName` - Auto-generate ID, no dependencies
8571
8573
  * - `GadgetName:my_id` - Explicit ID, no dependencies
8572
8574
  * - `GadgetName:my_id:dep1,dep2` - Explicit ID with dependencies
8575
+ * - `GadgetName:my_id:dep1:dep2:dep3` - Colons treated as dep separators (LLM resilience)
8573
8576
  *
8574
- * Dependencies must be comma-separated invocation IDs.
8577
+ * Dependencies can be comma-separated or colon-separated invocation IDs.
8575
8578
  */
8576
8579
  private parseInvocationMetadata;
8577
8580
  /**
package/dist/index.d.ts CHANGED
@@ -7676,6 +7676,8 @@ interface StreamProcessorOptions {
7676
7676
  requestHumanInput?: (question: string) => Promise<string>;
7677
7677
  /** Default gadget timeout */
7678
7678
  defaultGadgetTimeoutMs?: number;
7679
+ /** Maximum time (ms) to wait for in-flight gadgets to complete. Default: 300s. */
7680
+ inFlightTimeoutMs?: number;
7679
7681
  /** Gadget execution mode ('parallel' | 'sequential') */
7680
7682
  gadgetExecutionMode?: GadgetExecutionMode;
7681
7683
  /** LLMist client for ExecutionContext.llmist */
@@ -8570,8 +8572,9 @@ declare class GadgetCallParser {
8570
8572
  * - `GadgetName` - Auto-generate ID, no dependencies
8571
8573
  * - `GadgetName:my_id` - Explicit ID, no dependencies
8572
8574
  * - `GadgetName:my_id:dep1,dep2` - Explicit ID with dependencies
8575
+ * - `GadgetName:my_id:dep1:dep2:dep3` - Colons treated as dep separators (LLM resilience)
8573
8576
  *
8574
- * Dependencies must be comma-separated invocation IDs.
8577
+ * Dependencies can be comma-separated or colon-separated invocation IDs.
8575
8578
  */
8576
8579
  private parseInvocationMetadata;
8577
8580
  /**
package/dist/index.js CHANGED
@@ -13956,8 +13956,9 @@ var init_parser2 = __esm({
13956
13956
  * - `GadgetName` - Auto-generate ID, no dependencies
13957
13957
  * - `GadgetName:my_id` - Explicit ID, no dependencies
13958
13958
  * - `GadgetName:my_id:dep1,dep2` - Explicit ID with dependencies
13959
+ * - `GadgetName:my_id:dep1:dep2:dep3` - Colons treated as dep separators (LLM resilience)
13959
13960
  *
13960
- * Dependencies must be comma-separated invocation IDs.
13961
+ * Dependencies can be comma-separated or colon-separated invocation IDs.
13961
13962
  */
13962
13963
  parseInvocationMetadata(headerLine) {
13963
13964
  const parts = headerLine.split(":");
@@ -13974,7 +13975,12 @@ var init_parser2 = __esm({
13974
13975
  dependencies: []
13975
13976
  };
13976
13977
  } else {
13977
- const deps = parts[2].split(",").map((d) => d.trim()).filter((d) => d.length > 0);
13978
+ const depsRaw = parts.slice(2).join(",");
13979
+ const deps = [
13980
+ ...new Set(
13981
+ depsRaw.split(",").map((d) => d.trim()).filter((d) => d.length > 0)
13982
+ )
13983
+ ];
13978
13984
  return {
13979
13985
  gadgetName: parts[0],
13980
13986
  invocationId: parts[1].trim(),
@@ -14547,6 +14553,8 @@ var init_gadget_concurrency_manager = __esm({
14547
14553
  concurrencyQueue = /* @__PURE__ */ new Map();
14548
14554
  /** All active gadget promises, keyed by invocationId */
14549
14555
  inFlightExecutions = /* @__PURE__ */ new Map();
14556
+ /** Gadget name for each in-flight invocationId (for timeout event emission) */
14557
+ inFlightGadgetNames = /* @__PURE__ */ new Map();
14550
14558
  /** Queue of exclusive gadgets deferred until in-flight gadgets complete */
14551
14559
  exclusiveQueue = [];
14552
14560
  constructor(options) {
@@ -14674,6 +14682,7 @@ var init_gadget_concurrency_manager = __esm({
14674
14682
  const currentCount = this.activeCountByGadget.get(gadgetName) ?? 0;
14675
14683
  this.activeCountByGadget.set(gadgetName, currentCount + 1);
14676
14684
  this.inFlightExecutions.set(invocationId, promise);
14685
+ this.inFlightGadgetNames.set(invocationId, gadgetName);
14677
14686
  }
14678
14687
  /**
14679
14688
  * Called when a gadget execution completes.
@@ -14717,11 +14726,25 @@ var init_gadget_concurrency_manager = __esm({
14717
14726
  this.exclusiveQueue.push(call);
14718
14727
  }
14719
14728
  /**
14720
- * Clear the inFlightExecutions map after all promises have completed.
14721
- * Called after waitForAll resolves.
14729
+ * Clear all in-flight tracking state.
14730
+ * Called after all promises have completed, or on force-timeout.
14731
+ * Also clears active gadget counts to prevent stale state when
14732
+ * hanging promises eventually resolve into the void.
14722
14733
  */
14723
14734
  clearInFlight() {
14724
14735
  this.inFlightExecutions.clear();
14736
+ this.inFlightGadgetNames.clear();
14737
+ this.activeCountByGadget.clear();
14738
+ }
14739
+ /**
14740
+ * Get metadata for all currently in-flight executions.
14741
+ * Used by the dispatcher to emit skip events when the in-flight timeout fires.
14742
+ */
14743
+ getInFlightEntries() {
14744
+ return Array.from(this.inFlightGadgetNames.entries()).map(([invocationId, gadgetName]) => ({
14745
+ invocationId,
14746
+ gadgetName
14747
+ }));
14725
14748
  }
14726
14749
  // ==========================================================================
14727
14750
  // Waiting
@@ -15046,6 +15069,7 @@ var init_gadget_dispatcher = __esm({
15046
15069
  logger;
15047
15070
  pushToQueue;
15048
15071
  drainQueue;
15072
+ inFlightTimeoutMs;
15049
15073
  constructor(options) {
15050
15074
  this.iteration = options.iteration;
15051
15075
  this.hookLifecycle = options.hookLifecycle;
@@ -15060,6 +15084,7 @@ var init_gadget_dispatcher = __esm({
15060
15084
  this.logger = options.logger ?? createLogger({ name: "llmist:gadget-dispatcher" });
15061
15085
  this.pushToQueue = options.pushToQueue;
15062
15086
  this.drainQueue = options.drainQueue;
15087
+ this.inFlightTimeoutMs = options.inFlightTimeoutMs ?? 3e5;
15063
15088
  }
15064
15089
  // ==========================================================================
15065
15090
  // Primary dispatch entry point
@@ -15091,39 +15116,54 @@ var init_gadget_dispatcher = __esm({
15091
15116
  parentId: this.parentNodeId
15092
15117
  });
15093
15118
  }
15119
+ let effectiveCall = call;
15094
15120
  if (call.dependencies.length > 0) {
15095
- if (call.dependencies.includes(call.invocationId)) {
15096
- this.logger.warn("Gadget has self-referential dependency (depends on itself)", {
15121
+ const selfRefs = [];
15122
+ const validDeps = [];
15123
+ for (const dep of call.dependencies) {
15124
+ (dep === call.invocationId ? selfRefs : validDeps).push(dep);
15125
+ }
15126
+ if (selfRefs.length > 0) {
15127
+ this.logger.warn("Filtering self-referential dependencies", {
15097
15128
  gadgetName: call.gadgetName,
15098
- invocationId: call.invocationId
15129
+ invocationId: call.invocationId,
15130
+ removedSelfRefs: selfRefs,
15131
+ remainingDeps: validDeps
15099
15132
  });
15100
- const errorMessage = `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`;
15101
- for await (const evt of this.emitGadgetSkipEvents(call, call.invocationId, errorMessage)) {
15102
- yield evt;
15133
+ effectiveCall = { ...call, dependencies: validDeps };
15134
+ if (validDeps.length === 0) {
15135
+ const errorMessage = `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`;
15136
+ for await (const evt of this.emitGadgetSkipEvents(
15137
+ effectiveCall,
15138
+ call.invocationId,
15139
+ errorMessage
15140
+ )) {
15141
+ yield evt;
15142
+ }
15143
+ return;
15103
15144
  }
15104
- return;
15105
15145
  }
15106
- const failedDep = this.dependencyResolver.getFailedDependency(call);
15146
+ const failedDep = this.dependencyResolver.getFailedDependency(effectiveCall);
15107
15147
  if (failedDep) {
15108
- const skipEvents = await this.handleFailedDependency(call, failedDep);
15148
+ const skipEvents = await this.handleFailedDependency(effectiveCall, failedDep);
15109
15149
  for (const evt of skipEvents) {
15110
15150
  yield evt;
15111
15151
  }
15112
15152
  return;
15113
15153
  }
15114
- if (!this.dependencyResolver.isAllSatisfied(call)) {
15115
- const unsatisfied = call.dependencies.filter(
15154
+ if (!this.dependencyResolver.isAllSatisfied(effectiveCall)) {
15155
+ const unsatisfied = effectiveCall.dependencies.filter(
15116
15156
  (dep) => !this.dependencyResolver.isCompleted(dep)
15117
15157
  );
15118
15158
  this.logger.debug("Queueing gadget for later - waiting on dependencies", {
15119
- gadgetName: call.gadgetName,
15120
- invocationId: call.invocationId,
15159
+ gadgetName: effectiveCall.gadgetName,
15160
+ invocationId: effectiveCall.invocationId,
15121
15161
  waitingOn: unsatisfied
15122
15162
  });
15123
- this.dependencyResolver.addPending(call);
15163
+ this.dependencyResolver.addPending(effectiveCall);
15124
15164
  return;
15125
15165
  }
15126
- for await (const evt of this._checkLimitThenExecute(call)) {
15166
+ for await (const evt of this._checkLimitThenExecute(effectiveCall)) {
15127
15167
  yield evt;
15128
15168
  }
15129
15169
  for await (const evt of this.processPendingGadgets()) {
@@ -15262,7 +15302,31 @@ var init_gadget_dispatcher = __esm({
15262
15302
  queuedCount: this.concurrencyManager.getQueuedGadgetCount()
15263
15303
  });
15264
15304
  const POLL_INTERVAL_MS = 100;
15305
+ const startTime = Date.now();
15265
15306
  while (this.concurrencyManager.inFlightCount > 0 || this.concurrencyManager.hasQueuedGadgets()) {
15307
+ if (Date.now() - startTime >= this.inFlightTimeoutMs) {
15308
+ const timedOutEntries = this.concurrencyManager.getInFlightEntries();
15309
+ this.logger.error("In-flight gadget timeout exceeded, force-clearing remaining gadgets", {
15310
+ timeoutMs: this.inFlightTimeoutMs,
15311
+ remainingInFlight: timedOutEntries.length,
15312
+ remainingQueued: this.concurrencyManager.getQueuedGadgetCount(),
15313
+ timedOutInvocations: timedOutEntries.map((e) => e.invocationId)
15314
+ });
15315
+ const timeoutError = `Gadget execution timed out after ${this.inFlightTimeoutMs}ms`;
15316
+ for (const { invocationId, gadgetName } of timedOutEntries) {
15317
+ this.dependencyResolver.markFailed(invocationId);
15318
+ yield {
15319
+ type: "gadget_skipped",
15320
+ gadgetName,
15321
+ invocationId,
15322
+ parameters: {},
15323
+ failedDependency: invocationId,
15324
+ failedDependencyError: timeoutError
15325
+ };
15326
+ }
15327
+ this.concurrencyManager.clearInFlight();
15328
+ break;
15329
+ }
15266
15330
  const allDone = this.concurrencyManager.getAllDonePromise();
15267
15331
  const result = await Promise.race([
15268
15332
  allDone,
@@ -15848,7 +15912,8 @@ var init_stream_processor = __esm({
15848
15912
  const evts = [...this.completedResultsQueue];
15849
15913
  this.completedResultsQueue = [];
15850
15914
  return evts;
15851
- }
15915
+ },
15916
+ inFlightTimeoutMs: options.inFlightTimeoutMs
15852
15917
  });
15853
15918
  }
15854
15919
  /**
@@ -16072,6 +16137,7 @@ var init_stream_processor_factory = __esm({
16072
16137
  logger;
16073
16138
  requestHumanInput;
16074
16139
  defaultGadgetTimeoutMs;
16140
+ inFlightTimeoutMs;
16075
16141
  gadgetExecutionMode;
16076
16142
  client;
16077
16143
  mediaStore;
@@ -16090,6 +16156,7 @@ var init_stream_processor_factory = __esm({
16090
16156
  this.logger = options.logger;
16091
16157
  this.requestHumanInput = options.requestHumanInput;
16092
16158
  this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
16159
+ this.inFlightTimeoutMs = options.inFlightTimeoutMs;
16093
16160
  this.gadgetExecutionMode = options.gadgetExecutionMode;
16094
16161
  this.client = options.client;
16095
16162
  this.mediaStore = options.mediaStore;
@@ -16121,6 +16188,7 @@ var init_stream_processor_factory = __esm({
16121
16188
  logger: this.logger.getSubLogger({ name: "stream-processor" }),
16122
16189
  requestHumanInput: this.requestHumanInput,
16123
16190
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
16191
+ inFlightTimeoutMs: this.inFlightTimeoutMs,
16124
16192
  gadgetExecutionMode: this.gadgetExecutionMode,
16125
16193
  client: this.client,
16126
16194
  mediaStore: this.mediaStore,