@axiom-lattice/gateway 2.1.87 → 2.1.89

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
@@ -1649,7 +1649,7 @@ async function executeDataQuery(request, reply) {
1649
1649
  message: `Metrics server not registered: ${body.serverKey}. Please register the server first.`
1650
1650
  };
1651
1651
  }
1652
- const client = metricsServerManager.getClient(tenantId, body.serverKey);
1652
+ const client = await metricsServerManager.getClient(tenantId, body.serverKey);
1653
1653
  if (isSemanticQuery) {
1654
1654
  return await executeSemanticQuery(client, body, reply);
1655
1655
  } else {
@@ -3856,7 +3856,7 @@ async function testMetricsServerConnection(request, reply) {
3856
3856
  const testKey = `__test_${key}_${Date.now()}`;
3857
3857
  metricsServerManager2.registerServer(tenantId, testKey, config.config);
3858
3858
  try {
3859
- const client = metricsServerManager2.getClient(tenantId, testKey);
3859
+ const client = await metricsServerManager2.getClient(tenantId, testKey);
3860
3860
  const result = await client.testConnection();
3861
3861
  metricsServerManager2.removeServer(tenantId, testKey);
3862
3862
  return {
@@ -3907,7 +3907,7 @@ async function listAvailableMetrics(request, reply) {
3907
3907
  if (!metricsServerManager2.hasServer(tenantId, key)) {
3908
3908
  metricsServerManager2.registerServer(tenantId, key, config.config);
3909
3909
  }
3910
- const client = metricsServerManager2.getClient(tenantId, key);
3910
+ const client = await metricsServerManager2.getClient(tenantId, key);
3911
3911
  const metrics = await client.listMetrics();
3912
3912
  return {
3913
3913
  success: true,
@@ -3953,7 +3953,7 @@ async function queryMetricsData(request, reply) {
3953
3953
  if (!metricsServerManager2.hasServer(tenantId, key)) {
3954
3954
  metricsServerManager2.registerServer(tenantId, key, config.config);
3955
3955
  }
3956
- const client = metricsServerManager2.getClient(tenantId, key);
3956
+ const client = await metricsServerManager2.getClient(tenantId, key);
3957
3957
  const result = await client.queryMetricData(metricName, {
3958
3958
  startTime,
3959
3959
  endTime,
@@ -6299,19 +6299,8 @@ function registerChannelInstallationRoutes(app2) {
6299
6299
  app2.delete("/api/channel-installations/:installationId", deleteChannelInstallation);
6300
6300
  }
6301
6301
 
6302
- // src/bindings/index.ts
6303
- var registryInstance = null;
6304
- function setBindingRegistry(registry) {
6305
- registryInstance = registry;
6306
- }
6307
- function getBindingRegistry() {
6308
- if (!registryInstance) {
6309
- throw new Error("BindingRegistry not initialized. Call setBindingRegistry() first.");
6310
- }
6311
- return registryInstance;
6312
- }
6313
-
6314
6302
  // src/controllers/channel-bindings.ts
6303
+ import { getBindingRegistry } from "@axiom-lattice/core";
6315
6304
  function getTenantId12(request) {
6316
6305
  const userTenantId = request.user?.tenantId;
6317
6306
  if (userTenantId) return userTenantId;
@@ -6648,14 +6637,39 @@ var BindingNotFoundError = class extends Error {
6648
6637
  };
6649
6638
  var MessageRouter = class {
6650
6639
  constructor(config) {
6640
+ /**
6641
+ * Tracks reply subscriptions per thread+channel to avoid duplicate
6642
+ * `subscribeOnce` registrations and ensure proper cleanup.
6643
+ *
6644
+ * Key format: `{threadId}:{adapterChannel}:reply`
6645
+ */
6646
+ this._replySubs = /* @__PURE__ */ new Map();
6651
6647
  this.middlewares = [...config.middlewares];
6652
6648
  this.bindingRegistry = config.bindingRegistry;
6653
6649
  this.adapterRegistry = config.adapterRegistry;
6654
6650
  this.installationStore = config.installationStore;
6655
6651
  }
6652
+ /**
6653
+ * Register an additional middleware at the end of the chain.
6654
+ *
6655
+ * @param middleware - A {@link MessageMiddleware} function
6656
+ */
6656
6657
  use(middleware) {
6657
6658
  this.middlewares.push(middleware);
6658
6659
  }
6660
+ /**
6661
+ * Dispatch an inbound channel message to the bound agent.
6662
+ *
6663
+ * Full pipeline: middleware chain → binding resolution → thread lifecycle
6664
+ * → agent.addMessage() → (async) reply via {@link ChannelAdapter.sendReply}.
6665
+ *
6666
+ * If the message has a {@link InboundMessage.replyTarget}, the router subscribes
6667
+ * to the agent's `reply:ready` event before enqueuing the message, and sends
6668
+ * the AI response back to the channel when it arrives.
6669
+ *
6670
+ * @param message - Normalized inbound message from a channel adapter
6671
+ * @returns {@link DispatchResult} with success status, bindingId, and threadId
6672
+ */
6659
6673
  async dispatch(message) {
6660
6674
  const ctx = {
6661
6675
  inboundMessage: message,
@@ -6802,32 +6816,96 @@ var MessageRouter = class {
6802
6816
  workspace_id: ctx.binding.workspaceId || "",
6803
6817
  project_id: ctx.binding.projectId || ""
6804
6818
  });
6805
- const addResult = await agent.addMessage({
6806
- input: { message: message.content.text },
6807
- custom_run_config: message.content.metadata || {}
6808
- });
6809
- console.log({
6810
- event: "dispatch:complete",
6811
- agentId: ctx.binding.agentId,
6812
- threadId,
6813
- messageId: addResult?.messageId,
6814
- result: JSON.stringify(addResult)
6815
- }, "Agent dispatch complete \u2014 messageId = " + (addResult?.messageId || "N/A"));
6816
6819
  if (message.replyTarget) {
6820
+ const replySubKey = `${threadId}:${message.replyTarget.adapterChannel}:reply`;
6817
6821
  const adapter = this.adapterRegistry.get(message.replyTarget.adapterChannel);
6818
6822
  if (adapter) {
6819
6823
  const installation = await this.installationStore.getInstallationById(
6820
6824
  message.channelInstallationId
6821
6825
  );
6822
6826
  if (installation) {
6823
- await adapter.sendReply(
6824
- message.replyTarget,
6825
- { text: ctx.result || "" },
6826
- installation
6827
- );
6827
+ const existing = this._replySubs.get(replySubKey);
6828
+ if (!existing || existing.count === 0) {
6829
+ const timer = setTimeout(() => {
6830
+ const entry = this._replySubs.get(replySubKey);
6831
+ if (entry) {
6832
+ this._replySubs.delete(replySubKey);
6833
+ console.warn({
6834
+ event: "dispatch:reply:timeout",
6835
+ threadId,
6836
+ channel: message.replyTarget.adapterChannel
6837
+ }, "Reply subscription timed out \u2014 no reply:ready fired within 1h");
6838
+ }
6839
+ }, 36e5);
6840
+ this._replySubs.set(replySubKey, { count: 1, timer });
6841
+ console.log({
6842
+ event: "dispatch:reply:subscribed",
6843
+ threadId,
6844
+ channel: message.replyTarget.adapterChannel,
6845
+ senderId: message.sender.id
6846
+ }, "Subscribed to reply:ready for thread");
6847
+ agent.subscribeOnce("reply:ready", (data) => {
6848
+ const messages = data.state?.values?.messages;
6849
+ const lastAI = messages?.filter((m) => m.type === "ai" || m.getType?.() === "ai").pop();
6850
+ const replyText = lastAI?.content ?? "";
6851
+ const entry = this._replySubs.get(replySubKey);
6852
+ if (entry) {
6853
+ entry.count--;
6854
+ if (entry.count <= 0) {
6855
+ clearTimeout(entry.timer);
6856
+ this._replySubs.delete(replySubKey);
6857
+ }
6858
+ }
6859
+ if (replyText) {
6860
+ console.log({
6861
+ event: "dispatch:reply:sending",
6862
+ threadId,
6863
+ channel: message.replyTarget.adapterChannel,
6864
+ replyLength: replyText.length
6865
+ }, "Sending channel reply");
6866
+ adapter.sendReply(message.replyTarget, { text: replyText }, installation).then(() => {
6867
+ console.log({
6868
+ event: "dispatch:reply:sent",
6869
+ threadId,
6870
+ channel: message.replyTarget.adapterChannel
6871
+ }, "Channel reply sent successfully");
6872
+ }).catch((err) => console.error({
6873
+ event: "dispatch:reply:failed",
6874
+ threadId,
6875
+ channel: message.replyTarget.adapterChannel,
6876
+ error: err instanceof Error ? err.message : String(err)
6877
+ }, "Failed to send channel reply"));
6878
+ } else {
6879
+ console.warn({
6880
+ event: "dispatch:reply:empty",
6881
+ threadId,
6882
+ channel: message.replyTarget.adapterChannel
6883
+ }, "Agent produced no text output \u2014 skipping reply");
6884
+ }
6885
+ });
6886
+ } else {
6887
+ existing.count++;
6888
+ console.log({
6889
+ event: "dispatch:reply:incremented",
6890
+ threadId,
6891
+ channel: message.replyTarget.adapterChannel,
6892
+ count: existing.count
6893
+ }, "Incremented reply counter for thread (already subscribed)");
6894
+ }
6828
6895
  }
6829
6896
  }
6830
6897
  }
6898
+ const addResult = await agent.addMessage({
6899
+ input: { message: message.content.text },
6900
+ custom_run_config: message.replyTarget ? { ...message.content.metadata || {}, _replyTarget: message.replyTarget } : message.content.metadata || {}
6901
+ });
6902
+ console.log({
6903
+ event: "dispatch:complete",
6904
+ agentId: ctx.binding.agentId,
6905
+ threadId,
6906
+ messageId: addResult?.messageId,
6907
+ result: JSON.stringify(addResult)
6908
+ }, "Agent dispatch complete \u2014 messageId = " + (addResult?.messageId || "N/A"));
6831
6909
  });
6832
6910
  return {
6833
6911
  success: true,
@@ -6975,7 +7053,7 @@ function createAuditLoggerMiddleware() {
6975
7053
  }
6976
7054
 
6977
7055
  // src/index.ts
6978
- import { setBindingRegistry as setCoreBindingRegistry } from "@axiom-lattice/core";
7056
+ import { setBindingRegistry } from "@axiom-lattice/core";
6979
7057
 
6980
7058
  // src/swagger.ts
6981
7059
  import swagger from "@fastify/swagger";
@@ -7303,8 +7381,6 @@ import {
7303
7381
  getLoggerLattice,
7304
7382
  loggerLatticeManager,
7305
7383
  sandboxLatticeManager as sandboxLatticeManager2,
7306
- sqlDatabaseManager as sqlDatabaseManager2,
7307
- getStoreLattice as getStoreLattice15,
7308
7384
  agentInstanceManager as agentInstanceManager8,
7309
7385
  createSandboxProvider
7310
7386
  } from "@axiom-lattice/core";
@@ -7464,7 +7540,6 @@ var start = async (config) => {
7464
7540
  const bindingStore = getStoreLattice16("default", "channelBinding").store;
7465
7541
  const installationStore = getStoreLattice16("default", "channelInstallation").store;
7466
7542
  setBindingRegistry(bindingStore);
7467
- setCoreBindingRegistry(bindingStore);
7468
7543
  const adapterRegistry = new ChannelAdapterRegistry();
7469
7544
  adapterRegistry.register(larkChannelAdapter);
7470
7545
  const router = new MessageRouter({
@@ -7481,14 +7556,6 @@ var start = async (config) => {
7481
7556
  } catch {
7482
7557
  }
7483
7558
  registerLatticeRoutes(app, channelDeps);
7484
- try {
7485
- const storeLattice = getStoreLattice15("default", "database");
7486
- const store = storeLattice.store;
7487
- sqlDatabaseManager2.setConfigStore(store);
7488
- logger3.info("Database config store set for SqlDatabaseManager");
7489
- } catch (error) {
7490
- logger3.warn("Failed to set database config store: " + (error instanceof Error ? error.message : String(error)));
7491
- }
7492
7559
  if (!sandboxLatticeManager2.hasLattice("default")) {
7493
7560
  sandboxLatticeManager2.registerLattice("default", getConfiguredSandboxProvider());
7494
7561
  logger3.info("Registered sandbox manager from env configuration");