openzoo 0.50.61 → 0.50.63
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/cursorbackend.js +32 -1
- package/lib/proxy.js +32 -1
- package/package.json +1 -1
package/lib/cursorbackend.js
CHANGED
|
@@ -1843,11 +1843,18 @@ const MODEL_ALIASES = {
|
|
|
1843
1843
|
'glm-5.3': 'zai-org/glm-5.3-flash',
|
|
1844
1844
|
'glm-5.3-flash': 'zai-org/glm-5.3-flash',
|
|
1845
1845
|
flash: 'zai-org/glm-5.3-flash',
|
|
1846
|
+
deepseek: 'deepseek/deepseek-v4-pro',
|
|
1847
|
+
'deepseek-pro': 'deepseek/deepseek-v4-pro',
|
|
1848
|
+
'deepseek-flash': 'deepseek/deepseek-v4-flash',
|
|
1849
|
+
'deepseek-v4': 'deepseek/deepseek-v4-pro',
|
|
1846
1850
|
abliterated: 'abliterated-model-large-v2',
|
|
1847
1851
|
ablit: 'abliterated-model-large-v2',
|
|
1848
1852
|
'abliterated-large': 'abliterated-model-large-v2',
|
|
1849
1853
|
'abliterated-small': 'abliterated-model',
|
|
1850
1854
|
};
|
|
1855
|
+
/** Default zoo model for every bot without a /model override. DeepSeek v4 pro:
|
|
1856
|
+
* tool-capable, ~$1/M in · $2/M out — grok-4.6 burned $82 in one afternoon. */
|
|
1857
|
+
export const DEFAULT_ZOO_MODEL = 'deepseek/deepseek-v4-pro';
|
|
1851
1858
|
async function resolveModelId(raw) {
|
|
1852
1859
|
const s = String(raw || '').trim();
|
|
1853
1860
|
if (!s) return null;
|
|
@@ -1865,7 +1872,7 @@ async function resolveModelId(raw) {
|
|
|
1865
1872
|
function currentModel(agentId) {
|
|
1866
1873
|
return agentModels.get(agentId)
|
|
1867
1874
|
|| process.env.OPENZOO_DEFAULT_MODEL
|
|
1868
|
-
||
|
|
1875
|
+
|| DEFAULT_ZOO_MODEL;
|
|
1869
1876
|
}
|
|
1870
1877
|
|
|
1871
1878
|
const execFileAsync = promisify(execFile);
|
|
@@ -2944,6 +2951,30 @@ async function handleHijackedPodHttp(req, res, full, body, log) {
|
|
|
2944
2951
|
}
|
|
2945
2952
|
if (!path0.startsWith('/api/')) return false;
|
|
2946
2953
|
const name = path0.slice('/api/'.length);
|
|
2954
|
+
// Revive: the minutely cron (scripts/revive-bots.sh) calls this after it has
|
|
2955
|
+
// made sure the hijack + app are alive. Every non-group bot gets a wakeup
|
|
2956
|
+
// timer if it lost one; nothing is spawned, nothing already armed is touched.
|
|
2957
|
+
if (name === 'ozRevive') {
|
|
2958
|
+
let parsed = {};
|
|
2959
|
+
try { parsed = JSON.parse(String(body || '{}')); } catch { parsed = {}; }
|
|
2960
|
+
const every = String(parsed.every || '5m');
|
|
2961
|
+
const wakes = readWakeups(HOME);
|
|
2962
|
+
const list = (cachedAgentList() || []).filter((a) => a?.id && !a.isGroup);
|
|
2963
|
+
const armed = [];
|
|
2964
|
+
const already = [];
|
|
2965
|
+
for (const a of list) {
|
|
2966
|
+
if (wakes[a.id]) { already.push(a.id); continue; }
|
|
2967
|
+
try {
|
|
2968
|
+
scheduleAgentWakeup(a.id, { every, prompt: parsed.prompt });
|
|
2969
|
+
armed.push({ id: a.id, name: a.name });
|
|
2970
|
+
} catch (e) {
|
|
2971
|
+
log(`cursor-backend: ozRevive ${a.id} ${e.message}`);
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
log(`cursor-backend: ozRevive total=${list.length} armed=${armed.length} already=${already.length} every=${every}`);
|
|
2975
|
+
jsonSend(res, { ok: true, total: list.length, armed, already: already.length, every });
|
|
2976
|
+
return true;
|
|
2977
|
+
}
|
|
2947
2978
|
if (name === 'getHostStatus') {
|
|
2948
2979
|
jsonSend(res, { status: 'ready', ready: true, state: 'ready', hostStatus: 'ready' });
|
|
2949
2980
|
log('cursor-backend: -> getHostStatus ready');
|
package/lib/proxy.js
CHANGED
|
@@ -304,6 +304,18 @@ function replayPut(key, data, settle) {
|
|
|
304
304
|
*/
|
|
305
305
|
export async function startProxy({ silent = false, requireToken = null, sessionMaxUsd = null, autoTunnel = false } = {}) {
|
|
306
306
|
const client = new PayClient();
|
|
307
|
+
// HOUSE OUTAGE GATE. Measured 2026-09-01: TOKEN payments settled on chain
|
|
308
|
+
// (tx 3rwy5z…) and the gateway still answered 402 because ITS upstream
|
|
309
|
+
// (OpenRouter) was out of credits. Paying again buys nothing, and the
|
|
310
|
+
// "wallet underfunded" copy blamed the user's burner. When the paid 402 says
|
|
311
|
+
// upstream credits, stop paying for a minute and say what is actually wrong.
|
|
312
|
+
let upstreamOutageUntil = 0;
|
|
313
|
+
let upstreamOutageMsg = '';
|
|
314
|
+
const upstreamOutage = (body) => {
|
|
315
|
+
const m = String(body?.error?.message || body?.message || '');
|
|
316
|
+
const src = String(body?.error?.metadata?.limit_source || '');
|
|
317
|
+
return /openrouter_credits/i.test(src) || /insufficient credits/i.test(m);
|
|
318
|
+
};
|
|
307
319
|
const log = silent ? () => {} : (...a) => console.log(...a);
|
|
308
320
|
// ALWAYS-ON, BUT NEVER INTO A HARNESS'S TERMINAL. `silent` means another
|
|
309
321
|
// process (openzoo claude, the editor launcher) owns stdio — printing request
|
|
@@ -684,6 +696,11 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
|
|
|
684
696
|
}
|
|
685
697
|
|
|
686
698
|
try {
|
|
699
|
+
if (Date.now() < upstreamOutageUntil) {
|
|
700
|
+
log('upstream outage: not paying (gate)');
|
|
701
|
+
jsonErr(res, 503, upstreamOutageMsg);
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
687
704
|
const result = await client.fetch(url, init);
|
|
688
705
|
const { response, paid, receipt, accept } = result;
|
|
689
706
|
if (paid && receipt) {
|
|
@@ -786,8 +803,22 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
|
|
|
786
803
|
if (response.status === 402) {
|
|
787
804
|
let quoted = '';
|
|
788
805
|
let usd;
|
|
806
|
+
let q402 = null;
|
|
807
|
+
try { q402 = await response.clone().json(); } catch { q402 = null; }
|
|
808
|
+
if (paid && upstreamOutage(q402)) {
|
|
809
|
+
const settle = q402?.x402?.settle;
|
|
810
|
+
const tx = settle?.transaction || result.receipt?.tx || '';
|
|
811
|
+
upstreamOutageMsg = 'openzoo gateway upstream is out of credits (OpenRouter: "Insufficient credits"). '
|
|
812
|
+
+ `Your payment settled${tx ? ` (tx ${tx})` : ''} — this is NOT your wallet. `
|
|
813
|
+
+ 'The gateway operator must top up OpenRouter or route this model to another upstream. '
|
|
814
|
+
+ 'Pausing paid retries for 60s.';
|
|
815
|
+
upstreamOutageUntil = Date.now() + 60_000;
|
|
816
|
+
log(`upstream outage: ${upstreamOutageMsg.slice(0, 120)}`);
|
|
817
|
+
jsonErr(res, 503, upstreamOutageMsg);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
789
820
|
try {
|
|
790
|
-
const q =
|
|
821
|
+
const q = q402;
|
|
791
822
|
usd = Number(q?.accepts?.[0]?.extra?.billedUsd);
|
|
792
823
|
if (Number.isFinite(usd)) quoted = ` This call needs ≈$${usd.toFixed(4)}.`;
|
|
793
824
|
} catch { /* body was not the quote after all */ }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.63",
|
|
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",
|