Skip to content
This repository was archived by the owner on Sep 23, 2026. It is now read-only.

feat(shell): visual context progress bar with color coding - #1972

Open
xiaoye5200 wants to merge 8 commits into
MoonshotAI:mainfrom
xiaoye5200:feat/progress-bar-context-status
Open

xiaoye5200 wants to merge 8 commits into
MoonshotAI:mainfrom
xiaoye5200:feat/progress-bar-context-status

Conversation

@xiaoye5200

@xiaoye5200 xiaoye5200 commented Apr 21, 2026 •

Copy link
Copy Markdown

Related Issue

N/A (new feature, no prior issue)

Description

Replace the plain-text context: 0.0% status bar indicator with a color-coded Unicode block progress bar, matching the visual style of the claude-hud plugin.

Changes

src/kimi_cli/soul/__init__.py

  • format_context_status now renders Context █░░░░░░░░░ 4% instead of context: 4.0%
  • Uses math.ceil so any non-zero usage always shows at least 1 filled block

src/kimi_cli/ui/theme.py

  • Added context_ok / context_warn / context_critical color fields to ToolbarColors (bright green / amber / red, with dark/light theme variants)
  • Added context_dim_ok / context_dim_warn / context_dim_critical for the empty block color (same hue, darker shade)

src/kimi_cli/ui/shell/prompt.py

  • _render_right_span now returns list[tuple[str, str]] (FormattedText fragments) so each span can carry its own color
  • Filled blocks █, empty blocks ░, and percentage text each get independent color spans

src/kimi_cli/ui/shell/visualize/_blocks.py

  • Replaced self.text.plain = format_context_status(...) with styled Text.append() calls for Rich live-view rendering

Color thresholds (same as claude-hud)

Usage Filled █ Empty ░
< 70% Green Dim green
70–85% Yellow Dim yellow
≥ 85% Red Dim red

Empty blocks use a dimmed variant of the same hue, matching claude-hud's behavior of applying DIM after setting the color.

Example output

image
Context █░░░░░░░░░  4% (11k/262k)   ← green
Context ███████░░░ 72% (189k/262k)  ← yellow
Context █████████░ 92% (241k/262k)  ← red

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Open in Devin Review

devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment on lines +626 to +643
bounded = max(0.0, min(self._context_usage, 1.0))
bar_width = 10
filled = math.ceil(bounded * bar_width) if bounded > 0 else 0
pct = int(bounded * 100)
if bounded >= 0.85:
color = "red"
elif bounded >= 0.70:
color = "yellow"
else:
color = "green"
self.text = Text("Context ", justify="right")
self.text.append("█" * filled, style=color)
self.text.append("░" * (bar_width - filled), style=f"dim {color}")
self.text.append(f" {pct}%", style=color)
if self._max_context_tokens > 0:
used = format_token_count(self._context_tokens)
total = format_token_count(self._max_context_tokens)
self.text.append(f" ({used}/{total})")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Stale tests: _StatusBlock percentage format changed from 42.0% to 42% but tests not updated

The _StatusBlock.update() method in _blocks.py:626-643 now formats the percentage as int(bounded * 100) (producing "42%") instead of using format_context_status which produced "42.0%". Two assertions in tests/ui_and_conv/test_status_block.py will fail: line 16 checks "42.0%" in block.text.plain and line 32 checks "50.0%" in block.text.plain, but the new output contains "42%" and "50%" respectively. These substrings no longer match.

Prompt for agents
Update tests/ui_and_conv/test_status_block.py to match the new percentage format. At line 16, change '42.0%' to '42%'. At line 32, change '50.0%' to '50%'. The new _StatusBlock uses int(bounded * 100) which produces integer percentages without a decimal point.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@xiaoye5200

Copy link
Copy Markdown
Author

Hi @liruifengv @RealKai42 @tempurai @wbxl2000 👋

This PR replaces the plain-text context: 0.0% status bar indicator with a color-coded Unicode block progress bar (e.g. Context █░░░░░░░░░ 4%), using green / yellow / red thresholds at 70% and 85% — matching the visual style of the claude-hud plugin. No breaking changes; existing functionality is preserved.

A tracking issue has been created at #2188. Would appreciate a review when you have a moment — happy to adjust anything!

Thanks 🙏

unknown added 7 commits May 8, 2026 16:49
Replace the plain text `context: 0.0%` status bar indicator with a
block-style progress bar: `Context █░░░░░░░░░ 10%`.

