@axiom-lattice/gateway 3.0.7 → 3.0.9

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/index.mjs CHANGED
@@ -692,6 +692,125 @@ var getAgentGraph = async (request, reply) => {
692
692
  });
693
693
  }
694
694
  };
695
+ var STATS_CACHE_TTL_MS = 5 * 60 * 1e3;
696
+ var statsCache = /* @__PURE__ */ new Map();
697
+ async function getAssistantStats(request, reply) {
698
+ const tenantId = getTenantId(request);
699
+ const cached = statsCache.get(tenantId);
700
+ if (cached && cached.expiresAt > Date.now()) {
701
+ return {
702
+ success: true,
703
+ message: "Ok (cached)",
704
+ data: cached.data,
705
+ cache: {
706
+ expiresAt: new Date(cached.expiresAt).toISOString(),
707
+ remainingMs: cached.expiresAt - Date.now(),
708
+ cached: true
709
+ }
710
+ };
711
+ }
712
+ try {
713
+ const agentConfigs = await agentLatticeManager.getAllAgentConfigsByTenant(tenantId);
714
+ const codeConfiguredAssistants = agentConfigs.map(convertAgentConfigToAssistant);
715
+ const storeLattice = getStoreLattice("default", "assistant");
716
+ const assistantStore = storeLattice.store;
717
+ const storedAssistants = await assistantStore.getAllAssistants(tenantId);
718
+ const assistantMap = /* @__PURE__ */ new Map();
719
+ codeConfiguredAssistants.forEach((a) => assistantMap.set(a.id, a));
720
+ storedAssistants.forEach((a) => assistantMap.set(a.id, a));
721
+ const userId = getUserId(request);
722
+ const assistants = Array.from(assistantMap.values()).filter((a) => {
723
+ if (!a.ownerUserId) return true;
724
+ return a.ownerUserId === userId;
725
+ });
726
+ const threadStore = getStoreLattice("default", "thread").store;
727
+ const evalStore = getStoreLattice("default", "eval").store;
728
+ const now = Date.now();
729
+ const ms7d = 7 * 864e5;
730
+ const ms30d = 30 * 864e5;
731
+ const records = await Promise.all(
732
+ assistants.map(async (assistant) => {
733
+ let threadCount = 0;
734
+ let last7d = 0;
735
+ let last30d = 0;
736
+ let lastActive = null;
737
+ const daily7d = new Array(7).fill(0);
738
+ const daily30d = new Array(30).fill(0);
739
+ try {
740
+ const threads = await threadStore.getThreadsByAssistantId(tenantId, assistant.id);
741
+ threadCount = threads.length;
742
+ for (const t of threads) {
743
+ const created = new Date(t.createdAt).getTime();
744
+ if (created >= now - ms7d) last7d++;
745
+ if (created >= now - ms30d) last30d++;
746
+ const idx7 = Math.floor((now - created) / 864e5);
747
+ if (idx7 >= 0 && idx7 < 7) daily7d[6 - idx7]++;
748
+ const idx30 = Math.floor((now - created) / 864e5);
749
+ if (idx30 >= 0 && idx30 < 30) daily30d[29 - idx30]++;
750
+ const updated = new Date(t.updatedAt).getTime();
751
+ if (lastActive === null || updated > lastActive.getTime()) {
752
+ lastActive = new Date(t.updatedAt);
753
+ }
754
+ }
755
+ } catch {
756
+ }
757
+ let evalScore = null;
758
+ let evalPassRate = null;
759
+ let evalRuns = 0;
760
+ let evalTrend = [];
761
+ try {
762
+ const projects = await evalStore.getProjectsByTenant(tenantId);
763
+ const project = projects.find((p) => p.name === `eval-${assistant.id}`);
764
+ if (project) {
765
+ const runs = await evalStore.getRunsByTenant(tenantId, { projectId: project.id });
766
+ evalRuns = runs.length;
767
+ const sorted = [...runs].sort(
768
+ (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
769
+ );
770
+ evalTrend = sorted.map((r) => typeof r.avgScore === "number" ? r.avgScore : null).filter((v) => v !== null);
771
+ const latest = sorted[sorted.length - 1];
772
+ if (latest) {
773
+ evalScore = typeof latest.avgScore === "number" ? latest.avgScore : null;
774
+ if (latest.totalCases > 0) {
775
+ evalPassRate = Math.round(latest.passedCases / latest.totalCases * 100);
776
+ }
777
+ }
778
+ }
779
+ } catch {
780
+ }
781
+ return {
782
+ id: assistant.id,
783
+ threadCount,
784
+ last7d,
785
+ last30d,
786
+ lastActive: lastActive ? lastActive.toISOString() : null,
787
+ daily7d,
788
+ daily30d,
789
+ evalScore,
790
+ evalPassRate,
791
+ evalRuns,
792
+ evalTrend: evalTrend.slice(-8)
793
+ };
794
+ })
795
+ );
796
+ const payload = { records };
797
+ const expiresAt = Date.now() + STATS_CACHE_TTL_MS;
798
+ statsCache.set(tenantId, { data: payload, expiresAt });
799
+ return {
800
+ success: true,
801
+ message: "Ok",
802
+ data: payload,
803
+ cache: {
804
+ expiresAt: new Date(expiresAt).toISOString(),
805
+ remainingMs: STATS_CACHE_TTL_MS,
806
+ cached: false
807
+ }
808
+ };
809
+ } catch (err) {
810
+ const message = err instanceof Error ? err.message : "Failed to get assistant stats";
811
+ return reply.status(500).send({ success: false, message });
812
+ }
813
+ }
695
814
 
696
815
  // src/controllers/run.ts
697
816
  import { v4 } from "uuid";
@@ -3376,6 +3495,7 @@ async function listTasks(request, reply) {
3376
3495
  priority: query.priority,
3377
3496
  ...query.ownerId && { ownerId: query.ownerId },
3378
3497
  ...query.ownerType && { ownerType: query.ownerType },
3498
+ ...query.parentId && { parentId: query.parentId },
3379
3499
  metadata: query.metadata ? JSON.parse(query.metadata) : void 0,
3380
3500
  projectId: query.projectId,
3381
3501
  limit: query.limit ? parseInt(query.limit) : void 0,
@@ -6214,7 +6334,7 @@ var EvalRunner = class {
6214
6334
  getEventEmitter() {
6215
6335
  return this.eventEmitter;
6216
6336
  }
6217
- async startRun(tenantId, projectId, suiteIds, caseIds, runConfig) {
6337
+ async startRun(tenantId, projectId, suiteIds, caseIds, runConfig, taskId) {
6218
6338
  const store = this.getEvalStore();
6219
6339
  const project = await store.getProjectById(tenantId, projectId);
6220
6340
  if (!project) throw new Error("Project not found");
@@ -6285,12 +6405,15 @@ var EvalRunner = class {
6285
6405
  }
6286
6406
  resolvedJudgeModelKey = judgeModelKey;
6287
6407
  } else {
6288
- const firstModel = modelLatticeManager2.getAllLattices()[0];
6289
- if (!firstModel) {
6408
+ const models = modelLatticeManager2.getAllLattices();
6409
+ const defaultModel = models.find((m) => m.key === "default");
6410
+ resolvedJudgeModelKey = defaultModel?.key ?? models[0]?.key ?? "";
6411
+ if (!resolvedJudgeModelKey) {
6290
6412
  throw new Error("No model registered \u2014 cannot run eval without a judge model");
6291
6413
  }
6292
- resolvedJudgeModelKey = firstModel.key;
6293
- console.warn(`[eval-runner] Project "${project.name}" has no judge modelKey \u2014 falling back to first registered model "${firstModel.key}"`);
6414
+ if (!defaultModel) {
6415
+ console.warn(`[eval-runner] Project "${project.name}" has no judge modelKey and no "default" model \u2014 falling back to first registered model "${resolvedJudgeModelKey}"`);
6416
+ }
6294
6417
  }
6295
6418
  const runId = uuidv43();
6296
6419
  const concurrency = Math.max(1, Math.floor(project.concurrency) || 3);
@@ -6302,7 +6425,8 @@ var EvalRunner = class {
6302
6425
  concurrency,
6303
6426
  holdout: isHoldout,
6304
6427
  envWorkspaceId: workspaceId || void 0,
6305
- envProjectId: projectIdFromConfig || void 0
6428
+ envProjectId: projectIdFromConfig || void 0,
6429
+ taskId
6306
6430
  });
6307
6431
  const projectConfig = {
6308
6432
  projectName: project.name,
@@ -6409,7 +6533,7 @@ var EvalRunner = class {
6409
6533
  this.runs.delete(runId);
6410
6534
  }
6411
6535
  })();
6412
- this.runs.set(runId, { runId, projectId, tenantId, abortController, promise: runPromise });
6536
+ this.runs.set(runId, { runId, projectId, tenantId, abortController, promise: runPromise, taskId });
6413
6537
  runPromise.catch(() => {
6414
6538
  });
6415
6539
  return runId;
@@ -6480,7 +6604,9 @@ async function createProject(request, reply) {
6480
6604
  },
6481
6605
  targetServerConfig: {
6482
6606
  base_url: serverCfg.base_url || "",
6483
- api_key: serverCfg.api_key || ""
6607
+ api_key: serverCfg.api_key || "",
6608
+ // Project↔agent association pointer (see manage_eval create_project).
6609
+ ...serverCfg.targetAgentId ? { targetAgentId: serverCfg.targetAgentId } : {}
6484
6610
  },
6485
6611
  concurrency: data.concurrency ?? 1,
6486
6612
  reportConfig: data.reportConfig
@@ -6789,7 +6915,7 @@ function registerEvalRoutes(app2) {
6789
6915
  workspaceId: body?.runConfig?.workspaceId ?? bodyWs,
6790
6916
  projectId: body?.runConfig?.projectId ?? bodyPj
6791
6917
  };
6792
- const runId = await evalRunner.startRun(tenantId, pid, body?.suiteIds, body?.caseIds, runConfig);
6918
+ const runId = await evalRunner.startRun(tenantId, pid, body?.suiteIds, body?.caseIds, runConfig, body?.taskId);
6793
6919
  reply.status(202).send({ success: true, message: "Run started", data: { run_id: runId } });
6794
6920
  } catch (err) {
6795
6921
  const msg = err.message;
@@ -8792,6 +8918,7 @@ var registerLatticeRoutes = (app2, channelDeps) => {
8792
8918
  clearMemory
8793
8919
  );
8794
8920
  app2.get("/api/assistants", getAssistantList);
8921
+ app2.get("/api/assistants/stats", getAssistantStats);
8795
8922
  app2.get("/api/assistants/:id", getAssistant);
8796
8923
  app2.post("/api/assistants", createAssistant);
8797
8924
  app2.put("/api/assistants/:id", updateAssistant);