Skip to content

Commit de386b3

Browse files
committed
refactor: use message queue for compact continue messages
Previously, compact continue messages were handled by a frontend hook (useAutoCompactContinue) that watched for completed compactions and then sent the continue message. This introduced complexity, race conditions, and required tracking processed message IDs. Now leverages the existing message queue system: - Backend queues continue message when compaction starts - Queue auto-sends when compaction stream ends (existing behavior) - Continue message shown in queue UI during compaction - Proper cleanup on all error paths - Strip editMessageId to prevent truncation failures after compaction Net reduction of 134 lines. Simpler, more reliable, better UX.
1 parent c134523 commit de386b3

File tree

10 files changed

+14
-149
lines changed

10 files changed

+14
-149
lines changed

src/browser/App.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { usePersistedState, updatePersistedState } from "./hooks/usePersistedSta
1212
import { matchesKeybind, KEYBINDS } from "./utils/ui/keybinds";
1313
import { useResumeManager } from "./hooks/useResumeManager";
1414
import { useUnreadTracking } from "./hooks/useUnreadTracking";
15-
import { useAutoCompactContinue } from "./hooks/useAutoCompactContinue";
1615
import { useWorkspaceStoreRaw, useWorkspaceRecency } from "./stores/WorkspaceStore";
1716
import { ChatInput } from "./components/ChatInput/index";
1817
import type { ChatInputAPI } from "./components/ChatInput/types";
@@ -116,9 +115,6 @@ function AppInner() {
116115
// Auto-resume interrupted streams on app startup and when failures occur
117116
useResumeManager();
118117

119-
// Handle auto-continue after compaction (when user uses /compact -c)
120-
useAutoCompactContinue();
121-
122118
// Sync selectedWorkspace with URL hash
123119
useEffect(() => {
124120
if (selectedWorkspace) {

src/browser/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ const webApi: IPCApi = {
225225
invokeIPC(IPC_CHANNELS.WORKSPACE_RESUME_STREAM, workspaceId, options),
226226
interruptStream: (workspaceId, options) =>
227227
invokeIPC(IPC_CHANNELS.WORKSPACE_INTERRUPT_STREAM, workspaceId, options),
228-
clearQueue: (workspaceId) => invokeIPC(IPC_CHANNELS.WORKSPACE_QUEUE_CLEAR, workspaceId),
228+
clearQueue: (workspaceId) => invokeIPC(IPC_CHANNELS.WORKSPACE_CLEAR_QUEUE, workspaceId),
229229
truncateHistory: (workspaceId, percentage) =>
230230
invokeIPC(IPC_CHANNELS.WORKSPACE_TRUNCATE_HISTORY, workspaceId, percentage),
231231
replaceChatHistory: (workspaceId, summaryMessage) =>

src/browser/hooks/useAutoCompactContinue.ts

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

src/browser/stores/WorkspaceStore.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -672,12 +672,6 @@ export class WorkspaceStore {
672672
const historicalUsage =
673673
currentUsage.usageHistory.length > 0 ? sumUsageHistory(currentUsage.usageHistory) : undefined;
674674

675-
// Extract continueMessage from compaction-request before history gets replaced
676-
const compactRequestMsg = findCompactionRequestMessage(aggregator);
677-
const muxMeta = compactRequestMsg?.metadata?.muxMetadata;
678-
const continueMessage =
679-
muxMeta?.type === "compaction-request" ? muxMeta.parsed.continueMessage : undefined;
680-
681675
const summaryMessage = createMuxMessage(
682676
`summary-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,
683677
"assistant",
@@ -697,10 +691,7 @@ export class WorkspaceStore {
697691
metadata && "systemMessageTokens" in metadata
698692
? (metadata.systemMessageTokens as number | undefined)
699693
: undefined,
700-
// Store continueMessage in summary so it survives history replacement
701-
muxMetadata: continueMessage
702-
? { type: "compaction-result", continueMessage, requestId: compactRequestMsg?.id }
703-
: { type: "normal" },
694+
muxMetadata: { type: "normal" },
704695
}
705696
);
706697

src/common/constants/ipc-constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const IPC_CHANNELS = {
2525
WORKSPACE_SEND_MESSAGE: "workspace:sendMessage",
2626
WORKSPACE_RESUME_STREAM: "workspace:resumeStream",
2727
WORKSPACE_INTERRUPT_STREAM: "workspace:interruptStream",
28-
WORKSPACE_QUEUE_CLEAR: "workspace:queue:clear",
28+
WORKSPACE_CLEAR_QUEUE: "workspace:clearQueue",
2929
WORKSPACE_TRUNCATE_HISTORY: "workspace:truncateHistory",
3030
WORKSPACE_REPLACE_HISTORY: "workspace:replaceHistory",
3131
WORKSPACE_STREAM_HISTORY: "workspace:streamHistory",

src/common/constants/storage.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,6 @@ export const PREFERRED_COMPACTION_MODEL_KEY = "preferredCompactionModel";
126126
*/
127127
export const VIM_ENABLED_KEY = "vimEnabled";
128128

129-
/**
130-
* Get the localStorage key for the compact continue message for a workspace
131-
* Temporarily stores the continuation prompt for the current compaction
132-
* Should be deleted immediately after use to prevent bugs
133-
*/
134-
export function getCompactContinueMessageKey(workspaceId: string): string {
135-
return `compactContinueMessage:${workspaceId}`;
136-
}
137-
138129
/**
139130
* Get the localStorage key for hunk expand/collapse state in Review tab
140131
* Stores user's manual expand/collapse preferences per hunk
@@ -164,7 +155,6 @@ export function getReviewSearchStateKey(workspaceId: string): string {
164155

165156
/**
166157
* List of workspace-scoped key functions that should be copied on fork and deleted on removal
167-
* Note: Excludes ephemeral keys like getCompactContinueMessageKey
168158
*/
169159
const PERSISTENT_WORKSPACE_KEY_FUNCTIONS: Array<(workspaceId: string) => string> = [
170160
getModelKey,
@@ -183,7 +173,6 @@ const PERSISTENT_WORKSPACE_KEY_FUNCTIONS: Array<(workspaceId: string) => string>
183173
*/
184174
const EPHEMERAL_WORKSPACE_KEY_FUNCTIONS: Array<(workspaceId: string) => string> = [
185175
getCancelledCompactionKey,
186-
getCompactContinueMessageKey,
187176
];
188177

189178
/**

src/common/types/message.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ export type MuxFrontendMetadata =
2020
rawCommand: string; // The original /compact command as typed by user (for display)
2121
parsed: CompactionRequestData;
2222
}
23-
| {
24-
type: "compaction-result";
25-
continueMessage: string; // Message to send after compaction completes
26-
requestId?: string; // ID of the compaction-request user message that produced this summary (for idempotency)
27-
}
2823
| {
2924
type: "normal"; // Regular messages
3025
};

src/desktop/preload.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ const api: IPCApi = {
7575
interruptStream: (workspaceId: string, options?: { abandonPartial?: boolean }) =>
7676
ipcRenderer.invoke(IPC_CHANNELS.WORKSPACE_INTERRUPT_STREAM, workspaceId, options),
7777
clearQueue: (workspaceId: string) =>
78-
ipcRenderer.invoke(IPC_CHANNELS.WORKSPACE_QUEUE_CLEAR, workspaceId),
78+
ipcRenderer.invoke(IPC_CHANNELS.WORKSPACE_CLEAR_QUEUE, workspaceId),
7979
truncateHistory: (workspaceId, percentage) =>
8080
ipcRenderer.invoke(IPC_CHANNELS.WORKSPACE_TRUNCATE_HISTORY, workspaceId, percentage),
8181
replaceChatHistory: (workspaceId, summaryMessage) =>

src/node/services/agentSession.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,15 @@ export class AgentSession {
314314

315315
this.emitChatEvent(userMessage);
316316

317+
// If this is a compaction request with a continue message, queue it for auto-send after compaction
318+
const muxMeta = options?.muxMetadata;
319+
if (muxMeta?.type === "compaction-request" && muxMeta.parsed.continueMessage && options) {
320+
// Strip out edit-specific and compaction-specific fields so the queued message is a fresh user message
321+
const { muxMetadata, mode, editMessageId, ...continueOptions } = options;
322+
this.messageQueue.add(muxMeta.parsed.continueMessage, continueOptions);
323+
this.emitQueuedMessageChanged();
324+
}
325+
317326
if (!options?.model || options.model.trim().length === 0) {
318327
return Err(
319328
createUnknownSendMessageError("No model specified. Please select a model using /model.")

src/node/services/ipcMain.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ export class IpcMain {
10001000
}
10011001
);
10021002

1003-
ipcMain.handle(IPC_CHANNELS.WORKSPACE_QUEUE_CLEAR, (_event, workspaceId: string) => {
1003+
ipcMain.handle(IPC_CHANNELS.WORKSPACE_CLEAR_QUEUE, (_event, workspaceId: string) => {
10041004
try {
10051005
const session = this.getOrCreateSession(workspaceId);
10061006
session.clearQueue();

0 commit comments

Comments
 (0)