turbollm 1.10.0 → 1.10.2
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 +319 -62
- package/dist/webdist/assets/{AgentEditPage-qGzBfP6d.js → AgentEditPage-CFxWKFKa.js} +1 -1
- package/dist/webdist/assets/{ChatScreen-D0G5dkfp.js → ChatScreen-CTooMkHT.js} +1 -1
- package/dist/webdist/assets/{CodeComposer-Da87vS4k.js → CodeComposer-COwhPOhR.js} +1 -1
- package/dist/webdist/assets/{CodeHomeScreen-DU5GGdGi.js → CodeHomeScreen-Cj1xAoUo.js} +1 -1
- package/dist/webdist/assets/{CodeSessionScreen-Cgj25Rkp.js → CodeSessionScreen-V9-7hQju.js} +1 -1
- package/dist/webdist/assets/{CustomizeScreen-Dm6mG0zr.js → CustomizeScreen-CJvRx-tG.js} +1 -1
- package/dist/webdist/assets/{DeveloperScreen-BVe8HEzP.js → DeveloperScreen-CoPotQpU.js} +1 -1
- package/dist/webdist/assets/{EnginesScreen-ChX3oICU.js → EnginesScreen-BUv0pJQW.js} +2 -2
- package/dist/webdist/assets/ModelDetailDialog-lYcC9WmN.js +1 -0
- package/dist/webdist/assets/{ModelLoadMenu-Dhnm8dEz.js → ModelLoadMenu-D7QPq4Eq.js} +1 -1
- package/dist/webdist/assets/{ModelsScreen-CqFCDDL6.js → ModelsScreen-CzY28vxf.js} +1 -1
- package/dist/webdist/assets/{RoutineEditPage-BL932a0r.js → RoutineEditPage-CCNKZWJO.js} +1 -1
- package/dist/webdist/assets/{RoutinesPanel-De8YnBNe.js → RoutinesPanel-DIAdnFgF.js} +1 -1
- package/dist/webdist/assets/{SettingsScreen-UpQEQLrO.js → SettingsScreen-DSO9et1h.js} +1 -1
- package/dist/webdist/assets/{SidebarResizeHandle-CwKbNZ1T.js → SidebarResizeHandle-CTKybDtZ.js} +1 -1
- package/dist/webdist/assets/{SkillEditPage-BvSU02Jt.js → SkillEditPage-sYIbxMua.js} +1 -1
- package/dist/webdist/assets/{TokensScreen-DWYd_FJP.js → TokensScreen-U53Af6Qm.js} +1 -1
- package/dist/webdist/assets/{ToolApprovalBar-C2yMawx1.js → ToolApprovalBar-DouGFUhG.js} +3 -3
- package/dist/webdist/assets/WorkspaceScreen-XVHKj6V7.js +1 -0
- package/dist/webdist/assets/{agent-api-BDGYxu1V.js → agent-api-CbZW6U0W.js} +1 -1
- package/dist/webdist/assets/{alert-dialog-Cvh1bWmi.js → alert-dialog-Bmx12MjB.js} +1 -1
- package/dist/webdist/assets/{arc-DJUqJnyS.js → arc-Dd3jjp1g.js} +1 -1
- package/dist/webdist/assets/{architectureDiagram-3BPJPVTR-CSoVRmcb.js → architectureDiagram-3BPJPVTR-BR5uEm28.js} +1 -1
- package/dist/webdist/assets/{arrow-left-DnuoPO3d.js → arrow-left-j1bXiZDl.js} +1 -1
- package/dist/webdist/assets/{badge-DBnDZ8IB.js → badge-DJwa0mpu.js} +1 -1
- package/dist/webdist/assets/{blockDiagram-GPEHLZMM-B2tUVQkN.js → blockDiagram-GPEHLZMM-s-U3l46D.js} +1 -1
- package/dist/webdist/assets/{bot-BqK-Cvvj.js → bot-CwWPnHhZ.js} +1 -1
- package/dist/webdist/assets/{c4Diagram-AAUBKEIU-CK_SZ0No.js → c4Diagram-AAUBKEIU-nAf8RB3W.js} +1 -1
- package/dist/webdist/assets/channel-4e9Zw4DS.js +1 -0
- package/dist/webdist/assets/{chat-api-BWC8yB8f.js → chat-api-Vp38MmPT.js} +1 -1
- package/dist/webdist/assets/{chat-queries-Coy7H-R4.js → chat-queries-CYVi1fKX.js} +1 -1
- package/dist/webdist/assets/{chevron-left-C-tiOyyN.js → chevron-left-C7VOgCa-.js} +1 -1
- package/dist/webdist/assets/{chevron-right-DTJBClgw.js → chevron-right-Cvc6jjhp.js} +1 -1
- package/dist/webdist/assets/{chunk-2J33WTMH-bEj-T-z0.js → chunk-2J33WTMH-BLfjL7Zw.js} +1 -1
- package/dist/webdist/assets/{chunk-4BX2VUAB-Cif7ru1F.js → chunk-4BX2VUAB-Dlin1rha.js} +1 -1
- package/dist/webdist/assets/{chunk-55IACEB6-CDzzG-CE.js → chunk-55IACEB6-DCLFQcNB.js} +1 -1
- package/dist/webdist/assets/{chunk-727SXJPM-D0TNxHzv.js → chunk-727SXJPM-Dx3Y7Esd.js} +1 -1
- package/dist/webdist/assets/{chunk-AQP2D5EJ-Cyj0A4j9.js → chunk-AQP2D5EJ-BE9fOlAZ.js} +1 -1
- package/dist/webdist/assets/{chunk-FMBD7UC4-D6xVpEis.js → chunk-FMBD7UC4-aQyGnVKT.js} +1 -1
- package/dist/webdist/assets/{chunk-ND2GUHAM-DfrJt1zq.js → chunk-ND2GUHAM-DChmLkpD.js} +1 -1
- package/dist/webdist/assets/{chunk-QZHKN3VN-wRcKgWAJ.js → chunk-QZHKN3VN-Cg8HsKLL.js} +1 -1
- package/dist/webdist/assets/{circle-check-DyRGib7M.js → circle-check-ByAt4HHi.js} +1 -1
- package/dist/webdist/assets/{circle-x-B5hYGJpb.js → circle-x-BrZO5ZPK.js} +1 -1
- package/dist/webdist/assets/classDiagram-4FO5ZUOK-BpPs---J.js +1 -0
- package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-BpPs---J.js +1 -0
- package/dist/webdist/assets/{common-Zsod6hYN.js → common-DfiDFdG6.js} +1 -1
- package/dist/webdist/assets/{cose-bilkent-S5V4N54A-CVCCOgV-.js → cose-bilkent-S5V4N54A-BaX2n7he.js} +1 -1
- package/dist/webdist/assets/{dagre-BM42HDAG-BAkC4UTn.js → dagre-BM42HDAG-L-zSD6Id.js} +1 -1
- package/dist/webdist/assets/{diagram-2AECGRRQ-DL9rbgkc.js → diagram-2AECGRRQ-DubS0XE-.js} +1 -1
- package/dist/webdist/assets/{diagram-5GNKFQAL-DGC1tJsz.js → diagram-5GNKFQAL-DcUkYGcO.js} +1 -1
- package/dist/webdist/assets/{diagram-KO2AKTUF-COJcOzCk.js → diagram-KO2AKTUF-Bs5XJw3q.js} +1 -1
- package/dist/webdist/assets/{diagram-LMA3HP47-D5LDvdeL.js → diagram-LMA3HP47-CynTZtzf.js} +1 -1
- package/dist/webdist/assets/{diagram-OG6HWLK6-rZkdD7HA.js → diagram-OG6HWLK6-Ces3__8l.js} +1 -1
- package/dist/webdist/assets/{dropdown-menu-DD_r8t6u.js → dropdown-menu-CikrwibY.js} +1 -1
- package/dist/webdist/assets/{erDiagram-TEJ5UH35-DcFmBQnY.js → erDiagram-TEJ5UH35-B4pp5Bmb.js} +1 -1
- package/dist/webdist/assets/{external-link-BYGp_q8v.js → external-link-B6bNonST.js} +1 -1
- package/dist/webdist/assets/{file-text-Ednnzze6.js → file-text-tVVaHTZE.js} +1 -1
- package/dist/webdist/assets/{flowDiagram-I6XJVG4X-bjdPqmij.js → flowDiagram-I6XJVG4X-DYw6zosJ.js} +1 -1
- package/dist/webdist/assets/{folder-plus-VQ2YW037.js → folder-plus-CahK1jG-.js} +1 -1
- package/dist/webdist/assets/{ganttDiagram-6RSMTGT7-cioHCnwQ.js → ganttDiagram-6RSMTGT7-BXp-7Nw6.js} +1 -1
- package/dist/webdist/assets/{git-branch-BQAi48as.js → git-branch-D-ZVoool.js} +1 -1
- package/dist/webdist/assets/{gitGraphDiagram-PVQCEYII-CLHLJora.js → gitGraphDiagram-PVQCEYII-DzcmQ_Rc.js} +1 -1
- package/dist/webdist/assets/{index-Dh7kXOE1.js → index-x5TIbXu2.js} +2 -2
- package/dist/webdist/assets/{infoDiagram-5YYISTIA-DMq4ds-X.js → infoDiagram-5YYISTIA-BYGyZ8S1.js} +1 -1
- package/dist/webdist/assets/{ishikawaDiagram-YF4QCWOH-DlqgfsZZ.js → ishikawaDiagram-YF4QCWOH-CJBmxkmw.js} +1 -1
- package/dist/webdist/assets/{journeyDiagram-JHISSGLW-f4hD-rvS.js → journeyDiagram-JHISSGLW-CXi8N9Vd.js} +1 -1
- package/dist/webdist/assets/{kanban-definition-UN3LZRKU-CIlgPK2Q.js → kanban-definition-UN3LZRKU-B0AzyNbO.js} +1 -1
- package/dist/webdist/assets/{linear-Dwee7zpr.js → linear-BWBxaDER.js} +1 -1
- package/dist/webdist/assets/{lock-Bvay5gWG.js → lock-Cc8h_hdf.js} +1 -1
- package/dist/webdist/assets/{mermaid.core-J5pMsJoH.js → mermaid.core-ejH4ogS8.js} +4 -4
- package/dist/webdist/assets/{mindmap-definition-RKZ34NQL-dojADpM-.js → mindmap-definition-RKZ34NQL-D43jvdzR.js} +1 -1
- package/dist/webdist/assets/{pencil-BMbt1aP-.js → pencil-CBakPF4F.js} +1 -1
- package/dist/webdist/assets/{personas-In3Y_0cx.js → personas-B0p0BX69.js} +1 -1
- package/dist/webdist/assets/{pieDiagram-4H26LBE5-BkzBQcFB.js → pieDiagram-4H26LBE5-LEL1ZCx7.js} +1 -1
- package/dist/webdist/assets/{plus-iQMJ0v11.js → plus-B1dZKSGV.js} +1 -1
- package/dist/webdist/assets/{quadrantDiagram-W4KKPZXB-DkRwNabn.js → quadrantDiagram-W4KKPZXB-BM9YYsxt.js} +1 -1
- package/dist/webdist/assets/{refresh-cw-CQM4Lk5m.js → refresh-cw-CyuRU30b.js} +1 -1
- package/dist/webdist/assets/{requirementDiagram-4Y6WPE33-lmlcs3qi.js → requirementDiagram-4Y6WPE33-BzpmVcdD.js} +1 -1
- package/dist/webdist/assets/{rotate-ccw-DdsgYBnk.js → rotate-ccw-B4FPn_uu.js} +1 -1
- package/dist/webdist/assets/{sankeyDiagram-5OEKKPKP-lPssl2qV.js → sankeyDiagram-5OEKKPKP-CJjdQhEE.js} +1 -1
- package/dist/webdist/assets/{sequenceDiagram-3UESZ5HK-Cf7xZenl.js → sequenceDiagram-3UESZ5HK-DAtWr5sY.js} +1 -1
- package/dist/webdist/assets/{skeleton-DavzJK3x.js → skeleton-D4gswV0g.js} +1 -1
- package/dist/webdist/assets/{sliders-horizontal-BZJPHQPY.js → sliders-horizontal-zbQIfrTb.js} +1 -1
- package/dist/webdist/assets/{sparkles-Bz-IcHBC.js → sparkles-C9BYrK2a.js} +1 -1
- package/dist/webdist/assets/{star-Bu8NPW3a.js → star-C-V7uYuS.js} +1 -1
- package/dist/webdist/assets/{stateDiagram-AJRCARHV-CDvT3iZf.js → stateDiagram-AJRCARHV-BzqjpVkC.js} +1 -1
- package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-Jr4V5989.js +1 -0
- package/dist/webdist/assets/{switch-DdYgDvMh.js → switch-DJGUE0gu.js} +1 -1
- package/dist/webdist/assets/{terminal-c3Jeo9pG.js → terminal-DYWE0kIS.js} +1 -1
- package/dist/webdist/assets/{timeline-definition-PNZ67QCA-C_oMQ4Rj.js → timeline-definition-PNZ67QCA-DUWSWDIu.js} +1 -1
- package/dist/webdist/assets/{trash-2-B3sskeB1.js → trash-2-Bh6pLoU3.js} +1 -1
- package/dist/webdist/assets/{useIsDesktop-CkjcxpzL.js → useIsDesktop-BBFHOzWe.js} +1 -1
- package/dist/webdist/assets/{vennDiagram-CIIHVFJN-h6SJOwAI.js → vennDiagram-CIIHVFJN-O3R7gjwP.js} +1 -1
- package/dist/webdist/assets/{vram-D8-r3zny.js → vram-DuXXfpwQ.js} +1 -1
- package/dist/webdist/assets/{wardley-L42UT6IY-DhiFwT8Y.js → wardley-L42UT6IY-BoHQfIuF.js} +1 -1
- package/dist/webdist/assets/{wardleyDiagram-YWT4CUSO-Cj5qu2fK.js → wardleyDiagram-YWT4CUSO-CsNf6Ma0.js} +1 -1
- package/dist/webdist/assets/{wrench-_XyytN3N.js → wrench-DfrljGuQ.js} +1 -1
- package/dist/webdist/assets/{xychartDiagram-2RQKCTM6-CooqJBuV.js → xychartDiagram-2RQKCTM6-CA58m8lE.js} +1 -1
- package/dist/webdist/index.html +1 -1
- package/package.json +1 -1
- package/dist/webdist/assets/ModelDetailDialog-D1PpiVaP.js +0 -1
- package/dist/webdist/assets/WorkspaceScreen-Bh36JTwH.js +0 -1
- package/dist/webdist/assets/channel-vN9Rfh_6.js +0 -1
- package/dist/webdist/assets/classDiagram-4FO5ZUOK-O-iQ0ssF.js +0 -1
- package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-O-iQ0ssF.js +0 -1
- package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-CMrT-fsV.js +0 -1
package/dist/cli.js
CHANGED
|
@@ -34,9 +34,9 @@ function hideChildConsoleWindows() {
|
|
|
34
34
|
|
|
35
35
|
// src/cli.ts
|
|
36
36
|
import { spawn as spawn10 } from "child_process";
|
|
37
|
-
import { openSync as openSync3, readFileSync as
|
|
37
|
+
import { openSync as openSync3, readFileSync as readFileSync20 } from "fs";
|
|
38
38
|
import { serve } from "@hono/node-server";
|
|
39
|
-
import { dirname as dirname12, join as
|
|
39
|
+
import { dirname as dirname12, join as join37 } from "path";
|
|
40
40
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
41
41
|
|
|
42
42
|
// src/config/config.ts
|
|
@@ -2319,6 +2319,7 @@ async function probe(bin) {
|
|
|
2319
2319
|
if (!version2) version2 = "unknown";
|
|
2320
2320
|
const flags = extractFlags(h.out);
|
|
2321
2321
|
const kvTypes = detectKvTypes(h.out, flags.includes("--cache-type-k"));
|
|
2322
|
+
const flagInfo = flags.map((f) => classifyFlag(f, h.out));
|
|
2322
2323
|
const ENUM_RE = /--spec-type\s+(\[[^\]\n]+\]|[a-z][a-z0-9_-]*(?:[,|][a-z0-9_-]+)+)/gi;
|
|
2323
2324
|
for (const m2 of h.out.matchAll(ENUM_RE)) {
|
|
2324
2325
|
for (const v2 of m2[1].replace(/[[\]]/g, "").split(/[,|]/)) {
|
|
@@ -2326,7 +2327,7 @@ async function probe(bin) {
|
|
|
2326
2327
|
if (t) flags.push(`spec-type:${t}`);
|
|
2327
2328
|
}
|
|
2328
2329
|
}
|
|
2329
|
-
return { version: version2, capabilities: { kvTypes, flags: [...new Set(flags)].sort() } };
|
|
2330
|
+
return { version: version2, capabilities: { kvTypes, flags: [...new Set(flags)].sort(), flagInfo } };
|
|
2330
2331
|
}
|
|
2331
2332
|
function detectFormat(bin) {
|
|
2332
2333
|
let fd;
|
|
@@ -2362,12 +2363,37 @@ function extractFlags(helpText) {
|
|
|
2362
2363
|
}
|
|
2363
2364
|
function detectKvTypes(helpText, hasCacheTypeFlag) {
|
|
2364
2365
|
const kvTypes = hasCacheTypeFlag ? [...KNOWN_KV] : ["f16"];
|
|
2365
|
-
const
|
|
2366
|
-
if (
|
|
2367
|
-
for (const
|
|
2366
|
+
const cacheTypeK = classifyFlag("--cache-type-k", helpText);
|
|
2367
|
+
if (cacheTypeK.kind === "enum") {
|
|
2368
|
+
for (const extra of cacheTypeK.enumValues ?? []) if (!kvTypes.includes(extra)) kvTypes.push(extra);
|
|
2368
2369
|
}
|
|
2369
2370
|
return kvTypes;
|
|
2370
2371
|
}
|
|
2372
|
+
function parseEnumList(blockText) {
|
|
2373
|
+
const labeled = /allowed values:\s*([\s\S]+)/i.exec(blockText);
|
|
2374
|
+
const bracketed = /\[([^\]\n]+)\]/.exec(blockText);
|
|
2375
|
+
const raw = labeled?.[1] ?? bracketed?.[1];
|
|
2376
|
+
if (!raw) return [];
|
|
2377
|
+
const values = raw.split(/[,|]/).map((s) => s.trim()).filter((s) => /^[a-z][a-z0-9_-]*$/i.test(s));
|
|
2378
|
+
return values.length >= 2 ? values : [];
|
|
2379
|
+
}
|
|
2380
|
+
function classifyFlag(flagName, helpText) {
|
|
2381
|
+
const escaped = flagName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2382
|
+
const ALIAS = "-{1,2}[a-zA-Z][a-zA-Z0-9-]*";
|
|
2383
|
+
const re = new RegExp(
|
|
2384
|
+
`(?:^|\\n)[ \\t]*(?:${ALIAS}[ \\t]*,[ \\t]*)*${escaped}(?![-a-zA-Z0-9])(?:[ \\t]*,[ \\t]*${ALIAS})*( *)(\\S+)?([\\s\\S]{0,400}?)(?=\\n\\s*\\(default|\\n[ \\t]*${ALIAS}|\\n\\n|$)`,
|
|
2385
|
+
"i"
|
|
2386
|
+
);
|
|
2387
|
+
const m = re.exec(helpText);
|
|
2388
|
+
if (!m) return { name: flagName, kind: "valued" };
|
|
2389
|
+
const gap = m[1] ?? "";
|
|
2390
|
+
const placeholder = m[2] ?? "";
|
|
2391
|
+
const block = m[3] ?? "";
|
|
2392
|
+
const enumValues = parseEnumList(placeholder + "\n" + block);
|
|
2393
|
+
if (enumValues.length > 0) return { name: flagName, kind: "enum", enumValues };
|
|
2394
|
+
if (gap.length !== 1 || !placeholder) return { name: flagName, kind: "boolean" };
|
|
2395
|
+
return { name: flagName, kind: "valued" };
|
|
2396
|
+
}
|
|
2371
2397
|
function firstNonEmptyLine(s) {
|
|
2372
2398
|
for (const ln of s.split("\n")) {
|
|
2373
2399
|
const t = ln.trim();
|
|
@@ -3330,7 +3356,8 @@ var Registry = class {
|
|
|
3330
3356
|
* NextN/MTP gating has the data it needs without a manual re-probe. */
|
|
3331
3357
|
async ensureProbed() {
|
|
3332
3358
|
for (const e of this.list().engines) {
|
|
3333
|
-
if (e.
|
|
3359
|
+
if (e.kind !== "llama-server") continue;
|
|
3360
|
+
if (e.version && !isStaleCapabilities(e.capabilities.flags, e.capabilities.flagInfo)) continue;
|
|
3334
3361
|
try {
|
|
3335
3362
|
await this.reprobe(e.id);
|
|
3336
3363
|
} catch {
|
|
@@ -3342,12 +3369,102 @@ function customSourceKey(s) {
|
|
|
3342
3369
|
if (!s.sourceRepo) return s.binPath;
|
|
3343
3370
|
return `${normRepoUrl(s.sourceRepo)}#${(s.sourceBranch ?? "").trim().toLowerCase()}#${(s.sourceCommit ?? "").trim().toLowerCase()}`;
|
|
3344
3371
|
}
|
|
3345
|
-
function isStaleCapabilities(flags) {
|
|
3372
|
+
function isStaleCapabilities(flags, flagInfo) {
|
|
3346
3373
|
if (flags.includes("--spec-type") && !flags.some((f) => f.startsWith("spec-type:"))) return true;
|
|
3347
3374
|
if (["--draft-max", "--draft-min", "--draft", "--draft-n", "--draft-n-min"].some((f) => flags.includes(f))) return true;
|
|
3375
|
+
if (flagInfo === void 0) return true;
|
|
3348
3376
|
return false;
|
|
3349
3377
|
}
|
|
3350
3378
|
|
|
3379
|
+
// src/telemetry/classify.ts
|
|
3380
|
+
var OOM_SIGNS = [
|
|
3381
|
+
"out of memory",
|
|
3382
|
+
"outofmemory",
|
|
3383
|
+
"failed to allocate",
|
|
3384
|
+
"alloc_buffer",
|
|
3385
|
+
"memory allocation of size",
|
|
3386
|
+
"cudamalloc",
|
|
3387
|
+
"insufficient memory",
|
|
3388
|
+
"not enough memory",
|
|
3389
|
+
"unable to allocate",
|
|
3390
|
+
"bad_alloc",
|
|
3391
|
+
"out of vram",
|
|
3392
|
+
"vram allocation failed",
|
|
3393
|
+
"cuda_error_out_of_memory",
|
|
3394
|
+
"resource_exhausted"
|
|
3395
|
+
];
|
|
3396
|
+
var ARCH_SIGNS = [
|
|
3397
|
+
"unknown model architecture",
|
|
3398
|
+
"unsupported model architecture",
|
|
3399
|
+
"unsupported architecture",
|
|
3400
|
+
"architecture not supported",
|
|
3401
|
+
"unknown architecture"
|
|
3402
|
+
];
|
|
3403
|
+
var GGUF_SIGNS = [
|
|
3404
|
+
"invalid magic",
|
|
3405
|
+
"error loading model",
|
|
3406
|
+
"failed to load model",
|
|
3407
|
+
"gguf_init",
|
|
3408
|
+
"corrupt",
|
|
3409
|
+
"unexpected end of file",
|
|
3410
|
+
"unexpectedly reached end of file",
|
|
3411
|
+
"truncated",
|
|
3412
|
+
"failed to read tensor",
|
|
3413
|
+
"wrong number of tensors",
|
|
3414
|
+
"tensor not found"
|
|
3415
|
+
];
|
|
3416
|
+
function classifyLoadFailure(err8) {
|
|
3417
|
+
if (!err8) return "other";
|
|
3418
|
+
if (err8.code === "readiness_timeout") return "timeout";
|
|
3419
|
+
if (err8.code === "engine_unsupported") return "no_engine";
|
|
3420
|
+
const haystack = [err8.message ?? "", ...err8.logTail ?? []].join("\n").toLowerCase();
|
|
3421
|
+
if (haystack.includes("no_active_engine")) return "no_engine";
|
|
3422
|
+
if (haystack.includes("no_such_model")) return "bad_gguf";
|
|
3423
|
+
if (OOM_SIGNS.some((s) => haystack.includes(s))) return "oom";
|
|
3424
|
+
if (ARCH_SIGNS.some((s) => haystack.includes(s))) return "unsupported_arch";
|
|
3425
|
+
if (GGUF_SIGNS.some((s) => haystack.includes(s))) return "bad_gguf";
|
|
3426
|
+
return "other";
|
|
3427
|
+
}
|
|
3428
|
+
function classifyBenchFailure(results) {
|
|
3429
|
+
if (results.some((r) => r.outcome === "oom")) return "oom";
|
|
3430
|
+
if (results.some((r) => r.outcome === "timeout")) return "timeout";
|
|
3431
|
+
return "other";
|
|
3432
|
+
}
|
|
3433
|
+
function classifyEngineErrorFingerprint(err8) {
|
|
3434
|
+
if (!err8) return "other";
|
|
3435
|
+
if (err8.code === "readiness_timeout") return "engine_start_timeout";
|
|
3436
|
+
if (err8.code === "model_load_failed") return "model_load_failed";
|
|
3437
|
+
const haystack = [err8.message ?? "", ...err8.logTail ?? []].join("\n").toLowerCase();
|
|
3438
|
+
if (OOM_SIGNS.some((s) => haystack.includes(s))) return "cuda_oom";
|
|
3439
|
+
if (ARCH_SIGNS.some((s) => haystack.includes(s))) return "model_load_failed";
|
|
3440
|
+
if (GGUF_SIGNS.some((s) => haystack.includes(s))) return "model_load_failed";
|
|
3441
|
+
if (err8.code === "engine_exited" || err8.code === "engine_spawn_failed") return "engine_crash";
|
|
3442
|
+
return "other";
|
|
3443
|
+
}
|
|
3444
|
+
var NETWORK_SIGNS = [
|
|
3445
|
+
"enotfound",
|
|
3446
|
+
"econnreset",
|
|
3447
|
+
"econnrefused",
|
|
3448
|
+
"etimedout",
|
|
3449
|
+
"fetch failed",
|
|
3450
|
+
"network",
|
|
3451
|
+
"check your connection"
|
|
3452
|
+
];
|
|
3453
|
+
var NO_ASSET_SIGNS = ["404", "no downloadable binary", "no release asset", "not found in"];
|
|
3454
|
+
var UNSUPPORTED_PLATFORM_SIGNS = ["no prebuilt binary for this operating system", "unsupported platform", "unsupported architecture"];
|
|
3455
|
+
var DISK_FULL_SIGNS = ["enospc", "no space left"];
|
|
3456
|
+
var PERMISSION_SIGNS = ["eacces", "eperm", "permission denied", "access is denied"];
|
|
3457
|
+
function classifyProvisionFailure(message) {
|
|
3458
|
+
if (!message) return "other";
|
|
3459
|
+
const haystack = message.toLowerCase();
|
|
3460
|
+
if (UNSUPPORTED_PLATFORM_SIGNS.some((s) => haystack.includes(s))) return "unsupported_platform";
|
|
3461
|
+
if (NO_ASSET_SIGNS.some((s) => haystack.includes(s))) return "no_asset";
|
|
3462
|
+
if (DISK_FULL_SIGNS.some((s) => haystack.includes(s))) return "disk_full";
|
|
3463
|
+
if (PERMISSION_SIGNS.some((s) => haystack.includes(s))) return "permission_denied";
|
|
3464
|
+
if (NETWORK_SIGNS.some((s) => haystack.includes(s))) return "network";
|
|
3465
|
+
return "other";
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3351
3468
|
// src/engines/provision-state.ts
|
|
3352
3469
|
var ProvisionState = class {
|
|
3353
3470
|
s = { active: false, phase: "idle", backend: "", pct: 0, part: 1, parts: 1, error: null };
|
|
@@ -3365,8 +3482,9 @@ var ProvisionState = class {
|
|
|
3365
3482
|
this.s.parts = parts;
|
|
3366
3483
|
}
|
|
3367
3484
|
/** Optional observer for the terminal outcome, wired in cli.ts (ADR-299
|
|
3368
|
-
* `onboarding_step`). The error
|
|
3369
|
-
*
|
|
3485
|
+
* `onboarding_step`). The raw error STRING is deliberately never passed —
|
|
3486
|
+
* only `failReason`, a `classifyProvisionFailure` enum member, so the only
|
|
3487
|
+
* consumer still never sees free text even though it now learns *why*. */
|
|
3370
3488
|
onSettled;
|
|
3371
3489
|
done() {
|
|
3372
3490
|
this.s = { active: false, phase: "idle", backend: "", pct: 0, part: 1, parts: 1, error: null };
|
|
@@ -3374,11 +3492,11 @@ var ProvisionState = class {
|
|
|
3374
3492
|
}
|
|
3375
3493
|
fail(error) {
|
|
3376
3494
|
this.s = { active: false, phase: "error", backend: this.s.backend, pct: 0, part: 1, parts: 1, error };
|
|
3377
|
-
this.settle(false);
|
|
3495
|
+
this.settle(false, classifyProvisionFailure(error));
|
|
3378
3496
|
}
|
|
3379
|
-
settle(ok) {
|
|
3497
|
+
settle(ok, failReason) {
|
|
3380
3498
|
try {
|
|
3381
|
-
this.onSettled?.(ok);
|
|
3499
|
+
this.onSettled?.(ok, failReason);
|
|
3382
3500
|
} catch {
|
|
3383
3501
|
}
|
|
3384
3502
|
}
|
|
@@ -3411,21 +3529,31 @@ var BuildState = class {
|
|
|
3411
3529
|
if (this.s.log.length > LOG_TAIL) this.s.log.splice(0, this.s.log.length - LOG_TAIL);
|
|
3412
3530
|
}
|
|
3413
3531
|
/** Optional observer for the terminal outcome, wired in cli.ts (ADR-299
|
|
3414
|
-
* `onboarding_step`). A plain callback so this module keeps
|
|
3415
|
-
* dependency; the error STRING is deliberately
|
|
3416
|
-
* consumer may never send free text.
|
|
3532
|
+
* `onboarding_step` / ADR-327 `error`). A plain callback so this module keeps
|
|
3533
|
+
* no telemetry dependency; the error STRING is deliberately never passed,
|
|
3534
|
+
* because the only consumer may never send free text. Three outcomes, not
|
|
3535
|
+
* two — `cancelled` is distinct from `fail` (PR #105 review finding): a
|
|
3536
|
+
* build the user deliberately aborted must not be reported as a crash. */
|
|
3417
3537
|
onSettled;
|
|
3418
3538
|
done() {
|
|
3419
3539
|
this.s = { ...this.s, active: false, phase: "done", error: null };
|
|
3420
|
-
this.settle(
|
|
3540
|
+
this.settle("ok");
|
|
3421
3541
|
}
|
|
3422
3542
|
fail(error) {
|
|
3423
3543
|
this.s = { ...this.s, active: false, phase: "error", error };
|
|
3424
|
-
this.settle(
|
|
3544
|
+
this.settle("fail");
|
|
3545
|
+
}
|
|
3546
|
+
/** A deliberate user cancellation. Same terminal UI shape as `fail()` (phase
|
|
3547
|
+
* 'error', so the UI still shows the run ended and why) — only the observer
|
|
3548
|
+
* outcome differs. A cancel is a choice, not a failure, and must not be
|
|
3549
|
+
* reported as one. */
|
|
3550
|
+
cancel(message) {
|
|
3551
|
+
this.s = { ...this.s, active: false, phase: "error", error: message };
|
|
3552
|
+
this.settle("cancelled");
|
|
3425
3553
|
}
|
|
3426
|
-
settle(
|
|
3554
|
+
settle(outcome) {
|
|
3427
3555
|
try {
|
|
3428
|
-
this.onSettled?.(
|
|
3556
|
+
this.onSettled?.(outcome);
|
|
3429
3557
|
} catch {
|
|
3430
3558
|
}
|
|
3431
3559
|
}
|
|
@@ -15142,6 +15270,14 @@ var FAIL_REASONS = [
|
|
|
15142
15270
|
"cancelled",
|
|
15143
15271
|
"other"
|
|
15144
15272
|
];
|
|
15273
|
+
var PROVISION_FAIL_REASONS = [
|
|
15274
|
+
"network",
|
|
15275
|
+
"no_asset",
|
|
15276
|
+
"unsupported_platform",
|
|
15277
|
+
"disk_full",
|
|
15278
|
+
"permission_denied",
|
|
15279
|
+
"other"
|
|
15280
|
+
];
|
|
15145
15281
|
var COUNT_BUCKETS = ["1", "2-5", "6-20", "21-100", "100+"];
|
|
15146
15282
|
var ERROR_FINGERPRINTS = [
|
|
15147
15283
|
"cuda_oom",
|
|
@@ -15197,7 +15333,14 @@ var HW_SPEC = {
|
|
|
15197
15333
|
ramMb: { kind: "number" }
|
|
15198
15334
|
};
|
|
15199
15335
|
var PAYLOAD_SPECS = {
|
|
15200
|
-
|
|
15336
|
+
// `failReason` is optional and, today, only ever sent for `step: 'engine_install'`
|
|
15337
|
+
// (classified by `classifyProvisionFailure`, PROVISION_FAIL_REASONS) — mirrors
|
|
15338
|
+
// `model_first_load.failReason`'s own "optional, only present on a real failure"
|
|
15339
|
+
// shape. Not step-conditional at the schema level (this validator is flat per
|
|
15340
|
+
// event name, not per payload value) — enforced by convention at the one call
|
|
15341
|
+
// site that sends it (cli.ts's `provision.onSettled`), same as elsewhere in this
|
|
15342
|
+
// file's payload specs.
|
|
15343
|
+
onboarding_step: { step: { enum: ONBOARDING_STEPS }, outcome: { enum: OUTCOMES }, failReason: { enum: PROVISION_FAIL_REASONS, optional: true } },
|
|
15201
15344
|
model_first_load: { outcome: { enum: OUTCOMES }, failReason: { enum: FAIL_REASONS, optional: true } },
|
|
15202
15345
|
feature_first_use: { feature: { enum: FEATURES } },
|
|
15203
15346
|
feature_used_daily: { feature: { enum: FEATURES }, countBucket: { enum: COUNT_BUCKETS } },
|
|
@@ -15379,36 +15522,6 @@ function reportModelLoad(dataDir, emitter, outcome, failReason) {
|
|
|
15379
15522
|
}
|
|
15380
15523
|
}
|
|
15381
15524
|
|
|
15382
|
-
// src/telemetry/classify.ts
|
|
15383
|
-
var OOM_SIGNS = [
|
|
15384
|
-
"out of memory",
|
|
15385
|
-
"outofmemory",
|
|
15386
|
-
"failed to allocate",
|
|
15387
|
-
"alloc_buffer",
|
|
15388
|
-
"memory allocation of size",
|
|
15389
|
-
"cudamalloc",
|
|
15390
|
-
"insufficient memory"
|
|
15391
|
-
];
|
|
15392
|
-
var ARCH_SIGNS = ["unknown model architecture", "unsupported model architecture", "unsupported architecture"];
|
|
15393
|
-
var GGUF_SIGNS = ["invalid magic", "error loading model", "failed to load model", "gguf_init", "corrupt"];
|
|
15394
|
-
function classifyLoadFailure(err8) {
|
|
15395
|
-
if (!err8) return "other";
|
|
15396
|
-
if (err8.code === "readiness_timeout") return "timeout";
|
|
15397
|
-
if (err8.code === "engine_unsupported") return "no_engine";
|
|
15398
|
-
const haystack = [err8.message ?? "", ...err8.logTail ?? []].join("\n").toLowerCase();
|
|
15399
|
-
if (haystack.includes("no_active_engine")) return "no_engine";
|
|
15400
|
-
if (haystack.includes("no_such_model")) return "bad_gguf";
|
|
15401
|
-
if (OOM_SIGNS.some((s) => haystack.includes(s))) return "oom";
|
|
15402
|
-
if (ARCH_SIGNS.some((s) => haystack.includes(s))) return "unsupported_arch";
|
|
15403
|
-
if (GGUF_SIGNS.some((s) => haystack.includes(s))) return "bad_gguf";
|
|
15404
|
-
return "other";
|
|
15405
|
-
}
|
|
15406
|
-
function classifyBenchFailure(results) {
|
|
15407
|
-
if (results.some((r) => r.outcome === "oom")) return "oom";
|
|
15408
|
-
if (results.some((r) => r.outcome === "timeout")) return "timeout";
|
|
15409
|
-
return "other";
|
|
15410
|
-
}
|
|
15411
|
-
|
|
15412
15525
|
// src/telemetry/disabled.ts
|
|
15413
15526
|
var TELEMETRY_ENV = "TURBOLLM_TELEMETRY";
|
|
15414
15527
|
var OFF_VALUES = /* @__PURE__ */ new Set(["off", "0", "false", "no"]);
|
|
@@ -15618,6 +15731,9 @@ var BenchRunner = class {
|
|
|
15618
15731
|
this.telemetry.emit("onboarding_step", { step: "first_load", outcome });
|
|
15619
15732
|
}
|
|
15620
15733
|
reportModelLoad(this.store.dir(), this.telemetry, outcome, failReason);
|
|
15734
|
+
if (outcome === "fail") {
|
|
15735
|
+
this.telemetry.error(failReason === "oom" ? "cuda_oom" : failReason === "timeout" ? "engine_start_timeout" : "other");
|
|
15736
|
+
}
|
|
15621
15737
|
}
|
|
15622
15738
|
/** Stop the engine — force-killed immediately when the run is cancelled (the user is actively
|
|
15623
15739
|
* waiting for it to stop, ADR-220), gracefully otherwise (lets llama-server release resources
|
|
@@ -19464,7 +19580,7 @@ var ALL = [
|
|
|
19464
19580
|
platforms: ["win32", "darwin", "linux"],
|
|
19465
19581
|
support: "experimental",
|
|
19466
19582
|
installEndpoint: "",
|
|
19467
|
-
note: "Upstream publishes prebuilt binaries, but TurboLLM builds from source here. The KVarN cache types (kvarn2...kvarn8, set via --cache-type-k/-v) aren't in the auto-tune sweep yet \u2014
|
|
19583
|
+
note: "Upstream publishes prebuilt binaries, but TurboLLM builds from source here. The KVarN cache types (kvarn2...kvarn8, set via --cache-type-k/-v) show up directly in the KV cache type dropdown, but aren't in the auto-tune sweep yet \u2014 pick one manually.",
|
|
19468
19584
|
variants: [
|
|
19469
19585
|
{
|
|
19470
19586
|
id: "beellama-source",
|
|
@@ -20296,7 +20412,7 @@ function registerApi(app2, d) {
|
|
|
20296
20412
|
}
|
|
20297
20413
|
if (e?.name === "AbortError") {
|
|
20298
20414
|
d.build.log("Build cancelled.");
|
|
20299
|
-
d.build.
|
|
20415
|
+
d.build.cancel("Build cancelled.");
|
|
20300
20416
|
} else {
|
|
20301
20417
|
const asmIssue = d.build.get().log.some((l) => /No CMAKE_ASM_COMPILER could be found|ASM compiler identification is unknown/i.test(l));
|
|
20302
20418
|
const raw = e instanceof Error ? e.message : String(e);
|
|
@@ -20371,7 +20487,7 @@ function registerApi(app2, d) {
|
|
|
20371
20487
|
} catch (e) {
|
|
20372
20488
|
if (e?.name === "AbortError") {
|
|
20373
20489
|
d.build.log("CUDA download cancelled.");
|
|
20374
|
-
d.build.
|
|
20490
|
+
d.build.cancel("CUDA download cancelled.");
|
|
20375
20491
|
} else {
|
|
20376
20492
|
d.build.fail(`Could not download CUDA: ${e instanceof Error ? e.message : String(e)}`);
|
|
20377
20493
|
}
|
|
@@ -24226,7 +24342,15 @@ async function recordOpenAiStreamUsage(d, body8, source, modelKey, codeSessionId
|
|
|
24226
24342
|
|
|
24227
24343
|
// src/telemetry/feature-map.ts
|
|
24228
24344
|
var BY_SEGMENT = {
|
|
24345
|
+
// `chat` (bare) only covers `/api/v1/chat/stop` — the Stop-generation button. Real
|
|
24346
|
+
// chat traffic (sending a message, creating/loading a conversation) lives under
|
|
24347
|
+
// `/api/v1/conversations/*` instead (PR #105 review finding: `chat` alone was
|
|
24348
|
+
// silently under-counting the product's own core feature). `conversations` IS the
|
|
24349
|
+
// chat feature's own primary data endpoint, not a foreign feature fetched as a side
|
|
24350
|
+
// effect the way `/api/v1/skills`/`/api/v1/chat-agents` are (see the comment below) —
|
|
24351
|
+
// so, unlike those two, mapping it here doesn't risk corrupting an unrelated signal.
|
|
24229
24352
|
chat: "chat",
|
|
24353
|
+
conversations: "chat",
|
|
24230
24354
|
code: "code",
|
|
24231
24355
|
artifacts: "artifacts",
|
|
24232
24356
|
mcp: "mcp",
|
|
@@ -24272,7 +24396,10 @@ function createApp(d) {
|
|
|
24272
24396
|
app2.use("/api/v1/code/*", codeAuth(d));
|
|
24273
24397
|
app2.use("*", async (c, next) => {
|
|
24274
24398
|
const feature = d.telemetry ? featureForPath(c.req.path) : null;
|
|
24275
|
-
if (feature !== null)
|
|
24399
|
+
if (feature !== null) {
|
|
24400
|
+
d.telemetry?.firstUse(feature);
|
|
24401
|
+
d.telemetry?.useFeature(feature);
|
|
24402
|
+
}
|
|
24276
24403
|
await next();
|
|
24277
24404
|
});
|
|
24278
24405
|
app2.get("/healthz", (c) => c.json({ status: "ok", version: d.version }));
|
|
@@ -24578,6 +24705,89 @@ var TunnelManager = class {
|
|
|
24578
24705
|
|
|
24579
24706
|
// src/telemetry/emit.ts
|
|
24580
24707
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
24708
|
+
|
|
24709
|
+
// src/telemetry/daily-usage.ts
|
|
24710
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync17, mkdirSync as mkdirSync19 } from "fs";
|
|
24711
|
+
import { join as join36 } from "path";
|
|
24712
|
+
var cache = /* @__PURE__ */ new Map();
|
|
24713
|
+
function usagePath(dataDir) {
|
|
24714
|
+
return join36(dataDir, "telemetry", "daily-usage.json");
|
|
24715
|
+
}
|
|
24716
|
+
function readFromDisk(dataDir) {
|
|
24717
|
+
try {
|
|
24718
|
+
const parsed = JSON.parse(readFileSync19(usagePath(dataDir), "utf8"));
|
|
24719
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
|
|
24720
|
+
return parsed;
|
|
24721
|
+
} catch {
|
|
24722
|
+
return {};
|
|
24723
|
+
}
|
|
24724
|
+
}
|
|
24725
|
+
function writeToDisk(dataDir, usage) {
|
|
24726
|
+
mkdirSync19(join36(dataDir, "telemetry"), { recursive: true });
|
|
24727
|
+
writeFileSync17(usagePath(dataDir), JSON.stringify(usage));
|
|
24728
|
+
}
|
|
24729
|
+
function loadCache(dataDir) {
|
|
24730
|
+
let usage = cache.get(dataDir);
|
|
24731
|
+
if (usage === void 0) {
|
|
24732
|
+
usage = readFromDisk(dataDir);
|
|
24733
|
+
cache.set(dataDir, usage);
|
|
24734
|
+
}
|
|
24735
|
+
return usage;
|
|
24736
|
+
}
|
|
24737
|
+
function bucketCount(n) {
|
|
24738
|
+
if (n <= 1) return "1";
|
|
24739
|
+
if (n <= 5) return "2-5";
|
|
24740
|
+
if (n <= 20) return "6-20";
|
|
24741
|
+
if (n <= 100) return "21-100";
|
|
24742
|
+
return "100+";
|
|
24743
|
+
}
|
|
24744
|
+
function recordFeatureUse(dataDir, feature, today) {
|
|
24745
|
+
try {
|
|
24746
|
+
const usage = loadCache(dataDir);
|
|
24747
|
+
const existing = usage[feature];
|
|
24748
|
+
if (existing === void 0) {
|
|
24749
|
+
usage[feature] = { day: today, count: 1 };
|
|
24750
|
+
return null;
|
|
24751
|
+
}
|
|
24752
|
+
if (existing.day === today) {
|
|
24753
|
+
usage[feature] = { day: today, count: existing.count + 1 };
|
|
24754
|
+
return null;
|
|
24755
|
+
}
|
|
24756
|
+
const rolled = { day: existing.day, bucket: bucketCount(existing.count) };
|
|
24757
|
+
usage[feature] = { day: today, count: 1 };
|
|
24758
|
+
writeToDisk(dataDir, usage);
|
|
24759
|
+
return rolled;
|
|
24760
|
+
} catch {
|
|
24761
|
+
return null;
|
|
24762
|
+
}
|
|
24763
|
+
}
|
|
24764
|
+
function flushStaleDailyUsage(dataDir, today) {
|
|
24765
|
+
try {
|
|
24766
|
+
const usage = loadCache(dataDir);
|
|
24767
|
+
const rolled = [];
|
|
24768
|
+
let changed = false;
|
|
24769
|
+
for (const [feature, entry] of Object.entries(usage)) {
|
|
24770
|
+
if (entry.day === today) continue;
|
|
24771
|
+
rolled.push({ feature, day: entry.day, bucket: bucketCount(entry.count) });
|
|
24772
|
+
delete usage[feature];
|
|
24773
|
+
changed = true;
|
|
24774
|
+
}
|
|
24775
|
+
if (changed) writeToDisk(dataDir, usage);
|
|
24776
|
+
return rolled;
|
|
24777
|
+
} catch {
|
|
24778
|
+
return [];
|
|
24779
|
+
}
|
|
24780
|
+
}
|
|
24781
|
+
function persistDailyUsage(dataDir) {
|
|
24782
|
+
try {
|
|
24783
|
+
const usage = cache.get(dataDir);
|
|
24784
|
+
if (usage === void 0) return;
|
|
24785
|
+
writeToDisk(dataDir, usage);
|
|
24786
|
+
} catch {
|
|
24787
|
+
}
|
|
24788
|
+
}
|
|
24789
|
+
|
|
24790
|
+
// src/telemetry/emit.ts
|
|
24581
24791
|
var REQUIRES_FULL = /* @__PURE__ */ new Set(["error"]);
|
|
24582
24792
|
var Emitter = class {
|
|
24583
24793
|
o;
|
|
@@ -24634,6 +24844,45 @@ var Emitter = class {
|
|
|
24634
24844
|
if (!this.canSend("daily_active")) return;
|
|
24635
24845
|
if (this.claim(`daily:${this.today()}`)) this.emit("daily_active");
|
|
24636
24846
|
}
|
|
24847
|
+
/**
|
|
24848
|
+
* Count one use of `feature` toward today's tally, emitting a bucketed
|
|
24849
|
+
* `feature_used_daily` for the previous day the moment the calendar day
|
|
24850
|
+
* rolls over. Consent is checked BEFORE any count is recorded — same
|
|
24851
|
+
* reasoning as `firstUse` above (see its doc comment): usage while
|
|
24852
|
+
* telemetry is off must never silently contribute to a count reported
|
|
24853
|
+
* after the user opts in later.
|
|
24854
|
+
*/
|
|
24855
|
+
useFeature(feature) {
|
|
24856
|
+
if (!this.canSend("feature_used_daily")) return;
|
|
24857
|
+
const rolled = recordFeatureUse(this.o.dataDir, feature, this.today());
|
|
24858
|
+
if (rolled) this.emit("feature_used_daily", { feature, countBucket: rolled.bucket });
|
|
24859
|
+
}
|
|
24860
|
+
/**
|
|
24861
|
+
* Roll over any feature whose tally is from a day earlier than today, then
|
|
24862
|
+
* persist whatever's left (today's still-in-progress counts) to disk.
|
|
24863
|
+
* Called periodically (cli.ts, alongside the queue flush) for two reasons:
|
|
24864
|
+
* a feature used only on a user's LAST active day still gets reported
|
|
24865
|
+
* instead of waiting indefinitely for a next use that may never come, AND
|
|
24866
|
+
* same-day counts — which `useFeature` only ever keeps in memory, to avoid
|
|
24867
|
+
* a disk write on every matching API request — get a chance to survive a
|
|
24868
|
+
* crash instead of living only until the next rollover.
|
|
24869
|
+
*/
|
|
24870
|
+
flushDailyUsage() {
|
|
24871
|
+
if (!this.canSend("feature_used_daily")) return;
|
|
24872
|
+
for (const { feature, bucket } of flushStaleDailyUsage(this.o.dataDir, this.today())) {
|
|
24873
|
+
this.emit("feature_used_daily", { feature, countBucket: bucket });
|
|
24874
|
+
}
|
|
24875
|
+
persistDailyUsage(this.o.dataDir);
|
|
24876
|
+
}
|
|
24877
|
+
/**
|
|
24878
|
+
* Emit `error` — full level only (`REQUIRES_FULL` above), and deliberately
|
|
24879
|
+
* NOT once-only: unlike `model_first_load`'s single most-valuable-attempt
|
|
24880
|
+
* signal, every crash after the first is still a real data point (ADR-299's
|
|
24881
|
+
* "what is failing?" journey question, previously never wired to anything).
|
|
24882
|
+
*/
|
|
24883
|
+
error(fingerprint) {
|
|
24884
|
+
this.emit("error", { fingerprint });
|
|
24885
|
+
}
|
|
24637
24886
|
/**
|
|
24638
24887
|
* Mint the anonymous machine id lazily.
|
|
24639
24888
|
*
|
|
@@ -24662,8 +24911,8 @@ var Emitter = class {
|
|
|
24662
24911
|
hideChildConsoleWindows();
|
|
24663
24912
|
var version = "0.1.1";
|
|
24664
24913
|
try {
|
|
24665
|
-
const pkgPath =
|
|
24666
|
-
version = JSON.parse(
|
|
24914
|
+
const pkgPath = join37(dirname12(fileURLToPath2(import.meta.url)), "..", "package.json");
|
|
24915
|
+
version = JSON.parse(readFileSync20(pkgPath, "utf8")).version ?? version;
|
|
24667
24916
|
} catch {
|
|
24668
24917
|
}
|
|
24669
24918
|
var [nodeMajor, nodeMinor] = process.versions.node.split(".").map(Number);
|
|
@@ -24691,7 +24940,7 @@ function argValue(name, fallback) {
|
|
|
24691
24940
|
if (hasFlag("--no-telemetry")) process.env[TELEMETRY_ENV] = "off";
|
|
24692
24941
|
function configuredDaemonPort(configPath) {
|
|
24693
24942
|
try {
|
|
24694
|
-
const cfg2 = JSON.parse(
|
|
24943
|
+
const cfg2 = JSON.parse(readFileSync20(configPath, "utf8"));
|
|
24695
24944
|
if (typeof cfg2.daemon?.port === "number" && cfg2.daemon.port > 0) return cfg2.daemon.port;
|
|
24696
24945
|
} catch {
|
|
24697
24946
|
}
|
|
@@ -24816,7 +25065,7 @@ if (pruned > 0) console.log(`pruned ${pruned} dangling engine build(s)`);
|
|
|
24816
25065
|
var provision = new ProvisionState();
|
|
24817
25066
|
var build = new BuildState();
|
|
24818
25067
|
var updates = new UpdateChecker();
|
|
24819
|
-
var enginesDir =
|
|
25068
|
+
var enginesDir = join37(store.dir(), "engines");
|
|
24820
25069
|
void seedDefaultEngines(registry, enginesDir, provision).then(() => registry.ensureProbed());
|
|
24821
25070
|
var manager = new Manager(store);
|
|
24822
25071
|
var scanner = new Scanner(store);
|
|
@@ -24871,15 +25120,23 @@ manager.onLoadSettled = (ok, err8) => {
|
|
|
24871
25120
|
telemetry.emit("onboarding_step", { step: "first_load", outcome });
|
|
24872
25121
|
}
|
|
24873
25122
|
reportModelLoad(store.dir(), telemetry, outcome, ok ? void 0 : classifyLoadFailure(err8));
|
|
25123
|
+
if (!ok) telemetry.error(classifyEngineErrorFingerprint(err8));
|
|
24874
25124
|
};
|
|
24875
25125
|
bench.telemetry = telemetry;
|
|
24876
|
-
provision.onSettled = (ok) => telemetry.emit("onboarding_step", { step: "engine_install", outcome: ok ? "ok" : "fail" });
|
|
24877
|
-
downloads.onSettled = (outcome) =>
|
|
25126
|
+
provision.onSettled = (ok, failReason) => telemetry.emit("onboarding_step", { step: "engine_install", outcome: ok ? "ok" : "fail", ...failReason ? { failReason } : {} });
|
|
25127
|
+
downloads.onSettled = (outcome) => {
|
|
25128
|
+
telemetry.emit("onboarding_step", { step: "model_download", outcome });
|
|
25129
|
+
if (outcome === "fail") telemetry.error("download_failed");
|
|
25130
|
+
};
|
|
25131
|
+
build.onSettled = (outcome) => {
|
|
25132
|
+
if (outcome === "fail") telemetry.error("build_failed");
|
|
25133
|
+
};
|
|
24878
25134
|
setTimeout(() => {
|
|
24879
25135
|
telemetry.once("app_first_run");
|
|
24880
25136
|
void flush(store.dir(), store.snapshot().telemetry.level);
|
|
24881
25137
|
}, 3e3).unref();
|
|
24882
25138
|
setInterval(() => void flush(store.dir(), store.snapshot().telemetry.level), 5 * 6e4).unref();
|
|
25139
|
+
setInterval(() => telemetry.flushDailyUsage(), 5 * 6e4).unref();
|
|
24883
25140
|
var tunnelRequested = hasFlag("--tunnel");
|
|
24884
25141
|
if (tunnelRequested) deps.tunnel = new TunnelManager(store.dir());
|
|
24885
25142
|
deps.codeRuns = new CodeRunManager(deps);
|
|
@@ -25049,7 +25306,7 @@ var restarting = false;
|
|
|
25049
25306
|
function spawnReplacement() {
|
|
25050
25307
|
let out = "ignore";
|
|
25051
25308
|
try {
|
|
25052
|
-
out = openSync3(
|
|
25309
|
+
out = openSync3(join37(store.dir(), "restart.log"), "a");
|
|
25053
25310
|
} catch {
|
|
25054
25311
|
out = "ignore";
|
|
25055
25312
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./radix-fDePPJsY.js";import{b as M,u as W,r as b}from"./vendor-DnjiPEcz.js";import{u as $,b as G,d as H,e as Y,f as J,a as E,B as y,c as B,t as h,A as C}from"./index-
|
|
1
|
+
import{j as e}from"./radix-fDePPJsY.js";import{b as M,u as W,r as b}from"./vendor-DnjiPEcz.js";import{u as $,b as G,d as H,e as Y,f as J,a as E,B as y,c as B,t as h,A as C}from"./index-x5TIbXu2.js";import{f as U}from"./chat-api-Vp38MmPT.js";import{f as V,a as X}from"./agent-api-CbZW6U0W.js";import{P as z}from"./personas-B0p0BX69.js";import{C as Z}from"./chevron-left-C7VOgCa-.js";import{R as ee}from"./rotate-ccw-B4FPn_uu.js";import{T as te}from"./trash-2-Bh6pLoU3.js";import{C as se}from"./chevron-right-Cvc6jjhp.js";const ne=()=>({name:"",description:"",systemPrompt:"",skillIds:[],tools:[]});function oe(s){const d=[],x=new Map;for(const n of s){const o=/^mcp__([^_]+(?:_[^_]+)*)__/.exec(n.name);if(!o){d.push(n);continue}const i=o[1],p=/^\[([^\]]+)\]/.exec(n.description),c=p?p[1]:i.replace(/_/g," ");x.has(i)||x.set(i,{key:i,label:c,tools:[]}),x.get(i).tools.push(n)}return{builtin:d,groups:[...x.values()].sort((n,o)=>n.label.localeCompare(o.label))}}function ae(s){return s.replace(/^mcp__[^_]+(?:_[^_]+)*__/,"")}function le(s){return s.replace(/^\[[^\]]+\]\s*/,"")}function q({tool:s,checked:d,onToggle:x}){return e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-[12px]",children:[e.jsx("input",{type:"checkbox",className:"mt-0.5",checked:d,onChange:x}),e.jsxs("span",{className:"flex flex-col",children:[e.jsx("span",{className:"font-mono text-ink",children:ae(s.name)}),s.description&&e.jsx("span",{className:"text-faint",children:le(s.description)})]})]})}function re({group:s,selected:d,onToggleAll:x,onToggleOne:n}){const[o,i]=b.useState(!1),p=s.tools.map(l=>l.name),c=p.filter(l=>d.has(l)).length,a=c===p.length,f=c>0&&!a,u=b.useRef(null);return b.useEffect(()=>{u.current&&(u.current.indeterminate=f)},[f]),e.jsxs("div",{className:"rounded-md border border-border",children:[e.jsxs("div",{className:"flex items-center gap-2 px-2.5 py-2",children:[e.jsx("input",{ref:u,type:"checkbox",checked:a,onChange:()=>x(p,!a)}),e.jsxs("button",{type:"button",onClick:()=>i(l=>!l),className:"flex flex-1 items-center gap-1.5 text-left text-[13px] text-ink",children:[e.jsx(se,{size:12,className:B("shrink-0 text-faint transition-transform",o&&"rotate-90")}),s.label,e.jsxs("span",{className:"text-[11px] text-faint",children:["(",c,"/",p.length,")"]})]})]}),o&&e.jsx("div",{className:"flex flex-col gap-1.5 border-t border-border px-3 py-2 pl-9",children:s.tools.map(l=>e.jsx(q,{tool:l,checked:d.has(l.name),onToggle:()=>n(l.name)},l.name))})]})}function ie({tools:s,selected:d,onChange:x}){const n=new Set(d),{builtin:o,groups:i}=oe(s),p=a=>x(n.has(a)?d.filter(f=>f!==a):[...d,a]),c=(a,f)=>{const u=d.filter(l=>!a.includes(l));x(f?[...u,...a]:u)};return s.length===0?e.jsx("p",{className:"text-[12px] text-faint",children:"No tools available yet."}):e.jsxs("div",{className:"flex flex-col gap-2",children:[o.length>0&&e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:o.map(a=>e.jsx(q,{tool:a,checked:n.has(a.name),onToggle:()=>p(a.name)},a.name))}),i.map(a=>e.jsx(re,{group:a,selected:n,onToggleAll:c,onToggleOne:p},a.key))]})}function ke(){const{agentId:s="new"}=M(),d=W(),x=$(),n=s==="new",o=!n&&z.some(t=>t.id===s),i=o?z.find(t=>t.id===s):void 0,p=G(),c=!n&&!o?(p.data??[]).find(t=>t.id===s):void 0,a=H(),f=Y(),u=J(),l=o?f.data?.[s]:void 0,_=E({queryKey:X.list(),queryFn:V,staleTime:0}),k=_.data??[],I=E({queryKey:["available-tools"],queryFn:U}),j=I.data??[],[m,g]=b.useState(ne()),[S,T]=b.useState(!1),[A,P]=b.useState(!1),[D,w]=b.useState(!1),[R,L]=b.useState("skills");n&&!S&&(k.length||j.length)&&(g(t=>({...t,skillIds:k.map(r=>r.id),tools:j.map(r=>r.name)})),T(!0)),!n&&!o&&!S&&c&&(g({name:c.name,description:c.description,systemPrompt:c.systemPrompt,skillIds:c.skillIds,tools:c.tools}),T(!0)),o&&!S&&i&&f.isSuccess&&(k.length||j.length)&&(g({name:l?.name??i.name,description:l?.description??i.description,systemPrompt:l?.systemPrompt??i.systemPrompt,skillIds:l?.skillIds??k.map(t=>t.id),tools:l?.tools??j.map(t=>t.name)}),T(!0));const N=()=>d("/customize"),Q=t=>g(r=>({...r,skillIds:r.skillIds.includes(t)?r.skillIds.filter(v=>v!==t):[...r.skillIds,t]})),O=()=>{if(!m.name.trim()){h.error("Name is required.");return}P(!0);const t={name:m.name.trim(),description:m.description.trim(),systemPrompt:m.systemPrompt,skillIds:m.skillIds,tools:m.tools};if(o){u.save.mutate({id:s,override:t},{onSuccess:()=>{h.success("Agent saved."),N()},onError:v=>{h.error(v instanceof C?v.message:"Could not save agent."),P(!1)}});return}const r={onSuccess:()=>{x.invalidateQueries({queryKey:["chat-agents"]}),h.success(n?"Agent created.":"Agent saved."),N()},onError:v=>{h.error(v instanceof C?v.message:"Could not save agent."),P(!1)}};n?a.add.mutate(t,r):a.update.mutate({id:s,patch:t},r)},F=()=>{u.reset.mutate(s,{onSuccess:()=>{h.success("Reset to default."),i&&g({name:i.name,description:i.description,systemPrompt:i.systemPrompt,skillIds:k.map(t=>t.id),tools:j.map(t=>t.name)})},onError:t=>h.error(t instanceof C?t.message:"Could not reset agent.")})},K=()=>{a.remove.mutate(s,{onSuccess:()=>{h.success("Agent deleted."),N()},onError:t=>h.error(t instanceof C?t.message:"Could not delete agent.")})};return!n&&!o&&p.isSuccess&&!c?e.jsxs("div",{className:"flex w-full flex-col items-center gap-3 px-8 py-16",children:[e.jsx("p",{className:"text-[14px] text-muted",children:"That agent no longer exists."}),e.jsx(y,{size:"sm",variant:"outline",onClick:N,children:"Back to agents"})]}):e.jsxs("div",{className:"flex w-full max-w-4xl flex-col gap-5 px-4 py-6 md:px-8",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",onClick:N,className:"text-faint hover:text-ink",title:"Back to agents",children:e.jsx(Z,{size:18})}),e.jsx("span",{className:"text-[15px] font-medium text-ink",children:n?"New agent":o?l?"Edit agent (modified built-in)":"Edit agent (built-in)":"Edit agent"}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[o&&e.jsxs(y,{size:"sm",variant:"outline",onClick:F,disabled:u.reset.isPending,children:[e.jsx(ee,{size:13})," Reset to default"]}),e.jsx(y,{size:"sm",variant:"outline",onClick:N,children:"Cancel"}),e.jsx(y,{size:"sm",onClick:O,disabled:A||!m.name.trim(),children:A?"Saving…":"Save"})]})]}),o&&e.jsx("p",{className:"rounded-md border border-border bg-panel px-3 py-2 text-[12px] text-muted",children:"Built-in agents can be edited in place — Reset to default discards your changes and restores TurboLLM's original prompt and access."}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"Name"}),e.jsx("input",{className:"rounded-md border border-border bg-bg px-3 py-1.5 text-[13px] text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"Release Notes Writer",value:m.name,onChange:t=>g(r=>({...r,name:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"Description"}),e.jsx("input",{className:"rounded-md border border-border bg-bg px-3 py-1.5 text-[13px] text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"What this agent is for, in one line",value:m.description,onChange:t=>g(r=>({...r,description:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"System prompt"}),e.jsx("textarea",{className:"min-h-[160px] resize-y rounded-md border border-border bg-bg px-3 py-2 font-mono text-[12px] leading-relaxed text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"You are…",value:m.systemPrompt,onChange:t=>g(r=>({...r,systemPrompt:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-2.5",children:[e.jsx("div",{className:"inline-flex w-fit rounded-md border border-border p-0.5",children:["skills","tools"].map(t=>e.jsx("button",{type:"button",onClick:()=>L(t),className:B("rounded px-3 py-1.5 text-[13px] font-medium transition-colors",R===t?"bg-accent/12 text-accent":"text-muted hover:text-ink"),children:t==="skills"?`Skills (${m.skillIds.length})`:`Tools (${m.tools.length})`},t))}),R==="skills"?_.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):k.length===0?e.jsx("p",{className:"text-[12px] text-faint",children:"No skills yet — create one under Customize → Skills."}):e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:k.map(t=>e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-[13px]",children:[e.jsx("input",{type:"checkbox",className:"mt-0.5",checked:m.skillIds.includes(t.id),onChange:()=>Q(t.id)}),e.jsxs("span",{className:"flex flex-col",children:[e.jsx("span",{className:"text-ink",children:t.name}),t.description&&e.jsx("span",{className:"text-[12px] text-muted",children:t.description})]})]},t.id))}):I.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):e.jsx(ie,{tools:j,selected:m.tools,onChange:t=>g(r=>({...r,tools:t}))})]}),!n&&!o&&(D?e.jsxs("div",{className:"flex items-center gap-2 self-start rounded-md border border-border bg-panel p-2 text-[12px]",children:[e.jsx("span",{className:"flex-1 text-muted",children:"Delete this agent?"}),e.jsx("button",{type:"button",onClick:K,className:"rounded px-2 py-1 text-[color:var(--err)] hover:bg-[color:color-mix(in_srgb,var(--err)_12%,transparent)]",children:"Delete"}),e.jsx("button",{type:"button",onClick:()=>w(!1),className:"rounded px-2 py-1 text-faint hover:text-ink",children:"Cancel"})]}):e.jsxs("button",{type:"button",onClick:()=>w(!0),className:"flex items-center gap-1.5 self-start text-[12px] text-faint hover:text-[color:var(--err)]",children:[e.jsx(te,{size:13})," Delete agent"]}))]})}export{ke as AgentEditPage};
|