Team Ai
Modelpublic

Felipe97/llama-cpp-compiled

sourceHugging Faceupdated 21d agoView on Hugging Face
0likes1.2kdownloads
gpt-oss.cpp159 linesDownload Raw Back to parsers
1#include "parsers.h"2 3common_chat_params common_chat_params_init_gpt_oss(const common_chat_template &    tmpl,4                                                          const autoparser::generation_params & inputs) {5    common_chat_params data;6 7    // Copy reasoning to the "thinking" field as expected by the gpt-oss template8    auto adjusted_messages = json::array();9    for (auto msg : inputs.messages) {10        if (msg.contains("reasoning_content") && msg.at("reasoning_content").is_string()) {11            msg["thinking"] = msg.at("reasoning_content");12            if (msg.contains("tool_calls") && msg.at("tool_calls").is_array() && !msg.at("tool_calls").empty()) {13                msg.erase("content");14            }15        }16        adjusted_messages.push_back(msg);17    }18 19    auto prompt = common_chat_template_direct_apply_impl(tmpl, inputs, /* messages_override= */ adjusted_messages);20 21    // Check if we need to replace the return token with end token during22    // inference and without generation prompt. For more details see:23    // https://github.com/ggml-org/llama.cpp/issues/1541724    if (inputs.is_inference && !inputs.add_generation_prompt) {25        static constexpr std::string_view return_token = "<|return|>";26        static constexpr std::string_view end_token    = "<|end|>";27        if (size_t pos = prompt.rfind(return_token); pos != std::string::npos) {28            prompt.replace(pos, return_token.length(), end_token);29        }30    }31 32    data.prompt            = prompt;33    data.generation_prompt = common_chat_template_generation_prompt_impl(tmpl, inputs, /* messages_override= */ adjusted_messages);34    data.message_delimiters = {35        { COMMON_CHAT_ROLE_ASSISTANT, "<|start|>assistant" },36        { COMMON_CHAT_ROLE_USER,      "<|start|>user"      },37        { COMMON_CHAT_ROLE_SYSTEM,    "<|start|>developer" },38        { COMMON_CHAT_ROLE_SYSTEM,    "<|start|>system"    },39        { COMMON_CHAT_ROLE_TOOL,      "<|start|>functions" },40    };41 42    data.format            = COMMON_CHAT_FORMAT_PEG_NATIVE;43    data.supports_thinking = true;44 45    data.thinking_start_tag = "<|channel|>analysis<|message|>";46    data.thinking_end_tags  = {"<|end|>"};47 48    // These special tokens are required to parse properly, so we include them49    // even if parse_tool_calls is false.50    data.preserved_tokens = {51        "<|channel|>", "<|constrain|>", "<|message|>", "<|start|>", "<|end|>",52    };53 54    // Adjust prompt for continuation55    if (inputs.has_continuation()) {56        const auto & msg = inputs.continue_msg;57 58        data.generation_prompt = "<|start|>assistant<|channel|>analysis<|message|>" + msg.reasoning_content;59        if (inputs.continue_final_message == COMMON_CHAT_CONTINUATION_CONTENT) {60            data.generation_prompt += "<|end|><|start|>assistant<|channel|>final<|message|>" + msg.render_content();61        }62 63        data.prompt += data.generation_prompt;64    }65 66    auto has_tools           = inputs.tools.is_array() && !inputs.tools.empty();67    auto has_response_format = !inputs.json_schema.is_null() && inputs.json_schema.is_object();68    auto include_grammar     = has_response_format || (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE);69    auto extract_reasoning   = inputs.reasoning_format != COMMON_REASONING_FORMAT_NONE;70 71    auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {72        auto start           = p.rule("start", p.literal("<|start|>assistant"));73        auto end             = p.rule("end", p.literal("<|end|>"));74        auto content         = p.rule("message-content", p.until("<|end|>"));75        auto channel         = p.literal("<|channel|>") + (p.literal("commentary") | p.literal("analysis"));76        auto constrain_type  = p.chars("[A-Za-z0-9_-]", 1, -1);77 78        // Occasionally, gpt-oss-20b will prefix channels with this commentary79        auto stray_commentary = p.optional(p.literal("<|channel|>commentary") + p.optional(p.literal(" to=assistant")));80        auto start_analysis = stray_commentary + p.literal("<|channel|>analysis<|message|>");81 82        if (extract_reasoning) {83            p.rule("analysis", start_analysis + p.reasoning(content) + end);84        } else {85            p.rule("analysis", p.content(start_analysis + content + end));86        }87 88        auto analysis = p.ref("analysis");89        auto preamble = p.rule("preamble", p.literal("<|channel|>commentary<|message|>") + p.content(content) + end);90        auto final_msg = p.rule("final", stray_commentary + p.literal("<|channel|>final<|message|>") + p.content(content));91 92        // Consume any unsolicited tool calls, e.g. builtin functions93        auto unsolicited = p.rule("unsolicited", p.atomic(p.optional(channel) + p.literal(" to=") + content + end));94 95        auto any = p.rule("any", preamble | analysis);96 97        if (has_response_format) {98            auto constraint = p.optional(p.space() + p.optional(p.literal("<|constrain|>")) + constrain_type);99            auto response_format = p.rule("response-format",100                p.literal("<|channel|>final") + constraint + p.literal("<|message|>") +101                p.content(p.schema(p.json(), "response-format-schema", inputs.json_schema)));102 103            return p.zero_or_more(start + analysis) + start + response_format;104        }105 106        if (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE) {107            auto tool_choice = p.choice();108 109            foreach_function(inputs.tools, [&](const json & tool) {110                const auto & function = tool.at("function");111                std::string  name     = function.at("name");112                const auto   params   = common_chat_tool_parameters(function);113 114                auto func_name  = p.literal(" to=functions.") + p.tool_name(p.literal(name));115                auto constraint = p.optional(p.space() + p.optional(p.literal("<|constrain|>")) + constrain_type);116                auto args       = p.tool_args(p.schema(p.json(), "tool-" + name + "-schema", params));117 118                // recipient in role header119                //   <|start|>assistant to=functions.NAME<|channel|>(commentary|analysis)[constraint]<|message|>ARGS120                auto tool_in_role = p.tool(p.tool_open(func_name + channel + constraint + p.literal("<|message|>")) + args);121 122                // recipient in channel header123                //   <|channel|>(commentary|analysis) to=functions.NAME[constraint]<|message|>ARGS124                auto tool_in_channel = p.tool(p.tool_open(channel + func_name + constraint + p.literal("<|message|>")) + args);125 126                tool_choice |= p.rule("tool-" + name, tool_in_role | tool_in_channel);127            });128 129            auto tool_call  = p.trigger_rule("tool-call", tool_choice);130 131            if (inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED) {132                return p.zero_or_more(start + any) + start + tool_call;133            }134 135            return p.zero_or_more(start + any) + start + (tool_call | final_msg);136        }137 138        return p.zero_or_more(start + any) + start + (final_msg | unsolicited);139    });140 141    data.parser = parser.save();142 143    if (include_grammar) {144        data.grammar_lazy = !(has_response_format || (has_tools && inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED));145        data.grammar      = build_grammar([&](const common_grammar_builder & builder) {146            parser.build_grammar(builder, data.grammar_lazy);147        });148 149        data.grammar_triggers = {150            { COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN, "^\\s+to$" },151            { COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN, "^<\\|channel\\|>(?:commentary|analysis)\\s+to=functions$" },152            { COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN, "<\\|start\\|>assistant(\\s+to)" },153            { COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN, "<\\|start\\|>assistant(<\\|channel\\|>(?:commentary|analysis)\\s+to)" }154        };155    }156 157    return data;158}159