fix: read V2 provider settings for server discovery; bump 1.4.1

This commit is contained in:
Troed Sångberg
2026-09-21 10:53:25 +00:00
parent baea593f9c
commit 63bc15f0ae
3 changed files with 77 additions and 21 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@troed/oc-ls-stats",
"version": "1.4.0",
"version": "1.4.1",
"type": "module",
"files": [
"tui.tsx",
+26 -20
View File
@@ -220,22 +220,34 @@ export function stripBaseUrlPath(baseURL: string): string {
}
}
// V1 stores a provider endpoint under options; V2 under settings
// (migrate-v1: "api becomes settings.baseURL", "provider options are separated
// into settings, headers, and body"). Read whichever is present.
function extractBaseURL(entry: unknown): string | undefined {
if (!entry || typeof entry !== "object") return undefined
const record = entry as Record<string, unknown>
for (const key of ["settings", "options"]) {
const section = record[key]
if (!section || typeof section !== "object") continue
const baseURL =
(section as Record<string, unknown>).baseURL || (section as Record<string, unknown>).base_url
if (typeof baseURL === "string") return baseURL
}
return undefined
}
export function extractProviderUrls(config: unknown): string[] {
if (!config || typeof config !== "object") return []
const obj = config as Record<string, unknown>
const provider = obj.provider
const provider = obj.providers ?? obj.provider
if (!provider || typeof provider !== "object") return []
const urls: string[] = []
for (const [key, val] of Object.entries(provider as Record<string, unknown>)) {
if (val && typeof val === "object") {
const opts = (val as Record<string, unknown>).options
if (opts && typeof opts === "object") {
const baseURL = (opts as Record<string, unknown>).baseURL || (opts as Record<string, unknown>).base_url
if (typeof baseURL === "string" && key.toLowerCase().includes("llama") && !key.toLowerCase().includes("ollama")) {
urls.push(stripBaseUrlPath(baseURL))
}
}
const baseURL = extractBaseURL(val)
const hay = key.toLowerCase()
if (typeof baseURL === "string" && hay.includes("llama") && !hay.includes("ollama")) {
urls.push(stripBaseUrlPath(baseURL))
}
}
return urls
@@ -251,9 +263,7 @@ export function extractProviderUrlsFromList(providers: unknown): string[] {
const name = typeof provider.name === "string" ? provider.name.toLowerCase() : ""
const hay = `${id} ${name}`
if (!hay.includes("llama") || hay.includes("ollama")) continue
const opts = provider.options
if (!opts || typeof opts !== "object") continue
const baseURL = (opts as Record<string, unknown>).baseURL || (opts as Record<string, unknown>).base_url
const baseURL = extractBaseURL(provider)
if (typeof baseURL === "string") {
urls.push(stripBaseUrlPath(baseURL))
}
@@ -289,14 +299,10 @@ export function selectSessionUrls(
if (!entry || typeof entry !== "object") continue
const provider = entry as Record<string, unknown>
if (provider.id !== providerID) continue
const opts = provider.options
if (opts && typeof opts === "object") {
const baseURL =
(opts as Record<string, unknown>).baseURL || (opts as Record<string, unknown>).base_url
if (typeof baseURL === "string") {
const normalized = stripBaseUrlPath(baseURL)
if (candidates.includes(normalized)) return [normalized]
}
const baseURL = extractBaseURL(provider)
if (typeof baseURL === "string") {
const normalized = stripBaseUrlPath(baseURL)
if (candidates.includes(normalized)) return [normalized]
}
return []
}
+50
View File
@@ -239,3 +239,53 @@ test("duplicate provider URLs are deduped", () => {
]
assert.deepEqual(resolveServerUrls(undefined, providers, {}), ["http://same:7"])
})
// --- V2 provider shape -------------------------------------------------------
// V2 renames provider config "options" to "settings" and the "provider" map to
// "providers" (see migrate-v1: "api becomes settings.baseURL"). Provider records
// returned by the TUI data layer therefore carry settings, not options. These
// tests pin the shape the plugin actually receives at runtime.
const v2LlamaProviders = [
{
id: "llama-local",
name: "llama.cpp (conduct)",
package: "aisdk:@ai-sdk/openai-compatible",
settings: { baseURL: "http://<server-host>:8100/v1" },
models: {},
},
]
test("V2 provider settings.baseURL is detected", () => {
assert.deepEqual(resolveServerUrls(undefined, v2LlamaProviders, undefined), [
"http://<server-host>:8100",
])
})
test("V2 provider settings.base_url variant is detected", () => {
const snake = [
{ id: "llama-local", name: "llama.cpp", settings: { base_url: "http://localhost:9090/v1" } },
]
assert.deepEqual(resolveServerUrls(undefined, snake, undefined), ["http://localhost:9090"])
})
test("selectSessionUrls uses V2 provider settings.baseURL", () => {
assert.deepEqual(
selectSessionUrls(["http://<server-host>:8100"], v2LlamaProviders, "llama-local"),
["http://<server-host>:8100"],
)
})
test("V2 config providers/settings fallback is parsed", () => {
const v2Config = {
providers: {
"llama-local": { settings: { baseURL: "http://localhost:9090/v1" } },
},
}
assert.deepEqual(resolveServerUrls(undefined, undefined, v2Config), ["http://localhost:9090"])
})
test("V2 provider settings still excludes non-candidate providers", () => {
const providers = [{ id: "llama-local", name: "llama.cpp", settings: { baseURL: "http://other:1" } }]
assert.deepEqual(selectSessionUrls(["http://localhost:8080"], providers, "llama-local"), [])
})