@axiom-lattice/gateway 2.1.20 → 2.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +20 -0
- package/dist/index.js +691 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +680 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -4
- package/src/controllers/sandbox.ts +150 -0
- package/src/controllers/skills.ts +474 -0
- package/src/controllers/tools.ts +410 -0
- package/src/index.ts +4 -0
- package/src/routes/index.ts +69 -1
- package/src/schemas/index.ts +495 -0
- package/src/services/agent_service.ts +14 -6
- package/src/services/sandbox_service.ts +222 -0
package/dist/index.js
CHANGED
|
@@ -36,6 +36,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
36
36
|
var import_fastify = __toESM(require("fastify"));
|
|
37
37
|
var import_cors = __toESM(require("@fastify/cors"));
|
|
38
38
|
var import_sensible = __toESM(require("@fastify/sensible"));
|
|
39
|
+
var import_websocket = __toESM(require("@fastify/websocket"));
|
|
39
40
|
|
|
40
41
|
// src/services/agent_service.ts
|
|
41
42
|
var import_messages = require("@langchain/core/messages");
|
|
@@ -70,7 +71,11 @@ async function agent_invoke({
|
|
|
70
71
|
if (!runnable_agent) {
|
|
71
72
|
throw new Error(`Agent ${assistant_id} not found`);
|
|
72
73
|
}
|
|
73
|
-
const runConfig =
|
|
74
|
+
const runConfig = {
|
|
75
|
+
...agentLattice?.config?.runConfig || {},
|
|
76
|
+
assistant_id,
|
|
77
|
+
sandboxConfig: agentLattice?.config?.connectedSandbox
|
|
78
|
+
};
|
|
74
79
|
const result = await runnable_agent.invoke(
|
|
75
80
|
command ? new import_langgraph.Command(command) : { ...rest, messages, "x-tenant-id": tenant_id },
|
|
76
81
|
{
|
|
@@ -112,7 +117,11 @@ async function agent_stream({
|
|
|
112
117
|
messages = [humanMessage];
|
|
113
118
|
}
|
|
114
119
|
const chunkBuffer = getOrCreateChunkBuffer();
|
|
115
|
-
const runConfig =
|
|
120
|
+
const runConfig = {
|
|
121
|
+
...agentLattice?.config?.runConfig || {},
|
|
122
|
+
assistant_id,
|
|
123
|
+
sandboxConfig: agentLattice?.config?.connectedSandbox
|
|
124
|
+
};
|
|
116
125
|
try {
|
|
117
126
|
if (!runnable_agent) {
|
|
118
127
|
throw new Error(`Agent ${assistant_id} not found`);
|
|
@@ -1339,6 +1348,393 @@ async function getHealth(request, reply) {
|
|
|
1339
1348
|
}
|
|
1340
1349
|
}
|
|
1341
1350
|
|
|
1351
|
+
// src/controllers/skills.ts
|
|
1352
|
+
var import_core9 = require("@axiom-lattice/core");
|
|
1353
|
+
var import_core10 = require("@axiom-lattice/core");
|
|
1354
|
+
function serializeSkill(skill) {
|
|
1355
|
+
const serialized = {
|
|
1356
|
+
id: skill.id,
|
|
1357
|
+
name: skill.name,
|
|
1358
|
+
description: skill.description,
|
|
1359
|
+
license: skill.license,
|
|
1360
|
+
compatibility: skill.compatibility,
|
|
1361
|
+
metadata: skill.metadata || {},
|
|
1362
|
+
content: skill.content,
|
|
1363
|
+
subSkills: skill.subSkills,
|
|
1364
|
+
createdAt: skill.createdAt instanceof Date ? skill.createdAt.toISOString() : skill.createdAt ? new Date(skill.createdAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
|
|
1365
|
+
updatedAt: skill.updatedAt instanceof Date ? skill.updatedAt.toISOString() : skill.updatedAt ? new Date(skill.updatedAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
1366
|
+
};
|
|
1367
|
+
Object.keys(serialized).forEach((key) => {
|
|
1368
|
+
if (serialized[key] === void 0) {
|
|
1369
|
+
delete serialized[key];
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
return serialized;
|
|
1373
|
+
}
|
|
1374
|
+
async function getSkillList(request, reply) {
|
|
1375
|
+
try {
|
|
1376
|
+
const storeLattice = (0, import_core9.getStoreLattice)("default", "skill");
|
|
1377
|
+
const skillStore = storeLattice.store;
|
|
1378
|
+
const skills = await skillStore.getAllSkills();
|
|
1379
|
+
const serializedSkills = skills.map(serializeSkill);
|
|
1380
|
+
return {
|
|
1381
|
+
success: true,
|
|
1382
|
+
message: "Successfully retrieved skill list",
|
|
1383
|
+
data: {
|
|
1384
|
+
records: serializedSkills,
|
|
1385
|
+
total: serializedSkills.length
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
return reply.status(500).send({
|
|
1390
|
+
success: false,
|
|
1391
|
+
message: `Failed to retrieve skills: ${error.message}`,
|
|
1392
|
+
data: {
|
|
1393
|
+
records: [],
|
|
1394
|
+
total: 0
|
|
1395
|
+
}
|
|
1396
|
+
});
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
async function getSkill(request, reply) {
|
|
1400
|
+
try {
|
|
1401
|
+
const { id } = request.params;
|
|
1402
|
+
const storeLattice = (0, import_core9.getStoreLattice)("default", "skill");
|
|
1403
|
+
const skillStore = storeLattice.store;
|
|
1404
|
+
const skill = await skillStore.getSkillById(id);
|
|
1405
|
+
if (!skill) {
|
|
1406
|
+
return reply.status(404).send({
|
|
1407
|
+
success: false,
|
|
1408
|
+
message: "Skill not found"
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
return {
|
|
1412
|
+
success: true,
|
|
1413
|
+
message: "Successfully retrieved skill",
|
|
1414
|
+
data: serializeSkill(skill)
|
|
1415
|
+
};
|
|
1416
|
+
} catch (error) {
|
|
1417
|
+
return reply.status(500).send({
|
|
1418
|
+
success: false,
|
|
1419
|
+
message: `Failed to retrieve skill: ${error.message}`
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
async function createSkill(request, reply) {
|
|
1424
|
+
try {
|
|
1425
|
+
const data = request.body;
|
|
1426
|
+
if (!data.name) {
|
|
1427
|
+
return reply.status(400).send({
|
|
1428
|
+
success: false,
|
|
1429
|
+
message: "name is required"
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
if (!data.description) {
|
|
1433
|
+
return reply.status(400).send({
|
|
1434
|
+
success: false,
|
|
1435
|
+
message: "description is required"
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
try {
|
|
1439
|
+
(0, import_core10.validateSkillName)(data.name);
|
|
1440
|
+
} catch (error) {
|
|
1441
|
+
return reply.status(400).send({
|
|
1442
|
+
success: false,
|
|
1443
|
+
message: error.message || "Invalid skill name format"
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
const id = request.body.id || data.name;
|
|
1447
|
+
if (id !== data.name) {
|
|
1448
|
+
return reply.status(400).send({
|
|
1449
|
+
success: false,
|
|
1450
|
+
message: `id "${id}" must equal name "${data.name}" (name is used for path addressing)`
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1453
|
+
const storeLattice = (0, import_core9.getStoreLattice)("default", "skill");
|
|
1454
|
+
const skillStore = storeLattice.store;
|
|
1455
|
+
const exists = await skillStore.hasSkill(id);
|
|
1456
|
+
if (exists) {
|
|
1457
|
+
return reply.status(409).send({
|
|
1458
|
+
success: false,
|
|
1459
|
+
message: `Skill with id "${id}" already exists`
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
const newSkill = await skillStore.createSkill(id, data);
|
|
1463
|
+
return reply.status(201).send({
|
|
1464
|
+
success: true,
|
|
1465
|
+
message: "Successfully created skill",
|
|
1466
|
+
data: serializeSkill(newSkill)
|
|
1467
|
+
});
|
|
1468
|
+
} catch (error) {
|
|
1469
|
+
return reply.status(500).send({
|
|
1470
|
+
success: false,
|
|
1471
|
+
message: `Failed to create skill: ${error.message}`
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
async function updateSkill(request, reply) {
|
|
1476
|
+
try {
|
|
1477
|
+
const { id } = request.params;
|
|
1478
|
+
const updates = request.body;
|
|
1479
|
+
if (updates.name !== void 0) {
|
|
1480
|
+
try {
|
|
1481
|
+
(0, import_core10.validateSkillName)(updates.name);
|
|
1482
|
+
} catch (error) {
|
|
1483
|
+
return reply.status(400).send({
|
|
1484
|
+
success: false,
|
|
1485
|
+
message: error.message || "Invalid skill name format"
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
const storeLattice = (0, import_core9.getStoreLattice)("default", "skill");
|
|
1490
|
+
const skillStore = storeLattice.store;
|
|
1491
|
+
const exists = await skillStore.hasSkill(id);
|
|
1492
|
+
if (!exists) {
|
|
1493
|
+
return reply.status(404).send({
|
|
1494
|
+
success: false,
|
|
1495
|
+
message: "Skill not found"
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
const updatedSkill = await skillStore.updateSkill(id, updates);
|
|
1499
|
+
if (!updatedSkill) {
|
|
1500
|
+
return reply.status(500).send({
|
|
1501
|
+
success: false,
|
|
1502
|
+
message: "Failed to update skill"
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
return {
|
|
1506
|
+
success: true,
|
|
1507
|
+
message: "Successfully updated skill",
|
|
1508
|
+
data: serializeSkill(updatedSkill)
|
|
1509
|
+
};
|
|
1510
|
+
} catch (error) {
|
|
1511
|
+
return reply.status(500).send({
|
|
1512
|
+
success: false,
|
|
1513
|
+
message: `Failed to update skill: ${error.message}`
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
async function deleteSkill(request, reply) {
|
|
1518
|
+
try {
|
|
1519
|
+
const { id } = request.params;
|
|
1520
|
+
const storeLattice = (0, import_core9.getStoreLattice)("default", "skill");
|
|
1521
|
+
const skillStore = storeLattice.store;
|
|
1522
|
+
const exists = await skillStore.hasSkill(id);
|
|
1523
|
+
if (!exists) {
|
|
1524
|
+
return reply.status(404).send({
|
|
1525
|
+
success: false,
|
|
1526
|
+
message: "Skill not found"
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
const deleted = await skillStore.deleteSkill(id);
|
|
1530
|
+
if (!deleted) {
|
|
1531
|
+
return reply.status(500).send({
|
|
1532
|
+
success: false,
|
|
1533
|
+
message: "Failed to delete skill"
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
return {
|
|
1537
|
+
success: true,
|
|
1538
|
+
message: "Successfully deleted skill"
|
|
1539
|
+
};
|
|
1540
|
+
} catch (error) {
|
|
1541
|
+
return reply.status(500).send({
|
|
1542
|
+
success: false,
|
|
1543
|
+
message: `Failed to delete skill: ${error.message}`
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
async function searchSkillsByMetadata(request, reply) {
|
|
1548
|
+
try {
|
|
1549
|
+
const { key, value } = request.query;
|
|
1550
|
+
if (!key || !value) {
|
|
1551
|
+
return reply.status(400).send({
|
|
1552
|
+
success: false,
|
|
1553
|
+
message: "key and value query parameters are required",
|
|
1554
|
+
data: {
|
|
1555
|
+
records: [],
|
|
1556
|
+
total: 0
|
|
1557
|
+
}
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
const storeLattice = (0, import_core9.getStoreLattice)("default", "skill");
|
|
1561
|
+
const skillStore = storeLattice.store;
|
|
1562
|
+
const skills = await skillStore.searchByMetadata(key, value);
|
|
1563
|
+
const serializedSkills = skills.map(serializeSkill);
|
|
1564
|
+
return {
|
|
1565
|
+
success: true,
|
|
1566
|
+
message: "Successfully searched skills",
|
|
1567
|
+
data: {
|
|
1568
|
+
records: serializedSkills,
|
|
1569
|
+
total: serializedSkills.length
|
|
1570
|
+
}
|
|
1571
|
+
};
|
|
1572
|
+
} catch (error) {
|
|
1573
|
+
return reply.status(500).send({
|
|
1574
|
+
success: false,
|
|
1575
|
+
message: `Failed to search skills: ${error.message}`,
|
|
1576
|
+
data: {
|
|
1577
|
+
records: [],
|
|
1578
|
+
total: 0
|
|
1579
|
+
}
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
async function filterSkillsByCompatibility(request, reply) {
|
|
1584
|
+
try {
|
|
1585
|
+
const { compatibility } = request.query;
|
|
1586
|
+
if (!compatibility) {
|
|
1587
|
+
return reply.status(400).send({
|
|
1588
|
+
success: false,
|
|
1589
|
+
message: "compatibility query parameter is required",
|
|
1590
|
+
data: {
|
|
1591
|
+
records: [],
|
|
1592
|
+
total: 0
|
|
1593
|
+
}
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
const storeLattice = (0, import_core9.getStoreLattice)("default", "skill");
|
|
1597
|
+
const skillStore = storeLattice.store;
|
|
1598
|
+
const skills = await skillStore.filterByCompatibility(compatibility);
|
|
1599
|
+
const serializedSkills = skills.map(serializeSkill);
|
|
1600
|
+
return {
|
|
1601
|
+
success: true,
|
|
1602
|
+
message: "Successfully filtered skills",
|
|
1603
|
+
data: {
|
|
1604
|
+
records: serializedSkills,
|
|
1605
|
+
total: serializedSkills.length
|
|
1606
|
+
}
|
|
1607
|
+
};
|
|
1608
|
+
} catch (error) {
|
|
1609
|
+
return reply.status(500).send({
|
|
1610
|
+
success: false,
|
|
1611
|
+
message: `Failed to filter skills: ${error.message}`,
|
|
1612
|
+
data: {
|
|
1613
|
+
records: [],
|
|
1614
|
+
total: 0
|
|
1615
|
+
}
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
async function filterSkillsByLicense(request, reply) {
|
|
1620
|
+
try {
|
|
1621
|
+
const { license } = request.query;
|
|
1622
|
+
if (!license) {
|
|
1623
|
+
return reply.status(400).send({
|
|
1624
|
+
success: false,
|
|
1625
|
+
message: "license query parameter is required",
|
|
1626
|
+
data: {
|
|
1627
|
+
records: [],
|
|
1628
|
+
total: 0
|
|
1629
|
+
}
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
const storeLattice = (0, import_core9.getStoreLattice)("default", "skill");
|
|
1633
|
+
const skillStore = storeLattice.store;
|
|
1634
|
+
const skills = await skillStore.filterByLicense(license);
|
|
1635
|
+
const serializedSkills = skills.map(serializeSkill);
|
|
1636
|
+
return {
|
|
1637
|
+
success: true,
|
|
1638
|
+
message: "Successfully filtered skills",
|
|
1639
|
+
data: {
|
|
1640
|
+
records: serializedSkills,
|
|
1641
|
+
total: serializedSkills.length
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
} catch (error) {
|
|
1645
|
+
return reply.status(500).send({
|
|
1646
|
+
success: false,
|
|
1647
|
+
message: `Failed to filter skills: ${error.message}`,
|
|
1648
|
+
data: {
|
|
1649
|
+
records: [],
|
|
1650
|
+
total: 0
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
// src/controllers/tools.ts
|
|
1657
|
+
var import_core11 = require("@axiom-lattice/core");
|
|
1658
|
+
function serializeSchema(schema) {
|
|
1659
|
+
if (!schema) {
|
|
1660
|
+
return void 0;
|
|
1661
|
+
}
|
|
1662
|
+
try {
|
|
1663
|
+
if (schema._def) {
|
|
1664
|
+
const def = schema._def;
|
|
1665
|
+
if (def.typeName === "ZodObject") {
|
|
1666
|
+
const shape = def.shape();
|
|
1667
|
+
const properties = {};
|
|
1668
|
+
const required = [];
|
|
1669
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
1670
|
+
const fieldDef = value._def;
|
|
1671
|
+
if (fieldDef) {
|
|
1672
|
+
properties[key] = {
|
|
1673
|
+
type: fieldDef.typeName === "ZodString" ? "string" : fieldDef.typeName === "ZodNumber" ? "number" : fieldDef.typeName === "ZodBoolean" ? "boolean" : fieldDef.typeName === "ZodArray" ? "array" : fieldDef.typeName === "ZodObject" ? "object" : "unknown",
|
|
1674
|
+
description: fieldDef.description
|
|
1675
|
+
};
|
|
1676
|
+
if (!value.isOptional()) {
|
|
1677
|
+
required.push(key);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
return {
|
|
1682
|
+
type: "object",
|
|
1683
|
+
properties,
|
|
1684
|
+
required: required.length > 0 ? required : void 0
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
return {
|
|
1689
|
+
type: "object",
|
|
1690
|
+
description: schema.description || "Schema definition"
|
|
1691
|
+
};
|
|
1692
|
+
} catch (error) {
|
|
1693
|
+
return {
|
|
1694
|
+
type: "object",
|
|
1695
|
+
description: "Schema definition"
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
async function getToolConfigs(request, reply) {
|
|
1700
|
+
try {
|
|
1701
|
+
const allLattices = import_core11.toolLatticeManager.getAllLattices();
|
|
1702
|
+
const toolConfigs = allLattices.map((lattice) => {
|
|
1703
|
+
const config = { ...lattice.config };
|
|
1704
|
+
const serializedSchema = config.schema ? serializeSchema(config.schema) : void 0;
|
|
1705
|
+
return {
|
|
1706
|
+
id: lattice.key,
|
|
1707
|
+
name: config.name,
|
|
1708
|
+
description: config.description,
|
|
1709
|
+
schema: serializedSchema,
|
|
1710
|
+
returnDirect: config.returnDirect,
|
|
1711
|
+
needUserApprove: config.needUserApprove
|
|
1712
|
+
};
|
|
1713
|
+
});
|
|
1714
|
+
return reply.send({
|
|
1715
|
+
success: true,
|
|
1716
|
+
message: "Successfully retrieved tool configs",
|
|
1717
|
+
data: {
|
|
1718
|
+
records: toolConfigs,
|
|
1719
|
+
total: toolConfigs.length
|
|
1720
|
+
}
|
|
1721
|
+
});
|
|
1722
|
+
} catch (error) {
|
|
1723
|
+
console.error("Failed to get tool configs", {
|
|
1724
|
+
error: error.message,
|
|
1725
|
+
stack: error.stack
|
|
1726
|
+
});
|
|
1727
|
+
return reply.status(500).send({
|
|
1728
|
+
success: false,
|
|
1729
|
+
message: `Failed to retrieve tool configs: ${error.message}`,
|
|
1730
|
+
data: {
|
|
1731
|
+
records: [],
|
|
1732
|
+
total: 0
|
|
1733
|
+
}
|
|
1734
|
+
});
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1342
1738
|
// src/schemas/index.ts
|
|
1343
1739
|
var getAllMemoryItemsSchema = {
|
|
1344
1740
|
description: "Get all memory items for an assistant thread",
|
|
@@ -1610,6 +2006,256 @@ var getHealthSchema = {
|
|
|
1610
2006
|
}
|
|
1611
2007
|
};
|
|
1612
2008
|
|
|
2009
|
+
// src/services/sandbox_service.ts
|
|
2010
|
+
var import_core12 = require("@axiom-lattice/core");
|
|
2011
|
+
var SANDBOX_BASE_URL = process.env.SANDBOX_BASE_URL || "http://localhost:8080";
|
|
2012
|
+
var ERROR_HTML = `<!DOCTYPE html>
|
|
2013
|
+
<html lang="zh-CN">
|
|
2014
|
+
<head>
|
|
2015
|
+
<meta charset="UTF-8">
|
|
2016
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2017
|
+
<title>Sandbox \u8FDE\u63A5\u9519\u8BEF</title>
|
|
2018
|
+
<style>
|
|
2019
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
2020
|
+
body {
|
|
2021
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
2022
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
2023
|
+
min-height: 100vh;
|
|
2024
|
+
display: flex;
|
|
2025
|
+
align-items: center;
|
|
2026
|
+
justify-content: center;
|
|
2027
|
+
padding: 20px;
|
|
2028
|
+
}
|
|
2029
|
+
.container {
|
|
2030
|
+
background: white;
|
|
2031
|
+
border-radius: 16px;
|
|
2032
|
+
padding: 40px;
|
|
2033
|
+
max-width: 500px;
|
|
2034
|
+
width: 100%;
|
|
2035
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
2036
|
+
}
|
|
2037
|
+
.error-icon {
|
|
2038
|
+
width: 80px;
|
|
2039
|
+
height: 80px;
|
|
2040
|
+
background: #fee2e2;
|
|
2041
|
+
border-radius: 50%;
|
|
2042
|
+
display: flex;
|
|
2043
|
+
align-items: center;
|
|
2044
|
+
justify-content: center;
|
|
2045
|
+
margin: 0 auto 24px;
|
|
2046
|
+
}
|
|
2047
|
+
.error-icon svg {
|
|
2048
|
+
width: 40px;
|
|
2049
|
+
height: 40px;
|
|
2050
|
+
color: #dc2626;
|
|
2051
|
+
}
|
|
2052
|
+
h1 { color: #1f2937; margin-bottom: 16px; text-align: center; }
|
|
2053
|
+
p { color: #6b7280; margin-bottom: 12px; line-height: 1.6; }
|
|
2054
|
+
.info {
|
|
2055
|
+
background: #f3f4f6;
|
|
2056
|
+
border-radius: 8px;
|
|
2057
|
+
padding: 16px;
|
|
2058
|
+
margin: 20px 0;
|
|
2059
|
+
}
|
|
2060
|
+
.info-item {
|
|
2061
|
+
display: flex;
|
|
2062
|
+
justify-content: space-between;
|
|
2063
|
+
padding: 8px 0;
|
|
2064
|
+
border-bottom: 1px solid #e5e7eb;
|
|
2065
|
+
}
|
|
2066
|
+
.info-item:last-child { border-bottom: none; }
|
|
2067
|
+
.label { color: #6b7280; font-size: 14px; }
|
|
2068
|
+
.value { color: #1f2937; font-weight: 500; font-family: monospace; }
|
|
2069
|
+
.retry-btn {
|
|
2070
|
+
width: 100%;
|
|
2071
|
+
padding: 14px;
|
|
2072
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
2073
|
+
color: white;
|
|
2074
|
+
border: none;
|
|
2075
|
+
border-radius: 8px;
|
|
2076
|
+
font-size: 16px;
|
|
2077
|
+
cursor: pointer;
|
|
2078
|
+
transition: transform 0.2s;
|
|
2079
|
+
}
|
|
2080
|
+
.retry-btn:hover { transform: translateY(-2px); }
|
|
2081
|
+
</style>
|
|
2082
|
+
</head>
|
|
2083
|
+
<body>
|
|
2084
|
+
<div class="container">
|
|
2085
|
+
<div class="error-icon">
|
|
2086
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
2087
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
|
2088
|
+
</svg>
|
|
2089
|
+
</div>
|
|
2090
|
+
<h1>\u65E0\u6CD5\u8FDE\u63A5\u5230 Sandbox</h1>
|
|
2091
|
+
<p>\u65E0\u6CD5\u8FDE\u63A5\u5230\u6C99\u7BB1\u73AF\u5883\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E\u540E\u91CD\u8BD5\u3002</p>
|
|
2092
|
+
<div class="info">
|
|
2093
|
+
<div class="info-item">
|
|
2094
|
+
<span class="label">Assistant ID</span>
|
|
2095
|
+
<span class="value" id="assistantId">-</span>
|
|
2096
|
+
</div>
|
|
2097
|
+
<div class="info-item">
|
|
2098
|
+
<span class="label">Thread ID</span>
|
|
2099
|
+
<span class="value" id="threadId">-</span>
|
|
2100
|
+
</div>
|
|
2101
|
+
<div class="info-item">
|
|
2102
|
+
<span class="label">\u9694\u79BB\u7EA7\u522B</span>
|
|
2103
|
+
<span class="value" id="isolatedLevel">-</span>
|
|
2104
|
+
</div>
|
|
2105
|
+
<div class="info-item">
|
|
2106
|
+
<span class="label">\u9519\u8BEF\u4FE1\u606F</span>
|
|
2107
|
+
<span class="value" id="errorMsg">-</span>
|
|
2108
|
+
</div>
|
|
2109
|
+
</div>
|
|
2110
|
+
<button class="retry-btn" onclick="window.location.reload()">\u91CD\u65B0\u8FDE\u63A5</button>
|
|
2111
|
+
</div>
|
|
2112
|
+
<script>
|
|
2113
|
+
const params = new URLSearchParams(window.location.search);
|
|
2114
|
+
document.getElementById('assistantId').textContent = params.get('assistantId') || '-';
|
|
2115
|
+
document.getElementById('threadId').textContent = params.get('threadId') || '-';
|
|
2116
|
+
document.getElementById('isolatedLevel').textContent = params.get('isolatedLevel') || '-';
|
|
2117
|
+
document.getElementById('errorMsg').textContent = params.get('error') || '\u672A\u77E5\u9519\u8BEF';
|
|
2118
|
+
</script>
|
|
2119
|
+
</body>
|
|
2120
|
+
</html>`;
|
|
2121
|
+
var SandboxService = class {
|
|
2122
|
+
constructor(baseUrl) {
|
|
2123
|
+
this.baseUrl = baseUrl || SANDBOX_BASE_URL;
|
|
2124
|
+
}
|
|
2125
|
+
getSandboxConfig(assistantId) {
|
|
2126
|
+
const agentConfig = (0, import_core12.getAgentConfig)(assistantId);
|
|
2127
|
+
if (!agentConfig) {
|
|
2128
|
+
return null;
|
|
2129
|
+
}
|
|
2130
|
+
const agentLattice = (0, import_core12.getAgentLattice)(assistantId);
|
|
2131
|
+
return agentLattice?.config?.connectedSandbox || null;
|
|
2132
|
+
}
|
|
2133
|
+
computeSandboxName(assistantId, threadId, isolatedLevel) {
|
|
2134
|
+
let sandboxName;
|
|
2135
|
+
switch (isolatedLevel) {
|
|
2136
|
+
case "agent":
|
|
2137
|
+
sandboxName = assistantId;
|
|
2138
|
+
break;
|
|
2139
|
+
case "thread":
|
|
2140
|
+
sandboxName = threadId;
|
|
2141
|
+
break;
|
|
2142
|
+
case "global":
|
|
2143
|
+
default:
|
|
2144
|
+
sandboxName = "global";
|
|
2145
|
+
break;
|
|
2146
|
+
}
|
|
2147
|
+
return (0, import_core12.normalizeSandboxName)(sandboxName);
|
|
2148
|
+
}
|
|
2149
|
+
getTargetUrl(sandboxName) {
|
|
2150
|
+
return `${this.baseUrl}/sandbox/${sandboxName}`;
|
|
2151
|
+
}
|
|
2152
|
+
async getVncHtml(sandboxName) {
|
|
2153
|
+
const response = await fetch(`${this.getTargetUrl(sandboxName)}/vnc/index.html`);
|
|
2154
|
+
if (!response.ok) {
|
|
2155
|
+
throw new Error(`Failed to fetch VNC HTML: ${response.statusText}`);
|
|
2156
|
+
}
|
|
2157
|
+
return response.text();
|
|
2158
|
+
}
|
|
2159
|
+
rewriteHtml(html, assistantId, threadId) {
|
|
2160
|
+
const prefix = `/api/assistants/${assistantId}/threads/${threadId}/sandbox/vnc`;
|
|
2161
|
+
let rewritten = html;
|
|
2162
|
+
rewritten = rewritten.replace(
|
|
2163
|
+
/(src|href)=["']([^"']*)["']/g,
|
|
2164
|
+
(match, attr, url) => {
|
|
2165
|
+
if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("//")) {
|
|
2166
|
+
return match;
|
|
2167
|
+
}
|
|
2168
|
+
const rewrittenUrl = url.startsWith("/") ? `${prefix}${url}` : `${prefix}/${url}`;
|
|
2169
|
+
return `${attr}="${rewrittenUrl}"`;
|
|
2170
|
+
}
|
|
2171
|
+
);
|
|
2172
|
+
rewritten = rewritten.replace(
|
|
2173
|
+
/path=sandbox\/[^&"']+/g,
|
|
2174
|
+
(match) => {
|
|
2175
|
+
return `path=${prefix}/websockify`;
|
|
2176
|
+
}
|
|
2177
|
+
);
|
|
2178
|
+
rewritten = rewritten.replace(
|
|
2179
|
+
/new WebSocket\([^)]*\?path=sandbox[^)]*\)/g,
|
|
2180
|
+
(match) => {
|
|
2181
|
+
return match.replace(/path=sandbox[^)]+/, `path=${prefix}/websockify`);
|
|
2182
|
+
}
|
|
2183
|
+
);
|
|
2184
|
+
return rewritten;
|
|
2185
|
+
}
|
|
2186
|
+
generateErrorHtml(assistantId, threadId, isolatedLevel, errorMessage) {
|
|
2187
|
+
const encodedError = encodeURIComponent(errorMessage);
|
|
2188
|
+
return ERROR_HTML.replace("{assistantId}", assistantId).replace("{threadId}", threadId).replace("{isolatedLevel}", isolatedLevel).replace("{errorMessage}", errorMessage);
|
|
2189
|
+
}
|
|
2190
|
+
};
|
|
2191
|
+
var sandboxService = new SandboxService();
|
|
2192
|
+
|
|
2193
|
+
// src/controllers/sandbox.ts
|
|
2194
|
+
var SANDBOX_BASE_URL2 = process.env.SANDBOX_BASE_URL || "http://localhost:8080";
|
|
2195
|
+
async function registerSandboxProxyRoutes(app2) {
|
|
2196
|
+
app2.get(
|
|
2197
|
+
"/api/assistants/:assistantId/threads/:threadId/sandbox",
|
|
2198
|
+
async (request, reply) => {
|
|
2199
|
+
const { assistantId, threadId } = request.params;
|
|
2200
|
+
const sandboxConfig = sandboxService.getSandboxConfig(assistantId);
|
|
2201
|
+
if (!sandboxConfig) {
|
|
2202
|
+
const errorHtml = sandboxService.generateErrorHtml(
|
|
2203
|
+
assistantId,
|
|
2204
|
+
threadId,
|
|
2205
|
+
"unknown",
|
|
2206
|
+
`Assistant ${assistantId} not found`
|
|
2207
|
+
);
|
|
2208
|
+
return reply.status(404).type("text/html").send(errorHtml);
|
|
2209
|
+
}
|
|
2210
|
+
const { isolatedLevel } = sandboxConfig;
|
|
2211
|
+
const sandboxName = sandboxService.computeSandboxName(
|
|
2212
|
+
assistantId,
|
|
2213
|
+
threadId,
|
|
2214
|
+
isolatedLevel
|
|
2215
|
+
);
|
|
2216
|
+
try {
|
|
2217
|
+
const html = await sandboxService.getVncHtml(sandboxName);
|
|
2218
|
+
const rewrittenHtml = sandboxService.rewriteHtml(html, assistantId, threadId);
|
|
2219
|
+
return reply.type("text/html").send(rewrittenHtml);
|
|
2220
|
+
} catch (error) {
|
|
2221
|
+
const errorHtml = sandboxService.generateErrorHtml(
|
|
2222
|
+
assistantId,
|
|
2223
|
+
threadId,
|
|
2224
|
+
isolatedLevel,
|
|
2225
|
+
error.message || "Failed to connect to sandbox"
|
|
2226
|
+
);
|
|
2227
|
+
return reply.status(502).type("text/html").send(errorHtml);
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
);
|
|
2231
|
+
app2.get(
|
|
2232
|
+
"/api/assistants/:assistantId/threads/:threadId/sandbox/vnc/*",
|
|
2233
|
+
async (request, reply) => {
|
|
2234
|
+
const { assistantId, threadId, "*": restPath } = request.params;
|
|
2235
|
+
const sandboxConfig = sandboxService.getSandboxConfig(assistantId);
|
|
2236
|
+
if (!sandboxConfig) {
|
|
2237
|
+
return reply.status(404).send("Assistant not found");
|
|
2238
|
+
}
|
|
2239
|
+
const { isolatedLevel } = sandboxConfig;
|
|
2240
|
+
const sandboxName = sandboxService.computeSandboxName(
|
|
2241
|
+
assistantId,
|
|
2242
|
+
threadId,
|
|
2243
|
+
isolatedLevel
|
|
2244
|
+
);
|
|
2245
|
+
const targetPath = restPath ? `/vnc/${restPath}` : "/vnc/";
|
|
2246
|
+
const targetUrl = `${sandboxService.getTargetUrl(sandboxName)}${targetPath}`;
|
|
2247
|
+
try {
|
|
2248
|
+
const response = await fetch(targetUrl);
|
|
2249
|
+
const contentType = response.headers.get("content-type") || "application/octet-stream";
|
|
2250
|
+
const body = await response.arrayBuffer();
|
|
2251
|
+
reply.status(response.status).type(contentType).send(Buffer.from(body));
|
|
2252
|
+
} catch (error) {
|
|
2253
|
+
reply.status(502).send(`Proxy error: ${error.message}`);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
);
|
|
2257
|
+
}
|
|
2258
|
+
|
|
1613
2259
|
// src/routes/index.ts
|
|
1614
2260
|
var registerLatticeRoutes = (app2) => {
|
|
1615
2261
|
app2.post("/api/runs", createRun);
|
|
@@ -1685,6 +2331,7 @@ var registerLatticeRoutes = (app2) => {
|
|
|
1685
2331
|
);
|
|
1686
2332
|
app2.get("/api/models", getModels);
|
|
1687
2333
|
app2.put("/api/models", updateModels);
|
|
2334
|
+
app2.get("/api/tools", getToolConfigs);
|
|
1688
2335
|
app2.get(
|
|
1689
2336
|
"/health",
|
|
1690
2337
|
{ schema: getHealthSchema },
|
|
@@ -1698,6 +2345,36 @@ var registerLatticeRoutes = (app2) => {
|
|
|
1698
2345
|
app2.post("/api/schedules/:taskId/cancel", cancelScheduledTask);
|
|
1699
2346
|
app2.post("/api/schedules/:taskId/pause", pauseScheduledTask);
|
|
1700
2347
|
app2.post("/api/schedules/:taskId/resume", resumeScheduledTask);
|
|
2348
|
+
app2.get("/api/skills", getSkillList);
|
|
2349
|
+
app2.get(
|
|
2350
|
+
"/api/skills/:id",
|
|
2351
|
+
getSkill
|
|
2352
|
+
);
|
|
2353
|
+
app2.post(
|
|
2354
|
+
"/api/skills",
|
|
2355
|
+
createSkill
|
|
2356
|
+
);
|
|
2357
|
+
app2.put(
|
|
2358
|
+
"/api/skills/:id",
|
|
2359
|
+
updateSkill
|
|
2360
|
+
);
|
|
2361
|
+
app2.delete(
|
|
2362
|
+
"/api/skills/:id",
|
|
2363
|
+
deleteSkill
|
|
2364
|
+
);
|
|
2365
|
+
app2.get(
|
|
2366
|
+
"/api/skills/search/metadata",
|
|
2367
|
+
searchSkillsByMetadata
|
|
2368
|
+
);
|
|
2369
|
+
app2.get(
|
|
2370
|
+
"/api/skills/filter/compatibility",
|
|
2371
|
+
filterSkillsByCompatibility
|
|
2372
|
+
);
|
|
2373
|
+
app2.get(
|
|
2374
|
+
"/api/skills/filter/license",
|
|
2375
|
+
filterSkillsByLicense
|
|
2376
|
+
);
|
|
2377
|
+
registerSandboxProxyRoutes(app2);
|
|
1701
2378
|
};
|
|
1702
2379
|
|
|
1703
2380
|
// src/swagger.ts
|
|
@@ -1763,7 +2440,7 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
|
|
|
1763
2440
|
};
|
|
1764
2441
|
|
|
1765
2442
|
// src/services/agent_task_consumer.ts
|
|
1766
|
-
var
|
|
2443
|
+
var import_core13 = require("@axiom-lattice/core");
|
|
1767
2444
|
var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
1768
2445
|
const {
|
|
1769
2446
|
assistant_id,
|
|
@@ -1827,7 +2504,7 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
|
1827
2504
|
}
|
|
1828
2505
|
if (callback_event) {
|
|
1829
2506
|
const state = await agent_state({ assistant_id, thread_id });
|
|
1830
|
-
|
|
2507
|
+
import_core13.eventBus.publish(callback_event, {
|
|
1831
2508
|
success: true,
|
|
1832
2509
|
state,
|
|
1833
2510
|
config: { assistant_id, thread_id, tenant_id }
|
|
@@ -1841,7 +2518,7 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
|
1841
2518
|
await response.text();
|
|
1842
2519
|
if (callback_event) {
|
|
1843
2520
|
const state = await agent_state({ assistant_id, thread_id });
|
|
1844
|
-
|
|
2521
|
+
import_core13.eventBus.publish(callback_event, {
|
|
1845
2522
|
success: true,
|
|
1846
2523
|
state,
|
|
1847
2524
|
config: { assistant_id, thread_id, tenant_id }
|
|
@@ -1868,7 +2545,7 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
|
1868
2545
|
return handleAgentTask(taskRequest, nextRetryCount);
|
|
1869
2546
|
}
|
|
1870
2547
|
if (callback_event) {
|
|
1871
|
-
|
|
2548
|
+
import_core13.eventBus.publish(callback_event, {
|
|
1872
2549
|
success: false,
|
|
1873
2550
|
error: error instanceof Error ? error.message : String(error),
|
|
1874
2551
|
config: { assistant_id, thread_id, tenant_id }
|
|
@@ -1906,7 +2583,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
|
|
|
1906
2583
|
* 初始化事件监听和队列轮询
|
|
1907
2584
|
*/
|
|
1908
2585
|
initialize() {
|
|
1909
|
-
|
|
2586
|
+
import_core13.eventBus.subscribe(import_core13.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
|
|
1910
2587
|
this.startPollingQueue();
|
|
1911
2588
|
console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
|
|
1912
2589
|
}
|
|
@@ -2025,7 +2702,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
|
|
|
2025
2702
|
handleAgentTask(taskRequest).catch((error) => {
|
|
2026
2703
|
console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
|
|
2027
2704
|
if (taskRequest.callback_event) {
|
|
2028
|
-
|
|
2705
|
+
import_core13.eventBus.publish(taskRequest.callback_event, {
|
|
2029
2706
|
success: false,
|
|
2030
2707
|
error: error instanceof Error ? error.message : String(error),
|
|
2031
2708
|
config: {
|
|
@@ -2045,7 +2722,7 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
|
|
|
2045
2722
|
var AgentTaskConsumer = _AgentTaskConsumer;
|
|
2046
2723
|
|
|
2047
2724
|
// src/index.ts
|
|
2048
|
-
var
|
|
2725
|
+
var import_core14 = require("@axiom-lattice/core");
|
|
2049
2726
|
var import_protocols2 = require("@axiom-lattice/protocols");
|
|
2050
2727
|
process.on("unhandledRejection", (reason, promise) => {
|
|
2051
2728
|
console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
|
|
@@ -2060,11 +2737,11 @@ var DEFAULT_LOGGER_CONFIG = {
|
|
|
2060
2737
|
var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
|
|
2061
2738
|
var logger = loggerLattice.client;
|
|
2062
2739
|
function initializeLogger(config) {
|
|
2063
|
-
if (
|
|
2064
|
-
|
|
2740
|
+
if (import_core14.loggerLatticeManager.hasLattice("default")) {
|
|
2741
|
+
import_core14.loggerLatticeManager.removeLattice("default");
|
|
2065
2742
|
}
|
|
2066
|
-
(0,
|
|
2067
|
-
return (0,
|
|
2743
|
+
(0, import_core14.registerLoggerLattice)("default", config);
|
|
2744
|
+
return (0, import_core14.getLoggerLattice)("default");
|
|
2068
2745
|
}
|
|
2069
2746
|
var app = (0, import_fastify.default)({
|
|
2070
2747
|
logger: false,
|
|
@@ -2116,6 +2793,7 @@ app.register(import_cors.default, {
|
|
|
2116
2793
|
credentials: true
|
|
2117
2794
|
});
|
|
2118
2795
|
app.register(import_sensible.default);
|
|
2796
|
+
app.register(import_websocket.default);
|
|
2119
2797
|
app.setErrorHandler((error, request, reply) => {
|
|
2120
2798
|
const getHeaderValue = (header) => {
|
|
2121
2799
|
if (Array.isArray(header)) {
|