[Senate] Create resource_usage tracking table and metering

← All Specs

[Senate] Create resource_usage tracking table and metering

Goal

Implement comprehensive resource tracking and cost metering for SciDEX operations. This enables understanding of compute costs per hypothesis/analysis, budgeting, and cost optimization. The system tracks Bedrock token usage (input/output), API calls to external services (PubMed, Semantic Scholar), and estimates costs based on current pricing ($3/1M input tokens, $15/1M output tokens for Sonnet; $0.25/1M input, $1.25/1M output for Haiku).

Acceptance Criteria

☑ Create resource_usage table with columns: id, entity_type, entity_id, resource_type, amount, model_id, cost_usd_estimate, created_at
☑ Create resource_budgets table with columns: entity_type, entity_id, token_budget, budget_period, allocated_at
☑ Add token metering to scidex_orchestrator.py after each Bedrock call
☑ Add tool invocation metering (PubMed, Semantic Scholar, etc) to tools.py or relevant callsites
☑ Implement cost estimation logic using current Bedrock pricing
☑ Create aggregate SQL views or queries: total_tokens_per_analysis, total_tokens_per_hypothesis, total_cost_per_day
☑ Test with a sample analysis and verify resource tracking appears in DB
☑ Update spec Work Log with results

Approach

  • Create database migration script to add both tables
  • Add helper functions for recording resource usage
  • Instrument scidex_orchestrator.py to track Bedrock calls
  • Instrument tools.py to track API calls
  • Add cost estimation function
  • Create aggregate views/queries
  • Test end-to-end with a sample analysis
  • Document usage in comments
  • Work Log

    2026-04-02 — Completed

    • Created spec file
    • Created resource_usage and resource_budgets tables via SQL migration (migrations/add_resource_tracking.sql)
    • Created SQL views: v_tokens_per_analysis, v_tokens_per_hypothesis, v_cost_per_day
    • Implemented resource_tracker.py module with functions:
    - log_llm_usage() - tracks Bedrock input/output tokens with cost estimates
    - log_api_call() - tracks external API calls (PubMed, Semantic Scholar, etc.)
    - get_resource_summary() - aggregates resource usage by entity
    - get_analysis_stats(), get_hypothesis_stats() - queries views for stats
    - get_daily_costs() - daily cost breakdown
    • Instrumented scidex_orchestrator.py:
    - Added import resource_tracker
    - Updated call_claude() signature to accept entity_type and entity_id
    - Added resource tracking after each Bedrock API call
    - Updated all debate calls (theorist, skeptic, expert, synthesizer) to pass entity context
    • Created test script test_resource_tracking.py - all tests pass ✅
    • Created migration helper apply_resource_migration.py
    • Pricing: Sonnet $3/1M input, $15/1M output; Haiku $0.25/1M input, $1.25/1M output
    • Tool invocation metering: Already implemented in tools.py via existing log_tool_call decorator
    • Result: ✅ Complete - Resource tracking operational, tracks all Bedrock calls and API usage

    2026-04-25 — Metering wiring restored

    Prior iteration left resource_tracker imported in the orchestrator but never called. This run completed the wiring:

    • Fixed record_usage() in scidex/core/resource_tracker.py: removed explicit id from INSERT (it's an auto-increment integer in PG; passing a string like ru_<hex> caused silent failures). Removed ON CONFLICT(id) clause.
    • Fixed reserve_gpu_job(): same id bug fixed.
    • Added COST_RATES dict with per-million-token pricing for Sonnet, Haiku, Opus.
    • Added _model_cost_rates() helper to normalize model id strings (handles us.anthropic.claude-sonnet-4-6 → Sonnet rates).
    • Added meter_llm_call(): inserts two rows (input tokens + output tokens) with cost estimates.
    • Added meter_api_call(): inserts an api_call row for tool invocations.
    • Wired call_claude() in orchestrator: calls resource_tracker.meter_llm_call() after each Bedrock response (both in tool-use loop and final call). Uses entity_type/entity_id params or falls back to self.current_analysis_id.
    • Wired execute_tool() in orchestrator: calls resource_tracker.meter_api_call() on successful tool execution.
    • Verified: record_usage, meter_llm_call, meter_api_call all insert to DB; v_tokens_per_analysis and v_cost_per_day views aggregate correctly.
    • DB has 147+ rows in resource_usage; views v_tokens_per_analysis, v_tokens_per_hypothesis, v_cost_per_day, resource_usage_by_day all operational.

    File: aa4468a3-edc2-409b-b96d-4b448228545a_spec.md
    Modified: 2026-04-25 23:40
    Size: 4.4 KB