From ac792e0148a8ff07b651d05a67d6dce37e5e11ea Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Fri, 12 Jun 2026 15:51:35 -0400 Subject: [PATCH] Fix max CTA (#321197) * Fix max CTA * Fix * Fix tests --- .../src/platform/chat/common/commonTypes.ts | 9 +++++- .../chat/test/common/commonTypes.spec.ts | 30 +++++++++++++++++-- .../chatContentParts/chatQuotaExceededPart.ts | 27 +++++++---------- .../browser/chatQuotaExceededPart.test.ts | 12 ++++---- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/extensions/copilot/src/platform/chat/common/commonTypes.ts b/extensions/copilot/src/platform/chat/common/commonTypes.ts index 938d281e541..87c067b3179 100644 --- a/extensions/copilot/src/platform/chat/common/commonTypes.ts +++ b/extensions/copilot/src/platform/chat/common/commonTypes.ts @@ -387,7 +387,14 @@ function getQuotaHitMessage(fetchResult: ChatFetchError, copilotPlan: string | u comment: [`{Locked=']({'}`] }); } else if (fetchResult.capiError?.code === 'additional_spend_limit_reached') { - return l10n.t(`You've reached your additional usage limit for your plan. Upgrade your plan to keep going.`); + if (copilotPlan === 'business' || copilotPlan === 'enterprise') { + return l10n.t(`You've reached your additional usage limit for your plan. Please contact your admin.`); + } + return l10n.t({ + message: `You've reached your additional usage limit for your plan. [Manage Budget]({0})`, + args: ['https://github.com/settings/copilot/features'], + comment: [`{Locked=']({'}`] + }); } else if (fetchResult.capiError?.code === 'billing_not_configured' && fetchResult.capiError?.message) { return fetchResult.capiError.message; } else if (fetchResult.capiError?.code && fetchResult.capiError?.message) { diff --git a/extensions/copilot/src/platform/chat/test/common/commonTypes.spec.ts b/extensions/copilot/src/platform/chat/test/common/commonTypes.spec.ts index f47059cc7ae..c28ed72eee0 100644 --- a/extensions/copilot/src/platform/chat/test/common/commonTypes.spec.ts +++ b/extensions/copilot/src/platform/chat/test/common/commonTypes.spec.ts @@ -20,7 +20,7 @@ function makeQuotaExceededError(capiError?: { code?: string; message?: string }) describe('getErrorDetailsFromChatFetchError', () => { describe('QuotaExceeded with additional_spend_limit_reached', () => { - test('returns upgrade message and additional_spend_limit_reached code', () => { + test('returns manage budget link for individual plan', () => { const result = getErrorDetailsFromChatFetchError( makeQuotaExceededError({ code: 'additional_spend_limit_reached', message: 'Spend limit reached' }), 'individual', @@ -30,7 +30,33 @@ describe('getErrorDetailsFromChatFetchError', () => { expect(result.isQuotaExceeded).toBe(true); expect(result.code).toBe('additional_spend_limit_reached'); expect(result.message).toContain('additional usage limit'); - expect(result.message).toContain('Upgrade'); + expect(result.message).toContain('Manage Budget'); + expect(result.message).toContain('https://github.com/settings/copilot/features'); + }); + + test('returns contact admin message for business plan', () => { + const result = getErrorDetailsFromChatFetchError( + makeQuotaExceededError({ code: 'additional_spend_limit_reached', message: 'Spend limit reached' }), + 'business', + GitHubOutageStatus.None, + ); + + expect(result.isQuotaExceeded).toBe(true); + expect(result.code).toBe('additional_spend_limit_reached'); + expect(result.message).toContain('additional usage limit'); + expect(result.message).toContain('contact your admin'); + }); + + test('returns contact admin message for enterprise plan', () => { + const result = getErrorDetailsFromChatFetchError( + makeQuotaExceededError({ code: 'additional_spend_limit_reached', message: 'Spend limit reached' }), + 'enterprise', + GitHubOutageStatus.None, + ); + + expect(result.isQuotaExceeded).toBe(true); + expect(result.code).toBe('additional_spend_limit_reached'); + expect(result.message).toContain('contact your admin'); }); }); diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuotaExceededPart.ts b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuotaExceededPart.ts index 907ec621f15..d890c82de9e 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuotaExceededPart.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuotaExceededPart.ts @@ -62,22 +62,17 @@ export class ChatQuotaExceededPart extends Disposable implements IChatContentPar const markdownContent = this._register(renderer.render(new MarkdownString(errorDetails.message))); dom.append(messageContainer, markdownContent.element); - const isAdditionalSpendLimitReached = errorDetails.code === 'additional_spend_limit_reached'; let primaryButtonLabel: string | undefined; - if (isAdditionalSpendLimitReached) { - primaryButtonLabel = localize('upgradePlan', "Upgrade"); - } else { - switch (chatEntitlementService.entitlement) { - case ChatEntitlement.EDU: - case ChatEntitlement.Pro: - case ChatEntitlement.ProPlus: - case ChatEntitlement.Max: - primaryButtonLabel = localize('manageBudget', "Manage Budget"); - break; - case ChatEntitlement.Free: - primaryButtonLabel = localize('upgradeToCopilotPro', "Upgrade to GitHub Copilot Pro"); - break; - } + switch (chatEntitlementService.entitlement) { + case ChatEntitlement.EDU: + case ChatEntitlement.Pro: + case ChatEntitlement.ProPlus: + case ChatEntitlement.Max: + primaryButtonLabel = localize('manageBudget', "Manage Budget"); + break; + case ChatEntitlement.Free: + primaryButtonLabel = localize('upgradeToCopilotPro', "Upgrade to GitHub Copilot Pro"); + break; } let hasAddedWaitWarning = false; @@ -123,7 +118,7 @@ export class ChatQuotaExceededPart extends Disposable implements IChatContentPar primaryButton.element.classList.add('chat-quota-error-button'); this._register(primaryButton.onDidClick(async () => { - const commandId = chatEntitlementService.entitlement === ChatEntitlement.Free || isAdditionalSpendLimitReached ? 'workbench.action.chat.upgradePlan' : 'workbench.action.chat.manageAdditionalSpend'; + const commandId = chatEntitlementService.entitlement === ChatEntitlement.Free ? 'workbench.action.chat.upgradePlan' : 'workbench.action.chat.manageAdditionalSpend'; telemetryService.publicLog2('workbenchActionExecuted', { id: commandId, from: 'chat-response' }); await commandService.executeCommand(commandId); diff --git a/src/vs/workbench/contrib/chat/test/browser/chatQuotaExceededPart.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatQuotaExceededPart.test.ts index 4579ee29068..84b0d46965c 100644 --- a/src/vs/workbench/contrib/chat/test/browser/chatQuotaExceededPart.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/chatQuotaExceededPart.test.ts @@ -149,7 +149,7 @@ suite('ChatQuotaExceededPart', () => { assert.strictEqual(button.textContent, 'Upgrade to GitHub Copilot Pro'); }); - test('shows "Upgrade" for Pro user with additional_spend_limit_reached', () => { + test('shows "Manage Budget" for Pro user with additional_spend_limit_reached', () => { const widget = createWidget(ChatEntitlement.Pro, { message: 'Spend limit reached', isQuotaExceeded: true, @@ -158,10 +158,10 @@ suite('ChatQuotaExceededPart', () => { const button = getPrimaryButton(widget); assert.ok(button); - assert.strictEqual(button.textContent, 'Upgrade'); + assert.strictEqual(button.textContent, 'Manage Budget'); }); - test('shows "Upgrade" for ProPlus user with additional_spend_limit_reached', () => { + test('shows "Manage Budget" for ProPlus user with additional_spend_limit_reached', () => { const widget = createWidget(ChatEntitlement.ProPlus, { message: 'Spend limit reached', isQuotaExceeded: true, @@ -170,7 +170,7 @@ suite('ChatQuotaExceededPart', () => { const button = getPrimaryButton(widget); assert.ok(button); - assert.strictEqual(button.textContent, 'Upgrade'); + assert.strictEqual(button.textContent, 'Manage Budget'); }); test('shows "Manage Budget" for EDU user without additional_spend_limit_reached', () => { @@ -214,7 +214,7 @@ suite('ChatQuotaExceededPart', () => { assert.strictEqual(executedCommands[0], 'workbench.action.chat.upgradePlan'); }); - test('Pro user with additional_spend_limit_reached clicks "Upgrade" -> upgradePlan', async () => { + test('Pro user with additional_spend_limit_reached clicks "Manage Budget" -> manageAdditionalSpend', async () => { const widget = createWidget(ChatEntitlement.Pro, { message: 'Spend limit reached', isQuotaExceeded: true, @@ -226,7 +226,7 @@ suite('ChatQuotaExceededPart', () => { button.click(); await new Promise(r => setTimeout(r, 0)); - assert.strictEqual(executedCommands[0], 'workbench.action.chat.upgradePlan'); + assert.strictEqual(executedCommands[0], 'workbench.action.chat.manageAdditionalSpend'); }); }); });