@@ -104,15 +104,17 @@ export class ClaudeSDKAgent extends BaseAgent {
104104 /**
105105 * Wrapper around iterator.next() that yields heartbeat events while waiting
106106 * @param iterator - The async iterator
107- * @yields Heartbeat events (FormattedEvent) and the final iterator result (IteratorResult)
107+ * @yields Heartbeat events (FormattedEvent) while waiting, then the final iterator result (IteratorResult)
108108 */
109109 private async * nextWithHeartbeat ( iterator : AsyncIterator < any > ) : AsyncGenerator < any > {
110110 const heartbeatInterval = 20000 // 20 seconds
111111 let heartbeatTimer : NodeJS . Timeout | null = null
112112 let abortHandler : ( ( ) => void ) | null = null
113- let iteratorPromise = iterator . next ( )
114113
115- // Create abort promise ONCE outside loop to avoid accumulating event listeners
114+ // Call iterator.next() once - this generator wraps a single next() call
115+ const iteratorPromise = iterator . next ( )
116+
117+ // Create abort promise
116118 const abortPromise = new Promise < never > ( ( _ , reject ) => {
117119 if ( this . abortController ) {
118120 abortHandler = ( ) => {
@@ -123,19 +125,22 @@ export class ClaudeSDKAgent extends BaseAgent {
123125 } )
124126
125127 try {
128+ // Loop until the iterator promise resolves, yielding heartbeats while waiting
126129 while ( true ) {
127130 // Check if execution was aborted
128131 if ( this . abortController ?. signal . aborted ) {
129132 logger . info ( '⚠️ Agent execution aborted during heartbeat wait' )
130133 return
131134 }
132135
136+ // Create timeout promise for this iteration
133137 const timeoutPromise = new Promise ( resolve => {
134138 heartbeatTimer = setTimeout ( ( ) => resolve ( { type : 'heartbeat' } ) , heartbeatInterval )
135139 } )
136140
137141 type RaceResult = { type : 'result' ; result : any } | { type : 'heartbeat' }
138142 let race : RaceResult
143+
139144 try {
140145 race = await Promise . race ( [
141146 iteratorPromise . then ( result => ( { type : 'result' as const , result } ) ) ,
@@ -152,15 +157,18 @@ export class ClaudeSDKAgent extends BaseAgent {
152157 return
153158 }
154159
160+ // Clear the timeout if it was set
155161 if ( heartbeatTimer ) {
156162 clearTimeout ( heartbeatTimer )
157163 heartbeatTimer = null
158164 }
159165
160166 if ( race . type === 'heartbeat' ) {
167+ // Heartbeat timeout occurred - yield processing event and continue waiting
161168 yield EventFormatter . createProcessingEvent ( )
169+ // Loop continues - will race the same iteratorPromise (still pending) vs new timeout
162170 } else {
163- // Yield the iterator result (not return!) so the consumer receives it
171+ // Iterator result arrived - yield it and exit this generator
164172 yield race . result
165173 return
166174 }
0 commit comments