The bar uses 10 Unicode block characters (█ filled, ░ empty) to give
an at-a-glance sense of context usage, followed by an integer
percentage. Token counts are preserved when available:
`Context █████░░░░░ 50% (5.0k/10.0k)`.
Apply green/yellow/red coloring to the context progress bar and
percentage text based on usage thresholds:

  - < 70%  → green  (Context ██░░░░░░░░ 20%)
  - 70–85% → yellow (Context ███████░░░ 70%)
  - ≥ 85%  → red    (Context █████████░ 90%)

Both the bar characters and the percentage digits share the same color.
The "Context" label and optional token counts (e.g. 5.0k/10.0k) remain
in the default toolbar color.

Changes:
- theme.py: add context_ok/warn/critical color fields to ToolbarColors
- prompt.py: _render_right_span now returns FormattedText fragments so
  individual spans can carry independent styles; width calculation
  updated accordingly
- _blocks.py: rebuild Rich Text with styled append instead of setting
  .plain, so Rich renders the color in the streaming agent view
Split the progress bar into two separately styled spans so the filled
blocks (█) use the context color while the empty blocks (░) are dimmed,
matching claude-hud's coloredBar behavior exactly.

Also moves the percentage digit into its own colored span so the full
visual is: Context [colored █…][dim ░…][colored N%] [(tokens)].
Replace fixed grey dim color with per-state dim variants so the empty
░ blocks appear as dark green / dark amber / dark red instead of grey,
matching claude-hud's behavior of dimming within the same color family.

- theme.py: replace context_dim with context_dim_ok/warn/critical
- prompt.py: select matching dim_color alongside color
- _blocks.py: use Rich 'dim {color}' style for empty blocks
@xiaoye5200
xiaoye5200 force-pushed the feat/progress-bar-context-status branch from 04df66e to 142ae60 Compare May 8, 2026 08:50

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 142ae60a98

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

total = format_token_count(max_context_tokens)
return f"context: {bounded:.1%} ({used}/{total})"
return f"context: {bounded:.1%}"
return f"Context {bar} {pct}% ({used}/{total})"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve format_context_status contract or update dependent tests

This changes format_context_status from the previous plain string (context: 42.0% ...) to a new bar format (Context █...), but tests/core/test_status_formatting.py::test_format_context_status_uses_compact_token_counts still asserts the old output. That means this commit introduces a deterministic test-suite regression and will fail make test until the dependent assertions/callers are updated in the same change.

Useful? React with 👍 / 👎.

…in live view

- Replace math.ceil with max(1, round(...)) so 91-99% usage shows 9/10 blocks instead of appearing 100% full
- Mutate self.text in-place instead of reassigning, so Rich Group keeps a stable reference and context bar updates correctly in live mode without requiring a full recomposition
- Update tests to match new integer percentage format and new bar output
@xiaoye5200

Copy link
Copy Markdown
Author

Addressed all review comments from Devin and CodeX:

P1 - Test suite regression (format_context_status format change)
Updated tests/core/test_status_formatting.py to assert the new bar format (Context ████░░░░░░ 42% (3k/10k)).

BUG - Stale _StatusBlock percentage format in tests
Updated tests/ui_and_conv/test_status_block.py: 42.0% -> 42%, 50.0% -> 50%.

BUG - Toolbar tests asserting old context: 0.0% format
Updated tests/ui_and_conv/test_prompt_tips.py to check for Context instead of the old plain-text format.

P2 - math.ceil overfills bar at 91-99%
Replaced math.ceil with max(1, round(...)) in all three locations (soul/__init__.py, prompt.py, _blocks.py). Non-zero usage still shows at least 1 block, but 91% now correctly renders 9/10 blocks instead of appearing completely full.

P2 - self.text reassignment breaks Rich live-view updates
Changed self.text = Text(...) to mutate the existing Text object in-place (self.text.plain = "" then re-append), so the Group keeps a stable reference and the context bar refreshes correctly without a full recomposition.

@liruifengv @RealKai42 @tempurai @wbxl2000 happy to make any further adjustments!

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a584ecd56

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return [("", current_toast.message)]
bounded = max(0.0, min(status.context_usage, 1.0))
bar_width = 10
filled = max(1, round(bounded * bar_width)) if bounded > 0 else 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Replace half-even rounding in context bar block calculation

Using round(bounded * bar_width) makes block fill counts depend on Python’s half-even rounding, so exact x5% values under-report (e.g. 25%→2 blocks, 45%→4 blocks, 85%→8 blocks). This creates a misleading bar progression where adjacent percentages can jump inconsistently and 85% (already critical/red) still shows only 8/10 filled blocks. The issue is user-visible in the toolbar and can miscommunicate how close the session is to context exhaustion.

Useful? React with 👍 / 👎.

This branch has not been deployed

No deployments
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant