@@ -1786,39 +1786,56 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
17861786 * to replace the stored messages outright.
17871787 */
17881788 private async saveClineMessages ( merge = true ) : Promise < boolean > {
1789- // One save at a time per task, from the message write to the task-history write: callers that do not wait for it
1790- // (the fire-and-forget ones) would otherwise let an older save's metadata land after a newer save's and replace
1791- // it, an explicit clear of the usage breakdown included. A save that fails does not hold up the next one.
1792- const run = this . saveClineMessagesQueue . then (
1793- ( ) => this . persistClineMessages ( merge ) ,
1794- ( ) => this . persistClineMessages ( merge ) ,
1789+ // Two queues. The message writes go one at a time, and a write never waits for the metadata of the save before
1790+ // it: the messages are what must reach the disk, so a slow history write cannot delay them. The metadata stage
1791+ // (the history entry, derived from the messages that save persisted) also goes one at a time, in the order the
1792+ // message writes finished, which is the order the saves were asked for: callers that do not wait for a save (the
1793+ // fire-and-forget ones) would otherwise let an older save's metadata land after a newer save's and replace it,
1794+ // an explicit clear of the usage breakdown included. A save that fails does not hold up the next one.
1795+ const written = this . saveClineMessagesQueue . then (
1796+ ( ) => this . writeClineMessages ( merge ) ,
1797+ ( ) => this . writeClineMessages ( merge ) ,
17951798 )
1796- this . saveClineMessagesQueue = run . then (
1799+ this . saveClineMessagesQueue = written . then (
17971800 ( ) => undefined ,
17981801 ( ) => undefined ,
17991802 )
1800- return run
1803+
1804+ return written . then ( async ( result ) => {
1805+ if ( ! result . saved ) return false
1806+ const metadata = this . saveTaskMetadataQueue . then ( ( ) => this . writeTaskMetadata ( result . persistedMessages ) )
1807+ this . saveTaskMetadataQueue = metadata
1808+ await metadata
1809+ return true
1810+ } )
18011811 }
18021812
18031813 private saveClineMessagesQueue : Promise < void > = Promise . resolve ( )
1814+ private saveTaskMetadataQueue : Promise < void > = Promise . resolve ( )
18041815
1805- private async persistClineMessages ( merge : boolean ) : Promise < boolean > {
1816+ /** The message write: `saved` is whether it reached the disk, and `persistedMessages` what was actually stored. */
1817+ private async writeClineMessages (
1818+ merge : boolean ,
1819+ ) : Promise < { saved : false } | { saved : true ; persistedMessages : ClineMessage [ ] | undefined } > {
18061820 // What was actually persisted: with `merge`, newer messages another host wrote are folded in. The metadata
18071821 // (including the usage breakdown) is computed from it, so a stale local snapshot cannot clear usage that
18081822 // the stored messages still contain.
1809- let persistedMessages : ClineMessage [ ] | undefined
18101823 try {
1811- persistedMessages = await saveTaskMessages ( {
1824+ const persistedMessages = await saveTaskMessages ( {
18121825 messages : structuredClone ( this . clineMessages ) ,
18131826 taskId : this . taskId ,
18141827 globalStoragePath : this . globalStoragePath ,
18151828 merge,
18161829 } )
1830+ return { saved : true , persistedMessages }
18171831 } catch ( error ) {
18181832 console . error ( "Failed to save Roo messages:" , error )
1819- return false
1833+ return { saved : false }
18201834 }
1835+ }
18211836
1837+ /** The metadata stage of a save: it never fails the save, whose messages are already persisted. */
1838+ private async writeTaskMetadata ( persistedMessages : ClineMessage [ ] | undefined ) : Promise < void > {
18221839 try {
18231840 if ( this . _taskApiConfigName === undefined ) {
18241841 await this . taskApiConfigReady
@@ -1853,8 +1870,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
18531870 // recomputes and re-emits the metadata update.
18541871 console . error ( "Failed to save task metadata:" , error )
18551872 }
1856-
1857- return true
18581873 }
18591874
18601875 private findMessageByTimestamp ( ts : number ) : ClineMessage | undefined {
0 commit comments