Add Inkling model support (#31681)

Co-authored-by: Chunan Zeng <zcnrex@gmail.com>
Co-authored-by: Ke Bao <ispobaoke@gmail.com>
Co-authored-by: Yanbin Jiang <jybsuper@gmail.com>
Co-authored-by: Yuhao Yang <47235274+yhyang201@users.noreply.github.com>
Co-authored-by: Qiaolin Yu <qiaolin.yu@radixark.ai>
Co-authored-by: Zhichen Zeng <zczeng@uw.edu>
Co-authored-by: Aurick Qiao <aurick@thinkingmachines.ai>
Co-authored-by: Joseph <jk@thinkingmachines.ai>
This commit is contained in:
Cheng Wan
2026-07-19 22:57:37 -07:00
committed by GitHub
co-authored by Chunan Zeng Ke Bao Yanbin Jiang Yuhao Yang Qiaolin Yu Zhichen Zeng Aurick Qiao Joseph
parent 829e9ce9d5
commit 02236fa38c
279 changed files with 74334 additions and 931 deletions
@@ -9,6 +9,7 @@ from sglang.srt.parser.reasoning_parser import (
Gemma4Detector,
Glm45Detector,
HunyuanDetector,
InklingDetector,
KimiDetector,
KimiK2Detector,
Nemotron3Detector,
@@ -166,6 +167,89 @@ class TestQwen3Detector(CustomTestCase):
self.assertEqual(result.reasoning_text, "")
class TestInklingDetector(CustomTestCase):
def test_streaming_routes_blocks_across_all_string_boundaries(self):
detector = InklingDetector()
source = (
"<|message_model|><|content_thinking|>think<|end_message|>"
"<|message_model|><|content_text|>answer<|end_message|>"
"<|content_model_end_sampling|>"
)
reasoning = ""
content = ""
for char in source:
result = detector.parse_streaming_increment(char)
reasoning += result.reasoning_text
content += result.normal_text
self.assertEqual(reasoning, "think")
self.assertEqual(content, "answer")
def test_tool_header_is_preserved_for_the_tool_parser(self):
detector = InklingDetector()
source = (
"<|message_model|>weather<|content_invoke_tool_json|>"
'{"name":"weather","args":{"city":"SF"}}<|end_message|>'
)
content = ""
for char in source:
content += detector.parse_streaming_increment(char).normal_text
self.assertEqual(content, source)
def test_quoted_message_model_token_inside_content_is_preserved(self):
"""Bug regression: the header branch flipped to header state on ANY
<|message_model|> occurrence, so a literal token the model wrote
inside a content block (e.g. quoting the protocol) silently swallowed
all payload text up to the next control token."""
detector = InklingDetector()
source = (
"<|message_model|><|content_text|>Header token: <|message_model|>"
" then more text<|end_message|>"
)
result = detector.detect_and_parse(source)
self.assertEqual(
result.normal_text, "Header token: <|message_model|> then more text"
)
def test_control_token_inside_tool_header_shares_the_full_alphabet(self):
"""Bug regression: the tool-call detector validated headers against
INKLING_SPECIAL_TOKENS while the reasoning parser keyed on the larger
control alphabet (+ <|model_trigger_generation|>), so a control token
smuggled inside a header passed one machine and not the other."""
from sglang.srt.function_call.inkling_detector import (
InklingDetector as ToolDetector,
)
detector = ToolDetector()
prefix, name = detector._split_trailing_tool_header(
"<|message_model|>weather<|model_trigger_generation|>"
)
self.assertIsNone(name)
def test_continuation_stream_text_survives_chunk_boundaries(self):
"""Bug regression: text arriving with no open block (a
continue_final_message stream resumes MID text block) was routed to
content only when a chunk held no control token; a chunk like
'ld<|end_message|>' silently dropped the 'ld'. All out-of-block text
must reach content regardless of chunking."""
source = (
" world<|end_message|><|message_model|><|content_text|>next<|end_message|>"
)
for chunks in (
[source],
[
" wor",
"ld<|end_message|>",
"<|message_model|><|content_text|>next<|end_message|>",
],
list(source),
):
detector = InklingDetector()
content = ""
for chunk in chunks:
content += detector.parse_streaming_increment(chunk).normal_text
self.assertEqual(content, " worldnext", msg=f"chunks={chunks!r}")
class TestKimiDetector(CustomTestCase):
def setUp(self):
self.detector = KimiDetector()