From 33a97dcc8c1eb1a23add85740563cd24dd12dc0a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 12:37:46 +0000 Subject: [PATCH 1/2] Initial plan From 873cdc7eb33ee543970f772983786aea1e1bc7d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 12:40:34 +0000 Subject: [PATCH 2/2] Refactor hard-coded model names to use modelPricing.json data Co-authored-by: rajbos <6085745+rajbos@users.noreply.github.com> --- src/extension.ts | 36 ++++++++++++++++++++++-------------- src/modelPricing.json | 42 ++++++++++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 6f1db3e..8f788e2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -24,6 +24,7 @@ interface ModelPricing { inputCostPerMillion: number; outputCostPerMillion: number; category?: string; + displayNames?: string[]; } interface EditorUsage { @@ -2294,22 +2295,29 @@ class CopilotTokenTracker implements vscode.Disposable { if (request.result && request.result.metadata && request.result.metadata.modelId) { return request.result.metadata.modelId; } + + // Build a lookup map from display names to model IDs from modelPricing.json if (request.result && request.result.details) { - if (request.result.details.includes('Claude Sonnet 3.5')) { return 'claude-sonnet-3.5'; } - if (request.result.details.includes('Claude Sonnet 3.7')) { return 'claude-sonnet-3.7'; } - if (request.result.details.includes('Claude Sonnet 4')) { return 'claude-sonnet-4'; } - if (request.result.details.includes('Gemini 2.5 Pro')) { return 'gemini-2.5-pro'; } - if (request.result.details.includes('Gemini 3 Pro (Preview)')) { return 'gemini-3-pro-preview'; } - if (request.result.details.includes('Gemini 3 Pro')) { return 'gemini-3-pro'; } - if (request.result.details.includes('GPT-4.1')) { return 'gpt-4.1'; } - if (request.result.details.includes('GPT-4o-mini')) { return 'gpt-4o-mini'; } - if (request.result.details.includes('GPT-4o')) { return 'gpt-4o'; } - if (request.result.details.includes('GPT-4')) { return 'gpt-4'; } - if (request.result.details.includes('GPT-5')) { return 'gpt-5'; } - if (request.result.details.includes('GPT-3.5-Turbo')) { return 'gpt-3.5-turbo'; } - if (request.result.details.includes('o3-mini')) { return 'o3-mini'; } - if (request.result.details.includes('o4-mini')) { return 'o4-mini'; } + // Create reverse lookup: displayName -> modelId + const displayNameToModelId: { [displayName: string]: string } = {}; + for (const [modelId, pricing] of Object.entries(this.modelPricing)) { + if (pricing.displayNames) { + for (const displayName of pricing.displayNames) { + displayNameToModelId[displayName] = modelId; + } + } + } + + // Check which display name appears in the details + // Sort by length descending to match longer names first (e.g., "Gemini 3 Pro (Preview)" before "Gemini 3 Pro") + const sortedDisplayNames = Object.keys(displayNameToModelId).sort((a, b) => b.length - a.length); + for (const displayName of sortedDisplayNames) { + if (request.result.details.includes(displayName)) { + return displayNameToModelId[displayName]; + } + } } + return 'gpt-4'; // default } diff --git a/src/modelPricing.json b/src/modelPricing.json index dc9d197..8363a1a 100644 --- a/src/modelPricing.json +++ b/src/modelPricing.json @@ -32,7 +32,8 @@ "gpt-5": { "inputCostPerMillion": 1.25, "outputCostPerMillion": 10.0, - "category": "GPT-5 models" + "category": "GPT-5 models", + "displayNames": ["GPT-5"] }, "gpt-5-codex": { "inputCostPerMillion": 1.25, @@ -82,12 +83,14 @@ "gpt-4": { "inputCostPerMillion": 3.0, "outputCostPerMillion": 12.0, - "category": "GPT-4 models" + "category": "GPT-4 models", + "displayNames": ["GPT-4"] }, "gpt-4.1": { "inputCostPerMillion": 3.0, "outputCostPerMillion": 12.0, - "category": "GPT-4 models" + "category": "GPT-4 models", + "displayNames": ["GPT-4.1"] }, "gpt-4.1-mini": { "inputCostPerMillion": 0.8, @@ -102,27 +105,32 @@ "gpt-4o": { "inputCostPerMillion": 2.5, "outputCostPerMillion": 10.0, - "category": "GPT-4 models" + "category": "GPT-4 models", + "displayNames": ["GPT-4o"] }, "gpt-4o-mini": { "inputCostPerMillion": 0.15, "outputCostPerMillion": 0.6, - "category": "GPT-4 models" + "category": "GPT-4 models", + "displayNames": ["GPT-4o-mini", "GPT-4o Mini"] }, "claude-sonnet-3.5": { "inputCostPerMillion": 3.0, "outputCostPerMillion": 15.0, - "category": "Claude models (Anthropic)" + "category": "Claude models (Anthropic)", + "displayNames": ["Claude Sonnet 3.5"] }, "claude-sonnet-3.7": { "inputCostPerMillion": 3.0, "outputCostPerMillion": 15.0, - "category": "Claude models (Anthropic)" + "category": "Claude models (Anthropic)", + "displayNames": ["Claude Sonnet 3.7"] }, "claude-sonnet-4": { "inputCostPerMillion": 3.0, "outputCostPerMillion": 15.0, - "category": "Claude models (Anthropic)" + "category": "Claude models (Anthropic)", + "displayNames": ["Claude Sonnet 4"] }, "claude-sonnet-4.5": { "inputCostPerMillion": 3.0, @@ -152,22 +160,26 @@ "o3-mini": { "inputCostPerMillion": 4.0, "outputCostPerMillion": 16.0, - "category": "OpenAI reasoning models" + "category": "OpenAI reasoning models", + "displayNames": ["o3-mini"] }, "o4-mini": { "inputCostPerMillion": 4.0, "outputCostPerMillion": 16.0, - "category": "OpenAI reasoning models" + "category": "OpenAI reasoning models", + "displayNames": ["o4-mini"] }, "gpt-3.5-turbo": { "inputCostPerMillion": 0.5, "outputCostPerMillion": 1.5, - "category": "Legacy models" + "category": "Legacy models", + "displayNames": ["GPT-3.5-Turbo", "GPT-3.5 Turbo"] }, "gemini-2.5-pro": { "inputCostPerMillion": 1.25, "outputCostPerMillion": 10.0, - "category": "Google Gemini models" + "category": "Google Gemini models", + "displayNames": ["Gemini 2.5 Pro"] }, "gemini-2.5-flash": { "inputCostPerMillion": 0.30, @@ -197,12 +209,14 @@ "gemini-3-pro": { "inputCostPerMillion": 2.0, "outputCostPerMillion": 12.0, - "category": "Google Gemini models" + "category": "Google Gemini models", + "displayNames": ["Gemini 3 Pro"] }, "gemini-3-pro-preview": { "inputCostPerMillion": 2.0, "outputCostPerMillion": 12.0, - "category": "Google Gemini models" + "category": "Google Gemini models", + "displayNames": ["Gemini 3 Pro (Preview)"] }, "grok-code-fast-1": { "inputCostPerMillion": 0.20,