openzoo 0.50.23 → 0.50.25

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.
@@ -542,12 +542,13 @@ async function proxyPodHttp(req, res, full, body, log) {
542
542
  if (!realPod?.agent) return false;
543
543
  const agent = new URL(realPod.agent);
544
544
  const headers = copyReqHeaders(req, agent.host);
545
- if (realPod.accessToken && !headers.authorization && !headers.Authorization) {
546
- headers.authorization = `Bearer ${realPod.accessToken}`;
547
- }
548
- if (realPod.token && !headers['x-anyrun-network-token']) {
549
- headers['x-anyrun-network-token'] = realPod.token;
550
- }
545
+ // Incoming Authorization is Grok Bot oauth to api2. 1340 wants EnsureSandBox
546
+ // field 11. Leaving oauth in place 401s listAgents (measured: tails via
547
+ // podJson with field-11 worked, roster proxy with copied oauth 401ed).
548
+ delete headers.authorization;
549
+ delete headers.Authorization;
550
+ if (realPod.accessToken) headers.authorization = `Bearer ${realPod.accessToken}`;
551
+ if (realPod.token) headers['x-anyrun-network-token'] = realPod.token;
551
552
  if (!headers['x-sand-slim-avatars']) headers['x-sand-slim-avatars'] = '1';
552
553
  const path0 = (full || '').split('?')[0];
553
554
  const interesting = /sendPrompt|Transcript|listAgents|promptAcceptance|openAgentTail|createAgent/i.test(path0);
@@ -1256,6 +1257,7 @@ async function zooComplete(prompt, log, agentId, parsed = {}) {
1256
1257
  'Tools: read_file, write_file, exec, list_dir. USE THEM. Write files to disk instead of pasting giant HTML into chat.',
1257
1258
  'Pasted images arrive as attachments — you can see them when present. Do not claim you cannot see images if they are in this turn.',
1258
1259
  'Never claim you lack filesystem access or local-exec. If a tool errors, report the error.',
1260
+ 'After using tools you MUST still write a normal chat reply: what you did, file paths written, and what to open. Empty content is a bug.',
1259
1261
  'A spend footer is appended after your reply by the host — ignore it.',
1260
1262
  ].join(' '),
1261
1263
  },
@@ -1284,14 +1286,8 @@ async function zooComplete(prompt, log, agentId, parsed = {}) {
1284
1286
  const maxTok = Number(process.env.OPENZOO_ASK_MAX_TOKENS || 4096);
1285
1287
  let lastData = {};
1286
1288
  let text = '';
1287
- for (let step = 0; step < 8; step++) {
1288
- const payload = {
1289
- model,
1290
- messages,
1291
- tools: LOCAL_TOOLS,
1292
- tool_choice: 'auto',
1293
- max_tokens: maxTok,
1294
- };
1289
+ const usedTools = [];
1290
+ const zooPost = async (payload) => {
1295
1291
  const post = () => fetch('http://127.0.0.1:8402/v1/chat/completions', {
1296
1292
  method: 'POST',
1297
1293
  headers: { 'content-type': 'application/json', authorization: 'Bearer sk-openzoo' },
@@ -1305,6 +1301,16 @@ async function zooComplete(prompt, log, agentId, parsed = {}) {
1305
1301
  r = await post();
1306
1302
  }
1307
1303
  const data = await r.json();
1304
+ return { r, data };
1305
+ };
1306
+ for (let step = 0; step < 8; step++) {
1307
+ const { r, data } = await zooPost({
1308
+ model,
1309
+ messages,
1310
+ tools: LOCAL_TOOLS,
1311
+ tool_choice: 'auto',
1312
+ max_tokens: maxTok,
1313
+ });
1308
1314
  lastData = data;
1309
1315
  const msg = data.choices?.[0]?.message || {};
1310
1316
  const calls = Array.isArray(msg.tool_calls) ? msg.tool_calls : [];
@@ -1316,6 +1322,12 @@ async function zooComplete(prompt, log, agentId, parsed = {}) {
1316
1322
  try { args = JSON.parse(c.function?.arguments || c.arguments || '{}'); } catch { args = {}; }
1317
1323
  const name = c.function?.name || c.name || '';
1318
1324
  const result = await runLocalTool(name, args, log);
1325
+ usedTools.push({
1326
+ name,
1327
+ path: args.path,
1328
+ command: args.command ? String(args.command).slice(0, 120) : undefined,
1329
+ note: String(result).slice(0, 200),
1330
+ });
1319
1331
  messages.push({
1320
1332
  role: 'tool',
1321
1333
  tool_call_id: c.id,
@@ -1324,10 +1336,37 @@ async function zooComplete(prompt, log, agentId, parsed = {}) {
1324
1336
  }
1325
1337
  continue;
1326
1338
  }
1327
- text = zooTextFromMessage(msg, data) || (step ? '(tool loop ended with empty content)' : '(empty zoo reply)');
1339
+ text = zooTextFromMessage(msg, data);
1328
1340
  log(`cursor-backend: << zoo ${r.status} ${text.length}c model=${data.model || model} finish=${data.choices?.[0]?.finish_reason || '?'}`);
1329
1341
  break;
1330
1342
  }
1343
+ if (usedTools.length && !String(text || '').trim()) {
1344
+ messages.push({
1345
+ role: 'user',
1346
+ content: 'Stop calling tools. Write a short chat reply summarizing what you did: files written (full paths), commands that mattered, and what the user should open. No empty message.',
1347
+ });
1348
+ const { r, data } = await zooPost({
1349
+ model,
1350
+ messages,
1351
+ max_tokens: Math.max(800, Math.min(maxTok, 2048)),
1352
+ });
1353
+ lastData = data;
1354
+ text = zooTextFromMessage(data.choices?.[0]?.message, data);
1355
+ log(`cursor-backend: << zoo summary ${r.status} ${text.length}c`);
1356
+ }
1357
+ if (!String(text || '').trim()) {
1358
+ if (usedTools.length) {
1359
+ const writes = usedTools.filter((t) => t.name === 'write_file' && t.path).map((t) => t.path);
1360
+ const execs = usedTools.filter((t) => t.name === 'exec' && t.command).map((t) => t.command);
1361
+ const lines = ['Did local work (no model chat text came back):'];
1362
+ if (writes.length) lines.push(`wrote: ${[...new Set(writes)].join(', ')}`);
1363
+ if (execs.length) lines.push(`ran: ${execs.slice(-6).join(' · ')}`);
1364
+ if (lines.length === 1) lines.push(`${usedTools.length} tool calls.`);
1365
+ text = lines.join('\n');
1366
+ } else {
1367
+ text = '(empty zoo reply)';
1368
+ }
1369
+ }
1331
1370
  try { text += await zooSpendOverlay(lastData); } catch { /* overlay must never eat the reply */ }
1332
1371
  return { text, data: lastData };
1333
1372
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openzoo",
3
- "version": "0.50.23",
3
+ "version": "0.50.25",
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",