Skip to content

Instantly share code, notes, and snippets.

@duarteocarmo
Created September 1, 2026 13:18
Show Gist options
  • Select an option

  • Save duarteocarmo/39a3f1148e2e33c27fddbbef2d971deb to your computer and use it in GitHub Desktop.

Select an option

Save duarteocarmo/39a3f1148e2e33c27fddbbef2d971deb to your computer and use it in GitHub Desktop.
Experimental NobodyWho provider extension for Pi
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
const PROVIDER_ID = "nobodywho";
const DEFAULT_BASE_URL = "http://127.0.0.1:8888/v1";
const DEFAULT_CONTEXT_WINDOW = 4096;
const REQUEST_TIMEOUT_MS = 3000;
type ProviderModel = NonNullable<Parameters<ExtensionAPI["registerProvider"]>[1]["models"]>[number];
function apiBaseUrl(value: string): string {
const baseUrl = value.replace(/\/+$/, "");
return baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null;
}
function positiveNumber(value: unknown, fallback: number): number {
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
}
function parseModels(payload: unknown): ProviderModel[] {
if (!isRecord(payload) || !Array.isArray(payload.data)) {
throw new Error("invalid /v1/models response");
}
const models = payload.data.flatMap((value): ProviderModel[] => {
if (!isRecord(value) || typeof value.id !== "string" || value.owned_by !== "nobodywho") {
return [];
}
const contextWindow = positiveNumber(value.context_window, DEFAULT_CONTEXT_WINDOW);
const maxTokens = positiveNumber(value.max_tokens, contextWindow);
return [
{
id: value.id,
name: typeof value.name === "string" ? value.name : value.id,
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow,
maxTokens,
compat: {
supportsDeveloperRole: false,
supportsReasoningEffort: false,
supportsUsageInStreaming: false,
supportsStrictMode: false,
maxTokensField: "max_tokens",
},
},
];
});
if (models.length === 0) {
throw new Error(
"the configured endpoint did not report a NobodyWho model; another server may be using this port",
);
}
return models;
}
export default async function (pi: ExtensionAPI) {
const baseUrl = apiBaseUrl(process.env.NOBODYWHO_BASE_URL ?? DEFAULT_BASE_URL);
const apiKey = process.env.NOBODYWHO_API_KEY ?? "local";
let currentModels: ProviderModel[] = [];
async function refreshProvider(): Promise<ProviderModel[]> {
const response = await fetch(`${baseUrl}/models`, {
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
});
if (!response.ok) {
throw new Error(`${baseUrl}/models returned ${response.status}`);
}
const models = parseModels(await response.json());
currentModels = models;
pi.registerProvider(PROVIDER_ID, {
name: "NobodyWho",
baseUrl,
apiKey,
api: "openai-completions",
models,
});
return models;
}
pi.registerCommand("nobodywho-refresh", {
description: "Refresh models from the NobodyWho server",
handler: async (_args, ctx) => {
try {
const models = await refreshProvider();
ctx.ui.notify(
`[nobodywho] ${models.map((model) => model.id).join(", ")} at ${baseUrl}`,
"info",
);
} catch (error) {
ctx.ui.notify(`[nobodywho] ${(error as Error).message}`, "error");
}
},
});
try {
await refreshProvider();
} catch (error) {
console.warn(`[nobodywho] ${(error as Error).message}`);
}
pi.on("input", async (event) => {
if (event.text.trim().toLowerCase() !== "/model") {
return;
}
try {
await refreshProvider();
} catch (error) {
if (currentModels.length === 0) {
console.warn(`[nobodywho] ${(error as Error).message}`);
}
}
});
}
{
"name": "pi-nobodywho",
"version": "0.1.0",
"description": "NobodyWho provider extension for Pi",
"keywords": ["local-llm", "nobodywho", "pi-extension", "pi-package"],
"license": "EUPL-1.2",
"private": true,
"type": "module",
"peerDependencies": {
"@earendil-works/pi-coding-agent": "*"
},
"peerDependenciesMeta": {
"@earendil-works/pi-coding-agent": {
"optional": true
}
},
"pi": {
"extensions": ["./index.ts"]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment