[Model] Support Hy3 token suffix and JSON Schema array types (#47192)

Signed-off-by: stevenkuang-tencent <stevenkuang@tencent.com>
This commit is contained in:
stevenkuang
2026-07-01 10:16:07 +00:00
committed by GitHub
parent 024b06b0dc
commit cc56379e28
2 changed files with 24 additions and 11 deletions
+4 -2
View File
@@ -26,6 +26,8 @@ class HYV3ReasoningParser(BaseThinkingReasoningParser):
"""
def __init__(self, tokenizer: TokenizerLike, *args, **kwargs):
init_kwargs = getattr(tokenizer, "init_kwargs", None) or {}
self.suffix: str = init_kwargs.get("token_suffix") or ""
super().__init__(tokenizer, *args, **kwargs)
# First, If there is reasoning_effort in chat_kwargs,
@@ -52,12 +54,12 @@ class HYV3ReasoningParser(BaseThinkingReasoningParser):
@property
def start_token(self) -> str:
"""The token that starts reasoning content."""
return "<think>"
return f"<think{self.suffix}>"
@property
def end_token(self) -> str:
"""The token that ends reasoning content."""
return "</think>"
return f"</think{self.suffix}>"
def is_reasoning_end(self, input_ids: Sequence[int]) -> bool:
if self._identity_parser is not None:
+20 -9
View File
@@ -108,6 +108,14 @@ class HYV3ToolParser(ToolParser):
Note: single ``type`` has the highest priority.
"""
if "type" in arg_schema:
type_val = arg_schema["type"]
# JSON Schema allows "type" to be an array to represent union types,
# e.g. "type": ["string", "object"].
# Expand it into an anyOf-equivalent format:
# [{"type": "string"}, {"type": "object"}]
# so that _get_types / _parse_value can handle it uniformly later.
if isinstance(type_val, list):
return [{"type": t} for t in type_val]
return [arg_schema]
if "anyOf" in arg_schema:
return arg_schema["anyOf"]
@@ -261,19 +269,22 @@ class HYV3ToolParser(ToolParser):
self._current_arg_is_string: bool = False # is current arg pure string?
self._streamed_json_len: int = 0 # bytes of JSON already sent
self.tool_calls_start_token: str = "<tool_calls>"
self.tool_calls_end_token: str = "</tool_calls>"
init_kwargs = getattr(tokenizer, "init_kwargs", None) or {}
self.suffix: str = init_kwargs.get("token_suffix") or ""
self.tool_call_start_token: str = "<tool_call>"
self.tool_call_end_token: str = "</tool_call>"
self.tool_calls_start_token: str = f"<tool_calls{self.suffix}>"
self.tool_calls_end_token: str = f"</tool_calls{self.suffix}>"
self.tool_sep_token: str = "<tool_sep>"
self.tool_call_start_token: str = f"<tool_call{self.suffix}>"
self.tool_call_end_token: str = f"</tool_call{self.suffix}>"
self.arg_key_start_token: str = "<arg_key>"
self.arg_key_end_token: str = "</arg_key>"
self.tool_sep_token: str = f"<tool_sep{self.suffix}>"
self.arg_value_start_token: str = "<arg_value>"
self.arg_value_end_token: str = "</arg_value>"
self.arg_key_start_token: str = f"<arg_key{self.suffix}>"
self.arg_key_end_token: str = f"</arg_key{self.suffix}>"
self.arg_value_start_token: str = f"<arg_value{self.suffix}>"
self.arg_value_end_token: str = f"</arg_value{self.suffix}>"
self.tool_call_regex = re.compile(
rf"{self.tool_call_start_token}(.*?){self.tool_sep_token}"