Skip to content

feat(gateway): add /context command for a detailed context-window view - #52184

Closed
CharlesMcquade wants to merge 1 commit into
NousResearch:mainfrom
CharlesMcquade:add-context-command
Closed

feat(gateway): add /context command for a detailed context-window view#52184
CharlesMcquade wants to merge 1 commit into
NousResearch:mainfrom
CharlesMcquade:add-context-command

Conversation

@CharlesMcquade

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a dedicated /context gateway slash command (alias /ctx) that gives a full context-window view, and clarifies the /status line that users routinely misread as their current context size.

/status already shows a one-line Context: used / total (pct) summary. /context is the deep view for anyone who wants to understand and tune their context budget — and it answers the recurring "why is that token number millions?" confusion directly:

🧠 Context Window

Model: `zai/glm-5.1`
Window: 200,000 tokens
In use: 47,231 / 200,000 (24%)
██████░░░░░░░░░░░░░░░░░░
Headroom to limit: 152,769 tokens

Auto-compresses at: 100,000 (50%) — 52,769 to go
Compressions this session: 2
Last compression freed: 63% of context

Cache (session)
Read from cache: 2,900,000
Written to cache: 48,000
Hit rate: 88% of input served from cache

Session totals (cumulative across 47 API calls)
Input 410,000 · Output 38,000 · Reasoning 12,000
Total billed: 3,158,641
Throughput, not context size — each call re-sends the window above.

All numbers come straight from the agent's context_compressor. It resolves the live agent mid-turn (_running_agents) and the cached agent between turns (_agent_cache), with a rough transcript estimate when no agent is resident yet — mirroring the existing /usage resolution pattern.

