@@ -432,96 +432,74 @@ export function stripThinking(text: string): string {
432432 * Robustly extract text from various AI response formats.
433433 */
434434export function extractText ( obj : ExtractInput , includeReasoning = false ) : string {
435- if ( typeof obj === 'string' ) {
436- return obj ;
437- }
438- if ( typeof obj !== 'object' || obj === null ) {
439- return '' ;
440- }
435+ if ( typeof obj === 'string' ) return obj ;
436+ if ( ! obj || typeof obj !== 'object' ) return '' ;
441437
442- const response = obj as Record < string , unknown > ;
438+ const response = obj as any ;
443439
444- if ( typeof response . response === 'string' ) return response . response ;
445- if ( typeof response . text === 'string' ) return response . text ;
446- if ( typeof response . content === 'string' ) return response . content ;
440+ // Prioritize direct fields
441+ if ( response . response && typeof response . response === 'string' ) return response . response ;
442+ if ( response . text && typeof response . text === 'string' ) return response . text ;
443+ if ( response . content && typeof response . content === 'string' ) return response . content ;
447444
448445 // Handle delta objects (OpenAI-style streaming)
449- if ( typeof response . delta === 'object' && response . delta !== null ) {
450- const delta = response . delta as any ;
451- if ( typeof delta . content === 'string' ) return delta . content ;
446+ if ( response . delta && typeof response . delta === 'object' ) {
447+ if ( response . delta . content && typeof response . delta . content === 'string' ) return response . delta . content ;
452448 if ( includeReasoning ) {
453- if ( typeof delta . reasoning_content === 'string' ) return delta . reasoning_content ;
454- if ( typeof delta . thought === 'string' ) return delta . thought ;
449+ if ( response . delta . reasoning_content && typeof response . delta . reasoning_content === 'string' ) return response . delta . reasoning_content ;
450+ if ( response . delta . thought && typeof response . delta . thought === 'string' ) return response . delta . thought ;
455451 }
456- // Skip reasoning_content and thought in the final extraction to prevent leaks
457- if ( typeof delta . text === 'string' ) return delta . text ;
452+ if ( response . delta . text && typeof response . delta . text === 'string' ) return response . delta . text ;
458453 }
459- if ( typeof response . delta === 'string' ) return response . delta ;
460-
461- // Recursively search in common nested fields
462- if ( Array . isArray ( response . choices ) && response . choices . length > 0 )
463- return extractText ( response . choices [ 0 ] as ExtractInput , includeReasoning ) ;
464- if ( response . message ) return extractText ( response . message as ExtractInput , includeReasoning ) ;
465- if ( response . delta ) return extractText ( response . delta as ExtractInput , includeReasoning ) ;
466- if ( response . tool_calls ) return '' ; // Skip tool calls in extraction
467- if ( Array . isArray ( response . candidates ) && response . candidates . length > 0 )
468- return extractText ( response . candidates [ 0 ] as ExtractInput , includeReasoning ) ;
469- if ( response . content ) return extractText ( response . content as ExtractInput , includeReasoning ) ;
454+ if ( response . delta && typeof response . delta === 'string' ) return response . delta ;
455+
456+ // Nested fields
457+ if ( response . choices ?. [ 0 ] ) {
458+ const choice = response . choices [ 0 ] ;
459+ if ( choice . delta ) return extractText ( choice . delta , includeReasoning ) ;
460+ if ( choice . message ) return extractText ( choice . message , includeReasoning ) ;
461+ if ( choice . text && typeof choice . text === 'string' ) return choice . text ;
462+ }
463+
464+ if ( response . candidates ?. [ 0 ] ) return extractText ( response . candidates [ 0 ] . content , includeReasoning ) ;
470465
471466 // Gemini parts
472- if ( Array . isArray ( response . parts ) && response . parts . length > 0 ) {
467+ if ( Array . isArray ( response . parts ) ) {
473468 let text = '' ;
474- for ( const part of response . parts as GeminiPart [ ] ) {
475- if ( ! includeReasoning && part . thought ) continue ; // Gemini thinking parts
469+ for ( const part of response . parts ) {
470+ if ( ! includeReasoning && part . thought ) continue ;
476471 if ( part . text ) text += part . text ;
477472 }
478473 return text ;
479474 }
480475
481- // Any other string field as a fallback, but excluding known meta/thinking fields
482- for ( const key of Object . keys ( response ) ) {
483- if ( [ 'id' , 'model' , 'object' , 'created' , 'usage' , 'index' , 'finish_reason' , 'reasoning_content' , 'thought' ] . includes ( key ) ) continue ;
484- if ( typeof response [ key ] === 'string' && response [ key ] ) return response [ key ] as string ;
485- }
486-
487476 return '' ;
488477}
489478
490479export function extractThinking ( obj : ExtractInput ) : string {
491- if ( typeof obj !== 'object' || obj === null ) return '' ;
492- const response = obj as Record < string , unknown > ;
480+ if ( ! obj || typeof obj !== 'object' ) return '' ;
481+ const response = obj as any ;
493482
494- if ( typeof response . delta === 'object' && response . delta !== null ) {
495- const delta = response . delta as any ;
496- if ( typeof delta . thought === 'string' ) return delta . thought ;
497- }
483+ if ( response . delta ?. thought && typeof response . delta . thought === 'string' ) return response . delta . thought ;
498484
499- if ( Array . isArray ( response . choices ) && response . choices . length > 0 ) {
500- const choice = response . choices [ 0 ] as any ;
501- if ( choice . delta && typeof choice . delta . thought === 'string' ) return choice . delta . thought ;
502- if ( choice . message && typeof choice . message . thought === 'string' ) return choice . message . thought ;
503- return extractThinking ( choice as ExtractInput ) ;
485+ if ( response . choices ?. [ 0 ] ) {
486+ const choice = response . choices [ 0 ] ;
487+ if ( choice . delta ?. thought ) return choice . delta . thought ;
488+ if ( choice . message ?. thought ) return choice . message . thought ;
489+ return extractThinking ( choice ) ;
504490 }
505- if ( response . message ) {
506- if ( typeof ( response . message as any ) . thought === 'string' ) return ( response . message as any ) . thought ;
507- return extractThinking ( response . message as ExtractInput ) ;
508- }
509- if ( response . delta ) return extractThinking ( response . delta as ExtractInput ) ;
510-
511- if ( Array . isArray ( response . candidates ) && response . candidates . length > 0 ) {
512- const candidate = response . candidates [ 0 ] as any ;
513- if ( candidate . content && Array . isArray ( candidate . content . parts ) ) {
514- let thinking = '' ;
515- for ( const part of candidate . content . parts as GeminiPart [ ] ) {
516- if ( part . thought && part . text ) thinking += part . text ;
517- }
518- return thinking ;
491+
492+ if ( response . candidates ?. [ 0 ] ?. content ?. parts ) {
493+ let thinking = '' ;
494+ for ( const part of response . candidates [ 0 ] . content . parts ) {
495+ if ( part . thought && part . text ) thinking += part . text ;
519496 }
497+ return thinking ;
520498 }
521499
522500 if ( Array . isArray ( response . parts ) ) {
523501 let thinking = '' ;
524- for ( const part of response . parts as GeminiPart [ ] ) {
502+ for ( const part of response . parts ) {
525503 if ( part . thought && part . text ) thinking += part . text ;
526504 }
527505 return thinking ;
@@ -531,25 +509,17 @@ export function extractThinking(obj: ExtractInput): string {
531509}
532510
533511export function extractReasoning ( obj : ExtractInput ) : string {
534- if ( typeof obj !== 'object' || obj === null ) return '' ;
535- const response = obj as Record < string , unknown > ;
512+ if ( ! obj || typeof obj !== 'object' ) return '' ;
513+ const response = obj as any ;
536514
537- if ( typeof response . delta === 'object' && response . delta !== null ) {
538- const delta = response . delta as any ;
539- if ( typeof delta . reasoning_content === 'string' ) return delta . reasoning_content ;
540- }
515+ if ( response . delta ?. reasoning_content && typeof response . delta . reasoning_content === 'string' ) return response . delta . reasoning_content ;
541516
542- if ( Array . isArray ( response . choices ) && response . choices . length > 0 ) {
543- const choice = response . choices [ 0 ] as any ;
544- if ( choice . delta && typeof choice . delta . reasoning_content === 'string' ) return choice . delta . reasoning_content ;
545- if ( choice . message && typeof choice . message . reasoning_content === 'string' ) return choice . message . reasoning_content ;
546- return extractReasoning ( choice as ExtractInput ) ;
547- }
548- if ( response . message ) {
549- if ( typeof ( response . message as any ) . reasoning_content === 'string' ) return ( response . message as any ) . reasoning_content ;
550- return extractReasoning ( response . message as ExtractInput ) ;
517+ if ( response . choices ?. [ 0 ] ) {
518+ const choice = response . choices [ 0 ] ;
519+ if ( choice . delta ?. reasoning_content ) return choice . delta . reasoning_content ;
520+ if ( choice . message ?. reasoning_content ) return choice . message . reasoning_content ;
521+ return extractReasoning ( choice ) ;
551522 }
552- if ( response . delta ) return extractReasoning ( response . delta as ExtractInput ) ;
553523
554524 return '' ;
555525}
0 commit comments