@@ -31,6 +31,22 @@ export interface AzureResponsesModelConfig {
3131
3232const DEFAULT_API_VERSION = "2025-04-01-preview" ;
3333
34+ type HostedToolStatus = "in_progress" | "completed" | "searching" | "generating" | "interpreting" ;
35+ const HOSTED_TOOL_EVENT_MAP = new Map < string , { toolType : string ; status : HostedToolStatus } > ( [
36+ [ "response.web_search_call.in_progress" , { toolType : "web_search" , status : "in_progress" } ] ,
37+ [ "response.web_search_call.searching" , { toolType : "web_search" , status : "searching" } ] ,
38+ [ "response.web_search_call.completed" , { toolType : "web_search" , status : "completed" } ] ,
39+ [ "response.file_search_call.in_progress" , { toolType : "file_search" , status : "in_progress" } ] ,
40+ [ "response.file_search_call.searching" , { toolType : "file_search" , status : "searching" } ] ,
41+ [ "response.file_search_call.completed" , { toolType : "file_search" , status : "completed" } ] ,
42+ [ "response.code_interpreter_call.in_progress" , { toolType : "code_interpreter" , status : "in_progress" } ] ,
43+ [ "response.code_interpreter_call.interpreting" , { toolType : "code_interpreter" , status : "interpreting" } ] ,
44+ [ "response.code_interpreter_call.completed" , { toolType : "code_interpreter" , status : "completed" } ] ,
45+ [ "response.image_generation_call.in_progress" , { toolType : "image_generation" , status : "in_progress" } ] ,
46+ [ "response.image_generation_call.generating" , { toolType : "image_generation" , status : "generating" } ] ,
47+ [ "response.image_generation_call.completed" , { toolType : "image_generation" , status : "completed" } ] ,
48+ ] ) ;
49+
3450export class AzureResponsesModel implements Model {
3551 private readonly url : string ;
3652 private readonly apiKey ?: string ;
@@ -149,6 +165,25 @@ export class AzureResponsesModel implements Model {
149165 }
150166 break ;
151167 }
168+ // Hosted tool streaming events
169+ case "response.web_search_call.in_progress" :
170+ case "response.web_search_call.searching" :
171+ case "response.web_search_call.completed" :
172+ case "response.file_search_call.in_progress" :
173+ case "response.file_search_call.searching" :
174+ case "response.file_search_call.completed" :
175+ case "response.code_interpreter_call.in_progress" :
176+ case "response.code_interpreter_call.interpreting" :
177+ case "response.code_interpreter_call.completed" :
178+ case "response.image_generation_call.in_progress" :
179+ case "response.image_generation_call.generating" :
180+ case "response.image_generation_call.completed" : {
181+ const mapped = HOSTED_TOOL_EVENT_MAP . get ( event . type ) ;
182+ if ( mapped ) {
183+ yield { type : "hosted_tool_call" , toolType : mapped . toolType , status : mapped . status } ;
184+ }
185+ break ;
186+ }
152187 case "response.completed" : {
153188 const resp = event . response ;
154189 if ( resp ?. id ) {
@@ -170,6 +205,29 @@ export class AzureResponsesModel implements Model {
170205 finishReason = mapStatus ( resp ?. status ) ;
171206 break ;
172207 }
208+ case "response.failed" : {
209+ const errorMsg = event . response ?. error ?. message
210+ ?? "Response failed" ;
211+ throw new ModelError (
212+ `Azure API response failed: ${ errorMsg } ` ,
213+ { status : 200 } ,
214+ ) ;
215+ }
216+ case "error" : {
217+ const err = event . error ;
218+ const errorType = err ?. type ?? "unknown" ;
219+ const errorMsg = err ?. message ?? "Unknown error" ;
220+ if ( errorType === "too_many_requests" ) {
221+ throw new ModelError (
222+ `Azure API rate limited (SSE): ${ errorMsg } ` ,
223+ { status : 429 } ,
224+ ) ;
225+ }
226+ throw new ModelError (
227+ `Azure API stream error (${ errorType } ): ${ errorMsg } ` ,
228+ { status : 200 } ,
229+ ) ;
230+ }
173231 }
174232 }
175233
@@ -195,9 +253,11 @@ export class AzureResponsesModel implements Model {
195253 request : ModelRequest ,
196254 stream : boolean ,
197255 ) : Record < string , unknown > {
256+ // ModelSettings.store overrides config-level store
257+ const effectiveStore = request . modelSettings ?. store ?? this . store ;
198258 const body : Record < string , unknown > = {
199259 model : this . deployment ,
200- store : this . store ,
260+ store : effectiveStore ,
201261 } ;
202262
203263 const { instructions, input } = convertMessages ( request . messages ) ;
@@ -227,23 +287,33 @@ export class AzureResponsesModel implements Model {
227287 }
228288
229289 // Only send previous_response_id when store is enabled (API needs to persist responses)
230- if ( this . store && request . previousResponseId ) {
290+ if ( effectiveStore && request . previousResponseId ) {
231291 body . previous_response_id = request . previousResponseId ;
232292 }
233293
234294 const s = request . modelSettings ;
235295 if ( s ) {
236296 if ( s . temperature !== undefined ) body . temperature = s . temperature ;
237297 if ( s . topP !== undefined ) body . top_p = s . topP ;
238- if ( s . maxTokens !== undefined ) body . max_output_tokens = s . maxTokens ;
239- if ( s . maxCompletionTokens !== undefined )
298+ if ( s . maxCompletionTokens !== undefined ) {
240299 body . max_output_tokens = s . maxCompletionTokens ;
300+ } else if ( s . maxTokens !== undefined ) {
301+ body . max_output_tokens = s . maxTokens ;
302+ }
241303 if ( s . toolChoice !== undefined ) body . tool_choice = convertToolChoice ( s . toolChoice ) ;
242304 if ( s . parallelToolCalls !== undefined ) body . parallel_tool_calls = s . parallelToolCalls ;
243- if ( s . reasoningEffort !== undefined )
244- body . reasoning = { effort : s . reasoningEffort } ;
305+ if ( s . reasoningEffort !== undefined || s . reasoningSummary !== undefined ) {
306+ const reasoning : Record < string , unknown > = { } ;
307+ if ( s . reasoningEffort !== undefined ) reasoning . effort = s . reasoningEffort ;
308+ if ( s . reasoningSummary !== undefined ) reasoning . summary = s . reasoningSummary ;
309+ body . reasoning = reasoning ;
310+ }
245311 if ( s . promptCacheKey !== undefined )
246312 body . prompt_cache_key = s . promptCacheKey ;
313+ if ( s . truncation !== undefined ) body . truncation = s . truncation ;
314+ if ( s . store !== undefined ) body . store = s . store ;
315+ if ( s . metadata !== undefined ) body . metadata = s . metadata ;
316+ if ( s . user !== undefined ) body . user = s . user ;
247317 }
248318
249319 return body ;
@@ -569,4 +639,20 @@ type ResponsesStreamEvent =
569639 | { type : "response.output_item.added" ; item ?: ResponsesStreamItem }
570640 | { type : "response.function_call_arguments.delta" ; item_id ?: string ; delta ?: string }
571641 | { type : "response.output_item.done" ; item ?: ResponsesStreamItem }
572- | { type : "response.completed" ; response ?: { id ?: string ; status ?: string ; usage ?: ResponsesUsage } } ;
642+ | { type : "response.completed" ; response ?: { id ?: string ; status ?: string ; usage ?: ResponsesUsage } }
643+ // Hosted tool streaming events
644+ | { type : "response.web_search_call.in_progress" }
645+ | { type : "response.web_search_call.searching" }
646+ | { type : "response.web_search_call.completed" }
647+ | { type : "response.file_search_call.in_progress" }
648+ | { type : "response.file_search_call.searching" }
649+ | { type : "response.file_search_call.completed" }
650+ | { type : "response.code_interpreter_call.in_progress" }
651+ | { type : "response.code_interpreter_call.interpreting" }
652+ | { type : "response.code_interpreter_call.completed" }
653+ | { type : "response.image_generation_call.in_progress" }
654+ | { type : "response.image_generation_call.generating" }
655+ | { type : "response.image_generation_call.completed" }
656+ // Error / failure events (e.g. SSE-level 429)
657+ | { type : "response.failed" ; response ?: { id ?: string ; status ?: string ; error ?: { message ?: string ; type ?: string ; code ?: string } } }
658+ | { type : "error" ; error ?: { type ?: string ; code ?: string ; message ?: string } } ;
0 commit comments