open-agents-ai 0.105.6 → 0.105.7

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.
Files changed (2) hide show
  1. package/dist/index.js +186 -95
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -29319,8 +29319,10 @@ var init_expose = __esm({
29319
29319
  if (responseTail.length > 2048) {
29320
29320
  responseTail = responseTail.slice(-2048);
29321
29321
  }
29322
- if (isStreaming)
29322
+ if (isStreaming) {
29323
29323
  this.emit("token_flash");
29324
+ this.emit("stream_data", { content: text, model: requestModel, peer: userIp });
29325
+ }
29324
29326
  });
29325
29327
  if (isStreaming) {
29326
29328
  if (proxyRes.statusCode !== 200) {
@@ -40661,28 +40663,78 @@ async function showExposeDashboard(gateway, rl, ctx) {
40661
40663
  }
40662
40664
  return;
40663
40665
  }
40666
+ const cols = () => process.stdout.columns ?? 80;
40667
+ const rows = () => process.stdout.rows ?? 24;
40664
40668
  const peerLedColor = (peerIdx) => {
40665
40669
  const stops = [51, 81, 111, 141, 171, 201];
40666
40670
  const code = stops[Math.min(peerIdx, stops.length - 1)] ?? 51;
40667
40671
  return `\x1B[38;5;${code}m\u25CF\x1B[0m`;
40668
40672
  };
40669
- while (true) {
40673
+ const streamLog = [];
40674
+ const MAX_STREAM_ENTRIES = 200;
40675
+ function extractStreamContent(raw) {
40676
+ let result = "";
40677
+ const lines = raw.split("\n");
40678
+ for (const line of lines) {
40679
+ if (!line.startsWith("data: "))
40680
+ continue;
40681
+ const json = line.slice(6).trim();
40682
+ if (json === "[DONE]")
40683
+ continue;
40684
+ try {
40685
+ const obj = JSON.parse(json);
40686
+ if (obj.response)
40687
+ result += obj.response;
40688
+ else if (obj.message?.content)
40689
+ result += obj.message.content;
40690
+ else if (obj.choices?.[0]?.delta?.content)
40691
+ result += obj.choices[0].delta.content;
40692
+ } catch {
40693
+ }
40694
+ }
40695
+ return result;
40696
+ }
40697
+ const onStreamData = (data) => {
40698
+ const tokens = extractStreamContent(data.content);
40699
+ if (!tokens)
40700
+ return;
40701
+ streamLog.push({ time: Date.now(), model: data.model, peer: data.peer, content: tokens });
40702
+ if (streamLog.length > MAX_STREAM_ENTRIES)
40703
+ streamLog.splice(0, streamLog.length - MAX_STREAM_ENTRIES);
40704
+ scheduleRender();
40705
+ };
40706
+ let renderTimer = null;
40707
+ let refreshTimer = null;
40708
+ let stopped = false;
40709
+ function scheduleRender() {
40710
+ if (stopped)
40711
+ return;
40712
+ if (renderTimer)
40713
+ return;
40714
+ renderTimer = setTimeout(() => {
40715
+ renderTimer = null;
40716
+ renderDashboard();
40717
+ }, 50);
40718
+ }
40719
+ function renderDashboard() {
40720
+ if (stopped)
40721
+ return;
40670
40722
  const s = gateway.stats ?? gateway._stats;
40671
40723
  const now = Date.now();
40724
+ const w = cols();
40725
+ const h = rows();
40672
40726
  const uptime = s ? fmtUptime(now - (s.startedAt || now)) : "0s";
40673
- const statusColor = !s ? c2.dim : s.status === "active" ? c2.green : s.status === "error" ? c2.red : c2.yellow;
40727
+ const lines = [];
40728
+ const statusDot = !s ? c2.dim("\u25CF") : s.status === "active" ? c2.green("\u25CF") : s.status === "error" ? c2.red("\u25CF") : c2.yellow("\u25CF");
40674
40729
  const statusLabel = s?.status || "unknown";
40675
- const items = [];
40676
- const skipKeys = [];
40677
- items.push({ key: "hdr_status", label: selectColors.dim(`\u2500\u2500\u2500 ${statusColor("\u25CF")} ${statusLabel} uptime ${uptime} \u2500\u2500\u2500`), kind: "header" });
40678
- skipKeys.push("hdr_status");
40730
+ lines.push("");
40731
+ lines.push(` ${c2.bold("Expose Dashboard")} ${statusDot} ${statusLabel} ${c2.dim("uptime")} ${uptime} ${c2.dim((/* @__PURE__ */ new Date()).toLocaleTimeString())}`);
40679
40732
  const isTunnel = !!gateway.tunnelUrl;
40680
40733
  const isP2P = !!gateway.peerId;
40681
40734
  const endpointId = isTunnel ? gateway.tunnelUrl : isP2P ? gateway.peerId : null;
40682
40735
  const authKey = gateway.authKey ?? "";
40683
40736
  if (endpointId) {
40684
- const endpointCmd = `/endpoint ${endpointId} --auth ${authKey}`;
40685
- items.push({ key: "endpoint", label: "\u{1F517} Endpoint", detail: endpointCmd, kind: "action" });
40737
+ lines.push(` ${c2.dim("Endpoint:")} ${c2.cyan(`/endpoint ${endpointId} --auth ${authKey}`)}`);
40686
40738
  }
40687
40739
  if (s) {
40688
40740
  const totalReqs = s.totalRequests || 0;
@@ -40690,23 +40742,22 @@ async function showExposeDashboard(gateway, rl, ctx) {
40690
40742
  const tokIn = s.totalTokensIn || 0;
40691
40743
  const tokOut = s.totalTokensOut || 0;
40692
40744
  const errors = s.errors || 0;
40693
- const statsLine = `Req: ${totalReqs} Active: ${activeConns} Err: ${errors} Tok \u2191${fmtDashTokens(tokIn)} \u2193${fmtDashTokens(tokOut)}`;
40694
- items.push({ key: "info_stats", label: c2.dim(statsLine), kind: "info" });
40695
- skipKeys.push("info_stats");
40745
+ const activeDot = activeConns > 0 ? c2.green(`\u25CF ${activeConns}`) : c2.dim("0");
40746
+ lines.push("");
40747
+ lines.push(` ${c2.dim("Req")} ${c2.bold(String(totalReqs))} ${c2.dim("Active")} ${activeDot} ${c2.dim("Err")} ${errors > 0 ? c2.red(String(errors)) : c2.dim("0")} ${c2.dim("Tok")} \u2191${c2.cyan(fmtDashTokens(tokIn))} \u2193${c2.cyan(fmtDashTokens(tokOut))}`);
40696
40748
  if (s.budgetTokensTotal > 0) {
40697
40749
  const pct = Math.round(s.budgetTokensRemaining / s.budgetTokensTotal * 100);
40698
40750
  const budgetColor = pct > 50 ? c2.green : pct > 20 ? c2.yellow : c2.red;
40699
40751
  const barLen = 20;
40700
40752
  const filledLen = Math.round(pct / 100 * barLen);
40701
40753
  const bar = budgetColor("\u2588".repeat(filledLen)) + c2.dim("\u2591".repeat(barLen - filledLen));
40702
- items.push({ key: "info_budget", label: ` Budget ${bar} ${budgetColor(`${pct}%`)}`, kind: "info" });
40703
- skipKeys.push("info_budget");
40754
+ lines.push(` ${c2.dim("Budget")} ${bar} ${budgetColor(`${pct}%`)}`);
40704
40755
  }
40705
40756
  }
40706
40757
  const modelEntries = s?.modelUsage ? Array.from(s.modelUsage.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40707
40758
  if (modelEntries.length > 0) {
40708
- items.push({ key: "hdr_models", label: selectColors.dim(`\u2500\u2500\u2500 Models (${modelEntries.length}) \u2500\u2500\u2500`), kind: "header" });
40709
- skipKeys.push("hdr_models");
40759
+ lines.push("");
40760
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 Models (" + modelEntries.length + ") \u2500\u2500\u2500")}`);
40710
40761
  for (const [model, count] of modelEntries) {
40711
40762
  let mIn = 0, mOut = 0;
40712
40763
  if (s?.users) {
@@ -40718,19 +40769,14 @@ async function showExposeDashboard(gateway, rl, ctx) {
40718
40769
  }
40719
40770
  }
40720
40771
  }
40721
- const bar = count > 0 ? c2.green("\u25AE".repeat(Math.min(count, 10))) : "";
40722
- items.push({
40723
- key: `model_${model}`,
40724
- label: `${model}`,
40725
- detail: `${count} req \u2191${fmtDashTokens(mIn)} \u2193${fmtDashTokens(mOut)} ${bar}`,
40726
- kind: "model"
40727
- });
40772
+ const bar = count > 0 ? c2.green("\u25AE".repeat(Math.min(count, 20))) : "";
40773
+ lines.push(` ${c2.cyan(model)} ${c2.dim(`${count}req`)} \u2191${fmtDashTokens(mIn)} \u2193${fmtDashTokens(mOut)} ${bar}`);
40728
40774
  }
40729
40775
  }
40730
40776
  const users = s?.users ? Array.from(s.users.values()) : [];
40731
40777
  if (users.length > 0) {
40732
- items.push({ key: "hdr_peers", label: selectColors.dim(`\u2500\u2500\u2500 Peers (${users.length}) \u2500\u2500\u2500`), kind: "header" });
40733
- skipKeys.push("hdr_peers");
40778
+ lines.push("");
40779
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 Peers (" + users.length + ") \u2500\u2500\u2500")}`);
40734
40780
  for (let i = 0; i < users.length; i++) {
40735
40781
  const user = users[i];
40736
40782
  const ageSec = Math.floor((now - (user.firstSeen || now)) / 1e3);
@@ -40740,90 +40786,134 @@ async function showExposeDashboard(gateway, rl, ctx) {
40740
40786
  const activeFlag = (user.activeRequests || 0) > 0 ? ` ${c2.green(`\u25CF ${user.activeRequests} active`)}` : "";
40741
40787
  const led = peerLedColor(i);
40742
40788
  const peerTok = `\u2191${fmtDashTokens(user.tokensIn || 0)} \u2193${fmtDashTokens(user.tokensOut || 0)}`;
40743
- items.push({
40744
- key: `peer_${user.ip || i}`,
40745
- label: `${led} ${user.ip || "unknown"}${activeFlag}`,
40746
- detail: `${user.requests || 0}req ${peerTok} ${c2.dim(ageStr)} last: ${lastStr}`,
40747
- kind: "peer"
40748
- });
40789
+ lines.push(` ${led} ${user.ip || "unknown"}${activeFlag} ${c2.dim(`${user.requests || 0}req`)} ${peerTok} ${c2.dim(ageStr)} ${c2.dim("last:")} ${lastStr}`);
40749
40790
  }
40750
40791
  }
40751
40792
  const sys = getLocalSystemMetrics();
40752
- items.push({ key: "hdr_system", label: selectColors.dim("\u2500\u2500\u2500 System \u2500\u2500\u2500"), kind: "header" });
40753
- skipKeys.push("hdr_system");
40793
+ lines.push("");
40794
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 System \u2500\u2500\u2500")}`);
40754
40795
  const cpuColor = sys.cpuUtil > 80 ? c2.red : sys.cpuUtil > 50 ? c2.yellow : c2.green;
40755
40796
  const memColor = sys.memUtil > 80 ? c2.red : sys.memUtil > 50 ? c2.yellow : c2.green;
40756
- let sysLine = `CPU ${cpuColor(sys.cpuUtil + "%")} (${sys.cpuCores}c) RAM ${memColor(sys.memUtil + "%")} (${sys.memUsedGB}/${sys.memTotalGB}GB)`;
40797
+ let sysLine = ` CPU ${cpuColor(sys.cpuUtil + "%")} (${sys.cpuCores}c) RAM ${memColor(sys.memUtil + "%")} (${sys.memUsedGB}/${sys.memTotalGB}GB)`;
40757
40798
  if (sys.gpuAvailable) {
40758
40799
  const gpuColor = sys.gpuUtil > 80 ? c2.red : sys.gpuUtil > 50 ? c2.yellow : c2.green;
40759
40800
  const vramColor = sys.vramUtil > 80 ? c2.red : sys.vramUtil > 50 ? c2.yellow : c2.green;
40760
40801
  sysLine += ` GPU ${gpuColor(sys.gpuUtil + "%")} VRAM ${vramColor(sys.vramUtil + "%")} (${sys.vramUsedMB}/${sys.vramTotalMB}MB)`;
40761
40802
  }
40762
- items.push({ key: "info_system", label: c2.dim(sysLine), kind: "info" });
40763
- skipKeys.push("info_system");
40764
- items.push({ key: "hdr_actions", label: selectColors.dim("\u2500\u2500\u2500 Actions \u2500\u2500\u2500"), kind: "header" });
40765
- skipKeys.push("hdr_actions");
40766
- items.push({ key: "refresh", label: "\u{1F504} Refresh", detail: "Rebuild dashboard with latest data", kind: "action" });
40767
- items.push({ key: "stop", label: "\u{1F6D1} Stop Gateway", detail: "Shut down the expose gateway", kind: "action" });
40768
- const result = await tuiSelect({
40769
- items,
40770
- title: "Expose Dashboard",
40771
- rl,
40772
- skipKeys,
40773
- availableRows: ctx?.availableContentRows?.()
40774
- });
40775
- if (!result.confirmed || !result.key)
40776
- break;
40777
- switch (result.key) {
40778
- case "endpoint": {
40779
- const id = isTunnel ? gateway.tunnelUrl : gateway.peerId;
40780
- const cmd = `/endpoint ${id} --auth ${authKey}`;
40781
- if (process.stdout.isTTY && id) {
40782
- const b64 = Buffer.from(cmd).toString("base64");
40783
- process.stdout.write(`\x1B]52;c;${b64}\x07`);
40784
- }
40785
- process.stdout.write(`
40786
- ${c2.bold("Endpoint command")} ${c2.dim("(copied to clipboard)")}
40787
- ${c2.cyan(cmd)}
40788
-
40789
- `);
40790
- await new Promise((resolve32) => {
40791
- const onData = () => {
40792
- process.stdin.removeListener("data", onData);
40793
- resolve32();
40794
- };
40795
- process.stdin.once("data", onData);
40796
- });
40797
- continue;
40803
+ lines.push(` ${c2.dim(sysLine)}`);
40804
+ const metricsLines = lines.length;
40805
+ const streamAreaHeight = Math.max(3, h - metricsLines - 3);
40806
+ lines.push("");
40807
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 Live Token Stream \u2500\u2500\u2500")}`);
40808
+ if (streamLog.length === 0) {
40809
+ lines.push(` ${c2.dim("Waiting for streaming requests...")}`);
40810
+ for (let i = 1; i < streamAreaHeight - 1; i++)
40811
+ lines.push("");
40812
+ } else {
40813
+ const maxContentW = Math.max(20, w - 6);
40814
+ const recentEntries = [];
40815
+ for (let i = streamLog.length - 1; i >= 0 && recentEntries.length < streamAreaHeight - 1; i--) {
40816
+ const entry = streamLog[i];
40817
+ const clean = entry.content.replace(/\n/g, "\u23CE").replace(/[\x00-\x1F\x7F]/g, "");
40818
+ if (!clean)
40819
+ continue;
40820
+ const truncated = clean.length > maxContentW ? clean.slice(0, maxContentW - 1) + "\u2026" : clean;
40821
+ recentEntries.unshift(` \x1B[38;5;245m${truncated}\x1B[0m`);
40822
+ }
40823
+ while (recentEntries.length < streamAreaHeight - 1)
40824
+ recentEntries.unshift("");
40825
+ const visible = recentEntries.slice(-(streamAreaHeight - 1));
40826
+ lines.push(...visible);
40827
+ }
40828
+ const footerLine = ` ${c2.dim("q")} exit ${c2.dim("s")} stop gateway ${c2.dim("c")} copy endpoint ${c2.dim("auto-refresh 1s")}`;
40829
+ lines.push(footerLine);
40830
+ const frame = "\x1B[H\x1B[2J" + lines.join("\n") + "\n";
40831
+ overlayWrite(frame);
40832
+ }
40833
+ const onStats = () => scheduleRender();
40834
+ gateway.on("stats", onStats);
40835
+ gateway.on("stream_data", onStreamData);
40836
+ const savedRlListeners = [];
40837
+ if (rl) {
40838
+ rl.pause();
40839
+ for (const event of ["keypress", "data"]) {
40840
+ const listeners = process.stdin.listeners(event);
40841
+ for (const fn of listeners) {
40842
+ savedRlListeners.push({ event, fn });
40843
+ process.stdin.removeListener(event, fn);
40844
+ }
40845
+ }
40846
+ }
40847
+ const hadRawMode = process.stdin.isRaw;
40848
+ if (typeof process.stdin.setRawMode === "function") {
40849
+ process.stdin.setRawMode(true);
40850
+ }
40851
+ process.stdin.resume();
40852
+ enterOverlay();
40853
+ overlayWrite("\x1B[?1049h\x1B[?25l");
40854
+ renderDashboard();
40855
+ refreshTimer = setInterval(() => {
40856
+ renderDashboard();
40857
+ }, 1e3);
40858
+ let stopGateway = false;
40859
+ await new Promise((resolve32) => {
40860
+ const onData = (data) => {
40861
+ const key = data.toString();
40862
+ if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
40863
+ resolve32();
40864
+ return;
40798
40865
  }
40799
- case "refresh":
40800
- continue;
40801
- // Loop rebuilds items with fresh data
40802
- case "stop":
40803
- await ctx?.exposeStop?.();
40804
- renderInfo("Expose gateway stopped.");
40866
+ if (key === "s" || key === "S") {
40867
+ stopGateway = true;
40868
+ resolve32();
40805
40869
  return;
40806
- default:
40807
- if (result.key.startsWith("peer_")) {
40808
- const peerId = result.key.slice(5);
40809
- const user = users.find((u) => (u.ip || String(users.indexOf(u))) === peerId);
40810
- if (user) {
40811
- const userModels = user.models ? Array.from(user.models.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40812
- if (userModels.length > 0) {
40813
- process.stdout.write(`
40814
- ${c2.bold(user.ip || "unknown")} \u2014 model usage:
40815
- `);
40816
- for (const [m, mm] of userModels) {
40817
- process.stdout.write(` ${c2.cyan(m)} ${c2.dim(`${mm.requests}req \u2191${fmtDashTokens(mm.tokensIn)} \u2193${fmtDashTokens(mm.tokensOut)}`)}
40818
- `);
40819
- }
40820
- process.stdout.write("\n");
40821
- }
40822
- }
40823
- continue;
40870
+ }
40871
+ if (key === "c" || key === "C") {
40872
+ const id = gateway.tunnelUrl ?? gateway.peerId ?? null;
40873
+ if (id) {
40874
+ const cmd = `/endpoint ${id} --auth ${gateway.authKey ?? ""}`;
40875
+ const b64 = Buffer.from(cmd).toString("base64");
40876
+ overlayWrite(`\x1B]52;c;${b64}\x07`);
40877
+ overlayWrite(`\x1B[${rows()}H\x1B[2K ${c2.green("\u2713 Copied to clipboard")}`);
40878
+ setTimeout(() => scheduleRender(), 1500);
40824
40879
  }
40825
- continue;
40880
+ }
40881
+ };
40882
+ process.stdin.on("data", onData);
40883
+ const cleanup = () => {
40884
+ stopped = true;
40885
+ process.stdin.removeListener("data", onData);
40886
+ };
40887
+ const origResolve = resolve32;
40888
+ resolve32 = (() => {
40889
+ cleanup();
40890
+ origResolve();
40891
+ });
40892
+ });
40893
+ if (renderTimer) {
40894
+ clearTimeout(renderTimer);
40895
+ renderTimer = null;
40896
+ }
40897
+ if (refreshTimer) {
40898
+ clearInterval(refreshTimer);
40899
+ refreshTimer = null;
40900
+ }
40901
+ gateway.removeListener("stats", onStats);
40902
+ gateway.removeListener("stream_data", onStreamData);
40903
+ overlayWrite("\x1B[?25h\x1B[?1049l");
40904
+ leaveOverlay();
40905
+ if (typeof process.stdin.setRawMode === "function") {
40906
+ process.stdin.setRawMode(hadRawMode ?? false);
40907
+ }
40908
+ if (rl) {
40909
+ for (const { event, fn } of savedRlListeners) {
40910
+ process.stdin.on(event, fn);
40826
40911
  }
40912
+ rl.resume();
40913
+ }
40914
+ if (stopGateway) {
40915
+ await ctx?.exposeStop?.();
40916
+ renderInfo("Expose gateway stopped.");
40827
40917
  }
40828
40918
  }
40829
40919
  var DASH_INTERNAL;
@@ -40842,6 +40932,7 @@ var init_commands = __esm({
40842
40932
  init_listen();
40843
40933
  init_dist();
40844
40934
  init_tui_select();
40935
+ init_overlay_lock();
40845
40936
  init_drop_panel();
40846
40937
  init_neovim_mode();
40847
40938
  DASH_INTERNAL = /* @__PURE__ */ new Set(["system_metrics", "__list_capabilities"]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.105.6",
3
+ "version": "0.105.7",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",