pi / packages /evals /src /extensions.eval.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
f500658 verified
Raw History Blame Contribute Delete
4.9 kB
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect } from "vitest";
import { createJudge, describeEval } from "vitest-evals";
import { createPiCodingAgentHarness, excludePiDocumentation, type PiCodingAgentInput } from "./pi-harness.ts";
import { recordEvalSourceArtifact } from "./vitest-evals/artifacts.ts";
import { evalHarnessTable } from "./vitest-evals/harness-table.ts";
type ExtensionAuthoringOutput = {
response: string;
systemPromptHasGuidelines: boolean;
systemPromptHasPiDocs: boolean;
extensionErrors: Array<{ path: string; error: string }>;
loadedExtensions: Array<{ path: string; tools: string[] }>;
extensionSource: string | null;
};
function createExtensionAuthoringHarness(name: string, transformSystemPrompt?: (defaultPrompt: string) => string) {
return createPiCodingAgentHarness({
name,
...(transformSystemPrompt ? { transformSystemPrompt } : {}),
output: ({ response, session, systemPrompt }) => {
const extensions = session.resourceLoader.getExtensions();
const extensionPath = join(session.sessionManager.getCwd(), ".pi", "extensions", "hello.ts");
const extensionSource = existsSync(extensionPath) ? readFileSync(extensionPath, "utf8") : null;
return {
response,
systemPromptHasGuidelines: systemPrompt.includes("\nGuidelines:\n"),
systemPromptHasPiDocs: systemPrompt.includes("\nPi documentation (read only"),
extensionErrors: extensions.errors,
loadedExtensions: extensions.extensions.map(({ path, tools }) => ({
path,
tools: [...tools.keys()],
})),
extensionSource,
};
},
});
}
const ExtensionAuthoringJudge = createJudge<PiCodingAgentInput, ExtensionAuthoringOutput>(
"ExtensionAuthoringJudge",
({ output, toolCalls }) => {
const failures: string[] = [];
if (output.extensionSource === null) {
failures.push("generated extension source is unavailable");
} else {
const imports = Array.from(
output.extensionSource.matchAll(/\b(?:from|import)\s+["']([^"']+)["']/g),
(match) => match[1],
);
if (!imports.includes("@earendil-works/pi-coding-agent")) {
failures.push("extension does not import the canonical @earendil-works/pi-coding-agent package");
}
if (imports.some((specifier) => specifier.startsWith("@mariozechner/"))) {
failures.push("extension imports a legacy @mariozechner package");
}
if (imports.some((specifier) => specifier.startsWith("@sinclair/typebox"))) {
failures.push('extension imports legacy "@sinclair/typebox" instead of "typebox"');
}
}
if (output.extensionErrors.length > 0) failures.push("extension loader reported errors");
if (!output.loadedExtensions.some(({ tools }) => tools.includes("hello"))) {
failures.push('no loaded extension registered the "hello" tool');
}
if (
!toolCalls.some(
(call) =>
call.name === "hello" &&
call.status === "ok" &&
call.arguments?.name === "Bob" &&
call.result === "Hello, Bob!",
)
) {
failures.push('no successful hello({ name: "Bob" }) call returned "Hello, Bob!"');
}
if (output.response !== "Hello, Bob!") failures.push('final response was not exactly "Hello, Bob!"');
return {
score: failures.length === 0 ? 1 : 0,
metadata: {
rationale: failures.length === 0 ? "Extension authoring workflow completed." : failures.join("; "),
},
};
},
);
const extensionHarnessTable = evalHarnessTable("Create and use a tool extension", {
baseline: createExtensionAuthoringHarness("system-prompt-without-docs", excludePiDocumentation),
candidate: createExtensionAuthoringHarness("default-system-prompt"),
});
describe.for(extensionHarnessTable)("$name", ({ harness }) => {
describeEval(
"Create and use a tool extension",
{ harness, judges: [ExtensionAuthoringJudge], judgeThreshold: null },
(it) => {
it("creates and uses the extension", async ({ run, task }) => {
const result = await run([
{
type: "prompt",
content:
"Create a Pi extension with a hello tool that takes a name and returns a greeting. For example, passing Bob should return `Hello, Bob!`.",
},
{ type: "reload" },
{
type: "prompt",
content:
"Use the hello tool to greet Bob. Respond with exactly the tool's greeting and nothing else.",
},
]);
if (result.output.extensionSource !== null) {
const runId = result.artifacts?.runId;
if (typeof runId !== "string") throw new Error("Pi eval run did not record a run ID.");
await recordEvalSourceArtifact(task, runId, {
name: "hello.ts",
contentType: "text/typescript",
body: result.output.extensionSource,
bodyEncoding: "utf-8",
});
}
expect(result.output.systemPromptHasGuidelines).toBe(true);
expect(result.output.systemPromptHasPiDocs).toBe(harness.name === "default-system-prompt");
});
},
);
});