From 6e4a54717689b9f3de5f778fb030bd2c2c6ec20f Mon Sep 17 00:00:00 2001
From: Flora Feng <4florafeng@gmail.com>
Date: Fri, 12 Jun 2026 16:15:41 -0400
Subject: [PATCH] [Refactor] Deprecate ResponsesParser wrapper, inline parsing
into ParsableContext (#45431)
Signed-off-by: sfeng33 <4florafeng@gmail.com>
---
.../test_parsable_context_unit.py} | 171 +++++++----------
vllm/entrypoints/mcp/tool.py | 2 +-
.../openai/parser/responses_parser.py | 180 ------------------
vllm/entrypoints/openai/responses/context.py | 118 +++++++++---
vllm/entrypoints/openai/responses/serving.py | 6 +-
5 files changed, 169 insertions(+), 308 deletions(-)
rename tests/entrypoints/openai/{test_responses_parser_unified.py => responses/test_parsable_context_unit.py} (66%)
delete mode 100644 vllm/entrypoints/openai/parser/responses_parser.py
diff --git a/tests/entrypoints/openai/test_responses_parser_unified.py b/tests/entrypoints/openai/responses/test_parsable_context_unit.py
similarity index 66%
rename from tests/entrypoints/openai/test_responses_parser_unified.py
rename to tests/entrypoints/openai/responses/test_parsable_context_unit.py
index 231ccf34fc..0aadfbe99d 100644
--- a/tests/entrypoints/openai/test_responses_parser_unified.py
+++ b/tests/entrypoints/openai/responses/test_parsable_context_unit.py
@@ -1,10 +1,9 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
-"""Unit tests for ResponsesParser with the unified Parser interface.
+"""Unit tests for ParsableContext's parsing behavior.
-These tests verify that ResponsesParser correctly delegates to the unified
-Parser (via parse) instead of calling separate ReasoningParser / ToolParser
-instances directly.
+These tests verify that ParsableContext correctly delegates to the unified
+Parser (via parse) and properly builds response output items.
"""
from collections.abc import Sequence
@@ -18,12 +17,9 @@ from vllm.entrypoints.openai.engine.protocol import (
FunctionCall,
ToolCall,
)
-from vllm.entrypoints.openai.parser.responses_parser import (
- ResponsesParser,
- get_responses_parser_for_simple_context,
-)
+from vllm.entrypoints.openai.responses.context import ParsableContext
from vllm.entrypoints.openai.responses.protocol import ResponsesRequest
-from vllm.outputs import CompletionOutput
+from vllm.outputs import CompletionOutput, RequestOutput
from vllm.parser.abstract_parser import DelegatingParser
pytestmark = pytest.mark.skip_global_cleanup
@@ -162,32 +158,42 @@ def _make_request(**overrides) -> ResponsesRequest:
return ResponsesRequest.model_validate(defaults)
-def _make_output(
+def _make_request_output(
text: str = "Hello, world!",
token_ids: Sequence[int] = (1, 2, 3),
finish_reason: str = "stop",
-) -> CompletionOutput:
- return CompletionOutput(
- index=0,
- text=text,
- token_ids=list(token_ids),
- cumulative_logprob=None,
- logprobs=None,
- finish_reason=finish_reason,
+) -> RequestOutput:
+ return RequestOutput(
+ request_id="test",
+ prompt=None,
+ prompt_token_ids=[],
+ prompt_logprobs=None,
+ outputs=[
+ CompletionOutput(
+ index=0,
+ text=text,
+ token_ids=list(token_ids),
+ cumulative_logprob=None,
+ logprobs=None,
+ finish_reason=finish_reason,
+ )
+ ],
+ finished=True,
)
-def _make_parser(parser_cls, **overrides):
+def _make_context(parser_cls, **overrides):
defaults = dict(
tokenizer=MagicMock(),
parser_cls=parser_cls,
response_messages=[],
request=_make_request(),
+ available_tools=None,
chat_template=None,
chat_template_content_format="auto",
)
defaults.update(overrides)
- return ResponsesParser(**defaults)
+ return ParsableContext(**defaults)
# ---------------------------------------------------------------------------
@@ -197,22 +203,22 @@ def _make_parser(parser_cls, **overrides):
def test_process_text_with_parser():
"""Parser with no reasoning/tools returns a single message item."""
- parser = _make_parser(_NoOpParser)
- parser.process(_make_output(text="Hello!"))
+ ctx = _make_context(_NoOpParser)
+ ctx.append_output(_make_request_output(text="Hello!"))
- assert len(parser.response_messages) == 1
- msg = parser.response_messages[0]
+ assert len(ctx.response_messages) == 1
+ msg = ctx.response_messages[0]
assert msg.type == "message"
assert msg.content[0].text == "Hello!"
def test_process_text_without_parser():
"""parser_cls=None falls back to plain text wrapping."""
- parser = _make_parser(None)
- parser.process(_make_output(text="Hello!"))
+ ctx = _make_context(None)
+ ctx.append_output(_make_request_output(text="Hello!"))
- assert len(parser.response_messages) == 1
- msg = parser.response_messages[0]
+ assert len(ctx.response_messages) == 1
+ msg = ctx.response_messages[0]
assert msg.type == "message"
assert msg.content[0].text == "Hello!"
@@ -224,18 +230,18 @@ def test_process_text_without_parser():
def test_process_empty_text_without_parser():
"""Empty text with no parser produces no output items."""
- parser = _make_parser(None)
- parser.process(_make_output(text=""))
+ ctx = _make_context(None)
+ ctx.append_output(_make_request_output(text=""))
- assert len(parser.response_messages) == 0
+ assert len(ctx.response_messages) == 0
def test_process_empty_text_with_parser():
"""Empty text with parser produces no output items."""
- parser = _make_parser(_NoOpParser)
- parser.process(_make_output(text=""))
+ ctx = _make_context(_NoOpParser)
+ ctx.append_output(_make_request_output(text=""))
- assert len(parser.response_messages) == 0
+ assert len(ctx.response_messages) == 0
# ---------------------------------------------------------------------------
@@ -245,26 +251,28 @@ def test_process_empty_text_with_parser():
def test_process_extracts_reasoning():
"""Parser that finds reasoning produces both reasoning and message items."""
- parser = _make_parser(_ReasoningOnlyParser)
- parser.process(_make_output(text="Let me checkThe answer is 42"))
+ ctx = _make_context(_ReasoningOnlyParser)
+ ctx.append_output(
+ _make_request_output(text="Let me checkThe answer is 42")
+ )
- types = [m.type for m in parser.response_messages]
+ types = [m.type for m in ctx.response_messages]
assert "reasoning" in types
assert "message" in types
- reasoning_item = next(m for m in parser.response_messages if m.type == "reasoning")
+ reasoning_item = next(m for m in ctx.response_messages if m.type == "reasoning")
assert reasoning_item.content[0].text == "Let me check"
- message_item = next(m for m in parser.response_messages if m.type == "message")
+ message_item = next(m for m in ctx.response_messages if m.type == "message")
assert message_item.content[0].text == "The answer is 42"
def test_process_reasoning_only_no_content():
"""When reasoning consumes all text, only a reasoning item is produced."""
- parser = _make_parser(_ReasoningOnlyParser)
- parser.process(_make_output(text="Just thinking"))
+ ctx = _make_context(_ReasoningOnlyParser)
+ ctx.append_output(_make_request_output(text="Just thinking"))
- types = [m.type for m in parser.response_messages]
+ types = [m.type for m in ctx.response_messages]
assert "reasoning" in types
assert "message" not in types
@@ -286,13 +294,13 @@ def test_process_extracts_tool_calls():
}
],
)
- parser = _make_parser(_ToolCallingParser, request=request, enable_auto_tools=True)
- parser.process(_make_output(text="calling tool"))
+ ctx = _make_context(_ToolCallingParser, request=request, enable_auto_tools=True)
+ ctx.append_output(_make_request_output(text="calling tool"))
- types = [m.type for m in parser.response_messages]
+ types = [m.type for m in ctx.response_messages]
assert "function_call" in types
- tool_item = next(m for m in parser.response_messages if m.type == "function_call")
+ tool_item = next(m for m in ctx.response_messages if m.type == "function_call")
assert tool_item.name == "get_weather"
assert tool_item.arguments == '{"location": "Paris"}'
assert tool_item.status == "completed"
@@ -304,15 +312,15 @@ def test_process_extracts_tool_calls():
def test_finish_reason_tracked():
- """finish_reason from CompletionOutput is stored on the parser."""
- parser = _make_parser(_NoOpParser)
- assert parser.finish_reason is None
+ """finish_reason from CompletionOutput is stored on the context."""
+ ctx = _make_context(_NoOpParser)
+ assert ctx.finish_reason is None
- parser.process(_make_output(finish_reason="stop"))
- assert parser.finish_reason == "stop"
+ ctx.append_output(_make_request_output(finish_reason="stop"))
+ assert ctx.finish_reason == "stop"
- parser.process(_make_output(finish_reason="length"))
- assert parser.finish_reason == "length"
+ ctx.append_output(_make_request_output(finish_reason="length"))
+ assert ctx.finish_reason == "length"
# ---------------------------------------------------------------------------
@@ -321,62 +329,27 @@ def test_finish_reason_tracked():
def test_multi_turn_accumulation():
- """Multiple process() calls accumulate response_messages."""
- parser = _make_parser(_NoOpParser)
+ """Multiple append_output() calls accumulate response_messages."""
+ ctx = _make_context(_NoOpParser)
- parser.process(_make_output(text="First turn"))
- parser.process(_make_output(text="Second turn"))
+ ctx.append_output(_make_request_output(text="First turn"))
+ ctx.append_output(_make_request_output(text="Second turn"))
- assert len(parser.response_messages) == 2
- texts = [m.content[0].text for m in parser.response_messages]
+ assert len(ctx.response_messages) == 2
+ texts = [m.content[0].text for m in ctx.response_messages]
assert texts == ["First turn", "Second turn"]
def test_num_init_messages_offset():
"""Initial messages are preserved and offset works correctly."""
init_messages = [MagicMock(type="message")]
- parser = _make_parser(_NoOpParser, response_messages=init_messages)
+ ctx = _make_context(_NoOpParser, response_messages=init_messages)
- assert parser.num_init_messages == 1
+ assert ctx.num_init_messages == 1
- parser.process(_make_output(text="New output"))
+ ctx.append_output(_make_request_output(text="New output"))
- assert len(parser.response_messages) == 2
- items = parser.make_response_output_items_from_parsable_context()
+ assert len(ctx.response_messages) == 2
+ items = ctx.make_response_output_items()
assert len(items) == 1
assert items[0].type == "message"
-
-
-# ---------------------------------------------------------------------------
-# Tests: factory function
-# ---------------------------------------------------------------------------
-
-
-def test_factory_function_creates_parser():
- """get_responses_parser_for_simple_context returns a working parser."""
- rp = get_responses_parser_for_simple_context(
- tokenizer=MagicMock(),
- parser_cls=_NoOpParser,
- response_messages=[],
- request=_make_request(),
- chat_template=None,
- chat_template_content_format="auto",
- )
- assert isinstance(rp, ResponsesParser)
-
- rp.process(_make_output(text="Works!"))
- assert len(rp.response_messages) == 1
-
-
-def test_factory_function_none_parser():
- """Factory function works with parser_cls=None."""
- rp = get_responses_parser_for_simple_context(
- tokenizer=MagicMock(),
- parser_cls=None,
- response_messages=[],
- request=_make_request(),
- chat_template=None,
- chat_template_content_format="auto",
- )
- assert isinstance(rp, ResponsesParser)
- assert rp.parser_instance is None
diff --git a/vllm/entrypoints/mcp/tool.py b/vllm/entrypoints/mcp/tool.py
index 9533a1b2d2..cd25aef087 100644
--- a/vllm/entrypoints/mcp/tool.py
+++ b/vllm/entrypoints/mcp/tool.py
@@ -159,7 +159,7 @@ class HarmonyPythonTool(Tool):
assert isinstance(context, ParsableContext)
- last_msg = context.parser.response_messages[-1]
+ last_msg = context.response_messages[-1]
args = json.loads(last_msg.arguments)
last_msg_harmony = Message(
diff --git a/vllm/entrypoints/openai/parser/responses_parser.py b/vllm/entrypoints/openai/parser/responses_parser.py
deleted file mode 100644
index 810019a053..0000000000
--- a/vllm/entrypoints/openai/parser/responses_parser.py
+++ /dev/null
@@ -1,180 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
-import logging
-from typing import Any
-
-from openai.types.responses import ResponseFunctionToolCall, ResponseOutputItem
-from openai.types.responses.response_function_tool_call_output_item import (
- ResponseFunctionToolCallOutputItem,
-)
-from openai.types.responses.response_output_item import McpCall
-from openai.types.responses.response_output_message import ResponseOutputMessage
-from openai.types.responses.response_output_text import ResponseOutputText
-
-from vllm.entrypoints.chat_utils import ChatTemplateContentFormatOption
-from vllm.entrypoints.openai.responses.protocol import (
- ResponseInputOutputItem,
- ResponsesRequest,
-)
-from vllm.entrypoints.openai.responses.utils import build_response_output_items
-from vllm.entrypoints.serve.utils.constants import MCP_PREFIX
-from vllm.outputs import CompletionOutput
-from vllm.parser.abstract_parser import Parser
-from vllm.tokenizers import TokenizerLike
-from vllm.utils import random_uuid
-
-logger = logging.getLogger(__name__)
-
-
-class ResponsesParser:
- """Incremental parser over completion tokens with reasoning support."""
-
- def __init__(
- self,
- *,
- tokenizer: TokenizerLike,
- parser_cls: type[Parser] | None,
- response_messages: list[ResponseInputOutputItem],
- request: ResponsesRequest,
- chat_template: str | None,
- chat_template_content_format: ChatTemplateContentFormatOption,
- enable_auto_tools: bool = False,
- tool_call_id_type: str = "random",
- ):
- self.response_messages: list[ResponseInputOutputItem] = (
- # TODO: initial messages may not be properly typed
- response_messages
- )
- self.num_init_messages = len(response_messages)
- self.tokenizer = tokenizer
- self.request = request
-
- self.parser_instance: Parser | None = None
- if parser_cls is not None:
- chat_template_kwargs = _effective_chat_template_kwargs(
- request,
- chat_template=chat_template,
- chat_template_content_format=chat_template_content_format,
- )
-
- self.parser_instance = parser_cls(
- tokenizer,
- tools=request.tools,
- chat_template_kwargs=chat_template_kwargs,
- )
-
- self.enable_auto_tools = enable_auto_tools
- self.tool_call_id_type = tool_call_id_type
-
- # Store the last finish_reason to determine response status
- self.finish_reason: str | None = None
-
- def process(self, output: CompletionOutput) -> "ResponsesParser":
- # Store the finish_reason from the output
- self.finish_reason = output.finish_reason
-
- if self.parser_instance is not None:
- reasoning, content, tool_calls = self.parser_instance.parse(
- output.text,
- self.request,
- enable_auto_tools=self.enable_auto_tools,
- )
- output_items = build_response_output_items(
- reasoning=reasoning,
- content=content,
- tool_calls=tool_calls,
- tool_call_id_type=self.tool_call_id_type,
- )
- self.response_messages.extend(output_items)
- else:
- # No parser configured, treat entire output as text content
- if output.text:
- self.response_messages.append(
- ResponseOutputMessage(
- type="message",
- id=f"msg_{random_uuid()}",
- status="completed",
- role="assistant",
- content=[
- ResponseOutputText(
- annotations=[], # TODO
- type="output_text",
- text=output.text,
- logprobs=None, # TODO
- )
- ],
- )
- )
-
- return self
-
- def make_response_output_items_from_parsable_context(
- self,
- ) -> list[ResponseOutputItem]:
- """Given a list of sentences, construct ResponseOutput Items."""
- response_messages = self.response_messages[self.num_init_messages :]
- output_messages: list[ResponseOutputItem] = []
- for message in response_messages:
- if not isinstance(message, ResponseFunctionToolCallOutputItem):
- output_messages.append(message)
- else:
- if len(output_messages) == 0:
- raise ValueError(
- "Cannot have a FunctionToolCallOutput before FunctionToolCall."
- )
- if isinstance(output_messages[-1], ResponseFunctionToolCall):
- mcp_message = McpCall(
- id=f"{MCP_PREFIX}{random_uuid()}",
- arguments=output_messages[-1].arguments,
- name=output_messages[-1].name,
- server_label=output_messages[
- -1
- ].name, # TODO: store the server label
- type="mcp_call",
- status="completed",
- output=message.output,
- # TODO: support error output
- )
- output_messages[-1] = mcp_message
-
- return output_messages
-
-
-def get_responses_parser_for_simple_context(
- *,
- tokenizer: TokenizerLike,
- parser_cls: type[Parser] | None,
- response_messages: list[ResponseInputOutputItem],
- request: ResponsesRequest,
- chat_template: str | None,
- chat_template_content_format: ChatTemplateContentFormatOption,
- enable_auto_tools: bool = False,
- tool_call_id_type: str = "random",
-) -> ResponsesParser:
- """Factory function to create a ResponsesParser with
- optional unified parser.
-
- Returns:
- ResponsesParser instance configured with the provided parser
- """
- return ResponsesParser(
- tokenizer=tokenizer,
- parser_cls=parser_cls,
- response_messages=response_messages,
- request=request,
- chat_template=chat_template,
- chat_template_content_format=chat_template_content_format,
- enable_auto_tools=enable_auto_tools,
- tool_call_id_type=tool_call_id_type,
- )
-
-
-def _effective_chat_template_kwargs(
- request: ResponsesRequest,
- chat_template: str | None,
- chat_template_content_format: ChatTemplateContentFormatOption,
-) -> dict[str, Any]:
- return request.build_chat_params(
- default_template=chat_template,
- default_template_content_format=chat_template_content_format,
- ).chat_template_kwargs
diff --git a/vllm/entrypoints/openai/responses/context.py b/vllm/entrypoints/openai/responses/context.py
index e72032c24a..9679b732a7 100644
--- a/vllm/entrypoints/openai/responses/context.py
+++ b/vllm/entrypoints/openai/responses/context.py
@@ -10,9 +10,13 @@ from contextlib import AsyncExitStack
from dataclasses import replace
from typing import TYPE_CHECKING, Any, Final, Union
+from openai.types.responses import ResponseFunctionToolCall, ResponseOutputItem
from openai.types.responses.response_function_tool_call_output_item import (
ResponseFunctionToolCallOutputItem,
)
+from openai.types.responses.response_output_item import McpCall
+from openai.types.responses.response_output_message import ResponseOutputMessage
+from openai.types.responses.response_output_text import ResponseOutputText
from openai.types.responses.tool import Mcp
from openai_harmony import Author, Message, Role, StreamState, TextContent
@@ -30,15 +34,15 @@ from vllm.entrypoints.openai.parser.harmony_utils import (
get_streamable_parser_for_assistant,
render_for_completion,
)
-from vllm.entrypoints.openai.parser.responses_parser import (
- get_responses_parser_for_simple_context,
-)
from vllm.entrypoints.openai.responses.protocol import (
ResponseInputOutputItem,
ResponseRawMessageAndToken,
ResponsesRequest,
)
-from vllm.entrypoints.openai.responses.utils import construct_tool_dicts
+from vllm.entrypoints.openai.responses.utils import (
+ build_response_output_items,
+ construct_tool_dicts,
+)
from vllm.entrypoints.serve.utils.constants import MCP_PREFIX
from vllm.outputs import RequestOutput
from vllm.parser.abstract_parser import Parser
@@ -286,16 +290,24 @@ class ParsableContext(ConversationContext):
# not implemented yet for ParsableContext
self.all_turn_metrics: list[TurnMetrics] = []
- self.parser = get_responses_parser_for_simple_context(
- tokenizer=tokenizer,
- parser_cls=parser_cls,
- response_messages=response_messages,
- request=request,
- chat_template=chat_template,
- chat_template_content_format=chat_template_content_format,
- enable_auto_tools=enable_auto_tools,
- tool_call_id_type=tool_call_id_type,
- )
+ self.response_messages: list[ResponseInputOutputItem] = response_messages
+ self.num_init_messages = len(response_messages)
+ self.finish_reason: str | None = None
+ self.enable_auto_tools = enable_auto_tools
+ self.tool_call_id_type = tool_call_id_type
+
+ self.parser_instance: Parser | None = None
+ if parser_cls is not None:
+ chat_template_kwargs = request.build_chat_params(
+ default_template=chat_template,
+ default_template_content_format=chat_template_content_format,
+ ).chat_template_kwargs
+ self.parser_instance = parser_cls(
+ tokenizer,
+ tools=request.tools,
+ chat_template_kwargs=chat_template_kwargs,
+ )
+
self.parser_cls = parser_cls
self.request = request
@@ -318,11 +330,44 @@ class ParsableContext(ConversationContext):
self.num_output_tokens += len(output.outputs[0].token_ids or [])
if output.kv_transfer_params is not None:
self.kv_transfer_params = output.kv_transfer_params
- self.parser.process(output.outputs[0])
- output_token_ids = output.outputs[0].token_ids or []
- self._accumulated_token_ids.extend(output_token_ids)
- # only store if enable_response_messages is True, save memory
+ completion = output.outputs[0]
+ self.finish_reason = completion.finish_reason
+
+ if self.parser_instance is not None:
+ reasoning, content, tool_calls = self.parser_instance.parse(
+ completion.text,
+ self.request,
+ enable_auto_tools=self.enable_auto_tools,
+ )
+ self.response_messages.extend(
+ build_response_output_items(
+ reasoning=reasoning,
+ content=content,
+ tool_calls=tool_calls,
+ tool_call_id_type=self.tool_call_id_type,
+ )
+ )
+ elif completion.text:
+ self.response_messages.append(
+ ResponseOutputMessage(
+ type="message",
+ id=f"msg_{random_uuid()}",
+ status="completed",
+ role="assistant",
+ content=[
+ ResponseOutputText(
+ annotations=[],
+ type="output_text",
+ text=completion.text,
+ logprobs=None,
+ )
+ ],
+ )
+ )
+
+ self._accumulated_token_ids.extend(completion.token_ids or [])
+
if self.request.enable_response_messages:
output_prompt = output.prompt or ""
output_prompt_token_ids = output.prompt_token_ids or []
@@ -342,18 +387,18 @@ class ParsableContext(ConversationContext):
)
self.output_messages.append(
ResponseRawMessageAndToken(
- message=output.outputs[0].text,
- tokens=output.outputs[0].token_ids,
+ message=completion.text,
+ tokens=completion.token_ids,
)
)
def append_tool_output(self, output: list[ResponseInputOutputItem]) -> None:
- self.parser.response_messages.extend(output)
+ self.response_messages.extend(output)
def need_builtin_tool_call(self) -> bool:
"""Return true if the last message is a builtin tool call
that the request has enabled."""
- last_message = self.parser.response_messages[-1]
+ last_message = self.response_messages[-1]
if last_message.type != "function_call":
return False
if last_message.name in ("code_interpreter", "python"):
@@ -457,12 +502,12 @@ class ParsableContext(ConversationContext):
return [message]
async def call_tool(self) -> list[ResponseInputOutputItem]:
- if not self.parser.response_messages:
+ if not self.response_messages:
return []
- last_msg = self.parser.response_messages[-1]
+ last_msg = self.response_messages[-1]
# change this to a mcp_ function call
last_msg.id = f"{MCP_PREFIX}{random_uuid()}"
- self.parser.response_messages[-1] = last_msg
+ self.response_messages[-1] = last_msg
if last_msg.name == "code_interpreter":
return await self.call_python_tool(self._tool_sessions["python"], last_msg)
elif last_msg.name == "web_search_preview":
@@ -473,6 +518,29 @@ class ParsableContext(ConversationContext):
)
return []
+ def make_response_output_items(self) -> list[ResponseOutputItem]:
+ response_messages = self.response_messages[self.num_init_messages :]
+ output_messages: list[ResponseOutputItem] = []
+ for message in response_messages:
+ if not isinstance(message, ResponseFunctionToolCallOutputItem):
+ output_messages.append(message)
+ else:
+ if len(output_messages) == 0:
+ raise ValueError(
+ "Cannot have a FunctionToolCallOutput before FunctionToolCall."
+ )
+ if isinstance(output_messages[-1], ResponseFunctionToolCall):
+ output_messages[-1] = McpCall(
+ id=f"{MCP_PREFIX}{random_uuid()}",
+ arguments=output_messages[-1].arguments,
+ name=output_messages[-1].name,
+ server_label=output_messages[-1].name,
+ type="mcp_call",
+ status="completed",
+ output=message.output,
+ )
+ return output_messages
+
def render_for_completion(self):
raise NotImplementedError("Should not be called.")
diff --git a/vllm/entrypoints/openai/responses/serving.py b/vllm/entrypoints/openai/responses/serving.py
index 5b830cf6dc..9d95ccc0cb 100644
--- a/vllm/entrypoints/openai/responses/serving.py
+++ b/vllm/entrypoints/openai/responses/serving.py
@@ -702,7 +702,7 @@ class OpenAIServingResponses(OpenAIServing):
elif isinstance(context, ParsableContext):
(engine_input,) = await self._render_next_turn(
context.request,
- context.parser.response_messages,
+ context.response_messages,
context.tool_dicts,
context.parser_cls,
context.chat_template,
@@ -805,7 +805,7 @@ class OpenAIServingResponses(OpenAIServing):
else:
status = "incomplete"
elif isinstance(context, ParsableContext):
- output = context.parser.make_response_output_items_from_parsable_context()
+ output = context.make_response_output_items()
if request.enable_response_messages:
input_messages = context.input_messages
@@ -816,7 +816,7 @@ class OpenAIServingResponses(OpenAIServing):
num_tool_output_tokens = 0
# Check finish reason from the parser
- if context.parser.finish_reason == "length":
+ if context.finish_reason == "length":
status = "incomplete"
else:
assert isinstance(context, SimpleContext)