@axiom-lattice/gateway 2.1.53 → 2.1.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/CHANGELOG.md +19 -0
  3. package/dist/index.js +1043 -526
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +977 -449
  6. package/dist/index.mjs.map +1 -1
  7. package/jest.config.js +5 -0
  8. package/package.json +6 -5
  9. package/src/__tests__/__mocks__/e2b.ts +1 -0
  10. package/src/__tests__/channel-installations.test.ts +199 -0
  11. package/src/__tests__/sandbox-provider-registration.test.ts +74 -0
  12. package/src/__tests__/workspace.test.ts +119 -8
  13. package/src/channels/__tests__/routes.test.ts +71 -0
  14. package/src/channels/lark/README.md +187 -0
  15. package/src/channels/lark/__tests__/aggregator.test.ts +23 -0
  16. package/src/channels/lark/__tests__/controller.test.ts +270 -0
  17. package/src/channels/lark/__tests__/mapping-service.test.ts +118 -0
  18. package/src/channels/lark/__tests__/parser.test.ts +72 -0
  19. package/src/channels/lark/__tests__/sender.test.ts +37 -0
  20. package/src/channels/lark/__tests__/verification.test.ts +157 -0
  21. package/src/channels/lark/aggregator.ts +16 -0
  22. package/src/channels/lark/config.ts +44 -0
  23. package/src/channels/lark/controller.ts +189 -0
  24. package/src/channels/lark/mapping-service.ts +138 -0
  25. package/src/channels/lark/parser.ts +68 -0
  26. package/src/channels/lark/routes.ts +121 -0
  27. package/src/channels/lark/runner.ts +37 -0
  28. package/src/channels/lark/sender.ts +58 -0
  29. package/src/channels/lark/types.ts +33 -0
  30. package/src/channels/lark/verification.ts +67 -0
  31. package/src/channels/routes.ts +25 -0
  32. package/src/controllers/channel-installations.ts +354 -0
  33. package/src/controllers/sandbox.ts +30 -80
  34. package/src/controllers/skills.ts +71 -321
  35. package/src/controllers/threads.ts +8 -6
  36. package/src/controllers/workspace.ts +64 -179
  37. package/src/index.ts +28 -5
  38. package/src/routes/channel-installations.ts +33 -0
  39. package/src/routes/index.ts +6 -0
  40. package/src/schemas/index.ts +2 -2
  41. package/src/services/sandbox_service.ts +21 -21
  42. package/src/services/skill_service.ts +97 -0
