turbollm 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +54 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -705,6 +705,11 @@ function vllmServerCommand(python, model, port2, host2, tensorParallelSize = 1)
|
|
|
705
705
|
"vllm.entrypoints.openai.api_server",
|
|
706
706
|
"--model",
|
|
707
707
|
model,
|
|
708
|
+
// Serve under a fixed alias so requests can address the model by a stable name
|
|
709
|
+
// (TurboLLM's internal key is a display string with spaces). Mirrors mlx-lm's
|
|
710
|
+
// built-in `default_model` alias; see engineModelAlias() in compat.ts.
|
|
711
|
+
"--served-model-name",
|
|
712
|
+
"default_model",
|
|
708
713
|
"--host",
|
|
709
714
|
host2,
|
|
710
715
|
"--port",
|
|
@@ -781,7 +786,7 @@ var Manager = class {
|
|
|
781
786
|
}
|
|
782
787
|
}
|
|
783
788
|
const { cmd, args } = engineCommand(opts, port2, slotSavePath);
|
|
784
|
-
const child = spawn(cmd, args, { cwd: dirname2(cmd), windowsHide: true });
|
|
789
|
+
const child = spawn(cmd, args, { cwd: dirname2(cmd), windowsHide: true, env: pyEngineEnv(opts.engine.kind, this.store.dir()) });
|
|
785
790
|
child.stdout?.pipe(logStream, { end: false });
|
|
786
791
|
child.stderr?.pipe(logStream, { end: false });
|
|
787
792
|
this.state = "starting";
|
|
@@ -953,10 +958,22 @@ var Manager = class {
|
|
|
953
958
|
this.resolveExited?.();
|
|
954
959
|
}
|
|
955
960
|
async readiness(child, port2) {
|
|
956
|
-
const
|
|
961
|
+
const kind = this.opts?.engine.kind ?? "llama-server";
|
|
962
|
+
const deadline = Date.now() + readinessTimeoutMs(kind);
|
|
957
963
|
for (; ; ) {
|
|
958
964
|
await sleep(500);
|
|
959
965
|
if (this.child !== child || this.state !== "starting") return;
|
|
966
|
+
if (kind === "mlx" || kind === "vllm") {
|
|
967
|
+
const loadErr = detectPyLoadFailure(readTail(this.logPathStr, 200));
|
|
968
|
+
if (loadErr) {
|
|
969
|
+
if (this.child === child && this.state === "starting") {
|
|
970
|
+
this.state = "error";
|
|
971
|
+
this.errInfo = { code: "model_load_failed", message: loadErr, exitCode: -1, logTail: readTail(this.logPathStr, 20) };
|
|
972
|
+
child.kill("SIGKILL");
|
|
973
|
+
}
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
960
977
|
if (await probeReady(port2)) {
|
|
961
978
|
if (this.child === child && this.state === "starting") {
|
|
962
979
|
this.state = "running";
|
|
@@ -998,6 +1015,27 @@ function engineCommand(opts, port2, slotSavePath) {
|
|
|
998
1015
|
function readinessTimeoutMs(kind) {
|
|
999
1016
|
return kind === "vllm" ? 6e5 : 12e4;
|
|
1000
1017
|
}
|
|
1018
|
+
function pyEngineEnv(kind, dataDir) {
|
|
1019
|
+
if (kind !== "mlx" && kind !== "vllm") return void 0;
|
|
1020
|
+
const hfHome = join6(dataDir, "hf-cache");
|
|
1021
|
+
const hubCache = join6(hfHome, "hub");
|
|
1022
|
+
mkdirSync4(hubCache, { recursive: true });
|
|
1023
|
+
return {
|
|
1024
|
+
...process.env,
|
|
1025
|
+
HF_HUB_OFFLINE: "1",
|
|
1026
|
+
TRANSFORMERS_OFFLINE: "1",
|
|
1027
|
+
HF_HOME: hfHome,
|
|
1028
|
+
HF_HUB_CACHE: hubCache
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
function detectPyLoadFailure(lines) {
|
|
1032
|
+
const text = lines.join("\n");
|
|
1033
|
+
const isLoadCrash = /Exception in thread[^\n]*_generate/.test(text) || /in load_default\b/.test(text) || /in load_model\b/.test(text) || /load_weights/.test(text);
|
|
1034
|
+
if (!isLoadCrash) return null;
|
|
1035
|
+
const errLine = [...lines].reverse().find((l) => /^[A-Za-z_][\w.]*(Error|Exception):/.test(l.trim()));
|
|
1036
|
+
const detail = (errLine ? errLine.trim() : "the model failed to load").slice(0, 200);
|
|
1037
|
+
return `MLX could not load this model \u2014 ${detail} This usually means the installed mlx-lm version does not support this model's architecture or quantization.`;
|
|
1038
|
+
}
|
|
1001
1039
|
function buildArgs(opts, port2, slotSavePath) {
|
|
1002
1040
|
const args = ["-m", opts.modelPath, "--host", "127.0.0.1", "--port", String(port2)];
|
|
1003
1041
|
const flags = opts.engine.capabilities.flags;
|
|
@@ -1715,6 +1753,10 @@ function engineAcceptsFormat(engineKind, format) {
|
|
|
1715
1753
|
if (engineKind === "vllm") return format === "mlx";
|
|
1716
1754
|
return format === "gguf";
|
|
1717
1755
|
}
|
|
1756
|
+
var ENGINE_MODEL_ALIAS = "default_model";
|
|
1757
|
+
function engineModelAlias(engineKind) {
|
|
1758
|
+
return engineKind === "mlx" || engineKind === "vllm" ? ENGINE_MODEL_ALIAS : null;
|
|
1759
|
+
}
|
|
1718
1760
|
|
|
1719
1761
|
// src/models/scanner.ts
|
|
1720
1762
|
import { existsSync as existsSync9, lstatSync, readdirSync as readdirSync3, readFileSync as readFileSync3, rmSync as rmSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -5420,7 +5462,9 @@ async function runGeneration(d, stream, ctx) {
|
|
|
5420
5462
|
if (!(k in SAMPLING_KEYS) && k !== "stop") samplingOverride[k] = v;
|
|
5421
5463
|
}
|
|
5422
5464
|
const reqBody = {
|
|
5423
|
-
|
|
5465
|
+
// mlx-lm / vLLM serve under a fixed alias and 404 on TurboLLM's internal key;
|
|
5466
|
+
// llama.cpp ignores the field. engineModelAlias() returns the right value per kind.
|
|
5467
|
+
model: engineModelAlias(d.registry.active()?.kind ?? "") ?? ms.model.key,
|
|
5424
5468
|
messages: engineMessages,
|
|
5425
5469
|
stream: true,
|
|
5426
5470
|
stream_options: { include_usage: true },
|
|
@@ -5668,7 +5712,7 @@ async function autoTitle(d, convId, prevMessages, assistantReply, target) {
|
|
|
5668
5712
|
method: "POST",
|
|
5669
5713
|
headers: { "Content-Type": "application/json" },
|
|
5670
5714
|
body: JSON.stringify({
|
|
5671
|
-
model: ms.model?.key,
|
|
5715
|
+
model: engineModelAlias(d.registry.active()?.kind ?? "") ?? ms.model?.key,
|
|
5672
5716
|
messages: titleMessages,
|
|
5673
5717
|
stream: false,
|
|
5674
5718
|
temperature: 0.3,
|
|
@@ -6021,6 +6065,8 @@ function registerGateway(app2, d) {
|
|
|
6021
6065
|
const status = d.manager.status();
|
|
6022
6066
|
const modelName = status.state === "running" ? status.model?.name ?? req.model ?? "local" : req.model ?? "local";
|
|
6023
6067
|
const oaiBody = mapToOpenAI(req);
|
|
6068
|
+
const oaiAlias = engineModelAlias(d.registry.active()?.kind ?? "");
|
|
6069
|
+
if (oaiAlias) oaiBody.model = oaiAlias;
|
|
6024
6070
|
d.manager.generationStart();
|
|
6025
6071
|
let res;
|
|
6026
6072
|
try {
|
|
@@ -6144,6 +6190,10 @@ function registerGateway(app2, d) {
|
|
|
6144
6190
|
if (parsedBody && maxLimit > 0) {
|
|
6145
6191
|
parsedBody.max_tokens = clampMaxTokens(parsedBody.max_tokens, maxLimit);
|
|
6146
6192
|
}
|
|
6193
|
+
if (parsedBody) {
|
|
6194
|
+
const alias = engineModelAlias(d.registry.active()?.kind ?? "");
|
|
6195
|
+
if (alias) parsedBody.model = alias;
|
|
6196
|
+
}
|
|
6147
6197
|
headers.delete("content-length");
|
|
6148
6198
|
init.body = parsedBody ? JSON.stringify(parsedBody) : "";
|
|
6149
6199
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turbollm",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "TurboLLM — local LLM platform: run any inference engine auto-tuned to your GPU, with a web UI and OpenAI/Anthropic-compatible API. Point Claude Code at your own machine in one command.",
|
|
5
5
|
"license": "FSL-1.1-ALv2",
|
|
6
6
|
"author": "Mohit Soni",
|