Skip to content

feat(gateway): extend opt-in runtime footer metadata - #18188

Open
lancecheney wants to merge 3 commits into
NousResearch:mainfrom
lancecheney:feat/runtime-footer-quota
Open

lancecheney wants to merge 3 commits into
NousResearch:mainfrom
lancecheney:feat/runtime-footer-quota

Conversation

@lancecheney

@lancecheney lancecheney commented May 1, 2026

Copy link
Copy Markdown

What does this PR do?

Extends the existing opt-in gateway runtime footer with provider, account, full-context, quota, underline, and reasoning-effort fields while keeping the feature disabled by default.

The refreshed branch also incorporates @sfire123's quota hardening from lancecheney#1 with authorship preserved:

  • resolve footer config and the live post-fallback credential inside the routed profile scope
  • never carry raw API credentials in agent_result
  • refresh quota in the background with stale-while-revalidate behavior
  • preserve stale snapshots on transient provider failures
  • isolate cache entries by routed profile, provider/endpoint, and credential fingerprint
  • deduplicate in-flight refreshes and bound the cache to 64 entries

Cold quota lookups no longer delay the user's final reply; the first reply may omit quota while the background refresh populates the cache.

Related Issue

No public issue filed. This extends the existing runtime-footer feature and fixes quota correctness/latency across credential pools and multiplexed profiles.

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)
  • 🐛 Bug fix (quota correctness and non-blocking delivery)
  • 📝 Documentation update
  • ✅ Tests

Changes Made

  • agent/account_usage.py
    • Support provider-specific usage and balance snapshots.
    • Use the actual runtime Anthropic credential when supplied.
  • gateway/run.py
    • Resolve footer state inside routed profile scope.
    • Add profile/credential-scoped non-blocking quota refresh and bounded cache.
    • Pass only resolved footer config/snapshot to final rendering.
  • gateway/runtime_footer.py
    • Render provider, account, full context, quota, underline, latency, and reasoning abbreviations.
  • tests/gateway/test_runtime_footer.py
  • tests/gateway/test_runtime_footer_usage_cache.py
  • tests/test_account_usage.py
    • Cover rendering, runtime credential selection, profile isolation, SWR, failure retention, deduplication, and cache bounds.
  • website/docs/user-guide/configuration.md
    • Document the extended opt-in contract and non-blocking quota behavior.

How to Test

Canonical focused suite:

HERMES_HOME=$(mktemp -d) HERMES_PYTHON="$PWD/.venv/bin/python" \
  scripts/run_tests.sh \
  tests/gateway/test_runtime_footer.py \
  tests/gateway/test_runtime_footer_usage_cache.py \
  tests/test_account_usage.py -j 2

Result on current origin/main (4f675cf2f):

74 tests passed, 0 failed

Additional validation:

  • ruff check passed on all changed Python files
  • python -m py_compile passed on runtime files
  • scripts/check-windows-footguns.py passed on all changed Python files
  • git diff --check clean

Configuration

display:
  runtime_footer:
    enabled: true
    fields: [provider, account, model, context, quota, reasoning]
    underline: true

Default behavior remains unchanged: runtime footers are off unless explicitly enabled.

Checklist

Code

  • Commits follow Conventional Commits.
  • The PR remains opt-in and focused on the existing footer feature.
  • Focused canonical tests pass.
  • External contributor authorship is preserved.
  • The complete repository test suite has been run.

Documentation & Housekeeping

  • Runtime-footer configuration documentation is updated.
  • Cross-platform footgun checks pass.
  • No new user-facing environment variable was added.

Screenshots / Logs

Latest refreshed head: 4b8cc177d.

@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 May 1, 2026
@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch 2 times, most recently from 6d5af22 to 2c935b7 Compare May 2, 2026 18:01
@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch 7 times, most recently from 56d5086 to a67dd9d Compare May 9, 2026 02:07
@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch 7 times, most recently from dcbd451 to 573519d Compare May 15, 2026 13:34
@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch 7 times, most recently from fd00ad0 to 7509336 Compare May 22, 2026 10:04
@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch from 7509336 to 7fbef38 Compare May 24, 2026 10:04
@sfire123

Copy link
Copy Markdown

Prepared refreshed replacement PR #98180 on current upstream main.

The original #18188 branch is owned by lancecheney, so I did not rewrite it. #98180 carries the same 7-commit runtime-footer/quota scope, including the hardening from the closed fork PR #1, with head 8c4a71351d.

Validation on the refreshed branch: 82 focused tests passed, ruff passed, py_compile passed, and git diff --check passed.

#18188 is intentionally left open. Maintainers can use #98180 as the current-main review target, or refresh the original branch and close the replacement.

@alt-glitch alt-glitch added the sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades label Aug 29, 2026
@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch from ab55894 to a7da305 Compare August 30, 2026 01:45
@lancecheney

Copy link
Copy Markdown
Author

