open-agents-ai 0.103.44 → 0.103.46
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 +67 -53
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12601,6 +12601,18 @@ async function handleCmd(cmd) {
|
|
|
12601
12601
|
|
|
12602
12602
|
// \u2500\u2500 Metered Inference Exposure \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
|
|
12603
12603
|
case 'expose': {
|
|
12604
|
+
// Clear old inference capabilities before registering new ones
|
|
12605
|
+
// (prevents stale local Ollama models when switching to passthrough, or vice versa)
|
|
12606
|
+
if (typeof nexus.getRegisteredCapabilities === 'function' && typeof nexus.unregisterCapability === 'function') {
|
|
12607
|
+
var oldCaps = nexus.getRegisteredCapabilities();
|
|
12608
|
+
for (var oci = 0; oci < oldCaps.length; oci++) {
|
|
12609
|
+
if (oldCaps[oci].startsWith('inference:') || oldCaps[oci] === 'system_metrics' || oldCaps[oci] === '__list_capabilities') {
|
|
12610
|
+
try { nexus.unregisterCapability(oldCaps[oci]); } catch {}
|
|
12611
|
+
}
|
|
12612
|
+
}
|
|
12613
|
+
dlog('expose: cleared ' + oldCaps.length + ' old capabilities');
|
|
12614
|
+
}
|
|
12615
|
+
|
|
12604
12616
|
// Auth key for gating inference access (passed from ExposeP2PGateway)
|
|
12605
12617
|
var exposeAuthKey = args.auth_key || '';
|
|
12606
12618
|
if (exposeAuthKey) {
|
|
@@ -13629,23 +13641,56 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
13629
13641
|
// =========================================================================
|
|
13630
13642
|
async doConnect(args) {
|
|
13631
13643
|
await this.ensureDir();
|
|
13644
|
+
const currentScriptHash = createHash("sha256").update(DAEMON_SCRIPT).digest("hex").slice(0, 16);
|
|
13632
13645
|
const existingPid = this.getDaemonPid();
|
|
13633
13646
|
if (existingPid) {
|
|
13634
|
-
const
|
|
13635
|
-
|
|
13647
|
+
const daemonPath2 = join30(this.nexusDir, "nexus-daemon.mjs");
|
|
13648
|
+
let needsRestart = true;
|
|
13649
|
+
if (existsSync23(daemonPath2)) {
|
|
13636
13650
|
try {
|
|
13637
|
-
const
|
|
13638
|
-
|
|
13639
|
-
|
|
13651
|
+
const onDisk = readFileSync16(daemonPath2, "utf8");
|
|
13652
|
+
const diskHash = createHash("sha256").update(onDisk).digest("hex").slice(0, 16);
|
|
13653
|
+
if (diskHash === currentScriptHash) {
|
|
13654
|
+
needsRestart = false;
|
|
13640
13655
|
}
|
|
13641
13656
|
} catch {
|
|
13642
13657
|
}
|
|
13643
13658
|
}
|
|
13644
|
-
|
|
13645
|
-
|
|
13646
|
-
|
|
13659
|
+
if (needsRestart) {
|
|
13660
|
+
try {
|
|
13661
|
+
process.kill(existingPid, "SIGTERM");
|
|
13662
|
+
} catch {
|
|
13663
|
+
}
|
|
13664
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
13665
|
+
try {
|
|
13666
|
+
process.kill(existingPid, 0);
|
|
13667
|
+
process.kill(existingPid, "SIGKILL");
|
|
13668
|
+
} catch {
|
|
13669
|
+
}
|
|
13670
|
+
for (const f of ["daemon.pid", "status.json", "cmd.json", "resp.json"]) {
|
|
13671
|
+
const p = join30(this.nexusDir, f);
|
|
13672
|
+
if (existsSync23(p))
|
|
13673
|
+
await unlink(p).catch(() => {
|
|
13674
|
+
});
|
|
13675
|
+
}
|
|
13676
|
+
} else {
|
|
13677
|
+
const statusFile2 = join30(this.nexusDir, "status.json");
|
|
13678
|
+
if (existsSync23(statusFile2)) {
|
|
13679
|
+
try {
|
|
13680
|
+
const status = JSON.parse(await readFile13(statusFile2, "utf8"));
|
|
13681
|
+
if (status.connected && status.peerId) {
|
|
13682
|
+
await this.ensureWallet();
|
|
13683
|
+
return `Already connected (pid: ${existingPid}, peerId: ${status.peerId})`;
|
|
13684
|
+
}
|
|
13685
|
+
} catch {
|
|
13686
|
+
}
|
|
13687
|
+
}
|
|
13688
|
+
try {
|
|
13689
|
+
process.kill(existingPid, "SIGTERM");
|
|
13690
|
+
} catch {
|
|
13691
|
+
}
|
|
13692
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
13647
13693
|
}
|
|
13648
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
13649
13694
|
}
|
|
13650
13695
|
for (const f of ["daemon.pid", "status.json", "cmd.json", "resp.json"]) {
|
|
13651
13696
|
const p = join30(this.nexusDir, f);
|
|
@@ -28492,7 +28537,7 @@ ${this.formatConnectionInfo()}`);
|
|
|
28492
28537
|
}
|
|
28493
28538
|
};
|
|
28494
28539
|
P2P_STATE_FILE_NAME = "expose-p2p-state.json";
|
|
28495
|
-
ExposeP2PGateway = class
|
|
28540
|
+
ExposeP2PGateway = class extends EventEmitter3 {
|
|
28496
28541
|
_nexusTool;
|
|
28497
28542
|
// NexusTool instance
|
|
28498
28543
|
_kind;
|
|
@@ -28640,51 +28685,20 @@ ${this.formatConnectionInfo()}`);
|
|
|
28640
28685
|
}
|
|
28641
28686
|
/**
|
|
28642
28687
|
* Check for and reconnect to a surviving P2P expose from a previous session.
|
|
28643
|
-
*
|
|
28644
|
-
*
|
|
28645
|
-
*
|
|
28688
|
+
*
|
|
28689
|
+
* IMPORTANT: We no longer blindly reconnect to surviving daemons because:
|
|
28690
|
+
* 1. The daemon script may be outdated (OA was updated since daemon spawned)
|
|
28691
|
+
* 2. The registered capabilities may be stale (e.g., local Ollama from a previous expose)
|
|
28692
|
+
* 3. Only a fresh start() → doConnect() → expose can guarantee correct state
|
|
28693
|
+
*
|
|
28694
|
+
* Instead, we clean up the stale state so the next /expose command starts fresh.
|
|
28646
28695
|
*/
|
|
28647
|
-
static async checkAndReconnect(
|
|
28648
|
-
const state = readP2PExposeState(
|
|
28649
|
-
if (
|
|
28650
|
-
|
|
28651
|
-
const nexusDir = nexusTool.getNexusDir();
|
|
28652
|
-
const statusPath = join35(nexusDir, "status.json");
|
|
28653
|
-
try {
|
|
28654
|
-
if (!existsSync27(statusPath)) {
|
|
28655
|
-
removeP2PExposeState(stateDir);
|
|
28656
|
-
return null;
|
|
28657
|
-
}
|
|
28658
|
-
const status = JSON.parse(readFileSync19(statusPath, "utf8"));
|
|
28659
|
-
if (!status.connected || !status.peerId) {
|
|
28660
|
-
removeP2PExposeState(stateDir);
|
|
28661
|
-
return null;
|
|
28662
|
-
}
|
|
28663
|
-
if (status.peerId !== state.peerId) {
|
|
28664
|
-
removeP2PExposeState(stateDir);
|
|
28665
|
-
return null;
|
|
28666
|
-
}
|
|
28667
|
-
} catch {
|
|
28668
|
-
removeP2PExposeState(stateDir);
|
|
28669
|
-
return null;
|
|
28696
|
+
static async checkAndReconnect(_stateDir, _nexusTool, _options) {
|
|
28697
|
+
const state = readP2PExposeState(_stateDir);
|
|
28698
|
+
if (state) {
|
|
28699
|
+
removeP2PExposeState(_stateDir);
|
|
28670
28700
|
}
|
|
28671
|
-
|
|
28672
|
-
kind: state.kind,
|
|
28673
|
-
targetUrl: state.targetUrl,
|
|
28674
|
-
authKey: state.authKey,
|
|
28675
|
-
stateDir,
|
|
28676
|
-
margin: state.margin,
|
|
28677
|
-
passthrough: state.passthrough,
|
|
28678
|
-
loadbalance: state.loadbalance,
|
|
28679
|
-
...options
|
|
28680
|
-
}, nexusTool);
|
|
28681
|
-
gateway._peerId = state.peerId;
|
|
28682
|
-
gateway._stats.status = "active";
|
|
28683
|
-
gateway._stats.startedAt = new Date(state.startedAt).getTime();
|
|
28684
|
-
gateway.emitStats();
|
|
28685
|
-
gateway.startMeteringPoll(nexusDir);
|
|
28686
|
-
options.onInfo?.(`P2P expose reconnected: ${state.peerId}`);
|
|
28687
|
-
return gateway;
|
|
28701
|
+
return null;
|
|
28688
28702
|
}
|
|
28689
28703
|
/** Poll the daemon's metering.jsonl and status.json for stats */
|
|
28690
28704
|
startMeteringPoll(nexusDir) {
|
package/package.json
CHANGED