@axiom-lattice/gateway 2.1.73 → 2.1.74

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.js CHANGED
@@ -1772,6 +1772,7 @@ async function getDefinitionsFromAssistants(tenantId) {
1772
1772
  results.push({
1773
1773
  assistantId: a.id,
1774
1774
  assistantName: a.name,
1775
+ description: a.description,
1775
1776
  topologyEdges: mw.config.edges,
1776
1777
  totalEdges: mw.config.edges.length
1777
1778
  });
@@ -4606,12 +4607,590 @@ function registerMcpServerConfigRoutes(app2) {
4606
4607
  app2.post("/api/mcp-servers/test-tools", testMcpServerTools);
4607
4608
  }
4608
4609
 
4609
- // src/controllers/users.ts
4610
+ // src/controllers/eval.ts
4611
+ var import_core24 = require("@axiom-lattice/core");
4612
+ var import_uuid4 = require("uuid");
4613
+
4614
+ // src/services/eval-runner.ts
4615
+ var import_events = require("events");
4610
4616
  var import_core23 = require("@axiom-lattice/core");
4617
+ var import_agent_eval = require("@axiom-lattice/agent-eval");
4611
4618
  var import_uuid3 = require("uuid");
4619
+ function mapLogs(logs) {
4620
+ return logs.map((l) => ({
4621
+ timestamp: l.ts,
4622
+ level: l.level,
4623
+ message: l.message,
4624
+ data: l.data
4625
+ }));
4626
+ }
4627
+ var EvalRunner = class {
4628
+ constructor() {
4629
+ this.runs = /* @__PURE__ */ new Map();
4630
+ this.eventEmitter = new import_events.EventEmitter();
4631
+ }
4632
+ getEventEmitter() {
4633
+ return this.eventEmitter;
4634
+ }
4635
+ async startRun(tenantId, projectId) {
4636
+ const store = this.getEvalStore();
4637
+ const project = await store.getProjectById(tenantId, projectId);
4638
+ if (!project) throw new Error("Project not found");
4639
+ const existingRuns = await store.getRunsByTenant(tenantId, { projectId, status: "running" });
4640
+ if (existingRuns.length > 0) {
4641
+ throw new Error("A run is already in progress for this project");
4642
+ }
4643
+ const suites = await store.getSuitesByProject(tenantId, projectId);
4644
+ const evalSuites = [];
4645
+ let totalCases = 0;
4646
+ for (const suite of suites) {
4647
+ const cases = await store.getCasesBySuite(tenantId, suite.id);
4648
+ totalCases += cases.length;
4649
+ evalSuites.push({
4650
+ suiteName: suite.name,
4651
+ cases: cases.map((c) => ({
4652
+ caseId: c.id,
4653
+ input: { message: c.inputMessage, files: c.inputFiles },
4654
+ steps: c.steps,
4655
+ output: { type: c.outputType },
4656
+ eval: {
4657
+ content_assertion: c.contentAssertion,
4658
+ eval_rubrics: c.rubrics?.map((r) => ({
4659
+ dimension: r.name,
4660
+ weight: r.weight,
4661
+ description: r.description
4662
+ }))
4663
+ }
4664
+ }))
4665
+ });
4666
+ }
4667
+ const runId = (0, import_uuid3.v4)();
4668
+ const concurrency = project.concurrency || 3;
4669
+ await store.createRun(tenantId, projectId, runId, { totalCases, concurrency });
4670
+ const judgeCfg = project.judgeModelConfig;
4671
+ const hasModelKey = Boolean(judgeCfg.modelKey);
4672
+ const hasApiKey = Boolean(judgeCfg.apiKeyEnvName || judgeCfg.apiKey);
4673
+ const hasCredentials = hasApiKey;
4674
+ let judgeModelConfig = {};
4675
+ if (hasModelKey) {
4676
+ judgeModelConfig = { modelKey: judgeCfg.modelKey };
4677
+ } else if (!hasCredentials) {
4678
+ const firstModel = import_core23.modelLatticeManager.getAllLattices()[0];
4679
+ if (firstModel) {
4680
+ judgeModelConfig = { modelKey: firstModel.key };
4681
+ } else {
4682
+ judgeModelConfig = { model: judgeCfg };
4683
+ }
4684
+ } else {
4685
+ judgeModelConfig = { model: judgeCfg };
4686
+ }
4687
+ const projectConfig = {
4688
+ projectName: project.name,
4689
+ version: project.version,
4690
+ description: project.description,
4691
+ suites: evalSuites,
4692
+ judge_agent_config: judgeModelConfig,
4693
+ lattice_server_config: {
4694
+ base_url: project.targetServerConfig.base_url || "",
4695
+ api_key: project.targetServerConfig.api_key || "",
4696
+ tenant_id: tenantId
4697
+ },
4698
+ concurrency
4699
+ };
4700
+ const abortController = new AbortController();
4701
+ const stats = { passed: 0, failed: 0, totalScore: 0 };
4702
+ const onCaseComplete = async (result, suiteName) => {
4703
+ const passed = result.result?.pass ?? false;
4704
+ const score = result.result?.final_score ?? 0;
4705
+ if (passed) stats.passed++;
4706
+ else stats.failed++;
4707
+ stats.totalScore += score;
4708
+ const completedCount = stats.passed + stats.failed;
4709
+ await store.createRunResult(tenantId, runId, (0, import_uuid3.v4)(), {
4710
+ suiteName,
4711
+ caseId: result.caseId,
4712
+ pass: passed,
4713
+ score,
4714
+ summary: result.result?.summary,
4715
+ dimensionResults: result.result?.dimension_results?.map((d) => ({
4716
+ name: d.name,
4717
+ score: d.score,
4718
+ reason: d.reason
4719
+ })),
4720
+ durationMs: result.duration_ms,
4721
+ messages: result.messages,
4722
+ logs: mapLogs(result.logs),
4723
+ error: result.error
4724
+ });
4725
+ const avgScore = completedCount > 0 ? stats.totalScore / completedCount : 0;
4726
+ await store.updateRunStatus(tenantId, runId, {
4727
+ passedCases: stats.passed,
4728
+ failedCases: stats.failed,
4729
+ avgScore
4730
+ });
4731
+ this.eventEmitter.emit(`run:${runId}`, {
4732
+ type: "progress",
4733
+ runId,
4734
+ data: { suiteName, caseId: result.caseId, pass: passed, score, completed: completedCount, total: totalCases }
4735
+ });
4736
+ };
4737
+ const runPromise = (async () => {
4738
+ try {
4739
+ const evalProject = new import_agent_eval.LatticeEvalProject(projectConfig, onCaseComplete);
4740
+ const { report } = await evalProject.runAllSuitesBatch(concurrency);
4741
+ const completedCount = stats.passed + stats.failed;
4742
+ await store.updateRunStatus(tenantId, runId, {
4743
+ status: "completed",
4744
+ completedAt: /* @__PURE__ */ new Date(),
4745
+ passedCases: stats.passed,
4746
+ failedCases: stats.failed,
4747
+ avgScore: completedCount > 0 ? stats.totalScore / completedCount : 0
4748
+ });
4749
+ this.eventEmitter.emit(`run:${runId}`, {
4750
+ type: "completed",
4751
+ runId,
4752
+ data: { passed: stats.passed, failed: stats.failed, avgScore: completedCount > 0 ? stats.totalScore / completedCount : 0 }
4753
+ });
4754
+ return { report };
4755
+ } catch (err) {
4756
+ const errorMsg = err.message;
4757
+ await store.updateRunStatus(tenantId, runId, {
4758
+ status: "failed",
4759
+ error: errorMsg,
4760
+ completedAt: /* @__PURE__ */ new Date()
4761
+ });
4762
+ this.eventEmitter.emit(`run:${runId}`, {
4763
+ type: "error",
4764
+ runId,
4765
+ data: { message: errorMsg }
4766
+ });
4767
+ throw err;
4768
+ } finally {
4769
+ this.runs.delete(runId);
4770
+ }
4771
+ })();
4772
+ this.runs.set(runId, { runId, projectId, tenantId, abortController, promise: runPromise });
4773
+ runPromise.catch(() => {
4774
+ });
4775
+ return runId;
4776
+ }
4777
+ async abortRun(runId) {
4778
+ const ctx = this.runs.get(runId);
4779
+ if (!ctx) return false;
4780
+ ctx.abortController.abort();
4781
+ const store = this.getEvalStore();
4782
+ await store.updateRunStatus(ctx.tenantId, runId, { status: "aborted", completedAt: /* @__PURE__ */ new Date() });
4783
+ return true;
4784
+ }
4785
+ isRunning(runId) {
4786
+ return this.runs.has(runId);
4787
+ }
4788
+ getEvalStore() {
4789
+ return (0, import_core23.getStoreLattice)("default", "eval").store;
4790
+ }
4791
+ };
4792
+ var evalRunner = new EvalRunner();
4793
+
4794
+ // src/controllers/eval.ts
4795
+ function getTenantId10(request) {
4796
+ const userTenantId = request.user?.tenantId;
4797
+ if (userTenantId) {
4798
+ return userTenantId;
4799
+ }
4800
+ return request.headers["x-tenant-id"] || "default";
4801
+ }
4802
+ function getEvalStore() {
4803
+ return (0, import_core24.getStoreLattice)("default", "eval").store;
4804
+ }
4805
+ async function createProject(request, reply) {
4806
+ try {
4807
+ const tenantId = getTenantId10(request);
4808
+ const store = getEvalStore();
4809
+ const id = (0, import_uuid4.v4)();
4810
+ const data = request.body;
4811
+ const project = await store.createProject(tenantId, id, {
4812
+ name: data.name,
4813
+ description: data.description,
4814
+ version: data.version,
4815
+ judgeModelConfig: data.judgeModelConfig ?? {},
4816
+ targetServerConfig: data.targetServerConfig ?? {},
4817
+ concurrency: data.concurrency ?? 1,
4818
+ reportConfig: data.reportConfig
4819
+ });
4820
+ return reply.status(201).send({
4821
+ success: true,
4822
+ message: "Successfully created project",
4823
+ data: project
4824
+ });
4825
+ } catch (err) {
4826
+ const message = err instanceof Error ? err.message : "Failed to create project";
4827
+ return reply.status(500).send({ success: false, message });
4828
+ }
4829
+ }
4830
+ async function listProjects(request, reply) {
4831
+ try {
4832
+ const tenantId = getTenantId10(request);
4833
+ const store = getEvalStore();
4834
+ let projects = await store.getProjectsByTenant(tenantId);
4835
+ if (projects.length === 0) {
4836
+ try {
4837
+ const { modelLatticeManager: modelLatticeManager3 } = await import("@axiom-lattice/core");
4838
+ const models = modelLatticeManager3.getAllLattices();
4839
+ const first = models[0];
4840
+ const judgeModel = first ? { modelKey: first.key } : { provider: "openai", model: "gpt-4" };
4841
+ const host = request.hostname || "localhost";
4842
+ const baseUrl = `http://${host}:${process.env.PORT || 4001}`;
4843
+ await store.createProject(tenantId, (0, import_uuid4.v4)(), {
4844
+ name: "Default",
4845
+ description: "Built-in project for testing eval against this server",
4846
+ judgeModelConfig: judgeModel,
4847
+ targetServerConfig: { base_url: baseUrl, api_key: "" },
4848
+ concurrency: 3
4849
+ });
4850
+ projects = await store.getProjectsByTenant(tenantId);
4851
+ } catch {
4852
+ }
4853
+ }
4854
+ return {
4855
+ success: true,
4856
+ message: "Ok",
4857
+ data: { records: projects, total: projects.length }
4858
+ };
4859
+ } catch (err) {
4860
+ const message = err instanceof Error ? err.message : "Failed to list projects";
4861
+ return reply.status(500).send({ success: false, message });
4862
+ }
4863
+ }
4864
+ async function getProject(request, reply) {
4865
+ try {
4866
+ const tenantId = getTenantId10(request);
4867
+ const store = getEvalStore();
4868
+ const { pid } = request.params;
4869
+ const project = await store.getProjectById(tenantId, pid);
4870
+ if (!project) {
4871
+ return reply.status(404).send({ success: false, message: "Project not found" });
4872
+ }
4873
+ const suites = await store.getSuitesByProject(tenantId, pid);
4874
+ return {
4875
+ success: true,
4876
+ message: "Ok",
4877
+ data: { project, suites }
4878
+ };
4879
+ } catch (err) {
4880
+ const message = err instanceof Error ? err.message : "Failed to get project";
4881
+ return reply.status(500).send({ success: false, message });
4882
+ }
4883
+ }
4884
+ async function updateProject(request, reply) {
4885
+ try {
4886
+ const tenantId = getTenantId10(request);
4887
+ const store = getEvalStore();
4888
+ const { pid } = request.params;
4889
+ const existing = await store.getProjectById(tenantId, pid);
4890
+ if (!existing) {
4891
+ return reply.status(404).send({ success: false, message: "Project not found" });
4892
+ }
4893
+ const updated = await store.updateProject(tenantId, pid, request.body);
4894
+ return {
4895
+ success: true,
4896
+ message: "Successfully updated project",
4897
+ data: updated
4898
+ };
4899
+ } catch (err) {
4900
+ const message = err instanceof Error ? err.message : "Failed to update project";
4901
+ return reply.status(500).send({ success: false, message });
4902
+ }
4903
+ }
4904
+ async function deleteProject(request, reply) {
4905
+ try {
4906
+ const tenantId = getTenantId10(request);
4907
+ const store = getEvalStore();
4908
+ const { pid } = request.params;
4909
+ const existing = await store.getProjectById(tenantId, pid);
4910
+ if (!existing) {
4911
+ return reply.status(404).send({ success: false, message: "Project not found" });
4912
+ }
4913
+ const deleted = await store.deleteProject(tenantId, pid);
4914
+ if (!deleted) {
4915
+ return reply.status(500).send({ success: false, message: "Failed to delete project" });
4916
+ }
4917
+ return { success: true, message: "Successfully deleted project" };
4918
+ } catch (err) {
4919
+ const message = err instanceof Error ? err.message : "Failed to delete project";
4920
+ return reply.status(500).send({ success: false, message });
4921
+ }
4922
+ }
4923
+ async function createSuite(request, reply) {
4924
+ try {
4925
+ const tenantId = getTenantId10(request);
4926
+ const store = getEvalStore();
4927
+ const { pid } = request.params;
4928
+ const project = await store.getProjectById(tenantId, pid);
4929
+ if (!project) {
4930
+ return reply.status(404).send({ success: false, message: "Project not found" });
4931
+ }
4932
+ const id = (0, import_uuid4.v4)();
4933
+ const data = request.body;
4934
+ const suite = await store.createSuite(tenantId, pid, id, { name: data.name });
4935
+ return reply.status(201).send({
4936
+ success: true,
4937
+ message: "Successfully created suite",
4938
+ data: suite
4939
+ });
4940
+ } catch (err) {
4941
+ const message = err instanceof Error ? err.message : "Failed to create suite";
4942
+ return reply.status(500).send({ success: false, message });
4943
+ }
4944
+ }
4945
+ async function updateSuite(request, reply) {
4946
+ try {
4947
+ const tenantId = getTenantId10(request);
4948
+ const store = getEvalStore();
4949
+ const { sid } = request.params;
4950
+ const existing = await store.getSuiteById(tenantId, sid);
4951
+ if (!existing) {
4952
+ return reply.status(404).send({ success: false, message: "Suite not found" });
4953
+ }
4954
+ const updated = await store.updateSuite(tenantId, sid, request.body);
4955
+ return {
4956
+ success: true,
4957
+ message: "Successfully updated suite",
4958
+ data: updated
4959
+ };
4960
+ } catch (err) {
4961
+ const message = err instanceof Error ? err.message : "Failed to update suite";
4962
+ return reply.status(500).send({ success: false, message });
4963
+ }
4964
+ }
4965
+ async function deleteSuite(request, reply) {
4966
+ try {
4967
+ const tenantId = getTenantId10(request);
4968
+ const store = getEvalStore();
4969
+ const { sid } = request.params;
4970
+ const existing = await store.getSuiteById(tenantId, sid);
4971
+ if (!existing) {
4972
+ return reply.status(404).send({ success: false, message: "Suite not found" });
4973
+ }
4974
+ const deleted = await store.deleteSuite(tenantId, sid);
4975
+ if (!deleted) {
4976
+ return reply.status(500).send({ success: false, message: "Failed to delete suite" });
4977
+ }
4978
+ return { success: true, message: "Successfully deleted suite" };
4979
+ } catch (err) {
4980
+ const message = err instanceof Error ? err.message : "Failed to delete suite";
4981
+ return reply.status(500).send({ success: false, message });
4982
+ }
4983
+ }
4984
+ async function createCase(request, reply) {
4985
+ try {
4986
+ const tenantId = getTenantId10(request);
4987
+ const store = getEvalStore();
4988
+ const { sid } = request.params;
4989
+ const suite = await store.getSuiteById(tenantId, sid);
4990
+ if (!suite) {
4991
+ return reply.status(404).send({ success: false, message: "Suite not found" });
4992
+ }
4993
+ const id = (0, import_uuid4.v4)();
4994
+ const data = request.body;
4995
+ const created = await store.createCase(tenantId, sid, id, {
4996
+ inputMessage: data.inputMessage,
4997
+ inputFiles: data.inputFiles,
4998
+ steps: data.steps ?? [],
4999
+ outputType: data.outputType ?? "message_content",
5000
+ contentAssertion: data.contentAssertion ?? "",
5001
+ rubrics: data.rubrics
5002
+ });
5003
+ return reply.status(201).send({
5004
+ success: true,
5005
+ message: "Successfully created case",
5006
+ data: created
5007
+ });
5008
+ } catch (err) {
5009
+ const message = err instanceof Error ? err.message : "Failed to create case";
5010
+ return reply.status(500).send({ success: false, message });
5011
+ }
5012
+ }
5013
+ async function listCasesForSuite(request, reply) {
5014
+ try {
5015
+ const tenantId = getTenantId10(request);
5016
+ const store = getEvalStore();
5017
+ const { sid } = request.params;
5018
+ const cases = await store.getCasesBySuite(tenantId, sid);
5019
+ return {
5020
+ success: true,
5021
+ message: "Ok",
5022
+ data: { records: cases, total: cases.length }
5023
+ };
5024
+ } catch (err) {
5025
+ const message = err instanceof Error ? err.message : "Failed to list cases";
5026
+ return reply.status(500).send({ success: false, message });
5027
+ }
5028
+ }
5029
+ async function updateCase(request, reply) {
5030
+ try {
5031
+ const tenantId = getTenantId10(request);
5032
+ const store = getEvalStore();
5033
+ const { cid } = request.params;
5034
+ const existing = await store.getCaseById(tenantId, cid);
5035
+ if (!existing) {
5036
+ return reply.status(404).send({ success: false, message: "Case not found" });
5037
+ }
5038
+ const updated = await store.updateCase(tenantId, cid, request.body);
5039
+ return {
5040
+ success: true,
5041
+ message: "Successfully updated case",
5042
+ data: updated
5043
+ };
5044
+ } catch (err) {
5045
+ const message = err instanceof Error ? err.message : "Failed to update case";
5046
+ return reply.status(500).send({ success: false, message });
5047
+ }
5048
+ }
5049
+ async function deleteCase(request, reply) {
5050
+ try {
5051
+ const tenantId = getTenantId10(request);
5052
+ const store = getEvalStore();
5053
+ const { cid } = request.params;
5054
+ const existing = await store.getCaseById(tenantId, cid);
5055
+ if (!existing) {
5056
+ return reply.status(404).send({ success: false, message: "Case not found" });
5057
+ }
5058
+ const deleted = await store.deleteCase(tenantId, cid);
5059
+ if (!deleted) {
5060
+ return reply.status(500).send({ success: false, message: "Failed to delete case" });
5061
+ }
5062
+ return { success: true, message: "Successfully deleted case" };
5063
+ } catch (err) {
5064
+ const message = err instanceof Error ? err.message : "Failed to delete case";
5065
+ return reply.status(500).send({ success: false, message });
5066
+ }
5067
+ }
5068
+ function registerEvalRoutes(app2) {
5069
+ app2.post("/api/eval/projects", createProject);
5070
+ app2.get("/api/eval/projects", listProjects);
5071
+ app2.get("/api/eval/projects/:pid", getProject);
5072
+ app2.put("/api/eval/projects/:pid", updateProject);
5073
+ app2.delete("/api/eval/projects/:pid", deleteProject);
5074
+ app2.post("/api/eval/projects/:pid/suites", createSuite);
5075
+ app2.put("/api/eval/projects/:pid/suites/:sid", updateSuite);
5076
+ app2.delete("/api/eval/projects/:pid/suites/:sid", deleteSuite);
5077
+ app2.post("/api/eval/projects/:pid/suites/:sid/cases", createCase);
5078
+ app2.get("/api/eval/projects/:pid/suites/:sid/cases", listCasesForSuite);
5079
+ app2.put("/api/eval/projects/:pid/suites/:sid/cases/:cid", updateCase);
5080
+ app2.delete("/api/eval/projects/:pid/suites/:sid/cases/:cid", deleteCase);
5081
+ app2.post("/api/eval/projects/:pid/runs", async (request, reply) => {
5082
+ try {
5083
+ const tenantId = getTenantId10(request);
5084
+ const { pid } = request.params;
5085
+ const runId = await evalRunner.startRun(tenantId, pid);
5086
+ reply.status(202).send({ success: true, message: "Run started", data: { run_id: runId } });
5087
+ } catch (err) {
5088
+ const msg = err.message;
5089
+ const code = msg === "Project not found" ? 404 : msg.includes("already in progress") ? 409 : 500;
5090
+ reply.status(code).send({ success: false, message: msg });
5091
+ }
5092
+ });
5093
+ app2.get("/api/eval/runs", async (request, reply) => {
5094
+ try {
5095
+ const tenantId = getTenantId10(request);
5096
+ const query = request.query;
5097
+ const runs = await getEvalStore().getRunsByTenant(tenantId, { projectId: query.project_id, status: query.status });
5098
+ reply.send({ success: true, message: "Ok", data: { records: runs, total: runs.length } });
5099
+ } catch (err) {
5100
+ reply.status(500).send({ success: false, message: err.message });
5101
+ }
5102
+ });
5103
+ app2.get("/api/eval/runs/:rid", async (request, reply) => {
5104
+ try {
5105
+ const tenantId = getTenantId10(request);
5106
+ const { rid } = request.params;
5107
+ const run = await getEvalStore().getRunById(tenantId, rid);
5108
+ if (!run) return reply.status(404).send({ success: false, message: "Run not found" });
5109
+ const results = await getEvalStore().getResultsByRun(tenantId, rid);
5110
+ reply.send({ success: true, message: "Ok", data: { ...run, results } });
5111
+ } catch (err) {
5112
+ reply.status(500).send({ success: false, message: err.message });
5113
+ }
5114
+ });
5115
+ app2.get("/api/eval/runs/:rid/stream", async (request, reply) => {
5116
+ reply.hijack();
5117
+ reply.raw.writeHead(200, {
5118
+ "Content-Type": "text/event-stream",
5119
+ "Cache-Control": "no-cache",
5120
+ Connection: "keep-alive",
5121
+ "Access-Control-Allow-Origin": "*"
5122
+ });
5123
+ const { rid } = request.params;
5124
+ const emitter = evalRunner.getEventEmitter();
5125
+ const eventKey = `run:${rid}`;
5126
+ if (!evalRunner.isRunning(rid)) {
5127
+ const tenantId = getTenantId10(request);
5128
+ const run = await getEvalStore().getRunById(tenantId, rid);
5129
+ if (run) {
5130
+ const eventType = run.status === "completed" ? "completed" : "error";
5131
+ reply.raw.write(`event: ${eventType}
5132
+ data: ${JSON.stringify({ passed: run.passedCases, failed: run.failedCases, avgScore: run.avgScore })}
5133
+
5134
+ `);
5135
+ }
5136
+ reply.raw.end();
5137
+ return;
5138
+ }
5139
+ const handler = (event) => {
5140
+ reply.raw.write(`event: ${event.type}
5141
+ data: ${JSON.stringify(event.data)}
5142
+
5143
+ `);
5144
+ if (event.type === "completed" || event.type === "error") {
5145
+ emitter.off(eventKey, handler);
5146
+ reply.raw.end();
5147
+ }
5148
+ };
5149
+ emitter.on(eventKey, handler);
5150
+ request.raw.on("close", () => {
5151
+ emitter.off(eventKey, handler);
5152
+ });
5153
+ });
5154
+ app2.post("/api/eval/runs/:rid/abort", async (request, reply) => {
5155
+ try {
5156
+ const { rid } = request.params;
5157
+ const aborted = await evalRunner.abortRun(rid);
5158
+ if (!aborted) return reply.status(404).send({ success: false, message: "Run not found or not running" });
5159
+ reply.send({ success: true, message: "Run aborted" });
5160
+ } catch (err) {
5161
+ reply.status(500).send({ success: false, message: err.message });
5162
+ }
5163
+ });
5164
+ app2.delete("/api/eval/runs/:rid", async (request, reply) => {
5165
+ try {
5166
+ const tenantId = getTenantId10(request);
5167
+ const { rid } = request.params;
5168
+ const deleted = await getEvalStore().deleteRun(tenantId, rid);
5169
+ if (!deleted) return reply.status(404).send({ success: false, message: "Run not found" });
5170
+ reply.send({ success: true, message: "Run deleted" });
5171
+ } catch (err) {
5172
+ reply.status(500).send({ success: false, message: err.message });
5173
+ }
5174
+ });
5175
+ app2.get("/api/eval/reports/projects/:pid", async (request, reply) => {
5176
+ try {
5177
+ const tenantId = getTenantId10(request);
5178
+ const { pid } = request.params;
5179
+ const report = await getEvalStore().getProjectReport(tenantId, pid);
5180
+ if (!report) return reply.status(404).send({ success: false, message: "Project not found" });
5181
+ reply.send({ success: true, message: "Ok", data: report });
5182
+ } catch (err) {
5183
+ reply.status(500).send({ success: false, message: err.message });
5184
+ }
5185
+ });
5186
+ }
5187
+
5188
+ // src/controllers/users.ts
5189
+ var import_core25 = require("@axiom-lattice/core");
5190
+ var import_uuid5 = require("uuid");
4612
5191
  var UsersController = class {
4613
5192
  constructor() {
4614
- this.userStore = (0, import_core23.getStoreLattice)("default", "user").store;
5193
+ this.userStore = (0, import_core25.getStoreLattice)("default", "user").store;
4615
5194
  }
4616
5195
  async listUsers(request, reply) {
4617
5196
  const { email } = request.query;
@@ -4624,7 +5203,7 @@ var UsersController = class {
4624
5203
  }
4625
5204
  async createUser(request, reply) {
4626
5205
  const data = request.body;
4627
- const id = (0, import_uuid3.v4)();
5206
+ const id = (0, import_uuid5.v4)();
4628
5207
  const existingUser = await this.userStore.getUserByEmail(data.email);
4629
5208
  if (existingUser) {
4630
5209
  return reply.status(409).send({
@@ -4689,11 +5268,11 @@ function registerUserRoutes(app2) {
4689
5268
  }
4690
5269
 
4691
5270
  // src/controllers/tenants.ts
4692
- var import_core24 = require("@axiom-lattice/core");
4693
- var import_uuid4 = require("uuid");
5271
+ var import_core26 = require("@axiom-lattice/core");
5272
+ var import_uuid6 = require("uuid");
4694
5273
  var TenantsController = class {
4695
5274
  constructor() {
4696
- this.tenantStore = (0, import_core24.getStoreLattice)("default", "tenant").store;
5275
+ this.tenantStore = (0, import_core26.getStoreLattice)("default", "tenant").store;
4697
5276
  }
4698
5277
  // ==================== Tenant CRUD ====================
4699
5278
  async listTenants(request, reply) {
@@ -4702,7 +5281,7 @@ var TenantsController = class {
4702
5281
  }
4703
5282
  async createTenant(request, reply) {
4704
5283
  const data = request.body;
4705
- const id = (0, import_uuid4.v4)();
5284
+ const id = (0, import_uuid6.v4)();
4706
5285
  const tenant = await this.tenantStore.createTenant(id, data);
4707
5286
  return reply.status(201).send({ success: true, data: tenant });
4708
5287
  }
@@ -4757,8 +5336,8 @@ function registerTenantRoutes(app2) {
4757
5336
  }
4758
5337
 
4759
5338
  // src/controllers/auth.ts
4760
- var import_core25 = require("@axiom-lattice/core");
4761
- var import_uuid5 = require("uuid");
5339
+ var import_core27 = require("@axiom-lattice/core");
5340
+ var import_uuid7 = require("uuid");
4762
5341
  var defaultAuthConfig = {
4763
5342
  autoApproveUsers: true,
4764
5343
  allowTenantRegistration: true,
@@ -4766,9 +5345,9 @@ var defaultAuthConfig = {
4766
5345
  };
4767
5346
  var AuthController = class {
4768
5347
  constructor(config = {}) {
4769
- this.userStore = (0, import_core25.getStoreLattice)("default", "user").store;
4770
- this.tenantStore = (0, import_core25.getStoreLattice)("default", "tenant").store;
4771
- this.userTenantLinkStore = (0, import_core25.getStoreLattice)("default", "userTenantLink").store;
5348
+ this.userStore = (0, import_core27.getStoreLattice)("default", "user").store;
5349
+ this.tenantStore = (0, import_core27.getStoreLattice)("default", "tenant").store;
5350
+ this.userTenantLinkStore = (0, import_core27.getStoreLattice)("default", "userTenantLink").store;
4772
5351
  this.config = { ...defaultAuthConfig, ...config };
4773
5352
  }
4774
5353
  async register(request, reply) {
@@ -4781,7 +5360,7 @@ var AuthController = class {
4781
5360
  error: "User with this email already exists"
4782
5361
  });
4783
5362
  }
4784
- const userId = (0, import_uuid5.v4)();
5363
+ const userId = (0, import_uuid7.v4)();
4785
5364
  const userStatus = this.config.autoApproveUsers ? "active" : "pending";
4786
5365
  const userData = {
4787
5366
  email,
@@ -5136,7 +5715,7 @@ function registerAuthRoutes(app2, config) {
5136
5715
  }
5137
5716
 
5138
5717
  // src/channels/lark/routes.ts
5139
- var import_core27 = require("@axiom-lattice/core");
5718
+ var import_core29 = require("@axiom-lattice/core");
5140
5719
  var import_pg_stores = require("@axiom-lattice/pg-stores");
5141
5720
 
5142
5721
  // src/channels/lark/parser.ts
@@ -5384,7 +5963,7 @@ function resolveSubjectType(mappingMode, chatType) {
5384
5963
  }
5385
5964
 
5386
5965
  // src/channels/lark/runner.ts
5387
- var import_core26 = require("@axiom-lattice/core");
5966
+ var import_core28 = require("@axiom-lattice/core");
5388
5967
  var import_protocols5 = require("@axiom-lattice/protocols");
5389
5968
 
5390
5969
  // src/channels/lark/aggregator.ts
@@ -5397,7 +5976,7 @@ function aggregateLarkReply(messageId, chunks) {
5397
5976
 
5398
5977
  // src/channels/lark/runner.ts
5399
5978
  async function runAgentAndCollectLarkReply(input) {
5400
- const agent = import_core26.agentInstanceManager.getAgent({
5979
+ const agent = import_core28.agentInstanceManager.getAgent({
5401
5980
  tenant_id: input.tenantId,
5402
5981
  assistant_id: input.assistantId,
5403
5982
  thread_id: input.threadId,
@@ -5509,7 +6088,7 @@ function createDefaultLarkDependencies() {
5509
6088
  const installationStore = new import_pg_stores.PostgreSQLChannelInstallationStore({
5510
6089
  poolConfig: getDatabaseUrl()
5511
6090
  });
5512
- const threadStore = (0, import_core27.getStoreLattice)("default", "thread").store;
6091
+ const threadStore = (0, import_core29.getStoreLattice)("default", "thread").store;
5513
6092
  const mappingStore = new import_pg_stores.ChannelIdentityMappingStore({
5514
6093
  poolConfig: getDatabaseUrl()
5515
6094
  });
@@ -5590,7 +6169,7 @@ function registerChannelRoutes(app2, dependencies = {}) {
5590
6169
 
5591
6170
  // src/controllers/channel-installations.ts
5592
6171
  var import_crypto8 = require("crypto");
5593
- function getTenantId10(request) {
6172
+ function getTenantId11(request) {
5594
6173
  const userTenantId = request.user?.tenantId;
5595
6174
  if (userTenantId) {
5596
6175
  return userTenantId;
@@ -5608,7 +6187,7 @@ async function getInstallationStore() {
5608
6187
  });
5609
6188
  }
5610
6189
  async function getChannelInstallationList(request, reply) {
5611
- const tenantId = getTenantId10(request);
6190
+ const tenantId = getTenantId11(request);
5612
6191
  const { channel } = request.query;
5613
6192
  try {
5614
6193
  const store = await getInstallationStore();
@@ -5634,7 +6213,7 @@ async function getChannelInstallationList(request, reply) {
5634
6213
  }
5635
6214
  }
5636
6215
  async function getChannelInstallation(request, reply) {
5637
- const tenantId = getTenantId10(request);
6216
+ const tenantId = getTenantId11(request);
5638
6217
  const { installationId } = request.params;
5639
6218
  try {
5640
6219
  const store = await getInstallationStore();
@@ -5667,7 +6246,7 @@ async function getChannelInstallation(request, reply) {
5667
6246
  }
5668
6247
  }
5669
6248
  async function createChannelInstallation(request, reply) {
5670
- const tenantId = getTenantId10(request);
6249
+ const tenantId = getTenantId11(request);
5671
6250
  const body = request.body;
5672
6251
  try {
5673
6252
  if (!body.channel) {
@@ -5730,7 +6309,7 @@ async function createChannelInstallation(request, reply) {
5730
6309
  }
5731
6310
  }
5732
6311
  async function updateChannelInstallation(request, reply) {
5733
- const tenantId = getTenantId10(request);
6312
+ const tenantId = getTenantId11(request);
5734
6313
  const { installationId } = request.params;
5735
6314
  const body = request.body;
5736
6315
  try {
@@ -5776,7 +6355,7 @@ async function updateChannelInstallation(request, reply) {
5776
6355
  }
5777
6356
  }
5778
6357
  async function deleteChannelInstallation(request, reply) {
5779
- const tenantId = getTenantId10(request);
6358
+ const tenantId = getTenantId11(request);
5780
6359
  const { installationId } = request.params;
5781
6360
  try {
5782
6361
  const store = await getInstallationStore();
@@ -5945,6 +6524,7 @@ var registerLatticeRoutes = (app2) => {
5945
6524
  filterSkillsByLicense
5946
6525
  );
5947
6526
  registerSandboxProxyRoutes(app2);
6527
+ registerEvalRoutes(app2);
5948
6528
  registerWorkspaceRoutes(app2);
5949
6529
  registerDatabaseConfigRoutes(app2);
5950
6530
  registerMetricsServerConfigRoutes(app2);
@@ -6055,7 +6635,7 @@ var configureSwagger = async (app2, customSwaggerConfig, customSwaggerUiConfig)
6055
6635
  };
6056
6636
 
6057
6637
  // src/services/agent_task_consumer.ts
6058
- var import_core28 = require("@axiom-lattice/core");
6638
+ var import_core30 = require("@axiom-lattice/core");
6059
6639
  var handleAgentTask = async (taskRequest, retryCount = 0) => {
6060
6640
  const {
6061
6641
  assistant_id,
@@ -6073,18 +6653,18 @@ var handleAgentTask = async (taskRequest, retryCount = 0) => {
6073
6653
  console.log(
6074
6654
  `\u5F00\u59CB\u5904\u7406\u4EFB\u52A1 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
6075
6655
  );
6076
- const agent = import_core28.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
6077
- await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core28.QueueMode.STEER);
6656
+ const agent = import_core30.agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig });
6657
+ await agent.addMessage({ input, command, custom_run_config: runConfig }, import_core30.QueueMode.STEER);
6078
6658
  if (callback_event) {
6079
6659
  agent.subscribeOnce("message:completed", (evt) => {
6080
- import_core28.eventBus.publish(callback_event, {
6660
+ import_core30.eventBus.publish(callback_event, {
6081
6661
  success: true,
6082
6662
  state: evt.state,
6083
6663
  config: { assistant_id, thread_id, tenant_id }
6084
6664
  });
6085
6665
  if (main_thread_id && main_tenant_id) {
6086
6666
  try {
6087
- const mainAgent = import_core28.agentInstanceManager.getAgent({
6667
+ const mainAgent = import_core30.agentInstanceManager.getAgent({
6088
6668
  assistant_id: main_assistant_id ?? assistant_id,
6089
6669
  thread_id: main_thread_id,
6090
6670
  tenant_id: main_tenant_id
@@ -6112,7 +6692,7 @@ ${summary}`
6112
6692
  }
6113
6693
  });
6114
6694
  agent.subscribeOnce("message:interrupted", (evt) => {
6115
- import_core28.eventBus.publish(callback_event, {
6695
+ import_core30.eventBus.publish(callback_event, {
6116
6696
  success: true,
6117
6697
  state: evt.state,
6118
6698
  config: { assistant_id, thread_id, tenant_id }
@@ -6136,7 +6716,7 @@ ${summary}`
6136
6716
  return handleAgentTask(taskRequest, nextRetryCount);
6137
6717
  }
6138
6718
  if (callback_event) {
6139
- import_core28.eventBus.publish(callback_event, {
6719
+ import_core30.eventBus.publish(callback_event, {
6140
6720
  success: false,
6141
6721
  error: error instanceof Error ? error.message : String(error),
6142
6722
  config: { assistant_id, thread_id, tenant_id }
@@ -6174,7 +6754,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
6174
6754
  * 初始化事件监听和队列轮询
6175
6755
  */
6176
6756
  initialize() {
6177
- import_core28.eventBus.subscribe(import_core28.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
6757
+ import_core30.eventBus.subscribe(import_core30.AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
6178
6758
  this.startPollingQueue();
6179
6759
  console.log("Agent\u4EFB\u52A1\u6D88\u8D39\u8005\u5DF2\u542F\u52A8\u5E76\u76D1\u542C\u4EFB\u52A1\u4E8B\u4EF6\u548C\u961F\u5217");
6180
6760
  }
@@ -6293,7 +6873,7 @@ var _AgentTaskConsumer = class _AgentTaskConsumer {
6293
6873
  handleAgentTask(taskRequest).catch((error) => {
6294
6874
  console.error("\u5904\u7406Agent\u4EFB\u52A1\u65F6\u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:", error);
6295
6875
  if (taskRequest.callback_event) {
6296
- import_core28.eventBus.publish(taskRequest.callback_event, {
6876
+ import_core30.eventBus.publish(taskRequest.callback_event, {
6297
6877
  success: false,
6298
6878
  error: error instanceof Error ? error.message : String(error),
6299
6879
  config: {
@@ -6313,7 +6893,7 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
6313
6893
  var AgentTaskConsumer = _AgentTaskConsumer;
6314
6894
 
6315
6895
  // src/index.ts
6316
- var import_core29 = require("@axiom-lattice/core");
6896
+ var import_core31 = require("@axiom-lattice/core");
6317
6897
  var import_protocols6 = require("@axiom-lattice/protocols");
6318
6898
  var import_meta = {};
6319
6899
  process.on("unhandledRejection", (reason, promise) => {
@@ -6329,11 +6909,11 @@ var DEFAULT_LOGGER_CONFIG = {
6329
6909
  var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
6330
6910
  var logger = loggerLattice.client;
6331
6911
  function initializeLogger(config) {
6332
- if (import_core29.loggerLatticeManager.hasLattice("default")) {
6333
- import_core29.loggerLatticeManager.removeLattice("default");
6912
+ if (import_core31.loggerLatticeManager.hasLattice("default")) {
6913
+ import_core31.loggerLatticeManager.removeLattice("default");
6334
6914
  }
6335
- (0, import_core29.registerLoggerLattice)("default", config);
6336
- return (0, import_core29.getLoggerLattice)("default");
6915
+ (0, import_core31.registerLoggerLattice)("default", config);
6916
+ return (0, import_core31.getLoggerLattice)("default");
6337
6917
  }
6338
6918
  var app = (0, import_fastify.default)({
6339
6919
  logger: false,
@@ -6436,7 +7016,7 @@ app.setErrorHandler((error, request, reply) => {
6436
7016
  });
6437
7017
  function getConfiguredSandboxProvider() {
6438
7018
  const sandboxProviderType = process.env.SANDBOX_PROVIDER_TYPE || "microsandbox-remote";
6439
- return (0, import_core29.createSandboxProvider)({
7019
+ return (0, import_core31.createSandboxProvider)({
6440
7020
  type: sandboxProviderType,
6441
7021
  remoteBaseURL: process.env.SANDBOX_BASE_URL,
6442
7022
  microsandboxServiceBaseURL: process.env.MICROSANDBOX_SERVICE_BASE_URL,
@@ -6465,15 +7045,15 @@ var start = async (config) => {
6465
7045
  app.decorate("loggerLattice", loggerLattice);
6466
7046
  registerLatticeRoutes(app);
6467
7047
  try {
6468
- const storeLattice = (0, import_core29.getStoreLattice)("default", "database");
7048
+ const storeLattice = (0, import_core31.getStoreLattice)("default", "database");
6469
7049
  const store = storeLattice.store;
6470
- import_core29.sqlDatabaseManager.setConfigStore(store);
7050
+ import_core31.sqlDatabaseManager.setConfigStore(store);
6471
7051
  logger.info("Database config store set for SqlDatabaseManager");
6472
7052
  } catch (error) {
6473
7053
  logger.warn("Failed to set database config store: " + (error instanceof Error ? error.message : String(error)));
6474
7054
  }
6475
- if (!import_core29.sandboxLatticeManager.hasLattice("default")) {
6476
- import_core29.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
7055
+ if (!import_core31.sandboxLatticeManager.hasLattice("default")) {
7056
+ import_core31.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
6477
7057
  logger.info("Registered sandbox manager from env configuration");
6478
7058
  }
6479
7059
  const target_port = config?.port || Number(process.env.PORT) || 4001;
@@ -6494,7 +7074,7 @@ var start = async (config) => {
6494
7074
  }
6495
7075
  try {
6496
7076
  logger.info("Starting agent instance recovery...");
6497
- const restoreStats = await import_core29.agentInstanceManager.restore();
7077
+ const restoreStats = await import_core31.agentInstanceManager.restore();
6498
7078
  logger.info(`Agent recovery complete: ${restoreStats.restored} threads restored, ${restoreStats.errors} errors`);
6499
7079
  } catch (error) {
6500
7080
  logger.error("Agent recovery failed", { error });