@@ -671,15 +671,16 @@ static std::string wrap_code_as_arguments(common_chat_msg_parser & builder, cons
671671 * Takes a prefix regex that must have 1 group to capture the function name, a closing suffix, and expects json parameters in between.
672672 * Aggregates the prefix, suffix and in-between text into the content.
673673 */
674- static void parse_json_tool_calls_deepseek_v3_1 (
674+ static void parse_json_tool_calls (
675675 common_chat_msg_parser & builder,
676676 const std::optional<common_regex> & block_open,
677677 const std::optional<common_regex> & function_regex_start_only,
678678 const std::optional<common_regex> & function_regex,
679679 const common_regex & close_regex,
680680 const std::optional<common_regex> & block_close,
681681 bool allow_raw_python = false ,
682- const std::function<std::string(const common_chat_msg_parser::find_regex_result & fres)> & get_function_name = nullptr) {
682+ const std::function<std::string(const common_chat_msg_parser::find_regex_result & fres)> & get_function_name = nullptr,
683+ bool update_cursor = false) {
683684
684685 auto parse_tool_calls = [&]() {
685686 size_t from = std::string::npos;
@@ -705,93 +706,12 @@ static void parse_json_tool_calls_deepseek_v3_1(
705706 from = res->groups [0 ].begin + 1 ;
706707 continue ;
707708 }
708- builder.move_to (res->groups [0 ].end );
709- from = builder.pos ();
710-
711- auto maybe_raw_python = name == " python" && allow_raw_python;
712- if (builder.input ()[builder.pos ()] == ' {' || !maybe_raw_python) {
713- if (auto arguments = builder.try_consume_json_with_dumped_args ({{}})) {
714- if (!builder.add_tool_call (name, " " , arguments->value ) || arguments->is_partial ) {
715- throw common_chat_msg_partial_exception (" incomplete tool call" );
716- }
717- builder.consume_regex (close_regex);
718- from = builder.pos (); // continue after this call
719- continue ;
720- }
721- throw common_chat_msg_partial_exception (" incomplete tool call" );
722- }
723- if (maybe_raw_python) {
724- auto arguments = wrap_code_as_arguments (builder, builder.consume_rest ());
725- if (!builder.add_tool_call (name, " " , arguments)) {
726- throw common_chat_msg_partial_exception (" incomplete tool call" );
727- }
728- return ;
729- }
730- throw common_chat_msg_partial_exception (" incomplete tool call" );
731- }
732- break ;
733- }
734- if (block_close) {
735- // ensure we’re right after the last call header/close
736- if (from != std::string::npos) builder.move_to (from);
737- builder.consume_regex (*block_close);
738- }
739- builder.consume_spaces ();
740- builder.add_content (builder.consume_rest ());
741- };
742- if (block_open) {
743- if (auto res = builder.try_find_regex (*block_open)) {
744- builder.move_to (res->groups [0 ].end ); // consume opener
745- parse_tool_calls ();
746- return ;
747- } else {
748- builder.add_content (builder.consume_rest ());
749- return ;
750- }
751- } else {
752- parse_tool_calls ();
753- return ;
754- }
755- }
756-
757- /* *
758- * Takes a prefix regex that must have 1 group to capture the function name, a closing suffix, and expects json parameters in between.
759- * Aggregates the prefix, suffix and in-between text into the content.
760- */
761- static void parse_json_tool_calls (
762- common_chat_msg_parser & builder,
763- const std::optional<common_regex> & block_open,
764- const std::optional<common_regex> & function_regex_start_only,
765- const std::optional<common_regex> & function_regex,
766- const common_regex & close_regex,
767- const std::optional<common_regex> & block_close,
768- bool allow_raw_python = false ,
769- const std::function<std::string(const common_chat_msg_parser::find_regex_result & fres)> & get_function_name = nullptr) {
770-
771- auto parse_tool_calls = [&]() {
772- size_t from = std::string::npos;
773- auto first = true ;
774- while (true ) {
775- auto res = function_regex_start_only && first
776- ? builder.try_consume_regex (*function_regex_start_only)
777- : function_regex
778- ? builder.try_find_regex (*function_regex, from)
779- : std::nullopt ;
780- if (res) {
781- std::string name;
782- if (get_function_name) {
783- name = get_function_name (*res);
709+ if (update_cursor) {
710+ builder.move_to (res->groups [0 ].end );
711+ from = builder.pos ();
784712 } else {
785- GGML_ASSERT (res->groups .size () == 2 );
786- name = builder.str (res->groups [1 ]);
713+ from = std::string::npos;
787714 }
788- first = false ;
789- if (name.empty ()) {
790- // get_function_name signalled us that we should skip this match and treat it as content.
791- from = res->groups [0 ].begin + 1 ;
792- continue ;
793- }
794- from = std::string::npos;
795715
796716 auto maybe_raw_python = name == " python" && allow_raw_python;
797717 if (builder.input ()[builder.pos ()] == ' {' || !maybe_raw_python) {
@@ -800,8 +720,16 @@ static void parse_json_tool_calls(
800720 throw common_chat_msg_partial_exception (" incomplete tool call" );
801721 }
802722 builder.consume_regex (close_regex);
723+ if (update_cursor) {
724+ from = builder.pos (); // continue after this call
725+ continue ;
726+ }
727+ }
728+ if (update_cursor) {
729+ throw common_chat_msg_partial_exception (" incomplete tool call" );
730+ } else {
731+ continue ;
803732 }
804- continue ;
805733 }
806734 if (maybe_raw_python) {
807735 auto arguments = wrap_code_as_arguments (builder, builder.consume_rest ());
@@ -815,13 +743,18 @@ static void parse_json_tool_calls(
815743 break ;
816744 }
817745 if (block_close) {
746+ if (update_cursor) {
747+ // ensure we’re right after the last call header/close
748+ if (from != std::string::npos) builder.move_to (from);
749+ }
818750 builder.consume_regex (*block_close);
819751 }
820752 builder.consume_spaces ();
821753 builder.add_content (builder.consume_rest ());
822754 };
823755 if (block_open) {
824756 if (auto res = builder.try_find_regex (*block_open)) {
757+ if (update_cursor) builder.move_to (res->groups [0 ].end ); // consume opener
825758 parse_tool_calls ();
826759 } else {
827760 builder.add_content (builder.consume_rest ());
@@ -1502,13 +1435,16 @@ static void common_chat_parse_deepseek_v3_1_content(common_chat_msg_parser & bui
15021435
15031436 LOG_DBG (" %s: parse_tool_calls\n " , __func__);
15041437
1505- parse_json_tool_calls_deepseek_v3_1 (
1438+ parse_json_tool_calls (
15061439 builder,
15071440 /* block_open= */ tool_calls_begin,
15081441 /* function_regex_start_only= */ std::nullopt ,
15091442 function_regex,
15101443 close_regex,
1511- tool_calls_end);
1444+ tool_calls_end,
1445+ false ,
1446+ nullptr ,
1447+ true );
15121448}
15131449
15141450static void common_chat_parse_deepseek_v3_1 (common_chat_msg_parser & builder) {
0 commit comments