11import { calculateAicEntitlementContext , type AicEntitlementContext , type AicEntitlementOverrides } from '../pipeline/aicEntitlements'
22import { getAicUsageMetrics , getUsageMetrics , parseTokenUsageHeader , parseTokenUsageRecord , type TokenUsageHeader , type TokenUsageRecord } from '../pipeline/parser'
3- import { getProductBudgetName , type ProductBudgetName } from '../pipeline/productClassification'
3+ import { getProductBudgetName , isNonCopilotCodeReviewUsage , NON_COPILOT_CODE_REVIEW_USER_LABEL , type ProductBudgetName } from '../pipeline/productClassification'
44import { streamLines } from '../pipeline/streamer'
55
66export type BudgetSimulationResult = {
@@ -61,6 +61,19 @@ function getIndividualEntitlementKey(record: TokenUsageRecord): string | null {
6161 return `${ username } \u0000${ weekStart } `
6262}
6363
64+ function getBudgetSubject ( record : TokenUsageRecord ) : string | null {
65+ const username = record . username . trim ( )
66+ if ( username ) {
67+ return username
68+ }
69+
70+ if ( isNonCopilotCodeReviewUsage ( record ) ) {
71+ return NON_COPILOT_CODE_REVIEW_USER_LABEL
72+ }
73+
74+ return null
75+ }
76+
6477function getRemainingEntitlements (
6578 record : TokenUsageRecord ,
6679 context : BudgetSimulationContext ,
@@ -123,7 +136,7 @@ export function simulateBudgetFromRecords(
123136 const seenIndividualEntitlementKeys = new Set < string > ( )
124137
125138 for ( const record of records ) {
126- const username = record . username . trim ( )
139+ const budgetSubject = getBudgetSubject ( record )
127140 const productBudgetName = getProductBudgetName ( record )
128141 const { requests } = getUsageMetrics ( record )
129142 const { aicQuantity, aicGrossAmount } = getAicUsageMetrics ( record )
@@ -145,7 +158,7 @@ export function simulateBudgetFromRecords(
145158
146159 const remainingUserBudget = userBudgetCap === Number . POSITIVE_INFINITY
147160 ? Number . POSITIVE_INFINITY
148- : ( remainingUserBudgetByUser . get ( username ) ?? userBudgetCap )
161+ : ( budgetSubject ? ( remainingUserBudgetByUser . get ( budgetSubject ) ?? userBudgetCap ) : Number . POSITIVE_INFINITY )
149162 const remainingProductBudget = remainingProductBudgetByName . get ( productBudgetName ) ?? Number . POSITIVE_INFINITY
150163 const remainingEntitlements = getRemainingEntitlements (
151164 record ,
@@ -177,8 +190,8 @@ export function simulateBudgetFromRecords(
177190
178191 if ( allowedRatio < 1 ) {
179192 blockedRequests += requests * ( 1 - allowedRatio )
180- if ( username ) {
181- blockedUsers . add ( username )
193+ if ( budgetSubject ) {
194+ blockedUsers . add ( budgetSubject )
182195 }
183196 if ( userBudgetLimited && firstUserBlockedDate === null ) {
184197 firstUserBlockedDate = record . date || null
@@ -228,8 +241,8 @@ export function simulateBudgetFromRecords(
228241 remainingEnterpriseBudget = nextRemainingEnterpriseBudget
229242 }
230243
231- if ( remainingUserBudget !== Number . POSITIVE_INFINITY ) {
232- remainingUserBudgetByUser . set ( username , Math . max ( remainingUserBudget - allowedGrossAmount , 0 ) )
244+ if ( budgetSubject && remainingUserBudget !== Number . POSITIVE_INFINITY ) {
245+ remainingUserBudgetByUser . set ( budgetSubject , Math . max ( remainingUserBudget - allowedGrossAmount , 0 ) )
233246 }
234247 if ( remainingProductBudget !== Number . POSITIVE_INFINITY ) {
235248 const nextRemainingProductBudget = Math . max ( remainingProductBudget - overageAmount , 0 )
0 commit comments