A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 13, 08:15 UTC
[Frontend][responsesAPI][1/n] convert responses API tool input to chat completions tool format (#28231)
Signed-off-by: Andrew Xia <axia@fb.com> Co-authored-by: Andrew Xia <axia@fb.com> Co-authored-by: Chauncey <chaunceyjiang@gmail.com>
Andrew Xia committed
Nov 12, 2025 at 20:47 UTC
1a0b157a2ea46eebd69072f78e5a97ece4f6a2e7
5 files changed
+76
-21
tests/entrypoints/test_responses_utils.py
new
+30
@@ -0,0 +1,30 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+from vllm.entrypoints.responses_utils import (
5
+ convert_tool_responses_to_completions_format,
6
+)
7
+
8
+
9
+class TestResponsesUtils:
10
+ """Tests for convert_tool_responses_to_completions_format function."""
11
+
12
+ def test_convert_tool_responses_to_completions_format(self):
13
+ """Test basic conversion of a flat tool schema to nested format."""
14
+ input_tool = {
15
+ "type": "function",
16
+ "name": "get_weather",
17
+ "description": "Get the current weather in a given location",
18
+ "parameters": {
19
+ "type": "object",
20
+ "properties": {
21
+ "location": {"type": "string"},
22
+ "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
23
+ },
24
+ "required": ["location", "unit"],
25
+ },
26
+ }
27
+
28
+ result = convert_tool_responses_to_completions_format(input_tool)
29
+
30
+ assert result == {"type": "function", "function": input_tool}
tests/v1/entrypoints/openai/serving_responses/conftest.py
+4
-1
@@ -30,7 +30,10 @@ def server_with_store(default_server_args):
30
with RemoteOpenAIServer(
31
MODEL_NAME,
32
default_server_args,
33
- env_dict={"VLLM_ENABLE_RESPONSES_API_STORE": "1"},
33
+ env_dict={
34
+ "VLLM_ENABLE_RESPONSES_API_STORE": "1",
35
+ "VLLM_SERVER_DEV_MODE": "1",
36
+ },
37
) as remote_server:
38
yield remote_server
39
tests/v1/entrypoints/openai/serving_responses/test_function_call.py
+1
@@ -116,6 +116,7 @@ async def test_function_tool_use(
116
input=prompt,
117
tools=tools,
118
tool_choice=tool_choice,
119
+ temperature=0.0,
120
)
121
122
assert len(response.output) >= 1
vllm/entrypoints/openai/serving_responses.py
+9
-20
@@ -48,7 +48,6 @@ from openai.types.responses.response_output_text import Logprob, LogprobTopLogpr
48
from openai.types.responses.response_reasoning_item import (
49
Content as ResponseReasoningTextContent,
50
)
51
-from openai.types.responses.tool import Tool
51
from openai_harmony import Message as OpenAIHarmonyMessage
52
53
from vllm import envs
@@ -94,7 +93,11 @@ from vllm.entrypoints.openai.protocol import (
93
)
94
from vllm.entrypoints.openai.serving_engine import OpenAIServing
95
from vllm.entrypoints.openai.serving_models import OpenAIServingModels
97
-from vllm.entrypoints.responses_utils import construct_chat_message_with_tool_call
96
+from vllm.entrypoints.responses_utils import (
97
+ construct_chat_message_with_tool_call,
98
+ convert_tool_responses_to_completions_format,
99
+ extract_tool_types,
100
+)
101
from vllm.entrypoints.tool_server import ToolServer
102
from vllm.inputs.data import TokensPrompt as EngineTokensPrompt
103
from vllm.logger import init_logger
@@ -108,23 +111,6 @@ from vllm.utils import random_uuid
111
logger = init_logger(__name__)
112
113
111
-def extract_tool_types(tools: list[Tool]) -> set[str]:
112
- """
113
- Extracts the tool types from the given tools.
114
- """
115
- tool_types: set[str] = set()
116
- for tool in tools:
117
- if tool.type == "mcp":
118
- # Allow the MCP Tool type to enable built in tools if the
119
- # server_label is allowlisted in
120
- # envs.VLLM_GPT_OSS_SYSTEM_TOOL_MCP_LABELS
121
- if tool.server_label in envs.VLLM_GPT_OSS_SYSTEM_TOOL_MCP_LABELS:
122
- tool_types.add(tool.server_label)
123
- else:
124
- tool_types.add(tool.type)
125
- return tool_types
126
-
127
-
114
class OpenAIServingResponses(OpenAIServing):
115
def __init__(
116
self,
@@ -513,7 +499,10 @@ class OpenAIServingResponses(OpenAIServing):
499
):
500
tool_dicts = None
501
else:
516
- tool_dicts = [tool.model_dump() for tool in request.tools]
502
+ tool_dicts = [
503
+ convert_tool_responses_to_completions_format(tool.model_dump())
504
+ for tool in request.tools
505
+ ]
506
# Construct the input messages.
507
messages = self._construct_input_messages(request, prev_response)
508
_, request_prompts, engine_prompts = await self._preprocess_chat(
vllm/entrypoints/responses_utils.py
+32
@@ -10,7 +10,9 @@ from openai.types.chat.chat_completion_message_tool_call_param import (
10
Function as FunctionCallTool,
11
)
12
from openai.types.responses import ResponseFunctionToolCall
13
+from openai.types.responses.tool import Tool
14
15
+from vllm import envs
16
from vllm.entrypoints.openai.protocol import (
17
ChatCompletionMessageParam,
18
ResponseInputOutputItem,
@@ -43,3 +45,33 @@ def construct_chat_message_with_tool_call(
45
tool_call_id=item.get("call_id"),
46
)
47
return item # type: ignore
48
+
49
+
50
+def extract_tool_types(tools: list[Tool]) -> set[str]:
51
+ """
52
+ Extracts the tool types from the given tools.
53
+ """
54
+ tool_types: set[str] = set()
55
+ for tool in tools:
56
+ if tool.type == "mcp":
57
+ # Allow the MCP Tool type to enable built in tools if the
58
+ # server_label is allowlisted in
59
+ # envs.VLLM_GPT_OSS_SYSTEM_TOOL_MCP_LABELS
60
+ if tool.server_label in envs.VLLM_GPT_OSS_SYSTEM_TOOL_MCP_LABELS:
61
+ tool_types.add(tool.server_label)
62
+ else:
63
+ tool_types.add(tool.type)
64
+ return tool_types
65
+
66
+
67
+def convert_tool_responses_to_completions_format(tool: dict) -> dict:
68
+ """
69
+ Convert a flat tool schema:
70
+ {"type": "function", "name": "...", "description": "...", "parameters": {...}}
71
+ into:
72
+ {"type": "function", "function": {...}}
73
+ """
74
+ return {
75
+ "type": "function",
76
+ "function": tool,
77
+ }