@axiom-lattice/core 6.1.1 → 6.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.js CHANGED
@@ -1660,10 +1660,12 @@ __export(index_exports, {
1660
1660
  InMemoryChunkBuffer: () => InMemoryChunkBuffer,
1661
1661
  InMemoryCollectionStore: () => InMemoryCollectionStore,
1662
1662
  InMemoryDatabaseConfigStore: () => InMemoryDatabaseConfigStore,
1663
+ InMemoryLeaseStore: () => InMemoryLeaseStore,
1663
1664
  InMemoryMailboxStore: () => InMemoryMailboxStore,
1664
1665
  InMemoryMenuStore: () => InMemoryMenuStore,
1665
1666
  InMemoryModelProviderStore: () => InMemoryModelProviderStore,
1666
1667
  InMemoryOpenAuditStore: () => InMemoryOpenAuditStore,
1668
+ InMemoryOutboxStore: () => InMemoryOutboxStore,
1667
1669
  InMemoryProjectBotMembershipStore: () => InMemoryProjectBotMembershipStore,
1668
1670
  InMemoryProjectMembershipStore: () => InMemoryProjectMembershipStore,
1669
1671
  InMemoryProjectRoomCoordinator: () => InMemoryProjectRoomCoordinator,
@@ -1683,6 +1685,7 @@ __export(index_exports, {
1683
1685
  LatticeEval: () => LatticeEval,
1684
1686
  LatticeEvalProject: () => LatticeEvalProject,
1685
1687
  LatticeEvalSuite: () => LatticeEvalSuite,
1688
+ LeaseAcquisitionTimeoutError: () => LeaseAcquisitionTimeoutError,
1686
1689
  LocalSandboxInstance: () => LocalSandboxInstance,
1687
1690
  LocalSandboxProvider: () => LocalSandboxProvider,
1688
1691
  LoggerLatticeManager: () => LoggerLatticeManager,
@@ -1705,7 +1708,10 @@ __export(index_exports, {
1705
1708
  MicrosandboxServiceClient: () => MicrosandboxServiceClient,
1706
1709
  ModelLatticeManager: () => ModelLatticeManager,
1707
1710
  MysqlDatabase: () => MysqlDatabase,
1711
+ OutboxPoller: () => OutboxPoller,
1708
1712
  PACK_DIRECTORY_TIMEOUT_SECONDS: () => PACK_DIRECTORY_TIMEOUT_SECONDS,
1713
+ PLATFORM_SECRET_ENV_VARS: () => PLATFORM_SECRET_ENV_VARS,
1714
+ PLUGIN_CATALOG_CHANGED_TOPIC: () => PLUGIN_CATALOG_CHANGED_TOPIC,
1709
1715
  PersonalAssistantConfig: () => PersonalAssistantConfig,
1710
1716
  PinoLoggerClient: () => PinoLoggerClient,
1711
1717
  PluginRegistry: () => PluginRegistry,
@@ -1726,6 +1732,8 @@ __export(index_exports, {
1726
1732
  RepeatedToolCallError: () => RepeatedToolCallError,
1727
1733
  RoomAgentMessageService: () => RoomAgentMessageService,
1728
1734
  SAFE_PATH_COMPONENT: () => SAFE_PATH_COMPONENT,
1735
+ SANDBOX_OPEN_GATEWAY_URL_ENV: () => SANDBOX_OPEN_GATEWAY_URL_ENV,
1736
+ SANDBOX_OPEN_TOKEN_ENV: () => SANDBOX_OPEN_TOKEN_ENV,
1729
1737
  STTModelLattice: () => STTModelLattice,
1730
1738
  STTModelLatticeManager: () => STTModelLatticeManager,
1731
1739
  SandboxFilesystem: () => SandboxFilesystem,
@@ -1766,11 +1774,13 @@ __export(index_exports, {
1766
1774
  appendReconciliationWarning: () => appendReconciliationWarning,
1767
1775
  appendUiFence: () => appendUiFence,
1768
1776
  assertSafeUpstreamUrl: () => assertSafeUpstreamUrl,
1777
+ buildBundleFromDist: () => buildBundleFromDist,
1769
1778
  buildGrepResultsDict: () => buildGrepResultsDict,
1770
1779
  buildInput: () => buildInput,
1771
1780
  buildNamedVolumeName: () => buildNamedVolumeName,
1772
1781
  buildRemotePackDirectoryCommand: () => buildRemotePackDirectoryCommand,
1773
1782
  buildSandboxMetadataEnv: () => buildSandboxMetadataEnv,
1783
+ buildSandboxOpenEnv: () => buildSandboxOpenEnv,
1774
1784
  buildSkillFile: () => buildSkillFile,
1775
1785
  buildStateAnnotation: () => buildStateAnnotation,
1776
1786
  buildTableName: () => buildTableName,
@@ -1779,11 +1789,14 @@ __export(index_exports, {
1779
1789
  checkEmptyContent: () => checkEmptyContent,
1780
1790
  clearEncryptionKeyCache: () => clearEncryptionKeyCache,
1781
1791
  clearEvalRunService: () => clearEvalRunService,
1792
+ clearSandboxOpenCredentialProviderForTests: () => clearSandboxOpenCredentialProviderForTests,
1782
1793
  collectionLatticeManager: () => collectionLatticeManager,
1783
1794
  compileInternal: () => compileInternal,
1784
1795
  compileSandboxPlugin: () => compileSandboxPlugin,
1785
1796
  compileWorkflow: () => compileWorkflow,
1786
1797
  computeSandboxName: () => computeSandboxName,
1798
+ configureCoordinationLeaseStore: () => configureCoordinationLeaseStore,
1799
+ configurePluginCatalogSync: () => configurePluginCatalogSync,
1787
1800
  configureStores: () => configureStores,
1788
1801
  connectAllChannels: () => connectAllChannels,
1789
1802
  convertToConnection: () => convertToConnection,
@@ -1815,6 +1828,7 @@ __export(index_exports, {
1815
1828
  createSandboxResolver: () => createSandboxResolver,
1816
1829
  createSchedulerMiddleware: () => createSchedulerMiddleware,
1817
1830
  createSharePayload: () => createSharePayload,
1831
+ createShellExecTool: () => createShellExecTool,
1818
1832
  createTaskExecutionService: () => createTaskExecutionService,
1819
1833
  createTaskLifecycleService: () => createTaskLifecycleService,
1820
1834
  createTaskMiddleware: () => createTaskMiddleware,
@@ -1849,6 +1863,7 @@ __export(index_exports, {
1849
1863
  generateDirectHumanProjectId: () => generateDirectHumanProjectId,
1850
1864
  generateToken: () => generateToken,
1851
1865
  getAgentClient: () => getAgentClient,
1866
+ getAgentClientAsync: () => getAgentClientAsync,
1852
1867
  getAgentConfig: () => getAgentConfig,
1853
1868
  getAllAgentConfigs: () => getAllAgentConfigs,
1854
1869
  getAllBuiltInSkillMetas: () => getAllBuiltInSkillMetas,
@@ -1860,6 +1875,7 @@ __export(index_exports, {
1860
1875
  getCheckpointSaver: () => getCheckpointSaver,
1861
1876
  getChunkBuffer: () => getChunkBuffer,
1862
1877
  getCollectionEntryCount: () => getCollectionEntryCount,
1878
+ getCoordinationLeaseStore: () => getCoordinationLeaseStore,
1863
1879
  getEmbeddingsClient: () => getEmbeddingsClient,
1864
1880
  getEmbeddingsLattice: () => getEmbeddingsLattice,
1865
1881
  getEncryptionKey: () => getEncryptionKey,
@@ -1871,15 +1887,18 @@ __export(index_exports, {
1871
1887
  getOrCreateCollectionVectorStore: () => getOrCreateCollectionVectorStore,
1872
1888
  getPluginSkillManifestVersion: () => getPluginSkillManifestVersion,
1873
1889
  getQueueLattice: () => getQueueLattice,
1890
+ getReplicaId: () => getReplicaId,
1874
1891
  getRuntimeCapabilityConfig: () => getRuntimeCapabilityConfig,
1875
1892
  getRuntimeSkillSelection: () => getRuntimeSkillSelection,
1876
1893
  getSTTClient: () => getSTTClient,
1877
1894
  getSTTClientWithTenant: () => getSTTClientWithTenant,
1878
1895
  getSTTModelLattice: () => getSTTModelLattice,
1879
1896
  getSandBoxManager: () => getSandBoxManager,
1897
+ getSandboxOpenCredential: () => getSandboxOpenCredential,
1880
1898
  getSandboxPluginCatalog: () => getSandboxPluginCatalog,
1881
1899
  getScheduleLattice: () => getScheduleLattice,
1882
1900
  getStoreLattice: () => getStoreLattice,
1901
+ getThreadRunOwner: () => getThreadRunOwner,
1883
1902
  getToolClient: () => getToolClient,
1884
1903
  getToolClientWithTenant: () => getToolClientWithTenant,
1885
1904
  getToolDefinition: () => getToolDefinition,
@@ -1933,6 +1952,8 @@ __export(index_exports, {
1933
1952
  projectMutationMutex: () => projectMutationMutex,
1934
1953
  projectRoomPlugin: () => projectRoomPlugin,
1935
1954
  projectTaskAdmissionNotifier: () => projectTaskAdmissionNotifier,
1955
+ provisionSandboxOpenClient: () => provisionSandboxOpenClient,
1956
+ publishPluginCatalogChanged: () => publishPluginCatalogChanged,
1936
1957
  queueLatticeManager: () => queueLatticeManager,
1937
1958
  readLoopBreakerConfig: () => readLoopBreakerConfig,
1938
1959
  reconcileAllTenantTaskRuns: () => reconcileAllTenantTaskRuns,
@@ -1951,6 +1972,7 @@ __export(index_exports, {
1951
1972
  registerModelLatticeForTenant: () => registerModelLatticeForTenant,
1952
1973
  registerQueueLattice: () => registerQueueLattice,
1953
1974
  registerSTTModelLattice: () => registerSTTModelLattice,
1975
+ registerSandboxOpenCredentialProvider: () => registerSandboxOpenCredentialProvider,
1954
1976
  registerSandboxProviderType: () => registerSandboxProviderType,
1955
1977
  registerScheduleLattice: () => registerScheduleLattice,
1956
1978
  registerStoreLattice: () => registerStoreLattice,
@@ -1961,6 +1983,7 @@ __export(index_exports, {
1961
1983
  registerWorkflowRun: () => registerWorkflowRun,
1962
1984
  removeCollectionVectorStore: () => removeCollectionVectorStore,
1963
1985
  renderTemplate: () => renderTemplate,
1986
+ resetReplicaIdForTests: () => resetReplicaIdForTests,
1964
1987
  resolveEnabledPluginSkill: () => resolveEnabledPluginSkill,
1965
1988
  resolveJudgeModelKey: () => resolveJudgeModelKey,
1966
1989
  resolvePath: () => resolvePath,
@@ -1968,6 +1991,7 @@ __export(index_exports, {
1968
1991
  resolveSandboxPluginConnections: () => resolveSandboxPluginConnections,
1969
1992
  resolveTenantPluginSkill: () => resolveTenantPluginSkill,
1970
1993
  roomCoordinatorConfig: () => roomCoordinatorConfig,
1994
+ runAsLeader: () => runAsLeader,
1971
1995
  runRemotePackDirectory: () => runRemotePackDirectory,
1972
1996
  safeTaskResponseId: () => safeTaskResponseId,
1973
1997
  sandboxLatticeManager: () => sandboxLatticeManager,
@@ -1986,11 +2010,15 @@ __export(index_exports, {
1986
2010
  storeLatticeManager: () => storeLatticeManager,
1987
2011
  sttModelLatticeManager: () => sttModelLatticeManager,
1988
2012
  taskLifecycleNotifier: () => taskLifecycleNotifier,
2013
+ taskRunLeaseKey: () => taskRunLeaseKey,
1989
2014
  taskRunRegistry: () => taskRunRegistry,
2015
+ threadRunLeaseKey: () => threadRunLeaseKey,
1990
2016
  toJsonSchema: () => toJsonSchema,
1991
2017
  toSafeStateExpr: () => toSafeStateExpr,
1992
2018
  toolLatticeManager: () => toolLatticeManager,
1993
2019
  truncateIfTooLong: () => truncateIfTooLong,
2020
+ tryAcquireTaskRun: () => tryAcquireTaskRun,
2021
+ tryAcquireThreadRun: () => tryAcquireThreadRun,
1994
2022
  unregisterTeammateAgent: () => unregisterTeammateAgent,
1995
2023
  unregisterWorkflowRun: () => unregisterWorkflowRun,
1996
2024
  updateFileData: () => updateFileData,
@@ -2006,6 +2034,7 @@ __export(index_exports, {
2006
2034
  validateToolInput: () => validateToolInput,
2007
2035
  vectorStoreLatticeManager: () => vectorStoreLatticeManager,
2008
2036
  vectorStoreProviderManager: () => vectorStoreProviderManager,
2037
+ withLease: () => withLease,
2009
2038
  withTimeout: () => withTimeout2,
2010
2039
  wrapMcpToolWithUi: () => wrapMcpToolWithUi
2011
2040
  });
@@ -4099,7 +4128,7 @@ var InMemoryModelProviderStore = class {
4099
4128
  */
4100
4129
  async listProviders(tenantId2) {
4101
4130
  return Array.from(this.providers.values()).filter(
4102
- (provider) => provider.tenantId === tenantId2
4131
+ (provider2) => provider2.tenantId === tenantId2
4103
4132
  );
4104
4133
  }
4105
4134
  /**
@@ -4113,7 +4142,7 @@ var InMemoryModelProviderStore = class {
4113
4142
  */
4114
4143
  async getProviderByName(tenantId2, name) {
4115
4144
  const providers = await this.listProviders(tenantId2);
4116
- return providers.find((provider) => provider.name === name) || null;
4145
+ return providers.find((provider2) => provider2.name === name) || null;
4117
4146
  }
4118
4147
  /**
4119
4148
  * Create a new provider configuration
@@ -4297,8 +4326,8 @@ var InMemoryModelProviderStore = class {
4297
4326
  * Clear providers and models for a specific tenant
4298
4327
  */
4299
4328
  clearByTenant(tenantId2) {
4300
- for (const [key5, provider] of Array.from(this.providers.entries())) {
4301
- if (provider.tenantId === tenantId2) {
4329
+ for (const [key5, provider2] of Array.from(this.providers.entries())) {
4330
+ if (provider2.tenantId === tenantId2) {
4302
4331
  this.providers.delete(key5);
4303
4332
  }
4304
4333
  }
@@ -5174,6 +5203,123 @@ function entryKey(tenantId2, userId, endpoint) {
5174
5203
  return JSON.stringify([tenantId2, userId, endpoint]);
5175
5204
  }
5176
5205
 
5206
+ // src/store_lattice/InMemoryLeaseStore.ts
5207
+ var InMemoryLeaseStore = class {
5208
+ /**
5209
+ * @param now Injectable clock in epoch milliseconds (tests use a fake clock).
5210
+ */
5211
+ constructor(now = Date.now) {
5212
+ this.leases = /* @__PURE__ */ new Map();
5213
+ this.now = now;
5214
+ }
5215
+ /** Atomically acquires a free/expired key (or the caller's own key). */
5216
+ async tryAcquire(key5, holder, ttlMs) {
5217
+ const existing = this.leases.get(key5);
5218
+ if (existing && Date.parse(existing.expiresAt) > this.now()) {
5219
+ if (existing.holder !== holder) return false;
5220
+ this.leases.set(key5, { ...existing, expiresAt: new Date(this.now() + ttlMs).toISOString() });
5221
+ return true;
5222
+ }
5223
+ const acquiredAt = existing && existing.holder === holder ? existing.acquiredAt : new Date(this.now()).toISOString();
5224
+ this.leases.set(key5, {
5225
+ key: key5,
5226
+ holder,
5227
+ acquiredAt,
5228
+ expiresAt: new Date(this.now() + ttlMs).toISOString()
5229
+ });
5230
+ return true;
5231
+ }
5232
+ /** Extends a lease only while `holder` still owns it. */
5233
+ async renew(key5, holder, ttlMs) {
5234
+ const existing = this.leases.get(key5);
5235
+ if (!existing || existing.holder !== holder) return false;
5236
+ this.leases.set(key5, { ...existing, expiresAt: new Date(this.now() + ttlMs).toISOString() });
5237
+ return true;
5238
+ }
5239
+ /** Deletes a lease only when `holder` owns it. */
5240
+ async release(key5, holder) {
5241
+ const existing = this.leases.get(key5);
5242
+ if (!existing || existing.holder !== holder) return false;
5243
+ this.leases.delete(key5);
5244
+ return true;
5245
+ }
5246
+ /** Returns the live lease, pruning an expired one. */
5247
+ async get(key5) {
5248
+ const existing = this.leases.get(key5);
5249
+ if (!existing) return null;
5250
+ if (Date.parse(existing.expiresAt) <= this.now()) {
5251
+ this.leases.delete(key5);
5252
+ return null;
5253
+ }
5254
+ return { ...existing };
5255
+ }
5256
+ };
5257
+
5258
+ // src/store_lattice/InMemoryOutboxStore.ts
5259
+ var InMemoryOutboxStore = class {
5260
+ /**
5261
+ * Creates an in-memory outbox store.
5262
+ *
5263
+ * @param now Optional clock override (defaults to the system clock); it stamps
5264
+ * `createdAt` and is used to evaluate age-based retention.
5265
+ */
5266
+ constructor(now = () => /* @__PURE__ */ new Date()) {
5267
+ this.events = [];
5268
+ this.counter = 0;
5269
+ this.now = now;
5270
+ }
5271
+ /**
5272
+ * Appends one event, assigning the next monotonic id.
5273
+ * @param input Topic, JSON-safe payload, and authoring replica id.
5274
+ * @returns A defensive copy of the stored event.
5275
+ */
5276
+ async append(input) {
5277
+ const event = {
5278
+ id: String(++this.counter),
5279
+ topic: input.topic,
5280
+ payload: input.payload,
5281
+ originReplicaId: input.originReplicaId,
5282
+ createdAt: this.now().toISOString()
5283
+ };
5284
+ this.events.push(event);
5285
+ return { ...event };
5286
+ }
5287
+ /**
5288
+ * Lists events strictly newer than `cursor`, ascending, bounded by `limit`.
5289
+ * @param cursor Last-seen id, or `null` to read from the start.
5290
+ * @param limit Maximum number of events to return.
5291
+ * @returns Defensive copies of the matching events.
5292
+ */
5293
+ async listAfter(cursor, limit) {
5294
+ const floor = cursor === null ? 0 : Number(cursor);
5295
+ return this.events.filter((event) => Number(event.id) > floor).slice(0, limit).map((event) => ({ ...event }));
5296
+ }
5297
+ /**
5298
+ * Returns the newest event id.
5299
+ * @returns The last id, or `null` when the log is empty.
5300
+ */
5301
+ async latestId() {
5302
+ return this.events.length === 0 ? null : this.events[this.events.length - 1].id;
5303
+ }
5304
+ /**
5305
+ * Deletes events older than `olderThanMs`, evaluated against this store's clock.
5306
+ *
5307
+ * @param olderThanMs Age threshold in milliseconds.
5308
+ * @returns The number of events removed.
5309
+ */
5310
+ async pruneOlderThan(olderThanMs) {
5311
+ const cutoff = this.now().getTime() - olderThanMs;
5312
+ let removed = 0;
5313
+ for (let i = this.events.length - 1; i >= 0; i -= 1) {
5314
+ if (new Date(this.events[i].createdAt).getTime() < cutoff) {
5315
+ this.events.splice(i, 1);
5316
+ removed += 1;
5317
+ }
5318
+ }
5319
+ return removed;
5320
+ }
5321
+ };
5322
+
5177
5323
  // src/store_lattice/InMemoryUserStore.ts
5178
5324
  var InMemoryUserStore = class {
5179
5325
  constructor() {
@@ -5377,7 +5523,8 @@ function isMessageContentValue(value) {
5377
5523
 
5378
5524
  // src/store_lattice/InMemoryThreadMessageQueueStore.ts
5379
5525
  var InMemoryThreadMessageQueueStore = class {
5380
- constructor() {
5526
+ constructor(now = Date.now) {
5527
+ this.now = now;
5381
5528
  this.messages = /* @__PURE__ */ new Map();
5382
5529
  this.messageIdCounter = 0;
5383
5530
  this.capacityTail = Promise.resolve();
@@ -5484,6 +5631,36 @@ var InMemoryThreadMessageQueueStore = class {
5484
5631
  const threadMessages = this.getMessagesForThread(threadId);
5485
5632
  return threadMessages.filter((msg) => msg.status === "processing" && this.inScope(msg, scope)).sort((a, b) => (b.priority || 0) - (a.priority || 0) || a.sequence - b.sequence).map(clonePendingMessage);
5486
5633
  }
5634
+ async claimPendingMessages(threadId, scope, options) {
5635
+ const threadMessages = this.getMessagesForThread(threadId);
5636
+ const candidates = threadMessages.filter((msg) => (msg.status === "pending" || !msg.status) && this.inScope(msg, scope)).sort((a, b) => (b.priority || 0) - (a.priority || 0) || a.sequence - b.sequence);
5637
+ const limit = options.limit === void 0 ? void 0 : Math.max(0, Math.floor(options.limit));
5638
+ const selected = limit === void 0 ? candidates : candidates.slice(0, limit);
5639
+ const now = this.now();
5640
+ for (const message of selected) {
5641
+ message.status = "processing";
5642
+ message.lockedBy = options.owner;
5643
+ message.lockedAt = new Date(now);
5644
+ message.leaseExpiresAt = new Date(now + options.ttlMs);
5645
+ }
5646
+ return selected.map(clonePendingMessage);
5647
+ }
5648
+ async reclaimExpiredProcessing(threadId, scope) {
5649
+ const messages = this.messages.get(threadId);
5650
+ if (!messages) return 0;
5651
+ const now = this.now();
5652
+ let count = 0;
5653
+ for (const msg of messages) {
5654
+ if (msg.status === "processing" && this.inScope(msg, scope) && msg.leaseExpiresAt !== void 0 && msg.leaseExpiresAt.getTime() <= now) {
5655
+ msg.status = "pending";
5656
+ msg.lockedBy = void 0;
5657
+ msg.lockedAt = void 0;
5658
+ msg.leaseExpiresAt = void 0;
5659
+ count += 1;
5660
+ }
5661
+ }
5662
+ return count;
5663
+ }
5487
5664
  async getQueueSize(threadId, scope) {
5488
5665
  const pending = await this.getPendingMessages(threadId, scope);
5489
5666
  return pending.length;
@@ -5547,6 +5724,9 @@ var InMemoryThreadMessageQueueStore = class {
5547
5724
  for (const msg of messages) {
5548
5725
  if (msg.status === "processing" && this.inScope(msg, scope)) {
5549
5726
  msg.status = "pending";
5727
+ msg.lockedBy = void 0;
5728
+ msg.lockedAt = void 0;
5729
+ msg.leaseExpiresAt = void 0;
5550
5730
  count++;
5551
5731
  }
5552
5732
  }
@@ -6800,6 +6980,8 @@ var defaultProjectBotMembershipStore = new InMemoryProjectBotMembershipStore(def
6800
6980
  var defaultProjectRoomMessageStore = new InMemoryProjectRoomMessageStore(defaultProjectRoomCoordinator);
6801
6981
  var defaultProjectRoomReadStateStore = new InMemoryProjectRoomReadStateStore();
6802
6982
  var defaultUserPushSubscriptionStore = new InMemoryUserPushSubscriptionStore();
6983
+ var defaultLeaseStore = new InMemoryLeaseStore();
6984
+ var defaultOutboxStore = new InMemoryOutboxStore();
6803
6985
  storeLatticeManager.registerLattice("default", "thread", defaultThreadStore);
6804
6986
  storeLatticeManager.registerLattice(
6805
6987
  "default",
@@ -6821,6 +7003,8 @@ storeLatticeManager.registerLattice("default", "projectBotMembership", defaultPr
6821
7003
  storeLatticeManager.registerLattice("default", "projectRoomMessage", defaultProjectRoomMessageStore);
6822
7004
  storeLatticeManager.registerLattice("default", "projectRoomReadState", defaultProjectRoomReadStateStore);
6823
7005
  storeLatticeManager.registerLattice("default", "userPushSubscription", defaultUserPushSubscriptionStore);
7006
+ storeLatticeManager.registerLattice("default", "lease", defaultLeaseStore);
7007
+ storeLatticeManager.registerLattice("default", "outbox", defaultOutboxStore);
6824
7008
  var defaultUserStore = new InMemoryUserStore();
6825
7009
  var defaultTenantStore = new InMemoryTenantStore();
6826
7010
  var defaultUserTenantLinkStore = new InMemoryUserTenantLinkStore();
@@ -8689,8 +8873,8 @@ var MetricsServerManager = class _MetricsServerManager {
8689
8873
  } catch {
8690
8874
  }
8691
8875
  const tenantConfigs = this.configs.get(tenantId2);
8692
- const cached = tenantConfigs?.get(key5);
8693
- if (cached) return cached;
8876
+ const cached2 = tenantConfigs?.get(key5);
8877
+ if (cached2) return cached2;
8694
8878
  throw new Error(`Metrics server '${key5}' not found for tenant '${tenantId2}'`);
8695
8879
  }
8696
8880
  /**
@@ -10003,8 +10187,8 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
10003
10187
  getLatticeType() {
10004
10188
  return "sandbox_manager";
10005
10189
  }
10006
- registerLattice(key5, provider) {
10007
- this.register(key5, provider);
10190
+ registerLattice(key5, provider2) {
10191
+ this.register(key5, provider2);
10008
10192
  }
10009
10193
  getSandboxLattice(key5) {
10010
10194
  const lattice = this.get(key5);
@@ -10055,8 +10239,8 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
10055
10239
  return this.getVolumeBackendForPath(config, "/project");
10056
10240
  }
10057
10241
  async getVolumeBackendForPath(config, filePath) {
10058
- const provider = this._requireProvider();
10059
- if (!provider.createVolumeFsClient) {
10242
+ const provider2 = this._requireProvider();
10243
+ if (!provider2.createVolumeFsClient) {
10060
10244
  console.log(`[getVolumeBackendForPath] provider has no createVolumeFsClient, returning null`);
10061
10245
  return null;
10062
10246
  }
@@ -10067,7 +10251,7 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
10067
10251
  return null;
10068
10252
  }
10069
10253
  console.log(`[getVolumeBackendForPath] path=${filePath} volume=${mapping.volumeName} prefix=${mapping.pathPrefix}`);
10070
- const client = provider.createVolumeFsClient(mapping.volumeName, mapping.pathPrefix);
10254
+ const client = provider2.createVolumeFsClient(mapping.volumeName, mapping.pathPrefix);
10071
10255
  return new VolumeFilesystem(stripPrefixClient(client, mapping.pathPrefix), mapping.pathPrefix);
10072
10256
  }
10073
10257
  _resolveVolumeForPath(config, tenantId2, filePath) {
@@ -10102,35 +10286,35 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
10102
10286
  };
10103
10287
  }
10104
10288
  async createSandbox(name, config) {
10105
- const provider = this._requireProvider();
10106
- return provider.createSandbox(name, config);
10289
+ const provider2 = this._requireProvider();
10290
+ return provider2.createSandbox(name, config);
10107
10291
  }
10108
10292
  async getSandbox(name) {
10109
- const provider = this._requireProvider();
10110
- return provider.getSandbox(name);
10293
+ const provider2 = this._requireProvider();
10294
+ return provider2.getSandbox(name);
10111
10295
  }
10112
10296
  async stopSandbox(name) {
10113
- const provider = this._requireProvider();
10114
- return provider.stopSandbox(name);
10297
+ const provider2 = this._requireProvider();
10298
+ return provider2.stopSandbox(name);
10115
10299
  }
10116
10300
  async deleteSandbox(name) {
10117
- const provider = this._requireProvider();
10118
- return provider.deleteSandbox(name);
10301
+ const provider2 = this._requireProvider();
10302
+ return provider2.deleteSandbox(name);
10119
10303
  }
10120
10304
  async listSandboxes() {
10121
- const provider = this._requireProvider();
10122
- return provider.listSandboxes();
10305
+ const provider2 = this._requireProvider();
10306
+ return provider2.listSandboxes();
10123
10307
  }
10124
10308
  _requireProvider() {
10125
10309
  const keys = this.keysByTenant("default");
10126
10310
  if (keys.length === 0) {
10127
10311
  throw new Error("Sandbox provider not configured.");
10128
10312
  }
10129
- const provider = this.get(keys[0]);
10130
- if (!provider) {
10313
+ const provider2 = this.get(keys[0]);
10314
+ if (!provider2) {
10131
10315
  throw new Error("Sandbox provider not configured.");
10132
10316
  }
10133
- return provider;
10317
+ return provider2;
10134
10318
  }
10135
10319
  /**
10136
10320
  * Returns the first registered (default) sandbox provider.
@@ -10160,6 +10344,46 @@ var import_langchain13 = require("langchain");
10160
10344
  // src/tool_lattice/shell_exec/index.ts
10161
10345
  var import_zod17 = __toESM(require("zod"));
10162
10346
  var import_langchain14 = require("langchain");
10347
+
10348
+ // src/sandbox_lattice/sandboxOpenCredential.ts
10349
+ var SANDBOX_OPEN_GATEWAY_URL_ENV = "API_GATEWAY_URL";
10350
+ var SANDBOX_OPEN_TOKEN_ENV = "OPEN_API_TOKEN";
10351
+ var provider;
10352
+ var providerErrorHandler;
10353
+ function registerSandboxOpenCredentialProvider(next, options = {}) {
10354
+ provider = next;
10355
+ providerErrorHandler = options.onError;
10356
+ return () => {
10357
+ if (provider === next) {
10358
+ provider = void 0;
10359
+ providerErrorHandler = void 0;
10360
+ }
10361
+ };
10362
+ }
10363
+ async function getSandboxOpenCredential(context) {
10364
+ if (!provider) return void 0;
10365
+ try {
10366
+ return await provider(context);
10367
+ } catch (error) {
10368
+ try {
10369
+ providerErrorHandler?.(error);
10370
+ } catch {
10371
+ }
10372
+ return void 0;
10373
+ }
10374
+ }
10375
+ function buildSandboxOpenEnv(credential) {
10376
+ return `export ${SANDBOX_OPEN_GATEWAY_URL_ENV}=${shellSingleQuote(credential.gatewayUrl)} && export ${SANDBOX_OPEN_TOKEN_ENV}=${shellSingleQuote(credential.token)}`;
10377
+ }
10378
+ function shellSingleQuote(value) {
10379
+ return `'${value.replace(/'/g, "'\\''")}'`;
10380
+ }
10381
+ function clearSandboxOpenCredentialProviderForTests() {
10382
+ provider = void 0;
10383
+ providerErrorHandler = void 0;
10384
+ }
10385
+
10386
+ // src/tool_lattice/shell_exec/index.ts
10163
10387
  var SHELL_EXEC_DESCRIPTION = `Execute a shell command in the sandbox environment.
10164
10388
 
10165
10389
  Use this to run CLI tools, install packages, inspect files, or perform any operation that requires a shell.
@@ -10192,8 +10416,19 @@ var createShellExecTool = ({
10192
10416
  projectId: runConfig.projectId,
10193
10417
  vmIsolation
10194
10418
  });
10419
+ const tenantId2 = runConfig.tenantId;
10420
+ const credential = tenantId2 ? await getSandboxOpenCredential({
10421
+ tenantId: tenantId2,
10422
+ workspaceId: runConfig.workspaceId,
10423
+ projectId: runConfig.projectId,
10424
+ sandboxName: sandbox.name,
10425
+ assistantId: runConfig.assistant_id || void 0,
10426
+ threadId: runConfig.thread_id || void 0,
10427
+ depth: runConfig.depth
10428
+ }) : void 0;
10429
+ const command = credential ? `${buildSandboxOpenEnv(credential)} && ${input.command}` : input.command;
10195
10430
  const executeResult = await sandbox.shell.execCommand({
10196
- command: input.command,
10431
+ command,
10197
10432
  exec_dir: input.exec_dir,
10198
10433
  timeout: input.timeout ?? 300
10199
10434
  });
@@ -14925,13 +15160,23 @@ var SandboxPluginExecutor = class {
14925
15160
  validateRelativePath(args.handler, "handler");
14926
15161
  const pluginDir = `${PLUGINS_ROOT}/${args.manifest.type}`;
14927
15162
  const handlerAbs = `${pluginDir}/${args.handler}`;
15163
+ const tenantId2 = args.runConfig?.tenantId ?? args.context.tenantId;
14928
15164
  const sandbox = await this.deps.resolveSandbox({
14929
- tenantId: args.runConfig?.tenantId ?? args.context.tenantId,
15165
+ tenantId: tenantId2,
14930
15166
  assistantId: args.runConfig?.assistantId,
14931
15167
  threadId: args.runConfig?.threadId,
14932
15168
  workspaceId: args.runConfig?.workspaceId,
14933
15169
  projectId: args.runConfig?.projectId
14934
15170
  });
15171
+ const openCredential = tenantId2 ? await getSandboxOpenCredential({
15172
+ tenantId: tenantId2,
15173
+ workspaceId: args.runConfig?.workspaceId,
15174
+ projectId: args.runConfig?.projectId,
15175
+ sandboxName: sandbox.name,
15176
+ assistantId: args.runConfig?.assistantId,
15177
+ threadId: args.runConfig?.threadId,
15178
+ depth: args.runConfig?.depth
15179
+ }) : void 0;
14935
15180
  const timeoutMs = clamp(args.timeoutMs ?? DEFAULT_TIMEOUT_MS, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS);
14936
15181
  const cap = clamp(
14937
15182
  args.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES,
@@ -14962,6 +15207,12 @@ var SandboxPluginExecutor = class {
14962
15207
  envParts.push(`PLUGIN_CONNECTION_FILE=${quotePosixShellArg(connectionFile)}`);
14963
15208
  }
14964
15209
  envParts.push(`PLUGIN_CONTEXT=${quotePosixShellArg(encode(args.context))}`);
15210
+ if (openCredential) {
15211
+ envParts.push(
15212
+ `${SANDBOX_OPEN_GATEWAY_URL_ENV}=${quotePosixShellArg(openCredential.gatewayUrl)}`
15213
+ );
15214
+ envParts.push(`${SANDBOX_OPEN_TOKEN_ENV}=${quotePosixShellArg(openCredential.token)}`);
15215
+ }
14965
15216
  const command = `${envParts.join(" ")} node ${quotePosixShellArg(handlerAbs)}`;
14966
15217
  const execResult = await sandbox.shell.execCommand({
14967
15218
  command,
@@ -15913,10 +16164,10 @@ var TenantPluginCatalog = class {
15913
16164
  candidates.push({ type, dirPath: dir.path, raw, manifestJson, files: dirFiles });
15914
16165
  }
15915
16166
  const hash = (0, import_node_crypto3.createHash)("sha256").update(hashParts.sort().join("\n")).digest("hex").slice(0, 16);
15916
- const cached = this.cache.get(tenantId2)?.value;
15917
- if (cached && cached.hash === hash) {
15918
- this.cache.set(tenantId2, { value: cached, checkedAt: this.now() });
15919
- return cached;
16167
+ const cached2 = this.cache.get(tenantId2)?.value;
16168
+ if (cached2 && cached2.hash === hash) {
16169
+ this.cache.set(tenantId2, { value: cached2, checkedAt: this.now() });
16170
+ return cached2;
15920
16171
  }
15921
16172
  const plugins = [];
15922
16173
  const manifests = {};
@@ -17261,7 +17512,7 @@ var AgentWorkerState = import_langgraph5.Annotation.Root({
17261
17512
  default: () => ({})
17262
17513
  }),
17263
17514
  command2: (0, import_langgraph5.Annotation)({
17264
- reducer: (x, y) => y ?? x,
17515
+ reducer: (_x, y) => y,
17265
17516
  default: () => void 0
17266
17517
  }),
17267
17518
  // RunConfig for passing configuration through the graph
@@ -17278,12 +17529,12 @@ var AgentWorkerState = import_langgraph5.Annotation.Root({
17278
17529
  }),
17279
17530
  // Execution result
17280
17531
  result: (0, import_langgraph5.Annotation)({
17281
- reducer: (x, y) => y ?? x,
17532
+ reducer: (_x, y) => y,
17282
17533
  default: () => void 0
17283
17534
  }),
17284
17535
  // Interrupt data
17285
17536
  interruptValue: (0, import_langgraph5.Annotation)({
17286
- reducer: (x, y) => y ?? x,
17537
+ reducer: (_x, y) => y,
17287
17538
  default: () => void 0
17288
17539
  }),
17289
17540
  // Final state to return
@@ -17364,6 +17615,324 @@ var agentWorkerGraph = createAgentWorkerGraph();
17364
17615
  // src/deep_agent_new/middleware/subagents.ts
17365
17616
  init_MemoryLatticeManager();
17366
17617
 
17618
+ // src/util/toJsonSafeValue.ts
17619
+ var CIRCULAR_VALUE = "[Circular]";
17620
+ var REPEATED_VALUE = "[Repeated]";
17621
+ var arrayFrom = Array.from.bind(Array);
17622
+ var arrayIsArray = Array.isArray.bind(Array);
17623
+ var hasOwnProperty = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
17624
+ var isPrototypeOf = Object.prototype.isPrototypeOf.call.bind(Object.prototype.isPrototypeOf);
17625
+ var objectCreate = Object.create.bind(Object);
17626
+ var objectDefineProperty = Object.defineProperty.bind(Object);
17627
+ var objectIs = Object.is.bind(Object);
17628
+ var reflectGet = Reflect.get.bind(Reflect);
17629
+ var reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor.bind(Reflect);
17630
+ var reflectOwnKeys = Reflect.ownKeys.bind(Reflect);
17631
+ var stringifyJson = JSON.stringify.bind(JSON);
17632
+ var numberIsFinite = Number.isFinite.bind(Number);
17633
+ var numberIsNaN = Number.isNaN.bind(Number);
17634
+ var numberIsSafeInteger = Number.isSafeInteger.bind(Number);
17635
+ var mathMax = Math.max.bind(Math);
17636
+ var dateConstructor = Date;
17637
+ var datePrototype = dateConstructor.prototype;
17638
+ var dateGetTime = datePrototype.getTime.call.bind(datePrototype.getTime);
17639
+ var dateToISOString = datePrototype.toISOString.call.bind(datePrototype.toISOString);
17640
+ var bigintToString = BigInt.prototype.toString.call.bind(BigInt.prototype.toString);
17641
+ var stringSlice = String.prototype.slice.call.bind(String.prototype.slice);
17642
+ var weakMapGet = WeakMap.prototype.get.call.bind(WeakMap.prototype.get);
17643
+ var weakMapSet = WeakMap.prototype.set.call.bind(WeakMap.prototype.set);
17644
+ var WeakMapConstructor = WeakMap;
17645
+ var utf8Encoder = new TextEncoder();
17646
+ var encodeUtf8 = TextEncoder.prototype.encode.bind(utf8Encoder);
17647
+ var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
17648
+ var typedArrayByteLengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")?.get;
17649
+ if (!typedArrayByteLengthGetter) throw new Error("TypedArray byteLength getter is unavailable");
17650
+ var typedArrayByteLength = typedArrayByteLengthGetter.call.bind(typedArrayByteLengthGetter);
17651
+ var JSON_SAFE_MAX_DEPTH = 32;
17652
+ var JSON_SAFE_MAX_NODES = 1e4;
17653
+ var JSON_SAFE_MAX_COLLECTION_ENTRIES = 1e4;
17654
+ var JSON_SAFE_MAX_STRING_LENGTH = 64 * 1024;
17655
+ var JSON_SAFE_MAX_PROPERTY_KEY_LENGTH = JSON_SAFE_MAX_STRING_LENGTH;
17656
+ var JSON_SAFE_MAX_PROPERTY_KEY_BYTES = 256 * 1024;
17657
+ var JSON_SAFE_MAX_SERIALIZED_BYTES = 256 * 1024;
17658
+ var JsonSafeValueError = class extends Error {
17659
+ /**
17660
+ * Create a bounded normalization error.
17661
+ *
17662
+ * @param code Stable normalization failure code.
17663
+ * @param message Human-readable bounded failure description.
17664
+ */
17665
+ constructor(code, message) {
17666
+ super(message);
17667
+ objectDefineProperty(this, "name", {
17668
+ value: "JsonSafeValueError",
17669
+ writable: true,
17670
+ configurable: true
17671
+ });
17672
+ objectDefineProperty(this, "code", {
17673
+ value: code,
17674
+ writable: true,
17675
+ configurable: true
17676
+ });
17677
+ }
17678
+ };
17679
+ function fail(code, message) {
17680
+ throw new JsonSafeValueError(code, message);
17681
+ }
17682
+ function propertyAccess(operation, path8) {
17683
+ try {
17684
+ return operation();
17685
+ } catch {
17686
+ fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe value at ${path8}`);
17687
+ }
17688
+ }
17689
+ function serializedStringBytes(value) {
17690
+ if (value.length > JSON_SAFE_MAX_STRING_LENGTH) {
17691
+ fail("MAX_STRING_LENGTH", `JSON-safe string exceeds ${JSON_SAFE_MAX_STRING_LENGTH} characters`);
17692
+ }
17693
+ return typedArrayByteLength(encodeUtf8(stringifyJson(value)));
17694
+ }
17695
+ function validatePropertyKey(key5) {
17696
+ if (key5.length > JSON_SAFE_MAX_PROPERTY_KEY_LENGTH) {
17697
+ fail(
17698
+ "MAX_STRING_LENGTH",
17699
+ `JSON-safe property key exceeds ${JSON_SAFE_MAX_PROPERTY_KEY_LENGTH} characters`
17700
+ );
17701
+ }
17702
+ }
17703
+ function chargePropertyKey(state, key5) {
17704
+ state.propertyKeyBytes += typedArrayByteLength(encodeUtf8(key5));
17705
+ if (state.propertyKeyBytes > JSON_SAFE_MAX_PROPERTY_KEY_BYTES) {
17706
+ fail(
17707
+ "MAX_PROPERTY_KEY_BYTES",
17708
+ `JSON-safe property keys exceed ${JSON_SAFE_MAX_PROPERTY_KEY_BYTES} traversed UTF-8 bytes`
17709
+ );
17710
+ }
17711
+ }
17712
+ function chargeBytes(state, bytes) {
17713
+ state.serializedBytes += bytes;
17714
+ if (state.serializedBytes > JSON_SAFE_MAX_SERIALIZED_BYTES) {
17715
+ fail(
17716
+ "MAX_SERIALIZED_BYTES",
17717
+ `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
17718
+ );
17719
+ }
17720
+ }
17721
+ function chargeString(state, value) {
17722
+ chargeBytes(state, serializedStringBytes(value));
17723
+ }
17724
+ function objectPropertyPath(path8, key5) {
17725
+ const boundedKey = key5.length > 128 ? `${stringSlice(key5, 0, 128)}...` : key5;
17726
+ return `${path8}[${stringifyJson(boundedKey)}]`;
17727
+ }
17728
+ function convertJsonValue(value, state, depth, inArray, path8) {
17729
+ state.nodes += 1;
17730
+ if (state.nodes > JSON_SAFE_MAX_NODES) {
17731
+ fail("MAX_NODES", `JSON-safe value exceeds ${JSON_SAFE_MAX_NODES} total nodes`);
17732
+ }
17733
+ if (typeof value === "string") {
17734
+ chargeString(state, value);
17735
+ return value;
17736
+ }
17737
+ if (value === null) {
17738
+ chargeBytes(state, 4);
17739
+ return value;
17740
+ }
17741
+ if (typeof value === "boolean") {
17742
+ chargeBytes(state, value ? 4 : 5);
17743
+ return value;
17744
+ }
17745
+ if (typeof value === "number") {
17746
+ const normalized = numberIsFinite(value) ? objectIs(value, -0) ? 0 : value : null;
17747
+ chargeBytes(state, normalized === null ? 4 : stringifyJson(normalized).length);
17748
+ return normalized;
17749
+ }
17750
+ if (typeof value === "bigint") {
17751
+ const normalized = bigintToString(value);
17752
+ chargeString(state, normalized);
17753
+ return normalized;
17754
+ }
17755
+ if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
17756
+ if (inArray) chargeBytes(state, 4);
17757
+ return inArray ? null : void 0;
17758
+ }
17759
+ const isDate = propertyAccess(() => isPrototypeOf(datePrototype, value), path8);
17760
+ if (isDate) {
17761
+ const time = propertyAccess(() => dateGetTime(value), path8);
17762
+ if (numberIsNaN(time)) {
17763
+ chargeBytes(state, 4);
17764
+ return null;
17765
+ }
17766
+ const normalized = propertyAccess(() => dateToISOString(value), path8);
17767
+ chargeString(state, normalized);
17768
+ return normalized;
17769
+ }
17770
+ if (depth > JSON_SAFE_MAX_DEPTH) {
17771
+ fail("MAX_DEPTH", `JSON-safe value exceeds maximum depth ${JSON_SAFE_MAX_DEPTH}`);
17772
+ }
17773
+ const referenceState = weakMapGet(state.references, value);
17774
+ if (referenceState === "visiting") {
17775
+ chargeString(state, CIRCULAR_VALUE);
17776
+ return CIRCULAR_VALUE;
17777
+ }
17778
+ if (referenceState === "visited") {
17779
+ chargeString(state, REPEATED_VALUE);
17780
+ return REPEATED_VALUE;
17781
+ }
17782
+ weakMapSet(state.references, value, "visiting");
17783
+ if (propertyAccess(() => arrayIsArray(value), path8)) {
17784
+ const arrayValue = value;
17785
+ const length = propertyAccess(
17786
+ () => arrayValue.length,
17787
+ path8
17788
+ );
17789
+ if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 0) {
17790
+ fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe array length at ${path8}`);
17791
+ }
17792
+ if (length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
17793
+ fail(
17794
+ "COLLECTION_TOO_LARGE",
17795
+ `JSON-safe array exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} entries`
17796
+ );
17797
+ }
17798
+ chargeBytes(state, 2 + mathMax(0, length - 1));
17799
+ const result2 = arrayFrom({ length }, (_, index) => {
17800
+ const entryPath = `${path8}[${index}]`;
17801
+ const hasEntry = propertyAccess(
17802
+ () => hasOwnProperty(arrayValue, index),
17803
+ entryPath
17804
+ );
17805
+ if (!hasEntry) {
17806
+ chargeBytes(state, 4);
17807
+ return null;
17808
+ }
17809
+ const entry = propertyAccess(() => arrayValue[index], entryPath);
17810
+ return convertJsonValue(entry, state, depth + 1, true, `${path8}[${index}]`);
17811
+ });
17812
+ objectDefineProperty(result2, "toJSON", {
17813
+ value: void 0,
17814
+ configurable: true,
17815
+ writable: true
17816
+ });
17817
+ weakMapSet(state.references, value, "visited");
17818
+ return result2;
17819
+ }
17820
+ const keys = propertyAccess(() => reflectOwnKeys(value), path8);
17821
+ if (keys.length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
17822
+ fail(
17823
+ "COLLECTION_TOO_LARGE",
17824
+ `JSON-safe object exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} own keys`
17825
+ );
17826
+ }
17827
+ for (let index = 0; index < keys.length; index += 1) {
17828
+ const key5 = keys[index];
17829
+ if (typeof key5 !== "string") continue;
17830
+ validatePropertyKey(key5);
17831
+ chargePropertyKey(state, key5);
17832
+ }
17833
+ chargeBytes(state, 2);
17834
+ const result = objectCreate(null);
17835
+ let emittedProperties = 0;
17836
+ for (let index = 0; index < keys.length; index += 1) {
17837
+ const key5 = keys[index];
17838
+ const entryPath = typeof key5 === "string" ? objectPropertyPath(path8, key5) : path8;
17839
+ const descriptor = propertyAccess(
17840
+ () => reflectGetOwnPropertyDescriptor(value, key5),
17841
+ entryPath
17842
+ );
17843
+ if (typeof key5 !== "string" || !descriptor?.enumerable) continue;
17844
+ const entry = propertyAccess(() => reflectGet(value, key5), entryPath);
17845
+ const converted = convertJsonValue(entry, state, depth + 1, false, entryPath);
17846
+ if (converted !== void 0) {
17847
+ chargeBytes(state, serializedStringBytes(key5) + 1 + (emittedProperties === 0 ? 0 : 1));
17848
+ propertyAccess(() => objectDefineProperty(result, key5, {
17849
+ value: converted,
17850
+ enumerable: true,
17851
+ configurable: true,
17852
+ writable: true
17853
+ }), entryPath);
17854
+ emittedProperties += 1;
17855
+ }
17856
+ }
17857
+ weakMapSet(state.references, value, "visited");
17858
+ return result;
17859
+ }
17860
+ function toJsonSafeValue(value) {
17861
+ const state = {
17862
+ nodes: 0,
17863
+ propertyKeyBytes: 0,
17864
+ serializedBytes: 0,
17865
+ references: new WeakMapConstructor()
17866
+ };
17867
+ const converted = convertJsonValue(value, state, 0, false, "$");
17868
+ if (converted === void 0) chargeBytes(state, 4);
17869
+ const result = converted ?? null;
17870
+ const serialized = propertyAccess(() => stringifyJson(result), "$");
17871
+ if (typedArrayByteLength(encodeUtf8(serialized)) > JSON_SAFE_MAX_SERIALIZED_BYTES) {
17872
+ fail(
17873
+ "MAX_SERIALIZED_BYTES",
17874
+ `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
17875
+ );
17876
+ }
17877
+ return result;
17878
+ }
17879
+
17880
+ // src/util/truncateForJson.ts
17881
+ var TRUNCATION_MARKER = "...[truncated]";
17882
+ function truncateString(value, cap) {
17883
+ if (value.length <= cap) return value;
17884
+ const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
17885
+ return value.slice(0, budget) + TRUNCATION_MARKER;
17886
+ }
17887
+ function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
17888
+ if (typeof value === "string") return truncateString(value, maxStringLength);
17889
+ if (value === null || typeof value !== "object") return value;
17890
+ if (depth >= maxDepth) return "[truncated:max-depth]";
17891
+ if (seen.has(value)) return "[Circular]";
17892
+ seen.add(value);
17893
+ try {
17894
+ if (value instanceof Date) return value.toISOString();
17895
+ if (Array.isArray(value)) {
17896
+ const limit2 = Math.min(value.length, maxEntries);
17897
+ const output2 = [];
17898
+ for (let index = 0; index < limit2; index += 1) {
17899
+ output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
17900
+ }
17901
+ if (value.length > limit2) output2.push("[truncated:entries]");
17902
+ return output2;
17903
+ }
17904
+ const record = value;
17905
+ const output = {};
17906
+ const keys = Object.keys(record);
17907
+ const limit = Math.min(keys.length, maxEntries);
17908
+ for (let index = 0; index < limit; index += 1) {
17909
+ const key5 = keys[index];
17910
+ output[truncateString(key5, maxStringLength)] = truncateValue(
17911
+ record[key5],
17912
+ depth + 1,
17913
+ maxDepth,
17914
+ maxEntries,
17915
+ maxStringLength,
17916
+ seen
17917
+ );
17918
+ }
17919
+ if (keys.length > limit) output["[truncated]"] = true;
17920
+ return output;
17921
+ } finally {
17922
+ seen.delete(value);
17923
+ }
17924
+ }
17925
+ function truncateForJson(value, options = {}) {
17926
+ return truncateValue(
17927
+ value,
17928
+ 0,
17929
+ options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
17930
+ options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
17931
+ options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
17932
+ /* @__PURE__ */ new WeakSet()
17933
+ );
17934
+ }
17935
+
17367
17936
  // src/services/Agent.ts
17368
17937
  var import_protocols10 = require("@axiom-lattice/protocols");
17369
17938
  var import_langgraph6 = require("@langchain/langgraph");
@@ -18655,6 +19224,71 @@ var CapabilityRuntimeResolver = class {
18655
19224
  // src/services/TrustedAgentDispatchCapability.ts
18656
19225
  var TRUSTED_AGENT_DISPATCH = Symbol("axiom.trustedAgentDispatch");
18657
19226
 
19227
+ // src/services/threadRunLease.ts
19228
+ var import_node_crypto5 = require("crypto");
19229
+ function threadRunLeaseKey(tenantId2, assistantId, threadId) {
19230
+ return `thread-run:${tenantId2}:${assistantId}:${threadId}`;
19231
+ }
19232
+ async function tryAcquireThreadRun(input) {
19233
+ const key5 = threadRunLeaseKey(input.tenantId, input.assistantId, input.threadId);
19234
+ const holder = `${input.owner}#${(0, import_node_crypto5.randomUUID)()}`;
19235
+ if (!await input.store.tryAcquire(key5, holder, input.ttlMs)) return null;
19236
+ const heartbeatMs = input.heartbeatMs ?? Math.max(1e3, Math.floor(input.ttlMs / 3));
19237
+ let released = false;
19238
+ let lost = false;
19239
+ const heartbeat = setInterval(() => {
19240
+ void input.store.renew(key5, holder, input.ttlMs).then((renewed) => {
19241
+ if (released || renewed || lost) return;
19242
+ lost = true;
19243
+ try {
19244
+ input.onLost?.();
19245
+ } catch {
19246
+ }
19247
+ }).catch(() => void 0);
19248
+ }, heartbeatMs);
19249
+ heartbeat.unref?.();
19250
+ return {
19251
+ get lost() {
19252
+ return lost;
19253
+ },
19254
+ release: async () => {
19255
+ if (released) return;
19256
+ released = true;
19257
+ clearInterval(heartbeat);
19258
+ await input.store.release(key5, holder).catch(() => void 0);
19259
+ }
19260
+ };
19261
+ }
19262
+ async function getThreadRunOwner(input) {
19263
+ let store = input.store;
19264
+ if (!store) {
19265
+ try {
19266
+ store = storeLatticeManager.getStoreLattice("default", "lease").store;
19267
+ } catch {
19268
+ return null;
19269
+ }
19270
+ }
19271
+ try {
19272
+ const record = await store.get(threadRunLeaseKey(input.tenantId, input.assistantId, input.threadId));
19273
+ if (!record) return null;
19274
+ const hash = record.holder.lastIndexOf("#");
19275
+ return hash > 0 ? record.holder.slice(0, hash) : record.holder;
19276
+ } catch {
19277
+ return null;
19278
+ }
19279
+ }
19280
+
19281
+ // src/services/replicaIdentity.ts
19282
+ var import_node_os = __toESM(require("os"));
19283
+ var cached;
19284
+ function getReplicaId() {
19285
+ cached ?? (cached = process.env.AXIOM_REPLICA_ID?.trim() || `${import_node_os.default.hostname()}:${process.pid}`);
19286
+ return cached;
19287
+ }
19288
+ function resetReplicaIdForTests() {
19289
+ cached = void 0;
19290
+ }
19291
+
18658
19292
  // src/services/Agent.ts
18659
19293
  var ThreadStatus2 = /* @__PURE__ */ ((ThreadStatus3) => {
18660
19294
  ThreadStatus3["IDLE"] = "idle";
@@ -18902,6 +19536,27 @@ function statusFromSnapshot(state) {
18902
19536
  if (Array.isArray(state.next) && state.next.length > 0) return "busy" /* BUSY */;
18903
19537
  return "idle" /* IDLE */;
18904
19538
  }
19539
+ var MAX_EXECUTION_ERROR_LENGTH = 2e3;
19540
+ function executionErrorFromSnapshot(state) {
19541
+ if (!isPlainRecord(state) || !Array.isArray(state.tasks)) return void 0;
19542
+ for (const task of state.tasks) {
19543
+ if (!isPlainRecord(task) || task.error === void 0 || task.error === null) continue;
19544
+ const raw = task.error;
19545
+ const message = typeof raw === "string" ? raw : raw instanceof Error ? raw.message : isPlainRecord(raw) && typeof raw.message === "string" ? raw.message : (() => {
19546
+ try {
19547
+ return JSON.stringify(raw);
19548
+ } catch {
19549
+ return String(raw);
19550
+ }
19551
+ })();
19552
+ if (typeof message !== "string") continue;
19553
+ const trimmed = message.trim();
19554
+ if (trimmed.length === 0) continue;
19555
+ const bounded = truncateForJson(trimmed, { maxStringLength: MAX_EXECUTION_ERROR_LENGTH });
19556
+ if (typeof bounded === "string" && bounded.length > 0) return bounded;
19557
+ }
19558
+ return void 0;
19559
+ }
18905
19560
  function freshReply(state, preRunMarker, inputMessageId, consumedInputMessageIds) {
18906
19561
  const output = finalAiMessageMarker(state);
18907
19562
  if (output?.text === void 0 || output.index <= (preRunMarker?.index ?? -1) || output.totalMessageCount <= (preRunMarker?.totalMessageCount ?? 0)) return void 0;
@@ -18951,6 +19606,10 @@ function checkpointCapabilityRevision(state) {
18951
19606
  var QUEUE_PROCESSOR_RETRY_BASE_MS = 100;
18952
19607
  var QUEUE_PROCESSOR_MAX_RETRIES = 3;
18953
19608
  var AGENT_RECURSION_LIMIT = 1e3;
19609
+ var THREAD_RUN_LEASE_TTL_MS = 6e4;
19610
+ var THREAD_RUN_LEASE_RETRY_BASE_MS = 150;
19611
+ var THREAD_RUN_LEASE_RETRY_CAP_MS = 1500;
19612
+ var THREAD_RUN_LEASE_MAX_RETRIES = 12;
18954
19613
  function hasExactKeys(record, required, optional = []) {
18955
19614
  const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
18956
19615
  return required.every((key5) => Object.prototype.hasOwnProperty.call(record, key5)) && Reflect.ownKeys(record).every((key5) => typeof key5 === "string" && allowed.has(key5));
@@ -18980,6 +19639,13 @@ var Agent = class {
18980
19639
  this.queueProcessorRetryAttempt = 0;
18981
19640
  this.queueProcessorGeneration = 0;
18982
19641
  this.queueWakeRequested = false;
19642
+ /**
19643
+ * Thread-run ownership lease held while this replica is actively processing
19644
+ * the thread. Acquired non-blockingly in {@link startQueueProcessor}; released
19645
+ * exactly once when the processor definitively stops.
19646
+ */
19647
+ this.threadRunLease = null;
19648
+ this.threadRunLeaseRetryAttempt = 0;
18983
19649
  this.asyncTasks = [];
18984
19650
  this.agentExecutor = async ({ input, command, custom_run_config, expected_capability_revision, trusted_run_context }, signal) => {
18985
19651
  const { runnable_agent, runConfig } = await this.getLatticeClientAndRuntimeConfig(
@@ -19096,7 +19762,7 @@ var Agent = class {
19096
19762
  }
19097
19763
  };
19098
19764
  this.waitingForQueueEnd = async (signal) => {
19099
- while (!signal?.aborted) {
19765
+ while (!signal?.aborted && !this.threadRunLease?.lost) {
19100
19766
  const pendings = await this.getPendingMessages();
19101
19767
  if (pendings.length === 0) {
19102
19768
  const state = await this.getCurrentState();
@@ -19181,7 +19847,7 @@ var Agent = class {
19181
19847
  state
19182
19848
  });
19183
19849
  } else if (runStatus === "error" /* ERROR */) {
19184
- const failureReason = "Agent execution ended in an error state";
19850
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
19185
19851
  this.addChunk({
19186
19852
  type: "message_failed",
19187
19853
  data: { id: humanContent.id, content: failureReason }
@@ -19294,7 +19960,7 @@ var Agent = class {
19294
19960
  }
19295
19961
  if (runStatus === "busy" /* BUSY */) return;
19296
19962
  if (runStatus === "error" /* ERROR */) {
19297
- const failureReason = "Agent execution ended in an error state";
19963
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
19298
19964
  for (const p of collectPendings) {
19299
19965
  const messageId = p.content.id;
19300
19966
  this.addChunk({
@@ -19395,7 +20061,7 @@ var Agent = class {
19395
20061
  });
19396
20062
  if (p.execution_mode === "followup") return;
19397
20063
  } else if (runStatus === "error" /* ERROR */) {
19398
- const failureReason = "Agent execution ended in an error state";
20064
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
19399
20065
  this.addChunk({
19400
20066
  type: "message_failed",
19401
20067
  data: { id: humanContent.id, content: failureReason }
@@ -19702,12 +20368,17 @@ var Agent = class {
19702
20368
  capabilityRuntimeRevision: capabilityRuntime.revision,
19703
20369
  tenantId: this.tenant_id,
19704
20370
  workspaceId: this.workspace_id,
19705
- projectId: this.project_id,
20371
+ // The propagated project scope must not fabricate `"default"`:
20372
+ // `queue_project_id` is `null` when the run had no project, so an unscoped
20373
+ // run stays unscoped instead of later querying a project that may not
20374
+ // exist. An explicitly passed `"default"` is a real project for some
20375
+ // tenants and is preserved.
20376
+ projectId: this.queue_project_id ?? void 0,
19706
20377
  assistant_id: this.assistant_id,
19707
20378
  thread_id: this.thread_id,
19708
20379
  "x-tenant-id": this.tenant_id,
19709
20380
  "x-workspace-id": this.workspace_id,
19710
- "x-project-id": this.project_id,
20381
+ "x-project-id": this.queue_project_id ?? void 0,
19711
20382
  "x-thread-id": this.thread_id,
19712
20383
  "x-assistant-id": this.assistant_id
19713
20384
  };
@@ -19922,6 +20593,29 @@ var Agent = class {
19922
20593
  }
19923
20594
  return this.queueStore;
19924
20595
  }
20596
+ /**
20597
+ * Resolves the shared lease store used to serialize thread runs across
20598
+ * Gateway replicas. Returns `undefined` when no lease store is registered so
20599
+ * single-process deployments keep running unconditionally.
20600
+ */
20601
+ getLeaseStore() {
20602
+ try {
20603
+ return storeLatticeManager.getStoreLattice("default", "lease").store;
20604
+ } catch {
20605
+ return void 0;
20606
+ }
20607
+ }
20608
+ /**
20609
+ * Releases this replica's thread-run ownership lease, if held.
20610
+ *
20611
+ * @remarks Safe to call from any definitive-stop path; a second call is a
20612
+ * no-op. The handle's unique holder makes a stale release harmless.
20613
+ */
20614
+ async releaseThreadRunLease() {
20615
+ const lease = this.threadRunLease;
20616
+ this.threadRunLease = null;
20617
+ if (lease) await lease.release();
20618
+ }
19925
20619
  getDefaultQueueConfig() {
19926
20620
  return {
19927
20621
  mode: "collect" /* COLLECT */,
@@ -19947,6 +20641,8 @@ var Agent = class {
19947
20641
  */
19948
20642
  stopQueueProcessor() {
19949
20643
  this.cancelQueueProcessorRetry();
20644
+ this.cancelThreadRunLeaseRetry();
20645
+ void this.releaseThreadRunLease();
19950
20646
  this.clearRecoveryBlock();
19951
20647
  this.queueProcessorGeneration += 1;
19952
20648
  if (this.abortController) {
@@ -20052,7 +20748,15 @@ var Agent = class {
20052
20748
  if (!accepted) throw new Error(`Queue is full (max ${maxSize} messages)`);
20053
20749
  if (useMode === "steer" /* STEER */ && !queueMessage.command) {
20054
20750
  this.stopQueueProcessor();
20055
- await store.resetProcessingToPending(this.thread_id, this.queueScope());
20751
+ let runStatus;
20752
+ try {
20753
+ runStatus = await this.getRunStatus();
20754
+ } catch {
20755
+ runStatus = void 0;
20756
+ }
20757
+ if (runStatus !== "interrupted" /* INTERRUPTED */) {
20758
+ await store.resetProcessingToPending(this.thread_id, this.queueScope());
20759
+ }
20056
20760
  console.log(`[Agent] STEER mode: stopped current processing, reset queue, message ${messageId} will execute next`);
20057
20761
  }
20058
20762
  } else {
@@ -20086,16 +20790,50 @@ var Agent = class {
20086
20790
  startQueueProcessorIfNeeded() {
20087
20791
  return this.startQueueProcessor(true);
20088
20792
  }
20089
- startQueueProcessor(freshWakeup) {
20793
+ async startQueueProcessor(freshWakeup) {
20090
20794
  this.queueWakeRequested = true;
20091
20795
  if (this.queueProcessorPromise) return this.queueProcessorPromise;
20092
- if (this.queueProcessorRetryTimer) return Promise.resolve();
20796
+ if (this.queueProcessorRetryTimer) return;
20093
20797
  if (freshWakeup && this.queueProcessorRetryAttempt >= QUEUE_PROCESSOR_MAX_RETRIES) {
20094
20798
  this.queueProcessorRetryAttempt = 0;
20095
20799
  }
20800
+ if (freshWakeup && this.threadRunLeaseRetryAttempt >= THREAD_RUN_LEASE_MAX_RETRIES) {
20801
+ this.threadRunLeaseRetryAttempt = 0;
20802
+ }
20096
20803
  this.queueWakeRequested = false;
20097
- let processorFailed = false;
20098
20804
  const processorGeneration = this.queueProcessorGeneration;
20805
+ if (this.threadRunLease?.lost) await this.releaseThreadRunLease();
20806
+ let acquiredLeaseHere = false;
20807
+ if (this.threadRunLease === null) {
20808
+ const leaseStore = this.getLeaseStore();
20809
+ if (leaseStore) {
20810
+ const lease = await tryAcquireThreadRun({
20811
+ store: leaseStore,
20812
+ tenantId: this.tenant_id,
20813
+ assistantId: this.assistant_id,
20814
+ threadId: this.thread_id,
20815
+ owner: getReplicaId(),
20816
+ ttlMs: THREAD_RUN_LEASE_TTL_MS,
20817
+ onLost: () => {
20818
+ console.warn(`[Agent] Thread-run lease lost for thread ${this.thread_id}; aborting the held run`);
20819
+ this.abortController?.abort();
20820
+ }
20821
+ });
20822
+ if (!lease) {
20823
+ this.scheduleThreadRunLeaseRetry();
20824
+ return;
20825
+ }
20826
+ this.threadRunLease = lease;
20827
+ acquiredLeaseHere = true;
20828
+ this.cancelThreadRunLeaseRetry();
20829
+ }
20830
+ }
20831
+ if (this.queueProcessorPromise) return this.queueProcessorPromise;
20832
+ if (this.queueProcessorGeneration !== processorGeneration) {
20833
+ if (acquiredLeaseHere) await this.releaseThreadRunLease();
20834
+ return;
20835
+ }
20836
+ let processorFailed = false;
20099
20837
  const processor = this.runQueueProcessor().catch(async (error) => {
20100
20838
  processorFailed = true;
20101
20839
  console.error(`Queue processing error for thread ${this.thread_id}:`, error);
@@ -20113,7 +20851,11 @@ var Agent = class {
20113
20851
  if (this.queueWakeRequested) void this.startQueueProcessor(false);
20114
20852
  return;
20115
20853
  }
20116
- if (failed) return;
20854
+ if (failed) {
20855
+ this.cancelThreadRunLeaseRetry();
20856
+ await this.releaseThreadRunLease();
20857
+ return;
20858
+ }
20117
20859
  this.queueProcessorRetryAttempt = 0;
20118
20860
  if (this.queueWakeRequested) {
20119
20861
  void this.startQueueProcessor(false);
@@ -20126,7 +20868,11 @@ var Agent = class {
20126
20868
  void this.startQueueProcessor(false);
20127
20869
  return;
20128
20870
  }
20129
- if (pendingMessages.length === 0) return;
20871
+ if (pendingMessages.length === 0) {
20872
+ this.cancelThreadRunLeaseRetry();
20873
+ await this.releaseThreadRunLease();
20874
+ return;
20875
+ }
20130
20876
  const processingMessages = await this.getQueueStore().getProcessingMessages(
20131
20877
  this.thread_id,
20132
20878
  this.queueScope()
@@ -20138,12 +20884,20 @@ var Agent = class {
20138
20884
  }
20139
20885
  if (processingMessages.length > 0) {
20140
20886
  const runStatus = await this.getRunStatus();
20141
- if (runStatus === "busy" /* BUSY */ || runStatus === "interrupted" /* INTERRUPTED */) return;
20887
+ if (runStatus === "busy" /* BUSY */ || runStatus === "interrupted" /* INTERRUPTED */) {
20888
+ this.cancelThreadRunLeaseRetry();
20889
+ await this.releaseThreadRunLease();
20890
+ return;
20891
+ }
20142
20892
  }
20143
20893
  void this.startQueueProcessor(false);
20144
20894
  } catch (error) {
20145
20895
  console.error(`Queue processor finalization failed for thread ${this.thread_id}:`, error);
20146
20896
  await this.scheduleQueueProcessorRetry(error, generation);
20897
+ if (!this.queueProcessorPromise) {
20898
+ await this.releaseThreadRunLease();
20899
+ this.cancelThreadRunLeaseRetry();
20900
+ }
20147
20901
  }
20148
20902
  }
20149
20903
  async scheduleQueueProcessorRetry(error, generation) {
@@ -20181,6 +20935,36 @@ var Agent = class {
20181
20935
  this.queueProcessorRetryAttempt = 0;
20182
20936
  this.queueWakeRequested = false;
20183
20937
  }
20938
+ /**
20939
+ * Bounded re-attempt after losing the thread-run lease to a peer. Covers the
20940
+ * narrow window where the peer releases the lease without having observed a
20941
+ * just-enqueued message. Bounded so a genuinely long-held thread does not make
20942
+ * this replica poll forever — the owning replica's loop drains new messages.
20943
+ */
20944
+ scheduleThreadRunLeaseRetry() {
20945
+ if (this.threadRunLeaseRetryTimer || this.threadRunLeaseRetryAttempt >= THREAD_RUN_LEASE_MAX_RETRIES) return;
20946
+ const delay = Math.min(
20947
+ THREAD_RUN_LEASE_RETRY_BASE_MS * 2 ** this.threadRunLeaseRetryAttempt,
20948
+ THREAD_RUN_LEASE_RETRY_CAP_MS
20949
+ );
20950
+ this.threadRunLeaseRetryAttempt += 1;
20951
+ this.threadRunLeaseRetryTimer = setTimeout(() => {
20952
+ this.threadRunLeaseRetryTimer = void 0;
20953
+ void this.startQueueProcessor(false);
20954
+ }, delay);
20955
+ }
20956
+ /**
20957
+ * Clears any pending thread-run lease retry and resets its backoff budget.
20958
+ *
20959
+ * @remarks Called on lease acquisition and on every definitive processor
20960
+ * stop so the next enqueue starts from the base delay. Never called on
20961
+ * continue/re-arm paths, which must preserve the bounded budget.
20962
+ */
20963
+ cancelThreadRunLeaseRetry() {
20964
+ if (this.threadRunLeaseRetryTimer) clearTimeout(this.threadRunLeaseRetryTimer);
20965
+ this.threadRunLeaseRetryTimer = void 0;
20966
+ this.threadRunLeaseRetryAttempt = 0;
20967
+ }
20184
20968
  async runQueueProcessor() {
20185
20969
  const store = this.getQueueStore();
20186
20970
  const processingMessages = await store.getProcessingMessages(this.thread_id, this.queueScope());
@@ -20325,6 +21109,38 @@ var Agent = class {
20325
21109
  console.error(`[Agent] Failed to initialize agent lattice for ${this.assistant_id} (tenant: ${this.tenant_id}):`, error);
20326
21110
  throw error;
20327
21111
  }
21112
+ let acquiredLeaseHere = false;
21113
+ if (this.threadRunLease === null) {
21114
+ const leaseStore = this.getLeaseStore();
21115
+ if (leaseStore) {
21116
+ const lease = await tryAcquireThreadRun({
21117
+ store: leaseStore,
21118
+ tenantId: this.tenant_id,
21119
+ assistantId: this.assistant_id,
21120
+ threadId: this.thread_id,
21121
+ owner: getReplicaId(),
21122
+ ttlMs: THREAD_RUN_LEASE_TTL_MS,
21123
+ onLost: () => {
21124
+ console.warn(`[Agent] Thread-run lease lost for thread ${this.thread_id}; aborting the held run`);
21125
+ this.abortController?.abort();
21126
+ }
21127
+ });
21128
+ if (!lease) {
21129
+ return { status: await this.getRunStatus(), settled: false, leaseContended: true };
21130
+ }
21131
+ this.threadRunLease = lease;
21132
+ acquiredLeaseHere = true;
21133
+ this.cancelThreadRunLeaseRetry();
21134
+ }
21135
+ }
21136
+ try {
21137
+ return await this.resumeTaskLocked();
21138
+ } finally {
21139
+ if (acquiredLeaseHere && !this.queueProcessorPromise) await this.releaseThreadRunLease();
21140
+ }
21141
+ }
21142
+ /** Recovery body of {@link resumeTask}, executed while thread ownership is settled. */
21143
+ async resumeTaskLocked() {
20328
21144
  const store = this.getQueueStore();
20329
21145
  const processingMessages = await store.getProcessingMessages(this.thread_id, this.queueScope());
20330
21146
  const preRunState = await this.getCurrentState();
@@ -20368,7 +21184,7 @@ var Agent = class {
20368
21184
  }
20369
21185
  } else if (resumedStatus === "error" /* ERROR */) {
20370
21186
  this.clearRecoveryBlock();
20371
- const failureReason = "Agent execution ended in an error state";
21187
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
20372
21188
  for (const msg of processingMessages) {
20373
21189
  this.addChunk({ type: "message_failed", data: { id: msg.id, content: failureReason } });
20374
21190
  this.publish("message:failed", {
@@ -20404,7 +21220,7 @@ var Agent = class {
20404
21220
  } else if (runStatus === "error" /* ERROR */) {
20405
21221
  this.processingExecutionContext(processingMessages);
20406
21222
  this.clearRecoveryBlock();
20407
- const failureReason = "Agent execution ended in an error state";
21223
+ const failureReason = executionErrorFromSnapshot(preRunState) ?? "Agent execution ended in an error state";
20408
21224
  for (const msg of processingMessages) {
20409
21225
  this.addChunk({ type: "message_failed", data: { id: msg.id, content: failureReason } });
20410
21226
  this.publish("message:failed", {
@@ -20440,6 +21256,8 @@ var Agent = class {
20440
21256
  */
20441
21257
  async abort() {
20442
21258
  this.cancelQueueProcessorRetry();
21259
+ this.cancelThreadRunLeaseRetry();
21260
+ await this.releaseThreadRunLease();
20443
21261
  this.clearRecoveryBlock();
20444
21262
  this.queueProcessorGeneration += 1;
20445
21263
  if (this.abortController) {
@@ -20550,8 +21368,19 @@ var AgentInstanceManager = class _AgentInstanceManager {
20550
21368
  }
20551
21369
  return _AgentInstanceManager._instance;
20552
21370
  }
21371
+ /**
21372
+ * A thread's identity is `(tenant_id, assistant_id, thread_id)`.
21373
+ *
21374
+ * Workspace/project are execution scope chosen when the instance is created,
21375
+ * not part of identity: including them let the same thread exist as several
21376
+ * Agents when callers defaulted optional workspace/project headers
21377
+ * differently (e.g. `createRun` passing `undefined` while `abort` defaulted
21378
+ * to `"default"`), so control-plane calls could address a different instance
21379
+ * than the one running. `undefined`/`null` normalize to `""`; ids are assumed
21380
+ * not to contain `:` (UUID-shaped in practice).
21381
+ */
20553
21382
  getKey(params) {
20554
- return `${params.tenant_id}:${params.assistant_id}:${params.thread_id}:${params.workspace_id}:${params.project_id}`;
21383
+ return [params.tenant_id, params.assistant_id, params.thread_id].map((value) => value ?? "").join(":");
20555
21384
  }
20556
21385
  /**
20557
21386
  * Get or create Agent instance for a thread
@@ -20565,6 +21394,24 @@ var AgentInstanceManager = class _AgentInstanceManager {
20565
21394
  }
20566
21395
  return this.agents.get(key5);
20567
21396
  }
21397
+ /**
21398
+ * Get the managed Agent for a thread WITHOUT creating or registering one.
21399
+ *
21400
+ * Read-only control-plane callers (state, memory, inbox) must not be the first
21401
+ * to establish a thread's execution scope: since identity is
21402
+ * `(tenant_id, assistant_id, thread_id)`, whichever caller reaches
21403
+ * {@link getAgent} first fixes the instance's workspace/project for its whole
21404
+ * lifetime, and a later trusted dispatch on that thread would then fail
21405
+ * trusted-scope validation. This returns the existing managed instance when
21406
+ * present, otherwise a transient unregistered Agent that is sufficient for
21407
+ * state reads and disappears with the request.
21408
+ *
21409
+ * @param params - Thread identity; scope is only used for the transient Agent.
21410
+ * @returns The managed instance if any, else an unregistered read-only Agent.
21411
+ */
21412
+ getAgentForRead(params) {
21413
+ return this.agents.get(this.getKey(params)) ?? new Agent(params);
21414
+ }
20568
21415
  /**
20569
21416
  * Check if an agent instance exists for the thread
20570
21417
  */
@@ -20600,55 +21447,6 @@ var AgentInstanceManager = class _AgentInstanceManager {
20600
21447
  });
20601
21448
  this.agents.clear();
20602
21449
  }
20603
- /**
20604
- * Restore agent instances for threads with pending messages after server restart
20605
- * Queries the message queue store for threads with pending/processing messages
20606
- * and recreates agent instances to resume processing
20607
- */
20608
- async restore() {
20609
- const stats = { restored: 0, errors: 0 };
20610
- try {
20611
- const queueStoreLattice = storeLatticeManager.getStoreLattice("default", "threadMessageQueue");
20612
- const queueStore = queueStoreLattice.store;
20613
- const threadsWithPending = await queueStore.getThreadsWithPendingMessages();
20614
- if (threadsWithPending.length === 0) {
20615
- console.log("[AgentInstanceManager] No threads with pending messages found");
20616
- return stats;
20617
- }
20618
- console.log(`[AgentInstanceManager] Found ${threadsWithPending.length} threads with pending messages, restoring...`);
20619
- for (const threadInfo of threadsWithPending) {
20620
- try {
20621
- await this.restoreThread(threadInfo);
20622
- stats.restored++;
20623
- } catch (error) {
20624
- console.error(`[AgentInstanceManager] Failed to restore thread ${threadInfo.threadId}:`, error);
20625
- stats.errors++;
20626
- }
20627
- }
20628
- console.log(`[AgentInstanceManager] Restore complete: ${stats.restored} restored, ${stats.errors} errors`);
20629
- return stats;
20630
- } catch (error) {
20631
- console.error("[AgentInstanceManager] Restore failed:", error);
20632
- throw error;
20633
- }
20634
- }
20635
- /**
20636
- * Restore a single thread
20637
- * Delegates actual recovery logic to Agent.resumeTask()
20638
- */
20639
- async restoreThread(threadInfo) {
20640
- const { tenantId: tenantId2, assistantId, threadId, workspaceId, projectId } = threadInfo;
20641
- const threadParams = {
20642
- tenant_id: tenantId2,
20643
- assistant_id: assistantId,
20644
- thread_id: threadId,
20645
- workspace_id: workspaceId,
20646
- project_id: projectId
20647
- };
20648
- const agent = this.getAgent(threadParams);
20649
- await agent.resumeTask();
20650
- console.log(`[AgentInstanceManager] Restored thread ${threadId}`);
20651
- }
20652
21450
  };
20653
21451
  var agentInstanceManager = AgentInstanceManager.getInstance();
20654
21452
 
@@ -21119,27 +21917,27 @@ function createCheckAsyncTaskTool() {
21119
21917
  if (!mainAgent) {
21120
21918
  return "Cannot access main agent state.";
21121
21919
  }
21122
- const cached = mainAgent.getAsyncTask(task_id);
21123
- if (!cached) {
21920
+ const cached2 = mainAgent.getAsyncTask(task_id);
21921
+ if (!cached2) {
21124
21922
  return `Task ${task_id} not found. Use list_async_tasks to see all tasks.`;
21125
21923
  }
21126
21924
  try {
21127
21925
  if (!agentInstanceManager.hasAgent({
21128
- assistant_id: cached.assistantId,
21926
+ assistant_id: cached2.assistantId,
21129
21927
  thread_id: task_id,
21130
21928
  tenant_id: mainAgent.tenant_id
21131
21929
  })) {
21132
- return `Task ${task_id}: not found (may have been cleaned up). Status was: ${cached.status}`;
21930
+ return `Task ${task_id}: not found (may have been cleaned up). Status was: ${cached2.status}`;
21133
21931
  }
21134
21932
  const subAgent = agentInstanceManager.getAgent({
21135
- assistant_id: cached.assistantId,
21933
+ assistant_id: cached2.assistantId,
21136
21934
  thread_id: task_id,
21137
21935
  tenant_id: mainAgent.tenant_id
21138
21936
  });
21139
21937
  const status = await subAgent.getRunStatus();
21140
21938
  if (status === "busy") {
21141
21939
  return `Task ${task_id}: still running.
21142
- Description: ${cached.description}`;
21940
+ Description: ${cached2.description}`;
21143
21941
  }
21144
21942
  if (status === "idle") {
21145
21943
  const state = await subAgent.getCurrentState();
@@ -21150,21 +21948,21 @@ Description: ${cached.description}`;
21150
21948
  mainAgent.updateAsyncTaskStatus(task_id, "completed");
21151
21949
  const result = lastAI?.content ?? "(completed, no output)";
21152
21950
  return `Task ${task_id}: COMPLETED.
21153
- Description: ${cached.description}
21951
+ Description: ${cached2.description}
21154
21952
  Result:
21155
21953
  ${result}`;
21156
21954
  }
21157
21955
  if (status === "error") {
21158
21956
  mainAgent.updateAsyncTaskStatus(task_id, "failed");
21159
21957
  return `Task ${task_id}: failed.
21160
- Description: ${cached.description}`;
21958
+ Description: ${cached2.description}`;
21161
21959
  }
21162
21960
  if (status === "interrupted") {
21163
21961
  return `Task ${task_id}: interrupted (waiting for input).
21164
- Description: ${cached.description}`;
21962
+ Description: ${cached2.description}`;
21165
21963
  }
21166
21964
  return `Task ${task_id}: ${status}.
21167
- Description: ${cached.description}`;
21965
+ Description: ${cached2.description}`;
21168
21966
  } catch (err) {
21169
21967
  return `Task ${task_id}: error checking status: ${err instanceof Error ? err.message : String(err)}`;
21170
21968
  }
@@ -21237,25 +22035,25 @@ function createCancelAsyncTaskTool() {
21237
22035
  if (!mainAgent) {
21238
22036
  return "Cannot access main agent state.";
21239
22037
  }
21240
- const cached = mainAgent.getAsyncTask(task_id);
21241
- if (!cached) {
22038
+ const cached2 = mainAgent.getAsyncTask(task_id);
22039
+ if (!cached2) {
21242
22040
  return `Task ${task_id} not found.`;
21243
22041
  }
21244
22042
  try {
21245
22043
  const subAgentExists = agentInstanceManager.hasAgent({
21246
- assistant_id: cached.assistantId,
22044
+ assistant_id: cached2.assistantId,
21247
22045
  thread_id: task_id,
21248
22046
  tenant_id: mainAgent.tenant_id
21249
22047
  });
21250
22048
  if (subAgentExists) {
21251
22049
  const subAgent = agentInstanceManager.getAgent({
21252
- assistant_id: cached.assistantId,
22050
+ assistant_id: cached2.assistantId,
21253
22051
  thread_id: task_id,
21254
22052
  tenant_id: mainAgent.tenant_id
21255
22053
  });
21256
22054
  await subAgent.abort();
21257
22055
  agentInstanceManager.removeAgent({
21258
- assistant_id: cached.assistantId,
22056
+ assistant_id: cached2.assistantId,
21259
22057
  thread_id: task_id,
21260
22058
  tenant_id: mainAgent.tenant_id
21261
22059
  });
@@ -21498,6 +22296,48 @@ var MemoryScheduleStorage = class {
21498
22296
  });
21499
22297
  }
21500
22298
  }
22299
+ /**
22300
+ * Atomically claims one due fire by transitioning the task `pending -> running`.
22301
+ *
22302
+ * @param taskId Task to claim.
22303
+ * @returns True when this caller won the claim (task was `pending`); false if
22304
+ * another replica already claimed it or it is not pending.
22305
+ */
22306
+ async claimScheduledRun(taskId) {
22307
+ const task = this.tasks.get(taskId);
22308
+ if (!task || task.status !== import_protocols11.ScheduledTaskStatus.PENDING) {
22309
+ return false;
22310
+ }
22311
+ this.tasks.set(taskId, {
22312
+ ...task,
22313
+ status: import_protocols11.ScheduledTaskStatus.RUNNING,
22314
+ updatedAt: Date.now()
22315
+ });
22316
+ return true;
22317
+ }
22318
+ /**
22319
+ * Requeues `running` tasks whose `updatedAt` is older than `olderThanMs` back
22320
+ * to `pending` (recovery after a crash that left a claim unsettled).
22321
+ *
22322
+ * @param olderThanMs Age threshold in milliseconds.
22323
+ * @returns The number of tasks requeued.
22324
+ */
22325
+ async requeueStaleRunning(olderThanMs) {
22326
+ const now = Date.now();
22327
+ const cutoff = now - olderThanMs;
22328
+ let requeued = 0;
22329
+ for (const [taskId, task] of this.tasks.entries()) {
22330
+ if (task.status === import_protocols11.ScheduledTaskStatus.RUNNING && task.updatedAt < cutoff) {
22331
+ this.tasks.set(taskId, {
22332
+ ...task,
22333
+ status: import_protocols11.ScheduledTaskStatus.PENDING,
22334
+ updatedAt: now
22335
+ });
22336
+ requeued++;
22337
+ }
22338
+ }
22339
+ return requeued;
22340
+ }
21501
22341
  /**
21502
22342
  * Delete task
21503
22343
  */
@@ -21862,6 +22702,7 @@ function describeCronExpression(expression) {
21862
22702
  }
21863
22703
 
21864
22704
  // src/schedule_lattice/DefaultScheduleClient.ts
22705
+ var STALE_RUNNING_MS = 30 * 6e4;
21865
22706
  var _DefaultScheduleClient = class _DefaultScheduleClient {
21866
22707
  constructor(storage) {
21867
22708
  this.handlers = /* @__PURE__ */ new Map();
@@ -22102,6 +22943,19 @@ var _DefaultScheduleClient = class _DefaultScheduleClient {
22102
22943
  }
22103
22944
  // ===== Recovery =====
22104
22945
  async restore() {
22946
+ try {
22947
+ const requeued = await this.storage.requeueStaleRunning(STALE_RUNNING_MS);
22948
+ if (requeued > 0) {
22949
+ console.log(
22950
+ `[Scheduler] Requeued ${requeued} stale running task(s)`
22951
+ );
22952
+ }
22953
+ } catch (error) {
22954
+ console.error(
22955
+ "[Scheduler] Failed to requeue stale running tasks:",
22956
+ error
22957
+ );
22958
+ }
22105
22959
  const activeTasks = await this.storage.getActiveTasks();
22106
22960
  let restored = 0;
22107
22961
  for (const task of activeTasks) {
@@ -22162,6 +23016,16 @@ var _DefaultScheduleClient = class _DefaultScheduleClient {
22162
23016
  });
22163
23017
  }
22164
23018
  async executeTask(task) {
23019
+ let claimed = false;
23020
+ try {
23021
+ claimed = await this.storage.claimScheduledRun(task.taskId);
23022
+ } catch (error) {
23023
+ console.error(`[Scheduler] Failed to claim task ${task.taskId}:`, error);
23024
+ return;
23025
+ }
23026
+ if (!claimed) {
23027
+ return;
23028
+ }
22165
23029
  const handler = this.handlers.get(task.taskType);
22166
23030
  if (!handler) {
22167
23031
  console.error(
@@ -22173,9 +23037,6 @@ var _DefaultScheduleClient = class _DefaultScheduleClient {
22173
23037
  });
22174
23038
  return;
22175
23039
  }
22176
- await this.storage.update(task.taskId, {
22177
- status: import_protocols12.ScheduledTaskStatus.RUNNING
22178
- });
22179
23040
  console.log(`[Scheduler] Executing task: ${task.taskId}`);
22180
23041
  try {
22181
23042
  const latestTask = await this.storage.get(task.taskId);
@@ -26899,8 +27760,8 @@ var VectorStoreProviderManager = class _VectorStoreProviderManager extends BaseL
26899
27760
  * @param key Provider key name
26900
27761
  * @param provider VectorStoreProvider implementation
26901
27762
  */
26902
- registerProvider(key5, provider) {
26903
- const lattice = { key: key5, provider };
27763
+ registerProvider(key5, provider2) {
27764
+ const lattice = { key: key5, provider: provider2 };
26904
27765
  this.registerWithTenant("default", key5, lattice);
26905
27766
  }
26906
27767
  /**
@@ -26936,7 +27797,7 @@ var VectorStoreProviderManager = class _VectorStoreProviderManager extends BaseL
26936
27797
  };
26937
27798
  var vectorStoreProviderManager = VectorStoreProviderManager.getInstance();
26938
27799
  vectorStoreProviderManager.registerProvider("default", new MemoryVectorStoreProvider());
26939
- var registerVectorStoreProvider = (key5, provider) => vectorStoreProviderManager.registerProvider(key5, provider);
27800
+ var registerVectorStoreProvider = (key5, provider2) => vectorStoreProviderManager.registerProvider(key5, provider2);
26940
27801
  var getVectorStoreProvider = (key5) => vectorStoreProviderManager.getProvider(key5);
26941
27802
 
26942
27803
  // src/store_lattice/configureStores.ts
@@ -29638,7 +30499,110 @@ independently before the workflow's integration eval.
29638
30499
 
29639
30500
  An unsupported architecture conversion interrupts the flow and requests a new
29640
30501
  user decision. Do not route backward to the Charter or to [[agent-build]], and do
29641
- not create a replacement.`
30502
+ not create a replacement.`,
30503
+ "ptc": `---
30504
+ name: ptc
30505
+ description: Programmatic Tool Calling (PTC) \u2014 write sandbox code that discovers and calls platform Open capabilities (MCP tools) through the gateway. Use when orchestration is multi-step, data-heavy, or needs loops/branches across platform tools instead of one-at-a-time model tool calls.
30506
+ metadata:
30507
+ role: workflow
30508
+ domain: orchestration
30509
+ verified: unverified
30510
+ ---
30511
+
30512
+ # Programmatic Tool Calling (PTC)
30513
+
30514
+ PTC means the model writes and runs code that calls platform tools itself, instead
30515
+ of calling tools one at a time. Reach for it when orchestration is multi-step,
30516
+ data-heavy, or needs a loop/branch that would be wasteful as a chain of model tool
30517
+ calls.
30518
+
30519
+ ## Where the code runs
30520
+
30521
+ Run the code with \`code_eval\` (backed by \`shell_exec\`). Each execution process is
30522
+ injected with two environment variables:
30523
+
30524
+ - \`API_GATEWAY_URL\` \u2014 the gateway base URL.
30525
+ - \`OPEN_API_TOKEN\` \u2014 a short-lived bearer token **self-bound to this agent**. It is
30526
+ not reusable elsewhere.
30527
+
30528
+ The token already encodes this agent's authority: the platform reflects the agent's
30529
+ own configured middleware into Open grants, plus a small always-on baseline
30530
+ (\`kb\` read-only and \`sandbox:self\`). So the callable set = that baseline \u222A the
30531
+ domains your configured middleware exposes \u2014 and nothing beyond it.
30532
+
30533
+ ## Client
30534
+
30535
+ The sandbox must have the zero-dependency \`@axiom-lattice/open-mcp-client\` package.
30536
+ Get it one of two ways:
30537
+
30538
+ - **Preinstalled in the sandbox image** (recommended): \`open-mcp\` is on \`PATH\`; for
30539
+ \`require("@axiom-lattice/open-mcp-client")\` to resolve, install it into the working
30540
+ directory or point \`NODE_PATH\` at the global \`node_modules\`.
30541
+ - **Install it in this run** when the sandbox has network + npm:
30542
+
30543
+ \`\`\`bash
30544
+ npm install @axiom-lattice/open-mcp-client
30545
+ # or use without installing:
30546
+ npx @axiom-lattice/open-mcp-client tools list --json
30547
+ \`\`\`
30548
+
30549
+ \`\`\`js
30550
+ const { OpenMcpClient } = require("@axiom-lattice/open-mcp-client");
30551
+ const client = OpenMcpClient.fromEnv(); // reads API_GATEWAY_URL + OPEN_API_TOKEN
30552
+ \`\`\`
30553
+
30554
+ CLI equivalents (config comes from the same env vars):
30555
+
30556
+ \`\`\`bash
30557
+ open-mcp tools list --json
30558
+ open-mcp tools call kb_search --json '{"query":"refund policy"}'
30559
+ \`\`\`
30560
+
30561
+ ## Discover, then call
30562
+
30563
+ 1. **Discover first.** Call \`await client.listTools()\`. This returns exactly the
30564
+ tools this agent is authorized to call (the server filters by the token's grants
30565
+ on every request, so it is the source of truth).
30566
+ 2. **Only call discovered tools.** Pick a tool from that list and call
30567
+ \`await client.callTool(name, args)\` with args matching the tool's \`inputSchema\`.
30568
+ 3. **Print the final result as JSON to stdout** so the calling agent can consume it.
30569
+ Keep intermediate logs minimal.
30570
+
30571
+ An unconfigured domain isn't registered, so calling it returns an \`isError\`
30572
+ tool-not-found result; a registered tool refused by the token's grants surfaces
30573
+ \`GRANT_DENIED\`. Either way the capability is **not configured for this agent**.
30574
+ Do not retry or work around it \u2014 drop that step or tell the user which
30575
+ middleware/domain must be enabled. A denied call is expected behavior, not a
30576
+ transient failure.
30577
+
30578
+ ## Tips
30579
+
30580
+ - Fan out with \`Promise.all\` over many items instead of many sequential model turns;
30581
+ that is the main win of PTC.
30582
+ - Inspect \`tool.inputSchema\` before calling to avoid schema-validation errors.
30583
+ - Reduce large results in code and return only the fields the agent needs.
30584
+ - The token is short-lived; for very long jobs re-read the env per \`code_eval\` run
30585
+ rather than caching the token in a file.
30586
+
30587
+ ## Worked example
30588
+
30589
+ \`\`\`js
30590
+ const { OpenMcpClient } = require("@axiom-lattice/open-mcp-client");
30591
+
30592
+ async function main() {
30593
+ const client = OpenMcpClient.fromEnv(); // API_GATEWAY_URL + OPEN_API_TOKEN
30594
+ const tools = await client.listTools(); // exactly what this agent may call
30595
+ const pick = tools.find((t) => t.name === "kb_search") ?? tools[0];
30596
+ const out = await client.callTool(pick.name, { query: "refund policy" });
30597
+ console.log(JSON.stringify({ called: pick.name, result: out.json() }));
30598
+ }
30599
+
30600
+ main().catch((err) => { console.error(String(err)); process.exit(1); });
30601
+ \`\`\`
30602
+
30603
+ Run this in \`code_eval\`. The first run proves env + client wiring; then extend it
30604
+ into the real fan-out/aggregation the task needs.
30605
+ `
29642
30606
  };
29643
30607
  function getBuiltInSkillMeta(name) {
29644
30608
  const content = BUILTIN_SKILLS[name];
@@ -32772,9 +33736,9 @@ async function getOrCreateCollectionVectorStore(name, embeddingKey, tenantId2, p
32772
33736
  const pendingInitialization = pendingVectorStoreInitializations.get(storeKey);
32773
33737
  if (pendingInitialization) return pendingInitialization;
32774
33738
  const initialization = (async () => {
32775
- const provider = vectorStoreProviderManager.getProvider(providerKey);
33739
+ const provider2 = vectorStoreProviderManager.getProvider(providerKey);
32776
33740
  const tableName = buildTableName(tenantId2, name);
32777
- const vectorStore = await provider.create({ tableName, embeddingKey });
33741
+ const vectorStore = await provider2.create({ tableName, embeddingKey });
32778
33742
  vectorStoreLatticeManager.registerLattice(storeKey, vectorStore);
32779
33743
  return vectorStore;
32780
33744
  })();
@@ -32792,9 +33756,9 @@ async function getCollectionEntryCount(name, embeddingKey, tenantId2) {
32792
33756
  return vs.getDocumentCount();
32793
33757
  }
32794
33758
  try {
32795
- const provider = vectorStoreProviderManager.getProvider("default");
32796
- if (provider.getEntryCount) {
32797
- return provider.getEntryCount(buildTableName(tenantId2, name));
33759
+ const provider2 = vectorStoreProviderManager.getProvider("default");
33760
+ if (provider2.getEntryCount) {
33761
+ return provider2.getEntryCount(buildTableName(tenantId2, name));
32798
33762
  }
32799
33763
  } catch {
32800
33764
  }
@@ -32806,9 +33770,9 @@ async function listCollectionEntries(name, embeddingKey, tenantId2) {
32806
33770
  return vs.getAllDocuments();
32807
33771
  }
32808
33772
  try {
32809
- const provider = vectorStoreProviderManager.getProvider("default");
32810
- if (provider.listEntries) {
32811
- return provider.listEntries(buildTableName(tenantId2, name));
33773
+ const provider2 = vectorStoreProviderManager.getProvider("default");
33774
+ if (provider2.listEntries) {
33775
+ return provider2.listEntries(buildTableName(tenantId2, name));
32812
33776
  }
32813
33777
  } catch {
32814
33778
  }
@@ -32818,9 +33782,9 @@ async function removeCollectionVectorStore(name, tenantId2) {
32818
33782
  const storeKey = buildKey(tenantId2, name);
32819
33783
  const tableName = buildTableName(tenantId2, name);
32820
33784
  try {
32821
- const provider = vectorStoreProviderManager.getProvider("default");
32822
- if (provider.dropTable) {
32823
- await provider.dropTable(tableName);
33785
+ const provider2 = vectorStoreProviderManager.getProvider("default");
33786
+ if (provider2.dropTable) {
33787
+ await provider2.dropTable(tableName);
32824
33788
  }
32825
33789
  } catch {
32826
33790
  }
@@ -33552,7 +34516,7 @@ function parseRecursiveGrepOutput(output) {
33552
34516
  }
33553
34517
 
33554
34518
  // src/sandbox_lattice/packDirectory.ts
33555
- var import_node_crypto5 = require("crypto");
34519
+ var import_node_crypto6 = require("crypto");
33556
34520
  var posix2 = __toESM(require("path/posix"));
33557
34521
  var MAX_PACK_ENTRIES = 1e4;
33558
34522
  var MAX_PACK_FILE_BYTES = 100 * 1024 * 1024;
@@ -33578,7 +34542,7 @@ function buildRemotePackDirectoryCommand(parentDir, sourceName, archiveName) {
33578
34542
  const parent = quotePosixShellArg(parentDir);
33579
34543
  const name = quotePosixShellArg(sourceName);
33580
34544
  const lock = quotePosixShellArg(`.${archiveName}.lock`);
33581
- const tempDir = quotePosixShellArg(`.${archiveName}.tmp-${(0, import_node_crypto5.randomBytes)(16).toString("hex")}`);
34545
+ const tempDir = quotePosixShellArg(`.${archiveName}.tmp-${(0, import_node_crypto6.randomBytes)(16).toString("hex")}`);
33582
34546
  const archivePath = joinPhysicalPath(parentDir, archiveName);
33583
34547
  const archive = quotePosixShellArg(archivePath);
33584
34548
  return [
@@ -35136,12 +36100,12 @@ var DaytonaProvider = class {
35136
36100
 
35137
36101
  // src/sandbox_lattice/providers/LocalSandboxProvider.ts
35138
36102
  var path6 = __toESM(require("path"));
35139
- var os = __toESM(require("os"));
36103
+ var os2 = __toESM(require("os"));
35140
36104
  var fs4 = __toESM(require("fs/promises"));
35141
36105
 
35142
36106
  // src/sandbox_lattice/LocalSandboxInstance.ts
35143
36107
  var import_node_child_process = require("child_process");
35144
- var import_node_crypto6 = require("crypto");
36108
+ var import_node_crypto7 = require("crypto");
35145
36109
  var fs3 = __toESM(require("fs/promises"));
35146
36110
  var path5 = __toESM(require("path"));
35147
36111
  var posix5 = __toESM(require("path/posix"));
@@ -35163,6 +36127,32 @@ function assertRegularDeleteTarget(file, stat4) {
35163
36127
  function quoteShellArgument(value) {
35164
36128
  return `'${value.replace(/'/g, "'\\''")}'`;
35165
36129
  }
36130
+ var PLATFORM_SECRET_ENV_VARS = [
36131
+ "OPEN_TOKEN_SECRET",
36132
+ "AUTH_TOKEN_SECRET",
36133
+ "JWT_SECRET",
36134
+ "WEB_APP_ATTACHMENT_SECRET",
36135
+ "LATTICE_ENCRYPTION_KEY",
36136
+ "DATABASE_URL",
36137
+ "REDIS_PASSWORD",
36138
+ "MICROSANDBOX_API_KEY",
36139
+ "DAYTONA_API_KEY",
36140
+ "E2B_API_KEY",
36141
+ "OPENAI_API_KEY",
36142
+ "AZURE_OPENAI_API_KEY",
36143
+ "ANTHROPIC_API_KEY",
36144
+ "TAVILY_API_KEY",
36145
+ "VAPID_PRIVATE_KEY",
36146
+ "SUPABASE_KEY",
36147
+ "A2A_API_KEYS"
36148
+ ];
36149
+ function stripPlatformSecrets(env) {
36150
+ const rest = { ...env };
36151
+ for (const name of PLATFORM_SECRET_ENV_VARS) {
36152
+ delete rest[name];
36153
+ }
36154
+ return rest;
36155
+ }
35166
36156
  function validatePackEntryName(name) {
35167
36157
  if (!name || name === "." || name === ".." || name.includes("\\") || name.includes("/")) {
35168
36158
  throw new Error(`Cannot pack: unsafe entry name '${name}'`);
@@ -35335,7 +36325,7 @@ var LocalSandboxInstance = class {
35335
36325
  timeout: timeoutMs,
35336
36326
  maxBuffer: 10 * 1024 * 1024,
35337
36327
  // 10MB
35338
- env: { ...process.env, HOME: this.rootDir }
36328
+ env: stripPlatformSecrets({ ...process.env, HOME: this.rootDir })
35339
36329
  }
35340
36330
  );
35341
36331
  const output = stderr ? `${stdout}
@@ -35461,7 +36451,7 @@ ${errOut}`.trim() : out.trim();
35461
36451
  };
35462
36452
  await preflight(sourceHost);
35463
36453
  const lockName = `.${filename}.lock`;
35464
- const tempDirectoryName = `.${filename}.tmp-${(0, import_node_crypto6.randomBytes)(16).toString("hex")}`;
36454
+ const tempDirectoryName = `.${filename}.tmp-${(0, import_node_crypto7.randomBytes)(16).toString("hex")}`;
35465
36455
  const sourceOperand = `./${rootName}`;
35466
36456
  tempDirectoryHost = path5.join(realArchiveDirectory, tempDirectoryName);
35467
36457
  tempHost = path5.join(tempDirectoryHost, "archive.zip");
@@ -35600,7 +36590,7 @@ var LocalSandboxProvider = class {
35600
36590
  this.instances = /* @__PURE__ */ new Map();
35601
36591
  this.creating = /* @__PURE__ */ new Map();
35602
36592
  this.createResourceAddress = createResourceAddress;
35603
- this.basePath = config.basePath ?? path6.join(os.homedir(), ".axiom-local-sandbox");
36593
+ this.basePath = config.basePath ?? path6.join(os2.homedir(), ".axiom-local-sandbox");
35604
36594
  }
35605
36595
  async createSandbox(name, _config) {
35606
36596
  const existing = this.instances.get(name);
@@ -36976,6 +37966,10 @@ var TaskLifecycleNotifier = class {
36976
37966
  this.listeners = /* @__PURE__ */ new Set();
36977
37967
  this.tails = /* @__PURE__ */ new Map();
36978
37968
  }
37969
+ /** Installs (or clears) the durable outbox used to fan notifications to other replicas. */
37970
+ setOutbox(outbox2) {
37971
+ this.outbox = outbox2;
37972
+ }
36979
37973
  /**
36980
37974
  * Registers an async lifecycle listener.
36981
37975
  *
@@ -36996,6 +37990,25 @@ var TaskLifecycleNotifier = class {
36996
37990
  * @throws Error when the event is malformed or one or more listeners reject.
36997
37991
  */
36998
37992
  async publish(event) {
37993
+ const snapshot = snapshotNotification(event);
37994
+ const key5 = `${snapshot.tenantId}:${snapshot.taskId}`;
37995
+ const previous = this.tails.get(key5) ?? Promise.resolve();
37996
+ const delivery = previous.catch(() => void 0).then(() => this.deliver(snapshot));
37997
+ this.tails.set(key5, delivery);
37998
+ if (this.outbox) {
37999
+ try {
38000
+ await this.outbox.append({ topic: "task-lifecycle", payload: snapshot, originReplicaId: getReplicaId() });
38001
+ } catch {
38002
+ }
38003
+ }
38004
+ try {
38005
+ await delivery;
38006
+ } finally {
38007
+ if (this.tails.get(key5) === delivery) this.tails.delete(key5);
38008
+ }
38009
+ }
38010
+ /** Delivers one outbox payload to local listeners without re-appending (poller path). */
38011
+ async deliverFromOutbox(event) {
36999
38012
  const snapshot = snapshotNotification(event);
37000
38013
  const key5 = `${snapshot.tenantId}:${snapshot.taskId}`;
37001
38014
  const previous = this.tails.get(key5) ?? Promise.resolve();
@@ -37060,6 +38073,10 @@ var ProjectTaskAdmissionNotifier = class {
37060
38073
  if (!Number.isSafeInteger(timeout) || timeout <= 0) throw new Error("Invalid admission listener timeout");
37061
38074
  this.listenerTimeoutMs = timeout;
37062
38075
  }
38076
+ /** Installs (or clears) the durable outbox used to fan notifications to other replicas. */
38077
+ setOutbox(outbox2) {
38078
+ this.outbox = outbox2;
38079
+ }
37063
38080
  /**
37064
38081
  * Registers a Project task admission listener.
37065
38082
  *
@@ -37079,6 +38096,30 @@ var ProjectTaskAdmissionNotifier = class {
37079
38096
  * @returns A promise settled after every snapshotted listener settles.
37080
38097
  */
37081
38098
  async publish(event) {
38099
+ const snapshot = snapshotNotification2(event);
38100
+ const listeners = [...this.listeners];
38101
+ const key5 = `${snapshot.tenantId}\0${snapshot.taskId}`;
38102
+ const previous = this.tails.get(key5) ?? Promise.resolve();
38103
+ const delivery = previous.catch(() => void 0).then(() => this.deliver(snapshot, listeners));
38104
+ this.tails.set(key5, delivery);
38105
+ if (this.outbox) {
38106
+ try {
38107
+ await this.outbox.append({
38108
+ topic: "project-task-admission",
38109
+ payload: snapshot,
38110
+ originReplicaId: getReplicaId()
38111
+ });
38112
+ } catch {
38113
+ }
38114
+ }
38115
+ try {
38116
+ await delivery;
38117
+ } finally {
38118
+ if (this.tails.get(key5) === delivery) this.tails.delete(key5);
38119
+ }
38120
+ }
38121
+ /** Delivers one outbox payload to local listeners without re-appending (poller path). */
38122
+ async deliverFromOutbox(event) {
37082
38123
  const snapshot = snapshotNotification2(event);
37083
38124
  const listeners = [...this.listeners];
37084
38125
  const key5 = `${snapshot.tenantId}\0${snapshot.taskId}`;
@@ -37148,8 +38189,137 @@ function canonicalTimestamp(value) {
37148
38189
  return Number.isFinite(parsed.getTime()) && parsed.toISOString() === value;
37149
38190
  }
37150
38191
 
38192
+ // src/services/OutboxPoller.ts
38193
+ var OutboxPoller = class {
38194
+ /**
38195
+ * Creates a poller bound to one durable outbox.
38196
+ *
38197
+ * @param deps Store, owner replica id, topic handlers, and optional tuning.
38198
+ */
38199
+ constructor(deps) {
38200
+ this.deps = deps;
38201
+ this.cursor = null;
38202
+ this.polling = false;
38203
+ }
38204
+ /** Captures the starting cursor and begins polling. */
38205
+ async start() {
38206
+ this.cursor = await this.deps.store.latestId();
38207
+ this.timer = setInterval(() => {
38208
+ void this.pollOnce();
38209
+ }, this.deps.intervalMs ?? 1e3);
38210
+ this.timer.unref?.();
38211
+ }
38212
+ /** Stops polling. */
38213
+ stop() {
38214
+ if (this.timer) clearInterval(this.timer);
38215
+ this.timer = void 0;
38216
+ }
38217
+ /** Runs one drain pass (exported for tests). */
38218
+ async pollOnce() {
38219
+ if (this.polling) return;
38220
+ this.polling = true;
38221
+ try {
38222
+ const batchSize = this.deps.batchSize ?? 100;
38223
+ for (; ; ) {
38224
+ const events = await this.deps.store.listAfter(this.cursor, batchSize);
38225
+ if (events.length === 0) break;
38226
+ for (const event of events) {
38227
+ this.cursor = event.id;
38228
+ if (event.originReplicaId === this.deps.owner) continue;
38229
+ const handler = this.deps.handlers[event.topic];
38230
+ if (!handler) continue;
38231
+ try {
38232
+ await this.deliverWithTimeout(handler, event.payload);
38233
+ } catch {
38234
+ this.deps.log?.warn("Outbox delivery failed", { topic: event.topic, id: event.id });
38235
+ }
38236
+ }
38237
+ if (events.length < batchSize) break;
38238
+ }
38239
+ } catch (error) {
38240
+ this.deps.log?.warn("Outbox poll failed", { error: error instanceof Error ? error.message : String(error) });
38241
+ } finally {
38242
+ this.polling = false;
38243
+ }
38244
+ }
38245
+ /**
38246
+ * Runs one handler bounded by `handlerTimeoutMs` so a hung listener cannot
38247
+ * stall cross-replica delivery for this replica.
38248
+ */
38249
+ async deliverWithTimeout(handler, payload) {
38250
+ const timeoutMs = this.deps.handlerTimeoutMs ?? 5e3;
38251
+ let timer;
38252
+ const timeout = new Promise((_resolve, reject) => {
38253
+ timer = setTimeout(() => reject(new Error("Outbox handler timed out")), timeoutMs);
38254
+ timer.unref?.();
38255
+ });
38256
+ try {
38257
+ await Promise.race([Promise.resolve().then(() => handler(payload)), timeout]);
38258
+ } finally {
38259
+ if (timer) clearTimeout(timer);
38260
+ }
38261
+ }
38262
+ };
38263
+
37151
38264
  // src/services/ProjectMutationMutex.ts
37152
38265
  var import_protocols28 = require("@axiom-lattice/protocols");
38266
+
38267
+ // src/services/coordinationLease.ts
38268
+ var configured;
38269
+ function configureCoordinationLeaseStore(store) {
38270
+ configured = store;
38271
+ }
38272
+ function getCoordinationLeaseStore() {
38273
+ return configured;
38274
+ }
38275
+
38276
+ // src/services/withLease.ts
38277
+ var import_node_crypto8 = require("crypto");
38278
+ var LeaseAcquisitionTimeoutError = class extends Error {
38279
+ /**
38280
+ * @param key Lease key that could not be acquired.
38281
+ * @param holder Unique holder that attempted acquisition.
38282
+ * @param timeoutMs How long the caller waited before giving up.
38283
+ */
38284
+ constructor(key5, holder, timeoutMs) {
38285
+ super(`Could not acquire lease '${key5}' for '${holder}' within ${timeoutMs}ms`);
38286
+ this.key = key5;
38287
+ this.holder = holder;
38288
+ this.timeoutMs = timeoutMs;
38289
+ /** Stable machine-readable code. */
38290
+ this.code = "LEASE_ACQUISITION_TIMEOUT";
38291
+ this.name = "LeaseAcquisitionTimeoutError";
38292
+ }
38293
+ };
38294
+ function sleep(ms) {
38295
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
38296
+ }
38297
+ async function withLease(store, key5, ownerLabel, fn, options = {}) {
38298
+ const ttlMs = options.ttlMs ?? 3e4;
38299
+ const acquireTimeoutMs = options.acquireTimeoutMs ?? 1e4;
38300
+ const retryDelayMs = options.retryDelayMs ?? 50;
38301
+ const heartbeatMs = options.heartbeatMs ?? Math.max(1e3, Math.floor(ttlMs / 3));
38302
+ const holder = `${ownerLabel}#${(0, import_node_crypto8.randomUUID)()}`;
38303
+ const deadline = Date.now() + acquireTimeoutMs;
38304
+ for (; ; ) {
38305
+ if (await store.tryAcquire(key5, holder, ttlMs)) break;
38306
+ if (Date.now() >= deadline) throw new LeaseAcquisitionTimeoutError(key5, holder, acquireTimeoutMs);
38307
+ await sleep(retryDelayMs);
38308
+ }
38309
+ const heartbeat = setInterval(() => {
38310
+ void store.renew(key5, holder, ttlMs).catch(() => void 0);
38311
+ }, heartbeatMs);
38312
+ heartbeat.unref?.();
38313
+ try {
38314
+ return await fn();
38315
+ } finally {
38316
+ clearInterval(heartbeat);
38317
+ await store.release(key5, holder).catch(() => void 0);
38318
+ }
38319
+ }
38320
+
38321
+ // src/services/ProjectMutationMutex.ts
38322
+ var MUTATION_LEASE_OPTIONS = { ttlMs: 6e4, acquireTimeoutMs: 9e4, retryDelayMs: 100 };
37153
38323
  function projectKey(scope) {
37154
38324
  const row = (0, import_protocols28.snapshotExactRecord)(scope, ["tenantId", "projectId"]);
37155
38325
  if (!row || typeof row.tenantId !== "string" || !row.tenantId || row.tenantId.includes("\0") || typeof row.projectId !== "string" || !row.projectId || row.projectId.includes("\0")) {
@@ -37165,9 +38335,12 @@ var ProjectMutationMutex = class {
37165
38335
  /** Runs one mutation after all earlier mutations for the same Tenant and Project. */
37166
38336
  async runExclusive(scope, operation, signal) {
37167
38337
  const key5 = projectKey(scope);
38338
+ const leaseKey = `project-mutation:${encodeURIComponent(scope.tenantId)}:${encodeURIComponent(scope.projectId)}`;
37168
38339
  await this.acquire(key5, signal);
37169
38340
  try {
37170
- return await operation();
38341
+ const store = getCoordinationLeaseStore();
38342
+ if (!store) return await operation();
38343
+ return await withLease(store, leaseKey, getReplicaId(), operation, MUTATION_LEASE_OPTIONS);
37171
38344
  } finally {
37172
38345
  this.release(key5);
37173
38346
  }
@@ -37604,11 +38777,11 @@ function snapshotDate(value) {
37604
38777
  }
37605
38778
 
37606
38779
  // src/services/TaskLifecycleService.ts
37607
- var import_node_crypto8 = require("crypto");
38780
+ var import_node_crypto10 = require("crypto");
37608
38781
  var import_protocols31 = require("@axiom-lattice/protocols");
37609
38782
 
37610
38783
  // src/middlewares/taskBelief.ts
37611
- var import_node_crypto7 = require("crypto");
38784
+ var import_node_crypto9 = require("crypto");
37612
38785
  function buildBeliefCompletionEventKey(taskId, result, impacts) {
37613
38786
  const canonical = JSON.stringify({
37614
38787
  beliefImpact: impacts.map((impact) => ({
@@ -37619,7 +38792,7 @@ function buildBeliefCompletionEventKey(taskId, result, impacts) {
37619
38792
  })),
37620
38793
  result: result.trim()
37621
38794
  });
37622
- return (0, import_node_crypto7.createHash)("sha256").update(canonical).digest("hex");
38795
+ return (0, import_node_crypto9.createHash)("sha256").update(canonical).digest("hex");
37623
38796
  }
37624
38797
  function buildCompletionEvidenceDetail(result, impacts, eventKey) {
37625
38798
  return { result, beliefImpact: impacts, eventKey };
@@ -37653,6 +38826,8 @@ function buildParentBeliefActivity(input) {
37653
38826
  }
37654
38827
 
37655
38828
  // src/services/TaskLifecycleService.ts
38829
+ var WORK_ITEM_WRITE_ATTEMPTS = 3;
38830
+ var WORK_ITEM_WRITE_RETRY_DELAYS_MS = [20, 50];
37656
38831
  var RETRYABLE_LIFECYCLE_CODES = /* @__PURE__ */ new Set([
37657
38832
  "TASK_STATUS_CONFLICT",
37658
38833
  "TASK_STORE_WRITE_FAILED",
@@ -37672,9 +38847,9 @@ var BELIEF_OWNER_WRITE_ATTEMPTS = 3;
37672
38847
  function isWellFormedImpact(impact) {
37673
38848
  return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(impact.key) && Number.isInteger(impact.after) && impact.after >= 0 && impact.after <= 100 && impact.basis.trim().length > 0 && impact.basis.length <= 1e3 && !/[\r\n]/.test(impact.basis);
37674
38849
  }
37675
- async function applyBeliefImpacts(taskStore, owner, impacts) {
37676
- if (impacts.length === 0) return { description: owner.description ?? "" };
37677
- let current = owner;
38850
+ async function applyBeliefImpacts(taskStore, owner2, impacts) {
38851
+ if (impacts.length === 0) return { description: owner2.description ?? "" };
38852
+ let current = owner2;
37678
38853
  for (let attempt = 0; attempt < BELIEF_OWNER_WRITE_ATTEMPTS; attempt += 1) {
37679
38854
  const parsed = (0, import_protocols31.parseTaskBeliefState)(current.description ?? "");
37680
38855
  const existingTable = parsed.success;
@@ -37803,14 +38978,14 @@ function sameBeliefOwner(left, right) {
37803
38978
  function sameBeliefOwnerIdentity(left, right) {
37804
38979
  return canonicalJson({ ...left, beliefState: void 0 }) === canonicalJson({ ...right, beliefState: void 0 });
37805
38980
  }
37806
- function canonicalBeliefOwner(owner) {
38981
+ function canonicalBeliefOwner(owner2) {
37807
38982
  const beliefState = {
37808
- entries: owner.beliefState.entries.map((entry) => ({
38983
+ entries: owner2.beliefState.entries.map((entry) => ({
37809
38984
  ...entry,
37810
38985
  basis: entry.basis.trim().replace(/\s+/g, " ")
37811
38986
  })).sort((left, right) => left.key < right.key ? -1 : left.key > right.key ? 1 : 0)
37812
38987
  };
37813
- return { ...owner, beliefState };
38988
+ return { ...owner2, beliefState };
37814
38989
  }
37815
38990
  function eventKeyFor(taskId, result, impacts, beliefOwner) {
37816
38991
  const base = `belief-impact:${taskId}:${buildBeliefCompletionEventKey(taskId, result, impacts)}`;
@@ -37820,7 +38995,7 @@ function canonicalJson(value) {
37820
38995
  return JSON.stringify(value);
37821
38996
  }
37822
38997
  function sha256(value) {
37823
- return (0, import_node_crypto8.createHash)("sha256").update(canonicalJson(value)).digest("hex");
38998
+ return (0, import_node_crypto10.createHash)("sha256").update(canonicalJson(value)).digest("hex");
37824
38999
  }
37825
39000
  function sameEvidenceDetail(detail, taskId, result, impacts, eventKey, beliefOwner) {
37826
39001
  const storedOwner = detail.beliefOwner;
@@ -38019,7 +39194,8 @@ var TaskLifecycleService = class {
38019
39194
  const resumeKey = this.resumeEventKey(task);
38020
39195
  const audit = { eventKey: resumeKey, previousInterruption };
38021
39196
  const context = withLifecycleAudit(task.context, "lifecycle_resume_audit", audit);
38022
- if (input.threadId && !task.context?.thread_id) context.thread_id = input.threadId;
39197
+ if (input.threadId) context.thread_id = input.threadId;
39198
+ if (input.runId) context.run_id = input.runId;
38023
39199
  const updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
38024
39200
  input.tenantId,
38025
39201
  input.taskId,
@@ -38116,7 +39292,13 @@ var TaskLifecycleService = class {
38116
39292
  if (task.status !== "pending") {
38117
39293
  return { ...failure2("TASK_STATUS_CONFLICT", "Task cannot start."), transitioned: false };
38118
39294
  }
38119
- const context = { ...task.context ?? {}, ...input.threadId ? { thread_id: input.threadId } : {} };
39295
+ const context = {
39296
+ ...task.context ?? {},
39297
+ ...input.threadId ? { thread_id: input.threadId } : {},
39298
+ ...input.runId ? { run_id: input.runId } : {},
39299
+ ...input.callerThreadId ? { caller_thread_id: input.callerThreadId } : {},
39300
+ ...input.callerAssistantId ? { caller_assistant_id: input.callerAssistantId } : {}
39301
+ };
38120
39302
  let updated;
38121
39303
  try {
38122
39304
  updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
@@ -38192,7 +39374,9 @@ var TaskLifecycleService = class {
38192
39374
  expectedStatuses: ["failed"],
38193
39375
  updates: { status: "in_progress", failureReason: null },
38194
39376
  summary: "Task retried",
38195
- detail: { previousStatus: "failed" }
39377
+ detail: { previousStatus: "failed" },
39378
+ // A retry dispatches a new run thread; replace a stale persisted link.
39379
+ replaceThread: true
38196
39380
  });
38197
39381
  }
38198
39382
  /**
@@ -39168,8 +40352,8 @@ var TaskLifecycleService = class {
39168
40352
  return { task: existing, parent: parentResult, eventKey, evidence, result, impacts };
39169
40353
  }
39170
40354
  beliefOwnerSnapshot(task, parent) {
39171
- const owner = parent?.ownerType === "agent" ? parent : task;
39172
- const parsed = (0, import_protocols31.parseTaskBeliefState)(owner.description ?? "");
40355
+ const owner2 = parent?.ownerType === "agent" ? parent : task;
40356
+ const parsed = (0, import_protocols31.parseTaskBeliefState)(owner2.description ?? "");
39173
40357
  const beliefState = parsed.success ? parsed.state : { entries: [] };
39174
40358
  if (parent?.ownerType === "agent") {
39175
40359
  return {
@@ -39678,7 +40862,9 @@ var TaskLifecycleService = class {
39678
40862
  }
39679
40863
  if (!input.expectedStatuses.includes(task.status)) return failure2("TASK_STATUS_CONFLICT", "Task status cannot make this transition.");
39680
40864
  const clearedContext = clearInterruptionContext(task.context);
39681
- const withThread = input.threadId && task.context?.thread_id === void 0 ? { ...clearedContext ?? {}, thread_id: input.threadId } : clearedContext;
40865
+ const threadInput = input.threadId && (input.replaceThread || task.context?.thread_id === void 0) ? { thread_id: input.threadId } : {};
40866
+ const runInput = input.runId ? { run_id: input.runId } : {};
40867
+ const withThread = Object.keys(threadInput).length > 0 || Object.keys(runInput).length > 0 ? { ...clearedContext ?? {}, ...threadInput, ...runInput } : clearedContext;
39682
40868
  const updates = { ...input.updates, context: withThread };
39683
40869
  let updated;
39684
40870
  try {
@@ -39716,6 +40902,31 @@ var TaskLifecycleService = class {
39716
40902
  statusEventKey(task, status, detail) {
39717
40903
  return `task-lifecycle:${task.id}:${status}:${task.updatedAt.toISOString()}:${sha256(detail)}`;
39718
40904
  }
40905
+ /**
40906
+ * Writes a lifecycle work-item event, retrying transient store failures.
40907
+ *
40908
+ * @param request Event request passed through to the work-item store.
40909
+ * @returns The persisted or pre-existing work item.
40910
+ * @remarks The write is idempotent by `eventKey`
40911
+ * (`createIfAbsentByEventKey`), so retrying after a transient failure (pool
40912
+ * exhaustion, shutdown, statement timeout, disk IO) is safe. The status CAS has
40913
+ * already committed by this point, and the event key embeds `updatedAt`, so a
40914
+ * lost event cannot be reconstructed later — hence the bounded retry.
40915
+ */
40916
+ async writeWorkItemWithRetry(request) {
40917
+ let lastError;
40918
+ for (let attempt = 0; attempt < WORK_ITEM_WRITE_ATTEMPTS; attempt += 1) {
40919
+ if (attempt > 0) {
40920
+ await new Promise((resolve4) => setTimeout(resolve4, WORK_ITEM_WRITE_RETRY_DELAYS_MS[attempt - 1]));
40921
+ }
40922
+ try {
40923
+ return await this.deps.workItemStore.createIfAbsentByEventKey(request);
40924
+ } catch (error) {
40925
+ lastError = error;
40926
+ }
40927
+ }
40928
+ throw lastError;
40929
+ }
39719
40930
  async writeStatusEvent(task, actor, threadId, action, summary, detail, eventKey) {
39720
40931
  const warningCode = `${action.toUpperCase()}_WORK_ITEM_WRITE_FAILED`;
39721
40932
  const request = {
@@ -39731,7 +40942,7 @@ var TaskLifecycleService = class {
39731
40942
  eventKey
39732
40943
  };
39733
40944
  try {
39734
- const item = await this.deps.workItemStore.createIfAbsentByEventKey(request);
40945
+ const item = await this.writeWorkItemWithRetry(request);
39735
40946
  if (item.eventKey !== request.eventKey) throw new Error("Canonical lifecycle event key mismatch");
39736
40947
  return { eventKey: item.eventKey };
39737
40948
  } catch {
@@ -39862,7 +41073,7 @@ function createTaskLifecycleService(deps) {
39862
41073
  }
39863
41074
 
39864
41075
  // src/services/TaskExecutionService.ts
39865
- var import_node_crypto9 = require("crypto");
41076
+ var import_node_crypto12 = require("crypto");
39866
41077
  var import_node_util3 = require("util");
39867
41078
  var import_protocols32 = require("@axiom-lattice/protocols");
39868
41079
 
@@ -39917,7 +41128,7 @@ function createTaskRunBridge(deps) {
39917
41128
  return { success: true, task: updated };
39918
41129
  },
39919
41130
  async beginRun(input) {
39920
- const { tenantId: tenantId2, actor, threadId } = input;
41131
+ const { tenantId: tenantId2, actor, threadId, runId, callerThreadId, callerAssistantId } = input;
39921
41132
  let task = input.task;
39922
41133
  const warnings = [];
39923
41134
  if (task.status === "pending") {
@@ -39926,7 +41137,10 @@ function createTaskRunBridge(deps) {
39926
41137
  tenantId: tenantId2,
39927
41138
  taskId: task.id,
39928
41139
  actor,
39929
- threadId
41140
+ ...threadId !== void 0 ? { threadId } : {},
41141
+ ...runId !== void 0 ? { runId } : {},
41142
+ ...callerThreadId ? { callerThreadId } : {},
41143
+ ...callerAssistantId ? { callerAssistantId } : {}
39930
41144
  });
39931
41145
  if (!started.success) {
39932
41146
  return {
@@ -40014,7 +41228,19 @@ function createTaskRunBridge(deps) {
40014
41228
  error: "Lifecycle transitions only support agent tasks."
40015
41229
  };
40016
41230
  }
40017
- const result = task.status === "interrupted" ? await deps.lifecycle.resumeInterruption({ tenantId: tenantId2, taskId: task.id, actor, threadId }) : await deps.lifecycle.retryTask({ tenantId: tenantId2, taskId: task.id, actor, threadId });
41231
+ const result = task.status === "interrupted" ? await deps.lifecycle.resumeInterruption({
41232
+ tenantId: tenantId2,
41233
+ taskId: task.id,
41234
+ actor,
41235
+ ...threadId !== void 0 ? { threadId } : {},
41236
+ ...runId !== void 0 ? { runId } : {}
41237
+ }) : await deps.lifecycle.retryTask({
41238
+ tenantId: tenantId2,
41239
+ taskId: task.id,
41240
+ actor,
41241
+ ...threadId !== void 0 ? { threadId } : {},
41242
+ ...runId !== void 0 ? { runId } : {}
41243
+ });
40018
41244
  if (!result.success) {
40019
41245
  return {
40020
41246
  success: false,
@@ -40079,6 +41305,132 @@ function createTaskRunBridge(deps) {
40079
41305
  };
40080
41306
  }
40081
41307
 
41308
+ // src/services/TaskRunRegistry.ts
41309
+ var TaskRunRegistry = class {
41310
+ constructor() {
41311
+ this.live = /* @__PURE__ */ new Set();
41312
+ }
41313
+ /** Marks a task as currently held by a live run. */
41314
+ register(taskId) {
41315
+ this.live.add(taskId);
41316
+ }
41317
+ /** Removes a task once its run has ended. */
41318
+ unregister(taskId) {
41319
+ this.live.delete(taskId);
41320
+ }
41321
+ /** Reports whether a task is currently held by a live run. */
41322
+ isLive(taskId) {
41323
+ return this.live.has(taskId);
41324
+ }
41325
+ /** Returns a snapshot of the live task ids (diagnostics/tests). */
41326
+ snapshot() {
41327
+ return [...this.live];
41328
+ }
41329
+ /** Clears all live entries (tests / process teardown). */
41330
+ clear() {
41331
+ this.live.clear();
41332
+ }
41333
+ };
41334
+ var taskRunRegistry = new TaskRunRegistry();
41335
+ async function safelyLive(probe, task) {
41336
+ try {
41337
+ return await probe(task);
41338
+ } catch {
41339
+ return true;
41340
+ }
41341
+ }
41342
+ async function reconcileStaleTaskRuns(input) {
41343
+ const registry4 = input.registry ?? taskRunRegistry;
41344
+ const converged = [];
41345
+ const convergedTasks = [];
41346
+ for (const task of input.tasks) {
41347
+ if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
41348
+ if (input.isTaskLive && await safelyLive(input.isTaskLive, task)) continue;
41349
+ const result = await input.lifecycle.failTask({
41350
+ tenantId: task.tenantId,
41351
+ taskId: task.id,
41352
+ actor: input.actor,
41353
+ failureReason: "Run is no longer executing this task (no_executor)"
41354
+ });
41355
+ if (result.success) {
41356
+ converged.push(task.id);
41357
+ convergedTasks.push(result.task);
41358
+ }
41359
+ }
41360
+ return { converged, convergedTasks };
41361
+ }
41362
+ async function reconcileTenantTaskRuns(input) {
41363
+ const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
41364
+ const candidates = input.include ? tasks.filter(input.include) : tasks;
41365
+ return reconcileStaleTaskRuns({
41366
+ tasks: candidates,
41367
+ actor: input.actor,
41368
+ lifecycle: input.lifecycle,
41369
+ ...input.registry ? { registry: input.registry } : {},
41370
+ ...input.isTaskLive ? { isTaskLive: input.isTaskLive } : {}
41371
+ });
41372
+ }
41373
+ async function reconcileAllTenantTaskRuns(input) {
41374
+ const tenants = await input.tenantStore.listTenants();
41375
+ const converged = [];
41376
+ const convergedTasks = [];
41377
+ for (const tenant of tenants) {
41378
+ let result;
41379
+ try {
41380
+ result = await reconcileTenantTaskRuns({
41381
+ tenantId: tenant.id,
41382
+ actor: input.actor,
41383
+ taskStore: input.taskStore,
41384
+ lifecycle: input.lifecycle,
41385
+ ...input.registry ? { registry: input.registry } : {},
41386
+ ...input.include ? { include: input.include } : {},
41387
+ ...input.isTaskLive ? { isTaskLive: input.isTaskLive } : {}
41388
+ });
41389
+ } catch {
41390
+ continue;
41391
+ }
41392
+ converged.push(...result.converged);
41393
+ convergedTasks.push(...result.convergedTasks);
41394
+ }
41395
+ return { converged, convergedTasks };
41396
+ }
41397
+
41398
+ // src/services/taskRunLease.ts
41399
+ var import_node_crypto11 = require("crypto");
41400
+ function taskRunLeaseKey(taskId) {
41401
+ return `task-run:${taskId}`;
41402
+ }
41403
+ async function tryAcquireTaskRun(input) {
41404
+ const key5 = taskRunLeaseKey(input.taskId);
41405
+ const holder = `${input.owner}#${(0, import_node_crypto11.randomUUID)()}`;
41406
+ if (!await input.store.tryAcquire(key5, holder, input.ttlMs)) return null;
41407
+ const heartbeatMs = input.heartbeatMs ?? Math.max(1e3, Math.floor(input.ttlMs / 3));
41408
+ let released = false;
41409
+ let lost = false;
41410
+ const heartbeat = setInterval(() => {
41411
+ void input.store.renew(key5, holder, input.ttlMs).then((renewed) => {
41412
+ if (released || renewed || lost) return;
41413
+ lost = true;
41414
+ try {
41415
+ input.onLost?.();
41416
+ } catch {
41417
+ }
41418
+ }).catch(() => void 0);
41419
+ }, heartbeatMs);
41420
+ heartbeat.unref?.();
41421
+ return {
41422
+ get lost() {
41423
+ return lost;
41424
+ },
41425
+ release: async () => {
41426
+ if (released) return;
41427
+ released = true;
41428
+ clearInterval(heartbeat);
41429
+ await input.store.release(key5, holder).catch(() => void 0);
41430
+ }
41431
+ };
41432
+ }
41433
+
40082
41434
  // src/services/ExecutionAuthorityRegistry.ts
40083
41435
  var ManagedTaskStartError = class extends Error {
40084
41436
  /**
@@ -40340,276 +41692,23 @@ async function prepareTaskDispatch(deps, input) {
40340
41692
  agentId: input.agentId,
40341
41693
  actor: input.actor,
40342
41694
  ...input.callerThreadId !== void 0 ? { callerThreadId: input.callerThreadId } : {},
41695
+ ...input.callerAssistantId !== void 0 ? { callerAssistantId: input.callerAssistantId } : {},
40343
41696
  parent,
40344
41697
  completedDependencies
40345
41698
  }
40346
41699
  };
40347
41700
  }
40348
41701
 
40349
- // src/util/toJsonSafeValue.ts
40350
- var CIRCULAR_VALUE = "[Circular]";
40351
- var REPEATED_VALUE = "[Repeated]";
40352
- var arrayFrom = Array.from.bind(Array);
40353
- var arrayIsArray = Array.isArray.bind(Array);
40354
- var hasOwnProperty = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
40355
- var isPrototypeOf = Object.prototype.isPrototypeOf.call.bind(Object.prototype.isPrototypeOf);
40356
- var objectCreate = Object.create.bind(Object);
40357
- var objectDefineProperty = Object.defineProperty.bind(Object);
40358
- var objectIs = Object.is.bind(Object);
40359
- var reflectGet = Reflect.get.bind(Reflect);
40360
- var reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor.bind(Reflect);
40361
- var reflectOwnKeys = Reflect.ownKeys.bind(Reflect);
40362
- var stringifyJson = JSON.stringify.bind(JSON);
40363
- var numberIsFinite = Number.isFinite.bind(Number);
40364
- var numberIsNaN = Number.isNaN.bind(Number);
40365
- var numberIsSafeInteger = Number.isSafeInteger.bind(Number);
40366
- var mathMax = Math.max.bind(Math);
40367
- var dateConstructor = Date;
40368
- var datePrototype = dateConstructor.prototype;
40369
- var dateGetTime = datePrototype.getTime.call.bind(datePrototype.getTime);
40370
- var dateToISOString = datePrototype.toISOString.call.bind(datePrototype.toISOString);
40371
- var bigintToString = BigInt.prototype.toString.call.bind(BigInt.prototype.toString);
40372
- var stringSlice = String.prototype.slice.call.bind(String.prototype.slice);
40373
- var weakMapGet = WeakMap.prototype.get.call.bind(WeakMap.prototype.get);
40374
- var weakMapSet = WeakMap.prototype.set.call.bind(WeakMap.prototype.set);
40375
- var WeakMapConstructor = WeakMap;
40376
- var utf8Encoder = new TextEncoder();
40377
- var encodeUtf8 = TextEncoder.prototype.encode.bind(utf8Encoder);
40378
- var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
40379
- var typedArrayByteLengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")?.get;
40380
- if (!typedArrayByteLengthGetter) throw new Error("TypedArray byteLength getter is unavailable");
40381
- var typedArrayByteLength = typedArrayByteLengthGetter.call.bind(typedArrayByteLengthGetter);
40382
- var JSON_SAFE_MAX_DEPTH = 32;
40383
- var JSON_SAFE_MAX_NODES = 1e4;
40384
- var JSON_SAFE_MAX_COLLECTION_ENTRIES = 1e4;
40385
- var JSON_SAFE_MAX_STRING_LENGTH = 64 * 1024;
40386
- var JSON_SAFE_MAX_PROPERTY_KEY_LENGTH = JSON_SAFE_MAX_STRING_LENGTH;
40387
- var JSON_SAFE_MAX_PROPERTY_KEY_BYTES = 256 * 1024;
40388
- var JSON_SAFE_MAX_SERIALIZED_BYTES = 256 * 1024;
40389
- var JsonSafeValueError = class extends Error {
40390
- /**
40391
- * Create a bounded normalization error.
40392
- *
40393
- * @param code Stable normalization failure code.
40394
- * @param message Human-readable bounded failure description.
40395
- */
40396
- constructor(code, message) {
40397
- super(message);
40398
- objectDefineProperty(this, "name", {
40399
- value: "JsonSafeValueError",
40400
- writable: true,
40401
- configurable: true
40402
- });
40403
- objectDefineProperty(this, "code", {
40404
- value: code,
40405
- writable: true,
40406
- configurable: true
40407
- });
40408
- }
40409
- };
40410
- function fail(code, message) {
40411
- throw new JsonSafeValueError(code, message);
40412
- }
40413
- function propertyAccess(operation, path8) {
41702
+ // src/services/TaskExecutionService.ts
41703
+ var import_langgraph14 = require("@langchain/langgraph");
41704
+ var TASK_RUN_LEASE_TTL_MS = 12e4;
41705
+ function getLeaseStore() {
40414
41706
  try {
40415
- return operation();
41707
+ return storeLatticeManager.getStoreLattice("default", "lease").store;
40416
41708
  } catch {
40417
- fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe value at ${path8}`);
40418
- }
40419
- }
40420
- function serializedStringBytes(value) {
40421
- if (value.length > JSON_SAFE_MAX_STRING_LENGTH) {
40422
- fail("MAX_STRING_LENGTH", `JSON-safe string exceeds ${JSON_SAFE_MAX_STRING_LENGTH} characters`);
40423
- }
40424
- return typedArrayByteLength(encodeUtf8(stringifyJson(value)));
40425
- }
40426
- function validatePropertyKey(key5) {
40427
- if (key5.length > JSON_SAFE_MAX_PROPERTY_KEY_LENGTH) {
40428
- fail(
40429
- "MAX_STRING_LENGTH",
40430
- `JSON-safe property key exceeds ${JSON_SAFE_MAX_PROPERTY_KEY_LENGTH} characters`
40431
- );
40432
- }
40433
- }
40434
- function chargePropertyKey(state, key5) {
40435
- state.propertyKeyBytes += typedArrayByteLength(encodeUtf8(key5));
40436
- if (state.propertyKeyBytes > JSON_SAFE_MAX_PROPERTY_KEY_BYTES) {
40437
- fail(
40438
- "MAX_PROPERTY_KEY_BYTES",
40439
- `JSON-safe property keys exceed ${JSON_SAFE_MAX_PROPERTY_KEY_BYTES} traversed UTF-8 bytes`
40440
- );
40441
- }
40442
- }
40443
- function chargeBytes(state, bytes) {
40444
- state.serializedBytes += bytes;
40445
- if (state.serializedBytes > JSON_SAFE_MAX_SERIALIZED_BYTES) {
40446
- fail(
40447
- "MAX_SERIALIZED_BYTES",
40448
- `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
40449
- );
40450
- }
40451
- }
40452
- function chargeString(state, value) {
40453
- chargeBytes(state, serializedStringBytes(value));
40454
- }
40455
- function objectPropertyPath(path8, key5) {
40456
- const boundedKey = key5.length > 128 ? `${stringSlice(key5, 0, 128)}...` : key5;
40457
- return `${path8}[${stringifyJson(boundedKey)}]`;
40458
- }
40459
- function convertJsonValue(value, state, depth, inArray, path8) {
40460
- state.nodes += 1;
40461
- if (state.nodes > JSON_SAFE_MAX_NODES) {
40462
- fail("MAX_NODES", `JSON-safe value exceeds ${JSON_SAFE_MAX_NODES} total nodes`);
40463
- }
40464
- if (typeof value === "string") {
40465
- chargeString(state, value);
40466
- return value;
40467
- }
40468
- if (value === null) {
40469
- chargeBytes(state, 4);
40470
- return value;
40471
- }
40472
- if (typeof value === "boolean") {
40473
- chargeBytes(state, value ? 4 : 5);
40474
- return value;
40475
- }
40476
- if (typeof value === "number") {
40477
- const normalized = numberIsFinite(value) ? objectIs(value, -0) ? 0 : value : null;
40478
- chargeBytes(state, normalized === null ? 4 : stringifyJson(normalized).length);
40479
- return normalized;
40480
- }
40481
- if (typeof value === "bigint") {
40482
- const normalized = bigintToString(value);
40483
- chargeString(state, normalized);
40484
- return normalized;
40485
- }
40486
- if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
40487
- if (inArray) chargeBytes(state, 4);
40488
- return inArray ? null : void 0;
40489
- }
40490
- const isDate = propertyAccess(() => isPrototypeOf(datePrototype, value), path8);
40491
- if (isDate) {
40492
- const time = propertyAccess(() => dateGetTime(value), path8);
40493
- if (numberIsNaN(time)) {
40494
- chargeBytes(state, 4);
40495
- return null;
40496
- }
40497
- const normalized = propertyAccess(() => dateToISOString(value), path8);
40498
- chargeString(state, normalized);
40499
- return normalized;
40500
- }
40501
- if (depth > JSON_SAFE_MAX_DEPTH) {
40502
- fail("MAX_DEPTH", `JSON-safe value exceeds maximum depth ${JSON_SAFE_MAX_DEPTH}`);
40503
- }
40504
- const referenceState = weakMapGet(state.references, value);
40505
- if (referenceState === "visiting") {
40506
- chargeString(state, CIRCULAR_VALUE);
40507
- return CIRCULAR_VALUE;
40508
- }
40509
- if (referenceState === "visited") {
40510
- chargeString(state, REPEATED_VALUE);
40511
- return REPEATED_VALUE;
40512
- }
40513
- weakMapSet(state.references, value, "visiting");
40514
- if (propertyAccess(() => arrayIsArray(value), path8)) {
40515
- const arrayValue = value;
40516
- const length = propertyAccess(
40517
- () => arrayValue.length,
40518
- path8
40519
- );
40520
- if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 0) {
40521
- fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe array length at ${path8}`);
40522
- }
40523
- if (length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
40524
- fail(
40525
- "COLLECTION_TOO_LARGE",
40526
- `JSON-safe array exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} entries`
40527
- );
40528
- }
40529
- chargeBytes(state, 2 + mathMax(0, length - 1));
40530
- const result2 = arrayFrom({ length }, (_, index) => {
40531
- const entryPath = `${path8}[${index}]`;
40532
- const hasEntry = propertyAccess(
40533
- () => hasOwnProperty(arrayValue, index),
40534
- entryPath
40535
- );
40536
- if (!hasEntry) {
40537
- chargeBytes(state, 4);
40538
- return null;
40539
- }
40540
- const entry = propertyAccess(() => arrayValue[index], entryPath);
40541
- return convertJsonValue(entry, state, depth + 1, true, `${path8}[${index}]`);
40542
- });
40543
- objectDefineProperty(result2, "toJSON", {
40544
- value: void 0,
40545
- configurable: true,
40546
- writable: true
40547
- });
40548
- weakMapSet(state.references, value, "visited");
40549
- return result2;
40550
- }
40551
- const keys = propertyAccess(() => reflectOwnKeys(value), path8);
40552
- if (keys.length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
40553
- fail(
40554
- "COLLECTION_TOO_LARGE",
40555
- `JSON-safe object exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} own keys`
40556
- );
40557
- }
40558
- for (let index = 0; index < keys.length; index += 1) {
40559
- const key5 = keys[index];
40560
- if (typeof key5 !== "string") continue;
40561
- validatePropertyKey(key5);
40562
- chargePropertyKey(state, key5);
40563
- }
40564
- chargeBytes(state, 2);
40565
- const result = objectCreate(null);
40566
- let emittedProperties = 0;
40567
- for (let index = 0; index < keys.length; index += 1) {
40568
- const key5 = keys[index];
40569
- const entryPath = typeof key5 === "string" ? objectPropertyPath(path8, key5) : path8;
40570
- const descriptor = propertyAccess(
40571
- () => reflectGetOwnPropertyDescriptor(value, key5),
40572
- entryPath
40573
- );
40574
- if (typeof key5 !== "string" || !descriptor?.enumerable) continue;
40575
- const entry = propertyAccess(() => reflectGet(value, key5), entryPath);
40576
- const converted = convertJsonValue(entry, state, depth + 1, false, entryPath);
40577
- if (converted !== void 0) {
40578
- chargeBytes(state, serializedStringBytes(key5) + 1 + (emittedProperties === 0 ? 0 : 1));
40579
- propertyAccess(() => objectDefineProperty(result, key5, {
40580
- value: converted,
40581
- enumerable: true,
40582
- configurable: true,
40583
- writable: true
40584
- }), entryPath);
40585
- emittedProperties += 1;
40586
- }
40587
- }
40588
- weakMapSet(state.references, value, "visited");
40589
- return result;
40590
- }
40591
- function toJsonSafeValue(value) {
40592
- const state = {
40593
- nodes: 0,
40594
- propertyKeyBytes: 0,
40595
- serializedBytes: 0,
40596
- references: new WeakMapConstructor()
40597
- };
40598
- const converted = convertJsonValue(value, state, 0, false, "$");
40599
- if (converted === void 0) chargeBytes(state, 4);
40600
- const result = converted ?? null;
40601
- const serialized = propertyAccess(() => stringifyJson(result), "$");
40602
- if (typedArrayByteLength(encodeUtf8(serialized)) > JSON_SAFE_MAX_SERIALIZED_BYTES) {
40603
- fail(
40604
- "MAX_SERIALIZED_BYTES",
40605
- `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
40606
- );
41709
+ return void 0;
40607
41710
  }
40608
- return result;
40609
41711
  }
40610
-
40611
- // src/services/TaskExecutionService.ts
40612
- var import_langgraph14 = require("@langchain/langgraph");
40613
41712
  function persistedExecutionObservation(item, attempted) {
40614
41713
  const detail = item.detail;
40615
41714
  const persistedObservation = toJsonSafeValue(detail?.observation);
@@ -40656,10 +41755,26 @@ function createTaskExecutionService(deps) {
40656
41755
  const run = async (plan) => {
40657
41756
  const { tenantId: tenantId2, agentId, actor, parent, completedDependencies } = plan;
40658
41757
  let task = plan.task;
40659
- const persistedThreadId = (task.status === "interrupted" || task.status === "failed") && typeof task.context?.thread_id === "string" && task.context.thread_id.trim() !== "" ? task.context.thread_id : void 0;
41758
+ const storedThreadId = (task.status === "interrupted" || task.status === "failed") && typeof task.context?.thread_id === "string" && task.context.thread_id.trim() !== "" ? task.context.thread_id : void 0;
41759
+ const storedRunId = typeof task.context?.run_id === "string" && task.context.run_id.trim() !== "" ? task.context.run_id : void 0;
41760
+ let reuseCurrentRun = false;
41761
+ if (task.status === "interrupted" && storedThreadId) {
41762
+ const currentKey = storedRunId ? `execution-result:${storedThreadId}:${storedRunId}` : `execution-result:${storedThreadId}`;
41763
+ try {
41764
+ reuseCurrentRun = await deps.workItemStore.findByEventKey(tenantId2, task.id, currentKey) === null;
41765
+ } catch {
41766
+ reuseCurrentRun = false;
41767
+ }
41768
+ }
40660
41769
  let threadId;
41770
+ let runId;
40661
41771
  try {
40662
- threadId = persistedThreadId ?? (deps.createThreadId ?? import_node_crypto9.randomUUID)();
41772
+ threadId = storedThreadId ?? (deps.createThreadId ?? import_node_crypto12.randomUUID)();
41773
+ if (task.status === "interrupted" && reuseCurrentRun) {
41774
+ runId = storedRunId;
41775
+ } else if (task.status === "interrupted" || task.status === "failed") {
41776
+ runId = (deps.createRunId ?? import_node_crypto12.randomUUID)();
41777
+ }
40663
41778
  } catch (error) {
40664
41779
  return {
40665
41780
  success: false,
@@ -40669,7 +41784,7 @@ function createTaskExecutionService(deps) {
40669
41784
  agentId
40670
41785
  };
40671
41786
  }
40672
- const eventKey = `execution-result:${threadId}`;
41787
+ const eventKey = runId ? `execution-result:${threadId}:${runId}` : `execution-result:${threadId}`;
40673
41788
  if (!(0, import_protocols32.isExecutionResultEventKey)(eventKey)) {
40674
41789
  return {
40675
41790
  success: false,
@@ -40703,7 +41818,10 @@ function createTaskExecutionService(deps) {
40703
41818
  tenantId: tenantId2,
40704
41819
  task,
40705
41820
  actor,
40706
- threadId
41821
+ threadId,
41822
+ ...runId ? { runId } : {},
41823
+ ...plan.callerThreadId ? { callerThreadId: plan.callerThreadId } : {},
41824
+ ...plan.callerAssistantId ? { callerAssistantId: plan.callerAssistantId } : {}
40707
41825
  });
40708
41826
  if (!begun.success) return { ...begun, taskId: task.id };
40709
41827
  if (!begun.mutated || !begun.transitioned) {
@@ -40717,38 +41835,134 @@ function createTaskExecutionService(deps) {
40717
41835
  task = begun.task;
40718
41836
  warnings.push(...begun.warnings);
40719
41837
  }
40720
- const invocation = {
40721
- tenantId: tenantId2,
40722
- workspaceId: task.workspaceId,
40723
- projectId: task.projectId,
40724
- taskId: task.id,
40725
- agentId,
40726
- threadId,
40727
- message: buildWorkerMessage(task, parent, completedDependencies),
40728
- delegatedTaskId: task.id,
40729
- taskExecutionRole: "worker"
40730
- };
40731
- let observation;
41838
+ taskRunRegistry.register(task.id);
41839
+ let taskRunLease = null;
40732
41840
  try {
40733
- observation = toJsonSafeValue(await deps.invokeAgent(invocation));
40734
- } catch (error) {
40735
- if (error instanceof import_langgraph14.GraphInterrupt) {
41841
+ const leaseStore = getLeaseStore();
41842
+ if (leaseStore) {
41843
+ try {
41844
+ taskRunLease = await tryAcquireTaskRun({
41845
+ store: leaseStore,
41846
+ taskId: task.id,
41847
+ owner: getReplicaId(),
41848
+ ttlMs: TASK_RUN_LEASE_TTL_MS
41849
+ });
41850
+ } catch {
41851
+ taskRunLease = null;
41852
+ }
41853
+ }
41854
+ const invocation = {
41855
+ tenantId: tenantId2,
41856
+ workspaceId: task.workspaceId,
41857
+ projectId: task.projectId,
41858
+ taskId: task.id,
41859
+ agentId,
41860
+ threadId,
41861
+ message: buildWorkerMessage(task, parent, completedDependencies),
41862
+ delegatedTaskId: task.id,
41863
+ taskExecutionRole: "worker"
41864
+ };
41865
+ let observation;
41866
+ try {
41867
+ observation = toJsonSafeValue(await deps.invokeAgent(invocation));
41868
+ } catch (error) {
41869
+ if (error instanceof import_langgraph14.GraphInterrupt) {
41870
+ try {
41871
+ await bridge.settleRun({
41872
+ tenantId: tenantId2,
41873
+ task,
41874
+ actor,
41875
+ threadId,
41876
+ outcome: { kind: "interrupted", summary: "Awaiting user input" }
41877
+ });
41878
+ } catch {
41879
+ }
41880
+ throw error;
41881
+ }
41882
+ const normalizationError = error instanceof JsonSafeValueError;
41883
+ const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
41884
+ const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
40736
41885
  try {
40737
- await bridge.settleRun({
41886
+ const settled = await bridge.settleRun({
40738
41887
  tenantId: tenantId2,
40739
41888
  task,
40740
41889
  actor,
40741
41890
  threadId,
40742
- outcome: { kind: "interrupted", summary: "Awaiting user input" }
41891
+ outcome: {
41892
+ kind: "failed",
41893
+ lifecycleHandled: false,
41894
+ error: message.trim() || "Agent invocation failed"
41895
+ }
40743
41896
  });
41897
+ if (!settled.success) {
41898
+ warnings.push({ code: "TASK_FAILED_SETTLE_FAILED", taskId: task.id });
41899
+ }
40744
41900
  } catch {
41901
+ warnings.push({ code: "TASK_FAILED_SETTLE_FAILED", taskId: task.id });
41902
+ }
41903
+ const failedObservation = toJsonSafeValue(normalizationError ? { code: failureCode, error: message } : { error: message });
41904
+ try {
41905
+ const persisted = await deps.workItemStore.createIfAbsentByEventKey({
41906
+ taskId: task.id,
41907
+ tenantId: tenantId2,
41908
+ workspaceId: task.workspaceId,
41909
+ projectId: task.projectId,
41910
+ action: "execution_result",
41911
+ actor,
41912
+ threadId,
41913
+ summary: normalizationError ? `Agent ${agentId} returned an invalid execution observation` : `Agent ${agentId} invocation failed`,
41914
+ detail: {
41915
+ agentId,
41916
+ threadId,
41917
+ observation: failedObservation,
41918
+ success: false
41919
+ },
41920
+ eventKey
41921
+ });
41922
+ const validated = persistedExecutionObservation(persisted, {
41923
+ tenantId: tenantId2,
41924
+ taskId: task.id,
41925
+ agentId,
41926
+ threadId,
41927
+ eventKey,
41928
+ success: false,
41929
+ observation: failedObservation
41930
+ });
41931
+ if (!validated.matches) {
41932
+ return {
41933
+ success: false,
41934
+ code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
41935
+ error: "The execution result identity is already bound to a different execution payload",
41936
+ ...!normalizationError ? { invocationError: message } : {},
41937
+ taskId: task.id,
41938
+ agentId,
41939
+ threadId,
41940
+ ...warnings.length > 0 ? { warnings } : {}
41941
+ };
41942
+ }
41943
+ return {
41944
+ success: false,
41945
+ code: failureCode,
41946
+ error: typeof validated.observation?.error === "string" ? validated.observation.error : message,
41947
+ taskId: task.id,
41948
+ agentId,
41949
+ threadId,
41950
+ executionResultId: eventKey,
41951
+ ...warnings.length > 0 ? { warnings } : {}
41952
+ };
41953
+ } catch (persistenceError) {
41954
+ return {
41955
+ success: false,
41956
+ code: "EXECUTION_RESULT_WRITE_FAILED",
41957
+ error: errorMessage(persistenceError),
41958
+ ...!normalizationError ? { invocationError: message } : {},
41959
+ taskId: task.id,
41960
+ agentId,
41961
+ threadId,
41962
+ ...warnings.length > 0 ? { warnings } : {}
41963
+ };
40745
41964
  }
40746
- throw error;
40747
41965
  }
40748
- const normalizationError = error instanceof JsonSafeValueError;
40749
- const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
40750
- const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
40751
- const failedObservation = toJsonSafeValue(normalizationError ? { code: failureCode, error: message } : { error: message });
40752
41966
  try {
40753
41967
  const persisted = await deps.workItemStore.createIfAbsentByEventKey({
40754
41968
  taskId: task.id,
@@ -40758,13 +41972,8 @@ function createTaskExecutionService(deps) {
40758
41972
  action: "execution_result",
40759
41973
  actor,
40760
41974
  threadId,
40761
- summary: normalizationError ? `Agent ${agentId} returned an invalid execution observation` : `Agent ${agentId} invocation failed`,
40762
- detail: {
40763
- agentId,
40764
- threadId,
40765
- observation: failedObservation,
40766
- success: false
40767
- },
41975
+ summary: `Agent ${agentId} returned an execution observation`,
41976
+ detail: { agentId, threadId, observation, success: true },
40768
41977
  eventKey
40769
41978
  });
40770
41979
  const validated = persistedExecutionObservation(persisted, {
@@ -40773,15 +41982,14 @@ function createTaskExecutionService(deps) {
40773
41982
  agentId,
40774
41983
  threadId,
40775
41984
  eventKey,
40776
- success: false,
40777
- observation: failedObservation
41985
+ success: true,
41986
+ observation
40778
41987
  });
40779
41988
  if (!validated.matches) {
40780
41989
  return {
40781
41990
  success: false,
40782
41991
  code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
40783
41992
  error: "The execution result identity is already bound to a different execution payload",
40784
- ...!normalizationError ? { invocationError: message } : {},
40785
41993
  taskId: task.id,
40786
41994
  agentId,
40787
41995
  threadId,
@@ -40789,80 +41997,28 @@ function createTaskExecutionService(deps) {
40789
41997
  };
40790
41998
  }
40791
41999
  return {
40792
- success: false,
40793
- code: failureCode,
40794
- error: typeof validated.observation?.error === "string" ? validated.observation.error : message,
42000
+ success: true,
40795
42001
  taskId: task.id,
40796
42002
  agentId,
40797
42003
  threadId,
42004
+ observation: validated.observation,
40798
42005
  executionResultId: eventKey,
40799
42006
  ...warnings.length > 0 ? { warnings } : {}
40800
42007
  };
40801
- } catch (persistenceError) {
42008
+ } catch (error) {
40802
42009
  return {
40803
42010
  success: false,
40804
42011
  code: "EXECUTION_RESULT_WRITE_FAILED",
40805
- error: errorMessage(persistenceError),
40806
- ...!normalizationError ? { invocationError: message } : {},
40807
- taskId: task.id,
40808
- agentId,
40809
- threadId,
40810
- ...warnings.length > 0 ? { warnings } : {}
40811
- };
40812
- }
40813
- }
40814
- try {
40815
- const persisted = await deps.workItemStore.createIfAbsentByEventKey({
40816
- taskId: task.id,
40817
- tenantId: tenantId2,
40818
- workspaceId: task.workspaceId,
40819
- projectId: task.projectId,
40820
- action: "execution_result",
40821
- actor,
40822
- threadId,
40823
- summary: `Agent ${agentId} returned an execution observation`,
40824
- detail: { agentId, threadId, observation, success: true },
40825
- eventKey
40826
- });
40827
- const validated = persistedExecutionObservation(persisted, {
40828
- tenantId: tenantId2,
40829
- taskId: task.id,
40830
- agentId,
40831
- threadId,
40832
- eventKey,
40833
- success: true,
40834
- observation
40835
- });
40836
- if (!validated.matches) {
40837
- return {
40838
- success: false,
40839
- code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
40840
- error: "The execution result identity is already bound to a different execution payload",
42012
+ error: errorMessage(error),
40841
42013
  taskId: task.id,
40842
42014
  agentId,
40843
42015
  threadId,
40844
42016
  ...warnings.length > 0 ? { warnings } : {}
40845
42017
  };
40846
42018
  }
40847
- return {
40848
- success: true,
40849
- taskId: task.id,
40850
- agentId,
40851
- threadId,
40852
- observation: validated.observation,
40853
- executionResultId: eventKey,
40854
- ...warnings.length > 0 ? { warnings } : {}
40855
- };
40856
- } catch (error) {
40857
- return {
40858
- success: false,
40859
- code: "EXECUTION_RESULT_WRITE_FAILED",
40860
- error: errorMessage(error),
40861
- taskId: task.id,
40862
- agentId,
40863
- threadId,
40864
- ...warnings.length > 0 ? { warnings } : {}
40865
- };
42019
+ } finally {
42020
+ taskRunRegistry.unregister(task.id);
42021
+ if (taskRunLease) await taskRunLease.release();
40866
42022
  }
40867
42023
  };
40868
42024
  return {
@@ -40875,74 +42031,41 @@ function createTaskExecutionService(deps) {
40875
42031
  };
40876
42032
  }
40877
42033
 
40878
- // src/services/TaskRunRegistry.ts
40879
- var TaskRunRegistry = class {
40880
- constructor() {
40881
- this.live = /* @__PURE__ */ new Set();
40882
- }
40883
- /** Marks a task as currently held by a live run. */
40884
- register(taskId) {
40885
- this.live.add(taskId);
40886
- }
40887
- /** Removes a task once its run has ended. */
40888
- unregister(taskId) {
40889
- this.live.delete(taskId);
40890
- }
40891
- /** Reports whether a task is currently held by a live run. */
40892
- isLive(taskId) {
40893
- return this.live.has(taskId);
40894
- }
40895
- /** Returns a snapshot of the live task ids (diagnostics/tests). */
40896
- snapshot() {
40897
- return [...this.live];
40898
- }
40899
- /** Clears all live entries (tests / process teardown). */
40900
- clear() {
40901
- this.live.clear();
40902
- }
40903
- };
40904
- var taskRunRegistry = new TaskRunRegistry();
40905
- async function reconcileStaleTaskRuns(input) {
40906
- const registry4 = input.registry ?? taskRunRegistry;
40907
- const converged = [];
40908
- for (const task of input.tasks) {
40909
- if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
40910
- const result = await input.lifecycle.interruptTask({
40911
- tenantId: task.tenantId,
40912
- taskId: task.id,
40913
- actor: input.actor,
40914
- type: "missing_input",
40915
- summary: "Run is no longer executing this task (no_executor)"
40916
- });
40917
- if (result.success) converged.push(task.id);
42034
+ // src/services/leadership.ts
42035
+ var import_node_crypto13 = require("crypto");
42036
+ async function runAsLeader(store, name, fn, options = {}) {
42037
+ const key5 = `leader:${name}`;
42038
+ const owner2 = options.owner ?? getReplicaId();
42039
+ const holder = `${owner2}#${(0, import_node_crypto13.randomUUID)()}`;
42040
+ const ttlMs = options.ttlMs ?? 6e4;
42041
+ if (!await store.tryAcquire(key5, holder, ttlMs)) return { ran: false };
42042
+ const heartbeat = setInterval(() => {
42043
+ void store.renew(key5, holder, ttlMs).catch(() => void 0);
42044
+ }, Math.max(1e3, Math.floor(ttlMs / 3)));
42045
+ heartbeat.unref?.();
42046
+ try {
42047
+ const result = await fn();
42048
+ return { ran: true, result };
42049
+ } finally {
42050
+ clearInterval(heartbeat);
42051
+ if (!options.hold) await store.release(key5, holder).catch(() => void 0);
40918
42052
  }
40919
- return { converged };
40920
42053
  }
40921
- async function reconcileTenantTaskRuns(input) {
40922
- const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
40923
- const candidates = input.include ? tasks.filter(input.include) : tasks;
40924
- return reconcileStaleTaskRuns({
40925
- tasks: candidates,
40926
- actor: input.actor,
40927
- lifecycle: input.lifecycle,
40928
- ...input.registry ? { registry: input.registry } : {}
40929
- });
42054
+
42055
+ // src/services/pluginCatalogSync.ts
42056
+ var PLUGIN_CATALOG_CHANGED_TOPIC = "plugin-catalog-changed";
42057
+ var outbox;
42058
+ var owner = "unknown";
42059
+ function configurePluginCatalogSync(next) {
42060
+ outbox = next?.outbox;
42061
+ owner = next?.owner ?? "unknown";
40930
42062
  }
40931
- async function reconcileAllTenantTaskRuns(input) {
40932
- const tenants = await input.tenantStore.listTenants();
40933
- const converged = [];
40934
- for (const tenant of tenants) {
40935
- const result = await reconcileTenantTaskRuns({
40936
- tenantId: tenant.id,
40937
- actor: input.actor,
40938
- taskStore: input.taskStore,
40939
- lifecycle: input.lifecycle,
40940
- ...input.registry ? { registry: input.registry } : {},
40941
- ...input.include ? { include: input.include } : {}
40942
- });
40943
- converged.push(...result.converged);
42063
+ async function publishPluginCatalogChanged(tenantId2) {
42064
+ if (!outbox || !tenantId2) return;
42065
+ try {
42066
+ await outbox.append({ topic: PLUGIN_CATALOG_CHANGED_TOPIC, payload: { tenantId: tenantId2 }, originReplicaId: owner });
42067
+ } catch {
40944
42068
  }
40945
- return { converged };
40946
42069
  }
40947
42070
 
40948
42071
  // src/index.ts
@@ -41087,9 +42210,9 @@ var createLoadSkillsTool = ({ skills, readAll, pluginSkills, pluginSkillOwners }
41087
42210
  if (!skillName) continue;
41088
42211
  if (await isPluginSkillManagedInSandbox(sandbox, skillName)) {
41089
42212
  const enabledDefinition = pluginSkills?.[skillName];
41090
- const owner = pluginSkillOwners?.[skillName];
41091
- const registered = owner && enabledDefinition ? PluginRegistry.getSkillForPlugin(owner, skillName) : void 0;
41092
- if (!registered || registered.definition !== enabledDefinition || !owner || !await isPluginSkillAuthorizedInSandbox(sandbox, skillName, owner) || await getPluginSkillManifestVersion(sandbox, skillName) !== enabledDefinition.version) {
42213
+ const owner2 = pluginSkillOwners?.[skillName];
42214
+ const registered = owner2 && enabledDefinition ? PluginRegistry.getSkillForPlugin(owner2, skillName) : void 0;
42215
+ if (!registered || registered.definition !== enabledDefinition || !owner2 || !await isPluginSkillAuthorizedInSandbox(sandbox, skillName, owner2) || await getPluginSkillManifestVersion(sandbox, skillName) !== enabledDefinition.version) {
41093
42216
  continue;
41094
42217
  }
41095
42218
  }
@@ -41115,8 +42238,8 @@ var createLoadSkillsTool = ({ skills, readAll, pluginSkills, pluginSkillOwners }
41115
42238
  const seenNames = new Set(filteredSkills.map((skill) => skill.name));
41116
42239
  try {
41117
42240
  for (const [name, definition] of Object.entries(pluginSkills ?? {})) {
41118
- const owner = pluginSkillOwners?.[name];
41119
- const registered = owner ? PluginRegistry.getSkillForPlugin(owner, name) : void 0;
42241
+ const owner2 = pluginSkillOwners?.[name];
42242
+ const registered = owner2 ? PluginRegistry.getSkillForPlugin(owner2, name) : void 0;
41120
42243
  if (!registered || registered.definition !== definition) continue;
41121
42244
  const { meta } = parseSkillFrontmatter(definition.content);
41122
42245
  if (!meta.name || !meta.description || seenNames.has(meta.name)) continue;
@@ -41153,24 +42276,24 @@ var import_zod52 = __toESM(require("zod"));
41153
42276
  var import_langchain63 = require("langchain");
41154
42277
 
41155
42278
  // src/sandbox_plugin/pluginSkillResolution.ts
41156
- async function resolveTenantPluginSkill(tenantId2, owner, skillName) {
42279
+ async function resolveTenantPluginSkill(tenantId2, owner2, skillName) {
41157
42280
  try {
41158
42281
  const { plugins } = await getSandboxPluginCatalog().ensureLoaded(tenantId2);
41159
- const plugin = plugins.find((candidate) => candidate.meta.type === owner);
42282
+ const plugin = plugins.find((candidate) => candidate.meta.type === owner2);
41160
42283
  return plugin?.skills?.[skillName];
41161
42284
  } catch {
41162
42285
  return void 0;
41163
42286
  }
41164
42287
  }
41165
- async function resolveEnabledPluginSkill(owner, skillName, enabledDefinition, tenantId2) {
41166
- if (!owner || !enabledDefinition) return void 0;
41167
- const registered = PluginRegistry.getSkillForPlugin(owner, skillName);
41168
- if (registered && registered.pluginType === owner && registered.definition === enabledDefinition) {
41169
- return { pluginType: owner, definition: enabledDefinition };
42288
+ async function resolveEnabledPluginSkill(owner2, skillName, enabledDefinition, tenantId2) {
42289
+ if (!owner2 || !enabledDefinition) return void 0;
42290
+ const registered = PluginRegistry.getSkillForPlugin(owner2, skillName);
42291
+ if (registered && registered.pluginType === owner2 && registered.definition === enabledDefinition) {
42292
+ return { pluginType: owner2, definition: enabledDefinition };
41170
42293
  }
41171
42294
  if (!tenantId2) return void 0;
41172
- const tenantDefinition = await resolveTenantPluginSkill(tenantId2, owner, skillName);
41173
- return tenantDefinition ? { pluginType: owner, definition: tenantDefinition } : void 0;
42295
+ const tenantDefinition = await resolveTenantPluginSkill(tenantId2, owner2, skillName);
42296
+ return tenantDefinition ? { pluginType: owner2, definition: tenantDefinition } : void 0;
41174
42297
  }
41175
42298
 
41176
42299
  // src/tool_lattice/skill/load_skill_content.ts
@@ -41232,10 +42355,10 @@ var createLoadSkillContentTool = (pluginSkills, pluginSkillOwnersOrStaticSelecti
41232
42355
  return result2;
41233
42356
  }
41234
42357
  const enabledDefinition = pluginSkills?.[input.skill_name];
41235
- const owner = pluginSkillOwners?.[input.skill_name];
42358
+ const owner2 = pluginSkillOwners?.[input.skill_name];
41236
42359
  const runConfig = _exe_config?.configurable?.runConfig || {};
41237
42360
  const pluginSkill = await resolveEnabledPluginSkill(
41238
- owner,
42361
+ owner2,
41239
42362
  input.skill_name,
41240
42363
  enabledDefinition,
41241
42364
  runConfig.tenantId
@@ -41342,9 +42465,9 @@ var createLoadSkillResourceTool = (pluginSkills, pluginSkillOwners) => {
41342
42465
  validateRelativePath(input.resource_path, "resource");
41343
42466
  const sandbox = await getSandboxFromExeConfig3(_exe_config);
41344
42467
  const definition = pluginSkills?.[input.skill_name];
41345
- const owner = pluginSkillOwners?.[input.skill_name];
42468
+ const owner2 = pluginSkillOwners?.[input.skill_name];
41346
42469
  const tenantId2 = _exe_config?.configurable?.runConfig?.tenantId;
41347
- const resolved = await resolveEnabledPluginSkill(owner, input.skill_name, definition, tenantId2);
42470
+ const resolved = await resolveEnabledPluginSkill(owner2, input.skill_name, definition, tenantId2);
41348
42471
  if (definition) {
41349
42472
  if (!resolved || !resolved.definition.resources?.[input.resource_path]) {
41350
42473
  return `Resource "${input.resource_path}" not found for skill "${input.skill_name}".`;
@@ -43144,65 +44267,32 @@ var widgetPlugin = {
43144
44267
  var import_langchain83 = require("langchain");
43145
44268
  var import_zod68 = require("zod");
43146
44269
  var import_langgraph16 = require("@langchain/langgraph");
44270
+ var import_protocols34 = require("@axiom-lattice/protocols");
43147
44271
 
43148
- // src/util/truncateForJson.ts
43149
- var TRUNCATION_MARKER = "...[truncated]";
43150
- function truncateString(value, cap) {
43151
- if (value.length <= cap) return value;
43152
- const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
43153
- return value.slice(0, budget) + TRUNCATION_MARKER;
44272
+ // src/services/taskWorkerRunConfig.ts
44273
+ var import_protocols33 = require("@axiom-lattice/protocols");
44274
+ function resolveWorkerRunScope(input) {
44275
+ const caller = (0, import_protocols33.resolveRunScope)(input.runConfig);
44276
+ return {
44277
+ workspaceId: (0, import_protocols33.firstNonEmptyString)(input.invocation.workspaceId) ?? caller.workspaceId,
44278
+ projectId: (0, import_protocols33.firstNonEmptyString)(input.invocation.projectId) ?? caller.projectId
44279
+ };
43154
44280
  }
43155
- function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
43156
- if (typeof value === "string") return truncateString(value, maxStringLength);
43157
- if (value === null || typeof value !== "object") return value;
43158
- if (depth >= maxDepth) return "[truncated:max-depth]";
43159
- if (seen.has(value)) return "[Circular]";
43160
- seen.add(value);
43161
- try {
43162
- if (value instanceof Date) return value.toISOString();
43163
- if (Array.isArray(value)) {
43164
- const limit2 = Math.min(value.length, maxEntries);
43165
- const output2 = [];
43166
- for (let index = 0; index < limit2; index += 1) {
43167
- output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
43168
- }
43169
- if (value.length > limit2) output2.push("[truncated:entries]");
43170
- return output2;
43171
- }
43172
- const record = value;
43173
- const output = {};
43174
- const keys = Object.keys(record);
43175
- const limit = Math.min(keys.length, maxEntries);
43176
- for (let index = 0; index < limit; index += 1) {
43177
- const key5 = keys[index];
43178
- output[truncateString(key5, maxStringLength)] = truncateValue(
43179
- record[key5],
43180
- depth + 1,
43181
- maxDepth,
43182
- maxEntries,
43183
- maxStringLength,
43184
- seen
43185
- );
43186
- }
43187
- if (keys.length > limit) output["[truncated]"] = true;
43188
- return output;
43189
- } finally {
43190
- seen.delete(value);
44281
+ function applyWorkerRunScope(runConfig, scope) {
44282
+ const next = { ...runConfig };
44283
+ if (scope.workspaceId !== void 0) {
44284
+ next.workspaceId = scope.workspaceId;
44285
+ next["x-workspace-id"] = scope.workspaceId;
43191
44286
  }
43192
- }
43193
- function truncateForJson(value, options = {}) {
43194
- return truncateValue(
43195
- value,
43196
- 0,
43197
- options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
43198
- options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
43199
- options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
43200
- /* @__PURE__ */ new WeakSet()
43201
- );
44287
+ if (scope.projectId !== void 0) {
44288
+ next.projectId = scope.projectId;
44289
+ next["x-project-id"] = scope.projectId;
44290
+ }
44291
+ return next;
43202
44292
  }
43203
44293
 
43204
44294
  // src/middlewares/taskMiddleware.ts
43205
- var import_protocols33 = require("@axiom-lattice/protocols");
44295
+ var import_protocols35 = require("@axiom-lattice/protocols");
43206
44296
 
43207
44297
  // src/middlewares/taskResponseSerialization.ts
43208
44298
  var TASK_RESPONSE_SCALAR_MAX_BYTES = 4096;
@@ -43604,9 +44694,9 @@ async function renderAvailableExecutors(rc, tenantId2) {
43604
44694
  const governed = authority.kind === "projectRoom" || authority.kind === "projectTask";
43605
44695
  const projectId = governed ? (authority.trusted.projectTask ?? authority.trusted.projectRoom)?.projectId : void 0;
43606
44696
  const cacheKey = `${tenantId2}:${governed ? `project:${projectId ?? ""}` : "ordinary"}`;
43607
- const cached = executorCache.get(cacheKey);
44697
+ const cached2 = executorCache.get(cacheKey);
43608
44698
  const now = Date.now();
43609
- if (cached && now - cached.at < EXECUTOR_CACHE_TTL_MS) return cached.text;
44699
+ if (cached2 && now - cached2.at < EXECUTOR_CACHE_TTL_MS) return cached2.text;
43610
44700
  const lines = [];
43611
44701
  try {
43612
44702
  if (governed && projectId) {
@@ -43670,7 +44760,7 @@ function classifyTaskAuthority(runConfig) {
43670
44760
  return delegatedTaskId ? { kind: "delegated", taskId: delegatedTaskId } : { kind: "ordinary" };
43671
44761
  }
43672
44762
  try {
43673
- const trusted = (0, import_protocols33.parseTrustedRunContext)(hasProjectTask ? { projectTask: runConfig.projectTask } : { projectRoom: runConfig.projectRoom });
44763
+ const trusted = (0, import_protocols35.parseTrustedRunContext)(hasProjectTask ? { projectTask: runConfig.projectTask } : { projectRoom: runConfig.projectRoom });
43674
44764
  return { kind: hasProjectTask ? "projectTask" : "projectRoom", trusted };
43675
44765
  } catch {
43676
44766
  return { kind: "invalid" };
@@ -44007,7 +45097,7 @@ function getTaskWorkItemStore() {
44007
45097
  return getStoreLattice("default", "taskWorkItem").store;
44008
45098
  }
44009
45099
  function getProjectTaskWorkItemStore() {
44010
- return (0, import_protocols33.requireProjectTaskWorkItemStore)(getTaskWorkItemStore());
45100
+ return (0, import_protocols35.requireProjectTaskWorkItemStore)(getTaskWorkItemStore());
44011
45101
  }
44012
45102
  function reviewInterruption(task) {
44013
45103
  const value = task.context?.interruption;
@@ -44057,7 +45147,7 @@ var manageTaskSchema = import_zod68.z.object({
44057
45147
  })).optional().describe("Structured belief reports required when an agent-owned task completes; existing keys update the belief owner's table, and a brand-new key must be declared with isNew: true"),
44058
45148
  content: import_zod68.z.string().optional().describe("Markdown content required for add_activity"),
44059
45149
  summary: import_zod68.z.string().optional().describe("Brief summary of the operation"),
44060
- executionResultId: import_zod68.z.string().refine(import_protocols33.isExecutionResultEventKey, {
45150
+ executionResultId: import_zod68.z.string().refine(import_protocols35.isExecutionResultEventKey, {
44061
45151
  message: "executionResultId must be the execution-result:<threadId> event key returned by task()"
44062
45152
  }).optional().describe(
44063
45153
  "Canonical ASCII `execution-result:<suffix>` event key returned by task(); the nonempty suffix allows only A-Z, a-z, 0-9, period, underscore, colon, and hyphen, and is not a database row ID"
@@ -44122,7 +45212,7 @@ async function getPendingExecutionResultIds(store, tenantId2, taskId) {
44122
45212
  order: "desc",
44123
45213
  limit: PENDING_EXECUTION_RESULT_LIMIT + 1
44124
45214
  });
44125
- const canonicalCandidates = candidates.slice(0, PENDING_EXECUTION_RESULT_LIMIT + 1).filter((item) => (0, import_protocols33.isExecutionResultEventKey)(item.eventKey));
45215
+ const canonicalCandidates = candidates.slice(0, PENDING_EXECUTION_RESULT_LIMIT + 1).filter((item) => (0, import_protocols35.isExecutionResultEventKey)(item.eventKey));
44126
45216
  const reconciliationRows = new Array(canonicalCandidates.length);
44127
45217
  let nextCandidateIndex = 0;
44128
45218
  let firstError;
@@ -44207,8 +45297,9 @@ function createTaskMiddleware(options = {}) {
44207
45297
  const trustedProject = authority.kind === "projectRoom" || authority.kind === "projectTask" ? authority.trusted : void 0;
44208
45298
  const trustedScope = trustedProject?.projectTask ?? trustedProject?.projectRoom;
44209
45299
  const tenantId2 = trustedScope?.tenantId ?? (rc.tenantId || "default");
44210
- const workspaceId = trustedScope?.workspaceId ?? rc.workspaceId;
44211
- const projectId = trustedScope?.projectId ?? rc.projectId;
45300
+ const runScope = (0, import_protocols34.resolveRunScope)(rc);
45301
+ const workspaceId = trustedScope?.workspaceId ?? runScope.workspaceId;
45302
+ const projectId = trustedScope?.projectId ?? runScope.projectId;
44212
45303
  const revalidateCaller = async () => {
44213
45304
  if (!trustedProject || trustedRosterExempt(trustedProject)) return void 0;
44214
45305
  try {
@@ -44768,8 +45859,8 @@ function createTaskMiddleware(options = {}) {
44768
45859
  let reconciliationMetadata = {};
44769
45860
  let descriptionMutated = false;
44770
45861
  if (isAgentTask && input.description !== void 0 && !valuesEqual(input.description, existing.description)) {
44771
- const oldBelief = (0, import_protocols33.parseTaskBeliefState)(existing.description ?? "");
44772
- const newBelief = (0, import_protocols33.parseTaskBeliefState)(input.description);
45862
+ const oldBelief = (0, import_protocols35.parseTaskBeliefState)(existing.description ?? "");
45863
+ const newBelief = (0, import_protocols35.parseTaskBeliefState)(input.description);
44773
45864
  const hasBeliefState = oldBelief.success || newBelief.success;
44774
45865
  if (hasBeliefState) {
44775
45866
  await validateExecutionResult();
@@ -45437,15 +46528,16 @@ function createTaskMiddleware(options = {}) {
45437
46528
  assistant_id: invocation.agentId,
45438
46529
  thread_id: invocation.threadId,
45439
46530
  input: { message: invocation.message },
45440
- runConfig: {
45441
- ...rc,
45442
- assistant_id: invocation.agentId,
45443
- thread_id: invocation.threadId,
45444
- taskId: invocation.taskId,
45445
- tenantId: invocation.tenantId,
45446
- workspaceId: invocation.workspaceId,
45447
- projectId: invocation.projectId
45448
- }
46531
+ runConfig: applyWorkerRunScope(
46532
+ {
46533
+ ...rc,
46534
+ assistant_id: invocation.agentId,
46535
+ thread_id: invocation.threadId,
46536
+ taskId: invocation.taskId,
46537
+ tenantId: invocation.tenantId
46538
+ },
46539
+ resolveWorkerRunScope({ invocation, runConfig: rc })
46540
+ )
45449
46541
  });
45450
46542
  const finalState = workerResult?.finalState;
45451
46543
  return boundedWorkerObservation(finalState, void 0);
@@ -45460,7 +46552,7 @@ function createTaskMiddleware(options = {}) {
45460
46552
  agentId,
45461
46553
  actor,
45462
46554
  callerThreadId: rc.thread_id,
45463
- ...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : {}
46555
+ ...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : rc.assistant_id ? { callerAssistantId: rc.assistant_id } : {}
45464
46556
  }));
45465
46557
  };
45466
46558
  return (0, import_langchain83.createMiddleware)({
@@ -45520,7 +46612,14 @@ function createTaskMiddleware(options = {}) {
45520
46612
  task,
45521
46613
  actor: getRuntimeActor2(rc) ?? "system",
45522
46614
  ...threadId ? { threadId } : {},
45523
- outcome: { kind: "interrupted", summary: "Run ended without a task lifecycle transition" }
46615
+ // A run that ended without its own lifecycle transition is a mechanical
46616
+ // failure, NOT HITL. Human-in-the-loop pauses arrive as GraphInterrupt
46617
+ // and never reach afterAgent.
46618
+ outcome: {
46619
+ kind: "failed",
46620
+ lifecycleHandled: false,
46621
+ error: "Run ended without a task lifecycle transition"
46622
+ }
45524
46623
  });
45525
46624
  }
45526
46625
  taskRunRegistry.unregister(taskId);
@@ -46248,7 +47347,7 @@ function createParseDocumentTool({
46248
47347
  }
46249
47348
 
46250
47349
  // src/middlewares/documentParserMiddleware.ts
46251
- var import_protocols34 = require("@axiom-lattice/protocols");
47350
+ var import_protocols36 = require("@axiom-lattice/protocols");
46252
47351
 
46253
47352
  // src/middlewares/documentBenchmarkWorkflow.ts
46254
47353
  var DOCUMENT_PARSER_BENCHMARK_YAML = `name: document-parser-benchmark
@@ -46790,7 +47889,7 @@ var documentParserPlugin = {
46790
47889
  agents: {
46791
47890
  "document-parser": {
46792
47891
  key: "document-parser",
46793
- type: import_protocols34.AgentType.DEEP_AGENT,
47892
+ type: import_protocols36.AgentType.DEEP_AGENT,
46794
47893
  name: "Document Parser",
46795
47894
  description: "Parse documents (pdf, docx, images, spreadsheets) into clean Markdown. Defaults to local MarkItDown; escalates to remote engines only when quality or format needs it; runs engine benchmarking only on explicit request.",
46796
47895
  prompt: DOCUMENT_PARSER_SYSTEM_PROMPT,
@@ -46840,7 +47939,7 @@ var documentParserPlugin = {
46840
47939
  },
46841
47940
  "document-parser-benchmark": {
46842
47941
  key: "document-parser-benchmark",
46843
- type: import_protocols34.AgentType.WORKFLOW,
47942
+ type: import_protocols36.AgentType.WORKFLOW,
46844
47943
  name: "Document Parser Benchmark",
46845
47944
  description: "Benchmark document parsing engines. Parses a document with 5 engines in parallel, scores results, and produces a ranking report. Use this when you need to evaluate which parsing engine works best for a given document.",
46846
47945
  prompt: "Benchmark document parsing engines: parse with 5 engines, score, and rank results.",
@@ -46877,7 +47976,7 @@ var documentParserPlugin = {
46877
47976
 
46878
47977
  // src/middlewares/projectRoomMiddleware.ts
46879
47978
  var import_crypto10 = require("crypto");
46880
- var import_protocols35 = require("@axiom-lattice/protocols");
47979
+ var import_protocols37 = require("@axiom-lattice/protocols");
46881
47980
  var import_langchain87 = require("langchain");
46882
47981
  var import_zod70 = require("zod");
46883
47982
  var PROJECT_ROOM_CONTEXT_REQUIRED = "PROJECT_ROOM_CONTEXT_REQUIRED";
@@ -46907,7 +48006,7 @@ function ownDataValue2(record, key5) {
46907
48006
  if (typeof record !== "object" || record === null || Array.isArray(record)) return void 0;
46908
48007
  try {
46909
48008
  const descriptor = Object.getOwnPropertyDescriptor(record, key5);
46910
- return (0, import_protocols35.descriptorDataValue)(descriptor)?.value;
48009
+ return (0, import_protocols37.descriptorDataValue)(descriptor)?.value;
46911
48010
  } catch {
46912
48011
  return void 0;
46913
48012
  }
@@ -46917,14 +48016,14 @@ function readTrustedRoomScope(config) {
46917
48016
  const runConfig = ownDataValue2(configurable, "runConfig");
46918
48017
  const projectRoom = ownDataValue2(runConfig, "projectRoom");
46919
48018
  try {
46920
- return (0, import_protocols35.parseTrustedRunContext)({ projectRoom }).projectRoom;
48019
+ return (0, import_protocols37.parseTrustedRunContext)({ projectRoom }).projectRoom;
46921
48020
  } catch {
46922
48021
  return void 0;
46923
48022
  }
46924
48023
  }
46925
48024
  function exactValues2(value, required, optional = []) {
46926
48025
  try {
46927
- return (0, import_protocols35.snapshotExactRecord)(value, required, optional);
48026
+ return (0, import_protocols37.snapshotExactRecord)(value, required, optional);
46928
48027
  } catch {
46929
48028
  return void 0;
46930
48029
  }
@@ -46960,7 +48059,7 @@ function snapshotMembership3(value) {
46960
48059
  return { ...values, joinedAt, updatedAt };
46961
48060
  }
46962
48061
  function snapshotRows(value) {
46963
- return (0, import_protocols35.snapshotExactArray)(value) ?? [];
48062
+ return (0, import_protocols37.snapshotExactArray)(value) ?? [];
46964
48063
  }
46965
48064
  async function hasActiveCurrentMembership(scope) {
46966
48065
  const memberships = getStoreLattice("default", "projectBotMembership").store;
@@ -47047,7 +48146,7 @@ var projectRoomPlugin = {
47047
48146
  // src/middlewares/sandboxPluginsMiddleware.ts
47048
48147
  var import_langchain88 = require("langchain");
47049
48148
  var import_zod71 = require("zod");
47050
- var import_protocols36 = require("@axiom-lattice/protocols");
48149
+ var import_protocols38 = require("@axiom-lattice/protocols");
47051
48150
 
47052
48151
  // src/middlewares/sandboxPluginsSkills.ts
47053
48152
  var PLUGIN_JSON_TEMPLATE = `{
@@ -47797,7 +48896,7 @@ var sandboxPluginsPlugin = {
47797
48896
  key: "plugin-builder",
47798
48897
  name: "Plugin Builder",
47799
48898
  description: "Author and manage tenant plugins in the shared sandbox: clarify goal, inputs/outputs, credentials, and whether a UI is needed; then write the manifest and JS handlers, add an optional HTML MCP App UI, and validate/test with the manage_plugin tool.",
47800
- type: import_protocols36.AgentType.DEEP_AGENT,
48899
+ type: import_protocols38.AgentType.DEEP_AGENT,
47801
48900
  prompt: PLUGIN_BUILDER_PROMPT,
47802
48901
  middleware: [
47803
48902
  {
@@ -47878,6 +48977,7 @@ var sandboxPluginsPlugin = {
47878
48977
  }
47879
48978
  case "reload": {
47880
48979
  const loaded = await catalog2.reload(tenantId2);
48980
+ void publishPluginCatalogChanged(tenantId2);
47881
48981
  return JSON.stringify({ reloaded: true, plugins: loaded.plugins.length, diagnostics: loaded.diagnostics });
47882
48982
  }
47883
48983
  case "create":
@@ -47897,12 +48997,14 @@ var sandboxPluginsPlugin = {
47897
48997
  if (!check.manifest) return JSON.stringify({ written: false, diagnostics: check.diagnostics });
47898
48998
  await catalog2.writePlugin(tenantId2, input.type, input.manifest, handlers);
47899
48999
  const loaded = await catalog2.reload(tenantId2);
49000
+ void publishPluginCatalogChanged(tenantId2);
47900
49001
  return JSON.stringify({ written: true, diagnostics: loaded.diagnostics, hash: loaded.hash });
47901
49002
  }
47902
49003
  case "delete": {
47903
49004
  if (!input.type) return "type is required";
47904
49005
  await catalog2.deletePlugin(tenantId2, input.type);
47905
49006
  await catalog2.reload(tenantId2);
49007
+ void publishPluginCatalogChanged(tenantId2);
47906
49008
  return JSON.stringify({ deleted: true });
47907
49009
  }
47908
49010
  case "validate": {
@@ -48014,6 +49116,26 @@ function registerBuiltinPlugins() {
48014
49116
  }
48015
49117
  }
48016
49118
 
49119
+ // src/sandbox_plugin/provisionOpenClient.ts
49120
+ var import_node_fs = require("fs");
49121
+ var SDK_ROOT = "/root/.agents/sdk";
49122
+ var CLIENT_DIR = `${SDK_ROOT}/open-mcp-client`;
49123
+ var MANIFEST_PATH2 = `${SDK_ROOT}/.open-client-manifest.json`;
49124
+ async function provisionSandboxOpenClient(sandbox, bundle) {
49125
+ await sandbox.file.createDirectory(SDK_ROOT);
49126
+ await sandbox.file.createDirectory(CLIENT_DIR);
49127
+ await sandbox.file.writeFile(`${CLIENT_DIR}/index.js`, bundle.indexJs);
49128
+ await sandbox.file.writeFile(`${CLIENT_DIR}/cli.js`, bundle.cliJs);
49129
+ await sandbox.file.writeFile(MANIFEST_PATH2, JSON.stringify({ version: bundle.version }));
49130
+ }
49131
+ function buildBundleFromDist(distDir, version) {
49132
+ return {
49133
+ indexJs: (0, import_node_fs.readFileSync)(`${distDir}/index.js`, "utf8"),
49134
+ cliJs: (0, import_node_fs.readFileSync)(`${distDir}/cli.js`, "utf8"),
49135
+ version
49136
+ };
49137
+ }
49138
+
48017
49139
  // src/workflow/index.ts
48018
49140
  init_compile();
48019
49141
  init_parse_yaml();
@@ -48405,16 +49527,16 @@ var IdRemapper = class {
48405
49527
  };
48406
49528
 
48407
49529
  // src/util/directRoomId.ts
48408
- var import_node_crypto10 = require("crypto");
49530
+ var import_node_crypto14 = require("crypto");
48409
49531
  function generateDirectHumanProjectId(tenantId2, workspaceId, userId1, userId2) {
48410
49532
  const sortedUserIds = [userId1, userId2].sort();
48411
49533
  const parts = [tenantId2, workspaceId, ...sortedUserIds];
48412
- const hash = (0, import_node_crypto10.createHash)("sha256").update(parts.join(":")).digest("hex");
49534
+ const hash = (0, import_node_crypto14.createHash)("sha256").update(parts.join(":")).digest("hex");
48413
49535
  return `direct_human_${hash}`;
48414
49536
  }
48415
49537
  function generateDirectBotProjectId(tenantId2, workspaceId, userId, assistantId) {
48416
49538
  const parts = [tenantId2, workspaceId, userId, assistantId];
48417
- const hash = (0, import_node_crypto10.createHash)("sha256").update(parts.join(":")).digest("hex");
49539
+ const hash = (0, import_node_crypto14.createHash)("sha256").update(parts.join(":")).digest("hex");
48418
49540
  return `direct_bot_${hash}`;
48419
49541
  }
48420
49542
  function parseDirectRoomType(projectId) {
@@ -48483,10 +49605,12 @@ registerBuiltinPlugins();
48483
49605
  InMemoryChunkBuffer,
48484
49606
  InMemoryCollectionStore,
48485
49607
  InMemoryDatabaseConfigStore,
49608
+ InMemoryLeaseStore,
48486
49609
  InMemoryMailboxStore,
48487
49610
  InMemoryMenuStore,
48488
49611
  InMemoryModelProviderStore,
48489
49612
  InMemoryOpenAuditStore,
49613
+ InMemoryOutboxStore,
48490
49614
  InMemoryProjectBotMembershipStore,
48491
49615
  InMemoryProjectMembershipStore,
48492
49616
  InMemoryProjectRoomCoordinator,
@@ -48506,6 +49630,7 @@ registerBuiltinPlugins();
48506
49630
  LatticeEval,
48507
49631
  LatticeEvalProject,
48508
49632
  LatticeEvalSuite,
49633
+ LeaseAcquisitionTimeoutError,
48509
49634
  LocalSandboxInstance,
48510
49635
  LocalSandboxProvider,
48511
49636
  LoggerLatticeManager,
@@ -48528,7 +49653,10 @@ registerBuiltinPlugins();
48528
49653
  MicrosandboxServiceClient,
48529
49654
  ModelLatticeManager,
48530
49655
  MysqlDatabase,
49656
+ OutboxPoller,
48531
49657
  PACK_DIRECTORY_TIMEOUT_SECONDS,
49658
+ PLATFORM_SECRET_ENV_VARS,
49659
+ PLUGIN_CATALOG_CHANGED_TOPIC,
48532
49660
  PersonalAssistantConfig,
48533
49661
  PinoLoggerClient,
48534
49662
  PluginRegistry,
@@ -48549,6 +49677,8 @@ registerBuiltinPlugins();
48549
49677
  RepeatedToolCallError,
48550
49678
  RoomAgentMessageService,
48551
49679
  SAFE_PATH_COMPONENT,
49680
+ SANDBOX_OPEN_GATEWAY_URL_ENV,
49681
+ SANDBOX_OPEN_TOKEN_ENV,
48552
49682
  STTModelLattice,
48553
49683
  STTModelLatticeManager,
48554
49684
  SandboxFilesystem,
@@ -48589,11 +49719,13 @@ registerBuiltinPlugins();
48589
49719
  appendReconciliationWarning,
48590
49720
  appendUiFence,
48591
49721
  assertSafeUpstreamUrl,
49722
+ buildBundleFromDist,
48592
49723
  buildGrepResultsDict,
48593
49724
  buildInput,
48594
49725
  buildNamedVolumeName,
48595
49726
  buildRemotePackDirectoryCommand,
48596
49727
  buildSandboxMetadataEnv,
49728
+ buildSandboxOpenEnv,
48597
49729
  buildSkillFile,
48598
49730
  buildStateAnnotation,
48599
49731
  buildTableName,
@@ -48602,11 +49734,14 @@ registerBuiltinPlugins();
48602
49734
  checkEmptyContent,
48603
49735
  clearEncryptionKeyCache,
48604
49736
  clearEvalRunService,
49737
+ clearSandboxOpenCredentialProviderForTests,
48605
49738
  collectionLatticeManager,
48606
49739
  compileInternal,
48607
49740
  compileSandboxPlugin,
48608
49741
  compileWorkflow,
48609
49742
  computeSandboxName,
49743
+ configureCoordinationLeaseStore,
49744
+ configurePluginCatalogSync,
48610
49745
  configureStores,
48611
49746
  connectAllChannels,
48612
49747
  convertToConnection,
@@ -48638,6 +49773,7 @@ registerBuiltinPlugins();
48638
49773
  createSandboxResolver,
48639
49774
  createSchedulerMiddleware,
48640
49775
  createSharePayload,
49776
+ createShellExecTool,
48641
49777
  createTaskExecutionService,
48642
49778
  createTaskLifecycleService,
48643
49779
  createTaskMiddleware,
@@ -48672,6 +49808,7 @@ registerBuiltinPlugins();
48672
49808
  generateDirectHumanProjectId,
48673
49809
  generateToken,
48674
49810
  getAgentClient,
49811
+ getAgentClientAsync,
48675
49812
  getAgentConfig,
48676
49813
  getAllAgentConfigs,
48677
49814
  getAllBuiltInSkillMetas,
@@ -48683,6 +49820,7 @@ registerBuiltinPlugins();
48683
49820
  getCheckpointSaver,
48684
49821
  getChunkBuffer,
48685
49822
  getCollectionEntryCount,
49823
+ getCoordinationLeaseStore,
48686
49824
  getEmbeddingsClient,
48687
49825
  getEmbeddingsLattice,
48688
49826
  getEncryptionKey,
@@ -48694,15 +49832,18 @@ registerBuiltinPlugins();
48694
49832
  getOrCreateCollectionVectorStore,
48695
49833
  getPluginSkillManifestVersion,
48696
49834
  getQueueLattice,
49835
+ getReplicaId,
48697
49836
  getRuntimeCapabilityConfig,
48698
49837
  getRuntimeSkillSelection,
48699
49838
  getSTTClient,
48700
49839
  getSTTClientWithTenant,
48701
49840
  getSTTModelLattice,
48702
49841
  getSandBoxManager,
49842
+ getSandboxOpenCredential,
48703
49843
  getSandboxPluginCatalog,
48704
49844
  getScheduleLattice,
48705
49845
  getStoreLattice,
49846
+ getThreadRunOwner,
48706
49847
  getToolClient,
48707
49848
  getToolClientWithTenant,
48708
49849
  getToolDefinition,
@@ -48756,6 +49897,8 @@ registerBuiltinPlugins();
48756
49897
  projectMutationMutex,
48757
49898
  projectRoomPlugin,
48758
49899
  projectTaskAdmissionNotifier,
49900
+ provisionSandboxOpenClient,
49901
+ publishPluginCatalogChanged,
48759
49902
  queueLatticeManager,
48760
49903
  readLoopBreakerConfig,
48761
49904
  reconcileAllTenantTaskRuns,
@@ -48774,6 +49917,7 @@ registerBuiltinPlugins();
48774
49917
  registerModelLatticeForTenant,
48775
49918
  registerQueueLattice,
48776
49919
  registerSTTModelLattice,
49920
+ registerSandboxOpenCredentialProvider,
48777
49921
  registerSandboxProviderType,
48778
49922
  registerScheduleLattice,
48779
49923
  registerStoreLattice,
@@ -48784,6 +49928,7 @@ registerBuiltinPlugins();
48784
49928
  registerWorkflowRun,
48785
49929
  removeCollectionVectorStore,
48786
49930
  renderTemplate,
49931
+ resetReplicaIdForTests,
48787
49932
  resolveEnabledPluginSkill,
48788
49933
  resolveJudgeModelKey,
48789
49934
  resolvePath,
@@ -48791,6 +49936,7 @@ registerBuiltinPlugins();
48791
49936
  resolveSandboxPluginConnections,
48792
49937
  resolveTenantPluginSkill,
48793
49938
  roomCoordinatorConfig,
49939
+ runAsLeader,
48794
49940
  runRemotePackDirectory,
48795
49941
  safeTaskResponseId,
48796
49942
  sandboxLatticeManager,
@@ -48809,11 +49955,15 @@ registerBuiltinPlugins();
48809
49955
  storeLatticeManager,
48810
49956
  sttModelLatticeManager,
48811
49957
  taskLifecycleNotifier,
49958
+ taskRunLeaseKey,
48812
49959
  taskRunRegistry,
49960
+ threadRunLeaseKey,
48813
49961
  toJsonSchema,
48814
49962
  toSafeStateExpr,
48815
49963
  toolLatticeManager,
48816
49964
  truncateIfTooLong,
49965
+ tryAcquireTaskRun,
49966
+ tryAcquireThreadRun,
48817
49967
  unregisterTeammateAgent,
48818
49968
  unregisterWorkflowRun,
48819
49969
  updateFileData,
@@ -48829,6 +49979,7 @@ registerBuiltinPlugins();
48829
49979
  validateToolInput,
48830
49980
  vectorStoreLatticeManager,
48831
49981
  vectorStoreProviderManager,
49982
+ withLease,
48832
49983
  withTimeout,
48833
49984
  wrapMcpToolWithUi
48834
49985
  });