open-agents-ai 0.103.9 → 0.103.10
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/dist/index.js
CHANGED
|
@@ -12839,7 +12839,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
12839
12839
|
];
|
|
12840
12840
|
NexusTool = class {
|
|
12841
12841
|
name = "nexus";
|
|
12842
|
-
description = "
|
|
12842
|
+
description = "P2P agent mesh networking. IMPORTANT: You MUST call action='connect' FIRST \u2014 it spawns the daemon. Nothing works without it. After connect: join_room, send_message, discover_peers, expose (share models), remote_infer (use remote models). Quick start: connect \u2192 join_room \u2192 send_message. Also: wallet_create, wallet_status, ledger_status, budget_set, spend, invoke_capability, store_content.";
|
|
12843
12843
|
parameters = {
|
|
12844
12844
|
type: "object",
|
|
12845
12845
|
properties: {
|
|
@@ -12878,7 +12878,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
12878
12878
|
"spend",
|
|
12879
12879
|
"remote_infer"
|
|
12880
12880
|
],
|
|
12881
|
-
description: "The nexus action
|
|
12881
|
+
description: "The nexus action. MUST call 'connect' first (spawns daemon). Then: join_room, send_message, discover_peers, expose, status, etc."
|
|
12882
12882
|
},
|
|
12883
12883
|
room_id: {
|
|
12884
12884
|
type: "string",
|
|
@@ -26331,16 +26331,16 @@ var init_expose = __esm({
|
|
|
26331
26331
|
// ── Proxy server ────────────────────────────────────────────────────────
|
|
26332
26332
|
createProxyServer(localPort) {
|
|
26333
26333
|
const target = new URL2(this._targetUrl);
|
|
26334
|
-
|
|
26334
|
+
const server = createServer2((req, res) => {
|
|
26335
|
+
res.on("error", () => {
|
|
26336
|
+
});
|
|
26335
26337
|
const authHeader = req.headers.authorization;
|
|
26336
26338
|
const url = new URL2(req.url ?? "/", `http://127.0.0.1:${localPort}`);
|
|
26337
26339
|
const queryKey = url.searchParams.get("key");
|
|
26338
26340
|
const providedKey = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : queryKey;
|
|
26339
26341
|
if (providedKey !== this._authKey) {
|
|
26340
|
-
this._stats.errors++;
|
|
26341
26342
|
res.writeHead(401, { "Content-Type": "application/json" });
|
|
26342
26343
|
res.end(JSON.stringify({ error: "Unauthorized \u2014 provide Bearer token or ?key= parameter" }));
|
|
26343
|
-
this.emitStats();
|
|
26344
26344
|
return;
|
|
26345
26345
|
}
|
|
26346
26346
|
if (url.pathname === "/v1/system/metrics" && req.method === "GET") {
|
|
@@ -26358,70 +26358,75 @@ var init_expose = __esm({
|
|
|
26358
26358
|
this._stats.totalRequests++;
|
|
26359
26359
|
this._stats.activeConnections++;
|
|
26360
26360
|
this.emitStats();
|
|
26361
|
-
this.extractModelFromRequest(req);
|
|
26362
26361
|
url.searchParams.delete("key");
|
|
26363
26362
|
const forwardPath = url.pathname + url.search;
|
|
26364
|
-
const
|
|
26365
|
-
|
|
26366
|
-
|
|
26367
|
-
|
|
26368
|
-
|
|
26369
|
-
|
|
26370
|
-
|
|
26371
|
-
|
|
26372
|
-
|
|
26373
|
-
|
|
26374
|
-
|
|
26375
|
-
|
|
26363
|
+
const bodyChunks = [];
|
|
26364
|
+
req.on("data", (chunk) => bodyChunks.push(chunk));
|
|
26365
|
+
req.on("end", () => {
|
|
26366
|
+
const body = Buffer.concat(bodyChunks);
|
|
26367
|
+
if (req.method === "POST" && body.length > 0) {
|
|
26368
|
+
try {
|
|
26369
|
+
const text = body.toString("utf8", 0, Math.min(body.length, 1024));
|
|
26370
|
+
const modelMatch = text.match(/"model"\s*:\s*"([^"]+)"/);
|
|
26371
|
+
if (modelMatch) {
|
|
26372
|
+
const model = modelMatch[1];
|
|
26373
|
+
const count = this._stats.modelUsage.get(model) ?? 0;
|
|
26374
|
+
this._stats.modelUsage.set(model, count + 1);
|
|
26375
|
+
}
|
|
26376
|
+
} catch {
|
|
26377
|
+
}
|
|
26378
|
+
}
|
|
26379
|
+
const forwardHeaders = { ...req.headers, host: target.host };
|
|
26380
|
+
delete forwardHeaders.authorization;
|
|
26381
|
+
if (body.length > 0) {
|
|
26382
|
+
forwardHeaders["content-length"] = String(body.length);
|
|
26383
|
+
}
|
|
26384
|
+
const proxyReq = httpRequest({
|
|
26385
|
+
hostname: target.hostname,
|
|
26386
|
+
port: target.port || (target.protocol === "https:" ? 443 : 80),
|
|
26387
|
+
path: forwardPath,
|
|
26388
|
+
method: req.method,
|
|
26389
|
+
headers: forwardHeaders
|
|
26390
|
+
}, (proxyRes) => {
|
|
26391
|
+
proxyRes.on("error", () => {
|
|
26392
|
+
this._stats.activeConnections = Math.max(0, this._stats.activeConnections - 1);
|
|
26393
|
+
this.emitStats();
|
|
26394
|
+
});
|
|
26395
|
+
res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
|
|
26396
|
+
proxyRes.pipe(res);
|
|
26397
|
+
proxyRes.on("end", () => {
|
|
26398
|
+
this._stats.activeConnections = Math.max(0, this._stats.activeConnections - 1);
|
|
26399
|
+
this.emitStats();
|
|
26400
|
+
});
|
|
26401
|
+
});
|
|
26402
|
+
proxyReq.on("error", (err) => {
|
|
26403
|
+
this._stats.errors++;
|
|
26376
26404
|
this._stats.activeConnections = Math.max(0, this._stats.activeConnections - 1);
|
|
26405
|
+
if (!res.headersSent) {
|
|
26406
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
26407
|
+
res.end(JSON.stringify({ error: `Backend unreachable: ${err.message}` }));
|
|
26408
|
+
} else {
|
|
26409
|
+
try {
|
|
26410
|
+
res.end();
|
|
26411
|
+
} catch {
|
|
26412
|
+
}
|
|
26413
|
+
}
|
|
26377
26414
|
this.emitStats();
|
|
26378
26415
|
});
|
|
26416
|
+
if (body.length > 0) {
|
|
26417
|
+
proxyReq.write(body);
|
|
26418
|
+
}
|
|
26419
|
+
proxyReq.end();
|
|
26379
26420
|
});
|
|
26380
|
-
|
|
26381
|
-
this._stats.errors++;
|
|
26421
|
+
req.on("error", () => {
|
|
26382
26422
|
this._stats.activeConnections = Math.max(0, this._stats.activeConnections - 1);
|
|
26383
|
-
if (!res.headersSent) {
|
|
26384
|
-
res.writeHead(502, { "Content-Type": "application/json" });
|
|
26385
|
-
res.end(JSON.stringify({ error: `Backend unreachable: ${err.message}` }));
|
|
26386
|
-
}
|
|
26387
|
-
this._stats.status = "error";
|
|
26388
26423
|
this.emitStats();
|
|
26389
|
-
setTimeout(() => {
|
|
26390
|
-
if (this.server && this._stats.status === "error") {
|
|
26391
|
-
this._stats.status = "active";
|
|
26392
|
-
this.emitStats();
|
|
26393
|
-
}
|
|
26394
|
-
}, 5e3);
|
|
26395
26424
|
});
|
|
26396
|
-
req.pipe(proxyReq);
|
|
26397
26425
|
});
|
|
26398
|
-
|
|
26399
|
-
|
|
26400
|
-
|
|
26401
|
-
|
|
26402
|
-
return;
|
|
26403
|
-
const chunks = [];
|
|
26404
|
-
const origEmit = req.emit.bind(req);
|
|
26405
|
-
let peeked = false;
|
|
26406
|
-
const stats = this._stats;
|
|
26407
|
-
req.emit = function(event, ...args) {
|
|
26408
|
-
if (event === "data" && !peeked) {
|
|
26409
|
-
peeked = true;
|
|
26410
|
-
try {
|
|
26411
|
-
const chunk = args[0];
|
|
26412
|
-
chunks.push(chunk);
|
|
26413
|
-
const text = Buffer.concat(chunks).toString();
|
|
26414
|
-
const modelMatch = text.match(/"model"\s*:\s*"([^"]+)"/);
|
|
26415
|
-
if (modelMatch) {
|
|
26416
|
-
const model = modelMatch[1];
|
|
26417
|
-
const count = stats.modelUsage.get(model) ?? 0;
|
|
26418
|
-
stats.modelUsage.set(model, count + 1);
|
|
26419
|
-
}
|
|
26420
|
-
} catch {
|
|
26421
|
-
}
|
|
26422
|
-
}
|
|
26423
|
-
return origEmit(event, ...args);
|
|
26424
|
-
};
|
|
26426
|
+
server.on("error", (err) => {
|
|
26427
|
+
this.options.onError?.(`Proxy server error: ${err.message}`);
|
|
26428
|
+
});
|
|
26429
|
+
return server;
|
|
26425
26430
|
}
|
|
26426
26431
|
// ── Cloudflared ─────────────────────────────────────────────────────────
|
|
26427
26432
|
startCloudflared(port) {
|
|
@@ -29744,7 +29749,8 @@ function trySudoPasswordless(cmd, timeoutMs = 12e4) {
|
|
|
29744
29749
|
}
|
|
29745
29750
|
function runWithSudo(cmd, password, timeoutMs = 12e4) {
|
|
29746
29751
|
try {
|
|
29747
|
-
|
|
29752
|
+
const escaped = cmd.replace(/'/g, "'\\''");
|
|
29753
|
+
execSync26(`sudo -S bash -c '${escaped}'`, {
|
|
29748
29754
|
input: password + "\n",
|
|
29749
29755
|
stdio: ["pipe", "pipe", "pipe"],
|
|
29750
29756
|
timeout: timeoutMs,
|
|
@@ -31906,6 +31912,10 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
31906
31912
|
`);
|
|
31907
31913
|
}
|
|
31908
31914
|
process.stdout.write("\n");
|
|
31915
|
+
if (ctx.hasActiveTask?.()) {
|
|
31916
|
+
ctx.abortActiveTask?.();
|
|
31917
|
+
renderWarning("Active task aborted \u2014 endpoint changed. Send a new prompt to continue.");
|
|
31918
|
+
}
|
|
31909
31919
|
try {
|
|
31910
31920
|
const newModels = await fetchModels(normalizedUrl, apiKey);
|
|
31911
31921
|
if (newModels.length > 0) {
|
|
@@ -44000,6 +44010,11 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
44000
44010
|
},
|
|
44001
44011
|
refreshModelCache,
|
|
44002
44012
|
hasActiveTask: () => activeTask !== null,
|
|
44013
|
+
abortActiveTask() {
|
|
44014
|
+
if (!activeTask)
|
|
44015
|
+
return;
|
|
44016
|
+
activeTask.runner.abort();
|
|
44017
|
+
},
|
|
44003
44018
|
requestCompaction(strategy) {
|
|
44004
44019
|
if (!activeTask)
|
|
44005
44020
|
return false;
|
package/package.json
CHANGED
|
@@ -238,11 +238,13 @@ If you notice you're performing the SAME multi-step sequence for the 3rd time or
|
|
|
238
238
|
|
|
239
239
|
## Nexus P2P Networking (v1.5.6) — Decentralized Agent Communication + x402 Payments
|
|
240
240
|
|
|
241
|
-
You HAVE the nexus tool.
|
|
241
|
+
You HAVE the nexus tool. USE IT when asked about connecting, messaging, or networking with other agents.
|
|
242
242
|
|
|
243
|
-
|
|
243
|
+
**CRITICAL: ALWAYS call nexus(action='connect') FIRST.** It spawns the daemon process. No other action works without it.
|
|
244
244
|
|
|
245
|
-
|
|
245
|
+
Auto-installs open-agents-nexus on first use. Requires Node >= 22.
|
|
246
|
+
|
|
247
|
+
### Quick Start (3 steps — connect MUST be first)
|
|
246
248
|
nexus(action='connect', agent_name='MyAgent')
|
|
247
249
|
nexus(action='join_room', room_id='general')
|
|
248
250
|
nexus(action='send_message', room_id='general', message='Hello from MyAgent!')
|
|
@@ -21,7 +21,7 @@ NEVER say "I can't do that". ALWAYS attempt the task using your tools. If a tool
|
|
|
21
21
|
- web_search: Search the web
|
|
22
22
|
- web_fetch: Fetch a web page's text
|
|
23
23
|
- memory_read / memory_write: Persistent memory across sessions
|
|
24
|
-
- nexus: P2P agent
|
|
24
|
+
- nexus: P2P agent mesh. ALWAYS call connect FIRST (spawns daemon). Then: join_room, send_message, discover_peers, expose, etc.
|
|
25
25
|
- task_complete: Signal completion with a summary
|
|
26
26
|
- background_run / task_status / task_output / task_stop: Background tasks
|
|
27
27
|
- sub_agent: Delegate a subtask to an independent agent (use background=true for parallel work)
|
|
@@ -67,7 +67,7 @@ You are **Open Agent** (open-agents-ai), an autonomous AI coding agent running o
|
|
|
67
67
|
- Web: search documentation and fetch web pages
|
|
68
68
|
- Memory: persistent cross-session knowledge (memory_read/memory_write)
|
|
69
69
|
- Skills: 250+ behavioral skills (skill_list), build new ones (skill_build)
|
|
70
|
-
- P2P:
|
|
70
|
+
- P2P: nexus agent mesh — ALWAYS call nexus(action='connect') FIRST, then join_room/send_message/discover_peers/expose
|
|
71
71
|
- Background tasks: run long commands in background, check status later
|
|
72
72
|
- Voice/TTS: text-to-speech via ONNX (cross-platform) or MLX (Apple Silicon) — use /voice to enable
|
|
73
73
|
- Desktop/Vision: screenshot, click UI, OCR (via explore_tools)
|
|
@@ -20,5 +20,5 @@ Rules:
|
|
|
20
20
|
- Directory entries are RELATIVE. If you list "parent/" and see "child", the path is "parent/child" — NOT ".child".
|
|
21
21
|
- Use list_directory for directories, NOT file_read. Prefer list_directory over shell ls.
|
|
22
22
|
- You are **Open Agent** (open-agents-ai) — an AI coding agent running locally via Ollama/vLLM. No cloud APIs.
|
|
23
|
-
- Core: code editing, shell commands, web search, memory, 250+ skills (skill_list), P2P
|
|
23
|
+
- Core: code editing, shell commands, web search, memory, 250+ skills (skill_list), P2P mesh (nexus — call connect FIRST), background tasks.
|
|
24
24
|
- When asked "what can you do?", use explore_tools() and skill_list() to discover and report your actual capabilities. Do NOT hallucinate.
|