[Bugfix][Frontend] Preserve token IDs in completion derender responses (#62114)

Signed-off-by: Yuan Li <dskwelmcy@163.com>
This commit is contained in:
dskwe
2026-10-17 08:27:48 +00:00
committed by GitHub
parent 61bb590877
commit b05ede5616
2 changed files with 50 additions and 0 deletions
@@ -12,8 +12,10 @@ import pytest_asyncio
from tests.utils import RemoteLaunchRenderServer
from vllm.entrypoints.generate.base.protocol import FunctionCall
from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
from vllm.entrypoints.openai.completion.protocol import CompletionRequest
from vllm.entrypoints.scale_out.token_in_token_out.protocol import (
GenerateTokensResponse,
GenerateTokensStreamResponse,
)
from vllm.renderers.online_derenderer import OnlineDerenderer
from vllm.tokenizers import get_tokenizer
@@ -1579,3 +1581,43 @@ def test_derender_chat_keeps_parser_tool_call_id():
(tool_call,) = choice.message.tool_calls
assert tool_call.id == "functions.get_weather:1"
@pytest.mark.asyncio
@pytest.mark.parametrize("return_token_ids", [None, False, True])
@pytest.mark.parametrize("stream", [False, True])
async def test_derender_completion_preserves_requested_token_ids(
tokenizer, return_token_ids, stream
):
renderer = MagicMock()
renderer.get_tokenizer.return_value = tokenizer
renderer._executor = None
model_config = MagicMock()
model_config.model = MODEL_NAME
model_config.hf_config.model_type = "llama"
derenderer = OnlineDerenderer(
model_config,
renderer,
request_logger=None,
chat_template=None,
chat_template_content_format="string",
)
token_ids = tokenizer.encode("Hello world", add_special_tokens=False)
request = CompletionRequest(
model=MODEL_NAME, prompt="Hi", return_token_ids=return_token_ids
)
payload = _make_generate_response(token_ids, finish_reason="length")
if stream:
response, _ = await derenderer.derender_completion_stream(
MODEL_NAME,
GenerateTokensStreamResponse.model_validate(payload),
completion_request=request,
)
choices = response.choices
else:
choices, _, _ = await derenderer.derender_completion(
[GenerateTokensResponse.model_validate(payload)],
completion_request=request,
)
assert choices[0].text == tokenizer.decode(token_ids)
assert choices[0].token_ids == (token_ids if return_token_ids else None)
+8
View File
@@ -834,6 +834,9 @@ class OnlineDerenderer:
total_completion_tokens = 0
index = 0
top_limit = _completion_top_logprobs_limit(completion_request)
return_token_ids = (
completion_request is not None and completion_request.return_token_ids
)
for gen, pt, seed_ids_override in zip(
generate_responses, prompt_tokens_list, prompt_token_ids_list
@@ -877,6 +880,7 @@ class OnlineDerenderer:
finish_reason=choice.finish_reason,
stop_reason=choice.stop_reason,
logprobs=completion_logprobs,
token_ids=choice.token_ids if return_token_ids else None,
)
)
total_completion_tokens += len(choice.token_ids)
@@ -942,6 +946,9 @@ class OnlineDerenderer:
updated_state = state
top_limit = _completion_top_logprobs_limit(completion_request)
return_token_ids = (
completion_request is not None and completion_request.return_token_ids
)
for choice in generate_chunk.choices:
delta_tids = choice.token_ids or []
new_text, updated_state = await self._detokenize_delta_async(
@@ -982,6 +989,7 @@ class OnlineDerenderer:
logprobs=completion_logprobs,
finish_reason=choice.finish_reason,
stop_reason=choice.stop_reason,
token_ids=choice.token_ids if return_token_ids else None,
)
)