Created
September 1, 2026 13:18
-
-
Save duarteocarmo/39a3f1148e2e33c27fddbbef2d971deb to your computer and use it in GitHub Desktop.
Experimental NobodyWho provider extension for Pi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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}`); | |
| } | |
| } | |
| }); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "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