Cost Monitoring
Every costed step in the platform prices itself with one heuristic — characters ÷ 4, at gpt-4o-mini rates — and the dashboard sums the results. Cheap, instant, and deliberately approximate.
The flow of a cost number
The estimator
Full code walkthrough: Service: Monitoring. The essentials:
- Tokens =
max(1, len(text) // 4)per side (input, output); empty/None → 0. - Dollars = input tokens × $0.15/1M + output tokens × $0.60/1M (gpt-4o-mini list prices, hardcoded).
- Output =
{"model_name", "estimated_tokens", "estimated_cost": "0.000123"}— cost as a 6-decimal string.
Coverage map — what is and isn't costed
| LLM activity | Costed? | Why |
|---|---|---|
| Workflow analysis / reply / reviewer stages | ✅ | router calls the estimator per stage |
| Workflow task stage | ➖ n/a | no LLM call |
Chat (/chat) | ❌ | logs an AgentRun, no costed ToolCall |
| Single-agent email analyze | ❌ | ToolCalls logged without cost fields |
| Document search / RAG ask | ❌ | ToolCalls logged without cost fields |
| Embeddings (upload + queries) | ❌ | never logged at all |
Consequence: estimated_total_cost on the dashboard reflects workflow spend only, and therefore understates true OpenAI usage — possibly substantially for RAG-heavy agents. Extending coverage is a good first contribution (Guides).
Trust boundaries
Good for: spotting an agent that suddenly does 10× more work, comparing agents, watching trends, demoing observability.
Not for: budgeting, billing reconciliation, or per-request accounting. Reasons:
- chars/4 tokenization error (±30% typical, worse for non-English/code);
- system-prompt and JSON-scaffolding tokens are not counted;
- prices are frozen constants — model changes and OpenAI price changes don't propagate;
- coverage gaps above.
For ground truth use the OpenAI usage dashboard, or upgrade the platform to read response.usage (below).
Reading costs in practice
# Raw, per step:
curl http://localhost:8001/agents/1/tool-calls | jq \
'.[] | select(.estimated_cost != null) | {tool_name, model_name, estimated_tokens, estimated_cost, latency_ms}'
# Aggregated:
curl http://localhost:8001/agents/1/dashboard | jq \
'{estimated_total_tokens, estimated_total_cost, average_latency_ms}'The frontend surfaces the same aggregates in PerformanceCard (cost to 4 decimals, tokens locale-formatted) and the "Cost estimate" banner.
The upgrade path to real numbers
- Services return
(text, usage)instead of bare text —response.usagecarries exactprompt_tokens/completion_tokens. - Routers log real counts; keep the estimator as fallback.
- Move the price table to configuration keyed by model name.
- Store
estimated_costas a numeric column (Design Decisions).
Tracked on the Roadmap.
Related pages
- Service: Monitoring — the code
- Observability — the surrounding contract