Skip to content

Commit 2bac11b

Browse files
committed
Added code to fallback to old UI when TBB is not released.
1 parent d220e84 commit 2bac11b

7 files changed

Lines changed: 299 additions & 17 deletions

File tree

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/CopilotTurnWidget.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.eclipse.swt.widgets.Composite;
1313
import org.eclipse.swt.widgets.Label;
1414

15+
import com.microsoft.copilot.eclipse.core.CopilotCore;
1516
import com.microsoft.copilot.eclipse.ui.chat.services.AvatarService;
1617
import com.microsoft.copilot.eclipse.ui.chat.services.ChatServiceManager;
1718
import com.microsoft.copilot.eclipse.ui.i18n.Messages;
@@ -72,8 +73,19 @@ public void renderModelInfo(String modelName, double billingMultiplier) {
7273
}
7374
if (StringUtils.isNotBlank(modelName)) {
7475
Label modelInfoLabel = new Label(footer, SWT.NONE);
75-
String formattedMultiplier = ModelUtils.formatBillingMultiplier(billingMultiplier);
76-
String displayText = String.format("%s - %s", modelName, formattedMultiplier);
76+
// When token-based billing is enabled on the language server, the per-turn billing
77+
// multiplier is no longer a meaningful price signal, so render the model name on its
78+
// own. Fall back to the legacy "{model} - {multiplier}" format otherwise.
79+
boolean tbbEnabled = CopilotCore.getPlugin().getAuthStatusManager()
80+
.getQuotaStatus().tokenBasedBillingEnabled();
81+
String displayText;
82+
if (tbbEnabled) {
83+
displayText = modelName;
84+
} else {
85+
// TODO: Remove this legacy fallback after TBB is officially released.
86+
String formattedMultiplier = ModelUtils.formatBillingMultiplier(billingMultiplier);
87+
displayText = String.format("%s - %s", modelName, formattedMultiplier);
88+
}
7789
modelInfoLabel.setText(displayText);
7890
GridData labelGridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false);
7991
modelInfoLabel.setLayoutData(labelGridData);

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/handlers/QuotaTextCalculator.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,14 @@ private int calculateMaxWidth() {
4545
max = Math.max(max,
4646
gc.stringExtent(Messages.menu_quota_chatMessages + getPercentUsed(quotaResult.chat())).x);
4747
if (quotaResult.copilotPlan() != CopilotPlan.free && quotaResult.premiumInteractions() != null) {
48-
max = Math.max(max, gc.stringExtent(
49-
getPremiumRequestsLabel() + getPremiumRequestsSuffix()).x);
48+
if (quotaResult.tokenBasedBillingEnabled()) {
49+
max = Math.max(max, gc.stringExtent(
50+
getPremiumRequestsLabel() + getPremiumRequestsSuffix()).x);
51+
} else {
52+
// TODO: Remove this legacy fallback after TBB is officially released.
53+
max = Math.max(max, gc.stringExtent(
54+
Messages.menu_quota_premiumRequests + getPercentUsed(quotaResult.premiumInteractions())).x);
55+
}
5056
}
5157
max += PADDING_WIDTH;
5258
}
@@ -98,6 +104,17 @@ public String getPremiumRequestsText() {
98104
return getAlignedQuotaText(getPremiumRequestsLabel(), getPremiumRequestsSuffix());
99105
}
100106

