turbollm 0.7.0 → 0.7.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
CHANGED
|
@@ -2311,6 +2311,21 @@ function mlxEntryFor(dir) {
|
|
|
2311
2311
|
if (existsSync9(tc)) hasChatTemplate = readFileSync3(tc, "utf8").includes("chat_template");
|
|
2312
2312
|
} catch {
|
|
2313
2313
|
}
|
|
2314
|
+
let incomplete = false;
|
|
2315
|
+
try {
|
|
2316
|
+
const indexPath = join7(dir, "model.safetensors.index.json");
|
|
2317
|
+
if (existsSync9(indexPath)) {
|
|
2318
|
+
const index = JSON.parse(readFileSync3(indexPath, "utf8"));
|
|
2319
|
+
const shards = new Set(Object.values(index.weight_map ?? {}));
|
|
2320
|
+
for (const shard of shards) {
|
|
2321
|
+
if (!existsSync9(join7(dir, shard))) {
|
|
2322
|
+
incomplete = true;
|
|
2323
|
+
break;
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
} catch {
|
|
2328
|
+
}
|
|
2314
2329
|
const expertCount = cfg2.num_local_experts ?? cfg2.num_experts ?? 0;
|
|
2315
2330
|
const bits = cfg2.quantization?.bits;
|
|
2316
2331
|
const quant = bits ? `${bits}bit` : "fp16";
|
|
@@ -2336,7 +2351,7 @@ function mlxEntryFor(dir) {
|
|
|
2336
2351
|
mmprojPath: null,
|
|
2337
2352
|
hasChatTemplate,
|
|
2338
2353
|
embedding: isEmbeddingModel(arch2, basename(dir)),
|
|
2339
|
-
incomplete
|
|
2354
|
+
incomplete,
|
|
2340
2355
|
parseError,
|
|
2341
2356
|
loaded: false,
|
|
2342
2357
|
hasProfile: false,
|
|
@@ -5584,7 +5599,7 @@ function inferRepoFromPath(filePath, modelDirs) {
|
|
|
5584
5599
|
const root = norm(dir);
|
|
5585
5600
|
if (!fp.toLowerCase().startsWith(root.toLowerCase() + "/")) continue;
|
|
5586
5601
|
const parts = fp.slice(root.length + 1).split("/");
|
|
5587
|
-
if (parts.length >=
|
|
5602
|
+
if (parts.length >= 2 && seg.test(parts[0]) && seg.test(parts[1])) {
|
|
5588
5603
|
return `${parts[0]}/${parts[1]}`;
|
|
5589
5604
|
}
|
|
5590
5605
|
return null;
|
|
@@ -5864,6 +5879,11 @@ function buildConnectSnippets(cli, base2, apiKey, modelName) {
|
|
|
5864
5879
|
// src/chat/chat-routes.ts
|
|
5865
5880
|
import { streamSSE as streamSSE2 } from "hono/streaming";
|
|
5866
5881
|
var inflight = /* @__PURE__ */ new Map();
|
|
5882
|
+
var THINK_OPEN = "<think>";
|
|
5883
|
+
var THINK_CLOSE = "</think>";
|
|
5884
|
+
var CHAN_ANALYSIS_OPEN = "<|channel|>analysis<|message|>";
|
|
5885
|
+
var CHAN_CLOSE = "<|end|>";
|
|
5886
|
+
var CHAN_FINAL_SKIP = "<|start|>assistant<|channel|>final<|message|>";
|
|
5867
5887
|
var EXPERT_SYSTEM_PROMPT = `You are the TurboLLM in-app expert assistant \u2014 a knowledgeable, friendly guide built into TurboLLM, a local-first desktop app for running large language models on the user's own machine.
|
|
5868
5888
|
|
|
5869
5889
|
Your job is to help the user get the most out of TurboLLM:
|
|
@@ -6126,9 +6146,9 @@ async function runGeneration(d, stream, ctx) {
|
|
|
6126
6146
|
ac.signal.addEventListener("abort", cancelReader, { once: true });
|
|
6127
6147
|
}
|
|
6128
6148
|
let roundContent = "";
|
|
6129
|
-
let
|
|
6130
|
-
let
|
|
6131
|
-
let
|
|
6149
|
+
let parsePhase = "initial";
|
|
6150
|
+
let parseIsChannel = false;
|
|
6151
|
+
let parseBuf = "";
|
|
6132
6152
|
let finishReason = "";
|
|
6133
6153
|
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
6134
6154
|
roundLoop: while (true) {
|
|
@@ -6172,8 +6192,8 @@ async function runGeneration(d, stream, ctx) {
|
|
|
6172
6192
|
}
|
|
6173
6193
|
continue;
|
|
6174
6194
|
}
|
|
6175
|
-
|
|
6176
|
-
|
|
6195
|
+
const rc = delta.reasoning_content ?? delta.reasoning;
|
|
6196
|
+
if (rc) {
|
|
6177
6197
|
if (!thinkStart) thinkStart = Date.now();
|
|
6178
6198
|
thinkEnd = Date.now();
|
|
6179
6199
|
fullReasoning += rc;
|
|
@@ -6182,88 +6202,109 @@ async function runGeneration(d, stream, ctx) {
|
|
|
6182
6202
|
}
|
|
6183
6203
|
const raw_content = delta.content ?? "";
|
|
6184
6204
|
if (!raw_content) continue;
|
|
6185
|
-
|
|
6186
|
-
while (
|
|
6187
|
-
if (
|
|
6188
|
-
|
|
6189
|
-
const
|
|
6205
|
+
parseBuf += raw_content;
|
|
6206
|
+
while (parseBuf.length > 0) {
|
|
6207
|
+
if (parsePhase === "initial") {
|
|
6208
|
+
const thinkIdx = parseBuf.indexOf(THINK_OPEN);
|
|
6209
|
+
const chanIdx = parseBuf.indexOf(CHAN_ANALYSIS_OPEN);
|
|
6210
|
+
const hasThink = thinkIdx >= 0;
|
|
6211
|
+
const hasChan = chanIdx >= 0;
|
|
6212
|
+
const useThink = hasThink && (!hasChan || thinkIdx <= chanIdx);
|
|
6213
|
+
const openIdx = useThink ? thinkIdx : hasChan ? chanIdx : -1;
|
|
6214
|
+
const openTag = useThink ? THINK_OPEN : CHAN_ANALYSIS_OPEN;
|
|
6190
6215
|
if (openIdx === 0) {
|
|
6191
|
-
|
|
6216
|
+
parseIsChannel = !useThink;
|
|
6217
|
+
parsePhase = "reasoning";
|
|
6192
6218
|
if (!thinkStart) thinkStart = Date.now();
|
|
6193
|
-
|
|
6194
|
-
toProcess = "";
|
|
6219
|
+
parseBuf = parseBuf.slice(openTag.length);
|
|
6195
6220
|
} else if (openIdx > 0) {
|
|
6196
|
-
const before =
|
|
6221
|
+
const before = parseBuf.slice(0, openIdx);
|
|
6197
6222
|
fullContent += before;
|
|
6198
6223
|
roundContent += before;
|
|
6199
|
-
firstDelta = true;
|
|
6200
6224
|
if (!ttftMs) ttftMs = Date.now() - requestStart;
|
|
6201
6225
|
await stream.writeSSE({ event: "delta", data: JSON.stringify({ delta: before }) });
|
|
6202
|
-
|
|
6226
|
+
parseIsChannel = !useThink;
|
|
6227
|
+
parsePhase = "reasoning";
|
|
6203
6228
|
if (!thinkStart) thinkStart = Date.now();
|
|
6204
|
-
|
|
6205
|
-
toProcess = "";
|
|
6206
|
-
} else if (pendingThinkBuf.length > 20) {
|
|
6207
|
-
const flush = pendingThinkBuf;
|
|
6208
|
-
pendingThinkBuf = "";
|
|
6209
|
-
fullContent += flush;
|
|
6210
|
-
roundContent += flush;
|
|
6211
|
-
firstDelta = true;
|
|
6212
|
-
if (!ttftMs) ttftMs = Date.now() - requestStart;
|
|
6213
|
-
await stream.writeSSE({ event: "delta", data: JSON.stringify({ delta: flush }) });
|
|
6214
|
-
toProcess = "";
|
|
6229
|
+
parseBuf = parseBuf.slice(openIdx + openTag.length);
|
|
6215
6230
|
} else {
|
|
6216
|
-
|
|
6231
|
+
const safeLen = parseBuf.length - (CHAN_ANALYSIS_OPEN.length - 1);
|
|
6232
|
+
if (safeLen > 0) {
|
|
6233
|
+
const flush = parseBuf.slice(0, safeLen);
|
|
6234
|
+
parseBuf = parseBuf.slice(safeLen);
|
|
6235
|
+
fullContent += flush;
|
|
6236
|
+
roundContent += flush;
|
|
6237
|
+
if (!ttftMs) ttftMs = Date.now() - requestStart;
|
|
6238
|
+
d.manager.setLiveGen({ phase: "gen", pct: 0, outputTokens: ++liveOut });
|
|
6239
|
+
await stream.writeSSE({ event: "delta", data: JSON.stringify({ delta: flush }) });
|
|
6240
|
+
parsePhase = "content";
|
|
6241
|
+
} else {
|
|
6242
|
+
break;
|
|
6243
|
+
}
|
|
6217
6244
|
}
|
|
6218
|
-
} else if (
|
|
6219
|
-
|
|
6220
|
-
const closeIdx =
|
|
6245
|
+
} else if (parsePhase === "reasoning") {
|
|
6246
|
+
const closeTag = parseIsChannel ? CHAN_CLOSE : THINK_CLOSE;
|
|
6247
|
+
const closeIdx = parseBuf.indexOf(closeTag);
|
|
6221
6248
|
if (closeIdx >= 0) {
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
await stream.writeSSE({ event: "reasoning", data: JSON.stringify({ delta: thinkChunk }) });
|
|
6249
|
+
if (closeIdx > 0) {
|
|
6250
|
+
const chunk2 = parseBuf.slice(0, closeIdx);
|
|
6251
|
+
fullReasoning += chunk2;
|
|
6252
|
+
await stream.writeSSE({ event: "reasoning", data: JSON.stringify({ delta: chunk2 }) });
|
|
6227
6253
|
}
|
|
6228
|
-
inThink = false;
|
|
6229
6254
|
thinkEnd = Date.now();
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6255
|
+
const wasChannel = parseIsChannel;
|
|
6256
|
+
parseBuf = parseBuf.slice(closeIdx + closeTag.length);
|
|
6257
|
+
parsePhase = wasChannel ? "skipFinal" : "content";
|
|
6258
|
+
if (!wasChannel && parseBuf) {
|
|
6259
|
+
fullContent += parseBuf;
|
|
6260
|
+
roundContent += parseBuf;
|
|
6236
6261
|
if (!ttftMs) ttftMs = Date.now() - requestStart;
|
|
6237
|
-
await stream.writeSSE({ event: "delta", data: JSON.stringify({ delta:
|
|
6238
|
-
|
|
6262
|
+
await stream.writeSSE({ event: "delta", data: JSON.stringify({ delta: parseBuf }) });
|
|
6263
|
+
parseBuf = "";
|
|
6239
6264
|
}
|
|
6240
|
-
} else {
|
|
6265
|
+
} else if (parseBuf.length >= closeTag.length) {
|
|
6266
|
+
const safe = parseBuf.length - (closeTag.length - 1);
|
|
6267
|
+
const chunk2 = parseBuf.slice(0, safe);
|
|
6268
|
+
parseBuf = parseBuf.slice(safe);
|
|
6241
6269
|
thinkEnd = Date.now();
|
|
6242
|
-
fullReasoning +=
|
|
6243
|
-
await stream.writeSSE({ event: "reasoning", data: JSON.stringify({ delta:
|
|
6244
|
-
|
|
6245
|
-
|
|
6270
|
+
fullReasoning += chunk2;
|
|
6271
|
+
await stream.writeSSE({ event: "reasoning", data: JSON.stringify({ delta: chunk2 }) });
|
|
6272
|
+
} else {
|
|
6273
|
+
break;
|
|
6274
|
+
}
|
|
6275
|
+
} else if (parsePhase === "skipFinal") {
|
|
6276
|
+
if (parseBuf.startsWith(CHAN_FINAL_SKIP)) {
|
|
6277
|
+
parseBuf = parseBuf.slice(CHAN_FINAL_SKIP.length);
|
|
6278
|
+
parsePhase = "content";
|
|
6279
|
+
} else if (CHAN_FINAL_SKIP.startsWith(parseBuf) && parseBuf.length < CHAN_FINAL_SKIP.length) {
|
|
6280
|
+
break;
|
|
6281
|
+
} else {
|
|
6282
|
+
const skipIdx = parseBuf.indexOf(CHAN_FINAL_SKIP);
|
|
6283
|
+
parseBuf = skipIdx >= 0 ? parseBuf.slice(skipIdx + CHAN_FINAL_SKIP.length) : "";
|
|
6284
|
+
parsePhase = "content";
|
|
6246
6285
|
}
|
|
6247
6286
|
} else {
|
|
6248
6287
|
if (!ttftMs) ttftMs = Date.now() - requestStart;
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
roundContent += toProcess;
|
|
6288
|
+
fullContent += parseBuf;
|
|
6289
|
+
roundContent += parseBuf;
|
|
6252
6290
|
d.manager.setLiveGen({ phase: "gen", pct: 0, outputTokens: ++liveOut });
|
|
6253
|
-
await stream.writeSSE({ event: "delta", data: JSON.stringify({ delta:
|
|
6254
|
-
|
|
6291
|
+
await stream.writeSSE({ event: "delta", data: JSON.stringify({ delta: parseBuf }) });
|
|
6292
|
+
parseBuf = "";
|
|
6293
|
+
break;
|
|
6255
6294
|
}
|
|
6256
6295
|
}
|
|
6257
6296
|
}
|
|
6258
6297
|
}
|
|
6259
6298
|
ac.signal.removeEventListener("abort", cancelReader);
|
|
6260
|
-
if (
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6299
|
+
if (parseBuf) {
|
|
6300
|
+
if (parsePhase === "reasoning") {
|
|
6301
|
+
fullReasoning += parseBuf;
|
|
6302
|
+
await stream.writeSSE({ event: "reasoning", data: JSON.stringify({ delta: parseBuf }) });
|
|
6303
|
+
} else {
|
|
6304
|
+
fullContent += parseBuf;
|
|
6305
|
+
roundContent += parseBuf;
|
|
6306
|
+
await stream.writeSSE({ event: "delta", data: JSON.stringify({ delta: parseBuf }) });
|
|
6307
|
+
}
|
|
6267
6308
|
}
|
|
6268
6309
|
if ((finishReason === "tool_calls" || pendingToolCalls.size > 0) && d.tools && toolIter <= MAX_TOOL_ITER) {
|
|
6269
6310
|
const roundToolCalls = Array.from(pendingToolCalls.values());
|