It also relabels the /status cumulative-tokens line. It read Cumulative API tokens (re-sent each call) and was widely mistaken for the current context size (it's actually a lifetime billing total dominated by re-counted cache reads). It now reads Lifetime tokens billed: … (not your current context size; use /context).

Related Issue

Fixes #

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

Changes Made

  • gateway/slash_commands.py — new _handle_context_command (live → cached → transcript-estimate fallback).
  • gateway/run.py — dispatch in both the mid-turn dedicated-handler block and the cold path, so /context works while an agent is running (the most useful time) and between turns.
  • hermes_cli/commands.py — register /context (alias /ctx) and add it to ACTIVE_SESSION_BYPASS_COMMANDS.
  • locales/en.yamlgateway.context.* strings; reworded gateway.status.tokens.
  • tests/gateway/test_status_command.py — four /context tests (live window, over-threshold flag, transcript fallback, no-data) plus updated /status label assertions.

No new config keys; no provider/account calls (read-only, off the billing path); English-only strings (other locales fall back to English, per agent/i18n.py).

How to Test

  1. In a gateway chat (Telegram/Discord/etc.), send a message so an agent runs, then send /context (or /ctx) — verify the gauge, threshold, compression, cache, and throughput lines.
  2. Send /context again mid-turn (while the agent is responding) — it returns live numbers rather than the "busy" reply.
  3. Send /context in a brand-new session with no agent yet — verify the transcript-estimate fallback / no-data message.
  4. Send /status — verify the tokens line now reads Lifetime tokens billed: ….
  5. scripts/run_tests.sh tests/gateway/test_status_command.py -q

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this feature
  • I've run pytest tests/ -q and all tests pass — added tests are statically validated (py_compile) and the handler output was verified against a live gateway, but I was unable to run the suite in my environment; CI will exercise it.
  • I've added tests for my changes
  • I've tested on my platform: macOS (live gateway)

Documentation & Housekeeping

  • I've updated relevant documentation (docstrings) — command is self-describing via its CommandDef registry entry
  • N/A — no config keys added/changed
  • N/A — no architecture/workflow changes
  • Cross-platform: pure-Python string formatting, no platform-specific calls

🤖 Generated with Claude Code

@alt-glitch alt-glitch added type/feature New feature or request comp/gateway Gateway runner, session dispatch, delivery comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have labels Jun 24, 2026
@whoislikemiha

whoislikemiha commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Reviewed this PR end-to-end. The feature shape looks good and the rest of the diff is solid: command registration, mid-turn gateway dispatch, localization strings, and targeted coverage all line up with the existing gateway patterns.

I found one current-main merge issue: _handle_context_command() calls self._session_db.get_session(...) synchronously, but current main wraps the DB as AsyncSessionDB, so the between-turn /context gauge falls through to No context data available yet and pytest emits an un-awaited coroutine warning.

I tried to push a small maintainer fix directly to this branch, but GitHub denied my token push to the fork even though maintainer edits are enabled. I pushed the fix here instead: CharlesMcquade#1

The fix is intentionally minimal:

  • await/handle awaitable get_session() results in /context
  • ignore the post-compression last_prompt_tokens = -1 sentinel before choosing the displayed context usage
  • add regression coverage for the sentinel path and keep the between-turn gauge test compatible with both sync and async DB doubles

Verification I ran:

  • PR head with the fix: tests/gateway/test_status_command.py -> 23 passed
  • local merge into current NousResearch/hermes-agent main: same targeted file -> 23 passed

Once that small fix lands on this PR branch, I’m satisfied with the PR and would approve.

@CharlesMcquade

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review and the fix @whoislikemiha — landed it in 7737918 (co-authored with you). The async get_session() handling, the -1 sentinel skip, and the regression coverage are all in. Targeted suite passes (tests/gateway/test_status_command.py → 23 passed). Ready for your approval whenever you get a chance.

@teknium1 teknium1 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.

Thanks for the focused gateway command and the follow-up async SessionDB/sentinel fixes. /context is not present on current main, so the feature remains independently useful, but it needs two current-main adjustments before salvage.

Problems

  • gateway/slash_commands.py:3618 and :3748 call synchronous session_store methods from the async handler. Current main's 9d38a2309 enforces async_session_store for this boundary; current /usage awaits it at gateway/slash_commands.py:4064-4065.
  • gateway/slash_commands.py:3714-3726 restores cache read/write and hit-rate output. Commit 446b8e239 intentionally removed cache reporting from every user-facing surface because providers that omit cached-token details produce misleading values.

Suggested changes

  • Use awaited async_session_store calls for the session entry and transcript fallback.
  • Keep the context gauge/compression view, but remove cache-hit reporting and its strings/tests.

Automated hermes-sweeper review.

Comment thread gateway/slash_commands.py Outdated
from gateway.run import _AGENT_PENDING_SENTINEL
source = event.source
session_key = self._session_key_for_source(source)
session_entry = self.session_store.get_or_create_session(source)

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.

Current main requires async gateway handlers to use await self.async_session_store.get_or_create_session(source) (commit 9d38a2309); calling the synchronous store here bypasses the enforced off-loop boundary. Apply the same change to the transcript fallback below.

Comment thread gateway/slash_commands.py Outdated
if savings is not None:
lines.append(t("gateway.context.last_savings", savings=f"{savings:.0f}"))

cache_read = getattr(agent, "session_cache_read_tokens", 0) or 0

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.

Please do not restore cache read/write or hit-rate reporting. Current main removed these values from every user-facing surface in 446b8e239 because providers that omit cached-token details produce misleading cache results.

A dedicated /context (alias /ctx) gateway slash command that gives a full
context-window view with:

- Usage gauge: visual bar + fraction + percentage + headroom
- Auto-compression threshold and how far away it is
- Compression count and how much the last one freed
- Cumulative session throughput (explicitly labelled as throughput,
  NOT context size — each call re-sends the window)
- Cascading fallback: running agent → cached agent → SessionStore metadata
  → rough transcript estimate

Not included (per current-main design):
- Cache reporting removed: commit 446b8e2 intentionally removed cache
  reporting from user-facing surfaces because providers that omit cached-token
  details produce misleading values
- Sync DB calls replaced with async_session_store (current main requires
  AsyncSessionStore with await)

Also rewords the /status tokens line from 'Cumulative API tokens (re-sent
each call)' to 'Lifetime tokens billed: ... (not your current context size;
use /context)' to reduce the recurring confusion that the cumulative figure
is the current context window.

