Skip to content

feat(tui): Telemetry screen ÔÇö ASCII sparklines, provider stats, rate-limit heatmap, cost tracker#441

Open
jaeko44 wants to merge 5 commits intomainfrom
task/3cc669aec7e8-feat-tui-telemetry-screen-ascii-sparklines-provi
Open

feat(tui): Telemetry screen ÔÇö ASCII sparklines, provider stats, rate-limit heatmap, cost tracker#441
jaeko44 wants to merge 5 commits intomainfrom
task/3cc669aec7e8-feat-tui-telemetry-screen-ascii-sparklines-provi

Conversation

@jaeko44
Copy link
Copy Markdown
Member

@jaeko44 jaeko44 commented Mar 25, 2026

Task-ID: 3cc669ae-c7e8-4ceb-982f-37ab5be16659\n\nAutomated PR for task 3cc669ae-c7e8-4ceb-982f-37ab5be16659

@jaeko44 jaeko44 added the bosun-attached Bosun PR attachment marker label Mar 25, 2026
Copilot AI review requested due to automatic review settings March 25, 2026 19:25
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 25, 2026

Bosun CI signal: Bosun-created PR currently has failing checks.

@github-actions github-actions bot added the bosun-needs-fix Attached PR with failing CI that Bosun should pick up for repair label Mar 25, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Telemetry screen to both Ink-based TUIs (the ui/tui app and the tui/ CLI app), including sparklines, provider/token/cost aggregation, a 429 “heatmap”, and funnel stats, plus default telemetry cost config and tests.

Changes:

  • Introduce telemetry aggregation/rendering helpers and a richer Telemetry UI for ui/tui.
  • Add a new telemetry screen to the CLI TUI (tui/) with its own model/helpers.
  • Add default config for telemetry token-cost rates and new vitest coverage for both implementations.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
ui/tui/telemetry-helpers.js New helper module for sparklines + snapshot aggregation (providers/funnel/429 events/cost).
ui/tui/TelemetryScreen.js New telemetry UI panel layout (throughput, provider table, 429 heatmap, funnel, cost estimates).
ui/tui/App.js Wire the telemetry tab to the new TelemetryScreen component.
tui/screens/telemetry.mjs New CLI TUI telemetry screen rendering using a derived model.
tui/screens/telemetry-screen-helpers.mjs New CLI TUI telemetry model helpers (rates, provider rows, heatmap, funnel, sparklines).
tui/lib/navigation.mjs Add telemetry to navigation order/input mapping.
tui/app.mjs Register telemetry screen + add “Telemetry” tab to CLI TUI.
tests/tui-telemetry-ui.test.mjs New tests for ui/tui telemetry helper behaviors.
tests/tui-telemetry-screen.test.mjs New tests for CLI TUI telemetry model + navigation update.
config/config.mjs Add config.telemetry.costPer1kTokensUsd defaults.
Comments suppressed due to low confidence (1)

ui/tui/App.js:299

  • There are extra trailing blank lines at the end of the file. Please remove them to keep diffs clean.
}




💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"yellow",
"red",
);
const dailyCostUsd = history.reduce((sum, item) => sum + item.sessionCostUsd, 0);
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dailyCostUsd is computed by summing sessionCostUsd across the snapshot history, which will over-count the same sessions on every refresh (and the history window is rolling, not a day). This makes the displayed "Day Cost" misleading/incorrect. Derive a day/cumulative cost from backend-provided day totals, or change this to a windowed metric (e.g., compute deltas between consecutive snapshots) and rename the label accordingly.

Suggested change
const dailyCostUsd = history.reduce((sum, item) => sum + item.sessionCostUsd, 0);
const dailyCostUsd = Math.max(
0,
(latest.sessionCostUsd || 0) - (history[0]?.sessionCostUsd || 0),
);

Copilot uses AI. Check for mistakes.
Comment on lines 23 to 27
const navItems = [
{ key: "status", num: "1", label: "Status" },
{ key: "tasks", num: "2", label: "Tasks" },
{ key: "agents", num: "3", label: "Agents" },
{ key: "agents", num: "3", label: "Agents" },`r`n { key: "telemetry", num: "4", label: "Telemetry" },
];
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The navItems array has stray `r`n characters between entries, which will cause a syntax error at runtime. Remove the stray characters and add the telemetry tab item as its own element in the array.

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +125
const base = Math.max(1, counts.todo);
return {
stages: FUNNEL_ORDER.map((stage) => ({
...stage,
count: counts[stage.key],
conversionPct: Math.round((counts[stage.key] / base) * 100),
})),
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildTaskFunnel forces base to at least 1. If todo is 0 but later stages are non-zero (e.g., due to partial telemetry), conversionPct can become >100%, which is misleading. Consider using base = counts.todo and returning 0% when base is 0, or base the conversion on total task count when todo is 0.

Copilot uses AI. Check for mistakes.
["1", "status"],
["2", "tasks"],
["3", "agents"],
["3", "agents"],`r`n ["4", "telemetry"],
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The array literal contains stray characters `r`n (looks like an accidental CRLF escape) inside the Map initializer, which makes this module invalid JS and will break navigation + tests. Remove the stray characters and put the ["4", "telemetry"] entry on its own line like the other entries.

Suggested change
["3", "agents"],`r`n ["4", "telemetry"],
["3", "agents"],
["4", "telemetry"],

Copilot uses AI. Check for mistakes.
Comment on lines 9 to 11
import AgentsScreen from "./screens/agents.mjs";
import StatusScreen from "./screens/status.mjs";
import StatusScreen from "./screens/status.mjs";`r`nimport TelemetryScreen from "./screens/telemetry.mjs";
import { readTuiHeaderConfig } from "./lib/header-config.mjs";
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This import line includes stray `r`n characters, which makes the file fail to parse. Remove the stray characters and keep the TelemetryScreen import as a normal separate import statement.

Copilot uses AI. Check for mistakes.
Comment on lines 16 to 20
const SCREENS = {
status: StatusScreen,
tasks: TasksScreen,
agents: AgentsScreen,
agents: AgentsScreen,`r`n telemetry: TelemetryScreen,
};
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SCREENS object literal contains stray `r`n characters before the telemetry entry, which makes the object literal invalid JS. Remove the stray characters and add the telemetry screen as a normal key in the object.

Copilot uses AI. Check for mistakes.
Comment on lines +2137 to +2141
telemetry: Object.freeze({
costPer1kTokensUsd: Object.freeze({
claude: Number.isFinite(Number(configData.telemetry?.costPer1kTokensUsd?.claude)) ? Number(configData.telemetry.costPer1kTokensUsd.claude) : 0.003,
codex: Number.isFinite(Number(configData.telemetry?.costPer1kTokensUsd?.codex)) ? Number(configData.telemetry.costPer1kTokensUsd.codex) : 0.002,
gemini: Number.isFinite(Number(configData.telemetry?.costPer1kTokensUsd?.gemini)) ? Number(configData.telemetry.costPer1kTokensUsd.gemini) : 0.0001,
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

triggerSystem is no longer included in the returned config object (it was replaced by the new telemetry block). triggerSystem is referenced in infra/server code and config-validation tests, so omitting it will break consumers. Add triggerSystem back to the exported config (alongside telemetry, not instead of it).

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +12

function trimHistory(history, length = HISTORY_SECONDS) {
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HISTORY_SECONDS is used as a sample count in trimHistory, but snapshots are collected every 5s. With the current constants, keeping 60 entries actually retains ~5 minutes of history, not 60 seconds. Consider renaming this to HISTORY_SAMPLES or computing the max samples from HISTORY_SECONDS and REFRESH_MS (e.g., ceil(HISTORY_SECONDS*1000/REFRESH_MS)).

Suggested change
function trimHistory(history, length = HISTORY_SECONDS) {
const MAX_HISTORY_SAMPLES = Math.ceil((HISTORY_SECONDS * 1000) / REFRESH_MS);
function trimHistory(history, length = MAX_HISTORY_SAMPLES) {

Copilot uses AI. Check for mistakes.
@jaeko44 jaeko44 added the bosun-pr-bosun-created PR created by Bosun and eligible for Bosun automation label Mar 26, 2026
@github-actions
Copy link
Copy Markdown

Bosun PR classification: Bosun-created.
This PR is tracked by Bosun attachment automation.

  • PR class label: bosun-pr-bosun-created
  • Attach label: bosun-attached (yes, because Bosun-created PRs remain attached regardless of human PR attach mode)
  • Attach mode policy: all
  • Trusted author: no
  • Bosun-created label present: yes
  • Automation scope: Eligible for Bosun repair and merge automation (Bosun-created PR).
  • CI failure signal label: bosun-needs-fix
  • CI failure marker:
  • Trigger: pull_request_target / synchronize

}),
triggerSystem,
workflowWorktreeRecoveryCooldownMin,
workflows,
jaeko44 added 3 commits March 26, 2026 22:59
Co-authored-by: bosun-ve[bot] <262908237+bosun-ve[bot]@users.noreply.github.com>
Co-authored-by: bosun-ve[bot] <262908237+bosun-ve[bot]@users.noreply.github.com>
…t-tui-telemetry-screen-ascii-sparklines-provi

Co-authored-by: bosun-ve[bot] <262908237+bosun-ve[bot]@users.noreply.github.com>
@jaeko44 jaeko44 added bosun-needs-fix Attached PR with failing CI that Bosun should pick up for repair and removed bosun-needs-fix Attached PR with failing CI that Bosun should pick up for repair labels Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bosun-attached Bosun PR attachment marker bosun-needs-fix Attached PR with failing CI that Bosun should pick up for repair bosun-pr-bosun-created PR created by Bosun and eligible for Bosun automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants