openzoo 0.50.79 → 0.50.81

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 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),
@@ -1634,8 +1634,12 @@ function entryPlainText(v) {
1634
1634
  */
1635
1635
  export function foldSameRole(messages) {
1636
1636
  const out = [];
1637
+ // An assistant entry with no content and no tool_calls (a failed/empty turn
1638
+ // recorded on the canvas) is invalid for every OpenAI-compatible provider:
1639
+ // measured 2026-09-02 as `400 Invalid model provider request` param=messages.
1640
+ messages = (messages || []).filter((m) => !(m && m.role === 'assistant' && (m.content == null || m.content === '') && !m.tool_calls));
1637
1641
  const foldable = (m) => m && (m.role === 'user' || m.role === 'assistant') && !m.tool_calls && !m.tool_call_id;
1638
- for (const m of messages || []) {
1642
+ for (const m of messages) {
1639
1643
  const last = out[out.length - 1];
1640
1644
  if (last && foldable(last) && foldable(m) && last.role === m.role) {
1641
1645
  const a = last.content; const b = m.content;
@@ -2786,6 +2790,11 @@ function zooTextFromMessage(msg, data) {
2786
2790
  c = c.map((p) => (typeof p === 'string' ? p : (p?.text || p?.content || ''))).join('');
2787
2791
  }
2788
2792
  if (typeof c === 'string' && c.trim()) return c;
2793
+ // Reasoning models spend the whole budget thinking and return content:""
2794
+ // with finish=length — 8192 tokens, 0 visible. The thinking IS the reply
2795
+ // then; dropping it painted "(empty zoo reply)" and re-bought the turn.
2796
+ const rc = msg?.reasoning_content ?? msg?.reasoning;
2797
+ if (typeof rc === 'string' && rc.trim()) return rc;
2789
2798
  if (typeof data?.error?.message === 'string' && data.error.message) return data.error.message;
2790
2799
  return '';
2791
2800
  }
@@ -3141,6 +3150,18 @@ async function zooComplete(prompt, log, agentId, parsed = {}, opts = {}) {
3141
3150
  });
3142
3151
  continue;
3143
3152
  }
3153
+ // finish=length with NOTHING visible is not "parked": the model burned
3154
+ // its whole budget and said nothing. Re-POSTing bought the same nothing
3155
+ // seven times ($0.2–0.46 each, measured 2026-09-02). One attempt, then
3156
+ // say so.
3157
+ if (!chatOnly && finish === 'length' && !String(text || '').trim()) {
3158
+ log('cursor-backend: empty finish=length — not re-buying');
3159
+ try {
3160
+ 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));
3161
+ } catch { /* */ }
3162
+ 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.`;
3163
+ break;
3164
+ }
3144
3165
  if (!chatOnly && (finish === 'length' || looksStoppedReply(text)) && keepGoingNudge < 6) {
3145
3166
  keepGoingNudge += 1;
3146
3167
  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.79",
3
+ "version": "0.50.81",
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",