Skip to content

Commit 402805f

Browse files
authored
Merge pull request #685 from rajbos/rajbos/new-copilot-pricing-model
Add GitHub Copilot AI-Credit pricing alongside provider pricing
2 parents 821fcdd + 897dcdf commit 402805f

11 files changed

Lines changed: 406 additions & 43 deletions

File tree

cli/src/commands/usage.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ function printPeriodStats(
107107
console.log(` Avg tokens/session: ${chalk.bold(formatTokens(stats.avgTokensPerSession))}`);
108108

109109
if (options.cost && stats.estimatedCost > 0) {
110-
console.log(` Estimated cost: ${chalk.green('$' + stats.estimatedCost.toFixed(4))}`);
110+
console.log(` Estimated cost (est.): ${chalk.green('$' + stats.estimatedCost.toFixed(4))} ${chalk.dim('(provider API rates)')}`);
111+
if ((stats.estimatedCostCopilot ?? 0) > 0) {
112+
console.log(` Estimated cost (TBB): ${chalk.green('$' + (stats.estimatedCostCopilot ?? 0).toFixed(4))} ${chalk.dim('(Copilot AI Credits)')}`);
113+
}
111114
}
112115

113116
// Model breakdown

cli/src/helpers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ export async function calculateDetailedStats(
437437
period.treesEquivalent = period.co2 / CO2_ABSORPTION_PER_TREE_PER_YEAR;
438438
period.waterUsage = (period.tokens / 1000) * WATER_USAGE_PER_1K_TOKENS;
439439
period.estimatedCost = calculateEstimatedCost(period.modelUsage, modelPricing);
440+
period.estimatedCostCopilot = calculateEstimatedCost(period.modelUsage, modelPricing, 'copilot');
440441
}
441442

442443
return {

vscode-extension/src/README.md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,45 @@ Contains pricing information for AI models, including input and output token cos
4646
"cacheCreationCostPerMillion": 2.1875,
4747
"category": "Model category",
4848
"tier": "standard|premium|unknown",
49-
"multiplier": 1
49+
"multiplier": 1,
50+
"copilotPricing": {
51+
"inputCostPerMillion": 1.75,
52+
"cachedInputCostPerMillion": 0.175,
53+
"cacheCreationCostPerMillion": 2.1875,
54+
"outputCostPerMillion": 14.0,
55+
"releaseStatus": "GA",
56+
"category": "Versatile"
57+
}
5058
}
5159
}
5260
}
5361
```
5462

63+
**Provider vs. GitHub Copilot pricing**
64+
65+
The top-level `inputCostPerMillion` / `outputCostPerMillion` / cache fields
66+
represent the **direct provider/API price** (OpenAI, Anthropic, Google, xAI, …).
67+
The optional `copilotPricing` block represents **GitHub Copilot's published
68+
per-token AI Credit rates**
69+
(<https://docs.github.com/en/copilot/reference/copilot-billing/models-and-pricing>,
70+
1 AI credit = $0.01). Both are computed in parallel by `calculateEstimatedCost`:
71+
72+
```ts
73+
calculateEstimatedCost(usage, pricing); // provider/API cost (default)
74+
calculateEstimatedCost(usage, pricing, 'copilot'); // GitHub Copilot AI-Credit cost
75+
```
76+
77+
When a model has no `copilotPricing` block the `'copilot'` source falls back to
78+
the provider rates as a proxy — this means the Copilot cost is never
79+
*under-reported* due to a missing entry, it just won't reflect the (often
80+
identical) GitHub-published rate explicitly.
81+
82+
> ℹ️ **Caching note.** Copilot Chat session logs do not (yet) expose a
83+
> cached-read / cache-creation token breakdown, so the Copilot cost falls back
84+
> to the full input rate for those sources. Adapters that *do* surface cache
85+
> tokens (Claude Desktop, Claude Code, OpenCode) automatically benefit from the
86+
> reduced cached-input rates in `copilotPricing`.
87+
5588
**Cache pricing fields (optional):**
5689

5790
| Field | Description |

vscode-extension/src/extension.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,8 @@ class CopilotTokenTracker implements vscode.Disposable {
13321332
tooltip.appendMarkdown(`📅 Today \n`);
13331333
tooltip.appendMarkdown(`| | |\n|-----------------------|-------|\n`);
13341334
tooltip.appendMarkdown(`| Tokens : | ${detailedStats.today.tokens.toLocaleString()} |\n`);
1335-
tooltip.appendMarkdown(`| Estimated cost : | $ ${detailedStats.today.estimatedCost.toFixed(4)} |\n`);
1335+
tooltip.appendMarkdown(`| Estimated cost (est.) : | $ ${detailedStats.today.estimatedCost.toFixed(2)} |\n`);
1336+
tooltip.appendMarkdown(`| Estimated cost (TBB) : | $ ${(detailedStats.today.estimatedCostCopilot ?? 0).toFixed(2)} |\n`);
13361337
tooltip.appendMarkdown(`| CO₂ estimated : | ${detailedStats.today.co2.toFixed(2)} grams |\n`);
13371338
tooltip.appendMarkdown(`| Water estimated : | ${detailedStats.today.waterUsage.toFixed(3)} liters |\n`);
13381339
tooltip.appendMarkdown(`| Sessions : | ${detailedStats.today.sessions} |\n`);
@@ -1345,7 +1346,8 @@ class CopilotTokenTracker implements vscode.Disposable {
13451346
tooltip.appendMarkdown(`📊 Last 30 Days \n`);
13461347
tooltip.appendMarkdown(`| | |\n|-----------------------|-------|\n`);
13471348
tooltip.appendMarkdown(`| Tokens : | ${detailedStats.last30Days.tokens.toLocaleString()} |\n`);
1348-
tooltip.appendMarkdown(`| Estimated cost : | $ ${detailedStats.last30Days.estimatedCost.toFixed(4)} |\n`);
1349+
tooltip.appendMarkdown(`| Estimated cost (est.) : | $ ${detailedStats.last30Days.estimatedCost.toFixed(2)} |\n`);
1350+
tooltip.appendMarkdown(`| Estimated cost (TBB) : | $ ${(detailedStats.last30Days.estimatedCostCopilot ?? 0).toFixed(2)} |\n`);
13491351
tooltip.appendMarkdown(`| CO₂ estimated : | ${detailedStats.last30Days.co2.toFixed(2)} grams |\n`);
13501352
tooltip.appendMarkdown(`| Water estimated : | ${detailedStats.last30Days.waterUsage.toFixed(3)} liters |\n`);
13511353
tooltip.appendMarkdown(`| Sessions : | ${detailedStats.last30Days.sessions} |\n`);
@@ -1354,6 +1356,8 @@ class CopilotTokenTracker implements vscode.Disposable {
13541356
// Footer
13551357
tooltip.appendMarkdown('\n---\n');
13561358
tooltip.appendMarkdown('*Cost estimates based on actual input/output token ratios.* \n');
1359+
tooltip.appendMarkdown('*(est.) = provider API market rates, for reference only.* \n');
1360+
tooltip.appendMarkdown('*(TBB) = Copilot AI Credit rates — what Copilot will bill you.* \n');
13571361
tooltip.appendMarkdown('*Updates automatically every 5 minutes.*');
13581362

13591363
this.statusBarItem.tooltip = tooltip;
@@ -1811,6 +1815,11 @@ class CopilotTokenTracker implements vscode.Disposable {
18111815
const lastMonthCost = this.calculateEstimatedCost(lastMonthStats.modelUsage);
18121816
const last30DaysCost = this.calculateEstimatedCost(last30DaysStats.modelUsage);
18131817

1818+
const todayCostCopilot = this.calculateEstimatedCost(todayStats.modelUsage, 'copilot');
1819+
const monthCostCopilot = this.calculateEstimatedCost(monthStats.modelUsage, 'copilot');
1820+
const lastMonthCostCopilot = this.calculateEstimatedCost(lastMonthStats.modelUsage, 'copilot');
1821+
const last30DaysCostCopilot = this.calculateEstimatedCost(last30DaysStats.modelUsage, 'copilot');
1822+
18141823
const result: DetailedStats = {
18151824
today: {
18161825
tokens: todayStats.tokens,
@@ -1825,7 +1834,8 @@ class CopilotTokenTracker implements vscode.Disposable {
18251834
co2: todayCo2,
18261835
treesEquivalent: todayCo2 / this.co2AbsorptionPerTreePerYear,
18271836
waterUsage: todayWater,
1828-
estimatedCost: todayCost
1837+
estimatedCost: todayCost,
1838+
estimatedCostCopilot: todayCostCopilot
18291839
},
18301840
month: {
18311841
tokens: monthStats.tokens,
@@ -1840,7 +1850,8 @@ class CopilotTokenTracker implements vscode.Disposable {
18401850
co2: monthCo2,
18411851
treesEquivalent: monthCo2 / this.co2AbsorptionPerTreePerYear,
18421852
waterUsage: monthWater,
1843-
estimatedCost: monthCost
1853+
estimatedCost: monthCost,
1854+
estimatedCostCopilot: monthCostCopilot
18441855
},
18451856
lastMonth: {
18461857
tokens: lastMonthStats.tokens,
@@ -1855,7 +1866,8 @@ class CopilotTokenTracker implements vscode.Disposable {
18551866
co2: lastMonthCo2,
18561867
treesEquivalent: lastMonthCo2 / this.co2AbsorptionPerTreePerYear,
18571868
waterUsage: lastMonthWater,
1858-
estimatedCost: lastMonthCost
1869+
estimatedCost: lastMonthCost,
1870+
estimatedCostCopilot: lastMonthCostCopilot
18591871
},
18601872
last30Days: {
18611873
tokens: last30DaysStats.tokens,
@@ -1870,7 +1882,8 @@ class CopilotTokenTracker implements vscode.Disposable {
18701882
co2: last30DaysCo2,
18711883
treesEquivalent: last30DaysCo2 / this.co2AbsorptionPerTreePerYear,
18721884
waterUsage: last30DaysWater,
1873-
estimatedCost: last30DaysCost
1885+
estimatedCost: last30DaysCost,
1886+
estimatedCostCopilot: last30DaysCostCopilot
18741887
},
18751888
lastUpdated: now
18761889
};
@@ -3825,8 +3838,8 @@ usageAnalysis: undefined
38253838
return { responseText, thinkingText, toolCalls, mcpTools };
38263839
}
38273840

3828-
public calculateEstimatedCost(modelUsage: ModelUsage): number {
3829-
return _calculateEstimatedCost(modelUsage, this.modelPricing);
3841+
public calculateEstimatedCost(modelUsage: ModelUsage, pricingSource: 'provider' | 'copilot' = 'provider'): number {
3842+
return _calculateEstimatedCost(modelUsage, this.modelPricing, pricingSource);
38303843
}
38313844

38323845

0 commit comments

Comments
 (0)