Skip to content

Commit 58c526f

Browse files
committed
feat: Add Usage Status panel with alert threshold to the preferences.
1 parent 63127a7 commit 58c526f

16 files changed

Lines changed: 688 additions & 90 deletions

File tree

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/Constants.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ private Constants() {
1818

1919
public static final String PLUGIN_ID = "com.microsoft.copilot.eclipse";
2020
public static final String AUTO_SHOW_COMPLETION = "enableAutoCompletions";
21+
public static final String USAGE_ALERT_THRESHOLD = "usageAlertThreshold";
2122
public static final String ENABLE_NEXT_EDIT_SUGGESTION = "enableNextEditSuggestion";
2223
public static final String ENABLE_STRICT_SSL = "enableStrictSsl";
2324
public static final String PROXY_KERBEROS_SP = "proxyKerberosSp";
@@ -35,6 +36,8 @@ private Constants() {
3536
public static final String CUSTOM_INSTRUCTIONS_WORKSPACE_ENABLED = "customInstructionsWorkspaceEnabled";
3637
public static final String CUSTOM_INSTRUCTIONS_GIT_COMMIT = "customInstructionsGitCommit";
3738
public static final String GITHUB_COPILOT_URL = "http://github.com";
39+
public static final String GITHUB_COPILOT_SETTINGS_URL = "https://github.com/settings/copilot";
40+
public static final String GITHUB_COPILOT_INDIVIDUAL_UPGRADE_URL = "https://gh.io/ghcp-individual-upgrade";
3841
@Deprecated
3942
public static final String QUICK_START_VERSION = "quickStartVersion";
4043
public static final String COPILOT_QUICK_START_VERSION = "copilotQuickStartVersion";

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/CopilotLanguageServerSettings.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ public static class CopilotSettings {
278278

279279
private CopilotAgentSettings agent;
280280

281+
private int usageAlertThreshold;
282+
281283
/**
282284
* Constructor.
283285
*/
@@ -320,19 +322,29 @@ public void setAgent(CopilotAgentSettings agent) {
320322
this.agent = agent;
321323
}
322324

325+
public int getUsageAlertThreshold() {
326+
return usageAlertThreshold;
327+
}
328+
329+
public void setUsageAlertThreshold(int usageAlertThreshold) {
330+
this.usageAlertThreshold = usageAlertThreshold;
331+
}
332+
323333
@Override
324334
public String toString() {
325335
ToStringBuilder builder = new ToStringBuilder(this);
326336
builder.append("mcpServers", mcpServers);
327337
builder.append("workspaceCopilotInstructions", workspaceCopilotInstructions);
328338
builder.append("gitCommitCopilotInstructions", gitCommitCopilotInstructions);
329339
builder.append("agent", agent);
340+
builder.append("usageAlertThreshold", usageAlertThreshold);
330341
return builder.toString();
331342
}
332343

333344
@Override
334345
public int hashCode() {
335-
return Objects.hash(agent, gitCommitCopilotInstructions, mcpServers, workspaceCopilotInstructions);
346+
return Objects.hash(agent, gitCommitCopilotInstructions, mcpServers, usageAlertThreshold,
347+
workspaceCopilotInstructions);
336348
}
337349

338350
@Override
@@ -346,7 +358,7 @@ public boolean equals(Object obj) {
346358
CopilotSettings other = (CopilotSettings) obj;
347359
return Objects.equals(agent, other.agent)
348360
&& Objects.equals(gitCommitCopilotInstructions, other.gitCommitCopilotInstructions)
349-
&& Objects.equals(mcpServers, other.mcpServers)
361+
&& Objects.equals(mcpServers, other.mcpServers) && usageAlertThreshold == other.usageAlertThreshold
350362
&& Objects.equals(workspaceCopilotInstructions, other.workspaceCopilotInstructions);
351363
}
352364
}

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/quota/CheckQuotaResult.java

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ public class CheckQuotaResult {
1111
private Quota chat;
1212
private Quota completions;
1313
private Quota premiumInteractions;
14-
private IntervalQuota immediateUsageInterval;
15-
private IntervalQuota extendedUsageInterval;
14+
private TbbQuota immediateUsageInterval;
15+
private TbbQuota extendedUsageInterval;
1616
private String resetDate;
17+
private String resetDateUtc;
1718
private CopilotPlan copilotPlan;
1819

1920
public Quota getChatQuota() {
@@ -40,28 +41,6 @@ public void setPremiumInteractionsQuota(Quota premiumInteractions) {
4041
this.premiumInteractions = premiumInteractions;
4142
}
4243

43-
/**
44-
* Gets the immediate usage interval quota (for individual plans).
45-
*/
46-
public IntervalQuota getImmediateUsageInterval() {
47-
return immediateUsageInterval;
48-
}
49-
50-
public void setImmediateUsageInterval(IntervalQuota immediateUsageInterval) {
51-
this.immediateUsageInterval = immediateUsageInterval;
52-
}
53-
54-
/**
55-
* Gets the extended usage interval quota (for individual plans).
56-
*/
57-
public IntervalQuota getExtendedUsageInterval() {
58-
return extendedUsageInterval;
59-
}
60-
61-
public void setExtendedUsageInterval(IntervalQuota extendedUsageInterval) {
62-
this.extendedUsageInterval = extendedUsageInterval;
63-
}
64-
6544
public String getResetDate() {
6645
return resetDate;
6746
}
@@ -70,6 +49,14 @@ public void setResetDate(String resetDate) {
7049
this.resetDate = resetDate;
7150
}
7251

52+
public String getResetDateUtc() {
53+
return resetDateUtc;
54+
}
55+
56+
public void setResetDateUtc(String resetDateUtc) {
57+
this.resetDateUtc = resetDateUtc;
58+
}
59+
7360
public CopilotPlan getCopilotPlan() {
7461
return copilotPlan;
7562
}
@@ -78,10 +65,26 @@ public void setCopilotPlan(CopilotPlan copilotPlan) {
7865
this.copilotPlan = copilotPlan;
7966
}
8067

68+
public TbbQuota getImmediateUsageInterval() {
69+
return immediateUsageInterval;
70+
}
71+
72+
public void setImmediateUsageInterval(TbbQuota immediateUsageInterval) {
73+
this.immediateUsageInterval = immediateUsageInterval;
74+
}
75+
76+
public TbbQuota getExtendedUsageInterval() {
77+
return extendedUsageInterval;
78+
}
79+
80+
public void setExtendedUsageInterval(TbbQuota extendedUsageInterval) {
81+
this.extendedUsageInterval = extendedUsageInterval;
82+
}
83+
8184
@Override
8285
public int hashCode() {
83-
return Objects.hash(chat, completions, copilotPlan, extendedUsageInterval,
84-
immediateUsageInterval, premiumInteractions, resetDate);
86+
return Objects.hash(chat, completions, copilotPlan, extendedUsageInterval, immediateUsageInterval,
87+
premiumInteractions, resetDate, resetDateUtc);
8588
}
8689

8790
@Override
@@ -97,11 +100,11 @@ public boolean equals(Object obj) {
97100
}
98101
CheckQuotaResult other = (CheckQuotaResult) obj;
99102
return Objects.equals(chat, other.chat) && Objects.equals(completions, other.completions)
100-
&& copilotPlan == other.copilotPlan
101-
&& Objects.equals(extendedUsageInterval, other.extendedUsageInterval)
103+
&& copilotPlan == other.copilotPlan && Objects.equals(premiumInteractions, other.premiumInteractions)
104+
&& Objects.equals(resetDate, other.resetDate)
105+
&& Objects.equals(resetDateUtc, other.resetDateUtc)
102106
&& Objects.equals(immediateUsageInterval, other.immediateUsageInterval)
103-
&& Objects.equals(premiumInteractions, other.premiumInteractions)
104-
&& Objects.equals(resetDate, other.resetDate);
107+
&& Objects.equals(extendedUsageInterval, other.extendedUsageInterval);
105108
}
106109

107110
@Override
@@ -110,10 +113,11 @@ public String toString() {
110113
builder.append("chat", chat);
111114
builder.append("completions", completions);
112115
builder.append("premiumInteractions", premiumInteractions);
113-
builder.append("immediateUsageInterval", immediateUsageInterval);
114-
builder.append("extendedUsageInterval", extendedUsageInterval);
115116
builder.append("resetDate", resetDate);
117+
builder.append("resetDateUtc", resetDateUtc);
116118
builder.append("copilotPlan", copilotPlan);
119+
builder.append("immediateUsageInterval", immediateUsageInterval);
120+
builder.append("extendedUsageInterval", extendedUsageInterval);
117121
return builder.toString();
118122
}
119123
}

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/quota/IntervalQuota.java

Lines changed: 0 additions & 14 deletions
This file was deleted.

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/quota/Quota.java

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,23 @@
22

33
import java.util.Objects;
44

5+
import com.google.gson.annotations.SerializedName;
56
import org.apache.commons.lang3.builder.ToStringBuilder;
67

78
/**
8-
* Completions quota information.
9+
* Quota information for Copilot usage (completions, chat, premium interactions, etc.).
910
*/
1011
public class Quota {
1112
private double percentRemaining;
1213
private boolean unlimited;
1314
private boolean overagePermitted;
14-
private Integer entitlement;
15-
private Integer quotaRemaining;
16-
private String timeStamp;
15+
private int entitlement;
16+
private int quotaRemaining;
17+
@SerializedName("timeStamp")
18+
private String timestamp;
1719

1820
/**
19-
* Creates a new CompletionsQuota quota information with default values.
20-
*/
21-
public Quota() {
22-
this.percentRemaining = 0.0;
23-
this.unlimited = false;
24-
this.overagePermitted = false;
25-
}
26-
27-
/**
28-
* Gets the percentage of the quota remaining within the range of 0.0 to 100.0.
21+
* Gets the percentage of the quota remaining, clamped to [0.0, 100.0].
2922
*/
3023
public double getPercentRemaining() {
3124
if (percentRemaining < 0.0) {
@@ -56,60 +49,48 @@ public void setOveragePermitted(boolean overagePermitted) {
5649
this.overagePermitted = overagePermitted;
5750
}
5851

59-
/**
60-
* Gets the total entitlement (quota limit).
61-
*/
62-
public Integer getEntitlement() {
52+
public int getEntitlement() {
6353
return entitlement;
6454
}
6555

66-
public void setEntitlement(Integer entitlement) {
56+
public void setEntitlement(int entitlement) {
6757
this.entitlement = entitlement;
6858
}
6959

70-
/**
71-
* Gets the remaining quota count.
72-
*/
73-
public Integer getQuotaRemaining() {
60+
public int getQuotaRemaining() {
7461
return quotaRemaining;
7562
}
7663

77-
public void setQuotaRemaining(Integer quotaRemaining) {
64+
public void setQuotaRemaining(int quotaRemaining) {
7865
this.quotaRemaining = quotaRemaining;
7966
}
8067

81-
/**
82-
* Gets the timestamp of the quota snapshot.
83-
*/
84-
public String getTimeStamp() {
85-
return timeStamp;
68+
public String getTimestamp() {
69+
return timestamp;
8670
}
8771

88-
public void setTimeStamp(String timeStamp) {
89-
this.timeStamp = timeStamp;
72+
public void setTimestamp(String timestamp) {
73+
this.timestamp = timestamp;
9074
}
9175

9276
@Override
9377
public int hashCode() {
94-
return Objects.hash(entitlement, overagePermitted, percentRemaining, quotaRemaining, timeStamp, unlimited);
78+
return Objects.hash(entitlement, overagePermitted, percentRemaining, quotaRemaining, timestamp, unlimited);
9579
}
9680

9781
@Override
9882
public boolean equals(Object obj) {
9983
if (this == obj) {
10084
return true;
10185
}
102-
if (obj == null) {
103-
return false;
104-
}
105-
if (getClass() != obj.getClass()) {
86+
if (obj == null || getClass() != obj.getClass()) {
10687
return false;
10788
}
10889
Quota other = (Quota) obj;
109-
return Objects.equals(entitlement, other.entitlement) && overagePermitted == other.overagePermitted
110-
&& Double.doubleToLongBits(percentRemaining) == Double.doubleToLongBits(other.percentRemaining)
111-
&& Objects.equals(quotaRemaining, other.quotaRemaining) && Objects.equals(timeStamp, other.timeStamp)
112-
&& unlimited == other.unlimited;
90+
return Double.doubleToLongBits(percentRemaining) == Double.doubleToLongBits(other.percentRemaining)
91+
&& unlimited == other.unlimited && overagePermitted == other.overagePermitted
92+
&& entitlement == other.entitlement && quotaRemaining == other.quotaRemaining
93+
&& Objects.equals(timestamp, other.timestamp);
11394
}
11495

11596
@Override
@@ -120,7 +101,7 @@ public String toString() {
120101
builder.append("overagePermitted", overagePermitted);
121102
builder.append("entitlement", entitlement);
122103
builder.append("quotaRemaining", quotaRemaining);
123-
builder.append("timeStamp", timeStamp);
104+
builder.append("timestamp", timestamp);
124105
return builder.toString();
125106
}
126107
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.microsoft.copilot.eclipse.core.lsp.protocol.quota;
2+
3+
import java.util.Objects;
4+
5+
import org.apache.commons.lang3.builder.ToStringBuilder;
6+
7+
/**
8+
* Token based billing quota information with a reset timestamp.
9+
*/
10+
public class TbbQuota extends Quota {
11+
private String resetAt;
12+
13+
public String getResetAt() {
14+
return resetAt;
15+
}
16+
17+
public void setResetAt(String resetAt) {
18+
this.resetAt = resetAt;
19+
}
20+
21+
@Override
22+
public int hashCode() {
23+
return Objects.hash(super.hashCode(), resetAt);
24+
}
25+
26+
@Override
27+
public boolean equals(Object obj) {
28+
if (this == obj) {
29+
return true;
30+
}
31+
if (!(obj instanceof TbbQuota)) {
32+
return false;
33+
}
34+
if (!super.equals(obj)) {
35+
return false;
36+
}
37+
TbbQuota other = (TbbQuota) obj;
38+
return Objects.equals(resetAt, other.resetAt);
39+
}
40+
41+
@Override
42+
public String toString() {
43+
ToStringBuilder builder = new ToStringBuilder(this);
44+
builder.appendSuper(super.toString());
45+
builder.append("resetAt", resetAt);
46+
return builder.toString();
47+
}
48+
}

com.microsoft.copilot.eclipse.ui/plugin.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ page.preferencesPage.mcp.name=Model Context Protocol (MCP)
3838
page.preferencesPage.customInstructions.name=Custom Instructions
3939
page.preferencesPage.byok.name=Model Management
4040
page.preferencesPage.customAgents.name=Custom Agents
41+
page.preferencesPage.usageStatus.name=Usage Status
4142
page.showViewPage.name=GitHub Copilot
4243
page.showViewPageShowChatView.name=Chat
4344

com.microsoft.copilot.eclipse.ui/plugin.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@
175175
category="com.microsoft.copilot.eclipse.ui.preferences.CopilotPreferencesPage"
176176
class="com.microsoft.copilot.eclipse.ui.preferences.CustomModesPreferencePage">
177177
</page>
178+
<page
179+
id="com.microsoft.copilot.eclipse.ui.preferences.UsageStatusPreferencePage"
180+
name="%page.preferencesPage.usageStatus.name"
181+
category="com.microsoft.copilot.eclipse.ui.preferences.CopilotPreferencesPage"
182+
class="com.microsoft.copilot.eclipse.ui.preferences.UsageStatusPreferencePage">
183+
</page>
178184
</extension>
179185
<!-- Content type for agent.md files
180186
Matches *.md files but the describer validates only *.agent.md -->

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ private void addCopilotUsageAction(MenuManager menuManager) {
234234
percentRemaining = Math.min(quotaStatus.getCompletionsQuota().getPercentRemaining(),
235235
quotaStatus.getChatQuota().getPercentRemaining());
236236
} else {
237+
if (quotaStatus.getPremiumInteractionsQuota() == null
238+
|| quotaStatus.getCompletionsQuota() == null || quotaStatus.getChatQuota() == null) {
239+
return;
240+
}
237241
// For paid plans, also consider premium interactions quota
238242
percentRemaining = Math.min(quotaStatus.getCompletionsQuota().getPercentRemaining(),
239243
Math.min(quotaStatus.getChatQuota().getPercentRemaining(),

0 commit comments

Comments
 (0)