@tangle-network/agent-eval 0.178.0 → 0.180.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +13 -0
- package/dist/adapters/http.d.ts +2 -2
- package/dist/{agent-profile-_xPxqVJt.d.ts → agent-profile-B7yErX0q.d.ts} +3 -3
- package/dist/{agent-profile-_xPxqVJt.d.ts.map → agent-profile-B7yErX0q.d.ts.map} +1 -1
- package/dist/analyst/index.d.ts +10 -10
- package/dist/analyst/index.js +5 -5
- package/dist/{benchmark-command-DIxGSUP3.js → benchmark-command-D4vpnAdO.js} +6 -6
- package/dist/{benchmark-command-DIxGSUP3.js.map → benchmark-command-D4vpnAdO.js.map} +1 -1
- package/dist/benchmarks/index.d.ts +3 -3
- package/dist/campaign/index.d.ts +5 -5
- package/dist/cli.js +2 -2
- package/dist/{client-vyYQg3bm.d.ts → client-CuQgX33c.d.ts} +2 -2
- package/dist/{client-vyYQg3bm.d.ts.map → client-CuQgX33c.d.ts.map} +1 -1
- package/dist/contract/index.d.ts +9 -9
- package/dist/contract/index.js +3 -3
- package/dist/{default-registry-FfNzaUHV.d.ts → default-registry-IGDE9XIC.d.ts} +6 -6
- package/dist/{default-registry-FfNzaUHV.d.ts.map → default-registry-IGDE9XIC.d.ts.map} +1 -1
- package/dist/{default-registry-DBqVI4pq.js → default-registry-aL7xUrUz.js} +3 -3
- package/dist/{default-registry-DBqVI4pq.js.map → default-registry-aL7xUrUz.js.map} +1 -1
- package/dist/{define-agent-eval-DMsxDp1u.d.ts → define-agent-eval-Cx4Ls9ta.d.ts} +6 -6
- package/dist/{define-agent-eval-DMsxDp1u.d.ts.map → define-agent-eval-Cx4Ls9ta.d.ts.map} +1 -1
- package/dist/{dspy-rlm-engine-DqjER2sV.js → dspy-rlm-engine-xKiWmj_G.js} +2 -2
- package/dist/{dspy-rlm-engine-DqjER2sV.js.map → dspy-rlm-engine-xKiWmj_G.js.map} +1 -1
- package/dist/{engine-CvW_I72-.d.ts → engine-CX8ReXkn.d.ts} +5 -5
- package/dist/{engine-CvW_I72-.d.ts.map → engine-CX8ReXkn.d.ts.map} +1 -1
- package/dist/{exact-types-BKOEILRP.d.ts → exact-types-B7LC1EyX.d.ts} +2 -2
- package/dist/{exact-types-BKOEILRP.d.ts.map → exact-types-B7LC1EyX.d.ts.map} +1 -1
- package/dist/experiment/index.d.ts +2 -2
- package/dist/{experiment-tracker-CNwqCZFD.d.ts → experiment-tracker-B3TiF5-u.d.ts} +2 -2
- package/dist/{experiment-tracker-CNwqCZFD.d.ts.map → experiment-tracker-B3TiF5-u.d.ts.map} +1 -1
- package/dist/{feedback-trajectory-CMnv_uYs.d.ts → feedback-trajectory-eHWNv5Aj.d.ts} +3 -3
- package/dist/{feedback-trajectory-CMnv_uYs.d.ts.map → feedback-trajectory-eHWNv5Aj.d.ts.map} +1 -1
- package/dist/hosted/index.d.ts +1 -1
- package/dist/{index-CZ2tAJW2.d.ts → index-BxWvILU8.d.ts} +6 -6
- package/dist/{index-CZ2tAJW2.d.ts.map → index-BxWvILU8.d.ts.map} +1 -1
- package/dist/{index-BAAiSF3_.d.ts → index-CiUjjEIa.d.ts} +7 -7
- package/dist/{index-BAAiSF3_.d.ts.map → index-CiUjjEIa.d.ts.map} +1 -1
- package/dist/{index-nrWQbUgi.d.ts → index-DxNYmx4a.d.ts} +9 -9
- package/dist/{index-nrWQbUgi.d.ts.map → index-DxNYmx4a.d.ts.map} +1 -1
- package/dist/index.d.ts +15 -15
- package/dist/index.js +6 -6
- package/dist/{integrity-DsHWCebQ.js → integrity-DH5ng72x.js} +2 -2
- package/dist/{integrity-DsHWCebQ.js.map → integrity-DH5ng72x.js.map} +1 -1
- package/dist/{kind-factory-BLvL-E44.js → kind-factory-D5HOW3R0.js} +119 -15
- package/dist/kind-factory-D5HOW3R0.js.map +1 -0
- package/dist/{matrix-CJtXz1ky.d.ts → matrix-DeMmnWrP.d.ts} +2 -2
- package/dist/{matrix-CJtXz1ky.d.ts.map → matrix-DeMmnWrP.d.ts.map} +1 -1
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/openapi.json +1 -1
- package/dist/{registry-7pOUBrtX.d.ts → registry-ByVld1-5.d.ts} +3 -3
- package/dist/{registry-7pOUBrtX.d.ts.map → registry-ByVld1-5.d.ts.map} +1 -1
- package/dist/{report-command-DKlXfU5r.js → report-command-V1ecVgAv.js} +27 -3
- package/dist/report-command-V1ecVgAv.js.map +1 -0
- package/dist/rl.d.ts +1 -1
- package/dist/{semantic-concept-judge-Dw-f7TEs.js → semantic-concept-judge-Bi6_iGqg.js} +3 -3
- package/dist/{semantic-concept-judge-Dw-f7TEs.js.map → semantic-concept-judge-Bi6_iGqg.js.map} +1 -1
- package/dist/{statistical-heldout-Z9NROFFS.d.ts → statistical-heldout-0La5ZTlv.d.ts} +2 -2
- package/dist/{statistical-heldout-Z9NROFFS.d.ts.map → statistical-heldout-0La5ZTlv.d.ts.map} +1 -1
- package/dist/{store-otlp-DV_H2HDu.js → store-otlp-DWGUwlyj.js} +7 -2
- package/dist/store-otlp-DWGUwlyj.js.map +1 -0
- package/dist/{store-tool-spans-4o55ABER.d.ts → store-tool-spans-4J1EDElP.d.ts} +7 -4
- package/dist/{store-tool-spans-4o55ABER.d.ts.map → store-tool-spans-4J1EDElP.d.ts.map} +1 -1
- package/dist/{store-tool-spans-B9tjys_h.js → store-tool-spans-ceJoiUgS.js} +3 -3
- package/dist/{store-tool-spans-B9tjys_h.js.map → store-tool-spans-ceJoiUgS.js.map} +1 -1
- package/dist/supervisor-run/index.d.ts +4 -2
- package/dist/supervisor-run/index.d.ts.map +1 -1
- package/dist/supervisor-run/index.js +3 -3
- package/dist/{task-failure-attributes-CUy9mkIY.js → task-failure-attributes-B072KO_n.js} +2 -2
- package/dist/{task-failure-attributes-CUy9mkIY.js.map → task-failure-attributes-B072KO_n.js.map} +1 -1
- package/dist/{terminal-record-Ce9_UjRz.js → terminal-record-BtPwKTSr.js} +58 -26
- package/dist/terminal-record-BtPwKTSr.js.map +1 -0
- package/dist/{tool-groups-DAe1t6zb.d.ts → tool-groups-2QA0S7dK.d.ts} +4 -4
- package/dist/tool-groups-2QA0S7dK.d.ts.map +1 -0
- package/dist/trace-repair/index.d.ts +1 -1
- package/dist/traces.d.ts +4 -4
- package/dist/traces.js +4 -4
- package/dist/{types-Dd1ejaeI.d.ts → types-BmlkCrg0.d.ts} +2 -2
- package/dist/{types-Dd1ejaeI.d.ts.map → types-BmlkCrg0.d.ts.map} +1 -1
- package/dist/{types-BJz2CPTM.d.ts → types-C34V4Vto.d.ts} +2 -2
- package/dist/{types-BJz2CPTM.d.ts.map → types-C34V4Vto.d.ts.map} +1 -1
- package/dist/{types-DN2WdT5S.d.ts → types-DzuaM493.d.ts} +40 -2
- package/dist/types-DzuaM493.d.ts.map +1 -0
- package/dist/{types-vUdAx2Cj.d.ts → types-lPkDQNqJ.d.ts} +20 -2
- package/dist/{types-vUdAx2Cj.d.ts.map → types-lPkDQNqJ.d.ts.map} +1 -1
- package/dist/wire/index.d.ts +1 -1
- package/docs/trace-analysis.md +45 -0
- package/package.json +1 -1
- package/dist/kind-factory-BLvL-E44.js.map +0 -1
- package/dist/report-command-DKlXfU5r.js.map +0 -1
- package/dist/store-otlp-DV_H2HDu.js.map +0 -1
- package/dist/terminal-record-Ce9_UjRz.js.map +0 -1
- package/dist/tool-groups-DAe1t6zb.d.ts.map +0 -1
- package/dist/types-DN2WdT5S.d.ts.map +0 -1
package/dist/{semantic-concept-judge-Dw-f7TEs.js.map → semantic-concept-judge-Bi6_iGqg.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic-concept-judge-Dw-f7TEs.js","names":[],"sources":["../src/analyst/chat-trace-engine.ts","../src/locked-jsonl-appender.ts","../src/analyst/findings-store.ts","../src/semantic-concept-judge.ts"],"sourcesContent":["/**\n * A `TraceAnalysisEngine` that runs entirely inside Node against a\n * caller-owned `ChatClient`.\n *\n * The other engine in this package, `createDspyRlmTraceEngine`, reaches the\n * DSPy RLM through a Python subprocess. That made every model-backed analyst\n * unreachable for a consumer that already owns a model seam and no Python:\n * `createTraceAnalyst` requires an engine, the only exported constructor\n * required a Python runner, so `buildDefaultAnalystRegistry()` registered the\n * deterministic analyst alone and `analystsFromRegistry` refused the result.\n *\n * This engine closes that path. It drives the same investigation contract —\n * bounded trace tools, a prose answer, a strict findings array — with native\n * function calls over the transport the caller already bound with\n * `createChatClient`. A caller holding a bare\n * `(request: LlmCallRequest) => Promise<LlmCallResult>` adapts it in one line:\n *\n * createChatClient({ transport: 'custom', chat: call, defaultModel, maximumAttempts })\n *\n * agent-eval still executes no paid model and holds no provider credential.\n * Every call goes through `paidChat`, so the shared cost ledger reserves the\n * priced maximum before the call and settles the receipt after it.\n *\n * Shape of one investigation:\n * 1. Investigation turns. The model reads the trace store through the tools\n * its analyst kind was given. A turn that requests no tool ends the\n * phase; an exhausted iteration or tool budget also ends it.\n * 2. One report turn. The model returns `{ answer, findings }` as JSON,\n * decoded by the same `decodeRawFindingArray` the Python bridge uses, so\n * a row this engine accepts is a row that engine could report.\n */\n\nimport { z } from 'zod'\nimport { paidChat } from '../chat-json-call'\nimport type { CustomTokenPricing } from '../cost-ledger'\nimport {\n extractJsonPayload,\n type LlmCallRequest,\n type LlmMessage,\n type LlmThinkingMode,\n type LlmToolCall,\n type LlmToolDefinition,\n} from '../llm-client'\nimport type { TraceAnalysisToolDescriptor } from '../trace-analyst/tools'\nimport type { ChatClient } from './chat-client'\nimport {\n DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS,\n type TraceAnalysisEngine,\n type TraceAnalysisEngineRequest,\n type TraceAnalysisEngineResult,\n} from './engine'\nimport { decodeRawFindingArray } from './finding-codec'\nimport { RawAnalystFindingSchema } from './finding-signature'\n\n/** Bumped whenever this engine's execution behavior changes. */\nconst CHAT_TRACE_ENGINE_VERSION = '1.0.0'\nconst ENGINE_ID = 'chat-trace'\n\n/** Marker appended to a tool result cut down to the retained-output budget. */\nconst TRUNCATION_MARKER = '\\n…[truncated to the analyst maxOutputChars budget]'\n\nexport interface ChatTraceEngineOptions {\n /**\n * Caller-owned transport. Build it with `createChatClient`; agent-eval never\n * receives the provider credential.\n */\n chat: ChatClient\n /** Model for every call. Defaults to the client's `defaultModel`. */\n model?: string\n /** Endpoint rates used when the transport reports no billed amount. */\n pricing?: CustomTokenPricing\n /** Completion cap per turn. Default: {@link DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS}. */\n maxOutputTokens?: number\n /** Sampling temperature. Omitted from the request when absent. */\n temperature?: number\n /** Provider reasoning mode. Omitted when the provider default should apply. */\n thinking?: LlmThinkingMode\n /** Per-call deadline handed to the transport. */\n requestTimeoutMs?: number\n /**\n * How the report turn asks for structured output.\n *\n * `json-object` sends JSON mode, which every OpenAI-compatible endpoint\n * accepts, and relies on the finding grammar the analyst kind already puts\n * in its instructions. `json-schema` sends the generated response schema as\n * well, which stricter endpoints honour and older ones reject. Default:\n * `json-object`.\n */\n reportFormat?: 'json-object' | 'json-schema'\n}\n\n/**\n * The report envelope. Its `findings` rows are generated from\n * `RawAnalystFindingSchema`, so the schema offered to a provider and the\n * decoder that accepts the answer cannot drift apart.\n */\nfunction buildReportJsonSchema(): { name: string; schema: Record<string, unknown> } {\n const row = z.toJSONSchema(RawAnalystFindingSchema, { target: 'draft-7' }) as Record<\n string,\n unknown\n >\n delete row.$schema\n return {\n name: 'trace_analysis_report',\n schema: {\n type: 'object',\n additionalProperties: false,\n required: ['answer', 'findings'],\n properties: {\n answer: { type: 'string', description: 'Direct prose answer to the question.' },\n findings: { type: 'array', items: row },\n },\n },\n }\n}\n\nconst REPORT_JSON_SCHEMA = buildReportJsonSchema()\n\n/**\n * Run bounded recursive trace analysis in-process over a caller-owned chat\n * transport. No Python, no subprocess, no loopback proxy.\n */\nexport function createChatTraceEngine(options: ChatTraceEngineOptions): TraceAnalysisEngine {\n const model = resolveModel(options)\n const maxOutputTokens = options.maxOutputTokens ?? DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS\n if (!Number.isSafeInteger(maxOutputTokens) || maxOutputTokens <= 0) {\n throw new TypeError('chat trace engine maxOutputTokens must be a positive safe integer')\n }\n if (\n options.temperature !== undefined &&\n (!Number.isFinite(options.temperature) || options.temperature < 0)\n ) {\n throw new TypeError('chat trace engine temperature must be a non-negative finite number')\n }\n if (\n options.requestTimeoutMs !== undefined &&\n (!Number.isSafeInteger(options.requestTimeoutMs) || options.requestTimeoutMs <= 0)\n ) {\n throw new TypeError('chat trace engine requestTimeoutMs must be a positive safe integer')\n }\n const reportFormat = options.reportFormat ?? 'json-object'\n if (reportFormat !== 'json-object' && reportFormat !== 'json-schema') {\n throw new TypeError(`chat trace engine reportFormat must be json-object or json-schema`)\n }\n\n return {\n id: ENGINE_ID,\n description:\n 'In-process recursive trace analysis over a caller-owned ChatClient with native tool calls.',\n model,\n version: CHAT_TRACE_ENGINE_VERSION,\n executionConfig: {\n kind: ENGINE_ID,\n model,\n transport: options.chat.transport,\n maximum_attempts: options.chat.maximumAttempts ?? null,\n pricing: options.pricing ? { ...options.pricing } : null,\n max_output_tokens: maxOutputTokens,\n temperature: options.temperature ?? null,\n thinking: options.thinking ?? null,\n request_timeout_ms: options.requestTimeoutMs ?? null,\n report_format: reportFormat,\n report_schema_name: REPORT_JSON_SCHEMA.name,\n },\n analyze: (request) => analyze(request, { ...options, model, maxOutputTokens, reportFormat }),\n }\n}\n\ninterface ResolvedOptions extends ChatTraceEngineOptions {\n model: string\n maxOutputTokens: number\n reportFormat: 'json-object' | 'json-schema'\n}\n\nasync function analyze(\n request: TraceAnalysisEngineRequest,\n options: ResolvedOptions,\n): Promise<TraceAnalysisEngineResult> {\n // One model call is spent on the report, so a budget of one call would buy\n // an answer with no investigation behind it. Refuse instead of pretending.\n if (request.limits.maxLlmCalls < 2) {\n throw new Error(\n `chat trace engine reserves one model call for the report, so maxLlmCalls must be at least 2 (analyst '${request.analystId}' declared ${request.limits.maxLlmCalls})`,\n )\n }\n const toolsByName = new Map(request.tools.map((tool) => [tool.name, tool]))\n if (toolsByName.size !== request.tools.length) {\n throw new Error(`chat trace engine received duplicate tool names for '${request.analystId}'`)\n }\n const toolDefinitions: LlmToolDefinition[] = request.tools.map((tool) => ({\n type: 'function',\n function: { name: tool.name, description: tool.description, parameters: tool.parameters },\n }))\n const investigationTurns = Math.max(\n 1,\n Math.min(request.limits.maxIterations, request.limits.maxLlmCalls - 1),\n )\n\n const messages: LlmMessage[] = [\n { role: 'system', content: systemPrompt(request, investigationTurns) },\n ]\n if (request.taskInputs) {\n messages.push({ role: 'user', content: renderTaskInputs(request.taskInputs) })\n }\n messages.push({ role: 'user', content: request.question })\n\n request.log?.('trace analyst engine started', {\n engine: ENGINE_ID,\n model: options.model,\n transport: options.chat.transport,\n tools: request.tools.map((tool) => tool.name),\n limits: request.limits,\n })\n\n const trajectory: unknown[] = []\n const servedModels = new Set<string>()\n let modelCalls = 0\n let toolCalls = 0\n let truncatedToolResults = 0\n let toolBudgetExhausted = false\n let turnsUsed = 0\n let stoppedOnAnswer = false\n\n for (let turn = 0; turn < investigationTurns; turn++) {\n turnsUsed = turn + 1\n const response = await callModel(request, options, {\n messages,\n tools: toolDefinitions,\n toolChoice: 'auto',\n purpose: 'investigation',\n })\n modelCalls += 1\n servedModels.add(response.servedModel ?? 'unreported')\n const requested = response.toolCalls ?? []\n messages.push({\n role: 'assistant',\n content: response.content,\n ...(requested.length > 0 ? { toolCalls: requested } : {}),\n })\n trajectory.push({\n turn: turnsUsed,\n phase: 'investigation',\n content: response.content,\n tool_calls: requested.map((call) => ({ id: call.id, name: call.name })),\n finish_reason: response.finishReason ?? null,\n })\n if (requested.length === 0) {\n stoppedOnAnswer = true\n break\n }\n for (const call of requested) {\n if (toolCalls >= request.limits.maxToolCalls) {\n toolBudgetExhausted = true\n // Every requested id still needs an answer: a provider rejects the\n // next turn when one tool call is left unanswered.\n messages.push(toolMessage(call, exhaustedToolBudget(request.limits.maxToolCalls)))\n continue\n }\n toolCalls += 1\n const executed = await executeTool(call, toolsByName, request)\n if (executed.truncated) truncatedToolResults += 1\n messages.push(toolMessage(call, executed.payload))\n trajectory.push({\n turn: turnsUsed,\n phase: 'tool',\n name: call.name,\n ok: executed.ok,\n truncated: executed.truncated,\n result_chars: executed.payload.length,\n })\n }\n if (toolBudgetExhausted) break\n }\n\n messages.push({ role: 'user', content: reportPrompt(options.reportFormat) })\n const report = await callModel(request, options, {\n messages,\n purpose: 'report',\n json: options.reportFormat,\n })\n modelCalls += 1\n servedModels.add(report.servedModel ?? 'unreported')\n trajectory.push({\n turn: turnsUsed + 1,\n phase: 'report',\n content: report.content,\n finish_reason: report.finishReason ?? null,\n })\n\n const parsed = parseReport(report.content, request.analystId, (index, reason) => {\n request.log?.('finding rejected: report row failed schema validation', {\n engine: ENGINE_ID,\n index,\n reason,\n })\n })\n\n const result: TraceAnalysisEngineResult = {\n answer: parsed.answer,\n findings: parsed.findings,\n trajectory,\n modelCalls,\n toolCalls,\n runtime: {\n engine: ENGINE_ID,\n model: options.model,\n transport: options.chat.transport,\n report_format: options.reportFormat,\n investigation_turns: turnsUsed,\n investigation_stopped_on_answer: stoppedOnAnswer,\n tool_budget_exhausted: toolBudgetExhausted,\n truncated_tool_results: truncatedToolResults,\n rejected_findings: parsed.rejectedFindings,\n // A gateway can answer `model: X` from another model on HTTP 200, so the\n // ids the provider echoed travel with the result as evidence.\n served_models: [...servedModels].sort(),\n task_inputs: request.taskInputs ? 'prompt-delivered' : 'none',\n },\n }\n request.log?.('trace analyst engine completed', {\n engine: ENGINE_ID,\n model_calls: result.modelCalls,\n tool_calls: result.toolCalls,\n findings: result.findings.length,\n })\n return result\n}\n\ninterface ModelTurn {\n content: string\n toolCalls?: LlmToolCall[]\n servedModel?: string | null\n finishReason?: string | null\n}\n\nasync function callModel(\n request: TraceAnalysisEngineRequest,\n options: ResolvedOptions,\n turn: {\n messages: LlmMessage[]\n tools?: LlmToolDefinition[]\n toolChoice?: LlmCallRequest['toolChoice']\n purpose: 'investigation' | 'report'\n json?: 'json-object' | 'json-schema'\n },\n): Promise<ModelTurn> {\n const chatRequest: LlmCallRequest = {\n model: options.model,\n // The transport may mutate what it is handed; the conversation is ours.\n messages: turn.messages.map((message) => ({ ...message })),\n maxTokens: options.maxOutputTokens,\n ...(turn.tools && turn.tools.length > 0\n ? { tools: turn.tools, ...(turn.toolChoice ? { toolChoice: turn.toolChoice } : {}) }\n : {}),\n ...(turn.json ? { jsonMode: true } : {}),\n ...(turn.json === 'json-schema' ? { jsonSchema: REPORT_JSON_SCHEMA } : {}),\n ...(options.temperature === undefined ? {} : { temperature: options.temperature }),\n ...(options.thinking === undefined ? {} : { thinking: options.thinking }),\n ...(options.requestTimeoutMs === undefined ? {} : { timeoutMs: options.requestTimeoutMs }),\n }\n const paid = await paidChat({\n chat: options.chat,\n request: chatRequest,\n ledger: request.costLedger,\n channel: 'analyst',\n phase: request.costPhase,\n actor: request.analystId,\n ...(request.costTags ? { tags: request.costTags } : {}),\n ...(options.pricing ? { pricing: options.pricing } : {}),\n ...(request.signal ? { signal: request.signal } : {}),\n })\n if (!paid.succeeded) {\n // The transport already spent its own attempts. A failure here ends the\n // investigation: continuing would report an answer the model never gave.\n throw new Error(\n `chat trace engine ${turn.purpose} call failed for '${request.analystId}': ${paid.error.message}`,\n { cause: paid.error },\n )\n }\n return {\n content: paid.response.content,\n ...(paid.response.toolCalls ? { toolCalls: paid.response.toolCalls } : {}),\n ...(paid.response.servedModel === undefined ? {} : { servedModel: paid.response.servedModel }),\n ...(paid.response.finishReason === undefined\n ? {}\n : { finishReason: paid.response.finishReason }),\n }\n}\n\ninterface ExecutedTool {\n ok: boolean\n truncated: boolean\n payload: string\n}\n\nasync function executeTool(\n call: LlmToolCall,\n toolsByName: ReadonlyMap<string, TraceAnalysisToolDescriptor>,\n request: TraceAnalysisEngineRequest,\n): Promise<ExecutedTool> {\n const descriptor = toolsByName.get(call.name)\n if (!descriptor) {\n return {\n ok: false,\n truncated: false,\n payload: toolError(\n `unknown tool '${call.name}'; available tools are ${[...toolsByName.keys()].sort().join(', ')}`,\n ),\n }\n }\n let args: unknown\n try {\n args = call.argumentsJson.trim() === '' ? {} : JSON.parse(call.argumentsJson)\n } catch (error) {\n return {\n ok: false,\n truncated: false,\n payload: toolError(\n `arguments for '${call.name}' were not JSON: ${messageOf(error)}. Send valid JSON arguments.`,\n ),\n }\n }\n try {\n const value = await descriptor.handler(\n args,\n request.signal ? { signal: request.signal } : undefined,\n )\n return truncateToolPayload(JSON.stringify(value ?? null), request.limits.maxOutputChars)\n } catch (error) {\n // A bounded store refuses an oversized or malformed read by design. That\n // refusal is the model's next instruction, not the run's failure.\n if (request.signal?.aborted) throw error\n request.log?.('trace tool failed', {\n engine: ENGINE_ID,\n analyst_id: request.analystId,\n tool: call.name,\n reason: messageOf(error),\n })\n return { ok: false, truncated: false, payload: toolError(messageOf(error)) }\n }\n}\n\nfunction truncateToolPayload(payload: string, maxOutputChars: number): ExecutedTool {\n if (payload.length <= maxOutputChars) return { ok: true, truncated: false, payload }\n const keep = Math.max(0, maxOutputChars - TRUNCATION_MARKER.length)\n return { ok: true, truncated: true, payload: `${payload.slice(0, keep)}${TRUNCATION_MARKER}` }\n}\n\nfunction toolMessage(call: LlmToolCall, content: string): LlmMessage {\n return { role: 'tool', toolCallId: call.id, content }\n}\n\nfunction toolError(reason: string): string {\n return JSON.stringify({ error: reason })\n}\n\nfunction exhaustedToolBudget(maxToolCalls: number): string {\n return toolError(\n `the trace-tool budget of ${maxToolCalls} calls is spent; answer from the evidence already read`,\n )\n}\n\nfunction systemPrompt(request: TraceAnalysisEngineRequest, investigationTurns: number): string {\n return [\n request.instructions.trim(),\n [\n 'HOW THIS INVESTIGATION RUNS:',\n `- You have ${investigationTurns} investigation turns and at most ${request.limits.maxToolCalls} trace-tool calls.`,\n '- Call the trace tools to read the store. Never state a trace fact you did not read.',\n `- A tool result longer than ${request.limits.maxOutputChars} characters is truncated; narrow the query instead of asking again.`,\n '- A tool result carrying an \"error\" field is feedback: fix the call or take another route.',\n '- Answer with no tool call once you have the evidence. You are then asked for the final report.',\n ].join('\\n'),\n ].join('\\n\\n')\n}\n\nfunction reportPrompt(reportFormat: 'json-object' | 'json-schema'): string {\n return [\n 'Report now. Do not call any more tools.',\n 'Return one JSON object with exactly two fields:',\n ' \"answer\": a direct prose answer to the question.',\n ' \"findings\": an array of findings in the schema above. Emit [] when there is nothing to report.',\n reportFormat === 'json-object'\n ? 'Return the object alone, with no surrounding prose and no code fence.'\n : 'Return the object in the response schema you were given.',\n ].join('\\n')\n}\n\nfunction renderTaskInputs(taskInputs: Readonly<Record<string, unknown>>): string {\n // The engine contract forbids dropping structured inputs. This engine has no\n // code environment to bind them as variables, so they are delivered whole as\n // conversation material and the runtime record says which way they arrived.\n return [\n 'TASK INPUTS — structured material delivered with the question, not fetched through tools:',\n JSON.stringify(taskInputs, null, 2),\n ].join('\\n')\n}\n\ninterface ParsedReport {\n answer: string\n findings: TraceAnalysisEngineResult['findings']\n rejectedFindings: number\n}\n\nfunction parseReport(\n content: string,\n analystId: string,\n onRejectedFinding: (index: number, reason: string) => void,\n): ParsedReport {\n const envelope = coerceReportEnvelope(content, analystId)\n if (typeof envelope.answer !== 'string' || !envelope.answer.trim()) {\n throw new Error(`chat trace engine report for '${analystId}' carried no answer`)\n }\n // Findings are model output: one malformed row is model noise, not an engine\n // fault, and the rest of the paid investigation must survive it.\n const decoded = decodeRawFindingArray(envelope.findings)\n if (decoded.topLevelError !== undefined) {\n throw new Error(\n `chat trace engine report for '${analystId}' had a malformed findings array: ${decoded.topLevelError}`,\n )\n }\n for (const rejection of decoded.rejected) {\n onRejectedFinding(\n rejection.index,\n `${rejection.code}${rejection.path ? ` at ${rejection.path}` : ''}: ${rejection.message}`,\n )\n }\n return {\n answer: envelope.answer,\n findings: decoded.accepted,\n rejectedFindings: decoded.rejected.length,\n }\n}\n\nfunction coerceReportEnvelope(content: string, analystId: string): Record<string, unknown> {\n let value: unknown\n try {\n value = JSON.parse(extractJsonPayload(content))\n } catch (error) {\n throw new Error(`chat trace engine report for '${analystId}' was not JSON: ${messageOf(error)}`)\n }\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new Error(`chat trace engine report for '${analystId}' was not a JSON object`)\n }\n return value as Record<string, unknown>\n}\n\nfunction resolveModel(options: ChatTraceEngineOptions): string {\n const model = options.model ?? options.chat.defaultModel\n if (typeof model !== 'string' || !model.trim() || model !== model.trim()) {\n throw new TypeError(\n 'chat trace engine needs a model: pass ChatTraceEngineOptions.model or bind defaultModel on the ChatClient',\n )\n }\n return model\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","/**\n * LockedJsonlAppender — mutex-serialized JSONL append helper for arbitrary\n * payloads. The reference-replay store does the same thing for typed\n * `ReferenceReplayRun` rows; this is the generic version used by\n * `MutationTelemetry`, `TrialTelemetry`, and any other consumer that wants\n * append-only durable telemetry without rolling its own lock.\n *\n * Locks are per absolute file path (process-local). Cross-process\n * concurrency is NOT addressed — that's an fcntl/flock problem.\n */\n\nimport { appendFileSync, existsSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { Mutex } from './concurrency'\n\nconst mutexes = new Map<string, Mutex>()\n\nfunction getMutex(path: string): Mutex {\n let m = mutexes.get(path)\n if (!m) {\n m = new Mutex()\n mutexes.set(path, m)\n }\n return m\n}\n\nexport class LockedJsonlAppender {\n private readonly mutex: Mutex\n constructor(public readonly path: string) {\n this.mutex = getMutex(path)\n if (!existsSync(dirname(path))) {\n mkdirSync(dirname(path), { recursive: true })\n }\n }\n\n async append(entry: unknown): Promise<void> {\n const line = `${JSON.stringify(entry)}\\n`\n await this.mutex.runExclusive(() => {\n appendFileSync(this.path, line)\n })\n }\n}\n\n/** Reset all internal mutex state — tests only. */\nexport function resetLockedAppendersForTesting(): void {\n mutexes.clear()\n}\n","/**\n * FindingsStore — durable persistence for AnalystFinding rows + a diff\n * helper so we can answer \"what changed since the last run?\" without\n * recomputing analysts.\n *\n * On-disk shape is JSONL: one finding per line, append-only, locked via\n * LockedJsonlAppender. Operators get crash-safety (no partial JSON),\n * cheap reads (sequential parse), and trivial backup (rsync the file).\n *\n * Reads are non-locking: a reader sees a consistent snapshot of all\n * fully-written lines and skips an incomplete trailing line if the\n * writer is mid-append. Cross-process locking is intentionally out of\n * scope (see locked-jsonl-appender.ts).\n *\n * The store is run-scoped: callers pass `runId` on append and on load,\n * which keeps multi-run files cleanly partitioned. The `diffFindings`\n * helper compares two run-id sets using stable `finding_id` semantics —\n * the diff is the cross-run signal the regression dashboard renders.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\n\nimport { LockedJsonlAppender } from '../locked-jsonl-appender'\nimport type { AnalystFinding } from './types'\n\n/**\n * One persisted row. We attach `run_id` on disk so a single file can\n * hold multiple runs and the diff helper can query without re-walking\n * separate files.\n */\nexport interface PersistedFinding extends AnalystFinding {\n run_id: string\n}\n\nexport class FindingsStore {\n private readonly appender: LockedJsonlAppender\n\n constructor(public readonly path: string) {\n this.appender = new LockedJsonlAppender(path)\n }\n\n async append(runId: string, findings: AnalystFinding[]): Promise<void> {\n for (const f of findings) {\n const row: PersistedFinding = { ...f, run_id: runId }\n await this.appender.append(row)\n }\n }\n\n /** Load every persisted finding. Discards malformed trailing lines silently. */\n loadAll(): PersistedFinding[] {\n if (!existsSync(this.path)) return []\n const raw = readFileSync(this.path, 'utf8')\n if (!raw) return []\n const out: PersistedFinding[] = []\n for (const line of raw.split('\\n')) {\n if (!line) continue\n try {\n out.push(JSON.parse(line) as PersistedFinding)\n } catch {\n // Skip torn trailing line — the lock guarantees no torn lines\n // mid-file, only at EOF when a writer is in-flight.\n }\n }\n return out\n }\n\n /** Filter to a single run. */\n loadRun(runId: string): PersistedFinding[] {\n return this.loadAll().filter((r) => r.run_id === runId)\n }\n}\n\n// ── Cross-run diff ──────────────────────────────────────────────────\n\nexport interface FindingsDiff {\n /** New finding ids in `current` that weren't in `previous`. */\n appeared: PersistedFinding[]\n /** Finding ids in `previous` that aren't in `current`. */\n disappeared: PersistedFinding[]\n /** Same finding id present in both runs and unchanged per the materiality test. */\n persisted: PersistedFinding[]\n /**\n * Same finding id in both runs but at least one non-identity field\n * shifted per `DiffPolicy.isMaterial`. Reported as [previous, current].\n */\n changed: Array<{ previous: PersistedFinding; current: PersistedFinding }>\n}\n\nexport interface DiffPolicy {\n /**\n * Predicate that decides whether two findings (same finding_id) count\n * as a material change. Defaults to {@link defaultIsMaterial}: severity\n * shift, confidence Δ > 0.05, or evidence count change. Compliance /\n * perf consumers MAY supply a stricter predicate (e.g. rationale text\n * diff, metric Δ thresholds).\n */\n isMaterial?: (previous: AnalystFinding, current: AnalystFinding) => boolean\n}\n\n/**\n * Default materiality test. Deliberately narrow so LLM-reword churn\n * doesn't flood the diff. Stricter tests are opt-in via DiffPolicy.\n */\nexport function defaultIsMaterial(a: AnalystFinding, b: AnalystFinding): boolean {\n if (a.severity !== b.severity) return true\n if (Math.abs((a.confidence ?? 0) - (b.confidence ?? 0)) > 0.05) return true\n if (a.evidence_refs.length !== b.evidence_refs.length) return true\n return false\n}\n\n/**\n * Diff two findings sets by stable finding_id. Callers typically load\n * the two run-id slices from the same store and pass them in.\n */\nexport function diffFindings(\n previous: PersistedFinding[],\n current: PersistedFinding[],\n policy: DiffPolicy = {},\n): FindingsDiff {\n const isMaterial = policy.isMaterial ?? defaultIsMaterial\n const prevById = new Map(previous.map((f) => [f.finding_id, f]))\n const curById = new Map(current.map((f) => [f.finding_id, f]))\n\n const appeared: PersistedFinding[] = []\n const disappeared: PersistedFinding[] = []\n const persisted: PersistedFinding[] = []\n const changed: FindingsDiff['changed'] = []\n\n for (const [id, cur] of curById) {\n const prev = prevById.get(id)\n if (!prev) {\n appeared.push(cur)\n continue\n }\n if (isMaterial(prev, cur)) {\n changed.push({ previous: prev, current: cur })\n } else {\n persisted.push(cur)\n }\n }\n for (const [id, prev] of prevById) {\n if (!curById.has(id)) disappeared.push(prev)\n }\n return { appeared, disappeared, persisted, changed }\n}\n","/**\n * Semantic concept judge — \"does the built artifact actually implement\n * the features the user asked for?\"\n *\n * Distinct from the domain/code/coherence judges in `judges.ts`:\n * - those judges score free-form conversational agent outputs along\n * quality dimensions (accuracy, depth, etc.)\n * - this judge scores a *built artifact* (served HTML + source files)\n * against an explicit list of expected concepts, returning per-concept\n * {present, score 0-10, evidence, severity}.\n *\n * The judge is strict about distinguishing (a) a working implementation\n * from (b) a keyword-present stub. \"// TODO: mint button\" is NOT present.\n * Only real, functional, wired-up code counts.\n *\n * Use via {@link createSemanticConceptJudge} or directly via\n * {@link runSemanticConceptJudge}. Soft-fails (available=false) on LLM\n * or JSON-parse errors so the caller can treat that as \"layer skipped\"\n * rather than \"layer failed\" in a multi-layer pipeline.\n */\n\nimport type { ChatClient } from './analyst/chat-client'\nimport { paidJsonChat } from './chat-json-call'\nimport {\n CostLedger,\n type CostLedgerHandle,\n type CostReceipt,\n type CustomTokenPricing,\n} from './cost-ledger'\nimport type { LlmCallRequest } from './llm-client'\nimport type { Severity } from './multi-layer-verifier'\n\n// ─── Types ──────────────────────────────────────────────────────────────\n\n/**\n * Implementation complexity class for weighted scoring.\n *\n * - `render` (default): the concept is a UI surface that displays static\n * data — render a list, show a counter, lay out a button. Single-file\n * work, no external integration.\n * - `integrate`: the concept requires wiring a real external system —\n * wallet connect (wagmi + RainbowKit + chain config), payment provider\n * (Stripe Elements + intent + webhook), an API client with auth.\n * Multi-file, library-knowledge, runtime correctness matters.\n * - `compute`: the concept requires algorithmic work — solver, simulator,\n * constraint propagation, ML inference. Correctness > UI polish.\n *\n * Default weights (when applied via `weightConcepts: 'complexity'`):\n * render=1.0, integrate=2.0, compute=2.5\n *\n * Cross-vertical scoring without complexity weighting silently inflates\n * the rate of UI-heavy verticals (healthcare, fintech dashboards) vs\n * integration-heavy verticals (DeFi, wallets) — all concepts treated\n * equally even though the agent does 2-3x the work for `integrate`.\n */\nexport type ConceptComplexity = 'render' | 'integrate' | 'compute'\n\nexport interface ConceptSpec {\n name: string\n /** Short hints that help the judge; not used for matching. */\n keywords?: string[]\n /** Optional explicit weight; default 1.0. Overrides complexity-derived weight. */\n weight?: number\n /** Implementation complexity class. Default `render`. */\n complexity?: ConceptComplexity\n}\n\nexport interface ConceptFinding {\n concept: string\n present: boolean\n /** 0..10. 10 = production-ready; 7 = functional thin; 4 = partial; 0 = absent. */\n score: number\n evidence: string\n severity: Severity\n}\n\nexport interface SemanticConceptJudgeInput {\n /** Full natural-language prompt the agent was handed. */\n userRequest: string\n /** Rendered HTML the preview returns (UI artifacts). Optional. */\n servedHtml?: string\n /** Top-level source files from the agent's workdir. */\n sourceFiles: Array<{ path: string; content: string }>\n /** The expected concept list. */\n expectedConcepts: ConceptSpec[]\n /** Free-form metadata (id, difficulty) to inject into the prompt. */\n artifactLabel?: string\n artifactDescription?: string\n}\n\nexport interface SemanticConceptJudgeResult {\n kind: 'semantic-concept'\n version: string\n /** Normalized 0..1 score — mean of per-concept scores / 10. */\n score: number\n presentCount: number\n totalCount: number\n findings: ConceptFinding[]\n summary: string\n durationMs: number\n costUsd: number | null\n /** False on LLM/JSON error — treat as \"skipped / unable to judge\" in pipelines. */\n available: boolean\n error?: string\n}\n\n/**\n * Score-aggregation strategy. `mean` averages 0-10 scores uniformly.\n * `complexity` applies the default weight table (render=1, integrate=2,\n * compute=2.5) unless a concept has an explicit `weight`. `explicit`\n * honors only `weight` (defaulting to 1 for unspecified).\n */\nexport type ConceptWeightStrategy = 'mean' | 'complexity' | 'explicit'\n\nexport const DEFAULT_COMPLEXITY_WEIGHTS: Record<ConceptComplexity, number> = {\n render: 1.0,\n integrate: 2.0,\n compute: 2.5,\n}\n\nexport interface SemanticConceptJudgeOptions {\n /** Model id to call. Default 'claude-sonnet-4-6' via agent-eval defaults. */\n model?: string\n /** Per-call timeout. Default 300s. */\n timeoutMs?: number\n /** Provider-enforced output limit. Default 16000. */\n maxTokens?: number\n /** Pipeline budget for the prompt (source blob truncation). Default 45000. */\n maxSourceChars?: number\n /** Per-file cap before inclusion. Default 20000. */\n maxPerFileChars?: number\n /** HTML cap. Default 30000. */\n maxHtmlChars?: number\n /** Caller-owned transport. Required: agent-eval executes no paid model. */\n chat: ChatClient\n /** Endpoint rates used when the transport reports no billed amount. */\n pricing?: CustomTokenPricing\n costLedger?: CostLedgerHandle\n costPhase?: string\n costTags?: Record<string, string>\n signal?: AbortSignal\n /**\n * Score aggregation strategy. Default `mean` — uniform average across\n * concepts. Cross-vertical comparisons should use `complexity` to\n * neutralize the integrate-vs-render asymmetry.\n */\n weightConcepts?: ConceptWeightStrategy\n /** Override the default complexity → weight table. */\n complexityWeights?: Partial<Record<ConceptComplexity, number>>\n}\n\n// ─── Prompt assembly ────────────────────────────────────────────────────\n\nexport const SEMANTIC_CONCEPT_JUDGE_VERSION = 'semantic-concept-judge-v1-2026-04-24'\n\nconst DEFAULT_MAX_SOURCE = 45_000\nconst DEFAULT_MAX_HTML = 30_000\nconst DEFAULT_MAX_PER_FILE = 20_000\nconst DEFAULT_TIMEOUT = 300_000\nconst DEFAULT_MAX_TOKENS = 16_000\nconst DEFAULT_MODEL = 'claude-sonnet-4-6'\n\nconst SEMANTIC_SCHEMA = {\n type: 'object',\n additionalProperties: false,\n required: ['summary', 'concepts'],\n properties: {\n summary: { type: 'string', minLength: 20, maxLength: 600 },\n concepts: {\n type: 'array',\n minItems: 1,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['concept', 'present', 'score', 'evidence', 'severity'],\n properties: {\n concept: { type: 'string', minLength: 1, maxLength: 120 },\n present: { type: 'boolean' },\n score: { type: 'number', minimum: 0, maximum: 10 },\n evidence: { type: 'string', minLength: 5, maxLength: 400 },\n severity: { type: 'string', enum: ['critical', 'major', 'minor', 'info'] },\n },\n },\n },\n },\n}\n\nfunction truncate(body: string, cap: number, label: string): string {\n if (body.length <= cap) return body\n return `${body.slice(0, cap)}\\n… [truncated ${body.length - cap} chars of ${label}]`\n}\n\nfunction buildPrompt(\n input: SemanticConceptJudgeInput,\n opts: { maxPerFileChars: number; maxSourceChars: number; maxHtmlChars: number },\n): string {\n const sourceBlob = input.sourceFiles\n .filter((f) => f.content.length <= opts.maxPerFileChars)\n .map((f) => `--- FILE: ${f.path} ---\\n${f.content}`)\n .join('\\n\\n')\n\n const html = input.servedHtml ?? ''\n\n return `You are a strict code-review judge evaluating whether an agent's 0-to-1 build actually implements the features the user asked for.\n\nYou MUST distinguish:\n (a) WORKING code that implements the concept (rendered UI, wired handler, real API call),\n (b) KEYWORD-PRESENT stub (comments mentioning the concept, variable names, TODOs),\n (c) ABSENT (concept nowhere).\n\nA comment like \"// TODO: add mint button\" is NOT present — score 2-3. Only count a concept as present if there is real functional code: a rendered component, a call handler wired to state or a network call, a computed value actually used.\n\nUSER REQUEST (what the agent was asked to build):\n${input.userRequest}\n\n${input.artifactLabel ? `ARTIFACT METADATA:\\n name: ${input.artifactLabel}\\n description: ${input.artifactDescription ?? ''}\\n\\n` : ''}EXPECTED CONCEPTS (each must be graded independently):\n${input.expectedConcepts\n .map(\n (c, i) =>\n ` ${i + 1}. \"${c.name}\"${c.keywords?.length ? ` — hints: [${c.keywords.slice(0, 6).join(' | ')}]` : ''}`,\n )\n .join('\\n')}\n\n${html ? `SERVED HTML (what the preview returns when hit):\\n${truncate(html, opts.maxHtmlChars, 'HTML')}\\n\\n` : ''}SOURCE FILES (the agent's workdir):\n${truncate(sourceBlob, opts.maxSourceChars, 'source')}\n\nFor EACH concept, return:\n - concept: the concept name as given (match exactly)\n - present: boolean — does a working implementation exist?\n - score: 0-10 — 10 = production-ready; 7 = functional but thin; 4 = partial/stubbed; 2 = keyword-only comment; 0 = absent\n - evidence: cite \"<file>:<line>\" or \"served-html:<selector>\" pointing at the strongest supporting code. If the concept is absent or stubbed, explain what's missing.\n - severity:\n \"info\" when present: true AND score >= 7\n \"minor\" when present: true AND 4 <= score < 7\n \"major\" when present: false OR score < 4\n \"critical\" when the concept is not only absent but a core user flow depends on it\n\nAlso produce a \"summary\" (one sentence, 20-600 chars): overall verdict on whether this is a shippable implementation of the user request vs a keyword-dense placeholder.\n\nBE SKEPTICAL. Keyword matching already passed — your job is to catch what keyword matching misses. If the agent shipped a working build, say so. If it shipped a stub, say so. Don't grade on effort.\n\nReturn STRICT JSON. No prose outside the JSON.`\n}\n\n// ─── Runner ─────────────────────────────────────────────────────────────\n\n/**\n * Run the semantic concept judge. Soft-fails to available=false on\n * LLM/JSON errors — callers in a MultiLayerVerifier pipeline can treat\n * that as \"skip\" rather than \"fail.\"\n */\nexport async function runSemanticConceptJudge(\n input: SemanticConceptJudgeInput,\n options: SemanticConceptJudgeOptions,\n): Promise<SemanticConceptJudgeResult> {\n const start = Date.now()\n const totalCount = input.expectedConcepts.length\n\n if (totalCount === 0) {\n return {\n kind: 'semantic-concept',\n version: SEMANTIC_CONCEPT_JUDGE_VERSION,\n score: 0,\n presentCount: 0,\n totalCount: 0,\n findings: [],\n summary: 'no expected concepts declared',\n durationMs: 0,\n costUsd: null,\n available: false,\n error: 'no expected concepts declared',\n }\n }\n\n const opts = {\n chat: options.chat,\n model: options.model ?? options.chat.defaultModel ?? DEFAULT_MODEL,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT,\n maxTokens: options.maxTokens ?? DEFAULT_MAX_TOKENS,\n maxSourceChars: options.maxSourceChars ?? DEFAULT_MAX_SOURCE,\n maxPerFileChars: options.maxPerFileChars ?? DEFAULT_MAX_PER_FILE,\n maxHtmlChars: options.maxHtmlChars ?? DEFAULT_MAX_HTML,\n ...(options.pricing ? { pricing: options.pricing } : {}),\n costLedger: options.costLedger ?? new CostLedger(),\n costPhase: options.costPhase ?? 'judge.semantic-concept',\n costTags: options.costTags ?? {},\n signal: options.signal ?? new AbortController().signal,\n weightConcepts: options.weightConcepts ?? 'mean',\n complexityWeights: { ...DEFAULT_COMPLEXITY_WEIGHTS, ...(options.complexityWeights ?? {}) },\n }\n\n // Build a name → weight map for aggregation. Mean strategy keeps every\n // weight at 1 (uniform average). Complexity strategy reads the table\n // and lets an explicit `weight` override. Explicit strategy uses ONLY\n // the spec's `weight` (defaulting to 1).\n const weightForConcept = (spec: ConceptSpec): number => {\n if (opts.weightConcepts === 'mean') return 1\n if (spec.weight != null) return spec.weight\n if (opts.weightConcepts === 'complexity') {\n return opts.complexityWeights[spec.complexity ?? 'render'] ?? 1\n }\n return 1\n }\n const weightByName = new Map<string, number>(\n input.expectedConcepts.map((c) => [c.name, weightForConcept(c)]),\n )\n\n let receipt: CostReceipt | undefined\n try {\n const request = {\n model: opts.model,\n messages: [\n {\n role: 'system' as const,\n content:\n 'You are a strict code-review judge. Return strict JSON only. No prose outside the JSON. A keyword in a comment is NOT a working implementation.',\n },\n { role: 'user' as const, content: buildPrompt(input, opts) },\n ],\n jsonSchema: { name: 'semantic_concept_judge', schema: SEMANTIC_SCHEMA },\n temperature: 0,\n maxTokens: opts.maxTokens,\n timeoutMs: opts.timeoutMs,\n } satisfies LlmCallRequest\n const paid = await paidJsonChat<{ summary: string; concepts: ConceptFinding[] }>({\n chat: opts.chat,\n request,\n ledger: opts.costLedger,\n channel: 'judge',\n phase: opts.costPhase,\n actor: 'semantic-concept',\n tags: opts.costTags,\n signal: opts.signal,\n ...(opts.pricing ? { pricing: opts.pricing } : {}),\n })\n receipt = paid.receipt\n if (!paid.succeeded) throw paid.error\n const { value } = paid\n\n if (!value?.concepts || !Array.isArray(value.concepts)) {\n throw new Error('judge returned malformed response — expected array under \"concepts\"')\n }\n\n const findings: ConceptFinding[] = value.concepts.map((c) => ({\n concept: String(c.concept),\n present: Boolean(c.present),\n score: Math.max(0, Math.min(10, Number(c.score ?? 0))),\n evidence: String(c.evidence ?? ''),\n severity: (['critical', 'major', 'minor', 'info'] as const).includes(c.severity)\n ? c.severity\n : 'info',\n }))\n\n const presentCount = findings.filter((f) => f.present && f.score >= 7).length\n let weightSum = 0\n let weightedScoreSum = 0\n for (const f of findings) {\n const w = weightByName.get(f.concept) ?? 1\n weightSum += w\n weightedScoreSum += w * f.score\n }\n const scoreAvg =\n weightSum > 0\n ? weightedScoreSum / weightSum\n : findings.reduce((a, f) => a + f.score, 0) / Math.max(1, findings.length)\n\n return {\n kind: 'semantic-concept',\n version: SEMANTIC_CONCEPT_JUDGE_VERSION,\n score: Number((scoreAvg / 10).toFixed(3)),\n presentCount,\n totalCount,\n findings,\n summary: String(value.summary ?? ''),\n durationMs: Date.now() - start,\n costUsd: paid.receipt.costUnknown ? null : paid.receipt.costUsd,\n available: true,\n }\n } catch (err) {\n return {\n kind: 'semantic-concept',\n version: SEMANTIC_CONCEPT_JUDGE_VERSION,\n score: 0,\n presentCount: 0,\n totalCount,\n findings: [],\n summary: '',\n durationMs: Date.now() - start,\n costUsd: receipt && !receipt.costUnknown ? receipt.costUsd : null,\n available: false,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n}\n\n/**\n * Factory: pin LLM options once, return a closure that accepts inputs.\n * Convenient for pipelines that want to share a single LlmClient config.\n */\nexport function createSemanticConceptJudge(\n options: SemanticConceptJudgeOptions,\n): (input: SemanticConceptJudgeInput) => Promise<SemanticConceptJudgeResult> {\n return (input) => runSemanticConceptJudge(input, options)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"semantic-concept-judge-Bi6_iGqg.js","names":[],"sources":["../src/analyst/chat-trace-engine.ts","../src/locked-jsonl-appender.ts","../src/analyst/findings-store.ts","../src/semantic-concept-judge.ts"],"sourcesContent":["/**\n * A `TraceAnalysisEngine` that runs entirely inside Node against a\n * caller-owned `ChatClient`.\n *\n * The other engine in this package, `createDspyRlmTraceEngine`, reaches the\n * DSPy RLM through a Python subprocess. That made every model-backed analyst\n * unreachable for a consumer that already owns a model seam and no Python:\n * `createTraceAnalyst` requires an engine, the only exported constructor\n * required a Python runner, so `buildDefaultAnalystRegistry()` registered the\n * deterministic analyst alone and `analystsFromRegistry` refused the result.\n *\n * This engine closes that path. It drives the same investigation contract —\n * bounded trace tools, a prose answer, a strict findings array — with native\n * function calls over the transport the caller already bound with\n * `createChatClient`. A caller holding a bare\n * `(request: LlmCallRequest) => Promise<LlmCallResult>` adapts it in one line:\n *\n * createChatClient({ transport: 'custom', chat: call, defaultModel, maximumAttempts })\n *\n * agent-eval still executes no paid model and holds no provider credential.\n * Every call goes through `paidChat`, so the shared cost ledger reserves the\n * priced maximum before the call and settles the receipt after it.\n *\n * Shape of one investigation:\n * 1. Investigation turns. The model reads the trace store through the tools\n * its analyst kind was given. A turn that requests no tool ends the\n * phase; an exhausted iteration or tool budget also ends it.\n * 2. One report turn. The model returns `{ answer, findings }` as JSON,\n * decoded by the same `decodeRawFindingArray` the Python bridge uses, so\n * a row this engine accepts is a row that engine could report.\n */\n\nimport { z } from 'zod'\nimport { paidChat } from '../chat-json-call'\nimport type { CustomTokenPricing } from '../cost-ledger'\nimport {\n extractJsonPayload,\n type LlmCallRequest,\n type LlmMessage,\n type LlmThinkingMode,\n type LlmToolCall,\n type LlmToolDefinition,\n} from '../llm-client'\nimport type { TraceAnalysisToolDescriptor } from '../trace-analyst/tools'\nimport type { ChatClient } from './chat-client'\nimport {\n DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS,\n type TraceAnalysisEngine,\n type TraceAnalysisEngineRequest,\n type TraceAnalysisEngineResult,\n} from './engine'\nimport { decodeRawFindingArray } from './finding-codec'\nimport { RawAnalystFindingSchema } from './finding-signature'\n\n/** Bumped whenever this engine's execution behavior changes. */\nconst CHAT_TRACE_ENGINE_VERSION = '1.0.0'\nconst ENGINE_ID = 'chat-trace'\n\n/** Marker appended to a tool result cut down to the retained-output budget. */\nconst TRUNCATION_MARKER = '\\n…[truncated to the analyst maxOutputChars budget]'\n\nexport interface ChatTraceEngineOptions {\n /**\n * Caller-owned transport. Build it with `createChatClient`; agent-eval never\n * receives the provider credential.\n */\n chat: ChatClient\n /** Model for every call. Defaults to the client's `defaultModel`. */\n model?: string\n /** Endpoint rates used when the transport reports no billed amount. */\n pricing?: CustomTokenPricing\n /** Completion cap per turn. Default: {@link DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS}. */\n maxOutputTokens?: number\n /** Sampling temperature. Omitted from the request when absent. */\n temperature?: number\n /** Provider reasoning mode. Omitted when the provider default should apply. */\n thinking?: LlmThinkingMode\n /** Per-call deadline handed to the transport. */\n requestTimeoutMs?: number\n /**\n * How the report turn asks for structured output.\n *\n * `json-object` sends JSON mode, which every OpenAI-compatible endpoint\n * accepts, and relies on the finding grammar the analyst kind already puts\n * in its instructions. `json-schema` sends the generated response schema as\n * well, which stricter endpoints honour and older ones reject. Default:\n * `json-object`.\n */\n reportFormat?: 'json-object' | 'json-schema'\n}\n\n/**\n * The report envelope. Its `findings` rows are generated from\n * `RawAnalystFindingSchema`, so the schema offered to a provider and the\n * decoder that accepts the answer cannot drift apart.\n */\nfunction buildReportJsonSchema(): { name: string; schema: Record<string, unknown> } {\n const row = z.toJSONSchema(RawAnalystFindingSchema, { target: 'draft-7' }) as Record<\n string,\n unknown\n >\n delete row.$schema\n return {\n name: 'trace_analysis_report',\n schema: {\n type: 'object',\n additionalProperties: false,\n required: ['answer', 'findings'],\n properties: {\n answer: { type: 'string', description: 'Direct prose answer to the question.' },\n findings: { type: 'array', items: row },\n },\n },\n }\n}\n\nconst REPORT_JSON_SCHEMA = buildReportJsonSchema()\n\n/**\n * Run bounded recursive trace analysis in-process over a caller-owned chat\n * transport. No Python, no subprocess, no loopback proxy.\n */\nexport function createChatTraceEngine(options: ChatTraceEngineOptions): TraceAnalysisEngine {\n const model = resolveModel(options)\n const maxOutputTokens = options.maxOutputTokens ?? DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS\n if (!Number.isSafeInteger(maxOutputTokens) || maxOutputTokens <= 0) {\n throw new TypeError('chat trace engine maxOutputTokens must be a positive safe integer')\n }\n if (\n options.temperature !== undefined &&\n (!Number.isFinite(options.temperature) || options.temperature < 0)\n ) {\n throw new TypeError('chat trace engine temperature must be a non-negative finite number')\n }\n if (\n options.requestTimeoutMs !== undefined &&\n (!Number.isSafeInteger(options.requestTimeoutMs) || options.requestTimeoutMs <= 0)\n ) {\n throw new TypeError('chat trace engine requestTimeoutMs must be a positive safe integer')\n }\n const reportFormat = options.reportFormat ?? 'json-object'\n if (reportFormat !== 'json-object' && reportFormat !== 'json-schema') {\n throw new TypeError(`chat trace engine reportFormat must be json-object or json-schema`)\n }\n\n return {\n id: ENGINE_ID,\n description:\n 'In-process recursive trace analysis over a caller-owned ChatClient with native tool calls.',\n model,\n version: CHAT_TRACE_ENGINE_VERSION,\n executionConfig: {\n kind: ENGINE_ID,\n model,\n transport: options.chat.transport,\n maximum_attempts: options.chat.maximumAttempts ?? null,\n pricing: options.pricing ? { ...options.pricing } : null,\n max_output_tokens: maxOutputTokens,\n temperature: options.temperature ?? null,\n thinking: options.thinking ?? null,\n request_timeout_ms: options.requestTimeoutMs ?? null,\n report_format: reportFormat,\n report_schema_name: REPORT_JSON_SCHEMA.name,\n },\n analyze: (request) => analyze(request, { ...options, model, maxOutputTokens, reportFormat }),\n }\n}\n\ninterface ResolvedOptions extends ChatTraceEngineOptions {\n model: string\n maxOutputTokens: number\n reportFormat: 'json-object' | 'json-schema'\n}\n\nasync function analyze(\n request: TraceAnalysisEngineRequest,\n options: ResolvedOptions,\n): Promise<TraceAnalysisEngineResult> {\n // One model call is spent on the report, so a budget of one call would buy\n // an answer with no investigation behind it. Refuse instead of pretending.\n if (request.limits.maxLlmCalls < 2) {\n throw new Error(\n `chat trace engine reserves one model call for the report, so maxLlmCalls must be at least 2 (analyst '${request.analystId}' declared ${request.limits.maxLlmCalls})`,\n )\n }\n const toolsByName = new Map(request.tools.map((tool) => [tool.name, tool]))\n if (toolsByName.size !== request.tools.length) {\n throw new Error(`chat trace engine received duplicate tool names for '${request.analystId}'`)\n }\n const toolDefinitions: LlmToolDefinition[] = request.tools.map((tool) => ({\n type: 'function',\n function: { name: tool.name, description: tool.description, parameters: tool.parameters },\n }))\n const investigationTurns = Math.max(\n 1,\n Math.min(request.limits.maxIterations, request.limits.maxLlmCalls - 1),\n )\n\n const messages: LlmMessage[] = [\n { role: 'system', content: systemPrompt(request, investigationTurns) },\n ]\n if (request.taskInputs) {\n messages.push({ role: 'user', content: renderTaskInputs(request.taskInputs) })\n }\n messages.push({ role: 'user', content: request.question })\n\n request.log?.('trace analyst engine started', {\n engine: ENGINE_ID,\n model: options.model,\n transport: options.chat.transport,\n tools: request.tools.map((tool) => tool.name),\n limits: request.limits,\n })\n\n const trajectory: unknown[] = []\n const servedModels = new Set<string>()\n let modelCalls = 0\n let toolCalls = 0\n let truncatedToolResults = 0\n let toolBudgetExhausted = false\n let turnsUsed = 0\n let stoppedOnAnswer = false\n\n for (let turn = 0; turn < investigationTurns; turn++) {\n turnsUsed = turn + 1\n const response = await callModel(request, options, {\n messages,\n tools: toolDefinitions,\n toolChoice: 'auto',\n purpose: 'investigation',\n })\n modelCalls += 1\n servedModels.add(response.servedModel ?? 'unreported')\n const requested = response.toolCalls ?? []\n messages.push({\n role: 'assistant',\n content: response.content,\n ...(requested.length > 0 ? { toolCalls: requested } : {}),\n })\n trajectory.push({\n turn: turnsUsed,\n phase: 'investigation',\n content: response.content,\n tool_calls: requested.map((call) => ({ id: call.id, name: call.name })),\n finish_reason: response.finishReason ?? null,\n })\n if (requested.length === 0) {\n stoppedOnAnswer = true\n break\n }\n for (const call of requested) {\n if (toolCalls >= request.limits.maxToolCalls) {\n toolBudgetExhausted = true\n // Every requested id still needs an answer: a provider rejects the\n // next turn when one tool call is left unanswered.\n messages.push(toolMessage(call, exhaustedToolBudget(request.limits.maxToolCalls)))\n continue\n }\n toolCalls += 1\n const executed = await executeTool(call, toolsByName, request)\n if (executed.truncated) truncatedToolResults += 1\n messages.push(toolMessage(call, executed.payload))\n trajectory.push({\n turn: turnsUsed,\n phase: 'tool',\n name: call.name,\n ok: executed.ok,\n truncated: executed.truncated,\n result_chars: executed.payload.length,\n })\n }\n if (toolBudgetExhausted) break\n }\n\n messages.push({ role: 'user', content: reportPrompt(options.reportFormat) })\n const report = await callModel(request, options, {\n messages,\n purpose: 'report',\n json: options.reportFormat,\n })\n modelCalls += 1\n servedModels.add(report.servedModel ?? 'unreported')\n trajectory.push({\n turn: turnsUsed + 1,\n phase: 'report',\n content: report.content,\n finish_reason: report.finishReason ?? null,\n })\n\n const parsed = parseReport(report.content, request.analystId, (index, reason) => {\n request.log?.('finding rejected: report row failed schema validation', {\n engine: ENGINE_ID,\n index,\n reason,\n })\n })\n\n const result: TraceAnalysisEngineResult = {\n answer: parsed.answer,\n findings: parsed.findings,\n trajectory,\n modelCalls,\n toolCalls,\n runtime: {\n engine: ENGINE_ID,\n model: options.model,\n transport: options.chat.transport,\n report_format: options.reportFormat,\n investigation_turns: turnsUsed,\n investigation_stopped_on_answer: stoppedOnAnswer,\n tool_budget_exhausted: toolBudgetExhausted,\n truncated_tool_results: truncatedToolResults,\n rejected_findings: parsed.rejectedFindings,\n // A gateway can answer `model: X` from another model on HTTP 200, so the\n // ids the provider echoed travel with the result as evidence.\n served_models: [...servedModels].sort(),\n task_inputs: request.taskInputs ? 'prompt-delivered' : 'none',\n },\n }\n request.log?.('trace analyst engine completed', {\n engine: ENGINE_ID,\n model_calls: result.modelCalls,\n tool_calls: result.toolCalls,\n findings: result.findings.length,\n })\n return result\n}\n\ninterface ModelTurn {\n content: string\n toolCalls?: LlmToolCall[]\n servedModel?: string | null\n finishReason?: string | null\n}\n\nasync function callModel(\n request: TraceAnalysisEngineRequest,\n options: ResolvedOptions,\n turn: {\n messages: LlmMessage[]\n tools?: LlmToolDefinition[]\n toolChoice?: LlmCallRequest['toolChoice']\n purpose: 'investigation' | 'report'\n json?: 'json-object' | 'json-schema'\n },\n): Promise<ModelTurn> {\n const chatRequest: LlmCallRequest = {\n model: options.model,\n // The transport may mutate what it is handed; the conversation is ours.\n messages: turn.messages.map((message) => ({ ...message })),\n maxTokens: options.maxOutputTokens,\n ...(turn.tools && turn.tools.length > 0\n ? { tools: turn.tools, ...(turn.toolChoice ? { toolChoice: turn.toolChoice } : {}) }\n : {}),\n ...(turn.json ? { jsonMode: true } : {}),\n ...(turn.json === 'json-schema' ? { jsonSchema: REPORT_JSON_SCHEMA } : {}),\n ...(options.temperature === undefined ? {} : { temperature: options.temperature }),\n ...(options.thinking === undefined ? {} : { thinking: options.thinking }),\n ...(options.requestTimeoutMs === undefined ? {} : { timeoutMs: options.requestTimeoutMs }),\n }\n const paid = await paidChat({\n chat: options.chat,\n request: chatRequest,\n ledger: request.costLedger,\n channel: 'analyst',\n phase: request.costPhase,\n actor: request.analystId,\n ...(request.costTags ? { tags: request.costTags } : {}),\n ...(options.pricing ? { pricing: options.pricing } : {}),\n ...(request.signal ? { signal: request.signal } : {}),\n })\n if (!paid.succeeded) {\n // The transport already spent its own attempts. A failure here ends the\n // investigation: continuing would report an answer the model never gave.\n throw new Error(\n `chat trace engine ${turn.purpose} call failed for '${request.analystId}': ${paid.error.message}`,\n { cause: paid.error },\n )\n }\n return {\n content: paid.response.content,\n ...(paid.response.toolCalls ? { toolCalls: paid.response.toolCalls } : {}),\n ...(paid.response.servedModel === undefined ? {} : { servedModel: paid.response.servedModel }),\n ...(paid.response.finishReason === undefined\n ? {}\n : { finishReason: paid.response.finishReason }),\n }\n}\n\ninterface ExecutedTool {\n ok: boolean\n truncated: boolean\n payload: string\n}\n\nasync function executeTool(\n call: LlmToolCall,\n toolsByName: ReadonlyMap<string, TraceAnalysisToolDescriptor>,\n request: TraceAnalysisEngineRequest,\n): Promise<ExecutedTool> {\n const descriptor = toolsByName.get(call.name)\n if (!descriptor) {\n return {\n ok: false,\n truncated: false,\n payload: toolError(\n `unknown tool '${call.name}'; available tools are ${[...toolsByName.keys()].sort().join(', ')}`,\n ),\n }\n }\n let args: unknown\n try {\n args = call.argumentsJson.trim() === '' ? {} : JSON.parse(call.argumentsJson)\n } catch (error) {\n return {\n ok: false,\n truncated: false,\n payload: toolError(\n `arguments for '${call.name}' were not JSON: ${messageOf(error)}. Send valid JSON arguments.`,\n ),\n }\n }\n try {\n const value = await descriptor.handler(\n args,\n request.signal ? { signal: request.signal } : undefined,\n )\n return truncateToolPayload(JSON.stringify(value ?? null), request.limits.maxOutputChars)\n } catch (error) {\n // A bounded store refuses an oversized or malformed read by design. That\n // refusal is the model's next instruction, not the run's failure.\n if (request.signal?.aborted) throw error\n request.log?.('trace tool failed', {\n engine: ENGINE_ID,\n analyst_id: request.analystId,\n tool: call.name,\n reason: messageOf(error),\n })\n return { ok: false, truncated: false, payload: toolError(messageOf(error)) }\n }\n}\n\nfunction truncateToolPayload(payload: string, maxOutputChars: number): ExecutedTool {\n if (payload.length <= maxOutputChars) return { ok: true, truncated: false, payload }\n const keep = Math.max(0, maxOutputChars - TRUNCATION_MARKER.length)\n return { ok: true, truncated: true, payload: `${payload.slice(0, keep)}${TRUNCATION_MARKER}` }\n}\n\nfunction toolMessage(call: LlmToolCall, content: string): LlmMessage {\n return { role: 'tool', toolCallId: call.id, content }\n}\n\nfunction toolError(reason: string): string {\n return JSON.stringify({ error: reason })\n}\n\nfunction exhaustedToolBudget(maxToolCalls: number): string {\n return toolError(\n `the trace-tool budget of ${maxToolCalls} calls is spent; answer from the evidence already read`,\n )\n}\n\nfunction systemPrompt(request: TraceAnalysisEngineRequest, investigationTurns: number): string {\n return [\n request.instructions.trim(),\n [\n 'HOW THIS INVESTIGATION RUNS:',\n `- You have ${investigationTurns} investigation turns and at most ${request.limits.maxToolCalls} trace-tool calls.`,\n '- Call the trace tools to read the store. Never state a trace fact you did not read.',\n `- A tool result longer than ${request.limits.maxOutputChars} characters is truncated; narrow the query instead of asking again.`,\n '- A tool result carrying an \"error\" field is feedback: fix the call or take another route.',\n '- Answer with no tool call once you have the evidence. You are then asked for the final report.',\n ].join('\\n'),\n ].join('\\n\\n')\n}\n\nfunction reportPrompt(reportFormat: 'json-object' | 'json-schema'): string {\n return [\n 'Report now. Do not call any more tools.',\n 'Return one JSON object with exactly two fields:',\n ' \"answer\": a direct prose answer to the question.',\n ' \"findings\": an array of findings in the schema above. Emit [] when there is nothing to report.',\n reportFormat === 'json-object'\n ? 'Return the object alone, with no surrounding prose and no code fence.'\n : 'Return the object in the response schema you were given.',\n ].join('\\n')\n}\n\nfunction renderTaskInputs(taskInputs: Readonly<Record<string, unknown>>): string {\n // The engine contract forbids dropping structured inputs. This engine has no\n // code environment to bind them as variables, so they are delivered whole as\n // conversation material and the runtime record says which way they arrived.\n return [\n 'TASK INPUTS — structured material delivered with the question, not fetched through tools:',\n JSON.stringify(taskInputs, null, 2),\n ].join('\\n')\n}\n\ninterface ParsedReport {\n answer: string\n findings: TraceAnalysisEngineResult['findings']\n rejectedFindings: number\n}\n\nfunction parseReport(\n content: string,\n analystId: string,\n onRejectedFinding: (index: number, reason: string) => void,\n): ParsedReport {\n const envelope = coerceReportEnvelope(content, analystId)\n if (typeof envelope.answer !== 'string' || !envelope.answer.trim()) {\n throw new Error(`chat trace engine report for '${analystId}' carried no answer`)\n }\n // Findings are model output: one malformed row is model noise, not an engine\n // fault, and the rest of the paid investigation must survive it.\n const decoded = decodeRawFindingArray(envelope.findings)\n if (decoded.topLevelError !== undefined) {\n throw new Error(\n `chat trace engine report for '${analystId}' had a malformed findings array: ${decoded.topLevelError}`,\n )\n }\n for (const rejection of decoded.rejected) {\n onRejectedFinding(\n rejection.index,\n `${rejection.code}${rejection.path ? ` at ${rejection.path}` : ''}: ${rejection.message}`,\n )\n }\n return {\n answer: envelope.answer,\n findings: decoded.accepted,\n rejectedFindings: decoded.rejected.length,\n }\n}\n\nfunction coerceReportEnvelope(content: string, analystId: string): Record<string, unknown> {\n let value: unknown\n try {\n value = JSON.parse(extractJsonPayload(content))\n } catch (error) {\n throw new Error(`chat trace engine report for '${analystId}' was not JSON: ${messageOf(error)}`)\n }\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new Error(`chat trace engine report for '${analystId}' was not a JSON object`)\n }\n return value as Record<string, unknown>\n}\n\nfunction resolveModel(options: ChatTraceEngineOptions): string {\n const model = options.model ?? options.chat.defaultModel\n if (typeof model !== 'string' || !model.trim() || model !== model.trim()) {\n throw new TypeError(\n 'chat trace engine needs a model: pass ChatTraceEngineOptions.model or bind defaultModel on the ChatClient',\n )\n }\n return model\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","/**\n * LockedJsonlAppender — mutex-serialized JSONL append helper for arbitrary\n * payloads. The reference-replay store does the same thing for typed\n * `ReferenceReplayRun` rows; this is the generic version used by\n * `MutationTelemetry`, `TrialTelemetry`, and any other consumer that wants\n * append-only durable telemetry without rolling its own lock.\n *\n * Locks are per absolute file path (process-local). Cross-process\n * concurrency is NOT addressed — that's an fcntl/flock problem.\n */\n\nimport { appendFileSync, existsSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { Mutex } from './concurrency'\n\nconst mutexes = new Map<string, Mutex>()\n\nfunction getMutex(path: string): Mutex {\n let m = mutexes.get(path)\n if (!m) {\n m = new Mutex()\n mutexes.set(path, m)\n }\n return m\n}\n\nexport class LockedJsonlAppender {\n private readonly mutex: Mutex\n constructor(public readonly path: string) {\n this.mutex = getMutex(path)\n if (!existsSync(dirname(path))) {\n mkdirSync(dirname(path), { recursive: true })\n }\n }\n\n async append(entry: unknown): Promise<void> {\n const line = `${JSON.stringify(entry)}\\n`\n await this.mutex.runExclusive(() => {\n appendFileSync(this.path, line)\n })\n }\n}\n\n/** Reset all internal mutex state — tests only. */\nexport function resetLockedAppendersForTesting(): void {\n mutexes.clear()\n}\n","/**\n * FindingsStore — durable persistence for AnalystFinding rows + a diff\n * helper so we can answer \"what changed since the last run?\" without\n * recomputing analysts.\n *\n * On-disk shape is JSONL: one finding per line, append-only, locked via\n * LockedJsonlAppender. Operators get crash-safety (no partial JSON),\n * cheap reads (sequential parse), and trivial backup (rsync the file).\n *\n * Reads are non-locking: a reader sees a consistent snapshot of all\n * fully-written lines and skips an incomplete trailing line if the\n * writer is mid-append. Cross-process locking is intentionally out of\n * scope (see locked-jsonl-appender.ts).\n *\n * The store is run-scoped: callers pass `runId` on append and on load,\n * which keeps multi-run files cleanly partitioned. The `diffFindings`\n * helper compares two run-id sets using stable `finding_id` semantics —\n * the diff is the cross-run signal the regression dashboard renders.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\n\nimport { LockedJsonlAppender } from '../locked-jsonl-appender'\nimport type { AnalystFinding } from './types'\n\n/**\n * One persisted row. We attach `run_id` on disk so a single file can\n * hold multiple runs and the diff helper can query without re-walking\n * separate files.\n */\nexport interface PersistedFinding extends AnalystFinding {\n run_id: string\n}\n\nexport class FindingsStore {\n private readonly appender: LockedJsonlAppender\n\n constructor(public readonly path: string) {\n this.appender = new LockedJsonlAppender(path)\n }\n\n async append(runId: string, findings: AnalystFinding[]): Promise<void> {\n for (const f of findings) {\n const row: PersistedFinding = { ...f, run_id: runId }\n await this.appender.append(row)\n }\n }\n\n /** Load every persisted finding. Discards malformed trailing lines silently. */\n loadAll(): PersistedFinding[] {\n if (!existsSync(this.path)) return []\n const raw = readFileSync(this.path, 'utf8')\n if (!raw) return []\n const out: PersistedFinding[] = []\n for (const line of raw.split('\\n')) {\n if (!line) continue\n try {\n out.push(JSON.parse(line) as PersistedFinding)\n } catch {\n // Skip torn trailing line — the lock guarantees no torn lines\n // mid-file, only at EOF when a writer is in-flight.\n }\n }\n return out\n }\n\n /** Filter to a single run. */\n loadRun(runId: string): PersistedFinding[] {\n return this.loadAll().filter((r) => r.run_id === runId)\n }\n}\n\n// ── Cross-run diff ──────────────────────────────────────────────────\n\nexport interface FindingsDiff {\n /** New finding ids in `current` that weren't in `previous`. */\n appeared: PersistedFinding[]\n /** Finding ids in `previous` that aren't in `current`. */\n disappeared: PersistedFinding[]\n /** Same finding id present in both runs and unchanged per the materiality test. */\n persisted: PersistedFinding[]\n /**\n * Same finding id in both runs but at least one non-identity field\n * shifted per `DiffPolicy.isMaterial`. Reported as [previous, current].\n */\n changed: Array<{ previous: PersistedFinding; current: PersistedFinding }>\n}\n\nexport interface DiffPolicy {\n /**\n * Predicate that decides whether two findings (same finding_id) count\n * as a material change. Defaults to {@link defaultIsMaterial}: severity\n * shift, confidence Δ > 0.05, or evidence count change. Compliance /\n * perf consumers MAY supply a stricter predicate (e.g. rationale text\n * diff, metric Δ thresholds).\n */\n isMaterial?: (previous: AnalystFinding, current: AnalystFinding) => boolean\n}\n\n/**\n * Default materiality test. Deliberately narrow so LLM-reword churn\n * doesn't flood the diff. Stricter tests are opt-in via DiffPolicy.\n */\nexport function defaultIsMaterial(a: AnalystFinding, b: AnalystFinding): boolean {\n if (a.severity !== b.severity) return true\n if (Math.abs((a.confidence ?? 0) - (b.confidence ?? 0)) > 0.05) return true\n if (a.evidence_refs.length !== b.evidence_refs.length) return true\n return false\n}\n\n/**\n * Diff two findings sets by stable finding_id. Callers typically load\n * the two run-id slices from the same store and pass them in.\n */\nexport function diffFindings(\n previous: PersistedFinding[],\n current: PersistedFinding[],\n policy: DiffPolicy = {},\n): FindingsDiff {\n const isMaterial = policy.isMaterial ?? defaultIsMaterial\n const prevById = new Map(previous.map((f) => [f.finding_id, f]))\n const curById = new Map(current.map((f) => [f.finding_id, f]))\n\n const appeared: PersistedFinding[] = []\n const disappeared: PersistedFinding[] = []\n const persisted: PersistedFinding[] = []\n const changed: FindingsDiff['changed'] = []\n\n for (const [id, cur] of curById) {\n const prev = prevById.get(id)\n if (!prev) {\n appeared.push(cur)\n continue\n }\n if (isMaterial(prev, cur)) {\n changed.push({ previous: prev, current: cur })\n } else {\n persisted.push(cur)\n }\n }\n for (const [id, prev] of prevById) {\n if (!curById.has(id)) disappeared.push(prev)\n }\n return { appeared, disappeared, persisted, changed }\n}\n","/**\n * Semantic concept judge — \"does the built artifact actually implement\n * the features the user asked for?\"\n *\n * Distinct from the domain/code/coherence judges in `judges.ts`:\n * - those judges score free-form conversational agent outputs along\n * quality dimensions (accuracy, depth, etc.)\n * - this judge scores a *built artifact* (served HTML + source files)\n * against an explicit list of expected concepts, returning per-concept\n * {present, score 0-10, evidence, severity}.\n *\n * The judge is strict about distinguishing (a) a working implementation\n * from (b) a keyword-present stub. \"// TODO: mint button\" is NOT present.\n * Only real, functional, wired-up code counts.\n *\n * Use via {@link createSemanticConceptJudge} or directly via\n * {@link runSemanticConceptJudge}. Soft-fails (available=false) on LLM\n * or JSON-parse errors so the caller can treat that as \"layer skipped\"\n * rather than \"layer failed\" in a multi-layer pipeline.\n */\n\nimport type { ChatClient } from './analyst/chat-client'\nimport { paidJsonChat } from './chat-json-call'\nimport {\n CostLedger,\n type CostLedgerHandle,\n type CostReceipt,\n type CustomTokenPricing,\n} from './cost-ledger'\nimport type { LlmCallRequest } from './llm-client'\nimport type { Severity } from './multi-layer-verifier'\n\n// ─── Types ──────────────────────────────────────────────────────────────\n\n/**\n * Implementation complexity class for weighted scoring.\n *\n * - `render` (default): the concept is a UI surface that displays static\n * data — render a list, show a counter, lay out a button. Single-file\n * work, no external integration.\n * - `integrate`: the concept requires wiring a real external system —\n * wallet connect (wagmi + RainbowKit + chain config), payment provider\n * (Stripe Elements + intent + webhook), an API client with auth.\n * Multi-file, library-knowledge, runtime correctness matters.\n * - `compute`: the concept requires algorithmic work — solver, simulator,\n * constraint propagation, ML inference. Correctness > UI polish.\n *\n * Default weights (when applied via `weightConcepts: 'complexity'`):\n * render=1.0, integrate=2.0, compute=2.5\n *\n * Cross-vertical scoring without complexity weighting silently inflates\n * the rate of UI-heavy verticals (healthcare, fintech dashboards) vs\n * integration-heavy verticals (DeFi, wallets) — all concepts treated\n * equally even though the agent does 2-3x the work for `integrate`.\n */\nexport type ConceptComplexity = 'render' | 'integrate' | 'compute'\n\nexport interface ConceptSpec {\n name: string\n /** Short hints that help the judge; not used for matching. */\n keywords?: string[]\n /** Optional explicit weight; default 1.0. Overrides complexity-derived weight. */\n weight?: number\n /** Implementation complexity class. Default `render`. */\n complexity?: ConceptComplexity\n}\n\nexport interface ConceptFinding {\n concept: string\n present: boolean\n /** 0..10. 10 = production-ready; 7 = functional thin; 4 = partial; 0 = absent. */\n score: number\n evidence: string\n severity: Severity\n}\n\nexport interface SemanticConceptJudgeInput {\n /** Full natural-language prompt the agent was handed. */\n userRequest: string\n /** Rendered HTML the preview returns (UI artifacts). Optional. */\n servedHtml?: string\n /** Top-level source files from the agent's workdir. */\n sourceFiles: Array<{ path: string; content: string }>\n /** The expected concept list. */\n expectedConcepts: ConceptSpec[]\n /** Free-form metadata (id, difficulty) to inject into the prompt. */\n artifactLabel?: string\n artifactDescription?: string\n}\n\nexport interface SemanticConceptJudgeResult {\n kind: 'semantic-concept'\n version: string\n /** Normalized 0..1 score — mean of per-concept scores / 10. */\n score: number\n presentCount: number\n totalCount: number\n findings: ConceptFinding[]\n summary: string\n durationMs: number\n costUsd: number | null\n /** False on LLM/JSON error — treat as \"skipped / unable to judge\" in pipelines. */\n available: boolean\n error?: string\n}\n\n/**\n * Score-aggregation strategy. `mean` averages 0-10 scores uniformly.\n * `complexity` applies the default weight table (render=1, integrate=2,\n * compute=2.5) unless a concept has an explicit `weight`. `explicit`\n * honors only `weight` (defaulting to 1 for unspecified).\n */\nexport type ConceptWeightStrategy = 'mean' | 'complexity' | 'explicit'\n\nexport const DEFAULT_COMPLEXITY_WEIGHTS: Record<ConceptComplexity, number> = {\n render: 1.0,\n integrate: 2.0,\n compute: 2.5,\n}\n\nexport interface SemanticConceptJudgeOptions {\n /** Model id to call. Default 'claude-sonnet-4-6' via agent-eval defaults. */\n model?: string\n /** Per-call timeout. Default 300s. */\n timeoutMs?: number\n /** Provider-enforced output limit. Default 16000. */\n maxTokens?: number\n /** Pipeline budget for the prompt (source blob truncation). Default 45000. */\n maxSourceChars?: number\n /** Per-file cap before inclusion. Default 20000. */\n maxPerFileChars?: number\n /** HTML cap. Default 30000. */\n maxHtmlChars?: number\n /** Caller-owned transport. Required: agent-eval executes no paid model. */\n chat: ChatClient\n /** Endpoint rates used when the transport reports no billed amount. */\n pricing?: CustomTokenPricing\n costLedger?: CostLedgerHandle\n costPhase?: string\n costTags?: Record<string, string>\n signal?: AbortSignal\n /**\n * Score aggregation strategy. Default `mean` — uniform average across\n * concepts. Cross-vertical comparisons should use `complexity` to\n * neutralize the integrate-vs-render asymmetry.\n */\n weightConcepts?: ConceptWeightStrategy\n /** Override the default complexity → weight table. */\n complexityWeights?: Partial<Record<ConceptComplexity, number>>\n}\n\n// ─── Prompt assembly ────────────────────────────────────────────────────\n\nexport const SEMANTIC_CONCEPT_JUDGE_VERSION = 'semantic-concept-judge-v1-2026-04-24'\n\nconst DEFAULT_MAX_SOURCE = 45_000\nconst DEFAULT_MAX_HTML = 30_000\nconst DEFAULT_MAX_PER_FILE = 20_000\nconst DEFAULT_TIMEOUT = 300_000\nconst DEFAULT_MAX_TOKENS = 16_000\nconst DEFAULT_MODEL = 'claude-sonnet-4-6'\n\nconst SEMANTIC_SCHEMA = {\n type: 'object',\n additionalProperties: false,\n required: ['summary', 'concepts'],\n properties: {\n summary: { type: 'string', minLength: 20, maxLength: 600 },\n concepts: {\n type: 'array',\n minItems: 1,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['concept', 'present', 'score', 'evidence', 'severity'],\n properties: {\n concept: { type: 'string', minLength: 1, maxLength: 120 },\n present: { type: 'boolean' },\n score: { type: 'number', minimum: 0, maximum: 10 },\n evidence: { type: 'string', minLength: 5, maxLength: 400 },\n severity: { type: 'string', enum: ['critical', 'major', 'minor', 'info'] },\n },\n },\n },\n },\n}\n\nfunction truncate(body: string, cap: number, label: string): string {\n if (body.length <= cap) return body\n return `${body.slice(0, cap)}\\n… [truncated ${body.length - cap} chars of ${label}]`\n}\n\nfunction buildPrompt(\n input: SemanticConceptJudgeInput,\n opts: { maxPerFileChars: number; maxSourceChars: number; maxHtmlChars: number },\n): string {\n const sourceBlob = input.sourceFiles\n .filter((f) => f.content.length <= opts.maxPerFileChars)\n .map((f) => `--- FILE: ${f.path} ---\\n${f.content}`)\n .join('\\n\\n')\n\n const html = input.servedHtml ?? ''\n\n return `You are a strict code-review judge evaluating whether an agent's 0-to-1 build actually implements the features the user asked for.\n\nYou MUST distinguish:\n (a) WORKING code that implements the concept (rendered UI, wired handler, real API call),\n (b) KEYWORD-PRESENT stub (comments mentioning the concept, variable names, TODOs),\n (c) ABSENT (concept nowhere).\n\nA comment like \"// TODO: add mint button\" is NOT present — score 2-3. Only count a concept as present if there is real functional code: a rendered component, a call handler wired to state or a network call, a computed value actually used.\n\nUSER REQUEST (what the agent was asked to build):\n${input.userRequest}\n\n${input.artifactLabel ? `ARTIFACT METADATA:\\n name: ${input.artifactLabel}\\n description: ${input.artifactDescription ?? ''}\\n\\n` : ''}EXPECTED CONCEPTS (each must be graded independently):\n${input.expectedConcepts\n .map(\n (c, i) =>\n ` ${i + 1}. \"${c.name}\"${c.keywords?.length ? ` — hints: [${c.keywords.slice(0, 6).join(' | ')}]` : ''}`,\n )\n .join('\\n')}\n\n${html ? `SERVED HTML (what the preview returns when hit):\\n${truncate(html, opts.maxHtmlChars, 'HTML')}\\n\\n` : ''}SOURCE FILES (the agent's workdir):\n${truncate(sourceBlob, opts.maxSourceChars, 'source')}\n\nFor EACH concept, return:\n - concept: the concept name as given (match exactly)\n - present: boolean — does a working implementation exist?\n - score: 0-10 — 10 = production-ready; 7 = functional but thin; 4 = partial/stubbed; 2 = keyword-only comment; 0 = absent\n - evidence: cite \"<file>:<line>\" or \"served-html:<selector>\" pointing at the strongest supporting code. If the concept is absent or stubbed, explain what's missing.\n - severity:\n \"info\" when present: true AND score >= 7\n \"minor\" when present: true AND 4 <= score < 7\n \"major\" when present: false OR score < 4\n \"critical\" when the concept is not only absent but a core user flow depends on it\n\nAlso produce a \"summary\" (one sentence, 20-600 chars): overall verdict on whether this is a shippable implementation of the user request vs a keyword-dense placeholder.\n\nBE SKEPTICAL. Keyword matching already passed — your job is to catch what keyword matching misses. If the agent shipped a working build, say so. If it shipped a stub, say so. Don't grade on effort.\n\nReturn STRICT JSON. No prose outside the JSON.`\n}\n\n// ─── Runner ─────────────────────────────────────────────────────────────\n\n/**\n * Run the semantic concept judge. Soft-fails to available=false on\n * LLM/JSON errors — callers in a MultiLayerVerifier pipeline can treat\n * that as \"skip\" rather than \"fail.\"\n */\nexport async function runSemanticConceptJudge(\n input: SemanticConceptJudgeInput,\n options: SemanticConceptJudgeOptions,\n): Promise<SemanticConceptJudgeResult> {\n const start = Date.now()\n const totalCount = input.expectedConcepts.length\n\n if (totalCount === 0) {\n return {\n kind: 'semantic-concept',\n version: SEMANTIC_CONCEPT_JUDGE_VERSION,\n score: 0,\n presentCount: 0,\n totalCount: 0,\n findings: [],\n summary: 'no expected concepts declared',\n durationMs: 0,\n costUsd: null,\n available: false,\n error: 'no expected concepts declared',\n }\n }\n\n const opts = {\n chat: options.chat,\n model: options.model ?? options.chat.defaultModel ?? DEFAULT_MODEL,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT,\n maxTokens: options.maxTokens ?? DEFAULT_MAX_TOKENS,\n maxSourceChars: options.maxSourceChars ?? DEFAULT_MAX_SOURCE,\n maxPerFileChars: options.maxPerFileChars ?? DEFAULT_MAX_PER_FILE,\n maxHtmlChars: options.maxHtmlChars ?? DEFAULT_MAX_HTML,\n ...(options.pricing ? { pricing: options.pricing } : {}),\n costLedger: options.costLedger ?? new CostLedger(),\n costPhase: options.costPhase ?? 'judge.semantic-concept',\n costTags: options.costTags ?? {},\n signal: options.signal ?? new AbortController().signal,\n weightConcepts: options.weightConcepts ?? 'mean',\n complexityWeights: { ...DEFAULT_COMPLEXITY_WEIGHTS, ...(options.complexityWeights ?? {}) },\n }\n\n // Build a name → weight map for aggregation. Mean strategy keeps every\n // weight at 1 (uniform average). Complexity strategy reads the table\n // and lets an explicit `weight` override. Explicit strategy uses ONLY\n // the spec's `weight` (defaulting to 1).\n const weightForConcept = (spec: ConceptSpec): number => {\n if (opts.weightConcepts === 'mean') return 1\n if (spec.weight != null) return spec.weight\n if (opts.weightConcepts === 'complexity') {\n return opts.complexityWeights[spec.complexity ?? 'render'] ?? 1\n }\n return 1\n }\n const weightByName = new Map<string, number>(\n input.expectedConcepts.map((c) => [c.name, weightForConcept(c)]),\n )\n\n let receipt: CostReceipt | undefined\n try {\n const request = {\n model: opts.model,\n messages: [\n {\n role: 'system' as const,\n content:\n 'You are a strict code-review judge. Return strict JSON only. No prose outside the JSON. A keyword in a comment is NOT a working implementation.',\n },\n { role: 'user' as const, content: buildPrompt(input, opts) },\n ],\n jsonSchema: { name: 'semantic_concept_judge', schema: SEMANTIC_SCHEMA },\n temperature: 0,\n maxTokens: opts.maxTokens,\n timeoutMs: opts.timeoutMs,\n } satisfies LlmCallRequest\n const paid = await paidJsonChat<{ summary: string; concepts: ConceptFinding[] }>({\n chat: opts.chat,\n request,\n ledger: opts.costLedger,\n channel: 'judge',\n phase: opts.costPhase,\n actor: 'semantic-concept',\n tags: opts.costTags,\n signal: opts.signal,\n ...(opts.pricing ? { pricing: opts.pricing } : {}),\n })\n receipt = paid.receipt\n if (!paid.succeeded) throw paid.error\n const { value } = paid\n\n if (!value?.concepts || !Array.isArray(value.concepts)) {\n throw new Error('judge returned malformed response — expected array under \"concepts\"')\n }\n\n const findings: ConceptFinding[] = value.concepts.map((c) => ({\n concept: String(c.concept),\n present: Boolean(c.present),\n score: Math.max(0, Math.min(10, Number(c.score ?? 0))),\n evidence: String(c.evidence ?? ''),\n severity: (['critical', 'major', 'minor', 'info'] as const).includes(c.severity)\n ? c.severity\n : 'info',\n }))\n\n const presentCount = findings.filter((f) => f.present && f.score >= 7).length\n let weightSum = 0\n let weightedScoreSum = 0\n for (const f of findings) {\n const w = weightByName.get(f.concept) ?? 1\n weightSum += w\n weightedScoreSum += w * f.score\n }\n const scoreAvg =\n weightSum > 0\n ? weightedScoreSum / weightSum\n : findings.reduce((a, f) => a + f.score, 0) / Math.max(1, findings.length)\n\n return {\n kind: 'semantic-concept',\n version: SEMANTIC_CONCEPT_JUDGE_VERSION,\n score: Number((scoreAvg / 10).toFixed(3)),\n presentCount,\n totalCount,\n findings,\n summary: String(value.summary ?? ''),\n durationMs: Date.now() - start,\n costUsd: paid.receipt.costUnknown ? null : paid.receipt.costUsd,\n available: true,\n }\n } catch (err) {\n return {\n kind: 'semantic-concept',\n version: SEMANTIC_CONCEPT_JUDGE_VERSION,\n score: 0,\n presentCount: 0,\n totalCount,\n findings: [],\n summary: '',\n durationMs: Date.now() - start,\n costUsd: receipt && !receipt.costUnknown ? receipt.costUsd : null,\n available: false,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n}\n\n/**\n * Factory: pin LLM options once, return a closure that accepts inputs.\n * Convenient for pipelines that want to share a single LlmClient config.\n */\nexport function createSemanticConceptJudge(\n options: SemanticConceptJudgeOptions,\n): (input: SemanticConceptJudgeInput) => Promise<SemanticConceptJudgeResult> {\n return (input) => runSemanticConceptJudge(input, options)\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as RunRecord } from "./run-record-DTv1MdjK.js";
|
|
2
2
|
import { a as PairedPromotionDecision, d as PairedBootstrapResult, i as PairedMcNemarEvidence, r as PairedDecisionStatistic, t as PairedDecisionMethod, u as PairedBootstrapOptions } from "./paired-promotion-decision-CGzg0cI_.js";
|
|
3
|
-
import { R as Scenario, a as CampaignResult, b as GenerationRecord, h as GateContext, j as MutableSurface, p as Gate, v as GateResult, w as JudgeScore } from "./types-
|
|
3
|
+
import { R as Scenario, a as CampaignResult, b as GenerationRecord, h as GateContext, j as MutableSurface, p as Gate, v as GateResult, w as JudgeScore } from "./types-C34V4Vto.js";
|
|
4
4
|
//#region src/statistics/paired-binary.d.ts
|
|
5
5
|
/** A binomial proportion estimate with a confidence interval. */
|
|
6
6
|
interface ProportionInterval {
|
|
@@ -1277,4 +1277,4 @@ declare function dimensionRegressions(candidate: Map<string, Record<string, Judg
|
|
|
1277
1277
|
}): DimensionRegression[];
|
|
1278
1278
|
//#endregion
|
|
1279
1279
|
export { paretoSignificanceGate as $, PairArmsOptions as A, McNemarResult as At, PowerPreflight as B, passAtK as Bt, hashJson as C, verifyAttestation as Ct, ComparePairedArmsOptions as D, EProcessStep as Dt, verifyManifest as E, EProcessState as Et, PairedCorrectness as F, mcnemar as Ft, BuildEvidenceVectorOptions as G, powerPreflight as H, PairedMetricDelta as I, pairedBinaryScale as It, ParetoSignificanceGateOptions as J, EvidenceVector as K, comparePairedArms as L, pairedRiskDifference as Lt, PairRunRecordsResult as M, RiskDifferenceResult as Mt, PairedArmRow as N, ScoreRiskDifferenceResult as Nt, MatchedPair as O, eProcess as Ot, PairedArmsComparison as P, isBinaryOutcomeVector as Pt, paretoPolicy as Q, pairArms as R, pairedRiskDifferenceExact as Rt, evaluateHypothesis as S, attest as St, signManifest as T, EProcessOptions as Tt, AxisEvidence as U, PowerPreflightOptions as V, wilson as Vt, AxisVerdict as W, PromotionPolicy as X, PromotionObjective as Y, buildEvidenceVector as Z, sequentialPairedGate as _, verifyEvidenceReceipt as _t, detectScale as a, createCampaignEvidenceReceipt as at, SignedManifest as b, AttestationVerification as bt, pairHoldout as c, EVIDENCE_RECEIPT_VERSION as ct, SequentialDecision as d, EvidenceBinding as dt, Objective as et, SequentialObservation as f, EvidenceReceipt as ft, sequentialDecide as g, isIndependentEvidence as gt, SequentialStreamState as h, createEvidenceReceipt as ht, PairedHoldout as i, CampaignEvidenceContext as it, PairArmsResult as j, ProportionInterval as jt, MatchedRunRecordPair as k, ExactRiskDifferenceResult as kt, SequentialDecideFn as l, EvidenceAuthority as lt, SequentialPairedGateOptions as m, INDEPENDENT_EVIDENCE_AUTHORITY_KINDS as mt, HeldoutSignificance as n, dominates as nt, dimensionRegressions as o, CreateEvidenceReceiptInput as ot, SequentialPairedGate as p, EvidenceReceiptVerification as pt, ObjectiveSource as q, HeldoutSignificanceOptions as r, paretoFrontier as rt, heldoutSignificance as s, EVIDENCE_AUTHORITY_KINDS as st, DimensionRegression as t, ParetoResult as tt, SequentialDecideOptions as u, EvidenceAuthorityKind as ut, HypothesisManifest as v, ATTESTATION_ALGORITHM as vt, manifestContentDigest as w, EProcess as wt, SignedManifestAlgo as x, AttestedReport as xt, HypothesisResult as y, AttestationProvenance as yt, pairRunRecords as z, pairedRiskDifferenceScore as zt };
|
|
1280
|
-
//# sourceMappingURL=statistical-heldout-
|
|
1280
|
+
//# sourceMappingURL=statistical-heldout-0La5ZTlv.d.ts.map
|
package/dist/{statistical-heldout-Z9NROFFS.d.ts.map → statistical-heldout-0La5ZTlv.d.ts.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statistical-heldout-
|
|
1
|
+
{"version":3,"file":"statistical-heldout-0La5ZTlv.d.ts","names":[],"sources":["../src/statistics/paired-binary.ts","../src/statistics/sequential-eprocess.ts","../src/attestation.ts","../src/experiment/evidence-receipt.ts","../src/experiment/campaign-evidence.ts","../src/pareto.ts","../src/campaign/gates/promotion-policy.ts","../src/campaign/gates/power-preflight.ts","../src/paired-arms.ts","../src/pre-registration.ts","../src/campaign/gates/sequential.ts","../src/campaign/gates/statistical-heldout.ts"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as CaptureIntegrityError } from "./errors-Dngq5h35.js";
|
|
2
|
-
import {
|
|
2
|
+
import { C as TraceNotFoundError, E as extractOtlpAttributes, O as projectOtlpFlatLine, S as TraceFileTooLargeError, T as compareSpanTime, _ as TraceAnalysisLimitError, b as TraceFileMalformedError, c as bindSpanSourceReader, d as truncateForBudget, f as validateInteger, g as SpanNotFoundError, h as TRACE_ANALYSIS_LIMITS, k as spanEpochMillis, p as DEFAULT_TRACE_ANALYST_BUDGETS, u as compileSearchRegex, x as TraceFileMissingError, y as TraceAnalysisValidationError } from "./kind-factory-D5HOW3R0.js";
|
|
3
3
|
import { readFile, stat } from "node:fs/promises";
|
|
4
4
|
//#region src/trace-analyst/shared-abortable-task.ts
|
|
5
5
|
function createSharedAbortableTask(factory) {
|
|
@@ -87,6 +87,7 @@ async function scanCheckpoint(signal, item) {
|
|
|
87
87
|
/** Default ceiling for {@link OtlpFileTraceStoreOptions.maxFileBytes}. */
|
|
88
88
|
const DEFAULT_MAX_TRACE_FILE_BYTES = 256 * 1024 * 1024;
|
|
89
89
|
var BufferedOtlpTraceStore = class {
|
|
90
|
+
readSpanSource;
|
|
90
91
|
perAttributeViewBudget;
|
|
91
92
|
perAttributeSpanBudget;
|
|
92
93
|
perCallByteCeiling;
|
|
@@ -100,6 +101,10 @@ var BufferedOtlpTraceStore = class {
|
|
|
100
101
|
this.perAttributeSpanBudget = validateInteger(opts.perAttributeSpanBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perAttributeSpanBudget, "perAttributeSpanBudget", TRACE_ANALYSIS_LIMITS.minimumTextBudget);
|
|
101
102
|
this.perCallByteCeiling = validateInteger(opts.perCallByteCeiling ?? DEFAULT_TRACE_ANALYST_BUDGETS.perCallByteCeiling, "perCallByteCeiling", 1);
|
|
102
103
|
this.perMatchTextBudget = validateInteger(opts.perMatchTextBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perMatchTextBudget, "perMatchTextBudget", TRACE_ANALYSIS_LIMITS.minimumTextBudget);
|
|
104
|
+
if (opts.sourceReader !== void 0) this.readSpanSource = bindSpanSourceReader(this, opts.sourceReader, {
|
|
105
|
+
perAttributeSpanBudget: this.perAttributeSpanBudget,
|
|
106
|
+
perCallByteCeiling: this.perCallByteCeiling
|
|
107
|
+
});
|
|
103
108
|
}
|
|
104
109
|
async hasTrace(trace_id, context) {
|
|
105
110
|
context?.signal?.throwIfAborted();
|
|
@@ -754,4 +759,4 @@ function finalizeErrorClusters(clusters, errorTraceCount) {
|
|
|
754
759
|
//#endregion
|
|
755
760
|
export { otlpTextToTraceAnalysisStore as i, OtlpFileTraceStore as n, createOtlpBufferTraceStore as r, DEFAULT_MAX_TRACE_FILE_BYTES as t };
|
|
756
761
|
|
|
757
|
-
//# sourceMappingURL=store-otlp-
|
|
762
|
+
//# sourceMappingURL=store-otlp-DWGUwlyj.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-otlp-DWGUwlyj.js","names":[],"sources":["../src/trace-analyst/shared-abortable-task.ts","../src/trace-analyst/store-otlp.ts"],"sourcesContent":["export interface SharedAbortableTask<T> {\n controller: AbortController\n promise: Promise<T>\n consumers: number\n settled: boolean\n}\n\nexport function createSharedAbortableTask<T>(\n factory: (signal: AbortSignal) => Promise<T>,\n): SharedAbortableTask<T> {\n const controller = new AbortController()\n const task: SharedAbortableTask<T> = {\n controller,\n promise: factory(controller.signal),\n consumers: 0,\n settled: false,\n }\n void task.promise.then(\n () => {\n task.settled = true\n },\n () => {\n task.settled = true\n },\n )\n return task\n}\n\nexport function waitForSharedTask<T>(\n task: SharedAbortableTask<T>,\n signal: AbortSignal | undefined,\n): Promise<T> {\n signal?.throwIfAborted()\n task.consumers += 1\n\n return new Promise<T>((resolve, reject) => {\n let finished = false\n const finish = (callback: () => void): void => {\n if (finished) return\n finished = true\n signal?.removeEventListener('abort', onAbort)\n task.consumers -= 1\n callback()\n }\n const onAbort = (): void => {\n finish(() => {\n reject(signal?.reason)\n if (!task.settled && task.consumers === 0) {\n task.controller.abort(signal?.reason)\n }\n })\n }\n\n signal?.addEventListener('abort', onAbort, { once: true })\n task.promise.then(\n (value) => finish(() => resolve(value)),\n (error: unknown) => finish(() => reject(error)),\n )\n if (signal?.aborted) onAbort()\n })\n}\n","/**\n * `OtlpFileTraceStore` — read-only OTLP-JSONL trace store for the\n * trace-analyst.\n *\n * Wire shape. Each line of the input file is one OTLP-shaped span. The\n * store understands flattened OTLP JSONL plus the OpenInference vocab.\n * We project upstream's full\n * span shape down to `TraceAnalystSpan` lazily — full materialisation\n * only happens for the spans the agent actually requests.\n *\n * Indexing. On first read the store builds an in-memory index keyed\n * by `trace_id` carrying:\n * - byte offsets + lengths for each span line (for surgical reads\n * without re-parsing the whole file)\n * - a `TraceAnalystTraceSummary` rollup\n * - sets of services / agents / models / tools / has_errors\n * - byte size of the trace's JSONL slab\n *\n * Memory bound. The index keeps span metadata only — names, kinds,\n * offsets, status. Attribute payloads stay on disk until requested.\n * For a 50MB JSONL with 50k spans, the index is ~5MB.\n *\n * Concurrency. The store builds the index once on first read and\n * caches it. Subsequent reads reuse the index. The file is opened on\n * each read; we never hold a long-lived FD.\n */\n\nimport { readFile, stat } from 'node:fs/promises'\nimport type { RE2JS } from 're2js'\nimport { CaptureIntegrityError } from '../errors'\nimport {\n SpanNotFoundError,\n TraceAnalysisLimitError,\n TraceAnalysisValidationError,\n TraceFileMalformedError,\n TraceFileMissingError,\n TraceFileTooLargeError,\n TraceNotFoundError,\n} from './errors'\nimport {\n compareSpanTime,\n extractOtlpAttributes,\n projectOtlpFlatLine,\n spanEpochMillis,\n} from './otlp-span'\nimport {\n createSharedAbortableTask,\n type SharedAbortableTask,\n waitForSharedTask,\n} from './shared-abortable-task'\nimport {\n compileSearchRegex,\n TRACE_ANALYSIS_LIMITS,\n type TraceAnalysisStore,\n type TraceAnalysisStoreContext,\n truncateForBudget,\n validateInteger,\n} from './store'\nimport { bindSpanSourceReader } from './store-boundary'\nimport type { SpanSourceReader } from './store-contract'\nimport {\n type DatasetOverview,\n DEFAULT_TRACE_ANALYST_BUDGETS,\n type ErrorCluster,\n type QueryTracesPage,\n type SearchSpanResult,\n type SearchTraceResult,\n type SpanMatchRecord,\n type TraceAnalystFilters,\n type TraceAnalystSpan,\n type TraceAnalystSpanKind,\n type TraceAnalystSpanStatus,\n type TraceAnalystTraceSummary,\n type ViewSpansResult,\n type ViewTraceOversized,\n type ViewTraceResult,\n} from './types'\n\n/** Lines indexed between event-loop yields. Bounded synchronous work per\n * tick keeps the index build from starving other tasks on large files\n * while staying coarse enough that the yields are cheap. */\nconst INDEX_YIELD_LINES = 5000\nconst SCAN_YIELD_ITEMS = 500\n\n/** Hand control back to the event loop without busy-waiting. */\nfunction yieldToEventLoop(): Promise<void> {\n return new Promise((resolve) => setImmediate(resolve))\n}\n\nasync function scanCheckpoint(signal: AbortSignal | undefined, item: number): Promise<void> {\n signal?.throwIfAborted()\n if (item > 0 && item % SCAN_YIELD_ITEMS === 0) {\n await yieldToEventLoop()\n signal?.throwIfAborted()\n }\n}\n\ninterface SpanIndexEntry {\n span_id: string\n parent_span_id: string | null\n name: string\n kind: TraceAnalystSpanKind\n start_time: string\n end_time: string\n duration_ms: number\n status: TraceAnalystSpanStatus\n status_message: string | undefined\n service_name: string | null\n agent_name: string | null\n model_name: string | null\n tool_name: string | null\n /** Byte offset in the raw JSONL file to the start of this span's line. */\n line_byte_offset: number\n /** Length of this line in bytes (excluding the trailing newline). */\n line_byte_length: number\n}\n\ninterface TraceIndexEntry {\n trace_id: string\n service_name: string | null\n agent_name: string | null\n span_count: number\n has_errors: boolean\n start_time: string\n end_time: string\n duration_ms: number\n raw_jsonl_bytes: number\n models: Set<string>\n tools: Set<string>\n spans: SpanIndexEntry[]\n /** Sorted by line offset for stable iteration. */\n}\n\ninterface DatasetIndex {\n byTrace: Map<string, TraceIndexEntry>\n totalRawBytes: number\n // Pre-computed sorted trace_ids for sample/query stability.\n sortedTraceIds: string[]\n}\n\nexport interface ToolSpansToTraceAnalysisStoreOptions {\n /** Authorized original-record lookup, exposed only when supplied. */\n sourceReader?: SpanSourceReader\n /** Override the discovery (`viewTrace`) per-attribute byte cap. */\n perAttributeViewBudget?: number\n /** Override the surgical (`viewSpans`) per-attribute byte cap. */\n perAttributeSpanBudget?: number\n /** Override the per-call ceiling that triggers oversized summaries. */\n perCallByteCeiling?: number\n /** Override the per-match text budget. */\n perMatchTextBudget?: number\n}\n\ntype BufferedOtlpTraceStoreOptions = ToolSpansToTraceAnalysisStoreOptions\n\nexport interface OtlpFileTraceStoreOptions extends BufferedOtlpTraceStoreOptions {\n /** Path to the OTLP-JSONL file. */\n path: string\n /**\n * Hard ceiling on the trace file size in bytes. The store reads the\n * whole file into one Buffer and indexes it in memory, so an\n * unbounded file OOMs the process. Above this size the store fails\n * loud with `TraceFileTooLargeError` instead of degrading silently.\n * Default 256 MiB.\n */\n maxFileBytes?: number\n}\n\n/** Default ceiling for {@link OtlpFileTraceStoreOptions.maxFileBytes}. */\nexport const DEFAULT_MAX_TRACE_FILE_BYTES = 256 * 1024 * 1024\n\nabstract class BufferedOtlpTraceStore implements TraceAnalysisStore {\n readonly readSpanSource?: SpanSourceReader\n private readonly perAttributeViewBudget: number\n private readonly perAttributeSpanBudget: number\n private readonly perCallByteCeiling: number\n private readonly perMatchTextBudget: number\n private indexValue?: DatasetIndex\n private indexTask?: SharedAbortableTask<DatasetIndex>\n private bufferValue?: Buffer\n private bufferTask?: SharedAbortableTask<Buffer>\n\n constructor(opts: BufferedOtlpTraceStoreOptions) {\n this.perAttributeViewBudget = validateInteger(\n opts.perAttributeViewBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perAttributeViewBudget,\n 'perAttributeViewBudget',\n TRACE_ANALYSIS_LIMITS.minimumTextBudget,\n )\n this.perAttributeSpanBudget = validateInteger(\n opts.perAttributeSpanBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perAttributeSpanBudget,\n 'perAttributeSpanBudget',\n TRACE_ANALYSIS_LIMITS.minimumTextBudget,\n )\n this.perCallByteCeiling = validateInteger(\n opts.perCallByteCeiling ?? DEFAULT_TRACE_ANALYST_BUDGETS.perCallByteCeiling,\n 'perCallByteCeiling',\n 1,\n )\n this.perMatchTextBudget = validateInteger(\n opts.perMatchTextBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perMatchTextBudget,\n 'perMatchTextBudget',\n TRACE_ANALYSIS_LIMITS.minimumTextBudget,\n )\n if (opts.sourceReader !== undefined) {\n this.readSpanSource = bindSpanSourceReader(this, opts.sourceReader, {\n perAttributeSpanBudget: this.perAttributeSpanBudget,\n perCallByteCeiling: this.perCallByteCeiling,\n })\n }\n }\n\n // ─── Public API ────────────────────────────────────────────────────\n\n async hasTrace(trace_id: string, context?: TraceAnalysisStoreContext): Promise<boolean> {\n context?.signal?.throwIfAborted()\n const idx = await this.index(context)\n context?.signal?.throwIfAborted()\n return idx.byTrace.has(trace_id)\n }\n\n async hasSpans(\n opts: { trace_id: string; span_ids: readonly string[] },\n context?: TraceAnalysisStoreContext,\n ): Promise<string[]> {\n context?.signal?.throwIfAborted()\n const idx = await this.index(context)\n const trace = idx.byTrace.get(opts.trace_id)\n if (!trace) return []\n const requested = new Set(opts.span_ids)\n const found: string[] = []\n for (let index = 0; index < trace.spans.length; index += 1) {\n await scanCheckpoint(context?.signal, index)\n const spanId = trace.spans[index]!.span_id\n if (requested.has(spanId)) found.push(spanId)\n }\n return found\n }\n\n async getOverview(\n filters?: TraceAnalystFilters,\n context?: TraceAnalysisStoreContext,\n ): Promise<DatasetOverview> {\n const idx = await this.index(context)\n const matched = await this.matchedTraces(idx, filters, context)\n\n const services = new Set<string>()\n const agents = new Set<string>()\n const models = new Set<string>()\n const tools = new Set<string>()\n let rawBytes = 0\n let earliest: string | null = null\n let latest: string | null = null\n let errorTraceCount = 0\n let errorSpanCount = 0\n const clusters = new Map<string, ErrorClusterAccumulator>()\n\n let traceIndex = 0\n for (const t of matched) {\n await scanCheckpoint(context?.signal, traceIndex++)\n if (t.service_name) services.add(t.service_name)\n if (t.agent_name) agents.add(t.agent_name)\n for (const m of t.models) models.add(m)\n for (const tn of t.tools) tools.add(tn)\n rawBytes += t.raw_jsonl_bytes\n if (!earliest || compareSpanTime(t.start_time, earliest) < 0) earliest = t.start_time\n if (!latest || compareSpanTime(t.end_time, latest) > 0) latest = t.end_time\n if (t.has_errors) {\n errorTraceCount += 1\n let spanIndex = 0\n for (const s of t.spans) {\n await scanCheckpoint(context?.signal, spanIndex++)\n if (s.status !== 'ERROR') continue\n errorSpanCount += 1\n accumulateErrorCluster(clusters, t.trace_id, s)\n }\n }\n }\n\n const sample_trace_ids = matched.slice(0, 20).map((t) => t.trace_id)\n return {\n total_traces: matched.length,\n raw_jsonl_bytes: rawBytes,\n services: [...services].sort(),\n agents: [...agents].sort(),\n models: [...models].sort(),\n tool_names: [...tools].sort(),\n sample_trace_ids,\n errors: { trace_count: errorTraceCount, span_count: errorSpanCount },\n error_clusters: finalizeErrorClusters(clusters, errorTraceCount),\n time_range: earliest && latest ? { earliest, latest } : null,\n }\n }\n\n async queryTraces(\n opts: { filters?: TraceAnalystFilters; limit: number; offset?: number },\n context?: TraceAnalysisStoreContext,\n ): Promise<QueryTracesPage> {\n const limit = validateInteger(\n opts.limit,\n 'queryTraces.limit',\n 1,\n TRACE_ANALYSIS_LIMITS.queryTraces,\n )\n const offset = validateInteger(opts.offset ?? 0, 'queryTraces.offset', 0)\n\n const idx = await this.index(context)\n const matched = await this.matchedTraces(idx, opts.filters, context)\n const slice = matched.slice(offset, offset + limit)\n return {\n traces: slice.map((t) => this.toSummary(t)),\n total: matched.length,\n has_more: offset + slice.length < matched.length,\n }\n }\n\n async countTraces(\n filters?: TraceAnalystFilters,\n context?: TraceAnalysisStoreContext,\n ): Promise<number> {\n const idx = await this.index(context)\n const matched = await this.matchedTraces(idx, filters, context)\n return matched.length\n }\n\n async viewTrace(\n opts: { trace_id: string; per_attribute_byte_cap?: number },\n context?: TraceAnalysisStoreContext,\n ): Promise<ViewTraceResult> {\n context?.signal?.throwIfAborted()\n const idx = await this.index(context)\n const trace = idx.byTrace.get(opts.trace_id)\n if (!trace) {\n throw new TraceNotFoundError(opts.trace_id)\n }\n const cap = validateInteger(\n opts.per_attribute_byte_cap ?? this.perAttributeViewBudget,\n 'viewTrace.per_attribute_byte_cap',\n 1,\n )\n\n // Probe size first — if the materialised payload would exceed\n // the per-call ceiling we return an oversized summary rather than\n // blowing the agent's context.\n const buf = await this.buffer(context)\n const spans: TraceAnalystSpan[] = []\n let runningBytes = 0\n let span_response_bytes_max = 0\n const counter: TruncationCounter = { value: 0 }\n let spanIndex = 0\n for (const s of trace.spans) {\n await scanCheckpoint(context?.signal, spanIndex++)\n const projected = this.projectSpan(buf, trace.trace_id, s, cap, counter)\n const bytes = Buffer.byteLength(JSON.stringify(projected), 'utf8')\n span_response_bytes_max = Math.max(span_response_bytes_max, bytes)\n runningBytes += bytes\n if (runningBytes > this.perCallByteCeiling) {\n return {\n trace_id: trace.trace_id,\n oversized: this.buildOversizedSummary(trace, span_response_bytes_max),\n }\n }\n spans.push(projected)\n }\n return { trace_id: trace.trace_id, spans }\n }\n\n async viewSpans(\n opts: { trace_id: string; span_ids: readonly string[]; per_attribute_byte_cap?: number },\n context?: TraceAnalysisStoreContext,\n ): Promise<ViewSpansResult> {\n context?.signal?.throwIfAborted()\n const idx = await this.index(context)\n const trace = idx.byTrace.get(opts.trace_id)\n if (!trace) throw new TraceNotFoundError(opts.trace_id)\n if (opts.span_ids.length < 1 || opts.span_ids.length > TRACE_ANALYSIS_LIMITS.viewSpans) {\n throw new TraceAnalysisValidationError(\n `viewSpans.span_ids must contain 1..${TRACE_ANALYSIS_LIMITS.viewSpans} ids, got ${opts.span_ids.length}`,\n )\n }\n const cap = validateInteger(\n opts.per_attribute_byte_cap ?? this.perAttributeSpanBudget,\n 'viewSpans.per_attribute_byte_cap',\n 1,\n )\n\n const requested = [...new Set(opts.span_ids)]\n const wantSet = new Set(requested)\n const foundById = new Map<string, SpanIndexEntry>()\n for (let index = 0; index < trace.spans.length; index += 1) {\n await scanCheckpoint(context?.signal, index)\n const span = trace.spans[index]!\n if (wantSet.has(span.span_id)) foundById.set(span.span_id, span)\n }\n const missing = requested.filter((id) => !foundById.has(id))\n\n const buf = await this.buffer(context)\n const spans: TraceAnalystSpan[] = []\n let truncatedAttributeCount = 0\n const omitted = new Set(requested.filter((id) => foundById.has(id)))\n const buildResult = (): ViewSpansResult => ({\n trace_id: trace.trace_id,\n spans,\n missing_span_ids: missing,\n omitted_span_ids: requested.filter((id) => omitted.has(id)),\n has_more: omitted.size > 0,\n truncated_attribute_count: truncatedAttributeCount,\n })\n const metadataBytes = Buffer.byteLength(JSON.stringify(buildResult()), 'utf8')\n if (metadataBytes > this.perCallByteCeiling) {\n throw new TraceAnalysisLimitError(\n 'viewSpans',\n metadataBytes,\n this.perCallByteCeiling,\n `viewSpans accounting requires ${metadataBytes} bytes, over the ${this.perCallByteCeiling}-byte response limit`,\n )\n }\n let spanIndex = 0\n let smallestRejectedBytes = Number.POSITIVE_INFINITY\n for (const id of requested) {\n await scanCheckpoint(context?.signal, spanIndex++)\n const s = foundById.get(id)\n if (!s) continue\n const counter: TruncationCounter = { value: 0 }\n const projected = this.projectSpan(buf, trace.trace_id, s, cap, counter)\n spans.push(projected)\n omitted.delete(id)\n truncatedAttributeCount += counter.value\n const responseBytes = Buffer.byteLength(JSON.stringify(buildResult()), 'utf8')\n if (responseBytes <= this.perCallByteCeiling) {\n continue\n }\n smallestRejectedBytes = Math.min(smallestRejectedBytes, responseBytes)\n if (requested.length === 1) {\n throw new TraceAnalysisLimitError(\n 'viewSpans',\n responseBytes,\n this.perCallByteCeiling,\n `viewSpans cannot fit span ${JSON.stringify(id)} in the ${this.perCallByteCeiling}-byte response limit`,\n )\n }\n spans.pop()\n omitted.add(id)\n truncatedAttributeCount -= counter.value\n }\n if (foundById.size > 0 && spans.length === 0) {\n throw new TraceAnalysisLimitError(\n 'viewSpans',\n smallestRejectedBytes,\n this.perCallByteCeiling,\n `viewSpans cannot fit one requested span in the ${this.perCallByteCeiling}-byte response limit`,\n )\n }\n return buildResult()\n }\n\n async searchTrace(\n opts: { trace_id: string; regex_pattern: string; max_matches?: number },\n context?: TraceAnalysisStoreContext,\n ): Promise<SearchTraceResult> {\n const max_matches = validateInteger(\n opts.max_matches ?? 50,\n 'searchTrace.max_matches',\n 1,\n TRACE_ANALYSIS_LIMITS.searchMatches,\n )\n const idx = await this.index(context)\n const trace = idx.byTrace.get(opts.trace_id)\n if (!trace) throw new TraceNotFoundError(opts.trace_id)\n const re = compileSearchRegex(opts.regex_pattern)\n\n const buf = await this.buffer(context)\n const hits: SpanMatchRecord[] = []\n let hasMore = false\n let spanIndex = 0\n for (const s of trace.spans) {\n await scanCheckpoint(context?.signal, spanIndex++)\n const remaining = max_matches - hits.length\n const localHits = await this.scanSpanForMatches(\n buf,\n trace.trace_id,\n s,\n re,\n this.perMatchTextBudget,\n remaining,\n context,\n )\n for (const h of localHits.records) {\n if (hits.length >= max_matches) break\n hits.push(h)\n }\n if (localHits.hasMore) {\n hasMore = true\n break\n }\n }\n return {\n trace_id: trace.trace_id,\n hits,\n has_more: hasMore,\n }\n }\n\n async searchSpan(\n opts: { trace_id: string; span_id: string; regex_pattern: string; max_matches?: number },\n context?: TraceAnalysisStoreContext,\n ): Promise<SearchSpanResult> {\n const max_matches = validateInteger(\n opts.max_matches ?? 50,\n 'searchSpan.max_matches',\n 1,\n TRACE_ANALYSIS_LIMITS.searchMatches,\n )\n const idx = await this.index(context)\n const trace = idx.byTrace.get(opts.trace_id)\n if (!trace) throw new TraceNotFoundError(opts.trace_id)\n let span: SpanIndexEntry | undefined\n for (let index = 0; index < trace.spans.length; index += 1) {\n await scanCheckpoint(context?.signal, index)\n const candidate = trace.spans[index]!\n if (candidate.span_id === opts.span_id) {\n span = candidate\n break\n }\n }\n if (!span) {\n throw new SpanNotFoundError(opts.trace_id, opts.span_id)\n }\n const re = compileSearchRegex(opts.regex_pattern)\n const buf = await this.buffer(context)\n const localHits = await this.scanSpanForMatches(\n buf,\n trace.trace_id,\n span,\n re,\n this.perMatchTextBudget,\n max_matches,\n context,\n )\n return {\n trace_id: trace.trace_id,\n span_id: span.span_id,\n hits: localHits.records,\n has_more: localHits.hasMore,\n }\n }\n\n // ─── Index building ────────────────────────────────────────────────\n\n /** Force the index to materialise. Useful to amortise startup cost\n * before the first agent call. */\n async ensureIndexed(context?: TraceAnalysisStoreContext): Promise<void> {\n await this.index(context)\n }\n\n private async buffer(context?: TraceAnalysisStoreContext): Promise<Buffer> {\n context?.signal?.throwIfAborted()\n if (this.bufferValue) return this.bufferValue\n if (!this.bufferTask) {\n const task = createSharedAbortableTask((signal) => this.readBuffer(signal))\n this.bufferTask = task\n void task.promise.then(\n (value) => {\n this.bufferValue = value\n if (this.bufferTask === task) this.bufferTask = undefined\n },\n () => {\n if (this.bufferTask === task) this.bufferTask = undefined\n },\n )\n }\n return waitForSharedTask(this.bufferTask, context?.signal)\n }\n\n protected abstract readBuffer(signal?: AbortSignal): Promise<Buffer>\n\n protected abstract sourcePath(): string\n\n private async index(context?: TraceAnalysisStoreContext): Promise<DatasetIndex> {\n context?.signal?.throwIfAborted()\n if (this.indexValue) return this.indexValue\n if (!this.indexTask) {\n const task = createSharedAbortableTask((signal) => this.buildIndex(signal))\n this.indexTask = task\n void task.promise.then(\n (value) => {\n this.indexValue = value\n if (this.indexTask === task) this.indexTask = undefined\n },\n () => {\n if (this.indexTask === task) this.indexTask = undefined\n },\n )\n }\n return waitForSharedTask(this.indexTask, context?.signal)\n }\n\n private async buildIndex(signal?: AbortSignal): Promise<DatasetIndex> {\n // readGuarded surfaces missing/oversized files as typed errors.\n const buf = await this.buffer({ signal })\n signal?.throwIfAborted()\n\n const byTrace = new Map<string, TraceIndexEntry>()\n let cursor = 0\n let lineNumber = 0\n let sinceYield = 0\n while (cursor < buf.length) {\n lineNumber += 1\n // Yield to the event loop every INDEX_YIELD_LINES lines so a huge\n // file doesn't monopolise the thread for the whole index build.\n if (++sinceYield >= INDEX_YIELD_LINES) {\n sinceYield = 0\n await yieldToEventLoop()\n signal?.throwIfAborted()\n }\n const newlineIndex = buf.indexOf(0x0a, cursor) // \\n\n const lineEnd = newlineIndex === -1 ? buf.length : newlineIndex\n const lineLength = lineEnd - cursor\n if (lineLength === 0) {\n cursor = lineEnd + 1\n continue\n }\n const lineSlice = buf.subarray(cursor, lineEnd).toString('utf8')\n const lineOffset = cursor\n cursor = lineEnd + 1\n\n let parsed: unknown\n try {\n parsed = JSON.parse(lineSlice)\n } catch (cause) {\n throw new TraceFileMalformedError(this.sourcePath(), lineNumber, lineOffset, cause)\n }\n if (!parsed || typeof parsed !== 'object') {\n throw new TraceFileMalformedError(this.sourcePath(), lineNumber, lineOffset)\n }\n const span = projectOtlpFlatLine(parsed as Record<string, unknown>)\n if (!span) {\n throw new TraceFileMalformedError(this.sourcePath(), lineNumber, lineOffset)\n }\n\n let entry = byTrace.get(span.trace_id)\n if (!entry) {\n entry = {\n trace_id: span.trace_id,\n service_name: span.service_name,\n agent_name: span.agent_name,\n span_count: 0,\n has_errors: false,\n start_time: span.start_time,\n end_time: span.end_time,\n duration_ms: 0,\n raw_jsonl_bytes: 0,\n models: new Set(),\n tools: new Set(),\n spans: [],\n }\n byTrace.set(span.trace_id, entry)\n } else {\n // Pin the trace's service/agent to the first AGENT span we\n // Prefer the first agent/service fields that appear in the trace.\n if (!entry.service_name && span.service_name) entry.service_name = span.service_name\n if (!entry.agent_name && span.agent_name) entry.agent_name = span.agent_name\n }\n\n const indexEntry: SpanIndexEntry = {\n span_id: span.span_id,\n parent_span_id: span.parent_span_id,\n name: span.name,\n kind: span.kind,\n start_time: span.start_time,\n end_time: span.end_time,\n duration_ms: span.duration_ms,\n status: span.status,\n status_message: span.status_message,\n service_name: span.service_name,\n agent_name: span.agent_name,\n model_name: span.model_name,\n tool_name: span.tool_name,\n line_byte_offset: lineOffset,\n line_byte_length: lineLength,\n }\n entry.spans.push(indexEntry)\n entry.span_count += 1\n entry.raw_jsonl_bytes += lineLength + 1 // +1 newline byte\n if (span.status === 'ERROR') entry.has_errors = true\n if (compareSpanTime(span.start_time, entry.start_time) < 0) entry.start_time = span.start_time\n if (compareSpanTime(span.end_time, entry.end_time) > 0) entry.end_time = span.end_time\n if (span.model_name) entry.models.add(span.model_name)\n if (span.tool_name) entry.tools.add(span.tool_name)\n }\n\n // Compute trace duration once, sort spans by start time for\n // stable iteration.\n let totalRawBytes = 0\n for (const t of byTrace.values()) {\n signal?.throwIfAborted()\n totalRawBytes += t.raw_jsonl_bytes\n t.spans.sort(\n (a, b) =>\n compareSpanTime(a.start_time, b.start_time) || a.line_byte_offset - b.line_byte_offset,\n )\n // Duration is 0 unless BOTH bounds parse — a missing/garbage timestamp\n // yields 0, never a NaN (→ null in JSON) or a bogus epoch-from-zero span.\n const startMs = spanEpochMillis(t.start_time)\n const endMs = spanEpochMillis(t.end_time)\n t.duration_ms = startMs === null || endMs === null ? 0 : Math.max(0, endMs - startMs)\n }\n const sortedTraceIds = [...byTrace.keys()].sort()\n signal?.throwIfAborted()\n\n return { byTrace, totalRawBytes, sortedTraceIds }\n }\n\n // ─── Filter pipeline ───────────────────────────────────────────────\n\n private async matchedTraces(\n idx: DatasetIndex,\n filters: TraceAnalystFilters | undefined,\n context?: TraceAnalysisStoreContext,\n ): Promise<TraceIndexEntry[]> {\n context?.signal?.throwIfAborted()\n const traces: TraceIndexEntry[] = []\n for (let index = 0; index < idx.sortedTraceIds.length; index += 1) {\n await scanCheckpoint(context?.signal, index)\n const trace = idx.byTrace.get(idx.sortedTraceIds[index]!)\n if (trace) traces.push(trace)\n }\n if (!filters) return traces\n\n const indexedFiltered: TraceIndexEntry[] = []\n for (let index = 0; index < traces.length; index += 1) {\n await scanCheckpoint(context?.signal, index)\n const t = traces[index]!\n if (filters.has_errors !== undefined && t.has_errors !== filters.has_errors) continue\n if (filters.service_names && filters.service_names.length > 0) {\n if (!t.service_name || !filters.service_names.includes(t.service_name)) continue\n }\n if (filters.agent_names && filters.agent_names.length > 0) {\n if (!t.agent_name || !filters.agent_names.includes(t.agent_name)) continue\n }\n if (filters.model_names && filters.model_names.length > 0) {\n if (![...t.models].some((m) => filters.model_names!.includes(m))) continue\n }\n if (filters.tool_names && filters.tool_names.length > 0) {\n if (![...t.tools].some((tn) => filters.tool_names!.includes(tn))) continue\n }\n if (filters.start_time_after && t.start_time < filters.start_time_after) continue\n if (filters.start_time_before && t.start_time > filters.start_time_before) continue\n indexedFiltered.push(t)\n }\n\n if (!filters.regex_pattern) return indexedFiltered\n\n // Opt-in raw-bytes scan — only over the already-narrowed set.\n const re = compileSearchRegex(filters.regex_pattern)\n const buf = await this.buffer(context)\n const out: TraceIndexEntry[] = []\n let traceIndex = 0\n for (const t of indexedFiltered) {\n await scanCheckpoint(context?.signal, traceIndex++)\n let matched = false\n let spanIndex = 0\n for (const s of t.spans) {\n await scanCheckpoint(context?.signal, spanIndex++)\n const slice = buf.subarray(s.line_byte_offset, s.line_byte_offset + s.line_byte_length)\n // Buffer.toString allocates; tolerate it because regex_pattern\n // is opt-in. Future optimisation: byte-level fast-path for\n // ASCII-only patterns.\n if (re.test(slice.toString('utf8'))) {\n matched = true\n break\n }\n }\n if (matched) out.push(t)\n }\n return out\n }\n\n private toSummary(t: TraceIndexEntry): TraceAnalystTraceSummary {\n return {\n trace_id: t.trace_id,\n service_name: t.service_name,\n agent_name: t.agent_name,\n span_count: t.span_count,\n has_errors: t.has_errors,\n start_time: t.start_time,\n end_time: t.end_time,\n duration_ms: t.duration_ms,\n raw_jsonl_bytes: t.raw_jsonl_bytes,\n models: [...t.models].sort(),\n tools: [...t.tools].sort(),\n }\n }\n\n // ─── Span projection (lazy attribute reads) ────────────────────────\n\n private projectSpan(\n buf: Buffer,\n trace_id: string,\n s: SpanIndexEntry,\n perAttrCap: number,\n counter: TruncationCounter,\n ): TraceAnalystSpan {\n const slice = buf\n .subarray(s.line_byte_offset, s.line_byte_offset + s.line_byte_length)\n .toString('utf8')\n let raw: Record<string, unknown> = {}\n try {\n const parsed = JSON.parse(slice)\n if (parsed && typeof parsed === 'object') raw = parsed as Record<string, unknown>\n } catch {\n // Should not happen — index pre-validated.\n }\n const attrs = extractOtlpAttributes(raw)\n const projected: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(attrs)) {\n if (typeof v === 'string') {\n const trunc = truncateForBudget(v, perAttrCap)\n if (trunc !== v) counter.value += 1\n projected[k] = trunc\n } else if (Array.isArray(v) || (v && typeof v === 'object')) {\n const json = JSON.stringify(v)\n const trunc = truncateForBudget(json, perAttrCap)\n if (trunc !== json) {\n counter.value += 1\n projected[k] = trunc\n } else {\n projected[k] = v\n }\n } else {\n projected[k] = v\n }\n }\n return {\n trace_id,\n span_id: s.span_id,\n parent_span_id: s.parent_span_id,\n name: s.name,\n kind: s.kind,\n start_time: s.start_time,\n end_time: s.end_time,\n duration_ms: s.duration_ms,\n status: s.status,\n status_message: s.status_message,\n service_name: s.service_name,\n agent_name: s.agent_name,\n model_name: s.model_name,\n tool_name: s.tool_name,\n attributes: projected,\n }\n }\n\n private buildOversizedSummary(\n t: TraceIndexEntry,\n span_response_bytes_max: number,\n ): ViewTraceOversized {\n const counts = new Map<string, number>()\n let errorCount = 0\n for (const s of t.spans) {\n counts.set(s.name, (counts.get(s.name) ?? 0) + 1)\n if (s.status === 'ERROR') errorCount += 1\n }\n const top = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 20)\n return {\n span_count: t.span_count,\n top_span_names: top,\n span_response_bytes_max,\n error_span_count: errorCount,\n }\n }\n\n private async scanSpanForMatches(\n buf: Buffer,\n trace_id: string,\n s: SpanIndexEntry,\n re: RE2JS,\n textBudget: number,\n recordCap: number,\n context?: TraceAnalysisStoreContext,\n ): Promise<{ records: SpanMatchRecord[]; hasMore: boolean }> {\n // We scan against the original raw JSONL slice for each span and\n // record byte positions; the matched_text + context window is\n // truncated to `textBudget` bytes per record so total tool output\n // stays bounded even if hits cluster.\n const slice = buf\n .subarray(s.line_byte_offset, s.line_byte_offset + s.line_byte_length)\n .toString('utf8')\n const records: SpanMatchRecord[] = []\n let hasMore = false\n let matchIndex = 0\n for (const match of re.matchAll(slice)) {\n await scanCheckpoint(context?.signal, matchIndex++)\n if (records.length >= recordCap) {\n hasMore = true\n break\n }\n const offset = match.index ?? 0\n const before = slice.slice(Math.max(0, offset - textBudget / 2), offset)\n const after = slice.slice(\n offset + match[0].length,\n offset + match[0].length + Math.floor(textBudget / 2),\n )\n records.push({\n trace_id,\n span_id: s.span_id,\n span_name: s.name,\n span_kind: s.kind,\n attribute_path: bestAttributePathForOffset(slice, offset) ?? 'span.raw',\n matched_text: truncateForBudget(match[0], textBudget),\n context_before: truncateForBudget(before, textBudget),\n context_after: truncateForBudget(after, textBudget),\n match_offset: offset,\n })\n }\n return { records, hasMore }\n }\n}\n\nexport class OtlpFileTraceStore extends BufferedOtlpTraceStore {\n private readonly path: string\n private readonly maxFileBytes: number\n\n constructor(opts: OtlpFileTraceStoreOptions) {\n super(opts)\n this.path = opts.path\n this.maxFileBytes = validateInteger(\n opts.maxFileBytes ?? DEFAULT_MAX_TRACE_FILE_BYTES,\n 'maxFileBytes',\n 1,\n )\n }\n\n /** Stat-then-read so an oversized file fails loud before allocating the\n * source buffer. Missing files remain distinct from malformed traces. */\n protected async readBuffer(signal?: AbortSignal): Promise<Buffer> {\n signal?.throwIfAborted()\n let stats: Awaited<ReturnType<typeof stat>>\n try {\n stats = await stat(this.path)\n } catch (err) {\n if ((err as NodeJS.ErrnoException)?.code === 'ENOENT') {\n throw new TraceFileMissingError(this.path)\n }\n throw err\n }\n if (stats.size > this.maxFileBytes) {\n throw new TraceFileTooLargeError(this.path, stats.size, this.maxFileBytes)\n }\n signal?.throwIfAborted()\n return readFile(this.path, { signal })\n }\n\n protected sourcePath(): string {\n return this.path\n }\n}\n\nclass OtlpBufferTraceStore extends BufferedOtlpTraceStore {\n constructor(\n private readonly source: Buffer,\n opts: BufferedOtlpTraceStoreOptions,\n ) {\n super(opts)\n }\n\n protected async readBuffer(signal?: AbortSignal): Promise<Buffer> {\n signal?.throwIfAborted()\n return this.source\n }\n\n protected sourcePath(): string {\n return '<memory>'\n }\n}\n\n/** Build the bounded trace store directly from OpenInference JSONL text. */\nexport function otlpTextToTraceAnalysisStore(\n text: string,\n opts: ToolSpansToTraceAnalysisStoreOptions = {},\n): TraceAnalysisStore {\n if (!text.trim()) throw new CaptureIntegrityError('OTLP trace text must not be empty')\n return new OtlpBufferTraceStore(Buffer.from(text, 'utf8'), opts)\n}\n\nexport function createOtlpBufferTraceStore(\n source: Buffer,\n options: ToolSpansToTraceAnalysisStoreOptions = {},\n): TraceAnalysisStore {\n return new OtlpBufferTraceStore(source, options)\n}\n\nexport {\n SpanNotFoundError,\n TraceFileMalformedError,\n TraceFileMissingError,\n TraceFileTooLargeError,\n TraceNotFoundError,\n} from './errors'\n\n// ─── OTLP shape readers ──────────────────────────────────────────────\n//\n// The per-line projection lives in `./otlp-span` so the index here and\n// `otlpToRunRecords` read the same vocabulary off the same parser.\n\n// Per-call truncation counter. Each public read that projects spans\n// owns one of these and threads it through projectSpan; a store-keyed\n// counter would let two concurrent reads on the same store report each\n// other's truncation counts.\ninterface TruncationCounter {\n value: number\n}\n\n/** A `\"` at `idx` is a real JSON delimiter only when the run of `\\`\n * immediately preceding it is even-length; an odd run means the quote\n * is escaped (`\\\"`) and is part of a string value, not a boundary. */\nfunction isUnescapedQuote(slice: string, idx: number): boolean {\n if (slice[idx] !== '\"') return false\n let backslashes = 0\n let b = idx - 1\n while (b >= 0 && slice[b] === '\\\\') {\n backslashes += 1\n b -= 1\n }\n return backslashes % 2 === 0\n}\n\n/** Scan backwards from `from` (inclusive) for the nearest UNescaped `\"`.\n * Returns its index, or -1 when none is found. */\nfunction prevUnescapedQuote(slice: string, from: number): number {\n for (let i = from; i >= 0; i -= 1) {\n if (slice[i] === '\"' && isUnescapedQuote(slice, i)) return i\n }\n return -1\n}\n\n/**\n * Best-effort: locate the JSON path for the substring at `offset` in\n * a single span's JSONL slice. The slice is '...,\"key\":\"value...\"' — we\n * walk back from `offset` to the value-opening quote, past the `:`, to\n * the key's closing then opening quote, skipping `\\\"`-escaped quotes that\n * live inside string values. Returns `null` when the offset doesn't fall\n * inside a recognisable string field.\n */\nfunction bestAttributePathForOffset(slice: string, offset: number): string | null {\n // Value-opening quote: nearest unescaped '\"' at or before the offset.\n const valueQuote = prevUnescapedQuote(slice, Math.min(offset, slice.length - 1))\n if (valueQuote < 1) return null\n // The ':' separating key and value sits before the value quote.\n let j = valueQuote - 1\n while (j >= 0 && slice[j] !== ':') j -= 1\n if (j < 1) return null\n // Key closing quote, then key opening quote — both unescaped.\n const keyClose = prevUnescapedQuote(slice, j - 1)\n if (keyClose < 1) return null\n const keyOpen = prevUnescapedQuote(slice, keyClose - 1)\n if (keyOpen < 0) return null\n return slice.slice(keyOpen + 1, keyClose)\n}\n\n// ─── Error-cluster extraction ────────────────────────────────────────\n//\n// Deterministic failure-coverage population. The error-span loop in\n// getOverview already visits every ERROR span; bucketing them by a\n// normalized status_message signature turns \"N error spans\" into \"K\n// distinct failure modes\" — the checklist an analyst must close. No LLM.\n\nconst ERROR_CLUSTER_EXEMPLARS = 5\n\ninterface ErrorClusterAccumulator {\n signature: string\n sample: string\n traceIds: Set<string>\n spanIds: string[]\n spanCount: number\n spanNames: Map<string, number>\n toolNames: Map<string, number>\n}\n\n/** Collapse volatile tokens so semantically identical failures share a key:\n * hex/uuid ids → <id>, numbers → #, quoted/abs paths → <path>, durations →\n * <dur>, whitespace collapsed. Empty/absent messages fall back to the span\n * name so a no-message error still forms a real cluster. */\nfunction normalizeErrorSignature(message: string | undefined, spanName: string): string {\n const raw = (message ?? '').trim()\n const base = raw.length > 0 ? raw : `(${spanName || 'error'} — no message)`\n const norm = base\n .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '<id>')\n .replace(/\\b[0-9a-f]{12,}\\b/gi, '<id>')\n .replace(/(?:\\/[\\w.\\-@]+){2,}/g, '<path>')\n .replace(/\\b\\d+(?:\\.\\d+)?(ms|s|m|h|kb|mb|gb)?\\b/gi, (_m, u) => (u ? `#${u}` : '#'))\n .replace(/\\s+/g, ' ')\n .trim()\n return norm\n}\n\nfunction bump(map: Map<string, number>, key: string | null): void {\n if (!key) return\n map.set(key, (map.get(key) ?? 0) + 1)\n}\n\nfunction topKey(map: Map<string, number>): string | null {\n let best: string | null = null\n let bestN = 0\n for (const [k, n] of map)\n if (n > bestN) {\n best = k\n bestN = n\n }\n return best\n}\n\nfunction accumulateErrorCluster(\n clusters: Map<string, ErrorClusterAccumulator>,\n traceId: string,\n span: SpanIndexEntry,\n): void {\n const signature = normalizeErrorSignature(span.status_message, span.name)\n let acc = clusters.get(signature)\n if (!acc) {\n acc = {\n signature,\n sample: span.status_message ?? span.name ?? '',\n traceIds: new Set(),\n spanIds: [],\n spanCount: 0,\n spanNames: new Map(),\n toolNames: new Map(),\n }\n clusters.set(signature, acc)\n }\n acc.traceIds.add(traceId)\n acc.spanCount += 1\n if (acc.spanIds.length < ERROR_CLUSTER_EXEMPLARS && !acc.spanIds.includes(span.span_id)) {\n acc.spanIds.push(span.span_id)\n }\n bump(acc.spanNames, span.name)\n bump(acc.toolNames, span.tool_name)\n}\n\nfunction finalizeErrorClusters(\n clusters: Map<string, ErrorClusterAccumulator>,\n errorTraceCount: number,\n): ErrorCluster[] {\n const out = [...clusters.values()].map(\n (acc): ErrorCluster => ({\n signature: acc.signature,\n status_message_sample: acc.sample,\n span_name: topKey(acc.spanNames),\n tool_name: topKey(acc.toolNames),\n trace_count: acc.traceIds.size,\n span_count: acc.spanCount,\n prevalence: errorTraceCount > 0 ? acc.traceIds.size / errorTraceCount : 0,\n exemplar_trace_ids: [...acc.traceIds].slice(0, ERROR_CLUSTER_EXEMPLARS),\n exemplar_span_ids: acc.spanIds.slice(0, ERROR_CLUSTER_EXEMPLARS),\n }),\n )\n out.sort((a, b) => b.trace_count - a.trace_count || b.span_count - a.span_count)\n return out\n}\n"],"mappings":"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"}
|
|
@@ -2,11 +2,11 @@ import { r as CaptureIntegrityError } from "./errors-DEE6u6ot.js";
|
|
|
2
2
|
import { c as CostLedgerHandle } from "./cost-ledger-DbQdN3nO.js";
|
|
3
3
|
import { S as ToolSpan } from "./schema-CR5cpjQ3.js";
|
|
4
4
|
import { u as RunTokenUsage } from "./run-record-DTv1MdjK.js";
|
|
5
|
-
import { A as
|
|
5
|
+
import { A as DatasetOverview, D as TraceAnalysisStore, G as ViewTraceResult, M as QueryTracesPage, N as SearchSpanResult, O as TraceAnalysisStoreContext, P as SearchTraceResult, R as TraceAnalystFilters, S as BoundedTraceAnalysisStoreOptions, T as SpanSourceReader, U as ViewSpansResult, f as AnalystUsageReceipt, i as AnalystFinding } from "./types-DzuaM493.js";
|
|
6
6
|
import { K as ProviderRedactor, Y as RawProviderSink } from "./types-gvRsyJLh.js";
|
|
7
7
|
import { s as TraceStore } from "./store-BErPvYBr.js";
|
|
8
|
-
import { a as TraceAnalystLimits, i as TraceAnalysisEngineResult, n as TraceAnalysisEngine } from "./engine-
|
|
9
|
-
import { t as TraceToolGroupName } from "./tool-groups-
|
|
8
|
+
import { a as TraceAnalystLimits, i as TraceAnalysisEngineResult, n as TraceAnalysisEngine } from "./engine-CX8ReXkn.js";
|
|
9
|
+
import { t as TraceToolGroupName } from "./tool-groups-2QA0S7dK.js";
|
|
10
10
|
//#region src/trace-analyst/store-boundary.d.ts
|
|
11
11
|
/** Apply the public validation, cancellation, not-found, and size rules to any adapter. */
|
|
12
12
|
declare function createBoundedTraceAnalysisStore(source: TraceAnalysisStore, options?: BoundedTraceAnalysisStoreOptions): TraceAnalysisStore;
|
|
@@ -303,6 +303,8 @@ declare function buildTraceInsightPrompt(input: TraceInsightPromptInput): string
|
|
|
303
303
|
//#endregion
|
|
304
304
|
//#region src/trace-analyst/store-otlp.d.ts
|
|
305
305
|
interface ToolSpansToTraceAnalysisStoreOptions {
|
|
306
|
+
/** Authorized original-record lookup, exposed only when supplied. */
|
|
307
|
+
sourceReader?: SpanSourceReader;
|
|
306
308
|
/** Override the discovery (`viewTrace`) per-attribute byte cap. */
|
|
307
309
|
perAttributeViewBudget?: number;
|
|
308
310
|
/** Override the surgical (`viewSpans`) per-attribute byte cap. */
|
|
@@ -326,6 +328,7 @@ interface OtlpFileTraceStoreOptions extends BufferedOtlpTraceStoreOptions {
|
|
|
326
328
|
maxFileBytes?: number;
|
|
327
329
|
}
|
|
328
330
|
declare abstract class BufferedOtlpTraceStore implements TraceAnalysisStore {
|
|
331
|
+
readonly readSpanSource?: SpanSourceReader;
|
|
329
332
|
private readonly perAttributeViewBudget;
|
|
330
333
|
private readonly perAttributeSpanBudget;
|
|
331
334
|
private readonly perCallByteCeiling;
|
|
@@ -405,4 +408,4 @@ declare class ToolTraceMissingError extends CaptureIntegrityError {
|
|
|
405
408
|
declare function toolSpansToTraceAnalysisStore(spans: readonly ToolSpan[] | null | undefined, options?: ToolSpansToTraceAnalysisStoreOptions): TraceAnalysisStore;
|
|
406
409
|
//#endregion
|
|
407
410
|
export { REDACTION_VERSION as A, exportRunAsOtlp as B, scoreTraceInsightReadiness as C, AnalyzeTracesResult as D, AnalyzeTracesOptions as E, OtlpFlatLine as F, ExtractedUsage as G, CaptureFetchOptions as H, OTEL_AGENT_EVAL_SCOPE as I, extractUsageFromResponse as J, SseUsageMode as K, OtlpExport as L, RedactionRule as M, redactString as N, analyzeTraces as O, redactValue as P, OtlpResourceSpans as R, planTraceInsightQuestions as S, AnalyzeTracesInput as T, captureFetchToRawSink as U, CaptureFetchContext as V, ExtractUsageFromSseOptions as W, createBoundedTraceAnalysisStore as X, extractUsageFromSse as Y, buildTraceInsightPrompt as _, ToolSpansToTraceAnalysisStoreOptions as a, domainEvidencePattern as b, TraceInsightFinding as c, TraceInsightQualityGate as d, TraceInsightQuestion as f, buildTraceInsightContext as g, TraceInsightTask as h, OtlpFileTraceStoreOptions as i, RedactionReport as j, DEFAULT_REDACTION_RULES as k, TraceInsightPanelRole as l, TraceInsightSuite as m, toolSpansToTraceAnalysisStore as n, otlpTextToTraceAnalysisStore as o, TraceInsightReadiness as p, extractUsage as q, OtlpFileTraceStore as r, TraceInsightContext as s, ToolTraceMissingError as t, TraceInsightPromptInput as u, defaultTraceInsightPanel as v, tokenizeDomainWords as w, inferDomainKeywords as x, describeTraceInsightScope as y, OtlpSpan as z };
|
|
408
|
-
//# sourceMappingURL=store-tool-spans-
|
|
411
|
+
//# sourceMappingURL=store-tool-spans-4J1EDElP.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-tool-spans-
|
|
1
|
+
{"version":3,"file":"store-tool-spans-4J1EDElP.d.ts","names":[],"sources":["../src/trace-analyst/store-boundary.ts","../src/trace/extract-usage.ts","../src/trace/capture-fetch.ts","../src/trace/otel.ts","../src/trace/otlp-flat.ts","../src/trace/redact.ts","../src/trace-analyst/analyst.ts","../src/trace-analyst/insights.ts","../src/trace-analyst/store-otlp.ts","../src/trace-analyst/store-tool-spans.ts"],"mappings":"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"}
|