open-agents-ai 0.186.13 → 0.186.14
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 +180 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7270,6 +7270,179 @@ async function handleCmd(cmd) {
|
|
|
7270
7270
|
writeResp(id, { ok: true, output: 'pong' });
|
|
7271
7271
|
break;
|
|
7272
7272
|
}
|
|
7273
|
+
|
|
7274
|
+
// \u2500\u2500 NKN Backup Comms Layer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
7275
|
+
// Persistent NKN addresses for fallback agent-to-agent communication.
|
|
7276
|
+
// Each OA instance gets a deterministic NKN address derived from the
|
|
7277
|
+
// mnemonic agent name. Messages are signed with HMAC to verify the
|
|
7278
|
+
// AGENT sent them (not a human spoofing).
|
|
7279
|
+
|
|
7280
|
+
case 'nkn_status': {
|
|
7281
|
+
var _nknIdFile = join(nexusDir, 'nkn-identity.json');
|
|
7282
|
+
var _nknPeersFile = join(nexusDir, 'nkn-peers.json');
|
|
7283
|
+
var _nknId = existsSync(_nknIdFile) ? JSON.parse(readFileSync(_nknIdFile, 'utf8')) : null;
|
|
7284
|
+
var _nknPeers = existsSync(_nknPeersFile) ? JSON.parse(readFileSync(_nknPeersFile, 'utf8')) : { peers: [] };
|
|
7285
|
+
var _nknConnected = nexus.nkn && nexus.nkn.isConnected;
|
|
7286
|
+
writeResp(id, { ok: true, output: JSON.stringify({
|
|
7287
|
+
enabled: !!nexus.nkn,
|
|
7288
|
+
connected: _nknConnected,
|
|
7289
|
+
address: _nknId ? _nknId.address : (nexus.nkn ? nexus.nkn.address : null),
|
|
7290
|
+
publicKey: _nknId ? _nknId.publicKey : null,
|
|
7291
|
+
peerCount: _nknPeers.peers ? _nknPeers.peers.length : 0,
|
|
7292
|
+
libp2pPeerId: nexus.peerId || null,
|
|
7293
|
+
agentName: agentName,
|
|
7294
|
+
}) });
|
|
7295
|
+
break;
|
|
7296
|
+
}
|
|
7297
|
+
|
|
7298
|
+
case 'nkn_peers': {
|
|
7299
|
+
// List all known NKN peer addresses (agents we've discovered)
|
|
7300
|
+
var _npFile = join(nexusDir, 'nkn-peers.json');
|
|
7301
|
+
var _npData = existsSync(_npFile) ? JSON.parse(readFileSync(_npFile, 'utf8')) : { peers: [] };
|
|
7302
|
+
writeResp(id, { ok: true, output: JSON.stringify(_npData) });
|
|
7303
|
+
break;
|
|
7304
|
+
}
|
|
7305
|
+
|
|
7306
|
+
case 'nkn_inbox': {
|
|
7307
|
+
// Read NKN inbox messages (most recent first, capped)
|
|
7308
|
+
var _niDir = join(inboxDir, '_nkn');
|
|
7309
|
+
var _niMessages = [];
|
|
7310
|
+
try {
|
|
7311
|
+
if (existsSync(_niDir)) {
|
|
7312
|
+
var _niFiles = readdirSync(_niDir).filter(f => f.endsWith('.json')).sort().reverse().slice(0, 50);
|
|
7313
|
+
for (var _niF of _niFiles) {
|
|
7314
|
+
try { _niMessages.push(JSON.parse(readFileSync(join(_niDir, _niF), 'utf8'))); } catch {}
|
|
7315
|
+
}
|
|
7316
|
+
}
|
|
7317
|
+
} catch {}
|
|
7318
|
+
writeResp(id, { ok: true, output: JSON.stringify({ messages: _niMessages, count: _niMessages.length }) });
|
|
7319
|
+
break;
|
|
7320
|
+
}
|
|
7321
|
+
|
|
7322
|
+
case 'nkn_send': {
|
|
7323
|
+
// Send a DM to another agent via NKN
|
|
7324
|
+
// args: { to: "nkn-address", message: "text", verify: true }
|
|
7325
|
+
var _nsTo = args.to || args.address;
|
|
7326
|
+
var _nsMsg = args.message || args.content || '';
|
|
7327
|
+
if (!_nsTo || !_nsMsg) {
|
|
7328
|
+
writeResp(id, { ok: false, output: 'Required: to (NKN address) and message' });
|
|
7329
|
+
break;
|
|
7330
|
+
}
|
|
7331
|
+
// Lazy NKN init
|
|
7332
|
+
if (!nexus.nkn || !nexus.nkn.isConnected) {
|
|
7333
|
+
try {
|
|
7334
|
+
// Load or generate NKN seed from global identity
|
|
7335
|
+
var _nsSeedFile = join(nexusDir, 'nkn-seed.hex');
|
|
7336
|
+
var _nsSeed = undefined;
|
|
7337
|
+
if (existsSync(_nsSeedFile)) {
|
|
7338
|
+
_nsSeed = readFileSync(_nsSeedFile, 'utf8').trim();
|
|
7339
|
+
} else {
|
|
7340
|
+
// Derive NKN seed from agent name + identity key (deterministic)
|
|
7341
|
+
var _nsKeyData = existsSync(keyPath) ? readFileSync(keyPath) : Buffer.from(agentName);
|
|
7342
|
+
_nsSeed = createHash('sha256').update(_nsKeyData).update('nkn-seed-v1').digest('hex');
|
|
7343
|
+
writeFileSync(_nsSeedFile, _nsSeed, { mode: 0o600 });
|
|
7344
|
+
}
|
|
7345
|
+
// Connect NKN via nexus client if available
|
|
7346
|
+
if (nexus.nkn && typeof nexus.nkn.connect === 'function') {
|
|
7347
|
+
await nexus.nkn.connect(_nsSeed);
|
|
7348
|
+
} else {
|
|
7349
|
+
// Direct NKN init if nexus client doesn't expose nkn
|
|
7350
|
+
var nknSdk = await import('nkn-sdk');
|
|
7351
|
+
var _nknMC = new nknSdk.default.MultiClient({ seed: _nsSeed, identifier: 'oa-' + agentName.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 20), numSubClients: 3 });
|
|
7352
|
+
await new Promise(function(resolve, reject) {
|
|
7353
|
+
_nknMC.onConnect(resolve);
|
|
7354
|
+
setTimeout(function() { reject(new Error('NKN connect timeout (15s)')); }, 15000);
|
|
7355
|
+
});
|
|
7356
|
+
// Store address
|
|
7357
|
+
var _nsIdFile = join(nexusDir, 'nkn-identity.json');
|
|
7358
|
+
writeFileSync(_nsIdFile, JSON.stringify({
|
|
7359
|
+
address: _nknMC.addr,
|
|
7360
|
+
publicKey: _nknMC.getPublicKey(),
|
|
7361
|
+
agentName: agentName,
|
|
7362
|
+
libp2pPeerId: nexus.peerId || null,
|
|
7363
|
+
createdAt: new Date().toISOString(),
|
|
7364
|
+
}, null, 2), { mode: 0o600 });
|
|
7365
|
+
dlog('NKN connected: ' + _nknMC.addr);
|
|
7366
|
+
// Receive handler \u2014 store in inbox
|
|
7367
|
+
_nknMC.onMessage(function({ src, payload }) {
|
|
7368
|
+
var _body = typeof payload === 'string' ? payload : new TextDecoder().decode(payload);
|
|
7369
|
+
var _niDir2 = join(inboxDir, '_nkn');
|
|
7370
|
+
mkdirSync(_niDir2, { recursive: true });
|
|
7371
|
+
var _entry = { sender: src, raw: _body, receivedAt: Date.now(), verified: false };
|
|
7372
|
+
// Verify HMAC if present
|
|
7373
|
+
try {
|
|
7374
|
+
var _parsed = JSON.parse(_body);
|
|
7375
|
+
if (_parsed._hmac && _parsed._agentName && _parsed.content) {
|
|
7376
|
+
// Verify: HMAC(agentName + content + timestamp, shared_secret)
|
|
7377
|
+
var _sharedSecret = createHash('sha256').update(src).update(_nknMC.addr).update('oa-nkn-v1').digest('hex');
|
|
7378
|
+
var _expectedHmac = createHmac('sha256', _sharedSecret).update(_parsed._agentName + _parsed.content + String(_parsed.timestamp || 0)).digest('hex').slice(0, 16);
|
|
7379
|
+
_entry.verified = (_parsed._hmac === _expectedHmac);
|
|
7380
|
+
_entry.agentName = _parsed._agentName;
|
|
7381
|
+
_entry.content = _parsed.content;
|
|
7382
|
+
_entry.timestamp = _parsed.timestamp;
|
|
7383
|
+
}
|
|
7384
|
+
} catch { /* raw text message \u2014 not verified */ }
|
|
7385
|
+
try { writeFileSync(join(_niDir2, Date.now() + '.json'), JSON.stringify(_entry, null, 2)); } catch {}
|
|
7386
|
+
});
|
|
7387
|
+
// Stash the client for reuse
|
|
7388
|
+
nexus._nknDirect = _nknMC;
|
|
7389
|
+
}
|
|
7390
|
+
} catch (nknErr) {
|
|
7391
|
+
writeResp(id, { ok: false, output: 'NKN connect failed: ' + (nknErr.message || nknErr) });
|
|
7392
|
+
break;
|
|
7393
|
+
}
|
|
7394
|
+
}
|
|
7395
|
+
// Build verified message with HMAC
|
|
7396
|
+
var _nsClient = nexus._nknDirect || (nexus.nkn && nexus.nkn.client);
|
|
7397
|
+
if (!_nsClient) { writeResp(id, { ok: false, output: 'NKN not connected' }); break; }
|
|
7398
|
+
var _nsMyAddr = _nsClient.addr || (nexus.nkn ? nexus.nkn.address : '');
|
|
7399
|
+
var _nsTimestamp = Date.now();
|
|
7400
|
+
var _nsSharedSecret = createHash('sha256').update(_nsMyAddr).update(_nsTo).update('oa-nkn-v1').digest('hex');
|
|
7401
|
+
var _nsHmac = createHmac('sha256', _nsSharedSecret).update(agentName + _nsMsg + String(_nsTimestamp)).digest('hex').slice(0, 16);
|
|
7402
|
+
var _nsEnvelope = JSON.stringify({
|
|
7403
|
+
_agentName: agentName,
|
|
7404
|
+
content: _nsMsg,
|
|
7405
|
+
timestamp: _nsTimestamp,
|
|
7406
|
+
libp2pPeerId: nexus.peerId || null,
|
|
7407
|
+
_hmac: _nsHmac,
|
|
7408
|
+
});
|
|
7409
|
+
try {
|
|
7410
|
+
await _nsClient.send(_nsTo, _nsEnvelope, { msgHoldingSeconds: 3600 });
|
|
7411
|
+
// Add to peer list if not already there
|
|
7412
|
+
var _nsPeersFile = join(nexusDir, 'nkn-peers.json');
|
|
7413
|
+
var _nsPeers = existsSync(_nsPeersFile) ? JSON.parse(readFileSync(_nsPeersFile, 'utf8')) : { peers: [] };
|
|
7414
|
+
if (!_nsPeers.peers.find(function(p) { return p.nknAddress === _nsTo; })) {
|
|
7415
|
+
_nsPeers.peers.push({ nknAddress: _nsTo, lastContact: _nsTimestamp, agentName: args.to_agent || 'unknown' });
|
|
7416
|
+
writeFileSync(_nsPeersFile, JSON.stringify(_nsPeers, null, 2));
|
|
7417
|
+
}
|
|
7418
|
+
writeResp(id, { ok: true, output: 'Sent to ' + _nsTo + ' (HMAC verified, held 1h if offline)' });
|
|
7419
|
+
} catch (sendErr) {
|
|
7420
|
+
writeResp(id, { ok: false, output: 'NKN send failed: ' + (sendErr.message || sendErr) });
|
|
7421
|
+
}
|
|
7422
|
+
break;
|
|
7423
|
+
}
|
|
7424
|
+
|
|
7425
|
+
case 'nkn_add_peer': {
|
|
7426
|
+
// Manually add a peer's NKN address to the address book
|
|
7427
|
+
var _napAddr = args.nkn_address || args.address;
|
|
7428
|
+
var _napName = args.agent_name || args.name || 'unknown';
|
|
7429
|
+
var _napPeerId = args.libp2p_peer_id || args.peer_id || '';
|
|
7430
|
+
if (!_napAddr) { writeResp(id, { ok: false, output: 'Required: nkn_address' }); break; }
|
|
7431
|
+
var _napFile = join(nexusDir, 'nkn-peers.json');
|
|
7432
|
+
var _napData = existsSync(_napFile) ? JSON.parse(readFileSync(_napFile, 'utf8')) : { peers: [] };
|
|
7433
|
+
var _napExisting = _napData.peers.findIndex(function(p) { return p.nknAddress === _napAddr; });
|
|
7434
|
+
if (_napExisting >= 0) {
|
|
7435
|
+
_napData.peers[_napExisting].agentName = _napName;
|
|
7436
|
+
_napData.peers[_napExisting].libp2pPeerId = _napPeerId || _napData.peers[_napExisting].libp2pPeerId;
|
|
7437
|
+
_napData.peers[_napExisting].lastContact = Date.now();
|
|
7438
|
+
} else {
|
|
7439
|
+
_napData.peers.push({ nknAddress: _napAddr, agentName: _napName, libp2pPeerId: _napPeerId, addedAt: Date.now(), lastContact: Date.now() });
|
|
7440
|
+
}
|
|
7441
|
+
writeFileSync(_napFile, JSON.stringify(_napData, null, 2));
|
|
7442
|
+
writeResp(id, { ok: true, output: 'Added peer: ' + _napName + ' (' + _napAddr.slice(0, 30) + '...)' });
|
|
7443
|
+
break;
|
|
7444
|
+
}
|
|
7445
|
+
|
|
7273
7446
|
default:
|
|
7274
7447
|
writeResp(id, { ok: false, output: 'Unknown daemon command: ' + action });
|
|
7275
7448
|
}
|
|
@@ -8218,9 +8391,14 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
8218
8391
|
"ipfs_add",
|
|
8219
8392
|
"ipfs_pin",
|
|
8220
8393
|
"ipfs_ls",
|
|
8221
|
-
"cohere_publish_insight"
|
|
8394
|
+
"cohere_publish_insight",
|
|
8395
|
+
"nkn_status",
|
|
8396
|
+
"nkn_peers",
|
|
8397
|
+
"nkn_inbox",
|
|
8398
|
+
"nkn_send",
|
|
8399
|
+
"nkn_add_peer"
|
|
8222
8400
|
],
|
|
8223
|
-
description: "The nexus action. MUST call 'connect' first (spawns daemon). Then: join_room, send_message, discover_peers, expose, status,
|
|
8401
|
+
description: "The nexus action. MUST call 'connect' first (spawns daemon). Then: join_room, send_message, discover_peers, expose, status, nkn_status (NKN backup comms), nkn_peers (address book), nkn_inbox (read messages), nkn_send (DM via NKN with HMAC verification), nkn_add_peer (add to address book), cohere_stats, ipfs_add, etc."
|
|
8224
8402
|
},
|
|
8225
8403
|
room_id: {
|
|
8226
8404
|
type: "string",
|
package/package.json
CHANGED