@vitest-evals/harness-pi-ai 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 +17 -16
- package/dist/index.d.mts +51 -1
- package/dist/index.d.ts +51 -1
- package/dist/index.js +208 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +217 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -43,23 +43,24 @@ describeEval("refund agent", { harness }, (it) => {
|
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
`run` executes the Pi agent under test. Judges are created separately; keep
|
|
46
|
-
judge prompts and model calls
|
|
47
|
-
call on the app harness.
|
|
46
|
+
judge prompts on the judge and model calls on a judge harness instead of
|
|
47
|
+
putting a judge model call on the app harness.
|
|
48
48
|
|
|
49
49
|
```ts
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const verdict = await queryRefundJudgeModel({
|
|
54
|
-
prompt: formatJudgePrompt({
|
|
55
|
-
input: ctx.input,
|
|
56
|
-
output: ctx.output,
|
|
57
|
-
}),
|
|
58
|
-
});
|
|
50
|
+
import { getModel } from "@mariozechner/pi-ai";
|
|
51
|
+
import { piAiJudgeHarness } from "@vitest-evals/harness-pi-ai";
|
|
52
|
+
import { describeEval, FactualityJudge } from "vitest-evals";
|
|
59
53
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
54
|
+
const judgeHarness = piAiJudgeHarness({
|
|
55
|
+
model: getModel("anthropic", "claude-sonnet-4-5"),
|
|
56
|
+
temperature: 0,
|
|
57
|
+
});
|
|
58
|
+
const factualityJudge = FactualityJudge({ judgeHarness });
|
|
59
|
+
|
|
60
|
+
describeEval("refund agent", {
|
|
61
|
+
harness,
|
|
62
|
+
judges: [factualityJudge],
|
|
63
|
+
});
|
|
63
64
|
```
|
|
64
65
|
|
|
65
66
|
If the agent already exposes its own tools, the adapter will infer them from
|
|
@@ -170,7 +171,7 @@ overwrite the native recording.
|
|
|
170
171
|
|
|
171
172
|
Supported modes:
|
|
172
173
|
|
|
174
|
+
- `auto` (default): replay when present, otherwise call live and write a recording
|
|
175
|
+
- `record`: always call live and overwrite the recording
|
|
173
176
|
- `off`: never read or write recordings
|
|
174
|
-
- `auto`: replay when present, otherwise call live and write a recording
|
|
175
177
|
- `strict`: require an existing recording and fail if it is missing
|
|
176
|
-
- `record`: always call live and overwrite the recording
|
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,61 @@
|
|
|
1
|
+
import * as vitest_evals_judges from 'vitest-evals/judges';
|
|
1
2
|
import { NormalizedMessage, JsonValue, HarnessMetadata, HarnessContext, HarnessRun, Harness } from 'vitest-evals/harness';
|
|
2
3
|
import { ReplayMode, ToolRecording, ToolReplayConfig } from 'vitest-evals/replay';
|
|
4
|
+
import { Api, Model, SimpleStreamOptions } from '@mariozechner/pi-ai';
|
|
3
5
|
|
|
4
6
|
type MaybePromise<T> = T | Promise<T>;
|
|
5
7
|
type JsonOutput<TValue> = [TValue] extends [JsonValue | undefined] ? TValue : undefined;
|
|
6
8
|
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;
|
|
7
9
|
type AgentSource<TAgent, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = TAgent | ((args: PiAiCreateAgentArgs<TInput, TMetadata>) => MaybePromise<TAgent>);
|
|
8
10
|
type AnyPiAiToolset<TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = Record<string, PiAiToolDefinition<any, any, TInput, TMetadata>>;
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for adapting a Pi AI model into a judge harness.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { getModel } from "@mariozechner/pi-ai";
|
|
17
|
+
* import { piAiJudgeHarness } from "@vitest-evals/harness-pi-ai";
|
|
18
|
+
*
|
|
19
|
+
* const judgeHarness = piAiJudgeHarness({
|
|
20
|
+
* model: getModel("anthropic", "claude-sonnet-4-5"),
|
|
21
|
+
* temperature: 0,
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
interface PiAiJudgeHarnessConfig<TApi extends Api = Api> {
|
|
26
|
+
/** Pi AI model used for judge prompts. */
|
|
27
|
+
model: Model<TApi>;
|
|
28
|
+
/** Optional display name for diagnostics. */
|
|
29
|
+
name?: string;
|
|
30
|
+
/** Optional judge-model temperature. */
|
|
31
|
+
temperature?: number;
|
|
32
|
+
/** Optional judge-model token cap. */
|
|
33
|
+
maxOutputTokens?: number;
|
|
34
|
+
/** Additional Pi AI stream options forwarded to `completeSimple(...)`. */
|
|
35
|
+
options?: Omit<SimpleStreamOptions, "signal" | "temperature" | "maxTokens">;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Adapts a Pi AI model into the provider-neutral judge harness API.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { getModel } from "@mariozechner/pi-ai";
|
|
43
|
+
* import { piAiJudgeHarness } from "@vitest-evals/harness-pi-ai";
|
|
44
|
+
* import { describeEval, FactualityJudge } from "vitest-evals";
|
|
45
|
+
*
|
|
46
|
+
* const judgeHarness = piAiJudgeHarness({
|
|
47
|
+
* model: getModel("anthropic", "claude-sonnet-4-5"),
|
|
48
|
+
* temperature: 0,
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* describeEval("qa agent", {
|
|
52
|
+
* harness: qaHarness,
|
|
53
|
+
* judgeHarness,
|
|
54
|
+
* judges: [FactualityJudge()],
|
|
55
|
+
* }, (it) => {});
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare function piAiJudgeHarness<TApi extends Api>(config: PiAiJudgeHarnessConfig<TApi>): vitest_evals_judges.JudgeHarness;
|
|
9
59
|
type InferredPiAiToolset<TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = Record<string, PiAiToolDefinition<Record<string, JsonValue>, JsonValue, TInput, TMetadata>>;
|
|
10
60
|
type PiAiResultOutput<TResult> = TResult extends HarnessRun<infer TOutput> ? TOutput : "output" extends keyof TResult ? ResultFieldOutput<TResult, "output"> : undefined;
|
|
11
61
|
type PiAiAgentResult<TAgent, TInput, TMetadata extends HarnessMetadata, TTools extends PiAiToolset<TInput, TMetadata>> = TAgent extends {
|
|
@@ -118,4 +168,4 @@ declare function piAiHarness<TAgent, TInput = string, TMetadata extends HarnessM
|
|
|
118
168
|
declare function piAiHarness<TAgent, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata, TResult = unknown>(options: PiAiHarnessInferredToolsRunOptionsWithoutOutput<TAgent, TInput, TMetadata, TResult>): Harness<TInput, PiAiResultOutput<Awaited<TResult>>, TMetadata>;
|
|
119
169
|
declare function piAiHarness<TAgent, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata>(options: PiAiHarnessInferredToolsAgentOptionsWithoutOutput<TAgent, TInput, TMetadata>): Harness<TInput, PiAiResultOutput<PiAiAgentResult<TAgent, TInput, TMetadata, InferredPiAiToolset<TInput, TMetadata>>>, TMetadata>;
|
|
120
170
|
|
|
121
|
-
export { type PiAiCreateAgentArgs, type PiAiEventSink, type PiAiHarnessResultArgs, type PiAiHarnessRunArgs, type PiAiReplayMode, type PiAiRuntime, type PiAiToolContext, type PiAiToolDefinition, type PiAiToolRecording, type PiAiToolReplayConfig, type PiAiToolReplayPolicies, type PiAiToolReplayPolicy, type PiAiToolset, piAiHarness };
|
|
171
|
+
export { type PiAiCreateAgentArgs, type PiAiEventSink, type PiAiHarnessResultArgs, type PiAiHarnessRunArgs, type PiAiJudgeHarnessConfig, type PiAiReplayMode, type PiAiRuntime, type PiAiToolContext, type PiAiToolDefinition, type PiAiToolRecording, type PiAiToolReplayConfig, type PiAiToolReplayPolicies, type PiAiToolReplayPolicy, type PiAiToolset, piAiHarness, piAiJudgeHarness };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,61 @@
|
|
|
1
|
+
import * as vitest_evals_judges from 'vitest-evals/judges';
|
|
1
2
|
import { NormalizedMessage, JsonValue, HarnessMetadata, HarnessContext, HarnessRun, Harness } from 'vitest-evals/harness';
|
|
2
3
|
import { ReplayMode, ToolRecording, ToolReplayConfig } from 'vitest-evals/replay';
|
|
4
|
+
import { Api, Model, SimpleStreamOptions } from '@mariozechner/pi-ai';
|
|
3
5
|
|
|
4
6
|
type MaybePromise<T> = T | Promise<T>;
|
|
5
7
|
type JsonOutput<TValue> = [TValue] extends [JsonValue | undefined] ? TValue : undefined;
|
|
6
8
|
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;
|
|
7
9
|
type AgentSource<TAgent, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = TAgent | ((args: PiAiCreateAgentArgs<TInput, TMetadata>) => MaybePromise<TAgent>);
|
|
8
10
|
type AnyPiAiToolset<TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = Record<string, PiAiToolDefinition<any, any, TInput, TMetadata>>;
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for adapting a Pi AI model into a judge harness.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { getModel } from "@mariozechner/pi-ai";
|
|
17
|
+
* import { piAiJudgeHarness } from "@vitest-evals/harness-pi-ai";
|
|
18
|
+
*
|
|
19
|
+
* const judgeHarness = piAiJudgeHarness({
|
|
20
|
+
* model: getModel("anthropic", "claude-sonnet-4-5"),
|
|
21
|
+
* temperature: 0,
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
interface PiAiJudgeHarnessConfig<TApi extends Api = Api> {
|
|
26
|
+
/** Pi AI model used for judge prompts. */
|
|
27
|
+
model: Model<TApi>;
|
|
28
|
+
/** Optional display name for diagnostics. */
|
|
29
|
+
name?: string;
|
|
30
|
+
/** Optional judge-model temperature. */
|
|
31
|
+
temperature?: number;
|
|
32
|
+
/** Optional judge-model token cap. */
|
|
33
|
+
maxOutputTokens?: number;
|
|
34
|
+
/** Additional Pi AI stream options forwarded to `completeSimple(...)`. */
|
|
35
|
+
options?: Omit<SimpleStreamOptions, "signal" | "temperature" | "maxTokens">;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Adapts a Pi AI model into the provider-neutral judge harness API.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { getModel } from "@mariozechner/pi-ai";
|
|
43
|
+
* import { piAiJudgeHarness } from "@vitest-evals/harness-pi-ai";
|
|
44
|
+
* import { describeEval, FactualityJudge } from "vitest-evals";
|
|
45
|
+
*
|
|
46
|
+
* const judgeHarness = piAiJudgeHarness({
|
|
47
|
+
* model: getModel("anthropic", "claude-sonnet-4-5"),
|
|
48
|
+
* temperature: 0,
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* describeEval("qa agent", {
|
|
52
|
+
* harness: qaHarness,
|
|
53
|
+
* judgeHarness,
|
|
54
|
+
* judges: [FactualityJudge()],
|
|
55
|
+
* }, (it) => {});
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare function piAiJudgeHarness<TApi extends Api>(config: PiAiJudgeHarnessConfig<TApi>): vitest_evals_judges.JudgeHarness;
|
|
9
59
|
type InferredPiAiToolset<TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata> = Record<string, PiAiToolDefinition<Record<string, JsonValue>, JsonValue, TInput, TMetadata>>;
|
|
10
60
|
type PiAiResultOutput<TResult> = TResult extends HarnessRun<infer TOutput> ? TOutput : "output" extends keyof TResult ? ResultFieldOutput<TResult, "output"> : undefined;
|
|
11
61
|
type PiAiAgentResult<TAgent, TInput, TMetadata extends HarnessMetadata, TTools extends PiAiToolset<TInput, TMetadata>> = TAgent extends {
|
|
@@ -118,4 +168,4 @@ declare function piAiHarness<TAgent, TInput = string, TMetadata extends HarnessM
|
|
|
118
168
|
declare function piAiHarness<TAgent, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata, TResult = unknown>(options: PiAiHarnessInferredToolsRunOptionsWithoutOutput<TAgent, TInput, TMetadata, TResult>): Harness<TInput, PiAiResultOutput<Awaited<TResult>>, TMetadata>;
|
|
119
169
|
declare function piAiHarness<TAgent, TInput = string, TMetadata extends HarnessMetadata = HarnessMetadata>(options: PiAiHarnessInferredToolsAgentOptionsWithoutOutput<TAgent, TInput, TMetadata>): Harness<TInput, PiAiResultOutput<PiAiAgentResult<TAgent, TInput, TMetadata, InferredPiAiToolset<TInput, TMetadata>>>, TMetadata>;
|
|
120
170
|
|
|
121
|
-
export { type PiAiCreateAgentArgs, type PiAiEventSink, type PiAiHarnessResultArgs, type PiAiHarnessRunArgs, type PiAiReplayMode, type PiAiRuntime, type PiAiToolContext, type PiAiToolDefinition, type PiAiToolRecording, type PiAiToolReplayConfig, type PiAiToolReplayPolicies, type PiAiToolReplayPolicy, type PiAiToolset, piAiHarness };
|
|
171
|
+
export { type PiAiCreateAgentArgs, type PiAiEventSink, type PiAiHarnessResultArgs, type PiAiHarnessRunArgs, type PiAiJudgeHarnessConfig, type PiAiReplayMode, type PiAiRuntime, type PiAiToolContext, type PiAiToolDefinition, type PiAiToolRecording, type PiAiToolReplayConfig, type PiAiToolReplayPolicies, type PiAiToolReplayPolicy, type PiAiToolset, piAiHarness, piAiJudgeHarness };
|
package/dist/index.js
CHANGED
|
@@ -20,54 +20,129 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
piAiHarness: () => piAiHarness
|
|
23
|
+
piAiHarness: () => piAiHarness,
|
|
24
|
+
piAiJudgeHarness: () => piAiJudgeHarness
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(index_exports);
|
|
26
27
|
var import_harness = require("vitest-evals/harness");
|
|
27
28
|
var import_replay = require("vitest-evals/replay");
|
|
29
|
+
var import_judges = require("vitest-evals/judges");
|
|
30
|
+
var import_pi_ai = require("@mariozechner/pi-ai");
|
|
31
|
+
var nextTraceId = 0;
|
|
32
|
+
function piAiJudgeHarness(config) {
|
|
33
|
+
return (0, import_judges.createJudgeHarness)({
|
|
34
|
+
name: config.name ?? "pi-ai",
|
|
35
|
+
run: async ({ responseFormat, system, prompt }, { signal }) => {
|
|
36
|
+
const message = await (0, import_pi_ai.completeSimple)(
|
|
37
|
+
config.model,
|
|
38
|
+
{
|
|
39
|
+
systemPrompt: formatPiAiJudgeSystemPrompt(system, responseFormat),
|
|
40
|
+
messages: [
|
|
41
|
+
{
|
|
42
|
+
role: "user",
|
|
43
|
+
content: prompt,
|
|
44
|
+
timestamp: Date.now()
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
...config.options ?? {},
|
|
50
|
+
...config.temperature !== void 0 ? { temperature: config.temperature } : {},
|
|
51
|
+
...config.maxOutputTokens !== void 0 ? { maxTokens: config.maxOutputTokens } : {},
|
|
52
|
+
...signal ? { signal } : {}
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
return resolvePiAiJudgeText(message);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function formatPiAiJudgeSystemPrompt(system, responseFormat) {
|
|
60
|
+
if (responseFormat?.type !== "json") {
|
|
61
|
+
return system;
|
|
62
|
+
}
|
|
63
|
+
const jsonInstruction = [
|
|
64
|
+
"Return only valid JSON. Do not include markdown fences or explanatory prose.",
|
|
65
|
+
responseFormat.schema ? `JSON Schema:
|
|
66
|
+
${JSON.stringify(responseFormat.schema, null, 2)}` : void 0
|
|
67
|
+
].filter(Boolean).join("\n\n");
|
|
68
|
+
return system ? `${system}
|
|
69
|
+
|
|
70
|
+
${jsonInstruction}` : jsonInstruction;
|
|
71
|
+
}
|
|
72
|
+
function resolvePiAiJudgeText(message) {
|
|
73
|
+
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
74
|
+
throw new Error(message.errorMessage ?? "Pi AI judge harness failed.");
|
|
75
|
+
}
|
|
76
|
+
return message.content.filter((part) => part.type === "text").map((part) => part.text).join("").trim();
|
|
77
|
+
}
|
|
28
78
|
var ORIGINAL_NATIVE_EXECUTE = Symbol("vitest-evals.originalNativeExecute");
|
|
29
79
|
function piAiHarness(options) {
|
|
30
80
|
validateOptions(options);
|
|
81
|
+
const harnessName = options.name ?? "pi-ai";
|
|
31
82
|
const harness = {
|
|
32
|
-
name:
|
|
83
|
+
name: harnessName,
|
|
33
84
|
run: async (input, context) => {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
85
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
86
|
+
try {
|
|
87
|
+
const agent = await resolveAgent(options, {
|
|
88
|
+
input,
|
|
89
|
+
context
|
|
90
|
+
});
|
|
91
|
+
const messages = [
|
|
92
|
+
{
|
|
93
|
+
role: "user",
|
|
94
|
+
content: (0, import_harness.normalizeContent)(input)
|
|
95
|
+
}
|
|
96
|
+
];
|
|
97
|
+
const inferredTools = resolveInferredToolSurfaces(
|
|
98
|
+
agent
|
|
99
|
+
);
|
|
100
|
+
if (hasExplicitToolset(options)) {
|
|
101
|
+
return await executePiHarnessRun(
|
|
102
|
+
options,
|
|
103
|
+
agent,
|
|
104
|
+
input,
|
|
105
|
+
context,
|
|
106
|
+
messages,
|
|
107
|
+
options.tools,
|
|
108
|
+
inferredTools.nativeToolsets
|
|
109
|
+
);
|
|
42
110
|
}
|
|
43
|
-
|
|
44
|
-
const inferredTools = resolveInferredToolSurfaces(
|
|
45
|
-
agent
|
|
46
|
-
);
|
|
47
|
-
if (hasExplicitToolset(options)) {
|
|
48
|
-
return executePiHarnessRun(
|
|
111
|
+
return await executePiHarnessRun(
|
|
49
112
|
options,
|
|
50
113
|
agent,
|
|
51
114
|
input,
|
|
52
115
|
context,
|
|
53
116
|
messages,
|
|
54
|
-
|
|
117
|
+
inferredTools.runtimeTools,
|
|
55
118
|
inferredTools.nativeToolsets
|
|
56
119
|
);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if ((0, import_harness.getHarnessRunFromError)(error)) {
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
throw (0, import_harness.attachHarnessRunToError)(
|
|
125
|
+
error,
|
|
126
|
+
createFailedPiAiRun(input, context, error, harnessName, startedAt)
|
|
127
|
+
);
|
|
57
128
|
}
|
|
58
|
-
return executePiHarnessRun(
|
|
59
|
-
options,
|
|
60
|
-
agent,
|
|
61
|
-
input,
|
|
62
|
-
context,
|
|
63
|
-
messages,
|
|
64
|
-
inferredTools.runtimeTools,
|
|
65
|
-
inferredTools.nativeToolsets
|
|
66
|
-
);
|
|
67
129
|
}
|
|
68
130
|
};
|
|
69
131
|
return harness;
|
|
70
132
|
}
|
|
133
|
+
function createFailedPiAiRun(input, context, error, harnessName, startedAt) {
|
|
134
|
+
const run = (0, import_harness.createFailedHarnessRun)(input, error, {
|
|
135
|
+
artifacts: context.artifacts
|
|
136
|
+
});
|
|
137
|
+
(0, import_harness.ensureRunTrace)(run, {
|
|
138
|
+
name: harnessName,
|
|
139
|
+
startedAt,
|
|
140
|
+
finishedAt: /* @__PURE__ */ new Date(),
|
|
141
|
+
operationName: "invoke_agent",
|
|
142
|
+
source: "harness-pi-ai"
|
|
143
|
+
});
|
|
144
|
+
return run;
|
|
145
|
+
}
|
|
71
146
|
function validateOptions(options) {
|
|
72
147
|
if (options.agent === void 0) {
|
|
73
148
|
throw new Error(
|
|
@@ -76,6 +151,7 @@ function validateOptions(options) {
|
|
|
76
151
|
}
|
|
77
152
|
}
|
|
78
153
|
async function executePiHarnessRun(options, agent, input, context, messages, runtimeTools, nativeToolsets) {
|
|
154
|
+
const trace = createTraceRecorder(options.name ?? "pi-ai");
|
|
79
155
|
const executionState = createPiToolExecutionState();
|
|
80
156
|
const runtime = createRuntime({
|
|
81
157
|
input,
|
|
@@ -108,6 +184,7 @@ async function executePiHarnessRun(options, agent, input, context, messages, run
|
|
|
108
184
|
if (Object.keys(context.artifacts).length > 0 && !result.artifacts) {
|
|
109
185
|
result.artifacts = context.artifacts;
|
|
110
186
|
}
|
|
187
|
+
attachPiAiTrace(result, trace, /* @__PURE__ */ new Date());
|
|
111
188
|
return result;
|
|
112
189
|
}
|
|
113
190
|
const normalizeResult = result;
|
|
@@ -121,21 +198,42 @@ async function executePiHarnessRun(options, agent, input, context, messages, run
|
|
|
121
198
|
const output = options.output ? await options.output(resultArgs) : resolveOutput(normalizeResult);
|
|
122
199
|
const usage = resolveUsage(normalizeResult, runtime.toolCalls.length);
|
|
123
200
|
const session = resolveSession(normalizeResult, messages, output, usage);
|
|
201
|
+
const errors = resolveErrors(normalizeResult);
|
|
202
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
124
203
|
return {
|
|
125
204
|
session,
|
|
126
205
|
output,
|
|
127
206
|
usage,
|
|
128
207
|
artifacts: Object.keys(context.artifacts).length > 0 ? context.artifacts : void 0,
|
|
129
|
-
errors
|
|
208
|
+
errors,
|
|
209
|
+
traces: [
|
|
210
|
+
finishPiAiTrace(trace, {
|
|
211
|
+
session,
|
|
212
|
+
usage,
|
|
213
|
+
errors,
|
|
214
|
+
finishedAt
|
|
215
|
+
})
|
|
216
|
+
]
|
|
130
217
|
};
|
|
131
218
|
} catch (error) {
|
|
132
219
|
const usage = resolveUsage(void 0, runtime.toolCalls.length);
|
|
220
|
+
const session = resolveSession(void 0, messages, void 0, usage);
|
|
221
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
222
|
+
const serializedError = (0, import_harness.serializeError)(error);
|
|
133
223
|
const run = {
|
|
134
|
-
session
|
|
224
|
+
session,
|
|
135
225
|
output: void 0,
|
|
136
226
|
usage,
|
|
137
227
|
artifacts: Object.keys(context.artifacts).length > 0 ? context.artifacts : void 0,
|
|
138
|
-
errors: [
|
|
228
|
+
errors: [serializedError],
|
|
229
|
+
traces: [
|
|
230
|
+
finishPiAiTrace(trace, {
|
|
231
|
+
session,
|
|
232
|
+
usage,
|
|
233
|
+
errors: [serializedError],
|
|
234
|
+
finishedAt
|
|
235
|
+
})
|
|
236
|
+
]
|
|
139
237
|
};
|
|
140
238
|
throw (0, import_harness.attachHarnessRunToError)(error, run);
|
|
141
239
|
}
|
|
@@ -155,6 +253,83 @@ function isAgentFactory(agent) {
|
|
|
155
253
|
function hasOutputSelector(options) {
|
|
156
254
|
return Boolean(options.output);
|
|
157
255
|
}
|
|
256
|
+
function createTraceRecorder(name) {
|
|
257
|
+
const id = `pi_ai_trace_${++nextTraceId}`;
|
|
258
|
+
return {
|
|
259
|
+
id,
|
|
260
|
+
rootSpanId: `${id}:run`,
|
|
261
|
+
name,
|
|
262
|
+
startedAt: /* @__PURE__ */ new Date()
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function attachPiAiTrace(run, trace, finishedAt) {
|
|
266
|
+
const nativeTrace = finishPiAiTrace(trace, {
|
|
267
|
+
session: run.session,
|
|
268
|
+
usage: run.usage,
|
|
269
|
+
errors: run.errors ?? [],
|
|
270
|
+
finishedAt
|
|
271
|
+
});
|
|
272
|
+
run.traces = [...run.traces ?? [], nativeTrace];
|
|
273
|
+
}
|
|
274
|
+
function finishPiAiTrace(trace, options) {
|
|
275
|
+
const finishedAt = options.finishedAt;
|
|
276
|
+
const durationMs = finishedAt.getTime() - trace.startedAt.getTime();
|
|
277
|
+
const rootError = options.errors?.[0] ? (0, import_harness.normalizeSpanError)(options.errors[0]) : void 0;
|
|
278
|
+
const rootSpan = {
|
|
279
|
+
id: trace.rootSpanId,
|
|
280
|
+
traceId: trace.id,
|
|
281
|
+
name: trace.name,
|
|
282
|
+
kind: "run",
|
|
283
|
+
startedAt: trace.startedAt.toISOString(),
|
|
284
|
+
finishedAt: finishedAt.toISOString(),
|
|
285
|
+
durationMs,
|
|
286
|
+
status: rootError ? "error" : "ok",
|
|
287
|
+
...rootError ? { error: rootError } : {},
|
|
288
|
+
attributes: (0, import_harness.normalizeSpanAttributes)({
|
|
289
|
+
"gen_ai.operation.name": "invoke_agent",
|
|
290
|
+
"gen_ai.workflow.name": trace.name,
|
|
291
|
+
...(0, import_harness.createGenAiUsageAttributes)(options.usage)
|
|
292
|
+
})
|
|
293
|
+
};
|
|
294
|
+
const modelSpan = createUsageModelSpan(trace, options.usage);
|
|
295
|
+
const spans = [
|
|
296
|
+
rootSpan,
|
|
297
|
+
...modelSpan ? [modelSpan] : [],
|
|
298
|
+
...(0, import_harness.createToolCallSpans)((0, import_harness.toolCalls)(options.session), {
|
|
299
|
+
traceId: trace.id,
|
|
300
|
+
parentId: trace.rootSpanId,
|
|
301
|
+
spanIdPrefix: `${trace.id}:tool`
|
|
302
|
+
})
|
|
303
|
+
];
|
|
304
|
+
return {
|
|
305
|
+
id: trace.id,
|
|
306
|
+
name: trace.name,
|
|
307
|
+
startedAt: trace.startedAt.toISOString(),
|
|
308
|
+
finishedAt: finishedAt.toISOString(),
|
|
309
|
+
durationMs,
|
|
310
|
+
metadata: {
|
|
311
|
+
source: "harness-pi-ai"
|
|
312
|
+
},
|
|
313
|
+
spans
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function createUsageModelSpan(trace, usage) {
|
|
317
|
+
if (!usage?.provider && !usage?.model) {
|
|
318
|
+
return void 0;
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
id: `${trace.id}:model:1`,
|
|
322
|
+
traceId: trace.id,
|
|
323
|
+
parentId: trace.rootSpanId,
|
|
324
|
+
name: usage.model ? `pi-ai ${usage.model}` : "pi-ai model",
|
|
325
|
+
kind: "model",
|
|
326
|
+
status: "ok",
|
|
327
|
+
attributes: (0, import_harness.normalizeSpanAttributes)({
|
|
328
|
+
"gen_ai.operation.name": "chat",
|
|
329
|
+
...(0, import_harness.createGenAiUsageAttributes)(usage)
|
|
330
|
+
})
|
|
331
|
+
};
|
|
332
|
+
}
|
|
158
333
|
function resolveInferredToolSurfaces(agent) {
|
|
159
334
|
let runtimeTools;
|
|
160
335
|
const nativeToolsets = [];
|
|
@@ -286,6 +461,7 @@ async function withInstrumentedAgentTools(agent, toolsets, args, callback) {
|
|
|
286
461
|
});
|
|
287
462
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
288
463
|
const call = {
|
|
464
|
+
id: toolCallId,
|
|
289
465
|
name: tool.name,
|
|
290
466
|
arguments: rawArgs,
|
|
291
467
|
result: execution.normalizedResult,
|
|
@@ -310,6 +486,7 @@ async function withInstrumentedAgentTools(agent, toolsets, args, callback) {
|
|
|
310
486
|
} catch (error) {
|
|
311
487
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
312
488
|
const call = {
|
|
489
|
+
id: toolCallId,
|
|
313
490
|
name: tool.name,
|
|
314
491
|
arguments: rawArgs,
|
|
315
492
|
error: serializeToolCallError(error),
|
|
@@ -802,6 +979,7 @@ async function executeToolWithReplay({
|
|
|
802
979
|
}
|
|
803
980
|
// Annotate the CommonJS export names for ESM import in node:
|
|
804
981
|
0 && (module.exports = {
|
|
805
|
-
piAiHarness
|
|
982
|
+
piAiHarness,
|
|
983
|
+
piAiJudgeHarness
|
|
806
984
|
});
|
|
807
985
|
//# sourceMappingURL=index.js.map
|