Skip to content

Commit 762758d

Browse files
committed
feat: update CLI message UI for /compact
1 parent 51ad132 commit 762758d

8 files changed

Lines changed: 36 additions & 7 deletions

File tree

‎README-en.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Skills are discovered from these locations, in priority order:
7777
| `/resume` | Choose a previous conversation to continue |
7878
| `/fork` | Fork the current conversation |
7979
| `/continue` | Continue the active conversation or pick one to resume |
80+
| `/compact` | Manually compact the current conversation context |
8081
| `/model` | Switch model, thinking mode, and reasoning effort |
8182
| `/raw` | Toggle display mode (Normal / Lite / Raw scrollback) |
8283
| `/init` | Initialize an AGENTS.md file (LLM project instructions) |

‎README-zh_CN.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ Skills 会按以下优先级扫描:
7676
| `/resume` | 选择历史对话继续 |
7777
| `/fork` | 从当前对话创建独立的新会话 |
7878
| `/continue` | 继续当前对话,或选择历史对话恢复 |
79+
| `/compact` | 手动压缩当前对话上下文 |
7980
| `/model` | 切换模型、思考模式和推理强度 |
8081
| `/raw` | 切换显示模式(Normal / Lite / Raw 滚动回溯) |
8182
| `/init` | 初始化 AGENTS.md 文件 |

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ Skills 会按以下优先级扫描:
7676
| `/resume` | 选择历史对话继续 |
7777
| `/fork` | 从当前对话创建独立的新会话 |
7878
| `/continue` | 继续当前对话,或选择历史对话恢复 |
79+
| `/compact` | 手动压缩当前对话上下文 |
7980
| `/model` | 切换模型、思考模式和推理强度 |
8081
| `/raw` | 切换显示模式(Normal / Lite / Raw 滚动回溯) |
8182
| `/init` | 初始化 AGENTS.md 文件 |

