(filePath string)
| 402 | } |
| 403 | |
| 404 | func parseAgentUsageFile(filePath string) (*TokenUsageSummary, error) { |
| 405 | cleanPath := filepath.Clean(filePath) |
| 406 | data, err := os.ReadFile(cleanPath) |
| 407 | if err != nil { |
| 408 | return nil, fmt.Errorf("failed to read agent usage file: %w", err) |
| 409 | } |
| 410 | |
| 411 | var entry agentUsageEntry |
| 412 | if err := json.Unmarshal(data, &entry); err != nil { |
| 413 | return nil, fmt.Errorf("failed to parse agent usage file: %w", err) |
| 414 | } |
| 415 | |
| 416 | // Prefer primary_model when set; fall back to model; default to "unknown". |
| 417 | model := strings.TrimSpace(entry.PrimaryModel) |
| 418 | if model == "" { |
| 419 | model = strings.TrimSpace(entry.Model) |
| 420 | } |
| 421 | if model == "" { |
| 422 | model = "unknown" |
| 423 | } |
| 424 | // Prefer provider from entry; primary_model entries may omit it. |
| 425 | provider := strings.TrimSpace(entry.Provider) |
| 426 | |
| 427 | summary := &TokenUsageSummary{ |
| 428 | TotalInputTokens: entry.InputTokens, |
| 429 | TotalOutputTokens: entry.OutputTokens, |
| 430 | TotalCacheReadTokens: entry.CacheReadTokens, |
| 431 | TotalCacheWriteTokens: entry.CacheWriteTokens, |
| 432 | ByModel: make(map[string]*ModelTokenUsage), |
| 433 | } |
| 434 | |
| 435 | hasRawTokenData := summary.TotalInputTokens > 0 || |
| 436 | summary.TotalOutputTokens > 0 || |
| 437 | summary.TotalCacheReadTokens > 0 || |
| 438 | summary.TotalCacheWriteTokens > 0 || |
| 439 | entry.ReasoningTokens > 0 |
| 440 | hasTokenData := hasRawTokenData |
| 441 | if hasTokenData { |
| 442 | summary.TotalRequests = 1 |
| 443 | summary.ByModel[model] = &ModelTokenUsage{ |
| 444 | Provider: provider, |
| 445 | InputTokens: entry.InputTokens, |
| 446 | OutputTokens: entry.OutputTokens, |
| 447 | CacheReadTokens: entry.CacheReadTokens, |
| 448 | CacheWriteTokens: entry.CacheWriteTokens, |
| 449 | ReasoningTokens: entry.ReasoningTokens, |
| 450 | Requests: 1, |
| 451 | } |
| 452 | } |
| 453 | |
| 454 | ambientInputTokens := entry.InputTokens |
| 455 | if entry.AmbientContextTokens != nil { |
| 456 | ambientInputTokens = *entry.AmbientContextTokens |
| 457 | } |
| 458 | summary.AmbientContext = &AmbientContextMetrics{ |
| 459 | InputTokens: ambientInputTokens, |
| 460 | CachedTokens: entry.CacheReadTokens, |
| 461 | } |
no test coverage detected