openzoo 0.9.3 → 0.9.5

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/bin/openzoo.js CHANGED
@@ -30,12 +30,12 @@ env:
30
30
  OPENZOO_RPC (mainnet-beta) OPENZOO_TOKEN (402 rail preference) OPENZOO_WALLET (~/.openzoo/wallet.json)
31
31
  OPENZOO_RAIL (unset — force a rail: solana | base | robinhood)
32
32
  OPENZOO_BASE_RPC (https://mainnet.base.org) OPENZOO_RH_RPC (rpc.mainnet.chain.robinhood.com)
33
- OPENZOO_MAX_USD_PER_CALL (0.5) OPENZOO_DEMO_MAX_USD (0.01)
33
+ OPENZOO_MAX_USD_PER_CALL (unset — NO per-call ceiling; set to add one) OPENZOO_DEMO_MAX_USD (0.01)
34
34
  OPENZOO_CONTEXT_MIN_CHARS (16384 — bodies bigger than this bind once + reuse)
35
35
  OPENZOO_NO_CONTEXT_CACHE (0 — set 1 to always ship the full body)
36
36
  OPENZOO_ENABLE_RH (0 — let DEFAULT selection fall through to the Robinhood rail;
37
37
  OPENZOO_RAIL=robinhood forces it without this)
38
- OPENZOO_TUNNEL_MAX_USD (1.00 — public-url session ceiling) OPENZOO_TUNNEL_TOKEN (pin the api key)
38
+ OPENZOO_TUNNEL_MAX_USD (unsetNO public-url session ceiling; set to add one) OPENZOO_TUNNEL_TOKEN (pin the api key)
39
39
  OPENZOO_NO_TUNNEL (0 — set 1 for localhost-only, no public url)`;
40
40
 
41
41
  async function main() {
package/lib/config.js CHANGED
@@ -15,7 +15,9 @@ export const config = {
15
15
  rhRpcUrl: process.env.OPENZOO_RH_RPC || 'https://rpc.mainnet.chain.robinhood.com',
16
16
  walletPath: process.env.OPENZOO_WALLET || path.join(os.homedir(), '.openzoo', 'wallet.json'),
17
17
  // Refuse to auto-pay any single 402 quote above this many USD (extra.billedUsd).
18
- maxUsdPerCall: Number(process.env.OPENZOO_MAX_USD_PER_CALL || 0.5),
18
+ // UNCAPPED by default (user directive: no maximums — a giant bound-corpus
19
+ // call is a legitimate call). Set OPENZOO_MAX_USD_PER_CALL to add a ceiling.
20
+ maxUsdPerCall: process.env.OPENZOO_MAX_USD_PER_CALL ? Number(process.env.OPENZOO_MAX_USD_PER_CALL) : Infinity,
19
21
  // Demo will only actually pay if the quote is at or below this.
20
22
  demoMaxUsd: Number(process.env.OPENZOO_DEMO_MAX_USD || 0.01),
21
23
  };
package/lib/proxy.js CHANGED
@@ -118,6 +118,27 @@ function serveAsSse(res, data, upstream) {
118
118
  if (c.message?.content) {
119
119
  ev({ ...base, choices: [{ index: c.index ?? 0, delta: { content: c.message.content }, finish_reason: null }] });
120
120
  }
121
+ // Agent mode lives or dies here: a finish_reason of "tool_calls" with the
122
+ // calls themselves dropped strands the harness mid-turn (observed: Cursor
123
+ // agent hangs). Streaming spec: tool_calls ride the delta with an index,
124
+ // arguments as a string chunk — one full chunk per call is valid SSE.
125
+ if (Array.isArray(c.message?.tool_calls) && c.message.tool_calls.length) {
126
+ ev({
127
+ ...base,
128
+ choices: [{
129
+ index: c.index ?? 0,
130
+ delta: {
131
+ tool_calls: c.message.tool_calls.map((t, i) => ({
132
+ index: i,
133
+ id: t.id,
134
+ type: t.type || 'function',
135
+ function: { name: t.function?.name, arguments: t.function?.arguments ?? '' },
136
+ })),
137
+ },
138
+ finish_reason: null,
139
+ }],
140
+ });
141
+ }
121
142
  ev({ ...base, choices: [{ index: c.index ?? 0, delta: {}, finish_reason: c.finish_reason ?? 'stop' }], ...(data.usage ? { usage: data.usage } : {}) });
122
143
  }
123
144
  res.write('data: [DONE]\n\n');
@@ -494,7 +515,7 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
494
515
  try {
495
516
  const { ensureCloudflared, startCloudflared, mintToken } = await import('./tunnel.js');
496
517
  const token = mintToken();
497
- const cap = Number(process.env.OPENZOO_TUNNEL_MAX_USD || 1);
518
+ const cap = process.env.OPENZOO_TUNNEL_MAX_USD ? Number(process.env.OPENZOO_TUNNEL_MAX_USD) : Infinity;
498
519
  const bin = await ensureCloudflared((m) => log(m));
499
520
  const { url, proc } = await startCloudflared(bin, config.port, log);
500
521
  tunnelGate = { token, sessionMaxUsd: cap };
@@ -506,8 +527,8 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
506
527
  log('cloud IDE / remote harness? use the public URL (they cannot reach localhost):');
507
528
  log(` base_url = ${url}/v1`);
508
529
  log(` api_key = ${token}`);
509
- log(` (key REQUIRED on the public URL — it spends this wallet; capped at $${cap.toFixed(2)}/session,`);
510
- log(' OPENZOO_TUNNEL_MAX_USD to change, OPENZOO_NO_TUNNEL=1 for localhost-only)');
530
+ log(` (key REQUIRED on the public URL — it spends this wallet; ${Number.isFinite(cap) ? `capped at $${cap.toFixed(2)}/session` : 'NO session cap — OPENZOO_TUNNEL_MAX_USD adds one'},`);
531
+ log(' OPENZOO_NO_TUNNEL=1 for localhost-only)');
511
532
  } catch (err) {
512
533
  log(`public URL unavailable (${err.message}) — localhost still works; OPENZOO_NO_TUNNEL=1 hides this line`);
513
534
  }
package/lib/tunnel.js CHANGED
@@ -16,8 +16,8 @@
16
16
  * front of your money, so tunnel mode is the ONE mode where the api key is real:
17
17
  * - a random bearer token is minted per session and REQUIRED (401 otherwise),
18
18
  * checked before anything is forwarded, quoted, or paid;
19
- * - the per-call cap (OPENZOO_MAX_USD_PER_CALL) still applies, and a session
20
- * ceiling (OPENZOO_TUNNEL_MAX_USD, default $1) stops paying when reached;
19
+ * - caps are OPT-IN (user directive: no maximums by default) — set
20
+ * OPENZOO_MAX_USD_PER_CALL and/or OPENZOO_TUNNEL_MAX_USD to add them;
21
21
  * - every tunnel-served request is logged with its running spend.
22
22
  */
23
23
  import { spawn } from 'node:child_process';
@@ -119,7 +119,8 @@ export async function runTunnel() {
119
119
  const { config } = await import('./config.js');
120
120
 
121
121
  const token = mintToken();
122
- const sessionCap = Number(process.env.OPENZOO_TUNNEL_MAX_USD || 1);
122
+ // Uncapped unless the user sets a ceiling — the required token is the gate.
123
+ const sessionCap = process.env.OPENZOO_TUNNEL_MAX_USD ? Number(process.env.OPENZOO_TUNNEL_MAX_USD) : null;
123
124
 
124
125
  // The proxy enforces the gate itself: nothing is forwarded, quoted or paid
125
126
  // without the bearer token, and the session ceiling stops spend cold.
@@ -136,7 +137,9 @@ export async function runTunnel() {
136
137
  console.log(' ┌─────────────────────────────────────────────────────────────');
137
138
  console.log(' │ THIS URL SPENDS REAL MONEY FROM YOUR WALLET.');
138
139
  console.log(' │ The token below is the only thing protecting it.');
139
- console.log(` │ Session ceiling: $${sessionCap.toFixed(2)} then it stops paying.`);
140
+ console.log(sessionCap != null
141
+ ? ` │ Session ceiling: $${sessionCap.toFixed(2)} — then it stops paying.`
142
+ : ' │ NO session ceiling — OPENZOO_TUNNEL_MAX_USD adds one.');
140
143
  console.log(' │ Ctrl-C when you are done; the URL dies with this process.');
141
144
  console.log(' └─────────────────────────────────────────────────────────────');
142
145
  console.log('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openzoo",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
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",