openzoo 0.48.33 → 0.48.35
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/hrr.js +6 -2
- package/lib/proxy.js +58 -5
- package/package.json +1 -1
package/lib/hrr.js
CHANGED
|
@@ -26,7 +26,7 @@ export const contextCacheDisabled = () => process.env.OPENZOO_NO_CONTEXT_CACHE =
|
|
|
26
26
|
* Ensure `corpus` is bound on the zoo. Returns
|
|
27
27
|
* { contextId, hash, reused, bytes } — reused=true means zero bytes shipped.
|
|
28
28
|
*/
|
|
29
|
-
export async function bindCorpus(corpus, { onStage, force = false } = {}) {
|
|
29
|
+
export async function bindCorpus(corpus, { onStage, force = false, appendTo = null } = {}) {
|
|
30
30
|
const hash = corpusHash(corpus);
|
|
31
31
|
const bytes = Buffer.byteLength(corpus);
|
|
32
32
|
if (!force) {
|
|
@@ -37,7 +37,11 @@ export async function bindCorpus(corpus, { onStage, force = false } = {}) {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
onStage?.('binding', { bytes });
|
|
40
|
-
|
|
40
|
+
// APPEND, don't re-upload. The gateway takes context_id on /v1/hrr/bind and
|
|
41
|
+
// adds to that context — which is the difference between paying for the
|
|
42
|
+
// delta and paying for the whole transcript again on every single turn.
|
|
43
|
+
const r = await postWithUploadSignal(`${config.apiBase}/v1/hrr/bind`,
|
|
44
|
+
JSON.stringify(appendTo ? { corpus, context_id: appendTo } : { corpus }), {
|
|
41
45
|
headers: withNamespace(),
|
|
42
46
|
onUploaded: () => onStage?.('bound-uploading-done', { bytes }),
|
|
43
47
|
});
|
package/lib/proxy.js
CHANGED
|
@@ -90,6 +90,9 @@ function jsonErr(res, status, message, extraFields = {}) {
|
|
|
90
90
|
|
|
91
91
|
const mb = (n) => (n / 1048576).toFixed(1);
|
|
92
92
|
|
|
93
|
+
// anchor -> { corpus, contextId, hash } for append-only transcript spills
|
|
94
|
+
const spillMemo = new Map();
|
|
95
|
+
|
|
93
96
|
/**
|
|
94
97
|
* Every fundable balance across all three chains, for the startup line and
|
|
95
98
|
* the live refresh. Each read is independent and advisory — one lagging RPC
|
|
@@ -339,15 +342,65 @@ async function spillTranscript(body, log) {
|
|
|
339
342
|
}
|
|
340
343
|
if (cut <= firstSpillable) return null; // nothing safely severable
|
|
341
344
|
|
|
345
|
+
// TRIM THE TAIL BY BYTES, NOT MESSAGE COUNT.
|
|
346
|
+
//
|
|
347
|
+
// MEASURED on the live session: 9 kept turns of Claude Code tool output made
|
|
348
|
+
// promptTokens swamp the counterfactual and the call scored 1.00x, while the
|
|
349
|
+
// SAME bound context with a one-line ask scored 8.53x. Nine messages is a
|
|
350
|
+
// trivial number and an enormous payload — a single Read or grep result is
|
|
351
|
+
// tens of KB — so counting messages measures the wrong thing entirely.
|
|
352
|
+
//
|
|
353
|
+
// Walk backwards from the newest and stop at a byte budget. The newest turns
|
|
354
|
+
// are the ones the model actually needs verbatim; everything older is already
|
|
355
|
+
// in the bound corpus and comes back through recall.
|
|
356
|
+
let tailStart = cut;
|
|
357
|
+
{
|
|
358
|
+
const budget = Number(process.env.OPENZOO_TAIL_MAX_CHARS || 24000);
|
|
359
|
+
let used = 0;
|
|
360
|
+
for (let i = msgs.length - 1; i >= cut; i--) {
|
|
361
|
+
used += msgText(msgs[i]).length;
|
|
362
|
+
if (used > budget && severable(i)) { tailStart = i; break; }
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (tailStart > cut) cut = tailStart;
|
|
366
|
+
|
|
342
367
|
const head = msgs.slice(0, firstSpillable); // system block, always kept
|
|
343
368
|
const corpus = msgs.slice(firstSpillable, cut).map(msgText).filter(Boolean).join('\n\n');
|
|
344
369
|
if (corpus.length <= BIND_MIN_CHARS) return null;
|
|
345
370
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
371
|
+
// CONTINUE THE CONTEXT, BIND ONLY THE DELTA.
|
|
372
|
+
//
|
|
373
|
+
// A transcript grows by one message per turn, so the whole-corpus hash misses
|
|
374
|
+
// every time and the old code re-uploaded the ENTIRE prefix on every single
|
|
375
|
+
// turn — OBSERVED live: 0.4MB bound three turns running, a fresh context id
|
|
376
|
+
// each time, while only a few KB was actually new. Bind cost grew with
|
|
377
|
+
// conversation length and was re-paid per message.
|
|
378
|
+
//
|
|
379
|
+
// The corpus is append-only: each turn's corpus starts with the previous
|
|
380
|
+
// one. So when it does, send just the tail and keep the same context_id.
|
|
381
|
+
// Anchored on the FIRST 2KB, which is stable for the life of a conversation
|
|
382
|
+
// and distinguishes concurrent ones.
|
|
383
|
+
const anchor = corpus.slice(0, 2048);
|
|
384
|
+
const prior = spillMemo.get(anchor);
|
|
385
|
+
let bind;
|
|
386
|
+
if (prior && corpus.startsWith(prior.corpus) && corpus.length > prior.corpus.length) {
|
|
387
|
+
const delta = corpus.slice(prior.corpus.length);
|
|
388
|
+
await bindCorpus(delta, {
|
|
389
|
+
appendTo: prior.contextId,
|
|
390
|
+
onStage: (stage, info) => {
|
|
391
|
+
if (stage === 'binding') log(`appending ${mb(info.bytes)}MB to ${prior.contextId} (delta only)`);
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
bind = { contextId: prior.contextId, hash: prior.hash, reused: true, bytes: delta.length };
|
|
395
|
+
} else {
|
|
396
|
+
bind = await bindCorpus(corpus, {
|
|
397
|
+
onStage: (stage, info) => {
|
|
398
|
+
if (stage === 'binding') log(`binding ${mb(info.bytes)}MB of transcript to holographic memory...`);
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
spillMemo.set(anchor, { corpus, contextId: bind.contextId, hash: bind.hash });
|
|
403
|
+
if (spillMemo.size > 32) spillMemo.delete(spillMemo.keys().next().value);
|
|
351
404
|
const sent = msgs.length - cut;
|
|
352
405
|
log(bind.reused
|
|
353
406
|
? `transcript prefix already bound (${bind.contextId}) — sending ${sent}/${msgs.length} turns`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.48.
|
|
3
|
+
"version": "0.48.35",
|
|
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",
|