turbollm 1.6.0 → 1.6.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/README.md +7 -4
- package/dist/cli.js +206 -44
- package/dist/webdist/assets/{AgentsScreen-qd7_yqju.js → AgentsScreen-BviDj463.js} +1 -1
- package/dist/webdist/assets/ChatScreen-4a_6ZX6c.js +29 -0
- package/dist/webdist/assets/CustomizeScreen-BhZJK7xv.js +4 -0
- package/dist/webdist/assets/{DeveloperScreen-CCWBQQ4y.js → DeveloperScreen-8CVekggw.js} +1 -1
- package/dist/webdist/assets/EnginesScreen-zHLzht8k.js +7 -0
- package/dist/webdist/assets/ModelDetailDialog-DjMSf0rz.js +29 -0
- package/dist/webdist/assets/{ModelDirs-E_tFMIjS.js → ModelDirs-CIOcl5qu.js} +1 -1
- package/dist/webdist/assets/ModelsScreen-v7kDcWmr.js +2 -0
- package/dist/webdist/assets/{SettingsScreen-BFhQBO1d.js → SettingsScreen-DnSgBps7.js} +1 -1
- package/dist/webdist/assets/alert-dialog-93rFXd1_.js +1 -0
- package/dist/webdist/assets/{arc-820YYJ1l.js → arc-BFc9YP9w.js} +1 -1
- package/dist/webdist/assets/{architectureDiagram-3BPJPVTR-BTSJZjgr.js → architectureDiagram-3BPJPVTR-Bd6WFbHz.js} +1 -1
- package/dist/webdist/assets/{arrow-left-BJXqu8NS.js → arrow-left--NjoPnor.js} +1 -1
- package/dist/webdist/assets/{blockDiagram-GPEHLZMM-E_gowUIA.js → blockDiagram-GPEHLZMM-Dupawk92.js} +1 -1
- package/dist/webdist/assets/{c4Diagram-AAUBKEIU-DwJcumW7.js → c4Diagram-AAUBKEIU-BMhAUE8i.js} +1 -1
- package/dist/webdist/assets/channel-BCSKocRg.js +1 -0
- package/dist/webdist/assets/check-Bu2UFiB0.js +1 -0
- package/dist/webdist/assets/chevron-right-kiIQKgde.js +1 -0
- package/dist/webdist/assets/{chunk-2J33WTMH-DWJ9qmM_.js → chunk-2J33WTMH-BhxySqcq.js} +1 -1
- package/dist/webdist/assets/{chunk-4BX2VUAB-DgyEqU31.js → chunk-4BX2VUAB-B-UGkx88.js} +1 -1
- package/dist/webdist/assets/{chunk-55IACEB6-CsI85v4r.js → chunk-55IACEB6-BDvjmk8T.js} +1 -1
- package/dist/webdist/assets/{chunk-727SXJPM-YRdSK3U3.js → chunk-727SXJPM-BhyFFQxZ.js} +1 -1
- package/dist/webdist/assets/{chunk-AQP2D5EJ-BnTfokPI.js → chunk-AQP2D5EJ-VTSW3fZJ.js} +1 -1
- package/dist/webdist/assets/{chunk-FMBD7UC4-Dt8O7iM6.js → chunk-FMBD7UC4-QKx1b_-m.js} +1 -1
- package/dist/webdist/assets/{chunk-ND2GUHAM-OsM9VDgQ.js → chunk-ND2GUHAM-DZANzpY0.js} +1 -1
- package/dist/webdist/assets/{chunk-QZHKN3VN-CW3L84fX.js → chunk-QZHKN3VN-DVZIy115.js} +1 -1
- package/dist/webdist/assets/circle-check-C4aACGyb.js +1 -0
- package/dist/webdist/assets/circle-x-koFsrlGA.js +1 -0
- package/dist/webdist/assets/classDiagram-4FO5ZUOK-B_Eb_jRj.js +1 -0
- package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-B_Eb_jRj.js +1 -0
- package/dist/webdist/assets/common-CQVogVIs.js +1 -0
- package/dist/webdist/assets/{copy-button-DrRexlJn.js → copy-button-3_2Us2zb.js} +1 -1
- package/dist/webdist/assets/{cose-bilkent-S5V4N54A-cNqjZyGk.js → cose-bilkent-S5V4N54A-Ci07N3_4.js} +1 -1
- package/dist/webdist/assets/{dagre-BM42HDAG-zr_aSu4P.js → dagre-BM42HDAG-45qc0phu.js} +1 -1
- package/dist/webdist/assets/{diagram-2AECGRRQ-D8fYvWd0.js → diagram-2AECGRRQ-DA3u3hzE.js} +1 -1
- package/dist/webdist/assets/{diagram-5GNKFQAL-Cp2jBV3j.js → diagram-5GNKFQAL-B3wpvPKp.js} +1 -1
- package/dist/webdist/assets/{diagram-KO2AKTUF-SdWp_DPO.js → diagram-KO2AKTUF-h1qR3ckq.js} +1 -1
- package/dist/webdist/assets/{diagram-LMA3HP47-DHwQz9MP.js → diagram-LMA3HP47-B3uU2roT.js} +1 -1
- package/dist/webdist/assets/{diagram-OG6HWLK6-FGejDPqJ.js → diagram-OG6HWLK6-CibVtZrO.js} +1 -1
- package/dist/webdist/assets/dialog-Dn3dxmMP.js +1 -0
- package/dist/webdist/assets/{erDiagram-TEJ5UH35-Ci0ArYoY.js → erDiagram-TEJ5UH35-VsHZBAOZ.js} +1 -1
- package/dist/webdist/assets/{flowDiagram-I6XJVG4X-g96T9cRZ.js → flowDiagram-I6XJVG4X-DhYah8sF.js} +1 -1
- package/dist/webdist/assets/{ganttDiagram-6RSMTGT7-CFGWWtss.js → ganttDiagram-6RSMTGT7-RPkNEJnH.js} +1 -1
- package/dist/webdist/assets/{gitGraphDiagram-PVQCEYII-FFeX8xGw.js → gitGraphDiagram-PVQCEYII-JknfsYQp.js} +1 -1
- package/dist/webdist/assets/index-5NYGYU_t.css +1 -0
- package/dist/webdist/assets/{index-CM4wnT7v.js → index-K2ZQBdky.js} +4 -4
- package/dist/webdist/assets/{infoDiagram-5YYISTIA-CTuVSOzN.js → infoDiagram-5YYISTIA-BeGMPySd.js} +1 -1
- package/dist/webdist/assets/{ishikawaDiagram-YF4QCWOH-BMyIM99h.js → ishikawaDiagram-YF4QCWOH-D38Q1-tz.js} +1 -1
- package/dist/webdist/assets/{journeyDiagram-JHISSGLW-CcKLWYl8.js → journeyDiagram-JHISSGLW-CG8TFzp6.js} +1 -1
- package/dist/webdist/assets/{kanban-definition-UN3LZRKU-CuzVk9Q_.js → kanban-definition-UN3LZRKU-CNgUZ1rd.js} +1 -1
- package/dist/webdist/assets/{linear-DvYrxcXL.js → linear-DYIxmEeo.js} +1 -1
- package/dist/webdist/assets/{mermaid.core-DIGvaW9x.js → mermaid.core-CZhJJFjL.js} +4 -4
- package/dist/webdist/assets/{mindmap-definition-RKZ34NQL-Dh_7fzN2.js → mindmap-definition-RKZ34NQL-BIVYSbvh.js} +1 -1
- package/dist/webdist/assets/pencil-iVnKKeCp.js +1 -0
- package/dist/webdist/assets/{personas-DdUgL1dH.js → personas-DslX_qdt.js} +4 -4
- package/dist/webdist/assets/{pieDiagram-4H26LBE5-G_BsYb0k.js → pieDiagram-4H26LBE5-CU9qALXo.js} +1 -1
- package/dist/webdist/assets/plus-mSm32jpN.js +1 -0
- package/dist/webdist/assets/{quadrantDiagram-W4KKPZXB-B1DekSy3.js → quadrantDiagram-W4KKPZXB-AE50YmvR.js} +1 -1
- package/dist/webdist/assets/{radix-4XwKfE88.js → radix-9WP-OkMY.js} +2 -2
- package/dist/webdist/assets/refresh-cw-C04dn1r1.js +1 -0
- package/dist/webdist/assets/{requirementDiagram-4Y6WPE33-DPYkFc77.js → requirementDiagram-4Y6WPE33-Crymka5P.js} +1 -1
- package/dist/webdist/assets/{sankeyDiagram-5OEKKPKP-HfCQTOkK.js → sankeyDiagram-5OEKKPKP-DRviwCen.js} +1 -1
- package/dist/webdist/assets/save-BT2nzRB6.js +1 -0
- package/dist/webdist/assets/{sequenceDiagram-3UESZ5HK-C71xQD9L.js → sequenceDiagram-3UESZ5HK-DuBllsfJ.js} +1 -1
- package/dist/webdist/assets/skeleton-BfMJjCGZ.js +1 -0
- package/dist/webdist/assets/{stateDiagram-AJRCARHV-C0m1fR_s.js → stateDiagram-AJRCARHV-Cj4BwRLl.js} +1 -1
- package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-Y25sKBZm.js +1 -0
- package/dist/webdist/assets/{timeline-definition-PNZ67QCA-B5SB89Kk.js → timeline-definition-PNZ67QCA-BWnH2-RY.js} +1 -1
- package/dist/webdist/assets/trash-2-Ce39UFy5.js +1 -0
- package/dist/webdist/assets/{vendor-CKtmMAvG.js → vendor-W5GIuFcv.js} +1 -1
- package/dist/webdist/assets/{vennDiagram-CIIHVFJN-Bs3E_UnU.js → vennDiagram-CIIHVFJN-GgdSx9c7.js} +1 -1
- package/dist/webdist/assets/{wardley-L42UT6IY-D-lZEV6Q.js → wardley-L42UT6IY-C9XKbMb6.js} +1 -1
- package/dist/webdist/assets/{wardleyDiagram-YWT4CUSO-DIiAQmgm.js → wardleyDiagram-YWT4CUSO-ZxceNtWm.js} +1 -1
- package/dist/webdist/assets/{wrench-C7hemMKG.js → wrench-Ceqe74n2.js} +1 -1
- package/dist/webdist/assets/{xychartDiagram-2RQKCTM6-DViSTAkf.js → xychartDiagram-2RQKCTM6-C-mAbbHW.js} +1 -1
- package/dist/webdist/index.html +4 -4
- package/package.json +1 -1
- package/dist/webdist/assets/ChatScreen-DYeJQoLV.js +0 -57
- package/dist/webdist/assets/CustomizeScreen-DBXBuQPm.js +0 -4
- package/dist/webdist/assets/EnginesScreen-DQQLI0Qv.js +0 -7
- package/dist/webdist/assets/ModelDetailDialog-C-dRTp-J.js +0 -1
- package/dist/webdist/assets/ModelsScreen-JeCIZIdr.js +0 -1
- package/dist/webdist/assets/channel-6NEG4b4S.js +0 -1
- package/dist/webdist/assets/check-GYT4Bnhm.js +0 -1
- package/dist/webdist/assets/chevron-right-BTg0-ylt.js +0 -1
- package/dist/webdist/assets/circle-check-iwGQW5-3.js +0 -1
- package/dist/webdist/assets/circle-x-CDfcuELr.js +0 -1
- package/dist/webdist/assets/classDiagram-4FO5ZUOK-jpAzq28n.js +0 -1
- package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-jpAzq28n.js +0 -1
- package/dist/webdist/assets/common-BstanhE0.js +0 -1
- package/dist/webdist/assets/dialog-Cpwjl0SL.js +0 -1
- package/dist/webdist/assets/index-CJj8sGhF.css +0 -1
- package/dist/webdist/assets/pencil-veezqsms.js +0 -1
- package/dist/webdist/assets/plus-BLEwDzPR.js +0 -1
- package/dist/webdist/assets/refresh-cw-ByeAabM7.js +0 -1
- package/dist/webdist/assets/save-CuyovDOw.js +0 -1
- package/dist/webdist/assets/skeleton-XeFkC2WF.js +0 -1
- package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-C1sHKz6d.js +0 -1
- package/dist/webdist/assets/trash-2-MMGQet84.js +0 -1
package/README.md
CHANGED
|
@@ -136,9 +136,10 @@ the detail:
|
|
|
136
136
|
- **Use the folders you already have.** Point TurboLLM at any directory of GGUFs — your
|
|
137
137
|
existing LM Studio / Ollama / manual downloads — **no re-downloading.** It parses GGUF
|
|
138
138
|
metadata (arch, params, quant, context, vision) for every file.
|
|
139
|
-
- **Browse & download from Hugging Face**, in-app:
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
- **Browse & download from Hugging Face**, in-app: a live, sortable list (trending / downloads
|
|
140
|
+
/ likes / recently updated / newest) alongside a permanent detail pane — pick a quant, read
|
|
141
|
+
the **rendered model card**, and download with **resume + SHA-256 verification**. Gated
|
|
142
|
+
models (Llama, Gemma) work via your own HF token, which **never leaves your machine**.
|
|
142
143
|
- **Import from any URL** — not just Hugging Face. Paste a direct `.gguf` link (model-author
|
|
143
144
|
sites, mirrors, private servers); it disk-space-checks and downloads through the same manager.
|
|
144
145
|
- **Quant recommendation per GPU** and a **VRAM-fit verdict** so you pick a quant that
|
|
@@ -319,7 +320,9 @@ the engine as a swappable component.
|
|
|
319
320
|
support are hidden; ones it adds (e.g. low-bit KV cache, NextN) light up.
|
|
320
321
|
|
|
321
322
|
No prebuilt for your OS? The **build-from-source guide** checks your toolchain (git / CMake /
|
|
322
|
-
CUDA / MSVC), hands you the exact build commands
|
|
323
|
+
CUDA / a compiler — MSVC on Windows, gcc/clang on Linux), hands you the exact build commands
|
|
324
|
+
(or a 1-click **"Build it for me"** on Windows and Linux), then drops you into the folder scan
|
|
325
|
+
above.
|
|
323
326
|
|
|
324
327
|
**Auto-provisioned default.** Don't want to fetch anything? On first run TurboLLM downloads
|
|
325
328
|
the right upstream prebuilt for your GPU automatically — and a **backend picker** lets you
|
package/dist/cli.js
CHANGED
|
@@ -1427,7 +1427,12 @@ function readinessTimeoutMs(kind) {
|
|
|
1427
1427
|
return kind === "vllm" || kind === "sglang" ? 6e5 : 12e4;
|
|
1428
1428
|
}
|
|
1429
1429
|
function pyEngineEnv(kind, dataDir, binPath) {
|
|
1430
|
-
if (kind !== "mlx" && kind !== "vllm" && kind !== "sglang")
|
|
1430
|
+
if (kind !== "mlx" && kind !== "vllm" && kind !== "sglang") {
|
|
1431
|
+
if (process.platform === "win32") return void 0;
|
|
1432
|
+
const dir = dirname2(binPath);
|
|
1433
|
+
const existing = process.env.LD_LIBRARY_PATH;
|
|
1434
|
+
return { ...process.env, LD_LIBRARY_PATH: existing ? `${dir}:${existing}` : dir };
|
|
1435
|
+
}
|
|
1431
1436
|
const hfHome = join9(dataDir, "hf-cache");
|
|
1432
1437
|
const hubCache = join9(hfHome, "hub");
|
|
1433
1438
|
mkdirSync6(hubCache, { recursive: true });
|
|
@@ -3746,7 +3751,15 @@ function resolveProfile(m, sys, saved, overrides, defaults) {
|
|
|
3746
3751
|
// missing some fields) keeps the rest of the defaults instead of going undefined.
|
|
3747
3752
|
gpu: { ...base2.gpu, ...saved?.gpu ?? {}, ...overrides?.gpu ?? {} },
|
|
3748
3753
|
// vllm deep-merged for the same reason — old/partial profiles keep the defaults.
|
|
3749
|
-
vllm: { ...base2.vllm, ...saved?.vllm ?? {}, ...overrides?.vllm ?? {} }
|
|
3754
|
+
vllm: { ...base2.vllm, ...saved?.vllm ?? {}, ...overrides?.vllm ?? {} },
|
|
3755
|
+
// useMmproj has no UI control (only mmprojGpu — GPU-vs-CPU placement — is user-facing;
|
|
3756
|
+
// see ModelDetailDialog's "Vision encoder on GPU" toggle), so there is no legitimate way
|
|
3757
|
+
// for a saved profile or draft override to carry a meaningful `false` here. Forcing it to
|
|
3758
|
+
// track the model's own vision capability makes it self-healing: any profile saved with a
|
|
3759
|
+
// stale/incorrect useMmproj (e.g. auto-tune runs prior to the bench.ts fix that persisted
|
|
3760
|
+
// false) is corrected on the very next resolve, for every user, with no reset/migration
|
|
3761
|
+
// needed and no other tuned setting touched.
|
|
3762
|
+
useMmproj: m.vision
|
|
3750
3763
|
};
|
|
3751
3764
|
}
|
|
3752
3765
|
function profileToArgs(p, m, caps, cores = 0) {
|
|
@@ -4140,6 +4153,28 @@ var HfError = class extends Error {
|
|
|
4140
4153
|
}
|
|
4141
4154
|
code;
|
|
4142
4155
|
};
|
|
4156
|
+
var SORT_PARAM = {
|
|
4157
|
+
trending: "trendingScore",
|
|
4158
|
+
downloads: "downloads",
|
|
4159
|
+
likes: "likes",
|
|
4160
|
+
modified: "lastModified",
|
|
4161
|
+
created: "createdAt"
|
|
4162
|
+
};
|
|
4163
|
+
function libraryFilterFor(engineKind) {
|
|
4164
|
+
if (engineKind === "mlx") return "filter=mlx&";
|
|
4165
|
+
if (engineKind === "vllm") return "";
|
|
4166
|
+
return "filter=gguf&";
|
|
4167
|
+
}
|
|
4168
|
+
function toSearchItem(m) {
|
|
4169
|
+
return {
|
|
4170
|
+
repo: m.id ?? m.modelId ?? "",
|
|
4171
|
+
downloads: m.downloads ?? 0,
|
|
4172
|
+
likes: m.likes ?? 0,
|
|
4173
|
+
updatedAt: m.lastModified ?? m.createdAt ?? "",
|
|
4174
|
+
gated: m.gated === true || m.gated === "auto" || m.gated === "manual",
|
|
4175
|
+
tags: Array.isArray(m.tags) ? m.tags : []
|
|
4176
|
+
};
|
|
4177
|
+
}
|
|
4143
4178
|
var SPLIT_RE2 = /^(.*)-(\d{5})-of-(\d{5})\.gguf$/i;
|
|
4144
4179
|
var HfClient = class {
|
|
4145
4180
|
constructor(tokenFn, version2) {
|
|
@@ -4149,24 +4184,26 @@ var HfClient = class {
|
|
|
4149
4184
|
tokenFn;
|
|
4150
4185
|
version;
|
|
4151
4186
|
cache = /* @__PURE__ */ new Map();
|
|
4152
|
-
/** Search repos (spec 10 §2). Returns up to 30 rows
|
|
4153
|
-
*
|
|
4154
|
-
*
|
|
4155
|
-
*
|
|
4156
|
-
|
|
4157
|
-
async searchModels(query, engineKind) {
|
|
4187
|
+
/** Search repos by text (spec 10 §2). Returns up to 30 rows. `sort` defaults to HF's own
|
|
4188
|
+
* relevance ranking ('best-match' — omits `sort=` entirely, a genuinely different order
|
|
4189
|
+
* from `sort=downloads`, not just an alias for it). Format filter adapts to the active
|
|
4190
|
+
* engine kind (never hardcoded to GGUF) — see {@link libraryFilterFor}. */
|
|
4191
|
+
async searchModels(query, engineKind, sort = "best-match") {
|
|
4158
4192
|
const q = query.trim();
|
|
4159
|
-
const
|
|
4160
|
-
const url = `${BASE}/api/models?search=${encodeURIComponent(q)}${
|
|
4193
|
+
const sortParam = sort === "best-match" ? "" : `sort=${SORT_PARAM[sort]}&direction=-1&`;
|
|
4194
|
+
const url = `${BASE}/api/models?search=${encodeURIComponent(q)}&${libraryFilterFor(engineKind)}${sortParam}limit=30&full=false`;
|
|
4161
4195
|
const raw = await this.getJson(url);
|
|
4162
|
-
return raw.map(
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4196
|
+
return raw.map(toSearchItem);
|
|
4197
|
+
}
|
|
4198
|
+
/** Browse repos with no search term (spec 10 §7 rewrite) — the live equivalent of
|
|
4199
|
+
* https://huggingface.co/models?library=gguf&sort=trending, replacing what used to be a
|
|
4200
|
+
* hardcoded "Featured" list. 'best-match' has no meaning without a query, so it falls
|
|
4201
|
+
* back to 'trending'. Format filter adapts to the active engine kind, same as search. */
|
|
4202
|
+
async browseModels(sort, engineKind, limit = 30) {
|
|
4203
|
+
const effective = sort === "best-match" ? "trending" : sort;
|
|
4204
|
+
const url = `${BASE}/api/models?${libraryFilterFor(engineKind)}sort=${SORT_PARAM[effective]}&direction=-1&limit=${limit}&full=false`;
|
|
4205
|
+
const raw = await this.getJson(url);
|
|
4206
|
+
return raw.map(toSearchItem);
|
|
4170
4207
|
}
|
|
4171
4208
|
/** Repo detail (spec 10 §3): card data + the GGUF file tree, with split parts
|
|
4172
4209
|
* grouped and quant/mmproj detected per file. */
|
|
@@ -4991,7 +5028,7 @@ var BenchRunner = class {
|
|
|
4991
5028
|
const saved = this.store.snapshot().modelProfiles[modelKey];
|
|
4992
5029
|
const defaults = this.store.snapshot().modelDefaults;
|
|
4993
5030
|
const resolved = resolveProfile(entry, sys, saved, base2, defaults);
|
|
4994
|
-
const baseProfile = { ...resolved, speculative: "off", mtpHeadPath: "", draftModelPath: ""
|
|
5031
|
+
const baseProfile = { ...resolved, speculative: "off", mtpHeadPath: "", draftModelPath: "" };
|
|
4995
5032
|
const results = [];
|
|
4996
5033
|
let best = null;
|
|
4997
5034
|
const kvCandidates = pickKvQuants(baseProfile.kvTypeK, caps.kvTypes);
|
|
@@ -9115,6 +9152,36 @@ var ALL = [
|
|
|
9115
9152
|
// install endpoint of its own.
|
|
9116
9153
|
installEndpoint: ""
|
|
9117
9154
|
},
|
|
9155
|
+
{
|
|
9156
|
+
// Upstream publishes NO Linux CUDA prebuilt (download.ts availableBackends() — Linux
|
|
9157
|
+
// NVIDIA users get Vulkan from the main llama.cpp entry above). Now that the guided
|
|
9158
|
+
// build (ADR-100/build-runner.ts) runs on Linux too, offer official llama.cpp + CUDA
|
|
9159
|
+
// there as its own "build from source" card — same guided-build flow as ik_llama.cpp/
|
|
9160
|
+
// TurboQuant below, just pointed at the official repo. Windows/macOS never see this
|
|
9161
|
+
// (platforms:['linux']): Windows already gets a CUDA prebuilt, and macOS has no CUDA.
|
|
9162
|
+
id: "llama.cpp-cuda-linux",
|
|
9163
|
+
name: "llama.cpp (CUDA)",
|
|
9164
|
+
kind: "llama-server",
|
|
9165
|
+
description: "Official llama.cpp compiled with CUDA for NVIDIA GPUs on Linux \u2014 no prebuilt is published upstream, so this uses the guided in-app build.",
|
|
9166
|
+
provision: "github-release",
|
|
9167
|
+
homepage: "https://github.com/ggml-org/llama.cpp",
|
|
9168
|
+
repo: "ggml-org/llama.cpp",
|
|
9169
|
+
platforms: ["linux"],
|
|
9170
|
+
support: "experimental",
|
|
9171
|
+
installEndpoint: "",
|
|
9172
|
+
note: "Builds the official repo with -DGGML_CUDA=ON and bundles its CUDA runtime libraries next to the binary, so it runs standalone. Manages like any other engine afterward (rebuild on a newer commit, disable, delete).",
|
|
9173
|
+
variants: [
|
|
9174
|
+
{
|
|
9175
|
+
id: "llama.cpp-cuda-source",
|
|
9176
|
+
label: "CUDA (NVIDIA) \u2014 build from source",
|
|
9177
|
+
repo: "ggml-org/llama.cpp",
|
|
9178
|
+
requires: { platform: ["linux"], gpuVendor: ["nvidia"] },
|
|
9179
|
+
stability: "experimental",
|
|
9180
|
+
speed: "fast",
|
|
9181
|
+
hasPrebuilt: false
|
|
9182
|
+
}
|
|
9183
|
+
]
|
|
9184
|
+
},
|
|
9118
9185
|
{
|
|
9119
9186
|
id: "vllm",
|
|
9120
9187
|
name: "vLLM",
|
|
@@ -9369,7 +9436,8 @@ var INSTALL_URLS = {
|
|
|
9369
9436
|
cmake: "https://cmake.org/download/",
|
|
9370
9437
|
cuda: "https://developer.nvidia.com/cuda-downloads",
|
|
9371
9438
|
// The "Desktop development with C++" workload from the VS Build Tools installer.
|
|
9372
|
-
msvc: "https://visualstudio.microsoft.com/downloads/"
|
|
9439
|
+
msvc: "https://visualstudio.microsoft.com/downloads/",
|
|
9440
|
+
gcc: "https://gcc.gnu.org/install/"
|
|
9373
9441
|
};
|
|
9374
9442
|
async function runVersion(cmd, args, env) {
|
|
9375
9443
|
const { stdout, stderr } = await execFileP5(cmd, args, {
|
|
@@ -9392,6 +9460,10 @@ function parseNvccVersion(out) {
|
|
|
9392
9460
|
const m = out.match(/release\s+([\d.]+)/i);
|
|
9393
9461
|
return m ? m[1] : "";
|
|
9394
9462
|
}
|
|
9463
|
+
function parseCompilerVersion(out) {
|
|
9464
|
+
const m = out.match(/(?:g\+\+|gcc|clang(?:\+\+)?)[^\d]*(\d+(?:\.\d+)*)/i);
|
|
9465
|
+
return m ? m[1] : "";
|
|
9466
|
+
}
|
|
9395
9467
|
async function checkGit(env) {
|
|
9396
9468
|
let found = false;
|
|
9397
9469
|
let version2;
|
|
@@ -9453,13 +9525,30 @@ async function checkMsvc(env) {
|
|
|
9453
9525
|
installUrl: INSTALL_URLS.msvc
|
|
9454
9526
|
};
|
|
9455
9527
|
}
|
|
9528
|
+
async function checkGcc(env) {
|
|
9529
|
+
let found = false;
|
|
9530
|
+
let version2;
|
|
9531
|
+
try {
|
|
9532
|
+
version2 = parseCompilerVersion(await runVersion("g++", ["--version"], env)) || void 0;
|
|
9533
|
+
found = true;
|
|
9534
|
+
} catch {
|
|
9535
|
+
try {
|
|
9536
|
+
version2 = parseCompilerVersion(await runVersion("clang++", ["--version"], env)) || void 0;
|
|
9537
|
+
found = true;
|
|
9538
|
+
} catch {
|
|
9539
|
+
found = false;
|
|
9540
|
+
}
|
|
9541
|
+
}
|
|
9542
|
+
return { id: "gcc", name: "C++ compiler (g++/clang++)", found, version: version2, installUrl: INSTALL_URLS.gcc };
|
|
9543
|
+
}
|
|
9456
9544
|
async function checkBuildPrereqs(toolchainDirs = []) {
|
|
9457
|
-
|
|
9458
|
-
|
|
9545
|
+
const platform = process.platform;
|
|
9546
|
+
if (platform !== "win32" && platform !== "linux") {
|
|
9547
|
+
return { supported: false, os: "other", tools: [] };
|
|
9459
9548
|
}
|
|
9460
9549
|
const env = buildEnv(toolchainDirs);
|
|
9461
|
-
const tools = await Promise.all([checkGit(env), checkCmake(env), checkCuda(env), checkMsvc(env)]);
|
|
9462
|
-
return { supported: true, tools };
|
|
9550
|
+
const tools = platform === "win32" ? await Promise.all([checkGit(env), checkCmake(env), checkCuda(env), checkMsvc(env)]) : await Promise.all([checkGit(env), checkCmake(env), checkCuda(env), checkGcc(env)]);
|
|
9551
|
+
return { supported: true, os: platform === "win32" ? "windows" : "linux", tools };
|
|
9463
9552
|
}
|
|
9464
9553
|
|
|
9465
9554
|
// src/engines/build-runner.ts
|
|
@@ -9489,8 +9578,9 @@ function sourceBuildDirOf(binPath, enginesRoot) {
|
|
|
9489
9578
|
if (!m) return null;
|
|
9490
9579
|
return join19(enginesRoot, "build", m[1]);
|
|
9491
9580
|
}
|
|
9492
|
-
function pickGenerator(hasNinja) {
|
|
9493
|
-
|
|
9581
|
+
function pickGenerator(hasNinja, isWindows) {
|
|
9582
|
+
if (hasNinja) return "Ninja";
|
|
9583
|
+
return isWindows ? "NMake Makefiles" : "Unix Makefiles";
|
|
9494
9584
|
}
|
|
9495
9585
|
var CMAKE_CONFIGURE_ARGS = ["-DGGML_CUDA=ON", "-DCMAKE_BUILD_TYPE=Release"];
|
|
9496
9586
|
function vcvarsBatch(vcvars, cmakeArgs) {
|
|
@@ -9565,6 +9655,56 @@ function copyCudaRuntimeDlls(env, destDir, log) {
|
|
|
9565
9655
|
if (copied > 0) log(`Bundled ${copied} CUDA runtime DLL(s) next to the binary so the engine is self-contained.`);
|
|
9566
9656
|
return copied;
|
|
9567
9657
|
}
|
|
9658
|
+
var CUDA_RUNTIME_SO_PREFIXES = ["libcudart.so", "libcublas.so", "libcublasLt.so", "libnvrtc.so", "libnvrtc-builtins.so", "libnvJitLink.so"];
|
|
9659
|
+
function cudaSoSourceDirs(env) {
|
|
9660
|
+
const key = Object.keys(env).find((k) => k.toLowerCase() === "path") ?? "PATH";
|
|
9661
|
+
const pathDirs = (env[key] ?? "").split(delimiter2).filter(Boolean);
|
|
9662
|
+
const nvccDir = pathDirs.find((dir) => {
|
|
9663
|
+
try {
|
|
9664
|
+
return existsSync17(join19(dir, "nvcc"));
|
|
9665
|
+
} catch {
|
|
9666
|
+
return false;
|
|
9667
|
+
}
|
|
9668
|
+
});
|
|
9669
|
+
if (!nvccDir) return [];
|
|
9670
|
+
const toolkitRoot = dirname6(nvccDir);
|
|
9671
|
+
return [join19(toolkitRoot, "lib64"), join19(toolkitRoot, "lib"), join19(toolkitRoot, "targets", "x86_64-linux", "lib")].filter((d) => {
|
|
9672
|
+
try {
|
|
9673
|
+
return existsSync17(d);
|
|
9674
|
+
} catch {
|
|
9675
|
+
return false;
|
|
9676
|
+
}
|
|
9677
|
+
});
|
|
9678
|
+
}
|
|
9679
|
+
function copyCudaRuntimeLibs(env, destDir, log) {
|
|
9680
|
+
const sources = cudaSoSourceDirs(env);
|
|
9681
|
+
if (sources.length === 0) {
|
|
9682
|
+
log("Note: could not find the CUDA toolkit shared libraries to bundle \u2014 the engine may need LD_LIBRARY_PATH set to run.");
|
|
9683
|
+
return 0;
|
|
9684
|
+
}
|
|
9685
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9686
|
+
let copied = 0;
|
|
9687
|
+
for (const dir of sources) {
|
|
9688
|
+
let names;
|
|
9689
|
+
try {
|
|
9690
|
+
names = readdirSync5(dir);
|
|
9691
|
+
} catch {
|
|
9692
|
+
continue;
|
|
9693
|
+
}
|
|
9694
|
+
for (const name of names) {
|
|
9695
|
+
if (seen.has(name)) continue;
|
|
9696
|
+
if (!CUDA_RUNTIME_SO_PREFIXES.some((p) => name.startsWith(p))) continue;
|
|
9697
|
+
try {
|
|
9698
|
+
copyFileSync(join19(dir, name), join19(destDir, name));
|
|
9699
|
+
seen.add(name);
|
|
9700
|
+
copied++;
|
|
9701
|
+
} catch {
|
|
9702
|
+
}
|
|
9703
|
+
}
|
|
9704
|
+
}
|
|
9705
|
+
if (copied > 0) log(`Bundled ${copied} CUDA runtime librar${copied === 1 ? "y" : "ies"} next to the binary so the engine is self-contained.`);
|
|
9706
|
+
return copied;
|
|
9707
|
+
}
|
|
9568
9708
|
async function findVcvarsall() {
|
|
9569
9709
|
try {
|
|
9570
9710
|
const programFilesX86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
|
|
@@ -9683,10 +9823,11 @@ function neutralizeGratuitousAsm(srcDir, log) {
|
|
|
9683
9823
|
}
|
|
9684
9824
|
}
|
|
9685
9825
|
async function runBuild(req, hooks, signal) {
|
|
9826
|
+
const isWindows = process.platform === "win32";
|
|
9686
9827
|
const env = { ...buildEnv(req.toolchainDirs), GIT_TERMINAL_PROMPT: "0", GCM_INTERACTIVE: "never" };
|
|
9687
9828
|
hooks.phase("preparing");
|
|
9688
9829
|
const prereqs = await checkBuildPrereqs(req.toolchainDirs);
|
|
9689
|
-
if (!prereqs.supported) throw new Error("In-app build is currently Windows
|
|
9830
|
+
if (!prereqs.supported) throw new Error("In-app build is currently Windows or Linux (with CUDA) only.");
|
|
9690
9831
|
const missing = prereqs.tools.filter((t) => (t.id === "git" || t.id === "cmake" || t.id === "cuda") && !t.found);
|
|
9691
9832
|
if (missing.length > 0) {
|
|
9692
9833
|
const names = missing.map((t) => t.name).join(", ");
|
|
@@ -9694,10 +9835,17 @@ async function runBuild(req, hooks, signal) {
|
|
|
9694
9835
|
`Missing build prerequisite(s): ${names}. Install them, or \u2014 if they live in a conda env / custom path \u2014 add that folder under Build environment so TurboLLM can find them.`
|
|
9695
9836
|
);
|
|
9696
9837
|
}
|
|
9697
|
-
|
|
9698
|
-
if (
|
|
9838
|
+
let vcvars = null;
|
|
9839
|
+
if (isWindows) {
|
|
9840
|
+
vcvars = await findVcvarsall();
|
|
9841
|
+
if (!vcvars) {
|
|
9842
|
+
throw new Error(
|
|
9843
|
+
'Could not locate the Visual Studio C++ build environment (vcvarsall.bat). Install the "Desktop development with C++" workload from the Visual Studio Build Tools.'
|
|
9844
|
+
);
|
|
9845
|
+
}
|
|
9846
|
+
} else if (!prereqs.tools.some((t) => t.id === "gcc" && t.found)) {
|
|
9699
9847
|
throw new Error(
|
|
9700
|
-
|
|
9848
|
+
"Could not find a C++ compiler. Install one (e.g. `sudo apt install build-essential` on Debian/Ubuntu) and retry."
|
|
9701
9849
|
);
|
|
9702
9850
|
}
|
|
9703
9851
|
const buildRoot = join19(req.enginesRoot, "build", buildDirName(req.repoUrl, req.branch));
|
|
@@ -9713,24 +9861,35 @@ async function runBuild(req, hooks, signal) {
|
|
|
9713
9861
|
const commit = (await runStep("git", ["-C", srcDir, "rev-parse", "HEAD"], { env, signal, onLine: () => {
|
|
9714
9862
|
} })).trim();
|
|
9715
9863
|
neutralizeGratuitousAsm(srcDir, hooks.log);
|
|
9716
|
-
const generator = pickGenerator(onPath(env, "ninja.exe"));
|
|
9864
|
+
const generator = pickGenerator(onPath(env, isWindows ? "ninja.exe" : "ninja"), isWindows);
|
|
9717
9865
|
hooks.log(
|
|
9718
|
-
generator === "Ninja" ? "Using the Ninja generator (drives nvcc directly \u2014 no Visual Studio CUDA integration needed)." : "Ninja not found on PATH \u2014 using the NMake generator (works, but single-threaded and slower; add a folder containing ninja.exe under Build environment for much faster builds)."
|
|
9866
|
+
generator === "Ninja" ? "Using the Ninja generator (drives nvcc directly \u2014 no Visual Studio CUDA integration needed)." : isWindows ? "Ninja not found on PATH \u2014 using the NMake generator (works, but single-threaded and slower; add a folder containing ninja.exe under Build environment for much faster builds)." : "Ninja not found on PATH \u2014 using Unix Makefiles (works, but single-threaded and slower; add a folder containing ninja under Build environment for much faster builds)."
|
|
9719
9867
|
);
|
|
9720
9868
|
hooks.phase("configuring");
|
|
9721
|
-
const
|
|
9722
|
-
|
|
9723
|
-
|
|
9869
|
+
const configureArgs = ["-G", generator, "-B", buildSubdir, "-S", srcDir, ...CMAKE_CONFIGURE_ARGS];
|
|
9870
|
+
if (isWindows) {
|
|
9871
|
+
const configureBat = join19(buildRoot, "_tllm_configure.bat");
|
|
9872
|
+
writeFileSync8(configureBat, vcvarsBatch(vcvars, configureArgs));
|
|
9873
|
+
await runStep("cmd.exe", ["/c", configureBat], { cwd: buildRoot, env, signal, onLine: hooks.log });
|
|
9874
|
+
} else {
|
|
9875
|
+
await runStep("cmake", configureArgs, { cwd: buildRoot, env, signal, onLine: hooks.log });
|
|
9876
|
+
}
|
|
9724
9877
|
hooks.phase("compiling");
|
|
9725
|
-
const
|
|
9726
|
-
|
|
9727
|
-
|
|
9878
|
+
const compileArgs = ["--build", buildSubdir, "-j", "--target", "llama-server"];
|
|
9879
|
+
if (isWindows) {
|
|
9880
|
+
const compileBat = join19(buildRoot, "_tllm_build.bat");
|
|
9881
|
+
writeFileSync8(compileBat, vcvarsBatch(vcvars, compileArgs));
|
|
9882
|
+
await runStep("cmd.exe", ["/c", compileBat], { cwd: buildRoot, env, signal, onLine: hooks.log });
|
|
9883
|
+
} else {
|
|
9884
|
+
await runStep("cmake", compileArgs, { cwd: buildRoot, env, signal, onLine: hooks.log });
|
|
9885
|
+
}
|
|
9728
9886
|
hooks.phase("registering");
|
|
9729
9887
|
const binPath = resolveServerBinary(buildSubdir) ?? resolveServerBinary(buildRoot);
|
|
9730
9888
|
if (!binPath) {
|
|
9731
9889
|
throw new Error("Build finished but no llama-server binary was found in the output \u2014 see the log above.");
|
|
9732
9890
|
}
|
|
9733
|
-
copyCudaRuntimeDlls(env, dirname6(binPath), hooks.log);
|
|
9891
|
+
if (isWindows) copyCudaRuntimeDlls(env, dirname6(binPath), hooks.log);
|
|
9892
|
+
else copyCudaRuntimeLibs(env, dirname6(binPath), hooks.log);
|
|
9734
9893
|
return { binPath, commit, buildRoot };
|
|
9735
9894
|
}
|
|
9736
9895
|
|
|
@@ -10345,8 +10504,8 @@ function registerApi(app2, d) {
|
|
|
10345
10504
|
app2.post("/api/v1/build/run", async (c) => {
|
|
10346
10505
|
if (!isLocalRequest(c, d))
|
|
10347
10506
|
return err2(c, 403, "forbidden", "Building an engine is only available on the machine running TurboLLM.");
|
|
10348
|
-
if (process.platform !== "win32")
|
|
10349
|
-
return err2(c, 409, "unsupported_platform", "In-app build is currently Windows
|
|
10507
|
+
if (process.platform !== "win32" && process.platform !== "linux")
|
|
10508
|
+
return err2(c, 409, "unsupported_platform", "In-app build is currently Windows or Linux (with CUDA) only.");
|
|
10350
10509
|
const b = await body2(c);
|
|
10351
10510
|
const repoUrl = (b.repoUrl ?? "").trim();
|
|
10352
10511
|
if (!/^https?:\/\//i.test(repoUrl))
|
|
@@ -11262,11 +11421,13 @@ function registerApi(app2, d) {
|
|
|
11262
11421
|
});
|
|
11263
11422
|
return c.json(modelDirsPayload(d));
|
|
11264
11423
|
});
|
|
11424
|
+
const SORT_OPTIONS = ["best-match", "trending", "downloads", "likes", "modified", "created"];
|
|
11265
11425
|
app2.get("/api/v1/hf/search", async (c) => {
|
|
11266
11426
|
const q = (c.req.query("q") ?? "").trim();
|
|
11267
|
-
|
|
11427
|
+
const rawSort = c.req.query("sort") ?? "";
|
|
11428
|
+
const sort = SORT_OPTIONS.includes(rawSort) ? rawSort : "best-match";
|
|
11268
11429
|
try {
|
|
11269
|
-
const results = await d.hf.searchModels(q, d.registry.active()?.kind);
|
|
11430
|
+
const results = q ? await d.hf.searchModels(q, d.registry.active()?.kind, sort) : await d.hf.browseModels(sort, d.registry.active()?.kind);
|
|
11270
11431
|
const withLocal = results.map((r) => ({ ...r, localCount: localCountFor(d, r.repo) }));
|
|
11271
11432
|
return c.json({ results: withLocal });
|
|
11272
11433
|
} catch (e) {
|
|
@@ -12068,9 +12229,10 @@ async function* streamToAnthropic(oaiStream, modelName, msgId, onUsage, onLive)
|
|
|
12068
12229
|
yield cbStop(blockIdx);
|
|
12069
12230
|
blockIdx++;
|
|
12070
12231
|
}
|
|
12232
|
+
const nonCachedInput = Math.max(0, inputTokens - cacheReadTokens);
|
|
12071
12233
|
yield sse("message_delta", {
|
|
12072
12234
|
delta: { stop_reason: stopReason, stop_sequence: null },
|
|
12073
|
-
usage: { input_tokens:
|
|
12235
|
+
usage: { input_tokens: nonCachedInput, output_tokens: outputTokens, cache_read_input_tokens: cacheReadTokens }
|
|
12074
12236
|
});
|
|
12075
12237
|
yield sse("message_stop", {});
|
|
12076
12238
|
if (onUsage) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as e}from"./radix-
|
|
1
|
+
import{j as e}from"./radix-9WP-OkMY.js";import{r as u}from"./vendor-W5GIuFcv.js";import{a as w,d as k,A as T,u as v,L as h,e as S,c as b,f as C,g as q,X as A}from"./index-K2ZQBdky.js";import{P as N}from"./plus-mSm32jpN.js";import{C as y}from"./circle-x-koFsrlGA.js";import{C as O}from"./circle-check-C4aACGyb.js";import{W as E}from"./wrench-Ceqe74n2.js";const _=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}]],D=w("circle-dot",_);const L=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 6v6l4 2",key:"mmk7yg"}]],P=w("clock",L),p={all:["agent-runs"],list:()=>[...p.all,"list"],detail:t=>[...p.all,"detail",t]};async function g(t,a){const l={Accept:"application/json",...k(),...a?.headers??{}},i=await fetch(t,{...a,headers:l});if(i.status===204)return;const r=await i.text(),o=r?JSON.parse(r):void 0;if(!i.ok){const d=o;throw new T(d?.error?.code??"http_error",d?.error?.message??`Request failed with status ${i.status}.`,i.status)}return o}async function $(){return g("/api/v1/agents/runs")}async function I(t){return g(`/api/v1/agents/runs/${t}`)}async function Q(t){return g("/api/v1/agents/runs",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}async function K(t){await g(`/api/v1/agents/runs/${t}`,{method:"DELETE"})}async function*F(t,a=0,l){const i=`/api/v1/agents/runs/${t}/stream?fromSeq=${a}`,r=await fetch(i,{headers:{Accept:"text/event-stream",...k()},signal:l});if(!r.ok||!r.body)throw new Error(`Stream error: ${r.status}`);const o=r.body.getReader(),d=new TextDecoder;let m="";try{for(;;){const{done:s,value:x}=await o.read();if(s)break;m+=d.decode(x,{stream:!0});const c=m.split(`
|
|
2
2
|
`);m=c.pop()??"";let n="message";for(const f of c){if(f.startsWith("event: ")){n=f.slice(7).trim();continue}if(f.startsWith("data: ")){const j=f.slice(6).trim();if(j==="[DONE]")return;try{const R=JSON.parse(j);if(yield{event:n,data:R},n==="done"||n==="error")return}catch{}n="message"}}}}finally{o.cancel()}}const J={queued:e.jsx(P,{size:12}),running:e.jsx(h,{size:12,className:"animate-spin"}),done:e.jsx(O,{size:12}),failed:e.jsx(y,{size:12}),cancelled:e.jsx(y,{size:12}),interrupted:e.jsx(y,{size:12})},M={queued:"text-muted",running:"text-accent",done:"text-green-500",failed:"text-red-500",cancelled:"text-muted",interrupted:"text-orange-500"};function z({status:t}){return e.jsxs("span",{className:b("flex items-center gap-1 text-[11px] capitalize",M[t]),children:[J[t],t]})}function W(t){const a=Date.now()-new Date(t).getTime();return a<6e4?"just now":a<36e5?`${Math.floor(a/6e4)}m ago`:a<864e5?`${Math.floor(a/36e5)}h ago`:new Date(t).toLocaleDateString()}const U=[{id:"web_search",label:"Web search",hint:"Search the web (needs a provider configured in Settings)"},{id:"fetch_url",label:"Fetch URL",hint:"Read the contents of a web page"},{id:"run_code",label:"Run code",hint:"Execute JS in a sandbox — no mid-run confirmation, opt in only if you trust the task"}];function B({onClose:t,onCreated:a}){const[l,i]=u.useState(""),[r,o]=u.useState(""),[d,m]=u.useState({web_search:!0,fetch_url:!0,run_code:!1}),s=C(),x=n=>m(f=>({...f,[n]:!f[n]})),c=q({mutationFn:()=>Q({title:l.slice(0,60)||"Agent run",systemPrompt:r||void 0,userMessage:l,allowedTools:Object.entries(d).filter(([,n])=>n).map(([n])=>n)}),onSuccess:n=>{s.invalidateQueries({queryKey:p.list()}),a(n.id),t()}});return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/40",onClick:t,children:e.jsxs("div",{className:"w-full max-w-lg rounded-xl border border-border bg-panel p-5 shadow-xl",onClick:n=>n.stopPropagation(),children:[e.jsxs("div",{className:"mb-4 flex items-center justify-between",children:[e.jsx("h2",{className:"text-[15px] font-semibold",children:"New agent run"}),e.jsx("button",{type:"button",onClick:t,className:"text-faint hover:text-ink",children:e.jsx(A,{size:16})})]}),e.jsx("label",{className:"mb-1 block text-[12px] text-muted",children:"Task"}),e.jsx("textarea",{autoFocus:!0,value:l,onChange:n=>i(n.target.value),placeholder:"Describe what the agent should do…",rows:4,className:"mb-3 w-full resize-none rounded-lg border border-border bg-input px-3 py-2 text-[13px] text-ink placeholder:text-faint focus:border-accent focus:outline-none"}),e.jsxs("label",{className:"mb-1 block text-[12px] text-muted",children:["System prompt ",e.jsx("span",{className:"text-faint",children:"(optional)"})]}),e.jsx("textarea",{value:r,onChange:n=>o(n.target.value),placeholder:"You are a helpful assistant…",rows:2,className:"mb-4 w-full resize-none rounded-lg border border-border bg-input px-3 py-2 text-[13px] text-ink placeholder:text-faint focus:border-accent focus:outline-none"}),e.jsx("label",{className:"mb-1.5 block text-[12px] text-muted",children:"Tools"}),e.jsx("div",{className:"mb-4 space-y-1.5",children:U.map(n=>e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 rounded-lg border border-border px-2.5 py-2 hover:bg-panel-2",children:[e.jsx("input",{type:"checkbox",checked:d[n.id],onChange:()=>x(n.id),className:"mt-0.5 accent-[var(--accent)]"}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-[13px] font-medium text-ink",children:n.label}),e.jsx("span",{className:"block text-[11px] leading-snug text-faint",children:n.hint})]})]},n.id))}),e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx("button",{type:"button",onClick:t,className:"rounded-lg px-3 py-1.5 text-[13px] text-muted hover:text-ink",children:"Cancel"}),e.jsxs("button",{type:"button",disabled:!l.trim()||c.isPending,onClick:()=>c.mutate(),className:"flex items-center gap-1.5 rounded-lg bg-accent px-3 py-1.5 text-[13px] font-medium text-white disabled:opacity-50",children:[c.isPending?e.jsx(h,{size:13,className:"animate-spin"}):e.jsx(S,{size:13}),"Run agent"]})]}),c.isError&&e.jsx("p",{className:"mt-2 text-[12px]",style:{color:"var(--err)"},children:c.error.message})]})})}function X({call:t}){const[a,l]=u.useState(!1),i=typeof t.args?.query=="string"?t.args.query:typeof t.args?.url=="string"?t.args.url:JSON.stringify(t.args??{});return e.jsxs("div",{className:"w-full max-w-[85%] rounded-lg border border-border bg-panel px-2.5 py-1.5 text-[12px]",children:[e.jsxs("button",{type:"button",onClick:()=>l(r=>!r),className:"flex w-full items-center gap-1.5 text-left text-muted hover:text-ink",children:[e.jsx(E,{size:12,className:"shrink-0 text-accent"}),e.jsx("span",{className:"font-medium text-ink",children:t.name}),e.jsx("span",{className:"truncate text-faint",children:i})]}),a&&e.jsx("pre",{className:"mt-1.5 max-h-48 overflow-auto whitespace-pre-wrap break-words rounded bg-panel-2 p-2 text-[11px] text-muted",children:t.result})]})}function H({run:t}){const a=C(),l=u.useRef(null),[i,r]=u.useState(""),o=u.useRef(null),d=q({mutationFn:()=>K(t.id),onSuccess:()=>{a.invalidateQueries({queryKey:p.list()})}});u.useEffect(()=>{if(t.status!=="running"&&t.status!=="queued")return;const s=new AbortController;l.current=s;let x="";return(async()=>{try{for await(const c of F(t.id,0,s.signal))if(c.event==="delta")x+=c.data.delta,r(x);else if(c.event==="done"||c.event==="error"){r(""),a.invalidateQueries({queryKey:p.detail(t.id)}),a.invalidateQueries({queryKey:p.list()});break}}catch{}})(),()=>{s.abort(),l.current=null}},[t.id,t.status,a]),u.useEffect(()=>{o.current?.scrollIntoView({behavior:"smooth"})},[i,t.messages?.length]);const m=t.messages??[];return e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-border px-4 py-2.5",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[14px] font-medium text-ink",children:t.title}),e.jsx(z,{status:t.status})]}),(t.status==="running"||t.status==="queued")&&e.jsx("button",{type:"button",onClick:()=>d.mutate(),className:"rounded-lg border border-border px-3 py-1 text-[12px] text-muted transition-colors hover:border-red-400 hover:text-red-500",children:d.isPending?e.jsx(h,{size:12,className:"inline animate-spin"}):"Cancel"})]}),e.jsxs("div",{className:"flex-1 space-y-3 overflow-y-auto p-4",children:[m.map(s=>e.jsxs("div",{className:b("flex flex-col gap-1.5",s.role==="user"?"items-end":"items-start"),children:[s.toolCalls?.map(x=>e.jsx(X,{call:x},x.id)),(s.content||s.role==="user"||t.status==="running")&&e.jsx("div",{className:b("max-w-[85%] rounded-xl px-3 py-2 text-[13px] leading-relaxed",s.role==="user"?"bg-accent/15 text-ink":"bg-panel-2 text-ink"),children:e.jsx("p",{className:"whitespace-pre-wrap break-words",children:s.content||(s.role==="assistant"&&t.status==="running"?"…":"")})})]},s.id)),i&&e.jsx("div",{className:"flex gap-2",children:e.jsx("div",{className:"max-w-[85%] rounded-xl bg-panel-2 px-3 py-2 text-[13px] leading-relaxed text-ink",children:e.jsx("p",{className:"whitespace-pre-wrap break-words",children:i})})}),t.error&&e.jsxs("div",{className:"rounded-lg bg-red-500/10 px-3 py-2 text-[12px] text-red-500",children:["Error: ",t.error]}),e.jsx("div",{ref:o})]})]})}function ne(){const[t,a]=u.useState(null),[l,i]=u.useState(!1),r=v({queryKey:p.list(),queryFn:$,refetchInterval:s=>(s.state.data??[]).some(n=>n.status==="queued"||n.status==="running")?3e3:!1}),o=v({queryKey:p.detail(t??""),queryFn:()=>I(t),enabled:!!t,refetchInterval:s=>{const x=s.state.data;return x?.status==="queued"||x?.status==="running"?5e3:!1}}),d=r.data??[],m=o.data;return e.jsxs("div",{className:"flex h-full",children:[e.jsxs("div",{className:"flex w-64 shrink-0 flex-col border-r border-border",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-border px-3 py-2.5",children:[e.jsx("span",{className:"text-[13px] font-semibold text-ink",children:"Agents"}),e.jsxs("button",{type:"button",title:"New agent run",onClick:()=>i(!0),className:"flex items-center gap-1 rounded-lg bg-accent px-2 py-1 text-[11px] font-medium text-white transition-opacity hover:opacity-90",children:[e.jsx(N,{size:11})," New"]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[r.isLoading&&e.jsx("div",{className:"flex h-20 items-center justify-center",children:e.jsx(h,{size:16,className:"animate-spin text-faint"})}),d.length===0&&!r.isLoading&&e.jsxs("div",{className:"px-4 py-8 text-center",children:[e.jsx(S,{size:28,className:"mx-auto mb-2 text-faint"}),e.jsx("p",{className:"text-[12px] text-muted",children:"No agent runs yet."}),e.jsx("p",{className:"mt-0.5 text-[11px] text-faint",children:"Click “New” to start one."})]}),d.map(s=>e.jsxs("button",{type:"button",onClick:()=>a(s.id),className:b("w-full border-b border-border px-3 py-2.5 text-left transition-colors hover:bg-panel-2",t===s.id&&"bg-panel-2"),children:[e.jsx("p",{className:"mb-0.5 truncate text-[13px] font-medium text-ink",children:s.title}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(z,{status:s.status}),e.jsx("span",{className:"text-[10px] text-faint",children:W(s.createdAt)})]})]},s.id))]})]}),e.jsx("div",{className:"flex min-w-0 flex-1 flex-col",children:t?o.isLoading?e.jsx("div",{className:"flex h-full items-center justify-center",children:e.jsx(h,{size:20,className:"animate-spin text-faint"})}):m?e.jsx(H,{run:m}):null:e.jsxs("div",{className:"flex h-full flex-col items-center justify-center text-center",children:[e.jsx(D,{size:32,className:"mb-3 text-faint"}),e.jsx("p",{className:"text-[14px] font-medium text-ink",children:"Select a run"}),e.jsx("p",{className:"mt-1 text-[12px] text-muted",children:"or create a new agent run to get started"}),e.jsxs("button",{type:"button",onClick:()=>i(!0),className:"mt-4 flex items-center gap-1.5 rounded-lg bg-accent px-3 py-1.5 text-[13px] font-medium text-white hover:opacity-90",children:[e.jsx(N,{size:13})," New agent run"]})]})}),l&&e.jsx(B,{onClose:()=>i(!1),onCreated:s=>{a(s),r.refetch()}})]})}export{ne as AgentsScreen};
|