Skip to content

Commit b2628ba

Browse files
authored
feat: Implement auto compression feature for chat context (#250)
1 parent 2ad0568 commit b2628ba

16 files changed

Lines changed: 681 additions & 17 deletions

File tree

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/events/CopilotEventConstants.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,14 @@ public class CopilotEventConstants {
176176
* conversation templates on receipt.
177177
*/
178178
public static final String TOPIC_CHAT_DID_CHANGE_CUSTOMIZATION_FILES = TOPIC_CHAT + "DID_CHANGE_CUSTOMIZATION_FILES";
179+
180+
/**
181+
* Event when automatic conversation compression starts.
182+
*/
183+
public static final String TOPIC_CHAT_COMPRESSION_STARTED = TOPIC_CHAT + "COMPRESSION_STARTED";
184+
185+
/**
186+
* Event when automatic conversation compression completes.
187+
*/
188+
public static final String TOPIC_CHAT_COMPRESSION_COMPLETED = TOPIC_CHAT + "COMPRESSION_COMPLETED";
179189
}

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/CopilotLanguageClient.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
import com.microsoft.copilot.eclipse.core.lsp.mcp.McpOauthRequest;
4444
import com.microsoft.copilot.eclipse.core.lsp.mcp.McpRuntimeLog;
4545
import com.microsoft.copilot.eclipse.core.lsp.protocol.ChatProgressValue;
46+
import com.microsoft.copilot.eclipse.core.lsp.protocol.CompressionCompletedParams;
47+
import com.microsoft.copilot.eclipse.core.lsp.protocol.CompressionStartedParams;
4648
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationCapabilities;
4749
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationContextParams;
4850
import com.microsoft.copilot.eclipse.core.lsp.protocol.CurrentEditorContext;
@@ -366,6 +368,26 @@ public void onQuotaWarning(QuotaWarningParams params) {
366368
}
367369
}
368370

