@@ -13,6 +13,7 @@ import type {
1313 ContentPart ,
1414 ResponseFormat ,
1515 ToolCall ,
16+ ToolChoice ,
1617 ToolDefinition ,
1718} from "../core/types" ;
1819import { resolveResponsesUrl } from "./endpoint" ;
@@ -23,6 +24,7 @@ export interface AzureResponsesModelConfig {
2324 apiKey : string ;
2425 deployment : string ;
2526 apiVersion ?: string ;
27+ store ?: boolean ;
2628}
2729
2830const DEFAULT_API_VERSION = "2025-04-01-preview" ;
@@ -31,10 +33,12 @@ export class AzureResponsesModel implements Model {
3133 private readonly url : string ;
3234 private readonly apiKey : string ;
3335 private readonly deployment : string ;
36+ private readonly store : boolean ;
3437
3538 constructor ( config : AzureResponsesModelConfig ) {
3639 this . apiKey = config . apiKey ;
3740 this . deployment = config . deployment ;
41+ this . store = config . store ?? false ;
3842 this . url = resolveResponsesUrl (
3943 config . endpoint ,
4044 config . apiVersion ?? DEFAULT_API_VERSION ,
@@ -67,6 +71,7 @@ export class AzureResponsesModel implements Model {
6771 const toolCalls = new Map < string , { callId : string ; name : string ; arguments : string } > ( ) ;
6872 let usage : UsageInfo | undefined ;
6973 let finishReason : FinishReason | undefined ;
74+ let responseId : string | undefined ;
7075
7176 for await ( const data of parseSSE ( response . body ) ) {
7277 let event : ResponsesStreamEvent ;
@@ -124,6 +129,9 @@ export class AzureResponsesModel implements Model {
124129 }
125130 case "response.completed" : {
126131 const resp = event . response ;
132+ if ( resp ?. id ) {
133+ responseId = resp . id ;
134+ }
127135 if ( resp ?. usage ) {
128136 usage = {
129137 promptTokens : resp . usage . input_tokens ,
@@ -156,6 +164,7 @@ export class AzureResponsesModel implements Model {
156164 toolCalls : finalToolCalls ,
157165 usage,
158166 finishReason,
167+ responseId,
159168 } ,
160169 } ;
161170 }
@@ -166,7 +175,7 @@ export class AzureResponsesModel implements Model {
166175 ) : Record < string , unknown > {
167176 const body : Record < string , unknown > = {
168177 model : this . deployment ,
169- store : false ,
178+ store : this . store ,
170179 } ;
171180
172181 const { instructions, input } = convertMessages ( request . messages ) ;
@@ -182,21 +191,32 @@ export class AzureResponsesModel implements Model {
182191 }
183192
184193 if ( request . tools && request . tools . length > 0 ) {
185- body . tools = request . tools . map ( flattenToolDefinition ) ;
194+ body . tools = request . tools . map ( ( def ) => {
195+ if ( isFunctionToolDefinition ( def ) ) {
196+ return flattenToolDefinition ( def ) ;
197+ }
198+ // Hosted tool definitions pass through as-is
199+ return def ;
200+ } ) ;
186201 }
187202
188203 if ( request . responseFormat ) {
189204 body . text = convertResponseFormat ( request . responseFormat ) ;
190205 }
191206
207+ // Only send previous_response_id when store is enabled (API needs to persist responses)
208+ if ( this . store && request . previousResponseId ) {
209+ body . previous_response_id = request . previousResponseId ;
210+ }
211+
192212 const s = request . modelSettings ;
193213 if ( s ) {
194214 if ( s . temperature !== undefined ) body . temperature = s . temperature ;
195215 if ( s . topP !== undefined ) body . top_p = s . topP ;
196216 if ( s . maxTokens !== undefined ) body . max_output_tokens = s . maxTokens ;
197217 if ( s . maxCompletionTokens !== undefined )
198218 body . max_output_tokens = s . maxCompletionTokens ;
199- if ( s . toolChoice !== undefined ) body . tool_choice = s . toolChoice ;
219+ if ( s . toolChoice !== undefined ) body . tool_choice = convertToolChoice ( s . toolChoice ) ;
200220 if ( s . parallelToolCalls !== undefined ) body . parallel_tool_calls = s . parallelToolCalls ;
201221 if ( s . reasoningEffort !== undefined )
202222 body . reasoning = { effort : s . reasoningEffort } ;
@@ -277,6 +297,7 @@ export class AzureResponsesModel implements Model {
277297 toolCalls,
278298 usage : json . usage ? parseResponsesUsage ( json . usage ) : undefined ,
279299 finishReason : "length" ,
300+ responseId : json . id ,
280301 } ;
281302 }
282303
@@ -295,6 +316,7 @@ export class AzureResponsesModel implements Model {
295316 toolCalls,
296317 usage,
297318 finishReason,
319+ responseId : json . id ,
298320 } ;
299321 }
300322}
@@ -417,6 +439,21 @@ function convertUserContent(
417439 } ) ;
418440}
419441
442+ function isFunctionToolDefinition (
443+ def : ToolDefinition | Record < string , unknown > ,
444+ ) : def is ToolDefinition {
445+ return "function" in def && typeof ( def as ToolDefinition ) . function === "object" ;
446+ }
447+
448+ function convertToolChoice (
449+ toolChoice : ToolChoice ,
450+ ) : string | { type : string ; name : string } {
451+ if ( typeof toolChoice === "string" ) return toolChoice ;
452+ // Chat Completions format: { type: "function", function: { name } }
453+ // Responses API format: { type: "function", name }
454+ return { type : toolChoice . type , name : toolChoice . function . name } ;
455+ }
456+
420457function flattenToolDefinition (
421458 def : ToolDefinition ,
422459) : Record < string , unknown > {
@@ -459,6 +496,7 @@ function mapStatus(status: string | undefined): FinishReason {
459496// --- Responses API types ---
460497
461498interface ResponsesApiResponse {
499+ id ?: string ;
462500 status : string ;
463501 output ?: ResponsesOutputItem [ ] ;
464502 usage ?: ResponsesUsage ;
@@ -504,4 +542,4 @@ type ResponsesStreamEvent =
504542 | { type : "response.output_item.added" ; item ?: ResponsesStreamItem }
505543 | { type : "response.function_call_arguments.delta" ; item_id ?: string ; delta ?: string }
506544 | { type : "response.output_item.done" ; item ?: ResponsesStreamItem }
507- | { type : "response.completed" ; response ?: { status ?: string ; usage ?: ResponsesUsage } } ;
545+ | { type : "response.completed" ; response ?: { id ?: string ; status ?: string ; usage ?: ResponsesUsage } } ;
0 commit comments