5c6719817f
- 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
83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
import { LLMError } from "./llm-error.js";
|
|
import type { LLMClient } from "./llm-client.js";
|
|
|
|
/**
|
|
* Pi LLM Client — uses Pi's built-in `complete()` from `@mariozechner/pi-ai`.
|
|
*
|
|
* This runs inside the Pi extension runtime and calls Pi's internal AI layer,
|
|
* which respects the user's configured model (/model) and auth (/login).
|
|
* No external fetch() — Pi handles transport, retries, and token accounting.
|
|
*/
|
|
export class PiLLMClient implements LLMClient {
|
|
constructor(private extensionContext?: unknown) {}
|
|
|
|
async complete(prompt: string): Promise<string> {
|
|
const ctx = this.extensionContext as any;
|
|
|
|
if (!ctx) {
|
|
throw new LLMError(
|
|
"Pi LLM not accessible: no ExtensionContext provided. " +
|
|
"This tool must run inside Pi.",
|
|
);
|
|
}
|
|
|
|
// Get the active model from Pi's runtime
|
|
const model = ctx.model ?? ctx.modelRegistry?.get?.();
|
|
if (!model) {
|
|
throw new LLMError(
|
|
"Pi LLM not accessible: no model configured. " +
|
|
"Set a model via /model before using project-map tools.",
|
|
);
|
|
}
|
|
|
|
try {
|
|
// Dynamically import Pi's AI module (available in the Pi runtime)
|
|
const { complete } = await import("@mariozechner/pi-ai");
|
|
|
|
const response = await complete(
|
|
model,
|
|
{
|
|
systemPrompt:
|
|
"You are a code analysis assistant. Analyze the provided file and respond with concise, structured information.",
|
|
messages: [
|
|
{
|
|
role: "user",
|
|
content: prompt,
|
|
timestamp: Date.now(),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
temperature: 0.1,
|
|
maxTokens: 256,
|
|
},
|
|
);
|
|
|
|
if (response.errorMessage) {
|
|
throw new LLMError(`Pi LLM error: ${response.errorMessage}`);
|
|
}
|
|
|
|
// Extract text content from AssistantMessage
|
|
const text = response.content
|
|
.filter((c: any) => c.type === "text")
|
|
.map((c: any) => c.text)
|
|
.join("")
|
|
.trim();
|
|
|
|
return text;
|
|
} catch (err: any) {
|
|
if (err instanceof LLMError) throw err;
|
|
if (err.code === "MODULE_NOT_FOUND") {
|
|
throw new LLMError(
|
|
"Pi LLM not accessible: @mariozechner/pi-ai is not available. " +
|
|
"This extension must run inside the Pi runtime.",
|
|
);
|
|
}
|
|
throw new LLMError(
|
|
`Pi LLM call failed: ${err.message || String(err)}`,
|
|
err,
|
|
);
|
|
}
|
|
}
|
|
}
|