@@ -114,6 +114,7 @@ import { processFilesIntoText } from "@integrations/misc/extract-text"
114114import { featureFlagsService } from "@services/posthog/feature-flags/FeatureFlagsService"
115115import { StreamingJsonReplacer , ChangeLocation } from "@core/assistant-message/diff-json"
116116import { isClaude4ModelFamily } from "@/utils/model-utils"
117+ import { saveClineMessagesAndUpdateHistory } from "./message-state"
117118
118119export const USE_EXPERIMENTAL_CLAUDE4_FEATURES = false
119120
@@ -343,52 +344,28 @@ export class Task {
343344 message . conversationHistoryIndex = this . apiConversationHistory . length - 1 // NOTE: this is the index of the last added message which is the user message, and once the clinemessages have been presented we update the apiconversationhistory with the completed assistant message. This means when resetting to a message, we need to +1 this index to get the correct assistant message that this tool use corresponds to
344345 message . conversationHistoryDeletedRange = this . conversationHistoryDeletedRange
345346 this . clineMessages . push ( message )
346- await this . saveClineMessagesAndUpdateHistory ( )
347+ await saveClineMessagesAndUpdateHistory (
348+ this . getContext ( ) ,
349+ this . taskId ,
350+ this . clineMessages ,
351+ this . taskIsFavorited ?? false ,
352+ this . conversationHistoryDeletedRange ,
353+ this . checkpointTracker ,
354+ this . updateTaskHistory ,
355+ )
347356 }
348357
349358 private async overwriteClineMessages ( newMessages : ClineMessage [ ] ) {
350359 this . clineMessages = newMessages
351- await this . saveClineMessagesAndUpdateHistory ( )
352- }
353-
354- private async saveClineMessagesAndUpdateHistory ( ) {
355- try {
356- await saveClineMessages ( this . getContext ( ) , this . taskId , this . clineMessages )
357-
358- // combined as they are in ChatView
359- const apiMetrics = getApiMetrics ( combineApiRequests ( combineCommandSequences ( this . clineMessages . slice ( 1 ) ) ) )
360- const taskMessage = this . clineMessages [ 0 ] // first message is always the task say
361- const lastRelevantMessage =
362- this . clineMessages [
363- findLastIndex ( this . clineMessages , ( m ) => ! ( m . ask === "resume_task" || m . ask === "resume_completed_task" ) )
364- ]
365- const taskDir = await ensureTaskDirectoryExists ( this . getContext ( ) , this . taskId )
366- let taskDirSize = 0
367- try {
368- // getFolderSize.loose silently ignores errors
369- // returns # of bytes, size/1000/1000 = MB
370- taskDirSize = await getFolderSize . loose ( taskDir )
371- } catch ( error ) {
372- console . error ( "Failed to get task directory size:" , taskDir , error )
373- }
374- await this . updateTaskHistory ( {
375- id : this . taskId ,
376- ts : lastRelevantMessage . ts ,
377- task : taskMessage . text ?? "" ,
378- tokensIn : apiMetrics . totalTokensIn ,
379- tokensOut : apiMetrics . totalTokensOut ,
380- cacheWrites : apiMetrics . totalCacheWrites ,
381- cacheReads : apiMetrics . totalCacheReads ,
382- totalCost : apiMetrics . totalCost ,
383- size : taskDirSize ,
384- shadowGitConfigWorkTree : await this . checkpointTracker ?. getShadowGitConfigWorkTree ( ) ,
385- cwdOnTaskInitialization : cwd ,
386- conversationHistoryDeletedRange : this . conversationHistoryDeletedRange ,
387- isFavorited : this . taskIsFavorited ,
388- } )
389- } catch ( error ) {
390- console . error ( "Failed to save cline messages:" , error )
391- }
360+ await saveClineMessagesAndUpdateHistory (
361+ this . getContext ( ) ,
362+ this . taskId ,
363+ this . clineMessages ,
364+ this . taskIsFavorited ?? false ,
365+ this . conversationHistoryDeletedRange ,
366+ this . checkpointTracker ,
367+ this . updateTaskHistory ,
368+ )
392369 }
393370
394371 async restoreCheckpoint ( messageTs : number , restoreType : ClineCheckpointRestore , offset ?: number ) {
@@ -515,9 +492,15 @@ export class Task {
515492 } )
516493 }
517494
518- await this . saveClineMessagesAndUpdateHistory ( )
519-
520- sendRelinquishControlEvent ( )
495+ await saveClineMessagesAndUpdateHistory (
496+ this . getContext ( ) ,
497+ this . taskId ,
498+ this . clineMessages ,
499+ this . taskIsFavorited ?? false ,
500+ this . conversationHistoryDeletedRange ,
501+ this . checkpointTracker ,
502+ this . updateTaskHistory ,
503+ )
521504
522505 this . cancelTask ( ) // the task is already cancelled by the provider beforehand, but we need to re-init to get the updated messages
523506 } else {
@@ -790,7 +773,15 @@ export class Task {
790773 // lastMessage.ts = askTs
791774 lastMessage . text = text
792775 lastMessage . partial = false
793- await this . saveClineMessagesAndUpdateHistory ( )
776+ await saveClineMessagesAndUpdateHistory (
777+ this . getContext ( ) ,
778+ this . taskId ,
779+ this . clineMessages ,
780+ this . taskIsFavorited ?? false ,
781+ this . conversationHistoryDeletedRange ,
782+ this . checkpointTracker ,
783+ this . updateTaskHistory ,
784+ )
794785 // await this.postStateToWebview()
795786 const protoMessage = convertClineMessageToProto ( lastMessage )
796787 await sendPartialMessageEvent ( protoMessage )
@@ -898,7 +889,15 @@ export class Task {
898889 lastMessage . partial = false
899890
900891 // instead of streaming partialMessage events, we do a save and post like normal to persist to disk
901- await this . saveClineMessagesAndUpdateHistory ( )
892+ await saveClineMessagesAndUpdateHistory (
893+ this . getContext ( ) ,
894+ this . taskId ,
895+ this . clineMessages ,
896+ this . taskIsFavorited ?? false ,
897+ this . conversationHistoryDeletedRange ,
898+ this . checkpointTracker ,
899+ this . updateTaskHistory ,
900+ )
902901 // await this.postStateToWebview()
903902 const protoMessage = convertClineMessageToProto ( lastMessage )
904903 await sendPartialMessageEvent ( protoMessage ) // more performant than an entire postStateToWebview
@@ -947,8 +946,15 @@ export class Task {
947946 const lastMessage = this . clineMessages . at ( - 1 )
948947 if ( lastMessage ?. partial && lastMessage . type === type && ( lastMessage . ask === askOrSay || lastMessage . say === askOrSay ) ) {
949948 this . clineMessages . pop ( )
950- await this . saveClineMessagesAndUpdateHistory ( )
951- await this . postStateToWebview ( )
949+ await saveClineMessagesAndUpdateHistory (
950+ this . getContext ( ) ,
951+ this . taskId ,
952+ this . clineMessages ,
953+ this . taskIsFavorited ?? false ,
954+ this . conversationHistoryDeletedRange ,
955+ this . checkpointTracker ,
956+ this . updateTaskHistory ,
957+ )
952958 }
953959 }
954960
@@ -1232,7 +1238,15 @@ export class Task {
12321238 const lastCheckpointMessage = findLast ( this . clineMessages , ( m ) => m . say === "checkpoint_created" )
12331239 if ( lastCheckpointMessage ) {
12341240 lastCheckpointMessage . lastCheckpointHash = commitHash
1235- await this . saveClineMessagesAndUpdateHistory ( )
1241+ await saveClineMessagesAndUpdateHistory (
1242+ this . getContext ( ) ,
1243+ this . taskId ,
1244+ this . clineMessages ,
1245+ this . taskIsFavorited ?? false ,
1246+ this . conversationHistoryDeletedRange ,
1247+ this . checkpointTracker ,
1248+ this . updateTaskHistory ,
1249+ )
12361250 }
12371251 } ) // silently fails for now
12381252
@@ -1264,7 +1278,15 @@ export class Task {
12641278 )
12651279 if ( lastCompletionResultMessage ) {
12661280 lastCompletionResultMessage . lastCheckpointHash = commitHash
1267- await this . saveClineMessagesAndUpdateHistory ( )
1281+ await saveClineMessagesAndUpdateHistory (
1282+ this . getContext ( ) ,
1283+ this . taskId ,
1284+ this . clineMessages ,
1285+ this . taskIsFavorited ?? false ,
1286+ this . conversationHistoryDeletedRange ,
1287+ this . checkpointTracker ,
1288+ this . updateTaskHistory ,
1289+ )
12681290 }
12691291 } else {
12701292 console . error ( "Checkpoint tracker does not exist and could not be initialized for attempt completion" )
@@ -1702,7 +1724,15 @@ export class Task {
17021724
17031725 if ( contextManagementMetadata . updatedConversationHistoryDeletedRange ) {
17041726 this . conversationHistoryDeletedRange = contextManagementMetadata . conversationHistoryDeletedRange
1705- await this . saveClineMessagesAndUpdateHistory ( ) // saves task history item which we use to keep track of conversation history deleted range
1727+ await saveClineMessagesAndUpdateHistory (
1728+ this . getContext ( ) ,
1729+ this . taskId ,
1730+ this . clineMessages ,
1731+ this . taskIsFavorited ?? false ,
1732+ this . conversationHistoryDeletedRange ,
1733+ this . checkpointTracker ,
1734+ this . updateTaskHistory ,
1735+ ) // saves task history item which we use to keep track of conversation history deleted range
17061736 }
17071737
17081738 let stream = this . api . createMessage ( systemPrompt , contextManagementMetadata . truncatedConversationHistory )
@@ -1727,7 +1757,15 @@ export class Task {
17271757 this . conversationHistoryDeletedRange ,
17281758 "quarter" , // Force aggressive truncation
17291759 )
1730- await this . saveClineMessagesAndUpdateHistory ( )
1760+ await saveClineMessagesAndUpdateHistory (
1761+ this . getContext ( ) ,
1762+ this . taskId ,
1763+ this . clineMessages ,
1764+ this . taskIsFavorited ?? false ,
1765+ this . conversationHistoryDeletedRange ,
1766+ this . checkpointTracker ,
1767+ this . updateTaskHistory ,
1768+ )
17311769 await this . contextManager . triggerApplyStandardContextTruncationNoticeChange (
17321770 Date . now ( ) ,
17331771 await ensureTaskDirectoryExists ( this . getContext ( ) , this . taskId ) ,
@@ -1741,7 +1779,15 @@ export class Task {
17411779 this . conversationHistoryDeletedRange ,
17421780 "quarter" , // Force aggressive truncation
17431781 )
1744- await this . saveClineMessagesAndUpdateHistory ( )
1782+ await saveClineMessagesAndUpdateHistory (
1783+ this . getContext ( ) ,
1784+ this . taskId ,
1785+ this . clineMessages ,
1786+ this . taskIsFavorited ?? false ,
1787+ this . conversationHistoryDeletedRange ,
1788+ this . checkpointTracker ,
1789+ this . updateTaskHistory ,
1790+ )
17451791 await this . contextManager . triggerApplyStandardContextTruncationNoticeChange (
17461792 Date . now ( ) ,
17471793 await ensureTaskDirectoryExists ( this . getContext ( ) , this . taskId ) ,
@@ -3505,8 +3551,15 @@ export class Task {
35053551 ...sharedMessage ,
35063552 selected : text ,
35073553 } satisfies ClineAskQuestion )
3508- await this . saveClineMessagesAndUpdateHistory ( )
3509- telemetryService . captureOptionSelected ( this . taskId , options . length , "act" )
3554+ await saveClineMessagesAndUpdateHistory (
3555+ this . getContext ( ) ,
3556+ this . taskId ,
3557+ this . clineMessages ,
3558+ this . taskIsFavorited ?? false ,
3559+ this . conversationHistoryDeletedRange ,
3560+ this . checkpointTracker ,
3561+ this . updateTaskHistory ,
3562+ )
35103563 }
35113564 } else {
35123565 // Option not selected, send user feedback
@@ -3638,7 +3691,15 @@ export class Task {
36383691 this . conversationHistoryDeletedRange ,
36393692 keepStrategy ,
36403693 )
3641- await this . saveClineMessagesAndUpdateHistory ( )
3694+ await saveClineMessagesAndUpdateHistory (
3695+ this . getContext ( ) ,
3696+ this . taskId ,
3697+ this . clineMessages ,
3698+ this . taskIsFavorited ?? false ,
3699+ this . conversationHistoryDeletedRange ,
3700+ this . checkpointTracker ,
3701+ this . updateTaskHistory ,
3702+ )
36423703 await this . contextManager . triggerApplyStandardContextTruncationNoticeChange (
36433704 Date . now ( ) ,
36443705 await ensureTaskDirectoryExists ( this . getContext ( ) , this . taskId ) ,
@@ -3939,8 +4000,15 @@ export class Task {
39394000 ...sharedMessage ,
39404001 selected : text ,
39414002 } satisfies ClinePlanModeResponse )
3942- await this . saveClineMessagesAndUpdateHistory ( )
3943- telemetryService . captureOptionSelected ( this . taskId , options . length , "plan" )
4003+ await saveClineMessagesAndUpdateHistory (
4004+ this . getContext ( ) ,
4005+ this . taskId ,
4006+ this . clineMessages ,
4007+ this . taskIsFavorited ?? false ,
4008+ this . conversationHistoryDeletedRange ,
4009+ this . checkpointTracker ,
4010+ this . updateTaskHistory ,
4011+ )
39444012 }
39454013 } else {
39464014 // Option not selected, send user feedback
@@ -4042,7 +4110,15 @@ export class Task {
40424110 ) {
40434111 lastCompletionResultMessage . text += COMPLETION_RESULT_CHANGES_FLAG
40444112 }
4045- await this . saveClineMessagesAndUpdateHistory ( )
4113+ await saveClineMessagesAndUpdateHistory (
4114+ this . getContext ( ) ,
4115+ this . taskId ,
4116+ this . clineMessages ,
4117+ this . taskIsFavorited ?? false ,
4118+ this . conversationHistoryDeletedRange ,
4119+ this . checkpointTracker ,
4120+ this . updateTaskHistory ,
4121+ )
40464122 }
40474123
40484124 try {
@@ -4377,7 +4453,15 @@ export class Task {
43774453 this . clineMessages [ lastApiReqIndex ] . text = JSON . stringify ( {
43784454 request : userContent . map ( ( block ) => formatContentBlockToMarkdown ( block ) ) . join ( "\n\n" ) ,
43794455 } satisfies ClineApiReqInfo )
4380- await this . saveClineMessagesAndUpdateHistory ( )
4456+ await saveClineMessagesAndUpdateHistory (
4457+ this . getContext ( ) ,
4458+ this . taskId ,
4459+ this . clineMessages ,
4460+ this . taskIsFavorited ?? false ,
4461+ this . conversationHistoryDeletedRange ,
4462+ this . checkpointTracker ,
4463+ this . updateTaskHistory ,
4464+ )
43814465 await this . postStateToWebview ( )
43824466
43834467 try {
@@ -4448,7 +4532,15 @@ export class Task {
44484532
44494533 // update api_req_started to have cancelled and cost, so that we can display the cost of the partial stream
44504534 updateApiReqMsg ( cancelReason , streamingFailedMessage )
4451- await this . saveClineMessagesAndUpdateHistory ( )
4535+ await saveClineMessagesAndUpdateHistory (
4536+ this . getContext ( ) ,
4537+ this . taskId ,
4538+ this . clineMessages ,
4539+ this . taskIsFavorited ?? false ,
4540+ this . conversationHistoryDeletedRange ,
4541+ this . checkpointTracker ,
4542+ this . updateTaskHistory ,
4543+ )
44524544
44534545 telemetryService . captureConversationTurnEvent (
44544546 this . taskId ,
@@ -4574,7 +4666,15 @@ export class Task {
45744666 totalCost = apiStreamUsage . totalCost
45754667 }
45764668 updateApiReqMsg ( )
4577- await this . saveClineMessagesAndUpdateHistory ( )
4669+ await saveClineMessagesAndUpdateHistory (
4670+ this . getContext ( ) ,
4671+ this . taskId ,
4672+ this . clineMessages ,
4673+ this . taskIsFavorited ?? false ,
4674+ this . conversationHistoryDeletedRange ,
4675+ this . checkpointTracker ,
4676+ this . updateTaskHistory ,
4677+ )
45784678 await this . postStateToWebview ( )
45794679 } )
45804680 }
@@ -4598,7 +4698,15 @@ export class Task {
45984698 }
45994699
46004700 updateApiReqMsg ( )
4601- await this . saveClineMessagesAndUpdateHistory ( )
4701+ await saveClineMessagesAndUpdateHistory (
4702+ this . getContext ( ) ,
4703+ this . taskId ,
4704+ this . clineMessages ,
4705+ this . taskIsFavorited ?? false ,
4706+ this . conversationHistoryDeletedRange ,
4707+ this . checkpointTracker ,
4708+ this . updateTaskHistory ,
4709+ )
46024710 await this . postStateToWebview ( )
46034711
46044712 // now add to apiconversationhistory
0 commit comments