open-agents-ai 0.103.28 → 0.103.30
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 +237 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12206,7 +12206,43 @@ async function handleCmd(cmd) {
|
|
|
12206
12206
|
const node = nexus.network?.node;
|
|
12207
12207
|
const peers = node?.getPeers?.() || [];
|
|
12208
12208
|
const list = peers.slice(0, 20).map(p => p.toString?.() || String(p));
|
|
12209
|
-
|
|
12209
|
+
// Include NATS-discovered peers with capabilities
|
|
12210
|
+
var dpNatsFile = join(nexusDir, 'discovered-peers.json');
|
|
12211
|
+
var dpNats = {};
|
|
12212
|
+
try { if (existsSync(dpNatsFile)) dpNats = JSON.parse(readFileSync(dpNatsFile, 'utf8')); } catch {}
|
|
12213
|
+
var dpNatsCount = Object.keys(dpNats).length;
|
|
12214
|
+
var dpLines = ['Connected peers: ' + list.length];
|
|
12215
|
+
for (var dpi = 0; dpi < list.length; dpi++) {
|
|
12216
|
+
dpLines.push(' ' + list[dpi]);
|
|
12217
|
+
}
|
|
12218
|
+
if (dpNatsCount > 0) {
|
|
12219
|
+
dpLines.push('NATS-discovered peers: ' + dpNatsCount);
|
|
12220
|
+
for (var dpKey of Object.keys(dpNats)) {
|
|
12221
|
+
var dpEntry = dpNats[dpKey];
|
|
12222
|
+
var dpAge = Math.round((Date.now() - dpEntry.lastSeen) / 1000);
|
|
12223
|
+
dpLines.push(' ' + dpKey.slice(0, 20) + '... (' + dpEntry.agentName + ') caps=' + (dpEntry.capabilities || []).length + ' seen=' + dpAge + 's ago');
|
|
12224
|
+
}
|
|
12225
|
+
}
|
|
12226
|
+
writeResp(id, { ok: true, output: dpLines.join('\\n') });
|
|
12227
|
+
break;
|
|
12228
|
+
}
|
|
12229
|
+
case 'discover_peer_caps': {
|
|
12230
|
+
var dpcPeerId = args.peer_id;
|
|
12231
|
+
if (!dpcPeerId) { writeResp(id, { ok: false, output: 'peer_id is required' }); return; }
|
|
12232
|
+
var dpcFile = join(nexusDir, 'discovered-peers.json');
|
|
12233
|
+
var dpcPeers = {};
|
|
12234
|
+
try { if (existsSync(dpcFile)) dpcPeers = JSON.parse(readFileSync(dpcFile, 'utf8')); } catch {}
|
|
12235
|
+
var dpcEntry = dpcPeers[String(dpcPeerId)];
|
|
12236
|
+
if (dpcEntry && dpcEntry.capabilities && dpcEntry.capabilities.length > 0) {
|
|
12237
|
+
var dpcAge = Date.now() - dpcEntry.lastSeen;
|
|
12238
|
+
if (dpcAge < 5 * 60 * 1000) { // 5 minute freshness
|
|
12239
|
+
writeResp(id, { ok: true, output: JSON.stringify(dpcEntry, null, 2) });
|
|
12240
|
+
} else {
|
|
12241
|
+
writeResp(id, { ok: false, output: 'Peer data stale (' + Math.round(dpcAge / 1000) + 's old). Wait for NATS re-announce.' });
|
|
12242
|
+
}
|
|
12243
|
+
} else {
|
|
12244
|
+
writeResp(id, { ok: false, output: 'Peer not found in NATS discovery cache. Peer may not have announced yet (announcements every 30s).' });
|
|
12245
|
+
}
|
|
12210
12246
|
break;
|
|
12211
12247
|
}
|
|
12212
12248
|
case 'list_rooms': {
|
|
@@ -12224,8 +12260,34 @@ async function handleCmd(cmd) {
|
|
|
12224
12260
|
case 'find_agent': {
|
|
12225
12261
|
const peerId = args.peer_id;
|
|
12226
12262
|
if (!peerId) { writeResp(id, { ok: false, output: 'peer_id is required' }); return; }
|
|
12227
|
-
|
|
12228
|
-
|
|
12263
|
+
try {
|
|
12264
|
+
var FIND_TIMEOUT = 15000;
|
|
12265
|
+
var findPromise = nexus.findAgent(peerId);
|
|
12266
|
+
var findTimeoutPromise = new Promise(function(resolve) { setTimeout(function() { resolve(null); }, FIND_TIMEOUT); });
|
|
12267
|
+
var profile = await Promise.race([findPromise, findTimeoutPromise]);
|
|
12268
|
+
writeResp(id, { ok: true, output: profile ? JSON.stringify(profile, null, 2) : 'Agent not found: ' + peerId });
|
|
12269
|
+
} catch (findErr) {
|
|
12270
|
+
writeResp(id, { ok: false, output: 'find_agent error: ' + (findErr.message || String(findErr)) });
|
|
12271
|
+
}
|
|
12272
|
+
break;
|
|
12273
|
+
}
|
|
12274
|
+
case 'query_peer_caps': {
|
|
12275
|
+
var qpcPeerId = args.peer_id;
|
|
12276
|
+
if (!qpcPeerId) { writeResp(id, { ok: false, output: 'peer_id is required' }); return; }
|
|
12277
|
+
dlog('query_peer_caps: peer=' + String(qpcPeerId).slice(0, 20));
|
|
12278
|
+
try {
|
|
12279
|
+
var QPC_TIMEOUT = 15000;
|
|
12280
|
+
var qpcInput = {};
|
|
12281
|
+
if (args.auth_key) qpcInput.auth_key = args.auth_key;
|
|
12282
|
+
var qpcPromise = nexus.invokeCapability(String(qpcPeerId), '__list_capabilities', qpcInput, { stream: false, maxDurationMs: 10000 });
|
|
12283
|
+
var qpcTimeoutPromise = new Promise(function(_, reject) { setTimeout(function() { reject(new Error('query_peer_caps timed out after 15s')); }, QPC_TIMEOUT); });
|
|
12284
|
+
var qpcResult = await Promise.race([qpcPromise, qpcTimeoutPromise]);
|
|
12285
|
+
dlog('query_peer_caps: SUCCESS');
|
|
12286
|
+
writeResp(id, { ok: true, output: typeof qpcResult === 'string' ? qpcResult : JSON.stringify(qpcResult, null, 2) });
|
|
12287
|
+
} catch (qpcErr) {
|
|
12288
|
+
dlog('query_peer_caps: ERROR ' + (qpcErr.message || String(qpcErr)));
|
|
12289
|
+
writeResp(id, { ok: false, output: 'query_peer_caps error: ' + (qpcErr.message || String(qpcErr)) });
|
|
12290
|
+
}
|
|
12229
12291
|
break;
|
|
12230
12292
|
}
|
|
12231
12293
|
case 'invoke_capability': {
|
|
@@ -12849,6 +12911,30 @@ async function handleCmd(cmd) {
|
|
|
12849
12911
|
dlog('system_metrics capability registered');
|
|
12850
12912
|
}
|
|
12851
12913
|
|
|
12914
|
+
// Register __list_capabilities \u2014 allows remote peers to discover available models
|
|
12915
|
+
if (typeof nexus.registerCapability === 'function') {
|
|
12916
|
+
nexus.registerCapability('__list_capabilities', async (request, stream) => {
|
|
12917
|
+
dlog('__list_capabilities invoked from ' + (request.from || 'unknown'));
|
|
12918
|
+
await stream.write({ type: 'invoke.accept', version: 1, requestId: request.requestId, accepted: true });
|
|
12919
|
+
var allCaps = typeof nexus.getRegisteredCapabilities === 'function' ? nexus.getRegisteredCapabilities() : [];
|
|
12920
|
+
var modelsInfo = [];
|
|
12921
|
+
for (var ci = 0; ci < pricingMenu.length; ci++) {
|
|
12922
|
+
var pm = pricingMenu[ci];
|
|
12923
|
+
modelsInfo.push({
|
|
12924
|
+
name: pm.model,
|
|
12925
|
+
parameterSize: pm.parameterSize || '',
|
|
12926
|
+
family: pm.family || '',
|
|
12927
|
+
quantization: pm.quantization || '',
|
|
12928
|
+
});
|
|
12929
|
+
}
|
|
12930
|
+
var capsPayload = JSON.stringify({ capabilities: allCaps, models: modelsInfo, agentName: agentName, peerId: nexus.peerId });
|
|
12931
|
+
await stream.write({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'result', data: capsPayload });
|
|
12932
|
+
await stream.write({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: capsPayload.length } });
|
|
12933
|
+
stream.close();
|
|
12934
|
+
});
|
|
12935
|
+
dlog('__list_capabilities capability registered');
|
|
12936
|
+
}
|
|
12937
|
+
|
|
12852
12938
|
// Write pricing menu to file
|
|
12853
12939
|
const pricingFile = join(nexusDir, 'pricing.json');
|
|
12854
12940
|
writeFileSync(pricingFile, JSON.stringify({ updated: new Date().toISOString(), models: pricingMenu }, null, 2));
|
|
@@ -13014,6 +13100,35 @@ process.on('unhandledRejection', (reason) => {
|
|
|
13014
13100
|
}
|
|
13015
13101
|
} catch {}
|
|
13016
13102
|
|
|
13103
|
+
// Subscribe to NATS peer announcements \u2014 cache remote peer capabilities
|
|
13104
|
+
var discoveredPeers = {};
|
|
13105
|
+
var discoveredPeersFile = join(nexusDir, 'discovered-peers.json');
|
|
13106
|
+
try {
|
|
13107
|
+
if (existsSync(discoveredPeersFile)) {
|
|
13108
|
+
discoveredPeers = JSON.parse(readFileSync(discoveredPeersFile, 'utf8'));
|
|
13109
|
+
}
|
|
13110
|
+
} catch {}
|
|
13111
|
+
try {
|
|
13112
|
+
if (nexus.nats && typeof nexus.nats.subscribe === 'function') {
|
|
13113
|
+
nexus.nats.subscribe(function(announcement) {
|
|
13114
|
+
if (!announcement || !announcement.peerId) return;
|
|
13115
|
+
if (announcement.peerId === nexus.peerId) return; // skip self
|
|
13116
|
+
discoveredPeers[announcement.peerId] = {
|
|
13117
|
+
peerId: announcement.peerId,
|
|
13118
|
+
agentName: announcement.agentName || '',
|
|
13119
|
+
capabilities: announcement.capabilities || [],
|
|
13120
|
+
multiaddrs: announcement.multiaddrs || [],
|
|
13121
|
+
lastSeen: Date.now(),
|
|
13122
|
+
};
|
|
13123
|
+
try { writeFileSync(discoveredPeersFile, JSON.stringify(discoveredPeers, null, 2)); } catch {}
|
|
13124
|
+
dlog('NATS peer discovered: ' + String(announcement.peerId).slice(0, 20) + ' caps=' + (announcement.capabilities || []).length);
|
|
13125
|
+
});
|
|
13126
|
+
dlog('NATS peer discovery subscription active');
|
|
13127
|
+
}
|
|
13128
|
+
} catch (natsSubErr) {
|
|
13129
|
+
dlog('NATS subscribe failed: ' + (natsSubErr.message || natsSubErr));
|
|
13130
|
+
}
|
|
13131
|
+
|
|
13017
13132
|
writeStatus();
|
|
13018
13133
|
console.log('Nexus daemon connected as ' + nexus.peerId);
|
|
13019
13134
|
} catch (err) {
|
|
@@ -13215,6 +13330,9 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
13215
13330
|
case "discover_peers":
|
|
13216
13331
|
result = await this.sendDaemonCmd("discover_peers", args);
|
|
13217
13332
|
break;
|
|
13333
|
+
case "discover_peer_caps":
|
|
13334
|
+
result = await this.sendDaemonCmd("discover_peer_caps", args, 5e3);
|
|
13335
|
+
break;
|
|
13218
13336
|
case "list_rooms":
|
|
13219
13337
|
result = await this.sendDaemonCmd("list_rooms", args);
|
|
13220
13338
|
break;
|
|
@@ -13224,6 +13342,9 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
13224
13342
|
case "find_agent":
|
|
13225
13343
|
result = await this.sendDaemonCmd("find_agent", args, 3e4);
|
|
13226
13344
|
break;
|
|
13345
|
+
case "query_peer_caps":
|
|
13346
|
+
result = await this.sendDaemonCmd("query_peer_caps", args, 2e4);
|
|
13347
|
+
break;
|
|
13227
13348
|
case "invoke_capability":
|
|
13228
13349
|
result = await this.sendDaemonCmd("invoke_capability", args, 1e5);
|
|
13229
13350
|
break;
|
|
@@ -29845,26 +29966,102 @@ async function fetchPeerModels(peerId) {
|
|
|
29845
29966
|
} catch {
|
|
29846
29967
|
}
|
|
29847
29968
|
}
|
|
29848
|
-
|
|
29849
|
-
|
|
29850
|
-
|
|
29851
|
-
|
|
29852
|
-
|
|
29853
|
-
|
|
29854
|
-
|
|
29855
|
-
|
|
29856
|
-
|
|
29857
|
-
|
|
29858
|
-
|
|
29859
|
-
|
|
29860
|
-
|
|
29861
|
-
|
|
29862
|
-
|
|
29863
|
-
|
|
29864
|
-
|
|
29969
|
+
try {
|
|
29970
|
+
const capsResult = await nexusTool.execute({
|
|
29971
|
+
action: "query_peer_caps",
|
|
29972
|
+
peer_id: peerId
|
|
29973
|
+
});
|
|
29974
|
+
if (capsResult.success && capsResult.output) {
|
|
29975
|
+
let capsData = null;
|
|
29976
|
+
try {
|
|
29977
|
+
capsData = JSON.parse(capsResult.output);
|
|
29978
|
+
} catch {
|
|
29979
|
+
}
|
|
29980
|
+
if (capsData?.models && capsData.models.length > 0) {
|
|
29981
|
+
return capsData.models.map((m) => ({
|
|
29982
|
+
name: m.name || "unknown",
|
|
29983
|
+
size: m.parameterSize || "",
|
|
29984
|
+
modified: "",
|
|
29985
|
+
sizeBytes: 0,
|
|
29986
|
+
parameterSize: m.parameterSize || "remote"
|
|
29987
|
+
}));
|
|
29988
|
+
}
|
|
29989
|
+
if (capsData?.capabilities && capsData.capabilities.length > 0) {
|
|
29990
|
+
const models = [];
|
|
29991
|
+
for (const cap of capsData.capabilities) {
|
|
29992
|
+
if (typeof cap === "string" && cap.startsWith("inference:")) {
|
|
29993
|
+
const capName = cap.slice(10);
|
|
29994
|
+
const modelName = capName.replace(/_(\d+[bBmMkK])$/, ":$1").replace(/_latest$/, ":latest");
|
|
29995
|
+
models.push({
|
|
29996
|
+
name: modelName,
|
|
29997
|
+
size: "",
|
|
29998
|
+
modified: "",
|
|
29999
|
+
sizeBytes: 0,
|
|
30000
|
+
parameterSize: "remote"
|
|
30001
|
+
});
|
|
30002
|
+
}
|
|
30003
|
+
}
|
|
30004
|
+
if (models.length > 0)
|
|
30005
|
+
return models;
|
|
30006
|
+
}
|
|
29865
30007
|
}
|
|
29866
|
-
|
|
29867
|
-
|
|
30008
|
+
} catch {
|
|
30009
|
+
}
|
|
30010
|
+
try {
|
|
30011
|
+
const natsResult = await nexusTool.execute({
|
|
30012
|
+
action: "discover_peer_caps",
|
|
30013
|
+
peer_id: peerId
|
|
30014
|
+
});
|
|
30015
|
+
if (natsResult.success && natsResult.output) {
|
|
30016
|
+
let natsPeer = null;
|
|
30017
|
+
try {
|
|
30018
|
+
natsPeer = JSON.parse(natsResult.output);
|
|
30019
|
+
} catch {
|
|
30020
|
+
}
|
|
30021
|
+
if (natsPeer?.capabilities && natsPeer.capabilities.length > 0) {
|
|
30022
|
+
const models = [];
|
|
30023
|
+
for (const cap of natsPeer.capabilities) {
|
|
30024
|
+
if (typeof cap === "string" && cap.startsWith("inference:")) {
|
|
30025
|
+
const capName = cap.slice(10);
|
|
30026
|
+
const modelName = capName.replace(/_(\d+[bBmMkK])$/, ":$1").replace(/_latest$/, ":latest");
|
|
30027
|
+
models.push({
|
|
30028
|
+
name: modelName,
|
|
30029
|
+
size: "",
|
|
30030
|
+
modified: "",
|
|
30031
|
+
sizeBytes: 0,
|
|
30032
|
+
parameterSize: "remote"
|
|
30033
|
+
});
|
|
30034
|
+
}
|
|
30035
|
+
}
|
|
30036
|
+
if (models.length > 0)
|
|
30037
|
+
return models;
|
|
30038
|
+
}
|
|
30039
|
+
}
|
|
30040
|
+
} catch {
|
|
30041
|
+
}
|
|
30042
|
+
try {
|
|
30043
|
+
const result = await nexusTool.execute({
|
|
30044
|
+
action: "find_agent",
|
|
30045
|
+
peer_id: peerId
|
|
30046
|
+
});
|
|
30047
|
+
if (result.success && result.output) {
|
|
30048
|
+
const models = [];
|
|
30049
|
+
const capMatches = result.output.matchAll(/inference:([^\s,\]]+)/g);
|
|
30050
|
+
for (const m of capMatches) {
|
|
30051
|
+
const capName = m[1];
|
|
30052
|
+
const modelName = capName.replace(/_(\d+[bBmMkK])$/, ":$1").replace(/_latest$/, ":latest");
|
|
30053
|
+
models.push({
|
|
30054
|
+
name: modelName,
|
|
30055
|
+
size: "",
|
|
30056
|
+
modified: "",
|
|
30057
|
+
sizeBytes: 0,
|
|
30058
|
+
parameterSize: "remote"
|
|
30059
|
+
});
|
|
30060
|
+
}
|
|
30061
|
+
if (models.length > 0)
|
|
30062
|
+
return models;
|
|
30063
|
+
}
|
|
30064
|
+
} catch {
|
|
29868
30065
|
}
|
|
29869
30066
|
if (isLocalPeer) {
|
|
29870
30067
|
const pricingPath = join55(nexusDir, "pricing.json");
|
|
@@ -46476,11 +46673,24 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
46476
46673
|
p2pGateway = null;
|
|
46477
46674
|
}
|
|
46478
46675
|
const nexusTool = new NexusTool(repoRoot);
|
|
46676
|
+
let exposeSpinnerMsg = "Connecting to nexus P2P network...";
|
|
46677
|
+
const exposeFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
46678
|
+
let exposeFrame = 0;
|
|
46679
|
+
const exposeSpinner = setInterval(() => {
|
|
46680
|
+
process.stdout.write(`\r ${c2.cyan(exposeFrames[exposeFrame % exposeFrames.length])} ${c2.dim(exposeSpinnerMsg)}`);
|
|
46681
|
+
exposeFrame++;
|
|
46682
|
+
}, 80);
|
|
46479
46683
|
const newP2P = new ExposeP2PGateway({
|
|
46480
46684
|
kind,
|
|
46481
46685
|
targetUrl,
|
|
46482
46686
|
authKey,
|
|
46483
|
-
stateDir: join50(repoRoot, ".oa")
|
|
46687
|
+
stateDir: join50(repoRoot, ".oa"),
|
|
46688
|
+
onInfo: (msg) => {
|
|
46689
|
+
exposeSpinnerMsg = msg;
|
|
46690
|
+
},
|
|
46691
|
+
onError: (msg) => {
|
|
46692
|
+
exposeSpinnerMsg = msg;
|
|
46693
|
+
}
|
|
46484
46694
|
}, nexusTool);
|
|
46485
46695
|
newP2P.on("stats", (stats) => {
|
|
46486
46696
|
statusBar.setExposeStatus({
|
|
@@ -46492,12 +46702,16 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
46492
46702
|
});
|
|
46493
46703
|
try {
|
|
46494
46704
|
const peerId = await newP2P.start();
|
|
46705
|
+
clearInterval(exposeSpinner);
|
|
46706
|
+
process.stdout.write(`\r\x1B[2K`);
|
|
46495
46707
|
p2pGateway = newP2P;
|
|
46496
46708
|
writeContent(() => {
|
|
46497
46709
|
process.stdout.write("\n" + newP2P.formatConnectionInfo() + "\n\n");
|
|
46498
46710
|
});
|
|
46499
46711
|
return peerId;
|
|
46500
46712
|
} catch (err) {
|
|
46713
|
+
clearInterval(exposeSpinner);
|
|
46714
|
+
process.stdout.write(`\r\x1B[2K`);
|
|
46501
46715
|
if (!transport) {
|
|
46502
46716
|
writeContent(() => {
|
|
46503
46717
|
renderWarning(`libp2p expose failed: ${err instanceof Error ? err.message : String(err)}`);
|
package/package.json
CHANGED