2026-09-02 22:44:11 +03:00

70 lines
2.2 KiB
TypeScript

import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
const BASE_URL = "http://exacode-chat.lge.com/v1";
// The EXACODE gateway routes requests by the `X-Title` header.
// - "EXACODE Agent Roo" -> the official VS Code extension route; gated by a
// client-version check (blocks curl/SDKs/outdated builds).
// - "EXACODE SWE(API)" -> the API-client route; the intended tier for
// programmatic access. Requires an SWE(API)-scoped bearer token, which
// lives in `.env` as EXACODE_API_KEY (different from the Roo Code JWT).
//
// `X-Model` echoes the requested model id (redundant -- it also travels in the
// request body -- but the official example sets it as a default header).
const X_TITLE = "EXACODE SWE(API)";
// pi does not auto-load `.env`, so populate process.env ourselves at startup.
// Real environment variables take precedence over the file.
function loadDotEnv(file: string) {
if (!existsSync(file)) return;
const text = readFileSync(file, "utf8");
for (const rawLine of text.split(/\r?\n/)) {
const line = rawLine.trim();
if (!line || line.startsWith("#")) continue;
const eq = line.indexOf("=");
if (eq < 0) continue;
const key = line.slice(0, eq).trim();
let value = line.slice(eq + 1).trim();
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
}
if (key && process.env[key] === undefined) {
process.env[key] = value;
}
}
}
loadDotEnv(join(process.cwd(), ".env"));
const MODELS = [
{
id: "Chat-EXACODE-A",
name: "Chat-EXACODE-A (EXACODE 3.5)",
reasoning: true,
input: ["text"] as const,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 131072,
maxTokens: 8192,
headers: { "X-Model": "Chat-EXACODE-A" },
},
];
export default function (pi: ExtensionAPI) {
pi.registerProvider("exacode", {
name: "exacode",
baseUrl: BASE_URL,
apiKey: "$EXACODE_API_KEY",
authHeader: true,
api: "openai-completions",
headers: {
"X-Title": X_TITLE,
},
models: MODELS,
});
}