Skip to content
Merged
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
39622e8
add reasoning_tokens
Muqi1029 Dec 21, 2025
eb957f0
Merge branch 'main' into reasoning_tokens
Muqi1029 Dec 21, 2025
e059cdb
update for streaming situation
Muqi1029 Dec 21, 2025
8eafafd
Merge branch 'main' into reasoning_tokens
JustinTong0323 Dec 21, 2025
f5e0fd2
Merge branch 'main' into reasoning_tokens
JustinTong0323 Dec 21, 2025
48439ae
Merge branch 'main' into reasoning_tokens
Muqi1029 Dec 28, 2025
3e68a62
Cherry-pick test from #15875
Muqi1029 Dec 28, 2025
bb91801
Tiny fix
Muqi1029 Dec 28, 2025
bd8138e
Merge branch 'main' into reasoning_tokens
Muqi1029 Dec 29, 2025
86b5400
Add reasoning usage to responses and grpc
cklxx Dec 29, 2025
4e0f876
Merge pull request #2 from cklxx/ckl/reasoning-tokens-followup
Muqi1029 Dec 29, 2025
1c85346
Merge branch 'main' into reasoning_tokens
JustinTong0323 Dec 29, 2025
8a81432
Merge branch 'main' into reasoning_tokens
Muqi1029 Dec 30, 2025
f308942
Convert token_id to list to unify spec decoding
Muqi1029 Dec 30, 2025
a9fb2c0
remove print info
Muqi1029 Dec 30, 2025
a888f78
Remove redundant getattr in gRPC request manager
cklxx Dec 31, 2025
129f675
Merge pull request #17 from cklxx/remove-unnecessary-getattr-usage
cklxx Dec 31, 2025
a4ee9e1
Merge branch 'main' into reasoning_tokens
Muqi1029 Jan 3, 2026
4e09b56
Update tests
Muqi1029 Jan 4, 2026
080d306
Handle empty reasoning_tokens list in gRPC batch output
cklxx Jan 4, 2026
1380ef1
Merge branch 'ckl/reasoning-tokens-followup' into remove-unnecessary-…
cklxx Jan 4, 2026
7db9ca3
Merge pull request #18 from cklxx/remove-unnecessary-getattr-usage-8a…
cklxx Jan 4, 2026
1816807
Merge pull request #4 from cklxx/ckl/reasoning-tokens-followup
Muqi1029 Jan 4, 2026
c93a33a
Merge remote-tracking branch 'origin/reasoning_tokens' into reasoning…
Muqi1029 Jan 4, 2026
fbbae99
Merge branch 'main' into reasoning_tokens
Muqi1029 Jan 4, 2026
a7f99b3
Rename _reasoning_over to _is_reasoning_over
Muqi1029 Jan 4, 2026
6a4d305
Merge branch 'main' into reasoning_tokens
Muqi1029 Jan 10, 2026
11be80b
Revert "Add reasoning usage to responses and grpc"
Muqi1029 Jan 10, 2026
b2c6674
Merge branch 'main' into reasoning_tokens
Muqi1029 Jan 31, 2026
eb82d8c
Finish
Muqi1029 Feb 1, 2026
c64817a
Merge branch 'main' into reasoning_tokens
Muqi1029 Feb 1, 2026
1d1c680
Register CI and reduce tolist overhead
Muqi1029 Feb 2, 2026
7bf2235
Rename variables
Muqi1029 Feb 2, 2026
176233f
Tiny fix
Muqi1029 Feb 2, 2026
835b56e
Merge branch 'main' into reasoning_tokens
JustinTong0323 Feb 2, 2026
9e775d2
Fix suite due to oom
Muqi1029 Feb 2, 2026
fb4f52c
Add accept_length_per_req_cpu for ngram_worker
Muqi1029 Feb 2, 2026
a2e6b5a
Tiny fix
Muqi1029 Feb 2, 2026
cd21df3
Fix api
Muqi1029 Feb 2, 2026
3237808
Merge branch 'main' into reasoning_tokens
JustinTong0323 Feb 6, 2026
dbe5ddc
Merge branch 'main' into reasoning_tokens
Muqi1029 Feb 6, 2026
712da62
Fix
Muqi1029 Feb 6, 2026
a20c2f9
Merge remote-tracking branch 'origin/reasoning_tokens' into reasoning…
Muqi1029 Feb 6, 2026
811fc42
Merge branch 'main' into reasoning_tokens
Muqi1029 Mar 3, 2026
78012d9
Merge branch 'main' into reasoning_tokens
Muqi1029 Mar 4, 2026
4767dfa
Fix
Muqi1029 Mar 4, 2026
01d912f
Merge branch 'main' into reasoning_tokens
JustinTong0323 Mar 4, 2026
7be4714
Merge branch 'main' into reasoning_tokens
Muqi1029 Mar 25, 2026
4aa6f45
Merge remote-tracking branch 'origin/reasoning_tokens' into reasoning…
Muqi1029 Mar 25, 2026
e171f35
Merge branch 'main' into reasoning_tokens
JustinTong0323 Apr 3, 2026
8a7c8de
Keep ngram verify() return value unchanged, read accept_length from v…
hnyls2002 Apr 4, 2026
a73397d
Merge branch 'main' into reasoning_tokens
hnyls2002 Apr 4, 2026
c3950cf
Simplify update_reasoning_tokens with index lookup
hnyls2002 Apr 4, 2026
ebffd0c
Cache think_end_id and extract _maybe_update_reasoning_tokens helper
hnyls2002 Apr 4, 2026
eddfedc
Add type hint for _maybe_update_reasoning_tokens
hnyls2002 Apr 4, 2026
976d07b
Fix CI suite name for reasoning usage tokens test
hnyls2002 Apr 4, 2026
5e01651
Remove AMD CI registration from reasoning usage tokens test
hnyls2002 Apr 4, 2026
4295505
Merge branch 'main' into reasoning_tokens
hnyls2002 Apr 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion python/sglang/srt/entrypoints/openai/serving_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ async def _generate_chat_stream(

# Usage tracking
prompt_tokens = {}
reasoning_tokens = {}
completion_tokens = {}
cached_tokens = {}
hidden_states = {}
Expand All @@ -670,6 +671,9 @@ async def _generate_chat_stream(
completion_tokens[index] = content["meta_info"].get(
"completion_tokens", 0
)
reasoning_tokens[index] = content["meta_info"].get(
"reasoning_tokens", 0
)
cached_tokens[index] = content["meta_info"].get("cached_tokens", 0)
hidden_states[index] = content["meta_info"].get("hidden_states", None)
routed_experts[index] = content["meta_info"].get("routed_experts", None)
Expand Down Expand Up @@ -752,6 +756,7 @@ async def _generate_chat_stream(
if continuous_usage_stats:
chunk.usage = UsageProcessor.calculate_token_usage(
prompt_tokens=prompt_tokens.get(index, 0),
reasoning_tokens=reasoning_tokens.get(index, 0),
completion_tokens=completion_tokens.get(index, 0),
)

Expand Down Expand Up @@ -805,6 +810,7 @@ async def _generate_chat_stream(
if continuous_usage_stats:
chunk.usage = UsageProcessor.calculate_token_usage(
prompt_tokens=prompt_tokens.get(index, 0),
reasoning_tokens=reasoning_tokens.get(index, 0),
completion_tokens=completion_tokens.get(index, 0),
)

Expand Down Expand Up @@ -885,8 +891,9 @@ async def _generate_chat_stream(
if include_usage:
usage = UsageProcessor.calculate_streaming_usage(
prompt_tokens,
reasoning_tokens,
completion_tokens,
cached_tokens,
cached_tokens=cached_tokens,
n_choices=request.n,
enable_cache_report=self.tokenizer_manager.server_args.enable_cache_report,
)
Expand Down Expand Up @@ -1356,9 +1363,11 @@ async def _process_tool_call_stream(
if continuous_usage_stats:
prompt_tokens = content["meta_info"].get("prompt_tokens", 0)
completion_tokens = content["meta_info"].get("completion_tokens", 0)
reasoning_tokens = content["meta_info"].get("reasoning_tokens", 0)
chunk.usage = UsageProcessor.calculate_token_usage(
prompt_tokens=prompt_tokens,
completion_tokens=completion_tokens,
reasoning_tokens=reasoning_tokens,
)

yield f"data: {chunk.model_dump_json()}\n\n"
Expand Down Expand Up @@ -1406,9 +1415,11 @@ async def _process_tool_call_stream(
if continuous_usage_stats:
prompt_tokens = content["meta_info"].get("prompt_tokens", 0)
completion_tokens = content["meta_info"].get("completion_tokens", 0)
reasoning_tokens = content["meta_info"].get("reasoning_tokens", 0)
chunk.usage = UsageProcessor.calculate_token_usage(
prompt_tokens=prompt_tokens,
completion_tokens=completion_tokens,
reasoning_tokens=reasoning_tokens,
)

yield f"data: {chunk.model_dump_json()}\n\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ async def _generate_completion_stream(
# Usage tracking
prompt_tokens = {}
completion_tokens = {}
reasoning_tokens = {}
cached_tokens = {}
hidden_states = {}
routed_experts = {}
Expand All @@ -241,6 +242,9 @@ async def _generate_completion_stream(
completion_tokens[index] = content["meta_info"].get(
"completion_tokens", 0
)
reasoning_tokens[index] = content["meta_info"].get(
"reasoning_tokens", 0
)
cached_tokens[index] = content["meta_info"].get("cached_tokens", 0)
hidden_states[index] = content["meta_info"].get("hidden_states", None)
routed_experts[index] = content["meta_info"].get("routed_experts", None)
Expand Down Expand Up @@ -328,6 +332,7 @@ async def _generate_completion_stream(
chunk.usage = UsageProcessor.calculate_token_usage(
prompt_tokens=prompt_tokens.get(index, 0),
completion_tokens=completion_tokens.get(index, 0),
reasoning_tokens=reasoning_tokens.get(index, 0),
)

yield f"data: {chunk.model_dump_json()}\n\n"
Expand Down Expand Up @@ -377,8 +382,9 @@ async def _generate_completion_stream(
if include_usage:
usage = UsageProcessor.calculate_streaming_usage(
prompt_tokens,
reasoning_tokens,
completion_tokens,
cached_tokens,
cached_tokens=cached_tokens,
n_choices=request.n,
enable_cache_report=self.tokenizer_manager.server_args.enable_cache_report,
)
Expand Down
12 changes: 11 additions & 1 deletion python/sglang/srt/entrypoints/openai/usage_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@ def calculate_response_usage(
completion_tokens = sum(
r["meta_info"].get("completion_tokens", 0) for r in responses
)

prompt_tokens = sum(
responses[i]["meta_info"].get("prompt_tokens", 0)
for i in range(0, len(responses), n_choices)
)

# some API don't have reasoning_tokens semantics
reasoning_tokens = sum(
r["meta_info"].get("reasoning_tokens", 0) for r in responses
)

cached_details = None
if enable_cache_report:
cached_total = sum(
Expand All @@ -39,13 +43,15 @@ def calculate_response_usage(

return UsageProcessor.calculate_token_usage(
prompt_tokens=prompt_tokens,
reasoning_tokens=reasoning_tokens,
completion_tokens=completion_tokens,
cached_tokens=cached_details,
)

@staticmethod
def calculate_streaming_usage(
prompt_tokens: Mapping[int, int],
reasoning_tokens: Mapping[int, int],
completion_tokens: Mapping[int, int],
cached_tokens: Mapping[int, int],
n_choices: int,
Expand All @@ -55,6 +61,7 @@ def calculate_streaming_usage(
total_prompt_tokens = sum(
tok for idx, tok in prompt_tokens.items() if idx % n_choices == 0
)
total_reasoning_tokens = sum(reasoning_tokens.values())
total_completion_tokens = sum(completion_tokens.values())

cached_details = (
Expand All @@ -67,6 +74,7 @@ def calculate_streaming_usage(

return UsageProcessor.calculate_token_usage(
prompt_tokens=total_prompt_tokens,
reasoning_tokens=total_reasoning_tokens,
completion_tokens=total_completion_tokens,
cached_tokens=cached_details,
)
Expand All @@ -75,6 +83,7 @@ def calculate_streaming_usage(
def calculate_token_usage(
prompt_tokens: int,
completion_tokens: int,
reasoning_tokens: Optional[int] = 0,
cached_tokens: Optional[PromptTokensDetails] = None,
) -> UsageInfo:
"""Calculate token usage information"""
Expand All @@ -83,4 +92,5 @@ def calculate_token_usage(
completion_tokens=completion_tokens,
total_tokens=prompt_tokens + completion_tokens,
prompt_tokens_details=cached_tokens,
reasoning_tokens=reasoning_tokens,
)
1 change: 1 addition & 0 deletions python/sglang/srt/managers/detokenizer_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ def handle_batch_token_id_out(self, recv_obj: BatchTokenIDOutput):
output_strs=output_strs,
output_ids=recv_obj.output_ids,
prompt_tokens=recv_obj.prompt_tokens,
reasoning_tokens=recv_obj.reasoning_tokens,
completion_tokens=recv_obj.completion_tokens,
cached_tokens=recv_obj.cached_tokens,
cached_tokens_details=recv_obj.cached_tokens_details,
Expand Down
2 changes: 2 additions & 0 deletions python/sglang/srt/managers/io_struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,7 @@ class BatchTokenIDOutput(BaseBatchReq, SpeculativeDecodingMetricsMixin):

# Token counts
prompt_tokens: List[int]
reasoning_tokens: List[int]
completion_tokens: List[int]
cached_tokens: List[int]

Expand Down Expand Up @@ -1036,6 +1037,7 @@ class BatchStrOutput(BaseBatchReq, SpeculativeDecodingMetricsMixin):
# Token counts
prompt_tokens: List[int]
completion_tokens: List[int]
reasoning_tokens: List[int]
cached_tokens: List[int]

# Logprobs
Expand Down
2 changes: 2 additions & 0 deletions python/sglang/srt/managers/multi_tokenizer_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ def _handle_output_by_index(output, i):
no_stop_trim=_extract_field_by_index(output, "no_stop_trim", i),
prompt_tokens=_extract_field_by_index(output, "prompt_tokens", i),
completion_tokens=_extract_field_by_index(output, "completion_tokens", i),
reasoning_tokens=_extract_field_by_index(output, "reasoning_tokens", i),
cached_tokens=_extract_field_by_index(output, "cached_tokens", i),
cached_tokens_details=_extract_field_by_index(
output, "cached_tokens_details", i
Expand Down Expand Up @@ -224,6 +225,7 @@ def _handle_output_by_index(output, i):
output_ids=_extract_field_by_index(output, "output_ids", i),
prompt_tokens=_extract_field_by_index(output, "prompt_tokens", i),
completion_tokens=_extract_field_by_index(output, "completion_tokens", i),
reasoning_tokens=_extract_field_by_index(output, "reasoning_tokens", i),
cached_tokens=_extract_field_by_index(output, "cached_tokens", i),
input_token_logprobs_val=_extract_field_by_index(
output, "input_token_logprobs_val", i, check_length=False
Expand Down
20 changes: 19 additions & 1 deletion python/sglang/srt/managers/schedule_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,9 +634,13 @@ def __init__(
# For multi-http worker
self.http_worker_ipc = http_worker_ipc

# Require reasoning for the request (hybrid reasoning model only)
# Require reasoning for the request
self.require_reasoning = require_reasoning

# State indicating whether the reasoning phase has finished (only meaningful when require_reasoning is True)
self._is_reasoning_over = False
self.reasoning_tokens = 0
Comment thread
Muqi1029 marked this conversation as resolved.

# Sampling info
if isinstance(sampling_params.custom_params, dict):
sampling_params = copy.copy(sampling_params)
Expand Down Expand Up @@ -1276,6 +1280,20 @@ def set_finish_with_abort(self, error_msg: str):
error_msg, HTTPStatus.BAD_REQUEST, "BadRequestError"
)

def update_reasoning_tokens(self, token_id, think_end_id):
if self._is_reasoning_over:
return

if not isinstance(token_id, list):
token_id = [token_id]

try:
end_pos = token_id.index(think_end_id)
self.reasoning_tokens += end_pos + 1
self._is_reasoning_over = True
except ValueError:
self.reasoning_tokens += len(token_id)

def __repr__(self):
return (
f"Req(rid={self.rid}, "
Expand Down
3 changes: 3 additions & 0 deletions python/sglang/srt/managers/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,9 @@ def init_tokenizer(self):
self.tokenizer.think_end_id = self.tokenizer.encode(
reasoning_parser.detector.think_end_token, add_special_tokens=False
)[0]
self._think_end_id = self.tokenizer.think_end_id
else:
self._think_end_id = None

def init_mamba_backend(self) -> None:
initialize_mamba_selective_state_update_backend(self.server_args)
Expand Down
Loading
Loading