@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / d9ab1ad9d1
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, 14:30 UTC

`reasoning_content` -> `reasoning` (#27752)

Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com>

Harry Mellor committed Nov 8, 2025 at 04:15 UTC d9ab1ad9d1be96885f4387a33a3a82233c009ce9
46 files changed +428 -438
docs/features/reasoning_outputs.md
+24 -21
@@ -2,7 +2,10 @@
2
3 vLLM offers support for reasoning models like [DeepSeek R1](https://huggingface.co/deepseek-ai/DeepSeek-R1), which are designed to generate outputs containing both reasoning steps and final conclusions.
4
5 -Reasoning models return an additional `reasoning_content` field in their outputs, which contains the reasoning steps that led to the final conclusion. This field is not present in the outputs of other models.
5 +Reasoning models return an additional `reasoning` field in their outputs, which contains the reasoning steps that led to the final conclusion. This field is not present in the outputs of other models.
6 +
7 +!!! warning
8 + `reasoning` used to be called `reasoning_content`. For now, `reasoning_content` will continue to work. However, we encourage you to migrate to `reasoning` in case `reasoning_content` is removed in future.
9
10 ## Supported Models
11
@@ -61,18 +64,18 @@ Next, make a request to the model that should return the reasoning content in th
64 # extra_body={"chat_template_kwargs": {"enable_thinking": False}}
65 response = client.chat.completions.create(model=model, messages=messages)
66
64 - reasoning_content = response.choices[0].message.reasoning_content
67 + reasoning = response.choices[0].message.reasoning
68 content = response.choices[0].message.content
69
67 - print("reasoning_content:", reasoning_content)
70 + print("reasoning:", reasoning)
71 print("content:", content)
72 ```
73
71 -The `reasoning_content` field contains the reasoning steps that led to the final conclusion, while the `content` field contains the final conclusion.
74 +The `reasoning` field contains the reasoning steps that led to the final conclusion, while the `content` field contains the final conclusion.
75
76 ## Streaming chat completions
77
75 -Streaming chat completions are also supported for reasoning models. The `reasoning_content` field is available in the `delta` field in [chat completion response chunks](https://platform.openai.com/docs/api-reference/chat/streaming).
78 +Streaming chat completions are also supported for reasoning models. The `reasoning` field is available in the `delta` field in [chat completion response chunks](https://platform.openai.com/docs/api-reference/chat/streaming).
79
80 ??? console "Json"
81
@@ -88,7 +91,7 @@ Streaming chat completions are also supported for reasoning models. The `reasoni
91 "index": 0,
92 "delta": {
93 "role": "assistant",
91 - "reasoning_content": "is",
94 + "reasoning": "is",
95 },
96 "logprobs": null,
97 "finish_reason": null
@@ -97,7 +100,7 @@ Streaming chat completions are also supported for reasoning models. The `reasoni
100 }
101 ```
102
100 -OpenAI Python client library does not officially support `reasoning_content` attribute for streaming output. But the client supports extra attributes in the response. You can use `hasattr` to check if the `reasoning_content` attribute is present in the response. For example:
103 +OpenAI Python client library does not officially support `reasoning` attribute for streaming output. But the client supports extra attributes in the response. You can use `hasattr` to check if the `reasoning` attribute is present in the response. For example:
104
105 ??? code
106
@@ -127,22 +130,22 @@ OpenAI Python client library does not officially support `reasoning_content` att
130 )
131
132 print("client: Start streaming chat completions...")
130 - printed_reasoning_content = False
133 + printed_reasoning = False
134 printed_content = False
135
136 for chunk in stream:
134 - # Safely extract reasoning_content and content from delta,
137 + # Safely extract reasoning and content from delta,
138 # defaulting to None if attributes don't exist or are empty strings
136 - reasoning_content = (
137 - getattr(chunk.choices[0].delta, "reasoning_content", None) or None
139 + reasoning = (
140 + getattr(chunk.choices[0].delta, "reasoning", None) or None
141 )
142 content = getattr(chunk.choices[0].delta, "content", None) or None
143
141 - if reasoning_content is not None:
142 - if not printed_reasoning_content:
143 - printed_reasoning_content = True
144 - print("reasoning_content:", end="", flush=True)
145 - print(reasoning_content, end="", flush=True)
144 + if reasoning is not None:
145 + if not printed_reasoning:
146 + printed_reasoning = True
147 + print("reasoning:", end="", flush=True)
148 + print(reasoning, end="", flush=True)
149 elif content is not None:
150 if not printed_content:
151 printed_content = True
@@ -151,11 +154,11 @@ OpenAI Python client library does not officially support `reasoning_content` att
154 print(content, end="", flush=True)
155 ```
156
154 -Remember to check whether the `reasoning_content` exists in the response before accessing it. You could check out the [example](https://github.com/vllm-project/vllm/blob/main/examples/online_serving/openai_chat_completion_with_reasoning_streaming.py).
157 +Remember to check whether the `reasoning` exists in the response before accessing it. You could check out the [example](https://github.com/vllm-project/vllm/blob/main/examples/online_serving/openai_chat_completion_with_reasoning_streaming.py).
158
159 ## Tool Calling
160
158 -The reasoning content is also available when both tool calling and the reasoning parser are enabled. Additionally, tool calling only parses functions from the `content` field, not from the `reasoning_content`.
161 +The reasoning content is also available when both tool calling and the reasoning parser are enabled. Additionally, tool calling only parses functions from the `content` field, not from the `reasoning`.
162
163 ??? code
164
@@ -192,7 +195,7 @@ The reasoning content is also available when both tool calling and the reasoning
195 print(response)
196 tool_call = response.choices[0].message.tool_calls[0].function
197
195 - print(f"reasoning_content: {response.choices[0].message.reasoning_content}")
198 + print(f"reasoning: {response.choices[0].message.reasoning}")
199 print(f"Function called: {tool_call.name}")
200 print(f"Arguments: {tool_call.arguments}")
201 ```
@@ -223,7 +226,7 @@ You can add a new `ReasoningParser` similar to [vllm/reasoning/deepseek_r1_reaso
226 def __init__(self, tokenizer: AnyTokenizer):
227 super().__init__(tokenizer)
228
226 - def extract_reasoning_content_streaming(
229 + def extract_reasoning_streaming(
230 self,
231 previous_text: str,
232 current_text: str,
@@ -240,7 +243,7 @@ You can add a new `ReasoningParser` similar to [vllm/reasoning/deepseek_r1_reaso
243 previously been parsed and extracted (see constructor)
244 """
245
243 - def extract_reasoning_content(
246 + def extract_reasoning(
247 self,
248 model_output: str,
249 request: ChatCompletionRequest | ResponsesRequest,
docs/features/structured_outputs.md
+1 -1
@@ -204,7 +204,7 @@ Note that you can use reasoning with any provided structured outputs feature. Th
204 }
205 },
206 )
207 - print("reasoning_content: ", completion.choices[0].message.reasoning_content)
207 + print("reasoning: ", completion.choices[0].message.reasoning)
208 print("content: ", completion.choices[0].message.content)
209 ```
210
examples/online_serving/openai_chat_completion_tool_calls_with_reasoning.py
+11 -11
@@ -2,7 +2,7 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """
4 An example demonstrates how to use tool calling with reasoning models
5 -like QwQ-32B. The reasoning_content will not be parsed by the tool
5 +like QwQ-32B. The reasoning will not be parsed by the tool
6 calling process; only the final output will be parsed.
7
8 To run this example, you need to start the vLLM server with both
@@ -78,7 +78,7 @@ messages = [
78
79
80 def extract_reasoning_and_calls(chunks: list):
81 - reasoning_content = ""
81 + reasoning = ""
82 tool_call_idx = -1
83 arguments = []
84 function_names = []
@@ -97,9 +97,9 @@ def extract_reasoning_and_calls(chunks: list):
97 if tool_call.function.arguments:
98 arguments[tool_call_idx] += tool_call.function.arguments
99 else:
100 - if hasattr(chunk.choices[0].delta, "reasoning_content"):
101 - reasoning_content += chunk.choices[0].delta.reasoning_content
102 - return reasoning_content, arguments, function_names
100 + if hasattr(chunk.choices[0].delta, "reasoning"):
101 + reasoning += chunk.choices[0].delta.reasoning
102 + return reasoning, arguments, function_names
103
104
105 def main():
@@ -115,7 +115,7 @@ def main():
115 tool_calls = client.chat.completions.create(
116 messages=messages, model=model, tools=tools
117 )
118 - print(f"reasoning_content: {tool_calls.choices[0].message.reasoning_content}")
118 + print(f"reasoning: {tool_calls.choices[0].message.reasoning}")
119 print(f"function name: {tool_calls.choices[0].message.tool_calls[0].function.name}")
120 print(
121 f"function arguments: "
@@ -129,9 +129,9 @@ def main():
129
130 chunks = list(tool_calls_stream)
131
132 - reasoning_content, arguments, function_names = extract_reasoning_and_calls(chunks)
132 + reasoning, arguments, function_names = extract_reasoning_and_calls(chunks)
133
134 - print(f"reasoning_content: {reasoning_content}")
134 + print(f"reasoning: {reasoning}")
135 print(f"function name: {function_names[0]}")
136 print(f"function arguments: {arguments[0]}")
137
@@ -144,7 +144,7 @@ def main():
144 )
145
146 tool_call = tool_calls.choices[0].message.tool_calls[0].function
147 - print(f"reasoning_content: {tool_calls.choices[0].message.reasoning_content}")
147 + print(f"reasoning: {tool_calls.choices[0].message.reasoning}")
148 print(f"function name: {tool_call.name}")
149 print(f"function arguments: {tool_call.arguments}")
150 print("----------Stream Generate With Named Function Calling--------------")
@@ -159,8 +159,8 @@ def main():
159
160 chunks = list(tool_calls_stream)
161
162 - reasoning_content, arguments, function_names = extract_reasoning_and_calls(chunks)
163 - print(f"reasoning_content: {reasoning_content}")
162 + reasoning, arguments, function_names = extract_reasoning_and_calls(chunks)
163 + print(f"reasoning: {reasoning}")
164 print(f"function name: {function_names[0]}")
165 print(f"function arguments: {arguments[0]}")
166 print("\n\n")
examples/online_serving/openai_chat_completion_with_reasoning.py
+4 -4
@@ -38,10 +38,10 @@ def main():
38 # For granite, add: `extra_body={"chat_template_kwargs": {"thinking": True}}`
39 response = client.chat.completions.create(model=model, messages=messages)
40
41 - reasoning_content = response.choices[0].message.reasoning_content
41 + reasoning = response.choices[0].message.reasoning
42 content = response.choices[0].message.content
43
44 - print("reasoning_content for Round 1:", reasoning_content)
44 + print("reasoning for Round 1:", reasoning)
45 print("content for Round 1:", content)
46
47 # Round 2
@@ -54,10 +54,10 @@ def main():
54 )
55 response = client.chat.completions.create(model=model, messages=messages)
56
57 - reasoning_content = response.choices[0].message.reasoning_content
57 + reasoning = response.choices[0].message.reasoning
58 content = response.choices[0].message.content
59
60 - print("reasoning_content for Round 2:", reasoning_content)
60 + print("reasoning for Round 2:", reasoning)
61 print("content for Round 2:", content)
62
63
examples/online_serving/openai_chat_completion_with_reasoning_streaming.py
+9 -11
@@ -20,7 +20,7 @@ in real-time as they are generated by the model. This is useful for scenarios
20 where you want to display chat completions to the user as they are generated
21 by the model.
22
23 -Remember to check content and reasoning_content exist in `ChatCompletionChunk`,
23 +Remember to check content and reasoning exist in `ChatCompletionChunk`,
24 content may not exist leading to errors if you try to access it.
25 """
26
@@ -47,22 +47,20 @@ def main():
47 stream = client.chat.completions.create(model=model, messages=messages, stream=True)
48
49 print("client: Start streaming chat completions...")
50 - printed_reasoning_content = False
50 + printed_reasoning = False
51 printed_content = False
52
53 for chunk in stream:
54 - # Safely extract reasoning_content and content from delta,
54 + # Safely extract reasoning and content from delta,
55 # defaulting to None if attributes don't exist or are empty strings
56 - reasoning_content = (
57 - getattr(chunk.choices[0].delta, "reasoning_content", None) or None
58 - )
56 + reasoning = getattr(chunk.choices[0].delta, "reasoning", None) or None
57 content = getattr(chunk.choices[0].delta, "content", None) or None
58
61 - if reasoning_content is not None:
62 - if not printed_reasoning_content:
63 - printed_reasoning_content = True
64 - print("reasoning_content:", end="", flush=True)
65 - print(reasoning_content, end="", flush=True)
59 + if reasoning is not None:
60 + if not printed_reasoning:
61 + printed_reasoning = True
62 + print("reasoning:", end="", flush=True)
63 + print(reasoning, end="", flush=True)
64 elif content is not None:
65 if not printed_content:
66 printed_content = True
examples/online_serving/streamlit_openai_chatbot_webserver.py
+4 -4
@@ -159,8 +159,8 @@ def get_llm_response(messages, model, reason, content_ph=None, reasoning_ph=None
159 for chunk in response:
160 delta = chunk.choices[0].delta
161 # Stream reasoning first
162 - if reason and hasattr(delta, "reasoning_content") and live_think:
163 - rc = delta.reasoning_content
162 + if reason and hasattr(delta, "reasoning") and live_think:
163 + rc = delta.reasoning
164 if rc:
165 think_text += rc
166 live_think.markdown(think_text + "▌")
@@ -262,8 +262,8 @@ def server_supports_reasoning():
262 messages=[{"role": "user", "content": "Hi"}],
263 stream=False,
264 )
265 - return hasattr(resp.choices[0].message, "reasoning_content") and bool(
266 - resp.choices[0].message.reasoning_content
265 + return hasattr(resp.choices[0].message, "reasoning") and bool(
266 + resp.choices[0].message.reasoning
267 )
268
269
examples/online_serving/structured_outputs/structured_outputs.py
+3 -3
@@ -33,7 +33,7 @@ async def print_stream_response(
33 async for chunk in stream_response:
34 delta = chunk.choices[0].delta
35
36 - reasoning_chunk_text: str | None = getattr(delta, "reasoning_content", None)
36 + reasoning_chunk_text: str | None = getattr(delta, "reasoning", None)
37 content_chunk_text = delta.content
38
39 if args.reasoning:
@@ -255,8 +255,8 @@ async def cli():
255 for constraint, response in zip(constraints, results):
256 print(f"\n\n{constraint}:")
257 message = response.choices[0].message
258 - if args.reasoning and hasattr(message, "reasoning_content"):
259 - print(f" Reasoning: {message.reasoning_content or ''}")
258 + if args.reasoning and hasattr(message, "reasoning"):
259 + print(f" Reasoning: {message.reasoning or ''}")
260 print(f" Content: {message.content!r}")
261
262
tests/entrypoints/openai/test_chat_with_tool_reasoning.py
+7 -7
@@ -80,7 +80,7 @@ FUNC_ARGS = """{"city": "Dallas", "state": "TX", "unit": "fahrenheit"}"""
80
81
82 def extract_reasoning_and_calls(chunks: list):
83 - reasoning_content = ""
83 + reasoning = ""
84 tool_call_idx = -1
85 arguments = []
86 function_names = []
@@ -99,9 +99,9 @@ def extract_reasoning_and_calls(chunks: list):
99 if tool_call.function.arguments:
100 arguments[tool_call_idx] += tool_call.function.arguments
101 else:
102 - if hasattr(chunk.choices[0].delta, "reasoning_content"):
103 - reasoning_content += chunk.choices[0].delta.reasoning_content
104 - return reasoning_content, arguments, function_names
102 + if hasattr(chunk.choices[0].delta, "reasoning"):
103 + reasoning += chunk.choices[0].delta.reasoning
104 + return reasoning, arguments, function_names
105
106
107 # test streaming
@@ -119,8 +119,8 @@ async def test_chat_streaming_of_tool_and_reasoning(client: openai.AsyncOpenAI):
119 async for chunk in stream:
120 chunks.append(chunk)
121
122 - reasoning_content, arguments, function_names = extract_reasoning_and_calls(chunks)
123 - assert len(reasoning_content) > 0
122 + reasoning, arguments, function_names = extract_reasoning_and_calls(chunks)
123 + assert len(reasoning) > 0
124 assert len(function_names) > 0 and function_names[0] == FUNC_NAME
125 assert len(arguments) > 0 and arguments[0] == FUNC_ARGS
126
@@ -136,6 +136,6 @@ async def test_chat_full_of_tool_and_reasoning(client: openai.AsyncOpenAI):
136 stream=False,
137 )
138
139 - assert len(tool_calls.choices[0].message.reasoning_content) > 0
139 + assert len(tool_calls.choices[0].message.reasoning) > 0
140 assert tool_calls.choices[0].message.tool_calls[0].function.name == FUNC_NAME
141 assert tool_calls.choices[0].message.tool_calls[0].function.arguments == FUNC_ARGS
tests/entrypoints/openai/test_completion_with_function_calling.py
+4 -4
@@ -180,8 +180,8 @@ async def test_function_tool_use(
180 extra_body={"chat_template_kwargs": {"enable_thinking": enable_thinking}},
181 )
182 if enable_thinking:
183 - assert chat_completion.choices[0].message.reasoning_content is not None
184 - assert chat_completion.choices[0].message.reasoning_content != ""
183 + assert chat_completion.choices[0].message.reasoning is not None
184 + assert chat_completion.choices[0].message.reasoning != ""
185 assert chat_completion.choices[0].message.tool_calls is not None
186 assert len(chat_completion.choices[0].message.tool_calls) > 0
187 else:
@@ -200,9 +200,9 @@ async def test_function_tool_use(
200 async for chunk in output_stream:
201 if chunk.choices:
202 if enable_thinking and getattr(
203 - chunk.choices[0].delta, "reasoning_content", None
203 + chunk.choices[0].delta, "reasoning", None
204 ):
205 - reasoning.append(chunk.choices[0].delta.reasoning_content)
205 + reasoning.append(chunk.choices[0].delta.reasoning)
206 if chunk.choices[0].delta.tool_calls:
207 output.extend(chunk.choices[0].delta.tool_calls)
208
tests/entrypoints/openai/test_run_batch.py
+5 -5
@@ -232,9 +232,9 @@ def test_reasoning_parser():
232 assert isinstance(line_dict, dict)
233 assert line_dict["error"] is None
234
235 - # Check that reasoning_content is present and not empty
236 - reasoning_content = line_dict["response"]["body"]["choices"][0]["message"][
237 - "reasoning_content"
235 + # Check that reasoning is present and not empty
236 + reasoning = line_dict["response"]["body"]["choices"][0]["message"][
237 + "reasoning"
238 ]
239 - assert reasoning_content is not None
240 - assert len(reasoning_content) > 0
239 + assert reasoning is not None
240 + assert len(reasoning) > 0
tests/reasoning/test_base_thinking_reasoning_parser.py
+10 -10
@@ -151,57 +151,57 @@ class TestBaseThinkingReasoningParserMethods:
151 class TestBaseThinkingReasoningParserExtraction:
152 """Test reasoning content extraction methods."""
153
154 - def test_extract_reasoning_content_with_both_tokens(self, test_tokenizer):
154 + def test_extract_reasoning_with_both_tokens(self, test_tokenizer):
155 """Test extraction when both start and end tokens are present."""
156 parser = TestThinkingReasoningParser(test_tokenizer)
157 request = ChatCompletionRequest(messages=[], model="test-model")
158
159 model_output = "<test:think>This is reasoning</test:think>This is content"
160 - reasoning, content = parser.extract_reasoning_content(model_output, request)
160 + reasoning, content = parser.extract_reasoning(model_output, request)
161
162 assert reasoning == "This is reasoning"
163 assert content == "This is content"
164
165 - def test_extract_reasoning_content_only_end_token(self, test_tokenizer):
165 + def test_extract_reasoning_only_end_token(self, test_tokenizer):
166 """Test extraction when only end token is present."""
167 parser = TestThinkingReasoningParser(test_tokenizer)
168 request = ChatCompletionRequest(messages=[], model="test-model")
169
170 model_output = "This is reasoning</test:think>This is content"
171 - reasoning, content = parser.extract_reasoning_content(model_output, request)
171 + reasoning, content = parser.extract_reasoning(model_output, request)
172
173 assert reasoning == "This is reasoning"
174 assert content == "This is content"
175
176 - def test_extract_reasoning_content_no_end_token(self, test_tokenizer):
176 + def test_extract_reasoning_no_end_token(self, test_tokenizer):
177 """Test extraction when no end token is present."""
178 parser = TestThinkingReasoningParser(test_tokenizer)
179 request = ChatCompletionRequest(messages=[], model="test-model")
180
181 model_output = "This is just content"
182 - reasoning, content = parser.extract_reasoning_content(model_output, request)
182 + reasoning, content = parser.extract_reasoning(model_output, request)
183
184 assert reasoning == "This is just content"
185 assert content is None
186
187 - def test_extract_reasoning_content_empty_output(self, test_tokenizer):
187 + def test_extract_reasoning_empty_output(self, test_tokenizer):
188 """Test extraction with empty output."""
189 parser = TestThinkingReasoningParser(test_tokenizer)
190 request = ChatCompletionRequest(messages=[], model="test-model")
191
192 model_output = ""
193 - reasoning, content = parser.extract_reasoning_content(model_output, request)
193 + reasoning, content = parser.extract_reasoning(model_output, request)
194
195 assert reasoning == ""
196 assert content is None
197
198 - def test_extract_reasoning_content_only_tokens(self, test_tokenizer):
198 + def test_extract_reasoning_only_tokens(self, test_tokenizer):
199 """Test extraction with only tokens and no content."""
200 parser = TestThinkingReasoningParser(test_tokenizer)
201 request = ChatCompletionRequest(messages=[], model="test-model")
202
203 model_output = "<test:think></test:think>"
204 - reasoning, content = parser.extract_reasoning_content(model_output, request)
204 + reasoning, content = parser.extract_reasoning(model_output, request)
205
206 assert reasoning == ""
207 assert content is None
tests/reasoning/test_deepseekr1_reasoning_parser.py
+18 -18
@@ -21,97 +21,97 @@ def deepseek_r1_qwen_tokenizer():
21
22 SIMPLE_REASONING = {
23 "output": "This is a reasoning section</think>This is the rest",
24 - "reasoning_content": "This is a reasoning section",
24 + "reasoning": "This is a reasoning section",
25 "content": "This is the rest",
26 "is_reasoning_end": True,
27 }
28 COMPLETE_REASONING = {
29 "output": "This is a reasoning section</think>",
30 - "reasoning_content": "This is a reasoning section",
30 + "reasoning": "This is a reasoning section",
31 "content": None,
32 "is_reasoning_end": True,
33 }
34 NO_CONTENT = {
35 "output": "This is content",
36 - "reasoning_content": "This is content",
36 + "reasoning": "This is content",
37 "content": None,
38 "is_reasoning_end": False,
39 }
40 NO_REASONING_STREAMING = {
41 "output": "This is a reasoning section",
42 - "reasoning_content": "This is a reasoning section",
42 + "reasoning": "This is a reasoning section",
43 "content": None,
44 "is_reasoning_end": False,
45 }
46 MULTIPLE_LINES = {
47 "output": "This\nThat</think>This is the rest\nThat",
48 - "reasoning_content": "This\nThat",
48 + "reasoning": "This\nThat",
49 "content": "This is the rest\nThat",
50 "is_reasoning_end": True,
51 }
52 SHORTEST_REASONING_NO_STREAMING = {
53 "output": "</think>This is the rest",
54 - "reasoning_content": "",
54 + "reasoning": "",
55 "content": "This is the rest",
56 "is_reasoning_end": True,
57 }
58 SHORTEST_REASONING = {
59 "output": "</think>This is the rest",
60 - "reasoning_content": None,
60 + "reasoning": None,
61 "content": "This is the rest",
62 "is_reasoning_end": True,
63 }
64 REASONING_WITH_THINK = {
65 "output": "<think>This is a reasoning section</think>This is the rest",
66 - "reasoning_content": "This is a reasoning section",
66 + "reasoning": "This is a reasoning section",
67 "content": "This is the rest",
68 "is_reasoning_end": True,
69 }
70 COMPLETE_REASONING_WITH_THINK = {
71 "output": "<think>This is a reasoning section</think>",
72 - "reasoning_content": "This is a reasoning section",
72 + "reasoning": "This is a reasoning section",
73 "content": None,
74 "is_reasoning_end": True,
75 }
76 MULTIPLE_LINES_WITH_THINK = {
77 "output": "<think>This\nThat</think>This is the rest\nThat",
78 - "reasoning_content": "This\nThat",
78 + "reasoning": "This\nThat",
79 "content": "This is the rest\nThat",
80 "is_reasoning_end": True,
81 }
82 SHORTEST_REASONING_NO_STREAMING_WITH_THINK = {
83 "output": "</think>This is the rest",
84 - "reasoning_content": "",
84 + "reasoning": "",
85 "content": "This is the rest",
86 "is_reasoning_end": True,
87 }
88 SHORTEST_REASONING_WITH_THINK = {
89 "output": "</think>This is the rest",
90 - "reasoning_content": None,
90 + "reasoning": None,
91 "content": "This is the rest",
92 "is_reasoning_end": True,
93 }
94 THINK_NO_END = {
95 "output": "<think>This is a reasoning section",
96 - "reasoning_content": "This is a reasoning section",
96 + "reasoning": "This is a reasoning section",
97 "content": None,
98 "is_reasoning_end": False,
99 }
100 EMPTY = {
101 "output": "",
102 - "reasoning_content": "",
102 + "reasoning": "",
103 "content": None,
104 "is_reasoning_end": False,
105 }
106 EMPTY_STREAMING = {
107 "output": "",
108 - "reasoning_content": None,
108 + "reasoning": None,
109 "content": None,
110 "is_reasoning_end": False,
111 }
112 NEW_LINE = {
113 "output": "\n<think>This is a reasoning section</think>\nThis is the rest",
114 - "reasoning_content": "This is a reasoning section",
114 + "reasoning": "This is a reasoning section",
115 "content": "\nThis is the rest",
116 "is_reasoning_end": True,
117 }
@@ -121,7 +121,7 @@ NEW_LINE = {
121 # or not.
122 NEW_LINE_STREAMING = {
123 "output": "\n<think>This is a reasoning section</think>\nThis is the rest",
124 - "reasoning_content": "\nThis is a reasoning section",
124 + "reasoning": "\nThis is a reasoning section",
125 "content": "\nThis is the rest",
126 "is_reasoning_end": True,
127 }
@@ -269,7 +269,7 @@ def test_reasoning(
269 parser, output_tokens, streaming=streaming
270 )
271
272 - assert reasoning == param_dict["reasoning_content"]
272 + assert reasoning == param_dict["reasoning"]
273 assert content == param_dict["content"]
274
275 # Test is_reasoning_end
tests/reasoning/test_deepseekv3_reasoning_parser.py
+5 -5
@@ -44,14 +44,14 @@ def test_identity_reasoning_parser_basic(tokenizer):
44 # Test extract_content_ids returns all input_ids
45 assert parser.extract_content_ids(input_ids) == input_ids
46
47 - # Test extract_reasoning_content returns (None, model_output)
47 + # Test extract_reasoning returns (None, model_output)
48 request = ChatCompletionRequest(model="test-model", messages=[], temperature=1.0)
49 - reasoning, content = parser.extract_reasoning_content(input_text, request)
49 + reasoning, content = parser.extract_reasoning(input_text, request)
50 assert reasoning is None
51 assert content == input_text
52
53 - # Test extract_reasoning_content_streaming returns DeltaMessage or None
54 - result = parser.extract_reasoning_content_streaming(
53 + # Test extract_reasoning_streaming returns DeltaMessage or None
54 + result = parser.extract_reasoning_streaming(
55 previous_text="",
56 current_text="Hello world",
57 delta_text="Hello world",
@@ -63,7 +63,7 @@ def test_identity_reasoning_parser_basic(tokenizer):
63 assert result.content == "Hello world"
64
65 # If delta_text is empty, should return None
66 - result_none = parser.extract_reasoning_content_streaming(
66 + result_none = parser.extract_reasoning_streaming(
67 previous_text="Hello world",
68 current_text="Hello world",
69 delta_text="",
tests/reasoning/test_ernie45_reasoning_parser.py
+9 -9
@@ -20,36 +20,36 @@ def ernie45_tokenizer():
20 # 带 </think>,非stream
21 WITH_THINK = {
22 "output": "abc</think>def",
23 - "reasoning_content": "abc",
23 + "reasoning": "abc",
24 "content": "def",
25 }
26 # 带 </think>,stream
27 WITH_THINK_STREAM = {
28 "output": "abc</think>def",
29 - "reasoning_content": "abc",
29 + "reasoning": "abc",
30 "content": "def",
31 }
32 -# without </think>, all is reasoning_content
32 +# without </think>, all is reasoning
33 WITHOUT_THINK = {
34 "output": "abc",
35 - "reasoning_content": "abc",
35 + "reasoning": "abc",
36 "content": None,
37 }
38 -# without </think>, all is reasoning_content
38 +# without </think>, all is reasoning
39 WITHOUT_THINK_STREAM = {
40 "output": "abc",
41 - "reasoning_content": "abc",
41 + "reasoning": "abc",
42 "content": None,
43 }
44
45 COMPLETE_REASONING = {
46 "output": "abc</think>",
47 - "reasoning_content": "abc",
47 + "reasoning": "abc",
48 "content": None,
49 }
50 MULTILINE_REASONING = {
51 "output": "abc\nABC</think>def\nDEF",
52 - "reasoning_content": "abc\nABC",
52 + "reasoning": "abc\nABC",
53 "content": "def\nDEF",
54 }
55
@@ -120,5 +120,5 @@ def test_reasoning(
120
121 print()
122
123 - assert reasoning == param_dict["reasoning_content"]
123 + assert reasoning == param_dict["reasoning"]
124 assert content == param_dict["content"]
tests/reasoning/test_glm4_moe_reasoning_parser.py
+9 -9
@@ -21,54 +21,54 @@ def glm45_tokenizer():
21
22 WITH_THINK = {
23 "output": "<think>This is a reasoning section</think>This is the rest",
24 - "reasoning_content": "This is a reasoning section",
24 + "reasoning": "This is a reasoning section",
25 "content": "This is the rest",
26 "is_reasoning_end": True,
27 }
28
29 WITH_THINK_STREAM = {
30 "output": "<think>This is a reasoning section</think>This is the rest",
31 - "reasoning_content": "This is a reasoning section",
31 + "reasoning": "This is a reasoning section",
32 "content": "This is the rest",
33 "is_reasoning_end": True,
34 }
35
36 WITHOUT_THINK = {
37 "output": "This is the rest",
38 - "reasoning_content": None,
38 + "reasoning": None,
39 "content": "This is the rest",
40 "is_reasoning_end": False,
41 }
42
43 WITHOUT_THINK_STREAM = {
44 "output": "This is the rest",
45 - "reasoning_content": None,
45 + "reasoning": None,
46 "content": "This is the rest",
47 "is_reasoning_end": False,
48 }
49
50 COMPLETE_REASONING = {
51 "output": "<think>This is a reasoning section</think>",
52 - "reasoning_content": "This is a reasoning section",
52 + "reasoning": "This is a reasoning section",
53 "content": None,
54 "is_reasoning_end": True,
55 }
56 MULTILINE_REASONING = {
57 "output": "<think>This is a reasoning\nsection</think>This is the rest\nThat",
58 - "reasoning_content": "This is a reasoning\nsection",
58 + "reasoning": "This is a reasoning\nsection",
59 "content": "This is the rest\nThat",
60 "is_reasoning_end": True,
61 }
62 ONLY_OPEN_TAG = {
63 "output": "<think>This is a reasoning section",
64 - "reasoning_content": None,
64 + "reasoning": None,
65 "content": "<think>This is a reasoning section",
66 "is_reasoning_end": False,
67 }
68
69 ONLY_OPEN_TAG_STREAM = {
70 "output": "<think>This is a reasoning section",
71 - "reasoning_content": "This is a reasoning section",
71 + "reasoning": "This is a reasoning section",
72 "content": None,
73 "is_reasoning_end": False,
74 }
@@ -184,7 +184,7 @@ def test_reasoning(
184 parser, output_tokens, streaming=streaming
185 )
186
187 - assert reasoning == param_dict["reasoning_content"]
187 + assert reasoning == param_dict["reasoning"]
188 assert content == param_dict["content"]
189
190 output_ids = glm45_tokenizer.convert_tokens_to_ids(output)
tests/reasoning/test_granite_reasoning_parser.py
+24 -24
@@ -12,37 +12,37 @@ START_RESPONSE = "Here is my response:"
12
13 SIMPLE_REASONING = {
14 "output": f"{START_REASONING}This is a reasoning section{START_RESPONSE}This is the rest", # noqa: E501
15 - "reasoning_content": "This is a reasoning section",
15 + "reasoning": "This is a reasoning section",
16 "content": "This is the rest",
17 }
18 COMPLETE_REASONING = {
19 "output": f"{START_REASONING}This is a reasoning section{START_RESPONSE}",
20 - "reasoning_content": "This is a reasoning section",
20 + "reasoning": "This is a reasoning section",
21 "content": None,
22 }
23 NO_REASONING = {
24 "output": "This is content",
25 - "reasoning_content": None,
25 + "reasoning": None,
26 "content": "This is content",
27 }
28 MULTIPLE_LINES = {
29 "output": f"{START_REASONING}This\nThat{START_RESPONSE}This is the rest\nThat",
30 - "reasoning_content": "This\nThat",
30 + "reasoning": "This\nThat",
31 "content": "This is the rest\nThat",
32 }
33 REASONING_WITH_THINK = {
34 "output": f"{START_REASONING}This is a reasoning section{START_RESPONSE}This is the rest", # noqa: E501
35 - "reasoning_content": "This is a reasoning section",
35 + "reasoning": "This is a reasoning section",
36 "content": "This is the rest",
37 }
38 COMPLETE_REASONING_WITH_THINK = {
39 "output": f"{START_REASONING}This is a reasoning section{START_RESPONSE}",
40 - "reasoning_content": "This is a reasoning section",
40 + "reasoning": "This is a reasoning section",
41 "content": None,
42 }
43 MULTIPLE_LINES_WITH_THINK = {
44 "output": f"{START_REASONING}This\nThat{START_RESPONSE}This is the rest\nThat",
45 - "reasoning_content": "This\nThat",
45 + "reasoning": "This\nThat",
46 "content": "This is the rest\nThat",
47 }
48
@@ -141,7 +141,7 @@ def test_reasoning(
141 parser, output_tokens, streaming=streaming
142 )
143
144 - assert reasoning == param_dict["reasoning_content"]
144 + assert reasoning == param_dict["reasoning"]
145 assert content == param_dict["content"]
146
147
@@ -155,7 +155,7 @@ STREAMING_1 = {
155 "previous_text": None,
156 "current_text": "Here",
157 "delta_text": "Here",
158 - "reasoning_content": None,
158 + "reasoning": None,
159 "content": None,
160 }
161 # When we fail, we should give what was previously being silenced first
@@ -163,7 +163,7 @@ STREAMING_2 = {
163 "previous_text": "Here is my thought",
164 "current_text": "Here is my thought failure",
165 "delta_text": " failure",
166 - "reasoning_content": None,
166 + "reasoning": None,
167 "content": "Here is my thought failure",
168 }
169 # But then after the first one, we should only add the delta text to content
@@ -171,7 +171,7 @@ STREAMING_3 = {
171 "previous_text": "Here wrong",
172 "current_text": " words",
173 "delta_text": " Here wrong words",
174 - "reasoning_content": None,
174 + "reasoning": None,
175 "content": " words",
176 }
177 # But then after the first one, we should only add the delta text to content
@@ -179,7 +179,7 @@ STREAMING_4 = {
179 "previous_text": "Here is my thought",
180 "current_text": "Here is my thought process:",
181 "delta_text": " process:",
182 - "reasoning_content": None,
182 + "reasoning": None,
183 "content": None,
184 }
185 # Reasoning started successfully; parse reasoning content
@@ -187,7 +187,7 @@ STREAMING_5 = {
187 "previous_text": "Here is my thought process:",
188 "current_text": "Here is my thought process: foo",
189 "delta_text": " foo",
190 - "reasoning_content": " foo",
190 + "reasoning": " foo",
191 "content": None,
192 }
193 # Response special sequence has started, but not finished.
@@ -195,7 +195,7 @@ STREAMING_6 = {
195 "previous_text": "Here is my thought process: foo",
196 "current_text": "Here is my thought process: foo Here is",
197 "delta_text": " Here is",
198 - "reasoning_content": " ",
198 + "reasoning": " ",
199 "content": None,
200 }
201 # Response special sequence started, but was broken; the reasoning
@@ -204,7 +204,7 @@ STREAMING_7 = {
204 "previous_text": "Here is my thought process: foo Here is",
205 "current_text": "Here is my thought process: foo Here is Here",
206 "delta_text": " Here",
207 - "reasoning_content": "Here is ",
207 + "reasoning": "Here is ",
208 "content": None,
209 }
210 # Response special sequence is ongoing
@@ -212,7 +212,7 @@ STREAMING_8 = {
212 "previous_text": "Here is my thought process: foo Here is my response:",
213 "current_text": "Here is my thought process: foo Here is my response: bar",
214 "delta_text": " bar",
215 - "reasoning_content": None,
215 + "reasoning": None,
216 "content": " bar",
217 }
218 # The delta text has everything; we should be able to correctly parse both
@@ -220,7 +220,7 @@ STREAMING_9 = {
220 "previous_text": None,
221 "current_text": "Here is my thought process: foo Here is my response: bar",
222 "delta_text": "Here is my thought process: foo Here is my response: bar",
223 - "reasoning_content": " foo ",
223 + "reasoning": " foo ",
224 "content": " bar",
225 }
226 ## The Response is ongoing, and the delta mixes reasoning content / content
@@ -228,7 +228,7 @@ STREAMING_10 = {
228 "previous_text": "Here is my thought process: foo",
229 "current_text": "Here is my thought process: foo bar Here is my response: baz",
230 "delta_text": " bar Here is my response: baz",
231 - "reasoning_content": " bar ",
231 + "reasoning": " bar ",
232 "content": " baz",
233 }
234 # The delta text starts a new substring that might be a response special seq
@@ -236,7 +236,7 @@ STREAMING_11 = {
236 "previous_text": "Here is my thought process: This is a reasoning section ",
237 "current_text": "Here is my thought process: This is a reasoning section Here",
238 "delta_text": "Here",
239 - "reasoning_content": None,
239 + "reasoning": None,
240 "content": None,
241 }
242 # The delta text is finishing the response special seq
@@ -244,14 +244,14 @@ STREAMING_12 = {
244 "previous_text": "Here is my thought process: foo Here is my response",
245 "current_text": "Here is my thought process: foo Here is my response:",
246 "delta_text": ":",
247 - "reasoning_content": None,
247 + "reasoning": None,
248 "content": None,
249 }
250 STREAMING_13 = {
251 "previous_text": "Here is my thought process: foo Here",
252 "current_text": "Here is my thought process: foo Here was",
253 "delta_text": " was",
254 - "reasoning_content": "Here was",
254 + "reasoning": "Here was",
255 "content": None,
256 }
257
@@ -326,7 +326,7 @@ def test_streaming_subcases(param_dict):
326 tokenizer
327 )
328
329 - response = parser.extract_reasoning_content_streaming(
329 + response = parser.extract_reasoning_streaming(
330 previous_text=param_dict["previous_text"],
331 current_text=param_dict["current_text"],
332 delta_text=param_dict["delta_text"],
@@ -336,9 +336,9 @@ def test_streaming_subcases(param_dict):
336 )
337 # Streaming currently expects at least one of reasoning content / content,
338 # so the response should return None in that case.
339 - if param_dict["reasoning_content"] is None and param_dict["content"] is None:
339 + if param_dict["reasoning"] is None and param_dict["content"] is None:
340 assert response is None
341 else:
342 assert isinstance(response, DeltaMessage)
343 - assert param_dict["reasoning_content"] == response.reasoning_content
343 + assert param_dict["reasoning"] == response.reasoning
344 assert param_dict["content"] == response.content
tests/reasoning/test_hunyuan_reasoning_parser.py
+10 -10
@@ -14,49 +14,49 @@ END_RESPONSE = "\n</answer>"
14
15 NO_REASONING_QUICK_THROUGHT = {
16 "output": f"{START_REASONING}{START_RESPONSE}This is the rest{END_RESPONSE}", # noqa: E501
17 - "reasoning_content": None,
17 + "reasoning": None,
18 "content": "This is the rest",
19 }
20
21 SIMPLE_REASONING = {
22 "output": f"{START_REASONING}This is a reasoning section{START_RESPONSE}This is the rest{END_RESPONSE}", # noqa: E501
23 - "reasoning_content": "This is a reasoning section",
23 + "reasoning": "This is a reasoning section",
24 "content": "This is the rest",
25 }
26 COMPLETE_REASONING = {
27 "output": f"{START_REASONING}This is a reasoning section{START_RESPONSE}",
28 - "reasoning_content": "This is a reasoning section",
28 + "reasoning": "This is a reasoning section",
29 "content": None,
30 }
31
32 COMPLETE_REASONING_WITH_SYMBOL = {
33 "output": f"{START_REASONING}This is a reasoning section!{START_RESPONSE}",
34 - "reasoning_content": "This is a reasoning section!",
34 + "reasoning": "This is a reasoning section!",
35 "content": None,
36 }
37 NO_REASONING = {
38 "output": "This is content",
39 - "reasoning_content": None,
39 + "reasoning": None,
40 "content": "This is content",
41 }
42 MULTIPLE_LINES = {
43 "output": f"{START_REASONING}This\nThat{START_RESPONSE}This is the rest\nThat",
44 - "reasoning_content": "This\nThat",
44 + "reasoning": "This\nThat",
45 "content": "This is the rest\nThat",
46 }
47 REASONING_WITH_THINK = {
48 "output": f"{START_REASONING}This is a reasoning section{START_RESPONSE}This is the rest", # noqa: E501
49 - "reasoning_content": "This is a reasoning section",
49 + "reasoning": "This is a reasoning section",
50 "content": "This is the rest",
51 }
52 COMPLETE_REASONING_WITH_THINK = {
53 "output": f"{START_REASONING}This is a reasoning section{START_RESPONSE}",
54 - "reasoning_content": "This is a reasoning section",
54 + "reasoning": "This is a reasoning section",
55 "content": None,
56 }
57 MULTIPLE_LINES_WITH_THINK = {
58 "output": f"{START_REASONING}This\nThat{START_RESPONSE}This is the rest\nThat",
59 - "reasoning_content": "This\nThat",
59 + "reasoning": "This\nThat",
60 "content": "This is the rest\nThat",
61 }
62
@@ -164,5 +164,5 @@ def test_reasoning(
164 parser, output_tokens, streaming=streaming
165 )
166
167 - assert reasoning == param_dict["reasoning_content"]
167 + assert reasoning == param_dict["reasoning"]
168 assert content == param_dict["content"]
tests/reasoning/test_mistral_reasoning_parser.py
+18 -18
@@ -20,97 +20,97 @@ def mistral_tokenizer():
20
21 SIMPLE_REASONING = {
22 "output": "This is a reasoning section[/THINK]This is the rest",
23 - "reasoning_content": "This is a reasoning section",
23 + "reasoning": "This is a reasoning section",
24 "content": "This is the rest",
25 "is_reasoning_end": True,
26 }
27 COMPLETE_REASONING = {
28 "output": "This is a reasoning section[/THINK]",
29 - "reasoning_content": "This is a reasoning section",
29 + "reasoning": "This is a reasoning section",
30 "content": None,
31 "is_reasoning_end": True,
32 }
33 NO_CONTENT = {
34 "output": "This is content",
35 - "reasoning_content": "This is content",
35 + "reasoning": "This is content",
36 "content": None,
37 "is_reasoning_end": False,
38 }
39 NO_REASONING_STREAMING = {
40 "output": "This is a reasoning section",
41 - "reasoning_content": "This is a reasoning section",
41 + "reasoning": "This is a reasoning section",
42 "content": None,
43 "is_reasoning_end": False,
44 }
45 MULTIPLE_LINES = {
46 "output": "This\nThat[/THINK]This is the rest\nThat",
47 - "reasoning_content": "This\nThat",
47 + "reasoning": "This\nThat",
48 "content": "This is the rest\nThat",
49 "is_reasoning_end": True,
50 }
51 SHORTEST_REASONING_NO_STREAMING = {
52 "output": "[/THINK]This is the rest",
53 - "reasoning_content": "",
53 + "reasoning": "",
54 "content": "This is the rest",
55 "is_reasoning_end": True,
56 }
57 SHORTEST_REASONING = {
58 "output": "[/THINK]This is the rest",
59 - "reasoning_content": None,
59 + "reasoning": None,
60 "content": "This is the rest",
61 "is_reasoning_end": True,
62 }
63 REASONING_WITH_THINK = {
64 "output": "[THINK]This is a reasoning section[/THINK]This is the rest",
65 - "reasoning_content": "This is a reasoning section",
65 + "reasoning": "This is a reasoning section",
66 "content": "This is the rest",
67 "is_reasoning_end": True,
68 }
69 COMPLETE_REASONING_WITH_THINK = {
70 "output": "[THINK]This is a reasoning section[/THINK]",
71 - "reasoning_content": "This is a reasoning section",
71 + "reasoning": "This is a reasoning section",
72 "content": None,
73 "is_reasoning_end": True,
74 }
75 MULTIPLE_LINES_WITH_THINK = {
76 "output": "[THINK]This\nThat[/THINK]This is the rest\nThat",
77 - "reasoning_content": "This\nThat",
77 + "reasoning": "This\nThat",
78 "content": "This is the rest\nThat",
79 "is_reasoning_end": True,
80 }
81 SHORTEST_REASONING_NO_STREAMING_WITH_THINK = {
82 "output": "[/THINK]This is the rest",
83 - "reasoning_content": "",
83 + "reasoning": "",
84 "content": "This is the rest",
85 "is_reasoning_end": True,
86 }
87 SHORTEST_REASONING_WITH_THINK = {
88 "output": "[/THINK]This is the rest",
89 - "reasoning_content": None,
89 + "reasoning": None,
90 "content": "This is the rest",
91 "is_reasoning_end": True,
92 }
93 THINK_NO_END = {
94 "output": "[THINK]This is a reasoning section",
95 - "reasoning_content": "This is a reasoning section",
95 + "reasoning": "This is a reasoning section",
96 "content": None,
97 "is_reasoning_end": False,
98 }
99 EMPTY = {
100 "output": "",
101 - "reasoning_content": "",
101 + "reasoning": "",
102 "content": None,
103 "is_reasoning_end": False,
104 }
105 EMPTY_STREAMING = {
106 "output": "",
107 - "reasoning_content": None,
107 + "reasoning": None,
108 "content": None,
109 "is_reasoning_end": False,
110 }
111 NEW_LINE = {
112 "output": "\n[THINK]This is a reasoning section[/THINK]\nThis is the rest",
113 - "reasoning_content": "This is a reasoning section",
113 + "reasoning": "This is a reasoning section",
114 "content": "\nThis is the rest",
115 "is_reasoning_end": True,
116 }
@@ -120,7 +120,7 @@ NEW_LINE = {
120 # or not.
121 NEW_LINE_STREAMING = {
122 "output": "\n[THINK]This is a reasoning section[/THINK]\nThis is the rest",
123 - "reasoning_content": "\nThis is a reasoning section",
123 + "reasoning": "\nThis is a reasoning section",
124 "content": "\nThis is the rest",
125 "is_reasoning_end": True,
126 }
@@ -307,7 +307,7 @@ def test_mistral_reasoning(
307 parser, output_tokens, streaming=streaming
308 )
309
310 - assert reasoning == param_dict["reasoning_content"]
310 + assert reasoning == param_dict["reasoning"]
311 assert content == param_dict["content"]
312
313 # Test is_reasoning_end
tests/reasoning/test_olmo3_reasoning_parser.py
+8 -8
@@ -13,43 +13,43 @@ END_REASONING = "</think>"
13
14 NO_REASONING = {
15 "output": f"{START_REASONING}{END_REASONING}No thoughts, head empty!",
16 - "reasoning_content": None,
16 + "reasoning": None,
17 "content": "No thoughts, head empty!",
18 }
19
20 NO_REASONING_WITH_NEWLINE = {
21 "output": f"{START_REASONING}\n{END_REASONING}\n\nNo thoughts, head empty!",
22 - "reasoning_content": "\n",
22 + "reasoning": "\n",
23 "content": "\n\nNo thoughts, head empty!",
24 }
25
26 SIMPLE_REASONING = {
27 "output": f"{START_REASONING}This is a reasoning section{END_REASONING}This is the rest", # noqa: E501
28 - "reasoning_content": "This is a reasoning section",
28 + "reasoning": "This is a reasoning section",
29 "content": "This is the rest",
30 }
31
32 SIMPLE_REASONING_WITH_NEWLINE = {
33 "output": f"{START_REASONING} Look!\n\nI'm thinking...{END_REASONING}\nThis is the rest", # noqa: E501
34 - "reasoning_content": " Look!\n\nI'm thinking...",
34 + "reasoning": " Look!\n\nI'm thinking...",
35 "content": "\nThis is the rest",
36 }
37
38 SIMPLE_REASONING_WITH_MULTIPLE_NEWLINES = {
39 "output": f"{START_REASONING}\nLook!\nI'm thinking...\n\n{END_REASONING}\n\n\nThis is the rest", # noqa: E501
40 - "reasoning_content": "\nLook!\nI'm thinking...\n\n",
40 + "reasoning": "\nLook!\nI'm thinking...\n\n",
41 "content": "\n\n\nThis is the rest",
42 }
43
44 NO_REASONING_ONLY_END_THINK = {
45 "output": f"{END_REASONING}\n\nNo thoughts, head empty!",
46 - "reasoning_content": None,
46 + "reasoning": None,
47 "content": "\n\nNo thoughts, head empty!",
48 }
49
50 REASONING_ONLY_END_THINK = {
51 "output": f"The user is asking me not to think.{END_REASONING}No thoughts!",
52 - "reasoning_content": "The user is asking me not to think.",
52 + "reasoning": "The user is asking me not to think.",
53 "content": "No thoughts!",
54 }
55
@@ -148,5 +148,5 @@ def test_reasoning(
148 reasoning_parser=parser, model_output=model_output, streaming=streaming
149 )
150
151 - assert reasoning == param_dict["reasoning_content"]
151 + assert reasoning == param_dict["reasoning"]
152 assert content == param_dict["content"]
tests/reasoning/test_qwen3_reasoning_parser.py
+9 -9
@@ -22,47 +22,47 @@ def qwen3_tokenizer():
22 # 带 <think></think>,非stream
23 WITH_THINK = {
24 "output": "<think>This is a reasoning section</think>This is the rest",
25 - "reasoning_content": "This is a reasoning section",
25 + "reasoning": "This is a reasoning section",
26 "content": "This is the rest",
27 }
28 # 带 <think></think>,stream
29 WITH_THINK_STREAM = {
30 "output": "<think>This is a reasoning section</think>This is the rest",
31 - "reasoning_content": "This is a reasoning section",
31 + "reasoning": "This is a reasoning section",
32 "content": "This is the rest",
33 }
34 # 不带 <think></think>,非stream
35 WITHOUT_THINK = {
36 "output": "This is the rest",
37 - "reasoning_content": None,
37 + "reasoning": None,
38 "content": "This is the rest",
39 }
40 # 不带 <think></think>,stream
41 WITHOUT_THINK_STREAM = {
42 "output": "This is the rest",
43 - "reasoning_content": None,
43 + "reasoning": None,
44 "content": "This is the rest",
45 }
46
47 COMPLETE_REASONING = {
48 "output": "<think>This is a reasoning section</think>",
49 - "reasoning_content": "This is a reasoning section",
49 + "reasoning": "This is a reasoning section",
50 "content": None,
51 }
52 MULTILINE_REASONING = {
53 "output": "<think>This is a reasoning\nsection</think>This is the rest\nThat",
54 - "reasoning_content": "This is a reasoning\nsection",
54 + "reasoning": "This is a reasoning\nsection",
55 "content": "This is the rest\nThat",
56 }
57 ONLY_OPEN_TAG = {
58 "output": "<think>This is a reasoning section",
59 - "reasoning_content": None,
59 + "reasoning": None,
60 "content": "<think>This is a reasoning section",
61 }
62
63 ONLY_OPEN_TAG_STREAM = {
64 "output": "<think>This is a reasoning section",
65 - "reasoning_content": "This is a reasoning section",
65 + "reasoning": "This is a reasoning section",
66 "content": None,
67 }
68
@@ -138,5 +138,5 @@ def test_reasoning(
138 parser, output_tokens, streaming=streaming
139 )
140
141 - assert reasoning == param_dict["reasoning_content"]
141 + assert reasoning == param_dict["reasoning"]
142 assert content == param_dict["content"]
tests/reasoning/test_seedoss_reasoning_parser.py
+15 -15
@@ -28,49 +28,49 @@ def seedoss_tokenizer():
28
29 SIMPLE_REASONING: dict[str, Any] = {
30 "output": "This is a reasoning section</seed:think>This is the rest",
31 - "reasoning_content": "This is a reasoning section",
31 + "reasoning": "This is a reasoning section",
32 "content": "This is the rest",
33 "is_reasoning_end": True,
34 }
35 COMPLETE_REASONING: dict[str, Any] = {
36 "output": "This is a reasoning section</seed:think>",
37 - "reasoning_content": "This is a reasoning section",
37 + "reasoning": "This is a reasoning section",
38 "content": None,
39 "is_reasoning_end": True,
40 }
41 NO_CONTENT: dict[str, Any] = {
42 "output": "This is content",
43 - "reasoning_content": "This is content",
43 + "reasoning": "This is content",
44 "content": None,
45 "is_reasoning_end": False,
46 }
47 NO_REASONING_STREAMING: dict[str, Any] = {
48 "output": "This is a reasoning section",
49 - "reasoning_content": "This is a reasoning section",
49 + "reasoning": "This is a reasoning section",
50 "content": None,
51 "is_reasoning_end": False,
52 }
53 MULTIPLE_LINES: dict[str, Any] = {
54 "output": "This\nThat</seed:think>This is the rest\nThat",
55 - "reasoning_content": "This\nThat",
55 + "reasoning": "This\nThat",
56 "content": "This is the rest\nThat",
57 "is_reasoning_end": True,
58 }
59 WITH_START_TOKEN: dict[str, Any] = {
60 "output": ("<seed:think>This is a reasoning section</seed:think>This is the rest"),
61 - "reasoning_content": "This is a reasoning section",
61 + "reasoning": "This is a reasoning section",
62 "content": "This is the rest",
63 "is_reasoning_end": True,
64 }
65 ONLY_END_TOKEN: dict[str, Any] = {
66 "output": "Some reasoning</seed:think>This is the rest",
67 - "reasoning_content": "Some reasoning",
67 + "reasoning": "Some reasoning",
68 "content": "This is the rest",
69 "is_reasoning_end": True,
70 }
71 NO_TOKENS: dict[str, Any] = {
72 "output": "This is just content without any reasoning tokens",
73 - "reasoning_content": "This is just content without any reasoning tokens",
73 + "reasoning": "This is just content without any reasoning tokens",
74 "content": None,
75 "is_reasoning_end": False,
76 }
@@ -95,7 +95,7 @@ def test_simple_reasoning(seedoss_tokenizer, streaming):
95 parser, [cast(str, SIMPLE_REASONING["output"])], streaming=streaming
96 )
97
98 - assert reasoning == SIMPLE_REASONING["reasoning_content"]
98 + assert reasoning == SIMPLE_REASONING["reasoning"]
99 assert content == SIMPLE_REASONING["content"]
100
101
@@ -109,7 +109,7 @@ def test_complete_reasoning(seedoss_tokenizer, streaming):
109 parser, [cast(str, COMPLETE_REASONING["output"])], streaming=streaming
110 )
111
112 - assert reasoning == COMPLETE_REASONING["reasoning_content"]
112 + assert reasoning == COMPLETE_REASONING["reasoning"]
113 assert content == COMPLETE_REASONING["content"]
114
115
@@ -123,7 +123,7 @@ def test_no_content(seedoss_tokenizer, streaming):
123 parser, [cast(str, NO_CONTENT["output"])], streaming=streaming
124 )
125
126 - assert reasoning == NO_CONTENT["reasoning_content"]
126 + assert reasoning == NO_CONTENT["reasoning"]
127 assert content == NO_CONTENT["content"]
128
129
@@ -137,7 +137,7 @@ def test_multiple_lines(seedoss_tokenizer, streaming):
137 parser, [cast(str, MULTIPLE_LINES["output"])], streaming=streaming
138 )
139
140 - assert reasoning == MULTIPLE_LINES["reasoning_content"]
140 + assert reasoning == MULTIPLE_LINES["reasoning"]
141 assert content == MULTIPLE_LINES["content"]
142
143
@@ -151,7 +151,7 @@ def test_with_start_token(seedoss_tokenizer, streaming):
151 parser, [cast(str, WITH_START_TOKEN["output"])], streaming=streaming
152 )
153
154 - assert reasoning == WITH_START_TOKEN["reasoning_content"]
154 + assert reasoning == WITH_START_TOKEN["reasoning"]
155 assert content == WITH_START_TOKEN["content"]
156
157
@@ -168,7 +168,7 @@ def test_only_end_token(seedoss_tokenizer, streaming):
168 parser, [cast(str, ONLY_END_TOKEN["output"])], streaming=streaming
169 )
170
171 - assert reasoning == ONLY_END_TOKEN["reasoning_content"]
171 + assert reasoning == ONLY_END_TOKEN["reasoning"]
172 assert content == ONLY_END_TOKEN["content"]
173
174
@@ -182,7 +182,7 @@ def test_no_tokens(seedoss_tokenizer, streaming):
182 parser, [cast(str, NO_TOKENS["output"])], streaming=streaming
183 )
184
185 - assert reasoning == NO_TOKENS["reasoning_content"]
185 + assert reasoning == NO_TOKENS["reasoning"]
186 assert content == NO_TOKENS["content"]
187
188
tests/reasoning/utils.py
+13 -10
@@ -9,25 +9,28 @@ from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
9
10 class StreamingReasoningReconstructor:
11 def __init__(self):
12 - self.reasoning_content = None
12 + self.reasoning = None
13 self.other_content = None
14
15 def append_delta(self, delta: DeltaMessage):
16 # content and the reasoning content should not be present
17 # at the same time
18 - assert delta.content is None or delta.reasoning_content is None, (
18 + assert delta.content is None or delta.reasoning is None, (
19 "Both content and reasoning content are present in the delta message"
20 )
21 + assert delta.reasoning == delta.reasoning_content, (
22 + "reasoning_content should be present for backwards compatibility"
23 + )
24 if delta.content is not None:
25 if self.other_content is None:
26 self.other_content = delta.content
27 else:
28 self.other_content += delta.content
29 else:
27 - if self.reasoning_content is None:
28 - self.reasoning_content = delta.reasoning_content
30 + if self.reasoning is None:
31 + self.reasoning = delta.reasoning
32 else:
30 - self.reasoning_content += delta.reasoning_content
33 + self.reasoning += delta.reasoning
34
35
36 def run_reasoning_extraction(
@@ -43,7 +46,7 @@ def run_reasoning_extraction(
46 request,
47 )
48 return (
46 - reconstructor.reasoning_content,
49 + reconstructor.reasoning,
50 reconstructor.other_content or None,
51 )
52 else:
@@ -69,7 +72,7 @@ def run_reasoning_extraction_mistral(
72 request,
73 )
74 return (
72 - reconstructor.reasoning_content,
75 + reconstructor.reasoning,
76 reconstructor.other_content or None,
77 )
78 else:
@@ -88,7 +91,7 @@ def run_reasoning_extraction_nonstreaming(
91 request: ChatCompletionRequest | None = None,
92 ) -> tuple[str | None, str | None]:
93 request = request or ChatCompletionRequest(messages=[], model="test-model")
91 - return reasoning_parser.extract_reasoning_content(
94 + return reasoning_parser.extract_reasoning(
95 model_output="".join(model_output), request=request
96 )
97
@@ -110,7 +113,7 @@ def run_reasoning_extraction_streaming(
113 ]
114 current_text = previous_text + delta
115 current_tokens = previous_tokens + token_delta
113 - delta_message = reasoning_parser.extract_reasoning_content_streaming(
116 + delta_message = reasoning_parser.extract_reasoning_streaming(
117 previous_text,
118 current_text,
119 delta,
@@ -142,7 +145,7 @@ def run_reasoning_extraction_streaming_mistral(
145 delta = reasoning_parser.model_tokenizer.convert_ids_to_tokens([model_delta])[0]
146 current_text = previous_text + delta
147 current_tokens = previous_tokens + token_delta
145 - delta_message = reasoning_parser.extract_reasoning_content_streaming(
148 + delta_message = reasoning_parser.extract_reasoning_streaming(
149 previous_text,
150 current_text,
151 delta,
tests/tokenization/test_mistral_tokenizer.py
+2 -2
@@ -102,7 +102,7 @@ def test_prepare_apply_chat_template_tools_and_messages(
102 assert actual_request == expected_mistral_output
103
104
105 -# Tool use with list content and reasoning_content
105 +# Tool use with list content and reasoning
106 @pytest.mark.parametrize(
107 "openai_request,expected_mistral_output",
108 [
@@ -115,7 +115,7 @@ def test_prepare_apply_chat_template_tools_and_messages(
115 },
116 {
117 "role": "assistant",
118 - "reasoning_content": None,
118 + "reasoning": None,
119 "content": None,
120 "tool_calls": [
121 {
tests/tool_use/test_ernie45_moe_tool_parser.py
+1 -1
@@ -337,7 +337,7 @@ def test_extract_tool_calls_streaming_incremental(
337 if (
338 delta_message.role is None
339 and delta_message.content is None
340 - and delta_message.reasoning_content is None
340 + and delta_message.reasoning is None
341 and len(delta_message.tool_calls) == 0
342 ):
343 continue
tests/v1/entrypoints/llm/test_struct_output_generate.py
+3 -3
@@ -674,10 +674,10 @@ def test_structured_output_with_reasoning_matrices(
674 assert output is not None and isinstance(output, RequestOutput)
675 prompt = output.prompt
676 generated_text = output.outputs[0].text
677 - reasoning_content, content = run_reasoning_extraction(reasoner, [generated_text])
678 - print(f"Prompt: {prompt!r}\nReasoning: {reasoning_content!r}\nContent: {content!r}")
677 + reasoning, content = run_reasoning_extraction(reasoner, [generated_text])
678 + print(f"Prompt: {prompt!r}\nReasoning: {reasoning!r}\nContent: {content!r}")
679
680 - assert content is not None and reasoning_content is not None
680 + assert content is not None and reasoning is not None
681 output_json = json.loads(content)
682 jsonschema.validate(instance=output_json, schema=reasoning_schema)
683
vllm/entrypoints/harmony_utils.py
+4 -4
@@ -521,15 +521,15 @@ def parse_chat_output(
521 is_tool_call = False # TODO: update this when tool call is supported
522 if len(output_msgs) == 0:
523 # The generation has stopped during reasoning.
524 - reasoning_content = parser.current_content
524 + reasoning = parser.current_content
525 final_content = None
526 elif len(output_msgs) == 1:
527 # The generation has stopped during final message.
528 - reasoning_content = output_msgs[0].content[0].text
528 + reasoning = output_msgs[0].content[0].text
529 final_content = parser.current_content
530 else:
531 reasoning_msg = output_msgs[:-1]
532 final_msg = output_msgs[-1]
533 - reasoning_content = "\n".join([msg.content[0].text for msg in reasoning_msg])
533 + reasoning = "\n".join([msg.content[0].text for msg in reasoning_msg])
534 final_content = final_msg.content[0].text
535 - return reasoning_content, final_content, is_tool_call
535 + return reasoning, final_content, is_tool_call
vllm/entrypoints/openai/protocol.py
+16
@@ -2102,7 +2102,15 @@ class ChatMessage(OpenAIBaseModel):
2102 tool_calls: list[ToolCall] = Field(default_factory=list)
2103
2104 # vLLM-specific fields that are not in OpenAI spec
2105 + reasoning: str | None = None
2106 reasoning_content: str | None = None
2107 + """Deprecated: use `reasoning` instead."""
2108 +
2109 + @model_validator(mode="after")
2110 + def handle_deprecated_reasoning_content(self):
2111 + """Copy reasoning to reasoning_content for backward compatibility."""
2112 + self.reasoning_content = self.reasoning
2113 + return self
2114
2115
2116 class ChatCompletionLogProb(OpenAIBaseModel):
@@ -2156,9 +2164,17 @@ class ChatCompletionResponse(OpenAIBaseModel):
2164 class DeltaMessage(OpenAIBaseModel):
2165 role: str | None = None
2166 content: str | None = None
2167 + reasoning: str | None = None
2168 reasoning_content: str | None = None
2169 + """Deprecated: use `reasoning` instead."""
2170 tool_calls: list[DeltaToolCall] = Field(default_factory=list)
2171
2172 + @model_validator(mode="after")
2173 + def handle_deprecated_reasoning_content(self):
2174 + """Copy reasoning to reasoning_content for backward compatibility."""
2175 + self.reasoning_content = self.reasoning
2176 + return self
2177 +
2178
2179 class ChatCompletionResponseStreamChoice(OpenAIBaseModel):
2180 index: int
vllm/entrypoints/openai/serving_chat.py
+28 -38
@@ -759,9 +759,7 @@ class OpenAIServingChat(OpenAIServing):
759 delta_message = DeltaMessage(content=delta_text)
760 elif cur_channel == "analysis":
761 if request.include_reasoning:
762 - delta_message = DeltaMessage(
763 - reasoning_content=delta_text
764 - )
762 + delta_message = DeltaMessage(reasoning=delta_text)
763 else:
764 delta_message = None
765 elif (
@@ -823,7 +821,7 @@ class OpenAIServingChat(OpenAIServing):
821 ):
822 assert reasoning_parser is not None
823 delta_message = (
826 - reasoning_parser.extract_reasoning_content_streaming(
824 + reasoning_parser.extract_reasoning_streaming(
825 previous_text,
826 current_text,
827 delta_text,
@@ -836,7 +834,7 @@ class OpenAIServingChat(OpenAIServing):
834 # or think end id in prompt_token_ids
835 # i.e {"enable_thinking": False},
836 # set reasoning status to end.
839 - # Only keep 'content', remove 'reasoning_content'.
837 + # Only keep 'content', remove 'reasoning'.
838 if reasoning_parser.is_reasoning_end(
839 as_list(output.token_ids)
840 ) or (
@@ -899,7 +897,7 @@ class OpenAIServingChat(OpenAIServing):
897
898 if self.reasoning_parser and not reasoning_end_arr[i]:
899 delta_message = (
902 - reasoning_parser.extract_reasoning_content_streaming(
900 + reasoning_parser.extract_reasoning_streaming(
901 previous_text,
902 current_text,
903 delta_text,
@@ -948,7 +946,7 @@ class OpenAIServingChat(OpenAIServing):
946 output_token_ids = as_list(output.token_ids)
947 if not reasoning_end_arr[i]:
948 delta_message = (
951 - reasoning_parser.extract_reasoning_content_streaming(
949 + reasoning_parser.extract_reasoning_streaming(
950 previous_text,
951 current_text,
952 delta_text,
@@ -961,7 +959,7 @@ class OpenAIServingChat(OpenAIServing):
959 # i.e {"enable_thinking": False},
960 # set reasoning status to end.
961 # Remove the text and token ids related
964 - # to 'reasoning_content'.
962 + # to 'reasoning'.
963 if (
964 res.prompt_token_ids
965 and reasoning_parser.is_reasoning_end(
@@ -978,7 +976,7 @@ class OpenAIServingChat(OpenAIServing):
976 # When encountering think end id in delta_token_ids,
977 # set reasoning status to end.
978 # Remove the text and token ids related
981 - # to 'reasoning_content'.
979 + # to 'reasoning'.
980 if reasoning_parser.is_reasoning_end(output_token_ids):
981 reasoning_end_arr[i] = True
982 current_token_ids = (
@@ -1033,15 +1031,13 @@ class OpenAIServingChat(OpenAIServing):
1031
1032 # when only reasoning
1033 elif self.reasoning_parser:
1036 - delta_message = (
1037 - reasoning_parser.extract_reasoning_content_streaming(
1038 - previous_text,
1039 - current_text,
1040 - delta_text,
1041 - previous_token_ids,
1042 - current_token_ids,
1043 - output.token_ids,
1044 - )
1034 + delta_message = reasoning_parser.extract_reasoning_streaming(
1035 + previous_text,
1036 + current_text,
1037 + delta_text,
1038 + previous_token_ids,
1039 + current_token_ids,
1040 + output.token_ids,
1041 )
1042 # handle streaming just a content delta
1043 else:
@@ -1334,9 +1330,9 @@ class OpenAIServingChat(OpenAIServing):
1330 logprobs = None
1331
1332 if self.use_harmony:
1337 - reasoning_content, content, _ = parse_chat_output(token_ids)
1333 + reasoning, content, _ = parse_chat_output(token_ids)
1334 if not request.include_reasoning:
1339 - reasoning_content = None
1335 + reasoning = None
1336
1337 if self.tool_parser is not None:
1338 tool_parser = self.tool_parser(tokenizer)
@@ -1349,14 +1345,14 @@ class OpenAIServingChat(OpenAIServing):
1345 content = tool_call_info.content
1346 message = ChatMessage(
1347 role=role,
1352 - reasoning_content=reasoning_content,
1348 + reasoning=reasoning,
1349 content=content,
1350 tool_calls=tool_call_info.tool_calls,
1351 )
1352 else:
1353 message = ChatMessage(
1354 role=role,
1359 - reasoning_content=reasoning_content,
1355 + reasoning=reasoning,
1356 content=content,
1357 )
1358
@@ -1390,13 +1386,13 @@ class OpenAIServingChat(OpenAIServing):
1386 return self.create_error_response(str(e))
1387 # If the reasoning parser is enabled,
1388 # tool calls are extracted exclusively from the content.
1393 - reasoning_content, content = reasoning_parser.extract_reasoning_content(
1389 + reasoning, content = reasoning_parser.extract_reasoning(
1390 output.text, request=request
1391 )
1392 if not request.include_reasoning:
1397 - reasoning_content = None
1393 + reasoning = None
1394 else:
1399 - reasoning_content = None
1395 + reasoning = None
1396 content = output.text
1397
1398 auto_tools_called = False
@@ -1416,9 +1412,7 @@ class OpenAIServingChat(OpenAIServing):
1412 not isinstance(request.tool_choice, ChatCompletionNamedToolChoiceParam)
1413 and request.tool_choice != "required"
1414 ):
1419 - message = ChatMessage(
1420 - role=role, reasoning_content=reasoning_content, content=content
1421 - )
1415 + message = ChatMessage(role=role, reasoning=reasoning, content=content)
1416
1417 # if the request uses tools and specified a tool choice
1418 elif (
@@ -1428,7 +1422,7 @@ class OpenAIServingChat(OpenAIServing):
1422 assert tool_calls is not None and len(tool_calls) > 0
1423 message = ChatMessage(
1424 role=role,
1431 - reasoning_content=reasoning_content,
1425 + reasoning=reasoning,
1426 content="",
1427 tool_calls=[tool_call_class(function=tc) for tc in tool_calls],
1428 )
@@ -1452,15 +1446,13 @@ class OpenAIServingChat(OpenAIServing):
1446 role=role,
1447 content="",
1448 tool_calls=tool_call_class_items,
1455 - reasoning_content=reasoning_content,
1449 + reasoning=reasoning,
1450 )
1451
1452 # if the request doesn't use tool choice
1453 # OR specifies to not use a tool
1454 elif not request.tool_choice or request.tool_choice == "none":
1461 - message = ChatMessage(
1462 - role=role, reasoning_content=reasoning_content, content=content
1463 - )
1455 + message = ChatMessage(role=role, reasoning=reasoning, content=content)
1456
1457 # handle when there are tools and tool choice is auto
1458 elif (
@@ -1476,7 +1468,7 @@ class OpenAIServingChat(OpenAIServing):
1468 if tool_calls:
1469 message = ChatMessage(
1470 role=role,
1479 - reasoning_content=reasoning_content,
1471 + reasoning=reasoning,
1472 content=content,
1473 tool_calls=[
1474 ToolCall(
@@ -1498,7 +1490,7 @@ class OpenAIServingChat(OpenAIServing):
1490 ret_content = content
1491 message = ChatMessage(
1492 role=role,
1501 - reasoning_content=reasoning_content,
1493 + reasoning=reasoning,
1494 content=ret_content,
1495 )
1496
@@ -1509,9 +1501,7 @@ class OpenAIServingChat(OpenAIServing):
1501 " if tools should be extracted. Returning a standard chat "
1502 "completion."
1503 )
1512 - message = ChatMessage(
1513 - role=role, reasoning_content=reasoning_content, content=content
1514 - )
1504 + message = ChatMessage(role=role, reasoning=reasoning, content=content)
1505 # In OpenAI's API, when a tool is called, the finish_reason is:
1506 # "tool_calls" for "auto" or "required" tool calls,
1507 # and "stop" for named tool calls.
vllm/entrypoints/openai/serving_responses.py
+22 -26
@@ -778,11 +778,11 @@ class OpenAIServingResponses(OpenAIServing):
778 logger.exception("Error in reasoning parser creation.")
779 raise e
780
781 - reasoning_content, content = reasoning_parser.extract_reasoning_content(
781 + reasoning, content = reasoning_parser.extract_reasoning(
782 final_output.text, request=request
783 )
784 else:
785 - reasoning_content = None
785 + reasoning = None
786 content = final_output.text
787
788 # Log complete response if output logging is enabled
@@ -790,8 +790,8 @@ class OpenAIServingResponses(OpenAIServing):
790 output_text = ""
791 if content:
792 output_text = content
793 - elif reasoning_content:
794 - output_text = f"[reasoning: {reasoning_content}]"
793 + elif reasoning:
794 + output_text = f"[reasoning: {reasoning}]"
795
796 if output_text:
797 self.request_logger.log_outputs(
@@ -805,15 +805,13 @@ class OpenAIServingResponses(OpenAIServing):
805
806 reasoning_item = None
807 message_item = None
808 - if reasoning_content:
808 + if reasoning:
809 reasoning_item = ResponseReasoningItem(
810 id=f"rs_{random_uuid()}",
811 summary=[],
812 type="reasoning",
813 content=[
814 - ResponseReasoningTextContent(
815 - text=reasoning_content, type="reasoning_text"
816 - )
814 + ResponseReasoningTextContent(text=reasoning, type="reasoning_text")
815 ],
816 status=None, # NOTE: Only the last output item has status.
817 )
@@ -1208,15 +1206,13 @@ class OpenAIServingResponses(OpenAIServing):
1206 if ctx.last_output.outputs:
1207 output = ctx.last_output.outputs[0]
1208 if reasoning_parser:
1211 - delta_message = (
1212 - reasoning_parser.extract_reasoning_content_streaming(
1213 - previous_text=previous_text,
1214 - current_text=previous_text + output.text,
1215 - delta_text=output.text,
1216 - previous_token_ids=previous_token_ids,
1217 - current_token_ids=previous_token_ids + output.token_ids,
1218 - delta_token_ids=output.token_ids,
1219 - )
1209 + delta_message = reasoning_parser.extract_reasoning_streaming(
1210 + previous_text=previous_text,
1211 + current_text=previous_text + output.text,
1212 + delta_text=output.text,
1213 + previous_token_ids=previous_token_ids,
1214 + current_token_ids=previous_token_ids + output.token_ids,
1215 + delta_token_ids=output.token_ids,
1216 )
1217 else:
1218 delta_message = DeltaMessage(
@@ -1228,7 +1224,7 @@ class OpenAIServingResponses(OpenAIServing):
1224 continue
1225 if not first_delta_sent:
1226 current_item_id = str(uuid.uuid4())
1231 - if delta_message.reasoning_content:
1227 + if delta_message.reasoning:
1228 yield _increment_sequence_number_and_return(
1229 ResponseOutputItemAddedEvent(
1230 type="response.output_item.added",
@@ -1280,15 +1276,15 @@ class OpenAIServingResponses(OpenAIServing):
1276 # same as content or reasoning content
1277 if (
1278 previous_delta_messages
1283 - and previous_delta_messages[-1].reasoning_content is not None
1279 + and previous_delta_messages[-1].reasoning is not None
1280 and delta_message.content is not None
1281 ):
1282 # from reasoning to normal content, send done
1283 # event for reasoning
1284 reason_content = "".join(
1289 - pm.reasoning_content
1285 + pm.reasoning
1286 for pm in previous_delta_messages
1291 - if pm.reasoning_content is not None
1287 + if pm.reasoning is not None
1288 )
1289 yield _increment_sequence_number_and_return(
1290 ResponseReasoningTextDoneEvent(
@@ -1356,7 +1352,7 @@ class OpenAIServingResponses(OpenAIServing):
1352 # reset previous delta messages
1353 previous_delta_messages = []
1354
1359 - if delta_message.reasoning_content is not None:
1355 + if delta_message.reasoning is not None:
1356 yield _increment_sequence_number_and_return(
1357 ResponseReasoningTextDeltaEvent(
1358 type="response.reasoning_text.delta",
@@ -1364,7 +1360,7 @@ class OpenAIServingResponses(OpenAIServing):
1360 content_index=current_content_index,
1361 output_index=current_output_index,
1362 item_id=current_item_id,
1367 - delta=delta_message.reasoning_content,
1363 + delta=delta_message.reasoning,
1364 )
1365 )
1366 elif delta_message.content is not None:
@@ -1392,11 +1388,11 @@ class OpenAIServingResponses(OpenAIServing):
1388
1389 previous_delta_messages.append(delta_message)
1390 if previous_delta_messages:
1395 - if previous_delta_messages[-1].reasoning_content is not None:
1391 + if previous_delta_messages[-1].reasoning is not None:
1392 reason_content = "".join(
1397 - pm.reasoning_content
1393 + pm.reasoning
1394 for pm in previous_delta_messages
1399 - if pm.reasoning_content is not None
1395 + if pm.reasoning is not None
1396 )
1397 yield _increment_sequence_number_and_return(
1398 ResponseReasoningTextDoneEvent(
vllm/entrypoints/openai/tool_parsers/qwen3xml_tool_parser.py
+1 -1
@@ -279,7 +279,7 @@ class StreamingXMLToolCallParser:
279 final_delta = DeltaMessage(
280 role=None,
281 content=None,
282 - reasoning_content=None,
282 + reasoning=None,
283 tool_calls=[
284 DeltaToolCall(
285 index=self.tool_call_index - 1,
vllm/reasoning/abs_reasoning_parsers.py
+2 -2
@@ -76,7 +76,7 @@ class ReasoningParser:
76 """
77
78 @abstractmethod
79 - def extract_reasoning_content(
79 + def extract_reasoning(
80 self,
81 model_output: str,
82 request: ChatCompletionRequest | ResponsesRequest,
@@ -100,7 +100,7 @@ class ReasoningParser:
100 """
101
102 @abstractmethod
103 - def extract_reasoning_content_streaming(
103 + def extract_reasoning_streaming(
104 self,
105 previous_text: str,
106 current_text: str,
vllm/reasoning/basic_parsers.py
+10 -14
@@ -76,7 +76,7 @@ class BaseThinkingReasoningParser(ReasoningParser):
76 else:
77 return input_ids[input_ids.index(self.end_token_id) + 1 :]
78
79 - def extract_reasoning_content_streaming(
79 + def extract_reasoning_streaming(
80 self,
81 previous_text: str,
82 current_text: str,
@@ -103,11 +103,10 @@ class BaseThinkingReasoningParser(ReasoningParser):
103 # start token in previous, end token in delta,
104 # extract reasoning content
105 end_index = delta_text.find(self.end_token)
106 - reasoning_content = delta_text[:end_index]
106 + reasoning = delta_text[:end_index]
107 content = delta_text[end_index + len(self.end_token) :]
108 return DeltaMessage(
109 - reasoning_content=reasoning_content,
110 - content=content if content else None,
109 + reasoning=reasoning, content=content if content else None
110 )
111 elif self.end_token_id in previous_token_ids:
112 # start token in previous, end token in previous,
@@ -116,30 +115,27 @@ class BaseThinkingReasoningParser(ReasoningParser):
115 else:
116 # start token in previous, no end token in previous or delta,
117 # reasoning content continues
119 - return DeltaMessage(reasoning_content=delta_text)
118 + return DeltaMessage(reasoning=delta_text)
119 elif self.start_token_id in delta_token_ids:
120 if self.end_token_id in delta_token_ids:
121 # start token in delta, end token in delta,
122 # extract reasoning content
123 start_index = delta_text.find(self.start_token)
124 end_index = delta_text.find(self.end_token)
126 - reasoning_content = delta_text[
127 - start_index + len(self.start_token) : end_index
128 - ]
125 + reasoning = delta_text[start_index + len(self.start_token) : end_index]
126 content = delta_text[end_index + len(self.end_token) :]
127 return DeltaMessage(
131 - reasoning_content=reasoning_content,
132 - content=content if content else None,
128 + reasoning=reasoning, content=content if content else None
129 )
130 else:
131 # start token in delta, no end token in delta,
132 # reasoning content continues
137 - return DeltaMessage(reasoning_content=delta_text)
133 + return DeltaMessage(reasoning=delta_text)
134 else:
135 # not find thinking start token
136 return DeltaMessage(content=delta_text)
137
142 - def extract_reasoning_content(
138 + def extract_reasoning(
139 self, model_output: str, request: ChatCompletionRequest | ResponsesRequest
140 ) -> tuple[str | None, str | None]:
141 """
@@ -160,7 +156,7 @@ class BaseThinkingReasoningParser(ReasoningParser):
156 if self.end_token not in model_output:
157 return model_output, None
158 else:
163 - reasoning_content, _, content = model_output.partition(self.end_token)
159 + reasoning, _, content = model_output.partition(self.end_token)
160 # If generation stops right after end-of-think, return null content
161 final_content = content or None
166 - return reasoning_content, final_content
162 + return reasoning, final_content
vllm/reasoning/deepseek_r1_reasoning_parser.py
+5 -5
@@ -25,7 +25,7 @@ class DeepSeekR1ReasoningParser(BaseThinkingReasoningParser):
25 """The token that ends reasoning content."""
26 return "</think>"
27
28 - def extract_reasoning_content_streaming(
28 + def extract_reasoning_streaming(
29 self,
30 previous_text: str,
31 current_text: str,
@@ -34,7 +34,7 @@ class DeepSeekR1ReasoningParser(BaseThinkingReasoningParser):
34 current_token_ids: Sequence[int],
35 delta_token_ids: Sequence[int],
36 ) -> DeltaMessage | None:
37 - ret = super().extract_reasoning_content_streaming(
37 + ret = super().extract_reasoning_streaming(
38 previous_text,
39 current_text,
40 delta_text,
@@ -51,10 +51,10 @@ class DeepSeekR1ReasoningParser(BaseThinkingReasoningParser):
51 # end token in delta with more tokens,
52 # extract reasoning content and content
53 end_index = delta_text.find(self.end_token)
54 - reasoning_content = delta_text[:end_index]
54 + reasoning = delta_text[:end_index]
55 content = delta_text[end_index + len(self.end_token) :]
56 return DeltaMessage(
57 - reasoning_content=reasoning_content,
57 + reasoning=reasoning,
58 content=content if content else None,
59 )
60 elif self.end_token_id in previous_token_ids:
@@ -62,6 +62,6 @@ class DeepSeekR1ReasoningParser(BaseThinkingReasoningParser):
62 return DeltaMessage(content=delta_text)
63 else:
64 # no end token in previous or delta, reasoning content continues
65 - return DeltaMessage(reasoning_content=delta_text)
65 + return DeltaMessage(reasoning=delta_text)
66
67 return ret
vllm/reasoning/deepseek_v3_reasoning_parser.py
+4 -4
@@ -38,12 +38,12 @@ class DeepSeekV3ReasoningParser(ReasoningParser):
38 def extract_content_ids(self, input_ids: list[int]) -> list[int]:
39 return self._parser.extract_content_ids(input_ids)
40
41 - def extract_reasoning_content(
41 + def extract_reasoning(
42 self, model_output: str, request: ChatCompletionRequest
43 ) -> tuple[str | None, str | None]:
44 - return self._parser.extract_reasoning_content(model_output, request)
44 + return self._parser.extract_reasoning(model_output, request)
45
46 - def extract_reasoning_content_streaming(
46 + def extract_reasoning_streaming(
47 self,
48 previous_text: str,
49 current_text: str,
@@ -52,7 +52,7 @@ class DeepSeekV3ReasoningParser(ReasoningParser):
52 current_token_ids: Sequence[int],
53 delta_token_ids: Sequence[int],
54 ) -> DeltaMessage | None:
55 - return self._parser.extract_reasoning_content_streaming(
55 + return self._parser.extract_reasoning_streaming(
56 previous_text,
57 current_text,
58 delta_text,
vllm/reasoning/ernie45_reasoning_parser.py
+9 -11
@@ -57,7 +57,7 @@ class Ernie45ReasoningParser(BaseThinkingReasoningParser):
57 "tokens in the tokenizer!"
58 )
59
60 - def extract_reasoning_content_streaming(
60 + def extract_reasoning_streaming(
61 self,
62 previous_text: str,
63 current_text: str,
@@ -73,7 +73,7 @@ class Ernie45ReasoningParser(BaseThinkingReasoningParser):
73 The Ernie45 thinking model ouput format is
74 abc\n</think>\n\n<response>\ndef\n</response>\n
75 or abc\n</think>\ndef
76 - - 'abc' goes to reasoning_content
76 + - 'abc' goes to reasoning
77 - 'def' goes to content
78 """
79 # Skip single special tokens
@@ -94,7 +94,7 @@ class Ernie45ReasoningParser(BaseThinkingReasoningParser):
94 # </think> in delta with more tokens,
95 # extract reasoning content and content
96 think_end_index = delta_text.find(self.end_token)
97 - reasoning_content = delta_text[:think_end_index]
97 + reasoning = delta_text[:think_end_index]
98 content = delta_text[think_end_index + len(self.end_token) :]
99 content = content.lstrip("\n")
100 response_start_idx = content.find(self.response_start_token)
@@ -104,7 +104,7 @@ class Ernie45ReasoningParser(BaseThinkingReasoningParser):
104 if response_end_idx != -1:
105 content = content[:response_end_idx]
106 return DeltaMessage(
107 - reasoning_content=reasoning_content,
107 + reasoning=reasoning,
108 content=content if content else None,
109 )
110 elif self.end_token_id in previous_token_ids:
@@ -138,9 +138,9 @@ class Ernie45ReasoningParser(BaseThinkingReasoningParser):
138 return DeltaMessage(content=content if content else None)
139 else:
140 # no </think> in previous or delta, reasoning content continues
141 - return DeltaMessage(reasoning_content=delta_text)
141 + return DeltaMessage(reasoning=delta_text)
142
143 - def extract_reasoning_content(
143 + def extract_reasoning(
144 self, model_output: str, request: ChatCompletionRequest
145 ) -> tuple[str | None, str | None]:
146 """
@@ -148,14 +148,12 @@ class Ernie45ReasoningParser(BaseThinkingReasoningParser):
148 The Ernie45 thinking model ouput format is
149 abc\n</think>\n\n\n<response>\ndef\n</response>\n
150 or abc\n</think>\ndef
151 - - 'abc' goes to reasoning_content
151 + - 'abc' goes to reasoning
152 - 'def' goes to content
153 Returns:
154 tuple[Optional[str], Optional[str]]: reasoning content and content
155 """
156 - reasoning_content, content = super().extract_reasoning_content(
157 - model_output, request
158 - )
156 + reasoning, content = super().extract_reasoning(model_output, request)
157 if content:
158 start_idx = content.find(self.response_start_token)
159 end_idx = content.rfind(self.response_end_token)
@@ -164,4 +162,4 @@ class Ernie45ReasoningParser(BaseThinkingReasoningParser):
162 content = content[start_idx + len(self.response_start_token) : end_idx]
163 final_content = content or None
164
167 - return reasoning_content, final_content
165 + return reasoning, final_content
vllm/reasoning/glm4_moe_reasoning_parser.py
+12 -12
@@ -70,7 +70,7 @@ class Glm4MoeModelReasoningParser(ReasoningParser):
70 else:
71 return input_ids[input_ids.index(self.think_end_token_id) + 1 :]
72
73 - def extract_reasoning_content_streaming(
73 + def extract_reasoning_streaming(
74 self,
75 previous_text: str,
76 current_text: str,
@@ -84,7 +84,7 @@ class Glm4MoeModelReasoningParser(ReasoningParser):
84 Handles streaming output where previous + delta = current.
85 Uses token IDs for faster processing.
86 For text <think>abc</think>xyz:
87 - - 'abc' goes to reasoning_content
87 + - 'abc' goes to reasoning
88 - 'xyz' goes to content
89 """
90 # Skip single special tokens
@@ -98,10 +98,10 @@ class Glm4MoeModelReasoningParser(ReasoningParser):
98 # <think> in previous, </think> in delta,
99 # extract reasoning content
100 end_index = delta_text.find(self.think_end_token)
101 - reasoning_content = delta_text[:end_index]
101 + reasoning = delta_text[:end_index]
102 content = delta_text[end_index + len(self.think_end_token) :]
103 return DeltaMessage(
104 - reasoning_content=reasoning_content,
104 + reasoning=reasoning,
105 content=content if content else None,
106 )
107 elif self.think_end_token_id in previous_token_ids:
@@ -111,36 +111,36 @@ class Glm4MoeModelReasoningParser(ReasoningParser):
111 else:
112 # <think> in previous, no </think> in previous or delta,
113 # reasoning content continues
114 - return DeltaMessage(reasoning_content=delta_text)
114 + return DeltaMessage(reasoning=delta_text)
115 elif self.think_start_token_id in delta_token_ids:
116 if self.think_end_token_id in delta_token_ids:
117 # <think> in delta, </think> in delta, extract reasoning content
118 start_index = delta_text.find(self.think_start_token)
119 end_index = delta_text.find(self.think_end_token)
120 - reasoning_content = delta_text[
120 + reasoning = delta_text[
121 start_index + len(self.think_start_token) : end_index
122 ]
123 content = delta_text[end_index + len(self.think_end_token) :]
124 return DeltaMessage(
125 - reasoning_content=reasoning_content,
125 + reasoning=reasoning,
126 content=content if content else None,
127 )
128 else:
129 # <think> in delta, no </think> in delta,
130 # reasoning content continues
131 - return DeltaMessage(reasoning_content=delta_text)
131 + return DeltaMessage(reasoning=delta_text)
132 else:
133 # thinking is disabled, just content
134 return DeltaMessage(content=delta_text)
135
136 - def extract_reasoning_content(
136 + def extract_reasoning(
137 self, model_output: str, request: ChatCompletionRequest
138 ) -> tuple[str | None, str | None]:
139 """
140 Extract reasoning content from the model output.
141
142 For text <think>abc</think>xyz:
143 - - 'abc' goes to reasoning_content
143 + - 'abc' goes to reasoning
144 - 'xyz' goes to content
145
146 Returns:
@@ -165,7 +165,7 @@ class Glm4MoeModelReasoningParser(ReasoningParser):
165 return None, model_output
166
167 # Extract reasoning content from the model output.
168 - reasoning_content, _, content = model_output.partition(self.think_end_token)
168 + reasoning, _, content = model_output.partition(self.think_end_token)
169
170 final_content = content or None
171 - return reasoning_content, final_content
171 + return reasoning, final_content
vllm/reasoning/gptoss_reasoning_parser.py
+3 -3
@@ -104,7 +104,7 @@ class GptOssReasoningParser(ReasoningParser):
104 return []
105 return self.model_tokenizer.encode(content)
106
107 - def extract_reasoning_content_streaming(
107 + def extract_reasoning_streaming(
108 self,
109 previous_text: str,
110 current_text: str,
@@ -131,9 +131,9 @@ class GptOssReasoningParser(ReasoningParser):
131 content_delta = cur_content
132 if reasoning_delta is None and content_delta is None:
133 return None
134 - return DeltaMessage(reasoning_content=reasoning_delta, content=content_delta)
134 + return DeltaMessage(reasoning=reasoning_delta, content=content_delta)
135
136 - def extract_reasoning_content(
136 + def extract_reasoning(
137 self,
138 model_output: str,
139 request: ChatCompletionRequest,
vllm/reasoning/granite_reasoning_parser.py
+41 -47
@@ -49,7 +49,7 @@ class GraniteReasoningParser(ReasoningParser):
49 len(think_start) for think_start in self.valid_think_starts
50 )
51
52 - def extract_reasoning_content(
52 + def extract_reasoning(
53 self, model_output: str, request: ChatCompletionRequest
54 ) -> tuple[str | None, str | None]:
55 """Extract the reasoning content & content sections, respectively.
@@ -67,12 +67,12 @@ class GraniteReasoningParser(ReasoningParser):
67 re_match = self.reasoning_regex.findall(model_output)
68 if not re_match:
69 return None, model_output
70 - reasoning_content, response_content = re_match[0]
70 + reasoning, response_content = re_match[0]
71 if not response_content:
72 - return reasoning_content, None
73 - return reasoning_content, response_content
72 + return reasoning, None
73 + return reasoning, response_content
74
75 - def extract_reasoning_content_streaming(
75 + def extract_reasoning_streaming(
76 self,
77 previous_text: str,
78 current_text: str,
@@ -107,12 +107,10 @@ class GraniteReasoningParser(ReasoningParser):
107 Union[DeltaMessage, None]
108 DeltaMessage with either reasoning content or content, or None.
109 """
110 - reasoning_content, resp_seq_len, content = self._get_content_sections(
111 - current_text
112 - )
110 + reasoning, resp_seq_len, content = self._get_content_sections(current_text)
111 # Either we haven't finished the start of the reasoning sequence,
112 # or the model is generating something unexpected.
115 - if not reasoning_content:
113 + if not reasoning:
114 delta_message = self._get_delta_message_with_no_reasoning_bounds(
115 current_text, delta_text
116 )
@@ -120,16 +118,16 @@ class GraniteReasoningParser(ReasoningParser):
118 # the start of response sequence.
119 elif not content:
120 delta_message = self._get_delta_message_with_no_response_bounds(
123 - current_text, reasoning_content, delta_text
121 + current_text, reasoning, delta_text
122 )
123 # We've finished both the start of reasoning and start of response seq.
124 else:
125 # This should never happen since we matched on the response
126 assert resp_seq_len is not None
127 delta_message = self._get_delta_message_with_both_bounds(
130 - delta_text, reasoning_content, content, current_text, resp_seq_len
128 + delta_text, reasoning, content, current_text, resp_seq_len
129 )
132 - if not delta_message.content and not delta_message.reasoning_content:
130 + if not delta_message.content and not delta_message.reasoning:
131 return None
132 return delta_message
133
@@ -185,20 +183,20 @@ class GraniteReasoningParser(ReasoningParser):
183 # message and append everything to content in the future.
184 if was_substr and not is_substr:
185 return DeltaMessage(
188 - reasoning_content=None,
186 + reasoning=None,
187 content=current_text,
188 )
189 if is_substr:
190 # Might still be in the special token sequence; return nothing
193 - return DeltaMessage(reasoning_content=None, content=None)
191 + return DeltaMessage(reasoning=None, content=None)
192 # Otherwise the sequence has already been broken and we already
193 # corrected; just return the delta text as normal content.
196 - return DeltaMessage(reasoning_content=None, content=delta_text)
194 + return DeltaMessage(reasoning=None, content=delta_text)
195
196 def _get_delta_message_with_no_response_bounds(
197 self,
198 current_text: str,
201 - reasoning_content: str,
199 + reasoning: str,
200 delta_text: str,
201 ) -> DeltaMessage:
202 """Parse the delta message when the current text has both reasoning
@@ -208,7 +206,7 @@ class GraniteReasoningParser(ReasoningParser):
206
207 Args:
208 current_text (str): The full previous + delta text.
211 - reasoning_content (str): reasoning content from current_text.
209 + reasoning (str): reasoning content from current_text.
210 delta_text (str): Text to consider and parse content from.
211
212 Returns:
@@ -222,12 +220,12 @@ class GraniteReasoningParser(ReasoningParser):
220 current_text.endswith(response_start)
221 for response_start in self.valid_response_starts
222 )
225 - if reasoning_content is None or ends_with_start_response_seq:
226 - return DeltaMessage(reasoning_content=None, content=None)
223 + if reasoning is None or ends_with_start_response_seq:
224 + return DeltaMessage(reasoning=None, content=None)
225
226 # Consider previous / current text only within context of the reasoning
229 - previous_text = reasoning_content[: -len(delta_text)]
230 - current_text = reasoning_content
227 + previous_text = reasoning[: -len(delta_text)]
228 + current_text = reasoning
229
230 # We need to be careful about adding unfinished response sequences;
231 # Find the place at which we MIGHT be starting a response sequence
@@ -253,32 +251,30 @@ class GraniteReasoningParser(ReasoningParser):
251
252 # Delta only contains potential continued response sequence text.
253 if delta_continues_substr:
256 - return DeltaMessage(reasoning_content=None, content=None)
254 + return DeltaMessage(reasoning=None, content=None)
255
256 if not prev_was_substr:
257 # Delta may be starting a new response seq but has other text too.
258 if delta_new_substr:
261 - return DeltaMessage(
262 - reasoning_content=delta_text[:delta_idx], content=None
263 - )
259 + return DeltaMessage(reasoning=delta_text[:delta_idx], content=None)
260 # Normal case for most reasoning text (no potential special seqs).
265 - return DeltaMessage(reasoning_content=delta_text, content=None)
261 + return DeltaMessage(reasoning=delta_text, content=None)
262 # The substring that previously seemed to be a potential response
263 # seq wasn't one; we need to add the content to the delta message,
264 # and also slice off the potential response sequence
265 elif delta_new_substr:
270 - reasoning_content = previous_text[prev_idx:] + delta_text[:delta_idx]
271 - return DeltaMessage(reasoning_content=reasoning_content, content=None)
266 + reasoning = previous_text[prev_idx:] + delta_text[:delta_idx]
267 + return DeltaMessage(reasoning=reasoning, content=None)
268 # No new substring yet, and we broke our old one; take the whole delta
269 return DeltaMessage(
274 - reasoning_content=previous_text[prev_idx:] + delta_text,
270 + reasoning=previous_text[prev_idx:] + delta_text,
271 content=None,
272 )
273
274 def _get_delta_message_with_both_bounds(
275 self,
276 delta_text: str,
281 - reasoning_content: str,
277 + reasoning: str,
278 response_content: str,
279 current_text: str,
280 response_seq_len: int,
@@ -288,7 +284,7 @@ class GraniteReasoningParser(ReasoningParser):
284
285 Args:
286 delta_text: Text to consider and parse content from.
291 - reasoning_content: reasoning content from current_text.
287 + reasoning: reasoning content from current_text.
288 response_content: response content from current_text.
289 current_text: The full previous + delta text.
290 response_seq_len: Len of the complete response sequence used.
@@ -301,20 +297,20 @@ class GraniteReasoningParser(ReasoningParser):
297 reasoning_end_idx = len(delta_text) - (len(response_content) + response_seq_len)
298
299 if reasoning_end_idx < 0:
304 - delta_reasoning_content = None
300 + delta_reasoning = None
301 else:
302 # Get the starting offset
307 - start_reasoning_content_idx = (
308 - len(reasoning_content) + response_seq_len + len(response_content) - 1
303 + start_reasoning_idx = (
304 + len(reasoning) + response_seq_len + len(response_content) - 1
305 )
306 delta_offset = len(current_text) - len(delta_text)
311 - start_offset = start_reasoning_content_idx - delta_offset
307 + start_offset = start_reasoning_idx - delta_offset
308 if start_offset < 0:
309 start_offset = 0
314 - delta_reasoning_content = delta_text[start_offset:reasoning_end_idx]
310 + delta_reasoning = delta_text[start_offset:reasoning_end_idx]
311
312 return DeltaMessage(
317 - reasoning_content=delta_reasoning_content,
313 + reasoning=delta_reasoning,
314 content=delta_content,
315 )
316
@@ -333,7 +329,7 @@ class GraniteReasoningParser(ReasoningParser):
329 (if there is one) and the non-reasoning content.
330 """
331 current_chunk_start = 0
336 - start_reasoning_content = None
332 + start_reasoning = None
333 parsed_content = False
334 delimiter_idxs = [
335 idx
@@ -344,10 +340,10 @@ class GraniteReasoningParser(ReasoningParser):
340 for current_chunk_end in delimiter_idxs:
341 current_chunk = current_text[current_chunk_start:current_chunk_end]
342 # Check to see if the start of reasoning seq if complete
347 - if start_reasoning_content is None:
343 + if start_reasoning is None:
344 for think_start in self.valid_think_starts:
345 if current_chunk == think_start[:-1]:
350 - start_reasoning_content = current_chunk_end + 1
346 + start_reasoning = current_chunk_end + 1
347 current_chunk_start = current_chunk_end + 1
348 break
349
@@ -357,13 +353,11 @@ class GraniteReasoningParser(ReasoningParser):
353 if current_chunk[-len(response_start) + 1 :] == response_start[:-1]:
354 # Mark end of reasoning and start response content
355 # after the start of response sequence.
360 - end_reasoning_content = current_chunk_end - len(response_start)
361 - reasoning_content = current_text[
362 - start_reasoning_content:end_reasoning_content
363 - ]
356 + end_reasoning = current_chunk_end - len(response_start)
357 + reasoning = current_text[start_reasoning:end_reasoning]
358 response_content = current_text[current_chunk_end + 1 :]
365 - return reasoning_content, len(response_start), response_content
359 + return reasoning, len(response_start), response_content
360
367 - if start_reasoning_content and not parsed_content:
368 - return current_text[start_reasoning_content:], None, None
361 + if start_reasoning and not parsed_content:
362 + return current_text[start_reasoning:], None, None
363 return None, None, None
vllm/reasoning/hunyuan_a13b_reasoning_parser.py
+14 -18
@@ -86,7 +86,7 @@ class HunyuanA13BReasoningParser(ReasoningParser):
86 # this id is not part of content, so just return [] here.
87 return []
88
89 - def extract_reasoning_content(
89 + def extract_reasoning(
90 self, model_output: str, request: ChatCompletionRequest
91 ) -> tuple[str | None, str | None]:
92 """Extract the reasoning content & content sections, respectively.
@@ -104,27 +104,27 @@ class HunyuanA13BReasoningParser(ReasoningParser):
104
105 re_match = self.full_match_reasoning_regex.findall(model_output)
106 if re_match:
107 - reasoning_content, response_content = re_match[0]
108 - if len(reasoning_content) == 0:
109 - reasoning_content = None
107 + reasoning, response_content = re_match[0]
108 + if len(reasoning) == 0:
109 + reasoning = None
110 if len(response_content) == 0:
111 response_content = None
112 - return reasoning_content, response_content
112 + return reasoning, response_content
113
114 fallback_regex = self.half_match_reasoning_regex
115 fallback_match = fallback_regex.findall(model_output)
116 if fallback_match:
117 - reasoning_content, response_content = fallback_match[0]
117 + reasoning, response_content = fallback_match[0]
118
119 if response_content.endswith(self.response_end_expr):
120 response_content = response_content[: -len(self.response_end_expr)]
121
122 - if len(reasoning_content) == 0:
123 - reasoning_content = None
122 + if len(reasoning) == 0:
123 + reasoning = None
124 if len(response_content) == 0:
125 response_content = None
126
127 - return reasoning_content, response_content
127 + return reasoning, response_content
128
129 return None, model_output
130
@@ -140,7 +140,7 @@ class HunyuanA13BReasoningParser(ReasoningParser):
140 sub_idx += 1
141 return sub_idx == len(subsequence)
142
143 - def extract_reasoning_content_streaming(
143 + def extract_reasoning_streaming(
144 self,
145 previous_text: str,
146 current_text: str,
@@ -223,19 +223,15 @@ class HunyuanA13BReasoningParser(ReasoningParser):
223
224 # Return content based on current state
225 if self.current_state == "think":
226 - return DeltaMessage(
227 - reasoning_content=buffered_content, content=None
228 - )
226 + return DeltaMessage(reasoning=buffered_content, content=None)
227 else:
230 - return DeltaMessage(
231 - reasoning_content=None, content=buffered_content
232 - )
228 + return DeltaMessage(reasoning=None, content=buffered_content)
229 else:
230 # No buffered content, send normally
231 if self.current_state == "think":
236 - return DeltaMessage(reasoning_content=delta_text, content=None)
232 + return DeltaMessage(reasoning=delta_text, content=None)
233 else:
238 - return DeltaMessage(reasoning_content=None, content=delta_text)
234 + return DeltaMessage(reasoning=None, content=delta_text)
235
236 # If no content to send in this delta
237 return None
vllm/reasoning/identity_reasoning_parser.py
+3 -3
@@ -36,7 +36,7 @@ class IdentityReasoningParser(ReasoningParser):
36 # Identity: return all tokens as content
37 return input_ids
38
39 - def extract_reasoning_content_streaming(
39 + def extract_reasoning_streaming(
40 self,
41 previous_text: str,
42 current_text: str,
@@ -50,9 +50,9 @@ class IdentityReasoningParser(ReasoningParser):
50 return DeltaMessage(content=delta_text)
51 return None
52
53 - def extract_reasoning_content(
53 + def extract_reasoning(
54 self, model_output: str, request: ChatCompletionRequest
55 ) -> tuple[str | None, str | None]:
56 - # No reasoning separation: return None for reasoning_content,
56 + # No reasoning separation: return None for reasoning,
57 # and full model_output as content
58 return None, model_output
vllm/reasoning/minimax_m2_reasoning_parser.py
+2 -2
@@ -48,7 +48,7 @@ class MiniMaxM2AppendThinkReasoningParser(ReasoningParser):
48 def extract_content_ids(self, input_ids: list[int]) -> list[int]:
49 return input_ids
50
51 - def extract_reasoning_content_streaming(
51 + def extract_reasoning_streaming(
52 self,
53 previous_text: str,
54 current_text: str,
@@ -61,7 +61,7 @@ class MiniMaxM2AppendThinkReasoningParser(ReasoningParser):
61 delta_text = "<think>" + delta_text
62 return DeltaMessage(content=delta_text)
63
64 - def extract_reasoning_content(
64 + def extract_reasoning(
65 self, model_output: str, request: ChatCompletionRequest | ResponsesRequest
66 ) -> tuple[str | None, str | None]:
67 return None, "<think>" + model_output
vllm/reasoning/olmo3_reasoning_parser.py
+6 -6
@@ -115,7 +115,7 @@ class Olmo3ReasoningBuffer:
115 if end_think_idx > 0:
116 # this covers the case there's content before
117 # the end of the reasoning block
118 - return DeltaMessage(reasoning_content=pretext)
118 + return DeltaMessage(reasoning=pretext)
119
120 if self.state == Olmo3ReasoningState.REASONING:
121 # we are inside reasoning block, return and empty
@@ -124,7 +124,7 @@ class Olmo3ReasoningBuffer:
124 text_buffer,
125 self.buffer,
126 ) = self.buffer, ""
127 - return DeltaMessage(reasoning_content=text_buffer)
127 + return DeltaMessage(reasoning=text_buffer)
128
129 if self.state == Olmo3ReasoningState.CONTENT:
130 # we are outside reasoning block, return and empty
@@ -250,7 +250,7 @@ class Olmo3ReasoningParser(ReasoningParser):
250 # this id is not part of content, so just return [] here.
251 return []
252
253 - def extract_reasoning_content(
253 + def extract_reasoning(
254 self,
255 model_output: str,
256 request: ChatCompletionRequest | ResponsesRequest,
@@ -271,14 +271,14 @@ class Olmo3ReasoningParser(ReasoningParser):
271
272 re_match = self.reasoning_regex.match(model_output)
273 if re_match:
274 - reasoning_content = re_match.group("reasoning") or None
274 + reasoning = re_match.group("reasoning") or None
275 content = re_match.group("content") or None
276 - return reasoning_content, content
276 + return reasoning, content
277
278 # no reasoning content
279 return None, model_output
280
281 - def extract_reasoning_content_streaming(
281 + def extract_reasoning_streaming(
282 self,
283 previous_text: str,
284 current_text: str,
vllm/reasoning/qwen3_reasoning_parser.py
+4 -4
@@ -27,7 +27,7 @@ class Qwen3ReasoningParser(BaseThinkingReasoningParser):
27 """The token that ends reasoning content."""
28 return "</think>"
29
30 - def extract_reasoning_content(
30 + def extract_reasoning(
31 self, model_output: str, request: ChatCompletionRequest | ResponsesRequest
32 ) -> tuple[str | None, str | None]:
33 """
@@ -37,7 +37,7 @@ class Qwen3ReasoningParser(BaseThinkingReasoningParser):
37 to be present, unlike other models that work with just the end token.
38
39 For text <think>abc</think>xyz:
40 - - 'abc' goes to reasoning_content
40 + - 'abc' goes to reasoning
41 - 'xyz' goes to content
42
43 Returns:
@@ -61,7 +61,7 @@ class Qwen3ReasoningParser(BaseThinkingReasoningParser):
61 return None, model_output
62
63 # Extract reasoning content from the model output.
64 - reasoning_content, _, content = model_output.partition(self.end_token)
64 + reasoning, _, content = model_output.partition(self.end_token)
65
66 final_content = content or None
67 - return reasoning_content, final_content
67 + return reasoning, final_content
vllm/reasoning/step3_reasoning_parser.py
+8 -8
@@ -40,7 +40,7 @@ class Step3ReasoningParser(ReasoningParser):
40 "token in the tokenizer!"
41 )
42
43 - def extract_reasoning_content_streaming(
43 + def extract_reasoning_streaming(
44 self,
45 previous_text: str,
46 current_text: str,
@@ -54,7 +54,7 @@ class Step3ReasoningParser(ReasoningParser):
54 Handles streaming output where previous + delta = current.
55 Uses token IDs for faster processing.
56 For text "abc</think>xyz":
57 - - 'abc' goes to reasoning_content
57 + - 'abc' goes to reasoning
58 - 'xyz' goes to content
59 """
60 # Skip single special token
@@ -64,10 +64,10 @@ class Step3ReasoningParser(ReasoningParser):
64 if self.think_end_token_id in delta_token_ids:
65 # </think> in delta, extract reasoning content and remaining content
66 end_index = delta_text.find(self.think_end_token)
67 - reasoning_content = delta_text[:end_index]
67 + reasoning = delta_text[:end_index]
68 content = delta_text[end_index + len(self.think_end_token) :]
69 return DeltaMessage(
70 - reasoning_content=reasoning_content,
70 + reasoning=reasoning,
71 content=content if content else None,
72 )
73 elif self.think_end_token_id in previous_token_ids:
@@ -75,9 +75,9 @@ class Step3ReasoningParser(ReasoningParser):
75 return DeltaMessage(content=delta_text)
76 else:
77 # No </think> seen yet, everything is reasoning
78 - return DeltaMessage(reasoning_content=delta_text)
78 + return DeltaMessage(reasoning=delta_text)
79
80 - def extract_reasoning_content(
80 + def extract_reasoning(
81 self, model_output: str, request: ChatCompletionRequest
82 ) -> tuple[str | None, str | None]:
83 # Check if the model output contains the </think> token
@@ -87,7 +87,7 @@ class Step3ReasoningParser(ReasoningParser):
87 else:
88 # Find the first occurrence of </think>
89 end_index = model_output.find(self.think_end_token)
90 - reasoning_content = model_output[:end_index]
90 + reasoning = model_output[:end_index]
91
92 # Content after </think> token
93 content = model_output[end_index + len(self.think_end_token) :]
@@ -95,7 +95,7 @@ class Step3ReasoningParser(ReasoningParser):
95 if len(content) == 0:
96 content = None
97
98 - return reasoning_content, content
98 + return reasoning, content
99
100 def is_reasoning_end(self, input_ids: list[int]) -> bool:
101 return self.think_end_token_id in input_ids
vllm/transformers_utils/chat_templates/template_minicpmv45.jinja
+6 -6
@@ -30,18 +30,18 @@
30 {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
31 {%- elif message.role == "assistant" %}
32 {%- set content = message.content %}
33 - {%- set reasoning_content = '' %}
34 - {%- if message.reasoning_content is defined and message.reasoning_content is not none %}
35 - {%- set reasoning_content = message.reasoning_content %}
33 + {%- set reasoning = '' %}
34 + {%- if message.reasoning is defined and message.reasoning is not none %}
35 + {%- set reasoning = message.reasoning %}
36 {%- else %}
37 {%- if '</think>' in message.content %}
38 {%- set content = message.content.split('</think>')[-1].lstrip('\n') %}
39 - {%- set reasoning_content = message.content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
39 + {%- set reasoning = message.content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
40 {%- endif %}
41 {%- endif %}
42 {%- if loop.index0 > ns.last_query_index %}
43 - {%- if loop.last or (not loop.last and reasoning_content) %}
44 - {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
43 + {%- if loop.last or (not loop.last and reasoning) %}
44 + {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
45 {%- else %}
46 {{- '<|im_start|>' + message.role + '\n' + content }}
47 {%- endif %}
vllm/transformers_utils/tokenizers/mistral.py
+2 -2
@@ -121,8 +121,8 @@ def _prepare_apply_chat_template_tools_and_messages(
121 #
122 # [1]: https://github.com/mistralai/mistral-common/blob/f4a06998b75ed78bbf5aaf569590b772ea26c9f6/src/mistral_common/protocol/instruct/messages.py#L80
123 for message in messages:
124 - # Remove reasoning_content as unsupported by Mistral
125 - _ = message.pop("reasoning_content", None) # type: ignore
124 + # Remove reasoning as unsupported by Mistral
125 + _ = message.pop("reasoning", None) # type: ignore
126
127 # The Mistral client, in comparison to the OpenAI client, requires the
128 # "parameters" dict and the "description" string to be present