@vitest-evals/harness-ai-sdk 0.9.0 → 0.11.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/README.md CHANGED
@@ -89,24 +89,24 @@ const harness = aiSdkHarness({
89
89
  ```
90
90
 
91
91
  `run` executes the system under test. Judges are created separately; keep judge
92
- prompts and model calls in the judge instead of putting a judge model call on
93
- the app harness.
92
+ prompts and model calls on a judge harness instead of putting them on the app
93
+ harness.
94
94
 
95
95
  ```ts
96
- const FactualityJudge = createJudge(
97
- "FactualityJudge",
98
- async (ctx: JudgeContext<string, RefundDecision>) => {
99
- const verdict = await generateText({
100
- model: openai("gpt-4o-mini"),
101
- prompt: formatJudgePrompt({
102
- input: ctx.input,
103
- output: ctx.output,
104
- }),
105
- }).then((result) => result.text);
96
+ import { openai } from "@ai-sdk/openai";
97
+ import { aiSdkJudgeHarness } from "@vitest-evals/harness-ai-sdk";
98
+ import { describeEval, FactualityJudge } from "vitest-evals";
106
99
 
107
- return parseJudgeVerdict(verdict);
108
- },
109
- );
100
+ const judgeHarness = aiSdkJudgeHarness({
101
+ model: openai("gpt-4.1-mini"),
102
+ temperature: 0,
103
+ });
104
+ const factualityJudge = FactualityJudge({ judgeHarness });
105
+
106
+ describeEval("refund agent", {
107
+ harness,
108
+ judges: [factualityJudge],
109
+ });
110
110
  ```
111
111
 
112
112
  The adapter infers:
package/dist/index.d.mts CHANGED
@@ -1,12 +1,62 @@
1
+ import * as vitest_evals_judges from 'vitest-evals/judges';
1
2
  import { HarnessMetadata, HarnessContext, JsonValue, HarnessRun, Harness } from 'vitest-evals/harness';
3
+ import { LanguageModel, generateText, ToolExecutionOptions, Tool, ToolExecuteFunction } from 'ai';
2
4
  import { ReplayMode, ToolRecording, ToolReplayConfig } from 'vitest-evals/replay';
3
- import { ToolExecutionOptions, Tool, ToolExecuteFunction } from 'ai';
4
5
 
5
6
  type MaybePromise<T> = T | Promise<T>;
7
+ type AiSdkProviderOptions = Parameters<typeof generateText>[0]["providerOptions"];
6
8
  type JsonOutput<TValue> = [TValue] extends [JsonValue | undefined] ? TValue : undefined;
7
9
  type ResultFieldOutput<TResult, TKey extends string> = TKey extends keyof TResult ? Record<string, never> extends Pick<TResult, TKey> ? JsonOutput<TResult[TKey]> | undefined : JsonOutput<TResult[TKey]> : undefined;
8
10
  type AgentSource<TAgent, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = TAgent | ((args: AiSdkCreateAgentArgs<TInput, TMetadata>) => MaybePromise<TAgent>);
9
11
  type AnyAiSdkToolset<TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = Record<string, AiSdkToolDefinition<any, any, TInput, TMetadata>>;
12
+ /**
13
+ * Configuration for adapting an AI SDK language model into a judge harness.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { anthropic } from "@ai-sdk/anthropic";
18
+ * import { aiSdkJudgeHarness } from "@vitest-evals/harness-ai-sdk";
19
+ *
20
+ * const judgeHarness = aiSdkJudgeHarness({
21
+ * model: anthropic("claude-sonnet-4-5"),
22
+ * temperature: 0,
23
+ * });
24
+ * ```
25
+ */
26
+ interface AiSdkJudgeHarnessConfig {
27
+ /** AI SDK language model used for judge prompts. */
28
+ model: LanguageModel;
29
+ /** Optional display name for diagnostics. */
30
+ name?: string;
31
+ /** Optional judge-model temperature. */
32
+ temperature?: number;
33
+ /** Optional judge-model token cap. */
34
+ maxOutputTokens?: number;
35
+ /** Optional provider-specific options forwarded to the AI SDK. */
36
+ providerOptions?: AiSdkProviderOptions;
37
+ }
38
+ /**
39
+ * Adapts an AI SDK language model into the provider-neutral judge harness API.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * import { anthropic } from "@ai-sdk/anthropic";
44
+ * import { aiSdkJudgeHarness } from "@vitest-evals/harness-ai-sdk";
45
+ * import { describeEval, FactualityJudge } from "vitest-evals";
46
+ *
47
+ * const judgeHarness = aiSdkJudgeHarness({
48
+ * model: anthropic("claude-sonnet-4-5"),
49
+ * temperature: 0,
50
+ * });
51
+ *
52
+ * describeEval("qa agent", {
53
+ * harness: qaHarness,
54
+ * judgeHarness,
55
+ * judges: [FactualityJudge()],
56
+ * }, (it) => {});
57
+ * ```
58
+ */
59
+ declare function aiSdkJudgeHarness(config: AiSdkJudgeHarnessConfig): vitest_evals_judges.JudgeHarness;
10
60
  type AiSdkResultOutput<TResult> = TResult extends HarnessRun<infer TOutput> ? TOutput : "output" extends keyof TResult ? ResultFieldOutput<TResult, "output"> : "object" extends keyof TResult ? ResultFieldOutput<TResult, "object"> : "text" extends keyof TResult ? ResultFieldOutput<TResult, "text"> : undefined;
11
61
  type AiSdkAgentResult<TAgent, TInput, TMetadata extends HarnessMetadata, TTools extends AiSdkToolset<TInput, TMetadata>> = TAgent extends {
12
62
  run: (input: TInput, runtime: AiSdkRuntime<TTools, TInput, TMetadata>) => MaybePromise<infer TResult>;
@@ -95,4 +145,4 @@ declare function aiSdkHarness<TAgent = unknown, TInput = string, TMetadata exten
95
145
  declare function aiSdkHarness<TAgent = unknown, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata, TResult = unknown, TTools extends AiSdkToolset<TInput, TMetadata> = AiSdkToolset<TInput, TMetadata>>(options: AiSdkHarnessRunOptionsWithoutOutput<TAgent, TInput, TMetadata, TResult, TTools>): Harness<TInput, AiSdkResultOutput<Awaited<TResult>>, TMetadata>;
96
146
  declare function aiSdkHarness<TAgent = unknown, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata, TTools extends AiSdkToolset<TInput, TMetadata> = AiSdkToolset<TInput, TMetadata>>(options: AiSdkHarnessAgentOptionsWithoutOutput<TAgent, TInput, TMetadata, TTools>): Harness<TInput, AiSdkResultOutput<AiSdkAgentResult<TAgent, TInput, TMetadata, TTools>>, TMetadata>;
97
147
 
98
- export { type AiSdkCreateAgentArgs, type AiSdkHarnessResultArgs, type AiSdkHarnessRunArgs, type AiSdkReplayMode, type AiSdkRuntime, type AiSdkRuntimeToolset, type AiSdkToolContext, type AiSdkToolDefinition, type AiSdkToolRecording, type AiSdkToolReplayConfig, type AiSdkToolReplayPolicies, type AiSdkToolReplayPolicy, type AiSdkToolset, aiSdkHarness };
148
+ export { type AiSdkCreateAgentArgs, type AiSdkHarnessResultArgs, type AiSdkHarnessRunArgs, type AiSdkJudgeHarnessConfig, type AiSdkReplayMode, type AiSdkRuntime, type AiSdkRuntimeToolset, type AiSdkToolContext, type AiSdkToolDefinition, type AiSdkToolRecording, type AiSdkToolReplayConfig, type AiSdkToolReplayPolicies, type AiSdkToolReplayPolicy, type AiSdkToolset, aiSdkHarness, aiSdkJudgeHarness };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,62 @@
1
+ import * as vitest_evals_judges from 'vitest-evals/judges';
1
2
  import { HarnessMetadata, HarnessContext, JsonValue, HarnessRun, Harness } from 'vitest-evals/harness';
3
+ import { LanguageModel, generateText, ToolExecutionOptions, Tool, ToolExecuteFunction } from 'ai';
2
4
  import { ReplayMode, ToolRecording, ToolReplayConfig } from 'vitest-evals/replay';
3
- import { ToolExecutionOptions, Tool, ToolExecuteFunction } from 'ai';
4
5
 
5
6
  type MaybePromise<T> = T | Promise<T>;
7
+ type AiSdkProviderOptions = Parameters<typeof generateText>[0]["providerOptions"];
6
8
  type JsonOutput<TValue> = [TValue] extends [JsonValue | undefined] ? TValue : undefined;
7
9
  type ResultFieldOutput<TResult, TKey extends string> = TKey extends keyof TResult ? Record<string, never> extends Pick<TResult, TKey> ? JsonOutput<TResult[TKey]> | undefined : JsonOutput<TResult[TKey]> : undefined;
8
10
  type AgentSource<TAgent, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = TAgent | ((args: AiSdkCreateAgentArgs<TInput, TMetadata>) => MaybePromise<TAgent>);
9
11
  type AnyAiSdkToolset<TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = Record<string, AiSdkToolDefinition<any, any, TInput, TMetadata>>;
12
+ /**
13
+ * Configuration for adapting an AI SDK language model into a judge harness.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { anthropic } from "@ai-sdk/anthropic";
18
+ * import { aiSdkJudgeHarness } from "@vitest-evals/harness-ai-sdk";
19
+ *
20
+ * const judgeHarness = aiSdkJudgeHarness({
21
+ * model: anthropic("claude-sonnet-4-5"),
22
+ * temperature: 0,
23
+ * });
24
+ * ```
25
+ */
26
+ interface AiSdkJudgeHarnessConfig {
27
+ /** AI SDK language model used for judge prompts. */
28
+ model: LanguageModel;
29
+ /** Optional display name for diagnostics. */
30
+ name?: string;
31
+ /** Optional judge-model temperature. */
32
+ temperature?: number;
33
+ /** Optional judge-model token cap. */
34
+ maxOutputTokens?: number;
35
+ /** Optional provider-specific options forwarded to the AI SDK. */
36
+ providerOptions?: AiSdkProviderOptions;
37
+ }
38
+ /**
39
+ * Adapts an AI SDK language model into the provider-neutral judge harness API.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * import { anthropic } from "@ai-sdk/anthropic";
44
+ * import { aiSdkJudgeHarness } from "@vitest-evals/harness-ai-sdk";
45
+ * import { describeEval, FactualityJudge } from "vitest-evals";
46
+ *
47
+ * const judgeHarness = aiSdkJudgeHarness({
48
+ * model: anthropic("claude-sonnet-4-5"),
49
+ * temperature: 0,
50
+ * });
51
+ *
52
+ * describeEval("qa agent", {
53
+ * harness: qaHarness,
54
+ * judgeHarness,
55
+ * judges: [FactualityJudge()],
56
+ * }, (it) => {});
57
+ * ```
58
+ */
59
+ declare function aiSdkJudgeHarness(config: AiSdkJudgeHarnessConfig): vitest_evals_judges.JudgeHarness;
10
60
  type AiSdkResultOutput<TResult> = TResult extends HarnessRun<infer TOutput> ? TOutput : "output" extends keyof TResult ? ResultFieldOutput<TResult, "output"> : "object" extends keyof TResult ? ResultFieldOutput<TResult, "object"> : "text" extends keyof TResult ? ResultFieldOutput<TResult, "text"> : undefined;
11
61
  type AiSdkAgentResult<TAgent, TInput, TMetadata extends HarnessMetadata, TTools extends AiSdkToolset<TInput, TMetadata>> = TAgent extends {
12
62
  run: (input: TInput, runtime: AiSdkRuntime<TTools, TInput, TMetadata>) => MaybePromise<infer TResult>;
@@ -95,4 +145,4 @@ declare function aiSdkHarness<TAgent = unknown, TInput = string, TMetadata exten
95
145
  declare function aiSdkHarness<TAgent = unknown, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata, TResult = unknown, TTools extends AiSdkToolset<TInput, TMetadata> = AiSdkToolset<TInput, TMetadata>>(options: AiSdkHarnessRunOptionsWithoutOutput<TAgent, TInput, TMetadata, TResult, TTools>): Harness<TInput, AiSdkResultOutput<Awaited<TResult>>, TMetadata>;
96
146
  declare function aiSdkHarness<TAgent = unknown, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata, TTools extends AiSdkToolset<TInput, TMetadata> = AiSdkToolset<TInput, TMetadata>>(options: AiSdkHarnessAgentOptionsWithoutOutput<TAgent, TInput, TMetadata, TTools>): Harness<TInput, AiSdkResultOutput<AiSdkAgentResult<TAgent, TInput, TMetadata, TTools>>, TMetadata>;
97
147
 
98
- export { type AiSdkCreateAgentArgs, type AiSdkHarnessResultArgs, type AiSdkHarnessRunArgs, type AiSdkReplayMode, type AiSdkRuntime, type AiSdkRuntimeToolset, type AiSdkToolContext, type AiSdkToolDefinition, type AiSdkToolRecording, type AiSdkToolReplayConfig, type AiSdkToolReplayPolicies, type AiSdkToolReplayPolicy, type AiSdkToolset, aiSdkHarness };
148
+ export { type AiSdkCreateAgentArgs, type AiSdkHarnessResultArgs, type AiSdkHarnessRunArgs, type AiSdkJudgeHarnessConfig, type AiSdkReplayMode, type AiSdkRuntime, type AiSdkRuntimeToolset, type AiSdkToolContext, type AiSdkToolDefinition, type AiSdkToolRecording, type AiSdkToolReplayConfig, type AiSdkToolReplayPolicies, type AiSdkToolReplayPolicy, type AiSdkToolset, aiSdkHarness, aiSdkJudgeHarness };
package/dist/index.js CHANGED
@@ -20,26 +20,97 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- aiSdkHarness: () => aiSdkHarness
23
+ aiSdkHarness: () => aiSdkHarness,
24
+ aiSdkJudgeHarness: () => aiSdkJudgeHarness
24
25
  });
25
26
  module.exports = __toCommonJS(index_exports);
26
27
  var import_harness = require("vitest-evals/harness");
28
+ var import_ai = require("ai");
29
+ var import_judges = require("vitest-evals/judges");
27
30
  var import_replay = require("vitest-evals/replay");
31
+ var nextTraceId = 0;
32
+ function aiSdkJudgeHarness(config) {
33
+ return (0, import_judges.createJudgeHarness)({
34
+ name: config.name ?? "ai-sdk",
35
+ run: (input, options) => runAiSdkJudgeHarness(config, input, options)
36
+ });
37
+ }
38
+ async function runAiSdkJudgeHarness(config, input, options) {
39
+ const system = formatAiSdkJudgeSystemPrompt(
40
+ input.system,
41
+ input.responseFormat
42
+ );
43
+ const requestOptions = {
44
+ model: config.model,
45
+ prompt: input.prompt,
46
+ ...system !== void 0 ? { system } : {},
47
+ ...config.temperature !== void 0 ? { temperature: config.temperature } : {},
48
+ ...config.maxOutputTokens !== void 0 ? { maxOutputTokens: config.maxOutputTokens } : {},
49
+ ...config.providerOptions !== void 0 ? { providerOptions: config.providerOptions } : {},
50
+ ...options.signal ? { abortSignal: options.signal } : {}
51
+ };
52
+ if (input.responseFormat?.type === "json" && input.responseFormat.schema !== void 0) {
53
+ const { object } = await (0, import_ai.generateObject)({
54
+ ...requestOptions,
55
+ schema: (0, import_ai.jsonSchema)(
56
+ input.responseFormat.schema
57
+ )
58
+ });
59
+ return object;
60
+ }
61
+ const { text } = await (0, import_ai.generateText)(requestOptions);
62
+ return text;
63
+ }
64
+ function formatAiSdkJudgeSystemPrompt(system, responseFormat) {
65
+ if (responseFormat?.type !== "json" || responseFormat.schema !== void 0) {
66
+ return system;
67
+ }
68
+ const jsonInstruction = "Return only valid JSON. Do not include markdown fences or explanatory prose.";
69
+ return system ? `${system}
70
+
71
+ ${jsonInstruction}` : jsonInstruction;
72
+ }
28
73
  function aiSdkHarness(options) {
29
74
  validateOptions(options);
75
+ const harnessName = options.name ?? "ai-sdk";
30
76
  const harness = {
31
- name: options.name ?? "ai-sdk",
77
+ name: harnessName,
32
78
  run: async (input, context) => {
33
- const agent = await resolveAgent(options, {
34
- input,
35
- context
36
- });
37
- return runAiSdkHarness(options, agent, input, context);
79
+ const startedAt = /* @__PURE__ */ new Date();
80
+ try {
81
+ const agent = await resolveAgent(options, {
82
+ input,
83
+ context
84
+ });
85
+ return await runAiSdkHarness(options, agent, input, context);
86
+ } catch (error) {
87
+ if ((0, import_harness.getHarnessRunFromError)(error)) {
88
+ throw error;
89
+ }
90
+ throw (0, import_harness.attachHarnessRunToError)(
91
+ error,
92
+ createFailedAiSdkRun(input, context, error, harnessName, startedAt)
93
+ );
94
+ }
38
95
  }
39
96
  };
40
97
  return harness;
41
98
  }
99
+ function createFailedAiSdkRun(input, context, error, harnessName, startedAt) {
100
+ const run = (0, import_harness.createFailedHarnessRun)(input, error, {
101
+ artifacts: context.artifacts
102
+ });
103
+ (0, import_harness.ensureRunTrace)(run, {
104
+ name: harnessName,
105
+ startedAt,
106
+ finishedAt: /* @__PURE__ */ new Date(),
107
+ operationName: "invoke_workflow",
108
+ source: "harness-ai-sdk"
109
+ });
110
+ return run;
111
+ }
42
112
  async function runAiSdkHarness(options, agent, input, context) {
113
+ const trace = createTraceRecorder(options.name ?? "ai-sdk");
43
114
  const replayMetadataByToolCallId = /* @__PURE__ */ new Map();
44
115
  const runtimeToolCalls = [];
45
116
  const tools = createToolset({
@@ -66,6 +137,7 @@ async function runAiSdkHarness(options, agent, input, context) {
66
137
  if (Object.keys(context.artifacts).length > 0 && !result.artifacts) {
67
138
  result.artifacts = context.artifacts;
68
139
  }
140
+ attachAiSdkTrace(result, trace, result, /* @__PURE__ */ new Date());
69
141
  return result;
70
142
  }
71
143
  const resultArgs = {
@@ -86,26 +158,48 @@ async function runAiSdkHarness(options, agent, input, context) {
86
158
  runtimeToolCalls
87
159
  );
88
160
  const errors = (0, import_harness.resolveHarnessRunErrors)(result);
161
+ const finishedAt = /* @__PURE__ */ new Date();
89
162
  return {
90
163
  session,
91
164
  output,
92
165
  usage,
93
166
  artifacts: Object.keys(context.artifacts).length > 0 ? context.artifacts : void 0,
94
- errors
167
+ errors,
168
+ traces: [
169
+ finishAiSdkTrace(trace, {
170
+ result,
171
+ session,
172
+ usage,
173
+ errors,
174
+ finishedAt
175
+ })
176
+ ]
95
177
  };
96
178
  } catch (error) {
179
+ const finishedAt = /* @__PURE__ */ new Date();
180
+ const serializedError = (0, import_harness.serializeError)(error);
181
+ const usage = runtimeToolCalls.length > 0 ? { toolCalls: runtimeToolCalls.length } : {};
182
+ const session = resolveSession(
183
+ input,
184
+ void 0,
185
+ void 0,
186
+ replayMetadataByToolCallId,
187
+ runtimeToolCalls
188
+ );
97
189
  const run = {
98
- session: resolveSession(
99
- input,
100
- void 0,
101
- void 0,
102
- replayMetadataByToolCallId,
103
- runtimeToolCalls
104
- ),
190
+ session,
105
191
  output: void 0,
106
- usage: runtimeToolCalls.length > 0 ? { toolCalls: runtimeToolCalls.length } : {},
192
+ usage,
107
193
  artifacts: Object.keys(context.artifacts).length > 0 ? context.artifacts : void 0,
108
- errors: [(0, import_harness.serializeError)(error)]
194
+ errors: [serializedError],
195
+ traces: [
196
+ finishAiSdkTrace(trace, {
197
+ session,
198
+ usage,
199
+ errors: [serializedError],
200
+ finishedAt
201
+ })
202
+ ]
109
203
  };
110
204
  throw (0, import_harness.attachHarnessRunToError)(error, run);
111
205
  }
@@ -165,6 +259,119 @@ function hasAiSdkGenerateMethod(agent) {
165
259
  function isAgentFactory(agent) {
166
260
  return typeof agent === "function" && !(0, import_harness.hasCallableMethod)(agent, "run") && !(0, import_harness.hasCallableMethod)(agent, "generate");
167
261
  }
262
+ function createTraceRecorder(name) {
263
+ const id = `ai_sdk_trace_${++nextTraceId}`;
264
+ return {
265
+ id,
266
+ rootSpanId: `${id}:run`,
267
+ name,
268
+ startedAt: /* @__PURE__ */ new Date()
269
+ };
270
+ }
271
+ function attachAiSdkTrace(run, trace, result, finishedAt) {
272
+ const errors = run.errors ?? [];
273
+ const nativeTrace = finishAiSdkTrace(trace, {
274
+ result,
275
+ session: run.session,
276
+ usage: run.usage,
277
+ errors,
278
+ finishedAt
279
+ });
280
+ run.traces = [...run.traces ?? [], nativeTrace];
281
+ }
282
+ function finishAiSdkTrace(trace, options) {
283
+ const modelSpans = createAiSdkModelSpans(
284
+ trace,
285
+ options.result,
286
+ options.usage
287
+ );
288
+ const toolSpans = (0, import_harness.createToolCallSpans)((0, import_harness.toolCalls)(options.session), {
289
+ traceId: trace.id,
290
+ parentId: trace.rootSpanId,
291
+ spanIdPrefix: `${trace.id}:tool`
292
+ });
293
+ const finishedAt = options.finishedAt;
294
+ const durationMs = finishedAt.getTime() - trace.startedAt.getTime();
295
+ const rootError = options.errors?.[0] ? (0, import_harness.normalizeSpanError)(options.errors[0]) : void 0;
296
+ const rootSpan = {
297
+ id: trace.rootSpanId,
298
+ traceId: trace.id,
299
+ name: trace.name,
300
+ kind: "run",
301
+ startedAt: trace.startedAt.toISOString(),
302
+ finishedAt: finishedAt.toISOString(),
303
+ durationMs,
304
+ status: rootError ? "error" : "ok",
305
+ ...rootError ? { error: rootError } : {},
306
+ attributes: (0, import_harness.normalizeSpanAttributes)({
307
+ "gen_ai.operation.name": "invoke_workflow",
308
+ "gen_ai.workflow.name": trace.name,
309
+ ...(0, import_harness.createGenAiUsageAttributes)(options.usage)
310
+ })
311
+ };
312
+ const spans = [rootSpan, ...modelSpans, ...toolSpans];
313
+ return {
314
+ id: trace.id,
315
+ name: trace.name,
316
+ startedAt: trace.startedAt.toISOString(),
317
+ finishedAt: finishedAt.toISOString(),
318
+ durationMs,
319
+ metadata: {
320
+ source: "harness-ai-sdk"
321
+ },
322
+ spans
323
+ };
324
+ }
325
+ function createAiSdkModelSpans(trace, result, usage) {
326
+ const steps = resolveSteps(result);
327
+ if (steps.length === 0) {
328
+ const fallback = createUsageModelSpan(trace, usage);
329
+ return fallback ? [fallback] : [];
330
+ }
331
+ return steps.map((step, index) => {
332
+ const stepUsage = step.usage;
333
+ return {
334
+ id: `${trace.id}:model:${index + 1}`,
335
+ traceId: trace.id,
336
+ parentId: trace.rootSpanId,
337
+ name: `ai-sdk step ${step.stepNumber ?? index}`,
338
+ kind: "model",
339
+ status: "ok",
340
+ attributes: (0, import_harness.normalizeSpanAttributes)({
341
+ "gen_ai.operation.name": "chat",
342
+ "gen_ai.provider.name": step.model?.provider,
343
+ "gen_ai.request.model": step.model?.modelId,
344
+ "gen_ai.response.model": step.model?.modelId,
345
+ "gen_ai.response.finish_reasons": step.finishReason ? [String(step.finishReason)] : void 0,
346
+ "gen_ai.usage.input_tokens": stepUsage?.inputTokens,
347
+ "gen_ai.usage.output_tokens": stepUsage?.outputTokens,
348
+ "gen_ai.usage.reasoning.output_tokens": stepUsage?.outputTokenDetails?.reasoningTokens ?? stepUsage?.reasoningTokens,
349
+ "gen_ai.usage.cache_read.input_tokens": stepUsage?.inputTokenDetails?.cacheReadTokens ?? stepUsage?.cachedInputTokens,
350
+ "gen_ai.usage.cache_creation.input_tokens": stepUsage?.inputTokenDetails?.cacheWriteTokens,
351
+ "ai.step.number": step.stepNumber,
352
+ "ai.finish_reason": step.finishReason,
353
+ "ai.raw_finish_reason": step.rawFinishReason
354
+ })
355
+ };
356
+ });
357
+ }
358
+ function createUsageModelSpan(trace, usage) {
359
+ if (!usage?.provider && !usage?.model) {
360
+ return void 0;
361
+ }
362
+ return {
363
+ id: `${trace.id}:model:1`,
364
+ traceId: trace.id,
365
+ parentId: trace.rootSpanId,
366
+ name: usage.model ? `ai-sdk ${usage.model}` : "ai-sdk model",
367
+ kind: "model",
368
+ status: "ok",
369
+ attributes: (0, import_harness.normalizeSpanAttributes)({
370
+ "gen_ai.operation.name": "chat",
371
+ ...(0, import_harness.createGenAiUsageAttributes)(usage)
372
+ })
373
+ };
374
+ }
168
375
  function createToolset({
169
376
  input,
170
377
  context,
@@ -614,6 +821,7 @@ function isAsyncIterable(value) {
614
821
  }
615
822
  // Annotate the CommonJS export names for ESM import in node:
616
823
  0 && (module.exports = {
617
- aiSdkHarness
824
+ aiSdkHarness,
825
+ aiSdkJudgeHarness
618
826
  });
619
827
  //# sourceMappingURL=index.js.map