diff --git a/src/app/admin/api/users/[id]/dev/insert-usage-record/route.ts b/src/app/admin/api/users/[id]/dev/insert-usage-record/route.ts index e4692995c6..fb46a46647 100644 --- a/src/app/admin/api/users/[id]/dev/insert-usage-record/route.ts +++ b/src/app/admin/api/users/[id]/dev/insert-usage-record/route.ts @@ -88,6 +88,7 @@ export async function POST( cancelled: false, editor_name: null, has_tools: false, + machine_id: null, }; await insertUsageRecord(coreUsageFields, metadataFields); diff --git a/src/db/schema.ts b/src/db/schema.ts index f6863bb8f4..be135ef8dc 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -611,6 +611,7 @@ export const microdollar_usage_metadata = pgTable( cancelled: boolean(), editor_name_id: integer(), has_tools: boolean(), + machine_id: text(), }, table => [index('idx_microdollar_usage_metadata_created_at').on(table.created_at)] ); diff --git a/src/lib/processUsage.ts b/src/lib/processUsage.ts index 73fc0095fa..e909304f77 100644 --- a/src/lib/processUsage.ts +++ b/src/lib/processUsage.ts @@ -423,6 +423,7 @@ export type UsageMetaData = { cancelled: boolean | null; editor_name: string | null; has_tools: boolean | null; + machine_id: string | null; }; export async function insertUsageRecord( @@ -529,6 +530,7 @@ async function insertUsageAndMetadataWithBalanceUpdate( streamed, cancelled, has_tools, + machine_id, http_user_agent_id, http_ip_id, @@ -559,6 +561,7 @@ async function insertUsageAndMetadataWithBalanceUpdate( ${metadataFields.streamed}, ${metadataFields.cancelled}, ${metadataFields.has_tools}, + ${metadataFields.machine_id}, (SELECT http_user_agent_id FROM http_user_agent_cte), (SELECT http_ip_id FROM http_ip_cte), diff --git a/src/lib/utils.ts b/src/lib/utils.ts index a7f4f395a7..010df2b2fa 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -33,6 +33,7 @@ export function getFraudDetectionHeaders(headers: Headers) { http_x_vercel_ip_longitude: parseFloatOrNull(headers.get('x-vercel-ip-longitude')), http_x_vercel_ja4_digest: headers.get('x-vercel-ja4-digest'), http_user_agent: headers.get('user-agent'), + machine_id: headers.get('x-kilocode-machineid'), }; } diff --git a/src/scripts/usage/benchmark-insert-usage.ts b/src/scripts/usage/benchmark-insert-usage.ts index 61535f3a8e..6492868878 100644 --- a/src/scripts/usage/benchmark-insert-usage.ts +++ b/src/scripts/usage/benchmark-insert-usage.ts @@ -185,6 +185,7 @@ function generateRandomRecord( cancelled: maybeNull(Math.random() < 0.05, 50), editor_name: maybeNull(pickRandom(['vscode', 'cursor', 'windsurf', 'vim'], Math.random()), 30), has_tools: maybeNull(Math.random() < 0.3, 20), + machine_id: maybeNull(randomString(36, 36, 36), 50), }; return { core, metadata }; diff --git a/src/tests/helpers/microdollar-usage.helper.ts b/src/tests/helpers/microdollar-usage.helper.ts index ae1f0bce08..9359cd8ce4 100644 --- a/src/tests/helpers/microdollar-usage.helper.ts +++ b/src/tests/helpers/microdollar-usage.helper.ts @@ -42,6 +42,7 @@ function defineDefaultContextInfo(): UsageContextInfo { http_x_vercel_ip_latitude: 43, http_x_vercel_ip_longitude: -79, http_x_vercel_ja4_digest: 'normal_fingerprint', + machine_id: null, provider: 'openrouter', user_prompt_prefix: 'Implement a feature', system_prompt_prefix: 'You are Kilo Code, a highly skilled software engineer', diff --git a/src/tests/stripe.test.ts b/src/tests/stripe.test.ts index 2c9e87382c..f25474f401 100644 --- a/src/tests/stripe.test.ts +++ b/src/tests/stripe.test.ts @@ -148,6 +148,7 @@ describe('ensurePaymentMethodStored', () => { http_x_vercel_ip_longitude: -122.4194, http_x_vercel_ja4_digest: 'test_digest', http_user_agent: 'Mozilla/5.0 (test)', + machine_id: null, }; const result = await ensurePaymentMethodStored(testUser.id, mockStripePaymentMethod, headers); @@ -262,6 +263,7 @@ describe('ensurePaymentMethodStored', () => { http_x_vercel_ip_longitude: null, http_x_vercel_ja4_digest: null, http_user_agent: null, + machine_id: null, }; const uniquePaymentMethod = sampleStripePaymentMethod();