‎packages/cli/src/tests/compact-command.test.ts‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ async function harness(t: TestContext, compact: (signal: AbortSignal) => Promise
5959
const prompt = t.mock.method(SessionManager.prototype, "handleUserPrompt", async () => {});
6060
const interrupt = t.mock.method(SessionManager.prototype, "interruptActiveSession", () => {});
6161
const compaction = t.mock.method(
62-
SessionManager.prototype,
63-
"compactSession",
62+
SessionManager.prototype as unknown as {
63+
compactSessionOnce(sessionId: string, signal: AbortSignal, retain: number): Promise<boolean>;
64+
},
65+
"compactSessionOnce",
6466
async (id: string, signal?: AbortSignal) => {
6567
assert.equal(id, entry.id);
6668
assert.ok(signal);
@@ -136,13 +138,15 @@ test("/compact preserves displayed history, refreshes usage and waits for anothe
136138
await h.submit();
137139
assert.equal(h.compaction.mock.callCount(), 1);
138140
assert.equal(h.prompt.mock.callCount(), 0);
139-
assert.match(h.latest(), /Conversation compacted\./);
141+
assert.match(h.latest(), /> Conversation compacted\./);
142+
assert.equal(h.latest().match(/Conversation compacted\./g)?.length, 1);
143+
assert.ok(h.frames.some((frame) => frame.includes("Compacting conversation...")));
140144
assert.match(h.latest(), /1000\//);
141145
assert.ok(h.frames.some((frame) => frame.includes("Keep this conversation visible")));
142146
assert.ok(h.list.mock.callCount() > refreshes);
143147
await h.submit("Continue working");
144148
assert.equal(h.prompt.mock.callCount(), 1);
145-
assert.doesNotMatch(h.latest(), /Conversation compacted\./);
149+
assert.match(h.latest(), /> Conversation compacted\./);
146150
});
147151

148152
test("/compact reports no active conversation without starting a request", async (t) => {

‎packages/cli/src/ui/views/App.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ function App({ projectRoot, initialPrompt, resumeSessionId, forkSessionId, onRes
351351
const session = sessionManager.getSession(sessionId);
352352
setStatusLine(session ? buildStatusLine(session, resolveCurrentSettings(projectRoot)) : "");
353353
refreshSessionsList();
354-
setCommandNotice(changed ? "Conversation compacted." : "Conversation was not compacted.");
354+
if (!changed) setCommandNotice("Conversation was not compacted.");
355355
} catch (error) {
356356
if (compactionControllerRef.current !== controller) return;
357357
if (controller.signal.aborted) {

‎packages/core/src/session.ts‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2087,7 +2087,14 @@ ${agentInstructions}
20872087
}
20882088

20892089
async compactSession(sessionId: string, signal?: AbortSignal): Promise<boolean> {
2090-
return await this.compactSessionOnce(sessionId, signal ?? new AbortController().signal, 0);
2090+
const compactionSignal = signal ?? new AbortController().signal;
2091+
compactionSignal.throwIfAborted();
2092+
this.onAssistantMessage(this.buildAssistantMessage(sessionId, "Compacting conversation...", null), false);
2093+
const changed = await this.compactSessionOnce(sessionId, compactionSignal, 0);
2094+
if (changed) {
2095+
this.onAssistantMessage(this.buildUserMessage(sessionId, { text: "Conversation compacted." }), false);
2096+
}
2097+
return changed;
20912098
}
20922099

20932100
/** Commit only a complete, smaller checkpoint against an unchanged selected history. */

‎packages/core/src/tests/compaction.test.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ function fixture(history: SessionMessage[], respond: (request: any, call: number
5555
process.env.HOME = root;
5656
process.env.USERPROFILE = root;
5757
const requests: any[] = [];
58+
const notices: SessionMessage[] = [];
5859
const settings = {
5960
model: "test-vision",
6061
contextWindow: 256 * 1024,
@@ -79,14 +80,15 @@ function fixture(history: SessionMessage[], respond: (request: any, call: number
7980
}),
8081
getResolvedSettings: () => settings,
8182
renderMarkdown: (text) => text,
82-
onAssistantMessage: () => {},
83+
onAssistantMessage: (message) => notices.push(message),
8384
});
8485
const internal = manager as any;
8586
internal.saveSessionMessages("compact-test", history);
8687
return {
8788
manager,
8889
internal,
8990
requests,
91+
notices,
9092
settings,
9193
root,
9294
read: () => manager.listSessionMessages("compact-test"),
@@ -104,13 +106,25 @@ test("manual compaction reports whether it changed history", async () => {
104106
const empty = fixture([]);
105107
assert.equal(await empty.compact(), false);
106108
assert.equal(empty.requests.length, 0);
109+
assert.deepEqual(
110+
empty.notices.map((item) => item.content),
111+
["Compacting conversation..."]
112+
);
107113
const short = fixture([message("only")]);
108114
assert.equal(await short.compact(), false);
109115
assert.equal(short.requests.length, 0);
110116
const history = [message("older"), message("reply", "assistant"), message("tail")];
111117
const ready = fixture(history);
112118
assert.equal(await ready.compact(), true);
113119
assert.equal(ready.requests.length, 1);
120+
assert.deepEqual(
121+
ready.notices.map((item) => [item.role, item.content]),
122+
[
123+
["assistant", "Compacting conversation..."],
124+
["user", "Conversation compacted."],
125+
]
126+
);
127+
assert.ok(ready.notices.every((notice) => !ready.read().some((item) => item.id === notice.id)));
114128
assert.deepEqual(
115129
ready
116130
.read()

‎packages/core/templates/skills/bundled/deepcode-self-refer/references/README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ Skills 会按以下优先级扫描:
7878
| `/new` | 开始新对话 |
7979
| `/resume` | 选择历史对话继续 |
8080
| `/continue` | 继续当前对话,或选择历史对话恢复 |
81+
| `/compact` | 手动压缩当前对话上下文 |
8182
| `/model` | 切换模型、思考模式和推理强度 |
8283
| `/raw` | 切换显示模式(Normal / Lite / Raw 滚动回溯) |
8384
| `/init` | 初始化 AGENTS.md 文件 |

0 commit comments

Comments
 (0)