@mastra/core
Version:
1 lines • 35.8 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","names":["MastraError","createStep","z","MastraError","ErrorDomain","ErrorCategory","getEntityTypeForSpan","saveScorePayloadSchema","createWorkflow"],"sources":["../../../src/evals/scoreTraces/scoreTraces.ts","../../../src/evals/scoreTraces/utils.ts","../../../src/evals/scoreTraces/scoreTracesWorkflow.ts"],"sourcesContent":["import { MastraError } from '../../error';\nimport type { Mastra } from '../../mastra';\n\nexport async function scoreTraces({\n scorerId,\n targets,\n mastra,\n}: {\n scorerId: string;\n targets: { traceId: string; spanId?: string }[];\n mastra: Mastra;\n}) {\n const workflow = mastra.__getInternalWorkflow('__batch-scoring-traces');\n try {\n const run = await workflow.createRun();\n\n await run.start({ inputData: { targets, scorerId } });\n } catch (error) {\n const mastraError = new MastraError(\n {\n category: 'SYSTEM',\n domain: 'SCORER',\n id: 'MASTRA_SCORER_FAILED_TO_RUN_TRACE_SCORING',\n details: {\n scorerId,\n targets: JSON.stringify(targets),\n },\n },\n error,\n );\n mastra.getLogger()?.trackException(mastraError);\n }\n}\n","import type { MastraDBMessage } from '../../agent';\nimport { SpanType } from '../../observability';\nimport type { SpanRecord, TraceRecord } from '../../storage';\nimport type { ScorerRunInputForAgent, ScorerRunOutputForAgent } from '../types';\n\n// Types for span input/output structures\ninterface SpanMessage {\n role: string;\n content: string | Array<{ type: string; text: string }>;\n}\n\ninterface SpanInputWithMessages {\n messages: SpanMessage[];\n}\n\ninterface SpanOutputWithText {\n text?: string;\n}\n\n// Type guards for span data\nfunction isSpanMessage(value: unknown): value is SpanMessage {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'role' in value &&\n typeof (value as SpanMessage).role === 'string' &&\n 'content' in value\n );\n}\n\nfunction hasMessagesArray(value: unknown): value is SpanInputWithMessages {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'messages' in value &&\n Array.isArray((value as SpanInputWithMessages).messages)\n );\n}\n\nfunction hasTextProperty(value: unknown): value is SpanOutputWithText {\n return typeof value === 'object' && value !== null && 'text' in value;\n}\n\n// // Span tree structure for efficient lookups\ninterface SpanTree {\n spanMap: Map<string, SpanRecord>;\n childrenMap: Map<string, SpanRecord[]>;\n rootSpans: SpanRecord[];\n}\n\n/**\n * Build a hierarchical span tree with efficient lookup maps\n */\nexport function buildSpanTree(spans: SpanRecord[]): SpanTree {\n const spanMap = new Map<string, SpanRecord>();\n const childrenMap = new Map<string, SpanRecord[]>();\n const rootSpans: SpanRecord[] = [];\n\n // First pass: build span map\n for (const span of spans) {\n spanMap.set(span.spanId, span);\n }\n\n // Second pass: build parent-child relationships\n for (const span of spans) {\n if (span.parentSpanId == null) {\n // Root span (parentSpanId is null or undefined)\n rootSpans.push(span);\n } else {\n const siblings = childrenMap.get(span.parentSpanId) || [];\n siblings.push(span);\n childrenMap.set(span.parentSpanId, siblings);\n }\n }\n\n // Sort children by startedAt timestamp for temporal ordering\n for (const children of childrenMap.values()) {\n children.sort((a, b) => new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime());\n }\n\n // Sort root spans by startedAt\n rootSpans.sort((a, b) => new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime());\n\n return { spanMap, childrenMap, rootSpans };\n}\n\n/**\n * Extract children spans of a specific type\n */\nfunction getChildrenOfType<T extends SpanRecord>(spanTree: SpanTree, parentSpanId: string, spanType: SpanType): T[] {\n const children = spanTree.childrenMap.get(parentSpanId) || [];\n return children.filter(span => span.spanType === spanType) as T[];\n}\n\n/**\n * Normalize message content to string format\n * For arrays with multiple text parts, returns only the last text part (AI SDK convention)\n */\nfunction normalizeMessageContent(content: string | Array<{ type: string; text: string }>): string {\n if (typeof content === 'string') {\n return content;\n }\n\n // Extract text parts and return only the last one (AI SDK convention)\n const textParts = content.filter(part => part.type === 'text');\n return textParts.length > 0 ? textParts[textParts.length - 1]?.text || '' : '';\n}\n\n/**\n * Create MastraDBMessage directly from span message data\n */\nfunction createMastraDBMessage(\n message: { role: string; content: string | Array<{ type: string; text: string }> },\n createdAt: Date,\n id: string = '',\n): MastraDBMessage {\n const contentText = normalizeMessageContent(message.content);\n const role = message.role as 'user' | 'assistant' | 'system';\n\n return {\n id,\n role,\n content: {\n format: 2,\n parts: [{ type: 'text', text: contentText }],\n content: contentText,\n },\n createdAt: new Date(createdAt),\n };\n}\n\n/**\n * Extract input messages from agent run span\n */\nfunction extractInputMessages(agentSpan: SpanRecord): MastraDBMessage[] {\n const input = agentSpan.input;\n\n // Handle different input formats\n if (typeof input === 'string') {\n return [\n createMastraDBMessage(\n {\n role: 'user',\n content: input,\n },\n agentSpan.startedAt,\n ),\n ];\n }\n\n if (Array.isArray(input)) {\n const messages = input.filter(isSpanMessage) as SpanMessage[];\n return messages.map(msg => createMastraDBMessage(msg, agentSpan.startedAt));\n }\n\n if (hasMessagesArray(input)) {\n const messages = input.messages.filter(isSpanMessage) as SpanMessage[];\n return messages.map(msg => createMastraDBMessage(msg, agentSpan.startedAt));\n }\n return [];\n}\n\n/**\n * Extract system messages from LLM span\n */\nfunction extractSystemMessages(llmSpan: SpanRecord): Array<{ role: 'system'; content: string }> {\n const input = llmSpan.input;\n if (!hasMessagesArray(input)) {\n return [];\n }\n return input.messages\n .filter((msg): msg is SpanMessage & { role: 'system' } => isSpanMessage(msg) && msg.role === 'system')\n .map(msg => ({\n role: 'system' as const,\n content: normalizeMessageContent(msg.content),\n }));\n}\n\n/**\n * Extract conversation history (remembered messages) from LLM span\n * Excludes system messages and the current input message\n */\nfunction extractRememberedMessages(llmSpan: SpanRecord, currentInputContent: string): MastraDBMessage[] {\n const input = llmSpan.input;\n if (!hasMessagesArray(input)) {\n return [];\n }\n const filtered = input.messages.filter(isSpanMessage) as unknown as SpanMessage[];\n const messages = filtered\n .filter(msg => msg.role !== 'system')\n .filter(msg => normalizeMessageContent(msg.content) !== currentInputContent);\n\n return messages.map(msg => createMastraDBMessage(msg, llmSpan.startedAt));\n}\n\n/**\n * Reconstruct tool invocations from tool call spans\n */\nfunction reconstructToolInvocations(spanTree: SpanTree, parentSpanId: string) {\n const toolSpans = getChildrenOfType<SpanRecord>(spanTree, parentSpanId, SpanType.TOOL_CALL);\n\n return toolSpans.map(toolSpan => ({\n toolCallId: toolSpan.spanId,\n toolName: toolSpan.entityName ?? toolSpan.entityId ?? 'unknown',\n toolId: toolSpan.entityId,\n args: toolSpan.input || {},\n result: toolSpan.output || {},\n state: 'result' as const,\n }));\n}\n\n/**\n * Validate trace structure and throw descriptive errors\n */\nexport function validateTrace(trace: TraceRecord): void {\n if (!trace) {\n throw new Error('Trace is null or undefined');\n }\n\n if (!trace.spans || !Array.isArray(trace.spans)) {\n throw new Error('Trace must have a spans array');\n }\n\n if (trace.spans.length === 0) {\n throw new Error('Trace has no spans');\n }\n\n // Check for circular references in parent-child relationships\n const spanIds = new Set(trace.spans.map(span => span.spanId));\n for (const span of trace.spans) {\n if (span.parentSpanId && !spanIds.has(span.parentSpanId)) {\n throw new Error(`Span ${span.spanId} references non-existent parent ${span.parentSpanId}`);\n }\n }\n}\n\n/**\n * Find the most recent model span that contains conversation history\n */\nfunction findPrimaryLLMSpan(spanTree: SpanTree, rootAgentSpan: SpanRecord): SpanRecord {\n const directLLMSpans = getChildrenOfType<SpanRecord>(spanTree, rootAgentSpan.spanId, SpanType.MODEL_GENERATION);\n if (directLLMSpans.length > 0) {\n // There should only be one model generation span per agent run which is a direct child of the root agent span\n return directLLMSpans[0]!;\n }\n\n throw new Error('No model generation span found in trace');\n}\n\n/**\n * Extract common trace validation and span tree building logic\n */\nfunction prepareTraceForTransformation(trace: TraceRecord) {\n validateTrace(trace);\n const spanTree = buildSpanTree(trace.spans);\n\n // Find the root agent run span\n const rootAgentSpan = spanTree.rootSpans.find(span => span.spanType === 'agent_run') as SpanRecord | undefined;\n\n if (!rootAgentSpan) {\n throw new Error('No root agent_run span found in trace');\n }\n\n return { spanTree, rootAgentSpan };\n}\n\nexport function transformTraceToScorerInputAndOutput(trace: TraceRecord): {\n input: ScorerRunInputForAgent;\n output: ScorerRunOutputForAgent;\n} {\n const { spanTree, rootAgentSpan } = prepareTraceForTransformation(trace);\n\n if (!rootAgentSpan.output) {\n throw new Error('Root agent span has no output');\n }\n\n // Build input\n const primaryLLMSpan = findPrimaryLLMSpan(spanTree, rootAgentSpan);\n const inputMessages = extractInputMessages(rootAgentSpan);\n const systemMessages = extractSystemMessages(primaryLLMSpan);\n\n // Extract remembered messages from LLM span (excluding current input)\n const currentInputContent = inputMessages[0]?.content.content || '';\n const rememberedMessages = extractRememberedMessages(primaryLLMSpan, currentInputContent);\n\n const input = {\n inputMessages,\n rememberedMessages,\n systemMessages,\n taggedSystemMessages: {}, // Todo: Support tagged system messages\n };\n\n // Build output\n const toolInvocations = reconstructToolInvocations(spanTree, rootAgentSpan.spanId);\n const responseText = hasTextProperty(rootAgentSpan.output) ? (rootAgentSpan.output.text ?? '') : '';\n\n // Build parts array: tool invocations first, then text\n const parts: Array<{ type: 'tool-invocation'; toolInvocation: any } | { type: 'text'; text: string }> = [];\n\n // Add tool invocation parts\n for (const toolInvocation of toolInvocations) {\n parts.push({\n type: 'tool-invocation',\n toolInvocation,\n });\n }\n\n // Add text part if present\n if (responseText.trim()) {\n parts.push({\n type: 'text',\n text: responseText,\n });\n }\n\n const responseMessage: MastraDBMessage = {\n id: '',\n role: 'assistant',\n content: {\n format: 2,\n parts: parts as any, // Type assertion needed due to providerMetadata optional field\n content: responseText,\n toolInvocations, // Always include, even if empty array\n },\n createdAt: new Date(rootAgentSpan.endedAt || rootAgentSpan.startedAt),\n };\n\n const output: MastraDBMessage[] = [responseMessage];\n\n return {\n input,\n output,\n };\n}\n","import pMap from 'p-map';\nimport { z } from 'zod/v4';\nimport { ErrorCategory, ErrorDomain, MastraError } from '../../error';\nimport { getEntityTypeForSpan, InternalSpans } from '../../observability';\nimport type { SpanRecord, TraceRecord, MastraStorage } from '../../storage';\nimport { createStep, createWorkflow } from '../../workflows/evented';\nimport type { MastraScorer, ScorerRun } from '../base';\nimport type { ScoreRowData } from '../types';\nimport { saveScorePayloadSchema } from '../types';\nimport { transformTraceToScorerInputAndOutput } from './utils';\n\nconst getTraceStep = createStep({\n id: '__process-trace-scoring',\n inputSchema: z.object({\n targets: z.array(\n z.object({\n traceId: z.string(),\n spanId: z.string().optional(),\n }),\n ),\n scorerId: z.string(),\n }),\n outputSchema: z.any(),\n execute: async ({ inputData, mastra }) => {\n const logger = mastra.getLogger();\n if (!logger) {\n console.warn(\n '[scoreTracesWorkflow] Logger not initialized: no debug or error logs will be recorded for scoring traces.',\n );\n }\n\n const storage = mastra.getStorage();\n if (!storage) {\n const mastraError = new MastraError({\n id: 'MASTRA_STORAGE_NOT_FOUND_FOR_TRACE_SCORING',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.SYSTEM,\n text: 'Storage not found for trace scoring',\n details: {\n scorerId: inputData.scorerId,\n },\n });\n logger?.trackException(mastraError);\n return;\n }\n\n let scorer: MastraScorer | undefined;\n try {\n scorer = mastra.getScorerById(inputData.scorerId);\n } catch (error) {\n const mastraError = new MastraError(\n {\n id: 'MASTRA_SCORER_NOT_FOUND_FOR_TRACE_SCORING',\n domain: ErrorDomain.SCORER,\n category: ErrorCategory.SYSTEM,\n text: `Scorer not found for trace scoring`,\n details: {\n scorerId: inputData.scorerId,\n },\n },\n error,\n );\n logger?.trackException(mastraError);\n return;\n }\n\n await pMap(\n inputData.targets,\n async target => {\n try {\n await scoreTrace({ storage, scorer, target });\n } catch (error) {\n const mastraError = new MastraError(\n {\n id: 'MASTRA_SCORER_FAILED_TO_RUN_SCORER_ON_TRACE',\n domain: ErrorDomain.SCORER,\n category: ErrorCategory.SYSTEM,\n details: {\n scorerId: scorer.id,\n spanId: target.spanId || '',\n traceId: target.traceId,\n },\n },\n error,\n );\n logger?.trackException(mastraError);\n }\n },\n { concurrency: 3 },\n );\n },\n});\n\n/** Tenancy derived from a span, threaded into emitted scores. */\ntype ScoreTenancy = {\n organizationId?: string;\n projectId?: string;\n};\n\n/**\n * Derive score tenancy from a span. On spans, `resourceId` carries the project\n * scope, so it maps to the score's `projectId` field.\n */\nfunction getSpanTenancy(span: SpanRecord): ScoreTenancy {\n const tenancy: ScoreTenancy = {};\n if (span.organizationId) {\n tenancy.organizationId = span.organizationId;\n }\n if (span.resourceId) {\n tenancy.projectId = span.resourceId;\n }\n return tenancy;\n}\n\nexport type ScoreTraceTarget = { traceId: string; spanId?: string } | { trace: TraceRecord; spanId?: string };\n\nexport type ScoreTraceBatchTarget = {\n traceId: string;\n spanId?: string;\n datasetItemId?: string;\n};\n\nexport type ScoreTraceBatchResult =\n | {\n ok: true;\n index: number;\n traceId: string;\n spanId: string;\n datasetItemId?: string;\n score: ScoreRowData;\n }\n | {\n ok: false;\n index: number;\n traceId: string;\n spanId?: string;\n datasetItemId?: string;\n error: Error;\n };\n\ntype ScoreTraceReferenceTarget = { traceId: string; spanId?: string };\n\nfunction isScoreTraceReferenceTarget(target: ScoreTraceTarget): target is ScoreTraceReferenceTarget {\n return 'traceId' in target;\n}\n\nfunction resolveTargetSpan({ trace, spanId }: { trace: TraceRecord; spanId?: string }): SpanRecord {\n const span = spanId\n ? trace.spans.find(candidateSpan => candidateSpan.spanId === spanId)\n : trace.spans.find(candidateSpan => candidateSpan.parentSpanId === null);\n\n if (!span) {\n throw new Error(`Span not found for scoring, traceId: ${trace.traceId}, spanId: ${spanId ?? 'Not provided'}`);\n }\n\n return span;\n}\n\n/** Resolve the target span for a trace/target pair. */\nasync function resolveTraceAndSpan({\n storage,\n target,\n}: {\n storage: MastraStorage;\n target: ScoreTraceTarget;\n}): Promise<{ trace: TraceRecord; span: SpanRecord }> {\n if (!isScoreTraceReferenceTarget(target)) {\n return {\n trace: target.trace,\n span: resolveTargetSpan({ trace: target.trace, spanId: target.spanId }),\n };\n }\n\n // TODO: add storage api to get a single span\n const observabilityStore = await storage.getStore('observability');\n if (!observabilityStore) {\n throw new MastraError({\n id: 'MASTRA_OBSERVABILITY_STORAGE_NOT_AVAILABLE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.SYSTEM,\n text: 'Observability storage domain is not available',\n });\n }\n const trace = await observabilityStore.getTrace({ traceId: target.traceId });\n if (!trace) {\n throw new Error(`Trace not found for scoring, traceId: ${target.traceId}`);\n }\n\n return { trace, span: resolveTargetSpan({ trace, spanId: target.spanId }) };\n}\n\ntype TraceScoreResult = Awaited<ReturnType<MastraScorer['run']>>;\n\n/**\n * Run a scorer against an already-resolved trace + span.\n *\n * Span tenancy (`organizationId`, `resourceId` → `projectId`) is threaded into\n * the scorer run so any score the scorer emits is correctly multi-tenant.\n */\nasync function runScorerForTrace({\n scorer,\n trace,\n span,\n}: {\n scorer: MastraScorer;\n trace: TraceRecord;\n span: SpanRecord;\n}): Promise<TraceScoreResult> {\n const tenancy = getSpanTenancy(span);\n\n const scorerRun = buildScorerRun({\n scorerType: scorer.type === 'agent' ? 'agent' : undefined,\n trace,\n targetSpan: span,\n });\n\n return scorer.run({\n ...scorerRun,\n scoreSource: 'trace',\n targetScope: 'span',\n targetEntityType: getEntityTypeForSpan(span),\n targetTraceId: trace.traceId,\n targetSpanId: span.spanId,\n targetCorrelationContext: {\n traceId: trace.traceId,\n spanId: span.spanId,\n ...(tenancy.organizationId ? { organizationId: tenancy.organizationId } : {}),\n ...(tenancy.projectId ? { resourceId: tenancy.projectId } : {}),\n },\n targetMetadata: {\n ...(tenancy.organizationId ? { organizationId: tenancy.organizationId } : {}),\n ...(tenancy.projectId ? { projectId: tenancy.projectId } : {}),\n },\n });\n}\n\n/**\n * Resolve a trace/span target, run the scorer, and persist the resulting score.\n */\nexport async function scoreTrace({\n storage,\n scorer,\n target,\n batchId,\n datasetId,\n datasetItemId,\n}: {\n storage: MastraStorage;\n scorer: MastraScorer;\n target: ScoreTraceTarget;\n /** Optional batch handle stamped on the persisted score so all scores from one\n * batch scoring call share a `batchId` (each keeps its own per-execution `runId`). */\n batchId?: string;\n /** Optional dataset provenance stamped on the persisted score so baseline scores\n * can join back to the curated dataset item that produced them. Top-level handles,\n * independent of how the trace is resolved. */\n datasetId?: string;\n datasetItemId?: string;\n}): Promise<ScoreRowData> {\n const { trace, span } = await resolveTraceAndSpan({ storage, target });\n const tenancy = getSpanTenancy(span);\n\n const result = await runScorerForTrace({ scorer, trace, span });\n\n const scorerResult = {\n ...result,\n scorer: {\n id: scorer.id,\n name: scorer.name || scorer.id,\n description: scorer.description,\n hasJudge: !!scorer.judge,\n },\n traceId: trace.traceId,\n spanId: span.spanId,\n entityId: span.entityId || span.entityName || 'unknown',\n entityType: span.spanType,\n entity: { traceId: span.traceId, spanId: span.spanId },\n source: 'TEST',\n scorerId: scorer.id,\n ...(tenancy.organizationId ? { organizationId: tenancy.organizationId } : {}),\n ...(tenancy.projectId ? { projectId: tenancy.projectId } : {}),\n ...(batchId ? { batchId } : {}),\n ...(datasetId ? { datasetId } : {}),\n ...(datasetItemId ? { datasetItemId } : {}),\n };\n\n // Legacy score-store emission. This path is being deprecated.\n const savedScoreRecord = await validateAndSaveScore({ storage, scorerResult });\n await attachScoreToSpan({ storage, span, scoreRecord: savedScoreRecord });\n return savedScoreRecord;\n}\n\nfunction toBatchResultError(error: unknown): Error {\n if (error instanceof Error) {\n return error;\n }\n\n return new Error(typeof error === 'string' ? error : 'Unknown scoreTraceBatch error');\n}\n\nexport async function scoreTraceBatch({\n storage,\n scorer,\n targets,\n batchId,\n datasetId,\n concurrency = 3,\n}: {\n storage: MastraStorage;\n scorer: MastraScorer;\n targets: ScoreTraceBatchTarget[];\n batchId?: string;\n datasetId?: string;\n concurrency?: number;\n}): Promise<{\n batchId?: string;\n datasetId?: string;\n scoredCount: number;\n failedCount: number;\n results: ScoreTraceBatchResult[];\n}> {\n const results = await pMap(\n targets,\n async (target, index): Promise<ScoreTraceBatchResult> => {\n try {\n const score = await scoreTrace({\n storage,\n scorer,\n target,\n batchId,\n datasetId,\n datasetItemId: target.datasetItemId,\n });\n const spanId = score.spanId ?? target.spanId;\n\n if (!spanId) {\n throw new Error(`Persisted score is missing spanId for traceId: ${target.traceId}`);\n }\n\n return {\n ok: true,\n index,\n traceId: score.traceId ?? target.traceId,\n spanId,\n ...(target.datasetItemId ? { datasetItemId: target.datasetItemId } : {}),\n score,\n };\n } catch (error) {\n return {\n ok: false,\n index,\n traceId: target.traceId,\n ...(target.spanId ? { spanId: target.spanId } : {}),\n ...(target.datasetItemId ? { datasetItemId: target.datasetItemId } : {}),\n error: toBatchResultError(error),\n };\n }\n },\n { concurrency },\n );\n\n const scoredCount = results.filter(result => result.ok).length;\n\n return {\n ...(batchId ? { batchId } : {}),\n ...(datasetId ? { datasetId } : {}),\n scoredCount,\n failedCount: results.length - scoredCount,\n results,\n };\n}\n\n/**\n * @deprecated Legacy scores-store path. New score emission should use `mastra.observability.addScore()`.\n */\nasync function validateAndSaveScore({ storage, scorerResult }: { storage: MastraStorage; scorerResult: ScorerRun }) {\n const scoresStore = await storage.getStore('scores');\n if (!scoresStore) {\n throw new MastraError({\n id: 'MASTRA_SCORES_STORAGE_NOT_AVAILABLE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.SYSTEM,\n text: 'Scores storage domain is not available',\n });\n }\n const payloadToSave = saveScorePayloadSchema.parse(scorerResult);\n const result = await scoresStore.saveScore(payloadToSave);\n return result.score;\n}\n\nfunction buildScorerRun({\n scorerType,\n trace,\n targetSpan,\n}: {\n scorerType?: string;\n trace: TraceRecord;\n targetSpan: SpanRecord;\n}): ScorerRun {\n if (scorerType === 'agent') {\n const { input, output } = transformTraceToScorerInputAndOutput(trace);\n return { input, output };\n }\n return { input: targetSpan.input, output: targetSpan.output };\n}\n\n/**\n * @deprecated Legacy score-attach path. New score emission should use `mastra.observability.addScore()`\n * which autmatically attach scores to spans.\n */\nasync function attachScoreToSpan({\n storage,\n span,\n scoreRecord,\n}: {\n storage: MastraStorage;\n span: SpanRecord;\n scoreRecord: ScoreRowData;\n}) {\n const observabilityStore = await storage.getStore('observability');\n if (!observabilityStore) {\n throw new MastraError({\n id: 'MASTRA_OBSERVABILITY_STORAGE_NOT_AVAILABLE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.SYSTEM,\n text: 'Observability storage domain is not available',\n });\n }\n\n // Path 1: Legacy — attach score link to span\n try {\n const existingLinks = span.links || [];\n const link = {\n type: 'score',\n scoreId: scoreRecord.id,\n scorerId: scoreRecord.scorerId ?? scoreRecord.scorer?.id,\n score: scoreRecord.score,\n createdAt: scoreRecord.createdAt,\n };\n await observabilityStore.updateSpan({\n spanId: span.spanId,\n traceId: span.traceId,\n updates: { links: [...existingLinks, link] },\n });\n } catch {\n // Expected for event-sourced stores (e.g. DuckDB) that don't support updateSpan\n }\n}\n\nexport const scoreTracesWorkflow = createWorkflow({\n id: '__batch-scoring-traces',\n inputSchema: z.object({\n targets: z.array(\n z.object({\n traceId: z.string(),\n spanId: z.string().optional(),\n }),\n ),\n scorerId: z.string(),\n }),\n outputSchema: z.any(),\n steps: [getTraceStep],\n options: {\n validateInputs: false,\n // Internal batch-scoring plumbing — hide its workflow spans from exported\n // traces. Any user-facing work invoked from steps (e.g. the scorer's own\n // SCORER_RUN span) keeps its own policy and remains visible.\n tracingPolicy: {\n internal: InternalSpans.WORKFLOW,\n },\n },\n});\n\nscoreTracesWorkflow.then(getTraceStep).commit();\n"],"mappings":"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"}