open-agents-ai 0.103.50 → 0.103.51
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 +224 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -33836,12 +33836,12 @@ async function handleSlashCommand(input, ctx) {
|
|
|
33836
33836
|
return "handled";
|
|
33837
33837
|
}
|
|
33838
33838
|
if (arg === "status") {
|
|
33839
|
-
const
|
|
33840
|
-
if (
|
|
33841
|
-
process.stdout.write("\n" + info.stats + "\n\n");
|
|
33842
|
-
} else {
|
|
33839
|
+
const gateway = ctx.getExposeGateway?.();
|
|
33840
|
+
if (!gateway) {
|
|
33843
33841
|
renderWarning("No active expose gateway.");
|
|
33842
|
+
return "handled";
|
|
33844
33843
|
}
|
|
33844
|
+
await showExposeDashboard(gateway, ctx.rl);
|
|
33845
33845
|
return "handled";
|
|
33846
33846
|
}
|
|
33847
33847
|
if (arg === "config") {
|
|
@@ -35292,6 +35292,201 @@ async function switchModel(query, ctx, local = false) {
|
|
|
35292
35292
|
renderError(`Failed to switch model: ${err instanceof Error ? err.message : String(err)}`);
|
|
35293
35293
|
}
|
|
35294
35294
|
}
|
|
35295
|
+
function fmtDashTokens(n) {
|
|
35296
|
+
if (n < 1e3)
|
|
35297
|
+
return String(n);
|
|
35298
|
+
if (n < 1e6)
|
|
35299
|
+
return `${(n / 1e3).toFixed(1)}K`;
|
|
35300
|
+
return `${(n / 1e6).toFixed(1)}M`;
|
|
35301
|
+
}
|
|
35302
|
+
function fmtUptime(ms) {
|
|
35303
|
+
const sec = Math.floor(ms / 1e3);
|
|
35304
|
+
if (sec < 60)
|
|
35305
|
+
return `${sec}s`;
|
|
35306
|
+
if (sec < 3600)
|
|
35307
|
+
return `${Math.floor(sec / 60)}m ${sec % 60}s`;
|
|
35308
|
+
return `${Math.floor(sec / 3600)}h ${Math.floor(sec % 3600 / 60)}m`;
|
|
35309
|
+
}
|
|
35310
|
+
async function showExposeDashboard(gateway, rl) {
|
|
35311
|
+
const stdin = process.stdin;
|
|
35312
|
+
const stdout = process.stdout;
|
|
35313
|
+
if (!stdin.isTTY) {
|
|
35314
|
+
if (typeof gateway.formatStats === "function") {
|
|
35315
|
+
stdout.write("\n" + gateway.formatStats() + "\n\n");
|
|
35316
|
+
}
|
|
35317
|
+
return;
|
|
35318
|
+
}
|
|
35319
|
+
let lastRenderedLines = 0;
|
|
35320
|
+
let refreshTimer = null;
|
|
35321
|
+
const hadRawMode = stdin.isRaw;
|
|
35322
|
+
const savedListeners = rl ? stdin.listeners("data").slice() : [];
|
|
35323
|
+
if (rl) {
|
|
35324
|
+
rl.pause();
|
|
35325
|
+
for (const fn of savedListeners)
|
|
35326
|
+
stdin.removeListener("data", fn);
|
|
35327
|
+
}
|
|
35328
|
+
stdin.setRawMode(true);
|
|
35329
|
+
stdin.resume();
|
|
35330
|
+
stdout.write("\x1B[?25l");
|
|
35331
|
+
function buildDashboard() {
|
|
35332
|
+
const s = gateway.stats ?? gateway._stats;
|
|
35333
|
+
if (!s)
|
|
35334
|
+
return [" No stats available.", "", " Press Escape or 'q' to close."];
|
|
35335
|
+
const lines = [];
|
|
35336
|
+
const now = Date.now();
|
|
35337
|
+
const uptime = fmtUptime(now - (s.startedAt || now));
|
|
35338
|
+
const statusColor = s.status === "active" ? c2.green : s.status === "error" ? c2.red : c2.yellow;
|
|
35339
|
+
lines.push("");
|
|
35340
|
+
lines.push(` ${c2.bold("Expose Dashboard")} ${statusColor("\u25CF")} ${statusColor(s.status || "unknown")} ${c2.dim(`uptime ${uptime}`)}`);
|
|
35341
|
+
lines.push(` ${c2.dim("\u2500".repeat(60))}`);
|
|
35342
|
+
const activeConns = s.activeConnections || 0;
|
|
35343
|
+
const totalReqs = s.totalRequests || 0;
|
|
35344
|
+
const errors = s.errors || 0;
|
|
35345
|
+
const tokIn = s.totalTokensIn || 0;
|
|
35346
|
+
const tokOut = s.totalTokensOut || 0;
|
|
35347
|
+
lines.push(` ${c2.cyan("Requests")} ${c2.bold(String(totalReqs))} ${c2.dim("|")} ${c2.cyan("Active")} ${activeConns > 0 ? c2.green(c2.bold(String(activeConns))) : c2.dim("0")} ${c2.dim("|")} ${c2.cyan("Errors")} ${errors > 0 ? c2.red(String(errors)) : c2.dim("0")}`);
|
|
35348
|
+
lines.push(` ${c2.cyan("Tokens")} ${c2.dim("in:")}${c2.bold(fmtDashTokens(tokIn))} ${c2.dim("out:")}${c2.bold(fmtDashTokens(tokOut))} ${c2.dim("total:")}${fmtDashTokens(tokIn + tokOut)}`);
|
|
35349
|
+
if (s.budgetTokensTotal > 0) {
|
|
35350
|
+
const pct = Math.round(s.budgetTokensRemaining / s.budgetTokensTotal * 100);
|
|
35351
|
+
const budgetColor = pct > 50 ? c2.green : pct > 20 ? c2.yellow : c2.red;
|
|
35352
|
+
const barLen = 20;
|
|
35353
|
+
const filledLen = Math.round(pct / 100 * barLen);
|
|
35354
|
+
const bar = budgetColor("\u2588".repeat(filledLen)) + c2.dim("\u2591".repeat(barLen - filledLen));
|
|
35355
|
+
lines.push(` ${c2.cyan("Budget")} ${bar} ${budgetColor(`${pct}%`)} ${c2.dim(`(${fmtDashTokens(s.budgetTokensRemaining)}/${fmtDashTokens(s.budgetTokensTotal)})`)}`);
|
|
35356
|
+
}
|
|
35357
|
+
const modelEntries = s.modelUsage ? Array.from(s.modelUsage.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
|
|
35358
|
+
if (modelEntries.length > 0) {
|
|
35359
|
+
lines.push("");
|
|
35360
|
+
lines.push(` ${c2.bold("Models")}`);
|
|
35361
|
+
for (const [model, count] of modelEntries) {
|
|
35362
|
+
let mIn = 0, mOut = 0;
|
|
35363
|
+
if (s.users) {
|
|
35364
|
+
for (const user of s.users.values()) {
|
|
35365
|
+
const mm = user.models?.get?.(model);
|
|
35366
|
+
if (mm) {
|
|
35367
|
+
mIn += mm.tokensIn || 0;
|
|
35368
|
+
mOut += mm.tokensOut || 0;
|
|
35369
|
+
}
|
|
35370
|
+
}
|
|
35371
|
+
}
|
|
35372
|
+
const bar = count > 0 ? c2.green("\u25AE".repeat(Math.min(count, 20))) : "";
|
|
35373
|
+
lines.push(` ${c2.cyan(model.padEnd(35))} ${c2.bold(String(count).padStart(4))} req ${c2.dim(`in:${fmtDashTokens(mIn).padStart(6)} out:${fmtDashTokens(mOut).padStart(6)}`)} ${bar}`);
|
|
35374
|
+
}
|
|
35375
|
+
}
|
|
35376
|
+
const users = s.users ? Array.from(s.users.values()) : [];
|
|
35377
|
+
if (users.length > 0) {
|
|
35378
|
+
lines.push("");
|
|
35379
|
+
lines.push(` ${c2.bold("Connected Peers")} (${users.length})`);
|
|
35380
|
+
for (const user of users) {
|
|
35381
|
+
const ageSec = Math.floor((now - (user.firstSeen || now)) / 1e3);
|
|
35382
|
+
const ageStr = ageSec < 60 ? `${ageSec}s` : ageSec < 3600 ? `${Math.floor(ageSec / 60)}m` : `${Math.floor(ageSec / 3600)}h${Math.floor(ageSec % 3600 / 60)}m`;
|
|
35383
|
+
const lastSec = Math.floor((now - (user.lastSeen || now)) / 1e3);
|
|
35384
|
+
const lastStr = lastSec < 5 ? c2.green("now") : lastSec < 60 ? `${lastSec}s ago` : `${Math.floor(lastSec / 60)}m ago`;
|
|
35385
|
+
const activeStr = (user.activeRequests || 0) > 0 ? c2.green(` \u25CF ${user.activeRequests} active`) : "";
|
|
35386
|
+
lines.push(` ${c2.bold(user.ip || "unknown")}${activeStr}`);
|
|
35387
|
+
lines.push(` ${c2.dim("session")} ${ageStr} ${c2.dim("last")} ${lastStr} ${c2.dim("reqs")} ${user.requests || 0} ${c2.dim("tok")} ${c2.cyan("in:")}${fmtDashTokens(user.tokensIn || 0)} ${c2.cyan("out:")}${fmtDashTokens(user.tokensOut || 0)}`);
|
|
35388
|
+
const userModels = user.models ? Array.from(user.models.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
|
|
35389
|
+
for (const [m, mm] of userModels) {
|
|
35390
|
+
lines.push(` ${c2.dim("\u2514")} ${c2.cyan(m)} ${c2.dim(`${mm.requests || 0}req ${fmtDashTokens((mm.tokensIn || 0) + (mm.tokensOut || 0))}tok`)}`);
|
|
35391
|
+
}
|
|
35392
|
+
}
|
|
35393
|
+
}
|
|
35394
|
+
lines.push("");
|
|
35395
|
+
lines.push(` ${c2.dim("Press Escape or 'q' to close \u2502 Live \u25CF updates every 2s")}`);
|
|
35396
|
+
lines.push("");
|
|
35397
|
+
return lines;
|
|
35398
|
+
}
|
|
35399
|
+
function render() {
|
|
35400
|
+
const lines = buildDashboard();
|
|
35401
|
+
if (lastRenderedLines > 0) {
|
|
35402
|
+
stdout.write(`\x1B[${lastRenderedLines}A`);
|
|
35403
|
+
for (let i = 0; i < lastRenderedLines; i++) {
|
|
35404
|
+
stdout.write("\x1B[2K\n");
|
|
35405
|
+
}
|
|
35406
|
+
stdout.write(`\x1B[${lastRenderedLines}A`);
|
|
35407
|
+
}
|
|
35408
|
+
stdout.write(lines.join("\n") + "\n");
|
|
35409
|
+
lastRenderedLines = lines.length;
|
|
35410
|
+
}
|
|
35411
|
+
function cleanup() {
|
|
35412
|
+
if (refreshTimer) {
|
|
35413
|
+
clearInterval(refreshTimer);
|
|
35414
|
+
refreshTimer = null;
|
|
35415
|
+
}
|
|
35416
|
+
gateway.removeListener?.("stats", onStats);
|
|
35417
|
+
if (lastRenderedLines > 0) {
|
|
35418
|
+
stdout.write(`\x1B[${lastRenderedLines}A`);
|
|
35419
|
+
for (let i = 0; i < lastRenderedLines; i++) {
|
|
35420
|
+
stdout.write("\x1B[2K\n");
|
|
35421
|
+
}
|
|
35422
|
+
stdout.write(`\x1B[${lastRenderedLines}A`);
|
|
35423
|
+
}
|
|
35424
|
+
stdout.write("\x1B[?25h");
|
|
35425
|
+
stdin.setRawMode(hadRawMode ?? false);
|
|
35426
|
+
stdin.removeListener("data", onKey);
|
|
35427
|
+
if (rl) {
|
|
35428
|
+
for (const fn of savedListeners)
|
|
35429
|
+
stdin.on("data", fn);
|
|
35430
|
+
rl.resume();
|
|
35431
|
+
}
|
|
35432
|
+
}
|
|
35433
|
+
function onStats() {
|
|
35434
|
+
render();
|
|
35435
|
+
}
|
|
35436
|
+
function onKey(chunk) {
|
|
35437
|
+
const key = chunk.toString();
|
|
35438
|
+
if (key === "\x1B" || key === "q" || key === "Q") {
|
|
35439
|
+
cleanup();
|
|
35440
|
+
return;
|
|
35441
|
+
}
|
|
35442
|
+
if (key === "") {
|
|
35443
|
+
cleanup();
|
|
35444
|
+
return;
|
|
35445
|
+
}
|
|
35446
|
+
}
|
|
35447
|
+
if (typeof gateway.on === "function") {
|
|
35448
|
+
gateway.on("stats", onStats);
|
|
35449
|
+
}
|
|
35450
|
+
refreshTimer = setInterval(render, 2e3);
|
|
35451
|
+
render();
|
|
35452
|
+
stdin.on("data", onKey);
|
|
35453
|
+
return new Promise((resolve31) => {
|
|
35454
|
+
const origCleanup = cleanup;
|
|
35455
|
+
function wrappedCleanup() {
|
|
35456
|
+
origCleanup();
|
|
35457
|
+
resolve31();
|
|
35458
|
+
}
|
|
35459
|
+
stdin.removeListener("data", onKey);
|
|
35460
|
+
function onKeyWrapped(chunk) {
|
|
35461
|
+
const key = chunk.toString();
|
|
35462
|
+
if (key === "\x1B" || key === "q" || key === "Q" || key === "") {
|
|
35463
|
+
if (refreshTimer) {
|
|
35464
|
+
clearInterval(refreshTimer);
|
|
35465
|
+
refreshTimer = null;
|
|
35466
|
+
}
|
|
35467
|
+
gateway.removeListener?.("stats", onStats);
|
|
35468
|
+
if (lastRenderedLines > 0) {
|
|
35469
|
+
stdout.write(`\x1B[${lastRenderedLines}A`);
|
|
35470
|
+
for (let i = 0; i < lastRenderedLines; i++) {
|
|
35471
|
+
stdout.write("\x1B[2K\n");
|
|
35472
|
+
}
|
|
35473
|
+
stdout.write(`\x1B[${lastRenderedLines}A`);
|
|
35474
|
+
}
|
|
35475
|
+
stdout.write("\x1B[?25h");
|
|
35476
|
+
stdin.setRawMode(hadRawMode ?? false);
|
|
35477
|
+
stdin.removeListener("data", onKeyWrapped);
|
|
35478
|
+
if (rl) {
|
|
35479
|
+
for (const fn of savedListeners)
|
|
35480
|
+
stdin.on("data", fn);
|
|
35481
|
+
rl.resume();
|
|
35482
|
+
}
|
|
35483
|
+
resolve31();
|
|
35484
|
+
}
|
|
35485
|
+
}
|
|
35486
|
+
stdin.on("data", onKeyWrapped);
|
|
35487
|
+
});
|
|
35488
|
+
}
|
|
35489
|
+
var DASH_INTERNAL;
|
|
35295
35490
|
var init_commands = __esm({
|
|
35296
35491
|
"packages/cli/dist/tui/commands.js"() {
|
|
35297
35492
|
"use strict";
|
|
@@ -35307,6 +35502,7 @@ var init_commands = __esm({
|
|
|
35307
35502
|
init_listen();
|
|
35308
35503
|
init_dist();
|
|
35309
35504
|
init_tui_select();
|
|
35505
|
+
DASH_INTERNAL = /* @__PURE__ */ new Set(["system_metrics", "__list_capabilities"]);
|
|
35310
35506
|
}
|
|
35311
35507
|
});
|
|
35312
35508
|
|
|
@@ -44207,15 +44403,34 @@ var init_status_bar = __esm({
|
|
|
44207
44403
|
}
|
|
44208
44404
|
/** Expose gateway status — shown after capability emojis */
|
|
44209
44405
|
_expose = null;
|
|
44406
|
+
/** Blink state for expose icon during active inference */
|
|
44407
|
+
_exposeBlinkOn = true;
|
|
44408
|
+
_exposeBlinkTimer = null;
|
|
44210
44409
|
/** Update expose gateway status */
|
|
44211
44410
|
setExposeStatus(status) {
|
|
44212
44411
|
this._expose = status;
|
|
44412
|
+
if (status.activeConnections > 0 && !this._exposeBlinkTimer) {
|
|
44413
|
+
this._exposeBlinkTimer = setInterval(() => {
|
|
44414
|
+
this._exposeBlinkOn = !this._exposeBlinkOn;
|
|
44415
|
+
if (this.active)
|
|
44416
|
+
this.renderFooterPreserveCursor();
|
|
44417
|
+
}, 500);
|
|
44418
|
+
} else if (status.activeConnections === 0 && this._exposeBlinkTimer) {
|
|
44419
|
+
clearInterval(this._exposeBlinkTimer);
|
|
44420
|
+
this._exposeBlinkTimer = null;
|
|
44421
|
+
this._exposeBlinkOn = true;
|
|
44422
|
+
}
|
|
44213
44423
|
if (this.active)
|
|
44214
44424
|
this.renderFooterPreserveCursor();
|
|
44215
44425
|
}
|
|
44216
44426
|
/** Clear expose gateway status */
|
|
44217
44427
|
clearExposeStatus() {
|
|
44218
44428
|
this._expose = null;
|
|
44429
|
+
if (this._exposeBlinkTimer) {
|
|
44430
|
+
clearInterval(this._exposeBlinkTimer);
|
|
44431
|
+
this._exposeBlinkTimer = null;
|
|
44432
|
+
this._exposeBlinkOn = true;
|
|
44433
|
+
}
|
|
44219
44434
|
if (this.active)
|
|
44220
44435
|
this.renderFooterPreserveCursor();
|
|
44221
44436
|
}
|
|
@@ -44674,7 +44889,7 @@ var init_status_bar = __esm({
|
|
|
44674
44889
|
}
|
|
44675
44890
|
if (this._expose) {
|
|
44676
44891
|
const INTERNAL_CAPS = /* @__PURE__ */ new Set(["system_metrics", "__list_capabilities"]);
|
|
44677
|
-
const statusEmoji = this._expose.status === "active" ? "\u{1F7E2}" : this._expose.status === "error" ? "\u{1F534}" : "\u{1F7E0}";
|
|
44892
|
+
const statusEmoji = this._expose.activeConnections > 0 ? this._exposeBlinkOn ? "\u{1F7E2}" : "\u26AB" : this._expose.status === "active" ? "\u{1F7E2}" : this._expose.status === "error" ? "\u{1F534}" : "\u{1F7E0}";
|
|
44678
44893
|
const models = Array.from(this._expose.modelUsage.keys()).filter((m2) => !INTERNAL_CAPS.has(m2));
|
|
44679
44894
|
const modelParams = models.map((mdl) => {
|
|
44680
44895
|
const pm = mdl.match(/(\d+[bBmM])/);
|
|
@@ -47277,6 +47492,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
47277
47492
|
stats: infos[0].stats
|
|
47278
47493
|
};
|
|
47279
47494
|
},
|
|
47495
|
+
/** Get the raw expose gateway instance for live dashboard */
|
|
47496
|
+
getExposeGateway() {
|
|
47497
|
+
return p2pGateway ?? tunnelGateway ?? null;
|
|
47498
|
+
},
|
|
47280
47499
|
// ── Nexus daemon connect ──────────────────────────────────────────────
|
|
47281
47500
|
async nexusConnect() {
|
|
47282
47501
|
const nexusTool = new NexusTool(repoRoot);
|
package/package.json
CHANGED