@@ -33,7 +33,32 @@ const process_stream_chunk = (
3333 if ( ! json_string || json_string == DONE_TOKEN ) continue
3434
3535 const json_data = JSON . parse ( json_string )
36- const content = json_data . choices ?. [ 0 ] ?. delta ?. content
36+ let content = json_data . choices ?. [ 0 ] ?. delta ?. content
37+
38+ // Special handling for ChatGPT provider
39+ if ( content === undefined && json_data . type ) {
40+ if (
41+ [
42+ 'response.text.delta' ,
43+ 'response.output_text.delta' ,
44+ 'response.reasoning.delta' ,
45+ 'response.reasoning_text.delta'
46+ ] . includes ( json_data . type )
47+ ) {
48+ content = json_data . delta
49+ } else if ( json_data . type === 'response.content_part.added' ) {
50+ content =
51+ typeof json_data . part ?. text === 'string'
52+ ? json_data . part . text
53+ : json_data . part ?. text ?. value
54+ } else if (
55+ json_data . type === 'response.output_item.added' &&
56+ json_data . item ?. type === 'text'
57+ ) {
58+ content = json_data . item ?. text
59+ }
60+ }
61+
3762 if ( typeof content == 'string' ) {
3863 new_content += content
3964 }
@@ -76,12 +101,6 @@ export const make_api_request = async (params: {
76101 on_thinking_chunk ?: ThinkingStreamCallback
77102 rethrow_error ?: boolean
78103} ) : Promise < { response : string ; thoughts ?: string } | null > => {
79- Logger . info ( {
80- function_name : 'make_api_request' ,
81- message : 'API Request Body' ,
82- data : params . body
83- } )
84-
85104 let stream_start_time = 0
86105 let last_on_chunk_time = 0
87106 let total_tokens = 0
@@ -120,7 +139,79 @@ export const make_api_request = async (params: {
120139 }
121140
122141 try {
123- const request_body = { ...params . body , stream : true }
142+ const is_chatgpt = params . endpoint_url . includes ( 'chatgpt.com/backend-api' )
143+ const request_url = is_chatgpt
144+ ? params . endpoint_url + '/responses'
145+ : params . endpoint_url + '/chat/completions'
146+
147+ let request_body : any = { ...params . body , stream : true }
148+
149+ if ( is_chatgpt ) {
150+ const system_message = params . body . messages ?. find (
151+ ( m : any ) => m . role === 'system'
152+ )
153+ const other_messages =
154+ params . body . messages ?. filter ( ( m : any ) => m . role !== 'system' ) || [ ]
155+
156+ const formatted_input = other_messages . map ( ( m : any ) => {
157+ if ( m . role == 'user' ) {
158+ const content = [ ]
159+ if ( typeof m . content == 'string' ) {
160+ content . push ( { type : 'input_text' , text : m . content } )
161+ } else if ( Array . isArray ( m . content ) ) {
162+ for ( const block of m . content ) {
163+ if ( block . type == 'text' ) {
164+ content . push ( { type : 'input_text' , text : block . text } )
165+ } else if ( block . type == 'image_url' ) {
166+ content . push ( {
167+ type : 'input_image' ,
168+ image_url : block . image_url . url
169+ } )
170+ }
171+ }
172+ }
173+ return { role : 'user' , content }
174+ } else if ( m . role == 'assistant' ) {
175+ const content = [ ]
176+ if ( typeof m . content == 'string' ) {
177+ content . push ( { type : 'output_text' , text : m . content } )
178+ } else if ( Array . isArray ( m . content ) ) {
179+ for ( const block of m . content ) {
180+ if ( block . type == 'text' ) {
181+ content . push ( { type : 'output_text' , text : block . text } )
182+ }
183+ }
184+ }
185+ return { role : 'assistant' , content }
186+ }
187+ return m
188+ } )
189+
190+ request_body = {
191+ model : params . body . model ,
192+ input : formatted_input ,
193+ stream : true ,
194+ store : false
195+ }
196+ if ( system_message ) {
197+ request_body . instructions = system_message . content
198+ }
199+ if ( params . body . temperature !== undefined ) {
200+ request_body . temperature = params . body . temperature
201+ }
202+ if ( params . body . reasoning_effort ) {
203+ request_body . reasoning = {
204+ effort : params . body . reasoning_effort ,
205+ summary : 'auto'
206+ }
207+ }
208+ }
209+
210+ Logger . info ( {
211+ function_name : 'make_api_request' ,
212+ message : 'API Request Body' ,
213+ data : request_body
214+ } )
124215
125216 let buffer = ''
126217 let full_response = ''
@@ -233,22 +324,28 @@ export const make_api_request = async (params: {
233324 }
234325 }
235326
327+ const headers : Record < string , string > = {
328+ ...( params . api_key
329+ ? { [ 'Authorization' ] : `Bearer ${ params . api_key } ` }
330+ : { } ) ,
331+ [ 'Content-Type' ] : 'application/json' ,
332+ ...( params . endpoint_url == 'https://openrouter.ai/api/v1'
333+ ? {
334+ 'HTTP-Referer' : 'https://codeweb.chat/' ,
335+ 'X-Title' : 'Code Web Chat'
336+ }
337+ : { } )
338+ }
339+
340+ if ( is_chatgpt ) {
341+ headers [ 'originator' ] = 'code-web-chat'
342+ }
343+
236344 const response : AxiosResponse < NodeJS . ReadableStream > = await axios . post (
237- params . endpoint_url + '/chat/completions' ,
345+ request_url ,
238346 request_body ,
239347 {
240- headers : {
241- ...( params . api_key
242- ? { [ 'Authorization' ] : `Bearer ${ params . api_key } ` }
243- : { } ) ,
244- [ 'Content-Type' ] : 'application/json' ,
245- ...( params . endpoint_url == 'https://openrouter.ai/api/v1'
246- ? {
247- 'HTTP-Referer' : 'https://codeweb.chat/' ,
248- 'X-Title' : 'Code Web Chat'
249- }
250- : { } )
251- } ,
348+ headers,
252349 cancelToken : params . cancellation_token ,
253350 responseType : 'stream'
254351 }
@@ -289,7 +386,32 @@ export const make_api_request = async (params: {
289386 const json_string = trimmed_line . slice ( DATA_PREFIX . length ) . trim ( )
290387 if ( json_string && json_string !== DONE_TOKEN ) {
291388 const json_data = JSON . parse ( json_string )
292- const content = json_data . choices ?. [ 0 ] ?. delta ?. content
389+ let content = json_data . choices ?. [ 0 ] ?. delta ?. content
390+
391+ // Special handling for ChatGPT provider
392+ if ( content === undefined && json_data . type ) {
393+ if (
394+ [
395+ 'response.text.delta' ,
396+ 'response.output_text.delta' ,
397+ 'response.reasoning.delta' ,
398+ 'response.reasoning_text.delta'
399+ ] . includes ( json_data . type )
400+ ) {
401+ content = json_data . delta
402+ } else if ( json_data . type === 'response.content_part.added' ) {
403+ content =
404+ typeof json_data . part ?. text === 'string'
405+ ? json_data . part . text
406+ : json_data . part ?. text ?. value
407+ } else if (
408+ json_data . type === 'response.output_item.added' &&
409+ json_data . item ?. type === 'text'
410+ ) {
411+ content = json_data . item ?. text
412+ }
413+ }
414+
293415 if ( typeof content == 'string' ) {
294416 process_content ( content )
295417 }
0 commit comments