Files
brain/tools/cost-aggregator.mjs
T

74 lines
2.6 KiB
JavaScript

/**
* Pure cost aggregation over observer episodes.
*
* Two layers:
* - episodeUsd(episode, pricing) — compute 5-component USD breakdown per episode.
* - aggregateDay(episodes, dateISO, pricing) — sum across episodes whose
* started_at begins with dateISO ("YYYY-MM-DD").
*
* Spec: docs/superpowers/specs/2026-05-24-llm-first-router-overhaul-design.md §12.
* Consumed by `cost-stop-hook.mjs` and `/brain-retro` aggregations.
*/
export function episodeUsd(episode, pricing) {
const tc = (episode && episode.task_cost) || {};
const classifier_usd =
(tc.classifier_input_tokens || 0) * pricing.sonnet.input +
(tc.classifier_output_tokens || 0) * pricing.sonnet.output;
const self_assessment_usd =
(tc.self_assessment_input_tokens || 0) * pricing.opus.input +
(tc.self_assessment_output_tokens || 0) * pricing.opus.output;
const reviewer_subagent_usd = tc.reviewer_subagent_usd || 0;
const reviewer_direct_fallback_usd = tc.reviewer_direct_fallback_usd || 0;
const self_retrospect_usd = tc.self_retrospect_usd || 0;
const judge_spend_usd = tc.judge_spend_usd || 0;
const total_usd =
classifier_usd +
self_assessment_usd +
reviewer_subagent_usd +
reviewer_direct_fallback_usd +
self_retrospect_usd +
judge_spend_usd;
return {
classifier_usd,
self_assessment_usd,
reviewer_subagent_usd,
reviewer_direct_fallback_usd,
self_retrospect_usd,
judge_spend_usd,
total_usd,
};
}
export function aggregateDay(episodes, dateISO, pricing) {
const totals = {
classifier_usd: 0,
self_assessment_usd: 0,
reviewer_subagent_usd: 0,
reviewer_direct_fallback_usd: 0,
self_retrospect_usd: 0,
judge_spend_usd: 0,
};
let episode_count = 0;
for (const ep of Array.isArray(episodes) ? episodes : []) {
if (!ep || !ep.timestamps || typeof ep.timestamps.started_at !== 'string') continue;
if (!ep.timestamps.started_at.startsWith(dateISO)) continue;
const u = episodeUsd(ep, pricing);
totals.classifier_usd += u.classifier_usd;
totals.self_assessment_usd += u.self_assessment_usd;
totals.reviewer_subagent_usd += u.reviewer_subagent_usd;
totals.reviewer_direct_fallback_usd += u.reviewer_direct_fallback_usd;
totals.self_retrospect_usd += u.self_retrospect_usd;
totals.judge_spend_usd += u.judge_spend_usd;
episode_count += 1;
}
const total_usd =
totals.classifier_usd +
totals.self_assessment_usd +
totals.reviewer_subagent_usd +
totals.reviewer_direct_fallback_usd +
totals.self_retrospect_usd +
totals.judge_spend_usd;
return { ...totals, total_usd, episode_count };
}