Skip to content

feat(gateway): add per-turn token usage footer to gateway responses - #17592

Open
hyofeng wants to merge 4 commits into
NousResearch:mainfrom
hyofeng:feat/gateway-token-usage
Open

feat(gateway): add per-turn token usage footer to gateway responses#17592
hyofeng wants to merge 4 commits into
NousResearch:mainfrom
hyofeng:feat/gateway-token-usage

Conversation

@hyofeng

@hyofeng hyofeng commented Apr 29, 2026

Copy link
Copy Markdown

Summary

Add automatic per-turn token usage reporting to all gateway responses. Every agent reply now ends with a compact inline-code usage footer.

Changes

  • Add _snapshot_agent_token_usage(), _diff_agent_token_usage(), _build_gateway_usage_line() utilities for tracking and formatting token usage
  • Append usage:t=<total> i=<input> o=<output> footer after every gateway response
  • Support cached tokens ((+ N c)) and reasoning tokens ((r N)) display
  • Track per-turn deltas by snapshotting token counters before/after each agent run
  • Remove stale vercel_runtime env-var mapping

Test Plan

  • Verify usage line appears on CLI responses
  • Verify usage line appears on gateway platform responses (Telegram, Discord, WeChat etc.)
  • Verify cached token display works with prompt-caching providers
  • Verify reasoning token display works with reasoning models

- Add token usage snapshot/diff utilities in gateway/run.py
- Append inline-code usage line (t=/i=/o=) after every gateway reply
- Support cached tokens and reasoning tokens display
- Remove stale vercel_runtime env-var mapping
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery labels Apr 29, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Related to #15170, #11394, #16800, #17026 — multiple competing token/metadata footer PRs. #17026 already merged with opt-in runtime-metadata footer.

hyofeng added 3 commits April 30, 2026 02:40
Move token-usage rendering from inline run.py logic into
gateway/runtime_footer.py as a new 'tokens' field, aligning with
the merged NousResearch#17026 runtime-footer architecture.

Changes:
- runtime_footer.py: add _render_token_usage(), _format_usage_int();
  support 'tokens' field in format_runtime_footer() and
  build_footer_line()
- run.py: keep _snapshot_agent_token_usage() / _diff_agent_token_usage()
  for per-turn delta tracking; pass token_usage through
  build_footer_line(); add token_usage to approval-path result dicts

Usage: set display.runtime_footer.fields to include 'tokens'
e.g. fields: [model, context_pct, cwd, tokens]
agent.run_conversation() return value does not include input/output
token counters.  Snapshot agent session counters before and after
the run to compute accurate per-turn deltas.

Previous fallback (result.get('input_tokens')) always returned 0.
- Strip agent's self-reported usage:t=... line before appending gateway
  runtime footer to avoid duplicate token numbers in responses
- Wrap runtime footer in backticks for consistent inline-code formatting

@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 adapting the proposal to the existing runtime-footer surface.

Problems

  • gateway/runtime_footer.py:178 wraps every existing footer in backticks, not just token data. Current main has exact plain-text formatter contracts in tests/gateway/test_runtime_footer.py:70, :95, :127, :137, and :147; this diff does not update that coverage.
  • The new tokens field remains outside the default field list, while the footer remains disabled by default. That is compatible with the opt-in design from #17026, but it does not match the PR's “every reply” description. website/docs/user-guide/configuration.md:1483 also lists only model, context_pct, and cwd.
  • Current main's proxy branch (gateway/run.py:16899-16910) returns no token counters (gateway/run.py:16795-16806), so local snapshots alone cannot provide the proposed value for every gateway response.

Suggested changes

  • Preserve the existing formatter contract or update its exact-output tests deliberately.
  • Add token rendering, per-turn delta, streaming, and proxy-mode coverage; document tokens as an opt-in field.
  • Reapply the result plumbing to current gateway/run.py::_run_agent_inner, whose local result assembly is now at gateway/run.py:18789-19064.

Automated hermes-sweeper review.

Comment thread gateway/runtime_footer.py
if not parts:
return ""
return _SEP.join(parts)
return f"`{_SEP.join(parts)}`"

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.

This changes all pre-existing runtime-footer output to inline code, not only the new token field. Current main has exact plain-text output contracts in tests/gateway/test_runtime_footer.py (for example line 70); preserve that contract or update the corresponding tests and documentation deliberately.

Comment thread gateway/runtime_footer.py
rel = _home_relative_cwd(cwd or os.environ.get("TERMINAL_CWD", ""))
if rel:
parts.append(rel)
elif field == "tokens":

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.

tokens is opt-in because _DEFAULT_FIELDS remains unchanged, but this PR adds no configuration documentation or renderer tests for the new field. Please document the required fields: [..., tokens] configuration and cover token-only, mixed, zero, cache, and reasoning cases.

Comment thread gateway/run.py
_approval_session_key = session_key or ""
_approval_session_token = set_current_session_key(_approval_session_key)
register_gateway_notify(_approval_session_key, _approval_notify_sync)
_usage_before = _snapshot_agent_token_usage(agent)

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.

This snapshots only the local AIAgent path. The gateway also has a proxy execution branch on current main (_run_agent_inner_run_agent_via_proxy) that returns no counters, so define whether proxy responses propagate remote usage or intentionally omit the tokens field before claiming coverage for all gateway replies.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state 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 area/usage-cost Token accounting, usage reporting, billing, cost tracking labels Jul 12, 2026
vanhci pushed a commit to vanhci/hermes-agent that referenced this pull request Aug 11, 2026
…fields

Extend display.runtime_footer with token-count and reasoning-effort fields:
- tokens_in / tokens_out: compact k-formatted (15.9k) per-turn token usage
- effort: agent reasoning effort label from agent.reasoning_effort
- context_pct now renders as 'ctx N%' (aligns with cc-connect style)
- Feishu renders the footer as a card-style quote block (divider + '> ')
  instead of plain inline text

All new fields are opt-in: the default field set is unchanged.
Related: NousResearch#19922, NousResearch#17592, NousResearch#64526, NousResearch#28978
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/usage-cost Token accounting, usage reporting, billing, cost tracking 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 sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants