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