@axiom-lattice/gateway 6.0.1 → 6.1.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.
Files changed (26) hide show
  1. package/dist/embed/{embed-page-AgentDetailSideApp-JYVZKSUU.js → embed-page-AgentDetailSideApp-2UFH4RJG.js} +1 -1
  2. package/dist/embed/{embed-page-AgentGovernanceWorkbench-SD2EHW2B.js → embed-page-AgentGovernanceWorkbench-3JOSRW2V.js} +1 -1
  3. package/dist/embed/{embed-page-MessageGraph-GLQXKAVC.js → embed-page-MessageGraph-SPB75EHC.js} +1 -1
  4. package/dist/embed/{embed-page-ReactChart-74MHCE2K.js → embed-page-ReactChart-EE4A5WKS.js} +1 -1
  5. package/dist/embed/{embed-page-SkillFlow-NDAK3GAD.js → embed-page-SkillFlow-H2ARZGEX.js} +1 -1
  6. package/dist/embed/{embed-page-TasksSideApp-DA4LUTMD.js → embed-page-TasksSideApp-BQMOLOUF.js} +1 -1
  7. package/dist/embed/{embed-page-TeamWorkspace-DUB3L6V6.js → embed-page-TeamWorkspace-QXMRVXWU.js} +1 -1
  8. package/dist/embed/{embed-page-TopologyRuntimeView-NFBHAICN.js → embed-page-TopologyRuntimeView-OSV75P6Y.js} +1 -1
  9. package/dist/embed/{embed-page-WorkflowAutomationView-43YGTXGF.js → embed-page-WorkflowAutomationView-KJ6HJ5UT.js} +1 -1
  10. package/dist/embed/{embed-page-chunk-UHH575CK.js → embed-page-chunk-DBUC6J4G.js} +1 -1
  11. package/dist/embed/{embed-page-chunk-C4ZV4IXK.js → embed-page-chunk-E6F5YZBR.js} +1 -1
  12. package/dist/embed/{embed-page-chunk-BVSC3MSO.js → embed-page-chunk-FGKHXQAJ.js} +1 -1
  13. package/dist/embed/{embed-page-chunk-2PFKLMTR.js → embed-page-chunk-GSCVATOA.js} +1 -1
  14. package/dist/embed/{embed-page-chunk-GKHIPXZ2.js → embed-page-chunk-IIEDLN7W.js} +1 -1
  15. package/dist/embed/{embed-page-chunk-P477ZTUO.js → embed-page-chunk-U4XSGC4Y.js} +163 -163
  16. package/dist/embed/{embed-page-chunk-DWIBLGBW.js → embed-page-chunk-VXWRPT33.js} +1 -1
  17. package/dist/embed/{embed-page-en-S4MXFPIU.js → embed-page-en-X6B6RVNL.js} +1 -1
  18. package/dist/embed/{embed-page-zh-SSMSF5LE.js → embed-page-zh-EQ5X2M32.js} +1 -1
  19. package/dist/embed/embed-page.js +1 -1
  20. package/dist/index.d.mts +43 -8
  21. package/dist/index.d.ts +43 -8
  22. package/dist/index.js +1117 -365
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs +907 -148
  25. package/dist/index.mjs.map +1 -1
  26. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -1445,11 +1445,11 @@ async function resolveAgentOpenGrants(tenantId, assistantId, deps) {
1445
1445
  }
1446
1446
  }
1447
1447
  function createDefaultAgentReflectionDeps(tenantId) {
1448
- (0, import_core74.ensureBuiltinAgentsForTenant)(tenantId);
1448
+ (0, import_core75.ensureBuiltinAgentsForTenant)(tenantId);
1449
1449
  return {
1450
- ensure: (t2) => import_core74.agentLatticeManager.initializeStoredAssistantsForTenant(t2),
1450
+ ensure: (t2) => import_core75.agentLatticeManager.initializeStoredAssistantsForTenant(t2),
1451
1451
  getAgentConfig: (t2, assistantId) => {
1452
- const config = import_core74.agentLatticeManager.getAgentConfigWithTenant(t2, assistantId);
1452
+ const config = import_core75.agentLatticeManager.getAgentConfigWithTenant(t2, assistantId);
1453
1453
  if (!config) return void 0;
1454
1454
  return {
1455
1455
  middleware: extractMiddleware(config),
@@ -1457,16 +1457,16 @@ function createDefaultAgentReflectionDeps(tenantId) {
1457
1457
  };
1458
1458
  },
1459
1459
  getAssistantMiddleware: async (t2, assistantId) => {
1460
- const store2 = (0, import_core74.getStoreLattice)("default", "assistant").store;
1460
+ const store2 = (0, import_core75.getStoreLattice)("default", "assistant").store;
1461
1461
  const assistant = await store2.getAssistantById(t2, assistantId);
1462
1462
  return extractMiddleware(assistant?.graphDefinition);
1463
1463
  },
1464
1464
  exposedActionsByType: (type) => {
1465
- const plugin = import_core74.PluginRegistry.get(type);
1465
+ const plugin = import_core75.PluginRegistry.get(type);
1466
1466
  return plugin ? normalizeOpenExpose(plugin.meta.openExpose) : [];
1467
1467
  },
1468
1468
  resolvableAssistants: async (t2) => new Set(
1469
- import_core74.agentLatticeManager.getAllAgentLatticesByTenant(t2).map((lattice) => lattice.config.key)
1469
+ import_core75.agentLatticeManager.getAllAgentLatticesByTenant(t2).map((lattice) => lattice.config.key)
1470
1470
  )
1471
1471
  };
1472
1472
  }
@@ -1538,30 +1538,30 @@ function buildTenantExposedGrants(manifests) {
1538
1538
  }
1539
1539
  function createDefaultPluginReflectionDeps() {
1540
1540
  return {
1541
- ensure: (tenantId) => import_core74.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId),
1541
+ ensure: (tenantId) => import_core75.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId),
1542
1542
  globalExposedDomains: () => {
1543
1543
  const grants = [];
1544
- for (const type of import_core74.PluginRegistry.list()) {
1545
- const plugin = import_core74.PluginRegistry.get(type);
1544
+ for (const type of import_core75.PluginRegistry.list()) {
1545
+ const plugin = import_core75.PluginRegistry.get(type);
1546
1546
  const items = normalizeOpenExpose(plugin?.meta.openExpose);
1547
1547
  if (items.length > 0) grants.push({ domain: type, items });
1548
1548
  }
1549
1549
  return grants;
1550
1550
  },
1551
1551
  tenantExposedDomains: async (tenantId) => {
1552
- const { manifests } = await (0, import_core74.getSandboxPluginCatalog)().ensureLoaded(tenantId);
1552
+ const { manifests } = await (0, import_core75.getSandboxPluginCatalog)().ensureLoaded(tenantId);
1553
1553
  return buildTenantExposedGrants(Object.values(manifests));
1554
1554
  },
1555
1555
  resolvableAssistants: async (tenantId) => new Set(
1556
- import_core74.agentLatticeManager.getAllAgentLatticesByTenant(tenantId).map((lattice) => lattice.config.key)
1556
+ import_core75.agentLatticeManager.getAllAgentLatticesByTenant(tenantId).map((lattice) => lattice.config.key)
1557
1557
  )
1558
1558
  };
1559
1559
  }
