openzoo 0.21.7 → 0.22.0
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.
- package/lib/setup.js +58 -18
- package/package.json +1 -1
package/lib/setup.js
CHANGED
|
@@ -52,21 +52,37 @@ async function catalogModels(base) {
|
|
|
52
52
|
if (process.env.OPENZOO_MODELS) {
|
|
53
53
|
return process.env.OPENZOO_MODELS.split(',').map((m) => m.trim()).filter(Boolean);
|
|
54
54
|
}
|
|
55
|
+
// NAMES THE EDITOR WILL ACCEPT — this is the whole ballgame.
|
|
56
|
+
//
|
|
57
|
+
// We used to write `openzoo-<model>` twins here, on the theory that a name the
|
|
58
|
+
// editor recognises gets claimed by its own backend. That theory was never
|
|
59
|
+
// actually tested: it rested on "zero connections reached the proxy", which was
|
|
60
|
+
// equally true of both naming schemes, so it discriminated nothing. The real
|
|
61
|
+
// cause of zero connections was a stale pin trigger rewriting the base URL.
|
|
62
|
+
//
|
|
63
|
+
// MEASURED, on two machines: with openzoo-* names Cursor refuses before any
|
|
64
|
+
// request leaves the process — "Model name is not valid" — because it validates
|
|
65
|
+
// the name against its OWN catalog. The custom-OpenAI-endpoint setting only
|
|
66
|
+
// accepts OpenAI-branded ids. Those same ids route through us correctly
|
|
67
|
+
// (verified over the live tunnel: gpt-4o -> openai/gpt-4o-2024-11-20,
|
|
68
|
+
// gpt-4-turbo -> openai/gpt-4-turbo, o3 -> openai/o3-pro), because
|
|
69
|
+
// lib/models.js publishes them in /v1/models and maps them on the way through.
|
|
70
|
+
//
|
|
71
|
+
// OPENZOO_EDITOR_MODELS overrides the list; the zoo model each one lands on is
|
|
72
|
+
// still steerable per-request, and OPENZOO_DEFAULT_MODEL pins them all.
|
|
73
|
+
const fallback = ['gpt-4o', 'gpt-4.1', 'gpt-4-turbo', 'o3', 'o3-mini', 'o4-mini', 'gpt-4o-mini'];
|
|
74
|
+
if (process.env.OPENZOO_EDITOR_MODELS) {
|
|
75
|
+
return process.env.OPENZOO_EDITOR_MODELS.split(',').map((m) => m.trim()).filter(Boolean);
|
|
76
|
+
}
|
|
55
77
|
try {
|
|
56
78
|
const r = await fetch(`${base}/models`, { signal: AbortSignal.timeout(15000) });
|
|
57
79
|
const d = await r.json();
|
|
58
|
-
const
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const rest = twins.filter((t) => t.includes(':'));
|
|
63
|
-
const preferred = ['openzoo-claude-opus-5', 'openzoo-claude-sonnet-5', 'openzoo-gpt-5.6-sol-pro'];
|
|
64
|
-
const head = preferred.filter((p) => plain.includes(p));
|
|
65
|
-
const ordered = [...head, ...plain.filter((t) => !head.includes(t)), ...rest];
|
|
66
|
-
const limit = Number(process.env.OPENZOO_MODEL_LIMIT || 0);
|
|
67
|
-
return limit > 0 ? ordered.slice(0, limit) : ordered;
|
|
80
|
+
const have = new Set((d.data || []).map((m) => m.id));
|
|
81
|
+
// Only offer ids the proxy actually serves, so a pick can never 404.
|
|
82
|
+
const usable = fallback.filter((id) => have.has(id));
|
|
83
|
+
return usable.length ? usable : fallback;
|
|
68
84
|
} catch {
|
|
69
|
-
return
|
|
85
|
+
return fallback;
|
|
70
86
|
}
|
|
71
87
|
}
|
|
72
88
|
|
|
@@ -285,15 +301,39 @@ export async function setupEditor(which, target) {
|
|
|
285
301
|
const models = await catalogModels(base);
|
|
286
302
|
let wrote = null;
|
|
287
303
|
if (editorBase) {
|
|
304
|
+
// UNPIN FIRST — THIS IS THE BUG THAT BROKE THE TUNNEL ALL NIGHT.
|
|
305
|
+
// pinEditorProviderConfig installs a SQL trigger that re-applies the URL it
|
|
306
|
+
// was pinned with on EVERY update to that row. A previous run's trigger
|
|
307
|
+
// therefore silently rewrote each new tunnel URL back to its own, dead one:
|
|
308
|
+
// the banner printed the live tunnel while the DB (and Cursor) got the old
|
|
309
|
+
// hostname, which answered 530. Observed verbatim in one run —
|
|
310
|
+
// tunnel: https://friendly-api-suppliers-suits.trycloudflare.com/v1
|
|
311
|
+
// settings: openAIBaseUrl -> https://motors-multiple-parade-surround...
|
|
312
|
+
// Two hostnames, one run, because the printed value is read BACK from the DB
|
|
313
|
+
// after the trigger has had its say.
|
|
314
|
+
try { unpinEditorProviderConfig(target0); } catch { /* nothing pinned yet */ }
|
|
288
315
|
try { wrote = writeEditorProviderConfig(target0, { baseUrl: editorBase, models, apiKey: tunnelKey }); } catch (e) { wrote = { error: e.message }; }
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
316
|
+
// SELF-HEAL: verify what actually landed, and if anything rewrote it, drop
|
|
317
|
+
// the pin and write again rather than launching an editor we know is
|
|
318
|
+
// pointed at a dead host.
|
|
319
|
+
for (let attempt = 0; attempt < 2 && wrote && !wrote.error; attempt++) {
|
|
320
|
+
const got = wrote.verified?.openAIBaseUrl;
|
|
321
|
+
if (!got || got === editorBase) break;
|
|
322
|
+
console.log(`settings: something rewrote the url (${got}) — unpinning and retrying`);
|
|
323
|
+
try { unpinEditorProviderConfig(target0); } catch { /* ignore */ }
|
|
324
|
+
try { wrote = writeEditorProviderConfig(target0, { baseUrl: editorBase, models, apiKey: tunnelKey }); } catch (e) { wrote = { error: e.message }; }
|
|
325
|
+
}
|
|
296
326
|
const pin = pinEditorProviderConfig(target0, { baseUrl: editorBase, models });
|
|
327
|
+
// A pin that re-applies the WRONG url is worse than no pin at all.
|
|
328
|
+
try {
|
|
329
|
+
const after = writeEditorProviderConfig(target0, { baseUrl: editorBase, models, apiKey: tunnelKey });
|
|
330
|
+
const got = after?.verified?.openAIBaseUrl;
|
|
331
|
+
if (got && got !== editorBase) {
|
|
332
|
+
console.log(`settings: the pin re-applied ${got} — removing it so the live url stands`);
|
|
333
|
+
unpinEditorProviderConfig(target0);
|
|
334
|
+
writeEditorProviderConfig(target0, { baseUrl: editorBase, models, apiKey: tunnelKey });
|
|
335
|
+
}
|
|
336
|
+
} catch { /* advisory */ }
|
|
297
337
|
console.log(` models -> ${models.join(', ')}`);
|
|
298
338
|
console.log(` selected -> ${models[0]}`);
|
|
299
339
|
console.log(pin?.pinned
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Local x402-paying proxy + MCP server for openzoo.fun — point any OpenAI-compatible harness (Cursor, Claude Code, aider, SDKs) at localhost and it pays per call from a local burner wallet. Solana and Base rails live; Robinhood experimental.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|