@@ -125,68 +125,32 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
125125 yield * this . handleStreamResponse ( stream , model )
126126 }
127127
128- /**
129- * Makes a request to the OpenAI Responses API endpoint
130- * Used by codex-mini-latest model which requires the v1/responses endpoint
131- */
132- private async makeResponsesApiRequest (
133- modelId : string ,
134- instructions : string ,
135- input : string ,
136- stream : boolean = true ,
137- ) : Promise < Response > {
138- // Note: Using fetch() instead of OpenAI client because the OpenAI SDK v5.0.0
139- // does not support the v1/responses endpoint used by codex-mini-latest model.
140- // This is a special endpoint that requires a different request/response format.
141- const apiKey = this . options . openAiNativeApiKey ?? "not-provided"
142- const baseURL = this . options . openAiNativeBaseUrl ?? "https://api.openai.com/v1"
128+ private async * handleCodexMiniMessage (
129+ model : OpenAiNativeModel ,
130+ systemPrompt : string ,
131+ messages : Anthropic . Messages . MessageParam [ ] ,
132+ ) : ApiStream {
133+ // Convert messages to a single input string
134+ const input = this . convertMessagesToInput ( messages )
143135
144136 try {
145- const response = await fetch ( `${ baseURL } /responses` , {
146- method : "POST" ,
147- headers : {
148- "Content-Type" : "application/json" ,
149- Authorization : `Bearer ${ apiKey } ` ,
150- } ,
151- body : JSON . stringify ( {
152- model : modelId ,
153- instructions : instructions ,
154- input : input ,
155- stream : stream ,
156- } ) ,
137+ // Use the OpenAI SDK's responses endpoint
138+ const stream = await this . client . responses . create ( {
139+ model : model . id ,
140+ instructions : systemPrompt ,
141+ input : input ,
142+ stream : true ,
157143 } )
158144
159- if ( ! response . ok ) {
160- const errorText = await response . text ( )
161- throw new Error ( `OpenAI Responses API error: ${ response . status } ${ response . statusText } - ${ errorText } ` )
162- }
163-
164- return response
145+ yield * this . handleResponsesStreamResponse ( stream , model , systemPrompt , input )
165146 } catch ( error ) {
166- // Handle network failures and other errors
167- if ( error instanceof TypeError && error . message . includes ( "fetch" ) ) {
168- throw new Error ( `Network error while calling OpenAI Responses API: ${ error . message } ` )
169- }
170147 if ( error instanceof Error ) {
171148 throw new Error ( `OpenAI Responses API error: ${ error . message } ` )
172149 }
173- throw new Error ( "Unknown error occurred while calling OpenAI Responses API" )
150+ throw error
174151 }
175152 }
176153
177- private async * handleCodexMiniMessage (
178- model : OpenAiNativeModel ,
179- systemPrompt : string ,
180- messages : Anthropic . Messages . MessageParam [ ] ,
181- ) : ApiStream {
182- // Convert messages to a single input string
183- const input = this . convertMessagesToInput ( messages )
184-
185- // Make API call using shared helper
186- const response = await this . makeResponsesApiRequest ( model . id , systemPrompt , input , true )
187- yield * this . handleResponsesStreamResponse ( response . body , model , systemPrompt , input )
188- }
189-
190154 private convertMessagesToInput ( messages : Anthropic . Messages . MessageParam [ ] ) : string {
191155 return messages
192156 . map ( ( msg ) => {
@@ -207,80 +171,45 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
207171 }
208172
209173 private async * handleResponsesStreamResponse (
210- stream : ReadableStream < Uint8Array > | null ,
174+ stream : AsyncIterable < any > ,
211175 model : OpenAiNativeModel ,
212176 systemPrompt : string ,
213177 userInput : string ,
214178 ) : ApiStream {
215- if ( ! stream ) {
216- throw new Error ( "No response stream available" )
217- }
218-
219179 let totalText = ""
220- const reader = stream . getReader ( )
221- const decoder = new TextDecoder ( )
222- let buffer = ""
223180
224181 try {
225- while ( true ) {
226- const { done, value } = await reader . read ( )
227- if ( done ) break
228-
229- buffer += decoder . decode ( value , { stream : true } )
230- const lines = buffer . split ( "\n" )
231- buffer = lines . pop ( ) || ""
232-
233- for ( const line of lines ) {
234- if ( line . trim ( ) === "" ) continue
235- if ( line . startsWith ( "data: " ) ) {
236- const data = line . slice ( 6 )
237- if ( data === "[DONE]" ) continue
238-
239- try {
240- const event = JSON . parse ( data )
241- // Handle different event types from responses API
242- if ( event . type === "response.output_text.delta" ) {
243- yield {
244- type : "text" ,
245- text : event . delta ,
246- }
247- totalText += event . delta
248- } else if ( event . type === "response.completed" ) {
249- // Calculate usage based on text length (approximate)
250- // Estimate tokens: ~1 token per 4 characters
251- const promptTokens = Math . ceil ( ( systemPrompt . length + userInput . length ) / 4 )
252- const completionTokens = Math . ceil ( totalText . length / 4 )
253- yield * this . yieldUsage ( model . info , {
254- prompt_tokens : promptTokens ,
255- completion_tokens : completionTokens ,
256- total_tokens : promptTokens + completionTokens ,
257- } )
258- } else if ( event . type === "response.error" ) {
259- // Handle error events from the API
260- throw new Error (
261- `OpenAI Responses API stream error: ${ event . error ?. message || "Unknown error" } ` ,
262- )
263- } else {
264- // Log unknown event types for debugging and future compatibility
265- console . debug (
266- `OpenAI Responses API: Unknown event type '${ event . type } ' received` ,
267- event ,
268- )
269- }
270- } catch ( e ) {
271- // Only skip if it's a JSON parsing error
272- if ( e instanceof SyntaxError ) {
273- console . debug ( "OpenAI Responses API: Failed to parse SSE data" , data )
274- } else {
275- // Re-throw other errors (like API errors)
276- throw e
277- }
278- }
182+ for await ( const event of stream ) {
183+ // Handle different event types from responses API
184+ if ( event . type === "response.output_text.delta" ) {
185+ yield {
186+ type : "text" ,
187+ text : event . delta ,
279188 }
189+ totalText += event . delta
190+ } else if ( event . type === "response.completed" ) {
191+ // Calculate usage based on text length (approximate)
192+ // Estimate tokens: ~1 token per 4 characters
193+ const promptTokens = Math . ceil ( ( systemPrompt . length + userInput . length ) / 4 )
194+ const completionTokens = Math . ceil ( totalText . length / 4 )
195+ yield * this . yieldUsage ( model . info , {
196+ prompt_tokens : promptTokens ,
197+ completion_tokens : completionTokens ,
198+ total_tokens : promptTokens + completionTokens ,
199+ } )
200+ } else if ( event . type === "response.error" ) {
201+ // Handle error events from the API
202+ throw new Error ( `OpenAI Responses API stream error: ${ event . error ?. message || "Unknown error" } ` )
203+ } else {
204+ // Log unknown event types for debugging and future compatibility
205+ console . debug ( `OpenAI Responses API: Unknown event type '${ event . type } ' received` , event )
280206 }
281207 }
282- } finally {
283- reader . releaseLock ( )
208+ } catch ( error ) {
209+ if ( error instanceof Error ) {
210+ throw new Error ( `OpenAI Responses API error: ${ error . message } ` )
211+ }
212+ throw error
284213 }
285214 }
286215
@@ -348,10 +277,14 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
348277 const { id, temperature, reasoning } = this . getModel ( )
349278
350279 if ( id === "codex-mini-latest" ) {
351- // Make API call using shared helper
352- const response = await this . makeResponsesApiRequest ( id , "Complete the following prompt:" , prompt , false )
353- const data = await response . json ( )
354- return data . output_text || ""
280+ // Use the OpenAI SDK's responses endpoint
281+ const response = await this . client . responses . create ( {
282+ model : id ,
283+ instructions : "Complete the following prompt:" ,
284+ input : prompt ,
285+ stream : false ,
286+ } )
287+ return response . output_text || ""
355288 }
356289
357290 const params : OpenAI . Chat . Completions . ChatCompletionCreateParamsNonStreaming = {
0 commit comments