From bf7950338e61fbf4220a12d9cad8468f105d1fb7 Mon Sep 17 00:00:00 2001 From: Luis Tomas Bolivar Date: Fri, 3 Oct 2025 14:51:38 +0200 Subject: [PATCH 1/3] Update OpenAIResponseInput to include OpenAIResponseOutput --- docs/static/deprecated-llama-stack-spec.html | 17 +---- docs/static/deprecated-llama-stack-spec.yaml | 7 +- docs/static/llama-stack-spec.html | 17 +---- docs/static/llama-stack-spec.yaml | 7 +- docs/static/stainless-llama-stack-spec.html | 17 +---- docs/static/stainless-llama-stack-spec.yaml | 7 +- llama_stack/apis/agents/openai_responses.py | 7 +- .../meta_reference/test_openai_responses.py | 73 +++++++++++++++++++ 8 files changed, 80 insertions(+), 72 deletions(-) diff --git a/docs/static/deprecated-llama-stack-spec.html b/docs/static/deprecated-llama-stack-spec.html index e3e182dd76..f63995babf 100644 --- a/docs/static/deprecated-llama-stack-spec.html +++ b/docs/static/deprecated-llama-stack-spec.html @@ -8528,29 +8528,14 @@ "OpenAIResponseInput": { "oneOf": [ { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall" - }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall" - }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall" + "$ref": "#/components/schemas/OpenAIResponseOutput" }, { "$ref": "#/components/schemas/OpenAIResponseInputFunctionToolCallOutput" }, - { - "$ref": "#/components/schemas/OpenAIResponseMCPApprovalRequest" - }, { "$ref": "#/components/schemas/OpenAIResponseMCPApprovalResponse" }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPCall" - }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPListTools" - }, { "$ref": "#/components/schemas/OpenAIResponseMessage" } diff --git a/docs/static/deprecated-llama-stack-spec.yaml b/docs/static/deprecated-llama-stack-spec.yaml index 6b5b8230ad..ff84312355 100644 --- a/docs/static/deprecated-llama-stack-spec.yaml +++ b/docs/static/deprecated-llama-stack-spec.yaml @@ -6371,14 +6371,9 @@ components: Error details for failed OpenAI response requests. OpenAIResponseInput: oneOf: - - $ref: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutput' - $ref: '#/components/schemas/OpenAIResponseInputFunctionToolCallOutput' - - $ref: '#/components/schemas/OpenAIResponseMCPApprovalRequest' - $ref: '#/components/schemas/OpenAIResponseMCPApprovalResponse' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools' - $ref: '#/components/schemas/OpenAIResponseMessage' "OpenAIResponseInputFunctionToolCallOutput": type: object diff --git a/docs/static/llama-stack-spec.html b/docs/static/llama-stack-spec.html index 3847709542..f605105e89 100644 --- a/docs/static/llama-stack-spec.html +++ b/docs/static/llama-stack-spec.html @@ -7306,29 +7306,14 @@ "OpenAIResponseInput": { "oneOf": [ { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall" - }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall" - }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall" + "$ref": "#/components/schemas/OpenAIResponseOutput" }, { "$ref": "#/components/schemas/OpenAIResponseInputFunctionToolCallOutput" }, - { - "$ref": "#/components/schemas/OpenAIResponseMCPApprovalRequest" - }, { "$ref": "#/components/schemas/OpenAIResponseMCPApprovalResponse" }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPCall" - }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPListTools" - }, { "$ref": "#/components/schemas/OpenAIResponseMessage" } diff --git a/docs/static/llama-stack-spec.yaml b/docs/static/llama-stack-spec.yaml index 36b9c71536..788c13f1f3 100644 --- a/docs/static/llama-stack-spec.yaml +++ b/docs/static/llama-stack-spec.yaml @@ -5523,14 +5523,9 @@ components: Error details for failed OpenAI response requests. OpenAIResponseInput: oneOf: - - $ref: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutput' - $ref: '#/components/schemas/OpenAIResponseInputFunctionToolCallOutput' - - $ref: '#/components/schemas/OpenAIResponseMCPApprovalRequest' - $ref: '#/components/schemas/OpenAIResponseMCPApprovalResponse' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools' - $ref: '#/components/schemas/OpenAIResponseMessage' OpenAIResponseInputToolFileSearch: type: object diff --git a/docs/static/stainless-llama-stack-spec.html b/docs/static/stainless-llama-stack-spec.html index 77a64ced03..b9c12efd6b 100644 --- a/docs/static/stainless-llama-stack-spec.html +++ b/docs/static/stainless-llama-stack-spec.html @@ -8978,29 +8978,14 @@ "OpenAIResponseInput": { "oneOf": [ { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall" - }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall" - }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall" + "$ref": "#/components/schemas/OpenAIResponseOutput" }, { "$ref": "#/components/schemas/OpenAIResponseInputFunctionToolCallOutput" }, - { - "$ref": "#/components/schemas/OpenAIResponseMCPApprovalRequest" - }, { "$ref": "#/components/schemas/OpenAIResponseMCPApprovalResponse" }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPCall" - }, - { - "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPListTools" - }, { "$ref": "#/components/schemas/OpenAIResponseMessage" } diff --git a/docs/static/stainless-llama-stack-spec.yaml b/docs/static/stainless-llama-stack-spec.yaml index bd22f2129c..586c0e344e 100644 --- a/docs/static/stainless-llama-stack-spec.yaml +++ b/docs/static/stainless-llama-stack-spec.yaml @@ -6736,14 +6736,9 @@ components: Error details for failed OpenAI response requests. OpenAIResponseInput: oneOf: - - $ref: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutput' - $ref: '#/components/schemas/OpenAIResponseInputFunctionToolCallOutput' - - $ref: '#/components/schemas/OpenAIResponseMCPApprovalRequest' - $ref: '#/components/schemas/OpenAIResponseMCPApprovalResponse' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools' - $ref: '#/components/schemas/OpenAIResponseMessage' OpenAIResponseInputToolFileSearch: type: object diff --git a/llama_stack/apis/agents/openai_responses.py b/llama_stack/apis/agents/openai_responses.py index 821d6a8af6..d77948526d 100644 --- a/llama_stack/apis/agents/openai_responses.py +++ b/llama_stack/apis/agents/openai_responses.py @@ -1254,14 +1254,9 @@ class OpenAIResponseInputFunctionToolCallOutput(BaseModel): OpenAIResponseInput = Annotated[ # Responses API allows output messages to be passed in as input - OpenAIResponseOutputMessageWebSearchToolCall - | OpenAIResponseOutputMessageFileSearchToolCall - | OpenAIResponseOutputMessageFunctionToolCall + OpenAIResponseOutput | OpenAIResponseInputFunctionToolCallOutput - | OpenAIResponseMCPApprovalRequest | OpenAIResponseMCPApprovalResponse - | OpenAIResponseOutputMessageMCPCall - | OpenAIResponseOutputMessageMCPListTools | OpenAIResponseMessage, Field(union_mode="left_to_right"), ] diff --git a/tests/unit/providers/agents/meta_reference/test_openai_responses.py b/tests/unit/providers/agents/meta_reference/test_openai_responses.py index f31ec0c28d..ba914d808e 100644 --- a/tests/unit/providers/agents/meta_reference/test_openai_responses.py +++ b/tests/unit/providers/agents/meta_reference/test_openai_responses.py @@ -24,6 +24,7 @@ OpenAIResponseInputToolWebSearch, OpenAIResponseMessage, OpenAIResponseOutputMessageContentOutputText, + OpenAIResponseOutputMessageFunctionToolCall, OpenAIResponseOutputMessageMCPCall, OpenAIResponseOutputMessageWebSearchToolCall, OpenAIResponseText, @@ -1169,3 +1170,75 @@ async def test_create_openai_response_with_invalid_text_format(openai_responses_ model=model, text=OpenAIResponseText(format={"type": "invalid"}), ) + + +async def test_create_openai_response_with_output_types_as_input( + openai_responses_impl, mock_inference_api, mock_responses_store +): + """Test that response outputs can be used as inputs in multi-turn conversations. + + Before adding OpenAIResponseOutput types to OpenAIResponseInput, + creating a _OpenAIResponseObjectWithInputAndMessages with some output types + in the input field would fail with a Pydantic ValidationError. + + This test simulates storing a response where the input contains output message + types (MCP calls, function calls), which happens in multi-turn conversations. + """ + model = "meta-llama/Llama-3.1-8B-Instruct" + + # Mock the inference response + mock_inference_api.openai_chat_completion.return_value = fake_stream() + + # Create a response with store=True to trigger the storage path + result = await openai_responses_impl.create_openai_response( + input="What's the weather?", + model=model, + stream=True, + temperature=0.1, + store=True, + ) + + # Consume the stream + _ = [chunk async for chunk in result] + + # Verify store was called + assert mock_responses_store.store_response_object.called + + # Get the stored data + store_call_args = mock_responses_store.store_response_object.call_args + stored_response = store_call_args.kwargs["response_object"] + + # Now simulate a multi-turn conversation where outputs become inputs + input_with_output_types = [ + OpenAIResponseMessage(role="user", content="What's the weather?", name=None), + # These output types need to be valid OpenAIResponseInput + OpenAIResponseOutputMessageFunctionToolCall( + call_id="call_123", + name="get_weather", + arguments='{"city": "Tokyo"}', + type="function_call", + ), + OpenAIResponseOutputMessageMCPCall( + id="mcp_456", + type="mcp_call", + server_label="weather_server", + name="get_temperature", + arguments='{"location": "Tokyo"}', + output="25°C", + ), + ] + + # This simulates storing a response in a multi-turn conversation + # where previous outputs are included in the input. + stored_with_outputs = _OpenAIResponseObjectWithInputAndMessages( + id=stored_response.id, + created_at=stored_response.created_at, + model=stored_response.model, + status=stored_response.status, + output=stored_response.output, + input=input_with_output_types, # This will trigger Pydantic validation + messages=None, + ) + + assert stored_with_outputs.input == input_with_output_types + assert len(stored_with_outputs.input) == 3 From 37a9d4fb05cf5243d2e847d3dfcb6cdccb495bdf Mon Sep 17 00:00:00 2001 From: Luis Tomas Bolivar Date: Fri, 3 Oct 2025 15:11:26 +0200 Subject: [PATCH 2/3] Add protection to response_format --- .../inline/agents/meta_reference/responses/streaming.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/llama_stack/providers/inline/agents/meta_reference/responses/streaming.py b/llama_stack/providers/inline/agents/meta_reference/responses/streaming.py index e80ffcdd14..540d365403 100644 --- a/llama_stack/providers/inline/agents/meta_reference/responses/streaming.py +++ b/llama_stack/providers/inline/agents/meta_reference/responses/streaming.py @@ -217,7 +217,9 @@ async def create_response(self) -> AsyncIterator[OpenAIResponseObjectStream]: while True: # Text is the default response format for chat completion so don't need to pass it # (some providers don't support non-empty response_format when tools are present) - response_format = None if self.ctx.response_format.type == "text" else self.ctx.response_format + response_format = ( + None if getattr(self.ctx.response_format, "type", None) == "text" else self.ctx.response_format + ) logger.debug(f"calling openai_chat_completion with tools: {self.ctx.chat_tools}") params = OpenAIChatCompletionRequestWithExtraBody( From fb26f5def0b11cccfd300f0fc076c23e4bb19d6b Mon Sep 17 00:00:00 2001 From: Luis Tomas Bolivar Date: Thu, 23 Oct 2025 14:44:17 +0200 Subject: [PATCH 3/3] fix client-sdks/stainless/openapi.yml API spec --- client-sdks/stainless/openapi.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/client-sdks/stainless/openapi.yml b/client-sdks/stainless/openapi.yml index bd22f2129c..586c0e344e 100644 --- a/client-sdks/stainless/openapi.yml +++ b/client-sdks/stainless/openapi.yml @@ -6736,14 +6736,9 @@ components: Error details for failed OpenAI response requests. OpenAIResponseInput: oneOf: - - $ref: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutput' - $ref: '#/components/schemas/OpenAIResponseInputFunctionToolCallOutput' - - $ref: '#/components/schemas/OpenAIResponseMCPApprovalRequest' - $ref: '#/components/schemas/OpenAIResponseMCPApprovalResponse' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPCall' - - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools' - $ref: '#/components/schemas/OpenAIResponseMessage' OpenAIResponseInputToolFileSearch: type: object