@@ -7,6 +7,37 @@ import { isEmpty } from 'lodash-es'
77import { getCompletionPromptBase , pushRecord , setAbortController } from './shared.mjs'
88import { getModelValue , isUsingReasoningModel } from '../../utils/model-name-convert.mjs'
99
10+ /**
11+ * Extract content from structured response arrays for reasoning models
12+ * @param {Array } contentArray - Array of content segments
13+ * @returns {string } - Extracted text content
14+ */
15+ function extractContentFromArray ( contentArray ) {
16+ if ( ! Array . isArray ( contentArray ) ) {
17+ console . debug ( 'Content is not an array, returning empty string' )
18+ return ''
19+ }
20+
21+ try {
22+ const parts = contentArray
23+ . map ( ( part ) => {
24+ if ( typeof part === 'string' ) return part
25+ if ( part && typeof part === 'object' ) {
26+ // Prefer output_text segments; fallback to text property
27+ if ( typeof part . output_text === 'string' ) return part . output_text
28+ if ( typeof part . text === 'string' ) return part . text
29+ }
30+ return ''
31+ } )
32+ . filter ( Boolean )
33+
34+ return parts . join ( '' )
35+ } catch ( error ) {
36+ console . debug ( 'Error extracting content from array:' , error )
37+ return ''
38+ }
39+ }
40+
1041/**
1142 * @param {Browser.Runtime.Port } port
1243 * @param {string } question
@@ -177,12 +208,17 @@ export async function generateAnswersWithChatgptApiCompat(
177208 requestBody . temperature = config . temperature
178209 }
179210
211+ // Validate API key
212+ if ( ! apiKey || typeof apiKey !== 'string' || ! apiKey . trim ( ) ) {
213+ throw new Error ( 'Invalid API key provided' )
214+ }
215+
180216 await fetchSSE ( `${ baseUrl } /chat/completions` , {
181217 method : 'POST' ,
182218 signal : controller . signal ,
183219 headers : {
184220 'Content-Type' : 'application/json' ,
185- Authorization : `Bearer ${ apiKey } ` ,
221+ Authorization : `Bearer ${ apiKey . trim ( ) } ` ,
186222 } ,
187223 body : JSON . stringify ( requestBody ) ,
188224 onMessage ( message ) {
@@ -207,26 +243,25 @@ export async function generateAnswersWithChatgptApiCompat(
207243 console . debug ( 'No choice in response data for reasoning model' )
208244 return
209245 }
246+
210247 let content = choice . message ?. content ?? choice . text
248+
249+ // Handle structured response arrays for reasoning models
211250 if ( Array . isArray ( content ) ) {
212- // Prefer output_text segments; fallback to any string content
213- const parts = content
214- . map ( ( p ) => {
215- if ( typeof p === 'string' ) return p
216- if ( p && typeof p === 'object' ) {
217- if ( typeof p . output_text === 'string' ) return p . output_text
218- if ( typeof p . text === 'string' ) return p . text
219- }
220- return ''
221- } )
222- . filter ( Boolean )
223- content = parts . join ( '' )
251+ content = extractContentFromArray ( content )
224252 }
225- if ( content !== undefined && content !== null ) {
226- answer = String ( content )
227- port . postMessage ( { answer, done : false , session : null } )
253+
254+ // Ensure content is a string and not empty
255+ if ( content && typeof content === 'string' ) {
256+ const trimmedContent = content . trim ( )
257+ if ( trimmedContent ) {
258+ answer = trimmedContent
259+ port . postMessage ( { answer, done : false , session : null } )
260+ }
228261 }
229- if ( choice . finish_reason || content !== undefined ) {
262+
263+ // Only finish when we have a proper finish reason
264+ if ( choice . finish_reason ) {
230265 finish ( )
231266 }
232267 } else {
0 commit comments