• v1.13.10: per-tool token cost accounting (rolling 100-call view)

    indifferentketchup released this 2026-05-22 14:42:09 +00:00 | 83 commits to main since this release

    Surfaces per-tool prompt/completion-token rolling averages in
    AgentPicker for at-a-glance agent-cost hints. Implementation is a
    SQL view on top of messages_with_parts plus a read endpoint and
    AgentPicker tooltip extension. No new write site; all source data
    already lands via the existing tool-phase.ts:94-95 / error-handler.ts:
    109-110 / sentinel-summaries.ts UPDATEs that v1.13.7's includeUsage:
    true fix made non-NULL.

    (1) schema.sql — new tool_cost_stats view. Window-functions over
    messages_with_parts.tool_calls with LATERAL jsonb_array_elements.
    Attribution: equal split — multi-tool turn divides tokens N-ways;
    the 100-call rolling mean absorbs split noise. Filters: status=
    'complete' + metadata.kind NOT IN ('cap_hit','doom_loop') exclude
    failed turns and sentinels respectively; tool_calls IS NOT NULL is
    defense-in-depth since sentinels are role='system' rows. CREATE OR
    REPLACE means schema apply is idempotent.

    (2) routes/tools.ts NEW + index.ts wire-in. GET /api/tools/cost_stats
    returns { stats: ToolCostStat[] } with mean_prompt_tokens / mean_
    completion_tokens computed at read time (sum / n_calls). Sorted by
    tool_name ASC. No pagination — ≤30 tools.

    (3) tests/tool_cost_stats.test.ts NEW — 7 integration tests
    keyed off DATABASE_URL env var. Tests skip gracefully when unset
    (no-DB default). beforeAll applies the schema via sql.unsafe(read
    FileSync(schema.sql)) for self-contained runs. Helper insertAssistant
    Turn shared across cases. Covers: empty state, single-tool attribution,
    multi-tool equal split, 100-call FIFO window, NULL-tokens exclusion,
    parts-authoritative read via messages_with_parts, failed/sentinel
    exclusion.

    (4) web/api/types.ts + client.ts — ToolCostStat interface + api.tools.
    costStats() method binding.

    (5) AgentPicker.tsx — fetch costStats on mount, compute per-agent
    sum-of-means across whitelisted tools, render muted cost line below
    description: "~5.2k prompt / 280 completion · 6/8 tools · last call
    3h ago". Skips line entirely when no tool history; preserves existing
    native title= for layout backward-compat. formatK/formatAgo colocated.

    Tests: 202/202 pass (195 prior + 7 new view-integration). Server +
    web tsc clean.

    Smoke: schema applied cleanly; GET /api/tools/cost_stats returns
    canonical JSON; view + endpoint agree. Single-row result expected
    given the v1.13.1-A → v1.13.7 NULL latent regression window; new
    traffic populates organically.

    Roadmap row at boocode_roadmap.md:114 plus schema row at :474 both
    match. View vs table decision documented in handoff_v1.13.10_per_
    tool_cost.md (rollback-safe, microsecond-fast at BooCode scale).

    ~270 LoC across 8 files (5 modified + 3 new).

    Downloads