Tool parser: fallback to <|tool_call_begin|> when no section marker
Some Kimi K2.5 model variants (nvidia/Kimi-K2.5-NVFP4) omit <|tool_calls_section_begin|> and go directly to <|tool_call_begin|>. The tool parser was only looking for section-level markers, so these tool calls were forwarded as raw content text instead of being parsed. Fix: _find_section_start and _find_section_start_end now fall back to <|tool_call_begin|> as a section start when no section-level marker is found. The section end falls back to <|tool_call_end|>.
This commit is contained in:
@@ -109,6 +109,9 @@ class KimiK2ToolParser(ToolParser):
|
|||||||
"<|tool_calls_section_end|>",
|
"<|tool_calls_section_end|>",
|
||||||
"<|tool_call_section_end|>",
|
"<|tool_call_section_end|>",
|
||||||
]
|
]
|
||||||
|
# Some model variants omit the section-level marker and go
|
||||||
|
# directly to <|tool_call_begin|>. Treat it as a fallback.
|
||||||
|
self._fallback_section_start: str = "<|tool_call_begin|>"
|
||||||
# Primary variant for ToolParser base class / adjust_request
|
# Primary variant for ToolParser base class / adjust_request
|
||||||
self.tool_calls_start_token: str = "<|tool_calls_section_begin|>"
|
self.tool_calls_start_token: str = "<|tool_calls_section_begin|>"
|
||||||
self.tool_calls_end_token: str = "<|tool_calls_section_end|>"
|
self.tool_calls_end_token: str = "<|tool_calls_section_end|>"
|
||||||
@@ -209,12 +212,23 @@ class KimiK2ToolParser(ToolParser):
|
|||||||
return function_name, raw_id
|
return function_name, raw_id
|
||||||
|
|
||||||
def _find_section_start(self, text: str) -> int:
|
def _find_section_start(self, text: str) -> int:
|
||||||
"""Return the index of the first section-start marker, or -1."""
|
"""Return the index of the first section-start marker, or -1.
|
||||||
|
|
||||||
|
Falls back to <|tool_call_begin|> if no section-level marker
|
||||||
|
is found. Some model variants skip <|tool_calls_section_begin|>
|
||||||
|
and go directly to <|tool_call_begin|>.
|
||||||
|
"""
|
||||||
best = -1
|
best = -1
|
||||||
for variant in self.tool_calls_section_start_variants:
|
for variant in self.tool_calls_section_start_variants:
|
||||||
idx = text.find(variant)
|
idx = text.find(variant)
|
||||||
if idx != -1 and (best == -1 or idx < best):
|
if idx != -1 and (best == -1 or idx < best):
|
||||||
best = idx
|
best = idx
|
||||||
|
# Fallback: if no section-level marker found, look for
|
||||||
|
# <|tool_call_begin|> directly.
|
||||||
|
if best == -1 and self._fallback_section_start:
|
||||||
|
idx = text.find(self._fallback_section_start)
|
||||||
|
if idx != -1:
|
||||||
|
best = idx
|
||||||
return best
|
return best
|
||||||
|
|
||||||
def _find_section_start_end(self, text: str) -> tuple[int, int]:
|
def _find_section_start_end(self, text: str) -> tuple[int, int]:
|
||||||
@@ -223,6 +237,9 @@ class KimiK2ToolParser(ToolParser):
|
|||||||
*start_of_inner* points just past the section-start marker.
|
*start_of_inner* points just past the section-start marker.
|
||||||
*end_of_inner* is the index of the section-end marker, or -1
|
*end_of_inner* is the index of the section-end marker, or -1
|
||||||
if the section is still open.
|
if the section is still open.
|
||||||
|
|
||||||
|
Falls back to <|tool_call_begin|> if no section-level marker
|
||||||
|
is found.
|
||||||
"""
|
"""
|
||||||
for variant in self.tool_calls_section_start_variants:
|
for variant in self.tool_calls_section_start_variants:
|
||||||
idx = text.find(variant)
|
idx = text.find(variant)
|
||||||
@@ -234,6 +251,20 @@ class KimiK2ToolParser(ToolParser):
|
|||||||
if end_idx != -1:
|
if end_idx != -1:
|
||||||
return inner_start, end_idx
|
return inner_start, end_idx
|
||||||
return inner_start, -1
|
return inner_start, -1
|
||||||
|
|
||||||
|
# Fallback: no section-level marker found. Look for
|
||||||
|
# <|tool_call_begin|> directly as the section start.
|
||||||
|
if self._fallback_section_start:
|
||||||
|
idx = text.find(self._fallback_section_start)
|
||||||
|
if idx != -1:
|
||||||
|
inner_start = idx + len(self._fallback_section_start)
|
||||||
|
# Look for <|tool_call_end|> as the section end
|
||||||
|
end_marker = self._fallback_section_start.replace("begin", "end")
|
||||||
|
end_idx = text.find(end_marker, inner_start)
|
||||||
|
if end_idx != -1:
|
||||||
|
return inner_start, end_idx
|
||||||
|
return inner_start, -1
|
||||||
|
|
||||||
return -1, -1
|
return -1, -1
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user