@axlsdk/studio 0.19.1 → 0.20.1
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 +17 -3
- package/dist/{chunk-AYUKXMYW.js → chunk-KQ3HBRTC.js} +86 -42
- package/dist/chunk-KQ3HBRTC.js.map +1 -0
- package/dist/cli.cjs +84 -40
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/client/assets/index-C8R_CZcW.css +1 -0
- package/dist/client/assets/index-Dq8QQtXe.js +313 -0
- package/dist/client/index.html +2 -2
- package/dist/middleware.cjs +84 -40
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.js +1 -1
- package/dist/server/index.cjs +84 -40
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +14 -4
- package/dist/server/index.d.ts +14 -4
- package/dist/server/index.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-AYUKXMYW.js.map +0 -1
- package/dist/client/assets/index-7Nf4lAQm.js +0 -313
- package/dist/client/assets/index-CxBvTZU2.css +0 -1
package/README.md
CHANGED
|
@@ -89,7 +89,9 @@ The `--conditions` flag is useful in monorepos where workspace packages use the
|
|
|
89
89
|
|
|
90
90
|
## Panels
|
|
91
91
|
|
|
92
|
-
Eight panels, all live over WebSocket. The
|
|
92
|
+
Eight panels, all live over WebSocket. The captures below use representative seeded
|
|
93
|
+
runs; see [`docs/assets/CAPTURE.md`](../../docs/assets/CAPTURE.md) for how to regenerate
|
|
94
|
+
them.
|
|
93
95
|
|
|
94
96
|
### Agent Playground
|
|
95
97
|
|
|
@@ -101,7 +103,12 @@ Chat with any registered agent in real time. Streaming tokens, tool calls with e
|
|
|
101
103
|
|
|
102
104
|
### Trace Explorer
|
|
103
105
|
|
|
104
|
-
Waterfall visualization of execution traces. Filter by type, agent, or tool; see token
|
|
106
|
+
Waterfall visualization of execution traces. Filter by type, agent, or tool; see token
|
|
107
|
+
counts, cost per step, and duration. Tool rows distinguish calls that succeeded,
|
|
108
|
+
failed, were denied, were cancelled, or were rejected before they started. Studio also
|
|
109
|
+
keeps older trace history readable and identifies incomplete runs instead of presenting
|
|
110
|
+
missing events as a complete story. The Stats view shows the event-type distribution,
|
|
111
|
+
top tools, and retry stacks.
|
|
105
112
|
|
|
106
113
|
> **Studio vs `ctx.events`.** Studio consumes the same `AxlEvent` firehose via `runtime.on('trace', …)` — every event from every execution. Inside a workflow handler, `ctx.events` is the in-handler counterpart (per-context, scoped to the current workflow). The two coexist: Studio is for cross-execution observability and replay; `ctx.events` is for in-handler streaming UIs. See [`docs/observability.md`](../../docs/observability.md#observation-paths).
|
|
107
114
|
|
|
@@ -115,7 +122,14 @@ Track spending across agents, models, workflows, and embedders with time-window
|
|
|
115
122
|
|
|
116
123
|
### Eval Runner
|
|
117
124
|
|
|
118
|
-
Run evaluations from the UI, watch items stream in, and drill into per-item scores,
|
|
125
|
+
Run evaluations from the UI, watch items stream in, and drill into per-item scores,
|
|
126
|
+
timing, cost, and LLM-judge reasoning. Compare two runs (baseline vs candidate) with
|
|
127
|
+
bootstrap-CI significance, a score-distribution chart, and an item-level diff table.
|
|
128
|
+
The History tab groups multi-run results and tracks mean scores across runs. Toggle
|
|
129
|
+
**Capture traces** to render each item's events inline. For tool-using workflows, those
|
|
130
|
+
events show whether a call failed, was denied, was cancelled, or never started, giving
|
|
131
|
+
you better evidence for debugging and custom scorers. Studio does not turn those states
|
|
132
|
+
into scores automatically. Requires `@axlsdk/eval` as an optional peer dependency.
|
|
119
133
|
|
|
120
134
|
Amber banners flag runs you shouldn't fully trust — a scorer that failed on too many items, a subset run, or annotations dropped by the dataset schema — so a thinned or misconfigured run can't quietly look clean.
|
|
121
135
|
|
|
@@ -12,15 +12,14 @@ import { cors } from "hono/cors";
|
|
|
12
12
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
13
13
|
|
|
14
14
|
// src/server/redact.ts
|
|
15
|
-
import {
|
|
15
|
+
import { redactHistoricalEvent } from "@axlsdk/axl";
|
|
16
16
|
var REDACTED = "[redacted]";
|
|
17
17
|
var SAFE_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
18
18
|
"QuorumNotMet",
|
|
19
19
|
"NoConsensus",
|
|
20
20
|
"TimeoutError",
|
|
21
21
|
"MaxTurnsError",
|
|
22
|
-
"BudgetExceededError"
|
|
23
|
-
"ToolDenied"
|
|
22
|
+
"BudgetExceededError"
|
|
24
23
|
]);
|
|
25
24
|
function redactErrorMessage(err, redact) {
|
|
26
25
|
const raw = err instanceof Error ? err.message : String(err);
|
|
@@ -88,7 +87,7 @@ function redactSessionHistory(history, redact) {
|
|
|
88
87
|
}
|
|
89
88
|
function redactStreamEvent(event, redact) {
|
|
90
89
|
if (!redact) return event;
|
|
91
|
-
return
|
|
90
|
+
return redactHistoricalEvent(event);
|
|
92
91
|
}
|
|
93
92
|
function redactEvalItem(item) {
|
|
94
93
|
const scrubbed = {
|
|
@@ -151,31 +150,29 @@ function redactPendingDecisionList(decisions, redact) {
|
|
|
151
150
|
}
|
|
152
151
|
|
|
153
152
|
// src/server/middleware/error-handler.ts
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
status = 400;
|
|
170
|
-
}
|
|
171
|
-
const runtime = c.get("runtime");
|
|
172
|
-
const redactOn = runtime?.isRedactEnabled?.() ?? false;
|
|
173
|
-
const body = {
|
|
174
|
-
ok: false,
|
|
175
|
-
error: { code, message: redactErrorMessage(err, redactOn) }
|
|
176
|
-
};
|
|
177
|
-
return c.json(body, status);
|
|
153
|
+
function errorHandler(err, c) {
|
|
154
|
+
const rawMessage = err.message;
|
|
155
|
+
const code = err.code ?? "INTERNAL_ERROR";
|
|
156
|
+
let status = 500;
|
|
157
|
+
if ("status" in err) {
|
|
158
|
+
const errStatus = err.status;
|
|
159
|
+
if (typeof errStatus === "number" && errStatus >= 400 && errStatus < 600) {
|
|
160
|
+
status = errStatus;
|
|
161
|
+
}
|
|
162
|
+
} else if (code === "CROSS_PROCESS_RESUME_UNSUPPORTED") {
|
|
163
|
+
status = 409;
|
|
164
|
+
} else if (code === "NOT_FOUND" || code === "PENDING_DECISION_NOT_FOUND" || rawMessage.includes("not found") || rawMessage.includes("not registered")) {
|
|
165
|
+
status = 404;
|
|
166
|
+
} else if (code === "VALIDATION_ERROR" || code === "INVALID_HUMAN_DECISION" || rawMessage.includes("Expected") || rawMessage.includes("invalid")) {
|
|
167
|
+
status = 400;
|
|
178
168
|
}
|
|
169
|
+
const runtime = c.get("runtime");
|
|
170
|
+
const redactOn = runtime?.isRedactEnabled?.() ?? false;
|
|
171
|
+
const body = {
|
|
172
|
+
ok: false,
|
|
173
|
+
error: { code, message: redactErrorMessage(err, redactOn) }
|
|
174
|
+
};
|
|
175
|
+
return c.json(body, status);
|
|
179
176
|
}
|
|
180
177
|
|
|
181
178
|
// src/server/ws/connection-manager.ts
|
|
@@ -1091,19 +1088,58 @@ function reduceTraceStats(acc, event) {
|
|
|
1091
1088
|
const eventTypeCounts = { ...acc.eventTypeCounts };
|
|
1092
1089
|
eventTypeCounts[event.type] = (eventTypeCounts[event.type] ?? 0) + 1;
|
|
1093
1090
|
const byTool = { ...acc.byTool };
|
|
1094
|
-
if (event.type === "tool_call_end" || event.type === "tool_denied" || event.type === "tool_approval") {
|
|
1091
|
+
if (event.type === "tool_call_start" || event.type === "tool_call_end" || event.type === "tool_call_rejected" || event.type === "tool_denied" || event.type === "tool_approval") {
|
|
1095
1092
|
const toolName = event.tool;
|
|
1096
|
-
const prev = byTool[toolName] ?? {
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1093
|
+
const prev = byTool[toolName] ?? {
|
|
1094
|
+
accepted: 0,
|
|
1095
|
+
succeeded: 0,
|
|
1096
|
+
failed: 0,
|
|
1097
|
+
failedByPhase: {},
|
|
1098
|
+
denied: 0,
|
|
1099
|
+
cancelled: 0,
|
|
1100
|
+
rejected: 0,
|
|
1101
|
+
approved: 0,
|
|
1102
|
+
legacy: { calls: 0, denied: 0, approved: 0 }
|
|
1103
|
+
};
|
|
1104
|
+
const next = {
|
|
1105
|
+
...prev,
|
|
1106
|
+
failedByPhase: { ...prev.failedByPhase },
|
|
1107
|
+
legacy: { ...prev.legacy }
|
|
1106
1108
|
};
|
|
1109
|
+
if (event.schemaVersion === 2) {
|
|
1110
|
+
if (event.type === "tool_call_start") next.accepted++;
|
|
1111
|
+
if (event.type === "tool_call_rejected") next.rejected++;
|
|
1112
|
+
if (event.type === "tool_approval" && event.data?.approved) next.approved++;
|
|
1113
|
+
if (event.type === "tool_call_end") {
|
|
1114
|
+
switch (event.data.outcome.status) {
|
|
1115
|
+
case "succeeded":
|
|
1116
|
+
next.succeeded++;
|
|
1117
|
+
break;
|
|
1118
|
+
case "failed": {
|
|
1119
|
+
next.failed++;
|
|
1120
|
+
const phase = event.data.outcome.failure.phase;
|
|
1121
|
+
next.failedByPhase[phase] = (next.failedByPhase[phase] ?? 0) + 1;
|
|
1122
|
+
break;
|
|
1123
|
+
}
|
|
1124
|
+
case "denied":
|
|
1125
|
+
next.denied++;
|
|
1126
|
+
break;
|
|
1127
|
+
case "cancelled":
|
|
1128
|
+
next.cancelled++;
|
|
1129
|
+
break;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
} else if (event.type === "tool_call_end") {
|
|
1133
|
+
next.legacy.calls++;
|
|
1134
|
+
} else if (event.type === "tool_denied") {
|
|
1135
|
+
const approved = event.data?.approved === true;
|
|
1136
|
+
if (approved) next.legacy.approved++;
|
|
1137
|
+
else next.legacy.denied++;
|
|
1138
|
+
} else if (event.type === "tool_approval") {
|
|
1139
|
+
if (event.data?.approved === true) next.legacy.approved++;
|
|
1140
|
+
else if (event.data?.approved === false) next.legacy.denied++;
|
|
1141
|
+
}
|
|
1142
|
+
byTool[toolName] = next;
|
|
1107
1143
|
}
|
|
1108
1144
|
const retryByAgent = { ...acc.retryByAgent };
|
|
1109
1145
|
if (event.agent && event.type === "agent_call_end") {
|
|
@@ -1583,7 +1619,14 @@ app4.get("/decisions", async (c) => {
|
|
|
1583
1619
|
app4.post("/decisions/:executionId/resolve", async (c) => {
|
|
1584
1620
|
const runtime = c.get("runtime");
|
|
1585
1621
|
const executionId = c.req.param("executionId");
|
|
1586
|
-
|
|
1622
|
+
let body;
|
|
1623
|
+
try {
|
|
1624
|
+
body = await c.req.json();
|
|
1625
|
+
} catch {
|
|
1626
|
+
const error48 = new Error("Invalid JSON request body");
|
|
1627
|
+
Object.assign(error48, { code: "INVALID_HUMAN_DECISION", status: 400 });
|
|
1628
|
+
throw error48;
|
|
1629
|
+
}
|
|
1587
1630
|
await runtime.resolveDecision(executionId, body);
|
|
1588
1631
|
return c.json({ ok: true, data: { resolved: true } });
|
|
1589
1632
|
});
|
|
@@ -15923,6 +15966,7 @@ function createPlaygroundRoutes(connMgr) {
|
|
|
15923
15966
|
(async () => {
|
|
15924
15967
|
let stepCounter = Number.MAX_SAFE_INTEGER - 1;
|
|
15925
15968
|
const terminalFields = () => ({
|
|
15969
|
+
schemaVersion: 2,
|
|
15926
15970
|
executionId,
|
|
15927
15971
|
step: stepCounter++,
|
|
15928
15972
|
timestamp: Date.now()
|
|
@@ -16039,7 +16083,7 @@ function createServer(options) {
|
|
|
16039
16083
|
if (options.cors !== false) {
|
|
16040
16084
|
app5.use("*", cors());
|
|
16041
16085
|
}
|
|
16042
|
-
app5.
|
|
16086
|
+
app5.onError(errorHandler);
|
|
16043
16087
|
app5.use("*", async (c, next) => {
|
|
16044
16088
|
c.set("runtime", runtime);
|
|
16045
16089
|
await next();
|
|
@@ -16195,4 +16239,4 @@ export {
|
|
|
16195
16239
|
EvalAggregator,
|
|
16196
16240
|
createServer
|
|
16197
16241
|
};
|
|
16198
|
-
//# sourceMappingURL=chunk-
|
|
16242
|
+
//# sourceMappingURL=chunk-KQ3HBRTC.js.map
|