Skip to content

Commit 37fb2f3

Browse files
committed
Refactor of responses models dumping
1 parent 30b82a6 commit 37fb2f3

10 files changed

Lines changed: 177 additions & 167 deletions

File tree

docs/openapi.json

Lines changed: 101 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -13569,6 +13569,105 @@
1356913569
}
1357013570
]
1357113571
},
13572+
"InputToolMCP": {
13573+
"properties": {
13574+
"type": {
13575+
"type": "string",
13576+
"const": "mcp",
13577+
"title": "Type",
13578+
"default": "mcp"
13579+
},
13580+
"server_label": {
13581+
"type": "string",
13582+
"title": "Server Label"
13583+
},
13584+
"connector_id": {
13585+
"anyOf": [
13586+
{
13587+
"type": "string"
13588+
},
13589+
{
13590+
"type": "null"
13591+
}
13592+
],
13593+
"title": "Connector Id"
13594+
},
13595+
"server_url": {
13596+
"anyOf": [
13597+
{
13598+
"type": "string"
13599+
},
13600+
{
13601+
"type": "null"
13602+
}
13603+
],
13604+
"title": "Server Url"
13605+
},
13606+
"headers": {
13607+
"anyOf": [
13608+
{
13609+
"additionalProperties": true,
13610+
"type": "object"
13611+
},
13612+
{
13613+
"type": "null"
13614+
}
13615+
],
13616+
"title": "Headers"
13617+
},
13618+
"authorization": {
13619+
"anyOf": [
13620+
{
13621+
"type": "string"
13622+
},
13623+
{
13624+
"type": "null"
13625+
}
13626+
],
13627+
"title": "Authorization"
13628+
},
13629+
"require_approval": {
13630+
"anyOf": [
13631+
{
13632+
"type": "string",
13633+
"const": "always"
13634+
},
13635+
{
13636+
"type": "string",
13637+
"const": "never"
13638+
},
13639+
{
13640+
"$ref": "#/components/schemas/ApprovalFilter-Input"
13641+
}
13642+
],
13643+
"title": "Require Approval",
13644+
"default": "never"
13645+
},
13646+
"allowed_tools": {
13647+
"anyOf": [
13648+
{
13649+
"items": {
13650+
"type": "string"
13651+
},
13652+
"type": "array"
13653+
},
13654+
{
13655+
"$ref": "#/components/schemas/AllowedToolsFilter"
13656+
},
13657+
{
13658+
"type": "null"
13659+
}
13660+
],
13661+
"title": "Allowed Tools"
13662+
}
13663+
},
13664+
"type": "object",
13665+
"required": [
13666+
"server_label"
13667+
],
13668+
"title": "InputToolMCP",
13669+
"description": "MCP input tool with authorization included when serializing request bodies."
13670+
},
1357213671
"InternalServerErrorResponse": {
1357313672
"properties": {
1357413673
"status_code": {
@@ -15281,105 +15380,6 @@
1528115380
"title": "OpenAIResponseInputToolFunction",
1528215381
"description": "Function tool configuration for OpenAI response inputs.\n\n:param type: Tool type identifier, always \"function\"\n:param name: Name of the function that can be called\n:param description: (Optional) Description of what the function does\n:param parameters: (Optional) JSON schema defining the function's parameters\n:param strict: (Optional) Whether to enforce strict parameter validation"
1528315382
},
15284-
"OpenAIResponseInputToolMCP": {
15285-
"properties": {
15286-
"type": {
15287-
"type": "string",
15288-
"const": "mcp",
15289-
"title": "Type",
15290-
"default": "mcp"
15291-
},
15292-
"server_label": {
15293-
"type": "string",
15294-
"title": "Server Label"
15295-
},
15296-
"connector_id": {
15297-
"anyOf": [
15298-
{
15299-
"type": "string"
15300-
},
15301-
{
15302-
"type": "null"
15303-
}
15304-
],
15305-
"title": "Connector Id"
15306-
},
15307-
"server_url": {
15308-
"anyOf": [
15309-
{
15310-
"type": "string"
15311-
},
15312-
{
15313-
"type": "null"
15314-
}
15315-
],
15316-
"title": "Server Url"
15317-
},
15318-
"headers": {
15319-
"anyOf": [
15320-
{
15321-
"additionalProperties": true,
15322-
"type": "object"
15323-
},
15324-
{
15325-
"type": "null"
15326-
}
15327-
],
15328-
"title": "Headers"
15329-
},
15330-
"authorization": {
15331-
"anyOf": [
15332-
{
15333-
"type": "string"
15334-
},
15335-
{
15336-
"type": "null"
15337-
}
15338-
],
15339-
"title": "Authorization"
15340-
},
15341-
"require_approval": {
15342-
"anyOf": [
15343-
{
15344-
"type": "string",
15345-
"const": "always"
15346-
},
15347-
{
15348-
"type": "string",
15349-
"const": "never"
15350-
},
15351-
{
15352-
"$ref": "#/components/schemas/ApprovalFilter-Input"
15353-
}
15354-
],
15355-
"title": "Require Approval",
15356-
"default": "never"
15357-
},
15358-
"allowed_tools": {
15359-
"anyOf": [
15360-
{
15361-
"items": {
15362-
"type": "string"
15363-
},
15364-
"type": "array"
15365-
},
15366-
{
15367-
"$ref": "#/components/schemas/AllowedToolsFilter"
15368-
},
15369-
{
15370-
"type": "null"
15371-
}
15372-
],
15373-
"title": "Allowed Tools"
15374-
}
15375-
},
15376-
"type": "object",
15377-
"required": [
15378-
"server_label"
15379-
],
15380-
"title": "OpenAIResponseInputToolMCP",
15381-
"description": "Model Context Protocol (MCP) tool configuration for OpenAI response inputs.\n\n:param type: Tool type identifier, always \"mcp\"\n:param server_label: Label to identify this MCP server\n:param connector_id: (Optional) ID of the connector to use for this MCP server\n:param server_url: (Optional) URL endpoint of the MCP server\n:param headers: (Optional) HTTP headers to include when connecting to the server\n:param authorization: (Optional) OAuth access token for authenticating with the MCP server\n:param require_approval: Approval requirement for tool calls (\"always\", \"never\", or filter)\n:param allowed_tools: (Optional) Restriction on which tools can be used from this server"
15382-
},
1538315383
"OpenAIResponseInputToolWebSearch": {
1538415384
"properties": {
1538515385
"type": {
@@ -18167,15 +18167,15 @@
1816718167
"$ref": "#/components/schemas/OpenAIResponseInputToolFunction"
1816818168
},
1816918169
{
18170-
"$ref": "#/components/schemas/OpenAIResponseInputToolMCP"
18170+
"$ref": "#/components/schemas/InputToolMCP"
1817118171
}
1817218172
],
1817318173
"discriminator": {
1817418174
"propertyName": "type",
1817518175
"mapping": {
1817618176
"file_search": "#/components/schemas/OpenAIResponseInputToolFileSearch",
1817718177
"function": "#/components/schemas/OpenAIResponseInputToolFunction",
18178-
"mcp": "#/components/schemas/OpenAIResponseInputToolMCP",
18178+
"mcp": "#/components/schemas/InputToolMCP",
1817918179
"web_search": "#/components/schemas/OpenAIResponseInputToolWebSearch",
1818018180
"web_search_2025_08_26": "#/components/schemas/OpenAIResponseInputToolWebSearch",
1818118181
"web_search_preview": "#/components/schemas/OpenAIResponseInputToolWebSearch",

src/app/endpoints/responses.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -455,12 +455,7 @@ async def responses_endpoint_handler(
455455
original_request.input, inline_rag_context.context_text
456456
)
457457

458-
api_params = ResponsesApiParams.model_validate(
459-
{
460-
**updated_request.model_dump(exclude={"tools"}),
461-
"tools": updated_request.tools,
462-
}
463-
)
458+
api_params = ResponsesApiParams.model_validate(updated_request.model_dump())
464459
context = ResponsesContext(
465460
client=client,
466461
auth=auth,

src/models/api/requests/responses_openai.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
import json
44
from typing import Any, Optional, Self
55

6-
from llama_stack_api.openai_responses import (
7-
OpenAIResponseInputTool as InputTool,
8-
)
96
from llama_stack_api.openai_responses import (
107
OpenAIResponseInputToolChoice as ToolChoice,
118
)
@@ -22,7 +19,7 @@
2219

2320
from constants import RESPONSES_REQUEST_MAX_SIZE
2421
from models.common.query import SolrVectorSearchRequest
25-
from models.common.responses.types import IncludeParameter, ResponseInput
22+
from models.common.responses.types import IncludeParameter, InputTool, ResponseInput
2623
from utils import suid
2724

2825

src/models/common/responses/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
)
88
from models.common.responses.types import (
99
IncludeParameter,
10+
InputTool,
11+
InputToolMCP,
1012
ResponseInput,
1113
ResponseItem,
1214
)
@@ -15,6 +17,8 @@
1517
"ResponseInput",
1618
"ResponseItem",
1719
"IncludeParameter",
20+
"InputTool",
21+
"InputToolMCP",
1822
"ResponsesApiParams",
1923
"ResponsesContext",
2024
"ResponsesConversationContext",

src/models/common/responses/responses_api_params.py

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
from collections.abc import Mapping
44
from typing import Any, Final, Optional
55

6-
from llama_stack_api.openai_responses import (
7-
OpenAIResponseInputTool as InputTool,
8-
)
96
from llama_stack_api.openai_responses import (
107
OpenAIResponseInputToolChoice as ToolChoice,
118
)
@@ -23,7 +20,7 @@
2320
)
2421
from pydantic import BaseModel, Field
2522

26-
from models.common.responses.types import IncludeParameter, ResponseInput
23+
from models.common.responses.types import IncludeParameter, InputTool, ResponseInput
2724
from utils.tool_formatter import translate_vector_store_ids_to_user_facing
2825

2926
# Attribute names that are echoed back in the response.
@@ -126,28 +123,16 @@ class ResponsesApiParams(BaseModel):
126123
)
127124

128125
def model_dump(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
129-
"""Serialize params, re-injecting MCP authorization stripped by exclude=True.
126+
"""Serialize to a request body dict.
130127
131-
llama-stack-api marks ``InputToolMCP.authorization`` with
132-
``Field(exclude=True)`` to prevent token leakage in API responses.
133-
The base ``model_dump()`` therefore strips the field, but we need it
134-
in the request payload so llama-stack server can authenticate with
135-
MCP servers. See LCORE-1414 / GitHub issue #1269.
128+
Omits conversation when previous_response_id is set.
129+
130+
Returns:
131+
Serializable dict for the Responses API request body.
136132
"""
137133
result = super().model_dump(*args, **kwargs)
138-
# Only one context option is allowed, previous_response_id has priority
139-
# Turn is added to conversation manually if previous_response_id is used
140134
if self.previous_response_id:
141135
result.pop("conversation", None)
142-
dumped_tools = result.get("tools")
143-
if not self.tools or not isinstance(dumped_tools, list):
144-
return result
145-
if len(dumped_tools) != len(self.tools):
146-
return result
147-
for tool, dumped_tool in zip(self.tools, dumped_tools):
148-
authorization = getattr(tool, "authorization", None)
149-
if authorization is not None and isinstance(dumped_tool, dict):
150-
dumped_tool["authorization"] = authorization
151136
return result
152137

153138
def echoed_params(self, rag_id_mapping: Mapping[str, str]) -> dict[str, Any]:

src/models/common/responses/types.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
"""Type aliases for OpenAI-compatible Responses API input shapes."""
22

3-
from typing import Literal
3+
from typing import Annotated, Literal
44

55
from llama_stack_api.openai_responses import (
66
OpenAIResponseInputFunctionToolCallOutput as FunctionToolCallOutput,
77
)
8+
from llama_stack_api.openai_responses import (
9+
OpenAIResponseInputToolFileSearch as InputToolFileSearch,
10+
)
11+
from llama_stack_api.openai_responses import (
12+
OpenAIResponseInputToolFunction as InputToolFunction,
13+
)
14+
from llama_stack_api.openai_responses import OpenAIResponseInputToolMCP
15+
from llama_stack_api.openai_responses import (
16+
OpenAIResponseInputToolWebSearch as InputToolWebSearch,
17+
)
818
from llama_stack_api.openai_responses import (
919
OpenAIResponseMCPApprovalRequest as McpApprovalRequest,
1020
)
@@ -29,6 +39,19 @@
2939
from llama_stack_api.openai_responses import (
3040
OpenAIResponseOutputMessageWebSearchToolCall as WebSearchToolCall,
3141
)
42+
from pydantic import Field
43+
44+
45+
class InputToolMCP(OpenAIResponseInputToolMCP):
46+
"""MCP input tool with authorization included when serializing request bodies."""
47+
48+
authorization: str | None = None
49+
50+
51+
InputTool = Annotated[
52+
InputToolWebSearch | InputToolFileSearch | InputToolFunction | InputToolMCP,
53+
Field(discriminator="type"),
54+
]
3255

3356
type IncludeParameter = Literal[
3457
"web_search_call.action.sources",

0 commit comments

Comments
 (0)