@axiom-lattice/gateway 2.1.117 → 3.0.1
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 +12 -12
- package/CHANGELOG.md +38 -0
- package/dist/{a2a-ERG5RMUW.mjs → a2a-QMHEH3ZT.mjs} +77 -29
- package/dist/a2a-QMHEH3ZT.mjs.map +1 -0
- package/dist/index.js +1098 -181
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +967 -96
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
- package/src/__tests__/a2a.test.ts +82 -0
- package/src/__tests__/workspace.test.ts +13 -3
- package/src/config/local-a2a-templates.ts +59 -0
- package/src/controllers/__tests__/assistant-local-a2a.test.ts +147 -0
- package/src/controllers/__tests__/local-a2a-templates.test.ts +112 -0
- package/src/controllers/assistant.ts +126 -4
- package/src/controllers/eval.ts +6 -2
- package/src/controllers/local-a2a-templates.ts +18 -0
- package/src/controllers/local-a2a.ts +149 -0
- package/src/controllers/tasks.ts +2 -3
- package/src/controllers/workspace.ts +144 -17
- package/src/index.ts +1 -9
- package/src/routes/__tests__/a2a-test-connection.test.ts +177 -0
- package/src/routes/a2a-test-connection.ts +126 -0
- package/src/routes/a2a.ts +100 -28
- package/src/routes/index.ts +23 -0
- package/src/services/__tests__/eval-runner.test.ts +131 -0
- package/src/services/__tests__/local-a2a.test.ts +124 -0
- package/src/services/eval-runner.ts +50 -3
- package/src/services/local-a2a.ts +354 -0
- package/src/utils/__tests__/local-a2a-runtime.test.ts +77 -0
- package/src/utils/__tests__/path-containment.test.ts +35 -0
- package/src/utils/a2a-url.ts +20 -0
- package/src/utils/local-a2a-runtime.ts +107 -0
- package/src/utils/path-containment.ts +38 -0
- package/dist/a2a-ERG5RMUW.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -35,8 +35,8 @@ function getContentTypeFromFilename(filename) {
|
|
|
35
35
|
const ext = filename.includes(".") ? filename.slice(filename.lastIndexOf(".")).toLowerCase() : "";
|
|
36
36
|
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
37
37
|
}
|
|
38
|
-
function getFilenameFromPath(
|
|
39
|
-
const segments =
|
|
38
|
+
function getFilenameFromPath(path4) {
|
|
39
|
+
const segments = path4.replace(/\/+$/, "").split("/");
|
|
40
40
|
return segments[segments.length - 1] || "download";
|
|
41
41
|
}
|
|
42
42
|
var EXT_TO_MIME;
|
|
@@ -703,17 +703,17 @@ function generateWechatUin() {
|
|
|
703
703
|
buf.writeUInt32BE(Math.floor(Math.random() * 4294967295), 0);
|
|
704
704
|
return buf.toString("base64url");
|
|
705
705
|
}
|
|
706
|
-
async function apiGet(
|
|
707
|
-
const url = `${getBaseUrl()}${
|
|
706
|
+
async function apiGet(path4, extraHeaders) {
|
|
707
|
+
const url = `${getBaseUrl()}${path4}`;
|
|
708
708
|
const headers = { ...extraHeaders };
|
|
709
709
|
const res = await fetch(url, { headers });
|
|
710
710
|
if (!res.ok) {
|
|
711
|
-
throw new Error(`iLink GET ${
|
|
711
|
+
throw new Error(`iLink GET ${path4} failed: ${res.status} ${res.statusText}`);
|
|
712
712
|
}
|
|
713
713
|
return res.json();
|
|
714
714
|
}
|
|
715
|
-
async function apiPost(
|
|
716
|
-
const url = `${getBaseUrl()}${
|
|
715
|
+
async function apiPost(path4, body, botToken, signal) {
|
|
716
|
+
const url = `${getBaseUrl()}${path4}`;
|
|
717
717
|
const headers = {
|
|
718
718
|
"Content-Type": "application/json",
|
|
719
719
|
"AuthorizationType": "ilink_bot_token",
|
|
@@ -727,7 +727,7 @@ async function apiPost(path3, body, botToken, signal) {
|
|
|
727
727
|
signal
|
|
728
728
|
});
|
|
729
729
|
if (!res.ok) {
|
|
730
|
-
throw new Error(`iLink POST ${
|
|
730
|
+
throw new Error(`iLink POST ${path4} failed: ${res.status} ${res.statusText}`);
|
|
731
731
|
}
|
|
732
732
|
return res.json();
|
|
733
733
|
}
|
|
@@ -1031,7 +1031,7 @@ var init_WechatChannelAdapter = __esm({
|
|
|
1031
1031
|
installationId,
|
|
1032
1032
|
error: err instanceof Error ? err.message : String(err)
|
|
1033
1033
|
});
|
|
1034
|
-
await new Promise((
|
|
1034
|
+
await new Promise((resolve3) => setTimeout(resolve3, reconnectDelay));
|
|
1035
1035
|
reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT_DELAY_MS);
|
|
1036
1036
|
}
|
|
1037
1037
|
scheduleNextPoll();
|
|
@@ -1173,14 +1173,16 @@ function buildTextPart(text) {
|
|
|
1173
1173
|
function isoNow() {
|
|
1174
1174
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1175
1175
|
}
|
|
1176
|
-
async function streamChunksAsA2A(stream, taskId, sendEvent, onInterrupt) {
|
|
1176
|
+
async function streamChunksAsA2A(stream, taskId, contextId, sendEvent, onInterrupt) {
|
|
1177
1177
|
let accumulatedText = "";
|
|
1178
|
+
let interrupted = false;
|
|
1178
1179
|
for await (const chunk of stream) {
|
|
1179
1180
|
const chunkText = chunk.data?.content || "";
|
|
1180
1181
|
const chunkType = chunk.type;
|
|
1181
|
-
if (chunkType ===
|
|
1182
|
+
if (chunkType === import_protocols6.MessageChunkTypes.INTERRUPT) {
|
|
1182
1183
|
sendEvent("status-update", {
|
|
1183
1184
|
id: taskId,
|
|
1185
|
+
contextId,
|
|
1184
1186
|
status: {
|
|
1185
1187
|
state: "input-required",
|
|
1186
1188
|
message: {
|
|
@@ -1192,13 +1194,15 @@ async function streamChunksAsA2A(stream, taskId, sendEvent, onInterrupt) {
|
|
|
1192
1194
|
final: false
|
|
1193
1195
|
});
|
|
1194
1196
|
onInterrupt?.();
|
|
1195
|
-
|
|
1197
|
+
interrupted = true;
|
|
1198
|
+
break;
|
|
1196
1199
|
}
|
|
1197
|
-
if (chunkType ===
|
|
1200
|
+
if (chunkType === import_protocols6.MessageChunkTypes.AI || chunkType === import_protocols6.MessageChunkTypes.TOOL) {
|
|
1198
1201
|
if (chunkText) {
|
|
1199
1202
|
accumulatedText += chunkText;
|
|
1200
1203
|
sendEvent("status-update", {
|
|
1201
1204
|
id: taskId,
|
|
1205
|
+
contextId,
|
|
1202
1206
|
status: {
|
|
1203
1207
|
state: "working",
|
|
1204
1208
|
message: {
|
|
@@ -1212,7 +1216,7 @@ async function streamChunksAsA2A(stream, taskId, sendEvent, onInterrupt) {
|
|
|
1212
1216
|
}
|
|
1213
1217
|
}
|
|
1214
1218
|
}
|
|
1215
|
-
return accumulatedText;
|
|
1219
|
+
return { text: accumulatedText, interrupted };
|
|
1216
1220
|
}
|
|
1217
1221
|
async function getTaskStatus(taskId) {
|
|
1218
1222
|
const record = taskStore.get(taskId);
|
|
@@ -1266,13 +1270,48 @@ async function handleTasksSend(request, reply) {
|
|
|
1266
1270
|
});
|
|
1267
1271
|
return;
|
|
1268
1272
|
}
|
|
1273
|
+
const contextId = body.message.contextId;
|
|
1274
|
+
const referenceTaskIds = body.message.referenceTaskIds;
|
|
1269
1275
|
const taskId = body.id || (0, import_uuid10.v4)();
|
|
1270
|
-
|
|
1276
|
+
let threadId;
|
|
1277
|
+
let resolvedReferenceTaskIds;
|
|
1278
|
+
if (body.id) {
|
|
1279
|
+
const existingTask = taskStore.get(body.id);
|
|
1280
|
+
if (existingTask) {
|
|
1281
|
+
if (existingTask.status === "input-required") {
|
|
1282
|
+
threadId = existingTask.threadId;
|
|
1283
|
+
resolvedReferenceTaskIds = referenceTaskIds;
|
|
1284
|
+
} else if (existingTask.status === "completed" || existingTask.status === "failed" || existingTask.status === "canceled") {
|
|
1285
|
+
threadId = (0, import_uuid10.v4)();
|
|
1286
|
+
resolvedReferenceTaskIds = referenceTaskIds ? [...referenceTaskIds, body.id] : [body.id];
|
|
1287
|
+
} else {
|
|
1288
|
+
threadId = (0, import_uuid10.v4)();
|
|
1289
|
+
resolvedReferenceTaskIds = referenceTaskIds;
|
|
1290
|
+
}
|
|
1291
|
+
} else {
|
|
1292
|
+
threadId = (0, import_uuid10.v4)();
|
|
1293
|
+
resolvedReferenceTaskIds = referenceTaskIds ? [...referenceTaskIds, body.id] : [body.id];
|
|
1294
|
+
}
|
|
1295
|
+
} else if (contextId && contextThreadMap.has(contextId)) {
|
|
1296
|
+
threadId = contextThreadMap.get(contextId);
|
|
1297
|
+
console.warn({
|
|
1298
|
+
event: "a2a:deprecated:contextId_thread_reuse",
|
|
1299
|
+
message: "contextId-based thread reuse is deprecated; use referenceTaskIds and application-layer conversation state instead",
|
|
1300
|
+
contextId,
|
|
1301
|
+
threadId
|
|
1302
|
+
});
|
|
1303
|
+
resolvedReferenceTaskIds = referenceTaskIds;
|
|
1304
|
+
} else {
|
|
1305
|
+
threadId = (0, import_uuid10.v4)();
|
|
1306
|
+
resolvedReferenceTaskIds = referenceTaskIds;
|
|
1307
|
+
}
|
|
1271
1308
|
const tenantId = auth.tenantId || config.defaultTenantId;
|
|
1272
1309
|
const now = isoNow();
|
|
1273
1310
|
const record = {
|
|
1274
1311
|
id: taskId,
|
|
1275
1312
|
threadId,
|
|
1313
|
+
contextId,
|
|
1314
|
+
referenceTaskIds: resolvedReferenceTaskIds,
|
|
1276
1315
|
assistantId,
|
|
1277
1316
|
tenantId,
|
|
1278
1317
|
projectId: auth.projectId || void 0,
|
|
@@ -1290,7 +1329,7 @@ async function handleTasksSend(request, reply) {
|
|
|
1290
1329
|
taskStore.set(taskId, record);
|
|
1291
1330
|
let agent;
|
|
1292
1331
|
try {
|
|
1293
|
-
agent =
|
|
1332
|
+
agent = import_core56.agentInstanceManager.getAgent({
|
|
1294
1333
|
assistant_id: assistantId,
|
|
1295
1334
|
thread_id: threadId,
|
|
1296
1335
|
tenant_id: tenantId,
|
|
@@ -1326,26 +1365,29 @@ data: ${JSON.stringify(data)}
|
|
|
1326
1365
|
});
|
|
1327
1366
|
record.messageId = result.messageId;
|
|
1328
1367
|
const stream = agent.chunkStream(result.messageId, [
|
|
1329
|
-
|
|
1368
|
+
import_protocols6.MessageChunkTypes.MESSAGE_COMPLETED
|
|
1330
1369
|
]);
|
|
1331
|
-
const accumulatedText = await streamChunksAsA2A(stream, taskId, sendEvent, () => {
|
|
1370
|
+
const { text: accumulatedText, interrupted } = await streamChunksAsA2A(stream, taskId, contextId, sendEvent, () => {
|
|
1332
1371
|
record.status = "input-required";
|
|
1333
1372
|
record.updatedAt = isoNow();
|
|
1334
1373
|
});
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1374
|
+
if (!interrupted) {
|
|
1375
|
+
record.status = "completed";
|
|
1376
|
+
record.updatedAt = isoNow();
|
|
1377
|
+
record.history.push({
|
|
1378
|
+
role: "agent",
|
|
1379
|
+
parts: [buildTextPart(accumulatedText)]
|
|
1380
|
+
});
|
|
1381
|
+
sendEvent("status-update", {
|
|
1382
|
+
id: taskId,
|
|
1383
|
+
contextId,
|
|
1384
|
+
status: {
|
|
1385
|
+
state: "completed",
|
|
1386
|
+
timestamp: isoNow()
|
|
1387
|
+
},
|
|
1388
|
+
final: true
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1349
1391
|
} catch (err) {
|
|
1350
1392
|
record.status = "failed";
|
|
1351
1393
|
record.updatedAt = isoNow();
|
|
@@ -1355,6 +1397,7 @@ data: ${JSON.stringify(data)}
|
|
|
1355
1397
|
});
|
|
1356
1398
|
sendEvent("status-update", {
|
|
1357
1399
|
id: taskId,
|
|
1400
|
+
contextId,
|
|
1358
1401
|
status: {
|
|
1359
1402
|
state: "failed",
|
|
1360
1403
|
timestamp: isoNow()
|
|
@@ -1382,7 +1425,7 @@ async function handleTasksCancel(request, reply) {
|
|
|
1382
1425
|
return;
|
|
1383
1426
|
}
|
|
1384
1427
|
try {
|
|
1385
|
-
const agent =
|
|
1428
|
+
const agent = import_core56.agentInstanceManager.getAgent({
|
|
1386
1429
|
assistant_id: record.assistantId,
|
|
1387
1430
|
thread_id: record.threadId,
|
|
1388
1431
|
tenant_id: record.tenantId,
|
|
@@ -1419,7 +1462,7 @@ async function handleTasksStream(request, reply) {
|
|
|
1419
1462
|
}
|
|
1420
1463
|
let agent;
|
|
1421
1464
|
try {
|
|
1422
|
-
agent =
|
|
1465
|
+
agent = import_core56.agentInstanceManager.getAgent({
|
|
1423
1466
|
assistant_id: record.assistantId,
|
|
1424
1467
|
thread_id: record.threadId,
|
|
1425
1468
|
tenant_id: record.tenantId,
|
|
@@ -1448,6 +1491,7 @@ data: ${JSON.stringify(data)}
|
|
|
1448
1491
|
if (!record.messageId) {
|
|
1449
1492
|
sendEvent("status-update", {
|
|
1450
1493
|
id: taskId,
|
|
1494
|
+
contextId: record.contextId,
|
|
1451
1495
|
status: {
|
|
1452
1496
|
state: record.status,
|
|
1453
1497
|
timestamp: record.updatedAt
|
|
@@ -1459,17 +1503,20 @@ data: ${JSON.stringify(data)}
|
|
|
1459
1503
|
}
|
|
1460
1504
|
try {
|
|
1461
1505
|
const stream = agent.chunkStream(record.messageId, [
|
|
1462
|
-
|
|
1506
|
+
import_protocols6.MessageChunkTypes.MESSAGE_COMPLETED
|
|
1463
1507
|
]);
|
|
1464
|
-
await streamChunksAsA2A(stream, taskId, sendEvent);
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1508
|
+
const { interrupted } = await streamChunksAsA2A(stream, taskId, record.contextId, sendEvent);
|
|
1509
|
+
if (!interrupted) {
|
|
1510
|
+
sendEvent("status-update", {
|
|
1511
|
+
id: taskId,
|
|
1512
|
+
contextId: record.contextId,
|
|
1513
|
+
status: {
|
|
1514
|
+
state: record.status,
|
|
1515
|
+
timestamp: record.updatedAt
|
|
1516
|
+
},
|
|
1517
|
+
final: true
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1473
1520
|
} catch (err) {
|
|
1474
1521
|
sendEvent("error", {
|
|
1475
1522
|
code: "STREAM_ERROR",
|
|
@@ -1614,14 +1661,15 @@ function registerA2ARoutes(app2) {
|
|
|
1614
1661
|
handleApiKeyRotate
|
|
1615
1662
|
);
|
|
1616
1663
|
}
|
|
1617
|
-
var import_uuid10,
|
|
1664
|
+
var import_uuid10, import_core56, import_protocols6, taskStore, contextThreadMap, _a2aKeyStore, _storeKeyMap;
|
|
1618
1665
|
var init_a2a = __esm({
|
|
1619
1666
|
"src/routes/a2a.ts"() {
|
|
1620
1667
|
"use strict";
|
|
1621
1668
|
import_uuid10 = require("uuid");
|
|
1622
|
-
|
|
1623
|
-
|
|
1669
|
+
import_core56 = require("@axiom-lattice/core");
|
|
1670
|
+
import_protocols6 = require("@axiom-lattice/protocols");
|
|
1624
1671
|
taskStore = /* @__PURE__ */ new Map();
|
|
1672
|
+
contextThreadMap = /* @__PURE__ */ new Map();
|
|
1625
1673
|
_a2aKeyStore = null;
|
|
1626
1674
|
_storeKeyMap = /* @__PURE__ */ new Map();
|
|
1627
1675
|
}
|
|
@@ -1632,12 +1680,12 @@ var resources_exports = {};
|
|
|
1632
1680
|
__export(resources_exports, {
|
|
1633
1681
|
ResourceController: () => ResourceController
|
|
1634
1682
|
});
|
|
1635
|
-
var import_bcryptjs,
|
|
1683
|
+
var import_bcryptjs, import_core57, ResourceController;
|
|
1636
1684
|
var init_resources = __esm({
|
|
1637
1685
|
"src/controllers/resources.ts"() {
|
|
1638
1686
|
"use strict";
|
|
1639
1687
|
import_bcryptjs = __toESM(require("bcryptjs"));
|
|
1640
|
-
|
|
1688
|
+
import_core57 = require("@axiom-lattice/core");
|
|
1641
1689
|
init_mime();
|
|
1642
1690
|
ResourceController = class {
|
|
1643
1691
|
constructor(deps) {
|
|
@@ -1652,14 +1700,14 @@ var init_resources = __esm({
|
|
|
1652
1700
|
if (!workspaceId || !projectId) {
|
|
1653
1701
|
return reply.status(400).send({ error: "x-workspace-id and x-project-id headers required" });
|
|
1654
1702
|
}
|
|
1655
|
-
const payload = (0,
|
|
1703
|
+
const payload = (0, import_core57.createSharePayload)(
|
|
1656
1704
|
tenantId,
|
|
1657
1705
|
workspaceId,
|
|
1658
1706
|
projectId,
|
|
1659
1707
|
userId,
|
|
1660
1708
|
body
|
|
1661
1709
|
);
|
|
1662
|
-
const token = (0,
|
|
1710
|
+
const token = (0, import_core57.generateToken)();
|
|
1663
1711
|
try {
|
|
1664
1712
|
await this.deps.store.create({ ...payload, token });
|
|
1665
1713
|
this.deps.logger.info(
|
|
@@ -1811,7 +1859,7 @@ var init_resources = __esm({
|
|
|
1811
1859
|
resourcePath: subPath
|
|
1812
1860
|
}, subPath, ext, request, reply);
|
|
1813
1861
|
}
|
|
1814
|
-
const volume = (0,
|
|
1862
|
+
const volume = (0, import_core57.buildNamedVolumeName)("p", "project", tenantId, workspaceId, projectId);
|
|
1815
1863
|
return this._resolveAndServe(
|
|
1816
1864
|
volume,
|
|
1817
1865
|
subPath,
|
|
@@ -1862,8 +1910,8 @@ var init_resources = __esm({
|
|
|
1862
1910
|
return cookie.includes(`share_unlock_${token}=1`);
|
|
1863
1911
|
}
|
|
1864
1912
|
/** Returns true if the path has a file extension indicating it's a file, not a directory */
|
|
1865
|
-
_isFilePath(
|
|
1866
|
-
return /\.[a-zA-Z0-9]+$/.test(
|
|
1913
|
+
_isFilePath(path4) {
|
|
1914
|
+
return /\.[a-zA-Z0-9]+$/.test(path4);
|
|
1867
1915
|
}
|
|
1868
1916
|
/**
|
|
1869
1917
|
* Shared file resolution: directory → index.html, volume FS → sandbox, base tag, response.
|
|
@@ -1994,6 +2042,7 @@ __export(index_exports, {
|
|
|
1994
2042
|
LatticeGateway: () => LatticeGateway
|
|
1995
2043
|
});
|
|
1996
2044
|
module.exports = __toCommonJS(index_exports);
|
|
2045
|
+
var import_config2 = require("dotenv/config");
|
|
1997
2046
|
var import_fastify = __toESM(require("fastify"));
|
|
1998
2047
|
var import_cors = __toESM(require("@fastify/cors"));
|
|
1999
2048
|
var import_multipart = __toESM(require("@fastify/multipart"));
|
|
@@ -2005,8 +2054,375 @@ var import_url = require("url");
|
|
|
2005
2054
|
|
|
2006
2055
|
// src/controllers/assistant.ts
|
|
2007
2056
|
var import_core = require("@axiom-lattice/core");
|
|
2057
|
+
var import_protocols = require("@axiom-lattice/protocols");
|
|
2008
2058
|
var import_crypto = require("crypto");
|
|
2009
2059
|
var import_core2 = require("@axiom-lattice/core");
|
|
2060
|
+
|
|
2061
|
+
// src/services/local-a2a.ts
|
|
2062
|
+
var import_node_child_process = require("child_process");
|
|
2063
|
+
var import_node_fs = require("fs");
|
|
2064
|
+
var import_node_path = require("path");
|
|
2065
|
+
var import_promises = require("timers/promises");
|
|
2066
|
+
var STDERR_TAIL_LIMIT = 4096;
|
|
2067
|
+
function readBooleanEnv(name, defaultValue, env = process.env) {
|
|
2068
|
+
const value = env[name];
|
|
2069
|
+
if (value === void 0) return defaultValue;
|
|
2070
|
+
return value === "1" || value.toLowerCase() === "true";
|
|
2071
|
+
}
|
|
2072
|
+
function findWorkspaceRoot(startDir) {
|
|
2073
|
+
let current = (0, import_node_path.resolve)(startDir);
|
|
2074
|
+
const { root } = (0, import_node_path.parse)(current);
|
|
2075
|
+
while (current !== root) {
|
|
2076
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(current, "pnpm-workspace.yaml"))) {
|
|
2077
|
+
return current;
|
|
2078
|
+
}
|
|
2079
|
+
const parent = (0, import_node_path.dirname)(current);
|
|
2080
|
+
if (parent === current) return null;
|
|
2081
|
+
current = parent;
|
|
2082
|
+
}
|
|
2083
|
+
return null;
|
|
2084
|
+
}
|
|
2085
|
+
function resolveLocalA2AWorkingDirectory(options) {
|
|
2086
|
+
if (options.envWorkdir) return options.envWorkdir;
|
|
2087
|
+
if (options.commandCwd) return options.commandCwd;
|
|
2088
|
+
return findWorkspaceRoot(options.currentCwd) || options.currentCwd;
|
|
2089
|
+
}
|
|
2090
|
+
function validateWorkingDirectory(cwd) {
|
|
2091
|
+
try {
|
|
2092
|
+
const stat2 = (0, import_node_fs.statSync)(cwd);
|
|
2093
|
+
if (!stat2.isDirectory()) {
|
|
2094
|
+
return `Working directory is not a directory: ${cwd}`;
|
|
2095
|
+
}
|
|
2096
|
+
return null;
|
|
2097
|
+
} catch (error) {
|
|
2098
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2099
|
+
return `Working directory is not accessible: ${cwd} (${message})`;
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
function appendStderrTail(current, chunk) {
|
|
2103
|
+
const next = `${current}${chunk}`;
|
|
2104
|
+
if (next.length <= STDERR_TAIL_LIMIT) return next;
|
|
2105
|
+
return next.slice(-STDERR_TAIL_LIMIT);
|
|
2106
|
+
}
|
|
2107
|
+
function formatExitMessage(exitReason, stderrTail) {
|
|
2108
|
+
const stderr = stderrTail.trim();
|
|
2109
|
+
return stderr ? `Exited before becoming ready (${exitReason}): ${stderr}` : `Exited before becoming ready (${exitReason})`;
|
|
2110
|
+
}
|
|
2111
|
+
async function probeReady(agentCardUrl, healthUrl, timeoutMs) {
|
|
2112
|
+
const controller = new AbortController();
|
|
2113
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2114
|
+
try {
|
|
2115
|
+
if (healthUrl) {
|
|
2116
|
+
const resp = await fetch(healthUrl, { signal: controller.signal });
|
|
2117
|
+
if (!resp.ok) return false;
|
|
2118
|
+
}
|
|
2119
|
+
const cardResp = await fetch(agentCardUrl, { signal: controller.signal });
|
|
2120
|
+
return cardResp.ok;
|
|
2121
|
+
} catch {
|
|
2122
|
+
return false;
|
|
2123
|
+
} finally {
|
|
2124
|
+
clearTimeout(timer);
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
var _LocalA2AService = class _LocalA2AService {
|
|
2128
|
+
constructor() {
|
|
2129
|
+
this.states = /* @__PURE__ */ new Map();
|
|
2130
|
+
this.autoStartEnabled = readBooleanEnv("LOCAL_A2A_AUTO_START", true);
|
|
2131
|
+
}
|
|
2132
|
+
static getInstance() {
|
|
2133
|
+
if (!_LocalA2AService.instance) {
|
|
2134
|
+
_LocalA2AService.instance = new _LocalA2AService();
|
|
2135
|
+
}
|
|
2136
|
+
return _LocalA2AService.instance;
|
|
2137
|
+
}
|
|
2138
|
+
getOrCreateState(runtimeId, localRuntime) {
|
|
2139
|
+
let state = this.states.get(runtimeId);
|
|
2140
|
+
if (!state) {
|
|
2141
|
+
state = {
|
|
2142
|
+
runtimeId,
|
|
2143
|
+
label: localRuntime.label || runtimeId,
|
|
2144
|
+
status: this.autoStartEnabled ? "stopped" : "disabled",
|
|
2145
|
+
enabled: this.autoStartEnabled,
|
|
2146
|
+
assistantId: runtimeId,
|
|
2147
|
+
agentCardUrl: localRuntime.agentCardUrl,
|
|
2148
|
+
healthUrl: localRuntime.healthUrl,
|
|
2149
|
+
localRuntime
|
|
2150
|
+
};
|
|
2151
|
+
this.states.set(runtimeId, state);
|
|
2152
|
+
} else {
|
|
2153
|
+
state.localRuntime = localRuntime;
|
|
2154
|
+
state.label = localRuntime.label || state.label;
|
|
2155
|
+
state.agentCardUrl = localRuntime.agentCardUrl;
|
|
2156
|
+
state.healthUrl = localRuntime.healthUrl;
|
|
2157
|
+
}
|
|
2158
|
+
return state;
|
|
2159
|
+
}
|
|
2160
|
+
async getRegisteredState(runtimeId, localRuntime) {
|
|
2161
|
+
const state = this.getOrCreateState(runtimeId, localRuntime);
|
|
2162
|
+
if (state.process && state.status === "running") {
|
|
2163
|
+
const alive = await probeReady(
|
|
2164
|
+
localRuntime.agentCardUrl,
|
|
2165
|
+
localRuntime.healthUrl,
|
|
2166
|
+
2e3
|
|
2167
|
+
);
|
|
2168
|
+
if (!alive) {
|
|
2169
|
+
state.process = void 0;
|
|
2170
|
+
state.pid = void 0;
|
|
2171
|
+
state.status = "stopped";
|
|
2172
|
+
state.message = "Process exited unexpectedly";
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
return this.snapshotState(state);
|
|
2176
|
+
}
|
|
2177
|
+
async startProvider(runtimeId, localRuntime) {
|
|
2178
|
+
const state = this.getOrCreateState(runtimeId, localRuntime);
|
|
2179
|
+
if (!state.enabled) {
|
|
2180
|
+
state.status = "disabled";
|
|
2181
|
+
state.message = "Disabled by configuration";
|
|
2182
|
+
return this.snapshotState(state);
|
|
2183
|
+
}
|
|
2184
|
+
if (state.process && state.status === "running") {
|
|
2185
|
+
return this.snapshotState(state);
|
|
2186
|
+
}
|
|
2187
|
+
state.enabled = true;
|
|
2188
|
+
const { executable, args, cwd, env: cmdEnv } = localRuntime.command;
|
|
2189
|
+
const resolvedCwd = resolveLocalA2AWorkingDirectory({
|
|
2190
|
+
envWorkdir: process.env.LOCAL_A2A_WORKDIR || void 0,
|
|
2191
|
+
commandCwd: cwd,
|
|
2192
|
+
currentCwd: process.cwd()
|
|
2193
|
+
});
|
|
2194
|
+
const cwdError = validateWorkingDirectory(resolvedCwd);
|
|
2195
|
+
if (cwdError) {
|
|
2196
|
+
state.process = void 0;
|
|
2197
|
+
state.pid = void 0;
|
|
2198
|
+
state.status = "failed";
|
|
2199
|
+
state.message = cwdError;
|
|
2200
|
+
return this.snapshotState(state);
|
|
2201
|
+
}
|
|
2202
|
+
state.status = "starting";
|
|
2203
|
+
state.message = "Starting";
|
|
2204
|
+
let stderrTail = "";
|
|
2205
|
+
const childEnv = cmdEnv ? { ...process.env, ...cmdEnv } : process.env;
|
|
2206
|
+
const child = (0, import_node_child_process.spawn)(executable, args, {
|
|
2207
|
+
cwd: resolvedCwd,
|
|
2208
|
+
env: childEnv,
|
|
2209
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2210
|
+
shell: false
|
|
2211
|
+
});
|
|
2212
|
+
state.process = child;
|
|
2213
|
+
state.pid = child.pid ?? void 0;
|
|
2214
|
+
child.once("error", (error) => {
|
|
2215
|
+
const current = this.states.get(runtimeId);
|
|
2216
|
+
if (!current) return;
|
|
2217
|
+
current.process = void 0;
|
|
2218
|
+
current.pid = void 0;
|
|
2219
|
+
current.status = "failed";
|
|
2220
|
+
const stderr = stderrTail.trim();
|
|
2221
|
+
current.message = stderr ? `Failed to start: ${error.message}: ${stderr}` : `Failed to start: ${error.message}`;
|
|
2222
|
+
});
|
|
2223
|
+
child.stdout.on("data", (chunk) => {
|
|
2224
|
+
const text = chunk.toString("utf8").trim();
|
|
2225
|
+
if (text) console.log(`[local-a2a:${runtimeId}] ${text}`);
|
|
2226
|
+
});
|
|
2227
|
+
child.stderr.on("data", (chunk) => {
|
|
2228
|
+
const rawText = chunk.toString("utf8");
|
|
2229
|
+
stderrTail = appendStderrTail(stderrTail, rawText);
|
|
2230
|
+
const text = rawText.trim();
|
|
2231
|
+
if (text) console.error(`[local-a2a:${runtimeId}] ${text}`);
|
|
2232
|
+
});
|
|
2233
|
+
child.on("close", (code, signal) => {
|
|
2234
|
+
const current = this.states.get(runtimeId);
|
|
2235
|
+
if (!current) return;
|
|
2236
|
+
current.process = void 0;
|
|
2237
|
+
current.pid = void 0;
|
|
2238
|
+
const exitReason = signal ?? code ?? "unknown";
|
|
2239
|
+
if (current.status === "running") {
|
|
2240
|
+
current.status = "stopped";
|
|
2241
|
+
current.message = `Stopped (${exitReason})`;
|
|
2242
|
+
} else if (current.status === "starting") {
|
|
2243
|
+
current.status = "failed";
|
|
2244
|
+
current.message = formatExitMessage(exitReason, stderrTail);
|
|
2245
|
+
}
|
|
2246
|
+
});
|
|
2247
|
+
const ready = await this.waitUntilReady(localRuntime, state, 15e3);
|
|
2248
|
+
if (!ready) {
|
|
2249
|
+
if (state.process) {
|
|
2250
|
+
state.process.kill("SIGTERM");
|
|
2251
|
+
}
|
|
2252
|
+
state.process = void 0;
|
|
2253
|
+
state.pid = void 0;
|
|
2254
|
+
if (state.status !== "failed") {
|
|
2255
|
+
state.status = "failed";
|
|
2256
|
+
state.message = "Server did not become ready";
|
|
2257
|
+
}
|
|
2258
|
+
return this.snapshotState(state);
|
|
2259
|
+
}
|
|
2260
|
+
state.status = "running";
|
|
2261
|
+
state.message = "Running";
|
|
2262
|
+
state.lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2263
|
+
return this.snapshotState(state);
|
|
2264
|
+
}
|
|
2265
|
+
async stopProvider(runtimeId) {
|
|
2266
|
+
const state = this.states.get(runtimeId);
|
|
2267
|
+
if (!state) {
|
|
2268
|
+
return this.emptyState(runtimeId);
|
|
2269
|
+
}
|
|
2270
|
+
const child = state.process;
|
|
2271
|
+
if (child) {
|
|
2272
|
+
child.kill("SIGTERM");
|
|
2273
|
+
await (0, import_promises.setTimeout)(750);
|
|
2274
|
+
if (child.exitCode === null) {
|
|
2275
|
+
child.kill("SIGKILL");
|
|
2276
|
+
}
|
|
2277
|
+
state.process = void 0;
|
|
2278
|
+
}
|
|
2279
|
+
state.pid = void 0;
|
|
2280
|
+
state.status = "stopped";
|
|
2281
|
+
state.message = "Stopped";
|
|
2282
|
+
state.lastStoppedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2283
|
+
return this.snapshotState(state);
|
|
2284
|
+
}
|
|
2285
|
+
async restartProvider(runtimeId, localRuntime) {
|
|
2286
|
+
await this.stopProvider(runtimeId);
|
|
2287
|
+
return this.startProvider(runtimeId, localRuntime);
|
|
2288
|
+
}
|
|
2289
|
+
removeState(runtimeId) {
|
|
2290
|
+
const state = this.states.get(runtimeId);
|
|
2291
|
+
if (state?.process) {
|
|
2292
|
+
state.process.kill("SIGTERM");
|
|
2293
|
+
state.process = void 0;
|
|
2294
|
+
}
|
|
2295
|
+
this.states.delete(runtimeId);
|
|
2296
|
+
}
|
|
2297
|
+
async waitUntilReady(localRuntime, state, timeoutMs) {
|
|
2298
|
+
const start2 = Date.now();
|
|
2299
|
+
while (Date.now() - start2 < timeoutMs) {
|
|
2300
|
+
if (state.status === "failed") return false;
|
|
2301
|
+
if (await probeReady(localRuntime.agentCardUrl, localRuntime.healthUrl, 1500)) {
|
|
2302
|
+
return true;
|
|
2303
|
+
}
|
|
2304
|
+
await (0, import_promises.setTimeout)(500);
|
|
2305
|
+
}
|
|
2306
|
+
return false;
|
|
2307
|
+
}
|
|
2308
|
+
emptyState(runtimeId) {
|
|
2309
|
+
return {
|
|
2310
|
+
runtimeId,
|
|
2311
|
+
label: runtimeId,
|
|
2312
|
+
status: "stopped",
|
|
2313
|
+
enabled: false
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2316
|
+
snapshotState(state) {
|
|
2317
|
+
return {
|
|
2318
|
+
runtimeId: state.runtimeId,
|
|
2319
|
+
label: state.label,
|
|
2320
|
+
status: state.status,
|
|
2321
|
+
enabled: state.enabled,
|
|
2322
|
+
assistantId: state.assistantId,
|
|
2323
|
+
agentCardUrl: state.agentCardUrl,
|
|
2324
|
+
healthUrl: state.healthUrl,
|
|
2325
|
+
pid: state.pid,
|
|
2326
|
+
message: state.message,
|
|
2327
|
+
lastStartedAt: state.lastStartedAt,
|
|
2328
|
+
lastStoppedAt: state.lastStoppedAt
|
|
2329
|
+
};
|
|
2330
|
+
}
|
|
2331
|
+
};
|
|
2332
|
+
_LocalA2AService.instance = null;
|
|
2333
|
+
var LocalA2AService = _LocalA2AService;
|
|
2334
|
+
var localA2AService = LocalA2AService.getInstance();
|
|
2335
|
+
|
|
2336
|
+
// src/utils/a2a-url.ts
|
|
2337
|
+
var AGENT_CARD_PATH = "/.well-known/agent-card.json";
|
|
2338
|
+
function normalizeA2AAgentCardUrl(value, defaultProtocol = "https://") {
|
|
2339
|
+
const raw = value?.trim() ?? "";
|
|
2340
|
+
if (!raw) return "";
|
|
2341
|
+
const withProtocol = /^https?:\/\//i.test(raw) ? raw : `${defaultProtocol}${raw.replace(/^\/+/, "")}`;
|
|
2342
|
+
const trimmed = withProtocol.replace(/\/+$/, "");
|
|
2343
|
+
if (trimmed.endsWith(AGENT_CARD_PATH)) {
|
|
2344
|
+
return trimmed;
|
|
2345
|
+
}
|
|
2346
|
+
return `${trimmed}${AGENT_CARD_PATH}`;
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
// src/utils/local-a2a-runtime.ts
|
|
2350
|
+
function validateLocalRuntimeCommand(localRuntime) {
|
|
2351
|
+
const runtime = localRuntime;
|
|
2352
|
+
const executable = runtime.command?.executable;
|
|
2353
|
+
if (typeof executable !== "string" || executable.trim().length === 0) {
|
|
2354
|
+
return {
|
|
2355
|
+
ok: false,
|
|
2356
|
+
error: "Local managed A2A command executable is required"
|
|
2357
|
+
};
|
|
2358
|
+
}
|
|
2359
|
+
const args = runtime.command?.args;
|
|
2360
|
+
if (!Array.isArray(args) || !args.every((arg) => typeof arg === "string")) {
|
|
2361
|
+
return {
|
|
2362
|
+
ok: false,
|
|
2363
|
+
error: "Local managed A2A command args must be an array of strings"
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
return { ok: true };
|
|
2367
|
+
}
|
|
2368
|
+
function getAgentCardPort(agentCardUrl) {
|
|
2369
|
+
let url;
|
|
2370
|
+
try {
|
|
2371
|
+
url = new URL(agentCardUrl);
|
|
2372
|
+
} catch {
|
|
2373
|
+
return null;
|
|
2374
|
+
}
|
|
2375
|
+
if (url.port) {
|
|
2376
|
+
const port = Number(url.port);
|
|
2377
|
+
return Number.isInteger(port) ? port : null;
|
|
2378
|
+
}
|
|
2379
|
+
if (url.protocol === "http:") return 80;
|
|
2380
|
+
if (url.protocol === "https:") return 443;
|
|
2381
|
+
return null;
|
|
2382
|
+
}
|
|
2383
|
+
function parseCommandPort(args) {
|
|
2384
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
2385
|
+
const arg = args[index];
|
|
2386
|
+
const match = /^(--port|-p)(?:[=\s]+(\d+))?$/.exec(arg);
|
|
2387
|
+
if (!match) continue;
|
|
2388
|
+
const inlinePort = match[2];
|
|
2389
|
+
if (inlinePort) return Number(inlinePort);
|
|
2390
|
+
const nextArg = args[index + 1];
|
|
2391
|
+
if (nextArg && /^\d+$/.test(nextArg)) {
|
|
2392
|
+
return Number(nextArg);
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
return null;
|
|
2396
|
+
}
|
|
2397
|
+
function isLoopbackHost(hostname) {
|
|
2398
|
+
const normalized = hostname.toLowerCase();
|
|
2399
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1" || normalized === "[::1]";
|
|
2400
|
+
}
|
|
2401
|
+
function validateLocalRuntimePort(localRuntime, agentCardUrl) {
|
|
2402
|
+
let url;
|
|
2403
|
+
try {
|
|
2404
|
+
url = new URL(agentCardUrl);
|
|
2405
|
+
} catch {
|
|
2406
|
+
return { ok: true };
|
|
2407
|
+
}
|
|
2408
|
+
if (!isLoopbackHost(url.hostname) || !url.port) {
|
|
2409
|
+
return { ok: true };
|
|
2410
|
+
}
|
|
2411
|
+
const commandPort = parseCommandPort(localRuntime.command.args);
|
|
2412
|
+
if (commandPort === null) {
|
|
2413
|
+
return { ok: true };
|
|
2414
|
+
}
|
|
2415
|
+
const agentCardPort = Number(url.port);
|
|
2416
|
+
if (commandPort === agentCardPort) {
|
|
2417
|
+
return { ok: true };
|
|
2418
|
+
}
|
|
2419
|
+
return {
|
|
2420
|
+
ok: false,
|
|
2421
|
+
error: `Local managed A2A command port (${commandPort}) does not match agentCardUrl port (${agentCardPort}). Update the command args or Agent Card URL so they use the same port.`
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
// src/controllers/assistant.ts
|
|
2010
2426
|
function getTenantId(request) {
|
|
2011
2427
|
const userTenantId = request.user?.tenantId;
|
|
2012
2428
|
if (userTenantId) {
|
|
@@ -2136,6 +2552,79 @@ async function createAssistant(request, reply) {
|
|
|
2136
2552
|
});
|
|
2137
2553
|
}
|
|
2138
2554
|
const id = data.id ?? (0, import_crypto.randomUUID)();
|
|
2555
|
+
if (data.graphDefinition && data.graphDefinition.type === import_protocols.AgentType.A2A_REMOTE) {
|
|
2556
|
+
const a2aConfig = data.graphDefinition;
|
|
2557
|
+
const warnings = [];
|
|
2558
|
+
const isLocalManaged = !!a2aConfig.localRuntime;
|
|
2559
|
+
a2aConfig.agentCardUrl = normalizeA2AAgentCardUrl(
|
|
2560
|
+
a2aConfig.agentCardUrl,
|
|
2561
|
+
isLocalManaged ? "http://" : "https://"
|
|
2562
|
+
);
|
|
2563
|
+
if (a2aConfig.localRuntime) {
|
|
2564
|
+
const commandValidation = validateLocalRuntimeCommand(
|
|
2565
|
+
a2aConfig.localRuntime
|
|
2566
|
+
);
|
|
2567
|
+
if (!commandValidation.ok) {
|
|
2568
|
+
return reply.status(400).send({
|
|
2569
|
+
success: false,
|
|
2570
|
+
message: commandValidation.error
|
|
2571
|
+
});
|
|
2572
|
+
}
|
|
2573
|
+
a2aConfig.localRuntime.command.executable = a2aConfig.localRuntime.command.executable.trim();
|
|
2574
|
+
a2aConfig.localRuntime.agentCardUrl = normalizeA2AAgentCardUrl(
|
|
2575
|
+
a2aConfig.localRuntime.agentCardUrl || a2aConfig.agentCardUrl,
|
|
2576
|
+
"http://"
|
|
2577
|
+
);
|
|
2578
|
+
a2aConfig.agentCardUrl = a2aConfig.localRuntime.agentCardUrl;
|
|
2579
|
+
const portValidation = validateLocalRuntimePort(
|
|
2580
|
+
a2aConfig.localRuntime,
|
|
2581
|
+
a2aConfig.agentCardUrl
|
|
2582
|
+
);
|
|
2583
|
+
if (!portValidation.ok) {
|
|
2584
|
+
return reply.status(400).send({
|
|
2585
|
+
success: false,
|
|
2586
|
+
message: portValidation.error
|
|
2587
|
+
});
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
if (a2aConfig.localRuntime) {
|
|
2591
|
+
const existingAssistants = await (0, import_core.getStoreLattice)("default", "assistant").store.getAllAssistants(tenantId);
|
|
2592
|
+
const targetPort = getAgentCardPort(a2aConfig.localRuntime.agentCardUrl);
|
|
2593
|
+
const duplicate = existingAssistants.find((a) => {
|
|
2594
|
+
if (a.id === id) return false;
|
|
2595
|
+
const gd = a.graphDefinition && typeof a.graphDefinition === "object" ? a.graphDefinition : void 0;
|
|
2596
|
+
if (!gd || gd.type !== import_protocols.AgentType.A2A_REMOTE) return false;
|
|
2597
|
+
const lr = gd.localRuntime;
|
|
2598
|
+
if (!lr) return false;
|
|
2599
|
+
const existingAgentCardUrl = normalizeA2AAgentCardUrl(lr.agentCardUrl, "http://");
|
|
2600
|
+
const existingPort = getAgentCardPort(existingAgentCardUrl);
|
|
2601
|
+
if (targetPort !== null && existingPort !== null) {
|
|
2602
|
+
return existingPort === targetPort;
|
|
2603
|
+
}
|
|
2604
|
+
return existingAgentCardUrl === a2aConfig.localRuntime.agentCardUrl;
|
|
2605
|
+
});
|
|
2606
|
+
if (duplicate) {
|
|
2607
|
+
const conflictDetail = targetPort === null ? `agentCardUrl "${a2aConfig.localRuntime.agentCardUrl}"` : `port ${targetPort}`;
|
|
2608
|
+
return reply.status(409).send({
|
|
2609
|
+
success: false,
|
|
2610
|
+
message: `A local managed A2A assistant using ${conflictDetail} already exists: "${duplicate.name}". Each local managed A2A assistant needs a unique port.`
|
|
2611
|
+
});
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
try {
|
|
2615
|
+
const resp = await fetch(a2aConfig.agentCardUrl, {
|
|
2616
|
+
signal: AbortSignal.timeout(5e3)
|
|
2617
|
+
});
|
|
2618
|
+
if (!resp.ok) {
|
|
2619
|
+
warnings.push(`agentCardUrl returned HTTP ${resp.status}`);
|
|
2620
|
+
}
|
|
2621
|
+
} catch {
|
|
2622
|
+
warnings.push(`agentCardUrl is not reachable: ${a2aConfig.agentCardUrl}`);
|
|
2623
|
+
}
|
|
2624
|
+
if (warnings.length > 0) {
|
|
2625
|
+
console.warn(`[createAssistant] A2A warnings for ${a2aConfig.agentCardUrl}:`, warnings);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2139
2628
|
return upsertAssistant(tenantId, id, data, reply, true);
|
|
2140
2629
|
}
|
|
2141
2630
|
async function updateAssistant(request, reply) {
|
|
@@ -2149,11 +2638,28 @@ async function deleteAssistant(request, reply) {
|
|
|
2149
2638
|
const { id } = request.params;
|
|
2150
2639
|
const storeLattice = (0, import_core.getStoreLattice)("default", "assistant");
|
|
2151
2640
|
const assistantStore = storeLattice.store;
|
|
2641
|
+
const storedAssistant = await assistantStore.getAssistantById(tenantId, id);
|
|
2642
|
+
const graphDefinition = storedAssistant?.graphDefinition;
|
|
2643
|
+
const hasLocalRuntime = graphDefinition && typeof graphDefinition === "object" ? !!graphDefinition.localRuntime : false;
|
|
2644
|
+
if (storedAssistant && hasLocalRuntime) {
|
|
2645
|
+
localA2AService.removeState(id);
|
|
2646
|
+
const deleted2 = await assistantStore.deleteAssistant(tenantId, id);
|
|
2647
|
+
if (!deleted2) {
|
|
2648
|
+
return reply.status(500).send({
|
|
2649
|
+
success: false,
|
|
2650
|
+
message: "Failed to delete assistant"
|
|
2651
|
+
});
|
|
2652
|
+
}
|
|
2653
|
+
import_core2.eventBus.publish("assistant:deleted", { id, tenantId });
|
|
2654
|
+
return {
|
|
2655
|
+
success: true,
|
|
2656
|
+
message: "Deleted local A2A assistant"
|
|
2657
|
+
};
|
|
2658
|
+
}
|
|
2152
2659
|
const agentConfig = await import_core2.agentLatticeManager.getAgentConfigWithTenant(tenantId, id);
|
|
2153
2660
|
const isCodeConfigured = !!agentConfig;
|
|
2154
2661
|
if (isCodeConfigured) {
|
|
2155
|
-
|
|
2156
|
-
if (!exists2) {
|
|
2662
|
+
if (!storedAssistant) {
|
|
2157
2663
|
return reply.status(404).send({
|
|
2158
2664
|
success: false,
|
|
2159
2665
|
message: "Assistant not found (code-configured assistants cannot be deleted from code, only from store)"
|
|
@@ -2166,8 +2672,7 @@ async function deleteAssistant(request, reply) {
|
|
|
2166
2672
|
message: "Deleted assistant from store (code-configured registration remains)"
|
|
2167
2673
|
};
|
|
2168
2674
|
}
|
|
2169
|
-
|
|
2170
|
-
if (!exists) {
|
|
2675
|
+
if (!storedAssistant) {
|
|
2171
2676
|
return reply.status(404).send({
|
|
2172
2677
|
success: false,
|
|
2173
2678
|
message: "Assistant not found"
|
|
@@ -2221,7 +2726,7 @@ var getAgentGraph = async (request, reply) => {
|
|
|
2221
2726
|
// src/controllers/run.ts
|
|
2222
2727
|
var import_uuid = require("uuid");
|
|
2223
2728
|
var import_core3 = require("@axiom-lattice/core");
|
|
2224
|
-
var
|
|
2729
|
+
var import_protocols2 = require("@axiom-lattice/protocols");
|
|
2225
2730
|
function getUserId2(request) {
|
|
2226
2731
|
const authUser = request.user;
|
|
2227
2732
|
if (authUser?.id) return authUser.id;
|
|
@@ -2293,13 +2798,13 @@ var createRun = async (request, reply) => {
|
|
|
2293
2798
|
command,
|
|
2294
2799
|
custom_run_config: mergedConfig
|
|
2295
2800
|
}, mode);
|
|
2296
|
-
const stream = agent.chunkStream(result.messageId, [
|
|
2801
|
+
const stream = agent.chunkStream(result.messageId, [import_protocols2.MessageChunkTypes.MESSAGE_COMPLETED, import_protocols2.MessageChunkTypes.INTERRUPT, import_protocols2.MessageChunkTypes.MESSAGE_FAILED]);
|
|
2297
2802
|
for await (const chunk of stream) {
|
|
2298
2803
|
const success = reply.raw.write(`data: ${JSON.stringify(chunk)}
|
|
2299
2804
|
|
|
2300
2805
|
`);
|
|
2301
2806
|
if (!success) {
|
|
2302
|
-
await new Promise((
|
|
2807
|
+
await new Promise((resolve3) => reply.raw.once("drain", resolve3));
|
|
2303
2808
|
}
|
|
2304
2809
|
}
|
|
2305
2810
|
} catch (error) {
|
|
@@ -3077,7 +3582,7 @@ var configService = new ConfigService();
|
|
|
3077
3582
|
|
|
3078
3583
|
// src/services/queue_service.ts
|
|
3079
3584
|
var import_core8 = require("@axiom-lattice/core");
|
|
3080
|
-
var
|
|
3585
|
+
var import_protocols3 = require("@axiom-lattice/protocols");
|
|
3081
3586
|
var import_queue_redis = require("@axiom-lattice/queue-redis");
|
|
3082
3587
|
var DEFAULT_QUEUE_KEY = "default";
|
|
3083
3588
|
var queueServiceType = process.env.QUEUE_SERVICE_TYPE || "memory";
|
|
@@ -3088,7 +3593,7 @@ var setQueueServiceType = (type) => {
|
|
|
3088
3593
|
const config = {
|
|
3089
3594
|
name: "Default Queue Service",
|
|
3090
3595
|
description: `Default ${type} queue service`,
|
|
3091
|
-
type: type === "redis" ?
|
|
3596
|
+
type: type === "redis" ? import_protocols3.QueueType.REDIS : import_protocols3.QueueType.MEMORY,
|
|
3092
3597
|
queueName,
|
|
3093
3598
|
options: type === "redis" ? {
|
|
3094
3599
|
redisUrl: process.env.REDIS_URL,
|
|
@@ -4216,7 +4721,7 @@ async function executeSqlQuery(client, body, reply) {
|
|
|
4216
4721
|
|
|
4217
4722
|
// src/controllers/workflow-tracking.ts
|
|
4218
4723
|
var import_core15 = require("@axiom-lattice/core");
|
|
4219
|
-
var
|
|
4724
|
+
var import_protocols4 = require("@axiom-lattice/protocols");
|
|
4220
4725
|
function getTenantId7(request) {
|
|
4221
4726
|
const userTenantId = request.user?.tenantId;
|
|
4222
4727
|
if (userTenantId) return userTenantId;
|
|
@@ -4660,7 +5165,7 @@ async function replyInboxTask(request, reply) {
|
|
|
4660
5165
|
}).then((result) => {
|
|
4661
5166
|
const stream = agent.chunkStream(
|
|
4662
5167
|
result.messageId,
|
|
4663
|
-
[
|
|
5168
|
+
[import_protocols4.MessageChunkTypes.MESSAGE_COMPLETED]
|
|
4664
5169
|
);
|
|
4665
5170
|
(async () => {
|
|
4666
5171
|
for await (const _ of stream) {
|
|
@@ -4877,15 +5382,14 @@ function getStore() {
|
|
|
4877
5382
|
async function listTasks(request, reply) {
|
|
4878
5383
|
try {
|
|
4879
5384
|
const tenantId = getTenantId9(request);
|
|
4880
|
-
const userId = getUserId4(request);
|
|
4881
5385
|
const query = request.query;
|
|
4882
5386
|
const store2 = getStore();
|
|
4883
5387
|
const tasks = await store2.list({
|
|
4884
5388
|
tenantId,
|
|
4885
|
-
ownerId: query.ownerId || userId,
|
|
4886
5389
|
status: query.status,
|
|
4887
5390
|
priority: query.priority,
|
|
4888
|
-
|
|
5391
|
+
...query.ownerId && { ownerId: query.ownerId },
|
|
5392
|
+
...query.ownerType && { ownerType: query.ownerType },
|
|
4889
5393
|
metadata: query.metadata ? JSON.parse(query.metadata) : void 0,
|
|
4890
5394
|
projectId: query.projectId,
|
|
4891
5395
|
limit: query.limit ? parseInt(query.limit) : void 0,
|
|
@@ -6021,13 +6525,42 @@ function registerSandboxProxyRoutes(app2) {
|
|
|
6021
6525
|
}
|
|
6022
6526
|
|
|
6023
6527
|
// src/controllers/workspace.ts
|
|
6024
|
-
var
|
|
6025
|
-
var
|
|
6528
|
+
var fs2 = __toESM(require("fs/promises"));
|
|
6529
|
+
var path2 = __toESM(require("path"));
|
|
6530
|
+
var os = __toESM(require("os"));
|
|
6026
6531
|
var import_core24 = require("@axiom-lattice/core");
|
|
6027
6532
|
var import_core25 = require("@axiom-lattice/core");
|
|
6028
6533
|
var import_core26 = require("@axiom-lattice/core");
|
|
6029
6534
|
var import_uuid3 = require("uuid");
|
|
6030
6535
|
init_mime();
|
|
6536
|
+
|
|
6537
|
+
// src/utils/path-containment.ts
|
|
6538
|
+
var fs = __toESM(require("fs/promises"));
|
|
6539
|
+
var path = __toESM(require("path"));
|
|
6540
|
+
var PathOutsideRootError = class extends Error {
|
|
6541
|
+
constructor(rootPath, targetPath) {
|
|
6542
|
+
super(`Path is outside the allowed root: ${targetPath}`);
|
|
6543
|
+
this.rootPath = rootPath;
|
|
6544
|
+
this.targetPath = targetPath;
|
|
6545
|
+
this.name = "PathOutsideRootError";
|
|
6546
|
+
}
|
|
6547
|
+
};
|
|
6548
|
+
function isPathWithinRoot(rootPath, targetPath) {
|
|
6549
|
+
const relative2 = path.relative(rootPath, targetPath);
|
|
6550
|
+
return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${path.sep}`) && !path.isAbsolute(relative2);
|
|
6551
|
+
}
|
|
6552
|
+
async function resolvePathWithinRoot(rootPath, targetPath) {
|
|
6553
|
+
const [resolvedRoot, resolvedTarget] = await Promise.all([
|
|
6554
|
+
fs.realpath(rootPath),
|
|
6555
|
+
fs.realpath(targetPath)
|
|
6556
|
+
]);
|
|
6557
|
+
if (!isPathWithinRoot(resolvedRoot, resolvedTarget)) {
|
|
6558
|
+
throw new PathOutsideRootError(resolvedRoot, resolvedTarget);
|
|
6559
|
+
}
|
|
6560
|
+
return { rootPath: resolvedRoot, targetPath: resolvedTarget };
|
|
6561
|
+
}
|
|
6562
|
+
|
|
6563
|
+
// src/controllers/workspace.ts
|
|
6031
6564
|
var WorkspaceController = class {
|
|
6032
6565
|
constructor() {
|
|
6033
6566
|
this.workspaceStore = (0, import_core24.getStoreLattice)("default", "workspace").store;
|
|
@@ -6188,16 +6721,23 @@ var WorkspaceController = class {
|
|
|
6188
6721
|
}),
|
|
6189
6722
|
workspace
|
|
6190
6723
|
};
|
|
6191
|
-
} else {
|
|
6192
|
-
console.log(`[getBackend] using FilesystemBackend rootDir=/lattice_store/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`);
|
|
6193
|
-
return {
|
|
6194
|
-
backend: new import_core25.FilesystemBackend({
|
|
6195
|
-
rootDir: `/lattice_store/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`,
|
|
6196
|
-
virtualMode: true
|
|
6197
|
-
}),
|
|
6198
|
-
workspace
|
|
6199
|
-
};
|
|
6200
6724
|
}
|
|
6725
|
+
const rootDir = await this.getFilesystemRootDirectory(
|
|
6726
|
+
tenantId,
|
|
6727
|
+
workspaceId,
|
|
6728
|
+
projectId
|
|
6729
|
+
);
|
|
6730
|
+
console.log(`[getBackend] using FilesystemBackend rootDir=${rootDir}`);
|
|
6731
|
+
return {
|
|
6732
|
+
backend: new import_core25.FilesystemBackend({
|
|
6733
|
+
rootDir,
|
|
6734
|
+
virtualMode: true
|
|
6735
|
+
}),
|
|
6736
|
+
workspace
|
|
6737
|
+
};
|
|
6738
|
+
}
|
|
6739
|
+
async getFilesystemRootDirectory(tenantId, workspaceId, projectId) {
|
|
6740
|
+
return `/lattice_store/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`;
|
|
6201
6741
|
}
|
|
6202
6742
|
isBinaryContentType(filename) {
|
|
6203
6743
|
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
@@ -6386,21 +6926,21 @@ var WorkspaceController = class {
|
|
|
6386
6926
|
async listPath(request) {
|
|
6387
6927
|
const tenantId = this.getTenantId(request);
|
|
6388
6928
|
const { workspaceId, projectId } = request.params;
|
|
6389
|
-
const
|
|
6929
|
+
const path4 = request.query.path || "/";
|
|
6390
6930
|
const assistantId = request.query.assistantId;
|
|
6391
|
-
console.log(`[listPath] tenantId=${tenantId} workspaceId=${workspaceId} projectId=${projectId} path=${
|
|
6392
|
-
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId,
|
|
6393
|
-
console.log(`[listPath] backend type=${backend.constructor.name} calling lsInfo(${
|
|
6394
|
-
const files = await backend.lsInfo(
|
|
6931
|
+
console.log(`[listPath] tenantId=${tenantId} workspaceId=${workspaceId} projectId=${projectId} path=${path4} assistantId=${assistantId}`);
|
|
6932
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path4);
|
|
6933
|
+
console.log(`[listPath] backend type=${backend.constructor.name} calling lsInfo(${path4})`);
|
|
6934
|
+
const files = await backend.lsInfo(path4);
|
|
6395
6935
|
console.log(`[listPath] result count=${files.length}`);
|
|
6396
6936
|
return { success: true, data: files };
|
|
6397
6937
|
}
|
|
6398
6938
|
async readFile(request) {
|
|
6399
6939
|
const tenantId = this.getTenantId(request);
|
|
6400
6940
|
const { workspaceId, projectId } = request.params;
|
|
6401
|
-
const { path:
|
|
6402
|
-
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId,
|
|
6403
|
-
const content = await backend.read(
|
|
6941
|
+
const { path: path4, offset = 0, limit = 1e3, assistantId } = request.query;
|
|
6942
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path4);
|
|
6943
|
+
const content = await backend.read(path4, Number(offset), Number(limit));
|
|
6404
6944
|
return { success: true, data: { content, offset, limit } };
|
|
6405
6945
|
}
|
|
6406
6946
|
/**
|
|
@@ -6412,7 +6952,7 @@ var WorkspaceController = class {
|
|
|
6412
6952
|
* - `path`: optional directory path relative to project root (e.g., "docs", "src/utils")
|
|
6413
6953
|
* - `assistantId`: optional query parameter for sandbox identity matching
|
|
6414
6954
|
* For sandbox storage, delegates to the sandbox upload API.
|
|
6415
|
-
* For filesystem storage, writes
|
|
6955
|
+
* For filesystem storage, writes under the same project root used by the file backend.
|
|
6416
6956
|
*/
|
|
6417
6957
|
async uploadFile(request, reply) {
|
|
6418
6958
|
const tenantId = this.getTenantId(request);
|
|
@@ -6446,7 +6986,7 @@ var WorkspaceController = class {
|
|
|
6446
6986
|
workspaceId,
|
|
6447
6987
|
projectId
|
|
6448
6988
|
};
|
|
6449
|
-
const realPath = pathValue ?
|
|
6989
|
+
const realPath = pathValue ? path2.posix.join(pathValue, filename) : path2.posix.join("/project/uploads", filename);
|
|
6450
6990
|
const isBinary = this.isBinaryContentType(filename);
|
|
6451
6991
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, realPath);
|
|
6452
6992
|
if (volumeBackend && !isBinary) {
|
|
@@ -6457,7 +6997,7 @@ var WorkspaceController = class {
|
|
|
6457
6997
|
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
6458
6998
|
await sandbox.file.uploadFile({ file: realPath, data: buffer });
|
|
6459
6999
|
}
|
|
6460
|
-
const relativePath = pathValue ?
|
|
7000
|
+
const relativePath = pathValue ? path2.posix.join(pathValue, filename) : path2.posix.join("/project/uploads", filename);
|
|
6461
7001
|
const result2 = {
|
|
6462
7002
|
path: relativePath,
|
|
6463
7003
|
name: filename,
|
|
@@ -6467,14 +7007,43 @@ var WorkspaceController = class {
|
|
|
6467
7007
|
};
|
|
6468
7008
|
return reply.status(200).send({ success: true, data: result2 });
|
|
6469
7009
|
}
|
|
6470
|
-
const rootDir =
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
7010
|
+
const rootDir = await this.getFilesystemRootDirectory(
|
|
7011
|
+
tenantId,
|
|
7012
|
+
workspaceId,
|
|
7013
|
+
projectId
|
|
7014
|
+
);
|
|
7015
|
+
await fs2.mkdir(rootDir, { recursive: true });
|
|
7016
|
+
const relativeDirectory = pathValue?.replace(/^[/\\]+/, "") || ".";
|
|
7017
|
+
const targetDir = path2.resolve(rootDir, relativeDirectory);
|
|
7018
|
+
if (!isPathWithinRoot(path2.resolve(rootDir), targetDir)) {
|
|
7019
|
+
return reply.status(400).send({
|
|
7020
|
+
success: false,
|
|
7021
|
+
error: "Upload path must stay within the project directory"
|
|
7022
|
+
});
|
|
7023
|
+
}
|
|
7024
|
+
await fs2.mkdir(targetDir, { recursive: true });
|
|
7025
|
+
const [resolvedRoot, resolvedTargetDir] = await Promise.all([
|
|
7026
|
+
fs2.realpath(rootDir),
|
|
7027
|
+
fs2.realpath(targetDir)
|
|
7028
|
+
]);
|
|
7029
|
+
if (!isPathWithinRoot(resolvedRoot, resolvedTargetDir)) {
|
|
7030
|
+
return reply.status(400).send({
|
|
7031
|
+
success: false,
|
|
7032
|
+
error: "Upload path must stay within the project directory"
|
|
7033
|
+
});
|
|
7034
|
+
}
|
|
7035
|
+
const safeFilename = path2.basename(filename);
|
|
7036
|
+
if (safeFilename !== filename) {
|
|
7037
|
+
return reply.status(400).send({
|
|
7038
|
+
success: false,
|
|
7039
|
+
error: "Invalid filename"
|
|
7040
|
+
});
|
|
7041
|
+
}
|
|
7042
|
+
const targetPath = path2.join(resolvedTargetDir, safeFilename);
|
|
7043
|
+
await fs2.writeFile(targetPath, buffer);
|
|
7044
|
+
const stat2 = await fs2.stat(targetPath);
|
|
6476
7045
|
const result = {
|
|
6477
|
-
path:
|
|
7046
|
+
path: path2.posix.join("/", relativeDirectory, safeFilename),
|
|
6478
7047
|
name: filename,
|
|
6479
7048
|
is_dir: false,
|
|
6480
7049
|
size: stat2.size,
|
|
@@ -6482,9 +7051,63 @@ var WorkspaceController = class {
|
|
|
6482
7051
|
};
|
|
6483
7052
|
return reply.status(200).send({ success: true, data: result });
|
|
6484
7053
|
} catch (error) {
|
|
7054
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6485
7055
|
return reply.status(500).send({
|
|
6486
7056
|
success: false,
|
|
6487
|
-
error: `Upload handler error: ${
|
|
7057
|
+
error: `Upload handler error: ${message}`
|
|
7058
|
+
});
|
|
7059
|
+
}
|
|
7060
|
+
}
|
|
7061
|
+
/**
|
|
7062
|
+
* Browse local filesystem directories for the folder picker.
|
|
7063
|
+
*
|
|
7064
|
+
* Security constraints:
|
|
7065
|
+
* - Restricted to os.homedir()
|
|
7066
|
+
* - Blacklists system directories
|
|
7067
|
+
* - Returns only directory names, no file contents or hidden files
|
|
7068
|
+
*/
|
|
7069
|
+
async browseFilesystem(request, reply) {
|
|
7070
|
+
const homeDir = os.homedir();
|
|
7071
|
+
const requestedPath = request.query.path || homeDir;
|
|
7072
|
+
const SYSTEM_BLACKLIST = ["/etc", "/sys", "/proc", "/var", "/tmp", "/dev"];
|
|
7073
|
+
try {
|
|
7074
|
+
const resolved = await resolvePathWithinRoot(homeDir, requestedPath);
|
|
7075
|
+
const normalized = resolved.targetPath;
|
|
7076
|
+
for (const blacklisted of SYSTEM_BLACKLIST) {
|
|
7077
|
+
if (isPathWithinRoot(blacklisted, normalized)) {
|
|
7078
|
+
return reply.status(403).send({
|
|
7079
|
+
success: false,
|
|
7080
|
+
error: `Cannot browse system directory: ${blacklisted}`
|
|
7081
|
+
});
|
|
7082
|
+
}
|
|
7083
|
+
}
|
|
7084
|
+
const entries = await fs2.readdir(normalized, { withFileTypes: true });
|
|
7085
|
+
const dirEntries = entries.filter((entry) => !entry.name.startsWith(".") && entry.isDirectory()).map((entry) => ({
|
|
7086
|
+
name: entry.name,
|
|
7087
|
+
path: path2.join(normalized, entry.name),
|
|
7088
|
+
isDirectory: true
|
|
7089
|
+
}));
|
|
7090
|
+
const parentPath = path2.dirname(normalized);
|
|
7091
|
+
const hasParent = parentPath !== normalized && isPathWithinRoot(resolved.rootPath, parentPath);
|
|
7092
|
+
return {
|
|
7093
|
+
success: true,
|
|
7094
|
+
data: {
|
|
7095
|
+
path: normalized,
|
|
7096
|
+
parentPath: hasParent ? parentPath : void 0,
|
|
7097
|
+
entries: dirEntries
|
|
7098
|
+
}
|
|
7099
|
+
};
|
|
7100
|
+
} catch (error) {
|
|
7101
|
+
if (error instanceof PathOutsideRootError) {
|
|
7102
|
+
return reply.status(403).send({
|
|
7103
|
+
success: false,
|
|
7104
|
+
error: "Browse restricted to home directory"
|
|
7105
|
+
});
|
|
7106
|
+
}
|
|
7107
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7108
|
+
return reply.status(400).send({
|
|
7109
|
+
success: false,
|
|
7110
|
+
error: `Cannot read directory: ${message}`
|
|
6488
7111
|
});
|
|
6489
7112
|
}
|
|
6490
7113
|
}
|
|
@@ -6545,6 +7168,10 @@ function registerWorkspaceRoutes(app2) {
|
|
|
6545
7168
|
"/api/workspaces/:workspaceId/projects/:projectId/viewfile",
|
|
6546
7169
|
controller.viewFile.bind(controller)
|
|
6547
7170
|
);
|
|
7171
|
+
app2.get(
|
|
7172
|
+
"/api/filesystem/browse",
|
|
7173
|
+
controller.browseFilesystem.bind(controller)
|
|
7174
|
+
);
|
|
6548
7175
|
}
|
|
6549
7176
|
|
|
6550
7177
|
// src/controllers/database-configs.ts
|
|
@@ -6761,7 +7388,7 @@ async function testDatabaseConnection(request, reply) {
|
|
|
6761
7388
|
await db.connect();
|
|
6762
7389
|
await db.listTables();
|
|
6763
7390
|
const latency = Date.now() - startTime;
|
|
6764
|
-
await new Promise((
|
|
7391
|
+
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
6765
7392
|
await db.disconnect();
|
|
6766
7393
|
await import_core27.sqlDatabaseManager.removeDatabase(tenantId, testKey);
|
|
6767
7394
|
return {
|
|
@@ -7590,11 +8217,12 @@ var EvalRunner = class {
|
|
|
7590
8217
|
constructor() {
|
|
7591
8218
|
this.runs = /* @__PURE__ */ new Map();
|
|
7592
8219
|
this.eventEmitter = new import_events.EventEmitter();
|
|
8220
|
+
this.processStartedAt = /* @__PURE__ */ new Date();
|
|
7593
8221
|
}
|
|
7594
8222
|
getEventEmitter() {
|
|
7595
8223
|
return this.eventEmitter;
|
|
7596
8224
|
}
|
|
7597
|
-
async startRun(tenantId, projectId) {
|
|
8225
|
+
async startRun(tenantId, projectId, suiteIds) {
|
|
7598
8226
|
const store2 = this.getEvalStore();
|
|
7599
8227
|
const project = await store2.getProjectById(tenantId, projectId);
|
|
7600
8228
|
if (!project) throw new Error("Project not found");
|
|
@@ -7604,10 +8232,27 @@ var EvalRunner = class {
|
|
|
7604
8232
|
}
|
|
7605
8233
|
}
|
|
7606
8234
|
const existingRuns = await store2.getRunsByTenant(tenantId, { projectId, status: "running" });
|
|
7607
|
-
|
|
8235
|
+
for (const run of existingRuns) {
|
|
8236
|
+
const orphaned = !this.runs.has(run.id) && run.createdAt < this.processStartedAt;
|
|
8237
|
+
if (orphaned) {
|
|
8238
|
+
await store2.updateRunStatus(tenantId, run.id, {
|
|
8239
|
+
status: "failed",
|
|
8240
|
+
error: "Gateway restarted \u2014 run orphaned",
|
|
8241
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
8242
|
+
});
|
|
8243
|
+
}
|
|
8244
|
+
}
|
|
8245
|
+
const stillRunning = await store2.getRunsByTenant(tenantId, { projectId, status: "running" });
|
|
8246
|
+
if (stillRunning.length > 0) {
|
|
7608
8247
|
throw new Error("A run is already in progress for this project");
|
|
7609
8248
|
}
|
|
7610
|
-
|
|
8249
|
+
let suites = await store2.getSuitesByProject(tenantId, projectId);
|
|
8250
|
+
if (suiteIds && suiteIds.length > 0) {
|
|
8251
|
+
suites = suites.filter((s) => suiteIds.includes(s.id));
|
|
8252
|
+
if (suites.length === 0) {
|
|
8253
|
+
throw new Error("No suites match the requested suiteIds filter");
|
|
8254
|
+
}
|
|
8255
|
+
}
|
|
7611
8256
|
const evalSuites = [];
|
|
7612
8257
|
let totalCases = 0;
|
|
7613
8258
|
for (const suite of suites) {
|
|
@@ -7650,6 +8295,9 @@ var EvalRunner = class {
|
|
|
7650
8295
|
const runId = (0, import_uuid4.v4)();
|
|
7651
8296
|
const concurrency = Math.max(1, Math.floor(project.concurrency) || 3);
|
|
7652
8297
|
await store2.createRun(tenantId, projectId, runId, { totalCases, concurrency });
|
|
8298
|
+
const tsc = project.targetServerConfig ?? {};
|
|
8299
|
+
const workspaceId = tsc.workspace_id || "";
|
|
8300
|
+
const projectIdFromConfig = tsc.project_id || "";
|
|
7653
8301
|
const projectConfig = {
|
|
7654
8302
|
projectName: project.name,
|
|
7655
8303
|
version: project.version,
|
|
@@ -7657,7 +8305,9 @@ var EvalRunner = class {
|
|
|
7657
8305
|
suites: evalSuites,
|
|
7658
8306
|
judge_agent_config: { modelKey: resolvedJudgeModelKey },
|
|
7659
8307
|
lattice_server_config: {
|
|
7660
|
-
tenant_id: tenantId
|
|
8308
|
+
tenant_id: tenantId,
|
|
8309
|
+
workspace_id: workspaceId,
|
|
8310
|
+
project_id: projectIdFromConfig
|
|
7661
8311
|
},
|
|
7662
8312
|
concurrency
|
|
7663
8313
|
};
|
|
@@ -7701,6 +8351,15 @@ var EvalRunner = class {
|
|
|
7701
8351
|
const runPromise = (async () => {
|
|
7702
8352
|
try {
|
|
7703
8353
|
const evalProject = new import_core31.LatticeEvalProject(projectConfig, onCaseComplete);
|
|
8354
|
+
const calibration = await evalProject.calibrateJudge();
|
|
8355
|
+
if (!calibration.ok) {
|
|
8356
|
+
await store2.updateRunStatus(tenantId, runId, {
|
|
8357
|
+
status: "failed",
|
|
8358
|
+
error: `Judge calibration failed: ${calibration.reason}`,
|
|
8359
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
8360
|
+
});
|
|
8361
|
+
throw new Error(`Judge calibration failed: ${calibration.reason}`);
|
|
8362
|
+
}
|
|
7704
8363
|
const { report } = await evalProject.runAllSuitesBatch(concurrency, abortController.signal);
|
|
7705
8364
|
if (!abortController.signal.aborted) {
|
|
7706
8365
|
const completedCount = stats.passed + stats.failed;
|
|
@@ -8088,11 +8747,12 @@ function registerEvalRoutes(app2) {
|
|
|
8088
8747
|
try {
|
|
8089
8748
|
const tenantId = getTenantId14(request);
|
|
8090
8749
|
const { pid } = request.params;
|
|
8091
|
-
const
|
|
8750
|
+
const body = request.body ?? {};
|
|
8751
|
+
const runId = await evalRunner.startRun(tenantId, pid, body?.suiteIds);
|
|
8092
8752
|
reply.status(202).send({ success: true, message: "Run started", data: { run_id: runId } });
|
|
8093
8753
|
} catch (err) {
|
|
8094
8754
|
const msg = err.message;
|
|
8095
|
-
const code = msg === "Project not found" ? 404 : msg.includes("already in progress") ? 409 : 500;
|
|
8755
|
+
const code = msg === "Project not found" ? 404 : msg.includes("already in progress") ? 409 : msg.includes("No suites match") ? 400 : 500;
|
|
8096
8756
|
reply.status(code).send({ success: false, message: msg });
|
|
8097
8757
|
}
|
|
8098
8758
|
});
|
|
@@ -9072,8 +9732,8 @@ function getTenantId15(request) {
|
|
|
9072
9732
|
return request.headers["x-tenant-id"] || "default";
|
|
9073
9733
|
}
|
|
9074
9734
|
async function getInstallationStore() {
|
|
9075
|
-
const { getStoreLattice:
|
|
9076
|
-
const store2 =
|
|
9735
|
+
const { getStoreLattice: getStoreLattice32 } = await import("@axiom-lattice/core");
|
|
9736
|
+
const store2 = getStoreLattice32("default", "channelInstallation").store;
|
|
9077
9737
|
if (store2) return store2;
|
|
9078
9738
|
const { PostgreSQLChannelInstallationStore } = await import("@axiom-lattice/pg-stores");
|
|
9079
9739
|
const databaseUrl = process.env.DATABASE_URL;
|
|
@@ -9554,8 +10214,8 @@ var log = {
|
|
|
9554
10214
|
};
|
|
9555
10215
|
var connections = /* @__PURE__ */ new Map();
|
|
9556
10216
|
var pending = /* @__PURE__ */ new Map();
|
|
9557
|
-
function getAgentIdFromPath(
|
|
9558
|
-
const match =
|
|
10217
|
+
function getAgentIdFromPath(path4) {
|
|
10218
|
+
const match = path4.match(/^\/api\/a2a\/bridge\/proxy\/([^/]+)/);
|
|
9559
10219
|
return match ? match[1] : null;
|
|
9560
10220
|
}
|
|
9561
10221
|
function handleBridgeConnection(socket, _request) {
|
|
@@ -9663,12 +10323,12 @@ async function handleBridgeProxy(request, reply) {
|
|
|
9663
10323
|
};
|
|
9664
10324
|
const timeout = 3e5;
|
|
9665
10325
|
try {
|
|
9666
|
-
const response = await new Promise((
|
|
10326
|
+
const response = await new Promise((resolve3, reject) => {
|
|
9667
10327
|
const timer = setTimeout(() => {
|
|
9668
10328
|
pending.delete(requestId);
|
|
9669
10329
|
reject(new Error(`Bridge request timeout after ${timeout}ms`));
|
|
9670
10330
|
}, timeout);
|
|
9671
|
-
pending.set(requestId, { resolve, reject, timer, agentId });
|
|
10331
|
+
pending.set(requestId, { resolve: resolve3, reject, timer, agentId });
|
|
9672
10332
|
try {
|
|
9673
10333
|
if (conn.ws.readyState !== conn.ws.OPEN) {
|
|
9674
10334
|
pending.delete(requestId);
|
|
@@ -9791,10 +10451,272 @@ var registerSTTRoutes = (app2) => {
|
|
|
9791
10451
|
);
|
|
9792
10452
|
};
|
|
9793
10453
|
|
|
10454
|
+
// src/controllers/local-a2a.ts
|
|
10455
|
+
var import_core39 = require("@axiom-lattice/core");
|
|
10456
|
+
var import_protocols5 = require("@axiom-lattice/protocols");
|
|
10457
|
+
function getTenantId18(request) {
|
|
10458
|
+
const userTenantId = request.user?.tenantId;
|
|
10459
|
+
if (userTenantId) return userTenantId;
|
|
10460
|
+
return request.headers["x-tenant-id"] || "default";
|
|
10461
|
+
}
|
|
10462
|
+
function getLocalRuntime(assistant) {
|
|
10463
|
+
const graphDefinition = assistant.graphDefinition;
|
|
10464
|
+
if (!graphDefinition || typeof graphDefinition !== "object") return void 0;
|
|
10465
|
+
if (graphDefinition.type !== import_protocols5.AgentType.A2A_REMOTE) return void 0;
|
|
10466
|
+
return graphDefinition.localRuntime;
|
|
10467
|
+
}
|
|
10468
|
+
async function getLocalA2AAssistants(tenantId) {
|
|
10469
|
+
const storeLattice = (0, import_core39.getStoreLattice)("default", "assistant");
|
|
10470
|
+
const assistants = await storeLattice.store.getAllAssistants(tenantId);
|
|
10471
|
+
const results = [];
|
|
10472
|
+
for (const assistant of assistants) {
|
|
10473
|
+
const runtime = getLocalRuntime(assistant);
|
|
10474
|
+
if (runtime) {
|
|
10475
|
+
results.push({ assistant, localRuntime: runtime });
|
|
10476
|
+
}
|
|
10477
|
+
}
|
|
10478
|
+
return results;
|
|
10479
|
+
}
|
|
10480
|
+
async function getLocalA2AAssistant(tenantId, assistantId) {
|
|
10481
|
+
const storeLattice = (0, import_core39.getStoreLattice)("default", "assistant");
|
|
10482
|
+
const assistant = await storeLattice.store.getAssistantById(tenantId, assistantId);
|
|
10483
|
+
if (!assistant) return null;
|
|
10484
|
+
const runtime = getLocalRuntime(assistant);
|
|
10485
|
+
if (!runtime) return null;
|
|
10486
|
+
return { assistant, localRuntime: runtime };
|
|
10487
|
+
}
|
|
10488
|
+
async function requireManagedAssistant(request, reply) {
|
|
10489
|
+
const assistantId = request.params.assistantId;
|
|
10490
|
+
if (!assistantId) {
|
|
10491
|
+
reply.status(400).send({ success: false, error: "assistantId is required" });
|
|
10492
|
+
return null;
|
|
10493
|
+
}
|
|
10494
|
+
const registered = await getLocalA2AAssistant(getTenantId18(request), assistantId);
|
|
10495
|
+
if (!registered) {
|
|
10496
|
+
reply.status(404).send({
|
|
10497
|
+
success: false,
|
|
10498
|
+
error: `Assistant ${assistantId} is not a local managed A2A assistant`
|
|
10499
|
+
});
|
|
10500
|
+
return null;
|
|
10501
|
+
}
|
|
10502
|
+
return { assistantId, localRuntime: registered.localRuntime };
|
|
10503
|
+
}
|
|
10504
|
+
async function getLocalA2AStatus(request, reply) {
|
|
10505
|
+
const tenantId = getTenantId18(request);
|
|
10506
|
+
const managed = await getLocalA2AAssistants(tenantId);
|
|
10507
|
+
const states = await Promise.all(
|
|
10508
|
+
managed.map(
|
|
10509
|
+
({ assistant, localRuntime }) => localA2AService.getRegisteredState(assistant.id, localRuntime)
|
|
10510
|
+
)
|
|
10511
|
+
);
|
|
10512
|
+
reply.send({ success: true, data: { records: states, total: states.length } });
|
|
10513
|
+
}
|
|
10514
|
+
async function getLocalA2AProvider(request, reply) {
|
|
10515
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
10516
|
+
if (!registered) return;
|
|
10517
|
+
const state = await localA2AService.getRegisteredState(
|
|
10518
|
+
registered.assistantId,
|
|
10519
|
+
registered.localRuntime
|
|
10520
|
+
);
|
|
10521
|
+
reply.send({ success: true, data: state });
|
|
10522
|
+
}
|
|
10523
|
+
async function startLocalA2AProvider(request, reply) {
|
|
10524
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
10525
|
+
if (!registered) return;
|
|
10526
|
+
const state = await localA2AService.startProvider(
|
|
10527
|
+
registered.assistantId,
|
|
10528
|
+
registered.localRuntime
|
|
10529
|
+
);
|
|
10530
|
+
reply.send({ success: true, data: state });
|
|
10531
|
+
}
|
|
10532
|
+
async function stopLocalA2AProvider(request, reply) {
|
|
10533
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
10534
|
+
if (!registered) return;
|
|
10535
|
+
const state = await localA2AService.stopProvider(registered.assistantId);
|
|
10536
|
+
reply.send({ success: true, data: state });
|
|
10537
|
+
}
|
|
10538
|
+
async function restartLocalA2AProvider(request, reply) {
|
|
10539
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
10540
|
+
if (!registered) return;
|
|
10541
|
+
const state = await localA2AService.restartProvider(
|
|
10542
|
+
registered.assistantId,
|
|
10543
|
+
registered.localRuntime
|
|
10544
|
+
);
|
|
10545
|
+
reply.send({ success: true, data: state });
|
|
10546
|
+
}
|
|
10547
|
+
|
|
10548
|
+
// src/config/local-a2a-templates.ts
|
|
10549
|
+
var import_cli_path = require("@axiom-lattice/cli-a2a/cli-path");
|
|
10550
|
+
function buildCliA2ACommand(provider, agentName, agentDescription) {
|
|
10551
|
+
return {
|
|
10552
|
+
executable: process.execPath,
|
|
10553
|
+
args: [
|
|
10554
|
+
import_cli_path.cliA2AEntryPath,
|
|
10555
|
+
"--provider",
|
|
10556
|
+
provider,
|
|
10557
|
+
"--hostname",
|
|
10558
|
+
"localhost",
|
|
10559
|
+
"--advertise-host",
|
|
10560
|
+
"localhost",
|
|
10561
|
+
"--agent-name",
|
|
10562
|
+
agentName,
|
|
10563
|
+
"--agent-description",
|
|
10564
|
+
agentDescription,
|
|
10565
|
+
"--log-level",
|
|
10566
|
+
"info"
|
|
10567
|
+
]
|
|
10568
|
+
};
|
|
10569
|
+
}
|
|
10570
|
+
var LOCAL_A2A_TEMPLATES = [
|
|
10571
|
+
{
|
|
10572
|
+
key: "claude",
|
|
10573
|
+
name: "Claude Code",
|
|
10574
|
+
command: buildCliA2ACommand(
|
|
10575
|
+
"claude",
|
|
10576
|
+
"Claude Code",
|
|
10577
|
+
"Local Claude Code wrapper exposed through A2A."
|
|
10578
|
+
)
|
|
10579
|
+
},
|
|
10580
|
+
{
|
|
10581
|
+
key: "codex",
|
|
10582
|
+
name: "Codex",
|
|
10583
|
+
command: buildCliA2ACommand(
|
|
10584
|
+
"codex",
|
|
10585
|
+
"Codex",
|
|
10586
|
+
"Local Codex wrapper exposed through A2A."
|
|
10587
|
+
)
|
|
10588
|
+
},
|
|
10589
|
+
{
|
|
10590
|
+
key: "opencode",
|
|
10591
|
+
name: "OpenCode",
|
|
10592
|
+
command: buildCliA2ACommand(
|
|
10593
|
+
"opencode",
|
|
10594
|
+
"OpenCode",
|
|
10595
|
+
"Local OpenCode wrapper exposed through A2A."
|
|
10596
|
+
)
|
|
10597
|
+
}
|
|
10598
|
+
];
|
|
10599
|
+
|
|
10600
|
+
// src/controllers/local-a2a-templates.ts
|
|
10601
|
+
async function getLocalA2ATemplates(_request, reply) {
|
|
10602
|
+
reply.send({
|
|
10603
|
+
success: true,
|
|
10604
|
+
data: {
|
|
10605
|
+
records: LOCAL_A2A_TEMPLATES,
|
|
10606
|
+
total: LOCAL_A2A_TEMPLATES.length
|
|
10607
|
+
}
|
|
10608
|
+
});
|
|
10609
|
+
}
|
|
10610
|
+
|
|
10611
|
+
// src/routes/a2a-test-connection.ts
|
|
10612
|
+
var import_node_crypto = require("crypto");
|
|
10613
|
+
function describeTestConnectionError(error, agentCardUrl) {
|
|
10614
|
+
if (!(error instanceof Error)) {
|
|
10615
|
+
return `Failed to fetch agent card from ${agentCardUrl}: ${String(error)}`;
|
|
10616
|
+
}
|
|
10617
|
+
const cause = error.cause;
|
|
10618
|
+
const causeParts = [];
|
|
10619
|
+
if (cause instanceof Error) {
|
|
10620
|
+
causeParts.push(cause.message);
|
|
10621
|
+
const causeCode = cause.code;
|
|
10622
|
+
if (causeCode && !causeParts.some((part) => part.includes(causeCode))) {
|
|
10623
|
+
causeParts.push(causeCode);
|
|
10624
|
+
}
|
|
10625
|
+
} else if (typeof cause === "object" && cause !== null) {
|
|
10626
|
+
const code = "code" in cause ? String(cause.code) : "";
|
|
10627
|
+
const message = "message" in cause ? String(cause.message) : "";
|
|
10628
|
+
if (message) causeParts.push(message);
|
|
10629
|
+
if (code && !message.includes(code)) causeParts.push(code);
|
|
10630
|
+
}
|
|
10631
|
+
const detail = causeParts.length > 0 ? ` (${causeParts.join(", ")})` : "";
|
|
10632
|
+
return `Failed to fetch agent card from ${agentCardUrl}: ${error.message}${detail}`;
|
|
10633
|
+
}
|
|
10634
|
+
async function ensureLocalRuntimeForConnectionTest(localRuntime, agentCardUrl) {
|
|
10635
|
+
const commandValidation = validateLocalRuntimeCommand(localRuntime);
|
|
10636
|
+
if (!commandValidation.ok) {
|
|
10637
|
+
return { error: commandValidation.error };
|
|
10638
|
+
}
|
|
10639
|
+
const testRuntime = {
|
|
10640
|
+
...localRuntime,
|
|
10641
|
+
agentCardUrl,
|
|
10642
|
+
command: {
|
|
10643
|
+
...localRuntime.command,
|
|
10644
|
+
executable: localRuntime.command.executable.trim()
|
|
10645
|
+
}
|
|
10646
|
+
};
|
|
10647
|
+
const portValidation = validateLocalRuntimePort(testRuntime, agentCardUrl);
|
|
10648
|
+
if (!portValidation.ok) {
|
|
10649
|
+
return { error: portValidation.error };
|
|
10650
|
+
}
|
|
10651
|
+
const state = await localA2AService.startProvider(
|
|
10652
|
+
`test-${(0, import_node_crypto.randomUUID)()}`,
|
|
10653
|
+
testRuntime
|
|
10654
|
+
);
|
|
10655
|
+
if (state.status === "running") return { runtimeId: state.runtimeId };
|
|
10656
|
+
const detail = state.message ? ` ${state.message}` : "";
|
|
10657
|
+
localA2AService.removeState(state.runtimeId);
|
|
10658
|
+
return { error: `Local managed A2A server could not start for connection test.${detail}` };
|
|
10659
|
+
}
|
|
10660
|
+
async function readShortResponseBody(resp) {
|
|
10661
|
+
const body = await resp.text().catch(() => "");
|
|
10662
|
+
return body.length > 500 ? `${body.slice(0, 500)}...` : body;
|
|
10663
|
+
}
|
|
10664
|
+
function registerA2ATestConnectionRoute(app2) {
|
|
10665
|
+
app2.post("/api/a2a/test-connection", async (request, reply) => {
|
|
10666
|
+
const { agentCardUrl, apiKey, localRuntime } = request.body ?? {};
|
|
10667
|
+
const normalizedAgentCardUrl = normalizeA2AAgentCardUrl(
|
|
10668
|
+
agentCardUrl,
|
|
10669
|
+
localRuntime ? "http://" : "https://"
|
|
10670
|
+
);
|
|
10671
|
+
if (!normalizedAgentCardUrl) {
|
|
10672
|
+
return reply.status(400).send({ success: false, error: "agentCardUrl is required" });
|
|
10673
|
+
}
|
|
10674
|
+
let testRuntimeId = null;
|
|
10675
|
+
try {
|
|
10676
|
+
const headers = {};
|
|
10677
|
+
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
|
10678
|
+
if (localRuntime) {
|
|
10679
|
+
const localStartResult = await ensureLocalRuntimeForConnectionTest(localRuntime, normalizedAgentCardUrl);
|
|
10680
|
+
if ("error" in localStartResult) {
|
|
10681
|
+
return reply.send({ success: true, data: { reachable: false, error: localStartResult.error } });
|
|
10682
|
+
}
|
|
10683
|
+
testRuntimeId = localStartResult.runtimeId;
|
|
10684
|
+
}
|
|
10685
|
+
const resp = await fetch(normalizedAgentCardUrl, { headers, signal: AbortSignal.timeout(8e3) });
|
|
10686
|
+
if (!resp.ok) {
|
|
10687
|
+
const body = await readShortResponseBody(resp);
|
|
10688
|
+
const suffix = body ? `: ${body}` : "";
|
|
10689
|
+
return reply.send({ success: true, data: { reachable: false, error: `HTTP ${resp.status} ${resp.statusText}${suffix}` } });
|
|
10690
|
+
}
|
|
10691
|
+
const card = await resp.json();
|
|
10692
|
+
return reply.send({ success: true, data: { reachable: true, agentName: card.name, agentCard: card } });
|
|
10693
|
+
} catch (error) {
|
|
10694
|
+
return reply.send({
|
|
10695
|
+
success: true,
|
|
10696
|
+
data: {
|
|
10697
|
+
reachable: false,
|
|
10698
|
+
error: describeTestConnectionError(error, normalizedAgentCardUrl)
|
|
10699
|
+
}
|
|
10700
|
+
});
|
|
10701
|
+
} finally {
|
|
10702
|
+
if (testRuntimeId) {
|
|
10703
|
+
localA2AService.removeState(testRuntimeId);
|
|
10704
|
+
}
|
|
10705
|
+
}
|
|
10706
|
+
});
|
|
10707
|
+
}
|
|
10708
|
+
|
|
9794
10709
|
// src/routes/index.ts
|
|
9795
10710
|
var registerLatticeRoutes = (app2, channelDeps) => {
|
|
9796
10711
|
registerA2ABridgeRoutes(app2);
|
|
9797
10712
|
registerSTTRoutes(app2);
|
|
10713
|
+
app2.get("/api/local-a2a", getLocalA2AStatus);
|
|
10714
|
+
app2.get("/api/local-a2a/templates", getLocalA2ATemplates);
|
|
10715
|
+
app2.get("/api/local-a2a/:assistantId", getLocalA2AProvider);
|
|
10716
|
+
app2.post("/api/local-a2a/:assistantId/start", startLocalA2AProvider);
|
|
10717
|
+
app2.post("/api/local-a2a/:assistantId/stop", stopLocalA2AProvider);
|
|
10718
|
+
app2.post("/api/local-a2a/:assistantId/restart", restartLocalA2AProvider);
|
|
10719
|
+
registerA2ATestConnectionRoute(app2);
|
|
9798
10720
|
app2.post("/api/runs", createRun);
|
|
9799
10721
|
app2.post("/api/resume_stream", resumeStream);
|
|
9800
10722
|
app2.post("/api/assistants/:assistantId/threads/:threadId/abort", abortRun);
|
|
@@ -10086,12 +11008,12 @@ function registerResourceRoutes(app2, controller) {
|
|
|
10086
11008
|
}
|
|
10087
11009
|
|
|
10088
11010
|
// src/export_registrations/index.ts
|
|
10089
|
-
var
|
|
11011
|
+
var import_core53 = require("@axiom-lattice/core");
|
|
10090
11012
|
|
|
10091
11013
|
// src/export_registrations/skill.registration.ts
|
|
10092
|
-
var
|
|
11014
|
+
var import_core40 = require("@axiom-lattice/core");
|
|
10093
11015
|
function getStore2() {
|
|
10094
|
-
return (0,
|
|
11016
|
+
return (0, import_core40.getStoreLattice)("default", "skill").store;
|
|
10095
11017
|
}
|
|
10096
11018
|
var skillRegistration = {
|
|
10097
11019
|
entityType: "skill",
|
|
@@ -10166,9 +11088,9 @@ var skillRegistration = {
|
|
|
10166
11088
|
};
|
|
10167
11089
|
|
|
10168
11090
|
// src/export_registrations/agent.registration.ts
|
|
10169
|
-
var
|
|
11091
|
+
var import_core41 = require("@axiom-lattice/core");
|
|
10170
11092
|
function getStore3() {
|
|
10171
|
-
return (0,
|
|
11093
|
+
return (0, import_core41.getStoreLattice)("default", "assistant").store;
|
|
10172
11094
|
}
|
|
10173
11095
|
var agentRegistration = {
|
|
10174
11096
|
entityType: "agent",
|
|
@@ -10235,9 +11157,9 @@ var agentRegistration = {
|
|
|
10235
11157
|
};
|
|
10236
11158
|
|
|
10237
11159
|
// src/export_registrations/binding.registration.ts
|
|
10238
|
-
var
|
|
11160
|
+
var import_core42 = require("@axiom-lattice/core");
|
|
10239
11161
|
function getStore4() {
|
|
10240
|
-
return (0,
|
|
11162
|
+
return (0, import_core42.getStoreLattice)("default", "channelBinding").store;
|
|
10241
11163
|
}
|
|
10242
11164
|
var bindingRegistration = {
|
|
10243
11165
|
entityType: "binding",
|
|
@@ -10325,9 +11247,9 @@ var bindingRegistration = {
|
|
|
10325
11247
|
};
|
|
10326
11248
|
|
|
10327
11249
|
// src/export_registrations/database-config.registration.ts
|
|
10328
|
-
var
|
|
11250
|
+
var import_core43 = require("@axiom-lattice/core");
|
|
10329
11251
|
function getStore5() {
|
|
10330
|
-
return (0,
|
|
11252
|
+
return (0, import_core43.getStoreLattice)("default", "database").store;
|
|
10331
11253
|
}
|
|
10332
11254
|
var databaseConfigRegistration = {
|
|
10333
11255
|
entityType: "database_config",
|
|
@@ -10407,9 +11329,9 @@ var databaseConfigRegistration = {
|
|
|
10407
11329
|
};
|
|
10408
11330
|
|
|
10409
11331
|
// src/export_registrations/metrics-config.registration.ts
|
|
10410
|
-
var
|
|
11332
|
+
var import_core44 = require("@axiom-lattice/core");
|
|
10411
11333
|
function getStore6() {
|
|
10412
|
-
return (0,
|
|
11334
|
+
return (0, import_core44.getStoreLattice)("default", "metrics").store;
|
|
10413
11335
|
}
|
|
10414
11336
|
var metricsConfigRegistration = {
|
|
10415
11337
|
entityType: "metrics_config",
|
|
@@ -10489,9 +11411,9 @@ var metricsConfigRegistration = {
|
|
|
10489
11411
|
};
|
|
10490
11412
|
|
|
10491
11413
|
// src/export_registrations/mcp-config.registration.ts
|
|
10492
|
-
var
|
|
11414
|
+
var import_core45 = require("@axiom-lattice/core");
|
|
10493
11415
|
function getStore7() {
|
|
10494
|
-
return (0,
|
|
11416
|
+
return (0, import_core45.getStoreLattice)("default", "mcp").store;
|
|
10495
11417
|
}
|
|
10496
11418
|
var mcpConfigRegistration = {
|
|
10497
11419
|
entityType: "mcp_config",
|
|
@@ -10574,9 +11496,9 @@ var mcpConfigRegistration = {
|
|
|
10574
11496
|
};
|
|
10575
11497
|
|
|
10576
11498
|
// src/export_registrations/connection.registration.ts
|
|
10577
|
-
var
|
|
11499
|
+
var import_core46 = require("@axiom-lattice/core");
|
|
10578
11500
|
function getStore8() {
|
|
10579
|
-
return (0,
|
|
11501
|
+
return (0, import_core46.getStoreLattice)("default", "connection").store;
|
|
10580
11502
|
}
|
|
10581
11503
|
async function listAllConnections(tenantId) {
|
|
10582
11504
|
const store2 = getStore8();
|
|
@@ -10658,9 +11580,9 @@ var connectionRegistration = {
|
|
|
10658
11580
|
};
|
|
10659
11581
|
|
|
10660
11582
|
// src/export_registrations/collection.registration.ts
|
|
10661
|
-
var
|
|
11583
|
+
var import_core47 = require("@axiom-lattice/core");
|
|
10662
11584
|
function getStore9() {
|
|
10663
|
-
return (0,
|
|
11585
|
+
return (0, import_core47.getStoreLattice)("default", "collection").store;
|
|
10664
11586
|
}
|
|
10665
11587
|
var collectionRegistration = {
|
|
10666
11588
|
entityType: "collection",
|
|
@@ -10731,9 +11653,9 @@ var collectionRegistration = {
|
|
|
10731
11653
|
};
|
|
10732
11654
|
|
|
10733
11655
|
// src/export_registrations/channel-installation.registration.ts
|
|
10734
|
-
var
|
|
11656
|
+
var import_core48 = require("@axiom-lattice/core");
|
|
10735
11657
|
function getStore10() {
|
|
10736
|
-
return (0,
|
|
11658
|
+
return (0, import_core48.getStoreLattice)("default", "channelInstallation").store;
|
|
10737
11659
|
}
|
|
10738
11660
|
var channelInstallationRegistration = {
|
|
10739
11661
|
entityType: "channel_installation",
|
|
@@ -10808,9 +11730,9 @@ var channelInstallationRegistration = {
|
|
|
10808
11730
|
};
|
|
10809
11731
|
|
|
10810
11732
|
// src/export_registrations/menu.registration.ts
|
|
10811
|
-
var
|
|
11733
|
+
var import_core49 = require("@axiom-lattice/core");
|
|
10812
11734
|
function getStore11() {
|
|
10813
|
-
return (0,
|
|
11735
|
+
return (0, import_core49.getStoreLattice)("default", "menu").store;
|
|
10814
11736
|
}
|
|
10815
11737
|
var menuRegistration = {
|
|
10816
11738
|
entityType: "menu",
|
|
@@ -10888,9 +11810,9 @@ var menuRegistration = {
|
|
|
10888
11810
|
};
|
|
10889
11811
|
|
|
10890
11812
|
// src/export_registrations/task.registration.ts
|
|
10891
|
-
var
|
|
11813
|
+
var import_core50 = require("@axiom-lattice/core");
|
|
10892
11814
|
function getStore12() {
|
|
10893
|
-
return (0,
|
|
11815
|
+
return (0, import_core50.getStoreLattice)("default", "task").store;
|
|
10894
11816
|
}
|
|
10895
11817
|
var taskRegistration = {
|
|
10896
11818
|
entityType: "task",
|
|
@@ -10976,9 +11898,9 @@ var taskRegistration = {
|
|
|
10976
11898
|
};
|
|
10977
11899
|
|
|
10978
11900
|
// src/export_registrations/a2a-api-key.registration.ts
|
|
10979
|
-
var
|
|
11901
|
+
var import_core51 = require("@axiom-lattice/core");
|
|
10980
11902
|
function getStore13() {
|
|
10981
|
-
return (0,
|
|
11903
|
+
return (0, import_core51.getStoreLattice)("default", "a2aApiKey").store;
|
|
10982
11904
|
}
|
|
10983
11905
|
var a2aApiKeyRegistration = {
|
|
10984
11906
|
entityType: "a2a_api_key",
|
|
@@ -11049,9 +11971,9 @@ var a2aApiKeyRegistration = {
|
|
|
11049
11971
|
};
|
|
11050
11972
|
|
|
11051
11973
|
// src/export_registrations/eval.registration.ts
|
|
11052
|
-
var
|
|
11974
|
+
var import_core52 = require("@axiom-lattice/core");
|
|
11053
11975
|
function getStore14() {
|
|
11054
|
-
return (0,
|
|
11976
|
+
return (0, import_core52.getStoreLattice)("default", "eval").store;
|
|
11055
11977
|
}
|
|
11056
11978
|
var evalRegistration = {
|
|
11057
11979
|
entityType: "eval",
|
|
@@ -11377,7 +12299,7 @@ var evalRegistration = {
|
|
|
11377
12299
|
|
|
11378
12300
|
// src/export_registrations/index.ts
|
|
11379
12301
|
function registerAllBuiltinEntities() {
|
|
11380
|
-
const registry =
|
|
12302
|
+
const registry = import_core53.ExportableEntityRegistry.getInstance();
|
|
11381
12303
|
registry.register(skillRegistration);
|
|
11382
12304
|
registry.register(agentRegistration);
|
|
11383
12305
|
registry.register(bindingRegistration);
|
|
@@ -11394,7 +12316,7 @@ function registerAllBuiltinEntities() {
|
|
|
11394
12316
|
}
|
|
11395
12317
|
|
|
11396
12318
|
// src/router/MessageRouter.ts
|
|
11397
|
-
var
|
|
12319
|
+
var import_core54 = require("@axiom-lattice/core");
|
|
11398
12320
|
var import_crypto10 = require("crypto");
|
|
11399
12321
|
var BindingNotFoundError = class extends Error {
|
|
11400
12322
|
constructor(message) {
|
|
@@ -11555,7 +12477,7 @@ var MessageRouter = class {
|
|
|
11555
12477
|
channel: message.channel,
|
|
11556
12478
|
adapterChannel: adapter.channel
|
|
11557
12479
|
}, "Thread resolved by adapter strategy");
|
|
11558
|
-
const threadStore = (0,
|
|
12480
|
+
const threadStore = (0, import_core54.getStoreLattice)("default", "thread").store;
|
|
11559
12481
|
try {
|
|
11560
12482
|
await threadStore.createThread(
|
|
11561
12483
|
tenantId,
|
|
@@ -11592,7 +12514,7 @@ var MessageRouter = class {
|
|
|
11592
12514
|
}
|
|
11593
12515
|
}
|
|
11594
12516
|
if (!threadId) {
|
|
11595
|
-
const threadStore = (0,
|
|
12517
|
+
const threadStore = (0, import_core54.getStoreLattice)("default", "thread").store;
|
|
11596
12518
|
const newThreadId = (0, import_crypto10.randomUUID)();
|
|
11597
12519
|
console.log({
|
|
11598
12520
|
event: "dispatch:thread:create",
|
|
@@ -11632,7 +12554,7 @@ var MessageRouter = class {
|
|
|
11632
12554
|
senderId: message.sender.id,
|
|
11633
12555
|
contentLength: message.content.text.length
|
|
11634
12556
|
}, "Dispatching to agent");
|
|
11635
|
-
const agent =
|
|
12557
|
+
const agent = import_core54.agentInstanceManager.getAgent({
|
|
11636
12558
|
tenant_id: tenantId,
|
|
11637
12559
|
assistant_id: agentId,
|
|
11638
12560
|
thread_id: threadId,
|
|
@@ -11877,7 +12799,7 @@ function createAuditLoggerMiddleware() {
|
|
|
11877
12799
|
}
|
|
11878
12800
|
|
|
11879
12801
|
// src/index.ts
|
|
11880
|
-
var
|
|
12802
|
+
var import_core58 = require("@axiom-lattice/core");
|
|
11881
12803
|
|
|
11882
12804
|
// src/swagger.ts
|
|
11883
12805
|
var import_swagger = __toESM(require("@fastify/swagger"));
|
|
@@ -11942,7 +12864,7 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
|
|
|
11942
12864
|
};
|
|
11943
12865
|
|
|
11944
12866
|
// src/services/agent_task_consumer.ts
|
|
11945
|
-
var
|
|
12867
|
+
var import_core55 = require("@axiom-lattice/core");
|
|
11946
12868
|
var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
11947
12869
|
const {
|
|
11948
12870
|
assistant_id,
|
|
@@ -11960,17 +12882,17 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
|
11960
12882
|
console.log(
|
|
11961
12883
|
`\u5F00\u59CB\u5904\u7406\u4EFB\u52A1 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
|
|
11962
12884
|
);
|
|
11963
|
-
const agent =
|
|
11964
|
-
await agent.addMessage({ input, command, custom_run_config: runConfig },
|
|
12885
|
+
const agent = import_core55.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
|
|
12886
|
+
await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core55.QueueMode.STEER);
|
|
11965
12887
|
if (callback_event) {
|
|
11966
12888
|
agent.subscribeOnce("message:completed", (evt) => {
|
|
11967
|
-
|
|
12889
|
+
import_core55.eventBus.publish(callback_event, {
|
|
11968
12890
|
success: true,
|
|
11969
12891
|
state: evt.state
|
|
11970
12892
|
});
|
|
11971
12893
|
if (main_thread_id && main_tenant_id) {
|
|
11972
12894
|
try {
|
|
11973
|
-
const mainAgent =
|
|
12895
|
+
const mainAgent = import_core55.agentInstanceManager.getAgent({
|
|
11974
12896
|
assistant_id: main_assistant_id ?? assistant_id,
|
|
11975
12897
|
thread_id: main_thread_id,
|
|
11976
12898
|
tenant_id: main_tenant_id,
|
|
@@ -12000,7 +12922,7 @@ ${summary}`
|
|
|
12000
12922
|
}
|
|
12001
12923
|
});
|
|
12002
12924
|
agent.subscribeOnce("message:interrupted", (evt) => {
|
|
12003
|
-
|
|
12925
|
+
import_core55.eventBus.publish(callback_event, {
|
|
12004
12926
|
success: true,
|
|
12005
12927
|
state: evt.state
|
|
12006
12928
|
});
|
|
@@ -12019,11 +12941,11 @@ ${summary}`
|
|
|
12019
12941
|
console.log(
|
|
12020
12942
|
`\u5C06\u5728 ${delayMs}ms \u540E\u91CD\u8BD5\u4EFB\u52A1 (${nextRetryCount}/${maxRetries})`
|
|
12021
12943
|
);
|
|
12022
|
-
await new Promise((
|
|
12944
|
+
await new Promise((resolve3) => setTimeout(resolve3, delayMs));
|
|
12023
12945
|
return handleAgentTask(taskRequest, nextRetryCount);
|
|
12024
12946
|
}
|
|
12025
12947
|
if (callback_event) {
|
|
12026
|
-
|
|
12948
|
+
import_core55.eventBus.publish(callback_event, {
|
|
12027
12949
|
success: false,
|
|
12028
12950
|
error: error instanceof Error ? error.message : String(error)
|
|
12029
12951
|
});
|
|
@@ -12060,7 +12982,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
|
|
|
12060
12982
|
* 初始化事件监听和队列轮询
|
|
12061
12983
|
*/
|
|
12062
12984
|
initialize() {
|
|
12063
|
-
|
|
12985
|
+
import_core55.eventBus.subscribe(import_core55.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
|
|
12064
12986
|
this.startPollingQueue();
|
|
12065
12987
|
console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
|
|
12066
12988
|
}
|
|
@@ -12179,7 +13101,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
|
|
|
12179
13101
|
handleAgentTask(taskRequest).catch((error) => {
|
|
12180
13102
|
console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
|
|
12181
13103
|
if (taskRequest.callback_event) {
|
|
12182
|
-
|
|
13104
|
+
import_core55.eventBus.publish(taskRequest.callback_event, {
|
|
12183
13105
|
success: false,
|
|
12184
13106
|
error: error instanceof Error ? error.message : String(error)
|
|
12185
13107
|
});
|
|
@@ -12194,8 +13116,8 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
|
|
|
12194
13116
|
var AgentTaskConsumer = _AgentTaskConsumer;
|
|
12195
13117
|
|
|
12196
13118
|
// src/index.ts
|
|
12197
|
-
var
|
|
12198
|
-
var
|
|
13119
|
+
var import_core59 = require("@axiom-lattice/core");
|
|
13120
|
+
var import_protocols7 = require("@axiom-lattice/protocols");
|
|
12199
13121
|
var import_meta = {};
|
|
12200
13122
|
process.on("unhandledRejection", (reason, promise) => {
|
|
12201
13123
|
console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
|
|
@@ -12203,18 +13125,18 @@ process.on("unhandledRejection", (reason, promise) => {
|
|
|
12203
13125
|
var DEFAULT_LOGGER_CONFIG = {
|
|
12204
13126
|
name: "default",
|
|
12205
13127
|
description: "Default logger for lattice-gateway service",
|
|
12206
|
-
type:
|
|
13128
|
+
type: import_protocols7.LoggerType.PINO,
|
|
12207
13129
|
serviceName: "lattice/gateway",
|
|
12208
13130
|
loggerName: "lattice/gateway"
|
|
12209
13131
|
};
|
|
12210
13132
|
var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
|
|
12211
13133
|
var logger5 = loggerLattice.client;
|
|
12212
13134
|
function initializeLogger(config) {
|
|
12213
|
-
if (
|
|
12214
|
-
|
|
13135
|
+
if (import_core59.loggerLatticeManager.hasLattice("default")) {
|
|
13136
|
+
import_core59.loggerLatticeManager.removeLattice("default");
|
|
12215
13137
|
}
|
|
12216
|
-
(0,
|
|
12217
|
-
return (0,
|
|
13138
|
+
(0, import_core59.registerLoggerLattice)("default", config);
|
|
13139
|
+
return (0, import_core59.getLoggerLattice)("default");
|
|
12218
13140
|
}
|
|
12219
13141
|
var app = (0, import_fastify.default)({
|
|
12220
13142
|
logger: false,
|
|
@@ -12325,7 +13247,7 @@ app.setErrorHandler((error, request, reply) => {
|
|
|
12325
13247
|
});
|
|
12326
13248
|
function getConfiguredSandboxProvider() {
|
|
12327
13249
|
const sandboxProviderType = process.env.SANDBOX_PROVIDER_TYPE || "microsandbox-remote";
|
|
12328
|
-
return (0,
|
|
13250
|
+
return (0, import_core59.createSandboxProvider)({
|
|
12329
13251
|
type: sandboxProviderType,
|
|
12330
13252
|
remoteBaseURL: process.env.SANDBOX_BASE_URL,
|
|
12331
13253
|
microsandboxServiceBaseURL: process.env.MICROSANDBOX_SERVICE_BASE_URL,
|
|
@@ -12341,7 +13263,7 @@ function getConfiguredSandboxProvider() {
|
|
|
12341
13263
|
}
|
|
12342
13264
|
async function restoreMcpConnections() {
|
|
12343
13265
|
try {
|
|
12344
|
-
const storeLattice = (0,
|
|
13266
|
+
const storeLattice = (0, import_core59.getStoreLattice)("default", "mcp");
|
|
12345
13267
|
const store2 = storeLattice.store;
|
|
12346
13268
|
if (!store2) {
|
|
12347
13269
|
logger5.info("MCP store not configured, skipping connection restoration");
|
|
@@ -12355,15 +13277,15 @@ async function restoreMcpConnections() {
|
|
|
12355
13277
|
for (const config of connectedConfigs) {
|
|
12356
13278
|
try {
|
|
12357
13279
|
const connection = convertToConnection2(config.config);
|
|
12358
|
-
|
|
13280
|
+
import_core59.mcpManager.addServer(config.key, connection);
|
|
12359
13281
|
} catch (err) {
|
|
12360
13282
|
logger5.warn(`Failed to prepare MCP server "${config.key}" for restoration`, { error: err });
|
|
12361
13283
|
}
|
|
12362
13284
|
}
|
|
12363
|
-
await
|
|
13285
|
+
await import_core59.mcpManager.connect();
|
|
12364
13286
|
for (const config of connectedConfigs) {
|
|
12365
13287
|
try {
|
|
12366
|
-
await
|
|
13288
|
+
await import_core59.mcpManager.registerToolsToToolLattice(config.key, config.selectedTools);
|
|
12367
13289
|
logger5.info(`MCP server "${config.key}" restored with ${config.selectedTools.length} tools`);
|
|
12368
13290
|
} catch (err) {
|
|
12369
13291
|
logger5.warn(`Failed to register tools for MCP server "${config.key}"`, { error: err });
|
|
@@ -12396,7 +13318,7 @@ var start = async (config) => {
|
|
|
12396
13318
|
const { getStoreLattice: getStore15 } = await import("@axiom-lattice/core");
|
|
12397
13319
|
const bindingStore = getStore15("default", "channelBinding").store;
|
|
12398
13320
|
const installationStore = getStore15("default", "channelInstallation").store;
|
|
12399
|
-
(0,
|
|
13321
|
+
(0, import_core58.setBindingRegistry)(bindingStore);
|
|
12400
13322
|
const router = new MessageRouter({
|
|
12401
13323
|
middlewares: [
|
|
12402
13324
|
createDeduplicationMiddleware(),
|
|
@@ -12421,10 +13343,10 @@ var start = async (config) => {
|
|
|
12421
13343
|
error: err instanceof Error ? err.message : String(err)
|
|
12422
13344
|
});
|
|
12423
13345
|
}
|
|
12424
|
-
(0,
|
|
13346
|
+
(0, import_core58.setEvalRunService)(evalRunner);
|
|
12425
13347
|
try {
|
|
12426
|
-
const menuStore = (0,
|
|
12427
|
-
(0,
|
|
13348
|
+
const menuStore = (0, import_core59.getStoreLattice)("default", "menu").store;
|
|
13349
|
+
(0, import_core58.setMenuRegistry)(menuStore);
|
|
12428
13350
|
logger5.info("Menu registry initialized");
|
|
12429
13351
|
} catch {
|
|
12430
13352
|
}
|
|
@@ -12433,17 +13355,17 @@ var start = async (config) => {
|
|
|
12433
13355
|
setChannelControllerDeps({ adapterRegistry, router: channelDeps.router });
|
|
12434
13356
|
}
|
|
12435
13357
|
registerLatticeRoutes(app, channelDeps);
|
|
12436
|
-
if (!
|
|
12437
|
-
|
|
13358
|
+
if (!import_core59.sandboxLatticeManager.hasLattice("default")) {
|
|
13359
|
+
import_core59.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
|
|
12438
13360
|
logger5.info("Registered sandbox manager from env configuration");
|
|
12439
13361
|
}
|
|
12440
13362
|
try {
|
|
12441
13363
|
const { ResourceController: ResourceController2 } = await Promise.resolve().then(() => (init_resources(), resources_exports));
|
|
12442
|
-
const sharedResourceStore = (0,
|
|
12443
|
-
const cache = new
|
|
13364
|
+
const sharedResourceStore = (0, import_core59.getStoreLattice)("default", "sharedResource").store;
|
|
13365
|
+
const cache = new import_core59.TokenCache();
|
|
12444
13366
|
const resourceController = new ResourceController2({
|
|
12445
13367
|
store: sharedResourceStore,
|
|
12446
|
-
sandboxManager:
|
|
13368
|
+
sandboxManager: import_core59.sandboxLatticeManager,
|
|
12447
13369
|
cache,
|
|
12448
13370
|
logger: logger5
|
|
12449
13371
|
});
|
|
@@ -12470,11 +13392,6 @@ var start = async (config) => {
|
|
|
12470
13392
|
const target_port = config?.port || Number(process.env.PORT) || 4001;
|
|
12471
13393
|
await app.listen({ port: target_port, host: "0.0.0.0" });
|
|
12472
13394
|
logger5.info(`Lattice Gateway is running on port: ${target_port}`);
|
|
12473
|
-
try {
|
|
12474
|
-
logger5.info("AgentLifecycleManager initialized");
|
|
12475
|
-
} catch (error) {
|
|
12476
|
-
logger5.warn("Failed to initialize AgentLifecycleManager", { error });
|
|
12477
|
-
}
|
|
12478
13395
|
const queueServiceConfig = config?.queueServiceConfig;
|
|
12479
13396
|
if (queueServiceConfig) {
|
|
12480
13397
|
setQueueServiceType(queueServiceConfig.type);
|
|
@@ -12484,7 +13401,7 @@ var start = async (config) => {
|
|
|
12484
13401
|
}
|
|
12485
13402
|
}
|
|
12486
13403
|
if (process.env.AXIOM_RESTORE_PENDING_ON_STARTUP === "true") {
|
|
12487
|
-
|
|
13404
|
+
import_core59.agentInstanceManager.restore().then((stats) => {
|
|
12488
13405
|
logger5.info(`Agent recovery complete: ${stats.restored} threads restored, ${stats.errors} errors`);
|
|
12489
13406
|
}).catch((error) => {
|
|
12490
13407
|
logger5.error("Agent recovery failed", { error });
|