Skip to content

Commit 9536b05

Browse files
committed
feat: Implement quota warning handling and UI updates for TBB
1 parent 60dd17b commit 9536b05

27 files changed

Lines changed: 442 additions & 518 deletions

File tree

com.microsoft.copilot.eclipse.core.test/src/com/microsoft/copilot/eclipse/core/lsp/CopilotLanguageClientTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ void testOnDidChangeFeatureFlagsWithEmptyFeatureFlags() {
141141

142142
@Test
143143
void testOnQuotaWarning_PostsNotificationToEventBroker() {
144-
QuotaWarningNotification notification = new QuotaWarningNotification("Approaching quota", 90.0);
144+
QuotaWarningNotification notification = new QuotaWarningNotification(
145+
"Copilot Quota Usage Alert", "Approaching quota", "warning", null, null);
145146
setEventBroker(eventBroker);
146147

147148
client.onQuotaWarning(notification);

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@
66
import java.util.Objects;
77

88
import org.apache.commons.lang3.builder.ToStringBuilder;
9-
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
109

1110
/**
1211
* Result of a chat creation.
1312
*/
1413
public class ChatCreateResult {
15-
@NonNull
1614
private String conversationId;
17-
@NonNull
1815
private String turnId;
1916
private String agentSlug;
2017
private String modelName;

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,15 @@ public String getErrorReason() {
101101
return error != null ? error.getReason() : null;
102102
}
103103

104+
/**
105+
* Returns the BYOK model-provider name from the error payload, when present.
106+
*
107+
* @return the name of the BYOK model provider that produced the error, or {@code null} for built-in models.
108+
*/
109+
public String getErrorModelProviderName() {
110+
return error != null ? error.getModelProviderName() : null;
111+
}
112+
104113
public List<AgentRound> getAgentRounds() {
105114
return editAgentRounds;
106115
}

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@
66
import java.util.Objects;
77

88
import org.apache.commons.lang3.builder.ToStringBuilder;
9-
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
109

1110
/**
1211
* Result of a chat turn.
1312
*/
1413
public class ChatTurnResult {
15-
@NonNull
1614
private String conversationId;
17-
@NonNull
1815
private String turnId;
1916
private String agentSlug;
2017
private String modelName;

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class ConversationError {
1919
private String reason;
2020
private boolean responseIsIncomplete;
2121
private boolean responseIsFiltered;
22+
private String modelProviderName;
2223

2324
public void setMessage(String message) {
2425
this.message = message;
@@ -40,6 +41,10 @@ public void setResponseIsFiltered(boolean responseIsFiltered) {
4041
this.responseIsFiltered = responseIsFiltered;
4142
}
4243

44+
public void setModelProviderName(String modelProviderName) {
45+
this.modelProviderName = modelProviderName;
46+
}
47+
4348
public String getMessage() {
4449
return message;
4550
}
@@ -60,9 +65,17 @@ public boolean getResponseIsFiltered() {
6065
return responseIsFiltered;
6166
}
6267

68+
/**
69+
* The name of the model provider that produced the error, when the failing request was routed to a custom
70+
* Bring-Your-Own-Key (BYOK) model. {@code null} or blank for built-in Copilot models.
71+
*/
72+
public String getModelProviderName() {
73+
return modelProviderName;
74+
}
75+
6376
@Override
6477
public int hashCode() {
65-
return Objects.hash(message, code, reason, responseIsIncomplete, responseIsFiltered);
78+
return Objects.hash(message, code, reason, responseIsIncomplete, responseIsFiltered, modelProviderName);
6679
}
6780

6881
@Override
@@ -75,7 +88,8 @@ public boolean equals(Object o) {
7588
}
7689
ConversationError that = (ConversationError) o;
7790
return Objects.equals(message, that.message) && code == that.code && Objects.equals(reason, that.reason)
78-
&& responseIsIncomplete == that.responseIsIncomplete && responseIsFiltered == that.responseIsFiltered;
91+
&& responseIsIncomplete == that.responseIsIncomplete && responseIsFiltered == that.responseIsFiltered
92+
&& Objects.equals(modelProviderName, that.modelProviderName);
7993
}
8094

8195
@Override
@@ -86,6 +100,7 @@ public String toString() {
86100
builder.append("reason", reason);
87101
builder.append("responseIsIncomplete", responseIsIncomplete);
88102
builder.append("responseIsFiltered", responseIsFiltered);
103+
builder.append("modelProviderName", modelProviderName);
89104
return builder.toString();
90105
}
91106
}

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

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,46 @@
33

44
package com.microsoft.copilot.eclipse.core.lsp.protocol.quota;
55

6+
import com.google.gson.annotations.SerializedName;
7+
68
/**
7-
* Parameters for the "copilot/quotaWarning" notification. Sent by the language server when the user's AI quota exceeds
8-
* the warning threshold.
9+
* Parameters for the {@code copilot/quotaWarning} notification. Sent by the language server when the user's AI quota
10+
* exceeds a warning threshold.
11+
*
12+
* @param title the popup title supplied by the language server
13+
* @param message the popup body message
14+
* @param severity the language-server severity hint (e.g. {@code "info"} or {@code "warning"}); used by the client to
15+
* decide which icon to render on the banner. May be {@code null}.
16+
* @param copilotPlan the user's Copilot plan
17+
* @param premiumInteractions the premium-interactions snapshot for the warning, or {@code null} when the language
18+
* server does not include it
919
*/
10-
public record QuotaWarningNotification(String message, double percentUsed) {
20+
public record QuotaWarningNotification(
21+
String title,
22+
String message,
23+
String severity,
24+
CopilotPlan copilotPlan,
25+
@SerializedName("premium_interactions") PremiumInteractions premiumInteractions) {
26+
27+
/**
28+
* Premium-interactions snapshot embedded in a {@link QuotaWarningNotification}. The shape is dictated by the
29+
* language server and differs from {@link Quota}.
30+
*
31+
* @param quota total monthly premium-interactions allowance
32+
* @param used premium interactions consumed so far this period
33+
* @param percentRemaining percentage of the allowance remaining
34+
* @param overageUsed additional paid interactions consumed beyond the allowance
35+
* @param overageEnabled whether the user has enabled paid overage
36+
* @param resetDate ISO-8601 instant when the monthly allowance resets, or {@code null}
37+
* @param unlimited whether this quota has no monthly limit
38+
*/
39+
public record PremiumInteractions(
40+
double quota,
41+
double used,
42+
double percentRemaining,
43+
double overageUsed,
44+
boolean overageEnabled,
45+
String resetDate,
46+
boolean unlimited) {
47+
}
1148
}

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/persistence/ConversationDataFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ private void applyConversationError(ReplyData reply, ConversationError error) {
179179
ErrorData errorData = new ErrorData();
180180
errorData.setMessage(error.getMessage());
181181
errorData.setCode(error.getCode());
182+
errorData.setModelProviderName(error.getModelProviderName());
182183
ErrorMessageData em = new ErrorMessageData();
183184
em.setError(errorData);
184185
reply.getErrorMessages().add(em);

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/persistence/CopilotTurnData.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ public String toString() {
440440
public static class ErrorData {
441441
private String message;
442442
private int code;
443+
private String modelProviderName;
443444
private Map<String, Object> data;
444445

445446
public String getMessage() {
@@ -458,6 +459,18 @@ public void setCode(int code) {
458459
this.code = code;
459460
}
460461

462+
/**
463+
* The BYOK model provider responsible for the error, or {@code null} when the failing model was a
464+
* built-in Copilot model.
465+
*/
466+
public String getModelProviderName() {
467+
return modelProviderName;
468+
}
469+
470+
public void setModelProviderName(String modelProviderName) {
471+
this.modelProviderName = modelProviderName;
472+
}
473+
461474
public Map<String, Object> getData() {
462475
return data;
463476
}
@@ -468,7 +481,7 @@ public void setData(Map<String, Object> data) {
468481

469482
@Override
470483
public int hashCode() {
471-
return Objects.hash(code, data, message);
484+
return Objects.hash(code, data, message, modelProviderName);
472485
}
473486

474487
@Override
@@ -483,14 +496,16 @@ public boolean equals(Object obj) {
483496
return false;
484497
}
485498
ErrorData other = (ErrorData) obj;
486-
return code == other.code && Objects.equals(data, other.data) && Objects.equals(message, other.message);
499+
return code == other.code && Objects.equals(data, other.data) && Objects.equals(message, other.message)
500+
&& Objects.equals(modelProviderName, other.modelProviderName);
487501
}
488502

489503
@Override
490504
public String toString() {
491505
ToStringBuilder builder = new ToStringBuilder(this);
492506
builder.append("message", message);
493507
builder.append("code", code);
508+
builder.append("modelProviderName", modelProviderName);
494509
builder.append("data", data);
495510
return builder.toString();
496511
}

com.microsoft.copilot.eclipse.ui.test/src/com/microsoft/copilot/eclipse/ui/i18n/MessagesTest.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,5 @@ void testMessagesInitialization() {
1414
// Ensure that the static fields are initialized
1515
assertNotNull(Messages.menu_signToGitHub);
1616
assertNotNull(Messages.menu_signOutOfGitHub);
17-
assertNotNull(Messages.quotaWarning_title);
18-
assertNotNull(Messages.quotaWarning_closeButton);
19-
assertNotNull(Messages.quotaWarning_increaseBudgetButton);
2017
}
21-
}
18+
}

com.microsoft.copilot.eclipse.ui.test/src/com/microsoft/copilot/eclipse/ui/notifications/QuotaWarningNotificationPopupTest.java

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

0 commit comments

Comments
 (0)