|
37 | 37 | #include "backend.pb.h" |
38 | 38 | #include "backend.grpc.pb.h" |
39 | 39 | #include "common.h" |
| 40 | +#include "arg.h" |
40 | 41 | #include "chat-auto-parser.h" |
41 | 42 | #include <getopt.h> |
42 | 43 | #include <grpcpp/ext/proto_server_reflection_plugin.h> |
@@ -592,6 +593,10 @@ static void params_parse(server_context& /*ctx_server*/, const backend::ModelOpt |
592 | 593 | params.checkpoint_min_step = 256; |
593 | 594 | #endif |
594 | 595 |
|
| 596 | + // Raw upstream llama-server flags collected from any option entry that |
| 597 | + // starts with '-'. Applied once after the loop via common_params_parse. |
| 598 | + std::vector<std::string> extra_argv; |
| 599 | + |
595 | 600 | // decode options. Options are in form optname:optvale, or if booleans only optname. |
596 | 601 | for (int i = 0; i < request->options_size(); i++) { |
597 | 602 | std::string opt = request->options(i); |
@@ -1080,6 +1085,31 @@ static void params_parse(server_context& /*ctx_server*/, const backend::ModelOpt |
1080 | 1085 | } catch (...) {} |
1081 | 1086 | } |
1082 | 1087 |
|
| 1088 | + // --- main model MoE on CPU (upstream --cpu-moe / --n-cpu-moe) --- |
| 1089 | + } else if (!strcmp(optname, "cpu_moe")) { |
| 1090 | + // Bool-style flag: keep all MoE expert weights on CPU. |
| 1091 | + const bool enable = (optval == NULL) || |
| 1092 | + optval_str == "true" || optval_str == "1" || optval_str == "yes" || |
| 1093 | + optval_str == "on" || optval_str == "enabled"; |
| 1094 | + if (enable) { |
| 1095 | + params.tensor_buft_overrides.push_back(llm_ffn_exps_cpu_override()); |
| 1096 | + } |
| 1097 | + } else if (!strcmp(optname, "n_cpu_moe")) { |
| 1098 | + if (optval != NULL) { |
| 1099 | + try { |
| 1100 | + int n = std::stoi(optval_str); |
| 1101 | + if (n < 0) n = 0; |
| 1102 | + // Keep override-name storage alive for the lifetime of the |
| 1103 | + // params struct (mirrors upstream arg.cpp's function-local static). |
| 1104 | + static std::list<std::string> buft_overrides_main; |
| 1105 | + for (int i = 0; i < n; ++i) { |
| 1106 | + buft_overrides_main.push_back(llm_ffn_exps_block_regex(i)); |
| 1107 | + params.tensor_buft_overrides.push_back( |
| 1108 | + {buft_overrides_main.back().c_str(), ggml_backend_cpu_buffer_type()}); |
| 1109 | + } |
| 1110 | + } catch (...) {} |
| 1111 | + } |
| 1112 | + |
1083 | 1113 | // --- draft model tensor buffer overrides (upstream --spec-draft-override-tensor) --- |
1084 | 1114 | } else if (!strcmp(optname, "draft_override_tensor") || !strcmp(optname, "spec_draft_override_tensor")) { |
1085 | 1115 | // Format: <tensor regex>=<buffer type>,<tensor regex>=<buffer type>,... |
@@ -1111,6 +1141,30 @@ static void params_parse(server_context& /*ctx_server*/, const backend::ModelOpt |
1111 | 1141 | else { cur.push_back(c); } |
1112 | 1142 | } |
1113 | 1143 | if (!cur.empty()) flush(cur); |
| 1144 | + |
| 1145 | + // --- generic passthrough: any entry starting with '-' is a raw |
| 1146 | + // upstream llama-server flag, forwarded verbatim to the parser. --- |
| 1147 | + } else if (optname[0] == '-') { |
| 1148 | + std::string flag = optname; |
| 1149 | + // These flags make upstream's parser exit() (printing usage / |
| 1150 | + // completion), which would kill the backend process. Skip them. |
| 1151 | + if (flag == "-h" || flag == "--help" || flag == "--usage" || |
| 1152 | + flag == "--version" || flag == "--license" || |
| 1153 | + flag == "--list-devices" || flag == "-cl" || |
| 1154 | + flag == "--cache-list" || |
| 1155 | + flag.rfind("--completion", 0) == 0) { |
| 1156 | + fprintf(stderr, |
| 1157 | + "[llama-cpp] ignoring passthrough flag that would exit: %s\n", |
| 1158 | + flag.c_str()); |
| 1159 | + } else { |
| 1160 | + extra_argv.push_back(flag); |
| 1161 | + // Preserve the whole value after the first ':' so embedded |
| 1162 | + // colons (e.g. host:port) survive strtok's truncation of optval. |
| 1163 | + auto colon = opt.find(':'); |
| 1164 | + if (colon != std::string::npos) { |
| 1165 | + extra_argv.push_back(opt.substr(colon + 1)); |
| 1166 | + } |
| 1167 | + } |
1114 | 1168 | } |
1115 | 1169 | } |
1116 | 1170 |
|
@@ -1146,27 +1200,6 @@ static void params_parse(server_context& /*ctx_server*/, const backend::ModelOpt |
1146 | 1200 | } |
1147 | 1201 | } |
1148 | 1202 |
|
1149 | | - if (!params.kv_overrides.empty()) { |
1150 | | - params.kv_overrides.emplace_back(); |
1151 | | - params.kv_overrides.back().key[0] = 0; |
1152 | | - } |
1153 | | - |
1154 | | - // tensor_buft_overrides sentinel termination (mirrors upstream common/arg.cpp). |
1155 | | - // Real entries are pushed during option parsing; here we pad/terminate so the |
1156 | | - // model loader sees back().pattern == nullptr (GGML_ASSERT at common.cpp:1543) |
1157 | | - // and so llama_params_fit has the placeholder slots it requires. |
1158 | | - { |
1159 | | - const size_t ntbo = llama_max_tensor_buft_overrides(); |
1160 | | - while (params.tensor_buft_overrides.size() < ntbo) { |
1161 | | - params.tensor_buft_overrides.push_back({nullptr, nullptr}); |
1162 | | - } |
1163 | | - } |
1164 | | - // Terminate the draft tensor_buft_overrides list with a sentinel, mirroring |
1165 | | - // the main-model handling above. |
1166 | | - if (!params.speculative.draft.tensor_buft_overrides.empty()) { |
1167 | | - params.speculative.draft.tensor_buft_overrides.push_back({nullptr, nullptr}); |
1168 | | - } |
1169 | | - |
1170 | 1203 | // TODO: Add yarn |
1171 | 1204 |
|
1172 | 1205 | if (!request->tensorsplit().empty()) { |
@@ -1259,6 +1292,69 @@ static void params_parse(server_context& /*ctx_server*/, const backend::ModelOpt |
1259 | 1292 | params.sampling.grammar_triggers.push_back(std::move(trigger)); |
1260 | 1293 | } |
1261 | 1294 | } |
| 1295 | + |
| 1296 | + // Apply any raw upstream flags last so an explicit passthrough flag wins |
| 1297 | + // over the LocalAI-resolved field it maps to (e.g. --ctx-size beats |
| 1298 | + // context_size). This is the same parser llama-server itself uses. |
| 1299 | + if (!extra_argv.empty()) { |
| 1300 | + // common_params_parser_init resets a few fields for the SERVER example |
| 1301 | + // (n_parallel -> -1, use_color). Snapshot n_parallel so an unrelated |
| 1302 | + // passthrough flag can't silently clobber LocalAI's resolved value. |
| 1303 | + const int saved_n_parallel = params.n_parallel; |
| 1304 | + |
| 1305 | + std::vector<char *> argv; |
| 1306 | + std::string prog = "llama-server"; |
| 1307 | + argv.push_back(prog.data()); |
| 1308 | + for (auto & a : extra_argv) { |
| 1309 | + argv.push_back(a.data()); |
| 1310 | + } |
| 1311 | + |
| 1312 | + // ctx_arg.params is a reference, so this overlays the given flags onto |
| 1313 | + // `params` in place. Returns false on a recoverable parse error (and |
| 1314 | + // self-restores params); may exit() on a hard error, exactly as |
| 1315 | + // passing the same bad flag to llama-server would. |
| 1316 | + if (!common_params_parse((int)argv.size(), argv.data(), params, |
| 1317 | + LLAMA_EXAMPLE_SERVER)) { |
| 1318 | + fprintf(stderr, |
| 1319 | + "[llama-cpp] failed to parse passthrough options; ignoring them\n"); |
| 1320 | + } |
| 1321 | + |
| 1322 | + // Restore n_parallel unless a passthrough flag explicitly set it |
| 1323 | + // (parser_init's reset sentinel for SERVER is -1). |
| 1324 | + if (params.n_parallel == -1) { |
| 1325 | + params.n_parallel = saved_n_parallel; |
| 1326 | + } |
| 1327 | + } |
| 1328 | + |
| 1329 | + // Terminate/pad the override vectors only after BOTH the named-option loop |
| 1330 | + // and the generic passthrough (common_params_parse above) have pushed their |
| 1331 | + // real entries, so back() is the null sentinel the model loader asserts on. |
| 1332 | + // Running these before the passthrough let a passthrough flag (--cpu-moe, |
| 1333 | + // --override-tensor, --override-kv, ...) append a real entry after the |
| 1334 | + // sentinel: a GGML_ASSERT crash for tensor_buft_overrides, a silent drop for |
| 1335 | + // kv_overrides. Double-termination is harmless (the while is a no-op if the |
| 1336 | + // passthrough parse already padded; an extra trailing null is ignored). |
| 1337 | + |
| 1338 | + if (!params.kv_overrides.empty()) { |
| 1339 | + params.kv_overrides.emplace_back(); |
| 1340 | + params.kv_overrides.back().key[0] = 0; |
| 1341 | + } |
| 1342 | + |
| 1343 | + // tensor_buft_overrides sentinel termination (mirrors upstream common/arg.cpp). |
| 1344 | + // Real entries are pushed during option parsing; here we pad/terminate so the |
| 1345 | + // model loader sees back().pattern == nullptr (GGML_ASSERT at common.cpp:1543) |
| 1346 | + // and so llama_params_fit has the placeholder slots it requires. |
| 1347 | + { |
| 1348 | + const size_t ntbo = llama_max_tensor_buft_overrides(); |
| 1349 | + while (params.tensor_buft_overrides.size() < ntbo) { |
| 1350 | + params.tensor_buft_overrides.push_back({nullptr, nullptr}); |
| 1351 | + } |
| 1352 | + } |
| 1353 | + // Terminate the draft tensor_buft_overrides list with a sentinel, mirroring |
| 1354 | + // the main-model handling above. |
| 1355 | + if (!params.speculative.draft.tensor_buft_overrides.empty()) { |
| 1356 | + params.speculative.draft.tensor_buft_overrides.push_back({nullptr, nullptr}); |
| 1357 | + } |
1262 | 1358 | } |
1263 | 1359 |
|
1264 | 1360 |
|
|
0 commit comments