pi/wrapper.integration.test.mjs
Rama main · réplica de lectura del repositorio original.
import assert from "node:assert/strict";
import test from "node:test";
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
const packageRoot = process.env.PI_CODING_AGENT_ROOT;
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
// Opt-in: exercises the installed Pi runtime, without a provider or model calls.
test("real Pi runner handles structured prompts, legacy options and earlier overrides", {
skip: !packageRoot && "Set PI_CODING_AGENT_ROOT to an installed Pi package directory",
}, async (t) => {
const load = (path) => import(pathToFileURL(resolve(packageRoot, path)).href);
const { loadExtensions } = await load("dist/core/extensions/loader.js");
const { ExtensionRunner } = await load("dist/core/extensions/runner.js");
const { buildSystemPrompt, buildSystemPromptSections } = await load("dist/core/system-prompt.js");
const { version } = JSON.parse(readFileSync(resolve(packageRoot, "package.json"), "utf8"));
t.diagnostic(`Pi ${version}, Node ${process.version}, ${process.platform}/${process.arch}`);
for (const active of [false, true]) {
for (const override of [false, true]) {
await t.test(`active=${active}, earlier override=${override}`, async (t) => {
const tempRoot = mkdtempSync(join(tmpdir(), "ars-pi-composition-"));
t.after(() => rmSync(tempRoot, { recursive: true, force: true }));
const early = join(tempRoot, "early.mjs");
const late = join(tempRoot, "late.mjs");
writeFileSync(early, `export default pi => pi.on("before_agent_start", event => {
if (${override} || !event.systemPromptOptions?.sections) {
return { systemPrompt: event.systemPrompt + "\\nMCP sentinel from an earlier extension" };
}
event.systemPromptOptions.sections.mcp_servers = "MCP sentinel from an earlier extension";
});`);
writeFileSync(late, `export default pi => pi.on("before_agent_start", event => {
const options = event.systemPromptOptions;
if (!options?.sections || options.forceSystemPrompt !== undefined) {
return { systemPrompt: event.systemPrompt + "\\nSentinel from a later extension" };
}
options.sections.later_extension = "Sentinel from a later extension";
});`);
const loaded = await loadExtensions([early, resolve(repoRoot, "pi/wrapper.js"), late], tempRoot);
assert.deepEqual(loaded.errors, []);
// State persistence is isolated; no user session or provider is opened.
loaded.runtime.appendEntry = () => {};
const runner = new ExtensionRunner(loaded.extensions, loaded.runtime, tempRoot, {}, {});
const errors = [];
runner.onError((error) => errors.push(error));
const names = ["deep-research", "academic-paper", "academic-paper-reviewer", "academic-pipeline"];
const options = {
cwd: tempRoot,
skills: [
...names.map((name) => ({
name, description: "ARS skill", filePath: resolve(repoRoot, name, "SKILL.md"),
baseDir: resolve(repoRoot, name), source: "test",
})),
{ name: "deep-research", description: "Unrelated", filePath: "/missing/external/SKILL.md", baseDir: "/missing/external", source: "test" },
],
};
if (buildSystemPromptSections) options.sections = {};
if (active) await runner.emitInput("/skill:academic-pipeline topic", undefined, "interactive");
let result;
switch (runner.emitBeforeAgentStart.length) {
case 4: // Pi through 0.85: (prompt, images, rendered prompt, options).
result = await runner.emitBeforeAgentStart("Test prompt", undefined, buildSystemPrompt(options), options);
break;
case 3: // Pi 0.86 / 1.1: (prompt, images, options).
result = await runner.emitBeforeAgentStart("Test prompt", undefined, options);
break;
case 2: // Pi 1.3: (trigger, options).
result = await runner.emitBeforeAgentStart({ messageType: "user", prompt: "Test prompt" }, options);
break;
default:
assert.fail("Unrecognized Pi runner signature");
}
assert.deepEqual(errors, []);
const prompt = result?.systemPrompt ?? buildSystemPrompt(result?.systemPromptOptions ?? options);
assert.match(prompt, /MCP sentinel/);
assert.match(prompt, /Sentinel from a later extension/);
assert.match(prompt, /\/missing\/external\/SKILL.md/);
for (const name of names) assert.equal(prompt.includes(resolve(repoRoot, name, "SKILL.md")), active);
assert.equal(prompt.includes("## Academic Research Skills compatibility for Pi"), active);
if (buildSystemPromptSections && !override) {
assert.equal(result.systemPromptOptions.forceSystemPrompt, undefined);
assert.equal(result.systemPromptOptions.skills.length, active ? 5 : 1);
const sections = buildSystemPromptSections(result.systemPromptOptions);
assert.match(sections.mcp_servers, /MCP sentinel/);
assert.match(sections.later_extension, /Sentinel from a later extension/);
assert.equal(Object.hasOwn(sections, "ars_compatibility"), active);
assert.equal(buildSystemPrompt(result.systemPromptOptions), prompt);
}
});
}
}
});