@@ -18,6 +18,7 @@ export interface CostBreakdown {
1818 totalCost : number ;
1919 details : {
2020 llmCalls : number ;
21+ gateEvaluations : number ;
2122 revisionRounds : number ;
2223 ttsCharacters : number ;
2324 aiImages : number ;
@@ -98,6 +99,7 @@ export function estimateCost(
9899 videoProvider ?: VideoProviderKey ,
99100 llmProvider : LLMProviderKey = "anthropic" ,
100101 musicProvider : MusicProviderKey = "bundled" ,
102+ gateEvaluations = 0 ,
101103 revisionRounds = 0 ,
102104) : CostBreakdown {
103105 const aiImageScenes = score . scenes . filter ( ( s ) => s . visual_type === "ai_image" ) . length ;
@@ -118,10 +120,10 @@ export function estimateCost(
118120 callCost ( TOKEN_ESTIMATES . critic ) +
119121 aiImages * callCost ( TOKEN_ESTIMATES . imagePrompter ) ;
120122
121- // Revision cost: each evaluation = 1 critic call + 1 director-sized revise call .
122- // Slightly undercounts because revise prompts include the original score JSON (~1-3K extra tokens),
123- // but using the director estimate is a reasonable approximation .
124- const revisionCost = revisionRounds * ( callCost ( TOKEN_ESTIMATES . critic ) + callCost ( TOKEN_ESTIMATES . creativeDirector ) ) ;
123+ // Quality gate cost: critic calls for evaluation + director calls for revision .
124+ // Split because evaluations > revisions (gate always evaluates, only revises if score < 7).
125+ // Slightly undercounts revise calls because the prompt includes the original score JSON (~1-3K extra tokens) .
126+ const revisionCost = gateEvaluations * callCost ( TOKEN_ESTIMATES . critic ) + revisionRounds * callCost ( TOKEN_ESTIMATES . creativeDirector ) ;
125127 const ttsPerChar = PRICING . ttsPerChar [ ttsProvider ] ;
126128 const ttsCost = ttsCharacters * ttsPerChar ;
127129 const perImage = imageProvider === "openai" ? PRICING . openaiPerImage : PRICING . geminiPerImage ;
@@ -161,7 +163,7 @@ export function estimateCost(
161163
162164 return {
163165 llmCost, revisionCost, ttsCost, imageCost, videoCost, musicCost, totalCost,
164- details : { llmCalls, revisionRounds, ttsCharacters, aiImages, aiVideos : aiVideoScenes } ,
166+ details : { llmCalls, gateEvaluations , revisionRounds, ttsCharacters, aiImages, aiVideos : aiVideoScenes } ,
165167 perScene,
166168 } ;
167169}
@@ -177,7 +179,10 @@ export function formatCostEstimate(
177179 ` LLM: $${ breakdown . llmCost . toFixed ( 4 ) } (${ breakdown . details . llmCalls } calls)` ,
178180 ] ;
179181 if ( breakdown . revisionCost > 0 ) {
180- lines . push ( ` Gate: $${ breakdown . revisionCost . toFixed ( 4 ) } (${ breakdown . details . revisionRounds } quality gate eval${ breakdown . details . revisionRounds !== 1 ? "s" : "" } )` ) ;
182+ const evals = breakdown . details . gateEvaluations ;
183+ const revs = breakdown . details . revisionRounds ;
184+ const detail = revs > 0 ? `${ evals } eval${ evals !== 1 ? "s" : "" } , ${ revs } revision${ revs !== 1 ? "s" : "" } ` : `${ evals } eval${ evals !== 1 ? "s" : "" } ` ;
185+ lines . push ( ` Gate: $${ breakdown . revisionCost . toFixed ( 4 ) } (${ detail } )` ) ;
181186 }
182187 lines . push (
183188 ` TTS: $${ breakdown . ttsCost . toFixed ( 4 ) } (${ breakdown . details . ttsCharacters } chars)` ,
0 commit comments