Refreshed against upstream main and force-pushed.

  • Old head: ab55894dc2b2267f89d89de2917ff16802c257eb
  • New head: a7da3052c7a720425d8204eed550e2c6a4ef08f9
  • Focused validation: uv run --extra dev pytest tests/gateway/test_runtime_footer.py tests/gateway/test_runtime_footer_usage_cache.py tests/agent/test_account_usage.py tests/test_account_usage.py -q -o addopts=82 passed in 5.02s
  • Additional validation: python -m compileall -q agent/account_usage.py gateway/run.py gateway/runtime_footer.py — passed; uv run ruff check agent/account_usage.py gateway/run.py gateway/runtime_footer.py tests/gateway/test_runtime_footer.py tests/gateway/test_runtime_footer_usage_cache.py tests/agent/test_account_usage.py tests/test_account_usage.pyAll checks passed
  • git diff --check — passed

@lancecheney

Copy link
Copy Markdown
Author

Follow-up refresh: upstream main advanced while the other PRs were being updated, so this branch was rebased once more onto 60a4442826ee063bf39aa26ebac2af0f347cfce0.

  • Previous refreshed head: a7da3052c7a720425d8204eed550e2c6a4ef08f9
  • Final head: 321539aa1b0cd96d86430a1e6d1175f17a55dc59
  • Preserved PR commit count: 7
  • Focused validation: runtime-footer/account-usage suite → 82 passed
  • ruff check and python -m py_compile on changed Python files: passed
  • git diff --check origin/main...HEAD: clean

@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch from a7da305 to 321539a Compare August 30, 2026 01:51
@lancecheney

lancecheney commented Aug 30, 2026

Copy link
Copy Markdown
Author

@sfire123 Thanks for preparing the refreshed branch.

I’ve now rebased #18188 onto the current upstream main, preserving the existing 7-commit scope. The focused runtime-footer/account-usage suite still passes with 82 tests, and the PR is currently mergeable.

I also maintain a downstream integration that pulls upstream main daily and continuously carries and exercises this PR. Going forward, I plan to refresh the upstream PR when a relevant conflict, behavioral change, or new upstream feature requires adaptation, when a maintainer requests it, or when a new Hermes release warrants revalidation.

Since Hermes main changes continuously, I don’t plan to force-push the PR solely to follow routine unrelated commits when the feature remains compatible and the test suite continues to pass.

@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch from 321539a to a2584f2 Compare September 1, 2026 11:09
@lancecheney

Copy link
Copy Markdown
Author

Refreshed onto current upstream main (18a76be124d7c16ed98b629a358b23fef76a7f46).

  • Previous head: 321539aa1b0cd96d86430a1e6d1175f17a55dc59
  • New head: a2584f276dfd2cb9eef64731efeeb4b564a82065
  • Rebase applied cleanly (7 commits).
  • Validation: runtime-footer/account-usage focused suite → 82 passed.

@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch 2 times, most recently from fcc8b1d to 0582fc6 Compare September 5, 2026 12:02
@alt-glitch alt-glitch removed the area/billing Account usage, credit usage, billing (cross-cutting) label Sep 5, 2026
@sfire123

sfire123 commented Sep 5, 2026

Copy link
Copy Markdown

The latest force-push (0582fc6244) regressed the live runtime wiring and currently makes the new account/quota footer fields non-functional, even though the formatter/cache unit tests pass.

Blocking path:

  • gateway/run_turn_runner.py:1657-1680 builds the result metadata with only token counts, model, and context_length; it does not carry provider, base_url, a resolved usage snapshot, or the resolved footer config.
  • gateway/run_turn.py:1466-1484 then reads provider/base_url/api_key/account_usage from that result. For the normal turn result those keys are absent, so get_cached(None, ...) reaches the empty-provider guard in gateway/runtime_footer_usage.py:73-75 and no refresh is ever scheduled. provider, account, and quota therefore render nothing in the real gateway path.
  • Fetching only when "quota" is present also leaves an account-only field unable to resolve its account/plan label.

Please restore the compatible hardening shape that was previously incorporated from f5770e1b9, adapted to the current run_turn_runner.py split:

  1. Inside TurnRunner.run_sync() (while the routed profile scope is active), resolve the effective footer config and whether {account, quota} needs usage.
  2. Read the actual post-turn agent's provider/base URL/runtime credential there, call the non-blocking cache there (or pass an explicitly captured hermes_home), and return only the non-secret provider/base URL, usage snapshot, resolved config, and reasoning label.
  3. Do not add the raw API key to agent_result; gateway/run_turn.py should consume the pre-resolved snapshot/config instead.
  4. Add a real producer→consumer regression test that proves a configured quota field schedules refresh with the active credential and routed profile, and that api_key is absent from the returned result.

There is also a documentation regression from the earlier review: website/docs/user-guide/configuration.md:2068-2088 and the Chinese counterpart still document only the legacy fields/latency and omit provider, account, context, quota, reasoning, and underline.

I verified current head with the canonical targeted suite: 78 passed, 0 failed (test_runtime_footer.py, test_runtime_footer_usage_cache.py, test_account_usage.py), plus git diff --check and the Windows-footgun scan. The green suite currently does not exercise this missing live wiring. The legacy defaults remain correct (model, context_pct, cwd), and account/quota should remain opt-in and functional.

