@axlsdk/studio 0.16.1 → 0.17.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 +3 -3
- package/dist/{chunk-RE6VPUXA.js → chunk-GADFO7DZ.js} +159 -71
- package/dist/chunk-GADFO7DZ.js.map +1 -0
- package/dist/cli.cjs +173 -126
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +36 -10
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/index-C3yGF34O.js +313 -0
- package/dist/client/assets/index-DNRVA4F2.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/middleware.cjs +205 -174
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.js +37 -67
- package/dist/middleware.js.map +1 -1
- package/dist/server/index.cjs +158 -70
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +13 -0
- package/dist/server/index.d.ts +13 -0
- package/dist/server/index.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-JGQ3MSIG.js +0 -80
- package/dist/chunk-JGQ3MSIG.js.map +0 -1
- package/dist/chunk-RE6VPUXA.js.map +0 -1
- package/dist/client/assets/index-BzQe3w-R.js +0 -313
- package/dist/client/assets/index-C2nTRFWX.css +0 -1
package/dist/middleware.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware.ts","../src/server/index.ts","../src/server/redact.ts","../src/server/middleware/error-handler.ts","../src/server/ws/connection-manager.ts","../src/server/ws/protocol.ts","../src/server/ws/handler.ts","../src/server/aggregates/aggregate-snapshots.ts","../src/server/aggregates/trace-aggregator.ts","../src/server/aggregates/execution-aggregator.ts","../src/server/aggregates/eval-aggregator.ts","../src/server/aggregates/reducers.ts","../src/server/routes/health.ts","../src/server/routes/workflows.ts","../src/server/routes/executions.ts","../src/server/routes/sessions.ts","../src/server/routes/agents.ts","../src/server/routes/tools.ts","../src/server/routes/memory.ts","../src/server/routes/decisions.ts","../src/server/routes/costs.ts","../src/server/routes/evals.ts","../src/server/routes/playground.ts","../src/server/routes/eval-trends.ts","../src/server/routes/workflow-stats.ts","../src/server/routes/trace-stats.ts","../src/eval-loader.ts","../src/cli-utils.ts"],"sourcesContent":["import { resolve, dirname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { getRequestListener } from '@hono/node-server';\nimport { WebSocketServer } from 'ws';\nimport { createServer } from './server/index.js';\nimport { handleWsMessage } from './server/ws/protocol.js';\nimport { createEvalLoader } from './eval-loader.js';\nimport type { EvalLoaderConfig } from './eval-loader.js';\nimport type { BufferCaps } from './server/ws/connection-manager.js';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport type { IncomingMessage, ServerResponse, Server } from 'node:http';\n\nexport type { EvalLoaderConfig } from './eval-loader.js';\nexport type { BufferCaps } from './server/ws/connection-manager.js';\n\nexport type StudioMiddlewareOptions = {\n /** The AxlRuntime instance to observe and control. */\n runtime: AxlRuntime;\n\n /**\n * URL path prefix where Studio is mounted.\n * Must match the mount path in your framework (Express `app.use()`,\n * Fastify `register()`, Hono `app.route()`, etc.). The framework is\n * expected to strip the prefix from `req.url` before calling the handler.\n *\n * Do not set basePath when using a raw `http.Server` as the root handler —\n * leave it empty and mount at root instead.\n *\n * Must start with '/' when non-empty. Trailing slashes are stripped.\n * Only URL-safe characters allowed: [a-zA-Z0-9/_-]\n *\n * @example '/studio'\n * @example '/admin/studio'\n * @example '' — mounted at root (default)\n */\n basePath?: string;\n\n /**\n * Serve the pre-built Studio SPA.\n * Set to false if serving the client from a CDN or separate build.\n * @default true\n */\n serveClient?: boolean;\n\n /**\n * Verify a WebSocket upgrade request before completing the handshake.\n *\n * Return either a boolean (`true` allow, `false` reject) or an object\n * `{ allowed: boolean, metadata?: unknown }` to ALSO attach per-connection\n * metadata that `filterTraceEvent` can later read — typically the auth\n * subject (userId, tenantId, role). Throw to reject with an error.\n *\n * IMPORTANT: WebSocket upgrades bypass Express/Fastify/Koa middleware.\n * If your HTTP routes are behind auth middleware, WS connections are NOT\n * automatically protected. Use this callback to enforce authentication\n * on WebSocket connections.\n *\n * @example Multi-tenant: extract tenant from JWT, attach as metadata\n * verifyUpgrade: async (req) => {\n * const token = req.headers.authorization?.slice(7);\n * const claims = await verifyJwt(token);\n * if (!claims) return false;\n * return { allowed: true, metadata: { userId: claims.sub, tenantId: claims.tid } };\n * }\n */\n verifyUpgrade?: (\n req: IncomingMessage,\n ) =>\n | boolean\n | { allowed: boolean; metadata?: unknown }\n | Promise<boolean | { allowed: boolean; metadata?: unknown }>;\n\n /**\n * Optional per-event filter used by multi-tenant deployments to scope the\n * trace firehose. Called on every outbound WebSocket broadcast; return\n * `true` to deliver to this connection, `false` to drop.\n *\n * `event` is the parsed event payload — for the `trace:*` channel this is\n * an `AxlEvent` from `@axlsdk/axl` (narrow via the discriminated union);\n * for `costs` it's a `CostData`; for `execution:*` / `eval:*` it's the\n * legacy stream-event shape (until PR 3 collapses the wire to `AxlEvent`).\n * Typed `unknown` because the filter runs for every channel.\n * `metadata` is the per-connection metadata attached by `verifyUpgrade`,\n * or `undefined` if `verifyUpgrade` returned a bare boolean.\n *\n * Filter errors are treated as `drop` (fail-closed) so a buggy predicate\n * cannot accidentally leak events cross-tenant.\n *\n * @example Scope trace events by tenant id stored on agent metadata\n * import type { AxlEvent } from '@axlsdk/axl';\n *\n * filterTraceEvent: (event, meta) => {\n * const m = meta as { tenantId?: string } | undefined;\n * if (!m?.tenantId) return false;\n * const e = event as AxlEvent;\n * // Only narrow event.type === 'agent_call_end' events; pass structural\n * // events (workflow_start/end, cost updates) through unconditionally.\n * if (e.type !== 'agent_call_end') return true;\n * return e.workflow?.startsWith(`${m.tenantId}:`) ?? false;\n * }\n */\n filterTraceEvent?: (event: unknown, metadata: unknown) => boolean;\n\n /**\n * Disable all mutating endpoints (execute, test, send, delete, resolve).\n * When true, Studio is observation-only.\n * @default false\n */\n readOnly?: boolean;\n\n /**\n * Lazy-load eval files for the Eval Runner panel.\n *\n * Eval files are dynamically imported on first access to eval endpoints,\n * not at middleware construction time. This means:\n * - Zero cost during normal API operation\n * - Eval files can import from any module without creating circular deps\n * in the static module graph (they're loaded as standalone entry points)\n * - `@axlsdk/eval` can remain a devDependency — eval files never enter\n * the production bundle since bundlers can't see dynamic imports\n *\n * Accepts glob patterns, explicit file paths, or an object with\n * `conditions` for monorepo source export resolution.\n *\n * Eval files are loaded once and cached for the middleware's lifetime.\n * Changes to eval files require a server restart.\n *\n * @example\n * // Single glob pattern\n * evals: 'evals/*.eval.ts'\n *\n * @example\n * // Multiple patterns\n * evals: ['libs/api/evals/*.eval.ts', 'libs/ai/evals/*.eval.ts']\n *\n * @example\n * // With import conditions for monorepo source exports\n * evals: {\n * files: 'libs/api/evals/*.eval.ts',\n * conditions: ['development'],\n * }\n */\n evals?: EvalLoaderConfig;\n\n /**\n * Override the default WebSocket replay-buffer resource caps for\n * production deployments under sustained execution churn.\n *\n * Defaults: `maxEventsPerBuffer: 1000`, `maxBytesPerBuffer: 4 MiB`,\n * `maxActiveBuffers: 256`. Worst-case memory is roughly\n * `maxActiveBuffers × maxBytesPerBuffer` (≈1 GiB at defaults). Tighten\n * either dimension to lower the ceiling at the cost of late-subscriber\n * replay coverage; raise them if you need more event headroom on long\n * verbose-mode streams.\n *\n * Terminal `done` / `error` events are always buffered regardless of\n * caps, so a late subscriber to a completed stream still sees the\n * outcome — only intermediate non-terminal events are dropped.\n *\n * All fields are optional; passing `{}` is a no-op.\n *\n * @example\n * // Halve memory ceiling on a high-churn deployment\n * bufferCaps: { maxActiveBuffers: 128, maxBytesPerBuffer: 2 * 1024 * 1024 }\n */\n bufferCaps?: BufferCaps;\n};\n\n/**\n * Minimal contract a WebSocket connection must satisfy.\n * Matches the `ws` library API (de facto standard in Node.js).\n */\nexport interface StudioWebSocket {\n send(data: string): void;\n close(): void;\n on(event: 'message', fn: (data: string | Buffer) => void): void;\n on(event: 'close', fn: () => void): void;\n on(event: 'error', fn: (err: Error) => void): void;\n}\n\n// Re-export for Hono-in-Hono consumers\nexport { handleWsMessage } from './server/ws/protocol.js';\n\nexport type StudioMiddleware = ReturnType<typeof createStudioMiddleware>;\n\nexport function createStudioMiddleware(options: StudioMiddlewareOptions) {\n const {\n runtime,\n serveClient = true,\n verifyUpgrade,\n readOnly = false,\n filterTraceEvent,\n } = options;\n\n // Normalize basePath: strip trailing slashes, validate format\n const basePath = normalizeBasePath(options.basePath);\n\n // Resolve pre-built SPA assets from this package's dist/\n const staticRoot = serveClient ? resolveClientDist() : undefined;\n\n if (serveClient && !staticRoot) {\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n console.warn(\n '[axl-studio] serveClient is true but no pre-built client found at ' +\n `${resolve(dir, 'client')}. Studio UI will not be available. ` +\n 'Set serveClient: false to suppress this warning.',\n );\n }\n\n // Create lazy eval loader if eval files are configured\n const evalLoader = options.evals ? createEvalLoader(options.evals, runtime) : undefined;\n\n const { app, connMgr, traceListener, closeActiveRuns, closeAggregators } = createServer({\n runtime,\n staticRoot,\n basePath,\n readOnly,\n cors: false, // Host framework owns CORS policy\n evalLoader,\n bufferCaps: options.bufferCaps,\n });\n\n // Install the broadcast filter once at construction time. The connMgr\n // applies it on every outbound event; `metadata` is attached to each\n // connection after a successful `verifyUpgrade`.\n if (filterTraceEvent) {\n connMgr.setFilter(filterTraceEvent);\n }\n\n // Log production safety warning\n if (process.env.NODE_ENV === 'production' && !verifyUpgrade) {\n console.warn(\n '[axl-studio] WARNING: Studio middleware mounted in production without verifyUpgrade. ' +\n 'WebSocket connections are not authenticated. All registered workflows, tools, and ' +\n 'agents are accessible. See https://axlsdk.com/docs/studio/security',\n );\n }\n\n // Convert Hono app → Node.js (req, res) handler via @hono/node-server.\n // overrideGlobalObjects: false prevents replacing global.Request/Response,\n // which could break the host application.\n const listener = getRequestListener(app.fetch, {\n overrideGlobalObjects: false,\n });\n\n let closed = false;\n\n function handler(req: IncomingMessage, res: ServerResponse) {\n if (closed) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'CLOSED', message: 'Studio middleware has been shut down' },\n }),\n );\n return;\n }\n\n // Express/NestJS/Koa body parsers consume the raw IncomingMessage stream\n // and store the parsed result on req.body. When that happens,\n // @hono/node-server's getRequestListener reads an empty stream and Hono\n // sees no body. To fix this, we re-serialize req.body as req.rawBody —\n // a Buffer that getRequestListener checks before falling back to the\n // stream (see newRequestFromIncoming in @hono/node-server/dist/listener.js).\n //\n // Verified against @hono/node-server@1.19.9. If this breaks after an\n // upgrade, check whether the rawBody instanceof Buffer check still exists\n // in newRequestFromIncoming.\n const reqAny = req as unknown as Record<string, unknown>;\n if (reqAny.body != null && !reqAny.rawBody) {\n try {\n reqAny.rawBody = Buffer.from(JSON.stringify(reqAny.body));\n } catch {\n // Non-serializable body — Hono will see an empty body\n }\n }\n\n listener(req, res).catch((err) => {\n console.error('[axl-studio] Unhandled error in request handler:', err);\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'INTERNAL_ERROR', message: 'Internal server error' },\n }),\n );\n }\n });\n }\n\n // Handle an individual WebSocket using the Studio protocol.\n // Adapts any StudioWebSocket to ConnectionManager's internal BroadcastTarget.\n // `metadata` is whatever `verifyUpgrade` attached — passed through so the\n // `filterTraceEvent` callback can read it on every outbound event.\n function handleWebSocket(ws: StudioWebSocket, metadata?: unknown) {\n if (closed) {\n ws.close();\n return;\n }\n const socket = {\n send: (data: string) => ws.send(data),\n close: () => ws.close(),\n };\n connMgr.add(socket);\n if (metadata !== undefined) {\n connMgr.setMetadata(socket, metadata);\n }\n\n ws.on('message', (raw) => {\n const reply = handleWsMessage(String(raw), socket, connMgr);\n if (reply) ws.send(reply);\n });\n\n ws.on('close', () => connMgr.remove(socket));\n ws.on('error', () => connMgr.remove(socket));\n }\n\n // Internal WebSocketServer — created lazily by upgradeWebSocket()\n let wss: InstanceType<typeof WebSocketServer> | undefined;\n // References for cleanup: the upgrade handler and server it's attached to\n let upgradeHandler: ((...args: any[]) => void) | undefined;\n let serverRef: Server | undefined;\n\n // Convenience: attach WS handling to an http.Server.\n function upgradeWebSocket(server: Server, path?: string) {\n if (wss) {\n throw new Error(\n '[axl-studio] upgradeWebSocket() has already been called. ' +\n 'Call close() first if you need to re-attach.',\n );\n }\n\n const wsPath = path ?? (basePath ? `${basePath}/ws` : '/ws');\n\n wss = new WebSocketServer({ noServer: true });\n serverRef = server;\n\n upgradeHandler = async (req: IncomingMessage, socket: any, head: Buffer) => {\n // Match path, ignoring query string\n const pathname = new URL(req.url!, `http://${req.headers.host}`).pathname;\n if (pathname !== wsPath) return; // Let other upgrade handlers run\n\n // Early-reject if close() already started. This is a cheap pre-check —\n // we repeat it AFTER the async verifyUpgrade resolves to close the race\n // where close() runs while verifyUpgrade is still in flight.\n if (closed) {\n socket.destroy();\n return;\n }\n\n // Apply auth verification and capture optional per-connection metadata\n // (e.g. { userId, tenantId }) that filterTraceEvent can later read.\n let connectionMetadata: unknown;\n if (verifyUpgrade) {\n try {\n const result = await verifyUpgrade(req);\n // Normalize both return shapes: plain boolean or { allowed, metadata }\n const allowed = typeof result === 'boolean' ? result : result.allowed;\n if (!allowed) {\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n if (typeof result === 'object' && result !== null) {\n connectionMetadata = result.metadata;\n }\n } catch {\n socket.write('HTTP/1.1 403 Forbidden\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n }\n\n // Guard against close() having run during async verifyUpgrade. We check\n // BOTH `closed` (set at the top of `close()`) and `!wss` (set at the\n // end). `closed` is the authoritative signal — checking `!wss` alone\n // wouldn't catch the window where `close()` has marked the middleware\n // as shut down but hasn't yet torn down the WebSocketServer. Failing\n // open here would leak a connection past the middleware's lifetime\n // and leave it holding references the host expected to be released.\n if (closed || !wss) {\n socket.destroy();\n return;\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n handleWebSocket(ws, connectionMetadata);\n });\n };\n\n server.on('upgrade', upgradeHandler);\n }\n\n // Cleanup function for lifecycle management.\n function close() {\n closed = true;\n\n // Abort active streaming eval runs before closing connections\n closeActiveRuns();\n\n // Close all WebSocket connections\n connMgr.closeAll();\n\n // Remove the upgrade listener from the server before closing WSS\n if (upgradeHandler && serverRef) {\n serverRef.removeListener('upgrade', upgradeHandler);\n upgradeHandler = undefined;\n serverRef = undefined;\n }\n\n // Shut down the internal WebSocketServer if one was created\n if (wss) {\n wss.close();\n wss = undefined;\n }\n\n // Remove only our trace event listener from the runtime\n if (traceListener) {\n runtime.removeListener('trace', traceListener);\n }\n\n // Close all aggregators (clear intervals and unsubscribe listeners)\n closeAggregators();\n }\n\n return {\n handler,\n handleWebSocket,\n upgradeWebSocket,\n app,\n connectionManager: connMgr,\n close,\n };\n}\n\n/**\n * Normalize and validate basePath.\n * - Empty string and undefined → ''\n * - Strip trailing slashes\n * - Validate leading slash when non-empty\n * - Reject unsafe characters\n */\nfunction normalizeBasePath(raw?: string): string {\n if (!raw) return '';\n\n // Strip trailing slashes\n const normalized = raw.replace(/\\/+$/, '');\n if (!normalized) return '';\n\n // Must start with /\n if (!normalized.startsWith('/')) {\n throw new Error(`basePath must start with '/' (got '${raw}'). Example: '/studio'`);\n }\n\n // Reject path traversal, consecutive slashes, and unsafe characters\n if (normalized.includes('..')) {\n throw new Error(`basePath must not contain '..' segments (got '${raw}')`);\n }\n if (normalized.includes('//')) {\n throw new Error(`basePath must not contain consecutive slashes (got '${raw}')`);\n }\n if (!/^\\/[a-zA-Z0-9/_-]*$/.test(normalized)) {\n throw new Error(\n `basePath contains invalid characters (got '${raw}'). ` +\n 'Only alphanumeric characters, /, _, and - are allowed.',\n );\n }\n\n return normalized;\n}\n\nfunction resolveClientDist(): string | undefined {\n // Resolve the directory of this file (dist/ in published package).\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n const candidate = resolve(dir, 'client');\n return existsSync(resolve(candidate, 'index.html')) ? candidate : undefined;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport type { AxlRuntime, AxlEvent } from '@axlsdk/axl';\nimport { redactStreamEvent } from './redact.js';\nimport type { StudioEnv } from './types.js';\nimport { errorHandler } from './middleware/error-handler.js';\nimport { ConnectionManager } from './ws/connection-manager.js';\nimport type { BufferCaps } from './ws/connection-manager.js';\nimport { createWsHandlers } from './ws/handler.js';\nimport { TraceAggregator } from './aggregates/trace-aggregator.js';\nimport { ExecutionAggregator } from './aggregates/execution-aggregator.js';\nimport { EvalAggregator } from './aggregates/eval-aggregator.js';\nimport {\n reduceCost,\n emptyCostData,\n reduceWorkflowStats,\n emptyWorkflowStatsData,\n enrichWorkflowStats,\n reduceTraceStats,\n emptyTraceStatsData,\n reduceEvalTrends,\n emptyEvalTrendData,\n} from './aggregates/reducers.js';\nimport type { WindowId } from './aggregates/aggregate-snapshots.js';\nimport { createHealthRoutes } from './routes/health.js';\nimport { createWorkflowRoutes } from './routes/workflows.js';\nimport executionRoutes from './routes/executions.js';\nimport { createSessionRoutes } from './routes/sessions.js';\nimport agentRoutes from './routes/agents.js';\nimport toolRoutes from './routes/tools.js';\nimport memoryRoutes from './routes/memory.js';\nimport decisionRoutes from './routes/decisions.js';\nimport { createCostRoutes } from './routes/costs.js';\nimport { createEvalRoutes } from './routes/evals.js';\nimport { createPlaygroundRoutes } from './routes/playground.js';\nimport { createEvalTrendsRoutes } from './routes/eval-trends.js';\nimport { createWorkflowStatsRoutes } from './routes/workflow-stats.js';\nimport { createTraceStatsRoutes } from './routes/trace-stats.js';\n\nexport type { StudioEnv } from './types.js';\nexport { ConnectionManager } from './ws/connection-manager.js';\nexport type { BroadcastTarget, BufferCaps } from './ws/connection-manager.js';\nexport { TraceAggregator } from './aggregates/trace-aggregator.js';\nexport { ExecutionAggregator } from './aggregates/execution-aggregator.js';\nexport { EvalAggregator } from './aggregates/eval-aggregator.js';\nexport type { WindowId, AggregateBroadcast } from './aggregates/aggregate-snapshots.js';\n\nexport type CreateServerOptions = {\n runtime: AxlRuntime;\n /** Root path for serving pre-built SPA static assets. */\n staticRoot?: string;\n /** Base URL path for client-side routing and API calls. Injected into index.html at serve time. */\n basePath?: string;\n /** When true, disable all mutating API endpoints. */\n readOnly?: boolean;\n /** Apply CORS headers. Default: true (standalone CLI). Set false for embedded middleware. */\n cors?: boolean;\n /** Lazy eval file loader. Called before eval routes access the runtime's registered evals. */\n evalLoader?: () => Promise<void>;\n /**\n * Override the default WS replay-buffer resource caps. All fields are\n * optional; omitted fields keep their documented defaults\n * (1000 events / 4 MiB per buffer, 256 concurrent buffers).\n */\n bufferCaps?: BufferCaps;\n};\n\nexport function createServer(options: CreateServerOptions) {\n const { runtime, staticRoot, basePath = '', readOnly = false } = options;\n const app = new Hono<StudioEnv>();\n const connMgr = new ConnectionManager(options.bufferCaps);\n const windows: WindowId[] = ['24h', '7d', '30d', 'all'];\n\n const costAggregator = new TraceAggregator({\n runtime,\n connMgr,\n channel: 'costs',\n reducer: reduceCost,\n emptyState: emptyCostData,\n windows,\n });\n\n const workflowStatsAggregator = new ExecutionAggregator({\n runtime,\n connMgr,\n channel: 'workflow-stats',\n reducer: reduceWorkflowStats,\n emptyState: emptyWorkflowStatsData,\n windows,\n broadcastTransform: enrichWorkflowStats,\n });\n\n const traceStatsAggregator = new TraceAggregator({\n runtime,\n connMgr,\n channel: 'trace-stats',\n reducer: reduceTraceStats,\n emptyState: emptyTraceStatsData,\n windows,\n });\n\n const evalTrendsAggregator = new EvalAggregator({\n runtime,\n connMgr,\n channel: 'eval-trends',\n reducer: reduceEvalTrends,\n emptyState: emptyEvalTrendData,\n windows,\n });\n\n // ── Middleware ──────────────────────────────────────────────────────\n if (options.cors !== false) {\n app.use('*', cors());\n }\n app.use('*', errorHandler);\n app.use('*', async (c, next) => {\n c.set('runtime', runtime);\n await next();\n });\n\n // ── Read-only mode ──────────────────────────────────────────────────\n if (readOnly) {\n // Patterns must be precise: POST /api/evals/compare is pure computation\n // and must remain allowed, but POST /api/evals/:name/run mutates history.\n const blocked: RegExp[] = [\n /^POST \\/api\\/workflows(\\/|$)/,\n /^POST \\/api\\/executions(\\/|$)/,\n /^POST \\/api\\/sessions(\\/|$)/,\n /^DELETE \\/api\\/sessions(\\/|$)/,\n /^PUT \\/api\\/memory(\\/|$)/,\n /^DELETE \\/api\\/memory(\\/|$)/,\n /^POST \\/api\\/decisions(\\/|$)/,\n /^POST \\/api\\/tools(\\/|$)/,\n /^POST \\/api\\/evals\\/import$/,\n /^POST \\/api\\/evals\\/[^/]+\\/run$/,\n /^POST \\/api\\/evals\\/[^/]+\\/rescore$/,\n /^POST \\/api\\/evals\\/runs\\/[^/]+\\/cancel$/,\n /^DELETE \\/api\\/evals\\/history\\/[^/]+$/,\n /^POST \\/api\\/playground(\\/|$)/,\n ];\n app.use('/api/*', async (c, next) => {\n // c.req.path returns the full path including any parent route prefix\n // (e.g., /studio/api/workflows when mounted via app.route('/studio', ...)).\n // Extract just the /api/... portion for matching.\n const apiIdx = c.req.path.indexOf('/api/');\n const apiPath = apiIdx >= 0 ? c.req.path.slice(apiIdx) : c.req.path;\n const key = `${c.req.method} ${apiPath}`;\n if (blocked.some((re) => re.test(key))) {\n return c.json(\n {\n ok: false,\n error: { code: 'READ_ONLY', message: 'Studio is mounted in read-only mode' },\n },\n 405,\n );\n }\n await next();\n });\n }\n\n // ── API Routes ─────────────────────────────────────────────────────\n const api = new Hono<StudioEnv>();\n api.route('/', createHealthRoutes(readOnly));\n api.route('/', createWorkflowRoutes(connMgr));\n api.route('/', executionRoutes);\n api.route('/', createSessionRoutes(connMgr));\n api.route('/', agentRoutes);\n api.route('/', toolRoutes);\n api.route('/', memoryRoutes);\n api.route('/', decisionRoutes);\n api.route('/', createCostRoutes(costAggregator));\n api.route('/', createEvalTrendsRoutes(evalTrendsAggregator));\n api.route('/', createWorkflowStatsRoutes(workflowStatsAggregator));\n api.route('/', createTraceStatsRoutes(traceStatsAggregator));\n const { app: evalApp, closeActiveRuns } = createEvalRoutes(connMgr, options.evalLoader);\n api.route('/', evalApp);\n api.route('/', createPlaygroundRoutes(connMgr));\n\n app.route('/api', api);\n\n // ── Trace event bridging ───────────────────────────────────────────\n // Aggregators subscribe to runtime events directly via their start() method.\n // This listener handles trace channel broadcasting and decision events only.\n // `isRedactEnabled()` is read per-event so a runtime that flips the flag\n // at runtime (not the common path, but possible) reflects immediately.\n const traceListener = (event: unknown) => {\n // Wrap the whole body in try/catch so a throw in `redactStreamEvent`\n // (malformed event shape) or `broadcastWithWildcard` (serialization\n // error) doesn't propagate back through `EventEmitter.emit('trace')`\n // and starve downstream listeners. Fail-loud to console.error so ops\n // sees it in logs but the runtime keeps going.\n try {\n const traceEvent = event as AxlEvent;\n\n // Broadcast to trace channels — apply the same scrubbing as the\n // playground/workflow execution paths so the trace firehose doesn't\n // leak content the per-route broadcasts are scrubbing.\n const redacted = redactStreamEvent(traceEvent, runtime.isRedactEnabled());\n if (traceEvent.executionId) {\n connMgr.broadcastWithWildcard(`trace:${traceEvent.executionId}`, redacted);\n }\n\n // Broadcast pending decisions. `await_human` is now a first-class\n // AxlEvent type (was a `log` variant before 0.16). Send the redacted\n // shape — `prompt` is user-visible LLM content that respects redact.\n if (traceEvent.type === 'await_human') {\n connMgr.broadcast('decisions', redacted);\n }\n } catch (err) {\n console.error(\n '[axl-studio] trace listener threw; event dropped:',\n err instanceof Error ? err.message : String(err),\n );\n }\n };\n runtime.on('trace', traceListener);\n\n // ── Start aggregators (rebuild from history + subscribe to live events) ──\n const aggregatorStartPromise = Promise.all([\n costAggregator.start(),\n workflowStatsAggregator.start(),\n traceStatsAggregator.start(),\n evalTrendsAggregator.start(),\n ]).catch((err) => console.error('[axl-studio] aggregator start failed:', err));\n\n // ── Static SPA serving (production) ────────────────────────────────\n if (staticRoot) {\n // Read index.html once at startup. When basePath is set, inject the <base>\n // tag and runtime config so asset paths and client-side routing work\n // regardless of whether the mount URL has a trailing slash.\n const indexPath = resolve(staticRoot, 'index.html');\n let spaHtml: string | undefined;\n\n if (!existsSync(indexPath)) {\n console.warn(`[axl-studio] index.html not found at ${indexPath}`);\n } else {\n const rawHtml = readFileSync(indexPath, 'utf-8');\n\n if (basePath) {\n // Escape '<' to prevent </script> in basePath from breaking out of\n // the script tag. JSON.stringify alone is insufficient because the\n // HTML parser processes </script> before JavaScript runs.\n const safeBasePath = JSON.stringify(basePath).replace(/</g, '\\\\u003c');\n const injected = rawHtml.replace(\n '<head>',\n `<head>\\n<base href=\"${basePath}/\">\\n` +\n `<script>window.__AXL_STUDIO_BASE__=${safeBasePath}</script>`,\n );\n\n if (injected === rawHtml) {\n console.warn(\n '[axl-studio] Could not inject basePath into index.html — ' +\n '<head> tag not found. The SPA may not route correctly.',\n );\n }\n spaHtml = injected;\n } else {\n spaHtml = rawHtml;\n }\n }\n\n // Serve static assets (JS, CSS, images). index.html is excluded so the\n // SPA fallback below always serves the version with basePath injection.\n // Without this guard, serveStatic would serve the raw index.html for root\n // requests (/ or /index.html), missing <base> and __AXL_STUDIO_BASE__.\n const staticHandler = serveStatic({\n root: staticRoot,\n rewriteRequestPath: basePath\n ? (path) => (path.startsWith(basePath) ? path.slice(basePath.length) || '/' : path)\n : undefined,\n });\n\n app.use('/*', async (c, next) => {\n const reqPath = c.req.path;\n const resolved =\n basePath && reqPath.startsWith(basePath) ? reqPath.slice(basePath.length) || '/' : reqPath;\n // Skip index.html (handled by SPA fallback) and /ws (handled by WebSocket upgrader)\n if (resolved === '/' || resolved === '/index.html' || resolved === '/ws') {\n return next();\n }\n return staticHandler(c, next);\n });\n\n // SPA fallback: serve the (possibly injected) index.html for all\n // non-API, non-static-asset routes so React Router handles routing.\n // Skip /ws so the WebSocket upgrader (registered after createServer) can handle it.\n if (spaHtml) {\n app.get('*', async (c, next) => {\n const resolved =\n basePath && c.req.path.startsWith(basePath)\n ? c.req.path.slice(basePath.length) || '/'\n : c.req.path;\n if (resolved === '/ws') return next();\n return c.html(spaHtml!);\n });\n }\n }\n\n return {\n app,\n connMgr,\n costAggregator,\n workflowStatsAggregator,\n traceStatsAggregator,\n evalTrendsAggregator,\n aggregatorStartPromise,\n /** Create WS handlers. Call before registering static/SPA routes are reached. */\n createWsHandlers: () => createWsHandlers(connMgr),\n traceListener,\n /** Abort all active streaming eval runs. */\n closeActiveRuns,\n /** Close all aggregators (clear intervals and unsubscribe listeners). */\n closeAggregators: () => {\n costAggregator.close();\n workflowStatsAggregator.close();\n traceStatsAggregator.close();\n evalTrendsAggregator.close();\n },\n };\n}\n","/**\n * Server-side redaction for observability responses.\n *\n * `config.trace.redact` was originally scoped to trace events emitted via\n * `emitTrace()` — it scrubs user/LLM content in prompts, responses, memory\n * values, tool args, etc. But data returned through Studio's REST surface\n * (execution results, memory values, session history) bypassed trace\n * emission entirely and leaked raw content even when trace redaction was\n * on. That inconsistency made \"compliance mode\" misleading: a user would\n * see `[redacted]` in the Trace Explorer timeline and then see raw user\n * data in the sibling Result pane, Memory Browser, or Session Manager.\n *\n * The right user mental model for this config is \"what can the observability\n * layer see?\". We keep the config name `trace.redact` but broaden its scope\n * at the REST read boundary to also scrub:\n *\n * - `ExecutionInfo.result` / `.error` (/api/executions, /api/executions/:id)\n * - Memory values (/api/memory/:scope, /api/memory/:scope/:key)\n * - Session message content + tool call arguments (/api/sessions/:id)\n *\n * Structural metadata (workflow names, agent names, tool names, keys, IDs,\n * timestamps, cost/token metrics) is preserved so the Trace Explorer,\n * Memory Browser, and Session Manager still render useful context when\n * compliance mode is on.\n *\n * Programmatic callers of `runtime.execute()` and direct StateStore access\n * still receive raw values — redaction is an *observability boundary* filter,\n * not a data-at-rest transform. If a user needs scrubbed state-at-rest they\n * configure their own StateStore to store scrubbed values.\n */\nimport type {\n ExecutionInfo,\n ChatMessage,\n PendingDecision,\n AxlEvent,\n EvalHistoryEntry,\n} from '@axlsdk/axl';\nimport { redactEvent } from '@axlsdk/axl';\nimport type { EvalResult, EvalItem, ScorerDetail } from '@axlsdk/eval';\n\n// Stream events on the wire are `AxlEvent` — the translation layer was\n// deleted in PR 1 commit 4. The legacy `StreamEvent` shapes are gone;\n// consumers narrow on the AxlEvent union.\n\nconst REDACTED = '[redacted]';\n\n/**\n * Error `name` values whose `message` is purely structural (codes, counts,\n * identifiers) and safe to surface verbatim under redact mode. Every other\n * error — `ValidationError`, `GuardrailError`, `VerifyError`, arbitrary\n * provider errors, `Error` from user code — is treated as potentially\n * echoing user/LLM content and has its message scrubbed.\n *\n * Kept in sync with the allow-list in\n * `server/middleware/error-handler.ts`; both sites must match so a route\n * that surfaces errors inline has identical redaction semantics to one\n * that throws through the global handler.\n */\nconst SAFE_ERROR_NAMES = new Set([\n 'QuorumNotMet',\n 'NoConsensus',\n 'TimeoutError',\n 'MaxTurnsError',\n 'BudgetExceededError',\n 'ToolDenied',\n]);\n\n/**\n * Scrub an error's `.message` for inclusion in a REST error envelope or WS\n * error event. Under redact mode, only messages from the structural\n * allow-list above pass through; everything else becomes `[redacted]`. The\n * `code`/`name` stay untouched so clients can still branch programmatically.\n *\n * Call sites that catch an error and build a `{ code, message }` envelope\n * locally (instead of re-throwing through `errorHandler`) should use this\n * helper so their redaction behavior stays consistent with the global path.\n */\nexport function redactErrorMessage(err: unknown, redact: boolean): string {\n const raw = err instanceof Error ? err.message : String(err);\n if (!redact) return raw;\n const name = err instanceof Error ? err.name : '';\n return SAFE_ERROR_NAMES.has(name) ? raw : REDACTED;\n}\n\n/**\n * Generic \"scrub any value to the redacted sentinel\" helper. Used by\n * routes that return a single opaque payload (workflow execute result,\n * tool test result, playground done data) where the value could be\n * anything — string, object, array, null, number — and we just want a\n * consistent scrubbed marker regardless of shape.\n */\nexport function redactValue(value: unknown, redact: boolean): unknown {\n if (!redact) return value;\n return REDACTED;\n}\n\n/**\n * Return a shallow-cloned ExecutionInfo with user-content fields scrubbed\n * when `redact` is true. Never mutates the input. When `redact` is false,\n * returns the input unchanged (reference equality preserved).\n *\n * Event scrubbing: every event in `events[]` is piped through\n * `redactStreamEvent` to catch per-variant payloads that emit-time\n * redaction may have missed (e.g., `partial_object.data.object`,\n * `verify.data.lastError`, `pipeline.reason`, terminal `done`/`error`,\n * `tool_call_start.data.args`, `tool_denied.data.*`). Defense in depth —\n * core `emitEvent` scrubs most variants at emission, but the REST\n * serialization boundary is the last line before PII leaves the\n * observability envelope.\n */\nexport function redactExecutionInfo(info: ExecutionInfo, redact: boolean): ExecutionInfo {\n if (!redact) return info;\n return {\n ...info,\n ...(info.result !== undefined ? { result: REDACTED } : {}),\n ...(info.error !== undefined ? { error: REDACTED } : {}),\n events: info.events.map((e) => redactStreamEvent(e, true)),\n };\n}\n\n/** List variant: maps each entry through the single-item redactor. */\nexport function redactExecutionList(infos: ExecutionInfo[], redact: boolean): ExecutionInfo[] {\n if (!redact) return infos;\n return infos.map((info) => redactExecutionInfo(info, redact));\n}\n\n/**\n * Scrub a memory value read through Studio's REST API. Memory values\n * don't flow through `emitTrace` (the memory_remember / memory_recall log\n * events deliberately exclude values — operation-only audit trail), so\n * this isn't closing a trace-to-REST inconsistency. It's broadening the\n * observability-boundary scope to cover memory browser reads.\n *\n * Keys are deliberately preserved so the Memory Browser stays navigable —\n * users with redact on can still see which keys exist and which ones\n * their code is writing to. Keys are programmer-chosen identifiers; if a\n * specific deployment has PII in keys it's a code-level problem and\n * should be fixed at the `ctx.remember()` call site.\n */\nexport function redactMemoryValue(value: unknown, redact: boolean): unknown {\n if (!redact) return value;\n return REDACTED;\n}\n\n/**\n * Memory list variant. Scrubs values on every `{ key, value }` entry;\n * preserves keys for navigation.\n */\nexport function redactMemoryList(\n entries: Array<{ key: string; value: unknown }>,\n redact: boolean,\n): Array<{ key: string; value: unknown }> {\n if (!redact) return entries;\n return entries.map((entry) => ({ key: entry.key, value: REDACTED }));\n}\n\n/**\n * Scrub a single ChatMessage for session history responses. Removes:\n * - `content` — user/LLM text\n * - `tool_calls[*].function.arguments` — tool inputs (JSON string)\n * - `providerMetadata` — opaque provider bag that\n * may contain encoded reasoning / thinking signatures / cache keys\n *\n * Preserves:\n * - `role` — system/user/assistant/tool\n * - `name` — tool/function name on\n * role='tool' messages (non-PII identifier)\n * - `tool_call_id` — join key for tool responses\n * - `tool_calls[*].id` — call ID\n * - `tool_calls[*].type` — always 'function'\n * - `tool_calls[*].function.name` — tool name (non-PII)\n *\n * The preserved fields are exactly the structural metadata you need to\n * understand the shape of a conversation (who said what, which tools\n * were called) without seeing any user/LLM content.\n */\nfunction redactChatMessage(msg: ChatMessage): ChatMessage {\n // We deliberately hand-build the output with an explicit allow-list\n // instead of spreading `msg`, so any new field added to `ChatMessage`\n // in the future (e.g. `refusal`, `reasoning_content`) is silently\n // dropped rather than passing through unscrubbed. The `satisfies`\n // assertion catches the case where a new REQUIRED field is added to\n // `ChatMessage` — typecheck will fail and force a code review on\n // whether the new field should be scrubbed or preserved.\n const scrubbed = {\n role: msg.role,\n content: REDACTED,\n ...(msg.name !== undefined ? { name: msg.name } : {}),\n ...(msg.tool_call_id !== undefined ? { tool_call_id: msg.tool_call_id } : {}),\n ...(msg.tool_calls !== undefined\n ? {\n tool_calls: msg.tool_calls.map((tc) => ({\n id: tc.id,\n type: tc.type,\n function: {\n name: tc.function.name,\n arguments: REDACTED,\n },\n })),\n }\n : {}),\n // providerMetadata deliberately omitted — opaque content.\n } satisfies ChatMessage;\n return scrubbed;\n}\n\n/**\n * Scrub a session history response. Maps every message through\n * `redactChatMessage`. HandoffRecord entries (on the same response) have\n * no content fields — just source/target/mode/timestamp/duration — so\n * they don't need scrubbing.\n */\nexport function redactSessionHistory(history: ChatMessage[], redact: boolean): ChatMessage[] {\n if (!redact) return history;\n return history.map(redactChatMessage);\n}\n\n// ── Stream events (WS broadcast) ─────────────────────────────────────\n\n/**\n * Scrub an `AxlEvent` before broadcasting it to Studio WS subscribers or\n * serializing it through a REST response.\n *\n * Per-variant scrub logic lives in core's `REDACTION_RULES` table\n * (`packages/axl/src/redaction.ts`). Both this WS-boundary scrubber and\n * core's emit-time scrubber consult the same rules, so adding a new\n * `AxlEvent` variant updates both layers in one place — no drift.\n *\n * The defense-in-depth value of this layer remains: when a runtime emits\n * events with `redact: false` (rare but possible — e.g. a multi-tenant\n * setup where the per-request decision is made later) and they land in\n * `ExecutionInfo.events` for a REST read with `redact: true`, this\n * second pass catches the missed scrub. Structural metadata\n * (`executionId`/`step`/`timestamp`/`askId`/`agent`/etc.) and numeric\n * observability fields (`cost`/`tokens`/`duration`) are preserved by\n * every rule.\n *\n * Programmatic callers of `runtime.execute()` and direct StateStore\n * reads still receive raw events — redaction is an observability-boundary\n * filter, not a data-at-rest transform.\n */\nexport function redactStreamEvent(event: AxlEvent, redact: boolean): AxlEvent {\n if (!redact) return event;\n return redactEvent(event);\n}\n\n// ── Eval results ─────────────────────────────────────────────────────\n\n/**\n * Scrub a single `EvalItem`. Per-item user/LLM content lives in:\n * input — the dataset item that drove the workflow\n * output — the workflow's return value\n * error — failure message (may echo user input)\n * annotations — user-supplied per-item labels/ground truth\n * scorerErrors — scorer-thrown error strings that can echo content\n * scoreDetails[*].metadata — especially LLM-scorer reasoning,\n * which mirrors agent_call response content\n *\n * Preserved fields (structural / metrics):\n * scores (numeric), duration, cost, scorerCost\n * scoreDetails[*].{score, duration, cost} (but not metadata)\n * metadata (execution metadata: models, tokens, agentCalls, workflows)\n * traces (trace events — already redacted at emission time)\n */\nfunction redactEvalItem(item: EvalItem): EvalItem {\n const scrubbed: EvalItem = {\n ...item,\n input: REDACTED,\n output: REDACTED,\n ...(item.annotations !== undefined ? { annotations: REDACTED } : {}),\n ...(item.error !== undefined ? { error: REDACTED } : {}),\n ...(item.scorerErrors !== undefined\n ? { scorerErrors: item.scorerErrors.map(() => REDACTED) }\n : {}),\n };\n if (item.scoreDetails) {\n const detailsOut: Record<string, ScorerDetail> = {};\n for (const [name, detail] of Object.entries(item.scoreDetails)) {\n detailsOut[name] = {\n score: detail.score,\n ...(detail.duration !== undefined ? { duration: detail.duration } : {}),\n ...(detail.cost !== undefined ? { cost: detail.cost } : {}),\n // metadata deliberately omitted — may contain LLM scorer reasoning\n };\n }\n scrubbed.scoreDetails = detailsOut;\n }\n return scrubbed;\n}\n\n/**\n * Scrub an `EvalResult` for an observability-boundary read. Items are\n * mapped through `redactEvalItem`; result-level metadata (`dataset`, `id`,\n * `timestamp`, `totalCost`, `duration`, `summary`, `metadata`) is\n * preserved so the Eval Runner UI can still render summary stats,\n * timing, score distributions, and cost aggregates under compliance mode.\n */\nexport function redactEvalResult(result: EvalResult, redact: boolean): EvalResult {\n if (!redact) return result;\n return {\n ...result,\n items: result.items.map(redactEvalItem),\n };\n}\n\n/**\n * Scrub an `EvalHistoryEntry`. Entry-level metadata (id, eval name,\n * timestamp) is preserved; the nested `data` (an `EvalResult`) is\n * scrubbed recursively.\n */\nexport function redactEvalHistoryEntry(entry: EvalHistoryEntry, redact: boolean): EvalHistoryEntry {\n if (!redact) return entry;\n return {\n ...entry,\n data: redactEvalResult(entry.data as EvalResult, redact),\n };\n}\n\n/** List variant for eval history. */\nexport function redactEvalHistoryList(\n entries: EvalHistoryEntry[],\n redact: boolean,\n): EvalHistoryEntry[] {\n if (!redact) return entries;\n return entries.map((e) => redactEvalHistoryEntry(e, redact));\n}\n\n// ── Pending decisions (human-in-the-loop) ───────────────────────────\n\n/**\n * Scrub a `PendingDecision`. The `prompt` field is the human-visible\n * approval question that typically echoes user or agent content (e.g.\n * \"Approve sending this email to `user@acme.com`?\"). Metadata is also\n * scrubbed because it's a free-form bag that may contain arbitrary\n * user data. Structural fields (executionId, channel, createdAt) stay\n * visible so the Decisions panel can still render the approval queue.\n */\nexport function redactPendingDecision(decision: PendingDecision, redact: boolean): PendingDecision {\n if (!redact) return decision;\n return {\n ...decision,\n prompt: REDACTED,\n ...(decision.metadata !== undefined ? { metadata: { redacted: true } } : {}),\n };\n}\n\n/** List variant for pending decisions. */\nexport function redactPendingDecisionList(\n decisions: PendingDecision[],\n redact: boolean,\n): PendingDecision[] {\n if (!redact) return decisions;\n return decisions.map((d) => redactPendingDecision(d, redact));\n}\n","import type { Context, Next } from 'hono';\nimport type { StudioEnv, ApiError } from '../types.js';\nimport { redactErrorMessage } from '../redact.js';\n\nexport async function errorHandler(c: Context<StudioEnv>, next: Next) {\n try {\n await next();\n } catch (err) {\n const rawMessage = err instanceof Error ? err.message : String(err);\n const code = (err as { code?: string }).code ?? 'INTERNAL_ERROR';\n\n // Determine HTTP status from error properties. Status classification\n // uses the raw message (not the redacted one) — redaction only affects\n // what the client sees, not how we categorize the error.\n let status = 500;\n if ('status' in (err as object)) {\n const errStatus = (err as { status: unknown }).status;\n if (typeof errStatus === 'number' && errStatus >= 400 && errStatus < 600) {\n status = errStatus;\n }\n } else if (\n code === 'NOT_FOUND' ||\n rawMessage.includes('not found') ||\n rawMessage.includes('not registered')\n ) {\n status = 404;\n } else if (\n code === 'VALIDATION_ERROR' ||\n rawMessage.includes('Expected') ||\n rawMessage.includes('invalid')\n ) {\n status = 400;\n }\n\n // Under `trace.redact`, error messages can echo user input\n // (ValidationError includes the failing reason, provider errors often\n // quote the request body, GuardrailError includes the trigger reason).\n // `redactErrorMessage` lets structural errors (Budget/Timeout/MaxTurns/\n // Quorum/NoConsensus/ToolDenied) pass through and scrubs the rest.\n const runtime = c.get('runtime');\n const redactOn = runtime?.isRedactEnabled?.() ?? false;\n\n const body: ApiError = {\n ok: false,\n error: { code, message: redactErrorMessage(err, redactOn) },\n };\n\n return c.json(body, status as 400 | 404 | 500);\n }\n}\n","/**\n * Minimal interface for a connection that can receive broadcast messages.\n * Satisfied by WSContext (Hono), ws.WebSocket (Node.js), and the middleware's\n * adapted socket. Internal to ConnectionManager — not part of the public API.\n */\nexport interface BroadcastTarget {\n send(data: string): void;\n close?(): void;\n}\n\n/**\n * Short-lived event buffer for execution streams.\n * Solves the race where a fast provider (e.g., MockProvider) completes\n * before the client's WS subscription is established. Events are buffered\n * per-channel and replayed to late subscribers.\n */\ninterface BufferedEvent {\n /** Pre-serialized JSON message (ready to `ws.send`). */\n msg: string;\n /** Original event data for filter evaluation on replay. */\n data: unknown;\n}\n\ninterface ChannelBuffer {\n events: BufferedEvent[];\n complete: boolean; // True after done/error event\n timer?: ReturnType<typeof setTimeout>;\n /** Sum of `msg.length` over buffered events. Byte-accurate; used to\n * enforce the per-buffer memory cap below. Maintained incrementally\n * so we don't have to re-scan on every push. */\n bytes: number;\n}\n\nconst BUFFER_TTL_MS = 30_000; // Clean up buffers 30s after stream completes\n\n/** Default cap on per-channel buffered events (raised from 500 in\n * spec/16 §5.2 to absorb nested-ask volume — ~10 nested asks × ~20\n * structural events each, with headroom). Override via the\n * `bufferCaps.maxEventsPerBuffer` constructor option on\n * `ConnectionManager`. */\nconst DEFAULT_MAX_BUFFER_EVENTS = 1000;\n\n/** Default per-buffer byte budget. 1000 events × 64KB max each would\n * peak at ~64MB per stream; the real-world distribution is bimodal\n * (hundreds of small structural events + a few verbose `agent_call_end`\n * snapshots), so 4MB per buffer is generous. When exceeded, new non-\n * terminal events are dropped (terminal `done`/`error` always\n * buffered). Review B-4. Override via\n * `bufferCaps.maxBytesPerBuffer`. */\nconst DEFAULT_MAX_BUFFER_BYTES = 4 * 1024 * 1024;\n\n/** Default cap on the number of concurrently-live replay buffers. Each\n * buffer is an open execution/eval stream; without a cap, a server\n * that sees sustained churn (say, 10k short-lived executions / minute)\n * holds 10k × maxBytesPerBuffer = 40GB of event-log memory across the\n * TTL window. When we hit the cap, the oldest complete buffer is\n * evicted immediately; if all live buffers are still incomplete, the\n * oldest one is dropped anyway (its late subscribers will miss the\n * replay, which is degraded UX but NOT a crash). Review SEC-H5.\n * Override via `bufferCaps.maxActiveBuffers`. */\nconst DEFAULT_MAX_ACTIVE_BUFFERS = 256;\n\n/**\n * Operator-tunable replay-buffer resource limits. Exposed via\n * `createStudioMiddleware({ bufferCaps })` and `createServer({ bufferCaps })`\n * so production deployments can tighten or relax memory pressure\n * without forking the package.\n *\n * All three fields are optional; omitted fields fall back to their\n * documented defaults, so passing `{}` is a no-op.\n */\nexport interface BufferCaps {\n /** Per-channel buffered event count cap. Default: 1000. */\n maxEventsPerBuffer?: number;\n /** Per-channel buffered byte budget. Default: 4 MiB. */\n maxBytesPerBuffer?: number;\n /** Global concurrently-live buffer cap. Default: 256. */\n maxActiveBuffers?: number;\n}\n\n/**\n * Stream-only event types excluded from the replay buffer entirely.\n * Late subscribers to an in-flight stream don't need per-token chatter\n * or per-delta progressive-render snapshots — they reconstruct the same\n * info from the final `agent_call_end` (token aggregates) and `done`\n * (final result). Both types are stream-only ergonomics, not\n * correctness-critical for replay. Spec/16 §5.2.\n */\nconst UNBUFFERED_EVENT_TYPES = new Set(['token', 'partial_object']);\n\n/** WS frame size soft cap. Used for both the inbound message reject in\n * `protocol.ts` and the outbound broadcast truncation below — keeping them\n * in one place so they never drift. Events that serialize larger than this\n * on the outbound path are replaced with a truncated placeholder so\n * consumers still receive a signal instead of having the browser's WS\n * client silently drop or close the connection. */\nexport const MAX_WS_FRAME_BYTES = 65536;\n\n/** Channels eligible for replay buffering (execution streams). */\nfunction isBufferedChannel(channel: string): boolean {\n return channel.startsWith('execution:') || channel.startsWith('eval:');\n}\n\n/**\n * Guard against outbound frames that exceed the WS size budget. Verbose-mode\n * `agent_call` events with a full `messages[]` snapshot can balloon past 64KB\n * on long conversations; browsers/ws libraries behave inconsistently when this\n * happens (silent drop, connection close, errors). Instead of hoping the\n * underlying stack handles it, we serialize once, check size, and fall back to\n * a truncated placeholder event if the payload is too large.\n *\n * The replacement preserves `channel`, `data.type`, `data.step`, `data.agent`,\n * and `data.tool` so the UI still sees the event shape — it just sees an\n * explicit truncation marker instead of silently losing data.\n */\nfunction truncateIfOversized(msg: string, channel: string, data: unknown): string {\n // WS frame budgets are measured in bytes. `string.length` counts UTF-16\n // code units; a payload with emoji / CJK / other multi-byte UTF-8 chars\n // can pass `msg.length <= 65536` yet serialize to >128KB when the\n // browser encodes the frame. Measure bytes directly to avoid\n // reintroducing the silent-drop / disconnect behavior this function\n // exists to prevent.\n const msgBytes = Buffer.byteLength(msg, 'utf8');\n if (msgBytes <= MAX_WS_FRAME_BYTES) return msg;\n const event = (data ?? {}) as {\n type?: string;\n step?: number;\n agent?: string;\n tool?: string;\n executionId?: string;\n };\n const truncated = {\n type: 'event',\n channel,\n data: {\n ...event,\n data: {\n __truncated: true,\n originalBytes: msgBytes,\n maxBytes: MAX_WS_FRAME_BYTES,\n hint: 'Event exceeded WS frame budget (likely a verbose agent_call with a large messages[] snapshot). Fetch via REST if you need the full payload.',\n },\n },\n };\n return JSON.stringify(truncated);\n}\n\n/**\n * Per-event, per-connection filter used by multi-tenant integrators to scope\n * the trace firehose. Return `true` to deliver the event to this connection,\n * `false` to skip it.\n *\n * `event` is the parsed payload (the same shape that was passed to `broadcast`);\n * `metadata` is whatever the middleware attached via `setMetadata(ws, ...)`\n * after a successful `verifyUpgrade` — typically `{ userId, tenantId }` or\n * similar, sourced from the upgrade request's auth token.\n */\nexport type BroadcastFilter = (event: unknown, metadata: unknown) => boolean;\n\n/**\n * Manages WebSocket connections and channel subscriptions.\n * Supports channel multiplexing: clients subscribe/unsubscribe to channels\n * and receive events only for channels they're subscribed to.\n *\n * Execution channels (`execution:*`) are replay-buffered: events are stored\n * so that late subscribers receive the full event history. Buffers are cleaned\n * up shortly after the stream completes.\n *\n * Multi-tenant deployments can attach per-connection metadata via\n * `setMetadata(ws, data)` and register a `BroadcastFilter` to scope the\n * trace firehose to the authenticated user/tenant.\n */\nexport class ConnectionManager {\n /** channel -> set of WS connections */\n private channels = new Map<string, Set<BroadcastTarget>>();\n /** ws -> subscribed channels + optional integrator-supplied metadata */\n private connections = new Map<BroadcastTarget, { channels: Set<string>; metadata?: unknown }>();\n /** channel -> replay buffer for execution streams */\n private buffers = new Map<string, ChannelBuffer>();\n private maxConnections = 100;\n private filter?: BroadcastFilter;\n /** Resolved replay-buffer caps. Per-instance so embedders can dial them\n * without monkey-patching module-level constants. */\n private readonly maxEventsPerBuffer: number;\n private readonly maxBytesPerBuffer: number;\n private readonly maxActiveBuffers: number;\n\n constructor(bufferCaps?: BufferCaps) {\n // Reject pathological values up-front. `0` would silently drop every\n // non-terminal event (operators following the JSDoc to \"tighten memory\n // pressure\" might pass 0 thinking it disables buffering); negatives\n // make eviction always fire. Fail-loud beats degraded replay UX.\n const validatePositiveInt = (key: keyof BufferCaps, value: number | undefined): void => {\n if (value === undefined) return;\n if (!Number.isFinite(value) || !Number.isInteger(value) || value < 1) {\n throw new RangeError(`bufferCaps.${key} must be a positive integer (>= 1); got ${value}`);\n }\n };\n validatePositiveInt('maxEventsPerBuffer', bufferCaps?.maxEventsPerBuffer);\n validatePositiveInt('maxBytesPerBuffer', bufferCaps?.maxBytesPerBuffer);\n validatePositiveInt('maxActiveBuffers', bufferCaps?.maxActiveBuffers);\n this.maxEventsPerBuffer = bufferCaps?.maxEventsPerBuffer ?? DEFAULT_MAX_BUFFER_EVENTS;\n this.maxBytesPerBuffer = bufferCaps?.maxBytesPerBuffer ?? DEFAULT_MAX_BUFFER_BYTES;\n this.maxActiveBuffers = bufferCaps?.maxActiveBuffers ?? DEFAULT_MAX_ACTIVE_BUFFERS;\n }\n\n /**\n * Register a broadcast filter. Called once at middleware construction.\n * The filter runs on every outbound event and can drop or deliver based\n * on the destination connection's metadata.\n */\n setFilter(filter: BroadcastFilter | undefined): void {\n this.filter = filter;\n }\n\n /** Attach integrator-supplied metadata to an already-added connection. */\n setMetadata(ws: BroadcastTarget, metadata: unknown): void {\n const entry = this.connections.get(ws);\n if (entry) entry.metadata = metadata;\n }\n\n /** Register a new WS connection. */\n add(ws: BroadcastTarget): void {\n if (this.connections.size >= this.maxConnections) {\n ws.close?.();\n return;\n }\n this.connections.set(ws, { channels: new Set() });\n }\n\n /** Remove a WS connection and all its subscriptions. */\n remove(ws: BroadcastTarget): void {\n const entry = this.connections.get(ws);\n if (entry) {\n for (const ch of entry.channels) {\n this.channels.get(ch)?.delete(ws);\n if (this.channels.get(ch)?.size === 0) {\n this.channels.delete(ch);\n }\n }\n }\n this.connections.delete(ws);\n }\n\n /** Subscribe a connection to a channel. Replays buffered events for execution channels. */\n subscribe(ws: BroadcastTarget, channel: string): void {\n if (!this.connections.has(ws)) return;\n let subs = this.channels.get(channel);\n if (!subs) {\n subs = new Set();\n this.channels.set(channel, subs);\n }\n subs.add(ws);\n this.connections.get(ws)!.channels.add(channel);\n\n // Replay buffered events for late subscribers. Filter is re-applied on\n // replay so a tenant-B subscriber joining an execution channel doesn't\n // get tenant-A events that were buffered before it connected.\n const buffer = this.buffers.get(channel);\n if (buffer) {\n const metadata = this.connections.get(ws)?.metadata;\n for (const event of buffer.events) {\n if (this.filter) {\n try {\n if (!this.filter(event.data, metadata)) continue;\n } catch {\n continue;\n }\n }\n try {\n ws.send(event.msg);\n } catch {\n this.remove(ws);\n return;\n }\n }\n }\n }\n\n /** Unsubscribe a connection from a channel. */\n unsubscribe(ws: BroadcastTarget, channel: string): void {\n this.channels.get(channel)?.delete(ws);\n if (this.channels.get(channel)?.size === 0) {\n this.channels.delete(channel);\n }\n this.connections.get(ws)?.channels.delete(channel);\n }\n\n /** Broadcast data to all subscribers of a channel. Buffers events for execution channels. */\n broadcast(channel: string, data: unknown): void {\n const msg = truncateIfOversized(\n JSON.stringify({ type: 'event', channel, data }),\n channel,\n data,\n );\n\n // Buffer events for execution channels so late subscribers can replay\n if (isBufferedChannel(channel)) {\n let buffer = this.buffers.get(channel);\n if (!buffer) {\n // Enforce the global-buffer cap before allocating. Evict the\n // oldest-inserted buffer (Map preserves insertion order, so\n // `.keys().next().value` is the eldest). Prefer evicting a\n // completed buffer if any exist — its late-subscriber window\n // is already effectively closed. Falls back to evicting the\n // eldest live buffer under sustained pressure.\n if (this.buffers.size >= this.maxActiveBuffers) {\n let victim: string | undefined;\n for (const [ch, buf] of this.buffers) {\n if (buf.complete) {\n victim = ch;\n break;\n }\n }\n if (victim === undefined) {\n victim = this.buffers.keys().next().value as string | undefined;\n }\n if (victim !== undefined) {\n const old = this.buffers.get(victim);\n if (old?.timer) clearTimeout(old.timer);\n this.buffers.delete(victim);\n }\n }\n buffer = { events: [], complete: false, bytes: 0 };\n this.buffers.set(channel, buffer);\n }\n // Always buffer terminal events; skip non-terminal if at capacity\n // on EITHER the event-count OR byte budget; never buffer\n // high-volume types (token, partial_object) per spec/16 §5.2 —\n // late subscribers reconstruct the same info from structural\n // events.\n const event = data as { type?: string };\n const isTerminal = event.type === 'done' || event.type === 'error';\n const isUnbuffered = event.type !== undefined && UNBUFFERED_EVENT_TYPES.has(event.type);\n if (!isUnbuffered) {\n const msgBytes = Buffer.byteLength(msg, 'utf8');\n const atCountCap = buffer.events.length >= this.maxEventsPerBuffer;\n const atByteCap = buffer.bytes + msgBytes > this.maxBytesPerBuffer;\n if (isTerminal || (!atCountCap && !atByteCap)) {\n buffer.events.push({ msg, data });\n buffer.bytes += msgBytes;\n }\n }\n\n // Schedule buffer cleanup after terminal events\n if (isTerminal) {\n buffer.complete = true;\n if (buffer.timer) clearTimeout(buffer.timer);\n buffer.timer = setTimeout(() => {\n this.buffers.delete(channel);\n }, BUFFER_TTL_MS);\n }\n }\n\n // Send to current subscribers\n const subs = this.channels.get(channel);\n if (!subs || subs.size === 0) return;\n\n for (const ws of [...subs]) {\n // Multi-tenant filter: drop events that don't match this connection's\n // metadata (e.g., wrong tenant). Filter errors are treated as `drop`\n // so a buggy predicate can't accidentally leak events cross-tenant.\n if (this.filter) {\n const metadata = this.connections.get(ws)?.metadata;\n try {\n if (!this.filter(data, metadata)) continue;\n } catch {\n continue;\n }\n }\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n }\n }\n }\n\n /** Broadcast to channel and all wildcard subscribers (e.g., trace:* matches trace:abc). */\n broadcastWithWildcard(channel: string, data: unknown): void {\n this.broadcast(channel, data);\n\n // Check for wildcard subscribers: \"prefix:*\" matches \"prefix:anything\"\n // Send with the actual channel name so wildcard subscribers know the source.\n const colonIdx = channel.indexOf(':');\n if (colonIdx > 0) {\n const wildcardChannel = channel.substring(0, colonIdx) + ':*';\n const subs = this.channels.get(wildcardChannel);\n if (!subs || subs.size === 0) return;\n\n const msg = truncateIfOversized(\n JSON.stringify({ type: 'event', channel, data }),\n channel,\n data,\n );\n for (const ws of [...subs]) {\n if (this.filter) {\n const metadata = this.connections.get(ws)?.metadata;\n try {\n if (!this.filter(data, metadata)) continue;\n } catch {\n continue;\n }\n }\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n }\n }\n }\n }\n\n /** Close all connections, clear all state and buffers. Used during shutdown. */\n closeAll(): void {\n for (const ws of this.connections.keys()) {\n ws.close?.();\n }\n for (const buffer of this.buffers.values()) {\n if (buffer.timer) clearTimeout(buffer.timer);\n }\n this.connections.clear();\n this.channels.clear();\n this.buffers.clear();\n }\n\n /** Get the number of active connections. */\n get connectionCount(): number {\n return this.connections.size;\n }\n\n /** Check if any connections are subscribed to a channel. */\n hasSubscribers(channel: string): boolean {\n return (this.channels.get(channel)?.size ?? 0) > 0;\n }\n}\n","import type { BroadcastTarget } from './connection-manager.js';\nimport { MAX_WS_FRAME_BYTES, type ConnectionManager } from './connection-manager.js';\n\n/** Channel prefixes that accept suffixes (e.g., execution:abc, trace:*). */\nconst VALID_CHANNEL_PREFIXES = ['execution:', 'trace:', 'eval:'];\n/** Channels that must match exactly (no suffix allowed). */\nconst VALID_EXACT_CHANNELS = ['costs', 'decisions', 'eval-trends', 'workflow-stats', 'trace-stats'];\nconst MAX_CHANNEL_LENGTH = 256;\n\n/**\n * Handle a single WebSocket message according to the Studio protocol.\n * Returns a JSON string to send back to the client, or null for no response.\n *\n * Used by both the Hono WS handler (ws/handler.ts) and the Node.js\n * middleware (middleware.ts) to keep the protocol in one place.\n */\nexport function handleWsMessage(\n raw: string,\n socket: BroadcastTarget,\n connMgr: ConnectionManager,\n): string | null {\n // Reject oversized messages. Shared cap with the outbound broadcast path\n // in connection-manager.ts — see `MAX_WS_FRAME_BYTES` for rationale.\n // Measure bytes (not UTF-16 code units) so multi-byte payloads (emoji /\n // CJK / other non-ASCII) can't pass `raw.length` while serializing past\n // 64KB on the wire — keeping symmetry with the outbound `Buffer.byteLength`\n // check in `connection-manager.ts:truncateIfOversized`.\n if (Buffer.byteLength(raw, 'utf8') > MAX_WS_FRAME_BYTES) {\n return JSON.stringify({ type: 'error', message: 'Message too large' });\n }\n\n let msg: { type: string; channel?: string };\n try {\n msg = JSON.parse(raw);\n } catch {\n return JSON.stringify({ type: 'error', message: 'Invalid JSON' });\n }\n\n switch (msg.type) {\n case 'subscribe': {\n const error = validateChannel(msg.channel);\n if (error) return JSON.stringify({ type: 'error', message: error });\n connMgr.subscribe(socket, msg.channel!);\n return JSON.stringify({ type: 'subscribed', channel: msg.channel });\n }\n case 'unsubscribe': {\n const error = validateChannel(msg.channel);\n if (error) return JSON.stringify({ type: 'error', message: error });\n connMgr.unsubscribe(socket, msg.channel!);\n return JSON.stringify({ type: 'unsubscribed', channel: msg.channel });\n }\n case 'ping':\n return JSON.stringify({ type: 'pong' });\n default:\n return JSON.stringify({ type: 'error', message: 'Unknown message type' });\n }\n}\n\nfunction validateChannel(channel: unknown): string | null {\n if (typeof channel !== 'string' || !channel) {\n return 'Missing or invalid channel';\n }\n if (channel.length > MAX_CHANNEL_LENGTH) {\n return `Channel name exceeds ${MAX_CHANNEL_LENGTH} characters`;\n }\n if (\n !VALID_EXACT_CHANNELS.includes(channel as (typeof VALID_EXACT_CHANNELS)[number]) &&\n !VALID_CHANNEL_PREFIXES.some((p) => channel.startsWith(p))\n ) {\n return `Invalid channel: ${channel}`;\n }\n return null;\n}\n","import type { WSContext } from 'hono/ws';\nimport type { ConnectionManager } from './connection-manager.js';\nimport { handleWsMessage } from './protocol.js';\n\n/** Create WS event handlers for a Hono WebSocket connection. */\nexport function createWsHandlers(connMgr: ConnectionManager) {\n return {\n onOpen(_event: Event, ws: WSContext) {\n connMgr.add(ws);\n },\n\n onMessage(event: MessageEvent, ws: WSContext) {\n const reply = handleWsMessage(String(event.data), ws, connMgr);\n if (reply) ws.send(reply);\n },\n\n onClose(_event: CloseEvent, ws: WSContext) {\n connMgr.remove(ws);\n },\n\n onError(_event: Event, ws: WSContext) {\n connMgr.remove(ws);\n },\n };\n}\n","import type { ConnectionManager } from '../ws/connection-manager.js';\n\nexport type WindowId = '24h' | '7d' | '30d' | 'all';\n\nexport type AggregateBroadcast<State> = {\n snapshots: Record<WindowId, State>;\n updatedAt: number;\n};\n\nconst WINDOW_MS: Record<WindowId, number> = {\n '24h': 24 * 60 * 60 * 1000,\n '7d': 7 * 24 * 60 * 60 * 1000,\n '30d': 30 * 24 * 60 * 60 * 1000,\n all: Number.POSITIVE_INFINITY,\n};\n\nexport function withinWindow(ts: number, window: WindowId, now: number): boolean {\n return ts >= now - WINDOW_MS[window];\n}\n\n/** Hardcoded rebuild interval — no env var or config surface in v1. */\nexport const REBUILD_INTERVAL_MS = 5 * 60_000;\n\nconst ALL_WINDOWS = new Set<string>(Object.keys(WINDOW_MS));\n\n/** Parse a `?window=` query param into a validated WindowId, defaulting to `7d`. */\nexport function parseWindowParam(raw?: string | null, fallback: WindowId = '7d'): WindowId {\n return raw && ALL_WINDOWS.has(raw) ? (raw as WindowId) : fallback;\n}\n\n/**\n * Holds per-window snapshots of an aggregate state and handles\n * window-filter logic and WebSocket broadcast.\n */\nexport class AggregateSnapshots<State> {\n private snapshots: Map<WindowId, State>;\n\n constructor(\n private windows: WindowId[],\n private emptyState: () => State,\n private connMgr: ConnectionManager,\n private channel: string,\n /** Optional transform applied to each window's state before WS broadcast.\n * Useful when the broadcast payload differs from the internal state\n * (e.g., stripping internal arrays and adding computed fields). */\n private broadcastTransform?: (state: State) => unknown,\n ) {\n this.snapshots = new Map(windows.map((w) => [w, emptyState()]));\n }\n\n /** Replace all snapshots atomically — used after a full rebuild. */\n replace(fresh: Map<WindowId, State>): void {\n this.snapshots = fresh;\n this.broadcast();\n }\n\n /** Apply a reducer update to every window where `ts` falls inside the window. */\n fold(ts: number, update: (prev: State) => State): void {\n const now = Date.now();\n let changed = false;\n for (const window of this.windows) {\n if (withinWindow(ts, window, now)) {\n const prev = this.snapshots.get(window)!;\n this.snapshots.set(window, update(prev));\n changed = true;\n }\n }\n if (changed) this.broadcast();\n }\n\n get(window: WindowId): State {\n return this.snapshots.get(window) ?? this.emptyState();\n }\n\n getAll(): Record<WindowId, State> {\n return Object.fromEntries(this.snapshots) as Record<WindowId, State>;\n }\n\n private broadcast(): void {\n const snapshots = this.broadcastTransform\n ? (Object.fromEntries(\n this.windows.map((w) => [w, this.broadcastTransform!(this.snapshots.get(w)!)]),\n ) as Record<WindowId, unknown>)\n : this.getAll();\n this.connMgr.broadcast(this.channel, {\n snapshots,\n updatedAt: Date.now(),\n });\n }\n}\n","import type { AxlRuntime, AxlEvent, ExecutionInfo } from '@axlsdk/axl';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { AggregateSnapshots, REBUILD_INTERVAL_MS, withinWindow } from './aggregate-snapshots.js';\nimport type { WindowId } from './aggregate-snapshots.js';\n\nexport type TraceReducer<State> = (acc: State, event: AxlEvent) => State;\n\nexport type TraceAggregatorOptions<State> = {\n runtime: AxlRuntime;\n connMgr: ConnectionManager;\n channel: string;\n reducer: TraceReducer<State>;\n emptyState: () => State;\n windows: WindowId[];\n /** Max executions to replay on rebuild. Default 2000. */\n executionCap?: number;\n /** Optional transform applied to each window's state before WS broadcast. */\n broadcastTransform?: (state: State) => unknown;\n};\n\n/**\n * Consumes AxlEvents from execution history and the live trace stream.\n * Maintains per-window aggregate snapshots via a pure reducer.\n */\nexport class TraceAggregator<State> {\n private snaps: AggregateSnapshots<State>;\n private interval?: ReturnType<typeof setInterval>;\n private listener?: (event: AxlEvent) => void;\n private options: TraceAggregatorOptions<State>;\n\n constructor(options: TraceAggregatorOptions<State>) {\n this.options = options;\n this.snaps = new AggregateSnapshots(\n options.windows,\n options.emptyState,\n options.connMgr,\n options.channel,\n options.broadcastTransform,\n );\n }\n\n async start(): Promise<void> {\n await this.rebuild();\n this.listener = (event: AxlEvent) => {\n this.snaps.fold(event.timestamp, (prev) => this.options.reducer(prev, event));\n };\n this.options.runtime.on('trace', this.listener);\n this.interval = setInterval(\n () => this.rebuild().catch((err) => console.error('[axl-studio] rebuild failed:', err)),\n REBUILD_INTERVAL_MS,\n );\n }\n\n async rebuild(): Promise<void> {\n const executions: ExecutionInfo[] = await this.options.runtime.getExecutions();\n const cap = this.options.executionCap ?? 2000;\n const capped = executions.slice(0, cap);\n const now = Date.now();\n const fresh = new Map<WindowId, State>(\n this.options.windows.map((w) => [w, this.options.emptyState()]),\n );\n for (const exec of capped) {\n for (const event of exec.events) {\n for (const window of this.options.windows) {\n if (withinWindow(event.timestamp, window, now)) {\n fresh.set(window, this.options.reducer(fresh.get(window)!, event));\n }\n }\n }\n }\n this.snaps.replace(fresh);\n }\n\n getSnapshot(window: WindowId): State {\n return this.snaps.get(window);\n }\n\n getAllSnapshots(): Record<WindowId, State> {\n return this.snaps.getAll();\n }\n\n close(): void {\n if (this.listener) this.options.runtime.off('trace', this.listener);\n if (this.interval) clearInterval(this.interval);\n }\n}\n","import type { AxlRuntime, AxlEvent, ExecutionInfo } from '@axlsdk/axl';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { AggregateSnapshots, REBUILD_INTERVAL_MS, withinWindow } from './aggregate-snapshots.js';\nimport type { WindowId } from './aggregate-snapshots.js';\n\nexport type ExecutionReducer<State> = (acc: State, execution: ExecutionInfo) => State;\n\nexport type ExecutionAggregatorOptions<State> = {\n runtime: AxlRuntime;\n connMgr: ConnectionManager;\n channel: string;\n reducer: ExecutionReducer<State>;\n emptyState: () => State;\n windows: WindowId[];\n /** Max executions to replay on rebuild. Default 2000. */\n executionCap?: number;\n /** Optional transform applied to each window's state before WS broadcast. */\n broadcastTransform?: (state: State) => unknown;\n};\n\n/**\n * Consumes ExecutionInfo at the execution granularity (not individual trace events).\n * Live updates arrive via workflow_end trace events — the aggregator fetches the\n * finalized ExecutionInfo and folds it.\n */\nexport class ExecutionAggregator<State> {\n private snaps: AggregateSnapshots<State>;\n private interval?: ReturnType<typeof setInterval>;\n private listener?: (event: AxlEvent) => void;\n private options: ExecutionAggregatorOptions<State>;\n /** Generation counter to prevent stale async fold after rebuild. */\n private generation = 0;\n\n constructor(options: ExecutionAggregatorOptions<State>) {\n this.options = options;\n this.snaps = new AggregateSnapshots(\n options.windows,\n options.emptyState,\n options.connMgr,\n options.channel,\n options.broadcastTransform,\n );\n }\n\n async start(): Promise<void> {\n await this.rebuild();\n this.listener = (event: AxlEvent) => {\n if (event.type !== 'workflow_end') return;\n // Capture generation before the async gap\n const gen = this.generation;\n this.options.runtime\n .getExecution(event.executionId)\n .then((exec) => {\n // Skip if a rebuild happened between event and resolution\n if (this.generation !== gen) return;\n if (exec) {\n this.snaps.fold(exec.startedAt, (prev) => this.options.reducer(prev, exec));\n }\n })\n .catch((err) => console.error('[axl-studio] execution fold failed:', err));\n };\n this.options.runtime.on('trace', this.listener);\n this.interval = setInterval(\n () => this.rebuild().catch((err) => console.error('[axl-studio] rebuild failed:', err)),\n REBUILD_INTERVAL_MS,\n );\n }\n\n async rebuild(): Promise<void> {\n this.generation++;\n const executions: ExecutionInfo[] = await this.options.runtime.getExecutions();\n const cap = this.options.executionCap ?? 2000;\n const capped = executions.slice(0, cap);\n const now = Date.now();\n const fresh = new Map<WindowId, State>(\n this.options.windows.map((w) => [w, this.options.emptyState()]),\n );\n for (const exec of capped) {\n for (const window of this.options.windows) {\n if (withinWindow(exec.startedAt, window, now)) {\n fresh.set(window, this.options.reducer(fresh.get(window)!, exec));\n }\n }\n }\n this.snaps.replace(fresh);\n }\n\n getSnapshot(window: WindowId): State {\n return this.snaps.get(window);\n }\n\n getAllSnapshots(): Record<WindowId, State> {\n return this.snaps.getAll();\n }\n\n close(): void {\n if (this.listener) this.options.runtime.off('trace', this.listener);\n if (this.interval) clearInterval(this.interval);\n }\n}\n","import type { AxlRuntime, EvalHistoryEntry } from '@axlsdk/axl';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { AggregateSnapshots, REBUILD_INTERVAL_MS, withinWindow } from './aggregate-snapshots.js';\nimport type { WindowId } from './aggregate-snapshots.js';\n\nexport type EvalReducer<State> = (acc: State, entry: EvalHistoryEntry) => State;\n\nexport type EvalAggregatorOptions<State> = {\n runtime: AxlRuntime;\n connMgr: ConnectionManager;\n channel: string;\n reducer: EvalReducer<State>;\n emptyState: () => State;\n windows: WindowId[];\n /** Max eval entries to replay on rebuild. Default 500. */\n entryCap?: number;\n /** Optional transform applied to each window's state before WS broadcast. */\n broadcastTransform?: (state: State) => unknown;\n};\n\n/**\n * Consumes EvalHistoryEntry. Rebuilds from runtime.getEvalHistory().\n * Live updates arrive via runtime.on('eval_result', entry).\n */\nexport class EvalAggregator<State> {\n private snaps: AggregateSnapshots<State>;\n private interval?: ReturnType<typeof setInterval>;\n private listener?: (entry: EvalHistoryEntry) => void;\n private options: EvalAggregatorOptions<State>;\n\n constructor(options: EvalAggregatorOptions<State>) {\n this.options = options;\n this.snaps = new AggregateSnapshots(\n options.windows,\n options.emptyState,\n options.connMgr,\n options.channel,\n options.broadcastTransform,\n );\n }\n\n async start(): Promise<void> {\n await this.rebuild();\n this.listener = (entry: EvalHistoryEntry) => {\n this.snaps.fold(entry.timestamp, (prev) => this.options.reducer(prev, entry));\n };\n this.options.runtime.on('eval_result', this.listener);\n this.interval = setInterval(\n () => this.rebuild().catch((err) => console.error('[axl-studio] rebuild failed:', err)),\n REBUILD_INTERVAL_MS,\n );\n }\n\n async rebuild(): Promise<void> {\n const history: EvalHistoryEntry[] = await this.options.runtime.getEvalHistory();\n const cap = this.options.entryCap ?? 500;\n const capped = history.slice(0, cap);\n const now = Date.now();\n const fresh = new Map<WindowId, State>(\n this.options.windows.map((w) => [w, this.options.emptyState()]),\n );\n for (const entry of capped) {\n for (const window of this.options.windows) {\n if (withinWindow(entry.timestamp, window, now)) {\n fresh.set(window, this.options.reducer(fresh.get(window)!, entry));\n }\n }\n }\n this.snaps.replace(fresh);\n }\n\n getSnapshot(window: WindowId): State {\n return this.snaps.get(window);\n }\n\n getAllSnapshots(): Record<WindowId, State> {\n return this.snaps.getAll();\n }\n\n close(): void {\n if (this.listener) this.options.runtime.off('eval_result', this.listener);\n if (this.interval) clearInterval(this.interval);\n }\n}\n","/**\n * Pure reducer functions for each aggregate panel.\n * Each reducer is a pure (state, source) => state function — no I/O, no mutation.\n */\nimport type { AxlEvent, ExecutionInfo, EvalHistoryEntry } from '@axlsdk/axl';\nimport { eventCostContribution } from '@axlsdk/axl';\nimport type { CostData } from '../types.js';\n\n// ── Shared helpers ────────────────────────────────────────────────────\n\n/** Clamp a possibly-NaN/Infinity number to 0. */\nconst finite = (v: number | undefined): number => (Number.isFinite(v) ? v! : 0);\n\n// ── Cost reducer (AxlEvent → CostData) ──────────────────────────────\n\nfunction emptyRetry(): CostData['retry'] {\n return {\n primary: 0,\n primaryCalls: 0,\n schema: 0,\n schemaCalls: 0,\n validate: 0,\n validateCalls: 0,\n guardrail: 0,\n guardrailCalls: 0,\n retryCalls: 0,\n };\n}\n\nexport function emptyCostData(): CostData {\n return {\n totalCost: 0,\n totalTokens: { input: 0, output: 0, reasoning: 0 },\n byAgent: {},\n byModel: {},\n byWorkflow: {},\n retry: emptyRetry(),\n byEmbedder: {},\n };\n}\n\n/**\n * Pure reducer for CostData with full parity to CostAggregator.onTrace.\n * Handles retry decomposition, embedder cost bucketing, workflow_start\n * detection (both production log-form and test runtime shapes), and\n * NaN/Infinity guards on all numeric accumulations.\n */\nexport function reduceCost(acc: CostData, event: AxlEvent): CostData {\n const isWorkflowStart = event.type === 'workflow_start';\n\n // workflow_start events increment per-workflow executions and return early.\n // They carry no meaningful cost — any cost/token fields are incidental.\n if (isWorkflowStart && event.workflow) {\n const byWorkflow = { ...acc.byWorkflow };\n const prev = byWorkflow[event.workflow] ?? { cost: 0, executions: 0 };\n byWorkflow[event.workflow] = { ...prev, executions: prev.executions + 1 };\n return { ...acc, byWorkflow };\n }\n\n // Early return for events with no cost data.\n if (event.cost == null && !event.tokens) return acc;\n\n // Rollup guard: `eventCostContribution` encapsulates the spec §10\n // \"skip ask_end, finite-check, leaf-only\" invariant. The rest of\n // this reducer buckets the charge across per-agent / per-model /\n // per-workflow views; calling the helper once here keeps the\n // semantics in one place. If the contribution is 0 (ask_end or\n // NaN), short-circuit so we don't increment call counts either.\n const cost = eventCostContribution(event);\n if (event.type === 'ask_end') return acc;\n const tokens = event.tokens ?? {};\n\n // Only count tokens from agent_call_end events — embedder tokens are\n // bucketed separately into byEmbedder.tokens.\n const totalTokens =\n event.type === 'agent_call_end'\n ? {\n input: acc.totalTokens.input + finite(tokens.input),\n output: acc.totalTokens.output + finite(tokens.output),\n reasoning: acc.totalTokens.reasoning + finite(tokens.reasoning),\n }\n : acc.totalTokens;\n\n const byAgent = { ...acc.byAgent };\n if (event.agent) {\n const prev = byAgent[event.agent] ?? { cost: 0, calls: 0 };\n byAgent[event.agent] = { cost: prev.cost + cost, calls: prev.calls + 1 };\n }\n\n const byModel = { ...acc.byModel };\n if (event.model) {\n const prev = byModel[event.model] ?? { cost: 0, calls: 0, tokens: { input: 0, output: 0 } };\n byModel[event.model] = {\n cost: prev.cost + cost,\n calls: prev.calls + 1,\n tokens: {\n input: prev.tokens.input + finite(tokens.input),\n output: prev.tokens.output + finite(tokens.output),\n },\n };\n }\n\n const byWorkflow = { ...acc.byWorkflow };\n if (event.workflow) {\n const prev = byWorkflow[event.workflow] ?? { cost: 0, executions: 0 };\n byWorkflow[event.workflow] = {\n cost: prev.cost + cost,\n executions: prev.executions + (isWorkflowStart ? 1 : 0),\n };\n }\n\n // Retry-cost decomposition: split agent_call_end cost by retryReason.\n let retry = acc.retry;\n if (event.type === 'agent_call_end') {\n const d = (event.data ?? {}) as { retryReason?: 'schema' | 'validate' | 'guardrail' };\n const reason = d.retryReason;\n retry = { ...acc.retry };\n if (reason === 'schema') {\n retry.schema += cost;\n retry.schemaCalls += 1;\n retry.retryCalls += 1;\n } else if (reason === 'validate') {\n retry.validate += cost;\n retry.validateCalls += 1;\n retry.retryCalls += 1;\n } else if (reason === 'guardrail') {\n retry.guardrail += cost;\n retry.guardrailCalls += 1;\n retry.retryCalls += 1;\n } else {\n retry.primary += cost;\n retry.primaryCalls += 1;\n }\n }\n\n // Embedder cost: `memory_remember` / `memory_recall` variants carry\n // `usage.{tokens,model}` and a top-level `cost` (mirrored by the\n // emitter). Bucket by embedder model so the Cost Dashboard's\n // \"Memory (Embedder)\" section can break down spend.\n let byEmbedder = acc.byEmbedder;\n if (event.type === 'memory_remember' || event.type === 'memory_recall') {\n const usage = event.data.usage;\n byEmbedder = { ...acc.byEmbedder };\n const modelKey = usage?.model ?? 'unknown';\n const embedTokens = typeof usage?.tokens === 'number' ? finite(usage.tokens) : 0;\n const prev = byEmbedder[modelKey] ?? { cost: 0, calls: 0, tokens: 0 };\n byEmbedder[modelKey] = {\n cost: prev.cost + cost,\n calls: prev.calls + 1,\n tokens: prev.tokens + embedTokens,\n };\n }\n\n return {\n totalCost: acc.totalCost + cost,\n totalTokens,\n byAgent,\n byModel,\n byWorkflow,\n retry,\n byEmbedder,\n };\n}\n\n// ── Eval trends reducer (EvalHistoryEntry → EvalTrendData) ────────────\n\nexport type EvalTrendRun = {\n timestamp: number;\n id: string;\n scores: Record<string, number>;\n cost: number;\n /** Primary model for this run (first entry of `metadata.models`). Undefined\n * when the run has no recorded models (e.g., legacy data or test harnesses). */\n model?: string;\n /** Total run duration in ms (from `EvalResult.duration`). */\n duration?: number;\n};\n\nexport type EvalTrendEntry = {\n runs: EvalTrendRun[];\n latestScores: Record<string, number>;\n scoreMean: Record<string, number>;\n scoreStd: Record<string, number>;\n costTotal: number;\n runCount: number;\n};\n\nexport type EvalTrendData = {\n byEval: Record<string, EvalTrendEntry>;\n totalRuns: number;\n totalCost: number;\n};\n\nexport function emptyEvalTrendData(): EvalTrendData {\n return { byEval: {}, totalRuns: 0, totalCost: 0 };\n}\n\n/** Extract per-scorer aggregate score from an EvalHistoryEntry's data blob.\n * The EvalResult shape is `{ summary: { scorers: Record<string, { mean, min,\n * max, p50, p95 }> }, ... }`. We take `mean` as the representative score for\n * each scorer in this run — what gets plotted on the trend line. */\nfunction extractScores(data: unknown): Record<string, number> {\n if (!data || typeof data !== 'object') return {};\n const result = data as Record<string, unknown>;\n const summary = result.summary as Record<string, unknown> | undefined;\n const scorers = summary?.scorers as Record<string, { mean?: number } | number> | undefined;\n if (!scorers) return {};\n const out: Record<string, number> = {};\n for (const [name, entry] of Object.entries(scorers)) {\n if (typeof entry === 'number' && Number.isFinite(entry)) {\n out[name] = entry;\n } else if (entry && typeof entry === 'object' && Number.isFinite(entry.mean)) {\n out[name] = entry.mean as number;\n }\n }\n return out;\n}\n\n/** Extract total cost from an EvalHistoryEntry's data blob.\n * `EvalResult.totalCost` is at the top level (not under summary). */\nfunction extractCost(data: unknown): number {\n if (!data || typeof data !== 'object') return 0;\n const result = data as Record<string, unknown>;\n if (Number.isFinite(result.totalCost)) return result.totalCost as number;\n // Back-compat: some early tests/fixtures put it under summary.totalCost\n const summary = result.summary as Record<string, unknown> | undefined;\n return Number.isFinite(summary?.totalCost) ? (summary!.totalCost as number) : 0;\n}\n\n/** Extract the primary model for this run.\n * Prefers the most-called model from `metadata.modelCounts`, falling back to\n * `metadata.models[0]`. Returns undefined if no model is recorded — UI groups\n * those runs under \"unknown\". For a mixed-model run (e.g., classify-then-answer),\n * the most-called model is the honest \"primary\" choice. */\nfunction extractModel(data: unknown): string | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const result = data as Record<string, unknown>;\n const metadata = result.metadata as { models?: unknown; modelCounts?: unknown } | undefined;\n const counts = metadata?.modelCounts;\n if (counts && typeof counts === 'object' && !Array.isArray(counts)) {\n const entries = Object.entries(counts as Record<string, unknown>).filter(\n ([, v]) => typeof v === 'number',\n ) as Array<[string, number]>;\n if (entries.length > 0) {\n // Secondary alphabetical sort breaks ties deterministically so two\n // runs with the same modelCounts (e.g., { a: 3, b: 3 } vs { b: 3, a: 3 })\n // always resolve to the same \"primary model\" regardless of insertion order.\n entries.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));\n return entries[0][0];\n }\n }\n const models = metadata?.models;\n if (Array.isArray(models) && typeof models[0] === 'string') return models[0];\n return undefined;\n}\n\n/** Extract run duration in ms from `EvalResult.duration`. */\nfunction extractDuration(data: unknown): number | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const result = data as Record<string, unknown>;\n return Number.isFinite(result.duration) ? (result.duration as number) : undefined;\n}\n\n/** Compute mean and std for score arrays. */\nfunction computeScoreStats(runs: EvalTrendRun[]): {\n mean: Record<string, number>;\n std: Record<string, number>;\n} {\n const scorerNames = new Set<string>();\n for (const run of runs) {\n for (const name of Object.keys(run.scores)) scorerNames.add(name);\n }\n\n const mean: Record<string, number> = {};\n const std: Record<string, number> = {};\n for (const name of scorerNames) {\n const values = runs.map((r) => r.scores[name]).filter((v) => v != null);\n if (values.length === 0) continue;\n const m = values.reduce((a, b) => a + b, 0) / values.length;\n mean[name] = m;\n const variance = values.reduce((sum, v) => sum + (v - m) ** 2, 0) / values.length;\n std[name] = Math.sqrt(variance);\n }\n return { mean, std };\n}\n\nexport function reduceEvalTrends(acc: EvalTrendData, entry: EvalHistoryEntry): EvalTrendData {\n const scores = extractScores(entry.data);\n const cost = extractCost(entry.data);\n const model = extractModel(entry.data);\n const duration = extractDuration(entry.data);\n const run: EvalTrendRun = {\n timestamp: entry.timestamp,\n id: entry.id,\n scores,\n cost,\n ...(model !== undefined ? { model } : {}),\n ...(duration !== undefined ? { duration } : {}),\n };\n\n const byEval = { ...acc.byEval };\n const prev = byEval[entry.eval];\n // Cap runs array to limit WS broadcast payload size. Client only shows\n // the 10 most recent; keep 50 for future chart use.\n const MAX_EVAL_RUNS = 50;\n const allRuns = prev ? [...prev.runs, run] : [run];\n const runs = allRuns.length > MAX_EVAL_RUNS ? allRuns.slice(-MAX_EVAL_RUNS) : allRuns;\n const { mean, std } = computeScoreStats(runs);\n\n // latestScores is the most recent run's scores by timestamp.\n // During rebuild, entries arrive newest-first, so only overwrite if\n // there's no existing entry or this run is newer.\n const latestScores =\n prev && prev.runs.length > 0 && prev.runs[prev.runs.length - 1].timestamp > run.timestamp\n ? prev.latestScores\n : scores;\n\n byEval[entry.eval] = {\n runs,\n latestScores,\n scoreMean: mean,\n scoreStd: std,\n costTotal: (prev?.costTotal ?? 0) + cost,\n runCount: (prev?.runCount ?? 0) + 1,\n };\n\n return {\n byEval,\n totalRuns: acc.totalRuns + 1,\n totalCost: acc.totalCost + cost,\n };\n}\n\n// ── Workflow stats reducer (ExecutionInfo → WorkflowStatsData) ────────\n\n/** Max recent durations to keep per workflow for percentile computation. */\nconst MAX_DURATIONS = 200;\n\nexport type WorkflowStatsData = {\n byWorkflow: Record<\n string,\n {\n total: number;\n completed: number;\n failed: number;\n /** Bounded sorted array of recent durations for p50/p95. Max MAX_DURATIONS entries. */\n durations: number[];\n durationSum: number;\n avgDuration: number;\n }\n >;\n totalExecutions: number;\n failureRate: number;\n};\n\nexport function emptyWorkflowStatsData(): WorkflowStatsData {\n return { byWorkflow: {}, totalExecutions: 0, failureRate: 0 };\n}\n\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const idx = (p / 100) * (sorted.length - 1);\n const lower = Math.floor(idx);\n const upper = Math.ceil(idx);\n if (lower === upper) return sorted[lower];\n return sorted[lower] + (sorted[upper] - sorted[lower]) * (idx - lower);\n}\n\nexport function reduceWorkflowStats(\n acc: WorkflowStatsData,\n execution: ExecutionInfo,\n): WorkflowStatsData {\n const byWorkflow = { ...acc.byWorkflow };\n const prev = byWorkflow[execution.workflow] ?? {\n total: 0,\n completed: 0,\n failed: 0,\n durations: [],\n durationSum: 0,\n avgDuration: 0,\n };\n\n // Maintain a bounded sorted array for percentile computation.\n // Insert in sorted position, evict the smallest (front) if over cap.\n // This biases toward recent larger values — acceptable for dashboard use.\n const dur = finite(execution.duration);\n const durations = [...prev.durations];\n const insertIdx = durations.findIndex((d) => d > dur);\n if (insertIdx === -1) durations.push(dur);\n else durations.splice(insertIdx, 0, dur);\n if (durations.length > MAX_DURATIONS) durations.shift();\n\n const total = prev.total + 1;\n const completed = prev.completed + (execution.status === 'completed' ? 1 : 0);\n const failed = prev.failed + (execution.status === 'failed' ? 1 : 0);\n const durationSum = prev.durationSum + dur;\n const avgDuration = durationSum / total;\n\n byWorkflow[execution.workflow] = {\n total,\n completed,\n failed,\n durations,\n durationSum,\n avgDuration,\n };\n\n const totalExecutions = acc.totalExecutions + 1;\n const totalFailed = Object.values(byWorkflow).reduce((sum, w) => sum + w.failed, 0);\n const failureRate = totalExecutions > 0 ? totalFailed / totalExecutions : 0;\n\n return { byWorkflow, totalExecutions, failureRate };\n}\n\n/** Get p50/p95 from a WorkflowStatsData entry. Durations are pre-sorted. */\nexport function getWorkflowPercentiles(entry: WorkflowStatsData['byWorkflow'][string]): {\n durationP50: number;\n durationP95: number;\n} {\n // Durations are maintained in sorted order by the reducer\n return {\n durationP50: percentile(entry.durations, 50),\n durationP95: percentile(entry.durations, 95),\n };\n}\n\n/** Enrich raw WorkflowStatsData with computed percentiles for API/WS consumers.\n * Strips the internal `durations` and `durationSum` fields to keep payloads lean. */\nexport function enrichWorkflowStats(data: WorkflowStatsData) {\n const byWorkflow: Record<\n string,\n {\n total: number;\n completed: number;\n failed: number;\n durationP50: number;\n durationP95: number;\n avgDuration: number;\n }\n > = {};\n for (const [name, entry] of Object.entries(data.byWorkflow)) {\n const { durationP50, durationP95 } = getWorkflowPercentiles(entry);\n byWorkflow[name] = {\n total: entry.total,\n completed: entry.completed,\n failed: entry.failed,\n durationP50,\n durationP95,\n avgDuration: entry.avgDuration,\n };\n }\n return {\n byWorkflow,\n totalExecutions: data.totalExecutions,\n failureRate: data.failureRate,\n };\n}\n\n// ── Trace stats reducer (AxlEvent → TraceStatsData) ────────────────\n\nexport type TraceStatsData = {\n eventTypeCounts: Record<string, number>;\n byTool: Record<string, { calls: number; denied: number; approved: number }>;\n retryByAgent: Record<string, { schema: number; validate: number; guardrail: number }>;\n totalEvents: number;\n};\n\nexport function emptyTraceStatsData(): TraceStatsData {\n return {\n eventTypeCounts: {},\n byTool: {},\n retryByAgent: {},\n totalEvents: 0,\n };\n}\n\nexport function reduceTraceStats(acc: TraceStatsData, event: AxlEvent): TraceStatsData {\n const eventTypeCounts = { ...acc.eventTypeCounts };\n eventTypeCounts[event.type] = (eventTypeCounts[event.type] ?? 0) + 1;\n\n const byTool = { ...acc.byTool };\n if (\n event.type === 'tool_call_end' ||\n event.type === 'tool_denied' ||\n event.type === 'tool_approval'\n ) {\n const toolName = event.tool;\n const prev = byTool[toolName] ?? { calls: 0, denied: 0, approved: 0 };\n // tool_denied: legacy event for \"tool not available\" path. data.approved\n // distinguishes approvals (true) from denials (absent/false).\n // tool_approval: distinct event from the approval gate with data.approved.\n const isDeniedEvent = event.type === 'tool_denied';\n const isApprovalEvent = event.type === 'tool_approval';\n const eventData =\n isDeniedEvent || isApprovalEvent\n ? (event.data as { approved?: boolean } | undefined)\n : undefined;\n const isApproved =\n (isDeniedEvent && eventData?.approved === true) ||\n (isApprovalEvent && eventData?.approved === true);\n const isDenied =\n (isDeniedEvent && !eventData?.approved) || (isApprovalEvent && eventData?.approved === false);\n byTool[toolName] = {\n calls: prev.calls + (event.type === 'tool_call_end' ? 1 : 0),\n denied: prev.denied + (isDenied ? 1 : 0),\n approved: prev.approved + (isApproved ? 1 : 0),\n };\n }\n\n const retryByAgent = { ...acc.retryByAgent };\n if (event.agent && event.type === 'agent_call_end') {\n const data = event.data as { retryReason?: string } | undefined;\n if (data?.retryReason) {\n const prev = retryByAgent[event.agent] ?? { schema: 0, validate: 0, guardrail: 0 };\n const reason = data.retryReason as 'schema' | 'validate' | 'guardrail';\n if (reason in prev) {\n retryByAgent[event.agent] = { ...prev, [reason]: prev[reason] + 1 };\n }\n }\n }\n\n return {\n eventTypeCounts,\n byTool,\n retryByAgent,\n totalEvents: acc.totalEvents + 1,\n };\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nexport function createHealthRoutes(readOnly: boolean) {\n const app = new Hono<StudioEnv>();\n\n app.get('/health', (c) => {\n const runtime = c.get('runtime');\n return c.json({\n ok: true,\n data: {\n status: 'healthy',\n readOnly,\n workflows: runtime.getWorkflowNames().length,\n agents: runtime.getAgents().length,\n tools: runtime.getTools().length,\n },\n });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, WorkflowSummary } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { redactStreamEvent, redactValue } from '../redact.js';\n\nexport function createWorkflowRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // List all workflows\n app.get('/workflows', (c) => {\n const runtime = c.get('runtime');\n const workflows: WorkflowSummary[] = runtime.getWorkflows().map((w) => ({\n name: w.name,\n hasInputSchema: !!w.inputSchema,\n hasOutputSchema: !!w.outputSchema,\n }));\n return c.json({ ok: true, data: workflows });\n });\n\n // Get workflow detail (including schemas)\n app.get('/workflows/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const workflow = runtime.getWorkflow(name);\n if (!workflow) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Workflow \"${name}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: {\n name: workflow.name,\n inputSchema: workflow.inputSchema ? zodToJsonSchema(workflow.inputSchema) : null,\n outputSchema: workflow.outputSchema ? zodToJsonSchema(workflow.outputSchema) : null,\n },\n });\n });\n\n // Execute a workflow\n app.post('/workflows/:name/execute', async (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n\n const workflow = runtime.getWorkflow(name);\n if (!workflow) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Workflow \"${name}\" not found` } },\n 404,\n );\n }\n\n const body = await c.req.json<{\n input?: unknown;\n stream?: boolean;\n metadata?: Record<string, unknown>;\n }>();\n\n if (body.stream) {\n // Streaming execution — pipe events to WS channel. Under\n // `trace.redact`, scrub each StreamEvent before broadcast so\n // token deltas, tool args/results, and the final `done.data`\n // don't leak raw LLM/user content to WS subscribers.\n // TODO(PR-3-spec-16): the wire emits AxlEvent directly after PR 3 and\n // `redactStreamEvent` is replaced with an AxlEvent-aware scrubber.\n const stream = runtime.stream(name, body.input ?? {}, { metadata: body.metadata });\n const executionId = `stream-${Date.now()}`;\n const redactOn = runtime.isRedactEnabled();\n\n // Forward stream events to WS (error events flow through the iterator)\n (async () => {\n for await (const event of stream) {\n connMgr.broadcastWithWildcard(\n `execution:${executionId}`,\n redactStreamEvent(event, redactOn),\n );\n }\n })();\n\n return c.json({ ok: true, data: { executionId, streaming: true } });\n }\n\n const result = await runtime.execute(name, body.input ?? {}, { metadata: body.metadata });\n return c.json({\n ok: true,\n data: { result: redactValue(result, runtime.isRedactEnabled()) },\n });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport { redactExecutionInfo, redactExecutionList } from '../redact.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all executions\napp.get('/executions', async (c) => {\n const runtime = c.get('runtime');\n const executions = await runtime.getExecutions();\n return c.json({\n ok: true,\n data: redactExecutionList(executions, runtime.isRedactEnabled()),\n });\n});\n\n// Get execution by ID.\n//\n// Supports `?since={step}` pagination (spec/16 §5.4) — filters\n// `events` to those with `step > since`. `step` is monotonic\n// per-execution and shared across nested asks (spec §3.7), so\n// polling clients can request only the tail since their last known\n// step without missing events from concurrent branches.\n//\n// Polling pattern: client tracks `lastStep = events[events.length - 1]?.step`\n// and passes `?since=<lastStep>` on the next poll. First poll either\n// omits `since` or passes `-1` for \"everything from step 0 onward\" —\n// `since=0` explicitly means \"I already have step 0, give me step 1+\".\n// This preserves correctness when `workflow_start` lands at step 0.\n//\n// Malformed `since` (non-integer / non-finite) returns 400 — stale or\n// buggy clients get a clear diagnostic instead of silently receiving\n// the full events array and blowing their memory budget.\napp.get('/executions/:id', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const execution = await runtime.getExecution(id);\n if (!execution) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Execution \"${id}\" not found` } },\n 404,\n );\n }\n\n const sinceParam = c.req.query('since');\n let paged = execution;\n if (sinceParam !== undefined) {\n const since = Number(sinceParam);\n // Accept any finite integer, including -1 for \"everything\". Reject\n // NaN, Infinity, fractions, and non-numeric strings with a 400.\n if (!Number.isFinite(since) || !Number.isInteger(since)) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'INVALID_PARAM',\n message: `\\`since\\` must be a finite integer (got \"${sinceParam}\")`,\n param: 'since',\n },\n },\n 400,\n );\n }\n paged = {\n ...execution,\n events: execution.events.filter((e) => e.step > since),\n };\n }\n\n return c.json({\n ok: true,\n data: redactExecutionInfo(paged, runtime.isRedactEnabled()),\n });\n});\n\n// Abort a running execution\napp.post('/executions/:id/abort', (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n runtime.abort(id);\n return c.json({ ok: true, data: { aborted: true } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv, SessionSummary } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { redactSessionHistory } from '../redact.js';\n\nexport function createSessionRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // List all sessions\n app.get('/sessions', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n if (!store.listSessions) {\n return c.json({ ok: true, data: [] });\n }\n const ids = await store.listSessions();\n const sessions: SessionSummary[] = [];\n for (const id of ids) {\n const history = await store.getSession(id);\n sessions.push({ id, messageCount: history.length });\n }\n // List endpoint carries no message content — just id + count.\n // Nothing to redact.\n return c.json({ ok: true, data: sessions });\n });\n\n // Get session history\n app.get('/sessions/:id', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const id = c.req.param('id');\n const history = await store.getSession(id);\n const handoffHistory = await store.getSessionMeta(id, 'handoffHistory');\n return c.json({\n ok: true,\n data: {\n id,\n history: redactSessionHistory(history, runtime.isRedactEnabled()),\n // HandoffRecord has no content fields (source/target/mode/\n // timestamp/duration) — nothing to scrub.\n handoffHistory: handoffHistory ?? [],\n },\n });\n });\n\n // Send message to session (non-streaming)\n app.post('/sessions/:id/send', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const body = await c.req.json<{ message: string; workflow: string }>();\n\n const session = runtime.session(id);\n const result = await session.send(body.workflow, body.message);\n return c.json({ ok: true, data: { result } });\n });\n\n // Stream session message\n app.post('/sessions/:id/stream', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const body = await c.req.json<{ message: string; workflow: string }>();\n\n const session = runtime.session(id);\n const stream = await session.stream(body.workflow, body.message);\n const executionId = `session-${id}-${Date.now()}`;\n\n // Forward stream events to WS (error events flow through the iterator)\n (async () => {\n for await (const event of stream) {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, event);\n }\n })();\n\n return c.json({ ok: true, data: { executionId, streaming: true } });\n });\n\n // Delete session\n app.delete('/sessions/:id', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const id = c.req.param('id');\n await store.deleteSession(id);\n return c.json({ ok: true, data: { deleted: true } });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, AgentSummary } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all agents\napp.get('/agents', (c) => {\n const runtime = c.get('runtime');\n const agents: AgentSummary[] = runtime.getAgents().map((a) => ({\n name: a._name,\n model: a.resolveModel(),\n system: a.resolveSystem(),\n tools: a._config.tools?.map((t) => t.name) ?? [],\n handoffs:\n typeof a._config.handoffs === 'function'\n ? ['(dynamic)']\n : (a._config.handoffs?.map((h) => h.agent._name) ?? []),\n maxTurns: a._config.maxTurns,\n temperature: a._config.temperature,\n maxTokens: a._config.maxTokens,\n effort: a._config.effort,\n thinkingBudget: a._config.thinkingBudget,\n includeThoughts: a._config.includeThoughts,\n toolChoice: a._config.toolChoice,\n stop: a._config.stop,\n }));\n return c.json({ ok: true, data: agents });\n});\n\n// Get agent detail\napp.get('/agents/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const agent = runtime.getAgent(name);\n if (!agent) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Agent \"${name}\" not found` } },\n 404,\n );\n }\n\n const cfg = agent._config;\n return c.json({\n ok: true,\n data: {\n name: agent._name,\n model: agent.resolveModel(),\n system: agent.resolveSystem(),\n tools:\n cfg.tools?.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: zodToJsonSchema(t.inputSchema),\n })) ?? [],\n handoffs:\n typeof cfg.handoffs === 'function'\n ? [\n {\n agent: '(dynamic)',\n description: 'Resolved at runtime from metadata',\n mode: 'oneway' as const,\n },\n ]\n : (cfg.handoffs?.map((h) => ({\n agent: h.agent._name,\n description: h.description,\n mode: h.mode ?? 'oneway',\n })) ?? []),\n maxTurns: cfg.maxTurns,\n temperature: cfg.temperature,\n maxTokens: cfg.maxTokens,\n effort: cfg.effort,\n thinkingBudget: cfg.thinkingBudget,\n includeThoughts: cfg.includeThoughts,\n toolChoice: cfg.toolChoice,\n stop: cfg.stop,\n timeout: cfg.timeout,\n maxContext: cfg.maxContext,\n version: cfg.version,\n mcp: cfg.mcp,\n mcpTools: cfg.mcpTools,\n hasGuardrails: !!cfg.guardrails,\n guardrails: cfg.guardrails\n ? {\n hasInput: !!cfg.guardrails.input,\n hasOutput: !!cfg.guardrails.output,\n onBlock: cfg.guardrails.onBlock ?? 'throw',\n maxRetries: cfg.guardrails.maxRetries,\n }\n : null,\n },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, ToolSummary } from '../types.js';\nimport { redactValue } from '../redact.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all tools\napp.get('/tools', (c) => {\n const runtime = c.get('runtime');\n const tools: ToolSummary[] = runtime.getTools().map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema ? zodToJsonSchema(t.inputSchema) : {},\n sensitive: t.sensitive ?? false,\n requireApproval: t.requireApproval ?? false,\n }));\n return c.json({ ok: true, data: tools });\n});\n\n// Get tool detail\napp.get('/tools/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const tool = runtime.getTool(name);\n if (!tool) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Tool \"${name}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema ? zodToJsonSchema(tool.inputSchema) : {},\n sensitive: tool.sensitive,\n requireApproval: tool.requireApproval,\n retry: tool.retry,\n hasHooks: !!tool.hooks,\n hooks: tool.hooks\n ? {\n hasBefore: !!tool.hooks.before,\n hasAfter: !!tool.hooks.after,\n }\n : null,\n },\n });\n});\n\n// Test a tool directly\napp.post('/tools/:name/test', async (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const tool = runtime.getTool(name);\n if (!tool) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Tool \"${name}\" not found` } },\n 404,\n );\n }\n\n const body = await c.req.json<{ input: unknown }>();\n const ctx = runtime.createContext();\n const result = await tool.run(ctx, body.input);\n return c.json({\n ok: true,\n data: { result: redactValue(result, runtime.isRedactEnabled()) },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport { redactMemoryList, redactMemoryValue } from '../redact.js';\n\nconst app = new Hono<StudioEnv>();\n\n// Get all memory entries for a scope\napp.get('/memory/:scope', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n\n if (!store.getAllMemory) {\n return c.json({ ok: true, data: [] });\n }\n\n const entries = await store.getAllMemory(scope);\n return c.json({ ok: true, data: redactMemoryList(entries, runtime.isRedactEnabled()) });\n});\n\n// Get a specific memory entry\napp.get('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.getMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n const value = await store.getMemory(scope, key);\n if (value === null) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Memory \"${scope}/${key}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: { key, value: redactMemoryValue(value, runtime.isRedactEnabled()) },\n });\n});\n\n// Save a memory entry\napp.put('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.saveMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n const body = await c.req.json<{ value: unknown }>();\n await store.saveMemory(scope, key, body.value);\n return c.json({ ok: true, data: { saved: true } });\n});\n\n// Delete a memory entry\napp.delete('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.deleteMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n await store.deleteMemory(scope, key);\n return c.json({ ok: true, data: { deleted: true } });\n});\n\n// Semantic search\napp.post('/memory/search', async (c) => {\n // TODO: Connect to MemoryManager's vector search once exposed\n return c.json({\n ok: true,\n data: { results: [], message: 'Semantic search requires MemoryManager with vector store' },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport { redactPendingDecisionList } from '../redact.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List pending decisions\napp.get('/decisions', async (c) => {\n const runtime = c.get('runtime');\n const decisions = await runtime.getPendingDecisions();\n return c.json({\n ok: true,\n data: redactPendingDecisionList(decisions, runtime.isRedactEnabled()),\n });\n});\n\n// Resolve a pending decision\napp.post('/decisions/:executionId/resolve', async (c) => {\n const runtime = c.get('runtime');\n const executionId = c.req.param('executionId');\n const body = await c.req.json<{ approved: boolean; reason?: string }>();\n\n await runtime.resolveDecision(executionId, body);\n return c.json({ ok: true, data: { resolved: true } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { TraceAggregator } from '../aggregates/trace-aggregator.js';\nimport type { CostData } from '../types.js';\nimport { parseWindowParam } from '../aggregates/aggregate-snapshots.js';\n\nexport function createCostRoutes(costAggregator: TraceAggregator<CostData>) {\n const app = new Hono<StudioEnv>();\n\n app.get('/costs', (c) => {\n // Multi-window debug mode\n if (c.req.query('windows') === 'all') {\n return c.json({ ok: true, data: costAggregator.getAllSnapshots() });\n }\n\n const window = parseWindowParam(c.req.query('window'));\n return c.json({ ok: true, data: costAggregator.getSnapshot(window) });\n });\n\n // Migration stub for the removed `POST /api/costs/reset` endpoint.\n //\n // Pre-0.15 Studio exposed a mutating reset that cleared the in-memory cost\n // aggregator. In 0.15 the dashboard switched to time-window aggregates over\n // StateStore history, so \"reset\" is no longer meaningful — the displayed\n // window simply narrows. Scripts (CI dashboards, ops tooling) that still hit\n // this URL would otherwise get Hono's default 404 with no hint about the\n // migration path. Return a structured 410 Gone with a concrete pointer.\n app.post('/costs/reset', (c) => {\n return c.json(\n {\n ok: false,\n error: {\n code: 'GONE',\n message:\n 'POST /api/costs/reset was removed in @axlsdk/studio 0.15. ' +\n 'Cost aggregates are now time-windowed and rebuilt from StateStore history. ' +\n 'Use GET /api/costs?window=24h|7d|30d|all to narrow the view instead of resetting.',\n },\n },\n 410,\n );\n });\n\n return app;\n}\n","import { randomUUID } from 'node:crypto';\nimport { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport type { EvalResult, Scorer } from '@axlsdk/eval';\nimport { redactEvalHistoryList, redactEvalResult, redactErrorMessage } from '../redact.js';\n\nexport function createEvalRoutes(connMgr: ConnectionManager, evalLoader?: () => Promise<void>) {\n const app = new Hono<StudioEnv>();\n\n // Active streaming eval runs, keyed by evalRunId. Scoped per-middleware\n // instance so multiple `createStudioMiddleware()` mounts in the same process\n // (multi-tenant deployments, concurrent unit tests) don't collide on run IDs\n // or leak AbortControllers across middleware lifecycles.\n const activeRuns = new Map<string, AbortController>();\n\n // List registered eval configs\n app.get('/evals', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const evals = runtime.getRegisteredEvals();\n // Registered eval configs contain dataset definitions — the dataset\n // `.getItems()` contents aren't serialized in this response (we just\n // return names + scorer list), so there's no raw content to scrub.\n return c.json({ ok: true, data: evals });\n });\n\n // Get eval run history\n app.get('/evals/history', async (c) => {\n const runtime = c.get('runtime');\n const history = await runtime.getEvalHistory();\n return c.json({\n ok: true,\n data: redactEvalHistoryList(history, runtime.isRedactEnabled()),\n });\n });\n\n // Delete a single eval history entry by id.\n app.delete('/evals/history/:id', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const deleted = await runtime.deleteEvalResult(id);\n if (!deleted) {\n return c.json(\n {\n ok: false,\n error: { code: 'NOT_FOUND', message: `Eval history entry \"${id}\" not found` },\n },\n 404,\n );\n }\n return c.json({ ok: true, data: { id, deleted: true } });\n });\n\n // Run a registered eval by name.\n //\n // Body options:\n // runs?: number — multi-run count (capped at 25)\n // stream?: true — return evalRunId immediately, broadcast progress via WS\n //\n // When stream is false/absent, the endpoint blocks until the eval completes\n // and returns the full result (backward compatible).\n app.post('/evals/:name/run', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const redactOn = runtime.isRedactEnabled();\n\n const entry = runtime.getRegisteredEval(name);\n if (!entry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Eval \"${name}\" not found` } },\n 404,\n );\n }\n\n let runs = 1;\n let stream = false;\n let captureTraces = false;\n try {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n if (typeof body.runs === 'number' && Number.isFinite(body.runs) && body.runs > 1) {\n runs = Math.min(Math.floor(body.runs), 25);\n }\n if (body.stream === true) {\n stream = true;\n }\n if (body.captureTraces === true) {\n captureTraces = true;\n }\n } catch {\n // No body or invalid body — single run, synchronous\n }\n\n // ── Streaming mode ─────────────────────────────────────────────\n if (stream) {\n const evalRunId = `eval-${randomUUID()}`;\n const ac = new AbortController();\n activeRuns.set(evalRunId, ac);\n\n // Fire-and-forget async execution with WS progress broadcasting.\n //\n // NOTE on the done event shape: we deliberately broadcast only a\n // pointer (`evalResultId`, optional `runGroupId`) instead of the\n // full `EvalResult`. A real eval result with ~12 items, per-item\n // score details, and metadata easily exceeds 64KB, which is our\n // WS frame budget. When we previously embedded the whole result,\n // `truncateIfOversized` replaced it with a `{__truncated}` stub\n // and the client rendered a blank screen.\n //\n // Architecturally: WS events are for small notifications,\n // `runRegisteredEval` already persists results to history via the\n // StateStore, and the client can fetch the full payload from\n // `GET /api/evals/history` once notified. This matches the hint\n // text that the truncation placeholder already used to emit.\n (async () => {\n try {\n if (runs > 1) {\n const runGroupId = randomUUID();\n const results: EvalResult[] = [];\n\n for (let r = 0; r < runs; r++) {\n if (ac.signal.aborted) break;\n const result = (await runtime.runRegisteredEval(name, {\n metadata: { runGroupId, runIndex: r },\n signal: ac.signal,\n captureTraces,\n onProgress: (event) => {\n // Library-level `run_done` fires after every iteration with\n // `{ totalItems, failures }`; Studio emits its own wire-level\n // `run_done` below with `{ run, totalRuns }` semantics, so we\n // drop the library variant to avoid collision on the client.\n if (event.type === 'run_done') return;\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n ...event,\n run: r + 1,\n totalRuns: runs,\n });\n },\n })) as EvalResult;\n results.push(result);\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'run_done',\n run: r + 1,\n totalRuns: runs,\n });\n }\n\n if (results.length > 0) {\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'done',\n evalResultId: results[0].id,\n runGroupId,\n });\n } else {\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'error',\n message: 'All runs were cancelled',\n });\n }\n } else {\n const result = (await runtime.runRegisteredEval(name, {\n signal: ac.signal,\n captureTraces,\n onProgress: (event) => {\n // Drop library-level `run_done` — Studio's terminal signal for\n // single-run streams is the `done` event below, which carries\n // the `evalResultId` pointer the client uses to refetch.\n if (event.type === 'run_done') return;\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, event);\n },\n })) as EvalResult;\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'done',\n evalResultId: result.id,\n });\n }\n } catch (err) {\n // Eval-channel error event shape is NOT a `StreamEvent`, so it\n // doesn't pass through `redactStreamEvent`. Scrub the message\n // inline so ValidationError/GuardrailError/provider errors don't\n // leak user input on the eval:* channel under redact mode.\n // (StreamEvent itself is legacy — see TODO in redact.ts.)\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'error',\n message: redactErrorMessage(err, redactOn),\n });\n } finally {\n activeRuns.delete(evalRunId);\n }\n })();\n\n return c.json({ ok: true, data: { evalRunId } });\n }\n\n // ── Synchronous mode (backward compatible) ─────────────────────\n try {\n if (runs > 1) {\n const { aggregateRuns } = await import('@axlsdk/eval');\n const runGroupId = randomUUID();\n const results = [];\n for (let r = 0; r < runs; r++) {\n const result = await runtime.runRegisteredEval(name, {\n metadata: { runGroupId, runIndex: r },\n captureTraces,\n });\n results.push(result);\n }\n const typedResults = results as EvalResult[];\n const aggregate = aggregateRuns(typedResults);\n const first = typedResults[0]!;\n const result = {\n ...first,\n _multiRun: { aggregate, allRuns: typedResults },\n } as EvalResult;\n return c.json({\n ok: true,\n data: redactEvalResult(result, redactOn),\n });\n } else {\n // Runtime persists eval result to history automatically\n const result = (await runtime.runRegisteredEval(name, { captureTraces })) as EvalResult;\n return c.json({\n ok: true,\n data: redactEvalResult(result, redactOn),\n });\n }\n } catch (err) {\n // Inline error envelope — scrub to keep redaction semantics\n // consistent with the global `errorHandler` middleware.\n return c.json(\n { ok: false, error: { code: 'EVAL_ERROR', message: redactErrorMessage(err, redactOn) } },\n 400,\n );\n }\n });\n\n // Cancel an active streaming eval run.\n app.post('/evals/runs/:evalRunId/cancel', (c) => {\n const evalRunId = c.req.param('evalRunId');\n const ac = activeRuns.get(evalRunId);\n if (!ac) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: 'No active eval run found' } },\n 404,\n );\n }\n ac.abort();\n activeRuns.delete(evalRunId);\n return c.json({ ok: true, data: { cancelled: true } });\n });\n\n // Rescore: re-run scorers on saved outputs\n app.post('/evals/:name/rescore', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const redactOn = runtime.isRedactEnabled();\n const name = c.req.param('name');\n const body = await c.req.json<{ resultId: string }>();\n\n if (!body.resultId || typeof body.resultId !== 'string') {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'resultId is required' } },\n 400,\n );\n }\n\n const entry = runtime.getRegisteredEval(name);\n if (!entry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Eval \"${name}\" not found` } },\n 404,\n );\n }\n\n const history = await runtime.getEvalHistory();\n const historyEntry = history.find((h) => h.id === body.resultId);\n if (!historyEntry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Result \"${body.resultId}\" not found` } },\n 404,\n );\n }\n\n try {\n const { rescore } = await import('@axlsdk/eval');\n const config = entry.config as { scorers?: unknown[] };\n const result = await rescore(\n historyEntry.data as EvalResult,\n config.scorers as Scorer[],\n runtime,\n );\n await runtime.saveEvalResult({\n id: result.id,\n eval: name,\n timestamp: Date.now(),\n data: result,\n });\n return c.json({\n ok: true,\n data: redactEvalResult(result, redactOn),\n });\n } catch (err) {\n return c.json(\n { ok: false, error: { code: 'EVAL_ERROR', message: redactErrorMessage(err, redactOn) } },\n 400,\n );\n }\n });\n\n // Compare eval results by history ID.\n //\n // Accepts baselineId/candidateId as string (single run) or string[] (pooled\n // multi-run group). IDs are resolved from runtime history server-side so the\n // wire payload stays tiny — this avoids hitting host body-parser limits when\n // Studio is mounted as middleware behind Express/NestJS/Fastify.\n app.post('/evals/compare', async (c) => {\n const runtime = c.get('runtime');\n const redactOn = runtime.isRedactEnabled();\n const body = await c.req.json<{\n baselineId: string | string[];\n candidateId: string | string[];\n options?: { thresholds?: Record<string, number> | number };\n }>();\n\n // Validate ID shapes up front. Each side must be a non-empty string or a\n // non-empty array of non-empty strings. `!body.baselineId` would treat\n // `[]` as truthy, so check explicitly. We also reject arrays that contain\n // any non-string element (e.g. `[null]`), which would otherwise produce a\n // confusing \"Eval result(s) not found in history: null\" error downstream.\n //\n // DoS cap (reviewer HIGH H1): `evalCompare` pools items across all runs\n // for paired bootstrap CI (1000 resamples). An unbounded array lets a\n // readOnly attacker run 500-run × 100-item × 1000-resample comparisons\n // on each request. Cap at 25 to match the multi-run ceiling on\n // `POST /api/evals/:name/run`.\n const MAX_POOLED_RUNS = 25;\n const validateIdParam = (v: unknown, name: string): string | null => {\n if (typeof v === 'string') return v === '' ? `${name} must be non-empty` : null;\n if (Array.isArray(v)) {\n if (v.length === 0) return `${name} must be a non-empty array`;\n if (v.length > MAX_POOLED_RUNS) {\n return `${name} may contain at most ${MAX_POOLED_RUNS} ids (pooled comparison)`;\n }\n for (const elem of v) {\n if (typeof elem !== 'string' || elem === '') {\n return `${name} array must contain only non-empty strings`;\n }\n }\n return null;\n }\n return `${name} is required (string or string[])`;\n };\n const baselineErr = validateIdParam(body.baselineId, 'baselineId');\n const candidateErr = validateIdParam(body.candidateId, 'candidateId');\n if (baselineErr || candidateErr) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'BAD_REQUEST',\n message: [baselineErr, candidateErr].filter(Boolean).join('; '),\n },\n },\n 400,\n );\n }\n\n const history = await runtime.getEvalHistory();\n const byId = new Map(history.map((h) => [h.id, h.data as EvalResult]));\n\n const missing: string[] = [];\n const resolveOne = (id: string): EvalResult | undefined => {\n const data = byId.get(id);\n if (!data) missing.push(id);\n return data;\n };\n const resolveSelection = (\n idOrIds: string | string[],\n ): EvalResult | EvalResult[] | undefined => {\n if (Array.isArray(idOrIds)) {\n // Dedupe so callers passing [id, id] don't artificially shrink the\n // paired-bootstrap variance in downstream CI computation.\n const unique = Array.from(new Set(idOrIds));\n // Single-element groups are semantically equivalent to a single ID;\n // unwrap so evalCompare uses the simpler single-result code path\n // instead of the multi-run pooling path with one run.\n if (unique.length === 1) return resolveOne(unique[0]);\n const results: EvalResult[] = [];\n for (const id of unique) {\n const data = resolveOne(id);\n if (data) results.push(data);\n }\n return results;\n }\n return resolveOne(idOrIds);\n };\n\n const baseline = resolveSelection(body.baselineId);\n const candidate = resolveSelection(body.candidateId);\n\n if (missing.length > 0) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'NOT_FOUND',\n message: `Eval result(s) not found in history: ${missing.join(', ')}`,\n },\n },\n 404,\n );\n }\n\n try {\n // `missing.length === 0` guarantees both are defined here.\n const result = await runtime.evalCompare(baseline!, candidate!, body.options);\n return c.json({ ok: true, data: result });\n } catch (err) {\n return c.json(\n {\n ok: false,\n error: { code: 'COMPARE_FAILED', message: redactErrorMessage(err, redactOn) },\n },\n 400,\n );\n }\n });\n\n // Import a CLI eval artifact into runtime history.\n //\n // Accepts a parsed EvalResult JSON (typically produced by `axl-eval --output`).\n // Generates a fresh UUID for the history entry (overwriting result.id) so\n // repeated imports of the same file don't collide. The imported entry is\n // indistinguishable from a natively-run result in the history picker, run\n // detail view, and comparison flows.\n //\n // Note: this is the one Studio endpoint whose request bodies can be large.\n // If mounted as middleware and importing sizeable eval files, raise the\n // host framework's JSON body limit on the Studio mount.\n app.post('/evals/import', async (c) => {\n const runtime = c.get('runtime');\n const body = await c.req.json<{\n result: unknown;\n eval?: string;\n }>();\n\n const bad = (message: string) =>\n c.json({ ok: false, error: { code: 'BAD_REQUEST', message } }, 400);\n\n if (!body.result || typeof body.result !== 'object') {\n return bad('result is required');\n }\n\n const result = body.result as Record<string, unknown>;\n\n // Shape validation — catch obvious garbage early with a clear error,\n // rather than letting downstream compare/rescore throw with a confusing\n // stack. Keep the check narrow: verify the fields Studio actually reads.\n if (!Array.isArray(result.items)) {\n return bad('result.items must be an array');\n }\n if (typeof result.summary !== 'object' || result.summary == null) {\n return bad('result.summary must be an object');\n }\n if (typeof result.dataset !== 'string' || !result.dataset) {\n return bad('result.dataset must be a non-empty string (required for compare)');\n }\n const summary = result.summary as Record<string, unknown>;\n if (typeof summary.scorers !== 'object' || summary.scorers == null) {\n return bad('result.summary.scorers must be an object');\n }\n const summaryScorerNames = Object.keys(summary.scorers as Record<string, unknown>);\n\n // Verify that per-item score keys are covered by summary.scorers across\n // ALL items — a heterogeneous artifact where item[0] is well-formed but\n // item[N] references unknown scorers would otherwise break compare\n // downstream with a cryptic error.\n const items = result.items as Array<Record<string, unknown>>;\n const summaryScorerSet = new Set(summaryScorerNames);\n const uncoveredAcrossItems = new Set<string>();\n for (const item of items) {\n const itemScores = item?.scores;\n if (itemScores && typeof itemScores === 'object') {\n for (const name of Object.keys(itemScores as Record<string, unknown>)) {\n if (!summaryScorerSet.has(name)) uncoveredAcrossItems.add(name);\n }\n }\n }\n if (uncoveredAcrossItems.size > 0) {\n return bad(\n `item scores reference scorer(s) not in summary.scorers: ${[...uncoveredAcrossItems].join(', ')}`,\n );\n }\n\n // EvalResult has no eval-name field of its own — the name lives on the\n // history entry. Prefer an explicit body.eval (client may know the\n // registered eval name), then fall back to the first workflow observed\n // in metadata.workflows (primary workflow of the run), then to the\n // legacy top-level workflow field for pre-0.14 CLI artifacts, then to\n // a generic label.\n //\n // Normalize via trim() to reject strings that are whitespace-only or\n // empty (would otherwise silently fall through to the next branch).\n const trim = (v: unknown): string | undefined =>\n typeof v === 'string' && v.trim() !== '' ? v.trim() : undefined;\n\n // metadata.workflows is the canonical source post-0.14.\n const metadataObj =\n typeof result.metadata === 'object' && result.metadata != null\n ? (result.metadata as Record<string, unknown>)\n : {};\n const workflowsFromMeta = Array.isArray(metadataObj.workflows)\n ? (metadataObj.workflows as unknown[])\n : [];\n const primaryWorkflow = workflowsFromMeta.find((w): w is string => typeof w === 'string');\n\n const evalName =\n trim(body.eval) ??\n trim(primaryWorkflow) ??\n // Legacy fallback: pre-0.14 CLI artifacts had workflow at the top level.\n trim((result as { workflow?: unknown }).workflow) ??\n 'imported';\n\n const id = randomUUID();\n const timestamp = Date.now();\n\n // Overwrite id so repeated imports of the same file get distinct entries.\n // Default metadata to {} since downstream code assumes it exists\n // (e.g. evalCompare reads metadata.scorerTypes).\n const imported: EvalResult = {\n ...(result as unknown as EvalResult),\n id,\n metadata:\n typeof result.metadata === 'object' && result.metadata != null\n ? (result.metadata as Record<string, unknown>)\n : {},\n };\n\n await runtime.saveEvalResult({\n id,\n eval: evalName,\n timestamp,\n data: imported,\n });\n\n return c.json({ ok: true, data: { id, eval: evalName, timestamp } });\n });\n\n function closeActiveRuns() {\n for (const ac of activeRuns.values()) ac.abort();\n activeRuns.clear();\n }\n\n return { app, closeActiveRuns };\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { redactStreamEvent } from '../redact.js';\nimport type { AxlEvent } from '@axlsdk/axl';\n\nexport function createPlaygroundRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // Chat with an agent directly — no workflow required\n app.post('/playground/chat', async (c) => {\n const runtime = c.get('runtime');\n const body = await c.req.json<{\n sessionId?: string;\n message: string;\n agent?: string;\n }>();\n\n if (!body.message || typeof body.message !== 'string' || !body.message.trim()) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'INVALID_INPUT',\n message: 'message is required and must be a non-empty string',\n },\n },\n 400,\n );\n }\n\n const agents = runtime.getAgents();\n const agent = body.agent ? agents.find((a) => a._name === body.agent) : agents[0];\n if (!agent) {\n return c.json(\n {\n ok: false,\n error: { code: 'NO_AGENT', message: `Agent \"${body.agent ?? ''}\" not found` },\n },\n 400,\n );\n }\n\n const sessionId = body.sessionId ?? `playground-${Date.now()}`;\n const store = runtime.getStateStore();\n\n // Load session history for multi-turn conversations\n const history = await store.getSession(sessionId);\n history.push({ role: 'user', content: body.message });\n\n const redactOn = runtime.isRedactEnabled();\n\n // Create context — its auto-generated executionId becomes the WS channel name.\n // Token events flow through emitEvent → runtime.emit('trace') → our listener below,\n // so no manual onToken needed.\n const ctx = runtime.createContext({ sessionHistory: history });\n const executionId = ctx.executionId;\n\n // Forward ALL AxlEvents from this execution to the WS channel.\n // This gives the playground UI access to ask_start, agent_call, tool_call,\n // handoff, pipeline, etc. — not just tokens.\n const traceListener = (event: AxlEvent) => {\n if (event.executionId !== executionId) return;\n connMgr.broadcastWithWildcard(`execution:${executionId}`, redactStreamEvent(event, redactOn));\n };\n runtime.on('trace', traceListener);\n\n // Run the agent ask asynchronously, stream results via WS\n (async () => {\n let stepCounter = Number.MAX_SAFE_INTEGER - 1;\n const terminalFields = () => ({\n executionId,\n step: stepCounter++,\n timestamp: Date.now(),\n });\n\n try {\n const result = await ctx.ask(agent, body.message);\n const resultText = typeof result === 'string' ? result : JSON.stringify(result);\n\n history.push({ role: 'assistant', content: resultText });\n await store.saveSession(sessionId, history);\n\n const doneEvent: AxlEvent = {\n ...terminalFields(),\n type: 'done',\n data: { result: resultText },\n };\n connMgr.broadcastWithWildcard(\n `execution:${executionId}`,\n redactStreamEvent(doneEvent, redactOn),\n );\n } catch (err) {\n const errorEvent: AxlEvent = {\n ...terminalFields(),\n type: 'error',\n data: { message: err instanceof Error ? err.message : String(err) },\n };\n connMgr.broadcastWithWildcard(\n `execution:${executionId}`,\n redactStreamEvent(errorEvent, redactOn),\n );\n } finally {\n runtime.off('trace', traceListener);\n }\n })();\n\n return c.json({\n ok: true,\n data: { sessionId, executionId, streaming: true },\n });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { EvalAggregator } from '../aggregates/eval-aggregator.js';\nimport type { EvalTrendData } from '../aggregates/reducers.js';\nimport { parseWindowParam } from '../aggregates/aggregate-snapshots.js';\n\nexport function createEvalTrendsRoutes(aggregator: EvalAggregator<EvalTrendData>) {\n const app = new Hono<StudioEnv>();\n\n app.get('/eval-trends', (c) => {\n const window = parseWindowParam(c.req.query('window'));\n return c.json({ ok: true, data: aggregator.getSnapshot(window) });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { ExecutionAggregator } from '../aggregates/execution-aggregator.js';\nimport type { WorkflowStatsData } from '../aggregates/reducers.js';\nimport { enrichWorkflowStats } from '../aggregates/reducers.js';\nimport { parseWindowParam } from '../aggregates/aggregate-snapshots.js';\n\nexport function createWorkflowStatsRoutes(aggregator: ExecutionAggregator<WorkflowStatsData>) {\n const app = new Hono<StudioEnv>();\n\n app.get('/workflow-stats', (c) => {\n const window = parseWindowParam(c.req.query('window'));\n return c.json({ ok: true, data: enrichWorkflowStats(aggregator.getSnapshot(window)) });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { TraceAggregator } from '../aggregates/trace-aggregator.js';\nimport type { TraceStatsData } from '../aggregates/reducers.js';\nimport { parseWindowParam } from '../aggregates/aggregate-snapshots.js';\n\nexport function createTraceStatsRoutes(aggregator: TraceAggregator<TraceStatsData>) {\n const app = new Hono<StudioEnv>();\n\n app.get('/trace-stats', (c) => {\n const window = parseWindowParam(c.req.query('window'));\n return c.json({ ok: true, data: aggregator.getSnapshot(window) });\n });\n\n return app;\n}\n","import { resolve, relative, dirname, basename } from 'node:path';\nimport { readdirSync, statSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport { importModule } from './cli-utils.js';\n\n// In the CJS bundle, tsup stubs import.meta as {} so import.meta.url is\n// undefined. Fall back to __filename (which CJS defines) converted to a\n// file:// URL so tsImport() gets a valid parentURL.\nconst parentURL: string =\n import.meta.url ?? pathToFileURL(typeof __filename !== 'undefined' ? __filename : __dirname).href;\n\n/**\n * Configuration for lazy eval file discovery.\n *\n * - `string` — a glob pattern or explicit file path\n * - `string[]` — multiple patterns/paths\n * - `object` — patterns with optional import conditions\n */\nexport type EvalLoaderConfig =\n | string\n | string[]\n | {\n files: string | string[];\n\n /**\n * Custom Node.js import conditions (e.g., `['development']`).\n *\n * In monorepos, package.json `exports` often use the `development` condition\n * to point at source (`.ts`) instead of built dist. Without this, eval files\n * that import workspace packages resolve to dist files, which may not exist.\n *\n * **WARNING**: Conditions are registered process-wide via `module.register()`.\n * They affect all subsequent imports in the process, not just eval files.\n */\n conditions?: string[];\n };\n\n/**\n * Create a lazy eval loader that resolves file patterns and dynamically imports\n * eval files on first call, registering them with the runtime.\n *\n * The loader is idempotent — subsequent calls return the same promise.\n * Concurrent callers all await the same loading work.\n *\n * Eval files should export a default config with `{ workflow, dataset, scorers }`\n * (the result of `defineEval()` from `@axlsdk/eval`). An optional named export\n * `executeWorkflow` overrides the default `runtime.execute()` behavior.\n *\n * Eval names are the file's path relative to `cwd` (project root), minus the\n * `.eval.*` suffix. This makes names completely stable — a file's name never\n * changes regardless of what other files or patterns exist.\n *\n * @param config Glob patterns, file paths, or object with conditions\n * @param runtime The AxlRuntime to register discovered evals on\n * @param cwd Base directory for resolving patterns and deriving names (default: `process.cwd()`)\n */\nexport function createEvalLoader(\n config: EvalLoaderConfig,\n runtime: AxlRuntime,\n cwd?: string,\n): () => Promise<void> {\n let loadPromise: Promise<void> | undefined;\n const { patterns, conditions } = normalizeConfig(config);\n const baseCwd = cwd ?? process.cwd();\n\n return () => {\n if (!loadPromise) {\n loadPromise = loadEvalFiles(patterns, conditions, baseCwd, runtime).catch((err) => {\n loadPromise = undefined; // Allow retry on next request\n throw err;\n });\n }\n return loadPromise;\n };\n}\n\n// ── Core loading logic ─────────────────────────────────────────────\n\nasync function loadEvalFiles(\n patterns: string[],\n conditions: string[],\n cwd: string,\n runtime: AxlRuntime,\n): Promise<void> {\n if (conditions.length > 0) {\n await registerConditions(conditions);\n }\n\n const files = resolvePatterns(patterns, cwd);\n\n if (files.length === 0) {\n console.warn(`[axl-studio] No eval files found matching: ${patterns.join(', ')}`);\n return;\n }\n\n for (const file of files) {\n try {\n const mod = await importModule(file, parentURL);\n const evalConfig = mod.default?.default ?? mod.default ?? mod.config ?? mod;\n\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n console.warn(\n `[axl-studio] Skipping ${file}: not a valid eval config ` +\n `(missing workflow, dataset, or scorers)`,\n );\n continue;\n }\n\n const name = deriveEvalName(file, cwd);\n\n if (runtime.getRegisteredEval(name)) {\n console.warn(\n `[axl-studio] Eval name \"${name}\" from ${file} collides with an ` +\n `already-registered eval — overwriting`,\n );\n }\n\n runtime.registerEval(name, evalConfig, mod.executeWorkflow);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[axl-studio] Failed to load eval ${file}: ${msg}`);\n }\n }\n}\n\n// ── Internal helpers ───────────────────────────────────────────────\n\nfunction normalizeConfig(config: EvalLoaderConfig): {\n patterns: string[];\n conditions: string[];\n} {\n if (typeof config === 'string') {\n return { patterns: [config], conditions: [] };\n }\n if (Array.isArray(config)) {\n return { patterns: config, conditions: [] };\n }\n const files = typeof config.files === 'string' ? [config.files] : config.files;\n return { patterns: files, conditions: config.conditions ?? [] };\n}\n\n/**\n * Derive eval name from file path relative to cwd.\n *\n * Examples (cwd = `/project`):\n * - `/project/evals/suggestions.eval.ts` → `\"evals/suggestions\"`\n * - `/project/evals/api/accuracy.eval.ts` → `\"evals/api/accuracy\"`\n */\nfunction deriveEvalName(filePath: string, cwd: string): string {\n const rel = relative(cwd, filePath);\n // Normalize to forward slashes for cross-platform consistency\n const normalized = rel.replace(/\\\\/g, '/');\n // Guard: file outside cwd (symlink, absolute path) — fall back to basename\n if (normalized.startsWith('../')) {\n const base = basename(filePath);\n const stripped = base.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n return stripped !== base ? stripped : base.replace(/\\.[mc]?[jt]sx?$/, '') || base;\n }\n // Strip .eval.ts, .eval.mjs, .eval.js, etc.\n const withoutEval = normalized.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n if (withoutEval !== normalized) return withoutEval;\n // Fallback: strip extension\n const withoutExt = normalized.replace(/\\.[mc]?[jt]sx?$/, '');\n return withoutExt || normalized;\n}\n\n/**\n * Resolve patterns to absolute file paths.\n *\n * Supports:\n * - Explicit file paths (no wildcards)\n * - Single-directory globs: `dir/*.eval.ts`\n * - Recursive globs: `dir/**\\/*.eval.ts` or `**\\/*.eval.ts`\n *\n * Multi-segment `**` (e.g., `a/**\\/b/**\\/*.ts`) is not supported.\n */\nfunction resolvePatterns(patterns: string[], cwd: string): string[] {\n const files: string[] = [];\n const seen = new Set<string>();\n for (const pattern of patterns) {\n const resolved = pattern.includes('*') ? expandGlob(pattern, cwd) : [resolve(cwd, pattern)];\n for (const file of resolved) {\n if (!seen.has(file)) {\n seen.add(file);\n files.push(file);\n }\n }\n }\n return files;\n}\n\n/**\n * Expand a glob pattern to matching file paths.\n *\n * Supported forms:\n * - `dir/*.eval.ts` — match files in dir/\n * - `dir/**\\/*.eval.ts` — recursively match under dir/\n * - `**\\/*.eval.ts` — recursively match under cwd\n */\nfunction expandGlob(pattern: string, cwd: string): string[] {\n if (pattern.includes('**/')) {\n const sepIdx = pattern.indexOf('**/');\n const baseDir = resolve(cwd, pattern.slice(0, sepIdx) || '.');\n const fileGlob = pattern.slice(sepIdx + 3) || '*';\n return findFiles(baseDir, fileGlob, true);\n }\n\n const dir = resolve(cwd, dirname(pattern));\n const fileGlob = basename(pattern);\n return findFiles(dir, fileGlob, false);\n}\n\nconst MAX_DEPTH = 20;\n\nfunction findFiles(dir: string, fileGlob: string, recursive: boolean, depth = 0): string[] {\n if (depth > MAX_DEPTH) return [];\n const matcher = globToRegex(fileGlob);\n const results: string[] = [];\n\n try {\n const entries = readdirSync(dir);\n for (const entry of entries) {\n const full = resolve(dir, entry);\n try {\n const stat = statSync(full);\n if (stat.isFile() && matcher.test(entry)) {\n results.push(full);\n } else if (stat.isDirectory() && recursive) {\n results.push(...findFiles(full, fileGlob, true, depth + 1));\n }\n } catch {\n // Skip unreadable entries\n }\n }\n } catch {\n // Directory doesn't exist or unreadable\n }\n\n return results;\n}\n\n/** Convert a simple glob pattern (e.g., `*.eval.ts`) to a RegExp. */\nfunction globToRegex(glob: string): RegExp {\n const escaped = glob.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`);\n}\n\nasync function registerConditions(conditions: string[]): Promise<void> {\n try {\n const nodeModule = await import('node:module');\n const hookCode = [\n `const extra = ${JSON.stringify(conditions)};`,\n `export async function resolve(specifier, context, nextResolve) {`,\n ` return nextResolve(specifier, {`,\n ` ...context,`,\n ` conditions: [...new Set([...context.conditions, ...extra])],`,\n ` });`,\n `}`,\n ].join('\\n');\n nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);\n } catch {\n console.warn('[axl-studio] Warning: import conditions require Node.js 20.6+');\n }\n}\n","import { resolve } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\n\n// ── Config auto-detection ──────────────────────────────────────────\n\nexport const CONFIG_CANDIDATES = [\n 'axl.config.mts',\n 'axl.config.ts',\n 'axl.config.mjs',\n 'axl.config.js',\n];\n\nexport function findConfig(cwd: string): string | undefined {\n for (const name of CONFIG_CANDIDATES) {\n const p = resolve(cwd, name);\n if (existsSync(p)) return p;\n }\n return undefined;\n}\n\n// ── Parse CLI args ──────────────────────────────────────────────────\n\nexport interface CliArgs {\n port: number;\n config?: string;\n open: boolean;\n conditions: string[];\n readOnly: boolean;\n help: boolean;\n portError?: string;\n}\n\nexport function parseArgs(argv: string[]): CliArgs {\n let port = 4400;\n let config: string | undefined;\n let open = false;\n let help = false;\n let conditions: string[] = [];\n let readOnly = false;\n\n for (let i = 2; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === '--port' && argv[i + 1]) {\n port = parseInt(argv[i + 1], 10);\n i++;\n } else if (arg === '--config' && argv[i + 1]) {\n config = argv[i + 1];\n i++;\n } else if (arg === '--conditions' && argv[i + 1]) {\n conditions = argv[i + 1]\n .split(',')\n .map((c) => c.trim())\n .filter(Boolean);\n i++;\n } else if (arg === '--open') {\n open = true;\n } else if (arg === '--read-only' || arg === '--readonly') {\n readOnly = true;\n } else if (arg === '--help' || arg === '-h') {\n help = true;\n }\n }\n\n const result: CliArgs = { port, config, open, help, conditions, readOnly };\n\n if (isNaN(port) || port < 1 || port > 65535) {\n result.portError = `Invalid port: ${port}. Must be between 1 and 65535.`;\n }\n\n return result;\n}\n\n// ── Extension helpers ──────────────────────────────────────────────\n\n/**\n * Returns true if the file is TypeScript and needs tsx to load.\n */\nexport function needsTsxLoader(configPath: string): boolean {\n return /\\.[mc]?tsx?$/.test(configPath);\n}\n\n// ── Module loading ────────────────────────────────────────────────\n\n// Lazily resolved tsImport function from tsx. `undefined` = not yet checked,\n// `null` = tsx not available.\nlet tsImportFn:\n | ((specifier: string, parentURL: string) => Promise<Record<string, any>>)\n | null\n | undefined;\n\n/**\n * Import a module, using tsx's `tsImport()` for TypeScript files.\n *\n * `tsImport()` handles ESM/CJS format correctly without process-wide side effects —\n * no need for `register()` hooks or ESM-forcing workarounds. Falls back to regular\n * `import()` for non-TypeScript files or when tsx is not installed.\n */\nexport async function importModule(\n filePath: string,\n parentURL: string,\n): Promise<Record<string, any>> {\n if (needsTsxLoader(filePath)) {\n if (tsImportFn === undefined) {\n try {\n const mod = await import('tsx/esm/api');\n tsImportFn = mod.tsImport ?? null;\n } catch {\n tsImportFn = null;\n console.warn(\n '[axl-studio] Warning: tsx is not installed. TypeScript config files require tsx as a dependency.\\n' +\n ' Install it with: npm install -D tsx',\n );\n }\n }\n if (tsImportFn) {\n return (await tsImportFn(pathToFileURL(filePath).href, parentURL)) as Record<string, any>;\n }\n }\n return await import(pathToFileURL(filePath).href);\n}\n"],"mappings":"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","names":["import_node_path","import_node_fs","import_node_url","import_hono","import_axl","byWorkflow","app","import_hono","import_axl","app","import_hono","import_hono","app","import_hono","import_axl","app","import_hono","import_axl","app","import_hono","app","import_hono","app","import_hono","app","import_hono","app","result","import_hono","app","import_hono","app","import_hono","app","import_hono","app","app","import_node_path","import_node_fs","import_node_url","import_node_path","import_node_fs","parentURL","fileGlob","import_meta","app"]}
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts","../src/server/index.ts","../src/server/redact.ts","../src/server/middleware/error-handler.ts","../src/server/ws/connection-manager.ts","../src/server/ws/protocol.ts","../src/server/ws/handler.ts","../src/server/aggregates/aggregate-snapshots.ts","../src/server/aggregates/trace-aggregator.ts","../src/server/aggregates/execution-aggregator.ts","../src/server/aggregates/eval-aggregator.ts","../src/server/aggregates/reducers.ts","../src/server/routes/health.ts","../src/server/routes/workflows.ts","../src/server/routes/executions.ts","../src/server/routes/sessions.ts","../src/server/routes/agents.ts","../src/server/routes/tools.ts","../src/server/routes/memory.ts","../src/server/routes/decisions.ts","../src/server/routes/costs.ts","../src/server/routes/evals.ts","../src/server/routes/playground.ts","../src/server/routes/eval-trends.ts","../src/server/routes/workflow-stats.ts","../src/server/routes/trace-stats.ts","../src/eval-loader.ts"],"sourcesContent":["import { resolve, dirname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { getRequestListener } from '@hono/node-server';\nimport { WebSocketServer } from 'ws';\nimport { createServer } from './server/index.js';\nimport { handleWsMessage } from './server/ws/protocol.js';\nimport { createEvalLoader } from './eval-loader.js';\nimport type { EvalLoaderConfig } from './eval-loader.js';\nimport type { BufferCaps } from './server/ws/connection-manager.js';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport type { IncomingMessage, ServerResponse, Server } from 'node:http';\n\nexport type { EvalLoaderConfig } from './eval-loader.js';\nexport type { BufferCaps } from './server/ws/connection-manager.js';\n\nexport type StudioMiddlewareOptions = {\n /** The AxlRuntime instance to observe and control. */\n runtime: AxlRuntime;\n\n /**\n * URL path prefix where Studio is mounted.\n * Must match the mount path in your framework (Express `app.use()`,\n * Fastify `register()`, Hono `app.route()`, etc.). The framework is\n * expected to strip the prefix from `req.url` before calling the handler.\n *\n * Do not set basePath when using a raw `http.Server` as the root handler —\n * leave it empty and mount at root instead.\n *\n * Must start with '/' when non-empty. Trailing slashes are stripped.\n * Only URL-safe characters allowed: [a-zA-Z0-9/_-]\n *\n * @example '/studio'\n * @example '/admin/studio'\n * @example '' — mounted at root (default)\n */\n basePath?: string;\n\n /**\n * Serve the pre-built Studio SPA.\n * Set to false if serving the client from a CDN or separate build.\n * @default true\n */\n serveClient?: boolean;\n\n /**\n * Verify a WebSocket upgrade request before completing the handshake.\n *\n * Return either a boolean (`true` allow, `false` reject) or an object\n * `{ allowed: boolean, metadata?: unknown }` to ALSO attach per-connection\n * metadata that `filterTraceEvent` can later read — typically the auth\n * subject (userId, tenantId, role). Throw to reject with an error.\n *\n * IMPORTANT: WebSocket upgrades bypass Express/Fastify/Koa middleware.\n * If your HTTP routes are behind auth middleware, WS connections are NOT\n * automatically protected. Use this callback to enforce authentication\n * on WebSocket connections.\n *\n * @example Multi-tenant: extract tenant from JWT, attach as metadata\n * verifyUpgrade: async (req) => {\n * const token = req.headers.authorization?.slice(7);\n * const claims = await verifyJwt(token);\n * if (!claims) return false;\n * return { allowed: true, metadata: { userId: claims.sub, tenantId: claims.tid } };\n * }\n */\n verifyUpgrade?: (\n req: IncomingMessage,\n ) =>\n | boolean\n | { allowed: boolean; metadata?: unknown }\n | Promise<boolean | { allowed: boolean; metadata?: unknown }>;\n\n /**\n * Optional per-event filter used by multi-tenant deployments to scope the\n * trace firehose. Called on every outbound WebSocket broadcast; return\n * `true` to deliver to this connection, `false` to drop.\n *\n * `event` is the parsed event payload — for the `trace:*` channel this is\n * an `AxlEvent` from `@axlsdk/axl` (narrow via the discriminated union);\n * for `costs` it's a `CostData`; for `execution:*` / `eval:*` it's the\n * legacy stream-event shape (until PR 3 collapses the wire to `AxlEvent`).\n * Typed `unknown` because the filter runs for every channel.\n * `metadata` is the per-connection metadata attached by `verifyUpgrade`,\n * or `undefined` if `verifyUpgrade` returned a bare boolean.\n *\n * Filter errors are treated as `drop` (fail-closed) so a buggy predicate\n * cannot accidentally leak events cross-tenant.\n *\n * @example Scope trace events by tenant id stored on agent metadata\n * import type { AxlEvent } from '@axlsdk/axl';\n *\n * filterTraceEvent: (event, meta) => {\n * const m = meta as { tenantId?: string } | undefined;\n * if (!m?.tenantId) return false;\n * const e = event as AxlEvent;\n * // Only narrow event.type === 'agent_call_end' events; pass structural\n * // events (workflow_start/end, cost updates) through unconditionally.\n * if (e.type !== 'agent_call_end') return true;\n * return e.workflow?.startsWith(`${m.tenantId}:`) ?? false;\n * }\n */\n filterTraceEvent?: (event: unknown, metadata: unknown) => boolean;\n\n /**\n * Disable all mutating endpoints (execute, test, send, delete, resolve).\n * When true, Studio is observation-only.\n * @default false\n */\n readOnly?: boolean;\n\n /**\n * Lazy-load eval files for the Eval Runner panel.\n *\n * Eval files are dynamically imported on first access to eval endpoints,\n * not at middleware construction time. This means:\n * - Zero cost during normal API operation\n * - Eval files can import from any module without creating circular deps\n * in the static module graph (they're loaded as standalone entry points)\n * - `@axlsdk/eval` can remain a devDependency — eval files never enter\n * the production bundle since bundlers can't see dynamic imports\n *\n * Accepts glob patterns, explicit file paths, or an object with\n * `conditions` for monorepo source export resolution.\n *\n * Eval files are loaded once and cached for the middleware's lifetime.\n * Changes to eval files require a server restart.\n *\n * @example\n * // Single glob pattern\n * evals: 'evals/*.eval.ts'\n *\n * @example\n * // Multiple patterns\n * evals: ['libs/api/evals/*.eval.ts', 'libs/ai/evals/*.eval.ts']\n *\n * @example\n * // With import conditions for monorepo source exports\n * evals: {\n * files: 'libs/api/evals/*.eval.ts',\n * conditions: ['development'],\n * }\n */\n evals?: EvalLoaderConfig;\n\n /**\n * Override the default WebSocket replay-buffer resource caps for\n * production deployments under sustained execution churn.\n *\n * Defaults: `maxEventsPerBuffer: 1000`, `maxBytesPerBuffer: 4 MiB`,\n * `maxActiveBuffers: 256`. Worst-case memory is roughly\n * `maxActiveBuffers × maxBytesPerBuffer` (≈1 GiB at defaults). Tighten\n * either dimension to lower the ceiling at the cost of late-subscriber\n * replay coverage; raise them if you need more event headroom on long\n * verbose-mode streams.\n *\n * Terminal `done` / `error` events are always buffered regardless of\n * caps, so a late subscriber to a completed stream still sees the\n * outcome — only intermediate non-terminal events are dropped.\n *\n * All fields are optional; passing `{}` is a no-op.\n *\n * @example\n * // Halve memory ceiling on a high-churn deployment\n * bufferCaps: { maxActiveBuffers: 128, maxBytesPerBuffer: 2 * 1024 * 1024 }\n */\n bufferCaps?: BufferCaps;\n};\n\n/**\n * Minimal contract a WebSocket connection must satisfy.\n * Matches the `ws` library API (de facto standard in Node.js).\n */\nexport interface StudioWebSocket {\n send(data: string): void;\n close(): void;\n on(event: 'message', fn: (data: string | Buffer) => void): void;\n on(event: 'close', fn: () => void): void;\n on(event: 'error', fn: (err: Error) => void): void;\n}\n\n// Re-export for Hono-in-Hono consumers\nexport { handleWsMessage } from './server/ws/protocol.js';\n\nexport type StudioMiddleware = ReturnType<typeof createStudioMiddleware>;\n\nexport function createStudioMiddleware(options: StudioMiddlewareOptions) {\n const {\n runtime,\n serveClient = true,\n verifyUpgrade,\n readOnly = false,\n filterTraceEvent,\n } = options;\n\n // Normalize basePath: strip trailing slashes, validate format\n const basePath = normalizeBasePath(options.basePath);\n\n // Resolve pre-built SPA assets from this package's dist/\n const staticRoot = serveClient ? resolveClientDist() : undefined;\n\n if (serveClient && !staticRoot) {\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n console.warn(\n '[axl-studio] serveClient is true but no pre-built client found at ' +\n `${resolve(dir, 'client')}. Studio UI will not be available. ` +\n 'Set serveClient: false to suppress this warning.',\n );\n }\n\n // Create lazy eval loader if eval files are configured\n const evalLoader = options.evals ? createEvalLoader(options.evals, runtime) : undefined;\n\n const { app, connMgr, traceListener, closeActiveRuns, closeAggregators } = createServer({\n runtime,\n staticRoot,\n basePath,\n readOnly,\n cors: false, // Host framework owns CORS policy\n evalLoader,\n bufferCaps: options.bufferCaps,\n });\n\n // Install the broadcast filter once at construction time. The connMgr\n // applies it on every outbound event; `metadata` is attached to each\n // connection after a successful `verifyUpgrade`.\n if (filterTraceEvent) {\n connMgr.setFilter(filterTraceEvent);\n }\n\n // Log production safety warning\n if (process.env.NODE_ENV === 'production' && !verifyUpgrade) {\n console.warn(\n '[axl-studio] WARNING: Studio middleware mounted in production without verifyUpgrade. ' +\n 'WebSocket connections are not authenticated. All registered workflows, tools, and ' +\n 'agents are accessible. See https://axlsdk.com/docs/studio/security',\n );\n }\n\n // Convert Hono app → Node.js (req, res) handler via @hono/node-server.\n // overrideGlobalObjects: false prevents replacing global.Request/Response,\n // which could break the host application.\n const listener = getRequestListener(app.fetch, {\n overrideGlobalObjects: false,\n });\n\n let closed = false;\n\n function handler(req: IncomingMessage, res: ServerResponse) {\n if (closed) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'CLOSED', message: 'Studio middleware has been shut down' },\n }),\n );\n return;\n }\n\n // Express/NestJS/Koa body parsers consume the raw IncomingMessage stream\n // and store the parsed result on req.body. When that happens,\n // @hono/node-server's getRequestListener reads an empty stream and Hono\n // sees no body. To fix this, we re-serialize req.body as req.rawBody —\n // a Buffer that getRequestListener checks before falling back to the\n // stream (see newRequestFromIncoming in @hono/node-server/dist/listener.js).\n //\n // Verified against @hono/node-server@1.19.9. If this breaks after an\n // upgrade, check whether the rawBody instanceof Buffer check still exists\n // in newRequestFromIncoming.\n const reqAny = req as unknown as Record<string, unknown>;\n if (reqAny.body != null && !reqAny.rawBody) {\n try {\n reqAny.rawBody = Buffer.from(JSON.stringify(reqAny.body));\n } catch {\n // Non-serializable body — Hono will see an empty body\n }\n }\n\n listener(req, res).catch((err) => {\n console.error('[axl-studio] Unhandled error in request handler:', err);\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'INTERNAL_ERROR', message: 'Internal server error' },\n }),\n );\n }\n });\n }\n\n // Handle an individual WebSocket using the Studio protocol.\n // Adapts any StudioWebSocket to ConnectionManager's internal BroadcastTarget.\n // `metadata` is whatever `verifyUpgrade` attached — passed through so the\n // `filterTraceEvent` callback can read it on every outbound event.\n function handleWebSocket(ws: StudioWebSocket, metadata?: unknown) {\n if (closed) {\n ws.close();\n return;\n }\n const socket = {\n send: (data: string) => ws.send(data),\n close: () => ws.close(),\n };\n connMgr.add(socket);\n if (metadata !== undefined) {\n connMgr.setMetadata(socket, metadata);\n }\n\n ws.on('message', (raw) => {\n const reply = handleWsMessage(String(raw), socket, connMgr);\n if (reply) ws.send(reply);\n });\n\n ws.on('close', () => connMgr.remove(socket));\n ws.on('error', () => connMgr.remove(socket));\n }\n\n // Internal WebSocketServer — created lazily by upgradeWebSocket()\n let wss: InstanceType<typeof WebSocketServer> | undefined;\n // References for cleanup: the upgrade handler and server it's attached to\n let upgradeHandler: ((...args: any[]) => void) | undefined;\n let serverRef: Server | undefined;\n\n // Convenience: attach WS handling to an http.Server.\n function upgradeWebSocket(server: Server, path?: string) {\n if (wss) {\n throw new Error(\n '[axl-studio] upgradeWebSocket() has already been called. ' +\n 'Call close() first if you need to re-attach.',\n );\n }\n\n const wsPath = path ?? (basePath ? `${basePath}/ws` : '/ws');\n\n wss = new WebSocketServer({ noServer: true });\n serverRef = server;\n\n upgradeHandler = async (req: IncomingMessage, socket: any, head: Buffer) => {\n // Match path, ignoring query string\n const pathname = new URL(req.url!, `http://${req.headers.host}`).pathname;\n if (pathname !== wsPath) return; // Let other upgrade handlers run\n\n // Early-reject if close() already started. This is a cheap pre-check —\n // we repeat it AFTER the async verifyUpgrade resolves to close the race\n // where close() runs while verifyUpgrade is still in flight.\n if (closed) {\n socket.destroy();\n return;\n }\n\n // Apply auth verification and capture optional per-connection metadata\n // (e.g. { userId, tenantId }) that filterTraceEvent can later read.\n let connectionMetadata: unknown;\n if (verifyUpgrade) {\n try {\n const result = await verifyUpgrade(req);\n // Normalize both return shapes: plain boolean or { allowed, metadata }\n const allowed = typeof result === 'boolean' ? result : result.allowed;\n if (!allowed) {\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n if (typeof result === 'object' && result !== null) {\n connectionMetadata = result.metadata;\n }\n } catch {\n socket.write('HTTP/1.1 403 Forbidden\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n }\n\n // Guard against close() having run during async verifyUpgrade. We check\n // BOTH `closed` (set at the top of `close()`) and `!wss` (set at the\n // end). `closed` is the authoritative signal — checking `!wss` alone\n // wouldn't catch the window where `close()` has marked the middleware\n // as shut down but hasn't yet torn down the WebSocketServer. Failing\n // open here would leak a connection past the middleware's lifetime\n // and leave it holding references the host expected to be released.\n if (closed || !wss) {\n socket.destroy();\n return;\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n handleWebSocket(ws, connectionMetadata);\n });\n };\n\n server.on('upgrade', upgradeHandler);\n }\n\n // Cleanup function for lifecycle management.\n function close() {\n closed = true;\n\n // Abort active streaming eval runs before closing connections\n closeActiveRuns();\n\n // Close all WebSocket connections\n connMgr.closeAll();\n\n // Remove the upgrade listener from the server before closing WSS\n if (upgradeHandler && serverRef) {\n serverRef.removeListener('upgrade', upgradeHandler);\n upgradeHandler = undefined;\n serverRef = undefined;\n }\n\n // Shut down the internal WebSocketServer if one was created\n if (wss) {\n wss.close();\n wss = undefined;\n }\n\n // Remove only our trace event listener from the runtime\n if (traceListener) {\n runtime.removeListener('trace', traceListener);\n }\n\n // Close all aggregators (clear intervals and unsubscribe listeners)\n closeAggregators();\n }\n\n return {\n handler,\n handleWebSocket,\n upgradeWebSocket,\n app,\n connectionManager: connMgr,\n close,\n };\n}\n\n/**\n * Normalize and validate basePath.\n * - Empty string and undefined → ''\n * - Strip trailing slashes\n * - Validate leading slash when non-empty\n * - Reject unsafe characters\n */\nfunction normalizeBasePath(raw?: string): string {\n if (!raw) return '';\n\n // Strip trailing slashes\n const normalized = raw.replace(/\\/+$/, '');\n if (!normalized) return '';\n\n // Must start with /\n if (!normalized.startsWith('/')) {\n throw new Error(`basePath must start with '/' (got '${raw}'). Example: '/studio'`);\n }\n\n // Reject path traversal, consecutive slashes, and unsafe characters\n if (normalized.includes('..')) {\n throw new Error(`basePath must not contain '..' segments (got '${raw}')`);\n }\n if (normalized.includes('//')) {\n throw new Error(`basePath must not contain consecutive slashes (got '${raw}')`);\n }\n if (!/^\\/[a-zA-Z0-9/_-]*$/.test(normalized)) {\n throw new Error(\n `basePath contains invalid characters (got '${raw}'). ` +\n 'Only alphanumeric characters, /, _, and - are allowed.',\n );\n }\n\n return normalized;\n}\n\nfunction resolveClientDist(): string | undefined {\n // Resolve the directory of this file (dist/ in published package).\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n const candidate = resolve(dir, 'client');\n return existsSync(resolve(candidate, 'index.html')) ? candidate : undefined;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport type { AxlRuntime, AxlEvent } from '@axlsdk/axl';\nimport { redactStreamEvent } from './redact.js';\nimport type { StudioEnv } from './types.js';\nimport { errorHandler } from './middleware/error-handler.js';\nimport { ConnectionManager } from './ws/connection-manager.js';\nimport type { BufferCaps } from './ws/connection-manager.js';\nimport { createWsHandlers } from './ws/handler.js';\nimport { TraceAggregator } from './aggregates/trace-aggregator.js';\nimport { ExecutionAggregator } from './aggregates/execution-aggregator.js';\nimport { EvalAggregator } from './aggregates/eval-aggregator.js';\nimport {\n reduceCost,\n emptyCostData,\n reduceWorkflowStats,\n emptyWorkflowStatsData,\n enrichWorkflowStats,\n reduceTraceStats,\n emptyTraceStatsData,\n reduceEvalTrends,\n emptyEvalTrendData,\n} from './aggregates/reducers.js';\nimport type { WindowId } from './aggregates/aggregate-snapshots.js';\nimport { createHealthRoutes } from './routes/health.js';\nimport { createWorkflowRoutes } from './routes/workflows.js';\nimport executionRoutes from './routes/executions.js';\nimport { createSessionRoutes } from './routes/sessions.js';\nimport agentRoutes from './routes/agents.js';\nimport toolRoutes from './routes/tools.js';\nimport memoryRoutes from './routes/memory.js';\nimport decisionRoutes from './routes/decisions.js';\nimport { createCostRoutes } from './routes/costs.js';\nimport { createEvalRoutes } from './routes/evals.js';\nimport { createPlaygroundRoutes } from './routes/playground.js';\nimport { createEvalTrendsRoutes } from './routes/eval-trends.js';\nimport { createWorkflowStatsRoutes } from './routes/workflow-stats.js';\nimport { createTraceStatsRoutes } from './routes/trace-stats.js';\n\nexport type { StudioEnv } from './types.js';\nexport { ConnectionManager } from './ws/connection-manager.js';\nexport type { BroadcastTarget, BufferCaps } from './ws/connection-manager.js';\nexport { TraceAggregator } from './aggregates/trace-aggregator.js';\nexport { ExecutionAggregator } from './aggregates/execution-aggregator.js';\nexport { EvalAggregator } from './aggregates/eval-aggregator.js';\nexport type { WindowId, AggregateBroadcast } from './aggregates/aggregate-snapshots.js';\n\nexport type CreateServerOptions = {\n runtime: AxlRuntime;\n /** Root path for serving pre-built SPA static assets. */\n staticRoot?: string;\n /** Base URL path for client-side routing and API calls. Injected into index.html at serve time. */\n basePath?: string;\n /** When true, disable all mutating API endpoints. */\n readOnly?: boolean;\n /** Apply CORS headers. Default: true (standalone CLI). Set false for embedded middleware. */\n cors?: boolean;\n /** Lazy eval file loader. Called before eval routes access the runtime's registered evals. */\n evalLoader?: () => Promise<void>;\n /**\n * Override the default WS replay-buffer resource caps. All fields are\n * optional; omitted fields keep their documented defaults\n * (1000 events / 4 MiB per buffer, 256 concurrent buffers).\n */\n bufferCaps?: BufferCaps;\n};\n\nexport function createServer(options: CreateServerOptions) {\n const { runtime, staticRoot, basePath = '', readOnly = false } = options;\n const app = new Hono<StudioEnv>();\n const connMgr = new ConnectionManager(options.bufferCaps);\n const windows: WindowId[] = ['24h', '7d', '30d', 'all'];\n\n const costAggregator = new TraceAggregator({\n runtime,\n connMgr,\n channel: 'costs',\n reducer: reduceCost,\n emptyState: emptyCostData,\n windows,\n });\n\n const workflowStatsAggregator = new ExecutionAggregator({\n runtime,\n connMgr,\n channel: 'workflow-stats',\n reducer: reduceWorkflowStats,\n emptyState: emptyWorkflowStatsData,\n windows,\n broadcastTransform: enrichWorkflowStats,\n });\n\n const traceStatsAggregator = new TraceAggregator({\n runtime,\n connMgr,\n channel: 'trace-stats',\n reducer: reduceTraceStats,\n emptyState: emptyTraceStatsData,\n windows,\n });\n\n const evalTrendsAggregator = new EvalAggregator({\n runtime,\n connMgr,\n channel: 'eval-trends',\n reducer: reduceEvalTrends,\n emptyState: emptyEvalTrendData,\n windows,\n });\n\n // ── Middleware ──────────────────────────────────────────────────────\n if (options.cors !== false) {\n app.use('*', cors());\n }\n app.use('*', errorHandler);\n app.use('*', async (c, next) => {\n c.set('runtime', runtime);\n await next();\n });\n\n // ── Read-only mode ──────────────────────────────────────────────────\n if (readOnly) {\n // Patterns must be precise: POST /api/evals/compare is pure computation\n // and must remain allowed, but POST /api/evals/:name/run mutates history.\n const blocked: RegExp[] = [\n /^POST \\/api\\/workflows(\\/|$)/,\n /^POST \\/api\\/executions(\\/|$)/,\n /^POST \\/api\\/sessions(\\/|$)/,\n /^DELETE \\/api\\/sessions(\\/|$)/,\n /^PUT \\/api\\/memory(\\/|$)/,\n /^DELETE \\/api\\/memory(\\/|$)/,\n /^POST \\/api\\/decisions(\\/|$)/,\n /^POST \\/api\\/tools(\\/|$)/,\n /^POST \\/api\\/evals\\/import$/,\n /^POST \\/api\\/evals\\/[^/]+\\/run$/,\n /^POST \\/api\\/evals\\/[^/]+\\/rescore$/,\n /^POST \\/api\\/evals\\/runs\\/[^/]+\\/cancel$/,\n /^DELETE \\/api\\/evals\\/history\\/[^/]+$/,\n /^POST \\/api\\/playground(\\/|$)/,\n ];\n app.use('/api/*', async (c, next) => {\n // c.req.path returns the full path including any parent route prefix\n // (e.g., /studio/api/workflows when mounted via app.route('/studio', ...)).\n // Extract just the /api/... portion for matching.\n const apiIdx = c.req.path.indexOf('/api/');\n const apiPath = apiIdx >= 0 ? c.req.path.slice(apiIdx) : c.req.path;\n const key = `${c.req.method} ${apiPath}`;\n if (blocked.some((re) => re.test(key))) {\n return c.json(\n {\n ok: false,\n error: { code: 'READ_ONLY', message: 'Studio is mounted in read-only mode' },\n },\n 405,\n );\n }\n await next();\n });\n }\n\n // ── API Routes ─────────────────────────────────────────────────────\n const api = new Hono<StudioEnv>();\n api.route('/', createHealthRoutes(readOnly));\n api.route('/', createWorkflowRoutes(connMgr));\n api.route('/', executionRoutes);\n api.route('/', createSessionRoutes(connMgr));\n api.route('/', agentRoutes);\n api.route('/', toolRoutes);\n api.route('/', memoryRoutes);\n api.route('/', decisionRoutes);\n api.route('/', createCostRoutes(costAggregator));\n api.route('/', createEvalTrendsRoutes(evalTrendsAggregator));\n api.route('/', createWorkflowStatsRoutes(workflowStatsAggregator));\n api.route('/', createTraceStatsRoutes(traceStatsAggregator));\n const { app: evalApp, closeActiveRuns } = createEvalRoutes(connMgr, options.evalLoader);\n api.route('/', evalApp);\n api.route('/', createPlaygroundRoutes(connMgr));\n\n app.route('/api', api);\n\n // ── Trace event bridging ───────────────────────────────────────────\n // Aggregators subscribe to runtime events directly via their start() method.\n // This listener handles trace channel broadcasting and decision events only.\n // `isRedactEnabled()` is read per-event so a runtime that flips the flag\n // at runtime (not the common path, but possible) reflects immediately.\n const traceListener = (event: unknown) => {\n // Wrap the whole body in try/catch so a throw in `redactStreamEvent`\n // (malformed event shape) or `broadcastWithWildcard` (serialization\n // error) doesn't propagate back through `EventEmitter.emit('trace')`\n // and starve downstream listeners. Fail-loud to console.error so ops\n // sees it in logs but the runtime keeps going.\n try {\n const traceEvent = event as AxlEvent;\n\n // Broadcast to trace channels — apply the same scrubbing as the\n // playground/workflow execution paths so the trace firehose doesn't\n // leak content the per-route broadcasts are scrubbing.\n const redacted = redactStreamEvent(traceEvent, runtime.isRedactEnabled());\n if (traceEvent.executionId) {\n connMgr.broadcastWithWildcard(`trace:${traceEvent.executionId}`, redacted);\n }\n\n // Broadcast pending decisions. `await_human` is now a first-class\n // AxlEvent type (was a `log` variant before 0.16). Send the redacted\n // shape — `prompt` is user-visible LLM content that respects redact.\n if (traceEvent.type === 'await_human') {\n connMgr.broadcast('decisions', redacted);\n }\n } catch (err) {\n console.error(\n '[axl-studio] trace listener threw; event dropped:',\n err instanceof Error ? err.message : String(err),\n );\n }\n };\n runtime.on('trace', traceListener);\n\n // ── Start aggregators (rebuild from history + subscribe to live events) ──\n const aggregatorStartPromise = Promise.all([\n costAggregator.start(),\n workflowStatsAggregator.start(),\n traceStatsAggregator.start(),\n evalTrendsAggregator.start(),\n ]).catch((err) => console.error('[axl-studio] aggregator start failed:', err));\n\n // ── Static SPA serving (production) ────────────────────────────────\n if (staticRoot) {\n // Read index.html once at startup. When basePath is set, inject the <base>\n // tag and runtime config so asset paths and client-side routing work\n // regardless of whether the mount URL has a trailing slash.\n const indexPath = resolve(staticRoot, 'index.html');\n let spaHtml: string | undefined;\n\n if (!existsSync(indexPath)) {\n console.warn(`[axl-studio] index.html not found at ${indexPath}`);\n } else {\n const rawHtml = readFileSync(indexPath, 'utf-8');\n\n if (basePath) {\n // Escape '<' to prevent </script> in basePath from breaking out of\n // the script tag. JSON.stringify alone is insufficient because the\n // HTML parser processes </script> before JavaScript runs.\n const safeBasePath = JSON.stringify(basePath).replace(/</g, '\\\\u003c');\n const injected = rawHtml.replace(\n '<head>',\n `<head>\\n<base href=\"${basePath}/\">\\n` +\n `<script>window.__AXL_STUDIO_BASE__=${safeBasePath}</script>`,\n );\n\n if (injected === rawHtml) {\n console.warn(\n '[axl-studio] Could not inject basePath into index.html — ' +\n '<head> tag not found. The SPA may not route correctly.',\n );\n }\n spaHtml = injected;\n } else {\n spaHtml = rawHtml;\n }\n }\n\n // Serve static assets (JS, CSS, images). index.html is excluded so the\n // SPA fallback below always serves the version with basePath injection.\n // Without this guard, serveStatic would serve the raw index.html for root\n // requests (/ or /index.html), missing <base> and __AXL_STUDIO_BASE__.\n const staticHandler = serveStatic({\n root: staticRoot,\n rewriteRequestPath: basePath\n ? (path) => (path.startsWith(basePath) ? path.slice(basePath.length) || '/' : path)\n : undefined,\n });\n\n app.use('/*', async (c, next) => {\n const reqPath = c.req.path;\n const resolved =\n basePath && reqPath.startsWith(basePath) ? reqPath.slice(basePath.length) || '/' : reqPath;\n // Skip index.html (handled by SPA fallback) and /ws (handled by WebSocket upgrader)\n if (resolved === '/' || resolved === '/index.html' || resolved === '/ws') {\n return next();\n }\n return staticHandler(c, next);\n });\n\n // SPA fallback: serve the (possibly injected) index.html for all\n // non-API, non-static-asset routes so React Router handles routing.\n // Skip /ws so the WebSocket upgrader (registered after createServer) can handle it.\n if (spaHtml) {\n app.get('*', async (c, next) => {\n const resolved =\n basePath && c.req.path.startsWith(basePath)\n ? c.req.path.slice(basePath.length) || '/'\n : c.req.path;\n if (resolved === '/ws') return next();\n return c.html(spaHtml!);\n });\n }\n }\n\n return {\n app,\n connMgr,\n costAggregator,\n workflowStatsAggregator,\n traceStatsAggregator,\n evalTrendsAggregator,\n aggregatorStartPromise,\n /** Create WS handlers. Call before registering static/SPA routes are reached. */\n createWsHandlers: () => createWsHandlers(connMgr),\n traceListener,\n /** Abort all active streaming eval runs. */\n closeActiveRuns,\n /** Close all aggregators (clear intervals and unsubscribe listeners). */\n closeAggregators: () => {\n costAggregator.close();\n workflowStatsAggregator.close();\n traceStatsAggregator.close();\n evalTrendsAggregator.close();\n },\n };\n}\n","/**\n * Server-side redaction for observability responses.\n *\n * `config.trace.redact` was originally scoped to trace events emitted via\n * `emitTrace()` — it scrubs user/LLM content in prompts, responses, memory\n * values, tool args, etc. But data returned through Studio's REST surface\n * (execution results, memory values, session history) bypassed trace\n * emission entirely and leaked raw content even when trace redaction was\n * on. That inconsistency made \"compliance mode\" misleading: a user would\n * see `[redacted]` in the Trace Explorer timeline and then see raw user\n * data in the sibling Result pane, Memory Browser, or Session Manager.\n *\n * The right user mental model for this config is \"what can the observability\n * layer see?\". We keep the config name `trace.redact` but broaden its scope\n * at the REST read boundary to also scrub:\n *\n * - `ExecutionInfo.result` / `.error` (/api/executions, /api/executions/:id)\n * - Memory values (/api/memory/:scope, /api/memory/:scope/:key)\n * - Session message content + tool call arguments (/api/sessions/:id)\n *\n * Structural metadata (workflow names, agent names, tool names, keys, IDs,\n * timestamps, cost/token metrics) is preserved so the Trace Explorer,\n * Memory Browser, and Session Manager still render useful context when\n * compliance mode is on.\n *\n * Programmatic callers of `runtime.execute()` and direct StateStore access\n * still receive raw values — redaction is an *observability boundary* filter,\n * not a data-at-rest transform. If a user needs scrubbed state-at-rest they\n * configure their own StateStore to store scrubbed values.\n */\nimport type {\n ExecutionInfo,\n ChatMessage,\n PendingDecision,\n AxlEvent,\n EvalHistoryEntry,\n} from '@axlsdk/axl';\nimport { redactEvent } from '@axlsdk/axl';\nimport type { EvalResult, EvalItem, ScorerDetail } from '@axlsdk/eval';\n\n// Stream events on the wire are `AxlEvent` — the translation layer was\n// deleted in PR 1 commit 4. The legacy `StreamEvent` shapes are gone;\n// consumers narrow on the AxlEvent union.\n\nconst REDACTED = '[redacted]';\n\n/**\n * Error `name` values whose `message` is purely structural (codes, counts,\n * identifiers) and safe to surface verbatim under redact mode. Every other\n * error — `ValidationError`, `GuardrailError`, `VerifyError`, arbitrary\n * provider errors, `Error` from user code — is treated as potentially\n * echoing user/LLM content and has its message scrubbed.\n *\n * Kept in sync with the allow-list in\n * `server/middleware/error-handler.ts`; both sites must match so a route\n * that surfaces errors inline has identical redaction semantics to one\n * that throws through the global handler.\n */\nconst SAFE_ERROR_NAMES = new Set([\n 'QuorumNotMet',\n 'NoConsensus',\n 'TimeoutError',\n 'MaxTurnsError',\n 'BudgetExceededError',\n 'ToolDenied',\n]);\n\n/**\n * Scrub an error's `.message` for inclusion in a REST error envelope or WS\n * error event. Under redact mode, only messages from the structural\n * allow-list above pass through; everything else becomes `[redacted]`. The\n * `code`/`name` stay untouched so clients can still branch programmatically.\n *\n * Call sites that catch an error and build a `{ code, message }` envelope\n * locally (instead of re-throwing through `errorHandler`) should use this\n * helper so their redaction behavior stays consistent with the global path.\n */\nexport function redactErrorMessage(err: unknown, redact: boolean): string {\n const raw = err instanceof Error ? err.message : String(err);\n if (!redact) return raw;\n const name = err instanceof Error ? err.name : '';\n return SAFE_ERROR_NAMES.has(name) ? raw : REDACTED;\n}\n\n/**\n * Generic \"scrub any value to the redacted sentinel\" helper. Used by\n * routes that return a single opaque payload (workflow execute result,\n * tool test result, playground done data) where the value could be\n * anything — string, object, array, null, number — and we just want a\n * consistent scrubbed marker regardless of shape.\n */\nexport function redactValue(value: unknown, redact: boolean): unknown {\n if (!redact) return value;\n return REDACTED;\n}\n\n/**\n * Return a shallow-cloned ExecutionInfo with user-content fields scrubbed\n * when `redact` is true. Never mutates the input. When `redact` is false,\n * returns the input unchanged (reference equality preserved).\n *\n * Event scrubbing: every event in `events[]` is piped through\n * `redactStreamEvent` to catch per-variant payloads that emit-time\n * redaction may have missed (e.g., `partial_object.data.object`,\n * `verify.data.lastError`, `pipeline.reason`, terminal `done`/`error`,\n * `tool_call_start.data.args`, `tool_denied.data.*`). Defense in depth —\n * core `emitEvent` scrubs most variants at emission, but the REST\n * serialization boundary is the last line before PII leaves the\n * observability envelope.\n */\nexport function redactExecutionInfo(info: ExecutionInfo, redact: boolean): ExecutionInfo {\n if (!redact) return info;\n return {\n ...info,\n ...(info.result !== undefined ? { result: REDACTED } : {}),\n ...(info.error !== undefined ? { error: REDACTED } : {}),\n events: info.events.map((e) => redactStreamEvent(e, true)),\n };\n}\n\n/** List variant: maps each entry through the single-item redactor. */\nexport function redactExecutionList(infos: ExecutionInfo[], redact: boolean): ExecutionInfo[] {\n if (!redact) return infos;\n return infos.map((info) => redactExecutionInfo(info, redact));\n}\n\n/**\n * Scrub a memory value read through Studio's REST API. Memory values\n * don't flow through `emitTrace` (the memory_remember / memory_recall log\n * events deliberately exclude values — operation-only audit trail), so\n * this isn't closing a trace-to-REST inconsistency. It's broadening the\n * observability-boundary scope to cover memory browser reads.\n *\n * Keys are deliberately preserved so the Memory Browser stays navigable —\n * users with redact on can still see which keys exist and which ones\n * their code is writing to. Keys are programmer-chosen identifiers; if a\n * specific deployment has PII in keys it's a code-level problem and\n * should be fixed at the `ctx.remember()` call site.\n */\nexport function redactMemoryValue(value: unknown, redact: boolean): unknown {\n if (!redact) return value;\n return REDACTED;\n}\n\n/**\n * Memory list variant. Scrubs values on every `{ key, value }` entry;\n * preserves keys for navigation.\n */\nexport function redactMemoryList(\n entries: Array<{ key: string; value: unknown }>,\n redact: boolean,\n): Array<{ key: string; value: unknown }> {\n if (!redact) return entries;\n return entries.map((entry) => ({ key: entry.key, value: REDACTED }));\n}\n\n/**\n * Scrub a single ChatMessage for session history responses. Removes:\n * - `content` — user/LLM text\n * - `tool_calls[*].function.arguments` — tool inputs (JSON string)\n * - `providerMetadata` — opaque provider bag that\n * may contain encoded reasoning / thinking signatures / cache keys\n *\n * Preserves:\n * - `role` — system/user/assistant/tool\n * - `name` — tool/function name on\n * role='tool' messages (non-PII identifier)\n * - `tool_call_id` — join key for tool responses\n * - `tool_calls[*].id` — call ID\n * - `tool_calls[*].type` — always 'function'\n * - `tool_calls[*].function.name` — tool name (non-PII)\n *\n * The preserved fields are exactly the structural metadata you need to\n * understand the shape of a conversation (who said what, which tools\n * were called) without seeing any user/LLM content.\n */\nfunction redactChatMessage(msg: ChatMessage): ChatMessage {\n // We deliberately hand-build the output with an explicit allow-list\n // instead of spreading `msg`, so any new field added to `ChatMessage`\n // in the future (e.g. `refusal`, `reasoning_content`) is silently\n // dropped rather than passing through unscrubbed. The `satisfies`\n // assertion catches the case where a new REQUIRED field is added to\n // `ChatMessage` — typecheck will fail and force a code review on\n // whether the new field should be scrubbed or preserved.\n const scrubbed = {\n role: msg.role,\n content: REDACTED,\n ...(msg.name !== undefined ? { name: msg.name } : {}),\n ...(msg.tool_call_id !== undefined ? { tool_call_id: msg.tool_call_id } : {}),\n ...(msg.tool_calls !== undefined\n ? {\n tool_calls: msg.tool_calls.map((tc) => ({\n id: tc.id,\n type: tc.type,\n function: {\n name: tc.function.name,\n arguments: REDACTED,\n },\n })),\n }\n : {}),\n // providerMetadata deliberately omitted — opaque content.\n } satisfies ChatMessage;\n return scrubbed;\n}\n\n/**\n * Scrub a session history response. Maps every message through\n * `redactChatMessage`. HandoffRecord entries (on the same response) have\n * no content fields — just source/target/mode/timestamp/duration — so\n * they don't need scrubbing.\n */\nexport function redactSessionHistory(history: ChatMessage[], redact: boolean): ChatMessage[] {\n if (!redact) return history;\n return history.map(redactChatMessage);\n}\n\n// ── Stream events (WS broadcast) ─────────────────────────────────────\n\n/**\n * Scrub an `AxlEvent` before broadcasting it to Studio WS subscribers or\n * serializing it through a REST response.\n *\n * Per-variant scrub logic lives in core's `REDACTION_RULES` table\n * (`packages/axl/src/redaction.ts`). Both this WS-boundary scrubber and\n * core's emit-time scrubber consult the same rules, so adding a new\n * `AxlEvent` variant updates both layers in one place — no drift.\n *\n * The defense-in-depth value of this layer remains: when a runtime emits\n * events with `redact: false` (rare but possible — e.g. a multi-tenant\n * setup where the per-request decision is made later) and they land in\n * `ExecutionInfo.events` for a REST read with `redact: true`, this\n * second pass catches the missed scrub. Structural metadata\n * (`executionId`/`step`/`timestamp`/`askId`/`agent`/etc.) and numeric\n * observability fields (`cost`/`tokens`/`duration`) are preserved by\n * every rule.\n *\n * Programmatic callers of `runtime.execute()` and direct StateStore\n * reads still receive raw events — redaction is an observability-boundary\n * filter, not a data-at-rest transform.\n */\nexport function redactStreamEvent(event: AxlEvent, redact: boolean): AxlEvent {\n if (!redact) return event;\n return redactEvent(event);\n}\n\n// ── Eval results ─────────────────────────────────────────────────────\n\n/**\n * Scrub a single `EvalItem`. Per-item user/LLM content lives in:\n * input — the dataset item that drove the workflow\n * output — the workflow's return value\n * error — failure message (may echo user input)\n * annotations — user-supplied per-item labels/ground truth\n * scorerErrors — scorer-thrown error strings that can echo content\n * scoreDetails[*].metadata — especially LLM-scorer reasoning,\n * which mirrors agent_call response content\n *\n * Preserved fields (structural / metrics):\n * scores (numeric), duration, cost, scorerCost\n * scoreDetails[*].{score, duration, cost} (but not metadata)\n * metadata (execution metadata: models, tokens, agentCalls, workflows)\n * traces (trace events — already redacted at emission time)\n */\nfunction redactEvalItem(item: EvalItem): EvalItem {\n const scrubbed: EvalItem = {\n ...item,\n input: REDACTED,\n output: REDACTED,\n ...(item.annotations !== undefined ? { annotations: REDACTED } : {}),\n ...(item.error !== undefined ? { error: REDACTED } : {}),\n ...(item.scorerErrors !== undefined\n ? { scorerErrors: item.scorerErrors.map(() => REDACTED) }\n : {}),\n };\n if (item.scoreDetails) {\n const detailsOut: Record<string, ScorerDetail> = {};\n for (const [name, detail] of Object.entries(item.scoreDetails)) {\n detailsOut[name] = {\n score: detail.score,\n ...(detail.duration !== undefined ? { duration: detail.duration } : {}),\n ...(detail.cost !== undefined ? { cost: detail.cost } : {}),\n // metadata deliberately omitted — may contain LLM scorer reasoning\n };\n }\n scrubbed.scoreDetails = detailsOut;\n }\n return scrubbed;\n}\n\n/**\n * Scrub an `EvalResult` for an observability-boundary read. Items are\n * mapped through `redactEvalItem`; result-level metadata (`dataset`, `id`,\n * `timestamp`, `totalCost`, `duration`, `summary`, `metadata`) is\n * preserved so the Eval Runner UI can still render summary stats,\n * timing, score distributions, and cost aggregates under compliance mode.\n *\n * One narrow exception: `metadata.batchFailure` is the raw error message\n * from a partial-batch failure. Studio-generated batches pre-redact this\n * at the run endpoint, but CLI-imported artifacts can carry an unredacted\n * error string that may quote user input (e.g. a guardrail rejection that\n * echoes the prompt). Scrub it here so imports under redact mode don't\n * leak.\n */\nexport function redactEvalResult(result: EvalResult, redact: boolean): EvalResult {\n if (!redact) return result;\n const meta = result.metadata as Record<string, unknown> | undefined;\n const scrubbedMetadata =\n meta && typeof meta.batchFailure === 'string'\n ? { ...meta, batchFailure: REDACTED }\n : result.metadata;\n return {\n ...result,\n metadata: scrubbedMetadata,\n items: result.items.map(redactEvalItem),\n };\n}\n\n/**\n * Scrub an `EvalHistoryEntry`. Entry-level metadata (id, eval name,\n * timestamp) is preserved; the nested `data` (an `EvalResult`) is\n * scrubbed recursively.\n */\nexport function redactEvalHistoryEntry(entry: EvalHistoryEntry, redact: boolean): EvalHistoryEntry {\n if (!redact) return entry;\n return {\n ...entry,\n data: redactEvalResult(entry.data as EvalResult, redact),\n };\n}\n\n/** List variant for eval history. */\nexport function redactEvalHistoryList(\n entries: EvalHistoryEntry[],\n redact: boolean,\n): EvalHistoryEntry[] {\n if (!redact) return entries;\n return entries.map((e) => redactEvalHistoryEntry(e, redact));\n}\n\n// ── Pending decisions (human-in-the-loop) ───────────────────────────\n\n/**\n * Scrub a `PendingDecision`. The `prompt` field is the human-visible\n * approval question that typically echoes user or agent content (e.g.\n * \"Approve sending this email to `user@acme.com`?\"). Metadata is also\n * scrubbed because it's a free-form bag that may contain arbitrary\n * user data. Structural fields (executionId, channel, createdAt) stay\n * visible so the Decisions panel can still render the approval queue.\n */\nexport function redactPendingDecision(decision: PendingDecision, redact: boolean): PendingDecision {\n if (!redact) return decision;\n return {\n ...decision,\n prompt: REDACTED,\n ...(decision.metadata !== undefined ? { metadata: { redacted: true } } : {}),\n };\n}\n\n/** List variant for pending decisions. */\nexport function redactPendingDecisionList(\n decisions: PendingDecision[],\n redact: boolean,\n): PendingDecision[] {\n if (!redact) return decisions;\n return decisions.map((d) => redactPendingDecision(d, redact));\n}\n","import type { Context, Next } from 'hono';\nimport type { StudioEnv, ApiError } from '../types.js';\nimport { redactErrorMessage } from '../redact.js';\n\nexport async function errorHandler(c: Context<StudioEnv>, next: Next) {\n try {\n await next();\n } catch (err) {\n const rawMessage = err instanceof Error ? err.message : String(err);\n const code = (err as { code?: string }).code ?? 'INTERNAL_ERROR';\n\n // Determine HTTP status from error properties. Status classification\n // uses the raw message (not the redacted one) — redaction only affects\n // what the client sees, not how we categorize the error.\n let status = 500;\n if ('status' in (err as object)) {\n const errStatus = (err as { status: unknown }).status;\n if (typeof errStatus === 'number' && errStatus >= 400 && errStatus < 600) {\n status = errStatus;\n }\n } else if (\n code === 'NOT_FOUND' ||\n rawMessage.includes('not found') ||\n rawMessage.includes('not registered')\n ) {\n status = 404;\n } else if (\n code === 'VALIDATION_ERROR' ||\n rawMessage.includes('Expected') ||\n rawMessage.includes('invalid')\n ) {\n status = 400;\n }\n\n // Under `trace.redact`, error messages can echo user input\n // (ValidationError includes the failing reason, provider errors often\n // quote the request body, GuardrailError includes the trigger reason).\n // `redactErrorMessage` lets structural errors (Budget/Timeout/MaxTurns/\n // Quorum/NoConsensus/ToolDenied) pass through and scrubs the rest.\n const runtime = c.get('runtime');\n const redactOn = runtime?.isRedactEnabled?.() ?? false;\n\n const body: ApiError = {\n ok: false,\n error: { code, message: redactErrorMessage(err, redactOn) },\n };\n\n return c.json(body, status as 400 | 404 | 500);\n }\n}\n","/**\n * Minimal interface for a connection that can receive broadcast messages.\n * Satisfied by WSContext (Hono), ws.WebSocket (Node.js), and the middleware's\n * adapted socket. Internal to ConnectionManager — not part of the public API.\n */\nexport interface BroadcastTarget {\n send(data: string): void;\n close?(): void;\n}\n\n/**\n * Short-lived event buffer for execution streams.\n * Solves the race where a fast provider (e.g., MockProvider) completes\n * before the client's WS subscription is established. Events are buffered\n * per-channel and replayed to late subscribers.\n */\ninterface BufferedEvent {\n /** Pre-serialized JSON message (ready to `ws.send`). */\n msg: string;\n /** Original event data for filter evaluation on replay. */\n data: unknown;\n}\n\ninterface ChannelBuffer {\n events: BufferedEvent[];\n complete: boolean; // True after done/error event\n timer?: ReturnType<typeof setTimeout>;\n /** Sum of `msg.length` over buffered events. Byte-accurate; used to\n * enforce the per-buffer memory cap below. Maintained incrementally\n * so we don't have to re-scan on every push. */\n bytes: number;\n}\n\nconst BUFFER_TTL_MS = 30_000; // Clean up buffers 30s after stream completes\n\n/** Default cap on per-channel buffered events (raised from 500 in\n * spec/16 §5.2 to absorb nested-ask volume — ~10 nested asks × ~20\n * structural events each, with headroom). Override via the\n * `bufferCaps.maxEventsPerBuffer` constructor option on\n * `ConnectionManager`. */\nconst DEFAULT_MAX_BUFFER_EVENTS = 1000;\n\n/** Default per-buffer byte budget. 1000 events × 64KB max each would\n * peak at ~64MB per stream; the real-world distribution is bimodal\n * (hundreds of small structural events + a few verbose `agent_call_end`\n * snapshots), so 4MB per buffer is generous. When exceeded, new non-\n * terminal events are dropped (terminal `done`/`error` always\n * buffered). Review B-4. Override via\n * `bufferCaps.maxBytesPerBuffer`. */\nconst DEFAULT_MAX_BUFFER_BYTES = 4 * 1024 * 1024;\n\n/** Default cap on the number of concurrently-live replay buffers. Each\n * buffer is an open execution/eval stream; without a cap, a server\n * that sees sustained churn (say, 10k short-lived executions / minute)\n * holds 10k × maxBytesPerBuffer = 40GB of event-log memory across the\n * TTL window. When we hit the cap, the oldest complete buffer is\n * evicted immediately; if all live buffers are still incomplete, the\n * oldest one is dropped anyway (its late subscribers will miss the\n * replay, which is degraded UX but NOT a crash). Review SEC-H5.\n * Override via `bufferCaps.maxActiveBuffers`. */\nconst DEFAULT_MAX_ACTIVE_BUFFERS = 256;\n\n/**\n * Operator-tunable replay-buffer resource limits. Exposed via\n * `createStudioMiddleware({ bufferCaps })` and `createServer({ bufferCaps })`\n * so production deployments can tighten or relax memory pressure\n * without forking the package.\n *\n * All three fields are optional; omitted fields fall back to their\n * documented defaults, so passing `{}` is a no-op.\n */\nexport interface BufferCaps {\n /** Per-channel buffered event count cap. Default: 1000. */\n maxEventsPerBuffer?: number;\n /** Per-channel buffered byte budget. Default: 4 MiB. */\n maxBytesPerBuffer?: number;\n /** Global concurrently-live buffer cap. Default: 256. */\n maxActiveBuffers?: number;\n}\n\n/**\n * Stream-only event types excluded from the replay buffer entirely.\n * Late subscribers to an in-flight stream don't need per-token chatter\n * or per-delta progressive-render snapshots — they reconstruct the same\n * info from the final `agent_call_end` (token aggregates) and `done`\n * (final result). Both types are stream-only ergonomics, not\n * correctness-critical for replay. Spec/16 §5.2.\n */\nconst UNBUFFERED_EVENT_TYPES = new Set(['token', 'partial_object']);\n\n/** WS frame size soft cap. Used for both the inbound message reject in\n * `protocol.ts` and the outbound broadcast truncation below — keeping them\n * in one place so they never drift. Events that serialize larger than this\n * on the outbound path are replaced with a truncated placeholder so\n * consumers still receive a signal instead of having the browser's WS\n * client silently drop or close the connection. */\nexport const MAX_WS_FRAME_BYTES = 65536;\n\n/** Channels eligible for replay buffering (execution streams). */\nfunction isBufferedChannel(channel: string): boolean {\n return channel.startsWith('execution:') || channel.startsWith('eval:');\n}\n\n/**\n * Guard against outbound frames that exceed the WS size budget. Verbose-mode\n * `agent_call` events with a full `messages[]` snapshot can balloon past 64KB\n * on long conversations; browsers/ws libraries behave inconsistently when this\n * happens (silent drop, connection close, errors). Instead of hoping the\n * underlying stack handles it, we serialize once, check size, and fall back to\n * a truncated placeholder event if the payload is too large.\n *\n * The replacement preserves `channel`, `data.type`, `data.step`, `data.agent`,\n * and `data.tool` so the UI still sees the event shape — it just sees an\n * explicit truncation marker instead of silently losing data.\n */\nfunction truncateIfOversized(msg: string, channel: string, data: unknown): string {\n // WS frame budgets are measured in bytes. `string.length` counts UTF-16\n // code units; a payload with emoji / CJK / other multi-byte UTF-8 chars\n // can pass `msg.length <= 65536` yet serialize to >128KB when the\n // browser encodes the frame. Measure bytes directly to avoid\n // reintroducing the silent-drop / disconnect behavior this function\n // exists to prevent.\n const msgBytes = Buffer.byteLength(msg, 'utf8');\n if (msgBytes <= MAX_WS_FRAME_BYTES) return msg;\n const event = (data ?? {}) as {\n type?: string;\n step?: number;\n agent?: string;\n tool?: string;\n executionId?: string;\n };\n const truncated = {\n type: 'event',\n channel,\n data: {\n ...event,\n data: {\n __truncated: true,\n originalBytes: msgBytes,\n maxBytes: MAX_WS_FRAME_BYTES,\n hint: 'Event exceeded WS frame budget (likely a verbose agent_call with a large messages[] snapshot). Fetch via REST if you need the full payload.',\n },\n },\n };\n return JSON.stringify(truncated);\n}\n\n/**\n * Per-event, per-connection filter used by multi-tenant integrators to scope\n * the trace firehose. Return `true` to deliver the event to this connection,\n * `false` to skip it.\n *\n * `event` is the parsed payload (the same shape that was passed to `broadcast`);\n * `metadata` is whatever the middleware attached via `setMetadata(ws, ...)`\n * after a successful `verifyUpgrade` — typically `{ userId, tenantId }` or\n * similar, sourced from the upgrade request's auth token.\n */\nexport type BroadcastFilter = (event: unknown, metadata: unknown) => boolean;\n\n/**\n * Manages WebSocket connections and channel subscriptions.\n * Supports channel multiplexing: clients subscribe/unsubscribe to channels\n * and receive events only for channels they're subscribed to.\n *\n * Execution channels (`execution:*`) are replay-buffered: events are stored\n * so that late subscribers receive the full event history. Buffers are cleaned\n * up shortly after the stream completes.\n *\n * Multi-tenant deployments can attach per-connection metadata via\n * `setMetadata(ws, data)` and register a `BroadcastFilter` to scope the\n * trace firehose to the authenticated user/tenant.\n */\nexport class ConnectionManager {\n /** channel -> set of WS connections */\n private channels = new Map<string, Set<BroadcastTarget>>();\n /** ws -> subscribed channels + optional integrator-supplied metadata */\n private connections = new Map<BroadcastTarget, { channels: Set<string>; metadata?: unknown }>();\n /** channel -> replay buffer for execution streams */\n private buffers = new Map<string, ChannelBuffer>();\n private maxConnections = 100;\n private filter?: BroadcastFilter;\n /** Resolved replay-buffer caps. Per-instance so embedders can dial them\n * without monkey-patching module-level constants. */\n private readonly maxEventsPerBuffer: number;\n private readonly maxBytesPerBuffer: number;\n private readonly maxActiveBuffers: number;\n\n constructor(bufferCaps?: BufferCaps) {\n // Reject pathological values up-front. `0` would silently drop every\n // non-terminal event (operators following the JSDoc to \"tighten memory\n // pressure\" might pass 0 thinking it disables buffering); negatives\n // make eviction always fire. Fail-loud beats degraded replay UX.\n const validatePositiveInt = (key: keyof BufferCaps, value: number | undefined): void => {\n if (value === undefined) return;\n if (!Number.isFinite(value) || !Number.isInteger(value) || value < 1) {\n throw new RangeError(`bufferCaps.${key} must be a positive integer (>= 1); got ${value}`);\n }\n };\n validatePositiveInt('maxEventsPerBuffer', bufferCaps?.maxEventsPerBuffer);\n validatePositiveInt('maxBytesPerBuffer', bufferCaps?.maxBytesPerBuffer);\n validatePositiveInt('maxActiveBuffers', bufferCaps?.maxActiveBuffers);\n this.maxEventsPerBuffer = bufferCaps?.maxEventsPerBuffer ?? DEFAULT_MAX_BUFFER_EVENTS;\n this.maxBytesPerBuffer = bufferCaps?.maxBytesPerBuffer ?? DEFAULT_MAX_BUFFER_BYTES;\n this.maxActiveBuffers = bufferCaps?.maxActiveBuffers ?? DEFAULT_MAX_ACTIVE_BUFFERS;\n }\n\n /**\n * Register a broadcast filter. Called once at middleware construction.\n * The filter runs on every outbound event and can drop or deliver based\n * on the destination connection's metadata.\n */\n setFilter(filter: BroadcastFilter | undefined): void {\n this.filter = filter;\n }\n\n /** Attach integrator-supplied metadata to an already-added connection. */\n setMetadata(ws: BroadcastTarget, metadata: unknown): void {\n const entry = this.connections.get(ws);\n if (entry) entry.metadata = metadata;\n }\n\n /** Register a new WS connection. */\n add(ws: BroadcastTarget): void {\n if (this.connections.size >= this.maxConnections) {\n ws.close?.();\n return;\n }\n this.connections.set(ws, { channels: new Set() });\n }\n\n /** Remove a WS connection and all its subscriptions. */\n remove(ws: BroadcastTarget): void {\n const entry = this.connections.get(ws);\n if (entry) {\n for (const ch of entry.channels) {\n this.channels.get(ch)?.delete(ws);\n if (this.channels.get(ch)?.size === 0) {\n this.channels.delete(ch);\n }\n }\n }\n this.connections.delete(ws);\n }\n\n /** Subscribe a connection to a channel. Replays buffered events for execution channels. */\n subscribe(ws: BroadcastTarget, channel: string): void {\n if (!this.connections.has(ws)) return;\n let subs = this.channels.get(channel);\n if (!subs) {\n subs = new Set();\n this.channels.set(channel, subs);\n }\n subs.add(ws);\n this.connections.get(ws)!.channels.add(channel);\n\n // Replay buffered events for late subscribers. Filter is re-applied on\n // replay so a tenant-B subscriber joining an execution channel doesn't\n // get tenant-A events that were buffered before it connected.\n const buffer = this.buffers.get(channel);\n if (buffer) {\n const metadata = this.connections.get(ws)?.metadata;\n for (const event of buffer.events) {\n if (this.filter) {\n try {\n if (!this.filter(event.data, metadata)) continue;\n } catch {\n continue;\n }\n }\n try {\n ws.send(event.msg);\n } catch {\n this.remove(ws);\n return;\n }\n }\n }\n }\n\n /** Unsubscribe a connection from a channel. */\n unsubscribe(ws: BroadcastTarget, channel: string): void {\n this.channels.get(channel)?.delete(ws);\n if (this.channels.get(channel)?.size === 0) {\n this.channels.delete(channel);\n }\n this.connections.get(ws)?.channels.delete(channel);\n }\n\n /** Broadcast data to all subscribers of a channel. Buffers events for execution channels. */\n broadcast(channel: string, data: unknown): void {\n const msg = truncateIfOversized(\n JSON.stringify({ type: 'event', channel, data }),\n channel,\n data,\n );\n\n // Buffer events for execution channels so late subscribers can replay\n if (isBufferedChannel(channel)) {\n let buffer = this.buffers.get(channel);\n if (!buffer) {\n // Enforce the global-buffer cap before allocating. Evict the\n // oldest-inserted buffer (Map preserves insertion order, so\n // `.keys().next().value` is the eldest). Prefer evicting a\n // completed buffer if any exist — its late-subscriber window\n // is already effectively closed. Falls back to evicting the\n // eldest live buffer under sustained pressure.\n if (this.buffers.size >= this.maxActiveBuffers) {\n let victim: string | undefined;\n for (const [ch, buf] of this.buffers) {\n if (buf.complete) {\n victim = ch;\n break;\n }\n }\n if (victim === undefined) {\n victim = this.buffers.keys().next().value as string | undefined;\n }\n if (victim !== undefined) {\n const old = this.buffers.get(victim);\n if (old?.timer) clearTimeout(old.timer);\n this.buffers.delete(victim);\n }\n }\n buffer = { events: [], complete: false, bytes: 0 };\n this.buffers.set(channel, buffer);\n }\n // Always buffer terminal events; skip non-terminal if at capacity\n // on EITHER the event-count OR byte budget; never buffer\n // high-volume types (token, partial_object) per spec/16 §5.2 —\n // late subscribers reconstruct the same info from structural\n // events.\n const event = data as { type?: string };\n const isTerminal = event.type === 'done' || event.type === 'error';\n const isUnbuffered = event.type !== undefined && UNBUFFERED_EVENT_TYPES.has(event.type);\n if (!isUnbuffered) {\n const msgBytes = Buffer.byteLength(msg, 'utf8');\n const atCountCap = buffer.events.length >= this.maxEventsPerBuffer;\n const atByteCap = buffer.bytes + msgBytes > this.maxBytesPerBuffer;\n if (isTerminal || (!atCountCap && !atByteCap)) {\n buffer.events.push({ msg, data });\n buffer.bytes += msgBytes;\n }\n }\n\n // Schedule buffer cleanup after terminal events\n if (isTerminal) {\n buffer.complete = true;\n if (buffer.timer) clearTimeout(buffer.timer);\n buffer.timer = setTimeout(() => {\n this.buffers.delete(channel);\n }, BUFFER_TTL_MS);\n }\n }\n\n // Send to current subscribers\n const subs = this.channels.get(channel);\n if (!subs || subs.size === 0) return;\n\n for (const ws of [...subs]) {\n // Multi-tenant filter: drop events that don't match this connection's\n // metadata (e.g., wrong tenant). Filter errors are treated as `drop`\n // so a buggy predicate can't accidentally leak events cross-tenant.\n if (this.filter) {\n const metadata = this.connections.get(ws)?.metadata;\n try {\n if (!this.filter(data, metadata)) continue;\n } catch {\n continue;\n }\n }\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n }\n }\n }\n\n /** Broadcast to channel and all wildcard subscribers (e.g., trace:* matches trace:abc). */\n broadcastWithWildcard(channel: string, data: unknown): void {\n this.broadcast(channel, data);\n\n // Check for wildcard subscribers: \"prefix:*\" matches \"prefix:anything\"\n // Send with the actual channel name so wildcard subscribers know the source.\n const colonIdx = channel.indexOf(':');\n if (colonIdx > 0) {\n const wildcardChannel = channel.substring(0, colonIdx) + ':*';\n const subs = this.channels.get(wildcardChannel);\n if (!subs || subs.size === 0) return;\n\n const msg = truncateIfOversized(\n JSON.stringify({ type: 'event', channel, data }),\n channel,\n data,\n );\n for (const ws of [...subs]) {\n if (this.filter) {\n const metadata = this.connections.get(ws)?.metadata;\n try {\n if (!this.filter(data, metadata)) continue;\n } catch {\n continue;\n }\n }\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n }\n }\n }\n }\n\n /** Close all connections, clear all state and buffers. Used during shutdown. */\n closeAll(): void {\n for (const ws of this.connections.keys()) {\n ws.close?.();\n }\n for (const buffer of this.buffers.values()) {\n if (buffer.timer) clearTimeout(buffer.timer);\n }\n this.connections.clear();\n this.channels.clear();\n this.buffers.clear();\n }\n\n /** Get the number of active connections. */\n get connectionCount(): number {\n return this.connections.size;\n }\n\n /** Check if any connections are subscribed to a channel. */\n hasSubscribers(channel: string): boolean {\n return (this.channels.get(channel)?.size ?? 0) > 0;\n }\n}\n","import type { BroadcastTarget } from './connection-manager.js';\nimport { MAX_WS_FRAME_BYTES, type ConnectionManager } from './connection-manager.js';\n\n/** Channel prefixes that accept suffixes (e.g., execution:abc, trace:*). */\nconst VALID_CHANNEL_PREFIXES = ['execution:', 'trace:', 'eval:'];\n/** Channels that must match exactly (no suffix allowed). */\nconst VALID_EXACT_CHANNELS = ['costs', 'decisions', 'eval-trends', 'workflow-stats', 'trace-stats'];\nconst MAX_CHANNEL_LENGTH = 256;\n\n/**\n * Handle a single WebSocket message according to the Studio protocol.\n * Returns a JSON string to send back to the client, or null for no response.\n *\n * Used by both the Hono WS handler (ws/handler.ts) and the Node.js\n * middleware (middleware.ts) to keep the protocol in one place.\n */\nexport function handleWsMessage(\n raw: string,\n socket: BroadcastTarget,\n connMgr: ConnectionManager,\n): string | null {\n // Reject oversized messages. Shared cap with the outbound broadcast path\n // in connection-manager.ts — see `MAX_WS_FRAME_BYTES` for rationale.\n // Measure bytes (not UTF-16 code units) so multi-byte payloads (emoji /\n // CJK / other non-ASCII) can't pass `raw.length` while serializing past\n // 64KB on the wire — keeping symmetry with the outbound `Buffer.byteLength`\n // check in `connection-manager.ts:truncateIfOversized`.\n if (Buffer.byteLength(raw, 'utf8') > MAX_WS_FRAME_BYTES) {\n return JSON.stringify({ type: 'error', message: 'Message too large' });\n }\n\n let msg: { type: string; channel?: string };\n try {\n msg = JSON.parse(raw);\n } catch {\n return JSON.stringify({ type: 'error', message: 'Invalid JSON' });\n }\n\n switch (msg.type) {\n case 'subscribe': {\n const error = validateChannel(msg.channel);\n if (error) return JSON.stringify({ type: 'error', message: error });\n connMgr.subscribe(socket, msg.channel!);\n return JSON.stringify({ type: 'subscribed', channel: msg.channel });\n }\n case 'unsubscribe': {\n const error = validateChannel(msg.channel);\n if (error) return JSON.stringify({ type: 'error', message: error });\n connMgr.unsubscribe(socket, msg.channel!);\n return JSON.stringify({ type: 'unsubscribed', channel: msg.channel });\n }\n case 'ping':\n return JSON.stringify({ type: 'pong' });\n default:\n return JSON.stringify({ type: 'error', message: 'Unknown message type' });\n }\n}\n\nfunction validateChannel(channel: unknown): string | null {\n if (typeof channel !== 'string' || !channel) {\n return 'Missing or invalid channel';\n }\n if (channel.length > MAX_CHANNEL_LENGTH) {\n return `Channel name exceeds ${MAX_CHANNEL_LENGTH} characters`;\n }\n if (\n !VALID_EXACT_CHANNELS.includes(channel as (typeof VALID_EXACT_CHANNELS)[number]) &&\n !VALID_CHANNEL_PREFIXES.some((p) => channel.startsWith(p))\n ) {\n return `Invalid channel: ${channel}`;\n }\n return null;\n}\n","import type { WSContext } from 'hono/ws';\nimport type { ConnectionManager } from './connection-manager.js';\nimport { handleWsMessage } from './protocol.js';\n\n/** Create WS event handlers for a Hono WebSocket connection. */\nexport function createWsHandlers(connMgr: ConnectionManager) {\n return {\n onOpen(_event: Event, ws: WSContext) {\n connMgr.add(ws);\n },\n\n onMessage(event: MessageEvent, ws: WSContext) {\n const reply = handleWsMessage(String(event.data), ws, connMgr);\n if (reply) ws.send(reply);\n },\n\n onClose(_event: CloseEvent, ws: WSContext) {\n connMgr.remove(ws);\n },\n\n onError(_event: Event, ws: WSContext) {\n connMgr.remove(ws);\n },\n };\n}\n","import type { ConnectionManager } from '../ws/connection-manager.js';\n\nexport type WindowId = '24h' | '7d' | '30d' | 'all';\n\nexport type AggregateBroadcast<State> = {\n snapshots: Record<WindowId, State>;\n updatedAt: number;\n};\n\nconst WINDOW_MS: Record<WindowId, number> = {\n '24h': 24 * 60 * 60 * 1000,\n '7d': 7 * 24 * 60 * 60 * 1000,\n '30d': 30 * 24 * 60 * 60 * 1000,\n all: Number.POSITIVE_INFINITY,\n};\n\nexport function withinWindow(ts: number, window: WindowId, now: number): boolean {\n return ts >= now - WINDOW_MS[window];\n}\n\n/** Hardcoded rebuild interval — no env var or config surface in v1. */\nexport const REBUILD_INTERVAL_MS = 5 * 60_000;\n\nconst ALL_WINDOWS = new Set<string>(Object.keys(WINDOW_MS));\n\n/** Parse a `?window=` query param into a validated WindowId, defaulting to `7d`. */\nexport function parseWindowParam(raw?: string | null, fallback: WindowId = '7d'): WindowId {\n return raw && ALL_WINDOWS.has(raw) ? (raw as WindowId) : fallback;\n}\n\n/**\n * Holds per-window snapshots of an aggregate state and handles\n * window-filter logic and WebSocket broadcast.\n */\nexport class AggregateSnapshots<State> {\n private snapshots: Map<WindowId, State>;\n\n constructor(\n private windows: WindowId[],\n private emptyState: () => State,\n private connMgr: ConnectionManager,\n private channel: string,\n /** Optional transform applied to each window's state before WS broadcast.\n * Useful when the broadcast payload differs from the internal state\n * (e.g., stripping internal arrays and adding computed fields). */\n private broadcastTransform?: (state: State) => unknown,\n ) {\n this.snapshots = new Map(windows.map((w) => [w, emptyState()]));\n }\n\n /** Replace all snapshots atomically — used after a full rebuild. */\n replace(fresh: Map<WindowId, State>): void {\n this.snapshots = fresh;\n this.broadcast();\n }\n\n /** Apply a reducer update to every window where `ts` falls inside the window. */\n fold(ts: number, update: (prev: State) => State): void {\n const now = Date.now();\n let changed = false;\n for (const window of this.windows) {\n if (withinWindow(ts, window, now)) {\n const prev = this.snapshots.get(window)!;\n this.snapshots.set(window, update(prev));\n changed = true;\n }\n }\n if (changed) this.broadcast();\n }\n\n get(window: WindowId): State {\n return this.snapshots.get(window) ?? this.emptyState();\n }\n\n getAll(): Record<WindowId, State> {\n return Object.fromEntries(this.snapshots) as Record<WindowId, State>;\n }\n\n private broadcast(): void {\n const snapshots = this.broadcastTransform\n ? (Object.fromEntries(\n this.windows.map((w) => [w, this.broadcastTransform!(this.snapshots.get(w)!)]),\n ) as Record<WindowId, unknown>)\n : this.getAll();\n this.connMgr.broadcast(this.channel, {\n snapshots,\n updatedAt: Date.now(),\n });\n }\n}\n","import type { AxlRuntime, AxlEvent, ExecutionInfo } from '@axlsdk/axl';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { AggregateSnapshots, REBUILD_INTERVAL_MS, withinWindow } from './aggregate-snapshots.js';\nimport type { WindowId } from './aggregate-snapshots.js';\n\nexport type TraceReducer<State> = (acc: State, event: AxlEvent) => State;\n\nexport type TraceAggregatorOptions<State> = {\n runtime: AxlRuntime;\n connMgr: ConnectionManager;\n channel: string;\n reducer: TraceReducer<State>;\n emptyState: () => State;\n windows: WindowId[];\n /** Max executions to replay on rebuild. Default 2000. */\n executionCap?: number;\n /** Optional transform applied to each window's state before WS broadcast. */\n broadcastTransform?: (state: State) => unknown;\n};\n\n/**\n * Consumes AxlEvents from execution history and the live trace stream.\n * Maintains per-window aggregate snapshots via a pure reducer.\n */\nexport class TraceAggregator<State> {\n private snaps: AggregateSnapshots<State>;\n private interval?: ReturnType<typeof setInterval>;\n private listener?: (event: AxlEvent) => void;\n private options: TraceAggregatorOptions<State>;\n\n constructor(options: TraceAggregatorOptions<State>) {\n this.options = options;\n this.snaps = new AggregateSnapshots(\n options.windows,\n options.emptyState,\n options.connMgr,\n options.channel,\n options.broadcastTransform,\n );\n }\n\n async start(): Promise<void> {\n await this.rebuild();\n this.listener = (event: AxlEvent) => {\n this.snaps.fold(event.timestamp, (prev) => this.options.reducer(prev, event));\n };\n this.options.runtime.on('trace', this.listener);\n this.interval = setInterval(\n () => this.rebuild().catch((err) => console.error('[axl-studio] rebuild failed:', err)),\n REBUILD_INTERVAL_MS,\n );\n }\n\n async rebuild(): Promise<void> {\n const executions: ExecutionInfo[] = await this.options.runtime.getExecutions();\n const cap = this.options.executionCap ?? 2000;\n const capped = executions.slice(0, cap);\n const now = Date.now();\n const fresh = new Map<WindowId, State>(\n this.options.windows.map((w) => [w, this.options.emptyState()]),\n );\n for (const exec of capped) {\n for (const event of exec.events) {\n for (const window of this.options.windows) {\n if (withinWindow(event.timestamp, window, now)) {\n fresh.set(window, this.options.reducer(fresh.get(window)!, event));\n }\n }\n }\n }\n this.snaps.replace(fresh);\n }\n\n getSnapshot(window: WindowId): State {\n return this.snaps.get(window);\n }\n\n getAllSnapshots(): Record<WindowId, State> {\n return this.snaps.getAll();\n }\n\n close(): void {\n if (this.listener) this.options.runtime.off('trace', this.listener);\n if (this.interval) clearInterval(this.interval);\n }\n}\n","import type { AxlRuntime, AxlEvent, ExecutionInfo } from '@axlsdk/axl';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { AggregateSnapshots, REBUILD_INTERVAL_MS, withinWindow } from './aggregate-snapshots.js';\nimport type { WindowId } from './aggregate-snapshots.js';\n\nexport type ExecutionReducer<State> = (acc: State, execution: ExecutionInfo) => State;\n\nexport type ExecutionAggregatorOptions<State> = {\n runtime: AxlRuntime;\n connMgr: ConnectionManager;\n channel: string;\n reducer: ExecutionReducer<State>;\n emptyState: () => State;\n windows: WindowId[];\n /** Max executions to replay on rebuild. Default 2000. */\n executionCap?: number;\n /** Optional transform applied to each window's state before WS broadcast. */\n broadcastTransform?: (state: State) => unknown;\n};\n\n/**\n * Consumes ExecutionInfo at the execution granularity (not individual trace events).\n * Live updates arrive via workflow_end trace events — the aggregator fetches the\n * finalized ExecutionInfo and folds it.\n */\nexport class ExecutionAggregator<State> {\n private snaps: AggregateSnapshots<State>;\n private interval?: ReturnType<typeof setInterval>;\n private listener?: (event: AxlEvent) => void;\n private options: ExecutionAggregatorOptions<State>;\n /** Generation counter to prevent stale async fold after rebuild. */\n private generation = 0;\n\n constructor(options: ExecutionAggregatorOptions<State>) {\n this.options = options;\n this.snaps = new AggregateSnapshots(\n options.windows,\n options.emptyState,\n options.connMgr,\n options.channel,\n options.broadcastTransform,\n );\n }\n\n async start(): Promise<void> {\n await this.rebuild();\n this.listener = (event: AxlEvent) => {\n if (event.type !== 'workflow_end') return;\n // Capture generation before the async gap\n const gen = this.generation;\n this.options.runtime\n .getExecution(event.executionId)\n .then((exec) => {\n // Skip if a rebuild happened between event and resolution\n if (this.generation !== gen) return;\n if (exec) {\n this.snaps.fold(exec.startedAt, (prev) => this.options.reducer(prev, exec));\n }\n })\n .catch((err) => console.error('[axl-studio] execution fold failed:', err));\n };\n this.options.runtime.on('trace', this.listener);\n this.interval = setInterval(\n () => this.rebuild().catch((err) => console.error('[axl-studio] rebuild failed:', err)),\n REBUILD_INTERVAL_MS,\n );\n }\n\n async rebuild(): Promise<void> {\n this.generation++;\n const executions: ExecutionInfo[] = await this.options.runtime.getExecutions();\n const cap = this.options.executionCap ?? 2000;\n const capped = executions.slice(0, cap);\n const now = Date.now();\n const fresh = new Map<WindowId, State>(\n this.options.windows.map((w) => [w, this.options.emptyState()]),\n );\n for (const exec of capped) {\n for (const window of this.options.windows) {\n if (withinWindow(exec.startedAt, window, now)) {\n fresh.set(window, this.options.reducer(fresh.get(window)!, exec));\n }\n }\n }\n this.snaps.replace(fresh);\n }\n\n getSnapshot(window: WindowId): State {\n return this.snaps.get(window);\n }\n\n getAllSnapshots(): Record<WindowId, State> {\n return this.snaps.getAll();\n }\n\n close(): void {\n if (this.listener) this.options.runtime.off('trace', this.listener);\n if (this.interval) clearInterval(this.interval);\n }\n}\n","import type { AxlRuntime, EvalHistoryEntry } from '@axlsdk/axl';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { AggregateSnapshots, REBUILD_INTERVAL_MS, withinWindow } from './aggregate-snapshots.js';\nimport type { WindowId } from './aggregate-snapshots.js';\n\nexport type EvalReducer<State> = (acc: State, entry: EvalHistoryEntry) => State;\n\nexport type EvalAggregatorOptions<State> = {\n runtime: AxlRuntime;\n connMgr: ConnectionManager;\n channel: string;\n reducer: EvalReducer<State>;\n emptyState: () => State;\n windows: WindowId[];\n /** Max eval entries to replay on rebuild. Default 500. */\n entryCap?: number;\n /** Optional transform applied to each window's state before WS broadcast. */\n broadcastTransform?: (state: State) => unknown;\n};\n\n/**\n * Consumes EvalHistoryEntry. Rebuilds from runtime.getEvalHistory().\n * Live updates arrive via runtime.on('eval_result', entry).\n */\nexport class EvalAggregator<State> {\n private snaps: AggregateSnapshots<State>;\n private interval?: ReturnType<typeof setInterval>;\n private listener?: (entry: EvalHistoryEntry) => void;\n private options: EvalAggregatorOptions<State>;\n\n constructor(options: EvalAggregatorOptions<State>) {\n this.options = options;\n this.snaps = new AggregateSnapshots(\n options.windows,\n options.emptyState,\n options.connMgr,\n options.channel,\n options.broadcastTransform,\n );\n }\n\n async start(): Promise<void> {\n await this.rebuild();\n this.listener = (entry: EvalHistoryEntry) => {\n this.snaps.fold(entry.timestamp, (prev) => this.options.reducer(prev, entry));\n };\n this.options.runtime.on('eval_result', this.listener);\n this.interval = setInterval(\n () => this.rebuild().catch((err) => console.error('[axl-studio] rebuild failed:', err)),\n REBUILD_INTERVAL_MS,\n );\n }\n\n async rebuild(): Promise<void> {\n const history: EvalHistoryEntry[] = await this.options.runtime.getEvalHistory();\n const cap = this.options.entryCap ?? 500;\n const capped = history.slice(0, cap);\n const now = Date.now();\n const fresh = new Map<WindowId, State>(\n this.options.windows.map((w) => [w, this.options.emptyState()]),\n );\n for (const entry of capped) {\n for (const window of this.options.windows) {\n if (withinWindow(entry.timestamp, window, now)) {\n fresh.set(window, this.options.reducer(fresh.get(window)!, entry));\n }\n }\n }\n this.snaps.replace(fresh);\n }\n\n getSnapshot(window: WindowId): State {\n return this.snaps.get(window);\n }\n\n getAllSnapshots(): Record<WindowId, State> {\n return this.snaps.getAll();\n }\n\n close(): void {\n if (this.listener) this.options.runtime.off('eval_result', this.listener);\n if (this.interval) clearInterval(this.interval);\n }\n}\n","/**\n * Pure reducer functions for each aggregate panel.\n * Each reducer is a pure (state, source) => state function — no I/O, no mutation.\n */\nimport type { AxlEvent, ExecutionInfo, EvalHistoryEntry } from '@axlsdk/axl';\nimport { eventCostContribution } from '@axlsdk/axl';\nimport type { CostData } from '../types.js';\n\n// ── Shared helpers ────────────────────────────────────────────────────\n\n/** Clamp a possibly-NaN/Infinity number to 0. */\nconst finite = (v: number | undefined): number => (Number.isFinite(v) ? v! : 0);\n\n// ── Cost reducer (AxlEvent → CostData) ──────────────────────────────\n\nfunction emptyRetry(): CostData['retry'] {\n return {\n primary: 0,\n primaryCalls: 0,\n schema: 0,\n schemaCalls: 0,\n validate: 0,\n validateCalls: 0,\n guardrail: 0,\n guardrailCalls: 0,\n retryCalls: 0,\n };\n}\n\nexport function emptyCostData(): CostData {\n return {\n totalCost: 0,\n totalTokens: { input: 0, output: 0, reasoning: 0 },\n byAgent: {},\n byModel: {},\n byWorkflow: {},\n retry: emptyRetry(),\n byEmbedder: {},\n };\n}\n\n/**\n * Pure reducer for CostData with full parity to CostAggregator.onTrace.\n * Handles retry decomposition, embedder cost bucketing, workflow_start\n * detection (both production log-form and test runtime shapes), and\n * NaN/Infinity guards on all numeric accumulations.\n */\nexport function reduceCost(acc: CostData, event: AxlEvent): CostData {\n const isWorkflowStart = event.type === 'workflow_start';\n\n // workflow_start events increment per-workflow executions and return early.\n // They carry no meaningful cost — any cost/token fields are incidental.\n if (isWorkflowStart && event.workflow) {\n const byWorkflow = { ...acc.byWorkflow };\n const prev = byWorkflow[event.workflow] ?? { cost: 0, executions: 0 };\n byWorkflow[event.workflow] = { ...prev, executions: prev.executions + 1 };\n return { ...acc, byWorkflow };\n }\n\n // Early return for events with no cost data.\n if (event.cost == null && !event.tokens) return acc;\n\n // Rollup guard: `eventCostContribution` encapsulates the spec §10\n // \"skip ask_end, finite-check, leaf-only\" invariant. The rest of\n // this reducer buckets the charge across per-agent / per-model /\n // per-workflow views; calling the helper once here keeps the\n // semantics in one place. If the contribution is 0 (ask_end or\n // NaN), short-circuit so we don't increment call counts either.\n const cost = eventCostContribution(event);\n if (event.type === 'ask_end') return acc;\n const tokens = event.tokens ?? {};\n\n // Only count tokens from agent_call_end events — embedder tokens are\n // bucketed separately into byEmbedder.tokens.\n const totalTokens =\n event.type === 'agent_call_end'\n ? {\n input: acc.totalTokens.input + finite(tokens.input),\n output: acc.totalTokens.output + finite(tokens.output),\n reasoning: acc.totalTokens.reasoning + finite(tokens.reasoning),\n }\n : acc.totalTokens;\n\n const byAgent = { ...acc.byAgent };\n if (event.agent) {\n const prev = byAgent[event.agent] ?? { cost: 0, calls: 0 };\n byAgent[event.agent] = { cost: prev.cost + cost, calls: prev.calls + 1 };\n }\n\n const byModel = { ...acc.byModel };\n if (event.model) {\n const prev = byModel[event.model] ?? { cost: 0, calls: 0, tokens: { input: 0, output: 0 } };\n byModel[event.model] = {\n cost: prev.cost + cost,\n calls: prev.calls + 1,\n tokens: {\n input: prev.tokens.input + finite(tokens.input),\n output: prev.tokens.output + finite(tokens.output),\n },\n };\n }\n\n const byWorkflow = { ...acc.byWorkflow };\n if (event.workflow) {\n const prev = byWorkflow[event.workflow] ?? { cost: 0, executions: 0 };\n byWorkflow[event.workflow] = {\n cost: prev.cost + cost,\n executions: prev.executions + (isWorkflowStart ? 1 : 0),\n };\n }\n\n // Retry-cost decomposition: split agent_call_end cost by retryReason.\n let retry = acc.retry;\n if (event.type === 'agent_call_end') {\n const d = (event.data ?? {}) as { retryReason?: 'schema' | 'validate' | 'guardrail' };\n const reason = d.retryReason;\n retry = { ...acc.retry };\n if (reason === 'schema') {\n retry.schema += cost;\n retry.schemaCalls += 1;\n retry.retryCalls += 1;\n } else if (reason === 'validate') {\n retry.validate += cost;\n retry.validateCalls += 1;\n retry.retryCalls += 1;\n } else if (reason === 'guardrail') {\n retry.guardrail += cost;\n retry.guardrailCalls += 1;\n retry.retryCalls += 1;\n } else {\n retry.primary += cost;\n retry.primaryCalls += 1;\n }\n }\n\n // Embedder cost: `memory_remember` / `memory_recall` variants carry\n // `usage.{tokens,model}` and a top-level `cost` (mirrored by the\n // emitter). Bucket by embedder model so the Cost Dashboard's\n // \"Memory (Embedder)\" section can break down spend.\n let byEmbedder = acc.byEmbedder;\n if (event.type === 'memory_remember' || event.type === 'memory_recall') {\n const usage = event.data.usage;\n byEmbedder = { ...acc.byEmbedder };\n const modelKey = usage?.model ?? 'unknown';\n const embedTokens = typeof usage?.tokens === 'number' ? finite(usage.tokens) : 0;\n const prev = byEmbedder[modelKey] ?? { cost: 0, calls: 0, tokens: 0 };\n byEmbedder[modelKey] = {\n cost: prev.cost + cost,\n calls: prev.calls + 1,\n tokens: prev.tokens + embedTokens,\n };\n }\n\n return {\n totalCost: acc.totalCost + cost,\n totalTokens,\n byAgent,\n byModel,\n byWorkflow,\n retry,\n byEmbedder,\n };\n}\n\n// ── Eval trends reducer (EvalHistoryEntry → EvalTrendData) ────────────\n\nexport type EvalTrendRun = {\n timestamp: number;\n id: string;\n scores: Record<string, number>;\n cost: number;\n /** Primary model for this run (first entry of `metadata.models`). Undefined\n * when the run has no recorded models (e.g., legacy data or test harnesses). */\n model?: string;\n /** Total run duration in ms (from `EvalResult.duration`). */\n duration?: number;\n /**\n * Multi-run group id (`metadata.runGroupId`). Forwarded so the client can\n * detect partial batches by counting runs sharing this id and comparing\n * against `batchAttempted`.\n */\n runGroupId?: string;\n /**\n * Original planned multi-run count (`metadata.batchAttempted`). Set on\n * every run that was part of a multi-run batch; absent on single-run\n * results. The client compares this against the count of sibling runs in\n * the same `runGroupId` to mark partial trend points distinctly.\n */\n batchAttempted?: number;\n};\n\nexport type EvalTrendEntry = {\n runs: EvalTrendRun[];\n latestScores: Record<string, number>;\n scoreMean: Record<string, number>;\n scoreStd: Record<string, number>;\n costTotal: number;\n runCount: number;\n};\n\nexport type EvalTrendData = {\n byEval: Record<string, EvalTrendEntry>;\n totalRuns: number;\n totalCost: number;\n};\n\nexport function emptyEvalTrendData(): EvalTrendData {\n return { byEval: {}, totalRuns: 0, totalCost: 0 };\n}\n\n/** Extract per-scorer aggregate score from an EvalHistoryEntry's data blob.\n * The EvalResult shape is `{ summary: { scorers: Record<string, { mean, min,\n * max, p50, p95 }> }, ... }`. We take `mean` as the representative score for\n * each scorer in this run — what gets plotted on the trend line. */\nfunction extractScores(data: unknown): Record<string, number> {\n if (!data || typeof data !== 'object') return {};\n const result = data as Record<string, unknown>;\n const summary = result.summary as Record<string, unknown> | undefined;\n const scorers = summary?.scorers as Record<string, { mean?: number } | number> | undefined;\n if (!scorers) return {};\n const out: Record<string, number> = {};\n for (const [name, entry] of Object.entries(scorers)) {\n if (typeof entry === 'number' && Number.isFinite(entry)) {\n out[name] = entry;\n } else if (entry && typeof entry === 'object' && Number.isFinite(entry.mean)) {\n out[name] = entry.mean as number;\n }\n }\n return out;\n}\n\n/** Extract total cost from an EvalHistoryEntry's data blob.\n * `EvalResult.totalCost` is at the top level (not under summary). */\nfunction extractCost(data: unknown): number {\n if (!data || typeof data !== 'object') return 0;\n const result = data as Record<string, unknown>;\n if (Number.isFinite(result.totalCost)) return result.totalCost as number;\n // Back-compat: some early tests/fixtures put it under summary.totalCost\n const summary = result.summary as Record<string, unknown> | undefined;\n return Number.isFinite(summary?.totalCost) ? (summary!.totalCost as number) : 0;\n}\n\n/** Extract the primary model for this run.\n * Prefers the most-called model from `metadata.modelCounts`, falling back to\n * `metadata.models[0]`. Returns undefined if no model is recorded — UI groups\n * those runs under \"unknown\". For a mixed-model run (e.g., classify-then-answer),\n * the most-called model is the honest \"primary\" choice. */\nfunction extractModel(data: unknown): string | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const result = data as Record<string, unknown>;\n const metadata = result.metadata as { models?: unknown; modelCounts?: unknown } | undefined;\n const counts = metadata?.modelCounts;\n if (counts && typeof counts === 'object' && !Array.isArray(counts)) {\n const entries = Object.entries(counts as Record<string, unknown>).filter(\n ([, v]) => typeof v === 'number',\n ) as Array<[string, number]>;\n if (entries.length > 0) {\n // Secondary alphabetical sort breaks ties deterministically so two\n // runs with the same modelCounts (e.g., { a: 3, b: 3 } vs { b: 3, a: 3 })\n // always resolve to the same \"primary model\" regardless of insertion order.\n entries.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));\n return entries[0][0];\n }\n }\n const models = metadata?.models;\n if (Array.isArray(models) && typeof models[0] === 'string') return models[0];\n return undefined;\n}\n\n/** Extract run duration in ms from `EvalResult.duration`. */\nfunction extractDuration(data: unknown): number | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const result = data as Record<string, unknown>;\n return Number.isFinite(result.duration) ? (result.duration as number) : undefined;\n}\n\n/** Compute mean and std for score arrays. */\nfunction computeScoreStats(runs: EvalTrendRun[]): {\n mean: Record<string, number>;\n std: Record<string, number>;\n} {\n const scorerNames = new Set<string>();\n for (const run of runs) {\n for (const name of Object.keys(run.scores)) scorerNames.add(name);\n }\n\n const mean: Record<string, number> = {};\n const std: Record<string, number> = {};\n for (const name of scorerNames) {\n const values = runs.map((r) => r.scores[name]).filter((v) => v != null);\n if (values.length === 0) continue;\n const m = values.reduce((a, b) => a + b, 0) / values.length;\n mean[name] = m;\n const variance = values.reduce((sum, v) => sum + (v - m) ** 2, 0) / values.length;\n std[name] = Math.sqrt(variance);\n }\n return { mean, std };\n}\n\nexport function reduceEvalTrends(acc: EvalTrendData, entry: EvalHistoryEntry): EvalTrendData {\n const scores = extractScores(entry.data);\n const cost = extractCost(entry.data);\n const model = extractModel(entry.data);\n const duration = extractDuration(entry.data);\n // Forward multi-run identity fields (`runGroupId`, `batchAttempted`) so\n // the client can detect partial batches at render time. We can't decide\n // partial-ness here because it's a group property: partial iff\n // count(group) < batchAttempted, and the reducer processes one entry at\n // a time without knowledge of siblings in the same group.\n const metadata = (entry.data as { metadata?: Record<string, unknown> })?.metadata;\n const runGroupId = typeof metadata?.runGroupId === 'string' ? metadata.runGroupId : undefined;\n const batchAttempted =\n typeof metadata?.batchAttempted === 'number' && Number.isFinite(metadata.batchAttempted)\n ? metadata.batchAttempted\n : undefined;\n\n const run: EvalTrendRun = {\n timestamp: entry.timestamp,\n id: entry.id,\n scores,\n cost,\n ...(model !== undefined ? { model } : {}),\n ...(duration !== undefined ? { duration } : {}),\n ...(runGroupId !== undefined ? { runGroupId } : {}),\n ...(batchAttempted !== undefined ? { batchAttempted } : {}),\n };\n\n const byEval = { ...acc.byEval };\n const prev = byEval[entry.eval];\n // Cap runs array to limit WS broadcast payload size. Client only shows\n // the 10 most recent; keep 50 for future chart use.\n const MAX_EVAL_RUNS = 50;\n const allRuns = prev ? [...prev.runs, run] : [run];\n const runs = allRuns.length > MAX_EVAL_RUNS ? allRuns.slice(-MAX_EVAL_RUNS) : allRuns;\n const { mean, std } = computeScoreStats(runs);\n\n // latestScores is the most recent run's scores by timestamp.\n // During rebuild, entries arrive newest-first, so only overwrite if\n // there's no existing entry or this run is newer.\n const latestScores =\n prev && prev.runs.length > 0 && prev.runs[prev.runs.length - 1].timestamp > run.timestamp\n ? prev.latestScores\n : scores;\n\n byEval[entry.eval] = {\n runs,\n latestScores,\n scoreMean: mean,\n scoreStd: std,\n costTotal: (prev?.costTotal ?? 0) + cost,\n runCount: (prev?.runCount ?? 0) + 1,\n };\n\n return {\n byEval,\n totalRuns: acc.totalRuns + 1,\n totalCost: acc.totalCost + cost,\n };\n}\n\n// ── Workflow stats reducer (ExecutionInfo → WorkflowStatsData) ────────\n\n/** Max recent durations to keep per workflow for percentile computation. */\nconst MAX_DURATIONS = 200;\n\nexport type WorkflowStatsData = {\n byWorkflow: Record<\n string,\n {\n total: number;\n completed: number;\n failed: number;\n /** Bounded sorted array of recent durations for p50/p95. Max MAX_DURATIONS entries. */\n durations: number[];\n durationSum: number;\n avgDuration: number;\n }\n >;\n totalExecutions: number;\n failureRate: number;\n};\n\nexport function emptyWorkflowStatsData(): WorkflowStatsData {\n return { byWorkflow: {}, totalExecutions: 0, failureRate: 0 };\n}\n\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const idx = (p / 100) * (sorted.length - 1);\n const lower = Math.floor(idx);\n const upper = Math.ceil(idx);\n if (lower === upper) return sorted[lower];\n return sorted[lower] + (sorted[upper] - sorted[lower]) * (idx - lower);\n}\n\nexport function reduceWorkflowStats(\n acc: WorkflowStatsData,\n execution: ExecutionInfo,\n): WorkflowStatsData {\n const byWorkflow = { ...acc.byWorkflow };\n const prev = byWorkflow[execution.workflow] ?? {\n total: 0,\n completed: 0,\n failed: 0,\n durations: [],\n durationSum: 0,\n avgDuration: 0,\n };\n\n // Maintain a bounded sorted array for percentile computation.\n // Insert in sorted position, evict the smallest (front) if over cap.\n // This biases toward recent larger values — acceptable for dashboard use.\n const dur = finite(execution.duration);\n const durations = [...prev.durations];\n const insertIdx = durations.findIndex((d) => d > dur);\n if (insertIdx === -1) durations.push(dur);\n else durations.splice(insertIdx, 0, dur);\n if (durations.length > MAX_DURATIONS) durations.shift();\n\n const total = prev.total + 1;\n const completed = prev.completed + (execution.status === 'completed' ? 1 : 0);\n const failed = prev.failed + (execution.status === 'failed' ? 1 : 0);\n const durationSum = prev.durationSum + dur;\n const avgDuration = durationSum / total;\n\n byWorkflow[execution.workflow] = {\n total,\n completed,\n failed,\n durations,\n durationSum,\n avgDuration,\n };\n\n const totalExecutions = acc.totalExecutions + 1;\n const totalFailed = Object.values(byWorkflow).reduce((sum, w) => sum + w.failed, 0);\n const failureRate = totalExecutions > 0 ? totalFailed / totalExecutions : 0;\n\n return { byWorkflow, totalExecutions, failureRate };\n}\n\n/** Get p50/p95 from a WorkflowStatsData entry. Durations are pre-sorted. */\nexport function getWorkflowPercentiles(entry: WorkflowStatsData['byWorkflow'][string]): {\n durationP50: number;\n durationP95: number;\n} {\n // Durations are maintained in sorted order by the reducer\n return {\n durationP50: percentile(entry.durations, 50),\n durationP95: percentile(entry.durations, 95),\n };\n}\n\n/** Enrich raw WorkflowStatsData with computed percentiles for API/WS consumers.\n * Strips the internal `durations` and `durationSum` fields to keep payloads lean. */\nexport function enrichWorkflowStats(data: WorkflowStatsData) {\n const byWorkflow: Record<\n string,\n {\n total: number;\n completed: number;\n failed: number;\n durationP50: number;\n durationP95: number;\n avgDuration: number;\n }\n > = {};\n for (const [name, entry] of Object.entries(data.byWorkflow)) {\n const { durationP50, durationP95 } = getWorkflowPercentiles(entry);\n byWorkflow[name] = {\n total: entry.total,\n completed: entry.completed,\n failed: entry.failed,\n durationP50,\n durationP95,\n avgDuration: entry.avgDuration,\n };\n }\n return {\n byWorkflow,\n totalExecutions: data.totalExecutions,\n failureRate: data.failureRate,\n };\n}\n\n// ── Trace stats reducer (AxlEvent → TraceStatsData) ────────────────\n\nexport type TraceStatsData = {\n eventTypeCounts: Record<string, number>;\n byTool: Record<string, { calls: number; denied: number; approved: number }>;\n retryByAgent: Record<string, { schema: number; validate: number; guardrail: number }>;\n totalEvents: number;\n};\n\nexport function emptyTraceStatsData(): TraceStatsData {\n return {\n eventTypeCounts: {},\n byTool: {},\n retryByAgent: {},\n totalEvents: 0,\n };\n}\n\nexport function reduceTraceStats(acc: TraceStatsData, event: AxlEvent): TraceStatsData {\n const eventTypeCounts = { ...acc.eventTypeCounts };\n eventTypeCounts[event.type] = (eventTypeCounts[event.type] ?? 0) + 1;\n\n const byTool = { ...acc.byTool };\n if (\n event.type === 'tool_call_end' ||\n event.type === 'tool_denied' ||\n event.type === 'tool_approval'\n ) {\n const toolName = event.tool;\n const prev = byTool[toolName] ?? { calls: 0, denied: 0, approved: 0 };\n // tool_denied: legacy event for \"tool not available\" path. data.approved\n // distinguishes approvals (true) from denials (absent/false).\n // tool_approval: distinct event from the approval gate with data.approved.\n const isDeniedEvent = event.type === 'tool_denied';\n const isApprovalEvent = event.type === 'tool_approval';\n const eventData =\n isDeniedEvent || isApprovalEvent\n ? (event.data as { approved?: boolean } | undefined)\n : undefined;\n const isApproved =\n (isDeniedEvent && eventData?.approved === true) ||\n (isApprovalEvent && eventData?.approved === true);\n const isDenied =\n (isDeniedEvent && !eventData?.approved) || (isApprovalEvent && eventData?.approved === false);\n byTool[toolName] = {\n calls: prev.calls + (event.type === 'tool_call_end' ? 1 : 0),\n denied: prev.denied + (isDenied ? 1 : 0),\n approved: prev.approved + (isApproved ? 1 : 0),\n };\n }\n\n const retryByAgent = { ...acc.retryByAgent };\n if (event.agent && event.type === 'agent_call_end') {\n const data = event.data as { retryReason?: string } | undefined;\n if (data?.retryReason) {\n const prev = retryByAgent[event.agent] ?? { schema: 0, validate: 0, guardrail: 0 };\n const reason = data.retryReason as 'schema' | 'validate' | 'guardrail';\n if (reason in prev) {\n retryByAgent[event.agent] = { ...prev, [reason]: prev[reason] + 1 };\n }\n }\n }\n\n return {\n eventTypeCounts,\n byTool,\n retryByAgent,\n totalEvents: acc.totalEvents + 1,\n };\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nexport function createHealthRoutes(readOnly: boolean) {\n const app = new Hono<StudioEnv>();\n\n app.get('/health', (c) => {\n const runtime = c.get('runtime');\n return c.json({\n ok: true,\n data: {\n status: 'healthy',\n readOnly,\n workflows: runtime.getWorkflowNames().length,\n agents: runtime.getAgents().length,\n tools: runtime.getTools().length,\n },\n });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, WorkflowSummary } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { redactStreamEvent, redactValue } from '../redact.js';\n\nexport function createWorkflowRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // List all workflows\n app.get('/workflows', (c) => {\n const runtime = c.get('runtime');\n const workflows: WorkflowSummary[] = runtime.getWorkflows().map((w) => ({\n name: w.name,\n hasInputSchema: !!w.inputSchema,\n hasOutputSchema: !!w.outputSchema,\n }));\n return c.json({ ok: true, data: workflows });\n });\n\n // Get workflow detail (including schemas)\n app.get('/workflows/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const workflow = runtime.getWorkflow(name);\n if (!workflow) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Workflow \"${name}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: {\n name: workflow.name,\n inputSchema: workflow.inputSchema ? zodToJsonSchema(workflow.inputSchema) : null,\n outputSchema: workflow.outputSchema ? zodToJsonSchema(workflow.outputSchema) : null,\n },\n });\n });\n\n // Execute a workflow\n app.post('/workflows/:name/execute', async (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n\n const workflow = runtime.getWorkflow(name);\n if (!workflow) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Workflow \"${name}\" not found` } },\n 404,\n );\n }\n\n const body = await c.req.json<{\n input?: unknown;\n stream?: boolean;\n metadata?: Record<string, unknown>;\n }>();\n\n if (body.stream) {\n // Streaming execution — pipe events to WS channel. Under\n // `trace.redact`, scrub each StreamEvent before broadcast so\n // token deltas, tool args/results, and the final `done.data`\n // don't leak raw LLM/user content to WS subscribers.\n // TODO(PR-3-spec-16): the wire emits AxlEvent directly after PR 3 and\n // `redactStreamEvent` is replaced with an AxlEvent-aware scrubber.\n const stream = runtime.stream(name, body.input ?? {}, { metadata: body.metadata });\n const executionId = `stream-${Date.now()}`;\n const redactOn = runtime.isRedactEnabled();\n\n // Forward stream events to WS (error events flow through the iterator)\n (async () => {\n for await (const event of stream) {\n connMgr.broadcastWithWildcard(\n `execution:${executionId}`,\n redactStreamEvent(event, redactOn),\n );\n }\n })();\n\n return c.json({ ok: true, data: { executionId, streaming: true } });\n }\n\n const result = await runtime.execute(name, body.input ?? {}, { metadata: body.metadata });\n return c.json({\n ok: true,\n data: { result: redactValue(result, runtime.isRedactEnabled()) },\n });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport { redactExecutionInfo, redactExecutionList } from '../redact.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all executions\napp.get('/executions', async (c) => {\n const runtime = c.get('runtime');\n const executions = await runtime.getExecutions();\n return c.json({\n ok: true,\n data: redactExecutionList(executions, runtime.isRedactEnabled()),\n });\n});\n\n// Get execution by ID.\n//\n// Supports `?since={step}` pagination (spec/16 §5.4) — filters\n// `events` to those with `step > since`. `step` is monotonic\n// per-execution and shared across nested asks (spec §3.7), so\n// polling clients can request only the tail since their last known\n// step without missing events from concurrent branches.\n//\n// Polling pattern: client tracks `lastStep = events[events.length - 1]?.step`\n// and passes `?since=<lastStep>` on the next poll. First poll either\n// omits `since` or passes `-1` for \"everything from step 0 onward\" —\n// `since=0` explicitly means \"I already have step 0, give me step 1+\".\n// This preserves correctness when `workflow_start` lands at step 0.\n//\n// Malformed `since` (non-integer / non-finite) returns 400 — stale or\n// buggy clients get a clear diagnostic instead of silently receiving\n// the full events array and blowing their memory budget.\napp.get('/executions/:id', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const execution = await runtime.getExecution(id);\n if (!execution) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Execution \"${id}\" not found` } },\n 404,\n );\n }\n\n const sinceParam = c.req.query('since');\n let paged = execution;\n if (sinceParam !== undefined) {\n const since = Number(sinceParam);\n // Accept any finite integer, including -1 for \"everything\". Reject\n // NaN, Infinity, fractions, and non-numeric strings with a 400.\n if (!Number.isFinite(since) || !Number.isInteger(since)) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'INVALID_PARAM',\n message: `\\`since\\` must be a finite integer (got \"${sinceParam}\")`,\n param: 'since',\n },\n },\n 400,\n );\n }\n paged = {\n ...execution,\n events: execution.events.filter((e) => e.step > since),\n };\n }\n\n return c.json({\n ok: true,\n data: redactExecutionInfo(paged, runtime.isRedactEnabled()),\n });\n});\n\n// Abort a running execution\napp.post('/executions/:id/abort', (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n runtime.abort(id);\n return c.json({ ok: true, data: { aborted: true } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv, SessionSummary } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { redactSessionHistory } from '../redact.js';\n\nexport function createSessionRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // List all sessions\n app.get('/sessions', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n if (!store.listSessions) {\n return c.json({ ok: true, data: [] });\n }\n const ids = await store.listSessions();\n const sessions: SessionSummary[] = [];\n for (const id of ids) {\n const history = await store.getSession(id);\n sessions.push({ id, messageCount: history.length });\n }\n // List endpoint carries no message content — just id + count.\n // Nothing to redact.\n return c.json({ ok: true, data: sessions });\n });\n\n // Get session history\n app.get('/sessions/:id', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const id = c.req.param('id');\n const history = await store.getSession(id);\n const handoffHistory = await store.getSessionMeta(id, 'handoffHistory');\n return c.json({\n ok: true,\n data: {\n id,\n history: redactSessionHistory(history, runtime.isRedactEnabled()),\n // HandoffRecord has no content fields (source/target/mode/\n // timestamp/duration) — nothing to scrub.\n handoffHistory: handoffHistory ?? [],\n },\n });\n });\n\n // Send message to session (non-streaming)\n app.post('/sessions/:id/send', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const body = await c.req.json<{ message: string; workflow: string }>();\n\n const session = runtime.session(id);\n const result = await session.send(body.workflow, body.message);\n return c.json({ ok: true, data: { result } });\n });\n\n // Stream session message\n app.post('/sessions/:id/stream', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const body = await c.req.json<{ message: string; workflow: string }>();\n\n const session = runtime.session(id);\n const stream = await session.stream(body.workflow, body.message);\n const executionId = `session-${id}-${Date.now()}`;\n\n // Forward stream events to WS (error events flow through the iterator)\n (async () => {\n for await (const event of stream) {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, event);\n }\n })();\n\n return c.json({ ok: true, data: { executionId, streaming: true } });\n });\n\n // Delete session\n app.delete('/sessions/:id', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const id = c.req.param('id');\n await store.deleteSession(id);\n return c.json({ ok: true, data: { deleted: true } });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, AgentSummary } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all agents\napp.get('/agents', (c) => {\n const runtime = c.get('runtime');\n const agents: AgentSummary[] = runtime.getAgents().map((a) => ({\n name: a._name,\n model: a.resolveModel(),\n system: a.resolveSystem(),\n tools: a._config.tools?.map((t) => t.name) ?? [],\n handoffs:\n typeof a._config.handoffs === 'function'\n ? ['(dynamic)']\n : (a._config.handoffs?.map((h) => h.agent._name) ?? []),\n maxTurns: a._config.maxTurns,\n temperature: a._config.temperature,\n maxTokens: a._config.maxTokens,\n effort: a._config.effort,\n thinkingBudget: a._config.thinkingBudget,\n includeThoughts: a._config.includeThoughts,\n toolChoice: a._config.toolChoice,\n stop: a._config.stop,\n }));\n return c.json({ ok: true, data: agents });\n});\n\n// Get agent detail\napp.get('/agents/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const agent = runtime.getAgent(name);\n if (!agent) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Agent \"${name}\" not found` } },\n 404,\n );\n }\n\n const cfg = agent._config;\n return c.json({\n ok: true,\n data: {\n name: agent._name,\n model: agent.resolveModel(),\n system: agent.resolveSystem(),\n tools:\n cfg.tools?.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: zodToJsonSchema(t.inputSchema),\n })) ?? [],\n handoffs:\n typeof cfg.handoffs === 'function'\n ? [\n {\n agent: '(dynamic)',\n description: 'Resolved at runtime from metadata',\n mode: 'oneway' as const,\n },\n ]\n : (cfg.handoffs?.map((h) => ({\n agent: h.agent._name,\n description: h.description,\n mode: h.mode ?? 'oneway',\n })) ?? []),\n maxTurns: cfg.maxTurns,\n temperature: cfg.temperature,\n maxTokens: cfg.maxTokens,\n effort: cfg.effort,\n thinkingBudget: cfg.thinkingBudget,\n includeThoughts: cfg.includeThoughts,\n toolChoice: cfg.toolChoice,\n stop: cfg.stop,\n timeout: cfg.timeout,\n maxContext: cfg.maxContext,\n version: cfg.version,\n mcp: cfg.mcp,\n mcpTools: cfg.mcpTools,\n hasGuardrails: !!cfg.guardrails,\n guardrails: cfg.guardrails\n ? {\n hasInput: !!cfg.guardrails.input,\n hasOutput: !!cfg.guardrails.output,\n onBlock: cfg.guardrails.onBlock ?? 'throw',\n maxRetries: cfg.guardrails.maxRetries,\n }\n : null,\n },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, ToolSummary } from '../types.js';\nimport { redactValue } from '../redact.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all tools\napp.get('/tools', (c) => {\n const runtime = c.get('runtime');\n const tools: ToolSummary[] = runtime.getTools().map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema ? zodToJsonSchema(t.inputSchema) : {},\n sensitive: t.sensitive ?? false,\n requireApproval: t.requireApproval ?? false,\n }));\n return c.json({ ok: true, data: tools });\n});\n\n// Get tool detail\napp.get('/tools/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const tool = runtime.getTool(name);\n if (!tool) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Tool \"${name}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema ? zodToJsonSchema(tool.inputSchema) : {},\n sensitive: tool.sensitive,\n requireApproval: tool.requireApproval,\n retry: tool.retry,\n hasHooks: !!tool.hooks,\n hooks: tool.hooks\n ? {\n hasBefore: !!tool.hooks.before,\n hasAfter: !!tool.hooks.after,\n }\n : null,\n },\n });\n});\n\n// Test a tool directly\napp.post('/tools/:name/test', async (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const tool = runtime.getTool(name);\n if (!tool) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Tool \"${name}\" not found` } },\n 404,\n );\n }\n\n const body = await c.req.json<{ input: unknown }>();\n const ctx = runtime.createContext();\n const result = await tool.run(ctx, body.input);\n return c.json({\n ok: true,\n data: { result: redactValue(result, runtime.isRedactEnabled()) },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport { redactMemoryList, redactMemoryValue } from '../redact.js';\n\nconst app = new Hono<StudioEnv>();\n\n// Get all memory entries for a scope\napp.get('/memory/:scope', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n\n if (!store.getAllMemory) {\n return c.json({ ok: true, data: [] });\n }\n\n const entries = await store.getAllMemory(scope);\n return c.json({ ok: true, data: redactMemoryList(entries, runtime.isRedactEnabled()) });\n});\n\n// Get a specific memory entry\napp.get('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.getMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n const value = await store.getMemory(scope, key);\n if (value === null) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Memory \"${scope}/${key}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: { key, value: redactMemoryValue(value, runtime.isRedactEnabled()) },\n });\n});\n\n// Save a memory entry\napp.put('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.saveMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n const body = await c.req.json<{ value: unknown }>();\n await store.saveMemory(scope, key, body.value);\n return c.json({ ok: true, data: { saved: true } });\n});\n\n// Delete a memory entry\napp.delete('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.deleteMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n await store.deleteMemory(scope, key);\n return c.json({ ok: true, data: { deleted: true } });\n});\n\n// Semantic search\napp.post('/memory/search', async (c) => {\n // TODO: Connect to MemoryManager's vector search once exposed\n return c.json({\n ok: true,\n data: { results: [], message: 'Semantic search requires MemoryManager with vector store' },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport { redactPendingDecisionList } from '../redact.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List pending decisions\napp.get('/decisions', async (c) => {\n const runtime = c.get('runtime');\n const decisions = await runtime.getPendingDecisions();\n return c.json({\n ok: true,\n data: redactPendingDecisionList(decisions, runtime.isRedactEnabled()),\n });\n});\n\n// Resolve a pending decision\napp.post('/decisions/:executionId/resolve', async (c) => {\n const runtime = c.get('runtime');\n const executionId = c.req.param('executionId');\n const body = await c.req.json<{ approved: boolean; reason?: string }>();\n\n await runtime.resolveDecision(executionId, body);\n return c.json({ ok: true, data: { resolved: true } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { TraceAggregator } from '../aggregates/trace-aggregator.js';\nimport type { CostData } from '../types.js';\nimport { parseWindowParam } from '../aggregates/aggregate-snapshots.js';\n\nexport function createCostRoutes(costAggregator: TraceAggregator<CostData>) {\n const app = new Hono<StudioEnv>();\n\n app.get('/costs', (c) => {\n // Multi-window debug mode\n if (c.req.query('windows') === 'all') {\n return c.json({ ok: true, data: costAggregator.getAllSnapshots() });\n }\n\n const window = parseWindowParam(c.req.query('window'));\n return c.json({ ok: true, data: costAggregator.getSnapshot(window) });\n });\n\n // Migration stub for the removed `POST /api/costs/reset` endpoint.\n //\n // Pre-0.15 Studio exposed a mutating reset that cleared the in-memory cost\n // aggregator. In 0.15 the dashboard switched to time-window aggregates over\n // StateStore history, so \"reset\" is no longer meaningful — the displayed\n // window simply narrows. Scripts (CI dashboards, ops tooling) that still hit\n // this URL would otherwise get Hono's default 404 with no hint about the\n // migration path. Return a structured 410 Gone with a concrete pointer.\n app.post('/costs/reset', (c) => {\n return c.json(\n {\n ok: false,\n error: {\n code: 'GONE',\n message:\n 'POST /api/costs/reset was removed in @axlsdk/studio 0.15. ' +\n 'Cost aggregates are now time-windowed and rebuilt from StateStore history. ' +\n 'Use GET /api/costs?window=24h|7d|30d|all to narrow the view instead of resetting.',\n },\n },\n 410,\n );\n });\n\n return app;\n}\n","import { randomUUID } from 'node:crypto';\nimport { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport type { EvalResult, Scorer } from '@axlsdk/eval';\nimport { redactEvalHistoryList, redactEvalResult, redactErrorMessage } from '../redact.js';\n\nexport function createEvalRoutes(connMgr: ConnectionManager, evalLoader?: () => Promise<void>) {\n const app = new Hono<StudioEnv>();\n\n // Active streaming eval runs, keyed by evalRunId. Scoped per-middleware\n // instance so multiple `createStudioMiddleware()` mounts in the same process\n // (multi-tenant deployments, concurrent unit tests) don't collide on run IDs\n // or leak AbortControllers across middleware lifecycles.\n const activeRuns = new Map<string, AbortController>();\n\n // List registered eval configs\n app.get('/evals', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const evals = runtime.getRegisteredEvals();\n // Registered eval configs contain dataset definitions — the dataset\n // `.getItems()` contents aren't serialized in this response (we just\n // return names + scorer list), so there's no raw content to scrub.\n return c.json({ ok: true, data: evals });\n });\n\n // Get eval run history\n app.get('/evals/history', async (c) => {\n const runtime = c.get('runtime');\n const history = await runtime.getEvalHistory();\n return c.json({\n ok: true,\n data: redactEvalHistoryList(history, runtime.isRedactEnabled()),\n });\n });\n\n // Delete a single eval history entry by id.\n app.delete('/evals/history/:id', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const deleted = await runtime.deleteEvalResult(id);\n if (!deleted) {\n return c.json(\n {\n ok: false,\n error: { code: 'NOT_FOUND', message: `Eval history entry \"${id}\" not found` },\n },\n 404,\n );\n }\n return c.json({ ok: true, data: { id, deleted: true } });\n });\n\n // Run a registered eval by name.\n //\n // Body options:\n // runs?: number — multi-run count (capped at 25)\n // stream?: true — return evalRunId immediately, broadcast progress via WS\n //\n // When stream is false/absent, the endpoint blocks until the eval completes\n // and returns the full result (backward compatible).\n app.post('/evals/:name/run', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const redactOn = runtime.isRedactEnabled();\n\n const entry = runtime.getRegisteredEval(name);\n if (!entry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Eval \"${name}\" not found` } },\n 404,\n );\n }\n\n let runs = 1;\n let stream = false;\n let captureTraces = false;\n try {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n if (typeof body.runs === 'number' && Number.isFinite(body.runs) && body.runs > 1) {\n runs = Math.min(Math.floor(body.runs), 25);\n }\n if (body.stream === true) {\n stream = true;\n }\n if (body.captureTraces === true) {\n captureTraces = true;\n }\n } catch {\n // No body or invalid body — single run, synchronous\n }\n\n // ── Streaming mode ─────────────────────────────────────────────\n if (stream) {\n const evalRunId = `eval-${randomUUID()}`;\n const ac = new AbortController();\n activeRuns.set(evalRunId, ac);\n\n // Fire-and-forget async execution with WS progress broadcasting.\n //\n // NOTE on the done event shape: we deliberately broadcast only a\n // pointer (`evalResultId`, optional `runGroupId`) instead of the\n // full `EvalResult`. A real eval result with ~12 items, per-item\n // score details, and metadata easily exceeds 64KB, which is our\n // WS frame budget. When we previously embedded the whole result,\n // `truncateIfOversized` replaced it with a `{__truncated}` stub\n // and the client rendered a blank screen.\n //\n // Architecturally: WS events are for small notifications,\n // `runRegisteredEval` already persists results to history via the\n // StateStore, and the client can fetch the full payload from\n // `GET /api/evals/history` once notified. This matches the hint\n // text that the truncation placeholder already used to emit.\n (async () => {\n try {\n if (runs > 1) {\n const runGroupId = randomUUID();\n const results: EvalResult[] = [];\n // Per-run failure no longer tanks the whole batch — completed\n // runs cost real money and have statistical signal. We capture\n // the first failure, stop attempting further runs (same\n // reasoning as the CLI: don't speculatively burn API calls on a\n // potentially-permanent failure), and emit a partial-aware\n // `done` event so the client can render the partial result\n // distinctly. `batchAttempted` is stamped on every run's\n // metadata up front so persisted history records carry the\n // expected count, letting any later viewer derive partial-ness.\n let runFailure: Error | undefined;\n\n // Tracks user cancellation separately from genuine failure\n // so the terminal `done` event can label the partial batch\n // correctly (`cancelled: true` vs `batchFailure: \"<msg>\"`).\n // Without this distinction, a mid-run cancel would show as\n // \"Run 3/5 failed: AbortError: ...\" — confusing UX since the\n // user knows they pressed cancel.\n let cancelled = false;\n for (let r = 0; r < runs; r++) {\n if (ac.signal.aborted) {\n cancelled = true;\n break;\n }\n try {\n const result = (await runtime.runRegisteredEval(name, {\n metadata: { runGroupId, runIndex: r, batchAttempted: runs },\n signal: ac.signal,\n captureTraces,\n onProgress: (event) => {\n // Library-level `run_done` fires after every iteration with\n // `{ totalItems, failures }`; Studio emits its own wire-level\n // `run_done` below with `{ run, totalRuns }` semantics, so we\n // drop the library variant to avoid collision on the client.\n if (event.type === 'run_done') return;\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n ...event,\n run: r + 1,\n totalRuns: runs,\n });\n },\n })) as EvalResult;\n results.push(result);\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'run_done',\n run: r + 1,\n totalRuns: runs,\n });\n } catch (err) {\n // Distinguish user cancellation from genuine failure. An\n // AbortError thrown mid-`runRegisteredEval` (signal fired\n // while the run was in flight) is the user pressing\n // cancel, not the provider failing. Don't stamp a\n // `batchFailure` for it — that field reads as a fault\n // signal in the History badge and Compare banners.\n const isAbort =\n ac.signal.aborted || (err instanceof Error && err.name === 'AbortError');\n if (isAbort) {\n cancelled = true;\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'run_cancelled',\n run: r + 1,\n totalRuns: runs,\n });\n break;\n }\n runFailure = err instanceof Error ? err : new Error(String(err));\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'run_failed',\n run: r + 1,\n totalRuns: runs,\n message: redactErrorMessage(runFailure, redactOn),\n });\n break;\n }\n }\n\n if (results.length > 0) {\n const partial = results.length < runs;\n // Coalesce empty-message errors so the banner never shows a\n // blank \"Stopped after:\" line. `new Error('')` produces\n // `message === ''`; `redactErrorMessage` preserves that under\n // safe-error-name allow-listing, so we fall through to\n // `String(runFailure)` (which yields at least the constructor\n // name) before omitting the field entirely.\n const failureMsg = runFailure\n ? redactErrorMessage(runFailure, redactOn) || String(runFailure) || undefined\n : undefined;\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'done',\n evalResultId: results[0].id,\n runGroupId,\n ...(partial && {\n partial: true,\n batchCompleted: results.length,\n batchAttempted: runs,\n // `cancelled` and `batchFailure` are mutually exclusive:\n // the catch block sets at most one of {cancelled,\n // runFailure}. The client uses `cancelled` to render a\n // neutral \"Cancelled — X of N runs completed\" caption\n // instead of the amber \"Stopped after: <message>\"\n // failure caption.\n ...(cancelled ? { cancelled: true } : {}),\n ...(failureMsg ? { batchFailure: failureMsg } : {}),\n }),\n });\n } else if (runFailure) {\n // No runs completed — a hard error, not a partial.\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'error',\n message: redactErrorMessage(runFailure, redactOn),\n });\n } else {\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'error',\n message: 'All runs were cancelled',\n });\n }\n } else {\n const result = (await runtime.runRegisteredEval(name, {\n signal: ac.signal,\n captureTraces,\n onProgress: (event) => {\n // Drop library-level `run_done` — Studio's terminal signal for\n // single-run streams is the `done` event below, which carries\n // the `evalResultId` pointer the client uses to refetch.\n if (event.type === 'run_done') return;\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, event);\n },\n })) as EvalResult;\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'done',\n evalResultId: result.id,\n });\n }\n } catch (err) {\n // Eval-channel error event shape is NOT a `StreamEvent`, so it\n // doesn't pass through `redactStreamEvent`. Scrub the message\n // inline so ValidationError/GuardrailError/provider errors don't\n // leak user input on the eval:* channel under redact mode.\n // (StreamEvent itself is legacy — see TODO in redact.ts.)\n connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {\n type: 'error',\n message: redactErrorMessage(err, redactOn),\n });\n } finally {\n activeRuns.delete(evalRunId);\n }\n })();\n\n return c.json({ ok: true, data: { evalRunId } });\n }\n\n // ── Synchronous mode (backward compatible) ─────────────────────\n try {\n if (runs > 1) {\n const { aggregateRuns } = await import('@axlsdk/eval');\n const runGroupId = randomUUID();\n const results: EvalResult[] = [];\n // Same partial-preservation pattern as the streaming path: catch\n // per-run failures, break, return the partial batch with explicit\n // markers. Differs from streaming only in delivery — here partial\n // info rides on the JSON response (`_multiRun.partial` etc.)\n // instead of a WS event.\n let runFailure: Error | undefined;\n for (let r = 0; r < runs; r++) {\n try {\n const result = await runtime.runRegisteredEval(name, {\n metadata: { runGroupId, runIndex: r, batchAttempted: runs },\n captureTraces,\n });\n results.push(result as EvalResult);\n } catch (err) {\n runFailure = err instanceof Error ? err : new Error(String(err));\n break;\n }\n }\n if (results.length === 0) {\n throw runFailure ?? new Error('No runs completed');\n }\n const aggregate = aggregateRuns(results);\n const first = results[0];\n const partial = results.length < runs;\n // Coalesce empty-message errors so the response never carries a\n // blank batchFailure (downstream `buildMultiRunResult` filters\n // empty strings, so an empty value here just becomes silent —\n // worse than omitting the field).\n const failureMsg = runFailure\n ? redactErrorMessage(runFailure, redactOn) || String(runFailure) || undefined\n : undefined;\n const result = {\n ...first,\n _multiRun: {\n aggregate,\n allRuns: results,\n ...(partial && {\n partial: true,\n batchCompleted: results.length,\n batchAttempted: runs,\n ...(failureMsg ? { batchFailure: failureMsg } : {}),\n }),\n },\n } as EvalResult;\n return c.json({\n ok: true,\n data: redactEvalResult(result, redactOn),\n });\n } else {\n // Runtime persists eval result to history automatically\n const result = (await runtime.runRegisteredEval(name, { captureTraces })) as EvalResult;\n return c.json({\n ok: true,\n data: redactEvalResult(result, redactOn),\n });\n }\n } catch (err) {\n // Inline error envelope — scrub to keep redaction semantics\n // consistent with the global `errorHandler` middleware.\n return c.json(\n { ok: false, error: { code: 'EVAL_ERROR', message: redactErrorMessage(err, redactOn) } },\n 400,\n );\n }\n });\n\n // Cancel an active streaming eval run.\n app.post('/evals/runs/:evalRunId/cancel', (c) => {\n const evalRunId = c.req.param('evalRunId');\n const ac = activeRuns.get(evalRunId);\n if (!ac) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: 'No active eval run found' } },\n 404,\n );\n }\n ac.abort();\n activeRuns.delete(evalRunId);\n return c.json({ ok: true, data: { cancelled: true } });\n });\n\n // Rescore: re-run scorers on saved outputs\n app.post('/evals/:name/rescore', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const redactOn = runtime.isRedactEnabled();\n const name = c.req.param('name');\n const body = await c.req.json<{ resultId: string }>();\n\n if (!body.resultId || typeof body.resultId !== 'string') {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'resultId is required' } },\n 400,\n );\n }\n\n const entry = runtime.getRegisteredEval(name);\n if (!entry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Eval \"${name}\" not found` } },\n 404,\n );\n }\n\n const history = await runtime.getEvalHistory();\n const historyEntry = history.find((h) => h.id === body.resultId);\n if (!historyEntry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Result \"${body.resultId}\" not found` } },\n 404,\n );\n }\n\n try {\n const { rescore } = await import('@axlsdk/eval');\n const config = entry.config as { scorers?: unknown[] };\n const result = await rescore(\n historyEntry.data as EvalResult,\n config.scorers as Scorer[],\n runtime,\n );\n await runtime.saveEvalResult({\n id: result.id,\n eval: name,\n timestamp: Date.now(),\n data: result,\n });\n return c.json({\n ok: true,\n data: redactEvalResult(result, redactOn),\n });\n } catch (err) {\n return c.json(\n { ok: false, error: { code: 'EVAL_ERROR', message: redactErrorMessage(err, redactOn) } },\n 400,\n );\n }\n });\n\n // Compare eval results by history ID.\n //\n // Accepts baselineId/candidateId as string (single run) or string[] (pooled\n // multi-run group). IDs are resolved from runtime history server-side so the\n // wire payload stays tiny — this avoids hitting host body-parser limits when\n // Studio is mounted as middleware behind Express/NestJS/Fastify.\n app.post('/evals/compare', async (c) => {\n const runtime = c.get('runtime');\n const redactOn = runtime.isRedactEnabled();\n const body = await c.req.json<{\n baselineId: string | string[];\n candidateId: string | string[];\n options?: { thresholds?: Record<string, number> | number };\n }>();\n\n // Validate ID shapes up front. Each side must be a non-empty string or a\n // non-empty array of non-empty strings. `!body.baselineId` would treat\n // `[]` as truthy, so check explicitly. We also reject arrays that contain\n // any non-string element (e.g. `[null]`), which would otherwise produce a\n // confusing \"Eval result(s) not found in history: null\" error downstream.\n //\n // DoS cap (reviewer HIGH H1): `evalCompare` pools items across all runs\n // for paired bootstrap CI (1000 resamples). An unbounded array lets a\n // readOnly attacker run 500-run × 100-item × 1000-resample comparisons\n // on each request. Cap at 25 to match the multi-run ceiling on\n // `POST /api/evals/:name/run`.\n const MAX_POOLED_RUNS = 25;\n const validateIdParam = (v: unknown, name: string): string | null => {\n if (typeof v === 'string') return v === '' ? `${name} must be non-empty` : null;\n if (Array.isArray(v)) {\n if (v.length === 0) return `${name} must be a non-empty array`;\n if (v.length > MAX_POOLED_RUNS) {\n return `${name} may contain at most ${MAX_POOLED_RUNS} ids (pooled comparison)`;\n }\n for (const elem of v) {\n if (typeof elem !== 'string' || elem === '') {\n return `${name} array must contain only non-empty strings`;\n }\n }\n return null;\n }\n return `${name} is required (string or string[])`;\n };\n const baselineErr = validateIdParam(body.baselineId, 'baselineId');\n const candidateErr = validateIdParam(body.candidateId, 'candidateId');\n if (baselineErr || candidateErr) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'BAD_REQUEST',\n message: [baselineErr, candidateErr].filter(Boolean).join('; '),\n },\n },\n 400,\n );\n }\n\n const history = await runtime.getEvalHistory();\n const byId = new Map(history.map((h) => [h.id, h.data as EvalResult]));\n\n const missing: string[] = [];\n const resolveOne = (id: string): EvalResult | undefined => {\n const data = byId.get(id);\n if (!data) missing.push(id);\n return data;\n };\n const resolveSelection = (\n idOrIds: string | string[],\n ): EvalResult | EvalResult[] | undefined => {\n if (Array.isArray(idOrIds)) {\n // Dedupe so callers passing [id, id] don't artificially shrink the\n // paired-bootstrap variance in downstream CI computation.\n const unique = Array.from(new Set(idOrIds));\n // Single-element groups are semantically equivalent to a single ID;\n // unwrap so evalCompare uses the simpler single-result code path\n // instead of the multi-run pooling path with one run.\n if (unique.length === 1) return resolveOne(unique[0]);\n const results: EvalResult[] = [];\n for (const id of unique) {\n const data = resolveOne(id);\n if (data) results.push(data);\n }\n return results;\n }\n return resolveOne(idOrIds);\n };\n\n const baseline = resolveSelection(body.baselineId);\n const candidate = resolveSelection(body.candidateId);\n\n if (missing.length > 0) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'NOT_FOUND',\n message: `Eval result(s) not found in history: ${missing.join(', ')}`,\n },\n },\n 404,\n );\n }\n\n try {\n // `missing.length === 0` guarantees both are defined here.\n const result = await runtime.evalCompare(baseline!, candidate!, body.options);\n return c.json({ ok: true, data: result });\n } catch (err) {\n return c.json(\n {\n ok: false,\n error: { code: 'COMPARE_FAILED', message: redactErrorMessage(err, redactOn) },\n },\n 400,\n );\n }\n });\n\n // Import a CLI eval artifact into runtime history.\n //\n // Accepts a parsed EvalResult JSON (single object) OR an array of\n // EvalResults (multi-run output). The CLI writes a single object when\n // `results.length === 1` and an array otherwise — including for partial\n // batches (e.g. 2-of-5 produces a 2-element array). Without array\n // support, partial multi-run artifacts couldn't be imported in one\n // request, undermining the partial-batch story we worked to preserve.\n //\n // For arrays: every result is imported as its own history entry; if the\n // artifact's per-run `metadata.runGroupId` is consistent across the\n // array, the entries appear together as a multi-run group in the\n // History tab. A fresh UUID is generated per entry so repeated imports\n // don't collide.\n //\n // Note: this is the one Studio endpoint whose request bodies can be large.\n // If mounted as middleware and importing sizeable eval files, raise the\n // host framework's JSON body limit on the Studio mount.\n app.post('/evals/import', async (c) => {\n const runtime = c.get('runtime');\n const body = await c.req.json<{\n result: unknown;\n eval?: string;\n }>();\n\n const bad = (message: string) =>\n c.json({ ok: false, error: { code: 'BAD_REQUEST', message } }, 400);\n\n if (body.result === undefined || body.result === null) {\n return bad('result is required');\n }\n\n // Normalize to an array up front. Single-object form is just a\n // 1-element array internally — keeps the validation/import loop\n // uniform and avoids two divergent code paths that could drift.\n const resultsRaw = Array.isArray(body.result) ? body.result : [body.result];\n if (resultsRaw.length === 0) {\n return bad('result must be a non-empty array or object');\n }\n\n // Validate each entry separately so a heterogeneous batch (one bad\n // run in a 5-run array) reports a precise index rather than rejecting\n // the whole import or accepting it half-formed.\n const validatedResults: Array<Record<string, unknown>> = [];\n for (let i = 0; i < resultsRaw.length; i++) {\n const entry = resultsRaw[i];\n const prefix = resultsRaw.length > 1 ? `result[${i}]` : 'result';\n if (!entry || typeof entry !== 'object') {\n return bad(`${prefix} must be an object`);\n }\n const r = entry as Record<string, unknown>;\n if (!Array.isArray(r.items)) {\n return bad(`${prefix}.items must be an array`);\n }\n if (typeof r.summary !== 'object' || r.summary == null) {\n return bad(`${prefix}.summary must be an object`);\n }\n if (typeof r.dataset !== 'string' || !r.dataset) {\n return bad(`${prefix}.dataset must be a non-empty string (required for compare)`);\n }\n const summary = r.summary as Record<string, unknown>;\n if (typeof summary.scorers !== 'object' || summary.scorers == null) {\n return bad(`${prefix}.summary.scorers must be an object`);\n }\n const summaryScorerNames = Object.keys(summary.scorers as Record<string, unknown>);\n const items = r.items as Array<Record<string, unknown>>;\n const summaryScorerSet = new Set(summaryScorerNames);\n const uncoveredAcrossItems = new Set<string>();\n for (const item of items) {\n const itemScores = item?.scores;\n if (itemScores && typeof itemScores === 'object') {\n for (const name of Object.keys(itemScores as Record<string, unknown>)) {\n if (!summaryScorerSet.has(name)) uncoveredAcrossItems.add(name);\n }\n }\n }\n if (uncoveredAcrossItems.size > 0) {\n return bad(\n `${prefix} item scores reference scorer(s) not in summary.scorers: ${[...uncoveredAcrossItems].join(', ')}`,\n );\n }\n validatedResults.push(r);\n }\n\n // Eval-name resolution uses the FIRST run's metadata as the\n // representative — multi-run groups always share a workflow today\n // (the runner produces homogeneous batches), and falling back across\n // all runs would silently mask a heterogeneous import the user\n // probably didn't intend.\n const trim = (v: unknown): string | undefined =>\n typeof v === 'string' && v.trim() !== '' ? v.trim() : undefined;\n const firstResult = validatedResults[0];\n const metadataObj =\n typeof firstResult.metadata === 'object' && firstResult.metadata != null\n ? (firstResult.metadata as Record<string, unknown>)\n : {};\n const workflowsFromMeta = Array.isArray(metadataObj.workflows)\n ? (metadataObj.workflows as unknown[])\n : [];\n const primaryWorkflow = workflowsFromMeta.find((w): w is string => typeof w === 'string');\n const evalName =\n trim(body.eval) ??\n trim(primaryWorkflow) ??\n trim((firstResult as { workflow?: unknown }).workflow) ??\n 'imported';\n\n const timestamp = Date.now();\n const imported: Array<{ id: string; eval: string; timestamp: number }> = [];\n for (const r of validatedResults) {\n const id = randomUUID();\n // Overwrite id so repeated imports of the same file get distinct\n // entries. Preserve metadata so per-run runGroupId / batchAttempted\n // / fromPartialBatch flow through to compare and trends views.\n const entry: EvalResult = {\n ...(r as unknown as EvalResult),\n id,\n metadata:\n typeof r.metadata === 'object' && r.metadata != null\n ? (r.metadata as Record<string, unknown>)\n : {},\n };\n await runtime.saveEvalResult({ id, eval: evalName, timestamp, data: entry });\n imported.push({ id, eval: evalName, timestamp });\n }\n\n // Back-compat: single-import callers still get the flat shape they\n // expected. Multi-import callers get an array indistinguishable\n // from the input order.\n if (imported.length === 1) {\n return c.json({ ok: true, data: imported[0] });\n }\n return c.json({ ok: true, data: { imported } });\n });\n\n function closeActiveRuns() {\n for (const ac of activeRuns.values()) ac.abort();\n activeRuns.clear();\n }\n\n return { app, closeActiveRuns };\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\nimport { redactStreamEvent } from '../redact.js';\nimport type { AxlEvent } from '@axlsdk/axl';\n\nexport function createPlaygroundRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // Chat with an agent directly — no workflow required\n app.post('/playground/chat', async (c) => {\n const runtime = c.get('runtime');\n const body = await c.req.json<{\n sessionId?: string;\n message: string;\n agent?: string;\n }>();\n\n if (!body.message || typeof body.message !== 'string' || !body.message.trim()) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'INVALID_INPUT',\n message: 'message is required and must be a non-empty string',\n },\n },\n 400,\n );\n }\n\n const agents = runtime.getAgents();\n const agent = body.agent ? agents.find((a) => a._name === body.agent) : agents[0];\n if (!agent) {\n return c.json(\n {\n ok: false,\n error: { code: 'NO_AGENT', message: `Agent \"${body.agent ?? ''}\" not found` },\n },\n 400,\n );\n }\n\n const sessionId = body.sessionId ?? `playground-${Date.now()}`;\n const store = runtime.getStateStore();\n\n // Load session history for multi-turn conversations\n const history = await store.getSession(sessionId);\n history.push({ role: 'user', content: body.message });\n\n const redactOn = runtime.isRedactEnabled();\n\n // Create context — its auto-generated executionId becomes the WS channel name.\n // Token events flow through emitEvent → runtime.emit('trace') → our listener below,\n // so no manual onToken needed.\n const ctx = runtime.createContext({ sessionHistory: history });\n const executionId = ctx.executionId;\n\n // Forward ALL AxlEvents from this execution to the WS channel.\n // This gives the playground UI access to ask_start, agent_call, tool_call,\n // handoff, pipeline, etc. — not just tokens.\n const traceListener = (event: AxlEvent) => {\n if (event.executionId !== executionId) return;\n connMgr.broadcastWithWildcard(`execution:${executionId}`, redactStreamEvent(event, redactOn));\n };\n runtime.on('trace', traceListener);\n\n // Run the agent ask asynchronously, stream results via WS\n (async () => {\n let stepCounter = Number.MAX_SAFE_INTEGER - 1;\n const terminalFields = () => ({\n executionId,\n step: stepCounter++,\n timestamp: Date.now(),\n });\n\n try {\n const result = await ctx.ask(agent, body.message);\n const resultText = typeof result === 'string' ? result : JSON.stringify(result);\n\n history.push({ role: 'assistant', content: resultText });\n await store.saveSession(sessionId, history);\n\n const doneEvent: AxlEvent = {\n ...terminalFields(),\n type: 'done',\n data: { result: resultText },\n };\n connMgr.broadcastWithWildcard(\n `execution:${executionId}`,\n redactStreamEvent(doneEvent, redactOn),\n );\n } catch (err) {\n const errorEvent: AxlEvent = {\n ...terminalFields(),\n type: 'error',\n data: { message: err instanceof Error ? err.message : String(err) },\n };\n connMgr.broadcastWithWildcard(\n `execution:${executionId}`,\n redactStreamEvent(errorEvent, redactOn),\n );\n } finally {\n runtime.off('trace', traceListener);\n }\n })();\n\n return c.json({\n ok: true,\n data: { sessionId, executionId, streaming: true },\n });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { EvalAggregator } from '../aggregates/eval-aggregator.js';\nimport type { EvalTrendData } from '../aggregates/reducers.js';\nimport { parseWindowParam } from '../aggregates/aggregate-snapshots.js';\n\nexport function createEvalTrendsRoutes(aggregator: EvalAggregator<EvalTrendData>) {\n const app = new Hono<StudioEnv>();\n\n app.get('/eval-trends', (c) => {\n const window = parseWindowParam(c.req.query('window'));\n return c.json({ ok: true, data: aggregator.getSnapshot(window) });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { ExecutionAggregator } from '../aggregates/execution-aggregator.js';\nimport type { WorkflowStatsData } from '../aggregates/reducers.js';\nimport { enrichWorkflowStats } from '../aggregates/reducers.js';\nimport { parseWindowParam } from '../aggregates/aggregate-snapshots.js';\n\nexport function createWorkflowStatsRoutes(aggregator: ExecutionAggregator<WorkflowStatsData>) {\n const app = new Hono<StudioEnv>();\n\n app.get('/workflow-stats', (c) => {\n const window = parseWindowParam(c.req.query('window'));\n return c.json({ ok: true, data: enrichWorkflowStats(aggregator.getSnapshot(window)) });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { TraceAggregator } from '../aggregates/trace-aggregator.js';\nimport type { TraceStatsData } from '../aggregates/reducers.js';\nimport { parseWindowParam } from '../aggregates/aggregate-snapshots.js';\n\nexport function createTraceStatsRoutes(aggregator: TraceAggregator<TraceStatsData>) {\n const app = new Hono<StudioEnv>();\n\n app.get('/trace-stats', (c) => {\n const window = parseWindowParam(c.req.query('window'));\n return c.json({ ok: true, data: aggregator.getSnapshot(window) });\n });\n\n return app;\n}\n","import { resolve, relative, basename } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { AxlRuntime, EvalExecuteWorkflow } from '@axlsdk/axl';\nimport { importModule, expandGlob, registerConditions, pickDefault, pickExport } from '@axlsdk/axl';\n\n// In the CJS bundle, tsup stubs import.meta as {} so import.meta.url is\n// undefined. Fall back to __filename (which CJS defines) converted to a\n// file:// URL so tsImport() gets a valid parentURL.\nconst parentURL: string =\n import.meta.url ?? pathToFileURL(typeof __filename !== 'undefined' ? __filename : __dirname).href;\n\n/**\n * Configuration for lazy eval file discovery.\n *\n * - `string` — a glob pattern or explicit file path\n * - `string[]` — multiple patterns/paths\n * - `object` — patterns with optional import conditions\n */\nexport type EvalLoaderConfig =\n | string\n | string[]\n | {\n files: string | string[];\n\n /**\n * Custom Node.js import conditions (e.g., `['development']`).\n *\n * In monorepos, package.json `exports` often use the `development` condition\n * to point at source (`.ts`) instead of built dist. Without this, eval files\n * that import workspace packages resolve to dist files, which may not exist.\n *\n * **WARNING**: Conditions are registered process-wide via `module.register()`.\n * They affect all subsequent imports in the process, not just eval files.\n */\n conditions?: string[];\n };\n\n/**\n * Create a lazy eval loader that resolves file patterns and dynamically imports\n * eval files on first call, registering them with the runtime.\n *\n * The loader is idempotent — subsequent calls return the same promise.\n * Concurrent callers all await the same loading work.\n *\n * Eval files should export a default config with `{ workflow, dataset, scorers }`\n * (the result of `defineEval()` from `@axlsdk/eval`). An optional named export\n * `executeWorkflow` overrides the default `runtime.execute()` behavior.\n *\n * Eval names are the file's path relative to `cwd` (project root), minus the\n * `.eval.*` suffix. This makes names completely stable — a file's name never\n * changes regardless of what other files or patterns exist.\n *\n * @param config Glob patterns, file paths, or object with conditions\n * @param runtime The AxlRuntime to register discovered evals on\n * @param cwd Base directory for resolving patterns and deriving names (default: `process.cwd()`)\n */\nexport function createEvalLoader(\n config: EvalLoaderConfig,\n runtime: AxlRuntime,\n cwd?: string,\n): () => Promise<void> {\n let loadPromise: Promise<void> | undefined;\n const { patterns, conditions } = normalizeConfig(config);\n const baseCwd = cwd ?? process.cwd();\n\n return () => {\n if (!loadPromise) {\n loadPromise = loadEvalFiles(patterns, conditions, baseCwd, runtime).catch((err) => {\n loadPromise = undefined; // Allow retry on next request\n throw err;\n });\n }\n return loadPromise;\n };\n}\n\n// ── Core loading logic ─────────────────────────────────────────────\n\nasync function loadEvalFiles(\n patterns: string[],\n conditions: string[],\n cwd: string,\n runtime: AxlRuntime,\n): Promise<void> {\n if (conditions.length > 0) {\n await registerConditions(conditions);\n }\n\n const files = resolvePatterns(patterns, cwd);\n\n if (files.length === 0) {\n console.warn(`[axl-studio] No eval files found matching: ${patterns.join(', ')}`);\n return;\n }\n\n for (const file of files) {\n try {\n const mod = await importModule(file, parentURL);\n const evalConfig = pickDefault<{\n workflow?: string;\n dataset?: unknown;\n scorers?: unknown;\n }>(mod);\n\n if (!evalConfig || typeof evalConfig !== 'object') {\n console.warn(\n `[axl-studio] Skipping ${file}: default export is ` +\n `${evalConfig === null ? 'null' : typeof evalConfig}, expected an eval config object.`,\n );\n continue;\n }\n if (Array.isArray(evalConfig.scorers) && evalConfig.scorers.length === 0) {\n console.warn(\n `[axl-studio] Skipping ${file}: scorers array is empty — at least one scorer is required.`,\n );\n continue;\n }\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n const missing = [\n !evalConfig.workflow && 'workflow',\n !evalConfig.dataset && 'dataset',\n !evalConfig.scorers && 'scorers',\n ]\n .filter(Boolean)\n .join(', ');\n const keys = Object.keys(evalConfig).slice(0, 10);\n const got = keys.length > 0 ? ` Got: { ${keys.join(', ')} }.` : '';\n console.warn(\n `[axl-studio] Skipping ${file}: not a valid eval config (missing ${missing}).${got}`,\n );\n continue;\n }\n\n const name = deriveEvalName(file, cwd);\n\n if (runtime.getRegisteredEval(name)) {\n console.warn(\n `[axl-studio] Eval name \"${name}\" from ${file} collides with an ` +\n `already-registered eval — overwriting`,\n );\n }\n\n // Walk the ESM/CJS interop chain symmetrically with the default export\n // so `executeWorkflow` stays visible when tsx loads the eval module as CJS\n // (e.g. a `.ts` file in a package without `\"type\": \"module\"`). Validate\n // the export is callable — a non-function `executeWorkflow` is silently\n // ignored so registration falls back to `runtime.execute()`, with a\n // warning so the user knows their export was rejected.\n const exported = pickExport<unknown>(mod, 'executeWorkflow');\n let customExecute: EvalExecuteWorkflow | undefined;\n if (typeof exported === 'function') {\n customExecute = exported as EvalExecuteWorkflow;\n } else if (exported !== undefined) {\n console.warn(\n `[axl-studio] ${file} exports executeWorkflow but it is ${typeof exported}, ` +\n `not a function — ignoring and falling back to runtime.execute()`,\n );\n }\n runtime.registerEval(name, evalConfig, customExecute);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[axl-studio] Failed to load eval ${file}: ${msg}`);\n }\n }\n}\n\n// ── Internal helpers ───────────────────────────────────────────────\n\nfunction normalizeConfig(config: EvalLoaderConfig): {\n patterns: string[];\n conditions: string[];\n} {\n if (typeof config === 'string') {\n return { patterns: [config], conditions: [] };\n }\n if (Array.isArray(config)) {\n return { patterns: config, conditions: [] };\n }\n const files = typeof config.files === 'string' ? [config.files] : config.files;\n return { patterns: files, conditions: config.conditions ?? [] };\n}\n\n/**\n * Derive eval name from file path relative to cwd.\n *\n * Examples (cwd = `/project`):\n * - `/project/evals/suggestions.eval.ts` → `\"evals/suggestions\"`\n * - `/project/evals/api/accuracy.eval.ts` → `\"evals/api/accuracy\"`\n */\nfunction deriveEvalName(filePath: string, cwd: string): string {\n const rel = relative(cwd, filePath);\n // Normalize to forward slashes for cross-platform consistency\n const normalized = rel.replace(/\\\\/g, '/');\n // Guard: file outside cwd (symlink, absolute path) — fall back to basename\n if (normalized.startsWith('../')) {\n const base = basename(filePath);\n const stripped = base.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n return stripped !== base ? stripped : base.replace(/\\.[mc]?[jt]sx?$/, '') || base;\n }\n // Strip .eval.ts, .eval.mjs, .eval.js, etc.\n const withoutEval = normalized.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n if (withoutEval !== normalized) return withoutEval;\n // Fallback: strip extension\n const withoutExt = normalized.replace(/\\.[mc]?[jt]sx?$/, '');\n return withoutExt || normalized;\n}\n\n/**\n * Resolve patterns to absolute file paths.\n *\n * Supports:\n * - Explicit file paths (no wildcards)\n * - Single-directory globs: `dir/*.eval.ts`\n * - Recursive globs: `dir/**\\/*.eval.ts` or `**\\/*.eval.ts`\n *\n * Multi-segment `**` (e.g., `a/**\\/b/**\\/*.ts`) is not supported.\n */\nfunction resolvePatterns(patterns: string[], cwd: string): string[] {\n const files: string[] = [];\n const seen = new Set<string>();\n for (const pattern of patterns) {\n const resolved = pattern.includes('*') ? expandGlob(pattern, cwd) : [resolve(cwd, pattern)];\n for (const file of resolved) {\n if (!seen.has(file)) {\n seen.add(file);\n files.push(file);\n }\n }\n }\n return files;\n}\n\n// `expandGlob` and `registerConditions` are imported from @axlsdk/axl above.\n// The studio-specific glob helpers and conditions registration that used to\n// live here are now shared with @axlsdk/eval to prevent drift.\n"],"mappings":"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","names":["import_node_path","import_node_fs","import_node_url","import_hono","import_axl","byWorkflow","app","import_hono","import_axl","app","import_hono","import_hono","app","import_hono","import_axl","app","import_hono","import_axl","app","import_hono","app","import_hono","app","import_hono","app","import_hono","app","result","import_hono","app","import_hono","app","import_hono","app","import_hono","app","app","import_node_path","import_axl","import_meta","app"]}
|