@axiom-lattice/gateway 3.0.9 → 4.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/dist/A2AAuthService-DK5X6VIL.mjs +11 -0
- package/dist/A2AAuthService-DK5X6VIL.mjs.map +1 -0
- package/dist/a2a-7N3WDAOP.mjs +147 -0
- package/dist/a2a-7N3WDAOP.mjs.map +1 -0
- package/dist/a2a-standard-U2XYG45L.mjs +1376 -0
- package/dist/a2a-standard-U2XYG45L.mjs.map +1 -0
- package/dist/chunk-2HOCF46L.mjs +143 -0
- package/dist/chunk-2HOCF46L.mjs.map +1 -0
- package/dist/chunk-IDOEIBCF.mjs +165 -0
- package/dist/chunk-IDOEIBCF.mjs.map +1 -0
- package/dist/index.js +3450 -1637
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1635 -1065
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -6
- package/dist/a2a-QMHEH3ZT.mjs +0 -615
- package/dist/a2a-QMHEH3ZT.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -6,6 +6,15 @@ import {
|
|
|
6
6
|
getQrCode,
|
|
7
7
|
getQrCodeStatus
|
|
8
8
|
} from "./chunk-6CUQGDJI.mjs";
|
|
9
|
+
import {
|
|
10
|
+
PathOutsideRootError,
|
|
11
|
+
ProjectFileValidationError,
|
|
12
|
+
filesystemRootDirectory,
|
|
13
|
+
isBinaryContentType,
|
|
14
|
+
isPathWithinRoot,
|
|
15
|
+
resolvePathWithinRoot,
|
|
16
|
+
saveProjectFile
|
|
17
|
+
} from "./chunk-IDOEIBCF.mjs";
|
|
9
18
|
import {
|
|
10
19
|
getContentTypeFromFilename,
|
|
11
20
|
getFilenameFromPath
|
|
@@ -59,8 +68,8 @@ function resolveLocalA2AWorkingDirectory(options) {
|
|
|
59
68
|
}
|
|
60
69
|
function validateWorkingDirectory(cwd) {
|
|
61
70
|
try {
|
|
62
|
-
const
|
|
63
|
-
if (!
|
|
71
|
+
const stat = statSync(cwd);
|
|
72
|
+
if (!stat.isDirectory()) {
|
|
64
73
|
return `Working directory is not a directory: ${cwd}`;
|
|
65
74
|
}
|
|
66
75
|
return null;
|
|
@@ -739,17 +748,17 @@ async function getAssistantStats(request, reply) {
|
|
|
739
748
|
try {
|
|
740
749
|
const threads = await threadStore.getThreadsByAssistantId(tenantId, assistant.id);
|
|
741
750
|
threadCount = threads.length;
|
|
742
|
-
for (const
|
|
743
|
-
const created = new Date(
|
|
751
|
+
for (const t2 of threads) {
|
|
752
|
+
const created = new Date(t2.createdAt).getTime();
|
|
744
753
|
if (created >= now - ms7d) last7d++;
|
|
745
754
|
if (created >= now - ms30d) last30d++;
|
|
746
755
|
const idx7 = Math.floor((now - created) / 864e5);
|
|
747
756
|
if (idx7 >= 0 && idx7 < 7) daily7d[6 - idx7]++;
|
|
748
757
|
const idx30 = Math.floor((now - created) / 864e5);
|
|
749
758
|
if (idx30 >= 0 && idx30 < 30) daily30d[29 - idx30]++;
|
|
750
|
-
const updated = new Date(
|
|
759
|
+
const updated = new Date(t2.updatedAt).getTime();
|
|
751
760
|
if (lastActive === null || updated > lastActive.getTime()) {
|
|
752
|
-
lastActive = new Date(
|
|
761
|
+
lastActive = new Date(t2.updatedAt);
|
|
753
762
|
}
|
|
754
763
|
}
|
|
755
764
|
} catch {
|
|
@@ -895,7 +904,7 @@ var createRun = async (request, reply) => {
|
|
|
895
904
|
|
|
896
905
|
`);
|
|
897
906
|
if (!success) {
|
|
898
|
-
await new Promise((
|
|
907
|
+
await new Promise((resolve2) => reply.raw.once("drain", resolve2));
|
|
899
908
|
}
|
|
900
909
|
}
|
|
901
910
|
} catch (error) {
|
|
@@ -2183,11 +2192,11 @@ var CollectionService = class {
|
|
|
2183
2192
|
async getAllCollections(request) {
|
|
2184
2193
|
const tenantId = getTenantId5(request);
|
|
2185
2194
|
const collections = await collectionLatticeManager.getAllCollections(tenantId);
|
|
2186
|
-
for (const
|
|
2195
|
+
for (const c2 of collections) {
|
|
2187
2196
|
try {
|
|
2188
|
-
|
|
2197
|
+
c2._entryCount = await getCollectionEntryCount(c2.name, c2.embeddingKey, c2.tenantId);
|
|
2189
2198
|
} catch {
|
|
2190
|
-
|
|
2199
|
+
c2._entryCount = 0;
|
|
2191
2200
|
}
|
|
2192
2201
|
}
|
|
2193
2202
|
return collections;
|
|
@@ -3041,7 +3050,7 @@ async function getInboxItems(request, reply) {
|
|
|
3041
3050
|
const runStatus = await agent.getRunStatus();
|
|
3042
3051
|
if (runStatus !== "interrupted") return [];
|
|
3043
3052
|
const state = await agent.getCurrentState();
|
|
3044
|
-
const interrupts = state.tasks?.flatMap((
|
|
3053
|
+
const interrupts = state.tasks?.flatMap((t2) => t2.interrupts || []) || [];
|
|
3045
3054
|
return interrupts.map((i) => ({
|
|
3046
3055
|
runId: r.id,
|
|
3047
3056
|
assistantId: r.assistantId,
|
|
@@ -3398,7 +3407,8 @@ async function createPersonalAssistant(request, reply) {
|
|
|
3398
3407
|
const wsId = getWorkspaceId2(request);
|
|
3399
3408
|
await projectStore.createProject(tenantId, wsId, projectId, {
|
|
3400
3409
|
name: `${name}'s Space`,
|
|
3401
|
-
description: "Personal workspace for your assistant"
|
|
3410
|
+
description: "Personal workspace for your assistant",
|
|
3411
|
+
kind: "personal"
|
|
3402
3412
|
});
|
|
3403
3413
|
const config = PersonalAssistantConfig.get();
|
|
3404
3414
|
config.key = assistantId;
|
|
@@ -3448,8 +3458,8 @@ async function deletePersonalAssistant(request, reply) {
|
|
|
3448
3458
|
const threadStore = getStoreLattice5("default", "thread").store;
|
|
3449
3459
|
try {
|
|
3450
3460
|
const threads = await threadStore.getThreadsByAssistantId(tenantId, assistant.id);
|
|
3451
|
-
for (const
|
|
3452
|
-
await threadStore.deleteThread(tenantId,
|
|
3461
|
+
for (const t2 of threads) {
|
|
3462
|
+
await threadStore.deleteThread(tenantId, t2.id);
|
|
3453
3463
|
}
|
|
3454
3464
|
} catch {
|
|
3455
3465
|
}
|
|
@@ -3469,170 +3479,19 @@ async function deletePersonalAssistant(request, reply) {
|
|
|
3469
3479
|
return { success: true, message: "Personal assistant deleted" };
|
|
3470
3480
|
}
|
|
3471
3481
|
|
|
3472
|
-
// src/controllers/tasks.ts
|
|
3473
|
-
import { getStoreLattice as getStoreLattice6 } from "@axiom-lattice/core";
|
|
3474
|
-
function getTenantId9(request) {
|
|
3475
|
-
const userTenantId = request.user?.tenantId;
|
|
3476
|
-
if (userTenantId) return userTenantId;
|
|
3477
|
-
return request.headers["x-tenant-id"] || "default";
|
|
3478
|
-
}
|
|
3479
|
-
function getUserId4(request) {
|
|
3480
|
-
const userId = request.user?.id || request.headers["x-user-id"];
|
|
3481
|
-
if (!userId) throw new Error("User ID is required");
|
|
3482
|
-
return userId;
|
|
3483
|
-
}
|
|
3484
|
-
function getStore() {
|
|
3485
|
-
return getStoreLattice6("default", "task").store;
|
|
3486
|
-
}
|
|
3487
|
-
async function listTasks(request, reply) {
|
|
3488
|
-
try {
|
|
3489
|
-
const tenantId = getTenantId9(request);
|
|
3490
|
-
const query = request.query;
|
|
3491
|
-
const store = getStore();
|
|
3492
|
-
const tasks = await store.list({
|
|
3493
|
-
tenantId,
|
|
3494
|
-
status: query.status,
|
|
3495
|
-
priority: query.priority,
|
|
3496
|
-
...query.ownerId && { ownerId: query.ownerId },
|
|
3497
|
-
...query.ownerType && { ownerType: query.ownerType },
|
|
3498
|
-
...query.parentId && { parentId: query.parentId },
|
|
3499
|
-
metadata: query.metadata ? JSON.parse(query.metadata) : void 0,
|
|
3500
|
-
projectId: query.projectId,
|
|
3501
|
-
limit: query.limit ? parseInt(query.limit) : void 0,
|
|
3502
|
-
offset: query.offset ? parseInt(query.offset) : void 0
|
|
3503
|
-
});
|
|
3504
|
-
return { success: true, data: tasks, count: tasks.length };
|
|
3505
|
-
} catch (error) {
|
|
3506
|
-
return { success: false, error: error.message };
|
|
3507
|
-
}
|
|
3508
|
-
}
|
|
3509
|
-
async function getTask(request, reply) {
|
|
3510
|
-
try {
|
|
3511
|
-
const tenantId = getTenantId9(request);
|
|
3512
|
-
const userId = getUserId4(request);
|
|
3513
|
-
const { id } = request.params;
|
|
3514
|
-
const store = getStore();
|
|
3515
|
-
const task = await store.getById(tenantId, id);
|
|
3516
|
-
if (!task) {
|
|
3517
|
-
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
3518
|
-
}
|
|
3519
|
-
if (task.ownerType === "user" && task.ownerId !== userId) {
|
|
3520
|
-
return reply.status(403).send({ success: false, error: "Access denied" });
|
|
3521
|
-
}
|
|
3522
|
-
return { success: true, data: task };
|
|
3523
|
-
} catch (error) {
|
|
3524
|
-
return { success: false, error: error.message };
|
|
3525
|
-
}
|
|
3526
|
-
}
|
|
3527
|
-
async function createTask(request, reply) {
|
|
3528
|
-
try {
|
|
3529
|
-
const tenantId = getTenantId9(request);
|
|
3530
|
-
const userId = getUserId4(request);
|
|
3531
|
-
const body = request.body;
|
|
3532
|
-
if (!body.title) {
|
|
3533
|
-
return reply.status(400).send({ success: false, error: "title is required" });
|
|
3534
|
-
}
|
|
3535
|
-
const store = getStore();
|
|
3536
|
-
const task = await store.create({
|
|
3537
|
-
...body,
|
|
3538
|
-
tenantId,
|
|
3539
|
-
ownerType: body.ownerType || "user",
|
|
3540
|
-
ownerId: body.ownerId || userId
|
|
3541
|
-
});
|
|
3542
|
-
return reply.status(201).send({ success: true, data: task });
|
|
3543
|
-
} catch (error) {
|
|
3544
|
-
return reply.status(500).send({ success: false, error: error.message });
|
|
3545
|
-
}
|
|
3546
|
-
}
|
|
3547
|
-
async function updateTask(request, reply) {
|
|
3548
|
-
try {
|
|
3549
|
-
const tenantId = getTenantId9(request);
|
|
3550
|
-
const userId = getUserId4(request);
|
|
3551
|
-
const { id } = request.params;
|
|
3552
|
-
const store = getStore();
|
|
3553
|
-
const existing = await store.getById(tenantId, id);
|
|
3554
|
-
if (!existing) {
|
|
3555
|
-
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
3556
|
-
}
|
|
3557
|
-
if (existing.ownerType === "user" && existing.ownerId !== userId) {
|
|
3558
|
-
return reply.status(403).send({ success: false, error: "Access denied" });
|
|
3559
|
-
}
|
|
3560
|
-
const task = await store.update(tenantId, id, request.body);
|
|
3561
|
-
if (!task) {
|
|
3562
|
-
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
3563
|
-
}
|
|
3564
|
-
return { success: true, data: task };
|
|
3565
|
-
} catch (error) {
|
|
3566
|
-
return reply.status(500).send({ success: false, error: error.message });
|
|
3567
|
-
}
|
|
3568
|
-
}
|
|
3569
|
-
async function deleteTask(request, reply) {
|
|
3570
|
-
try {
|
|
3571
|
-
const tenantId = getTenantId9(request);
|
|
3572
|
-
const userId = getUserId4(request);
|
|
3573
|
-
const { id } = request.params;
|
|
3574
|
-
const store = getStore();
|
|
3575
|
-
const existing = await store.getById(tenantId, id);
|
|
3576
|
-
if (!existing) {
|
|
3577
|
-
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
3578
|
-
}
|
|
3579
|
-
if (existing.ownerType === "user" && existing.ownerId !== userId) {
|
|
3580
|
-
return reply.status(403).send({ success: false, error: "Access denied" });
|
|
3581
|
-
}
|
|
3582
|
-
const deleted = await store.delete(tenantId, id);
|
|
3583
|
-
if (!deleted) {
|
|
3584
|
-
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
3585
|
-
}
|
|
3586
|
-
return { success: true, message: "Task deleted" };
|
|
3587
|
-
} catch (error) {
|
|
3588
|
-
return reply.status(500).send({ success: false, error: error.message });
|
|
3589
|
-
}
|
|
3590
|
-
}
|
|
3591
|
-
async function completeTask(request, reply) {
|
|
3592
|
-
try {
|
|
3593
|
-
const tenantId = getTenantId9(request);
|
|
3594
|
-
const userId = getUserId4(request);
|
|
3595
|
-
const { id } = request.params;
|
|
3596
|
-
const store = getStore();
|
|
3597
|
-
const existing = await store.getById(tenantId, id);
|
|
3598
|
-
if (!existing) {
|
|
3599
|
-
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
3600
|
-
}
|
|
3601
|
-
if (existing.ownerType === "user" && existing.ownerId !== userId) {
|
|
3602
|
-
return reply.status(403).send({ success: false, error: "Access denied" });
|
|
3603
|
-
}
|
|
3604
|
-
const task = await store.update(tenantId, id, { status: "completed" });
|
|
3605
|
-
if (!task) {
|
|
3606
|
-
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
3607
|
-
}
|
|
3608
|
-
return { success: true, data: task };
|
|
3609
|
-
} catch (error) {
|
|
3610
|
-
return reply.status(500).send({ success: false, error: error.message });
|
|
3611
|
-
}
|
|
3612
|
-
}
|
|
3613
|
-
function getTaskWorkItemStore() {
|
|
3614
|
-
return getStoreLattice6("default", "taskWorkItem").store;
|
|
3615
|
-
}
|
|
3616
|
-
async function listTaskWorkItems(request, reply) {
|
|
3617
|
-
const tenantId = getTenantId9(request);
|
|
3618
|
-
const { id } = request.params;
|
|
3619
|
-
const { action, limit, offset } = request.query;
|
|
3620
|
-
const store = getTaskWorkItemStore();
|
|
3621
|
-
const items = await store.list({
|
|
3622
|
-
tenantId,
|
|
3623
|
-
taskId: id,
|
|
3624
|
-
action,
|
|
3625
|
-
limit: limit ? Number(limit) : void 0,
|
|
3626
|
-
offset: offset ? Number(offset) : void 0
|
|
3627
|
-
});
|
|
3628
|
-
return reply.send({ success: true, data: items });
|
|
3629
|
-
}
|
|
3630
|
-
|
|
3631
3482
|
// src/services/ExportImportService.ts
|
|
3632
|
-
import { ExportableEntityRegistry, DependencyResolver, IdRemapper } from "@axiom-lattice/core";
|
|
3483
|
+
import { ExportableEntityRegistry, DependencyResolver, IdRemapper, isBuiltInSkill } from "@axiom-lattice/core";
|
|
3633
3484
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
3485
|
+
import * as fs from "fs/promises";
|
|
3486
|
+
import * as os from "os";
|
|
3487
|
+
import * as path from "path";
|
|
3488
|
+
import * as tar from "tar";
|
|
3489
|
+
import * as zlib from "zlib";
|
|
3634
3490
|
var exportJobs = /* @__PURE__ */ new Map();
|
|
3635
3491
|
var JOB_TTL_MS = 60 * 60 * 1e3;
|
|
3492
|
+
var MAX_ARCHIVE_ENTRIES = 1e4;
|
|
3493
|
+
var MAX_ARCHIVE_FILE_BYTES = 100 * 1024 * 1024;
|
|
3494
|
+
var MAX_ARCHIVE_TOTAL_BYTES = 512 * 1024 * 1024;
|
|
3636
3495
|
function cleanExpiredJobs() {
|
|
3637
3496
|
const now = Date.now();
|
|
3638
3497
|
for (const [id, entry] of exportJobs) {
|
|
@@ -3641,6 +3500,9 @@ function cleanExpiredJobs() {
|
|
|
3641
3500
|
}
|
|
3642
3501
|
}
|
|
3643
3502
|
}
|
|
3503
|
+
function archiveFileKey(entityType, entityId, relPath) {
|
|
3504
|
+
return `files/${entityType}/${entityId}/${relPath}`;
|
|
3505
|
+
}
|
|
3644
3506
|
var ExportImportService = class {
|
|
3645
3507
|
constructor() {
|
|
3646
3508
|
this.registry = ExportableEntityRegistry.getInstance();
|
|
@@ -3648,40 +3510,44 @@ var ExportImportService = class {
|
|
|
3648
3510
|
/**
|
|
3649
3511
|
* Preview an export: check which types would be auto-included, which dependencies are missing.
|
|
3650
3512
|
*/
|
|
3651
|
-
async exportPreview(tenantId, selectedTypes) {
|
|
3513
|
+
async exportPreview(tenantId, selectedTypes, entityIds, context) {
|
|
3652
3514
|
const allDefs = this.registry.getAll();
|
|
3653
3515
|
const expanded = DependencyResolver.expandCascade(allDefs, selectedTypes);
|
|
3654
|
-
const cascadeAdditions = expanded.filter((
|
|
3516
|
+
const cascadeAdditions = expanded.filter((t2) => !selectedTypes.includes(t2));
|
|
3655
3517
|
const deps = DependencyResolver.computeDependencies(allDefs, expanded);
|
|
3656
3518
|
const registeredTypes = new Set(allDefs.map((d) => d.entityType));
|
|
3657
|
-
const missingDependencies = deps.missing.filter((
|
|
3519
|
+
const missingDependencies = deps.missing.filter((t2) => registeredTypes.has(t2));
|
|
3520
|
+
await this.resolveExportSelection(tenantId, selectedTypes, entityIds, context);
|
|
3658
3521
|
return { missingDependencies, cascadeAdditions };
|
|
3659
3522
|
}
|
|
3660
3523
|
/**
|
|
3661
|
-
* Generate a full
|
|
3662
|
-
* Stores the
|
|
3524
|
+
* Generate a full export (bundle + file content) for the given tenant and entity types.
|
|
3525
|
+
* Stores the data in-memory and returns a jobId for download.
|
|
3663
3526
|
*/
|
|
3664
|
-
async export(tenantId, entityTypes, entityIds) {
|
|
3665
|
-
const
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3527
|
+
async export(tenantId, entityTypes, entityIds, context) {
|
|
3528
|
+
const { dependencyOrder, entities: rawEntities } = await this.resolveExportSelection(
|
|
3529
|
+
tenantId,
|
|
3530
|
+
entityTypes,
|
|
3531
|
+
entityIds,
|
|
3532
|
+
context
|
|
3670
3533
|
);
|
|
3671
3534
|
const entities = {};
|
|
3535
|
+
const files = /* @__PURE__ */ new Map();
|
|
3672
3536
|
let exportCounter = 0;
|
|
3673
3537
|
for (const type of dependencyOrder) {
|
|
3674
3538
|
const def = this.registry.get(type);
|
|
3675
|
-
|
|
3676
|
-
if (entityIds && entityIds[type] && entityIds[type].length > 0) {
|
|
3677
|
-
const idSet = new Set(entityIds[type]);
|
|
3678
|
-
raw = raw.filter((e) => idSet.has(e.data.id));
|
|
3679
|
-
}
|
|
3539
|
+
const raw = rawEntities[type];
|
|
3680
3540
|
entities[type] = raw.map((e) => ({
|
|
3681
3541
|
...e,
|
|
3682
3542
|
_exportId: `exp-${type}-${String(++exportCounter).padStart(3, "0")}`,
|
|
3683
3543
|
data: this.sanitizeEntityData(e.data)
|
|
3684
3544
|
}));
|
|
3545
|
+
if (def.listFilesForExport && entities[type].length > 0) {
|
|
3546
|
+
const entityFiles = await def.listFilesForExport(tenantId, entities[type], context);
|
|
3547
|
+
for (const f of entityFiles) {
|
|
3548
|
+
files.set(archiveFileKey(type, f.entityId, f.path), f.content);
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3685
3551
|
}
|
|
3686
3552
|
const rawIdToExportId = /* @__PURE__ */ new Map();
|
|
3687
3553
|
for (const [, entityList] of Object.entries(entities)) {
|
|
@@ -3716,31 +3582,193 @@ var ExportImportService = class {
|
|
|
3716
3582
|
_warning: "This file contains plaintext secrets (passwords, API keys, tokens). Store it securely and delete after import."
|
|
3717
3583
|
};
|
|
3718
3584
|
const jobId = randomUUID4();
|
|
3719
|
-
exportJobs.set(jobId, { bundle, tenantId, createdAt: Date.now() });
|
|
3720
|
-
return { jobId, bundle };
|
|
3585
|
+
exportJobs.set(jobId, { data: { bundle, files }, tenantId, createdAt: Date.now() });
|
|
3586
|
+
return { jobId, data: { bundle, files } };
|
|
3721
3587
|
}
|
|
3722
3588
|
/**
|
|
3723
|
-
* Retrieve a previously generated export
|
|
3589
|
+
* Retrieve a previously generated export job data by jobId with tenant validation.
|
|
3724
3590
|
*/
|
|
3725
3591
|
getExportJob(jobId, tenantId) {
|
|
3726
3592
|
cleanExpiredJobs();
|
|
3727
3593
|
const entry = exportJobs.get(jobId);
|
|
3728
3594
|
if (!entry || entry.tenantId !== tenantId) return void 0;
|
|
3729
|
-
return entry.
|
|
3595
|
+
return entry.data;
|
|
3596
|
+
}
|
|
3597
|
+
/**
|
|
3598
|
+
* Pack an ExportJobData into a tar.gz buffer.
|
|
3599
|
+
* Layout: bundle.json at root, files under files/{entityType}/{entityId}/{path}.
|
|
3600
|
+
*/
|
|
3601
|
+
async packTarGz(data) {
|
|
3602
|
+
const { bundle, files } = data;
|
|
3603
|
+
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "lattice-export-"));
|
|
3604
|
+
try {
|
|
3605
|
+
await fs.writeFile(path.join(tmpDir, "bundle.json"), JSON.stringify(bundle, null, 2), "utf-8");
|
|
3606
|
+
for (const [relPath, content] of files.entries()) {
|
|
3607
|
+
const fullPath = path.join(tmpDir, relPath);
|
|
3608
|
+
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
3609
|
+
await fs.writeFile(fullPath, content);
|
|
3610
|
+
}
|
|
3611
|
+
const stream = tar.c({ gzip: true, portable: true, cwd: tmpDir }, ["./bundle.json", ...Array.from(files.keys())]);
|
|
3612
|
+
const chunks = [];
|
|
3613
|
+
for await (const chunk of stream) {
|
|
3614
|
+
chunks.push(Buffer.from(chunk));
|
|
3615
|
+
}
|
|
3616
|
+
return Buffer.concat(chunks);
|
|
3617
|
+
} finally {
|
|
3618
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
3619
|
+
}
|
|
3620
|
+
}
|
|
3621
|
+
/**
|
|
3622
|
+
* Unpack a tar.gz buffer into an ExportJobData (bundle + files).
|
|
3623
|
+
*/
|
|
3624
|
+
async unpackTarGz(buffer) {
|
|
3625
|
+
const files = /* @__PURE__ */ new Map();
|
|
3626
|
+
let bundle;
|
|
3627
|
+
const gunzip = zlib.createGunzip();
|
|
3628
|
+
await new Promise((resolve2, reject) => {
|
|
3629
|
+
let settled = false;
|
|
3630
|
+
let entryCount = 0;
|
|
3631
|
+
let declaredTotalBytes = 0;
|
|
3632
|
+
let decompressedBytes = 0;
|
|
3633
|
+
let activeEntry;
|
|
3634
|
+
const paths = /* @__PURE__ */ new Set();
|
|
3635
|
+
const fail = (reason) => {
|
|
3636
|
+
if (settled) return;
|
|
3637
|
+
settled = true;
|
|
3638
|
+
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
3639
|
+
reject(error);
|
|
3640
|
+
try {
|
|
3641
|
+
activeEntry?.destroy(error);
|
|
3642
|
+
} catch {
|
|
3643
|
+
}
|
|
3644
|
+
try {
|
|
3645
|
+
parser.abort(error);
|
|
3646
|
+
} catch {
|
|
3647
|
+
}
|
|
3648
|
+
gunzip.destroy(error);
|
|
3649
|
+
};
|
|
3650
|
+
const countEntry = () => {
|
|
3651
|
+
entryCount += 1;
|
|
3652
|
+
if (entryCount <= MAX_ARCHIVE_ENTRIES) return true;
|
|
3653
|
+
fail(new Error(`Invalid export archive: exceeds ${MAX_ARCHIVE_ENTRIES.toLocaleString("en-US")} entries`));
|
|
3654
|
+
return false;
|
|
3655
|
+
};
|
|
3656
|
+
const parser = tar.t({
|
|
3657
|
+
gzip: false,
|
|
3658
|
+
onentry: (entry) => {
|
|
3659
|
+
activeEntry = entry;
|
|
3660
|
+
if (!countEntry()) return;
|
|
3661
|
+
entry.on("error", fail);
|
|
3662
|
+
entry.on("end", () => {
|
|
3663
|
+
if (activeEntry === entry) activeEntry = void 0;
|
|
3664
|
+
});
|
|
3665
|
+
const isDirectory = entry.type === "Directory";
|
|
3666
|
+
if (!isDirectory && entry.type !== "File" && entry.type !== "OldFile") {
|
|
3667
|
+
fail(new Error(`Invalid export archive: unsupported entry type "${entry.type}"`));
|
|
3668
|
+
return;
|
|
3669
|
+
}
|
|
3670
|
+
const rawPath = entry.path;
|
|
3671
|
+
if (rawPath.startsWith("/") || rawPath.includes("\\") || rawPath.includes("\0")) {
|
|
3672
|
+
fail(new Error(`Invalid export archive path: "${rawPath}"`));
|
|
3673
|
+
return;
|
|
3674
|
+
}
|
|
3675
|
+
const entryPath = rawPath.startsWith("./") ? rawPath.slice(2) : rawPath;
|
|
3676
|
+
const pathToValidate = isDirectory && entryPath.endsWith("/") ? entryPath.slice(0, -1) : entryPath;
|
|
3677
|
+
const segments = pathToValidate.split("/");
|
|
3678
|
+
if (segments.some((segment) => segment === "" || segment === "." || segment === "..") || (isDirectory ? !(pathToValidate === "files" || pathToValidate.startsWith("files/")) : entryPath !== "bundle.json" && !(entryPath.startsWith("files/") && segments.length > 1))) {
|
|
3679
|
+
fail(new Error(`Invalid export archive path: "${rawPath}"`));
|
|
3680
|
+
return;
|
|
3681
|
+
}
|
|
3682
|
+
if (isDirectory) {
|
|
3683
|
+
entry.resume();
|
|
3684
|
+
return;
|
|
3685
|
+
}
|
|
3686
|
+
if (paths.has(entryPath)) {
|
|
3687
|
+
fail(new Error(`Invalid export archive: duplicate path "${entryPath}"`));
|
|
3688
|
+
return;
|
|
3689
|
+
}
|
|
3690
|
+
paths.add(entryPath);
|
|
3691
|
+
if (!Number.isSafeInteger(entry.size) || entry.size < 0 || entry.size > MAX_ARCHIVE_FILE_BYTES) {
|
|
3692
|
+
fail(new Error("Invalid export archive: regular file size exceeds 100 MB"));
|
|
3693
|
+
return;
|
|
3694
|
+
}
|
|
3695
|
+
declaredTotalBytes += entry.size;
|
|
3696
|
+
if (declaredTotalBytes > MAX_ARCHIVE_TOTAL_BYTES) {
|
|
3697
|
+
fail(new Error("Invalid export archive: total uncompressed size exceeds 512 MB"));
|
|
3698
|
+
return;
|
|
3699
|
+
}
|
|
3700
|
+
const chunks = [];
|
|
3701
|
+
let streamedEntryBytes = 0;
|
|
3702
|
+
entry.on("data", (chunk) => {
|
|
3703
|
+
if (settled) return;
|
|
3704
|
+
streamedEntryBytes += chunk.length;
|
|
3705
|
+
if (streamedEntryBytes > MAX_ARCHIVE_FILE_BYTES) {
|
|
3706
|
+
fail(new Error("Invalid export archive: regular file size exceeds 100 MB"));
|
|
3707
|
+
return;
|
|
3708
|
+
}
|
|
3709
|
+
chunks.push(chunk);
|
|
3710
|
+
});
|
|
3711
|
+
entry.on("end", () => {
|
|
3712
|
+
if (settled) return;
|
|
3713
|
+
const content = Buffer.concat(chunks, streamedEntryBytes);
|
|
3714
|
+
if (entryPath === "bundle.json") {
|
|
3715
|
+
try {
|
|
3716
|
+
bundle = JSON.parse(content.toString("utf-8"));
|
|
3717
|
+
} catch (error) {
|
|
3718
|
+
fail(new Error(
|
|
3719
|
+
`Invalid export archive: malformed bundle.json: ${error instanceof Error ? error.message : String(error)}`
|
|
3720
|
+
));
|
|
3721
|
+
}
|
|
3722
|
+
} else {
|
|
3723
|
+
files.set(entryPath, content);
|
|
3724
|
+
}
|
|
3725
|
+
});
|
|
3726
|
+
}
|
|
3727
|
+
});
|
|
3728
|
+
gunzip.on("data", (chunk) => {
|
|
3729
|
+
if (settled) return;
|
|
3730
|
+
decompressedBytes += chunk.length;
|
|
3731
|
+
if (decompressedBytes > MAX_ARCHIVE_TOTAL_BYTES) {
|
|
3732
|
+
fail(new Error("Invalid export archive: total uncompressed size exceeds 512 MB"));
|
|
3733
|
+
}
|
|
3734
|
+
});
|
|
3735
|
+
gunzip.on("error", fail);
|
|
3736
|
+
parser.on("ignoredEntry", (entry) => {
|
|
3737
|
+
if (!countEntry()) return;
|
|
3738
|
+
fail(new Error(`Invalid export archive: unsupported entry type "${entry.type}"`));
|
|
3739
|
+
});
|
|
3740
|
+
parser.on("meta", () => {
|
|
3741
|
+
if (!countEntry()) return;
|
|
3742
|
+
fail(new Error("Invalid export archive: unsupported metadata entry"));
|
|
3743
|
+
});
|
|
3744
|
+
parser.on("error", fail);
|
|
3745
|
+
parser.on("end", () => {
|
|
3746
|
+
if (settled) return;
|
|
3747
|
+
settled = true;
|
|
3748
|
+
resolve2();
|
|
3749
|
+
});
|
|
3750
|
+
gunzip.pipe(parser);
|
|
3751
|
+
gunzip.end(buffer);
|
|
3752
|
+
});
|
|
3753
|
+
if (!bundle) {
|
|
3754
|
+
throw new Error("Invalid export archive: missing bundle.json");
|
|
3755
|
+
}
|
|
3756
|
+
return { bundle, files };
|
|
3730
3757
|
}
|
|
3731
3758
|
/**
|
|
3732
3759
|
* Preview import: validate bundle and detect conflicts.
|
|
3733
3760
|
*/
|
|
3734
|
-
async previewImport(tenantId, bundle) {
|
|
3735
|
-
this.validateBundle(bundle);
|
|
3761
|
+
async previewImport(tenantId, bundle, context) {
|
|
3762
|
+
const dependencyOrder = this.validateBundle(bundle);
|
|
3736
3763
|
const allConflicts = [];
|
|
3737
3764
|
const allInsertions = [];
|
|
3738
3765
|
const allErrors = [];
|
|
3739
|
-
for (const
|
|
3766
|
+
for (const entityType of dependencyOrder) {
|
|
3767
|
+
const entities = bundle.entities[entityType];
|
|
3740
3768
|
if (entities.length === 0) continue;
|
|
3741
3769
|
try {
|
|
3742
3770
|
const def = this.registry.get(entityType);
|
|
3743
|
-
const result = await def.previewImport(tenantId, entities);
|
|
3771
|
+
const result = await def.previewImport(tenantId, entities, context);
|
|
3744
3772
|
allConflicts.push(...result.conflicts);
|
|
3745
3773
|
allInsertions.push(...result.insertions);
|
|
3746
3774
|
allErrors.push(...result.errors);
|
|
@@ -3758,25 +3786,132 @@ var ExportImportService = class {
|
|
|
3758
3786
|
}
|
|
3759
3787
|
/**
|
|
3760
3788
|
* Apply import: create entities in dependency order with ID remapping.
|
|
3789
|
+
* File content (if any) is passed to registrations via the `files` map.
|
|
3761
3790
|
*/
|
|
3762
|
-
async applyImport(tenantId, bundle, resolutions) {
|
|
3763
|
-
this.validateBundle(bundle);
|
|
3791
|
+
async applyImport(tenantId, bundle, resolutions, files, context) {
|
|
3792
|
+
const dependencyOrder = this.validateBundle(bundle);
|
|
3764
3793
|
const results = [];
|
|
3765
3794
|
const idMap = {};
|
|
3795
|
+
const unresolvedExportIds = /* @__PURE__ */ new Set();
|
|
3766
3796
|
const skillIdRemap = {};
|
|
3767
|
-
|
|
3797
|
+
const skillSourceToTarget = /* @__PURE__ */ new Map();
|
|
3798
|
+
const unresolvedSkillReferences = /* @__PURE__ */ new Map();
|
|
3799
|
+
const skillEntities = bundle.entities.skill ?? [];
|
|
3800
|
+
const skillConflicts = skillEntities.length > 0 ? await this.registry.get("skill").previewImport(tenantId, skillEntities, context) : { conflicts: [] };
|
|
3801
|
+
const skillConflictByExportId = new Map(
|
|
3802
|
+
skillConflicts.conflicts.map((conflict) => [conflict._exportId, conflict])
|
|
3803
|
+
);
|
|
3804
|
+
for (const entity of skillEntities) {
|
|
3805
|
+
const resolution = resolutions[entity._exportId];
|
|
3806
|
+
const sourceId = entity.data.id;
|
|
3807
|
+
const targetId = resolution?.action === "skip" ? skillConflictByExportId.get(entity._exportId)?.existingId : resolution?.action === "rename" && resolution.newId ? resolution.newId : sourceId;
|
|
3808
|
+
if (targetId) skillSourceToTarget.set(sourceId, targetId);
|
|
3809
|
+
}
|
|
3810
|
+
for (const entity of skillEntities) {
|
|
3811
|
+
const subSkills = entity.data.subSkills;
|
|
3812
|
+
if (!Array.isArray(subSkills)) continue;
|
|
3813
|
+
const unresolved = subSkills.find((id) => typeof id === "string" && !skillSourceToTarget.has(id) && !isBuiltInSkill(id));
|
|
3814
|
+
if (unresolved) unresolvedSkillReferences.set(entity._exportId, unresolved);
|
|
3815
|
+
}
|
|
3816
|
+
for (const entityType of dependencyOrder) {
|
|
3768
3817
|
const entities = bundle.entities[entityType];
|
|
3769
3818
|
if (!entities || entities.length === 0) continue;
|
|
3770
3819
|
const def = this.registry.get(entityType);
|
|
3771
3820
|
const remapper = new IdRemapper(idMap);
|
|
3821
|
+
let insertions = /* @__PURE__ */ new Set();
|
|
3822
|
+
let conflicts = /* @__PURE__ */ new Set();
|
|
3823
|
+
let conflictByExportId = /* @__PURE__ */ new Map();
|
|
3824
|
+
let previewError;
|
|
3825
|
+
try {
|
|
3826
|
+
const preview = await def.previewImport(tenantId, entities, context);
|
|
3827
|
+
insertions = new Set(preview.insertions.map((item) => item._exportId));
|
|
3828
|
+
conflicts = new Set(preview.conflicts.map((item) => item._exportId));
|
|
3829
|
+
conflictByExportId = new Map(preview.conflicts.map((item) => [item._exportId, item]));
|
|
3830
|
+
} catch (err) {
|
|
3831
|
+
previewError = err.message;
|
|
3832
|
+
}
|
|
3772
3833
|
for (const entity of entities) {
|
|
3773
|
-
|
|
3834
|
+
let resolution = resolutions[entity._exportId];
|
|
3774
3835
|
if (resolution?.action === "skip") {
|
|
3775
|
-
|
|
3836
|
+
const conflict = conflictByExportId.get(entity._exportId);
|
|
3837
|
+
if (conflict && !conflict.existingId) {
|
|
3838
|
+
unresolvedExportIds.add(entity._exportId);
|
|
3839
|
+
results.push({
|
|
3840
|
+
_exportId: entity._exportId,
|
|
3841
|
+
entityType,
|
|
3842
|
+
status: "failed",
|
|
3843
|
+
error: "Cannot skip conflict without an existing ID"
|
|
3844
|
+
});
|
|
3845
|
+
continue;
|
|
3846
|
+
}
|
|
3847
|
+
if (conflict?.existingId) {
|
|
3848
|
+
idMap[entity._exportId] = conflict.existingId;
|
|
3849
|
+
}
|
|
3850
|
+
results.push({
|
|
3851
|
+
_exportId: entity._exportId,
|
|
3852
|
+
entityType,
|
|
3853
|
+
status: "skipped",
|
|
3854
|
+
newId: conflict?.existingId
|
|
3855
|
+
});
|
|
3856
|
+
continue;
|
|
3857
|
+
}
|
|
3858
|
+
const pendingValues = [entity.data];
|
|
3859
|
+
let unresolvedReference;
|
|
3860
|
+
while (pendingValues.length > 0 && !unresolvedReference) {
|
|
3861
|
+
const value = pendingValues.pop();
|
|
3862
|
+
if (typeof value === "string") {
|
|
3863
|
+
const match = value.match(/^@\w+\/(.+)$/);
|
|
3864
|
+
if (match && unresolvedExportIds.has(match[1])) {
|
|
3865
|
+
unresolvedReference = match[1];
|
|
3866
|
+
}
|
|
3867
|
+
} else if (Array.isArray(value)) {
|
|
3868
|
+
pendingValues.push(...value);
|
|
3869
|
+
} else if (value && typeof value === "object") {
|
|
3870
|
+
pendingValues.push(...Object.values(value));
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
if (unresolvedReference) {
|
|
3874
|
+
unresolvedExportIds.add(entity._exportId);
|
|
3875
|
+
results.push({
|
|
3876
|
+
_exportId: entity._exportId,
|
|
3877
|
+
entityType,
|
|
3878
|
+
status: "failed",
|
|
3879
|
+
error: `Unresolved reference to failed import entity "${unresolvedReference}"`
|
|
3880
|
+
});
|
|
3776
3881
|
continue;
|
|
3777
3882
|
}
|
|
3883
|
+
if (!resolution) {
|
|
3884
|
+
if (previewError || conflicts.has(entity._exportId) || !insertions.has(entity._exportId)) {
|
|
3885
|
+
results.push({
|
|
3886
|
+
_exportId: entity._exportId,
|
|
3887
|
+
entityType,
|
|
3888
|
+
status: "failed",
|
|
3889
|
+
error: previewError ? `Unable to verify missing conflict resolution: ${previewError}` : "Missing conflict resolution"
|
|
3890
|
+
});
|
|
3891
|
+
continue;
|
|
3892
|
+
}
|
|
3893
|
+
resolution = {
|
|
3894
|
+
_exportId: entity._exportId,
|
|
3895
|
+
action: "insert"
|
|
3896
|
+
};
|
|
3897
|
+
}
|
|
3778
3898
|
try {
|
|
3779
3899
|
const remappedData = remapper.remapReferences(entity.data);
|
|
3900
|
+
if (entityType === "skill") {
|
|
3901
|
+
const unresolvedSkill = unresolvedSkillReferences.get(entity._exportId);
|
|
3902
|
+
if (unresolvedSkill) {
|
|
3903
|
+
results.push({
|
|
3904
|
+
_exportId: entity._exportId,
|
|
3905
|
+
entityType,
|
|
3906
|
+
status: "failed",
|
|
3907
|
+
error: `Unresolved subSkill reference "${unresolvedSkill}"`
|
|
3908
|
+
});
|
|
3909
|
+
continue;
|
|
3910
|
+
}
|
|
3911
|
+
if (Array.isArray(remappedData.subSkills)) {
|
|
3912
|
+
remappedData.subSkills = remappedData.subSkills.map((id) => typeof id === "string" ? skillSourceToTarget.get(id) ?? id : id);
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3780
3915
|
if (entityType === "agent" && Object.keys(skillIdRemap).length > 0) {
|
|
3781
3916
|
const skillRemapper = new IdRemapper({});
|
|
3782
3917
|
remappedData.graphDefinition = skillRemapper.remapSkillIds(
|
|
@@ -3784,19 +3919,26 @@ var ExportImportService = class {
|
|
|
3784
3919
|
skillIdRemap
|
|
3785
3920
|
);
|
|
3786
3921
|
}
|
|
3787
|
-
if (resolution
|
|
3922
|
+
if (resolution.action === "rename" && resolution.newId) {
|
|
3788
3923
|
remappedData.id = resolution.newId;
|
|
3789
3924
|
}
|
|
3925
|
+
const entityFiles = this.extractEntityFiles(
|
|
3926
|
+
entityType,
|
|
3927
|
+
entity.data.id,
|
|
3928
|
+
files
|
|
3929
|
+
);
|
|
3790
3930
|
const entityWithRemappedData = { ...entity, data: remappedData };
|
|
3791
3931
|
const { newId } = await def.applyImport(
|
|
3792
3932
|
tenantId,
|
|
3793
3933
|
entityWithRemappedData,
|
|
3794
|
-
resolution
|
|
3934
|
+
resolution,
|
|
3935
|
+
entityFiles,
|
|
3936
|
+
context
|
|
3795
3937
|
);
|
|
3796
3938
|
if (newId) {
|
|
3797
3939
|
idMap[entity._exportId] = newId;
|
|
3798
3940
|
if (entityType === "skill" && newId) {
|
|
3799
|
-
const oldSkillId =
|
|
3941
|
+
const oldSkillId = entity.data.id;
|
|
3800
3942
|
if (oldSkillId !== newId) {
|
|
3801
3943
|
skillIdRemap[oldSkillId] = newId;
|
|
3802
3944
|
}
|
|
@@ -3804,7 +3946,7 @@ var ExportImportService = class {
|
|
|
3804
3946
|
results.push({
|
|
3805
3947
|
_exportId: entity._exportId,
|
|
3806
3948
|
entityType,
|
|
3807
|
-
status: resolution
|
|
3949
|
+
status: resolution.action === "overwrite" ? "updated" : "created",
|
|
3808
3950
|
newId
|
|
3809
3951
|
});
|
|
3810
3952
|
}
|
|
@@ -3826,43 +3968,292 @@ var ExportImportService = class {
|
|
|
3826
3968
|
listExportableTypes() {
|
|
3827
3969
|
return this.registry.listTypes();
|
|
3828
3970
|
}
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
}
|
|
3836
|
-
|
|
3837
|
-
|
|
3971
|
+
/**
|
|
3972
|
+
* Extract file content for a single entity from the archive files map.
|
|
3973
|
+
* Keys are `files/{entityType}/{entityId}/{path}`; returns a Map of relative path → Buffer.
|
|
3974
|
+
*/
|
|
3975
|
+
extractEntityFiles(entityType, entityId, files) {
|
|
3976
|
+
if (!files || files.size === 0) return void 0;
|
|
3977
|
+
const prefix = `files/${entityType}/${entityId}/`;
|
|
3978
|
+
const result = /* @__PURE__ */ new Map();
|
|
3979
|
+
for (const [path4, content] of files.entries()) {
|
|
3980
|
+
if (path4.startsWith(prefix)) {
|
|
3981
|
+
result.set(path4.slice(prefix.length), content);
|
|
3982
|
+
}
|
|
3838
3983
|
}
|
|
3984
|
+
return result.size > 0 ? result : void 0;
|
|
3839
3985
|
}
|
|
3840
|
-
|
|
3841
|
-
const
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
}
|
|
3986
|
+
async resolveExportSelection(tenantId, entityTypes, entityIds, context) {
|
|
3987
|
+
const allDefs = this.registry.getAll();
|
|
3988
|
+
const registeredTypes = new Set(allDefs.map((def) => def.entityType));
|
|
3989
|
+
for (const type of entityTypes) {
|
|
3990
|
+
if (!registeredTypes.has(type)) {
|
|
3991
|
+
throw new Error(`Exportable entity type is not registered: "${type}"`);
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
const expanded = DependencyResolver.expandCascade(allDefs, entityTypes);
|
|
3995
|
+
const dependencies = DependencyResolver.computeDependencies(allDefs, expanded).missing;
|
|
3996
|
+
const finalTypeSet = /* @__PURE__ */ new Set([...expanded, ...dependencies]);
|
|
3997
|
+
const dependencyOrder = DependencyResolver.resolveOrder(
|
|
3998
|
+
allDefs.filter((def) => finalTypeSet.has(def.entityType))
|
|
3999
|
+
);
|
|
4000
|
+
const availableByType = /* @__PURE__ */ new Map();
|
|
4001
|
+
const selectedIds = /* @__PURE__ */ new Map();
|
|
4002
|
+
const processedIds = /* @__PURE__ */ new Map();
|
|
4003
|
+
for (const type of dependencyOrder) {
|
|
4004
|
+
const raw = await this.registry.get(type).listForExport(tenantId, context);
|
|
4005
|
+
availableByType.set(type, new Map(raw.map((entity) => [entity.data.id, entity])));
|
|
4006
|
+
if (entityIds && Object.prototype.hasOwnProperty.call(entityIds, type)) {
|
|
4007
|
+
selectedIds.set(type, new Set(entityIds[type]));
|
|
4008
|
+
} else if (expanded.includes(type)) {
|
|
4009
|
+
selectedIds.set(type, new Set(raw.map((entity) => entity.data.id)));
|
|
4010
|
+
} else {
|
|
4011
|
+
selectedIds.set(type, /* @__PURE__ */ new Set());
|
|
4012
|
+
}
|
|
4013
|
+
processedIds.set(type, /* @__PURE__ */ new Set());
|
|
4014
|
+
}
|
|
4015
|
+
let referencesAdded = true;
|
|
4016
|
+
while (referencesAdded) {
|
|
4017
|
+
referencesAdded = false;
|
|
4018
|
+
for (const type of dependencyOrder) {
|
|
4019
|
+
const def = this.registry.get(type);
|
|
4020
|
+
if (!def.getReferencedEntityIds) continue;
|
|
4021
|
+
const processed = processedIds.get(type);
|
|
4022
|
+
const available = availableByType.get(type);
|
|
4023
|
+
const unprocessed = [...selectedIds.get(type)].filter((id) => !processed.has(id)).map((id) => available.get(id)).filter((entity) => entity !== void 0);
|
|
4024
|
+
if (unprocessed.length === 0) continue;
|
|
4025
|
+
for (const entity of unprocessed) processed.add(entity.data.id);
|
|
4026
|
+
const references = await def.getReferencedEntityIds(tenantId, unprocessed, context);
|
|
4027
|
+
for (const [referencedType, ids] of Object.entries(references)) {
|
|
4028
|
+
if (!finalTypeSet.has(referencedType)) {
|
|
4029
|
+
throw new Error(
|
|
4030
|
+
`Unresolved reference from ${type}: entity type "${referencedType}" is not in its registered dependency closure`
|
|
4031
|
+
);
|
|
4032
|
+
}
|
|
4033
|
+
const targetSelection = selectedIds.get(referencedType);
|
|
4034
|
+
const targetEntities = availableByType.get(referencedType);
|
|
4035
|
+
const explicitSelection = entityIds && Object.prototype.hasOwnProperty.call(entityIds, referencedType) ? new Set(entityIds[referencedType]) : void 0;
|
|
4036
|
+
for (const id of new Set(ids)) {
|
|
4037
|
+
if (referencedType === "skill" && isBuiltInSkill(id)) continue;
|
|
4038
|
+
if (explicitSelection && !explicitSelection.has(id)) {
|
|
4039
|
+
throw new Error(
|
|
4040
|
+
`Required reference from ${type} to ${referencedType} "${id}" is omitted by entityIds.${referencedType}`
|
|
4041
|
+
);
|
|
4042
|
+
}
|
|
4043
|
+
if (!targetEntities.has(id)) {
|
|
4044
|
+
throw new Error(`Unresolved reference from ${type} to ${referencedType} "${id}"`);
|
|
4045
|
+
}
|
|
4046
|
+
if (!targetSelection.has(id)) {
|
|
4047
|
+
targetSelection.add(id);
|
|
4048
|
+
referencesAdded = true;
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
const entities = {};
|
|
4055
|
+
for (const type of dependencyOrder) {
|
|
4056
|
+
const ids = selectedIds.get(type);
|
|
4057
|
+
entities[type] = [...availableByType.get(type).values()].filter((entity) => ids.has(entity.data.id));
|
|
4058
|
+
}
|
|
4059
|
+
return { dependencyOrder, entities };
|
|
4060
|
+
}
|
|
4061
|
+
validateBundle(bundle) {
|
|
4062
|
+
if (bundle.version !== 1) {
|
|
4063
|
+
throw new Error(`Unsupported bundle version: ${bundle.version}. Expected: 1`);
|
|
4064
|
+
}
|
|
4065
|
+
if (!bundle.entities || typeof bundle.entities !== "object" || Array.isArray(bundle.entities)) {
|
|
4066
|
+
throw new Error("Invalid bundle: missing entities");
|
|
4067
|
+
}
|
|
4068
|
+
if (!Array.isArray(bundle.dependencyOrder)) {
|
|
4069
|
+
throw new Error("Invalid bundle: missing dependencyOrder");
|
|
4070
|
+
}
|
|
4071
|
+
const orderSet = new Set(bundle.dependencyOrder);
|
|
4072
|
+
if (orderSet.size !== bundle.dependencyOrder.length) {
|
|
4073
|
+
throw new Error("Invalid bundle: duplicate type in dependencyOrder");
|
|
4074
|
+
}
|
|
4075
|
+
const entityTypes = Object.keys(bundle.entities);
|
|
4076
|
+
for (const entityType of entityTypes) {
|
|
4077
|
+
if (!Array.isArray(bundle.entities[entityType])) {
|
|
4078
|
+
throw new Error(`Invalid bundle: entities.${entityType} must be an array`);
|
|
4079
|
+
}
|
|
4080
|
+
if (!orderSet.has(entityType)) {
|
|
4081
|
+
throw new Error(`Invalid bundle: dependencyOrder omits entities type "${entityType}"`);
|
|
4082
|
+
}
|
|
4083
|
+
}
|
|
4084
|
+
for (const entityType of bundle.dependencyOrder) {
|
|
4085
|
+
if (!Object.prototype.hasOwnProperty.call(bundle.entities, entityType)) {
|
|
4086
|
+
throw new Error(`Invalid bundle: missing entities key for dependencyOrder type "${entityType}"`);
|
|
4087
|
+
}
|
|
4088
|
+
const def = this.registry.getAll().find((candidate) => candidate.entityType === entityType);
|
|
4089
|
+
if (!def) {
|
|
4090
|
+
throw new Error(`Invalid bundle: unregistered entity type "${entityType}"`);
|
|
4091
|
+
}
|
|
4092
|
+
for (const dependency of def.dependsOn) {
|
|
4093
|
+
const dependencyRegistered = this.registry.getAll().some((candidate) => candidate.entityType === dependency);
|
|
4094
|
+
if (dependencyRegistered && !orderSet.has(dependency)) {
|
|
4095
|
+
throw new Error(
|
|
4096
|
+
`Invalid bundle: missing registered dependency "${dependency}" required by "${entityType}"`
|
|
4097
|
+
);
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
const exportIds = /* @__PURE__ */ new Set();
|
|
4102
|
+
for (const entityType of entityTypes) {
|
|
4103
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4104
|
+
for (const entity of bundle.entities[entityType]) {
|
|
4105
|
+
if (!entity || typeof entity !== "object" || typeof entity._exportId !== "string") {
|
|
4106
|
+
throw new Error(`Invalid bundle: malformed entity in "${entityType}"`);
|
|
4107
|
+
}
|
|
4108
|
+
if (exportIds.has(entity._exportId)) {
|
|
4109
|
+
throw new Error(`Invalid bundle: duplicate _exportId "${entity._exportId}"`);
|
|
4110
|
+
}
|
|
4111
|
+
exportIds.add(entity._exportId);
|
|
4112
|
+
const id = entity.data?.id;
|
|
4113
|
+
if (typeof id !== "string") {
|
|
4114
|
+
throw new Error(`Invalid bundle: entity ID in "${entityType}" must be a string`);
|
|
4115
|
+
}
|
|
4116
|
+
if (ids.has(id)) {
|
|
4117
|
+
throw new Error(`Invalid bundle: duplicate entity ID in "${entityType}": "${id}"`);
|
|
4118
|
+
}
|
|
4119
|
+
ids.add(id);
|
|
4120
|
+
}
|
|
4121
|
+
}
|
|
4122
|
+
const typeSet = new Set(entityTypes);
|
|
4123
|
+
const canonicalOrder = DependencyResolver.resolveOrder(
|
|
4124
|
+
this.registry.getAll().filter((def) => typeSet.has(def.entityType))
|
|
4125
|
+
);
|
|
4126
|
+
if (canonicalOrder.length !== bundle.dependencyOrder.length || canonicalOrder.some((type, index) => bundle.dependencyOrder[index] !== type)) {
|
|
4127
|
+
throw new Error(
|
|
4128
|
+
`Invalid bundle: dependencyOrder is not canonical; expected ${canonicalOrder.join(", ")}`
|
|
4129
|
+
);
|
|
4130
|
+
}
|
|
4131
|
+
return canonicalOrder;
|
|
4132
|
+
}
|
|
4133
|
+
sanitizeEntityData(data) {
|
|
4134
|
+
const sanitized = { ...data };
|
|
4135
|
+
delete sanitized.tenantId;
|
|
4136
|
+
delete sanitized.createdAt;
|
|
4137
|
+
delete sanitized.updatedAt;
|
|
4138
|
+
return sanitized;
|
|
4139
|
+
}
|
|
4140
|
+
};
|
|
3848
4141
|
|
|
3849
4142
|
// src/controllers/export-import.ts
|
|
3850
4143
|
import { ExportableEntityRegistry as ExportableEntityRegistry2 } from "@axiom-lattice/core";
|
|
3851
4144
|
var service = new ExportImportService();
|
|
3852
|
-
|
|
3853
|
-
|
|
4145
|
+
var TenantScopeError = class extends Error {
|
|
4146
|
+
constructor() {
|
|
4147
|
+
super(...arguments);
|
|
4148
|
+
this.statusCode = 403;
|
|
4149
|
+
}
|
|
4150
|
+
};
|
|
4151
|
+
function resolveTenantId(request, routeTenantId) {
|
|
4152
|
+
const authenticatedTenantId = request.user?.tenantId;
|
|
4153
|
+
const header = request.headers["x-tenant-id"];
|
|
4154
|
+
const headerTenantId = Array.isArray(header) ? header[0] : header;
|
|
4155
|
+
if (authenticatedTenantId) {
|
|
4156
|
+
if (headerTenantId && headerTenantId !== authenticatedTenantId) {
|
|
4157
|
+
throw new TenantScopeError(
|
|
4158
|
+
`Tenant scope mismatch: header tenant "${headerTenantId}" does not match authenticated tenant "${authenticatedTenantId}"`
|
|
4159
|
+
);
|
|
4160
|
+
}
|
|
4161
|
+
if (routeTenantId && routeTenantId !== authenticatedTenantId) {
|
|
4162
|
+
throw new TenantScopeError(
|
|
4163
|
+
`Tenant scope mismatch: route tenant "${routeTenantId}" does not match authenticated tenant "${authenticatedTenantId}"`
|
|
4164
|
+
);
|
|
4165
|
+
}
|
|
4166
|
+
return authenticatedTenantId;
|
|
4167
|
+
}
|
|
4168
|
+
return headerTenantId || routeTenantId || "default";
|
|
4169
|
+
}
|
|
4170
|
+
function getContext(request) {
|
|
4171
|
+
return {
|
|
4172
|
+
workspaceId: request.headers["x-workspace-id"] || void 0,
|
|
4173
|
+
projectId: request.headers["x-project-id"] || void 0
|
|
4174
|
+
};
|
|
4175
|
+
}
|
|
4176
|
+
function safeArchiveFilename(sourceTenantId) {
|
|
4177
|
+
const safeTenantId = sourceTenantId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
4178
|
+
return `tenant-export-${safeTenantId}.tar.gz`;
|
|
4179
|
+
}
|
|
4180
|
+
function assertCompleteFile(file) {
|
|
4181
|
+
if (file.truncated) {
|
|
4182
|
+
throw new Error("Uploaded file was truncated because it exceeds the configured file size limit");
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
function parseResolutions(value) {
|
|
4186
|
+
let parsed = value;
|
|
4187
|
+
if (typeof value === "string") {
|
|
4188
|
+
try {
|
|
4189
|
+
parsed = JSON.parse(value);
|
|
4190
|
+
} catch {
|
|
4191
|
+
throw new Error("resolutions must be valid JSON");
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
4195
|
+
throw new Error("resolutions must be a JSON object");
|
|
4196
|
+
}
|
|
4197
|
+
return parsed;
|
|
4198
|
+
}
|
|
4199
|
+
function requireJsonBundle(request, body) {
|
|
4200
|
+
const contentType = request.headers["content-type"]?.split(";", 1)[0]?.trim().toLowerCase();
|
|
4201
|
+
if (contentType !== "application/json" || body.bundle === void 0) {
|
|
4202
|
+
throw new Error('Provide a multipart tar.gz file or an application/json body with "bundle"');
|
|
4203
|
+
}
|
|
4204
|
+
return body.bundle;
|
|
4205
|
+
}
|
|
4206
|
+
async function readPreviewArchive(request) {
|
|
4207
|
+
const part = await request.file();
|
|
4208
|
+
if (!part || part.fieldname !== "file") {
|
|
4209
|
+
throw new Error('Multipart import requires a tar.gz file field named "file"');
|
|
4210
|
+
}
|
|
4211
|
+
const archive = await part.toBuffer();
|
|
4212
|
+
assertCompleteFile(part.file);
|
|
4213
|
+
return archive;
|
|
4214
|
+
}
|
|
4215
|
+
async function readApplyMultipart(request) {
|
|
4216
|
+
let archive;
|
|
4217
|
+
let resolutionsValue;
|
|
4218
|
+
for await (const part of request.parts()) {
|
|
4219
|
+
if (part.type === "file") {
|
|
4220
|
+
if (part.fieldname !== "file" || archive !== void 0) {
|
|
4221
|
+
part.file.resume();
|
|
4222
|
+
throw new Error('Multipart import requires exactly one tar.gz file field named "file"');
|
|
4223
|
+
}
|
|
4224
|
+
archive = await part.toBuffer();
|
|
4225
|
+
assertCompleteFile(part.file);
|
|
4226
|
+
} else if (part.fieldname === "resolutions") {
|
|
4227
|
+
if (resolutionsValue !== void 0) {
|
|
4228
|
+
throw new Error('Multipart import requires exactly one "resolutions" field');
|
|
4229
|
+
}
|
|
4230
|
+
resolutionsValue = part.value;
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
if (!archive) {
|
|
4234
|
+
throw new Error('Multipart import requires a tar.gz file field named "file"');
|
|
4235
|
+
}
|
|
4236
|
+
if (resolutionsValue === void 0) {
|
|
4237
|
+
throw new Error('Multipart import requires a "resolutions" JSON field');
|
|
4238
|
+
}
|
|
4239
|
+
return { archive, resolutions: parseResolutions(resolutionsValue) };
|
|
3854
4240
|
}
|
|
3855
4241
|
async function getExportableTypes(_request, reply) {
|
|
3856
4242
|
const types = service.listExportableTypes();
|
|
3857
4243
|
return reply.send({ success: true, data: types });
|
|
3858
4244
|
}
|
|
3859
4245
|
async function exportConfig(request, reply) {
|
|
3860
|
-
const tenantId =
|
|
4246
|
+
const tenantId = resolveTenantId(request, request.params.tenantId);
|
|
3861
4247
|
const { entityTypes, entityIds } = request.body;
|
|
3862
4248
|
if (!Array.isArray(entityTypes) || entityTypes.length === 0) {
|
|
3863
4249
|
return reply.status(400).send({ success: false, message: "entityTypes must be a non-empty array" });
|
|
3864
4250
|
}
|
|
3865
|
-
const preview = await service.exportPreview(
|
|
4251
|
+
const preview = await service.exportPreview(
|
|
4252
|
+
tenantId,
|
|
4253
|
+
entityTypes,
|
|
4254
|
+
entityIds,
|
|
4255
|
+
getContext(request)
|
|
4256
|
+
);
|
|
3866
4257
|
if (preview.missingDependencies.length > 0 || preview.cascadeAdditions.length > 0) {
|
|
3867
4258
|
return reply.send({
|
|
3868
4259
|
success: true,
|
|
@@ -3873,40 +4264,41 @@ async function exportConfig(request, reply) {
|
|
|
3873
4264
|
}
|
|
3874
4265
|
});
|
|
3875
4266
|
}
|
|
3876
|
-
const { jobId,
|
|
4267
|
+
const { jobId, data } = await service.export(tenantId, entityTypes, entityIds, getContext(request));
|
|
3877
4268
|
return reply.send({
|
|
3878
4269
|
success: true,
|
|
3879
4270
|
data: {
|
|
3880
4271
|
jobId,
|
|
3881
4272
|
summary: Object.fromEntries(
|
|
3882
|
-
Object.entries(bundle.entities).map(([type, entities]) => [type, entities.length])
|
|
4273
|
+
Object.entries(data.bundle.entities).map(([type, entities]) => [type, entities.length])
|
|
3883
4274
|
)
|
|
3884
4275
|
}
|
|
3885
4276
|
});
|
|
3886
4277
|
}
|
|
3887
4278
|
async function exportConfigConfirm(request, reply) {
|
|
3888
|
-
const tenantId =
|
|
4279
|
+
const tenantId = resolveTenantId(request, request.params.tenantId);
|
|
3889
4280
|
const { entityTypes, entityIds } = request.body;
|
|
3890
|
-
const { jobId,
|
|
4281
|
+
const { jobId, data } = await service.export(tenantId, entityTypes, entityIds, getContext(request));
|
|
3891
4282
|
return reply.send({
|
|
3892
4283
|
success: true,
|
|
3893
4284
|
data: {
|
|
3894
4285
|
jobId,
|
|
3895
4286
|
summary: Object.fromEntries(
|
|
3896
|
-
Object.entries(bundle.entities).map(([type, entities]) => [type, entities.length])
|
|
4287
|
+
Object.entries(data.bundle.entities).map(([type, entities]) => [type, entities.length])
|
|
3897
4288
|
)
|
|
3898
4289
|
}
|
|
3899
4290
|
});
|
|
3900
4291
|
}
|
|
3901
4292
|
async function previewEntities(request, reply) {
|
|
3902
|
-
const tenantId =
|
|
4293
|
+
const tenantId = resolveTenantId(request, request.params.tenantId);
|
|
3903
4294
|
const { entityTypes } = request.body;
|
|
4295
|
+
const context = getContext(request);
|
|
3904
4296
|
try {
|
|
3905
4297
|
const registry = ExportableEntityRegistry2.getInstance();
|
|
3906
4298
|
const result = {};
|
|
3907
4299
|
for (const type of entityTypes) {
|
|
3908
4300
|
const def = registry.get(type);
|
|
3909
|
-
const entities = await def.listForExport(tenantId);
|
|
4301
|
+
const entities = await def.listForExport(tenantId, context);
|
|
3910
4302
|
result[type] = entities.map((e) => ({
|
|
3911
4303
|
id: e.data.id,
|
|
3912
4304
|
name: e.data.name || e.data.id,
|
|
@@ -3919,21 +4311,22 @@ async function previewEntities(request, reply) {
|
|
|
3919
4311
|
}
|
|
3920
4312
|
}
|
|
3921
4313
|
async function downloadExport(request, reply) {
|
|
3922
|
-
const tenantId =
|
|
3923
|
-
const
|
|
3924
|
-
if (!
|
|
4314
|
+
const tenantId = resolveTenantId(request, request.params.tenantId);
|
|
4315
|
+
const data = service.getExportJob(request.params.jobId, tenantId);
|
|
4316
|
+
if (!data) {
|
|
3925
4317
|
return reply.status(404).send({ success: false, message: "Export job not found or expired" });
|
|
3926
4318
|
}
|
|
3927
|
-
|
|
4319
|
+
const tarGz = await service.packTarGz(data);
|
|
4320
|
+
const filename = safeArchiveFilename(data.bundle.sourceTenantId);
|
|
4321
|
+
reply.type("application/gzip");
|
|
4322
|
+
reply.header("Content-Disposition", `attachment; filename="${filename}"`);
|
|
4323
|
+
return reply.send(tarGz);
|
|
3928
4324
|
}
|
|
3929
4325
|
async function importPreview(request, reply) {
|
|
3930
|
-
const tenantId =
|
|
3931
|
-
const { bundle } = request.body;
|
|
3932
|
-
if (!bundle) {
|
|
3933
|
-
return reply.status(400).send({ success: false, message: "No bundle provided in request body" });
|
|
3934
|
-
}
|
|
4326
|
+
const tenantId = resolveTenantId(request, request.params.tenantId);
|
|
3935
4327
|
try {
|
|
3936
|
-
const
|
|
4328
|
+
const data = request.isMultipart() ? await service.unpackTarGz(await readPreviewArchive(request)) : { bundle: requireJsonBundle(request, request.body), files: void 0 };
|
|
4329
|
+
const preview = await service.previewImport(tenantId, data.bundle, getContext(request));
|
|
3937
4330
|
return reply.send({ success: true, data: preview });
|
|
3938
4331
|
} catch (err) {
|
|
3939
4332
|
return reply.status(400).send({
|
|
@@ -3943,10 +4336,12 @@ async function importPreview(request, reply) {
|
|
|
3943
4336
|
}
|
|
3944
4337
|
}
|
|
3945
4338
|
async function importApply(request, reply) {
|
|
3946
|
-
const tenantId =
|
|
4339
|
+
const tenantId = resolveTenantId(request, request.params.tenantId);
|
|
3947
4340
|
try {
|
|
3948
|
-
const
|
|
3949
|
-
const
|
|
4341
|
+
const multipart2 = request.isMultipart() ? await readApplyMultipart(request) : void 0;
|
|
4342
|
+
const data = multipart2 ? await service.unpackTarGz(multipart2.archive) : { bundle: requireJsonBundle(request, request.body), files: void 0 };
|
|
4343
|
+
const resolutions = multipart2?.resolutions ?? parseResolutions(request.body.resolutions);
|
|
4344
|
+
const result = await service.applyImport(tenantId, data.bundle, resolutions, data.files, getContext(request));
|
|
3950
4345
|
return reply.send({ success: true, data: result });
|
|
3951
4346
|
} catch (err) {
|
|
3952
4347
|
return reply.status(400).send({
|
|
@@ -4632,43 +5027,15 @@ function registerSandboxProxyRoutes(app2) {
|
|
|
4632
5027
|
// src/controllers/workspace.ts
|
|
4633
5028
|
import * as fs2 from "fs/promises";
|
|
4634
5029
|
import * as path2 from "path";
|
|
4635
|
-
import * as
|
|
4636
|
-
import { getStoreLattice as
|
|
5030
|
+
import * as os2 from "os";
|
|
5031
|
+
import { getStoreLattice as getStoreLattice6 } from "@axiom-lattice/core";
|
|
4637
5032
|
import { SandboxFilesystem, FilesystemBackend } from "@axiom-lattice/core";
|
|
4638
5033
|
import { getSandBoxManager as getSandBoxManager3 } from "@axiom-lattice/core";
|
|
4639
5034
|
import { v4 as uuidv42 } from "uuid";
|
|
4640
|
-
|
|
4641
|
-
// src/utils/path-containment.ts
|
|
4642
|
-
import * as fs from "fs/promises";
|
|
4643
|
-
import * as path from "path";
|
|
4644
|
-
var PathOutsideRootError = class extends Error {
|
|
4645
|
-
constructor(rootPath, targetPath) {
|
|
4646
|
-
super(`Path is outside the allowed root: ${targetPath}`);
|
|
4647
|
-
this.rootPath = rootPath;
|
|
4648
|
-
this.targetPath = targetPath;
|
|
4649
|
-
this.name = "PathOutsideRootError";
|
|
4650
|
-
}
|
|
4651
|
-
};
|
|
4652
|
-
function isPathWithinRoot(rootPath, targetPath) {
|
|
4653
|
-
const relative2 = path.relative(rootPath, targetPath);
|
|
4654
|
-
return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${path.sep}`) && !path.isAbsolute(relative2);
|
|
4655
|
-
}
|
|
4656
|
-
async function resolvePathWithinRoot(rootPath, targetPath) {
|
|
4657
|
-
const [resolvedRoot, resolvedTarget] = await Promise.all([
|
|
4658
|
-
fs.realpath(rootPath),
|
|
4659
|
-
fs.realpath(targetPath)
|
|
4660
|
-
]);
|
|
4661
|
-
if (!isPathWithinRoot(resolvedRoot, resolvedTarget)) {
|
|
4662
|
-
throw new PathOutsideRootError(resolvedRoot, resolvedTarget);
|
|
4663
|
-
}
|
|
4664
|
-
return { rootPath: resolvedRoot, targetPath: resolvedTarget };
|
|
4665
|
-
}
|
|
4666
|
-
|
|
4667
|
-
// src/controllers/workspace.ts
|
|
4668
5035
|
var WorkspaceController = class {
|
|
4669
5036
|
constructor() {
|
|
4670
|
-
this.workspaceStore =
|
|
4671
|
-
this.projectStore =
|
|
5037
|
+
this.workspaceStore = getStoreLattice6("default", "workspace").store;
|
|
5038
|
+
this.projectStore = getStoreLattice6("default", "project").store;
|
|
4672
5039
|
}
|
|
4673
5040
|
getTenantId(request) {
|
|
4674
5041
|
const userTenantId = request.user?.tenantId;
|
|
@@ -4740,11 +5107,33 @@ var WorkspaceController = class {
|
|
|
4740
5107
|
async listProjects(request, reply) {
|
|
4741
5108
|
const tenantId = this.getTenantId(request);
|
|
4742
5109
|
const { workspaceId } = request.params;
|
|
4743
|
-
const
|
|
5110
|
+
const kindFilter = request.query.kind;
|
|
5111
|
+
await this.ensureTrainingProject(tenantId, workspaceId);
|
|
5112
|
+
const projects = kindFilter ? await this.projectStore.getProjectsByWorkspace(tenantId, workspaceId, {
|
|
5113
|
+
kind: kindFilter
|
|
5114
|
+
}) : await this.projectStore.getProjectsByWorkspace(tenantId, workspaceId);
|
|
5115
|
+
return { success: true, data: projects };
|
|
5116
|
+
}
|
|
5117
|
+
/**
|
|
5118
|
+
* Ensure at least one training project exists per tenant/workspace.
|
|
5119
|
+
*
|
|
5120
|
+
* Multiple training projects are allowed; this only creates the first one
|
|
5121
|
+
* when none exist so the frontend always has a default to select.
|
|
5122
|
+
*/
|
|
5123
|
+
async ensureTrainingProject(tenantId, workspaceId) {
|
|
5124
|
+
const existing = await this.projectStore.getProjectsByWorkspace(
|
|
4744
5125
|
tenantId,
|
|
4745
|
-
workspaceId
|
|
5126
|
+
workspaceId,
|
|
5127
|
+
{ kind: "training" }
|
|
4746
5128
|
);
|
|
4747
|
-
|
|
5129
|
+
if (existing.length > 0) {
|
|
5130
|
+
return;
|
|
5131
|
+
}
|
|
5132
|
+
await this.projectStore.createProject(tenantId, workspaceId, uuidv42(), {
|
|
5133
|
+
name: "Training",
|
|
5134
|
+
description: "Shared workspace for agent training",
|
|
5135
|
+
kind: "training"
|
|
5136
|
+
});
|
|
4748
5137
|
}
|
|
4749
5138
|
async createProject(request, reply) {
|
|
4750
5139
|
const tenantId = this.getTenantId(request);
|
|
@@ -4784,7 +5173,24 @@ var WorkspaceController = class {
|
|
|
4784
5173
|
}
|
|
4785
5174
|
async deleteProject(request, reply) {
|
|
4786
5175
|
const tenantId = this.getTenantId(request);
|
|
4787
|
-
const { projectId } = request.params;
|
|
5176
|
+
const { workspaceId, projectId } = request.params;
|
|
5177
|
+
const project = await this.projectStore.getProjectById(tenantId, projectId);
|
|
5178
|
+
if (!project) {
|
|
5179
|
+
return reply.status(404).send({ success: false, error: "Project not found" });
|
|
5180
|
+
}
|
|
5181
|
+
if (project.kind === "training") {
|
|
5182
|
+
const training = await this.projectStore.getProjectsByWorkspace(
|
|
5183
|
+
tenantId,
|
|
5184
|
+
workspaceId,
|
|
5185
|
+
{ kind: "training" }
|
|
5186
|
+
);
|
|
5187
|
+
if (training.length <= 1) {
|
|
5188
|
+
return reply.status(409).send({
|
|
5189
|
+
success: false,
|
|
5190
|
+
error: "The last training project cannot be deleted"
|
|
5191
|
+
});
|
|
5192
|
+
}
|
|
5193
|
+
}
|
|
4788
5194
|
const deleted = await this.projectStore.deleteProject(tenantId, projectId);
|
|
4789
5195
|
if (!deleted) {
|
|
4790
5196
|
return reply.status(404).send({ success: false, error: "Project not found" });
|
|
@@ -4826,7 +5232,7 @@ var WorkspaceController = class {
|
|
|
4826
5232
|
workspace
|
|
4827
5233
|
};
|
|
4828
5234
|
}
|
|
4829
|
-
const rootDir =
|
|
5235
|
+
const rootDir = filesystemRootDirectory(
|
|
4830
5236
|
tenantId,
|
|
4831
5237
|
workspaceId,
|
|
4832
5238
|
projectId
|
|
@@ -4840,41 +5246,6 @@ var WorkspaceController = class {
|
|
|
4840
5246
|
workspace
|
|
4841
5247
|
};
|
|
4842
5248
|
}
|
|
4843
|
-
async getFilesystemRootDirectory(tenantId, workspaceId, projectId) {
|
|
4844
|
-
return `/lattice_store/tenants/${tenantId}/workspaces/${workspaceId}/${projectId}`;
|
|
4845
|
-
}
|
|
4846
|
-
isBinaryContentType(filename) {
|
|
4847
|
-
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
4848
|
-
const binaryExtensions = /* @__PURE__ */ new Set([
|
|
4849
|
-
"pdf",
|
|
4850
|
-
"xlsx",
|
|
4851
|
-
"xls",
|
|
4852
|
-
"docx",
|
|
4853
|
-
"doc",
|
|
4854
|
-
"pptx",
|
|
4855
|
-
"ppt",
|
|
4856
|
-
"png",
|
|
4857
|
-
"jpg",
|
|
4858
|
-
"jpeg",
|
|
4859
|
-
"gif",
|
|
4860
|
-
"bmp",
|
|
4861
|
-
"ico",
|
|
4862
|
-
"webp",
|
|
4863
|
-
"mp3",
|
|
4864
|
-
"mp4",
|
|
4865
|
-
"webm",
|
|
4866
|
-
"ogg",
|
|
4867
|
-
"wav",
|
|
4868
|
-
"avi",
|
|
4869
|
-
"mov",
|
|
4870
|
-
"zip",
|
|
4871
|
-
"tar",
|
|
4872
|
-
"gz",
|
|
4873
|
-
"rar",
|
|
4874
|
-
"7z"
|
|
4875
|
-
]);
|
|
4876
|
-
return binaryExtensions.has(ext);
|
|
4877
|
-
}
|
|
4878
5249
|
async downloadFile(request, reply) {
|
|
4879
5250
|
const tenantId = this.getTenantId(request);
|
|
4880
5251
|
const { workspaceId, projectId } = request.params;
|
|
@@ -4896,11 +5267,10 @@ var WorkspaceController = class {
|
|
|
4896
5267
|
projectId
|
|
4897
5268
|
};
|
|
4898
5269
|
const filename2 = getFilenameFromPath(resolvedPath);
|
|
4899
|
-
const isBinary = this.isBinaryContentType(filename2);
|
|
4900
5270
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, resolvedPath);
|
|
4901
5271
|
let buf;
|
|
4902
5272
|
if (volumeBackend) {
|
|
4903
|
-
if (
|
|
5273
|
+
if (volumeBackend.readBinary) {
|
|
4904
5274
|
buf = await volumeBackend.readBinary(resolvedPath);
|
|
4905
5275
|
} else {
|
|
4906
5276
|
const fileData = await volumeBackend.readRaw(resolvedPath);
|
|
@@ -4915,10 +5285,12 @@ var WorkspaceController = class {
|
|
|
4915
5285
|
return reply.status(200).type(inferredContentType).header("Content-Disposition", contentDisposition).send(buf);
|
|
4916
5286
|
}
|
|
4917
5287
|
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, resolvedPath);
|
|
4918
|
-
|
|
5288
|
+
if (!backend.readBinary) {
|
|
5289
|
+
throw new Error("Filesystem backend does not support binary reads");
|
|
5290
|
+
}
|
|
5291
|
+
const buffer = await backend.readBinary(resolvedPath);
|
|
4919
5292
|
const filename = getFilenameFromPath(resolvedPath);
|
|
4920
5293
|
const mimeType = getContentTypeFromFilename(filename);
|
|
4921
|
-
const buffer = Buffer.from(content, "utf-8");
|
|
4922
5294
|
return reply.status(200).type(mimeType).header("Content-Disposition", `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`).send(buffer);
|
|
4923
5295
|
} catch (error) {
|
|
4924
5296
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -4950,7 +5322,7 @@ var WorkspaceController = class {
|
|
|
4950
5322
|
projectId
|
|
4951
5323
|
};
|
|
4952
5324
|
const filename2 = getFilenameFromPath(resolvedPath);
|
|
4953
|
-
const isBinary =
|
|
5325
|
+
const isBinary = isBinaryContentType(filename2);
|
|
4954
5326
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, resolvedPath);
|
|
4955
5327
|
let buf;
|
|
4956
5328
|
if (volumeBackend) {
|
|
@@ -5081,80 +5453,29 @@ var WorkspaceController = class {
|
|
|
5081
5453
|
if (pathValue && !/^[a-zA-Z0-9_./~-]+$/.test(pathValue)) {
|
|
5082
5454
|
return reply.status(400).send({ success: false, error: "Invalid path parameter" });
|
|
5083
5455
|
}
|
|
5084
|
-
|
|
5085
|
-
const sandboxManager = getSandBoxManager3();
|
|
5086
|
-
const volumeConfig = {
|
|
5087
|
-
assistant_id: assistantId || "",
|
|
5088
|
-
thread_id: "",
|
|
5089
|
-
tenantId,
|
|
5090
|
-
workspaceId,
|
|
5091
|
-
projectId
|
|
5092
|
-
};
|
|
5093
|
-
const realPath = pathValue ? path2.posix.join(pathValue, filename) : path2.posix.join("/project/uploads", filename);
|
|
5094
|
-
const isBinary = this.isBinaryContentType(filename);
|
|
5095
|
-
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, realPath);
|
|
5096
|
-
if (volumeBackend && !isBinary) {
|
|
5097
|
-
await volumeBackend.write(realPath, buffer.toString("utf-8"));
|
|
5098
|
-
} else if (volumeBackend && volumeBackend.writeBinary) {
|
|
5099
|
-
await volumeBackend.writeBinary(realPath, buffer);
|
|
5100
|
-
} else {
|
|
5101
|
-
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
5102
|
-
await sandbox.file.uploadFile({ file: realPath, data: buffer });
|
|
5103
|
-
}
|
|
5104
|
-
const relativePath = pathValue ? path2.posix.join(pathValue, filename) : path2.posix.join("/project/uploads", filename);
|
|
5105
|
-
const result2 = {
|
|
5106
|
-
path: relativePath,
|
|
5107
|
-
name: filename,
|
|
5108
|
-
is_dir: false,
|
|
5109
|
-
size: buffer.length,
|
|
5110
|
-
modified_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5111
|
-
};
|
|
5112
|
-
return reply.status(200).send({ success: true, data: result2 });
|
|
5113
|
-
}
|
|
5114
|
-
const rootDir = await this.getFilesystemRootDirectory(
|
|
5456
|
+
const saved = await saveProjectFile({
|
|
5115
5457
|
tenantId,
|
|
5116
5458
|
workspaceId,
|
|
5117
|
-
projectId
|
|
5118
|
-
);
|
|
5119
|
-
await fs2.mkdir(rootDir, { recursive: true });
|
|
5120
|
-
const relativeDirectory = pathValue?.replace(/^[/\\]+/, "") || ".";
|
|
5121
|
-
const targetDir = path2.resolve(rootDir, relativeDirectory);
|
|
5122
|
-
if (!isPathWithinRoot(path2.resolve(rootDir), targetDir)) {
|
|
5123
|
-
return reply.status(400).send({
|
|
5124
|
-
success: false,
|
|
5125
|
-
error: "Upload path must stay within the project directory"
|
|
5126
|
-
});
|
|
5127
|
-
}
|
|
5128
|
-
await fs2.mkdir(targetDir, { recursive: true });
|
|
5129
|
-
const [resolvedRoot, resolvedTargetDir] = await Promise.all([
|
|
5130
|
-
fs2.realpath(rootDir),
|
|
5131
|
-
fs2.realpath(targetDir)
|
|
5132
|
-
]);
|
|
5133
|
-
if (!isPathWithinRoot(resolvedRoot, resolvedTargetDir)) {
|
|
5134
|
-
return reply.status(400).send({
|
|
5135
|
-
success: false,
|
|
5136
|
-
error: "Upload path must stay within the project directory"
|
|
5137
|
-
});
|
|
5138
|
-
}
|
|
5139
|
-
const safeFilename = path2.basename(filename);
|
|
5140
|
-
if (safeFilename !== filename) {
|
|
5141
|
-
return reply.status(400).send({
|
|
5142
|
-
success: false,
|
|
5143
|
-
error: "Invalid filename"
|
|
5144
|
-
});
|
|
5145
|
-
}
|
|
5146
|
-
const targetPath = path2.join(resolvedTargetDir, safeFilename);
|
|
5147
|
-
await fs2.writeFile(targetPath, buffer);
|
|
5148
|
-
const stat2 = await fs2.stat(targetPath);
|
|
5149
|
-
const result = {
|
|
5150
|
-
path: path2.posix.join("/", relativeDirectory, safeFilename),
|
|
5459
|
+
projectId,
|
|
5151
5460
|
name: filename,
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
};
|
|
5156
|
-
return reply.status(200).send({
|
|
5461
|
+
bytes: buffer,
|
|
5462
|
+
...pathValue ? { path: pathValue } : {},
|
|
5463
|
+
assistantId
|
|
5464
|
+
});
|
|
5465
|
+
return reply.status(200).send({
|
|
5466
|
+
success: true,
|
|
5467
|
+
data: {
|
|
5468
|
+
path: saved.uri,
|
|
5469
|
+
name: saved.name,
|
|
5470
|
+
is_dir: false,
|
|
5471
|
+
size: saved.size,
|
|
5472
|
+
modified_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5473
|
+
}
|
|
5474
|
+
});
|
|
5157
5475
|
} catch (error) {
|
|
5476
|
+
if (error instanceof ProjectFileValidationError) {
|
|
5477
|
+
return reply.status(400).send({ success: false, error: error.message });
|
|
5478
|
+
}
|
|
5158
5479
|
const message = error instanceof Error ? error.message : String(error);
|
|
5159
5480
|
return reply.status(500).send({
|
|
5160
5481
|
success: false,
|
|
@@ -5171,7 +5492,7 @@ var WorkspaceController = class {
|
|
|
5171
5492
|
* - Returns only directory names, no file contents or hidden files
|
|
5172
5493
|
*/
|
|
5173
5494
|
async browseFilesystem(request, reply) {
|
|
5174
|
-
const homeDir =
|
|
5495
|
+
const homeDir = os2.homedir();
|
|
5175
5496
|
const requestedPath = request.query.path || homeDir;
|
|
5176
5497
|
const SYSTEM_BLACKLIST = ["/etc", "/sys", "/proc", "/var", "/tmp", "/dev"];
|
|
5177
5498
|
try {
|
|
@@ -5280,11 +5601,11 @@ function registerWorkspaceRoutes(app2) {
|
|
|
5280
5601
|
|
|
5281
5602
|
// src/controllers/database-configs.ts
|
|
5282
5603
|
import {
|
|
5283
|
-
getStoreLattice as
|
|
5604
|
+
getStoreLattice as getStoreLattice7,
|
|
5284
5605
|
sqlDatabaseManager
|
|
5285
5606
|
} from "@axiom-lattice/core";
|
|
5286
5607
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
5287
|
-
function
|
|
5608
|
+
function getTenantId9(request) {
|
|
5288
5609
|
const userTenantId = request.user?.tenantId;
|
|
5289
5610
|
if (userTenantId) {
|
|
5290
5611
|
return userTenantId;
|
|
@@ -5292,9 +5613,9 @@ function getTenantId11(request) {
|
|
|
5292
5613
|
return request.headers["x-tenant-id"] || "default";
|
|
5293
5614
|
}
|
|
5294
5615
|
async function getDatabaseConfigList(request, reply) {
|
|
5295
|
-
const tenantId =
|
|
5616
|
+
const tenantId = getTenantId9(request);
|
|
5296
5617
|
try {
|
|
5297
|
-
const storeLattice =
|
|
5618
|
+
const storeLattice = getStoreLattice7("default", "database");
|
|
5298
5619
|
const store = storeLattice.store;
|
|
5299
5620
|
const configs = await store.getAllConfigs(tenantId);
|
|
5300
5621
|
console.log("Backend: getAllConfigs returned:", configs);
|
|
@@ -5322,10 +5643,10 @@ async function getDatabaseConfigList(request, reply) {
|
|
|
5322
5643
|
}
|
|
5323
5644
|
}
|
|
5324
5645
|
async function getDatabaseConfig(request, reply) {
|
|
5325
|
-
const tenantId =
|
|
5646
|
+
const tenantId = getTenantId9(request);
|
|
5326
5647
|
const { key } = request.params;
|
|
5327
5648
|
try {
|
|
5328
|
-
const storeLattice =
|
|
5649
|
+
const storeLattice = getStoreLattice7("default", "database");
|
|
5329
5650
|
const store = storeLattice.store;
|
|
5330
5651
|
const config = await store.getConfigByKey(tenantId, key);
|
|
5331
5652
|
if (!config) {
|
|
@@ -5348,10 +5669,10 @@ async function getDatabaseConfig(request, reply) {
|
|
|
5348
5669
|
}
|
|
5349
5670
|
}
|
|
5350
5671
|
async function createDatabaseConfig(request, reply) {
|
|
5351
|
-
const tenantId =
|
|
5672
|
+
const tenantId = getTenantId9(request);
|
|
5352
5673
|
const body = request.body;
|
|
5353
5674
|
try {
|
|
5354
|
-
const storeLattice =
|
|
5675
|
+
const storeLattice = getStoreLattice7("default", "database");
|
|
5355
5676
|
const store = storeLattice.store;
|
|
5356
5677
|
const existing = await store.getConfigByKey(tenantId, body.key);
|
|
5357
5678
|
if (existing) {
|
|
@@ -5383,11 +5704,11 @@ async function createDatabaseConfig(request, reply) {
|
|
|
5383
5704
|
}
|
|
5384
5705
|
}
|
|
5385
5706
|
async function updateDatabaseConfig(request, reply) {
|
|
5386
|
-
const tenantId =
|
|
5707
|
+
const tenantId = getTenantId9(request);
|
|
5387
5708
|
const { key } = request.params;
|
|
5388
5709
|
const updates = request.body;
|
|
5389
5710
|
try {
|
|
5390
|
-
const storeLattice =
|
|
5711
|
+
const storeLattice = getStoreLattice7("default", "database");
|
|
5391
5712
|
const store = storeLattice.store;
|
|
5392
5713
|
const existing = await store.getConfigByKey(tenantId, key);
|
|
5393
5714
|
if (!existing) {
|
|
@@ -5425,10 +5746,10 @@ async function updateDatabaseConfig(request, reply) {
|
|
|
5425
5746
|
}
|
|
5426
5747
|
}
|
|
5427
5748
|
async function deleteDatabaseConfig(request, reply) {
|
|
5428
|
-
const tenantId =
|
|
5749
|
+
const tenantId = getTenantId9(request);
|
|
5429
5750
|
const { keyOrId } = request.params;
|
|
5430
5751
|
try {
|
|
5431
|
-
const storeLattice =
|
|
5752
|
+
const storeLattice = getStoreLattice7("default", "database");
|
|
5432
5753
|
const store = storeLattice.store;
|
|
5433
5754
|
console.log("Delete request - keyOrId:", keyOrId);
|
|
5434
5755
|
let config = await store.getConfigByKey(tenantId, keyOrId);
|
|
@@ -5474,10 +5795,10 @@ async function deleteDatabaseConfig(request, reply) {
|
|
|
5474
5795
|
}
|
|
5475
5796
|
}
|
|
5476
5797
|
async function testDatabaseConnection(request, reply) {
|
|
5477
|
-
const tenantId =
|
|
5798
|
+
const tenantId = getTenantId9(request);
|
|
5478
5799
|
const { key } = request.params;
|
|
5479
5800
|
try {
|
|
5480
|
-
const storeLattice =
|
|
5801
|
+
const storeLattice = getStoreLattice7("default", "database");
|
|
5481
5802
|
const store = storeLattice.store;
|
|
5482
5803
|
const config = await store.getConfigByKey(tenantId, key);
|
|
5483
5804
|
if (!config) {
|
|
@@ -5495,7 +5816,7 @@ async function testDatabaseConnection(request, reply) {
|
|
|
5495
5816
|
await db.connect();
|
|
5496
5817
|
await db.listTables();
|
|
5497
5818
|
const latency = Date.now() - startTime;
|
|
5498
|
-
await new Promise((
|
|
5819
|
+
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
5499
5820
|
await db.disconnect();
|
|
5500
5821
|
await sqlDatabaseManager.removeDatabase(tenantId, testKey);
|
|
5501
5822
|
return {
|
|
@@ -5562,12 +5883,12 @@ function registerDatabaseConfigRoutes(app2) {
|
|
|
5562
5883
|
|
|
5563
5884
|
// src/controllers/metrics-configs.ts
|
|
5564
5885
|
import {
|
|
5565
|
-
getStoreLattice as
|
|
5886
|
+
getStoreLattice as getStoreLattice8,
|
|
5566
5887
|
metricsServerManager as metricsServerManager2,
|
|
5567
5888
|
SemanticMetricsClient as SemanticMetricsClient2
|
|
5568
5889
|
} from "@axiom-lattice/core";
|
|
5569
5890
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
5570
|
-
function
|
|
5891
|
+
function getTenantId10(request) {
|
|
5571
5892
|
const userTenantId = request.user?.tenantId;
|
|
5572
5893
|
if (userTenantId) {
|
|
5573
5894
|
return userTenantId;
|
|
@@ -5575,9 +5896,9 @@ function getTenantId12(request) {
|
|
|
5575
5896
|
return request.headers["x-tenant-id"] || "default";
|
|
5576
5897
|
}
|
|
5577
5898
|
async function getMetricsServerConfigList(request, reply) {
|
|
5578
|
-
const tenantId =
|
|
5899
|
+
const tenantId = getTenantId10(request);
|
|
5579
5900
|
try {
|
|
5580
|
-
const storeLattice =
|
|
5901
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5581
5902
|
const store = storeLattice.store;
|
|
5582
5903
|
const configs = await store.getAllConfigs(tenantId);
|
|
5583
5904
|
return {
|
|
@@ -5601,10 +5922,10 @@ async function getMetricsServerConfigList(request, reply) {
|
|
|
5601
5922
|
}
|
|
5602
5923
|
}
|
|
5603
5924
|
async function getMetricsServerConfig(request, reply) {
|
|
5604
|
-
const tenantId =
|
|
5925
|
+
const tenantId = getTenantId10(request);
|
|
5605
5926
|
const { key } = request.params;
|
|
5606
5927
|
try {
|
|
5607
|
-
const storeLattice =
|
|
5928
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5608
5929
|
const store = storeLattice.store;
|
|
5609
5930
|
const config = await store.getConfigByKey(tenantId, key);
|
|
5610
5931
|
if (!config) {
|
|
@@ -5627,10 +5948,10 @@ async function getMetricsServerConfig(request, reply) {
|
|
|
5627
5948
|
}
|
|
5628
5949
|
}
|
|
5629
5950
|
async function createMetricsServerConfig(request, reply) {
|
|
5630
|
-
const tenantId =
|
|
5951
|
+
const tenantId = getTenantId10(request);
|
|
5631
5952
|
const body = request.body;
|
|
5632
5953
|
try {
|
|
5633
|
-
const storeLattice =
|
|
5954
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5634
5955
|
const store = storeLattice.store;
|
|
5635
5956
|
const existing = await store.getConfigByKey(tenantId, body.key);
|
|
5636
5957
|
if (existing) {
|
|
@@ -5678,11 +5999,11 @@ async function createMetricsServerConfig(request, reply) {
|
|
|
5678
5999
|
}
|
|
5679
6000
|
}
|
|
5680
6001
|
async function updateMetricsServerConfig(request, reply) {
|
|
5681
|
-
const tenantId =
|
|
6002
|
+
const tenantId = getTenantId10(request);
|
|
5682
6003
|
const { key } = request.params;
|
|
5683
6004
|
const updates = request.body;
|
|
5684
6005
|
try {
|
|
5685
|
-
const storeLattice =
|
|
6006
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5686
6007
|
const store = storeLattice.store;
|
|
5687
6008
|
const existing = await store.getConfigByKey(tenantId, key);
|
|
5688
6009
|
if (!existing) {
|
|
@@ -5729,10 +6050,10 @@ async function updateMetricsServerConfig(request, reply) {
|
|
|
5729
6050
|
}
|
|
5730
6051
|
}
|
|
5731
6052
|
async function deleteMetricsServerConfig(request, reply) {
|
|
5732
|
-
const tenantId =
|
|
6053
|
+
const tenantId = getTenantId10(request);
|
|
5733
6054
|
const { keyOrId } = request.params;
|
|
5734
6055
|
try {
|
|
5735
|
-
const storeLattice =
|
|
6056
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5736
6057
|
const store = storeLattice.store;
|
|
5737
6058
|
let config = await store.getConfigByKey(tenantId, keyOrId);
|
|
5738
6059
|
let configKey = keyOrId;
|
|
@@ -5776,10 +6097,10 @@ async function deleteMetricsServerConfig(request, reply) {
|
|
|
5776
6097
|
}
|
|
5777
6098
|
}
|
|
5778
6099
|
async function testMetricsServerConnection(request, reply) {
|
|
5779
|
-
const tenantId =
|
|
6100
|
+
const tenantId = getTenantId10(request);
|
|
5780
6101
|
const { key } = request.params;
|
|
5781
6102
|
try {
|
|
5782
|
-
const storeLattice =
|
|
6103
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5783
6104
|
const store = storeLattice.store;
|
|
5784
6105
|
const config = await store.getConfigByKey(tenantId, key);
|
|
5785
6106
|
if (!config) {
|
|
@@ -5827,10 +6148,10 @@ async function testMetricsServerConnection(request, reply) {
|
|
|
5827
6148
|
}
|
|
5828
6149
|
}
|
|
5829
6150
|
async function listAvailableMetrics(request, reply) {
|
|
5830
|
-
const tenantId =
|
|
6151
|
+
const tenantId = getTenantId10(request);
|
|
5831
6152
|
const { key } = request.params;
|
|
5832
6153
|
try {
|
|
5833
|
-
const storeLattice =
|
|
6154
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5834
6155
|
const store = storeLattice.store;
|
|
5835
6156
|
const config = await store.getConfigByKey(tenantId, key);
|
|
5836
6157
|
if (!config) {
|
|
@@ -5865,11 +6186,11 @@ async function listAvailableMetrics(request, reply) {
|
|
|
5865
6186
|
}
|
|
5866
6187
|
}
|
|
5867
6188
|
async function queryMetricsData(request, reply) {
|
|
5868
|
-
const tenantId =
|
|
6189
|
+
const tenantId = getTenantId10(request);
|
|
5869
6190
|
const { key } = request.params;
|
|
5870
6191
|
const { metricName, startTime, endTime, step, labels } = request.body;
|
|
5871
6192
|
try {
|
|
5872
|
-
const storeLattice =
|
|
6193
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5873
6194
|
const store = storeLattice.store;
|
|
5874
6195
|
const config = await store.getConfigByKey(tenantId, key);
|
|
5875
6196
|
if (!config) {
|
|
@@ -5913,10 +6234,10 @@ async function queryMetricsData(request, reply) {
|
|
|
5913
6234
|
}
|
|
5914
6235
|
}
|
|
5915
6236
|
async function getDataSources(request, reply) {
|
|
5916
|
-
const tenantId =
|
|
6237
|
+
const tenantId = getTenantId10(request);
|
|
5917
6238
|
const { key } = request.params;
|
|
5918
6239
|
try {
|
|
5919
|
-
const storeLattice =
|
|
6240
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5920
6241
|
const store = storeLattice.store;
|
|
5921
6242
|
const config = await store.getConfigByKey(tenantId, key);
|
|
5922
6243
|
if (!config) {
|
|
@@ -5954,10 +6275,10 @@ async function getDataSources(request, reply) {
|
|
|
5954
6275
|
}
|
|
5955
6276
|
}
|
|
5956
6277
|
async function getDatasourceMetrics(request, reply) {
|
|
5957
|
-
const tenantId =
|
|
6278
|
+
const tenantId = getTenantId10(request);
|
|
5958
6279
|
const { key, datasourceId } = request.params;
|
|
5959
6280
|
try {
|
|
5960
|
-
const storeLattice =
|
|
6281
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5961
6282
|
const store = storeLattice.store;
|
|
5962
6283
|
const config = await store.getConfigByKey(tenantId, key);
|
|
5963
6284
|
if (!config) {
|
|
@@ -5991,11 +6312,11 @@ async function getDatasourceMetrics(request, reply) {
|
|
|
5991
6312
|
}
|
|
5992
6313
|
}
|
|
5993
6314
|
async function querySemanticMetrics(request, reply) {
|
|
5994
|
-
const tenantId =
|
|
6315
|
+
const tenantId = getTenantId10(request);
|
|
5995
6316
|
const { key } = request.params;
|
|
5996
6317
|
const body = request.body;
|
|
5997
6318
|
try {
|
|
5998
|
-
const storeLattice =
|
|
6319
|
+
const storeLattice = getStoreLattice8("default", "metrics");
|
|
5999
6320
|
const store = storeLattice.store;
|
|
6000
6321
|
const config = await store.getConfigByKey(tenantId, key);
|
|
6001
6322
|
if (!config) {
|
|
@@ -6306,13 +6627,13 @@ function connectionRoutes(fastify2) {
|
|
|
6306
6627
|
}
|
|
6307
6628
|
|
|
6308
6629
|
// src/controllers/eval.ts
|
|
6309
|
-
import { getStoreLattice as
|
|
6630
|
+
import { getStoreLattice as getStoreLattice10 } from "@axiom-lattice/core";
|
|
6310
6631
|
import { v4 as uuidv44 } from "uuid";
|
|
6311
6632
|
|
|
6312
6633
|
// src/services/eval-runner.ts
|
|
6313
6634
|
import { EventEmitter } from "events";
|
|
6314
6635
|
import {
|
|
6315
|
-
getStoreLattice as
|
|
6636
|
+
getStoreLattice as getStoreLattice9,
|
|
6316
6637
|
modelLatticeManager as modelLatticeManager2,
|
|
6317
6638
|
LatticeEvalProject
|
|
6318
6639
|
} from "@axiom-lattice/core";
|
|
@@ -6370,21 +6691,21 @@ var EvalRunner = class {
|
|
|
6370
6691
|
for (const suite of suites) {
|
|
6371
6692
|
let cases = await store.getCasesBySuite(tenantId, suite.id);
|
|
6372
6693
|
if (caseIds && caseIds.length > 0) {
|
|
6373
|
-
cases = cases.filter((
|
|
6694
|
+
cases = cases.filter((c2) => caseIds.includes(c2.id));
|
|
6374
6695
|
if (cases.length === 0) continue;
|
|
6375
6696
|
}
|
|
6376
6697
|
totalCases += cases.length;
|
|
6377
6698
|
evalSuites.push({
|
|
6378
6699
|
suiteName: suite.name,
|
|
6379
|
-
cases: cases.map((
|
|
6380
|
-
caseId:
|
|
6381
|
-
input: { message:
|
|
6382
|
-
steps:
|
|
6700
|
+
cases: cases.map((c2) => ({
|
|
6701
|
+
caseId: c2.id,
|
|
6702
|
+
input: { message: c2.inputMessage, files: c2.inputFiles },
|
|
6703
|
+
steps: c2.steps,
|
|
6383
6704
|
output: { type: "message_content" },
|
|
6384
|
-
interruptPolicy:
|
|
6705
|
+
interruptPolicy: c2.interruptPolicy,
|
|
6385
6706
|
eval: {
|
|
6386
|
-
content_assertion:
|
|
6387
|
-
eval_rubrics:
|
|
6707
|
+
content_assertion: c2.contentAssertion,
|
|
6708
|
+
eval_rubrics: c2.rubrics?.map((r) => ({
|
|
6388
6709
|
dimension: r.name,
|
|
6389
6710
|
weight: r.weight,
|
|
6390
6711
|
description: r.description
|
|
@@ -6556,13 +6877,13 @@ var EvalRunner = class {
|
|
|
6556
6877
|
return this.runs.has(runId);
|
|
6557
6878
|
}
|
|
6558
6879
|
getEvalStore() {
|
|
6559
|
-
return
|
|
6880
|
+
return getStoreLattice9("default", "eval").store;
|
|
6560
6881
|
}
|
|
6561
6882
|
};
|
|
6562
6883
|
var evalRunner = new EvalRunner();
|
|
6563
6884
|
|
|
6564
6885
|
// src/controllers/eval.ts
|
|
6565
|
-
function
|
|
6886
|
+
function getTenantId11(request) {
|
|
6566
6887
|
const userTenantId = request.user?.tenantId;
|
|
6567
6888
|
if (userTenantId) {
|
|
6568
6889
|
return userTenantId;
|
|
@@ -6570,11 +6891,11 @@ function getTenantId13(request) {
|
|
|
6570
6891
|
return request.headers["x-tenant-id"] || "default";
|
|
6571
6892
|
}
|
|
6572
6893
|
function getEvalStore() {
|
|
6573
|
-
return
|
|
6894
|
+
return getStoreLattice10("default", "eval").store;
|
|
6574
6895
|
}
|
|
6575
6896
|
async function createProject(request, reply) {
|
|
6576
6897
|
try {
|
|
6577
|
-
const tenantId =
|
|
6898
|
+
const tenantId = getTenantId11(request);
|
|
6578
6899
|
const store = getEvalStore();
|
|
6579
6900
|
const id = uuidv44();
|
|
6580
6901
|
const data = request.body;
|
|
@@ -6631,7 +6952,7 @@ async function createProject(request, reply) {
|
|
|
6631
6952
|
}
|
|
6632
6953
|
async function listProjects(request, reply) {
|
|
6633
6954
|
try {
|
|
6634
|
-
const tenantId =
|
|
6955
|
+
const tenantId = getTenantId11(request);
|
|
6635
6956
|
const store = getEvalStore();
|
|
6636
6957
|
let projects = await store.getProjectsByTenant(tenantId);
|
|
6637
6958
|
if (projects.length === 0) {
|
|
@@ -6665,7 +6986,7 @@ async function listProjects(request, reply) {
|
|
|
6665
6986
|
}
|
|
6666
6987
|
async function getProject(request, reply) {
|
|
6667
6988
|
try {
|
|
6668
|
-
const tenantId =
|
|
6989
|
+
const tenantId = getTenantId11(request);
|
|
6669
6990
|
const store = getEvalStore();
|
|
6670
6991
|
const { pid } = request.params;
|
|
6671
6992
|
const project = await store.getProjectById(tenantId, pid);
|
|
@@ -6685,7 +7006,7 @@ async function getProject(request, reply) {
|
|
|
6685
7006
|
}
|
|
6686
7007
|
async function updateProject(request, reply) {
|
|
6687
7008
|
try {
|
|
6688
|
-
const tenantId =
|
|
7009
|
+
const tenantId = getTenantId11(request);
|
|
6689
7010
|
const store = getEvalStore();
|
|
6690
7011
|
const { pid } = request.params;
|
|
6691
7012
|
const existing = await store.getProjectById(tenantId, pid);
|
|
@@ -6728,7 +7049,7 @@ async function updateProject(request, reply) {
|
|
|
6728
7049
|
}
|
|
6729
7050
|
async function deleteProject(request, reply) {
|
|
6730
7051
|
try {
|
|
6731
|
-
const tenantId =
|
|
7052
|
+
const tenantId = getTenantId11(request);
|
|
6732
7053
|
const store = getEvalStore();
|
|
6733
7054
|
const { pid } = request.params;
|
|
6734
7055
|
const existing = await store.getProjectById(tenantId, pid);
|
|
@@ -6747,7 +7068,7 @@ async function deleteProject(request, reply) {
|
|
|
6747
7068
|
}
|
|
6748
7069
|
async function createSuite(request, reply) {
|
|
6749
7070
|
try {
|
|
6750
|
-
const tenantId =
|
|
7071
|
+
const tenantId = getTenantId11(request);
|
|
6751
7072
|
const store = getEvalStore();
|
|
6752
7073
|
const { pid } = request.params;
|
|
6753
7074
|
const project = await store.getProjectById(tenantId, pid);
|
|
@@ -6769,7 +7090,7 @@ async function createSuite(request, reply) {
|
|
|
6769
7090
|
}
|
|
6770
7091
|
async function updateSuite(request, reply) {
|
|
6771
7092
|
try {
|
|
6772
|
-
const tenantId =
|
|
7093
|
+
const tenantId = getTenantId11(request);
|
|
6773
7094
|
const store = getEvalStore();
|
|
6774
7095
|
const { sid } = request.params;
|
|
6775
7096
|
const existing = await store.getSuiteById(tenantId, sid);
|
|
@@ -6789,7 +7110,7 @@ async function updateSuite(request, reply) {
|
|
|
6789
7110
|
}
|
|
6790
7111
|
async function deleteSuite(request, reply) {
|
|
6791
7112
|
try {
|
|
6792
|
-
const tenantId =
|
|
7113
|
+
const tenantId = getTenantId11(request);
|
|
6793
7114
|
const store = getEvalStore();
|
|
6794
7115
|
const { sid } = request.params;
|
|
6795
7116
|
const existing = await store.getSuiteById(tenantId, sid);
|
|
@@ -6808,7 +7129,7 @@ async function deleteSuite(request, reply) {
|
|
|
6808
7129
|
}
|
|
6809
7130
|
async function createCase(request, reply) {
|
|
6810
7131
|
try {
|
|
6811
|
-
const tenantId =
|
|
7132
|
+
const tenantId = getTenantId11(request);
|
|
6812
7133
|
const store = getEvalStore();
|
|
6813
7134
|
const { sid } = request.params;
|
|
6814
7135
|
const suite = await store.getSuiteById(tenantId, sid);
|
|
@@ -6838,7 +7159,7 @@ async function createCase(request, reply) {
|
|
|
6838
7159
|
}
|
|
6839
7160
|
async function listCasesForSuite(request, reply) {
|
|
6840
7161
|
try {
|
|
6841
|
-
const tenantId =
|
|
7162
|
+
const tenantId = getTenantId11(request);
|
|
6842
7163
|
const store = getEvalStore();
|
|
6843
7164
|
const { sid } = request.params;
|
|
6844
7165
|
const cases = await store.getCasesBySuite(tenantId, sid);
|
|
@@ -6854,7 +7175,7 @@ async function listCasesForSuite(request, reply) {
|
|
|
6854
7175
|
}
|
|
6855
7176
|
async function updateCase(request, reply) {
|
|
6856
7177
|
try {
|
|
6857
|
-
const tenantId =
|
|
7178
|
+
const tenantId = getTenantId11(request);
|
|
6858
7179
|
const store = getEvalStore();
|
|
6859
7180
|
const { cid } = request.params;
|
|
6860
7181
|
const existing = await store.getCaseById(tenantId, cid);
|
|
@@ -6874,7 +7195,7 @@ async function updateCase(request, reply) {
|
|
|
6874
7195
|
}
|
|
6875
7196
|
async function deleteCase(request, reply) {
|
|
6876
7197
|
try {
|
|
6877
|
-
const tenantId =
|
|
7198
|
+
const tenantId = getTenantId11(request);
|
|
6878
7199
|
const store = getEvalStore();
|
|
6879
7200
|
const { cid } = request.params;
|
|
6880
7201
|
const existing = await store.getCaseById(tenantId, cid);
|
|
@@ -6906,7 +7227,7 @@ function registerEvalRoutes(app2) {
|
|
|
6906
7227
|
app2.delete("/api/eval/projects/:pid/suites/:sid/cases/:cid", deleteCase);
|
|
6907
7228
|
app2.post("/api/eval/projects/:pid/runs", async (request, reply) => {
|
|
6908
7229
|
try {
|
|
6909
|
-
const tenantId =
|
|
7230
|
+
const tenantId = getTenantId11(request);
|
|
6910
7231
|
const { pid } = request.params;
|
|
6911
7232
|
const body = request.body ?? {};
|
|
6912
7233
|
const bodyWs = request.headers["x-workspace-id"] || "";
|
|
@@ -6925,7 +7246,7 @@ function registerEvalRoutes(app2) {
|
|
|
6925
7246
|
});
|
|
6926
7247
|
app2.get("/api/eval/runs", async (request, reply) => {
|
|
6927
7248
|
try {
|
|
6928
|
-
const tenantId =
|
|
7249
|
+
const tenantId = getTenantId11(request);
|
|
6929
7250
|
const query = request.query;
|
|
6930
7251
|
const runs = await getEvalStore().getRunsByTenant(tenantId, { projectId: query.project_id, status: query.status });
|
|
6931
7252
|
reply.send({ success: true, message: "Ok", data: { records: runs, total: runs.length } });
|
|
@@ -6935,7 +7256,7 @@ function registerEvalRoutes(app2) {
|
|
|
6935
7256
|
});
|
|
6936
7257
|
app2.get("/api/eval/runs/:rid", async (request, reply) => {
|
|
6937
7258
|
try {
|
|
6938
|
-
const tenantId =
|
|
7259
|
+
const tenantId = getTenantId11(request);
|
|
6939
7260
|
const { rid } = request.params;
|
|
6940
7261
|
const run = await getEvalStore().getRunById(tenantId, rid);
|
|
6941
7262
|
if (!run) return reply.status(404).send({ success: false, message: "Run not found" });
|
|
@@ -6957,7 +7278,7 @@ function registerEvalRoutes(app2) {
|
|
|
6957
7278
|
const emitter = evalRunner.getEventEmitter();
|
|
6958
7279
|
const eventKey = `run:${rid}`;
|
|
6959
7280
|
if (!evalRunner.isRunning(rid)) {
|
|
6960
|
-
const tenantId =
|
|
7281
|
+
const tenantId = getTenantId11(request);
|
|
6961
7282
|
const run = await getEvalStore().getRunById(tenantId, rid);
|
|
6962
7283
|
if (run) {
|
|
6963
7284
|
const eventType = run.status === "completed" ? "completed" : "error";
|
|
@@ -6996,7 +7317,7 @@ data: ${JSON.stringify(event.data)}
|
|
|
6996
7317
|
});
|
|
6997
7318
|
app2.delete("/api/eval/runs/:rid", async (request, reply) => {
|
|
6998
7319
|
try {
|
|
6999
|
-
const tenantId =
|
|
7320
|
+
const tenantId = getTenantId11(request);
|
|
7000
7321
|
const { rid } = request.params;
|
|
7001
7322
|
const deleted = await getEvalStore().deleteRun(tenantId, rid);
|
|
7002
7323
|
if (!deleted) return reply.status(404).send({ success: false, message: "Run not found" });
|
|
@@ -7007,7 +7328,7 @@ data: ${JSON.stringify(event.data)}
|
|
|
7007
7328
|
});
|
|
7008
7329
|
app2.get("/api/eval/reports/projects/:pid", async (request, reply) => {
|
|
7009
7330
|
try {
|
|
7010
|
-
const tenantId =
|
|
7331
|
+
const tenantId = getTenantId11(request);
|
|
7011
7332
|
const { pid } = request.params;
|
|
7012
7333
|
const report = await getEvalStore().getProjectReport(tenantId, pid);
|
|
7013
7334
|
if (!report) return reply.status(404).send({ success: false, message: "Project not found" });
|
|
@@ -7019,11 +7340,11 @@ data: ${JSON.stringify(event.data)}
|
|
|
7019
7340
|
}
|
|
7020
7341
|
|
|
7021
7342
|
// src/controllers/users.ts
|
|
7022
|
-
import { getStoreLattice as
|
|
7343
|
+
import { getStoreLattice as getStoreLattice11 } from "@axiom-lattice/core";
|
|
7023
7344
|
import { v4 as uuidv45 } from "uuid";
|
|
7024
7345
|
var UsersController = class {
|
|
7025
7346
|
constructor() {
|
|
7026
|
-
this.userStore =
|
|
7347
|
+
this.userStore = getStoreLattice11("default", "user").store;
|
|
7027
7348
|
}
|
|
7028
7349
|
async listUsers(request, reply) {
|
|
7029
7350
|
const { email } = request.query;
|
|
@@ -7101,11 +7422,11 @@ function registerUserRoutes(app2) {
|
|
|
7101
7422
|
}
|
|
7102
7423
|
|
|
7103
7424
|
// src/controllers/tenants.ts
|
|
7104
|
-
import { getStoreLattice as
|
|
7425
|
+
import { getStoreLattice as getStoreLattice12 } from "@axiom-lattice/core";
|
|
7105
7426
|
import { v4 as uuidv46 } from "uuid";
|
|
7106
7427
|
var TenantsController = class {
|
|
7107
7428
|
constructor() {
|
|
7108
|
-
this.tenantStore =
|
|
7429
|
+
this.tenantStore = getStoreLattice12("default", "tenant").store;
|
|
7109
7430
|
}
|
|
7110
7431
|
// ==================== Tenant CRUD ====================
|
|
7111
7432
|
async listTenants(request, reply) {
|
|
@@ -7169,8 +7490,9 @@ function registerTenantRoutes(app2) {
|
|
|
7169
7490
|
}
|
|
7170
7491
|
|
|
7171
7492
|
// src/controllers/auth.ts
|
|
7172
|
-
import { getStoreLattice as
|
|
7493
|
+
import { getStoreLattice as getStoreLattice13 } from "@axiom-lattice/core";
|
|
7173
7494
|
import { v4 as uuidv47 } from "uuid";
|
|
7495
|
+
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
7174
7496
|
var defaultAuthConfig = {
|
|
7175
7497
|
autoApproveUsers: true,
|
|
7176
7498
|
allowTenantRegistration: true,
|
|
@@ -7178,9 +7500,9 @@ var defaultAuthConfig = {
|
|
|
7178
7500
|
};
|
|
7179
7501
|
var AuthController = class {
|
|
7180
7502
|
constructor(config = {}) {
|
|
7181
|
-
this.userStore =
|
|
7182
|
-
this.tenantStore =
|
|
7183
|
-
this.userTenantLinkStore =
|
|
7503
|
+
this.userStore = getStoreLattice13("default", "user").store;
|
|
7504
|
+
this.tenantStore = getStoreLattice13("default", "tenant").store;
|
|
7505
|
+
this.userTenantLinkStore = getStoreLattice13("default", "userTenantLink").store;
|
|
7184
7506
|
this.config = { ...defaultAuthConfig, ...config };
|
|
7185
7507
|
}
|
|
7186
7508
|
async register(request, reply) {
|
|
@@ -7251,7 +7573,8 @@ var AuthController = class {
|
|
|
7251
7573
|
});
|
|
7252
7574
|
}
|
|
7253
7575
|
const tenantLinks = await this.userTenantLinkStore.getTenantsByUser(user.id);
|
|
7254
|
-
const
|
|
7576
|
+
const singleTenantId = tenantLinks.length === 1 ? tenantLinks[0].tenantId : void 0;
|
|
7577
|
+
const token = await this.generateToken(user.id, singleTenantId);
|
|
7255
7578
|
return {
|
|
7256
7579
|
success: true,
|
|
7257
7580
|
data: {
|
|
@@ -7338,7 +7661,7 @@ var AuthController = class {
|
|
|
7338
7661
|
const linkMeta = link?.metadata || {};
|
|
7339
7662
|
let personalAssistant = null;
|
|
7340
7663
|
if (linkMeta.personalAssistantId) {
|
|
7341
|
-
const assistantStore =
|
|
7664
|
+
const assistantStore = getStoreLattice13("default", "assistant").store;
|
|
7342
7665
|
const exists = await assistantStore.hasAssistant(tenantId, linkMeta.personalAssistantId);
|
|
7343
7666
|
if (exists) {
|
|
7344
7667
|
personalAssistant = {
|
|
@@ -7457,6 +7780,9 @@ var AuthController = class {
|
|
|
7457
7780
|
return hashedPassword === hash;
|
|
7458
7781
|
}
|
|
7459
7782
|
async generateToken(userId, tenantId) {
|
|
7783
|
+
if (!this.config.jwtSecret) {
|
|
7784
|
+
throw new Error("AUTH_TOKEN_SECRET is required to issue console sessions");
|
|
7785
|
+
}
|
|
7460
7786
|
const payload = {
|
|
7461
7787
|
userId,
|
|
7462
7788
|
exp: Date.now() + this.config.tokenExpiration * 1e3
|
|
@@ -7464,7 +7790,7 @@ var AuthController = class {
|
|
|
7464
7790
|
if (tenantId) {
|
|
7465
7791
|
payload.tenantId = tenantId;
|
|
7466
7792
|
}
|
|
7467
|
-
return
|
|
7793
|
+
return createConsoleSessionToken(payload, this.config.jwtSecret);
|
|
7468
7794
|
}
|
|
7469
7795
|
async changePassword(request, reply) {
|
|
7470
7796
|
const userId = request.user?.id;
|
|
@@ -7518,12 +7844,46 @@ var AuthController = class {
|
|
|
7518
7844
|
}
|
|
7519
7845
|
}
|
|
7520
7846
|
};
|
|
7521
|
-
function
|
|
7522
|
-
|
|
7847
|
+
function resolveConsoleTokenSecret(_authRequired) {
|
|
7848
|
+
const configured = process.env.AUTH_TOKEN_SECRET || process.env.JWT_SECRET;
|
|
7849
|
+
if (configured) return configured;
|
|
7850
|
+
devSessionSecret ?? (devSessionSecret = randomBytes(32).toString("hex"));
|
|
7851
|
+
console.warn(
|
|
7852
|
+
"[auth] AUTH_TOKEN_SECRET/JWT_SECRET is not set; using an in-process generated signing secret (sessions are invalidated on restart). Set AUTH_TOKEN_SECRET for production."
|
|
7853
|
+
);
|
|
7854
|
+
return devSessionSecret;
|
|
7855
|
+
}
|
|
7856
|
+
var devSessionSecret;
|
|
7857
|
+
function createConsoleSessionToken(payload, secret) {
|
|
7858
|
+
const encodedPayload = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
7859
|
+
const signature = createHmac("sha256", secret).update(encodedPayload).digest("base64url");
|
|
7860
|
+
return `${encodedPayload}.${signature}`;
|
|
7861
|
+
}
|
|
7862
|
+
function isConsoleSessionPayload(value) {
|
|
7863
|
+
if (typeof value !== "object" || value === null) return false;
|
|
7864
|
+
const payload = value;
|
|
7865
|
+
return typeof payload.userId === "string" && payload.userId.length > 0 && typeof payload.exp === "number" && (payload.tenantId === void 0 || typeof payload.tenantId === "string");
|
|
7866
|
+
}
|
|
7867
|
+
function extractUserFromAuthHeader(authHeader, secret) {
|
|
7868
|
+
if (!secret || !authHeader?.startsWith("Bearer ")) return void 0;
|
|
7523
7869
|
const token = authHeader.substring(7);
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7870
|
+
const parts = token.split(".");
|
|
7871
|
+
if (parts.length !== 2) return void 0;
|
|
7872
|
+
const [encodedPayload, encodedSignature] = parts;
|
|
7873
|
+
if (!/^[A-Za-z0-9_-]{43}$/.test(encodedSignature)) return void 0;
|
|
7874
|
+
try {
|
|
7875
|
+
const actualSignature = Buffer.from(encodedSignature, "base64url");
|
|
7876
|
+
if (actualSignature.toString("base64url") !== encodedSignature) return void 0;
|
|
7877
|
+
const expectedSignature = createHmac("sha256", secret).update(encodedPayload).digest();
|
|
7878
|
+
if (actualSignature.length !== expectedSignature.length || !timingSafeEqual(actualSignature, expectedSignature)) {
|
|
7879
|
+
return void 0;
|
|
7880
|
+
}
|
|
7881
|
+
const payload = JSON.parse(
|
|
7882
|
+
Buffer.from(encodedPayload, "base64url").toString("utf8")
|
|
7883
|
+
);
|
|
7884
|
+
if (!isConsoleSessionPayload(payload) || payload.exp < Date.now()) {
|
|
7885
|
+
return void 0;
|
|
7886
|
+
}
|
|
7527
7887
|
return {
|
|
7528
7888
|
id: payload.userId,
|
|
7529
7889
|
tenantId: payload.tenantId
|
|
@@ -7532,10 +7892,43 @@ function extractUserFromAuthHeader(authHeader) {
|
|
|
7532
7892
|
return void 0;
|
|
7533
7893
|
}
|
|
7534
7894
|
}
|
|
7895
|
+
var PUBLIC_ROUTES = ["/api/auth/login", "/api/auth/register", "/health", "/api/stt/models"];
|
|
7896
|
+
function bypassesConsoleAuth(request) {
|
|
7897
|
+
const path4 = request.url.split("?")[0];
|
|
7898
|
+
if (request.method === "GET" && /^\/api\/a2a\/agents\/[^/]+\/\.well-known\/agent-card\.json$/.test(path4)) {
|
|
7899
|
+
return true;
|
|
7900
|
+
}
|
|
7901
|
+
return request.method === "POST" && /^\/api\/a2a\/agents\/[^/]+\/jsonrpc$/.test(path4);
|
|
7902
|
+
}
|
|
7903
|
+
function registerConsoleAuthHook(app2, options) {
|
|
7904
|
+
app2.addHook("preHandler", async (request, reply) => {
|
|
7905
|
+
if (bypassesConsoleAuth(request)) return;
|
|
7906
|
+
const secret = options.tokenSecret ?? resolveConsoleTokenSecret(options.authRequired);
|
|
7907
|
+
const user = extractUserFromAuthHeader(request.headers.authorization, secret);
|
|
7908
|
+
if (user) {
|
|
7909
|
+
request.user = user;
|
|
7910
|
+
return;
|
|
7911
|
+
}
|
|
7912
|
+
if (!options.authRequired || request.method === "OPTIONS") return;
|
|
7913
|
+
if (PUBLIC_ROUTES.some((route) => request.url === route)) return;
|
|
7914
|
+
if (request.url.startsWith("/s/")) return;
|
|
7915
|
+
const path4 = request.url.split("?")[0];
|
|
7916
|
+
if (path4.includes("/viewfile") || path4.includes("/downloadfile") || path4.includes("/uploadfile") || path4.startsWith("/f/") || path4 === "/f") {
|
|
7917
|
+
return;
|
|
7918
|
+
}
|
|
7919
|
+
await reply.status(401).send({
|
|
7920
|
+
success: false,
|
|
7921
|
+
error: "Unauthorized - Missing or invalid token"
|
|
7922
|
+
});
|
|
7923
|
+
});
|
|
7924
|
+
}
|
|
7535
7925
|
function registerAuthRoutes(app2, config) {
|
|
7536
7926
|
const controller = new AuthController(config);
|
|
7537
7927
|
const authHook = async (request, reply) => {
|
|
7538
|
-
const user = extractUserFromAuthHeader(
|
|
7928
|
+
const user = extractUserFromAuthHeader(
|
|
7929
|
+
request.headers.authorization,
|
|
7930
|
+
config?.jwtSecret
|
|
7931
|
+
);
|
|
7539
7932
|
if (!user) {
|
|
7540
7933
|
return reply.status(401).send({
|
|
7541
7934
|
success: false,
|
|
@@ -7888,20 +8281,36 @@ function setChannelControllerDeps(deps) {
|
|
|
7888
8281
|
_adapterRegistry = deps.adapterRegistry;
|
|
7889
8282
|
_router = deps.router;
|
|
7890
8283
|
}
|
|
7891
|
-
function
|
|
8284
|
+
function getTenantId12(request) {
|
|
7892
8285
|
const userTenantId = request.user?.tenantId;
|
|
7893
8286
|
if (userTenantId) {
|
|
7894
8287
|
return userTenantId;
|
|
7895
8288
|
}
|
|
7896
8289
|
return request.headers["x-tenant-id"] || "default";
|
|
7897
8290
|
}
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
8291
|
+
function snapshotPlainObject(value) {
|
|
8292
|
+
try {
|
|
8293
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
8294
|
+
const prototype = Object.getPrototypeOf(value);
|
|
8295
|
+
if (prototype !== Object.prototype && prototype !== null) return null;
|
|
8296
|
+
const snapshot = {};
|
|
8297
|
+
for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
|
|
8298
|
+
if (!descriptor.enumerable) continue;
|
|
8299
|
+
if (!("value" in descriptor)) return null;
|
|
8300
|
+
snapshot[key] = descriptor.value;
|
|
8301
|
+
}
|
|
8302
|
+
return snapshot;
|
|
8303
|
+
} catch {
|
|
8304
|
+
return null;
|
|
8305
|
+
}
|
|
8306
|
+
}
|
|
8307
|
+
async function getInstallationStore() {
|
|
8308
|
+
const { getStoreLattice: getStoreLattice27 } = await import("@axiom-lattice/core");
|
|
8309
|
+
const store = getStoreLattice27("default", "channelInstallation").store;
|
|
8310
|
+
if (store) return store;
|
|
8311
|
+
const { PostgreSQLChannelInstallationStore } = await import("@axiom-lattice/pg-stores");
|
|
8312
|
+
const databaseUrl = process.env.DATABASE_URL;
|
|
8313
|
+
if (!databaseUrl) {
|
|
7905
8314
|
throw new Error("DATABASE_URL is required for channel installation store");
|
|
7906
8315
|
}
|
|
7907
8316
|
return new PostgreSQLChannelInstallationStore({
|
|
@@ -7909,7 +8318,7 @@ async function getInstallationStore() {
|
|
|
7909
8318
|
});
|
|
7910
8319
|
}
|
|
7911
8320
|
async function getChannelInstallationList(request, reply) {
|
|
7912
|
-
const tenantId =
|
|
8321
|
+
const tenantId = getTenantId12(request);
|
|
7913
8322
|
const { channel } = request.query;
|
|
7914
8323
|
try {
|
|
7915
8324
|
const store = await getInstallationStore();
|
|
@@ -7935,7 +8344,7 @@ async function getChannelInstallationList(request, reply) {
|
|
|
7935
8344
|
}
|
|
7936
8345
|
}
|
|
7937
8346
|
async function getChannelInstallation(request, reply) {
|
|
7938
|
-
const tenantId =
|
|
8347
|
+
const tenantId = getTenantId12(request);
|
|
7939
8348
|
const { installationId } = request.params;
|
|
7940
8349
|
try {
|
|
7941
8350
|
const store = await getInstallationStore();
|
|
@@ -7968,9 +8377,25 @@ async function getChannelInstallation(request, reply) {
|
|
|
7968
8377
|
}
|
|
7969
8378
|
}
|
|
7970
8379
|
async function createChannelInstallation(request, reply) {
|
|
7971
|
-
const tenantId =
|
|
7972
|
-
const
|
|
7973
|
-
try {
|
|
8380
|
+
const tenantId = getTenantId12(request);
|
|
8381
|
+
const bodySnapshot = snapshotPlainObject(request.body);
|
|
8382
|
+
try {
|
|
8383
|
+
const allowedKeys = /* @__PURE__ */ new Set([
|
|
8384
|
+
"channel",
|
|
8385
|
+
"name",
|
|
8386
|
+
"config",
|
|
8387
|
+
"enabled",
|
|
8388
|
+
"fallbackAgentId",
|
|
8389
|
+
"rejectWhenNoBinding"
|
|
8390
|
+
]);
|
|
8391
|
+
if (!bodySnapshot || Object.keys(bodySnapshot).some((key) => !allowedKeys.has(key))) {
|
|
8392
|
+
reply.code(400);
|
|
8393
|
+
return {
|
|
8394
|
+
success: false,
|
|
8395
|
+
message: "Invalid request body"
|
|
8396
|
+
};
|
|
8397
|
+
}
|
|
8398
|
+
const body = bodySnapshot;
|
|
7974
8399
|
if (!body.channel) {
|
|
7975
8400
|
reply.code(400);
|
|
7976
8401
|
return {
|
|
@@ -8003,7 +8428,7 @@ async function createChannelInstallation(request, reply) {
|
|
|
8003
8428
|
}
|
|
8004
8429
|
}
|
|
8005
8430
|
const store = await getInstallationStore();
|
|
8006
|
-
const installationId =
|
|
8431
|
+
const installationId = randomUUID7();
|
|
8007
8432
|
const installation = await store.createInstallation(
|
|
8008
8433
|
tenantId,
|
|
8009
8434
|
installationId,
|
|
@@ -8027,7 +8452,8 @@ async function createChannelInstallation(request, reply) {
|
|
|
8027
8452
|
};
|
|
8028
8453
|
} catch (error) {
|
|
8029
8454
|
console.error("Failed to create channel installation:", error);
|
|
8030
|
-
|
|
8455
|
+
const errorMessage2 = error.message?.toLowerCase();
|
|
8456
|
+
if (errorMessage2?.includes("duplicate") || errorMessage2?.includes("unique constraint") || error.code === "23505") {
|
|
8031
8457
|
reply.code(409);
|
|
8032
8458
|
return {
|
|
8033
8459
|
success: false,
|
|
@@ -8041,7 +8467,7 @@ async function createChannelInstallation(request, reply) {
|
|
|
8041
8467
|
}
|
|
8042
8468
|
}
|
|
8043
8469
|
async function updateChannelInstallation(request, reply) {
|
|
8044
|
-
const tenantId =
|
|
8470
|
+
const tenantId = getTenantId12(request);
|
|
8045
8471
|
const { installationId } = request.params;
|
|
8046
8472
|
const body = request.body;
|
|
8047
8473
|
try {
|
|
@@ -8095,7 +8521,7 @@ async function updateChannelInstallation(request, reply) {
|
|
|
8095
8521
|
}
|
|
8096
8522
|
}
|
|
8097
8523
|
async function deleteChannelInstallation(request, reply) {
|
|
8098
|
-
const tenantId =
|
|
8524
|
+
const tenantId = getTenantId12(request);
|
|
8099
8525
|
const { installationId } = request.params;
|
|
8100
8526
|
try {
|
|
8101
8527
|
const store = await getInstallationStore();
|
|
@@ -8156,13 +8582,13 @@ function registerChannelInstallationRoutes(app2) {
|
|
|
8156
8582
|
|
|
8157
8583
|
// src/controllers/channel-bindings.ts
|
|
8158
8584
|
import { getBindingRegistry } from "@axiom-lattice/core";
|
|
8159
|
-
function
|
|
8585
|
+
function getTenantId13(request) {
|
|
8160
8586
|
const userTenantId = request.user?.tenantId;
|
|
8161
8587
|
if (userTenantId) return userTenantId;
|
|
8162
8588
|
return request.headers["x-tenant-id"] || "default";
|
|
8163
8589
|
}
|
|
8164
8590
|
async function getBindingList(request, _reply) {
|
|
8165
|
-
const tenantId =
|
|
8591
|
+
const tenantId = getTenantId13(request);
|
|
8166
8592
|
const { channel, agentId, channelInstallationId, limit, offset } = request.query;
|
|
8167
8593
|
try {
|
|
8168
8594
|
const registry = getBindingRegistry();
|
|
@@ -8174,7 +8600,7 @@ async function getBindingList(request, _reply) {
|
|
|
8174
8600
|
}
|
|
8175
8601
|
}
|
|
8176
8602
|
async function getBinding(request, reply) {
|
|
8177
|
-
const tenantId =
|
|
8603
|
+
const tenantId = getTenantId13(request);
|
|
8178
8604
|
try {
|
|
8179
8605
|
const registry = getBindingRegistry();
|
|
8180
8606
|
const bindings = await registry.list({ tenantId });
|
|
@@ -8190,7 +8616,7 @@ async function getBinding(request, reply) {
|
|
|
8190
8616
|
}
|
|
8191
8617
|
}
|
|
8192
8618
|
async function createBinding(request, reply) {
|
|
8193
|
-
const tenantId =
|
|
8619
|
+
const tenantId = getTenantId13(request);
|
|
8194
8620
|
try {
|
|
8195
8621
|
const registry = getBindingRegistry();
|
|
8196
8622
|
const binding = await registry.create({ ...request.body, tenantId });
|
|
@@ -8204,7 +8630,7 @@ async function createBinding(request, reply) {
|
|
|
8204
8630
|
}
|
|
8205
8631
|
async function updateBinding(request, reply) {
|
|
8206
8632
|
try {
|
|
8207
|
-
const tenantId =
|
|
8633
|
+
const tenantId = getTenantId13(request);
|
|
8208
8634
|
const registry = getBindingRegistry();
|
|
8209
8635
|
const bindings = await registry.list({ tenantId });
|
|
8210
8636
|
const existing = bindings.find((b) => b.id === request.params.id);
|
|
@@ -8222,7 +8648,7 @@ async function updateBinding(request, reply) {
|
|
|
8222
8648
|
}
|
|
8223
8649
|
async function deleteBinding(request, reply) {
|
|
8224
8650
|
try {
|
|
8225
|
-
const tenantId =
|
|
8651
|
+
const tenantId = getTenantId13(request);
|
|
8226
8652
|
const registry = getBindingRegistry();
|
|
8227
8653
|
const bindings = await registry.list({ tenantId });
|
|
8228
8654
|
const existing = bindings.find((b) => b.id === request.params.id);
|
|
@@ -8239,7 +8665,7 @@ async function deleteBinding(request, reply) {
|
|
|
8239
8665
|
}
|
|
8240
8666
|
}
|
|
8241
8667
|
async function resolveBinding(request, _reply) {
|
|
8242
|
-
const tenantId =
|
|
8668
|
+
const tenantId = getTenantId13(request);
|
|
8243
8669
|
const { channel, senderId, channelInstallationId } = request.query;
|
|
8244
8670
|
try {
|
|
8245
8671
|
const registry = getBindingRegistry();
|
|
@@ -8266,7 +8692,7 @@ function registerChannelBindingRoutes(app2) {
|
|
|
8266
8692
|
|
|
8267
8693
|
// src/controllers/menu-items.ts
|
|
8268
8694
|
import { getMenuRegistry } from "@axiom-lattice/core";
|
|
8269
|
-
function
|
|
8695
|
+
function getTenantId14(request) {
|
|
8270
8696
|
const userTenantId = request.user?.tenantId;
|
|
8271
8697
|
if (userTenantId) return userTenantId;
|
|
8272
8698
|
return request.headers["x-tenant-id"] || "default";
|
|
@@ -8275,7 +8701,7 @@ function errorMessage(err) {
|
|
|
8275
8701
|
return err instanceof Error ? err.message : "Unexpected error";
|
|
8276
8702
|
}
|
|
8277
8703
|
async function getMenuItemList(request, _reply) {
|
|
8278
|
-
const tenantId =
|
|
8704
|
+
const tenantId = getTenantId14(request);
|
|
8279
8705
|
try {
|
|
8280
8706
|
const registry = getMenuRegistry();
|
|
8281
8707
|
const items = await registry.list({ tenantId, menuTarget: request.query.menuTarget });
|
|
@@ -8287,7 +8713,7 @@ async function getMenuItemList(request, _reply) {
|
|
|
8287
8713
|
}
|
|
8288
8714
|
}
|
|
8289
8715
|
async function getMenuItem(request, reply) {
|
|
8290
|
-
const tenantId =
|
|
8716
|
+
const tenantId = getTenantId14(request);
|
|
8291
8717
|
try {
|
|
8292
8718
|
const registry = getMenuRegistry();
|
|
8293
8719
|
const item = await registry.getById(request.params.id);
|
|
@@ -8304,7 +8730,7 @@ async function getMenuItem(request, reply) {
|
|
|
8304
8730
|
}
|
|
8305
8731
|
}
|
|
8306
8732
|
async function createMenuItem(request, reply) {
|
|
8307
|
-
const tenantId =
|
|
8733
|
+
const tenantId = getTenantId14(request);
|
|
8308
8734
|
try {
|
|
8309
8735
|
const registry = getMenuRegistry();
|
|
8310
8736
|
const item = await registry.create({ ...request.body, tenantId });
|
|
@@ -8319,7 +8745,7 @@ async function createMenuItem(request, reply) {
|
|
|
8319
8745
|
}
|
|
8320
8746
|
async function updateMenuItem(request, reply) {
|
|
8321
8747
|
try {
|
|
8322
|
-
const tenantId =
|
|
8748
|
+
const tenantId = getTenantId14(request);
|
|
8323
8749
|
const registry = getMenuRegistry();
|
|
8324
8750
|
const existing = await registry.getById(request.params.id);
|
|
8325
8751
|
if (!existing || existing.tenantId !== tenantId) {
|
|
@@ -8337,7 +8763,7 @@ async function updateMenuItem(request, reply) {
|
|
|
8337
8763
|
}
|
|
8338
8764
|
async function deleteMenuItem(request, reply) {
|
|
8339
8765
|
try {
|
|
8340
|
-
const tenantId =
|
|
8766
|
+
const tenantId = getTenantId14(request);
|
|
8341
8767
|
const registry = getMenuRegistry();
|
|
8342
8768
|
const existing = await registry.getById(request.params.id);
|
|
8343
8769
|
if (!existing || existing.tenantId !== tenantId) {
|
|
@@ -8487,12 +8913,12 @@ async function handleBridgeProxy(request, reply) {
|
|
|
8487
8913
|
};
|
|
8488
8914
|
const timeout = 3e5;
|
|
8489
8915
|
try {
|
|
8490
|
-
const response = await new Promise((
|
|
8916
|
+
const response = await new Promise((resolve2, reject) => {
|
|
8491
8917
|
const timer = setTimeout(() => {
|
|
8492
8918
|
pending.delete(requestId);
|
|
8493
8919
|
reject(new Error(`Bridge request timeout after ${timeout}ms`));
|
|
8494
8920
|
}, timeout);
|
|
8495
|
-
pending.set(requestId, { resolve:
|
|
8921
|
+
pending.set(requestId, { resolve: resolve2, reject, timer, agentId });
|
|
8496
8922
|
try {
|
|
8497
8923
|
if (conn.ws.readyState !== conn.ws.OPEN) {
|
|
8498
8924
|
pending.delete(requestId);
|
|
@@ -8616,11 +9042,11 @@ var registerSTTRoutes = (app2) => {
|
|
|
8616
9042
|
};
|
|
8617
9043
|
|
|
8618
9044
|
// src/controllers/local-a2a.ts
|
|
8619
|
-
import { getStoreLattice as
|
|
9045
|
+
import { getStoreLattice as getStoreLattice14 } from "@axiom-lattice/core";
|
|
8620
9046
|
import {
|
|
8621
9047
|
AgentType as AgentType2
|
|
8622
9048
|
} from "@axiom-lattice/protocols";
|
|
8623
|
-
function
|
|
9049
|
+
function getTenantId15(request) {
|
|
8624
9050
|
const userTenantId = request.user?.tenantId;
|
|
8625
9051
|
if (userTenantId) return userTenantId;
|
|
8626
9052
|
return request.headers["x-tenant-id"] || "default";
|
|
@@ -8632,7 +9058,7 @@ function getLocalRuntime(assistant) {
|
|
|
8632
9058
|
return graphDefinition.localRuntime;
|
|
8633
9059
|
}
|
|
8634
9060
|
async function getLocalA2AAssistants(tenantId) {
|
|
8635
|
-
const storeLattice =
|
|
9061
|
+
const storeLattice = getStoreLattice14("default", "assistant");
|
|
8636
9062
|
const assistants = await storeLattice.store.getAllAssistants(tenantId);
|
|
8637
9063
|
const results = [];
|
|
8638
9064
|
for (const assistant of assistants) {
|
|
@@ -8644,7 +9070,7 @@ async function getLocalA2AAssistants(tenantId) {
|
|
|
8644
9070
|
return results;
|
|
8645
9071
|
}
|
|
8646
9072
|
async function getLocalA2AAssistant(tenantId, assistantId) {
|
|
8647
|
-
const storeLattice =
|
|
9073
|
+
const storeLattice = getStoreLattice14("default", "assistant");
|
|
8648
9074
|
const assistant = await storeLattice.store.getAssistantById(tenantId, assistantId);
|
|
8649
9075
|
if (!assistant) return null;
|
|
8650
9076
|
const runtime = getLocalRuntime(assistant);
|
|
@@ -8657,7 +9083,7 @@ async function requireManagedAssistant(request, reply) {
|
|
|
8657
9083
|
reply.status(400).send({ success: false, error: "assistantId is required" });
|
|
8658
9084
|
return null;
|
|
8659
9085
|
}
|
|
8660
|
-
const registered = await getLocalA2AAssistant(
|
|
9086
|
+
const registered = await getLocalA2AAssistant(getTenantId15(request), assistantId);
|
|
8661
9087
|
if (!registered) {
|
|
8662
9088
|
reply.status(404).send({
|
|
8663
9089
|
success: false,
|
|
@@ -8668,7 +9094,7 @@ async function requireManagedAssistant(request, reply) {
|
|
|
8668
9094
|
return { assistantId, localRuntime: registered.localRuntime };
|
|
8669
9095
|
}
|
|
8670
9096
|
async function getLocalA2AStatus(request, reply) {
|
|
8671
|
-
const tenantId =
|
|
9097
|
+
const tenantId = getTenantId15(request);
|
|
8672
9098
|
const managed = await getLocalA2AAssistants(tenantId);
|
|
8673
9099
|
const states = await Promise.all(
|
|
8674
9100
|
managed.map(
|
|
@@ -8872,6 +9298,294 @@ function registerA2ATestConnectionRoute(app2) {
|
|
|
8872
9298
|
});
|
|
8873
9299
|
}
|
|
8874
9300
|
|
|
9301
|
+
// src/controllers/tasks.ts
|
|
9302
|
+
import {
|
|
9303
|
+
getStoreLattice as getStoreLattice15
|
|
9304
|
+
} from "@axiom-lattice/core";
|
|
9305
|
+
var AGENT_CREATE_STATUSES = /* @__PURE__ */ new Set(["pending"]);
|
|
9306
|
+
var FORBIDDEN_AGENT_CREATE_KEYS = /* @__PURE__ */ new Set([
|
|
9307
|
+
"beliefImpact",
|
|
9308
|
+
"beliefState",
|
|
9309
|
+
"cancelledAt",
|
|
9310
|
+
"completedAt",
|
|
9311
|
+
"completionEvidence",
|
|
9312
|
+
"evidenceId",
|
|
9313
|
+
"failureReason",
|
|
9314
|
+
"failedAt",
|
|
9315
|
+
"interruption",
|
|
9316
|
+
"lifecycle_completion_audit",
|
|
9317
|
+
"lifecycle_resume_audit",
|
|
9318
|
+
"requireReview",
|
|
9319
|
+
"result",
|
|
9320
|
+
"reviewedAt",
|
|
9321
|
+
"status",
|
|
9322
|
+
"interruptedAt"
|
|
9323
|
+
]);
|
|
9324
|
+
function containsLifecycleField(value) {
|
|
9325
|
+
if (!value || typeof value !== "object") return false;
|
|
9326
|
+
if (Array.isArray(value)) return value.some(containsLifecycleField);
|
|
9327
|
+
return Object.entries(value).some(([key, nested]) => FORBIDDEN_AGENT_CREATE_KEYS.has(key) || key.startsWith("lifecycle_") || containsLifecycleField(nested));
|
|
9328
|
+
}
|
|
9329
|
+
function governedAgentCreateError(body) {
|
|
9330
|
+
if (body.ownerType !== "agent") return void 0;
|
|
9331
|
+
if (body.status && !AGENT_CREATE_STATUSES.has(body.status)) {
|
|
9332
|
+
return {
|
|
9333
|
+
code: "TASK_LIFECYCLE_TRANSITION_REQUIRED",
|
|
9334
|
+
error: "Public agent tasks can only be created pending."
|
|
9335
|
+
};
|
|
9336
|
+
}
|
|
9337
|
+
const raw = body;
|
|
9338
|
+
if (Object.prototype.hasOwnProperty.call(raw, "result") || Object.prototype.hasOwnProperty.call(raw, "failureReason") || Object.prototype.hasOwnProperty.call(raw, "requireReview") || Object.prototype.hasOwnProperty.call(raw, "createdAt") || Object.prototype.hasOwnProperty.call(raw, "updatedAt") || containsLifecycleField(body.context) || containsLifecycleField(body.metadata)) {
|
|
9339
|
+
return {
|
|
9340
|
+
code: "TASK_LIFECYCLE_CONTEXT_FORBIDDEN",
|
|
9341
|
+
error: "Agent lifecycle results, review policy, interruption state, and audit fields require a trusted lifecycle adapter."
|
|
9342
|
+
};
|
|
9343
|
+
}
|
|
9344
|
+
return void 0;
|
|
9345
|
+
}
|
|
9346
|
+
function getTenantId16(request) {
|
|
9347
|
+
const userTenantId = request.user?.tenantId;
|
|
9348
|
+
if (userTenantId) return userTenantId;
|
|
9349
|
+
return request.headers["x-tenant-id"] || "default";
|
|
9350
|
+
}
|
|
9351
|
+
function getUserId4(request) {
|
|
9352
|
+
const userId = request.user?.id || request.headers["x-user-id"];
|
|
9353
|
+
if (!userId) throw new Error("User ID is required");
|
|
9354
|
+
return userId;
|
|
9355
|
+
}
|
|
9356
|
+
function getStore() {
|
|
9357
|
+
return getStoreLattice15("default", "task").store;
|
|
9358
|
+
}
|
|
9359
|
+
function getAssistantStore2() {
|
|
9360
|
+
return getStoreLattice15("default", "assistant").store;
|
|
9361
|
+
}
|
|
9362
|
+
function governedAgentUpdateError(task, updates) {
|
|
9363
|
+
const has = (key) => Object.prototype.hasOwnProperty.call(updates, key);
|
|
9364
|
+
if (has("ownerType") && updates.ownerType !== task.ownerType || has("ownerId") && updates.ownerId !== task.ownerId) {
|
|
9365
|
+
return "TASK_OWNERSHIP_IMMUTABLE";
|
|
9366
|
+
}
|
|
9367
|
+
if (task.ownerType !== "agent") return void 0;
|
|
9368
|
+
if (has("parentId") && updates.parentId !== task.parentId || has("requireReview") && updates.requireReview !== task.requireReview || has("result") || has("failureReason") || has("status")) {
|
|
9369
|
+
return "TASK_LIFECYCLE_TRANSITION_REQUIRED";
|
|
9370
|
+
}
|
|
9371
|
+
if (has("context") || has("description")) {
|
|
9372
|
+
return "COMPLETION_CONTEXT_MUTATION";
|
|
9373
|
+
}
|
|
9374
|
+
return void 0;
|
|
9375
|
+
}
|
|
9376
|
+
async function listTasks(request) {
|
|
9377
|
+
try {
|
|
9378
|
+
const tenantId = getTenantId16(request);
|
|
9379
|
+
const userId = getUserId4(request);
|
|
9380
|
+
const query = request.query;
|
|
9381
|
+
const ownerType = query.ownerType;
|
|
9382
|
+
const mixedOwnership = ownerType === void 0;
|
|
9383
|
+
const limit = query.limit ? parseInt(query.limit) : void 0;
|
|
9384
|
+
const offset = query.offset ? parseInt(query.offset) : void 0;
|
|
9385
|
+
const store = getStore();
|
|
9386
|
+
const tasks = await store.list({
|
|
9387
|
+
tenantId,
|
|
9388
|
+
status: query.status,
|
|
9389
|
+
priority: query.priority,
|
|
9390
|
+
...ownerType === "user" ? { ownerType, ownerId: userId } : {},
|
|
9391
|
+
...ownerType === "agent" ? { ownerType, ...query.ownerId && { ownerId: query.ownerId } } : {},
|
|
9392
|
+
...mixedOwnership && query.ownerId ? { ownerId: query.ownerId } : {},
|
|
9393
|
+
...query.parentId && { parentId: query.parentId },
|
|
9394
|
+
metadata: query.metadata ? JSON.parse(query.metadata) : void 0,
|
|
9395
|
+
projectId: query.projectId,
|
|
9396
|
+
...!mixedOwnership && limit !== void 0 ? { limit } : {},
|
|
9397
|
+
...!mixedOwnership && offset !== void 0 ? { offset } : {}
|
|
9398
|
+
});
|
|
9399
|
+
const visibleTasks = mixedOwnership ? tasks.filter((task) => task.ownerType === "agent" || task.ownerType === "user" && task.ownerId === userId) : tasks;
|
|
9400
|
+
const pageOffset = mixedOwnership ? offset ?? 0 : 0;
|
|
9401
|
+
const page = mixedOwnership ? visibleTasks.slice(pageOffset, limit === void 0 ? void 0 : pageOffset + limit) : visibleTasks;
|
|
9402
|
+
return { success: true, data: page, count: page.length };
|
|
9403
|
+
} catch (error) {
|
|
9404
|
+
return { success: false, error: error.message };
|
|
9405
|
+
}
|
|
9406
|
+
}
|
|
9407
|
+
async function getTask(request, reply) {
|
|
9408
|
+
try {
|
|
9409
|
+
const tenantId = getTenantId16(request);
|
|
9410
|
+
const userId = getUserId4(request);
|
|
9411
|
+
const { id } = request.params;
|
|
9412
|
+
const store = getStore();
|
|
9413
|
+
const task = await store.getById(tenantId, id);
|
|
9414
|
+
if (!task) {
|
|
9415
|
+
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
9416
|
+
}
|
|
9417
|
+
if (task.ownerType === "user" && task.ownerId !== userId) {
|
|
9418
|
+
return reply.status(403).send({ success: false, error: "Access denied" });
|
|
9419
|
+
}
|
|
9420
|
+
return { success: true, data: task };
|
|
9421
|
+
} catch (error) {
|
|
9422
|
+
return { success: false, error: error.message };
|
|
9423
|
+
}
|
|
9424
|
+
}
|
|
9425
|
+
async function createTask(request, reply) {
|
|
9426
|
+
try {
|
|
9427
|
+
const tenantId = getTenantId16(request);
|
|
9428
|
+
const userId = getUserId4(request);
|
|
9429
|
+
const body = request.body;
|
|
9430
|
+
if (!body.title) {
|
|
9431
|
+
return reply.status(400).send({ success: false, error: "title is required" });
|
|
9432
|
+
}
|
|
9433
|
+
const lifecycleError = governedAgentCreateError(body);
|
|
9434
|
+
if (lifecycleError) {
|
|
9435
|
+
return reply.status(409).send({ success: false, ...lifecycleError });
|
|
9436
|
+
}
|
|
9437
|
+
const ownerType = body.ownerType || "user";
|
|
9438
|
+
const ownerId = body.ownerId || userId;
|
|
9439
|
+
if (ownerType === "agent") {
|
|
9440
|
+
const assistant = await getAssistantStore2().getAssistantById(tenantId, ownerId);
|
|
9441
|
+
if (!assistant || assistant.tenantId !== tenantId) {
|
|
9442
|
+
return reply.status(404).send({
|
|
9443
|
+
success: false,
|
|
9444
|
+
code: "AGENT_OWNER_NOT_FOUND",
|
|
9445
|
+
error: "Agent owner was not found in the current tenant."
|
|
9446
|
+
});
|
|
9447
|
+
}
|
|
9448
|
+
}
|
|
9449
|
+
const store = getStore();
|
|
9450
|
+
const task = await store.create({
|
|
9451
|
+
...body,
|
|
9452
|
+
tenantId,
|
|
9453
|
+
ownerType,
|
|
9454
|
+
ownerId
|
|
9455
|
+
});
|
|
9456
|
+
return reply.status(201).send({ success: true, data: task });
|
|
9457
|
+
} catch (error) {
|
|
9458
|
+
return reply.status(500).send({ success: false, error: error.message });
|
|
9459
|
+
}
|
|
9460
|
+
}
|
|
9461
|
+
async function updateTask(request, reply) {
|
|
9462
|
+
try {
|
|
9463
|
+
const tenantId = getTenantId16(request);
|
|
9464
|
+
const userId = getUserId4(request);
|
|
9465
|
+
const { id } = request.params;
|
|
9466
|
+
const store = getStore();
|
|
9467
|
+
const existing = await store.getById(tenantId, id);
|
|
9468
|
+
if (!existing) {
|
|
9469
|
+
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
9470
|
+
}
|
|
9471
|
+
if (existing.ownerType === "user" && existing.ownerId !== userId) {
|
|
9472
|
+
return reply.status(403).send({ success: false, error: "Access denied" });
|
|
9473
|
+
}
|
|
9474
|
+
const lifecycleError = governedAgentUpdateError(existing, request.body);
|
|
9475
|
+
if (lifecycleError) {
|
|
9476
|
+
return reply.status(409).send({
|
|
9477
|
+
success: false,
|
|
9478
|
+
code: lifecycleError,
|
|
9479
|
+
error: lifecycleError === "COMPLETION_CONTEXT_MUTATION" ? "Agent completion context is owned by the task lifecycle service." : lifecycleError === "TASK_OWNERSHIP_IMMUTABLE" ? "Task ownership is immutable after creation." : "Agent ownership, hierarchy, and lifecycle transitions require a trusted lifecycle adapter."
|
|
9480
|
+
});
|
|
9481
|
+
}
|
|
9482
|
+
const task = await store.update(tenantId, id, request.body);
|
|
9483
|
+
if (!task) {
|
|
9484
|
+
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
9485
|
+
}
|
|
9486
|
+
return { success: true, data: task };
|
|
9487
|
+
} catch (error) {
|
|
9488
|
+
return reply.status(500).send({ success: false, error: error.message });
|
|
9489
|
+
}
|
|
9490
|
+
}
|
|
9491
|
+
async function deleteTask(request, reply) {
|
|
9492
|
+
try {
|
|
9493
|
+
const tenantId = getTenantId16(request);
|
|
9494
|
+
const userId = getUserId4(request);
|
|
9495
|
+
const { id } = request.params;
|
|
9496
|
+
const store = getStore();
|
|
9497
|
+
const existing = await store.getById(tenantId, id);
|
|
9498
|
+
if (!existing) {
|
|
9499
|
+
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
9500
|
+
}
|
|
9501
|
+
if (existing.ownerType === "user" && existing.ownerId !== userId) {
|
|
9502
|
+
return reply.status(403).send({ success: false, error: "Access denied" });
|
|
9503
|
+
}
|
|
9504
|
+
if (existing.ownerType === "agent") {
|
|
9505
|
+
return reply.status(403).send({
|
|
9506
|
+
success: false,
|
|
9507
|
+
code: "AGENT_RUNTIME_REQUIRED",
|
|
9508
|
+
error: "Agent-owned tasks can only be deleted by a trusted agent runtime."
|
|
9509
|
+
});
|
|
9510
|
+
}
|
|
9511
|
+
const deleted = await store.delete(tenantId, id);
|
|
9512
|
+
if (!deleted) {
|
|
9513
|
+
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
9514
|
+
}
|
|
9515
|
+
return { success: true, message: "Task deleted" };
|
|
9516
|
+
} catch (error) {
|
|
9517
|
+
return reply.status(500).send({ success: false, error: error.message });
|
|
9518
|
+
}
|
|
9519
|
+
}
|
|
9520
|
+
async function completeTask(request, reply) {
|
|
9521
|
+
try {
|
|
9522
|
+
const tenantId = getTenantId16(request);
|
|
9523
|
+
const userId = getUserId4(request);
|
|
9524
|
+
const { id } = request.params;
|
|
9525
|
+
const store = getStore();
|
|
9526
|
+
const existing = await store.getById(tenantId, id);
|
|
9527
|
+
if (!existing) {
|
|
9528
|
+
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
9529
|
+
}
|
|
9530
|
+
if (existing.ownerType === "user" && existing.ownerId !== userId) {
|
|
9531
|
+
return reply.status(403).send({ success: false, error: "Access denied" });
|
|
9532
|
+
}
|
|
9533
|
+
const body = request.body ?? {};
|
|
9534
|
+
if (existing.ownerType === "user") {
|
|
9535
|
+
const task = await store.update(tenantId, id, {
|
|
9536
|
+
status: "completed",
|
|
9537
|
+
...body.result === void 0 ? {} : { result: body.result }
|
|
9538
|
+
});
|
|
9539
|
+
if (!task) return reply.status(404).send({ success: false, error: "Task not found" });
|
|
9540
|
+
return { success: true, data: task };
|
|
9541
|
+
}
|
|
9542
|
+
return reply.status(403).send({
|
|
9543
|
+
success: false,
|
|
9544
|
+
code: "AGENT_RUNTIME_REQUIRED",
|
|
9545
|
+
error: "Agent-owned tasks can only be completed by a trusted agent runtime."
|
|
9546
|
+
});
|
|
9547
|
+
} catch (error) {
|
|
9548
|
+
return reply.status(500).send({ success: false, error: error.message });
|
|
9549
|
+
}
|
|
9550
|
+
}
|
|
9551
|
+
function getTaskWorkItemStore() {
|
|
9552
|
+
return getStoreLattice15("default", "taskWorkItem").store;
|
|
9553
|
+
}
|
|
9554
|
+
async function listTaskWorkItems(request, reply) {
|
|
9555
|
+
const tenantId = getTenantId16(request);
|
|
9556
|
+
const userId = getUserId4(request);
|
|
9557
|
+
const { id } = request.params;
|
|
9558
|
+
const { action, limit, offset } = request.query;
|
|
9559
|
+
const task = await getStore().getById(tenantId, id);
|
|
9560
|
+
if (!task) {
|
|
9561
|
+
return reply.status(404).send({ success: false, error: "Task not found" });
|
|
9562
|
+
}
|
|
9563
|
+
if (task.ownerType === "user" && task.ownerId !== userId) {
|
|
9564
|
+
return reply.status(403).send({ success: false, error: "Access denied" });
|
|
9565
|
+
}
|
|
9566
|
+
const store = getTaskWorkItemStore();
|
|
9567
|
+
const items = await store.list({
|
|
9568
|
+
tenantId,
|
|
9569
|
+
taskId: id,
|
|
9570
|
+
action,
|
|
9571
|
+
limit: limit ? Number(limit) : void 0,
|
|
9572
|
+
offset: offset ? Number(offset) : void 0
|
|
9573
|
+
});
|
|
9574
|
+
return reply.send({ success: true, data: items });
|
|
9575
|
+
}
|
|
9576
|
+
|
|
9577
|
+
// src/routes/task-routes.ts
|
|
9578
|
+
function registerTaskRoutes(app2) {
|
|
9579
|
+
app2.get("/api/tasks", listTasks);
|
|
9580
|
+
app2.get("/api/tasks/:id", getTask);
|
|
9581
|
+
app2.post("/api/tasks", createTask);
|
|
9582
|
+
app2.put("/api/tasks/:id", updateTask);
|
|
9583
|
+
app2.patch("/api/tasks/:id", updateTask);
|
|
9584
|
+
app2.delete("/api/tasks/:id", deleteTask);
|
|
9585
|
+
app2.patch("/api/tasks/:id/complete", completeTask);
|
|
9586
|
+
app2.get("/api/tasks/:id/work-items", listTaskWorkItems);
|
|
9587
|
+
}
|
|
9588
|
+
|
|
8875
9589
|
// src/routes/index.ts
|
|
8876
9590
|
var registerLatticeRoutes = (app2, channelDeps) => {
|
|
8877
9591
|
registerA2ABridgeRoutes(app2);
|
|
@@ -8926,13 +9640,7 @@ var registerLatticeRoutes = (app2, channelDeps) => {
|
|
|
8926
9640
|
app2.post("/api/personal-assistant", createPersonalAssistant);
|
|
8927
9641
|
app2.get("/api/personal-assistant", getPersonalAssistant);
|
|
8928
9642
|
app2.delete("/api/personal-assistant", deletePersonalAssistant);
|
|
8929
|
-
app2
|
|
8930
|
-
app2.get("/api/tasks/:id", getTask);
|
|
8931
|
-
app2.post("/api/tasks", createTask);
|
|
8932
|
-
app2.put("/api/tasks/:id", updateTask);
|
|
8933
|
-
app2.delete("/api/tasks/:id", deleteTask);
|
|
8934
|
-
app2.patch("/api/tasks/:id/complete", completeTask);
|
|
8935
|
-
app2.get("/api/tasks/:id/work-items", listTaskWorkItems);
|
|
9643
|
+
registerTaskRoutes(app2);
|
|
8936
9644
|
app2.get(
|
|
8937
9645
|
"/api/assistants/:assistantId/graph",
|
|
8938
9646
|
{ schema: getAgentGraphSchema },
|
|
@@ -9041,7 +9749,8 @@ var registerLatticeRoutes = (app2, channelDeps) => {
|
|
|
9041
9749
|
registerTenantRoutes(app2);
|
|
9042
9750
|
registerAuthRoutes(app2, {
|
|
9043
9751
|
autoApproveUsers: process.env.AUTO_APPROVE_USERS !== "false",
|
|
9044
|
-
allowTenantRegistration: process.env.ALLOW_TENANT_REGISTRATION !== "false"
|
|
9752
|
+
allowTenantRegistration: process.env.ALLOW_TENANT_REGISTRATION !== "false",
|
|
9753
|
+
jwtSecret: resolveConsoleTokenSecret(process.env.AUTH_REQUIRED === "true")
|
|
9045
9754
|
});
|
|
9046
9755
|
registerChannelRoutes(app2, channelDeps);
|
|
9047
9756
|
registerChannelInstallationRoutes(app2);
|
|
@@ -9178,9 +9887,16 @@ function registerResourceRoutes(app2, controller) {
|
|
|
9178
9887
|
import { ExportableEntityRegistry as ExportableEntityRegistry3 } from "@axiom-lattice/core";
|
|
9179
9888
|
|
|
9180
9889
|
// src/export_registrations/skill.registration.ts
|
|
9181
|
-
import {
|
|
9182
|
-
function getStore2() {
|
|
9183
|
-
return
|
|
9890
|
+
import { SandboxSkillStore as SandboxSkillStore2, isBuiltInSkill as isBuiltInSkill2 } from "@axiom-lattice/core";
|
|
9891
|
+
function getStore2(context) {
|
|
9892
|
+
return new SandboxSkillStore2({
|
|
9893
|
+
workspaceId: context?.workspaceId,
|
|
9894
|
+
projectId: context?.projectId
|
|
9895
|
+
});
|
|
9896
|
+
}
|
|
9897
|
+
function toStoreContext(context) {
|
|
9898
|
+
if (!context) return void 0;
|
|
9899
|
+
return { workspaceId: context.workspaceId, projectId: context.projectId };
|
|
9184
9900
|
}
|
|
9185
9901
|
var skillRegistration = {
|
|
9186
9902
|
entityType: "skill",
|
|
@@ -9188,10 +9904,10 @@ var skillRegistration = {
|
|
|
9188
9904
|
category: "core",
|
|
9189
9905
|
dependsOn: [],
|
|
9190
9906
|
cascadeParents: [],
|
|
9191
|
-
async listForExport(tenantId) {
|
|
9192
|
-
const store = getStore2();
|
|
9193
|
-
const skills = await store.getAllSkills(tenantId);
|
|
9194
|
-
return skills.map((s) => ({
|
|
9907
|
+
async listForExport(tenantId, context) {
|
|
9908
|
+
const store = getStore2(context);
|
|
9909
|
+
const skills = await store.getAllSkills(tenantId, toStoreContext(context));
|
|
9910
|
+
return skills.filter((s) => !isBuiltInSkill2(s.id)).map((s) => ({
|
|
9195
9911
|
_exportId: "",
|
|
9196
9912
|
data: {
|
|
9197
9913
|
id: s.id,
|
|
@@ -9205,14 +9921,58 @@ var skillRegistration = {
|
|
|
9205
9921
|
}
|
|
9206
9922
|
}));
|
|
9207
9923
|
},
|
|
9208
|
-
async
|
|
9209
|
-
const
|
|
9210
|
-
const
|
|
9924
|
+
async getReferencedEntityIds(_tenantId, entities) {
|
|
9925
|
+
const subSkillIds = /* @__PURE__ */ new Set();
|
|
9926
|
+
for (const entity of entities) {
|
|
9927
|
+
const subSkills = entity.data.subSkills;
|
|
9928
|
+
if (!Array.isArray(subSkills)) continue;
|
|
9929
|
+
for (const id of subSkills) {
|
|
9930
|
+
if (typeof id === "string" && id) subSkillIds.add(id);
|
|
9931
|
+
}
|
|
9932
|
+
}
|
|
9933
|
+
return { skill: [...subSkillIds] };
|
|
9934
|
+
},
|
|
9935
|
+
async listFilesForExport(tenantId, entities, context) {
|
|
9936
|
+
const store = getStore2(context);
|
|
9937
|
+
const ctx = toStoreContext(context);
|
|
9938
|
+
const files = [];
|
|
9939
|
+
for (const entity of entities) {
|
|
9940
|
+
const skillId = entity.data.id;
|
|
9941
|
+
if (!skillId) continue;
|
|
9942
|
+
const content = entity.data.content;
|
|
9943
|
+
files.push({
|
|
9944
|
+
entityId: skillId,
|
|
9945
|
+
path: "SKILL.md",
|
|
9946
|
+
content: Buffer.from(content ?? "", "utf-8")
|
|
9947
|
+
});
|
|
9948
|
+
try {
|
|
9949
|
+
const resources = await store.listSkillResources?.(tenantId, skillId, ctx);
|
|
9950
|
+
if (resources) {
|
|
9951
|
+
for (const resourcePath of resources) {
|
|
9952
|
+
const resourceContent = typeof store.loadSkillResourceRaw === "function" ? await store.loadSkillResourceRaw(tenantId, skillId, resourcePath, ctx) : await store.loadSkillResource?.(tenantId, skillId, resourcePath, ctx);
|
|
9953
|
+
if (resourceContent !== null && resourceContent !== void 0) {
|
|
9954
|
+
files.push({
|
|
9955
|
+
entityId: skillId,
|
|
9956
|
+
path: `resources/${resourcePath}`,
|
|
9957
|
+
content: Buffer.isBuffer(resourceContent) ? resourceContent : Buffer.from(resourceContent, "utf-8")
|
|
9958
|
+
});
|
|
9959
|
+
}
|
|
9960
|
+
}
|
|
9961
|
+
}
|
|
9962
|
+
} catch {
|
|
9963
|
+
}
|
|
9964
|
+
}
|
|
9965
|
+
return files;
|
|
9966
|
+
},
|
|
9967
|
+
async previewImport(tenantId, entities, context) {
|
|
9968
|
+
const store = getStore2(context);
|
|
9969
|
+
const existing = await store.getAllSkills(tenantId, toStoreContext(context));
|
|
9211
9970
|
const existingIds = new Set(existing.map((s) => s.id));
|
|
9212
9971
|
const conflicts = [];
|
|
9213
9972
|
const insertions = [];
|
|
9214
9973
|
for (const entity of entities) {
|
|
9215
9974
|
const id = entity.data.id;
|
|
9975
|
+
if (isBuiltInSkill2(id)) continue;
|
|
9216
9976
|
if (existingIds.has(id)) {
|
|
9217
9977
|
conflicts.push({
|
|
9218
9978
|
_exportId: entity._exportId,
|
|
@@ -9231,33 +9991,49 @@ var skillRegistration = {
|
|
|
9231
9991
|
}
|
|
9232
9992
|
return { conflicts, insertions, errors: [] };
|
|
9233
9993
|
},
|
|
9234
|
-
async applyImport(tenantId, entity, resolution) {
|
|
9235
|
-
const store = getStore2();
|
|
9994
|
+
async applyImport(tenantId, entity, resolution, files, context) {
|
|
9995
|
+
const store = getStore2(context);
|
|
9996
|
+
const ctx = toStoreContext(context);
|
|
9236
9997
|
const data = entity.data;
|
|
9237
|
-
const
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
} catch {
|
|
9242
|
-
}
|
|
9998
|
+
const originalName = data.name;
|
|
9999
|
+
const targetName = resolution.action === "rename" ? resolution.newId : originalName;
|
|
10000
|
+
if (typeof targetName !== "string" || targetName.trim().length === 0) {
|
|
10001
|
+
throw new Error("Skill import target name must not be empty");
|
|
9243
10002
|
}
|
|
9244
|
-
await store.createSkill(tenantId,
|
|
9245
|
-
name:
|
|
10003
|
+
await store.createSkill(tenantId, targetName, {
|
|
10004
|
+
name: targetName,
|
|
9246
10005
|
description: data.description,
|
|
9247
10006
|
license: data.license,
|
|
9248
10007
|
compatibility: data.compatibility,
|
|
9249
10008
|
metadata: data.metadata,
|
|
9250
10009
|
content: data.content,
|
|
9251
10010
|
subSkills: data.subSkills
|
|
9252
|
-
});
|
|
9253
|
-
|
|
10011
|
+
}, ctx);
|
|
10012
|
+
if (files && files.size > 0) {
|
|
10013
|
+
for (const [relPath, content] of files.entries()) {
|
|
10014
|
+
if (relPath === "SKILL.md") {
|
|
10015
|
+
const fileContent = content.toString("utf-8");
|
|
10016
|
+
if (fileContent !== data.content && typeof store.updateSkill === "function") {
|
|
10017
|
+
await store.updateSkill(tenantId, targetName, { content: fileContent }, ctx);
|
|
10018
|
+
}
|
|
10019
|
+
} else if (relPath.startsWith("resources/")) {
|
|
10020
|
+
const resourcePath = relPath.slice("resources/".length);
|
|
10021
|
+
if (typeof store.writeSkillResourceRaw === "function") {
|
|
10022
|
+
await store.writeSkillResourceRaw(tenantId, targetName, resourcePath, content, ctx);
|
|
10023
|
+
} else if (typeof store.writeSkillResource === "function") {
|
|
10024
|
+
await store.writeSkillResource(tenantId, targetName, resourcePath, content.toString("utf-8"), ctx);
|
|
10025
|
+
}
|
|
10026
|
+
}
|
|
10027
|
+
}
|
|
10028
|
+
}
|
|
10029
|
+
return { newId: targetName };
|
|
9254
10030
|
}
|
|
9255
10031
|
};
|
|
9256
10032
|
|
|
9257
10033
|
// src/export_registrations/agent.registration.ts
|
|
9258
|
-
import { getStoreLattice as
|
|
10034
|
+
import { getStoreLattice as getStoreLattice16 } from "@axiom-lattice/core";
|
|
9259
10035
|
function getStore3() {
|
|
9260
|
-
return
|
|
10036
|
+
return getStoreLattice16("default", "assistant").store;
|
|
9261
10037
|
}
|
|
9262
10038
|
var agentRegistration = {
|
|
9263
10039
|
entityType: "agent",
|
|
@@ -9278,145 +10054,68 @@ var agentRegistration = {
|
|
|
9278
10054
|
}
|
|
9279
10055
|
}));
|
|
9280
10056
|
},
|
|
9281
|
-
async
|
|
9282
|
-
const
|
|
9283
|
-
const existing = await store.getAllAssistants(tenantId);
|
|
9284
|
-
const existingIds = new Set(existing.map((a) => a.id));
|
|
9285
|
-
const conflicts = [];
|
|
9286
|
-
const insertions = [];
|
|
10057
|
+
async getReferencedEntityIds(_tenantId, entities) {
|
|
10058
|
+
const skillIds = /* @__PURE__ */ new Set();
|
|
9287
10059
|
for (const entity of entities) {
|
|
9288
|
-
const
|
|
9289
|
-
if (
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9293
|
-
|
|
9294
|
-
existingId: id,
|
|
9295
|
-
existingName: entity.data.name || id
|
|
9296
|
-
});
|
|
9297
|
-
} else {
|
|
9298
|
-
insertions.push({
|
|
9299
|
-
_exportId: entity._exportId,
|
|
9300
|
-
entityType: "agent",
|
|
9301
|
-
name: entity.data.name || id
|
|
9302
|
-
});
|
|
10060
|
+
const graphDefinition = entity.data.graphDefinition;
|
|
10061
|
+
if (!graphDefinition || typeof graphDefinition !== "object") continue;
|
|
10062
|
+
const ids = graphDefinition.skillIds;
|
|
10063
|
+
if (!Array.isArray(ids)) continue;
|
|
10064
|
+
for (const id of ids) {
|
|
10065
|
+
if (typeof id === "string" && id) skillIds.add(id);
|
|
9303
10066
|
}
|
|
9304
10067
|
}
|
|
9305
|
-
return {
|
|
9306
|
-
},
|
|
9307
|
-
async applyImport(tenantId, entity, resolution) {
|
|
9308
|
-
const store = getStore3();
|
|
9309
|
-
const data = entity.data;
|
|
9310
|
-
const id = resolution.action === "rename" && resolution.newId ? resolution.newId : data.id;
|
|
9311
|
-
if (resolution.action === "overwrite") {
|
|
9312
|
-
try {
|
|
9313
|
-
await store.deleteAssistant(tenantId, id);
|
|
9314
|
-
} catch {
|
|
9315
|
-
}
|
|
9316
|
-
}
|
|
9317
|
-
await store.createAssistant(tenantId, id, {
|
|
9318
|
-
name: data.name,
|
|
9319
|
-
description: data.description || "",
|
|
9320
|
-
graphDefinition: data.graphDefinition
|
|
9321
|
-
});
|
|
9322
|
-
return { newId: id };
|
|
9323
|
-
}
|
|
9324
|
-
};
|
|
9325
|
-
|
|
9326
|
-
// src/export_registrations/binding.registration.ts
|
|
9327
|
-
import { getStoreLattice as getStoreLattice18 } from "@axiom-lattice/core";
|
|
9328
|
-
function getStore4() {
|
|
9329
|
-
return getStoreLattice18("default", "channelBinding").store;
|
|
9330
|
-
}
|
|
9331
|
-
var bindingRegistration = {
|
|
9332
|
-
entityType: "binding",
|
|
9333
|
-
label: "Binding(\u6E20\u9053\u7ED1\u5B9A)",
|
|
9334
|
-
category: "core",
|
|
9335
|
-
dependsOn: ["agent", "channel_installation"],
|
|
9336
|
-
cascadeParents: [],
|
|
9337
|
-
referenceFields: { agentId: "agent", channelInstallationId: "channel_installation" },
|
|
9338
|
-
async listForExport(tenantId) {
|
|
9339
|
-
const store = getStore4();
|
|
9340
|
-
const bindings = await store.list({ tenantId, limit: 1e4, offset: 0 });
|
|
9341
|
-
return bindings.map((b) => ({
|
|
9342
|
-
_exportId: "",
|
|
9343
|
-
data: {
|
|
9344
|
-
channel: b.channel,
|
|
9345
|
-
channelInstallationId: b.channelInstallationId,
|
|
9346
|
-
senderId: b.senderId,
|
|
9347
|
-
agentId: b.agentId,
|
|
9348
|
-
threadId: b.threadId,
|
|
9349
|
-
workspaceId: b.workspaceId,
|
|
9350
|
-
projectId: b.projectId,
|
|
9351
|
-
threadMode: b.threadMode,
|
|
9352
|
-
senderDisplayName: b.senderDisplayName,
|
|
9353
|
-
senderMetadata: b.senderMetadata,
|
|
9354
|
-
enabled: b.enabled
|
|
9355
|
-
}
|
|
9356
|
-
}));
|
|
10068
|
+
return { skill: [...skillIds] };
|
|
9357
10069
|
},
|
|
9358
10070
|
async previewImport(tenantId, entities) {
|
|
9359
|
-
const store =
|
|
9360
|
-
const existing = await store.
|
|
9361
|
-
const
|
|
9362
|
-
existing.map((b) => `${b.channel}:${b.channelInstallationId}:${b.senderId}`)
|
|
9363
|
-
);
|
|
10071
|
+
const store = getStore3();
|
|
10072
|
+
const existing = await store.getAllAssistants(tenantId);
|
|
10073
|
+
const existingIds = new Set(existing.map((a) => a.id));
|
|
9364
10074
|
const conflicts = [];
|
|
9365
10075
|
const insertions = [];
|
|
9366
10076
|
for (const entity of entities) {
|
|
9367
|
-
const
|
|
9368
|
-
|
|
9369
|
-
if (existingKeys.has(key)) {
|
|
10077
|
+
const id = entity.data.id;
|
|
10078
|
+
if (existingIds.has(id)) {
|
|
9370
10079
|
conflicts.push({
|
|
9371
10080
|
_exportId: entity._exportId,
|
|
9372
|
-
entityType: "
|
|
9373
|
-
conflictType: "
|
|
9374
|
-
|
|
9375
|
-
|
|
10081
|
+
entityType: "agent",
|
|
10082
|
+
conflictType: "id_exists",
|
|
10083
|
+
existingId: id,
|
|
10084
|
+
existingName: entity.data.name || id
|
|
9376
10085
|
});
|
|
9377
10086
|
} else {
|
|
9378
10087
|
insertions.push({
|
|
9379
10088
|
_exportId: entity._exportId,
|
|
9380
|
-
entityType: "
|
|
9381
|
-
name:
|
|
10089
|
+
entityType: "agent",
|
|
10090
|
+
name: entity.data.name || id
|
|
9382
10091
|
});
|
|
9383
10092
|
}
|
|
9384
10093
|
}
|
|
9385
10094
|
return { conflicts, insertions, errors: [] };
|
|
9386
10095
|
},
|
|
9387
10096
|
async applyImport(tenantId, entity, resolution) {
|
|
9388
|
-
|
|
9389
|
-
const
|
|
9390
|
-
const
|
|
10097
|
+
const store = getStore3();
|
|
10098
|
+
const data = entity.data;
|
|
10099
|
+
const id = resolution.action === "rename" && resolution.newId ? resolution.newId : data.id;
|
|
9391
10100
|
if (resolution.action === "overwrite") {
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
);
|
|
9396
|
-
if (match) {
|
|
9397
|
-
await store.delete(match.id);
|
|
10101
|
+
try {
|
|
10102
|
+
await store.deleteAssistant(tenantId, id);
|
|
10103
|
+
} catch {
|
|
9398
10104
|
}
|
|
9399
10105
|
}
|
|
9400
|
-
await store.
|
|
9401
|
-
|
|
9402
|
-
|
|
9403
|
-
|
|
9404
|
-
senderId: d.senderId,
|
|
9405
|
-
agentId: d.agentId,
|
|
9406
|
-
threadMode: d.threadMode || "fixed",
|
|
9407
|
-
senderDisplayName: d.senderDisplayName,
|
|
9408
|
-
senderMetadata: d.senderMetadata,
|
|
9409
|
-
workspaceId: d.workspaceId,
|
|
9410
|
-
projectId: d.projectId
|
|
10106
|
+
await store.createAssistant(tenantId, id, {
|
|
10107
|
+
name: data.name,
|
|
10108
|
+
description: data.description || "",
|
|
10109
|
+
graphDefinition: data.graphDefinition
|
|
9411
10110
|
});
|
|
9412
|
-
return { newId:
|
|
10111
|
+
return { newId: id };
|
|
9413
10112
|
}
|
|
9414
10113
|
};
|
|
9415
10114
|
|
|
9416
10115
|
// src/export_registrations/database-config.registration.ts
|
|
9417
|
-
import { getStoreLattice as
|
|
9418
|
-
function
|
|
9419
|
-
return
|
|
10116
|
+
import { getStoreLattice as getStoreLattice17 } from "@axiom-lattice/core";
|
|
10117
|
+
function getStore4() {
|
|
10118
|
+
return getStoreLattice17("default", "database").store;
|
|
9420
10119
|
}
|
|
9421
10120
|
var databaseConfigRegistration = {
|
|
9422
10121
|
entityType: "database_config",
|
|
@@ -9425,24 +10124,24 @@ var databaseConfigRegistration = {
|
|
|
9425
10124
|
dependsOn: [],
|
|
9426
10125
|
cascadeParents: [],
|
|
9427
10126
|
async listForExport(tenantId) {
|
|
9428
|
-
const store =
|
|
10127
|
+
const store = getStore4();
|
|
9429
10128
|
const configs = await store.getAllConfigs(tenantId);
|
|
9430
|
-
return configs.map((
|
|
10129
|
+
return configs.map((c2) => ({
|
|
9431
10130
|
_exportId: "",
|
|
9432
10131
|
data: {
|
|
9433
|
-
id:
|
|
9434
|
-
key:
|
|
9435
|
-
name:
|
|
9436
|
-
description:
|
|
9437
|
-
config:
|
|
10132
|
+
id: c2.id,
|
|
10133
|
+
key: c2.key,
|
|
10134
|
+
name: c2.name,
|
|
10135
|
+
description: c2.description,
|
|
10136
|
+
config: c2.config
|
|
9438
10137
|
}
|
|
9439
10138
|
}));
|
|
9440
10139
|
},
|
|
9441
10140
|
async previewImport(tenantId, entities) {
|
|
9442
|
-
const store =
|
|
10141
|
+
const store = getStore4();
|
|
9443
10142
|
const existing = await store.getAllConfigs(tenantId);
|
|
9444
|
-
const existingIds = new Set(existing.map((
|
|
9445
|
-
const existingKeys = new Set(existing.map((
|
|
10143
|
+
const existingIds = new Set(existing.map((c2) => c2.id));
|
|
10144
|
+
const existingKeys = new Set(existing.map((c2) => c2.key));
|
|
9446
10145
|
const conflicts = [];
|
|
9447
10146
|
const insertions = [];
|
|
9448
10147
|
for (const entity of entities) {
|
|
@@ -9476,7 +10175,7 @@ var databaseConfigRegistration = {
|
|
|
9476
10175
|
return { conflicts, insertions, errors: [] };
|
|
9477
10176
|
},
|
|
9478
10177
|
async applyImport(tenantId, entity, resolution) {
|
|
9479
|
-
const store =
|
|
10178
|
+
const store = getStore4();
|
|
9480
10179
|
const data = entity.data;
|
|
9481
10180
|
const id = resolution.action === "rename" && resolution.newId ? resolution.newId : data.id;
|
|
9482
10181
|
if (resolution.action === "overwrite") {
|
|
@@ -9496,9 +10195,9 @@ var databaseConfigRegistration = {
|
|
|
9496
10195
|
};
|
|
9497
10196
|
|
|
9498
10197
|
// src/export_registrations/metrics-config.registration.ts
|
|
9499
|
-
import { getStoreLattice as
|
|
9500
|
-
function
|
|
9501
|
-
return
|
|
10198
|
+
import { getStoreLattice as getStoreLattice18 } from "@axiom-lattice/core";
|
|
10199
|
+
function getStore5() {
|
|
10200
|
+
return getStoreLattice18("default", "metrics").store;
|
|
9502
10201
|
}
|
|
9503
10202
|
var metricsConfigRegistration = {
|
|
9504
10203
|
entityType: "metrics_config",
|
|
@@ -9507,24 +10206,24 @@ var metricsConfigRegistration = {
|
|
|
9507
10206
|
dependsOn: [],
|
|
9508
10207
|
cascadeParents: [],
|
|
9509
10208
|
async listForExport(tenantId) {
|
|
9510
|
-
const store =
|
|
10209
|
+
const store = getStore5();
|
|
9511
10210
|
const configs = await store.getAllConfigs(tenantId);
|
|
9512
|
-
return configs.map((
|
|
10211
|
+
return configs.map((c2) => ({
|
|
9513
10212
|
_exportId: "",
|
|
9514
10213
|
data: {
|
|
9515
|
-
id:
|
|
9516
|
-
key:
|
|
9517
|
-
name:
|
|
9518
|
-
description:
|
|
9519
|
-
config:
|
|
10214
|
+
id: c2.id,
|
|
10215
|
+
key: c2.key,
|
|
10216
|
+
name: c2.name,
|
|
10217
|
+
description: c2.description,
|
|
10218
|
+
config: c2.config
|
|
9520
10219
|
}
|
|
9521
10220
|
}));
|
|
9522
10221
|
},
|
|
9523
10222
|
async previewImport(tenantId, entities) {
|
|
9524
|
-
const store =
|
|
10223
|
+
const store = getStore5();
|
|
9525
10224
|
const existing = await store.getAllConfigs(tenantId);
|
|
9526
|
-
const existingIds = new Set(existing.map((
|
|
9527
|
-
const existingKeys = new Set(existing.map((
|
|
10225
|
+
const existingIds = new Set(existing.map((c2) => c2.id));
|
|
10226
|
+
const existingKeys = new Set(existing.map((c2) => c2.key));
|
|
9528
10227
|
const conflicts = [];
|
|
9529
10228
|
const insertions = [];
|
|
9530
10229
|
for (const entity of entities) {
|
|
@@ -9558,7 +10257,7 @@ var metricsConfigRegistration = {
|
|
|
9558
10257
|
return { conflicts, insertions, errors: [] };
|
|
9559
10258
|
},
|
|
9560
10259
|
async applyImport(tenantId, entity, resolution) {
|
|
9561
|
-
const store =
|
|
10260
|
+
const store = getStore5();
|
|
9562
10261
|
const data = entity.data;
|
|
9563
10262
|
const id = resolution.action === "rename" && resolution.newId ? resolution.newId : data.id;
|
|
9564
10263
|
if (resolution.action === "overwrite") {
|
|
@@ -9578,9 +10277,9 @@ var metricsConfigRegistration = {
|
|
|
9578
10277
|
};
|
|
9579
10278
|
|
|
9580
10279
|
// src/export_registrations/mcp-config.registration.ts
|
|
9581
|
-
import { getStoreLattice as
|
|
9582
|
-
function
|
|
9583
|
-
return
|
|
10280
|
+
import { getStoreLattice as getStoreLattice19 } from "@axiom-lattice/core";
|
|
10281
|
+
function getStore6() {
|
|
10282
|
+
return getStoreLattice19("default", "mcp").store;
|
|
9584
10283
|
}
|
|
9585
10284
|
var mcpConfigRegistration = {
|
|
9586
10285
|
entityType: "mcp_config",
|
|
@@ -9589,26 +10288,26 @@ var mcpConfigRegistration = {
|
|
|
9589
10288
|
dependsOn: [],
|
|
9590
10289
|
cascadeParents: [],
|
|
9591
10290
|
async listForExport(tenantId) {
|
|
9592
|
-
const store =
|
|
10291
|
+
const store = getStore6();
|
|
9593
10292
|
const configs = await store.getAllConfigs(tenantId);
|
|
9594
|
-
return configs.map((
|
|
10293
|
+
return configs.map((c2) => ({
|
|
9595
10294
|
_exportId: "",
|
|
9596
10295
|
data: {
|
|
9597
|
-
id:
|
|
9598
|
-
key:
|
|
9599
|
-
name:
|
|
9600
|
-
description:
|
|
9601
|
-
config:
|
|
9602
|
-
selectedTools:
|
|
9603
|
-
status:
|
|
10296
|
+
id: c2.id,
|
|
10297
|
+
key: c2.key,
|
|
10298
|
+
name: c2.name,
|
|
10299
|
+
description: c2.description,
|
|
10300
|
+
config: c2.config,
|
|
10301
|
+
selectedTools: c2.selectedTools,
|
|
10302
|
+
status: c2.status
|
|
9604
10303
|
}
|
|
9605
10304
|
}));
|
|
9606
10305
|
},
|
|
9607
10306
|
async previewImport(tenantId, entities) {
|
|
9608
|
-
const store =
|
|
10307
|
+
const store = getStore6();
|
|
9609
10308
|
const existing = await store.getAllConfigs(tenantId);
|
|
9610
|
-
const existingIds = new Set(existing.map((
|
|
9611
|
-
const existingKeys = new Set(existing.map((
|
|
10309
|
+
const existingIds = new Set(existing.map((c2) => c2.id));
|
|
10310
|
+
const existingKeys = new Set(existing.map((c2) => c2.key));
|
|
9612
10311
|
const conflicts = [];
|
|
9613
10312
|
const insertions = [];
|
|
9614
10313
|
for (const entity of entities) {
|
|
@@ -9642,7 +10341,7 @@ var mcpConfigRegistration = {
|
|
|
9642
10341
|
return { conflicts, insertions, errors: [] };
|
|
9643
10342
|
},
|
|
9644
10343
|
async applyImport(tenantId, entity, resolution) {
|
|
9645
|
-
const store =
|
|
10344
|
+
const store = getStore6();
|
|
9646
10345
|
const data = entity.data;
|
|
9647
10346
|
const id = resolution.action === "rename" && resolution.newId ? resolution.newId : data.id;
|
|
9648
10347
|
if (resolution.action === "overwrite") {
|
|
@@ -9663,12 +10362,12 @@ var mcpConfigRegistration = {
|
|
|
9663
10362
|
};
|
|
9664
10363
|
|
|
9665
10364
|
// src/export_registrations/connection.registration.ts
|
|
9666
|
-
import { getStoreLattice as
|
|
9667
|
-
function
|
|
9668
|
-
return
|
|
10365
|
+
import { getStoreLattice as getStoreLattice20 } from "@axiom-lattice/core";
|
|
10366
|
+
function getStore7() {
|
|
10367
|
+
return getStoreLattice20("default", "connection").store;
|
|
9669
10368
|
}
|
|
9670
10369
|
async function listAllConnections(tenantId) {
|
|
9671
|
-
const store =
|
|
10370
|
+
const store = getStore7();
|
|
9672
10371
|
if (typeof store.listByTenant !== "function") {
|
|
9673
10372
|
throw new Error("ConnectionStore.listByTenant is not implemented. SQL bypass removed \u2014 upgrade your store adapter.");
|
|
9674
10373
|
}
|
|
@@ -9682,22 +10381,22 @@ var connectionRegistration = {
|
|
|
9682
10381
|
cascadeParents: [],
|
|
9683
10382
|
async listForExport(tenantId) {
|
|
9684
10383
|
const connections2 = await listAllConnections(tenantId);
|
|
9685
|
-
return connections2.map((
|
|
10384
|
+
return connections2.map((c2) => ({
|
|
9686
10385
|
_exportId: "",
|
|
9687
10386
|
data: {
|
|
9688
|
-
id:
|
|
9689
|
-
type:
|
|
9690
|
-
key:
|
|
9691
|
-
name:
|
|
9692
|
-
description:
|
|
9693
|
-
config:
|
|
10387
|
+
id: c2.id,
|
|
10388
|
+
type: c2.type,
|
|
10389
|
+
key: c2.key,
|
|
10390
|
+
name: c2.name,
|
|
10391
|
+
description: c2.description,
|
|
10392
|
+
config: c2.config
|
|
9694
10393
|
}
|
|
9695
10394
|
}));
|
|
9696
10395
|
},
|
|
9697
10396
|
async previewImport(tenantId, entities) {
|
|
9698
10397
|
const existing = await listAllConnections(tenantId);
|
|
9699
10398
|
const existingCompositeKeys = new Set(
|
|
9700
|
-
existing.map((
|
|
10399
|
+
existing.map((c2) => `${c2.type}:${c2.key}`)
|
|
9701
10400
|
);
|
|
9702
10401
|
const conflicts = [];
|
|
9703
10402
|
const insertions = [];
|
|
@@ -9724,7 +10423,7 @@ var connectionRegistration = {
|
|
|
9724
10423
|
},
|
|
9725
10424
|
async applyImport(tenantId, entity, resolution) {
|
|
9726
10425
|
if (resolution.action === "skip") return {};
|
|
9727
|
-
const store =
|
|
10426
|
+
const store = getStore7();
|
|
9728
10427
|
const d = entity.data;
|
|
9729
10428
|
const type = d.type;
|
|
9730
10429
|
const key = d.key;
|
|
@@ -9747,9 +10446,9 @@ var connectionRegistration = {
|
|
|
9747
10446
|
};
|
|
9748
10447
|
|
|
9749
10448
|
// src/export_registrations/collection.registration.ts
|
|
9750
|
-
import { getStoreLattice as
|
|
9751
|
-
function
|
|
9752
|
-
return
|
|
10449
|
+
import { getStoreLattice as getStoreLattice21 } from "@axiom-lattice/core";
|
|
10450
|
+
function getStore8() {
|
|
10451
|
+
return getStoreLattice21("default", "collection").store;
|
|
9753
10452
|
}
|
|
9754
10453
|
var collectionRegistration = {
|
|
9755
10454
|
entityType: "collection",
|
|
@@ -9758,23 +10457,23 @@ var collectionRegistration = {
|
|
|
9758
10457
|
dependsOn: [],
|
|
9759
10458
|
cascadeParents: [],
|
|
9760
10459
|
async listForExport(tenantId) {
|
|
9761
|
-
const store =
|
|
10460
|
+
const store = getStore8();
|
|
9762
10461
|
const collections = await store.getAllCollections(tenantId);
|
|
9763
|
-
return collections.map((
|
|
10462
|
+
return collections.map((c2) => ({
|
|
9764
10463
|
_exportId: "",
|
|
9765
10464
|
data: {
|
|
9766
|
-
id:
|
|
9767
|
-
name:
|
|
9768
|
-
label:
|
|
9769
|
-
embeddingKey:
|
|
9770
|
-
schema:
|
|
10465
|
+
id: c2.id,
|
|
10466
|
+
name: c2.name,
|
|
10467
|
+
label: c2.label,
|
|
10468
|
+
embeddingKey: c2.embeddingKey,
|
|
10469
|
+
schema: c2.schema
|
|
9771
10470
|
}
|
|
9772
10471
|
}));
|
|
9773
10472
|
},
|
|
9774
10473
|
async previewImport(tenantId, entities) {
|
|
9775
|
-
const store =
|
|
10474
|
+
const store = getStore8();
|
|
9776
10475
|
const existing = await store.getAllCollections(tenantId);
|
|
9777
|
-
const existingNames = new Set(existing.map((
|
|
10476
|
+
const existingNames = new Set(existing.map((c2) => c2.name));
|
|
9778
10477
|
const conflicts = [];
|
|
9779
10478
|
const insertions = [];
|
|
9780
10479
|
for (const entity of entities) {
|
|
@@ -9800,7 +10499,7 @@ var collectionRegistration = {
|
|
|
9800
10499
|
},
|
|
9801
10500
|
async applyImport(tenantId, entity, resolution) {
|
|
9802
10501
|
if (resolution.action === "skip") return {};
|
|
9803
|
-
const store =
|
|
10502
|
+
const store = getStore8();
|
|
9804
10503
|
const d = entity.data;
|
|
9805
10504
|
const name = d.name;
|
|
9806
10505
|
if (resolution.action === "overwrite") {
|
|
@@ -9820,9 +10519,11 @@ var collectionRegistration = {
|
|
|
9820
10519
|
};
|
|
9821
10520
|
|
|
9822
10521
|
// src/export_registrations/channel-installation.registration.ts
|
|
9823
|
-
import { getStoreLattice as
|
|
9824
|
-
|
|
9825
|
-
|
|
10522
|
+
import { getStoreLattice as getStoreLattice22 } from "@axiom-lattice/core";
|
|
10523
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
10524
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
10525
|
+
function getStore9() {
|
|
10526
|
+
return getStoreLattice22("default", "channelInstallation").store;
|
|
9826
10527
|
}
|
|
9827
10528
|
var channelInstallationRegistration = {
|
|
9828
10529
|
entityType: "channel_installation",
|
|
@@ -9832,7 +10533,7 @@ var channelInstallationRegistration = {
|
|
|
9832
10533
|
cascadeParents: [],
|
|
9833
10534
|
referenceFields: { fallbackAgentId: "agent" },
|
|
9834
10535
|
async listForExport(tenantId) {
|
|
9835
|
-
const store =
|
|
10536
|
+
const store = getStore9();
|
|
9836
10537
|
const installations = await store.getInstallationsByTenant(tenantId);
|
|
9837
10538
|
return installations.map((i) => ({
|
|
9838
10539
|
_exportId: "",
|
|
@@ -9848,21 +10549,20 @@ var channelInstallationRegistration = {
|
|
|
9848
10549
|
}));
|
|
9849
10550
|
},
|
|
9850
10551
|
async previewImport(tenantId, entities) {
|
|
9851
|
-
const store =
|
|
9852
|
-
const existing = await store.getInstallationsByTenant(tenantId);
|
|
9853
|
-
const existingIds = new Set(existing.map((i) => i.id));
|
|
10552
|
+
const store = getStore9();
|
|
9854
10553
|
const conflicts = [];
|
|
9855
10554
|
const insertions = [];
|
|
9856
10555
|
for (const entity of entities) {
|
|
9857
10556
|
const d = entity.data;
|
|
9858
10557
|
const id = d.id;
|
|
9859
|
-
|
|
10558
|
+
const existing = UUID_PATTERN.test(id) ? await store.getInstallationById(id) : null;
|
|
10559
|
+
if (existing) {
|
|
9860
10560
|
conflicts.push({
|
|
9861
10561
|
_exportId: entity._exportId,
|
|
9862
10562
|
entityType: "channel_installation",
|
|
9863
10563
|
conflictType: "id_exists",
|
|
9864
10564
|
existingId: id,
|
|
9865
|
-
existingName:
|
|
10565
|
+
existingName: existing.name || id
|
|
9866
10566
|
});
|
|
9867
10567
|
} else {
|
|
9868
10568
|
insertions.push({
|
|
@@ -9875,31 +10575,56 @@ var channelInstallationRegistration = {
|
|
|
9875
10575
|
return { conflicts, insertions, errors: [] };
|
|
9876
10576
|
},
|
|
9877
10577
|
async applyImport(tenantId, entity, resolution) {
|
|
9878
|
-
const store =
|
|
10578
|
+
const store = getStore9();
|
|
9879
10579
|
const data = entity.data;
|
|
9880
|
-
const
|
|
10580
|
+
const sourceId = data.id;
|
|
10581
|
+
const commonData = {
|
|
10582
|
+
name: data.name,
|
|
10583
|
+
enabled: data.enabled,
|
|
10584
|
+
fallbackAgentId: data.fallbackAgentId,
|
|
10585
|
+
rejectWhenNoBinding: data.rejectWhenNoBinding
|
|
10586
|
+
};
|
|
9881
10587
|
if (resolution.action === "overwrite") {
|
|
9882
|
-
|
|
9883
|
-
|
|
9884
|
-
|
|
10588
|
+
const existing = await store.getInstallationById(sourceId);
|
|
10589
|
+
if (!existing || !UUID_PATTERN.test(existing.id)) {
|
|
10590
|
+
throw new Error("Channel installation overwrite target must be an existing UUID");
|
|
10591
|
+
}
|
|
10592
|
+
const updated = await store.updateInstallation(tenantId, existing.id, {
|
|
10593
|
+
...commonData,
|
|
10594
|
+
config: data.config
|
|
10595
|
+
});
|
|
10596
|
+
if (!updated) {
|
|
10597
|
+
throw new Error("Channel installation overwrite target is not available in the target tenant");
|
|
9885
10598
|
}
|
|
10599
|
+
return { newId: existing.id };
|
|
10600
|
+
}
|
|
10601
|
+
let id;
|
|
10602
|
+
if (resolution.action === "rename") {
|
|
10603
|
+
if (!resolution.newId || !UUID_PATTERN.test(resolution.newId)) {
|
|
10604
|
+
throw new Error("Channel installation rename ID must be a valid UUID");
|
|
10605
|
+
}
|
|
10606
|
+
id = resolution.newId;
|
|
10607
|
+
} else if (UUID_PATTERN.test(sourceId)) {
|
|
10608
|
+
if (await store.getInstallationById(sourceId)) {
|
|
10609
|
+
throw new Error(`Channel installation UUID already exists: ${sourceId}`);
|
|
10610
|
+
}
|
|
10611
|
+
id = sourceId;
|
|
10612
|
+
} else {
|
|
10613
|
+
id = randomUUID9();
|
|
9886
10614
|
}
|
|
9887
10615
|
await store.createInstallation(tenantId, id, {
|
|
9888
10616
|
channel: data.channel,
|
|
9889
|
-
|
|
9890
|
-
config: data.config
|
|
9891
|
-
enabled: data.enabled,
|
|
9892
|
-
fallbackAgentId: data.fallbackAgentId,
|
|
9893
|
-
rejectWhenNoBinding: data.rejectWhenNoBinding
|
|
10617
|
+
...commonData,
|
|
10618
|
+
config: data.config
|
|
9894
10619
|
});
|
|
9895
10620
|
return { newId: id };
|
|
9896
10621
|
}
|
|
9897
10622
|
};
|
|
9898
10623
|
|
|
9899
10624
|
// src/export_registrations/menu.registration.ts
|
|
9900
|
-
import { getStoreLattice as
|
|
9901
|
-
function
|
|
9902
|
-
return
|
|
10625
|
+
import { getStoreLattice as getStoreLattice23 } from "@axiom-lattice/core";
|
|
10626
|
+
function getStore10() {
|
|
10627
|
+
return getStoreLattice23("default", "menu").store;
|
|
9903
10628
|
}
|
|
9904
10629
|
var menuRegistration = {
|
|
9905
10630
|
entityType: "menu",
|
|
@@ -9908,7 +10633,7 @@ var menuRegistration = {
|
|
|
9908
10633
|
dependsOn: ["agent"],
|
|
9909
10634
|
cascadeParents: [],
|
|
9910
10635
|
async listForExport(tenantId) {
|
|
9911
|
-
const store =
|
|
10636
|
+
const store = getStore10();
|
|
9912
10637
|
const menus = await store.list({ tenantId });
|
|
9913
10638
|
return menus.map((m) => ({
|
|
9914
10639
|
_exportId: "",
|
|
@@ -9926,7 +10651,7 @@ var menuRegistration = {
|
|
|
9926
10651
|
}));
|
|
9927
10652
|
},
|
|
9928
10653
|
async previewImport(tenantId, entities) {
|
|
9929
|
-
const store =
|
|
10654
|
+
const store = getStore10();
|
|
9930
10655
|
const existing = await store.list({ tenantId });
|
|
9931
10656
|
const existingIds = new Set(existing.map((m) => m.id));
|
|
9932
10657
|
const conflicts = [];
|
|
@@ -9953,7 +10678,7 @@ var menuRegistration = {
|
|
|
9953
10678
|
return { conflicts, insertions, errors: [] };
|
|
9954
10679
|
},
|
|
9955
10680
|
async applyImport(tenantId, entity, resolution) {
|
|
9956
|
-
const store =
|
|
10681
|
+
const store = getStore10();
|
|
9957
10682
|
const d = entity.data;
|
|
9958
10683
|
const id = resolution.action === "rename" && resolution.newId ? resolution.newId : d.id;
|
|
9959
10684
|
if (resolution.action === "overwrite") {
|
|
@@ -9976,171 +10701,10 @@ var menuRegistration = {
|
|
|
9976
10701
|
}
|
|
9977
10702
|
};
|
|
9978
10703
|
|
|
9979
|
-
// src/export_registrations/task.registration.ts
|
|
9980
|
-
import { getStoreLattice as getStoreLattice26 } from "@axiom-lattice/core";
|
|
9981
|
-
function getStore12() {
|
|
9982
|
-
return getStoreLattice26("default", "task").store;
|
|
9983
|
-
}
|
|
9984
|
-
var taskRegistration = {
|
|
9985
|
-
entityType: "task",
|
|
9986
|
-
label: "Task(\u4EFB\u52A1)",
|
|
9987
|
-
category: "core",
|
|
9988
|
-
dependsOn: ["agent"],
|
|
9989
|
-
cascadeParents: [],
|
|
9990
|
-
referenceFields: { ownerId: "agent", parentId: "task" },
|
|
9991
|
-
async listForExport(tenantId) {
|
|
9992
|
-
const store = getStore12();
|
|
9993
|
-
const tasks = await store.list({ tenantId, limit: 1e4, offset: 0 });
|
|
9994
|
-
return tasks.map((t) => ({
|
|
9995
|
-
_exportId: "",
|
|
9996
|
-
data: {
|
|
9997
|
-
id: t.id,
|
|
9998
|
-
title: t.title,
|
|
9999
|
-
description: t.description,
|
|
10000
|
-
status: t.status,
|
|
10001
|
-
priority: t.priority,
|
|
10002
|
-
dueDate: t.dueDate,
|
|
10003
|
-
ownerType: t.ownerType,
|
|
10004
|
-
ownerId: t.ownerId,
|
|
10005
|
-
metadata: t.metadata,
|
|
10006
|
-
parentId: t.parentId,
|
|
10007
|
-
sourceId: t.sourceId,
|
|
10008
|
-
context: t.context
|
|
10009
|
-
}
|
|
10010
|
-
}));
|
|
10011
|
-
},
|
|
10012
|
-
async previewImport(tenantId, entities) {
|
|
10013
|
-
const store = getStore12();
|
|
10014
|
-
const existing = await store.list({ tenantId, limit: 1e4, offset: 0 });
|
|
10015
|
-
const existingIds = new Set(existing.map((t) => t.id));
|
|
10016
|
-
const conflicts = [];
|
|
10017
|
-
const insertions = [];
|
|
10018
|
-
for (const entity of entities) {
|
|
10019
|
-
const d = entity.data;
|
|
10020
|
-
const id = d.id;
|
|
10021
|
-
if (existingIds.has(id)) {
|
|
10022
|
-
conflicts.push({
|
|
10023
|
-
_exportId: entity._exportId,
|
|
10024
|
-
entityType: "task",
|
|
10025
|
-
conflictType: "id_exists",
|
|
10026
|
-
existingId: id,
|
|
10027
|
-
existingName: d.title || id
|
|
10028
|
-
});
|
|
10029
|
-
} else {
|
|
10030
|
-
insertions.push({
|
|
10031
|
-
_exportId: entity._exportId,
|
|
10032
|
-
entityType: "task",
|
|
10033
|
-
name: d.title || id
|
|
10034
|
-
});
|
|
10035
|
-
}
|
|
10036
|
-
}
|
|
10037
|
-
return { conflicts, insertions, errors: [] };
|
|
10038
|
-
},
|
|
10039
|
-
async applyImport(tenantId, entity, resolution) {
|
|
10040
|
-
const store = getStore12();
|
|
10041
|
-
const data = entity.data;
|
|
10042
|
-
const id = resolution.action === "rename" && resolution.newId ? resolution.newId : data.id;
|
|
10043
|
-
if (resolution.action === "overwrite") {
|
|
10044
|
-
try {
|
|
10045
|
-
await store.delete(tenantId, id);
|
|
10046
|
-
} catch {
|
|
10047
|
-
}
|
|
10048
|
-
}
|
|
10049
|
-
await store.create({
|
|
10050
|
-
tenantId,
|
|
10051
|
-
ownerType: data.ownerType || "user",
|
|
10052
|
-
ownerId: data.ownerId || "",
|
|
10053
|
-
title: data.title,
|
|
10054
|
-
description: data.description,
|
|
10055
|
-
status: data.status,
|
|
10056
|
-
priority: data.priority,
|
|
10057
|
-
dueDate: data.dueDate,
|
|
10058
|
-
metadata: data.metadata,
|
|
10059
|
-
parentId: data.parentId,
|
|
10060
|
-
sourceId: data.sourceId,
|
|
10061
|
-
context: data.context
|
|
10062
|
-
});
|
|
10063
|
-
return { newId: id };
|
|
10064
|
-
}
|
|
10065
|
-
};
|
|
10066
|
-
|
|
10067
|
-
// src/export_registrations/a2a-api-key.registration.ts
|
|
10068
|
-
import { getStoreLattice as getStoreLattice27 } from "@axiom-lattice/core";
|
|
10069
|
-
function getStore13() {
|
|
10070
|
-
return getStoreLattice27("default", "a2aApiKey").store;
|
|
10071
|
-
}
|
|
10072
|
-
var a2aApiKeyRegistration = {
|
|
10073
|
-
entityType: "a2a_api_key",
|
|
10074
|
-
label: "A2A API Key(API\u5BC6\u94A5)",
|
|
10075
|
-
category: "core",
|
|
10076
|
-
dependsOn: [],
|
|
10077
|
-
cascadeParents: [],
|
|
10078
|
-
async listForExport(tenantId) {
|
|
10079
|
-
const store = getStore13();
|
|
10080
|
-
const keys = await store.list({ tenantId, limit: 1e4, offset: 0 });
|
|
10081
|
-
return keys.map((k) => ({
|
|
10082
|
-
_exportId: "",
|
|
10083
|
-
data: {
|
|
10084
|
-
id: k.id,
|
|
10085
|
-
tenantId: k.tenantId,
|
|
10086
|
-
projectId: k.projectId,
|
|
10087
|
-
workspaceId: k.workspaceId,
|
|
10088
|
-
label: k.label,
|
|
10089
|
-
enabled: k.enabled
|
|
10090
|
-
}
|
|
10091
|
-
}));
|
|
10092
|
-
},
|
|
10093
|
-
async previewImport(tenantId, entities) {
|
|
10094
|
-
const store = getStore13();
|
|
10095
|
-
const existing = await store.list({ tenantId, limit: 1e4, offset: 0 });
|
|
10096
|
-
const existingIds = new Set(existing.map((k) => k.id));
|
|
10097
|
-
const conflicts = [];
|
|
10098
|
-
const insertions = [];
|
|
10099
|
-
for (const entity of entities) {
|
|
10100
|
-
const d = entity.data;
|
|
10101
|
-
const id = d.id;
|
|
10102
|
-
if (existingIds.has(id)) {
|
|
10103
|
-
conflicts.push({
|
|
10104
|
-
_exportId: entity._exportId,
|
|
10105
|
-
entityType: "a2a_api_key",
|
|
10106
|
-
conflictType: "id_exists",
|
|
10107
|
-
existingId: id,
|
|
10108
|
-
existingName: d.label || id
|
|
10109
|
-
});
|
|
10110
|
-
} else {
|
|
10111
|
-
insertions.push({
|
|
10112
|
-
_exportId: entity._exportId,
|
|
10113
|
-
entityType: "a2a_api_key",
|
|
10114
|
-
name: d.label || id
|
|
10115
|
-
});
|
|
10116
|
-
}
|
|
10117
|
-
}
|
|
10118
|
-
return { conflicts, insertions, errors: [] };
|
|
10119
|
-
},
|
|
10120
|
-
async applyImport(tenantId, entity, resolution) {
|
|
10121
|
-
if (resolution.action === "skip") return {};
|
|
10122
|
-
const store = getStore13();
|
|
10123
|
-
const d = entity.data;
|
|
10124
|
-
if (resolution.action === "overwrite") {
|
|
10125
|
-
try {
|
|
10126
|
-
await store.delete(d.id);
|
|
10127
|
-
} catch {
|
|
10128
|
-
}
|
|
10129
|
-
}
|
|
10130
|
-
await store.create({
|
|
10131
|
-
tenantId,
|
|
10132
|
-
projectId: d.projectId,
|
|
10133
|
-
workspaceId: d.workspaceId,
|
|
10134
|
-
label: d.label
|
|
10135
|
-
});
|
|
10136
|
-
return { newId: void 0 };
|
|
10137
|
-
}
|
|
10138
|
-
};
|
|
10139
|
-
|
|
10140
10704
|
// src/export_registrations/eval.registration.ts
|
|
10141
|
-
import { getStoreLattice as
|
|
10142
|
-
function
|
|
10143
|
-
return
|
|
10705
|
+
import { getStoreLattice as getStoreLattice24 } from "@axiom-lattice/core";
|
|
10706
|
+
function getStore11() {
|
|
10707
|
+
return getStoreLattice24("default", "eval").store;
|
|
10144
10708
|
}
|
|
10145
10709
|
var evalRegistration = {
|
|
10146
10710
|
entityType: "eval",
|
|
@@ -10150,7 +10714,7 @@ var evalRegistration = {
|
|
|
10150
10714
|
cascadeParents: [],
|
|
10151
10715
|
referenceFields: { suiteId: "eval_suite", projectId: "eval_project", runId: "eval_run", caseId: "eval_case" },
|
|
10152
10716
|
async listForExport(tenantId) {
|
|
10153
|
-
const store =
|
|
10717
|
+
const store = getStore11();
|
|
10154
10718
|
const projects = await store.getProjectsByTenant(tenantId);
|
|
10155
10719
|
const entities = [];
|
|
10156
10720
|
for (const project of projects) {
|
|
@@ -10180,19 +10744,19 @@ var evalRegistration = {
|
|
|
10180
10744
|
}
|
|
10181
10745
|
});
|
|
10182
10746
|
const cases = await store.getCasesBySuite(tenantId, suite.id);
|
|
10183
|
-
for (const
|
|
10747
|
+
for (const c2 of cases) {
|
|
10184
10748
|
entities.push({
|
|
10185
10749
|
_exportId: "",
|
|
10186
10750
|
data: {
|
|
10187
10751
|
_subType: "eval_case",
|
|
10188
|
-
id:
|
|
10189
|
-
suiteId:
|
|
10190
|
-
inputMessage:
|
|
10191
|
-
inputFiles:
|
|
10192
|
-
steps:
|
|
10193
|
-
outputType:
|
|
10194
|
-
contentAssertion:
|
|
10195
|
-
rubrics:
|
|
10752
|
+
id: c2.id,
|
|
10753
|
+
suiteId: c2.suiteId,
|
|
10754
|
+
inputMessage: c2.inputMessage,
|
|
10755
|
+
inputFiles: c2.inputFiles,
|
|
10756
|
+
steps: c2.steps,
|
|
10757
|
+
outputType: c2.outputType,
|
|
10758
|
+
contentAssertion: c2.contentAssertion,
|
|
10759
|
+
rubrics: c2.rubrics
|
|
10196
10760
|
}
|
|
10197
10761
|
});
|
|
10198
10762
|
}
|
|
@@ -10240,7 +10804,7 @@ var evalRegistration = {
|
|
|
10240
10804
|
return entities;
|
|
10241
10805
|
},
|
|
10242
10806
|
async previewImport(tenantId, entities) {
|
|
10243
|
-
const store =
|
|
10807
|
+
const store = getStore11();
|
|
10244
10808
|
const existingProjects = await store.getProjectsByTenant(tenantId);
|
|
10245
10809
|
const existingProjectIds = new Set(existingProjects.map((p) => p.id));
|
|
10246
10810
|
const existingProjectNames = new Set(existingProjects.map((p) => p.name));
|
|
@@ -10256,7 +10820,7 @@ var evalRegistration = {
|
|
|
10256
10820
|
existingSuiteIds.add(s.id);
|
|
10257
10821
|
try {
|
|
10258
10822
|
const cases = await store.getCasesBySuite(tenantId, s.id);
|
|
10259
|
-
for (const
|
|
10823
|
+
for (const c2 of cases) existingCaseIds.add(c2.id);
|
|
10260
10824
|
} catch {
|
|
10261
10825
|
}
|
|
10262
10826
|
}
|
|
@@ -10373,7 +10937,7 @@ var evalRegistration = {
|
|
|
10373
10937
|
},
|
|
10374
10938
|
async applyImport(tenantId, entity, resolution) {
|
|
10375
10939
|
if (resolution.action === "skip") return {};
|
|
10376
|
-
const store =
|
|
10940
|
+
const store = getStore11();
|
|
10377
10941
|
const d = entity.data;
|
|
10378
10942
|
const subType = d._subType;
|
|
10379
10943
|
const id = resolution.action === "rename" && resolution.newId ? resolution.newId : d.id;
|
|
@@ -10469,7 +11033,6 @@ function registerAllBuiltinEntities() {
|
|
|
10469
11033
|
const registry = ExportableEntityRegistry3.getInstance();
|
|
10470
11034
|
registry.register(skillRegistration);
|
|
10471
11035
|
registry.register(agentRegistration);
|
|
10472
|
-
registry.register(bindingRegistration);
|
|
10473
11036
|
registry.register(databaseConfigRegistration);
|
|
10474
11037
|
registry.register(metricsConfigRegistration);
|
|
10475
11038
|
registry.register(mcpConfigRegistration);
|
|
@@ -10477,23 +11040,33 @@ function registerAllBuiltinEntities() {
|
|
|
10477
11040
|
registry.register(collectionRegistration);
|
|
10478
11041
|
registry.register(channelInstallationRegistration);
|
|
10479
11042
|
registry.register(menuRegistration);
|
|
10480
|
-
registry.register(taskRegistration);
|
|
10481
|
-
registry.register(a2aApiKeyRegistration);
|
|
10482
11043
|
registry.register(evalRegistration);
|
|
10483
11044
|
}
|
|
10484
11045
|
|
|
10485
11046
|
// src/router/MessageRouter.ts
|
|
10486
11047
|
import {
|
|
10487
|
-
getStoreLattice as
|
|
11048
|
+
getStoreLattice as getStoreLattice25,
|
|
10488
11049
|
agentInstanceManager as agentInstanceManager6
|
|
10489
11050
|
} from "@axiom-lattice/core";
|
|
10490
|
-
import { randomUUID as
|
|
11051
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
10491
11052
|
var BindingNotFoundError = class extends Error {
|
|
10492
11053
|
constructor(message) {
|
|
10493
11054
|
super(message);
|
|
10494
11055
|
this.name = "BindingNotFoundError";
|
|
10495
11056
|
}
|
|
10496
11057
|
};
|
|
11058
|
+
var ChannelInstallationNotFoundError = class extends Error {
|
|
11059
|
+
constructor() {
|
|
11060
|
+
super("Channel installation is unavailable");
|
|
11061
|
+
this.name = "ChannelInstallationNotFoundError";
|
|
11062
|
+
}
|
|
11063
|
+
};
|
|
11064
|
+
var InvalidChannelInstallationError = class extends Error {
|
|
11065
|
+
constructor(message = "Channel installation is not valid for this message") {
|
|
11066
|
+
super(message);
|
|
11067
|
+
this.name = "InvalidChannelInstallationError";
|
|
11068
|
+
}
|
|
11069
|
+
};
|
|
10497
11070
|
var MessageRouter = class {
|
|
10498
11071
|
constructor(config) {
|
|
10499
11072
|
/**
|
|
@@ -10538,20 +11111,20 @@ var MessageRouter = class {
|
|
|
10538
11111
|
let threadId;
|
|
10539
11112
|
let agentId;
|
|
10540
11113
|
try {
|
|
11114
|
+
const installation = await this.installationStore.getInstallationById(
|
|
11115
|
+
message.channelInstallationId
|
|
11116
|
+
);
|
|
11117
|
+
if (!installation) {
|
|
11118
|
+
throw new ChannelInstallationNotFoundError();
|
|
11119
|
+
}
|
|
11120
|
+
if (installation.enabled !== true) {
|
|
11121
|
+
throw new InvalidChannelInstallationError("Channel installation is disabled");
|
|
11122
|
+
}
|
|
11123
|
+
if (installation.channel !== message.channel || message.tenantId !== void 0 && message.tenantId !== installation.tenantId) {
|
|
11124
|
+
throw new InvalidChannelInstallationError();
|
|
11125
|
+
}
|
|
11126
|
+
const tenantId = installation.tenantId;
|
|
10541
11127
|
await this.runMiddlewares(ctx, async () => {
|
|
10542
|
-
const tenantId = message.tenantId || (await this.installationStore.getInstallationById(message.channelInstallationId))?.tenantId;
|
|
10543
|
-
if (!tenantId) {
|
|
10544
|
-
console.error({
|
|
10545
|
-
event: "dispatch:error",
|
|
10546
|
-
error: "tenantId missing",
|
|
10547
|
-
channel: message.channel,
|
|
10548
|
-
channelInstallationId: message.channelInstallationId,
|
|
10549
|
-
senderId: message.sender.id
|
|
10550
|
-
}, "tenantId is required");
|
|
10551
|
-
throw new Error(
|
|
10552
|
-
"tenantId is required: provide it in the message or ensure the channelInstallation has a tenantId"
|
|
10553
|
-
);
|
|
10554
|
-
}
|
|
10555
11128
|
console.log({ event: "dispatch:start", channel: message.channel, senderId: message.sender.id, tenantId }, "Message dispatch started");
|
|
10556
11129
|
const adapter = this.adapterRegistry.get(message.channel);
|
|
10557
11130
|
const hasAdapterThreadStrategy = !!adapter?.resolveThreadId;
|
|
@@ -10561,11 +11134,8 @@ var MessageRouter = class {
|
|
|
10561
11134
|
channelInstallationId: message.channelInstallationId,
|
|
10562
11135
|
tenantId
|
|
10563
11136
|
});
|
|
10564
|
-
const installation = await this.installationStore.getInstallationById(
|
|
10565
|
-
message.channelInstallationId
|
|
10566
|
-
);
|
|
10567
11137
|
if (!binding) {
|
|
10568
|
-
if (installation
|
|
11138
|
+
if (installation.rejectWhenNoBinding) {
|
|
10569
11139
|
console.warn({
|
|
10570
11140
|
event: "dispatch:no_binding",
|
|
10571
11141
|
channel: message.channel,
|
|
@@ -10577,7 +11147,7 @@ var MessageRouter = class {
|
|
|
10577
11147
|
`No binding for sender "${message.sender.id}" on channel "${message.channel}"`
|
|
10578
11148
|
);
|
|
10579
11149
|
}
|
|
10580
|
-
if (installation
|
|
11150
|
+
if (installation.fallbackAgentId) {
|
|
10581
11151
|
console.warn({
|
|
10582
11152
|
event: "dispatch:fallback",
|
|
10583
11153
|
channel: message.channel,
|
|
@@ -10632,7 +11202,7 @@ var MessageRouter = class {
|
|
|
10632
11202
|
);
|
|
10633
11203
|
}
|
|
10634
11204
|
}
|
|
10635
|
-
agentId = binding?.agentId ?? installation
|
|
11205
|
+
agentId = binding?.agentId ?? installation.fallbackAgentId;
|
|
10636
11206
|
if (!agentId) {
|
|
10637
11207
|
throw new BindingNotFoundError(
|
|
10638
11208
|
`No agent configured for sender "${message.sender.id}"`
|
|
@@ -10647,7 +11217,7 @@ var MessageRouter = class {
|
|
|
10647
11217
|
channel: message.channel,
|
|
10648
11218
|
adapterChannel: adapter.channel
|
|
10649
11219
|
}, "Thread resolved by adapter strategy");
|
|
10650
|
-
const threadStore =
|
|
11220
|
+
const threadStore = getStoreLattice25("default", "thread").store;
|
|
10651
11221
|
try {
|
|
10652
11222
|
await threadStore.createThread(
|
|
10653
11223
|
tenantId,
|
|
@@ -10684,8 +11254,8 @@ var MessageRouter = class {
|
|
|
10684
11254
|
}
|
|
10685
11255
|
}
|
|
10686
11256
|
if (!threadId) {
|
|
10687
|
-
const threadStore =
|
|
10688
|
-
const newThreadId =
|
|
11257
|
+
const threadStore = getStoreLattice25("default", "thread").store;
|
|
11258
|
+
const newThreadId = randomUUID10();
|
|
10689
11259
|
console.log({
|
|
10690
11260
|
event: "dispatch:thread:create",
|
|
10691
11261
|
agentId,
|
|
@@ -10735,78 +11305,73 @@ var MessageRouter = class {
|
|
|
10735
11305
|
const replySubKey = `${threadId}:${message.replyTarget.adapterChannel}:reply`;
|
|
10736
11306
|
const adapter2 = this.adapterRegistry.get(message.replyTarget.adapterChannel);
|
|
10737
11307
|
if (adapter2) {
|
|
10738
|
-
const
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
11308
|
+
const existing = this._replySubs.get(replySubKey);
|
|
11309
|
+
if (!existing || existing.count === 0) {
|
|
11310
|
+
const timer = setTimeout(() => {
|
|
11311
|
+
const entry = this._replySubs.get(replySubKey);
|
|
11312
|
+
if (entry) {
|
|
11313
|
+
this._replySubs.delete(replySubKey);
|
|
11314
|
+
console.warn({
|
|
11315
|
+
event: "dispatch:reply:timeout",
|
|
11316
|
+
threadId,
|
|
11317
|
+
channel: message.replyTarget.adapterChannel
|
|
11318
|
+
}, "Reply subscription timed out \u2014 no reply:ready fired within 1h");
|
|
11319
|
+
}
|
|
11320
|
+
}, 36e5);
|
|
11321
|
+
this._replySubs.set(replySubKey, { count: 1, timer });
|
|
11322
|
+
console.log({
|
|
11323
|
+
event: "dispatch:reply:subscribed",
|
|
11324
|
+
threadId,
|
|
11325
|
+
channel: message.replyTarget.adapterChannel,
|
|
11326
|
+
senderId: message.sender.id
|
|
11327
|
+
}, "Subscribed to reply:ready for thread");
|
|
11328
|
+
agent.subscribeOnce("reply:ready", (data) => {
|
|
11329
|
+
const messages = data.state?.values?.messages;
|
|
11330
|
+
const lastAI = messages?.filter((m) => m.type === "ai" || m.getType?.() === "ai").pop();
|
|
11331
|
+
const replyText = lastAI?.content ?? "";
|
|
11332
|
+
const entry = this._replySubs.get(replySubKey);
|
|
11333
|
+
if (entry) {
|
|
11334
|
+
entry.count--;
|
|
11335
|
+
if (entry.count <= 0) {
|
|
11336
|
+
clearTimeout(entry.timer);
|
|
10747
11337
|
this._replySubs.delete(replySubKey);
|
|
10748
|
-
console.warn({
|
|
10749
|
-
event: "dispatch:reply:timeout",
|
|
10750
|
-
threadId,
|
|
10751
|
-
channel: message.replyTarget.adapterChannel
|
|
10752
|
-
}, "Reply subscription timed out \u2014 no reply:ready fired within 1h");
|
|
10753
11338
|
}
|
|
10754
|
-
}
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
const messages = data.state?.values?.messages;
|
|
10764
|
-
const lastAI = messages?.filter((m) => m.type === "ai" || m.getType?.() === "ai").pop();
|
|
10765
|
-
const replyText = lastAI?.content ?? "";
|
|
10766
|
-
const entry = this._replySubs.get(replySubKey);
|
|
10767
|
-
if (entry) {
|
|
10768
|
-
entry.count--;
|
|
10769
|
-
if (entry.count <= 0) {
|
|
10770
|
-
clearTimeout(entry.timer);
|
|
10771
|
-
this._replySubs.delete(replySubKey);
|
|
10772
|
-
}
|
|
10773
|
-
}
|
|
10774
|
-
if (replyText) {
|
|
11339
|
+
}
|
|
11340
|
+
if (replyText) {
|
|
11341
|
+
console.log({
|
|
11342
|
+
event: "dispatch:reply:sending",
|
|
11343
|
+
threadId,
|
|
11344
|
+
channel: message.replyTarget.adapterChannel,
|
|
11345
|
+
replyLength: replyText.length
|
|
11346
|
+
}, "Sending channel reply");
|
|
11347
|
+
adapter2.sendReply(message.replyTarget, { text: replyText }, installation).then(() => {
|
|
10775
11348
|
console.log({
|
|
10776
|
-
event: "dispatch:reply:
|
|
10777
|
-
threadId,
|
|
10778
|
-
channel: message.replyTarget.adapterChannel,
|
|
10779
|
-
replyLength: replyText.length
|
|
10780
|
-
}, "Sending channel reply");
|
|
10781
|
-
adapter2.sendReply(message.replyTarget, { text: replyText }, installation2).then(() => {
|
|
10782
|
-
console.log({
|
|
10783
|
-
event: "dispatch:reply:sent",
|
|
10784
|
-
threadId,
|
|
10785
|
-
channel: message.replyTarget.adapterChannel
|
|
10786
|
-
}, "Channel reply sent successfully");
|
|
10787
|
-
}).catch((err) => console.error({
|
|
10788
|
-
event: "dispatch:reply:failed",
|
|
10789
|
-
threadId,
|
|
10790
|
-
channel: message.replyTarget.adapterChannel,
|
|
10791
|
-
error: err instanceof Error ? err.message : String(err)
|
|
10792
|
-
}, "Failed to send channel reply"));
|
|
10793
|
-
} else {
|
|
10794
|
-
console.warn({
|
|
10795
|
-
event: "dispatch:reply:empty",
|
|
11349
|
+
event: "dispatch:reply:sent",
|
|
10796
11350
|
threadId,
|
|
10797
11351
|
channel: message.replyTarget.adapterChannel
|
|
10798
|
-
}, "
|
|
10799
|
-
}
|
|
10800
|
-
|
|
10801
|
-
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
11352
|
+
}, "Channel reply sent successfully");
|
|
11353
|
+
}).catch((err) => console.error({
|
|
11354
|
+
event: "dispatch:reply:failed",
|
|
11355
|
+
threadId,
|
|
11356
|
+
channel: message.replyTarget.adapterChannel,
|
|
11357
|
+
error: err instanceof Error ? err.message : String(err)
|
|
11358
|
+
}, "Failed to send channel reply"));
|
|
11359
|
+
} else {
|
|
11360
|
+
console.warn({
|
|
11361
|
+
event: "dispatch:reply:empty",
|
|
11362
|
+
threadId,
|
|
11363
|
+
channel: message.replyTarget.adapterChannel
|
|
11364
|
+
}, "Agent produced no text output \u2014 skipping reply");
|
|
11365
|
+
}
|
|
11366
|
+
});
|
|
11367
|
+
} else {
|
|
11368
|
+
existing.count++;
|
|
11369
|
+
console.log({
|
|
11370
|
+
event: "dispatch:reply:incremented",
|
|
11371
|
+
threadId,
|
|
11372
|
+
channel: message.replyTarget.adapterChannel,
|
|
11373
|
+
count: existing.count
|
|
11374
|
+
}, "Incremented reply counter for thread (already subscribed)");
|
|
10810
11375
|
}
|
|
10811
11376
|
}
|
|
10812
11377
|
}
|
|
@@ -11110,7 +11675,7 @@ ${summary}`
|
|
|
11110
11675
|
console.log(
|
|
11111
11676
|
`\u5C06\u5728 ${delayMs}ms \u540E\u91CD\u8BD5\u4EFB\u52A1 (${nextRetryCount}/${maxRetries})`
|
|
11112
11677
|
);
|
|
11113
|
-
await new Promise((
|
|
11678
|
+
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
11114
11679
|
return handleAgentTask(taskRequest, nextRetryCount);
|
|
11115
11680
|
}
|
|
11116
11681
|
if (callback_event) {
|
|
@@ -11290,7 +11855,7 @@ import {
|
|
|
11290
11855
|
getLoggerLattice,
|
|
11291
11856
|
loggerLatticeManager,
|
|
11292
11857
|
sandboxLatticeManager as sandboxLatticeManager2,
|
|
11293
|
-
getStoreLattice as
|
|
11858
|
+
getStoreLattice as getStoreLattice26,
|
|
11294
11859
|
agentInstanceManager as agentInstanceManager8,
|
|
11295
11860
|
createSandboxProvider,
|
|
11296
11861
|
TokenCache,
|
|
@@ -11340,26 +11905,8 @@ var getHeaderValue = (header) => {
|
|
|
11340
11905
|
}
|
|
11341
11906
|
return header;
|
|
11342
11907
|
};
|
|
11343
|
-
var
|
|
11344
|
-
app
|
|
11345
|
-
const user = extractUserFromAuthHeader(request.headers.authorization);
|
|
11346
|
-
if (user) {
|
|
11347
|
-
request.user = user;
|
|
11348
|
-
return;
|
|
11349
|
-
}
|
|
11350
|
-
const authRequired = process.env.AUTH_REQUIRED === "true";
|
|
11351
|
-
if (!authRequired) return;
|
|
11352
|
-
if (request.method === "OPTIONS") return;
|
|
11353
|
-
if (PUBLIC_ROUTES.some((r) => request.url === r)) return;
|
|
11354
|
-
if (request.url.startsWith("/s/")) return;
|
|
11355
|
-
const urlPath = request.url.split("?")[0];
|
|
11356
|
-
if (urlPath.includes("/viewfile") || urlPath.includes("/downloadfile") || urlPath.includes("/uploadfile")) return;
|
|
11357
|
-
if (urlPath.startsWith("/f/") || urlPath === "/f") return;
|
|
11358
|
-
return reply.status(401).send({
|
|
11359
|
-
success: false,
|
|
11360
|
-
error: "Unauthorized - Missing or invalid token"
|
|
11361
|
-
});
|
|
11362
|
-
});
|
|
11908
|
+
var authRequired = process.env.AUTH_REQUIRED === "true";
|
|
11909
|
+
registerConsoleAuthHook(app, { authRequired });
|
|
11363
11910
|
app.addHook("onRequest", (request, reply, done) => {
|
|
11364
11911
|
if (!request.headers["x-project-id"]) {
|
|
11365
11912
|
request.headers["x-project-id"] = "default";
|
|
@@ -11389,7 +11936,7 @@ app.register(cors, {
|
|
|
11389
11936
|
origin: true,
|
|
11390
11937
|
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
|
|
11391
11938
|
allowedHeaders: "*",
|
|
11392
|
-
exposedHeaders: ["Content-Type"],
|
|
11939
|
+
exposedHeaders: ["Content-Type", "Content-Disposition"],
|
|
11393
11940
|
credentials: true
|
|
11394
11941
|
});
|
|
11395
11942
|
app.register(sensible);
|
|
@@ -11443,14 +11990,14 @@ function getConfiguredSandboxProvider() {
|
|
|
11443
11990
|
}
|
|
11444
11991
|
async function restoreMcpConnections() {
|
|
11445
11992
|
try {
|
|
11446
|
-
const storeLattice =
|
|
11993
|
+
const storeLattice = getStoreLattice26("default", "mcp");
|
|
11447
11994
|
const store = storeLattice.store;
|
|
11448
11995
|
if (!store) {
|
|
11449
11996
|
logger4.info("MCP store not configured, skipping connection restoration");
|
|
11450
11997
|
return;
|
|
11451
11998
|
}
|
|
11452
11999
|
const configs = await store.getAllConfigs("default");
|
|
11453
|
-
const connectedConfigs = configs.filter((
|
|
12000
|
+
const connectedConfigs = configs.filter((c2) => c2.status === "connected");
|
|
11454
12001
|
if (connectedConfigs.length === 0) return;
|
|
11455
12002
|
logger4.info(`Restoring ${connectedConfigs.length} MCP server connections...`);
|
|
11456
12003
|
const { convertToConnection } = await import("./mcp-configs-SHRMQHIL.mjs");
|
|
@@ -11495,9 +12042,9 @@ var start = async (config) => {
|
|
|
11495
12042
|
const { wechatChannelAdapter } = await import("./WechatChannelAdapter-WSDKR4OA.mjs");
|
|
11496
12043
|
adapterRegistry.register(wechatChannelAdapter);
|
|
11497
12044
|
try {
|
|
11498
|
-
const { getStoreLattice:
|
|
11499
|
-
const bindingStore =
|
|
11500
|
-
const installationStore =
|
|
12045
|
+
const { getStoreLattice: getStore12 } = await import("@axiom-lattice/core");
|
|
12046
|
+
const bindingStore = getStore12("default", "channelBinding").store;
|
|
12047
|
+
const installationStore = getStore12("default", "channelInstallation").store;
|
|
11501
12048
|
setBindingRegistry(bindingStore);
|
|
11502
12049
|
const router = new MessageRouter({
|
|
11503
12050
|
middlewares: [
|
|
@@ -11510,14 +12057,6 @@ var start = async (config) => {
|
|
|
11510
12057
|
installationStore
|
|
11511
12058
|
});
|
|
11512
12059
|
channelDeps = { router, installationStore };
|
|
11513
|
-
try {
|
|
11514
|
-
const a2aKeyStore = getStore15("default", "a2aApiKey").store;
|
|
11515
|
-
const a2a = await import("./a2a-QMHEH3ZT.mjs");
|
|
11516
|
-
a2a.setA2AKeyStore(a2aKeyStore);
|
|
11517
|
-
await a2a.refreshStoreKeyMap();
|
|
11518
|
-
logger4.info("A2A key store initialized");
|
|
11519
|
-
} catch {
|
|
11520
|
-
}
|
|
11521
12060
|
} catch (err) {
|
|
11522
12061
|
logger4.warn("Channel infrastructure unavailable", {
|
|
11523
12062
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -11525,7 +12064,7 @@ var start = async (config) => {
|
|
|
11525
12064
|
}
|
|
11526
12065
|
setEvalRunService(evalRunner);
|
|
11527
12066
|
try {
|
|
11528
|
-
const menuStore =
|
|
12067
|
+
const menuStore = getStoreLattice26("default", "menu").store;
|
|
11529
12068
|
setMenuRegistry(menuStore);
|
|
11530
12069
|
logger4.info("Menu registry initialized");
|
|
11531
12070
|
} catch {
|
|
@@ -11535,13 +12074,44 @@ var start = async (config) => {
|
|
|
11535
12074
|
setChannelControllerDeps({ adapterRegistry, router: channelDeps.router });
|
|
11536
12075
|
}
|
|
11537
12076
|
registerLatticeRoutes(app, channelDeps);
|
|
12077
|
+
try {
|
|
12078
|
+
const { A2AAuthService, parseEnvKeys } = await import("./A2AAuthService-DK5X6VIL.mjs");
|
|
12079
|
+
const { registerA2AStandardRoutes } = await import("./a2a-standard-U2XYG45L.mjs");
|
|
12080
|
+
const a2a = await import("./a2a-7N3WDAOP.mjs");
|
|
12081
|
+
const a2aKeyStore = getStoreLattice26("default", "a2aApiKey").store;
|
|
12082
|
+
const assistantStore = getStoreLattice26("default", "assistant").store;
|
|
12083
|
+
const projectStore = getStoreLattice26("default", "project").store;
|
|
12084
|
+
const taskStore = getStoreLattice26("default", "task").store;
|
|
12085
|
+
const authService = new A2AAuthService({
|
|
12086
|
+
keyStore: a2aKeyStore,
|
|
12087
|
+
assistantStore,
|
|
12088
|
+
projectStore,
|
|
12089
|
+
envKeyMap: parseEnvKeys(process.env.A2A_API_KEYS || ""),
|
|
12090
|
+
allowUnauthenticated: process.env.A2A_ALLOW_UNAUTHENTICATED === "true"
|
|
12091
|
+
});
|
|
12092
|
+
await authService.refresh();
|
|
12093
|
+
a2a.setA2AKeyStore(a2aKeyStore);
|
|
12094
|
+
a2a.setA2AAuthService(authService);
|
|
12095
|
+
registerA2AStandardRoutes(app, {
|
|
12096
|
+
authService,
|
|
12097
|
+
getTaskStoreLattice: () => taskStore,
|
|
12098
|
+
getAssistantStore: () => assistantStore,
|
|
12099
|
+
getProjectStore: () => projectStore
|
|
12100
|
+
});
|
|
12101
|
+
a2a.registerA2ARoutes(app);
|
|
12102
|
+
logger4.info("A2A standard routes registered");
|
|
12103
|
+
} catch (err) {
|
|
12104
|
+
logger4.warn("A2A standard routes unavailable", {
|
|
12105
|
+
error: err instanceof Error ? err.message : String(err)
|
|
12106
|
+
});
|
|
12107
|
+
}
|
|
11538
12108
|
if (!sandboxLatticeManager2.hasLattice("default")) {
|
|
11539
12109
|
sandboxLatticeManager2.registerLattice("default", getConfiguredSandboxProvider());
|
|
11540
12110
|
logger4.info("Registered sandbox manager from env configuration");
|
|
11541
12111
|
}
|
|
11542
12112
|
try {
|
|
11543
12113
|
const { ResourceController } = await import("./resources-VA7LSDKN.mjs");
|
|
11544
|
-
const sharedResourceStore =
|
|
12114
|
+
const sharedResourceStore = getStoreLattice26("default", "sharedResource").store;
|
|
11545
12115
|
const cache = new TokenCache();
|
|
11546
12116
|
const resourceController = new ResourceController({
|
|
11547
12117
|
store: sharedResourceStore,
|