Skip to content

Commit f661dbe

Browse files
committed
Merge deepseek V3.1 and regular parse_json_tool_calls() function
behaviors by adding optional update_cursor argument.
1 parent 92003d7 commit f661dbe

File tree

1 file changed

+26
-90
lines changed

1 file changed

+26
-90
lines changed

common/chat.cpp

Lines changed: 26 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -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

15141450
static void common_chat_parse_deepseek_v3_1(common_chat_msg_parser & builder) {

0 commit comments

Comments
 (0)