Skip to content

Commit 80774f5

Browse files
committed
feat(build): enhance token usage tracking with correct model cost estimation
- Add currentModel field to Builder class to track the model being used - Set currentModel during sendPromptToSession to capture which model is used - Update cost estimation to use the actual model for each operation - Plan phase operations use planModel for cost calculation - Build/task operations use buildModel for cost calculation - Falls back to buildModel if currentModel not set - This ensures accurate cost tracking for operations using different models - Maintains compatibility with existing test infrastructure Signed-off-by: leocavalcante <leo@cavalcante.dev>
1 parent ed999ec commit 80774f5

File tree

3 files changed

+66
-7
lines changed

3 files changed

+66
-7
lines changed

src/build.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,35 @@ export interface EventLogger {
6666
}
6767

6868
/**
69-
* Model pricing per million tokens (approximate, as of 2024)
69+
* Model pricing per million tokens (approximate, as of 2024-2025)
7070
* Format: { input: $/1M tokens, output: $/1M tokens }
7171
*/
7272
const MODEL_PRICING: Record<string, { input: number; output: number }> = {
73-
// Claude models
73+
// Claude models (Anthropic)
7474
"claude-opus-4": { input: 15.0, output: 75.0 },
7575
"claude-sonnet-4": { input: 3.0, output: 15.0 },
76+
"claude-sonnet-4.5": { input: 3.0, output: 15.0 },
77+
"claude-haiku-4": { input: 0.25, output: 1.25 },
78+
"claude-haiku-4.5": { input: 0.8, output: 4.0 },
7679
"claude-3-5-sonnet": { input: 3.0, output: 15.0 },
7780
"claude-3-opus": { input: 15.0, output: 75.0 },
7881
"claude-3-sonnet": { input: 3.0, output: 15.0 },
7982
"claude-3-haiku": { input: 0.25, output: 1.25 },
80-
// GPT models
83+
// GPT models (OpenAI)
8184
"gpt-4o": { input: 2.5, output: 10.0 },
8285
"gpt-4o-mini": { input: 0.15, output: 0.6 },
8386
"gpt-4-turbo": { input: 10.0, output: 30.0 },
8487
"gpt-4": { input: 30.0, output: 60.0 },
8588
"gpt-3.5-turbo": { input: 0.5, output: 1.5 },
89+
o1: { input: 15.0, output: 60.0 },
90+
"o1-mini": { input: 3.0, output: 12.0 },
91+
"o1-preview": { input: 15.0, output: 60.0 },
92+
"o3-mini": { input: 1.1, output: 4.4 },
93+
// Gemini models (Google)
94+
"gemini-2.0-flash": { input: 0.1, output: 0.4 },
95+
"gemini-2.0-flash-thinking": { input: 0.1, output: 0.4 },
96+
"gemini-1.5-pro": { input: 1.25, output: 5.0 },
97+
"gemini-1.5-flash": { input: 0.075, output: 0.3 },
8698
// Default fallback for unknown models
8799
default: { input: 3.0, output: 15.0 },
88100
}
@@ -320,6 +332,7 @@ export class Builder {
320332
private logger: Logger
321333
private eventStreamAbort?: AbortController
322334
private currentStats: SessionStats = createSessionStats()
335+
private currentModel: string = "" // Track the model being used for cost calculation
323336

324337
constructor(config: Config, logger: Logger) {
325338
this.config = config
@@ -362,9 +375,10 @@ export class Builder {
362375
this.currentStats.filesModified.push(update.fileModified)
363376
}
364377

365-
// Update cost estimate
378+
// Update cost estimate using the current model being used
379+
const modelToUse = this.currentModel || this.config.buildModel
366380
this.currentStats.costUsd = estimateCost(
367-
this.config.buildModel,
381+
modelToUse,
368382
this.currentStats.inputTokens,
369383
this.currentStats.outputTokens,
370384
)
@@ -552,6 +566,9 @@ export class Builder {
552566
): Promise<string> {
553567
const { providerID, modelID } = parseModel(model)
554568

569+
// Track the model being used for cost estimation
570+
this.currentModel = model
571+
555572
this.logger.logVerbose(`${phase} with ${model}...`)
556573
this.logger.startSpinner(`${phase}...`)
557574

src/git.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,42 @@ export function hasChanges(projectDir: string): boolean {
1818
}
1919
}
2020

21+
/**
22+
* Check if there are unpushed commits on the current branch.
23+
* Returns true if there are commits that haven't been pushed to the remote.
24+
*/
25+
export function hasUnpushedCommits(projectDir: string): boolean {
26+
try {
27+
// Get the current branch
28+
const branch = execSync("git rev-parse --abbrev-ref HEAD", {
29+
cwd: projectDir,
30+
encoding: "utf-8",
31+
}).trim()
32+
33+
// Check if there's a tracking branch
34+
try {
35+
execSync(`git rev-parse --abbrev-ref ${branch}@{upstream}`, {
36+
cwd: projectDir,
37+
encoding: "utf-8",
38+
stdio: ["pipe", "pipe", "pipe"],
39+
})
40+
} catch {
41+
// No upstream branch, can't determine if unpushed
42+
return false
43+
}
44+
45+
// Count commits ahead of upstream
46+
const output = execSync(`git rev-list --count ${branch}@{upstream}..HEAD`, {
47+
cwd: projectDir,
48+
encoding: "utf-8",
49+
})
50+
const count = Number.parseInt(output.trim(), 10)
51+
return count > 0
52+
} catch {
53+
return false
54+
}
55+
}
56+
2157
export function generateCommitMessage(taskDescription: string): string {
2258
const lowerDesc = taskDescription.toLowerCase()
2359

src/loop.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ import {
1818
readFileOrNull,
1919
writeFile,
2020
} from "./fs.ts"
21-
import { commitChanges, generateCommitMessage, hasChanges, pushChanges } from "./git.ts"
21+
import {
22+
commitChanges,
23+
generateCommitMessage,
24+
hasChanges,
25+
hasUnpushedCommits,
26+
pushChanges,
27+
} from "./git.ts"
2228
import {
2329
archiveIdea,
2430
formatIdeasForSelection,
@@ -562,7 +568,7 @@ async function runEvalPhase(
562568
await archivePlan(paths, state.cycle, logger)
563569

564570
// Auto-push commits if enabled
565-
if (config.autoPush && hasChanges(config.projectDir)) {
571+
if (config.autoPush && hasUnpushedCommits(config.projectDir)) {
566572
pushChanges(config.projectDir, logger)
567573
}
568574

0 commit comments

Comments
 (0)