@axlsdk/studio 0.13.8 → 0.14.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/README.md +54 -1
- package/dist/{chunk-YWRYXT7U.js → chunk-HUKUQDYL.js} +232 -90
- package/dist/chunk-HUKUQDYL.js.map +1 -0
- package/dist/{chunk-6VDX5CRP.js → chunk-JGQ3MSIG.js} +5 -2
- package/dist/chunk-JGQ3MSIG.js.map +1 -0
- package/dist/cli.cjs +246 -96
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +8 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/index-7aDhMztu.css +1 -0
- package/dist/client/assets/index-Bzr3vDPz.js +255 -0
- package/dist/client/index.html +2 -2
- package/dist/middleware.cjs +235 -93
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.js +2 -2
- package/dist/server/index.cjs +232 -90
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +5 -4
- package/dist/chunk-6VDX5CRP.js.map +0 -1
- package/dist/chunk-YWRYXT7U.js.map +0 -1
- package/dist/client/assets/index-C_uwupnn.js +0 -221
- package/dist/client/assets/index-DVcH6P9w.css +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -329,27 +329,30 @@ var CostAggregator = class {
|
|
|
329
329
|
|
|
330
330
|
// src/server/routes/health.ts
|
|
331
331
|
var import_hono = require("hono");
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
332
|
+
function createHealthRoutes(readOnly) {
|
|
333
|
+
const app6 = new import_hono.Hono();
|
|
334
|
+
app6.get("/health", (c) => {
|
|
335
|
+
const runtime = c.get("runtime");
|
|
336
|
+
return c.json({
|
|
337
|
+
ok: true,
|
|
338
|
+
data: {
|
|
339
|
+
status: "healthy",
|
|
340
|
+
readOnly,
|
|
341
|
+
workflows: runtime.getWorkflowNames().length,
|
|
342
|
+
agents: runtime.getAgents().length,
|
|
343
|
+
tools: runtime.getTools().length
|
|
344
|
+
}
|
|
345
|
+
});
|
|
343
346
|
});
|
|
344
|
-
|
|
345
|
-
|
|
347
|
+
return app6;
|
|
348
|
+
}
|
|
346
349
|
|
|
347
350
|
// src/server/routes/workflows.ts
|
|
348
351
|
var import_hono2 = require("hono");
|
|
349
352
|
var import_axl = require("@axlsdk/axl");
|
|
350
353
|
function createWorkflowRoutes(connMgr) {
|
|
351
|
-
const
|
|
352
|
-
|
|
354
|
+
const app6 = new import_hono2.Hono();
|
|
355
|
+
app6.get("/workflows", (c) => {
|
|
353
356
|
const runtime = c.get("runtime");
|
|
354
357
|
const workflows = runtime.getWorkflows().map((w) => ({
|
|
355
358
|
name: w.name,
|
|
@@ -358,7 +361,7 @@ function createWorkflowRoutes(connMgr) {
|
|
|
358
361
|
}));
|
|
359
362
|
return c.json({ ok: true, data: workflows });
|
|
360
363
|
});
|
|
361
|
-
|
|
364
|
+
app6.get("/workflows/:name", (c) => {
|
|
362
365
|
const runtime = c.get("runtime");
|
|
363
366
|
const name = c.req.param("name");
|
|
364
367
|
const workflow = runtime.getWorkflow(name);
|
|
@@ -377,7 +380,7 @@ function createWorkflowRoutes(connMgr) {
|
|
|
377
380
|
}
|
|
378
381
|
});
|
|
379
382
|
});
|
|
380
|
-
|
|
383
|
+
app6.post("/workflows/:name/execute", async (c) => {
|
|
381
384
|
const runtime = c.get("runtime");
|
|
382
385
|
const name = c.req.param("name");
|
|
383
386
|
const workflow = runtime.getWorkflow(name);
|
|
@@ -401,18 +404,18 @@ function createWorkflowRoutes(connMgr) {
|
|
|
401
404
|
const result = await runtime.execute(name, body.input ?? {}, { metadata: body.metadata });
|
|
402
405
|
return c.json({ ok: true, data: { result } });
|
|
403
406
|
});
|
|
404
|
-
return
|
|
407
|
+
return app6;
|
|
405
408
|
}
|
|
406
409
|
|
|
407
410
|
// src/server/routes/executions.ts
|
|
408
411
|
var import_hono3 = require("hono");
|
|
409
|
-
var
|
|
410
|
-
|
|
412
|
+
var app = new import_hono3.Hono();
|
|
413
|
+
app.get("/executions", async (c) => {
|
|
411
414
|
const runtime = c.get("runtime");
|
|
412
415
|
const executions = await runtime.getExecutions();
|
|
413
416
|
return c.json({ ok: true, data: executions });
|
|
414
417
|
});
|
|
415
|
-
|
|
418
|
+
app.get("/executions/:id", async (c) => {
|
|
416
419
|
const runtime = c.get("runtime");
|
|
417
420
|
const id = c.req.param("id");
|
|
418
421
|
const execution = await runtime.getExecution(id);
|
|
@@ -424,19 +427,19 @@ app2.get("/executions/:id", async (c) => {
|
|
|
424
427
|
}
|
|
425
428
|
return c.json({ ok: true, data: execution });
|
|
426
429
|
});
|
|
427
|
-
|
|
430
|
+
app.post("/executions/:id/abort", (c) => {
|
|
428
431
|
const runtime = c.get("runtime");
|
|
429
432
|
const id = c.req.param("id");
|
|
430
433
|
runtime.abort(id);
|
|
431
434
|
return c.json({ ok: true, data: { aborted: true } });
|
|
432
435
|
});
|
|
433
|
-
var executions_default =
|
|
436
|
+
var executions_default = app;
|
|
434
437
|
|
|
435
438
|
// src/server/routes/sessions.ts
|
|
436
439
|
var import_hono4 = require("hono");
|
|
437
440
|
function createSessionRoutes(connMgr) {
|
|
438
|
-
const
|
|
439
|
-
|
|
441
|
+
const app6 = new import_hono4.Hono();
|
|
442
|
+
app6.get("/sessions", async (c) => {
|
|
440
443
|
const runtime = c.get("runtime");
|
|
441
444
|
const store = runtime.getStateStore();
|
|
442
445
|
if (!store.listSessions) {
|
|
@@ -450,7 +453,7 @@ function createSessionRoutes(connMgr) {
|
|
|
450
453
|
}
|
|
451
454
|
return c.json({ ok: true, data: sessions });
|
|
452
455
|
});
|
|
453
|
-
|
|
456
|
+
app6.get("/sessions/:id", async (c) => {
|
|
454
457
|
const runtime = c.get("runtime");
|
|
455
458
|
const store = runtime.getStateStore();
|
|
456
459
|
const id = c.req.param("id");
|
|
@@ -458,7 +461,7 @@ function createSessionRoutes(connMgr) {
|
|
|
458
461
|
const handoffHistory = await store.getSessionMeta(id, "handoffHistory");
|
|
459
462
|
return c.json({ ok: true, data: { id, history, handoffHistory: handoffHistory ?? [] } });
|
|
460
463
|
});
|
|
461
|
-
|
|
464
|
+
app6.post("/sessions/:id/send", async (c) => {
|
|
462
465
|
const runtime = c.get("runtime");
|
|
463
466
|
const id = c.req.param("id");
|
|
464
467
|
const body = await c.req.json();
|
|
@@ -466,7 +469,7 @@ function createSessionRoutes(connMgr) {
|
|
|
466
469
|
const result = await session.send(body.workflow, body.message);
|
|
467
470
|
return c.json({ ok: true, data: { result } });
|
|
468
471
|
});
|
|
469
|
-
|
|
472
|
+
app6.post("/sessions/:id/stream", async (c) => {
|
|
470
473
|
const runtime = c.get("runtime");
|
|
471
474
|
const id = c.req.param("id");
|
|
472
475
|
const body = await c.req.json();
|
|
@@ -480,21 +483,21 @@ function createSessionRoutes(connMgr) {
|
|
|
480
483
|
})();
|
|
481
484
|
return c.json({ ok: true, data: { executionId, streaming: true } });
|
|
482
485
|
});
|
|
483
|
-
|
|
486
|
+
app6.delete("/sessions/:id", async (c) => {
|
|
484
487
|
const runtime = c.get("runtime");
|
|
485
488
|
const store = runtime.getStateStore();
|
|
486
489
|
const id = c.req.param("id");
|
|
487
490
|
await store.deleteSession(id);
|
|
488
491
|
return c.json({ ok: true, data: { deleted: true } });
|
|
489
492
|
});
|
|
490
|
-
return
|
|
493
|
+
return app6;
|
|
491
494
|
}
|
|
492
495
|
|
|
493
496
|
// src/server/routes/agents.ts
|
|
494
497
|
var import_hono5 = require("hono");
|
|
495
498
|
var import_axl2 = require("@axlsdk/axl");
|
|
496
|
-
var
|
|
497
|
-
|
|
499
|
+
var app2 = new import_hono5.Hono();
|
|
500
|
+
app2.get("/agents", (c) => {
|
|
498
501
|
const runtime = c.get("runtime");
|
|
499
502
|
const agents = runtime.getAgents().map((a) => ({
|
|
500
503
|
name: a._name,
|
|
@@ -513,7 +516,7 @@ app3.get("/agents", (c) => {
|
|
|
513
516
|
}));
|
|
514
517
|
return c.json({ ok: true, data: agents });
|
|
515
518
|
});
|
|
516
|
-
|
|
519
|
+
app2.get("/agents/:name", (c) => {
|
|
517
520
|
const runtime = c.get("runtime");
|
|
518
521
|
const name = c.req.param("name");
|
|
519
522
|
const agent = runtime.getAgent(name);
|
|
@@ -569,13 +572,13 @@ app3.get("/agents/:name", (c) => {
|
|
|
569
572
|
}
|
|
570
573
|
});
|
|
571
574
|
});
|
|
572
|
-
var agents_default =
|
|
575
|
+
var agents_default = app2;
|
|
573
576
|
|
|
574
577
|
// src/server/routes/tools.ts
|
|
575
578
|
var import_hono6 = require("hono");
|
|
576
579
|
var import_axl3 = require("@axlsdk/axl");
|
|
577
|
-
var
|
|
578
|
-
|
|
580
|
+
var app3 = new import_hono6.Hono();
|
|
581
|
+
app3.get("/tools", (c) => {
|
|
579
582
|
const runtime = c.get("runtime");
|
|
580
583
|
const tools = runtime.getTools().map((t) => ({
|
|
581
584
|
name: t.name,
|
|
@@ -586,7 +589,7 @@ app4.get("/tools", (c) => {
|
|
|
586
589
|
}));
|
|
587
590
|
return c.json({ ok: true, data: tools });
|
|
588
591
|
});
|
|
589
|
-
|
|
592
|
+
app3.get("/tools/:name", (c) => {
|
|
590
593
|
const runtime = c.get("runtime");
|
|
591
594
|
const name = c.req.param("name");
|
|
592
595
|
const tool = runtime.getTool(name);
|
|
@@ -613,7 +616,7 @@ app4.get("/tools/:name", (c) => {
|
|
|
613
616
|
}
|
|
614
617
|
});
|
|
615
618
|
});
|
|
616
|
-
|
|
619
|
+
app3.post("/tools/:name/test", async (c) => {
|
|
617
620
|
const runtime = c.get("runtime");
|
|
618
621
|
const name = c.req.param("name");
|
|
619
622
|
const tool = runtime.getTool(name);
|
|
@@ -628,12 +631,12 @@ app4.post("/tools/:name/test", async (c) => {
|
|
|
628
631
|
const result = await tool.run(ctx, body.input);
|
|
629
632
|
return c.json({ ok: true, data: { result } });
|
|
630
633
|
});
|
|
631
|
-
var tools_default =
|
|
634
|
+
var tools_default = app3;
|
|
632
635
|
|
|
633
636
|
// src/server/routes/memory.ts
|
|
634
637
|
var import_hono7 = require("hono");
|
|
635
|
-
var
|
|
636
|
-
|
|
638
|
+
var app4 = new import_hono7.Hono();
|
|
639
|
+
app4.get("/memory/:scope", async (c) => {
|
|
637
640
|
const runtime = c.get("runtime");
|
|
638
641
|
const store = runtime.getStateStore();
|
|
639
642
|
const scope = c.req.param("scope");
|
|
@@ -643,7 +646,7 @@ app5.get("/memory/:scope", async (c) => {
|
|
|
643
646
|
const entries = await store.getAllMemory(scope);
|
|
644
647
|
return c.json({ ok: true, data: entries });
|
|
645
648
|
});
|
|
646
|
-
|
|
649
|
+
app4.get("/memory/:scope/:key", async (c) => {
|
|
647
650
|
const runtime = c.get("runtime");
|
|
648
651
|
const store = runtime.getStateStore();
|
|
649
652
|
const scope = c.req.param("scope");
|
|
@@ -663,7 +666,7 @@ app5.get("/memory/:scope/:key", async (c) => {
|
|
|
663
666
|
}
|
|
664
667
|
return c.json({ ok: true, data: { key, value } });
|
|
665
668
|
});
|
|
666
|
-
|
|
669
|
+
app4.put("/memory/:scope/:key", async (c) => {
|
|
667
670
|
const runtime = c.get("runtime");
|
|
668
671
|
const store = runtime.getStateStore();
|
|
669
672
|
const scope = c.req.param("scope");
|
|
@@ -678,7 +681,7 @@ app5.put("/memory/:scope/:key", async (c) => {
|
|
|
678
681
|
await store.saveMemory(scope, key, body.value);
|
|
679
682
|
return c.json({ ok: true, data: { saved: true } });
|
|
680
683
|
});
|
|
681
|
-
|
|
684
|
+
app4.delete("/memory/:scope/:key", async (c) => {
|
|
682
685
|
const runtime = c.get("runtime");
|
|
683
686
|
const store = runtime.getStateStore();
|
|
684
687
|
const scope = c.req.param("scope");
|
|
@@ -692,61 +695,77 @@ app5.delete("/memory/:scope/:key", async (c) => {
|
|
|
692
695
|
await store.deleteMemory(scope, key);
|
|
693
696
|
return c.json({ ok: true, data: { deleted: true } });
|
|
694
697
|
});
|
|
695
|
-
|
|
698
|
+
app4.post("/memory/search", async (c) => {
|
|
696
699
|
return c.json({
|
|
697
700
|
ok: true,
|
|
698
701
|
data: { results: [], message: "Semantic search requires MemoryManager with vector store" }
|
|
699
702
|
});
|
|
700
703
|
});
|
|
701
|
-
var memory_default =
|
|
704
|
+
var memory_default = app4;
|
|
702
705
|
|
|
703
706
|
// src/server/routes/decisions.ts
|
|
704
707
|
var import_hono8 = require("hono");
|
|
705
|
-
var
|
|
706
|
-
|
|
708
|
+
var app5 = new import_hono8.Hono();
|
|
709
|
+
app5.get("/decisions", async (c) => {
|
|
707
710
|
const runtime = c.get("runtime");
|
|
708
711
|
const decisions = await runtime.getPendingDecisions();
|
|
709
712
|
return c.json({ ok: true, data: decisions });
|
|
710
713
|
});
|
|
711
|
-
|
|
714
|
+
app5.post("/decisions/:executionId/resolve", async (c) => {
|
|
712
715
|
const runtime = c.get("runtime");
|
|
713
716
|
const executionId = c.req.param("executionId");
|
|
714
717
|
const body = await c.req.json();
|
|
715
718
|
await runtime.resolveDecision(executionId, body);
|
|
716
719
|
return c.json({ ok: true, data: { resolved: true } });
|
|
717
720
|
});
|
|
718
|
-
var decisions_default =
|
|
721
|
+
var decisions_default = app5;
|
|
719
722
|
|
|
720
723
|
// src/server/routes/costs.ts
|
|
721
724
|
var import_hono9 = require("hono");
|
|
722
725
|
function createCostRoutes(costAggregator) {
|
|
723
|
-
const
|
|
724
|
-
|
|
726
|
+
const app6 = new import_hono9.Hono();
|
|
727
|
+
app6.get("/costs", (c) => {
|
|
725
728
|
return c.json({ ok: true, data: costAggregator.getData() });
|
|
726
729
|
});
|
|
727
|
-
|
|
730
|
+
app6.post("/costs/reset", (c) => {
|
|
728
731
|
costAggregator.reset();
|
|
729
732
|
return c.json({ ok: true, data: { reset: true } });
|
|
730
733
|
});
|
|
731
|
-
return
|
|
734
|
+
return app6;
|
|
732
735
|
}
|
|
733
736
|
|
|
734
737
|
// src/server/routes/evals.ts
|
|
738
|
+
var import_node_crypto = require("crypto");
|
|
735
739
|
var import_hono10 = require("hono");
|
|
736
740
|
function createEvalRoutes(evalLoader) {
|
|
737
|
-
const
|
|
738
|
-
|
|
741
|
+
const app6 = new import_hono10.Hono();
|
|
742
|
+
app6.get("/evals", async (c) => {
|
|
739
743
|
if (evalLoader) await evalLoader();
|
|
740
744
|
const runtime = c.get("runtime");
|
|
741
745
|
const evals = runtime.getRegisteredEvals();
|
|
742
746
|
return c.json({ ok: true, data: evals });
|
|
743
747
|
});
|
|
744
|
-
|
|
748
|
+
app6.get("/evals/history", async (c) => {
|
|
745
749
|
const runtime = c.get("runtime");
|
|
746
750
|
const history = await runtime.getEvalHistory();
|
|
747
751
|
return c.json({ ok: true, data: history });
|
|
748
752
|
});
|
|
749
|
-
|
|
753
|
+
app6.delete("/evals/history/:id", async (c) => {
|
|
754
|
+
const runtime = c.get("runtime");
|
|
755
|
+
const id = c.req.param("id");
|
|
756
|
+
const deleted = await runtime.deleteEvalResult(id);
|
|
757
|
+
if (!deleted) {
|
|
758
|
+
return c.json(
|
|
759
|
+
{
|
|
760
|
+
ok: false,
|
|
761
|
+
error: { code: "NOT_FOUND", message: `Eval history entry "${id}" not found` }
|
|
762
|
+
},
|
|
763
|
+
404
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
return c.json({ ok: true, data: { id, deleted: true } });
|
|
767
|
+
});
|
|
768
|
+
app6.post("/evals/:name/run", async (c) => {
|
|
750
769
|
if (evalLoader) await evalLoader();
|
|
751
770
|
const runtime = c.get("runtime");
|
|
752
771
|
const name = c.req.param("name");
|
|
@@ -767,9 +786,8 @@ function createEvalRoutes(evalLoader) {
|
|
|
767
786
|
}
|
|
768
787
|
try {
|
|
769
788
|
if (runs > 1) {
|
|
770
|
-
const { randomUUID } = await import("crypto");
|
|
771
789
|
const { aggregateRuns } = await import("@axlsdk/eval");
|
|
772
|
-
const runGroupId = randomUUID();
|
|
790
|
+
const runGroupId = (0, import_node_crypto.randomUUID)();
|
|
773
791
|
const results = [];
|
|
774
792
|
for (let r = 0; r < runs; r++) {
|
|
775
793
|
const result2 = await runtime.runRegisteredEval(name, {
|
|
@@ -791,7 +809,7 @@ function createEvalRoutes(evalLoader) {
|
|
|
791
809
|
return c.json({ ok: false, error: { code: "EVAL_ERROR", message } }, 400);
|
|
792
810
|
}
|
|
793
811
|
});
|
|
794
|
-
|
|
812
|
+
app6.post("/evals/:name/rescore", async (c) => {
|
|
795
813
|
if (evalLoader) await evalLoader();
|
|
796
814
|
const runtime = c.get("runtime");
|
|
797
815
|
const name = c.req.param("name");
|
|
@@ -837,25 +855,146 @@ function createEvalRoutes(evalLoader) {
|
|
|
837
855
|
return c.json({ ok: false, error: { code: "EVAL_ERROR", message } }, 400);
|
|
838
856
|
}
|
|
839
857
|
});
|
|
840
|
-
|
|
858
|
+
app6.post("/evals/compare", async (c) => {
|
|
841
859
|
const runtime = c.get("runtime");
|
|
842
860
|
const body = await c.req.json();
|
|
861
|
+
const validateIdParam = (v, name) => {
|
|
862
|
+
if (typeof v === "string") return v === "" ? `${name} must be non-empty` : null;
|
|
863
|
+
if (Array.isArray(v)) {
|
|
864
|
+
if (v.length === 0) return `${name} must be a non-empty array`;
|
|
865
|
+
for (const elem of v) {
|
|
866
|
+
if (typeof elem !== "string" || elem === "") {
|
|
867
|
+
return `${name} array must contain only non-empty strings`;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
return null;
|
|
871
|
+
}
|
|
872
|
+
return `${name} is required (string or string[])`;
|
|
873
|
+
};
|
|
874
|
+
const baselineErr = validateIdParam(body.baselineId, "baselineId");
|
|
875
|
+
const candidateErr = validateIdParam(body.candidateId, "candidateId");
|
|
876
|
+
if (baselineErr || candidateErr) {
|
|
877
|
+
return c.json(
|
|
878
|
+
{
|
|
879
|
+
ok: false,
|
|
880
|
+
error: {
|
|
881
|
+
code: "BAD_REQUEST",
|
|
882
|
+
message: [baselineErr, candidateErr].filter(Boolean).join("; ")
|
|
883
|
+
}
|
|
884
|
+
},
|
|
885
|
+
400
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
const history = await runtime.getEvalHistory();
|
|
889
|
+
const byId = new Map(history.map((h) => [h.id, h.data]));
|
|
890
|
+
const missing = [];
|
|
891
|
+
const resolveOne = (id) => {
|
|
892
|
+
const data = byId.get(id);
|
|
893
|
+
if (!data) missing.push(id);
|
|
894
|
+
return data;
|
|
895
|
+
};
|
|
896
|
+
const resolveSelection = (idOrIds) => {
|
|
897
|
+
if (Array.isArray(idOrIds)) {
|
|
898
|
+
const unique = Array.from(new Set(idOrIds));
|
|
899
|
+
if (unique.length === 1) return resolveOne(unique[0]);
|
|
900
|
+
const results = [];
|
|
901
|
+
for (const id of unique) {
|
|
902
|
+
const data = resolveOne(id);
|
|
903
|
+
if (data) results.push(data);
|
|
904
|
+
}
|
|
905
|
+
return results;
|
|
906
|
+
}
|
|
907
|
+
return resolveOne(idOrIds);
|
|
908
|
+
};
|
|
909
|
+
const baseline = resolveSelection(body.baselineId);
|
|
910
|
+
const candidate = resolveSelection(body.candidateId);
|
|
911
|
+
if (missing.length > 0) {
|
|
912
|
+
return c.json(
|
|
913
|
+
{
|
|
914
|
+
ok: false,
|
|
915
|
+
error: {
|
|
916
|
+
code: "NOT_FOUND",
|
|
917
|
+
message: `Eval result(s) not found in history: ${missing.join(", ")}`
|
|
918
|
+
}
|
|
919
|
+
},
|
|
920
|
+
404
|
|
921
|
+
);
|
|
922
|
+
}
|
|
843
923
|
try {
|
|
844
|
-
const result = await runtime.evalCompare(
|
|
924
|
+
const result = await runtime.evalCompare(baseline, candidate, body.options);
|
|
845
925
|
return c.json({ ok: true, data: result });
|
|
846
926
|
} catch (err) {
|
|
847
927
|
const message = err instanceof Error ? err.message : String(err);
|
|
848
|
-
return c.json({ ok: false, error: { code: "
|
|
928
|
+
return c.json({ ok: false, error: { code: "COMPARE_FAILED", message } }, 400);
|
|
849
929
|
}
|
|
850
930
|
});
|
|
851
|
-
|
|
931
|
+
app6.post("/evals/import", async (c) => {
|
|
932
|
+
const runtime = c.get("runtime");
|
|
933
|
+
const body = await c.req.json();
|
|
934
|
+
const bad = (message) => c.json({ ok: false, error: { code: "BAD_REQUEST", message } }, 400);
|
|
935
|
+
if (!body.result || typeof body.result !== "object") {
|
|
936
|
+
return bad("result is required");
|
|
937
|
+
}
|
|
938
|
+
const result = body.result;
|
|
939
|
+
if (!Array.isArray(result.items)) {
|
|
940
|
+
return bad("result.items must be an array");
|
|
941
|
+
}
|
|
942
|
+
if (typeof result.summary !== "object" || result.summary == null) {
|
|
943
|
+
return bad("result.summary must be an object");
|
|
944
|
+
}
|
|
945
|
+
if (typeof result.dataset !== "string" || !result.dataset) {
|
|
946
|
+
return bad("result.dataset must be a non-empty string (required for compare)");
|
|
947
|
+
}
|
|
948
|
+
const summary = result.summary;
|
|
949
|
+
if (typeof summary.scorers !== "object" || summary.scorers == null) {
|
|
950
|
+
return bad("result.summary.scorers must be an object");
|
|
951
|
+
}
|
|
952
|
+
const summaryScorerNames = Object.keys(summary.scorers);
|
|
953
|
+
const items = result.items;
|
|
954
|
+
const summaryScorerSet = new Set(summaryScorerNames);
|
|
955
|
+
const uncoveredAcrossItems = /* @__PURE__ */ new Set();
|
|
956
|
+
for (const item of items) {
|
|
957
|
+
const itemScores = item?.scores;
|
|
958
|
+
if (itemScores && typeof itemScores === "object") {
|
|
959
|
+
for (const name of Object.keys(itemScores)) {
|
|
960
|
+
if (!summaryScorerSet.has(name)) uncoveredAcrossItems.add(name);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
if (uncoveredAcrossItems.size > 0) {
|
|
965
|
+
return bad(
|
|
966
|
+
`item scores reference scorer(s) not in summary.scorers: ${[...uncoveredAcrossItems].join(", ")}`
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
const trim = (v) => typeof v === "string" && v.trim() !== "" ? v.trim() : void 0;
|
|
970
|
+
const metadataObj = typeof result.metadata === "object" && result.metadata != null ? result.metadata : {};
|
|
971
|
+
const workflowsFromMeta = Array.isArray(metadataObj.workflows) ? metadataObj.workflows : [];
|
|
972
|
+
const primaryWorkflow = workflowsFromMeta.find((w) => typeof w === "string");
|
|
973
|
+
const evalName = trim(body.eval) ?? trim(primaryWorkflow) ?? // Legacy fallback: pre-0.14 CLI artifacts had workflow at the top level.
|
|
974
|
+
trim(result.workflow) ?? "imported";
|
|
975
|
+
const id = (0, import_node_crypto.randomUUID)();
|
|
976
|
+
const timestamp = Date.now();
|
|
977
|
+
const imported = {
|
|
978
|
+
...result,
|
|
979
|
+
id,
|
|
980
|
+
metadata: typeof result.metadata === "object" && result.metadata != null ? result.metadata : {}
|
|
981
|
+
};
|
|
982
|
+
await runtime.saveEvalResult({
|
|
983
|
+
id,
|
|
984
|
+
eval: evalName,
|
|
985
|
+
timestamp,
|
|
986
|
+
data: imported
|
|
987
|
+
});
|
|
988
|
+
return c.json({ ok: true, data: { id, eval: evalName, timestamp } });
|
|
989
|
+
});
|
|
990
|
+
return app6;
|
|
852
991
|
}
|
|
853
992
|
|
|
854
993
|
// src/server/routes/playground.ts
|
|
855
994
|
var import_hono11 = require("hono");
|
|
856
995
|
function createPlaygroundRoutes(connMgr) {
|
|
857
|
-
const
|
|
858
|
-
|
|
996
|
+
const app6 = new import_hono11.Hono();
|
|
997
|
+
app6.post("/playground/chat", async (c) => {
|
|
859
998
|
const runtime = c.get("runtime");
|
|
860
999
|
const body = await c.req.json();
|
|
861
1000
|
if (!body.message || typeof body.message !== "string" || !body.message.trim()) {
|
|
@@ -917,42 +1056,45 @@ function createPlaygroundRoutes(connMgr) {
|
|
|
917
1056
|
data: { sessionId, executionId, streaming: true }
|
|
918
1057
|
});
|
|
919
1058
|
});
|
|
920
|
-
return
|
|
1059
|
+
return app6;
|
|
921
1060
|
}
|
|
922
1061
|
|
|
923
1062
|
// src/server/index.ts
|
|
924
1063
|
function createServer(options) {
|
|
925
1064
|
const { runtime, staticRoot, basePath = "", readOnly = false } = options;
|
|
926
|
-
const
|
|
1065
|
+
const app6 = new import_hono12.Hono();
|
|
927
1066
|
const connMgr = new ConnectionManager();
|
|
928
1067
|
const costAggregator = new CostAggregator(connMgr);
|
|
929
1068
|
if (options.cors !== false) {
|
|
930
|
-
|
|
1069
|
+
app6.use("*", (0, import_cors.cors)());
|
|
931
1070
|
}
|
|
932
|
-
|
|
933
|
-
|
|
1071
|
+
app6.use("*", errorHandler);
|
|
1072
|
+
app6.use("*", async (c, next) => {
|
|
934
1073
|
c.set("runtime", runtime);
|
|
935
1074
|
await next();
|
|
936
1075
|
});
|
|
937
1076
|
if (readOnly) {
|
|
938
1077
|
const blocked = [
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1078
|
+
/^POST \/api\/workflows(\/|$)/,
|
|
1079
|
+
/^POST \/api\/executions(\/|$)/,
|
|
1080
|
+
/^POST \/api\/sessions(\/|$)/,
|
|
1081
|
+
/^DELETE \/api\/sessions(\/|$)/,
|
|
1082
|
+
/^PUT \/api\/memory(\/|$)/,
|
|
1083
|
+
/^DELETE \/api\/memory(\/|$)/,
|
|
1084
|
+
/^POST \/api\/decisions(\/|$)/,
|
|
1085
|
+
/^POST \/api\/costs(\/|$)/,
|
|
1086
|
+
/^POST \/api\/tools(\/|$)/,
|
|
1087
|
+
/^POST \/api\/evals\/import$/,
|
|
1088
|
+
/^POST \/api\/evals\/[^/]+\/run$/,
|
|
1089
|
+
/^POST \/api\/evals\/[^/]+\/rescore$/,
|
|
1090
|
+
/^DELETE \/api\/evals\/history\/[^/]+$/,
|
|
1091
|
+
/^POST \/api\/playground(\/|$)/
|
|
950
1092
|
];
|
|
951
|
-
|
|
1093
|
+
app6.use("/api/*", async (c, next) => {
|
|
952
1094
|
const apiIdx = c.req.path.indexOf("/api/");
|
|
953
1095
|
const apiPath = apiIdx >= 0 ? c.req.path.slice(apiIdx) : c.req.path;
|
|
954
1096
|
const key = `${c.req.method} ${apiPath}`;
|
|
955
|
-
if (blocked.some((
|
|
1097
|
+
if (blocked.some((re) => re.test(key))) {
|
|
956
1098
|
return c.json(
|
|
957
1099
|
{
|
|
958
1100
|
ok: false,
|
|
@@ -965,7 +1107,7 @@ function createServer(options) {
|
|
|
965
1107
|
});
|
|
966
1108
|
}
|
|
967
1109
|
const api = new import_hono12.Hono();
|
|
968
|
-
api.route("/",
|
|
1110
|
+
api.route("/", createHealthRoutes(readOnly));
|
|
969
1111
|
api.route("/", createWorkflowRoutes(connMgr));
|
|
970
1112
|
api.route("/", executions_default);
|
|
971
1113
|
api.route("/", createSessionRoutes(connMgr));
|
|
@@ -976,7 +1118,7 @@ function createServer(options) {
|
|
|
976
1118
|
api.route("/", createCostRoutes(costAggregator));
|
|
977
1119
|
api.route("/", createEvalRoutes(options.evalLoader));
|
|
978
1120
|
api.route("/", createPlaygroundRoutes(connMgr));
|
|
979
|
-
|
|
1121
|
+
app6.route("/api", api);
|
|
980
1122
|
const traceListener = (event) => {
|
|
981
1123
|
const traceEvent = event;
|
|
982
1124
|
if (traceEvent.executionId) {
|
|
@@ -1017,7 +1159,7 @@ function createServer(options) {
|
|
|
1017
1159
|
root: staticRoot,
|
|
1018
1160
|
rewriteRequestPath: basePath ? (path) => path.startsWith(basePath) ? path.slice(basePath.length) || "/" : path : void 0
|
|
1019
1161
|
});
|
|
1020
|
-
|
|
1162
|
+
app6.use("/*", async (c, next) => {
|
|
1021
1163
|
const reqPath = c.req.path;
|
|
1022
1164
|
const resolved = basePath && reqPath.startsWith(basePath) ? reqPath.slice(basePath.length) || "/" : reqPath;
|
|
1023
1165
|
if (resolved === "/" || resolved === "/index.html" || resolved === "/ws") {
|
|
@@ -1026,7 +1168,7 @@ function createServer(options) {
|
|
|
1026
1168
|
return staticHandler(c, next);
|
|
1027
1169
|
});
|
|
1028
1170
|
if (spaHtml) {
|
|
1029
|
-
|
|
1171
|
+
app6.get("*", async (c, next) => {
|
|
1030
1172
|
const resolved = basePath && c.req.path.startsWith(basePath) ? c.req.path.slice(basePath.length) || "/" : c.req.path;
|
|
1031
1173
|
if (resolved === "/ws") return next();
|
|
1032
1174
|
return c.html(spaHtml);
|
|
@@ -1034,7 +1176,7 @@ function createServer(options) {
|
|
|
1034
1176
|
}
|
|
1035
1177
|
}
|
|
1036
1178
|
return {
|
|
1037
|
-
app:
|
|
1179
|
+
app: app6,
|
|
1038
1180
|
connMgr,
|
|
1039
1181
|
costAggregator,
|
|
1040
1182
|
/** Create WS handlers. Call before registering static/SPA routes are reached. */
|
|
@@ -1072,6 +1214,7 @@ function parseArgs(argv) {
|
|
|
1072
1214
|
let open = false;
|
|
1073
1215
|
let help = false;
|
|
1074
1216
|
let conditions = [];
|
|
1217
|
+
let readOnly = false;
|
|
1075
1218
|
for (let i = 2; i < argv.length; i++) {
|
|
1076
1219
|
const arg = argv[i];
|
|
1077
1220
|
if (arg === "--port" && argv[i + 1]) {
|
|
@@ -1085,11 +1228,13 @@ function parseArgs(argv) {
|
|
|
1085
1228
|
i++;
|
|
1086
1229
|
} else if (arg === "--open") {
|
|
1087
1230
|
open = true;
|
|
1231
|
+
} else if (arg === "--read-only" || arg === "--readonly") {
|
|
1232
|
+
readOnly = true;
|
|
1088
1233
|
} else if (arg === "--help" || arg === "-h") {
|
|
1089
1234
|
help = true;
|
|
1090
1235
|
}
|
|
1091
1236
|
}
|
|
1092
|
-
const result = { port, config, open, help, conditions };
|
|
1237
|
+
const result = { port, config, open, help, conditions, readOnly };
|
|
1093
1238
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
1094
1239
|
result.portError = `Invalid port: ${port}. Must be between 1 and 65535.`;
|
|
1095
1240
|
}
|
|
@@ -1134,6 +1279,7 @@ Options:
|
|
|
1134
1279
|
--port <number> Server port (default: 4400)
|
|
1135
1280
|
--config <path> Path to config file (default: auto-detect)
|
|
1136
1281
|
--conditions <list> Comma-separated Node.js import conditions (e.g., development)
|
|
1282
|
+
--read-only Disable all mutating endpoints (runs, imports, rescore, etc)
|
|
1137
1283
|
--open Auto-open browser
|
|
1138
1284
|
-h, --help Show this help message
|
|
1139
1285
|
|
|
@@ -1220,19 +1366,23 @@ Tip: Use .mts for configs with top-level await or in projects without "type": "m
|
|
|
1220
1366
|
}
|
|
1221
1367
|
const staticRoot = (0, import_node_path3.resolve)(import_meta.dirname ?? __dirname, "client");
|
|
1222
1368
|
const hasStaticAssets = (0, import_node_fs3.existsSync)((0, import_node_path3.resolve)(staticRoot, "index.html"));
|
|
1223
|
-
const { app:
|
|
1369
|
+
const { app: app6, createWsHandlers: createWsHandlers2 } = createServer({
|
|
1224
1370
|
runtime,
|
|
1225
|
-
staticRoot: hasStaticAssets ? staticRoot : void 0
|
|
1371
|
+
staticRoot: hasStaticAssets ? staticRoot : void 0,
|
|
1372
|
+
readOnly: args.readOnly
|
|
1226
1373
|
});
|
|
1227
|
-
|
|
1374
|
+
if (args.readOnly) {
|
|
1375
|
+
console.log("[axl-studio] Read-only mode enabled \u2014 mutating endpoints are disabled.");
|
|
1376
|
+
}
|
|
1377
|
+
const { injectWebSocket, upgradeWebSocket } = (0, import_node_ws.createNodeWebSocket)({ app: app6 });
|
|
1228
1378
|
const wsHandlers = createWsHandlers2();
|
|
1229
|
-
|
|
1379
|
+
app6.get(
|
|
1230
1380
|
"/ws",
|
|
1231
1381
|
upgradeWebSocket(() => wsHandlers)
|
|
1232
1382
|
);
|
|
1233
1383
|
const server = (0, import_node_server.serve)(
|
|
1234
1384
|
{
|
|
1235
|
-
fetch:
|
|
1385
|
+
fetch: app6.fetch,
|
|
1236
1386
|
port: args.port
|
|
1237
1387
|
},
|
|
1238
1388
|
(info) => {
|