@@ -86,6 +86,9 @@ import { ApiMessage } from "../task-persistence/apiMessages"
8686import { getMessagesSinceLastSummary , summarizeConversation } from "../condense"
8787import { maybeRemoveImageBlocks } from "../../api/transform/image-cleaning"
8888
89+ // Constants
90+ export const DEFAULT_CKPT_INIT_TIMEOUT_MS = 10000 // 10 seconds
91+
8992export type ClineEvents = {
9093 message : [ { action : "created" | "updated" ; message : ClineMessage } ]
9194 taskStarted : [ ]
@@ -105,6 +108,7 @@ export type TaskOptions = {
105108 apiConfiguration : ProviderSettings
106109 enableDiff ?: boolean
107110 enableCheckpoints ?: boolean
111+ checkpointInitTimeoutMs ?: number
108112 fuzzyMatchThreshold ?: number
109113 consecutiveMistakeLimit ?: number
110114 task ?: string
@@ -186,6 +190,7 @@ export class Task extends EventEmitter<ClineEvents> {
186190
187191 // Checkpoints
188192 enableCheckpoints : boolean
193+ checkpointInitTimeoutMs : number
189194 checkpointService ?: RepoPerTaskCheckpointService
190195 checkpointServiceInitializing = false
191196
@@ -207,6 +212,7 @@ export class Task extends EventEmitter<ClineEvents> {
207212 apiConfiguration,
208213 enableDiff = false ,
209214 enableCheckpoints = true ,
215+ checkpointInitTimeoutMs = DEFAULT_CKPT_INIT_TIMEOUT_MS ,
210216 fuzzyMatchThreshold = 1.0 ,
211217 consecutiveMistakeLimit = 3 ,
212218 task,
@@ -252,6 +258,7 @@ export class Task extends EventEmitter<ClineEvents> {
252258 this . globalStoragePath = provider . context . globalStorageUri . fsPath
253259 this . diffViewProvider = new DiffViewProvider ( this . cwd )
254260 this . enableCheckpoints = enableCheckpoints
261+ this . checkpointInitTimeoutMs = checkpointInitTimeoutMs
255262
256263 this . rootTask = rootTask
257264 this . parentTask = parentTask
@@ -1108,8 +1115,8 @@ export class Task extends EventEmitter<ClineEvents> {
11081115 // Task Loop
11091116
11101117 private async initiateTaskLoop ( userContent : Anthropic . Messages . ContentBlockParam [ ] ) : Promise < void > {
1111- // Kicks off the checkpoints initialization process in the background.
1112- getCheckpointService ( this )
1118+ // Ensure checkpoint initialization completes before starting the main loop to prevent content duplication
1119+ await this . ensureCheckpointInitialization ( )
11131120
11141121 let nextUserContent = userContent
11151122 let includeFileDetails = true
@@ -1142,6 +1149,60 @@ export class Task extends EventEmitter<ClineEvents> {
11421149 }
11431150 }
11441151
1152+ /**
1153+ * Ensures checkpoint initialization completes before proceeding with task execution.
1154+ * This prevents content duplication issues where checkpoint_saved messages arrive
1155+ * after model streaming has already started.
1156+ *
1157+ * @param timeout - Configurable timeout in milliseconds (default: 10 seconds)
1158+ */
1159+ private async ensureCheckpointInitialization ( ) : Promise < void > {
1160+ if ( ! this . enableCheckpoints ) {
1161+ return
1162+ }
1163+
1164+ const provider = this . providerRef . deref ( )
1165+ if ( ! provider ) {
1166+ return
1167+ }
1168+
1169+ try {
1170+ // Start checkpoint service initialization
1171+ const service = getCheckpointService ( this )
1172+ if ( ! service ) {
1173+ return
1174+ }
1175+
1176+ // Wait for initialization to complete or timeout
1177+ await pWaitFor (
1178+ ( ) => {
1179+ if ( this . abort ) {
1180+ return true // Exit early if task is aborted
1181+ }
1182+ return service . isInitialized || ! this . enableCheckpoints
1183+ } ,
1184+ {
1185+ interval : 100 ,
1186+ timeout : this . checkpointInitTimeoutMs ,
1187+ } ,
1188+ )
1189+
1190+ // If still initializing after timeout, disable checkpoints and continue
1191+ if ( ! service . isInitialized && this . enableCheckpoints ) {
1192+ provider . log (
1193+ `[Task#ensureCheckpointInitialization] checkpoint initialization timed out after ${ this . checkpointInitTimeoutMs } ms, disabling checkpoints` ,
1194+ )
1195+ this . enableCheckpoints = false
1196+ }
1197+ } catch ( error ) {
1198+ // If checkpoint initialization fails, disable checkpoints and continue
1199+ provider ?. log (
1200+ `[Task#ensureCheckpointInitialization] checkpoint initialization failed: ${ error } , disabling checkpoints` ,
1201+ )
1202+ this . enableCheckpoints = false
1203+ }
1204+ }
1205+
11451206 public async recursivelyMakeClineRequests (
11461207 userContent : Anthropic . Messages . ContentBlockParam [ ] ,
11471208 includeFileDetails : boolean = false ,
0 commit comments