Skip to content

Commit 0180311

Browse files
heheda12345googlercolin
authored andcommitted
[gpt-oss] add demo tool server (vllm-project#22393)
Signed-off-by: Chen Zhang <[email protected]>
1 parent a21edb3 commit 0180311

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed

vllm/entrypoints/openai/api_server.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
from vllm.entrypoints.openai.serving_transcription import (
9393
OpenAIServingTranscription, OpenAIServingTranslation)
9494
from vllm.entrypoints.openai.tool_parsers import ToolParserManager
95+
from vllm.entrypoints.tool_server import DemoToolServer, ToolServer
9596
from vllm.entrypoints.utils import (cli_env_setup, load_aware_call,
9697
log_non_default_args, with_cancellation)
9798
from vllm.logger import init_logger
@@ -1620,6 +1621,11 @@ async def init_app_state(
16201621
"This discrepancy may lead to performance degradation.",
16211622
resolved_chat_template, args.model)
16221623

1624+
if args.tool_server == "demo":
1625+
tool_server: Optional[ToolServer] = DemoToolServer()
1626+
else:
1627+
tool_server = None
1628+
16231629
# Merge default_mm_loras into the static lora_modules
16241630
default_mm_loras = (vllm_config.lora_config.default_mm_loras
16251631
if vllm_config.lora_config is not None else {})
@@ -1654,6 +1660,7 @@ async def init_app_state(
16541660
return_tokens_as_token_ids=args.return_tokens_as_token_ids,
16551661
enable_auto_tools=args.enable_auto_tool_choice,
16561662
tool_parser=args.tool_call_parser,
1663+
tool_server=tool_server,
16571664
reasoning_parser=args.reasoning_parser,
16581665
enable_prompt_tokens_details=args.enable_prompt_tokens_details,
16591666
enable_force_include_usage=args.enable_force_include_usage,

vllm/entrypoints/openai/cli_args.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ class FrontendArgs:
147147
"""Special the tool parser plugin write to parse the model-generated tool
148148
into OpenAI API format, the name register in this plugin can be used in
149149
`--tool-call-parser`."""
150+
tool_server: Optional[str] = None
151+
"""Comma-separated list of host:port pairs (IPv4, IPv6, or hostname).
152+
Examples: 127.0.0.1:8000, [::1]:8000, localhost:1234. Or `demo` for demo
153+
purpose."""
150154
log_config_file: Optional[str] = envs.VLLM_LOGGING_CONFIG_PATH
151155
"""Path to logging config JSON file for both vllm and uvicorn"""
152156
max_log_len: Optional[int] = None

vllm/entrypoints/openai/serving_responses.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
# yapf: enable
3030
from vllm.entrypoints.openai.serving_engine import OpenAIServing
3131
from vllm.entrypoints.openai.serving_models import OpenAIServingModels
32+
from vllm.entrypoints.tool_server import ToolServer
3233
from vllm.logger import init_logger
3334
from vllm.reasoning import ReasoningParser, ReasoningParserManager
3435
from vllm.sampling_params import SamplingParams
@@ -53,6 +54,7 @@ def __init__(
5354
reasoning_parser: str = "",
5455
enable_auto_tools: bool = False,
5556
tool_parser: Optional[str] = None,
57+
tool_server: Optional[ToolServer] = None,
5658
enable_prompt_tokens_details: bool = False,
5759
enable_force_include_usage: bool = False,
5860
) -> None:
@@ -114,6 +116,8 @@ def __init__(
114116

115117
self.background_tasks: dict[str, asyncio.Task] = {}
116118

119+
self.tool_server = tool_server
120+
117121
async def create_responses(
118122
self,
119123
request: ResponsesRequest,

vllm/entrypoints/tool_server.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3+
from abc import ABC, abstractmethod
4+
from contextlib import AbstractAsyncContextManager, asynccontextmanager
5+
from typing import Any, Optional
6+
7+
from openai_harmony import ToolNamespaceConfig
8+
9+
from vllm.entrypoints.tool import HarmonyBrowserTool, HarmonyPythonTool, Tool
10+
from vllm.logger import init_logger
11+
12+
logger = init_logger(__name__)
13+
14+
15+
class ToolServer(ABC):
16+
17+
@abstractmethod
18+
def has_tool(self, tool_name: str) -> bool:
19+
"""
20+
Return True if the tool is supported, False otherwise.
21+
"""
22+
pass
23+
24+
@abstractmethod
25+
def get_tool_description(self,
26+
tool_name: str) -> Optional[ToolNamespaceConfig]:
27+
"""
28+
Return the tool description for the given tool name.
29+
If the tool is not supported, return None.
30+
"""
31+
pass
32+
33+
@abstractmethod
34+
def new_session(self, tool_name: str) -> AbstractAsyncContextManager[Any]:
35+
"""
36+
Create a session for the tool.
37+
"""
38+
...
39+
40+
41+
class DemoToolServer(ToolServer):
42+
43+
def __init__(self):
44+
self.tools: dict[str, Tool] = {}
45+
browser_tool = HarmonyBrowserTool()
46+
if browser_tool.enabled:
47+
self.tools["browser"] = browser_tool
48+
python_tool = HarmonyPythonTool()
49+
if python_tool.enabled:
50+
self.tools["python"] = python_tool
51+
logger.info("DemoToolServer initialized with tools: %s",
52+
list(self.tools.keys()))
53+
54+
def has_tool(self, tool_name: str) -> bool:
55+
return tool_name in self.tools
56+
57+
def get_tool_description(self,
58+
tool_name: str) -> Optional[ToolNamespaceConfig]:
59+
if tool_name not in self.tools:
60+
return None
61+
if tool_name == "browser":
62+
return ToolNamespaceConfig.browser()
63+
elif tool_name == "python":
64+
return ToolNamespaceConfig.python()
65+
else:
66+
raise ValueError(f"Unknown tool {tool_name}")
67+
68+
@asynccontextmanager
69+
async def new_session(self, tool_name: str):
70+
yield self.tools[tool_name]

0 commit comments

Comments
 (0)