openzoo 0.50.94 → 0.50.95
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/launch.js +36 -5
- package/lib/proxy.js +33 -0
- package/package.json +1 -1
package/lib/launch.js
CHANGED
|
@@ -164,7 +164,30 @@ export function claudeZooEnv(baseEnv = process.env, { base, port } = {}) {
|
|
|
164
164
|
// Correct here for the same reason as everything else in this block: the
|
|
165
165
|
// proxy binds the prefix and forwards a bounded tail, so the request that
|
|
166
166
|
// leaves this machine stays small no matter how long the conversation runs.
|
|
167
|
-
|
|
167
|
+
//
|
|
168
|
+
// OPT-IN NOW, BECAUSE THE PRECONDITION IS NOT REAL.
|
|
169
|
+
//
|
|
170
|
+
// Everything above is correct ONLY IF something bounds the body that leaves
|
|
171
|
+
// this machine. Two comments here named that something — `spillTranscript`,
|
|
172
|
+
// and the knobs `OPENZOO_TAIL_MAX_CHARS` / `OPENZOO_KEEP_TAIL_MSGS`. None of
|
|
173
|
+
// the three exists: `grep -rn spillTranscript` matches nothing but these
|
|
174
|
+
// comments, in this package and in the gateway. Checked 2026-09-03.
|
|
175
|
+
//
|
|
176
|
+
// So the shipped behaviour was: compaction off, ceiling raised to 1M, and
|
|
177
|
+
// NOTHING trimming the transcript — Claude Code accumulates without limit and
|
|
178
|
+
// re-sends the whole thing every turn. The gateway's leCore cannot rescue it
|
|
179
|
+
// either: an agent body is few-and-huge, so `msgs.length <= KEEP_TAIL` leaves
|
|
180
|
+
// nothing "older than the live window", and what bulk there is sits in the
|
|
181
|
+
// system block and first user turn, both deliberately never spilled.
|
|
182
|
+
//
|
|
183
|
+
// MEASURED on a user's session: 20 calls, $13.86, `spilled 0/20`, 1.0159x vs
|
|
184
|
+
// direct — paying almost exactly retail to send an ever-growing transcript.
|
|
185
|
+
//
|
|
186
|
+
// Until a real bound ships, default to Claude Code's own behaviour, which is
|
|
187
|
+
// bounded and known-good. OPENZOO_UNBOUNDED_CONTEXT=1 restores the old
|
|
188
|
+
// settings for anyone who wants them back.
|
|
189
|
+
const unboundedContext = baseEnv.OPENZOO_UNBOUNDED_CONTEXT === '1';
|
|
190
|
+
if (unboundedContext && baseEnv.OPENZOO_KEEP_COMPACT !== '1') {
|
|
168
191
|
env.DISABLE_COMPACT = baseEnv.DISABLE_COMPACT || '1';
|
|
169
192
|
env.DISABLE_AUTO_COMPACT = baseEnv.DISABLE_AUTO_COMPACT || '1';
|
|
170
193
|
}
|
|
@@ -177,9 +200,9 @@ export function claudeZooEnv(baseEnv = process.env, { base, port } = {}) {
|
|
|
177
200
|
// sent. Disabling auto-compact WITHOUT raising this made it worse: it used to
|
|
178
201
|
// compact and carry on, and instead it just stopped.
|
|
179
202
|
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
if (baseEnv.OPENZOO_KEEP_COMPACT !== '1' && !baseEnv.CLAUDE_CODE_MAX_CONTEXT_TOKENS) {
|
|
203
|
+
// WAS justified by `spillTranscript` / OPENZOO_TAIL_MAX_CHARS — neither of
|
|
204
|
+
// which exists. Now gated behind OPENZOO_UNBOUNDED_CONTEXT; see below.
|
|
205
|
+
if (unboundedContext && baseEnv.OPENZOO_KEEP_COMPACT !== '1' && !baseEnv.CLAUDE_CODE_MAX_CONTEXT_TOKENS) {
|
|
183
206
|
env.CLAUDE_CODE_MAX_CONTEXT_TOKENS = baseEnv.OPENZOO_CLAUDE_CONTEXT_TOKENS || '1000000';
|
|
184
207
|
}
|
|
185
208
|
return env;
|
|
@@ -361,7 +384,15 @@ export async function launchClaude(argv) {
|
|
|
361
384
|
// side by side is the only way the markup is visible while it is happening.
|
|
362
385
|
+ 'const ac=j.actual||{};'
|
|
363
386
|
+ 'const real=(ac.calls>0)?(" \\u00b7 $"+Number(ac.upstreamUsd||0).toFixed(4)+" real"+(ac.markupX?(" ("+ac.markupX+"x)"):"")):"";'
|
|
364
|
-
|
|
387
|
+
// TWO NUMBERS, NEVER ONE. `spent` is cumulative across every session on
|
|
388
|
+
// this machine (restored from ~/.openzoo/session.json); `wallet` is what
|
|
389
|
+
// is left to pay with. Shown unlabelled, the first was read as the
|
|
390
|
+
// second — "$13.86" on screen while the wallet held $0.18 and every call
|
|
391
|
+
// 402'd underfunded. The words `spent` and `wallet` are the whole fix.
|
|
392
|
+
+ 'const wu=Number(j.walletUsd);'
|
|
393
|
+
+ 'const wcol=(!isFinite(wu)||wu<=0)?"\\x1b[31m":(wu<0.5?"\\x1b[33m":"\\x1b[90m");'
|
|
394
|
+
+ 'const wal=isFinite(wu)?(" \\u00b7 "+wcol+"wallet $"+wu.toFixed(2)+"\\x1b[0m"):"";'
|
|
395
|
+
+ 'process.stdout.write("\\x1b[38;5;208m\\u25cf\\x1b[0m openzoo spent $"+(Number(j.spendUsd)||0).toFixed(4)+" all-time"+wal+" \\u00b7 "+(j.paidCalls||0)+" call"+((j.paidCalls||0)===1?"":"s")+save+real+spill+cr+" \\u00b7 x402")}'
|
|
365
396
|
+ 'catch{process.stdout.write("\\x1b[38;5;208m\\u25cf\\x1b[0m openzoo \\u00b7 x402")}})\'\n');
|
|
366
397
|
fs.chmodSync(scriptPath, 0o755);
|
|
367
398
|
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
package/lib/proxy.js
CHANGED
|
@@ -388,6 +388,33 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
|
|
|
388
388
|
let creditInflight = null;
|
|
389
389
|
let lastPrices = {};
|
|
390
390
|
let pricesAt = 0;
|
|
391
|
+
// WALLET BALANCE, CACHED LIKE CREDIT.
|
|
392
|
+
//
|
|
393
|
+
// The HUD showed one number — cumulative spend — and a user read it as their
|
|
394
|
+
// balance: "$13.86" beside a wallet holding $0.18, then every call 402'd
|
|
395
|
+
// "underfunded" and nothing on screen explained why. Spend is a total to
|
|
396
|
+
// date; the wallet is what is left. Both, labelled, or neither is legible.
|
|
397
|
+
//
|
|
398
|
+
// Never awaited on the /v1/info path: this quotes the gateway and reads
|
|
399
|
+
// chain balances, and the statusline gives it 1s. Serve last-known, refresh
|
|
400
|
+
// behind it — the same contract refreshCredit() keeps.
|
|
401
|
+
let walletUsd = null;
|
|
402
|
+
let walletAt = 0;
|
|
403
|
+
let walletInflight = null;
|
|
404
|
+
const refreshWallet = async (force = false) => {
|
|
405
|
+
if (!force && Date.now() - walletAt < 60000 && walletUsd != null) return walletUsd;
|
|
406
|
+
if (walletInflight) return walletInflight;
|
|
407
|
+
walletInflight = (async () => {
|
|
408
|
+
try {
|
|
409
|
+
const { affordableUsd } = await import('./info.js');
|
|
410
|
+
const v = await affordableUsd();
|
|
411
|
+
if (Number.isFinite(v)) { walletUsd = v; walletAt = Date.now(); }
|
|
412
|
+
} catch { /* keep last known */ }
|
|
413
|
+
walletInflight = null;
|
|
414
|
+
return walletUsd;
|
|
415
|
+
})();
|
|
416
|
+
return walletInflight;
|
|
417
|
+
};
|
|
391
418
|
const refreshCredit = async (force = false) => {
|
|
392
419
|
if (!force && Date.now() - creditAt < 20000 && creditUsd != null) return creditUsd;
|
|
393
420
|
if (creditInflight) return creditInflight;
|
|
@@ -508,6 +535,7 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
|
|
|
508
535
|
const p0 = (req.url || '').split('?')[0];
|
|
509
536
|
if (req.method === 'GET' && (p0 === '/v1/info' || p0 === '/info')) {
|
|
510
537
|
refreshCredit();
|
|
538
|
+
refreshWallet();
|
|
511
539
|
const self = viaTunnel && tunnelGate?.publicUrl
|
|
512
540
|
? `${tunnelGate.publicUrl}/v1`
|
|
513
541
|
: `http://localhost:${config.port}/v1`;
|
|
@@ -518,7 +546,12 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
|
|
|
518
546
|
reachedVia: viaTunnel ? 'public tunnel' : 'localhost',
|
|
519
547
|
publicTunnel: tunnelGate?.publicUrl ? `${tunnelGate.publicUrl}/v1` : null,
|
|
520
548
|
servedRequests,
|
|
549
|
+
// SPENT-TO-DATE, not a balance: restored from ~/.openzoo/session.json at
|
|
550
|
+
// startup, so it spans every session on this machine.
|
|
521
551
|
spendUsd: sessionSpent,
|
|
552
|
+
spendScope: 'all-time on this machine',
|
|
553
|
+
// WHAT IS LEFT to pay with. null while the first read is in flight.
|
|
554
|
+
walletUsd,
|
|
522
555
|
creditUsd,
|
|
523
556
|
// WHAT THE SAME CALLS WOULD HAVE COST DIRECT. Spend on its own is a
|
|
524
557
|
// bill; spend beside the counterfactual is the product.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.95",
|
|
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",
|