mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 16:45:22 +00:00
98 lines
4.1 KiB
TypeScript
98 lines
4.1 KiB
TypeScript
/**
|
|
* mention-clone-tool-reachability.e2e.test.ts — reachability guard for the one
|
|
* tool the mention clone is built around.
|
|
*
|
|
* `runMentionClone` hands a session ONE tool and expects the model to call it.
|
|
* Whether that tool ever reaches the model is decided entirely inside Pi, by
|
|
* `createAgentSession`'s allowlist plumbing — and the unit tests cannot see it:
|
|
* their `createAgentSession` is a mock that hands `customTools[0]` straight to
|
|
* the model turn, so a session option that silently strips the tool passes
|
|
* every one of them.
|
|
*
|
|
* That is not hypothetical. The clone shipped with `noTools: "all"` on the
|
|
* reading its doc comment invites ("start with no tools enabled" — no
|
|
* built-ins, keep mine). Pi turns that flag into an EMPTY allowlist, and an
|
|
* empty array is truthy, so `AgentSession` builds an empty `Set` and
|
|
* `isAllowedTool` rejects every name — custom tools are filtered by the same
|
|
* predicate as built-ins. Every mention was prompted with no tools, answered in
|
|
* prose, and fell back to a direct start with a warning. The unit suite stayed
|
|
* green throughout.
|
|
*
|
|
* So this asserts against a REAL session, on the two things a mock cannot
|
|
* establish:
|
|
* 1. the clone's `Agent` tool is actually active on it, and
|
|
* 2. nothing else is — the invisible turn cannot read, write or run anything.
|
|
*
|
|
* No network/LLM: a faux provider satisfies session construction, and the
|
|
* assertion is on the constructed tool set rather than on a model turn.
|
|
*/
|
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
// Real pi-mono session construction; a cold first run under full-suite CPU
|
|
// contention can exceed vitest's 5s default.
|
|
vi.setConfig({ testTimeout: 30_000 });
|
|
|
|
// Hoisted so the (lifted) mock factory can reach it. Everything except the
|
|
// capture is the real module — the point is to construct a REAL session.
|
|
const { sessions } = vi.hoisted(() => ({ sessions: [] as any[] }));
|
|
|
|
vi.mock("@earendil-works/pi-coding-agent", async () => {
|
|
const actual = await vi.importActual<any>("@earendil-works/pi-coding-agent");
|
|
return {
|
|
...actual,
|
|
createAgentSession: async (opts: any) => {
|
|
const created = await actual.createAgentSession(opts);
|
|
sessions.push(created.session);
|
|
return created;
|
|
},
|
|
};
|
|
});
|
|
|
|
import { runMentionClone } from "../../src/mention-clone.js";
|
|
import { fauxModelBackend } from "../helpers/faux-model-backend.js";
|
|
import { registerFauxProvider } from "../helpers/pi-ai.js";
|
|
|
|
describe("mention clone tool reachability against real pi-mono", () => {
|
|
let cwd: string;
|
|
let faux: ReturnType<typeof registerFauxProvider>;
|
|
|
|
beforeEach(() => {
|
|
sessions.length = 0;
|
|
cwd = mkdtempSync(join(tmpdir(), "subagents-mention-clone-"));
|
|
faux = registerFauxProvider({ provider: "faux", models: [{ id: "faux-1", contextWindow: 200_000 }] });
|
|
});
|
|
afterEach(() => {
|
|
faux.unregister();
|
|
rmSync(cwd, { recursive: true, force: true });
|
|
});
|
|
|
|
it("the clone's Agent tool is live on the real session, and it is the only one", async () => {
|
|
const model = faux.getModel();
|
|
const backend = fauxModelBackend(model);
|
|
const ctx: any = {
|
|
cwd,
|
|
model,
|
|
getSystemPrompt: () => "PARENT",
|
|
// mention-clone reads the runtime off the registry facade, the same shim
|
|
// agent-runner carries for Pi >= 0.80.8.
|
|
modelRegistry: { ...backend.modelRegistry, runtime: backend.modelRuntime },
|
|
sessionManager: { getEntries: () => [], getLeafId: () => undefined },
|
|
};
|
|
|
|
// Never called: the assertion is on what the session exposes, not on the
|
|
// faux model deciding to use it.
|
|
const agentTool = { name: "Agent", execute: vi.fn() } as any;
|
|
|
|
// Never rejects by contract; a faux turn that cannot complete is fine,
|
|
// because the tool set is fixed at construction.
|
|
await runMentionClone({ ctx, type: "Explore", message: "go", agentTool });
|
|
|
|
expect(sessions).toHaveLength(1);
|
|
// The bug this file exists for: with an empty allowlist this is `[]`.
|
|
expect(sessions[0].getActiveToolNames()).toEqual(["Agent"]);
|
|
});
|
|
});
|