From aa5ae2b7241d7aa14cb295e0f3151415228ba6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Troed=20S=C3=A5ngberg?= Date: Fri, 21 Aug 2026 15:52:50 +0200 Subject: [PATCH] fix: stop polling llama-servers during external-model sessions selectSessionUrls fell back to all discovered servers when the current session's provider matched no candidate, so external sessions kept polling local servers: one answered /slots with idle slots (showing '- tps (TG)') while another rejected unknown models with HTTP 400 (flickering 'n/a'). Narrow to zero URLs instead and surface n/a. --- src/stats.ts | 6 +++--- test-backoff.ts | 28 ++++++++++++++++++++++------ tui.tsx | 6 +++++- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/stats.ts b/src/stats.ts index fea030f..22ee523 100644 --- a/src/stats.ts +++ b/src/stats.ts @@ -284,7 +284,7 @@ export function selectSessionUrls( ): string[] { if (typeof providerID !== "string" || providerID.trim() === "" || candidates.length === 0) return candidates - if (!Array.isArray(providers)) return candidates + if (!Array.isArray(providers) || providers.length === 0) return candidates for (const entry of providers) { if (!entry || typeof entry !== "object") continue const provider = entry as Record @@ -298,7 +298,7 @@ export function selectSessionUrls( if (candidates.includes(normalized)) return [normalized] } } - break + return [] } - return candidates + return [] } diff --git a/test-backoff.ts b/test-backoff.ts index 787a860..ed62034 100644 --- a/test-backoff.ts +++ b/test-backoff.ts @@ -178,10 +178,10 @@ test("selectSessionUrls returns candidates unchanged when provider not found", ( assert.deepEqual(selectSessionUrls(candidates, [], "nope"), ["http://a:1"]) }) -test("selectSessionUrls returns candidates unchanged when matched provider URL is not a candidate", () => { +test("selectSessionUrls excludes polling when matched provider URL is not a candidate", () => { const candidates = ["http://a:1"] const providers = [{ id: "ollama", name: "Ollama", options: { baseURL: "http://d:4" } }] - assert.deepEqual(selectSessionUrls(candidates, providers, "ollama"), ["http://a:1"]) + assert.deepEqual(selectSessionUrls(candidates, providers, "ollama"), []) }) test("selectSessionUrls returns candidates unchanged for missing or empty providerID", () => { @@ -191,20 +191,36 @@ test("selectSessionUrls returns candidates unchanged for missing or empty provid assert.deepEqual(selectSessionUrls(["http://a:1"], [], 42), ["http://a:1"]) }) -test("selectSessionUrls ignores non-string baseURL on matched provider", () => { +test("selectSessionUrls excludes polling when matched provider has no usable baseURL", () => { const candidates = ["http://a:1"] const providers = [{ id: "p", name: "P", options: { baseURL: 42 } }] - assert.deepEqual(selectSessionUrls(candidates, providers, "p"), ["http://a:1"]) + assert.deepEqual(selectSessionUrls(candidates, providers, "p"), []) }) test("selectSessionUrls returns empty candidates unchanged", () => { assert.deepEqual(selectSessionUrls([], [], "p"), []) }) -test("selectSessionUrls tolerates non-array and malformed providers", () => { +test("selectSessionUrls tolerates non-array providers", () => { const c = ["http://a:1"] assert.deepEqual(selectSessionUrls(c, undefined, "p"), c) - assert.deepEqual(selectSessionUrls(c, [null, 42, {}, { id: "p" }], "p"), c) +}) + +test("selectSessionUrls excludes polling when id is absent from a non-empty provider list", () => { + assert.deepEqual(selectSessionUrls(["http://a:1"], [null, 42, {}], "p"), []) + assert.deepEqual(selectSessionUrls(["http://a:1"], [{ id: "other", options: { baseURL: "http://a:1" } }], "p"), []) +}) + +test("selectSessionUrls excludes polling during external-model sessions", () => { + // Mirrors the reported regression: local router + single-model server discovered, + // while the session runs on an unrelated external provider. + const candidates = ["http://localhost:8080", "http://127.0.0.1:40909"] + const providers = [ + { id: "llamacpp-router", name: "llama.cpp router", options: { baseURL: "http://localhost:8080/v1" } }, + { id: "ornith", name: "Ornith", options: { baseURL: "http://127.0.0.1:40909/v1" } }, + { id: "opencode", name: "OpenCode", options: { baseURL: "https://api.example.internal/v1" } }, + ] + assert.deepEqual(selectSessionUrls(candidates, providers, "opencode"), []) }) test("selectSessionUrls first match wins for duplicate ids", () => { diff --git a/tui.tsx b/tui.tsx index 10f900f..bafb046 100644 --- a/tui.tsx +++ b/tui.tsx @@ -197,7 +197,11 @@ const tui: TuiPlugin = async (api, options) => { } const activeUrls = selectSessionUrls(llamaServerUrls, api.state.provider, sessionProviderId) - if (!activeUrls.length) return + if (!activeUrls.length) { + tracker.failure = "n/a" + bump() + return + } for (const baseUrl of activeUrls) { const now = Date.now() const backoff = backoffByUrl.get(baseUrl)