@lancecheney

Copy link
Copy Markdown
Author

Thanks for the detailed report. Addressed in c4baa58148dec6e4216b46aec0bb307edc689b8a.

The fix now:

  • Resolves the effective runtime-footer config and usage metadata in TurnRunner.run_sync() while the routed profile scope is active.
  • Uses the live agent provider, base URL, credential, and captured HERMES_HOME for the non-blocking usage cache.
  • Supports both account-only and quota footer fields.
  • Keeps the raw API key out of agent_result.
  • Passes the resolved footer config directly to the renderer.
  • Adds producer-to-consumer wiring regression coverage.
  • Documents the extended footer fields and underline.

Validation:

  • Runtime-footer/account-usage suite: 84 passed
  • Ruff: passed
  • py_compile: passed
  • git diff --check: passed

The PR head is now c4baa58148dec6e4216b46aec0bb307edc689b8a. Could you please re-review the updated branch?

@sfire123

sfire123 commented Sep 5, 2026

Copy link
Copy Markdown

Re-reviewed the updated branch at c4baa58148dec6e4216b46aec0bb307edc689b8a. No blocking findings.

The hardening invariants remain intact:

  • account and quota are opt-in and both trigger the non-blocking stale-while-revalidate path.
  • The default footer remains disabled with the unchanged default fields (model, context_pct, cwd).
  • Effective footer config, routed HERMES_HOME, and the live agent credential are captured while the turn's profile scope is active.
  • Cache identity remains profile/provider/base-URL/credential scoped, with only a credential digest stored in the key.
  • The raw API key is used only to schedule/key the refresh and is not returned in agent_result.
  • The resolved profile-specific footer config is passed to the renderer, so the later unscoped config fallback does not override it.

Local verification on this exact head:

  • Canonical targeted suite: 84 passed (test_runtime_footer.py, test_runtime_footer_usage_cache.py, test_runtime_footer_runner_wiring.py, both account-usage test files).
  • Additional producer→consumer/default-invariant exercise: passed; an account + quota footer rendered Pro · 5h 75%, with no API key in the metadata result.
  • Ruff: passed.
  • py_compile: passed.
  • Windows-footgun scan: passed (10 changed Python files).
  • git diff --check origin/main...HEAD: passed.

@sfire123

sfire123 commented Sep 9, 2026

Copy link
Copy Markdown

Prepared a conflict-resolution refresh in lancecheney#2 (head cb38c7662289e5f07e9f0706c20ce82dc23f8d3d).

It merges upstream main at facb9eb4f17735a7d70f28cb6a26d95ffdc4c105 into the existing PR head and resolves the sole content conflict in gateway/run_turn_runner.py by retaining both the profile-safe quota-footer helper and upstream _ExecApprovalDeclined/egress-decline protection.

Verified locally: 143 passed, 0 failed across the footer/account-usage and egress-decline suites; Ruff, Windows-footgun scan, and the feature diff whitespace check passed. Account/quota rendering, opt-in defaults, non-blocking refresh, and no raw API key in result metadata are preserved.

The follow-up PR is mergeable. I cannot push directly to this branch; please merge that PR normally (not squash) or fast-forward to its head so the upstream-main ancestry is retained and this PR's conflict clears. GitHub-hosted checks have not reported any runs on the follow-up yet.

@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch from 3e5500a to 6c2ed05 Compare September 10, 2026 07:00
@lancecheney

Copy link
Copy Markdown
Author

Thanks for preparing the conflict-resolution refresh in lancecheney#2 — much appreciated, and your read of the conflict was spot-on.

I've resolved it with the same approach (retaining both _ExecApprovalDeclined/egress-decline protection and the profile-safe quota-footer helper), but rebased onto current upstream main (cfdbbb6e3) rather than merging, so the branch carries no merge commit and is based on the latest 371 upstream commits past your baseline facb9eb4f.

  • New head: 6c2ed05ada (force-pushed; your PR Support passing morph snapshot id #2 head cb38c76622 is superseded)
  • All three original commits replayed cleanly with the conflict fixed in gateway/run_turn_runner.py
  • Validation: footer/turn-runner suites — 89 passed (runtime_footer, runner wiring, usage cache, mid-run footer command, turn context/overrides)

The follow-up PR #2 can stay closed; nothing from it is lost since the resolution is equivalent. Thanks again for the two thorough reviews — the invariants you flagged (opt-in account/quota, non-blocking refresh, no raw API key in result metadata) are all preserved.

@lancecheney
lancecheney force-pushed the feat/runtime-footer-quota branch from d16ba48 to 310f555 Compare September 15, 2026 08:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles area/profiles Multi-profile isolation, HERMES_HOME scoping area/usage-cost Token accounting, usage reporting, billing, cost tracking comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/gateway Gateway runner, session dispatch, delivery needs-decision Awaiting maintainer decision before any implementation P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users 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.

5 participants