@@ -393,6 +393,33 @@ export class Cline extends EventEmitter<ClineEvents> {
393393 throw new Error ( `[Cline#ask] task ${ this . taskId } .${ this . instanceId } aborted` )
394394 }
395395
396+ // --- ADD LOGIC FOR chat_input_wait ---
397+ if ( type === "chat_input_wait" ) {
398+ console . log ( "[Cline.ts ask] Waiting for chat input..." )
399+ this . askResponse = undefined // Clear previous response state
400+ this . askResponseText = undefined
401+ this . askResponseImages = undefined
402+ // Don't add a visible message for this internal state
403+ // Signal UI to enable input
404+ const provider = this . providerRef . deref ( )
405+ if ( ! provider ) {
406+ throw new Error ( "[Cline.ts ask] Cannot wait for input, provider reference lost." )
407+ }
408+ await provider . postMessageToWebview ( { type : "acceptInput" } )
409+
410+ // Wait for handleWebviewAskResponse to set this.askResponse
411+ await pWaitFor ( ( ) => this . askResponse !== undefined , { interval : 100 } )
412+
413+ console . log ( "[Cline.ts ask] Resuming after chat input received." )
414+ const result = { response : this . askResponse ! , text : this . askResponseText , images : this . askResponseImages }
415+ this . askResponse = undefined // Clear state for next potential ask
416+ this . askResponseText = undefined
417+ this . askResponseImages = undefined
418+ this . emit ( "taskAskResponded" ) // Emit standard event
419+ return result
420+ }
421+ // --- END LOGIC FOR chat_input_wait ---
422+
396423 let askTs : number
397424
398425 if ( partial !== undefined ) {
@@ -852,8 +879,18 @@ export class Cline extends EventEmitter<ClineEvents> {
852879 }
853880
854881 private async initiateTaskLoop ( userContent : UserContent ) : Promise < void > {
855- // Kicks off the checkpoints initialization process in the background.
856- this . getCheckpointService ( )
882+ // Only kickoff checkpoints for non-chat modes
883+ const provider = this . providerRef . deref ( )
884+ const { mode } = ( await provider ?. getState ( ) ) ?? { }
885+
886+ // Skip checkpoints for continuous chat modes
887+ if ( mode !== "chat" ) {
888+ // Kicks off the checkpoints initialization process in the background.
889+ this . getCheckpointService ( )
890+ } else {
891+ // Disable checkpoints for chat modes
892+ this . enableCheckpoints = false
893+ }
857894
858895 let nextUserContent = userContent
859896 let includeFileDetails = true
@@ -876,10 +913,13 @@ export class Cline extends EventEmitter<ClineEvents> {
876913 // as he can.
877914
878915 if ( didEndLoop ) {
879- // For now a task never 'completes'. This will only happen if
880- // the user hits max requests and denies resetting the count .
916+ // If recursivelyMakeClineRequests returns true, it means the loop should end
917+ // This happens on error, abort, or when chat mode needs user input .
881918 break
882919 } else {
920+ // If recursivelyMakeClineRequests returns false, it means the model didn't end the loop
921+ // (e.g., it completed a turn without using a tool in non-chat mode).
922+ // We need to prepare the input for the next iteration of this loop.
883923 nextUserContent = [ { type : "text" , text : formatResponse . noToolsUsed ( ) } ]
884924 this . consecutiveMistakeCount ++
885925 }
@@ -1011,6 +1051,32 @@ export class Cline extends EventEmitter<ClineEvents> {
10111051 )
10121052 } ) ( )
10131053
1054+ // =================================
1055+ // DEBUG: Log API request details
1056+ // =================================
1057+ console . log ( `\n\n========== ROO CODE API REQUEST (${ new Date ( ) . toISOString ( ) } ) ==========` )
1058+ console . log ( `Mode: ${ mode || "default" } ` )
1059+ console . log ( `System prompt length: ${ systemPrompt . length } characters` )
1060+ console . log ( `Conversation history: ${ this . apiConversationHistory . length } messages` )
1061+
1062+ // Count total tokens in system prompt + conversation history
1063+ const modelInfo = this . api . getModel ( ) . info
1064+ console . log ( `Model: ${ this . api . getModel ( ) . id } , Context window: ${ modelInfo . contextWindow } tokens` )
1065+
1066+ // Detailed debug info on each message
1067+ if ( mode === "chat" ) {
1068+ console . log ( `\n======= MINIMAL MODE DEBUG INFO =======` )
1069+ console . log ( `System prompt: ${ systemPrompt } ...` )
1070+ console . log (
1071+ `\nLast user message content: ${
1072+ this . apiConversationHistory . length > 0 &&
1073+ this . apiConversationHistory [ this . apiConversationHistory . length - 1 ] . role === "user"
1074+ ? JSON . stringify ( this . apiConversationHistory [ this . apiConversationHistory . length - 1 ] . content )
1075+ : "No user message"
1076+ } ...`,
1077+ )
1078+ }
1079+
10141080 // If the previous API request's total token usage is close to the context window, truncate the conversation history to free up space for the new request
10151081 if ( previousApiReqIndex >= 0 ) {
10161082 const previousRequest = this . clineMessages [ previousApiReqIndex ] ?. text
@@ -1199,7 +1265,7 @@ export class Cline extends EventEmitter<ClineEvents> {
11991265 // (have to do this for partial and complete since sending content in thinking tags to markdown renderer will automatically be removed)
12001266 // Remove end substrings of <thinking or </thinking (below xml parsing is only for opening tags)
12011267 // (this is done with the xml parsing below now, but keeping here for reference)
1202- // content = content.replace(/<\/?t(?:h(?:i(?:n(?:k(?:i(?:n(?:g)?)?)?$/, "")
1268+ // content = content.replace(/<\/?t(?:h(?:i(?:n(?:k(?:i(?:n(?:g)?)?)?)? $/, "")
12031269 // Remove all instances of <thinking> (with optional line break after) and </thinking> (with optional line break before)
12041270 // - Needs to be separate since we dont want to remove the line break before the first tag
12051271 // - Needs to happen before the xml parsing below
@@ -1545,7 +1611,7 @@ export class Cline extends EventEmitter<ClineEvents> {
15451611 if ( ! block . partial || this . didRejectTool || this . didAlreadyUseTool ) {
15461612 // block is finished streaming and executing
15471613 if ( this . currentStreamingContentIndex === this . assistantMessageContent . length - 1 ) {
1548- // its okay that we increment if !didCompleteReadingStream, it'll just return bc out of bounds and as streaming continues it will call presentAssitantMessage if a new block is ready. if streaming is finished then we set userMessageContentReady to true when out of bounds. This gracefully allows the stream to continue on and all potential content blocks be presented.
1614+ // its okay that we increment if !didCompleteReadingStream, it'll just return bc out of bounds and as streaming continues it will call presentAssistantMessage if a new block is ready. if streaming is finished then we set userMessageContentReady to true when out of bounds. This gracefully allows the stream to continue on and all potential content blocks be presented.
15491615 // last block is complete and it is finished executing
15501616 this . userMessageContentReady = true // will allow pwaitfor to continue
15511617 }
@@ -1892,15 +1958,52 @@ export class Cline extends EventEmitter<ClineEvents> {
18921958 // if the model did not tool use, then we need to tell it to either use a tool or attempt_completion
18931959 const didToolUse = this . assistantMessageContent . some ( ( block ) => block . type === "tool_use" )
18941960 if ( ! didToolUse ) {
1895- this . userMessageContent . push ( {
1896- type : "text" ,
1897- text : formatResponse . noToolsUsed ( ) ,
1898- } )
1899- this . consecutiveMistakeCount ++
1900- }
1961+ // --- Get provider and mode ---
1962+ const provider = this . providerRef . deref ( )
1963+ const { mode } = ( await provider ?. getState ( ) ) ?? { }
19011964
1902- const recDidEndLoop = await this . recursivelyMakeClineRequests ( this . userMessageContent )
1903- didEndLoop = recDidEndLoop
1965+ if ( mode !== "chat" ) {
1966+ // Non-chat mode, no tool use: Add feedback and recurse internally
1967+ this . userMessageContent . push ( {
1968+ type : "text" ,
1969+ text : formatResponse . noToolsUsed ( ) ,
1970+ } )
1971+ this . consecutiveMistakeCount ++
1972+ // Continue the loop by recursing with the feedback message
1973+ // Return the boolean result of this recursive call
1974+ return await this . recursivelyMakeClineRequests ( this . userMessageContent , false )
1975+ } else {
1976+ // Chat mode, no tool use: Use ask('chat_input_wait') to pause and get input
1977+ console . log ( "[Cline.ts] Chat mode, no tool use. Waiting for next user input via ask." )
1978+ const { response, text, images } = await this . ask ( "chat_input_wait" )
1979+
1980+ if ( response === "messageResponse" ) {
1981+ // User provided input
1982+ const nextUserContent : UserContent = [ ]
1983+ if ( text ) nextUserContent . push ( { type : "text" , text } )
1984+ if ( images ) nextUserContent . push ( ...formatResponse . imageBlocks ( images ) )
1985+
1986+ if ( nextUserContent . length > 0 ) {
1987+ // Add user input to UI (ask doesn't add messages for chat_input_wait)
1988+ await this . say ( "user_feedback" , text , images )
1989+ // Recurse with the new user input
1990+ return await this . recursivelyMakeClineRequests ( nextUserContent , false )
1991+ } else {
1992+ // Resumed but no content? End the loop.
1993+ console . warn ( "[Cline.ts] Resumed chat wait but received no content." )
1994+ return true
1995+ }
1996+ } else {
1997+ // User likely cancelled or something went wrong during the ask wait. End the loop.
1998+ console . log ( "[Cline.ts] Chat input wait did not receive messageResponse." )
1999+ return true
2000+ }
2001+ }
2002+ } else {
2003+ // Tool use detected: tool results are already prepared in this.userMessageContent
2004+ // by presentAssistantMessage. Continue the loop by recursing.
2005+ return await this . recursivelyMakeClineRequests ( this . userMessageContent , false )
2006+ }
19042007 } else {
19052008 // if there's no assistant_responses, that means we got no text or tool_use content blocks from API which we should assume is an error
19062009 await this . say (
@@ -1996,10 +2099,13 @@ export class Cline extends EventEmitter<ClineEvents> {
19962099 }
19972100
19982101 async getEnvironmentDetails ( includeFileDetails : boolean = false ) {
2102+ const state = await this . providerRef . deref ( ) ?. getState ( )
2103+
2104+ if ( state ?. mode === "chat" ) return ""
2105+
19992106 let details = ""
20002107
2001- const { terminalOutputLineLimit = 500 , maxWorkspaceFiles = 200 } =
2002- ( await this . providerRef . deref ( ) ?. getState ( ) ) ?? { }
2108+ const { terminalOutputLineLimit = 500 , maxWorkspaceFiles = 200 } = state ?? { }
20032109
20042110 // It could be useful for cline to know if the user went from one or no file to another between messages, so we always include this context
20052111 details += "\n\n# VSCode Visible Files"
@@ -2196,6 +2302,7 @@ export class Cline extends EventEmitter<ClineEvents> {
21962302
21972303 details += `\n\n# Current Mode\n`
21982304 details += `<slug>${ currentMode } </slug>\n`
2305+
21992306 details += `<name>${ modeDetails . name } </name>\n`
22002307 details += `<model>${ apiModelId } </model>\n`
22012308
0 commit comments