11import { PanelProvider } from '@/views/panel/backend/panel-provider'
22import { make_api_request } from '@/utils/make-api-request'
33import axios , { CancelTokenSource } from 'axios'
4- import { randomUUID } from 'crypto'
4+ import { randomUUID , createHash } from 'crypto'
55import { Logger } from '@shared/utils/logger'
66
77export class ApiManager {
88 private cancel_token_sources : Map < string , CancelTokenSource > = new Map ( )
99 private next_allowed_finish_time = 0
1010 // Waiting pipeline to utilize KV cache for the same endpoint urls
11- private waiting_chain : Map < string , Promise < void > > = new Map ( )
11+ private waiting_chain : Map <
12+ string ,
13+ { promise : Promise < void > ; resolve : ( ) => void ; body_hash : string }
14+ > = new Map ( )
1215
1316 constructor ( private panel_provider : PanelProvider ) { }
1417
@@ -22,12 +25,23 @@ export class ApiManager {
2225 const cancel_token_source = axios . CancelToken . source ( )
2326 this . cancel_token_sources . set ( request_id , cancel_token_source )
2427
25- const previous_waiting_promise = this . waiting_chain . get ( params . endpoint_url )
26- let resolve_waiting : ( ) => void = ( ) => { }
27- const waiting_promise = new Promise < void > ( ( resolve ) => {
28- resolve_waiting = resolve
28+ const body_hash = createHash ( 'md5' )
29+ . update ( JSON . stringify ( params . body ) )
30+ . digest ( 'hex' )
31+ const previous_waiting = this . waiting_chain . get ( params . endpoint_url )
32+
33+ let resolve_current : ( ) => void = ( ) => { }
34+ const current_promise = new Promise < void > ( ( resolve ) => {
35+ resolve_current = resolve
2936 } )
30- this . waiting_chain . set ( params . endpoint_url , waiting_promise )
37+
38+ if ( ! previous_waiting || previous_waiting . body_hash !== body_hash ) {
39+ this . waiting_chain . set ( params . endpoint_url , {
40+ promise : current_promise ,
41+ resolve : resolve_current ,
42+ body_hash
43+ } )
44+ }
3145
3246 try {
3347 this . panel_provider . send_message ( {
@@ -36,8 +50,8 @@ export class ApiManager {
3650 title : 'Waiting...'
3751 } )
3852
39- if ( previous_waiting_promise ) {
40- await previous_waiting_promise
53+ if ( previous_waiting && previous_waiting . body_hash === body_hash ) {
54+ await previous_waiting . promise
4155 }
4256
4357 const result = await make_api_request ( {
@@ -46,15 +60,23 @@ export class ApiManager {
4660 body : params . body ,
4761 cancellation_token : cancel_token_source . token ,
4862 on_thinking_chunk : ( ) => {
49- resolve_waiting ( )
63+ const chain_entry = this . waiting_chain . get ( params . endpoint_url )
64+ if ( chain_entry && chain_entry . resolve === resolve_current ) {
65+ chain_entry . resolve ( )
66+ this . waiting_chain . delete ( params . endpoint_url )
67+ }
5068 this . panel_provider . send_message ( {
5169 command : 'SHOW_API_MANAGER_PROGRESS' ,
5270 id : request_id ,
5371 title : 'Thinking...'
5472 } )
5573 } ,
5674 on_chunk : ( tokens_per_second , total_tokens ) => {
57- resolve_waiting ( )
75+ const chain_entry = this . waiting_chain . get ( params . endpoint_url )
76+ if ( chain_entry && chain_entry . resolve === resolve_current ) {
77+ chain_entry . resolve ( )
78+ this . waiting_chain . delete ( params . endpoint_url )
79+ }
5880 this . panel_provider . send_message ( {
5981 command : 'SHOW_API_MANAGER_PROGRESS' ,
6082 id : request_id ,
@@ -81,7 +103,13 @@ export class ApiManager {
81103 } )
82104 return null
83105 } finally {
84- resolve_waiting ( )
106+ // Unblock anyone waiting for this request if it was the one in the chain
107+ const chain_entry = this . waiting_chain . get ( params . endpoint_url )
108+ if ( chain_entry && chain_entry . resolve === resolve_current ) {
109+ chain_entry . resolve ( )
110+ this . waiting_chain . delete ( params . endpoint_url )
111+ }
112+
85113 this . panel_provider . send_message ( {
86114 command : 'HIDE_API_MANAGER_PROGRESS' ,
87115 id : request_id
0 commit comments