@axiom-lattice/gateway 2.1.111 → 2.1.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +12 -12
- package/CHANGELOG.md +11 -0
- package/dist/index.js +181 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +187 -65
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -6
- package/src/controllers/__tests__/workflow-tracking.test.ts +113 -0
- package/src/controllers/connections.ts +7 -0
- package/src/controllers/eval.ts +44 -4
- package/src/controllers/workflow-tracking.ts +105 -11
- package/src/index.ts +14 -8
- package/src/routes/index.ts +8 -1
- package/src/services/eval-runner.ts +63 -55
package/dist/index.mjs
CHANGED
|
@@ -2227,7 +2227,7 @@ async function executeSqlQuery(client, body, reply) {
|
|
|
2227
2227
|
}
|
|
2228
2228
|
|
|
2229
2229
|
// src/controllers/workflow-tracking.ts
|
|
2230
|
-
import { getStoreLattice as getStoreLattice4, agentInstanceManager as agentInstanceManager4, ThreadStatus as ThreadStatus2 } from "@axiom-lattice/core";
|
|
2230
|
+
import { getStoreLattice as getStoreLattice4, agentInstanceManager as agentInstanceManager4, ThreadStatus as ThreadStatus2, abortWorkflowRun as signalAbort } from "@axiom-lattice/core";
|
|
2231
2231
|
import { MessageChunkTypes as MessageChunkTypes2 } from "@axiom-lattice/protocols";
|
|
2232
2232
|
function getTenantId7(request) {
|
|
2233
2233
|
const userTenantId = request.user?.tenantId;
|
|
@@ -2366,6 +2366,8 @@ async function getAllWorkflowRuns(request, reply) {
|
|
|
2366
2366
|
});
|
|
2367
2367
|
}
|
|
2368
2368
|
}
|
|
2369
|
+
var INBOX_DEFAULT_PAGE_SIZE = 20;
|
|
2370
|
+
var INBOX_MAX_PAGE_SIZE = 100;
|
|
2369
2371
|
async function getInboxItems(request, reply) {
|
|
2370
2372
|
const tenantId = getTenantId7(request);
|
|
2371
2373
|
try {
|
|
@@ -2383,10 +2385,30 @@ async function getInboxItems(request, reply) {
|
|
|
2383
2385
|
}
|
|
2384
2386
|
} catch {
|
|
2385
2387
|
}
|
|
2386
|
-
const
|
|
2387
|
-
const
|
|
2388
|
+
const { page: pageParam, pageSize: pageSizeParam } = request.query;
|
|
2389
|
+
const paged = pageParam !== void 0 || pageSizeParam !== void 0;
|
|
2390
|
+
const page = Math.max(1, parseInt(pageParam ?? "", 10) || 1);
|
|
2391
|
+
const pageSize = Math.min(INBOX_MAX_PAGE_SIZE, Math.max(1, parseInt(pageSizeParam ?? "", 10) || INBOX_DEFAULT_PAGE_SIZE));
|
|
2392
|
+
let pendingRuns;
|
|
2393
|
+
let total;
|
|
2394
|
+
if (paged) {
|
|
2395
|
+
const result = await store.queryWorkflowRuns(tenantId, {
|
|
2396
|
+
status: "interrupted",
|
|
2397
|
+
limit: pageSize,
|
|
2398
|
+
offset: (page - 1) * pageSize
|
|
2399
|
+
});
|
|
2400
|
+
pendingRuns = result.records;
|
|
2401
|
+
total = result.total;
|
|
2402
|
+
} else {
|
|
2403
|
+
const result = await store.queryWorkflowRuns(tenantId, { status: "interrupted" });
|
|
2404
|
+
pendingRuns = result.records;
|
|
2405
|
+
}
|
|
2388
2406
|
if (pendingRuns.length === 0) {
|
|
2389
|
-
return {
|
|
2407
|
+
return {
|
|
2408
|
+
success: true,
|
|
2409
|
+
message: "No pending workflows",
|
|
2410
|
+
data: paged ? { records: [], total, page, pageSize } : { records: [] }
|
|
2411
|
+
};
|
|
2390
2412
|
}
|
|
2391
2413
|
const checkPromises = pendingRuns.map(async (r) => {
|
|
2392
2414
|
try {
|
|
@@ -2443,13 +2465,10 @@ async function getInboxItems(request, reply) {
|
|
|
2443
2465
|
});
|
|
2444
2466
|
const results = await Promise.all(checkPromises);
|
|
2445
2467
|
const inboxItems = results.flat();
|
|
2446
|
-
inboxItems.sort(
|
|
2447
|
-
(a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime()
|
|
2448
|
-
);
|
|
2449
2468
|
return {
|
|
2450
2469
|
success: true,
|
|
2451
2470
|
message: "Successfully retrieved inbox items",
|
|
2452
|
-
data: { records: inboxItems }
|
|
2471
|
+
data: paged ? { records: inboxItems, total, page, pageSize } : { records: inboxItems }
|
|
2453
2472
|
};
|
|
2454
2473
|
} catch (error) {
|
|
2455
2474
|
request.log.error(error, "Failed to get inbox items");
|
|
@@ -2682,6 +2701,54 @@ async function replyInboxTask(request, reply) {
|
|
|
2682
2701
|
});
|
|
2683
2702
|
}
|
|
2684
2703
|
}
|
|
2704
|
+
async function abortWorkflowRun(request, reply) {
|
|
2705
|
+
try {
|
|
2706
|
+
const { runId } = request.params;
|
|
2707
|
+
const tenantId = getTenantId7(request);
|
|
2708
|
+
const store = getTrackingStore();
|
|
2709
|
+
if (!store) {
|
|
2710
|
+
return reply.status(404).send({
|
|
2711
|
+
success: false,
|
|
2712
|
+
message: "No workflow tracking store configured"
|
|
2713
|
+
});
|
|
2714
|
+
}
|
|
2715
|
+
const run = await store.getWorkflowRun(runId);
|
|
2716
|
+
if (!run) {
|
|
2717
|
+
return reply.status(404).send({
|
|
2718
|
+
success: false,
|
|
2719
|
+
message: "Workflow run not found"
|
|
2720
|
+
});
|
|
2721
|
+
}
|
|
2722
|
+
await store.updateWorkflowRun(runId, {
|
|
2723
|
+
status: "cancelled",
|
|
2724
|
+
errorMessage: "Aborted by user",
|
|
2725
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
2726
|
+
}).catch(() => {
|
|
2727
|
+
});
|
|
2728
|
+
const workspace_id = request.headers["x-workspace-id"];
|
|
2729
|
+
const project_id = request.headers["x-project-id"];
|
|
2730
|
+
const agent = agentInstanceManager4.getAgent({
|
|
2731
|
+
assistant_id: run.assistantId,
|
|
2732
|
+
thread_id: run.threadId,
|
|
2733
|
+
tenant_id: tenantId,
|
|
2734
|
+
workspace_id,
|
|
2735
|
+
project_id
|
|
2736
|
+
});
|
|
2737
|
+
await agent.abort();
|
|
2738
|
+
signalAbort(runId);
|
|
2739
|
+
return reply.status(200).send({
|
|
2740
|
+
success: true,
|
|
2741
|
+
message: "Workflow aborted",
|
|
2742
|
+
data: { runId, assistantId: run.assistantId, threadId: run.threadId }
|
|
2743
|
+
});
|
|
2744
|
+
} catch (error) {
|
|
2745
|
+
request.log.error(error, "Failed to abort workflow run");
|
|
2746
|
+
return reply.status(500).send({
|
|
2747
|
+
success: false,
|
|
2748
|
+
message: `Abort failed: ${error.message}`
|
|
2749
|
+
});
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2685
2752
|
|
|
2686
2753
|
// src/controllers/personal-assistant.ts
|
|
2687
2754
|
import { getStoreLattice as getStoreLattice5, PersonalAssistantConfig } from "@axiom-lattice/core";
|
|
@@ -5026,6 +5093,10 @@ var testOrDiscoverBody = z.object({
|
|
|
5026
5093
|
config: z.record(z.unknown()).optional()
|
|
5027
5094
|
});
|
|
5028
5095
|
function getTenant(request) {
|
|
5096
|
+
const userTenantId = request.user?.tenantId;
|
|
5097
|
+
if (userTenantId) {
|
|
5098
|
+
return userTenantId;
|
|
5099
|
+
}
|
|
5029
5100
|
return request.headers["x-tenant-id"] || "default";
|
|
5030
5101
|
}
|
|
5031
5102
|
function maskSecrets(config) {
|
|
@@ -5171,8 +5242,11 @@ import { v4 as uuidv44 } from "uuid";
|
|
|
5171
5242
|
|
|
5172
5243
|
// src/services/eval-runner.ts
|
|
5173
5244
|
import { EventEmitter } from "events";
|
|
5174
|
-
import {
|
|
5175
|
-
|
|
5245
|
+
import {
|
|
5246
|
+
getStoreLattice as getStoreLattice10,
|
|
5247
|
+
modelLatticeManager as modelLatticeManager2,
|
|
5248
|
+
LatticeEvalProject
|
|
5249
|
+
} from "@axiom-lattice/core";
|
|
5176
5250
|
import { v4 as uuidv43 } from "uuid";
|
|
5177
5251
|
function mapLogs(logs) {
|
|
5178
5252
|
return logs.map((l) => ({
|
|
@@ -5194,6 +5268,11 @@ var EvalRunner = class {
|
|
|
5194
5268
|
const store = this.getEvalStore();
|
|
5195
5269
|
const project = await store.getProjectById(tenantId, projectId);
|
|
5196
5270
|
if (!project) throw new Error("Project not found");
|
|
5271
|
+
for (const ctx of this.runs.values()) {
|
|
5272
|
+
if (ctx.projectId === projectId) {
|
|
5273
|
+
throw new Error("A run is already in progress for this project");
|
|
5274
|
+
}
|
|
5275
|
+
}
|
|
5197
5276
|
const existingRuns = await store.getRunsByTenant(tenantId, { projectId, status: "running" });
|
|
5198
5277
|
if (existingRuns.length > 0) {
|
|
5199
5278
|
throw new Error("A run is already in progress for this project");
|
|
@@ -5210,7 +5289,7 @@ var EvalRunner = class {
|
|
|
5210
5289
|
caseId: c.id,
|
|
5211
5290
|
input: { message: c.inputMessage, files: c.inputFiles },
|
|
5212
5291
|
steps: c.steps,
|
|
5213
|
-
output: { type:
|
|
5292
|
+
output: { type: "message_content" },
|
|
5214
5293
|
eval: {
|
|
5215
5294
|
content_assertion: c.contentAssertion,
|
|
5216
5295
|
eval_rubrics: c.rubrics?.map((r) => ({
|
|
@@ -5222,35 +5301,32 @@ var EvalRunner = class {
|
|
|
5222
5301
|
}))
|
|
5223
5302
|
});
|
|
5224
5303
|
}
|
|
5225
|
-
const
|
|
5226
|
-
const
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
const hasCredentials = hasApiKey;
|
|
5232
|
-
let judgeModelConfig = {};
|
|
5233
|
-
if (hasModelKey) {
|
|
5234
|
-
judgeModelConfig = { modelKey: judgeCfg.modelKey };
|
|
5235
|
-
} else if (!hasCredentials) {
|
|
5236
|
-
const firstModel = modelLatticeManager2.getAllLattices()[0];
|
|
5237
|
-
if (firstModel) {
|
|
5238
|
-
judgeModelConfig = { modelKey: firstModel.key };
|
|
5239
|
-
} else {
|
|
5240
|
-
judgeModelConfig = { model: judgeCfg };
|
|
5304
|
+
const judgeCfg = project.judgeModelConfig ?? {};
|
|
5305
|
+
const judgeModelKey = judgeCfg.modelKey || "";
|
|
5306
|
+
let resolvedJudgeModelKey;
|
|
5307
|
+
if (judgeModelKey) {
|
|
5308
|
+
if (!modelLatticeManager2.hasLattice(judgeModelKey)) {
|
|
5309
|
+
throw new Error(`Judge model "${judgeModelKey}" is not registered`);
|
|
5241
5310
|
}
|
|
5311
|
+
resolvedJudgeModelKey = judgeModelKey;
|
|
5242
5312
|
} else {
|
|
5243
|
-
|
|
5313
|
+
const firstModel = modelLatticeManager2.getAllLattices()[0];
|
|
5314
|
+
if (!firstModel) {
|
|
5315
|
+
throw new Error("No model registered \u2014 cannot run eval without a judge model");
|
|
5316
|
+
}
|
|
5317
|
+
resolvedJudgeModelKey = firstModel.key;
|
|
5318
|
+
console.warn(`[eval-runner] Project "${project.name}" has no judge modelKey \u2014 falling back to first registered model "${firstModel.key}"`);
|
|
5244
5319
|
}
|
|
5320
|
+
const runId = uuidv43();
|
|
5321
|
+
const concurrency = Math.max(1, Math.floor(project.concurrency) || 3);
|
|
5322
|
+
await store.createRun(tenantId, projectId, runId, { totalCases, concurrency });
|
|
5245
5323
|
const projectConfig = {
|
|
5246
5324
|
projectName: project.name,
|
|
5247
5325
|
version: project.version,
|
|
5248
5326
|
description: project.description,
|
|
5249
5327
|
suites: evalSuites,
|
|
5250
|
-
judge_agent_config:
|
|
5328
|
+
judge_agent_config: { modelKey: resolvedJudgeModelKey },
|
|
5251
5329
|
lattice_server_config: {
|
|
5252
|
-
base_url: project.targetServerConfig.base_url || "",
|
|
5253
|
-
api_key: project.targetServerConfig.api_key || "",
|
|
5254
5330
|
tenant_id: tenantId
|
|
5255
5331
|
},
|
|
5256
5332
|
concurrency
|
|
@@ -5295,33 +5371,37 @@ var EvalRunner = class {
|
|
|
5295
5371
|
const runPromise = (async () => {
|
|
5296
5372
|
try {
|
|
5297
5373
|
const evalProject = new LatticeEvalProject(projectConfig, onCaseComplete);
|
|
5298
|
-
const { report } = await evalProject.runAllSuitesBatch(concurrency);
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5374
|
+
const { report } = await evalProject.runAllSuitesBatch(concurrency, abortController.signal);
|
|
5375
|
+
if (!abortController.signal.aborted) {
|
|
5376
|
+
const completedCount = stats.passed + stats.failed;
|
|
5377
|
+
await store.updateRunStatus(tenantId, runId, {
|
|
5378
|
+
status: "completed",
|
|
5379
|
+
completedAt: /* @__PURE__ */ new Date(),
|
|
5380
|
+
passedCases: stats.passed,
|
|
5381
|
+
failedCases: stats.failed,
|
|
5382
|
+
avgScore: completedCount > 0 ? stats.totalScore / completedCount : 0
|
|
5383
|
+
});
|
|
5384
|
+
this.eventEmitter.emit(`run:${runId}`, {
|
|
5385
|
+
type: "completed",
|
|
5386
|
+
runId,
|
|
5387
|
+
data: { passed: stats.passed, failed: stats.failed, avgScore: completedCount > 0 ? stats.totalScore / completedCount : 0 }
|
|
5388
|
+
});
|
|
5389
|
+
}
|
|
5312
5390
|
return { report };
|
|
5313
5391
|
} catch (err) {
|
|
5314
5392
|
const errorMsg = err.message;
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5393
|
+
if (!abortController.signal.aborted) {
|
|
5394
|
+
await store.updateRunStatus(tenantId, runId, {
|
|
5395
|
+
status: "failed",
|
|
5396
|
+
error: errorMsg,
|
|
5397
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
5398
|
+
});
|
|
5399
|
+
this.eventEmitter.emit(`run:${runId}`, {
|
|
5400
|
+
type: "error",
|
|
5401
|
+
runId,
|
|
5402
|
+
data: { message: errorMsg }
|
|
5403
|
+
});
|
|
5404
|
+
}
|
|
5325
5405
|
throw err;
|
|
5326
5406
|
} finally {
|
|
5327
5407
|
this.runs.delete(runId);
|
|
@@ -5366,12 +5446,27 @@ async function createProject(request, reply) {
|
|
|
5366
5446
|
const store = getEvalStore();
|
|
5367
5447
|
const id = uuidv44();
|
|
5368
5448
|
const data = request.body;
|
|
5449
|
+
const serverCfg = data.targetServerConfig || {};
|
|
5450
|
+
const judgeCfg = data.judgeModelConfig || {};
|
|
5451
|
+
const modelKey = judgeCfg.modelKey || "";
|
|
5452
|
+
if (modelKey) {
|
|
5453
|
+
const { modelLatticeManager: modelLatticeManager3 } = await import("@axiom-lattice/core");
|
|
5454
|
+
if (!modelLatticeManager3.hasLattice(modelKey)) {
|
|
5455
|
+
return reply.status(400).send({ success: false, message: `Judge model "${modelKey}" is not registered` });
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5369
5458
|
const project = await store.createProject(tenantId, id, {
|
|
5370
5459
|
name: data.name,
|
|
5371
5460
|
description: data.description,
|
|
5372
5461
|
version: data.version,
|
|
5373
|
-
judgeModelConfig:
|
|
5374
|
-
|
|
5462
|
+
judgeModelConfig: {
|
|
5463
|
+
modelKey,
|
|
5464
|
+
displayName: judgeCfg.displayName || ""
|
|
5465
|
+
},
|
|
5466
|
+
targetServerConfig: {
|
|
5467
|
+
base_url: serverCfg.base_url || "",
|
|
5468
|
+
api_key: serverCfg.api_key || ""
|
|
5469
|
+
},
|
|
5375
5470
|
concurrency: data.concurrency ?? 1,
|
|
5376
5471
|
reportConfig: data.reportConfig
|
|
5377
5472
|
});
|
|
@@ -5395,7 +5490,7 @@ async function listProjects(request, reply) {
|
|
|
5395
5490
|
const { modelLatticeManager: modelLatticeManager3 } = await import("@axiom-lattice/core");
|
|
5396
5491
|
const models = modelLatticeManager3.getAllLattices();
|
|
5397
5492
|
const first = models[0];
|
|
5398
|
-
const judgeModel = first ? { modelKey: first.key } : {
|
|
5493
|
+
const judgeModel = first ? { modelKey: first.key } : {};
|
|
5399
5494
|
const host = request.hostname || "localhost";
|
|
5400
5495
|
const baseUrl = `http://${host}:${process.env.PORT || 4001}`;
|
|
5401
5496
|
await store.createProject(tenantId, uuidv44(), {
|
|
@@ -5448,7 +5543,30 @@ async function updateProject(request, reply) {
|
|
|
5448
5543
|
if (!existing) {
|
|
5449
5544
|
return reply.status(404).send({ success: false, message: "Project not found" });
|
|
5450
5545
|
}
|
|
5451
|
-
const
|
|
5546
|
+
const body = request.body;
|
|
5547
|
+
const updateData = { ...body };
|
|
5548
|
+
const serverCfg = body.targetServerConfig || {};
|
|
5549
|
+
if (body.targetServerConfig !== void 0) {
|
|
5550
|
+
updateData.targetServerConfig = {
|
|
5551
|
+
base_url: serverCfg.base_url || "",
|
|
5552
|
+
api_key: serverCfg.api_key || ""
|
|
5553
|
+
};
|
|
5554
|
+
}
|
|
5555
|
+
if (body.judgeModelConfig !== void 0) {
|
|
5556
|
+
const judgeCfg = body.judgeModelConfig || {};
|
|
5557
|
+
const modelKey = judgeCfg.modelKey || "";
|
|
5558
|
+
if (modelKey) {
|
|
5559
|
+
const { modelLatticeManager: modelLatticeManager3 } = await import("@axiom-lattice/core");
|
|
5560
|
+
if (!modelLatticeManager3.hasLattice(modelKey)) {
|
|
5561
|
+
return reply.status(400).send({ success: false, message: `Judge model "${modelKey}" is not registered` });
|
|
5562
|
+
}
|
|
5563
|
+
}
|
|
5564
|
+
updateData.judgeModelConfig = {
|
|
5565
|
+
modelKey,
|
|
5566
|
+
displayName: judgeCfg.displayName || ""
|
|
5567
|
+
};
|
|
5568
|
+
}
|
|
5569
|
+
const updated = await store.updateProject(tenantId, pid, updateData);
|
|
5452
5570
|
return {
|
|
5453
5571
|
success: true,
|
|
5454
5572
|
message: "Successfully updated project",
|
|
@@ -7499,6 +7617,7 @@ var registerLatticeRoutes = (app2, channelDeps) => {
|
|
|
7499
7617
|
app2.delete("/api/workflows/runs/:runId", deleteWorkflowRun);
|
|
7500
7618
|
app2.get("/api/workflows/runs/:runId/steps", getRunSteps);
|
|
7501
7619
|
app2.get("/api/workflows/runs/:runId/tasks", getRunTasks);
|
|
7620
|
+
app2.post("/api/workflows/runs/:runId/abort", abortWorkflowRun);
|
|
7502
7621
|
app2.post("/api/workflows/inbox/reply", replyInboxTask);
|
|
7503
7622
|
app2.delete(
|
|
7504
7623
|
"/api/assistants/:assistant_id/threads/:thread_id/pending-messages/:message_id",
|
|
@@ -8018,7 +8137,7 @@ function createAuditLoggerMiddleware() {
|
|
|
8018
8137
|
}
|
|
8019
8138
|
|
|
8020
8139
|
// src/index.ts
|
|
8021
|
-
import { setBindingRegistry, setMenuRegistry } from "@axiom-lattice/core";
|
|
8140
|
+
import { setBindingRegistry, setMenuRegistry, setEvalRunService } from "@axiom-lattice/core";
|
|
8022
8141
|
|
|
8023
8142
|
// src/swagger.ts
|
|
8024
8143
|
import swagger from "@fastify/swagger";
|
|
@@ -8573,6 +8692,7 @@ var start = async (config) => {
|
|
|
8573
8692
|
error: err instanceof Error ? err.message : String(err)
|
|
8574
8693
|
});
|
|
8575
8694
|
}
|
|
8695
|
+
setEvalRunService(evalRunner);
|
|
8576
8696
|
try {
|
|
8577
8697
|
const menuStore = getStoreLattice16("default", "menu").store;
|
|
8578
8698
|
setMenuRegistry(menuStore);
|
|
@@ -8633,11 +8753,13 @@ var start = async (config) => {
|
|
|
8633
8753
|
agentTaskConsumer.startPollingQueue();
|
|
8634
8754
|
}
|
|
8635
8755
|
}
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8756
|
+
if (process.env.AXIOM_RESTORE_PENDING_ON_STARTUP === "true") {
|
|
8757
|
+
agentInstanceManager8.restore().then((stats) => {
|
|
8758
|
+
logger4.info(`Agent recovery complete: ${stats.restored} threads restored, ${stats.errors} errors`);
|
|
8759
|
+
}).catch((error) => {
|
|
8760
|
+
logger4.error("Agent recovery failed", { error });
|
|
8761
|
+
});
|
|
8762
|
+
}
|
|
8641
8763
|
restoreMcpConnections().catch((error) => {
|
|
8642
8764
|
logger4.error("MCP connection restoration failed", { error });
|
|
8643
8765
|
});
|