@@ -1663,11 +1663,32 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
16631663 const iterator = stream [ Symbol . asyncIterator ] ( )
16641664 let item = await iterator . next ( )
16651665 while ( ! item . done ) {
1666+ // Check for abort BEFORE processing the chunk and waiting for the next one
1667+ if ( this . abort ) {
1668+ console . log ( `aborting stream, this.abandoned = ${ this . abandoned } ` )
1669+
1670+ if ( ! this . abandoned ) {
1671+ // Only need to gracefully abort if this instance
1672+ // isn't abandoned (sometimes OpenRouter stream
1673+ // hangs, in which case this would affect future
1674+ // instances of Cline).
1675+ await abortStream ( "user_cancelled" )
1676+ }
1677+
1678+ // Clean up the iterator if it has a return method
1679+ if ( iterator . return ) {
1680+ await iterator . return ( undefined )
1681+ }
1682+
1683+ break // Aborts the stream.
1684+ }
1685+
16661686 const chunk = item . value
1667- item = await iterator . next ( )
1687+
16681688 if ( ! chunk ) {
16691689 // Sometimes chunk is undefined, no idea that can cause
16701690 // it, but this workaround seems to fix it.
1691+ item = await iterator . next ( )
16711692 continue
16721693 }
16731694
@@ -1707,20 +1728,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
17071728 }
17081729 }
17091730
1710- if ( this . abort ) {
1711- console . log ( `aborting stream, this.abandoned = ${ this . abandoned } ` )
1712-
1713- if ( ! this . abandoned ) {
1714- // Only need to gracefully abort if this instance
1715- // isn't abandoned (sometimes OpenRouter stream
1716- // hangs, in which case this would affect future
1717- // instances of Cline).
1718- await abortStream ( "user_cancelled" )
1719- }
1720-
1721- break // Aborts the stream.
1722- }
1723-
17241731 if ( this . didRejectTool ) {
17251732 // `userContent` has a tool rejection, so interrupt the
17261733 // assistant's response to present the user's feedback.
@@ -1737,6 +1744,9 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
17371744 "\n\n[Response interrupted by a tool use result. Only one tool may be used at a time and should be placed at the end of the message.]"
17381745 break
17391746 }
1747+
1748+ // Get next item at the end, after all checks
1749+ item = await iterator . next ( )
17401750 }
17411751
17421752 // Create a copy of current token values to avoid race conditions
@@ -1815,6 +1825,16 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
18151825
18161826 // Use the same iterator that the main loop was using
18171827 while ( ! item . done ) {
1828+ // Check for abort first
1829+ if ( this . abort ) {
1830+ console . log ( `[Background Usage Collection] Aborting due to task cancellation` )
1831+ // Clean up the iterator before breaking
1832+ if ( iterator . return ) {
1833+ await iterator . return ( undefined )
1834+ }
1835+ break
1836+ }
1837+
18181838 // Check for timeout
18191839 if ( Date . now ( ) - startTime > timeoutMs ) {
18201840 console . warn (
0 commit comments