(
workspaceId: string,
summaryMessage: MuxMessage,
options?: {
mode?: "destructive" | "append-compaction-boundary" | null;
deletePlanFile?: boolean;
}
)
| 8065 | } |
| 8066 | |
| 8067 | async replaceHistory( |
| 8068 | workspaceId: string, |
| 8069 | summaryMessage: MuxMessage, |
| 8070 | options?: { |
| 8071 | mode?: "destructive" | "append-compaction-boundary" | null; |
| 8072 | deletePlanFile?: boolean; |
| 8073 | } |
| 8074 | ): Promise<Result<void>> { |
| 8075 | // Support both new enum ("user"|"idle") and legacy boolean (true) |
| 8076 | const isCompaction = !!summaryMessage.metadata?.compacted; |
| 8077 | if (!isCompaction) { |
| 8078 | const session = this.sessions.get(workspaceId); |
| 8079 | if (session?.isBusy() || this.aiService.isStreaming(workspaceId)) { |
| 8080 | return Err( |
| 8081 | "Cannot replace history while a turn is active. Press Esc to stop the stream first." |
| 8082 | ); |
| 8083 | } |
| 8084 | } |
| 8085 | |
| 8086 | const replaceMode = options?.mode ?? "destructive"; |
| 8087 | |
| 8088 | try { |
| 8089 | let messageToAppend = summaryMessage; |
| 8090 | let deletedSequences: number[] = []; |
| 8091 | |
| 8092 | if (replaceMode === "append-compaction-boundary") { |
| 8093 | assert( |
| 8094 | summaryMessage.role === "assistant", |
| 8095 | "append-compaction-boundary replace mode requires an assistant summary message" |
| 8096 | ); |
| 8097 | |
| 8098 | // Only need the current epoch's messages — the latest boundary marker holds |
| 8099 | // the max compaction epoch, and epochs are monotonically increasing with |
| 8100 | // append-only compaction. Falls back to full history for uncompacted workspaces. |
| 8101 | const historyResult = await this.historyService.getHistoryFromLatestBoundary(workspaceId); |
| 8102 | if (!historyResult.success) { |
| 8103 | return Err( |
| 8104 | `Failed to read history for append-compaction-boundary mode: ${historyResult.error}` |
| 8105 | ); |
| 8106 | } |
| 8107 | |
| 8108 | const nextCompactionEpoch = getNextCompactionEpochForAppendBoundary( |
| 8109 | workspaceId, |
| 8110 | historyResult.data |
| 8111 | ); |
| 8112 | assert( |
| 8113 | isPositiveInteger(nextCompactionEpoch), |
| 8114 | "append-compaction-boundary replace mode must compute a positive compaction epoch" |
| 8115 | ); |
| 8116 | |
| 8117 | const compactedMarker = isDurableCompactedMarker(summaryMessage.metadata?.compacted) |
| 8118 | ? summaryMessage.metadata.compacted |
| 8119 | : "user"; |
| 8120 | |
| 8121 | messageToAppend = { |
| 8122 | ...summaryMessage, |
| 8123 | metadata: { |
| 8124 | ...(summaryMessage.metadata ?? {}), |
no test coverage detected