stratagate-dsh 0.2.78 → 0.2.79

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/plugin.js CHANGED
@@ -5751,6 +5751,7 @@ var DshModelBridge = class {
5751
5751
  this.structuredReasoningEffort = config.structuredReasoningEffort ?? "auto";
5752
5752
  this.ctx.on?.("llm/adapters-updated", () => {
5753
5753
  this.offCapabilities.clear();
5754
+ for (const listener of this.adaptersUpdatedListeners) listener();
5754
5755
  });
5755
5756
  }
5756
5757
  ctx;
@@ -5759,7 +5760,24 @@ var DshModelBridge = class {
5759
5760
  successfulResponses = [];
5760
5761
  offCapabilities = /* @__PURE__ */ new Map();
5761
5762
  warnedOffFallbackRoutes = /* @__PURE__ */ new Set();
5763
+ adaptersUpdatedListeners = /* @__PURE__ */ new Set();
5762
5764
  structuredReasoningEffort;
5765
+ /** True only when the exact provider route has a registered DSH adapter. */
5766
+ isReady(session) {
5767
+ try {
5768
+ const { provider } = this.resolveRoute(session);
5769
+ return this.ctx.llm.listProviders().some(({ id }) => id === provider);
5770
+ } catch {
5771
+ return false;
5772
+ }
5773
+ }
5774
+ /** Wake durable workers when DSH changes the adapter registry. */
5775
+ onAdaptersUpdated(listener) {
5776
+ this.adaptersUpdatedListeners.add(listener);
5777
+ return () => {
5778
+ this.adaptersUpdatedListeners.delete(listener);
5779
+ };
5780
+ }
5763
5781
  setStructuredReasoningEffort(mode) {
5764
5782
  this.structuredReasoningEffort = mode;
5765
5783
  }
@@ -5970,6 +5988,7 @@ var DshModelBridge = class {
5970
5988
  let lastError;
5971
5989
  let lastResponse = "";
5972
5990
  let attemptsUsed = 0;
5991
+ let noAdapterRetried = false;
5973
5992
  for (let attempt = 1; attempt <= JSON_RESPONSE_ATTEMPTS; attempt += 1) {
5974
5993
  attemptsUsed = attempt;
5975
5994
  const message = createUserMessage({
@@ -6000,6 +6019,11 @@ ${JSON_RETRY_INSTRUCTION}`,
6000
6019
  try {
6001
6020
  await this.consumeStructuredStream(request, assembler);
6002
6021
  } catch (error) {
6022
+ if (!noAdapterRetried && isNoAdapter(error)) {
6023
+ noAdapterRetried = true;
6024
+ attempt -= 1;
6025
+ continue;
6026
+ }
6003
6027
  if (useOff && isOffRejection(error)) {
6004
6028
  this.offCapabilities.set(routeKey, "unsupported");
6005
6029
  useOff = false;
@@ -6012,6 +6036,11 @@ ${JSON_RETRY_INSTRUCTION}`,
6012
6036
  const finish = assembler.finish;
6013
6037
  if (finish.kind === "error" || finish.kind === "aborted") {
6014
6038
  const failure = new Error(`StrataGate model call failed [${finish.failure.code}]: ${finish.failure.message}`);
6039
+ if (!noAdapterRetried && isNoAdapter(finish.failure)) {
6040
+ noAdapterRetried = true;
6041
+ attempt -= 1;
6042
+ continue;
6043
+ }
6015
6044
  if (useOff && isOffRejection(finish.failure)) {
6016
6045
  this.offCapabilities.set(routeKey, "unsupported");
6017
6046
  useOff = false;
@@ -6177,6 +6206,17 @@ ${JSON_RETRY_INSTRUCTION}`,
6177
6206
  return { provider: fallback.provider, model: fallback.model };
6178
6207
  }
6179
6208
  };
6209
+ function isNoAdapter(error) {
6210
+ const seen = /* @__PURE__ */ new Set();
6211
+ let current = error;
6212
+ while (current && typeof current === "object" && !seen.has(current)) {
6213
+ seen.add(current);
6214
+ const candidate = current;
6215
+ if (candidate.code === "NO_ADAPTER") return true;
6216
+ current = candidate.cause;
6217
+ }
6218
+ return false;
6219
+ }
6180
6220
  function isOffRejection(error) {
6181
6221
  let detail;
6182
6222
  try {
@@ -6618,6 +6658,7 @@ var StrataGateRuntime = class {
6618
6658
  this.openPath = openPath;
6619
6659
  this.blockTurnSize = config.blockTurnSize;
6620
6660
  this.blockDecayLambda = config.blockDecayLambda;
6661
+ this.disposeAdaptersUpdated = this.models.onAdaptersUpdated(() => this.wakeModelWorkers());
6621
6662
  this.scheduleBackgroundWorker(BACKGROUND_WORKER_INITIAL_DELAY_MS);
6622
6663
  }
6623
6664
  config;
@@ -6632,6 +6673,7 @@ var StrataGateRuntime = class {
6632
6673
  latestBatchIds = /* @__PURE__ */ new Map();
6633
6674
  workspaceNames = /* @__PURE__ */ new Map();
6634
6675
  migrationTimers = /* @__PURE__ */ new Map();
6676
+ migrationRuns = /* @__PURE__ */ new Map();
6635
6677
  derivationTimers = /* @__PURE__ */ new Map();
6636
6678
  derivationRuns = /* @__PURE__ */ new Map();
6637
6679
  knownSessions = /* @__PURE__ */ new Map();
@@ -6650,6 +6692,8 @@ var StrataGateRuntime = class {
6650
6692
  backgroundNamespaceRuns = /* @__PURE__ */ new Map();
6651
6693
  backgroundWorkerTimer;
6652
6694
  backgroundWorkerRun;
6695
+ backgroundWorkerWakePending = false;
6696
+ disposeAdaptersUpdated;
6653
6697
  settingsTail = Promise.resolve();
6654
6698
  batchSequence = 0;
6655
6699
  closed = false;
@@ -6665,13 +6709,15 @@ var StrataGateRuntime = class {
6665
6709
  this.backgroundWorkerRun = run;
6666
6710
  void run.finally(() => {
6667
6711
  if (this.backgroundWorkerRun === run) this.backgroundWorkerRun = void 0;
6668
- this.scheduleBackgroundWorker(BACKGROUND_WORKER_INTERVAL_MS);
6712
+ const delay = this.backgroundWorkerWakePending ? 0 : BACKGROUND_WORKER_INTERVAL_MS;
6713
+ this.backgroundWorkerWakePending = false;
6714
+ this.scheduleBackgroundWorker(delay);
6669
6715
  });
6670
6716
  }, delayMs);
6671
6717
  this.backgroundWorkerTimer.unref?.();
6672
6718
  }
6673
6719
  async runBackgroundWorker() {
6674
- if (this.closed) return;
6720
+ if (this.closed || !this.models.isReady()) return;
6675
6721
  let namespaces;
6676
6722
  try {
6677
6723
  namespaces = await this.adminNamespaces();
@@ -6689,6 +6735,7 @@ var StrataGateRuntime = class {
6689
6735
  }
6690
6736
  }
6691
6737
  async runBackgroundNamespace(namespace) {
6738
+ if (this.closed || !this.models.isReady()) return;
6692
6739
  const existing = this.backgroundNamespaceRuns.get(namespace);
6693
6740
  if (existing) return existing;
6694
6741
  const run = (async () => {
@@ -6704,9 +6751,11 @@ var StrataGateRuntime = class {
6704
6751
  const hasActiveSessionWork = [
6705
6752
  ...this.derivationTimers.keys(),
6706
6753
  ...this.derivationRuns.keys(),
6707
- ...this.migrationTimers.keys()
6754
+ ...this.migrationTimers.keys(),
6755
+ ...this.migrationRuns.keys()
6708
6756
  ].some((key) => key.startsWith(`${namespace}\0`) || key === namespace);
6709
6757
  if (hasActiveSessionWork) return;
6758
+ if (!this.models.isReady()) return;
6710
6759
  const resumed = await this.models.runDetached(
6711
6760
  `stratagate-worker:${namespace}`,
6712
6761
  () => memory.resumePendingWork()
@@ -6734,6 +6783,33 @@ var StrataGateRuntime = class {
6734
6783
  if (this.backgroundNamespaceRuns.get(namespace) === run) this.backgroundNamespaceRuns.delete(namespace);
6735
6784
  }
6736
6785
  }
6786
+ wakeBackgroundWorker() {
6787
+ if (this.closed) return;
6788
+ if (this.backgroundWorkerTimer) {
6789
+ clearTimeout(this.backgroundWorkerTimer);
6790
+ this.backgroundWorkerTimer = void 0;
6791
+ }
6792
+ if (this.backgroundWorkerRun) {
6793
+ this.backgroundWorkerWakePending = true;
6794
+ return;
6795
+ }
6796
+ this.scheduleBackgroundWorker(0);
6797
+ }
6798
+ wakeModelWorkers() {
6799
+ if (this.closed) return;
6800
+ this.wakeBackgroundWorker();
6801
+ for (const reference of this.knownSessions.values()) {
6802
+ const session = reference.deref();
6803
+ if (!session || !this.models.isReady(session)) continue;
6804
+ const opening = this.spaces.get(this.namespaceFor(session));
6805
+ if (!opening) continue;
6806
+ void opening.then((memory) => {
6807
+ if (this.closed || !this.models.isReady(session)) return;
6808
+ this.scheduleGraphMigration(session, memory);
6809
+ this.scheduleBlockDerivation(session, memory);
6810
+ }).catch((error) => this.onIngestError(error));
6811
+ }
6812
+ }
6737
6813
  acceptEvent(session, event) {
6738
6814
  if (this.closed) return;
6739
6815
  if (!this.config.ingestSubagents && session.header.origin === "subagent") return;
@@ -7217,6 +7293,7 @@ var StrataGateRuntime = class {
7217
7293
  async close() {
7218
7294
  if (this.closed) return;
7219
7295
  this.closed = true;
7296
+ this.disposeAdaptersUpdated();
7220
7297
  if (this.backgroundWorkerTimer) clearTimeout(this.backgroundWorkerTimer);
7221
7298
  this.backgroundWorkerTimer = void 0;
7222
7299
  for (const timer of this.migrationTimers.values()) clearTimeout(timer);
@@ -7234,6 +7311,7 @@ var StrataGateRuntime = class {
7234
7311
  const settled = await Promise.allSettled(this.spaces.values());
7235
7312
  await Promise.allSettled(this.backgroundNamespaceRuns.values());
7236
7313
  if (this.backgroundWorkerRun) await Promise.allSettled([this.backgroundWorkerRun]);
7314
+ await Promise.allSettled(this.migrationRuns.values());
7237
7315
  await Promise.allSettled(this.derivationRuns.values());
7238
7316
  await Promise.allSettled(this.externalImportRuns.values());
7239
7317
  await Promise.all(settled.flatMap((result) => result.status === "fulfilled" ? [result.value.close()] : []));
@@ -7770,6 +7848,9 @@ var StrataGateRuntime = class {
7770
7848
  if (kind === "event-extraction") return memory.retryEventExtraction(jobId);
7771
7849
  return memory.retryGraphProjection(jobId);
7772
7850
  };
7851
+ if (!this.models.isReady(session)) {
7852
+ throw new Error("StrataGate model adapter is not ready; retry after DSH finishes registering adapters");
7853
+ }
7773
7854
  const result = session && this.namespaceFor(session) === key ? await this.models.run(session, retry) : await this.models.runDetached(threadId, retry);
7774
7855
  await this.persistSuccessfulResponses(memory);
7775
7856
  const currentBlock = blockId ? memory.listBlocks().find(({ id: candidateId }) => candidateId === blockId) : void 0;
@@ -7969,7 +8050,7 @@ var StrataGateRuntime = class {
7969
8050
  scheduleBlockDerivation(session, memory) {
7970
8051
  const threadId = String(session.id);
7971
8052
  const key = `${this.namespaceFor(session)}\0${threadId}`;
7972
- if (this.closed || this.derivationTimers.has(key) || this.derivationRuns.has(key)) return;
8053
+ if (this.closed || !this.models.isReady(session) || this.derivationTimers.has(key) || this.derivationRuns.has(key)) return;
7973
8054
  const pendingBlockIds = new Set(memory.listBlocks().filter((block) => block.threadId === threadId && block.processingStatus === "pending").map((block) => block.id));
7974
8055
  if (pendingBlockIds.size === 0) return;
7975
8056
  const retryTimes = [
@@ -7980,7 +8061,7 @@ var StrataGateRuntime = class {
7980
8061
  const delay = Math.max(0, Math.min(...retryTimes) - Date.now());
7981
8062
  const timer = setTimeout(() => {
7982
8063
  this.derivationTimers.delete(key);
7983
- if (this.closed) return;
8064
+ if (this.closed || !this.models.isReady(session)) return;
7984
8065
  const failedBefore = this.failedCoreJobs(memory);
7985
8066
  const run = this.models.run(session, () => memory.resumePendingWork({ threadId })).then(async (resumed) => {
7986
8067
  await this.persistSuccessfulResponses(memory);
@@ -8008,24 +8089,29 @@ var StrataGateRuntime = class {
8008
8089
  }
8009
8090
  scheduleGraphMigration(session, memory) {
8010
8091
  const namespace = this.namespaceFor(session);
8011
- if (this.closed || this.migrationTimers.has(namespace)) return;
8092
+ if (this.closed || !this.models.isReady(session) || this.migrationTimers.has(namespace) || this.migrationRuns.has(namespace)) return;
8012
8093
  if (typeof memory.listGraphProjectionJobs !== "function") return;
8013
8094
  const pending = memory.listGraphProjectionJobs().some((job) => graphProjectionCanRun(job));
8014
8095
  if (!pending) return;
8015
8096
  const timer = setTimeout(() => {
8016
8097
  this.migrationTimers.delete(namespace);
8017
- if (this.closed) return;
8098
+ if (this.closed || !this.models.isReady(session)) return;
8018
8099
  const failedBefore = this.failedCoreJobs(memory);
8019
8100
  const completedBefore = memory.listGraphProjectionJobs().filter(({ status }) => status === "completed").length;
8020
- void this.models.run(session, () => memory.resumePendingWork()).then(async () => {
8101
+ let madeProgress = false;
8102
+ const run = this.models.run(session, () => memory.resumePendingWork()).then(async () => {
8021
8103
  await this.persistSuccessfulResponses(memory);
8022
8104
  this.noteNewCoreJobFailures(session, failedBefore, memory);
8023
8105
  const completedAfter = memory.listGraphProjectionJobs().filter(({ status }) => status === "completed").length;
8024
- if (completedAfter > completedBefore) this.scheduleGraphMigration(session, memory);
8106
+ madeProgress = completedAfter > completedBefore;
8025
8107
  }).catch((error) => {
8026
8108
  this.notePluginError(session, error);
8027
8109
  this.onIngestError(error);
8110
+ }).finally(() => {
8111
+ if (this.migrationRuns.get(namespace) === run) this.migrationRuns.delete(namespace);
8112
+ if (madeProgress) this.scheduleGraphMigration(session, memory);
8028
8113
  });
8114
+ this.migrationRuns.set(namespace, run);
8029
8115
  }, 1500);
8030
8116
  timer.unref?.();
8031
8117
  this.migrationTimers.set(namespace, timer);