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