feat: provider-agnostic balance/credits display in Hermes Desktop - #51182
feat: provider-agnostic balance/credits display in Hermes Desktop#51182DavidMetcalfe wants to merge 1 commit into
Conversation
7414a99 to
bac2ef3
Compare
Known Limitation: Hardcoded low-balance thresholdThe Desktop statusbar uses a hardcoded For non-USD providers (EUR, GBP) or providers that report in abstract credits (e.g. OpenRouter's credit system), this threshold will produce incorrect warnings. The Future improvement: Make the low-balance threshold configurable per-provider via |
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment (high surface area)
This PR adds a provider-agnostic balance/credits display to Hermes Desktop across 21 files (+2334 lines). The scope is broad — changes touch MCP client setup, balance calculation, desktop UI components, and configuration handling. Given the size and multi-area nature, human review is recommended before merging.
Observations
- The
api_key_envfield appears to be a config lookup (not a hardcoded credential) — safe. - The banner error message on line 1401 is a UI string literal, not a security issue.
- The
KILOCODE_API_KEYand balance config defaults are config field references, not exposed secrets.
The changes appear reasonable but warrant a thorough review given the scope.
Reviewed by Hermes Agent
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment (high surface area + prior COMMENT)
Overview
New feature: provider-agnostic balance/credits display in Hermes Desktop and Web UI. Implements BalanceProvider ABC, BalanceProviderRegistry, and the UI components to show balance in the status bar.
Surface Area Note
21 files changed with ~2,334 additions. This exceeds the surface-area threshold (15+ files or ~1000+ additions). Key areas touched:
agent/balance_provider.py— new ABC + registry with thread-safe cachingapps/desktop/— TypeScript hooks and state managementweb/src/— React components, i18n, plugin registryplugins/model-providers/kilocode/balance.py— first provider implementationplugins/kanban/dashboard/dist/index.js— pre-compiled artifact (not reviewable in diff form)
Architectural Quality
The balance provider architecture is clean: ABC pattern, thread-safe registry, cache with TTL, and per-provider subclasses. This is a good design.
Concerns
- Pre-compiled artifact:
dist/index.jsis not reviewable as a diff. Full review of the kanban dashboard changes is deferred. - Surface area: The combined scope of agent ABC, desktop UI, web UI, and plugin changes is substantial. Consider whether the dashboard/kanban changes could be reviewed separately.
Prior Review Note
This PR has a prior COMMENT-only review from another session. This review adds additional observations without overwriting the prior review.
Reviewed by Hermes Agent (cron/heavy mode)
Add a general system for displaying AI provider balance/credits information in the Desktop statusbar, starting with Kilo AI. Backend: - agent/balance_provider.py: BalanceProvider ABC, ProviderBalance dataclass, BalanceConfig, and thread-safe BalanceProviderRegistry with TTL caching - plugins/model-providers/kilocode/balance.py: KiloBalanceProvider fetching GET https://api.kilo.ai/api/profile/balance - tui_gateway/server.py: @method('balance.view') RPC handler — resolves the active runtime provider, merges config.yaml overrides with per-class defaults, and returns cached or fresh balance data Desktop frontend: - apps/desktop/src/types/hermes.ts: ProviderBalance and BalanceViewResponse types - apps/desktop/src/store/provider-balance.ts: nanostore atom for balance state - apps/desktop/src/lib/hooks/use-provider-balance.ts: React hook with 2min auto-poll, gateway-connect trigger, and click-to-force-refresh - apps/desktop/src/app/shell/hooks/use-statusbar-items.tsx: statusbar item between session-timer and YOLO toggle (color-coded: red=depleted, amber=low) - apps/desktop/src/app/desktop-controller.tsx: wired useProviderBalance Design: provider-agnostic from day one. Adding a new provider is one Python file + one-line BalanceProviderRegistry.register() call — no frontend changes. Config keys under providers.<slug>.balance: { endpoint, enabled, cache_ttl_seconds }. Fail-open on all error paths. Closes NousResearch#51175
bac2ef3 to
196ef8c
Compare
|
Branch cleaned up. The previous version included 7 unrelated commits (kanban dialog work, dashboard fix) that leaked in from my fork's base branch. I've rebased onto current This should resolve the surface-area concern. Happy to address any further review feedback. |
|
Thanks for the focused, rebased implementation. This automated hermes-sweeper review is closing this PR under the standing
This is a coupling-and-maintenance decision, not a judgment on the quality of the work. Closed as not-planned per standing maintainer policy ( |
Closes #51175
Summary
Adds a general, provider-agnostic system for displaying AI provider balance/credit
information in the Desktop statusbar. Starts with Kilo AI; adding a new provider
is one Python file + one-line registration call — no frontend changes needed.
Backend
BalanceProvider(ABC),ProviderBalancedataclass,
BalanceConfig, andBalanceProviderRegistry(thread-safe,TTL-based caching with in-flight dedup)
KiloBalanceProviderfetching
GET https://api.kilo.ai/api/profile/balance@method("balance.view")RPC handler thatresolves the active runtime provider, merges config.yaml overrides with
provider defaults, and returns cached or fresh balance data
Desktop Frontend
provider's balance (e.g. "Kilo AI .61"). Color-coded: red when depleted,
amber when low (< ). Click to force-refresh.
credentials or with an unsupported provider.
Config
Optional
providers.<slug>.balance:subsection in config.yaml:Extensibility
Adding OpenAI, OpenRouter, Anthropic, etc.:
plugins/model-providers/<slug>/balance.py(~40 lines)BalanceProviderRegistry.register(YourBalanceProvider)to__init__.pyReview Notes
All review findings from Gemini 3.5 Flash + GPT-OSS cross-vendor audit addressed:
{in statusbar items array (compile error — fixed)cachedfield no longer hardcodedTruecached_or_fetch(in-flight tracking added)httpximport moved to top leveldisplayproperty removed