@webfueler/oc-dash 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ocGetJson } from "./opencode.js";
|
|
2
|
+
/**
|
|
3
|
+
* Pure parse of the opencode2 service's GET /api/model payload into the
|
|
4
|
+
* providerID/id -> name map. Entries missing any of the three fields — or
|
|
5
|
+
* carrying an empty or whitespace-only name — drop out, so the client's
|
|
6
|
+
* fallback (the raw id) never receives a blank or wrong label. Accepts both
|
|
7
|
+
* the raw array and the { data: [...] } wrapper the promise client can
|
|
8
|
+
* produce.
|
|
9
|
+
*/
|
|
10
|
+
export function parseModelNames(payload) {
|
|
11
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
12
|
+
const wrapped = payload;
|
|
13
|
+
if (Array.isArray(wrapped.data))
|
|
14
|
+
payload = wrapped.data;
|
|
15
|
+
}
|
|
16
|
+
if (!Array.isArray(payload))
|
|
17
|
+
return {};
|
|
18
|
+
const names = {};
|
|
19
|
+
for (const entry of payload) {
|
|
20
|
+
if (!entry || typeof entry !== "object")
|
|
21
|
+
continue;
|
|
22
|
+
const { providerID, id, name } = entry;
|
|
23
|
+
if (typeof providerID !== "string" || typeof id !== "string" || typeof name !== "string") {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
// Trim before the non-empty check so a whitespace-only name can never
|
|
27
|
+
// reach the label surfaces as a blank; surrounding whitespace on a real
|
|
28
|
+
// name is noise, so the trimmed value is what gets stored.
|
|
29
|
+
const trimmed = name.trim();
|
|
30
|
+
if (!providerID || !id || !trimmed)
|
|
31
|
+
continue;
|
|
32
|
+
names[`${providerID}/${id}`] = trimmed;
|
|
33
|
+
}
|
|
34
|
+
return names;
|
|
35
|
+
}
|
|
36
|
+
// The model catalog is static for the life of a service, so a success lives
|
|
37
|
+
// an hour and a failure retries sooner — the update-check pattern
|
|
38
|
+
// (index.ts:43-44): the caller never waits on a cold fetch more than once
|
|
39
|
+
// per window, and any failure degrades to an empty map (raw-id labels).
|
|
40
|
+
const MODEL_NAMES_TTL_MS = 60 * 60 * 1000;
|
|
41
|
+
const MODEL_NAMES_RETRY_MS = 5 * 60 * 1000;
|
|
42
|
+
let cache = null;
|
|
43
|
+
/**
|
|
44
|
+
* The cached name map. One /api/model fetch per TTL window, never per
|
|
45
|
+
* request; any failure is an empty map so every label surface falls back to
|
|
46
|
+
* today's raw-id behavior.
|
|
47
|
+
*/
|
|
48
|
+
export async function modelNames(oc) {
|
|
49
|
+
if (cache && Date.now() < cache.expiresAt)
|
|
50
|
+
return cache.names;
|
|
51
|
+
let names;
|
|
52
|
+
let ttl;
|
|
53
|
+
try {
|
|
54
|
+
names = parseModelNames(await ocGetJson(oc, "/api/model"));
|
|
55
|
+
ttl = MODEL_NAMES_TTL_MS;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
names = {};
|
|
59
|
+
ttl = MODEL_NAMES_RETRY_MS;
|
|
60
|
+
}
|
|
61
|
+
cache = { names, expiresAt: Date.now() + ttl };
|
|
62
|
+
return names;
|
|
63
|
+
}
|
|
64
|
+
/** Test seam: forget the module-level cache. */
|
|
65
|
+
export function resetModelNamesCache() {
|
|
66
|
+
cache = null;
|
|
67
|
+
}
|