371+
/**
372+
* Notify when automatic conversation compression starts.
373+
*/
374+
@JsonNotification("$/copilot/compressionStarted")
375+
public void onCompressionStarted(CompressionStartedParams params) {
376+
if (eventBroker != null) {
377+
eventBroker.post(CopilotEventConstants.TOPIC_CHAT_COMPRESSION_STARTED, params);
378+
}
379+
}
380+
381+
/**
382+
* Notify when automatic conversation compression completes.
383+
*/
384+
@JsonNotification("$/copilot/compressionCompleted")
385+
public void onCompressionCompleted(CompressionCompletedParams params) {
386+
if (eventBroker != null) {
387+
eventBroker.post(CopilotEventConstants.TOPIC_CHAT_COMPRESSION_COMPLETED, params);
388+
}
389+
}
390+
369391
/**
370392
* Reads the contents and stats of a file given its URI.
371393
*/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
package com.microsoft.copilot.eclipse.core.lsp.protocol;
5+
6+
/**
7+
* Parameters for the {@code $/copilot/compressionCompleted} notification sent by the language server when automatic
8+
* conversation compression finishes. The {@code contextInfo} field is optional and may be {@code null}.
9+
*/
10+
public record CompressionCompletedParams(
11+
String conversationId,
12+
int archivedPartitionId,
13+
int newPartitionId,
14+
int summaryLength,
15+
int turnCount,
16+
int durationMs,
17+
ContextSizeInfo contextInfo) {
18+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
package com.microsoft.copilot.eclipse.core.lsp.protocol;
5+
6+
/**
7+
* Parameters for the {@code $/copilot/compressionStarted} notification sent by the language server when automatic
8+
* conversation compression begins.
9+
*/
10+
public record CompressionStartedParams(String conversationId, int partitionId, String reason) {
11+
}

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class CopilotAgentSettings {
1717
@SerializedName("maxToolCallingLoop")
1818
private int agentMaxRequests;
1919
private boolean enableSkills;
20+
private boolean autoCompress;
2021

2122
private String transcriptDirectory;
2223

@@ -178,6 +179,14 @@ public String getTranscriptDirectory() {
178179
return transcriptDirectory;
179180
}
180181

182+
public boolean isAutoCompress() {
183+
return autoCompress;
184+
}
185+
186+
public void setAutoCompress(boolean autoCompress) {
187+
this.autoCompress = autoCompress;
188+
}
189+
181190
public void setTranscriptDirectory(String transcriptDirectory) {
182191
this.transcriptDirectory = transcriptDirectory;
183192
}
@@ -212,7 +221,7 @@ public ToolsSettings getTools() {
212221

213222
@Override
214223
public int hashCode() {
215-
return Objects.hash(agentMaxRequests, enableSkills, transcriptDirectory,
224+
return Objects.hash(agentMaxRequests, enableSkills, autoCompress, transcriptDirectory,
216225
editorHandlesAllConfirmation, autoApproveUnmatchedTerminal, autoApproveUnmatchedFileOp, tools);
217226
}
218227

@@ -229,6 +238,7 @@ public boolean equals(Object obj) {
229238
}
230239
CopilotAgentSettings other = (CopilotAgentSettings) obj;
231240
return agentMaxRequests == other.agentMaxRequests && enableSkills == other.enableSkills
241+
&& autoCompress == other.autoCompress
232242
&& Objects.equals(transcriptDirectory, other.transcriptDirectory)
233243
&& editorHandlesAllConfirmation == other.editorHandlesAllConfirmation
234244
&& autoApproveUnmatchedTerminal == other.autoApproveUnmatchedTerminal
@@ -241,6 +251,7 @@ public String toString() {
241251
ToStringBuilder builder = new ToStringBuilder(this);
242252
builder.append("agentMaxRequests", agentMaxRequests);
243253
builder.append("enableSkills", enableSkills);
254+
builder.append("autoCompress", autoCompress);
244255
builder.append("transcriptDirectory", transcriptDirectory);
245256
builder.append("editorHandlesAllConfirmation", editorHandlesAllConfirmation);
246257
builder.append("autoApproveUnmatchedTerminal", autoApproveUnmatchedTerminal);
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Auto Context Compression
2+
3+
## Overview
4+
Verifies the **Auto Compress** feature that automatically compresses long
5+
conversations to keep context usage within the model's limit. Auto Compress
6+
is always enabled (no user-facing preference). While compression is in
7+
progress, the chat view shows a "Compacting conversation..." spinner below
8+
the latest Copilot turn, and the context size donut updates once it
9+
completes.
10+
11+
Entry points:
12+
- **Copilot Chat view** → latest Copilot turn (spinner banner appears here).
13+
- **Copilot Chat view** → control bar **Context Size Donut** (updates after
14+
compression completes).
15+
16+
---
17+
18+
## Prerequisites
19+
20+
- Eclipse IDE with the GitHub Copilot for Eclipse plugin installed (built from
21+
the branch containing the staged Auto Compress changes).
22+
- A valid GitHub Copilot subscription is active (authentication completed).
23+
- A model that supports a finite context window is selected (so the donut and
24+
compression can be exercised — e.g. Claude Sonnet 4.6 or GPT-4.1).
25+
- The Copilot Chat view is open and visible.
26+
27+
---
28+
29+
## Test Cases
30+
31+
### TC-001: Compacting banner appears when compression starts
32+
33+
**Type:** `Happy Path`
34+
**Priority:** `P0`
35+
36+
#### Preconditions
37+
- The Copilot Chat view is open with a new conversation.
38+
39+
#### Steps
40+
1. Start a conversation and drive the context usage toward the model limit —
41+
for example, attach several large files and/or run multiple tool-heavy
42+
turns until the **Context Size Donut** approaches its warning threshold
43+
(≥90 %).
44+
2. Continue sending messages until the conversation goes over the threshold
45+
so the server initiates automatic compression.
46+
3. Observe the latest Copilot turn while the server processes the request.
47+
48+
#### Expected Result
49+
- A small banner appears **below the latest Copilot turn** containing:
50+
- An animated spinner.
51+
- The status text **"Compacting conversation..."**.
52+
- The chat view layout refreshes so the banner is fully visible (not clipped).
53+
- No error dialogs are shown.
54+
55+
#### 📸 Key Screenshots
56+
- [ ] **Compacting banner** — spinner + "Compacting conversation..." text
57+
rendered under the latest Copilot turn.
58+
59+
---
60+
61+
### TC-002: Compacting banner is dismissed and context donut updates on completion
62+
63+
**Type:** `Happy Path`
64+
**Priority:** `P0`
65+
66+
#### Preconditions
67+
- TC-001 has been executed and the "Compacting conversation..." banner is
68+
currently visible.
69+
70+
#### Steps
71+
1. Wait for the server to finish compression (typically a few seconds).
72+
2. Observe the latest Copilot turn after compression completes.
73+
3. Hover the **Context Size Donut** in the chat view control bar.
74+
75+
#### Expected Result
76+
- The "Compacting conversation..." banner is removed from the Copilot turn.
77+
- The chat view scroller relayouts cleanly (no leftover blank space, no
78+
clipping).
79+
- The Context Size Donut updates to reflect the new, smaller token usage
80+
(the ring's filled portion shrinks).
81+
- The **Context Window** popup shows the post-compression token breakdown
82+
consistent with the new total.
83+
- The subsequent reply continues to stream normally on top of the freshly
84+
compressed history.
85+
86+
#### 📸 Key Screenshots
87+
- [ ] **After completion** — Copilot turn without the banner.
88+
- [ ] **Donut after compression** — Context Size Donut showing reduced usage.
89+
- [ ] **Context Window popup** — Token breakdown after compression.
90+
91+
---
92+
93+
### TC-003: Cancelling a chat hides the compacting banner
94+
95+
**Type:** `Edge Case`
96+
**Priority:** `P1`
97+
98+
#### Preconditions
99+
- A conversation is set up so the next send will trigger compression
100+
(as in TC-001).
101+
102+
#### Steps
103+
1. Send the message that triggers compression and wait for the
104+
"Compacting conversation..." banner to appear.
105+
2. While the banner is showing, click the **Cancel** (stop) button in the
106+
chat input action bar.
107+
108+
#### Expected Result
109+
- The send button is restored from its stop/cancel state back to its normal
110+
send state.
111+
- The "Compacting conversation..." banner is removed from the latest Copilot
112+
turn.
113+
- Any buffered reply text that arrived just before cancellation is rendered
114+
(no missing trailing line).
115+
- The chat view relayouts cleanly so the flushed reply is fully visible.
116+
- The user can immediately send a new message in the same conversation.
117+
118+
#### 📸 Key Screenshots
119+
- [ ] **After cancel** — banner gone, send button reset, any buffered reply
120+
visible.
121+
122+
---
123+
124+
### TC-004: Compacting banner only updates the matching conversation
125+
126+
**Type:** `Edge Case`
127+
**Priority:** `P2`
128+
129+
#### Preconditions
130+
- Two conversations exist in chat history: *Conversation A* (about to
131+
trigger compression) and *Conversation B* (short, well under the limit).
132+
133+
#### Steps
134+
1. In *Conversation A*, send a message that triggers compression and wait
135+
for the "Compacting conversation..." banner to appear.
136+
2. Without waiting for completion, open chat history and switch to
137+
*Conversation B*.
138+
3. Inspect *Conversation B* for any compaction banner.
139+
4. Switch back to *Conversation A*.
140+
141+
#### Expected Result
142+
- *Conversation B* never shows a "Compacting conversation..." banner — the
143+
compaction status is scoped to *Conversation A* only.
144+
- When you return to *Conversation A*, its state is consistent with the
145+
compression outcome (banner cleared if it completed in the meantime; new
146+
reply continues to stream if still in progress).
147+
- No errors or stale spinners are left behind in either conversation.
148+
149+
#### 📸 Key Screenshots
150+
- [ ] **Conversation B during A's compaction** — no banner shown.
151+
152+
---
153+
154+
## Screenshots Checklist
155+
> Consolidated list of all key screenshot moments.
156+
157+
- [ ] `TC-001` Compacting banner under latest Copilot turn.
158+
- [ ] `TC-002` Copilot turn after compaction completes (banner gone).
159+
- [ ] `TC-002` Context Size Donut after compaction (reduced usage).
160+
- [ ] `TC-002` Context Window popup with post-compaction token breakdown.
161+
- [ ] `TC-003` State after cancel — banner gone, send button reset, buffered
162+
reply visible.
163+
- [ ] `TC-004` Conversation B during Conversation A's compaction (no banner).

0 commit comments

Comments
 (0)