@@ -671,15 +671,16 @@ static std::string wrap_code_as_arguments(common_chat_msg_parser & builder, cons
671
671
* Takes a prefix regex that must have 1 group to capture the function name, a closing suffix, and expects json parameters in between.
672
672
* Aggregates the prefix, suffix and in-between text into the content.
673
673
*/
674
- static void parse_json_tool_calls_deepseek_v3_1 (
674
+ static void parse_json_tool_calls (
675
675
common_chat_msg_parser & builder,
676
676
const std::optional<common_regex> & block_open,
677
677
const std::optional<common_regex> & function_regex_start_only,
678
678
const std::optional<common_regex> & function_regex,
679
679
const common_regex & close_regex,
680
680
const std::optional<common_regex> & block_close,
681
681
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) {
683
684
684
685
auto parse_tool_calls = [&]() {
685
686
size_t from = std::string::npos;
@@ -705,93 +706,12 @@ static void parse_json_tool_calls_deepseek_v3_1(
705
706
from = res->groups [0 ].begin + 1 ;
706
707
continue ;
707
708
}
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 ();
784
712
} else {
785
- GGML_ASSERT (res->groups .size () == 2 );
786
- name = builder.str (res->groups [1 ]);
713
+ from = std::string::npos;
787
714
}
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;
795
715
796
716
auto maybe_raw_python = name == " python" && allow_raw_python;
797
717
if (builder.input ()[builder.pos ()] == ' {' || !maybe_raw_python) {
@@ -800,8 +720,16 @@ static void parse_json_tool_calls(
800
720
throw common_chat_msg_partial_exception (" incomplete tool call" );
801
721
}
802
722
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 ;
803
732
}
804
- continue ;
805
733
}
806
734
if (maybe_raw_python) {
807
735
auto arguments = wrap_code_as_arguments (builder, builder.consume_rest ());
@@ -815,13 +743,18 @@ static void parse_json_tool_calls(
815
743
break ;
816
744
}
817
745
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
+ }
818
750
builder.consume_regex (*block_close);
819
751
}
820
752
builder.consume_spaces ();
821
753
builder.add_content (builder.consume_rest ());
822
754
};
823
755
if (block_open) {
824
756
if (auto res = builder.try_find_regex (*block_open)) {
757
+ if (update_cursor) builder.move_to (res->groups [0 ].end ); // consume opener
825
758
parse_tool_calls ();
826
759
} else {
827
760
builder.add_content (builder.consume_rest ());
@@ -1502,13 +1435,16 @@ static void common_chat_parse_deepseek_v3_1_content(common_chat_msg_parser & bui
1502
1435
1503
1436
LOG_DBG (" %s: parse_tool_calls\n " , __func__);
1504
1437
1505
- parse_json_tool_calls_deepseek_v3_1 (
1438
+ parse_json_tool_calls (
1506
1439
builder,
1507
1440
/* block_open= */ tool_calls_begin,
1508
1441
/* function_regex_start_only= */ std::nullopt,
1509
1442
function_regex,
1510
1443
close_regex,
1511
- tool_calls_end);
1444
+ tool_calls_end,
1445
+ false ,
1446
+ nullptr ,
1447
+ true );
1512
1448
}
1513
1449
1514
1450
static void common_chat_parse_deepseek_v3_1 (common_chat_msg_parser & builder) {
0 commit comments