Skip to content

Commit 92003d7

Browse files
committed
Merge branch 'master' into deepseek_3_1_thinking_mode
2 parents ec984da + ef47691 commit 92003d7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1981
-477
lines changed

common/arg.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2555,15 +2555,15 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
25552555
{"--lora"}, "FNAME",
25562556
"path to LoRA adapter (can be repeated to use multiple adapters)",
25572557
[](common_params & params, const std::string & value) {
2558-
params.lora_adapters.push_back({ std::string(value), 1.0, nullptr });
2558+
params.lora_adapters.push_back({ std::string(value), 1.0, "", "", nullptr });
25592559
}
25602560
// we define this arg on both COMMON and EXPORT_LORA, so when showing help message of export-lora, it will be categorized as "example-specific" arg
25612561
).set_examples({LLAMA_EXAMPLE_COMMON, LLAMA_EXAMPLE_EXPORT_LORA}));
25622562
add_opt(common_arg(
25632563
{"--lora-scaled"}, "FNAME", "SCALE",
25642564
"path to LoRA adapter with user defined scaling (can be repeated to use multiple adapters)",
25652565
[](common_params & params, const std::string & fname, const std::string & scale) {
2566-
params.lora_adapters.push_back({ fname, std::stof(scale), nullptr });
2566+
params.lora_adapters.push_back({ fname, std::stof(scale), "", "", nullptr });
25672567
}
25682568
// we define this arg on both COMMON and EXPORT_LORA, so when showing help message of export-lora, it will be categorized as "example-specific" arg
25692569
).set_examples({LLAMA_EXAMPLE_COMMON, LLAMA_EXAMPLE_EXPORT_LORA}));

common/chat.cpp

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ const char * common_chat_format_name(common_chat_format format) {
623623
case COMMON_CHAT_FORMAT_COMMAND_R7B: return "Command R7B";
624624
case COMMON_CHAT_FORMAT_GRANITE: return "Granite";
625625
case COMMON_CHAT_FORMAT_GPT_OSS: return "GPT-OSS";
626+
case COMMON_CHAT_FORMAT_SEED_OSS: return "Seed-OSS";
626627
default:
627628
throw std::runtime_error("Unknown chat format");
628629
}
@@ -2259,6 +2260,94 @@ static void common_chat_parse_granite(common_chat_msg_parser & builder) {
22592260
}
22602261
}
22612262

