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 +2 -2
- package/lib/config.js +3 -1
- package/lib/proxy.js +24 -3
- package/lib/tunnel.js +7 -4
- package/package.json +1 -1
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 (
|
|
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 (
|
|
38
|
+
OPENZOO_TUNNEL_MAX_USD (unset — NO 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
|
-
|
|
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
|
|
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('
|
|
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
|
-
* -
|
|
20
|
-
*
|
|
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
|
-
|
|
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(
|
|
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
|
+
"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",
|