openzoo 0.50.80 → 0.50.82
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/claude-zoo.js +19 -0
- package/lib/cursorbackend.js +30 -0
- package/package.json +1 -1
package/bin/claude-zoo.js
CHANGED
|
@@ -90,6 +90,25 @@ function zooEnv(base) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
const base = await ensureProxy();
|
|
93
|
+
// `claude auth status --json` / `claude auth login` — answered here, never
|
|
94
|
+
// forwarded. Tools that embed Claude Code as an AI provider (OKX's okx-a2a
|
|
95
|
+
// daemon probes exactly this before it will run) expect a JSON
|
|
96
|
+
// {"loggedIn":true} and a zero exit. occ has no `auth` command: it read the
|
|
97
|
+
// words as a prompt and sat waiting for input, so the probe timed out and the
|
|
98
|
+
// provider was reported "not logged in". Through the zoo the credential is
|
|
99
|
+
// the gateway token set above, so logged-in is simply true.
|
|
100
|
+
if (process.argv[2] === 'auth') {
|
|
101
|
+
const sub = process.argv[3];
|
|
102
|
+
if (sub === 'status') {
|
|
103
|
+
process.stdout.write(JSON.stringify({ loggedIn: true, authMethod: 'openzoo', apiProvider: 'openzoo', baseUrl: PROXY_URL }) + '\n');
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
if (sub === 'login' || sub === 'logout') {
|
|
107
|
+
process.stdout.write(`openzoo: nothing to ${sub} — every call pays x402 through ${PROXY_URL}\n`);
|
|
108
|
+
process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
93
112
|
const child = spawn(occ, process.argv.slice(2), {
|
|
94
113
|
stdio: 'inherit',
|
|
95
114
|
env: zooEnv(process.env),
|
package/lib/cursorbackend.js
CHANGED
|
@@ -1633,6 +1633,19 @@ function entryPlainText(v) {
|
|
|
1633
1633
|
* Lossless fold: texts joined with a blank line; tool turns never crossed.
|
|
1634
1634
|
*/
|
|
1635
1635
|
export function foldSameRole(messages) {
|
|
1636
|
+
// Assistant turns stored from the raw upstream object carry refusal:null,
|
|
1637
|
+
// reasoning, annotations… Bisected 2026-09-02: that one message drew
|
|
1638
|
+
// "Invalid model provider request" from the abliteration lane with every
|
|
1639
|
+
// other message shrunk to 300 chars. Keep the four keys every provider takes.
|
|
1640
|
+
const ASSISTANT_KEYS = new Set(['role', 'content', 'tool_calls', 'name']);
|
|
1641
|
+
messages = (Array.isArray(messages) ? messages : []).map((m) => {
|
|
1642
|
+
if (!m || m.role !== 'assistant') return m;
|
|
1643
|
+
const out = {};
|
|
1644
|
+
for (const [k, v] of Object.entries(m)) if (ASSISTANT_KEYS.has(k)) out[k] = v;
|
|
1645
|
+
if (out.content === undefined && !out.tool_calls) out.content = '';
|
|
1646
|
+
if (out.content === null && out.tool_calls) delete out.content;
|
|
1647
|
+
return out;
|
|
1648
|
+
});
|
|
1636
1649
|
const out = [];
|
|
1637
1650
|
// An assistant entry with no content and no tool_calls (a failed/empty turn
|
|
1638
1651
|
// recorded on the canvas) is invalid for every OpenAI-compatible provider:
|
|
@@ -2790,6 +2803,11 @@ function zooTextFromMessage(msg, data) {
|
|
|
2790
2803
|
c = c.map((p) => (typeof p === 'string' ? p : (p?.text || p?.content || ''))).join('');
|
|
2791
2804
|
}
|
|
2792
2805
|
if (typeof c === 'string' && c.trim()) return c;
|
|
2806
|
+
// Reasoning models spend the whole budget thinking and return content:""
|
|
2807
|
+
// with finish=length — 8192 tokens, 0 visible. The thinking IS the reply
|
|
2808
|
+
// then; dropping it painted "(empty zoo reply)" and re-bought the turn.
|
|
2809
|
+
const rc = msg?.reasoning_content ?? msg?.reasoning;
|
|
2810
|
+
if (typeof rc === 'string' && rc.trim()) return rc;
|
|
2793
2811
|
if (typeof data?.error?.message === 'string' && data.error.message) return data.error.message;
|
|
2794
2812
|
return '';
|
|
2795
2813
|
}
|
|
@@ -3145,6 +3163,18 @@ async function zooComplete(prompt, log, agentId, parsed = {}, opts = {}) {
|
|
|
3145
3163
|
});
|
|
3146
3164
|
continue;
|
|
3147
3165
|
}
|
|
3166
|
+
// finish=length with NOTHING visible is not "parked": the model burned
|
|
3167
|
+
// its whole budget and said nothing. Re-POSTing bought the same nothing
|
|
3168
|
+
// seven times ($0.2–0.46 each, measured 2026-09-02). One attempt, then
|
|
3169
|
+
// say so.
|
|
3170
|
+
if (!chatOnly && finish === 'length' && !String(text || '').trim()) {
|
|
3171
|
+
log('cursor-backend: empty finish=length — not re-buying');
|
|
3172
|
+
try {
|
|
3173
|
+
fs.writeFileSync(path.join(os.homedir(), '.openzoo', 'zoo-last-empty-body.json'), JSON.stringify({ at: new Date().toISOString(), agentId, model, response: data, payload: { ...messages.slice(-3) } }, null, 1));
|
|
3174
|
+
} catch { /* */ }
|
|
3175
|
+
text = `${model} used its whole ${maxTok}-token budget and produced no visible text (finish=length, ${Number(data?.usage?.completion_tokens || 0)} completion tokens). Try /model grok-4.6 or shorten the ask.`;
|
|
3176
|
+
break;
|
|
3177
|
+
}
|
|
3148
3178
|
if (!chatOnly && (finish === 'length' || looksStoppedReply(text)) && keepGoingNudge < 6) {
|
|
3149
3179
|
keepGoingNudge += 1;
|
|
3150
3180
|
log(`cursor-backend: keep-going nudge=${keepGoingNudge} finish=${finish}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.82",
|
|
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",
|