2263+
static void common_chat_parse_seed_oss(common_chat_msg_parser & builder) {
2264+
// Parse thinking tags first - this handles the main reasoning content
2265+
builder.try_parse_reasoning("<seed:think>", "</seed:think>");
2266+
2267+
if (!builder.syntax().parse_tool_calls) {
2268+
builder.add_content(builder.consume_rest());
2269+
return;
2270+
}
2271+
2272+
// Parse tool calls - Seed-OSS uses <seed:tool_call> format
2273+
static const common_regex tool_call_begin_regex("<seed:tool_call>");
2274+
static const common_regex tool_call_end_regex("</seed:tool_call>");
2275+
static const common_regex function_regex("<function=([^>]+)>");
2276+
static const common_regex param_regex("<parameter=([^>]+)>");
2277+
2278+
while (auto tool_res = builder.try_find_regex(tool_call_begin_regex)) {
2279+
builder.consume_spaces(); // Consume whitespace after <seed:tool_call>
2280+
2281+
// Look for function call inside tool call, ignore any content before it
2282+
if (auto func_res = builder.try_find_regex(function_regex, std::string::npos, false)) {
2283+
auto function_name = builder.str(func_res->groups[1]);
2284+
2285+
// Parse Seed-OSS parameters <parameter=name>value</parameter>
2286+
json args = json::object();
2287+
// Parse all parameters
2288+
while (auto param_res = builder.try_find_regex(param_regex, std::string::npos, false)) {
2289+
// again, ignore noise around parameters
2290+
auto param_name = builder.str(param_res->groups[1]);
2291+
builder.move_to(param_res->groups[0].end);
2292+
builder.consume_spaces(); // Consume whitespace after parameter
2293+
auto savedPos = builder.pos();
2294+
if (auto param_parse = builder.try_find_literal("</parameter>")) {
2295+
auto param = param_parse->prelude;
2296+
builder.move_to(savedPos);
2297+
try {
2298+
if (auto param_res = builder.try_consume_json()) {
2299+
args[param_name] = param_res->json;
2300+
} else {
2301+
args[param_name] = param;
2302+
}
2303+
} catch (json::exception &) {
2304+
args[param_name] = param;
2305+
}
2306+
} else {
2307+
throw common_chat_msg_partial_exception("Incomplete tool parameter");
2308+
}
2309+
}
2310+
// Look for closing function tag
2311+
auto end_func = builder.try_find_literal("</function>");
2312+
if (end_func) {
2313+
builder.move_to(end_func->groups[0].end);
2314+
builder.consume_spaces(); // Consume whitespace after </function>
2315+
2316+
// Add the tool call with parsed arguments, but only if we REALLY got the literal
2317+
auto eaten_fragment = builder.input().substr(end_func->groups[0].begin, end_func->groups[0].end);
2318+
auto funlen = std::string("</function>").length();
2319+
if (eaten_fragment.length() >= funlen && eaten_fragment.substr(0, funlen) == std::string("</function>")) {
2320+
if (!builder.add_tool_call(function_name, "", args.dump())) {
2321+
throw common_chat_msg_partial_exception("Incomplete tool call");
2322+
}
2323+
} else {
2324+
throw common_chat_msg_partial_exception("Incomplete tool call");
2325+
}
2326+
} else {
2327+
throw common_chat_msg_partial_exception("Incomplete tool call");
2328+
}
2329+
// Look for closing tool call tag
2330+
if (auto end_tool = builder.try_find_regex(tool_call_end_regex, std::string::npos, false)) {
2331+
builder.move_to(end_tool->groups[0].end);
2332+
builder.consume_spaces(); // Consume trailing whitespace after tool call
2333+
} else {
2334+
throw common_chat_msg_partial_exception("Incomplete tool call");
2335+
}
2336+
} else {
2337+
// No function found - don't consume content here, let it be handled at the end
2338+
break;
2339+
}
2340+
}
2341+
2342+
// Consume any remaining whitespace after all tool call processing
2343+
builder.consume_spaces();
2344+
auto remaining = builder.consume_rest();
2345+
// If there's any non-whitespace content remaining, add it as content
2346+
if (!string_strip(remaining).empty()) {
2347+
builder.add_content(remaining);
2348+
}
2349+
}
2350+
22622351
static common_chat_params common_chat_params_init_without_tools(const common_chat_template & tmpl, const struct templates_params & inputs) {
22632352
common_chat_params data;
22642353
data.prompt = apply(tmpl, inputs);
@@ -2275,8 +2364,62 @@ static common_chat_params common_chat_params_init_without_tools(const common_cha
22752364
return data;
22762365
}
22772366

2367+
static common_chat_params common_chat_params_init_seed_oss(
2368+
const common_chat_template & tmpl,
2369+
templates_params & params,
2370+
const common_chat_templates_inputs & inputs)
2371+
{
2372+
common_chat_params data;
2373+
data.prompt = apply(tmpl, params);
2374+
data.format = COMMON_CHAT_FORMAT_SEED_OSS;
2375+
if (string_ends_with(data.prompt, "<seed:think>")) {
2376+
if (!inputs.enable_thinking) {
2377+
data.prompt += "</seed:think>";
2378+
} else {
2379+
data.thinking_forced_open = true;
2380+
}
2381+
}
2382+
2383+
if (params.tools.is_array() && !params.tools.empty()) {
2384+
data.grammar_lazy = inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_REQUIRED;
2385+
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
2386+
std::vector<std::string> tool_rules;
2387+
foreach_function(params.tools, [&](const json & tool) {
2388+
const auto & function = tool.at("function");
2389+
std::string name = function.at("name");
2390+
auto parameters = function.at("parameters");
2391+
builder.resolve_refs(parameters);
2392+
2393+
// Create rule for Seed-OSS function call format
2394+
std::string param_rules;
2395+
if (parameters.contains("properties")) {
2396+
for (const auto & [key, value] : parameters.at("properties").items()) {
2397+
param_rules += "\"<parameter=" + key + ">\"" + builder.add_schema(name + "-arg-" + key, value) +
2398+
"\"</parameter>\"";
2399+
}
2400+
}
2401+
2402+
tool_rules.push_back(builder.add_rule(name + "-call",
2403+
"\"<seed:tool_call>\" space \"<function=" + name + ">\" space " +
2404+
param_rules +
2405+
" \"</function>\" space \"</seed:tool_call>\""));
2406+
});
2407+
2408+
data.grammar_triggers.push_back({ COMMON_GRAMMAR_TRIGGER_TYPE_WORD, "<seed:tool_call>" });
2409+
2410+
data.preserved_tokens = {
2411+
"<seed:think>", "</seed:think>", "<seed:tool_call>", "</seed:tool_call>",
2412+
"<function=", "</function>", "<parameter=", "</parameter>",
2413+
};
2414+
2415+
builder.add_rule("root", string_join(tool_rules, " | "));
2416+
});
2417+
}
2418+
return data;
2419+
}
2420+
22782421
static common_chat_params common_chat_templates_apply_jinja(
2279-
const struct common_chat_templates * tmpls,
2422+
const struct common_chat_templates * tmpls,
22802423
const struct common_chat_templates_inputs & inputs)
22812424
{
22822425
templates_params params;
@@ -2351,6 +2494,11 @@ static common_chat_params common_chat_templates_apply_jinja(
23512494
return common_chat_params_init_gpt_oss(tmpl, params);
23522495
}
23532496

2497+
// Seed-OSS
2498+
if (src.find("<seed:think>") != std::string::npos) {
2499+
return common_chat_params_init_seed_oss(tmpl, params, inputs);
2500+
}
2501+
23542502
// Use generic handler when mixing tools + JSON schema.
23552503
// TODO: support that mix in handlers below.
23562504
if ((params.tools.is_array() && params.json_schema.is_object())) {
@@ -2512,6 +2660,9 @@ static void common_chat_parse(common_chat_msg_parser & builder) {
25122660
case COMMON_CHAT_FORMAT_GPT_OSS:
25132661
common_chat_parse_gpt_oss(builder);
25142662
break;
2663+
case COMMON_CHAT_FORMAT_SEED_OSS:
2664+
common_chat_parse_seed_oss(builder);
2665+
break;
25152666
default:
25162667
throw std::runtime_error(std::string("Unsupported format: ") + common_chat_format_name(builder.syntax().format));
25172668
}

common/chat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ enum common_chat_format {
112112
COMMON_CHAT_FORMAT_COMMAND_R7B,
113113
COMMON_CHAT_FORMAT_GRANITE,
114114
COMMON_CHAT_FORMAT_GPT_OSS,
115+
COMMON_CHAT_FORMAT_SEED_OSS,
115116

116117
COMMON_CHAT_FORMAT_COUNT, // Not a format, just the # formats
117118
};

common/common.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,12 @@ struct common_init_result common_init_from_params(common_params & params) {
988988
return iparams;
989989
}
990990

991+
char buf[1024];
991992
la.ptr = lora.get();
993+
llama_adapter_meta_val_str(la.ptr, "adapter.lora.task_name", buf, sizeof(buf));
994+
la.task_name = buf;
995+
llama_adapter_meta_val_str(la.ptr, "adapter.lora.prompt_prefix", buf, sizeof(buf));
996+
la.prompt_prefix = buf;
992997
iparams.lora.emplace_back(std::move(lora)); // copy to list of loaded adapters
993998
}
994999

common/common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ struct common_adapter_lora_info {
3434
std::string path;
3535
float scale;
3636

37+
std::string task_name;
38+
std::string prompt_prefix;
39+
3740
struct llama_adapter_lora * ptr;
3841
};
3942

0 commit comments

Comments
 (0)