From 46a87f26688e9b0155e677b2434afef2e32555e8 Mon Sep 17 00:00:00 2001 From: Lianmin Zheng Date: Fri, 27 Mar 2026 21:14:07 -0700 Subject: [PATCH 1/6] clean up detokenizer --- python/sglang/srt/managers/detokenizer_manager.py | 12 ++++-------- python/sglang/srt/utils/common.py | 5 +---- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/python/sglang/srt/managers/detokenizer_manager.py b/python/sglang/srt/managers/detokenizer_manager.py index 17972005ffed..97f30cfe7723 100644 --- a/python/sglang/srt/managers/detokenizer_manager.py +++ b/python/sglang/srt/managers/detokenizer_manager.py @@ -88,9 +88,6 @@ def __init__( # Init running status self.init_running_status(server_args) - if server_args.enable_metrics: - start_cpu_monitor_thread("detokenizer") - # Init dispatcher self.init_request_dispatcher() @@ -120,9 +117,8 @@ def init_tokenizer(self, server_args: ServerArgs): def init_running_status(self, server_args: ServerArgs): self.decode_status = LimitedCapacityDict(capacity=DETOKENIZER_MAX_STATES) - self.is_dummy = False - self.is_tool_call_parser_gpt_oss = server_args.tool_call_parser == "gpt-oss" self.disable_tokenizer_batch_decode = server_args.disable_tokenizer_batch_decode + self.is_tool_call_parser_gpt_oss = server_args.tool_call_parser == "gpt-oss" self.soft_watchdog = Watchdog.create( debug_name="DetokenizerManager", @@ -131,6 +127,9 @@ def init_running_status(self, server_args: ServerArgs): test_stuck_time=envs.SGLANG_TEST_STUCK_DETOKENIZER.get(), ) + if server_args.enable_metrics: + start_cpu_monitor_thread("detokenizer") + def init_request_dispatcher(self): self._request_dispatcher = TypeBasedDispatcher( [ @@ -404,9 +403,6 @@ def handle_batch_token_id_out(self, recv_obj: BatchTokenIDOutput): time_stats=recv_obj.time_stats, ) - def handle_multimodal_decode_req(self, recv_obj: BatchMultimodalDecodeReq): - raise NotImplementedError() - def handle_freeze_gc_req(self, recv_req: FreezeGCReq): freeze_gc("Detokenizer Manager") return None diff --git a/python/sglang/srt/utils/common.py b/python/sglang/srt/utils/common.py index e3b737e7eb8c..2b0af457d53e 100644 --- a/python/sglang/srt/utils/common.py +++ b/python/sglang/srt/utils/common.py @@ -24,6 +24,7 @@ import inspect import io import itertools +import gc import json import logging import math @@ -2945,8 +2946,6 @@ def gc_callback(phase, info): def freeze_gc(context: str): - import gc - g0_before, g1_before, g2_before = gc_object_counts() gc.freeze() g0_after, g1_after, g2_after = gc_object_counts() @@ -2961,8 +2960,6 @@ def freeze_gc(context: str): def configure_gc_logger(): logger.info("Enable GC Logger") - import gc - gc_start_time = {} def gc_callback(phase, info): From 7480743851006c13ccc490846ec301ffd980f5af Mon Sep 17 00:00:00 2001 From: Lianmin Zheng Date: Fri, 27 Mar 2026 21:48:12 -0700 Subject: [PATCH 2/6] Use HEALTH_CHECK_RID_PREFIX constant and remove dead is_multimodal_gen code Replace all hardcoded "HEALTH_CHECK" strings with the HEALTH_CHECK_RID_PREFIX constant from sglang.srt.constants. Also remove all is_multimodal_gen branches in python/sglang/srt since is_multimodal_gen=True is never used. Co-Authored-By: Claude Opus 4.6 (1M context) --- python/sglang/srt/constants.py | 2 ++ python/sglang/srt/entrypoints/http_server.py | 3 ++- python/sglang/srt/managers/scheduler.py | 3 ++- .../managers/scheduler_output_processor_mixin.py | 16 ++-------------- python/sglang/srt/managers/tokenizer_manager.py | 1 - .../observability/request_metrics_exporter.py | 3 ++- python/sglang/srt/utils/request_logger.py | 14 ++++---------- .../bench_fn/test_bench_serving_functionality.py | 3 ++- .../test_request_metrics_exporter.py | 3 ++- test/registered/utils/test_request_logger.py | 3 ++- 10 files changed, 20 insertions(+), 31 deletions(-) diff --git a/python/sglang/srt/constants.py b/python/sglang/srt/constants.py index c9da6b6bb1d5..76d3b1cd3ad5 100644 --- a/python/sglang/srt/constants.py +++ b/python/sglang/srt/constants.py @@ -8,3 +8,5 @@ GPU_MEMORY_TYPE_WEIGHTS, GPU_MEMORY_TYPE_CUDA_GRAPH, ] + +HEALTH_CHECK_RID_PREFIX = "HEALTH_CHECK" diff --git a/python/sglang/srt/entrypoints/http_server.py b/python/sglang/srt/entrypoints/http_server.py index eeefe3f9ba53..8a47f0dfeadc 100644 --- a/python/sglang/srt/entrypoints/http_server.py +++ b/python/sglang/srt/entrypoints/http_server.py @@ -59,6 +59,7 @@ from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import ORJSONResponse, Response, StreamingResponse +from sglang.srt.constants import HEALTH_CHECK_RID_PREFIX from sglang.srt.disaggregation.utils import FAKE_BOOTSTRAP_HOST, DisaggregationMode from sglang.srt.entrypoints.anthropic.protocol import ( AnthropicCountTokensRequest, @@ -509,7 +510,7 @@ async def health_generate(request: Request) -> Response: return Response(status_code=200) sampling_params = {"max_new_tokens": 1, "temperature": 0.0} - rid = f"HEALTH_CHECK_{time.time()}" + rid = f"{HEALTH_CHECK_RID_PREFIX}_{time.time()}" if _global_state.tokenizer_manager.is_image_gen: gri = _global_state.tokenizer_manager.get_image_gen_health_check_request( diff --git a/python/sglang/srt/managers/scheduler.py b/python/sglang/srt/managers/scheduler.py index 60043fc49b27..58aee70c1414 100644 --- a/python/sglang/srt/managers/scheduler.py +++ b/python/sglang/srt/managers/scheduler.py @@ -39,6 +39,7 @@ from sglang.jit_kernel.ngram_embedding import update_token_table from sglang.srt.configs.model_config import ModelConfig +from sglang.srt.constants import HEALTH_CHECK_RID_PREFIX from sglang.srt.constrained.grammar_manager import GrammarManager from sglang.srt.disaggregation.decode import ( DecodePreallocQueue, @@ -3406,7 +3407,7 @@ def maybe_sleep(self): def is_health_check_generate_req(recv_req): rid = getattr(recv_req, "rid", None) - return rid is not None and rid.startswith("HEALTH_CHECK") + return rid is not None and rid.startswith(HEALTH_CHECK_RID_PREFIX) def is_work_request(recv_req): diff --git a/python/sglang/srt/managers/scheduler_output_processor_mixin.py b/python/sglang/srt/managers/scheduler_output_processor_mixin.py index 7b8c9211bb71..570cc81c2db0 100644 --- a/python/sglang/srt/managers/scheduler_output_processor_mixin.py +++ b/python/sglang/srt/managers/scheduler_output_processor_mixin.py @@ -953,10 +953,6 @@ def stream_output_generation( if req is skip_req: continue - # Multimodal partial stream chunks break the detokenizer, so drop aborted requests here. - if self.model_config.is_multimodal_gen and req.to_finish: - continue - if req.finished(): if req.finished_output: # With the overlap schedule, a request will try to output twice and hit this line twice @@ -975,8 +971,7 @@ def stream_output_generation( # origin stream_interval logic should_output = ( len(req.output_ids) % stream_interval == 1 - if not self.model_config.is_multimodal_gen - and stream_interval > 1 + if stream_interval > 1 else len(req.output_ids) % stream_interval == 0 ) @@ -986,8 +981,6 @@ def stream_output_generation( else: should_output = ( len(req.output_ids) % DEFAULT_FORCE_STREAM_INTERVAL == 0 - if not self.model_config.is_multimodal_gen - else False ) if should_output: @@ -1003,10 +996,7 @@ def stream_output_generation( decoded_texts.append(req.decoded_text) decode_ids, read_offset = req.init_incremental_detokenize() - if self.model_config.is_multimodal_gen: - decode_ids_list.append(decode_ids) - else: - decode_ids_list.append(decode_ids[req.send_decode_id_offset :]) + decode_ids_list.append(decode_ids[req.send_decode_id_offset :]) # Exclude the tokens after stop condition output_ids_ = req.output_ids_through_stop @@ -1132,8 +1122,6 @@ def stream_output_generation( # Send to detokenizer if reqs or is_idle_batch: - if self.model_config.is_multimodal_gen: - return self.send_to_detokenizer.send_output( BatchTokenIDOutput( rids=rids, diff --git a/python/sglang/srt/managers/tokenizer_manager.py b/python/sglang/srt/managers/tokenizer_manager.py index 810165e0fa3f..f2ffb6be3b72 100644 --- a/python/sglang/srt/managers/tokenizer_manager.py +++ b/python/sglang/srt/managers/tokenizer_manager.py @@ -1194,7 +1194,6 @@ async def _wait_one_response( self.request_logger.log_finished_request( obj, out, - is_multimodal_gen=self.model_config.is_multimodal_gen, request=request, ) diff --git a/python/sglang/srt/observability/request_metrics_exporter.py b/python/sglang/srt/observability/request_metrics_exporter.py index ca4db1a9b6ff..14ece7498a6a 100644 --- a/python/sglang/srt/observability/request_metrics_exporter.py +++ b/python/sglang/srt/observability/request_metrics_exporter.py @@ -7,6 +7,7 @@ from datetime import datetime from typing import List, Optional, Union +from sglang.srt.constants import HEALTH_CHECK_RID_PREFIX from sglang.srt.managers.io_struct import EmbeddingReqInput, GenerateReqInput from sglang.srt.server_args import ServerArgs @@ -128,7 +129,7 @@ async def write_record( self, obj: Union[GenerateReqInput, EmbeddingReqInput], out_dict: dict ): # Do not log health check requests, since they don't represent real user requests. - if isinstance(obj.rid, str) and "HEALTH_CHECK" in obj.rid: + if isinstance(obj.rid, str) and HEALTH_CHECK_RID_PREFIX in obj.rid: return try: diff --git a/python/sglang/srt/utils/request_logger.py b/python/sglang/srt/utils/request_logger.py index e20a19a91625..4ce4585ad072 100644 --- a/python/sglang/srt/utils/request_logger.py +++ b/python/sglang/srt/utils/request_logger.py @@ -162,7 +162,6 @@ def log_finished_request( self, obj: Union["GenerateReqInput", "EmbeddingReqInput"], out: Any, - is_multimodal_gen: bool = False, request: Optional["fastapi.Request"] = None, ) -> None: if not self.log_requests: @@ -181,20 +180,15 @@ def log_finished_request( } if headers: log_data["headers"] = headers - if not is_multimodal_gen: - log_data["out"] = _transform_data_for_logging( - out, max_length, out_skip_names - ) + log_data["out"] = _transform_data_for_logging( + out, max_length, out_skip_names + ) log_json(self.targets, "request.finished", log_data) else: obj_str = _dataclass_to_string_truncated( obj, max_length, skip_names=skip_names ) - out_str = ( - "" - if is_multimodal_gen - else f", out={_dataclass_to_string_truncated(out, max_length, skip_names=out_skip_names)}" - ) + out_str = f", out={_dataclass_to_string_truncated(out, max_length, skip_names=out_skip_names)}" headers_str = f", headers={headers}" if headers else "" self._log(f"Finish: obj={obj_str}{headers_str}{out_str}") diff --git a/test/registered/bench_fn/test_bench_serving_functionality.py b/test/registered/bench_fn/test_bench_serving_functionality.py index 564fdee29252..f573319c7e84 100644 --- a/test/registered/bench_fn/test_bench_serving_functionality.py +++ b/test/registered/bench_fn/test_bench_serving_functionality.py @@ -8,6 +8,7 @@ from sglang.bench_serving import run_benchmark from sglang.benchmark.utils import parse_custom_headers +from sglang.srt.constants import HEALTH_CHECK_RID_PREFIX from sglang.srt.utils import kill_process_tree from sglang.test.ci.ci_register import register_amd_ci, register_cuda_ci from sglang.test.test_utils import ( @@ -80,7 +81,7 @@ def _verify_multi_turn_logs(self, content: str): continue text = obj.get("obj", {}).get("text") rid = obj.get("rid", "") - if text and not rid.startswith("HEALTH_CHECK"): + if text and not rid.startswith(HEALTH_CHECK_RID_PREFIX): reqs.append(text) self.assertGreaterEqual(len(reqs), NUM_CONVERSATIONS * NUM_TURNS) diff --git a/test/registered/unit/observability/test_request_metrics_exporter.py b/test/registered/unit/observability/test_request_metrics_exporter.py index f808f3f7c682..22a4496fa394 100644 --- a/test/registered/unit/observability/test_request_metrics_exporter.py +++ b/test/registered/unit/observability/test_request_metrics_exporter.py @@ -58,6 +58,7 @@ def __init__(self, **kwargs): import unittest from unittest.mock import MagicMock, patch +from sglang.srt.constants import HEALTH_CHECK_RID_PREFIX from sglang.srt.observability.request_metrics_exporter import ( FileRequestMetricsExporter, RequestMetricsExporter, @@ -243,7 +244,7 @@ def test_write_record(self): def test_write_record_skips_health_check(self): exporter = self._make_exporter() - obj = _GenerateReqInput(rid="HEALTH_CHECK_123", text="ping") + obj = _GenerateReqInput(rid=f"{HEALTH_CHECK_RID_PREFIX}_123", text="ping") asyncio.run(exporter.write_record(obj, {})) files = os.listdir(self.tmp_dir) diff --git a/test/registered/utils/test_request_logger.py b/test/registered/utils/test_request_logger.py index 28af9f9495c0..c87a88448c09 100644 --- a/test/registered/utils/test_request_logger.py +++ b/test/registered/utils/test_request_logger.py @@ -8,6 +8,7 @@ import requests +from sglang.srt.constants import HEALTH_CHECK_RID_PREFIX from sglang.srt.utils import kill_process_tree from sglang.test.ci.ci_register import register_amd_ci, register_cuda_ci from sglang.test.test_utils import ( @@ -197,7 +198,7 @@ def _verify_logs(self, content: str, source_name: str): continue rid = data.get("rid", "") - if rid.startswith("HEALTH_CHECK"): + if rid.startswith(HEALTH_CHECK_RID_PREFIX): continue if data.get("event") == "request.received": From a1ecd0ea6eb63ece792bffde86ae3aecaec4df8e Mon Sep 17 00:00:00 2001 From: Lianmin Zheng Date: Fri, 27 Mar 2026 21:49:22 -0700 Subject: [PATCH 3/6] Remove dead is_multimodal_gen/is_image_gen from model_config and clean up detokenizer - Remove is_multimodal_gen and is_image_gen attributes and their stub functions from ModelConfig since they always return False - Clean up detokenizer: remove health-check special-casing, dummy-weights branch, unnecessary assert, and dead handle_multimodal_decode_req method Co-Authored-By: Claude Opus 4.6 (1M context) --- python/sglang/srt/configs/model_config.py | 14 ---- .../srt/managers/detokenizer_manager.py | 69 +++++++------------ 2 files changed, 26 insertions(+), 57 deletions(-) diff --git a/python/sglang/srt/configs/model_config.py b/python/sglang/srt/configs/model_config.py index a57cc863f6db..9d60ea675724 100644 --- a/python/sglang/srt/configs/model_config.py +++ b/python/sglang/srt/configs/model_config.py @@ -178,12 +178,6 @@ def __init__( self.is_multimodal = enable_multimodal and is_multimodal_model( self.hf_config.architectures ) - self.is_multimodal_gen = enable_multimodal and is_multimodal_gen_model( - self.hf_config.architectures - ) - self.is_image_gen = enable_multimodal and is_image_gen_model( - self.hf_config.architectures - ) self.is_audio_model = enable_multimodal and is_audio_model( self.hf_config.architectures ) @@ -1351,14 +1345,6 @@ def is_multimodal_model(model_architectures: List[str]): return False -def is_multimodal_gen_model(model_architectures: List[str]): - return False - - -def is_image_gen_model(model_architectures: List[str]): - return False - - def is_audio_model(model_architectures: List[str]): models = [ "WhisperForConditionalGeneration", diff --git a/python/sglang/srt/managers/detokenizer_manager.py b/python/sglang/srt/managers/detokenizer_manager.py index 97f30cfe7723..23f8845c4c00 100644 --- a/python/sglang/srt/managers/detokenizer_manager.py +++ b/python/sglang/srt/managers/detokenizer_manager.py @@ -26,6 +26,7 @@ import zmq from sglang.srt.environ import envs +from sglang.srt.constants import HEALTH_CHECK_RID_PREFIX from sglang.srt.managers.io_struct import ( BatchEmbeddingOutput, BatchMultimodalDecodeReq, @@ -91,10 +92,6 @@ def __init__( # Init dispatcher self.init_request_dispatcher() - @staticmethod - def is_health_check_request(rid: Optional[str]) -> bool: - return isinstance(rid, str) and rid.startswith("HEALTH_CHECK") - def init_ipc_channels(self, port_args: PortArgs): context = zmq.Context(2) self.recv_from_scheduler = get_zmq_socket( @@ -189,8 +186,6 @@ def _grouped_batch_decode( ) -> List[str]: """Batch decode with grouping by (skip_special_tokens, spaces_between_special_tokens).""" - assert self.tokenizer is not None - # fast path first_skip, first_space = skip_list[0], space_list[0] if all(s == first_skip for s in skip_list) and all( @@ -235,9 +230,6 @@ def _decode_batch_token_id_output(self, recv_obj: BatchTokenIDOutput): surr_offset=0, read_offset=recv_obj.read_offsets[i], ) - if not self.is_health_check_request(rid): - # for health check requests, we do not store the decode status - self.decode_status[rid] = s else: s = self.decode_status[rid] s.decode_ids.extend(recv_obj.decode_ids[i]) @@ -253,22 +245,16 @@ def _decode_batch_token_id_output(self, recv_obj: BatchTokenIDOutput): # Decode token ids to strings if not self.disable_tokenizer_batch_decode: - if not self.is_dummy: - # Run normal batch decode - surr_texts = self._grouped_batch_decode( - surr_ids, - recv_obj.skip_special_tokens, - recv_obj.spaces_between_special_tokens, - ) - read_texts = self._grouped_batch_decode( - read_ids, - recv_obj.skip_special_tokens, - recv_obj.spaces_between_special_tokens, - ) - else: - # If it is dummy weights, just return dummy strings to prevent potential detokenization edge cases - surr_texts = ["dog" for _ in surr_ids] - read_texts = ["cat" for _ in read_ids] + surr_texts = self._grouped_batch_decode( + surr_ids, + recv_obj.skip_special_tokens, + recv_obj.spaces_between_special_tokens, + ) + read_texts = self._grouped_batch_decode( + read_ids, + recv_obj.skip_special_tokens, + recv_obj.spaces_between_special_tokens, + ) else: # Do not use batch decode to prevent some detokenization edge cases (e.g., gpt-oss). surr_texts = [ @@ -296,25 +282,17 @@ def _decode_batch_token_id_output(self, recv_obj: BatchTokenIDOutput): output_strs = [] for i in range(bs): rid = recv_obj.rids[i] - if self.is_health_check_request(rid): - s = DecodeStatus( - decoded_text=recv_obj.decoded_texts[i], - decode_ids=recv_obj.decode_ids[i], - surr_offset=0, - read_offset=recv_obj.read_offsets[i], + try: + s = self.decode_status[rid] + except KeyError: + raise RuntimeError( + f"Decode status not found for request {rid}. " + "It may be due to the request being evicted from the decode status due to memory pressure. " + "Please increase the maximum number of requests by setting " + "the SGLANG_DETOKENIZER_MAX_STATES environment variable to a bigger value than the default value. " + f"The current value is {DETOKENIZER_MAX_STATES}. " + "For more details, see: https://github.com/sgl-project/sglang/issues/2812" ) - else: - try: - s = self.decode_status[rid] - except KeyError: - raise RuntimeError( - f"Decode status not found for request {rid}. " - "It may be due to the request being evicted from the decode status due to memory pressure. " - "Please increase the maximum number of requests by setting " - "the SGLANG_DETOKENIZER_MAX_STATES environment variable to a bigger value than the default value. " - f"The current value is {DETOKENIZER_MAX_STATES}. " - "For more details, see: https://github.com/sgl-project/sglang/issues/2812" - ) new_text = read_texts[i][len(surr_texts[i]) :] if recv_obj.finished_reasons[i] is None: # Streaming chunk: update the decode status @@ -334,6 +312,7 @@ def _decode_batch_token_id_output(self, recv_obj: BatchTokenIDOutput): recv_obj.finished_reasons[i], recv_obj.no_stop_trim[i], ) + # Incrementally send text. incremental_output = output_str[s.sent_offset :] s.sent_offset = len(output_str) @@ -408,6 +387,10 @@ def handle_freeze_gc_req(self, recv_req: FreezeGCReq): return None +def is_health_check_request(rid: Optional[str]) -> bool: + return isinstance(rid, str) and rid.startswith(HEALTH_CHECK_RID_PREFIX) + + class LimitedCapacityDict(OrderedDict): def __init__(self, capacity: int, *args, **kwargs): super().__init__(*args, **kwargs) From 2f18024a497a51dc54554cb8c59f554f28c578d1 Mon Sep 17 00:00:00 2001 From: Lianmin Zheng Date: Fri, 27 Mar 2026 22:33:17 -0700 Subject: [PATCH 4/6] Fix missing handle_multimodal_decode_req and isort import ordering Remove leftover dispatcher entry for handle_multimodal_decode_req that was deleted in the cleanup, and fix import sort order in detokenizer_manager.py and common.py to pass isort CI checks. Co-Authored-By: Claude Opus 4.6 (1M context) --- python/sglang/srt/managers/detokenizer_manager.py | 4 +--- python/sglang/srt/utils/common.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/python/sglang/srt/managers/detokenizer_manager.py b/python/sglang/srt/managers/detokenizer_manager.py index 23f8845c4c00..090fac1b2f0b 100644 --- a/python/sglang/srt/managers/detokenizer_manager.py +++ b/python/sglang/srt/managers/detokenizer_manager.py @@ -25,11 +25,10 @@ import setproctitle import zmq -from sglang.srt.environ import envs from sglang.srt.constants import HEALTH_CHECK_RID_PREFIX +from sglang.srt.environ import envs from sglang.srt.managers.io_struct import ( BatchEmbeddingOutput, - BatchMultimodalDecodeReq, BatchStrOutput, BatchTokenIDOutput, FreezeGCReq, @@ -132,7 +131,6 @@ def init_request_dispatcher(self): [ (BatchEmbeddingOutput, self.handle_batch_embedding_out), (BatchTokenIDOutput, self.handle_batch_token_id_out), - (BatchMultimodalDecodeReq, self.handle_multimodal_decode_req), (FreezeGCReq, self.handle_freeze_gc_req), ] ) diff --git a/python/sglang/srt/utils/common.py b/python/sglang/srt/utils/common.py index 2b0af457d53e..9090b6c942f0 100644 --- a/python/sglang/srt/utils/common.py +++ b/python/sglang/srt/utils/common.py @@ -20,11 +20,11 @@ import builtins import ctypes import functools +import gc import importlib import inspect import io import itertools -import gc import json import logging import math From 3afc27ec448f796ea8290c86bbca26cc513de46e Mon Sep 17 00:00:00 2001 From: Lianmin Zheng Date: Sat, 28 Mar 2026 05:57:57 +0000 Subject: [PATCH 5/6] Fix AttributeError for removed is_image_gen on ModelConfig Use getattr with default False since is_image_gen was removed from ModelConfig in a1ecd0ea6 but tokenizer_manager still referenced it. Co-Authored-By: Claude Opus 4.6 (1M context) --- python/sglang/srt/managers/tokenizer_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/sglang/srt/managers/tokenizer_manager.py b/python/sglang/srt/managers/tokenizer_manager.py index f2ffb6be3b72..1d52c9013cf2 100644 --- a/python/sglang/srt/managers/tokenizer_manager.py +++ b/python/sglang/srt/managers/tokenizer_manager.py @@ -231,7 +231,7 @@ def init_model_config(self): self.served_model_name = server_args.served_model_name self.model_config = model_config_class.from_server_args(server_args) self.is_generation = self.model_config.is_generation - self.is_image_gen = self.model_config.is_image_gen + self.is_image_gen = getattr(self.model_config, "is_image_gen", False) self.context_len = self.model_config.context_len self.image_token_id = self.model_config.image_token_id self.max_req_input_len = None # Will be set later in engine.py From fc0f9c767b2e7ce98cbb7046b5efe1720cfc6afd Mon Sep 17 00:00:00 2001 From: Lianmin Zheng Date: Sat, 28 Mar 2026 19:27:09 -0700 Subject: [PATCH 6/6] Store newly created decode status in decode_status dict Co-Authored-By: Claude Opus 4.6 (1M context) --- python/sglang/srt/managers/detokenizer_manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/sglang/srt/managers/detokenizer_manager.py b/python/sglang/srt/managers/detokenizer_manager.py index 090fac1b2f0b..30f804bea20d 100644 --- a/python/sglang/srt/managers/detokenizer_manager.py +++ b/python/sglang/srt/managers/detokenizer_manager.py @@ -228,6 +228,7 @@ def _decode_batch_token_id_output(self, recv_obj: BatchTokenIDOutput): surr_offset=0, read_offset=recv_obj.read_offsets[i], ) + self.decode_status[rid] = s else: s = self.decode_status[rid] s.decode_ids.extend(recv_obj.decode_ids[i])