107+
// TODO: Remove this legacy fallback after TBB is officially released.
108+
/**
109+
* Returns the aligned text for the legacy "Premium Requests" row used when token-based billing is
110+
* not enabled on the language server. Preserves the original main-branch label and "{percent}%"
111+
* suffix.
112+
*/
113+
public String getPremiumText() {
114+
return getAlignedQuotaText(Messages.menu_quota_premiumRequests,
115+
getPercentUsed(quotaResult.premiumInteractions()));
116+
}
117+
101118
/**
102119
* Returns the suffix used for the premium requests row. CFI (Copilot for Individuals) plans get
103120
* the absolute "{used}/{entitlement} AI credits used" form; other paid plans get the standard
@@ -140,6 +157,10 @@ private String getPercentUsed(Quota quota) {
140157
double percent = Math.max(0, 100 - quota.percentRemaining());
141158
String formattedPercent = percent < 0.1 ? "0"
142159
: String.format("%.1f", Math.round(percent * 10) / 10.0);
160+
if (!quotaResult.tokenBasedBillingEnabled()) {
161+
// TODO: Remove this legacy fallback after TBB is officially released.
162+
return formattedPercent + "%";
163+
}
143164
return NLS.bind(Messages.menu_quota_percentUsedFormat, formattedPercent);
144165
}
145166
}

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/handlers/ShowMenuBarMenuHandler.java

Lines changed: 118 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
package com.microsoft.copilot.eclipse.ui.handlers;
55

66
import java.lang.reflect.Field;
7+
import java.time.LocalDate;
8+
import java.time.format.DateTimeFormatter;
79
import java.util.ArrayList;
810
import java.util.List;
911
import java.util.Map;
@@ -149,6 +151,22 @@ private void addCopilotUsageItems(AuthStatusManager authStatusManager, List<ICon
149151
// TODO: remove reset date null check when the CLS is ready for all IDEs.
150152
items.add(new Separator());
151153

154+
if (quotaStatus.tokenBasedBillingEnabled()) {
155+
addCopilotUsageItemsTbb(items, quotaStatus);
156+
} else {
157+
// TODO: Remove this legacy branch after TBB is officially released.
158+
addCopilotUsageItemsLegacy(items, quotaStatus);
159+
}
160+
161+
// Create a CompletableFuture to update quota information
162+
CopilotCore.getPlugin().getAuthStatusManager().checkQuota().thenAccept(this::updateQuotaItems);
163+
}
164+
165+
/**
166+
* Renders the Copilot usage rows using the token-based-billing layout (Monthly Limit / Included
167+
* Credits, Enable Additional Usage / Increase Budget, Upgrade Plan, dynamic allowance reset).
168+
*/
169+
private void addCopilotUsageItemsTbb(List<IContributionItem> items, CheckQuotaResult quotaStatus) {
152170
ImageDescriptor usageIcon = MenuUtils.getUsageIcon(MenuUtils.calculatePercentRemaining(quotaStatus));
153171
ImageDescriptor blankIcon = MenuUtils.getBlankIcon();
154172
CopilotPlan plan = quotaStatus.copilotPlan();
@@ -213,8 +231,94 @@ private void addCopilotUsageItems(AuthStatusManager authStatusManager, List<ICon
213231
items.add(createCommandItem("com.microsoft.copilot.eclipse.commands.upgradeCopilotPlan",
214232
Messages.menu_quota_upgradePlan, upgradePlanIcon));
215233
}
216-
// Create a CompletableFuture to update quota information
217-
CopilotCore.getPlugin().getAuthStatusManager().checkQuota().thenAccept(this::updateQuotaItems);
234+
}
235+
236+
// TODO: Remove this legacy fallback after TBB is officially released.
237+
/**
238+
* Renders the original main-branch Copilot usage rows. Used when the language server has not
239+
* enabled token-based billing yet, in which case the new TBB-only APIs (premium interactions
240+
* entitlement, overage budget UI, dynamic allowance-reset wording) are not relied on.
241+
*/
242+
private void addCopilotUsageItemsLegacy(List<IContributionItem> items, CheckQuotaResult quotaStatus) {
243+
Quota completionsQuota = quotaStatus.completions();
244+
Quota chatQuota = quotaStatus.chat();
245+
Quota premiumQuota = quotaStatus.premiumInteractions();
246+
CopilotPlan plan = quotaStatus.copilotPlan();
247+
248+
// Calculate percentRemaining based on plan
249+
double percentRemaining;
250+
if (plan == CopilotPlan.free) {
251+
percentRemaining = Math.min(completionsQuota.percentRemaining(), chatQuota.percentRemaining());
252+
} else if (premiumQuota != null) {
253+
percentRemaining = Math.min(completionsQuota.percentRemaining(),
254+
Math.min(chatQuota.percentRemaining(), premiumQuota.percentRemaining()));
255+
} else {
256+
percentRemaining = Math.min(completionsQuota.percentRemaining(), chatQuota.percentRemaining());
257+
}
258+
259+
ImageDescriptor icon = MenuUtils.getUsageIcon(percentRemaining);
260+
ImageDescriptor blankIcon = MenuUtils.getBlankIcon();
261+
262+
Map<String, String> parameters = Map.of(UiConstants.OPEN_URL_PARAMETER_NAME, UiConstants.MANAGE_COPILOT_URL);
263+
items.add(createCommandItem(UiConstants.OPEN_URL_COMMAND_ID, Messages.menu_quota_copilotUsage, parameters,
264+
Messages.menu_quota_manageCopilotTooltip, icon));
265+
266+
GC gc = new GC(PlatformUI.getWorkbench().getDisplay());
267+
QuotaTextCalculator calculator = new QuotaTextCalculator(gc, quotaStatus);
268+
try {
269+
// Premium requests row first when both completion/chat quotas are unlimited.
270+
if (plan != CopilotPlan.free && premiumQuota != null && completionsQuota.unlimited() && chatQuota.unlimited()) {
271+
this.premiumRequestsUsageItem = createCommandItem("com.microsoft.copilot.eclipse.commands.enabledDoNothing",
272+
calculator.getPremiumText(), blankIcon);
273+
items.add(this.premiumRequestsUsageItem);
274+
}
275+
276+
// Code completions usage
277+
this.completionsUsageItem = createCommandItem("com.microsoft.copilot.eclipse.commands.enabledDoNothing",
278+
calculator.getCompletionText(), blankIcon);
279+
items.add(this.completionsUsageItem);
280+
281+
// Chat messages usage
282+
this.chatUsageItem = createCommandItem("com.microsoft.copilot.eclipse.commands.enabledDoNothing",
283+
calculator.getChatText(), blankIcon);
284+
items.add(this.chatUsageItem);
285+
286+
// Premium requests usage / additional-paid status for non-free plans.
287+
if (plan != CopilotPlan.free && premiumQuota != null) {
288+
if (!completionsQuota.unlimited() || !chatQuota.unlimited()) {
289+
this.premiumRequestsUsageItem = createCommandItem("com.microsoft.copilot.eclipse.commands.enabledDoNothing",
290+
calculator.getPremiumText(), blankIcon);
291+
items.add(this.premiumRequestsUsageItem);
292+
}
293+
294+
CommandContributionItem additionalPremiumRequestsDesc = createCommandItem(
295+
"com.microsoft.copilot.eclipse.commands.disabledDoNothing",
296+
Messages.menu_quota_additionalPremiumRequests
297+
+ (premiumQuota.overagePermitted() ? Messages.menu_quota_enabled : Messages.menu_quota_disabled),
298+
null);
299+
items.add(additionalPremiumRequestsDesc);
300+
}
301+
} finally {
302+
gc.dispose();
303+
}
304+
305+
// Allowance reset date (legacy: simple "Allowance resets <date>" string).
306+
if (!StringUtils.isEmpty(quotaStatus.resetDate())) {
307+
LocalDate resetDate = LocalDate.parse(quotaStatus.resetDate());
308+
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy");
309+
items.add(createCommandItem("com.microsoft.copilot.eclipse.commands.disabledDoNothing",
310+
Messages.menu_quota_allowanceReset + resetDate.format(formatter), null));
311+
}
312+
313+
// Upsell actions based on the user's plan (legacy wording).
314+
ImageDescriptor upgradeIcon = UiUtils.buildImageDescriptorFromPngPath("/icons/quota/upgrade.png");
315+
if (plan == CopilotPlan.free) {
316+
items.add(createCommandItem("com.microsoft.copilot.eclipse.commands.upgradeCopilotPlan",
317+
Messages.menu_quota_updateCopilotToPro, Messages.menu_quota_updateCopilotToProPlus, upgradeIcon));
318+
} else if (plan != CopilotPlan.business && plan != CopilotPlan.enterprise) {
319+
items.add(createCommandItem(UiConstants.OPEN_URL_COMMAND_ID, Messages.menu_quota_managePaidPremiumRequests,
320+
Map.of(UiConstants.OPEN_URL_PARAMETER_NAME, UiConstants.MANAGE_COPILOT_OVERAGE_URL), upgradeIcon));
321+
}
218322
}
219323

