@axiom-lattice/gateway 4.0.0 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -958,6 +958,21 @@ var init_wechat_client = __esm({
958
958
  }
959
959
  });
960
960
 
961
+ // src/services/files/task-file-refs.ts
962
+ function formatFileRefsSection(refs) {
963
+ const lines = refs.map((ref) => {
964
+ const label = ref.name ?? ref.uri;
965
+ const mime = ref.mimeType ? ` (${ref.mimeType})` : "";
966
+ return `- ${label}${mime}: ${ref.uri}`;
967
+ });
968
+ return ["[\u9644\u4EF6]", ...lines].join("\n");
969
+ }
970
+ var init_task_file_refs = __esm({
971
+ "src/services/files/task-file-refs.ts"() {
972
+ "use strict";
973
+ }
974
+ });
975
+
961
976
  // src/channels/wechat/context-store.ts
962
977
  function makeKey(installationId, senderId) {
963
978
  return `${installationId}::${senderId}`;
@@ -1025,18 +1040,18 @@ function extractText(msg) {
1025
1040
  }
1026
1041
  return null;
1027
1042
  }
1028
- var import_zod3, logger4, wechatConfigSchema, MAX_RECONNECT_DELAY_MS, BASE_RECONNECT_DELAY_MS, HEARTBEAT_INTERVAL_MS, MSG_TYPE_USER, MSG_ITEM_TEXT, activeConnections2, seenClientIds, wechatChannelAdapter;
1043
+ var import_zod6, logger4, wechatConfigSchema, MAX_RECONNECT_DELAY_MS, BASE_RECONNECT_DELAY_MS, HEARTBEAT_INTERVAL_MS, MSG_TYPE_USER, MSG_ITEM_TEXT, activeConnections2, seenClientIds, wechatChannelAdapter;
1029
1044
  var init_WechatChannelAdapter = __esm({
1030
1045
  "src/channels/wechat/WechatChannelAdapter.ts"() {
1031
1046
  "use strict";
1032
- import_zod3 = require("zod");
1047
+ import_zod6 = require("zod");
1033
1048
  init_wechat_client();
1034
1049
  init_context_store();
1035
1050
  init_Logger();
1036
1051
  logger4 = new Logger({ serviceName: "lattice/gateway/wechat" });
1037
- wechatConfigSchema = import_zod3.z.object({
1038
- botToken: import_zod3.z.string(),
1039
- uin: import_zod3.z.string().optional()
1052
+ wechatConfigSchema = import_zod6.z.object({
1053
+ botToken: import_zod6.z.string(),
1054
+ uin: import_zod6.z.string().optional()
1040
1055
  });
1041
1056
  MAX_RECONNECT_DELAY_MS = 3e4;
1042
1057
  BASE_RECONNECT_DELAY_MS = 1e3;
@@ -1497,7 +1512,7 @@ function extractFailureReason(task) {
1497
1512
  return extractText2(task.status.message.parts);
1498
1513
  }
1499
1514
  function observationEventKey(task, result, failureReason) {
1500
- const digest = (0, import_node_crypto3.createHash)("sha256").update(JSON.stringify({
1515
+ const digest = (0, import_node_crypto5.createHash)("sha256").update(JSON.stringify({
1501
1516
  state: task.status.state,
1502
1517
  timestamp: task.status.timestamp,
1503
1518
  message: task.status.message,
@@ -1507,7 +1522,7 @@ function observationEventKey(task, result, failureReason) {
1507
1522
  return `a2a-status-observation:${task.id}:${digest}`;
1508
1523
  }
1509
1524
  function snapshotEventKey(task) {
1510
- const digest = (0, import_node_crypto3.createHash)("sha256").update(JSON.stringify(task)).digest("hex");
1525
+ const digest = (0, import_node_crypto5.createHash)("sha256").update(JSON.stringify(task)).digest("hex");
1511
1526
  return `a2a-task-snapshot:${task.id}:${digest}`;
1512
1527
  }
1513
1528
  function isGovernedObservation(state) {
@@ -1519,11 +1534,11 @@ function isA2ATaskSnapshot(value) {
1519
1534
  function snapshotSequence(value) {
1520
1535
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
1521
1536
  }
1522
- var import_node_crypto3, import_node_util, TASK_STATUS_TO_A2A_STATE, TITLE_MAX_LENGTH, A2ATaskScopeConflictError, A2ATaskStoreAdapter;
1537
+ var import_node_crypto5, import_node_util, TASK_STATUS_TO_A2A_STATE, TITLE_MAX_LENGTH, A2ATaskScopeConflictError, A2ATaskStoreAdapter;
1523
1538
  var init_A2ATaskStoreAdapter = __esm({
1524
1539
  "src/services/a2a/A2ATaskStoreAdapter.ts"() {
1525
1540
  "use strict";
1526
- import_node_crypto3 = require("crypto");
1541
+ import_node_crypto5 = require("crypto");
1527
1542
  import_node_util = require("util");
1528
1543
  TASK_STATUS_TO_A2A_STATE = {
1529
1544
  pending: "submitted",
@@ -1842,14 +1857,6 @@ function filePartsToRefs(parts, addedBy) {
1842
1857
  }
1843
1858
  return refs;
1844
1859
  }
1845
- function formatFileRefsSection(refs) {
1846
- const lines = refs.map((ref) => {
1847
- const label = ref.name ?? ref.uri;
1848
- const mime = ref.mimeType ? ` (${ref.mimeType})` : "";
1849
- return `- ${label}${mime}: ${ref.uri}`;
1850
- });
1851
- return ["[\u9644\u4EF6]", ...lines].join("\n");
1852
- }
1853
1860
  async function filePartsToRefsWithIngest(parts, addedBy, ingestor, dedupeKeyBase, projectId) {
1854
1861
  if (!ingestor) {
1855
1862
  return filePartsToRefs(parts, addedBy);
@@ -1866,6 +1873,7 @@ async function filePartsToRefsWithIngest(parts, addedBy, ingestor, dedupeKeyBase
1866
1873
  var init_a2aFileRefs = __esm({
1867
1874
  "src/services/a2a/a2aFileRefs.ts"() {
1868
1875
  "use strict";
1876
+ init_task_file_refs();
1869
1877
  }
1870
1878
  });
1871
1879
 
@@ -1887,14 +1895,15 @@ function agentMessage(text) {
1887
1895
  parts: [{ kind: "text", text }]
1888
1896
  };
1889
1897
  }
1890
- var import_uuid10, import_core54, import_protocols6, _AxiomAgentExecutor, AxiomAgentExecutor;
1898
+ var import_uuid10, import_core55, import_protocols8, _AxiomAgentExecutor, AxiomAgentExecutor;
1891
1899
  var init_AxiomAgentExecutor = __esm({
1892
1900
  "src/services/a2a/AxiomAgentExecutor.ts"() {
1893
1901
  "use strict";
1894
1902
  import_uuid10 = require("uuid");
1895
- import_core54 = require("@axiom-lattice/core");
1896
- import_protocols6 = require("@axiom-lattice/protocols");
1903
+ import_core55 = require("@axiom-lattice/core");
1904
+ import_protocols8 = require("@axiom-lattice/protocols");
1897
1905
  init_a2aFileRefs();
1906
+ init_task_file_refs();
1898
1907
  _AxiomAgentExecutor = class _AxiomAgentExecutor {
1899
1908
  constructor(options) {
1900
1909
  this.scope = options.scope;
@@ -1978,7 +1987,7 @@ var init_AxiomAgentExecutor = __esm({
1978
1987
  await this.taskStore.save(initialTask);
1979
1988
  bus.publish(initialTask);
1980
1989
  try {
1981
- const agent = import_core54.agentInstanceManager.getAgent({
1990
+ const agent = import_core55.agentInstanceManager.getAgent({
1982
1991
  assistant_id: this.scope.assistantId,
1983
1992
  thread_id: threadId,
1984
1993
  tenant_id: this.scope.tenantId,
@@ -2001,16 +2010,16 @@ ${formatFileRefsSection(inputFiles)}` : text;
2001
2010
  custom_run_config: { taskId: ctx.taskId }
2002
2011
  });
2003
2012
  const stream = agent.chunkStream(messageId, [
2004
- import_protocols6.MessageChunkTypes.MESSAGE_COMPLETED
2013
+ import_protocols8.MessageChunkTypes.MESSAGE_COMPLETED
2005
2014
  ]);
2006
2015
  for await (const chunk of stream) {
2007
2016
  if (execution.canceled) return;
2008
2017
  const chunkType = chunk.type;
2009
2018
  const chunkText = chunk.data?.content ?? "";
2010
- if (chunkType === import_protocols6.MessageChunkTypes.INTERRUPT) {
2019
+ if (chunkType === import_protocols8.MessageChunkTypes.INTERRUPT) {
2011
2020
  break;
2012
2021
  }
2013
- if (chunkType === import_protocols6.MessageChunkTypes.AI || chunkType === import_protocols6.MessageChunkTypes.TOOL) {
2022
+ if (chunkType === import_protocols8.MessageChunkTypes.AI || chunkType === import_protocols8.MessageChunkTypes.TOOL) {
2014
2023
  if (chunkText) {
2015
2024
  bus.publish({
2016
2025
  kind: "status-update",
@@ -2128,7 +2137,7 @@ ${formatFileRefsSection(inputFiles)}` : text;
2128
2137
  const threadId = task ? asString2(task.metadata?.threadId) : void 0;
2129
2138
  if (threadId) {
2130
2139
  try {
2131
- const agent = import_core54.agentInstanceManager.getAgent({
2140
+ const agent = import_core55.agentInstanceManager.getAgent({
2132
2141
  assistant_id: this.scope.assistantId,
2133
2142
  thread_id: threadId,
2134
2143
  tenant_id: this.scope.tenantId,
@@ -2490,13 +2499,13 @@ function isAsyncGenerator(value) {
2490
2499
  }
2491
2500
  function registerA2AStandardRoutes(app2, deps) {
2492
2501
  const authService = deps.authService;
2493
- const getTaskStore = deps.getTaskStoreLattice ?? (() => (0, import_core55.getStoreLattice)("default", "task").store);
2494
- const getTaskWorkItemStore2 = deps.getTaskWorkItemStore ?? (() => (0, import_core55.getStoreLattice)("default", "taskWorkItem").store);
2495
- const getAssistantStore3 = deps.getAssistantStore ?? (() => (0, import_core55.getStoreLattice)("default", "assistant").store);
2496
- const getProjectStore2 = deps.getProjectStore ?? (() => (0, import_core55.getStoreLattice)("default", "project").store);
2502
+ const getTaskStore = deps.getTaskStoreLattice ?? (() => (0, import_core56.getStoreLattice)("default", "task").store);
2503
+ const getTaskWorkItemStore2 = deps.getTaskWorkItemStore ?? (() => (0, import_core56.getStoreLattice)("default", "taskWorkItem").store);
2504
+ const getAssistantStore3 = deps.getAssistantStore ?? (() => (0, import_core56.getStoreLattice)("default", "assistant").store);
2505
+ const getProjectStore2 = deps.getProjectStore ?? (() => (0, import_core56.getStoreLattice)("default", "project").store);
2497
2506
  const getTenantStore = deps.getTenantStore ?? (() => {
2498
2507
  try {
2499
- return (0, import_core55.getStoreLattice)("default", "tenant").store;
2508
+ return (0, import_core56.getStoreLattice)("default", "tenant").store;
2500
2509
  } catch {
2501
2510
  return void 0;
2502
2511
  }
@@ -2588,7 +2597,7 @@ function registerA2AStandardRoutes(app2, deps) {
2588
2597
  const taskStore = new A2ATaskStoreAdapter({
2589
2598
  taskStore: internalTaskStore,
2590
2599
  workItemStore,
2591
- lifecycle: (0, import_core55.createTaskLifecycleService)({
2600
+ lifecycle: (0, import_core56.createTaskLifecycleService)({
2592
2601
  taskStore: internalTaskStore,
2593
2602
  workItemStore
2594
2603
  }),
@@ -2707,7 +2716,7 @@ data: ${JSON.stringify(errorResponse)}
2707
2716
  const taskStore = new A2ATaskStoreAdapter({
2708
2717
  taskStore: internalTaskStore,
2709
2718
  workItemStore,
2710
- lifecycle: (0, import_core55.createTaskLifecycleService)({
2719
+ lifecycle: (0, import_core56.createTaskLifecycleService)({
2711
2720
  taskStore: internalTaskStore,
2712
2721
  workItemStore
2713
2722
  }),
@@ -2752,13 +2761,13 @@ data: ${JSON.stringify(data)}
2752
2761
  }
2753
2762
  );
2754
2763
  }
2755
- var import_uuid11, import_server2, import_core55, SSE_HEADERS;
2764
+ var import_uuid11, import_server2, import_core56, SSE_HEADERS;
2756
2765
  var init_a2a_standard = __esm({
2757
2766
  "src/routes/a2a-standard.ts"() {
2758
2767
  "use strict";
2759
2768
  import_uuid11 = require("uuid");
2760
2769
  import_server2 = require("@a2a-js/sdk/server");
2761
- import_core55 = require("@axiom-lattice/core");
2770
+ import_core56 = require("@axiom-lattice/core");
2762
2771
  init_A2AAuthService();
2763
2772
  init_A2AAgentCardBuilder();
2764
2773
  init_A2ATaskStoreAdapter();
@@ -2932,12 +2941,12 @@ var resources_exports = {};
2932
2941
  __export(resources_exports, {
2933
2942
  ResourceController: () => ResourceController
2934
2943
  });
2935
- var import_bcryptjs, import_core56, ResourceController;
2944
+ var import_bcryptjs, import_core57, ResourceController;
2936
2945
  var init_resources = __esm({
2937
2946
  "src/controllers/resources.ts"() {
2938
2947
  "use strict";
2939
2948
  import_bcryptjs = __toESM(require("bcryptjs"));
2940
- import_core56 = require("@axiom-lattice/core");
2949
+ import_core57 = require("@axiom-lattice/core");
2941
2950
  init_mime();
2942
2951
  ResourceController = class {
2943
2952
  constructor(deps) {
@@ -2952,14 +2961,14 @@ var init_resources = __esm({
2952
2961
  if (!workspaceId || !projectId) {
2953
2962
  return reply.status(400).send({ error: "x-workspace-id and x-project-id headers required" });
2954
2963
  }
2955
- const payload = (0, import_core56.createSharePayload)(
2964
+ const payload = (0, import_core57.createSharePayload)(
2956
2965
  tenantId,
2957
2966
  workspaceId,
2958
2967
  projectId,
2959
2968
  userId,
2960
2969
  body
2961
2970
  );
2962
- const token = (0, import_core56.generateToken)();
2971
+ const token = (0, import_core57.generateToken)();
2963
2972
  try {
2964
2973
  await this.deps.store.create({ ...payload, token });
2965
2974
  this.deps.logger.info(
@@ -3111,7 +3120,7 @@ var init_resources = __esm({
3111
3120
  resourcePath: subPath
3112
3121
  }, subPath, ext, request, reply);
3113
3122
  }
3114
- const volume = (0, import_core56.buildNamedVolumeName)("p", "project", tenantId, workspaceId, projectId);
3123
+ const volume = (0, import_core57.buildNamedVolumeName)("p", "project", tenantId, workspaceId, projectId);
3115
3124
  return this._resolveAndServe(
3116
3125
  volume,
3117
3126
  subPath,
@@ -4098,6 +4107,90 @@ async function getAssistantStats(request, reply) {
4098
4107
  var import_uuid = require("uuid");
4099
4108
  var import_core3 = require("@axiom-lattice/core");
4100
4109
  var import_protocols2 = require("@axiom-lattice/protocols");
4110
+
4111
+ // src/services/agents/ScopedAgentExecution.ts
4112
+ async function executeScopedAgentMessage(agent, request, stopTypes, options) {
4113
+ const { messageId } = options === void 0 ? await agent.addMessage(request) : await agent.addMessage(request, options.queueMode);
4114
+ return { messageId, stream: agent.chunkStream(messageId, stopTypes) };
4115
+ }
4116
+
4117
+ // src/services/streaming/pipeAsyncIterableToSse.ts
4118
+ async function pipeAsyncIterableToSse(raw, stream, options = {}) {
4119
+ const iterator = stream[Symbol.asyncIterator]();
4120
+ const project = options.project ?? ((value) => [value]);
4121
+ const serialize = options.serialize ?? ((event) => `data: ${JSON.stringify(event)}
4122
+
4123
+ `);
4124
+ const closeSources = options.closeSource && options.closeSource !== raw ? [raw, options.closeSource] : [raw];
4125
+ let closed = raw.destroyed || raw.writableEnded;
4126
+ let returned = false;
4127
+ let resolveClosed;
4128
+ const closedPromise = new Promise((resolve3) => {
4129
+ resolveClosed = resolve3;
4130
+ });
4131
+ const returnConsumer = () => {
4132
+ if (returned) return;
4133
+ returned = true;
4134
+ void Promise.resolve(iterator.return?.()).catch(() => void 0);
4135
+ };
4136
+ const onClose = () => {
4137
+ closed = true;
4138
+ returnConsumer();
4139
+ resolveClosed?.();
4140
+ };
4141
+ for (const source of closeSources) {
4142
+ source.on("close", onClose);
4143
+ source.on("error", onClose);
4144
+ }
4145
+ try {
4146
+ while (!closed) {
4147
+ const next = await Promise.race([
4148
+ iterator.next().then((result) => ({ kind: "next", result })),
4149
+ closedPromise.then(() => ({ kind: "closed" }))
4150
+ ]);
4151
+ if (next.kind === "closed" || next.result.done) break;
4152
+ for (const event of project(next.result.value)) {
4153
+ if (!await writeSse(raw, serialize(event), closedPromise)) {
4154
+ closed = true;
4155
+ returnConsumer();
4156
+ break;
4157
+ }
4158
+ }
4159
+ }
4160
+ } catch (error) {
4161
+ if (!options.onError) throw error;
4162
+ if (!closed && !raw.destroyed && !raw.writableEnded) {
4163
+ for (const event of options.onError(error)) {
4164
+ if (!await writeSse(raw, serialize(event), closedPromise)) break;
4165
+ }
4166
+ }
4167
+ returnConsumer();
4168
+ } finally {
4169
+ for (const source of closeSources) {
4170
+ source.removeListener("close", onClose);
4171
+ source.removeListener("error", onClose);
4172
+ }
4173
+ if (!closed && !raw.destroyed && !raw.writableEnded) raw.end();
4174
+ }
4175
+ }
4176
+ async function writeSse(raw, value, closed) {
4177
+ if (raw.destroyed || raw.writableEnded) return false;
4178
+ if (raw.write(value)) return true;
4179
+ return new Promise((resolve3) => {
4180
+ let settled = false;
4181
+ const onDrain = () => finish(!raw.destroyed && !raw.writableEnded);
4182
+ const finish = (writable) => {
4183
+ if (settled) return;
4184
+ settled = true;
4185
+ raw.removeListener("drain", onDrain);
4186
+ resolve3(writable);
4187
+ };
4188
+ raw.once("drain", onDrain);
4189
+ void closed.then(() => finish(false));
4190
+ });
4191
+ }
4192
+
4193
+ // src/controllers/run.ts
4101
4194
  function getUserId2(request) {
4102
4195
  const authUser = request.user;
4103
4196
  if (authUser?.id) return authUser.id;
@@ -4164,20 +4257,22 @@ var createRun = async (request, reply) => {
4164
4257
  });
4165
4258
  try {
4166
4259
  const messageInput = message_id ? { ...input, id: message_id } : input;
4167
- const result = await agent.addMessage({
4260
+ const result = await executeScopedAgentMessage(agent, {
4168
4261
  input: messageInput,
4169
4262
  command,
4170
4263
  custom_run_config: mergedConfig
4171
- }, mode);
4172
- const stream = agent.chunkStream(result.messageId, [import_protocols2.MessageChunkTypes.MESSAGE_COMPLETED, import_protocols2.MessageChunkTypes.INTERRUPT, import_protocols2.MessageChunkTypes.MESSAGE_FAILED]);
4173
- for await (const chunk of stream) {
4174
- const success = reply.raw.write(`data: ${JSON.stringify(chunk)}
4175
-
4176
- `);
4177
- if (!success) {
4178
- await new Promise((resolve3) => reply.raw.once("drain", resolve3));
4179
- }
4180
- }
4264
+ }, [import_protocols2.MessageChunkTypes.MESSAGE_COMPLETED, import_protocols2.MessageChunkTypes.INTERRUPT, import_protocols2.MessageChunkTypes.MESSAGE_FAILED], {
4265
+ queueMode: mode
4266
+ });
4267
+ await pipeAsyncIterableToSse(reply.raw, result.stream, {
4268
+ onError: (error) => [{
4269
+ type: "error",
4270
+ data: {
4271
+ id: (0, import_uuid.v4)(),
4272
+ content: error instanceof Error ? error.message : "Stream processing error"
4273
+ }
4274
+ }]
4275
+ });
4181
4276
  } catch (error) {
4182
4277
  const errorEvent = {
4183
4278
  type: "error",
@@ -4190,7 +4285,7 @@ var createRun = async (request, reply) => {
4190
4285
 
4191
4286
  `);
4192
4287
  } finally {
4193
- reply.raw.end();
4288
+ if (!reply.raw.writableEnded && !reply.raw.destroyed) reply.raw.end();
4194
4289
  }
4195
4290
  } else {
4196
4291
  const { message: msg, ...restInputNonStream } = input;
@@ -4239,17 +4334,16 @@ var resumeStream = async (request, reply) => {
4239
4334
  workspace_id,
4240
4335
  project_id
4241
4336
  });
4242
- const stream = agent.chunkStream(message_id, []);
4243
- let closed = false;
4244
- request.raw.on("close", () => {
4245
- closed = true;
4337
+ await pipeAsyncIterableToSse(reply.raw, agent.chunkStream(message_id, []), {
4338
+ closeSource: request.raw,
4339
+ onError: (error) => [{
4340
+ type: "error",
4341
+ data: {
4342
+ id: (0, import_uuid.v4)(),
4343
+ content: error instanceof Error ? error.message : "Resume stream processing error"
4344
+ }
4345
+ }]
4246
4346
  });
4247
- for await (const chunk of stream) {
4248
- if (closed || reply.raw.destroyed) break;
4249
- reply.raw.write(`data: ${JSON.stringify(chunk)}
4250
-
4251
- `);
4252
- }
4253
4347
  } catch (error) {
4254
4348
  const errorEvent = {
4255
4349
  type: "error",
@@ -4262,7 +4356,7 @@ var resumeStream = async (request, reply) => {
4262
4356
 
4263
4357
  `);
4264
4358
  } finally {
4265
- reply.raw.end();
4359
+ if (!reply.raw.writableEnded && !reply.raw.destroyed) reply.raw.end();
4266
4360
  }
4267
4361
  } catch (error) {
4268
4362
  reply.status(500).send({
@@ -6712,6 +6806,7 @@ async function deletePersonalAssistant(request, reply) {
6712
6806
  if (!deleted) {
6713
6807
  return reply.status(500).send({ success: false, message: "Failed to delete personal assistant" });
6714
6808
  }
6809
+ import_core16.eventBus.publish("assistant:deleted", { id: assistant.id, tenantId });
6715
6810
  const threadStore = (0, import_core16.getStoreLattice)("default", "thread").store;
6716
6811
  try {
6717
6812
  const threads = await threadStore.getThreadsByAssistantId(tenantId, assistant.id);
@@ -10161,11 +10256,11 @@ async function createProject(request, reply) {
10161
10256
  }
10162
10257
  const serverCfg = data.targetServerConfig || {};
10163
10258
  const judgeCfg = data.judgeModelConfig || {};
10164
- const modelKey = judgeCfg.modelKey || "";
10165
- if (modelKey) {
10166
- const { modelLatticeManager: modelLatticeManager3 } = await import("@axiom-lattice/core");
10167
- if (!modelLatticeManager3.hasLattice(modelKey)) {
10168
- return reply.status(400).send({ success: false, message: `Judge model "${modelKey}" is not registered` });
10259
+ const modelKey2 = judgeCfg.modelKey || "";
10260
+ if (modelKey2) {
10261
+ const { modelLatticeManager: modelLatticeManager4 } = await import("@axiom-lattice/core");
10262
+ if (!modelLatticeManager4.hasLattice(modelKey2)) {
10263
+ return reply.status(400).send({ success: false, message: `Judge model "${modelKey2}" is not registered` });
10169
10264
  }
10170
10265
  }
10171
10266
  const project = await store2.createProject(tenantId, id, {
@@ -10173,7 +10268,7 @@ async function createProject(request, reply) {
10173
10268
  description: data.description,
10174
10269
  version: data.version,
10175
10270
  judgeModelConfig: {
10176
- modelKey,
10271
+ modelKey: modelKey2,
10177
10272
  displayName: judgeCfg.displayName || ""
10178
10273
  },
10179
10274
  targetServerConfig: {
@@ -10210,8 +10305,8 @@ async function listProjects(request, reply) {
10210
10305
  let projects = await store2.getProjectsByTenant(tenantId);
10211
10306
  if (projects.length === 0) {
10212
10307
  try {
10213
- const { modelLatticeManager: modelLatticeManager3 } = await import("@axiom-lattice/core");
10214
- const models = modelLatticeManager3.getAllLattices();
10308
+ const { modelLatticeManager: modelLatticeManager4 } = await import("@axiom-lattice/core");
10309
+ const models = modelLatticeManager4.getAllLattices();
10215
10310
  const first = models[0];
10216
10311
  const judgeModel = first ? { modelKey: first.key } : {};
10217
10312
  const host = request.hostname || "localhost";
@@ -10277,15 +10372,15 @@ async function updateProject(request, reply) {
10277
10372
  }
10278
10373
  if (body.judgeModelConfig !== void 0) {
10279
10374
  const judgeCfg = body.judgeModelConfig || {};
10280
- const modelKey = judgeCfg.modelKey || "";
10281
- if (modelKey) {
10282
- const { modelLatticeManager: modelLatticeManager3 } = await import("@axiom-lattice/core");
10283
- if (!modelLatticeManager3.hasLattice(modelKey)) {
10284
- return reply.status(400).send({ success: false, message: `Judge model "${modelKey}" is not registered` });
10375
+ const modelKey2 = judgeCfg.modelKey || "";
10376
+ if (modelKey2) {
10377
+ const { modelLatticeManager: modelLatticeManager4 } = await import("@axiom-lattice/core");
10378
+ if (!modelLatticeManager4.hasLattice(modelKey2)) {
10379
+ return reply.status(400).send({ success: false, message: `Judge model "${modelKey2}" is not registered` });
10285
10380
  }
10286
10381
  }
10287
10382
  updateData.judgeModelConfig = {
10288
- modelKey,
10383
+ modelKey: modelKey2,
10289
10384
  displayName: judgeCfg.displayName || ""
10290
10385
  };
10291
10386
  }
@@ -11148,6 +11243,8 @@ function extractUserFromAuthHeader(authHeader, secret) {
11148
11243
  var PUBLIC_ROUTES = ["/api/auth/login", "/api/auth/register", "/health", "/api/stt/models"];
11149
11244
  function bypassesConsoleAuth(request) {
11150
11245
  const path6 = request.url.split("?")[0];
11246
+ const method = request.method;
11247
+ if (method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/bootstrap$/.test(path6) || (method === "GET" || method === "POST") && /^\/api\/web-apps\/[^/]+\/runtime\/threads$/.test(path6) || (method === "PATCH" || method === "DELETE") && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+$/.test(path6) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/messages$/.test(path6) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/(messages\/stream|abort|attachments)$/.test(path6) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/interrupts\/[^/]+\/resume$/.test(path6)) return true;
11151
11248
  if (request.method === "GET" && /^\/api\/a2a\/agents\/[^/]+\/\.well-known\/agent-card\.json$/.test(path6)) {
11152
11249
  return true;
11153
11250
  }
@@ -11155,13 +11252,13 @@ function bypassesConsoleAuth(request) {
11155
11252
  }
11156
11253
  function registerConsoleAuthHook(app2, options) {
11157
11254
  app2.addHook("preHandler", async (request, reply) => {
11158
- if (bypassesConsoleAuth(request)) return;
11159
11255
  const secret = options.tokenSecret ?? resolveConsoleTokenSecret(options.authRequired);
11160
11256
  const user = extractUserFromAuthHeader(request.headers.authorization, secret);
11161
11257
  if (user) {
11162
11258
  request.user = user;
11163
- return;
11164
11259
  }
11260
+ if (bypassesConsoleAuth(request)) return;
11261
+ if (user) return;
11165
11262
  if (!options.authRequired || request.method === "OPTIONS") return;
11166
11263
  if (PUBLIC_ROUTES.some((route) => request.url === route)) return;
11167
11264
  if (request.url.startsWith("/s/")) return;
@@ -11561,8 +11658,8 @@ function snapshotPlainObject(value) {
11561
11658
  }
11562
11659
  }
11563
11660
  async function getInstallationStore() {
11564
- const { getStoreLattice: getStoreLattice30 } = await import("@axiom-lattice/core");
11565
- const store2 = getStoreLattice30("default", "channelInstallation").store;
11661
+ const { getStoreLattice: getStoreLattice31 } = await import("@axiom-lattice/core");
11662
+ const store2 = getStoreLattice31("default", "channelInstallation").store;
11566
11663
  if (store2) return store2;
11567
11664
  const { PostgreSQLChannelInstallationStore } = await import("@axiom-lattice/pg-stores");
11568
11665
  const databaseUrl = process.env.DATABASE_URL;
@@ -12258,7 +12355,7 @@ var registerSTTRoutes = (app2) => {
12258
12355
  }
12259
12356
  },
12260
12357
  async (request, reply) => {
12261
- const modelKey = request.query.model || "default";
12358
+ const modelKey2 = request.query.model || "default";
12262
12359
  const data = await request.file({
12263
12360
  limits: { fileSize: MAX_AUDIO_FILE_SIZE }
12264
12361
  });
@@ -12276,9 +12373,9 @@ var registerSTTRoutes = (app2) => {
12276
12373
  try {
12277
12374
  let client;
12278
12375
  try {
12279
- client = (0, import_core38.getSTTClient)(modelKey);
12376
+ client = (0, import_core38.getSTTClient)(modelKey2);
12280
12377
  } catch {
12281
- return reply.status(404).send({ error: `STT model "${modelKey}" not found` });
12378
+ return reply.status(404).send({ error: `STT model "${modelKey2}" not found` });
12282
12379
  }
12283
12380
  const result = await client.transcribe(buffer, format);
12284
12381
  return reply.send({
@@ -12689,8 +12786,10 @@ async function createTask(request, reply) {
12689
12786
  const ownerType = body.ownerType || "user";
12690
12787
  const ownerId = body.ownerId || userId;
12691
12788
  if (ownerType === "agent") {
12789
+ (0, import_core40.ensureBuiltinAgentsForTenant)(tenantId);
12692
12790
  const assistant = await getAssistantStore2().getAssistantById(tenantId, ownerId);
12693
- if (!assistant || assistant.tenantId !== tenantId) {
12791
+ const configuredAgent = import_core40.agentLatticeManager.getAgentConfigWithTenant(tenantId, ownerId);
12792
+ if ((!assistant || assistant.tenantId !== tenantId) && !configuredAgent) {
12694
12793
  return reply.status(404).send({
12695
12794
  success: false,
12696
12795
  code: "AGENT_OWNER_NOT_FOUND",
@@ -12839,7 +12938,1032 @@ function registerTaskRoutes(app2) {
12839
12938
  }
12840
12939
 
12841
12940
  // src/routes/index.ts
12941
+ var import_core41 = require("@axiom-lattice/core");
12942
+
12943
+ // src/services/agent-web-app/AgentWebAppService.ts
12944
+ function createConfiguredAgentResolver(registry) {
12945
+ return {
12946
+ async exists(tenantId, assistantId) {
12947
+ await registry.hydrate(tenantId);
12948
+ return registry.has(tenantId, assistantId);
12949
+ }
12950
+ };
12951
+ }
12952
+ var AgentWebAppError = class extends Error {
12953
+ constructor(code, statusCode, message) {
12954
+ super(message);
12955
+ this.code = code;
12956
+ this.statusCode = statusCode;
12957
+ this.name = "AgentWebAppError";
12958
+ }
12959
+ };
12960
+ var AgentWebAppService = class {
12961
+ constructor(deps) {
12962
+ this.deps = deps;
12963
+ }
12964
+ async create(context, input) {
12965
+ await this.validateAssistant(context, input.assistantId);
12966
+ const normalized = await this.validateConfig(context.tenantId, input);
12967
+ return this.deps.webAppStore.create(context.tenantId, normalized);
12968
+ }
12969
+ async list(context, assistantId) {
12970
+ const records = await this.deps.webAppStore.list(context.tenantId, assistantId);
12971
+ const visible = [];
12972
+ for (const record of records) {
12973
+ if (await this.canAccessAssistant(context, record.assistantId)) visible.push(record);
12974
+ }
12975
+ return visible;
12976
+ }
12977
+ async get(context, webAppId) {
12978
+ return this.requireAuthorizedWebApp(context, webAppId);
12979
+ }
12980
+ async update(context, webAppId, patch) {
12981
+ const current = await this.requireAuthorizedWebApp(context, webAppId);
12982
+ const effective = {
12983
+ assistantId: current.assistantId,
12984
+ name: patch.name ?? current.name,
12985
+ description: Object.prototype.hasOwnProperty.call(patch, "description") ? patch.description : current.description,
12986
+ integration: current.integration,
12987
+ scope: { ...current.scope, ...patch.scope },
12988
+ features: { ...current.features, ...patch.features },
12989
+ appearance: { ...current.appearance, ...patch.appearance }
12990
+ };
12991
+ await this.validateAssistant(context, current.assistantId);
12992
+ const validated = await this.validateConfig(context.tenantId, effective);
12993
+ const update = {
12994
+ ...patch.name !== void 0 ? { name: validated.name } : {},
12995
+ ...Object.prototype.hasOwnProperty.call(patch, "description") ? { description: validated.description } : {},
12996
+ ...patch.scope ? { scope: validated.scope } : {},
12997
+ ...patch.features ? { features: validated.features } : {},
12998
+ ...patch.appearance ? { appearance: validated.appearance } : {}
12999
+ };
13000
+ return this.writeSnapshot(context, current, update);
13001
+ }
13002
+ async enable(context, webAppId) {
13003
+ const current = await this.requireAuthorizedWebApp(context, webAppId);
13004
+ await this.validateConfig(context.tenantId, current);
13005
+ return this.writeSnapshot(context, current, { status: "active" });
13006
+ }
13007
+ async disable(context, webAppId) {
13008
+ const current = await this.requireAuthorizedWebApp(context, webAppId);
13009
+ return this.writeSnapshot(context, current, { status: "disabled" });
13010
+ }
13011
+ async delete(context, webAppId) {
13012
+ await this.requireAuthorizedWebApp(context, webAppId);
13013
+ if (!await this.deps.webAppStore.delete(context.tenantId, webAppId)) this.notFound();
13014
+ }
13015
+ async validateAssistant(context, assistantId) {
13016
+ const assistant = await this.deps.assistantStore.getAssistantById(context.tenantId, assistantId);
13017
+ if (assistant) {
13018
+ if (assistant.ownerUserId && assistant.ownerUserId !== context.userId) {
13019
+ throw new AgentWebAppError("ASSISTANT_FORBIDDEN", 403, "Assistant is not available to this user");
13020
+ }
13021
+ return;
13022
+ }
13023
+ if (await this.deps.configuredAgentResolver.exists(context.tenantId, assistantId)) return;
13024
+ throw new AgentWebAppError("ASSISTANT_NOT_FOUND", 404, "Assistant not found");
13025
+ }
13026
+ async validateConfig(tenantId, input) {
13027
+ const allowedProjectIds = [...new Set(input.scope.allowedProjectIds)];
13028
+ if (!allowedProjectIds.length || !allowedProjectIds.includes(input.scope.defaultProjectId)) {
13029
+ throw new AgentWebAppError("PROJECT_SCOPE_INVALID", 400, "Default project must be in the project allowlist");
13030
+ }
13031
+ if (!input.features.projectSelector && allowedProjectIds.length !== 1) {
13032
+ throw new AgentWebAppError("PROJECT_SCOPE_INVALID", 400, "Disabled project selection requires exactly one project");
13033
+ }
13034
+ for (const projectId of allowedProjectIds) {
13035
+ if (!await this.deps.projectStore.getProjectById(tenantId, projectId)) {
13036
+ throw new AgentWebAppError("PROJECT_NOT_FOUND", 404, "Project not found");
13037
+ }
13038
+ }
13039
+ const scope = this.validateModels(input.scope, input.features.modelSelector);
13040
+ return { ...input, scope: { ...scope, allowedProjectIds } };
13041
+ }
13042
+ validateModels(scope, modelSelector) {
13043
+ const allowedModelKeys = scope.allowedModelKeys ? [...new Set(scope.allowedModelKeys)] : void 0;
13044
+ if (!allowedModelKeys?.length) {
13045
+ if (scope.defaultModelKey || modelSelector) {
13046
+ throw new AgentWebAppError("MODEL_SCOPE_INVALID", 400, "Agent-default models cannot enable model selection or set a default");
13047
+ }
13048
+ return { ...scope, defaultModelKey: void 0, allowedModelKeys: void 0 };
13049
+ }
13050
+ if (!modelSelector && allowedModelKeys.length > 1) {
13051
+ throw new AgentWebAppError("MODEL_SCOPE_INVALID", 400, "Disabled model selection allows at most one model");
13052
+ }
13053
+ if (scope.defaultModelKey && !allowedModelKeys.includes(scope.defaultModelKey)) {
13054
+ throw new AgentWebAppError("MODEL_SCOPE_INVALID", 400, "Default model must be in the model allowlist");
13055
+ }
13056
+ for (const key of allowedModelKeys) {
13057
+ if (!this.deps.modelRegistry.has(key)) {
13058
+ throw new AgentWebAppError("MODEL_NOT_FOUND", 400, "Configured model is not registered");
13059
+ }
13060
+ }
13061
+ return { ...scope, allowedModelKeys };
13062
+ }
13063
+ async requireWebApp(tenantId, webAppId) {
13064
+ return await this.deps.webAppStore.getById(tenantId, webAppId) ?? this.notFound();
13065
+ }
13066
+ async requireAuthorizedWebApp(context, webAppId) {
13067
+ const webApp = await this.requireWebApp(context.tenantId, webAppId);
13068
+ if (!await this.canAccessAssistant(context, webApp.assistantId)) this.notFound();
13069
+ return webApp;
13070
+ }
13071
+ async canAccessAssistant(context, assistantId) {
13072
+ const assistant = await this.deps.assistantStore.getAssistantById(context.tenantId, assistantId);
13073
+ if (assistant) return !assistant.ownerUserId || assistant.ownerUserId === context.userId;
13074
+ return this.deps.configuredAgentResolver.exists(context.tenantId, assistantId);
13075
+ }
13076
+ async writeSnapshot(context, current, patch) {
13077
+ const updated = await this.deps.webAppStore.update(
13078
+ context.tenantId,
13079
+ current.id,
13080
+ patch,
13081
+ { expectedUpdatedAt: current.updatedAt }
13082
+ );
13083
+ if (updated) return updated;
13084
+ await this.requireAuthorizedWebApp(context, current.id);
13085
+ throw new AgentWebAppError("WEB_APP_CONFLICT", 409, "Agent Web App was modified concurrently");
13086
+ }
13087
+ notFound() {
13088
+ throw new AgentWebAppError("WEB_APP_NOT_FOUND", 404, "Agent Web App not found");
13089
+ }
13090
+ };
13091
+
13092
+ // src/routes/agent-web-apps.ts
13093
+ var import_zod4 = require("zod");
13094
+
13095
+ // src/schemas/agent-web-app.ts
13096
+ var import_zod3 = require("zod");
13097
+ var externalId = import_zod3.z.string().min(1).max(128).regex(/^[A-Za-z0-9._:@-]+$/);
13098
+ var modelKey = import_zod3.z.string().min(1).max(128);
13099
+ var agentWebAppScopeSchema = import_zod3.z.object({
13100
+ defaultProjectId: externalId,
13101
+ allowedProjectIds: import_zod3.z.array(externalId).min(1).max(100),
13102
+ defaultModelKey: modelKey.optional(),
13103
+ allowedModelKeys: import_zod3.z.array(modelKey).max(100).optional()
13104
+ }).strict();
13105
+ var agentWebAppFeaturesSchema = import_zod3.z.object({
13106
+ projectSelector: import_zod3.z.boolean(),
13107
+ modelSelector: import_zod3.z.boolean(),
13108
+ threadManagement: import_zod3.z.boolean(),
13109
+ attachments: import_zod3.z.boolean(),
13110
+ hitl: import_zod3.z.boolean(),
13111
+ genUI: import_zod3.z.boolean()
13112
+ }).strict();
13113
+ var agentWebAppAppearanceSchema = import_zod3.z.object({
13114
+ title: import_zod3.z.string().max(120).optional(),
13115
+ welcomeMessage: import_zod3.z.string().max(1e3).optional(),
13116
+ primaryColor: import_zod3.z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional()
13117
+ }).strict();
13118
+ var createAgentWebAppSchema = import_zod3.z.object({
13119
+ assistantId: externalId,
13120
+ name: import_zod3.z.string().min(1).max(120),
13121
+ description: import_zod3.z.string().max(1e3).optional(),
13122
+ integration: import_zod3.z.object({ type: import_zod3.z.literal("react_sdk") }).strict(),
13123
+ scope: agentWebAppScopeSchema,
13124
+ features: agentWebAppFeaturesSchema,
13125
+ appearance: agentWebAppAppearanceSchema
13126
+ }).strict();
13127
+ var updateAgentWebAppSchema = import_zod3.z.object({
13128
+ name: import_zod3.z.string().min(1).max(120).optional(),
13129
+ description: import_zod3.z.string().max(1e3).optional(),
13130
+ scope: agentWebAppScopeSchema.partial().strict().optional(),
13131
+ features: agentWebAppFeaturesSchema.partial().strict().optional(),
13132
+ appearance: agentWebAppAppearanceSchema.partial().strict().optional()
13133
+ }).strict().refine((value) => Object.keys(value).length > 0, "Patch must not be empty");
13134
+ var listAgentWebAppsQuerySchema = import_zod3.z.object({
13135
+ assistantId: externalId.optional()
13136
+ }).strict();
13137
+
13138
+ // src/routes/agent-web-apps.ts
13139
+ function registerAgentWebAppRoutes(app2, deps) {
13140
+ app2.register(async (routes) => {
13141
+ routes.setErrorHandler((error, _request, reply) => normalizeError(reply, error));
13142
+ registerScopedRoutes(routes, deps.service);
13143
+ });
13144
+ }
13145
+ function registerScopedRoutes(app2, service2) {
13146
+ app2.post("/api/web-apps", async (request, reply) => handle(reply, async () => ({
13147
+ statusCode: 201,
13148
+ data: await service2.create(requireContext(request), createAgentWebAppSchema.parse(request.body))
13149
+ })));
13150
+ app2.get("/api/web-apps", async (request, reply) => handle(reply, async () => {
13151
+ const context = requireContext(request);
13152
+ const query = listAgentWebAppsQuerySchema.parse(request.query);
13153
+ const records = await service2.list(context, query.assistantId);
13154
+ return { data: { records, total: records.length } };
13155
+ }));
13156
+ app2.get("/api/web-apps/:webAppId", async (request, reply) => handle(reply, async () => ({ data: await service2.get(requireContext(request), request.params.webAppId) })));
13157
+ app2.patch("/api/web-apps/:webAppId", async (request, reply) => handle(reply, async () => ({
13158
+ data: await service2.update(
13159
+ requireContext(request),
13160
+ request.params.webAppId,
13161
+ updateAgentWebAppSchema.parse(request.body)
13162
+ )
13163
+ })));
13164
+ app2.post("/api/web-apps/:webAppId/enable", async (request, reply) => handle(reply, async () => ({ data: await service2.enable(requireContext(request), request.params.webAppId) })));
13165
+ app2.post("/api/web-apps/:webAppId/disable", async (request, reply) => handle(reply, async () => ({ data: await service2.disable(requireContext(request), request.params.webAppId) })));
13166
+ app2.delete("/api/web-apps/:webAppId", async (request, reply) => handle(reply, async () => {
13167
+ await service2.delete(requireContext(request), request.params.webAppId);
13168
+ return { data: { id: request.params.webAppId } };
13169
+ }));
13170
+ }
13171
+ function requireContext(request) {
13172
+ const user = request.user;
13173
+ const userId = user?.id ?? user?.userId;
13174
+ if (!userId || !user?.tenantId) {
13175
+ throw new AgentWebAppError("UNAUTHORIZED", 401, "Console session required");
13176
+ }
13177
+ return { tenantId: user.tenantId, userId };
13178
+ }
13179
+ async function handle(reply, operation) {
13180
+ try {
13181
+ const result = await operation();
13182
+ return reply.code(result.statusCode ?? 200).send({ success: true, data: result.data });
13183
+ } catch (error) {
13184
+ if (error instanceof import_zod4.ZodError) {
13185
+ return invalidRequest(reply, 400);
13186
+ }
13187
+ if (error instanceof AgentWebAppError) {
13188
+ return reply.code(error.statusCode).send({
13189
+ success: false,
13190
+ error: { code: error.code, message: error.message, retryable: false }
13191
+ });
13192
+ }
13193
+ throw error;
13194
+ }
13195
+ }
13196
+ function normalizeError(reply, error) {
13197
+ if (error instanceof AgentWebAppError) {
13198
+ return reply.code(error.statusCode).send({
13199
+ success: false,
13200
+ error: { code: error.code, message: error.message, retryable: false }
13201
+ });
13202
+ }
13203
+ if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500) {
13204
+ return invalidRequest(reply, error.statusCode);
13205
+ }
13206
+ return reply.code(500).send({
13207
+ success: false,
13208
+ error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false }
13209
+ });
13210
+ }
13211
+ function invalidRequest(reply, statusCode) {
13212
+ return reply.code(statusCode).send({
13213
+ success: false,
13214
+ error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false }
13215
+ });
13216
+ }
13217
+
13218
+ // src/routes/agent-web-app-runtime.ts
13219
+ var import_zod5 = require("zod");
13220
+
13221
+ // src/services/agent-web-app/AgentWebAppRuntimeService.ts
13222
+ var import_node_crypto3 = require("crypto");
13223
+ var import_protocols6 = require("@axiom-lattice/protocols");
13224
+ init_task_file_refs();
13225
+ function isRecord(value) {
13226
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13227
+ }
13228
+ var AgentWebAppRuntimeError = class extends Error {
13229
+ constructor(code, statusCode, message) {
13230
+ super(message);
13231
+ this.code = code;
13232
+ this.statusCode = statusCode;
13233
+ this.name = "AgentWebAppRuntimeError";
13234
+ }
13235
+ };
13236
+ var AgentWebAppRuntimeService = class {
13237
+ constructor(deps) {
13238
+ this.deps = deps;
13239
+ }
13240
+ async bootstrap(webAppId, userId, selection) {
13241
+ const runtime = await this.resolveRuntime(webAppId, selection);
13242
+ const assistant = await this.deps.assistantResolver.resolve(
13243
+ runtime.webApp.tenantId,
13244
+ runtime.webApp.assistantId
13245
+ );
13246
+ if (!assistant) this.fail("WEB_APP_DISABLED", 403, "Agent Web App is unavailable");
13247
+ const publicProjectIds = runtime.webApp.features.projectSelector ? runtime.webApp.scope.allowedProjectIds : [runtime.webApp.scope.defaultProjectId];
13248
+ const projects = await Promise.all(publicProjectIds.map(async (id) => {
13249
+ const project = await this.deps.projectStore.getProjectById(runtime.webApp.tenantId, id);
13250
+ if (!project) this.fail("PROJECT_NOT_ALLOWED", 400, "Project is not available");
13251
+ return { id: project.id, name: project.name };
13252
+ }));
13253
+ const defaultModelKey = runtime.webApp.scope.defaultModelKey;
13254
+ if (defaultModelKey && !this.deps.modelRegistry.has(defaultModelKey)) {
13255
+ this.fail("MODEL_NOT_ALLOWED", 400, "Default model is not available");
13256
+ }
13257
+ const configuredPublicModelKeys = runtime.webApp.features.modelSelector ? runtime.webApp.scope.allowedModelKeys ?? [] : defaultModelKey ? [defaultModelKey] : [];
13258
+ const publicModelKeys = [...new Set(configuredPublicModelKeys)].filter((key) => this.deps.modelRegistry.has(key));
13259
+ const models = publicModelKeys.map((key) => ({
13260
+ key,
13261
+ label: this.deps.modelRegistry.label(key)
13262
+ }));
13263
+ const result = {
13264
+ webApp: {
13265
+ id: runtime.webApp.id,
13266
+ name: runtime.webApp.name,
13267
+ description: runtime.webApp.description,
13268
+ assistant,
13269
+ defaultProjectId: runtime.webApp.scope.defaultProjectId,
13270
+ defaultModelKey: runtime.webApp.scope.defaultModelKey,
13271
+ features: runtime.webApp.features,
13272
+ appearance: runtime.webApp.appearance,
13273
+ identityAssurance: "unverified"
13274
+ },
13275
+ projects,
13276
+ models
13277
+ };
13278
+ if (!runtime.webApp.features.threadManagement) {
13279
+ result.thread = await this.resolveImplicitThread(runtime, userId);
13280
+ }
13281
+ return result;
13282
+ }
13283
+ async listThreads(webAppId, userId, selection) {
13284
+ const runtime = await this.resolveRuntime(webAppId, selection);
13285
+ this.requireFeature(runtime.webApp.features.threadManagement);
13286
+ const threads = await this.ownedThreads(runtime, userId);
13287
+ return threads.sort(compareThreads).map(toRuntimeThread);
13288
+ }
13289
+ async createThread(webAppId, userId, input) {
13290
+ const runtime = await this.resolveRuntime(webAppId, input);
13291
+ this.requireFeature(runtime.webApp.features.threadManagement);
13292
+ return this.createOwnedThread(runtime, userId, input.label);
13293
+ }
13294
+ /** Update a thread label; omitted or blank labels preserve the existing label. */
13295
+ async updateThread(webAppId, userId, threadId, input) {
13296
+ const runtime = await this.resolveRuntime(webAppId, input);
13297
+ this.requireFeature(runtime.webApp.features.threadManagement);
13298
+ const thread = await this.requireOwnedThread(runtime, userId, threadId);
13299
+ const label = normalizeLabel(input.label);
13300
+ const updated = await this.deps.threadStore.updateThread(runtime.webApp.tenantId, thread.id, {
13301
+ metadata: this.metadata(runtime, userId, label)
13302
+ });
13303
+ if (!updated) this.threadNotFound();
13304
+ return toRuntimeThread(updated);
13305
+ }
13306
+ async deleteThread(webAppId, userId, threadId, selection) {
13307
+ const runtime = await this.resolveRuntime(webAppId, selection);
13308
+ this.requireFeature(runtime.webApp.features.threadManagement);
13309
+ await this.requireOwnedThread(runtime, userId, threadId);
13310
+ if (!await this.deps.threadStore.deleteThread(runtime.webApp.tenantId, threadId)) this.threadNotFound();
13311
+ }
13312
+ async getMessages(webAppId, userId, threadId, selection) {
13313
+ const runtime = await this.resolveRuntime(webAppId, selection);
13314
+ await this.requireOwnedThread(runtime, userId, threadId);
13315
+ const messages = await this.deps.messageReader.getCurrentMessages({
13316
+ tenantId: runtime.webApp.tenantId,
13317
+ assistantId: runtime.webApp.assistantId,
13318
+ threadId,
13319
+ workspaceId: runtime.project.workspaceId,
13320
+ projectId: runtime.project.id
13321
+ });
13322
+ return messages.flatMap((message) => {
13323
+ if (!isRecord(message) || typeof message.id !== "string" || message.role !== "human" && message.role !== "ai") return [];
13324
+ const content = typeof message.content === "string" ? message.content : runtime.webApp.features.genUI && Array.isArray(message.content) ? message.content.map(import_protocols6.parseAgentWebAppGenUIBlock).filter((block) => block !== void 0) : void 0;
13325
+ return [{ id: message.id, role: message.role, ...content && (typeof content === "string" || content.length > 0) ? { content } : {} }];
13326
+ });
13327
+ }
13328
+ async streamMessage(webAppId, userId, threadId, input) {
13329
+ const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, input);
13330
+ const refs = this.resolveAttachmentRefs(runtime, userId, threadId, input.attachmentRefs ?? []);
13331
+ const agent = this.resolveAgent(runtime, threadId);
13332
+ const content = refs.length ? `${input.content}
13333
+
13334
+ ${formatFileRefsSection(refs)}` : input.content;
13335
+ const execution = await this.execute(agent, runtime, { input: { message: content } });
13336
+ return { ...execution, allowInterrupts: runtime.webApp.features.hitl, allowGenUI: runtime.webApp.features.genUI };
13337
+ }
13338
+ async abort(webAppId, userId, threadId, selection) {
13339
+ const { agent } = await this.resolveOwnedAgent(webAppId, userId, threadId, selection);
13340
+ await agent.abort();
13341
+ }
13342
+ async uploadAttachment(webAppId, userId, threadId, selection, file) {
13343
+ const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, selection);
13344
+ this.requireNamedFeature(runtime.webApp.features.attachments, "Attachments are disabled");
13345
+ if (!this.deps.saveProjectFile || !this.deps.attachmentRefs) this.fail("INTERNAL_ERROR", 500, "Attachment service is unavailable");
13346
+ const userDigest = (0, import_node_crypto3.createHash)("sha256").update(userId, "utf8").digest("hex");
13347
+ const contentDigest = (0, import_node_crypto3.createHash)("sha256").update(file.bytes).digest("hex");
13348
+ const displayName = file.name;
13349
+ const physicalName = `${(0, import_node_crypto3.randomUUID)()}-${sanitizePhysicalFilename(file.name)}`;
13350
+ const saved = await this.deps.saveProjectFile({
13351
+ tenantId: runtime.webApp.tenantId,
13352
+ workspaceId: runtime.project.workspaceId,
13353
+ projectId: runtime.project.id,
13354
+ assistantId: runtime.webApp.assistantId,
13355
+ name: physicalName,
13356
+ mimeType: file.mimeType,
13357
+ bytes: file.bytes,
13358
+ path: `/project/web-apps/${runtime.webApp.id}/${userDigest}/${threadId}`
13359
+ });
13360
+ const ref = this.deps.attachmentRefs.sign({
13361
+ webAppId: runtime.webApp.id,
13362
+ userId,
13363
+ threadId,
13364
+ projectId: runtime.project.id,
13365
+ uri: saved.uri,
13366
+ name: displayName,
13367
+ mimeType: file.mimeType,
13368
+ size: saved.size,
13369
+ contentDigest
13370
+ });
13371
+ return { ref, name: displayName, mimeType: file.mimeType, size: saved.size };
13372
+ }
13373
+ async resumeInterrupt(webAppId, userId, threadId, interruptId, selection, input) {
13374
+ const { runtime, agent } = await this.resolveOwnedAgent(webAppId, userId, threadId, selection);
13375
+ this.requireNamedFeature(runtime.webApp.features.hitl, "Human review is disabled");
13376
+ const state = await agent.getCurrentState();
13377
+ if (!hasInterrupt(state, interruptId)) this.fail("INVALID_REQUEST", 400, "Interrupt not found");
13378
+ const execution = await this.execute(agent, runtime, {
13379
+ input: { message: input.message },
13380
+ command: { resume: input.response }
13381
+ });
13382
+ return { ...execution, allowInterrupts: true, allowGenUI: runtime.webApp.features.genUI };
13383
+ }
13384
+ execute(agent, runtime, request) {
13385
+ return executeScopedAgentMessage(agent, {
13386
+ ...request,
13387
+ ...runtime.modelKey ? { custom_run_config: { modelConfig: { modelKey: runtime.modelKey } } } : {}
13388
+ }, [import_protocols6.MessageChunkTypes.MESSAGE_COMPLETED, import_protocols6.MessageChunkTypes.INTERRUPT, import_protocols6.MessageChunkTypes.MESSAGE_FAILED]);
13389
+ }
13390
+ async resolveRuntime(webAppId, selection) {
13391
+ const webApp = await this.deps.webAppStore.findById(webAppId);
13392
+ if (!webApp) this.fail("WEB_APP_NOT_FOUND", 404, "Agent Web App not found");
13393
+ const previewAllowed = webApp.status === "draft" && selection.preview?.tenantId === webApp.tenantId && await this.deps.authorizePreview?.(webApp, selection.preview) === true;
13394
+ if (webApp.status !== "active" && !previewAllowed) this.fail("WEB_APP_DISABLED", 403, "Agent Web App is disabled");
13395
+ if (!webApp.features.projectSelector && selection.projectId !== void 0) {
13396
+ this.fail("PROJECT_SELECTOR_DISABLED", 400, "Project selection is disabled");
13397
+ }
13398
+ const projectId = selection.projectId ?? webApp.scope.defaultProjectId;
13399
+ if (!webApp.scope.allowedProjectIds.includes(projectId)) {
13400
+ this.fail("PROJECT_NOT_ALLOWED", 400, "Project is not allowed");
13401
+ }
13402
+ const project = await this.deps.projectStore.getProjectById(webApp.tenantId, projectId);
13403
+ if (!project) this.fail("PROJECT_NOT_ALLOWED", 400, "Project is not available");
13404
+ if (!webApp.features.modelSelector && selection.modelKey !== void 0) {
13405
+ this.fail("MODEL_NOT_ALLOWED", 400, "Model selection is disabled");
13406
+ }
13407
+ const modelKey2 = selection.modelKey ?? webApp.scope.defaultModelKey;
13408
+ const allowedModels = webApp.scope.allowedModelKeys;
13409
+ if (modelKey2 && (!allowedModels?.includes(modelKey2) || !this.deps.modelRegistry.has(modelKey2))) {
13410
+ this.fail("MODEL_NOT_ALLOWED", 400, "Model is not allowed");
13411
+ }
13412
+ return { webApp, project, modelKey: modelKey2 };
13413
+ }
13414
+ async resolveOwnedAgent(webAppId, userId, threadId, selection) {
13415
+ const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, selection);
13416
+ return { runtime, agent: this.resolveAgent(runtime, threadId) };
13417
+ }
13418
+ async resolveOwnedRuntime(webAppId, userId, threadId, selection) {
13419
+ const runtime = await this.resolveRuntime(webAppId, selection);
13420
+ await this.requireOwnedThread(runtime, userId, threadId);
13421
+ return runtime;
13422
+ }
13423
+ resolveAgent(runtime, threadId) {
13424
+ if (!this.deps.agentResolver) this.fail("INTERNAL_ERROR", 500, "Agent runtime is unavailable");
13425
+ return this.deps.agentResolver.getAgent({
13426
+ tenantId: runtime.webApp.tenantId,
13427
+ assistantId: runtime.webApp.assistantId,
13428
+ threadId,
13429
+ workspaceId: runtime.project.workspaceId,
13430
+ projectId: runtime.project.id,
13431
+ ...runtime.modelKey ? { modelKey: runtime.modelKey } : {}
13432
+ });
13433
+ }
13434
+ resolveAttachmentRefs(runtime, userId, threadId, refs) {
13435
+ if (refs.length === 0) return [];
13436
+ this.requireNamedFeature(runtime.webApp.features.attachments, "Attachments are disabled");
13437
+ if (!this.deps.attachmentRefs) this.fail("INTERNAL_ERROR", 500, "Attachment service is unavailable");
13438
+ try {
13439
+ return refs.map((ref) => ({
13440
+ ...this.deps.attachmentRefs.verify(ref, {
13441
+ webAppId: runtime.webApp.id,
13442
+ userId,
13443
+ threadId,
13444
+ projectId: runtime.project.id
13445
+ }),
13446
+ addedBy: "user"
13447
+ }));
13448
+ } catch {
13449
+ return this.fail("INVALID_REQUEST", 400, "Invalid attachment reference");
13450
+ }
13451
+ }
13452
+ async ownedThreads(runtime, userId) {
13453
+ return this.deps.threadStore.getThreadsByAssistantId(
13454
+ runtime.webApp.tenantId,
13455
+ runtime.webApp.assistantId,
13456
+ {
13457
+ source: "web_app",
13458
+ webAppId: runtime.webApp.id,
13459
+ userId,
13460
+ projectId: runtime.project.id
13461
+ }
13462
+ );
13463
+ }
13464
+ async requireOwnedThread(runtime, userId, threadId) {
13465
+ const thread = await this.deps.threadStore.getThreadById(runtime.webApp.tenantId, threadId);
13466
+ const metadata = thread?.metadata;
13467
+ if (!thread || thread.assistantId !== runtime.webApp.assistantId || metadata?.source !== "web_app" || metadata.webAppId !== runtime.webApp.id || metadata.userId !== userId || metadata.projectId !== runtime.project.id) this.threadNotFound();
13468
+ return thread;
13469
+ }
13470
+ async resolveImplicitThread(runtime, userId) {
13471
+ const latest = (await this.ownedThreads(runtime, userId)).sort(compareThreads)[0];
13472
+ if (latest) return toRuntimeThread(latest);
13473
+ const threadId = implicitThreadId(runtime, userId);
13474
+ const existing = await this.deps.threadStore.getThreadById(
13475
+ runtime.webApp.tenantId,
13476
+ threadId
13477
+ );
13478
+ if (existing) return toRuntimeThread(this.requireImplicitOwnership(runtime, userId, existing));
13479
+ await this.deps.threadStore.createThread(
13480
+ runtime.webApp.tenantId,
13481
+ runtime.webApp.assistantId,
13482
+ threadId,
13483
+ { metadata: this.metadata(runtime, userId) }
13484
+ );
13485
+ const persisted = await this.deps.threadStore.getThreadById(
13486
+ runtime.webApp.tenantId,
13487
+ threadId
13488
+ );
13489
+ if (!persisted) this.fail("INTERNAL_ERROR", 500, "Implicit thread could not be resolved");
13490
+ return toRuntimeThread(this.requireImplicitOwnership(runtime, userId, persisted));
13491
+ }
13492
+ requireImplicitOwnership(runtime, userId, thread) {
13493
+ const metadata = thread.metadata;
13494
+ if (thread.assistantId !== runtime.webApp.assistantId || metadata?.source !== "web_app" || metadata.webAppId !== runtime.webApp.id || metadata.userId !== userId || metadata.projectId !== runtime.project.id) this.fail("INTERNAL_ERROR", 500, "Implicit thread identity conflict");
13495
+ return thread;
13496
+ }
13497
+ async createOwnedThread(runtime, userId, rawLabel) {
13498
+ const thread = await this.deps.threadStore.createThread(
13499
+ runtime.webApp.tenantId,
13500
+ runtime.webApp.assistantId,
13501
+ (0, import_node_crypto3.randomUUID)(),
13502
+ { metadata: this.metadata(runtime, userId, normalizeLabel(rawLabel)) }
13503
+ );
13504
+ return toRuntimeThread(thread);
13505
+ }
13506
+ metadata(runtime, userId, label) {
13507
+ return {
13508
+ source: "web_app",
13509
+ webAppId: runtime.webApp.id,
13510
+ userId,
13511
+ projectId: runtime.project.id,
13512
+ ...label ? { label } : {}
13513
+ };
13514
+ }
13515
+ requireFeature(enabled) {
13516
+ if (!enabled) this.fail("FEATURE_DISABLED", 403, "Thread management is disabled");
13517
+ }
13518
+ requireNamedFeature(enabled, message) {
13519
+ if (!enabled) this.fail("FEATURE_DISABLED", 403, message);
13520
+ }
13521
+ threadNotFound() {
13522
+ return this.fail("THREAD_NOT_FOUND", 404, "Thread not found");
13523
+ }
13524
+ fail(code, statusCode, message) {
13525
+ throw new AgentWebAppRuntimeError(code, statusCode, message);
13526
+ }
13527
+ };
13528
+ function hasInterrupt(state, interruptId) {
13529
+ if (typeof state !== "object" || state === null || !("tasks" in state) || !Array.isArray(state.tasks)) return false;
13530
+ return state.tasks.some((task) => {
13531
+ if (typeof task !== "object" || task === null || !("interrupts" in task) || !Array.isArray(task.interrupts)) return false;
13532
+ return task.interrupts.some((interrupt) => typeof interrupt === "object" && interrupt !== null && "id" in interrupt && interrupt.id === interruptId);
13533
+ });
13534
+ }
13535
+ function sanitizePhysicalFilename(name) {
13536
+ const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+/, "");
13537
+ return sanitized || "file";
13538
+ }
13539
+ function normalizeLabel(label) {
13540
+ const normalized = label?.trim();
13541
+ return normalized || void 0;
13542
+ }
13543
+ function implicitThreadId(runtime, userId) {
13544
+ const canonicalTuple = JSON.stringify([
13545
+ "axiom.agent-web-app.implicit-thread",
13546
+ 1,
13547
+ runtime.webApp.tenantId,
13548
+ runtime.webApp.assistantId,
13549
+ runtime.webApp.id,
13550
+ userId,
13551
+ runtime.project.id
13552
+ ]);
13553
+ const bytes = (0, import_node_crypto3.createHash)("sha256").update(canonicalTuple, "utf8").digest().subarray(0, 16);
13554
+ bytes[6] = bytes[6] & 15 | 128;
13555
+ bytes[8] = bytes[8] & 63 | 128;
13556
+ const hex = bytes.toString("hex");
13557
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
13558
+ }
13559
+ function compareThreads(left, right) {
13560
+ return right.updatedAt.getTime() - left.updatedAt.getTime() || right.id.localeCompare(left.id);
13561
+ }
13562
+ function toRuntimeThread(thread) {
13563
+ return {
13564
+ id: thread.id,
13565
+ projectId: String(thread.metadata?.projectId),
13566
+ ...typeof thread.metadata?.label === "string" ? { label: thread.metadata.label } : {},
13567
+ createdAt: thread.createdAt,
13568
+ updatedAt: thread.updatedAt
13569
+ };
13570
+ }
13571
+
13572
+ // src/services/agent-web-app/AgentWebAppStreamProjector.ts
13573
+ var import_protocols7 = require("@axiom-lattice/protocols");
13574
+ function createAgentWebAppStreamProjectionContext(options = {}) {
13575
+ return { startedToolIds: /* @__PURE__ */ new Set(), allowInterrupts: options.allowInterrupts ?? true, allowGenUI: options.allowGenUI ?? false };
13576
+ }
13577
+ function projectAgentWebAppChunk(chunk, context) {
13578
+ if (chunk.type === import_protocols7.MessageChunkTypes.AI) {
13579
+ const events = [];
13580
+ const startedToolIds = context?.startedToolIds ?? /* @__PURE__ */ new Set();
13581
+ if (typeof chunk.data.content === "string" && chunk.data.content) events.push({ type: "message.delta", text: chunk.data.content });
13582
+ if (context?.allowGenUI && Array.isArray(chunk.data.content)) {
13583
+ for (const value of chunk.data.content) {
13584
+ const block = (0, import_protocols7.parseAgentWebAppGenUIBlock)(value);
13585
+ if (block) events.push({ type: "genui.render", block });
13586
+ }
13587
+ }
13588
+ for (const call of chunk.data.tool_call_chunks ?? []) {
13589
+ if (call.id && call.name && !startedToolIds.has(call.id)) {
13590
+ startedToolIds.add(call.id);
13591
+ events.push({ type: "tool.started", id: call.id, name: call.name });
13592
+ }
13593
+ }
13594
+ for (const call of chunk.data.tool_calls ?? []) {
13595
+ if (!startedToolIds.has(call.id)) {
13596
+ startedToolIds.add(call.id);
13597
+ events.push({ type: "tool.started", id: call.id, name: call.name });
13598
+ }
13599
+ }
13600
+ return events;
13601
+ }
13602
+ if (chunk.type === import_protocols7.MessageChunkTypes.TOOL && chunk.data.tool_call_id) {
13603
+ return [{ type: "tool.completed", id: chunk.data.tool_call_id }];
13604
+ }
13605
+ if (chunk.type === import_protocols7.MessageChunkTypes.INTERRUPT) {
13606
+ if (context && !context.allowInterrupts) return [{ type: "stream.completed" }];
13607
+ const interrupt = publicInterrupt(chunk);
13608
+ return interrupt ? [{ type: "interrupt.created", interrupt }, { type: "stream.completed" }] : [{ type: "stream.completed" }];
13609
+ }
13610
+ if (chunk.type === import_protocols7.MessageChunkTypes.MESSAGE_COMPLETED) {
13611
+ return [
13612
+ { type: "message.completed", messageId: chunk.data.id },
13613
+ { type: "stream.completed" }
13614
+ ];
13615
+ }
13616
+ if (chunk.type === import_protocols7.MessageChunkTypes.MESSAGE_FAILED) {
13617
+ return [
13618
+ { type: "error", error: { code: "STREAM_FAILED", message: "Stream failed", retryable: true } },
13619
+ { type: "stream.completed" }
13620
+ ];
13621
+ }
13622
+ return [];
13623
+ }
13624
+ function publicInterrupt(chunk) {
13625
+ const value = parseInterruptContent(chunk.data.content);
13626
+ if (!value) return void 0;
13627
+ const topLevelId = chunk.id;
13628
+ const id = typeof topLevelId === "string" ? topLevelId : chunk.data.id;
13629
+ if (!id) return void 0;
13630
+ return {
13631
+ id,
13632
+ type: typeof value.type === "string" ? value.type : "input",
13633
+ prompt: typeof value.prompt === "string" ? value.prompt : typeof value.message === "string" ? value.message : "Input required",
13634
+ ...isRecord2(value.data) ? { data: value.data } : {}
13635
+ };
13636
+ }
13637
+ function parseInterruptContent(content) {
13638
+ if (!content) return {};
13639
+ if (isRecord2(content)) return content;
13640
+ if (typeof content !== "string") return void 0;
13641
+ try {
13642
+ const parsed = JSON.parse(content);
13643
+ return isRecord2(parsed) ? parsed : { prompt: content };
13644
+ } catch {
13645
+ return { prompt: content };
13646
+ }
13647
+ }
13648
+ function isRecord2(value) {
13649
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13650
+ }
13651
+
13652
+ // src/routes/agent-web-app-runtime.ts
13653
+ var idSchema = import_zod5.z.string().min(1).max(128);
13654
+ var paramsSchema = import_zod5.z.object({ webAppId: idSchema }).strict();
13655
+ var threadParamsSchema = import_zod5.z.object({ webAppId: idSchema, threadId: idSchema }).strict();
13656
+ var interruptParamsSchema = import_zod5.z.object({ webAppId: idSchema, threadId: idSchema, interruptId: idSchema }).strict();
13657
+ var bootstrapQuerySchema = import_zod5.z.object({ projectId: idSchema.optional(), modelKey: idSchema.optional() }).strict();
13658
+ var projectQuerySchema = import_zod5.z.object({ projectId: idSchema.optional() }).strict();
13659
+ var threadBodySchema = import_zod5.z.object({ projectId: idSchema.optional(), label: import_zod5.z.string().max(128).optional() }).strict();
13660
+ var streamBodySchema = import_zod5.z.object({
13661
+ content: import_zod5.z.string().trim().min(1).max(32768),
13662
+ projectId: idSchema.optional(),
13663
+ modelKey: idSchema.optional(),
13664
+ attachmentRefs: import_zod5.z.array(import_zod5.z.string().min(1).max(8192)).max(10).optional()
13665
+ }).strict();
13666
+ var resumeBodySchema = import_zod5.z.object({
13667
+ projectId: idSchema.optional(),
13668
+ modelKey: idSchema.optional(),
13669
+ message: import_zod5.z.string().trim().min(1).max(4096),
13670
+ response: import_zod5.z.union([
13671
+ import_zod5.z.boolean(),
13672
+ import_zod5.z.string().max(4096),
13673
+ import_zod5.z.object({ approved: import_zod5.z.boolean(), feedback: import_zod5.z.string().max(4096).optional() }).strict()
13674
+ ])
13675
+ }).strict();
13676
+ var MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
13677
+ function createExternalHeaderIdentityResolver() {
13678
+ return { resolve(request) {
13679
+ const raw = request.headers["x-axiom-external-user-id"];
13680
+ if (raw === void 0) throw new AgentWebAppRuntimeError("USER_ID_REQUIRED", 401, "External user id is required");
13681
+ if (Array.isArray(raw) || typeof raw !== "string") throw new AgentWebAppRuntimeError("INVALID_USER_ID", 400, "External user id is invalid");
13682
+ const userId = raw.trim();
13683
+ if (!/^[A-Za-z0-9._:@-]+$/.test(userId) || userId.length > 128) throw new AgentWebAppRuntimeError("INVALID_USER_ID", 400, "External user id is invalid");
13684
+ return { userId, assurance: "unverified" };
13685
+ } };
13686
+ }
13687
+ function registerAgentWebAppRuntimeRoutes(app2, deps) {
13688
+ const identities = deps.identityResolver ?? createExternalHeaderIdentityResolver();
13689
+ app2.register(async (routes) => {
13690
+ routes.setErrorHandler((error, _request, reply) => normalizeError2(reply, error));
13691
+ routes.get("/api/web-apps/:webAppId/runtime/bootstrap", async (request, reply) => handle2(reply, async () => {
13692
+ const { webAppId } = paramsSchema.parse(request.params);
13693
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13694
+ return { data: await deps.service.bootstrap(webAppId, identity.userId, withPreview(bootstrapQuerySchema.parse(request.query), identity.preview)) };
13695
+ }));
13696
+ routes.get("/api/web-apps/:webAppId/runtime/threads", async (request, reply) => handle2(reply, async () => {
13697
+ const { webAppId } = paramsSchema.parse(request.params);
13698
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13699
+ const records = await deps.service.listThreads(webAppId, identity.userId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
13700
+ return { data: { records, total: records.length } };
13701
+ }));
13702
+ routes.post("/api/web-apps/:webAppId/runtime/threads", async (request, reply) => handle2(reply, async () => {
13703
+ const { webAppId } = paramsSchema.parse(request.params);
13704
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13705
+ return { statusCode: 201, data: await deps.service.createThread(webAppId, identity.userId, withPreview(threadBodySchema.parse(request.body), identity.preview)) };
13706
+ }));
13707
+ routes.patch("/api/web-apps/:webAppId/runtime/threads/:threadId", async (request, reply) => handle2(reply, async () => {
13708
+ const { webAppId, threadId } = threadParamsSchema.parse(request.params);
13709
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13710
+ return { data: await deps.service.updateThread(webAppId, identity.userId, threadId, withPreview(threadBodySchema.parse(request.body), identity.preview)) };
13711
+ }));
13712
+ routes.delete("/api/web-apps/:webAppId/runtime/threads/:threadId", async (request, reply) => handle2(reply, async () => {
13713
+ const { webAppId, threadId } = threadParamsSchema.parse(request.params);
13714
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13715
+ await deps.service.deleteThread(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
13716
+ return { data: { id: threadId } };
13717
+ }));
13718
+ routes.get("/api/web-apps/:webAppId/runtime/threads/:threadId/messages", async (request, reply) => handle2(reply, async () => {
13719
+ const { webAppId, threadId } = threadParamsSchema.parse(request.params);
13720
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13721
+ const messages = await deps.service.getMessages(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
13722
+ return { data: { messages } };
13723
+ }));
13724
+ routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/messages/stream", async (request, reply) => {
13725
+ try {
13726
+ const { webAppId, threadId } = threadParamsSchema.parse(request.params);
13727
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13728
+ const input = streamBodySchema.parse(request.body);
13729
+ const result = await deps.service.streamMessage(webAppId, identity.userId, threadId, withPreview(input, identity.preview));
13730
+ beginSse(reply);
13731
+ await pipeAgentWebAppStream(reply.raw, result.stream, result);
13732
+ } catch (error) {
13733
+ return normalizeError2(reply, error);
13734
+ }
13735
+ });
13736
+ routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/abort", async (request, reply) => handle2(reply, async () => {
13737
+ const { webAppId, threadId } = threadParamsSchema.parse(request.params);
13738
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13739
+ await deps.service.abort(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview));
13740
+ return { data: { aborted: true } };
13741
+ }));
13742
+ routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/attachments", async (request, reply) => handle2(reply, async () => {
13743
+ const { webAppId, threadId } = threadParamsSchema.parse(request.params);
13744
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13745
+ if (!request.isMultipart()) throw new import_zod5.ZodError([]);
13746
+ const part = await request.file({ limits: { files: 1, fileSize: MAX_ATTACHMENT_BYTES } });
13747
+ if (!part || !part.filename || part.filename.length > 255) throw new import_zod5.ZodError([]);
13748
+ const bytes = await part.toBuffer();
13749
+ if (bytes.length === 0 || part.file.truncated) throw new import_zod5.ZodError([]);
13750
+ const data = await deps.service.uploadAttachment(webAppId, identity.userId, threadId, withPreview(projectQuerySchema.parse(request.query), identity.preview), {
13751
+ name: part.filename,
13752
+ mimeType: part.mimetype || "application/octet-stream",
13753
+ bytes
13754
+ });
13755
+ return { statusCode: 201, data };
13756
+ }));
13757
+ routes.post("/api/web-apps/:webAppId/runtime/threads/:threadId/interrupts/:interruptId/resume", async (request, reply) => {
13758
+ try {
13759
+ const { webAppId, threadId, interruptId } = interruptParamsSchema.parse(request.params);
13760
+ const identity = resolveRuntimeIdentity(request, webAppId, identities);
13761
+ const { projectId, modelKey: modelKey2, message, response } = resumeBodySchema.parse(request.body);
13762
+ const result = await deps.service.resumeInterrupt(webAppId, identity.userId, threadId, interruptId, withPreview({ projectId, modelKey: modelKey2 }, identity.preview), { message, response });
13763
+ beginSse(reply);
13764
+ await pipeAgentWebAppStream(reply.raw, result.stream, result);
13765
+ } catch (error) {
13766
+ return normalizeError2(reply, error);
13767
+ }
13768
+ });
13769
+ });
13770
+ }
13771
+ function resolveRuntimeIdentity(request, webAppId, identities) {
13772
+ if (request.headers["x-axiom-web-app-preview"] !== "true") return identities.resolve(request);
13773
+ const user = request.user;
13774
+ if (!user?.id || !user.tenantId) throw new AgentWebAppRuntimeError("USER_ID_REQUIRED", 401, "Authenticated Console preview is required");
13775
+ return { userId: `console-preview:${user.id}:${webAppId}`, preview: { tenantId: user.tenantId, userId: user.id } };
13776
+ }
13777
+ function withPreview(selection, preview) {
13778
+ return { ...selection, ...preview ? { preview } : {} };
13779
+ }
13780
+ async function pipeAgentWebAppStream(raw, stream, options = {}) {
13781
+ const projection = createAgentWebAppStreamProjectionContext(options);
13782
+ await pipeAsyncIterableToSse(raw, stream, {
13783
+ project: (chunk) => projectAgentWebAppChunk(chunk, projection),
13784
+ onError: () => [
13785
+ { type: "error", error: { code: "STREAM_FAILED", message: "Stream failed", retryable: true } },
13786
+ { type: "stream.completed" }
13787
+ ]
13788
+ });
13789
+ }
13790
+ function beginSse(reply) {
13791
+ reply.hijack();
13792
+ reply.raw.writeHead(200, {
13793
+ "Content-Type": "text/event-stream; charset=utf-8",
13794
+ "Cache-Control": "no-cache, no-transform",
13795
+ Connection: "keep-alive",
13796
+ "X-Accel-Buffering": "no"
13797
+ });
13798
+ }
13799
+ async function handle2(reply, operation) {
13800
+ try {
13801
+ const result = await operation();
13802
+ return reply.code(result.statusCode ?? 200).send({ success: true, data: result.data });
13803
+ } catch (error) {
13804
+ return normalizeError2(reply, error);
13805
+ }
13806
+ }
13807
+ function normalizeError2(reply, error) {
13808
+ if (error instanceof AgentWebAppRuntimeError) return reply.code(error.statusCode).send({ success: false, error: { code: error.code, message: error.message, retryable: false } });
13809
+ if (error instanceof import_zod5.ZodError) return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
13810
+ if (isMultipartRequestError(error)) return reply.code(400).send({ success: false, error: { code: "INVALID_REQUEST", message: "Invalid request", retryable: false } });
13811
+ return reply.code(500).send({ success: false, error: { code: "INTERNAL_ERROR", message: "Internal server error", retryable: false } });
13812
+ }
13813
+ function isMultipartRequestError(error) {
13814
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && error.code.startsWith("FST_");
13815
+ }
13816
+
13817
+ // src/services/agent-web-app/AgentWebAppAttachmentRef.ts
13818
+ var import_node_crypto4 = require("crypto");
13819
+ var TTL_MS = 15 * 6e4;
13820
+ function resolveAgentWebAppAttachmentSecret(consoleSecret) {
13821
+ return process.env.WEB_APP_ATTACHMENT_SECRET || process.env.AUTH_TOKEN_SECRET || process.env.JWT_SECRET || consoleSecret;
13822
+ }
13823
+ var AgentWebAppAttachmentRefService = class {
13824
+ constructor(secret, now = Date.now) {
13825
+ this.now = now;
13826
+ if (!secret) throw new Error("Attachment signing secret is required");
13827
+ this.key = (0, import_node_crypto4.createHash)("sha256").update(secret, "utf8").digest();
13828
+ }
13829
+ sign(input) {
13830
+ const payload = {
13831
+ webAppId: input.webAppId,
13832
+ userDigest: digestUser(input.userId),
13833
+ threadId: input.threadId,
13834
+ projectId: input.projectId,
13835
+ uri: input.uri,
13836
+ name: input.name,
13837
+ mimeType: input.mimeType,
13838
+ size: input.size,
13839
+ contentDigest: input.contentDigest,
13840
+ exp: this.now() + TTL_MS
13841
+ };
13842
+ const iv = (0, import_node_crypto4.randomBytes)(12);
13843
+ const cipher = (0, import_node_crypto4.createCipheriv)("aes-256-gcm", this.key, iv);
13844
+ const ciphertext = Buffer.concat([
13845
+ cipher.update(JSON.stringify(payload), "utf8"),
13846
+ cipher.final()
13847
+ ]);
13848
+ const tag = cipher.getAuthTag();
13849
+ return `v1.${iv.toString("base64url")}.${ciphertext.toString("base64url")}.${tag.toString("base64url")}`;
13850
+ }
13851
+ verify(ref, scope) {
13852
+ const [version, encodedIv, encodedCiphertext, encodedTag, extra] = ref.split(".");
13853
+ if (version !== "v1" || !encodedIv || !encodedCiphertext || !encodedTag || extra !== void 0 || !/^[A-Za-z0-9_-]{16}$/.test(encodedIv) || !/^[A-Za-z0-9_-]+$/.test(encodedCiphertext) || !/^[A-Za-z0-9_-]{22}$/.test(encodedTag)) this.invalid();
13854
+ try {
13855
+ const iv = decodeCanonical(encodedIv, 12);
13856
+ const ciphertext = decodeCanonical(encodedCiphertext);
13857
+ const tag = decodeCanonical(encodedTag, 16);
13858
+ const decipher = (0, import_node_crypto4.createDecipheriv)("aes-256-gcm", this.key, iv);
13859
+ decipher.setAuthTag(tag);
13860
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
13861
+ const value = JSON.parse(plaintext.toString("utf8"));
13862
+ if (!isAttachmentPayload(value)) this.invalid();
13863
+ if (value.exp <= this.now()) throw new Error("Attachment reference expired");
13864
+ if (value.webAppId !== scope.webAppId || value.userDigest !== digestUser(scope.userId) || value.threadId !== scope.threadId || value.projectId !== scope.projectId) this.invalid();
13865
+ return {
13866
+ uri: value.uri,
13867
+ name: value.name,
13868
+ mimeType: value.mimeType,
13869
+ size: value.size,
13870
+ contentDigest: value.contentDigest
13871
+ };
13872
+ } catch (error) {
13873
+ if (error instanceof Error && error.message === "Attachment reference expired") throw error;
13874
+ this.invalid();
13875
+ }
13876
+ }
13877
+ invalid() {
13878
+ throw new Error("Invalid attachment reference");
13879
+ }
13880
+ };
13881
+ function decodeCanonical(value, expectedBytes) {
13882
+ const decoded = Buffer.from(value, "base64url");
13883
+ if (decoded.toString("base64url") !== value || expectedBytes !== void 0 && decoded.length !== expectedBytes) {
13884
+ throw new Error("Invalid attachment reference");
13885
+ }
13886
+ return decoded;
13887
+ }
13888
+ function digestUser(userId) {
13889
+ return (0, import_node_crypto4.createHash)("sha256").update(userId, "utf8").digest("hex");
13890
+ }
13891
+ function isAttachmentPayload(value) {
13892
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
13893
+ const record = value;
13894
+ if (Object.keys(record).sort().join(",") !== "contentDigest,exp,mimeType,name,projectId,size,threadId,uri,userDigest,webAppId") return false;
13895
+ return typeof record.webAppId === "string" && typeof record.userDigest === "string" && /^[a-f0-9]{64}$/.test(record.userDigest) && typeof record.threadId === "string" && typeof record.projectId === "string" && typeof record.uri === "string" && record.uri.startsWith("/") && typeof record.name === "string" && record.name.length > 0 && typeof record.mimeType === "string" && record.mimeType.length > 0 && typeof record.size === "number" && Number.isSafeInteger(record.size) && record.size >= 0 && typeof record.contentDigest === "string" && /^[a-f0-9]{64}$/.test(record.contentDigest) && typeof record.exp === "number" && Number.isSafeInteger(record.exp);
13896
+ }
13897
+
13898
+ // src/routes/index.ts
13899
+ init_workspace_file_service();
12842
13900
  var registerLatticeRoutes = (app2, channelDeps) => {
13901
+ const webAppStore = (0, import_core41.getStoreLattice)("default", "agentWebApp").store;
13902
+ const assistantStore = (0, import_core41.getStoreLattice)("default", "assistant").store;
13903
+ const projectStore = (0, import_core41.getStoreLattice)("default", "project").store;
13904
+ registerAgentWebAppRoutes(app2, {
13905
+ service: new AgentWebAppService({
13906
+ webAppStore,
13907
+ assistantStore,
13908
+ projectStore,
13909
+ modelRegistry: { has: (key) => import_core41.modelLatticeManager.hasLattice(key) },
13910
+ configuredAgentResolver: createConfiguredAgentResolver({
13911
+ hydrate: (tenantId) => import_core41.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId),
13912
+ has: (tenantId, assistantId) => import_core41.agentLatticeManager.hasAgentLatticeWithTenant(tenantId, assistantId)
13913
+ })
13914
+ })
13915
+ });
13916
+ registerAgentWebAppRuntimeRoutes(app2, {
13917
+ service: new AgentWebAppRuntimeService({
13918
+ webAppStore,
13919
+ threadStore: (0, import_core41.getStoreLattice)("default", "thread").store,
13920
+ projectStore,
13921
+ assistantResolver: {
13922
+ resolve: async (tenantId, assistantId) => {
13923
+ const stored = await assistantStore.getAssistantById(tenantId, assistantId);
13924
+ if (stored) return stored;
13925
+ await import_core41.agentLatticeManager.initializeStoredAssistantsForTenant(tenantId);
13926
+ const config = import_core41.agentLatticeManager.getAgentConfigWithTenant(tenantId, assistantId);
13927
+ return config ? { id: assistantId, name: config.name, description: config.description } : null;
13928
+ }
13929
+ },
13930
+ modelRegistry: {
13931
+ has: (key) => import_core41.modelLatticeManager.hasLattice(key),
13932
+ label: (key) => key
13933
+ },
13934
+ messageReader: {
13935
+ getCurrentMessages: ({ tenantId, assistantId, threadId, workspaceId, projectId }) => import_core41.agentInstanceManager.getAgent({
13936
+ tenant_id: tenantId,
13937
+ assistant_id: assistantId,
13938
+ thread_id: threadId,
13939
+ workspace_id: workspaceId,
13940
+ project_id: projectId
13941
+ }).getCurrentMessages()
13942
+ },
13943
+ agentResolver: {
13944
+ getAgent: ({ tenantId, assistantId, threadId, workspaceId, projectId }) => import_core41.agentInstanceManager.getAgent({
13945
+ tenant_id: tenantId,
13946
+ assistant_id: assistantId,
13947
+ thread_id: threadId,
13948
+ workspace_id: workspaceId,
13949
+ project_id: projectId
13950
+ })
13951
+ },
13952
+ attachmentRefs: new AgentWebAppAttachmentRefService(
13953
+ resolveAgentWebAppAttachmentSecret(
13954
+ resolveConsoleTokenSecret(process.env.AUTH_REQUIRED === "true")
13955
+ )
13956
+ ),
13957
+ saveProjectFile,
13958
+ authorizePreview: async (webApp, preview) => {
13959
+ if (webApp.tenantId !== preview.tenantId) return false;
13960
+ const assistant = await assistantStore.getAssistantById(preview.tenantId, webApp.assistantId);
13961
+ if (assistant) return !assistant.ownerUserId || assistant.ownerUserId === preview.userId;
13962
+ await import_core41.agentLatticeManager.initializeStoredAssistantsForTenant(preview.tenantId);
13963
+ return import_core41.agentLatticeManager.hasAgentLatticeWithTenant(preview.tenantId, webApp.assistantId);
13964
+ }
13965
+ })
13966
+ });
12843
13967
  registerA2ABridgeRoutes(app2);
12844
13968
  registerSTTRoutes(app2);
12845
13969
  app2.get("/api/local-a2a", getLocalA2AStatus);
@@ -13136,12 +14260,12 @@ function registerResourceRoutes(app2, controller) {
13136
14260
  }
13137
14261
 
13138
14262
  // src/export_registrations/index.ts
13139
- var import_core51 = require("@axiom-lattice/core");
14263
+ var import_core52 = require("@axiom-lattice/core");
13140
14264
 
13141
14265
  // src/export_registrations/skill.registration.ts
13142
- var import_core41 = require("@axiom-lattice/core");
14266
+ var import_core42 = require("@axiom-lattice/core");
13143
14267
  function getStore2(context) {
13144
- return new import_core41.SandboxSkillStore({
14268
+ return new import_core42.SandboxSkillStore({
13145
14269
  workspaceId: context?.workspaceId,
13146
14270
  projectId: context?.projectId
13147
14271
  });
@@ -13159,7 +14283,7 @@ var skillRegistration = {
13159
14283
  async listForExport(tenantId, context) {
13160
14284
  const store2 = getStore2(context);
13161
14285
  const skills = await store2.getAllSkills(tenantId, toStoreContext(context));
13162
- return skills.filter((s) => !(0, import_core41.isBuiltInSkill)(s.id)).map((s) => ({
14286
+ return skills.filter((s) => !(0, import_core42.isBuiltInSkill)(s.id)).map((s) => ({
13163
14287
  _exportId: "",
13164
14288
  data: {
13165
14289
  id: s.id,
@@ -13224,7 +14348,7 @@ var skillRegistration = {
13224
14348
  const insertions = [];
13225
14349
  for (const entity of entities) {
13226
14350
  const id = entity.data.id;
13227
- if ((0, import_core41.isBuiltInSkill)(id)) continue;
14351
+ if ((0, import_core42.isBuiltInSkill)(id)) continue;
13228
14352
  if (existingIds.has(id)) {
13229
14353
  conflicts.push({
13230
14354
  _exportId: entity._exportId,
@@ -13283,9 +14407,9 @@ var skillRegistration = {
13283
14407
  };
13284
14408
 
13285
14409
  // src/export_registrations/agent.registration.ts
13286
- var import_core42 = require("@axiom-lattice/core");
14410
+ var import_core43 = require("@axiom-lattice/core");
13287
14411
  function getStore3() {
13288
- return (0, import_core42.getStoreLattice)("default", "assistant").store;
14412
+ return (0, import_core43.getStoreLattice)("default", "assistant").store;
13289
14413
  }
13290
14414
  var agentRegistration = {
13291
14415
  entityType: "agent",
@@ -13365,9 +14489,9 @@ var agentRegistration = {
13365
14489
  };
13366
14490
 
13367
14491
  // src/export_registrations/database-config.registration.ts
13368
- var import_core43 = require("@axiom-lattice/core");
14492
+ var import_core44 = require("@axiom-lattice/core");
13369
14493
  function getStore4() {
13370
- return (0, import_core43.getStoreLattice)("default", "database").store;
14494
+ return (0, import_core44.getStoreLattice)("default", "database").store;
13371
14495
  }
13372
14496
  var databaseConfigRegistration = {
13373
14497
  entityType: "database_config",
@@ -13447,9 +14571,9 @@ var databaseConfigRegistration = {
13447
14571
  };
13448
14572
 
13449
14573
  // src/export_registrations/metrics-config.registration.ts
13450
- var import_core44 = require("@axiom-lattice/core");
14574
+ var import_core45 = require("@axiom-lattice/core");
13451
14575
  function getStore5() {
13452
- return (0, import_core44.getStoreLattice)("default", "metrics").store;
14576
+ return (0, import_core45.getStoreLattice)("default", "metrics").store;
13453
14577
  }
13454
14578
  var metricsConfigRegistration = {
13455
14579
  entityType: "metrics_config",
@@ -13529,9 +14653,9 @@ var metricsConfigRegistration = {
13529
14653
  };
13530
14654
 
13531
14655
  // src/export_registrations/mcp-config.registration.ts
13532
- var import_core45 = require("@axiom-lattice/core");
14656
+ var import_core46 = require("@axiom-lattice/core");
13533
14657
  function getStore6() {
13534
- return (0, import_core45.getStoreLattice)("default", "mcp").store;
14658
+ return (0, import_core46.getStoreLattice)("default", "mcp").store;
13535
14659
  }
13536
14660
  var mcpConfigRegistration = {
13537
14661
  entityType: "mcp_config",
@@ -13614,9 +14738,9 @@ var mcpConfigRegistration = {
13614
14738
  };
13615
14739
 
13616
14740
  // src/export_registrations/connection.registration.ts
13617
- var import_core46 = require("@axiom-lattice/core");
14741
+ var import_core47 = require("@axiom-lattice/core");
13618
14742
  function getStore7() {
13619
- return (0, import_core46.getStoreLattice)("default", "connection").store;
14743
+ return (0, import_core47.getStoreLattice)("default", "connection").store;
13620
14744
  }
13621
14745
  async function listAllConnections(tenantId) {
13622
14746
  const store2 = getStore7();
@@ -13698,9 +14822,9 @@ var connectionRegistration = {
13698
14822
  };
13699
14823
 
13700
14824
  // src/export_registrations/collection.registration.ts
13701
- var import_core47 = require("@axiom-lattice/core");
14825
+ var import_core48 = require("@axiom-lattice/core");
13702
14826
  function getStore8() {
13703
- return (0, import_core47.getStoreLattice)("default", "collection").store;
14827
+ return (0, import_core48.getStoreLattice)("default", "collection").store;
13704
14828
  }
13705
14829
  var collectionRegistration = {
13706
14830
  entityType: "collection",
@@ -13771,11 +14895,11 @@ var collectionRegistration = {
13771
14895
  };
13772
14896
 
13773
14897
  // src/export_registrations/channel-installation.registration.ts
13774
- var import_core48 = require("@axiom-lattice/core");
14898
+ var import_core49 = require("@axiom-lattice/core");
13775
14899
  var import_crypto10 = require("crypto");
13776
14900
  var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
13777
14901
  function getStore9() {
13778
- return (0, import_core48.getStoreLattice)("default", "channelInstallation").store;
14902
+ return (0, import_core49.getStoreLattice)("default", "channelInstallation").store;
13779
14903
  }
13780
14904
  var channelInstallationRegistration = {
13781
14905
  entityType: "channel_installation",
@@ -13874,9 +14998,9 @@ var channelInstallationRegistration = {
13874
14998
  };
13875
14999
 
13876
15000
  // src/export_registrations/menu.registration.ts
13877
- var import_core49 = require("@axiom-lattice/core");
15001
+ var import_core50 = require("@axiom-lattice/core");
13878
15002
  function getStore10() {
13879
- return (0, import_core49.getStoreLattice)("default", "menu").store;
15003
+ return (0, import_core50.getStoreLattice)("default", "menu").store;
13880
15004
  }
13881
15005
  var menuRegistration = {
13882
15006
  entityType: "menu",
@@ -13954,9 +15078,9 @@ var menuRegistration = {
13954
15078
  };
13955
15079
 
13956
15080
  // src/export_registrations/eval.registration.ts
13957
- var import_core50 = require("@axiom-lattice/core");
15081
+ var import_core51 = require("@axiom-lattice/core");
13958
15082
  function getStore11() {
13959
- return (0, import_core50.getStoreLattice)("default", "eval").store;
15083
+ return (0, import_core51.getStoreLattice)("default", "eval").store;
13960
15084
  }
13961
15085
  var evalRegistration = {
13962
15086
  entityType: "eval",
@@ -14282,7 +15406,7 @@ var evalRegistration = {
14282
15406
 
14283
15407
  // src/export_registrations/index.ts
14284
15408
  function registerAllBuiltinEntities() {
14285
- const registry = import_core51.ExportableEntityRegistry.getInstance();
15409
+ const registry = import_core52.ExportableEntityRegistry.getInstance();
14286
15410
  registry.register(skillRegistration);
14287
15411
  registry.register(agentRegistration);
14288
15412
  registry.register(databaseConfigRegistration);
@@ -14296,7 +15420,7 @@ function registerAllBuiltinEntities() {
14296
15420
  }
14297
15421
 
14298
15422
  // src/router/MessageRouter.ts
14299
- var import_core52 = require("@axiom-lattice/core");
15423
+ var import_core53 = require("@axiom-lattice/core");
14300
15424
  var import_crypto11 = require("crypto");
14301
15425
  var BindingNotFoundError = class extends Error {
14302
15426
  constructor(message) {
@@ -14466,7 +15590,7 @@ var MessageRouter = class {
14466
15590
  channel: message.channel,
14467
15591
  adapterChannel: adapter.channel
14468
15592
  }, "Thread resolved by adapter strategy");
14469
- const threadStore = (0, import_core52.getStoreLattice)("default", "thread").store;
15593
+ const threadStore = (0, import_core53.getStoreLattice)("default", "thread").store;
14470
15594
  try {
14471
15595
  await threadStore.createThread(
14472
15596
  tenantId,
@@ -14503,7 +15627,7 @@ var MessageRouter = class {
14503
15627
  }
14504
15628
  }
14505
15629
  if (!threadId) {
14506
- const threadStore = (0, import_core52.getStoreLattice)("default", "thread").store;
15630
+ const threadStore = (0, import_core53.getStoreLattice)("default", "thread").store;
14507
15631
  const newThreadId = (0, import_crypto11.randomUUID)();
14508
15632
  console.log({
14509
15633
  event: "dispatch:thread:create",
@@ -14543,7 +15667,7 @@ var MessageRouter = class {
14543
15667
  senderId: message.sender.id,
14544
15668
  contentLength: message.content.text.length
14545
15669
  }, "Dispatching to agent");
14546
- const agent = import_core52.agentInstanceManager.getAgent({
15670
+ const agent = import_core53.agentInstanceManager.getAgent({
14547
15671
  tenant_id: tenantId,
14548
15672
  assistant_id: agentId,
14549
15673
  thread_id: threadId,
@@ -14783,7 +15907,7 @@ function createAuditLoggerMiddleware() {
14783
15907
  }
14784
15908
 
14785
15909
  // src/index.ts
14786
- var import_core57 = require("@axiom-lattice/core");
15910
+ var import_core58 = require("@axiom-lattice/core");
14787
15911
 
14788
15912
  // src/swagger.ts
14789
15913
  var import_swagger = __toESM(require("@fastify/swagger"));
@@ -14848,7 +15972,7 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
14848
15972
  };
14849
15973
 
14850
15974
  // src/services/agent_task_consumer.ts
14851
- var import_core53 = require("@axiom-lattice/core");
15975
+ var import_core54 = require("@axiom-lattice/core");
14852
15976
  var handleAgentTask = async (taskRequest, retryCount = 0) => {
14853
15977
  const {
14854
15978
  assistant_id,
@@ -14866,17 +15990,17 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
14866
15990
  console.log(
14867
15991
  `\u5F00\u59CB\u5904\u7406\u4EFB\u52A1 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
14868
15992
  );
14869
- const agent = import_core53.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
14870
- await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core53.QueueMode.STEER);
15993
+ const agent = import_core54.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
15994
+ await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core54.QueueMode.STEER);
14871
15995
  if (callback_event) {
14872
15996
  agent.subscribeOnce("message:completed", (evt) => {
14873
- import_core53.eventBus.publish(callback_event, {
15997
+ import_core54.eventBus.publish(callback_event, {
14874
15998
  success: true,
14875
15999
  state: evt.state
14876
16000
  });
14877
16001
  if (main_thread_id && main_tenant_id) {
14878
16002
  try {
14879
- const mainAgent = import_core53.agentInstanceManager.getAgent({
16003
+ const mainAgent = import_core54.agentInstanceManager.getAgent({
14880
16004
  assistant_id: main_assistant_id ?? assistant_id,
14881
16005
  thread_id: main_thread_id,
14882
16006
  tenant_id: main_tenant_id,
@@ -14906,7 +16030,7 @@ ${summary}`
14906
16030
  }
14907
16031
  });
14908
16032
  agent.subscribeOnce("message:interrupted", (evt) => {
14909
- import_core53.eventBus.publish(callback_event, {
16033
+ import_core54.eventBus.publish(callback_event, {
14910
16034
  success: true,
14911
16035
  state: evt.state
14912
16036
  });
@@ -14929,7 +16053,7 @@ ${summary}`
14929
16053
  return handleAgentTask(taskRequest, nextRetryCount);
14930
16054
  }
14931
16055
  if (callback_event) {
14932
- import_core53.eventBus.publish(callback_event, {
16056
+ import_core54.eventBus.publish(callback_event, {
14933
16057
  success: false,
14934
16058
  error: error instanceof Error ? error.message : String(error)
14935
16059
  });
@@ -14966,7 +16090,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
14966
16090
  * 初始化事件监听和队列轮询
14967
16091
  */
14968
16092
  initialize() {
14969
- import_core53.eventBus.subscribe(import_core53.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
16093
+ import_core54.eventBus.subscribe(import_core54.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
14970
16094
  this.startPollingQueue();
14971
16095
  console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
14972
16096
  }
@@ -15085,7 +16209,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
15085
16209
  handleAgentTask(taskRequest).catch((error) => {
15086
16210
  console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
15087
16211
  if (taskRequest.callback_event) {
15088
- import_core53.eventBus.publish(taskRequest.callback_event, {
16212
+ import_core54.eventBus.publish(taskRequest.callback_event, {
15089
16213
  success: false,
15090
16214
  error: error instanceof Error ? error.message : String(error)
15091
16215
  });
@@ -15100,8 +16224,8 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
15100
16224
  var AgentTaskConsumer = _AgentTaskConsumer;
15101
16225
 
15102
16226
  // src/index.ts
15103
- var import_core58 = require("@axiom-lattice/core");
15104
- var import_protocols7 = require("@axiom-lattice/protocols");
16227
+ var import_core59 = require("@axiom-lattice/core");
16228
+ var import_protocols9 = require("@axiom-lattice/protocols");
15105
16229
  var import_meta = {};
15106
16230
  process.on("unhandledRejection", (reason, promise) => {
15107
16231
  console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
@@ -15109,18 +16233,18 @@ process.on("unhandledRejection", (reason, promise) => {
15109
16233
  var DEFAULT_LOGGER_CONFIG = {
15110
16234
  name: "default",
15111
16235
  description: "Default logger for lattice-gateway service",
15112
- type: import_protocols7.LoggerType.PINO,
16236
+ type: import_protocols9.LoggerType.PINO,
15113
16237
  serviceName: "lattice/gateway",
15114
16238
  loggerName: "lattice/gateway"
15115
16239
  };
15116
16240
  var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
15117
16241
  var logger5 = loggerLattice.client;
15118
16242
  function initializeLogger(config) {
15119
- if (import_core58.loggerLatticeManager.hasLattice("default")) {
15120
- import_core58.loggerLatticeManager.removeLattice("default");
16243
+ if (import_core59.loggerLatticeManager.hasLattice("default")) {
16244
+ import_core59.loggerLatticeManager.removeLattice("default");
15121
16245
  }
15122
- (0, import_core58.registerLoggerLattice)("default", config);
15123
- return (0, import_core58.getLoggerLattice)("default");
16246
+ (0, import_core59.registerLoggerLattice)("default", config);
16247
+ return (0, import_core59.getLoggerLattice)("default");
15124
16248
  }
15125
16249
  var app = (0, import_fastify.default)({
15126
16250
  logger: false,
@@ -15213,7 +16337,7 @@ app.setErrorHandler((error, request, reply) => {
15213
16337
  });
15214
16338
  function getConfiguredSandboxProvider() {
15215
16339
  const sandboxProviderType = process.env.SANDBOX_PROVIDER_TYPE || "microsandbox-remote";
15216
- return (0, import_core58.createSandboxProvider)({
16340
+ return (0, import_core59.createSandboxProvider)({
15217
16341
  type: sandboxProviderType,
15218
16342
  remoteBaseURL: process.env.SANDBOX_BASE_URL,
15219
16343
  microsandboxServiceBaseURL: process.env.MICROSANDBOX_SERVICE_BASE_URL,
@@ -15229,7 +16353,7 @@ function getConfiguredSandboxProvider() {
15229
16353
  }
15230
16354
  async function restoreMcpConnections() {
15231
16355
  try {
15232
- const storeLattice = (0, import_core58.getStoreLattice)("default", "mcp");
16356
+ const storeLattice = (0, import_core59.getStoreLattice)("default", "mcp");
15233
16357
  const store2 = storeLattice.store;
15234
16358
  if (!store2) {
15235
16359
  logger5.info("MCP store not configured, skipping connection restoration");
@@ -15243,15 +16367,15 @@ async function restoreMcpConnections() {
15243
16367
  for (const config of connectedConfigs) {
15244
16368
  try {
15245
16369
  const connection = convertToConnection2(config.config);
15246
- import_core58.mcpManager.addServer(config.key, connection);
16370
+ import_core59.mcpManager.addServer(config.key, connection);
15247
16371
  } catch (err) {
15248
16372
  logger5.warn(`Failed to prepare MCP server "${config.key}" for restoration`, { error: err });
15249
16373
  }
15250
16374
  }
15251
- await import_core58.mcpManager.connect();
16375
+ await import_core59.mcpManager.connect();
15252
16376
  for (const config of connectedConfigs) {
15253
16377
  try {
15254
- await import_core58.mcpManager.registerToolsToToolLattice(config.key, config.selectedTools);
16378
+ await import_core59.mcpManager.registerToolsToToolLattice(config.key, config.selectedTools);
15255
16379
  logger5.info(`MCP server "${config.key}" restored with ${config.selectedTools.length} tools`);
15256
16380
  } catch (err) {
15257
16381
  logger5.warn(`Failed to register tools for MCP server "${config.key}"`, { error: err });
@@ -15284,7 +16408,7 @@ var start = async (config) => {
15284
16408
  const { getStoreLattice: getStore12 } = await import("@axiom-lattice/core");
15285
16409
  const bindingStore = getStore12("default", "channelBinding").store;
15286
16410
  const installationStore = getStore12("default", "channelInstallation").store;
15287
- (0, import_core57.setBindingRegistry)(bindingStore);
16411
+ (0, import_core58.setBindingRegistry)(bindingStore);
15288
16412
  const router = new MessageRouter({
15289
16413
  middlewares: [
15290
16414
  createDeduplicationMiddleware(),
@@ -15301,10 +16425,10 @@ var start = async (config) => {
15301
16425
  error: err instanceof Error ? err.message : String(err)
15302
16426
  });
15303
16427
  }
15304
- (0, import_core57.setEvalRunService)(evalRunner);
16428
+ (0, import_core58.setEvalRunService)(evalRunner);
15305
16429
  try {
15306
- const menuStore = (0, import_core58.getStoreLattice)("default", "menu").store;
15307
- (0, import_core57.setMenuRegistry)(menuStore);
16430
+ const menuStore = (0, import_core59.getStoreLattice)("default", "menu").store;
16431
+ (0, import_core58.setMenuRegistry)(menuStore);
15308
16432
  logger5.info("Menu registry initialized");
15309
16433
  } catch {
15310
16434
  }
@@ -15317,10 +16441,10 @@ var start = async (config) => {
15317
16441
  const { A2AAuthService: A2AAuthService2, parseEnvKeys: parseEnvKeys2 } = await Promise.resolve().then(() => (init_A2AAuthService(), A2AAuthService_exports));
15318
16442
  const { registerA2AStandardRoutes: registerA2AStandardRoutes2 } = await Promise.resolve().then(() => (init_a2a_standard(), a2a_standard_exports));
15319
16443
  const a2a = await Promise.resolve().then(() => (init_a2a(), a2a_exports));
15320
- const a2aKeyStore = (0, import_core58.getStoreLattice)("default", "a2aApiKey").store;
15321
- const assistantStore = (0, import_core58.getStoreLattice)("default", "assistant").store;
15322
- const projectStore = (0, import_core58.getStoreLattice)("default", "project").store;
15323
- const taskStore = (0, import_core58.getStoreLattice)("default", "task").store;
16444
+ const a2aKeyStore = (0, import_core59.getStoreLattice)("default", "a2aApiKey").store;
16445
+ const assistantStore = (0, import_core59.getStoreLattice)("default", "assistant").store;
16446
+ const projectStore = (0, import_core59.getStoreLattice)("default", "project").store;
16447
+ const taskStore = (0, import_core59.getStoreLattice)("default", "task").store;
15324
16448
  const authService = new A2AAuthService2({
15325
16449
  keyStore: a2aKeyStore,
15326
16450
  assistantStore,
@@ -15344,17 +16468,17 @@ var start = async (config) => {
15344
16468
  error: err instanceof Error ? err.message : String(err)
15345
16469
  });
15346
16470
  }
15347
- if (!import_core58.sandboxLatticeManager.hasLattice("default")) {
15348
- import_core58.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
16471
+ if (!import_core59.sandboxLatticeManager.hasLattice("default")) {
16472
+ import_core59.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
15349
16473
  logger5.info("Registered sandbox manager from env configuration");
15350
16474
  }
15351
16475
  try {
15352
16476
  const { ResourceController: ResourceController2 } = await Promise.resolve().then(() => (init_resources(), resources_exports));
15353
- const sharedResourceStore = (0, import_core58.getStoreLattice)("default", "sharedResource").store;
15354
- const cache = new import_core58.TokenCache();
16477
+ const sharedResourceStore = (0, import_core59.getStoreLattice)("default", "sharedResource").store;
16478
+ const cache = new import_core59.TokenCache();
15355
16479
  const resourceController = new ResourceController2({
15356
16480
  store: sharedResourceStore,
15357
- sandboxManager: import_core58.sandboxLatticeManager,
16481
+ sandboxManager: import_core59.sandboxLatticeManager,
15358
16482
  cache,
15359
16483
  logger: logger5
15360
16484
  });
@@ -15390,7 +16514,7 @@ var start = async (config) => {
15390
16514
  }
15391
16515
  }
15392
16516
  if (process.env.AXIOM_RESTORE_PENDING_ON_STARTUP === "true") {
15393
- import_core58.agentInstanceManager.restore().then((stats) => {
16517
+ import_core59.agentInstanceManager.restore().then((stats) => {
15394
16518
  logger5.info(`Agent recovery complete: ${stats.restored} threads restored, ${stats.errors} errors`);
15395
16519
  }).catch((error) => {
15396
16520
  logger5.error("Agent recovery failed", { error });