openzoo 0.48.52 → 0.48.53

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.
Files changed (2) hide show
  1. package/lib/proxy.js +20 -3
  2. package/package.json +1 -1
package/lib/proxy.js CHANGED
@@ -463,7 +463,15 @@ async function spillTranscript(body, log, req) {
463
463
  //
464
464
  // Claude Code identifies its session, so use that when it is offered and fall
465
465
  // back to the content anchor when it is not. Same memo, better key.
466
- const sessionId = req?.headers?.['x-session-id']
466
+ // CAPTURED FROM A LIVE claude-cli/2.1.232 REQUEST, not guessed. The first
467
+ // version of this checked x-session-id / x-claude-session-id /
468
+ // metadata.user_id — none of which Claude Code sends, so it silently fell
469
+ // back to the content anchor on every request and the feature did nothing.
470
+ // The real header list is:
471
+ // anthropic-beta, anthropic-version, x-app, x-claude-code-session-id,
472
+ // x-stainless-*
473
+ const sessionId = req?.headers?.['x-claude-code-session-id']
474
+ || req?.headers?.['x-session-id']
467
475
  || req?.headers?.['x-claude-session-id']
468
476
  || (typeof body?.metadata?.user_id === 'string' ? body.metadata.user_id : null);
469
477
  const anchor = sessionId ? `sid:${sessionId}` : corpus.slice(0, 2048);
@@ -499,9 +507,12 @@ async function spillTranscript(body, log, req) {
499
507
  spillMemo.set(anchor, { corpus, contextId: bind.contextId, hash: bind.hash });
500
508
  if (spillMemo.size > 32) spillMemo.delete(spillMemo.keys().next().value);
501
509
  const sent = msgs.length - cut;
510
+ // NAME THE KEY. A memo keyed on the wrong thing fails silently — it just
511
+ // re-binds forever and collides sessions — so the log says which key was used.
512
+ const keyKind = sessionId ? `sid ${String(sessionId).slice(0, 8)}` : 'content-anchor';
502
513
  log(bind.reused
503
- ? `transcript prefix already bound (${bind.contextId}) — sending ${sent}/${msgs.length} turns`
504
- : `transcript prefix bound (${mb(bind.bytes)}MB → ${bind.contextId}) — sending ${sent}/${msgs.length} turns`);
514
+ ? `transcript prefix already bound (${bind.contextId}, ${keyKind}) — sending ${sent}/${msgs.length} turns`
515
+ : `transcript prefix bound (${mb(bind.bytes)}MB → ${bind.contextId}, ${keyKind}) — sending ${sent}/${msgs.length} turns`);
505
516
 
506
517
  // ADAPTIVE TOP-K. A fixed 32 chunks is what was actually eating the saving:
507
518
  // MEASURED on a 56,265-token corpus, top_k 32 handed 9,990 tokens back and
@@ -1018,6 +1029,12 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
1018
1029
  if ((req.url || '').includes('/chat/completions') && req.method === 'POST') {
1019
1030
  servedRequests += 1;
1020
1031
  say(`\n<- request #${servedRequests} from ${(req.headers['user-agent'] || 'unknown').slice(0, 40)}`);
1032
+ // TEMPORARY: name the headers (not values) so we can see whether the
1033
+ // client offers a session id at all. Values are never logged — several
1034
+ // of these carry auth.
1035
+ if (process.env.OPENZOO_LOG_HEADERS === '1') {
1036
+ log(` headers: ${Object.keys(req.headers).sort().join(', ')}`);
1037
+ }
1021
1038
  }
1022
1039
  if (rewritablePath(req.method, req.url)) {
1023
1040
  const rw = await maybeRewriteModel(bodyBuf);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openzoo",
3
- "version": "0.48.52",
3
+ "version": "0.48.53",
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",