220324
private void addAuthenticationActions(List<IContributionItem> items, String status) {
@@ -252,6 +356,7 @@ private void updateQuotaItems(CheckQuotaResult quotaResult) {
252356

253357
private void updateQuotaActionTexts(CheckQuotaResult quotaResult, GC gc) {
254358
QuotaTextCalculator calculator = new QuotaTextCalculator(gc, quotaResult);
359+
boolean tbbEnabled = quotaResult.tokenBasedBillingEnabled();
255360

256361
if (this.chatUsageItem != null && quotaResult.chat() != null) {
257362
String chatMessagesText = calculator.getChatText();
@@ -264,18 +369,23 @@ private void updateQuotaActionTexts(CheckQuotaResult quotaResult, GC gc) {
264369
}
265370

266371
if (this.premiumRequestsUsageItem != null && quotaResult.premiumInteractions() != null) {
267-
String monthlyLimitText = calculator.getPremiumRequestsText();
268-
setCommandItemField(this.premiumRequestsUsageItem, "label", monthlyLimitText);
269-
// Refresh the usage icon (red/yellow/blue) to reflect the latest percent remaining.
270-
setCommandItemField(this.premiumRequestsUsageItem, "icon",
271-
MenuUtils.getUsageIcon(MenuUtils.calculatePercentRemaining(quotaResult)));
372+
if (tbbEnabled) {
373+
String monthlyLimitText = calculator.getPremiumRequestsText();
374+
setCommandItemField(this.premiumRequestsUsageItem, "label", monthlyLimitText);
375+
// Refresh the usage icon (red/yellow/blue) to reflect the latest percent remaining.
376+
setCommandItemField(this.premiumRequestsUsageItem, "icon",
377+
MenuUtils.getUsageIcon(MenuUtils.calculatePercentRemaining(quotaResult)));
378+
} else {
379+
// TODO: Remove this legacy fallback after TBB is officially released.
380+
setCommandItemField(this.premiumRequestsUsageItem, "label", calculator.getPremiumText());
381+
}
272382
}
273383

274384
// Refresh the allowance-reset row label, which switches between "Reset in N days..." and
275385
// "No usage yet" depending on whether any of the tracked quotas have been consumed. When the
276386
// predicate flips off (e.g. plan changed to unlimited mid-session), skip the update and leave
277387
// the stale label until the menu is rebuilt rather than rendering an empty disabled row.
278-
if (this.allowanceResetItem != null && MenuUtils.shouldShowAllowanceResetRow(quotaResult)) {
388+
if (tbbEnabled && this.allowanceResetItem != null && MenuUtils.shouldShowAllowanceResetRow(quotaResult)) {
279389
setCommandItemField(this.allowanceResetItem, "label", MenuUtils.formatAllowanceReset(quotaResult));
280390
this.allowanceResetItem.update();
281391
}

0 commit comments

Comments
 (0)