@@ -51,6 +51,8 @@ export class ChatService {
5151 onChunk,
5252 onComplete,
5353 onError,
54+ onReasoningChunk,
55+ onModel,
5456 // Generation parameters
5557 temperature,
5658 max_tokens,
@@ -196,10 +198,11 @@ export class ChatService {
196198 onChunk ,
197199 onComplete ,
198200 onError ,
199- options . onReasoningChunk
201+ onReasoningChunk ,
202+ onModel
200203 ) ;
201204 } else {
202- return this . handleNonStreamResponse ( response , onComplete , onError ) ;
205+ return this . handleNonStreamResponse ( response , onComplete , onError , onModel ) ;
203206 }
204207 } catch ( error ) {
205208 if ( error instanceof Error && error . name === 'AbortError' ) {
@@ -257,7 +260,8 @@ export class ChatService {
257260 timings ?: ChatMessageTimings
258261 ) => void ,
259262 onError ?: ( error : Error ) => void ,
260- onReasoningChunk ?: ( chunk : string ) => void
263+ onReasoningChunk ?: ( chunk : string ) => void ,
264+ onModel ?: ( model : string ) => void
261265 ) : Promise < void > {
262266 const reader = response . body ?. getReader ( ) ;
263267
@@ -271,6 +275,7 @@ export class ChatService {
271275 let hasReceivedData = false ;
272276 let lastTimings : ChatMessageTimings | undefined ;
273277 let streamFinished = false ;
278+ let modelEmitted = false ;
274279
275280 try {
276281 let chunk = '' ;
@@ -280,7 +285,7 @@ export class ChatService {
280285
281286 chunk += decoder . decode ( value , { stream : true } ) ;
282287 const lines = chunk . split ( '\n' ) ;
283- chunk = lines . pop ( ) || '' ; // Save incomplete line for next read
288+ chunk = lines . pop ( ) || '' ;
284289
285290 for ( const line of lines ) {
286291 if ( line . startsWith ( 'data: ' ) ) {
@@ -293,6 +298,12 @@ export class ChatService {
293298 try {
294299 const parsed : ApiChatCompletionStreamChunk = JSON . parse ( data ) ;
295300
301+ const chunkModel = this . extractModelName ( parsed ) ;
302+ if ( chunkModel && ! modelEmitted ) {
303+ modelEmitted = true ;
304+ onModel ?.( chunkModel ) ;
305+ }
306+
296307 const content = parsed . choices [ 0 ] ?. delta ?. content ;
297308 const reasoningContent = parsed . choices [ 0 ] ?. delta ?. reasoning_content ;
298309 const timings = parsed . timings ;
@@ -301,7 +312,6 @@ export class ChatService {
301312 if ( timings || promptProgress ) {
302313 this . updateProcessingState ( timings , promptProgress ) ;
303314
304- // Store the latest timing data
305315 if ( timings ) {
306316 lastTimings = timings ;
307317 }
@@ -361,7 +371,8 @@ export class ChatService {
361371 reasoningContent ?: string ,
362372 timings ?: ChatMessageTimings
363373 ) => void ,
364- onError ?: ( error : Error ) => void
374+ onError ?: ( error : Error ) => void ,
375+ onModel ?: ( model : string ) => void
365376 ) : Promise < string > {
366377 try {
367378 const responseText = await response . text ( ) ;
@@ -372,6 +383,11 @@ export class ChatService {
372383 }
373384
374385 const data : ApiChatCompletionResponse = JSON . parse ( responseText ) ;
386+ const responseModel = this . extractModelName ( data ) ;
387+ if ( responseModel ) {
388+ onModel ?.( responseModel ) ;
389+ }
390+
375391 const content = data . choices [ 0 ] ?. message ?. content || '' ;
376392 const reasoningContent = data . choices [ 0 ] ?. message ?. reasoning_content ;
377393
@@ -594,6 +610,69 @@ export class ChatService {
594610 }
595611 }
596612
613+ private extractModelName ( data : unknown ) : string | undefined {
614+ if ( ! data || typeof data !== 'object' ) {
615+ return undefined ;
616+ }
617+
618+ const record = data as Record < string , unknown > ;
619+ const normalize = ( value : unknown ) : string | undefined => {
620+ if ( typeof value !== 'string' ) {
621+ return undefined ;
622+ }
623+
624+ const trimmed = value . trim ( ) ;
625+
626+ return trimmed . length > 0 ? trimmed : undefined ;
627+ } ;
628+
629+ const rootModel = normalize ( record [ 'model' ] ) ;
630+ if ( rootModel ) {
631+ return rootModel ;
632+ }
633+
634+ const choices = record [ 'choices' ] ;
635+ if ( ! Array . isArray ( choices ) || choices . length === 0 ) {
636+ return undefined ;
637+ }
638+
639+ const firstChoice = choices [ 0 ] as Record < string , unknown > | undefined ;
640+ if ( ! firstChoice ) {
641+ return undefined ;
642+ }
643+
644+ const choiceModel = normalize ( firstChoice [ 'model' ] ) ;
645+ if ( choiceModel ) {
646+ return choiceModel ;
647+ }
648+
649+ const delta = firstChoice [ 'delta' ] as Record < string , unknown > | undefined ;
650+ if ( delta ) {
651+ const deltaModel = normalize ( delta [ 'model' ] ) ;
652+ if ( deltaModel ) {
653+ return deltaModel ;
654+ }
655+ }
656+
657+ const message = firstChoice [ 'message' ] as Record < string , unknown > | undefined ;
658+ if ( message ) {
659+ const messageModel = normalize ( message [ 'model' ] ) ;
660+ if ( messageModel ) {
661+ return messageModel ;
662+ }
663+ }
664+
665+ const metadata = firstChoice [ 'metadata' ] as Record < string , unknown > | undefined ;
666+ if ( metadata ) {
667+ const metadataModel = normalize ( metadata [ 'model' ] ) ;
668+ if ( metadataModel ) {
669+ return metadataModel ;
670+ }
671+ }
672+
673+ return undefined ;
674+ }
675+
597676 private updateProcessingState (
598677 timings ?: ChatMessageTimings ,
599678 promptProgress ?: ChatMessagePromptProgress
0 commit comments