Team Ai
Datasetpublic

Brunobkr/llama.cpp_AlgMor24_github

ΩFFFΣLLIa • llama.cpp • AlgMor24 ██████╗ ███████╗███████╗███████╗██╗ ██╗ ██╗ █████╗ ██╔═══██╗██╔════╝██╔════╝██╔════╝██║ ██║ ██║██╔══██╗ ██║ ██║█████╗ █████╗ █████╗ ██║ ██║ ██║███████║ ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║██╔══██║ ╚██████╔╝██║ ██║ ███████╗███████╗███████╗██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝╚═╝ ╚═╝ High-Performance LLM / VLM Inference & Autonomous Agentic Ecosystem… See the full description on the dataset page: https://huggingface.co/datasets/Brunobkr/llama.cpp_AlgMor24_github.

sourceHugging Faceupdated 2mo agoView on Hugging Face
0likes3kdownloads
test-chat-auto-parser.cpp2202 linesDownload Raw Back to tests
1#include "chat-auto-parser-helpers.h"2#include "chat-auto-parser.h"3#include "chat-peg-parser.h"4#include "chat.h"5#include "peg-parser.h"6#include "testing.h"7 8#include <fstream>9#include <iostream>10#include <sstream>11#include <string>12 13using namespace autoparser;14 15static void test_calculate_diff_split_basic(testing & t);16static void test_calculate_diff_split_identical(testing & t);17static void test_calculate_diff_split_common_prefix(testing & t);18static void test_calculate_diff_split_common_suffix(testing & t);19static void test_calculate_diff_split_common_both(testing & t);20static void test_calculate_diff_split_empty_cases(testing & t);21static void test_calculate_diff_split_no_common(testing & t);22static void test_calculate_diff_split_single_char(testing & t);23static void test_calculate_diff_split_overlaps(testing & t);24static void test_calculate_diff_split_tag_boundaries(testing & t);25static void test_calculate_diff_split_generation_prompt(testing & t);26static void test_calculate_diff_split(testing & t);27 28static void test_until_common_prefix_basic(testing & t);29static void test_until_common_prefix(testing & t);30 31static void test_after_common_suffix_basic(testing & t);32static void test_after_common_suffix(testing & t);33 34static void test_analyze_tool_call_pure_json(testing & t);35static void test_analyze_tool_call_function_name_markers(testing & t);36static void test_analyze_tool_call_full_markers(testing & t);37static void test_analyze_tool_call_edge_cases(testing & t);38 39static void test_compare_variants_basic(testing & t);40static void test_compare_variants_messages_modifier(testing & t);41static void test_compare_variants_tools_modifier(testing & t);42static void test_compare_variants_both_modifiers(testing & t);43static void test_compare_variants_template_failure(testing & t);44static void test_compare_variants_identity(testing & t);45static void test_compare_variants(testing & t);46 47// Seed-OSS template tool calling analysis tests48static void test_seed_oss_tool_analysis(testing & t);49static void test_seed_oss_tool_presence(testing & t);50static void test_seed_oss_call_count(testing & t);51static void test_seed_oss_function_names(testing & t);52static void test_seed_oss_argument_count(testing & t);53static void test_seed_oss_args_presence(testing & t);54static void test_seed_oss_tool_with_reasoning(testing & t);55 56// Nemotron template analysis tests57static void test_nemotron_analysis(testing & t);58static void test_nemotron_reasoning_detection(testing & t);59static void test_nemotron_tool_format(testing & t);60static void test_laguna_analysis(testing & t);61static void test_laguna_reasoning_detection(testing & t);62static void test_laguna_tool_format(testing & t);63static void test_laguna_s_analysis(testing & t);64static void test_laguna_s_reasoning_detection(testing & t);65static void test_laguna_s_tool_format(testing & t);66static void test_laguna_s_preserve_reasoning(testing & t);67static void test_laguna_xs2_analysis(testing & t);68static void test_laguna_xs2_reasoning_detection(testing & t);69static void test_laguna_xs2_tool_format(testing & t);70 71// CohereForAI template analysis tests72static void test_cohere_reasoning_detection(testing & t);73static void test_cohere_analysis(testing & t);74 75// SmolLM3 template analysis tests76static void test_smollm3_analysis(testing & t);77 78// Marker separation79static void test_marker_separation(testing & t);80 81// standard_json_tools format tests82static void test_standard_json_tools_formats(testing & t);83static void test_standard_json_tools_openai(testing & t);84static void test_standard_json_tools_cohere(testing & t);85static void test_standard_json_tools_function_key(testing & t);86 87// normalize_quotes_to_json tests88static void test_normalize_quotes_to_json(testing & t);89static void test_normalize_quotes_with_embedded_quotes(testing & t);90 91// TAG_WITH_TAGGED argument parsing tests92static void test_tagged_args_with_embedded_quotes(testing & t);93 94static void test_role_markers_all_templates(testing & t);95 96int main(int argc, char * argv[]) {97    testing t(std::cout);98    t.verbose = true;99 100    // usage: test-chat-auto-parser-helpers [filter_regex]101 102    if (argc > 1) {103        t.set_filter(argv[1]);104    }105 106    t.test("diff_split", test_calculate_diff_split);107    t.test("common_prefix", test_until_common_prefix);108    t.test("common_suffix", test_after_common_suffix);109    t.test("compare_variants", test_compare_variants);110    t.test("segments", test_marker_separation);111    t.test("seed_oss_diffs", test_seed_oss_tool_analysis);112    t.test("cohere", test_cohere_analysis);113    t.test("nemotron", test_nemotron_analysis);114    t.test("laguna", test_laguna_analysis);115    t.test("laguna-s", test_laguna_s_analysis);116    t.test("laguna-xs2", test_laguna_xs2_analysis);117    t.test("smollm3", test_smollm3_analysis);118    t.test("standard_json_tools", test_standard_json_tools_formats);119    t.test("normalize_quotes_to_json", test_normalize_quotes_to_json);120    t.test("tagged_args_embedded_quotes", test_tagged_args_with_embedded_quotes);121    t.test("role_markers_all_templates", test_role_markers_all_templates);122 123    return t.summary();124}125 126static void test_marker_separation(testing & t) {127    auto single_square_marker = segmentize_markers("pre_marker[marker]post_marker");128    auto single_diag_marker = segmentize_markers("pre_marker<marker>post_marker");129    auto paired_markers = segmentize_markers("<hello>world</hello>");130    auto double_different_markers = segmentize_markers("<hello>[hello]<world>[world]");131    auto in_between = segmentize_markers("im<blue>daba<dee>da[hey]");132 133    t.test("single_square_marker", [&] (testing & t) {134        t.assert_equal("first is text", segment_type::TEXT, single_square_marker[0].type);135        t.assert_equal("second is marker", segment_type::MARKER, single_square_marker[1].type);136        t.assert_equal("last is text", segment_type::TEXT, single_square_marker[2].type);137 138        t.assert_equal("first is 'pre_marker'", "pre_marker", single_square_marker[0].value);139        t.assert_equal("second is '[marker]'", "[marker]", single_square_marker[1].value);140        t.assert_equal("last is 'post_marker'", "post_marker", single_square_marker[2].value);141    });142 143    t.test("single_diagonal_marker", [&] (testing & t) {144        t.assert_equal("first is text", segment_type::TEXT, single_diag_marker[0].type);145        t.assert_equal("second is marker", segment_type::MARKER, single_diag_marker[1].type);146        t.assert_equal("last is text", segment_type::TEXT, single_diag_marker[2].type);147 148        t.assert_equal("first is 'pre_marker'", "pre_marker", single_diag_marker[0].value);149        t.assert_equal("second is '<marker>'", "<marker>", single_diag_marker[1].value);150        t.assert_equal("last is 'post_marker'", "post_marker", single_diag_marker[2].value);151    });152 153    t.test("paired_markers", [&] (testing & t) {154        t.assert_equal("first is marker", segment_type::MARKER, paired_markers[0].type);155        t.assert_equal("second is text", segment_type::TEXT, paired_markers[1].type);156        t.assert_equal("third is marker", segment_type::MARKER, paired_markers[2].type);157 158        t.assert_equal("first is '<hello>'", "<hello>", paired_markers[0].value);159        t.assert_equal("second is 'world'", "world", paired_markers[1].value);160        t.assert_equal("third is '</hello>'", "</hello>", paired_markers[2].value);161    });162 163    t.test("double_different_markers", [&] (testing & t) {164        t.assert_equal("first is marker", segment_type::MARKER, double_different_markers[0].type);165        t.assert_equal("second is marker", segment_type::MARKER, double_different_markers[1].type);166        t.assert_equal("third is marker", segment_type::MARKER, double_different_markers[2].type);167        t.assert_equal("fourth is marker", segment_type::MARKER, double_different_markers[3].type);168 169        t.assert_equal("first is '<hello>'", "<hello>", double_different_markers[0].value);170        t.assert_equal("second is '[hello]'", "[hello]", double_different_markers[1].value);171        t.assert_equal("third is '<world>'", "<world>", double_different_markers[2].value);172        t.assert_equal("fourth is '[world]'", "[world]", double_different_markers[3].value);173    });174 175    t.test("in_between", [&] (testing & t) {176        t.assert_equal("first is text", segment_type::TEXT, in_between[0].type);177        t.assert_equal("second is marker", segment_type::MARKER, in_between[1].type);178        t.assert_equal("third is text", segment_type::TEXT, in_between[2].type);179        t.assert_equal("fourth is marker", segment_type::MARKER, in_between[3].type);180        t.assert_equal("fifth is text", segment_type::TEXT, in_between[4].type);181        t.assert_equal("sixth is marker", segment_type::MARKER, in_between[5].type);182 183        t.assert_equal("first is 'im'", "im", in_between[0].value);184        t.assert_equal("second is '<blue>'", "<blue>", in_between[1].value);185        t.assert_equal("third is 'daba'", "daba", in_between[2].value);186        t.assert_equal("fourth is '<dee>'", "<dee>", in_between[3].value);187        t.assert_equal("fifth is 'da'", "da", in_between[4].value);188        t.assert_equal("sixth is '[hey]'", "[hey]", in_between[5].value);189    });190}191 192static void test_calculate_diff_split(testing & t) {193    t.test("calculate_diff_split basic", test_calculate_diff_split_basic);194    t.test("calculate_diff_split identical", test_calculate_diff_split_identical);195    t.test("calculate_diff_split common prefix", test_calculate_diff_split_common_prefix);196    t.test("calculate_diff_split common suffix", test_calculate_diff_split_common_suffix);197    t.test("calculate_diff_split common both", test_calculate_diff_split_common_both);198    t.test("calculate_diff_split empty cases", test_calculate_diff_split_empty_cases);199    t.test("calculate_diff_split no common", test_calculate_diff_split_no_common);200    t.test("calculate_diff_split single char", test_calculate_diff_split_single_char);201    t.test("calculate_diff_split overlaps", test_calculate_diff_split_overlaps);202    t.test("calculate_diff_split tag boundaries", test_calculate_diff_split_tag_boundaries);203    t.test("calculate_diff_split generation prompt", test_calculate_diff_split_generation_prompt);204}205 206static void test_calculate_diff_split_basic(testing & t) {207    diff_split result = calculate_diff_split("hello world", "hello test");208    t.assert_equal("prefix should be 'hello '", "hello ", result.prefix);209    t.assert_equal("left should be 'world'", "world", result.left);210    t.assert_equal("right should be 'test'", "test", result.right);211    t.assert_equal("suffix should be empty", "", result.suffix);212 213    result = calculate_diff_split("abc", "xyz");214    t.assert_equal("prefix should be empty", "", result.prefix);215    t.assert_equal("left should be 'abc'", "abc", result.left);216    t.assert_equal("right should be 'xyz'", "xyz", result.right);217    t.assert_equal("suffix should be empty", "", result.suffix);218 219    result = calculate_diff_split("prefixA suffix", "prefixB suffix");220    t.assert_equal("prefix should be 'prefix'", "prefix", result.prefix);221    t.assert_equal("left should be 'A'", "A", result.left);222    t.assert_equal("right should be 'B'", "B", result.right);223    t.assert_equal("suffix should be ' suffix'", " suffix", result.suffix);224}225 226static void test_calculate_diff_split_identical(testing & t) {227    diff_split result = calculate_diff_split("hello", "hello");228    t.assert_equal("prefix should be 'hello'", "hello", result.prefix);229    t.assert_equal("left should be empty", "", result.left);230    t.assert_equal("right should be empty", "", result.right);231    t.assert_equal("suffix should be empty", "", result.suffix);232 233    result = calculate_diff_split("", "");234    t.assert_equal("prefix should be empty", "", result.prefix);235    t.assert_equal("left should be empty", "", result.left);236    t.assert_equal("right should be empty", "", result.right);237    t.assert_equal("suffix should be empty", "", result.suffix);238 239    result = calculate_diff_split("a", "a");240    t.assert_equal("prefix should be 'a'", "a", result.prefix);241    t.assert_equal("left should be empty", "", result.left);242    t.assert_equal("right should be empty", "", result.right);243    t.assert_equal("suffix should be empty", "", result.suffix);244 245    result = calculate_diff_split("<row><row><row><your><boat><gently>", "<row><row><row><your><boat><gently>");246    t.assert_equal("prefix should be '<row><row><row><your><boat><gently>'", "<row><row><row><your><boat><gently>", result.prefix);247    t.assert_equal("left should be empty", "", result.left);248    t.assert_equal("right should be empty", "", result.right);249    t.assert_equal("suffix should be empty", "", result.suffix);250}251 252static void test_calculate_diff_split_common_prefix(testing & t) {253    diff_split result = calculate_diff_split("abcdef", "abcxyz");254    t.assert_equal("prefix should be 'abc'", "abc", result.prefix);255    t.assert_equal("left should be 'def'", "def", result.left);256    t.assert_equal("right should be 'xyz'", "xyz", result.right);257    t.assert_equal("suffix should be empty", "", result.suffix);258 259    result = calculate_diff_split("same", "sameagain");260    t.assert_equal("prefix should be 'same'", "same", result.prefix);261    t.assert_equal("left should be empty", "", result.left);262    t.assert_equal("right should be 'again'", "again", result.right);263    t.assert_equal("suffix should be empty", "", result.suffix);264 265    result = calculate_diff_split("test", "testing");266    t.assert_equal("prefix should be 'test'", "test", result.prefix);267    t.assert_equal("left should be empty", "", result.left);268    t.assert_equal("right should be 'ing'", "ing", result.right);269    t.assert_equal("suffix should be empty", "", result.suffix);270}271 272static void test_calculate_diff_split_common_suffix(testing & t) {273    diff_split result = calculate_diff_split("123end", "456end");274    t.assert_equal("prefix should be empty", "", result.prefix);275    t.assert_equal("left should be '123'", "123", result.left);276    t.assert_equal("right should be '456'", "456", result.right);277    t.assert_equal("suffix should be 'end'", "end", result.suffix);278 279    result = calculate_diff_split("start", "end");280    t.assert_equal("prefix should be empty", "", result.prefix);281    t.assert_equal("left should be 'start'", "start", result.left);282    t.assert_equal("right should be 'end'", "end", result.right);283    t.assert_equal("suffix should be empty", "", result.suffix);284 285    result = calculate_diff_split("abcsuffix", "xyzsuffix");286    t.assert_equal("prefix should be empty", "", result.prefix);287    t.assert_equal("left should be 'abc'", "abc", result.left);288    t.assert_equal("right should be 'xyz'", "xyz", result.right);289    t.assert_equal("suffix should be 'suffix'", "suffix", result.suffix);290}291 292static void test_calculate_diff_split_common_both(testing & t) {293    diff_split result = calculate_diff_split("helloXworld", "helloYworld");294    t.assert_equal("prefix should be 'hello'", "hello", result.prefix);295    t.assert_equal("left should be 'X'", "X", result.left);296    t.assert_equal("right should be 'Y'", "Y", result.right);297    t.assert_equal("suffix should be 'world'", "world", result.suffix);298 299    result = calculate_diff_split("ABCmiddleXYZ", "ABCdifferentXYZ");300    t.assert_equal("prefix should be 'ABC'", "ABC", result.prefix);301    t.assert_equal("left should be 'middle'", "middle", result.left);302    t.assert_equal("right should be 'different'", "different", result.right);303    t.assert_equal("suffix should be 'XYZ'", "XYZ", result.suffix);304 305    result = calculate_diff_split("startAend", "startBend");306    t.assert_equal("prefix should be 'start'", "start", result.prefix);307    t.assert_equal("left should be 'A'", "A", result.left);308    t.assert_equal("right should be 'B'", "B", result.right);309    t.assert_equal("suffix should be 'end'", "end", result.suffix);310 311    // Edge case: common prefix and suffix overlap312    result = calculate_diff_split("aa", "ab");313    t.assert_equal("prefix should be 'a'", "a", result.prefix);314    t.assert_equal("left should be 'a'", "a", result.left);315    t.assert_equal("right should be 'b'", "b", result.right);316    t.assert_equal("suffix should be empty", "", result.suffix);317}318 319static void test_calculate_diff_split_empty_cases(testing & t) {320    // Empty left, non-empty right321    diff_split result = calculate_diff_split("", "hello");322    t.assert_equal("prefix should be empty", "", result.prefix);323    t.assert_equal("left should be empty", "", result.left);324    t.assert_equal("right should be 'hello'", "hello", result.right);325    t.assert_equal("suffix should be empty", "", result.suffix);326 327    // Non-empty left, empty right328    result = calculate_diff_split("hello", "");329    t.assert_equal("prefix should be empty", "", result.prefix);330    t.assert_equal("left should be 'hello'", "hello", result.left);331    t.assert_equal("right should be empty", "", result.right);332    t.assert_equal("suffix should be empty", "", result.suffix);333 334    // Both empty335    result = calculate_diff_split("", "");336    t.assert_equal("prefix should be empty", "", result.prefix);337    t.assert_equal("left should be empty", "", result.left);338    t.assert_equal("right should be empty", "", result.right);339    t.assert_equal("suffix should be empty", "", result.suffix);340 341    // Left single char, empty right342    result = calculate_diff_split("a", "");343    t.assert_equal("prefix should be empty", "", result.prefix);344    t.assert_equal("left should be 'a'", "a", result.left);345    t.assert_equal("right should be empty", "", result.right);346    t.assert_equal("suffix should be empty", "", result.suffix);347 348    // Empty left, right single char349    result = calculate_diff_split("", "a");350    t.assert_equal("prefix should be empty", "", result.prefix);351    t.assert_equal("left should be empty", "", result.left);352    t.assert_equal("right should be 'a'", "a", result.right);353    t.assert_equal("suffix should be empty", "", result.suffix);354}355 356static void test_calculate_diff_split_no_common(testing & t) {357    diff_split result = calculate_diff_split("abc", "xyz");358    t.assert_equal("prefix should be empty", "", result.prefix);359    t.assert_equal("left should be 'abc'", "abc", result.left);360    t.assert_equal("right should be 'xyz'", "xyz", result.right);361    t.assert_equal("suffix should be empty", "", result.suffix);362 363    result = calculate_diff_split("left", "right");364    // The algorithm finds "t" as a common suffix since both strings end with 't'365    // This is the algorithm's actual behavior - it finds maximal common suffix366    t.assert_equal("prefix should be empty", "", result.prefix);367    t.assert_equal("left should be 'lef'", "lef", result.left);368    t.assert_equal("right should be 'righ'", "righ", result.right);369    t.assert_equal("suffix should be 't'", "t", result.suffix);370 371    result = calculate_diff_split("123", "456");372    t.assert_equal("prefix should be empty", "", result.prefix);373    t.assert_equal("left should be '123'", "123", result.left);374    t.assert_equal("right should be '456'", "456", result.right);375    t.assert_equal("suffix should be empty", "", result.suffix);376}377 378static void test_calculate_diff_split_single_char(testing & t) {379    diff_split result = calculate_diff_split("a", "b");380    t.assert_equal("prefix should be empty", "", result.prefix);381    t.assert_equal("left should be 'a'", "a", result.left);382    t.assert_equal("right should be 'b'", "b", result.right);383    t.assert_equal("suffix should be empty", "", result.suffix);384 385    result = calculate_diff_split("a", "a");386    t.assert_equal("prefix should be 'a'", "a", result.prefix);387    t.assert_equal("left should be empty", "", result.left);388    t.assert_equal("right should be empty", "", result.right);389    t.assert_equal("suffix should be empty", "", result.suffix);390 391    result = calculate_diff_split("a", "ab");392    t.assert_equal("prefix should be 'a'", "a", result.prefix);393    t.assert_equal("left should be empty", "", result.left);394    t.assert_equal("right should be 'b'", "b", result.right);395    t.assert_equal("suffix should be empty", "", result.suffix);396 397    result = calculate_diff_split("ab", "a");398    t.assert_equal("prefix should be 'a'", "a", result.prefix);399    t.assert_equal("left should be 'b'", "b", result.left);400    t.assert_equal("right should be empty", "", result.right);401    t.assert_equal("suffix should be empty", "", result.suffix);402}403 404static void test_calculate_diff_split_overlaps(testing & t) {405    // One string is substring of another406    diff_split result = calculate_diff_split("test", "testing");407    t.assert_equal("prefix should be 'test'", "test", result.prefix);408    t.assert_equal("left should be empty", "", result.left);409    t.assert_equal("right should be 'ing'", "ing", result.right);410    t.assert_equal("suffix should be empty", "", result.suffix);411 412    result = calculate_diff_split("testing", "test");413    t.assert_equal("prefix should be 'test'", "test", result.prefix);414    t.assert_equal("left should be 'ing'", "ing", result.left);415    t.assert_equal("right should be empty", "", result.right);416    t.assert_equal("suffix should be empty", "", result.suffix);417 418    // Similar strings with one extra char at start419    result = calculate_diff_split("Xtest", "Ytest");420    // The algorithm finds "test" as a common suffix since both strings end with "test"421    // This is the algorithm's actual behavior - it finds maximal common suffix422    t.assert_equal("prefix should be empty", "", result.prefix);423    t.assert_equal("left should be 'X'", "X", result.left);424    t.assert_equal("right should be 'Y'", "Y", result.right);425    t.assert_equal("suffix should be 'test'", "test", result.suffix);426 427    // Similar strings with one extra char at end428    result = calculate_diff_split("testX", "testY");429    t.assert_equal("prefix should be 'test'", "test", result.prefix);430    t.assert_equal("left should be 'X'", "X", result.left);431    t.assert_equal("right should be 'Y'", "Y", result.right);432    t.assert_equal("suffix should be empty", "", result.suffix);433 434    // Strings that are reverses435    result = calculate_diff_split("abc", "cba");436    t.assert_equal("prefix should be empty", "", result.prefix);437    t.assert_equal("left should be 'abc'", "abc", result.left);438    t.assert_equal("right should be 'cba'", "cba", result.right);439    t.assert_equal("suffix should be empty", "", result.suffix);440}441 442static void test_calculate_diff_split_tag_boundaries(testing & t) {443    // Test with unclosed XML tags444    diff_split result = calculate_diff_split("test<tag", "test>content");445    // The fix_tag_boundaries should move incomplete tags appropriately446    t.assert_true("prefix should start with 'test'", result.prefix.find("test") == 0);447    t.assert_true("should handle tag boundaries", result.left != "" || result.right != "" || result.suffix != "");448 449    // Test with unclosed brackets450    result = calculate_diff_split("test[", "test]value");451    t.assert_true("should handle bracket boundaries", result.left != "" || result.right != "" || result.suffix != "");452 453    // Test with partial tags on both sides454    result = calculate_diff_split("prefix<tag>", "prefix</tag>suffix");455    // fix_tag_boundaries moves the incomplete '<' from prefix to left/right456    t.assert_equal("prefix should be 'prefix'", "prefix", result.prefix);457    t.assert_equal("left should be '<tag>'", "<tag>", result.left);458    t.assert_equal("right should be '</tag>suffix'", "</tag>suffix", result.right);459    t.assert_equal("suffix should be empty", "", result.suffix);460 461    // Test with complex nested tags462    result = calculate_diff_split("prefix<div>content</div>", "prefix<div>different</div>");463    // Algorithm finds "ent</div>" as a common suffix because both strings end with it464    // This is the actual algorithm behavior, though not semantically ideal465    t.assert_equal("prefix should be 'prefix<div>'", "prefix<div>", result.prefix);466    t.assert_equal("left should be 'cont'", "cont", result.left);467    t.assert_equal("right should be 'differ'", "differ", result.right);468    t.assert_equal("suffix should be 'ent</div>'", "ent</div>", result.suffix);469 470    // Test with unclosed angle bracket471    result = calculate_diff_split("Hello <world>", "Hello test");472    t.assert_equal("prefix should be 'Hello '", "Hello ", result.prefix);473    t.assert_true("left should contain '<world>'", result.left.find("<world>") != std::string::npos);474    t.assert_equal("right should be 'test'", "test", result.right);475    t.assert_equal("suffix should be empty", "", result.suffix);476 477    // Test with unclosed square bracket478    result = calculate_diff_split("test [array]", "test other");479    t.assert_equal("prefix should be 'test '", "test ", result.prefix);480    t.assert_true("left should contain '[array]'", result.left.find("[array]") != std::string::npos);481    t.assert_equal("right should be 'other'", "other", result.right);482    t.assert_equal("suffix should be empty", "", result.suffix);483 484    // Test empty prefix and suffix with tags485    result = calculate_diff_split("<tag>left</tag>", "<tag>righ</tag>");486    t.assert_equal("prefix should be '<tag>'", "<tag>", result.prefix);487    t.assert_equal("left should be 'left'", "left", result.left);488    t.assert_equal("right should be 'righ'", "righ", result.right);489    t.assert_equal("suffix should be '</tag>'", "</tag>", result.suffix);490 491    {492        // real case from template tests, simplified493        std::string left  = "PREFIX</think>Sure";494        std::string right = "PREFIX<think>Lemme think</think>Sure";495        result            = calculate_diff_split(left, right);496        t.assert_equal("prefix should be PREFIX", "PREFIX", result.prefix);497        t.assert_equal("suffix should be </think>Sure", "</think>Sure", result.suffix);498        t.assert_equal("left should be empty", "", result.left);499        t.assert_equal("right should be <think>Lemme think", "<think>Lemme think", result.right);500    }501 502    {503        // Real case: special tokens with |> boundary issue504        // The suffix starts with |> which should be moved to complete <|END_RESPONSE and <|END_ACTION505        std::string prefix    = "SOME_PREFIX";506        std::string suffix    = "|><|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>";507        std::string left_diff = "<|START_RESPONSE|>Let me help you.<|END_RESPONSE";508        std::string right_diff =509            "<|START_THINKING|><|END_THINKING|><|START_ACTION|>[\n"510            "    {\"tool_call_id\": \"0\", \"tool_name\": \"test_function_name\", "511            "\"parameters\": {\"param1\": \"value1\", \"param2\": \"value2\"}}\n"512            "]<|END_ACTION";513 514        std::string left  = prefix + left_diff + suffix;515        std::string right = prefix + right_diff + suffix;516        result            = calculate_diff_split(left, right);517 518        t.assert_equal("special token prefix", prefix, result.prefix);519        // The |> should be moved from suffix to complete the tokens520        t.assert_equal("special token left", "<|START_RESPONSE|>Let me help you.<|END_RESPONSE|>", result.left);521        t.assert_true("special token right ends with |>", result.right.find("<|END_ACTION|>") != std::string::npos);522        t.assert_equal("special token suffix", "<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>",523                       result.suffix);524    }525}526 527static void test_calculate_diff_split_generation_prompt(testing & t) {528    // ChatML thinking template: left is a prefix of right, generation_prompt is the appended part.529    // The trailing \n in left matches the trailing \n in the generation_prompt, causing530    // the suffix matcher to steal it and rotate the diff result.531    {532        // Simplified reproduction: left ends with \n, right = left + "<|im_start|>assistant\n<think>\n"533        std::string left  = "<|im_start|>user\nHello<|im_end|>\n";534        std::string right = left + "<|im_start|>assistant\n<think>\n";535        diff_split result = calculate_diff_split(left, right);536        t.assert_equal("chatml prefix", left, result.prefix);537        t.assert_equal("chatml left", "", result.left);538        t.assert_equal("chatml right should be generation prompt",539                       "<|im_start|>assistant\n<think>\n", result.right);540        t.assert_equal("chatml suffix", "", result.suffix);541    }542 543    {544        // More realistic: longer conversation ending with tool_response545        std::string common =546            "<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n"547            "<|im_start|>user\nSearch for files<|im_end|>\n"548            "<|im_start|>assistant\n<think>\nLet me search.\n</think>\n\n"549            "<tool_call>\n<function=search>\n</function>\n</tool_call><|im_end|>\n"550            "<|im_start|>user\n<tool_response>\nNo files found\n</tool_response><|im_end|>\n";551        std::string left  = common;552        std::string right = common + "<|im_start|>assistant\n<think>\n";553        diff_split result = calculate_diff_split(left, right);554        t.assert_equal("tool_response left", "", result.left);555        t.assert_equal("tool_response right should be generation prompt",556                       "<|im_start|>assistant\n<think>\n", result.right);557    }558}559 560static void test_until_common_prefix(testing & t) {561    t.test("until_common_prefix basic", test_until_common_prefix_basic);562}563 564static void test_until_common_prefix_basic(testing & t) {565    // Test case from the user request566    std::string result = until_common_prefix("<function name=foo><arg name=bar>", "<arg name=bar>", "<arg name=baz>");567    t.assert_equal("untilCommonPrefix should return '<function name=foo>'", "<function name=foo>", result);568 569    // Additional test cases to ensure robustness570    // Test with different common prefix lengths571    result = until_common_prefix("prefix<test>suffix", "<test>different", "<test>other");572    t.assert_equal("should return 'prefix'", "prefix", result);573 574    // Test when common prefix is at the start575    result = until_common_prefix("<common>rest", "<common>left", "<common>right");576    t.assert_equal("should return empty string when common prefix at start", "", result);577 578    // Test when there's no common prefix579    result = until_common_prefix("something", "left", "right");580    t.assert_equal("should return empty string when no common prefix", "", result);581 582    // Test with empty strings583    result = until_common_prefix("test", "", "right");584    t.assert_equal("should return empty string when left is empty", "", result);585 586    // Test with longer common prefix587    result = until_common_prefix("abcXYZ<shared_prefix>rest", "<shared_prefix>left", "<shared_prefix>right");588    t.assert_equal("should return 'abcXYZ'", "abcXYZ", result);589}590 591static void test_after_common_suffix(testing & t) {592    t.test("after_common_suffix basic", test_after_common_suffix_basic);593}594 595static void test_after_common_suffix_basic(testing & t) {596    // Test case from the user request597    std::string result = after_common_suffix("<function name=foo><arg name=bar>100</arg></function>",598                                            "<arg name=bar>100</arg>",599                                            "<arg name=baz>535</arg>");600    t.assert_equal("afterCommonSuffix should return '</function>'", "</function>", result);601 602    // Test when common suffix is at the end603    result = after_common_suffix("rest<common>", "left<common>", "right<common>");604    t.assert_equal("should return empty string when common suffix at end", "", result);605 606    // Test with empty strings607    result = after_common_suffix("test", "left", "");608    t.assert_equal("should return empty string when right is empty", "", result);609 610    // Test case with XML-like structure similar to the main example611    result = after_common_suffix("<outer><inner>value</inner></outer>",612                                "<inner>value</inner>",613                                "<inner>different</inner>");614    t.assert_equal("should return '</outer>'", "</outer>", result);615 616    // Test with longer common suffix appearing at the end of full617    result = after_common_suffix("prefix<shared>rest</shared>", "prefix<shared>left</shared>", "prefix<shared>right</shared>");618    t.assert_equal("should return '' when common suffix is at end of full", "", result);619 620    // Test with common suffix appearing in middle but not at end621    result = after_common_suffix("<tag>content</tag><extra>", "<tag>value</tag>", "<tag>other</tag>");622    t.assert_equal("should return '<extra>' when common suffix appears before end", "<extra>", result);623 624    // Test with multi-character common suffix at the very end of full625    result = after_common_suffix("start<middle>end</middle>", "prefix<middle>left</middle>", "prefix<middle>right</middle>");626    t.assert_equal("should return '' when common suffix </middle> is at end of full", "", result);627}628 629static void test_compare_variants(testing & t) {630    t.test("compare_variants basic", test_compare_variants_basic);631    t.test("compare_variants messages modifier", test_compare_variants_messages_modifier);632    t.test("compare_variants tools modifier", test_compare_variants_tools_modifier);633    t.test("compare_variants both modifiers", test_compare_variants_both_modifiers);634    t.test("compare_variants template failure", test_compare_variants_template_failure);635    t.test("compare_variants identity", test_compare_variants_identity);636}637 638static void test_compare_variants_basic(testing & t) {639    // Create a simple template that just echoes messages640    common_chat_template tmpl("{{ messages[0]['content'] }}", "", "");641 642    template_params params;643    params.messages = json::array({644        json {{"role", "user"}, {"content", "Hello"}}645    });646 647    auto modifier = [](template_params & p) {648        p.messages[0]["content"] = "World";649    };650 651    auto result = ::compare_variants(tmpl, params, modifier);652 653    if (!t.assert_true("result should have value", result.has_value())) {654        return;655    }656    // The template might not output anything if messages is empty or format is different657    // Check that we get a valid result658    t.assert_true("prefix or left should have content", !result->diff.prefix.empty() || !result->diff.left.empty());659}660 661static void test_compare_variants_messages_modifier(testing & t) {662    // Test with messages modifier only663    common_chat_template tmpl("{% for message in messages %}{{ message['role'] }}:{{ message['content'] }}{% endfor %}", "", "");664 665    template_params params;666    params.messages = json::array({667        json {{"role", "user"}, {"content", "A"}}668    });669 670    auto modifier = [](template_params & p) {671        p.messages[0]["content"] = "B";672    };673 674    std::optional<compare_variants_result> result = ::compare_variants(tmpl, params, modifier);675 676    if (!t.assert_true("result should have value", result.has_value())) {677        return;678    }679    t.assert_equal("left should be 'A'", "A", result->diff.left);680    t.assert_equal("right should be 'B'", "B", result->diff.right);681}682 683static void test_compare_variants_tools_modifier(testing & t) {684    // Test with tools modifier only685    common_chat_template tmpl(686        "{% for tool in tools %}{{ tool['name'] }}{% endfor %}", "", "");687 688    template_params params;689    params.tools = json::array({690        json {{"name", "foo"}}691    });692 693    auto modifier = [](template_params & p) {694        p.tools[0]["name"] = "bar";695    };696 697    auto result = ::compare_variants(tmpl, params, modifier);698 699    if (!t.assert_true("result should have value", result.has_value())) {700        return;701    }702    t.assert_equal("left should be 'foo'", "foo", result->diff.left);703    t.assert_equal("right should be 'bar'", "bar", result->diff.right);704}705 706static void test_compare_variants_both_modifiers(testing & t) {707    // Test with both messages and tools modifiers using the for loop approach708    common_chat_template tmpl(709        "{% for message in messages %}{{ message['role'] }}:{{ message['content'] }}{% endfor %}", "", "");710 711    template_params params;712    params.messages = json::array({713        json {{"role", "user"}, {"content", "A"}}714    });715 716    auto modifier = [](template_params & p) {717        p.messages[0]["content"] = "B";718        p.messages[0]["role"] = "newuser";719    };720 721    auto result = ::compare_variants(tmpl, params, modifier);722 723    if (!t.assert_true("result should have value", result.has_value())) {724        return;725    }726    t.assert_equal("left should be 'user:A'", "user:A", result->diff.left);727    t.assert_equal("right should be 'newuser:B'", "newuser:B", result->diff.right);728}729 730static void test_compare_variants_template_failure(testing & t) {731    // Test with template that causes failure during application (not construction)732    // We use a valid template syntax but one that will fail during application733    common_chat_template tmpl("{{ messages.cahoot()[0]['nonexistent_field'] }}", "", "");734 735    template_params params;736    params.messages = json::array({737        json {{"role", "user"}, {"content", "Hello"}}738    });739 740    auto modifier = [](template_params & p) {741        p.messages[0]["content"] = "World";742    };743 744    auto result = ::compare_variants(tmpl, params, modifier);745 746    t.assert_true("result should be nullopt on template failure", !result.has_value());747}748 749static void test_compare_variants_identity(testing & t) {750    // Test with identity modifier (no change)751    common_chat_template tmpl("{{ messages[0]['content'] }}", "", "");752 753    template_params params;754    params.messages = json::array({755        json {{"role", "user"}, {"content", "Hello"}}756    });757 758    // No modifier - should use identity759    auto result = ::compare_variants(tmpl, params, nullptr);760 761    if (!t.assert_true("result should have value", result.has_value())) {762        return;763    }764    t.assert_equal("prefix should be 'Hello'", "Hello", result->diff.prefix);765    t.assert_equal("left should be empty", "", result->diff.left);766    t.assert_equal("right should be empty", "", result->diff.right);767    t.assert_equal("suffix should be empty", "", result->diff.suffix);768}769 770// ============================================================================771// Seed-OSS Template Tool Calling Analysis Tests772// ============================================================================773 774static void test_seed_oss_tool_analysis(testing & t) {775    t.test("Seed-OSS tool presence", test_seed_oss_tool_presence);776    t.test("Seed-OSS call count", test_seed_oss_call_count);777    t.test("Seed-OSS function names", test_seed_oss_function_names);778    t.test("Seed-OSS argument count", test_seed_oss_argument_count);779    t.test("Seed-OSS args presence", test_seed_oss_args_presence);780    t.test("Seed-OSS tool with reasoning", test_seed_oss_tool_with_reasoning);781}782 783// Helper to load Seed-OSS template784static common_chat_template load_seed_oss_template(testing & t) {785    std::string template_path = "models/templates/ByteDance-Seed-OSS.jinja";786    std::ifstream fin(template_path, std::ios::binary);787    std::ostringstream buf;788    if (fin.is_open()) {789        buf << fin.rdbuf();790    }791    std::string template_source = buf.str();792    common_chat_template tmpl(template_source, "", "");793    t.assert_true("Seed-OSS template loaded successfully", template_source.length() > 0);794    return tmpl;795}796 797// Helper to build tool call JSON798static json build_tool_call(const std::string & name, const json & args, const std::string & id = "call_001") {799    return json{800        {"id", id},801        {"type", "function"},802        {"function", json{803            {"name", name},804            {"arguments", args}805        }}806    };807}808 809// Helper to build tools definition810static json build_tools_definition() {811    json parameters_schema = json::object();812    parameters_schema["type"] = "object";813    parameters_schema["properties"] = json::object();814    parameters_schema["properties"]["param1"] = json::object({815        {"type", "string"},816        {"description", "First parameter"}817    });818    parameters_schema["properties"]["param2"] = json::object({819        {"type", "string"},820        {"description", "Second parameter"}821    });822    parameters_schema["required"] = json::array({"param1", "param2"});823 824    return json::array({825        json{826            {"type", "function"},827            {"function", json{828                {"name", "test_function_name"},829                {"description", "A test function for debugging"},830                {"parameters", parameters_schema}831            }}832        }833    });834}835 836// T1: Compare with/without tool call (user, assistant)837static void test_seed_oss_tool_presence(testing & t) {838    common_chat_template tmpl = load_seed_oss_template(t);839 840    json assistant_no_tools = json{841        {"role", "assistant"},842        {"content", "Let me help you."}843    };844 845    json assistant_with_tools = json{846        {"role", "assistant"},847        {"content", nullptr},848        {"tool_calls", json::array({849            build_tool_call("test_function_name", json::object({{"param1", "value1"}, {"param2", "value2"}}))850        })}851    };852 853    json user_msg = json{854        {"role", "user"},855        {"content", "Hello, please help me."}856    };857 858    template_params params_no_tools;859    params_no_tools.messages = json::array({user_msg, assistant_no_tools});860    params_no_tools.tools = build_tools_definition();861    params_no_tools.add_generation_prompt = false;862    params_no_tools.enable_thinking = true;863 864    template_params params_with_tools;865    params_with_tools.messages = json::array({user_msg, assistant_with_tools});866    params_with_tools.tools = build_tools_definition();867    params_with_tools.add_generation_prompt = false;868    params_with_tools.enable_thinking = true;869 870    auto result = ::compare_variants(tmpl, params_no_tools,871        [&](template_params & p) {872            p.messages = params_with_tools.messages;873        });874 875    if (!t.assert_true("T1 result should have value", result.has_value())) {876        return;877    }878 879    const auto & diff = result->diff;880    t.assert_true("T1 prefix should contain system", diff.prefix.find("system") != std::string::npos);881    t.assert_true("T1 prefix should contain user", diff.prefix.find("user") != std::string::npos);882    t.assert_true("T1 prefix should contain assistant", diff.prefix.find("assistant") != std::string::npos);883 884    // Left should be the assistant content without tool885    t.assert_equal("T1 left should contain 'Let me help you.'", "Let me help you.", diff.left);886 887    // Right should contain the tool call markers888    t.assert_true("T1 right should contain tool_call begin", diff.right.find("<seed:tool_call>") != std::string::npos);889    t.assert_true("T1 right should contain function tag", diff.right.find("<function=test_function_name>") != std::string::npos);890    t.assert_true("T1 right should contain parameter=param1", diff.right.find("<parameter=param1>") != std::string::npos);891    t.assert_true("T1 right should contain parameter=param2", diff.right.find("<parameter=param2>") != std::string::npos);892    t.assert_true("T1 right should contain value1", diff.right.find("value1") != std::string::npos);893    t.assert_true("T1 right should contain value2", diff.right.find("value2") != std::string::npos);894    t.assert_true("T1 right should contain tool_call end", diff.right.find("</seed:tool_call>") != std::string::npos);895 896    // Suffix should be the eos token897    t.assert_equal("T1 suffix should be '<seed:eos>'", "<seed:eos>", diff.suffix);898}899 900// T2: Compare one vs two tool calls901static void test_seed_oss_call_count(testing & t) {902    common_chat_template tmpl = load_seed_oss_template(t);903 904    json assistant_one_call = json{905        {"role", "assistant"},906        {"content", nullptr},907        {"tool_calls", json::array({908            build_tool_call("test_function_name", json::object({{"param1", "value1"}, {"param2", "value2"}}))909        })}910    };911 912    json assistant_two_calls = json{913        {"role", "assistant"},914        {"content", nullptr},915        {"tool_calls", json::array({916            build_tool_call("test_function_name", json::object({{"param1", "value1"}, {"param2", "value2"}})),917            build_tool_call("test_function_name", json::object({{"param1", "value3"}, {"param2", "value4"}}), "call_002")918        })}919    };920 921    json user_msg = json{922        {"role", "user"},923        {"content", "Hello, please help me."}924    };925 926    template_params params_one;927    params_one.messages = json::array({user_msg, assistant_one_call});928    params_one.tools = build_tools_definition();929    params_one.add_generation_prompt = false;930    params_one.enable_thinking = true;931 932    auto result = ::compare_variants(tmpl, params_one,933        [&](template_params & p) {934            p.messages = json::array({user_msg, assistant_two_calls});935        });936 937    if (!t.assert_true("T2 result should have value", result.has_value())) {938        return;939    }940 941    const auto & diff = result->diff;942 943    // Prefix should include the first tool call944    t.assert_true("T2 prefix should contain first tool_call begin", diff.prefix.find("<seed:tool_call>") != std::string::npos);945    t.assert_true("T2 prefix should contain first function", diff.prefix.find("<function=test_function_name>") != std::string::npos);946    t.assert_true("T2 prefix should contain value1", diff.prefix.find("value1") != std::string::npos);947    t.assert_true("T2 prefix should contain value2", diff.prefix.find("value2") != std::string::npos);948    t.assert_true("T2 prefix should contain first tool_call end", diff.prefix.find("</seed:tool_call>") != std::string::npos);949 950    // Left should be empty (no second tool call in variant A)951    t.assert_equal("T2 left should be empty", "", diff.left);952 953    // Right should contain the second tool call954    t.assert_true("T2 right should contain second tool_call begin", diff.right.find("<seed:tool_call>") != std::string::npos);955    t.assert_true("T2 right should contain second function", diff.right.find("<function=test_function_name>") != std::string::npos);956    t.assert_true("T2 right should contain value3", diff.right.find("value3") != std::string::npos);957    t.assert_true("T2 right should contain value4", diff.right.find("value4") != std::string::npos);958    t.assert_true("T2 right should contain second tool_call end", diff.right.find("</seed:tool_call>") != std::string::npos);959 960    // Suffix should end with the eos token961    t.assert_equal("T2 suffix should end with '<seed:eos>'", "<seed:eos>", diff.suffix.substr(diff.suffix.length() - 10, 10));962}963 964// T3: Compare different function names965static void test_seed_oss_function_names(testing & t) {966    common_chat_template tmpl = load_seed_oss_template(t);967 968    // Build tools with two different function names969    json parameters_schema = json::object();970    parameters_schema["type"] = "object";971    parameters_schema["properties"] = json::object();972    parameters_schema["properties"]["arg1"] = json::object({973        {"type", "string"},974        {"description", "Argument 1"}975    });976    parameters_schema["required"] = json::array({"arg1"});977 978    json tools = json::array({979        json{980            {"type", "function"},981            {"function", json{982                {"name", "func_alpha"},983                {"description", "First function"},984                {"parameters", parameters_schema}985            }}986        },987        json{988            {"type", "function"},989            {"function", json{990                {"name", "func_beta"},991                {"description", "Second function"},992                {"parameters", parameters_schema}993            }}994        }995    });996 997    json assistant_func_alpha = json{998        {"role", "assistant"},999        {"content", nullptr},1000        {"tool_calls", json::array({1001            build_tool_call("func_alpha", json::object({{"arg1", "test_value"}}))1002        })}1003    };1004 1005    json assistant_func_beta = json{1006        {"role", "assistant"},1007        {"content", nullptr},1008        {"tool_calls", json::array({1009            build_tool_call("func_beta", json::object({{"arg1", "test_value"}}))1010        })}1011    };1012 1013    json user_msg = json{1014        {"role", "user"},1015        {"content", "Hello"}1016    };1017 1018    template_params params_alpha;1019    params_alpha.messages = json::array({user_msg, assistant_func_alpha});1020    params_alpha.tools = tools;1021    params_alpha.add_generation_prompt = false;1022    params_alpha.enable_thinking = true;1023 1024    auto result = ::compare_variants(tmpl, params_alpha,1025        [&](template_params & p) {1026            p.messages = json::array({user_msg, assistant_func_beta});1027        });1028 1029    if (!t.assert_true("T3 result should have value", result.has_value())) {1030        return;1031    }1032 1033    const auto & diff = result->diff;1034 1035    bool func_alpha_in_left = diff.left.find("func_alpha") != std::string::npos;1036    bool func_alpha_in_prefix = diff.prefix.find("func_alpha") != std::string::npos;1037    bool func_beta_in_right = diff.right.find("func_beta") != std::string::npos;1038    bool func_beta_in_prefix = diff.prefix.find("func_beta") != std::string::npos;1039    bool func_beta_in_suffix = diff.suffix.find("func_beta") != std::string::npos;1040 1041    // Left should contain func_alpha (or be in prefix)1042    t.assert_true("T3 left should contain func_alpha (or prefix)", func_alpha_in_left || func_alpha_in_prefix);1043 1044    // Right should contain func_beta1045    t.assert_true("T3 right should contain func_beta", func_beta_in_right || func_beta_in_prefix || func_beta_in_suffix);1046 1047    // Both should have the same parameter value (in common parts, not in diffs)1048    // Since both have same args, test_value will be in prefix/suffix1049    t.assert_true("T3 diff should contain test_value (in prefix or suffix)",1050        diff.prefix.find("test_value") != std::string::npos || diff.suffix.find("test_value") != std::string::npos);1051}1052 1053// T4: Compare different argument counts (zero, one, two parameters)1054static void test_seed_oss_argument_count(testing & t) {1055    common_chat_template tmpl = load_seed_oss_template(t);1056 1057    // Build tools with 0, 1, or 2 required parameters1058    json params_2_required = json::object();1059    params_2_required["type"] = "object";1060    params_2_required["properties"] = json::object();1061    params_2_required["properties"]["arg1"] = json::object({1062        {"type", "string"},1063        {"description", "Argument 1"}1064    });1065    params_2_required["properties"]["arg2"] = json::object({1066        {"type", "string"},1067        {"description", "Argument 2"}1068    });1069    params_2_required["required"] = json::array({"arg1", "arg2"});1070 1071    json params_1_required = json::object();1072    params_1_required["type"] = "object";1073    params_1_required["properties"] = json::object();1074    params_1_required["properties"]["arg1"] = json::object({1075        {"type", "string"},1076        {"description", "Argument 1"}1077    });1078    params_1_required["required"] = json::array({"arg1"});1079 1080    json tools = json::array({1081        json{1082            {"type", "function"},1083            {"function", json{1084                {"name", "test_func"},1085                {"description", "Test function"},1086                {"parameters", params_2_required}1087            }}1088        }1089    });1090 1091    // Test: zero args vs one arg1092    json assistant_zero_args = json{1093        {"role", "assistant"},1094        {"content", nullptr},1095        {"tool_calls", json::array({1096            build_tool_call("test_func", json::object())1097        })}1098    };1099 1100    json assistant_one_arg = json{1101        {"role", "assistant"},1102        {"content", nullptr},1103        {"tool_calls", json::array({1104            build_tool_call("test_func", json::object({{"arg1", "value1"}}))1105        })}1106    };1107 1108    json assistant_two_args = json{1109        {"role", "assistant"},1110        {"content", nullptr},1111        {"tool_calls", json::array({1112            build_tool_call("test_func", json::object({{"arg1", "value1"}, {"arg2", "value2"}}))1113        })}1114    };1115 1116    json user_msg = json{1117        {"role", "user"},1118        {"content", "Hello"}1119    };1120 1121    // Test zero vs one1122    template_params params_zero;1123    params_zero.messages = json::array({user_msg, assistant_zero_args});1124    params_zero.tools = tools;1125    params_zero.add_generation_prompt = false;1126    params_zero.enable_thinking = true;1127 1128    auto result_zero_one = ::compare_variants(tmpl, params_zero,1129        [&](template_params & p) {1130            p.messages = json::array({user_msg, assistant_one_arg});1131        });1132 1133    if (!t.assert_true("T4 zero vs one result should have value", result_zero_one.has_value())) {1134        return;1135    }1136    t.assert_true("T4 zero vs one left should be empty or minimal", result_zero_one->diff.left.empty() || result_zero_one->diff.left == "");1137    t.assert_true("T4 zero vs one right should contain arg1", result_zero_one->diff.right.find("arg1") != std::string::npos);1138 1139    // Test one vs two1140    template_params params_one;1141    params_one.messages = json::array({user_msg, assistant_one_arg});1142    params_one.tools = tools;1143    params_one.add_generation_prompt = false;1144    params_one.enable_thinking = true;1145 1146    auto result_one_two = ::compare_variants(tmpl, params_one,1147        [&](template_params & p) {1148            p.messages = json::array({user_msg, assistant_two_args});1149        });1150 1151    if (!t.assert_true("T4 one vs two result should have value", result_one_two.has_value())) {1152        return;1153    }1154 1155    const auto & diff4 = result_one_two->diff;1156    t.assert_true("T4 one vs two left should contain arg1 (or prefix)",1157        diff4.left.find("arg1") != std::string::npos || diff4.prefix.find("arg1") != std::string::npos);1158    t.assert_true("T4 one vs two right should contain arg1 (or prefix)",1159        diff4.right.find("arg1") != std::string::npos || diff4.prefix.find("arg1") != std::string::npos);1160    t.assert_true("T4 one vs two right should contain arg2 (or prefix/suffix)",1161        diff4.right.find("arg2") != std::string::npos || diff4.prefix.find("arg2") != std::string::npos || diff4.suffix.find("arg2") != std::string::npos);1162}1163 1164// T5: Compare different argument values1165static void test_seed_oss_args_presence(testing & t) {1166    common_chat_template tmpl = load_seed_oss_template(t);1167 1168    json assistant_same_arg = json{1169        {"role", "assistant"},1170        {"content", nullptr},1171        {"tool_calls", json::array({1172            build_tool_call("test_function_name", json::object({{"param1", "value1"}}))1173        })}1174    };1175 1176    json assistant_other_arg = json{1177        {"role", "assistant"},1178        {"content", nullptr},1179        {"tool_calls", json::array({1180            build_tool_call("test_function_name", json::object({{"param2", "value2"}}))1181        })}1182    };1183 1184    json assistant_both_args = json{1185        {"role", "assistant"},1186        {"content", nullptr},1187        {"tool_calls", json::array({1188            build_tool_call("test_function_name", json::object({{"param1", "value1"}, {"param2", "value2"}}))1189        })}1190    };1191 1192    json user_msg = json{1193        {"role", "user"},1194        {"content", "Hello"}1195    };1196 1197    template_params params_same;1198    params_same.messages = json::array({user_msg, assistant_same_arg});1199    params_same.tools = build_tools_definition();1200    params_same.add_generation_prompt = false;

Showing the first 1,200 of 2202 lines. Download the file for the rest.

Brunobkr/llama.cpp_AlgMor24_github · Team Ai