open-agents-ai 0.103.69 → 0.103.71
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 +240 -167
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12130,6 +12130,26 @@ const blockedPeers = [];
|
|
|
12130
12130
|
// Both peers connect to wss://demo.nats.io:8443, so NATS request/reply bridges the gap.
|
|
12131
12131
|
var _natsConn = null;
|
|
12132
12132
|
var _natsCodec = null;
|
|
12133
|
+
var _tokensByRequest = {};
|
|
12134
|
+
|
|
12135
|
+
// Check if an error is a connectivity/dial failure (should trigger NATS fallback)
|
|
12136
|
+
// vs an application-level error (auth rejected, capability not found \u2014 no point retrying via NATS)
|
|
12137
|
+
function isDialFailure(errMsg) {
|
|
12138
|
+
var appErrors = ['unauthorized', 'capability not found', 'not registered', 'auth rejected'];
|
|
12139
|
+
var lower = errMsg.toLowerCase();
|
|
12140
|
+
for (var i = 0; i < appErrors.length; i++) {
|
|
12141
|
+
if (lower.includes(appErrors[i])) return false;
|
|
12142
|
+
}
|
|
12143
|
+
// Any network/transport error should fall back to NATS
|
|
12144
|
+
return lower.includes('multiaddrs failed') || lower.includes('econnrefused') ||
|
|
12145
|
+
lower.includes('etimedout') || lower.includes('dial to peer') ||
|
|
12146
|
+
lower.includes('no route') || lower.includes('circuit relay') ||
|
|
12147
|
+
lower.includes('stream was reset') || lower.includes('timeout') ||
|
|
12148
|
+
lower.includes('connection reset') || lower.includes('ehostunreach') ||
|
|
12149
|
+
lower.includes('enetunreach') || lower.includes('peer not reachable') ||
|
|
12150
|
+
lower.includes('dial error') || lower.includes('aborted') ||
|
|
12151
|
+
lower.includes('connection refused');
|
|
12152
|
+
}
|
|
12133
12153
|
|
|
12134
12154
|
function writeStatus(extra = {}) {
|
|
12135
12155
|
const caps = typeof nexus.getRegisteredCapabilities === 'function'
|
|
@@ -12284,43 +12304,34 @@ async function handleCmd(cmd) {
|
|
|
12284
12304
|
var QPC_TIMEOUT = 15000;
|
|
12285
12305
|
var qpcInput = {};
|
|
12286
12306
|
if (args.auth_key) qpcInput.auth_key = args.auth_key;
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
var
|
|
12307
|
+
|
|
12308
|
+
// Race libp2p + NATS in parallel \u2014 fastest route wins
|
|
12309
|
+
var qpcLibp2p = nexus.invokeCapability(String(qpcPeerId), '__list_capabilities', qpcInput, { stream: false, maxDurationMs: 10000 });
|
|
12310
|
+
var qpcTimeout = new Promise(function(_, reject) { setTimeout(function() { reject(new Error('query_peer_caps timed out')); }, QPC_TIMEOUT); });
|
|
12311
|
+
var qpcRace = [qpcLibp2p, qpcTimeout];
|
|
12312
|
+
|
|
12313
|
+
if (_natsConn && _natsCodec) {
|
|
12314
|
+
var _qpcNatsP = (async function() {
|
|
12315
|
+
var _s = 'nexus.invoke.' + String(qpcPeerId);
|
|
12316
|
+
var _p = JSON.stringify({ capability: '__list_capabilities', input: qpcInput, from: nexus.peerId || '' });
|
|
12317
|
+
var _r = await _natsConn.request(_s, _natsCodec.encode(_p), { timeout: 15000 });
|
|
12318
|
+
var _res = JSON.parse(_natsCodec.decode(_r.data));
|
|
12319
|
+
if (_res && _res.error) throw new Error('NATS: ' + _res.error);
|
|
12320
|
+
dlog('query_peer_caps: NATS won the race');
|
|
12321
|
+
return _res;
|
|
12322
|
+
})();
|
|
12323
|
+
qpcRace.push(_qpcNatsP);
|
|
12324
|
+
}
|
|
12325
|
+
|
|
12326
|
+
var qpcResult = await Promise.any(qpcRace.map(function(p) {
|
|
12327
|
+
return p.catch(function(e) { return Promise.reject(e); });
|
|
12328
|
+
}));
|
|
12290
12329
|
dlog('query_peer_caps: SUCCESS');
|
|
12291
12330
|
writeResp(id, { ok: true, output: typeof qpcResult === 'string' ? qpcResult : JSON.stringify(qpcResult, null, 2) });
|
|
12292
12331
|
} catch (qpcErr) {
|
|
12293
|
-
var qpcErrMsg = qpcErr.message || String(qpcErr);
|
|
12294
|
-
dlog('query_peer_caps:
|
|
12295
|
-
|
|
12296
|
-
if (_natsConn && _natsCodec && qpcErrMsg.includes('multiaddrs failed')) {
|
|
12297
|
-
dlog('query_peer_caps: trying NATS relay fallback');
|
|
12298
|
-
try {
|
|
12299
|
-
var _qpcNatsSubject = 'nexus.invoke.' + String(qpcPeerId);
|
|
12300
|
-
var _qpcNatsPayload = JSON.stringify({
|
|
12301
|
-
capability: '__list_capabilities',
|
|
12302
|
-
input: qpcInput,
|
|
12303
|
-
from: nexus.peerId || '',
|
|
12304
|
-
});
|
|
12305
|
-
var _qpcNatsResp = await _natsConn.request(
|
|
12306
|
-
_qpcNatsSubject,
|
|
12307
|
-
_natsCodec.encode(_qpcNatsPayload),
|
|
12308
|
-
{ timeout: 15000 }
|
|
12309
|
-
);
|
|
12310
|
-
var _qpcNatsResult = JSON.parse(_natsCodec.decode(_qpcNatsResp.data));
|
|
12311
|
-
if (_qpcNatsResult && _qpcNatsResult.error) {
|
|
12312
|
-
writeResp(id, { ok: false, output: 'query_peer_caps (NATS): ' + _qpcNatsResult.error });
|
|
12313
|
-
} else {
|
|
12314
|
-
dlog('query_peer_caps: SUCCESS via NATS relay');
|
|
12315
|
-
writeResp(id, { ok: true, output: typeof _qpcNatsResult === 'string' ? _qpcNatsResult : JSON.stringify(_qpcNatsResult, null, 2) });
|
|
12316
|
-
}
|
|
12317
|
-
} catch (_qpcNatsErr) {
|
|
12318
|
-
dlog('query_peer_caps: NATS fallback also failed: ' + (_qpcNatsErr.message || _qpcNatsErr));
|
|
12319
|
-
writeResp(id, { ok: false, output: 'query_peer_caps error (libp2p + NATS): ' + qpcErrMsg });
|
|
12320
|
-
}
|
|
12321
|
-
} else {
|
|
12322
|
-
writeResp(id, { ok: false, output: 'query_peer_caps error: ' + qpcErrMsg });
|
|
12323
|
-
}
|
|
12332
|
+
var qpcErrMsg = qpcErr.errors ? qpcErr.errors.map(function(e) { return e.message || String(e); }).join('; ') : (qpcErr.message || String(qpcErr));
|
|
12333
|
+
dlog('query_peer_caps: ALL paths failed: ' + qpcErrMsg);
|
|
12334
|
+
writeResp(id, { ok: false, output: 'query_peer_caps error: ' + qpcErrMsg });
|
|
12324
12335
|
}
|
|
12325
12336
|
break;
|
|
12326
12337
|
}
|
|
@@ -12331,45 +12342,36 @@ async function handleCmd(cmd) {
|
|
|
12331
12342
|
if (!peerId) { writeResp(id, { ok: false, output: 'target_peer is required' }); return; }
|
|
12332
12343
|
dlog('invoke_capability: peer=' + peerId.slice(0, 20) + ' cap=' + capability);
|
|
12333
12344
|
try {
|
|
12334
|
-
//
|
|
12345
|
+
// Race libp2p + NATS in parallel \u2014 whichever route works first wins
|
|
12335
12346
|
const INVOKE_TIMEOUT = 300_000;
|
|
12336
|
-
const
|
|
12337
|
-
const
|
|
12338
|
-
const
|
|
12347
|
+
const invokeInput = typeof input === 'string' ? { prompt: input } : input;
|
|
12348
|
+
const invokePromise = nexus.invokeCapability(peerId, capability, invokeInput, { stream: false, maxDurationMs: 240000 });
|
|
12349
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('invoke_capability timed out after ' + (INVOKE_TIMEOUT / 1000) + 's')), INVOKE_TIMEOUT));
|
|
12350
|
+
|
|
12351
|
+
var icRaceCandidates = [invokePromise, timeoutPromise];
|
|
12352
|
+
|
|
12353
|
+
if (_natsConn && _natsCodec) {
|
|
12354
|
+
var _icNatsRaceP = (async function() {
|
|
12355
|
+
var _s = 'nexus.invoke.' + peerId;
|
|
12356
|
+
var _p = JSON.stringify({ capability: capability, input: invokeInput, from: nexus.peerId || '' });
|
|
12357
|
+
var _r = await _natsConn.request(_s, _natsCodec.encode(_p), { timeout: 240000 });
|
|
12358
|
+
var _res = JSON.parse(_natsCodec.decode(_r.data));
|
|
12359
|
+
if (_res && _res.error) throw new Error('NATS: ' + _res.error);
|
|
12360
|
+
dlog('invoke_capability: NATS won the race');
|
|
12361
|
+
return _res;
|
|
12362
|
+
})();
|
|
12363
|
+
icRaceCandidates.push(_icNatsRaceP);
|
|
12364
|
+
}
|
|
12365
|
+
|
|
12366
|
+
const result = await Promise.any(icRaceCandidates.map(function(p) {
|
|
12367
|
+
return p.catch(function(e) { return Promise.reject(e); });
|
|
12368
|
+
}));
|
|
12339
12369
|
dlog('invoke_capability: SUCCESS');
|
|
12340
|
-
writeResp(id, { ok: true, output: JSON.stringify(result, null, 2) });
|
|
12370
|
+
writeResp(id, { ok: true, output: typeof result === 'string' ? result : JSON.stringify(result, null, 2) });
|
|
12341
12371
|
} catch (invokeErr) {
|
|
12342
|
-
var invokeErrMsg = invokeErr.message || String(invokeErr);
|
|
12343
|
-
dlog('invoke_capability:
|
|
12344
|
-
|
|
12345
|
-
if (_natsConn && _natsCodec && invokeErrMsg.includes('multiaddrs failed')) {
|
|
12346
|
-
dlog('invoke_capability: trying NATS relay fallback for ' + peerId.slice(0, 20));
|
|
12347
|
-
try {
|
|
12348
|
-
var _icNatsSubject = 'nexus.invoke.' + peerId;
|
|
12349
|
-
var _icNatsPayload = JSON.stringify({
|
|
12350
|
-
capability: capability,
|
|
12351
|
-
input: typeof input === 'string' ? { prompt: input } : input,
|
|
12352
|
-
from: nexus.peerId || '',
|
|
12353
|
-
});
|
|
12354
|
-
var _icNatsResp = await _natsConn.request(
|
|
12355
|
-
_icNatsSubject,
|
|
12356
|
-
_natsCodec.encode(_icNatsPayload),
|
|
12357
|
-
{ timeout: 240000 }
|
|
12358
|
-
);
|
|
12359
|
-
var _icNatsResult = JSON.parse(_natsCodec.decode(_icNatsResp.data));
|
|
12360
|
-
if (_icNatsResult && _icNatsResult.error) {
|
|
12361
|
-
writeResp(id, { ok: false, output: 'NATS relay error: ' + _icNatsResult.error });
|
|
12362
|
-
} else {
|
|
12363
|
-
dlog('invoke_capability: SUCCESS via NATS relay');
|
|
12364
|
-
writeResp(id, { ok: true, output: typeof _icNatsResult === 'string' ? _icNatsResult : JSON.stringify(_icNatsResult, null, 2) });
|
|
12365
|
-
}
|
|
12366
|
-
} catch (_icNatsErr) {
|
|
12367
|
-
dlog('invoke_capability: NATS fallback also failed: ' + (_icNatsErr.message || _icNatsErr));
|
|
12368
|
-
writeResp(id, { ok: false, output: 'Invoke error (libp2p + NATS fallback failed): ' + invokeErrMsg });
|
|
12369
|
-
}
|
|
12370
|
-
} else {
|
|
12371
|
-
writeResp(id, { ok: false, output: 'Invoke error: ' + invokeErrMsg });
|
|
12372
|
-
}
|
|
12372
|
+
var invokeErrMsg = invokeErr.errors ? invokeErr.errors.map(function(e) { return e.message || String(e); }).join('; ') : (invokeErr.message || String(invokeErr));
|
|
12373
|
+
dlog('invoke_capability: ALL paths failed: ' + invokeErrMsg);
|
|
12374
|
+
writeResp(id, { ok: false, output: 'Invoke error: ' + invokeErrMsg });
|
|
12373
12375
|
}
|
|
12374
12376
|
break;
|
|
12375
12377
|
}
|
|
@@ -12409,48 +12411,42 @@ async function handleCmd(cmd) {
|
|
|
12409
12411
|
|
|
12410
12412
|
// If target_peer specified, invoke directly. Otherwise auto-discover.
|
|
12411
12413
|
if (riTargetPeer) {
|
|
12412
|
-
//
|
|
12413
|
-
|
|
12414
|
+
// Race libp2p direct dial and NATS relay IN PARALLEL.
|
|
12415
|
+
// For cross-NAT peers, libp2p dial can take 10-60s to fail while NATS
|
|
12416
|
+
// succeeds in <1s. Racing them eliminates the wait.
|
|
12417
|
+
dlog('remote_infer: invoking ' + riCapName + ' on peer ' + riTargetPeer.slice(0, 20) + ' (libp2p' + (_natsConn ? ' + NATS parallel' : '') + ')');
|
|
12414
12418
|
try {
|
|
12415
|
-
var RI_TIMEOUT = 300000;
|
|
12419
|
+
var RI_TIMEOUT = 300000;
|
|
12416
12420
|
var riInvokeP = nexus.invokeCapability(riTargetPeer, riCapName, riData, { stream: false, maxDurationMs: 240000 });
|
|
12417
12421
|
var riTimeoutP = new Promise(function(_, reject) { setTimeout(function() { reject(new Error('remote_infer timed out after ' + (RI_TIMEOUT / 1000) + 's')); }, RI_TIMEOUT); });
|
|
12418
|
-
|
|
12419
|
-
|
|
12420
|
-
|
|
12421
|
-
|
|
12422
|
-
|
|
12423
|
-
|
|
12424
|
-
|
|
12425
|
-
|
|
12426
|
-
|
|
12427
|
-
var
|
|
12428
|
-
var
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
_riNatsSubject,
|
|
12435
|
-
_natsCodec.encode(_riNatsPayload),
|
|
12436
|
-
{ timeout: 240000 }
|
|
12437
|
-
);
|
|
12438
|
-
var _riNatsResult = JSON.parse(_natsCodec.decode(_riNatsResp.data));
|
|
12439
|
-
if (_riNatsResult && _riNatsResult.error) {
|
|
12440
|
-
writeResp(id, { ok: false, output: 'Remote inference failed (NATS relay): ' + _riNatsResult.error });
|
|
12441
|
-
return;
|
|
12442
|
-
}
|
|
12443
|
-
riResult = _riNatsResult;
|
|
12444
|
-
dlog('remote_infer: SUCCESS via NATS relay');
|
|
12445
|
-
} catch (_riNatsErr) {
|
|
12446
|
-
dlog('remote_infer: NATS fallback also failed: ' + (_riNatsErr.message || _riNatsErr));
|
|
12447
|
-
writeResp(id, { ok: false, output: 'Remote inference failed (libp2p + NATS): ' + riErrMsg });
|
|
12448
|
-
return;
|
|
12449
|
-
}
|
|
12450
|
-
} else {
|
|
12451
|
-
writeResp(id, { ok: false, output: 'Remote inference failed: ' + riErrMsg });
|
|
12452
|
-
return;
|
|
12422
|
+
|
|
12423
|
+
// Build race candidates \u2014 libp2p + timeout always present
|
|
12424
|
+
var riRaceCandidates = [riInvokeP, riTimeoutP];
|
|
12425
|
+
|
|
12426
|
+
// Add NATS as a parallel candidate if available
|
|
12427
|
+
if (_natsConn && _natsCodec) {
|
|
12428
|
+
var _riNatsRaceP = (async function() {
|
|
12429
|
+
var _rSubject = 'nexus.invoke.' + riTargetPeer;
|
|
12430
|
+
var _rPayload = JSON.stringify({ capability: riCapName, input: riData, from: nexus.peerId || '' });
|
|
12431
|
+
var _rResp = await _natsConn.request(_rSubject, _natsCodec.encode(_rPayload), { timeout: 240000 });
|
|
12432
|
+
var _rResult = JSON.parse(_natsCodec.decode(_rResp.data));
|
|
12433
|
+
if (_rResult && _rResult.error) throw new Error('NATS: ' + _rResult.error);
|
|
12434
|
+
dlog('remote_infer: NATS won the race');
|
|
12435
|
+
return _rResult;
|
|
12436
|
+
})();
|
|
12437
|
+
riRaceCandidates.push(_riNatsRaceP);
|
|
12453
12438
|
}
|
|
12439
|
+
|
|
12440
|
+
var riResult = await Promise.any(riRaceCandidates.map(function(p) {
|
|
12441
|
+
return p.catch(function(e) { return Promise.reject(e); });
|
|
12442
|
+
}));
|
|
12443
|
+
dlog('remote_infer: SUCCESS (peer ' + riTargetPeer.slice(0, 20) + ')');
|
|
12444
|
+
} catch (riErr) {
|
|
12445
|
+
// Promise.any throws AggregateError when ALL candidates fail
|
|
12446
|
+
var riErrMsg = riErr.errors ? riErr.errors.map(function(e) { return e.message || String(e); }).join('; ') : (riErr.message || String(riErr));
|
|
12447
|
+
dlog('remote_infer: ALL paths failed: ' + riErrMsg);
|
|
12448
|
+
writeResp(id, { ok: false, output: 'Remote inference failed: ' + riErrMsg });
|
|
12449
|
+
return;
|
|
12454
12450
|
}
|
|
12455
12451
|
} else {
|
|
12456
12452
|
// Auto-discover: try speculative invoke on each 12D3KooW peer
|
|
@@ -12488,6 +12484,36 @@ async function handleCmd(cmd) {
|
|
|
12488
12484
|
}
|
|
12489
12485
|
dlog('remote_infer: auto-discover took ' + (Date.now() - discStart) + 'ms');
|
|
12490
12486
|
|
|
12487
|
+
// If libp2p auto-discover failed, try NATS relay against discovered peers from cache
|
|
12488
|
+
if (!riResult && _natsConn && _natsCodec) {
|
|
12489
|
+
try {
|
|
12490
|
+
var _dpFile = join(nexusDir, 'discovered-peers.json');
|
|
12491
|
+
if (existsSync(_dpFile)) {
|
|
12492
|
+
var _dpData = JSON.parse(readFileSync(_dpFile, 'utf8'));
|
|
12493
|
+
var _dpPeers = Object.keys(_dpData).filter(function(p) { return p.startsWith('12D3KooW'); });
|
|
12494
|
+
dlog('remote_infer: trying NATS relay on ' + _dpPeers.length + ' cached peers');
|
|
12495
|
+
for (var _dpi = 0; _dpi < _dpPeers.length && !riResult; _dpi++) {
|
|
12496
|
+
var _dpPid = _dpPeers[_dpi];
|
|
12497
|
+
try {
|
|
12498
|
+
var _dpSubject = 'nexus.invoke.' + _dpPid;
|
|
12499
|
+
var _dpPayload = JSON.stringify({ capability: riCapName, input: riData, from: nexus.peerId || '' });
|
|
12500
|
+
var _dpResp = await _natsConn.request(_dpSubject, _natsCodec.encode(_dpPayload), { timeout: 180000 });
|
|
12501
|
+
var _dpResult = JSON.parse(_natsCodec.decode(_dpResp.data));
|
|
12502
|
+
if (_dpResult && !_dpResult.error) {
|
|
12503
|
+
riResult = _dpResult;
|
|
12504
|
+
riTargetPeer = _dpPid;
|
|
12505
|
+
dlog('remote_infer: SUCCESS via NATS relay peer ' + _dpPid.slice(0, 20));
|
|
12506
|
+
}
|
|
12507
|
+
} catch (_dpErr) {
|
|
12508
|
+
dlog('remote_infer: NATS peer ' + _dpPid.slice(0, 20) + ' failed: ' + (_dpErr.message || _dpErr));
|
|
12509
|
+
}
|
|
12510
|
+
}
|
|
12511
|
+
}
|
|
12512
|
+
} catch (_dpCacheErr) {
|
|
12513
|
+
dlog('remote_infer: NATS discovery cache error: ' + (_dpCacheErr.message || _dpCacheErr));
|
|
12514
|
+
}
|
|
12515
|
+
}
|
|
12516
|
+
|
|
12491
12517
|
if (!riResult) {
|
|
12492
12518
|
writeResp(id, { ok: false, output: 'No peer found with capability: ' + riCapName + '. Ensure a provider is running expose with model ' + riModel });
|
|
12493
12519
|
return;
|
|
@@ -13100,6 +13126,12 @@ async function handleCmd(cmd) {
|
|
|
13100
13126
|
// Register system_metrics capability \u2014 returns CPU/GPU/memory utilization
|
|
13101
13127
|
if (typeof nexus.registerCapability === 'function') {
|
|
13102
13128
|
nexus.registerCapability('system_metrics', async (request, stream) => {
|
|
13129
|
+
// Stream safety wrapper \u2014 prevents unguarded writes after consumer disconnects
|
|
13130
|
+
var smStreamClosed = false;
|
|
13131
|
+
async function smWrite(msg) {
|
|
13132
|
+
if (smStreamClosed) return;
|
|
13133
|
+
try { await stream.write(msg); } catch { smStreamClosed = true; }
|
|
13134
|
+
}
|
|
13103
13135
|
// Collect input via stream data events (auth_key arrives in invoke.chunk, NOT invoke.open)
|
|
13104
13136
|
var smDataChunks = [];
|
|
13105
13137
|
var smInputDone = false;
|
|
@@ -13113,7 +13145,7 @@ async function handleCmd(cmd) {
|
|
|
13113
13145
|
});
|
|
13114
13146
|
|
|
13115
13147
|
// Accept invocation so consumer sends data
|
|
13116
|
-
await
|
|
13148
|
+
await smWrite({ type: 'invoke.accept', version: 1, requestId: request.requestId, accepted: true });
|
|
13117
13149
|
|
|
13118
13150
|
// Wait briefly for data (auth key arrives in chunk)
|
|
13119
13151
|
var smWait = 0;
|
|
@@ -13138,9 +13170,9 @@ async function handleCmd(cmd) {
|
|
|
13138
13170
|
}
|
|
13139
13171
|
if (smAuthKey !== exposeAuthKey) {
|
|
13140
13172
|
dlog('system_metrics: auth REJECTED from ' + (request.from || 'unknown'));
|
|
13141
|
-
await
|
|
13142
|
-
await
|
|
13143
|
-
stream.close();
|
|
13173
|
+
await smWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'error', data: 'Unauthorized' });
|
|
13174
|
+
await smWrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
|
|
13175
|
+
try { stream.close(); } catch {}
|
|
13144
13176
|
return;
|
|
13145
13177
|
}
|
|
13146
13178
|
dlog('system_metrics: auth OK');
|
|
@@ -13175,13 +13207,13 @@ async function handleCmd(cmd) {
|
|
|
13175
13207
|
gpu: gpuInfo,
|
|
13176
13208
|
timestamp: new Date().toISOString(),
|
|
13177
13209
|
};
|
|
13178
|
-
await
|
|
13179
|
-
await
|
|
13210
|
+
await smWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'result', data: JSON.stringify(metricsPayload) });
|
|
13211
|
+
await smWrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: JSON.stringify(metricsPayload).length } });
|
|
13180
13212
|
} catch (me) {
|
|
13181
|
-
await
|
|
13182
|
-
await
|
|
13213
|
+
await smWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'error', data: 'metrics error: ' + me.message });
|
|
13214
|
+
await smWrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
|
|
13183
13215
|
}
|
|
13184
|
-
stream.close();
|
|
13216
|
+
try { stream.close(); } catch {}
|
|
13185
13217
|
});
|
|
13186
13218
|
dlog('system_metrics capability registered');
|
|
13187
13219
|
}
|
|
@@ -13380,7 +13412,6 @@ process.on('unhandledRejection', (reason) => {
|
|
|
13380
13412
|
// The nexus library fires this hook AFTER handler returns, so it has the correct
|
|
13381
13413
|
// peerId from connection context. We stash token data per requestId so the hook
|
|
13382
13414
|
// can merge them into one complete record written to metering.jsonl.
|
|
13383
|
-
var _tokensByRequest = {};
|
|
13384
13415
|
try {
|
|
13385
13416
|
if (nexus.metering && typeof nexus.metering.addHook === 'function') {
|
|
13386
13417
|
nexus.metering.addHook(function(record) {
|
|
@@ -13532,25 +13563,39 @@ process.on('unhandledRejection', (reason) => {
|
|
|
13532
13563
|
continue;
|
|
13533
13564
|
}
|
|
13534
13565
|
|
|
13535
|
-
// Create mock stream handle that captures the handler's output
|
|
13566
|
+
// Create mock stream handle that captures the handler's output.
|
|
13567
|
+
// Uses retroactive delivery: if handler registers onData after data is
|
|
13568
|
+
// already queued, deliver immediately. Eliminates timing race.
|
|
13536
13569
|
var _nResults = [];
|
|
13537
|
-
var
|
|
13570
|
+
var _nDataCbs = [];
|
|
13571
|
+
var _nDataDelivered = false;
|
|
13538
13572
|
var _nHandle = {
|
|
13539
13573
|
write: async function(msg) {
|
|
13540
13574
|
if (msg && msg.type === 'invoke.event') _nResults.push(msg);
|
|
13541
|
-
if (msg && msg.type === 'invoke.done') _nHandleDone = true;
|
|
13542
13575
|
},
|
|
13543
13576
|
onData: function(cb) {
|
|
13544
|
-
|
|
13545
|
-
|
|
13577
|
+
if (_nDataDelivered) {
|
|
13578
|
+
// Data already flushed \u2014 deliver retroactively
|
|
13546
13579
|
try {
|
|
13547
13580
|
cb({ type: 'invoke.chunk', data: _nInputStr, seq: 0 });
|
|
13548
13581
|
cb({ type: 'invoke.done' });
|
|
13549
13582
|
} catch {}
|
|
13550
|
-
}
|
|
13583
|
+
} else {
|
|
13584
|
+
_nDataCbs.push(cb);
|
|
13585
|
+
}
|
|
13551
13586
|
},
|
|
13552
13587
|
close: function() {},
|
|
13553
13588
|
};
|
|
13589
|
+
// Flush input data to any registered onData listeners after 50ms
|
|
13590
|
+
setTimeout(function() {
|
|
13591
|
+
_nDataDelivered = true;
|
|
13592
|
+
for (var _di = 0; _di < _nDataCbs.length; _di++) {
|
|
13593
|
+
try {
|
|
13594
|
+
_nDataCbs[_di]({ type: 'invoke.chunk', data: _nInputStr, seq: 0 });
|
|
13595
|
+
_nDataCbs[_di]({ type: 'invoke.done' });
|
|
13596
|
+
} catch {}
|
|
13597
|
+
}
|
|
13598
|
+
}, 50);
|
|
13554
13599
|
|
|
13555
13600
|
var _nRequest = {
|
|
13556
13601
|
type: 'invoke.open',
|
|
@@ -13803,7 +13848,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
13803
13848
|
result = await this.sendDaemonCmd("query_peer_caps", args, 2e4);
|
|
13804
13849
|
break;
|
|
13805
13850
|
case "invoke_capability":
|
|
13806
|
-
result = await this.sendDaemonCmd("invoke_capability", args,
|
|
13851
|
+
result = await this.sendDaemonCmd("invoke_capability", args, 32e4);
|
|
13807
13852
|
break;
|
|
13808
13853
|
case "store_content":
|
|
13809
13854
|
result = await this.sendDaemonCmd("store_content", args);
|
|
@@ -14899,7 +14944,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
14899
14944
|
} else {
|
|
14900
14945
|
daemonArgs.prompt = prompt;
|
|
14901
14946
|
}
|
|
14902
|
-
const result = await this.sendDaemonCmd("remote_infer", daemonArgs,
|
|
14947
|
+
const result = await this.sendDaemonCmd("remote_infer", daemonArgs, 32e4);
|
|
14903
14948
|
let peerUsed = args.target_peer || "auto-selected";
|
|
14904
14949
|
try {
|
|
14905
14950
|
const parsed = JSON.parse(result);
|
|
@@ -35530,12 +35575,6 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
35530
35575
|
process.stdout.write("\n");
|
|
35531
35576
|
const checkSpinner = startInlineSpinner(`Checking for updates ${c2.dim(`(current: v${currentVersion})`)}`);
|
|
35532
35577
|
const info = await checkForUpdate(currentVersion, true);
|
|
35533
|
-
if (!info) {
|
|
35534
|
-
checkSpinner.stop(`You're on the latest version (v${currentVersion}).`);
|
|
35535
|
-
process.stdout.write("\n");
|
|
35536
|
-
return;
|
|
35537
|
-
}
|
|
35538
|
-
checkSpinner.stop(`Update available: v${info.currentVersion} \u2192 v${c2.bold(c2.green(info.latestVersion))}`);
|
|
35539
35578
|
const { exec: exec3, execSync: es2 } = await import("node:child_process");
|
|
35540
35579
|
let needsSudo = false;
|
|
35541
35580
|
try {
|
|
@@ -35548,21 +35587,6 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
35548
35587
|
}
|
|
35549
35588
|
} catch {
|
|
35550
35589
|
}
|
|
35551
|
-
if (needsSudo) {
|
|
35552
|
-
renderInfo("Global npm directory requires elevated permissions.");
|
|
35553
|
-
renderInfo("You'll be asked for your password once \u2014 it covers all update steps.");
|
|
35554
|
-
process.stdout.write("\n");
|
|
35555
|
-
try {
|
|
35556
|
-
es2("sudo -v", { stdio: "inherit", timeout: 6e4 });
|
|
35557
|
-
} catch {
|
|
35558
|
-
renderWarning("Could not acquire sudo credentials. Try: sudo npm i -g open-agents-ai");
|
|
35559
|
-
return;
|
|
35560
|
-
}
|
|
35561
|
-
}
|
|
35562
|
-
const sudoPrefix = needsSudo ? "sudo " : "";
|
|
35563
|
-
const installSpinner = startInlineSpinner("Installing update");
|
|
35564
|
-
const installCmd = `${sudoPrefix}npm install -g open-agents-ai@latest --prefer-online`;
|
|
35565
|
-
let installOk = false;
|
|
35566
35590
|
let installError = "";
|
|
35567
35591
|
const runInstall2 = (cmd) => new Promise((resolve31) => {
|
|
35568
35592
|
const child = exec3(cmd, { timeout: 18e4 }, (err, _stdout, stderr) => {
|
|
@@ -35572,35 +35596,84 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
35572
35596
|
});
|
|
35573
35597
|
child.stdout?.resume();
|
|
35574
35598
|
});
|
|
35575
|
-
|
|
35576
|
-
|
|
35577
|
-
|
|
35599
|
+
if (needsSudo) {
|
|
35600
|
+
renderInfo("Global npm directory requires elevated permissions.");
|
|
35601
|
+
renderInfo("You'll be asked for your password once \u2014 it covers all update steps.");
|
|
35602
|
+
process.stdout.write("\n");
|
|
35578
35603
|
try {
|
|
35579
|
-
|
|
35580
|
-
const globalModules = prefix.endsWith("/lib") ? prefix + "/node_modules" : prefix + "/lib/node_modules";
|
|
35581
|
-
es2(`${sudoPrefix}find "${globalModules}" -maxdepth 1 -name ".open-agents-ai-*" -type d -exec rm -rf {} + 2>/dev/null || true`, { timeout: 15e3 });
|
|
35582
|
-
es2(`${sudoPrefix}rm -rf "${globalModules}/open-agents-ai" 2>/dev/null || true`, { timeout: 15e3 });
|
|
35604
|
+
es2("sudo -v", { stdio: "inherit", timeout: 6e4 });
|
|
35583
35605
|
} catch {
|
|
35606
|
+
renderWarning("Could not acquire sudo credentials. Try: sudo npm i -g open-agents-ai");
|
|
35607
|
+
return;
|
|
35584
35608
|
}
|
|
35585
|
-
|
|
35586
|
-
|
|
35609
|
+
}
|
|
35610
|
+
const sudoPrefix = needsSudo ? "sudo " : "";
|
|
35611
|
+
let primaryUpdated = false;
|
|
35612
|
+
if (!info) {
|
|
35613
|
+
checkSpinner.stop(`Primary package up to date (v${currentVersion}).`);
|
|
35614
|
+
} else {
|
|
35615
|
+
checkSpinner.stop(`Update available: v${info.currentVersion} \u2192 v${c2.bold(c2.green(info.latestVersion))}`);
|
|
35616
|
+
const installSpinner = startInlineSpinner("Installing update");
|
|
35617
|
+
const installCmd = `${sudoPrefix}npm install -g open-agents-ai@latest --prefer-online`;
|
|
35618
|
+
let installOk = false;
|
|
35587
35619
|
installOk = await runInstall2(installCmd);
|
|
35620
|
+
if (!installOk && /ENOTEMPTY|errno -39/i.test(installError)) {
|
|
35621
|
+
installSpinner.stop("Cleaning stale npm temp files...");
|
|
35622
|
+
try {
|
|
35623
|
+
const prefix = es2("npm prefix -g", { encoding: "utf8", timeout: 5e3 }).trim();
|
|
35624
|
+
const globalModules = prefix.endsWith("/lib") ? prefix + "/node_modules" : prefix + "/lib/node_modules";
|
|
35625
|
+
es2(`${sudoPrefix}find "${globalModules}" -maxdepth 1 -name ".open-agents-ai-*" -type d -exec rm -rf {} + 2>/dev/null || true`, { timeout: 15e3 });
|
|
35626
|
+
es2(`${sudoPrefix}rm -rf "${globalModules}/open-agents-ai" 2>/dev/null || true`, { timeout: 15e3 });
|
|
35627
|
+
} catch {
|
|
35628
|
+
}
|
|
35629
|
+
const retrySpinner = startInlineSpinner("Retrying install");
|
|
35630
|
+
installError = "";
|
|
35631
|
+
installOk = await runInstall2(installCmd);
|
|
35632
|
+
if (!installOk) {
|
|
35633
|
+
retrySpinner.stop("Retry failed.");
|
|
35634
|
+
} else {
|
|
35635
|
+
retrySpinner.stop(`Update installed (v${info.latestVersion}).`);
|
|
35636
|
+
}
|
|
35637
|
+
}
|
|
35588
35638
|
if (!installOk) {
|
|
35589
|
-
|
|
35590
|
-
|
|
35591
|
-
|
|
35639
|
+
installSpinner.stop("Update install failed.");
|
|
35640
|
+
const errPreview = installError.split("\n").filter((l) => l.trim()).slice(-3).join("\n ");
|
|
35641
|
+
if (errPreview)
|
|
35642
|
+
renderWarning(`Error:
|
|
35643
|
+
${errPreview}`);
|
|
35644
|
+
renderWarning(`Try manually: ${sudoPrefix}npm i -g open-agents-ai`);
|
|
35645
|
+
return;
|
|
35592
35646
|
}
|
|
35647
|
+
installSpinner.stop(`Update installed (v${info.latestVersion}).`);
|
|
35648
|
+
primaryUpdated = true;
|
|
35593
35649
|
}
|
|
35594
|
-
|
|
35595
|
-
|
|
35596
|
-
|
|
35597
|
-
|
|
35598
|
-
|
|
35599
|
-
|
|
35600
|
-
|
|
35650
|
+
const depsSpinner = startInlineSpinner("Checking subordinate dependencies");
|
|
35651
|
+
let depsUpdated = false;
|
|
35652
|
+
try {
|
|
35653
|
+
const prefix = es2("npm prefix -g", { encoding: "utf8", timeout: 5e3 }).trim();
|
|
35654
|
+
const globalModules = prefix.endsWith("/lib") ? prefix + "/node_modules" : prefix + "/lib/node_modules";
|
|
35655
|
+
const { existsSync: fe, readFileSync: rf } = await import("node:fs");
|
|
35656
|
+
const { join: pj } = await import("node:path");
|
|
35657
|
+
const pkgPath = pj(globalModules, "open-agents-ai", "package.json");
|
|
35658
|
+
if (fe(pkgPath)) {
|
|
35659
|
+
const pkg = JSON.parse(rf(pkgPath, "utf8"));
|
|
35660
|
+
const allDeps = { ...pkg.dependencies || {}, ...pkg.optionalDependencies || {} };
|
|
35661
|
+
const depNames = Object.keys(allDeps);
|
|
35662
|
+
if (depNames.length > 0) {
|
|
35663
|
+
const updateCmd = `${sudoPrefix}npm update --prefer-online --prefix "${pj(globalModules, "open-agents-ai")}" 2>/dev/null || true`;
|
|
35664
|
+
const updateOk = await runInstall2(updateCmd);
|
|
35665
|
+
if (updateOk)
|
|
35666
|
+
depsUpdated = true;
|
|
35667
|
+
}
|
|
35668
|
+
}
|
|
35669
|
+
} catch {
|
|
35670
|
+
}
|
|
35671
|
+
depsSpinner.stop(depsUpdated ? "Dependencies updated to latest." : "Dependencies checked.");
|
|
35672
|
+
if (!primaryUpdated && !depsUpdated) {
|
|
35673
|
+
renderInfo("Everything is up to date \u2014 no changes needed.");
|
|
35674
|
+
process.stdout.write("\n");
|
|
35601
35675
|
return;
|
|
35602
35676
|
}
|
|
35603
|
-
installSpinner.stop(`Update installed (v${info.latestVersion}).`);
|
|
35604
35677
|
const rebuildSpinner = startInlineSpinner("Rebuilding native modules");
|
|
35605
35678
|
const rebuildOk = await new Promise((resolve31) => {
|
|
35606
35679
|
const child = exec3(`${sudoPrefix}npm rebuild -g open-agents-ai 2>/dev/null || true`, { timeout: 12e4 }, () => resolve31(true));
|
package/package.json
CHANGED