@kontextmind/kxm
Version:
KXM local-first multi-agent orchestration and operator dashboard
288 lines (262 loc) • 8.67 kB
text/typescript
/**
* Legacy Pi registerProvider glue for opt-in Nous routes.
* No @earendil-works/pi-ai import. Direct auth is NOUS_API_KEY only.
*/
import { readFile } from "node:fs/promises";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import {
NOUS_DIRECT_BASE_URL,
NOUS_DIRECT_ID,
NOUS_PROXY_DEFAULT_BASE_URL,
NOUS_PROXY_ID,
NOUS_PROXY_PLACEHOLDER_KEY,
buildModelConfigs,
fetchNousModels,
guidanceFor,
isLoopbackUrl,
modelsUrl,
parseCatalogPin,
parseNousEnv,
sanitizeNousText,
type BuiltModel,
type CatalogLoad,
type DiscoveryOutcome,
type DiscoveryProvenance,
type GuidanceMessage,
type NousCatalogPin,
type NousEnvParse,
type NousProviderKind,
} from "./nous-provider.ts";
export interface NousProviderRegistration {
id: string;
registered: number;
skipped: number;
error?: string;
reason?: string;
provenance?: DiscoveryProvenance;
}
export interface NousRegistrationReport {
optedIn: boolean;
direct: NousProviderRegistration;
proxy: NousProviderRegistration;
guidance: GuidanceMessage[];
registeredProviders: string[];
}
export interface NousRegisterDeps {
env?: NodeJS.Dict<string>;
fetch?: typeof fetch;
readFile?: (path: string) => Promise<string>;
nowMs?: number;
}
type LegacyPi = Pick<ExtensionAPI, "registerProvider">;
const emptySide = (id: string): NousProviderRegistration => ({ id, registered: 0, skipped: 0 });
export function emptyNousReport(): NousRegistrationReport {
return {
optedIn: false,
direct: emptySide(NOUS_DIRECT_ID),
proxy: emptySide(NOUS_PROXY_ID),
guidance: [],
registeredProviders: [],
};
}
/**
* Factory helper: unset stays synchronous; invalid tokens fail closed without
* fetch; opted-in routes discover then register before Pi lists models.
*/
export function nousFactoryWork(
pi: ExtensionAPI,
onReport: (report: NousRegistrationReport) => void,
deps: NousRegisterDeps = {},
): void | Promise<void> {
const env = deps.env ?? process.env;
const parsed = parseNousEnv(env);
if (parsed.status === "unset") {
onReport(emptyNousReport());
return;
}
if (parsed.status === "invalid") {
onReport({
...emptyNousReport(),
optedIn: true,
guidance: guidanceFor({ parsed }),
});
return;
}
return registerNousProviders(pi, deps).then(onReport);
}
export async function registerNousProviders(
pi: LegacyPi,
deps: NousRegisterDeps = {},
): Promise<NousRegistrationReport> {
const env = deps.env ?? process.env;
const parsed = parseNousEnv(env);
if (parsed.status === "unset") return emptyNousReport();
if (parsed.status === "invalid") {
return { ...emptyNousReport(), optedIn: true, guidance: guidanceFor({ parsed }) };
}
const report = emptyNousReport();
report.optedIn = true;
let pin: NousCatalogPin | undefined;
let catalogError: string | undefined;
if (parsed.catalogFile) {
const loaded = await loadCatalog(parsed.catalogFile, deps);
if (loaded.ok) pin = loaded.pin;
else catalogError = loaded.reason;
}
const skipped: Array<{ id: string; reason: string }> = [];
let directDiscovery: DiscoveryOutcome | undefined;
let proxyDiscovery: DiscoveryOutcome | undefined;
let proxyUrlInvalid = false;
const directHasKey = hasDirectKey(env);
if (parsed.providers.includes("direct")) {
const result = await registerRoute({
pi,
route: "direct",
env,
parsed,
pin,
hasKey: directHasKey,
...(deps.fetch ? { fetchImpl: deps.fetch } : {}),
...(deps.nowMs !== undefined ? { nowMs: deps.nowMs } : {}),
});
report.direct = result.side;
directDiscovery = result.discovery;
skipped.push(...result.skipped);
if (result.registered) report.registeredProviders.push(NOUS_DIRECT_ID);
}
if (parsed.providers.includes("proxy")) {
if (!isLoopbackUrl(parsed.proxyUrl)) {
proxyUrlInvalid = true;
report.proxy = {
id: NOUS_PROXY_ID,
registered: 0,
skipped: 0,
error: "non-loopback",
reason: "proxy URL is not loopback http(s)",
};
} else {
const result = await registerRoute({
pi,
route: "proxy",
env,
parsed,
pin,
hasKey: true,
...(deps.fetch ? { fetchImpl: deps.fetch } : {}),
...(deps.nowMs !== undefined ? { nowMs: deps.nowMs } : {}),
});
report.proxy = result.side;
proxyDiscovery = result.discovery;
skipped.push(...result.skipped);
if (result.registered) report.registeredProviders.push(NOUS_PROXY_ID);
}
}
report.guidance = guidanceFor({
parsed,
directHasKey,
proxyUrlInvalid,
skipped,
...(directDiscovery ? { directDiscovery } : {}),
...(proxyDiscovery ? { proxyDiscovery } : {}),
...(catalogError ? { catalogError } : {}),
});
return report;
}
async function registerRoute(input: {
pi: LegacyPi;
route: NousProviderKind;
env: NodeJS.Dict<string>;
parsed: Extract<NousEnvParse, { status: "ready" }>;
pin: NousCatalogPin | undefined;
fetchImpl?: typeof fetch;
hasKey: boolean;
nowMs?: number;
}): Promise<{
side: NousProviderRegistration;
discovery?: DiscoveryOutcome;
skipped: Array<{ id: string; reason: string }>;
registered: boolean;
}> {
const providerId = input.route === "direct" ? NOUS_DIRECT_ID : NOUS_PROXY_ID;
const baseUrl = input.route === "direct" ? NOUS_DIRECT_BASE_URL : input.parsed.proxyUrl;
const side: NousProviderRegistration = { id: providerId, registered: 0, skipped: 0 };
if (input.route === "direct" && !input.hasKey) {
registerLegacy(input.pi, providerId, baseUrl, "$NOUS_API_KEY", []);
return { side, skipped: [], registered: true };
}
const authorization = input.route === "direct"
? input.env.NOUS_API_KEY
: NOUS_PROXY_PLACEHOLDER_KEY;
const discovery = await fetchNousModels({
url: modelsUrl(baseUrl),
timeoutMs: input.parsed.timeoutMs,
...(authorization ? { authorization } : {}),
...(input.fetchImpl ? { fetchImpl: input.fetchImpl } : {}),
...(input.nowMs !== undefined ? { nowMs: input.nowMs } : {}),
});
if (!discovery.ok) {
side.error = discovery.error;
side.reason = discovery.reason;
registerLegacy(input.pi, providerId, baseUrl, apiKeyRef(input.route), []);
return { side, discovery, skipped: [], registered: true };
}
if (discovery.provenance) side.provenance = discovery.provenance;
const built = buildModelConfigs(discovery.models, input.pin, input.route);
side.registered = built.registered.length;
side.skipped = built.skipped.length;
registerLegacy(input.pi, providerId, baseUrl, apiKeyRef(input.route), built.registered);
return { side, discovery, skipped: built.skipped, registered: true };
}
function apiKeyRef(route: NousProviderKind): string {
return route === "direct" ? "$NOUS_API_KEY" : NOUS_PROXY_PLACEHOLDER_KEY;
}
function registerLegacy(
pi: LegacyPi,
id: string,
baseUrl: string,
apiKey: string,
models: BuiltModel[],
): void {
if (typeof pi.registerProvider !== "function") {
throw new Error("Pi registerProvider is unavailable");
}
pi.registerProvider(id, {
name: id === NOUS_DIRECT_ID ? "Nous" : "Nous subscription proxy",
baseUrl,
apiKey,
api: "openai-completions",
authHeader: true,
models: models.map((model) => ({
id: model.id,
name: model.name,
reasoning: model.reasoning === true,
input: model.input && model.input.length > 0 ? model.input : ["text"],
// Upper-bound rates only: Pi cost.tiers uses strict > and can underquote.
cost: {
input: model.cost.input,
output: model.cost.output,
cacheRead: model.cost.cacheRead,
cacheWrite: model.cost.cacheWrite,
},
contextWindow: model.contextWindow,
maxTokens: model.maxTokens,
})),
});
}
function hasDirectKey(env: NodeJS.Dict<string>): boolean {
const key = env.NOUS_API_KEY;
return typeof key === "string" && key.trim().length > 0;
}
async function loadCatalog(path: string, deps: NousRegisterDeps): Promise<CatalogLoad> {
try {
const read = deps.readFile ?? ((filePath: string) => readFile(filePath, "utf8"));
const text = await read(path);
return parseCatalogPin(JSON.parse(text) as unknown, deps.nowMs ?? Date.now());
} catch (error) {
if (error instanceof SyntaxError) {
return { ok: false, reason: "catalog file is not valid JSON" };
}
return { ok: false, reason: sanitizeNousText(error instanceof Error ? error.message : "catalog file could not be read") };
}
}
export const NOUS_PROXY_DEFAULT = NOUS_PROXY_DEFAULT_BASE_URL;