This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

tools.pi: add ollama provider with auto-discovery, fix settings reload

New extension queries /api/tags at startup and registers every model
under a single "ollama" provider via the OpenAI-compat layer. Endpoint
points at neoprism.r:11434 — reachable from retiolum via the c-base-ai
autossh tunnel.

settings-env.patch also patches SettingsManager.reload() so the
PI_SETTINGS_FILE merge survives resourceLoader.reload() — without this
the bundled extensions list was being wiped after initial load.

+92 -4
+1
tools/pi/flake-module.nix
··· 49 49 ./questionnaire.ts 50 50 ./auto-theme.ts 51 51 ./websearch.ts 52 + ./ollama.ts 52 53 ]; 53 54 defaultProvider = "openrouter"; 54 55 defaultModel = "deepseek/deepseek-v4-pro";
+73
tools/pi/ollama.ts
··· 1 + /** 2 + * Ollama provider — auto-discover models from a remote Ollama server. 3 + * 4 + * Queries the Ollama `/api/tags` endpoint at startup and registers every 5 + * model it returns under a single provider, talking via Ollama's OpenAI 6 + * compatibility layer (`/v1/chat/completions`). 7 + */ 8 + 9 + import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"; 10 + 11 + const ENDPOINTS: { name: string; host: string }[] = [ 12 + { name: "c-base", host: "http://neoprism.r:11434" }, 13 + ]; 14 + 15 + const DISCOVERY_TIMEOUT_MS = 3000; 16 + 17 + interface OllamaTag { 18 + name: string; 19 + model: string; 20 + details?: { 21 + parameter_size?: string; 22 + family?: string; 23 + }; 24 + } 25 + 26 + async function fetchTags(host: string): Promise<OllamaTag[]> { 27 + const ctl = new AbortController(); 28 + const timer = setTimeout(() => ctl.abort(), DISCOVERY_TIMEOUT_MS); 29 + try { 30 + const res = await fetch(`${host}/api/tags`, { signal: ctl.signal }); 31 + if (!res.ok) throw new Error(`HTTP ${res.status}`); 32 + const body = (await res.json()) as { models?: OllamaTag[] }; 33 + return body.models ?? []; 34 + } finally { 35 + clearTimeout(timer); 36 + } 37 + } 38 + 39 + export default async function ollama(pi: ExtensionAPI) { 40 + for (const { name, host } of ENDPOINTS) { 41 + let tags: OllamaTag[]; 42 + try { 43 + tags = await fetchTags(host); 44 + } catch (err) { 45 + console.error( 46 + `[ollama] discovery failed for ${host}: ${err instanceof Error ? err.message : err}`, 47 + ); 48 + continue; 49 + } 50 + 51 + if (tags.length === 0) continue; 52 + 53 + const providerName = ENDPOINTS.length === 1 ? "ollama" : `ollama-${name}`; 54 + 55 + pi.registerProvider(providerName, { 56 + name: `Ollama (${name})`, 57 + baseUrl: `${host}/v1`, 58 + apiKey: "ollama", 59 + api: "openai-completions", 60 + models: tags.map((t) => ({ 61 + id: t.model, 62 + name: t.details?.parameter_size 63 + ? `${t.model} (${t.details.parameter_size})` 64 + : t.model, 65 + reasoning: false, 66 + input: ["text"], 67 + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, 68 + contextWindow: 32768, 69 + maxTokens: 8192, 70 + })), 71 + }); 72 + } 73 + }
+18 -4
wrapperModules/pi/settings-env.patch
··· 1 - --- /tmp/settings-manager.js.orig 2026-02-18 23:29:05.967146474 +0100 2 - +++ /tmp/settings-manager.js 2026-02-18 23:29:12.452952321 +0100 3 - @@ -97,7 +97,16 @@ 1 + --- a/dist/core/settings-manager.js 2 + +++ b/dist/core/settings-manager.js 3 + @@ -130,7 +130,16 @@ 4 4 /** Create a SettingsManager that loads from files */ 5 - static create(cwd = process.cwd(), agentDir = getAgentDir()) { 5 + static create(cwd, agentDir = getAgentDir()) { 6 6 const storage = new FileSettingsStorage(cwd, agentDir); 7 7 - return SettingsManager.fromStorage(storage); 8 8 + const manager = SettingsManager.fromStorage(storage); ··· 18 18 } 19 19 /** Create a SettingsManager from an arbitrary storage backend */ 20 20 static fromStorage(storage) { 21 + @@ -250,6 +259,13 @@ 22 + this.projectSettingsLoadError = projectLoad.error; 23 + this.recordError("project", projectLoad.error); 24 + } 25 + + const baseFile = process.env.PI_SETTINGS_FILE; 26 + + if (baseFile) { 27 + + try { 28 + + const baseSettings = JSON.parse(readFileSync(baseFile, "utf-8")); 29 + + this.globalSettings = deepMergeSettings(this.globalSettings, baseSettings); 30 + + } catch (e) {} 31 + + } 32 + this.settings = deepMergeSettings(this.globalSettings, this.projectSettings); 33 + } 34 + /** Apply additional overrides on top of current settings */