feat(platform): add copilot/autopilot cost tracking via token_tracking.py

Copilot uses OpenRouter via a separate code path (not through the block
executor). This integrates PlatformCostLog into the shared
persist_and_record_usage() function which is called by both SDK and
baseline copilot paths, capturing:
- Every LLM turn (main conversation, title gen, context compression)
- Tokens (prompt + completion + cache)
- Actual USD cost when available (SDK path provides cost_usd)
- Session ID for correlation
This commit is contained in:
Zamil Majdy
2026-04-02 17:17:53 +02:00
parent 95524e94b3
commit 83b00f4789

View File

@@ -4,12 +4,15 @@ Both the baseline (OpenRouter) and SDK (Anthropic) service layers need to:
1. Append a ``Usage`` record to the session.
2. Log the turn's token counts.
3. Record weighted usage in Redis for rate-limiting.
4. Write a PlatformCostLog entry for admin cost tracking.
This module extracts that common logic so both paths stay in sync.
"""
import logging
from backend.data.platform_cost import PlatformCostEntry, log_platform_cost_safe
from .model import ChatSession, Usage
from .rate_limit import record_token_usage
@@ -95,4 +98,45 @@ async def persist_and_record_usage(
except Exception as usage_err:
logger.warning(f"{log_prefix} Failed to record token usage: {usage_err}")
# Log to PlatformCostLog for admin cost dashboard
if user_id and total_tokens > 0:
cost_float = None
if cost_usd is not None:
try:
cost_float = float(cost_usd)
except (ValueError, TypeError):
pass
cost_microdollars = int(cost_float * 1_000_000) if cost_float else None
session_id = session.session_id if session else None
if cost_float is not None:
tracking_type = "cost_usd"
tracking_amount = cost_float
else:
tracking_type = "tokens"
tracking_amount = total_tokens
await log_platform_cost_safe(
PlatformCostEntry(
user_id=user_id,
graph_exec_id=session_id,
block_id="copilot",
block_name=f"copilot:{log_prefix.strip(' []')}".rstrip(":"),
provider="open_router",
credential_id="copilot_system",
cost_microdollars=cost_microdollars,
input_tokens=prompt_tokens,
output_tokens=completion_tokens,
model=None,
metadata={
"tracking_type": tracking_type,
"tracking_amount": tracking_amount,
"cache_read_tokens": cache_read_tokens,
"cache_creation_tokens": cache_creation_tokens,
"source": "copilot",
},
)
)
return total_tokens