@@ -20,8 +20,14 @@ import {
2020 normalizeReasoningEffortSetting ,
2121 resolveReasoningEffort ,
2222} from "./llmproviders/shared/reasoning" ;
23+ import {
24+ isAbortError ,
25+ normalizeAbortError ,
26+ throwIfAborted ,
27+ } from "./llmproviders/shared/requestAbort" ;
2328import type {
2429 ConversationMessage ,
30+ LLMAbortSignal ,
2531 LLMOptions ,
2632 LLMModelInfo ,
2733 LLMProviderCapabilities ,
@@ -103,6 +109,7 @@ export type LLMTransportOptions = {
103109 timeoutMs ?: number ;
104110 retry ?: boolean ;
105111 keyRotation ?: boolean ;
112+ abortSignal ?: LLMAbortSignal ;
106113} ;
107114
108115export type LLMGenerateRequest = {
@@ -266,6 +273,7 @@ export class LLMService {
266273 const common : LLMOptions = {
267274 stream : transport ?. stream ?? getPref ( "stream" ) ?? true ,
268275 requestTimeoutMs : transport ?. timeoutMs ?? this . getRequestTimeout ( ) ,
276+ abortSignal : transport ?. abortSignal ,
269277 } ;
270278
271279 if ( enableTemperature ) {
@@ -496,6 +504,7 @@ export class LLMService {
496504 let lastError : Error | null = null ;
497505
498506 for ( let attempt = 0 ; attempt < maxRetries ; attempt ++ ) {
507+ throwIfAborted ( request . transport ?. abortSignal ) ;
499508 const endpoint = route . endpoints [ attempt % route . endpoints . length ] ;
500509 try {
501510 const response = await this . generateOnceWithEndpoint (
@@ -506,6 +515,9 @@ export class LLMService {
506515 LLMEndpointManager . markEndpointAttempted ( endpoint . id ) ;
507516 return response ;
508517 } catch ( error : unknown ) {
518+ if ( isAbortError ( error , request . transport ?. abortSignal ) ) {
519+ throw normalizeAbortError ( error , request . transport ?. abortSignal ) ;
520+ }
509521 LLMEndpointManager . markEndpointAttempted ( endpoint . id ) ;
510522 lastError = error instanceof Error ? error : new Error ( String ( error ) ) ;
511523 ztoolkit . log (
@@ -524,12 +536,14 @@ export class LLMService {
524536 ) : Promise < LLMResponse > {
525537 const provider = this . getProviderForEndpoint ( endpoint ) ;
526538 const warnings : string [ ] = [ ] ;
539+ throwIfAborted ( request . transport ?. abortSignal ) ;
527540 const resolved = await this . resolveContent (
528541 provider ,
529542 request . content ,
530543 warnings ,
531544 true ,
532545 ) ;
546+ throwIfAborted ( request . transport ?. abortSignal ) ;
533547 const options = this . buildOptions (
534548 endpoint ,
535549 request . generation ,
@@ -550,6 +564,9 @@ export class LLMService {
550564 request . onProgress ,
551565 ) ;
552566 } catch ( error : unknown ) {
567+ if ( isAbortError ( error , options . abortSignal ) ) {
568+ throw normalizeAbortError ( error , options . abortSignal ) ;
569+ }
553570 throw this . toApiCallError ( endpoint , error ) ;
554571 }
555572 } else {
@@ -562,6 +579,9 @@ export class LLMService {
562579 request . onProgress ,
563580 ) ;
564581 } catch ( error : unknown ) {
582+ if ( isAbortError ( error , options . abortSignal ) ) {
583+ throw normalizeAbortError ( error , options . abortSignal ) ;
584+ }
565585 throw this . toApiCallError ( endpoint , error ) ;
566586 }
567587 }
@@ -584,9 +604,13 @@ export class LLMService {
584604 let lastError : Error | null = null ;
585605
586606 for ( let attempt = 0 ; attempt < maxAttempts ; attempt ++ ) {
607+ throwIfAborted ( request . transport ?. abortSignal ) ;
587608 try {
588609 return await this . generateOnceWithEndpoint ( endpoint , request , prompt ) ;
589610 } catch ( error : unknown ) {
611+ if ( isAbortError ( error , request . transport ?. abortSignal ) ) {
612+ throw normalizeAbortError ( error , request . transport ?. abortSignal ) ;
613+ }
590614 lastError = error instanceof Error ? error : new Error ( String ( error ) ) ;
591615 ztoolkit . log (
592616 `[LLMService] API failed via ${ endpoint . name } (${ attempt + 1 } /${ maxAttempts } ): ${ lastError . message } ` ,
@@ -606,12 +630,16 @@ export class LLMService {
606630 let lastError : Error | null = null ;
607631
608632 for ( let attempt = 0 ; attempt < maxRetries ; attempt ++ ) {
633+ throwIfAborted ( request . transport ?. abortSignal ) ;
609634 const endpoint = route . endpoints [ attempt % route . endpoints . length ] ;
610635 try {
611636 const response = await this . chatOnceWithEndpoint ( endpoint , request ) ;
612637 LLMEndpointManager . markEndpointAttempted ( endpoint . id ) ;
613638 return response ;
614639 } catch ( error : unknown ) {
640+ if ( isAbortError ( error , request . transport ?. abortSignal ) ) {
641+ throw normalizeAbortError ( error , request . transport ?. abortSignal ) ;
642+ }
615643 LLMEndpointManager . markEndpointAttempted ( endpoint . id ) ;
616644 lastError = error instanceof Error ? error : new Error ( String ( error ) ) ;
617645 ztoolkit . log (
@@ -629,12 +657,14 @@ export class LLMService {
629657 ) : Promise < LLMResponse > {
630658 const provider = this . getProviderForEndpoint ( endpoint ) ;
631659 const warnings : string [ ] = [ ] ;
660+ throwIfAborted ( request . transport ?. abortSignal ) ;
632661 const resolved = await this . resolveContent (
633662 provider ,
634663 request . content ,
635664 warnings ,
636665 false ,
637666 ) ;
667+ throwIfAborted ( request . transport ?. abortSignal ) ;
638668 if ( resolved . mode !== "single" ) {
639669 throw new Error ( "Chat requests do not support multi-file input." ) ;
640670 }
@@ -653,6 +683,9 @@ export class LLMService {
653683 request . onProgress ,
654684 ) ;
655685 } catch ( error : unknown ) {
686+ if ( isAbortError ( error , options . abortSignal ) ) {
687+ throw normalizeAbortError ( error , options . abortSignal ) ;
688+ }
656689 throw this . toApiCallError ( endpoint , error ) ;
657690 }
658691 return this . toResponse (
@@ -673,9 +706,13 @@ export class LLMService {
673706 let lastError : Error | null = null ;
674707
675708 for ( let attempt = 0 ; attempt < maxAttempts ; attempt ++ ) {
709+ throwIfAborted ( request . transport ?. abortSignal ) ;
676710 try {
677711 return await this . chatOnceWithEndpoint ( endpoint , request ) ;
678712 } catch ( error : unknown ) {
713+ if ( isAbortError ( error , request . transport ?. abortSignal ) ) {
714+ throw normalizeAbortError ( error , request . transport ?. abortSignal ) ;
715+ }
679716 lastError = error instanceof Error ? error : new Error ( String ( error ) ) ;
680717 ztoolkit . log (
681718 `[LLMService] Chat API failed via ${ endpoint . name } (${ attempt + 1 } /${ maxAttempts } ): ${ lastError . message } ` ,
@@ -711,6 +748,7 @@ export class LLMService {
711748 let lastError : Error | null = null ;
712749
713750 for ( let attempt = 0 ; attempt < maxRetries ; attempt ++ ) {
751+ throwIfAborted ( request . transport ?. abortSignal ) ;
714752 try {
715753 const options = this . buildOptions (
716754 providerId ,
@@ -740,6 +778,9 @@ export class LLMService {
740778 if ( useKeyRotation ) ApiKeyManager . advanceToNextKey ( keyManagerId ) ;
741779 return this . toResponse ( text , providerId , options , warnings ) ;
742780 } catch ( error : unknown ) {
781+ if ( isAbortError ( error , request . transport ?. abortSignal ) ) {
782+ throw normalizeAbortError ( error , request . transport ?. abortSignal ) ;
783+ }
743784 lastError = error instanceof Error ? error : new Error ( String ( error ) ) ;
744785 ztoolkit . log (
745786 `[LLMService] API 调用失败 (尝试 ${ attempt + 1 } /${ maxRetries } ): ${ lastError . message } ` ,
0 commit comments