package/dist/index.js CHANGED
@@ -623,11 +623,13 @@ async function getThreadList(request, reply) {
623
623
  const tenantId = getTenantId2(request);
624
624
  const { assistantId } = request.params;
625
625
  const metadataFilter = {};
626
- if (request.query.workspaceId) {
627
- metadataFilter.workspaceId = request.query.workspaceId;
626
+ const workspaceId = request.headers["x-workspace-id"];
627
+ const projectId = request.headers["x-project-id"];
628
+ if (workspaceId) {
629
+ metadataFilter.workspaceId = workspaceId;
628
630
  }
629
- if (request.query.projectId) {
630
- metadataFilter.projectId = request.query.projectId;
631
+ if (projectId) {
632
+ metadataFilter.projectId = projectId;
631
633
  }
632
634
  const storeLattice = (0, import_core6.getStoreLattice)("default", "thread");
633
635
  const threadStore = storeLattice.store;
@@ -1267,16 +1269,63 @@ async function getHealth(request, reply) {
1267
1269
  }
1268
1270
  }
1269
1271
 
1270
- // src/controllers/skills.ts
1272
+ // src/services/skill_service.ts
1271
1273
  var import_core10 = require("@axiom-lattice/core");
1272
- var import_core11 = require("@axiom-lattice/core");
1273
1274
  function getTenantId4(request) {
1274
- const userTenantId = request.user?.tenantId;
1275
- if (userTenantId) {
1276
- return userTenantId;
1277
- }
1278
- return request.headers["x-tenant-id"] || "default";
1275
+ return request.user?.tenantId || request.headers["x-tenant-id"] || "default";
1276
+ }
1277
+ function getWorkspaceId(request) {
1278
+ return request.headers["x-workspace-id"];
1279
+ }
1280
+ function getProjectId(request) {
1281
+ return request.headers["x-project-id"];
1282
+ }
1283
+ function buildContext(request) {
1284
+ return {
1285
+ workspaceId: getWorkspaceId(request),
1286
+ projectId: getProjectId(request)
1287
+ };
1279
1288
  }
1289
+ var SkillService = class {
1290
+ constructor() {
1291
+ this.store = new import_core10.SandboxSkillStore();
1292
+ }
1293
+ async getAllSkills(request) {
1294
+ const tenantId = getTenantId4(request);
1295
+ return this.store.getAllSkills(tenantId, buildContext(request));
1296
+ }
1297
+ async getSkillById(request, id) {
1298
+ const tenantId = getTenantId4(request);
1299
+ return this.store.getSkillById(tenantId, id, buildContext(request));
1300
+ }
1301
+ async createSkill(request, id, data) {
1302
+ const tenantId = getTenantId4(request);
1303
+ return this.store.createSkill(tenantId, id, data, buildContext(request));
1304
+ }
1305
+ async updateSkill(request, id, updates) {
1306
+ const tenantId = getTenantId4(request);
1307
+ return this.store.updateSkill(tenantId, id, updates, buildContext(request));
1308
+ }
1309
+ async deleteSkill(request, id) {
1310
+ const tenantId = getTenantId4(request);
1311
+ return this.store.deleteSkill(tenantId, id, buildContext(request));
1312
+ }
1313
+ async searchByMetadata(request, key, value) {
1314
+ const tenantId = getTenantId4(request);
1315
+ return this.store.searchByMetadata(tenantId, key, value, buildContext(request));
1316
+ }
1317
+ async filterByCompatibility(request, compatibility) {
1318
+ const tenantId = getTenantId4(request);
1319
+ return this.store.filterByCompatibility(tenantId, compatibility, buildContext(request));
1320
+ }
1321
+ async filterByLicense(request, license) {
1322
+ const tenantId = getTenantId4(request);
1323
+ return this.store.filterByLicense(tenantId, license, buildContext(request));
1324
+ }
1325
+ };
1326
+
1327
+ // src/controllers/skills.ts
1328
+ var skillService = new SkillService();
1280
1329
  function serializeSkill(skill) {
1281
1330
  const serialized = {
1282
1331
  id: skill.id,
@@ -1287,192 +1336,100 @@ function serializeSkill(skill) {
1287
1336
  metadata: skill.metadata || {},
1288
1337
  content: skill.content,
1289
1338
  subSkills: skill.subSkills,
1290
- createdAt: skill.createdAt instanceof Date ? skill.createdAt.toISOString() : skill.createdAt ? new Date(skill.createdAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
1291
- updatedAt: skill.updatedAt instanceof Date ? skill.updatedAt.toISOString() : skill.updatedAt ? new Date(skill.updatedAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString()
1339
+ createdAt: skill.createdAt instanceof Date ? skill.createdAt.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
1340
+ updatedAt: skill.updatedAt instanceof Date ? skill.updatedAt.toISOString() : (/* @__PURE__ */ new Date()).toISOString()
1292
1341
  };
1293
1342
  Object.keys(serialized).forEach((key) => {
1294
- if (serialized[key] === void 0) {
1295
- delete serialized[key];
1296
- }
1343
+ if (serialized[key] === void 0) delete serialized[key];
1297
1344
  });
1298
1345
  return serialized;
1299
1346
  }
1300
1347
  async function getSkillList(request, reply) {
1301
1348
  try {
1302
- const tenantId = getTenantId4(request);
1303
- const storeLattice = (0, import_core10.getStoreLattice)("default", "skill");
1304
- const skillStore = storeLattice.store;
1305
- const skills = await skillStore.getAllSkills(tenantId);
1306
- const serializedSkills = skills.map(serializeSkill);
1349
+ const skills = await skillService.getAllSkills(request);
1307
1350
  return {
1308
1351
  success: true,
1309
1352
  message: "Successfully retrieved skill list",
1310
- data: {
1311
- records: serializedSkills,
1312
- total: serializedSkills.length
1313
- }
1353
+ data: { records: skills.map(serializeSkill), total: skills.length }
1314
1354
  };
1315
1355
  } catch (error) {
1316
1356
  return reply.status(500).send({
1317
1357
  success: false,
1318
1358
  message: `Failed to retrieve skills: ${error.message}`,
1319
- data: {
1320
- records: [],
1321
- total: 0
1322
- }
1359
+ data: { records: [], total: 0 }
1323
1360
  });
1324
1361
  }
1325
1362
  }
1326
1363
  async function getSkill(request, reply) {
1327
1364
  try {
1328
- const tenantId = getTenantId4(request);
1329
1365
  const { id } = request.params;
1330
- const storeLattice = (0, import_core10.getStoreLattice)("default", "skill");
1331
- const skillStore = storeLattice.store;
1332
- const skill = await skillStore.getSkillById(tenantId, id);
1366
+ const skill = await skillService.getSkillById(request, id);
1333
1367
  if (!skill) {
1334
- return reply.status(404).send({
1335
- success: false,
1336
- message: "Skill not found"
1337
- });
1368
+ return reply.status(404).send({ success: false, message: "Skill not found" });
1338
1369
  }
1339
- return {
1340
- success: true,
1341
- message: "Successfully retrieved skill",
1342
- data: serializeSkill(skill)
1343
- };
1370
+ return { success: true, message: "Successfully retrieved skill", data: serializeSkill(skill) };
1344
1371
  } catch (error) {
1345
- return reply.status(500).send({
1346
- success: false,
1347
- message: `Failed to retrieve skill: ${error.message}`
1348
- });
1372
+ return reply.status(500).send({ success: false, message: `Failed to retrieve skill: ${error.message}` });
1349
1373
  }
1350
1374
  }
1351
1375
  async function createSkill(request, reply) {
1352
1376
  try {
1353
1377
  const data = request.body;
1354
1378
  if (!data.name) {
1355
- return reply.status(400).send({
1356
- success: false,
1357
- message: "name is required"
1358
- });
1379
+ return reply.status(400).send({ success: false, message: "name is required" });
1359
1380
  }
1360
1381
  if (!data.description) {
1361
- return reply.status(400).send({
1362
- success: false,
1363
- message: "description is required"
1364
- });
1365
- }
1366
- try {
1367
- (0, import_core11.validateSkillName)(data.name);
1368
- } catch (error) {
1369
- return reply.status(400).send({
1370
- success: false,
1371
- message: error.message || "Invalid skill name format"
1372
- });
1382
+ return reply.status(400).send({ success: false, message: "description is required" });
1373
1383
  }
1374
1384
  const id = request.body.id || data.name;
1375
1385
  if (id !== data.name) {
1376
1386
  return reply.status(400).send({
1377
1387
  success: false,
1378
- message: `id "${id}" must equal name "${data.name}" (name is used for path addressing)`
1379
- });
1380
- }
1381
- const tenantId = getTenantId4(request);
1382
- const storeLattice = (0, import_core10.getStoreLattice)("default", "skill");
1383
- const skillStore = storeLattice.store;
1384
- const exists = await skillStore.hasSkill(tenantId, id);
1385
- if (exists) {
1386
- return reply.status(409).send({
1387
- success: false,
1388
- message: `Skill with id "${id}" already exists`
1388
+ message: `id "${id}" must equal name "${data.name}"`
1389
1389
  });
1390
1390
  }
1391
- const newSkill = await skillStore.createSkill(tenantId, id, data);
1391
+ const skill = await skillService.createSkill(request, id, data);
1392
1392
  return reply.status(201).send({
1393
1393
  success: true,
1394
1394
  message: "Successfully created skill",
1395
- data: serializeSkill(newSkill)
1395
+ data: serializeSkill(skill)
1396
1396
  });
1397
1397
  } catch (error) {
1398
- return reply.status(500).send({
1399
- success: false,
1400
- message: `Failed to create skill: ${error.message}`
1401
- });
1398
+ if (error.message?.includes("already exists")) {
1399
+ return reply.status(409).send({ success: false, message: error.message });
1400
+ }
1401
+ if (error.message?.includes("must equal name") || error.message?.includes("Invalid skill name")) {
1402
+ return reply.status(400).send({ success: false, message: error.message });
1403
+ }
1404
+ return reply.status(500).send({ success: false, message: `Failed to create skill: ${error.message}` });
1402
1405
  }
1403
1406
  }
1404
1407
  async function updateSkill(request, reply) {
1405
1408
  try {
1406
1409
  const { id } = request.params;
1407
1410
  const updates = request.body;
1408
- if (updates.name !== void 0) {
1409
- try {
1410
- (0, import_core11.validateSkillName)(updates.name);
1411
- } catch (error) {
1412
- return reply.status(400).send({
1413
- success: false,
1414
- message: error.message || "Invalid skill name format"
1415
- });
1416
- }
1417
- }
1418
- const tenantId = getTenantId4(request);
1419
- const storeLattice = (0, import_core10.getStoreLattice)("default", "skill");
1420
- const skillStore = storeLattice.store;
1421
- const exists = await skillStore.hasSkill(tenantId, id);
1422
- if (!exists) {
1423
- return reply.status(404).send({
1424
- success: false,
1425
- message: "Skill not found"
1426
- });
1427
- }
1428
- const updatedSkill = await skillStore.updateSkill(tenantId, id, updates);
1429
- if (!updatedSkill) {
1430
- return reply.status(500).send({
1431
- success: false,
1432
- message: "Failed to update skill"
1433
- });
1411
+ const skill = await skillService.updateSkill(request, id, updates);
1412
+ if (!skill) {
1413
+ return reply.status(404).send({ success: false, message: "Skill not found" });
1434
1414
  }
1435
- return {
1436
- success: true,
1437
- message: "Successfully updated skill",
1438
- data: serializeSkill(updatedSkill)
1439
- };
1415
+ return { success: true, message: "Successfully updated skill", data: serializeSkill(skill) };
1440
1416
  } catch (error) {
1441
- return reply.status(500).send({
1442
- success: false,
1443
- message: `Failed to update skill: ${error.message}`
1444
- });
1417
+ if (error.message?.includes("Invalid skill name")) {
1418
+ return reply.status(400).send({ success: false, message: error.message });
1419
+ }
1420
+ return reply.status(500).send({ success: false, message: `Failed to update skill: ${error.message}` });
1445
1421
  }
1446
1422
  }
1447
1423
  async function deleteSkill(request, reply) {
1448
1424
  try {
1449
1425
  const { id } = request.params;
1450
- const tenantId = getTenantId4(request);
1451
- const storeLattice = (0, import_core10.getStoreLattice)("default", "skill");
1452
- const skillStore = storeLattice.store;
1453
- const exists = await skillStore.hasSkill(tenantId, id);
1454
- if (!exists) {
1455
- return reply.status(404).send({
1456
- success: false,
1457
- message: "Skill not found"
1458
- });
1459
- }
1460
- const deleted = await skillStore.deleteSkill(tenantId, id);
1461
- if (!deleted) {
1462
- return reply.status(500).send({
1463
- success: false,
1464
- message: "Failed to delete skill"
1465
- });
1426
+ const result = await skillService.deleteSkill(request, id);
1427
+ if (!result) {
1428
+ return reply.status(404).send({ success: false, message: "Skill not found" });
1466
1429
  }
1467
- return {
1468
- success: true,
1469
- message: "Successfully deleted skill"
1470
- };
1430
+ return { success: true, message: "Successfully deleted skill" };
1471
1431
  } catch (error) {
1472
- return reply.status(500).send({
1473
- success: false,
1474
- message: `Failed to delete skill: ${error.message}`
1475
- });
1432
+ return reply.status(500).send({ success: false, message: `Failed to delete skill: ${error.message}` });
1476
1433
  }
1477
1434
  }
1478
1435
  async function searchSkillsByMetadata(request, reply) {
@@ -1482,33 +1439,20 @@ async function searchSkillsByMetadata(request, reply) {
1482
1439
  return reply.status(400).send({
1483
1440
  success: false,
1484
1441
  message: "key and value query parameters are required",
1485
- data: {
1486
- records: [],
1487
- total: 0
1488
- }
1442
+ data: { records: [], total: 0 }
1489
1443
  });
1490
1444
  }
1491
- const tenantId = getTenantId4(request);
1492
- const storeLattice = (0, import_core10.getStoreLattice)("default", "skill");
1493
- const skillStore = storeLattice.store;
1494
- const skills = await skillStore.searchByMetadata(tenantId, key, value);
1495
- const serializedSkills = skills.map(serializeSkill);
1445
+ const skills = await skillService.searchByMetadata(request, key, value);
1496
1446
  return {
1497
1447
  success: true,
1498
1448
  message: "Successfully searched skills",
1499
- data: {
1500
- records: serializedSkills,
1501
- total: serializedSkills.length
1502
- }
1449
+ data: { records: skills.map(serializeSkill), total: skills.length }
1503
1450
  };
1504
1451
  } catch (error) {
1505
1452
  return reply.status(500).send({
1506
1453
  success: false,
1507
1454
  message: `Failed to search skills: ${error.message}`,
1508
- data: {
1509
- records: [],
1510
- total: 0
1511
- }
1455
+ data: { records: [], total: 0 }
1512
1456
  });
1513
1457
  }
1514
1458
  }
@@ -1519,33 +1463,20 @@ async function filterSkillsByCompatibility(request, reply) {
1519
1463
  return reply.status(400).send({
1520
1464
  success: false,
1521
1465
  message: "compatibility query parameter is required",
1522
- data: {
1523
- records: [],
1524
- total: 0
1525
- }
1466
+ data: { records: [], total: 0 }
1526
1467
  });
1527
1468
  }
1528
- const tenantId = getTenantId4(request);
1529
- const storeLattice = (0, import_core10.getStoreLattice)("default", "skill");
1530
- const skillStore = storeLattice.store;
1531
- const skills = await skillStore.filterByCompatibility(tenantId, compatibility);
1532
- const serializedSkills = skills.map(serializeSkill);
1469
+ const skills = await skillService.filterByCompatibility(request, compatibility);
1533
1470
  return {
1534
1471
  success: true,
1535
1472
  message: "Successfully filtered skills",
1536
- data: {
1537
- records: serializedSkills,
1538
- total: serializedSkills.length
1539
- }
1473
+ data: { records: skills.map(serializeSkill), total: skills.length }
1540
1474
  };
1541
1475
  } catch (error) {
1542
1476
  return reply.status(500).send({
1543
1477
  success: false,
1544
1478
  message: `Failed to filter skills: ${error.message}`,
1545
- data: {
1546
- records: [],
1547
- total: 0
1548
- }
1479
+ data: { records: [], total: 0 }
1549
1480
  });
1550
1481
  }
1551
1482
  }
@@ -1556,39 +1487,26 @@ async function filterSkillsByLicense(request, reply) {
1556
1487
  return reply.status(400).send({
1557
1488
  success: false,
1558
1489
  message: "license query parameter is required",
1559
- data: {
1560
- records: [],
1561
- total: 0
1562
- }
1490
+ data: { records: [], total: 0 }
1563
1491
  });
1564
1492
  }
1565
- const tenantId = getTenantId4(request);
1566
- const storeLattice = (0, import_core10.getStoreLattice)("default", "skill");
1567
- const skillStore = storeLattice.store;
1568
- const skills = await skillStore.filterByLicense(tenantId, license);
1569
- const serializedSkills = skills.map(serializeSkill);
1493
+ const skills = await skillService.filterByLicense(request, license);
1570
1494
  return {
1571
1495
  success: true,
1572
1496
  message: "Successfully filtered skills",
1573
- data: {
1574
- records: serializedSkills,
1575
- total: serializedSkills.length
1576
- }
1497
+ data: { records: skills.map(serializeSkill), total: skills.length }
1577
1498
  };
1578
1499
  } catch (error) {
1579
1500
  return reply.status(500).send({
1580
1501
  success: false,
1581
1502
  message: `Failed to filter skills: ${error.message}`,
1582
- data: {
1583
- records: [],
1584
- total: 0
1585
- }
1503
+ data: { records: [], total: 0 }
1586
1504
  });
1587
1505
  }
1588
1506
  }
1589
1507
 
1590
1508
  // src/controllers/tools.ts
1591
- var import_core12 = require("@axiom-lattice/core");
1509
+ var import_core11 = require("@axiom-lattice/core");
1592
1510
  function serializeSchema(schema) {
1593
1511
  if (!schema) {
1594
1512
  return void 0;
@@ -1632,7 +1550,7 @@ function serializeSchema(schema) {
1632
1550
  }
1633
1551
  async function getToolConfigs(request, reply) {
1634
1552
  try {
1635
- const allLattices = import_core12.toolLatticeManager.getAllLattices();
1553
+ const allLattices = import_core11.toolLatticeManager.getAllLattices();
1636
1554
  const toolConfigs = allLattices.map((lattice) => {
1637
1555
  const config = { ...lattice.config };
1638
1556
  const serializedSchema = config.schema ? serializeSchema(config.schema) : void 0;
@@ -1670,7 +1588,7 @@ async function getToolConfigs(request, reply) {
1670
1588
  }
1671
1589
 
1672
1590
  // src/controllers/data-query.ts
1673
- var import_core13 = require("@axiom-lattice/core");
1591
+ var import_core12 = require("@axiom-lattice/core");
1674
1592
  function getTenantId5(request) {
1675
1593
  return request.headers["x-tenant-id"] || "default";
1676
1594
  }
@@ -1701,7 +1619,7 @@ async function executeDataQuery(request, reply) {
1701
1619
  message: "Cannot provide both metrics and customSql. Use one query type only."
1702
1620
  };
1703
1621
  }
1704
- const storeLattice = (0, import_core13.getStoreLattice)("default", "metrics");
1622
+ const storeLattice = (0, import_core12.getStoreLattice)("default", "metrics");
1705
1623
  const store = storeLattice.store;
1706
1624
  if (!body.serverKey) {
1707
1625
  reply.code(400);
@@ -1732,14 +1650,14 @@ async function executeDataQuery(request, reply) {
1732
1650
  message: "datasourceId is required"
1733
1651
  };
1734
1652
  }
1735
- if (!import_core13.metricsServerManager.hasServer(tenantId, body.serverKey)) {
1653
+ if (!import_core12.metricsServerManager.hasServer(tenantId, body.serverKey)) {
1736
1654
  reply.code(400);
1737
1655
  return {
1738
1656
  success: false,
1739
1657
  message: `Metrics server not registered: ${body.serverKey}. Please register the server first.`
1740
1658
  };
1741
1659
  }
1742
- const client = import_core13.metricsServerManager.getClient(tenantId, body.serverKey);
1660
+ const client = import_core12.metricsServerManager.getClient(tenantId, body.serverKey);
1743
1661
  if (isSemanticQuery) {
1744
1662
  return await executeSemanticQuery(client, body, reply);
1745
1663
  } else {
@@ -2147,7 +2065,7 @@ var getHealthSchema = {
2147
2065
  };
2148
2066
 
2149
2067
  // src/controllers/thread_status.ts
2150
- var import_core14 = require("@axiom-lattice/core");
2068
+ var import_core13 = require("@axiom-lattice/core");
2151
2069
  async function removePendingMessageHandler(request, reply) {
2152
2070
  try {
2153
2071
  const { assistant_id, thread_id, message_id } = request.params;
@@ -2160,7 +2078,7 @@ async function removePendingMessageHandler(request, reply) {
2160
2078
  if (!assistant_id) {
2161
2079
  return reply.code(400).send({ error: "Missing assistant_id parameter" });
2162
2080
  }
2163
- const agent = import_core14.agentInstanceManager.getAgent({
2081
+ const agent = import_core13.agentInstanceManager.getAgent({
2164
2082
  assistant_id,
2165
2083
  thread_id,
2166
2084
  tenant_id,
@@ -2193,11 +2111,8 @@ async function removePendingMessageHandler(request, reply) {
2193
2111
  }
2194
2112
  }
2195
2113
 
2196
- // src/controllers/sandbox.ts
2197
- var import_stream = require("stream");
2198
-
2199
2114
  // src/services/sandbox_service.ts
2200
- var import_core15 = require("@axiom-lattice/core");
2115
+ var import_core14 = require("@axiom-lattice/core");
2201
2116
  var ERROR_HTML = `<!DOCTYPE html>
2202
2117
  <html lang="zh-CN">
2203
2118
  <head>
@@ -2289,7 +2204,7 @@ var ERROR_HTML = `<!DOCTYPE html>
2289
2204
  </div>
2290
2205
  <div class="info-item">
2291
2206
  <span class="label">\u9694\u79BB\u7EA7\u522B</span>
2292
- <span class="value" id="isolatedLevel">-</span>
2207
+ <span class="value" id="vmIsolation">-</span>
2293
2208
  </div>
2294
2209
  <div class="info-item">
2295
2210
  <span class="label">\u9519\u8BEF\u4FE1\u606F</span>
@@ -2302,14 +2217,14 @@ var ERROR_HTML = `<!DOCTYPE html>
2302
2217
  const params = new URLSearchParams(window.location.search);
2303
2218
  document.getElementById('assistantId').textContent = params.get('assistantId') || '-';
2304
2219
  document.getElementById('threadId').textContent = params.get('threadId') || '-';
2305
- document.getElementById('isolatedLevel').textContent = params.get('isolatedLevel') || '-';
2220
+ document.getElementById('vmIsolation').textContent = params.get('vmIsolation') || '-';
2306
2221
  document.getElementById('errorMsg').textContent = params.get('error') || '\u672A\u77E5\u9519\u8BEF';
2307
2222
  </script>
2308
2223
  </body>
2309
2224
  </html>`;
2310
2225
  var SandboxService = class {
2311
- getFilesystemIsolatedLevel(tenantId, assistantId) {
2312
- const agentLattice = import_core15.agentLatticeManager.getAgentLatticeWithTenant(tenantId, assistantId);
2226
+ getFilesystemVmIsolation(tenantId, assistantId) {
2227
+ const agentLattice = import_core14.agentLatticeManager.getAgentLatticeWithTenant(tenantId, assistantId);
2313
2228
  if (!agentLattice) {
2314
2229
  return null;
2315
2230
  }
@@ -2318,27 +2233,26 @@ var SandboxService = class {
2318
2233
  return null;
2319
2234
  }
2320
2235
  const config = filesystemConfig.config;
2321
- return config?.isolatedLevel || null;
2236
+ return config?.vmIsolation || null;
2322
2237
  }
2323
- computeSandboxName(assistantId, threadId, isolatedLevel) {
2324
- let sandboxName;
2325
- switch (isolatedLevel) {
2238
+ computeSandboxName(assistantId, threadId, vmIsolation, tenantId, workspaceId, projectId) {
2239
+ switch (vmIsolation) {
2326
2240
  case "agent":
2327
- sandboxName = assistantId;
2328
- break;
2329
- case "thread":
2330
- sandboxName = threadId;
2331
- break;
2241
+ return (0, import_core14.normalizeSandboxName)(`${tenantId ?? "default"}-${assistantId}`);
2242
+ case "project":
2243
+ return (0, import_core14.normalizeSandboxName)(
2244
+ `${tenantId ?? "default"}-${workspaceId ?? "default"}-${projectId ?? "default"}`
2245
+ );
2332
2246
  case "global":
2333
2247
  default:
2334
- sandboxName = "global";
2335
- break;
2248
+ return "global";
2336
2249
  }
2337
- return (0, import_core15.normalizeSandboxName)(sandboxName);
2250
+ }
2251
+ getBrowserSandboxBaseURL() {
2252
+ return process.env.AGENT_INFRA_SANDBOX_BASE_URL || "http://localhost:8080";
2338
2253
  }
2339
2254
  getTargetUrl(sandboxName) {
2340
- const sandboxManager = (0, import_core15.getSandBoxManager)();
2341
- return `${sandboxManager.getBaseURL()}/sandbox/${sandboxName}`;
2255
+ return `${this.getBrowserSandboxBaseURL()}/sandbox/${sandboxName}`;
2342
2256
  }
2343
2257
  async getVncHtml(sandboxName) {
2344
2258
  const response = await fetch(`${this.getTargetUrl(sandboxName)}/vnc/index.html`);
@@ -2374,15 +2288,15 @@ var SandboxService = class {
2374
2288
  );
2375
2289
  return rewritten;
2376
2290
  }
2377
- generateErrorHtml(assistantId, threadId, isolatedLevel, errorMessage) {
2291
+ generateErrorHtml(assistantId, threadId, vmIsolation, errorMessage) {
2378
2292
  const encodedError = encodeURIComponent(errorMessage);
2379
- return ERROR_HTML.replace("{assistantId}", assistantId).replace("{threadId}", threadId).replace("{isolatedLevel}", isolatedLevel).replace("{errorMessage}", errorMessage);
2293
+ return ERROR_HTML.replace("{assistantId}", assistantId).replace("{threadId}", threadId).replace("{vmIsolation}", vmIsolation).replace("{errorMessage}", errorMessage);
2380
2294
  }
2381
2295
  };
2382
2296
  var sandboxService = new SandboxService();
2383
2297
 
2384
2298
  // src/controllers/sandbox.ts
2385
- var import_core16 = require("@axiom-lattice/core");
2299
+ var import_core15 = require("@axiom-lattice/core");
2386
2300
  function getFilenameFromPath(path3) {
2387
2301
  const segments = path3.replace(/\/+$/, "").split("/");
2388
2302
  return segments[segments.length - 1] || "download";
@@ -2415,16 +2329,16 @@ function registerSandboxProxyRoutes(app2) {
2415
2329
  console.log("[Sandbox Upload] Route matched:", request.url);
2416
2330
  const { assistantId, threadId } = request.params;
2417
2331
  const tenantId = request.headers["x-tenant-id"] || "default";
2418
- const isolatedLevel = sandboxService.getFilesystemIsolatedLevel(tenantId, assistantId);
2419
- if (!isolatedLevel) {
2332
+ const vmIsolation = sandboxService.getFilesystemVmIsolation(tenantId, assistantId);
2333
+ if (!vmIsolation) {
2420
2334
  return reply.status(500).send({ error: "Assistant sandbox config not found" });
2421
2335
  }
2422
2336
  const sandboxName = sandboxService.computeSandboxName(
2423
2337
  assistantId,
2424
2338
  threadId,
2425
- isolatedLevel
2339
+ vmIsolation
2426
2340
  );
2427
- const sandboxManager = (0, import_core16.getSandBoxManager)();
2341
+ const sandboxManager = (0, import_core15.getSandBoxManager)();
2428
2342
  const sandbox = await sandboxManager.createSandbox(sandboxName);
2429
2343
  try {
2430
2344
  const data = await request.file();
@@ -2434,17 +2348,14 @@ function registerSandboxProxyRoutes(app2) {
2434
2348
  const buffer = await data.toBuffer();
2435
2349
  const pathEntry = data.fields?.path;
2436
2350
  const pathValue = pathEntry && typeof pathEntry === "object" && "value" in pathEntry ? String(pathEntry.value) : typeof pathEntry === "string" ? pathEntry : void 0;
2437
- const formData = new FormData();
2438
- formData.append("file", new Blob([buffer]), data.filename ?? "file");
2439
- const path3 = `/home/gem/uploads/${pathValue ? pathValue : ""}${data.filename}`;
2440
- const uploadResult = await sandbox.file.uploadFile({
2441
- file: buffer,
2442
- path: path3
2443
- });
2444
- if (!uploadResult.ok) {
2445
- return reply.status(502).send({ error: `Upload error: ${uploadResult.error}` });
2351
+ const filePath = `~/uploads/${pathValue ? pathValue : ""}${data.filename}`;
2352
+ try {
2353
+ await sandbox.file.uploadFile({ file: filePath, data: buffer });
2354
+ } catch (err) {
2355
+ reply.status(500).send({ error: String(err) });
2356
+ return;
2446
2357
  }
2447
- const relativePath = uploadResult.body?.data?.file_path.replace(`/home/gem`, "");
2358
+ const relativePath = filePath.replace(`~/`, "");
2448
2359
  const result = { id: relativePath, name: data.filename, size: buffer.length };
2449
2360
  return reply.status(200).send({ message: "File uploaded successfully", ...result });
2450
2361
  } catch (error) {
@@ -2462,59 +2373,30 @@ function registerSandboxProxyRoutes(app2) {
2462
2373
  if (!filePath || typeof filePath !== "string") {
2463
2374
  return reply.status(400).send({ error: "Query parameter 'path' is required" });
2464
2375
  }
2465
- const isolatedLevel = sandboxService.getFilesystemIsolatedLevel(tenantId, assistantId);
2466
- if (!isolatedLevel) {
2467
- return reply.status(500).send({ error: "Assistant filesystem isolated level not found" });
2376
+ const vmIsolation = sandboxService.getFilesystemVmIsolation(tenantId, assistantId);
2377
+ if (!vmIsolation) {
2378
+ return reply.status(500).send({ error: "Assistant filesystem vmIsolation not found" });
2468
2379
  }
2469
2380
  const sandboxName = sandboxService.computeSandboxName(
2470
2381
  assistantId,
2471
2382
  threadId,
2472
- isolatedLevel
2383
+ vmIsolation
2473
2384
  );
2474
- const sandboxManager = (0, import_core16.getSandBoxManager)();
2385
+ const sandboxManager = (0, import_core15.getSandBoxManager)();
2475
2386
  const sandbox = await sandboxManager.createSandbox(sandboxName);
2476
2387
  try {
2477
- const resolvedPath = filePath.startsWith("/home/gem") ? filePath : `/home/gem/${filePath.replace(/^\//, "")}`;
2388
+ const resolvedPath = filePath.startsWith("~/") ? filePath : `~/${filePath.replace(/^\//, "")}`;
2478
2389
  const filename = getFilenameFromPath(resolvedPath);
2479
2390
  const inferredContentType = getContentTypeFromFilename(filename);
2480
- const downloadResult = await sandbox.file.downloadFile({
2481
- path: resolvedPath
2482
- });
2483
- if (!downloadResult.ok) {
2484
- return reply.status(502).send({
2485
- error: `Download error: ${JSON.stringify(downloadResult.error)}`
2486
- });
2487
- }
2488
- const body = downloadResult.body;
2489
- if (typeof body?.stream === "function") {
2490
- const webStream = body.stream();
2491
- const nodeStream = import_stream.Readable.fromWeb(webStream);
2492
- const contentType2 = body.contentType ?? inferredContentType;
2493
- const contentDisposition2 = body.contentDisposition ?? `inline; filename="${filename.replace(/"/g, '\\"')}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
2494
- reply = reply.status(200).type(contentType2).header("Content-Disposition", contentDisposition2).send(nodeStream);
2391
+ try {
2392
+ const buf = await sandbox.file.downloadFile({ file: resolvedPath });
2393
+ const contentDisposition = `inline; filename="${filename.replace(/"/g, '\\"')}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
2394
+ reply = reply.status(200).type(inferredContentType).header("Content-Disposition", contentDisposition).send(buf);
2495
2395
  return reply;
2396
+ } catch (err) {
2397
+ reply.status(500).send({ error: String(err) });
2398
+ return;
2496
2399
  }
2497
- const bodyUnknown = downloadResult.body;
2498
- let buf;
2499
- let contentType = inferredContentType;
2500
- let contentDisposition = `inline; filename="${filename.replace(/"/g, '\\"')}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
2501
- if (bodyUnknown instanceof ArrayBuffer) {
2502
- buf = Buffer.from(bodyUnknown);
2503
- } else if (bodyUnknown instanceof Buffer) {
2504
- buf = bodyUnknown;
2505
- } else if (bodyUnknown && typeof bodyUnknown.arrayBuffer === "function") {
2506
- const res = bodyUnknown;
2507
- buf = Buffer.from(await res.arrayBuffer());
2508
- if (res.headers?.get("content-type")) contentType = res.headers.get("content-type");
2509
- if (res.headers?.get("content-disposition")) contentDisposition = res.headers.get("content-disposition");
2510
- } else if (bodyUnknown && typeof bodyUnknown.blob === "function") {
2511
- const blob = await bodyUnknown.blob();
2512
- buf = Buffer.from(await blob.arrayBuffer());
2513
- } else {
2514
- return reply.status(502).send({ error: "Unexpected download response format" });
2515
- }
2516
- reply = reply.status(200).type(contentType).header("Content-Disposition", contentDisposition).send(buf);
2517
- return reply;
2518
2400
  } catch (error) {
2519
2401
  const message = error instanceof Error ? error.message : String(error);
2520
2402
  return reply.status(502).send({ error: `Download proxy error: ${message}` });
@@ -2526,15 +2408,14 @@ function registerSandboxProxyRoutes(app2) {
2526
2408
  // src/controllers/workspace.ts
2527
2409
  var fs = __toESM(require("fs/promises"));
2528
2410
  var path = __toESM(require("path"));
2529
- var import_stream2 = require("stream");
2411
+ var import_core16 = require("@axiom-lattice/core");
2530
2412
  var import_core17 = require("@axiom-lattice/core");
2531
2413
  var import_core18 = require("@axiom-lattice/core");
2532
- var import_core19 = require("@axiom-lattice/core");
2533
2414
  var import_uuid2 = require("uuid");
2534
2415
  var WorkspaceController = class {
2535
2416
  constructor() {
2536
- this.workspaceStore = (0, import_core17.getStoreLattice)("default", "workspace").store;
2537
- this.projectStore = (0, import_core17.getStoreLattice)("default", "project").store;
2417
+ this.workspaceStore = (0, import_core16.getStoreLattice)("default", "workspace").store;
2418
+ this.projectStore = (0, import_core16.getStoreLattice)("default", "project").store;
2538
2419
  }
2539
2420
  getTenantId(request) {
2540
2421
  const userTenantId = request.user?.tenantId;
@@ -2667,19 +2548,23 @@ var WorkspaceController = class {
2667
2548
  throw new Error("Workspace not found");
2668
2549
  }
2669
2550
  if (workspace.storageType === "sandbox") {
2670
- const sandboxManager = (0, import_core19.getSandBoxManager)();
2671
- const sandboxName = "global";
2672
- const sandbox = await sandboxManager.createSandbox(sandboxName);
2551
+ const sandboxManager = (0, import_core18.getSandBoxManager)();
2552
+ const sandbox = await sandboxManager.getSandboxFromConfig({
2553
+ assistant_id: "",
2554
+ thread_id: "",
2555
+ tenantId,
2556
+ workspaceId,
2557
+ projectId
2558
+ });
2673
2559
  return {
2674
- backend: new import_core18.SandboxFilesystem({
2675
- sandboxInstance: sandbox,
2676
- workingDirectory: `/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`
2560
+ backend: new import_core17.SandboxFilesystem({
2561
+ sandboxInstance: sandbox
2677
2562
  }),
2678
2563
  workspace
2679
2564
  };
2680
2565
  } else {
2681
2566
  return {
2682
- backend: new import_core18.FilesystemBackend({
2567
+ backend: new import_core17.FilesystemBackend({
2683
2568
  rootDir: `/lattice_store/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`,
2684
2569
  virtualMode: true
2685
2570
  }),
@@ -2722,50 +2607,26 @@ var WorkspaceController = class {
2722
2607
  }
2723
2608
  try {
2724
2609
  const { workspace } = await this.getBackend(tenantId, workspaceId, projectId);
2725
- const resolvedPath = filePath.startsWith("/") ? filePath : `/${filePath}`;
2610
+ const resolvedPath = filePath;
2726
2611
  if (workspace.storageType === "sandbox") {
2727
- const sandboxManager = (0, import_core19.getSandBoxManager)();
2728
- const sandbox = await sandboxManager.createSandbox("global");
2729
- const realPath = path.join("/home/gem/tenants", tenantId, "workspaces", workspaceId, projectId, resolvedPath);
2612
+ const sandboxManager = (0, import_core18.getSandBoxManager)();
2613
+ const sandbox = await sandboxManager.getSandboxFromConfig({
2614
+ assistant_id: "",
2615
+ thread_id: "",
2616
+ tenantId,
2617
+ workspaceId,
2618
+ projectId
2619
+ });
2620
+ const realPath = resolvedPath;
2730
2621
  const filename2 = this.getFilenameFromPath(resolvedPath);
2731
2622
  const inferredContentType = this.getMimeType(filename2);
2732
- const downloadResult = await sandbox.file.downloadFile({
2733
- path: realPath
2734
- });
2735
- if (!downloadResult.ok) {
2736
- return reply.status(502).send({
2737
- success: false,
2738
- error: `Download error: ${JSON.stringify(downloadResult.error)}`
2739
- });
2740
- }
2741
- const body = downloadResult.body;
2742
- if (typeof body?.stream === "function") {
2743
- const webStream = body.stream();
2744
- const nodeStream = import_stream2.Readable.fromWeb(webStream);
2745
- const contentType2 = body.contentType ?? inferredContentType;
2746
- const contentDisposition2 = body.contentDisposition ?? `attachment; filename*=UTF-8''${encodeURIComponent(filename2)}`;
2747
- return reply.status(200).type(contentType2).header("Content-Disposition", contentDisposition2).send(nodeStream);
2748
- }
2749
- const bodyUnknown = downloadResult.body;
2750
- let buf;
2751
- let contentType = inferredContentType;
2752
- let contentDisposition = `attachment; filename*=UTF-8''${encodeURIComponent(filename2)}`;
2753
- if (bodyUnknown instanceof ArrayBuffer) {
2754
- buf = Buffer.from(bodyUnknown);
2755
- } else if (bodyUnknown instanceof Buffer) {
2756
- buf = bodyUnknown;
2757
- } else if (bodyUnknown && typeof bodyUnknown.arrayBuffer === "function") {
2758
- const res = bodyUnknown;
2759
- buf = Buffer.from(await res.arrayBuffer());
2760
- if (res.headers?.get("content-type")) contentType = res.headers.get("content-type");
2761
- if (res.headers?.get("content-disposition")) contentDisposition = res.headers.get("content-disposition");
2762
- } else if (bodyUnknown && typeof bodyUnknown.blob === "function") {
2763
- const blob = await bodyUnknown.blob();
2764
- buf = Buffer.from(await blob.arrayBuffer());
2765
- } else {
2766
- return reply.status(502).send({ success: false, error: "Unexpected download response format" });
2623
+ try {
2624
+ const buf = await sandbox.file.downloadFile({ file: realPath });
2625
+ const contentDisposition = `attachment; filename*=UTF-8''${encodeURIComponent(filename2)}`;
2626
+ return reply.status(200).type(inferredContentType).header("Content-Disposition", contentDisposition).send(buf);
2627
+ } catch (err) {
2628
+ return reply.status(502).send({ success: false, error: String(err) });
2767
2629
  }
2768
- return reply.status(200).type(contentType).header("Content-Disposition", contentDisposition).send(buf);
2769
2630
  }
2770
2631
  const { backend } = await this.getBackend(tenantId, workspaceId, projectId);
2771
2632
  const content = await backend.read(resolvedPath, 0, Infinity);
@@ -2791,36 +2652,27 @@ var WorkspaceController = class {
2791
2652
  }
2792
2653
  try {
2793
2654
  const { workspace } = await this.getBackend(tenantId, workspaceId, projectId);
2794
- const resolvedPath = filePath.startsWith("/") ? filePath : `/${filePath}`;
2655
+ const resolvedPath = filePath;
2795
2656
  if (workspace.storageType === "sandbox") {
2796
- const sandboxManager = (0, import_core19.getSandBoxManager)();
2797
- const sandbox = await sandboxManager.createSandbox("global");
2798
- const realPath = path.join("/home/gem/tenants", tenantId, "workspaces", workspaceId, projectId, resolvedPath);
2657
+ const sandboxManager = (0, import_core18.getSandBoxManager)();
2658
+ const sandbox = await sandboxManager.getSandboxFromConfig({
2659
+ assistant_id: "",
2660
+ thread_id: "",
2661
+ tenantId,
2662
+ workspaceId,
2663
+ projectId
2664
+ });
2665
+ const realPath = resolvedPath;
2799
2666
  const filename2 = this.getFilenameFromPath(resolvedPath);
2800
2667
  const inferredContentType = this.getMimeType(filename2);
2801
- const downloadResult = await sandbox.file.downloadFile({
2802
- path: realPath
2803
- });
2804
- if (!downloadResult.ok) {
2805
- return reply.status(502).send({
2806
- success: false,
2807
- error: `View error: ${JSON.stringify(downloadResult.error)}`
2808
- });
2809
- }
2810
- const body = downloadResult.body;
2811
- if (typeof body?.stream === "function") {
2812
- const webStream = body.stream();
2813
- const nodeStream = import_stream2.Readable.fromWeb(webStream);
2814
- const contentType2 = body.contentType ?? inferredContentType;
2815
- console.log(`[viewFile] Sandbox returned stream, contentType: ${contentType2}, filename: ${filename2}`);
2816
- const isHtml2 = contentType2?.toLowerCase().includes("text/html") || filename2.toLowerCase().endsWith(".html") || filename2.toLowerCase().endsWith(".htm");
2817
- if (isHtml2) {
2818
- console.log(`[viewFile] HTML stream detected, collecting for context injection`);
2819
- const chunks = [];
2820
- for await (const chunk of nodeStream) {
2821
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
2822
- }
2823
- let content2 = Buffer.concat(chunks).toString("utf-8");
2668
+ try {
2669
+ const buf = await sandbox.file.downloadFile({ file: realPath });
2670
+ let contentType = inferredContentType;
2671
+ const isHtml = contentType?.toLowerCase().includes("text/html") || filename2.toLowerCase().endsWith(".html") || filename2.toLowerCase().endsWith(".htm");
2672
+ let outputBuf = buf;
2673
+ if (isHtml) {
2674
+ console.log(`[viewFile] Injecting AI2APP context for sandbox HTML file: ${filename2}, tenantId: ${tenantId}, contentType: ${contentType}`);
2675
+ let content2 = buf.toString("utf-8");
2824
2676
  const contextScript = `<script>window.__AI2APP_CONTEXT__=${JSON.stringify({
2825
2677
  tenantId,
2826
2678
  workspaceId,
@@ -2829,58 +2681,20 @@ var WorkspaceController = class {
2829
2681
  })};</script>`;
2830
2682
  if (content2.toLowerCase().includes("</head>")) {
2831
2683
  content2 = content2.replace(/<\/head>/i, `${contextScript}</head>`);
2832
- console.log(`[viewFile] Context script injected before </head> (stream)`);
2684
+ console.log(`[viewFile] Context script injected before </head>`);
2833
2685
  } else if (content2.toLowerCase().includes("<html>")) {
2834
2686
  content2 = content2.replace(/<html>/i, `<html>${contextScript}`);
2835
- console.log(`[viewFile] Context script injected after <html> (stream)`);
2687
+ console.log(`[viewFile] Context script injected after <html>`);
2836
2688
  } else {
2837
2689
  content2 = contextScript + content2;
2838
- console.log(`[viewFile] Context script prepended to content (stream)`);
2690
+ console.log(`[viewFile] Context script prepended to content`);
2839
2691
  }
2840
- return reply.status(200).type(contentType2).header("Content-Disposition", "inline").send(Buffer.from(content2, "utf-8"));
2841
- }
2842
- return reply.status(200).type(contentType2).header("Content-Disposition", "inline").send(nodeStream);
2843
- }
2844
- const bodyUnknown = downloadResult.body;
2845
- let buf;
2846
- let contentType = inferredContentType;
2847
- if (bodyUnknown instanceof ArrayBuffer) {
2848
- buf = Buffer.from(bodyUnknown);
2849
- } else if (bodyUnknown instanceof Buffer) {
2850
- buf = bodyUnknown;
2851
- } else if (bodyUnknown && typeof bodyUnknown.arrayBuffer === "function") {
2852
- const res = bodyUnknown;
2853
- buf = Buffer.from(await res.arrayBuffer());
2854
- if (res.headers?.get("content-type")) contentType = res.headers.get("content-type");
2855
- } else if (bodyUnknown && typeof bodyUnknown.blob === "function") {
2856
- const blob = await bodyUnknown.blob();
2857
- buf = Buffer.from(await blob.arrayBuffer());
2858
- } else {
2859
- return reply.status(502).send({ success: false, error: "Unexpected view response format" });
2860
- }
2861
- const isHtml = contentType?.toLowerCase().includes("text/html") || filename2.toLowerCase().endsWith(".html") || filename2.toLowerCase().endsWith(".htm");
2862
- if (isHtml) {
2863
- console.log(`[viewFile] Injecting AI2APP context for sandbox HTML file: ${filename2}, tenantId: ${tenantId}, contentType: ${contentType}`);
2864
- let content2 = buf.toString("utf-8");
2865
- const contextScript = `<script>window.__AI2APP_CONTEXT__=${JSON.stringify({
2866
- tenantId,
2867
- workspaceId,
2868
- projectId,
2869
- timestamp: Date.now()
2870
- })};</script>`;
2871
- if (content2.toLowerCase().includes("</head>")) {
2872
- content2 = content2.replace(/<\/head>/i, `${contextScript}</head>`);
2873
- console.log(`[viewFile] Context script injected before </head>`);
2874
- } else if (content2.toLowerCase().includes("<html>")) {
2875
- content2 = content2.replace(/<html>/i, `<html>${contextScript}`);
2876
- console.log(`[viewFile] Context script injected after <html>`);
2877
- } else {
2878
- content2 = contextScript + content2;
2879
- console.log(`[viewFile] Context script prepended to content`);
2692
+ outputBuf = Buffer.from(content2, "utf-8");
2880
2693
  }
2881
- buf = Buffer.from(content2, "utf-8");
2694
+ return reply.status(200).type(contentType).header("Content-Disposition", "inline").send(outputBuf);
2695
+ } catch (err) {
2696
+ return reply.status(502).send({ success: false, error: String(err) });
2882
2697
  }
2883
- return reply.status(200).type(contentType).header("Content-Disposition", "inline").send(buf);
2884
2698
  }
2885
2699
  const { backend } = await this.getBackend(tenantId, workspaceId, projectId);
2886
2700
  const content = await backend.read(resolvedPath, 0, Infinity);
@@ -2959,26 +2773,25 @@ var WorkspaceController = class {
2959
2773
  const filename = data.filename || "file";
2960
2774
  const pathEntry = data.fields?.path;
2961
2775
  const pathValue = pathEntry && typeof pathEntry === "object" && "value" in pathEntry ? String(pathEntry.value) : typeof pathEntry === "string" ? pathEntry : void 0;
2962
- if (pathValue && !/^[a-zA-Z0-9_./-]+$/.test(pathValue)) {
2776
+ if (pathValue && !/^[a-zA-Z0-9_./~\-]+$/.test(pathValue)) {
2963
2777
  return reply.status(400).send({ success: false, error: "Invalid path parameter" });
2964
2778
  }
2965
2779
  if (workspace.storageType === "sandbox") {
2966
- const sandboxManager = (0, import_core19.getSandBoxManager)();
2967
- const sandboxName = "global";
2968
- const sandbox = await sandboxManager.createSandbox(sandboxName);
2969
- const baseDir = path.join("/home/gem/tenants", tenantId, "workspaces", workspaceId, projectId);
2970
- const realPath = pathValue ? path.join(baseDir, pathValue, filename) : path.join(baseDir, filename);
2971
- const uploadResult = await sandbox.file.uploadFile({
2972
- file: buffer,
2973
- path: realPath
2974
- }, { timeoutInSeconds: 300 });
2975
- if (!uploadResult.ok) {
2976
- return reply.status(502).send({
2977
- success: false,
2978
- error: `Upload error: ${JSON.stringify(uploadResult.error)}`
2979
- });
2780
+ const sandboxManager = (0, import_core18.getSandBoxManager)();
2781
+ const sandbox = await sandboxManager.getSandboxFromConfig({
2782
+ assistant_id: "",
2783
+ thread_id: "",
2784
+ tenantId,
2785
+ workspaceId,
2786
+ projectId
2787
+ });
2788
+ const realPath = pathValue ? path.posix.join(pathValue, filename) : filename;
2789
+ try {
2790
+ await sandbox.file.uploadFile({ file: realPath, data: buffer });
2791
+ } catch (err) {
2792
+ return reply.status(500).send({ success: false, error: String(err) });
2980
2793
  }
2981
- const relativePath = uploadResult.body?.data?.file_path?.replace(path.join("/home/gem/tenants", tenantId, "workspaces", workspaceId, projectId), "") || (pathValue ? `/${pathValue}/${filename}` : `/${filename}`);
2794
+ const relativePath = pathValue ? path.posix.join(pathValue, filename) : `/${filename}`;
2982
2795
  const result2 = {
2983
2796
  path: relativePath,
2984
2797
  name: filename,
@@ -3069,7 +2882,7 @@ function registerWorkspaceRoutes(app2) {
3069
2882
  }
3070
2883
 
3071
2884
  // src/controllers/database-configs.ts
3072
- var import_core20 = require("@axiom-lattice/core");
2885
+ var import_core19 = require("@axiom-lattice/core");
3073
2886
  var import_crypto3 = require("crypto");
3074
2887
  function getTenantId6(request) {
3075
2888
  const userTenantId = request.user?.tenantId;
@@ -3081,7 +2894,7 @@ function getTenantId6(request) {
3081
2894
  async function getDatabaseConfigList(request, reply) {
3082
2895
  const tenantId = getTenantId6(request);
3083
2896
  try {
3084
- const storeLattice = (0, import_core20.getStoreLattice)("default", "database");
2897
+ const storeLattice = (0, import_core19.getStoreLattice)("default", "database");
3085
2898
  const store = storeLattice.store;
3086
2899
  const configs = await store.getAllConfigs(tenantId);
3087
2900
  console.log("Backend: getAllConfigs returned:", configs);
@@ -3112,7 +2925,7 @@ async function getDatabaseConfig(request, reply) {
3112
2925
  const tenantId = getTenantId6(request);
3113
2926
  const { key } = request.params;
3114
2927
  try {
3115
- const storeLattice = (0, import_core20.getStoreLattice)("default", "database");
2928
+ const storeLattice = (0, import_core19.getStoreLattice)("default", "database");
3116
2929
  const store = storeLattice.store;
3117
2930
  const config = await store.getConfigByKey(tenantId, key);
3118
2931
  if (!config) {
@@ -3138,7 +2951,7 @@ async function createDatabaseConfig(request, reply) {
3138
2951
  const tenantId = getTenantId6(request);
3139
2952
  const body = request.body;
3140
2953
  try {
3141
- const storeLattice = (0, import_core20.getStoreLattice)("default", "database");
2954
+ const storeLattice = (0, import_core19.getStoreLattice)("default", "database");
3142
2955
  const store = storeLattice.store;
3143
2956
  const existing = await store.getConfigByKey(tenantId, body.key);
3144
2957
  if (existing) {
@@ -3151,7 +2964,7 @@ async function createDatabaseConfig(request, reply) {
3151
2964
  const id = body.id || (0, import_crypto3.randomUUID)();
3152
2965
  const config = await store.createConfig(tenantId, id, body);
3153
2966
  try {
3154
- import_core20.sqlDatabaseManager.registerDatabase(tenantId, config.key, config.config);
2967
+ import_core19.sqlDatabaseManager.registerDatabase(tenantId, config.key, config.config);
3155
2968
  } catch (error) {
3156
2969
  console.warn("Failed to auto-register database:", error);
3157
2970
  }
@@ -3174,7 +2987,7 @@ async function updateDatabaseConfig(request, reply) {
3174
2987
  const { key } = request.params;
3175
2988
  const updates = request.body;
3176
2989
  try {
3177
- const storeLattice = (0, import_core20.getStoreLattice)("default", "database");
2990
+ const storeLattice = (0, import_core19.getStoreLattice)("default", "database");
3178
2991
  const store = storeLattice.store;
3179
2992
  const existing = await store.getConfigByKey(tenantId, key);
3180
2993
  if (!existing) {
@@ -3193,7 +3006,7 @@ async function updateDatabaseConfig(request, reply) {
3193
3006
  }
3194
3007
  if (updates.config) {
3195
3008
  try {
3196
- import_core20.sqlDatabaseManager.registerDatabase(tenantId, updated.key, updated.config);
3009
+ import_core19.sqlDatabaseManager.registerDatabase(tenantId, updated.key, updated.config);
3197
3010
  } catch (error) {
3198
3011
  console.warn("Failed to re-register database:", error);
3199
3012
  }
@@ -3215,7 +3028,7 @@ async function deleteDatabaseConfig(request, reply) {
3215
3028
  const tenantId = getTenantId6(request);
3216
3029
  const { keyOrId } = request.params;
3217
3030
  try {
3218
- const storeLattice = (0, import_core20.getStoreLattice)("default", "database");
3031
+ const storeLattice = (0, import_core19.getStoreLattice)("default", "database");
3219
3032
  const store = storeLattice.store;
3220
3033
  console.log("Delete request - keyOrId:", keyOrId);
3221
3034
  let config = await store.getConfigByKey(tenantId, keyOrId);
@@ -3242,8 +3055,8 @@ async function deleteDatabaseConfig(request, reply) {
3242
3055
  };
3243
3056
  }
3244
3057
  try {
3245
- if (import_core20.sqlDatabaseManager.hasDatabase(tenantId, configKey)) {
3246
- await import_core20.sqlDatabaseManager.removeDatabase(tenantId, configKey);
3058
+ if (import_core19.sqlDatabaseManager.hasDatabase(tenantId, configKey)) {
3059
+ await import_core19.sqlDatabaseManager.removeDatabase(tenantId, configKey);
3247
3060
  }
3248
3061
  } catch (error) {
3249
3062
  console.warn("Failed to remove from SqlDatabaseManager:", error);
@@ -3264,7 +3077,7 @@ async function testDatabaseConnection(request, reply) {
3264
3077
  const tenantId = getTenantId6(request);
3265
3078
  const { key } = request.params;
3266
3079
  try {
3267
- const storeLattice = (0, import_core20.getStoreLattice)("default", "database");
3080
+ const storeLattice = (0, import_core19.getStoreLattice)("default", "database");
3268
3081
  const store = storeLattice.store;
3269
3082
  const config = await store.getConfigByKey(tenantId, key);
3270
3083
  if (!config) {
@@ -3275,16 +3088,16 @@ async function testDatabaseConnection(request, reply) {
3275
3088
  };
3276
3089
  }
3277
3090
  const testKey = `__test_${key}_${Date.now()}`;
3278
- import_core20.sqlDatabaseManager.registerDatabase(tenantId, testKey, config.config);
3091
+ import_core19.sqlDatabaseManager.registerDatabase(tenantId, testKey, config.config);
3279
3092
  const startTime = Date.now();
3280
- const db = await import_core20.sqlDatabaseManager.getDatabase(tenantId, testKey);
3093
+ const db = await import_core19.sqlDatabaseManager.getDatabase(tenantId, testKey);
3281
3094
  try {
3282
3095
  await db.connect();
3283
3096
  await db.listTables();
3284
3097
  const latency = Date.now() - startTime;
3285
3098
  await new Promise((resolve) => setTimeout(resolve, 100));
3286
3099
  await db.disconnect();
3287
- await import_core20.sqlDatabaseManager.removeDatabase(tenantId, testKey);
3100
+ await import_core19.sqlDatabaseManager.removeDatabase(tenantId, testKey);
3288
3101
  return {
3289
3102
  success: true,
3290
3103
  message: "Connection test successful",
@@ -3296,7 +3109,7 @@ async function testDatabaseConnection(request, reply) {
3296
3109
  } catch (error) {
3297
3110
  try {
3298
3111
  await db.disconnect();
3299
- await import_core20.sqlDatabaseManager.removeDatabase(tenantId, testKey);
3112
+ await import_core19.sqlDatabaseManager.removeDatabase(tenantId, testKey);
3300
3113
  } catch {
3301
3114
  }
3302
3115
  return {
@@ -3348,7 +3161,7 @@ function registerDatabaseConfigRoutes(app2) {
3348
3161
  }
3349
3162
 
3350
3163
  // src/controllers/metrics-configs.ts
3351
- var import_core21 = require("@axiom-lattice/core");
3164
+ var import_core20 = require("@axiom-lattice/core");
3352
3165
  var import_crypto4 = require("crypto");
3353
3166
  function getTenantId7(request) {
3354
3167
  const userTenantId = request.user?.tenantId;
@@ -3360,7 +3173,7 @@ function getTenantId7(request) {
3360
3173
  async function getMetricsServerConfigList(request, reply) {
3361
3174
  const tenantId = getTenantId7(request);
3362
3175
  try {
3363
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3176
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3364
3177
  const store = storeLattice.store;
3365
3178
  const configs = await store.getAllConfigs(tenantId);
3366
3179
  return {
@@ -3387,7 +3200,7 @@ async function getMetricsServerConfig(request, reply) {
3387
3200
  const tenantId = getTenantId7(request);
3388
3201
  const { key } = request.params;
3389
3202
  try {
3390
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3203
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3391
3204
  const store = storeLattice.store;
3392
3205
  const config = await store.getConfigByKey(tenantId, key);
3393
3206
  if (!config) {
@@ -3413,7 +3226,7 @@ async function createMetricsServerConfig(request, reply) {
3413
3226
  const tenantId = getTenantId7(request);
3414
3227
  const body = request.body;
3415
3228
  try {
3416
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3229
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3417
3230
  const store = storeLattice.store;
3418
3231
  const existing = await store.getConfigByKey(tenantId, body.key);
3419
3232
  if (existing) {
@@ -3442,7 +3255,7 @@ async function createMetricsServerConfig(request, reply) {
3442
3255
  };
3443
3256
  const config = await store.createConfig(tenantId, id, configData);
3444
3257
  try {
3445
- import_core21.metricsServerManager.registerServer(tenantId, config.key, config.config);
3258
+ import_core20.metricsServerManager.registerServer(tenantId, config.key, config.config);
3446
3259
  } catch (error) {
3447
3260
  console.warn("Failed to auto-register metrics server:", error);
3448
3261
  }
@@ -3465,7 +3278,7 @@ async function updateMetricsServerConfig(request, reply) {
3465
3278
  const { key } = request.params;
3466
3279
  const updates = request.body;
3467
3280
  try {
3468
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3281
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3469
3282
  const store = storeLattice.store;
3470
3283
  const existing = await store.getConfigByKey(tenantId, key);
3471
3284
  if (!existing) {
@@ -3493,7 +3306,7 @@ async function updateMetricsServerConfig(request, reply) {
3493
3306
  }
3494
3307
  if (updates.config) {
3495
3308
  try {
3496
- import_core21.metricsServerManager.registerServer(tenantId, updated.key, updated.config);
3309
+ import_core20.metricsServerManager.registerServer(tenantId, updated.key, updated.config);
3497
3310
  } catch (error) {
3498
3311
  console.warn("Failed to re-register metrics server:", error);
3499
3312
  }
@@ -3515,7 +3328,7 @@ async function deleteMetricsServerConfig(request, reply) {
3515
3328
  const tenantId = getTenantId7(request);
3516
3329
  const { keyOrId } = request.params;
3517
3330
  try {
3518
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3331
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3519
3332
  const store = storeLattice.store;
3520
3333
  let config = await store.getConfigByKey(tenantId, keyOrId);
3521
3334
  let configKey = keyOrId;
@@ -3540,8 +3353,8 @@ async function deleteMetricsServerConfig(request, reply) {
3540
3353
  };
3541
3354
  }
3542
3355
  try {
3543
- if (import_core21.metricsServerManager.hasServer(tenantId, configKey)) {
3544
- import_core21.metricsServerManager.removeServer(tenantId, configKey);
3356
+ if (import_core20.metricsServerManager.hasServer(tenantId, configKey)) {
3357
+ import_core20.metricsServerManager.removeServer(tenantId, configKey);
3545
3358
  }
3546
3359
  } catch (error) {
3547
3360
  console.warn("Failed to remove from MetricsServerManager:", error);
@@ -3562,7 +3375,7 @@ async function testMetricsServerConnection(request, reply) {
3562
3375
  const tenantId = getTenantId7(request);
3563
3376
  const { key } = request.params;
3564
3377
  try {
3565
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3378
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3566
3379
  const store = storeLattice.store;
3567
3380
  const config = await store.getConfigByKey(tenantId, key);
3568
3381
  if (!config) {
@@ -3573,11 +3386,11 @@ async function testMetricsServerConnection(request, reply) {
3573
3386
  };
3574
3387
  }
3575
3388
  const testKey = `__test_${key}_${Date.now()}`;
3576
- import_core21.metricsServerManager.registerServer(tenantId, testKey, config.config);
3389
+ import_core20.metricsServerManager.registerServer(tenantId, testKey, config.config);
3577
3390
  try {
3578
- const client = import_core21.metricsServerManager.getClient(tenantId, testKey);
3391
+ const client = import_core20.metricsServerManager.getClient(tenantId, testKey);
3579
3392
  const result = await client.testConnection();
3580
- import_core21.metricsServerManager.removeServer(tenantId, testKey);
3393
+ import_core20.metricsServerManager.removeServer(tenantId, testKey);
3581
3394
  return {
3582
3395
  success: true,
3583
3396
  message: result.connected ? "Connection test successful" : "Connection test failed",
@@ -3585,7 +3398,7 @@ async function testMetricsServerConnection(request, reply) {
3585
3398
  };
3586
3399
  } catch (error) {
3587
3400
  try {
3588
- import_core21.metricsServerManager.removeServer(tenantId, testKey);
3401
+ import_core20.metricsServerManager.removeServer(tenantId, testKey);
3589
3402
  } catch {
3590
3403
  }
3591
3404
  return {
@@ -3613,7 +3426,7 @@ async function listAvailableMetrics(request, reply) {
3613
3426
  const tenantId = getTenantId7(request);
3614
3427
  const { key } = request.params;
3615
3428
  try {
3616
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3429
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3617
3430
  const store = storeLattice.store;
3618
3431
  const config = await store.getConfigByKey(tenantId, key);
3619
3432
  if (!config) {
@@ -3623,10 +3436,10 @@ async function listAvailableMetrics(request, reply) {
3623
3436
  message: "Metrics server configuration not found"
3624
3437
  };
3625
3438
  }
3626
- if (!import_core21.metricsServerManager.hasServer(tenantId, key)) {
3627
- import_core21.metricsServerManager.registerServer(tenantId, key, config.config);
3439
+ if (!import_core20.metricsServerManager.hasServer(tenantId, key)) {
3440
+ import_core20.metricsServerManager.registerServer(tenantId, key, config.config);
3628
3441
  }
3629
- const client = import_core21.metricsServerManager.getClient(tenantId, key);
3442
+ const client = import_core20.metricsServerManager.getClient(tenantId, key);
3630
3443
  const metrics = await client.listMetrics();
3631
3444
  return {
3632
3445
  success: true,
@@ -3652,7 +3465,7 @@ async function queryMetricsData(request, reply) {
3652
3465
  const { key } = request.params;
3653
3466
  const { metricName, startTime, endTime, step, labels } = request.body;
3654
3467
  try {
3655
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3468
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3656
3469
  const store = storeLattice.store;
3657
3470
  const config = await store.getConfigByKey(tenantId, key);
3658
3471
  if (!config) {
@@ -3669,10 +3482,10 @@ async function queryMetricsData(request, reply) {
3669
3482
  message: "metricName is required"
3670
3483
  };
3671
3484
  }
3672
- if (!import_core21.metricsServerManager.hasServer(tenantId, key)) {
3673
- import_core21.metricsServerManager.registerServer(tenantId, key, config.config);
3485
+ if (!import_core20.metricsServerManager.hasServer(tenantId, key)) {
3486
+ import_core20.metricsServerManager.registerServer(tenantId, key, config.config);
3674
3487
  }
3675
- const client = import_core21.metricsServerManager.getClient(tenantId, key);
3488
+ const client = import_core20.metricsServerManager.getClient(tenantId, key);
3676
3489
  const result = await client.queryMetricData(metricName, {
3677
3490
  startTime,
3678
3491
  endTime,
@@ -3699,7 +3512,7 @@ async function getDataSources(request, reply) {
3699
3512
  const tenantId = getTenantId7(request);
3700
3513
  const { key } = request.params;
3701
3514
  try {
3702
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3515
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3703
3516
  const store = storeLattice.store;
3704
3517
  const config = await store.getConfigByKey(tenantId, key);
3705
3518
  if (!config) {
@@ -3717,7 +3530,7 @@ async function getDataSources(request, reply) {
3717
3530
  };
3718
3531
  }
3719
3532
  const semanticConfig = config.config;
3720
- const client = new import_core21.SemanticMetricsClient(semanticConfig);
3533
+ const client = new import_core20.SemanticMetricsClient(semanticConfig);
3721
3534
  const allDatasources = await client.getDataSources();
3722
3535
  const selectedIds = semanticConfig.selectedDataSources || [];
3723
3536
  const filteredDatasources = selectedIds.length > 0 ? allDatasources.filter((ds) => selectedIds.includes(String(ds.id))) : allDatasources;
@@ -3740,7 +3553,7 @@ async function getDatasourceMetrics(request, reply) {
3740
3553
  const tenantId = getTenantId7(request);
3741
3554
  const { key, datasourceId } = request.params;
3742
3555
  try {
3743
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3556
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3744
3557
  const store = storeLattice.store;
3745
3558
  const config = await store.getConfigByKey(tenantId, key);
3746
3559
  if (!config) {
@@ -3758,7 +3571,7 @@ async function getDatasourceMetrics(request, reply) {
3758
3571
  };
3759
3572
  }
3760
3573
  const semanticConfig = config.config;
3761
- const client = new import_core21.SemanticMetricsClient(semanticConfig);
3574
+ const client = new import_core20.SemanticMetricsClient(semanticConfig);
3762
3575
  const metrics = await client.getDatasourceMetrics(datasourceId);
3763
3576
  return {
3764
3577
  success: true,
@@ -3778,7 +3591,7 @@ async function querySemanticMetrics(request, reply) {
3778
3591
  const { key } = request.params;
3779
3592
  const body = request.body;
3780
3593
  try {
3781
- const storeLattice = (0, import_core21.getStoreLattice)("default", "metrics");
3594
+ const storeLattice = (0, import_core20.getStoreLattice)("default", "metrics");
3782
3595
  const store = storeLattice.store;
3783
3596
  const config = await store.getConfigByKey(tenantId, key);
3784
3597
  if (!config) {
@@ -3803,7 +3616,7 @@ async function querySemanticMetrics(request, reply) {
3803
3616
  };
3804
3617
  }
3805
3618
  const semanticConfig = config.config;
3806
- const client = new import_core21.SemanticMetricsClient(semanticConfig);
3619
+ const client = new import_core20.SemanticMetricsClient(semanticConfig);
3807
3620
  const result = await client.semanticQuery(body);
3808
3621
  const columnNames = result.columns.map((col) => col.name);
3809
3622
  const allDataPoints = [];
@@ -3863,7 +3676,7 @@ async function testSemanticDataSources(request, reply) {
3863
3676
  password: body.password,
3864
3677
  headers: body.headers
3865
3678
  };
3866
- const client = new import_core21.SemanticMetricsClient(testConfig);
3679
+ const client = new import_core20.SemanticMetricsClient(testConfig);
3867
3680
  const datasources = await client.getDataSources();
3868
3681
  return {
3869
3682
  success: true,
@@ -3899,7 +3712,7 @@ async function testDatasourceMetrics(request, reply) {
3899
3712
  password: body.password,
3900
3713
  headers: body.headers
3901
3714
  };
3902
- const client = new import_core21.SemanticMetricsClient(testConfig);
3715
+ const client = new import_core20.SemanticMetricsClient(testConfig);
3903
3716
  const metrics = await client.getDatasourceMetrics(datasourceId);
3904
3717
  return {
3905
3718
  success: true,
@@ -3931,7 +3744,7 @@ function registerMetricsServerConfigRoutes(app2) {
3931
3744
  }
3932
3745
 
3933
3746
  // src/controllers/mcp-configs.ts
3934
- var import_core22 = require("@axiom-lattice/core");
3747
+ var import_core21 = require("@axiom-lattice/core");
3935
3748
  var import_crypto5 = require("crypto");
3936
3749
  function getTenantId8(request) {
3937
3750
  const userTenantId = request.user?.tenantId;
@@ -3943,7 +3756,7 @@ function getTenantId8(request) {
3943
3756
  async function getMcpServerConfigList(request, reply) {
3944
3757
  const tenantId = getTenantId8(request);
3945
3758
  try {
3946
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
3759
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
3947
3760
  const store = storeLattice.store;
3948
3761
  const configs = await store.getAllConfigs(tenantId);
3949
3762
  return {
@@ -3970,7 +3783,7 @@ async function getMcpServerConfig(request, reply) {
3970
3783
  const tenantId = getTenantId8(request);
3971
3784
  const { key } = request.params;
3972
3785
  try {
3973
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
3786
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
3974
3787
  const store = storeLattice.store;
3975
3788
  const config = await store.getConfigByKey(tenantId, key);
3976
3789
  if (!config) {
@@ -3996,7 +3809,7 @@ async function createMcpServerConfig(request, reply) {
3996
3809
  const tenantId = getTenantId8(request);
3997
3810
  const body = request.body;
3998
3811
  try {
3999
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
3812
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
4000
3813
  const store = storeLattice.store;
4001
3814
  const existing = await store.getConfigByKey(tenantId, body.key);
4002
3815
  if (existing) {
@@ -4036,7 +3849,7 @@ async function updateMcpServerConfig(request, reply) {
4036
3849
  const { key } = request.params;
4037
3850
  const updates = request.body;
4038
3851
  try {
4039
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
3852
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
4040
3853
  const store = storeLattice.store;
4041
3854
  const existing = await store.getConfigByKey(tenantId, key);
4042
3855
  if (!existing) {
@@ -4056,8 +3869,8 @@ async function updateMcpServerConfig(request, reply) {
4056
3869
  }
4057
3870
  if (shouldReconnect) {
4058
3871
  try {
4059
- if (import_core22.mcpManager.hasServer(key)) {
4060
- await import_core22.mcpManager.removeServer(key);
3872
+ if (import_core21.mcpManager.hasServer(key)) {
3873
+ await import_core21.mcpManager.removeServer(key);
4061
3874
  }
4062
3875
  await connectAndRegisterTools(updated);
4063
3876
  await store.updateConfig(tenantId, existing.id, { status: "connected" });
@@ -4085,7 +3898,7 @@ async function deleteMcpServerConfig(request, reply) {
4085
3898
  const tenantId = getTenantId8(request);
4086
3899
  const { keyOrId } = request.params;
4087
3900
  try {
4088
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
3901
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
4089
3902
  const store = storeLattice.store;
4090
3903
  let config = await store.getConfigByKey(tenantId, keyOrId);
4091
3904
  let configKey = keyOrId;
@@ -4103,8 +3916,8 @@ async function deleteMcpServerConfig(request, reply) {
4103
3916
  };
4104
3917
  }
4105
3918
  try {
4106
- if (import_core22.mcpManager.hasServer(configKey)) {
4107
- await import_core22.mcpManager.removeServer(configKey);
3919
+ if (import_core21.mcpManager.hasServer(configKey)) {
3920
+ await import_core21.mcpManager.removeServer(configKey);
4108
3921
  }
4109
3922
  } catch (error) {
4110
3923
  console.warn("Failed to remove from MCP manager:", error);
@@ -4132,7 +3945,7 @@ async function testMcpServerConnection(request, reply) {
4132
3945
  const tenantId = getTenantId8(request);
4133
3946
  const { key } = request.params;
4134
3947
  try {
4135
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
3948
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
4136
3949
  const store = storeLattice.store;
4137
3950
  const config = await store.getConfigByKey(tenantId, key);
4138
3951
  if (!config) {
@@ -4146,11 +3959,11 @@ async function testMcpServerConnection(request, reply) {
4146
3959
  try {
4147
3960
  const testKey = `__test_${key}_${Date.now()}`;
4148
3961
  const connection = convertToConnection(config.config);
4149
- import_core22.mcpManager.addServer(testKey, connection);
4150
- await import_core22.mcpManager.connect();
4151
- const tools = await import_core22.mcpManager.getAllTools();
3962
+ import_core21.mcpManager.addServer(testKey, connection);
3963
+ await import_core21.mcpManager.connect();
3964
+ const tools = await import_core21.mcpManager.getAllTools();
4152
3965
  const latency = Date.now() - startTime;
4153
- await import_core22.mcpManager.removeServer(testKey);
3966
+ await import_core21.mcpManager.removeServer(testKey);
4154
3967
  return {
4155
3968
  success: true,
4156
3969
  message: "Connection test successful",
@@ -4185,7 +3998,7 @@ async function listMcpServerTools(request, reply) {
4185
3998
  const tenantId = getTenantId8(request);
4186
3999
  const { key } = request.params;
4187
4000
  try {
4188
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
4001
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
4189
4002
  const store = storeLattice.store;
4190
4003
  const config = await store.getConfigByKey(tenantId, key);
4191
4004
  if (!config) {
@@ -4195,10 +4008,10 @@ async function listMcpServerTools(request, reply) {
4195
4008
  message: "MCP server configuration not found"
4196
4009
  };
4197
4010
  }
4198
- if (!import_core22.mcpManager.hasServer(key)) {
4011
+ if (!import_core21.mcpManager.hasServer(key)) {
4199
4012
  await connectAndRegisterTools(config);
4200
4013
  }
4201
- const tools = await import_core22.mcpManager.getAllTools();
4014
+ const tools = await import_core21.mcpManager.getAllTools();
4202
4015
  return {
4203
4016
  success: true,
4204
4017
  message: "Tools retrieved successfully",
@@ -4218,7 +4031,7 @@ async function connectMcpServer(request, reply) {
4218
4031
  const tenantId = getTenantId8(request);
4219
4032
  const { key } = request.params;
4220
4033
  try {
4221
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
4034
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
4222
4035
  const store = storeLattice.store;
4223
4036
  const config = await store.getConfigByKey(tenantId, key);
4224
4037
  if (!config) {
@@ -4239,7 +4052,7 @@ async function connectMcpServer(request, reply) {
4239
4052
  };
4240
4053
  } catch (error) {
4241
4054
  console.error("Failed to connect MCP server:", error);
4242
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
4055
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
4243
4056
  const store = storeLattice.store;
4244
4057
  const config = await store.getConfigByKey(tenantId, key);
4245
4058
  if (config) {
@@ -4255,7 +4068,7 @@ async function disconnectMcpServer(request, reply) {
4255
4068
  const tenantId = getTenantId8(request);
4256
4069
  const { key } = request.params;
4257
4070
  try {
4258
- const storeLattice = (0, import_core22.getStoreLattice)("default", "mcp");
4071
+ const storeLattice = (0, import_core21.getStoreLattice)("default", "mcp");
4259
4072
  const store = storeLattice.store;
4260
4073
  const config = await store.getConfigByKey(tenantId, key);
4261
4074
  if (!config) {
@@ -4265,8 +4078,8 @@ async function disconnectMcpServer(request, reply) {
4265
4078
  message: "MCP server configuration not found"
4266
4079
  };
4267
4080
  }
4268
- if (import_core22.mcpManager.hasServer(key)) {
4269
- await import_core22.mcpManager.removeServer(key);
4081
+ if (import_core21.mcpManager.hasServer(key)) {
4082
+ await import_core21.mcpManager.removeServer(key);
4270
4083
  }
4271
4084
  const updated = await store.updateConfig(tenantId, config.id, {
4272
4085
  status: "disconnected"
@@ -4296,10 +4109,10 @@ async function testMcpServerTools(request, reply) {
4296
4109
  }
4297
4110
  const testKey = `__test_${Date.now()}`;
4298
4111
  const connection = convertToConnection(body.config);
4299
- import_core22.mcpManager.addServer(testKey, connection);
4300
- await import_core22.mcpManager.connect();
4301
- const tools = await import_core22.mcpManager.getAllTools();
4302
- await import_core22.mcpManager.removeServer(testKey);
4112
+ import_core21.mcpManager.addServer(testKey, connection);
4113
+ await import_core21.mcpManager.connect();
4114
+ const tools = await import_core21.mcpManager.getAllTools();
4115
+ await import_core21.mcpManager.removeServer(testKey);
4303
4116
  return {
4304
4117
  success: true,
4305
4118
  message: "Tools retrieved successfully",
@@ -4336,14 +4149,14 @@ function convertToConnection(config) {
4336
4149
  }
4337
4150
  async function connectAndRegisterTools(config) {
4338
4151
  const connection = convertToConnection(config.config);
4339
- import_core22.mcpManager.addServer(config.key, connection);
4340
- await import_core22.mcpManager.connect();
4341
- const allTools = await import_core22.mcpManager.getAllTools();
4152
+ import_core21.mcpManager.addServer(config.key, connection);
4153
+ await import_core21.mcpManager.connect();
4154
+ const allTools = await import_core21.mcpManager.getAllTools();
4342
4155
  const selectedTools = allTools.filter(
4343
4156
  (tool) => config.selectedTools.includes(tool.name)
4344
4157
  );
4345
4158
  for (const tool of selectedTools) {
4346
- import_core22.toolLatticeManager.registerExistingTool(tool.name, tool);
4159
+ import_core21.toolLatticeManager.registerExistingTool(tool.name, tool);
4347
4160
  }
4348
4161
  }
4349
4162
  function registerMcpServerConfigRoutes(app2) {
@@ -4360,11 +4173,11 @@ function registerMcpServerConfigRoutes(app2) {
4360
4173
  }
4361
4174
 
4362
4175
  // src/controllers/users.ts
4363
- var import_core23 = require("@axiom-lattice/core");
4176
+ var import_core22 = require("@axiom-lattice/core");
4364
4177
  var import_uuid3 = require("uuid");
4365
4178
  var UsersController = class {
4366
4179
  constructor() {
4367
- this.userStore = (0, import_core23.getStoreLattice)("default", "user").store;
4180
+ this.userStore = (0, import_core22.getStoreLattice)("default", "user").store;
4368
4181
  }
4369
4182
  async listUsers(request, reply) {
4370
4183
  const { email } = request.query;
@@ -4442,11 +4255,11 @@ function registerUserRoutes(app2) {
4442
4255
  }
4443
4256
 
4444
4257
  // src/controllers/tenants.ts
4445
- var import_core24 = require("@axiom-lattice/core");
4258
+ var import_core23 = require("@axiom-lattice/core");
4446
4259
  var import_uuid4 = require("uuid");
4447
4260
  var TenantsController = class {
4448
4261
  constructor() {
4449
- this.tenantStore = (0, import_core24.getStoreLattice)("default", "tenant").store;
4262
+ this.tenantStore = (0, import_core23.getStoreLattice)("default", "tenant").store;
4450
4263
  }
4451
4264
  // ==================== Tenant CRUD ====================
4452
4265
  async listTenants(request, reply) {
@@ -4510,7 +4323,7 @@ function registerTenantRoutes(app2) {
4510
4323
  }
4511
4324
 
4512
4325
  // src/controllers/auth.ts
4513
- var import_core25 = require("@axiom-lattice/core");
4326
+ var import_core24 = require("@axiom-lattice/core");
4514
4327
  var import_uuid5 = require("uuid");
4515
4328
  var defaultAuthConfig = {
4516
4329
  autoApproveUsers: true,
@@ -4519,9 +4332,9 @@ var defaultAuthConfig = {
4519
4332
  };
4520
4333
  var AuthController = class {
4521
4334
  constructor(config = {}) {
4522
- this.userStore = (0, import_core25.getStoreLattice)("default", "user").store;
4523
- this.tenantStore = (0, import_core25.getStoreLattice)("default", "tenant").store;
4524
- this.userTenantLinkStore = (0, import_core25.getStoreLattice)("default", "userTenantLink").store;
4335
+ this.userStore = (0, import_core24.getStoreLattice)("default", "user").store;
4336
+ this.tenantStore = (0, import_core24.getStoreLattice)("default", "tenant").store;
4337
+ this.userTenantLinkStore = (0, import_core24.getStoreLattice)("default", "userTenantLink").store;
4525
4338
  this.config = { ...defaultAuthConfig, ...config };
4526
4339
  }
4527
4340
  async register(request, reply) {
@@ -4892,6 +4705,695 @@ function registerAuthRoutes(app2, config) {
4892
4705
  );
4893
4706
  }
4894
4707
 
4708
+ // src/channels/lark/routes.ts
4709
+ var import_core26 = require("@axiom-lattice/core");
4710
+ var import_pg_stores = require("@axiom-lattice/pg-stores");
4711
+
4712
+ // src/channels/lark/parser.ts
4713
+ function parseLarkMessageEvent(payload) {
4714
+ const raw = payload;
4715
+ if (raw.header?.event_type !== "im.message.receive_v1") {
4716
+ return null;
4717
+ }
4718
+ const message = raw.event?.message;
4719
+ const openId = raw.event?.sender?.sender_id?.open_id;
4720
+ if (!message || !openId || message.message_type !== "text") {
4721
+ return null;
4722
+ }
4723
+ const parsedContent = parseLarkTextContent(message.content);
4724
+ if (!message.message_id || !message.chat_id || !parsedContent) {
4725
+ return null;
4726
+ }
4727
+ return {
4728
+ messageId: message.message_id,
4729
+ openId,
4730
+ chatId: message.chat_id,
4731
+ chatType: normalizeChatType(message.chat_type),
4732
+ text: parsedContent
4733
+ };
4734
+ }
4735
+ function parseLarkTextContent(content) {
4736
+ if (!content) {
4737
+ return null;
4738
+ }
4739
+ try {
4740
+ const parsed = JSON.parse(content);
4741
+ return typeof parsed.text === "string" ? parsed.text : null;
4742
+ } catch {
4743
+ return null;
4744
+ }
4745
+ }
4746
+ function normalizeChatType(chatType) {
4747
+ return chatType === "p2p" ? "direct" : "group";
4748
+ }
4749
+
4750
+ // src/channels/lark/controller.ts
4751
+ function createLarkEventHandler(dependencies) {
4752
+ return async function handleLarkEvent2(request, reply) {
4753
+ const installationId = request.params?.installationId;
4754
+ if (!installationId) {
4755
+ reply.status(400).send({ success: false, message: "Missing installationId" });
4756
+ return;
4757
+ }
4758
+ const config = await dependencies.getInstallationConfig(installationId);
4759
+ if (!config) {
4760
+ reply.status(404).send({ success: false, message: "Lark installation not found" });
4761
+ return;
4762
+ }
4763
+ const body = dependencies.parseRequestBody(
4764
+ request.body,
4765
+ config.encryptKey
4766
+ );
4767
+ if (!dependencies.verifyParsedBody(body, config)) {
4768
+ reply.status(401).send({ success: false, message: "Invalid Lark request" });
4769
+ return;
4770
+ }
4771
+ if (body.type === "url_verification" && body.challenge) {
4772
+ reply.status(200).send({ challenge: body.challenge });
4773
+ return;
4774
+ }
4775
+ const parsed = dependencies.parseEvent(request.body);
4776
+ if (!parsed) {
4777
+ reply.status(200).send({ success: true, ignored: true });
4778
+ return;
4779
+ }
4780
+ const receipt = await dependencies.claimInboundReceipt({
4781
+ channel: "lark",
4782
+ channelAppId: config.appId,
4783
+ externalMessageId: parsed.messageId,
4784
+ tenantId: config.tenantId
4785
+ });
4786
+ if (!receipt.accepted) {
4787
+ reply.status(200).send(
4788
+ receipt.status === "processing" ? { success: true, processing: true } : { success: true, duplicate: true }
4789
+ );
4790
+ return;
4791
+ }
4792
+ try {
4793
+ const { threadId } = await dependencies.resolveThread({
4794
+ channel: "lark",
4795
+ channelAppId: config.appId,
4796
+ tenantId: config.tenantId,
4797
+ assistantId: config.assistantId,
4798
+ mappingMode: config.mappingMode,
4799
+ openId: parsed.openId,
4800
+ chatId: parsed.chatId,
4801
+ chatType: parsed.chatType,
4802
+ messageId: parsed.messageId,
4803
+ workspaceId: config.workspaceId,
4804
+ projectId: config.projectId
4805
+ });
4806
+ const text = await dependencies.runAgentAndCollectText({
4807
+ tenantId: config.tenantId,
4808
+ assistantId: config.assistantId,
4809
+ threadId,
4810
+ text: parsed.text,
4811
+ workspaceId: config.workspaceId,
4812
+ projectId: config.projectId
4813
+ });
4814
+ await dependencies.sendTextReply({
4815
+ chatId: parsed.chatId,
4816
+ text,
4817
+ config
4818
+ });
4819
+ await dependencies.markInboundReceiptCompleted({
4820
+ channel: "lark",
4821
+ channelAppId: config.appId,
4822
+ externalMessageId: parsed.messageId,
4823
+ tenantId: config.tenantId,
4824
+ threadId
4825
+ });
4826
+ reply.status(200).send({ success: true, threadId });
4827
+ } catch (error) {
4828
+ await dependencies.markInboundReceiptFailed({
4829
+ channel: "lark",
4830
+ channelAppId: config.appId,
4831
+ externalMessageId: parsed.messageId,
4832
+ tenantId: config.tenantId
4833
+ });
4834
+ throw error;
4835
+ }
4836
+ };
4837
+ }
4838
+ var handleLarkEvent = createLarkEventHandler({
4839
+ getInstallationConfig: async () => null,
4840
+ parseRequestBody: (body) => body || {},
4841
+ verifyParsedBody: () => true,
4842
+ parseEvent: parseLarkMessageEvent,
4843
+ claimInboundReceipt: async () => ({ accepted: true, status: "processing" }),
4844
+ markInboundReceiptCompleted: async () => void 0,
4845
+ markInboundReceiptFailed: async () => void 0,
4846
+ resolveThread: async () => ({ threadId: "" }),
4847
+ runAgentAndCollectText: async () => "",
4848
+ sendTextReply: async () => void 0
4849
+ });
4850
+
4851
+ // src/channels/lark/config.ts
4852
+ function loadLarkIngressConfig() {
4853
+ return {
4854
+ enabled: process.env.LARK_ENABLED !== "false",
4855
+ appId: process.env.LARK_APP_ID || "",
4856
+ appSecret: process.env.LARK_APP_SECRET || "",
4857
+ verificationToken: process.env.LARK_VERIFICATION_TOKEN,
4858
+ encryptKey: process.env.LARK_ENCRYPT_KEY,
4859
+ tenantId: process.env.LARK_TENANT_ID || "default",
4860
+ assistantId: process.env.LARK_ASSISTANT_ID || "default_agent",
4861
+ workspaceId: process.env.LARK_WORKSPACE_ID,
4862
+ projectId: process.env.LARK_PROJECT_ID,
4863
+ mappingMode: process.env.LARK_MAPPING_MODE || "hybrid"
4864
+ };
4865
+ }
4866
+ function isLarkIngressEnabled(config) {
4867
+ return config.enabled;
4868
+ }
4869
+
4870
+ // src/channels/lark/mapping-service.ts
4871
+ var import_crypto6 = require("crypto");
4872
+ function createChannelThreadMappingService(deps) {
4873
+ return {
4874
+ async getOrCreateThread(input) {
4875
+ const externalSubjectKey = buildExternalSubjectKey(input);
4876
+ const existing = await deps.mappingStore.getMappingBySubject({
4877
+ channel: input.channel,
4878
+ channelAppId: input.channelAppId,
4879
+ tenantId: input.tenantId,
4880
+ assistantId: input.assistantId,
4881
+ externalSubjectKey
4882
+ });
4883
+ if (existing) {
4884
+ return { threadId: existing.threadId };
4885
+ }
4886
+ const threadId = (deps.uuid || import_crypto6.randomUUID)();
4887
+ await deps.threadStore.createThread(input.tenantId, input.assistantId, threadId, {
4888
+ metadata: {
4889
+ tenantId: input.tenantId,
4890
+ workspaceId: input.workspaceId,
4891
+ projectId: input.projectId,
4892
+ channel: input.channel,
4893
+ larkChatId: input.chatId,
4894
+ larkOpenId: input.openId
4895
+ }
4896
+ });
4897
+ try {
4898
+ await deps.mappingStore.createMapping({
4899
+ channel: input.channel,
4900
+ channelAppId: input.channelAppId,
4901
+ tenantId: input.tenantId,
4902
+ assistantId: input.assistantId,
4903
+ mappingMode: input.mappingMode,
4904
+ externalSubjectType: resolveSubjectType(input.mappingMode, input.chatType) === "user" ? "user" : "chat",
4905
+ externalSubjectKey,
4906
+ larkOpenId: input.openId,
4907
+ larkChatId: input.chatId,
4908
+ larkMessageId: input.messageId,
4909
+ threadId
4910
+ });
4911
+ } catch (error) {
4912
+ if (!isUniqueViolation(error)) {
4913
+ throw error;
4914
+ }
4915
+ const canonical = await deps.mappingStore.getMappingBySubject({
4916
+ channel: input.channel,
4917
+ channelAppId: input.channelAppId,
4918
+ tenantId: input.tenantId,
4919
+ assistantId: input.assistantId,
4920
+ externalSubjectKey
4921
+ });
4922
+ if (!canonical) {
4923
+ throw error;
4924
+ }
4925
+ await deps.threadStore.deleteThread(input.tenantId, threadId);
4926
+ return { threadId: canonical.threadId };
4927
+ }
4928
+ return { threadId };
4929
+ }
4930
+ };
4931
+ }
4932
+ function isUniqueViolation(error) {
4933
+ return typeof error === "object" && error !== null && "code" in error && error.code === "23505";
4934
+ }
4935
+ function buildExternalSubjectKey(input) {
4936
+ const subjectType = resolveSubjectType(input.mappingMode, input.chatType);
4937
+ const subjectValue = subjectType === "user" ? input.openId : input.chatId;
4938
+ return [
4939
+ input.channel,
4940
+ input.channelAppId,
4941
+ `tenant:${input.tenantId}`,
4942
+ `assistant:${input.assistantId}`,
4943
+ `${subjectType}:${subjectValue}`
4944
+ ].join(":");
4945
+ }
4946
+ function resolveSubjectType(mappingMode, chatType) {
4947
+ if (mappingMode === "user") {
4948
+ return "user";
4949
+ }
4950
+ if (mappingMode === "group") {
4951
+ return "chat";
4952
+ }
4953
+ return chatType === "direct" ? "user" : "chat";
4954
+ }
4955
+
4956
+ // src/channels/lark/runner.ts
4957
+ var import_core25 = require("@axiom-lattice/core");
4958
+ var import_protocols4 = require("@axiom-lattice/protocols");
4959
+
4960
+ // src/channels/lark/aggregator.ts
4961
+ var import_protocols3 = require("@axiom-lattice/protocols");
4962
+ function aggregateLarkReply(messageId, chunks) {
4963
+ return chunks.filter(
4964
+ (chunk) => chunk.type === import_protocols3.MessageChunkTypes.AI && chunk.data.id === messageId
4965
+ ).map((chunk) => chunk.data.content || "").join("").trim();
4966
+ }
4967
+
4968
+ // src/channels/lark/runner.ts
4969
+ async function runAgentAndCollectLarkReply(input) {
4970
+ const agent = import_core25.agentInstanceManager.getAgent({
4971
+ tenant_id: input.tenantId,
4972
+ assistant_id: input.assistantId,
4973
+ thread_id: input.threadId,
4974
+ workspace_id: input.workspaceId,
4975
+ project_id: input.projectId
4976
+ });
4977
+ const result = await agent.addMessage({
4978
+ input: {
4979
+ message: input.text
4980
+ }
4981
+ });
4982
+ const chunks = [];
4983
+ const stream = agent.chunkStream(result.messageId, [
4984
+ import_protocols4.MessageChunkTypes.MESSAGE_COMPLETED
4985
+ ]);
4986
+ for await (const chunk of stream) {
4987
+ chunks.push(chunk);
4988
+ }
4989
+ return aggregateLarkReply(result.messageId, chunks);
4990
+ }
4991
+
4992
+ // src/channels/lark/sender.ts
4993
+ function createLarkSender(config, client = createDefaultLarkClient(config)) {
4994
+ return {
4995
+ async sendTextReply(input) {
4996
+ const response = await client.im.v1.message.create({
4997
+ params: {
4998
+ receive_id_type: "chat_id"
4999
+ },
5000
+ data: {
5001
+ receive_id: input.chatId,
5002
+ msg_type: "text",
5003
+ content: JSON.stringify({ text: input.text })
5004
+ }
5005
+ });
5006
+ if (response.code && response.code !== 0) {
5007
+ throw new Error("Failed to send Lark reply");
5008
+ }
5009
+ }
5010
+ };
5011
+ }
5012
+ function createDefaultLarkClient(config) {
5013
+ const Lark = require("@larksuiteoapi/node-sdk");
5014
+ return new Lark.Client({
5015
+ appId: config.appId,
5016
+ appSecret: config.appSecret
5017
+ });
5018
+ }
5019
+
5020
+ // src/channels/lark/verification.ts
5021
+ var import_crypto7 = __toESM(require("crypto"));
5022
+ function parseLarkRequestBody(body, encryptKey) {
5023
+ const parsed = body || {};
5024
+ if (encryptKey && typeof parsed.encrypt === "string") {
5025
+ return decryptLarkPayload(encryptKey, parsed.encrypt);
5026
+ }
5027
+ return parsed;
5028
+ }
5029
+ function decryptLarkPayload(encryptKey, encryptedPayload) {
5030
+ const key = import_crypto7.default.createHash("sha256").update(encryptKey).digest();
5031
+ const buffer = Buffer.from(encryptedPayload, "base64");
5032
+ const iv = buffer.subarray(0, 16);
5033
+ const ciphertext = buffer.subarray(16);
5034
+ const decipher = import_crypto7.default.createDecipheriv("aes-256-cbc", key, iv);
5035
+ const plaintext = Buffer.concat([
5036
+ decipher.update(ciphertext),
5037
+ decipher.final()
5038
+ ]).toString("utf8");
5039
+ return JSON.parse(plaintext);
5040
+ }
5041
+ function createLarkRequestVerifier(config) {
5042
+ return function verifyRequest(request) {
5043
+ const body = parseLarkRequestBody(request.body, config.encryptKey);
5044
+ return verifyLarkParsedBody(body, config);
5045
+ };
5046
+ }
5047
+ function verifyLarkParsedBody(body, config) {
5048
+ if (!config.verificationToken) {
5049
+ return true;
5050
+ }
5051
+ return extractVerificationToken(body) === config.verificationToken;
5052
+ }
5053
+ function extractVerificationToken(body) {
5054
+ if (typeof body.token === "string") {
5055
+ return body.token;
5056
+ }
5057
+ if (typeof body.header?.token === "string") {
5058
+ return body.header.token;
5059
+ }
5060
+ return void 0;
5061
+ }
5062
+
5063
+ // src/channels/lark/routes.ts
5064
+ function registerLarkChannelRoutes(app2, dependencies) {
5065
+ const config = loadLarkIngressConfig();
5066
+ if (!dependencies && !isLarkIngressEnabled(config)) {
5067
+ return;
5068
+ }
5069
+ const handlerDependencies = dependencies || createDefaultLarkDependencies();
5070
+ app2.post(
5071
+ "/api/channels/lark/installations/:installationId/events",
5072
+ createLarkEventHandler({
5073
+ ...handlerDependencies
5074
+ })
5075
+ );
5076
+ }
5077
+ function createDefaultLarkDependencies() {
5078
+ const installationStore = new import_pg_stores.PostgreSQLChannelInstallationStore({
5079
+ poolConfig: getDatabaseUrl()
5080
+ });
5081
+ const threadStore = (0, import_core26.getStoreLattice)("default", "thread").store;
5082
+ const mappingStore = new import_pg_stores.ChannelIdentityMappingStore({
5083
+ poolConfig: getDatabaseUrl()
5084
+ });
5085
+ const mappingService = createChannelThreadMappingService({
5086
+ mappingStore,
5087
+ threadStore
5088
+ });
5089
+ return {
5090
+ getInstallationConfig: async (installationId) => {
5091
+ const installation = await installationStore.getInstallationById(
5092
+ installationId
5093
+ );
5094
+ if (!installation || installation.channel !== "lark") {
5095
+ return null;
5096
+ }
5097
+ return {
5098
+ enabled: true,
5099
+ installationId: installation.id,
5100
+ tenantId: installation.tenantId,
5101
+ assistantId: installation.config.assistantId,
5102
+ appId: installation.config.appId,
5103
+ appSecret: installation.config.appSecret,
5104
+ verificationToken: installation.config.verificationToken,
5105
+ encryptKey: installation.config.encryptKey,
5106
+ workspaceId: installation.config.workspaceId,
5107
+ projectId: installation.config.projectId,
5108
+ mappingMode: installation.config.mappingMode
5109
+ };
5110
+ },
5111
+ parseRequestBody: (body, encryptKey) => parseLarkRequestBody(body, encryptKey),
5112
+ verifyParsedBody: (body, config) => {
5113
+ if (!config.verificationToken) {
5114
+ return true;
5115
+ }
5116
+ return createLarkRequestVerifier(config)({
5117
+ body
5118
+ });
5119
+ },
5120
+ parseEvent: parseLarkMessageEvent,
5121
+ claimInboundReceipt: (input) => mappingStore.claimInboundReceipt(input),
5122
+ markInboundReceiptCompleted: (input) => mappingStore.markInboundReceiptCompleted(input),
5123
+ markInboundReceiptFailed: (input) => mappingStore.markInboundReceiptFailed(input),
5124
+ resolveThread: (input) => mappingService.getOrCreateThread(input),
5125
+ runAgentAndCollectText: ({ tenantId, assistantId, threadId, text, workspaceId, projectId }) => runAgentAndCollectLarkReply({
5126
+ tenantId,
5127
+ assistantId,
5128
+ threadId,
5129
+ text,
5130
+ workspaceId,
5131
+ projectId
5132
+ }),
5133
+ sendTextReply: async ({ chatId, text, config }) => {
5134
+ const sender = createLarkSender({
5135
+ appId: config.appId,
5136
+ appSecret: config.appSecret
5137
+ });
5138
+ await sender.sendTextReply({ chatId, text });
5139
+ }
5140
+ };
5141
+ }
5142
+ function getDatabaseUrl() {
5143
+ const databaseUrl = process.env.DATABASE_URL;
5144
+ if (!databaseUrl) {
5145
+ throw new Error("DATABASE_URL is required for Lark channel ingress");
5146
+ }
5147
+ return databaseUrl;
5148
+ }
5149
+
5150
+ // src/channels/routes.ts
5151
+ var channelRouteRegistrars = [
5152
+ (app2, dependencies) => registerLarkChannelRoutes(app2, dependencies.lark)
5153
+ ];
5154
+ function registerChannelRoutes(app2, dependencies = {}) {
5155
+ for (const registerRoutes of channelRouteRegistrars) {
5156
+ registerRoutes(app2, dependencies);
5157
+ }
5158
+ }
5159
+
5160
+ // src/controllers/channel-installations.ts
5161
+ var import_crypto8 = require("crypto");
5162
+ function getTenantId9(request) {
5163
+ const userTenantId = request.user?.tenantId;
5164
+ if (userTenantId) {
5165
+ return userTenantId;
5166
+ }
5167
+ return request.headers["x-tenant-id"] || "default";
5168
+ }
5169
+ function getInstallationStore() {
5170
+ const { PostgreSQLChannelInstallationStore: PostgreSQLChannelInstallationStore2 } = require("@axiom-lattice/pg-stores");
5171
+ const databaseUrl = process.env.DATABASE_URL;
5172
+ if (!databaseUrl) {
5173
+ throw new Error("DATABASE_URL is required for channel installation store");
5174
+ }
5175
+ return new PostgreSQLChannelInstallationStore2({
5176
+ poolConfig: databaseUrl
5177
+ });
5178
+ }
5179
+ async function getChannelInstallationList(request, reply) {
5180
+ const tenantId = getTenantId9(request);
5181
+ const { channel } = request.query;
5182
+ try {
5183
+ const store = getInstallationStore();
5184
+ const installations = await store.getInstallationsByTenant(tenantId, channel);
5185
+ return {
5186
+ success: true,
5187
+ message: "Channel installations retrieved successfully",
5188
+ data: {
5189
+ records: installations,
5190
+ total: installations.length
5191
+ }
5192
+ };
5193
+ } catch (error) {
5194
+ console.error("Failed to get channel installations:", error);
5195
+ return {
5196
+ success: false,
5197
+ message: "Failed to retrieve channel installations",
5198
+ data: {
5199
+ records: [],
5200
+ total: 0
5201
+ }
5202
+ };
5203
+ }
5204
+ }
5205
+ async function getChannelInstallation(request, reply) {
5206
+ const tenantId = getTenantId9(request);
5207
+ const { installationId } = request.params;
5208
+ try {
5209
+ const store = getInstallationStore();
5210
+ const installation = await store.getInstallationById(installationId);
5211
+ if (!installation) {
5212
+ reply.code(404);
5213
+ return {
5214
+ success: false,
5215
+ message: "Channel installation not found"
5216
+ };
5217
+ }
5218
+ if (installation.tenantId !== tenantId) {
5219
+ reply.code(403);
5220
+ return {
5221
+ success: false,
5222
+ message: "Access denied"
5223
+ };
5224
+ }
5225
+ return {
5226
+ success: true,
5227
+ message: "Channel installation retrieved successfully",
5228
+ data: installation
5229
+ };
5230
+ } catch (error) {
5231
+ console.error("Failed to get channel installation:", error);
5232
+ return {
5233
+ success: false,
5234
+ message: "Failed to retrieve channel installation"
5235
+ };
5236
+ }
5237
+ }
5238
+ async function createChannelInstallation(request, reply) {
5239
+ const tenantId = getTenantId9(request);
5240
+ const body = request.body;
5241
+ try {
5242
+ if (!body.channel) {
5243
+ reply.code(400);
5244
+ return {
5245
+ success: false,
5246
+ message: "Channel type is required"
5247
+ };
5248
+ }
5249
+ if (!body.config) {
5250
+ reply.code(400);
5251
+ return {
5252
+ success: false,
5253
+ message: "Configuration is required"
5254
+ };
5255
+ }
5256
+ if (body.channel === "lark") {
5257
+ const larkConfig = body.config;
5258
+ if (!larkConfig.appId || !larkConfig.appSecret) {
5259
+ reply.code(400);
5260
+ return {
5261
+ success: false,
5262
+ message: "appId and appSecret are required for Lark installations"
5263
+ };
5264
+ }
5265
+ if (!larkConfig.assistantId) {
5266
+ reply.code(400);
5267
+ return {
5268
+ success: false,
5269
+ message: "assistantId is required for Lark installations"
5270
+ };
5271
+ }
5272
+ }
5273
+ const store = getInstallationStore();
5274
+ const installationId = body.id || (0, import_crypto8.randomUUID)();
5275
+ const installation = await store.createInstallation(
5276
+ tenantId,
5277
+ installationId,
5278
+ body
5279
+ );
5280
+ reply.code(201);
5281
+ return {
5282
+ success: true,
5283
+ message: "Channel installation created successfully",
5284
+ data: installation
5285
+ };
5286
+ } catch (error) {
5287
+ console.error("Failed to create channel installation:", error);
5288
+ if (error.message?.includes("duplicate") || error.code === "23505") {
5289
+ reply.code(409);
5290
+ return {
5291
+ success: false,
5292
+ message: "Channel installation with this ID already exists"
5293
+ };
5294
+ }
5295
+ return {
5296
+ success: false,
5297
+ message: "Failed to create channel installation"
5298
+ };
5299
+ }
5300
+ }
5301
+ async function updateChannelInstallation(request, reply) {
5302
+ const tenantId = getTenantId9(request);
5303
+ const { installationId } = request.params;
5304
+ const body = request.body;
5305
+ try {
5306
+ const store = getInstallationStore();
5307
+ const existing = await store.getInstallationById(installationId);
5308
+ if (!existing) {
5309
+ reply.code(404);
5310
+ return {
5311
+ success: false,
5312
+ message: "Channel installation not found"
5313
+ };
5314
+ }
5315
+ if (existing.tenantId !== tenantId) {
5316
+ reply.code(403);
5317
+ return {
5318
+ success: false,
5319
+ message: "Access denied"
5320
+ };
5321
+ }
5322
+ const installation = await store.updateInstallation(
5323
+ tenantId,
5324
+ installationId,
5325
+ body
5326
+ );
5327
+ if (!installation) {
5328
+ reply.code(404);
5329
+ return {
5330
+ success: false,
5331
+ message: "Channel installation not found"
5332
+ };
5333
+ }
5334
+ return {
5335
+ success: true,
5336
+ message: "Channel installation updated successfully",
5337
+ data: installation
5338
+ };
5339
+ } catch (error) {
5340
+ console.error("Failed to update channel installation:", error);
5341
+ return {
5342
+ success: false,
5343
+ message: "Failed to update channel installation"
5344
+ };
5345
+ }
5346
+ }
5347
+ async function deleteChannelInstallation(request, reply) {
5348
+ const tenantId = getTenantId9(request);
5349
+ const { installationId } = request.params;
5350
+ try {
5351
+ const store = getInstallationStore();
5352
+ const existing = await store.getInstallationById(installationId);
5353
+ if (!existing) {
5354
+ reply.code(404);
5355
+ return {
5356
+ success: false,
5357
+ message: "Channel installation not found"
5358
+ };
5359
+ }
5360
+ if (existing.tenantId !== tenantId) {
5361
+ reply.code(403);
5362
+ return {
5363
+ success: false,
5364
+ message: "Access denied"
5365
+ };
5366
+ }
5367
+ const deleted = await store.deleteInstallation(tenantId, installationId);
5368
+ if (!deleted) {
5369
+ reply.code(404);
5370
+ return {
5371
+ success: false,
5372
+ message: "Channel installation not found"
5373
+ };
5374
+ }
5375
+ return {
5376
+ success: true,
5377
+ message: "Channel installation deleted successfully"
5378
+ };
5379
+ } catch (error) {
5380
+ console.error("Failed to delete channel installation:", error);
5381
+ return {
5382
+ success: false,
5383
+ message: "Failed to delete channel installation"
5384
+ };
5385
+ }
5386
+ }
5387
+
5388
+ // src/routes/channel-installations.ts
5389
+ function registerChannelInstallationRoutes(app2) {
5390
+ app2.get("/api/channel-installations", getChannelInstallationList);
5391
+ app2.get("/api/channel-installations/:installationId", getChannelInstallation);
5392
+ app2.post("/api/channel-installations", createChannelInstallation);
5393
+ app2.put("/api/channel-installations/:installationId", updateChannelInstallation);
5394
+ app2.delete("/api/channel-installations/:installationId", deleteChannelInstallation);
5395
+ }
5396
+
4895
5397
  // src/routes/index.ts
4896
5398
  var registerLatticeRoutes = (app2) => {
4897
5399
  app2.post("/api/runs", createRun);
@@ -5027,6 +5529,8 @@ var registerLatticeRoutes = (app2) => {
5027
5529
  autoApproveUsers: process.env.AUTO_APPROVE_USERS !== "false",
5028
5530
  allowTenantRegistration: process.env.ALLOW_TENANT_REGISTRATION !== "false"
5029
5531
  });
5532
+ registerChannelRoutes(app2);
5533
+ registerChannelInstallationRoutes(app2);
5030
5534
  app2.delete(
5031
5535
  "/api/assistants/:assistant_id/threads/:thread_id/pending-messages/:message_id",
5032
5536
  removePendingMessageHandler
@@ -5096,7 +5600,7 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
5096
5600
  };
5097
5601
 
5098
5602
  // src/services/agent_task_consumer.ts
5099
- var import_core26 = require("@axiom-lattice/core");
5603
+ var import_core27 = require("@axiom-lattice/core");
5100
5604
  var handleAgentTask = async (taskRequest, retryCount = 0) => {
5101
5605
  const {
5102
5606
  assistant_id,
@@ -5111,18 +5615,18 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
5111
5615
  console.log(
5112
5616
  `\u5F00\u59CB\u5904\u7406\u4EFB\u52A1 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
5113
5617
  );
5114
- const agent = import_core26.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
5115
- await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core26.QueueMode.STEER);
5618
+ const agent = import_core27.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
5619
+ await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core27.QueueMode.STEER);
5116
5620
  if (callback_event) {
5117
5621
  agent.subscribeOnce("message:completed", (evt) => {
5118
- import_core26.eventBus.publish(callback_event, {
5622
+ import_core27.eventBus.publish(callback_event, {
5119
5623
  success: true,
5120
5624
  state: evt.state,
5121
5625
  config: { assistant_id, thread_id, tenant_id }
5122
5626
  });
5123
5627
  });
5124
5628
  agent.subscribeOnce("message:interrupted", (evt) => {
5125
- import_core26.eventBus.publish(callback_event, {
5629
+ import_core27.eventBus.publish(callback_event, {
5126
5630
  success: true,
5127
5631
  state: evt.state,
5128
5632
  config: { assistant_id, thread_id, tenant_id }
@@ -5146,7 +5650,7 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
5146
5650
  return handleAgentTask(taskRequest, nextRetryCount);
5147
5651
  }
5148
5652
  if (callback_event) {
5149
- import_core26.eventBus.publish(callback_event, {
5653
+ import_core27.eventBus.publish(callback_event, {
5150
5654
  success: false,
5151
5655
  error: error instanceof Error ? error.message : String(error),
5152
5656
  config: { assistant_id, thread_id, tenant_id }
@@ -5184,7 +5688,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
5184
5688
  * 初始化事件监听和队列轮询
5185
5689
  */
5186
5690
  initialize() {
5187
- import_core26.eventBus.subscribe(import_core26.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
5691
+ import_core27.eventBus.subscribe(import_core27.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
5188
5692
  this.startPollingQueue();
5189
5693
  console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
5190
5694
  }
@@ -5303,7 +5807,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
5303
5807
  handleAgentTask(taskRequest).catch((error) => {
5304
5808
  console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
5305
5809
  if (taskRequest.callback_event) {
5306
- import_core26.eventBus.publish(taskRequest.callback_event, {
5810
+ import_core27.eventBus.publish(taskRequest.callback_event, {
5307
5811
  success: false,
5308
5812
  error: error instanceof Error ? error.message : String(error),
5309
5813
  config: {
@@ -5323,26 +5827,26 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
5323
5827
  var AgentTaskConsumer = _AgentTaskConsumer;
5324
5828
 
5325
5829
  // src/index.ts
5326
- var import_core27 = require("@axiom-lattice/core");
5327
- var import_protocols3 = require("@axiom-lattice/protocols");
5830
+ var import_core28 = require("@axiom-lattice/core");
5831
+ var import_protocols5 = require("@axiom-lattice/protocols");
5328
5832
  process.on("unhandledRejection", (reason, promise) => {
5329
5833
  console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
5330
5834
  });
5331
5835
  var DEFAULT_LOGGER_CONFIG = {
5332
5836
  name: "default",
5333
5837
  description: "Default logger for lattice-gateway service",
5334
- type: import_protocols3.LoggerType.PINO,
5838
+ type: import_protocols5.LoggerType.PINO,
5335
5839
  serviceName: "lattice/gateway",
5336
5840
  loggerName: "lattice/gateway"
5337
5841
  };
5338
5842
  var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
5339
5843
  var logger = loggerLattice.client;
5340
5844
  function initializeLogger(config) {
5341
- if (import_core27.loggerLatticeManager.hasLattice("default")) {
5342
- import_core27.loggerLatticeManager.removeLattice("default");
5845
+ if (import_core28.loggerLatticeManager.hasLattice("default")) {
5846
+ import_core28.loggerLatticeManager.removeLattice("default");
5343
5847
  }
5344
- (0, import_core27.registerLoggerLattice)("default", config);
5345
- return (0, import_core27.getLoggerLattice)("default");
5848
+ (0, import_core28.registerLoggerLattice)("default", config);
5849
+ return (0, import_core28.getLoggerLattice)("default");
5346
5850
  }
5347
5851
  var app = (0, import_fastify.default)({
5348
5852
  logger: false,
@@ -5434,6 +5938,22 @@ app.setErrorHandler((error, request, reply) => {
5434
5938
  error: error.message || "\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF"
5435
5939
  });
5436
5940
  });
5941
+ function getConfiguredSandboxProvider() {
5942
+ const sandboxProviderType = process.env.SANDBOX_PROVIDER_TYPE || "microsandbox";
5943
+ return (0, import_core28.createSandboxProvider)({
5944
+ type: sandboxProviderType,
5945
+ remoteBaseURL: process.env.SANDBOX_BASE_URL,
5946
+ microsandboxServiceBaseURL: process.env.MICROSANDBOX_SERVICE_BASE_URL,
5947
+ e2bApiKey: process.env.E2B_API_KEY,
5948
+ e2bTemplate: process.env.E2B_TEMPLATE,
5949
+ e2bTimeoutMs: process.env.E2B_TIMEOUT_MS ? parseInt(process.env.E2B_TIMEOUT_MS, 10) : void 0,
5950
+ daytonaApiKey: process.env.DAYTONA_API_KEY,
5951
+ daytonaApiUrl: process.env.DAYTONA_API_URL,
5952
+ daytonaTarget: process.env.DAYTONA_TARGET,
5953
+ daytonaTimeout: process.env.DAYTONA_TIMEOUT ? parseInt(process.env.DAYTONA_TIMEOUT, 10) : void 0,
5954
+ daytonaVolumeName: process.env.DAYTONA_VOLUME_NAME
5955
+ });
5956
+ }
5437
5957
  var start = async (config) => {
5438
5958
  try {
5439
5959
  if (config?.loggerConfig) {
@@ -5449,19 +5969,16 @@ var start = async (config) => {
5449
5969
  app.decorate("loggerLattice", loggerLattice);
5450
5970
  registerLatticeRoutes(app);
5451
5971
  try {
5452
- const storeLattice = (0, import_core27.getStoreLattice)("default", "database");
5972
+ const storeLattice = (0, import_core28.getStoreLattice)("default", "database");
5453
5973
  const store = storeLattice.store;
5454
- import_core27.sqlDatabaseManager.setConfigStore(store);
5974
+ import_core28.sqlDatabaseManager.setConfigStore(store);
5455
5975
  logger.info("Database config store set for SqlDatabaseManager");
5456
5976
  } catch (error) {
5457
5977
  logger.warn("Failed to set database config store: " + (error instanceof Error ? error.message : String(error)));
5458
5978
  }
5459
- if (!import_core27.sandboxLatticeManager.hasLattice("default")) {
5460
- const sandboxBaseURL = process.env.SANDBOX_BASE_URL || "http://localhost:8080";
5461
- import_core27.sandboxLatticeManager.registerLattice("default", {
5462
- baseURL: sandboxBaseURL
5463
- });
5464
- logger.info(`Registered sandbox manager with baseURL: ${sandboxBaseURL}`);
5979
+ if (!import_core28.sandboxLatticeManager.hasLattice("default")) {
5980
+ import_core28.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
5981
+ logger.info("Registered sandbox manager from env configuration");
5465
5982
  }
5466
5983
  const target_port = config?.port || Number(process.env.PORT) || 4001;
5467
5984
  await app.listen({ port: target_port, host: "0.0.0.0" });
@@ -5481,7 +5998,7 @@ var start = async (config) => {
5481
5998
  }
5482
5999
  try {
5483
6000
  logger.info("Starting agent instance recovery...");
5484
- const restoreStats = await import_core27.agentInstanceManager.restore();
6001
+ const restoreStats = await import_core28.agentInstanceManager.restore();
5485
6002
  logger.info(`Agent recovery complete: ${restoreStats.restored} threads restored, ${restoreStats.errors} errors`);
5486
6003
  } catch (error) {
5487
6004
  logger.error("Agent recovery failed", { error });