@axiom-lattice/gateway 4.5.0 → 4.6.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 (23) hide show
  1. package/dist/embed/{embed-page-AgentDetailSideApp-I4ZT3MQQ.js → embed-page-AgentDetailSideApp-7NYLPLAX.js} +1 -1
  2. package/dist/embed/{embed-page-AgentGovernanceWorkbench-HVFB6EPY.js → embed-page-AgentGovernanceWorkbench-LNGNSI7X.js} +2 -2
  3. package/dist/embed/{embed-page-MessageGraph-CZQROEO7.js → embed-page-MessageGraph-E6DZDT65.js} +1 -1
  4. package/dist/embed/{embed-page-ReactChart-WMWBSL54.js → embed-page-ReactChart-3VE7F5VJ.js} +1 -1
  5. package/dist/embed/{embed-page-SkillFlow-5JLJ5R57.js → embed-page-SkillFlow-XMMHEHQL.js} +1 -1
  6. package/dist/embed/{embed-page-TasksSideApp-5BYTO4KT.js → embed-page-TasksSideApp-QM5TZ7EG.js} +1 -1
  7. package/dist/embed/{embed-page-TeamWorkspace-5KN7ZZWQ.js → embed-page-TeamWorkspace-E7RFY3ZY.js} +1 -1
  8. package/dist/embed/{embed-page-TopologyRuntimeView-S6XAQHDF.js → embed-page-TopologyRuntimeView-DLPDUB7Z.js} +1 -1
  9. package/dist/embed/{embed-page-WorkflowAutomationView-E6G446HW.js → embed-page-WorkflowAutomationView-FKSVOHHB.js} +1 -1
  10. package/dist/embed/embed-page-chunk-EXCJ42IB.js +2 -0
  11. package/dist/embed/{embed-page-chunk-MUE3GWJV.js → embed-page-chunk-H6TK3FAR.js} +1 -1
  12. package/dist/embed/{embed-page-chunk-QU52HUXW.js → embed-page-chunk-HEMNMC4X.js} +4 -4
  13. package/dist/embed/{embed-page-chunk-2JOGNXZT.js → embed-page-chunk-I7PWCKAG.js} +9 -9
  14. package/dist/embed/{embed-page-chunk-KDWA6VOG.js → embed-page-chunk-KN7D66KL.js} +1 -1
  15. package/dist/embed/{embed-page-chunk-7GAD6Q52.js → embed-page-chunk-U276WBDI.js} +2078 -2078
  16. package/dist/embed/{embed-page-chunk-YQ3BA27D.js → embed-page-chunk-WWTU55RX.js} +1 -1
  17. package/dist/embed/embed-page.js +1 -1
  18. package/dist/index.js +1830 -644
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.mjs +1335 -147
  21. package/dist/index.mjs.map +1 -1
  22. package/package.json +7 -7
  23. package/dist/embed/embed-page-chunk-DSQ4DIQY.js +0 -2
package/dist/index.js CHANGED
@@ -956,18 +956,18 @@ function extractText(msg) {
956
956
  }
957
957
  return null;
958
958
  }
