@@ -24,7 +24,7 @@ export class ApiClient {
2424 return { ok : res . ok , status : res . status , timeMs } ;
2525 }
2626
27- async callModel ( { model, baseURL, apiKey, endpointType, temperature= 0 , maxTokens= 300 , extraHeaders, timeoutMs= 60000 , apiVersion, reasoningEffort } , imageBlob , prompt , onLogSanitized , imageW , imageH , systemPromptTemplate ) {
27+ async callModel ( { model, baseURL, apiKey, endpointType, temperature= 0 , maxTokens= 2048 , extraHeaders, timeoutMs= 60000 , apiVersion, reasoningEffort } , imageBlob , prompt , onLogSanitized , imageW , imageH , systemPromptTemplate ) {
2828 const url = this . _endpointUrl ( { baseURL, endpointType, apiVersion } ) ;
2929 const headers = this . _headers ( { apiKey, extraHeaders, baseURL } ) ;
3030 const b64 = await blobToDataURL ( imageBlob ) ;
@@ -140,6 +140,29 @@ export class ApiClient {
140140 }
141141 clearTimeout ( to2 ) ;
142142 }
143+ // Auto-retry for Chat when finish_reason === 'length'
144+ if ( endpointType !== 'responses' && j && Array . isArray ( j . choices ) && j . choices [ 0 ] ?. finish_reason === 'length' ) {
145+ const increased = Math . min ( Math . max ( Number ( maxTokens ) || 300 , 300 ) * 2 , 4096 ) ;
146+ const retryBody = {
147+ ...body ,
148+ max_tokens : increased
149+ } ;
150+ const controller2 = new AbortController ( ) ;
151+ const to2 = setTimeout ( ( ) => controller2 . abort ( 'timeout' ) , timeoutMs ) ;
152+ const res2 = await fetch ( url , { method : 'POST' , headers, body : JSON . stringify ( retryBody ) , signal : controller2 . signal } ) ;
153+ status = res2 . status ;
154+ const contentType2 = res2 . headers . get ( 'content-type' ) || '' ;
155+ if ( contentType2 . includes ( 'application/json' ) ) {
156+ const j2 = await res2 . json ( ) ;
157+ j = j2 ;
158+ rawText = this . _extractTextFromResponse ( j2 , endpointType ) ;
159+ rawFull = JSON . stringify ( j2 ) ;
160+ } else {
161+ rawText = await res2 . text ( ) ;
162+ rawFull = undefined ;
163+ }
164+ clearTimeout ( to2 ) ;
165+ }
143166 const latency = Math . round ( performance . now ( ) - t0 ) ;
144167 const sanitizedReq = {
145168 url,
@@ -248,6 +271,9 @@ export class ApiClient {
248271 const first = t . find ( x => x . type && ( x . type . includes ( 'text' ) || x . type === 'output_text' ) ) ;
249272 if ( first && first . text ) return first . text ;
250273 }
274+ // Some providers return choices[0].text
275+ const t2 = j ?. choices ?. [ 0 ] ?. text ;
276+ if ( typeof t2 === 'string' ) return t2 ;
251277 }
252278 // Fallback
253279 return JSON . stringify ( j ) ;
0 commit comments