Fixes salvation of PR NousResearch#52184 (salvage commit replaces a 12K-commit-behind
fork branch with a fresh implementation against current main, incorporating
reviewer feedback from @whoislikemiha and the hermes-sweeper).
@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026
@CharlesMcquade

Copy link
Copy Markdown
Contributor Author

Both points from the review are already addressed in the current branch head (656856e):

  1. Async session store_handle_context_command uses await self.async_session_store.get_or_create_session(source) for the session lookup and await self.async_session_store.load_transcript(...) for the transcript fallback. Both go through the async facade, not the sync store.

  2. No cache read/write or hit-rate reporting — the command does not read session_cache_read_tokens, session_cache_write_tokens, or any hit-rate fields. The test stub includes those attributes on the agent but the command code never touches them, and the tests explicitly assert Cache read, Cache write, Cache hit, and Hit rate are absent from the output.

All 21 tests in test_status_command.py pass (including 4 new /context tests). Ready for another look.

teknium1 pushed a commit that referenced this pull request Jul 26, 2026
A dedicated /context (alias /ctx) gateway slash command that gives a full
context-window view with:

- Usage gauge: visual bar + fraction + percentage + headroom
- Auto-compression threshold and how far away it is
- Compression count and how much the last one freed
- Cumulative session throughput (explicitly labelled as throughput,
  NOT context size — each call re-sends the window)
- Cascading fallback: running agent → cached agent → SessionStore metadata
  → rough transcript estimate

Not included (per current-main design):
- Cache reporting removed: commit 446b8e2 intentionally removed cache
  reporting from user-facing surfaces because providers that omit cached-token
  details produce misleading values
- Sync DB calls replaced with async_session_store (current main requires
  AsyncSessionStore with await)

Also rewords the /status tokens line from 'Cumulative API tokens (re-sent
each call)' to 'Lifetime tokens billed: ... (not your current context size;
use /context)' to reduce the recurring confusion that the cumulative figure
is the current context window.