1560
- var import_core74, AGENT_REFLECTION_CACHE_TTL_MS, cache, PLUGIN_REFLECTION_CACHE_TTL_MS, pluginCache;
1560
+ var import_core75, AGENT_REFLECTION_CACHE_TTL_MS, cache, PLUGIN_REFLECTION_CACHE_TTL_MS, pluginCache;
1561
1561
  var init_sandboxOpenReflection = __esm({
1562
1562
  "src/services/open/sandboxOpenReflection.ts"() {
1563
1563
  "use strict";
1564
- import_core74 = require("@axiom-lattice/core");
1564
+ import_core75 = require("@axiom-lattice/core");
1565
1565
  AGENT_REFLECTION_CACHE_TTL_MS = 6e4;
1566
1566
  cache = /* @__PURE__ */ new Map();
1567
1567
  PLUGIN_REFLECTION_CACHE_TTL_MS = 6e4;
@@ -1608,7 +1608,7 @@ function outcome(task) {
1608
1608
  });
1609
1609
  }
1610
1610
  async function backfillTopCallerGroup(tasks, top, deps) {
1611
- const registry = deps.registry ?? import_core77.taskRunRegistry;
1611
+ const registry = deps.registry ?? import_core78.taskRunRegistry;
1612
1612
  const results = [];
1613
1613
  const eligible = [];
1614
1614
  for (const task of tasks) {
@@ -1662,11 +1662,11 @@ async function recoverTask(task, deps) {
1662
1662
  if (task.status !== "in_progress") {
1663
1663
  return { kind: "skipped", reason: "not_in_progress" };
1664
1664
  }
1665
- const registry = deps.registry ?? import_core77.taskRunRegistry;
1665
+ const registry = deps.registry ?? import_core78.taskRunRegistry;
1666
1666
  if (registry.isLive(task.id) || deps.isTaskLive && await deps.isTaskLive(task)) {
1667
1667
  return { kind: "skipped", reason: "live" };
1668
1668
  }
1669
- const { convergedTasks } = await (0, import_core77.reconcileStaleTaskRuns)({
1669
+ const { convergedTasks } = await (0, import_core78.reconcileStaleTaskRuns)({
1670
1670
  tasks: [task],
1671
1671
  actor: "system:on-demand-recovery",
1672
1672
  lifecycle: deps.lifecycle,
@@ -1762,30 +1762,30 @@ async function runOrphanRecovery(deps) {
1762
1762
  deps.log.info("Task orphan recovery complete", { recovered, skipped });
1763
1763
  return { recovered, skipped };
1764
1764
  }
1765
- var import_messages, import_core77;
1765
+ var import_messages, import_core78;
1766
1766
  var init_TopCallerRecovery = __esm({
1767
1767
  "src/services/collaboration/TopCallerRecovery.ts"() {
1768
1768
  "use strict";
1769
1769
  import_messages = require("@langchain/core/messages");
1770
- import_core77 = require("@axiom-lattice/core");
1770
+ import_core78 = require("@axiom-lattice/core");
1771
1771
  }
1772
1772
  });
1773
1773
 
1774
1774
  // src/services/collaboration/taskRunLiveness.ts
1775
1775
  function createTaskRunLiveness() {
1776
1776
  try {
1777
- import_core78.storeLatticeManager.getStoreLattice("default", "lease");
1777
+ import_core79.storeLatticeManager.getStoreLattice("default", "lease");
1778
1778
  } catch {
1779
1779
  return void 0;
1780
1780
  }
1781
- return (task) => (0, import_core79.isTaskRunLeaseHeld)(task);
1781
+ return (task) => (0, import_core80.isTaskRunLeaseHeld)(task);
1782
1782
  }
1783
- var import_core78, import_core79;
1783
+ var import_core79, import_core80;
1784
1784
  var init_taskRunLiveness = __esm({
1785
1785
  "src/services/collaboration/taskRunLiveness.ts"() {
1786
1786
  "use strict";
1787
- import_core78 = require("@axiom-lattice/core");
1788
1787
  import_core79 = require("@axiom-lattice/core");
1788
+ import_core80 = require("@axiom-lattice/core");
1789
1789
  }
1790
1790
  });
1791
1791
 
@@ -1795,7 +1795,7 @@ __export(OrphanRecoveryRuntime_exports, {
1795
1795
  createOrphanRecoveryRuntime: () => createOrphanRecoveryRuntime
1796
1796
  });
1797
1797
  function createOrphanRecoveryRuntime(deps) {
1798
- const lifecycle = deps.lifecycle ?? (0, import_core80.createTaskLifecycleService)({
1798
+ const lifecycle = deps.lifecycle ?? (0, import_core81.createTaskLifecycleService)({
1799
1799
  taskStore: deps.taskStore,
1800
1800
  workItemStore: deps.workItemStore
1801
1801
  });
@@ -1803,7 +1803,7 @@ function createOrphanRecoveryRuntime(deps) {
1803
1803
  async recoverAll() {
1804
1804
  const isTaskLive = deps.isTaskLive ?? createTaskRunLiveness();
1805
1805
  return runOrphanRecovery({
1806
- reconcile: () => (0, import_core80.reconcileAllTenantTaskRuns)({
1806
+ reconcile: () => (0, import_core81.reconcileAllTenantTaskRuns)({
1807
1807
  actor: "system:orphan-recovery",
1808
1808
  tenantStore: {
1809
1809
  listTenants: async () => (await deps.tenantStore.getAllTenants()).map((tenant2) => ({ id: tenant2.id }))
@@ -1829,7 +1829,7 @@ function createOrphanRecoveryRuntime(deps) {
1829
1829
  const isTaskLive = deps.isTaskLive ?? createTaskRunLiveness();
1830
1830
  return recoverTask(task, {
1831
1831
  lifecycle,
1832
- registry: import_core80.taskRunRegistry,
1832
+ registry: import_core81.taskRunRegistry,
1833
1833
  orphans,
1834
1834
  callerFor: deps.callerFor,
1835
1835
  resume: deps.resume,
@@ -1838,11 +1838,11 @@ function createOrphanRecoveryRuntime(deps) {
1838
1838
  }
1839
1839
  };
1840
1840
  }
1841
- var import_core80;
1841
+ var import_core81;
1842
1842
  var init_OrphanRecoveryRuntime = __esm({
1843
1843
  "src/services/collaboration/OrphanRecoveryRuntime.ts"() {
1844
1844
  "use strict";
1845
- import_core80 = require("@axiom-lattice/core");
1845
+ import_core81 = require("@axiom-lattice/core");
1846
1846
  init_TopCallerRecovery();
1847
1847
  init_projectTaskScope();
1848
1848
  init_taskRunLiveness();
@@ -1858,12 +1858,12 @@ function createRecoveryCallerDeps() {
1858
1858
  return {
1859
1859
  callerFor: async (top, tenantId) => {
1860
1860
  if (!top.assistantId) return void 0;
1861
- const load = import_core81.getAgentClientAsync ?? import_core81.getAgentClient;
1861
+ const load = import_core82.getAgentClientAsync ?? import_core82.getAgentClient;
1862
1862
  const client = await load(tenantId, top.assistantId);
1863
1863
  const config = { configurable: { thread_id: top.threadId, runConfig: { tenantId, assistant_id: top.assistantId } } };
1864
1864
  let agent;
1865
1865
  try {
1866
- agent = import_core81.agentInstanceManager.getAgent({ assistant_id: top.assistantId, thread_id: top.threadId, tenant_id: tenantId });
1866
+ agent = import_core82.agentInstanceManager.getAgent({ assistant_id: top.assistantId, thread_id: top.threadId, tenant_id: tenantId });
1867
1867
  } catch {
1868
1868
  }
1869
1869
  return agent ? { client, config, agent } : { client, config };
@@ -1880,11 +1880,11 @@ function createRecoveryCallerDeps() {
1880
1880
  }
1881
1881
  };
1882
1882
  }
1883
- var import_core81;
1883
+ var import_core82;
1884
1884
  var init_RecoveryCallerDeps = __esm({
1885
1885
  "src/services/collaboration/RecoveryCallerDeps.ts"() {
1886
1886
  "use strict";
1887
- import_core81 = require("@axiom-lattice/core");
1887
+ import_core82 = require("@axiom-lattice/core");
1888
1888
  }
1889
1889
  });
1890
1890
 
@@ -1955,18 +1955,18 @@ function extractText(msg) {
1955
1955
  }
1956
1956
  return null;
1957
1957
  }
1958
- var import_zod19, logger7, wechatConfigSchema, MAX_RECONNECT_DELAY_MS, BASE_RECONNECT_DELAY_MS, HEARTBEAT_INTERVAL_MS, MSG_TYPE_USER, MSG_ITEM_TEXT, activeConnections3, seenClientIds, wechatChannelAdapter;
1958
+ var import_zod20, logger7, wechatConfigSchema, MAX_RECONNECT_DELAY_MS, BASE_RECONNECT_DELAY_MS, HEARTBEAT_INTERVAL_MS, MSG_TYPE_USER, MSG_ITEM_TEXT, activeConnections3, seenClientIds, wechatChannelAdapter;
1959
1959
  var init_WechatChannelAdapter = __esm({
1960
1960
  "src/channels/wechat/WechatChannelAdapter.ts"() {
1961
1961
  "use strict";
1962
- import_zod19 = require("zod");
1962
+ import_zod20 = require("zod");
1963
1963
  init_wechat_client();
1964
1964
  init_context_store();
1965
1965
  init_Logger();
1966
1966
  logger7 = new Logger({ serviceName: "lattice/gateway/wechat" });
1967
- wechatConfigSchema = import_zod19.z.object({
1968
- botToken: import_zod19.z.string(),
1969
- uin: import_zod19.z.string().optional()
1967
+ wechatConfigSchema = import_zod20.z.object({
1968
+ botToken: import_zod20.z.string(),
1969
+ uin: import_zod20.z.string().optional()
1970
1970
  });
1971
1971
  MAX_RECONNECT_DELAY_MS = 3e4;
1972
1972
  BASE_RECONNECT_DELAY_MS = 1e3;
@@ -2303,13 +2303,13 @@ function isA2ATaskSnapshot(value) {
2303
2303
  function snapshotSequence(value) {
2304
2304
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
2305
2305
  }
2306
- var import_node_crypto31, import_node_util, import_core82, TASK_STATUS_TO_A2A_STATE, TITLE_MAX_LENGTH, A2ATaskScopeConflictError, A2ATaskStoreAdapter;
2306
+ var import_node_crypto31, import_node_util, import_core83, TASK_STATUS_TO_A2A_STATE, TITLE_MAX_LENGTH, A2ATaskScopeConflictError, A2ATaskStoreAdapter;
2307
2307
  var init_A2ATaskStoreAdapter = __esm({
2308
2308
  "src/services/a2a/A2ATaskStoreAdapter.ts"() {
2309
2309
  "use strict";
2310
2310
  import_node_crypto31 = require("crypto");
2311
2311
  import_node_util = require("util");
2312
- import_core82 = require("@axiom-lattice/core");
2312
+ import_core83 = require("@axiom-lattice/core");
2313
2313
  TASK_STATUS_TO_A2A_STATE = {
2314
2314
  pending: "submitted",
2315
2315
  in_progress: "working",
@@ -2335,7 +2335,7 @@ var init_A2ATaskStoreAdapter = __esm({
2335
2335
  this.workItemStore = options.workItemStore;
2336
2336
  this.lifecycle = options.lifecycle;
2337
2337
  this.scope = options.scope;
2338
- this.runBridge = (0, import_core82.createTaskRunBridge)({
2338
+ this.runBridge = (0, import_core83.createTaskRunBridge)({
2339
2339
  lifecycle: this.lifecycle,
2340
2340
  taskStore: this.taskStore,
2341
2341
  workItemStore: this.workItemStore
@@ -2686,12 +2686,12 @@ function assistantHasGovernedTask(assistant) {
2686
2686
  const allowedTools = taskMiddleware?.allowedTools;
2687
2687
  return !!taskMiddleware && (allowedTools === void 0 || Array.isArray(allowedTools) && (allowedTools.length === 0 || allowedTools.includes("manage_task")));
2688
2688
  }
2689
- var import_uuid11, import_core83, import_protocols35, _AxiomAgentExecutor, AxiomAgentExecutor;
2689
+ var import_uuid11, import_core84, import_protocols35, _AxiomAgentExecutor, AxiomAgentExecutor;
2690
2690
  var init_AxiomAgentExecutor = __esm({
2691
2691
  "src/services/a2a/AxiomAgentExecutor.ts"() {
2692
2692
  "use strict";
2693
2693
  import_uuid11 = require("uuid");
2694
- import_core83 = require("@axiom-lattice/core");
2694
+ import_core84 = require("@axiom-lattice/core");
2695
2695
  import_protocols35 = require("@axiom-lattice/protocols");
2696
2696
  init_a2aFileRefs();
2697
2697
  init_task_file_refs();
@@ -2788,7 +2788,7 @@ var init_AxiomAgentExecutor = __esm({
2788
2788
  await this.taskStore.save(initialTask);
2789
2789
  bus.publish(initialTask);
2790
2790
  try {
2791
- const agent = import_core83.agentInstanceManager.getAgent(this.agentParams(threadId));
2791
+ const agent = import_core84.agentInstanceManager.getAgent(this.agentParams(threadId));
2792
2792
  const requestText = inputFiles.length > 0 ? `${text}
2793
2793
 
2794
2794
  ${formatFileRefsSection(inputFiles)}` : text;
@@ -2976,7 +2976,7 @@ ${formatFileRefsSection(inputFiles)}` : text;
2976
2976
  const threadId = task ? asString2(task.metadata?.threadId) : void 0;
2977
2977
  if (threadId) {
2978
2978
  try {
2979
- const agent = import_core83.agentInstanceManager.getAgent(this.agentParams(threadId));
2979
+ const agent = import_core84.agentInstanceManager.getAgent(this.agentParams(threadId));
2980
2980
  await agent.abort();
2981
2981
  } catch (err) {
2982
2982
  console.warn({
@@ -3350,10 +3350,10 @@ function isAsyncGenerator(value) {
3350
3350
  }
3351
3351
  function registerA2AStandardRoutes(app2, deps) {
3352
3352
  const authService = deps.authService;
3353
- const resolveTasks = deps.getTaskStoreLattice ?? (() => (0, import_core84.getStoreLattice)("default", "task").store);
3354
- const resolveTaskWorkItems = deps.getTaskWorkItemStore ?? (() => (0, import_core84.getStoreLattice)("default", "taskWorkItem").store);
3355
- const getAssistantStore2 = deps.getAssistantStore ?? (() => (0, import_core84.getStoreLattice)("default", "assistant").store);
3356
- const getProjectStore2 = deps.getProjectStore ?? (() => (0, import_core84.getStoreLattice)("default", "project").store);
3353
+ const resolveTasks = deps.getTaskStoreLattice ?? (() => (0, import_core85.getStoreLattice)("default", "task").store);
3354
+ const resolveTaskWorkItems = deps.getTaskWorkItemStore ?? (() => (0, import_core85.getStoreLattice)("default", "taskWorkItem").store);
3355
+ const getAssistantStore2 = deps.getAssistantStore ?? (() => (0, import_core85.getStoreLattice)("default", "assistant").store);
3356
+ const getProjectStore2 = deps.getProjectStore ?? (() => (0, import_core85.getStoreLattice)("default", "project").store);
3357
3357
  const runtimeRegistry = deps.runtimeRegistry ?? new A2ARuntimeRegistry();
3358
3358
  app2.addHook("onClose", async () => {
3359
3359
  runtimeRegistry.close();
@@ -3436,7 +3436,7 @@ function registerA2AStandardRoutes(app2, deps) {
3436
3436
  const taskStore = assistantHasGovernedTask(assistant) ? new A2ATaskStoreAdapter({
3437
3437
  taskStore: internalTasks,
3438
3438
  workItemStore: workItems,
3439
- lifecycle: (0, import_core84.createTaskLifecycleService)({
3439
+ lifecycle: (0, import_core85.createTaskLifecycleService)({
3440
3440
  taskStore: internalTasks,
3441
3441
  workItemStore: workItems
3442
3442
  }),
@@ -3555,7 +3555,7 @@ data: ${JSON.stringify(errorResponse)}
3555
3555
  const taskStore = assistantHasGovernedTask(assistant) ? new A2ATaskStoreAdapter({
3556
3556
  taskStore: internalTasks,
3557
3557
  workItemStore: workItems,
3558
- lifecycle: (0, import_core84.createTaskLifecycleService)({
3558
+ lifecycle: (0, import_core85.createTaskLifecycleService)({
3559
3559
  taskStore: internalTasks,
3560
3560
  workItemStore: workItems
3561
3561
  }),
@@ -3610,13 +3610,13 @@ data: ${JSON.stringify(data)}
3610
3610
  }
3611
3611
  );
3612
3612
  }
3613
- var import_uuid12, import_server2, import_core84, SSE_HEADERS;
3613
+ var import_uuid12, import_server2, import_core85, SSE_HEADERS;
3614
3614
  var init_a2a_standard = __esm({
3615
3615
  "src/routes/a2a-standard.ts"() {
3616
3616
  "use strict";
3617
3617
  import_uuid12 = require("uuid");
3618
3618
  import_server2 = require("@a2a-js/sdk/server");
3619
- import_core84 = require("@axiom-lattice/core");
3619
+ import_core85 = require("@axiom-lattice/core");
3620
3620
  init_A2AAuthService();
3621
3621
  init_A2AAgentCardBuilder();
3622
3622
  init_A2ATaskStoreAdapter();
@@ -3829,11 +3829,11 @@ function grantCovers(grants, domain, action) {
3829
3829
  (g) => g.domain === domain && (!g.items || g.items.length === 0 || g.items.includes(action))
3830
3830
  );
3831
3831
  }
3832
- var import_zod20, GrantDeniedError, ValidationError, ActionNotFoundError, OpenLattice, openLattice;
3832
+ var import_zod21, GrantDeniedError, ValidationError, ActionNotFoundError, OpenLattice, openLattice;
3833
3833
  var init_openLattice = __esm({
3834
3834
  "src/services/open/openLattice.ts"() {
3835
3835
  "use strict";
3836
- import_zod20 = require("zod");
3836
+ import_zod21 = require("zod");
3837
3837
  GrantDeniedError = class extends Error {
3838
3838
  constructor(toolName) {
3839
3839
  super(`GRANT_DENIED: no grant covers ${toolName}`);
@@ -3973,7 +3973,7 @@ var init_openLattice = __esm({
3973
3973
  throw new GrantDeniedError(toolName);
3974
3974
  }
3975
3975
  const resolvedSchema = resolved.action.schema;
3976
- const parsed = "safeParse" in resolvedSchema ? resolvedSchema.safeParse(args) : import_zod20.z.object(resolvedSchema).safeParse(args);
3976
+ const parsed = "safeParse" in resolvedSchema ? resolvedSchema.safeParse(args) : import_zod21.z.object(resolvedSchema).safeParse(args);
3977
3977
  if (!parsed.success) {
3978
3978
  throw new ValidationError(parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; "));
3979
3979
  }
@@ -4106,7 +4106,7 @@ var init_openMcpServer = __esm({
4106
4106
 
4107
4107
  // src/services/open/pluginExposeAdapter.ts
4108
4108
  function schemaOf(tool) {
4109
- return tool.lc_kwargs?.schema ?? tool.schema ?? import_zod21.z.object({}).passthrough();
4109
+ return tool.lc_kwargs?.schema ?? tool.schema ?? import_zod22.z.object({}).passthrough();
4110
4110
  }
4111
4111
  function createPluginProvider(domain, tools, options = {}) {
4112
4112
  function toAction(info) {
@@ -4154,11 +4154,11 @@ function createPluginProvider(domain, tools, options = {}) {
4154
4154
  }
4155
4155
  };
4156
4156
  }
4157
- var import_zod21;
4157
+ var import_zod22;
4158
4158
  var init_pluginExposeAdapter = __esm({
4159
4159
  "src/services/open/pluginExposeAdapter.ts"() {
4160
4160
  "use strict";
4161
- import_zod21 = require("zod");
4161
+ import_zod22 = require("zod");
4162
4162
  }
4163
4163
  });
4164
4164
 
@@ -4183,8 +4183,8 @@ function exposedDeclarations(plugin) {
4183
4183
  return (plugin.meta.tools ?? []).filter((t2) => t2.expose);
4184
4184
  }
4185
4185
  async function registerExposedPluginTools() {
4186
- for (const key of import_core85.PluginRegistry.list()) {
4187
- const plugin = import_core85.PluginRegistry.get(key);
4186
+ for (const key of import_core86.PluginRegistry.list()) {
4187
+ const plugin = import_core86.PluginRegistry.get(key);
4188
4188
  if (!plugin?.middleware) continue;
4189
4189
  const exposed = exposedDeclarations(plugin);
4190
4190
  if (exposed.length === 0) continue;
@@ -4219,8 +4219,8 @@ async function registerExposedPluginTools() {
4219
4219
  }
4220
4220
  function collectExposedPluginUiResources(grants) {
4221
4221
  const resources = /* @__PURE__ */ new Map();
4222
- for (const type of import_core85.PluginRegistry.list()) {
4223
- const plugin = import_core85.PluginRegistry.get(type);
4222
+ for (const type of import_core86.PluginRegistry.list()) {
4223
+ const plugin = import_core86.PluginRegistry.get(type);
4224
4224
  if (!plugin?.middleware) continue;
4225
4225
  const exposedNames = new Set(exposedDeclarations(plugin).map((d) => d.name));
4226
4226
  if (exposedNames.size === 0) continue;
@@ -4244,11 +4244,11 @@ function collectExposedPluginUiResources(grants) {
4244
4244
  }
4245
4245
  return resources;
4246
4246
  }
4247
- var import_core85;
4247
+ var import_core86;
4248
4248
  var init_registerExposedPlugins = __esm({
4249
4249
  "src/services/open/registerExposedPlugins.ts"() {
4250
4250
  "use strict";
4251
- import_core85 = require("@axiom-lattice/core");
4251
+ import_core86 = require("@axiom-lattice/core");
4252
4252
  init_openLattice();
4253
4253
  init_pluginExposeAdapter();
4254
4254
  }
@@ -4263,14 +4263,14 @@ function toText(result) {
4263
4263
  }
4264
4264
  function defaultCatalog() {
4265
4265
  return {
4266
- getValidatedManifest: (tenantId, type) => (0, import_core86.getSandboxPluginCatalog)().getValidatedManifest(tenantId, type),
4267
- getExecutor: () => (0, import_core86.getSandboxPluginCatalog)().getExecutor(),
4268
- readPluginFile: (tenantId, type, relPath) => (0, import_core86.getSandboxPluginCatalog)().readPluginFile(tenantId, type, relPath)
4266
+ getValidatedManifest: (tenantId, type) => (0, import_core87.getSandboxPluginCatalog)().getValidatedManifest(tenantId, type),
4267
+ getExecutor: () => (0, import_core87.getSandboxPluginCatalog)().getExecutor(),
4268
+ readPluginFile: (tenantId, type, relPath) => (0, import_core87.getSandboxPluginCatalog)().readPluginFile(tenantId, type, relPath)
4269
4269
  };
4270
4270
  }
4271
4271
  async function defaultResolveConnections(pluginType, ctx) {
4272
4272
  try {
4273
- return await (0, import_core86.resolveSandboxPluginConnections)(
4273
+ return await (0, import_core87.resolveSandboxPluginConnections)(
4274
4274
  pluginType,
4275
4275
  { connectAll: true },
4276
4276
  {
@@ -4299,7 +4299,7 @@ function mergeOpenCatalog(globalCatalog, tenantTools) {
4299
4299
  async function buildTenantOpenPlugins(tenantId, grants, deps = {}) {
4300
4300
  const catalog = deps.catalog ?? defaultCatalog();
4301
4301
  const listPlugins = deps.listPlugins ?? (async (tenant2) => {
4302
- const snapshot = await (0, import_core86.getSandboxPluginCatalog)().ensureLoaded(tenant2);
4302
+ const snapshot = await (0, import_core87.getSandboxPluginCatalog)().ensureLoaded(tenant2);
4303
4303
  return { plugins: snapshot.plugins, diagnostics: snapshot.diagnostics };
4304
4304
  });
4305
4305
  const resolveConnections = deps.resolveConnections ?? defaultResolveConnections;
@@ -4341,7 +4341,7 @@ async function buildTenantOpenPlugins(tenantId, grants, deps = {}) {
4341
4341
  domain,
4342
4342
  action: tool.name,
4343
4343
  description: tool.description,
4344
- schema: (0, import_core86.jsonSchemaToZod)(tool.schema),
4344
+ schema: (0, import_core87.jsonSchemaToZod)(tool.schema),
4345
4345
  annotations: {
4346
4346
  readOnlyHint: tool.readOnly ?? false,
4347
4347
  destructiveHint: tool.destructive ?? false
@@ -4392,11 +4392,11 @@ async function buildTenantOpenPlugins(tenantId, grants, deps = {}) {
4392
4392
  }
4393
4393
  };
4394
4394
  }
4395
- var import_core86;
4395
+ var import_core87;
4396
4396
  var init_tenantOpenPlugins = __esm({
4397
4397
  "src/services/open/tenantOpenPlugins.ts"() {
4398
4398
  "use strict";
4399
- import_core86 = require("@axiom-lattice/core");
4399
+ import_core87 = require("@axiom-lattice/core");
4400
4400
  init_openLattice();
4401
4401
  init_pluginToolExecution();
4402
4402
  }
@@ -4433,13 +4433,13 @@ function emptyTenantPlugins() {
4433
4433
  }
4434
4434
  function registerOpenRoutes(app2, deps = {}) {
4435
4435
  const openAuth = deps.openAuth ?? new OpenCredentialService(
4436
- (0, import_core87.getStoreLattice)("default", "a2aApiKey").store,
4437
- (0, import_core87.getStoreLattice)("default", "project").store
4436
+ (0, import_core88.getStoreLattice)("default", "a2aApiKey").store,
4437
+ (0, import_core88.getStoreLattice)("default", "project").store
4438
4438
  );
4439
4439
  const grantsSource = deps.grantsSource ?? ((ctx) => ctx.grants);
4440
4440
  const audit = deps.audit ?? (() => {
4441
4441
  try {
4442
- const store2 = (0, import_core87.getStoreLattice)("default", "openAudit").store;
4442
+ const store2 = (0, import_core88.getStoreLattice)("default", "openAudit").store;
4443
4443
  return new OpenAuditService(store2);
4444
4444
  } catch {
4445
4445
  return void 0;
@@ -4611,12 +4611,12 @@ function registerOpenRoutes(app2, deps = {}) {
4611
4611
  }
4612
4612
  );
4613
4613
  }
4614
- var import_types, import_core87, RPC_ERROR;
4614
+ var import_types, import_core88, RPC_ERROR;
4615
4615
  var init_open = __esm({
4616
4616
  "src/routes/open.ts"() {
4617
4617
  "use strict";
4618
4618
  import_types = require("@modelcontextprotocol/sdk/types.js");
4619
- import_core87 = require("@axiom-lattice/core");
4619
+ import_core88 = require("@axiom-lattice/core");
4620
4620
  init_openCredentialService();
4621
4621
  init_openAuditService();
4622
4622
  init_openRateLimiter();
@@ -4649,7 +4649,7 @@ function registerOpenSessionRoutes(app2) {
4649
4649
  if (typeof shareToken !== "string" || shareToken.length === 0) {
4650
4650
  return reply.status(400).send({ error: "SHARE_TOKEN_REQUIRED" });
4651
4651
  }
4652
- const store2 = (0, import_core88.getStoreLattice)("default", "sharedResource").store;
4652
+ const store2 = (0, import_core89.getStoreLattice)("default", "sharedResource").store;
4653
4653
  const record = await store2.findByToken(shareToken);
4654
4654
  if (!record || record.revoked) {
4655
4655
  return reply.status(404).send({ error: "SHARE_NOT_FOUND" });
@@ -4674,11 +4674,11 @@ function registerOpenSessionRoutes(app2) {
4674
4674
  }
4675
4675
  );
4676
4676
  }
4677
- var import_core88;
4677
+ var import_core89;
4678
4678
  var init_open_session = __esm({
4679
4679
  "src/routes/open-session.ts"() {
4680
4680
  "use strict";
4681
- import_core88 = require("@axiom-lattice/core");
4681
+ import_core89 = require("@axiom-lattice/core");
4682
4682
  init_openToken();
4683
4683
  init_previewToken();
4684
4684
  init_openLattice();
@@ -4687,13 +4687,13 @@ var init_open_session = __esm({
4687
4687
 
4688
4688
  // src/services/open/openCatalogService.ts
4689
4689
  async function defaultListTenantPlugins(tenantId) {
4690
- return (await (0, import_core89.getSandboxPluginCatalog)().ensureLoaded(tenantId)).plugins;
4690
+ return (await (0, import_core90.getSandboxPluginCatalog)().ensureLoaded(tenantId)).plugins;
4691
4691
  }
4692
- var import_core89, OpenCatalogService;
4692
+ var import_core90, OpenCatalogService;
4693
4693
  var init_openCatalogService = __esm({
4694
4694
  "src/services/open/openCatalogService.ts"() {
4695
4695
  "use strict";
4696
- import_core89 = require("@axiom-lattice/core");
4696
+ import_core90 = require("@axiom-lattice/core");
4697
4697
  init_openLattice();
4698
4698
  OpenCatalogService = class {
4699
4699
  constructor(assistantStore, lattice = openLattice, listTenantPlugins2 = defaultListTenantPlugins) {
@@ -4759,26 +4759,26 @@ var open_catalog_exports = {};
4759
4759
  __export(open_catalog_exports, {
4760
4760
  registerOpenCatalogRoutes: () => registerOpenCatalogRoutes
4761
4761
  });
4762
- function tenantIdOf(request) {
4762
+ function tenantIdOf2(request) {
4763
4763
  return request.user?.tenantId;
4764
4764
  }
4765
4765
  function registerOpenCatalogRoutes(app2) {
4766
4766
  app2.get("/api/open/catalog", async (request, reply) => {
4767
- const tenantId = tenantIdOf(request);
4767
+ const tenantId = tenantIdOf2(request);
4768
4768
  if (!tenantId) {
4769
4769
  return reply.status(401).send({ success: false, error: "Unauthorized" });
4770
4770
  }
4771
- const assistantStore = (0, import_core90.getStoreLattice)("default", "assistant").store;
4771
+ const assistantStore = (0, import_core91.getStoreLattice)("default", "assistant").store;
4772
4772
  const service2 = new OpenCatalogService(assistantStore);
4773
4773
  const catalog = await service2.buildForTenant(tenantId);
4774
4774
  return reply.status(200).send({ success: true, data: catalog });
4775
4775
  });
4776
4776
  }
4777
- var import_core90;
4777
+ var import_core91;
4778
4778
  var init_open_catalog = __esm({
4779
4779
  "src/routes/open-catalog.ts"() {
4780
4780
  "use strict";
4781
- import_core90 = require("@axiom-lattice/core");
4781
+ import_core91 = require("@axiom-lattice/core");
4782
4782
  init_openCatalogService();
4783
4783
  }
4784
4784
  });
@@ -4793,11 +4793,11 @@ async function resolveContextSandbox(ctx) {
4793
4793
  const sandboxName = ctx.runConfig?.sandboxName;
4794
4794
  if (typeof sandboxName === "string" && sandboxName.length > 0) {
4795
4795
  try {
4796
- return await import_core91.sandboxLatticeManager.getSandbox(sandboxName);
4796
+ return await import_core92.sandboxLatticeManager.getSandbox(sandboxName);
4797
4797
  } catch {
4798
4798
  }
4799
4799
  }
4800
- return import_core91.sandboxLatticeManager.getSandboxFromConfig({
4800
+ return import_core92.sandboxLatticeManager.getSandboxFromConfig({
4801
4801
  assistant_id: "",
4802
4802
  thread_id: "",
4803
4803
  tenantId: ctx.tenantId,
@@ -4816,21 +4816,21 @@ function createOpenSandboxProvider() {
4816
4816
  name: "files_read",
4817
4817
  label: "Read files",
4818
4818
  description: "Read a file from the project sandbox.",
4819
- schema: { path: import_zod22.z.string().min(1) },
4819
+ schema: { path: import_zod23.z.string().min(1) },
4820
4820
  annotations: { readOnlyHint: true, destructiveHint: false }
4821
4821
  },
4822
4822
  {
4823
4823
  name: "files_list",
4824
4824
  label: "List files",
4825
4825
  description: "List files under a directory in the project sandbox.",
4826
- schema: { path: import_zod22.z.string(), recursive: import_zod22.z.boolean().optional() },
4826
+ schema: { path: import_zod23.z.string(), recursive: import_zod23.z.boolean().optional() },
4827
4827
  annotations: { readOnlyHint: true, destructiveHint: false }
4828
4828
  },
4829
4829
  {
4830
4830
  name: "files_write",
4831
4831
  label: "Write files",
4832
4832
  description: "Write content to a file in the project sandbox.",
4833
- schema: { path: import_zod22.z.string().min(1), content: import_zod22.z.string() },
4833
+ schema: { path: import_zod23.z.string().min(1), content: import_zod23.z.string() },
4834
4834
  annotations: { readOnlyHint: false, destructiveHint: true }
4835
4835
  },
4836
4836
  {
@@ -4838,9 +4838,9 @@ function createOpenSandboxProvider() {
4838
4838
  label: "Run shell commands",
4839
4839
  description: "Execute a shell command in the project sandbox. Returns stdout (up to 64KB) and exit code.",
4840
4840
  schema: {
4841
- command: import_zod22.z.string().min(1),
4842
- exec_dir: import_zod22.z.string().optional(),
4843
- timeout: import_zod22.z.number().int().min(1e3).optional()
4841
+ command: import_zod23.z.string().min(1),
4842
+ exec_dir: import_zod23.z.string().optional(),
4843
+ timeout: import_zod23.z.number().int().min(1e3).optional()
4844
4844
  },
4845
4845
  annotations: { readOnlyHint: false, destructiveHint: true }
4846
4846
  }
@@ -4895,12 +4895,12 @@ ${truncated}`
4895
4895
  }
4896
4896
  };
4897
4897
  }
4898
- var import_zod22, import_core91, MAX_OUTPUT_BYTES;
4898
+ var import_zod23, import_core92, MAX_OUTPUT_BYTES;
4899
4899
  var init_sandboxProvider = __esm({
4900
4900
  "src/services/open/providers/sandboxProvider.ts"() {
4901
4901
  "use strict";
4902
- import_zod22 = require("zod");
4903
- import_core91 = require("@axiom-lattice/core");
4902
+ import_zod23 = require("zod");
4903
+ import_core92 = require("@axiom-lattice/core");
4904
4904
  MAX_OUTPUT_BYTES = 64e3;
4905
4905
  }
4906
4906
  });
@@ -4922,12 +4922,12 @@ function safePath(raw) {
4922
4922
  }
4923
4923
  function registerOpenFilesRoutes(app2, deps = {}) {
4924
4924
  const openAuth = deps.openAuth ?? new OpenCredentialService(
4925
- (0, import_core92.getStoreLattice)("default", "a2aApiKey").store,
4926
- (0, import_core92.getStoreLattice)("default", "project").store
4925
+ (0, import_core93.getStoreLattice)("default", "a2aApiKey").store,
4926
+ (0, import_core93.getStoreLattice)("default", "project").store
4927
4927
  );
4928
4928
  const audit = deps.audit ?? (() => {
4929
4929
  try {
4930
- const store2 = (0, import_core92.getStoreLattice)("default", "openAudit").store;
4930
+ const store2 = (0, import_core93.getStoreLattice)("default", "openAudit").store;
4931
4931
  return new OpenAuditService(store2);
4932
4932
  } catch {
4933
4933
  return void 0;
@@ -5037,11 +5037,11 @@ function registerOpenFilesRoutes(app2, deps = {}) {
5037
5037
  }
5038
5038
  });
5039
5039
  }
5040
- var import_core92;
5040
+ var import_core93;
5041
5041
  var init_open_files = __esm({
5042
5042
  "src/routes/open-files.ts"() {
5043
5043
  "use strict";
5044
- import_core92 = require("@axiom-lattice/core");
5044
+ import_core93 = require("@axiom-lattice/core");
5045
5045
  init_openCredentialService();
5046
5046
  init_openLattice();
5047
5047
  init_sandboxProvider();
@@ -5063,7 +5063,7 @@ function registerOpenAuditRoutes(app2) {
5063
5063
  return reply.status(401).send({ success: false, error: "Unauthorized" });
5064
5064
  }
5065
5065
  const status = request.query.status === "ok" || request.query.status === "error" ? request.query.status : void 0;
5066
- const store2 = (0, import_core93.getStoreLattice)("default", "openAudit").store;
5066
+ const store2 = (0, import_core94.getStoreLattice)("default", "openAudit").store;
5067
5067
  const records = await store2.query({
5068
5068
  tenantId,
5069
5069
  credentialId: request.query.credentialId,
@@ -5078,11 +5078,11 @@ function registerOpenAuditRoutes(app2) {
5078
5078
  }
5079
5079
  );
5080
5080
  }
5081
- var import_core93;
5081
+ var import_core94;
5082
5082
  var init_open_audit = __esm({
5083
5083
  "src/routes/open-audit.ts"() {
5084
5084
  "use strict";
5085
- import_core93 = require("@axiom-lattice/core");
5085
+ import_core94 = require("@axiom-lattice/core");
5086
5086
  }
5087
5087
  });
5088
5088
 
@@ -5099,7 +5099,7 @@ function registerOpenExposureRoutes(app2, deps = {}) {
5099
5099
  if (!tenantId) {
5100
5100
  return reply.status(401).send({ success: false, error: "Unauthorized" });
5101
5101
  }
5102
- const keyStore = (0, import_core94.getStoreLattice)("default", "a2aApiKey").store;
5102
+ const keyStore = (0, import_core95.getStoreLattice)("default", "a2aApiKey").store;
5103
5103
  const record = await keyStore.findById(request.params.id);
5104
5104
  if (!record || record.tenantId !== tenantId) {
5105
5105
  return reply.status(404).send({ success: false, error: "Key not found" });
@@ -5133,7 +5133,7 @@ function registerOpenExposureRoutes(app2, deps = {}) {
5133
5133
  hasUi: Boolean(t2.ui)
5134
5134
  }));
5135
5135
  const agentGrant = grants.find((g) => g.domain === "agent");
5136
- const assistantStore = (0, import_core94.getStoreLattice)("default", "assistant").store;
5136
+ const assistantStore = (0, import_core95.getStoreLattice)("default", "assistant").store;
5137
5137
  const agents = [];
5138
5138
  for (const assistantId of agentGrant?.items ?? []) {
5139
5139
  const assistant = await assistantStore.getAssistantById(
@@ -5168,11 +5168,11 @@ function registerOpenExposureRoutes(app2, deps = {}) {
5168
5168
  }
5169
5169
  );
5170
5170
  }
5171
- var import_core94, import_protocols38;
5171
+ var import_core95, import_protocols38;
5172
5172
  var init_open_exposure = __esm({
5173
5173
  "src/routes/open-exposure.ts"() {
5174
5174
  "use strict";
5175
- import_core94 = require("@axiom-lattice/core");
5175
+ import_core95 = require("@axiom-lattice/core");
5176
5176
  import_protocols38 = require("@axiom-lattice/protocols");
5177
5177
  init_openLattice();
5178
5178
  init_tenantOpenPlugins();
@@ -5197,9 +5197,9 @@ function createKbProvider(collectionService3) {
5197
5197
  label: "Search collections",
5198
5198
  description: "Search a knowledge base collection. Returns matched entries with content, metadata and similarity score.",
5199
5199
  schema: {
5200
- collection: import_zod23.z.string().min(1),
5201
- query: import_zod23.z.string().min(1),
5202
- limit: import_zod23.z.number().int().min(1).max(50).optional()
5200
+ collection: import_zod24.z.string().min(1),
5201
+ query: import_zod24.z.string().min(1),
5202
+ limit: import_zod24.z.number().int().min(1).max(50).optional()
5203
5203
  },
5204
5204
  annotations: { readOnlyHint: true, destructiveHint: false }
5205
5205
  }
@@ -5227,11 +5227,11 @@ function createKbProvider(collectionService3) {
5227
5227
  }
5228
5228
  };
5229
5229
  }
5230
- var import_zod23;
5230
+ var import_zod24;
5231
5231
  var init_kbProvider = __esm({
5232
5232
  "src/services/open/providers/kbProvider.ts"() {
5233
5233
  "use strict";
5234
- import_zod23 = require("zod");
5234
+ import_zod24 = require("zod");
5235
5235
  }
5236
5236
  });
5237
5237
 
@@ -5269,7 +5269,7 @@ function createAgentProvider(deps = {}) {
5269
5269
  toolName: `invoke_${assistantId}`,
5270
5270
  label: name,
5271
5271
  description: `Invoke the "${name}" agent${description ? ` \u2014 ${description}` : ""}. Returns its final reply.`,
5272
- schema: { message: import_zod24.z.string().min(1) },
5272
+ schema: { message: import_zod25.z.string().min(1) },
5273
5273
  annotations: { readOnlyHint: false, destructiveHint: false }
5274
5274
  };
5275
5275
  })
@@ -5292,7 +5292,7 @@ function createAgentProvider(deps = {}) {
5292
5292
  } catch {
5293
5293
  }
5294
5294
  }
5295
- const agent = import_core95.agentInstanceManager.getAgent({
5295
+ const agent = import_core96.agentInstanceManager.getAgent({
5296
5296
  tenant_id: ctx.tenantId,
5297
5297
  assistant_id: assistantId,
5298
5298
  thread_id: threadId,
@@ -5317,12 +5317,12 @@ function createAgentProvider(deps = {}) {
5317
5317
  }
5318
5318
  };
5319
5319
  }
5320
- var import_zod24, import_core95, import_protocols39, STOP_TYPES;
5320
+ var import_zod25, import_core96, import_protocols39, STOP_TYPES;
5321
5321
  var init_agentProvider = __esm({
5322
5322
  "src/services/open/providers/agentProvider.ts"() {
5323
5323
  "use strict";
5324
- import_zod24 = require("zod");
5325
- import_core95 = require("@axiom-lattice/core");
5324
+ import_zod25 = require("zod");
5325
+ import_core96 = require("@axiom-lattice/core");
5326
5326
  import_protocols39 = require("@axiom-lattice/protocols");
5327
5327
  STOP_TYPES = [import_protocols39.MessageChunkTypes.MESSAGE_COMPLETED];
5328
5328
  }
@@ -5366,7 +5366,7 @@ function createSandboxOpenCredentialProvider(options) {
5366
5366
  };
5367
5367
  }
5368
5368
  function registerGatewaySandboxOpenCredentialProvider(onError) {
5369
- return (0, import_core96.registerSandboxOpenCredentialProvider)(
5369
+ return (0, import_core97.registerSandboxOpenCredentialProvider)(
5370
5370
  createSandboxOpenCredentialProvider({
5371
5371
  gatewayUrl: process.env.PUBLIC_GATEWAY_URL?.trim() || void 0,
5372
5372
  onError
@@ -5374,11 +5374,11 @@ function registerGatewaySandboxOpenCredentialProvider(onError) {
5374
5374
  { onError }
5375
5375
  );
5376
5376
  }
5377
- var import_core96, DEFAULT_SANDBOX_OPEN_GRANTS, MAX_SANDBOX_OPEN_DEPTH;
5377
+ var import_core97, DEFAULT_SANDBOX_OPEN_GRANTS, MAX_SANDBOX_OPEN_DEPTH;
5378
5378
  var init_sandboxOpenCredentialProvider = __esm({
5379
5379
  "src/services/open/sandboxOpenCredentialProvider.ts"() {
5380
5380
  "use strict";
5381
- import_core96 = require("@axiom-lattice/core");
5381
+ import_core97 = require("@axiom-lattice/core");
5382
5382
  init_openToken();
5383
5383
  init_sandboxOpenReflection();
5384
5384
  DEFAULT_SANDBOX_OPEN_GRANTS = [
@@ -5415,12 +5415,12 @@ var resources_exports = {};
5415
5415
  __export(resources_exports, {
5416
5416
  ResourceController: () => ResourceController
5417
5417
  });
5418
- var import_bcryptjs, import_core97, ResourceController;
5418
+ var import_bcryptjs, import_core98, ResourceController;
5419
5419
  var init_resources = __esm({
5420
5420
  "src/controllers/resources.ts"() {
5421
5421
  "use strict";
5422
5422
  import_bcryptjs = __toESM(require("bcryptjs"));
5423
- import_core97 = require("@axiom-lattice/core");
5423
+ import_core98 = require("@axiom-lattice/core");
5424
5424
  init_mime();
5425
5425
  init_http_range();
5426
5426
  init_sandboxGrants();
@@ -5437,14 +5437,14 @@ var init_resources = __esm({
5437
5437
  if (!workspaceId || !projectId) {
5438
5438
  return reply.status(400).send({ error: "x-workspace-id and x-project-id headers required" });
5439
5439
  }
5440
- const payload = (0, import_core97.createSharePayload)(
5440
+ const payload = (0, import_core98.createSharePayload)(
5441
5441
  tenantId,
5442
5442
  workspaceId,
5443
5443
  projectId,
5444
5444
  userId,
5445
5445
  body
5446
5446
  );
5447
- const token = (0, import_core97.generateToken)();
5447
+ const token = (0, import_core98.generateToken)();
5448
5448
  try {
5449
5449
  await this.deps.store.create({ ...payload, token });
5450
5450
  this.deps.logger.info(
@@ -5581,7 +5581,7 @@ var init_resources = __esm({
5581
5581
  resourcePath: subPath
5582
5582
  }, subPath, ext, request, reply);
5583
5583
  }
5584
- const volume = (0, import_core97.buildNamedVolumeName)("p", "project", tenantId, workspaceId, projectId);
5584
+ const volume = (0, import_core98.buildNamedVolumeName)("p", "project", tenantId, workspaceId, projectId);
5585
5585
  return this._resolveAndServe(
5586
5586
  volume,
5587
5587
  subPath,
@@ -8417,13 +8417,13 @@ async function searchEntries(request, reply) {
8417
8417
 
8418
8418
  // src/controllers/tools.ts
8419
8419
  var import_core14 = require("@axiom-lattice/core");
8420
- function serializeSchema(schema) {
8421
- if (!schema) {
8420
+ function serializeSchema(schema2) {
8421
+ if (!schema2) {
8422
8422
  return void 0;
8423
8423
  }
8424
8424
  try {
8425
- if (schema._def) {
8426
- const def = schema._def;
8425
+ if (schema2._def) {
8426
+ const def = schema2._def;
8427
8427
  if (def.typeName === "ZodObject") {
8428
8428
  const shape = def.shape();
8429
8429
  const properties = {};
@@ -8449,7 +8449,7 @@ function serializeSchema(schema) {
8449
8449
  }
8450
8450
  return {
8451
8451
  type: "object",
8452
- description: schema.description || "Schema definition"
8452
+ description: schema2.description || "Schema definition"
8453
8453
  };
8454
8454
  } catch (error) {
8455
8455
  return {
@@ -17118,6 +17118,49 @@ function registerA2ABridgeRoutes(app2) {
17118
17118
 
17119
17119
  // src/routes/stt.ts
17120
17120
  var import_core46 = require("@axiom-lattice/core");
17121
+
17122
+ // src/controllers/tenant-scope.ts
17123
+ var TenantScopeError2 = class extends Error {
17124
+ /** Creates a tenant scope error. */
17125
+ constructor(code, statusCode, message) {
17126
+ super(message);
17127
+ this.code = code;
17128
+ this.statusCode = statusCode;
17129
+ this.name = "TenantScopeError";
17130
+ }
17131
+ };
17132
+ function resolveTenantScope(request, authRequired2) {
17133
+ const authenticated = request.user?.tenantId;
17134
+ const header2 = request.headers["x-tenant-id"];
17135
+ const requested = Array.isArray(header2) ? header2[0] : header2;
17136
+ if (authenticated) {
17137
+ if (requested && requested !== authenticated) {
17138
+ throw new TenantScopeError2(
17139
+ "TENANT_ACCESS_DENIED",
17140
+ 403,
17141
+ "Tenant access denied"
17142
+ );
17143
+ }
17144
+ return { tenantId: authenticated, userId: request.user?.id };
17145
+ }
17146
+ if (authRequired2) {
17147
+ throw new TenantScopeError2(
17148
+ "UNAUTHENTICATED",
17149
+ 401,
17150
+ "Console session required"
17151
+ );
17152
+ }
17153
+ return { tenantId: requested || "default" };
17154
+ }
17155
+
17156
+ // src/routes/stt.ts
17157
+ function tenantIdOf(request) {
17158
+ try {
17159
+ return resolveTenantScope(request, false).tenantId;
17160
+ } catch {
17161
+ return "default";
17162
+ }
17163
+ }
17121
17164
  var ALLOWED_AUDIO_FORMATS = /* @__PURE__ */ new Set([
17122
17165
  "webm",
17123
17166
  "wav",
@@ -17171,10 +17214,11 @@ var registerSTTRoutes = (app2) => {
17171
17214
  return reply.status(400).send({ error: `Unsupported audio format: ${format}` });
17172
17215
  }
17173
17216
  try {
17174
- let client;
17175
- try {
17176
- client = (0, import_core46.getSTTClient)(modelKey2);
17177
- } catch {
17217
+ const client = await import_core46.sttModelLatticeManager.getSTTClientWithTenantAsync(
17218
+ tenantIdOf(request),
17219
+ modelKey2
17220
+ );
17221
+ if (!client) {
17178
17222
  return reply.status(404).send({ error: `STT model "${modelKey2}" not found` });
17179
17223
  }
17180
17224
  const result = await client.transcribe(buffer, format);
@@ -21451,13 +21495,48 @@ function resolveDiscoveryTimeoutMs(raw = process.env.LATTICE_MODEL_DISCOVERY_TIM
21451
21495
  return parsed;
21452
21496
  }
21453
21497
  function buildModelsEndpoint(baseURL) {
21498
+ return buildOpenAiEndpoint(baseURL, "models");
21499
+ }
21500
+ function buildOpenAiEndpoint(baseURL, path7) {
21454
21501
  const url = new URL(baseURL);
21455
21502
  const trimmed = url.pathname.replace(/\/+$/, "");
21456
- url.pathname = trimmed.endsWith("/v1") ? `${trimmed}/models` : `${trimmed}/v1/models`;
21503
+ url.pathname = /\/v\d+$/.test(trimmed) ? `${trimmed}/${path7}` : `${trimmed}/v1/${path7}`;
21457
21504
  url.search = "";
21458
21505
  url.hash = "";
21459
21506
  return url.toString();
21460
21507
  }
21508
+ function assertUpstreamOk(response) {
21509
+ if (response.status >= 300 && response.status < 400) {
21510
+ throw new ModelProviderServiceError(
21511
+ "UPSTREAM_REDIRECT_BLOCKED",
21512
+ 502,
21513
+ "Upstream returned a redirect; configure the final URL directly"
21514
+ );
21515
+ }
21516
+ if (response.status === 401 || response.status === 403) {
21517
+ throw new ModelProviderServiceError(
21518
+ "UPSTREAM_AUTH_FAILED",
21519
+ 502,
21520
+ "Upstream rejected the configured credentials"
21521
+ );
21522
+ }
21523
+ if (response.status === 429) {
21524
+ throw new ModelProviderServiceError(
21525
+ "UPSTREAM_RATE_LIMITED",
21526
+ 502,
21527
+ "Upstream rate limited the request",
21528
+ true
21529
+ );
21530
+ }
21531
+ if (!response.ok) {
21532
+ throw new ModelProviderServiceError(
21533
+ "UPSTREAM_UNREACHABLE",
21534
+ 502,
21535
+ "Upstream returned an error response",
21536
+ response.status >= 500
21537
+ );
21538
+ }
21539
+ }
21461
21540
  function parseModelsPayload(payload) {
21462
21541
  const entries = Array.isArray(payload) ? payload : typeof payload === "object" && payload !== null ? payload.data : void 0;
21463
21542
  if (!Array.isArray(entries)) {
@@ -21528,36 +21607,60 @@ var openAiCompatibleAdapter = {
21528
21607
  true
21529
21608
  );
21530
21609
  }
21531
- if (response.status >= 300 && response.status < 400) {
21532
- throw new ModelProviderServiceError(
21533
- "UPSTREAM_REDIRECT_BLOCKED",
21534
- 502,
21535
- "Upstream returned a redirect; configure the final URL directly"
21536
- );
21537
- }
21538
- if (response.status === 401 || response.status === 403) {
21539
- throw new ModelProviderServiceError(
21540
- "UPSTREAM_AUTH_FAILED",
21541
- 502,
21542
- "Upstream rejected the configured credentials"
21543
- );
21544
- }
21545
- if (response.status === 429) {
21610
+ assertUpstreamOk(response);
21611
+ const body = await readBodyWithLimit(response, MAX_RESPONSE_BYTES);
21612
+ let payload;
21613
+ try {
21614
+ payload = JSON.parse(body);
21615
+ } catch {
21546
21616
  throw new ModelProviderServiceError(
21547
- "UPSTREAM_RATE_LIMITED",
21617
+ "UPSTREAM_INVALID_RESPONSE",
21548
21618
  502,
21549
- "Upstream rate limited the request",
21550
- true
21619
+ "Upstream response was not valid JSON"
21551
21620
  );
21552
21621
  }
21553
- if (!response.ok) {
21622
+ return parseModelsPayload(payload);
21623
+ }
21624
+ };
21625
+ async function probeEmbeddingInference(input, signal) {
21626
+ const startedAt = Date.now();
21627
+ const endpoint = buildOpenAiEndpoint(input.baseURL, "embeddings");
21628
+ const headers = {
21629
+ Accept: "application/json",
21630
+ "Content-Type": "application/json"
21631
+ };
21632
+ if (input.apiKey) {
21633
+ headers.Authorization = `Bearer ${input.apiKey}`;
21634
+ }
21635
+ try {
21636
+ let response;
21637
+ try {
21638
+ response = await fetch(endpoint, {
21639
+ method: "POST",
21640
+ headers,
21641
+ // Never follow redirects: a redirected request could reach an address
21642
+ // that bypassed the SSRF checks.
21643
+ redirect: "manual",
21644
+ signal,
21645
+ body: JSON.stringify({ model: input.modelId, input: "ping" })
21646
+ });
21647
+ } catch (error) {
21648
+ if (error instanceof Error && error.name === "AbortError") {
21649
+ throw new ModelProviderServiceError(
21650
+ "UPSTREAM_TIMEOUT",
21651
+ 504,
21652
+ "Upstream did not respond in time",
21653
+ true
21654
+ );
21655
+ }
21554
21656
  throw new ModelProviderServiceError(
21555
21657
  "UPSTREAM_UNREACHABLE",
21556
21658
  502,
21557
- "Upstream returned an error response",
21558
- response.status >= 500
21659
+ "Upstream could not be reached",
21660
+ true
21559
21661
  );
21560
21662
  }
21663
+ assertUpstreamOk(response);
21561
21664
  const body = await readBodyWithLimit(response, MAX_RESPONSE_BYTES);
21562
21665
  let payload;
21563
21666
  try {
@@ -21569,9 +21672,37 @@ var openAiCompatibleAdapter = {
21569
21672
  "Upstream response was not valid JSON"
21570
21673
  );
21571
21674
  }
21572
- return parseModelsPayload(payload);
21675
+ return {
21676
+ reachable: true,
21677
+ latencyMs: Date.now() - startedAt,
21678
+ dimensions: readEmbeddingDimensions(payload)
21679
+ };
21680
+ } catch (error) {
21681
+ if (error instanceof ModelProviderServiceError && isUpstreamErrorCode(error.code)) {
21682
+ return {
21683
+ reachable: false,
21684
+ latencyMs: Date.now() - startedAt,
21685
+ error: error.code
21686
+ };
21687
+ }
21688
+ throw error;
21573
21689
  }
21574
- };
21690
+ }
21691
+ function readEmbeddingDimensions(payload) {
21692
+ if (typeof payload !== "object" || payload === null) {
21693
+ return void 0;
21694
+ }
21695
+ const data = payload.data;
21696
+ if (!Array.isArray(data) || data.length === 0) {
21697
+ return void 0;
21698
+ }
21699
+ const first = data[0];
21700
+ if (typeof first !== "object" || first === null) {
21701
+ return void 0;
21702
+ }
21703
+ const embedding = first.embedding;
21704
+ return Array.isArray(embedding) ? embedding.length : void 0;
21705
+ }
21575
21706
  async function readBodyWithLimit(response, maxBytes) {
21576
21707
  if (!response.body) {
21577
21708
  return response.text();
@@ -21673,6 +21804,9 @@ var ModelProviderService = class {
21673
21804
  }
21674
21805
  const models = snapshot.map((model) => ({
21675
21806
  modelKey: (0, import_protocols16.toModelKey)(model.providerId, model.modelId),
21807
+ // What this row can do. Pickers filter on it, so it travels with every
21808
+ // entry rather than being re-derived by each consumer.
21809
+ kind: model.kind,
21676
21810
  displayName: model.displayName,
21677
21811
  providerId: model.providerId,
21678
21812
  providerName: providerNames.get(model.providerId) ?? model.providerId,
@@ -21700,6 +21834,9 @@ var ModelProviderService = class {
21700
21834
  // which is how the deployment's `default` alias came to be offered as
21701
21835
  // a model literally called "default".
21702
21836
  displayName: config.displayName || config.model || modelKey2,
21837
+ // Deployment-registered models are chat by construction: they are
21838
+ // built with `registerModelLattice`, which only mints LLM clients.
21839
+ kind: "chat",
21703
21840
  providerId: "",
21704
21841
  providerName: "registered",
21705
21842
  source: "registered",
@@ -21753,6 +21890,8 @@ var ModelProviderService = class {
21753
21890
  * left untouched.
21754
21891
  */
21755
21892
  async reconcileProvider(tenantId, providerId2) {
21893
+ this.deps.registry.evictProviderCache?.(tenantId, providerId2);
21894
+ this.deps.registry.forgetTenantDefaultMiss?.(tenantId);
21756
21895
  if (!this.shouldRegister(tenantId)) {
21757
21896
  return;
21758
21897
  }
@@ -21762,21 +21901,9 @@ var ModelProviderService = class {
21762
21901
  }
21763
21902
  const provider = await this.deps.providerStore.getProviderById(tenantId, providerId2);
21764
21903
  if (!provider) {
21765
- const prefix = `${providerId2}/`;
21766
- for (const { modelKey: modelKey2 } of this.deps.registry.listRegistered(tenantId)) {
21767
- if (modelKey2.startsWith(prefix)) {
21768
- this.deps.registry.remove(tenantId, modelKey2);
21769
- }
21770
- }
21771
21904
  return;
21772
21905
  }
21773
21906
  const models = await this.deps.providerStore.listModels(tenantId, providerId2);
21774
- const current = new Set(models.map((model) => (0, import_protocols16.toModelKey)(providerId2, model.modelId)));
21775
- for (const { modelKey: modelKey2 } of this.deps.registry.listRegistered(tenantId)) {
21776
- if (modelKey2.startsWith(`${providerId2}/`) && !current.has(modelKey2)) {
21777
- this.deps.registry.remove(tenantId, modelKey2);
21778
- }
21779
- }
21780
21907
  this.syncRegistry(tenantId, provider, models);
21781
21908
  }
21782
21909
  /**
@@ -21875,11 +22002,9 @@ var ModelProviderService = class {
21875
22002
  async remove(userId, tenantId, id3) {
21876
22003
  await this.assertAdmin(userId, tenantId);
21877
22004
  await this.requireProvider(tenantId, id3);
21878
- const snapshot = await this.deps.providerStore.listModels(tenantId, id3);
21879
22005
  await this.deps.providerStore.deleteProvider(tenantId, id3);
21880
- for (const model of snapshot) {
21881
- this.deps.registry.remove(tenantId, (0, import_protocols16.toModelKey)(id3, model.modelId));
21882
- }
22006
+ this.deps.registry.evictProviderCache?.(tenantId, id3);
22007
+ this.deps.registry.forgetTenantDefaultMiss?.(tenantId);
21883
22008
  this.notifyChanged(tenantId, id3);
21884
22009
  }
21885
22010
  /**
@@ -21909,7 +22034,8 @@ var ModelProviderService = class {
21909
22034
  () => controller.abort(),
21910
22035
  resolveDiscoveryTimeoutMs()
21911
22036
  );
21912
- const previous = this.shouldRegister(tenantId) ? await this.deps.providerStore.listModels(tenantId, id3) : [];
22037
+ const previous = await this.deps.providerStore.listModels(tenantId, id3);
22038
+ const previousIds = new Set(previous.map((model) => model.modelId));
21913
22039
  let discovered;
21914
22040
  try {
21915
22041
  discovered = await adapter.discover({
@@ -21935,7 +22061,12 @@ var ModelProviderService = class {
21935
22061
  const inserted = await this.deps.providerStore.replaceProviderModels(
21936
22062
  tenantId,
21937
22063
  id3,
21938
- discovered
22064
+ discovered.map((model) => ({
22065
+ ...model,
22066
+ // Same rule as `setModels`: a row this provider just brought in starts
22067
+ // with the default config, a row already stored keeps the tenant's.
22068
+ extra: previousIds.has(model.id) ? void 0 : { ...import_core53.DEFAULT_MODEL_EXTRA }
22069
+ }))
21939
22070
  );
21940
22071
  await this.deps.providerStore.markProviderStatus(
21941
22072
  tenantId,
@@ -22009,6 +22140,30 @@ var ModelProviderService = class {
22009
22140
  resolveDiscoveryTimeoutMs()
22010
22141
  );
22011
22142
  const startedAt = Date.now();
22143
+ if (input.kind === "embedding") {
22144
+ if (!input.modelId) {
22145
+ throw new ModelProviderServiceError(
22146
+ "INVALID_INPUT",
22147
+ 400,
22148
+ "An embedding probe needs a model id"
22149
+ );
22150
+ }
22151
+ try {
22152
+ const outcome2 = await probeEmbeddingInference(
22153
+ { baseURL: input.baseURL, apiKey, modelId: input.modelId },
22154
+ controller.signal
22155
+ );
22156
+ return {
22157
+ reachable: outcome2.reachable,
22158
+ latencyMs: outcome2.latencyMs,
22159
+ models: [],
22160
+ ...outcome2.dimensions === void 0 ? {} : { dimensions: outcome2.dimensions },
22161
+ ...outcome2.error ? { error: outcome2.error } : {}
22162
+ };
22163
+ } finally {
22164
+ clearTimeout(timeout);
22165
+ }
22166
+ }
22012
22167
  try {
22013
22168
  const models = await adapter.discover({
22014
22169
  baseURL: input.baseURL,
@@ -22073,8 +22228,13 @@ var ModelProviderService = class {
22073
22228
  ownedBy: previousById.get(entry.modelId)?.ownedBy,
22074
22229
  // An omitted `extra` means "keep what is stored" — the picker sends no
22075
22230
  // config, and a sync must not wipe one set by hand. The store resolves
22076
- // the fallback against the row's current value.
22077
- extra: entry.extra,
22231
+ // the fallback against the row's current value. A model that is not
22232
+ // stored at all gets the default config rather than an empty one.
22233
+ extra: entry.extra ?? (previousById.has(entry.modelId) ? void 0 : { ...import_core53.DEFAULT_MODEL_EXTRA }),
22234
+ // Omitted means "keep the stored kind"; the store defaults a new row
22235
+ // to chat. A picker that only toggles `enabled` therefore cannot
22236
+ // accidentally reclassify a model.
22237
+ kind: entry.kind,
22078
22238
  // Same rule: omitted leaves the flag alone, so a sync cannot quietly
22079
22239
  // move the tenant's default.
22080
22240
  isDefault: entry.isDefault
@@ -22097,14 +22257,17 @@ var ModelProviderService = class {
22097
22257
  return this.toPublicEntry(provider, models.length);
22098
22258
  }
22099
22259
  /**
22100
- * Give a tenant's sole model the default flag.
22260
+ * Give a tenant's sole **chat** model the default flag.
22261
+ *
22262
+ * A tenant with exactly one runnable chat model has an obvious default, and
22263
+ * saying so is what keeps the invariant the rest of the feature leans on: a
22264
+ * tenant either has no chat model at all — and falls back to the deployment's
22265
+ * default — or has a default, which cannot be deleted. Without this a tenant
22266
+ * could sit with one model and no default, and deleting that model would
22267
+ * leave nothing behind.
22101
22268
  *
22102
- * A tenant with exactly one runnable model has an obvious default, and saying
22103
- * so is what keeps the invariant the rest of the feature leans on: a tenant
22104
- * either has no models at all — and falls back to the deployment's default —
22105
- * or has a default, which cannot be deleted. Without this a tenant could sit
22106
- * with one model and no default, and deleting that model would leave nothing
22107
- * behind.
22269
+ * Chat only: a bare `"default"` key resolves to a chat client, so an
22270
+ * embedding or ASR row must never be marked as one.
22108
22271
  *
22109
22272
  * Deliberately narrow: more than one model is the tenant's choice to make,
22110
22273
  * and a disabled model is not a candidate for "the model this tenant runs".
@@ -22113,24 +22276,33 @@ var ModelProviderService = class {
22113
22276
  */
22114
22277
  async ensureDefaultModel(tenantId) {
22115
22278
  const models = await this.deps.providerStore.listModels(tenantId);
22116
- if (models.length !== 1) {
22279
+ const chatModels = models.filter((model) => model.kind === "chat");
22280
+ if (chatModels.length !== 1) {
22117
22281
  return;
22118
22282
  }
22119
- const [only] = models;
22283
+ const [only] = chatModels;
22120
22284
  if (only.isDefault || !only.enabled) {
22121
22285
  return;
22122
22286
  }
22123
- await this.deps.providerStore.replaceProviderModels(tenantId, only.providerId, [
22124
- {
22125
- id: only.modelId,
22126
- enabled: only.enabled,
22127
- stale: only.stale,
22128
- extra: only.extra,
22129
- isDefault: true
22130
- }
22131
- ]);
22287
+ const siblings = models.filter(
22288
+ (model) => model.providerId === only.providerId
22289
+ );
22290
+ await this.deps.providerStore.replaceProviderModels(
22291
+ tenantId,
22292
+ only.providerId,
22293
+ siblings.map((model) => ({
22294
+ id: model.modelId,
22295
+ enabled: model.enabled,
22296
+ stale: model.stale,
22297
+ extra: model.extra,
22298
+ kind: model.kind,
22299
+ isDefault: model.modelId === only.modelId
22300
+ }))
22301
+ );
22132
22302
  }
22133
22303
  syncRegistry(tenantId, provider, models) {
22304
+ this.deps.registry.evictProviderCache?.(tenantId, provider.id);
22305
+ this.deps.registry.forgetTenantDefaultMiss?.(tenantId);
22134
22306
  if (!this.shouldRegister(tenantId)) {
22135
22307
  return [];
22136
22308
  }
@@ -22377,6 +22549,10 @@ var setModelsSchema = import_zod10.z.object({
22377
22549
  // Omitted means "leave the stored config alone" — the picker sends
22378
22550
  // only ids and states, and must not wipe a config set by hand.
22379
22551
  extra: extraSchema.optional(),
22552
+ // What this model does. Omitted means "leave the stored kind
22553
+ // alone"; a new row defaults to chat. The kinds are independent —
22554
+ // each has its own runtime lattice and loader guard.
22555
+ kind: import_zod10.z.enum(["chat", "embedding", "asr"]).optional(),
22380
22556
  // At most one per tenant; the service rejects a tie with a
22381
22557
  // readable error rather than letting the unique index raise one.
22382
22558
  // Omitted means "leave the stored flag alone", which is what a
@@ -22389,43 +22565,13 @@ var probeProviderSchema = import_zod10.z.object({
22389
22565
  baseURL: import_zod10.z.string().trim().min(1).max(2048),
22390
22566
  apiKey: import_zod10.z.string().max(1024).optional(),
22391
22567
  providerId: import_zod10.z.string().trim().min(1).max(255).optional(),
22392
- protocol: protocolSchema.optional()
22568
+ protocol: protocolSchema.optional(),
22569
+ // Only an embedding probe uses these: it names the model and asks for one
22570
+ // inference, because a model list cannot prove a model can embed.
22571
+ kind: import_zod10.z.enum(["chat", "embedding", "asr"]).optional(),
22572
+ modelId: import_zod10.z.string().trim().min(1).max(512).optional()
22393
22573
  }).strict();
22394
22574
 
22395
- // src/controllers/tenant-scope.ts
22396
- var TenantScopeError2 = class extends Error {
22397
- /** Creates a tenant scope error. */
22398
- constructor(code, statusCode, message) {
22399
- super(message);
22400
- this.code = code;
22401
- this.statusCode = statusCode;
22402
- this.name = "TenantScopeError";
22403
- }
22404
- };
22405
- function resolveTenantScope(request, authRequired2) {
22406
- const authenticated = request.user?.tenantId;
22407
- const header2 = request.headers["x-tenant-id"];
22408
- const requested = Array.isArray(header2) ? header2[0] : header2;
22409
- if (authenticated) {
22410
- if (requested && requested !== authenticated) {
22411
- throw new TenantScopeError2(
22412
- "TENANT_ACCESS_DENIED",
22413
- 403,
22414
- "Tenant access denied"
22415
- );
22416
- }
22417
- return { tenantId: authenticated, userId: request.user?.id };
22418
- }
22419
- if (authRequired2) {
22420
- throw new TenantScopeError2(
22421
- "UNAUTHENTICATED",
22422
- 401,
22423
- "Console session required"
22424
- );
22425
- }
22426
- return { tenantId: requested || "default" };
22427
- }
22428
-
22429
22575
  // src/controllers/model-providers.ts
22430
22576
  init_Logger();
22431
22577
  var logger4 = new Logger({ serviceName: "lattice/gateway/model-providers" });
@@ -28767,7 +28913,13 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
28767
28913
  config: lattice.client.getConfig()
28768
28914
  }))
28769
28915
  ),
28770
- forgetTenantDefaultMiss: (tenantId) => import_core58.modelLatticeManager.forgetTenantDefaultMiss(tenantId)
28916
+ forgetTenantDefaultMiss: (tenantId) => import_core58.modelLatticeManager.forgetTenantDefaultMiss(tenantId),
28917
+ evictProviderCache: (tenantId, providerId2) => {
28918
+ import_core58.modelLatticeManager.evictProviderCache(tenantId, providerId2);
28919
+ import_core58.embeddingsLatticeManager.evictProviderCache(tenantId, providerId2);
28920
+ import_core58.sttModelLatticeManager.evictProviderCache(tenantId, providerId2);
28921
+ import_core58.vectorStoreLatticeManager.clearTenantVectorStores(tenantId);
28922
+ }
28771
28923
  },
28772
28924
  onChanged: (tenantId, providerId2) => broadcastModelProviderChanged(tenantId, providerId2)
28773
28925
  }, { authRequired: process.env.AUTH_REQUIRED === "true" });
@@ -30827,11 +30979,11 @@ function createAuditLoggerMiddleware() {
30827
30979
  }
30828
30980
 
30829
30981
  // src/index.ts
30830
- var import_core98 = require("@axiom-lattice/core");
30982
+ var import_core99 = require("@axiom-lattice/core");
30831
30983
 
30832
30984
  // src/channels/wecom/WecomChannelAdapter.ts
30833
30985
  var import_node_crypto27 = require("crypto");
30834
- var import_zod17 = require("zod");
30986
+ var import_zod18 = require("zod");
30835
30987
  var WecomAiBot = __toESM(require("@wecom/aibot-node-sdk"));
30836
30988
 
30837
30989
  // src/channels/wecom/parser.ts
@@ -30856,24 +31008,288 @@ function parseWecomTextFrame(frame) {
30856
31008
  };
30857
31009
  }
30858
31010
 
31011
+ // src/channels/wecom/cardTool.ts
31012
+ var import_core71 = require("@axiom-lattice/core");
31013
+ var import_zod17 = require("zod");
31014
+ var CARD_TTL_MS = 10 * 6e4;
31015
+ var MAX_CARD_ENTRIES = 1e3;
31016
+ var cardEntries = /* @__PURE__ */ new Map();
31017
+ function pruneCards(now) {
31018
+ for (const [key, entry] of cardEntries) {
31019
+ if (entry.expiresAt <= now) cardEntries.delete(key);
31020
+ }
31021
+ while (cardEntries.size > MAX_CARD_ENTRIES) {
31022
+ const oldest = cardEntries.keys().next().value;
31023
+ if (oldest === void 0) break;
31024
+ cardEntries.delete(oldest);
31025
+ }
31026
+ }
31027
+ function putWecomCard(key, card) {
31028
+ const now = Date.now();
31029
+ pruneCards(now);
31030
+ if (cardEntries.get(key)?.closed) return false;
31031
+ cardEntries.delete(key);
31032
+ cardEntries.set(key, { card, expiresAt: now + CARD_TTL_MS, closed: false });
31033
+ return true;
31034
+ }
31035
+ function takeWecomCard(key) {
31036
+ const now = Date.now();
31037
+ pruneCards(now);
31038
+ const entry = cardEntries.get(key);
31039
+ if (!entry) return void 0;
31040
+ cardEntries.delete(key);
31041
+ cardEntries.set(key, { expiresAt: now + CARD_TTL_MS, closed: true });
31042
+ return entry.card;
31043
+ }
31044
+ function discardWecomCard(key) {
31045
+ const now = Date.now();
31046
+ pruneCards(now);
31047
+ const entry = cardEntries.get(key);
31048
+ if (entry) entry.card = void 0;
31049
+ cardEntries.delete(key);
31050
+ cardEntries.set(key, { expiresAt: now + CARD_TTL_MS, closed: true });
31051
+ }
31052
+ var CARD_TYPES = [
31053
+ "text_notice",
31054
+ "news_notice",
31055
+ "button_interaction",
31056
+ "vote_interaction",
31057
+ "multiple_interaction"
31058
+ ];
31059
+ var optionSchema = import_zod17.z.object({
31060
+ id: import_zod17.z.string().describe("\u9009\u9879 ID"),
31061
+ text: import_zod17.z.string().describe("\u9009\u9879\u6587\u6848"),
31062
+ is_checked: import_zod17.z.boolean().optional().describe("\u662F\u5426\u9ED8\u8BA4\u9009\u4E2D")
31063
+ });
31064
+ var schema = import_zod17.z.object({
31065
+ card_type: import_zod17.z.enum(CARD_TYPES).default("text_notice").describe(
31066
+ "\u5361\u7247\u7C7B\u578B\uFF1Atext_notice(\u6587\u672C\u901A\u77E5)/news_notice(\u56FE\u6587)/button_interaction(\u6309\u94AE)/vote_interaction(\u6295\u7968)/multiple_interaction(\u591A\u9009)"
31067
+ ),
31068
+ title: import_zod17.z.string().min(1).max(26).describe("\u4E00\u7EA7\u6807\u9898\uFF0C\u4E0D\u8D85\u8FC7 26 \u5B57"),
31069
+ desc: import_zod17.z.string().max(30).optional().describe("\u6807\u9898\u8F85\u52A9\u4FE1\u606F\uFF0C\u4E0D\u8D85\u8FC7 30 \u5B57"),
31070
+ source_desc: import_zod17.z.string().max(13).optional().describe("\u5361\u7247\u5DE6\u4E0A\u89D2\u6765\u6E90\u6587\u6848\uFF0C\u4E0D\u8D85\u8FC7 13 \u5B57"),
31071
+ source_color: import_zod17.z.number().int().min(0).max(3).optional().describe("\u6765\u6E90\u6587\u5B57\u989C\u8272\uFF1A0 \u7070(\u9ED8\u8BA4)/1 \u9ED1/2 \u7EA2/3 \u7EFF"),
31072
+ emphasis_title: import_zod17.z.string().max(10).optional().describe("\u5173\u952E\u6570\u5B57\uFF0C\u4E0D\u8D85\u8FC7 10 \u5B57"),
31073
+ emphasis_desc: import_zod17.z.string().max(15).optional().describe("\u5173\u952E\u6570\u5B57\u8BF4\u660E\uFF0C\u4E0D\u8D85\u8FC7 15 \u5B57"),
31074
+ subtitle: import_zod17.z.string().max(112).optional().describe("\u4E8C\u7EA7\u666E\u901A\u6587\u672C\uFF0C\u4E0D\u8D85\u8FC7 112 \u5B57"),
31075
+ quote_text: import_zod17.z.string().optional().describe("\u5F15\u7528\u6837\u5F0F\u6587\u672C\uFF08\u4E0E\u5173\u952E\u6570\u5B57\u4E8C\u9009\u4E00\uFF09"),
31076
+ items: import_zod17.z.array(import_zod17.z.object({
31077
+ key: import_zod17.z.string().max(5).describe("\u4E8C\u7EA7\u6807\u9898\uFF0C\u4E0D\u8D85\u8FC7 5 \u5B57"),
31078
+ value: import_zod17.z.string().max(26).describe("\u4E8C\u7EA7\u6587\u672C\uFF0C\u4E0D\u8D85\u8FC7 26 \u5B57"),
31079
+ url: import_zod17.z.string().optional().describe("\u70B9\u51FB\u8DF3\u8F6C\u94FE\u63A5\uFF08\u53EF\u9009\uFF09")
31080
+ })).max(6).optional().describe("\u952E\u503C\u660E\u7EC6\u5217\u8868\uFF0C\u6700\u591A 6 \u6761"),
31081
+ links: import_zod17.z.array(import_zod17.z.object({
31082
+ title: import_zod17.z.string().max(13).describe("\u94FE\u63A5\u6587\u6848\uFF0C\u4E0D\u8D85\u8FC7 13 \u5B57"),
31083
+ url: import_zod17.z.string()
31084
+ })).max(3).optional().describe("\u8DF3\u8F6C\u94FE\u63A5\u5217\u8868\uFF0C\u6700\u591A 3 \u6761"),
31085
+ action_url: import_zod17.z.string().optional().describe("\u6574\u5F20\u5361\u7247\u70B9\u51FB\u8DF3\u8F6C\u7684\u94FE\u63A5\uFF08\u4F01\u5FAE\u8981\u6C42\u5FC5\u586B\uFF1B\u7F3A\u7701\u65F6\u81EA\u52A8\u53D6\u7B2C\u4E00\u6761 links[].url\uFF09"),
31086
+ // ── news_notice ──────────────────────────────────────────────
31087
+ image_url: import_zod17.z.string().optional().describe("\u5361\u7247\u56FE\u7247\uFF08news_notice\uFF09"),
31088
+ image_text: import_zod17.z.object({ title: import_zod17.z.string(), desc: import_zod17.z.string().optional(), url: import_zod17.z.string().optional() }).optional().describe("\u5DE6\u56FE\u53F3\u6587\u533A\u57DF\uFF08news_notice\uFF09"),
31089
+ vertical_items: import_zod17.z.array(import_zod17.z.object({ title: import_zod17.z.string(), desc: import_zod17.z.string().optional() })).max(4).optional().describe("\u5782\u76F4\u5185\u5BB9\u5217\u8868\uFF0C\u6700\u591A 4 \u6761\uFF08news_notice\uFF09"),
31090
+ // ── button_interaction ───────────────────────────────────────
31091
+ buttons: import_zod17.z.array(import_zod17.z.object({
31092
+ text: import_zod17.z.string().max(4).describe("\u6309\u94AE\u6587\u6848\uFF0C\u4E0D\u8D85\u8FC7 4 \u5B57"),
31093
+ key: import_zod17.z.string().describe("\u6309\u94AE key\uFF0C\u7528\u4E8E\u56DE\u8C03"),
31094
+ style: import_zod17.z.number().int().min(1).max(4).optional().describe("\u6309\u94AE\u6837\u5F0F 1-4")
31095
+ })).max(6).optional().describe("\u6309\u94AE\u5217\u8868\uFF0C\u6700\u591A 6 \u6761\uFF08button_interaction\uFF09"),
31096
+ // ── vote_interaction ─────────────────────────────────────────
31097
+ checkbox: import_zod17.z.object({
31098
+ question_key: import_zod17.z.string().describe("\u9009\u62E9\u9898 key"),
31099
+ option_list: import_zod17.z.array(optionSchema).max(20).describe("\u9009\u9879\u5217\u8868\uFF0C\u6700\u591A 20 \u4E2A")
31100
+ }).optional().describe("\u9009\u62E9\u9898\uFF08vote_interaction\uFF09"),
31101
+ submit_text: import_zod17.z.string().optional().describe("\u63D0\u4EA4\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4\u300C\u63D0\u4EA4\u300D"),
31102
+ // ── multiple_interaction ─────────────────────────────────────
31103
+ selections: import_zod17.z.array(import_zod17.z.object({
31104
+ question_key: import_zod17.z.string(),
31105
+ title: import_zod17.z.string().optional(),
31106
+ option_list: import_zod17.z.array(optionSchema).max(20)
31107
+ })).max(3).optional().describe("\u4E0B\u62C9\u9009\u62E9\u5668\u5217\u8868\uFF0C\u6700\u591A 3 \u4E2A\uFF08multiple_interaction\uFF09")
31108
+ });
31109
+ function assertUrl(url, field) {
31110
+ if (url === void 0) return;
31111
+ if (!/^https?:\/\/\S+$/i.test(url)) {
31112
+ throw new Error(`${field} \u5FC5\u987B\u662F http(s):// \u5F00\u5934\u7684\u53EF\u8BBF\u95EE\u94FE\u63A5\uFF0C\u6536\u5230\u300C${url}\u300D`);
31113
+ }
31114
+ }
31115
+ function newTaskId() {
31116
+ return `wecom-card-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
31117
+ }
31118
+ function buildTemplateCard(input) {
31119
+ if (!input.title.trim()) throw new Error("title \u4E0D\u80FD\u4E3A\u7A7A");
31120
+ assertUrl(input.action_url, "action_url");
31121
+ assertUrl(input.image_url, "image_url");
31122
+ input.links?.forEach((link, i) => assertUrl(link.url, `links[${i}].url`));
31123
+ input.items?.forEach((item, i) => assertUrl(item.url, `items[${i}].url`));
31124
+ assertUrl(input.image_text?.url, "image_text.url");
31125
+ const actionUrl = input.action_url ?? input.links?.[0]?.url;
31126
+ if (!actionUrl) {
31127
+ throw new Error(
31128
+ "\u5361\u7247\u5FC5\u987B\u63D0\u4F9B action_url\uFF08\u6574\u5361\u70B9\u51FB\u8DF3\u8F6C\uFF09\uFF0C\u6216\u81F3\u5C11\u4E00\u6761\u5E26 url \u7684 links \u2014\u2014 \u4F01\u5FAE\u8981\u6C42 card_action \u4E0D\u80FD\u4E3A\u7A7A"
31129
+ );
31130
+ }
31131
+ const card = {
31132
+ card_type: input.card_type,
31133
+ main_title: {
31134
+ title: input.title,
31135
+ ...input.desc ? { desc: input.desc } : {}
31136
+ },
31137
+ card_action: { type: 1, url: actionUrl }
31138
+ };
31139
+ if (input.source_desc) {
31140
+ card.source = {
31141
+ desc: input.source_desc,
31142
+ ...input.source_color !== void 0 ? { desc_color: input.source_color } : {}
31143
+ };
31144
+ }
31145
+ if (input.emphasis_title || input.emphasis_desc) {
31146
+ card.emphasis_content = {
31147
+ ...input.emphasis_title ? { title: input.emphasis_title } : {},
31148
+ ...input.emphasis_desc ? { desc: input.emphasis_desc } : {}
31149
+ };
31150
+ }
31151
+ if (input.subtitle) card.sub_title_text = input.subtitle;
31152
+ if (input.quote_text) card.quote_area = { type: 0, quote_text: input.quote_text };
31153
+ if (input.items?.length) {
31154
+ card.horizontal_content_list = input.items.map((item) => ({
31155
+ type: item.url ? 1 : 0,
31156
+ keyname: item.key,
31157
+ value: item.value,
31158
+ ...item.url ? { url: item.url } : {}
31159
+ }));
31160
+ }
31161
+ if (input.links?.length) {
31162
+ card.jump_list = input.links.map((link) => ({
31163
+ type: 1,
31164
+ url: link.url,
31165
+ title: link.title
31166
+ }));
31167
+ }
31168
+ if (input.card_type === "news_notice") {
31169
+ if (input.image_url) card.card_image = { url: input.image_url };
31170
+ if (input.image_text) {
31171
+ card.image_text_area = {
31172
+ type: input.image_text.url ? 1 : 0,
31173
+ ...input.image_text.url ? { url: input.image_text.url } : {},
31174
+ title: input.image_text.title,
31175
+ ...input.image_text.desc ? { desc: input.image_text.desc } : {}
31176
+ };
31177
+ }
31178
+ if (input.vertical_items?.length) {
31179
+ card.vertical_content_list = input.vertical_items.map((item) => ({
31180
+ title: item.title,
31181
+ ...item.desc ? { desc: item.desc } : {}
31182
+ }));
31183
+ }
31184
+ }
31185
+ if (input.card_type === "button_interaction") {
31186
+ if (!input.buttons?.length) throw new Error("button_interaction \u5FC5\u987B\u63D0\u4F9B buttons");
31187
+ card.button_list = input.buttons.map((button) => ({
31188
+ text: button.text,
31189
+ key: button.key,
31190
+ ...button.style !== void 0 ? { style: button.style } : {}
31191
+ }));
31192
+ card.task_id = newTaskId();
31193
+ }
31194
+ if (input.card_type === "vote_interaction") {
31195
+ if (!input.checkbox) throw new Error("vote_interaction \u5FC5\u987B\u63D0\u4F9B checkbox");
31196
+ card.checkbox = {
31197
+ question_key: input.checkbox.question_key,
31198
+ option_list: input.checkbox.option_list.map((option) => ({
31199
+ id: option.id,
31200
+ text: option.text,
31201
+ ...option.is_checked !== void 0 ? { is_checked: option.is_checked } : {}
31202
+ }))
31203
+ };
31204
+ card.submit_button = { text: input.submit_text ?? "\u63D0\u4EA4", type: 1, key: "submit" };
31205
+ card.task_id = newTaskId();
31206
+ }
31207
+ if (input.card_type === "multiple_interaction") {
31208
+ if (!input.selections?.length) throw new Error("multiple_interaction \u5FC5\u987B\u63D0\u4F9B selections");
31209
+ card.select_list = input.selections.map((selection) => ({
31210
+ question_key: selection.question_key,
31211
+ ...selection.title ? { title: selection.title } : {},
31212
+ option_list: selection.option_list.map((option) => ({
31213
+ id: option.id,
31214
+ text: option.text,
31215
+ ...option.is_checked !== void 0 ? { is_checked: option.is_checked } : {}
31216
+ }))
31217
+ }));
31218
+ card.submit_button = { text: input.submit_text ?? "\u63D0\u4EA4", type: 1, key: "submit" };
31219
+ card.task_id = newTaskId();
31220
+ }
31221
+ return card;
31222
+ }
31223
+ function readReplyKey(exeConfig) {
31224
+ const configurable = exeConfig?.configurable;
31225
+ const key = configurable?.runConfig?.wecomReplyKey;
31226
+ return typeof key === "string" && key.length > 0 ? key : void 0;
31227
+ }
31228
+ function registerWecomCardTool() {
31229
+ if ((0, import_core71.getToolLattice)("wecom_card")) return;
31230
+ (0, import_core71.registerToolLattice)(
31231
+ "wecom_card",
31232
+ {
31233
+ name: "wecom_card",
31234
+ description: "\u5728**\u4F01\u4E1A\u5FAE\u4FE1\u4F1A\u8BDD**\u4E2D\uFF0C\u628A\u672C\u8F6E\u56DE\u590D\u7684\u6838\u5FC3\u7ED3\u679C\u505A\u6210\u4E00\u5F20\u6A21\u677F\u5361\u7247\uFF0C\u5361\u7247\u4F1A\u5728\u672C\u6761\u56DE\u590D\u540E\u7531\u6E20\u9053\u81EA\u52A8\u53D1\u9001\u3002\n\n\u4E3B\u52A8\u4F7F\u7528\uFF08\u7528\u6237\u4E0D\u9700\u8981\u8BF4\u300C\u5361\u7247\u300D\u300C\u5361\u7247\u6D88\u606F\u300D\uFF09\uFF1A\u5F53\u56DE\u590D\u7684\u4E3B\u8981\u4EF7\u503C\u662F\u7ED3\u6784\u5316\u4E1A\u52A1\u5BF9\u8C61\u65F6 \u2014\u2014 \u5BA2\u6237\u4EA4\u63A5/\u6D3E\u5355\u3001\u544A\u8B66/\u5F02\u5E38/\u98CE\u9669\u3001\u6E05\u5355/\u6838\u5BF9\u8868\u3001\u5F85\u529E/\u884C\u52A8\u9879\u3001\u72B6\u6001/\u8FDB\u5EA6/\u6307\u6807\u6C47\u603B\u3001\u6295\u7968/\u9009\u62E9/\u786E\u8BA4\u3001\u9700\u8981\u70B9\u51FB\u8FDB\u5165\u7684\u94FE\u63A5/\u516C\u544A\u5165\u53E3\u3002\u53EA\u8981\u7ED3\u679C\u5177\u5907\u300C\u6807\u9898 + 1-6 \u6761\u952E\u503C\u660E\u7EC6\uFF08\u6216\u9009\u9879\uFF09+ \u4E00\u4E2A\u53EF\u8DF3\u8F6C\u94FE\u63A5\u300D\uFF0C\u5C31\u5E94\u8C03\u7528\u3002\n\n\u4E0D\u8981\u4F7F\u7528\uFF1A\u666E\u901A\u95EE\u7B54\u3001\u89E3\u91CA\u3001\u95F2\u804A\u3001\u957F\u6587\u5206\u6790\u3001\u4EE3\u7801\u3001\u6CA1\u6709\u660E\u786E\u8DF3\u8F6C\u76EE\u6807\u7684\u5BF9\u8BDD\u3001\u4E00\u53E5\u8BDD\u5C31\u80FD\u8BF4\u6E05\u7684\u7ED3\u679C\u3002\n\n\u8C03\u7528\u540E\u4ECD\u7528\u4E00\u4E24\u53E5\u8BDD\u603B\u7ED3\u7ED3\u8BBA\uFF1B\u4E0D\u8981\u518D\u8F93\u51FA JSON\uFF0C\u4E5F\u4E0D\u8981\u5199\u3010\u5361\u7247\u6D88\u606F\u3011\u3002\u6BCF\u6761\u56DE\u590D\u6700\u591A\u4E00\u5F20\u5361\u7247\uFF0C\u91CD\u590D\u8C03\u7528\u4F1A\u66FF\u6362\u4E0A\u4E00\u5F20\u3002\u8FD4\u56DE ERROR \u65F6\u6309\u63D0\u793A\u4FEE\u6B63\u540E\u91CD\u8BD5\uFF0C\u4E0D\u8981\u628A ERROR \u653E\u8FDB\u56DE\u590D\u3002\u5B50 agent \u4E0D\u8981\u8C03\u7528\u672C\u5DE5\u5177\u3002",
31235
+ schema
31236
+ },
31237
+ async (input, exeConfig) => {
31238
+ const replyKey = readReplyKey(exeConfig);
31239
+ if (!replyKey) {
31240
+ return "ERROR: wecom_card \u53EA\u80FD\u5728\u4F01\u4E1A\u5FAE\u4FE1\u5B9E\u65F6\u4F1A\u8BDD\u4E2D\u4F7F\u7528\uFF0C\u8BF7\u76F4\u63A5\u7528\u6587\u5B57\u56DE\u590D\u3002";
31241
+ }
31242
+ try {
31243
+ const card = buildTemplateCard(input);
31244
+ if (!putWecomCard(replyKey, card)) {
31245
+ return "ERROR: \u672C\u6761\u56DE\u590D\u5DF2\u7ED3\u675F\uFF0C\u65E0\u6CD5\u518D\u9644\u5E26\u5361\u7247\u3002\u8BF7\u628A\u7ED3\u679C\u5199\u5165\u6B63\u6587\u3002";
31246
+ }
31247
+ const title = card.main_title?.title;
31248
+ const suffix = typeof title === "string" && title ? `\u300C${title}\u300D` : "";
31249
+ return `\u5DF2\u751F\u6210\u4F01\u4E1A\u5FAE\u4FE1\u5361\u7247${suffix}\uFF0C\u5C06\u968F\u672C\u6761\u56DE\u590D\u81EA\u52A8\u53D1\u9001\u3002\u8BF7\u7528\u6587\u5B57\u603B\u7ED3\u7ED3\u8BBA\uFF0C\u4E0D\u8981\u91CD\u590D\u5361\u7247\u5185\u5BB9\u3002`;
31250
+ } catch (error) {
31251
+ return `ERROR: ${error instanceof Error ? error.message : String(error)}\u3002\u8BF7\u4FEE\u6B63\u53C2\u6570\u540E\u91CD\u65B0\u8C03\u7528 wecom_card\u3002`;
31252
+ }
31253
+ }
31254
+ );
31255
+ }
31256
+
30859
31257
  // src/channels/wecom/WecomChannelAdapter.ts
30860
31258
  init_Logger();
30861
31259
  var logger6 = new Logger({ serviceName: "lattice/gateway/wecom" });
30862
- var wecomConfigSchema = import_zod17.z.object({
30863
- botId: import_zod17.z.string(),
30864
- secret: import_zod17.z.string()
31260
+ var wecomConfigSchema = import_zod18.z.object({
31261
+ botId: import_zod18.z.string(),
31262
+ secret: import_zod18.z.string()
30865
31263
  });
30866
31264
  var RECONNECT_BASE_MS = 5e3;
30867
31265
  var RECONNECT_MAX_MS = 6e4;
31266
+ var SENT_CARD_TTL_MS = 10 * 6e4;
31267
+ var MAX_SENT_CARDS = 1e3;
30868
31268
  var activeConnections2 = /* @__PURE__ */ new Map();
30869
31269
  var streamIdsByReqId = /* @__PURE__ */ new Map();
30870
31270
  var MAX_TRACKED_STREAMS = 1e3;
30871
- function streamKeyOf(replyTarget) {
30872
- const frame = replyTarget.rawTarget.frame;
30873
- return frame?.headers?.req_id ?? replyTarget.channelInstallationId;
31271
+ var sentCardsByTaskId = /* @__PURE__ */ new Map();
31272
+ var handledCardEventKeys = /* @__PURE__ */ new Map();
31273
+ var ACKNOWLEDGED_TTL_MS = 10 * 6e4;
31274
+ function isRecord4(value) {
31275
+ return value !== null && typeof value === "object" && !Array.isArray(value);
31276
+ }
31277
+ function replyKeyOf(installationId, reqId) {
31278
+ return `${installationId}:${reqId ?? "no-req"}`;
31279
+ }
31280
+ function replyKeyForTarget(replyTarget) {
31281
+ const frame = replyTarget.rawTarget?.frame;
31282
+ return replyKeyOf(replyTarget.channelInstallationId, frame?.headers?.req_id);
31283
+ }
31284
+ function isEventReplyTarget(replyTarget) {
31285
+ return replyTarget.rawTarget?.kind === "template_card_event";
31286
+ }
31287
+ function eventChatId(replyTarget) {
31288
+ const chatId = replyTarget.rawTarget?.chatId;
31289
+ return typeof chatId === "string" && chatId.length > 0 ? chatId : void 0;
30874
31290
  }
30875
31291
  function streamIdFor(replyTarget) {
30876
- const key = streamKeyOf(replyTarget);
31292
+ const key = replyKeyForTarget(replyTarget);
30877
31293
  let streamId = streamIdsByReqId.get(key);
30878
31294
  if (!streamId) {
30879
31295
  streamId = (0, import_node_crypto27.randomUUID)();
@@ -30885,6 +31301,267 @@ function streamIdFor(replyTarget) {
30885
31301
  }
30886
31302
  return streamId;
30887
31303
  }
31304
+ function rememberSentCard(card) {
31305
+ const taskId = typeof card.task_id === "string" ? card.task_id : void 0;
31306
+ if (!taskId) return;
31307
+ const now = Date.now();
31308
+ for (const [key, entry] of sentCardsByTaskId) {
31309
+ if (entry.expiresAt <= now) sentCardsByTaskId.delete(key);
31310
+ }
31311
+ sentCardsByTaskId.set(taskId, { card, expiresAt: now + SENT_CARD_TTL_MS });
31312
+ while (sentCardsByTaskId.size > MAX_SENT_CARDS) {
31313
+ const oldest = sentCardsByTaskId.keys().next().value;
31314
+ if (oldest === void 0) break;
31315
+ sentCardsByTaskId.delete(oldest);
31316
+ }
31317
+ }
31318
+ function sentCardForTask(taskId) {
31319
+ if (!taskId) return void 0;
31320
+ const entry = sentCardsByTaskId.get(taskId);
31321
+ if (!entry) return void 0;
31322
+ if (entry.expiresAt <= Date.now()) {
31323
+ sentCardsByTaskId.delete(taskId);
31324
+ return void 0;
31325
+ }
31326
+ return entry.card;
31327
+ }
31328
+ function claimCardEvent(taskId, eventKey) {
31329
+ if (!taskId) return true;
31330
+ const key = `${taskId}:${eventKey ?? ""}`;
31331
+ const now = Date.now();
31332
+ for (const [handled, expiresAt] of handledCardEventKeys) {
31333
+ if (expiresAt <= now) handledCardEventKeys.delete(handled);
31334
+ }
31335
+ if (handledCardEventKeys.has(key)) return false;
31336
+ handledCardEventKeys.set(key, now + ACKNOWLEDGED_TTL_MS);
31337
+ while (handledCardEventKeys.size > MAX_SENT_CARDS) {
31338
+ const oldest = handledCardEventKeys.keys().next().value;
31339
+ if (oldest === void 0) break;
31340
+ handledCardEventKeys.delete(oldest);
31341
+ }
31342
+ return true;
31343
+ }
31344
+ async function sendStreamFrame(connection, replyTarget, input) {
31345
+ if (isEventReplyTarget(replyTarget)) {
31346
+ await sendEventReply(connection, replyTarget, input);
31347
+ return;
31348
+ }
31349
+ const frame = replyTarget.rawTarget?.frame;
31350
+ if (!frame) {
31351
+ logger6.warn("WeCom reply target has no inbound frame, skipping", {
31352
+ installationId: replyTarget.channelInstallationId
31353
+ });
31354
+ return;
31355
+ }
31356
+ const report = (message, error) => logger6.warn(message, {
31357
+ installationId: replyTarget.channelInstallationId,
31358
+ error: error instanceof Error ? error.message : String(error)
31359
+ });
31360
+ const text = input.text || (input.done ? input.card ? "\u5DF2\u5B8C\u6210\uFF0C\u8BE6\u60C5\u89C1\u4E0B\u65B9\u5361\u7247\u3002" : "\u5904\u7406\u5B8C\u6210\u3002" : "");
31361
+ if (!text) return;
31362
+ try {
31363
+ await Promise.resolve(connection.client.reply(frame, {
31364
+ msgtype: "stream",
31365
+ stream: { id: streamIdFor(replyTarget), finish: input.done, content: text }
31366
+ }));
31367
+ } catch (error) {
31368
+ report("WeCom stream reply failed", error);
31369
+ }
31370
+ if (input.done && input.card) {
31371
+ try {
31372
+ await Promise.resolve(connection.client.reply(frame, {
31373
+ msgtype: "template_card",
31374
+ template_card: input.card
31375
+ }));
31376
+ rememberSentCard(input.card);
31377
+ logger6.info("WeCom card sent", {
31378
+ installationId: replyTarget.channelInstallationId,
31379
+ cardType: input.card.card_type
31380
+ });
31381
+ } catch (error) {
31382
+ report("WeCom card reply failed (text already sent)", error);
31383
+ }
31384
+ }
31385
+ }
31386
+ async function sendEventReply(connection, replyTarget, input) {
31387
+ if (!input.done) return;
31388
+ const chatId = eventChatId(replyTarget);
31389
+ if (!chatId) {
31390
+ logger6.warn("WeCom card event has no chat id, cannot reply", {
31391
+ installationId: replyTarget.channelInstallationId
31392
+ });
31393
+ return;
31394
+ }
31395
+ const sendMessage2 = connection.client.sendMessage;
31396
+ if (!sendMessage2) {
31397
+ logger6.warn("WeCom client does not support sendMessage, cannot reply to card event", {
31398
+ installationId: replyTarget.channelInstallationId
31399
+ });
31400
+ return;
31401
+ }
31402
+ const report = (message, error) => logger6.warn(message, {
31403
+ installationId: replyTarget.channelInstallationId,
31404
+ error: error instanceof Error ? error.message : String(error)
31405
+ });
31406
+ if (input.card) {
31407
+ try {
31408
+ await Promise.resolve(sendMessage2.call(connection.client, chatId, {
31409
+ msgtype: "template_card",
31410
+ template_card: input.card
31411
+ }));
31412
+ rememberSentCard(input.card);
31413
+ logger6.info("WeCom card sent", {
31414
+ installationId: replyTarget.channelInstallationId,
31415
+ cardType: input.card.card_type
31416
+ });
31417
+ } catch (error) {
31418
+ report("WeCom card event card failed", error);
31419
+ }
31420
+ return;
31421
+ }
31422
+ if (input.text) {
31423
+ try {
31424
+ await Promise.resolve(sendMessage2.call(connection.client, chatId, {
31425
+ msgtype: "markdown",
31426
+ markdown: { content: input.text }
31427
+ }));
31428
+ } catch (error) {
31429
+ report("WeCom card event reply failed", error);
31430
+ }
31431
+ }
31432
+ }
31433
+ function acknowledgedCard(taskId, eventKey) {
31434
+ const desc = eventKey ? `\u5DF2\u6536\u5230\uFF1A${eventKey}` : "\u5DF2\u63D0\u4EA4\uFF0C\u6B63\u5728\u5904\u7406\u2026";
31435
+ const original = sentCardForTask(taskId);
31436
+ if (original) {
31437
+ const mainTitle = isRecord4(original.main_title) ? original.main_title : {};
31438
+ return { ...original, main_title: { ...mainTitle, desc } };
31439
+ }
31440
+ return {
31441
+ card_type: "text_notice",
31442
+ main_title: { title: "\u5DF2\u6536\u5230\u4F60\u7684\u64CD\u4F5C", desc },
31443
+ ...taskId ? { task_id: taskId } : {}
31444
+ };
31445
+ }
31446
+ function cardEventFields(event) {
31447
+ const nested = isRecord4(event?.template_card_event) ? event.template_card_event : event;
31448
+ const source = nested ?? {};
31449
+ return {
31450
+ cardEvent: source,
31451
+ taskId: typeof source.task_id === "string" ? source.task_id : void 0,
31452
+ eventKey: typeof source.event_key === "string" ? source.event_key : void 0,
31453
+ cardType: typeof source.card_type === "string" ? source.card_type : void 0
31454
+ };
31455
+ }
31456
+ function describeError(error) {
31457
+ if (error instanceof Error) return error.message;
31458
+ if (typeof error === "string") return error;
31459
+ try {
31460
+ return JSON.stringify(error);
31461
+ } catch {
31462
+ return String(error);
31463
+ }
31464
+ }
31465
+ function cardEventInbound(frame, installation, input) {
31466
+ const body = frame.body;
31467
+ const { cardEvent, taskId, eventKey, cardType } = cardEventFields(body.event);
31468
+ const summary = eventKey ? `\u7528\u6237\u70B9\u51FB\u4E86\u5361\u7247\u6309\u94AE\u300C${eventKey}\u300D${taskId ? `\uFF08task_id=${taskId}\uFF09` : ""}` : `\u7528\u6237\u63D0\u4EA4\u4E86\u5361\u7247\u64CD\u4F5C${taskId ? `\uFF08task_id=${taskId}\uFF09` : ""}\uFF1A${JSON.stringify(cardEvent)}`;
31469
+ return {
31470
+ channel: "wecom",
31471
+ channelInstallationId: installation.id,
31472
+ tenantId: installation.tenantId,
31473
+ sender: { id: input.userId },
31474
+ content: {
31475
+ text: summary,
31476
+ metadata: {
31477
+ messageId: body.msgid,
31478
+ chatId: input.chatId,
31479
+ chatType: body.chattype === "group" ? "group" : "direct",
31480
+ taskId,
31481
+ eventKey,
31482
+ cardType,
31483
+ cardEvent,
31484
+ wecomReplyKey: replyKeyOf(installation.id, frame.headers.req_id)
31485
+ }
31486
+ },
31487
+ conversation: {
31488
+ id: input.chatId,
31489
+ type: body.chattype === "group" ? "group" : "direct"
31490
+ },
31491
+ replyTarget: {
31492
+ adapterChannel: "wecom",
31493
+ channelInstallationId: installation.id,
31494
+ rawTarget: { kind: "template_card_event", frame, chatId: input.chatId }
31495
+ }
31496
+ };
31497
+ }
31498
+ function handleTemplateCardEvent(rawFrame, installation, client, router) {
31499
+ const frame = rawFrame;
31500
+ const body = frame?.body;
31501
+ const event = body?.event;
31502
+ const reqId = frame?.headers?.req_id;
31503
+ if (!body || event?.eventtype !== "template_card_event" || typeof reqId !== "string") {
31504
+ return;
31505
+ }
31506
+ const userId = body.from?.userid;
31507
+ const chatId = typeof body.chatid === "string" && body.chatid ? body.chatid : userId;
31508
+ if (!userId || !chatId) {
31509
+ logger6.warn("WeCom card event missing user/chat id, skipping", {
31510
+ installationId: installation.id
31511
+ });
31512
+ return;
31513
+ }
31514
+ const { taskId, eventKey } = cardEventFields(event);
31515
+ if (!claimCardEvent(taskId, eventKey)) {
31516
+ logger6.info("WeCom duplicate card event ignored", {
31517
+ installationId: installation.id,
31518
+ taskId,
31519
+ eventKey
31520
+ });
31521
+ return;
31522
+ }
31523
+ const updateTemplateCard = client.updateTemplateCard;
31524
+ if (updateTemplateCard) {
31525
+ const updated = acknowledgedCard(taskId, eventKey);
31526
+ try {
31527
+ void Promise.resolve(updateTemplateCard.call(client, rawFrame, updated)).catch((error) => {
31528
+ logger6.warn("WeCom template card update failed", {
31529
+ installationId: installation.id,
31530
+ error: describeError(error)
31531
+ });
31532
+ });
31533
+ } catch (error) {
31534
+ logger6.warn("WeCom template card update failed", {
31535
+ installationId: installation.id,
31536
+ error: describeError(error)
31537
+ });
31538
+ }
31539
+ } else {
31540
+ logger6.warn("WeCom client does not support updateTemplateCard", {
31541
+ installationId: installation.id
31542
+ });
31543
+ }
31544
+ if (!router) return;
31545
+ logger6.info("WeCom card event dispatched", {
31546
+ installationId: installation.id,
31547
+ taskId,
31548
+ eventKey,
31549
+ chatId
31550
+ });
31551
+ try {
31552
+ void router.dispatch(cardEventInbound(frame, installation, { chatId, userId })).catch((error) => {
31553
+ logger6.error("WeCom card event dispatch error", {
31554
+ installationId: installation.id,
31555
+ error: describeError(error)
31556
+ });
31557
+ });
31558
+ } catch (error) {
31559
+ logger6.error("WeCom card event dispatch error", {
31560
+ installationId: installation.id,
31561
+ error: describeError(error)
31562
+ });
31563
+ }
31564
+ }
30888
31565
  var wecomChannelAdapter = {
30889
31566
  channel: "wecom",
30890
31567
  configSchema: wecomConfigSchema,
@@ -30898,11 +31575,13 @@ var wecomChannelAdapter = {
30898
31575
  sender: { id: parsed.fromUserId },
30899
31576
  content: {
30900
31577
  text: parsed.text,
30901
- // `messageId` 供去重中间件使用(企业微信可能重投同一 msgid)。
31578
+ // `messageId` 供去重中间件使用(企业微信可能重投同一 msgid);
31579
+ // `wecomReplyKey` 供 `wecom_card` 工具登记本轮卡片。
30902
31580
  metadata: {
30903
31581
  messageId: parsed.msgId,
30904
31582
  chatId: parsed.chatId,
30905
- chatType: parsed.chatType
31583
+ chatType: parsed.chatType,
31584
+ wecomReplyKey: replyKeyOf(installation.id, parsed.reqId)
30906
31585
  }
30907
31586
  },
30908
31587
  conversation: {
@@ -30926,14 +31605,12 @@ var wecomChannelAdapter = {
30926
31605
  });
30927
31606
  return;
30928
31607
  }
30929
- const key = streamKeyOf(replyTarget);
30930
- connection.client.reply(replyTarget.rawTarget.frame, {
30931
- msgtype: "stream",
30932
- stream: {
30933
- id: streamIdFor(replyTarget),
30934
- finish: true,
30935
- content: message.text
30936
- }
31608
+ const key = replyKeyForTarget(replyTarget);
31609
+ const card = takeWecomCard(key);
31610
+ await sendStreamFrame(connection, replyTarget, {
31611
+ text: message.text,
31612
+ done: true,
31613
+ card
30937
31614
  });
30938
31615
  streamIdsByReqId.delete(key);
30939
31616
  },
@@ -30952,15 +31629,21 @@ var wecomChannelAdapter = {
30952
31629
  });
30953
31630
  return;
30954
31631
  }
30955
- connection.client.reply(replyTarget.rawTarget.frame, {
30956
- msgtype: "stream",
30957
- stream: {
30958
- id: streamIdFor(replyTarget),
30959
- finish: chunk.done,
30960
- content: chunk.text
31632
+ const key = replyKeyForTarget(replyTarget);
31633
+ let card;
31634
+ if (chunk.done) {
31635
+ if (chunk.reason !== void 0 && chunk.reason !== "completed") {
31636
+ discardWecomCard(key);
31637
+ } else {
31638
+ card = takeWecomCard(key);
30961
31639
  }
31640
+ }
31641
+ await sendStreamFrame(connection, replyTarget, {
31642
+ text: chunk.text,
31643
+ done: chunk.done,
31644
+ card
30962
31645
  });
30963
- if (chunk.done) streamIdsByReqId.delete(streamKeyOf(replyTarget));
31646
+ if (chunk.done) streamIdsByReqId.delete(key);
30964
31647
  },
30965
31648
  resolveThreadId(message, binding) {
30966
31649
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -30994,6 +31677,9 @@ var wecomChannelAdapter = {
30994
31677
  });
30995
31678
  });
30996
31679
  });
31680
+ client.on("event.template_card_event", (frame) => {
31681
+ handleTemplateCardEvent(frame, installation, client, router);
31682
+ });
30997
31683
  client.on("authenticated", () => {
30998
31684
  connection.attempts = 0;
30999
31685
  });
@@ -31130,7 +31816,7 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
31130
31816
 
31131
31817
  // src/services/agent_task_consumer.ts
31132
31818
  var import_node_crypto28 = require("crypto");
31133
- var import_core71 = require("@axiom-lattice/core");
31819
+ var import_core72 = require("@axiom-lattice/core");
31134
31820
  var import_protocols32 = require("@axiom-lattice/protocols");
31135
31821
  var handleAgentTask = async (taskRequest, retryCount = 0) => {
31136
31822
  const {
@@ -31150,7 +31836,7 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
31150
31836
  `\u5F00\u59CB\u5904\u7406\u4EFB\u52A1 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
31151
31837
  );
31152
31838
  const scope = (0, import_protocols32.resolveRunScope)(runConfig);
31153
- const agent = import_core71.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: scope.workspaceId, project_id: scope.projectId, custom_run_config: runConfig });
31839
+ const agent = import_core72.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: scope.workspaceId, project_id: scope.projectId, custom_run_config: runConfig });
31154
31840
  if (callback_event) {
31155
31841
  const callbackEvent = callback_event;
31156
31842
  const messageId = typeof input?.id === "string" && input.id !== "" ? input.id : (0, import_node_crypto28.randomUUID)();
@@ -31171,13 +31857,13 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
31171
31857
  const onCompleted = (evt) => {
31172
31858
  if (!belongsToMessage(evt)) return;
31173
31859
  settle(() => {
31174
- import_core71.eventBus.publish(callbackEvent, {
31860
+ import_core72.eventBus.publish(callbackEvent, {
31175
31861
  success: true,
31176
31862
  state: evt.state
31177
31863
  });
31178
31864
  if (main_thread_id && main_tenant_id) {
31179
31865
  try {
31180
- const mainAgent = import_core71.agentInstanceManager.getAgent({
31866
+ const mainAgent = import_core72.agentInstanceManager.getAgent({
31181
31867
  assistant_id: main_assistant_id ?? assistant_id,
31182
31868
  thread_id: main_thread_id,
31183
31869
  tenant_id: main_tenant_id,
@@ -31210,7 +31896,7 @@ ${summary}`
31210
31896
  const onInterrupted = (evt) => {
31211
31897
  if (!belongsToMessage(evt)) return;
31212
31898
  settle(() => {
31213
- import_core71.eventBus.publish(callbackEvent, {
31899
+ import_core72.eventBus.publish(callbackEvent, {
31214
31900
  success: true,
31215
31901
  state: evt.state
31216
31902
  });
@@ -31219,7 +31905,7 @@ ${summary}`
31219
31905
  const onFailed = (evt) => {
31220
31906
  if (!belongsToMessage(evt)) return;
31221
31907
  settle(() => {
31222
- import_core71.eventBus.publish(callbackEvent, {
31908
+ import_core72.eventBus.publish(callbackEvent, {
31223
31909
  success: false,
31224
31910
  error: evt?.error instanceof Error ? evt.error.message : typeof evt?.error === "string" ? evt.error : "Agent execution failed"
31225
31911
  });
@@ -31234,13 +31920,13 @@ ${summary}`
31234
31920
  agent.subscribe("message:interrupted", onInterrupted);
31235
31921
  agent.subscribe("message:failed", onFailed);
31236
31922
  try {
31237
- await agent.addMessage({ input: { ...input, id: messageId }, command, custom_run_config: runConfig }, import_core71.QueueMode.STEER);
31923
+ await agent.addMessage({ input: { ...input, id: messageId }, command, custom_run_config: runConfig }, import_core72.QueueMode.STEER);
31238
31924
  } catch (error) {
31239
31925
  dispose();
31240
31926
  throw error;
31241
31927
  }
31242
31928
  } else {
31243
- await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core71.QueueMode.STEER);
31929
+ await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core72.QueueMode.STEER);
31244
31930
  }
31245
31931
  return true;
31246
31932
  } catch (error) {
@@ -31259,7 +31945,7 @@ ${summary}`
31259
31945
  return handleAgentTask(taskRequest, nextRetryCount);
31260
31946
  }
31261
31947
  if (callback_event) {
31262
- import_core71.eventBus.publish(callback_event, {
31948
+ import_core72.eventBus.publish(callback_event, {
31263
31949
  success: false,
31264
31950
  error: error instanceof Error ? error.message : String(error)
31265
31951
  });
@@ -31296,7 +31982,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
31296
31982
  * 初始化事件监听和队列轮询
31297
31983
  */
31298
31984
  initialize() {
31299
- import_core71.eventBus.subscribe(import_core71.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
31985
+ import_core72.eventBus.subscribe(import_core72.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
31300
31986
  this.startPollingQueue();
31301
31987
  console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
31302
31988
  }
@@ -31415,7 +32101,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
31415
32101
  handleAgentTask(taskRequest).catch((error) => {
31416
32102
  console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
31417
32103
  if (taskRequest.callback_event) {
31418
- import_core71.eventBus.publish(taskRequest.callback_event, {
32104
+ import_core72.eventBus.publish(taskRequest.callback_event, {
31419
32105
  success: false,
31420
32106
  error: error instanceof Error ? error.message : String(error)
31421
32107
  });
@@ -31464,13 +32150,13 @@ function createGracefulShutdown(options) {
31464
32150
  }
31465
32151
 
31466
32152
  // src/index.ts
31467
- var import_core99 = require("@axiom-lattice/core");
32153
+ var import_core100 = require("@axiom-lattice/core");
31468
32154
 
31469
32155
  // src/channels/ChannelInfrastructure.ts
31470
- var import_core73 = require("@axiom-lattice/core");
32156
+ var import_core74 = require("@axiom-lattice/core");
31471
32157
 
31472
32158
  // src/router/MessageRouter.ts
31473
- var import_core72 = require("@axiom-lattice/core");
32159
+ var import_core73 = require("@axiom-lattice/core");
31474
32160
  var import_protocols33 = require("@axiom-lattice/protocols");
31475
32161
  var import_crypto11 = require("crypto");
31476
32162
  var BindingNotFoundError = class extends Error {
@@ -31486,6 +32172,7 @@ var ChannelInstallationNotFoundError = class extends Error {
31486
32172
  }
31487
32173
  };
31488
32174
  var DEFAULT_STREAM_PLACEHOLDER = "\u6B63\u5728\u5904\u7406\u2026";
32175
+ var DEFAULT_STREAM_FAILURE_TEXT = "\u5904\u7406\u672A\u5B8C\u6210\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
31489
32176
  function streamPlaceholderFor(installation) {
31490
32177
  const config = installation?.config;
31491
32178
  if (config !== null && typeof config === "object" && !Array.isArray(config)) {
@@ -31494,6 +32181,14 @@ function streamPlaceholderFor(installation) {
31494
32181
  }
31495
32182
  return DEFAULT_STREAM_PLACEHOLDER;
31496
32183
  }
32184
+ function streamFailureTextFor(installation) {
32185
+ const config = installation?.config;
32186
+ if (config !== null && typeof config === "object" && !Array.isArray(config)) {
32187
+ const value = config.streamFailureText;
32188
+ if (typeof value === "string") return value;
32189
+ }
32190
+ return DEFAULT_STREAM_FAILURE_TEXT;
32191
+ }
31497
32192
  var InvalidChannelInstallationError = class extends Error {
31498
32193
  constructor(message = "Channel installation is not valid for this message") {
31499
32194
  super(message);
@@ -31765,7 +32460,7 @@ var _MessageRouter = class _MessageRouter {
31765
32460
  channel: message.channel,
31766
32461
  adapterChannel: adapter.channel
31767
32462
  }, "Thread resolved by adapter strategy");
31768
- const threadStore = (0, import_core72.getStoreLattice)("default", "thread").store;
32463
+ const threadStore = (0, import_core73.getStoreLattice)("default", "thread").store;
31769
32464
  try {
31770
32465
  await threadStore.createThread(
31771
32466
  tenantId,
@@ -31802,7 +32497,7 @@ var _MessageRouter = class _MessageRouter {
31802
32497
  }
31803
32498
  }
31804
32499
  if (!threadId) {
31805
- const threadStore = (0, import_core72.getStoreLattice)("default", "thread").store;
32500
+ const threadStore = (0, import_core73.getStoreLattice)("default", "thread").store;
31806
32501
  const newThreadId = (0, import_crypto11.randomUUID)();
31807
32502
  console.log({
31808
32503
  event: "dispatch:thread:create",
@@ -31842,7 +32537,7 @@ var _MessageRouter = class _MessageRouter {
31842
32537
  senderId: message.sender.id,
31843
32538
  contentLength: message.content.text.length
31844
32539
  }, "Dispatching to agent");
31845
- const agent = import_core72.agentInstanceManager.getAgent({
32540
+ const agent = import_core73.agentInstanceManager.getAgent({
31846
32541
  tenant_id: tenantId,
31847
32542
  assistant_id: agentId,
31848
32543
  thread_id: threadId,
@@ -31905,7 +32600,13 @@ var _MessageRouter = class _MessageRouter {
31905
32600
  if (cleaned || !event.consumedInputMessageIds.includes(inputMessageId)) return;
31906
32601
  cleanup();
31907
32602
  if (event.inputMessageId !== inputMessageId) return;
31908
- const delivery = replyAdapter.sendStreamChunk ? streamState.finished ? void 0 : replyAdapter.sendStreamChunk(replyTarget, { text: event.outputText, done: true }, installation) : replyAdapter.sendReply(replyTarget, {
32603
+ if (replyAdapter.sendStreamChunk && streamState.finished) return;
32604
+ if (replyAdapter.sendStreamChunk) streamState.finished = true;
32605
+ const delivery = replyAdapter.sendStreamChunk ? replyAdapter.sendStreamChunk(
32606
+ replyTarget,
32607
+ { text: event.outputText, done: true, reason: "completed" },
32608
+ installation
32609
+ ) : replyAdapter.sendReply(replyTarget, {
31909
32610
  text: event.outputText,
31910
32611
  metadata: { inputMessageId, outputMessageId: event.outputMessageId }
31911
32612
  }, installation);
@@ -32029,17 +32730,34 @@ var _MessageRouter = class _MessageRouter {
32029
32730
  const send = adapter.sendStreamChunk;
32030
32731
  if (!send) return;
32031
32732
  let started = false;
32733
+ let normalEnd = false;
32032
32734
  let accumulated = "";
32033
32735
  let lastSentText = "";
32034
32736
  let lastSentAt = 0;
32035
32737
  let sent = 0;
32036
32738
  const warn = (event, error) => console.warn({ event, inputMessageId, error: error instanceof Error ? error.message : String(error) });
32037
- const push = (text, done) => send.call(adapter, replyTarget, { text, done }, installation).catch((error) => warn("dispatch:stream:failed", error));
32739
+ const push = (text, done, reason) => send.call(
32740
+ adapter,
32741
+ replyTarget,
32742
+ reason ? { text, done, reason } : { text, done },
32743
+ installation
32744
+ ).catch((error) => warn("dispatch:stream:failed", error));
32038
32745
  const placeholder = streamPlaceholderFor(installation);
32746
+ const closeWith = async (reason) => {
32747
+ if (state.finished) return;
32748
+ state.finished = true;
32749
+ const text = accumulated || (reason === "completed" ? "" : streamFailureTextFor(installation) || placeholder);
32750
+ await push(text, true, reason);
32751
+ };
32752
+ const timer = setTimeout(() => {
32753
+ void closeWith("timeout");
32754
+ }, _MessageRouter.STREAM_TIMEOUT_MS);
32755
+ timer.unref?.();
32039
32756
  try {
32040
32757
  if (placeholder) await push(placeholder, false);
32041
32758
  const stream = agent.chunkStream(inputMessageId, []);
32042
32759
  for await (const chunk of stream) {
32760
+ if (state.finished) break;
32043
32761
  if (!started) {
32044
32762
  if (chunk?.type === import_protocols33.MessageChunkTypes.HUMAN && chunk?.data?.id === inputMessageId) {
32045
32763
  started = true;
@@ -32047,12 +32765,19 @@ var _MessageRouter = class _MessageRouter {
32047
32765
  continue;
32048
32766
  }
32049
32767
  if (chunk?.type === import_protocols33.MessageChunkTypes.MESSAGE_COMPLETED || chunk?.type === import_protocols33.MessageChunkTypes.MESSAGE_FAILED || chunk?.type === import_protocols33.MessageChunkTypes.INTERRUPT) {
32050
- if (chunk.type !== import_protocols33.MessageChunkTypes.MESSAGE_COMPLETED) {
32051
- const text2 = accumulated || placeholder;
32052
- if (text2) {
32053
- await push(text2, true);
32054
- state.finished = true;
32055
- }
32768
+ if (chunk.type === import_protocols33.MessageChunkTypes.MESSAGE_COMPLETED) {
32769
+ normalEnd = true;
32770
+ const grace = setTimeout(
32771
+ () => {
32772
+ void closeWith("completed");
32773
+ },
32774
+ _MessageRouter.COMPLETION_GRACE_MS
32775
+ );
32776
+ grace.unref?.();
32777
+ } else if (chunk.type === import_protocols33.MessageChunkTypes.MESSAGE_FAILED) {
32778
+ await closeWith("failed");
32779
+ } else {
32780
+ await closeWith("interrupted");
32056
32781
  }
32057
32782
  break;
32058
32783
  }
@@ -32072,7 +32797,11 @@ var _MessageRouter = class _MessageRouter {
32072
32797
  }
32073
32798
  } catch (error) {
32074
32799
  warn("dispatch:stream:error", error);
32800
+ await closeWith("failed");
32801
+ } finally {
32802
+ clearTimeout(timer);
32075
32803
  }
32804
+ if (!normalEnd) await closeWith("failed");
32076
32805
  }
32077
32806
  /**
32078
32807
  * Projects a pending HITL interrupt into the room as an independent bot message.
@@ -32097,15 +32826,30 @@ var _MessageRouter = class _MessageRouter {
32097
32826
  }
32098
32827
  }
32099
32828
  };
32100
- /** 流式中途刷新的节流间隔与上限(微信单会话 30 条/分钟,留余量)。 */
32101
- _MessageRouter.STREAM_CHUNK_INTERVAL_MS = 800;
32102
- _MessageRouter.MAX_STREAM_CHUNKS = 60;
32829
+ /**
32830
+ * 流式中途刷新的节流间隔与上限。
32831
+ *
32832
+ * 企业微信单会话限制 30 条/分钟(含占位、收尾和卡片)。2500ms 约 24 次
32833
+ * 刷新/分钟,再加最多 3 条生命周期消息仍留有余量。
32834
+ */
32835
+ _MessageRouter.STREAM_CHUNK_INTERVAL_MS = 2500;
32836
+ _MessageRouter.MAX_STREAM_CHUNKS = 190;
32837
+ /** 流式回复的硬超时:企微要求 10 分钟内 `finish=true`,留 2 分钟余量。 */
32838
+ _MessageRouter.STREAM_TIMEOUT_MS = 8 * 6e4;
32839
+ /**
32840
+ * `MESSAGE_COMPLETED` 后等待 `reply:ready` 的宽限。
32841
+ *
32842
+ * 正常完成通常由 `reply:ready` 用权威全文收尾;但最终 AI 消息为空时
32843
+ * (例如模型只调用了 `wecom_card`、没有产出文字)不会触发 `reply:ready`,
32844
+ * 这里兜底自行收尾,避免流挂住、卡片丢失。
32845
+ */
32846
+ _MessageRouter.COMPLETION_GRACE_MS = 3e3;
32103
32847
  var MessageRouter = _MessageRouter;
32104
32848
 
32105
32849
  // src/channels/room/RoomChannelAdapter.ts
32106
- var import_zod18 = require("zod");
32850
+ var import_zod19 = require("zod");
32107
32851
  var import_protocols34 = require("@axiom-lattice/protocols");
32108
- var roomConfigSchema = import_zod18.z.object({}).strict();
32852
+ var roomConfigSchema = import_zod19.z.object({}).strict();
32109
32853
  function createRoomChannelAdapter(writer) {
32110
32854
  return {
32111
32855
  channel: "room",
@@ -32202,7 +32946,7 @@ function createChannelInfrastructure(deps) {
32202
32946
  onMessageCommitted: deps.onMessageCommitted ?? (deps.realtime ? (message) => deps.realtime?.messageCreated(message) : void 0),
32203
32947
  onCallbackFailure: (event) => deps.warn("project-room:message-commit-callback-failed", event)
32204
32948
  };
32205
- deps.adapterRegistry.register(createRoomChannelAdapter(new import_core73.RoomAgentMessageService(writerDeps)));
32949
+ deps.adapterRegistry.register(createRoomChannelAdapter(new import_core74.RoomAgentMessageService(writerDeps)));
32206
32950
  } catch (error) {
32207
32951
  deps.warn("Room channel unavailable", { error: error instanceof Error ? error.message : String(error) });
32208
32952
  }
@@ -32226,11 +32970,11 @@ async function prepareProjectTaskRuntime(runtime, log2) {
32226
32970
  }
32227
32971
 
32228
32972
  // src/services/plugins/PluginDeploymentRuntimeStartup.ts
32229
- var import_core76 = require("@axiom-lattice/core");
32973
+ var import_core77 = require("@axiom-lattice/core");
32230
32974
 
32231
32975
  // src/services/plugins/PluginDeploymentService.ts
32232
32976
  var import_node_crypto30 = require("crypto");
32233
- var import_core75 = require("@axiom-lattice/core");
32977
+ var import_core76 = require("@axiom-lattice/core");
32234
32978
 
32235
32979
  // src/services/plugins/pluginDeploymentNaming.ts
32236
32980
  var import_node_crypto29 = require("crypto");
@@ -32248,7 +32992,7 @@ function pluginSandboxName(tenantId, pluginType) {
32248
32992
  }
32249
32993
 
32250
32994
  // src/services/plugins/PluginDeploymentService.ts
32251
- var PLUGIN_HOST_SERVER_PATH = `${import_core75.PLUGIN_HOST_DIR}/server.js`;
32995
+ var PLUGIN_HOST_SERVER_PATH = `${import_core76.PLUGIN_HOST_DIR}/server.js`;
32252
32996
  var DEFAULT_PLUGIN_IDLE_TIMEOUT_MS = 15 * 60 * 1e3;
32253
32997
  var DEFAULT_PLUGIN_HEALTH_TIMEOUT_MS = 3e4;
32254
32998
  var DEFAULT_PLUGIN_HEALTH_POLL_INTERVAL_MS = 500;
@@ -32267,7 +33011,7 @@ var PluginDeploymentError = class extends Error {
32267
33011
  this.code = code;
32268
33012
  }
32269
33013
  };
32270
- function isRecord4(value) {
33014
+ function isRecord5(value) {
32271
33015
  return typeof value === "object" && value !== null && !Array.isArray(value);
32272
33016
  }
32273
33017
  function buildBootstrapEntrypoint(pluginType) {
@@ -32287,7 +33031,7 @@ var PluginDeploymentService = class {
32287
33031
  this.catalog = deps.catalog;
32288
33032
  this.installPluginHost = deps.installPluginHost;
32289
33033
  this.lease = deps.lease;
32290
- this.registry = deps.registry ?? new import_core75.PluginDeploymentRuntimeRegistry({ now: deps.clock ?? Date.now });
33034
+ this.registry = deps.registry ?? new import_core76.PluginDeploymentRuntimeRegistry({ now: deps.clock ?? Date.now });
32291
33035
  this.now = deps.clock ?? Date.now;
32292
33036
  this.logger = deps.logger ?? { info: () => void 0 };
32293
33037
  this.limits = deps.limits ?? {};
@@ -32821,7 +33565,7 @@ var PluginDeploymentService = class {
32821
33565
  return { ok: false, error: `health responded with HTTP ${response.status}` };
32822
33566
  }
32823
33567
  const body = await response.json().catch(() => void 0);
32824
- if (isRecord4(body) && body.ok === true) {
33568
+ if (isRecord5(body) && body.ok === true) {
32825
33569
  return { ok: true };
32826
33570
  }
32827
33571
  return { ok: false, error: "health returned an invalid envelope" };
@@ -33004,7 +33748,7 @@ function startPluginDeploymentRuntime(options) {
33004
33748
  );
33005
33749
  return { reconcile: Promise.resolve(), dispose: async () => void 0 };
33006
33750
  }
33007
- const register = options.register ?? ((service3) => (0, import_core76.setPluginDeploymentService)(service3));
33751
+ const register = options.register ?? ((service3) => (0, import_core77.setPluginDeploymentService)(service3));
33008
33752
  const setIntervalFn = options.setIntervalFn ?? setInterval;
33009
33753
  const clearIntervalFn = options.clearIntervalFn ?? clearInterval;
33010
33754
  const watchdogIntervalMs = options.watchdogIntervalMs ?? DEFAULT_PLUGIN_WATCHDOG_INTERVAL_MS;
@@ -33287,11 +34031,11 @@ var DEFAULT_LOGGER_CONFIG = {
33287
34031
  var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
33288
34032
  var logger8 = loggerLattice.client;
33289
34033
  function initializeLogger(config) {
33290
- if (import_core99.loggerLatticeManager.hasLattice("default")) {
33291
- import_core99.loggerLatticeManager.removeLattice("default");
34034
+ if (import_core100.loggerLatticeManager.hasLattice("default")) {
34035
+ import_core100.loggerLatticeManager.removeLattice("default");
33292
34036
  }
33293
- (0, import_core99.registerLoggerLattice)("default", config);
33294
- return (0, import_core99.getLoggerLattice)("default");
34037
+ (0, import_core100.registerLoggerLattice)("default", config);
34038
+ return (0, import_core100.getLoggerLattice)("default");
33295
34039
  }
33296
34040
  var app = (0, import_fastify.default)({
33297
34041
  logger: false,
@@ -33389,7 +34133,7 @@ app.setErrorHandler((error, request, reply) => {
33389
34133
  var shutdownHandlersInstalled = false;
33390
34134
  function getConfiguredSandboxProvider() {
33391
34135
  const sandboxProviderType = process.env.SANDBOX_PROVIDER_TYPE || "microsandbox-remote";
33392
- return (0, import_core99.createSandboxProvider)({
34136
+ return (0, import_core100.createSandboxProvider)({
33393
34137
  type: sandboxProviderType,
33394
34138
  remoteBaseURL: process.env.SANDBOX_BASE_URL,
33395
34139
  microsandboxServiceBaseURL: process.env.MICROSANDBOX_SERVICE_BASE_URL,
@@ -33405,7 +34149,7 @@ function getConfiguredSandboxProvider() {
33405
34149
  }
33406
34150
  async function restoreMcpConnections() {
33407
34151
  try {
33408
- const storeLattice = (0, import_core99.getStoreLattice)("default", "mcp");
34152
+ const storeLattice = (0, import_core100.getStoreLattice)("default", "mcp");
33409
34153
  const store2 = storeLattice.store;
33410
34154
  if (!store2) {
33411
34155
  logger8.info("MCP store not configured, skipping connection restoration");
@@ -33418,8 +34162,8 @@ async function restoreMcpConnections() {
33418
34162
  logger8.info(`Restoring ${configs.length} MCP server connections...`);
33419
34163
  const deps = {
33420
34164
  store: store2,
33421
- manager: import_core99.mcpManager,
33422
- convertToConnection: import_core99.convertToConnection
34165
+ manager: import_core100.mcpManager,
34166
+ convertToConnection: import_core100.convertToConnection
33423
34167
  };
33424
34168
  const results = await Promise.allSettled(
33425
34169
  configs.map(
@@ -33460,9 +34204,9 @@ var start = async (config) => {
33460
34204
  let projectRoomRealtimeRuntime;
33461
34205
  if (projectRoomRealtimeMode === "single-gateway") {
33462
34206
  projectRoomRealtimeRuntime = createProjectRoomRealtimeRuntime({
33463
- tasks: (0, import_core99.getStoreLattice)("default", "task").store,
33464
- rooms: (0, import_core99.getStoreLattice)("default", "projectRoom").store,
33465
- memberships: (0, import_core99.getStoreLattice)("default", "projectBotMembership").store,
34207
+ tasks: (0, import_core100.getStoreLattice)("default", "task").store,
34208
+ rooms: (0, import_core100.getStoreLattice)("default", "projectRoom").store,
34209
+ memberships: (0, import_core100.getStoreLattice)("default", "projectBotMembership").store,
33466
34210
  log: { warn: (message, context) => logger8.warn(message, context) }
33467
34211
  });
33468
34212
  }
@@ -33470,13 +34214,14 @@ var start = async (config) => {
33470
34214
  const adapterRegistry = new ChannelAdapterRegistry();
33471
34215
  adapterRegistry.register(larkChannelAdapter);
33472
34216
  adapterRegistry.register(wecomChannelAdapter);
34217
+ registerWecomCardTool();
33473
34218
  const { wechatChannelAdapter: wechatChannelAdapter2 } = await Promise.resolve().then(() => (init_WechatChannelAdapter(), WechatChannelAdapter_exports));
33474
34219
  adapterRegistry.register(wechatChannelAdapter2);
33475
34220
  try {
33476
34221
  const infrastructure = createChannelInfrastructure({
33477
34222
  adapterRegistry,
33478
- getStore: ((kind) => (0, import_core99.getStoreLattice)("default", kind).store),
33479
- trustedDispatcher: (0, import_core99.createTrustedAgentMessageDispatcher)((scope) => import_core99.agentInstanceManager.getAgent(scope)),
34223
+ getStore: ((kind) => (0, import_core100.getStoreLattice)("default", kind).store),
34224
+ trustedDispatcher: (0, import_core100.createTrustedAgentMessageDispatcher)((scope) => import_core100.agentInstanceManager.getAgent(scope)),
33480
34225
  middlewares: [
33481
34226
  createDeduplicationMiddleware(),
33482
34227
  createRateLimitMiddleware(),
@@ -33487,7 +34232,7 @@ var start = async (config) => {
33487
34232
  });
33488
34233
  const bindingStore = infrastructure.bindingRegistry;
33489
34234
  const installationStore = infrastructure.installationStore;
33490
- (0, import_core98.setBindingRegistry)(bindingStore);
34235
+ (0, import_core99.setBindingRegistry)(bindingStore);
33491
34236
  const router = infrastructure.router;
33492
34237
  app.addHook("onClose", async () => router.dispose());
33493
34238
  channelDeps = {
@@ -33503,10 +34248,10 @@ var start = async (config) => {
33503
34248
  error: err instanceof Error ? err.message : String(err)
33504
34249
  });
33505
34250
  }
33506
- (0, import_core98.setEvalRunService)(evalRunner);
34251
+ (0, import_core99.setEvalRunService)(evalRunner);
33507
34252
  try {
33508
- const menuStore = (0, import_core99.getStoreLattice)("default", "menu").store;
33509
- (0, import_core98.setMenuRegistry)(menuStore);
34253
+ const menuStore = (0, import_core100.getStoreLattice)("default", "menu").store;
34254
+ (0, import_core99.setMenuRegistry)(menuStore);
33510
34255
  logger8.info("Menu registry initialized");
33511
34256
  } catch {
33512
34257
  }
@@ -33523,10 +34268,10 @@ var start = async (config) => {
33523
34268
  const { A2AAuthService: A2AAuthService2, parseEnvKeys: parseEnvKeys2 } = await Promise.resolve().then(() => (init_A2AAuthService(), A2AAuthService_exports));
33524
34269
  const { registerA2AStandardRoutes: registerA2AStandardRoutes2 } = await Promise.resolve().then(() => (init_a2a_standard(), a2a_standard_exports));
33525
34270
  const a2a = await Promise.resolve().then(() => (init_a2a(), a2a_exports));
33526
- const a2aKeyStore = (0, import_core99.getStoreLattice)("default", "a2aApiKey").store;
33527
- const assistantStore = (0, import_core99.getStoreLattice)("default", "assistant").store;
33528
- const projectStore = (0, import_core99.getStoreLattice)("default", "project").store;
33529
- const taskStore = (0, import_core99.getStoreLattice)("default", "task").store;
34271
+ const a2aKeyStore = (0, import_core100.getStoreLattice)("default", "a2aApiKey").store;
34272
+ const assistantStore = (0, import_core100.getStoreLattice)("default", "assistant").store;
34273
+ const projectStore = (0, import_core100.getStoreLattice)("default", "project").store;
34274
+ const taskStore = (0, import_core100.getStoreLattice)("default", "task").store;
33530
34275
  const authService = new A2AAuthService2({
33531
34276
  keyStore: a2aKeyStore,
33532
34277
  assistantStore,
@@ -33566,8 +34311,8 @@ var start = async (config) => {
33566
34311
  const { CollectionService: CollectionService2 } = await Promise.resolve().then(() => (init_collection_service(), collection_service_exports));
33567
34312
  openLattice2.register(createKbProvider2(new CollectionService2()));
33568
34313
  openLattice2.register(createOpenSandboxProvider2());
33569
- const threadStore = (0, import_core99.getStoreLattice)("default", "thread").store;
33570
- const assistantStore = (0, import_core99.getStoreLattice)("default", "assistant").store;
34314
+ const threadStore = (0, import_core100.getStoreLattice)("default", "thread").store;
34315
+ const assistantStore = (0, import_core100.getStoreLattice)("default", "assistant").store;
33571
34316
  openLattice2.register(
33572
34317
  createAgentProvider2({
33573
34318
  threadStore,
@@ -33612,15 +34357,15 @@ var start = async (config) => {
33612
34357
  error: err instanceof Error ? err.message : String(err)
33613
34358
  });
33614
34359
  }
33615
- if (!import_core99.sandboxLatticeManager.hasLattice("default")) {
33616
- import_core99.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
34360
+ if (!import_core100.sandboxLatticeManager.hasLattice("default")) {
34361
+ import_core100.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
33617
34362
  logger8.info("Registered sandbox manager from env configuration");
33618
34363
  }
33619
34364
  if (isPluginDeploymentRuntimeEnabled()) {
33620
34365
  try {
33621
- const pluginDeploymentStore = (0, import_core99.getStoreLattice)("default", "pluginDeployment").store;
33622
- const tenantStore = (0, import_core99.getStoreLattice)("default", "tenant").store;
33623
- const leaseStore2 = (0, import_core99.getStoreLattice)("default", "lease").store;
34366
+ const pluginDeploymentStore = (0, import_core100.getStoreLattice)("default", "pluginDeployment").store;
34367
+ const tenantStore = (0, import_core100.getStoreLattice)("default", "tenant").store;
34368
+ const leaseStore2 = (0, import_core100.getStoreLattice)("default", "lease").store;
33624
34369
  const listAllDeployments = async () => {
33625
34370
  const tenants = await tenantStore.getAllTenants();
33626
34371
  const lists = await Promise.all(
@@ -33633,9 +34378,9 @@ var start = async (config) => {
33633
34378
  const pluginDeploymentRuntime = startPluginDeploymentRuntime({
33634
34379
  wiring: {
33635
34380
  store: pluginDeploymentStore,
33636
- sandboxManager: (0, import_core99.getSandBoxManager)(),
33637
- catalog: (0, import_core99.getSandboxPluginCatalog)(),
33638
- installPluginHost: import_core99.installPluginHost,
34381
+ sandboxManager: (0, import_core100.getSandBoxManager)(),
34382
+ catalog: (0, import_core100.getSandboxPluginCatalog)(),
34383
+ installPluginHost: import_core100.installPluginHost,
33639
34384
  limits: readPluginDeploymentLimits(),
33640
34385
  serviceKey: process.env.MICROSANDBOX_API_KEY,
33641
34386
  listAllDeployments,
@@ -33647,7 +34392,7 @@ var start = async (config) => {
33647
34392
  }
33648
34393
  },
33649
34394
  lease: leaseStore2,
33650
- holder: (0, import_core99.getReplicaId)(),
34395
+ holder: (0, import_core100.getReplicaId)(),
33651
34396
  logger: logger8
33652
34397
  });
33653
34398
  app.addHook("onClose", async () => {
@@ -33662,11 +34407,11 @@ var start = async (config) => {
33662
34407
  }
33663
34408
  try {
33664
34409
  const { ResourceController: ResourceController2 } = await Promise.resolve().then(() => (init_resources(), resources_exports));
33665
- const sharedResourceStore = (0, import_core99.getStoreLattice)("default", "sharedResource").store;
33666
- const cache2 = new import_core99.TokenCache();
34410
+ const sharedResourceStore = (0, import_core100.getStoreLattice)("default", "sharedResource").store;
34411
+ const cache2 = new import_core100.TokenCache();
33667
34412
  const resourceController = new ResourceController2({
33668
34413
  store: sharedResourceStore,
33669
- sandboxManager: import_core99.sandboxLatticeManager,
34414
+ sandboxManager: import_core100.sandboxLatticeManager,
33670
34415
  cache: cache2,
33671
34416
  logger: logger8
33672
34417
  });
@@ -33679,13 +34424,13 @@ var start = async (config) => {
33679
34424
  }
33680
34425
  if (channelDeps && process.env.CHANNELS_ENABLED !== "false") {
33681
34426
  try {
33682
- const channelLeader = new import_core99.ChannelConnectionLeader({
33683
- leaseStore: (0, import_core99.getStoreLattice)("default", "lease").store,
33684
- owner: (0, import_core99.getReplicaId)(),
33685
- connect: () => (0, import_core99.connectAllChannels)((channel) => adapterRegistry.get(channel), {
34427
+ const channelLeader = new import_core100.ChannelConnectionLeader({
34428
+ leaseStore: (0, import_core100.getStoreLattice)("default", "lease").store,
34429
+ owner: (0, import_core100.getReplicaId)(),
34430
+ connect: () => (0, import_core100.connectAllChannels)((channel) => adapterRegistry.get(channel), {
33686
34431
  deps: { router: channelDeps.router }
33687
34432
  }),
33688
- disconnect: () => (0, import_core99.disconnectAllChannels)((channel) => adapterRegistry.get(channel)),
34433
+ disconnect: () => (0, import_core100.disconnectAllChannels)((channel) => adapterRegistry.get(channel)),
33689
34434
  log: { warn: (message, context) => logger8.warn(message, context) }
33690
34435
  });
33691
34436
  app.addHook("onClose", async () => {
@@ -33699,45 +34444,52 @@ var start = async (config) => {
33699
34444
  }
33700
34445
  }
33701
34446
  const target_port = config?.port || Number(process.env.PORT) || 4001;
33702
- (0, import_core99.configureCoordinationLeaseStore)((0, import_core99.getStoreLattice)("default", "lease").store);
33703
- const outboxStore = (0, import_core99.getStoreLattice)("default", "outbox").store;
33704
- import_core99.taskLifecycleNotifier.setOutbox(outboxStore);
33705
- import_core99.projectTaskAdmissionNotifier.setOutbox(outboxStore);
33706
- (0, import_core99.configurePluginCatalogSync)({ outbox: outboxStore, owner: (0, import_core99.getReplicaId)() });
34447
+ (0, import_core100.configureCoordinationLeaseStore)((0, import_core100.getStoreLattice)("default", "lease").store);
34448
+ const outboxStore = (0, import_core100.getStoreLattice)("default", "outbox").store;
34449
+ import_core100.taskLifecycleNotifier.setOutbox(outboxStore);
34450
+ import_core100.projectTaskAdmissionNotifier.setOutbox(outboxStore);
34451
+ (0, import_core100.configurePluginCatalogSync)({ outbox: outboxStore, owner: (0, import_core100.getReplicaId)() });
34452
+ (0, import_core100.configureCollectionSync)({ outbox: outboxStore, owner: (0, import_core100.getReplicaId)() });
33707
34453
  bridgeAssistantEvents(
33708
- (event, cb) => import_core99.eventBus.subscribe(event, cb),
34454
+ (event, cb) => import_core100.eventBus.subscribe(event, cb),
33709
34455
  outboxStore,
33710
- (0, import_core99.getReplicaId)()
34456
+ (0, import_core100.getReplicaId)()
33711
34457
  );
33712
34458
  if (projectRoomRealtimeRuntime) {
33713
34459
  projectRoomRealtimeRuntime.broker.setBroadcastHook((scope, serialized, sourceKey) => {
33714
- void publishRoomEvent(outboxStore, (0, import_core99.getReplicaId)(), scope, serialized, sourceKey);
34460
+ void publishRoomEvent(outboxStore, (0, import_core100.getReplicaId)(), scope, serialized, sourceKey);
33715
34461
  });
33716
34462
  }
33717
- const outboxPoller = new import_core99.OutboxPoller({
34463
+ const outboxPoller = new import_core100.OutboxPoller({
33718
34464
  store: outboxStore,
33719
- owner: (0, import_core99.getReplicaId)(),
34465
+ owner: (0, import_core100.getReplicaId)(),
33720
34466
  handlers: {
33721
- "task-lifecycle": (payload) => import_core99.taskLifecycleNotifier.deliverFromOutbox(payload),
33722
- "project-task-admission": (payload) => import_core99.projectTaskAdmissionNotifier.deliverFromOutbox(payload),
34467
+ "task-lifecycle": (payload) => import_core100.taskLifecycleNotifier.deliverFromOutbox(payload),
34468
+ "project-task-admission": (payload) => import_core100.projectTaskAdmissionNotifier.deliverFromOutbox(payload),
33723
34469
  [ROOM_EVENT_TOPIC]: async (payload) => {
33724
34470
  if (projectRoomRealtimeRuntime) ingestRoomEvent(payload, projectRoomRealtimeRuntime.broker);
33725
34471
  },
33726
34472
  "assistant-changed": (payload) => handleAssistantChanged(payload, async (tenantId) => {
33727
- await import_core99.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId);
34473
+ await import_core100.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId);
33728
34474
  invalidateAgentReflectionCache(tenantId);
33729
34475
  invalidatePluginReflectionCache(tenantId);
33730
34476
  }),
33731
34477
  [A2A_KEY_CHANGED_TOPIC]: (payload) => handleA2AKeyChanged(payload, () => refreshStoreKeyMap()),
33732
34478
  [MCP_CONFIG_CHANGED_TOPIC]: (payload) => reconcileMcpConfigChange(payload, {
33733
- store: (0, import_core99.getStoreLattice)("default", "mcp").store,
33734
- manager: import_core99.mcpManager,
33735
- convertToConnection: import_core99.convertToConnection
34479
+ store: (0, import_core100.getStoreLattice)("default", "mcp").store,
34480
+ manager: import_core100.mcpManager,
34481
+ convertToConnection: import_core100.convertToConnection
33736
34482
  }),
33737
- [import_core99.PLUGIN_CATALOG_CHANGED_TOPIC]: async (payload) => {
34483
+ [import_core100.COLLECTION_CHANGED_TOPIC]: async (payload) => {
34484
+ const tenantId = payload?.tenantId;
34485
+ if (typeof tenantId === "string" && tenantId.length > 0) {
34486
+ import_core100.vectorStoreLatticeManager.clearTenantVectorStores(tenantId);
34487
+ }
34488
+ },
34489
+ [import_core100.PLUGIN_CATALOG_CHANGED_TOPIC]: async (payload) => {
33738
34490
  const tenantId = payload?.tenantId;
33739
34491
  if (typeof tenantId === "string" && tenantId.length > 0) {
33740
- (0, import_core99.getSandboxPluginCatalog)().invalidate(tenantId);
34492
+ (0, import_core100.getSandboxPluginCatalog)().invalidate(tenantId);
33741
34493
  invalidatePluginReflectionCache(tenantId);
33742
34494
  invalidateAgentReflectionCache(tenantId);
33743
34495
  await getMcpUiResourceResolver()?.invalidateTenantPlugins(tenantId);
@@ -33756,7 +34508,7 @@ var start = async (config) => {
33756
34508
  } catch (err) {
33757
34509
  logger8.warn("Outbox poller failed to start", { error: err instanceof Error ? err.message : String(err) });
33758
34510
  }
33759
- const leaseStore = (0, import_core99.getStoreLattice)("default", "lease").store;
34511
+ const leaseStore = (0, import_core100.getStoreLattice)("default", "lease").store;
33760
34512
  if (leaseStore.constructor?.name === "InMemoryLeaseStore") {
33761
34513
  logger8.warn(
33762
34514
  "Startup recovery leader gate uses a non-distributed lease store (per-process only); configure a shared 'lease' store for multi-replica deployments",
@@ -33764,7 +34516,7 @@ var start = async (config) => {
33764
34516
  );
33765
34517
  }
33766
34518
  warnMultiReplicaReadiness(logger8);
33767
- const startup = await (0, import_core99.runAsLeader)(leaseStore, "startup-recovery", async () => {
34519
+ const startup = await (0, import_core100.runAsLeader)(leaseStore, "startup-recovery", async () => {
33768
34520
  if (routes.projectTaskRuntime) {
33769
34521
  await prepareProjectTaskRuntime(routes.projectTaskRuntime, logger8);
33770
34522
  }
@@ -33773,9 +34525,9 @@ var start = async (config) => {
33773
34525
  const { createOrphanRecoveryRuntime: createOrphanRecoveryRuntime2 } = await Promise.resolve().then(() => (init_OrphanRecoveryRuntime(), OrphanRecoveryRuntime_exports));
33774
34526
  const { createRecoveryCallerDeps: createRecoveryCallerDeps2 } = await Promise.resolve().then(() => (init_RecoveryCallerDeps(), RecoveryCallerDeps_exports));
33775
34527
  const runtime = createOrphanRecoveryRuntime2({
33776
- taskStore: (0, import_core99.getStoreLattice)("default", "task").store,
33777
- workItemStore: (0, import_core99.getStoreLattice)("default", "taskWorkItem").store,
33778
- tenantStore: (0, import_core99.getStoreLattice)("default", "tenant").store,
34528
+ taskStore: (0, import_core100.getStoreLattice)("default", "task").store,
34529
+ workItemStore: (0, import_core100.getStoreLattice)("default", "taskWorkItem").store,
34530
+ tenantStore: (0, import_core100.getStoreLattice)("default", "tenant").store,
33779
34531
  ...createRecoveryCallerDeps2(),
33780
34532
  log: logger8
33781
34533
  });
@@ -33784,9 +34536,9 @@ var start = async (config) => {
33784
34536
  logger8.warn("Task orphan recovery failed", { error: err instanceof Error ? err.message : String(err) });
33785
34537
  }
33786
34538
  }
33787
- if (import_core99.scheduleLatticeManager.hasLattice("default")) {
34539
+ if (import_core100.scheduleLatticeManager.hasLattice("default")) {
33788
34540
  try {
33789
- const restored = await import_core99.scheduleLatticeManager.getScheduleLattice("default").restore();
34541
+ const restored = await import_core100.scheduleLatticeManager.getScheduleLattice("default").restore();
33790
34542
  logger8.info("Scheduled tasks restored", { phase: "startup_recovery", restored });
33791
34543
  } catch (err) {
33792
34544
  logger8.warn("Scheduled task restore failed", {
@@ -33829,7 +34581,7 @@ var start = async (config) => {
33829
34581
  steps: [
33830
34582
  async () => {
33831
34583
  await Promise.all(
33832
- import_core99.agentInstanceManager.getAllAgents().map((agent) => agent.abort().catch(() => void 0))
34584
+ import_core100.agentInstanceManager.getAllAgents().map((agent) => agent.abort().catch(() => void 0))
33833
34585
  );
33834
34586
  },
33835
34587
  () => agentTaskConsumer?.stopPollingQueue(),