diff --git a/client-sdks/stainless/openapi.yml b/client-sdks/stainless/openapi.yml
index 51607d92d..7c819a79e 100644
--- a/client-sdks/stainless/openapi.yml
+++ b/client-sdks/stainless/openapi.yml
@@ -6784,6 +6784,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -7171,6 +7203,38 @@ components:
title: OpenAIResponseText
- type: 'null'
title: OpenAIResponseText
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
tools:
anyOf:
- items:
@@ -7330,6 +7394,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -11803,6 +11899,112 @@ components:
type: object
title: OpenAIChatCompletionUsagePromptTokensDetails
description: Token details for prompt tokens in OpenAI chat completion usage.
+ OpenAIResponseInputToolChoiceAllowedTools:
+ properties:
+ mode:
+ type: string
+ enum:
+ - auto
+ - required
+ title: Mode
+ default: auto
+ tools:
+ items:
+ additionalProperties:
+ type: string
+ type: object
+ type: array
+ title: Tools
+ type:
+ type: string
+ const: allowed_tools
+ title: Type
+ default: allowed_tools
+ type: object
+ required:
+ - tools
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ description: Constrains the tools available to the model to a pre-defined set.
+ OpenAIResponseInputToolChoiceCustomTool:
+ properties:
+ type:
+ type: string
+ const: custom
+ title: Type
+ default: custom
+ name:
+ type: string
+ title: Name
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceCustomTool
+ description: Forces the model to call a custom tool.
+ OpenAIResponseInputToolChoiceFileSearch:
+ properties:
+ type:
+ type: string
+ const: file_search
+ title: Type
+ default: file_search
+ type: object
+ title: OpenAIResponseInputToolChoiceFileSearch
+ description: Indicates that the model should use file search to generate a response.
+ OpenAIResponseInputToolChoiceFunctionTool:
+ properties:
+ name:
+ type: string
+ title: Name
+ type:
+ type: string
+ const: function
+ title: Type
+ default: function
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ description: Forces the model to call a specific function.
+ OpenAIResponseInputToolChoiceMCPTool:
+ properties:
+ server_label:
+ type: string
+ title: Server Label
+ type:
+ type: string
+ const: mcp
+ title: Type
+ default: mcp
+ name:
+ anyOf:
+ - type: string
+ - type: 'null'
+ type: object
+ required:
+ - server_label
+ title: OpenAIResponseInputToolChoiceMCPTool
+ description: Forces the model to call a specific tool on a remote MCP server
+ OpenAIResponseInputToolChoiceMode:
+ type: string
+ enum:
+ - auto
+ - required
+ - none
+ title: OpenAIResponseInputToolChoiceMode
+ OpenAIResponseInputToolChoiceWebSearch:
+ properties:
+ type:
+ title: Type
+ default: web_search
+ type: string
+ enum:
+ - web_search
+ - web_search_preview
+ - web_search_preview_2025_03_11
+ - web_search_2025_08_26
+ type: object
+ title: OpenAIResponseInputToolChoiceWebSearch
+ description: Indicates that the model should use web search to generate a response
OpenAIResponseMessage-Input:
properties:
content:
@@ -12189,6 +12391,132 @@ components:
- $ref: '#/components/schemas/GrammarResponseFormat'
title: GrammarResponseFormat
title: JsonSchemaResponseFormat | GrammarResponseFormat
+ AllowedToolsConfig:
+ properties:
+ tools:
+ items:
+ additionalProperties: true
+ type: object
+ title: Tools
+ type: array
+ mode:
+ enum:
+ - auto
+ - required
+ title: Mode
+ type: string
+ required:
+ - tools
+ - mode
+ title: AllowedToolsConfig
+ type: object
+ CustomToolConfig:
+ description: Custom tool configuration for OpenAI-compatible chat completion requests.
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: CustomToolConfig
+ type: object
+ FunctionToolConfig:
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: FunctionToolConfig
+ type: object
+ OpenAIChatCompletionToolChoiceAllowedTools:
+ description: Allowed tools response format for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: allowed_tools
+ default: allowed_tools
+ title: Type
+ type: string
+ allowed_tools:
+ $ref: '#/components/schemas/AllowedToolsConfig'
+ required:
+ - allowed_tools
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ type: object
+ OpenAIChatCompletionToolChoiceCustomTool:
+ description: Custom tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: custom
+ default: custom
+ title: Type
+ type: string
+ custom:
+ $ref: '#/components/schemas/CustomToolConfig'
+ required:
+ - custom
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ type: object
+ OpenAIChatCompletionToolChoiceFunctionTool:
+ description: Function tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: function
+ default: function
+ title: Type
+ type: string
+ function:
+ $ref: '#/components/schemas/FunctionToolConfig'
+ required:
+ - function
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ type: object
+ OpenAIChatCompletionToolChoice:
+ discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ function: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ title: OpenAIChatCompletionToolChoiceAllowedTools | OpenAIChatCompletionToolChoiceFunctionTool | OpenAIChatCompletionToolChoiceCustomTool
+ OpenAIResponseInputToolChoice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ title: OpenAIResponseInputToolChoiceMode
OpenAIResponseContentPart:
discriminator:
mapping:
diff --git a/docs/static/deprecated-llama-stack-spec.html b/docs/static/deprecated-llama-stack-spec.html
new file mode 100644
index 000000000..d80415665
--- /dev/null
+++ b/docs/static/deprecated-llama-stack-spec.html
@@ -0,0 +1,14419 @@
+
+
+
+
+
+
+ OpenAPI specification
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/static/deprecated-llama-stack-spec.yaml b/docs/static/deprecated-llama-stack-spec.yaml
index 2d0ce6e08..8ad6b51ab 100644
--- a/docs/static/deprecated-llama-stack-spec.yaml
+++ b/docs/static/deprecated-llama-stack-spec.yaml
@@ -3778,6 +3778,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -4165,6 +4197,38 @@ components:
title: OpenAIResponseText
- type: 'null'
title: OpenAIResponseText
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
tools:
anyOf:
- items:
@@ -4324,6 +4388,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -8797,6 +8893,112 @@ components:
type: object
title: OpenAIChatCompletionUsagePromptTokensDetails
description: Token details for prompt tokens in OpenAI chat completion usage.
+ OpenAIResponseInputToolChoiceAllowedTools:
+ properties:
+ mode:
+ type: string
+ enum:
+ - auto
+ - required
+ title: Mode
+ default: auto
+ tools:
+ items:
+ additionalProperties:
+ type: string
+ type: object
+ type: array
+ title: Tools
+ type:
+ type: string
+ const: allowed_tools
+ title: Type
+ default: allowed_tools
+ type: object
+ required:
+ - tools
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ description: Constrains the tools available to the model to a pre-defined set.
+ OpenAIResponseInputToolChoiceCustomTool:
+ properties:
+ type:
+ type: string
+ const: custom
+ title: Type
+ default: custom
+ name:
+ type: string
+ title: Name
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceCustomTool
+ description: Forces the model to call a custom tool.
+ OpenAIResponseInputToolChoiceFileSearch:
+ properties:
+ type:
+ type: string
+ const: file_search
+ title: Type
+ default: file_search
+ type: object
+ title: OpenAIResponseInputToolChoiceFileSearch
+ description: Indicates that the model should use file search to generate a response.
+ OpenAIResponseInputToolChoiceFunctionTool:
+ properties:
+ name:
+ type: string
+ title: Name
+ type:
+ type: string
+ const: function
+ title: Type
+ default: function
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ description: Forces the model to call a specific function.
+ OpenAIResponseInputToolChoiceMCPTool:
+ properties:
+ server_label:
+ type: string
+ title: Server Label
+ type:
+ type: string
+ const: mcp
+ title: Type
+ default: mcp
+ name:
+ anyOf:
+ - type: string
+ - type: 'null'
+ type: object
+ required:
+ - server_label
+ title: OpenAIResponseInputToolChoiceMCPTool
+ description: Forces the model to call a specific tool on a remote MCP server
+ OpenAIResponseInputToolChoiceMode:
+ type: string
+ enum:
+ - auto
+ - required
+ - none
+ title: OpenAIResponseInputToolChoiceMode
+ OpenAIResponseInputToolChoiceWebSearch:
+ properties:
+ type:
+ title: Type
+ default: web_search
+ type: string
+ enum:
+ - web_search
+ - web_search_preview
+ - web_search_preview_2025_03_11
+ - web_search_2025_08_26
+ type: object
+ title: OpenAIResponseInputToolChoiceWebSearch
+ description: Indicates that the model should use web search to generate a response
OpenAIResponseMessage-Input:
properties:
content:
@@ -9183,6 +9385,132 @@ components:
- $ref: '#/components/schemas/GrammarResponseFormat'
title: GrammarResponseFormat
title: JsonSchemaResponseFormat | GrammarResponseFormat
+ AllowedToolsConfig:
+ properties:
+ tools:
+ items:
+ additionalProperties: true
+ type: object
+ title: Tools
+ type: array
+ mode:
+ enum:
+ - auto
+ - required
+ title: Mode
+ type: string
+ required:
+ - tools
+ - mode
+ title: AllowedToolsConfig
+ type: object
+ CustomToolConfig:
+ description: Custom tool configuration for OpenAI-compatible chat completion requests.
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: CustomToolConfig
+ type: object
+ FunctionToolConfig:
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: FunctionToolConfig
+ type: object
+ OpenAIChatCompletionToolChoiceAllowedTools:
+ description: Allowed tools response format for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: allowed_tools
+ default: allowed_tools
+ title: Type
+ type: string
+ allowed_tools:
+ $ref: '#/components/schemas/AllowedToolsConfig'
+ required:
+ - allowed_tools
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ type: object
+ OpenAIChatCompletionToolChoiceCustomTool:
+ description: Custom tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: custom
+ default: custom
+ title: Type
+ type: string
+ custom:
+ $ref: '#/components/schemas/CustomToolConfig'
+ required:
+ - custom
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ type: object
+ OpenAIChatCompletionToolChoiceFunctionTool:
+ description: Function tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: function
+ default: function
+ title: Type
+ type: string
+ function:
+ $ref: '#/components/schemas/FunctionToolConfig'
+ required:
+ - function
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ type: object
+ OpenAIChatCompletionToolChoice:
+ discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ function: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ title: OpenAIChatCompletionToolChoiceAllowedTools | OpenAIChatCompletionToolChoiceFunctionTool | OpenAIChatCompletionToolChoiceCustomTool
+ OpenAIResponseInputToolChoice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ title: OpenAIResponseInputToolChoiceMode
OpenAIResponseContentPart:
discriminator:
mapping:
diff --git a/docs/static/experimental-llama-stack-spec.yaml b/docs/static/experimental-llama-stack-spec.yaml
index 4d5a43693..913bec2f6 100644
--- a/docs/static/experimental-llama-stack-spec.yaml
+++ b/docs/static/experimental-llama-stack-spec.yaml
@@ -3318,6 +3318,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -3724,6 +3756,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -7632,6 +7696,112 @@ components:
type: object
title: OpenAIChatCompletionUsagePromptTokensDetails
description: Token details for prompt tokens in OpenAI chat completion usage.
+ OpenAIResponseInputToolChoiceAllowedTools:
+ properties:
+ mode:
+ type: string
+ enum:
+ - auto
+ - required
+ title: Mode
+ default: auto
+ tools:
+ items:
+ additionalProperties:
+ type: string
+ type: object
+ type: array
+ title: Tools
+ type:
+ type: string
+ const: allowed_tools
+ title: Type
+ default: allowed_tools
+ type: object
+ required:
+ - tools
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ description: Constrains the tools available to the model to a pre-defined set.
+ OpenAIResponseInputToolChoiceCustomTool:
+ properties:
+ type:
+ type: string
+ const: custom
+ title: Type
+ default: custom
+ name:
+ type: string
+ title: Name
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceCustomTool
+ description: Forces the model to call a custom tool.
+ OpenAIResponseInputToolChoiceFileSearch:
+ properties:
+ type:
+ type: string
+ const: file_search
+ title: Type
+ default: file_search
+ type: object
+ title: OpenAIResponseInputToolChoiceFileSearch
+ description: Indicates that the model should use file search to generate a response.
+ OpenAIResponseInputToolChoiceFunctionTool:
+ properties:
+ name:
+ type: string
+ title: Name
+ type:
+ type: string
+ const: function
+ title: Type
+ default: function
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ description: Forces the model to call a specific function.
+ OpenAIResponseInputToolChoiceMCPTool:
+ properties:
+ server_label:
+ type: string
+ title: Server Label
+ type:
+ type: string
+ const: mcp
+ title: Type
+ default: mcp
+ name:
+ anyOf:
+ - type: string
+ - type: 'null'
+ type: object
+ required:
+ - server_label
+ title: OpenAIResponseInputToolChoiceMCPTool
+ description: Forces the model to call a specific tool on a remote MCP server
+ OpenAIResponseInputToolChoiceMode:
+ type: string
+ enum:
+ - auto
+ - required
+ - none
+ title: OpenAIResponseInputToolChoiceMode
+ OpenAIResponseInputToolChoiceWebSearch:
+ properties:
+ type:
+ title: Type
+ default: web_search
+ type: string
+ enum:
+ - web_search
+ - web_search_preview
+ - web_search_preview_2025_03_11
+ - web_search_2025_08_26
+ type: object
+ title: OpenAIResponseInputToolChoiceWebSearch
+ description: Indicates that the model should use web search to generate a response
OpenAIResponseMessage-Output:
properties:
content:
@@ -7949,6 +8119,132 @@ components:
- $ref: '#/components/schemas/GrammarResponseFormat'
title: GrammarResponseFormat
title: JsonSchemaResponseFormat | GrammarResponseFormat
+ AllowedToolsConfig:
+ properties:
+ tools:
+ items:
+ additionalProperties: true
+ type: object
+ title: Tools
+ type: array
+ mode:
+ enum:
+ - auto
+ - required
+ title: Mode
+ type: string
+ required:
+ - tools
+ - mode
+ title: AllowedToolsConfig
+ type: object
+ CustomToolConfig:
+ description: Custom tool configuration for OpenAI-compatible chat completion requests.
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: CustomToolConfig
+ type: object
+ FunctionToolConfig:
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: FunctionToolConfig
+ type: object
+ OpenAIChatCompletionToolChoiceAllowedTools:
+ description: Allowed tools response format for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: allowed_tools
+ default: allowed_tools
+ title: Type
+ type: string
+ allowed_tools:
+ $ref: '#/components/schemas/AllowedToolsConfig'
+ required:
+ - allowed_tools
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ type: object
+ OpenAIChatCompletionToolChoiceCustomTool:
+ description: Custom tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: custom
+ default: custom
+ title: Type
+ type: string
+ custom:
+ $ref: '#/components/schemas/CustomToolConfig'
+ required:
+ - custom
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ type: object
+ OpenAIChatCompletionToolChoiceFunctionTool:
+ description: Function tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: function
+ default: function
+ title: Type
+ type: string
+ function:
+ $ref: '#/components/schemas/FunctionToolConfig'
+ required:
+ - function
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ type: object
+ OpenAIChatCompletionToolChoice:
+ discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ function: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ title: OpenAIChatCompletionToolChoiceAllowedTools | OpenAIChatCompletionToolChoiceFunctionTool | OpenAIChatCompletionToolChoiceCustomTool
+ OpenAIResponseInputToolChoice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ title: OpenAIResponseInputToolChoiceMode
OpenAIResponseContentPart:
discriminator:
mapping:
diff --git a/docs/static/llama-stack-spec.html b/docs/static/llama-stack-spec.html
new file mode 100644
index 000000000..b0e6f13a1
--- /dev/null
+++ b/docs/static/llama-stack-spec.html
@@ -0,0 +1,14231 @@
+
+
+
+
+
+
+ OpenAPI specification
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/static/llama-stack-spec.yaml b/docs/static/llama-stack-spec.yaml
index a593fef85..d5a3963f3 100644
--- a/docs/static/llama-stack-spec.yaml
+++ b/docs/static/llama-stack-spec.yaml
@@ -5589,6 +5589,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -5976,6 +6008,38 @@ components:
title: OpenAIResponseText
- type: 'null'
title: OpenAIResponseText
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
tools:
anyOf:
- items:
@@ -6135,6 +6199,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -10239,6 +10335,112 @@ components:
type: object
title: OpenAIChatCompletionUsagePromptTokensDetails
description: Token details for prompt tokens in OpenAI chat completion usage.
+ OpenAIResponseInputToolChoiceAllowedTools:
+ properties:
+ mode:
+ type: string
+ enum:
+ - auto
+ - required
+ title: Mode
+ default: auto
+ tools:
+ items:
+ additionalProperties:
+ type: string
+ type: object
+ type: array
+ title: Tools
+ type:
+ type: string
+ const: allowed_tools
+ title: Type
+ default: allowed_tools
+ type: object
+ required:
+ - tools
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ description: Constrains the tools available to the model to a pre-defined set.
+ OpenAIResponseInputToolChoiceCustomTool:
+ properties:
+ type:
+ type: string
+ const: custom
+ title: Type
+ default: custom
+ name:
+ type: string
+ title: Name
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceCustomTool
+ description: Forces the model to call a custom tool.
+ OpenAIResponseInputToolChoiceFileSearch:
+ properties:
+ type:
+ type: string
+ const: file_search
+ title: Type
+ default: file_search
+ type: object
+ title: OpenAIResponseInputToolChoiceFileSearch
+ description: Indicates that the model should use file search to generate a response.
+ OpenAIResponseInputToolChoiceFunctionTool:
+ properties:
+ name:
+ type: string
+ title: Name
+ type:
+ type: string
+ const: function
+ title: Type
+ default: function
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ description: Forces the model to call a specific function.
+ OpenAIResponseInputToolChoiceMCPTool:
+ properties:
+ server_label:
+ type: string
+ title: Server Label
+ type:
+ type: string
+ const: mcp
+ title: Type
+ default: mcp
+ name:
+ anyOf:
+ - type: string
+ - type: 'null'
+ type: object
+ required:
+ - server_label
+ title: OpenAIResponseInputToolChoiceMCPTool
+ description: Forces the model to call a specific tool on a remote MCP server
+ OpenAIResponseInputToolChoiceMode:
+ type: string
+ enum:
+ - auto
+ - required
+ - none
+ title: OpenAIResponseInputToolChoiceMode
+ OpenAIResponseInputToolChoiceWebSearch:
+ properties:
+ type:
+ title: Type
+ default: web_search
+ type: string
+ enum:
+ - web_search
+ - web_search_preview
+ - web_search_preview_2025_03_11
+ - web_search_2025_08_26
+ type: object
+ title: OpenAIResponseInputToolChoiceWebSearch
+ description: Indicates that the model should use web search to generate a response
OpenAIResponseMessage-Input:
properties:
content:
@@ -10625,6 +10827,132 @@ components:
- $ref: '#/components/schemas/GrammarResponseFormat'
title: GrammarResponseFormat
title: JsonSchemaResponseFormat | GrammarResponseFormat
+ AllowedToolsConfig:
+ properties:
+ tools:
+ items:
+ additionalProperties: true
+ type: object
+ title: Tools
+ type: array
+ mode:
+ enum:
+ - auto
+ - required
+ title: Mode
+ type: string
+ required:
+ - tools
+ - mode
+ title: AllowedToolsConfig
+ type: object
+ CustomToolConfig:
+ description: Custom tool configuration for OpenAI-compatible chat completion requests.
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: CustomToolConfig
+ type: object
+ FunctionToolConfig:
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: FunctionToolConfig
+ type: object
+ OpenAIChatCompletionToolChoiceAllowedTools:
+ description: Allowed tools response format for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: allowed_tools
+ default: allowed_tools
+ title: Type
+ type: string
+ allowed_tools:
+ $ref: '#/components/schemas/AllowedToolsConfig'
+ required:
+ - allowed_tools
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ type: object
+ OpenAIChatCompletionToolChoiceCustomTool:
+ description: Custom tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: custom
+ default: custom
+ title: Type
+ type: string
+ custom:
+ $ref: '#/components/schemas/CustomToolConfig'
+ required:
+ - custom
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ type: object
+ OpenAIChatCompletionToolChoiceFunctionTool:
+ description: Function tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: function
+ default: function
+ title: Type
+ type: string
+ function:
+ $ref: '#/components/schemas/FunctionToolConfig'
+ required:
+ - function
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ type: object
+ OpenAIChatCompletionToolChoice:
+ discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ function: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ title: OpenAIChatCompletionToolChoiceAllowedTools | OpenAIChatCompletionToolChoiceFunctionTool | OpenAIChatCompletionToolChoiceCustomTool
+ OpenAIResponseInputToolChoice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ title: OpenAIResponseInputToolChoiceMode
OpenAIResponseContentPart:
discriminator:
mapping:
diff --git a/docs/static/stainless-llama-stack-spec.html b/docs/static/stainless-llama-stack-spec.html
new file mode 100644
index 000000000..b0d151ca7
--- /dev/null
+++ b/docs/static/stainless-llama-stack-spec.html
@@ -0,0 +1,18929 @@
+
+
+
+
+
+
+ OpenAPI specification
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/static/stainless-llama-stack-spec.yaml b/docs/static/stainless-llama-stack-spec.yaml
index 51607d92d..7c819a79e 100644
--- a/docs/static/stainless-llama-stack-spec.yaml
+++ b/docs/static/stainless-llama-stack-spec.yaml
@@ -6784,6 +6784,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -7171,6 +7203,38 @@ components:
title: OpenAIResponseText
- type: 'null'
title: OpenAIResponseText
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
tools:
anyOf:
- items:
@@ -7330,6 +7394,38 @@ components:
title: OpenAIResponseInputToolWebSearch | ... (4 variants)
type: array
- type: 'null'
+ tool_choice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ discriminator:
+ propertyName: type
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ - type: 'null'
+ title: OpenAIResponseInputToolChoiceMode
truncation:
anyOf:
- type: string
@@ -11803,6 +11899,112 @@ components:
type: object
title: OpenAIChatCompletionUsagePromptTokensDetails
description: Token details for prompt tokens in OpenAI chat completion usage.
+ OpenAIResponseInputToolChoiceAllowedTools:
+ properties:
+ mode:
+ type: string
+ enum:
+ - auto
+ - required
+ title: Mode
+ default: auto
+ tools:
+ items:
+ additionalProperties:
+ type: string
+ type: object
+ type: array
+ title: Tools
+ type:
+ type: string
+ const: allowed_tools
+ title: Type
+ default: allowed_tools
+ type: object
+ required:
+ - tools
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ description: Constrains the tools available to the model to a pre-defined set.
+ OpenAIResponseInputToolChoiceCustomTool:
+ properties:
+ type:
+ type: string
+ const: custom
+ title: Type
+ default: custom
+ name:
+ type: string
+ title: Name
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceCustomTool
+ description: Forces the model to call a custom tool.
+ OpenAIResponseInputToolChoiceFileSearch:
+ properties:
+ type:
+ type: string
+ const: file_search
+ title: Type
+ default: file_search
+ type: object
+ title: OpenAIResponseInputToolChoiceFileSearch
+ description: Indicates that the model should use file search to generate a response.
+ OpenAIResponseInputToolChoiceFunctionTool:
+ properties:
+ name:
+ type: string
+ title: Name
+ type:
+ type: string
+ const: function
+ title: Type
+ default: function
+ type: object
+ required:
+ - name
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ description: Forces the model to call a specific function.
+ OpenAIResponseInputToolChoiceMCPTool:
+ properties:
+ server_label:
+ type: string
+ title: Server Label
+ type:
+ type: string
+ const: mcp
+ title: Type
+ default: mcp
+ name:
+ anyOf:
+ - type: string
+ - type: 'null'
+ type: object
+ required:
+ - server_label
+ title: OpenAIResponseInputToolChoiceMCPTool
+ description: Forces the model to call a specific tool on a remote MCP server
+ OpenAIResponseInputToolChoiceMode:
+ type: string
+ enum:
+ - auto
+ - required
+ - none
+ title: OpenAIResponseInputToolChoiceMode
+ OpenAIResponseInputToolChoiceWebSearch:
+ properties:
+ type:
+ title: Type
+ default: web_search
+ type: string
+ enum:
+ - web_search
+ - web_search_preview
+ - web_search_preview_2025_03_11
+ - web_search_2025_08_26
+ type: object
+ title: OpenAIResponseInputToolChoiceWebSearch
+ description: Indicates that the model should use web search to generate a response
OpenAIResponseMessage-Input:
properties:
content:
@@ -12189,6 +12391,132 @@ components:
- $ref: '#/components/schemas/GrammarResponseFormat'
title: GrammarResponseFormat
title: JsonSchemaResponseFormat | GrammarResponseFormat
+ AllowedToolsConfig:
+ properties:
+ tools:
+ items:
+ additionalProperties: true
+ type: object
+ title: Tools
+ type: array
+ mode:
+ enum:
+ - auto
+ - required
+ title: Mode
+ type: string
+ required:
+ - tools
+ - mode
+ title: AllowedToolsConfig
+ type: object
+ CustomToolConfig:
+ description: Custom tool configuration for OpenAI-compatible chat completion requests.
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: CustomToolConfig
+ type: object
+ FunctionToolConfig:
+ properties:
+ name:
+ title: Name
+ type: string
+ required:
+ - name
+ title: FunctionToolConfig
+ type: object
+ OpenAIChatCompletionToolChoiceAllowedTools:
+ description: Allowed tools response format for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: allowed_tools
+ default: allowed_tools
+ title: Type
+ type: string
+ allowed_tools:
+ $ref: '#/components/schemas/AllowedToolsConfig'
+ required:
+ - allowed_tools
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ type: object
+ OpenAIChatCompletionToolChoiceCustomTool:
+ description: Custom tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: custom
+ default: custom
+ title: Type
+ type: string
+ custom:
+ $ref: '#/components/schemas/CustomToolConfig'
+ required:
+ - custom
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ type: object
+ OpenAIChatCompletionToolChoiceFunctionTool:
+ description: Function tool choice for OpenAI-compatible chat completion requests.
+ properties:
+ type:
+ const: function
+ default: function
+ title: Type
+ type: string
+ function:
+ $ref: '#/components/schemas/FunctionToolConfig'
+ required:
+ - function
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ type: object
+ OpenAIChatCompletionToolChoice:
+ discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ function: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceAllowedTools'
+ title: OpenAIChatCompletionToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceFunctionTool'
+ title: OpenAIChatCompletionToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIChatCompletionToolChoiceCustomTool'
+ title: OpenAIChatCompletionToolChoiceCustomTool
+ title: OpenAIChatCompletionToolChoiceAllowedTools | OpenAIChatCompletionToolChoiceFunctionTool | OpenAIChatCompletionToolChoiceCustomTool
+ OpenAIResponseInputToolChoice:
+ anyOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMode'
+ title: OpenAIResponseInputToolChoiceMode
+ - discriminator:
+ mapping:
+ allowed_tools: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ custom: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ file_search: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ function: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ mcp: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ web_search: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_2025_08_26: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ web_search_preview_2025_03_11: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ propertyName: type
+ oneOf:
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceAllowedTools'
+ title: OpenAIResponseInputToolChoiceAllowedTools
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFileSearch'
+ title: OpenAIResponseInputToolChoiceFileSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceWebSearch'
+ title: OpenAIResponseInputToolChoiceWebSearch
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceFunctionTool'
+ title: OpenAIResponseInputToolChoiceFunctionTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceMCPTool'
+ title: OpenAIResponseInputToolChoiceMCPTool
+ - $ref: '#/components/schemas/OpenAIResponseInputToolChoiceCustomTool'
+ title: OpenAIResponseInputToolChoiceCustomTool
+ title: OpenAIResponseInputToolChoiceAllowedTools | ... (6 variants)
+ title: OpenAIResponseInputToolChoiceMode
OpenAIResponseContentPart:
discriminator:
mapping:
diff --git a/src/llama_stack/providers/inline/agents/meta_reference/agents.py b/src/llama_stack/providers/inline/agents/meta_reference/agents.py
index 39cc22be7..54848c27c 100644
--- a/src/llama_stack/providers/inline/agents/meta_reference/agents.py
+++ b/src/llama_stack/providers/inline/agents/meta_reference/agents.py
@@ -19,6 +19,7 @@ from llama_stack_api import (
OpenAIDeleteResponseObject,
OpenAIResponseInput,
OpenAIResponseInputTool,
+ OpenAIResponseInputToolChoice,
OpenAIResponseObject,
OpenAIResponsePrompt,
OpenAIResponseText,
@@ -104,6 +105,7 @@ class MetaReferenceAgentsImpl(Agents):
stream: bool | None = False,
temperature: float | None = None,
text: OpenAIResponseText | None = None,
+ tool_choice: OpenAIResponseInputToolChoice | None = None,
tools: list[OpenAIResponseInputTool] | None = None,
include: list[str] | None = None,
max_infer_iters: int | None = 10,
@@ -123,6 +125,7 @@ class MetaReferenceAgentsImpl(Agents):
stream,
temperature,
text,
+ tool_choice,
tools,
include,
max_infer_iters,
diff --git a/src/llama_stack/providers/inline/agents/meta_reference/responses/openai_responses.py b/src/llama_stack/providers/inline/agents/meta_reference/responses/openai_responses.py
index 9cf30908c..7ad8b406f 100644
--- a/src/llama_stack/providers/inline/agents/meta_reference/responses/openai_responses.py
+++ b/src/llama_stack/providers/inline/agents/meta_reference/responses/openai_responses.py
@@ -32,6 +32,7 @@ from llama_stack_api import (
OpenAIResponseInputMessageContentImage,
OpenAIResponseInputMessageContentText,
OpenAIResponseInputTool,
+ OpenAIResponseInputToolChoice,
OpenAIResponseMessage,
OpenAIResponseObject,
OpenAIResponseObjectStream,
@@ -330,6 +331,7 @@ class OpenAIResponsesImpl:
stream: bool | None = False,
temperature: float | None = None,
text: OpenAIResponseText | None = None,
+ tool_choice: OpenAIResponseInputToolChoice | None = None,
tools: list[OpenAIResponseInputTool] | None = None,
include: list[str] | None = None,
max_infer_iters: int | None = 10,
@@ -387,6 +389,7 @@ class OpenAIResponsesImpl:
temperature=temperature,
text=text,
tools=tools,
+ tool_choice=tool_choice,
max_infer_iters=max_infer_iters,
guardrail_ids=guardrail_ids,
parallel_tool_calls=parallel_tool_calls,
@@ -440,6 +443,7 @@ class OpenAIResponsesImpl:
temperature: float | None = None,
text: OpenAIResponseText | None = None,
tools: list[OpenAIResponseInputTool] | None = None,
+ tool_choice: OpenAIResponseInputToolChoice | None = None,
max_infer_iters: int | None = 10,
guardrail_ids: list[str] | None = None,
parallel_tool_calls: bool | None = True,
@@ -469,6 +473,7 @@ class OpenAIResponsesImpl:
model=model,
messages=messages,
response_tools=tools,
+ tool_choice=tool_choice,
temperature=temperature,
response_format=response_format,
tool_context=tool_context,
diff --git a/src/llama_stack/providers/inline/agents/meta_reference/responses/streaming.py b/src/llama_stack/providers/inline/agents/meta_reference/responses/streaming.py
index c778d65e7..a4dda8303 100644
--- a/src/llama_stack/providers/inline/agents/meta_reference/responses/streaming.py
+++ b/src/llama_stack/providers/inline/agents/meta_reference/responses/streaming.py
@@ -8,6 +8,7 @@ import uuid
from collections.abc import AsyncIterator
from typing import Any
+from openai.types.chat import ChatCompletionToolParam
from opentelemetry import trace
from llama_stack.log import get_logger
@@ -23,6 +24,10 @@ from llama_stack_api import (
OpenAIChatCompletionChunk,
OpenAIChatCompletionRequestWithExtraBody,
OpenAIChatCompletionToolCall,
+ OpenAIChatCompletionToolChoice,
+ OpenAIChatCompletionToolChoiceAllowedTools,
+ OpenAIChatCompletionToolChoiceCustomTool,
+ OpenAIChatCompletionToolChoiceFunctionTool,
OpenAIChoice,
OpenAIMessageParam,
OpenAIResponseContentPartOutputText,
@@ -30,6 +35,14 @@ from llama_stack_api import (
OpenAIResponseContentPartRefusal,
OpenAIResponseError,
OpenAIResponseInputTool,
+ OpenAIResponseInputToolChoice,
+ OpenAIResponseInputToolChoiceAllowedTools,
+ OpenAIResponseInputToolChoiceCustomTool,
+ OpenAIResponseInputToolChoiceFileSearch,
+ OpenAIResponseInputToolChoiceFunctionTool,
+ OpenAIResponseInputToolChoiceMCPTool,
+ OpenAIResponseInputToolChoiceMode,
+ OpenAIResponseInputToolChoiceWebSearch,
OpenAIResponseInputToolMCP,
OpenAIResponseMCPApprovalRequest,
OpenAIResponseMessage,
@@ -75,6 +88,7 @@ from llama_stack_api import (
from .types import ChatCompletionContext, ChatCompletionResult
from .utils import (
convert_chat_choice_to_response_message,
+ convert_mcp_tool_choice,
is_function_tool_call,
run_guardrails,
)
@@ -144,6 +158,13 @@ class StreamingResponseOrchestrator:
self.mcp_tool_to_server: dict[str, OpenAIResponseInputToolMCP] = (
ctx.tool_context.previous_tools if ctx.tool_context else {}
)
+ # Reverse mapping: server_label -> list of tool names for efficient lookup
+ self.server_label_to_tools: dict[str, list[str]] = {}
+ # Build initial reverse mapping from previous_tools
+ for tool_name, mcp_server in self.mcp_tool_to_server.items():
+ if mcp_server.server_label not in self.server_label_to_tools:
+ self.server_label_to_tools[mcp_server.server_label] = []
+ self.server_label_to_tools[mcp_server.server_label].append(tool_name)
# Track final messages after all tool executions
self.final_messages: list[OpenAIMessageParam] = []
# mapping for annotations
@@ -196,6 +217,7 @@ class StreamingResponseOrchestrator:
output=self._clone_outputs(outputs),
text=self.text,
tools=self.ctx.available_tools(),
+ tool_choice=self.ctx.tool_choice,
error=error,
usage=self.accumulated_usage,
instructions=self.instructions,
@@ -231,6 +253,19 @@ class StreamingResponseOrchestrator:
async for stream_event in self._process_tools(output_messages):
yield stream_event
+ chat_tool_choice = None
+ if self.ctx.tool_choice and len(self.ctx.chat_tools) > 0:
+ processed_tool_choice = await _process_tool_choice(
+ self.ctx.chat_tools,
+ self.ctx.tool_choice,
+ self.server_label_to_tools,
+ )
+ # chat_tool_choice can be str, dict-like object, or None
+ if isinstance(processed_tool_choice, str | type(None)):
+ chat_tool_choice = processed_tool_choice
+ else:
+ chat_tool_choice = processed_tool_choice.model_dump()
+
n_iter = 0
messages = self.ctx.messages.copy()
final_status = "completed"
@@ -250,6 +285,7 @@ class StreamingResponseOrchestrator:
messages=messages,
# Pydantic models are dict-compatible but mypy treats them as distinct types
tools=self.ctx.chat_tools, # type: ignore[arg-type]
+ tool_choice=chat_tool_choice,
stream=True,
temperature=self.ctx.temperature,
response_format=response_format,
@@ -326,6 +362,10 @@ class StreamingResponseOrchestrator:
break
n_iter += 1
+ # After first iteration, reset tool_choice to "auto" to let model decide freely
+ # based on tool results (prevents infinite loops when forcing specific tools)
+ if n_iter == 1 and chat_tool_choice:
+ chat_tool_choice = "auto"
if n_iter >= self.max_infer_iters:
logger.info(
f"Exiting inference loop since iteration count({n_iter}) exceeds {self.max_infer_iters=}"
@@ -1145,6 +1185,11 @@ class StreamingResponseOrchestrator:
raise ValueError(f"Duplicate tool name {t.name} found for server {mcp_tool.server_label}")
self.mcp_tool_to_server[t.name] = mcp_tool
+ # Add to reverse mapping for efficient server_label lookup
+ if mcp_tool.server_label not in self.server_label_to_tools:
+ self.server_label_to_tools[mcp_tool.server_label] = []
+ self.server_label_to_tools[mcp_tool.server_label].append(t.name)
+
# Add to MCP list message
mcp_list_message.tools.append(
MCPListToolsTool(
@@ -1284,3 +1329,112 @@ class StreamingResponseOrchestrator:
async for stream_event in self._add_mcp_list_tools(mcp_list_message, output_messages):
yield stream_event
+
+
+async def _process_tool_choice(
+ chat_tools: list[ChatCompletionToolParam],
+ tool_choice: OpenAIResponseInputToolChoice,
+ server_label_to_tools: dict[str, list[str]],
+) -> str | OpenAIChatCompletionToolChoice | None:
+ """Process and validate the OpenAI Responses tool choice and return the appropriate chat completion tool choice object.
+
+ :param chat_tools: The list of chat tools to enforce tool choice against.
+ :param tool_choice: The OpenAI Responses tool choice to process.
+ :param server_label_to_tools: A dictionary mapping server labels to the list of tools available on that server.
+ :return: The appropriate chat completion tool choice object.
+ """
+
+ # retrieve all function tool names from the chat tools
+ # Note: chat_tools contains dicts, not objects
+ chat_tool_names = [tool["function"]["name"] for tool in chat_tools if tool["type"] == "function"]
+
+ if isinstance(tool_choice, OpenAIResponseInputToolChoiceMode):
+ if tool_choice.value == "required":
+ if len(chat_tool_names) == 0:
+ return None
+
+ # add all function tools to the allowed tools list and set mode to required
+ return OpenAIChatCompletionToolChoiceAllowedTools(
+ tools=[{"type": "function", "function": {"name": tool}} for tool in chat_tool_names],
+ mode="required",
+ )
+ # return other modes as is
+ return tool_choice.value
+
+ elif isinstance(tool_choice, OpenAIResponseInputToolChoiceAllowedTools):
+ # ensure that specified tool choices are available in the chat tools, if not, remove them from the list
+ final_tools = []
+ for tool in tool_choice.tools:
+ match tool.get("type"):
+ case "function":
+ final_tools.append({"type": "function", "function": {"name": tool.get("name")}})
+ case "custom":
+ final_tools.append({"type": "custom", "custom": {"name": tool.get("name")}})
+ case "mcp":
+ mcp_tools = convert_mcp_tool_choice(
+ chat_tool_names, tool.get("server_label"), server_label_to_tools, None
+ )
+ # convert_mcp_tool_choice can return a dict, list, or None
+ if isinstance(mcp_tools, list):
+ final_tools.extend(mcp_tools)
+ elif isinstance(mcp_tools, dict):
+ final_tools.append(mcp_tools)
+ # Skip if None or empty
+ case "file_search":
+ final_tools.append({"type": "function", "function": {"name": "file_search"}})
+ case _ if tool["type"] in WebSearchToolTypes:
+ final_tools.append({"type": "function", "function": {"name": "web_search"}})
+ case _:
+ logger.warning(f"Unsupported tool type: {tool['type']}, skipping tool choice enforcement for it")
+ continue
+
+ return OpenAIChatCompletionToolChoiceAllowedTools(
+ tools=final_tools,
+ mode=tool_choice.mode,
+ )
+
+ else:
+ # Handle specific tool choice by type
+ # Each case validates the tool exists in chat_tools before returning
+ tool_name = getattr(tool_choice, "name", None)
+ match tool_choice:
+ case OpenAIResponseInputToolChoiceCustomTool():
+ if tool_name and tool_name not in chat_tool_names:
+ logger.warning(f"Tool {tool_name} not found in chat tools")
+ return None
+ return OpenAIChatCompletionToolChoiceCustomTool(name=tool_name)
+
+ case OpenAIResponseInputToolChoiceFunctionTool():
+ if tool_name and tool_name not in chat_tool_names:
+ logger.warning(f"Tool {tool_name} not found in chat tools")
+ return None
+ return OpenAIChatCompletionToolChoiceFunctionTool(name=tool_name)
+
+ case OpenAIResponseInputToolChoiceFileSearch():
+ if "file_search" not in chat_tool_names:
+ logger.warning("Tool file_search not found in chat tools")
+ return None
+ return OpenAIChatCompletionToolChoiceFunctionTool(name="file_search")
+
+ case OpenAIResponseInputToolChoiceWebSearch():
+ if "web_search" not in chat_tool_names:
+ logger.warning("Tool web_search not found in chat tools")
+ return None
+ return OpenAIChatCompletionToolChoiceFunctionTool(name="web_search")
+
+ case OpenAIResponseInputToolChoiceMCPTool():
+ tool_choice = convert_mcp_tool_choice(
+ chat_tool_names,
+ tool_choice.server_label,
+ server_label_to_tools,
+ tool_name,
+ )
+ if isinstance(tool_choice, dict):
+ # for single tool choice, return as function tool choice
+ return OpenAIChatCompletionToolChoiceFunctionTool(name=tool_choice["function"]["name"])
+ elif isinstance(tool_choice, list):
+ # for multiple tool choices, return as allowed tools
+ return OpenAIChatCompletionToolChoiceAllowedTools(
+ tools=tool_choice,
+ mode="required",
+ )
diff --git a/src/llama_stack/providers/inline/agents/meta_reference/responses/types.py b/src/llama_stack/providers/inline/agents/meta_reference/responses/types.py
index f6efcee22..614bdace1 100644
--- a/src/llama_stack/providers/inline/agents/meta_reference/responses/types.py
+++ b/src/llama_stack/providers/inline/agents/meta_reference/responses/types.py
@@ -16,6 +16,7 @@ from llama_stack_api import (
OpenAIResponseFormatParam,
OpenAIResponseInput,
OpenAIResponseInputTool,
+ OpenAIResponseInputToolChoice,
OpenAIResponseInputToolFileSearch,
OpenAIResponseInputToolFunction,
OpenAIResponseInputToolMCP,
@@ -160,6 +161,7 @@ class ChatCompletionContext(BaseModel):
temperature: float | None
response_format: OpenAIResponseFormatParam
tool_context: ToolContext | None
+ tool_choice: OpenAIResponseInputToolChoice | None = None
approval_requests: list[OpenAIResponseMCPApprovalRequest] = []
approval_responses: dict[str, OpenAIResponseMCPApprovalResponse] = {}
@@ -172,6 +174,7 @@ class ChatCompletionContext(BaseModel):
response_format: OpenAIResponseFormatParam,
tool_context: ToolContext,
inputs: list[OpenAIResponseInput] | str,
+ tool_choice: OpenAIResponseInputToolChoice | None = None,
):
super().__init__(
model=model,
@@ -180,6 +183,7 @@ class ChatCompletionContext(BaseModel):
temperature=temperature,
response_format=response_format,
tool_context=tool_context,
+ tool_choice=tool_choice,
)
if not isinstance(inputs, str):
self.approval_requests = [input for input in inputs if input.type == "mcp_approval_request"]
diff --git a/src/llama_stack/providers/inline/agents/meta_reference/responses/utils.py b/src/llama_stack/providers/inline/agents/meta_reference/responses/utils.py
index 7bbf6bd30..863c57284 100644
--- a/src/llama_stack/providers/inline/agents/meta_reference/responses/utils.py
+++ b/src/llama_stack/providers/inline/agents/meta_reference/responses/utils.py
@@ -499,3 +499,28 @@ def extract_guardrail_ids(guardrails: list | None) -> list[str]:
raise ValueError(f"Unknown guardrail format: {guardrail}, expected str or ResponseGuardrailSpec")
return guardrail_ids
+
+
+def convert_mcp_tool_choice(
+ chat_tool_names: list[str],
+ server_label: str | None = None,
+ server_label_to_tools: dict[str, list[str]] | None = None,
+ tool_name: str | None = None,
+) -> dict[str, str] | list[dict[str, str]]:
+ """Convert a responses tool choice of type mcp to a chat completions compatible function tool choice."""
+
+ if tool_name:
+ if tool_name not in chat_tool_names:
+ return None
+ return {"type": "function", "function": {"name": tool_name}}
+
+ elif server_label and server_label_to_tools:
+ # no tool name specified, so we need to enforce an allowed_tools with the function tools derived only from the given server label
+ # Use reverse mapping for lookup by server_label
+ # This already accounts for allowed_tools restrictions applied during _process_mcp_tool
+ tool_names = server_label_to_tools.get(server_label, [])
+ if not tool_names:
+ return None
+ matching_tools = [{"type": "function", "function": {"name": tool_name}} for tool_name in tool_names]
+ return matching_tools
+ return []
diff --git a/src/llama_stack_api/__init__.py b/src/llama_stack_api/__init__.py
index b6fe2fd23..c1612886d 100644
--- a/src/llama_stack_api/__init__.py
+++ b/src/llama_stack_api/__init__.py
@@ -147,6 +147,10 @@ from .inference import (
OpenAIChatCompletionTextOnlyMessageContent,
OpenAIChatCompletionToolCall,
OpenAIChatCompletionToolCallFunction,
+ OpenAIChatCompletionToolChoice,
+ OpenAIChatCompletionToolChoiceAllowedTools,
+ OpenAIChatCompletionToolChoiceCustomTool,
+ OpenAIChatCompletionToolChoiceFunctionTool,
OpenAIChatCompletionUsage,
OpenAIChatCompletionUsageCompletionTokensDetails,
OpenAIChatCompletionUsagePromptTokensDetails,
@@ -239,6 +243,15 @@ from .openai_responses import (
OpenAIResponseInputMessageContentImage,
OpenAIResponseInputMessageContentText,
OpenAIResponseInputTool,
+ OpenAIResponseInputToolChoice,
+ OpenAIResponseInputToolChoiceAllowedTools,
+ OpenAIResponseInputToolChoiceCustomTool,
+ OpenAIResponseInputToolChoiceFileSearch,
+ OpenAIResponseInputToolChoiceFunctionTool,
+ OpenAIResponseInputToolChoiceMCPTool,
+ OpenAIResponseInputToolChoiceMode,
+ OpenAIResponseInputToolChoiceObject,
+ OpenAIResponseInputToolChoiceWebSearch,
OpenAIResponseInputToolFileSearch,
OpenAIResponseInputToolFunction,
OpenAIResponseInputToolMCP,
@@ -601,6 +614,10 @@ __all__ = [
"OpenAIChatCompletionUsage",
"OpenAIChatCompletionUsageCompletionTokensDetails",
"OpenAIChatCompletionUsagePromptTokensDetails",
+ "OpenAIChatCompletionToolChoiceAllowedTools",
+ "OpenAIChatCompletionToolChoiceFunctionTool",
+ "OpenAIChatCompletionToolChoiceCustomTool",
+ "OpenAIChatCompletionToolChoice",
"OpenAIChoice",
"OpenAIChoiceDelta",
"OpenAIChoiceLogprobs",
@@ -655,6 +672,15 @@ __all__ = [
"OpenAIResponseInputToolFunction",
"OpenAIResponseInputToolMCP",
"OpenAIResponseInputToolWebSearch",
+ "OpenAIResponseInputToolChoice",
+ "OpenAIResponseInputToolChoiceAllowedTools",
+ "OpenAIResponseInputToolChoiceFileSearch",
+ "OpenAIResponseInputToolChoiceWebSearch",
+ "OpenAIResponseInputToolChoiceFunctionTool",
+ "OpenAIResponseInputToolChoiceMCPTool",
+ "OpenAIResponseInputToolChoiceCustomTool",
+ "OpenAIResponseInputToolChoiceMode",
+ "OpenAIResponseInputToolChoiceObject",
"OpenAIResponseMCPApprovalRequest",
"OpenAIResponseMCPApprovalResponse",
"OpenAIResponseMessage",
diff --git a/src/llama_stack_api/agents.py b/src/llama_stack_api/agents.py
index 8d3b489e1..892116666 100644
--- a/src/llama_stack_api/agents.py
+++ b/src/llama_stack_api/agents.py
@@ -19,6 +19,7 @@ from .openai_responses import (
OpenAIDeleteResponseObject,
OpenAIResponseInput,
OpenAIResponseInputTool,
+ OpenAIResponseInputToolChoice,
OpenAIResponseObject,
OpenAIResponseObjectStream,
OpenAIResponsePrompt,
@@ -79,6 +80,7 @@ class Agents(Protocol):
stream: bool | None = False,
temperature: float | None = None,
text: OpenAIResponseText | None = None,
+ tool_choice: OpenAIResponseInputToolChoice | None = None,
tools: list[OpenAIResponseInputTool] | None = None,
include: list[str] | None = None,
max_infer_iters: int | None = 10, # this is an extension to the OpenAI API
diff --git a/src/llama_stack_api/inference.py b/src/llama_stack_api/inference.py
index 4a169486a..aeddf34c5 100644
--- a/src/llama_stack_api/inference.py
+++ b/src/llama_stack_api/inference.py
@@ -555,6 +555,81 @@ OpenAIResponseFormatParam = Annotated[
register_schema(OpenAIResponseFormatParam, name="OpenAIResponseFormatParam")
+@json_schema_type
+class FunctionToolConfig(BaseModel):
+ name: str
+
+
+@json_schema_type
+class OpenAIChatCompletionToolChoiceFunctionTool(BaseModel):
+ """Function tool choice for OpenAI-compatible chat completion requests.
+
+ :param type: Must be "function" to indicate function tool choice
+ :param function: The function tool configuration
+ """
+
+ type: Literal["function"] = "function"
+ function: FunctionToolConfig
+
+ def __init__(self, name: str):
+ super().__init__(type="function", function=FunctionToolConfig(name=name))
+
+
+@json_schema_type
+class CustomToolConfig(BaseModel):
+ """Custom tool configuration for OpenAI-compatible chat completion requests.
+
+ :param name: Name of the custom tool
+ """
+
+ name: str
+
+
+@json_schema_type
+class OpenAIChatCompletionToolChoiceCustomTool(BaseModel):
+ """Custom tool choice for OpenAI-compatible chat completion requests.
+
+ :param type: Must be "custom" to indicate custom tool choice
+ """
+
+ type: Literal["custom"] = "custom"
+ custom: CustomToolConfig
+
+ def __init__(self, name: str):
+ super().__init__(type="custom", custom=CustomToolConfig(name=name))
+
+
+@json_schema_type
+class AllowedToolsConfig(BaseModel):
+ tools: list[dict[str, Any]]
+ mode: Literal["auto", "required"]
+
+
+@json_schema_type
+class OpenAIChatCompletionToolChoiceAllowedTools(BaseModel):
+ """Allowed tools response format for OpenAI-compatible chat completion requests.
+
+ :param type: Must be "allowed_tools" to indicate allowed tools response format
+ """
+
+ type: Literal["allowed_tools"] = "allowed_tools"
+ allowed_tools: AllowedToolsConfig
+
+ def __init__(self, tools: list[dict[str, Any]], mode: Literal["auto", "required"]):
+ super().__init__(type="allowed_tools", allowed_tools=AllowedToolsConfig(tools=tools, mode=mode))
+
+
+# Define the object-level union with discriminator
+OpenAIChatCompletionToolChoice = Annotated[
+ OpenAIChatCompletionToolChoiceAllowedTools
+ | OpenAIChatCompletionToolChoiceFunctionTool
+ | OpenAIChatCompletionToolChoiceCustomTool,
+ Field(discriminator="type"),
+]
+
+register_schema(OpenAIChatCompletionToolChoice, name="OpenAIChatCompletionToolChoice")
+
+
@json_schema_type
class OpenAITopLogProb(BaseModel):
"""The top log probability for a token from an OpenAI-compatible chat completion response.
diff --git a/src/llama_stack_api/openai_responses.py b/src/llama_stack_api/openai_responses.py
index 177d2314a..8dc372394 100644
--- a/src/llama_stack_api/openai_responses.py
+++ b/src/llama_stack_api/openai_responses.py
@@ -5,6 +5,7 @@
# the root directory of this source tree.
from collections.abc import Sequence
+from enum import Enum
from typing import Annotated, Any, Literal
from pydantic import BaseModel, Field, model_validator
@@ -539,6 +540,105 @@ OpenAIResponseTool = Annotated[
register_schema(OpenAIResponseTool, name="OpenAIResponseTool")
+@json_schema_type
+class OpenAIResponseInputToolChoiceAllowedTools(BaseModel):
+ """Constrains the tools available to the model to a pre-defined set.
+
+ :param mode: Constrains the tools available to the model to a pre-defined set
+ :param tools: A list of tool definitions that the model should be allowed to call
+ :param type: Tool choice type identifier, always "allowed_tools"
+ """
+
+ mode: Literal["auto", "required"] = "auto"
+ tools: list[dict[str, str]]
+ type: Literal["allowed_tools"] = "allowed_tools"
+
+
+@json_schema_type
+class OpenAIResponseInputToolChoiceFileSearch(BaseModel):
+ """Indicates that the model should use file search to generate a response.
+
+ :param type: Tool choice type identifier, always "file_search"
+ """
+
+ type: Literal["file_search"] = "file_search"
+
+
+@json_schema_type
+class OpenAIResponseInputToolChoiceWebSearch(BaseModel):
+ """Indicates that the model should use web search to generate a response
+
+ :param type: Web search tool type variant to use
+ """
+
+ type: (
+ Literal["web_search"]
+ | Literal["web_search_preview"]
+ | Literal["web_search_preview_2025_03_11"]
+ | Literal["web_search_2025_08_26"]
+ ) = "web_search"
+
+
+@json_schema_type
+class OpenAIResponseInputToolChoiceFunctionTool(BaseModel):
+ """Forces the model to call a specific function.
+
+ :param name: The name of the function to call
+ :param type: Tool choice type identifier, always "function"
+ """
+
+ name: str
+ type: Literal["function"] = "function"
+
+
+@json_schema_type
+class OpenAIResponseInputToolChoiceMCPTool(BaseModel):
+ """Forces the model to call a specific tool on a remote MCP server
+
+ :param server_label: The label of the MCP server to use.
+ :param type: Tool choice type identifier, always "mcp"
+ :param name: (Optional) The name of the tool to call on the server.
+ """
+
+ server_label: str
+ type: Literal["mcp"] = "mcp"
+ name: str | None = None
+
+
+@json_schema_type
+class OpenAIResponseInputToolChoiceCustomTool(BaseModel):
+ """Forces the model to call a custom tool.
+
+ :param type: Tool choice type identifier, always "custom"
+ :param name: The name of the custom tool to call.
+ """
+
+ type: Literal["custom"] = "custom"
+ name: str
+
+
+class OpenAIResponseInputToolChoiceMode(str, Enum):
+ auto = "auto"
+ required = "required"
+ none = "none"
+
+
+OpenAIResponseInputToolChoiceObject = Annotated[
+ OpenAIResponseInputToolChoiceAllowedTools
+ | OpenAIResponseInputToolChoiceFileSearch
+ | OpenAIResponseInputToolChoiceWebSearch
+ | OpenAIResponseInputToolChoiceFunctionTool
+ | OpenAIResponseInputToolChoiceMCPTool
+ | OpenAIResponseInputToolChoiceCustomTool,
+ Field(discriminator="type"),
+]
+
+# 3. Final Union without registration or None (Keep it clean)
+OpenAIResponseInputToolChoice = OpenAIResponseInputToolChoiceMode | OpenAIResponseInputToolChoiceObject
+
+register_schema(OpenAIResponseInputToolChoice, name="OpenAIResponseInputToolChoice")
+
+
class OpenAIResponseUsageOutputTokensDetails(BaseModel):
"""Token details for output tokens in OpenAI response usage.
@@ -593,6 +693,7 @@ class OpenAIResponseObject(BaseModel):
:param text: Text formatting configuration for the response
:param top_p: (Optional) Nucleus sampling parameter used for generation
:param tools: (Optional) An array of tools the model may call while generating a response.
+ :param tool_choice: (Optional) Tool choice configuration for the response.
:param truncation: (Optional) Truncation strategy applied to the response
:param usage: (Optional) Token usage information for the response
:param instructions: (Optional) System message inserted into the model's context
@@ -616,6 +717,7 @@ class OpenAIResponseObject(BaseModel):
text: OpenAIResponseText = OpenAIResponseText(format=OpenAIResponseTextFormat(type="text"))
top_p: float | None = None
tools: Sequence[OpenAIResponseTool] | None = None
+ tool_choice: OpenAIResponseInputToolChoice | None = None
truncation: str | None = None
usage: OpenAIResponseUsage | None = None
instructions: str | None = None
diff --git a/tests/unit/providers/agents/meta_reference/test_response_tool_context.py b/tests/unit/providers/agents/meta_reference/test_response_tool_context.py
index 4054debd5..325844ae2 100644
--- a/tests/unit/providers/agents/meta_reference/test_response_tool_context.py
+++ b/tests/unit/providers/agents/meta_reference/test_response_tool_context.py
@@ -5,9 +5,22 @@
# the root directory of this source tree.
+from llama_stack.providers.inline.agents.meta_reference.responses.streaming import (
+ _process_tool_choice,
+)
from llama_stack.providers.inline.agents.meta_reference.responses.types import ToolContext
-from llama_stack_api.openai_responses import (
+from llama_stack_api import (
MCPListToolsTool,
+ OpenAIChatCompletionToolChoiceAllowedTools,
+ OpenAIChatCompletionToolChoiceCustomTool,
+ OpenAIChatCompletionToolChoiceFunctionTool,
+ OpenAIResponseInputToolChoiceAllowedTools,
+ OpenAIResponseInputToolChoiceCustomTool,
+ OpenAIResponseInputToolChoiceFileSearch,
+ OpenAIResponseInputToolChoiceFunctionTool,
+ OpenAIResponseInputToolChoiceMCPTool,
+ OpenAIResponseInputToolChoiceMode,
+ OpenAIResponseInputToolChoiceWebSearch,
OpenAIResponseInputToolFileSearch,
OpenAIResponseInputToolFunction,
OpenAIResponseInputToolMCP,
@@ -181,3 +194,326 @@ class TestToolContext:
assert len(context.previous_tool_listings) == 1
assert len(context.previous_tool_listings[0].tools) == 1
assert context.previous_tool_listings[0].server_label == "anotherlabel"
+
+
+class TestProcessToolChoice:
+ """Comprehensive test suite for _process_tool_choice function."""
+
+ def setup_method(self):
+ """Set up common test fixtures."""
+ self.chat_tools = [
+ {"type": "function", "function": {"name": "get_weather"}},
+ {"type": "function", "function": {"name": "calculate"}},
+ {"type": "function", "function": {"name": "file_search"}},
+ {"type": "function", "function": {"name": "web_search"}},
+ ]
+ self.server_label_to_tools = {
+ "mcp_server_1": ["mcp_tool_1", "mcp_tool_2"],
+ "mcp_server_2": ["mcp_tool_3"],
+ }
+
+ async def test_mode_auto(self):
+ """Test auto mode - should return 'auto' string."""
+ tool_choice = OpenAIResponseInputToolChoiceMode.auto
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+ assert result == "auto"
+
+ async def test_mode_none(self):
+ """Test none mode - should return 'none' string."""
+ tool_choice = OpenAIResponseInputToolChoiceMode.none
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+ assert result == "none"
+
+ async def test_mode_required_with_tools(self):
+ """Test required mode with available tools - should return AllowedTools with all function tools."""
+ tool_choice = OpenAIResponseInputToolChoiceMode.required
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert result.allowed_tools.mode == "required"
+ assert len(result.allowed_tools.tools) == 4
+ tool_names = [tool["function"]["name"] for tool in result.allowed_tools.tools]
+ assert "get_weather" in tool_names
+ assert "calculate" in tool_names
+ assert "file_search" in tool_names
+ assert "web_search" in tool_names
+
+ async def test_mode_required_without_tools(self):
+ """Test required mode without available tools - should return None."""
+ tool_choice = OpenAIResponseInputToolChoiceMode.required
+ result = await _process_tool_choice([], tool_choice, self.server_label_to_tools)
+ assert result is None
+
+ async def test_allowed_tools_function(self):
+ """Test allowed_tools with function tool types."""
+ tool_choice = OpenAIResponseInputToolChoiceAllowedTools(
+ mode="required",
+ tools=[
+ {"type": "function", "name": "get_weather"},
+ {"type": "function", "name": "calculate"},
+ ],
+ )
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert result.allowed_tools.mode == "required"
+ assert len(result.allowed_tools.tools) == 2
+ assert result.allowed_tools.tools[0]["function"]["name"] == "get_weather"
+ assert result.allowed_tools.tools[1]["function"]["name"] == "calculate"
+
+ async def test_allowed_tools_custom(self):
+ """Test allowed_tools with custom tool types."""
+ chat_tools = [{"type": "function", "function": {"name": "custom_tool_1"}}]
+ tool_choice = OpenAIResponseInputToolChoiceAllowedTools(
+ mode="auto",
+ tools=[{"type": "custom", "name": "custom_tool_1"}],
+ )
+ result = await _process_tool_choice(chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert result.allowed_tools.mode == "auto"
+ assert len(result.allowed_tools.tools) == 1
+ assert result.allowed_tools.tools[0]["type"] == "custom"
+ assert result.allowed_tools.tools[0]["custom"]["name"] == "custom_tool_1"
+
+ async def test_allowed_tools_file_search(self):
+ """Test allowed_tools with file_search."""
+ tool_choice = OpenAIResponseInputToolChoiceAllowedTools(
+ mode="required",
+ tools=[{"type": "file_search"}],
+ )
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert len(result.allowed_tools.tools) == 1
+ assert result.allowed_tools.tools[0]["function"]["name"] == "file_search"
+
+ async def test_allowed_tools_web_search(self):
+ """Test allowed_tools with web_search."""
+ tool_choice = OpenAIResponseInputToolChoiceAllowedTools(
+ mode="required",
+ tools=[
+ {"type": "web_search_preview_2025_03_11"},
+ {"type": "web_search_2025_08_26"},
+ {"type": "web_search_preview"},
+ ],
+ )
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert len(result.allowed_tools.tools) == 3
+ assert result.allowed_tools.tools[0]["function"]["name"] == "web_search"
+ assert result.allowed_tools.tools[0]["type"] == "function"
+ assert result.allowed_tools.tools[1]["function"]["name"] == "web_search"
+ assert result.allowed_tools.tools[1]["type"] == "function"
+ assert result.allowed_tools.tools[2]["function"]["name"] == "web_search"
+ assert result.allowed_tools.tools[2]["type"] == "function"
+
+ async def test_allowed_tools_mcp_server_label(self):
+ """Test allowed_tools with MCP server label (no specific tool name)."""
+ chat_tools = [
+ {"type": "function", "function": {"name": "mcp_tool_1"}},
+ {"type": "function", "function": {"name": "mcp_tool_2"}},
+ ]
+ tool_choice = OpenAIResponseInputToolChoiceAllowedTools(
+ mode="required",
+ tools=[{"type": "mcp", "server_label": "mcp_server_1"}],
+ )
+ result = await _process_tool_choice(chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert len(result.allowed_tools.tools) == 2
+ tool_names = [tool["function"]["name"] for tool in result.allowed_tools.tools]
+ assert "mcp_tool_1" in tool_names
+ assert "mcp_tool_2" in tool_names
+
+ async def test_allowed_tools_mixed_types(self):
+ """Test allowed_tools with mixed tool types."""
+ chat_tools = [
+ {"type": "function", "function": {"name": "get_weather"}},
+ {"type": "function", "function": {"name": "file_search"}},
+ {"type": "function", "function": {"name": "web_search"}},
+ {"type": "function", "function": {"name": "mcp_tool_1"}},
+ ]
+ tool_choice = OpenAIResponseInputToolChoiceAllowedTools(
+ mode="auto",
+ tools=[
+ {"type": "function", "name": "get_weather"},
+ {"type": "file_search"},
+ {"type": "web_search"},
+ {"type": "mcp", "server_label": "mcp_server_1"},
+ ],
+ )
+ result = await _process_tool_choice(chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ # Should have: get_weather, file_search, web_search, mcp_tool_1, mcp_tool_2
+ assert len(result.allowed_tools.tools) >= 3
+
+ async def test_allowed_tools_invalid_type(self):
+ """Test allowed_tools with an unsupported tool type - should skip it."""
+ tool_choice = OpenAIResponseInputToolChoiceAllowedTools(
+ mode="required",
+ tools=[
+ {"type": "function", "name": "get_weather"},
+ {"type": "unsupported_type", "name": "bad_tool"},
+ ],
+ )
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ # Should only include the valid function tool
+ assert len(result.allowed_tools.tools) == 1
+ assert result.allowed_tools.tools[0]["function"]["name"] == "get_weather"
+
+ async def test_specific_custom_tool_valid(self):
+ """Test specific custom tool choice when tool exists."""
+ chat_tools = [{"type": "function", "function": {"name": "custom_tool"}}]
+ tool_choice = OpenAIResponseInputToolChoiceCustomTool(name="custom_tool")
+ result = await _process_tool_choice(chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceCustomTool)
+ assert result.custom.name == "custom_tool"
+
+ async def test_specific_custom_tool_invalid(self):
+ """Test specific custom tool choice when tool doesn't exist - should return None."""
+ tool_choice = OpenAIResponseInputToolChoiceCustomTool(name="nonexistent_tool")
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+ assert result is None
+
+ async def test_specific_function_tool_valid(self):
+ """Test specific function tool choice when tool exists."""
+ tool_choice = OpenAIResponseInputToolChoiceFunctionTool(name="get_weather")
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceFunctionTool)
+ assert result.function.name == "get_weather"
+
+ async def test_specific_function_tool_invalid(self):
+ """Test specific function tool choice when tool doesn't exist - should return None."""
+ tool_choice = OpenAIResponseInputToolChoiceFunctionTool(name="nonexistent_function")
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+ assert result is None
+
+ async def test_specific_file_search_valid(self):
+ """Test file_search tool choice when available."""
+ tool_choice = OpenAIResponseInputToolChoiceFileSearch()
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceFunctionTool)
+ assert result.function.name == "file_search"
+
+ async def test_specific_file_search_invalid(self):
+ """Test file_search tool choice when not available - should return None."""
+ chat_tools = [{"type": "function", "function": {"name": "get_weather"}}]
+ tool_choice = OpenAIResponseInputToolChoiceFileSearch()
+ result = await _process_tool_choice(chat_tools, tool_choice, self.server_label_to_tools)
+ assert result is None
+
+ async def test_specific_web_search_valid(self):
+ """Test web_search tool choice when available."""
+ tool_choice = OpenAIResponseInputToolChoiceWebSearch()
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceFunctionTool)
+ assert result.function.name == "web_search"
+
+ async def test_specific_web_search_invalid(self):
+ """Test web_search tool choice when not available - should return None."""
+ chat_tools = [{"type": "function", "function": {"name": "get_weather"}}]
+ tool_choice = OpenAIResponseInputToolChoiceWebSearch()
+ result = await _process_tool_choice(chat_tools, tool_choice, self.server_label_to_tools)
+ assert result is None
+
+ async def test_specific_mcp_tool_with_name(self):
+ """Test MCP tool choice with specific tool name."""
+ chat_tools = [{"type": "function", "function": {"name": "mcp_tool_1"}}]
+ tool_choice = OpenAIResponseInputToolChoiceMCPTool(
+ server_label="mcp_server_1",
+ name="mcp_tool_1",
+ )
+ result = await _process_tool_choice(chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceFunctionTool)
+ assert result.function.name == "mcp_tool_1"
+
+ async def test_specific_mcp_tool_with_name_not_in_chat_tools(self):
+ """Test MCP tool choice with specific tool name that doesn't exist in chat_tools."""
+ chat_tools = [{"type": "function", "function": {"name": "other_tool"}}]
+ tool_choice = OpenAIResponseInputToolChoiceMCPTool(
+ server_label="mcp_server_1",
+ name="mcp_tool_1",
+ )
+ result = await _process_tool_choice(chat_tools, tool_choice, self.server_label_to_tools)
+ assert result is None
+
+ async def test_specific_mcp_tool_server_label_only(self):
+ """Test MCP tool choice with only server label (no specific tool name)."""
+ chat_tools = [
+ {"type": "function", "function": {"name": "mcp_tool_1"}},
+ {"type": "function", "function": {"name": "mcp_tool_2"}},
+ ]
+ tool_choice = OpenAIResponseInputToolChoiceMCPTool(server_label="mcp_server_1")
+ result = await _process_tool_choice(chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert result.allowed_tools.mode == "required"
+ assert len(result.allowed_tools.tools) == 2
+ tool_names = [tool["function"]["name"] for tool in result.allowed_tools.tools]
+ assert "mcp_tool_1" in tool_names
+ assert "mcp_tool_2" in tool_names
+
+ async def test_specific_mcp_tool_unknown_server(self):
+ """Test MCP tool choice with unknown server label."""
+ tool_choice = OpenAIResponseInputToolChoiceMCPTool(
+ server_label="unknown_server",
+ name="some_tool",
+ )
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+ # Should return None because server not found
+ assert result is None
+
+ async def test_empty_chat_tools(self):
+ """Test with empty chat_tools list."""
+ tool_choice = OpenAIResponseInputToolChoiceFunctionTool(name="get_weather")
+ result = await _process_tool_choice([], tool_choice, self.server_label_to_tools)
+ assert result is None
+
+ async def test_empty_server_label_to_tools(self):
+ """Test with empty server_label_to_tools mapping."""
+ tool_choice = OpenAIResponseInputToolChoiceMCPTool(server_label="mcp_server_1")
+ result = await _process_tool_choice(self.chat_tools, tool_choice, {})
+ # Should handle gracefully
+ assert result is None or isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+
+ async def test_allowed_tools_empty_list(self):
+ """Test allowed_tools with empty tools list."""
+ tool_choice = OpenAIResponseInputToolChoiceAllowedTools(mode="auto", tools=[])
+ result = await _process_tool_choice(self.chat_tools, tool_choice, self.server_label_to_tools)
+
+ assert isinstance(result, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert len(result.allowed_tools.tools) == 0
+
+ async def test_mcp_tool_multiple_servers(self):
+ """Test MCP tool choice with multiple server labels."""
+ chat_tools = [
+ {"type": "function", "function": {"name": "mcp_tool_1"}},
+ {"type": "function", "function": {"name": "mcp_tool_2"}},
+ {"type": "function", "function": {"name": "mcp_tool_3"}},
+ ]
+ server_label_to_tools = {
+ "server_a": ["mcp_tool_1"],
+ "server_b": ["mcp_tool_2", "mcp_tool_3"],
+ }
+
+ # Test server_a
+ tool_choice_a = OpenAIResponseInputToolChoiceMCPTool(server_label="server_a")
+ result_a = await _process_tool_choice(chat_tools, tool_choice_a, server_label_to_tools)
+ assert isinstance(result_a, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert len(result_a.allowed_tools.tools) == 1
+
+ # Test server_b
+ tool_choice_b = OpenAIResponseInputToolChoiceMCPTool(server_label="server_b")
+ result_b = await _process_tool_choice(chat_tools, tool_choice_b, server_label_to_tools)
+ assert isinstance(result_b, OpenAIChatCompletionToolChoiceAllowedTools)
+ assert len(result_b.allowed_tools.tools) == 2