@tangle-network/agent-eval 0.140.1 → 0.141.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/dist/analyst/index.d.ts +74 -6
- package/dist/analyst/index.d.ts.map +1 -1
- package/dist/analyst/index.js +6 -6
- package/dist/{benchmark-command-Bo_hkhQf.js → benchmark-command-D8xXNVVh.js} +2239 -1820
- package/dist/benchmark-command-D8xXNVVh.js.map +1 -0
- package/dist/benchmarks/index.js +1 -1
- package/dist/{benchmarks-HwoBE32G.js → benchmarks-Ce8GdJbc.js} +4 -4
- package/dist/{benchmarks-HwoBE32G.js.map → benchmarks-Ce8GdJbc.js.map} +1 -1
- package/dist/campaign/index.js +3 -3
- package/dist/{campaign-BzjYNYVZ.js → campaign-COFTVy3Q.js} +3 -3
- package/dist/{campaign-BzjYNYVZ.js.map → campaign-COFTVy3Q.js.map} +1 -1
- package/dist/cli.js +1 -1
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +56 -13
- package/dist/contract/index.js.map +1 -1
- package/dist/{default-registry-BOiBXNFh.js → default-registry-BupFSXSN.js} +108 -20
- package/dist/default-registry-BupFSXSN.js.map +1 -0
- package/dist/default-registry-Ci7wAAR8.d.ts.map +1 -1
- package/dist/{dspy-rlm-engine-Bkak4nzo.js → dspy-rlm-engine-Bw8Zz9CX.js} +7 -4
- package/dist/{dspy-rlm-engine-Bkak4nzo.js.map → dspy-rlm-engine-Bw8Zz9CX.js.map} +1 -1
- package/dist/{extract-usage-C5vMw-0R.js → extract-usage-7l1Xq5ti.js} +2 -2
- package/dist/{extract-usage-C5vMw-0R.js.map → extract-usage-7l1Xq5ti.js.map} +1 -1
- package/dist/index.d.ts +68 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -46
- package/dist/index.js.map +1 -1
- package/dist/{kind-factory-DB7nIs35.js → kind-factory-Bvwe3pup.js} +11 -1
- package/dist/kind-factory-Bvwe3pup.js.map +1 -0
- package/dist/multishot/index.d.ts +29 -6
- package/dist/multishot/index.d.ts.map +1 -1
- package/dist/multishot/index.js +53 -3
- package/dist/multishot/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/replay-BqTgoioO.d.ts.map +1 -1
- package/dist/{replay-k2MsOmv5.js → replay-DjUfTrHD.js} +40 -48
- package/dist/replay-DjUfTrHD.js.map +1 -0
- package/dist/{single-run-lock-CiQThJxB.js → single-run-lock-BcvPQY57.js} +65 -15
- package/dist/single-run-lock-BcvPQY57.js.map +1 -0
- package/dist/{skill-usage-CVVnoIx-.d.ts → skill-usage-CNZTk_LT.d.ts} +8 -4
- package/dist/{skill-usage-CVVnoIx-.d.ts.map → skill-usage-CNZTk_LT.d.ts.map} +1 -1
- package/dist/{skillopt-optimization-method-CSBQ8Qma.js → skillopt-optimization-method-DV6c4ooy.js} +2 -2
- package/dist/{skillopt-optimization-method-CSBQ8Qma.js.map → skillopt-optimization-method-DV6c4ooy.js.map} +1 -1
- package/dist/{store-otlp-vRByAR6h.js → store-otlp-D4I90_vR.js} +2 -2
- package/dist/{store-otlp-vRByAR6h.js.map → store-otlp-D4I90_vR.js.map} +1 -1
- package/dist/traces.js +4 -4
- package/docs/adapters-observability.md +35 -21
- package/docs/concepts.md +1 -0
- package/docs/distributed-driver.md +7 -3
- package/docs/feature-guide.md +1 -0
- package/docs/insight-report.md +1 -1
- package/docs/trace-analysis.md +11 -0
- package/docs/wire-protocol.md +70 -2
- package/package.json +5 -3
- package/dist/benchmark-command-Bo_hkhQf.js.map +0 -1
- package/dist/default-registry-BOiBXNFh.js.map +0 -1
- package/dist/kind-factory-DB7nIs35.js.map +0 -1
- package/dist/replay-k2MsOmv5.js.map +0 -1
- package/dist/single-run-lock-CiQThJxB.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dspy-rlm-engine-Bkak4nzo.js","names":["isRecord"],"sources":["../src/analyst/trace-tool-callback.ts","../src/analyst/dspy-rlm-engine.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto'\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http'\nimport { closeServer, listenLocal, sendJson } from '../campaign/external-optimizer-http'\nimport type { TraceAnalysisToolDescriptor } from '../trace-analyst/tools'\n\nconst MAX_REQUEST_BYTES = 1_000_000\nconst MAX_RESPONSE_BYTES = 4_000_000\n\nexport interface TraceToolCallback {\n url: string\n token: string\n calls: () => number\n close: () => Promise<void>\n}\n\n/** Expose one bounded trace-tool set only on an authenticated loopback socket. */\nexport async function startTraceToolCallback(args: {\n tools: readonly TraceAnalysisToolDescriptor[]\n maxCalls: number\n signal?: AbortSignal\n}): Promise<TraceToolCallback> {\n if (!Number.isSafeInteger(args.maxCalls) || args.maxCalls <= 0) {\n throw new TypeError('trace tool callback maxCalls must be a positive safe integer')\n }\n args.signal?.throwIfAborted()\n const byName = new Map(args.tools.map((tool) => [tool.name, tool]))\n if (byName.size !== args.tools.length) {\n throw new Error('trace tool callback received duplicate tool names')\n }\n\n const token = randomBytes(32).toString('hex')\n let calls = 0\n let accepting = true\n let closePromise: Promise<void> | undefined\n const activeControllers = new Set<AbortController>()\n const activeHandlers = new Set<Promise<void>>()\n const server = createServer((request, response) => {\n if (!accepting) {\n sendJsonIfOpen(response, 503, { error: 'trace tool callback is closing' })\n return\n }\n const controller = new AbortController()\n const abortRequest = (): void => {\n request.destroy()\n response.destroy()\n }\n activeControllers.add(controller)\n controller.signal.addEventListener('abort', abortRequest, { once: true })\n\n let handler!: Promise<void>\n handler = handleRequest(request, response, controller.signal).finally(() => {\n controller.signal.removeEventListener('abort', abortRequest)\n activeControllers.delete(controller)\n activeHandlers.delete(handler)\n })\n activeHandlers.add(handler)\n void handler.catch(() => undefined)\n })\n const port = await listenLocal(server)\n const close = (): Promise<void> => {\n closePromise ??= closeCallback()\n return closePromise\n }\n const onAbort = (): void => {\n void close().catch(() => undefined)\n }\n args.signal?.addEventListener('abort', onAbort, { once: true })\n if (args.signal?.aborted) onAbort()\n\n return {\n url: `http://127.0.0.1:${port}/call`,\n token,\n calls: () => calls,\n close,\n }\n\n async function handleRequest(\n request: IncomingMessage,\n response: ServerResponse,\n signal: AbortSignal,\n ): Promise<void> {\n try {\n if (request.method !== 'POST' || request.url !== '/call') {\n sendJsonIfOpen(response, 404, { error: 'not found' })\n return\n }\n if (request.headers.authorization !== `Bearer ${token}`) {\n sendJsonIfOpen(response, 401, { error: 'unauthorized' })\n return\n }\n if (calls >= args.maxCalls) {\n sendJsonIfOpen(response, 429, { error: 'trace tool call limit reached' })\n return\n }\n const body = await readJson(request)\n if (!isRecord(body) || typeof body.name !== 'string' || !('args' in body)) {\n sendJsonIfOpen(response, 400, { error: 'name and args are required' })\n return\n }\n const tool = byName.get(body.name)\n if (!tool) {\n sendJsonIfOpen(response, 404, { error: `unknown trace tool '${body.name}'` })\n return\n }\n calls += 1\n const result = await tool.handler(body.args, { signal })\n const encoded = JSON.stringify({ result })\n if (Buffer.byteLength(encoded) > MAX_RESPONSE_BYTES) {\n sendJsonIfOpen(response, 413, { error: 'trace tool response too large' })\n return\n }\n response.writeHead(200, {\n 'content-type': 'application/json; charset=utf-8',\n 'content-length': String(Buffer.byteLength(encoded)),\n })\n response.end(encoded)\n } catch (error) {\n sendJsonIfOpen(response, signal.aborted ? 499 : 400, {\n error: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n async function closeCallback(): Promise<void> {\n args.signal?.removeEventListener('abort', onAbort)\n accepting = false\n const closingServer = closeServer(server)\n server.closeIdleConnections?.()\n for (const controller of activeControllers) controller.abort()\n const [serverResult] = await Promise.allSettled([\n closingServer,\n waitForActiveHandlers(activeHandlers),\n ])\n if (activeControllers.size !== 0 || activeHandlers.size !== 0) {\n throw new Error('trace tool callback closed with active requests')\n }\n if (serverResult?.status === 'rejected') throw serverResult.reason\n }\n}\n\nasync function waitForActiveHandlers(activeHandlers: Set<Promise<void>>): Promise<void> {\n while (activeHandlers.size > 0) {\n await Promise.allSettled([...activeHandlers])\n }\n}\n\nfunction readJson(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let size = 0\n const chunks: Buffer[] = []\n request.on('data', (chunk: Buffer) => {\n size += chunk.length\n if (size > MAX_REQUEST_BYTES) {\n reject(new Error('trace tool request too large'))\n request.destroy()\n return\n }\n chunks.push(chunk)\n })\n request.on('error', reject)\n request.on('end', () => {\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')))\n } catch (error) {\n reject(error)\n }\n })\n })\n}\n\nfunction sendJsonIfOpen(response: ServerResponse, status: number, body: unknown): void {\n if (response.destroyed || response.writableEnded) return\n sendJson(response, status, body)\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import {\n type ExternalOptimizerModelProxy,\n type ExternalOptimizerRunnerCommand,\n removeCredentialEnvironment,\n} from '../campaign/external-optimizer-contracts'\nimport { startExternalOptimizerModelProxy } from '../campaign/external-optimizer-model-proxy'\nimport { runWithCleanup } from '../campaign/external-optimizer-resources'\nimport { runExternalOptimizerProcess } from '../campaign/external-optimizer-subprocess'\nimport type { CustomTokenPricing } from '../cost-ledger'\nimport { resolveModelPricing } from '../metrics'\nimport type { TraceAnalysisEngine, TraceAnalysisEngineResult } from './engine'\nimport { type RawAnalystFinding, RawAnalystFindingSchema } from './finding-signature'\nimport { startTraceToolCallback } from './trace-tool-callback'\n\nconst DEFAULT_TIMEOUT_MS = 10 * 60_000\n// 4096 is below what current coding models emit for a full findings array:\n// glm-5.2 through an OpenAI-compatible gateway returns 8192 and the request is\n// rejected outright (`502 — provider reported 8192 completion tokens,\n// exceeding requested limit 4096`), so the default failed 2/2 smoke cases\n// before any analysis ran. The cap exists to bound spend, and `maxCostUsd`\n// already does that directly, so it starts above what a real completion needs.\nconst DEFAULT_MODEL_OUTPUT_TOKENS = 16_384\nconst DEFAULT_MAX_COST_USD = 1\nconst MAX_MODEL_REQUEST_BYTES = 16 * 1024 * 1024\nconst MAX_MODEL_RESPONSE_BYTES = 4 * 1024 * 1024\nconst BRIDGE_MODULE = 'agent_eval_rpc.dspy_rlm_bridge'\n/** Bumped whenever this engine's execution behavior changes. */\nconst DSPY_RLM_ENGINE_VERSION = '1.0.0'\n\nexport interface DspyRlmTraceEngineOptions {\n baseUrl: string\n apiKey: string\n model: string\n /** Exact provider rates. Required when the model is absent from the pricing table. */\n pricing?: CustomTokenPricing\n /** Maximum provider spend for one investigation. Default: 1 USD. */\n maxCostUsd?: number\n /** Controller response cap. Default: 16384. */\n maxOutputTokens?: number\n /**\n * Thinking tokens one controller turn may bill on top of its completion.\n * A reasoning model bills these beyond `maxOutputTokens`, so the cost\n * reservation must cover them. Default: four times the completion cap.\n */\n maxReasoningTokens?: number\n /**\n * How the controller's reasoning and code fields are obtained.\n *\n * `tolerant` parses marker output strictly first, then recovers the fields\n * deterministically from prose plus a fenced code block — the shape coding\n * models naturally emit — at no extra model cost. `two-step` extracts with a\n * second call per turn. `chat` accepts marker output only. Default:\n * `tolerant`.\n */\n controlAdapter?: 'chat' | 'two-step' | 'tolerant'\n /** Python command used to load agent-eval-rpc[dspy]. Default: python. */\n runner?: ExternalOptimizerRunnerCommand\n /** Whole investigation deadline. Default: 10 minutes. */\n timeoutMs?: number\n}\n\n/** Use the official DSPy RLM as a bounded recursive trace-analysis engine. */\nexport function createDspyRlmTraceEngine(options: DspyRlmTraceEngineOptions): TraceAnalysisEngine {\n assertOptions(options)\n const maxOutputTokens = options.maxOutputTokens ?? DEFAULT_MODEL_OUTPUT_TOKENS\n if (!Number.isSafeInteger(maxOutputTokens) || maxOutputTokens <= 0) {\n throw new TypeError('DSPy RLM maxOutputTokens must be a positive safe integer')\n }\n const controlAdapter = options.controlAdapter ?? 'tolerant'\n const maxReasoningTokens = options.maxReasoningTokens ?? maxOutputTokens * 4\n if (!Number.isSafeInteger(maxReasoningTokens) || maxReasoningTokens < 0) {\n throw new TypeError('DSPy RLM maxReasoningTokens must be a non-negative safe integer')\n }\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) {\n throw new TypeError('DSPy RLM timeoutMs must be a positive safe integer')\n }\n const maxCostUsd = options.maxCostUsd ?? DEFAULT_MAX_COST_USD\n if (!Number.isFinite(maxCostUsd) || maxCostUsd <= 0) {\n throw new TypeError('DSPy RLM maxCostUsd must be positive and finite')\n }\n const pricing = options.pricing ?? pricingForModel(options.model)\n\n const runner = sanitizedRunner(options.runner)\n return {\n id: 'dspy-rlm',\n description: 'Official DSPy RLM with bounded trace tools and metered model calls.',\n model: options.model,\n version: DSPY_RLM_ENGINE_VERSION,\n executionConfig: {\n bridge_module: BRIDGE_MODULE,\n base_url: options.baseUrl,\n model: options.model,\n api_key_provided: true,\n pricing: { ...pricing },\n max_cost_usd: maxCostUsd,\n max_output_tokens: maxOutputTokens,\n max_reasoning_tokens: maxReasoningTokens,\n control_adapter: controlAdapter,\n timeout_ms: timeoutMs,\n max_request_bytes: MAX_MODEL_REQUEST_BYTES,\n max_response_bytes: MAX_MODEL_RESPONSE_BYTES,\n runner: runner ? 'caller-supplied' : 'default',\n runner_command: runner?.command ?? null,\n },\n async analyze(request) {\n const callback = await startTraceToolCallback({\n tools: request.tools,\n maxCalls: request.limits.maxToolCalls,\n ...(request.signal ? { signal: request.signal } : {}),\n })\n let modelProxy: ExternalOptimizerModelProxy | undefined\n const result = await runWithCleanup({\n label: 'DSPy RLM trace-analysis resources',\n run: async () => {\n modelProxy = await startExternalOptimizerModelProxy({\n upstreamBaseUrl: options.baseUrl,\n upstreamApiKey: options.apiKey,\n model: options.model,\n budget: {\n maxCostUsd,\n maxRequests: request.limits.maxIterations + request.limits.maxLlmCalls + 1,\n maxRequestBytes: MAX_MODEL_REQUEST_BYTES,\n maxResponseBytes: MAX_MODEL_RESPONSE_BYTES,\n maxOutputTokensPerRequest: maxOutputTokens,\n maxReasoningTokensPerRequest: maxReasoningTokens,\n requestTimeoutMs: timeoutMs,\n pricing,\n },\n costLedger: request.costLedger,\n channel: 'analyst',\n phase: request.costPhase,\n actor: request.analystId,\n ...(request.costTags ? { tags: request.costTags } : {}),\n ...(request.signal ? { signal: request.signal } : {}),\n })\n request.log?.('trace analyst engine started', {\n engine: 'dspy-rlm',\n model: options.model,\n tools: request.tools.map((tool) => tool.name),\n limits: request.limits,\n })\n const raw = await runExternalOptimizerProcess<unknown>({\n label: 'DSPy RLM trace analysis',\n tempPrefix: 'agent-eval-dspy-rlm-',\n module: BRIDGE_MODULE,\n input: {\n operation: 'analyze',\n question: request.question,\n instructions: request.instructions,\n modelProxy: {\n baseUrl: modelProxy.baseUrl,\n apiKey: modelProxy.apiKey,\n model: options.model,\n maxOutputTokens,\n },\n toolCallback: {\n url: callback.url,\n token: callback.token,\n },\n toolSpecs: request.tools.map(({ name, description, parameters }) => ({\n name,\n description,\n parameters,\n })),\n controlAdapter,\n limits: {\n maxIterations: request.limits.maxIterations,\n maxLlmCalls: request.limits.maxLlmCalls,\n maxOutputChars: request.limits.maxOutputChars,\n },\n },\n ...(runner ? { runner } : {}),\n timeoutMs,\n ...(request.signal ? { signal: request.signal } : {}),\n })\n const parsed = parseBridgeOutput(raw, (index, reason) => {\n request.log?.('finding rejected: bridge row failed schema validation', {\n engine: 'dspy-rlm',\n index,\n reason,\n })\n })\n const successfulCompletions = modelProxy.successfulCompletions()\n const requestAttempts = modelProxy.requestAttempts()\n if (parsed.modelCalls !== successfulCompletions) {\n throw new Error(\n `DSPy RLM reported ${parsed.modelCalls} model calls, but the provider proxy recorded ${successfulCompletions}`,\n )\n }\n return {\n ...parsed,\n toolCalls: callback.calls(),\n runtime: {\n ...parsed.runtime,\n modelRequestAttempts: requestAttempts,\n modelSuccessfulCompletions: successfulCompletions,\n },\n } satisfies TraceAnalysisEngineResult\n },\n cleanup: async () => {\n const results = await Promise.allSettled([\n ...(modelProxy ? [modelProxy.close()] : []),\n callback.close(),\n ])\n const errors = results.flatMap((entry) =>\n entry.status === 'rejected' ? [entry.reason] : [],\n )\n if (errors.length > 0) {\n throw new AggregateError(errors, 'DSPy RLM resource cleanup failed')\n }\n },\n })\n request.log?.('trace analyst engine completed', {\n engine: 'dspy-rlm',\n model_calls: result.modelCalls,\n model_request_attempts: result.runtime.modelRequestAttempts,\n tool_calls: result.toolCalls,\n findings: result.findings.length,\n })\n return result\n },\n }\n}\n\nfunction parseBridgeOutput(\n value: unknown,\n onRejectedFinding: (index: number, reason: string) => void,\n): Omit<TraceAnalysisEngineResult, 'toolCalls'> {\n if (!isRecord(value)) throw new Error('DSPy RLM bridge output must be an object')\n if (typeof value.answer !== 'string' || !value.answer.trim()) {\n throw new Error('DSPy RLM bridge returned no answer')\n }\n if (!Array.isArray(value.findings)) {\n throw new Error('DSPy RLM bridge findings must be an array')\n }\n // Findings are model output: one malformed row is model noise, not a bridge\n // fault, and the rest of the paid investigation must survive it. Rejected\n // rows are logged per row and counted in runtime.rejectedFindings.\n let rejectedFindings = 0\n const findings: RawAnalystFinding[] = []\n value.findings.forEach((finding, index) => {\n const parsed = RawAnalystFindingSchema.safeParse(finding)\n if (!parsed.success) {\n rejectedFindings += 1\n onRejectedFinding(\n index,\n parsed.error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`).join('; '),\n )\n return\n }\n findings.push(parsed.data)\n })\n if (!Array.isArray(value.trajectory)) {\n throw new Error('DSPy RLM bridge trajectory must be an array')\n }\n if (!Number.isSafeInteger(value.modelCalls) || (value.modelCalls as number) <= 0) {\n throw new Error('DSPy RLM bridge modelCalls must be a positive safe integer')\n }\n if (!isRecord(value.runtime)) {\n throw new Error('DSPy RLM bridge runtime must be an object')\n }\n return {\n answer: value.answer,\n findings,\n trajectory: value.trajectory,\n modelCalls: value.modelCalls as number,\n runtime: { ...value.runtime, rejectedFindings },\n }\n}\n\nfunction assertOptions(options: DspyRlmTraceEngineOptions): void {\n for (const [name, value] of [\n ['baseUrl', options.baseUrl],\n ['apiKey', options.apiKey],\n ['model', options.model],\n ] as const) {\n if (typeof value !== 'string' || !value.trim()) {\n throw new TypeError(`DSPy RLM ${name} must be a non-empty string`)\n }\n }\n}\n\nfunction pricingForModel(model: string): CustomTokenPricing {\n const pricing = resolveModelPricing(model)\n if (!pricing) {\n throw new Error(\n `no pricing is configured for '${model}'; provide DspyRlmTraceEngineOptions.pricing`,\n )\n }\n return {\n inputUsdPerMillion: pricing.input * 1_000,\n outputUsdPerMillion: pricing.output * 1_000,\n }\n}\n\nfunction sanitizedRunner(\n runner: ExternalOptimizerRunnerCommand | undefined,\n): ExternalOptimizerRunnerCommand | undefined {\n if (!runner) return undefined\n return {\n ...(runner.command ? { command: runner.command } : {}),\n ...(runner.args ? { args: runner.args } : {}),\n ...(runner.env ? { env: removeCredentialEnvironment(runner.env) } : {}),\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dspy-rlm-engine-Bw8Zz9CX.js","names":["isRecord"],"sources":["../src/analyst/trace-tool-callback.ts","../src/analyst/dspy-rlm-engine.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto'\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http'\nimport { closeServer, listenLocal, sendJson } from '../campaign/external-optimizer-http'\nimport type { TraceAnalysisToolDescriptor } from '../trace-analyst/tools'\n\nconst MAX_REQUEST_BYTES = 1_000_000\nconst MAX_RESPONSE_BYTES = 4_000_000\n\nexport interface TraceToolCallback {\n url: string\n token: string\n calls: () => number\n close: () => Promise<void>\n}\n\n/** Expose one bounded trace-tool set only on an authenticated loopback socket. */\nexport async function startTraceToolCallback(args: {\n tools: readonly TraceAnalysisToolDescriptor[]\n maxCalls: number\n signal?: AbortSignal\n}): Promise<TraceToolCallback> {\n if (!Number.isSafeInteger(args.maxCalls) || args.maxCalls <= 0) {\n throw new TypeError('trace tool callback maxCalls must be a positive safe integer')\n }\n args.signal?.throwIfAborted()\n const byName = new Map(args.tools.map((tool) => [tool.name, tool]))\n if (byName.size !== args.tools.length) {\n throw new Error('trace tool callback received duplicate tool names')\n }\n\n const token = randomBytes(32).toString('hex')\n let calls = 0\n let accepting = true\n let closePromise: Promise<void> | undefined\n const activeControllers = new Set<AbortController>()\n const activeHandlers = new Set<Promise<void>>()\n const server = createServer((request, response) => {\n if (!accepting) {\n sendJsonIfOpen(response, 503, { error: 'trace tool callback is closing' })\n return\n }\n const controller = new AbortController()\n const abortRequest = (): void => {\n request.destroy()\n response.destroy()\n }\n activeControllers.add(controller)\n controller.signal.addEventListener('abort', abortRequest, { once: true })\n\n let handler!: Promise<void>\n handler = handleRequest(request, response, controller.signal).finally(() => {\n controller.signal.removeEventListener('abort', abortRequest)\n activeControllers.delete(controller)\n activeHandlers.delete(handler)\n })\n activeHandlers.add(handler)\n void handler.catch(() => undefined)\n })\n const port = await listenLocal(server)\n const close = (): Promise<void> => {\n closePromise ??= closeCallback()\n return closePromise\n }\n const onAbort = (): void => {\n void close().catch(() => undefined)\n }\n args.signal?.addEventListener('abort', onAbort, { once: true })\n if (args.signal?.aborted) onAbort()\n\n return {\n url: `http://127.0.0.1:${port}/call`,\n token,\n calls: () => calls,\n close,\n }\n\n async function handleRequest(\n request: IncomingMessage,\n response: ServerResponse,\n signal: AbortSignal,\n ): Promise<void> {\n try {\n if (request.method !== 'POST' || request.url !== '/call') {\n sendJsonIfOpen(response, 404, { error: 'not found' })\n return\n }\n if (request.headers.authorization !== `Bearer ${token}`) {\n sendJsonIfOpen(response, 401, { error: 'unauthorized' })\n return\n }\n if (calls >= args.maxCalls) {\n sendJsonIfOpen(response, 429, { error: 'trace tool call limit reached' })\n return\n }\n const body = await readJson(request)\n if (!isRecord(body) || typeof body.name !== 'string' || !('args' in body)) {\n sendJsonIfOpen(response, 400, { error: 'name and args are required' })\n return\n }\n const tool = byName.get(body.name)\n if (!tool) {\n sendJsonIfOpen(response, 404, { error: `unknown trace tool '${body.name}'` })\n return\n }\n calls += 1\n const result = await tool.handler(body.args, { signal })\n const encoded = JSON.stringify({ result })\n if (Buffer.byteLength(encoded) > MAX_RESPONSE_BYTES) {\n sendJsonIfOpen(response, 413, { error: 'trace tool response too large' })\n return\n }\n response.writeHead(200, {\n 'content-type': 'application/json; charset=utf-8',\n 'content-length': String(Buffer.byteLength(encoded)),\n })\n response.end(encoded)\n } catch (error) {\n sendJsonIfOpen(response, signal.aborted ? 499 : 400, {\n error: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n async function closeCallback(): Promise<void> {\n args.signal?.removeEventListener('abort', onAbort)\n accepting = false\n const closingServer = closeServer(server)\n server.closeIdleConnections?.()\n for (const controller of activeControllers) controller.abort()\n const [serverResult] = await Promise.allSettled([\n closingServer,\n waitForActiveHandlers(activeHandlers),\n ])\n if (activeControllers.size !== 0 || activeHandlers.size !== 0) {\n throw new Error('trace tool callback closed with active requests')\n }\n if (serverResult?.status === 'rejected') throw serverResult.reason\n }\n}\n\nasync function waitForActiveHandlers(activeHandlers: Set<Promise<void>>): Promise<void> {\n while (activeHandlers.size > 0) {\n await Promise.allSettled([...activeHandlers])\n }\n}\n\nfunction readJson(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let size = 0\n const chunks: Buffer[] = []\n request.on('data', (chunk: Buffer) => {\n size += chunk.length\n if (size > MAX_REQUEST_BYTES) {\n reject(new Error('trace tool request too large'))\n request.destroy()\n return\n }\n chunks.push(chunk)\n })\n request.on('error', reject)\n request.on('end', () => {\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')))\n } catch (error) {\n reject(error)\n }\n })\n })\n}\n\nfunction sendJsonIfOpen(response: ServerResponse, status: number, body: unknown): void {\n if (response.destroyed || response.writableEnded) return\n sendJson(response, status, body)\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import {\n type ExternalOptimizerModelProxy,\n type ExternalOptimizerRunnerCommand,\n removeCredentialEnvironment,\n} from '../campaign/external-optimizer-contracts'\nimport { startExternalOptimizerModelProxy } from '../campaign/external-optimizer-model-proxy'\nimport { runWithCleanup } from '../campaign/external-optimizer-resources'\nimport { runExternalOptimizerProcess } from '../campaign/external-optimizer-subprocess'\nimport type { CustomTokenPricing } from '../cost-ledger'\nimport { resolveModelPricing } from '../metrics'\nimport type { TraceAnalysisEngine, TraceAnalysisEngineResult } from './engine'\nimport { type RawAnalystFinding, RawAnalystFindingSchema } from './finding-signature'\nimport { startTraceToolCallback } from './trace-tool-callback'\n\nconst DEFAULT_TIMEOUT_MS = 10 * 60_000\n// 4096 is below what current coding models emit for a full findings array:\n// glm-5.2 through an OpenAI-compatible gateway returns 8192 and the request is\n// rejected outright (`502 — provider reported 8192 completion tokens,\n// exceeding requested limit 4096`), so the default failed 2/2 smoke cases\n// before any analysis ran. The cap exists to bound spend, and `maxCostUsd`\n// already does that directly, so it starts above what a real completion needs.\nconst DEFAULT_MODEL_OUTPUT_TOKENS = 16_384\nconst DEFAULT_MAX_COST_USD = 1\nconst MAX_MODEL_REQUEST_BYTES = 16 * 1024 * 1024\nconst MAX_MODEL_RESPONSE_BYTES = 4 * 1024 * 1024\nconst BRIDGE_MODULE = 'agent_eval_rpc.dspy_rlm_bridge'\n/** Bumped whenever this engine's execution behavior changes. */\nconst DSPY_RLM_ENGINE_VERSION = '1.0.0'\n\nexport interface DspyRlmTraceEngineOptions {\n baseUrl: string\n apiKey: string\n model: string\n /** Exact provider rates. Required when the model is absent from the pricing table. */\n pricing?: CustomTokenPricing\n /** Maximum provider spend for one investigation. Default: 1 USD. */\n maxCostUsd?: number\n /** Controller response cap. Default: 16384. */\n maxOutputTokens?: number\n /**\n * Thinking tokens one controller turn may bill on top of its completion.\n * A reasoning model bills these beyond `maxOutputTokens`, so the cost\n * reservation must cover them. Default: four times the completion cap.\n */\n maxReasoningTokens?: number\n /**\n * How the controller's reasoning and code fields are obtained.\n *\n * `tolerant` parses marker output strictly first, then recovers the fields\n * deterministically from prose plus a fenced code block — the shape coding\n * models naturally emit — at no extra model cost. `two-step` extracts with a\n * second call per turn. `chat` accepts marker output only. Default:\n * `tolerant`.\n */\n controlAdapter?: 'chat' | 'two-step' | 'tolerant'\n /** Python command used to load agent-eval-rpc[dspy]. Default: python. */\n runner?: ExternalOptimizerRunnerCommand\n /** Whole investigation deadline. Default: 10 minutes. */\n timeoutMs?: number\n}\n\n/** Use the official DSPy RLM as a bounded recursive trace-analysis engine. */\nexport function createDspyRlmTraceEngine(options: DspyRlmTraceEngineOptions): TraceAnalysisEngine {\n assertOptions(options)\n const maxOutputTokens = options.maxOutputTokens ?? DEFAULT_MODEL_OUTPUT_TOKENS\n if (!Number.isSafeInteger(maxOutputTokens) || maxOutputTokens <= 0) {\n throw new TypeError('DSPy RLM maxOutputTokens must be a positive safe integer')\n }\n const controlAdapter = options.controlAdapter ?? 'tolerant'\n const maxReasoningTokens = options.maxReasoningTokens ?? maxOutputTokens * 4\n if (!Number.isSafeInteger(maxReasoningTokens) || maxReasoningTokens < 0) {\n throw new TypeError('DSPy RLM maxReasoningTokens must be a non-negative safe integer')\n }\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) {\n throw new TypeError('DSPy RLM timeoutMs must be a positive safe integer')\n }\n const maxCostUsd = options.maxCostUsd ?? DEFAULT_MAX_COST_USD\n if (!Number.isFinite(maxCostUsd) || maxCostUsd <= 0) {\n throw new TypeError('DSPy RLM maxCostUsd must be positive and finite')\n }\n const pricing = options.pricing ?? pricingForModel(options.model)\n\n const runner = sanitizedRunner(options.runner)\n return {\n id: 'dspy-rlm',\n description: 'Official DSPy RLM with bounded trace tools and metered model calls.',\n model: options.model,\n version: DSPY_RLM_ENGINE_VERSION,\n executionConfig: {\n bridge_module: BRIDGE_MODULE,\n base_url: options.baseUrl,\n model: options.model,\n api_key_provided: true,\n pricing: { ...pricing },\n max_cost_usd: maxCostUsd,\n max_output_tokens: maxOutputTokens,\n max_reasoning_tokens: maxReasoningTokens,\n control_adapter: controlAdapter,\n timeout_ms: timeoutMs,\n max_request_bytes: MAX_MODEL_REQUEST_BYTES,\n max_response_bytes: MAX_MODEL_RESPONSE_BYTES,\n runner: runner ? 'caller-supplied' : 'default',\n runner_command: runner?.command ?? null,\n },\n async analyze(request) {\n const callback = await startTraceToolCallback({\n tools: request.tools,\n maxCalls: request.limits.maxToolCalls,\n ...(request.signal ? { signal: request.signal } : {}),\n })\n let modelProxy: ExternalOptimizerModelProxy | undefined\n const result = await runWithCleanup({\n label: 'DSPy RLM trace-analysis resources',\n run: async () => {\n modelProxy = await startExternalOptimizerModelProxy({\n upstreamBaseUrl: options.baseUrl,\n upstreamApiKey: options.apiKey,\n model: options.model,\n budget: {\n maxCostUsd,\n maxRequests: request.limits.maxIterations + request.limits.maxLlmCalls + 1,\n maxRequestBytes: MAX_MODEL_REQUEST_BYTES,\n maxResponseBytes: MAX_MODEL_RESPONSE_BYTES,\n maxOutputTokensPerRequest: maxOutputTokens,\n maxReasoningTokensPerRequest: maxReasoningTokens,\n requestTimeoutMs: timeoutMs,\n pricing,\n },\n costLedger: request.costLedger,\n channel: 'analyst',\n phase: request.costPhase,\n actor: request.analystId,\n ...(request.costTags ? { tags: request.costTags } : {}),\n ...(request.signal ? { signal: request.signal } : {}),\n })\n request.log?.('trace analyst engine started', {\n engine: 'dspy-rlm',\n model: options.model,\n tools: request.tools.map((tool) => tool.name),\n limits: request.limits,\n })\n const raw = await runExternalOptimizerProcess<unknown>({\n label: 'DSPy RLM trace analysis',\n tempPrefix: 'agent-eval-dspy-rlm-',\n module: BRIDGE_MODULE,\n input: {\n operation: 'analyze',\n question: request.question,\n instructions: request.instructions,\n modelProxy: {\n baseUrl: modelProxy.baseUrl,\n apiKey: modelProxy.apiKey,\n model: options.model,\n maxOutputTokens,\n },\n toolCallback: {\n url: callback.url,\n token: callback.token,\n },\n toolSpecs: request.tools.map(({ name, description, parameters }) => ({\n name,\n description,\n parameters,\n })),\n controlAdapter,\n limits: {\n maxIterations: request.limits.maxIterations,\n maxLlmCalls: request.limits.maxLlmCalls,\n maxOutputChars: request.limits.maxOutputChars,\n },\n },\n ...(runner ? { runner } : {}),\n timeoutMs,\n ...(request.signal ? { signal: request.signal } : {}),\n })\n const parsed = parseBridgeOutput(raw, (index, reason) => {\n request.log?.('finding rejected: bridge row failed schema validation', {\n engine: 'dspy-rlm',\n index,\n reason,\n })\n })\n const successfulCompletions = modelProxy.successfulCompletions()\n const requestAttempts = modelProxy.requestAttempts()\n const rateLimitRetries = modelProxy.rateLimitRetries()\n if (parsed.modelCalls !== successfulCompletions) {\n throw new Error(\n `DSPy RLM reported ${parsed.modelCalls} model calls, but the provider proxy recorded ${successfulCompletions}`,\n )\n }\n return {\n ...parsed,\n toolCalls: callback.calls(),\n runtime: {\n ...parsed.runtime,\n modelRequestAttempts: requestAttempts,\n modelSuccessfulCompletions: successfulCompletions,\n modelRateLimitRetries: rateLimitRetries,\n },\n } satisfies TraceAnalysisEngineResult\n },\n cleanup: async () => {\n const results = await Promise.allSettled([\n ...(modelProxy ? [modelProxy.close()] : []),\n callback.close(),\n ])\n const errors = results.flatMap((entry) =>\n entry.status === 'rejected' ? [entry.reason] : [],\n )\n if (errors.length > 0) {\n throw new AggregateError(errors, 'DSPy RLM resource cleanup failed')\n }\n },\n })\n request.log?.('trace analyst engine completed', {\n engine: 'dspy-rlm',\n model_calls: result.modelCalls,\n model_request_attempts: result.runtime.modelRequestAttempts,\n model_rate_limit_retries: result.runtime.modelRateLimitRetries,\n tool_calls: result.toolCalls,\n findings: result.findings.length,\n })\n return result\n },\n }\n}\n\nfunction parseBridgeOutput(\n value: unknown,\n onRejectedFinding: (index: number, reason: string) => void,\n): Omit<TraceAnalysisEngineResult, 'toolCalls'> {\n if (!isRecord(value)) throw new Error('DSPy RLM bridge output must be an object')\n if (typeof value.answer !== 'string' || !value.answer.trim()) {\n throw new Error('DSPy RLM bridge returned no answer')\n }\n if (!Array.isArray(value.findings)) {\n throw new Error('DSPy RLM bridge findings must be an array')\n }\n // Findings are model output: one malformed row is model noise, not a bridge\n // fault, and the rest of the paid investigation must survive it. Rejected\n // rows are logged per row and counted in runtime.rejectedFindings.\n let rejectedFindings = 0\n const findings: RawAnalystFinding[] = []\n value.findings.forEach((finding, index) => {\n const parsed = RawAnalystFindingSchema.safeParse(finding)\n if (!parsed.success) {\n rejectedFindings += 1\n onRejectedFinding(\n index,\n parsed.error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`).join('; '),\n )\n return\n }\n findings.push(parsed.data)\n })\n if (!Array.isArray(value.trajectory)) {\n throw new Error('DSPy RLM bridge trajectory must be an array')\n }\n if (!Number.isSafeInteger(value.modelCalls) || (value.modelCalls as number) <= 0) {\n throw new Error('DSPy RLM bridge modelCalls must be a positive safe integer')\n }\n if (!isRecord(value.runtime)) {\n throw new Error('DSPy RLM bridge runtime must be an object')\n }\n return {\n answer: value.answer,\n findings,\n trajectory: value.trajectory,\n modelCalls: value.modelCalls as number,\n runtime: { ...value.runtime, rejectedFindings },\n }\n}\n\nfunction assertOptions(options: DspyRlmTraceEngineOptions): void {\n for (const [name, value] of [\n ['baseUrl', options.baseUrl],\n ['apiKey', options.apiKey],\n ['model', options.model],\n ] as const) {\n if (typeof value !== 'string' || !value.trim()) {\n throw new TypeError(`DSPy RLM ${name} must be a non-empty string`)\n }\n }\n}\n\nfunction pricingForModel(model: string): CustomTokenPricing {\n const pricing = resolveModelPricing(model)\n if (!pricing) {\n throw new Error(\n `no pricing is configured for '${model}'; provide DspyRlmTraceEngineOptions.pricing`,\n )\n }\n return {\n inputUsdPerMillion: pricing.input * 1_000,\n outputUsdPerMillion: pricing.output * 1_000,\n }\n}\n\nfunction sanitizedRunner(\n runner: ExternalOptimizerRunnerCommand | undefined,\n): ExternalOptimizerRunnerCommand | undefined {\n if (!runner) return undefined\n return {\n ...(runner.command ? { command: runner.command } : {}),\n ...(runner.args ? { args: runner.args } : {}),\n ...(runner.env ? { env: removeCredentialEnvironment(runner.env) } : {}),\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c as ValidationError } from "./errors-D-LKuDhb.js";
|
|
2
2
|
import { LLM_CACHED_TOKEN_ATTR_KEYS, LLM_CACHE_WRITE_TOKEN_ATTR_KEYS, LLM_COST_ATTR_KEYS, LLM_INPUT_TOKEN_ATTR_KEYS, LLM_OUTPUT_TOKEN_ATTR_KEYS, LLM_REASONING_TOKEN_ATTR_KEYS, RUN_COST_ATTR_KEYS } from "./trace-attributes.js";
|
|
3
|
-
import "./kind-factory-
|
|
3
|
+
import "./kind-factory-Bvwe3pup.js";
|
|
4
4
|
import { t as FAILURE_CLASSES } from "./schema-CRhEY1SO.js";
|
|
5
5
|
import { TOKEN_USAGE_INPUT_KEYS, TOKEN_USAGE_OUTPUT_KEYS, firstTokenCount, tokenUsageSource } from "@tangle-network/agent-core/telemetry";
|
|
6
6
|
import { SSEChunkParser } from "@tangle-network/agent-core/sse";
|
|
@@ -460,4 +460,4 @@ async function extractUsageFromResponse(response, sseOptions) {
|
|
|
460
460
|
//#endregion
|
|
461
461
|
export { recordAggregateMeasurements as a, readTaskFailureLabels as i, extractUsageFromResponse as n, summarizeExecutionMeasurements as o, extractUsageFromSse as r, summarizeTraceErrors as s, extractUsage as t };
|
|
462
462
|
|
|
463
|
-
//# sourceMappingURL=extract-usage-
|
|
463
|
+
//# sourceMappingURL=extract-usage-7l1Xq5ti.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-usage-C5vMw-0R.js","names":["obj"],"sources":["../src/trace/error-classification.ts","../src/trace/execution-measurements.ts","../src/trace/task-failure-attributes.ts","../src/trace/extract-usage.ts"],"sourcesContent":["import type { OtlpSpanRole } from './otlp-attributes'\n\nexport type TraceErrorRole = OtlpSpanRole\n\nexport interface TraceErrorSignal {\n id: string\n parentId?: string\n role: TraceErrorRole\n error: boolean\n processRoot: boolean\n}\n\nexport interface TraceErrorSummary {\n total: number\n execution: number\n process: number\n guardrail: number\n evaluation: number\n propagated: number\n unclassified: number\n}\n\n/**\n * Classify errored spans without counting a propagated parent status as a\n * second execution failure.\n */\nexport function summarizeTraceErrors(signals: readonly TraceErrorSignal[]): TraceErrorSummary {\n const byId = new Map<string, TraceErrorSignal>()\n for (const signal of signals) {\n if (byId.has(signal.id)) {\n throw new Error(`summarizeTraceErrors: duplicate span id '${signal.id}'`)\n }\n byId.set(signal.id, signal)\n }\n\n const propagated = new Set<string>()\n for (const signal of signals) {\n if (!signal.error) continue\n const visited = new Set<string>()\n let parentId = signal.parentId\n while (parentId && !visited.has(parentId)) {\n visited.add(parentId)\n const parent = byId.get(parentId)\n if (!parent) break\n if (parent.error) propagated.add(parent.id)\n parentId = parent.parentId\n }\n }\n\n const summary: TraceErrorSummary = {\n total: 0,\n execution: 0,\n process: 0,\n guardrail: 0,\n evaluation: 0,\n propagated: 0,\n unclassified: 0,\n }\n\n for (const signal of signals) {\n if (!signal.error) continue\n summary.total += 1\n if (signal.role === 'GUARDRAIL') {\n summary.guardrail += 1\n } else if (signal.role === 'EVALUATOR') {\n summary.evaluation += 1\n } else if (signal.processRoot) {\n summary.process += 1\n } else if (propagated.has(signal.id)) {\n summary.propagated += 1\n } else if (\n signal.role === 'AGENT' ||\n signal.role === 'CHAIN' ||\n signal.role === 'LLM' ||\n signal.role === 'TOOL'\n ) {\n summary.execution += 1\n } else {\n summary.unclassified += 1\n }\n }\n\n return summary\n}\n","import type { RunTokenUsage } from '../run-record'\nimport {\n LLM_CACHE_WRITE_TOKEN_ATTR_KEYS,\n LLM_CACHED_TOKEN_ATTR_KEYS,\n LLM_COST_ATTR_KEYS,\n LLM_INPUT_TOKEN_ATTR_KEYS,\n LLM_OUTPUT_TOKEN_ATTR_KEYS,\n LLM_REASONING_TOKEN_ATTR_KEYS,\n RUN_COST_ATTR_KEYS,\n} from './otlp-attributes'\n\nexport interface ExecutionMeasurementSpan {\n id: string\n parentId?: string\n attributes: Record<string, unknown>\n modelCall: boolean\n aggregate: boolean\n}\n\nexport interface MeasurementCoverage {\n value?: number\n reportingCalls: number\n complete: boolean\n}\n\nexport interface ExecutionMeasurements {\n tokenUsage: RunTokenUsage\n modelCallCount: number\n callSpanIds: string[]\n cost: MeasurementCoverage\n aggregate?: {\n tokenUsage: RunTokenUsage\n costUsd?: number\n }\n}\n\nconst TOKEN_MEASUREMENT_KEY_GROUPS = [\n LLM_INPUT_TOKEN_ATTR_KEYS,\n LLM_OUTPUT_TOKEN_ATTR_KEYS,\n LLM_REASONING_TOKEN_ATTR_KEYS,\n LLM_CACHED_TOKEN_ATTR_KEYS,\n LLM_CACHE_WRITE_TOKEN_ATTR_KEYS,\n] as const\n\nconst EXECUTION_MEASUREMENT_KEY_GROUPS = [\n ...TOKEN_MEASUREMENT_KEY_GROUPS,\n LLM_COST_ATTR_KEYS,\n] as const\n\ninterface RetainedCallSummary {\n callCount: number\n measurements: Array<{\n total: number\n reportingCalls: number\n }>\n}\n\n/**\n * Reconcile execution measurements across nested telemetry wrappers.\n * A measured parent is used only when a descendant call does not report the\n * same field, so aggregate wrappers neither duplicate complete child data nor\n * erase complementary parent fields.\n */\nexport function summarizeExecutionMeasurements(\n spans: ExecutionMeasurementSpan[],\n): ExecutionMeasurements {\n const byId = new Map<string, ExecutionMeasurementSpan>()\n for (const span of spans) {\n if (byId.has(span.id)) {\n throw new Error(`summarizeExecutionMeasurements: duplicate span id \"${span.id}\"`)\n }\n byId.set(span.id, span)\n }\n const tokenMeasurementKeys = TOKEN_MEASUREMENT_KEY_GROUPS.flat()\n const candidates = spans.filter(\n (span) =>\n span.modelCall ||\n (!span.aggregate && readNumber(span.attributes, tokenMeasurementKeys) !== undefined),\n )\n const candidateIds = new Set(candidates.map((span) => span.id))\n const candidateChildren = new Map<string, ExecutionMeasurementSpan[]>()\n for (const candidate of candidates) {\n const parentId = nearestCandidateParent(candidate, byId, candidateIds)\n if (!parentId) continue\n const children = candidateChildren.get(parentId) ?? []\n children.push(candidate)\n candidateChildren.set(parentId, children)\n }\n const aggregateIds = classifyAggregateSpans(candidates, candidateChildren)\n const untypedRunCostIds = new Set(\n spans\n .filter(\n (span) =>\n !span.modelCall &&\n !span.aggregate &&\n !candidateIds.has(span.id) &&\n readNumber(span.attributes, RUN_COST_ATTR_KEYS) !== undefined,\n )\n .map((span) => span.id),\n )\n const aggregateSourceIds = new Set(\n spans\n .filter(\n (span) => span.aggregate || aggregateIds.has(span.id) || untypedRunCostIds.has(span.id),\n )\n .map((span) => span.id),\n )\n\n const calls = candidates.filter((span) => !aggregateIds.has(span.id))\n const input = reconcileMeasurement(calls, byId, aggregateSourceIds, LLM_INPUT_TOKEN_ATTR_KEYS)\n const reasoning = reconcileMeasurement(\n calls,\n byId,\n aggregateSourceIds,\n LLM_REASONING_TOKEN_ATTR_KEYS,\n )\n const output = reconcileMeasurement(\n calls,\n byId,\n aggregateSourceIds,\n LLM_OUTPUT_TOKEN_ATTR_KEYS,\n LLM_REASONING_TOKEN_ATTR_KEYS,\n )\n const cached = reconcileMeasurement(calls, byId, aggregateSourceIds, LLM_CACHED_TOKEN_ATTR_KEYS)\n const cacheWrite = reconcileMeasurement(\n calls,\n byId,\n aggregateSourceIds,\n LLM_CACHE_WRITE_TOKEN_ATTR_KEYS,\n )\n const aggregate = summarizeAggregateMeasurements(\n spans,\n byId,\n new Set([...aggregateIds, ...untypedRunCostIds]),\n )\n\n return {\n tokenUsage: {\n input: input.value ?? 0,\n output: Math.max(output.value ?? 0, reasoning.value ?? 0),\n ...(reasoning.value !== undefined ? { reasoning: reasoning.value } : {}),\n ...(cached.value !== undefined ? { cached: cached.value } : {}),\n ...(cacheWrite.value !== undefined ? { cacheWrite: cacheWrite.value } : {}),\n },\n modelCallCount: calls.length,\n callSpanIds: calls.map((span) => span.id),\n cost: reconcileMeasurement(calls, byId, aggregateSourceIds, LLM_COST_ATTR_KEYS),\n ...(aggregate ? { aggregate } : {}),\n }\n}\n\nexport function recordAggregateMeasurements(\n raw: Record<string, number>,\n aggregate: ExecutionMeasurements['aggregate'],\n): void {\n if (!aggregate) return\n raw.aggregate_prompt_tokens = aggregate.tokenUsage.input\n raw.aggregate_completion_tokens = aggregate.tokenUsage.output\n if (aggregate.tokenUsage.reasoning !== undefined)\n raw.aggregate_reasoning_tokens = aggregate.tokenUsage.reasoning\n if (aggregate.tokenUsage.cached !== undefined)\n raw.aggregate_cached_tokens = aggregate.tokenUsage.cached\n if (aggregate.tokenUsage.cacheWrite !== undefined)\n raw.aggregate_cache_write_tokens = aggregate.tokenUsage.cacheWrite\n if (aggregate.costUsd !== undefined) raw.aggregate_cost_usd = aggregate.costUsd\n}\n\nfunction summarizeAggregateMeasurements(\n spans: ExecutionMeasurementSpan[],\n byId: Map<string, ExecutionMeasurementSpan>,\n aggregateIds: Set<string>,\n): ExecutionMeasurements['aggregate'] {\n const aggregates = spans.filter((span) => span.aggregate || aggregateIds.has(span.id))\n const input = reconcileTopLevelMeasurement(aggregates, byId, LLM_INPUT_TOKEN_ATTR_KEYS)\n const output = reconcileTopLevelMeasurement(aggregates, byId, LLM_OUTPUT_TOKEN_ATTR_KEYS)\n const reasoning = reconcileTopLevelMeasurement(aggregates, byId, LLM_REASONING_TOKEN_ATTR_KEYS)\n const cached = reconcileTopLevelMeasurement(aggregates, byId, LLM_CACHED_TOKEN_ATTR_KEYS)\n const cacheWrite = reconcileTopLevelMeasurement(aggregates, byId, LLM_CACHE_WRITE_TOKEN_ATTR_KEYS)\n const costUsd = reconcileTopLevelMeasurement(aggregates, byId, LLM_COST_ATTR_KEYS)\n if (\n input === undefined &&\n output === undefined &&\n reasoning === undefined &&\n cached === undefined &&\n cacheWrite === undefined &&\n costUsd === undefined\n )\n return undefined\n return {\n tokenUsage: {\n input: input ?? 0,\n output: output ?? reasoning ?? 0,\n ...(reasoning !== undefined ? { reasoning } : {}),\n ...(cached !== undefined ? { cached } : {}),\n ...(cacheWrite !== undefined ? { cacheWrite } : {}),\n },\n ...(costUsd !== undefined ? { costUsd } : {}),\n }\n}\n\nfunction reconcileTopLevelMeasurement(\n spans: ExecutionMeasurementSpan[],\n byId: Map<string, ExecutionMeasurementSpan>,\n keys: readonly string[],\n): number | undefined {\n const selected = new Map<string, number>()\n for (const span of spans) {\n const value = readNumber(span.attributes, keys)\n if (value !== undefined) selected.set(span.id, value)\n }\n for (const spanId of [...selected.keys()]) {\n const span = byId.get(spanId)\n if (!span) continue\n if (ancestorIds(span, byId).some((ancestorId) => selected.has(ancestorId))) {\n selected.delete(spanId)\n }\n }\n return selected.size > 0\n ? [...selected.values()].reduce((total, value) => total + value, 0)\n : undefined\n}\n\nfunction reconcileMeasurement(\n calls: ExecutionMeasurementSpan[],\n byId: Map<string, ExecutionMeasurementSpan>,\n aggregateSourceIds: Set<string>,\n keys: readonly string[],\n fallbackKeys?: readonly string[],\n): MeasurementCoverage {\n const selected = new Map<string, number>()\n const callIds = new Set(calls.map((call) => call.id))\n let reportingCalls = 0\n\n for (const call of calls) {\n const primary = nearestMeasurement(call, byId, callIds, aggregateSourceIds, keys)\n const fallback = fallbackKeys\n ? nearestMeasurement(call, byId, callIds, aggregateSourceIds, fallbackKeys)\n : undefined\n const source =\n primary && fallback && primary.span.id === fallback.span.id\n ? { span: primary.span, value: Math.max(primary.value, fallback.value) }\n : (primary ?? fallback)\n if (!source) continue\n reportingCalls += 1\n selected.set(source.span.id, source.value)\n }\n\n for (const spanId of [...selected.keys()]) {\n const span = byId.get(spanId)\n if (!span) continue\n if (\n ancestorIds(span, byId).some(\n (ancestorId) => selected.has(ancestorId) && !callIds.has(ancestorId),\n )\n ) {\n selected.delete(spanId)\n }\n }\n\n return {\n ...(selected.size > 0\n ? { value: [...selected.values()].reduce((total, value) => total + value, 0) }\n : {}),\n reportingCalls,\n complete: calls.length > 0 && reportingCalls === calls.length,\n }\n}\n\nfunction nearestMeasurement(\n call: ExecutionMeasurementSpan,\n byId: Map<string, ExecutionMeasurementSpan>,\n callIds: Set<string>,\n aggregateSourceIds: Set<string>,\n keys: readonly string[],\n): { span: ExecutionMeasurementSpan; value: number } | undefined {\n let current: ExecutionMeasurementSpan | undefined = call\n const seen = new Set<string>()\n while (current && !seen.has(current.id)) {\n seen.add(current.id)\n const value = readNumber(current.attributes, keys)\n if (\n value !== undefined &&\n (current.id === call.id || (!callIds.has(current.id) && aggregateSourceIds.has(current.id)))\n ) {\n return { span: current, value }\n }\n current = current.parentId ? byId.get(current.parentId) : undefined\n }\n return undefined\n}\n\nfunction classifyAggregateSpans(\n candidates: ExecutionMeasurementSpan[],\n childrenById: Map<string, ExecutionMeasurementSpan[]>,\n): Set<string> {\n const aggregateIds = new Set<string>()\n const summaries = new Map<string, RetainedCallSummary>()\n const visiting = new Set<string>()\n\n const visit = (span: ExecutionMeasurementSpan): RetainedCallSummary => {\n const cached = summaries.get(span.id)\n if (cached) return cached\n if (visiting.has(span.id)) return emptyRetainedCallSummary()\n visiting.add(span.id)\n\n const descendants = emptyRetainedCallSummary()\n for (const child of childrenById.get(span.id) ?? []) {\n const childDescendants = visit(child)\n if (!aggregateIds.has(child.id)) addRetainedCall(descendants, child)\n addRetainedCallSummary(descendants, childDescendants)\n }\n\n if (\n descendants.callCount > 0 &&\n (!span.modelCall || hasCompatibleDescendantMeasurements(span, descendants))\n ) {\n aggregateIds.add(span.id)\n }\n\n visiting.delete(span.id)\n summaries.set(span.id, descendants)\n return descendants\n }\n\n for (const candidate of candidates) visit(candidate)\n return aggregateIds\n}\n\nfunction emptyRetainedCallSummary(): RetainedCallSummary {\n return {\n callCount: 0,\n measurements: EXECUTION_MEASUREMENT_KEY_GROUPS.map(() => ({\n total: 0,\n reportingCalls: 0,\n })),\n }\n}\n\nfunction addRetainedCall(summary: RetainedCallSummary, span: ExecutionMeasurementSpan): void {\n summary.callCount += 1\n for (let index = 0; index < EXECUTION_MEASUREMENT_KEY_GROUPS.length; index += 1) {\n const value = readNumber(span.attributes, EXECUTION_MEASUREMENT_KEY_GROUPS[index]!)\n if (value === undefined) continue\n const measurement = summary.measurements[index]!\n measurement.total += value\n measurement.reportingCalls += 1\n }\n}\n\nfunction addRetainedCallSummary(target: RetainedCallSummary, source: RetainedCallSummary): void {\n target.callCount += source.callCount\n for (let index = 0; index < target.measurements.length; index += 1) {\n const measurement = target.measurements[index]!\n const sourceMeasurement = source.measurements[index]!\n measurement.total += sourceMeasurement.total\n measurement.reportingCalls += sourceMeasurement.reportingCalls\n }\n}\n\nfunction hasCompatibleDescendantMeasurements(\n span: ExecutionMeasurementSpan,\n descendants: RetainedCallSummary,\n): boolean {\n let parentMeasurements = 0\n let descendantMeasurements = 0\n for (let index = 0; index < EXECUTION_MEASUREMENT_KEY_GROUPS.length; index += 1) {\n const keys = EXECUTION_MEASUREMENT_KEY_GROUPS[index]!\n const parentValue = readNumber(span.attributes, keys)\n const measurement = descendants.measurements[index]!\n if (parentValue !== undefined) parentMeasurements += 1\n if (measurement.reportingCalls > 0) descendantMeasurements += 1\n if (parentValue === undefined || measurement.reportingCalls === 0) continue\n if (measurement.reportingCalls !== descendants.callCount) continue\n if (Math.abs(parentValue - measurement.total) > 1e-12) return false\n }\n return parentMeasurements === 0 || descendantMeasurements > 0\n}\n\nfunction ancestorIds(\n span: ExecutionMeasurementSpan,\n byId: Map<string, ExecutionMeasurementSpan>,\n): string[] {\n const ids: string[] = []\n const seen = new Set<string>()\n let parentId = span.parentId\n while (parentId && !seen.has(parentId)) {\n ids.push(parentId)\n seen.add(parentId)\n parentId = byId.get(parentId)?.parentId\n }\n return ids\n}\n\nfunction nearestCandidateParent(\n span: ExecutionMeasurementSpan,\n byId: Map<string, ExecutionMeasurementSpan>,\n candidateIds: Set<string>,\n): string | undefined {\n const seen = new Set<string>()\n let parentId = span.parentId\n while (parentId && !seen.has(parentId)) {\n if (candidateIds.has(parentId)) return parentId\n seen.add(parentId)\n parentId = byId.get(parentId)?.parentId\n }\n return undefined\n}\n\nfunction readNumber(\n attributes: Record<string, unknown>,\n keys: readonly string[],\n): number | undefined {\n for (const key of keys) {\n const value = attributes[key]\n const parsed =\n typeof value === 'number'\n ? value\n : typeof value === 'string' && value.length > 0\n ? Number(value)\n : Number.NaN\n if (Number.isFinite(parsed) && parsed >= 0) return parsed\n }\n return undefined\n}\n","import { ValidationError } from '../errors'\nimport { FAILURE_CLASSES, type FailureClass } from './schema'\n\nconst TASK_FAILURE_CLASS_ATTR = 'tangle.task.failure_class'\nconst TASK_FAILURE_MODE_ATTR = 'tangle.task.failure_mode'\n\ninterface AttributeCarrier {\n attributes: Record<string, unknown>\n}\n\nexport type TaskFailureLabels =\n | { failureClass?: undefined; failureMode?: undefined }\n | { failureClass: 'success'; failureMode?: undefined }\n | { failureClass: Exclude<FailureClass, 'success'>; failureMode?: string }\n\nexport function readTaskFailureLabels(\n roots: readonly AttributeCarrier[],\n context: string,\n): TaskFailureLabels {\n const failureClass = readConsistentRootString(roots, TASK_FAILURE_CLASS_ATTR, context)\n const failureMode = readConsistentRootString(roots, TASK_FAILURE_MODE_ATTR, context)\n\n if (failureClass !== undefined && !FAILURE_CLASSES.includes(failureClass as FailureClass)) {\n throw new ValidationError(\n `${context}: ${TASK_FAILURE_CLASS_ATTR} must be one of ${FAILURE_CLASSES.join(', ')}`,\n )\n }\n if (failureMode !== undefined && (failureClass === undefined || failureClass === 'success')) {\n throw new ValidationError(\n `${context}: ${TASK_FAILURE_MODE_ATTR} requires a non-success ${TASK_FAILURE_CLASS_ATTR}`,\n )\n }\n\n if (failureClass === undefined) return {}\n if (failureClass === 'success') return { failureClass }\n return {\n failureClass: failureClass as Exclude<FailureClass, 'success'>,\n ...(failureMode ? { failureMode } : {}),\n }\n}\n\nfunction readConsistentRootString(\n roots: readonly AttributeCarrier[],\n key: string,\n context: string,\n): string | undefined {\n const values = new Set<string>()\n for (const root of roots) {\n if (!Object.hasOwn(root.attributes, key)) continue\n const value = root.attributes[key]\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new ValidationError(`${context}: ${key} must be a non-empty string`)\n }\n values.add(value)\n }\n\n if (values.size > 1) {\n throw new ValidationError(\n `${context}: conflicting ${key} values: ${[...values].sort().join(', ')}`,\n )\n }\n return values.values().next().value\n}\n","/**\n * Provider response and SSE usage extraction.\n *\n * Missing usage returns `null`; reported zeroes and cache-only activity remain\n * distinguishable from absent telemetry.\n */\n\nimport { SSEChunkParser } from '@tangle-network/agent-core/sse'\nimport {\n firstTokenCount,\n TOKEN_USAGE_INPUT_KEYS,\n TOKEN_USAGE_OUTPUT_KEYS,\n tokenUsageSource,\n} from '@tangle-network/agent-core/telemetry'\nimport type { RunTokenUsage } from '../run-record'\n\nexport type ExtractedUsage = RunTokenUsage\nexport type SseUsageMode = 'cumulative' | 'delta'\n\nexport interface ExtractUsageFromSseOptions {\n /** Provider usage events are cumulative snapshots unless explicitly marked as deltas. */\n mode?: SseUsageMode\n}\n\nconst INPUT_OTHER_KEYS = ['input_other'] as const\nconst EXCLUSIVE_REASONING_KEYS = ['reasoning', 'reasoning_tokens', 'reasoningTokens'] as const\nconst INCLUSIVE_REASONING_KEYS = ['reasoning_output_tokens', 'reasoningOutputTokens'] as const\nconst INPUT_DETAIL_KEYS = ['prompt_tokens_details', 'input_tokens_details'] as const\nconst OUTPUT_DETAIL_KEYS = ['completion_tokens_details', 'output_tokens_details'] as const\nconst CACHED_KEYS = [\n 'cache',\n 'cached_tokens',\n 'cached_input_tokens',\n 'cache_read_tokens',\n 'cache_read_input_tokens',\n 'cachedTokens',\n 'cachedInputTokens',\n 'cacheReadTokens',\n 'cacheReadInputTokens',\n 'input_cache_read',\n] as const\nconst CACHE_WRITE_KEYS = [\n 'cache_creation_tokens',\n 'cache_creation_input_tokens',\n 'cacheCreationTokens',\n 'cacheCreationInputTokens',\n 'input_cache_creation',\n] as const\n\nfunction nestedRecord(\n source: Record<string, unknown>,\n key: string,\n): Record<string, unknown> | undefined {\n const value = source[key]\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n}\n\nfunction nestedNumber(\n source: Record<string, unknown>,\n recordKeys: readonly string[],\n valueKeys: readonly string[],\n): number | undefined {\n for (const recordKey of recordKeys) {\n const value = firstTokenCount(nestedRecord(source, recordKey), valueKeys)\n if (value !== undefined) return value\n }\n return undefined\n}\n\n/**\n * Pull `{ input, output, cached?, cacheWrite? }` from a parsed response\n * body. Accepts a top-level `usage` object (the common case) or a body that IS\n * the usage object. Returns null only when none of those categories is present.\n */\nexport function extractUsage(body: unknown): ExtractedUsage | null {\n if (!body || typeof body !== 'object') return null\n const obj = body as Record<string, unknown>\n const usage = tokenUsageSource(obj)\n const input = firstTokenCount(usage, TOKEN_USAGE_INPUT_KEYS)\n const inputOther = firstTokenCount(usage, INPUT_OTHER_KEYS)\n const output = firstTokenCount(usage, TOKEN_USAGE_OUTPUT_KEYS)\n const exclusiveReasoning = firstTokenCount(usage, EXCLUSIVE_REASONING_KEYS)\n const inclusiveReasoning =\n firstTokenCount(usage, INCLUSIVE_REASONING_KEYS) ??\n nestedNumber(usage, OUTPUT_DETAIL_KEYS, ['reasoning_tokens', 'reasoningTokens'])\n const reasoning = exclusiveReasoning ?? inclusiveReasoning\n const nestedCache = nestedRecord(usage, 'cache')\n const cached =\n firstTokenCount(usage, CACHED_KEYS) ??\n firstTokenCount(nestedCache, ['read']) ??\n nestedNumber(usage, INPUT_DETAIL_KEYS, ['cached_tokens', 'cachedTokens'])\n const cacheWrite =\n firstTokenCount(usage, CACHE_WRITE_KEYS) ?? firstTokenCount(nestedCache, ['write'])\n if (\n input === undefined &&\n inputOther === undefined &&\n output === undefined &&\n reasoning === undefined &&\n cached === undefined &&\n cacheWrite === undefined\n )\n return null\n const result: ExtractedUsage = {\n input: (input ?? 0) + (inputOther ?? 0),\n output:\n (output ?? (inclusiveReasoning !== undefined ? inclusiveReasoning : 0)) +\n (exclusiveReasoning ?? 0),\n }\n if (reasoning !== undefined) result.reasoning = reasoning\n if (cached !== undefined) result.cached = cached\n if (cacheWrite !== undefined) result.cacheWrite = cacheWrite\n return result\n}\n\n/**\n * Extract token usage from a complete SSE response body using the shared SSE\n * frame parser. Cumulative snapshots are the fail-safe default because summing\n * them inflates billing; callers with explicit delta events opt into `mode: 'delta'`.\n */\nexport function extractUsageFromSse(\n text: string,\n options: ExtractUsageFromSseOptions = {},\n): ExtractedUsage | null {\n const mode = options.mode ?? 'cumulative'\n let input = 0\n let output = 0\n let reasoning = 0\n let sawReasoning = false\n let cached = 0\n let sawCached = false\n let cacheWrite = 0\n let sawCacheWrite = false\n let found = false\n const parser = new SSEChunkParser<unknown>({ transform: parseSseJson })\n const events = [...parser.push(text), ...parser.flush()]\n const merge = mode === 'delta' ? (current: number, next: number) => current + next : Math.max\n\n for (const event of events) {\n const usage = extractUsage(event.data)\n if (!usage) continue\n input = merge(input, usage.input)\n output = merge(output, usage.output)\n if (usage.reasoning !== undefined) {\n reasoning = merge(reasoning, usage.reasoning)\n sawReasoning = true\n }\n if (usage.cached !== undefined) {\n cached = merge(cached, usage.cached)\n sawCached = true\n }\n if (usage.cacheWrite !== undefined) {\n cacheWrite = merge(cacheWrite, usage.cacheWrite)\n sawCacheWrite = true\n }\n found = true\n }\n if (!found) return null\n return {\n input,\n output,\n ...(sawReasoning ? { reasoning } : {}),\n ...(sawCached ? { cached } : {}),\n ...(sawCacheWrite ? { cacheWrite } : {}),\n }\n}\n\nfunction parseSseJson(raw: string): unknown | null {\n const payload = raw.trim()\n if (!payload || payload === '[DONE]') return null\n try {\n return JSON.parse(payload)\n } catch {\n return null\n }\n}\n\n/**\n * Extract usage from an HTTP `Response` without consuming the caller's body:\n * clones, reads the text, and tries the JSON parser first, then the SSE\n * accumulator. Best-effort — returns null on any read/parse miss so a usage tee\n * never takes down the underlying call.\n */\nexport async function extractUsageFromResponse(\n response: Response,\n sseOptions?: ExtractUsageFromSseOptions,\n): Promise<ExtractedUsage | null> {\n let text: string\n try {\n text = await response.clone().text()\n } catch {\n return null\n }\n let json: unknown\n try {\n json = JSON.parse(text)\n } catch {\n json = undefined\n }\n return extractUsage(json) ?? extractUsageFromSse(text, sseOptions)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extract-usage-7l1Xq5ti.js","names":["obj"],"sources":["../src/trace/error-classification.ts","../src/trace/execution-measurements.ts","../src/trace/task-failure-attributes.ts","../src/trace/extract-usage.ts"],"sourcesContent":["import type { OtlpSpanRole } from './otlp-attributes'\n\nexport type TraceErrorRole = OtlpSpanRole\n\nexport interface TraceErrorSignal {\n id: string\n parentId?: string\n role: TraceErrorRole\n error: boolean\n processRoot: boolean\n}\n\nexport interface TraceErrorSummary {\n total: number\n execution: number\n process: number\n guardrail: number\n evaluation: number\n propagated: number\n unclassified: number\n}\n\n/**\n * Classify errored spans without counting a propagated parent status as a\n * second execution failure.\n */\nexport function summarizeTraceErrors(signals: readonly TraceErrorSignal[]): TraceErrorSummary {\n const byId = new Map<string, TraceErrorSignal>()\n for (const signal of signals) {\n if (byId.has(signal.id)) {\n throw new Error(`summarizeTraceErrors: duplicate span id '${signal.id}'`)\n }\n byId.set(signal.id, signal)\n }\n\n const propagated = new Set<string>()\n for (const signal of signals) {\n if (!signal.error) continue\n const visited = new Set<string>()\n let parentId = signal.parentId\n while (parentId && !visited.has(parentId)) {\n visited.add(parentId)\n const parent = byId.get(parentId)\n if (!parent) break\n if (parent.error) propagated.add(parent.id)\n parentId = parent.parentId\n }\n }\n\n const summary: TraceErrorSummary = {\n total: 0,\n execution: 0,\n process: 0,\n guardrail: 0,\n evaluation: 0,\n propagated: 0,\n unclassified: 0,\n }\n\n for (const signal of signals) {\n if (!signal.error) continue\n summary.total += 1\n if (signal.role === 'GUARDRAIL') {\n summary.guardrail += 1\n } else if (signal.role === 'EVALUATOR') {\n summary.evaluation += 1\n } else if (signal.processRoot) {\n summary.process += 1\n } else if (propagated.has(signal.id)) {\n summary.propagated += 1\n } else if (\n signal.role === 'AGENT' ||\n signal.role === 'CHAIN' ||\n signal.role === 'LLM' ||\n signal.role === 'TOOL'\n ) {\n summary.execution += 1\n } else {\n summary.unclassified += 1\n }\n }\n\n return summary\n}\n","import type { RunTokenUsage } from '../run-record'\nimport {\n LLM_CACHE_WRITE_TOKEN_ATTR_KEYS,\n LLM_CACHED_TOKEN_ATTR_KEYS,\n LLM_COST_ATTR_KEYS,\n LLM_INPUT_TOKEN_ATTR_KEYS,\n LLM_OUTPUT_TOKEN_ATTR_KEYS,\n LLM_REASONING_TOKEN_ATTR_KEYS,\n RUN_COST_ATTR_KEYS,\n} from './otlp-attributes'\n\nexport interface ExecutionMeasurementSpan {\n id: string\n parentId?: string\n attributes: Record<string, unknown>\n modelCall: boolean\n aggregate: boolean\n}\n\nexport interface MeasurementCoverage {\n value?: number\n reportingCalls: number\n complete: boolean\n}\n\nexport interface ExecutionMeasurements {\n tokenUsage: RunTokenUsage\n modelCallCount: number\n callSpanIds: string[]\n cost: MeasurementCoverage\n aggregate?: {\n tokenUsage: RunTokenUsage\n costUsd?: number\n }\n}\n\nconst TOKEN_MEASUREMENT_KEY_GROUPS = [\n LLM_INPUT_TOKEN_ATTR_KEYS,\n LLM_OUTPUT_TOKEN_ATTR_KEYS,\n LLM_REASONING_TOKEN_ATTR_KEYS,\n LLM_CACHED_TOKEN_ATTR_KEYS,\n LLM_CACHE_WRITE_TOKEN_ATTR_KEYS,\n] as const\n\nconst EXECUTION_MEASUREMENT_KEY_GROUPS = [\n ...TOKEN_MEASUREMENT_KEY_GROUPS,\n LLM_COST_ATTR_KEYS,\n] as const\n\ninterface RetainedCallSummary {\n callCount: number\n measurements: Array<{\n total: number\n reportingCalls: number\n }>\n}\n\n/**\n * Reconcile execution measurements across nested telemetry wrappers.\n * A measured parent is used only when a descendant call does not report the\n * same field, so aggregate wrappers neither duplicate complete child data nor\n * erase complementary parent fields.\n */\nexport function summarizeExecutionMeasurements(\n spans: ExecutionMeasurementSpan[],\n): ExecutionMeasurements {\n const byId = new Map<string, ExecutionMeasurementSpan>()\n for (const span of spans) {\n if (byId.has(span.id)) {\n throw new Error(`summarizeExecutionMeasurements: duplicate span id \"${span.id}\"`)\n }\n byId.set(span.id, span)\n }\n const tokenMeasurementKeys = TOKEN_MEASUREMENT_KEY_GROUPS.flat()\n const candidates = spans.filter(\n (span) =>\n span.modelCall ||\n (!span.aggregate && readNumber(span.attributes, tokenMeasurementKeys) !== undefined),\n )\n const candidateIds = new Set(candidates.map((span) => span.id))\n const candidateChildren = new Map<string, ExecutionMeasurementSpan[]>()\n for (const candidate of candidates) {\n const parentId = nearestCandidateParent(candidate, byId, candidateIds)\n if (!parentId) continue\n const children = candidateChildren.get(parentId) ?? []\n children.push(candidate)\n candidateChildren.set(parentId, children)\n }\n const aggregateIds = classifyAggregateSpans(candidates, candidateChildren)\n const untypedRunCostIds = new Set(\n spans\n .filter(\n (span) =>\n !span.modelCall &&\n !span.aggregate &&\n !candidateIds.has(span.id) &&\n readNumber(span.attributes, RUN_COST_ATTR_KEYS) !== undefined,\n )\n .map((span) => span.id),\n )\n const aggregateSourceIds = new Set(\n spans\n .filter(\n (span) => span.aggregate || aggregateIds.has(span.id) || untypedRunCostIds.has(span.id),\n )\n .map((span) => span.id),\n )\n\n const calls = candidates.filter((span) => !aggregateIds.has(span.id))\n const input = reconcileMeasurement(calls, byId, aggregateSourceIds, LLM_INPUT_TOKEN_ATTR_KEYS)\n const reasoning = reconcileMeasurement(\n calls,\n byId,\n aggregateSourceIds,\n LLM_REASONING_TOKEN_ATTR_KEYS,\n )\n const output = reconcileMeasurement(\n calls,\n byId,\n aggregateSourceIds,\n LLM_OUTPUT_TOKEN_ATTR_KEYS,\n LLM_REASONING_TOKEN_ATTR_KEYS,\n )\n const cached = reconcileMeasurement(calls, byId, aggregateSourceIds, LLM_CACHED_TOKEN_ATTR_KEYS)\n const cacheWrite = reconcileMeasurement(\n calls,\n byId,\n aggregateSourceIds,\n LLM_CACHE_WRITE_TOKEN_ATTR_KEYS,\n )\n const aggregate = summarizeAggregateMeasurements(\n spans,\n byId,\n new Set([...aggregateIds, ...untypedRunCostIds]),\n )\n\n return {\n tokenUsage: {\n input: input.value ?? 0,\n output: Math.max(output.value ?? 0, reasoning.value ?? 0),\n ...(reasoning.value !== undefined ? { reasoning: reasoning.value } : {}),\n ...(cached.value !== undefined ? { cached: cached.value } : {}),\n ...(cacheWrite.value !== undefined ? { cacheWrite: cacheWrite.value } : {}),\n },\n modelCallCount: calls.length,\n callSpanIds: calls.map((span) => span.id),\n cost: reconcileMeasurement(calls, byId, aggregateSourceIds, LLM_COST_ATTR_KEYS),\n ...(aggregate ? { aggregate } : {}),\n }\n}\n\nexport function recordAggregateMeasurements(\n raw: Record<string, number>,\n aggregate: ExecutionMeasurements['aggregate'],\n): void {\n if (!aggregate) return\n raw.aggregate_prompt_tokens = aggregate.tokenUsage.input\n raw.aggregate_completion_tokens = aggregate.tokenUsage.output\n if (aggregate.tokenUsage.reasoning !== undefined)\n raw.aggregate_reasoning_tokens = aggregate.tokenUsage.reasoning\n if (aggregate.tokenUsage.cached !== undefined)\n raw.aggregate_cached_tokens = aggregate.tokenUsage.cached\n if (aggregate.tokenUsage.cacheWrite !== undefined)\n raw.aggregate_cache_write_tokens = aggregate.tokenUsage.cacheWrite\n if (aggregate.costUsd !== undefined) raw.aggregate_cost_usd = aggregate.costUsd\n}\n\nfunction summarizeAggregateMeasurements(\n spans: ExecutionMeasurementSpan[],\n byId: Map<string, ExecutionMeasurementSpan>,\n aggregateIds: Set<string>,\n): ExecutionMeasurements['aggregate'] {\n const aggregates = spans.filter((span) => span.aggregate || aggregateIds.has(span.id))\n const input = reconcileTopLevelMeasurement(aggregates, byId, LLM_INPUT_TOKEN_ATTR_KEYS)\n const output = reconcileTopLevelMeasurement(aggregates, byId, LLM_OUTPUT_TOKEN_ATTR_KEYS)\n const reasoning = reconcileTopLevelMeasurement(aggregates, byId, LLM_REASONING_TOKEN_ATTR_KEYS)\n const cached = reconcileTopLevelMeasurement(aggregates, byId, LLM_CACHED_TOKEN_ATTR_KEYS)\n const cacheWrite = reconcileTopLevelMeasurement(aggregates, byId, LLM_CACHE_WRITE_TOKEN_ATTR_KEYS)\n const costUsd = reconcileTopLevelMeasurement(aggregates, byId, LLM_COST_ATTR_KEYS)\n if (\n input === undefined &&\n output === undefined &&\n reasoning === undefined &&\n cached === undefined &&\n cacheWrite === undefined &&\n costUsd === undefined\n )\n return undefined\n return {\n tokenUsage: {\n input: input ?? 0,\n output: output ?? reasoning ?? 0,\n ...(reasoning !== undefined ? { reasoning } : {}),\n ...(cached !== undefined ? { cached } : {}),\n ...(cacheWrite !== undefined ? { cacheWrite } : {}),\n },\n ...(costUsd !== undefined ? { costUsd } : {}),\n }\n}\n\nfunction reconcileTopLevelMeasurement(\n spans: ExecutionMeasurementSpan[],\n byId: Map<string, ExecutionMeasurementSpan>,\n keys: readonly string[],\n): number | undefined {\n const selected = new Map<string, number>()\n for (const span of spans) {\n const value = readNumber(span.attributes, keys)\n if (value !== undefined) selected.set(span.id, value)\n }\n for (const spanId of [...selected.keys()]) {\n const span = byId.get(spanId)\n if (!span) continue\n if (ancestorIds(span, byId).some((ancestorId) => selected.has(ancestorId))) {\n selected.delete(spanId)\n }\n }\n return selected.size > 0\n ? [...selected.values()].reduce((total, value) => total + value, 0)\n : undefined\n}\n\nfunction reconcileMeasurement(\n calls: ExecutionMeasurementSpan[],\n byId: Map<string, ExecutionMeasurementSpan>,\n aggregateSourceIds: Set<string>,\n keys: readonly string[],\n fallbackKeys?: readonly string[],\n): MeasurementCoverage {\n const selected = new Map<string, number>()\n const callIds = new Set(calls.map((call) => call.id))\n let reportingCalls = 0\n\n for (const call of calls) {\n const primary = nearestMeasurement(call, byId, callIds, aggregateSourceIds, keys)\n const fallback = fallbackKeys\n ? nearestMeasurement(call, byId, callIds, aggregateSourceIds, fallbackKeys)\n : undefined\n const source =\n primary && fallback && primary.span.id === fallback.span.id\n ? { span: primary.span, value: Math.max(primary.value, fallback.value) }\n : (primary ?? fallback)\n if (!source) continue\n reportingCalls += 1\n selected.set(source.span.id, source.value)\n }\n\n for (const spanId of [...selected.keys()]) {\n const span = byId.get(spanId)\n if (!span) continue\n if (\n ancestorIds(span, byId).some(\n (ancestorId) => selected.has(ancestorId) && !callIds.has(ancestorId),\n )\n ) {\n selected.delete(spanId)\n }\n }\n\n return {\n ...(selected.size > 0\n ? { value: [...selected.values()].reduce((total, value) => total + value, 0) }\n : {}),\n reportingCalls,\n complete: calls.length > 0 && reportingCalls === calls.length,\n }\n}\n\nfunction nearestMeasurement(\n call: ExecutionMeasurementSpan,\n byId: Map<string, ExecutionMeasurementSpan>,\n callIds: Set<string>,\n aggregateSourceIds: Set<string>,\n keys: readonly string[],\n): { span: ExecutionMeasurementSpan; value: number } | undefined {\n let current: ExecutionMeasurementSpan | undefined = call\n const seen = new Set<string>()\n while (current && !seen.has(current.id)) {\n seen.add(current.id)\n const value = readNumber(current.attributes, keys)\n if (\n value !== undefined &&\n (current.id === call.id || (!callIds.has(current.id) && aggregateSourceIds.has(current.id)))\n ) {\n return { span: current, value }\n }\n current = current.parentId ? byId.get(current.parentId) : undefined\n }\n return undefined\n}\n\nfunction classifyAggregateSpans(\n candidates: ExecutionMeasurementSpan[],\n childrenById: Map<string, ExecutionMeasurementSpan[]>,\n): Set<string> {\n const aggregateIds = new Set<string>()\n const summaries = new Map<string, RetainedCallSummary>()\n const visiting = new Set<string>()\n\n const visit = (span: ExecutionMeasurementSpan): RetainedCallSummary => {\n const cached = summaries.get(span.id)\n if (cached) return cached\n if (visiting.has(span.id)) return emptyRetainedCallSummary()\n visiting.add(span.id)\n\n const descendants = emptyRetainedCallSummary()\n for (const child of childrenById.get(span.id) ?? []) {\n const childDescendants = visit(child)\n if (!aggregateIds.has(child.id)) addRetainedCall(descendants, child)\n addRetainedCallSummary(descendants, childDescendants)\n }\n\n if (\n descendants.callCount > 0 &&\n (!span.modelCall || hasCompatibleDescendantMeasurements(span, descendants))\n ) {\n aggregateIds.add(span.id)\n }\n\n visiting.delete(span.id)\n summaries.set(span.id, descendants)\n return descendants\n }\n\n for (const candidate of candidates) visit(candidate)\n return aggregateIds\n}\n\nfunction emptyRetainedCallSummary(): RetainedCallSummary {\n return {\n callCount: 0,\n measurements: EXECUTION_MEASUREMENT_KEY_GROUPS.map(() => ({\n total: 0,\n reportingCalls: 0,\n })),\n }\n}\n\nfunction addRetainedCall(summary: RetainedCallSummary, span: ExecutionMeasurementSpan): void {\n summary.callCount += 1\n for (let index = 0; index < EXECUTION_MEASUREMENT_KEY_GROUPS.length; index += 1) {\n const value = readNumber(span.attributes, EXECUTION_MEASUREMENT_KEY_GROUPS[index]!)\n if (value === undefined) continue\n const measurement = summary.measurements[index]!\n measurement.total += value\n measurement.reportingCalls += 1\n }\n}\n\nfunction addRetainedCallSummary(target: RetainedCallSummary, source: RetainedCallSummary): void {\n target.callCount += source.callCount\n for (let index = 0; index < target.measurements.length; index += 1) {\n const measurement = target.measurements[index]!\n const sourceMeasurement = source.measurements[index]!\n measurement.total += sourceMeasurement.total\n measurement.reportingCalls += sourceMeasurement.reportingCalls\n }\n}\n\nfunction hasCompatibleDescendantMeasurements(\n span: ExecutionMeasurementSpan,\n descendants: RetainedCallSummary,\n): boolean {\n let parentMeasurements = 0\n let descendantMeasurements = 0\n for (let index = 0; index < EXECUTION_MEASUREMENT_KEY_GROUPS.length; index += 1) {\n const keys = EXECUTION_MEASUREMENT_KEY_GROUPS[index]!\n const parentValue = readNumber(span.attributes, keys)\n const measurement = descendants.measurements[index]!\n if (parentValue !== undefined) parentMeasurements += 1\n if (measurement.reportingCalls > 0) descendantMeasurements += 1\n if (parentValue === undefined || measurement.reportingCalls === 0) continue\n if (measurement.reportingCalls !== descendants.callCount) continue\n if (Math.abs(parentValue - measurement.total) > 1e-12) return false\n }\n return parentMeasurements === 0 || descendantMeasurements > 0\n}\n\nfunction ancestorIds(\n span: ExecutionMeasurementSpan,\n byId: Map<string, ExecutionMeasurementSpan>,\n): string[] {\n const ids: string[] = []\n const seen = new Set<string>()\n let parentId = span.parentId\n while (parentId && !seen.has(parentId)) {\n ids.push(parentId)\n seen.add(parentId)\n parentId = byId.get(parentId)?.parentId\n }\n return ids\n}\n\nfunction nearestCandidateParent(\n span: ExecutionMeasurementSpan,\n byId: Map<string, ExecutionMeasurementSpan>,\n candidateIds: Set<string>,\n): string | undefined {\n const seen = new Set<string>()\n let parentId = span.parentId\n while (parentId && !seen.has(parentId)) {\n if (candidateIds.has(parentId)) return parentId\n seen.add(parentId)\n parentId = byId.get(parentId)?.parentId\n }\n return undefined\n}\n\nfunction readNumber(\n attributes: Record<string, unknown>,\n keys: readonly string[],\n): number | undefined {\n for (const key of keys) {\n const value = attributes[key]\n const parsed =\n typeof value === 'number'\n ? value\n : typeof value === 'string' && value.length > 0\n ? Number(value)\n : Number.NaN\n if (Number.isFinite(parsed) && parsed >= 0) return parsed\n }\n return undefined\n}\n","import { ValidationError } from '../errors'\nimport { FAILURE_CLASSES, type FailureClass } from './schema'\n\nconst TASK_FAILURE_CLASS_ATTR = 'tangle.task.failure_class'\nconst TASK_FAILURE_MODE_ATTR = 'tangle.task.failure_mode'\n\ninterface AttributeCarrier {\n attributes: Record<string, unknown>\n}\n\nexport type TaskFailureLabels =\n | { failureClass?: undefined; failureMode?: undefined }\n | { failureClass: 'success'; failureMode?: undefined }\n | { failureClass: Exclude<FailureClass, 'success'>; failureMode?: string }\n\nexport function readTaskFailureLabels(\n roots: readonly AttributeCarrier[],\n context: string,\n): TaskFailureLabels {\n const failureClass = readConsistentRootString(roots, TASK_FAILURE_CLASS_ATTR, context)\n const failureMode = readConsistentRootString(roots, TASK_FAILURE_MODE_ATTR, context)\n\n if (failureClass !== undefined && !FAILURE_CLASSES.includes(failureClass as FailureClass)) {\n throw new ValidationError(\n `${context}: ${TASK_FAILURE_CLASS_ATTR} must be one of ${FAILURE_CLASSES.join(', ')}`,\n )\n }\n if (failureMode !== undefined && (failureClass === undefined || failureClass === 'success')) {\n throw new ValidationError(\n `${context}: ${TASK_FAILURE_MODE_ATTR} requires a non-success ${TASK_FAILURE_CLASS_ATTR}`,\n )\n }\n\n if (failureClass === undefined) return {}\n if (failureClass === 'success') return { failureClass }\n return {\n failureClass: failureClass as Exclude<FailureClass, 'success'>,\n ...(failureMode ? { failureMode } : {}),\n }\n}\n\nfunction readConsistentRootString(\n roots: readonly AttributeCarrier[],\n key: string,\n context: string,\n): string | undefined {\n const values = new Set<string>()\n for (const root of roots) {\n if (!Object.hasOwn(root.attributes, key)) continue\n const value = root.attributes[key]\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new ValidationError(`${context}: ${key} must be a non-empty string`)\n }\n values.add(value)\n }\n\n if (values.size > 1) {\n throw new ValidationError(\n `${context}: conflicting ${key} values: ${[...values].sort().join(', ')}`,\n )\n }\n return values.values().next().value\n}\n","/**\n * Provider response and SSE usage extraction.\n *\n * Missing usage returns `null`; reported zeroes and cache-only activity remain\n * distinguishable from absent telemetry.\n */\n\nimport { SSEChunkParser } from '@tangle-network/agent-core/sse'\nimport {\n firstTokenCount,\n TOKEN_USAGE_INPUT_KEYS,\n TOKEN_USAGE_OUTPUT_KEYS,\n tokenUsageSource,\n} from '@tangle-network/agent-core/telemetry'\nimport type { RunTokenUsage } from '../run-record'\n\nexport type ExtractedUsage = RunTokenUsage\nexport type SseUsageMode = 'cumulative' | 'delta'\n\nexport interface ExtractUsageFromSseOptions {\n /** Provider usage events are cumulative snapshots unless explicitly marked as deltas. */\n mode?: SseUsageMode\n}\n\nconst INPUT_OTHER_KEYS = ['input_other'] as const\nconst EXCLUSIVE_REASONING_KEYS = ['reasoning', 'reasoning_tokens', 'reasoningTokens'] as const\nconst INCLUSIVE_REASONING_KEYS = ['reasoning_output_tokens', 'reasoningOutputTokens'] as const\nconst INPUT_DETAIL_KEYS = ['prompt_tokens_details', 'input_tokens_details'] as const\nconst OUTPUT_DETAIL_KEYS = ['completion_tokens_details', 'output_tokens_details'] as const\nconst CACHED_KEYS = [\n 'cache',\n 'cached_tokens',\n 'cached_input_tokens',\n 'cache_read_tokens',\n 'cache_read_input_tokens',\n 'cachedTokens',\n 'cachedInputTokens',\n 'cacheReadTokens',\n 'cacheReadInputTokens',\n 'input_cache_read',\n] as const\nconst CACHE_WRITE_KEYS = [\n 'cache_creation_tokens',\n 'cache_creation_input_tokens',\n 'cacheCreationTokens',\n 'cacheCreationInputTokens',\n 'input_cache_creation',\n] as const\n\nfunction nestedRecord(\n source: Record<string, unknown>,\n key: string,\n): Record<string, unknown> | undefined {\n const value = source[key]\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n}\n\nfunction nestedNumber(\n source: Record<string, unknown>,\n recordKeys: readonly string[],\n valueKeys: readonly string[],\n): number | undefined {\n for (const recordKey of recordKeys) {\n const value = firstTokenCount(nestedRecord(source, recordKey), valueKeys)\n if (value !== undefined) return value\n }\n return undefined\n}\n\n/**\n * Pull `{ input, output, cached?, cacheWrite? }` from a parsed response\n * body. Accepts a top-level `usage` object (the common case) or a body that IS\n * the usage object. Returns null only when none of those categories is present.\n */\nexport function extractUsage(body: unknown): ExtractedUsage | null {\n if (!body || typeof body !== 'object') return null\n const obj = body as Record<string, unknown>\n const usage = tokenUsageSource(obj)\n const input = firstTokenCount(usage, TOKEN_USAGE_INPUT_KEYS)\n const inputOther = firstTokenCount(usage, INPUT_OTHER_KEYS)\n const output = firstTokenCount(usage, TOKEN_USAGE_OUTPUT_KEYS)\n const exclusiveReasoning = firstTokenCount(usage, EXCLUSIVE_REASONING_KEYS)\n const inclusiveReasoning =\n firstTokenCount(usage, INCLUSIVE_REASONING_KEYS) ??\n nestedNumber(usage, OUTPUT_DETAIL_KEYS, ['reasoning_tokens', 'reasoningTokens'])\n const reasoning = exclusiveReasoning ?? inclusiveReasoning\n const nestedCache = nestedRecord(usage, 'cache')\n const cached =\n firstTokenCount(usage, CACHED_KEYS) ??\n firstTokenCount(nestedCache, ['read']) ??\n nestedNumber(usage, INPUT_DETAIL_KEYS, ['cached_tokens', 'cachedTokens'])\n const cacheWrite =\n firstTokenCount(usage, CACHE_WRITE_KEYS) ?? firstTokenCount(nestedCache, ['write'])\n if (\n input === undefined &&\n inputOther === undefined &&\n output === undefined &&\n reasoning === undefined &&\n cached === undefined &&\n cacheWrite === undefined\n )\n return null\n const result: ExtractedUsage = {\n input: (input ?? 0) + (inputOther ?? 0),\n output:\n (output ?? (inclusiveReasoning !== undefined ? inclusiveReasoning : 0)) +\n (exclusiveReasoning ?? 0),\n }\n if (reasoning !== undefined) result.reasoning = reasoning\n if (cached !== undefined) result.cached = cached\n if (cacheWrite !== undefined) result.cacheWrite = cacheWrite\n return result\n}\n\n/**\n * Extract token usage from a complete SSE response body using the shared SSE\n * frame parser. Cumulative snapshots are the fail-safe default because summing\n * them inflates billing; callers with explicit delta events opt into `mode: 'delta'`.\n */\nexport function extractUsageFromSse(\n text: string,\n options: ExtractUsageFromSseOptions = {},\n): ExtractedUsage | null {\n const mode = options.mode ?? 'cumulative'\n let input = 0\n let output = 0\n let reasoning = 0\n let sawReasoning = false\n let cached = 0\n let sawCached = false\n let cacheWrite = 0\n let sawCacheWrite = false\n let found = false\n const parser = new SSEChunkParser<unknown>({ transform: parseSseJson })\n const events = [...parser.push(text), ...parser.flush()]\n const merge = mode === 'delta' ? (current: number, next: number) => current + next : Math.max\n\n for (const event of events) {\n const usage = extractUsage(event.data)\n if (!usage) continue\n input = merge(input, usage.input)\n output = merge(output, usage.output)\n if (usage.reasoning !== undefined) {\n reasoning = merge(reasoning, usage.reasoning)\n sawReasoning = true\n }\n if (usage.cached !== undefined) {\n cached = merge(cached, usage.cached)\n sawCached = true\n }\n if (usage.cacheWrite !== undefined) {\n cacheWrite = merge(cacheWrite, usage.cacheWrite)\n sawCacheWrite = true\n }\n found = true\n }\n if (!found) return null\n return {\n input,\n output,\n ...(sawReasoning ? { reasoning } : {}),\n ...(sawCached ? { cached } : {}),\n ...(sawCacheWrite ? { cacheWrite } : {}),\n }\n}\n\nfunction parseSseJson(raw: string): unknown | null {\n const payload = raw.trim()\n if (!payload || payload === '[DONE]') return null\n try {\n return JSON.parse(payload)\n } catch {\n return null\n }\n}\n\n/**\n * Extract usage from an HTTP `Response` without consuming the caller's body:\n * clones, reads the text, and tries the JSON parser first, then the SSE\n * accumulator. Best-effort — returns null on any read/parse miss so a usage tee\n * never takes down the underlying call.\n */\nexport async function extractUsageFromResponse(\n response: Response,\n sseOptions?: ExtractUsageFromSseOptions,\n): Promise<ExtractedUsage | null> {\n let text: string\n try {\n text = await response.clone().text()\n } catch {\n return null\n }\n let json: unknown\n try {\n json = JSON.parse(text)\n } catch {\n json = undefined\n }\n return extractUsage(json) ?? extractUsageFromSse(text, sseOptions)\n}\n"],"mappings":"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"}
|