openzoo 0.50.44 → 0.50.46
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/lib/cursorbackend.js +76 -8
- package/lib/grokbotAccount.js +11 -1
- package/package.json +1 -1
package/lib/cursorbackend.js
CHANGED
|
@@ -39,7 +39,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
39
39
|
import { encodeAvailableModels, encodeForMethod, encodeEnsureSandBox, encodeGetGrokBotSendStatus, decodeProtoFields, unwrapConnect } from './cursorapi.js';
|
|
40
40
|
import {
|
|
41
41
|
accountPodPath, accountAgentsPath, rosterForAccount, rosterForEvent,
|
|
42
|
-
readHouseRoster, houseAgentsPath, shapeAgent, agentBrief,
|
|
42
|
+
readHouseRoster, houseAgentsPath, shapeAgent, agentBrief, briefFromName,
|
|
43
43
|
} from './grokbotAccount.js';
|
|
44
44
|
import { formatSpendFooter, mergeTurnProof } from './spendProof.js';
|
|
45
45
|
import { prefixVisitorRichText } from './grokbotweb.js';
|
|
@@ -361,8 +361,18 @@ function useHouseRoster() {
|
|
|
361
361
|
return Boolean(process.env.OZ_HIJACK_POD) && !sniffOn();
|
|
362
362
|
}
|
|
363
363
|
function loadAgents() {
|
|
364
|
-
const house = readHouseRoster(HOME, activeAccountId);
|
|
365
|
-
|
|
364
|
+
const house = readHouseRoster(HOME, activeAccountId) || [];
|
|
365
|
+
const shaped = house.map(shapeAgent);
|
|
366
|
+
const dirty = shaped.some((a, i) => a.brief && a.brief !== String(house[i]?.brief || house[i]?.description || ''));
|
|
367
|
+
if (dirty && shaped.length) {
|
|
368
|
+
writeJsonFile(houseAgentsPath(HOME), shaped);
|
|
369
|
+
if (activeAccountId) {
|
|
370
|
+
const p = accountAgentsPath(HOME, activeAccountId);
|
|
371
|
+
if (p) writeJsonFile(p, shaped);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
for (const a of shaped) seedBriefOnCanvas(a);
|
|
375
|
+
return shaped;
|
|
366
376
|
}
|
|
367
377
|
function saveAgents(a) {
|
|
368
378
|
if (!Array.isArray(a)) return;
|
|
@@ -1251,8 +1261,66 @@ function mintLocalAgent(parsed = {}) {
|
|
|
1251
1261
|
}
|
|
1252
1262
|
saveAgents(list.map(shapeAgent));
|
|
1253
1263
|
agentTranscript(id);
|
|
1264
|
+
seedBriefOnCanvas(agent);
|
|
1254
1265
|
return agent;
|
|
1255
1266
|
}
|
|
1267
|
+
|
|
1268
|
+
function entryKickText(e) {
|
|
1269
|
+
if (!e || typeof e !== 'object') return '';
|
|
1270
|
+
if (e.kind === 'send-message') return String(e.message?.content || '');
|
|
1271
|
+
return String(e.content || '');
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
const briefKicked = new Set();
|
|
1275
|
+
function needsJobKick(agent) {
|
|
1276
|
+
if (!agent?.id || !String(agent.brief || '').trim()) return false;
|
|
1277
|
+
if (briefKicked.has(agent.id)) return false;
|
|
1278
|
+
const entries = agentTranscript(agent.id).entries || [];
|
|
1279
|
+
if (!entries.length) return true;
|
|
1280
|
+
if (entries.length > 4) return false;
|
|
1281
|
+
const blob = entries.map(entryKickText).join('\n');
|
|
1282
|
+
if (/\[brief\]/i.test(blob) && entries.length <= 3) {
|
|
1283
|
+
if (/Working from this brief/i.test(blob)) return true;
|
|
1284
|
+
if (entries.length === 1) return true;
|
|
1285
|
+
}
|
|
1286
|
+
return false;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
function kickBriefedAgent(agent, log = () => {}) {
|
|
1290
|
+
if (!needsJobKick(agent)) return false;
|
|
1291
|
+
briefKicked.add(agent.id);
|
|
1292
|
+
const nonce = `oz-kick-${agent.id}`;
|
|
1293
|
+
log(`cursor-backend: brief-kick start ${agent.id} ${JSON.stringify(agent.name)}`);
|
|
1294
|
+
setImmediate(async () => {
|
|
1295
|
+
try {
|
|
1296
|
+
const z = await zooComplete(
|
|
1297
|
+
'Your brief is in this thread. Start that job now. Use tools. Do real work. Do not wait for another human message. Do not only say understood.',
|
|
1298
|
+
log,
|
|
1299
|
+
agent.id,
|
|
1300
|
+
{},
|
|
1301
|
+
);
|
|
1302
|
+
const line = fanoutLine(agent.id, 'assistant', z.text, { clientNonce: nonce, requestId: nonce });
|
|
1303
|
+
ssePush('transcript', { ...gatewayEntry(line), agentId: agent.id });
|
|
1304
|
+
bumpAgent(agent.id, { preview: z.text, notify: true });
|
|
1305
|
+
log(`cursor-backend: brief-kick done ${agent.id} seq=${line.seq}`);
|
|
1306
|
+
} catch (e) {
|
|
1307
|
+
briefKicked.delete(agent.id);
|
|
1308
|
+
log(`cursor-backend: brief-kick failed ${agent.id}: ${e.message}`);
|
|
1309
|
+
}
|
|
1310
|
+
});
|
|
1311
|
+
return true;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
function seedBriefOnCanvas(agent, log) {
|
|
1315
|
+
if (!agent?.id || !String(agent.brief || '').trim()) return false;
|
|
1316
|
+
const t = agentTranscript(agent.id);
|
|
1317
|
+
if (!(t.entries || []).length) {
|
|
1318
|
+
const nonce = `oz-brief-${agent.id}`;
|
|
1319
|
+
const userLine = fanoutLine(agent.id, 'user', `[brief]\n${agent.brief}`, { clientNonce: nonce, requestId: nonce });
|
|
1320
|
+
ssePush('transcript', { ...gatewayEntry(userLine), agentId: agent.id });
|
|
1321
|
+
}
|
|
1322
|
+
return kickBriefedAgent(agent, log || ((m) => console.error(m)));
|
|
1323
|
+
}
|
|
1256
1324
|
function groupMemberIds(agentId) {
|
|
1257
1325
|
const a = (cachedAgentList() || []).find((x) => x.id === agentId);
|
|
1258
1326
|
if (!a?.isGroup) return [];
|
|
@@ -2078,12 +2146,12 @@ async function runLocalTool(name, args, log, ctx = {}) {
|
|
|
2078
2146
|
return JSON.stringify(got);
|
|
2079
2147
|
}
|
|
2080
2148
|
if (name === 'create_agent') {
|
|
2081
|
-
const
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
});
|
|
2149
|
+
const name = String(args.name || args.title || 'New Bot').slice(0, 80);
|
|
2150
|
+
const brief = String(args.brief || args.instructions || '').trim() || briefFromName(name);
|
|
2151
|
+
const agent = mintLocalAgent({ name, brief });
|
|
2085
2152
|
pushCreatedAgent(agent, { select: args.select !== false });
|
|
2086
|
-
|
|
2153
|
+
seedBriefOnCanvas(agent);
|
|
2154
|
+
log(`cursor-backend: create_agent tool id=${agent.id} name=${JSON.stringify(agent.name)} brief=${brief ? brief.length : 0}c`);
|
|
2087
2155
|
return JSON.stringify({ ok: true, id: agent.id, name: agent.name, brief: agent.brief || '' });
|
|
2088
2156
|
}
|
|
2089
2157
|
if (name === 'set_brief') {
|
package/lib/grokbotAccount.js
CHANGED
|
@@ -111,6 +111,15 @@ function activityTs(agent, activity) {
|
|
|
111
111
|
* nulls, then clears the whole persisted tray. That is how a group vanished
|
|
112
112
|
* after the first send: bumpAgent wrote a partial row, restore returned null.
|
|
113
113
|
*/
|
|
114
|
+
/** Standing job from a sidebar name like "6 · Content Studio" or "Bot 1 — Marketing (X)". */
|
|
115
|
+
export function briefFromName(name) {
|
|
116
|
+
const n = String(name || '').trim();
|
|
117
|
+
if (!n || /^(new bot|chat|group)$/i.test(n)) return '';
|
|
118
|
+
const role = n.replace(/^\d+\s*[·.•.\-—–]+\s*/, '').trim() || n;
|
|
119
|
+
if (role.length < 2) return '';
|
|
120
|
+
return `You are ${n}. Your job is ${role}. Do that job. Do not ask the human to re-brief you. Coordinate with list_agents and message_agent.`;
|
|
121
|
+
}
|
|
122
|
+
|
|
114
123
|
/** Standing job text. shapeAgent used to drop this, so every restart was amnesia. */
|
|
115
124
|
export function agentBrief(raw = {}) {
|
|
116
125
|
const a = raw && typeof raw === 'object' ? raw : {};
|
|
@@ -119,7 +128,8 @@ export function agentBrief(raw = {}) {
|
|
|
119
128
|
if (typeof v === 'string' && v.trim()) return v.trim().slice(0, 8000);
|
|
120
129
|
}
|
|
121
130
|
const d = String(a.description || '').trim();
|
|
122
|
-
return d.slice(0, 8000);
|
|
131
|
+
if (d) return d.slice(0, 8000);
|
|
132
|
+
return briefFromName(a.name || a.title).slice(0, 8000);
|
|
123
133
|
}
|
|
124
134
|
|
|
125
135
|
export function shapeAgent(raw = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.46",
|
|
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",
|