| 817 | } |
| 818 | |
| 819 | common_peg_parser common_chat_peg_builder::standard_json_tools( |
| 820 | const std::string & section_start, |
| 821 | const std::string & section_end, |
| 822 | const ordered_json & tools, |
| 823 | bool parallel_tool_calls, |
| 824 | bool force_tool_calls, |
| 825 | const std::string & name_key, |
| 826 | const std::string & args_key, |
| 827 | bool array_wrapped, |
| 828 | bool function_is_key, |
| 829 | const std::string & call_id_key, |
| 830 | const std::string & gen_call_id_key, |
| 831 | const std::vector<std::string> & parameters_order) { |
| 832 | if (!tools.is_array() || tools.empty()) { |
| 833 | return eps(); |
| 834 | } |
| 835 | |
| 836 | std::string effective_name_key = name_key.empty() ? "name" : name_key; |
| 837 | std::string effective_args_key = args_key.empty() ? "arguments" : args_key; |
| 838 | |
| 839 | // Dispatch to the appropriate builder based on the JSON layout mode |
| 840 | common_peg_parser tool_choices = eps(); |
| 841 | if (function_is_key) { |
| 842 | tool_choices = build_json_tools_function_is_key(tools, args_key, effective_args_key, call_id_key, gen_call_id_key); |
| 843 | } else { |
| 844 | auto name_spec = parse_key_spec(effective_name_key); |
| 845 | auto args_spec = parse_key_spec(effective_args_key); |
| 846 | if (!name_spec.first.empty() || !args_spec.first.empty()) { |
| 847 | tool_choices = build_json_tools_nested_keys(tools, effective_name_key, effective_args_key, call_id_key, gen_call_id_key); |
| 848 | } else { |
| 849 | tool_choices = build_json_tools_flat_keys(tools, effective_name_key, effective_args_key, call_id_key, gen_call_id_key, parameters_order); |
| 850 | } |
| 851 | } |
| 852 | |
| 853 | // Build the section with markers |
| 854 | auto tool_calls = tool_choices; |
| 855 | if (parallel_tool_calls) { |
| 856 | tool_calls = tool_calls + zero_or_more(space() + literal(",") + space() + tool_choices); |
| 857 | } |
| 858 | |
| 859 | if (array_wrapped) { |
| 860 | tool_calls = literal("[") + space() + tool_calls + space() + literal("]"); |
| 861 | } |
| 862 | |
| 863 | auto section = |
| 864 | trigger_rule("tool-call", literal(section_start) + space() + tool_calls + space() + literal(section_end)); |
| 865 | |
| 866 | return force_tool_calls ? section : optional(section); |
| 867 | } |
| 868 | |
| 869 | void common_chat_peg_gemma4_mapper::from_ast(const common_peg_ast_arena & arena, const common_peg_parse_result & result) { |
| 870 | for (const auto & node : result.nodes) { |