@axiom-lattice/core 2.1.75 → 2.1.77

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.mjs CHANGED
@@ -2319,24 +2319,6 @@ var InMemoryThreadMessageQueueStore = class {
2319
2319
  }
2320
2320
  }
2321
2321
  }
2322
- async markCompleted(messageId) {
2323
- for (const messages of this.messages.values()) {
2324
- const message = messages.find((msg) => msg.id === messageId);
2325
- if (message) {
2326
- message.status = "completed";
2327
- return;
2328
- }
2329
- }
2330
- }
2331
- async clearCompletedMessages(threadId) {
2332
- const messages = this.messages.get(threadId);
2333
- if (messages) {
2334
- const filtered = messages.filter(
2335
- (msg) => msg.status !== "completed"
2336
- );
2337
- this.messages.set(threadId, filtered);
2338
- }
2339
- }
2340
2322
  async resetProcessingToPending(threadId) {
2341
2323
  const messages = this.messages.get(threadId);
2342
2324
  if (!messages) {
@@ -2481,14 +2463,35 @@ var InMemoryChannelInstallationStore = class {
2481
2463
  constructor() {
2482
2464
  this.installations = /* @__PURE__ */ new Map();
2483
2465
  }
2466
+ /**
2467
+ * Retrieves a channel installation by its unique ID.
2468
+ *
2469
+ * @param installationId - The installation identifier
2470
+ * @returns The {@link ChannelInstallation} or `null` if not found
2471
+ */
2484
2472
  async getInstallationById(installationId) {
2485
2473
  return this.installations.get(installationId) || null;
2486
2474
  }
2475
+ /**
2476
+ * Lists all channel installations for a tenant, optionally filtered by channel type.
2477
+ *
2478
+ * @param tenantId - Tenant identifier
2479
+ * @param channel - Optional channel type filter (`"lark"`, `"email"`, `"slack"`)
2480
+ * @returns Array of matching {@link ChannelInstallation} objects
2481
+ */
2487
2482
  async getInstallationsByTenant(tenantId, channel) {
2488
2483
  return Array.from(this.installations.values()).filter(
2489
2484
  (inst) => inst.tenantId === tenantId && (!channel || inst.channel === channel)
2490
2485
  );
2491
2486
  }
2487
+ /**
2488
+ * Creates a new channel installation for a tenant.
2489
+ *
2490
+ * @param tenantId - Tenant identifier
2491
+ * @param installationId - Unique installation ID (caller-defined)
2492
+ * @param data - {@link CreateChannelInstallationRequest} containing channel type, name, config, and fallback settings
2493
+ * @returns The created {@link ChannelInstallation}
2494
+ */
2492
2495
  async createInstallation(tenantId, installationId, data) {
2493
2496
  const now = /* @__PURE__ */ new Date();
2494
2497
  const installation = {
@@ -2506,6 +2509,14 @@ var InMemoryChannelInstallationStore = class {
2506
2509
  this.installations.set(installationId, installation);
2507
2510
  return installation;
2508
2511
  }
2512
+ /**
2513
+ * Updates an existing channel installation. Config fields are shallow-merged.
2514
+ *
2515
+ * @param tenantId - Tenant identifier (used for isolation check)
2516
+ * @param installationId - Installation ID to update
2517
+ * @param updates - {@link UpdateChannelInstallationRequest} with fields to patch
2518
+ * @returns The updated {@link ChannelInstallation} or `null` if not found or tenant mismatch
2519
+ */
2509
2520
  async updateInstallation(tenantId, installationId, updates) {
2510
2521
  const existing = this.installations.get(installationId);
2511
2522
  if (!existing || existing.tenantId !== tenantId) return null;
@@ -2521,11 +2532,21 @@ var InMemoryChannelInstallationStore = class {
2521
2532
  this.installations.set(installationId, updated);
2522
2533
  return updated;
2523
2534
  }
2535
+ /**
2536
+ * Deletes a channel installation.
2537
+ *
2538
+ * @param tenantId - Tenant identifier (used for isolation check)
2539
+ * @param installationId - Installation ID to delete
2540
+ * @returns `true` if deleted, `false` if not found or tenant mismatch
2541
+ */
2524
2542
  async deleteInstallation(tenantId, installationId) {
2525
2543
  const existing = this.installations.get(installationId);
2526
2544
  if (!existing || existing.tenantId !== tenantId) return false;
2527
2545
  return this.installations.delete(installationId);
2528
2546
  }
2547
+ /**
2548
+ * Clears all in-memory installations. Primarily used in tests.
2549
+ */
2529
2550
  clear() {
2530
2551
  this.installations.clear();
2531
2552
  }
@@ -2537,6 +2558,16 @@ var InMemoryBindingStore = class {
2537
2558
  constructor() {
2538
2559
  this.bindings = /* @__PURE__ */ new Map();
2539
2560
  }
2561
+ /**
2562
+ * Resolves a binding for the given sender across a specific channel installation.
2563
+ *
2564
+ * Called by `MessageRouter.dispatch()` during inbound message processing.
2565
+ * Matches on `channel + senderId + channelInstallationId + tenantId` and
2566
+ * requires `enabled === true`.
2567
+ *
2568
+ * @param params - Resolution parameters
2569
+ * @returns The matching {@link Binding} or `null` if none found.
2570
+ */
2540
2571
  async resolve(params) {
2541
2572
  for (const binding of this.bindings.values()) {
2542
2573
  if (binding.channel === params.channel && binding.senderId === params.senderId && binding.channelInstallationId === params.channelInstallationId && binding.tenantId === params.tenantId && binding.enabled) {
@@ -2545,6 +2576,12 @@ var InMemoryBindingStore = class {
2545
2576
  }
2546
2577
  return null;
2547
2578
  }
2579
+ /**
2580
+ * Creates a new sender-to-agent binding.
2581
+ *
2582
+ * @param input - {@link CreateBindingInput} defining channel, sender, target agent, and thread mode.
2583
+ * @returns The newly created {@link Binding}.
2584
+ */
2548
2585
  async create(input) {
2549
2586
  const now = /* @__PURE__ */ new Date();
2550
2587
  const binding = {
@@ -2567,6 +2604,14 @@ var InMemoryBindingStore = class {
2567
2604
  this.bindings.set(binding.id, binding);
2568
2605
  return binding;
2569
2606
  }
2607
+ /**
2608
+ * Updates an existing binding (e.g. changing the target agent or thread mode).
2609
+ *
2610
+ * @param id - Binding ID
2611
+ * @param patch - Partial {@link Binding} fields to update
2612
+ * @returns The updated {@link Binding}
2613
+ * @throws {Error} If the binding does not exist
2614
+ */
2570
2615
  async update(id, patch) {
2571
2616
  const existing = this.bindings.get(id);
2572
2617
  if (!existing) throw new Error(`Binding ${id} not found`);
@@ -2578,9 +2623,20 @@ var InMemoryBindingStore = class {
2578
2623
  this.bindings.set(id, updated);
2579
2624
  return updated;
2580
2625
  }
2626
+ /**
2627
+ * Deletes a binding by ID.
2628
+ *
2629
+ * @param id - Binding ID
2630
+ */
2581
2631
  async delete(id) {
2582
2632
  this.bindings.delete(id);
2583
2633
  }
2634
+ /**
2635
+ * Lists bindings filtered by tenant and optional channel/agent/installation.
2636
+ *
2637
+ * @param params - Filter and pagination parameters
2638
+ * @returns Array of matching {@link Binding} objects
2639
+ */
2584
2640
  async list(params) {
2585
2641
  let results = Array.from(this.bindings.values()).filter((b) => {
2586
2642
  if (b.tenantId !== params.tenantId) return false;
@@ -2593,6 +2649,12 @@ var InMemoryBindingStore = class {
2593
2649
  const limit = params.limit ?? 50;
2594
2650
  return results.slice(offset, offset + limit);
2595
2651
  }
2652
+ /**
2653
+ * Bulk-imports bindings.
2654
+ *
2655
+ * @param bindings - Array of {@link CreateBindingInput}
2656
+ * @returns Array of created {@link Binding} objects
2657
+ */
2596
2658
  async import(bindings) {
2597
2659
  const result = [];
2598
2660
  for (const input of bindings) {
@@ -2600,9 +2662,18 @@ var InMemoryBindingStore = class {
2600
2662
  }
2601
2663
  return result;
2602
2664
  }
2665
+ /**
2666
+ * Exports all bindings for a tenant.
2667
+ *
2668
+ * @param params - Filter by tenantId
2669
+ * @returns Array of {@link Binding} objects
2670
+ */
2603
2671
  async export(params) {
2604
2672
  return this.list({ tenantId: params.tenantId, limit: 1e4 });
2605
2673
  }
2674
+ /**
2675
+ * Clears all in-memory bindings. Primarily used in tests.
2676
+ */
2606
2677
  clear() {
2607
2678
  this.bindings.clear();
2608
2679
  }
@@ -3225,7 +3296,6 @@ var SqlDatabaseManager = class _SqlDatabaseManager {
3225
3296
  constructor() {
3226
3297
  this.databases = /* @__PURE__ */ new Map();
3227
3298
  this.defaultDatabaseKeys = /* @__PURE__ */ new Map();
3228
- this.configStore = null;
3229
3299
  }
3230
3300
  /**
3231
3301
  * Get the singleton instance
@@ -3285,16 +3355,9 @@ var SqlDatabaseManager = class _SqlDatabaseManager {
3285
3355
  }
3286
3356
  this.defaultDatabaseKeys.set(tenantId, key);
3287
3357
  }
3288
- /**
3289
- * Set the configuration store for on-demand database loading
3290
- * @param store - The database configuration store
3291
- */
3292
- setConfigStore(store) {
3293
- this.configStore = store;
3294
- }
3295
3358
  /**
3296
3359
  * Get a database by key for a specific tenant
3297
- * If database is not registered and configStore is set, will try to load from store
3360
+ * If database is not registered, tries to load from the store lattice
3298
3361
  * @param tenantId - Tenant identifier (required)
3299
3362
  * @param key - Database key (optional, uses default if not provided)
3300
3363
  * @returns ISqlDatabase instance
@@ -3312,8 +3375,10 @@ var SqlDatabaseManager = class _SqlDatabaseManager {
3312
3375
  return database;
3313
3376
  }
3314
3377
  }
3315
- if (this.configStore) {
3316
- const configEntry = await this.configStore.getConfigByKey(tenantId, dbKey);
3378
+ try {
3379
+ const { store } = getStoreLattice("default", "database");
3380
+ const configStore = store;
3381
+ const configEntry = await configStore.getConfigByKey(tenantId, dbKey);
3317
3382
  if (configEntry) {
3318
3383
  this.registerDatabase(tenantId, dbKey, configEntry.config);
3319
3384
  if (!this.defaultDatabaseKeys.has(tenantId)) {
@@ -3327,6 +3392,7 @@ var SqlDatabaseManager = class _SqlDatabaseManager {
3327
3392
  }
3328
3393
  }
3329
3394
  }
3395
+ } catch {
3330
3396
  }
3331
3397
  if (!tenantDbs) {
3332
3398
  throw new Error(`No databases registered for tenant '${tenantId}'`);
@@ -4436,6 +4502,7 @@ var MetricsServerManager = class _MetricsServerManager {
4436
4502
  this.clients = /* @__PURE__ */ new Map();
4437
4503
  this.configs = /* @__PURE__ */ new Map();
4438
4504
  this.defaultServerKeys = /* @__PURE__ */ new Map();
4505
+ this._loadingPromise = null;
4439
4506
  }
4440
4507
  /**
4441
4508
  * Get the singleton instance
@@ -4446,6 +4513,32 @@ var MetricsServerManager = class _MetricsServerManager {
4446
4513
  }
4447
4514
  return _MetricsServerManager.instance;
4448
4515
  }
4516
+ /**
4517
+ * Ensure configurations are loaded from the store lattice.
4518
+ * Uses a promise-lock to prevent concurrent loads.
4519
+ */
4520
+ async _ensureLoaded() {
4521
+ if (this.clients.size > 0) {
4522
+ return;
4523
+ }
4524
+ if (this._loadingPromise) {
4525
+ return this._loadingPromise;
4526
+ }
4527
+ this._loadingPromise = (async () => {
4528
+ try {
4529
+ const { store } = getStoreLattice("default", "metrics");
4530
+ const configStore = store;
4531
+ const configs = await configStore.getAllConfigsWithoutTenant();
4532
+ for (const entry of configs) {
4533
+ const tenantId = entry.tenantId || "default";
4534
+ this.registerServer(tenantId, entry.key, entry.config);
4535
+ }
4536
+ } finally {
4537
+ this._loadingPromise = null;
4538
+ }
4539
+ })();
4540
+ return this._loadingPromise;
4541
+ }
4449
4542
  /**
4450
4543
  * Get or create tenant clients map
4451
4544
  */
@@ -4514,7 +4607,8 @@ var MetricsServerManager = class _MetricsServerManager {
4514
4607
  * @param tenantId - Tenant identifier
4515
4608
  * @param key - Server key (optional, uses default if not provided)
4516
4609
  */
4517
- getClient(tenantId, key) {
4610
+ async getClient(tenantId, key) {
4611
+ await this._ensureLoaded();
4518
4612
  const tenantClients = this.clients.get(tenantId);
4519
4613
  if (!tenantClients) {
4520
4614
  throw new Error(`No metrics servers registered for tenant '${tenantId}'`);
@@ -4534,7 +4628,8 @@ var MetricsServerManager = class _MetricsServerManager {
4534
4628
  * @param tenantId - Tenant identifier
4535
4629
  * @param key - Server key (optional, uses default if not provided)
4536
4630
  */
4537
- getConfig(tenantId, key) {
4631
+ async getConfig(tenantId, key) {
4632
+ await this._ensureLoaded();
4538
4633
  const tenantConfigs = this.configs.get(tenantId);
4539
4634
  if (!tenantConfigs) {
4540
4635
  throw new Error(`No metrics servers registered for tenant '${tenantId}'`);
@@ -4562,7 +4657,8 @@ var MetricsServerManager = class _MetricsServerManager {
4562
4657
  * Get all registered metrics server keys with their types for a tenant
4563
4658
  * @param tenantId - Tenant identifier
4564
4659
  */
4565
- getServerKeys(tenantId) {
4660
+ async getServerKeys(tenantId) {
4661
+ await this._ensureLoaded();
4566
4662
  const tenantConfigs = this.configs.get(tenantId);
4567
4663
  if (!tenantConfigs) {
4568
4664
  return [];
@@ -4629,20 +4725,6 @@ var MetricsServerManager = class _MetricsServerManager {
4629
4725
  this.registerServer(tenantId, entry.key, entry.config);
4630
4726
  }
4631
4727
  }
4632
- /**
4633
- * Load all metrics server configurations from a store
4634
- * across all tenants and register them with this manager
4635
- *
4636
- * @param store - The metrics server configuration store
4637
- * @deprecated Use loadConfigsFromStore with specific tenant instead
4638
- */
4639
- async loadAllConfigsFromStore(store) {
4640
- const configs = await store.getAllConfigsWithoutTenant();
4641
- for (const entry of configs) {
4642
- const tenantId = entry.tenantId || "default";
4643
- this.registerServer(tenantId, entry.key, entry.config);
4644
- }
4645
- }
4646
4728
  };
4647
4729
  var metricsServerManager = MetricsServerManager.getInstance();
4648
4730
 
@@ -4661,7 +4743,7 @@ ${serverKeys.map(
4661
4743
  async (_input, _exeConfig) => {
4662
4744
  try {
4663
4745
  const tenantId = getTenantIdFromConfig2(_exeConfig, getTenantId2);
4664
- const servers = metricsServerManager.getServerKeys(tenantId);
4746
+ const servers = await metricsServerManager.getServerKeys(tenantId);
4665
4747
  if (servers.length === 0) {
4666
4748
  return "No metrics servers registered.";
4667
4749
  }
@@ -4700,7 +4782,7 @@ ${serverKeys.map(
4700
4782
  const tenantId = getTenantIdFromConfig2(_exeConfig, getTenantId2);
4701
4783
  let effectiveServerKeys = serverKeys;
4702
4784
  if (connectAll) {
4703
- effectiveServerKeys = metricsServerManager.getServerKeys(tenantId).map((s) => s.key);
4785
+ effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
4704
4786
  }
4705
4787
  const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
4706
4788
  const runConfig = _exeConfig?.configurable?.runConfig || {};
@@ -4723,12 +4805,12 @@ To view all available data sources, please clear the current selection or reopen
4723
4805
  const allDataSources = [];
4724
4806
  for (const serverKey of filteredServerKeys) {
4725
4807
  try {
4726
- const config = metricsServerManager.getConfig(tenantId, serverKey);
4808
+ const config = await metricsServerManager.getConfig(tenantId, serverKey);
4727
4809
  if (config.type !== "semantic") {
4728
4810
  console.warn(`Server "${serverKey}" is not a semantic metrics server, skipping.`);
4729
4811
  continue;
4730
4812
  }
4731
- const client = metricsServerManager.getClient(tenantId, serverKey);
4813
+ const client = await metricsServerManager.getClient(tenantId, serverKey);
4732
4814
  const dataSources = await client.getDataSources();
4733
4815
  const selectedIds = config.selectedDataSources || [];
4734
4816
  const filteredDataSources = selectedIds.length > 0 ? dataSources.filter((ds) => selectedIds.includes(String(ds.id))) : dataSources;
@@ -4819,7 +4901,7 @@ ${serverKeys.map(
4819
4901
  const tenantId = getTenantIdFromConfig2(_exeConfig, getTenantId2);
4820
4902
  let effectiveServerKeys = serverKeys;
4821
4903
  if (connectAll) {
4822
- effectiveServerKeys = metricsServerManager.getServerKeys(tenantId).map((s) => s.key);
4904
+ effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
4823
4905
  }
4824
4906
  const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
4825
4907
  const runConfig = _exeConfig?.configurable?.runConfig || {};
@@ -4831,11 +4913,11 @@ ${serverKeys.map(
4831
4913
  if (!filteredServerKeys.includes(serverKey)) {
4832
4914
  return `Error: serverKey "${serverKey}" is not available for tenant "${tenantId}". Available servers: [${filteredServerKeys.join(", ")}]`;
4833
4915
  }
4834
- const config = metricsServerManager.getConfig(tenantId, serverKey);
4916
+ const config = await metricsServerManager.getConfig(tenantId, serverKey);
4835
4917
  if (config.type !== "semantic") {
4836
4918
  return `Error: Server "${serverKey}" is not a semantic metrics server. This tool only works with semantic servers.`;
4837
4919
  }
4838
- const client = metricsServerManager.getClient(tenantId, serverKey);
4920
+ const client = await metricsServerManager.getClient(tenantId, serverKey);
4839
4921
  const targetDatasourceIds = datasourceIds && datasourceIds.length > 0 ? datasourceIds : metricsDataSource?.datasourceId ? [metricsDataSource.datasourceId] : client.getSelectedDataSources();
4840
4922
  if (targetDatasourceIds.length === 0) {
4841
4923
  return `Error: No data sources specified and no default data sources configured for server "${serverKey}".`;
@@ -4977,7 +5059,7 @@ ${serverKeys.map(
4977
5059
  const tenantId = getTenantIdFromConfig2(_exeConfig, getTenantId2);
4978
5060
  let effectiveServerKeys = serverKeys;
4979
5061
  if (connectAll) {
4980
- effectiveServerKeys = metricsServerManager.getServerKeys(tenantId).map((s) => s.key);
5062
+ effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
4981
5063
  }
4982
5064
  const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
4983
5065
  const runConfig = _exeConfig?.configurable?.runConfig || {};
@@ -4993,11 +5075,11 @@ ${serverKeys.map(
4993
5075
  if (!metricName) {
4994
5076
  return "Error: metricName parameter is required.";
4995
5077
  }
4996
- const config = metricsServerManager.getConfig(tenantId, serverKey);
5078
+ const config = await metricsServerManager.getConfig(tenantId, serverKey);
4997
5079
  if (config.type !== "semantic") {
4998
5080
  return `Error: Server "${serverKey}" is not a semantic metrics server. This tool only works with semantic servers.`;
4999
5081
  }
5000
- const client = metricsServerManager.getClient(tenantId, serverKey);
5082
+ const client = await metricsServerManager.getClient(tenantId, serverKey);
5001
5083
  const targetDatasourceIds = datasourceId ? [datasourceId] : client.getSelectedDataSources();
5002
5084
  if (targetDatasourceIds.length === 0) {
5003
5085
  return `Error: No datasourceId specified and no default data sources configured for server "${serverKey}".`;
@@ -5213,7 +5295,7 @@ ${serverKeys.map(
5213
5295
  const tenantId = getTenantIdFromConfig2(_exeConfig, getTenantId2);
5214
5296
  let effectiveServerKeys = serverKeys;
5215
5297
  if (connectAll) {
5216
- effectiveServerKeys = metricsServerManager.getServerKeys(tenantId).map((s) => s.key);
5298
+ effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
5217
5299
  }
5218
5300
  const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
5219
5301
  const runConfig = _exeConfig?.configurable?.runConfig || {};
@@ -5232,11 +5314,11 @@ ${serverKeys.map(
5232
5314
  if (!metrics || metrics.length === 0) {
5233
5315
  return "Error: metrics parameter is required (at least one metric name).";
5234
5316
  }
5235
- const config = metricsServerManager.getConfig(tenantId, serverKey);
5317
+ const config = await metricsServerManager.getConfig(tenantId, serverKey);
5236
5318
  if (config.type !== "semantic") {
5237
5319
  return `Error: Server "${serverKey}" is not a semantic metrics server. This tool only works with semantic servers.`;
5238
5320
  }
5239
- const client = metricsServerManager.getClient(tenantId, serverKey);
5321
+ const client = await metricsServerManager.getClient(tenantId, serverKey);
5240
5322
  const semanticFilters = (filters || []).map((f) => ({
5241
5323
  dimension: f.dimension,
5242
5324
  operator: f.operator,
@@ -5294,7 +5376,7 @@ ${serverKeys.map(
5294
5376
  const tenantId = getTenantIdFromConfig2(_exeConfig, getTenantId2);
5295
5377
  let effectiveServerKeys = serverKeys;
5296
5378
  if (connectAll) {
5297
- effectiveServerKeys = metricsServerManager.getServerKeys(tenantId).map((s) => s.key);
5379
+ effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
5298
5380
  }
5299
5381
  const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
5300
5382
  const runConfig = _exeConfig?.configurable?.runConfig || {};
@@ -5306,11 +5388,11 @@ ${serverKeys.map(
5306
5388
  if (!filteredServerKeys.includes(serverKey)) {
5307
5389
  return `Error: serverKey "${serverKey}" is not available for tenant "${tenantId}". Available servers: [${filteredServerKeys.join(", ")}]`;
5308
5390
  }
5309
- const config = metricsServerManager.getConfig(tenantId, serverKey);
5391
+ const config = await metricsServerManager.getConfig(tenantId, serverKey);
5310
5392
  if (config.type !== "semantic") {
5311
5393
  return `Error: Server "${serverKey}" is not a semantic metrics server. This tool only works with semantic servers.`;
5312
5394
  }
5313
- const client = metricsServerManager.getClient(tenantId, serverKey);
5395
+ const client = await metricsServerManager.getClient(tenantId, serverKey);
5314
5396
  const targetDatasourceIds = datasourceIds && datasourceIds.length > 0 ? datasourceIds : metricsDataSource?.datasourceId ? [metricsDataSource.datasourceId] : client.getSelectedDataSources();
5315
5397
  if (targetDatasourceIds.length === 0) {
5316
5398
  return `Error: No data sources specified and no default data sources configured for server "${serverKey}".`;
@@ -5399,7 +5481,7 @@ ${serverKeys.map(
5399
5481
  const tenantId = getTenantIdFromConfig2(_exeConfig, getTenantId2);
5400
5482
  let effectiveServerKeys = serverKeys;
5401
5483
  if (connectAll) {
5402
- effectiveServerKeys = metricsServerManager.getServerKeys(tenantId).map((s) => s.key);
5484
+ effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
5403
5485
  }
5404
5486
  const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
5405
5487
  const runConfig = _exeConfig?.configurable?.runConfig || {};
@@ -5415,11 +5497,11 @@ ${serverKeys.map(
5415
5497
  if (!tableName) {
5416
5498
  return "Error: tableName parameter is required.";
5417
5499
  }
5418
- const config = metricsServerManager.getConfig(tenantId, serverKey);
5500
+ const config = await metricsServerManager.getConfig(tenantId, serverKey);
5419
5501
  if (config.type !== "semantic") {
5420
5502
  return `Error: Server "${serverKey}" is not a semantic metrics server. This tool only works with semantic servers.`;
5421
5503
  }
5422
- const client = metricsServerManager.getClient(tenantId, serverKey);
5504
+ const client = await metricsServerManager.getClient(tenantId, serverKey);
5423
5505
  const targetDatasourceIds = datasourceId ? [datasourceId] : client.getSelectedDataSources();
5424
5506
  if (targetDatasourceIds.length === 0) {
5425
5507
  return `Error: No datasourceId specified and no default data sources configured for server "${serverKey}".`;
@@ -5539,7 +5621,7 @@ ${serverKeys.map(
5539
5621
  const tenantId = getTenantIdFromConfig2(_exeConfig, getTenantId2);
5540
5622
  let effectiveServerKeys = serverKeys;
5541
5623
  if (connectAll) {
5542
- effectiveServerKeys = metricsServerManager.getServerKeys(tenantId).map((s) => s.key);
5624
+ effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
5543
5625
  }
5544
5626
  const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
5545
5627
  const runConfig = _exeConfig?.configurable?.runConfig || {};
@@ -5558,11 +5640,11 @@ ${serverKeys.map(
5558
5640
  if (!customSql || customSql.trim().length === 0) {
5559
5641
  return "Error: customSql parameter is required and cannot be empty.";
5560
5642
  }
5561
- const config = metricsServerManager.getConfig(tenantId, serverKey);
5643
+ const config = await metricsServerManager.getConfig(tenantId, serverKey);
5562
5644
  if (config.type !== "semantic") {
5563
5645
  return `Error: Server "${serverKey}" is not a semantic metrics server. This tool only works with semantic servers.`;
5564
5646
  }
5565
- const client = metricsServerManager.getClient(tenantId, serverKey);
5647
+ const client = await metricsServerManager.getClient(tenantId, serverKey);
5566
5648
  const result = await client.executeSqlQuery({
5567
5649
  datasourceId,
5568
5650
  customSql,
@@ -11913,6 +11995,14 @@ var ThreadStatus2 = /* @__PURE__ */ ((ThreadStatus3) => {
11913
11995
  return ThreadStatus3;
11914
11996
  })(ThreadStatus2 || {});
11915
11997
  var Agent = class {
11998
+ /**
11999
+ * Constructs an Agent instance.
12000
+ *
12001
+ * Prefer {@link AgentInstanceManager.getAgent} over direct construction — it
12002
+ * ensures a single instance per thread.
12003
+ *
12004
+ * @param params - {@link AgentThreadInterface}
12005
+ */
11916
12006
  constructor({
11917
12007
  assistant_id,
11918
12008
  thread_id,
@@ -12122,9 +12212,10 @@ var Agent = class {
12122
12212
  command: p.command,
12123
12213
  custom_run_config: p.custom_run_config ?? queueMessageData.custom_run_config
12124
12214
  }, signal);
12125
- await this.queueStore?.markCompleted(p.id);
12215
+ await this.queueStore?.removeMessage(p.id);
12126
12216
  const runStatus = await this.getRunStatus();
12127
12217
  const state = await this.getCurrentState();
12218
+ const customRunConfig = p.custom_run_config ?? queueMessageData.custom_run_config;
12128
12219
  if (runStatus === "interrupted" /* INTERRUPTED */) {
12129
12220
  this.publish("message:interrupted", {
12130
12221
  type: "message:interrupted",
@@ -12149,6 +12240,12 @@ var Agent = class {
12149
12240
  state
12150
12241
  });
12151
12242
  }
12243
+ this.publish("reply:ready", {
12244
+ type: "reply:ready",
12245
+ timestamp: /* @__PURE__ */ new Date(),
12246
+ state,
12247
+ customRunConfig
12248
+ });
12152
12249
  } catch (error) {
12153
12250
  console.error(`STEER/Command message ${p.id} execution failed:`, error);
12154
12251
  this.addChunk({
@@ -12164,7 +12261,8 @@ var Agent = class {
12164
12261
  error: error instanceof Error ? error.message : String(error),
12165
12262
  timestamp: /* @__PURE__ */ new Date()
12166
12263
  });
12167
- throw error;
12264
+ await this.queueStore?.removeMessage(p.id);
12265
+ continue;
12168
12266
  }
12169
12267
  }
12170
12268
  }
@@ -12200,7 +12298,7 @@ var Agent = class {
12200
12298
  const runStatus = await this.getRunStatus();
12201
12299
  const state = await this.getCurrentState();
12202
12300
  for (const p of remainingPendings) {
12203
- await this.queueStore?.markCompleted(p.id);
12301
+ await this.queueStore?.removeMessage(p.id);
12204
12302
  if (runStatus === "interrupted" /* INTERRUPTED */) {
12205
12303
  this.publish("message:interrupted", {
12206
12304
  type: "message:interrupted",
@@ -12226,6 +12324,12 @@ var Agent = class {
12226
12324
  });
12227
12325
  }
12228
12326
  }
12327
+ this.publish("reply:ready", {
12328
+ type: "reply:ready",
12329
+ timestamp: /* @__PURE__ */ new Date(),
12330
+ state,
12331
+ customRunConfig: remainingPendings[0]?.custom_run_config ?? firstQueueMessage?.custom_run_config
12332
+ });
12229
12333
  } catch (error) {
12230
12334
  console.error(`COLLECT mode execution failed:`, error);
12231
12335
  for (const p of remainingPendings) {
@@ -12242,8 +12346,8 @@ var Agent = class {
12242
12346
  error: error instanceof Error ? error.message : String(error),
12243
12347
  timestamp: /* @__PURE__ */ new Date()
12244
12348
  });
12349
+ await this.queueStore?.removeMessage(p.id);
12245
12350
  }
12246
- throw error;
12247
12351
  }
12248
12352
  } else if (this.queueMode.mode === "followup" /* FOLLOWUP */) {
12249
12353
  for (const p of remainingPendings) {
@@ -12271,9 +12375,10 @@ var Agent = class {
12271
12375
  input,
12272
12376
  custom_run_config: p.custom_run_config ?? queueMessageData.custom_run_config
12273
12377
  }, signal);
12274
- await this.queueStore?.markCompleted(p.id);
12378
+ await this.queueStore?.removeMessage(p.id);
12275
12379
  const runStatus = await this.getRunStatus();
12276
12380
  const state = await this.getCurrentState();
12381
+ const customRunConfig = p.custom_run_config ?? queueMessageData.custom_run_config;
12277
12382
  if (runStatus === "interrupted" /* INTERRUPTED */) {
12278
12383
  this.publish("message:interrupted", {
12279
12384
  type: "message:interrupted",
@@ -12298,6 +12403,12 @@ var Agent = class {
12298
12403
  state
12299
12404
  });
12300
12405
  }
12406
+ this.publish("reply:ready", {
12407
+ type: "reply:ready",
12408
+ timestamp: /* @__PURE__ */ new Date(),
12409
+ state,
12410
+ customRunConfig
12411
+ });
12301
12412
  } catch (error) {
12302
12413
  console.error(`FOLLOWUP mode message ${p.id} execution failed:`, error);
12303
12414
  this.addChunk({
@@ -12313,7 +12424,8 @@ var Agent = class {
12313
12424
  error: error instanceof Error ? error.message : String(error),
12314
12425
  timestamp: /* @__PURE__ */ new Date()
12315
12426
  });
12316
- throw error;
12427
+ await this.queueStore?.removeMessage(p.id);
12428
+ continue;
12317
12429
  }
12318
12430
  }
12319
12431
  }
@@ -12339,9 +12451,25 @@ var Agent = class {
12339
12451
  setQueueStore(store) {
12340
12452
  this.queueStore = store;
12341
12453
  }
12454
+ /**
12455
+ * Push a chunk into the streaming buffer for this thread.
12456
+ *
12457
+ * Consumers read chunks via {@link chunkStream}.
12458
+ *
12459
+ * @param content - The message chunk to buffer
12460
+ */
12342
12461
  addChunk(content) {
12343
12462
  return this.chunkBuffer.addChunk(this.thread_id, content);
12344
12463
  }
12464
+ /**
12465
+ * Returns an async iterator over new chunks since the given message ID.
12466
+ *
12467
+ * Used by SSE endpoints to stream agent output to clients in real time.
12468
+ *
12469
+ * @param message_id - The client message ID to start streaming from
12470
+ * @param stopTypes - Optional chunk types that terminate the stream
12471
+ * @returns An async iterable yielding {@link MessageChunk} objects
12472
+ */
12345
12473
  chunkStream(message_id, stopTypes) {
12346
12474
  const stream = this.chunkBuffer.getNewChunksSinceContentIterator(
12347
12475
  this.thread_id,
@@ -12430,13 +12558,21 @@ var Agent = class {
12430
12558
  };
12431
12559
  }
12432
12560
  /**
12433
- * Set queue configuration for thread
12561
+ * Override the thread's queue processing mode.
12562
+ *
12563
+ * @param config - Partial {@link ThreadQueueConfig} (e.g. `{ mode: QueueMode.FOLLOWUP }`)
12434
12564
  */
12435
12565
  async setQueueConfig(config) {
12436
12566
  this.queueMode = { ...this.queueMode, ...config };
12437
12567
  }
12438
12568
  /**
12439
- * Stop queue processor
12569
+ * Abort any ongoing queue processing without clearing the queue.
12570
+ *
12571
+ * Used internally by STEER mode to interrupt the current execution so the
12572
+ * steer message can be processed next. For a full abort that also clears
12573
+ * pending messages, use {@link abort}.
12574
+ *
12575
+ * @see {@link abort}
12440
12576
  */
12441
12577
  stopQueueProcessor() {
12442
12578
  if (this.abortController) {
@@ -12445,14 +12581,34 @@ var Agent = class {
12445
12581
  }
12446
12582
  }
12447
12583
  /**
12448
- * Add message to queue
12449
- * All messages go to queue, processor auto-starts if not running
12450
- * STEER/Command messages are inserted at head of queue for immediate processing
12451
- *
12452
- * Supports both legacy single message format and new messages[] format:
12453
- * - Legacy: input.message (single human message)
12454
- * - New: input.messages[] (array of mixed human/system messages)
12455
- * - When input.messages is provided, it takes precedence over input.message
12584
+ * Enqueue a message for this thread.
12585
+ *
12586
+ * Messages are always queued; the queue processor starts automatically if idle.
12587
+ * Returns immediately with the message ID — execution is asynchronous.
12588
+ *
12589
+ * **Queue modes** (via the optional `mode` param):
12590
+ * - `COLLECT` (default) Batch multiple pending messages into one agent call.
12591
+ * - `FOLLOWUP` — Process messages one at a time in order.
12592
+ * - `STEER` — High-priority, inserted at queue head, interrupts current processing.
12593
+ *
12594
+ * **Format**: Supports both `input.message` (legacy string) and `input.messages[]`
12595
+ * (array of `{ role, content }` objects). The array form takes precedence.
12596
+ *
12597
+ * The `custom_run_config` field is round-tripped through the queue and emitted
12598
+ * back in {@link ReplyReadyEvent}, enabling callers to attach routing metadata
12599
+ * (e.g. `_replyTarget` for channel reply).
12600
+ *
12601
+ * @param queueMessage - The message to enqueue
12602
+ * @param mode - Optional queue mode override (defaults to thread's current mode)
12603
+ * @returns `{ queued: true, executed: false, messageId }` — execution happens asynchronously
12604
+ *
12605
+ * @example
12606
+ * ```ts
12607
+ * await agent.addMessage({
12608
+ * input: { message: "Hello" },
12609
+ * custom_run_config: { _replyTarget: { adapterChannel: "lark", rawTarget: { chatId: "xxx" } } },
12610
+ * });
12611
+ * ```
12456
12612
  */
12457
12613
  async addMessage(queueMessage, mode) {
12458
12614
  const useMode = mode ?? this.queueMode.mode;
@@ -12546,8 +12702,13 @@ var Agent = class {
12546
12702
  return { queued: true, executed: false, messageId };
12547
12703
  }
12548
12704
  /**
12549
- * Start queue processor if not already running
12550
- * Public method to allow external triggering (e.g., from recovery)
12705
+ * Start the queue processor if it is not already running.
12706
+ *
12707
+ * Called automatically by {@link addMessage} and {@link resumeTask}.
12708
+ * Safe to call externally — it is a no-op if processing is already active.
12709
+ *
12710
+ * Emits `thread:busy` before starting, and starts the {@link waitingForQueueEnd}
12711
+ * loop with a fresh {@link AbortController}.
12551
12712
  */
12552
12713
  async startQueueProcessorIfNeeded() {
12553
12714
  const store = this.getQueueStore();
@@ -12595,6 +12756,12 @@ var Agent = class {
12595
12756
  type: "system"
12596
12757
  });
12597
12758
  }
12759
+ /**
12760
+ * Returns a LangGraph StateSnapshot for this thread.
12761
+ *
12762
+ * Includes `state.values.messages` (full conversation history) and
12763
+ * `state.tasks` / `state.next` (execution progress).
12764
+ */
12598
12765
  async getCurrentState() {
12599
12766
  const { runnable_agent } = await this.getLatticeClientAndRuntimeConfig();
12600
12767
  const state = await runnable_agent.getState({
@@ -12602,6 +12769,14 @@ var Agent = class {
12602
12769
  });
12603
12770
  return state;
12604
12771
  }
12772
+ /**
12773
+ * Returns the conversation history as normalized message objects.
12774
+ *
12775
+ * Filters to `human`, `ai`, and `tool` message types. Each entry has
12776
+ * `{ id, role, content }` plus any LangChain kwargs.
12777
+ *
12778
+ * @returns Array of message objects with `id`, `role`, and `content`
12779
+ */
12605
12780
  async getCurrentMessages() {
12606
12781
  const state = await this.getCurrentState();
12607
12782
  const messages = state.values.messages || [];
@@ -12624,6 +12799,14 @@ var Agent = class {
12624
12799
  const image = await drawableGraph.drawMermaid();
12625
12800
  return image;
12626
12801
  }
12802
+ /**
12803
+ * Determine the current thread execution status.
12804
+ *
12805
+ * Checks LangGraph's `state.tasks` for interrupts and `state.next` for
12806
+ * pending steps.
12807
+ *
12808
+ * @returns {@link ThreadStatus} — `IDLE`, `BUSY`, or `INTERRUPTED`
12809
+ */
12627
12810
  async getRunStatus() {
12628
12811
  const state = await this.getCurrentState();
12629
12812
  const isInterrupted = state.tasks?.some(
@@ -12638,9 +12821,14 @@ var Agent = class {
12638
12821
  return "idle" /* IDLE */;
12639
12822
  }
12640
12823
  /**
12641
- * Resume task processing after server restart
12642
- * Resets any stuck processing messages to pending and starts queue processing
12643
- * Note: Does not rely on LangGraph state as it may be stale after crash/restart
12824
+ * Resume processing after a server restart.
12825
+ *
12826
+ * Resets any stuck "processing" messages back to "pending" and restarts the
12827
+ * queue processor. Skips threads that are in `INTERRUPTED` state (the
12828
+ * interruption was intentional).
12829
+ *
12830
+ * Called during gateway startup to recover threads that were mid-execution
12831
+ * when the server went down.
12644
12832
  */
12645
12833
  async resumeTask() {
12646
12834
  try {
@@ -12662,9 +12850,14 @@ var Agent = class {
12662
12850
  await this.startQueueProcessorIfNeeded();
12663
12851
  }
12664
12852
  /**
12665
- * Abort the current agent execution
12666
- * This will cancel any ongoing invoke or stream operations
12667
- * and clear all queued messages (pending + processing)
12853
+ * Fully abort all activity on this thread.
12854
+ *
12855
+ * Aborts any in-flight agent execution (via {@link AbortController}) and
12856
+ * clears all pending and processing messages from the queue. Also marks
12857
+ * the chunk buffer thread as aborted so streaming consumers can detect it.
12858
+ *
12859
+ * Unlike {@link stopQueueProcessor}, this is a destructive abort — the
12860
+ * queue is drained.
12668
12861
  */
12669
12862
  async abort() {
12670
12863
  if (this.abortController) {
@@ -12682,22 +12875,44 @@ var Agent = class {
12682
12875
  return this.abortController?.signal.aborted ?? false;
12683
12876
  }
12684
12877
  /**
12685
- * Subscribe to lifecycle events for this agent/thread
12686
- * Events are automatically namespaced by tenantId and threadId
12878
+ * Subscribe to a lifecycle event for this specific thread.
12879
+ *
12880
+ * Event names are namespaced as `{eventName}:{tenantId}:{threadId}` so
12881
+ * listeners only receive events for this agent instance.
12882
+ *
12883
+ * @param eventName - One of {@link AgentLifecycleEventName}
12884
+ * @param callback - Handler receiving the event data payload
12885
+ *
12886
+ * @example
12887
+ * ```ts
12888
+ * agent.subscribe("message:completed", (evt) => {
12889
+ * console.log("AI response:", evt.state?.values?.messages);
12890
+ * });
12891
+ * ```
12687
12892
  */
12688
12893
  subscribe(eventName, callback) {
12689
12894
  const namespacedEvent = `${eventName}:${this.tenant_id}:${this.thread_id}`;
12690
12895
  event_bus_default.subscribe(namespacedEvent, callback);
12691
12896
  }
12692
12897
  /**
12693
- * Unsubscribe from lifecycle events
12898
+ * Remove a previously registered event listener.
12899
+ *
12900
+ * @param eventName - The event that was subscribed to
12901
+ * @param callback - The same function reference used in {@link subscribe}
12694
12902
  */
12695
12903
  unsubscribe(eventName, callback) {
12696
12904
  const namespacedEvent = `${eventName}:${this.tenant_id}:${this.thread_id}`;
12697
12905
  event_bus_default.unsubscribe(namespacedEvent, callback);
12698
12906
  }
12699
12907
  /**
12700
- * Subscribe to lifecycle events once (auto-unsubscribe after first event)
12908
+ * Subscribe to a lifecycle event once the listener is removed after the
12909
+ * first invocation.
12910
+ *
12911
+ * Ideal for one-shot async patterns (e.g. waiting for `reply:ready` before
12912
+ * sending a channel reply).
12913
+ *
12914
+ * @param eventName - One of {@link AgentLifecycleEventName}
12915
+ * @param callback - Handler receiving the event data payload
12701
12916
  */
12702
12917
  subscribeOnce(eventName, callback) {
12703
12918
  const namespacedEvent = `${eventName}:${this.tenant_id}:${this.thread_id}`;
@@ -12711,6 +12926,12 @@ var Agent = class {
12711
12926
  console.log(namespacedEvent);
12712
12927
  event_bus_default.publish(namespacedEvent, data);
12713
12928
  }
12929
+ /**
12930
+ * Track a sub-agent async task spawned by this agent.
12931
+ *
12932
+ * Tasks are monitored by the agent task consumer in `packages/gateway`
12933
+ * and their status can be polled via {@link getAsyncTasks}.
12934
+ */
12714
12935
  addAsyncTask(task) {
12715
12936
  this.asyncTasks.push(task);
12716
12937
  }
@@ -12720,6 +12941,12 @@ var Agent = class {
12720
12941
  getAsyncTask(taskId) {
12721
12942
  return this.asyncTasks.find((t) => t.taskId === taskId);
12722
12943
  }
12944
+ /**
12945
+ * Update the status of a tracked async task.
12946
+ *
12947
+ * Terminal states (`completed`, `failed`, `cancelled`) automatically
12948
+ * set `completedAt` to the current timestamp.
12949
+ */
12723
12950
  updateAsyncTaskStatus(taskId, status) {
12724
12951
  const task = this.getAsyncTask(taskId);
12725
12952
  if (!task) return;
@@ -13085,6 +13312,65 @@ function createSchedulerMiddleware(options = {}) {
13085
13312
  });
13086
13313
  }
13087
13314
 
13315
+ // src/agent_lattice/builders/CustomMiddlewareRegistry.ts
13316
+ var CustomMiddlewareRegistry = class {
13317
+ /**
13318
+ * Register a custom middleware factory under the given key.
13319
+ *
13320
+ * The key is referenced by `config.key` in the database middleware configuration.
13321
+ * When an agent is built, the framework looks up this key and calls the factory
13322
+ * with the remaining config fields.
13323
+ *
13324
+ * @param key - Unique identifier, referenced in database config as `config.key`
13325
+ * @param factory - Function that receives config (minus `key`) and returns an AgentMiddleware
13326
+ *
13327
+ * @example
13328
+ * ```ts
13329
+ * CustomMiddlewareRegistry.register("my-logger", (config) =>
13330
+ * createMiddleware({ name: "Logger", beforeAgent: async () => { ... } }),
13331
+ * );
13332
+ * ```
13333
+ */
13334
+ static register(key, factory) {
13335
+ this.factories.set(key, factory);
13336
+ }
13337
+ /**
13338
+ * Remove a previously registered factory.
13339
+ *
13340
+ * @param key - The factory key to unregister
13341
+ * @returns `true` if a factory was removed, `false` if the key was not found
13342
+ */
13343
+ static unregister(key) {
13344
+ return this.factories.delete(key);
13345
+ }
13346
+ /**
13347
+ * Look up a factory by key.
13348
+ *
13349
+ * @param key - The factory key
13350
+ * @returns The factory function, or `undefined` if not registered
13351
+ */
13352
+ static get(key) {
13353
+ return this.factories.get(key);
13354
+ }
13355
+ /**
13356
+ * Check whether a factory is registered under the given key.
13357
+ *
13358
+ * @param key - The factory key to check
13359
+ */
13360
+ static has(key) {
13361
+ return this.factories.has(key);
13362
+ }
13363
+ /**
13364
+ * Get all currently registered factory keys.
13365
+ *
13366
+ * @returns Array of registered key strings
13367
+ */
13368
+ static list() {
13369
+ return Array.from(this.factories.keys());
13370
+ }
13371
+ };
13372
+ CustomMiddlewareRegistry.factories = /* @__PURE__ */ new Map();
13373
+
13088
13374
  // src/agent_lattice/builders/commonMiddleware.ts
13089
13375
  async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsIsExised) {
13090
13376
  const middlewares = [];
@@ -13161,6 +13447,21 @@ async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsI
13161
13447
  case "scheduler":
13162
13448
  middlewares.push(createSchedulerMiddleware(config.config));
13163
13449
  break;
13450
+ case "custom":
13451
+ {
13452
+ const customConfig = config.config;
13453
+ const { key, ...rest } = customConfig;
13454
+ const factory = CustomMiddlewareRegistry.get(key);
13455
+ if (factory) {
13456
+ const middleware = factory(rest);
13457
+ middlewares.push(middleware instanceof Promise ? await middleware : middleware);
13458
+ } else {
13459
+ console.warn(
13460
+ `[custom middleware] No factory registered for key "${key}". Use CustomMiddlewareRegistry.register("${key}", factory) before building the agent.`
13461
+ );
13462
+ }
13463
+ }
13464
+ break;
13164
13465
  }
13165
13466
  }
13166
13467
  return middlewares;
@@ -17934,6 +18235,75 @@ function mergeAgentConfig(parent, child) {
17934
18235
  return merged;
17935
18236
  }
17936
18237
 
18238
+ // src/store_lattice/configureStores.ts
18239
+ var _disposables = [];
18240
+ var _cleanupRegistered = false;
18241
+ function registerSignalCleanup() {
18242
+ if (_cleanupRegistered) return;
18243
+ _cleanupRegistered = true;
18244
+ for (const sig of ["SIGINT", "SIGTERM"]) {
18245
+ process.once(sig, async () => {
18246
+ for (const s of _disposables) {
18247
+ if (s.dispose) await s.dispose();
18248
+ }
18249
+ });
18250
+ }
18251
+ }
18252
+ async function initAndRegister(store, localDisposables) {
18253
+ const initStore = store;
18254
+ if (typeof initStore.initialize === "function" && initStore.initialize.length === 0) {
18255
+ await initStore.initialize();
18256
+ }
18257
+ const dispStore = store;
18258
+ if (typeof dispStore.dispose === "function") {
18259
+ localDisposables.push(dispStore);
18260
+ }
18261
+ }
18262
+ async function configureStores(stores, options = {}) {
18263
+ const localDisposables = [];
18264
+ const { schedule, checkpoint, ...regularStores } = stores;
18265
+ for (const [type, store] of Object.entries(regularStores)) {
18266
+ await initAndRegister(store, localDisposables);
18267
+ if (storeLatticeManager.hasLattice("default", type)) {
18268
+ storeLatticeManager.removeLattice("default", type);
18269
+ }
18270
+ storeLatticeManager.registerLattice("default", type, store);
18271
+ }
18272
+ if (schedule !== void 0) {
18273
+ await initAndRegister(schedule, localDisposables);
18274
+ const scheduleConfig = {
18275
+ name: "Default Scheduler",
18276
+ description: "Auto-configured schedule storage",
18277
+ type: "postgres",
18278
+ storage: schedule
18279
+ };
18280
+ registerScheduleLattice("default", scheduleConfig);
18281
+ }
18282
+ if (checkpoint !== void 0) {
18283
+ MemoryLatticeManager.getInstance().removeCheckpointSaver("default");
18284
+ registerCheckpointSaver("default", checkpoint);
18285
+ }
18286
+ if (options.customStores) {
18287
+ for (const [type, store] of Object.entries(options.customStores)) {
18288
+ await initAndRegister(store, localDisposables);
18289
+ const t = type;
18290
+ if (storeLatticeManager.hasLattice("default", t)) {
18291
+ storeLatticeManager.removeLattice("default", t);
18292
+ }
18293
+ storeLatticeManager.registerLattice("default", t, store);
18294
+ }
18295
+ }
18296
+ if (options.autoDisposeStores) {
18297
+ registerSignalCleanup();
18298
+ _disposables.push(...localDisposables);
18299
+ }
18300
+ return async () => {
18301
+ for (const s of localDisposables.reverse()) {
18302
+ if (s.dispose) await s.dispose();
18303
+ }
18304
+ };
18305
+ }
18306
+
17937
18307
  // src/store_lattice/SandboxSkillStore.ts
17938
18308
  function parseFrontmatter2(content) {
17939
18309
  const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
@@ -22468,6 +22838,7 @@ export {
22468
22838
  CompositeBackend,
22469
22839
  ConsoleLoggerClient,
22470
22840
  CustomMetricsClient,
22841
+ CustomMiddlewareRegistry,
22471
22842
  DaytonaInstance,
22472
22843
  DaytonaProvider,
22473
22844
  DefaultScheduleClient,
@@ -22541,6 +22912,7 @@ export {
22541
22912
  checkEmptyContent,
22542
22913
  clearEncryptionKeyCache,
22543
22914
  computeSandboxName,
22915
+ configureStores,
22544
22916
  createAgentTeam,
22545
22917
  createExecuteSqlQueryTool,
22546
22918
  createFileData,