@@ -505,13 +505,14 @@ async def get_stats(self, since: str | None = None) -> dict:
505505 }
506506
507507 async def get_daily_stats (self , days : int = 30 ) -> list [dict ]:
508- """Get daily token aggregates for the last N days."""
508+ """Get daily token and cost aggregates for the last N days."""
509509 cursor = await self ._db .conn .execute (
510510 """
511511 SELECT
512512 DATE(started_at) as date,
513513 SUM(input_tokens) as input_tokens,
514- SUM(output_tokens) as output_tokens
514+ SUM(output_tokens) as output_tokens,
515+ SUM(cost) as cost
515516 FROM agent_runs
516517 WHERE started_at >= DATE('now', ?)
517518 GROUP BY DATE(started_at)
@@ -525,10 +526,47 @@ async def get_daily_stats(self, days: int = 30) -> list[dict]:
525526 "date" : row ["date" ],
526527 "input_tokens" : row ["input_tokens" ] or 0 ,
527528 "output_tokens" : row ["output_tokens" ] or 0 ,
529+ "cost" : round (row ["cost" ] or 0.0 , 4 ),
528530 }
529531 for row in rows
530532 ]
531533
534+ async def backfill_costs (self ) -> int :
535+ """Recalculate costs for runs with tokens but zero cost."""
536+ cursor = await self ._db .conn .execute (
537+ """SELECT ar.id, ar.input_tokens, ar.output_tokens, p.model
538+ FROM agent_runs ar
539+ JOIN projects p ON ar.project_id = p.id
540+ WHERE ar.cost = 0.0 AND (ar.input_tokens > 0 OR ar.output_tokens > 0)"""
541+ )
542+ rows = await cursor .fetchall ()
543+ if not rows :
544+ return 0
545+
546+ try :
547+ from prompture .drivers import get_driver_for_model
548+
549+ updated = 0
550+ for row in rows :
551+ model_str = row ["model" ] or ""
552+ provider = model_str .split ("/" )[0 ] if "/" in model_str else ""
553+ model_id = model_str .split ("/" , 1 )[1 ] if "/" in model_str else model_str
554+ try :
555+ drv = get_driver_for_model (model_str )
556+ cost = drv ._calculate_cost (provider , model_id , row ["input_tokens" ], row ["output_tokens" ])
557+ except Exception :
558+ cost = 0.0
559+ if cost > 0 :
560+ await self ._db .conn .execute (
561+ "UPDATE agent_runs SET cost = ? WHERE id = ?" ,
562+ (round (cost , 6 ), row ["id" ]),
563+ )
564+ updated += 1
565+ await self ._db .conn .commit ()
566+ return updated
567+ except ImportError :
568+ return 0
569+
532570 @staticmethod
533571 def _row_to_run (row : Any ) -> AgentRun :
534572 return AgentRun (
0 commit comments