open-agents-ai 0.103.27 → 0.103.29
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 +267 -37
- 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;
|
|
@@ -29809,10 +29930,10 @@ async function fetchPeerModels(peerId) {
|
|
|
29809
29930
|
} catch {
|
|
29810
29931
|
}
|
|
29811
29932
|
if (isLocalPeer) {
|
|
29812
|
-
const
|
|
29813
|
-
if (existsSync42(
|
|
29933
|
+
const pricingPath = join55(nexusDir, "pricing.json");
|
|
29934
|
+
if (existsSync42(pricingPath)) {
|
|
29814
29935
|
try {
|
|
29815
|
-
const pricing = JSON.parse(readFileSync31(
|
|
29936
|
+
const pricing = JSON.parse(readFileSync31(pricingPath, "utf8"));
|
|
29816
29937
|
const localModels = (pricing.models || []).map((m) => ({
|
|
29817
29938
|
name: m.model || "unknown",
|
|
29818
29939
|
size: m.parameterSize || "",
|
|
@@ -29826,41 +29947,138 @@ async function fetchPeerModels(peerId) {
|
|
|
29826
29947
|
}
|
|
29827
29948
|
}
|
|
29828
29949
|
}
|
|
29829
|
-
const
|
|
29830
|
-
|
|
29831
|
-
peer_id: peerId
|
|
29832
|
-
});
|
|
29833
|
-
if (result.success && result.output) {
|
|
29834
|
-
const models = [];
|
|
29835
|
-
const capMatches = result.output.matchAll(/inference:([^\s,\]]+)/g);
|
|
29836
|
-
for (const m of capMatches) {
|
|
29837
|
-
const capName = m[1];
|
|
29838
|
-
const modelName = capName.replace(/_(\d+[bBmMkK])$/, ":$1").replace(/_latest$/, ":latest");
|
|
29839
|
-
models.push({
|
|
29840
|
-
name: modelName,
|
|
29841
|
-
size: "",
|
|
29842
|
-
modified: "",
|
|
29843
|
-
sizeBytes: 0,
|
|
29844
|
-
parameterSize: "remote"
|
|
29845
|
-
});
|
|
29846
|
-
}
|
|
29847
|
-
if (models.length > 0)
|
|
29848
|
-
return models;
|
|
29849
|
-
}
|
|
29850
|
-
const pricingPath = join55(nexusDir, "pricing.json");
|
|
29851
|
-
if (existsSync42(pricingPath)) {
|
|
29950
|
+
const cachePath = join55(nexusDir, "peer-models-cache.json");
|
|
29951
|
+
if (existsSync42(cachePath)) {
|
|
29852
29952
|
try {
|
|
29853
|
-
const
|
|
29854
|
-
|
|
29855
|
-
|
|
29856
|
-
|
|
29857
|
-
|
|
29858
|
-
|
|
29859
|
-
|
|
29860
|
-
|
|
29953
|
+
const cache4 = JSON.parse(readFileSync31(cachePath, "utf8"));
|
|
29954
|
+
if (cache4.peerId === peerId && cache4.models?.length > 0) {
|
|
29955
|
+
const age = Date.now() - new Date(cache4.cachedAt).getTime();
|
|
29956
|
+
if (age < 5 * 60 * 1e3) {
|
|
29957
|
+
return cache4.models.map((m) => ({
|
|
29958
|
+
name: m.name || "unknown",
|
|
29959
|
+
size: m.size || m.parameterSize || "",
|
|
29960
|
+
modified: "",
|
|
29961
|
+
sizeBytes: 0,
|
|
29962
|
+
parameterSize: m.parameterSize || "remote"
|
|
29963
|
+
}));
|
|
29964
|
+
}
|
|
29965
|
+
}
|
|
29861
29966
|
} catch {
|
|
29862
29967
|
}
|
|
29863
29968
|
}
|
|
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
|
+
}
|
|
30007
|
+
}
|
|
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 {
|
|
30065
|
+
}
|
|
30066
|
+
if (isLocalPeer) {
|
|
30067
|
+
const pricingPath = join55(nexusDir, "pricing.json");
|
|
30068
|
+
if (existsSync42(pricingPath)) {
|
|
30069
|
+
try {
|
|
30070
|
+
const pricing = JSON.parse(readFileSync31(pricingPath, "utf8"));
|
|
30071
|
+
return (pricing.models || []).map((m) => ({
|
|
30072
|
+
name: m.model || "unknown",
|
|
30073
|
+
size: m.parameterSize || "",
|
|
30074
|
+
modified: "",
|
|
30075
|
+
sizeBytes: 0,
|
|
30076
|
+
parameterSize: m.parameterSize || "remote"
|
|
30077
|
+
}));
|
|
30078
|
+
} catch {
|
|
30079
|
+
}
|
|
30080
|
+
}
|
|
30081
|
+
}
|
|
29864
30082
|
return [];
|
|
29865
30083
|
} catch {
|
|
29866
30084
|
return [];
|
|
@@ -34273,6 +34491,18 @@ async function handlePeerEndpoint(peerId, authKey, ctx, local) {
|
|
|
34273
34491
|
try {
|
|
34274
34492
|
const models = await fetchModels(peerUrl, authKey);
|
|
34275
34493
|
if (models.length > 0) {
|
|
34494
|
+
try {
|
|
34495
|
+
const { writeFileSync: writeFileSync19, mkdirSync: mkdirSync21 } = await import("node:fs");
|
|
34496
|
+
const { join: join55, dirname: dirname20 } = await import("node:path");
|
|
34497
|
+
const cachePath = join55(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
|
|
34498
|
+
mkdirSync21(dirname20(cachePath), { recursive: true });
|
|
34499
|
+
writeFileSync19(cachePath, JSON.stringify({
|
|
34500
|
+
peerId,
|
|
34501
|
+
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
34502
|
+
models: models.map((m) => ({ name: m.name, size: m.size, parameterSize: m.parameterSize }))
|
|
34503
|
+
}, null, 2));
|
|
34504
|
+
} catch {
|
|
34505
|
+
}
|
|
34276
34506
|
process.stdout.write(` ${c2.green("\u2714")} Discovered ${models.length} model(s) on peer:
|
|
34277
34507
|
`);
|
|
34278
34508
|
for (const m of models.slice(0, 10)) {
|
package/package.json
CHANGED