[fix] Relax white space rules in EBNFComposer (#9595)
This commit is contained in:
@@ -50,19 +50,19 @@ class EBNFComposer:
|
||||
|
||||
CALL_RULE_MAP = {
|
||||
"pythonic": 'call_{name} ::= "{name}" "(" {arguments_rule} ")"',
|
||||
"json": 'call_{name} ::= "{{" "\\"name\\"" ":" "\\"{name}\\"" ", " "\\"arguments\\"" ":" {arguments_rule} "}}"',
|
||||
"json": 'call_{name} ::= "{{" ws "\\"name\\"" ws ":" ws "\\"{name}\\"" ws "," ws "\\"arguments\\"" ws ":" ws {arguments_rule} ws "}}"',
|
||||
"xml": 'call_{name} ::= "<function={name}>\\n" {arguments_rule} "\\n</function>"',
|
||||
}
|
||||
|
||||
ARGUMENTS_RULE_MAP = {
|
||||
"pythonic": "{arg_rules}",
|
||||
"json": '"{{" {arg_rules} "}}"',
|
||||
"json": '"{{" ws {arg_rules} ws "}}"',
|
||||
"xml": "{arg_rules}",
|
||||
}
|
||||
|
||||
KEY_VALUE_RULE_MAP = {
|
||||
"pythonic": '"{key}" "=" {valrule}',
|
||||
"json": '"\\"{key}\\"" ":" {valrule}',
|
||||
"json": '"\\"{key}\\"" ws ":" ws {valrule}',
|
||||
"xml": '"<parameter={key}>\\n" {valrule} "\\n</parameter>"',
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ class EBNFComposer:
|
||||
tool_call_separator: Optional[str] = None,
|
||||
call_rule_fmt: Optional[str] = None,
|
||||
key_value_rule_fmt: Optional[str] = None,
|
||||
key_value_separator: str = ",",
|
||||
key_value_separator: str = 'ws "," ws',
|
||||
):
|
||||
"""
|
||||
Generalized EBNF builder for all detectors.
|
||||
@@ -183,6 +183,10 @@ class EBNFComposer:
|
||||
key_value_rule_fmt: Optional custom format string for key-value pairs. It should define how each parameter is formatted,
|
||||
with placeholders {key} for the parameter name and {valrule} for the value rule. If None, a default format
|
||||
based on function_format will be used.
|
||||
key_value_separator: Raw EBNF fragment inserted between key-value pairs.
|
||||
This string is used verbatim (not auto-quoted). Pass:
|
||||
- Quoted terminals when you need a literal token (e.g. '","' or '"\\n"').
|
||||
- Raw/non-terminals when you need grammar tokens (e.g. 'ws "," ws').
|
||||
"""
|
||||
# =================================================================
|
||||
# Step 1: Determine the root tool calls rule
|
||||
@@ -281,9 +285,7 @@ class EBNFComposer:
|
||||
# Add required properties joined by commas
|
||||
if required:
|
||||
rule_parts.append(
|
||||
f' "{key_value_separator}" '.join(
|
||||
prop_kv_pairs[k] for k in required
|
||||
)
|
||||
f" {key_value_separator} ".join(prop_kv_pairs[k] for k in required)
|
||||
)
|
||||
|
||||
# Add optional properties with flexible ordering
|
||||
@@ -298,14 +300,14 @@ class EBNFComposer:
|
||||
opt_parts.append(prop_kv_pairs[optional[j]])
|
||||
else:
|
||||
opt_parts.append(
|
||||
f' ( "{key_value_separator}" {prop_kv_pairs[optional[j]]} )?'
|
||||
f" ( {key_value_separator} {prop_kv_pairs[optional[j]]} )?"
|
||||
)
|
||||
opt_alternatives.append("".join(opt_parts))
|
||||
|
||||
# Wrap with appropriate comma handling based on whether we have required properties
|
||||
if required:
|
||||
# Required properties exist, so optional group needs outer comma
|
||||
rule_parts.append(f' ( "{key_value_separator}" ( ')
|
||||
rule_parts.append(f" ( {key_value_separator} ( ")
|
||||
rule_parts.append(" | ".join(opt_alternatives))
|
||||
rule_parts.append(" ) )?")
|
||||
else:
|
||||
|
||||
@@ -160,5 +160,5 @@ class Glm4MoeDetector(BaseFormatDetector):
|
||||
function_format="xml",
|
||||
call_rule_fmt='"{name}" "\\n" ( {arguments_rule} "\\n" )?',
|
||||
key_value_rule_fmt='"<arg_key>{key}</arg_key>" "\\n" "<arg_value>" {valrule} "</arg_value>"',
|
||||
key_value_separator="\\n",
|
||||
key_value_separator='"\\n"',
|
||||
)
|
||||
|
||||
@@ -358,5 +358,5 @@ class Qwen3CoderDetector(BaseFormatDetector):
|
||||
function_format="xml",
|
||||
call_rule_fmt='"<function={name}>\\n" {arguments_rule} "\\n</function>"',
|
||||
key_value_rule_fmt='"<parameter={key}>\\n" {valrule} "\\n</parameter>"',
|
||||
key_value_separator="\\n",
|
||||
key_value_separator='"\\n"',
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user