@@ -101,6 +101,38 @@ export class Core {
101
101
this . messageAbortControllers . get ( messageId ) ?. abort ( ) ;
102
102
}
103
103
104
+
105
+ /**
106
+ * Wraps async task execution with automatic AbortController cleanup.
107
+ */
108
+ private runWithAbortController < T extends Promise < any > | AsyncGenerator < any > > (
109
+ id : string ,
110
+ task : ( controller : AbortController ) => T
111
+ ) : T {
112
+ const controller = this . addMessageAbortController ( id ) ;
113
+ const cleanup = ( ) => this . abortById ( id ) ;
114
+
115
+ try {
116
+ const result = task ( controller ) ;
117
+
118
+ if ( result instanceof Promise ) {
119
+ return result . finally ( cleanup ) as T ;
120
+ }
121
+
122
+ // AsyncGenerator handling (intentionally skipping return/throw as caller only consumes via next())
123
+ return ( async function * ( ) {
124
+ try {
125
+ yield * result ;
126
+ } finally {
127
+ cleanup ( ) ;
128
+ }
129
+ } ) ( ) as T ;
130
+ } catch ( error ) {
131
+ cleanup ( ) ;
132
+ throw error ;
133
+ }
134
+ }
135
+
104
136
invoke < T extends keyof ToCoreProtocol > (
105
137
messageType : T ,
106
138
data : ToCoreProtocol [ T ] [ 0 ] ,
@@ -430,13 +462,14 @@ export class Core {
430
462
} ) ;
431
463
432
464
on ( "llm/streamChat" , ( msg ) => {
433
- const abortController = this . addMessageAbortController ( msg . messageId ) ;
434
- return llmStreamChat (
435
- this . configHandler ,
436
- abortController ,
437
- msg ,
438
- this . ide ,
439
- this . messenger ,
465
+ return this . runWithAbortController ( msg . messageId , ( abortController ) =>
466
+ llmStreamChat (
467
+ this . configHandler ,
468
+ abortController ,
469
+ msg ,
470
+ this . ide ,
471
+ this . messenger ,
472
+ ) ,
440
473
) ;
441
474
} ) ;
442
475
@@ -446,12 +479,15 @@ export class Core {
446
479
if ( ! model ) {
447
480
throw new Error ( "No chat model selected" ) ;
448
481
}
449
- const abortController = this . addMessageAbortController ( msg . messageId ) ;
450
482
451
- const completion = await model . complete (
452
- msg . data . prompt ,
453
- abortController . signal ,
454
- msg . data . completionOptions ,
483
+ const completion = await this . runWithAbortController (
484
+ msg . messageId ,
485
+ ( abortController ) =>
486
+ model . complete (
487
+ msg . data . prompt ,
488
+ abortController . signal ,
489
+ msg . data . completionOptions ,
490
+ ) ,
455
491
) ;
456
492
return completion ;
457
493
} ) ;
0 commit comments