Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
change
sglang
Commits
466992b2
Unverified
Commit
466992b2
authored
Oct 06, 2025
by
Chang Su
Committed by
GitHub
Oct 06, 2025
Browse files
[router][tool call] Clean up redundant `detect_format` and `has_tool_markers` (#11270)
parent
155cbb51
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
52 additions
and
93 deletions
+52
-93
sgl-router/src/routers/grpc/pd_router.rs
sgl-router/src/routers/grpc/pd_router.rs
+1
-1
sgl-router/src/routers/grpc/router.rs
sgl-router/src/routers/grpc/router.rs
+1
-1
sgl-router/src/tool_parser/parsers/deepseek_parser.rs
sgl-router/src/tool_parser/parsers/deepseek_parser.rs
+2
-7
sgl-router/src/tool_parser/parsers/glm4_moe_parser.rs
sgl-router/src/tool_parser/parsers/glm4_moe_parser.rs
+2
-7
sgl-router/src/tool_parser/parsers/gpt_oss_harmony_parser.rs
sgl-router/src/tool_parser/parsers/gpt_oss_harmony_parser.rs
+1
-1
sgl-router/src/tool_parser/parsers/gpt_oss_parser.rs
sgl-router/src/tool_parser/parsers/gpt_oss_parser.rs
+2
-7
sgl-router/src/tool_parser/parsers/json_parser.rs
sgl-router/src/tool_parser/parsers/json_parser.rs
+1
-1
sgl-router/src/tool_parser/parsers/kimik2_parser.rs
sgl-router/src/tool_parser/parsers/kimik2_parser.rs
+2
-7
sgl-router/src/tool_parser/parsers/llama_parser.rs
sgl-router/src/tool_parser/parsers/llama_parser.rs
+1
-1
sgl-router/src/tool_parser/parsers/mistral_parser.rs
sgl-router/src/tool_parser/parsers/mistral_parser.rs
+2
-7
sgl-router/src/tool_parser/parsers/pythonic_parser.rs
sgl-router/src/tool_parser/parsers/pythonic_parser.rs
+1
-1
sgl-router/src/tool_parser/parsers/qwen_parser.rs
sgl-router/src/tool_parser/parsers/qwen_parser.rs
+3
-13
sgl-router/src/tool_parser/parsers/step3_parser.rs
sgl-router/src/tool_parser/parsers/step3_parser.rs
+2
-7
sgl-router/src/tool_parser/tests.rs
sgl-router/src/tool_parser/tests.rs
+6
-6
sgl-router/src/tool_parser/traits.rs
sgl-router/src/tool_parser/traits.rs
+1
-1
sgl-router/tests/tool_parser_deepseek.rs
sgl-router/tests/tool_parser_deepseek.rs
+5
-5
sgl-router/tests/tool_parser_glm4_moe.rs
sgl-router/tests/tool_parser_glm4_moe.rs
+5
-5
sgl-router/tests/tool_parser_gpt_oss.rs
sgl-router/tests/tool_parser_gpt_oss.rs
+6
-6
sgl-router/tests/tool_parser_json.rs
sgl-router/tests/tool_parser_json.rs
+3
-3
sgl-router/tests/tool_parser_kimik2.rs
sgl-router/tests/tool_parser_kimik2.rs
+5
-6
No files found.
sgl-router/src/routers/grpc/pd_router.rs
View file @
466992b2
...
...
@@ -1859,7 +1859,7 @@ impl GrpcPDRouter {
// Check format detection first
let
can_parse
=
{
let
parser
=
pooled_parser
.lock
()
.await
;
parser
.
detect_format
(
processed_text
)
parser
.
has_tool_markers
(
processed_text
)
// Lock is dropped here
};
...
...
sgl-router/src/routers/grpc/router.rs
View file @
466992b2
...
...
@@ -306,7 +306,7 @@ impl GrpcRouter {
// Check format detection first
let
can_parse
=
{
let
parser
=
pooled_parser
.lock
()
.await
;
parser
.
detect_format
(
processed_text
)
parser
.
has_tool_markers
(
processed_text
)
// Lock is dropped here
};
...
...
sgl-router/src/tool_parser/parsers/deepseek_parser.rs
View file @
466992b2
...
...
@@ -77,11 +77,6 @@ impl DeepSeekParser {
}
}
/// Check if text contains DeepSeek tool markers
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"<|tool▁calls▁begin|>"
)
}
/// Parse a single tool call block - throws error if parsing fails
fn
parse_tool_call
(
&
self
,
block
:
&
str
)
->
ToolParserResult
<
ToolCall
>
{
let
captures
=
self
.func_detail_extractor
.captures
(
block
)
.ok_or_else
(||
{
...
...
@@ -312,8 +307,8 @@ impl ToolParser for DeepSeekParser {
})
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
self
.has_tool_markers
(
text
)
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"<|tool▁calls▁begin|>"
)
}
fn
get_unstreamed_tool_args
(
&
self
)
->
Option
<
Vec
<
ToolCallItem
>>
{
...
...
sgl-router/src/tool_parser/parsers/glm4_moe_parser.rs
View file @
466992b2
...
...
@@ -71,11 +71,6 @@ impl Glm4MoeParser {
}
}
/// Check if text contains GLM-4 MoE tool markers
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
self
.bot_token
)
}
/// Parse arguments from key-value pairs
fn
parse_arguments
(
&
self
,
args_text
:
&
str
)
->
ToolParserResult
<
serde_json
::
Map
<
String
,
Value
>>
{
let
mut
arguments
=
serde_json
::
Map
::
new
();
...
...
@@ -313,8 +308,8 @@ impl ToolParser for Glm4MoeParser {
})
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
self
.has_tool_markers
(
text
)
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
self
.bot_token
)
}
fn
get_unstreamed_tool_args
(
&
self
)
->
Option
<
Vec
<
ToolCallItem
>>
{
...
...
sgl-router/src/tool_parser/parsers/gpt_oss_harmony_parser.rs
View file @
466992b2
...
...
@@ -38,7 +38,7 @@ impl ToolParser for GptOssHarmonyParser {
Ok
(
StreamingParseResult
::
default
())
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
// Reuse the legacy heuristics for now; this will be replaced with Harmony-specific
// start-token detection when the parser is fully implemented.
text
.contains
(
"<|channel|>commentary"
)
...
...
sgl-router/src/tool_parser/parsers/gpt_oss_parser.rs
View file @
466992b2
...
...
@@ -58,11 +58,6 @@ impl GptOssParser {
}
}
/// Check if text contains GPT-OSS tool markers
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"<|channel|>commentary to="
)
}
/// Extract function name from full namespace (e.g., "functions.get_weather" -> "get_weather")
fn
extract_function_name
(
&
self
,
full_name
:
&
str
)
->
String
{
if
let
Some
(
dot_pos
)
=
full_name
.rfind
(
'.'
)
{
...
...
@@ -242,7 +237,7 @@ impl ToolParser for GptOssParser {
Ok
(
StreamingParseResult
::
default
())
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
self
.has_tool_markers
(
text
)
||
text
.contains
(
"<|channel|>commentary"
)
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"<|channel|>commentary"
)
}
}
sgl-router/src/tool_parser/parsers/json_parser.rs
View file @
466992b2
...
...
@@ -261,7 +261,7 @@ impl ToolParser for JsonParser {
)
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
let
trimmed
=
text
.trim
();
(
trimmed
.starts_with
(
'['
)
||
trimmed
.starts_with
(
'{'
))
&&
trimmed
.contains
(
r#""name""#
)
}
...
...
sgl-router/src/tool_parser/parsers/kimik2_parser.rs
View file @
466992b2
...
...
@@ -82,11 +82,6 @@ impl KimiK2Parser {
}
}
/// Check if text contains Kimi K2 tool markers
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"<|tool_calls_section_begin|>"
)
}
/// Parse function ID to extract name and index
fn
parse_function_id
(
&
self
,
id
:
&
str
)
->
Option
<
(
String
,
usize
)
>
{
if
let
Some
(
captures
)
=
self
.tool_call_id_regex
.captures
(
id
)
{
...
...
@@ -331,8 +326,8 @@ impl ToolParser for KimiK2Parser {
})
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
self
.has_tool_markers
(
text
)
||
text
.contains
(
"<|tool_call_begin|>"
)
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"<|tool_call
s_section
_begin|>"
)
}
fn
get_unstreamed_tool_args
(
&
self
)
->
Option
<
Vec
<
ToolCallItem
>>
{
...
...
sgl-router/src/tool_parser/parsers/llama_parser.rs
View file @
466992b2
...
...
@@ -228,7 +228,7 @@ impl ToolParser for LlamaParser {
)
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
// Llama format if contains python_tag or starts with JSON object
text
.contains
(
"<|python_tag|>"
)
||
(
text
.trim_start
()
.starts_with
(
'{'
)
&&
text
.contains
(
r#""name""#
))
...
...
sgl-router/src/tool_parser/parsers/mistral_parser.rs
View file @
466992b2
...
...
@@ -156,11 +156,6 @@ impl MistralParser {
Ok
(
None
)
}
}
/// Check if text contains Mistral tool markers
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"[TOOL_CALLS]"
)
}
}
impl
Default
for
MistralParser
{
...
...
@@ -254,8 +249,8 @@ impl ToolParser for MistralParser {
)
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
self
.has_tool_markers
(
text
)
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"[TOOL_CALLS]"
)
}
fn
get_unstreamed_tool_args
(
&
self
)
->
Option
<
Vec
<
crate
::
tool_parser
::
types
::
ToolCallItem
>>
{
...
...
sgl-router/src/tool_parser/parsers/pythonic_parser.rs
View file @
466992b2
...
...
@@ -203,7 +203,7 @@ impl ToolParser for PythonicParser {
})
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
let
cleaned
=
Self
::
strip_special_tokens
(
text
);
if
pythonic_block_regex
()
.is_match
(
&
cleaned
)
{
return
true
;
...
...
sgl-router/src/tool_parser/parsers/qwen_parser.rs
View file @
466992b2
...
...
@@ -98,16 +98,6 @@ impl QwenParser {
Ok
(
None
)
}
}
/// Check if text contains Qwen tool markers
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"<tool_call>"
)
}
/// Check if text has tool call
fn
has_tool_call
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"<tool_call>"
)
}
}
impl
Default
for
QwenParser
{
...
...
@@ -165,7 +155,7 @@ impl ToolParser for QwenParser {
let
current_text
=
&
self
.buffer
.clone
();
// Check if current_text has tool_call
let
has_tool_start
=
self
.has_tool_
call
(
current_text
)
let
has_tool_start
=
self
.has_tool_
markers
(
current_text
)
||
(
self
.current_tool_id
>=
0
&&
current_text
.starts_with
(
self
.tool_call_separator
));
if
!
has_tool_start
{
...
...
@@ -243,8 +233,8 @@ impl ToolParser for QwenParser {
Ok
(
result
)
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
self
.has_tool_markers
(
text
)
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
"<tool_call>"
)
}
fn
get_unstreamed_tool_args
(
&
self
)
->
Option
<
Vec
<
crate
::
tool_parser
::
types
::
ToolCallItem
>>
{
...
...
sgl-router/src/tool_parser/parsers/step3_parser.rs
View file @
466992b2
...
...
@@ -96,11 +96,6 @@ impl Step3Parser {
}
}
/// Check if text contains Step3 tool markers
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
self
.bot_token
)
}
/// Reset streaming state for the next tool call
fn
reset_streaming_state
(
&
mut
self
)
{
self
.in_tool_call
=
false
;
...
...
@@ -553,8 +548,8 @@ impl ToolParser for Step3Parser {
Ok
(
StreamingParseResult
::
default
())
}
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
{
self
.has_tool_markers
(
text
)
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
{
text
.contains
(
self
.bot_token
)
}
fn
get_unstreamed_tool_args
(
&
self
)
->
Option
<
Vec
<
ToolCallItem
>>
{
...
...
sgl-router/src/tool_parser/tests.rs
View file @
466992b2
...
...
@@ -12,7 +12,7 @@ async fn test_tool_parser_factory() {
// Test that we can get a pooled parser
let
pooled_parser
=
factory
.get_pooled
(
"gpt-4"
);
let
parser
=
pooled_parser
.lock
()
.await
;
assert
!
(
parser
.
detect_format
(
r#"{"name": "test", "arguments": {}}"#
));
assert
!
(
parser
.
has_tool_markers
(
r#"{"name": "test", "arguments": {}}"#
));
}
#[tokio::test]
...
...
@@ -25,7 +25,7 @@ async fn test_tool_parser_factory_model_mapping() {
// Get parser for the test model
let
pooled_parser
=
factory
.get_pooled
(
"test-model"
);
let
parser
=
pooled_parser
.lock
()
.await
;
assert
!
(
parser
.
detect_format
(
r#"{"name": "test", "arguments": {}}"#
));
assert
!
(
parser
.
has_tool_markers
(
r#"{"name": "test", "arguments": {}}"#
));
}
#[test]
...
...
@@ -234,12 +234,12 @@ fn test_json_parser_format_detection() {
let
parser
=
JsonParser
::
new
();
// Should detect valid tool call formats
assert
!
(
parser
.
detect_format
(
r#"{"name": "test", "arguments": {}}"#
));
assert
!
(
parser
.
detect_format
(
r#"{"name": "test", "parameters": {"x": 1}}"#
));
assert
!
(
parser
.
detect_format
(
r#"[{"name": "test"}]"#
));
assert
!
(
parser
.
has_tool_markers
(
r#"{"name": "test", "arguments": {}}"#
));
assert
!
(
parser
.
has_tool_markers
(
r#"{"name": "test", "parameters": {"x": 1}}"#
));
assert
!
(
parser
.
has_tool_markers
(
r#"[{"name": "test"}]"#
));
// Should not detect non-tool formats
assert
!
(
!
parser
.
detect_format
(
"plain text"
));
assert
!
(
!
parser
.
has_tool_markers
(
"plain text"
));
}
#[tokio::test]
...
...
sgl-router/src/tool_parser/traits.rs
View file @
466992b2
...
...
@@ -25,7 +25,7 @@ pub trait ToolParser: Send + Sync {
)
->
ToolParserResult
<
StreamingParseResult
>
;
/// Check if text contains tool calls in this parser's format
fn
detect_format
(
&
self
,
text
:
&
str
)
->
bool
;
fn
has_tool_markers
(
&
self
,
text
:
&
str
)
->
bool
;
/// Optionally expose a token-aware parser implementation.
/// Default returns `None`, meaning the parser only supports text input.
...
...
sgl-router/tests/tool_parser_deepseek.rs
View file @
466992b2
...
...
@@ -108,13 +108,13 @@ fn test_deepseek_format_detection() {
let
parser
=
DeepSeekParser
::
new
();
// Should detect DeepSeek format
assert
!
(
parser
.
detect_format
(
"<|tool▁calls▁begin|>"
));
assert
!
(
parser
.
detect_format
(
"text with <|tool▁calls▁begin|> marker"
));
assert
!
(
parser
.
has_tool_markers
(
"<|tool▁calls▁begin|>"
));
assert
!
(
parser
.
has_tool_markers
(
"text with <|tool▁calls▁begin|> marker"
));
// Should not detect other formats
assert
!
(
!
parser
.
detect_format
(
"[TOOL_CALLS]"
));
assert
!
(
!
parser
.
detect_format
(
"<tool_call>"
));
assert
!
(
!
parser
.
detect_format
(
"plain text"
));
assert
!
(
!
parser
.
has_tool_markers
(
"[TOOL_CALLS]"
));
assert
!
(
!
parser
.
has_tool_markers
(
"<tool_call>"
));
assert
!
(
!
parser
.
has_tool_markers
(
"plain text"
));
}
#[tokio::test]
...
...
sgl-router/tests/tool_parser_glm4_moe.rs
View file @
466992b2
...
...
@@ -117,13 +117,13 @@ fn test_glm4_format_detection() {
let
parser
=
Glm4MoeParser
::
new
();
// Should detect GLM-4 format
assert
!
(
parser
.
detect_format
(
"<tool_call>"
));
assert
!
(
parser
.
detect_format
(
"text with <tool_call> marker"
));
assert
!
(
parser
.
has_tool_markers
(
"<tool_call>"
));
assert
!
(
parser
.
has_tool_markers
(
"text with <tool_call> marker"
));
// Should not detect other formats
assert
!
(
!
parser
.
detect_format
(
"[TOOL_CALLS]"
));
assert
!
(
!
parser
.
detect_format
(
"<|tool▁calls▁begin|>"
));
assert
!
(
!
parser
.
detect_format
(
"plain text"
));
assert
!
(
!
parser
.
has_tool_markers
(
"[TOOL_CALLS]"
));
assert
!
(
!
parser
.
has_tool_markers
(
"<|tool▁calls▁begin|>"
));
assert
!
(
!
parser
.
has_tool_markers
(
"plain text"
));
}
#[tokio::test]
...
...
sgl-router/tests/tool_parser_gpt_oss.rs
View file @
466992b2
...
...
@@ -109,14 +109,14 @@ fn test_gpt_oss_format_detection() {
let
parser
=
GptOssParser
::
new
();
// Should detect GPT-OSS format
assert
!
(
parser
.
detect_format
(
"<|channel|>commentary to="
));
assert
!
(
parser
.
detect_format
(
"<|channel|>commentary"
));
assert
!
(
parser
.
detect_format
(
"text with <|channel|>commentary to= marker"
));
assert
!
(
parser
.
has_tool_markers
(
"<|channel|>commentary to="
));
assert
!
(
parser
.
has_tool_markers
(
"<|channel|>commentary"
));
assert
!
(
parser
.
has_tool_markers
(
"text with <|channel|>commentary to= marker"
));
// Should not detect other formats
assert
!
(
!
parser
.
detect_format
(
"[TOOL_CALLS]"
));
assert
!
(
!
parser
.
detect_format
(
"<tool_call>"
));
assert
!
(
!
parser
.
detect_format
(
"plain text"
));
assert
!
(
!
parser
.
has_tool_markers
(
"[TOOL_CALLS]"
));
assert
!
(
!
parser
.
has_tool_markers
(
"<tool_call>"
));
assert
!
(
!
parser
.
has_tool_markers
(
"plain text"
));
}
#[tokio::test]
...
...
sgl-router/tests/tool_parser_json.rs
View file @
466992b2
...
...
@@ -155,7 +155,7 @@ async fn test_json_invalid_format() {
async
fn
test_json_format_detection
()
{
let
parser
=
JsonParser
::
new
();
assert
!
(
parser
.
detect_format
(
r#"{"name": "test", "arguments": {}}"#
));
assert
!
(
parser
.
detect_format
(
r#"[{"name": "test"}]"#
));
assert
!
(
!
parser
.
detect_format
(
"plain text"
));
assert
!
(
parser
.
has_tool_markers
(
r#"{"name": "test", "arguments": {}}"#
));
assert
!
(
parser
.
has_tool_markers
(
r#"[{"name": "test"}]"#
));
assert
!
(
!
parser
.
has_tool_markers
(
"plain text"
));
}
sgl-router/tests/tool_parser_kimik2.rs
View file @
466992b2
...
...
@@ -98,14 +98,13 @@ fn test_kimik2_format_detection() {
let
parser
=
KimiK2Parser
::
new
();
// Should detect Kimi K2 format
assert
!
(
parser
.detect_format
(
"<|tool_calls_section_begin|>"
));
assert
!
(
parser
.detect_format
(
"<|tool_call_begin|>"
));
assert
!
(
parser
.detect_format
(
"text with <|tool_calls_section_begin|> marker"
));
assert
!
(
parser
.has_tool_markers
(
"<|tool_calls_section_begin|>"
));
assert
!
(
parser
.has_tool_markers
(
"text with <|tool_calls_section_begin|> marker"
));
// Should not detect other formats
assert
!
(
!
parser
.
detect_format
(
"[TOOL_CALLS]"
));
assert
!
(
!
parser
.
detect_format
(
"<tool_call>"
));
assert
!
(
!
parser
.
detect_format
(
"plain text"
));
assert
!
(
!
parser
.
has_tool_markers
(
"[TOOL_CALLS]"
));
assert
!
(
!
parser
.
has_tool_markers
(
"<tool_call>"
));
assert
!
(
!
parser
.
has_tool_markers
(
"plain text"
));
}
#[tokio::test]
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment