@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 1a0b157a2e
Fork 0

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 + }