import type { ExtensionAPI, ExtensionContext } from "@jaeswift/jae-coding-agent"; interface CostState { inputTokens: number; outputTokens: number; cacheReadTokens: number; cacheWriteTokens: number; totalCost: number; budgetLimit: number | null; turns: number; } const COST_PER_1K_INPUT = 0.003; const COST_PER_1K_OUTPUT = 0.015; const COST_PER_1K_CACHE_READ = 0.0003; const COST_PER_1K_CACHE_WRITE = 0.00375; export default function (pi: ExtensionAPI) { const state: CostState = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, totalCost: 0, budgetLimit: null, turns: 0, }; function recalcCost() { state.totalCost = (state.inputTokens / 1000) * COST_PER_1K_INPUT + (state.outputTokens / 1000) * COST_PER_1K_OUTPUT + (state.cacheReadTokens / 1000) * COST_PER_1K_CACHE_READ + (state.cacheWriteTokens / 1000) * COST_PER_1K_CACHE_WRITE; } function updateStatus(ctx: ExtensionContext) { const cost = state.totalCost.toFixed(4); const budget = state.budgetLimit ? ` / $${state.budgetLimit.toFixed(2)}` : ""; const tokens = ((state.inputTokens + state.outputTokens) / 1000).toFixed(1); ctx.ui.setStatus("cost-tracker", `\u{1F4B0} $${cost}${budget} | ${tokens}k tok | ${state.turns} turns`); } pi.on("turn_start", async (_event, ctx) => { state.turns++; updateStatus(ctx); }); pi.on("agent_end", async (event, ctx) => { for (const message of event.messages) { if (message && typeof message === "object" && "usage" in message) { const u = (message as any).usage; state.inputTokens += u.input || 0; state.outputTokens += u.output || 0; state.cacheReadTokens += u.cacheRead || 0; state.cacheWriteTokens += u.cacheWrite || 0; } } recalcCost(); updateStatus(ctx); if (state.budgetLimit && state.totalCost >= state.budgetLimit) { ctx.ui.notify( `\u26A0\uFE0F Budget limit of $${state.budgetLimit} reached! Total: $${state.totalCost.toFixed(4)}`, "warning", ); } }); pi.registerCommand("cost", { description: "Show session cost breakdown", handler: async (_args, ctx) => { ctx.ui.notify( `\u{1F4CA} Cost Report:\n` + ` Input: ${state.inputTokens.toLocaleString()} tokens ($${((state.inputTokens / 1000) * COST_PER_1K_INPUT).toFixed(4)})\n` + ` Output: ${state.outputTokens.toLocaleString()} tokens ($${((state.outputTokens / 1000) * COST_PER_1K_OUTPUT).toFixed(4)})\n` + ` Cache Read: ${state.cacheReadTokens.toLocaleString()} tokens\n` + ` Cache Write: ${state.cacheWriteTokens.toLocaleString()} tokens\n` + ` Total Cost: $${state.totalCost.toFixed(4)}\n` + ` Turns: ${state.turns}`, "info", ); }, }); pi.registerCommand("budget", { description: "Set session budget limit: /budget ", handler: async (args, ctx) => { const amount = parseFloat(args || ""); if (isNaN(amount) || amount <= 0) { ctx.ui.notify( state.budgetLimit ? `Current budget: $${state.budgetLimit.toFixed(2)} | Spent: $${state.totalCost.toFixed(4)}` : "No budget set. Usage: /budget 5.00", "info", ); } else { state.budgetLimit = amount; ctx.ui.notify(`\u{1F4B0} Budget set to $${amount.toFixed(2)}`, "info"); updateStatus(ctx); } }, }); }