common : replace wrap_for_generation with a prefix convenience function and fix gpt-oss (#20912)
This commit is contained in:
parent
7cadbfce10
commit
312d870a89
6 changed files with 34 additions and 47 deletions
|
|
@ -112,8 +112,7 @@ common_peg_arena autoparser::build_parser(const generation_params & inputs) cons
|
||||||
} else {
|
} else {
|
||||||
parser = content.build_parser(ctx);
|
parser = content.build_parser(ctx);
|
||||||
}
|
}
|
||||||
parser = wrap_for_generation_prompt(p, parser, inputs, reasoning.start);
|
return p.prefix(inputs.generation_prompt, reasoning.start) + parser;
|
||||||
return parser;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -308,22 +308,6 @@ std::vector<segment> prune_whitespace_segments(const std::vector<segment> & segm
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
common_peg_parser wrap_for_generation_prompt(common_chat_peg_builder & p,
|
|
||||||
const common_peg_parser & prs,
|
|
||||||
const autoparser::generation_params & inputs,
|
|
||||||
const std::string & reasoning_start) {
|
|
||||||
auto parser = prs;
|
|
||||||
if (!inputs.generation_prompt.empty()) {
|
|
||||||
size_t end_pos = inputs.generation_prompt.size();
|
|
||||||
if (!reasoning_start.empty() && inputs.generation_prompt.find(reasoning_start) != std::string::npos) {
|
|
||||||
end_pos = inputs.generation_prompt.find(reasoning_start);
|
|
||||||
}
|
|
||||||
std::string cut_genprompt = inputs.generation_prompt.substr(0, end_pos);
|
|
||||||
parser = p.literal(cut_genprompt) + parser;
|
|
||||||
}
|
|
||||||
return parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace autoparser {
|
namespace autoparser {
|
||||||
|
|
||||||
std::string apply_template(const common_chat_template & tmpl, const template_params & params) {
|
std::string apply_template(const common_chat_template & tmpl, const template_params & params) {
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,6 @@ std::vector<segment> segmentize_markers(const std::string & text);
|
||||||
// (MARKER, "</function>"), (MARKER, "</tool_call>") ]
|
// (MARKER, "</function>"), (MARKER, "</tool_call>") ]
|
||||||
std::vector<segment> prune_whitespace_segments(const std::vector<segment> & segments);
|
std::vector<segment> prune_whitespace_segments(const std::vector<segment> & segments);
|
||||||
|
|
||||||
// Wrap parser with generation prompt parser
|
|
||||||
common_peg_parser wrap_for_generation_prompt(common_chat_peg_builder & p,
|
|
||||||
const common_peg_parser & prs,
|
|
||||||
const autoparser::generation_params & inputs,
|
|
||||||
const std::string & reasoning_start = {});
|
|
||||||
namespace autoparser {
|
namespace autoparser {
|
||||||
|
|
||||||
// Apply a template with the given parameters, returning the rendered string (empty on failure)
|
// Apply a template with the given parameters, returning the rendered string (empty on failure)
|
||||||
|
|
|
||||||
|
|
@ -802,6 +802,16 @@ common_peg_parser common_chat_peg_builder::build_json_tools_flat_keys(
|
||||||
return tool_choices;
|
return tool_choices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
common_peg_parser common_chat_peg_builder::prefix(const std::string & s, const std::string & delimiter) {
|
||||||
|
if (s.empty()) {
|
||||||
|
return eps();
|
||||||
|
}
|
||||||
|
if (delimiter.empty()) {
|
||||||
|
return literal(s);
|
||||||
|
}
|
||||||
|
return literal(s.substr(0, s.rfind(delimiter)));
|
||||||
|
}
|
||||||
|
|
||||||
common_peg_parser common_chat_peg_builder::standard_json_tools(
|
common_peg_parser common_chat_peg_builder::standard_json_tools(
|
||||||
const std::string & section_start,
|
const std::string & section_start,
|
||||||
const std::string & section_end,
|
const std::string & section_end,
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,10 @@ class common_chat_peg_builder : public common_peg_parser_builder {
|
||||||
common_peg_parser tool_arg_string_value(const common_peg_parser & p) { return tag(TOOL_ARG_STRING_VALUE, p); }
|
common_peg_parser tool_arg_string_value(const common_peg_parser & p) { return tag(TOOL_ARG_STRING_VALUE, p); }
|
||||||
common_peg_parser tool_arg_json_value(const common_peg_parser & p) { return atomic(tag(TOOL_ARG_VALUE, p)); }
|
common_peg_parser tool_arg_json_value(const common_peg_parser & p) { return atomic(tag(TOOL_ARG_VALUE, p)); }
|
||||||
|
|
||||||
|
|
||||||
|
// Return a parser that parses the prefix of a string, up to a given delimiter.
|
||||||
|
common_peg_parser prefix(const std::string & s, const std::string & delimiter = {});
|
||||||
|
|
||||||
// Legacy-compatible helper for building standard JSON tool calls
|
// Legacy-compatible helper for building standard JSON tool calls
|
||||||
// Used by tests and manual parsers
|
// Used by tests and manual parsers
|
||||||
// name_key/args_key: JSON key names for function name and arguments
|
// name_key/args_key: JSON key names for function name and arguments
|
||||||
|
|
|
||||||
|
|
@ -872,14 +872,14 @@ static common_chat_params common_chat_params_init_ministral_3(const common_chat_
|
||||||
};
|
};
|
||||||
|
|
||||||
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
||||||
|
auto generation_prompt = p.prefix(inputs.generation_prompt, "[THINK]");
|
||||||
auto reasoning =
|
auto reasoning =
|
||||||
extract_reasoning ? p.optional("[THINK]" + p.reasoning(p.until("[/THINK]")) + "[/THINK]") : p.eps();
|
extract_reasoning ? p.optional("[THINK]" + p.reasoning(p.until("[/THINK]")) + "[/THINK]") : p.eps();
|
||||||
|
|
||||||
// Response format parser
|
// Response format parser
|
||||||
if (inputs.json_schema.is_object() && !inputs.json_schema.empty()) {
|
if (inputs.json_schema.is_object() && !inputs.json_schema.empty()) {
|
||||||
// Ministral wants to emit json surrounded by code fences
|
// Ministral wants to emit json surrounded by code fences
|
||||||
return wrap_for_generation_prompt(p, reasoning << "```json" << p.content(p.schema(p.json(), "response-format", inputs.json_schema)) << "```",
|
return generation_prompt + (reasoning << "```json" << p.content(p.schema(p.json(), "response-format", inputs.json_schema)) << "```");
|
||||||
inputs, "[THINK]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tool call parser
|
// Tool call parser
|
||||||
|
|
@ -899,13 +899,12 @@ static common_chat_params common_chat_params_init_ministral_3(const common_chat_
|
||||||
auto max_calls = inputs.parallel_tool_calls ? -1 : 1;
|
auto max_calls = inputs.parallel_tool_calls ? -1 : 1;
|
||||||
auto tool_calls = p.trigger_rule("tool-call", p.repeat("[TOOL_CALLS]" + tool_choice, min_calls, max_calls));
|
auto tool_calls = p.trigger_rule("tool-call", p.repeat("[TOOL_CALLS]" + tool_choice, min_calls, max_calls));
|
||||||
|
|
||||||
return wrap_for_generation_prompt(p, reasoning << p.content(p.until("[TOOL_CALLS]")) << tool_calls,
|
return generation_prompt + (reasoning << p.content(p.until("[TOOL_CALLS]")) << tool_calls);
|
||||||
inputs, "[THINK]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content only parser
|
// Content only parser
|
||||||
include_grammar = false;
|
include_grammar = false;
|
||||||
return wrap_for_generation_prompt(p, reasoning << p.content(p.rest()), inputs, "[THINK]");
|
return generation_prompt + (reasoning << p.content(p.rest()));
|
||||||
});
|
});
|
||||||
|
|
||||||
data.parser = parser.save();
|
data.parser = parser.save();
|
||||||
|
|
@ -991,8 +990,7 @@ static common_chat_params common_chat_params_init_gpt_oss(const common_chat_temp
|
||||||
p.literal("<|channel|>final") + constraint + p.literal("<|message|>") +
|
p.literal("<|channel|>final") + constraint + p.literal("<|message|>") +
|
||||||
p.content(p.schema(p.json(), "response-format-schema", inputs.json_schema)));
|
p.content(p.schema(p.json(), "response-format-schema", inputs.json_schema)));
|
||||||
|
|
||||||
return wrap_for_generation_prompt(p, response_format | (analysis + p.zero_or_more(start + analysis) + start + response_format),
|
return p.zero_or_more(start + analysis) + start + response_format;
|
||||||
inputs, "<|channel|>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE) {
|
if (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE) {
|
||||||
|
|
@ -1021,15 +1019,13 @@ static common_chat_params common_chat_params_init_gpt_oss(const common_chat_temp
|
||||||
auto tool_call = p.trigger_rule("tool-call", tool_choice);
|
auto tool_call = p.trigger_rule("tool-call", tool_choice);
|
||||||
|
|
||||||
if (inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED) {
|
if (inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED) {
|
||||||
return tool_call | ( any + p.zero_or_more(start + any) + start + tool_call);
|
return p.zero_or_more(start + any) + start + tool_call;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrap_for_generation_prompt(p, tool_call | final_msg | (any + p.zero_or_more(start + any) + start + (tool_call | final_msg)),
|
return p.zero_or_more(start + any) + start + (tool_call | final_msg);
|
||||||
inputs, "<|channel|>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrap_for_generation_prompt(p, final_msg | (any + p.zero_or_more(start + any) + start + final_msg),
|
return p.zero_or_more(start + any) + start + final_msg;
|
||||||
inputs, "<|channel|>");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
data.parser = parser.save();
|
data.parser = parser.save();
|
||||||
|
|
@ -1080,11 +1076,12 @@ static common_chat_params common_chat_params_init_functionary_v3_2(const common_
|
||||||
// When no tools, content goes until end
|
// When no tools, content goes until end
|
||||||
auto content_until_tool = p.literal("all\n") + p.content(p.until(">>>"));
|
auto content_until_tool = p.literal("all\n") + p.content(p.until(">>>"));
|
||||||
auto content_until_end = p.literal("all\n") + p.content(p.rest());
|
auto content_until_end = p.literal("all\n") + p.content(p.rest());
|
||||||
|
auto generation_prompt = p.literal(inputs.generation_prompt);
|
||||||
|
|
||||||
// If no tools or tool_choice is NONE, just parse content
|
// If no tools or tool_choice is NONE, just parse content
|
||||||
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
|
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
|
||||||
// When no tools, just match the prefix and capture everything after
|
// When no tools, just match the prefix and capture everything after
|
||||||
return wrap_for_generation_prompt(p, content_until_end + p.end(), inputs);
|
return generation_prompt + content_until_end + p.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build tool call parsers for each available function
|
// Build tool call parsers for each available function
|
||||||
|
|
@ -1120,7 +1117,7 @@ static common_chat_params common_chat_params_init_functionary_v3_2(const common_
|
||||||
auto content_and_tool = content_until_tool + tool_choice;
|
auto content_and_tool = content_until_tool + tool_choice;
|
||||||
ret = p.choice({ content_and_tool, content_only, tool_choice }) + p.end();
|
ret = p.choice({ content_and_tool, content_only, tool_choice }) + p.end();
|
||||||
}
|
}
|
||||||
return wrap_for_generation_prompt(p, ret, inputs);
|
return generation_prompt + ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
data.parser = parser.save();
|
data.parser = parser.save();
|
||||||
|
|
@ -1201,12 +1198,12 @@ static common_chat_params common_chat_params_init_kimi_k2(const common_chat_temp
|
||||||
auto reasoning = extract_reasoning ? p.optional(THINK_START + p.reasoning(
|
auto reasoning = extract_reasoning ? p.optional(THINK_START + p.reasoning(
|
||||||
p.until_one_of({ THINK_END, "<|tool_calls_section_begin|>", "<|tool_call_begin|>" })) +
|
p.until_one_of({ THINK_END, "<|tool_calls_section_begin|>", "<|tool_call_begin|>" })) +
|
||||||
p.optional(p.literal(THINK_END))) : p.eps();
|
p.optional(p.literal(THINK_END))) : p.eps();
|
||||||
|
auto generation_prompt = p.prefix(inputs.generation_prompt, THINK_START);
|
||||||
|
|
||||||
|
|
||||||
// Content only parser (no tools)
|
// Content only parser (no tools)
|
||||||
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
|
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
|
||||||
return wrap_for_generation_prompt(p, reasoning + p.content(p.rest()) + end,
|
return generation_prompt + reasoning + p.content(p.rest()) + end;
|
||||||
inputs, THINK_START);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build tool call parsers for each available function
|
// Build tool call parsers for each available function
|
||||||
|
|
@ -1242,8 +1239,7 @@ static common_chat_params common_chat_params_init_kimi_k2(const common_chat_temp
|
||||||
|
|
||||||
auto content_before_tools = p.content(p.until_one_of({ SECTION_BEGIN, CALL_BEGIN }));
|
auto content_before_tools = p.content(p.until_one_of({ SECTION_BEGIN, CALL_BEGIN }));
|
||||||
|
|
||||||
return wrap_for_generation_prompt(p, reasoning + content_before_tools + tool_calls + end,
|
return generation_prompt + reasoning + content_before_tools + tool_calls + end;
|
||||||
inputs, THINK_START);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
data.parser = parser.save();
|
data.parser = parser.save();
|
||||||
|
|
@ -1301,6 +1297,7 @@ static common_chat_params common_chat_params_init_lfm2(const common_chat_templat
|
||||||
data.thinking_end_tag = THINK_END;
|
data.thinking_end_tag = THINK_END;
|
||||||
|
|
||||||
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
||||||
|
auto generation_prompt = p.prefix(inputs.generation_prompt, THINK_START);
|
||||||
auto end = p.end();
|
auto end = p.end();
|
||||||
|
|
||||||
auto reasoning = p.eps();
|
auto reasoning = p.eps();
|
||||||
|
|
@ -1309,8 +1306,7 @@ static common_chat_params common_chat_params_init_lfm2(const common_chat_templat
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
|
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
|
||||||
return wrap_for_generation_prompt(p, reasoning + p.content(p.rest()) + end, inputs,
|
return generation_prompt + reasoning + p.content(p.rest()) + end;
|
||||||
THINK_START);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tool_calls = p.rule("tool-calls",
|
auto tool_calls = p.rule("tool-calls",
|
||||||
|
|
@ -1322,8 +1318,7 @@ static common_chat_params common_chat_params_init_lfm2(const common_chat_templat
|
||||||
|
|
||||||
auto content = p.content(p.until(TOOL_CALL_START));
|
auto content = p.content(p.until(TOOL_CALL_START));
|
||||||
|
|
||||||
return wrap_for_generation_prompt(p, reasoning + content + tool_calls + end, inputs,
|
return generation_prompt + reasoning + content + tool_calls + end;
|
||||||
THINK_START);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
data.parser = parser.save();
|
data.parser = parser.save();
|
||||||
|
|
@ -1396,7 +1391,7 @@ static common_chat_params common_chat_params_init_gigachat_v3(
|
||||||
ret = p.content(p.rest());
|
ret = p.content(p.rest());
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrap_for_generation_prompt(p, ret, inputs);
|
return p.literal(inputs.generation_prompt) + ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
data.parser = parser.save();
|
data.parser = parser.save();
|
||||||
|
|
@ -1621,7 +1616,7 @@ static common_chat_params common_chat_templates_apply_jinja(const struct common_
|
||||||
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
||||||
data.generation_prompt = params.generation_prompt;
|
data.generation_prompt = params.generation_prompt;
|
||||||
auto parser = build_chat_peg_parser([¶ms](common_chat_peg_builder &p) {
|
auto parser = build_chat_peg_parser([¶ms](common_chat_peg_builder &p) {
|
||||||
return wrap_for_generation_prompt(p, p.content(p.rest()), params);
|
return p.prefix(params.generation_prompt) + p.content(p.rest());
|
||||||
});
|
});
|
||||||
data.parser = parser.save();
|
data.parser = parser.save();
|
||||||
return data;
|
return data;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue