UNPKG

ai-functions

Version:

Core AI primitives for building intelligent applications

103 lines 4.24 kB
/** * traceMiddleware — emit per-call trace events for `wrapLanguageModel` * * Wraps `doGenerate` / `doStream` and emits a {@link TraceEvent} on every * completion. The sink is opaque (caller supplies `emit`) so this primitive * works equally well piping into: * * - the v3 cascade-walker InvocationEvent stream (round 16+ work to add * `'persona-trace'` / `'cascade-trace'` to the union), * - an {@link import('../eval-log/index.js').EvalLogStore} for fixture * replay, * - OpenTelemetry / Datadog / Honeycomb adapters that map the event into * a span. * * **Emit-error tolerance:** if the supplied `emit` throws, we *swallow* the * error (with a one-time `console.warn`) so a flaky trace sink can never * break the wrapped LLM call. This matches the Evalite v0.19 trace * middleware behaviour. * * Composition note: install **last** so the event sees the final outcome * (post-cache, post-budget). The event's `costUsd` field is best-effort — * the trace middleware doesn't have direct access to the budget tracker, so * the caller can pass a `getCostUsd` resolver if they want costs in the * event payload. * * @packageDocumentation */ import type { LanguageModelV3Middleware, LanguageModelV3Usage } from '@ai-sdk/provider'; /** * Discriminator for the originating call site. Callers inject this via the * `kind` option so a single sink can fan events into different downstream * streams (persona panel vs. cascade walker vs. ad-hoc test). */ export type TraceEventKind = 'persona-trace' | 'cascade-trace' | 'eval-trace' | string; /** * Trace event payload emitted on every wrapped call completion. * * Field design notes: * - `prompt` / `response` are stringified for cheap downstream storage * (the structured `LanguageModelV3Prompt` / `LanguageModelV3Content[]` * shapes are intentionally flattened). * - `usage` is the raw V3 shape (with the cache breakdown) — the * EvalLogStore consumer flattens it into total counts. * - `costUsd` is optional because the trace middleware doesn't compute * cost itself; callers either pass a resolver or compute downstream * from `usage`. */ export interface TraceEvent { kind: TraceEventKind; model: string; prompt: string; response: string; usage: LanguageModelV3Usage | undefined; costUsd?: number; durationMs: number; /** Optional caller-supplied tags for downstream filtering. */ tags?: Record<string, string>; } /** Options for {@link traceMiddleware}. */ export interface TraceMiddlewareOptions { /** * Opaque sink. Errors thrown from `emit` are swallowed (with a one-time * `console.warn`) so a flaky sink never breaks the wrapped LLM call. */ emit: (event: TraceEvent) => void | Promise<void>; /** * Discriminator threaded into the event's `kind` field. Defaults to * `'eval-trace'`. */ kind?: TraceEventKind; /** * Optional cost resolver. When supplied, called with the V3 usage shape * and the modelId; result is set on `event.costUsd`. Useful when the * caller has a side-channel pricing table (the budgetMiddleware's * tracker) and wants costs in the trace event itself. */ getCostUsd?: (modelId: string, usage: LanguageModelV3Usage | undefined) => number; /** Optional caller-supplied tags merged into every emitted event. */ tags?: Record<string, string>; } /** * Build a trace middleware for `wrapLanguageModel`. Emits a * {@link TraceEvent} on every successful `doGenerate` / `doStream` * completion. Errors from `emit` are swallowed (one-time warn) so a flaky * trace sink can never break the wrapped LLM call. * * @example * ```ts * import { wrapLanguageModel } from 'ai' * import { traceMiddleware, getEvalLogStore } from 'ai-functions' * * const store = getEvalLogStore() * const model = wrapLanguageModel({ * model: openai('gpt-4o'), * middleware: traceMiddleware({ * kind: 'cascade-trace', * emit: (event) => store.record({ ...event, costUsd: event.costUsd ?? 0 }), * }), * }) * ``` */ export declare function traceMiddleware(options: TraceMiddlewareOptions): LanguageModelV3Middleware; //# sourceMappingURL=trace.d.ts.map