11import { randomUUID } from 'crypto' ;
22import { db } from './drizzle' ;
3- import type { MicrodollarUsage , Organization } from '@kilocode/db/schema' ;
3+ import type { MicrodollarUsage } from '@kilocode/db/schema' ;
44import { microdollar_usage } from '@kilocode/db/schema' ;
5- import type { FeatureValue } from '@/lib/feature-detection' ;
65import { createTimer } from '@/lib/timer' ;
76import type { OpenAI } from 'openai' ;
87import { createParser , type EventSourceMessage } from 'eventsource-parser' ;
@@ -11,7 +10,6 @@ import type {
1110 OpenRouterGeneration ,
1211} from './providers/openrouter/types' ;
1312import { fetchGeneration , PROVIDERS } from './providers' ;
14- import type { FraudDetectionHeaders } from './utils' ;
1513import { toMicrodollars } from './utils' ;
1614import { captureException , captureMessage , startSpan , startInactiveSpan } from '@sentry/nextjs' ;
1715import type { Span } from '@sentry/nextjs' ;
@@ -30,45 +28,24 @@ import { appendKiloPassAuditLog } from '@/lib/kilo-pass/issuance';
3028import { KiloPassAuditLogAction , KiloPassAuditLogResult } from '@/lib/kilo-pass/enums' ;
3129import { reportAbuseCost } from '@/lib/abuse-service' ;
3230import { isActiveReviewPromo } from '@/lib/code-reviews/core/constants' ;
31+ import type {
32+ BalanceUpdateResult ,
33+ ChatCompletionChunk ,
34+ CoreUsageWithMetaData ,
35+ JustTheCostsUsageStats ,
36+ MaybeHasOpenRouterUsage ,
37+ MaybeHasVercelProviderMetaData ,
38+ Message ,
39+ MicrodollarUsageContext ,
40+ MicrodollarUsageStats ,
41+ NotYetCostedUsageStats ,
42+ OpenRouterError ,
43+ OpenRouterUsage ,
44+ UsageMetaData ,
45+ } from '@/lib/processUsage.types' ;
3346
3447const posthogClient = PostHogClient ( ) ;
3548
36- export type OpenRouterUsage = {
37- cost ?: number ;
38- is_byok ?: boolean | null ;
39- cost_details ?: { upstream_inference_cost : number } ;
40- completion_tokens : number ;
41- completion_tokens_details : { reasoning_tokens : number } ;
42- prompt_tokens : number ;
43- prompt_tokens_details : { cached_tokens : number } ;
44- total_tokens : number ;
45- } ; //ref: https://openrouter.ai/docs/use-cases/usage-accounting#response-format
46-
47- type VercelProviderMetaData = { gateway ?: { routing ?: { finalProvider ?: string } } } ;
48-
49- type MaybeHasVercelProviderMetaData = {
50- choices ?: {
51- message ?: {
52- provider_metadata ?: VercelProviderMetaData ;
53- } ;
54- } [ ] ;
55- } ;
56-
57- type MaybeHasVercelProviderMetaDataChunk = {
58- choices ?: {
59- delta ?: { provider_metadata ?: VercelProviderMetaData } ;
60- } [ ] ;
61- } ;
62-
63- type MaybeHasOpenRouterUsage = {
64- usage ?: OpenRouterUsage | null ;
65- provider ?: string | null ;
66- } ;
67-
68- export type ChatCompletionChunk = OpenAI . Chat . Completions . ChatCompletionChunk &
69- MaybeHasOpenRouterUsage &
70- MaybeHasVercelProviderMetaDataChunk ;
71-
7249// For BYOK (Bring Your Own Key) requests, OpenRouter only reports 5% of the actual cost
7350// because that's what they charge for the BYOK feature. Although we now use upstream_inference_cost, we still do some sanity checks.
7451const OPENROUTER_BYOK_COST_MULTIPLIER = 20.0 ;
@@ -104,12 +81,6 @@ export function extractPromptInfo(body: OpenRouterChatCompletionRequest) {
10481 }
10582}
10683
107- interface Message {
108- role : string ;
109- content ?: string | { type ?: string ; text ?: string } [ ] ;
110- parts ?: { text ?: string } [ ] ;
111- }
112-
11384const extractMessageTextContent = ( m : Message ) =>
11485 typeof m . content === 'string'
11586 ? m . content
@@ -120,76 +91,8 @@ const extractMessageTextContent = (m: Message) =>
12091 . join ( '\n' )
12192 : '' ;
12293
123- type NotYetCostedUsageStats = {
124- messageId : string | null ;
125- model : string | null ;
126- responseContent : string ;
127- hasError : boolean ;
128- inference_provider : string | null ;
129- upstream_id : string | null ;
130- finish_reason : string | null ;
131- latency : number | null ;
132- moderation_latency : number | null ;
133- generation_time : number | null ;
134- streamed : boolean | null ;
135- cancelled : boolean | null ;
136- } ;
137-
138- type JustTheCostsUsageStats = {
139- cost_mUsd : number ;
140- cacheDiscount_mUsd ?: number ;
141- /** The real cost before any free/BYOK/promo zeroing. Set by processTokenData. */
142- market_cost ?: number ;
143- inputTokens : number ;
144- outputTokens : number ;
145- cacheWriteTokens : number ;
146- cacheHitTokens : number ;
147- is_byok : boolean | null ;
148- } ;
149-
150- export type MicrodollarUsageStats = NotYetCostedUsageStats & JustTheCostsUsageStats ;
151-
152- export type PromptInfo = {
153- system_prompt_prefix : string ;
154- system_prompt_length : number ;
155- user_prompt_prefix : string ;
156- } ;
157-
158- export type MicrodollarUsageContext = {
159- kiloUserId : string ;
160- fraudHeaders : FraudDetectionHeaders ;
161- organizationId ?: Organization [ 'id' ] ;
162- provider : ProviderId ;
163- requested_model : string ;
164- promptInfo : PromptInfo ;
165- max_tokens : number | null ;
166- has_middle_out_transform : boolean | null ;
167- isStreaming : boolean ;
168- prior_microdollar_usage : number ;
169- /** User email for authenticated users - used as PostHog distinctId. Undefined for anonymous users. */
170- posthog_distinct_id ?: string ;
171- project_id : string | null ;
172- status_code : number | null ;
173- editor_name : string | null ;
174- machine_id : string | null ;
175- /** True if user/org is using their own API key - cost should be zeroed out */
176- user_byok : boolean ;
177- has_tools : boolean ;
178- botId ?: string ;
179- tokenSource ?: string ;
180- /** Request ID from abuse service classify response, for cost tracking correlation. 0 means skip. */
181- abuse_request_id ?: number ;
182- /** Which product feature generated this API call. NULL if header not sent. */
183- feature : FeatureValue | null ;
184- /** Client session/task identifier from X-KiloCode-TaskId header. */
185- session_id : string | null ;
186- /** Client mode from x-kilocode-mode header (e.g. 'code', 'build', 'architect'). */
187- mode : string | null ;
188- /** The auto model ID when one was requested (e.g. 'kilo-auto/free'). */
189- auto_model : string | null ;
190- } ;
191-
19294export type UsageContextInfo = ReturnType < typeof extractUsageContextInfo > ;
95+
19396export function extractUsageContextInfo ( usageContext : MicrodollarUsageContext ) {
19497 return {
19598 kilo_user_id : usageContext . kiloUserId ,
@@ -213,11 +116,6 @@ export function extractUsageContextInfo(usageContext: MicrodollarUsageContext) {
213116 } ;
214117}
215118
216- export type CoreUsageWithMetaData = {
217- core : MicrodollarUsage ;
218- metadata : UsageMetaData ;
219- } ;
220-
221119export function toInsertableDbUsageRecord (
222120 usageStats : MicrodollarUsageStats ,
223121 usageContextInfo : UsageContextInfo
@@ -344,8 +242,6 @@ async function sendFirstUsageEvent(usage: MicrodollarUsage, posthog_distinct_id:
344242 }
345243}
346244
347- type BalanceUpdateResult = { newMicrodollarsUsed : number } | null ;
348-
349245async function sendFirstMicrodollarUsageEventIfNeeded (
350246 balanceUpdateResult : BalanceUpdateResult ,
351247 usage : MicrodollarUsage ,
@@ -414,42 +310,6 @@ ${metaDataKindName}_cte AS (
414310 SELECT ${ metaDataKindName } _id FROM ${ metaDataKindName } _ins
415311)` ;
416312
417- export type UsageMetaData = {
418- id : string ;
419- message_id : string ;
420- created_at : string ;
421- http_x_forwarded_for : string | null ;
422- http_x_vercel_ip_city : string | null ;
423- http_x_vercel_ip_country : string | null ;
424- http_x_vercel_ip_latitude : number | null ;
425- http_x_vercel_ip_longitude : number | null ;
426- http_x_vercel_ja4_digest : string | null ;
427- user_prompt_prefix : string | null ;
428- system_prompt_prefix : string | null ;
429- system_prompt_length : number | null ;
430- http_user_agent : string | null ;
431- max_tokens : number | null ;
432- has_middle_out_transform : boolean | null ;
433- status_code : number | null ;
434- upstream_id : string | null ;
435- finish_reason : string | null ;
436- latency : number | null ;
437- moderation_latency : number | null ;
438- generation_time : number | null ;
439- is_byok : boolean | null ;
440- is_user_byok : boolean ;
441- streamed : boolean | null ;
442- cancelled : boolean | null ;
443- editor_name : string | null ;
444- has_tools : boolean | null ;
445- machine_id : string | null ;
446- feature : string | null ;
447- session_id : string | null ;
448- mode : string | null ;
449- auto_model : string | null ;
450- market_cost : number | null ;
451- } ;
452-
453313export async function insertUsageRecord (
454314 coreUsageFields : MicrodollarUsage ,
455315 metadataFields : UsageMetaData
@@ -684,13 +544,6 @@ export function countAndStoreUsage(
684544 return usageStatsPromise . then ( usageStats => processTokenData ( usageStats , usageContext ) ) ;
685545}
686546
687- type OpenRouterError = {
688- message : string ;
689- code : string ;
690- metadata ?: Record < string , unknown > ;
691- provider_name ?: string ;
692- } ;
693-
694547export function processOpenRouterUsage (
695548 usage : OpenRouterUsage | null | undefined ,
696549 coreProps : NotYetCostedUsageStats
0 commit comments