@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 +15 -15
- package/dist/index.d.mts +52 -2
- package/dist/index.d.ts +52 -2
- package/dist/index.js +226 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +235 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
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
|
|
93
|
-
|
|
92
|
+
prompts and model calls on a judge harness instead of putting them on the app
|
|
93
|
+
harness.
|
|
94
94
|
|
|
95
95
|
```ts
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
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:
|
|
77
|
+
name: harnessName,
|
|
32
78
|
run: async (input, context) => {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
99
|
-
input,
|
|
100
|
-
void 0,
|
|
101
|
-
void 0,
|
|
102
|
-
replayMetadataByToolCallId,
|
|
103
|
-
runtimeToolCalls
|
|
104
|
-
),
|
|
190
|
+
session,
|
|
105
191
|
output: void 0,
|
|
106
|
-
usage
|
|
192
|
+
usage,
|
|
107
193
|
artifacts: Object.keys(context.artifacts).length > 0 ? context.artifacts : void 0,
|
|
108
|
-
errors: [
|
|
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
|