@axiom-lattice/gateway 2.1.116 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +15 -15
- package/CHANGELOG.md +37 -0
- package/dist/{a2a-ERG5RMUW.mjs → a2a-QMHEH3ZT.mjs} +77 -29
- package/dist/a2a-QMHEH3ZT.mjs.map +1 -0
- package/dist/index.js +1144 -177
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1013 -92
- 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/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 +2 -10
- 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 +27 -0
- package/src/routes/stt.ts +102 -0
- package/src/services/__tests__/local-a2a.test.ts +124 -0
- package/src/services/eval-runner.ts +6 -0
- package/src/services/local-a2a.ts +352 -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,374 @@ 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
|
+
}
|
|
2084
|
+
function resolveLocalA2AWorkingDirectory(options) {
|
|
2085
|
+
if (options.envWorkdir) return options.envWorkdir;
|
|
2086
|
+
if (options.commandCwd) return options.commandCwd;
|
|
2087
|
+
return findWorkspaceRoot(options.currentCwd) || options.currentCwd;
|
|
2088
|
+
}
|
|
2089
|
+
function validateWorkingDirectory(cwd) {
|
|
2090
|
+
try {
|
|
2091
|
+
const stat2 = (0, import_node_fs.statSync)(cwd);
|
|
2092
|
+
if (!stat2.isDirectory()) {
|
|
2093
|
+
return `Working directory is not a directory: ${cwd}`;
|
|
2094
|
+
}
|
|
2095
|
+
return null;
|
|
2096
|
+
} catch (error) {
|
|
2097
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2098
|
+
return `Working directory is not accessible: ${cwd} (${message})`;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
function appendStderrTail(current, chunk) {
|
|
2102
|
+
const next = `${current}${chunk}`;
|
|
2103
|
+
if (next.length <= STDERR_TAIL_LIMIT) return next;
|
|
2104
|
+
return next.slice(-STDERR_TAIL_LIMIT);
|
|
2105
|
+
}
|
|
2106
|
+
function formatExitMessage(exitReason, stderrTail) {
|
|
2107
|
+
const stderr = stderrTail.trim();
|
|
2108
|
+
return stderr ? `Exited before becoming ready (${exitReason}): ${stderr}` : `Exited before becoming ready (${exitReason})`;
|
|
2109
|
+
}
|
|
2110
|
+
async function probeReady(agentCardUrl, healthUrl, timeoutMs) {
|
|
2111
|
+
const controller = new AbortController();
|
|
2112
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2113
|
+
try {
|
|
2114
|
+
if (healthUrl) {
|
|
2115
|
+
const resp = await fetch(healthUrl, { signal: controller.signal });
|
|
2116
|
+
if (!resp.ok) return false;
|
|
2117
|
+
}
|
|
2118
|
+
const cardResp = await fetch(agentCardUrl, { signal: controller.signal });
|
|
2119
|
+
return cardResp.ok;
|
|
2120
|
+
} catch {
|
|
2121
|
+
return false;
|
|
2122
|
+
} finally {
|
|
2123
|
+
clearTimeout(timer);
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
var _LocalA2AService = class _LocalA2AService {
|
|
2127
|
+
constructor() {
|
|
2128
|
+
this.states = /* @__PURE__ */ new Map();
|
|
2129
|
+
this.autoStartEnabled = readBooleanEnv("LOCAL_A2A_AUTO_START", true);
|
|
2130
|
+
}
|
|
2131
|
+
static getInstance() {
|
|
2132
|
+
if (!_LocalA2AService.instance) {
|
|
2133
|
+
_LocalA2AService.instance = new _LocalA2AService();
|
|
2134
|
+
}
|
|
2135
|
+
return _LocalA2AService.instance;
|
|
2136
|
+
}
|
|
2137
|
+
getOrCreateState(runtimeId, localRuntime) {
|
|
2138
|
+
let state = this.states.get(runtimeId);
|
|
2139
|
+
if (!state) {
|
|
2140
|
+
state = {
|
|
2141
|
+
runtimeId,
|
|
2142
|
+
label: localRuntime.label || runtimeId,
|
|
2143
|
+
status: this.autoStartEnabled ? "stopped" : "disabled",
|
|
2144
|
+
enabled: this.autoStartEnabled,
|
|
2145
|
+
assistantId: runtimeId,
|
|
2146
|
+
agentCardUrl: localRuntime.agentCardUrl,
|
|
2147
|
+
healthUrl: localRuntime.healthUrl,
|
|
2148
|
+
localRuntime
|
|
2149
|
+
};
|
|
2150
|
+
this.states.set(runtimeId, state);
|
|
2151
|
+
} else {
|
|
2152
|
+
state.localRuntime = localRuntime;
|
|
2153
|
+
state.label = localRuntime.label || state.label;
|
|
2154
|
+
state.agentCardUrl = localRuntime.agentCardUrl;
|
|
2155
|
+
state.healthUrl = localRuntime.healthUrl;
|
|
2156
|
+
}
|
|
2157
|
+
return state;
|
|
2158
|
+
}
|
|
2159
|
+
async getRegisteredState(runtimeId, localRuntime) {
|
|
2160
|
+
const state = this.getOrCreateState(runtimeId, localRuntime);
|
|
2161
|
+
if (state.process && state.status === "running") {
|
|
2162
|
+
const alive = await probeReady(
|
|
2163
|
+
localRuntime.agentCardUrl,
|
|
2164
|
+
localRuntime.healthUrl,
|
|
2165
|
+
2e3
|
|
2166
|
+
);
|
|
2167
|
+
if (!alive) {
|
|
2168
|
+
state.process = void 0;
|
|
2169
|
+
state.pid = void 0;
|
|
2170
|
+
state.status = "stopped";
|
|
2171
|
+
state.message = "Process exited unexpectedly";
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
return this.snapshotState(state);
|
|
2175
|
+
}
|
|
2176
|
+
async startProvider(runtimeId, localRuntime) {
|
|
2177
|
+
const state = this.getOrCreateState(runtimeId, localRuntime);
|
|
2178
|
+
if (!state.enabled) {
|
|
2179
|
+
state.status = "disabled";
|
|
2180
|
+
state.message = "Disabled by configuration";
|
|
2181
|
+
return this.snapshotState(state);
|
|
2182
|
+
}
|
|
2183
|
+
if (state.process && state.status === "running") {
|
|
2184
|
+
return this.snapshotState(state);
|
|
2185
|
+
}
|
|
2186
|
+
state.enabled = true;
|
|
2187
|
+
const { executable, args, cwd, env: cmdEnv } = localRuntime.command;
|
|
2188
|
+
const resolvedCwd = resolveLocalA2AWorkingDirectory({
|
|
2189
|
+
envWorkdir: process.env.LOCAL_A2A_WORKDIR || void 0,
|
|
2190
|
+
commandCwd: cwd,
|
|
2191
|
+
currentCwd: process.cwd()
|
|
2192
|
+
});
|
|
2193
|
+
const cwdError = validateWorkingDirectory(resolvedCwd);
|
|
2194
|
+
if (cwdError) {
|
|
2195
|
+
state.process = void 0;
|
|
2196
|
+
state.pid = void 0;
|
|
2197
|
+
state.status = "failed";
|
|
2198
|
+
state.message = cwdError;
|
|
2199
|
+
return this.snapshotState(state);
|
|
2200
|
+
}
|
|
2201
|
+
state.status = "starting";
|
|
2202
|
+
state.message = "Starting";
|
|
2203
|
+
let stderrTail = "";
|
|
2204
|
+
const childEnv = cmdEnv ? { ...process.env, ...cmdEnv } : process.env;
|
|
2205
|
+
const child = (0, import_node_child_process.spawn)(executable, args, {
|
|
2206
|
+
cwd: resolvedCwd,
|
|
2207
|
+
env: childEnv,
|
|
2208
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2209
|
+
shell: false
|
|
2210
|
+
});
|
|
2211
|
+
state.process = child;
|
|
2212
|
+
state.pid = child.pid ?? void 0;
|
|
2213
|
+
child.once("error", (error) => {
|
|
2214
|
+
const current = this.states.get(runtimeId);
|
|
2215
|
+
if (!current) return;
|
|
2216
|
+
current.process = void 0;
|
|
2217
|
+
current.pid = void 0;
|
|
2218
|
+
current.status = "failed";
|
|
2219
|
+
const stderr = stderrTail.trim();
|
|
2220
|
+
current.message = stderr ? `Failed to start: ${error.message}: ${stderr}` : `Failed to start: ${error.message}`;
|
|
2221
|
+
});
|
|
2222
|
+
child.stdout.on("data", (chunk) => {
|
|
2223
|
+
const text = chunk.toString("utf8").trim();
|
|
2224
|
+
if (text) console.log(`[local-a2a:${runtimeId}] ${text}`);
|
|
2225
|
+
});
|
|
2226
|
+
child.stderr.on("data", (chunk) => {
|
|
2227
|
+
const rawText = chunk.toString("utf8");
|
|
2228
|
+
stderrTail = appendStderrTail(stderrTail, rawText);
|
|
2229
|
+
const text = rawText.trim();
|
|
2230
|
+
if (text) console.error(`[local-a2a:${runtimeId}] ${text}`);
|
|
2231
|
+
});
|
|
2232
|
+
child.on("close", (code, signal) => {
|
|
2233
|
+
const current = this.states.get(runtimeId);
|
|
2234
|
+
if (!current) return;
|
|
2235
|
+
current.process = void 0;
|
|
2236
|
+
current.pid = void 0;
|
|
2237
|
+
const exitReason = signal ?? code ?? "unknown";
|
|
2238
|
+
if (current.status === "running") {
|
|
2239
|
+
current.status = "stopped";
|
|
2240
|
+
current.message = `Stopped (${exitReason})`;
|
|
2241
|
+
} else if (current.status === "starting") {
|
|
2242
|
+
current.status = "failed";
|
|
2243
|
+
current.message = formatExitMessage(exitReason, stderrTail);
|
|
2244
|
+
}
|
|
2245
|
+
});
|
|
2246
|
+
const ready = await this.waitUntilReady(localRuntime, state, 15e3);
|
|
2247
|
+
if (!ready) {
|
|
2248
|
+
if (state.process) {
|
|
2249
|
+
state.process.kill("SIGTERM");
|
|
2250
|
+
}
|
|
2251
|
+
state.process = void 0;
|
|
2252
|
+
state.pid = void 0;
|
|
2253
|
+
if (state.status !== "failed") {
|
|
2254
|
+
state.status = "failed";
|
|
2255
|
+
state.message = "Server did not become ready";
|
|
2256
|
+
}
|
|
2257
|
+
return this.snapshotState(state);
|
|
2258
|
+
}
|
|
2259
|
+
state.status = "running";
|
|
2260
|
+
state.message = "Running";
|
|
2261
|
+
state.lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2262
|
+
return this.snapshotState(state);
|
|
2263
|
+
}
|
|
2264
|
+
async stopProvider(runtimeId) {
|
|
2265
|
+
const state = this.states.get(runtimeId);
|
|
2266
|
+
if (!state) {
|
|
2267
|
+
return this.emptyState(runtimeId);
|
|
2268
|
+
}
|
|
2269
|
+
const child = state.process;
|
|
2270
|
+
if (child) {
|
|
2271
|
+
child.kill("SIGTERM");
|
|
2272
|
+
await (0, import_promises.setTimeout)(750);
|
|
2273
|
+
if (child.exitCode === null) {
|
|
2274
|
+
child.kill("SIGKILL");
|
|
2275
|
+
}
|
|
2276
|
+
state.process = void 0;
|
|
2277
|
+
}
|
|
2278
|
+
state.pid = void 0;
|
|
2279
|
+
state.status = "stopped";
|
|
2280
|
+
state.message = "Stopped";
|
|
2281
|
+
state.lastStoppedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2282
|
+
return this.snapshotState(state);
|
|
2283
|
+
}
|
|
2284
|
+
async restartProvider(runtimeId, localRuntime) {
|
|
2285
|
+
await this.stopProvider(runtimeId);
|
|
2286
|
+
return this.startProvider(runtimeId, localRuntime);
|
|
2287
|
+
}
|
|
2288
|
+
removeState(runtimeId) {
|
|
2289
|
+
const state = this.states.get(runtimeId);
|
|
2290
|
+
if (state?.process) {
|
|
2291
|
+
state.process.kill("SIGTERM");
|
|
2292
|
+
state.process = void 0;
|
|
2293
|
+
}
|
|
2294
|
+
this.states.delete(runtimeId);
|
|
2295
|
+
}
|
|
2296
|
+
async waitUntilReady(localRuntime, state, timeoutMs) {
|
|
2297
|
+
const start2 = Date.now();
|
|
2298
|
+
while (Date.now() - start2 < timeoutMs) {
|
|
2299
|
+
if (state.status === "failed") return false;
|
|
2300
|
+
if (await probeReady(localRuntime.agentCardUrl, localRuntime.healthUrl, 1500)) {
|
|
2301
|
+
return true;
|
|
2302
|
+
}
|
|
2303
|
+
await (0, import_promises.setTimeout)(500);
|
|
2304
|
+
}
|
|
2305
|
+
return false;
|
|
2306
|
+
}
|
|
2307
|
+
emptyState(runtimeId) {
|
|
2308
|
+
return {
|
|
2309
|
+
runtimeId,
|
|
2310
|
+
label: runtimeId,
|
|
2311
|
+
status: "stopped",
|
|
2312
|
+
enabled: false
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
snapshotState(state) {
|
|
2316
|
+
return {
|
|
2317
|
+
runtimeId: state.runtimeId,
|
|
2318
|
+
label: state.label,
|
|
2319
|
+
status: state.status,
|
|
2320
|
+
enabled: state.enabled,
|
|
2321
|
+
assistantId: state.assistantId,
|
|
2322
|
+
agentCardUrl: state.agentCardUrl,
|
|
2323
|
+
healthUrl: state.healthUrl,
|
|
2324
|
+
pid: state.pid,
|
|
2325
|
+
message: state.message,
|
|
2326
|
+
lastStartedAt: state.lastStartedAt,
|
|
2327
|
+
lastStoppedAt: state.lastStoppedAt
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
};
|
|
2331
|
+
_LocalA2AService.instance = null;
|
|
2332
|
+
var LocalA2AService = _LocalA2AService;
|
|
2333
|
+
var localA2AService = LocalA2AService.getInstance();
|
|
2334
|
+
|
|
2335
|
+
// src/utils/a2a-url.ts
|
|
2336
|
+
var AGENT_CARD_PATH = "/.well-known/agent-card.json";
|
|
2337
|
+
function normalizeA2AAgentCardUrl(value, defaultProtocol = "https://") {
|
|
2338
|
+
const raw = value?.trim() ?? "";
|
|
2339
|
+
if (!raw) return "";
|
|
2340
|
+
const withProtocol = /^https?:\/\//i.test(raw) ? raw : `${defaultProtocol}${raw.replace(/^\/+/, "")}`;
|
|
2341
|
+
const trimmed = withProtocol.replace(/\/+$/, "");
|
|
2342
|
+
if (trimmed.endsWith(AGENT_CARD_PATH)) {
|
|
2343
|
+
return trimmed;
|
|
2344
|
+
}
|
|
2345
|
+
return `${trimmed}${AGENT_CARD_PATH}`;
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
// src/utils/local-a2a-runtime.ts
|
|
2349
|
+
function validateLocalRuntimeCommand(localRuntime) {
|
|
2350
|
+
const runtime = localRuntime;
|
|
2351
|
+
const executable = runtime.command?.executable;
|
|
2352
|
+
if (typeof executable !== "string" || executable.trim().length === 0) {
|
|
2353
|
+
return {
|
|
2354
|
+
ok: false,
|
|
2355
|
+
error: "Local managed A2A command executable is required"
|
|
2356
|
+
};
|
|
2357
|
+
}
|
|
2358
|
+
const args = runtime.command?.args;
|
|
2359
|
+
if (!Array.isArray(args) || !args.every((arg) => typeof arg === "string")) {
|
|
2360
|
+
return {
|
|
2361
|
+
ok: false,
|
|
2362
|
+
error: "Local managed A2A command args must be an array of strings"
|
|
2363
|
+
};
|
|
2364
|
+
}
|
|
2365
|
+
return { ok: true };
|
|
2366
|
+
}
|
|
2367
|
+
function getAgentCardPort(agentCardUrl) {
|
|
2368
|
+
let url;
|
|
2369
|
+
try {
|
|
2370
|
+
url = new URL(agentCardUrl);
|
|
2371
|
+
} catch {
|
|
2372
|
+
return null;
|
|
2373
|
+
}
|
|
2374
|
+
if (url.port) {
|
|
2375
|
+
const port = Number(url.port);
|
|
2376
|
+
return Number.isInteger(port) ? port : null;
|
|
2377
|
+
}
|
|
2378
|
+
if (url.protocol === "http:") return 80;
|
|
2379
|
+
if (url.protocol === "https:") return 443;
|
|
2380
|
+
return null;
|
|
2381
|
+
}
|
|
2382
|
+
function parseCommandPort(args) {
|
|
2383
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
2384
|
+
const arg = args[index];
|
|
2385
|
+
const match = /^(--port|-p)(?:[=\s]+(\d+))?$/.exec(arg);
|
|
2386
|
+
if (!match) continue;
|
|
2387
|
+
const inlinePort = match[2];
|
|
2388
|
+
if (inlinePort) return Number(inlinePort);
|
|
2389
|
+
const nextArg = args[index + 1];
|
|
2390
|
+
if (nextArg && /^\d+$/.test(nextArg)) {
|
|
2391
|
+
return Number(nextArg);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
return null;
|
|
2395
|
+
}
|
|
2396
|
+
function isLoopbackHost(hostname) {
|
|
2397
|
+
const normalized = hostname.toLowerCase();
|
|
2398
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1" || normalized === "[::1]";
|
|
2399
|
+
}
|
|
2400
|
+
function validateLocalRuntimePort(localRuntime, agentCardUrl) {
|
|
2401
|
+
let url;
|
|
2402
|
+
try {
|
|
2403
|
+
url = new URL(agentCardUrl);
|
|
2404
|
+
} catch {
|
|
2405
|
+
return { ok: true };
|
|
2406
|
+
}
|
|
2407
|
+
if (!isLoopbackHost(url.hostname) || !url.port) {
|
|
2408
|
+
return { ok: true };
|
|
2409
|
+
}
|
|
2410
|
+
const commandPort = parseCommandPort(localRuntime.command.args);
|
|
2411
|
+
if (commandPort === null) {
|
|
2412
|
+
return { ok: true };
|
|
2413
|
+
}
|
|
2414
|
+
const agentCardPort = Number(url.port);
|
|
2415
|
+
if (commandPort === agentCardPort) {
|
|
2416
|
+
return { ok: true };
|
|
2417
|
+
}
|
|
2418
|
+
return {
|
|
2419
|
+
ok: false,
|
|
2420
|
+
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.`
|
|
2421
|
+
};
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
// src/controllers/assistant.ts
|
|
2010
2425
|
function getTenantId(request) {
|
|
2011
2426
|
const userTenantId = request.user?.tenantId;
|
|
2012
2427
|
if (userTenantId) {
|
|
@@ -2136,6 +2551,79 @@ async function createAssistant(request, reply) {
|
|
|
2136
2551
|
});
|
|
2137
2552
|
}
|
|
2138
2553
|
const id = data.id ?? (0, import_crypto.randomUUID)();
|
|
2554
|
+
if (data.graphDefinition && data.graphDefinition.type === import_protocols.AgentType.A2A_REMOTE) {
|
|
2555
|
+
const a2aConfig = data.graphDefinition;
|
|
2556
|
+
const warnings = [];
|
|
2557
|
+
const isLocalManaged = !!a2aConfig.localRuntime;
|
|
2558
|
+
a2aConfig.agentCardUrl = normalizeA2AAgentCardUrl(
|
|
2559
|
+
a2aConfig.agentCardUrl,
|
|
2560
|
+
isLocalManaged ? "http://" : "https://"
|
|
2561
|
+
);
|
|
2562
|
+
if (a2aConfig.localRuntime) {
|
|
2563
|
+
const commandValidation = validateLocalRuntimeCommand(
|
|
2564
|
+
a2aConfig.localRuntime
|
|
2565
|
+
);
|
|
2566
|
+
if (!commandValidation.ok) {
|
|
2567
|
+
return reply.status(400).send({
|
|
2568
|
+
success: false,
|
|
2569
|
+
message: commandValidation.error
|
|
2570
|
+
});
|
|
2571
|
+
}
|
|
2572
|
+
a2aConfig.localRuntime.command.executable = a2aConfig.localRuntime.command.executable.trim();
|
|
2573
|
+
a2aConfig.localRuntime.agentCardUrl = normalizeA2AAgentCardUrl(
|
|
2574
|
+
a2aConfig.localRuntime.agentCardUrl || a2aConfig.agentCardUrl,
|
|
2575
|
+
"http://"
|
|
2576
|
+
);
|
|
2577
|
+
a2aConfig.agentCardUrl = a2aConfig.localRuntime.agentCardUrl;
|
|
2578
|
+
const portValidation = validateLocalRuntimePort(
|
|
2579
|
+
a2aConfig.localRuntime,
|
|
2580
|
+
a2aConfig.agentCardUrl
|
|
2581
|
+
);
|
|
2582
|
+
if (!portValidation.ok) {
|
|
2583
|
+
return reply.status(400).send({
|
|
2584
|
+
success: false,
|
|
2585
|
+
message: portValidation.error
|
|
2586
|
+
});
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
if (a2aConfig.localRuntime) {
|
|
2590
|
+
const existingAssistants = await (0, import_core.getStoreLattice)("default", "assistant").store.getAllAssistants(tenantId);
|
|
2591
|
+
const targetPort = getAgentCardPort(a2aConfig.localRuntime.agentCardUrl);
|
|
2592
|
+
const duplicate = existingAssistants.find((a) => {
|
|
2593
|
+
if (a.id === id) return false;
|
|
2594
|
+
const gd = a.graphDefinition && typeof a.graphDefinition === "object" ? a.graphDefinition : void 0;
|
|
2595
|
+
if (!gd || gd.type !== import_protocols.AgentType.A2A_REMOTE) return false;
|
|
2596
|
+
const lr = gd.localRuntime;
|
|
2597
|
+
if (!lr) return false;
|
|
2598
|
+
const existingAgentCardUrl = normalizeA2AAgentCardUrl(lr.agentCardUrl, "http://");
|
|
2599
|
+
const existingPort = getAgentCardPort(existingAgentCardUrl);
|
|
2600
|
+
if (targetPort !== null && existingPort !== null) {
|
|
2601
|
+
return existingPort === targetPort;
|
|
2602
|
+
}
|
|
2603
|
+
return existingAgentCardUrl === a2aConfig.localRuntime.agentCardUrl;
|
|
2604
|
+
});
|
|
2605
|
+
if (duplicate) {
|
|
2606
|
+
const conflictDetail = targetPort === null ? `agentCardUrl "${a2aConfig.localRuntime.agentCardUrl}"` : `port ${targetPort}`;
|
|
2607
|
+
return reply.status(409).send({
|
|
2608
|
+
success: false,
|
|
2609
|
+
message: `A local managed A2A assistant using ${conflictDetail} already exists: "${duplicate.name}". Each local managed A2A assistant needs a unique port.`
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
try {
|
|
2614
|
+
const resp = await fetch(a2aConfig.agentCardUrl, {
|
|
2615
|
+
signal: AbortSignal.timeout(5e3)
|
|
2616
|
+
});
|
|
2617
|
+
if (!resp.ok) {
|
|
2618
|
+
warnings.push(`agentCardUrl returned HTTP ${resp.status}`);
|
|
2619
|
+
}
|
|
2620
|
+
} catch {
|
|
2621
|
+
warnings.push(`agentCardUrl is not reachable: ${a2aConfig.agentCardUrl}`);
|
|
2622
|
+
}
|
|
2623
|
+
if (warnings.length > 0) {
|
|
2624
|
+
console.warn(`[createAssistant] A2A warnings for ${a2aConfig.agentCardUrl}:`, warnings);
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2139
2627
|
return upsertAssistant(tenantId, id, data, reply, true);
|
|
2140
2628
|
}
|
|
2141
2629
|
async function updateAssistant(request, reply) {
|
|
@@ -2149,11 +2637,28 @@ async function deleteAssistant(request, reply) {
|
|
|
2149
2637
|
const { id } = request.params;
|
|
2150
2638
|
const storeLattice = (0, import_core.getStoreLattice)("default", "assistant");
|
|
2151
2639
|
const assistantStore = storeLattice.store;
|
|
2640
|
+
const storedAssistant = await assistantStore.getAssistantById(tenantId, id);
|
|
2641
|
+
const graphDefinition = storedAssistant?.graphDefinition;
|
|
2642
|
+
const hasLocalRuntime = graphDefinition && typeof graphDefinition === "object" ? !!graphDefinition.localRuntime : false;
|
|
2643
|
+
if (storedAssistant && hasLocalRuntime) {
|
|
2644
|
+
localA2AService.removeState(id);
|
|
2645
|
+
const deleted2 = await assistantStore.deleteAssistant(tenantId, id);
|
|
2646
|
+
if (!deleted2) {
|
|
2647
|
+
return reply.status(500).send({
|
|
2648
|
+
success: false,
|
|
2649
|
+
message: "Failed to delete assistant"
|
|
2650
|
+
});
|
|
2651
|
+
}
|
|
2652
|
+
import_core2.eventBus.publish("assistant:deleted", { id, tenantId });
|
|
2653
|
+
return {
|
|
2654
|
+
success: true,
|
|
2655
|
+
message: "Deleted local A2A assistant"
|
|
2656
|
+
};
|
|
2657
|
+
}
|
|
2152
2658
|
const agentConfig = await import_core2.agentLatticeManager.getAgentConfigWithTenant(tenantId, id);
|
|
2153
2659
|
const isCodeConfigured = !!agentConfig;
|
|
2154
2660
|
if (isCodeConfigured) {
|
|
2155
|
-
|
|
2156
|
-
if (!exists2) {
|
|
2661
|
+
if (!storedAssistant) {
|
|
2157
2662
|
return reply.status(404).send({
|
|
2158
2663
|
success: false,
|
|
2159
2664
|
message: "Assistant not found (code-configured assistants cannot be deleted from code, only from store)"
|
|
@@ -2166,8 +2671,7 @@ async function deleteAssistant(request, reply) {
|
|
|
2166
2671
|
message: "Deleted assistant from store (code-configured registration remains)"
|
|
2167
2672
|
};
|
|
2168
2673
|
}
|
|
2169
|
-
|
|
2170
|
-
if (!exists) {
|
|
2674
|
+
if (!storedAssistant) {
|
|
2171
2675
|
return reply.status(404).send({
|
|
2172
2676
|
success: false,
|
|
2173
2677
|
message: "Assistant not found"
|
|
@@ -2221,7 +2725,7 @@ var getAgentGraph = async (request, reply) => {
|
|
|
2221
2725
|
// src/controllers/run.ts
|
|
2222
2726
|
var import_uuid = require("uuid");
|
|
2223
2727
|
var import_core3 = require("@axiom-lattice/core");
|
|
2224
|
-
var
|
|
2728
|
+
var import_protocols2 = require("@axiom-lattice/protocols");
|
|
2225
2729
|
function getUserId2(request) {
|
|
2226
2730
|
const authUser = request.user;
|
|
2227
2731
|
if (authUser?.id) return authUser.id;
|
|
@@ -2293,13 +2797,13 @@ var createRun = async (request, reply) => {
|
|
|
2293
2797
|
command,
|
|
2294
2798
|
custom_run_config: mergedConfig
|
|
2295
2799
|
}, mode);
|
|
2296
|
-
const stream = agent.chunkStream(result.messageId, [
|
|
2800
|
+
const stream = agent.chunkStream(result.messageId, [import_protocols2.MessageChunkTypes.MESSAGE_COMPLETED, import_protocols2.MessageChunkTypes.INTERRUPT, import_protocols2.MessageChunkTypes.MESSAGE_FAILED]);
|
|
2297
2801
|
for await (const chunk of stream) {
|
|
2298
2802
|
const success = reply.raw.write(`data: ${JSON.stringify(chunk)}
|
|
2299
2803
|
|
|
2300
2804
|
`);
|
|
2301
2805
|
if (!success) {
|
|
2302
|
-
await new Promise((
|
|
2806
|
+
await new Promise((resolve3) => reply.raw.once("drain", resolve3));
|
|
2303
2807
|
}
|
|
2304
2808
|
}
|
|
2305
2809
|
} catch (error) {
|
|
@@ -3077,7 +3581,7 @@ var configService = new ConfigService();
|
|
|
3077
3581
|
|
|
3078
3582
|
// src/services/queue_service.ts
|
|
3079
3583
|
var import_core8 = require("@axiom-lattice/core");
|
|
3080
|
-
var
|
|
3584
|
+
var import_protocols3 = require("@axiom-lattice/protocols");
|
|
3081
3585
|
var import_queue_redis = require("@axiom-lattice/queue-redis");
|
|
3082
3586
|
var DEFAULT_QUEUE_KEY = "default";
|
|
3083
3587
|
var queueServiceType = process.env.QUEUE_SERVICE_TYPE || "memory";
|
|
@@ -3088,7 +3592,7 @@ var setQueueServiceType = (type) => {
|
|
|
3088
3592
|
const config = {
|
|
3089
3593
|
name: "Default Queue Service",
|
|
3090
3594
|
description: `Default ${type} queue service`,
|
|
3091
|
-
type: type === "redis" ?
|
|
3595
|
+
type: type === "redis" ? import_protocols3.QueueType.REDIS : import_protocols3.QueueType.MEMORY,
|
|
3092
3596
|
queueName,
|
|
3093
3597
|
options: type === "redis" ? {
|
|
3094
3598
|
redisUrl: process.env.REDIS_URL,
|
|
@@ -4216,7 +4720,7 @@ async function executeSqlQuery(client, body, reply) {
|
|
|
4216
4720
|
|
|
4217
4721
|
// src/controllers/workflow-tracking.ts
|
|
4218
4722
|
var import_core15 = require("@axiom-lattice/core");
|
|
4219
|
-
var
|
|
4723
|
+
var import_protocols4 = require("@axiom-lattice/protocols");
|
|
4220
4724
|
function getTenantId7(request) {
|
|
4221
4725
|
const userTenantId = request.user?.tenantId;
|
|
4222
4726
|
if (userTenantId) return userTenantId;
|
|
@@ -4660,7 +5164,7 @@ async function replyInboxTask(request, reply) {
|
|
|
4660
5164
|
}).then((result) => {
|
|
4661
5165
|
const stream = agent.chunkStream(
|
|
4662
5166
|
result.messageId,
|
|
4663
|
-
[
|
|
5167
|
+
[import_protocols4.MessageChunkTypes.MESSAGE_COMPLETED]
|
|
4664
5168
|
);
|
|
4665
5169
|
(async () => {
|
|
4666
5170
|
for await (const _ of stream) {
|
|
@@ -4877,15 +5381,14 @@ function getStore() {
|
|
|
4877
5381
|
async function listTasks(request, reply) {
|
|
4878
5382
|
try {
|
|
4879
5383
|
const tenantId = getTenantId9(request);
|
|
4880
|
-
const userId = getUserId4(request);
|
|
4881
5384
|
const query = request.query;
|
|
4882
5385
|
const store2 = getStore();
|
|
4883
5386
|
const tasks = await store2.list({
|
|
4884
5387
|
tenantId,
|
|
4885
|
-
ownerId: query.ownerId || userId,
|
|
4886
5388
|
status: query.status,
|
|
4887
5389
|
priority: query.priority,
|
|
4888
|
-
|
|
5390
|
+
...query.ownerId && { ownerId: query.ownerId },
|
|
5391
|
+
...query.ownerType && { ownerType: query.ownerType },
|
|
4889
5392
|
metadata: query.metadata ? JSON.parse(query.metadata) : void 0,
|
|
4890
5393
|
projectId: query.projectId,
|
|
4891
5394
|
limit: query.limit ? parseInt(query.limit) : void 0,
|
|
@@ -6021,13 +6524,42 @@ function registerSandboxProxyRoutes(app2) {
|
|
|
6021
6524
|
}
|
|
6022
6525
|
|
|
6023
6526
|
// src/controllers/workspace.ts
|
|
6024
|
-
var
|
|
6025
|
-
var
|
|
6527
|
+
var fs2 = __toESM(require("fs/promises"));
|
|
6528
|
+
var path2 = __toESM(require("path"));
|
|
6529
|
+
var os = __toESM(require("os"));
|
|
6026
6530
|
var import_core24 = require("@axiom-lattice/core");
|
|
6027
6531
|
var import_core25 = require("@axiom-lattice/core");
|
|
6028
6532
|
var import_core26 = require("@axiom-lattice/core");
|
|
6029
6533
|
var import_uuid3 = require("uuid");
|
|
6030
6534
|
init_mime();
|
|
6535
|
+
|
|
6536
|
+
// src/utils/path-containment.ts
|
|
6537
|
+
var fs = __toESM(require("fs/promises"));
|
|
6538
|
+
var path = __toESM(require("path"));
|
|
6539
|
+
var PathOutsideRootError = class extends Error {
|
|
6540
|
+
constructor(rootPath, targetPath) {
|
|
6541
|
+
super(`Path is outside the allowed root: ${targetPath}`);
|
|
6542
|
+
this.rootPath = rootPath;
|
|
6543
|
+
this.targetPath = targetPath;
|
|
6544
|
+
this.name = "PathOutsideRootError";
|
|
6545
|
+
}
|
|
6546
|
+
};
|
|
6547
|
+
function isPathWithinRoot(rootPath, targetPath) {
|
|
6548
|
+
const relative2 = path.relative(rootPath, targetPath);
|
|
6549
|
+
return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${path.sep}`) && !path.isAbsolute(relative2);
|
|
6550
|
+
}
|
|
6551
|
+
async function resolvePathWithinRoot(rootPath, targetPath) {
|
|
6552
|
+
const [resolvedRoot, resolvedTarget] = await Promise.all([
|
|
6553
|
+
fs.realpath(rootPath),
|
|
6554
|
+
fs.realpath(targetPath)
|
|
6555
|
+
]);
|
|
6556
|
+
if (!isPathWithinRoot(resolvedRoot, resolvedTarget)) {
|
|
6557
|
+
throw new PathOutsideRootError(resolvedRoot, resolvedTarget);
|
|
6558
|
+
}
|
|
6559
|
+
return { rootPath: resolvedRoot, targetPath: resolvedTarget };
|
|
6560
|
+
}
|
|
6561
|
+
|
|
6562
|
+
// src/controllers/workspace.ts
|
|
6031
6563
|
var WorkspaceController = class {
|
|
6032
6564
|
constructor() {
|
|
6033
6565
|
this.workspaceStore = (0, import_core24.getStoreLattice)("default", "workspace").store;
|
|
@@ -6188,16 +6720,23 @@ var WorkspaceController = class {
|
|
|
6188
6720
|
}),
|
|
6189
6721
|
workspace
|
|
6190
6722
|
};
|
|
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
6723
|
}
|
|
6724
|
+
const rootDir = await this.getFilesystemRootDirectory(
|
|
6725
|
+
tenantId,
|
|
6726
|
+
workspaceId,
|
|
6727
|
+
projectId
|
|
6728
|
+
);
|
|
6729
|
+
console.log(`[getBackend] using FilesystemBackend rootDir=${rootDir}`);
|
|
6730
|
+
return {
|
|
6731
|
+
backend: new import_core25.FilesystemBackend({
|
|
6732
|
+
rootDir,
|
|
6733
|
+
virtualMode: true
|
|
6734
|
+
}),
|
|
6735
|
+
workspace
|
|
6736
|
+
};
|
|
6737
|
+
}
|
|
6738
|
+
async getFilesystemRootDirectory(tenantId, workspaceId, projectId) {
|
|
6739
|
+
return `/lattice_store/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`;
|
|
6201
6740
|
}
|
|
6202
6741
|
isBinaryContentType(filename) {
|
|
6203
6742
|
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
@@ -6386,21 +6925,21 @@ var WorkspaceController = class {
|
|
|
6386
6925
|
async listPath(request) {
|
|
6387
6926
|
const tenantId = this.getTenantId(request);
|
|
6388
6927
|
const { workspaceId, projectId } = request.params;
|
|
6389
|
-
const
|
|
6928
|
+
const path4 = request.query.path || "/";
|
|
6390
6929
|
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(
|
|
6930
|
+
console.log(`[listPath] tenantId=${tenantId} workspaceId=${workspaceId} projectId=${projectId} path=${path4} assistantId=${assistantId}`);
|
|
6931
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path4);
|
|
6932
|
+
console.log(`[listPath] backend type=${backend.constructor.name} calling lsInfo(${path4})`);
|
|
6933
|
+
const files = await backend.lsInfo(path4);
|
|
6395
6934
|
console.log(`[listPath] result count=${files.length}`);
|
|
6396
6935
|
return { success: true, data: files };
|
|
6397
6936
|
}
|
|
6398
6937
|
async readFile(request) {
|
|
6399
6938
|
const tenantId = this.getTenantId(request);
|
|
6400
6939
|
const { workspaceId, projectId } = request.params;
|
|
6401
|
-
const { path:
|
|
6402
|
-
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId,
|
|
6403
|
-
const content = await backend.read(
|
|
6940
|
+
const { path: path4, offset = 0, limit = 1e3, assistantId } = request.query;
|
|
6941
|
+
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, path4);
|
|
6942
|
+
const content = await backend.read(path4, Number(offset), Number(limit));
|
|
6404
6943
|
return { success: true, data: { content, offset, limit } };
|
|
6405
6944
|
}
|
|
6406
6945
|
/**
|
|
@@ -6412,7 +6951,7 @@ var WorkspaceController = class {
|
|
|
6412
6951
|
* - `path`: optional directory path relative to project root (e.g., "docs", "src/utils")
|
|
6413
6952
|
* - `assistantId`: optional query parameter for sandbox identity matching
|
|
6414
6953
|
* For sandbox storage, delegates to the sandbox upload API.
|
|
6415
|
-
* For filesystem storage, writes
|
|
6954
|
+
* For filesystem storage, writes under the same project root used by the file backend.
|
|
6416
6955
|
*/
|
|
6417
6956
|
async uploadFile(request, reply) {
|
|
6418
6957
|
const tenantId = this.getTenantId(request);
|
|
@@ -6446,7 +6985,7 @@ var WorkspaceController = class {
|
|
|
6446
6985
|
workspaceId,
|
|
6447
6986
|
projectId
|
|
6448
6987
|
};
|
|
6449
|
-
const realPath = pathValue ?
|
|
6988
|
+
const realPath = pathValue ? path2.posix.join(pathValue, filename) : path2.posix.join("/project/uploads", filename);
|
|
6450
6989
|
const isBinary = this.isBinaryContentType(filename);
|
|
6451
6990
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, realPath);
|
|
6452
6991
|
if (volumeBackend && !isBinary) {
|
|
@@ -6457,7 +6996,7 @@ var WorkspaceController = class {
|
|
|
6457
6996
|
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
6458
6997
|
await sandbox.file.uploadFile({ file: realPath, data: buffer });
|
|
6459
6998
|
}
|
|
6460
|
-
const relativePath = pathValue ?
|
|
6999
|
+
const relativePath = pathValue ? path2.posix.join(pathValue, filename) : path2.posix.join("/project/uploads", filename);
|
|
6461
7000
|
const result2 = {
|
|
6462
7001
|
path: relativePath,
|
|
6463
7002
|
name: filename,
|
|
@@ -6467,14 +7006,43 @@ var WorkspaceController = class {
|
|
|
6467
7006
|
};
|
|
6468
7007
|
return reply.status(200).send({ success: true, data: result2 });
|
|
6469
7008
|
}
|
|
6470
|
-
const rootDir =
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
7009
|
+
const rootDir = await this.getFilesystemRootDirectory(
|
|
7010
|
+
tenantId,
|
|
7011
|
+
workspaceId,
|
|
7012
|
+
projectId
|
|
7013
|
+
);
|
|
7014
|
+
await fs2.mkdir(rootDir, { recursive: true });
|
|
7015
|
+
const relativeDirectory = pathValue?.replace(/^[/\\]+/, "") || ".";
|
|
7016
|
+
const targetDir = path2.resolve(rootDir, relativeDirectory);
|
|
7017
|
+
if (!isPathWithinRoot(path2.resolve(rootDir), targetDir)) {
|
|
7018
|
+
return reply.status(400).send({
|
|
7019
|
+
success: false,
|
|
7020
|
+
error: "Upload path must stay within the project directory"
|
|
7021
|
+
});
|
|
7022
|
+
}
|
|
7023
|
+
await fs2.mkdir(targetDir, { recursive: true });
|
|
7024
|
+
const [resolvedRoot, resolvedTargetDir] = await Promise.all([
|
|
7025
|
+
fs2.realpath(rootDir),
|
|
7026
|
+
fs2.realpath(targetDir)
|
|
7027
|
+
]);
|
|
7028
|
+
if (!isPathWithinRoot(resolvedRoot, resolvedTargetDir)) {
|
|
7029
|
+
return reply.status(400).send({
|
|
7030
|
+
success: false,
|
|
7031
|
+
error: "Upload path must stay within the project directory"
|
|
7032
|
+
});
|
|
7033
|
+
}
|
|
7034
|
+
const safeFilename = path2.basename(filename);
|
|
7035
|
+
if (safeFilename !== filename) {
|
|
7036
|
+
return reply.status(400).send({
|
|
7037
|
+
success: false,
|
|
7038
|
+
error: "Invalid filename"
|
|
7039
|
+
});
|
|
7040
|
+
}
|
|
7041
|
+
const targetPath = path2.join(resolvedTargetDir, safeFilename);
|
|
7042
|
+
await fs2.writeFile(targetPath, buffer);
|
|
7043
|
+
const stat2 = await fs2.stat(targetPath);
|
|
6476
7044
|
const result = {
|
|
6477
|
-
path:
|
|
7045
|
+
path: path2.posix.join("/", relativeDirectory, safeFilename),
|
|
6478
7046
|
name: filename,
|
|
6479
7047
|
is_dir: false,
|
|
6480
7048
|
size: stat2.size,
|
|
@@ -6482,9 +7050,63 @@ var WorkspaceController = class {
|
|
|
6482
7050
|
};
|
|
6483
7051
|
return reply.status(200).send({ success: true, data: result });
|
|
6484
7052
|
} catch (error) {
|
|
7053
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6485
7054
|
return reply.status(500).send({
|
|
6486
7055
|
success: false,
|
|
6487
|
-
error: `Upload handler error: ${
|
|
7056
|
+
error: `Upload handler error: ${message}`
|
|
7057
|
+
});
|
|
7058
|
+
}
|
|
7059
|
+
}
|
|
7060
|
+
/**
|
|
7061
|
+
* Browse local filesystem directories for the folder picker.
|
|
7062
|
+
*
|
|
7063
|
+
* Security constraints:
|
|
7064
|
+
* - Restricted to os.homedir()
|
|
7065
|
+
* - Blacklists system directories
|
|
7066
|
+
* - Returns only directory names, no file contents or hidden files
|
|
7067
|
+
*/
|
|
7068
|
+
async browseFilesystem(request, reply) {
|
|
7069
|
+
const homeDir = os.homedir();
|
|
7070
|
+
const requestedPath = request.query.path || homeDir;
|
|
7071
|
+
const SYSTEM_BLACKLIST = ["/etc", "/sys", "/proc", "/var", "/tmp", "/dev"];
|
|
7072
|
+
try {
|
|
7073
|
+
const resolved = await resolvePathWithinRoot(homeDir, requestedPath);
|
|
7074
|
+
const normalized = resolved.targetPath;
|
|
7075
|
+
for (const blacklisted of SYSTEM_BLACKLIST) {
|
|
7076
|
+
if (isPathWithinRoot(blacklisted, normalized)) {
|
|
7077
|
+
return reply.status(403).send({
|
|
7078
|
+
success: false,
|
|
7079
|
+
error: `Cannot browse system directory: ${blacklisted}`
|
|
7080
|
+
});
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
7083
|
+
const entries = await fs2.readdir(normalized, { withFileTypes: true });
|
|
7084
|
+
const dirEntries = entries.filter((entry) => !entry.name.startsWith(".") && entry.isDirectory()).map((entry) => ({
|
|
7085
|
+
name: entry.name,
|
|
7086
|
+
path: path2.join(normalized, entry.name),
|
|
7087
|
+
isDirectory: true
|
|
7088
|
+
}));
|
|
7089
|
+
const parentPath = path2.dirname(normalized);
|
|
7090
|
+
const hasParent = parentPath !== normalized && isPathWithinRoot(resolved.rootPath, parentPath);
|
|
7091
|
+
return {
|
|
7092
|
+
success: true,
|
|
7093
|
+
data: {
|
|
7094
|
+
path: normalized,
|
|
7095
|
+
parentPath: hasParent ? parentPath : void 0,
|
|
7096
|
+
entries: dirEntries
|
|
7097
|
+
}
|
|
7098
|
+
};
|
|
7099
|
+
} catch (error) {
|
|
7100
|
+
if (error instanceof PathOutsideRootError) {
|
|
7101
|
+
return reply.status(403).send({
|
|
7102
|
+
success: false,
|
|
7103
|
+
error: "Browse restricted to home directory"
|
|
7104
|
+
});
|
|
7105
|
+
}
|
|
7106
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7107
|
+
return reply.status(400).send({
|
|
7108
|
+
success: false,
|
|
7109
|
+
error: `Cannot read directory: ${message}`
|
|
6488
7110
|
});
|
|
6489
7111
|
}
|
|
6490
7112
|
}
|
|
@@ -6545,6 +7167,10 @@ function registerWorkspaceRoutes(app2) {
|
|
|
6545
7167
|
"/api/workspaces/:workspaceId/projects/:projectId/viewfile",
|
|
6546
7168
|
controller.viewFile.bind(controller)
|
|
6547
7169
|
);
|
|
7170
|
+
app2.get(
|
|
7171
|
+
"/api/filesystem/browse",
|
|
7172
|
+
controller.browseFilesystem.bind(controller)
|
|
7173
|
+
);
|
|
6548
7174
|
}
|
|
6549
7175
|
|
|
6550
7176
|
// src/controllers/database-configs.ts
|
|
@@ -6761,7 +7387,7 @@ async function testDatabaseConnection(request, reply) {
|
|
|
6761
7387
|
await db.connect();
|
|
6762
7388
|
await db.listTables();
|
|
6763
7389
|
const latency = Date.now() - startTime;
|
|
6764
|
-
await new Promise((
|
|
7390
|
+
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
6765
7391
|
await db.disconnect();
|
|
6766
7392
|
await import_core27.sqlDatabaseManager.removeDatabase(tenantId, testKey);
|
|
6767
7393
|
return {
|
|
@@ -7650,6 +8276,9 @@ var EvalRunner = class {
|
|
|
7650
8276
|
const runId = (0, import_uuid4.v4)();
|
|
7651
8277
|
const concurrency = Math.max(1, Math.floor(project.concurrency) || 3);
|
|
7652
8278
|
await store2.createRun(tenantId, projectId, runId, { totalCases, concurrency });
|
|
8279
|
+
const tsc = project.targetServerConfig ?? {};
|
|
8280
|
+
const workspaceId = tsc.workspace_id || "";
|
|
8281
|
+
const projectIdFromConfig = tsc.project_id || "";
|
|
7653
8282
|
const projectConfig = {
|
|
7654
8283
|
projectName: project.name,
|
|
7655
8284
|
version: project.version,
|
|
@@ -7657,7 +8286,9 @@ var EvalRunner = class {
|
|
|
7657
8286
|
suites: evalSuites,
|
|
7658
8287
|
judge_agent_config: { modelKey: resolvedJudgeModelKey },
|
|
7659
8288
|
lattice_server_config: {
|
|
7660
|
-
tenant_id: tenantId
|
|
8289
|
+
tenant_id: tenantId,
|
|
8290
|
+
workspace_id: workspaceId,
|
|
8291
|
+
project_id: projectIdFromConfig
|
|
7661
8292
|
},
|
|
7662
8293
|
concurrency
|
|
7663
8294
|
};
|
|
@@ -9072,8 +9703,8 @@ function getTenantId15(request) {
|
|
|
9072
9703
|
return request.headers["x-tenant-id"] || "default";
|
|
9073
9704
|
}
|
|
9074
9705
|
async function getInstallationStore() {
|
|
9075
|
-
const { getStoreLattice:
|
|
9076
|
-
const store2 =
|
|
9706
|
+
const { getStoreLattice: getStoreLattice32 } = await import("@axiom-lattice/core");
|
|
9707
|
+
const store2 = getStoreLattice32("default", "channelInstallation").store;
|
|
9077
9708
|
if (store2) return store2;
|
|
9078
9709
|
const { PostgreSQLChannelInstallationStore } = await import("@axiom-lattice/pg-stores");
|
|
9079
9710
|
const databaseUrl = process.env.DATABASE_URL;
|
|
@@ -9554,8 +10185,8 @@ var log = {
|
|
|
9554
10185
|
};
|
|
9555
10186
|
var connections = /* @__PURE__ */ new Map();
|
|
9556
10187
|
var pending = /* @__PURE__ */ new Map();
|
|
9557
|
-
function getAgentIdFromPath(
|
|
9558
|
-
const match =
|
|
10188
|
+
function getAgentIdFromPath(path4) {
|
|
10189
|
+
const match = path4.match(/^\/api\/a2a\/bridge\/proxy\/([^/]+)/);
|
|
9559
10190
|
return match ? match[1] : null;
|
|
9560
10191
|
}
|
|
9561
10192
|
function handleBridgeConnection(socket, _request) {
|
|
@@ -9663,12 +10294,12 @@ async function handleBridgeProxy(request, reply) {
|
|
|
9663
10294
|
};
|
|
9664
10295
|
const timeout = 3e5;
|
|
9665
10296
|
try {
|
|
9666
|
-
const response = await new Promise((
|
|
10297
|
+
const response = await new Promise((resolve3, reject) => {
|
|
9667
10298
|
const timer = setTimeout(() => {
|
|
9668
10299
|
pending.delete(requestId);
|
|
9669
10300
|
reject(new Error(`Bridge request timeout after ${timeout}ms`));
|
|
9670
10301
|
}, timeout);
|
|
9671
|
-
pending.set(requestId, { resolve, reject, timer, agentId });
|
|
10302
|
+
pending.set(requestId, { resolve: resolve3, reject, timer, agentId });
|
|
9672
10303
|
try {
|
|
9673
10304
|
if (conn.ws.readyState !== conn.ws.OPEN) {
|
|
9674
10305
|
pending.delete(requestId);
|
|
@@ -9713,9 +10344,350 @@ function registerA2ABridgeRoutes(app2) {
|
|
|
9713
10344
|
});
|
|
9714
10345
|
}
|
|
9715
10346
|
|
|
10347
|
+
// src/routes/stt.ts
|
|
10348
|
+
var import_core38 = require("@axiom-lattice/core");
|
|
10349
|
+
var ALLOWED_AUDIO_FORMATS = /* @__PURE__ */ new Set([
|
|
10350
|
+
"webm",
|
|
10351
|
+
"wav",
|
|
10352
|
+
"mp3",
|
|
10353
|
+
"m4a",
|
|
10354
|
+
"ogg",
|
|
10355
|
+
"flac",
|
|
10356
|
+
"aac"
|
|
10357
|
+
]);
|
|
10358
|
+
var MAX_AUDIO_FILE_SIZE = 25 * 1024 * 1024;
|
|
10359
|
+
var registerSTTRoutes = (app2) => {
|
|
10360
|
+
app2.get("/api/stt/models", async (_request, reply) => {
|
|
10361
|
+
const models = import_core38.sttModelLatticeManager.getAllSTTModelInfo();
|
|
10362
|
+
return reply.send({ models });
|
|
10363
|
+
});
|
|
10364
|
+
app2.post(
|
|
10365
|
+
"/api/stt/transcribe",
|
|
10366
|
+
{
|
|
10367
|
+
schema: {
|
|
10368
|
+
querystring: {
|
|
10369
|
+
type: "object",
|
|
10370
|
+
properties: {
|
|
10371
|
+
model: { type: "string" }
|
|
10372
|
+
}
|
|
10373
|
+
},
|
|
10374
|
+
response: {
|
|
10375
|
+
200: {
|
|
10376
|
+
type: "object",
|
|
10377
|
+
properties: {
|
|
10378
|
+
text: { type: "string" },
|
|
10379
|
+
confidence: { type: "number" }
|
|
10380
|
+
}
|
|
10381
|
+
}
|
|
10382
|
+
}
|
|
10383
|
+
}
|
|
10384
|
+
},
|
|
10385
|
+
async (request, reply) => {
|
|
10386
|
+
const modelKey = request.query.model || "default";
|
|
10387
|
+
const data = await request.file({
|
|
10388
|
+
limits: { fileSize: MAX_AUDIO_FILE_SIZE }
|
|
10389
|
+
});
|
|
10390
|
+
if (!data) {
|
|
10391
|
+
return reply.status(400).send({ error: "No audio file provided" });
|
|
10392
|
+
}
|
|
10393
|
+
const buffer = await data.toBuffer();
|
|
10394
|
+
if (buffer.length === 0) {
|
|
10395
|
+
return reply.status(400).send({ error: "Empty audio file" });
|
|
10396
|
+
}
|
|
10397
|
+
const format = (data.filename.split(".").pop() || "webm").toLowerCase();
|
|
10398
|
+
if (!ALLOWED_AUDIO_FORMATS.has(format)) {
|
|
10399
|
+
return reply.status(400).send({ error: `Unsupported audio format: ${format}` });
|
|
10400
|
+
}
|
|
10401
|
+
try {
|
|
10402
|
+
let client;
|
|
10403
|
+
try {
|
|
10404
|
+
client = (0, import_core38.getSTTClient)(modelKey);
|
|
10405
|
+
} catch {
|
|
10406
|
+
return reply.status(404).send({ error: `STT model "${modelKey}" not found` });
|
|
10407
|
+
}
|
|
10408
|
+
const result = await client.transcribe(buffer, format);
|
|
10409
|
+
return reply.send({
|
|
10410
|
+
text: result.text,
|
|
10411
|
+
confidence: result.confidence
|
|
10412
|
+
});
|
|
10413
|
+
} catch (error) {
|
|
10414
|
+
const sanitizedMessage = error instanceof Error ? error.message : "Transcription failed";
|
|
10415
|
+
request.log.error(
|
|
10416
|
+
{ error: sanitizedMessage },
|
|
10417
|
+
"STT transcription failed"
|
|
10418
|
+
);
|
|
10419
|
+
return reply.status(500).send({ error: "Transcription service error. Please try again." });
|
|
10420
|
+
}
|
|
10421
|
+
}
|
|
10422
|
+
);
|
|
10423
|
+
};
|
|
10424
|
+
|
|
10425
|
+
// src/controllers/local-a2a.ts
|
|
10426
|
+
var import_core39 = require("@axiom-lattice/core");
|
|
10427
|
+
var import_protocols5 = require("@axiom-lattice/protocols");
|
|
10428
|
+
function getTenantId18(request) {
|
|
10429
|
+
const userTenantId = request.user?.tenantId;
|
|
10430
|
+
if (userTenantId) return userTenantId;
|
|
10431
|
+
return request.headers["x-tenant-id"] || "default";
|
|
10432
|
+
}
|
|
10433
|
+
function getLocalRuntime(assistant) {
|
|
10434
|
+
const graphDefinition = assistant.graphDefinition;
|
|
10435
|
+
if (!graphDefinition || typeof graphDefinition !== "object") return void 0;
|
|
10436
|
+
if (graphDefinition.type !== import_protocols5.AgentType.A2A_REMOTE) return void 0;
|
|
10437
|
+
return graphDefinition.localRuntime;
|
|
10438
|
+
}
|
|
10439
|
+
async function getLocalA2AAssistants(tenantId) {
|
|
10440
|
+
const storeLattice = (0, import_core39.getStoreLattice)("default", "assistant");
|
|
10441
|
+
const assistants = await storeLattice.store.getAllAssistants(tenantId);
|
|
10442
|
+
const results = [];
|
|
10443
|
+
for (const assistant of assistants) {
|
|
10444
|
+
const runtime = getLocalRuntime(assistant);
|
|
10445
|
+
if (runtime) {
|
|
10446
|
+
results.push({ assistant, localRuntime: runtime });
|
|
10447
|
+
}
|
|
10448
|
+
}
|
|
10449
|
+
return results;
|
|
10450
|
+
}
|
|
10451
|
+
async function getLocalA2AAssistant(tenantId, assistantId) {
|
|
10452
|
+
const storeLattice = (0, import_core39.getStoreLattice)("default", "assistant");
|
|
10453
|
+
const assistant = await storeLattice.store.getAssistantById(tenantId, assistantId);
|
|
10454
|
+
if (!assistant) return null;
|
|
10455
|
+
const runtime = getLocalRuntime(assistant);
|
|
10456
|
+
if (!runtime) return null;
|
|
10457
|
+
return { assistant, localRuntime: runtime };
|
|
10458
|
+
}
|
|
10459
|
+
async function requireManagedAssistant(request, reply) {
|
|
10460
|
+
const assistantId = request.params.assistantId;
|
|
10461
|
+
if (!assistantId) {
|
|
10462
|
+
reply.status(400).send({ success: false, error: "assistantId is required" });
|
|
10463
|
+
return null;
|
|
10464
|
+
}
|
|
10465
|
+
const registered = await getLocalA2AAssistant(getTenantId18(request), assistantId);
|
|
10466
|
+
if (!registered) {
|
|
10467
|
+
reply.status(404).send({
|
|
10468
|
+
success: false,
|
|
10469
|
+
error: `Assistant ${assistantId} is not a local managed A2A assistant`
|
|
10470
|
+
});
|
|
10471
|
+
return null;
|
|
10472
|
+
}
|
|
10473
|
+
return { assistantId, localRuntime: registered.localRuntime };
|
|
10474
|
+
}
|
|
10475
|
+
async function getLocalA2AStatus(request, reply) {
|
|
10476
|
+
const tenantId = getTenantId18(request);
|
|
10477
|
+
const managed = await getLocalA2AAssistants(tenantId);
|
|
10478
|
+
const states = await Promise.all(
|
|
10479
|
+
managed.map(
|
|
10480
|
+
({ assistant, localRuntime }) => localA2AService.getRegisteredState(assistant.id, localRuntime)
|
|
10481
|
+
)
|
|
10482
|
+
);
|
|
10483
|
+
reply.send({ success: true, data: { records: states, total: states.length } });
|
|
10484
|
+
}
|
|
10485
|
+
async function getLocalA2AProvider(request, reply) {
|
|
10486
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
10487
|
+
if (!registered) return;
|
|
10488
|
+
const state = await localA2AService.getRegisteredState(
|
|
10489
|
+
registered.assistantId,
|
|
10490
|
+
registered.localRuntime
|
|
10491
|
+
);
|
|
10492
|
+
reply.send({ success: true, data: state });
|
|
10493
|
+
}
|
|
10494
|
+
async function startLocalA2AProvider(request, reply) {
|
|
10495
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
10496
|
+
if (!registered) return;
|
|
10497
|
+
const state = await localA2AService.startProvider(
|
|
10498
|
+
registered.assistantId,
|
|
10499
|
+
registered.localRuntime
|
|
10500
|
+
);
|
|
10501
|
+
reply.send({ success: true, data: state });
|
|
10502
|
+
}
|
|
10503
|
+
async function stopLocalA2AProvider(request, reply) {
|
|
10504
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
10505
|
+
if (!registered) return;
|
|
10506
|
+
const state = await localA2AService.stopProvider(registered.assistantId);
|
|
10507
|
+
reply.send({ success: true, data: state });
|
|
10508
|
+
}
|
|
10509
|
+
async function restartLocalA2AProvider(request, reply) {
|
|
10510
|
+
const registered = await requireManagedAssistant(request, reply);
|
|
10511
|
+
if (!registered) return;
|
|
10512
|
+
const state = await localA2AService.restartProvider(
|
|
10513
|
+
registered.assistantId,
|
|
10514
|
+
registered.localRuntime
|
|
10515
|
+
);
|
|
10516
|
+
reply.send({ success: true, data: state });
|
|
10517
|
+
}
|
|
10518
|
+
|
|
10519
|
+
// src/config/local-a2a-templates.ts
|
|
10520
|
+
var import_cli_path = require("@axiom-lattice/cli-a2a/cli-path");
|
|
10521
|
+
function buildCliA2ACommand(provider, agentName, agentDescription) {
|
|
10522
|
+
return {
|
|
10523
|
+
executable: process.execPath,
|
|
10524
|
+
args: [
|
|
10525
|
+
import_cli_path.cliA2AEntryPath,
|
|
10526
|
+
"--provider",
|
|
10527
|
+
provider,
|
|
10528
|
+
"--hostname",
|
|
10529
|
+
"localhost",
|
|
10530
|
+
"--advertise-host",
|
|
10531
|
+
"localhost",
|
|
10532
|
+
"--agent-name",
|
|
10533
|
+
agentName,
|
|
10534
|
+
"--agent-description",
|
|
10535
|
+
agentDescription,
|
|
10536
|
+
"--log-level",
|
|
10537
|
+
"info"
|
|
10538
|
+
]
|
|
10539
|
+
};
|
|
10540
|
+
}
|
|
10541
|
+
var LOCAL_A2A_TEMPLATES = [
|
|
10542
|
+
{
|
|
10543
|
+
key: "claude",
|
|
10544
|
+
name: "Claude Code",
|
|
10545
|
+
command: buildCliA2ACommand(
|
|
10546
|
+
"claude",
|
|
10547
|
+
"Claude Code",
|
|
10548
|
+
"Local Claude Code wrapper exposed through A2A."
|
|
10549
|
+
)
|
|
10550
|
+
},
|
|
10551
|
+
{
|
|
10552
|
+
key: "codex",
|
|
10553
|
+
name: "Codex",
|
|
10554
|
+
command: buildCliA2ACommand(
|
|
10555
|
+
"codex",
|
|
10556
|
+
"Codex",
|
|
10557
|
+
"Local Codex wrapper exposed through A2A."
|
|
10558
|
+
)
|
|
10559
|
+
},
|
|
10560
|
+
{
|
|
10561
|
+
key: "opencode",
|
|
10562
|
+
name: "OpenCode",
|
|
10563
|
+
command: buildCliA2ACommand(
|
|
10564
|
+
"opencode",
|
|
10565
|
+
"OpenCode",
|
|
10566
|
+
"Local OpenCode wrapper exposed through A2A."
|
|
10567
|
+
)
|
|
10568
|
+
}
|
|
10569
|
+
];
|
|
10570
|
+
|
|
10571
|
+
// src/controllers/local-a2a-templates.ts
|
|
10572
|
+
async function getLocalA2ATemplates(_request, reply) {
|
|
10573
|
+
reply.send({
|
|
10574
|
+
success: true,
|
|
10575
|
+
data: {
|
|
10576
|
+
records: LOCAL_A2A_TEMPLATES,
|
|
10577
|
+
total: LOCAL_A2A_TEMPLATES.length
|
|
10578
|
+
}
|
|
10579
|
+
});
|
|
10580
|
+
}
|
|
10581
|
+
|
|
10582
|
+
// src/routes/a2a-test-connection.ts
|
|
10583
|
+
var import_node_crypto = require("crypto");
|
|
10584
|
+
function describeTestConnectionError(error, agentCardUrl) {
|
|
10585
|
+
if (!(error instanceof Error)) {
|
|
10586
|
+
return `Failed to fetch agent card from ${agentCardUrl}: ${String(error)}`;
|
|
10587
|
+
}
|
|
10588
|
+
const cause = error.cause;
|
|
10589
|
+
const causeParts = [];
|
|
10590
|
+
if (cause instanceof Error) {
|
|
10591
|
+
causeParts.push(cause.message);
|
|
10592
|
+
const causeCode = cause.code;
|
|
10593
|
+
if (causeCode && !causeParts.some((part) => part.includes(causeCode))) {
|
|
10594
|
+
causeParts.push(causeCode);
|
|
10595
|
+
}
|
|
10596
|
+
} else if (typeof cause === "object" && cause !== null) {
|
|
10597
|
+
const code = "code" in cause ? String(cause.code) : "";
|
|
10598
|
+
const message = "message" in cause ? String(cause.message) : "";
|
|
10599
|
+
if (message) causeParts.push(message);
|
|
10600
|
+
if (code && !message.includes(code)) causeParts.push(code);
|
|
10601
|
+
}
|
|
10602
|
+
const detail = causeParts.length > 0 ? ` (${causeParts.join(", ")})` : "";
|
|
10603
|
+
return `Failed to fetch agent card from ${agentCardUrl}: ${error.message}${detail}`;
|
|
10604
|
+
}
|
|
10605
|
+
async function ensureLocalRuntimeForConnectionTest(localRuntime, agentCardUrl) {
|
|
10606
|
+
const commandValidation = validateLocalRuntimeCommand(localRuntime);
|
|
10607
|
+
if (!commandValidation.ok) {
|
|
10608
|
+
return { error: commandValidation.error };
|
|
10609
|
+
}
|
|
10610
|
+
const testRuntime = {
|
|
10611
|
+
...localRuntime,
|
|
10612
|
+
agentCardUrl,
|
|
10613
|
+
command: {
|
|
10614
|
+
...localRuntime.command,
|
|
10615
|
+
executable: localRuntime.command.executable.trim()
|
|
10616
|
+
}
|
|
10617
|
+
};
|
|
10618
|
+
const portValidation = validateLocalRuntimePort(testRuntime, agentCardUrl);
|
|
10619
|
+
if (!portValidation.ok) {
|
|
10620
|
+
return { error: portValidation.error };
|
|
10621
|
+
}
|
|
10622
|
+
const state = await localA2AService.startProvider(
|
|
10623
|
+
`test-${(0, import_node_crypto.randomUUID)()}`,
|
|
10624
|
+
testRuntime
|
|
10625
|
+
);
|
|
10626
|
+
if (state.status === "running") return { runtimeId: state.runtimeId };
|
|
10627
|
+
const detail = state.message ? ` ${state.message}` : "";
|
|
10628
|
+
localA2AService.removeState(state.runtimeId);
|
|
10629
|
+
return { error: `Local managed A2A server could not start for connection test.${detail}` };
|
|
10630
|
+
}
|
|
10631
|
+
async function readShortResponseBody(resp) {
|
|
10632
|
+
const body = await resp.text().catch(() => "");
|
|
10633
|
+
return body.length > 500 ? `${body.slice(0, 500)}...` : body;
|
|
10634
|
+
}
|
|
10635
|
+
function registerA2ATestConnectionRoute(app2) {
|
|
10636
|
+
app2.post("/api/a2a/test-connection", async (request, reply) => {
|
|
10637
|
+
const { agentCardUrl, apiKey, localRuntime } = request.body ?? {};
|
|
10638
|
+
const normalizedAgentCardUrl = normalizeA2AAgentCardUrl(
|
|
10639
|
+
agentCardUrl,
|
|
10640
|
+
localRuntime ? "http://" : "https://"
|
|
10641
|
+
);
|
|
10642
|
+
if (!normalizedAgentCardUrl) {
|
|
10643
|
+
return reply.status(400).send({ success: false, error: "agentCardUrl is required" });
|
|
10644
|
+
}
|
|
10645
|
+
let testRuntimeId = null;
|
|
10646
|
+
try {
|
|
10647
|
+
const headers = {};
|
|
10648
|
+
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
|
10649
|
+
if (localRuntime) {
|
|
10650
|
+
const localStartResult = await ensureLocalRuntimeForConnectionTest(localRuntime, normalizedAgentCardUrl);
|
|
10651
|
+
if ("error" in localStartResult) {
|
|
10652
|
+
return reply.send({ success: true, data: { reachable: false, error: localStartResult.error } });
|
|
10653
|
+
}
|
|
10654
|
+
testRuntimeId = localStartResult.runtimeId;
|
|
10655
|
+
}
|
|
10656
|
+
const resp = await fetch(normalizedAgentCardUrl, { headers, signal: AbortSignal.timeout(8e3) });
|
|
10657
|
+
if (!resp.ok) {
|
|
10658
|
+
const body = await readShortResponseBody(resp);
|
|
10659
|
+
const suffix = body ? `: ${body}` : "";
|
|
10660
|
+
return reply.send({ success: true, data: { reachable: false, error: `HTTP ${resp.status} ${resp.statusText}${suffix}` } });
|
|
10661
|
+
}
|
|
10662
|
+
const card = await resp.json();
|
|
10663
|
+
return reply.send({ success: true, data: { reachable: true, agentName: card.name, agentCard: card } });
|
|
10664
|
+
} catch (error) {
|
|
10665
|
+
return reply.send({
|
|
10666
|
+
success: true,
|
|
10667
|
+
data: {
|
|
10668
|
+
reachable: false,
|
|
10669
|
+
error: describeTestConnectionError(error, normalizedAgentCardUrl)
|
|
10670
|
+
}
|
|
10671
|
+
});
|
|
10672
|
+
} finally {
|
|
10673
|
+
if (testRuntimeId) {
|
|
10674
|
+
localA2AService.removeState(testRuntimeId);
|
|
10675
|
+
}
|
|
10676
|
+
}
|
|
10677
|
+
});
|
|
10678
|
+
}
|
|
10679
|
+
|
|
9716
10680
|
// src/routes/index.ts
|
|
9717
10681
|
var registerLatticeRoutes = (app2, channelDeps) => {
|
|
9718
10682
|
registerA2ABridgeRoutes(app2);
|
|
10683
|
+
registerSTTRoutes(app2);
|
|
10684
|
+
app2.get("/api/local-a2a", getLocalA2AStatus);
|
|
10685
|
+
app2.get("/api/local-a2a/templates", getLocalA2ATemplates);
|
|
10686
|
+
app2.get("/api/local-a2a/:assistantId", getLocalA2AProvider);
|
|
10687
|
+
app2.post("/api/local-a2a/:assistantId/start", startLocalA2AProvider);
|
|
10688
|
+
app2.post("/api/local-a2a/:assistantId/stop", stopLocalA2AProvider);
|
|
10689
|
+
app2.post("/api/local-a2a/:assistantId/restart", restartLocalA2AProvider);
|
|
10690
|
+
registerA2ATestConnectionRoute(app2);
|
|
9719
10691
|
app2.post("/api/runs", createRun);
|
|
9720
10692
|
app2.post("/api/resume_stream", resumeStream);
|
|
9721
10693
|
app2.post("/api/assistants/:assistantId/threads/:threadId/abort", abortRun);
|
|
@@ -10007,12 +10979,12 @@ function registerResourceRoutes(app2, controller) {
|
|
|
10007
10979
|
}
|
|
10008
10980
|
|
|
10009
10981
|
// src/export_registrations/index.ts
|
|
10010
|
-
var
|
|
10982
|
+
var import_core53 = require("@axiom-lattice/core");
|
|
10011
10983
|
|
|
10012
10984
|
// src/export_registrations/skill.registration.ts
|
|
10013
|
-
var
|
|
10985
|
+
var import_core40 = require("@axiom-lattice/core");
|
|
10014
10986
|
function getStore2() {
|
|
10015
|
-
return (0,
|
|
10987
|
+
return (0, import_core40.getStoreLattice)("default", "skill").store;
|
|
10016
10988
|
}
|
|
10017
10989
|
var skillRegistration = {
|
|
10018
10990
|
entityType: "skill",
|
|
@@ -10087,9 +11059,9 @@ var skillRegistration = {
|
|
|
10087
11059
|
};
|
|
10088
11060
|
|
|
10089
11061
|
// src/export_registrations/agent.registration.ts
|
|
10090
|
-
var
|
|
11062
|
+
var import_core41 = require("@axiom-lattice/core");
|
|
10091
11063
|
function getStore3() {
|
|
10092
|
-
return (0,
|
|
11064
|
+
return (0, import_core41.getStoreLattice)("default", "assistant").store;
|
|
10093
11065
|
}
|
|
10094
11066
|
var agentRegistration = {
|
|
10095
11067
|
entityType: "agent",
|
|
@@ -10156,9 +11128,9 @@ var agentRegistration = {
|
|
|
10156
11128
|
};
|
|
10157
11129
|
|
|
10158
11130
|
// src/export_registrations/binding.registration.ts
|
|
10159
|
-
var
|
|
11131
|
+
var import_core42 = require("@axiom-lattice/core");
|
|
10160
11132
|
function getStore4() {
|
|
10161
|
-
return (0,
|
|
11133
|
+
return (0, import_core42.getStoreLattice)("default", "channelBinding").store;
|
|
10162
11134
|
}
|
|
10163
11135
|
var bindingRegistration = {
|
|
10164
11136
|
entityType: "binding",
|
|
@@ -10246,9 +11218,9 @@ var bindingRegistration = {
|
|
|
10246
11218
|
};
|
|
10247
11219
|
|
|
10248
11220
|
// src/export_registrations/database-config.registration.ts
|
|
10249
|
-
var
|
|
11221
|
+
var import_core43 = require("@axiom-lattice/core");
|
|
10250
11222
|
function getStore5() {
|
|
10251
|
-
return (0,
|
|
11223
|
+
return (0, import_core43.getStoreLattice)("default", "database").store;
|
|
10252
11224
|
}
|
|
10253
11225
|
var databaseConfigRegistration = {
|
|
10254
11226
|
entityType: "database_config",
|
|
@@ -10328,9 +11300,9 @@ var databaseConfigRegistration = {
|
|
|
10328
11300
|
};
|
|
10329
11301
|
|
|
10330
11302
|
// src/export_registrations/metrics-config.registration.ts
|
|
10331
|
-
var
|
|
11303
|
+
var import_core44 = require("@axiom-lattice/core");
|
|
10332
11304
|
function getStore6() {
|
|
10333
|
-
return (0,
|
|
11305
|
+
return (0, import_core44.getStoreLattice)("default", "metrics").store;
|
|
10334
11306
|
}
|
|
10335
11307
|
var metricsConfigRegistration = {
|
|
10336
11308
|
entityType: "metrics_config",
|
|
@@ -10410,9 +11382,9 @@ var metricsConfigRegistration = {
|
|
|
10410
11382
|
};
|
|
10411
11383
|
|
|
10412
11384
|
// src/export_registrations/mcp-config.registration.ts
|
|
10413
|
-
var
|
|
11385
|
+
var import_core45 = require("@axiom-lattice/core");
|
|
10414
11386
|
function getStore7() {
|
|
10415
|
-
return (0,
|
|
11387
|
+
return (0, import_core45.getStoreLattice)("default", "mcp").store;
|
|
10416
11388
|
}
|
|
10417
11389
|
var mcpConfigRegistration = {
|
|
10418
11390
|
entityType: "mcp_config",
|
|
@@ -10495,9 +11467,9 @@ var mcpConfigRegistration = {
|
|
|
10495
11467
|
};
|
|
10496
11468
|
|
|
10497
11469
|
// src/export_registrations/connection.registration.ts
|
|
10498
|
-
var
|
|
11470
|
+
var import_core46 = require("@axiom-lattice/core");
|
|
10499
11471
|
function getStore8() {
|
|
10500
|
-
return (0,
|
|
11472
|
+
return (0, import_core46.getStoreLattice)("default", "connection").store;
|
|
10501
11473
|
}
|
|
10502
11474
|
async function listAllConnections(tenantId) {
|
|
10503
11475
|
const store2 = getStore8();
|
|
@@ -10579,9 +11551,9 @@ var connectionRegistration = {
|
|
|
10579
11551
|
};
|
|
10580
11552
|
|
|
10581
11553
|
// src/export_registrations/collection.registration.ts
|
|
10582
|
-
var
|
|
11554
|
+
var import_core47 = require("@axiom-lattice/core");
|
|
10583
11555
|
function getStore9() {
|
|
10584
|
-
return (0,
|
|
11556
|
+
return (0, import_core47.getStoreLattice)("default", "collection").store;
|
|
10585
11557
|
}
|
|
10586
11558
|
var collectionRegistration = {
|
|
10587
11559
|
entityType: "collection",
|
|
@@ -10652,9 +11624,9 @@ var collectionRegistration = {
|
|
|
10652
11624
|
};
|
|
10653
11625
|
|
|
10654
11626
|
// src/export_registrations/channel-installation.registration.ts
|
|
10655
|
-
var
|
|
11627
|
+
var import_core48 = require("@axiom-lattice/core");
|
|
10656
11628
|
function getStore10() {
|
|
10657
|
-
return (0,
|
|
11629
|
+
return (0, import_core48.getStoreLattice)("default", "channelInstallation").store;
|
|
10658
11630
|
}
|
|
10659
11631
|
var channelInstallationRegistration = {
|
|
10660
11632
|
entityType: "channel_installation",
|
|
@@ -10729,9 +11701,9 @@ var channelInstallationRegistration = {
|
|
|
10729
11701
|
};
|
|
10730
11702
|
|
|
10731
11703
|
// src/export_registrations/menu.registration.ts
|
|
10732
|
-
var
|
|
11704
|
+
var import_core49 = require("@axiom-lattice/core");
|
|
10733
11705
|
function getStore11() {
|
|
10734
|
-
return (0,
|
|
11706
|
+
return (0, import_core49.getStoreLattice)("default", "menu").store;
|
|
10735
11707
|
}
|
|
10736
11708
|
var menuRegistration = {
|
|
10737
11709
|
entityType: "menu",
|
|
@@ -10809,9 +11781,9 @@ var menuRegistration = {
|
|
|
10809
11781
|
};
|
|
10810
11782
|
|
|
10811
11783
|
// src/export_registrations/task.registration.ts
|
|
10812
|
-
var
|
|
11784
|
+
var import_core50 = require("@axiom-lattice/core");
|
|
10813
11785
|
function getStore12() {
|
|
10814
|
-
return (0,
|
|
11786
|
+
return (0, import_core50.getStoreLattice)("default", "task").store;
|
|
10815
11787
|
}
|
|
10816
11788
|
var taskRegistration = {
|
|
10817
11789
|
entityType: "task",
|
|
@@ -10897,9 +11869,9 @@ var taskRegistration = {
|
|
|
10897
11869
|
};
|
|
10898
11870
|
|
|
10899
11871
|
// src/export_registrations/a2a-api-key.registration.ts
|
|
10900
|
-
var
|
|
11872
|
+
var import_core51 = require("@axiom-lattice/core");
|
|
10901
11873
|
function getStore13() {
|
|
10902
|
-
return (0,
|
|
11874
|
+
return (0, import_core51.getStoreLattice)("default", "a2aApiKey").store;
|
|
10903
11875
|
}
|
|
10904
11876
|
var a2aApiKeyRegistration = {
|
|
10905
11877
|
entityType: "a2a_api_key",
|
|
@@ -10970,9 +11942,9 @@ var a2aApiKeyRegistration = {
|
|
|
10970
11942
|
};
|
|
10971
11943
|
|
|
10972
11944
|
// src/export_registrations/eval.registration.ts
|
|
10973
|
-
var
|
|
11945
|
+
var import_core52 = require("@axiom-lattice/core");
|
|
10974
11946
|
function getStore14() {
|
|
10975
|
-
return (0,
|
|
11947
|
+
return (0, import_core52.getStoreLattice)("default", "eval").store;
|
|
10976
11948
|
}
|
|
10977
11949
|
var evalRegistration = {
|
|
10978
11950
|
entityType: "eval",
|
|
@@ -11298,7 +12270,7 @@ var evalRegistration = {
|
|
|
11298
12270
|
|
|
11299
12271
|
// src/export_registrations/index.ts
|
|
11300
12272
|
function registerAllBuiltinEntities() {
|
|
11301
|
-
const registry =
|
|
12273
|
+
const registry = import_core53.ExportableEntityRegistry.getInstance();
|
|
11302
12274
|
registry.register(skillRegistration);
|
|
11303
12275
|
registry.register(agentRegistration);
|
|
11304
12276
|
registry.register(bindingRegistration);
|
|
@@ -11315,7 +12287,7 @@ function registerAllBuiltinEntities() {
|
|
|
11315
12287
|
}
|
|
11316
12288
|
|
|
11317
12289
|
// src/router/MessageRouter.ts
|
|
11318
|
-
var
|
|
12290
|
+
var import_core54 = require("@axiom-lattice/core");
|
|
11319
12291
|
var import_crypto10 = require("crypto");
|
|
11320
12292
|
var BindingNotFoundError = class extends Error {
|
|
11321
12293
|
constructor(message) {
|
|
@@ -11476,7 +12448,7 @@ var MessageRouter = class {
|
|
|
11476
12448
|
channel: message.channel,
|
|
11477
12449
|
adapterChannel: adapter.channel
|
|
11478
12450
|
}, "Thread resolved by adapter strategy");
|
|
11479
|
-
const threadStore = (0,
|
|
12451
|
+
const threadStore = (0, import_core54.getStoreLattice)("default", "thread").store;
|
|
11480
12452
|
try {
|
|
11481
12453
|
await threadStore.createThread(
|
|
11482
12454
|
tenantId,
|
|
@@ -11513,7 +12485,7 @@ var MessageRouter = class {
|
|
|
11513
12485
|
}
|
|
11514
12486
|
}
|
|
11515
12487
|
if (!threadId) {
|
|
11516
|
-
const threadStore = (0,
|
|
12488
|
+
const threadStore = (0, import_core54.getStoreLattice)("default", "thread").store;
|
|
11517
12489
|
const newThreadId = (0, import_crypto10.randomUUID)();
|
|
11518
12490
|
console.log({
|
|
11519
12491
|
event: "dispatch:thread:create",
|
|
@@ -11553,7 +12525,7 @@ var MessageRouter = class {
|
|
|
11553
12525
|
senderId: message.sender.id,
|
|
11554
12526
|
contentLength: message.content.text.length
|
|
11555
12527
|
}, "Dispatching to agent");
|
|
11556
|
-
const agent =
|
|
12528
|
+
const agent = import_core54.agentInstanceManager.getAgent({
|
|
11557
12529
|
tenant_id: tenantId,
|
|
11558
12530
|
assistant_id: agentId,
|
|
11559
12531
|
thread_id: threadId,
|
|
@@ -11798,7 +12770,7 @@ function createAuditLoggerMiddleware() {
|
|
|
11798
12770
|
}
|
|
11799
12771
|
|
|
11800
12772
|
// src/index.ts
|
|
11801
|
-
var
|
|
12773
|
+
var import_core58 = require("@axiom-lattice/core");
|
|
11802
12774
|
|
|
11803
12775
|
// src/swagger.ts
|
|
11804
12776
|
var import_swagger = __toESM(require("@fastify/swagger"));
|
|
@@ -11863,7 +12835,7 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
|
|
|
11863
12835
|
};
|
|
11864
12836
|
|
|
11865
12837
|
// src/services/agent_task_consumer.ts
|
|
11866
|
-
var
|
|
12838
|
+
var import_core55 = require("@axiom-lattice/core");
|
|
11867
12839
|
var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
11868
12840
|
const {
|
|
11869
12841
|
assistant_id,
|
|
@@ -11881,17 +12853,17 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
|
|
|
11881
12853
|
console.log(
|
|
11882
12854
|
`\u5F00\u59CB\u5904\u7406\u4EFB\u52A1 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
|
|
11883
12855
|
);
|
|
11884
|
-
const agent =
|
|
11885
|
-
await agent.addMessage({ input, command, custom_run_config: runConfig },
|
|
12856
|
+
const agent = import_core55.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
|
|
12857
|
+
await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core55.QueueMode.STEER);
|
|
11886
12858
|
if (callback_event) {
|
|
11887
12859
|
agent.subscribeOnce("message:completed", (evt) => {
|
|
11888
|
-
|
|
12860
|
+
import_core55.eventBus.publish(callback_event, {
|
|
11889
12861
|
success: true,
|
|
11890
12862
|
state: evt.state
|
|
11891
12863
|
});
|
|
11892
12864
|
if (main_thread_id && main_tenant_id) {
|
|
11893
12865
|
try {
|
|
11894
|
-
const mainAgent =
|
|
12866
|
+
const mainAgent = import_core55.agentInstanceManager.getAgent({
|
|
11895
12867
|
assistant_id: main_assistant_id ?? assistant_id,
|
|
11896
12868
|
thread_id: main_thread_id,
|
|
11897
12869
|
tenant_id: main_tenant_id,
|
|
@@ -11921,7 +12893,7 @@ ${summary}`
|
|
|
11921
12893
|
}
|
|
11922
12894
|
});
|
|
11923
12895
|
agent.subscribeOnce("message:interrupted", (evt) => {
|
|
11924
|
-
|
|
12896
|
+
import_core55.eventBus.publish(callback_event, {
|
|
11925
12897
|
success: true,
|
|
11926
12898
|
state: evt.state
|
|
11927
12899
|
});
|
|
@@ -11940,11 +12912,11 @@ ${summary}`
|
|
|
11940
12912
|
console.log(
|
|
11941
12913
|
`\u5C06\u5728 ${delayMs}ms \u540E\u91CD\u8BD5\u4EFB\u52A1 (${nextRetryCount}/${maxRetries})`
|
|
11942
12914
|
);
|
|
11943
|
-
await new Promise((
|
|
12915
|
+
await new Promise((resolve3) => setTimeout(resolve3, delayMs));
|
|
11944
12916
|
return handleAgentTask(taskRequest, nextRetryCount);
|
|
11945
12917
|
}
|
|
11946
12918
|
if (callback_event) {
|
|
11947
|
-
|
|
12919
|
+
import_core55.eventBus.publish(callback_event, {
|
|
11948
12920
|
success: false,
|
|
11949
12921
|
error: error instanceof Error ? error.message : String(error)
|
|
11950
12922
|
});
|
|
@@ -11981,7 +12953,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
|
|
|
11981
12953
|
* 初始化事件监听和队列轮询
|
|
11982
12954
|
*/
|
|
11983
12955
|
initialize() {
|
|
11984
|
-
|
|
12956
|
+
import_core55.eventBus.subscribe(import_core55.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
|
|
11985
12957
|
this.startPollingQueue();
|
|
11986
12958
|
console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
|
|
11987
12959
|
}
|
|
@@ -12100,7 +13072,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
|
|
|
12100
13072
|
handleAgentTask(taskRequest).catch((error) => {
|
|
12101
13073
|
console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
|
|
12102
13074
|
if (taskRequest.callback_event) {
|
|
12103
|
-
|
|
13075
|
+
import_core55.eventBus.publish(taskRequest.callback_event, {
|
|
12104
13076
|
success: false,
|
|
12105
13077
|
error: error instanceof Error ? error.message : String(error)
|
|
12106
13078
|
});
|
|
@@ -12115,8 +13087,8 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
|
|
|
12115
13087
|
var AgentTaskConsumer = _AgentTaskConsumer;
|
|
12116
13088
|
|
|
12117
13089
|
// src/index.ts
|
|
12118
|
-
var
|
|
12119
|
-
var
|
|
13090
|
+
var import_core59 = require("@axiom-lattice/core");
|
|
13091
|
+
var import_protocols7 = require("@axiom-lattice/protocols");
|
|
12120
13092
|
var import_meta = {};
|
|
12121
13093
|
process.on("unhandledRejection", (reason, promise) => {
|
|
12122
13094
|
console.error("\u672A\u5904\u7406\u7684Promise\u62D2\u7EDD:", reason);
|
|
@@ -12124,18 +13096,18 @@ process.on("unhandledRejection", (reason, promise) => {
|
|
|
12124
13096
|
var DEFAULT_LOGGER_CONFIG = {
|
|
12125
13097
|
name: "default",
|
|
12126
13098
|
description: "Default logger for lattice-gateway service",
|
|
12127
|
-
type:
|
|
13099
|
+
type: import_protocols7.LoggerType.PINO,
|
|
12128
13100
|
serviceName: "lattice/gateway",
|
|
12129
13101
|
loggerName: "lattice/gateway"
|
|
12130
13102
|
};
|
|
12131
13103
|
var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
|
|
12132
13104
|
var logger5 = loggerLattice.client;
|
|
12133
13105
|
function initializeLogger(config) {
|
|
12134
|
-
if (
|
|
12135
|
-
|
|
13106
|
+
if (import_core59.loggerLatticeManager.hasLattice("default")) {
|
|
13107
|
+
import_core59.loggerLatticeManager.removeLattice("default");
|
|
12136
13108
|
}
|
|
12137
|
-
(0,
|
|
12138
|
-
return (0,
|
|
13109
|
+
(0, import_core59.registerLoggerLattice)("default", config);
|
|
13110
|
+
return (0, import_core59.getLoggerLattice)("default");
|
|
12139
13111
|
}
|
|
12140
13112
|
var app = (0, import_fastify.default)({
|
|
12141
13113
|
logger: false,
|
|
@@ -12159,7 +13131,7 @@ var getHeaderValue = (header) => {
|
|
|
12159
13131
|
}
|
|
12160
13132
|
return header;
|
|
12161
13133
|
};
|
|
12162
|
-
var PUBLIC_ROUTES = ["/api/auth/login", "/api/auth/register", "/health"];
|
|
13134
|
+
var PUBLIC_ROUTES = ["/api/auth/login", "/api/auth/register", "/health", "/api/stt/models"];
|
|
12163
13135
|
app.addHook("preHandler", async (request, reply) => {
|
|
12164
13136
|
const user = extractUserFromAuthHeader(request.headers.authorization);
|
|
12165
13137
|
if (user) {
|
|
@@ -12246,7 +13218,7 @@ app.setErrorHandler((error, request, reply) => {
|
|
|
12246
13218
|
});
|
|
12247
13219
|
function getConfiguredSandboxProvider() {
|
|
12248
13220
|
const sandboxProviderType = process.env.SANDBOX_PROVIDER_TYPE || "microsandbox-remote";
|
|
12249
|
-
return (0,
|
|
13221
|
+
return (0, import_core59.createSandboxProvider)({
|
|
12250
13222
|
type: sandboxProviderType,
|
|
12251
13223
|
remoteBaseURL: process.env.SANDBOX_BASE_URL,
|
|
12252
13224
|
microsandboxServiceBaseURL: process.env.MICROSANDBOX_SERVICE_BASE_URL,
|
|
@@ -12262,7 +13234,7 @@ function getConfiguredSandboxProvider() {
|
|
|
12262
13234
|
}
|
|
12263
13235
|
async function restoreMcpConnections() {
|
|
12264
13236
|
try {
|
|
12265
|
-
const storeLattice = (0,
|
|
13237
|
+
const storeLattice = (0, import_core59.getStoreLattice)("default", "mcp");
|
|
12266
13238
|
const store2 = storeLattice.store;
|
|
12267
13239
|
if (!store2) {
|
|
12268
13240
|
logger5.info("MCP store not configured, skipping connection restoration");
|
|
@@ -12276,15 +13248,15 @@ async function restoreMcpConnections() {
|
|
|
12276
13248
|
for (const config of connectedConfigs) {
|
|
12277
13249
|
try {
|
|
12278
13250
|
const connection = convertToConnection2(config.config);
|
|
12279
|
-
|
|
13251
|
+
import_core59.mcpManager.addServer(config.key, connection);
|
|
12280
13252
|
} catch (err) {
|
|
12281
13253
|
logger5.warn(`Failed to prepare MCP server "${config.key}" for restoration`, { error: err });
|
|
12282
13254
|
}
|
|
12283
13255
|
}
|
|
12284
|
-
await
|
|
13256
|
+
await import_core59.mcpManager.connect();
|
|
12285
13257
|
for (const config of connectedConfigs) {
|
|
12286
13258
|
try {
|
|
12287
|
-
await
|
|
13259
|
+
await import_core59.mcpManager.registerToolsToToolLattice(config.key, config.selectedTools);
|
|
12288
13260
|
logger5.info(`MCP server "${config.key}" restored with ${config.selectedTools.length} tools`);
|
|
12289
13261
|
} catch (err) {
|
|
12290
13262
|
logger5.warn(`Failed to register tools for MCP server "${config.key}"`, { error: err });
|
|
@@ -12317,7 +13289,7 @@ var start = async (config) => {
|
|
|
12317
13289
|
const { getStoreLattice: getStore15 } = await import("@axiom-lattice/core");
|
|
12318
13290
|
const bindingStore = getStore15("default", "channelBinding").store;
|
|
12319
13291
|
const installationStore = getStore15("default", "channelInstallation").store;
|
|
12320
|
-
(0,
|
|
13292
|
+
(0, import_core58.setBindingRegistry)(bindingStore);
|
|
12321
13293
|
const router = new MessageRouter({
|
|
12322
13294
|
middlewares: [
|
|
12323
13295
|
createDeduplicationMiddleware(),
|
|
@@ -12342,10 +13314,10 @@ var start = async (config) => {
|
|
|
12342
13314
|
error: err instanceof Error ? err.message : String(err)
|
|
12343
13315
|
});
|
|
12344
13316
|
}
|
|
12345
|
-
(0,
|
|
13317
|
+
(0, import_core58.setEvalRunService)(evalRunner);
|
|
12346
13318
|
try {
|
|
12347
|
-
const menuStore = (0,
|
|
12348
|
-
(0,
|
|
13319
|
+
const menuStore = (0, import_core59.getStoreLattice)("default", "menu").store;
|
|
13320
|
+
(0, import_core58.setMenuRegistry)(menuStore);
|
|
12349
13321
|
logger5.info("Menu registry initialized");
|
|
12350
13322
|
} catch {
|
|
12351
13323
|
}
|
|
@@ -12354,17 +13326,17 @@ var start = async (config) => {
|
|
|
12354
13326
|
setChannelControllerDeps({ adapterRegistry, router: channelDeps.router });
|
|
12355
13327
|
}
|
|
12356
13328
|
registerLatticeRoutes(app, channelDeps);
|
|
12357
|
-
if (!
|
|
12358
|
-
|
|
13329
|
+
if (!import_core59.sandboxLatticeManager.hasLattice("default")) {
|
|
13330
|
+
import_core59.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
|
|
12359
13331
|
logger5.info("Registered sandbox manager from env configuration");
|
|
12360
13332
|
}
|
|
12361
13333
|
try {
|
|
12362
13334
|
const { ResourceController: ResourceController2 } = await Promise.resolve().then(() => (init_resources(), resources_exports));
|
|
12363
|
-
const sharedResourceStore = (0,
|
|
12364
|
-
const cache = new
|
|
13335
|
+
const sharedResourceStore = (0, import_core59.getStoreLattice)("default", "sharedResource").store;
|
|
13336
|
+
const cache = new import_core59.TokenCache();
|
|
12365
13337
|
const resourceController = new ResourceController2({
|
|
12366
13338
|
store: sharedResourceStore,
|
|
12367
|
-
sandboxManager:
|
|
13339
|
+
sandboxManager: import_core59.sandboxLatticeManager,
|
|
12368
13340
|
cache,
|
|
12369
13341
|
logger: logger5
|
|
12370
13342
|
});
|
|
@@ -12391,11 +13363,6 @@ var start = async (config) => {
|
|
|
12391
13363
|
const target_port = config?.port || Number(process.env.PORT) || 4001;
|
|
12392
13364
|
await app.listen({ port: target_port, host: "0.0.0.0" });
|
|
12393
13365
|
logger5.info(`Lattice Gateway is running on port: ${target_port}`);
|
|
12394
|
-
try {
|
|
12395
|
-
logger5.info("AgentLifecycleManager initialized");
|
|
12396
|
-
} catch (error) {
|
|
12397
|
-
logger5.warn("Failed to initialize AgentLifecycleManager", { error });
|
|
12398
|
-
}
|
|
12399
13366
|
const queueServiceConfig = config?.queueServiceConfig;
|
|
12400
13367
|
if (queueServiceConfig) {
|
|
12401
13368
|
setQueueServiceType(queueServiceConfig.type);
|
|
@@ -12405,7 +13372,7 @@ var start = async (config) => {
|
|
|
12405
13372
|
}
|
|
12406
13373
|
}
|
|
12407
13374
|
if (process.env.AXIOM_RESTORE_PENDING_ON_STARTUP === "true") {
|
|
12408
|
-
|
|
13375
|
+
import_core59.agentInstanceManager.restore().then((stats) => {
|
|
12409
13376
|
logger5.info(`Agent recovery complete: ${stats.restored} threads restored, ${stats.errors} errors`);
|
|
12410
13377
|
}).catch((error) => {
|
|
12411
13378
|
logger5.error("Agent recovery failed", { error });
|