Fixes salvation of PR #52184 (salvage commit replaces a 12K-commit-behind
fork branch with a fresh implementation against current main, incorporating
reviewer feedback from @whoislikemiha and the hermes-sweeper).
teknium1 added a commit that referenced this pull request Jul 26, 2026
Extends the cherry-picked /context command (PR #52184) and prompt-size
attribution helpers (PR #66656) into one visual context view across
surfaces, and absorbs the per-component budget-visibility goal of the
/tokens proposal (PR #48470):

- agent/context_breakdown.py: pure renderers over the existing payload —
  a 5x20 glyph block grid (1 cell ~= 1% of the model window), an
  'Estimated usage by category' table with free space, and expanded
  per-skill / per-toolset listings via compute_context_details(), which
  reuses the prompt-size attribution mechanism (skills index-line bytes +
  registry tool->toolset map) converted to the same chars/4 heuristic.
- cli.py: /context [all] renders grid + category table (+ expanded
  listings) from the live agent and in-memory conversation history.
- gateway/slash_commands.py: /context appends the plain-text category
  table (no grid — monospace not guaranteed on messaging platforms);
  /context all adds the expanded listings. Fail-open: breakdown errors
  never break the gauge.
- hermes_cli/commands.py: /context gains the 'all' subcommand; /version
  demoted to /hermes version on Slack to keep the 50-slash cap.
- tests: renderer unit tests against synthetic payloads, registry test,
  gateway /context + /context all + failure-degradation handler tests.
- docs: slash-commands reference + CLI guide entries.

Read-only and locally computed: no provider calls, no prompt-cache impact.

Co-authored-by: RemyFevry <29257684+RemyFevry@users.noreply.github.com>
Co-authored-by: joelbrilliant <joelbrilliant1@gmail.com>
Co-authored-by: CharlesMcquade <6466275+CharlesMcquade@users.noreply.github.com>
teknium1 pushed a commit that referenced this pull request Jul 27, 2026
A dedicated /context (alias /ctx) gateway slash command that gives a full
context-window view with:

- Usage gauge: visual bar + fraction + percentage + headroom
- Auto-compression threshold and how far away it is
- Compression count and how much the last one freed
- Cumulative session throughput (explicitly labelled as throughput,
  NOT context size — each call re-sends the window)
- Cascading fallback: running agent → cached agent → SessionStore metadata
  → rough transcript estimate

Not included (per current-main design):
- Cache reporting removed: commit 446b8e2 intentionally removed cache
  reporting from user-facing surfaces because providers that omit cached-token
  details produce misleading values
- Sync DB calls replaced with async_session_store (current main requires
  AsyncSessionStore with await)

Also rewords the /status tokens line from 'Cumulative API tokens (re-sent
each call)' to 'Lifetime tokens billed: ... (not your current context size;
use /context)' to reduce the recurring confusion that the cumulative figure
is the current context window.

Fixes salvation of PR #52184 (salvage commit replaces a 12K-commit-behind
fork branch with a fresh implementation against current main, incorporating
reviewer feedback from @whoislikemiha and the hermes-sweeper).
teknium1 added a commit that referenced this pull request Jul 27, 2026
Extends the cherry-picked /context command (PR #52184) and prompt-size
attribution helpers (PR #66656) into one visual context view across
surfaces, and absorbs the per-component budget-visibility goal of the
/tokens proposal (PR #48470):

- agent/context_breakdown.py: pure renderers over the existing payload —
  a 5x20 glyph block grid (1 cell ~= 1% of the model window), an
  'Estimated usage by category' table with free space, and expanded
  per-skill / per-toolset listings via compute_context_details(), which
  reuses the prompt-size attribution mechanism (skills index-line bytes +
  registry tool->toolset map) converted to the same chars/4 heuristic.
- cli.py: /context [all] renders grid + category table (+ expanded
  listings) from the live agent and in-memory conversation history.
- gateway/slash_commands.py: /context appends the plain-text category
  table (no grid — monospace not guaranteed on messaging platforms);
  /context all adds the expanded listings. Fail-open: breakdown errors
  never break the gauge.
- hermes_cli/commands.py: /context gains the 'all' subcommand; /version
  demoted to /hermes version on Slack to keep the 50-slash cap.
- tests: renderer unit tests against synthetic payloads, registry test,
  gateway /context + /context all + failure-degradation handler tests.
- docs: slash-commands reference + CLI guide entries.

Read-only and locally computed: no provider calls, no prompt-cache impact.

Co-authored-by: RemyFevry <29257684+RemyFevry@users.noreply.github.com>
Co-authored-by: joelbrilliant <joelbrilliant1@gmail.com>
Co-authored-by: CharlesMcquade <6466275+CharlesMcquade@users.noreply.github.com>
teknium1 pushed a commit that referenced this pull request Jul 27, 2026
A dedicated /context (alias /ctx) gateway slash command that gives a full
context-window view with:

- Usage gauge: visual bar + fraction + percentage + headroom
- Auto-compression threshold and how far away it is
- Compression count and how much the last one freed
- Cumulative session throughput (explicitly labelled as throughput,
  NOT context size — each call re-sends the window)
- Cascading fallback: running agent → cached agent → SessionStore metadata
  → rough transcript estimate

Not included (per current-main design):
- Cache reporting removed: commit 446b8e2 intentionally removed cache
  reporting from user-facing surfaces because providers that omit cached-token
  details produce misleading values
- Sync DB calls replaced with async_session_store (current main requires
  AsyncSessionStore with await)

Also rewords the /status tokens line from 'Cumulative API tokens (re-sent
each call)' to 'Lifetime tokens billed: ... (not your current context size;
use /context)' to reduce the recurring confusion that the cumulative figure
is the current context window.

Fixes salvation of PR #52184 (salvage commit replaces a 12K-commit-behind
fork branch with a fresh implementation against current main, incorporating
reviewer feedback from @whoislikemiha and the hermes-sweeper).
teknium1 added a commit that referenced this pull request Jul 27, 2026
Extends the cherry-picked /context command (PR #52184) and prompt-size
attribution helpers (PR #66656) into one visual context view across
surfaces, and absorbs the per-component budget-visibility goal of the
/tokens proposal (PR #48470):

- agent/context_breakdown.py: pure renderers over the existing payload —
  a 5x20 glyph block grid (1 cell ~= 1% of the model window), an
  'Estimated usage by category' table with free space, and expanded
  per-skill / per-toolset listings via compute_context_details(), which
  reuses the prompt-size attribution mechanism (skills index-line bytes +
  registry tool->toolset map) converted to the same chars/4 heuristic.
- cli.py: /context [all] renders grid + category table (+ expanded
  listings) from the live agent and in-memory conversation history.
- gateway/slash_commands.py: /context appends the plain-text category
  table (no grid — monospace not guaranteed on messaging platforms);
  /context all adds the expanded listings. Fail-open: breakdown errors
  never break the gauge.
- hermes_cli/commands.py: /context gains the 'all' subcommand; /version
  demoted to /hermes version on Slack to keep the 50-slash cap.
- tests: renderer unit tests against synthetic payloads, registry test,
  gateway /context + /context all + failure-degradation handler tests.
- docs: slash-commands reference + CLI guide entries.

Read-only and locally computed: no provider calls, no prompt-cache impact.

Co-authored-by: RemyFevry <29257684+RemyFevry@users.noreply.github.com>
Co-authored-by: joelbrilliant <joelbrilliant1@gmail.com>
Co-authored-by: CharlesMcquade <6466275+CharlesMcquade@users.noreply.github.com>
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
A dedicated /context (alias /ctx) gateway slash command that gives a full
context-window view with:

- Usage gauge: visual bar + fraction + percentage + headroom
- Auto-compression threshold and how far away it is
- Compression count and how much the last one freed
- Cumulative session throughput (explicitly labelled as throughput,
  NOT context size — each call re-sends the window)
- Cascading fallback: running agent → cached agent → SessionStore metadata
  → rough transcript estimate

Not included (per current-main design):
- Cache reporting removed: commit 446b8e2 intentionally removed cache
  reporting from user-facing surfaces because providers that omit cached-token
  details produce misleading values
- Sync DB calls replaced with async_session_store (current main requires
  AsyncSessionStore with await)

Also rewords the /status tokens line from 'Cumulative API tokens (re-sent
each call)' to 'Lifetime tokens billed: ... (not your current context size;
use /context)' to reduce the recurring confusion that the cumulative figure
is the current context window.

Fixes salvation of PR NousResearch#52184 (salvage commit replaces a 12K-commit-behind
fork branch with a fresh implementation against current main, incorporating
reviewer feedback from @whoislikemiha and the hermes-sweeper).
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
Extends the cherry-picked /context command (PR NousResearch#52184) and prompt-size
attribution helpers (PR NousResearch#66656) into one visual context view across
surfaces, and absorbs the per-component budget-visibility goal of the
/tokens proposal (PR NousResearch#48470):

- agent/context_breakdown.py: pure renderers over the existing payload —
  a 5x20 glyph block grid (1 cell ~= 1% of the model window), an
  'Estimated usage by category' table with free space, and expanded
  per-skill / per-toolset listings via compute_context_details(), which
  reuses the prompt-size attribution mechanism (skills index-line bytes +
  registry tool->toolset map) converted to the same chars/4 heuristic.
- cli.py: /context [all] renders grid + category table (+ expanded
  listings) from the live agent and in-memory conversation history.
- gateway/slash_commands.py: /context appends the plain-text category
  table (no grid — monospace not guaranteed on messaging platforms);
  /context all adds the expanded listings. Fail-open: breakdown errors
  never break the gauge.
- hermes_cli/commands.py: /context gains the 'all' subcommand; /version
  demoted to /hermes version on Slack to keep the 50-slash cap.
- tests: renderer unit tests against synthetic payloads, registry test,
  gateway /context + /context all + failure-degradation handler tests.
- docs: slash-commands reference + CLI guide entries.

Read-only and locally computed: no provider calls, no prompt-cache impact.

Co-authored-by: RemyFevry <29257684+RemyFevry@users.noreply.github.com>
Co-authored-by: joelbrilliant <joelbrilliant1@gmail.com>
Co-authored-by: CharlesMcquade <6466275+CharlesMcquade@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants