Add cloud spend billing graphs #518

Closed
rikp777 wants to merge 5 commits from rikp777/feature/monthly-spend-navbar into main
rikp777 commented 2026-06-01 15:24:32 +02:00 (Migrated from github.com)

Summary

  • add optional multi-account cloud billing setup with encrypted provider tokens and a sidebar spend pill
  • add cloud spend limit enforcement before remote model calls
  • add provider-scoped model price metadata and hide cost UI when billing is disabled
  • add a billing graph endpoint, manage_billing tool, safe billing-chart rendering, and /billing
  • route deterministic billing graph requests through a generic direct-tool path instead of relying on LLM tool choice

Design note

The chat router now classifies tool intent before deciding how to run the request. Deterministic app-data requests can return ToolIntent(kind="direct_tool", tool="...", args={...}), which runs through a registered backend direct-tool runner and still streams/saves like a normal assistant reply. Billing is the first use case with manage_billing, but the path is intentionally generic so later safe app actions can bypass LLM tool selection without adding billing-specific routing branches.

Non-deterministic or planning-heavy requests still return agent_tool and promote chat to agent mode. That keeps model planning available where it helps, while avoiding wrong-tool selection and extra token spend for simple backend-owned data.

Issues

  • Closes #548
  • Closes #549
  • Related to #220: workspace separation is broader than billing, but this PR moves provider/account billing separation in that direction. Workspace-scoped chat history, settings, and API keys remain follow-up work.

Progress

Done in this PR:

  • multi-account billing configuration with encrypted/scrubbed provider tokens
  • sidebar month-to-date spend display and Settings billing status
  • provider-aware model price metadata and cost visibility controls
  • /billing and chat-triggered spending graph rendering through manage_billing
  • generic direct_tool execution path for deterministic app-data responses
  • remote model spend-limit enforcement when billing data is configured
  • local usage ledger for provider-generic token/cost tracking
  • daily/monthly budget controls for recorded model usage
  • refreshed screenshots for billing settings, model pricing, and the full chat graph

Still TODO:

  • expand provider billing adapters beyond DigitalOcean
  • expand provider pricing catalogs where provider APIs do not expose model prices
  • decide how workspace-scoped billing/settings should connect to #220
  • add richer historical graph series for local usage, not only current summaries
  • add user/workspace-scoped budget views for multi-user deployments
  • add notification hooks at budget thresholds

Screenshots

Chat billing graph

Chat billing graph

Billing settings

Billing settings

Model picker pricing

Model picker pricing

Tests

  • venv/bin/python -m py_compile app.py routes/chat_routes.py routes/auth_routes.py routes/billing_routes.py routes/model_routes.py src/action_intents.py src/agent_tools.py src/llm_core.py src/settings.py src/tool_execution.py src/tool_implementations.py src/tool_index.py src/tool_parsing.py src/tool_schemas.py src/tool_types.py
  • node --check static/js/markdown.js
  • node --check static/js/billing.js
  • node --check static/js/modelPicker.js
  • node --check static/js/chatRenderer.js
  • node --check static/js/settings.js
  • node --check static/js/slashCommands.js
  • venv/bin/python -m pytest -q
  • git diff --check
  • rg secret scan for local DigitalOcean/local model keys
## Summary - add optional multi-account cloud billing setup with encrypted provider tokens and a sidebar spend pill - add cloud spend limit enforcement before remote model calls - add provider-scoped model price metadata and hide cost UI when billing is disabled - add a billing graph endpoint, manage_billing tool, safe billing-chart rendering, and `/billing` - route deterministic billing graph requests through a generic direct-tool path instead of relying on LLM tool choice ## Design note The chat router now classifies tool intent before deciding how to run the request. Deterministic app-data requests can return `ToolIntent(kind="direct_tool", tool="...", args={...})`, which runs through a registered backend direct-tool runner and still streams/saves like a normal assistant reply. Billing is the first use case with `manage_billing`, but the path is intentionally generic so later safe app actions can bypass LLM tool selection without adding billing-specific routing branches. Non-deterministic or planning-heavy requests still return `agent_tool` and promote chat to agent mode. That keeps model planning available where it helps, while avoiding wrong-tool selection and extra token spend for simple backend-owned data. ## Issues - Closes #548 - Closes #549 - Related to #220: workspace separation is broader than billing, but this PR moves provider/account billing separation in that direction. Workspace-scoped chat history, settings, and API keys remain follow-up work. ## Progress Done in this PR: - multi-account billing configuration with encrypted/scrubbed provider tokens - sidebar month-to-date spend display and Settings billing status - provider-aware model price metadata and cost visibility controls - `/billing` and chat-triggered spending graph rendering through `manage_billing` - generic `direct_tool` execution path for deterministic app-data responses - remote model spend-limit enforcement when billing data is configured - local usage ledger for provider-generic token/cost tracking - daily/monthly budget controls for recorded model usage - refreshed screenshots for billing settings, model pricing, and the full chat graph Still TODO: - expand provider billing adapters beyond DigitalOcean - expand provider pricing catalogs where provider APIs do not expose model prices - decide how workspace-scoped billing/settings should connect to #220 - add richer historical graph series for local usage, not only current summaries - add user/workspace-scoped budget views for multi-user deployments - add notification hooks at budget thresholds ## Screenshots ### Chat billing graph ![Chat billing graph](https://raw.githubusercontent.com/rikp777/odysseus/49339d2/docs/pr-518-billing-chat-graph.png) ### Billing settings ![Billing settings](https://raw.githubusercontent.com/rikp777/odysseus/49339d2/docs/pr-518-billing-settings-card.png) ### Model picker pricing ![Model picker pricing](https://raw.githubusercontent.com/rikp777/odysseus/49339d2/docs/pr-518-billing-model-picker-menu.png) ## Tests - venv/bin/python -m py_compile app.py routes/chat_routes.py routes/auth_routes.py routes/billing_routes.py routes/model_routes.py src/action_intents.py src/agent_tools.py src/llm_core.py src/settings.py src/tool_execution.py src/tool_implementations.py src/tool_index.py src/tool_parsing.py src/tool_schemas.py src/tool_types.py - node --check static/js/markdown.js - node --check static/js/billing.js - node --check static/js/modelPicker.js - node --check static/js/chatRenderer.js - node --check static/js/settings.js - node --check static/js/slashCommands.js - venv/bin/python -m pytest -q - git diff --check - rg secret scan for local DigitalOcean/local model keys
rikp777 commented 2026-06-01 16:33:39 +02:00 (Migrated from github.com)

Merge/update note: while resolving upstream conflicts, the local full-suite run exposed a test-isolation issue unrelated to the billing feature. The failure was caused by collection-time core.database stubs leaking across tests; this branch fixes it by restoring sys.modules after the lightweight import tests. This keeps the upstream secret-scrubbing and calendar owner-scope fixes intact while making the combined test order pass.

Merge/update note: while resolving upstream conflicts, the local full-suite run exposed a test-isolation issue unrelated to the billing feature. The failure was caused by collection-time `core.database` stubs leaking across tests; this branch fixes it by restoring `sys.modules` after the lightweight import tests. This keeps the upstream secret-scrubbing and calendar owner-scope fixes intact while making the combined test order pass.
sleepy closed this pull request 2026-06-01 19:45:26 +02:00

Pull request closed

Sign in to join this conversation.
No description provided.