959
- var import_zod16, logger5, wechatConfigSchema, MAX_RECONNECT_DELAY_MS, BASE_RECONNECT_DELAY_MS, HEARTBEAT_INTERVAL_MS, MSG_TYPE_USER, MSG_ITEM_TEXT, activeConnections2, seenClientIds, wechatChannelAdapter;
959
+ var import_zod18, logger6, wechatConfigSchema, MAX_RECONNECT_DELAY_MS, BASE_RECONNECT_DELAY_MS, HEARTBEAT_INTERVAL_MS, MSG_TYPE_USER, MSG_ITEM_TEXT, activeConnections2, seenClientIds, wechatChannelAdapter;
960
960
  var init_WechatChannelAdapter = __esm({
961
961
  "src/channels/wechat/WechatChannelAdapter.ts"() {
962
962
  "use strict";
963
- import_zod16 = require("zod");
963
+ import_zod18 = require("zod");
964
964
  init_wechat_client();
965
965
  init_context_store();
966
966
  init_Logger();
967
- logger5 = new Logger({ serviceName: "lattice/gateway/wechat" });
968
- wechatConfigSchema = import_zod16.z.object({
969
- botToken: import_zod16.z.string(),
970
- uin: import_zod16.z.string().optional()
967
+ logger6 = new Logger({ serviceName: "lattice/gateway/wechat" });
968
+ wechatConfigSchema = import_zod18.z.object({
969
+ botToken: import_zod18.z.string(),
970
+ uin: import_zod18.z.string().optional()
971
971
  });
972
972
  MAX_RECONNECT_DELAY_MS = 3e4;
973
973
  BASE_RECONNECT_DELAY_MS = 1e3;
@@ -1015,7 +1015,7 @@ var init_WechatChannelAdapter = __esm({
1015
1015
  const senderId = replyTarget.rawTarget.senderId;
1016
1016
  const contextToken = getContextToken(installation.id, senderId);
1017
1017
  if (!contextToken) {
1018
- logger5.warn("WeChat context token expired, cannot send reply", {
1018
+ logger6.warn("WeChat context token expired, cannot send reply", {
1019
1019
  installationId: installation.id,
1020
1020
  senderId
1021
1021
  });
@@ -1033,14 +1033,14 @@ var init_WechatChannelAdapter = __esm({
1033
1033
  async connect(installation, deps) {
1034
1034
  const { id: installationId, tenantId, config } = installation;
1035
1035
  if (!config.botToken) {
1036
- logger5.warn("WeChat installation missing botToken, skipping", { installationId });
1036
+ logger6.warn("WeChat installation missing botToken, skipping", { installationId });
1037
1037
  return;
1038
1038
  }
1039
1039
  if (activeConnections2.has(installationId)) {
1040
- logger5.warn("WeChat polling already running for installation, skipping", { installationId });
1040
+ logger6.warn("WeChat polling already running for installation, skipping", { installationId });
1041
1041
  return;
1042
1042
  }
1043
- logger5.info("WeChat polling starting", { installationId, tenantId });
1043
+ logger6.info("WeChat polling starting", { installationId, tenantId });
1044
1044
  const abortController = new AbortController();
1045
1045
  const heartbeatTimer = setInterval(() => {
1046
1046
  const state2 = activeConnections2.get(installationId);
@@ -1050,7 +1050,7 @@ var init_WechatChannelAdapter = __esm({
1050
1050
  }
1051
1051
  const elapsed = Date.now() - state2.lastActivity;
1052
1052
  if (elapsed > HEARTBEAT_INTERVAL_MS * 2) {
1053
- logger5.error("WeChat polling heartbeat lost \u2014 no activity", {
1053
+ logger6.error("WeChat polling heartbeat lost \u2014 no activity", {
1054
1054
  installationId,
1055
1055
  elapsedMs: elapsed
1056
1056
  });
@@ -1069,7 +1069,7 @@ var init_WechatChannelAdapter = __esm({
1069
1069
  let reconnectDelay = BASE_RECONNECT_DELAY_MS;
1070
1070
  const scheduleNextPoll = () => {
1071
1071
  poll().catch((err) => {
1072
- logger5.error("WeChat poll iteration crashed", {
1072
+ logger6.error("WeChat poll iteration crashed", {
1073
1073
  installationId,
1074
1074
  error: err instanceof Error ? err.message : String(err)
1075
1075
  });
@@ -1082,7 +1082,7 @@ var init_WechatChannelAdapter = __esm({
1082
1082
  const poll = async () => {
1083
1083
  const currentState = activeConnections2.get(installationId);
1084
1084
  if (!currentState || currentState.abortController.signal.aborted) {
1085
- logger5.info("WeChat polling aborted", { installationId });
1085
+ logger6.info("WeChat polling aborted", { installationId });
1086
1086
  return;
1087
1087
  }
1088
1088
  try {
@@ -1095,7 +1095,7 @@ var init_WechatChannelAdapter = __esm({
1095
1095
  reconnectDelay = BASE_RECONNECT_DELAY_MS;
1096
1096
  currentState.lastActivity = Date.now();
1097
1097
  if (result.msgs.length > 0) {
1098
- logger5.info("WeChat poll received messages", {
1098
+ logger6.info("WeChat poll received messages", {
1099
1099
  installationId,
1100
1100
  count: result.msgs.length
1101
1101
  });
@@ -1112,7 +1112,7 @@ var init_WechatChannelAdapter = __esm({
1112
1112
  if (inbound && router) {
1113
1113
  const dispatchResult = await router.dispatch(inbound);
1114
1114
  if (!dispatchResult.success) {
1115
- logger5.warn("WeChat dispatch failed", {
1115
+ logger6.warn("WeChat dispatch failed", {
1116
1116
  installationId,
1117
1117
  error: dispatchResult.error?.message
1118
1118
  });
@@ -1121,10 +1121,10 @@ var init_WechatChannelAdapter = __esm({
1121
1121
  }
1122
1122
  } catch (err) {
1123
1123
  if (err instanceof Error && err.name === "AbortError") {
1124
- logger5.info("WeChat poll aborted by signal", { installationId });
1124
+ logger6.info("WeChat poll aborted by signal", { installationId });
1125
1125
  return;
1126
1126
  }
1127
- logger5.error("WeChat poll error", {
1127
+ logger6.error("WeChat poll error", {
1128
1128
  installationId,
1129
1129
  error: err instanceof Error ? err.message : String(err)
1130
1130
  });
@@ -1134,19 +1134,19 @@ var init_WechatChannelAdapter = __esm({
1134
1134
  scheduleNextPoll();
1135
1135
  };
1136
1136
  scheduleNextPoll();
1137
- logger5.info("WeChat polling started", { installationId });
1137
+ logger6.info("WeChat polling started", { installationId });
1138
1138
  },
1139
1139
  async disconnect(installationId) {
1140
1140
  const state = activeConnections2.get(installationId);
1141
1141
  if (!state) {
1142
- logger5.warn("WeChat polling not running, nothing to disconnect", { installationId });
1142
+ logger6.warn("WeChat polling not running, nothing to disconnect", { installationId });
1143
1143
  return;
1144
1144
  }
1145
- logger5.info("WeChat polling disconnecting", { installationId });
1145
+ logger6.info("WeChat polling disconnecting", { installationId });
1146
1146
  state.abortController.abort();
1147
1147
  clearInterval(state.heartbeatTimer);
1148
1148
  activeConnections2.delete(installationId);
1149
- logger5.info("WeChat polling disconnected", { installationId });
1149
+ logger6.info("WeChat polling disconnected", { installationId });
1150
1150
  }
1151
1151
  };
1152
1152
  }
@@ -1179,11 +1179,11 @@ function devModeDefaults() {
1179
1179
  const projectId = process.env[DEFAULT_PROJECT_ENV] || void 0;
1180
1180
  return { tenantId, projectId };
1181
1181
  }
1182
- var import_protocols32, A2AAuthError, DEFAULT_TENANT_ENV, DEFAULT_TENANT_ID, DEFAULT_PROJECT_ENV, BEARER_SCHEME_RE, A2AAuthService;
1182
+ var import_protocols33, A2AAuthError, DEFAULT_TENANT_ENV, DEFAULT_TENANT_ID, DEFAULT_PROJECT_ENV, BEARER_SCHEME_RE, A2AAuthService;
1183
1183
  var init_A2AAuthService = __esm({
1184
1184
  "src/services/a2a/A2AAuthService.ts"() {
1185
1185
  "use strict";
1186
- import_protocols32 = require("@axiom-lattice/protocols");
1186
+ import_protocols33 = require("@axiom-lattice/protocols");
1187
1187
  A2AAuthError = class extends Error {
1188
1188
  constructor(message, statusCode) {
1189
1189
  super(message);
@@ -1238,7 +1238,7 @@ var init_A2AAuthService = __esm({
1238
1238
  const entry = merged.get(token);
1239
1239
  if (!entry) return { authenticated: false };
1240
1240
  const hasExplicitGrants = Array.isArray(entry.grants) && entry.grants.length > 0;
1241
- const agentGrant = (0, import_protocols32.effectiveGrants)(entry).find((g) => g.domain === "agent");
1241
+ const agentGrant = (0, import_protocols33.effectiveGrants)(entry).find((g) => g.domain === "agent");
1242
1242
  const assistantIds = hasExplicitGrants ? agentGrant?.items ?? [] : entry.assistantIds;
1243
1243
  return {
1244
1244
  authenticated: true,
@@ -1453,7 +1453,7 @@ function extractFailureReason(task) {
1453
1453
  return extractText2(task.status.message.parts);
1454
1454
  }
1455
1455
  function observationEventKey(task, result, failureReason) {
1456
- const digest = (0, import_node_crypto26.createHash)("sha256").update(JSON.stringify({
1456
+ const digest = (0, import_node_crypto28.createHash)("sha256").update(JSON.stringify({
1457
1457
  state: task.status.state,
1458
1458
  timestamp: task.status.timestamp,
1459
1459
  message: task.status.message,
@@ -1463,7 +1463,7 @@ function observationEventKey(task, result, failureReason) {
1463
1463
  return `a2a-status-observation:${task.id}:${digest}`;
1464
1464
  }
1465
1465
  function snapshotEventKey(task) {
1466
- const digest = (0, import_node_crypto26.createHash)("sha256").update(JSON.stringify(task)).digest("hex");
1466
+ const digest = (0, import_node_crypto28.createHash)("sha256").update(JSON.stringify(task)).digest("hex");
1467
1467
  return `a2a-task-snapshot:${task.id}:${digest}`;
1468
1468
  }
1469
1469
  function isGovernedObservation(state) {
@@ -1475,13 +1475,13 @@ function isA2ATaskSnapshot(value) {
1475
1475
  function snapshotSequence(value) {
1476
1476
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
1477
1477
  }
1478
- var import_node_crypto26, import_node_util, import_core65, TASK_STATUS_TO_A2A_STATE, TITLE_MAX_LENGTH, A2ATaskScopeConflictError, A2ATaskStoreAdapter;
1478
+ var import_node_crypto28, import_node_util, import_core66, TASK_STATUS_TO_A2A_STATE, TITLE_MAX_LENGTH, A2ATaskScopeConflictError, A2ATaskStoreAdapter;
1479
1479
  var init_A2ATaskStoreAdapter = __esm({
1480
1480
  "src/services/a2a/A2ATaskStoreAdapter.ts"() {
1481
1481
  "use strict";
1482
- import_node_crypto26 = require("crypto");
1482
+ import_node_crypto28 = require("crypto");
1483
1483
  import_node_util = require("util");
1484
- import_core65 = require("@axiom-lattice/core");
1484
+ import_core66 = require("@axiom-lattice/core");
1485
1485
  TASK_STATUS_TO_A2A_STATE = {
1486
1486
  pending: "submitted",
1487
1487
  in_progress: "working",
@@ -1507,7 +1507,7 @@ var init_A2ATaskStoreAdapter = __esm({
1507
1507
  this.workItemStore = options.workItemStore;
1508
1508
  this.lifecycle = options.lifecycle;
1509
1509
  this.scope = options.scope;
1510
- this.runBridge = (0, import_core65.createTaskRunBridge)({
1510
+ this.runBridge = (0, import_core66.createTaskRunBridge)({
1511
1511
  lifecycle: this.lifecycle,
1512
1512
  taskStore: this.taskStore,
1513
1513
  workItemStore: this.workItemStore
@@ -1858,13 +1858,13 @@ function assistantHasGovernedTask(assistant) {
1858
1858
  const allowedTools = taskMiddleware?.allowedTools;
1859
1859
  return !!taskMiddleware && (allowedTools === void 0 || Array.isArray(allowedTools) && (allowedTools.length === 0 || allowedTools.includes("manage_task")));
1860
1860
  }
1861
- var import_uuid11, import_core66, import_protocols33, _AxiomAgentExecutor, AxiomAgentExecutor;
1861
+ var import_uuid11, import_core67, import_protocols34, _AxiomAgentExecutor, AxiomAgentExecutor;
1862
1862
  var init_AxiomAgentExecutor = __esm({
1863
1863
  "src/services/a2a/AxiomAgentExecutor.ts"() {
1864
1864
  "use strict";
1865
1865
  import_uuid11 = require("uuid");
1866
- import_core66 = require("@axiom-lattice/core");
1867
- import_protocols33 = require("@axiom-lattice/protocols");
1866
+ import_core67 = require("@axiom-lattice/core");
1867
+ import_protocols34 = require("@axiom-lattice/protocols");
1868
1868
  init_a2aFileRefs();
1869
1869
  init_task_file_refs();
1870
1870
  _AxiomAgentExecutor = class _AxiomAgentExecutor {
@@ -1945,7 +1945,7 @@ var init_AxiomAgentExecutor = __esm({
1945
1945
  await this.taskStore.save(initialTask);
1946
1946
  bus.publish(initialTask);
1947
1947
  try {
1948
- const agent = import_core66.agentInstanceManager.getAgent(this.agentParams(threadId));
1948
+ const agent = import_core67.agentInstanceManager.getAgent(this.agentParams(threadId));
1949
1949
  const requestText = inputFiles.length > 0 ? `${text}
1950
1950
 
1951
1951
  ${formatFileRefsSection(inputFiles)}` : text;
@@ -1963,7 +1963,7 @@ ${formatFileRefsSection(inputFiles)}` : text;
1963
1963
  custom_run_config: { taskId: ctx.taskId, execution: { taskId: ctx.taskId } }
1964
1964
  });
1965
1965
  const stream = agent.chunkStream(messageId, [
1966
- import_protocols33.MessageChunkTypes.MESSAGE_COMPLETED
1966
+ import_protocols34.MessageChunkTypes.MESSAGE_COMPLETED
1967
1967
  ]);
1968
1968
  let outputText = "";
1969
1969
  let interrupted = false;
@@ -1971,14 +1971,14 @@ ${formatFileRefsSection(inputFiles)}` : text;
1971
1971
  if (execution.canceled) return;
1972
1972
  const chunkType = chunk.type;
1973
1973
  const chunkText = chunk.data?.content ?? "";
1974
- if (chunkType === import_protocols33.MessageChunkTypes.INTERRUPT) {
1974
+ if (chunkType === import_protocols34.MessageChunkTypes.INTERRUPT) {
1975
1975
  interrupted = true;
1976
1976
  break;
1977
1977
  }
1978
- if (chunkType === import_protocols33.MessageChunkTypes.AI && chunkText) {
1978
+ if (chunkType === import_protocols34.MessageChunkTypes.AI && chunkText) {
1979
1979
  outputText += chunkText;
1980
1980
  }
1981
- if (chunkType === import_protocols33.MessageChunkTypes.AI || chunkType === import_protocols33.MessageChunkTypes.TOOL) {
1981
+ if (chunkType === import_protocols34.MessageChunkTypes.AI || chunkType === import_protocols34.MessageChunkTypes.TOOL) {
1982
1982
  if (chunkText) {
1983
1983
  bus.publish({
1984
1984
  kind: "status-update",
@@ -2140,7 +2140,7 @@ ${formatFileRefsSection(inputFiles)}` : text;
2140
2140
  const threadId = task ? asString2(task.metadata?.threadId) : void 0;
2141
2141
  if (threadId) {
2142
2142
  try {
2143
- const agent = import_core66.agentInstanceManager.getAgent(this.agentParams(threadId));
2143
+ const agent = import_core67.agentInstanceManager.getAgent(this.agentParams(threadId));
2144
2144
  await agent.abort();
2145
2145
  } catch (err) {
2146
2146
  console.warn({
@@ -2494,10 +2494,10 @@ function isAsyncGenerator(value) {
2494
2494
  }
2495
2495
  function registerA2AStandardRoutes(app2, deps) {
2496
2496
  const authService = deps.authService;
2497
- const resolveTasks = deps.getTaskStoreLattice ?? (() => (0, import_core67.getStoreLattice)("default", "task").store);
2498
- const resolveTaskWorkItems = deps.getTaskWorkItemStore ?? (() => (0, import_core67.getStoreLattice)("default", "taskWorkItem").store);
2499
- const getAssistantStore2 = deps.getAssistantStore ?? (() => (0, import_core67.getStoreLattice)("default", "assistant").store);
2500
- const getProjectStore2 = deps.getProjectStore ?? (() => (0, import_core67.getStoreLattice)("default", "project").store);
2497
+ const resolveTasks = deps.getTaskStoreLattice ?? (() => (0, import_core68.getStoreLattice)("default", "task").store);
2498
+ const resolveTaskWorkItems = deps.getTaskWorkItemStore ?? (() => (0, import_core68.getStoreLattice)("default", "taskWorkItem").store);
2499
+ const getAssistantStore2 = deps.getAssistantStore ?? (() => (0, import_core68.getStoreLattice)("default", "assistant").store);
2500
+ const getProjectStore2 = deps.getProjectStore ?? (() => (0, import_core68.getStoreLattice)("default", "project").store);
2501
2501
  const runtimeRegistry = deps.runtimeRegistry ?? new A2ARuntimeRegistry();
2502
2502
  app2.addHook("onClose", async () => {
2503
2503
  runtimeRegistry.close();
@@ -2580,7 +2580,7 @@ function registerA2AStandardRoutes(app2, deps) {
2580
2580
  const taskStore = assistantHasGovernedTask(assistant) ? new A2ATaskStoreAdapter({
2581
2581
  taskStore: internalTasks,
2582
2582
  workItemStore: workItems,
2583
- lifecycle: (0, import_core67.createTaskLifecycleService)({
2583
+ lifecycle: (0, import_core68.createTaskLifecycleService)({
2584
2584
  taskStore: internalTasks,
2585
2585
  workItemStore: workItems
2586
2586
  }),
@@ -2699,7 +2699,7 @@ data: ${JSON.stringify(errorResponse)}
2699
2699
  const taskStore = assistantHasGovernedTask(assistant) ? new A2ATaskStoreAdapter({
2700
2700
  taskStore: internalTasks,
2701
2701
  workItemStore: workItems,
2702
- lifecycle: (0, import_core67.createTaskLifecycleService)({
2702
+ lifecycle: (0, import_core68.createTaskLifecycleService)({
2703
2703
  taskStore: internalTasks,
2704
2704
  workItemStore: workItems
2705
2705
  }),
@@ -2744,13 +2744,13 @@ data: ${JSON.stringify(data)}
2744
2744
  }
2745
2745
  );
2746
2746
  }
2747
- var import_uuid12, import_server2, import_core67, SSE_HEADERS;
2747
+ var import_uuid12, import_server2, import_core68, SSE_HEADERS;
2748
2748
  var init_a2a_standard = __esm({
2749
2749
  "src/routes/a2a-standard.ts"() {
2750
2750
  "use strict";
2751
2751
  import_uuid12 = require("uuid");
2752
2752
  import_server2 = require("@a2a-js/sdk/server");
2753
- import_core67 = require("@axiom-lattice/core");
2753
+ import_core68 = require("@axiom-lattice/core");
2754
2754
  init_A2AAuthService();
2755
2755
  init_A2AAgentCardBuilder();
2756
2756
  init_A2ATaskStoreAdapter();
@@ -2958,11 +2958,11 @@ var init_a2a = __esm({
2958
2958
  });
2959
2959
 
2960
2960
  // src/services/open/openAuthService.ts
2961
- var import_protocols34, OpenAuthService;
2961
+ var import_protocols35, OpenAuthService;
2962
2962
  var init_openAuthService = __esm({
2963
2963
  "src/services/open/openAuthService.ts"() {
2964
2964
  "use strict";
2965
- import_protocols34 = require("@axiom-lattice/protocols");
2965
+ import_protocols35 = require("@axiom-lattice/protocols");
2966
2966
  OpenAuthService = class {
2967
2967
  constructor(keyStore) {
2968
2968
  this.keyStore = keyStore;
@@ -2976,7 +2976,7 @@ var init_openAuthService = __esm({
2976
2976
  kind: "api_key",
2977
2977
  tenantId: record.tenantId,
2978
2978
  projectId: record.projectId,
2979
- grants: (0, import_protocols34.effectiveGrants)(record)
2979
+ grants: (0, import_protocols35.effectiveGrants)(record)
2980
2980
  };
2981
2981
  }
2982
2982
  };
@@ -2984,11 +2984,11 @@ var init_openAuthService = __esm({
2984
2984
  });
2985
2985
 
2986
2986
  // src/services/open/openCredentialService.ts
2987
- var import_protocols35, OpenCredentialService;
2987
+ var import_protocols36, OpenCredentialService;
2988
2988
  var init_openCredentialService = __esm({
2989
2989
  "src/services/open/openCredentialService.ts"() {
2990
2990
  "use strict";
2991
- import_protocols35 = require("@axiom-lattice/protocols");
2991
+ import_protocols36 = require("@axiom-lattice/protocols");
2992
2992
  init_openToken();
2993
2993
  init_openAuthService();
2994
2994
  OpenCredentialService = class {
@@ -3147,11 +3147,11 @@ function grantCovers(grants, domain, action) {
3147
3147
  (g) => g.domain === domain && (!g.items || g.items.length === 0 || g.items.includes(action))
3148
3148
  );
3149
3149
  }
3150
- var import_zod17, GrantDeniedError, ValidationError, ActionNotFoundError, OpenLattice, openLattice;
3150
+ var import_zod19, GrantDeniedError, ValidationError, ActionNotFoundError, OpenLattice, openLattice;
3151
3151
  var init_openLattice = __esm({
3152
3152
  "src/services/open/openLattice.ts"() {
3153
3153
  "use strict";
3154
- import_zod17 = require("zod");
3154
+ import_zod19 = require("zod");
3155
3155
  GrantDeniedError = class extends Error {
3156
3156
  constructor(toolName) {
3157
3157
  super(`GRANT_DENIED: no grant covers ${toolName}`);
@@ -3291,7 +3291,7 @@ var init_openLattice = __esm({
3291
3291
  throw new GrantDeniedError(toolName);
3292
3292
  }
3293
3293
  const resolvedSchema = resolved.action.schema;
3294
- const parsed = "safeParse" in resolvedSchema ? resolvedSchema.safeParse(args) : import_zod17.z.object(resolvedSchema).safeParse(args);
3294
+ const parsed = "safeParse" in resolvedSchema ? resolvedSchema.safeParse(args) : import_zod19.z.object(resolvedSchema).safeParse(args);
3295
3295
  if (!parsed.success) {
3296
3296
  throw new ValidationError(parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; "));
3297
3297
  }
@@ -3424,7 +3424,7 @@ var init_openMcpServer = __esm({
3424
3424
 
3425
3425
  // src/services/open/pluginExposeAdapter.ts
3426
3426
  function schemaOf(tool) {
3427
- return tool.lc_kwargs?.schema ?? tool.schema ?? import_zod18.z.object({}).passthrough();
3427
+ return tool.lc_kwargs?.schema ?? tool.schema ?? import_zod20.z.object({}).passthrough();
3428
3428
  }
3429
3429
  function createPluginProvider(domain, tools, options = {}) {
3430
3430
  function toAction(info) {
@@ -3472,11 +3472,11 @@ function createPluginProvider(domain, tools, options = {}) {
3472
3472
  }
3473
3473
  };
3474
3474
  }
3475
- var import_zod18;
3475
+ var import_zod20;
3476
3476
  var init_pluginExposeAdapter = __esm({
3477
3477
  "src/services/open/pluginExposeAdapter.ts"() {
3478
3478
  "use strict";
3479
- import_zod18 = require("zod");
3479
+ import_zod20 = require("zod");
3480
3480
  }
3481
3481
  });
3482
3482
 
@@ -3501,8 +3501,8 @@ function exposedDeclarations(plugin) {
3501
3501
  return (plugin.meta.tools ?? []).filter((t2) => t2.expose);
3502
3502
  }
3503
3503
  async function registerExposedPluginTools() {
3504
- for (const key of import_core68.PluginRegistry.list()) {
3505
- const plugin = import_core68.PluginRegistry.get(key);
3504
+ for (const key of import_core69.PluginRegistry.list()) {
3505
+ const plugin = import_core69.PluginRegistry.get(key);
3506
3506
  if (!plugin?.middleware) continue;
3507
3507
  const exposed = exposedDeclarations(plugin);
3508
3508
  if (exposed.length === 0) continue;
@@ -3537,8 +3537,8 @@ async function registerExposedPluginTools() {
3537
3537
  }
3538
3538
  function collectExposedPluginUiResources(grants) {
3539
3539
  const resources = /* @__PURE__ */ new Map();
3540
- for (const type of import_core68.PluginRegistry.list()) {
3541
- const plugin = import_core68.PluginRegistry.get(type);
3540
+ for (const type of import_core69.PluginRegistry.list()) {
3541
+ const plugin = import_core69.PluginRegistry.get(type);
3542
3542
  if (!plugin?.middleware) continue;
3543
3543
  const exposedNames = new Set(exposedDeclarations(plugin).map((d) => d.name));
3544
3544
  if (exposedNames.size === 0) continue;
@@ -3562,11 +3562,11 @@ function collectExposedPluginUiResources(grants) {
3562
3562
  }
3563
3563
  return resources;
3564
3564
  }
3565
- var import_core68;
3565
+ var import_core69;
3566
3566
  var init_registerExposedPlugins = __esm({
3567
3567
  "src/services/open/registerExposedPlugins.ts"() {
3568
3568
  "use strict";
3569
- import_core68 = require("@axiom-lattice/core");
3569
+ import_core69 = require("@axiom-lattice/core");
3570
3570
  init_openLattice();
3571
3571
  init_pluginExposeAdapter();
3572
3572
  }
@@ -3581,14 +3581,14 @@ function toText(result) {
3581
3581
  }
3582
3582
  function defaultCatalog() {
3583
3583
  return {
3584
- getValidatedManifest: (tenantId, type) => (0, import_core69.getSandboxPluginCatalog)().getValidatedManifest(tenantId, type),
3585
- getExecutor: () => (0, import_core69.getSandboxPluginCatalog)().getExecutor(),
3586
- readPluginFile: (tenantId, type, relPath) => (0, import_core69.getSandboxPluginCatalog)().readPluginFile(tenantId, type, relPath)
3584
+ getValidatedManifest: (tenantId, type) => (0, import_core70.getSandboxPluginCatalog)().getValidatedManifest(tenantId, type),
3585
+ getExecutor: () => (0, import_core70.getSandboxPluginCatalog)().getExecutor(),
3586
+ readPluginFile: (tenantId, type, relPath) => (0, import_core70.getSandboxPluginCatalog)().readPluginFile(tenantId, type, relPath)
3587
3587
  };
3588
3588
  }
3589
3589
  async function defaultResolveConnections(pluginType, ctx) {
3590
3590
  try {
3591
- return await (0, import_core69.resolveSandboxPluginConnections)(
3591
+ return await (0, import_core70.resolveSandboxPluginConnections)(
3592
3592
  pluginType,
3593
3593
  { connectAll: true },
3594
3594
  {
@@ -3617,7 +3617,7 @@ function mergeOpenCatalog(globalCatalog, tenantTools) {
3617
3617
  async function buildTenantOpenPlugins(tenantId, grants, deps = {}) {
3618
3618
  const catalog = deps.catalog ?? defaultCatalog();
3619
3619
  const listPlugins = deps.listPlugins ?? (async (tenant2) => {
3620
- const snapshot = await (0, import_core69.getSandboxPluginCatalog)().ensureLoaded(tenant2);
3620
+ const snapshot = await (0, import_core70.getSandboxPluginCatalog)().ensureLoaded(tenant2);
3621
3621
  return { plugins: snapshot.plugins, diagnostics: snapshot.diagnostics };
3622
3622
  });
3623
3623
  const resolveConnections = deps.resolveConnections ?? defaultResolveConnections;
@@ -3659,7 +3659,7 @@ async function buildTenantOpenPlugins(tenantId, grants, deps = {}) {
3659
3659
  domain,
3660
3660
  action: tool.name,
3661
3661
  description: tool.description,
3662
- schema: (0, import_core69.jsonSchemaToZod)(tool.schema),
3662
+ schema: (0, import_core70.jsonSchemaToZod)(tool.schema),
3663
3663
  annotations: {
3664
3664
  readOnlyHint: tool.readOnly ?? false,
3665
3665
  destructiveHint: tool.destructive ?? false
@@ -3710,11 +3710,11 @@ async function buildTenantOpenPlugins(tenantId, grants, deps = {}) {
3710
3710
  }
3711
3711
  };
3712
3712
  }
3713
- var import_core69;
3713
+ var import_core70;
3714
3714
  var init_tenantOpenPlugins = __esm({
3715
3715
  "src/services/open/tenantOpenPlugins.ts"() {
3716
3716
  "use strict";
3717
- import_core69 = require("@axiom-lattice/core");
3717
+ import_core70 = require("@axiom-lattice/core");
3718
3718
  init_openLattice();
3719
3719
  init_pluginToolExecution();
3720
3720
  }
@@ -3751,13 +3751,13 @@ function emptyTenantPlugins() {
3751
3751
  }
3752
3752
  function registerOpenRoutes(app2, deps = {}) {
3753
3753
  const openAuth = deps.openAuth ?? new OpenCredentialService(
3754
- (0, import_core70.getStoreLattice)("default", "a2aApiKey").store,
3755
- (0, import_core70.getStoreLattice)("default", "project").store
3754
+ (0, import_core71.getStoreLattice)("default", "a2aApiKey").store,
3755
+ (0, import_core71.getStoreLattice)("default", "project").store
3756
3756
  );
3757
3757
  const grantsSource = deps.grantsSource ?? ((ctx) => ctx.grants);
3758
3758
  const audit = deps.audit ?? (() => {
3759
3759
  try {
3760
- const store2 = (0, import_core70.getStoreLattice)("default", "openAudit").store;
3760
+ const store2 = (0, import_core71.getStoreLattice)("default", "openAudit").store;
3761
3761
  return new OpenAuditService(store2);
3762
3762
  } catch {
3763
3763
  return void 0;
@@ -3911,12 +3911,12 @@ function registerOpenRoutes(app2, deps = {}) {
3911
3911
  }
3912
3912
  );
3913
3913
  }
3914
- var import_types, import_core70, RPC_ERROR;
3914
+ var import_types, import_core71, RPC_ERROR;
3915
3915
  var init_open = __esm({
3916
3916
  "src/routes/open.ts"() {
3917
3917
  "use strict";
3918
3918
  import_types = require("@modelcontextprotocol/sdk/types.js");
3919
- import_core70 = require("@axiom-lattice/core");
3919
+ import_core71 = require("@axiom-lattice/core");
3920
3920
  init_openCredentialService();
3921
3921
  init_openAuditService();
3922
3922
  init_openRateLimiter();
@@ -3949,7 +3949,7 @@ function registerOpenSessionRoutes(app2) {
3949
3949
  if (typeof shareToken !== "string" || shareToken.length === 0) {
3950
3950
  return reply.status(400).send({ error: "SHARE_TOKEN_REQUIRED" });
3951
3951
  }
3952
- const store2 = (0, import_core71.getStoreLattice)("default", "sharedResource").store;
3952
+ const store2 = (0, import_core72.getStoreLattice)("default", "sharedResource").store;
3953
3953
  const record = await store2.findByToken(shareToken);
3954
3954
  if (!record || record.revoked) {
3955
3955
  return reply.status(404).send({ error: "SHARE_NOT_FOUND" });
@@ -3974,11 +3974,11 @@ function registerOpenSessionRoutes(app2) {
3974
3974
  }
3975
3975
  );
3976
3976
  }
3977
- var import_core71;
3977
+ var import_core72;
3978
3978
  var init_open_session = __esm({
3979
3979
  "src/routes/open-session.ts"() {
3980
3980
  "use strict";
3981
- import_core71 = require("@axiom-lattice/core");
3981
+ import_core72 = require("@axiom-lattice/core");
3982
3982
  init_openToken();
3983
3983
  init_previewToken();
3984
3984
  init_openLattice();
@@ -3987,13 +3987,13 @@ var init_open_session = __esm({
3987
3987
 
3988
3988
  // src/services/open/openCatalogService.ts
3989
3989
  async function defaultListTenantPlugins(tenantId) {
3990
- return (await (0, import_core72.getSandboxPluginCatalog)().ensureLoaded(tenantId)).plugins;
3990
+ return (await (0, import_core73.getSandboxPluginCatalog)().ensureLoaded(tenantId)).plugins;
3991
3991
  }
3992
- var import_core72, OpenCatalogService;
3992
+ var import_core73, OpenCatalogService;
3993
3993
  var init_openCatalogService = __esm({
3994
3994
  "src/services/open/openCatalogService.ts"() {
3995
3995
  "use strict";
3996
- import_core72 = require("@axiom-lattice/core");
3996
+ import_core73 = require("@axiom-lattice/core");
3997
3997
  init_openLattice();
3998
3998
  OpenCatalogService = class {
3999
3999
  constructor(assistantStore, lattice = openLattice, listTenantPlugins2 = defaultListTenantPlugins) {
@@ -4068,17 +4068,17 @@ function registerOpenCatalogRoutes(app2) {
4068
4068
  if (!tenantId) {
4069
4069
  return reply.status(401).send({ success: false, error: "Unauthorized" });
4070
4070
  }
4071
- const assistantStore = (0, import_core73.getStoreLattice)("default", "assistant").store;
4071
+ const assistantStore = (0, import_core74.getStoreLattice)("default", "assistant").store;
4072
4072
  const service2 = new OpenCatalogService(assistantStore);
4073
4073
  const catalog = await service2.buildForTenant(tenantId);
4074
4074
  return reply.status(200).send({ success: true, data: catalog });
4075
4075
  });
4076
4076
  }
4077
- var import_core73;
4077
+ var import_core74;
4078
4078
  var init_open_catalog = __esm({
4079
4079
  "src/routes/open-catalog.ts"() {
4080
4080
  "use strict";
4081
- import_core73 = require("@axiom-lattice/core");
4081
+ import_core74 = require("@axiom-lattice/core");
4082
4082
  init_openCatalogService();
4083
4083
  }
4084
4084
  });
@@ -4090,7 +4090,7 @@ __export(sandboxProvider_exports, {
4090
4090
  resolveContextSandbox: () => resolveContextSandbox
4091
4091
  });
4092
4092
  async function resolveContextSandbox(ctx) {
4093
- return import_core74.sandboxLatticeManager.getSandboxFromConfig({
4093
+ return import_core75.sandboxLatticeManager.getSandboxFromConfig({
4094
4094
  assistant_id: "",
4095
4095
  thread_id: "",
4096
4096
  tenantId: ctx.tenantId,
@@ -4109,21 +4109,21 @@ function createOpenSandboxProvider() {
4109
4109
  name: "files_read",
4110
4110
  label: "Read files",
4111
4111
  description: "Read a file from the project sandbox.",
4112
- schema: { path: import_zod19.z.string().min(1) },
4112
+ schema: { path: import_zod21.z.string().min(1) },
4113
4113
  annotations: { readOnlyHint: true, destructiveHint: false }
4114
4114
  },
4115
4115
  {
4116
4116
  name: "files_list",
4117
4117
  label: "List files",
4118
4118
  description: "List files under a directory in the project sandbox.",
4119
- schema: { path: import_zod19.z.string(), recursive: import_zod19.z.boolean().optional() },
4119
+ schema: { path: import_zod21.z.string(), recursive: import_zod21.z.boolean().optional() },
4120
4120
  annotations: { readOnlyHint: true, destructiveHint: false }
4121
4121
  },
4122
4122
  {
4123
4123
  name: "files_write",
4124
4124
  label: "Write files",
4125
4125
  description: "Write content to a file in the project sandbox.",
4126
- schema: { path: import_zod19.z.string().min(1), content: import_zod19.z.string() },
4126
+ schema: { path: import_zod21.z.string().min(1), content: import_zod21.z.string() },
4127
4127
  annotations: { readOnlyHint: false, destructiveHint: true }
4128
4128
  },
4129
4129
  {
@@ -4131,9 +4131,9 @@ function createOpenSandboxProvider() {
4131
4131
  label: "Run shell commands",
4132
4132
  description: "Execute a shell command in the project sandbox. Returns stdout (up to 64KB) and exit code.",
4133
4133
  schema: {
4134
- command: import_zod19.z.string().min(1),
4135
- exec_dir: import_zod19.z.string().optional(),
4136
- timeout: import_zod19.z.number().int().min(1e3).optional()
4134
+ command: import_zod21.z.string().min(1),
4135
+ exec_dir: import_zod21.z.string().optional(),
4136
+ timeout: import_zod21.z.number().int().min(1e3).optional()
4137
4137
  },
4138
4138
  annotations: { readOnlyHint: false, destructiveHint: true }
4139
4139
  }
@@ -4188,12 +4188,12 @@ ${truncated}`
4188
4188
  }
4189
4189
  };
4190
4190
  }
4191
- var import_zod19, import_core74, MAX_OUTPUT_BYTES;
4191
+ var import_zod21, import_core75, MAX_OUTPUT_BYTES;
4192
4192
  var init_sandboxProvider = __esm({
4193
4193
  "src/services/open/providers/sandboxProvider.ts"() {
4194
4194
  "use strict";
4195
- import_zod19 = require("zod");
4196
- import_core74 = require("@axiom-lattice/core");
4195
+ import_zod21 = require("zod");
4196
+ import_core75 = require("@axiom-lattice/core");
4197
4197
  MAX_OUTPUT_BYTES = 64e3;
4198
4198
  }
4199
4199
  });
@@ -4215,12 +4215,12 @@ function safePath(raw) {
4215
4215
  }
4216
4216
  function registerOpenFilesRoutes(app2, deps = {}) {
4217
4217
  const openAuth = deps.openAuth ?? new OpenCredentialService(
4218
- (0, import_core75.getStoreLattice)("default", "a2aApiKey").store,
4219
- (0, import_core75.getStoreLattice)("default", "project").store
4218
+ (0, import_core76.getStoreLattice)("default", "a2aApiKey").store,
4219
+ (0, import_core76.getStoreLattice)("default", "project").store
4220
4220
  );
4221
4221
  const audit = deps.audit ?? (() => {
4222
4222
  try {
4223
- const store2 = (0, import_core75.getStoreLattice)("default", "openAudit").store;
4223
+ const store2 = (0, import_core76.getStoreLattice)("default", "openAudit").store;
4224
4224
  return new OpenAuditService(store2);
4225
4225
  } catch {
4226
4226
  return void 0;
@@ -4330,11 +4330,11 @@ function registerOpenFilesRoutes(app2, deps = {}) {
4330
4330
  }
4331
4331
  });
4332
4332
  }
4333
- var import_core75;
4333
+ var import_core76;
4334
4334
  var init_open_files = __esm({
4335
4335
  "src/routes/open-files.ts"() {
4336
4336
  "use strict";
4337
- import_core75 = require("@axiom-lattice/core");
4337
+ import_core76 = require("@axiom-lattice/core");
4338
4338
  init_openCredentialService();
4339
4339
  init_openLattice();
4340
4340
  init_sandboxProvider();
@@ -4356,7 +4356,7 @@ function registerOpenAuditRoutes(app2) {
4356
4356
  return reply.status(401).send({ success: false, error: "Unauthorized" });
4357
4357
  }
4358
4358
  const status = request.query.status === "ok" || request.query.status === "error" ? request.query.status : void 0;
4359
- const store2 = (0, import_core76.getStoreLattice)("default", "openAudit").store;
4359
+ const store2 = (0, import_core77.getStoreLattice)("default", "openAudit").store;
4360
4360
  const records = await store2.query({
4361
4361
  tenantId,
4362
4362
  credentialId: request.query.credentialId,
@@ -4371,11 +4371,11 @@ function registerOpenAuditRoutes(app2) {
4371
4371
  }
4372
4372
  );
4373
4373
  }
4374
- var import_core76;
4374
+ var import_core77;
4375
4375
  var init_open_audit = __esm({
4376
4376
  "src/routes/open-audit.ts"() {
4377
4377
  "use strict";
4378
- import_core76 = require("@axiom-lattice/core");
4378
+ import_core77 = require("@axiom-lattice/core");
4379
4379
  }
4380
4380
  });
4381
4381
 
@@ -4392,12 +4392,12 @@ function registerOpenExposureRoutes(app2, deps = {}) {
4392
4392
  if (!tenantId) {
4393
4393
  return reply.status(401).send({ success: false, error: "Unauthorized" });
4394
4394
  }
4395
- const keyStore = (0, import_core77.getStoreLattice)("default", "a2aApiKey").store;
4395
+ const keyStore = (0, import_core78.getStoreLattice)("default", "a2aApiKey").store;
4396
4396
  const record = await keyStore.findById(request.params.id);
4397
4397
  if (!record || record.tenantId !== tenantId) {
4398
4398
  return reply.status(404).send({ success: false, error: "Key not found" });
4399
4399
  }
4400
- const grants = (0, import_protocols36.effectiveGrants)(record);
4400
+ const grants = (0, import_protocols37.effectiveGrants)(record);
4401
4401
  const forwardedHost = request.headers["x-forwarded-host"];
4402
4402
  const host = (Array.isArray(forwardedHost) ? forwardedHost[0] : forwardedHost) ?? (Array.isArray(request.headers.host) ? request.headers.host[0] : request.headers.host) ?? request.hostname;
4403
4403
  const baseUrl = `${request.protocol}://${host}`;
@@ -4426,7 +4426,7 @@ function registerOpenExposureRoutes(app2, deps = {}) {
4426
4426
  hasUi: Boolean(t2.ui)
4427
4427
  }));
4428
4428
  const agentGrant = grants.find((g) => g.domain === "agent");
4429
- const assistantStore = (0, import_core77.getStoreLattice)("default", "assistant").store;
4429
+ const assistantStore = (0, import_core78.getStoreLattice)("default", "assistant").store;
4430
4430
  const agents = [];
4431
4431
  for (const assistantId of agentGrant?.items ?? []) {
4432
4432
  const assistant = await assistantStore.getAssistantById(
@@ -4461,12 +4461,12 @@ function registerOpenExposureRoutes(app2, deps = {}) {
4461
4461
  }
4462
4462
  );
4463
4463
  }
4464
- var import_core77, import_protocols36;
4464
+ var import_core78, import_protocols37;
4465
4465
  var init_open_exposure = __esm({
4466
4466
  "src/routes/open-exposure.ts"() {
4467
4467
  "use strict";
4468
- import_core77 = require("@axiom-lattice/core");
4469
- import_protocols36 = require("@axiom-lattice/protocols");
4468
+ import_core78 = require("@axiom-lattice/core");
4469
+ import_protocols37 = require("@axiom-lattice/protocols");
4470
4470
  init_openLattice();
4471
4471
  init_tenantOpenPlugins();
4472
4472
  init_A2AAgentCardBuilder();
@@ -4490,9 +4490,9 @@ function createKbProvider(collectionService3) {
4490
4490
  label: "Search collections",
4491
4491
  description: "Search a knowledge base collection. Returns matched entries with content, metadata and similarity score.",
4492
4492
  schema: {
4493
- collection: import_zod20.z.string().min(1),
4494
- query: import_zod20.z.string().min(1),
4495
- limit: import_zod20.z.number().int().min(1).max(50).optional()
4493
+ collection: import_zod22.z.string().min(1),
4494
+ query: import_zod22.z.string().min(1),
4495
+ limit: import_zod22.z.number().int().min(1).max(50).optional()
4496
4496
  },
4497
4497
  annotations: { readOnlyHint: true, destructiveHint: false }
4498
4498
  }
@@ -4520,11 +4520,11 @@ function createKbProvider(collectionService3) {
4520
4520
  }
4521
4521
  };
4522
4522
  }
4523
- var import_zod20;
4523
+ var import_zod22;
4524
4524
  var init_kbProvider = __esm({
4525
4525
  "src/services/open/providers/kbProvider.ts"() {
4526
4526
  "use strict";
4527
- import_zod20 = require("zod");
4527
+ import_zod22 = require("zod");
4528
4528
  }
4529
4529
  });
4530
4530
 
@@ -4562,7 +4562,7 @@ function createAgentProvider(deps = {}) {
4562
4562
  toolName: `invoke_${assistantId}`,
4563
4563
  label: name,
4564
4564
  description: `Invoke the "${name}" agent${description ? ` \u2014 ${description}` : ""}. Returns its final reply.`,
4565
- schema: { message: import_zod21.z.string().min(1) },
4565
+ schema: { message: import_zod23.z.string().min(1) },
4566
4566
  annotations: { readOnlyHint: false, destructiveHint: false }
4567
4567
  };
4568
4568
  })
@@ -4585,7 +4585,7 @@ function createAgentProvider(deps = {}) {
4585
4585
  } catch {
4586
4586
  }
4587
4587
  }
4588
- const agent = import_core78.agentInstanceManager.getAgent({
4588
+ const agent = import_core79.agentInstanceManager.getAgent({
4589
4589
  tenant_id: ctx.tenantId,
4590
4590
  assistant_id: assistantId,
4591
4591
  thread_id: threadId,
@@ -4599,8 +4599,8 @@ function createAgentProvider(deps = {}) {
4599
4599
  const stream = agent.chunkStream(messageId, [...STOP_TYPES]);
4600
4600
  for await (const chunk of stream) {
4601
4601
  const text = chunk.data?.content;
4602
- if (chunk.type === import_protocols37.MessageChunkTypes.INTERRUPT) break;
4603
- if (chunk.type === import_protocols37.MessageChunkTypes.AI && text) {
4602
+ if (chunk.type === import_protocols38.MessageChunkTypes.INTERRUPT) break;
4603
+ if (chunk.type === import_protocols38.MessageChunkTypes.AI && text) {
4604
4604
  parts.push(text);
4605
4605
  }
4606
4606
  }
@@ -4610,14 +4610,14 @@ function createAgentProvider(deps = {}) {
4610
4610
  }
4611
4611
  };
4612
4612
  }
4613
- var import_zod21, import_core78, import_protocols37, STOP_TYPES;
4613
+ var import_zod23, import_core79, import_protocols38, STOP_TYPES;
4614
4614
  var init_agentProvider = __esm({
4615
4615
  "src/services/open/providers/agentProvider.ts"() {
4616
4616
  "use strict";
4617
- import_zod21 = require("zod");
4618
- import_core78 = require("@axiom-lattice/core");
4619
- import_protocols37 = require("@axiom-lattice/protocols");
4620
- STOP_TYPES = [import_protocols37.MessageChunkTypes.MESSAGE_COMPLETED];
4617
+ import_zod23 = require("zod");
4618
+ import_core79 = require("@axiom-lattice/core");
4619
+ import_protocols38 = require("@axiom-lattice/protocols");
4620
+ STOP_TYPES = [import_protocols38.MessageChunkTypes.MESSAGE_COMPLETED];
4621
4621
  }
4622
4622
  });
4623
4623
 
@@ -4647,12 +4647,12 @@ var resources_exports = {};
4647
4647
  __export(resources_exports, {
4648
4648
  ResourceController: () => ResourceController
4649
4649
  });
4650
- var import_bcryptjs, import_core79, ResourceController;
4650
+ var import_bcryptjs, import_core80, ResourceController;
4651
4651
  var init_resources = __esm({
4652
4652
  "src/controllers/resources.ts"() {
4653
4653
  "use strict";
4654
4654
  import_bcryptjs = __toESM(require("bcryptjs"));
4655
- import_core79 = require("@axiom-lattice/core");
4655
+ import_core80 = require("@axiom-lattice/core");
4656
4656
  init_mime();
4657
4657
  init_http_range();
4658
4658
  init_sandboxGrants();
@@ -4669,14 +4669,14 @@ var init_resources = __esm({
4669
4669
  if (!workspaceId || !projectId) {
4670
4670
  return reply.status(400).send({ error: "x-workspace-id and x-project-id headers required" });
4671
4671
  }
4672
- const payload = (0, import_core79.createSharePayload)(
4672
+ const payload = (0, import_core80.createSharePayload)(
4673
4673
  tenantId,
4674
4674
  workspaceId,
4675
4675
  projectId,
4676
4676
  userId,
4677
4677
  body
4678
4678
  );
4679
- const token = (0, import_core79.generateToken)();
4679
+ const token = (0, import_core80.generateToken)();
4680
4680
  try {
4681
4681
  await this.deps.store.create({ ...payload, token });
4682
4682
  this.deps.logger.info(
@@ -4828,7 +4828,7 @@ var init_resources = __esm({
4828
4828
  resourcePath: subPath
4829
4829
  }, subPath, ext, request, reply);
4830
4830
  }
4831
- const volume = (0, import_core79.buildNamedVolumeName)("p", "project", tenantId, workspaceId, projectId);
4831
+ const volume = (0, import_core80.buildNamedVolumeName)("p", "project", tenantId, workspaceId, projectId);
4832
4832
  return this._resolveAndServe(
4833
4833
  volume,
4834
4834
  subPath,
@@ -5052,8 +5052,8 @@ var import_static = __toESM(require("@fastify/static"));
5052
5052
  var import_path = __toESM(require("path"));
5053
5053
 
5054
5054
  // src/routes/index.ts
5055
- var import_node_crypto25 = require("crypto");
5056
- var import_protocols29 = require("@axiom-lattice/protocols");
5055
+ var import_node_crypto26 = require("crypto");
5056
+ var import_protocols30 = require("@axiom-lattice/protocols");
5057
5057
 
5058
5058
  // src/controllers/assistant.ts
5059
5059
  var import_core = require("@axiom-lattice/core");
@@ -6910,9 +6910,9 @@ async function getConfig(request, reply) {
6910
6910
  var import_core9 = require("@axiom-lattice/core");
6911
6911
  async function getModels(request, reply) {
6912
6912
  try {
6913
- const allLattices = import_core9.modelLatticeManager.getAllLattices();
6913
+ const allLattices = import_core9.modelLatticeManager.getAllLatticesByTenant("default");
6914
6914
  const models = allLattices.map((lattice) => {
6915
- const config = lattice.client.config || {};
6915
+ const config = lattice.client.getConfig();
6916
6916
  const displayName = config.displayName || lattice.key.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
6917
6917
  return {
6918
6918
  key: lattice.key,
@@ -6920,7 +6920,13 @@ async function getModels(request, reply) {
6920
6920
  provider: config.provider || "openai",
6921
6921
  displayName,
6922
6922
  streaming: config.streaming || false,
6923
- apiKey: config.apiKey || "",
6923
+ // The key itself is NOT returned. `hasApiKey` is what a client needs to
6924
+ // render "configured — leave blank to keep"; the value was previously
6925
+ // sent in cleartext to every caller of this endpoint, which put provider
6926
+ // credentials in any browser that loaded the model settings. Clients
6927
+ // that edit a model therefore leave the key field empty, which
6928
+ // `updateModels` reads as "keep the existing one".
6929
+ hasApiKey: Boolean(config.apiKey),
6924
6930
  baseURL: config.baseURL || "",
6925
6931
  maxTokens: config.maxTokens,
6926
6932
  temperature: config.temperature,
@@ -6962,6 +6968,8 @@ async function updateModels(request, reply) {
6962
6968
  continue;
6963
6969
  }
6964
6970
  try {
6971
+ const existingConfig = import_core9.modelLatticeManager.hasLattice(modelConfig.key) ? import_core9.modelLatticeManager.getModelLattice(modelConfig.key).client.getConfig() : void 0;
6972
+ const effectiveApiKey = modelConfig.clearApiKey ? void 0 : modelConfig.apiKey || existingConfig?.apiKey;
6965
6973
  if (import_core9.modelLatticeManager.hasLattice(modelConfig.key)) {
6966
6974
  import_core9.modelLatticeManager.removeLattice(modelConfig.key);
6967
6975
  }
@@ -6970,7 +6978,7 @@ async function updateModels(request, reply) {
6970
6978
  model: modelConfig.model,
6971
6979
  displayName: modelConfig.displayName,
6972
6980
  streaming: modelConfig.streaming ?? false,
6973
- apiKey: modelConfig.apiKey,
6981
+ apiKey: effectiveApiKey,
6974
6982
  baseURL: modelConfig.baseURL,
6975
6983
  maxTokens: modelConfig.maxTokens,
6976
6984
  temperature: modelConfig.temperature,
@@ -16712,7 +16720,7 @@ function registerTaskRoutes(app2, controller) {
16712
16720
  }
16713
16721
 
16714
16722
  // src/routes/index.ts
16715
- var import_core50 = require("@axiom-lattice/core");
16723
+ var import_core51 = require("@axiom-lattice/core");
16716
16724
 
16717
16725
  // src/controllers/tasks.ts
16718
16726
  var import_protocols13 = require("@axiom-lattice/protocols");
@@ -20612,177 +20620,1298 @@ function registerCapabilityBundleRoutes(app2, controller) {
20612
20620
  app2.post("/api/projects/:projectId/capability-preview", controller.postProjectPreview.bind(controller));
20613
20621
  }
20614
20622
 
20615
- // src/services/collaboration/ProjectRoomService.ts
20623
+ // src/controllers/model-providers.ts
20624
+ var import_zod11 = require("zod");
20625
+
20626
+ // src/services/model-provider/ModelProviderService.ts
20616
20627
  var import_node_crypto14 = require("crypto");
20617
- var ProjectRoomService = class {
20618
- /** Creates a project room service from explicitly injected collaborators. */
20619
- constructor(deps) {
20620
- this.deps = deps;
20621
- this.idFactory = deps.idFactory ?? import_node_crypto14.randomUUID;
20622
- }
20623
- /**
20624
- * Authorizes read access and ensures the project's main room.
20625
- *
20626
- * @remarks
20627
- * This method is safe to call while holding the process-wide Project
20628
- * mutation mutex: it never re-enters it. Coordinator backfill is a separate
20629
- * entry point ({@link ensureMainRoomWithCoordinator}) because it acquires
20630
- * that mutex internally.
20631
- */
20632
- async ensureMainRoom(input) {
20633
- const { room } = await this.authorizedRoom(input);
20634
- return room;
20635
- }
20636
- /**
20637
- * Authorizes read access, ensures the main room, and lazily backfills the
20638
- * built-in coordinator for business projects.
20639
- *
20640
- * @remarks
20641
- * Only call this outside the Project mutation mutex (room open / bootstrap
20642
- * paths); calling it under the mutex deadlocks on the coordinator ensurer.
20643
- */
20644
- async ensureMainRoomWithCoordinator(input) {
20645
- const { project, room } = await this.authorizedRoom(input);
20646
- if ((project.kind === "business" || project.kind === "public") && this.deps.ensureCoordinator) {
20647
- try {
20648
- await this.deps.ensureCoordinator({
20649
- tenantId: input.tenantId,
20650
- workspaceId: project.workspaceId,
20651
- projectId: project.id,
20652
- roomId: room.id
20653
- });
20654
- } catch (error) {
20655
- this.deps.log?.warn("project-room:coordinator-ensure-failed", {
20656
- tenantId: input.tenantId,
20657
- projectId: project.id,
20658
- errorName: error instanceof Error ? error.name : "UnknownError"
20659
- });
20660
- }
20661
- }
20662
- return room;
20663
- }
20664
- async authorizedRoom(input) {
20665
- const { project } = await this.deps.accessService.requireProjectAccess({
20666
- ...input,
20667
- capability: "read"
20668
- });
20669
- const room = await this.deps.roomStore.ensureMainRoom({
20670
- id: this.idFactory(),
20671
- tenantId: input.tenantId,
20672
- workspaceId: project.workspaceId,
20673
- projectId: project.id,
20674
- name: project.name
20675
- });
20676
- return { project, room };
20677
- }
20678
- };
20628
+ var import_protocols16 = require("@axiom-lattice/protocols");
20629
+ var import_core47 = require("@axiom-lattice/core");
20679
20630
 
20680
- // src/services/collaboration/ProjectMembershipService.ts
20681
- var import_node_crypto15 = require("crypto");
20682
- var ProjectMembershipServiceError = class extends Error {
20683
- constructor(code, statusCode, message) {
20631
+ // src/services/model-provider/errors.ts
20632
+ var ModelProviderServiceError = class extends Error {
20633
+ /** Creates a model provider service error. */
20634
+ constructor(code, statusCode, message, retryable = false) {
20684
20635
  super(message);
20685
20636
  this.code = code;
20686
20637
  this.statusCode = statusCode;
20687
- this.name = "ProjectMembershipServiceError";
20638
+ this.retryable = retryable;
20639
+ this.name = "ModelProviderServiceError";
20688
20640
  }
20689
20641
  };
20690
- var membershipConflictNames2 = /* @__PURE__ */ new Set(["DuplicateProjectMembershipError", "ProjectMembershipIdConflictError"]);
20691
- function isMembershipConflict(error) {
20692
- return error instanceof Error && membershipConflictNames2.has(error.name);
20693
- }
20694
- var ProjectMembershipService = class {
20695
- constructor(deps) {
20696
- this.deps = deps;
20697
- this.idFactory = deps.idFactory ?? import_node_crypto15.randomUUID;
20698
- this.mutationMutex = deps.projectMutationMutex ?? import_core26.projectMutationMutex;
20699
- }
20700
- async list(actor3) {
20701
- await this.deps.accessService.requireRosterAccess(actor3);
20702
- const membership = await this.deps.membershipStore.findByUser(actor3.tenantId, actor3.projectId, actor3.userId);
20703
- if (!membership || membership.status !== "active") this.accessDenied();
20704
- return this.deps.membershipStore.list(actor3.tenantId, actor3.projectId);
20705
- }
20706
- async add(actor3, input) {
20707
- return this.withProjectLock(actor3, async () => {
20708
- const access = await this.authorize(actor3);
20709
- if (input.role === "owner" && access.role !== "owner") this.accessDenied();
20710
- if (!await this.deps.userTenantLinkStore.getLink(input.userId, actor3.tenantId)) {
20711
- throw new ProjectMembershipServiceError("TARGET_USER_NOT_IN_TENANT", 400, "Target user is not in the tenant");
20712
- }
20713
- if (await this.deps.membershipStore.findByUser(actor3.tenantId, actor3.projectId, input.userId)) {
20714
- throw new ProjectMembershipServiceError("MEMBERSHIP_EXISTS", 409, "Project membership already exists");
20715
- }
20716
- try {
20717
- const created = await this.deps.membershipStore.create({
20718
- id: this.idFactory(),
20719
- tenantId: actor3.tenantId,
20720
- projectId: actor3.projectId,
20721
- userId: input.userId,
20722
- role: input.role,
20723
- status: "active"
20724
- });
20725
- this.publish(created, "added", `membership:${created.id}:add:${created.joinedAt.toISOString()}`);
20726
- return created;
20727
- } catch (error) {
20728
- if (error instanceof Error && error.name === "DuplicateProjectMembershipError") {
20729
- throw new ProjectMembershipServiceError("MEMBERSHIP_EXISTS", 409, "Project membership already exists");
20730
- }
20731
- if (isMembershipConflict(error)) {
20732
- throw new ProjectMembershipServiceError("MEMBERSHIP_CONFLICT", 409, "Project membership could not be created");
20733
- }
20734
- throw error;
20735
- }
20736
- });
20642
+
20643
+ // src/services/model-provider/discovery.ts
20644
+ var MAX_DISCOVERED_MODELS = 1e3;
20645
+ var MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
20646
+ var DEFAULT_DISCOVERY_TIMEOUT_MS = 8e3;
20647
+ function resolveDiscoveryTimeoutMs(raw = process.env.LATTICE_MODEL_DISCOVERY_TIMEOUT_MS) {
20648
+ if (!raw) {
20649
+ return DEFAULT_DISCOVERY_TIMEOUT_MS;
20650
+ }
20651
+ const parsed = Number.parseInt(raw, 10);
20652
+ if (!Number.isFinite(parsed) || parsed <= 0) {
20653
+ return DEFAULT_DISCOVERY_TIMEOUT_MS;
20737
20654
  }
20738
- async updateRole(actor3, input) {
20739
- return this.withProjectLock(actor3, async () => {
20740
- const access = await this.authorize(actor3);
20741
- const target = await this.target(actor3, input.membershipId);
20742
- this.requireActiveAndCurrent(target, input.expectedUpdatedAt);
20743
- if ((target.role === "owner" || input.role === "owner") && access.role !== "owner") this.accessDenied();
20744
- const updated = await this.mapMutation(await this.deps.membershipStore.updateRole({ tenantId: actor3.tenantId, id: input.membershipId, role: input.role, expectedUpdatedAt: input.expectedUpdatedAt }));
20745
- this.publish(updated, "role_changed", `membership:${updated.id}:role:${updated.role}:${input.expectedUpdatedAt.toISOString()}`);
20746
- return updated;
20747
- });
20655
+ return parsed;
20656
+ }
20657
+ function buildModelsEndpoint(baseURL) {
20658
+ const url = new URL(baseURL);
20659
+ const trimmed = url.pathname.replace(/\/+$/, "");
20660
+ url.pathname = trimmed.endsWith("/v1") ? `${trimmed}/models` : `${trimmed}/v1/models`;
20661
+ url.search = "";
20662
+ url.hash = "";
20663
+ return url.toString();
20664
+ }
20665
+ function parseModelsPayload(payload) {
20666
+ const entries = Array.isArray(payload) ? payload : typeof payload === "object" && payload !== null ? payload.data : void 0;
20667
+ if (!Array.isArray(entries)) {
20668
+ throw new ModelProviderServiceError(
20669
+ "UPSTREAM_INVALID_RESPONSE",
20670
+ 502,
20671
+ "Upstream did not return a model list"
20672
+ );
20748
20673
  }
20749
- async remove(actor3, input) {
20750
- return this.withProjectLock(actor3, async () => {
20751
- const access = await this.authorize(actor3);
20752
- const target = await this.target(actor3, input.membershipId);
20753
- this.requireActiveAndCurrent(target, input.expectedUpdatedAt);
20754
- if (target.role === "owner" && access.role !== "owner") this.accessDenied();
20755
- const removed = await this.mapMutation(await this.deps.membershipStore.remove({ tenantId: actor3.tenantId, id: input.membershipId, expectedUpdatedAt: input.expectedUpdatedAt }));
20756
- this.publish(removed, "removed", `membership:${removed.id}:remove:${input.expectedUpdatedAt.toISOString()}`);
20757
- return removed;
20674
+ const models = [];
20675
+ for (const entry of entries.slice(0, MAX_DISCOVERED_MODELS)) {
20676
+ if (typeof entry !== "object" || entry === null) {
20677
+ continue;
20678
+ }
20679
+ const record = entry;
20680
+ const id3 = typeof record.id === "string" ? record.id.trim() : "";
20681
+ if (id3.length === 0) {
20682
+ continue;
20683
+ }
20684
+ models.push({
20685
+ id: id3,
20686
+ displayName: typeof record.name === "string" ? record.name : void 0,
20687
+ ownedBy: typeof record.owned_by === "string" ? record.owned_by : void 0,
20688
+ createdAt: parseUpstreamCreated(record.created),
20689
+ raw: record
20758
20690
  });
20759
20691
  }
20760
- async authorize(actor3) {
20761
- await this.deps.accessService.requireProjectAccess({ ...actor3, capability: "manage" });
20762
- const membership = await this.deps.membershipStore.findByUser(actor3.tenantId, actor3.projectId, actor3.userId);
20763
- if (!membership || membership.status !== "active") this.accessDenied();
20764
- return membership;
20765
- }
20766
- async target(actor3, id3) {
20767
- const target = (await this.deps.membershipStore.list(actor3.tenantId, actor3.projectId)).find((item) => item.id === id3);
20768
- if (!target) throw new ProjectMembershipServiceError("MEMBERSHIP_NOT_FOUND", 404, "Project membership not found");
20769
- return target;
20692
+ return models;
20693
+ }
20694
+ function parseUpstreamCreated(created) {
20695
+ if (typeof created !== "number" || !Number.isFinite(created)) {
20696
+ return void 0;
20770
20697
  }
20771
- requireActiveAndCurrent(target, expectedUpdatedAt2) {
20772
- if (target.status !== "active") {
20773
- throw new ProjectMembershipServiceError("MEMBERSHIP_NOT_FOUND", 404, "Project membership not found");
20698
+ const date = new Date(created * 1e3);
20699
+ return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
20700
+ }
20701
+ var openAiCompatibleAdapter = {
20702
+ protocol: "openai-compatible",
20703
+ async discover({ baseURL, apiKey, signal }) {
20704
+ const endpoint = buildModelsEndpoint(baseURL);
20705
+ const headers = { Accept: "application/json" };
20706
+ if (apiKey) {
20707
+ headers.Authorization = `Bearer ${apiKey}`;
20774
20708
  }
20775
- if (!Number.isFinite(expectedUpdatedAt2.getTime()) || target.updatedAt.getTime() !== expectedUpdatedAt2.getTime()) {
20776
- throw new ProjectMembershipServiceError("MEMBERSHIP_CONFLICT", 409, "Project membership changed; reload before saving");
20709
+ let response;
20710
+ try {
20711
+ response = await fetch(endpoint, {
20712
+ method: "GET",
20713
+ headers,
20714
+ // Never follow redirects: a redirected request could reach an
20715
+ // address that bypassed the SSRF checks.
20716
+ redirect: "manual",
20717
+ signal
20718
+ });
20719
+ } catch (error) {
20720
+ if (error instanceof Error && error.name === "AbortError") {
20721
+ throw new ModelProviderServiceError(
20722
+ "UPSTREAM_TIMEOUT",
20723
+ 504,
20724
+ "Upstream did not respond in time",
20725
+ true
20726
+ );
20727
+ }
20728
+ throw new ModelProviderServiceError(
20729
+ "UPSTREAM_UNREACHABLE",
20730
+ 502,
20731
+ "Upstream could not be reached",
20732
+ true
20733
+ );
20734
+ }
20735
+ if (response.status >= 300 && response.status < 400) {
20736
+ throw new ModelProviderServiceError(
20737
+ "UPSTREAM_REDIRECT_BLOCKED",
20738
+ 502,
20739
+ "Upstream returned a redirect; configure the final URL directly"
20740
+ );
20741
+ }
20742
+ if (response.status === 401 || response.status === 403) {
20743
+ throw new ModelProviderServiceError(
20744
+ "UPSTREAM_AUTH_FAILED",
20745
+ 502,
20746
+ "Upstream rejected the configured credentials"
20747
+ );
20748
+ }
20749
+ if (response.status === 429) {
20750
+ throw new ModelProviderServiceError(
20751
+ "UPSTREAM_RATE_LIMITED",
20752
+ 502,
20753
+ "Upstream rate limited the request",
20754
+ true
20755
+ );
20756
+ }
20757
+ if (!response.ok) {
20758
+ throw new ModelProviderServiceError(
20759
+ "UPSTREAM_UNREACHABLE",
20760
+ 502,
20761
+ "Upstream returned an error response",
20762
+ response.status >= 500
20763
+ );
20764
+ }
20765
+ const body = await readBodyWithLimit(response, MAX_RESPONSE_BYTES);
20766
+ let payload;
20767
+ try {
20768
+ payload = JSON.parse(body);
20769
+ } catch {
20770
+ throw new ModelProviderServiceError(
20771
+ "UPSTREAM_INVALID_RESPONSE",
20772
+ 502,
20773
+ "Upstream response was not valid JSON"
20774
+ );
20777
20775
  }
20776
+ return parseModelsPayload(payload);
20778
20777
  }
20779
- async mapMutation(result) {
20780
- if (result.kind === "updated" || result.kind === "removed") return result.membership;
20781
- if (result.kind === "not_found") throw new ProjectMembershipServiceError("MEMBERSHIP_NOT_FOUND", 404, "Project membership not found");
20782
- if (result.kind === "conflict") throw new ProjectMembershipServiceError("MEMBERSHIP_CONFLICT", 409, "Project membership changed; reload before saving");
20783
- throw new ProjectMembershipServiceError("LAST_OWNER", 409, "The project must retain an owner");
20778
+ };
20779
+ async function readBodyWithLimit(response, maxBytes) {
20780
+ if (!response.body) {
20781
+ return response.text();
20784
20782
  }
20785
- publish(membership, change, sourceKey) {
20783
+ const reader = response.body.getReader();
20784
+ const decoder = new TextDecoder();
20785
+ let received = 0;
20786
+ let text = "";
20787
+ try {
20788
+ for (; ; ) {
20789
+ const { done, value } = await reader.read();
20790
+ if (done) {
20791
+ break;
20792
+ }
20793
+ if (!value) {
20794
+ continue;
20795
+ }
20796
+ received += value.byteLength;
20797
+ if (received > maxBytes) {
20798
+ await reader.cancel();
20799
+ throw new ModelProviderServiceError(
20800
+ "UPSTREAM_INVALID_RESPONSE",
20801
+ 502,
20802
+ "Upstream response was too large"
20803
+ );
20804
+ }
20805
+ text += decoder.decode(value, { stream: true });
20806
+ }
20807
+ } finally {
20808
+ reader.releaseLock();
20809
+ }
20810
+ return text + decoder.decode();
20811
+ }
20812
+ var adapters = /* @__PURE__ */ new Map([
20813
+ [openAiCompatibleAdapter.protocol, openAiCompatibleAdapter]
20814
+ ]);
20815
+ function getDiscoveryAdapter(protocol) {
20816
+ return adapters.get(protocol);
20817
+ }
20818
+
20819
+ // src/services/model-provider/ModelProviderService.ts
20820
+ var PHASE1_REGISTRY_TENANT = "default";
20821
+ var ALLOWED_LLM_PROVIDERS = /* @__PURE__ */ new Set(["openai"]);
20822
+ var unsafeReasonToErrorCode = {
20823
+ INVALID_BASE_URL: "INVALID_BASE_URL",
20824
+ UNSUPPORTED_SCHEME: "INVALID_BASE_URL",
20825
+ CREDENTIALS_IN_URL: "INVALID_BASE_URL"
20826
+ };
20827
+ var ModelProviderService = class {
20828
+ constructor(deps) {
20829
+ this.deps = deps;
20830
+ this.idFactory = deps.idFactory ?? (() => (0, import_node_crypto14.randomUUID)());
20831
+ }
20832
+ /**
20833
+ * List the tenant's provider configurations.
20834
+ */
20835
+ async list(userId, tenantId) {
20836
+ await this.assertMember(userId, tenantId);
20837
+ const providers = await this.deps.providerStore.listProviders(tenantId);
20838
+ const models = await this.deps.providerStore.listModels(tenantId);
20839
+ const modelCounts = /* @__PURE__ */ new Map();
20840
+ for (const model of models) {
20841
+ modelCounts.set(
20842
+ model.providerId,
20843
+ (modelCounts.get(model.providerId) ?? 0) + 1
20844
+ );
20845
+ }
20846
+ return providers.map(
20847
+ (provider) => this.toPublicEntry(provider, modelCounts.get(provider.id) ?? 0)
20848
+ );
20849
+ }
20850
+ /**
20851
+ * Read one provider configuration.
20852
+ */
20853
+ async get(userId, tenantId, id3) {
20854
+ await this.assertMember(userId, tenantId);
20855
+ const provider = await this.requireProvider(tenantId, id3);
20856
+ const models = await this.deps.providerStore.listModels(tenantId, id3);
20857
+ return this.toPublicEntry(provider, models.length);
20858
+ }
20859
+ /**
20860
+ * The full model catalog visible to a tenant.
20861
+ */
20862
+ async catalog(userId, tenantId) {
20863
+ await this.assertMember(userId, tenantId);
20864
+ const providers = await this.deps.providerStore.listProviders(tenantId);
20865
+ const snapshot = await this.deps.providerStore.listModels(tenantId);
20866
+ const providerNames = new Map(
20867
+ providers.map((provider) => [provider.id, provider.name])
20868
+ );
20869
+ const disabledProviderIds = new Set(
20870
+ providers.filter((provider) => !provider.enabled).map((p) => p.id)
20871
+ );
20872
+ const modelCounts = /* @__PURE__ */ new Map();
20873
+ for (const model of snapshot) {
20874
+ modelCounts.set(
20875
+ model.providerId,
20876
+ (modelCounts.get(model.providerId) ?? 0) + 1
20877
+ );
20878
+ }
20879
+ const models = snapshot.map((model) => ({
20880
+ modelKey: (0, import_protocols16.toModelKey)(model.providerId, model.modelId),
20881
+ displayName: model.displayName,
20882
+ providerId: model.providerId,
20883
+ providerName: providerNames.get(model.providerId) ?? model.providerId,
20884
+ ownedBy: model.ownedBy,
20885
+ source: "snapshot",
20886
+ enabled: model.enabled,
20887
+ stale: model.stale ?? false,
20888
+ executable: model.enabled && // A disabled provider is a kill switch: its models stay visible in the
20889
+ // catalog but are no longer reported as runnable.
20890
+ !disabledProviderIds.has(model.providerId) && this.deps.registry.has(
20891
+ tenantId,
20892
+ (0, import_protocols16.toModelKey)(model.providerId, model.modelId)
20893
+ )
20894
+ }));
20895
+ const known = new Set(models.map((model) => model.modelKey));
20896
+ for (const modelKey2 of this.deps.registry.listRegistered(tenantId)) {
20897
+ if (known.has(modelKey2)) {
20898
+ continue;
20899
+ }
20900
+ models.push({
20901
+ modelKey: modelKey2,
20902
+ providerId: "",
20903
+ providerName: "registered",
20904
+ source: "registered",
20905
+ enabled: true,
20906
+ stale: false,
20907
+ executable: true
20908
+ });
20909
+ }
20910
+ return {
20911
+ providers: providers.map(
20912
+ (provider) => this.toPublicEntry(provider, modelCounts.get(provider.id) ?? 0)
20913
+ ),
20914
+ models
20915
+ };
20916
+ }
20917
+ /**
20918
+ * Create a provider configuration. Does not run discovery.
20919
+ */
20920
+ async create(userId, tenantId, input) {
20921
+ await this.assertAdmin(userId, tenantId);
20922
+ this.assertHasApiKey(input.apiKey);
20923
+ if (!getDiscoveryAdapter(input.protocol)) {
20924
+ throw new ModelProviderServiceError(
20925
+ "UNSUPPORTED_PROTOCOL",
20926
+ 400,
20927
+ `Unsupported provider protocol`
20928
+ );
20929
+ }
20930
+ await this.assertSafeUrl(input.baseURL);
20931
+ const existing = await this.deps.providerStore.getProviderByName(
20932
+ tenantId,
20933
+ input.name
20934
+ );
20935
+ if (existing) {
20936
+ throw new ModelProviderServiceError(
20937
+ "PROVIDER_NAME_CONFLICT",
20938
+ 409,
20939
+ "A provider with this name already exists"
20940
+ );
20941
+ }
20942
+ const id3 = this.idFactory();
20943
+ try {
20944
+ const created = await this.deps.providerStore.createProvider(
20945
+ tenantId,
20946
+ id3,
20947
+ { ...input, enabled: input.enabled ?? true }
20948
+ );
20949
+ return this.toPublicEntry(created, 0);
20950
+ } catch (error) {
20951
+ throw this.mapStoreError(error);
20952
+ }
20953
+ }
20954
+ /**
20955
+ * Update a provider configuration.
20956
+ * An omitted or empty `apiKey` keeps the stored key.
20957
+ */
20958
+ async update(userId, tenantId, id3, updates) {
20959
+ await this.assertAdmin(userId, tenantId);
20960
+ const existing = await this.requireProvider(tenantId, id3);
20961
+ if (updates.clearApiKey || !(updates.apiKey?.trim() || existing.apiKey)) {
20962
+ this.assertHasApiKey(void 0);
20963
+ }
20964
+ if (updates.protocol && !getDiscoveryAdapter(updates.protocol)) {
20965
+ throw new ModelProviderServiceError(
20966
+ "UNSUPPORTED_PROTOCOL",
20967
+ 400,
20968
+ `Unsupported provider protocol`
20969
+ );
20970
+ }
20971
+ if (updates.baseURL && updates.baseURL !== existing.baseURL) {
20972
+ await this.assertSafeUrl(updates.baseURL);
20973
+ }
20974
+ if (updates.name && updates.name !== existing.name) {
20975
+ const conflicting = await this.deps.providerStore.getProviderByName(
20976
+ tenantId,
20977
+ updates.name
20978
+ );
20979
+ if (conflicting && conflicting.id !== id3) {
20980
+ throw new ModelProviderServiceError(
20981
+ "PROVIDER_NAME_CONFLICT",
20982
+ 409,
20983
+ "A provider with this name already exists"
20984
+ );
20985
+ }
20986
+ }
20987
+ try {
20988
+ const updated = await this.deps.providerStore.updateProvider(
20989
+ tenantId,
20990
+ id3,
20991
+ updates
20992
+ );
20993
+ if (!updated) {
20994
+ throw new ModelProviderServiceError(
20995
+ "PROVIDER_NOT_FOUND",
20996
+ 404,
20997
+ "Model provider not found"
20998
+ );
20999
+ }
21000
+ const models = await this.deps.providerStore.listModels(tenantId, id3);
21001
+ this.syncRegistry(tenantId, updated, models);
21002
+ return this.toPublicEntry(updated, models.length);
21003
+ } catch (error) {
21004
+ throw this.mapStoreError(error);
21005
+ }
21006
+ }
21007
+ /**
21008
+ * Delete a provider configuration, its snapshot, and any registry entries
21009
+ * that no other provider in the tenant still supplies.
21010
+ */
21011
+ async remove(userId, tenantId, id3) {
21012
+ await this.assertAdmin(userId, tenantId);
21013
+ await this.requireProvider(tenantId, id3);
21014
+ const snapshot = await this.deps.providerStore.listModels(tenantId, id3);
21015
+ await this.deps.providerStore.deleteProvider(tenantId, id3);
21016
+ for (const model of snapshot) {
21017
+ this.deps.registry.remove(tenantId, (0, import_protocols16.toModelKey)(id3, model.modelId));
21018
+ }
21019
+ }
21020
+ /**
21021
+ * Discover the provider's models and replace its snapshot.
21022
+ */
21023
+ async discover(userId, tenantId, id3) {
21024
+ await this.assertAdmin(userId, tenantId);
21025
+ const provider = await this.requireProvider(tenantId, id3);
21026
+ if (!provider.enabled) {
21027
+ throw new ModelProviderServiceError(
21028
+ "PROVIDER_DISABLED",
21029
+ 400,
21030
+ "Model provider is disabled"
21031
+ );
21032
+ }
21033
+ const adapter = getDiscoveryAdapter(provider.protocol);
21034
+ if (!adapter) {
21035
+ throw new ModelProviderServiceError(
21036
+ "UNSUPPORTED_PROTOCOL",
21037
+ 400,
21038
+ `Unsupported provider protocol`
21039
+ );
21040
+ }
21041
+ await this.assertSafeUrl(provider.baseURL);
21042
+ const controller = new AbortController();
21043
+ const timeout = setTimeout(
21044
+ () => controller.abort(),
21045
+ resolveDiscoveryTimeoutMs()
21046
+ );
21047
+ const previous = this.shouldRegister(tenantId) ? await this.deps.providerStore.listModels(tenantId, id3) : [];
21048
+ let discovered;
21049
+ try {
21050
+ discovered = await adapter.discover({
21051
+ baseURL: provider.baseURL,
21052
+ apiKey: provider.apiKey,
21053
+ signal: controller.signal
21054
+ });
21055
+ } catch (error) {
21056
+ if (error instanceof ModelProviderServiceError) {
21057
+ await this.deps.providerStore.markProviderStatus(
21058
+ tenantId,
21059
+ id3,
21060
+ "error",
21061
+ error.code
21062
+ );
21063
+ throw error;
21064
+ }
21065
+ throw error;
21066
+ } finally {
21067
+ clearTimeout(timeout);
21068
+ }
21069
+ const now = /* @__PURE__ */ new Date();
21070
+ const inserted = await this.deps.providerStore.replaceProviderModels(
21071
+ tenantId,
21072
+ id3,
21073
+ discovered
21074
+ );
21075
+ await this.deps.providerStore.markProviderStatus(
21076
+ tenantId,
21077
+ id3,
21078
+ "ok",
21079
+ void 0,
21080
+ now
21081
+ );
21082
+ const registered = [];
21083
+ if (this.shouldRegister(tenantId)) {
21084
+ const snapshot = await this.deps.providerStore.listModels(tenantId, id3);
21085
+ const currentKeys = new Set(
21086
+ snapshot.map((model) => (0, import_protocols16.toModelKey)(id3, model.modelId))
21087
+ );
21088
+ for (const model of previous) {
21089
+ const modelKey2 = (0, import_protocols16.toModelKey)(id3, model.modelId);
21090
+ if (!currentKeys.has(modelKey2)) {
21091
+ this.deps.registry.remove(tenantId, modelKey2);
21092
+ }
21093
+ }
21094
+ registered.push(...this.syncRegistry(tenantId, provider, snapshot));
21095
+ }
21096
+ return {
21097
+ discovered,
21098
+ registered,
21099
+ status: "ok"
21100
+ };
21101
+ }
21102
+ /**
21103
+ * Bring the execution registry in line with a provider's current state.
21104
+ *
21105
+ * Registration copies `apiKey` and `baseURL` by value, so a rotated
21106
+ * credential or a changed endpoint only takes effect once the model is
21107
+ * re-registered. Disabled models — and every model of a disabled provider —
21108
+ * are removed instead.
21109
+ *
21110
+ * @returns The model keys left registered
21111
+ */
21112
+ /**
21113
+ * Probe an upstream without touching the store.
21114
+ *
21115
+ * Powers the provider form's "test latency" and "list models" actions, which
21116
+ * validate a base URL and API key the user has typed but not yet saved. The
21117
+ * URL is validated exactly as on create/update and is never persisted, so the
21118
+ * "discover resolves its URL from the store" rule is not weakened — nothing
21119
+ * a probe learns can reach the snapshot.
21120
+ */
21121
+ async probe(userId, tenantId, input) {
21122
+ await this.assertAdmin(userId, tenantId);
21123
+ const protocol = input.protocol ?? "openai-compatible";
21124
+ const adapter = getDiscoveryAdapter(protocol);
21125
+ if (!adapter) {
21126
+ throw new ModelProviderServiceError(
21127
+ "UNSUPPORTED_PROTOCOL",
21128
+ 400,
21129
+ `Unsupported provider protocol`
21130
+ );
21131
+ }
21132
+ await this.assertSafeUrl(input.baseURL);
21133
+ let apiKey = input.apiKey || void 0;
21134
+ if (!apiKey && input.providerId) {
21135
+ const existing = await this.requireProvider(tenantId, input.providerId);
21136
+ apiKey = existing.apiKey;
21137
+ }
21138
+ const controller = new AbortController();
21139
+ const timeout = setTimeout(
21140
+ () => controller.abort(),
21141
+ resolveDiscoveryTimeoutMs()
21142
+ );
21143
+ const startedAt = Date.now();
21144
+ try {
21145
+ const models = await adapter.discover({
21146
+ baseURL: input.baseURL,
21147
+ apiKey,
21148
+ signal: controller.signal
21149
+ });
21150
+ return {
21151
+ reachable: true,
21152
+ latencyMs: Date.now() - startedAt,
21153
+ models
21154
+ };
21155
+ } catch (error) {
21156
+ if (error instanceof ModelProviderServiceError) {
21157
+ return {
21158
+ reachable: false,
21159
+ latencyMs: Date.now() - startedAt,
21160
+ models: [],
21161
+ error: error.code
21162
+ };
21163
+ }
21164
+ throw error;
21165
+ } finally {
21166
+ clearTimeout(timeout);
21167
+ }
21168
+ }
21169
+ /**
21170
+ * Set exactly which models this provider contributes.
21171
+ *
21172
+ * This is the "add model" action: the caller passes the ids it picked from
21173
+ * the live list, and the provider's model set becomes precisely those. Ids
21174
+ * are expected to have come from a probe — model names cannot be guessed,
21175
+ * since a wrong id surfaces later as "model not found" or an authorisation
21176
+ * error rather than at configuration time.
21177
+ */
21178
+ async setModels(userId, tenantId, id3, selection) {
21179
+ await this.assertAdmin(userId, tenantId);
21180
+ const provider = await this.requireProvider(tenantId, id3);
21181
+ const previous = await this.deps.providerStore.listModels(tenantId, id3);
21182
+ const previousById = new Map(
21183
+ previous.map((model) => [model.modelId, model])
21184
+ );
21185
+ await this.deps.providerStore.replaceProviderModels(
21186
+ tenantId,
21187
+ id3,
21188
+ selection.map((entry) => ({
21189
+ id: entry.modelId,
21190
+ enabled: entry.enabled,
21191
+ // A model the upstream stopped offering stays in the set, flagged
21192
+ // rather than dropped: deleting it would silently break anything
21193
+ // referencing its key.
21194
+ stale: entry.stale ?? false,
21195
+ // The selection carries only ids and states, so a model already in the
21196
+ // snapshot keeps the metadata discovery gave it.
21197
+ displayName: previousById.get(entry.modelId)?.displayName,
21198
+ ownedBy: previousById.get(entry.modelId)?.ownedBy
21199
+ }))
21200
+ );
21201
+ const models = await this.deps.providerStore.listModels(tenantId, id3);
21202
+ const kept = new Set(models.map((model) => model.modelId));
21203
+ for (const model of previous) {
21204
+ if (!kept.has(model.modelId)) {
21205
+ this.deps.registry.remove(
21206
+ tenantId,
21207
+ (0, import_protocols16.toModelKey)(provider.id, model.modelId)
21208
+ );
21209
+ }
21210
+ }
21211
+ this.syncRegistry(tenantId, provider, models);
21212
+ return this.toPublicEntry(provider, models.length);
21213
+ }
21214
+ syncRegistry(tenantId, provider, models) {
21215
+ if (!this.shouldRegister(tenantId)) {
21216
+ return [];
21217
+ }
21218
+ const registered = [];
21219
+ for (const model of models) {
21220
+ const modelKey2 = (0, import_protocols16.toModelKey)(provider.id, model.modelId);
21221
+ if (!provider.enabled || !model.enabled) {
21222
+ this.deps.registry.remove(tenantId, modelKey2);
21223
+ continue;
21224
+ }
21225
+ this.deps.registry.register(
21226
+ tenantId,
21227
+ modelKey2,
21228
+ this.toLlmConfig(provider, model.modelId)
21229
+ );
21230
+ registered.push(modelKey2);
21231
+ }
21232
+ return registered;
21233
+ }
21234
+ /**
21235
+ * Enable or disable a single discovered model.
21236
+ */
21237
+ async setModelEnabled(userId, tenantId, id3, modelId, enabled) {
21238
+ await this.assertAdmin(userId, tenantId);
21239
+ const provider = await this.requireProvider(tenantId, id3);
21240
+ const updated = await this.deps.providerStore.setModelEnabled(
21241
+ tenantId,
21242
+ id3,
21243
+ modelId,
21244
+ enabled
21245
+ );
21246
+ if (!updated) {
21247
+ throw new ModelProviderServiceError(
21248
+ "MODEL_KEY_CONFLICT",
21249
+ 404,
21250
+ "Model not found for this provider"
21251
+ );
21252
+ }
21253
+ const models = await this.deps.providerStore.listModels(tenantId, id3);
21254
+ this.syncRegistry(tenantId, provider, models);
21255
+ return this.toPublicEntry(provider, models.length);
21256
+ }
21257
+ /**
21258
+ * Whether discovered models should be registered for execution.
21259
+ */
21260
+ shouldRegister(tenantId) {
21261
+ return tenantId === PHASE1_REGISTRY_TENANT;
21262
+ }
21263
+ /**
21264
+ * Build the runtime LLM config for a discovered model.
21265
+ *
21266
+ * `apiKeyEnvName`, `extra` and `modelKwargs` are deliberately omitted — they
21267
+ * would let a tenant name an arbitrary process environment variable to read
21268
+ * credentials from, or inject arbitrary constructor options.
21269
+ */
21270
+ toLlmConfig(provider, modelId) {
21271
+ if (!ALLOWED_LLM_PROVIDERS.has(provider.llmProvider)) {
21272
+ throw new ModelProviderServiceError(
21273
+ "UNSUPPORTED_PROTOCOL",
21274
+ 400,
21275
+ "Provider is configured with an unsupported LLM provider"
21276
+ );
21277
+ }
21278
+ return {
21279
+ provider: provider.llmProvider,
21280
+ model: modelId,
21281
+ displayName: modelId,
21282
+ streaming: true,
21283
+ apiKey: provider.apiKey,
21284
+ baseURL: provider.baseURL,
21285
+ // Chat Completions and the Responses API are different routes with
21286
+ // different request fields; without this the gateway would post
21287
+ // `messages` to an endpoint expecting `input`.
21288
+ ...provider.apiStyle === "responses" ? { useResponsesApi: true } : {}
21289
+ };
21290
+ }
21291
+ /**
21292
+ * The sole projection from an internal provider entry to an API-safe shape.
21293
+ */
21294
+ toPublicEntry(provider, modelCount) {
21295
+ return {
21296
+ id: provider.id,
21297
+ tenantId: provider.tenantId,
21298
+ name: provider.name,
21299
+ displayName: provider.displayName,
21300
+ protocol: provider.protocol,
21301
+ apiStyle: provider.apiStyle,
21302
+ llmProvider: provider.llmProvider,
21303
+ baseURL: provider.baseURL,
21304
+ hasApiKey: Boolean(provider.apiKey),
21305
+ apiKeyHint: provider.apiKeyHint,
21306
+ enabled: provider.enabled,
21307
+ status: provider.status,
21308
+ lastError: provider.lastError,
21309
+ lastDiscoveredAt: provider.lastDiscoveredAt?.toISOString(),
21310
+ modelCount,
21311
+ createdAt: provider.createdAt.toISOString(),
21312
+ updatedAt: provider.updatedAt.toISOString()
21313
+ };
21314
+ }
21315
+ /**
21316
+ * Reject a provider that would end up without a credential.
21317
+ *
21318
+ * @param apiKey - The key the provider would hold, if any
21319
+ * @throws {ModelProviderServiceError} When no key is present
21320
+ */
21321
+ assertHasApiKey(apiKey) {
21322
+ if (!apiKey?.trim()) {
21323
+ throw new ModelProviderServiceError(
21324
+ "INVALID_INPUT",
21325
+ 400,
21326
+ "A model provider must have an API key"
21327
+ );
21328
+ }
21329
+ }
21330
+ /**
21331
+ * Load a provider or fail with 404.
21332
+ *
21333
+ * Callers always pass the session's tenant, so a provider belonging to
21334
+ * another tenant is indistinguishable from a missing one.
21335
+ */
21336
+ async requireProvider(tenantId, id3) {
21337
+ const provider = await this.deps.providerStore.getProviderById(tenantId, id3);
21338
+ if (!provider) {
21339
+ throw new ModelProviderServiceError(
21340
+ "PROVIDER_NOT_FOUND",
21341
+ 404,
21342
+ "Model provider not found"
21343
+ );
21344
+ }
21345
+ return provider;
21346
+ }
21347
+ /**
21348
+ * Require that the caller belongs to the tenant.
21349
+ * An absent userId means the unauthenticated development fallback.
21350
+ */
21351
+ async assertMember(userId, tenantId) {
21352
+ if (!userId) {
21353
+ return;
21354
+ }
21355
+ const link = await this.deps.userTenantLinkStore.getLink(userId, tenantId);
21356
+ if (!link) {
21357
+ throw new ModelProviderServiceError(
21358
+ "TENANT_ACCESS_DENIED",
21359
+ 403,
21360
+ "Tenant access denied"
21361
+ );
21362
+ }
21363
+ }
21364
+ /**
21365
+ * Require that the caller is a tenant owner or admin.
21366
+ * Roles are read from the tenant link, never from the session token.
21367
+ */
21368
+ async assertAdmin(userId, tenantId) {
21369
+ await this.assertMember(userId, tenantId);
21370
+ if (!userId) {
21371
+ return;
21372
+ }
21373
+ const link = await this.deps.userTenantLinkStore.getLink(userId, tenantId);
21374
+ if (link?.role !== "owner" && link?.role !== "admin") {
21375
+ throw new ModelProviderServiceError(
21376
+ "FORBIDDEN_ROLE",
21377
+ 403,
21378
+ "Only tenant owner or admin can manage model providers"
21379
+ );
21380
+ }
21381
+ }
21382
+ /**
21383
+ * Validate the shape of an upstream URL and translate failures into service
21384
+ * errors.
21385
+ *
21386
+ * Addresses are deliberately not restricted: other tenant-configured URLs in
21387
+ * this platform (metrics servers, MCP servers) reach wherever they point, and
21388
+ * self-hosted model servers normally sit on the gateway's own network.
21389
+ *
21390
+ * The mapping is explicit so the public error codes stay decoupled from the
21391
+ * reasons the URL utility happens to use internally.
21392
+ */
21393
+ async assertSafeUrl(baseURL) {
21394
+ try {
21395
+ await (0, import_core47.assertSafeUpstreamUrl)(baseURL);
21396
+ } catch (error) {
21397
+ if (error instanceof import_core47.UnsafeUpstreamUrlError) {
21398
+ throw new ModelProviderServiceError(
21399
+ unsafeReasonToErrorCode[error.reason],
21400
+ 400,
21401
+ error.message
21402
+ );
21403
+ }
21404
+ throw error;
21405
+ }
21406
+ }
21407
+ /**
21408
+ * Translate a store-level unique violation into a stable service error.
21409
+ */
21410
+ mapStoreError(error) {
21411
+ if (error instanceof ModelProviderServiceError) {
21412
+ return error;
21413
+ }
21414
+ const code = error?.code;
21415
+ if (code === "23505") {
21416
+ return new ModelProviderServiceError(
21417
+ "PROVIDER_NAME_CONFLICT",
21418
+ 409,
21419
+ "A provider with this name already exists"
21420
+ );
21421
+ }
21422
+ if (code === "23503") {
21423
+ return new ModelProviderServiceError(
21424
+ "INVALID_INPUT",
21425
+ 400,
21426
+ "Model provider references a missing record"
21427
+ );
21428
+ }
21429
+ throw error;
21430
+ }
21431
+ };
21432
+
21433
+ // src/schemas/model-provider.ts
21434
+ var import_zod10 = require("zod");
21435
+ var providerId = import_zod10.z.string().trim().min(1).max(255);
21436
+ var providerParamsSchema = import_zod10.z.object({ providerId }).strict();
21437
+ var protocolSchema = import_zod10.z.enum(["openai-compatible"]);
21438
+ var apiStyleSchema = import_zod10.z.enum(["chat-completions", "responses"]);
21439
+ var createProviderSchema = import_zod10.z.object({
21440
+ name: import_zod10.z.string().trim().min(1).max(255),
21441
+ displayName: import_zod10.z.string().trim().max(255).optional(),
21442
+ protocol: protocolSchema,
21443
+ apiStyle: apiStyleSchema.optional(),
21444
+ baseURL: import_zod10.z.string().trim().min(1).max(2048),
21445
+ // Required, not optional: see CreateModelProviderRequest.apiKey — a
21446
+ // keyless provider would make the gateway send its own env credential.
21447
+ apiKey: import_zod10.z.string().trim().min(1).max(1024),
21448
+ enabled: import_zod10.z.boolean().optional()
21449
+ }).strict();
21450
+ var updateProviderSchema = createProviderSchema.partial().extend({
21451
+ /**
21452
+ * Remove the stored API key. Needed because an empty `apiKey` means "keep":
21453
+ * without this a leaked credential could not be revoked.
21454
+ */
21455
+ clearApiKey: import_zod10.z.boolean().optional()
21456
+ }).strict();
21457
+ var setModelEnabledSchema = import_zod10.z.object({
21458
+ modelId: import_zod10.z.string().trim().min(1).max(512),
21459
+ enabled: import_zod10.z.boolean()
21460
+ }).strict();
21461
+ var discoverSchema = import_zod10.z.object({}).strict();
21462
+ var setModelsSchema = import_zod10.z.object({
21463
+ models: import_zod10.z.array(
21464
+ import_zod10.z.object({
21465
+ modelId: import_zod10.z.string().trim().min(1).max(512),
21466
+ enabled: import_zod10.z.boolean(),
21467
+ stale: import_zod10.z.boolean().optional()
21468
+ }).strict()
21469
+ ).max(1e3)
21470
+ }).strict();
21471
+ var probeProviderSchema = import_zod10.z.object({
21472
+ baseURL: import_zod10.z.string().trim().min(1).max(2048),
21473
+ apiKey: import_zod10.z.string().max(1024).optional(),
21474
+ providerId: import_zod10.z.string().trim().min(1).max(255).optional(),
21475
+ protocol: protocolSchema.optional()
21476
+ }).strict();
21477
+
21478
+ // src/controllers/tenant-scope.ts
21479
+ var TenantScopeError2 = class extends Error {
21480
+ /** Creates a tenant scope error. */
21481
+ constructor(code, statusCode, message) {
21482
+ super(message);
21483
+ this.code = code;
21484
+ this.statusCode = statusCode;
21485
+ this.name = "TenantScopeError";
21486
+ }
21487
+ };
21488
+ function resolveTenantScope(request, authRequired2) {
21489
+ const authenticated = request.user?.tenantId;
21490
+ const header2 = request.headers["x-tenant-id"];
21491
+ const requested = Array.isArray(header2) ? header2[0] : header2;
21492
+ if (authenticated) {
21493
+ if (requested && requested !== authenticated) {
21494
+ throw new TenantScopeError2(
21495
+ "TENANT_ACCESS_DENIED",
21496
+ 403,
21497
+ "Tenant access denied"
21498
+ );
21499
+ }
21500
+ return { tenantId: authenticated, userId: request.user?.id };
21501
+ }
21502
+ if (authRequired2) {
21503
+ throw new TenantScopeError2(
21504
+ "UNAUTHENTICATED",
21505
+ 401,
21506
+ "Console session required"
21507
+ );
21508
+ }
21509
+ return { tenantId: requested || "default" };
21510
+ }
21511
+
21512
+ // src/controllers/model-providers.ts
21513
+ init_Logger();
21514
+ var logger4 = new Logger({ serviceName: "lattice/gateway/model-providers" });
21515
+ function sendError2(reply, error) {
21516
+ if (error instanceof ModelProviderServiceError) {
21517
+ return reply.status(error.statusCode).send({
21518
+ success: false,
21519
+ error: {
21520
+ code: error.code,
21521
+ message: error.message,
21522
+ retryable: error.retryable
21523
+ }
21524
+ });
21525
+ }
21526
+ if (error instanceof TenantScopeError2) {
21527
+ return reply.status(error.statusCode).send({
21528
+ success: false,
21529
+ error: {
21530
+ code: error.code,
21531
+ message: error.message,
21532
+ retryable: false
21533
+ }
21534
+ });
21535
+ }
21536
+ if (error instanceof import_zod11.ZodError) {
21537
+ return reply.status(400).send({
21538
+ success: false,
21539
+ error: {
21540
+ code: "INVALID_INPUT",
21541
+ message: "Invalid request",
21542
+ retryable: false
21543
+ }
21544
+ });
21545
+ }
21546
+ logger4.error("Model provider controller error", {
21547
+ error: error instanceof Error ? error : new Error(String(error))
21548
+ });
21549
+ return reply.status(500).send({
21550
+ success: false,
21551
+ error: {
21552
+ code: "INTERNAL_ERROR",
21553
+ message: "Internal server error",
21554
+ retryable: false
21555
+ }
21556
+ });
21557
+ }
21558
+ var ModelProviderController = class {
21559
+ constructor(deps, options = {}) {
21560
+ this.service = new ModelProviderService(deps);
21561
+ this.authRequired = options.authRequired ?? true;
21562
+ }
21563
+ /** GET /api/tenant-models */
21564
+ async getCatalog(request, reply) {
21565
+ try {
21566
+ const scope = resolveTenantScope(request, this.authRequired);
21567
+ const catalog = await this.service.catalog(scope.userId, scope.tenantId);
21568
+ return reply.send({ success: true, data: catalog });
21569
+ } catch (error) {
21570
+ return sendError2(reply, error);
21571
+ }
21572
+ }
21573
+ /** GET /api/model-providers */
21574
+ async listProviders(request, reply) {
21575
+ try {
21576
+ const scope = resolveTenantScope(request, this.authRequired);
21577
+ const records = await this.service.list(scope.userId, scope.tenantId);
21578
+ return reply.send({
21579
+ success: true,
21580
+ data: { records, total: records.length }
21581
+ });
21582
+ } catch (error) {
21583
+ return sendError2(reply, error);
21584
+ }
21585
+ }
21586
+ /** GET /api/model-providers/:providerId */
21587
+ async getProvider(request, reply) {
21588
+ try {
21589
+ const scope = resolveTenantScope(request, this.authRequired);
21590
+ const { providerId: providerId2 } = providerParamsSchema.parse(request.params);
21591
+ return reply.send({
21592
+ success: true,
21593
+ data: await this.service.get(scope.userId, scope.tenantId, providerId2)
21594
+ });
21595
+ } catch (error) {
21596
+ return sendError2(reply, error);
21597
+ }
21598
+ }
21599
+ /** POST /api/model-providers */
21600
+ async createProvider(request, reply) {
21601
+ try {
21602
+ const scope = resolveTenantScope(request, this.authRequired);
21603
+ const input = createProviderSchema.parse(request.body);
21604
+ return reply.status(201).send({
21605
+ success: true,
21606
+ data: await this.service.create(scope.userId, scope.tenantId, input)
21607
+ });
21608
+ } catch (error) {
21609
+ return sendError2(reply, error);
21610
+ }
21611
+ }
21612
+ /** PUT /api/model-providers/:providerId */
21613
+ async updateProvider(request, reply) {
21614
+ try {
21615
+ const scope = resolveTenantScope(request, this.authRequired);
21616
+ const { providerId: providerId2 } = providerParamsSchema.parse(request.params);
21617
+ const input = updateProviderSchema.parse(request.body);
21618
+ return reply.send({
21619
+ success: true,
21620
+ data: await this.service.update(
21621
+ scope.userId,
21622
+ scope.tenantId,
21623
+ providerId2,
21624
+ input
21625
+ )
21626
+ });
21627
+ } catch (error) {
21628
+ return sendError2(reply, error);
21629
+ }
21630
+ }
21631
+ /** DELETE /api/model-providers/:providerId */
21632
+ async deleteProvider(request, reply) {
21633
+ try {
21634
+ const scope = resolveTenantScope(request, this.authRequired);
21635
+ const { providerId: providerId2 } = providerParamsSchema.parse(request.params);
21636
+ await this.service.remove(scope.userId, scope.tenantId, providerId2);
21637
+ return reply.send({ success: true, data: null });
21638
+ } catch (error) {
21639
+ return sendError2(reply, error);
21640
+ }
21641
+ }
21642
+ /** POST /api/model-providers/probe */
21643
+ async probeProvider(request, reply) {
21644
+ try {
21645
+ const scope = resolveTenantScope(request, this.authRequired);
21646
+ const input = probeProviderSchema.parse(request.body);
21647
+ return reply.send({
21648
+ success: true,
21649
+ data: await this.service.probe(scope.userId, scope.tenantId, input)
21650
+ });
21651
+ } catch (error) {
21652
+ return sendError2(reply, error);
21653
+ }
21654
+ }
21655
+ /** PUT /api/model-providers/:providerId/models */
21656
+ async setProviderModels(request, reply) {
21657
+ try {
21658
+ const scope = resolveTenantScope(request, this.authRequired);
21659
+ const { providerId: providerId2 } = providerParamsSchema.parse(request.params);
21660
+ const { models } = setModelsSchema.parse(request.body);
21661
+ return reply.send({
21662
+ success: true,
21663
+ data: await this.service.setModels(
21664
+ scope.userId,
21665
+ scope.tenantId,
21666
+ providerId2,
21667
+ models
21668
+ )
21669
+ });
21670
+ } catch (error) {
21671
+ return sendError2(reply, error);
21672
+ }
21673
+ }
21674
+ /** POST /api/model-providers/:providerId/discover */
21675
+ async discoverProvider(request, reply) {
21676
+ try {
21677
+ const scope = resolveTenantScope(request, this.authRequired);
21678
+ const { providerId: providerId2 } = providerParamsSchema.parse(request.params);
21679
+ discoverSchema.parse(request.body ?? {});
21680
+ return reply.send({
21681
+ success: true,
21682
+ data: await this.service.discover(
21683
+ scope.userId,
21684
+ scope.tenantId,
21685
+ providerId2
21686
+ )
21687
+ });
21688
+ } catch (error) {
21689
+ return sendError2(reply, error);
21690
+ }
21691
+ }
21692
+ /** POST /api/model-providers/:providerId/models/enabled */
21693
+ async setModelEnabled(request, reply) {
21694
+ try {
21695
+ const scope = resolveTenantScope(request, this.authRequired);
21696
+ const { providerId: providerId2 } = providerParamsSchema.parse(request.params);
21697
+ const { modelId, enabled } = setModelEnabledSchema.parse(request.body);
21698
+ return reply.send({
21699
+ success: true,
21700
+ data: await this.service.setModelEnabled(
21701
+ scope.userId,
21702
+ scope.tenantId,
21703
+ providerId2,
21704
+ modelId,
21705
+ enabled
21706
+ )
21707
+ });
21708
+ } catch (error) {
21709
+ return sendError2(reply, error);
21710
+ }
21711
+ }
21712
+ };
21713
+ function registerModelProviderRoutes(app2, controller) {
21714
+ app2.get("/api/tenant-models", controller.getCatalog.bind(controller));
21715
+ app2.get("/api/model-providers", controller.listProviders.bind(controller));
21716
+ app2.post("/api/model-providers", controller.createProvider.bind(controller));
21717
+ app2.post("/api/model-providers/probe", controller.probeProvider.bind(controller));
21718
+ app2.get(
21719
+ "/api/model-providers/:providerId",
21720
+ controller.getProvider.bind(controller)
21721
+ );
21722
+ app2.put(
21723
+ "/api/model-providers/:providerId",
21724
+ controller.updateProvider.bind(controller)
21725
+ );
21726
+ app2.delete(
21727
+ "/api/model-providers/:providerId",
21728
+ controller.deleteProvider.bind(controller)
21729
+ );
21730
+ app2.post(
21731
+ "/api/model-providers/:providerId/discover",
21732
+ controller.discoverProvider.bind(controller)
21733
+ );
21734
+ app2.put(
21735
+ "/api/model-providers/:providerId/models",
21736
+ controller.setProviderModels.bind(controller)
21737
+ );
21738
+ app2.post(
21739
+ "/api/model-providers/:providerId/models/enabled",
21740
+ controller.setModelEnabled.bind(controller)
21741
+ );
21742
+ }
21743
+
21744
+ // src/services/collaboration/ProjectRoomService.ts
21745
+ var import_node_crypto15 = require("crypto");
21746
+ var ProjectRoomService = class {
21747
+ /** Creates a project room service from explicitly injected collaborators. */
21748
+ constructor(deps) {
21749
+ this.deps = deps;
21750
+ this.idFactory = deps.idFactory ?? import_node_crypto15.randomUUID;
21751
+ }
21752
+ /**
21753
+ * Authorizes read access and ensures the project's main room.
21754
+ *
21755
+ * @remarks
21756
+ * This method is safe to call while holding the process-wide Project
21757
+ * mutation mutex: it never re-enters it. Coordinator backfill is a separate
21758
+ * entry point ({@link ensureMainRoomWithCoordinator}) because it acquires
21759
+ * that mutex internally.
21760
+ */
21761
+ async ensureMainRoom(input) {
21762
+ const { room } = await this.authorizedRoom(input);
21763
+ return room;
21764
+ }
21765
+ /**
21766
+ * Authorizes read access, ensures the main room, and lazily backfills the
21767
+ * built-in coordinator for business projects.
21768
+ *
21769
+ * @remarks
21770
+ * Only call this outside the Project mutation mutex (room open / bootstrap
21771
+ * paths); calling it under the mutex deadlocks on the coordinator ensurer.
21772
+ */
21773
+ async ensureMainRoomWithCoordinator(input) {
21774
+ const { project, room } = await this.authorizedRoom(input);
21775
+ if ((project.kind === "business" || project.kind === "public") && this.deps.ensureCoordinator) {
21776
+ try {
21777
+ await this.deps.ensureCoordinator({
21778
+ tenantId: input.tenantId,
21779
+ workspaceId: project.workspaceId,
21780
+ projectId: project.id,
21781
+ roomId: room.id
21782
+ });
21783
+ } catch (error) {
21784
+ this.deps.log?.warn("project-room:coordinator-ensure-failed", {
21785
+ tenantId: input.tenantId,
21786
+ projectId: project.id,
21787
+ errorName: error instanceof Error ? error.name : "UnknownError"
21788
+ });
21789
+ }
21790
+ }
21791
+ return room;
21792
+ }
21793
+ async authorizedRoom(input) {
21794
+ const { project } = await this.deps.accessService.requireProjectAccess({
21795
+ ...input,
21796
+ capability: "read"
21797
+ });
21798
+ const room = await this.deps.roomStore.ensureMainRoom({
21799
+ id: this.idFactory(),
21800
+ tenantId: input.tenantId,
21801
+ workspaceId: project.workspaceId,
21802
+ projectId: project.id,
21803
+ name: project.name
21804
+ });
21805
+ return { project, room };
21806
+ }
21807
+ };
21808
+
21809
+ // src/services/collaboration/ProjectMembershipService.ts
21810
+ var import_node_crypto16 = require("crypto");
21811
+ var ProjectMembershipServiceError = class extends Error {
21812
+ constructor(code, statusCode, message) {
21813
+ super(message);
21814
+ this.code = code;
21815
+ this.statusCode = statusCode;
21816
+ this.name = "ProjectMembershipServiceError";
21817
+ }
21818
+ };
21819
+ var membershipConflictNames2 = /* @__PURE__ */ new Set(["DuplicateProjectMembershipError", "ProjectMembershipIdConflictError"]);
21820
+ function isMembershipConflict(error) {
21821
+ return error instanceof Error && membershipConflictNames2.has(error.name);
21822
+ }
21823
+ var ProjectMembershipService = class {
21824
+ constructor(deps) {
21825
+ this.deps = deps;
21826
+ this.idFactory = deps.idFactory ?? import_node_crypto16.randomUUID;
21827
+ this.mutationMutex = deps.projectMutationMutex ?? import_core26.projectMutationMutex;
21828
+ }
21829
+ async list(actor3) {
21830
+ await this.deps.accessService.requireRosterAccess(actor3);
21831
+ const membership = await this.deps.membershipStore.findByUser(actor3.tenantId, actor3.projectId, actor3.userId);
21832
+ if (!membership || membership.status !== "active") this.accessDenied();
21833
+ return this.deps.membershipStore.list(actor3.tenantId, actor3.projectId);
21834
+ }
21835
+ async add(actor3, input) {
21836
+ return this.withProjectLock(actor3, async () => {
21837
+ const access = await this.authorize(actor3);
21838
+ if (input.role === "owner" && access.role !== "owner") this.accessDenied();
21839
+ if (!await this.deps.userTenantLinkStore.getLink(input.userId, actor3.tenantId)) {
21840
+ throw new ProjectMembershipServiceError("TARGET_USER_NOT_IN_TENANT", 400, "Target user is not in the tenant");
21841
+ }
21842
+ if (await this.deps.membershipStore.findByUser(actor3.tenantId, actor3.projectId, input.userId)) {
21843
+ throw new ProjectMembershipServiceError("MEMBERSHIP_EXISTS", 409, "Project membership already exists");
21844
+ }
21845
+ try {
21846
+ const created = await this.deps.membershipStore.create({
21847
+ id: this.idFactory(),
21848
+ tenantId: actor3.tenantId,
21849
+ projectId: actor3.projectId,
21850
+ userId: input.userId,
21851
+ role: input.role,
21852
+ status: "active"
21853
+ });
21854
+ this.publish(created, "added", `membership:${created.id}:add:${created.joinedAt.toISOString()}`);
21855
+ return created;
21856
+ } catch (error) {
21857
+ if (error instanceof Error && error.name === "DuplicateProjectMembershipError") {
21858
+ throw new ProjectMembershipServiceError("MEMBERSHIP_EXISTS", 409, "Project membership already exists");
21859
+ }
21860
+ if (isMembershipConflict(error)) {
21861
+ throw new ProjectMembershipServiceError("MEMBERSHIP_CONFLICT", 409, "Project membership could not be created");
21862
+ }
21863
+ throw error;
21864
+ }
21865
+ });
21866
+ }
21867
+ async updateRole(actor3, input) {
21868
+ return this.withProjectLock(actor3, async () => {
21869
+ const access = await this.authorize(actor3);
21870
+ const target = await this.target(actor3, input.membershipId);
21871
+ this.requireActiveAndCurrent(target, input.expectedUpdatedAt);
21872
+ if ((target.role === "owner" || input.role === "owner") && access.role !== "owner") this.accessDenied();
21873
+ const updated = await this.mapMutation(await this.deps.membershipStore.updateRole({ tenantId: actor3.tenantId, id: input.membershipId, role: input.role, expectedUpdatedAt: input.expectedUpdatedAt }));
21874
+ this.publish(updated, "role_changed", `membership:${updated.id}:role:${updated.role}:${input.expectedUpdatedAt.toISOString()}`);
21875
+ return updated;
21876
+ });
21877
+ }
21878
+ async remove(actor3, input) {
21879
+ return this.withProjectLock(actor3, async () => {
21880
+ const access = await this.authorize(actor3);
21881
+ const target = await this.target(actor3, input.membershipId);
21882
+ this.requireActiveAndCurrent(target, input.expectedUpdatedAt);
21883
+ if (target.role === "owner" && access.role !== "owner") this.accessDenied();
21884
+ const removed = await this.mapMutation(await this.deps.membershipStore.remove({ tenantId: actor3.tenantId, id: input.membershipId, expectedUpdatedAt: input.expectedUpdatedAt }));
21885
+ this.publish(removed, "removed", `membership:${removed.id}:remove:${input.expectedUpdatedAt.toISOString()}`);
21886
+ return removed;
21887
+ });
21888
+ }
21889
+ async authorize(actor3) {
21890
+ await this.deps.accessService.requireProjectAccess({ ...actor3, capability: "manage" });
21891
+ const membership = await this.deps.membershipStore.findByUser(actor3.tenantId, actor3.projectId, actor3.userId);
21892
+ if (!membership || membership.status !== "active") this.accessDenied();
21893
+ return membership;
21894
+ }
21895
+ async target(actor3, id3) {
21896
+ const target = (await this.deps.membershipStore.list(actor3.tenantId, actor3.projectId)).find((item) => item.id === id3);
21897
+ if (!target) throw new ProjectMembershipServiceError("MEMBERSHIP_NOT_FOUND", 404, "Project membership not found");
21898
+ return target;
21899
+ }
21900
+ requireActiveAndCurrent(target, expectedUpdatedAt2) {
21901
+ if (target.status !== "active") {
21902
+ throw new ProjectMembershipServiceError("MEMBERSHIP_NOT_FOUND", 404, "Project membership not found");
21903
+ }
21904
+ if (!Number.isFinite(expectedUpdatedAt2.getTime()) || target.updatedAt.getTime() !== expectedUpdatedAt2.getTime()) {
21905
+ throw new ProjectMembershipServiceError("MEMBERSHIP_CONFLICT", 409, "Project membership changed; reload before saving");
21906
+ }
21907
+ }
21908
+ async mapMutation(result) {
21909
+ if (result.kind === "updated" || result.kind === "removed") return result.membership;
21910
+ if (result.kind === "not_found") throw new ProjectMembershipServiceError("MEMBERSHIP_NOT_FOUND", 404, "Project membership not found");
21911
+ if (result.kind === "conflict") throw new ProjectMembershipServiceError("MEMBERSHIP_CONFLICT", 409, "Project membership changed; reload before saving");
21912
+ throw new ProjectMembershipServiceError("LAST_OWNER", 409, "The project must retain an owner");
21913
+ }
21914
+ publish(membership, change, sourceKey) {
20786
21915
  if (!this.deps.realtime) return;
20787
21916
  if (!this.deps.roomStore) {
20788
21917
  this.reportRealtimeFailure(membership.id);
@@ -20828,7 +21957,7 @@ var ProjectMembershipService = class {
20828
21957
  };
20829
21958
 
20830
21959
  // src/services/collaboration/ProjectRosterService.ts
20831
- var import_node_crypto16 = require("crypto");
21960
+ var import_node_crypto17 = require("crypto");
20832
21961
  var ProjectRosterServiceError = class extends Error {
20833
21962
  /** Creates a stable roster service error. */
20834
21963
  constructor(code, statusCode, message) {
@@ -20847,7 +21976,7 @@ var ProjectRosterService = class {
20847
21976
  /** Creates a roster service from explicitly injected collaborators. */
20848
21977
  constructor(deps) {
20849
21978
  this.deps = deps;
20850
- this.idFactory = deps.idFactory ?? import_node_crypto16.randomUUID;
21979
+ this.idFactory = deps.idFactory ?? import_node_crypto17.randomUUID;
20851
21980
  this.mutationMutex = deps.projectMutationMutex ?? import_core26.projectMutationMutex;
20852
21981
  }
20853
21982
  /**
@@ -21113,15 +22242,15 @@ function publicProjectBot(project, roomId, agent, now) {
21113
22242
  }
21114
22243
 
21115
22244
  // src/services/collaboration/RoomMessageService.ts
21116
- var import_node_crypto17 = require("crypto");
22245
+ var import_node_crypto18 = require("crypto");
21117
22246
 
21118
22247
  // src/services/collaboration/ProjectBotMembershipSnapshot.ts
21119
- var import_protocols16 = require("@axiom-lattice/protocols");
22248
+ var import_protocols17 = require("@axiom-lattice/protocols");
21120
22249
  var requiredKeys = ["assistantId", "id", "joinedAt", "mentionName", "projectId", "role", "roomId", "roomThreadId", "status", "tenantId", "title", "updatedAt", "workspaceId"];
21121
22250
  function snapshotProjectBotMembership(value) {
21122
22251
  try {
21123
22252
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
21124
- const values = (0, import_protocols16.snapshotExactRecord)(value, requiredKeys, ["responsibility"]);
22253
+ const values = (0, import_protocols17.snapshotExactRecord)(value, requiredKeys, ["responsibility"]);
21125
22254
  if (!values) return void 0;
21126
22255
  const read = (key) => values[key];
21127
22256
  const id3 = read("id");
@@ -21202,7 +22331,7 @@ var RoomMessageService = class {
21202
22331
  constructor(deps, options = {}) {
21203
22332
  this.deps = deps;
21204
22333
  this.idempotentOutcomes = /* @__PURE__ */ new Map();
21205
- this.idFactory = deps.idFactory ?? import_node_crypto17.randomUUID;
22334
+ this.idFactory = deps.idFactory ?? import_node_crypto18.randomUUID;
21206
22335
  const limit = options.idempotentOutcomeLimit ?? 1e3;
21207
22336
  if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError("idempotentOutcomeLimit must be a positive safe integer");
21208
22337
  this.idempotentOutcomeLimit = limit;
@@ -21383,7 +22512,7 @@ var RoomMessageService = class {
21383
22512
  let idempotencyKey;
21384
22513
  if (value.requestIdempotencyKey !== void 0) {
21385
22514
  if (typeof value.requestIdempotencyKey !== "string" || !/^[\x21-\x7e]{1,200}$/.test(value.requestIdempotencyKey.trim())) throw new RoomMessageServiceError("INVALID_MESSAGE", 400, "Invalid idempotency key");
21386
- idempotencyKey = `room-human:${actor3.userId}:${(0, import_node_crypto17.createHash)("sha256").update(value.requestIdempotencyKey.trim(), "utf8").digest("hex")}`;
22515
+ idempotencyKey = `room-human:${actor3.userId}:${(0, import_node_crypto18.createHash)("sha256").update(value.requestIdempotencyKey.trim(), "utf8").digest("hex")}`;
21387
22516
  }
21388
22517
  return { text, mentions, botIds, ...value.replyToMessageId === void 0 ? {} : { replyToMessageId: value.replyToMessageId }, ...idempotencyKey === void 0 ? {} : { idempotencyKey } };
21389
22518
  }
@@ -21440,7 +22569,7 @@ function cloneRoomMessage(message) {
21440
22569
  };
21441
22570
  }
21442
22571
  function fingerprintRequest(input) {
21443
- return (0, import_node_crypto17.createHash)("sha256").update(JSON.stringify({
22572
+ return (0, import_node_crypto18.createHash)("sha256").update(JSON.stringify({
21444
22573
  text: input.text,
21445
22574
  mentions: input.mentions,
21446
22575
  replyToMessageId: input.replyToMessageId ?? null
@@ -21451,11 +22580,11 @@ function matchesNormalizedPayload(message, input) {
21451
22580
  }
21452
22581
 
21453
22582
  // src/routes/project-rooms.ts
21454
- var import_zod11 = require("zod");
21455
- var import_protocols17 = require("@axiom-lattice/protocols");
22583
+ var import_zod13 = require("zod");
22584
+ var import_protocols18 = require("@axiom-lattice/protocols");
21456
22585
 
21457
22586
  // src/services/collaboration/RoomInterruptService.ts
21458
- var import_node_crypto18 = require("crypto");
22587
+ var import_node_crypto19 = require("crypto");
21459
22588
  var RoomInterruptServiceError = class extends Error {
21460
22589
  /** Creates a stable room interrupt error. */
21461
22590
  constructor(code, statusCode, message) {
@@ -21469,7 +22598,7 @@ var RoomInterruptService = class {
21469
22598
  /** Creates the service from explicitly injected stores and dispatcher. */
21470
22599
  constructor(deps) {
21471
22600
  this.deps = deps;
21472
- this.idFactory = deps.idFactory ?? import_node_crypto18.randomUUID;
22601
+ this.idFactory = deps.idFactory ?? import_node_crypto19.randomUUID;
21473
22602
  }
21474
22603
  /** Resolves a pending clarify interrupt with no answers. */
21475
22604
  async skip(input) {
@@ -21527,52 +22656,52 @@ var RoomInterruptService = class {
21527
22656
  };
21528
22657
 
21529
22658
  // src/schemas/project-room.ts
21530
- var import_zod10 = require("zod");
21531
- var id2 = import_zod10.z.string().trim().min(1).max(128);
21532
- var isoDate = import_zod10.z.string().datetime({ offset: true }).transform((value) => new Date(value));
21533
- var expectedUpdatedAt = import_zod10.z.object({ expectedUpdatedAt: isoDate }).strict();
21534
- var projectRoomParamsSchema = import_zod10.z.object({ projectId: id2 }).strict();
21535
- var membershipParamsSchema = import_zod10.z.object({ projectId: id2, membershipId: id2 }).strict();
21536
- var roomMessagesQuerySchema = import_zod10.z.object({
21537
- beforeCreatedAt: import_zod10.z.string().datetime({ offset: true }).transform((value) => new Date(value)).optional(),
22659
+ var import_zod12 = require("zod");
22660
+ var id2 = import_zod12.z.string().trim().min(1).max(128);
22661
+ var isoDate = import_zod12.z.string().datetime({ offset: true }).transform((value) => new Date(value));
22662
+ var expectedUpdatedAt = import_zod12.z.object({ expectedUpdatedAt: isoDate }).strict();
22663
+ var projectRoomParamsSchema = import_zod12.z.object({ projectId: id2 }).strict();
22664
+ var membershipParamsSchema = import_zod12.z.object({ projectId: id2, membershipId: id2 }).strict();
22665
+ var roomMessagesQuerySchema = import_zod12.z.object({
22666
+ beforeCreatedAt: import_zod12.z.string().datetime({ offset: true }).transform((value) => new Date(value)).optional(),
21538
22667
  beforeId: id2.optional(),
21539
- limit: import_zod10.z.coerce.number().int().min(1).max(100).optional()
22668
+ limit: import_zod12.z.coerce.number().int().min(1).max(100).optional()
21540
22669
  }).strict().refine((value) => value.beforeCreatedAt === void 0 === (value.beforeId === void 0), { message: "Both cursor fields are required" });
21541
- var createRoomMessageSchema = import_zod10.z.object({
21542
- text: import_zod10.z.string(),
21543
- mentions: import_zod10.z.array(import_zod10.z.union([
21544
- import_zod10.z.object({ type: import_zod10.z.literal("team") }).strict(),
21545
- import_zod10.z.object({ type: import_zod10.z.literal("bot"), membershipId: id2 }).strict()
22670
+ var createRoomMessageSchema = import_zod12.z.object({
22671
+ text: import_zod12.z.string(),
22672
+ mentions: import_zod12.z.array(import_zod12.z.union([
22673
+ import_zod12.z.object({ type: import_zod12.z.literal("team") }).strict(),
22674
+ import_zod12.z.object({ type: import_zod12.z.literal("bot"), membershipId: id2 }).strict()
21546
22675
  ])).optional(),
21547
22676
  replyToMessageId: id2.optional()
21548
22677
  }).strict();
21549
- var addProjectMemberSchema = import_zod10.z.object({ userId: id2, role: import_zod10.z.enum(["owner", "admin", "member", "viewer"]) }).strict();
21550
- var updateProjectMemberSchema = import_zod10.z.object({ role: import_zod10.z.enum(["owner", "admin", "member", "viewer"]), expectedUpdatedAt: isoDate }).strict();
22678
+ var addProjectMemberSchema = import_zod12.z.object({ userId: id2, role: import_zod12.z.enum(["owner", "admin", "member", "viewer"]) }).strict();
22679
+ var updateProjectMemberSchema = import_zod12.z.object({ role: import_zod12.z.enum(["owner", "admin", "member", "viewer"]), expectedUpdatedAt: isoDate }).strict();
21551
22680
  var mutationExpectedUpdatedAtSchema = expectedUpdatedAt;
21552
- var roomMessageRetryParamsSchema = import_zod10.z.object({ projectId: id2, messageId: id2 }).strict();
21553
- var emptyObjectSchema = import_zod10.z.object({}).strict();
21554
- var idempotencyKeySchema = import_zod10.z.string().refine((value) => value.trim().length >= 1 && value.trim().length <= 200 && /^[\x20-\x7e]+$/.test(value.trim()), "Invalid idempotency key").transform((value) => value.trim());
21555
- var addProjectBotSchema = import_zod10.z.object({
22681
+ var roomMessageRetryParamsSchema = import_zod12.z.object({ projectId: id2, messageId: id2 }).strict();
22682
+ var emptyObjectSchema = import_zod12.z.object({}).strict();
22683
+ var idempotencyKeySchema = import_zod12.z.string().refine((value) => value.trim().length >= 1 && value.trim().length <= 200 && /^[\x20-\x7e]+$/.test(value.trim()), "Invalid idempotency key").transform((value) => value.trim());
22684
+ var addProjectBotSchema = import_zod12.z.object({
21556
22685
  assistantId: id2,
21557
- role: import_zod10.z.enum(["coordinator", "specialist"]),
21558
- title: import_zod10.z.string(),
21559
- responsibility: import_zod10.z.string().optional(),
21560
- mentionName: import_zod10.z.string()
22686
+ role: import_zod12.z.enum(["coordinator", "specialist"]),
22687
+ title: import_zod12.z.string(),
22688
+ responsibility: import_zod12.z.string().optional(),
22689
+ mentionName: import_zod12.z.string()
21561
22690
  }).strict();
21562
- var updateProjectBotSchema = import_zod10.z.object({
21563
- role: import_zod10.z.enum(["coordinator", "specialist"]).optional(),
21564
- title: import_zod10.z.string().optional(),
21565
- responsibility: import_zod10.z.string().optional(),
21566
- mentionName: import_zod10.z.string().optional(),
22691
+ var updateProjectBotSchema = import_zod12.z.object({
22692
+ role: import_zod12.z.enum(["coordinator", "specialist"]).optional(),
22693
+ title: import_zod12.z.string().optional(),
22694
+ responsibility: import_zod12.z.string().optional(),
22695
+ mentionName: import_zod12.z.string().optional(),
21567
22696
  expectedUpdatedAt: isoDate
21568
22697
  }).strict().refine((value) => value.role !== void 0 || value.title !== void 0 || value.responsibility !== void 0 || value.mentionName !== void 0, { message: "At least one mutable field is required" });
21569
- var resumeInterruptSchema = import_zod10.z.object({
22698
+ var resumeInterruptSchema = import_zod12.z.object({
21570
22699
  membershipId: id2,
21571
- answers: import_zod10.z.array(import_zod10.z.object({
21572
- questionIndex: import_zod10.z.number().int().nonnegative(),
21573
- otherText: import_zod10.z.string().optional(),
21574
- selectedOptions: import_zod10.z.array(import_zod10.z.string()).optional(),
21575
- filePath: import_zod10.z.string().optional()
22700
+ answers: import_zod12.z.array(import_zod12.z.object({
22701
+ questionIndex: import_zod12.z.number().int().nonnegative(),
22702
+ otherText: import_zod12.z.string().optional(),
22703
+ selectedOptions: import_zod12.z.array(import_zod12.z.string()).optional(),
22704
+ filePath: import_zod12.z.string().optional()
21576
22705
  }).strict()).optional()
21577
22706
  }).strict();
21578
22707
 
@@ -21661,7 +22790,7 @@ function actor(request, projectId) {
21661
22790
  return { tenantId: user.tenantId, userId: user.id, projectId };
21662
22791
  }
21663
22792
  function toProjectRoomMessage(message) {
21664
- const publicMessage = (0, import_protocols17.toProjectRoomPublicMessage)(message);
22793
+ const publicMessage = (0, import_protocols18.toProjectRoomPublicMessage)(message);
21665
22794
  if (publicMessage === void 0) throw new Error("Room message could not be mapped to its public DTO");
21666
22795
  return publicMessage;
21667
22796
  }
@@ -21670,7 +22799,7 @@ async function run(reply, operation) {
21670
22799
  const result = await operation();
21671
22800
  return reply.code(result.statusCode ?? 200).send({ success: true, data: result.data });
21672
22801
  } catch (error) {
21673
- if (error instanceof import_zod11.ZodError) return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
22802
+ if (error instanceof import_zod13.ZodError) return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
21674
22803
  if (error instanceof RoomInterruptServiceError) return reply.code(error.statusCode).send({ success: false, error: { code: error.code, message: error.message, retryable: false } });
21675
22804
  if (error instanceof ProjectRoomAuthError || error instanceof ProjectCollaborationError || error instanceof ProjectMembershipServiceError || error instanceof ProjectRosterServiceError || error instanceof RoomMessageServiceError) return reply.code(error.statusCode).send({ success: false, error: { code: error.code, message: error.message, retryable: error instanceof RoomMessageServiceError && error.retryable } });
21676
22805
  return reply.code(500).send({ success: false, error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false } });
@@ -21678,7 +22807,7 @@ async function run(reply, operation) {
21678
22807
  }
21679
22808
 
21680
22809
  // src/routes/project-roster.ts
21681
- var import_zod12 = require("zod");
22810
+ var import_zod14 = require("zod");
21682
22811
  var ProjectRosterAuthError = class extends Error {
21683
22812
  constructor() {
21684
22813
  super(...arguments);
@@ -21718,17 +22847,17 @@ async function execute(reply, operation) {
21718
22847
  const result = await operation();
21719
22848
  return reply.code(result.statusCode ?? 200).send({ success: true, data: result.data });
21720
22849
  } catch (error) {
21721
- if (error instanceof import_zod12.ZodError) return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
22850
+ if (error instanceof import_zod14.ZodError) return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
21722
22851
  if (error instanceof ProjectRosterAuthError || error instanceof ProjectCollaborationError || error instanceof ProjectRosterServiceError) return reply.code(error.statusCode).send({ success: false, error: { code: error.code, message: error.message, retryable: false } });
21723
22852
  return reply.code(500).send({ success: false, error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false } });
21724
22853
  }
21725
22854
  }
21726
22855
 
21727
22856
  // src/routes/cospace.ts
21728
- var import_node_crypto19 = require("crypto");
21729
- var import_zod13 = require("zod");
21730
- var import_core47 = require("@axiom-lattice/core");
21731
- var import_protocols18 = require("@axiom-lattice/protocols");
22857
+ var import_node_crypto20 = require("crypto");
22858
+ var import_zod15 = require("zod");
22859
+ var import_core48 = require("@axiom-lattice/core");
22860
+ var import_protocols19 = require("@axiom-lattice/protocols");
21732
22861
  var CoSpaceAuthError = class extends Error {
21733
22862
  constructor() {
21734
22863
  super(...arguments);
@@ -21756,7 +22885,7 @@ async function computeUnread(deps, tenantId, userId, roomId, lastMessage) {
21756
22885
  });
21757
22886
  }
21758
22887
  function registerCoSpaceRoutes(app2, deps) {
21759
- const idFactory = deps.idFactory ?? (() => (0, import_node_crypto19.randomUUID)());
22888
+ const idFactory = deps.idFactory ?? (() => (0, import_node_crypto20.randomUUID)());
21760
22889
  app2.get(
21761
22890
  "/api/workspaces/:workspaceId/rooms",
21762
22891
  async (request, reply) => {
@@ -21805,7 +22934,7 @@ function registerCoSpaceRoutes(app2, deps) {
21805
22934
  limit: 1
21806
22935
  });
21807
22936
  const lastMessage = messages[0];
21808
- const publicLastMessage = lastMessage === void 0 ? void 0 : (0, import_protocols18.toProjectRoomPublicMessage)(lastMessage);
22937
+ const publicLastMessage = lastMessage === void 0 ? void 0 : (0, import_protocols19.toProjectRoomPublicMessage)(lastMessage);
21809
22938
  const memberships = await deps.membershipStore.list(
21810
22939
  actor3.tenantId,
21811
22940
  project.id
@@ -21872,7 +23001,7 @@ function registerCoSpaceRoutes(app2, deps) {
21872
23001
  rooms.unshift({
21873
23002
  project: publicRoom.project,
21874
23003
  room: publicRoom.room,
21875
- lastMessage: publicLastMessage === void 0 ? void 0 : (0, import_protocols18.toProjectRoomPublicMessage)(publicLastMessage),
23004
+ lastMessage: publicLastMessage === void 0 ? void 0 : (0, import_protocols19.toProjectRoomPublicMessage)(publicLastMessage),
21876
23005
  participantCount: publicMemberships.filter((m) => m.status === "active").length,
21877
23006
  participantNames: publicParticipantNames,
21878
23007
  isPublic: true,
@@ -21912,14 +23041,14 @@ function registerCoSpaceRoutes(app2, deps) {
21912
23041
  }
21913
23042
  let projectId;
21914
23043
  if (body.type === "human") {
21915
- projectId = (0, import_core47.generateDirectHumanProjectId)(
23044
+ projectId = (0, import_core48.generateDirectHumanProjectId)(
21916
23045
  actor3.tenantId,
21917
23046
  params.workspaceId,
21918
23047
  actor3.userId,
21919
23048
  body.targetUserId
21920
23049
  );
21921
23050
  } else {
21922
- projectId = (0, import_core47.generateDirectBotProjectId)(
23051
+ projectId = (0, import_core48.generateDirectBotProjectId)(
21923
23052
  actor3.tenantId,
21924
23053
  params.workspaceId,
21925
23054
  actor3.userId,
@@ -22126,7 +23255,7 @@ function registerCoSpaceRoutes(app2, deps) {
22126
23255
  );
22127
23256
  const bots = [];
22128
23257
  for (const assistant of assistants) {
22129
- const directProjectId = (0, import_core47.generateDirectBotProjectId)(
23258
+ const directProjectId = (0, import_core48.generateDirectBotProjectId)(
22130
23259
  actor3.tenantId,
22131
23260
  params.workspaceId,
22132
23261
  actor3.userId,
@@ -22188,7 +23317,7 @@ function registerCoSpaceRoutes(app2, deps) {
22188
23317
  if (link.userId === actor3.userId) continue;
22189
23318
  const user = await deps.userStore.getUserById(link.userId);
22190
23319
  if (!user) continue;
22191
- const directProjectId = (0, import_core47.generateDirectHumanProjectId)(
23320
+ const directProjectId = (0, import_core48.generateDirectHumanProjectId)(
22192
23321
  actor3.tenantId,
22193
23322
  params.workspaceId,
22194
23323
  actor3.userId,
@@ -22277,7 +23406,7 @@ function registerCoSpaceRoutes(app2, deps) {
22277
23406
  data: result.data
22278
23407
  });
22279
23408
  } catch (error) {
22280
- if (error instanceof import_zod13.ZodError) {
23409
+ if (error instanceof import_zod15.ZodError) {
22281
23410
  return reply.code(400).send({
22282
23411
  success: false,
22283
23412
  error: {
@@ -22310,9 +23439,9 @@ function registerCoSpaceRoutes(app2, deps) {
22310
23439
  }
22311
23440
 
22312
23441
  // src/routes/push-notifications.ts
22313
- var import_zod14 = require("zod");
22314
- var subscriptionSchema = import_zod14.z.object({ endpoint: import_zod14.z.string().min(1), keys: import_zod14.z.object({ p256dh: import_zod14.z.string().min(1), auth: import_zod14.z.string().min(1) }).strict() }).strict();
22315
- var deleteSchema = import_zod14.z.object({ endpoint: import_zod14.z.string().min(1) }).strict();
23442
+ var import_zod16 = require("zod");
23443
+ var subscriptionSchema = import_zod16.z.object({ endpoint: import_zod16.z.string().min(1), keys: import_zod16.z.object({ p256dh: import_zod16.z.string().min(1), auth: import_zod16.z.string().min(1) }).strict() }).strict();
23444
+ var deleteSchema = import_zod16.z.object({ endpoint: import_zod16.z.string().min(1) }).strict();
22316
23445
  function actor2(request) {
22317
23446
  const user = request.user;
22318
23447
  return user?.id && user.tenantId ? { tenantId: user.tenantId, userId: user.id } : null;
@@ -22340,7 +23469,7 @@ function registerPushNotificationRoutes(app2, deps) {
22340
23469
  });
22341
23470
  return reply.code(204).send();
22342
23471
  } catch (error) {
22343
- if (error instanceof import_zod14.ZodError) {
23472
+ if (error instanceof import_zod16.ZodError) {
22344
23473
  return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
22345
23474
  }
22346
23475
  return reply.code(500).send({ success: false, error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false } });
@@ -22354,7 +23483,7 @@ function registerPushNotificationRoutes(app2, deps) {
22354
23483
  await deps.subscriptionStore.delete(current.tenantId, current.userId, body.endpoint);
22355
23484
  return reply.code(204).send();
22356
23485
  } catch (error) {
22357
- if (error instanceof import_zod14.ZodError) {
23486
+ if (error instanceof import_zod16.ZodError) {
22358
23487
  return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
22359
23488
  }
22360
23489
  return reply.code(500).send({ success: false, error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false } });
@@ -22585,7 +23714,7 @@ var RoomTargetResolver = class {
22585
23714
  };
22586
23715
 
22587
23716
  // src/services/collaboration/RoomDispatchService.ts
22588
- var import_protocols19 = require("@axiom-lattice/protocols");
23717
+ var import_protocols20 = require("@axiom-lattice/protocols");
22589
23718
 
22590
23719
  // src/router/InternalRoomDispatch.ts
22591
23720
  var INTERNAL_ROOM_DISPATCH = Symbol("internal-room-dispatch");
@@ -22687,7 +23816,7 @@ function snapshotDispatchSource(value) {
22687
23816
  };
22688
23817
  }
22689
23818
  function snapshotMentions(value) {
22690
- const rows = (0, import_protocols19.snapshotExactArray)(value);
23819
+ const rows = (0, import_protocols20.snapshotExactArray)(value);
22691
23820
  if (!rows) return void 0;
22692
23821
  const result = [];
22693
23822
  for (const row of rows) {
@@ -22705,15 +23834,15 @@ function snapshotMentions(value) {
22705
23834
  function exactValues(value, required, optional = []) {
22706
23835
  try {
22707
23836
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
22708
- return (0, import_protocols19.snapshotExactRecord)(value, required, optional);
23837
+ return (0, import_protocols20.snapshotExactRecord)(value, required, optional);
22709
23838
  } catch {
22710
23839
  return void 0;
22711
23840
  }
22712
23841
  }
22713
23842
 
22714
23843
  // src/services/collaboration/CoordinatorWakeNotifier.ts
22715
- var import_node_crypto20 = require("crypto");
22716
- var import_protocols20 = require("@axiom-lattice/protocols");
23844
+ var import_node_crypto21 = require("crypto");
23845
+ var import_protocols21 = require("@axiom-lattice/protocols");
22717
23846
  var SYNTHETIC_WAKE_AUTHOR = "coordinator-wake";
22718
23847
  var CoordinatorWakeNotifier = class {
22719
23848
  /** Creates a bounded Project Task lifecycle observer that wakes the Room Coordinator. */
@@ -22726,7 +23855,7 @@ var CoordinatorWakeNotifier = class {
22726
23855
  this.accepted = /* @__PURE__ */ new Set();
22727
23856
  this.maxPending = deps.maxPending ?? 1024;
22728
23857
  if (!Number.isSafeInteger(this.maxPending) || this.maxPending < 1) throw new RangeError("maxPending must be a positive safe integer");
22729
- this.idFactory = deps.idFactory ?? import_node_crypto20.randomUUID;
23858
+ this.idFactory = deps.idFactory ?? import_node_crypto21.randomUUID;
22730
23859
  }
22731
23860
  /** Admits one notification without awaiting any store or dispatch operation. */
22732
23861
  handle(value, anchorMessageId) {
@@ -22869,7 +23998,7 @@ var CoordinatorWakeNotifier = class {
22869
23998
  }
22870
23999
  }
22871
24000
  parse(value) {
22872
- const row = (0, import_protocols20.snapshotExactRecord)(value, ["tenantId", "workspaceId", "projectId", "taskId", "status", "action", "eventKey", "updatedAt"], ["threadId"]);
24001
+ const row = (0, import_protocols21.snapshotExactRecord)(value, ["tenantId", "workspaceId", "projectId", "taskId", "status", "action", "eventKey", "updatedAt"], ["threadId"]);
22873
24002
  const actions = ["in_progress", "interrupted", "failed", "completed", "cancelled", "reassigned"];
22874
24003
  const statuses = ["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"];
22875
24004
  if (!row || !actions.includes(String(row.action)) || !statuses.includes(String(row.status)) || !["tenantId", "workspaceId", "projectId", "taskId", "eventKey", "updatedAt"].every((key) => typeof row[key] === "string" && row[key].length > 0) || !Number.isFinite(Date.parse(row.updatedAt)) || row.threadId !== void 0 && typeof row.threadId !== "string") return void 0;
@@ -23003,9 +24132,9 @@ function createRoomMessageRetentionJob(input) {
23003
24132
  }
23004
24133
 
23005
24134
  // src/services/collaboration/ProjectTaskExecutionMutex.ts
23006
- var import_protocols21 = require("@axiom-lattice/protocols");
24135
+ var import_protocols22 = require("@axiom-lattice/protocols");
23007
24136
  function machineKey(scope) {
23008
- const snapshot = (0, import_protocols21.snapshotExactRecord)(scope, ["tenantId", "assistantId", "projectId"]);
24137
+ const snapshot = (0, import_protocols22.snapshotExactRecord)(scope, ["tenantId", "assistantId", "projectId"]);
23009
24138
  if (!snapshot) throw new Error("Invalid Project task machine scope");
23010
24139
  const values = [snapshot.tenantId, snapshot.assistantId, snapshot.projectId];
23011
24140
  for (const value of values) {
@@ -23081,9 +24210,9 @@ var ProjectTaskExecutionMutex = class {
23081
24210
  };
23082
24211
 
23083
24212
  // src/services/collaboration/ProjectTaskObserver.ts
23084
- var import_node_crypto21 = require("crypto");
23085
- var import_core48 = require("@axiom-lattice/core");
23086
- var import_protocols22 = require("@axiom-lattice/protocols");
24213
+ var import_node_crypto22 = require("crypto");
24214
+ var import_core49 = require("@axiom-lattice/core");
24215
+ var import_protocols23 = require("@axiom-lattice/protocols");
23087
24216
  var SYSTEM_ACTOR2 = "system";
23088
24217
  var TERMINAL_ACTIONS = ["completed", "failed", "interrupted", "cancelled"];
23089
24218
  var ProjectTaskObserver = class {
@@ -23104,7 +24233,7 @@ var ProjectTaskObserver = class {
23104
24233
  throw new Error(`Invalid Project task observer bound: ${name}`);
23105
24234
  }
23106
24235
  }
23107
- this.runBridge = (0, import_core48.createTaskRunBridge)({ lifecycle: this.deps.lifecycle });
24236
+ this.runBridge = (0, import_core49.createTaskRunBridge)({ lifecycle: this.deps.lifecycle });
23108
24237
  }
23109
24238
  /** Fire-and-forget notifier adapter that never waits for observer work or machine acquisition. */
23110
24239
  async listener(event) {
@@ -23634,7 +24763,7 @@ var ProjectTaskObserver = class {
23634
24763
  action: "activity",
23635
24764
  summary: "Project task recovery warning",
23636
24765
  detail: { type: "project_task_recovery_warning", phase, message },
23637
- eventKey: `project-task-recovery-warning:${task.id}:${phase}:${(0, import_node_crypto21.createHash)("sha256").update(message).digest("hex")}`
24766
+ eventKey: `project-task-recovery-warning:${task.id}:${phase}:${(0, import_node_crypto22.createHash)("sha256").update(message).digest("hex")}`
23638
24767
  });
23639
24768
  }
23640
24769
  async safeWarning(task, phase, error) {
@@ -23838,7 +24967,7 @@ var ProjectTaskObserver = class {
23838
24967
  }
23839
24968
  }
23840
24969
  async persistOverflowWarning(event) {
23841
- const scopeDigest = (0, import_node_crypto21.createHash)("sha256").update(JSON.stringify([event.tenantId, event.workspaceId, event.projectId])).digest("hex");
24970
+ const scopeDigest = (0, import_node_crypto22.createHash)("sha256").update(JSON.stringify([event.tenantId, event.workspaceId, event.projectId])).digest("hex");
23842
24971
  try {
23843
24972
  await this.deps.workItems.createIfAbsentByEventKey({
23844
24973
  tenantId: event.tenantId,
@@ -23929,7 +25058,7 @@ function errorMessage3(error) {
23929
25058
  }
23930
25059
  function readCreatedBy(value) {
23931
25060
  try {
23932
- const row = (0, import_protocols22.snapshotExactRecord)(value, ["assistantId", "membershipId"]);
25061
+ const row = (0, import_protocols23.snapshotExactRecord)(value, ["assistantId", "membershipId"]);
23933
25062
  return row && typeof row.assistantId === "string" && row.assistantId.length > 0 && typeof row.membershipId === "string" && row.membershipId.length > 0 ? { assistantId: row.assistantId, membershipId: row.membershipId } : void 0;
23934
25063
  } catch {
23935
25064
  return void 0;
@@ -23943,8 +25072,8 @@ function combineSignals(left, right) {
23943
25072
  }
23944
25073
 
23945
25074
  // src/services/collaboration/RoomProjectionService.ts
23946
- var import_node_crypto22 = require("crypto");
23947
- var import_protocols23 = require("@axiom-lattice/protocols");
25075
+ var import_node_crypto23 = require("crypto");
25076
+ var import_protocols24 = require("@axiom-lattice/protocols");
23948
25077
  var ROOM_PROJECTABLE_ACTIONS = [
23949
25078
  "interrupted",
23950
25079
  "failed",
@@ -24023,7 +25152,7 @@ var RoomProjectionService = class {
24023
25152
  projectId: task.projectId,
24024
25153
  roomId: room.id,
24025
25154
  author: { type: "system" },
24026
- content: { type: "text", text: `${import_protocols23.PROJECT_ROOM_TASK_DELEGATED_LABEL}${import_protocols23.PROJECT_ROOM_TASK_DELEGATED_SEPARATOR}${input.fromLabel} \u2192 ${input.toLabel}` },
25155
+ content: { type: "text", text: `${import_protocols24.PROJECT_ROOM_TASK_DELEGATED_LABEL}${import_protocols24.PROJECT_ROOM_TASK_DELEGATED_SEPARATOR}${input.fromLabel} \u2192 ${input.toLabel}` },
24027
25156
  mentions: [],
24028
25157
  source: "task",
24029
25158
  sourceId: task.id,
@@ -24158,7 +25287,7 @@ function safeRepairIdentity(value, scope) {
24158
25287
  return taskId && eventKey && tenantId === scope.tenantId && workspaceId === scope.workspaceId && projectId === scope.projectId ? { taskId, eventKey } : void 0;
24159
25288
  }
24160
25289
  function tupleKey(prefix, values) {
24161
- const digest = (0, import_node_crypto22.createHash)("sha256").update(JSON.stringify(values)).digest("hex");
25290
+ const digest = (0, import_node_crypto23.createHash)("sha256").update(JSON.stringify(values)).digest("hex");
24162
25291
  return `${prefix}:${digest}`;
24163
25292
  }
24164
25293
  function parseProjectionInput(taskValue, itemValue) {
@@ -24174,7 +25303,7 @@ function parseProjectionInput(taskValue, itemValue) {
24174
25303
  }
24175
25304
  }
24176
25305
  function snapshotProjectableWorkItem(value) {
24177
- const row = (0, import_protocols23.snapshotExactRecord)(value, ["id", "taskId", "tenantId", "action", "actor", "createdAt"], [
25306
+ const row = (0, import_protocols24.snapshotExactRecord)(value, ["id", "taskId", "tenantId", "action", "actor", "createdAt"], [
24178
25307
  "workspaceId",
24179
25308
  "projectId",
24180
25309
  "threadId",
@@ -24184,7 +25313,7 @@ function snapshotProjectableWorkItem(value) {
24184
25313
  "eventKey"
24185
25314
  ]);
24186
25315
  const createdAt = cloneExactDate(row?.createdAt);
24187
- if (!row || !createdAt || typeof row.id !== "string" || !row.id || typeof row.taskId !== "string" || !row.taskId || typeof row.tenantId !== "string" || !row.tenantId || typeof row.workspaceId !== "string" || !row.workspaceId || typeof row.projectId !== "string" || !row.projectId || typeof row.actor !== "string" || !row.actor || typeof row.eventKey !== "string" || !row.eventKey || !import_protocols23.PROJECT_TASK_LIFECYCLE_ACTIONS.includes(row.action) || row.threadId !== void 0 && typeof row.threadId !== "string" || row.summary !== void 0 && typeof row.summary !== "string" || row.attempt !== void 0 && (typeof row.attempt !== "number" || !Number.isFinite(row.attempt))) return void 0;
25316
+ if (!row || !createdAt || typeof row.id !== "string" || !row.id || typeof row.taskId !== "string" || !row.taskId || typeof row.tenantId !== "string" || !row.tenantId || typeof row.workspaceId !== "string" || !row.workspaceId || typeof row.projectId !== "string" || !row.projectId || typeof row.actor !== "string" || !row.actor || typeof row.eventKey !== "string" || !row.eventKey || !import_protocols24.PROJECT_TASK_LIFECYCLE_ACTIONS.includes(row.action) || row.threadId !== void 0 && typeof row.threadId !== "string" || row.summary !== void 0 && typeof row.summary !== "string" || row.attempt !== void 0 && (typeof row.attempt !== "number" || !Number.isFinite(row.attempt))) return void 0;
24188
25317
  try {
24189
25318
  const detail = row.detail === void 0 ? void 0 : snapshotJsonValue(row.detail);
24190
25319
  if (detail !== void 0 && !isRecord3(detail)) return void 0;
@@ -24211,26 +25340,26 @@ function parseIso(value) {
24211
25340
  return typeof value === "string" && value.length > 0 && Number.isFinite(Date.parse(value));
24212
25341
  }
24213
25342
  function parseInterruption(value) {
24214
- const common = (0, import_protocols23.snapshotExactRecord)(value, ["type", "summary", "requestedAt"]);
25343
+ const common = (0, import_protocols24.snapshotExactRecord)(value, ["type", "summary", "requestedAt"]);
24215
25344
  if (common && (common.type === "missing_input" || common.type === "user_decision") && typeof common.summary === "string" && common.summary.length > 0 && parseIso(common.requestedAt)) {
24216
25345
  return { type: common.type, summary: common.summary, requestedAt: common.requestedAt };
24217
25346
  }
24218
- const review = (0, import_protocols23.snapshotExactRecord)(value, ["type", "evidenceId"]);
25347
+ const review = (0, import_protocols24.snapshotExactRecord)(value, ["type", "evidenceId"]);
24219
25348
  return review?.type === "review_required" && typeof review.evidenceId === "string" && review.evidenceId.length > 0 ? { type: "review_required", evidenceId: review.evidenceId } : void 0;
24220
25349
  }
24221
25350
  function parseBeliefImpact(value) {
24222
- const rows = (0, import_protocols23.snapshotExactArray)(value);
25351
+ const rows = (0, import_protocols24.snapshotExactArray)(value);
24223
25352
  if (!rows) return void 0;
24224
25353
  const impacts = [];
24225
25354
  for (const row of rows) {
24226
- const entry = (0, import_protocols23.snapshotExactRecord)(row, ["key", "after", "basis"]);
25355
+ const entry = (0, import_protocols24.snapshotExactRecord)(row, ["key", "after", "basis"]);
24227
25356
  if (!entry || typeof entry.key !== "string" || !entry.key || typeof entry.after !== "number" || !Number.isFinite(entry.after) || typeof entry.basis !== "string" || !entry.basis) return void 0;
24228
25357
  impacts.push({ key: entry.key, after: entry.after, basis: entry.basis });
24229
25358
  }
24230
25359
  return impacts;
24231
25360
  }
24232
25361
  function parseCompletion(item) {
24233
- const row = (0, import_protocols23.snapshotExactRecord)(item.detail, ["evidenceId", "eventKey", "result", "beliefImpact"]);
25362
+ const row = (0, import_protocols24.snapshotExactRecord)(item.detail, ["evidenceId", "eventKey", "result", "beliefImpact"]);
24234
25363
  const beliefImpact = parseBeliefImpact(row?.beliefImpact);
24235
25364
  if (!row || typeof row.evidenceId !== "string" || !row.evidenceId || typeof row.eventKey !== "string" || !row.eventKey || item.eventKey !== `${row.eventKey}:completed` || typeof row.result !== "string" || !beliefImpact) return void 0;
24236
25365
  return { evidenceId: row.evidenceId, eventKey: row.eventKey, result: row.result, beliefImpact };
@@ -24240,19 +25369,19 @@ function parseProjection(item) {
24240
25369
  return parseInterruption(item.detail) ? { kind: "interrupted", text: "Task interrupted" } : void 0;
24241
25370
  }
24242
25371
  if (item.action === "failed") {
24243
- const row = (0, import_protocols23.snapshotExactRecord)(item.detail, ["failureReason"]);
25372
+ const row = (0, import_protocols24.snapshotExactRecord)(item.detail, ["failureReason"]);
24244
25373
  return typeof row?.failureReason === "string" && row.failureReason ? { kind: "failed", text: "Task failed" } : void 0;
24245
25374
  }
24246
25375
  if (item.action === "completed") {
24247
25376
  return parseCompletion(item) ? { kind: "completed", text: "Task completed" } : void 0;
24248
25377
  }
24249
25378
  if (item.action === "cancelled") {
24250
- const empty = (0, import_protocols23.snapshotExactRecord)(item.detail, []);
24251
- const summarized = (0, import_protocols23.snapshotExactRecord)(item.detail, ["summary"]);
25379
+ const empty = (0, import_protocols24.snapshotExactRecord)(item.detail, []);
25380
+ const summarized = (0, import_protocols24.snapshotExactRecord)(item.detail, ["summary"]);
24252
25381
  return empty || typeof summarized?.summary === "string" && summarized.summary ? { kind: "cancelled", text: "Task cancelled" } : void 0;
24253
25382
  }
24254
25383
  if (item.action === "reassigned") {
24255
- const row = (0, import_protocols23.snapshotExactRecord)(
25384
+ const row = (0, import_protocols24.snapshotExactRecord)(
24256
25385
  item.detail,
24257
25386
  ["previousOwnerId", "previousThreadId", "ownerId", "membershipId", "threadId"]
24258
25387
  );
@@ -24261,7 +25390,7 @@ function parseProjection(item) {
24261
25390
  return void 0;
24262
25391
  }
24263
25392
  function assertCanonicalProjection(value, expected) {
24264
- const row = (0, import_protocols23.snapshotExactRecord)(value, [
25393
+ const row = (0, import_protocols24.snapshotExactRecord)(value, [
24265
25394
  "id",
24266
25395
  "tenantId",
24267
25396
  "workspaceId",
@@ -24275,9 +25404,9 @@ function assertCanonicalProjection(value, expected) {
24275
25404
  "idempotencyKey",
24276
25405
  "createdAt"
24277
25406
  ]);
24278
- const author = (0, import_protocols23.snapshotExactRecord)(row?.author, ["type"]);
24279
- const content = (0, import_protocols23.snapshotExactRecord)(row?.content, ["type", "text"]);
24280
- const mentions = (0, import_protocols23.snapshotExactArray)(row?.mentions);
25407
+ const author = (0, import_protocols24.snapshotExactRecord)(row?.author, ["type"]);
25408
+ const content = (0, import_protocols24.snapshotExactRecord)(row?.content, ["type", "text"]);
25409
+ const mentions = (0, import_protocols24.snapshotExactArray)(row?.mentions);
24281
25410
  const createdAt = cloneExactDate(row?.createdAt);
24282
25411
  if (!row || !createdAt || author?.type !== "system" || content?.type !== "text" || content.text !== expected.content.text || !mentions || mentions.length !== 0 || typeof row.id !== "string" || !row.id || row.tenantId !== expected.tenantId || row.workspaceId !== expected.workspaceId || row.projectId !== expected.projectId || row.roomId !== expected.roomId || row.source !== "task" || row.sourceId !== expected.sourceId || row.idempotencyKey !== expected.idempotencyKey) {
24283
25412
  throw new Error("Invalid canonical task projection");
@@ -24298,7 +25427,7 @@ function assertCanonicalProjection(value, expected) {
24298
25427
  };
24299
25428
  }
24300
25429
  function snapshotLifecycleCursor(value) {
24301
- const row = (0, import_protocols23.snapshotExactRecord)(value, ["id", "taskId", "tenantId", "action", "actor", "createdAt"], [
25430
+ const row = (0, import_protocols24.snapshotExactRecord)(value, ["id", "taskId", "tenantId", "action", "actor", "createdAt"], [
24302
25431
  "workspaceId",
24303
25432
  "projectId",
24304
25433
  "threadId",
@@ -24315,11 +25444,11 @@ function isRecord3(value) {
24315
25444
  }
24316
25445
 
24317
25446
  // src/services/collaboration/ProjectRoomRealtimeRuntime.ts
24318
- var import_core49 = require("@axiom-lattice/core");
25447
+ var import_core50 = require("@axiom-lattice/core");
24319
25448
 
24320
25449
  // src/services/collaboration/ProjectRoomEventBroker.ts
24321
- var import_node_crypto23 = require("crypto");
24322
- var import_protocols24 = require("@axiom-lattice/protocols");
25450
+ var import_node_crypto24 = require("crypto");
25451
+ var import_protocols25 = require("@axiom-lattice/protocols");
24323
25452
  var DEFAULT_MAX_EVENTS_PER_ROOM = 1e3;
24324
25453
  var DEFAULT_MAX_EVENT_AGE_MS = 10 * 60 * 1e3;
24325
25454
  var DEFAULT_MAX_ROOMS = 1e3;
@@ -24343,7 +25472,7 @@ var ProjectRoomEventBroker = class {
24343
25472
  this.subscriberCount = 0;
24344
25473
  this.usageClock = 0;
24345
25474
  this.closed = false;
24346
- this.epoch = options.epoch ?? (0, import_node_crypto23.randomUUID)();
25475
+ this.epoch = options.epoch ?? (0, import_node_crypto24.randomUUID)();
24347
25476
  if (!UUID_PATTERN.test(this.epoch)) {
24348
25477
  throw new TypeError("Project Room event epoch must be a lowercase canonical UUID");
24349
25478
  }
@@ -24382,7 +25511,7 @@ var ProjectRoomEventBroker = class {
24382
25511
  const canonicalScope = snapshotScope(scope);
24383
25512
  const key = scopeKey2(canonicalScope);
24384
25513
  const now = this.currentTime();
24385
- if (this.sequence >= Number.MAX_SAFE_INTEGER) throw new import_protocols24.ProjectRoomBrokerCapacityError();
25514
+ if (this.sequence >= Number.MAX_SAFE_INTEGER) throw new import_protocols25.ProjectRoomBrokerCapacityError();
24386
25515
  const nextSequence = this.sequence + 1;
24387
25516
  const event = snapshotJson({
24388
25517
  ...snapshotDraft(draft),
@@ -24565,11 +25694,11 @@ var ProjectRoomEventBroker = class {
24565
25694
  }
24566
25695
  resolveCursor(key, afterEventId, plan) {
24567
25696
  if (afterEventId === void 0) return void 0;
24568
- const cursor = (0, import_protocols24.parseProjectRoomEventId)(afterEventId);
24569
- if (!cursor) throw new import_protocols24.ProjectRoomCursorError("CURSOR_EXPIRED");
24570
- if (cursor.epoch !== this.epoch) throw new import_protocols24.ProjectRoomCursorError("SERVER_RESTART");
25697
+ const cursor = (0, import_protocols25.parseProjectRoomEventId)(afterEventId);
25698
+ if (!cursor) throw new import_protocols25.ProjectRoomCursorError("CURSOR_EXPIRED");
25699
+ if (cursor.epoch !== this.epoch) throw new import_protocols25.ProjectRoomCursorError("SERVER_RESTART");
24571
25700
  if (plan.sequences.has(cursor.sequence) || this.sequenceScopes.get(cursor.sequence) !== key) {
24572
- throw new import_protocols24.ProjectRoomCursorError("CURSOR_EXPIRED");
25701
+ throw new import_protocols25.ProjectRoomCursorError("CURSOR_EXPIRED");
24573
25702
  }
24574
25703
  return cursor.sequence;
24575
25704
  }
@@ -24661,8 +25790,8 @@ function snapshotJson(value, ancestors = /* @__PURE__ */ new Set()) {
24661
25790
  }
24662
25791
 
24663
25792
  // src/services/collaboration/ProjectRoomRealtimePublisher.ts
24664
- var import_node_crypto24 = require("crypto");
24665
- var import_protocols25 = require("@axiom-lattice/protocols");
25793
+ var import_node_crypto25 = require("crypto");
25794
+ var import_protocols26 = require("@axiom-lattice/protocols");
24666
25795
  var BrokerProjectRoomRealtimePublisher = class {
24667
25796
  /** Creates a publisher around a broker and structured warning logger. */
24668
25797
  constructor(deps) {
@@ -24676,7 +25805,7 @@ var BrokerProjectRoomRealtimePublisher = class {
24676
25805
  /** Publishes a canonical message after projecting it to its public shape. */
24677
25806
  messageCreated(message) {
24678
25807
  this.publish("message.created", () => {
24679
- const projection = (0, import_protocols25.snapshotProjectRoomMessageRealtime)(message);
25808
+ const projection = (0, import_protocols26.snapshotProjectRoomMessageRealtime)(message);
24680
25809
  if (!projection) return void 0;
24681
25810
  return {
24682
25811
  sourceKey: `message:${projection.publicMessage.id}`,
@@ -24691,7 +25820,7 @@ var BrokerProjectRoomRealtimePublisher = class {
24691
25820
  this.publish("roster.changed", () => {
24692
25821
  const membership = snapshotInput(input, "roster");
24693
25822
  if (membership.membership.tenantId !== membership.tenantId || membership.membership.roomId !== membership.roomId || !safeId2(membership.membership.projectId)) throw new TypeError("Invalid roster scope");
24694
- const projection = (0, import_protocols25.snapshotProjectRoomBotMembershipRealtime)(membership.membership);
25823
+ const projection = (0, import_protocols26.snapshotProjectRoomBotMembershipRealtime)(membership.membership);
24695
25824
  if (!projection) return void 0;
24696
25825
  return {
24697
25826
  sourceKey: membership.sourceKey,
@@ -24706,7 +25835,7 @@ var BrokerProjectRoomRealtimePublisher = class {
24706
25835
  this.publish("membership.changed", () => {
24707
25836
  const membership = snapshotInput(input, "membership");
24708
25837
  if (membership.membership.tenantId !== membership.tenantId || !safeId2(membership.membership.projectId)) throw new TypeError("Invalid membership scope");
24709
- const projection = (0, import_protocols25.snapshotProjectRoomMembershipRealtime)(membership.membership);
25838
+ const projection = (0, import_protocols26.snapshotProjectRoomMembershipRealtime)(membership.membership);
24710
25839
  if (!projection) return void 0;
24711
25840
  return {
24712
25841
  sourceKey: membership.sourceKey,
@@ -24735,11 +25864,11 @@ var BrokerProjectRoomRealtimePublisher = class {
24735
25864
  /** Publishes a membership notice onto the affected user's channel scope. */
24736
25865
  membershipAffected(input) {
24737
25866
  this.publish("membership.affected", () => {
24738
- const value = (0, import_protocols25.snapshotExactRecord)(input, ["tenantId", "userId", "change", "projectId", "roomId", "sourceKey"]);
25867
+ const value = (0, import_protocols26.snapshotExactRecord)(input, ["tenantId", "userId", "change", "projectId", "roomId", "sourceKey"]);
24739
25868
  if (!value || !safeId2(value.tenantId) || !safeId2(value.userId) || !safeId2(value.projectId) || !safeId2(value.roomId) || !safeSourceKey(value.sourceKey) || !["added", "removed", "role_changed"].includes(value.change)) {
24740
25869
  throw new TypeError("Invalid membership input");
24741
25870
  }
24742
- const scope = (0, import_protocols25.projectRoomUserEventScope)(value.tenantId, value.userId);
25871
+ const scope = (0, import_protocols26.projectRoomUserEventScope)(value.tenantId, value.userId);
24743
25872
  return {
24744
25873
  sourceKey: value.sourceKey,
24745
25874
  id: value.sourceKey,
@@ -24755,11 +25884,11 @@ var BrokerProjectRoomRealtimePublisher = class {
24755
25884
  /** Publishes a read-marker update onto the acting user's channel scope. */
24756
25885
  readChanged(input) {
24757
25886
  this.publish("read.changed", () => {
24758
- const value = (0, import_protocols25.snapshotExactRecord)(input, ["tenantId", "userId", "projectId", "roomId", "lastReadAt", "sourceKey"]);
25887
+ const value = (0, import_protocols26.snapshotExactRecord)(input, ["tenantId", "userId", "projectId", "roomId", "lastReadAt", "sourceKey"]);
24759
25888
  if (!value || !safeId2(value.tenantId) || !safeId2(value.userId) || !safeId2(value.projectId) || !safeId2(value.roomId) || !safeSourceKey(value.sourceKey) || typeof value.lastReadAt !== "string" || !Number.isFinite(Date.parse(value.lastReadAt))) {
24760
25889
  throw new TypeError("Invalid read input");
24761
25890
  }
24762
- const scope = (0, import_protocols25.projectRoomUserEventScope)(value.tenantId, value.userId);
25891
+ const scope = (0, import_protocols26.projectRoomUserEventScope)(value.tenantId, value.userId);
24763
25892
  return {
24764
25893
  sourceKey: value.sourceKey,
24765
25894
  id: value.sourceKey,
@@ -24777,7 +25906,7 @@ var BrokerProjectRoomRealtimePublisher = class {
24777
25906
  try {
24778
25907
  event = build();
24779
25908
  if (!event) throw new Error("Invalid Project Room realtime projection");
24780
- const dedupeKey = (0, import_node_crypto24.createHash)("sha256").update(JSON.stringify([type, event.scope.tenantId, event.scope.projectId, event.scope.roomId, event.sourceKey])).digest("hex");
25909
+ const dedupeKey = (0, import_node_crypto25.createHash)("sha256").update(JSON.stringify([type, event.scope.tenantId, event.scope.projectId, event.scope.roomId, event.sourceKey])).digest("hex");
24781
25910
  if (this.sourceKeys.has(dedupeKey)) return;
24782
25911
  this.deps.broker.publish(event.scope, event.draft);
24783
25912
  this.sourceKeys.set(dedupeKey, true);
@@ -24800,13 +25929,13 @@ var BrokerProjectRoomRealtimePublisher = class {
24800
25929
  };
24801
25930
  function snapshotInput(input, kind) {
24802
25931
  const keys2 = kind === "message" ? ["tenantId", "roomId", "message", "sourceKey"] : kind === "roster" ? ["tenantId", "roomId", "membership", "sourceKey"] : ["tenantId", "roomId", "membership", "sourceKey"];
24803
- const value = (0, import_protocols25.snapshotExactRecord)(input, [...keys2, "change"]);
25932
+ const value = (0, import_protocols26.snapshotExactRecord)(input, [...keys2, "change"]);
24804
25933
  const validChange = kind === "roster" ? ["added", "updated", "paused", "resumed", "removed"].includes(value?.change) : ["added", "role_changed", "removed"].includes(value?.change);
24805
25934
  if (!value || !safeId2(value.tenantId) || !safeId2(value.roomId) || !safeSourceKey(value.sourceKey) || !validChange) throw new TypeError(`Invalid ${kind} input`);
24806
25935
  return value;
24807
25936
  }
24808
25937
  function snapshotTaskInput(input) {
24809
- const value = (0, import_protocols25.snapshotExactRecord)(input, ["tenantId", "roomId", "projectId", "taskId", "status", "ownerMembershipId", "updatedAt", "sourceKey"]);
25938
+ const value = (0, import_protocols26.snapshotExactRecord)(input, ["tenantId", "roomId", "projectId", "taskId", "status", "ownerMembershipId", "updatedAt", "sourceKey"]);
24810
25939
  if (!value || !safeId2(value.tenantId) || !safeId2(value.roomId) || !safeSourceKey(value.sourceKey)) throw new TypeError("Invalid task input");
24811
25940
  if (!safeId2(value.projectId) || !safeId2(value.taskId) || !safeId2(value.ownerMembershipId) || !["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"].includes(value.status)) throw new TypeError("Invalid task input");
24812
25941
  if (typeof value.updatedAt !== "string") throw new TypeError("Invalid task timestamp");
@@ -24831,7 +25960,7 @@ function safeErrorCode(error) {
24831
25960
  }
24832
25961
 
24833
25962
  // src/services/collaboration/ProjectRoomTaskEventSubscriber.ts
24834
- var import_protocols26 = require("@axiom-lattice/protocols");
25963
+ var import_protocols27 = require("@axiom-lattice/protocols");
24835
25964
  var ProjectRoomTaskEventSubscriber = class {
24836
25965
  /** Creates a bounded Project task lifecycle observer. */
24837
25966
  constructor(deps) {
@@ -24941,7 +26070,7 @@ var ProjectRoomTaskEventSubscriber = class {
24941
26070
  }
24942
26071
  }
24943
26072
  parse(value) {
24944
- const row = (0, import_protocols26.snapshotExactRecord)(value, ["tenantId", "workspaceId", "projectId", "taskId", "status", "action", "eventKey", "updatedAt"], ["threadId"]);
26073
+ const row = (0, import_protocols27.snapshotExactRecord)(value, ["tenantId", "workspaceId", "projectId", "taskId", "status", "action", "eventKey", "updatedAt"], ["threadId"]);
24945
26074
  const actions = ["in_progress", "interrupted", "failed", "completed", "cancelled", "reassigned"];
24946
26075
  const statuses = ["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"];
24947
26076
  if (!row || !actions.includes(String(row.action)) || !statuses.includes(String(row.status)) || !["tenantId", "workspaceId", "projectId", "taskId", "eventKey", "updatedAt"].every((key) => typeof row[key] === "string" && row[key].length > 0) || !Number.isFinite(Date.parse(row.updatedAt)) || row.threadId !== void 0 && typeof row.threadId !== "string") return void 0;
@@ -25017,7 +26146,7 @@ function createProjectRoomRealtimeRuntime(deps) {
25017
26146
  broker,
25018
26147
  publisher,
25019
26148
  subscriber,
25020
- subscribe: (listener) => import_core49.taskLifecycleNotifier.subscribe(listener),
26149
+ subscribe: (listener) => import_core50.taskLifecycleNotifier.subscribe(listener),
25021
26150
  log: deps.log,
25022
26151
  shutdownTimeoutMs: deps.shutdownTimeoutMs
25023
26152
  });
@@ -25137,7 +26266,7 @@ function createRoomPushNotifier(input) {
25137
26266
  }
25138
26267
 
25139
26268
  // src/services/collaboration/WorkspaceRoomEventsService.ts
25140
- var import_protocols27 = require("@axiom-lattice/protocols");
26269
+ var import_protocols28 = require("@axiom-lattice/protocols");
25141
26270
 
25142
26271
  // src/services/collaboration/ProjectRoomSseWriter.ts
25143
26272
  var DEFAULT_MAX_FRAMES = 256;
@@ -25385,7 +26514,7 @@ var WorkspaceRoomEventsService = class {
25385
26514
  const clear = (timer) => {
25386
26515
  if (timer !== void 0) clearTimeout(timer);
25387
26516
  };
25388
- const userScope = (0, import_protocols27.projectRoomUserEventScope)(actor3.tenantId, actor3.userId);
26517
+ const userScope = (0, import_protocols28.projectRoomUserEventScope)(actor3.tenantId, actor3.userId);
25389
26518
  const userScopeKey = JSON.stringify([userScope.tenantId, userScope.roomId, userScope.projectId]);
25390
26519
  const roomScopeKey = (scope) => JSON.stringify([scope.tenantId, scope.roomId, scope.projectId]);
25391
26520
  const serializeScoped = (scope, event) => scope === null ? `id: ${event.id}
@@ -25495,7 +26624,7 @@ data: ${JSON.stringify({ ...event, scope })}
25495
26624
  accessTimer = setTimeout(() => {
25496
26625
  accessTimer = void 0;
25497
26626
  if (closed) return;
25498
- const projectIds = [...subscriptions.values()].map((entry) => entry.scope.projectId).filter((projectId) => projectId !== import_protocols27.PROJECT_ROOM_USER_CHANNEL_PROJECT);
26627
+ const projectIds = [...subscriptions.values()].map((entry) => entry.scope.projectId).filter((projectId) => projectId !== import_protocols28.PROJECT_ROOM_USER_CHANNEL_PROJECT);
25499
26628
  Promise.all(projectIds.map((projectId) => Promise.resolve().then(() => this.deps.requireReadAccess({ tenantId: actor3.tenantId, userId: actor3.userId, projectId })))).then(() => {
25500
26629
  if (!closed) scheduleAccessCheck();
25501
26630
  }, () => {
@@ -25538,7 +26667,7 @@ function createWorkspaceMemberRoomLister(deps) {
25538
26667
  }
25539
26668
 
25540
26669
  // src/routes/workspace-room-events.ts
25541
- var import_protocols28 = require("@axiom-lattice/protocols");
26670
+ var import_protocols29 = require("@axiom-lattice/protocols");
25542
26671
  function registerWorkspaceRoomEventRoutes(app2, deps) {
25543
26672
  app2.get("/api/workspaces/:workspaceId/room-events", async (request, reply) => {
25544
26673
  try {
@@ -25566,7 +26695,7 @@ function registerWorkspaceRoomEventRoutes(app2, deps) {
25566
26695
  });
25567
26696
  }
25568
26697
  function exactParams(params) {
25569
- const value = (0, import_protocols28.snapshotExactRecord)(params, ["workspaceId"]);
26698
+ const value = (0, import_protocols29.snapshotExactRecord)(params, ["workspaceId"]);
25570
26699
  if (!value || typeof value.workspaceId !== "string" || !value.workspaceId.trim()) throw new InvalidRealtimeRequestError();
25571
26700
  return { workspaceId: value.workspaceId };
25572
26701
  }
@@ -25694,7 +26823,7 @@ function snapshotDataRecord(value) {
25694
26823
  for (const key of Reflect.ownKeys(descriptors)) {
25695
26824
  if (typeof key !== "string") return void 0;
25696
26825
  const descriptor = descriptors[key];
25697
- const data = (0, import_protocols29.descriptorDataValue)(descriptor);
26826
+ const data = (0, import_protocols30.descriptorDataValue)(descriptor);
25698
26827
  if (!data) return void 0;
25699
26828
  result[key] = data.value;
25700
26829
  }
@@ -25709,7 +26838,7 @@ function isPublicRoomAddress(message) {
25709
26838
  }
25710
26839
  async function validateReassignmentThread(threads, input) {
25711
26840
  const thread = snapshotThread(await threads.getThreadById(input.tenantId, input.newThreadId));
25712
- const metadata = (0, import_protocols29.snapshotExactRecord)(thread?.metadata, [
26841
+ const metadata = (0, import_protocols30.snapshotExactRecord)(thread?.metadata, [
25713
26842
  "source",
25714
26843
  "kind",
25715
26844
  "workspaceId",
@@ -25755,35 +26884,35 @@ function hookErrorMessage(error) {
25755
26884
  function wrapReassignmentThreadError(error) {
25756
26885
  if (error instanceof ProjectTaskThreadError) {
25757
26886
  if (error.code === "PROJECT_TASK_THREAD_SCOPE_INVALID") {
25758
- return new import_core50.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", error.message, {
26887
+ return new import_core51.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", error.message, {
25759
26888
  hint: "Project task, room, or roster scope changed; re-read the task and retry."
25760
26889
  });
25761
26890
  }
25762
26891
  if (error.code === "PROJECT_TASK_THREAD_OWNER_INVALID") {
25763
- return new import_core50.ManagedTaskStartError("TASK_REASSIGN_NO_CHANGE", error.message, {
26892
+ return new import_core51.ManagedTaskStartError("TASK_REASSIGN_NO_CHANGE", error.message, {
25764
26893
  hint: "The target already owns this task; re-read before dispatching."
25765
26894
  });
25766
26895
  }
25767
- return new import_core50.ManagedTaskStartError("TASK_THREAD_CONFLICT", error.message, {
26896
+ return new import_core51.ManagedTaskStartError("TASK_THREAD_CONFLICT", error.message, {
25768
26897
  hint: "Task Thread changed concurrently; re-read the task and retry."
25769
26898
  });
25770
26899
  }
25771
- return new import_core50.ManagedTaskStartError("TASK_EXECUTION_ENQUEUE_FAILED", hookErrorMessage(error), {
26900
+ return new import_core51.ManagedTaskStartError("TASK_EXECUTION_ENQUEUE_FAILED", hookErrorMessage(error), {
25772
26901
  hint: "Re-read the task and retry the dispatch."
25773
26902
  });
25774
26903
  }
25775
26904
  function wrapReassignmentAuthorizationError(error) {
25776
- if (error instanceof import_core50.ProjectTaskOwnerPolicyError) {
26905
+ if (error instanceof import_core51.ProjectTaskOwnerPolicyError) {
25777
26906
  if (error.code === "PROJECT_TASK_CALLER_INACTIVE") {
25778
- return new import_core50.ManagedTaskStartError("PROJECT_TASK_CALLER_INACTIVE", error.message, {
26907
+ return new import_core51.ManagedTaskStartError("PROJECT_TASK_CALLER_INACTIVE", error.message, {
25779
26908
  hint: "Dispatch from an active Project Room member bot."
25780
26909
  });
25781
26910
  }
25782
- return new import_core50.ManagedTaskStartError("PROJECT_TASK_OWNER_INACTIVE", error.message, {
26911
+ return new import_core51.ManagedTaskStartError("PROJECT_TASK_OWNER_INACTIVE", error.message, {
25783
26912
  hint: "Dispatch to an active bot in this Project's roster."
25784
26913
  });
25785
26914
  }
25786
- return new import_core50.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", hookErrorMessage(error), {
26915
+ return new import_core51.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", hookErrorMessage(error), {
25787
26916
  hint: "Re-read the task and roster, then retry the dispatch."
25788
26917
  });
25789
26918
  }
@@ -25812,43 +26941,43 @@ async function transferGovernedDispatchOwner(task, options, deps) {
25812
26941
  const agentId = options?.agentId;
25813
26942
  if (!agentId || agentId === task.ownerId) return void 0;
25814
26943
  if (!task.workspaceId || !task.projectId) {
25815
- throw new import_core50.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", "Task is not governed by a Project lifecycle.", {
26944
+ throw new import_core51.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", "Task is not governed by a Project lifecycle.", {
25816
26945
  hint: "Dispatch governed tasks from a trusted Project run; ordinary tasks execute immediately."
25817
26946
  });
25818
26947
  }
25819
26948
  return deps.mutex.runExclusive({ tenantId: task.tenantId, projectId: task.projectId }, async () => {
25820
26949
  const current = await deps.tasks.getById(task.tenantId, task.id);
25821
26950
  if (!current || !isProjectLifecycleTask(current) || current.workspaceId !== task.workspaceId || current.projectId !== task.projectId) {
25822
- throw new import_core50.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", "Task is no longer a Project lifecycle task.", {
26951
+ throw new import_core51.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", "Task is no longer a Project lifecycle task.", {
25823
26952
  hint: "Re-read the task and confirm it still belongs to this Project before dispatching."
25824
26953
  });
25825
26954
  }
25826
26955
  if (current.ownerType !== "agent") {
25827
- throw new import_core50.ManagedTaskStartError("AGENT_TASK_REQUIRED", "Project task owner must be an Agent.", {
26956
+ throw new import_core51.ManagedTaskStartError("AGENT_TASK_REQUIRED", "Project task owner must be an Agent.", {
25828
26957
  hint: "Assign the task to an Agent before dispatching."
25829
26958
  });
25830
26959
  }
25831
26960
  if (current.status !== "pending") {
25832
- throw new import_core50.ManagedTaskStartError("TASK_NOT_DISPATCHABLE", "Only a `pending` Project task can be dispatched.", {
26961
+ throw new import_core51.ManagedTaskStartError("TASK_NOT_DISPATCHABLE", "Only a `pending` Project task can be dispatched.", {
25833
26962
  hint: `This task is '${current.status}'. Resolve it or create a new task before dispatching.`
25834
26963
  });
25835
26964
  }
25836
26965
  if (agentId === current.ownerId) return current;
25837
26966
  const room = await deps.rooms.getMainRoom(current.tenantId, current.projectId);
25838
26967
  if (!room || room.tenantId !== current.tenantId || room.workspaceId !== current.workspaceId || room.projectId !== current.projectId || room.type !== "main") {
25839
- throw new import_core50.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", "Project main room is unavailable.", {
26968
+ throw new import_core51.ManagedTaskStartError("PROJECT_TASK_CONTEXT_INVALID", "Project main room is unavailable.", {
25840
26969
  hint: "Open or repair the Project Room before dispatching."
25841
26970
  });
25842
26971
  }
25843
26972
  const target = await deps.botMemberships.findByAssistant(current.tenantId, current.projectId, agentId);
25844
26973
  if (!target || target.status !== "active" || target.tenantId !== current.tenantId || target.workspaceId !== current.workspaceId || target.projectId !== current.projectId || target.assistantId !== agentId || target.roomId !== room.id) {
25845
- throw new import_core50.ManagedTaskStartError("PROJECT_TASK_OWNER_INACTIVE", "Target Project task owner is not active in the exact roster.", {
26974
+ throw new import_core51.ManagedTaskStartError("PROJECT_TASK_OWNER_INACTIVE", "Target Project task owner is not active in the exact roster.", {
25846
26975
  hint: "Dispatch to an active bot in this Project's roster."
25847
26976
  });
25848
26977
  }
25849
26978
  const caller = options?.callerMembershipId ? await deps.botMemberships.findById(current.tenantId, options.callerMembershipId) : null;
25850
26979
  if (!caller || !options?.callerAssistantId || caller.id !== options.callerMembershipId || caller.assistantId !== options.callerAssistantId || caller.status !== "active" || caller.tenantId !== current.tenantId || caller.workspaceId !== current.workspaceId || caller.projectId !== current.projectId || caller.roomId !== room.id) {
25851
- throw new import_core50.ManagedTaskStartError("PROJECT_TASK_CALLER_INACTIVE", "Current Project task caller is not active in the exact roster.", {
26980
+ throw new import_core51.ManagedTaskStartError("PROJECT_TASK_CALLER_INACTIVE", "Current Project task caller is not active in the exact roster.", {
25852
26981
  hint: "Dispatch from an active Project Room member bot."
25853
26982
  });
25854
26983
  }
@@ -25883,7 +27012,7 @@ async function transferGovernedDispatchOwner(task, options, deps) {
25883
27012
  actor: `agent:${caller.assistantId}`
25884
27013
  });
25885
27014
  if (!result.success) {
25886
- throw new import_core50.ManagedTaskStartError(result.code, result.error, {
27015
+ throw new import_core51.ManagedTaskStartError(result.code, result.error, {
25887
27016
  hint: result.hint ?? reassignmentFailureHint(result.code),
25888
27017
  ...result.retryable !== void 0 ? { retryable: result.retryable } : {}
25889
27018
  });
@@ -25892,19 +27021,19 @@ async function transferGovernedDispatchOwner(task, options, deps) {
25892
27021
  });
25893
27022
  }
25894
27023
  var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
25895
- const webAppStore = (0, import_core50.getStoreLattice)("default", "agentWebApp").store;
25896
- const assistantStore = (0, import_core50.getStoreLattice)("default", "assistant").store;
25897
- const projectStore = (0, import_core50.getStoreLattice)("default", "project").store;
25898
- const projectMembershipStore = (0, import_core50.getStoreLattice)("default", "projectMembership").store;
25899
- const userTenantLinkStore = (0, import_core50.getStoreLattice)("default", "userTenantLink").store;
25900
- const projectRoomStore = (0, import_core50.getStoreLattice)("default", "projectRoom").store;
25901
- const projectBotMembershipStore = (0, import_core50.getStoreLattice)("default", "projectBotMembership").store;
25902
- const projectRoomMessageStore = (0, import_core50.getStoreLattice)("default", "projectRoomMessage").store;
25903
- const projectRoomReadStateStore = (0, import_core50.getStoreLattice)("default", "projectRoomReadState").store;
25904
- const userPushSubscriptionStore = (0, import_core50.getStoreLattice)("default", "userPushSubscription").store;
25905
- const threadStore = (0, import_core50.getStoreLattice)("default", "thread").store;
25906
- const taskStore = (0, import_core50.getStoreLattice)("default", "task").store;
25907
- const taskWorkItemStore = (0, import_core50.getStoreLattice)("default", "taskWorkItem").store;
27024
+ const webAppStore = (0, import_core51.getStoreLattice)("default", "agentWebApp").store;
27025
+ const assistantStore = (0, import_core51.getStoreLattice)("default", "assistant").store;
27026
+ const projectStore = (0, import_core51.getStoreLattice)("default", "project").store;
27027
+ const projectMembershipStore = (0, import_core51.getStoreLattice)("default", "projectMembership").store;
27028
+ const userTenantLinkStore = (0, import_core51.getStoreLattice)("default", "userTenantLink").store;
27029
+ const projectRoomStore = (0, import_core51.getStoreLattice)("default", "projectRoom").store;
27030
+ const projectBotMembershipStore = (0, import_core51.getStoreLattice)("default", "projectBotMembership").store;
27031
+ const projectRoomMessageStore = (0, import_core51.getStoreLattice)("default", "projectRoomMessage").store;
27032
+ const projectRoomReadStateStore = (0, import_core51.getStoreLattice)("default", "projectRoomReadState").store;
27033
+ const userPushSubscriptionStore = (0, import_core51.getStoreLattice)("default", "userPushSubscription").store;
27034
+ const threadStore = (0, import_core51.getStoreLattice)("default", "thread").store;
27035
+ const taskStore = (0, import_core51.getStoreLattice)("default", "task").store;
27036
+ const taskWorkItemStore = (0, import_core51.getStoreLattice)("default", "taskWorkItem").store;
25908
27037
  const projectTaskEnabled = options.projectTaskEnabled ?? process.env.AXIOM_PROJECT_TASK_EXECUTION_ENABLED !== "false";
25909
27038
  const accessService = new ProjectAccessService({ projectStore, membershipStore: projectMembershipStore, userTenantLinkStore });
25910
27039
  const realtimeMode = resolveProjectRoomRealtimeMode();
@@ -25970,7 +27099,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
25970
27099
  updateAssistant: assistantStore.updateAssistant.bind(assistantStore)
25971
27100
  });
25972
27101
  const resolveCoordinatorMentionName = async (tenantId) => {
25973
- const tenant2 = await (0, import_core50.getStoreLattice)("default", "tenant").store.getTenantById(tenantId);
27102
+ const tenant2 = await (0, import_core51.getStoreLattice)("default", "tenant").store.getTenantById(tenantId);
25974
27103
  const value = tenant2?.metadata?.coordinatorMentionName;
25975
27104
  return typeof value === "string" && value.length > 0 ? value : void 0;
25976
27105
  };
@@ -25997,7 +27126,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
25997
27126
  return membership !== null && membership.projectId === projectId ? membership : null;
25998
27127
  },
25999
27128
  getThreadStatus: async ({ tenantId, assistantId, threadId, workspaceId, projectId }) => {
26000
- const agent = import_core50.agentInstanceManager.getAgent({
27129
+ const agent = import_core51.agentInstanceManager.getAgent({
26001
27130
  tenant_id: tenantId,
26002
27131
  assistant_id: assistantId,
26003
27132
  thread_id: threadId,
@@ -26006,9 +27135,9 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26006
27135
  });
26007
27136
  return String(await agent.getRunStatus());
26008
27137
  },
26009
- dispatcher: (0, import_core50.createTrustedAgentMessageDispatcher)((scope) => import_core50.agentInstanceManager.getAgent(scope))
27138
+ dispatcher: (0, import_core51.createTrustedAgentMessageDispatcher)((scope) => import_core51.agentInstanceManager.getAgent(scope))
26010
27139
  });
26011
- const membershipService = new ProjectMembershipService({ membershipStore: projectMembershipStore, userTenantLinkStore, accessService, projectMutationMutex: import_core50.projectMutationMutex, roomStore: projectRoomStore, realtime, onRealtimeFailure: realtime && channelDeps?.warn ? ({ code, membershipId }) => channelDeps.warn?.("project-room:membership-realtime-failed", { code, membershipId }) : void 0 });
27140
+ const membershipService = new ProjectMembershipService({ membershipStore: projectMembershipStore, userTenantLinkStore, accessService, projectMutationMutex: import_core51.projectMutationMutex, roomStore: projectRoomStore, realtime, onRealtimeFailure: realtime && channelDeps?.warn ? ({ code, membershipId }) => channelDeps.warn?.("project-room:membership-realtime-failed", { code, membershipId }) : void 0 });
26012
27141
  const rosterService = new ProjectRosterService({
26013
27142
  accessService,
26014
27143
  roomService,
@@ -26019,7 +27148,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26019
27148
  assistantStore,
26020
27149
  taskStore,
26021
27150
  bindingLifecycle,
26022
- projectMutationMutex: import_core50.projectMutationMutex,
27151
+ projectMutationMutex: import_core51.projectMutationMutex,
26023
27152
  realtime,
26024
27153
  onRealtimeFailure: realtime && channelDeps?.warn ? ({ code, membershipId }) => channelDeps.warn?.("project-room:roster-realtime-failed", { code, membershipId }) : void 0
26025
27154
  });
@@ -26074,10 +27203,10 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26074
27203
  });
26075
27204
  }
26076
27205
  if (projectTaskComposition) app2.addHook("onClose", async () => projectTaskComposition.lease.release());
26077
- const taskThreadService = projectTaskComposition?.lease.runtime.threads ?? new ProjectTaskThreadService({ threads: threadStore, idFactory: import_node_crypto25.randomUUID });
26078
- const taskLifecycle = projectTaskComposition?.lease.runtime.lifecycle ?? (0, import_core50.createTaskLifecycleService)({ taskStore, workItemStore: taskWorkItemStore });
26079
- const reassignmentAuthorizer = (0, import_core50.createProjectTaskReassignmentAuthorizer)(
26080
- new import_core50.ProjectTaskOwnerPolicy(projectBotMembershipStore),
27206
+ const taskThreadService = projectTaskComposition?.lease.runtime.threads ?? new ProjectTaskThreadService({ threads: threadStore, idFactory: import_node_crypto26.randomUUID });
27207
+ const taskLifecycle = projectTaskComposition?.lease.runtime.lifecycle ?? (0, import_core51.createTaskLifecycleService)({ taskStore, workItemStore: taskWorkItemStore });
27208
+ const reassignmentAuthorizer = (0, import_core51.createProjectTaskReassignmentAuthorizer)(
27209
+ new import_core51.ProjectTaskOwnerPolicy(projectBotMembershipStore),
26081
27210
  (input) => validateReassignmentThread(threadStore, input)
26082
27211
  );
26083
27212
  const taskCommandService = new TaskCommandService({
@@ -26086,7 +27215,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26086
27215
  lifecycle: taskLifecycle,
26087
27216
  execution: projectTaskComposition?.lease.runtime.execution,
26088
27217
  threads: taskThreadService,
26089
- agents: { getAgent: (params) => import_core50.agentInstanceManager.getAgent(params) },
27218
+ agents: { getAgent: (params) => import_core51.agentInstanceManager.getAgent(params) },
26090
27219
  taskScope: (task) => resolveCommandTaskScope(task, {
26091
27220
  rooms: projectRoomStore,
26092
27221
  bots: projectBotMembershipStore,
@@ -26124,7 +27253,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26124
27253
  readStateService,
26125
27254
  interruptService: roomInterruptService,
26126
27255
  userDirectory: {
26127
- getUserById: (id3) => (0, import_core50.getStoreLattice)("default", "user").store.getUserById(id3).then((u) => u ? { name: u.name } : null)
27256
+ getUserById: (id3) => (0, import_core51.getStoreLattice)("default", "user").store.getUserById(id3).then((u) => u ? { name: u.name } : null)
26128
27257
  }
26129
27258
  });
26130
27259
  registerProjectRosterRoutes(app2, { service: rosterService });
@@ -26135,7 +27264,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26135
27264
  createProject: projectStore.createProject.bind(projectStore)
26136
27265
  },
26137
27266
  workspaceStore: {
26138
- getWorkspaceById: (tenantId, id3) => (0, import_core50.getStoreLattice)("default", "workspace").store.getWorkspaceById(tenantId, id3)
27267
+ getWorkspaceById: (tenantId, id3) => (0, import_core51.getStoreLattice)("default", "workspace").store.getWorkspaceById(tenantId, id3)
26139
27268
  },
26140
27269
  membershipStore: {
26141
27270
  list: projectMembershipStore.list.bind(projectMembershipStore),
@@ -26158,7 +27287,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26158
27287
  getUsersByTenant: userTenantLinkStore.getUsersByTenant.bind(userTenantLinkStore)
26159
27288
  },
26160
27289
  userStore: {
26161
- getUserById: (id3) => (0, import_core50.getStoreLattice)("default", "user").store.getUserById(id3).then((u) => u ? { id: u.id, name: u.name, email: u.email } : null)
27290
+ getUserById: (id3) => (0, import_core51.getStoreLattice)("default", "user").store.getUserById(id3).then((u) => u ? { id: u.id, name: u.name, email: u.email } : null)
26162
27291
  },
26163
27292
  assistantStore: {
26164
27293
  getAssistantById: assistantStore.getAssistantById.bind(assistantStore),
@@ -26180,18 +27309,28 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26180
27309
  }
26181
27310
  });
26182
27311
  registerCapabilityBundleRoutes(app2, new CapabilityBundleController({
26183
- bundleStore: (0, import_core50.getStoreLattice)("default", "capabilityBundle").store,
27312
+ bundleStore: (0, import_core51.getStoreLattice)("default", "capabilityBundle").store,
26184
27313
  projectStore
26185
27314
  }, { authRequired: process.env.AUTH_REQUIRED === "true" }));
27315
+ registerModelProviderRoutes(app2, new ModelProviderController({
27316
+ providerStore: (0, import_core51.getStoreLattice)("default", "modelProvider").store,
27317
+ userTenantLinkStore,
27318
+ registry: {
27319
+ register: (tenantId, modelKey2, config) => import_core51.modelLatticeManager.registerLatticeWithTenant(tenantId, modelKey2, config),
27320
+ has: (tenantId, modelKey2) => import_core51.modelLatticeManager.hasLatticeWithTenant(tenantId, modelKey2),
27321
+ remove: (tenantId, modelKey2) => import_core51.modelLatticeManager.removeLatticeWithTenant(tenantId, modelKey2),
27322
+ listRegistered: (tenantId) => import_core51.modelLatticeManager.getLatticeKeysByTenant(tenantId)
27323
+ }
27324
+ }, { authRequired: process.env.AUTH_REQUIRED === "true" }));
26186
27325
  registerAgentWebAppRoutes(app2, {
26187
27326
  service: new AgentWebAppService({
26188
27327
  webAppStore,
26189
27328
  assistantStore,
26190
27329
  projectStore,
26191
- modelRegistry: { has: (key) => import_core50.modelLatticeManager.hasLattice(key) },
27330
+ modelRegistry: { has: (key) => import_core51.modelLatticeManager.hasLattice(key) },
26192
27331
  configuredAgentResolver: createConfiguredAgentResolver({
26193
- hydrate: (tenantId) => import_core50.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId),
26194
- has: (tenantId, assistantId) => import_core50.agentLatticeManager.hasAgentLatticeWithTenant(tenantId, assistantId)
27332
+ hydrate: (tenantId) => import_core51.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId),
27333
+ has: (tenantId, assistantId) => import_core51.agentLatticeManager.hasAgentLatticeWithTenant(tenantId, assistantId)
26195
27334
  })
26196
27335
  })
26197
27336
  });
@@ -26228,28 +27367,28 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26228
27367
  },
26229
27368
  tasks: taskStore,
26230
27369
  workItems: taskWorkItemStore,
26231
- projectMutationMutex: import_core50.projectMutationMutex,
27370
+ projectMutationMutex: import_core51.projectMutationMutex,
26232
27371
  ...projectTaskComposition ? { commands: taskCommandService } : {}
26233
27372
  }),
26234
27373
  service: new AgentWebAppRuntimeService({
26235
27374
  webAppStore,
26236
- threadStore: (0, import_core50.getStoreLattice)("default", "thread").store,
27375
+ threadStore: (0, import_core51.getStoreLattice)("default", "thread").store,
26237
27376
  projectStore,
26238
27377
  assistantResolver: {
26239
27378
  resolve: async (tenantId, assistantId) => {
26240
27379
  const stored = await assistantStore.getAssistantById(tenantId, assistantId);
26241
27380
  if (stored) return { id: stored.id, name: stored.name, description: stored.description };
26242
- await import_core50.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId);
26243
- const config = import_core50.agentLatticeManager.getAgentConfigWithTenant(tenantId, assistantId);
27381
+ await import_core51.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId);
27382
+ const config = import_core51.agentLatticeManager.getAgentConfigWithTenant(tenantId, assistantId);
26244
27383
  return config ? { id: assistantId, name: config.name, description: config.description } : null;
26245
27384
  }
26246
27385
  },
26247
27386
  modelRegistry: {
26248
- has: (key) => import_core50.modelLatticeManager.hasLattice(key),
27387
+ has: (key) => import_core51.modelLatticeManager.hasLattice(key),
26249
27388
  label: (key) => key
26250
27389
  },
26251
27390
  messageReader: {
26252
- getCurrentMessages: ({ tenantId, assistantId, threadId, workspaceId, projectId }) => import_core50.agentInstanceManager.getAgent({
27391
+ getCurrentMessages: ({ tenantId, assistantId, threadId, workspaceId, projectId }) => import_core51.agentInstanceManager.getAgent({
26253
27392
  tenant_id: tenantId,
26254
27393
  assistant_id: assistantId,
26255
27394
  thread_id: threadId,
@@ -26258,7 +27397,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26258
27397
  }).getCurrentMessages()
26259
27398
  },
26260
27399
  agentResolver: {
26261
- getAgent: ({ tenantId, assistantId, threadId, workspaceId, projectId }) => import_core50.agentInstanceManager.getAgent({
27400
+ getAgent: ({ tenantId, assistantId, threadId, workspaceId, projectId }) => import_core51.agentInstanceManager.getAgent({
26262
27401
  tenant_id: tenantId,
26263
27402
  assistant_id: assistantId,
26264
27403
  thread_id: threadId,
@@ -26276,8 +27415,8 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26276
27415
  if (webApp.tenantId !== preview.tenantId) return false;
26277
27416
  const assistant = await assistantStore.getAssistantById(preview.tenantId, webApp.assistantId);
26278
27417
  if (assistant) return !assistant.ownerUserId || assistant.ownerUserId === preview.userId;
26279
- await import_core50.agentLatticeManager.initializeStoredAssistantsForTenant(preview.tenantId);
26280
- return import_core50.agentLatticeManager.hasAgentLatticeWithTenant(preview.tenantId, webApp.assistantId);
27418
+ await import_core51.agentLatticeManager.initializeStoredAssistantsForTenant(preview.tenantId);
27419
+ return import_core51.agentLatticeManager.hasAgentLatticeWithTenant(preview.tenantId, webApp.assistantId);
26281
27420
  }
26282
27421
  })
26283
27422
  });
@@ -26334,14 +27473,14 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26334
27473
  app2.post("/api/personal-assistant", createPersonalAssistant);
26335
27474
  app2.get("/api/personal-assistant", getPersonalAssistant);
26336
27475
  app2.delete("/api/personal-assistant", deletePersonalAssistant);
26337
- import_core50.executionAuthorityRegistry.register({
27476
+ import_core51.executionAuthorityRegistry.register({
26338
27477
  id: "project-lifecycle",
26339
27478
  matches: isProjectLifecycleTask,
26340
27479
  code: "PROJECT_TASK_EXECUTION_MANAGED",
26341
27480
  message: "Project tasks are executed by the durable Project queue runtime",
26342
27481
  onManagedStart: async (task, options2) => {
26343
27482
  if (!projectTaskComposition && options2?.agentId && options2.agentId !== task.ownerId) {
26344
- throw new import_core50.ManagedTaskStartError(
27483
+ throw new import_core51.ManagedTaskStartError(
26345
27484
  "PROJECT_TASK_RUNTIME_UNAVAILABLE",
26346
27485
  "Project task ownership transfer requires the Project task runtime.",
26347
27486
  { hint: "Project task execution is disabled; enable the Project task runtime or dispatch to the current owner." }
@@ -26354,11 +27493,11 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26354
27493
  threads: taskThreadService,
26355
27494
  reassignmentAuthorizer,
26356
27495
  lifecycle: taskLifecycle,
26357
- mutex: import_core50.projectMutationMutex
27496
+ mutex: import_core51.projectMutationMutex
26358
27497
  }) : void 0;
26359
27498
  const admitted = transferred ?? task;
26360
27499
  if (!admitted.workspaceId || !admitted.projectId) return;
26361
- void import_core50.projectTaskAdmissionNotifier.publish({
27500
+ void import_core51.projectTaskAdmissionNotifier.publish({
26362
27501
  tenantId: admitted.tenantId,
26363
27502
  workspaceId: admitted.workspaceId,
26364
27503
  projectId: admitted.projectId,
@@ -26372,7 +27511,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26372
27511
  access: accessService,
26373
27512
  tasks: taskStore,
26374
27513
  workItems: taskWorkItemStore,
26375
- projectMutationMutex: import_core50.projectMutationMutex,
27514
+ projectMutationMutex: import_core51.projectMutationMutex,
26376
27515
  commands: taskCommandService,
26377
27516
  readableProjects: async ({ tenantId, userId, workspaceId }) => {
26378
27517
  const projects = await projectStore.getProjectsByWorkspace(tenantId, workspaceId);
@@ -26640,9 +27779,9 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
26640
27779
  function tryCreateProjectTaskRuntime(input) {
26641
27780
  let projectWorkItems;
26642
27781
  try {
26643
- projectWorkItems = (0, import_protocols29.requireProjectTaskWorkItemStore)(input.taskWorkItemStore);
27782
+ projectWorkItems = (0, import_protocols30.requireProjectTaskWorkItemStore)(input.taskWorkItemStore);
26644
27783
  } catch (error) {
26645
- if (error instanceof import_protocols29.ProjectTaskStoreUnsupportedError) {
27784
+ if (error instanceof import_protocols30.ProjectTaskStoreUnsupportedError) {
26646
27785
  input.log?.warn("project-task:runtime-unavailable", {
26647
27786
  code: error.code,
26648
27787
  missingMethods: error.missingMethods
@@ -26654,9 +27793,9 @@ function tryCreateProjectTaskRuntime(input) {
26654
27793
  let stores;
26655
27794
  try {
26656
27795
  stores = {
26657
- tenants: (0, import_core50.getStoreLattice)("default", "tenant").store,
26658
- workspaces: (0, import_core50.getStoreLattice)("default", "workspace").store,
26659
- queue: (0, import_core50.getStoreLattice)("default", "threadMessageQueue").store
27796
+ tenants: (0, import_core51.getStoreLattice)("default", "tenant").store,
27797
+ workspaces: (0, import_core51.getStoreLattice)("default", "workspace").store,
27798
+ queue: (0, import_core51.getStoreLattice)("default", "threadMessageQueue").store
26660
27799
  };
26661
27800
  const missing = missingRuntimeMethod(input, stores);
26662
27801
  if (missing) return { reason: missing };
@@ -26687,8 +27826,8 @@ function tryCreateProjectTaskRuntime(input) {
26687
27826
  function createRuntime(input, stores, log2) {
26688
27827
  const controller = new AbortController();
26689
27828
  const mutex = new ProjectTaskExecutionMutex();
26690
- const threads = new ProjectTaskThreadService({ threads: input.threadStore, idFactory: import_node_crypto25.randomUUID });
26691
- const lifecycle = (0, import_core50.createTaskLifecycleService)({ taskStore: input.taskStore, workItemStore: input.taskWorkItemStore });
27829
+ const threads = new ProjectTaskThreadService({ threads: input.threadStore, idFactory: import_node_crypto26.randomUUID });
27830
+ const lifecycle = (0, import_core51.createTaskLifecycleService)({ taskStore: input.taskStore, workItemStore: input.taskWorkItemStore });
26692
27831
  const projection = new RoomProjectionService({
26693
27832
  messages: input.projectRoomMessageStore,
26694
27833
  events: input.taskWorkItemStore,
@@ -26696,9 +27835,9 @@ function createRuntime(input, stores, log2) {
26696
27835
  warnings: input.taskWorkItemStore,
26697
27836
  log: log2,
26698
27837
  realtime: input.realtime,
26699
- idFactory: import_node_crypto25.randomUUID
27838
+ idFactory: import_node_crypto26.randomUUID
26700
27839
  });
26701
- const agentFor = (task, thread) => import_core50.agentInstanceManager.getAgent({
27840
+ const agentFor = (task, thread) => import_core51.agentInstanceManager.getAgent({
26702
27841
  tenant_id: task.tenantId,
26703
27842
  assistant_id: task.ownerId,
26704
27843
  thread_id: thread.id,
@@ -26712,7 +27851,7 @@ function createRuntime(input, stores, log2) {
26712
27851
  bots: input.projectBotMembershipStore,
26713
27852
  threads,
26714
27853
  lifecycle,
26715
- dispatcher: (0, import_core50.createTrustedAgentMessageDispatcher)((scope) => import_core50.agentInstanceManager.getAgent(scope)),
27854
+ dispatcher: (0, import_core51.createTrustedAgentMessageDispatcher)((scope) => import_core51.agentInstanceManager.getAgent(scope)),
26716
27855
  queue: stores.queue,
26717
27856
  agentFor
26718
27857
  }, {
@@ -26739,8 +27878,8 @@ function createRuntime(input, stores, log2) {
26739
27878
  const taskLifecycleListener = ((event) => {
26740
27879
  void observer.listener(event);
26741
27880
  });
26742
- const unsubscribe = import_core50.taskLifecycleNotifier.subscribe(taskLifecycleListener);
26743
- const unsubscribeAdmission = import_core50.projectTaskAdmissionNotifier.subscribe((event, signal) => {
27881
+ const unsubscribe = import_core51.taskLifecycleNotifier.subscribe(taskLifecycleListener);
27882
+ const unsubscribeAdmission = import_core51.projectTaskAdmissionNotifier.subscribe((event, signal) => {
26744
27883
  observer.admit(event, signal);
26745
27884
  });
26746
27885
  let reconciliationWork;
@@ -26887,12 +28026,12 @@ function registerResourceRoutes(app2, controller) {
26887
28026
  }
26888
28027
 
26889
28028
  // src/export_registrations/index.ts
26890
- var import_core61 = require("@axiom-lattice/core");
28029
+ var import_core62 = require("@axiom-lattice/core");
26891
28030
 
26892
28031
  // src/export_registrations/skill.registration.ts
26893
- var import_core51 = require("@axiom-lattice/core");
28032
+ var import_core52 = require("@axiom-lattice/core");
26894
28033
  function getStore(context) {
26895
- return new import_core51.SandboxSkillStore({
28034
+ return new import_core52.SandboxSkillStore({
26896
28035
  workspaceId: context?.workspaceId,
26897
28036
  projectId: context?.projectId
26898
28037
  });
@@ -26910,7 +28049,7 @@ var skillRegistration = {
26910
28049
  async listForExport(tenantId, context) {
26911
28050
  const store2 = getStore(context);
26912
28051
  const skills = await store2.getAllSkills(tenantId, toStoreContext(context));
26913
- return skills.filter((s) => !(0, import_core51.isBuiltInSkill)(s.id)).map((s) => ({
28052
+ return skills.filter((s) => !(0, import_core52.isBuiltInSkill)(s.id)).map((s) => ({
26914
28053
  _exportId: "",
26915
28054
  data: {
26916
28055
  id: s.id,
@@ -26975,7 +28114,7 @@ var skillRegistration = {
26975
28114
  const insertions = [];
26976
28115
  for (const entity of entities) {
26977
28116
  const id3 = entity.data.id;
26978
- if ((0, import_core51.isBuiltInSkill)(id3)) continue;
28117
+ if ((0, import_core52.isBuiltInSkill)(id3)) continue;
26979
28118
  if (existingIds.has(id3)) {
26980
28119
  conflicts.push({
26981
28120
  _exportId: entity._exportId,
@@ -27034,9 +28173,9 @@ var skillRegistration = {
27034
28173
  };
27035
28174
 
27036
28175
  // src/export_registrations/agent.registration.ts
27037
- var import_core52 = require("@axiom-lattice/core");
28176
+ var import_core53 = require("@axiom-lattice/core");
27038
28177
  function getStore2() {
27039
- return (0, import_core52.getStoreLattice)("default", "assistant").store;
28178
+ return (0, import_core53.getStoreLattice)("default", "assistant").store;
27040
28179
  }
27041
28180
  var agentRegistration = {
27042
28181
  entityType: "agent",
@@ -27116,9 +28255,9 @@ var agentRegistration = {
27116
28255
  };
27117
28256
 
27118
28257
  // src/export_registrations/database-config.registration.ts
27119
- var import_core53 = require("@axiom-lattice/core");
28258
+ var import_core54 = require("@axiom-lattice/core");
27120
28259
  function getStore3() {
27121
- return (0, import_core53.getStoreLattice)("default", "database").store;
28260
+ return (0, import_core54.getStoreLattice)("default", "database").store;
27122
28261
  }
27123
28262
  var databaseConfigRegistration = {
27124
28263
  entityType: "database_config",
@@ -27198,9 +28337,9 @@ var databaseConfigRegistration = {
27198
28337
  };
27199
28338
 
27200
28339
  // src/export_registrations/metrics-config.registration.ts
27201
- var import_core54 = require("@axiom-lattice/core");
28340
+ var import_core55 = require("@axiom-lattice/core");
27202
28341
  function getStore4() {
27203
- return (0, import_core54.getStoreLattice)("default", "metrics").store;
28342
+ return (0, import_core55.getStoreLattice)("default", "metrics").store;
27204
28343
  }
27205
28344
  var metricsConfigRegistration = {
27206
28345
  entityType: "metrics_config",
@@ -27280,9 +28419,9 @@ var metricsConfigRegistration = {
27280
28419
  };
27281
28420
 
27282
28421
  // src/export_registrations/mcp-config.registration.ts
27283
- var import_core55 = require("@axiom-lattice/core");
28422
+ var import_core56 = require("@axiom-lattice/core");
27284
28423
  function getStore5() {
27285
- return (0, import_core55.getStoreLattice)("default", "mcp").store;
28424
+ return (0, import_core56.getStoreLattice)("default", "mcp").store;
27286
28425
  }
27287
28426
  var mcpConfigRegistration = {
27288
28427
  entityType: "mcp_config",
@@ -27365,9 +28504,9 @@ var mcpConfigRegistration = {
27365
28504
  };
27366
28505
 
27367
28506
  // src/export_registrations/connection.registration.ts
27368
- var import_core56 = require("@axiom-lattice/core");
28507
+ var import_core57 = require("@axiom-lattice/core");
27369
28508
  function getStore6() {
27370
- return (0, import_core56.getStoreLattice)("default", "connection").store;
28509
+ return (0, import_core57.getStoreLattice)("default", "connection").store;
27371
28510
  }
27372
28511
  async function listAllConnections(tenantId) {
27373
28512
  const store2 = getStore6();
@@ -27449,9 +28588,9 @@ var connectionRegistration = {
27449
28588
  };
27450
28589
 
27451
28590
  // src/export_registrations/collection.registration.ts
27452
- var import_core57 = require("@axiom-lattice/core");
28591
+ var import_core58 = require("@axiom-lattice/core");
27453
28592
  function getStore7() {
27454
- return (0, import_core57.getStoreLattice)("default", "collection").store;
28593
+ return (0, import_core58.getStoreLattice)("default", "collection").store;
27455
28594
  }
27456
28595
  var collectionRegistration = {
27457
28596
  entityType: "collection",
@@ -27522,7 +28661,7 @@ var collectionRegistration = {
27522
28661
  };
27523
28662
 
27524
28663
  // src/export_registrations/channel-installation.registration.ts
27525
- var import_core58 = require("@axiom-lattice/core");
28664
+ var import_core59 = require("@axiom-lattice/core");
27526
28665
  var import_crypto11 = require("crypto");
27527
28666
  var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
27528
28667
  var PUBLIC_CHANNELS = /* @__PURE__ */ new Set(["lark", "email", "slack", "wechat"]);
@@ -27556,7 +28695,7 @@ function validateImportData(data) {
27556
28695
  };
27557
28696
  }
27558
28697
  function getStore8() {
27559
- return (0, import_core58.getStoreLattice)("default", "channelInstallation").store;
28698
+ return (0, import_core59.getStoreLattice)("default", "channelInstallation").store;
27560
28699
  }
27561
28700
  function getOverwriteError(tenantId, incomingChannel, existing) {
27562
28701
  if (!existing) return "Channel installation overwrite target must exist";
@@ -27690,9 +28829,9 @@ var channelInstallationRegistration = {
27690
28829
  };
27691
28830
 
27692
28831
  // src/export_registrations/menu.registration.ts
27693
- var import_core59 = require("@axiom-lattice/core");
28832
+ var import_core60 = require("@axiom-lattice/core");
27694
28833
  function getStore9() {
27695
- return (0, import_core59.getStoreLattice)("default", "menu").store;
28834
+ return (0, import_core60.getStoreLattice)("default", "menu").store;
27696
28835
  }
27697
28836
  var menuRegistration = {
27698
28837
  entityType: "menu",
@@ -27770,9 +28909,9 @@ var menuRegistration = {
27770
28909
  };
27771
28910
 
27772
28911
  // src/export_registrations/eval.registration.ts
27773
- var import_core60 = require("@axiom-lattice/core");
28912
+ var import_core61 = require("@axiom-lattice/core");
27774
28913
  function getStore10() {
27775
- return (0, import_core60.getStoreLattice)("default", "eval").store;
28914
+ return (0, import_core61.getStoreLattice)("default", "eval").store;
27776
28915
  }
27777
28916
  var evalRegistration = {
27778
28917
  entityType: "eval",
@@ -28098,7 +29237,7 @@ var evalRegistration = {
28098
29237
 
28099
29238
  // src/export_registrations/index.ts
28100
29239
  function registerAllBuiltinEntities() {
28101
- const registry = import_core61.ExportableEntityRegistry.getInstance();
29240
+ const registry = import_core62.ExportableEntityRegistry.getInstance();
28102
29241
  registry.register(skillRegistration);
28103
29242
  registry.register(agentRegistration);
28104
29243
  registry.register(databaseConfigRegistration);
@@ -28197,13 +29336,13 @@ function createRateLimitMiddleware(maxRequests = 10, windowMs = 60 * 1e3, maxEnt
28197
29336
 
28198
29337
  // src/router/middlewares/auditLogger.ts
28199
29338
  init_Logger();
28200
- var logger4 = new Logger({ serviceName: "lattice/gateway/audit" });
29339
+ var logger5 = new Logger({ serviceName: "lattice/gateway/audit" });
28201
29340
  function createAuditLoggerMiddleware() {
28202
29341
  return async (ctx, next) => {
28203
29342
  const start2 = Date.now();
28204
29343
  try {
28205
29344
  await next();
28206
- logger4.info("message routed", {
29345
+ logger5.info("message routed", {
28207
29346
  event: "message:routed",
28208
29347
  channel: ctx.inboundMessage.channel,
28209
29348
  senderId: ctx.inboundMessage.sender.id,
@@ -28213,7 +29352,7 @@ function createAuditLoggerMiddleware() {
28213
29352
  status: "success"
28214
29353
  });
28215
29354
  } catch (error) {
28216
- logger4.error(
29355
+ logger5.error(
28217
29356
  error instanceof Error ? error.message : String(error),
28218
29357
  {
28219
29358
  event: "message:error",
@@ -28229,7 +29368,7 @@ function createAuditLoggerMiddleware() {
28229
29368
  }
28230
29369
 
28231
29370
  // src/index.ts
28232
- var import_core80 = require("@axiom-lattice/core");
29371
+ var import_core81 = require("@axiom-lattice/core");
28233
29372
 
28234
29373
  // src/swagger.ts
28235
29374
  var import_swagger = __toESM(require("@fastify/swagger"));
@@ -28294,7 +29433,8 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
28294
29433
  };
28295
29434
 
28296
29435
  // src/services/agent_task_consumer.ts
28297
- var import_core62 = require("@axiom-lattice/core");
29436
+ var import_node_crypto27 = require("crypto");
29437
+ var import_core63 = require("@axiom-lattice/core");
28298
29438
  var handleAgentTask = async (taskRequest, retryCount = 0) => {
28299
29439
  const {
28300
29440
  assistant_id,
@@ -28312,51 +29452,97 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
28312
29452
  console.log(
28313
29453
  `\u5F00\u59CB\u5904\u7406\u4EFB\u52A1 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
28314
29454
  );
28315
- const agent = import_core62.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
28316
- await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core62.QueueMode.STEER);
29455
+ const agent = import_core63.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
28317
29456
  if (callback_event) {
28318
- agent.subscribeOnce("message:completed", (evt) => {
28319
- import_core62.eventBus.publish(callback_event, {
28320
- success: true,
28321
- state: evt.state
28322
- });
28323
- if (main_thread_id && main_tenant_id) {
28324
- try {
28325
- const mainAgent = import_core62.agentInstanceManager.getAgent({
28326
- assistant_id: main_assistant_id ?? assistant_id,
28327
- thread_id: main_thread_id,
28328
- tenant_id: main_tenant_id,
28329
- workspace_id: runConfig?.workspaceId,
28330
- project_id: runConfig?.projectId
28331
- });
28332
- if (mainAgent) {
28333
- const messages = evt.state?.values?.messages;
28334
- const lastAIMessage = messages?.filter((m) => m.type === "ai" || m.getType?.() === "ai").pop();
28335
- const summary = lastAIMessage?.content?.substring(0, 500) ?? "(no output)";
28336
- mainAgent.addMessage(
28337
- {
28338
- input: {
28339
- message: `[Async task completed]
29457
+ const callbackEvent = callback_event;
29458
+ const messageId = typeof input?.id === "string" && input.id !== "" ? input.id : (0, import_node_crypto27.randomUUID)();
29459
+ let settled = false;
29460
+ const subscriptions = [];
29461
+ const dispose = () => {
29462
+ for (const [eventName, handler] of subscriptions) {
29463
+ agent.unsubscribe(eventName, handler);
29464
+ }
29465
+ };
29466
+ const settle = (publish) => {
29467
+ if (settled) return;
29468
+ settled = true;
29469
+ dispose();
29470
+ publish();
29471
+ };
29472
+ const belongsToMessage = (evt) => evt?.messageId === messageId;
29473
+ const onCompleted = (evt) => {
29474
+ if (!belongsToMessage(evt)) return;
29475
+ settle(() => {
29476
+ import_core63.eventBus.publish(callbackEvent, {
29477
+ success: true,
29478
+ state: evt.state
29479
+ });
29480
+ if (main_thread_id && main_tenant_id) {
29481
+ try {
29482
+ const mainAgent = import_core63.agentInstanceManager.getAgent({
29483
+ assistant_id: main_assistant_id ?? assistant_id,
29484
+ thread_id: main_thread_id,
29485
+ tenant_id: main_tenant_id,
29486
+ workspace_id: runConfig?.workspaceId,
29487
+ project_id: runConfig?.projectId
29488
+ });
29489
+ if (mainAgent) {
29490
+ const messages = evt.state?.values?.messages;
29491
+ const lastAIMessage = messages?.filter((m) => m.type === "ai" || m.getType?.() === "ai").pop();
29492
+ const summary = lastAIMessage?.content?.substring(0, 500) ?? "(no output)";
29493
+ mainAgent.addMessage(
29494
+ {
29495
+ input: {
29496
+ message: `[Async task completed]
28340
29497
  task_id: ${thread_id}
28341
29498
  ${summary}`
29499
+ }
28342
29500
  }
28343
- }
28344
- ).catch((err) => {
28345
- console.error("Failed to notify main thread:", err);
28346
- });
28347
- mainAgent.updateAsyncTaskStatus(thread_id, "completed");
29501
+ ).catch((err) => {
29502
+ console.error("Failed to notify main thread:", err);
29503
+ });
29504
+ mainAgent.updateAsyncTaskStatus(thread_id, "completed");
29505
+ }
29506
+ } catch (err) {
29507
+ console.error("Failed to notify main thread:", err);
28348
29508
  }
28349
- } catch (err) {
28350
- console.error("Failed to notify main thread:", err);
28351
29509
  }
28352
- }
28353
- });
28354
- agent.subscribeOnce("message:interrupted", (evt) => {
28355
- import_core62.eventBus.publish(callback_event, {
28356
- success: true,
28357
- state: evt.state
28358
29510
  });
28359
- });
29511
+ };
29512
+ const onInterrupted = (evt) => {
29513
+ if (!belongsToMessage(evt)) return;
29514
+ settle(() => {
29515
+ import_core63.eventBus.publish(callbackEvent, {
29516
+ success: true,
29517
+ state: evt.state
29518
+ });
29519
+ });
29520
+ };
29521
+ const onFailed = (evt) => {
29522
+ if (!belongsToMessage(evt)) return;
29523
+ settle(() => {
29524
+ import_core63.eventBus.publish(callbackEvent, {
29525
+ success: false,
29526
+ error: evt?.error instanceof Error ? evt.error.message : typeof evt?.error === "string" ? evt.error : "Agent execution failed"
29527
+ });
29528
+ });
29529
+ };
29530
+ subscriptions.push(
29531
+ ["message:completed", onCompleted],
29532
+ ["message:interrupted", onInterrupted],
29533
+ ["message:failed", onFailed]
29534
+ );
29535
+ agent.subscribe("message:completed", onCompleted);
29536
+ agent.subscribe("message:interrupted", onInterrupted);
29537
+ agent.subscribe("message:failed", onFailed);
29538
+ try {
29539
+ await agent.addMessage({ input: { ...input, id: messageId }, command, custom_run_config: runConfig }, import_core63.QueueMode.STEER);
29540
+ } catch (error) {
29541
+ dispose();
29542
+ throw error;
29543
+ }
29544
+ } else {
29545
+ await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core63.QueueMode.STEER);
28360
29546
  }
28361
29547
  return true;
28362
29548
  } catch (error) {
@@ -28375,7 +29561,7 @@ ${summary}`
28375
29561
  return handleAgentTask(taskRequest, nextRetryCount);
28376
29562
  }
28377
29563
  if (callback_event) {
28378
- import_core62.eventBus.publish(callback_event, {
29564
+ import_core63.eventBus.publish(callback_event, {
28379
29565
  success: false,
28380
29566
  error: error instanceof Error ? error.message : String(error)
28381
29567
  });
@@ -28412,7 +29598,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
28412
29598
  * 初始化事件监听和队列轮询
28413
29599
  */
28414
29600
  initialize() {
28415
- import_core62.eventBus.subscribe(import_core62.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
29601
+ import_core63.eventBus.subscribe(import_core63.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
28416
29602
  this.startPollingQueue();
28417
29603
  console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
28418
29604
  }
@@ -28531,7 +29717,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
28531
29717
  handleAgentTask(taskRequest).catch((error) => {
28532
29718
  console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
28533
29719
  if (taskRequest.callback_event) {
28534
- import_core62.eventBus.publish(taskRequest.callback_event, {
29720
+ import_core63.eventBus.publish(taskRequest.callback_event, {
28535
29721
  success: false,
28536
29722
  error: error instanceof Error ? error.message : String(error)
28537
29723
  });
@@ -28546,14 +29732,14 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
28546
29732
  var AgentTaskConsumer = _AgentTaskConsumer;
28547
29733
 
28548
29734
  // src/index.ts
28549
- var import_core81 = require("@axiom-lattice/core");
29735
+ var import_core82 = require("@axiom-lattice/core");
28550
29736
 
28551
29737
  // src/channels/ChannelInfrastructure.ts
28552
- var import_core64 = require("@axiom-lattice/core");
29738
+ var import_core65 = require("@axiom-lattice/core");
28553
29739
 
28554
29740
  // src/router/MessageRouter.ts
28555
- var import_core63 = require("@axiom-lattice/core");
28556
- var import_protocols30 = require("@axiom-lattice/protocols");
29741
+ var import_core64 = require("@axiom-lattice/core");
29742
+ var import_protocols31 = require("@axiom-lattice/protocols");
28557
29743
  var import_crypto12 = require("crypto");
28558
29744
  var BindingNotFoundError = class extends Error {
28559
29745
  constructor(message) {
@@ -28588,10 +29774,10 @@ function clarifyText(clarify) {
28588
29774
  return ["```clarify", JSON.stringify({ questions: clarify.questions }), "```"].join("\n");
28589
29775
  }
28590
29776
  function exactDataValues(value, required, optional = []) {
28591
- return (0, import_protocols30.snapshotExactRecord)(value, required, optional);
29777
+ return (0, import_protocols31.snapshotExactRecord)(value, required, optional);
28592
29778
  }
28593
29779
  function uniqueNonemptyStrings(value) {
28594
- const snapshot = (0, import_protocols30.snapshotExactArray)(value);
29780
+ const snapshot = (0, import_protocols31.snapshotExactArray)(value);
28595
29781
  if (!snapshot || snapshot.length === 0 || snapshot.some((entry) => typeof entry !== "string" || entry.length === 0)) return void 0;
28596
29782
  const values = snapshot;
28597
29783
  return new Set(values).size === values.length ? values : void 0;
@@ -28838,7 +30024,7 @@ var MessageRouter = class {
28838
30024
  channel: message.channel,
28839
30025
  adapterChannel: adapter.channel
28840
30026
  }, "Thread resolved by adapter strategy");
28841
- const threadStore = (0, import_core63.getStoreLattice)("default", "thread").store;
30027
+ const threadStore = (0, import_core64.getStoreLattice)("default", "thread").store;
28842
30028
  try {
28843
30029
  await threadStore.createThread(
28844
30030
  tenantId,
@@ -28875,7 +30061,7 @@ var MessageRouter = class {
28875
30061
  }
28876
30062
  }
28877
30063
  if (!threadId) {
28878
- const threadStore = (0, import_core63.getStoreLattice)("default", "thread").store;
30064
+ const threadStore = (0, import_core64.getStoreLattice)("default", "thread").store;
28879
30065
  const newThreadId = (0, import_crypto12.randomUUID)();
28880
30066
  console.log({
28881
30067
  event: "dispatch:thread:create",
@@ -28915,7 +30101,7 @@ var MessageRouter = class {
28915
30101
  senderId: message.sender.id,
28916
30102
  contentLength: message.content.text.length
28917
30103
  }, "Dispatching to agent");
28918
- const agent = import_core63.agentInstanceManager.getAgent({
30104
+ const agent = import_core64.agentInstanceManager.getAgent({
28919
30105
  tenant_id: tenantId,
28920
30106
  assistant_id: agentId,
28921
30107
  thread_id: threadId,
@@ -29102,9 +30288,9 @@ var MessageRouter = class {
29102
30288
  };
29103
30289
 
29104
30290
  // src/channels/room/RoomChannelAdapter.ts
29105
- var import_zod15 = require("zod");
29106
- var import_protocols31 = require("@axiom-lattice/protocols");
29107
- var roomConfigSchema = import_zod15.z.object({}).strict();
30291
+ var import_zod17 = require("zod");
30292
+ var import_protocols32 = require("@axiom-lattice/protocols");
30293
+ var roomConfigSchema = import_zod17.z.object({}).strict();
29108
30294
  function createRoomChannelAdapter(writer) {
29109
30295
  return {
29110
30296
  channel: "room",
@@ -29164,7 +30350,7 @@ function exactStrings(value, keys2) {
29164
30350
  function exactValues2(value, required, optional = []) {
29165
30351
  try {
29166
30352
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
29167
- return (0, import_protocols31.snapshotExactRecord)(value, required, optional);
30353
+ return (0, import_protocols32.snapshotExactRecord)(value, required, optional);
29168
30354
  } catch {
29169
30355
  return void 0;
29170
30356
  }
@@ -29188,7 +30374,7 @@ function createChannelInfrastructure(deps) {
29188
30374
  onMessageCommitted: deps.onMessageCommitted ?? (deps.realtime ? (message) => deps.realtime?.messageCreated(message) : void 0),
29189
30375
  onCallbackFailure: (event) => deps.warn("project-room:message-commit-callback-failed", event)
29190
30376
  };
29191
- deps.adapterRegistry.register(createRoomChannelAdapter(new import_core64.RoomAgentMessageService(writerDeps)));
30377
+ deps.adapterRegistry.register(createRoomChannelAdapter(new import_core65.RoomAgentMessageService(writerDeps)));
29192
30378
  } catch (error) {
29193
30379
  deps.warn("Room channel unavailable", { error: error instanceof Error ? error.message : String(error) });
29194
30380
  }
@@ -29209,25 +30395,25 @@ async function prepareProjectTaskRuntime(runtime, log2) {
29209
30395
  }
29210
30396
 
29211
30397
  // src/index.ts
29212
- var import_protocols38 = require("@axiom-lattice/protocols");
30398
+ var import_protocols39 = require("@axiom-lattice/protocols");
29213
30399
  process.on("unhandledRejection", (reason, promise) => {
29214
30400
  console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
29215
30401
  });
29216
30402
  var DEFAULT_LOGGER_CONFIG = {
29217
30403
  name: "default",
29218
30404
  description: "Default logger for lattice-gateway service",
29219
- type: import_protocols38.LoggerType.PINO,
30405
+ type: import_protocols39.LoggerType.PINO,
29220
30406
  serviceName: "lattice/gateway",
29221
30407
  loggerName: "lattice/gateway"
29222
30408
  };
29223
30409
  var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
29224
- var logger6 = loggerLattice.client;
30410
+ var logger7 = loggerLattice.client;
29225
30411
  function initializeLogger(config) {
29226
- if (import_core81.loggerLatticeManager.hasLattice("default")) {
29227
- import_core81.loggerLatticeManager.removeLattice("default");
30412
+ if (import_core82.loggerLatticeManager.hasLattice("default")) {
30413
+ import_core82.loggerLatticeManager.removeLattice("default");
29228
30414
  }
29229
- (0, import_core81.registerLoggerLattice)("default", config);
29230
- return (0, import_core81.getLoggerLattice)("default");
30415
+ (0, import_core82.registerLoggerLattice)("default", config);
30416
+ return (0, import_core82.getLoggerLattice)("default");
29231
30417
  }
29232
30418
  var app = (0, import_fastify.default)({
29233
30419
  logger: false,
@@ -29308,7 +30494,7 @@ app.setErrorHandler((error, request, reply) => {
29308
30494
  "x-request-id": getHeaderValue(request.headers["x-request-id"]),
29309
30495
  "x-user-id": getHeaderValue(request.headers["x-user-id"])
29310
30496
  };
29311
- logger6.error(
30497
+ logger7.error(
29312
30498
  `\u8BF7\u6C42\u9519\u8BEF: ${request.method} ${request.url} error:${error.message}`,
29313
30499
  {
29314
30500
  ...context,
@@ -29324,7 +30510,7 @@ app.setErrorHandler((error, request, reply) => {
29324
30510
  });
29325
30511
  function getConfiguredSandboxProvider() {
29326
30512
  const sandboxProviderType = process.env.SANDBOX_PROVIDER_TYPE || "microsandbox-remote";
29327
- return (0, import_core81.createSandboxProvider)({
30513
+ return (0, import_core82.createSandboxProvider)({
29328
30514
  type: sandboxProviderType,
29329
30515
  remoteBaseURL: process.env.SANDBOX_BASE_URL,
29330
30516
  microsandboxServiceBaseURL: process.env.MICROSANDBOX_SERVICE_BASE_URL,
@@ -29340,33 +30526,33 @@ function getConfiguredSandboxProvider() {
29340
30526
  }
29341
30527
  async function restoreMcpConnections() {
29342
30528
  try {
29343
- const storeLattice = (0, import_core81.getStoreLattice)("default", "mcp");
30529
+ const storeLattice = (0, import_core82.getStoreLattice)("default", "mcp");
29344
30530
  const store2 = storeLattice.store;
29345
30531
  if (!store2) {
29346
- logger6.info("MCP store not configured, skipping connection restoration");
30532
+ logger7.info("MCP store not configured, skipping connection restoration");
29347
30533
  return;
29348
30534
  }
29349
30535
  const configs = (await store2.getAllConfigsWithoutTenant()).filter(
29350
30536
  (c2) => c2.status === "connected"
29351
30537
  );
29352
30538
  if (configs.length === 0) return;
29353
- logger6.info(`Restoring ${configs.length} MCP server connections...`);
30539
+ logger7.info(`Restoring ${configs.length} MCP server connections...`);
29354
30540
  for (const config of configs) {
29355
30541
  try {
29356
- const connection = (0, import_core81.convertToConnection)(config.config);
29357
- import_core81.mcpManager.registerServer(config.tenantId, config.key, connection, {
30542
+ const connection = (0, import_core82.convertToConnection)(config.config);
30543
+ import_core82.mcpManager.registerServer(config.tenantId, config.key, connection, {
29358
30544
  timeoutMs: config.config.timeout,
29359
30545
  maxAttempts: config.config.retryAttempts,
29360
30546
  selectedTools: config.selectedTools
29361
30547
  });
29362
30548
  } catch (err) {
29363
- logger6.warn(`Failed to prepare MCP server "${config.tenantId}/${config.key}"`, { error: err });
30549
+ logger7.warn(`Failed to prepare MCP server "${config.tenantId}/${config.key}"`, { error: err });
29364
30550
  }
29365
30551
  }
29366
- await import_core81.mcpManager.connectAll();
30552
+ await import_core82.mcpManager.connectAll();
29367
30553
  const results = await Promise.allSettled(
29368
30554
  configs.map(
29369
- (config) => import_core81.mcpManager.registerToolsToToolLattice(
30555
+ (config) => import_core82.mcpManager.registerToolsToToolLattice(
29370
30556
  config.tenantId,
29371
30557
  config.key,
29372
30558
  config.selectedTools
@@ -29376,15 +30562,15 @@ async function restoreMcpConnections() {
29376
30562
  results.forEach((result, index) => {
29377
30563
  if (result.status === "rejected") {
29378
30564
  const config = configs[index];
29379
- logger6.warn(
30565
+ logger7.warn(
29380
30566
  `Failed to register tools for MCP server "${config.tenantId}/${config.key}"`,
29381
30567
  { error: result.reason }
29382
30568
  );
29383
30569
  }
29384
30570
  });
29385
- logger6.info(`MCP connection restoration complete: ${configs.length} servers`);
30571
+ logger7.info(`MCP connection restoration complete: ${configs.length} servers`);
29386
30572
  } catch (err) {
29387
- logger6.error("MCP connection restoration failed", { error: err });
30573
+ logger7.error("MCP connection restoration failed", { error: err });
29388
30574
  }
29389
30575
  }
29390
30576
  var start = async (config) => {
@@ -29397,17 +30583,17 @@ var start = async (config) => {
29397
30583
  file: config.loggerConfig.file || DEFAULT_LOGGER_CONFIG.file
29398
30584
  };
29399
30585
  loggerLattice = initializeLogger(loggerConfig);
29400
- logger6 = loggerLattice.client;
30586
+ logger7 = loggerLattice.client;
29401
30587
  }
29402
30588
  app.decorate("loggerLattice", loggerLattice);
29403
30589
  const projectRoomRealtimeMode = resolveProjectRoomRealtimeMode();
29404
30590
  let projectRoomRealtimeRuntime;
29405
30591
  if (projectRoomRealtimeMode === "single-gateway") {
29406
30592
  projectRoomRealtimeRuntime = createProjectRoomRealtimeRuntime({
29407
- tasks: (0, import_core81.getStoreLattice)("default", "task").store,
29408
- rooms: (0, import_core81.getStoreLattice)("default", "projectRoom").store,
29409
- memberships: (0, import_core81.getStoreLattice)("default", "projectBotMembership").store,
29410
- log: { warn: (message, context) => logger6.warn(message, context) }
30593
+ tasks: (0, import_core82.getStoreLattice)("default", "task").store,
30594
+ rooms: (0, import_core82.getStoreLattice)("default", "projectRoom").store,
30595
+ memberships: (0, import_core82.getStoreLattice)("default", "projectBotMembership").store,
30596
+ log: { warn: (message, context) => logger7.warn(message, context) }
29411
30597
  });
29412
30598
  }
29413
30599
  let channelDeps;
@@ -29420,18 +30606,18 @@ var start = async (config) => {
29420
30606
  const infrastructure = createChannelInfrastructure({
29421
30607
  adapterRegistry,
29422
30608
  getStore: ((kind) => getStore11("default", kind).store),
29423
- trustedDispatcher: (0, import_core81.createTrustedAgentMessageDispatcher)((scope) => import_core81.agentInstanceManager.getAgent(scope)),
30609
+ trustedDispatcher: (0, import_core82.createTrustedAgentMessageDispatcher)((scope) => import_core82.agentInstanceManager.getAgent(scope)),
29424
30610
  middlewares: [
29425
30611
  createDeduplicationMiddleware(),
29426
30612
  createRateLimitMiddleware(),
29427
30613
  createAuditLoggerMiddleware()
29428
30614
  ],
29429
- warn: (message, context) => logger6.warn(message, context),
30615
+ warn: (message, context) => logger7.warn(message, context),
29430
30616
  realtime: projectRoomRealtimeRuntime?.publisher
29431
30617
  });
29432
30618
  const bindingStore = infrastructure.bindingRegistry;
29433
30619
  const installationStore = infrastructure.installationStore;
29434
- (0, import_core80.setBindingRegistry)(bindingStore);
30620
+ (0, import_core81.setBindingRegistry)(bindingStore);
29435
30621
  const router = infrastructure.router;
29436
30622
  app.addHook("onClose", async () => router.dispose());
29437
30623
  channelDeps = {
@@ -29440,18 +30626,18 @@ var start = async (config) => {
29440
30626
  installationStore,
29441
30627
  bindingRegistry: bindingStore,
29442
30628
  realtime: projectRoomRealtimeRuntime?.publisher,
29443
- warn: (message, context) => logger6.warn(message, context)
30629
+ warn: (message, context) => logger7.warn(message, context)
29444
30630
  };
29445
30631
  } catch (err) {
29446
- logger6.warn("Channel infrastructure unavailable", {
30632
+ logger7.warn("Channel infrastructure unavailable", {
29447
30633
  error: err instanceof Error ? err.message : String(err)
29448
30634
  });
29449
30635
  }
29450
- (0, import_core80.setEvalRunService)(evalRunner);
30636
+ (0, import_core81.setEvalRunService)(evalRunner);
29451
30637
  try {
29452
- const menuStore = (0, import_core81.getStoreLattice)("default", "menu").store;
29453
- (0, import_core80.setMenuRegistry)(menuStore);
29454
- logger6.info("Menu registry initialized");
30638
+ const menuStore = (0, import_core82.getStoreLattice)("default", "menu").store;
30639
+ (0, import_core81.setMenuRegistry)(menuStore);
30640
+ logger7.info("Menu registry initialized");
29455
30641
  } catch {
29456
30642
  }
29457
30643
  registerAllBuiltinEntities();
@@ -29460,17 +30646,17 @@ var start = async (config) => {
29460
30646
  }
29461
30647
  const routes = registerLatticeRoutes(app, channelDeps, {
29462
30648
  projectTaskEnabled: process.env.AXIOM_PROJECT_TASK_EXECUTION_ENABLED !== "false",
29463
- projectTaskLog: { warn: (message, context) => logger6.warn(message, context) },
30649
+ projectTaskLog: { warn: (message, context) => logger7.warn(message, context) },
29464
30650
  projectRoomRealtimeRuntime
29465
30651
  });
29466
30652
  try {
29467
30653
  const { A2AAuthService: A2AAuthService2, parseEnvKeys: parseEnvKeys2 } = await Promise.resolve().then(() => (init_A2AAuthService(), A2AAuthService_exports));
29468
30654
  const { registerA2AStandardRoutes: registerA2AStandardRoutes2 } = await Promise.resolve().then(() => (init_a2a_standard(), a2a_standard_exports));
29469
30655
  const a2a = await Promise.resolve().then(() => (init_a2a(), a2a_exports));
29470
- const a2aKeyStore = (0, import_core81.getStoreLattice)("default", "a2aApiKey").store;
29471
- const assistantStore = (0, import_core81.getStoreLattice)("default", "assistant").store;
29472
- const projectStore = (0, import_core81.getStoreLattice)("default", "project").store;
29473
- const taskStore = (0, import_core81.getStoreLattice)("default", "task").store;
30656
+ const a2aKeyStore = (0, import_core82.getStoreLattice)("default", "a2aApiKey").store;
30657
+ const assistantStore = (0, import_core82.getStoreLattice)("default", "assistant").store;
30658
+ const projectStore = (0, import_core82.getStoreLattice)("default", "project").store;
30659
+ const taskStore = (0, import_core82.getStoreLattice)("default", "task").store;
29474
30660
  const authService = new A2AAuthService2({
29475
30661
  keyStore: a2aKeyStore,
29476
30662
  assistantStore,
@@ -29488,9 +30674,9 @@ var start = async (config) => {
29488
30674
  getProjectStore: () => projectStore
29489
30675
  });
29490
30676
  a2a.registerA2ARoutes(app);
29491
- logger6.info("A2A standard routes registered");
30677
+ logger7.info("A2A standard routes registered");
29492
30678
  } catch (err) {
29493
- logger6.warn("A2A standard routes unavailable", {
30679
+ logger7.warn("A2A standard routes unavailable", {
29494
30680
  error: err instanceof Error ? err.message : String(err)
29495
30681
  });
29496
30682
  }
@@ -29509,8 +30695,8 @@ var start = async (config) => {
29509
30695
  const { CollectionService: CollectionService2 } = await Promise.resolve().then(() => (init_collection_service(), collection_service_exports));
29510
30696
  openLattice2.register(createKbProvider2(new CollectionService2()));
29511
30697
  openLattice2.register(createOpenSandboxProvider2());
29512
- const threadStore = (0, import_core81.getStoreLattice)("default", "thread").store;
29513
- const assistantStore = (0, import_core81.getStoreLattice)("default", "assistant").store;
30698
+ const threadStore = (0, import_core82.getStoreLattice)("default", "thread").store;
30699
+ const assistantStore = (0, import_core82.getStoreLattice)("default", "assistant").store;
29514
30700
  openLattice2.register(
29515
30701
  createAgentProvider2({
29516
30702
  threadStore,
@@ -29527,30 +30713,30 @@ var start = async (config) => {
29527
30713
  registerOpenFilesRoutes2(app);
29528
30714
  registerOpenAuditRoutes2(app);
29529
30715
  registerOpenExposureRoutes2(app);
29530
- logger6.info("Open API routes registered (kb + sandbox providers, session exchange)");
30716
+ logger7.info("Open API routes registered (kb + sandbox providers, session exchange)");
29531
30717
  } catch (err) {
29532
- logger6.warn("Open API routes unavailable", {
30718
+ logger7.warn("Open API routes unavailable", {
29533
30719
  error: err instanceof Error ? err.message : String(err)
29534
30720
  });
29535
30721
  }
29536
- if (!import_core81.sandboxLatticeManager.hasLattice("default")) {
29537
- import_core81.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
29538
- logger6.info("Registered sandbox manager from env configuration");
30722
+ if (!import_core82.sandboxLatticeManager.hasLattice("default")) {
30723
+ import_core82.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
30724
+ logger7.info("Registered sandbox manager from env configuration");
29539
30725
  }
29540
30726
  try {
29541
30727
  const { ResourceController: ResourceController2 } = await Promise.resolve().then(() => (init_resources(), resources_exports));
29542
- const sharedResourceStore = (0, import_core81.getStoreLattice)("default", "sharedResource").store;
29543
- const cache = new import_core81.TokenCache();
30728
+ const sharedResourceStore = (0, import_core82.getStoreLattice)("default", "sharedResource").store;
30729
+ const cache = new import_core82.TokenCache();
29544
30730
  const resourceController = new ResourceController2({
29545
30731
  store: sharedResourceStore,
29546
- sandboxManager: import_core81.sandboxLatticeManager,
30732
+ sandboxManager: import_core82.sandboxLatticeManager,
29547
30733
  cache,
29548
- logger: logger6
30734
+ logger: logger7
29549
30735
  });
29550
30736
  registerResourceRoutes(app, resourceController);
29551
- logger6.info("Resource share routes registered");
30737
+ logger7.info("Resource share routes registered");
29552
30738
  } catch (err) {
29553
- logger6.warn("Resource share infrastructure unavailable", {
30739
+ logger7.warn("Resource share infrastructure unavailable", {
29554
30740
  error: err instanceof Error ? err.message : String(err)
29555
30741
  });
29556
30742
  }
@@ -29562,17 +30748,17 @@ var start = async (config) => {
29562
30748
  { deps: { router: channelDeps.router } }
29563
30749
  );
29564
30750
  } catch (err) {
29565
- logger6.error("Failed to start channel connections", {
30751
+ logger7.error("Failed to start channel connections", {
29566
30752
  error: err instanceof Error ? err.message : String(err)
29567
30753
  });
29568
30754
  }
29569
30755
  }
29570
30756
  const target_port = config?.port || Number(process.env.PORT) || 4001;
29571
30757
  if (routes.projectTaskRuntime) {
29572
- await prepareProjectTaskRuntime(routes.projectTaskRuntime, logger6);
30758
+ await prepareProjectTaskRuntime(routes.projectTaskRuntime, logger7);
29573
30759
  }
29574
30760
  await app.listen({ port: target_port, host: "0.0.0.0" });
29575
- logger6.info(`Lattice Gateway is running on port: ${target_port}`);
30761
+ logger7.info(`Lattice Gateway is running on port: ${target_port}`);
29576
30762
  const queueServiceConfig = config?.queueServiceConfig;
29577
30763
  if (queueServiceConfig) {
29578
30764
  setQueueServiceType(queueServiceConfig.type);
@@ -29582,17 +30768,17 @@ var start = async (config) => {
29582
30768
  }
29583
30769
  }
29584
30770
  if (process.env.AXIOM_RESTORE_PENDING_ON_STARTUP === "true") {
29585
- import_core81.agentInstanceManager.restore().then((stats) => {
29586
- logger6.info(`Agent recovery complete: ${stats.restored} threads restored, ${stats.errors} errors`);
30771
+ import_core82.agentInstanceManager.restore().then((stats) => {
30772
+ logger7.info(`Agent recovery complete: ${stats.restored} threads restored, ${stats.errors} errors`);
29587
30773
  }).catch((error) => {
29588
- logger6.error("Agent recovery failed", { error });
30774
+ logger7.error("Agent recovery failed", { error });
29589
30775
  });
29590
30776
  }
29591
30777
  restoreMcpConnections().catch((error) => {
29592
- logger6.error("MCP connection restoration failed", { error });
30778
+ logger7.error("MCP connection restoration failed", { error });
29593
30779
  });
29594
30780
  } catch (err) {
29595
- logger6.error("Server start failed", { error: err });
30781
+ logger7.error("Server start failed", { error: err });
29596
30782
  process.exit(1);
29597
30783
  }
29598
30784
  };