feat: Pi extension uses Pi's internal complete() for LLM analysis
- PiLLMClient now imports @mariozechner/pi-ai's complete() function - Respects user's /model selection and /login auth - No external fetch() — Pi handles transport internally - Added src/types/pi-ai.d.ts for TypeScript declarations - Extension reverted to real LLM calls (initProject, patchFile, reinitPath) - Tests mock @mariozechner/pi-ai for verification
This commit is contained in:
+30
-12
@@ -15,14 +15,17 @@ vi.mock("typebox", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock Pi's AI module so PiLLMClient works in tests
|
||||
vi.mock("@mariozechner/pi-ai", () => ({
|
||||
complete: vi.fn(async (_model: any, _context: any) => ({
|
||||
role: "assistant" as const,
|
||||
content: [{ type: "text", text: "PURPOSE: Test file\nDEPS: none\nCONCEPTS: testing" }],
|
||||
})),
|
||||
}));
|
||||
|
||||
import extension from "../pi-extension.js";
|
||||
|
||||
const CACHE_FILE = join(
|
||||
homedir(),
|
||||
".cache",
|
||||
"pi-project-map",
|
||||
"llm-cache.json",
|
||||
);
|
||||
const CACHE_FILE = join(homedir(), ".cache", "pi-project-map", "llm-cache.json");
|
||||
function clearCache() {
|
||||
if (existsSync(CACHE_FILE)) unlinkSync(CACHE_FILE);
|
||||
}
|
||||
@@ -40,7 +43,10 @@ describe("pi-extension", () => {
|
||||
mockNotify = vi.fn();
|
||||
mockCtx = {
|
||||
cwd: "/home/project",
|
||||
modelRegistry: {},
|
||||
model: { provider: "openai", id: "gpt-4o-mini", api: "openai-completions" },
|
||||
modelRegistry: {
|
||||
getApiKeyAndHeaders: vi.fn(async () => ({ apiKey: "test-key", headers: {} })),
|
||||
},
|
||||
ui: { notify: mockNotify },
|
||||
};
|
||||
|
||||
@@ -72,7 +78,7 @@ describe("pi-extension", () => {
|
||||
});
|
||||
|
||||
describe("project_map_init tool", () => {
|
||||
it("generates heuristic maps successfully", async () => {
|
||||
it("generates maps with mocked Pi LLM", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "pi-ext-test-"));
|
||||
writeFileSync(join(dir, "test.ts"), `export const x = ${Date.now()};`);
|
||||
mockCtx.cwd = dir;
|
||||
@@ -80,12 +86,24 @@ describe("pi-extension", () => {
|
||||
const tool = registeredTools.project_map_init;
|
||||
const result = await tool.execute("tool-1", {}, null, null, mockCtx);
|
||||
expect(result.details.success).toBe(true);
|
||||
expect(result.content[0].text).toContain("Generated heuristic");
|
||||
expect(result.content[0].text).toContain("Generated");
|
||||
});
|
||||
|
||||
it("returns error when no Pi model configured", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "pi-ext-test-"));
|
||||
writeFileSync(join(dir, "test.ts"), `export const x = ${Date.now()};`);
|
||||
mockCtx.cwd = dir;
|
||||
mockCtx.model = null;
|
||||
|
||||
const tool = registeredTools.project_map_init;
|
||||
const result = await tool.execute("tool-1", {}, null, null, mockCtx);
|
||||
expect(result.details.success).toBe(false);
|
||||
expect(result.content[0].text).toContain("no model configured");
|
||||
});
|
||||
});
|
||||
|
||||
describe("project_map_patch tool", () => {
|
||||
it("patches map successfully using heuristics", async () => {
|
||||
it("patches map with mocked Pi LLM", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "pi-ext-test-"));
|
||||
const file = join(dir, "test.ts");
|
||||
writeFileSync(file, `export const x = ${Date.now()};`);
|
||||
@@ -132,7 +150,7 @@ describe("pi-extension", () => {
|
||||
});
|
||||
|
||||
describe("project_map_reinit tool", () => {
|
||||
it("regenerates heuristic maps successfully", async () => {
|
||||
it("regenerates maps with mocked Pi LLM", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "pi-ext-test-"));
|
||||
writeFileSync(join(dir, "test.ts"), `export const x = ${Date.now()};`);
|
||||
mockCtx.cwd = dir;
|
||||
@@ -140,7 +158,7 @@ describe("pi-extension", () => {
|
||||
const tool = registeredTools.project_map_reinit;
|
||||
const result = await tool.execute("tool-1", {}, null, null, mockCtx);
|
||||
expect(result.details.success).toBe(true);
|
||||
expect(result.content[0].text).toContain("Regenerated heuristic");
|
||||
expect(result.content[0].text).toContain("Regenerated");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user