llmist 16.2.0 → 16.2.1

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
@@ -13964,8 +13964,9 @@ var init_parser2 = __esm({
13964
13964
  * - `GadgetName` - Auto-generate ID, no dependencies
13965
13965
  * - `GadgetName:my_id` - Explicit ID, no dependencies
13966
13966
  * - `GadgetName:my_id:dep1,dep2` - Explicit ID with dependencies
13967
+ * - `GadgetName:my_id:dep1:dep2:dep3` - Colons treated as dep separators (LLM resilience)
13967
13968
  *
13968
- * Dependencies must be comma-separated invocation IDs.
13969
+ * Dependencies can be comma-separated or colon-separated invocation IDs.
13969
13970
  */
13970
13971
  parseInvocationMetadata(headerLine) {
13971
13972
  const parts = headerLine.split(":");
@@ -13982,7 +13983,12 @@ var init_parser2 = __esm({
13982
13983
  dependencies: []
13983
13984
  };
13984
13985
  } else {
13985
- const deps = parts[2].split(",").map((d) => d.trim()).filter((d) => d.length > 0);
13986
+ const depsRaw = parts.slice(2).join(",");
13987
+ const deps = [
13988
+ ...new Set(
13989
+ depsRaw.split(",").map((d) => d.trim()).filter((d) => d.length > 0)
13990
+ )
13991
+ ];
13986
13992
  return {
13987
13993
  gadgetName: parts[0],
13988
13994
  invocationId: parts[1].trim(),
@@ -14555,6 +14561,8 @@ var init_gadget_concurrency_manager = __esm({
14555
14561
  concurrencyQueue = /* @__PURE__ */ new Map();
14556
14562
  /** All active gadget promises, keyed by invocationId */
14557
14563
  inFlightExecutions = /* @__PURE__ */ new Map();
14564
+ /** Gadget name for each in-flight invocationId (for timeout event emission) */
14565
+ inFlightGadgetNames = /* @__PURE__ */ new Map();
14558
14566
  /** Queue of exclusive gadgets deferred until in-flight gadgets complete */
14559
14567
  exclusiveQueue = [];
14560
14568
  constructor(options) {
@@ -14682,6 +14690,7 @@ var init_gadget_concurrency_manager = __esm({
14682
14690
  const currentCount = this.activeCountByGadget.get(gadgetName) ?? 0;
14683
14691
  this.activeCountByGadget.set(gadgetName, currentCount + 1);
14684
14692
  this.inFlightExecutions.set(invocationId, promise);
14693
+ this.inFlightGadgetNames.set(invocationId, gadgetName);
14685
14694
  }
14686
14695
  /**
14687
14696
  * Called when a gadget execution completes.
@@ -14725,11 +14734,25 @@ var init_gadget_concurrency_manager = __esm({
14725
14734
  this.exclusiveQueue.push(call);
14726
14735
  }
14727
14736
  /**
14728
- * Clear the inFlightExecutions map after all promises have completed.
14729
- * Called after waitForAll resolves.
14737
+ * Clear all in-flight tracking state.
14738
+ * Called after all promises have completed, or on force-timeout.
14739
+ * Also clears active gadget counts to prevent stale state when
14740
+ * hanging promises eventually resolve into the void.
14730
14741
  */
14731
14742
  clearInFlight() {
14732
14743
  this.inFlightExecutions.clear();
14744
+ this.inFlightGadgetNames.clear();
14745
+ this.activeCountByGadget.clear();
14746
+ }
14747
+ /**
14748
+ * Get metadata for all currently in-flight executions.
14749
+ * Used by the dispatcher to emit skip events when the in-flight timeout fires.
14750
+ */
14751
+ getInFlightEntries() {
14752
+ return Array.from(this.inFlightGadgetNames.entries()).map(([invocationId, gadgetName]) => ({
14753
+ invocationId,
14754
+ gadgetName
14755
+ }));
14733
14756
  }
14734
14757
  // ==========================================================================
14735
14758
  // Waiting
@@ -15054,6 +15077,7 @@ var init_gadget_dispatcher = __esm({
15054
15077
  logger;
15055
15078
  pushToQueue;
15056
15079
  drainQueue;
15080
+ inFlightTimeoutMs;
15057
15081
  constructor(options) {
15058
15082
  this.iteration = options.iteration;
15059
15083
  this.hookLifecycle = options.hookLifecycle;
@@ -15068,6 +15092,7 @@ var init_gadget_dispatcher = __esm({
15068
15092
  this.logger = options.logger ?? createLogger({ name: "llmist:gadget-dispatcher" });
15069
15093
  this.pushToQueue = options.pushToQueue;
15070
15094
  this.drainQueue = options.drainQueue;
15095
+ this.inFlightTimeoutMs = options.inFlightTimeoutMs ?? 3e5;
15071
15096
  }
15072
15097
  // ==========================================================================
15073
15098
  // Primary dispatch entry point
@@ -15099,39 +15124,54 @@ var init_gadget_dispatcher = __esm({
15099
15124
  parentId: this.parentNodeId
15100
15125
  });
15101
15126
  }
15127
+ let effectiveCall = call;
15102
15128
  if (call.dependencies.length > 0) {
15103
- if (call.dependencies.includes(call.invocationId)) {
15104
- this.logger.warn("Gadget has self-referential dependency (depends on itself)", {
15129
+ const selfRefs = [];
15130
+ const validDeps = [];
15131
+ for (const dep of call.dependencies) {
15132
+ (dep === call.invocationId ? selfRefs : validDeps).push(dep);
15133
+ }
15134
+ if (selfRefs.length > 0) {
15135
+ this.logger.warn("Filtering self-referential dependencies", {
15105
15136
  gadgetName: call.gadgetName,
15106
- invocationId: call.invocationId
15137
+ invocationId: call.invocationId,
15138
+ removedSelfRefs: selfRefs,
15139
+ remainingDeps: validDeps
15107
15140
  });
15108
- const errorMessage = `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`;
15109
- for await (const evt of this.emitGadgetSkipEvents(call, call.invocationId, errorMessage)) {
15110
- yield evt;
15141
+ effectiveCall = { ...call, dependencies: validDeps };
15142
+ if (validDeps.length === 0) {
15143
+ const errorMessage = `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`;
15144
+ for await (const evt of this.emitGadgetSkipEvents(
15145
+ effectiveCall,
15146
+ call.invocationId,
15147
+ errorMessage
15148
+ )) {
15149
+ yield evt;
15150
+ }
15151
+ return;
15111
15152
  }
15112
- return;
15113
15153
  }
15114
- const failedDep = this.dependencyResolver.getFailedDependency(call);
15154
+ const failedDep = this.dependencyResolver.getFailedDependency(effectiveCall);
15115
15155
  if (failedDep) {
15116
- const skipEvents = await this.handleFailedDependency(call, failedDep);
15156
+ const skipEvents = await this.handleFailedDependency(effectiveCall, failedDep);
15117
15157
  for (const evt of skipEvents) {
15118
15158
  yield evt;
15119
15159
  }
15120
15160
  return;
15121
15161
  }
15122
- if (!this.dependencyResolver.isAllSatisfied(call)) {
15123
- const unsatisfied = call.dependencies.filter(
15162
+ if (!this.dependencyResolver.isAllSatisfied(effectiveCall)) {
15163
+ const unsatisfied = effectiveCall.dependencies.filter(
15124
15164
  (dep) => !this.dependencyResolver.isCompleted(dep)
15125
15165
  );
15126
15166
  this.logger.debug("Queueing gadget for later - waiting on dependencies", {
15127
- gadgetName: call.gadgetName,
15128
- invocationId: call.invocationId,
15167
+ gadgetName: effectiveCall.gadgetName,
15168
+ invocationId: effectiveCall.invocationId,
15129
15169
  waitingOn: unsatisfied
15130
15170
  });
15131
- this.dependencyResolver.addPending(call);
15171
+ this.dependencyResolver.addPending(effectiveCall);
15132
15172
  return;
15133
15173
  }
15134
- for await (const evt of this._checkLimitThenExecute(call)) {
15174
+ for await (const evt of this._checkLimitThenExecute(effectiveCall)) {
15135
15175
  yield evt;
15136
15176
  }
15137
15177
  for await (const evt of this.processPendingGadgets()) {
@@ -15270,7 +15310,31 @@ var init_gadget_dispatcher = __esm({
15270
15310
  queuedCount: this.concurrencyManager.getQueuedGadgetCount()
15271
15311
  });
15272
15312
  const POLL_INTERVAL_MS = 100;
15313
+ const startTime = Date.now();
15273
15314
  while (this.concurrencyManager.inFlightCount > 0 || this.concurrencyManager.hasQueuedGadgets()) {
15315
+ if (Date.now() - startTime >= this.inFlightTimeoutMs) {
15316
+ const timedOutEntries = this.concurrencyManager.getInFlightEntries();
15317
+ this.logger.error("In-flight gadget timeout exceeded, force-clearing remaining gadgets", {
15318
+ timeoutMs: this.inFlightTimeoutMs,
15319
+ remainingInFlight: timedOutEntries.length,
15320
+ remainingQueued: this.concurrencyManager.getQueuedGadgetCount(),
15321
+ timedOutInvocations: timedOutEntries.map((e) => e.invocationId)
15322
+ });
15323
+ const timeoutError = `Gadget execution timed out after ${this.inFlightTimeoutMs}ms`;
15324
+ for (const { invocationId, gadgetName } of timedOutEntries) {
15325
+ this.dependencyResolver.markFailed(invocationId);
15326
+ yield {
15327
+ type: "gadget_skipped",
15328
+ gadgetName,
15329
+ invocationId,
15330
+ parameters: {},
15331
+ failedDependency: invocationId,
15332
+ failedDependencyError: timeoutError
15333
+ };
15334
+ }
15335
+ this.concurrencyManager.clearInFlight();
15336
+ break;
15337
+ }
15274
15338
  const allDone = this.concurrencyManager.getAllDonePromise();
15275
15339
  const result = await Promise.race([
15276
15340
  allDone,
@@ -15856,7 +15920,8 @@ var init_stream_processor = __esm({
15856
15920
  const evts = [...this.completedResultsQueue];
15857
15921
  this.completedResultsQueue = [];
15858
15922
  return evts;
15859
- }
15923
+ },
15924
+ inFlightTimeoutMs: options.inFlightTimeoutMs
15860
15925
  });
15861
15926
  }
15862
15927
  /**
@@ -16080,6 +16145,7 @@ var init_stream_processor_factory = __esm({
16080
16145
  logger;
16081
16146
  requestHumanInput;
16082
16147
  defaultGadgetTimeoutMs;
16148
+ inFlightTimeoutMs;
16083
16149
  gadgetExecutionMode;
16084
16150
  client;
16085
16151
  mediaStore;
@@ -16098,6 +16164,7 @@ var init_stream_processor_factory = __esm({
16098
16164
  this.logger = options.logger;
16099
16165
  this.requestHumanInput = options.requestHumanInput;
16100
16166
  this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
16167
+ this.inFlightTimeoutMs = options.inFlightTimeoutMs;
16101
16168
  this.gadgetExecutionMode = options.gadgetExecutionMode;
16102
16169
  this.client = options.client;
16103
16170
  this.mediaStore = options.mediaStore;
@@ -16129,6 +16196,7 @@ var init_stream_processor_factory = __esm({
16129
16196
  logger: this.logger.getSubLogger({ name: "stream-processor" }),
16130
16197
  requestHumanInput: this.requestHumanInput,
16131
16198
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
16199
+ inFlightTimeoutMs: this.inFlightTimeoutMs,
16132
16200
  gadgetExecutionMode: this.gadgetExecutionMode,
16133
16201
  client: this.client,
16134
16202
  mediaStore: this.mediaStore,