turbollm 1.12.3 → 1.12.4
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 +4 -0
- package/dist/cli.js +118 -33
- package/dist/webdist/assets/{AgentEditPage-CE4lxy1g.js → AgentEditPage-CdHC3qGU.js} +1 -1
- package/dist/webdist/assets/{ChatScreen-BWZFrPkm.js → ChatScreen-CZ1jxorL.js} +1 -1
- package/dist/webdist/assets/{CodeComposer-53_HhRBK.js → CodeComposer-DVq1Owms.js} +1 -1
- package/dist/webdist/assets/{CodeHomeScreen-D1alRzQa.js → CodeHomeScreen-BcXb_FrC.js} +1 -1
- package/dist/webdist/assets/{CodeSessionScreen-p9tPPoVe.js → CodeSessionScreen-jIq1R-Be.js} +1 -1
- package/dist/webdist/assets/{CustomizeScreen-CebO4Kif.js → CustomizeScreen-1WEWeS2o.js} +1 -1
- package/dist/webdist/assets/{DeveloperScreen-CI5WYmmt.js → DeveloperScreen-CRd6LlbR.js} +1 -1
- package/dist/webdist/assets/EnginesScreen-DMpTol2j.js +8 -0
- package/dist/webdist/assets/{ModelDetailDialog-CriVmDMu.js → ModelDetailDialog-PesH4Lvj.js} +1 -1
- package/dist/webdist/assets/{ModelLoadMenu-yzCvMZFM.js → ModelLoadMenu-Kyk_PCm1.js} +1 -1
- package/dist/webdist/assets/{ModelsScreen-BLosszVi.js → ModelsScreen-BrWmAI3S.js} +1 -1
- package/dist/webdist/assets/{OnboardingScreen-1Eh4MMsz.js → OnboardingScreen-BqsISOAx.js} +1 -1
- package/dist/webdist/assets/{RoutineEditPage-BBptNINr.js → RoutineEditPage-DYyP5bcn.js} +1 -1
- package/dist/webdist/assets/{RoutinesPanel-DA1e-FlT.js → RoutinesPanel-CWNAB6XV.js} +1 -1
- package/dist/webdist/assets/SettingsScreen-BolAJ4j1.js +2 -0
- package/dist/webdist/assets/{SidebarResizeHandle-BS9E0P8t.js → SidebarResizeHandle-CvNSmidY.js} +1 -1
- package/dist/webdist/assets/{SkillEditPage-CswptEm0.js → SkillEditPage-Ce5jCKvK.js} +1 -1
- package/dist/webdist/assets/{TokensScreen-DqX7R08T.js → TokensScreen-i81av7bn.js} +1 -1
- package/dist/webdist/assets/{ToolApprovalBar-Ctxtcdk_.js → ToolApprovalBar-Dos3RNn4.js} +3 -3
- package/dist/webdist/assets/WorkspaceScreen-C8o9JVxH.js +1 -0
- package/dist/webdist/assets/{abnfDiagram-N423BO3Z-wYX3XzEU.js → abnfDiagram-N423BO3Z-BIBCjVzE.js} +1 -1
- package/dist/webdist/assets/{agent-api-CNgD3AG5.js → agent-api-DZ1WgRmZ.js} +1 -1
- package/dist/webdist/assets/{alert-dialog-DtFUjjf-.js → alert-dialog-BBENYlWb.js} +1 -1
- package/dist/webdist/assets/{arc-CAVYLnrV.js → arc-zf5dBjx2.js} +1 -1
- package/dist/webdist/assets/{architectureDiagram-T3A2C74G-B-ep8-Wc.js → architectureDiagram-T3A2C74G-DnThYv0T.js} +1 -1
- package/dist/webdist/assets/{arrow-left-BUyjb-eA.js → arrow-left-D_WlfmJO.js} +1 -1
- package/dist/webdist/assets/{badge-fTl4lUnO.js → badge-DIC-2P-e.js} +1 -1
- package/dist/webdist/assets/{blockDiagram-VBNYF7ZC-C_yOS3Cn.js → blockDiagram-VBNYF7ZC-BNrOo7My.js} +1 -1
- package/dist/webdist/assets/{bot-DjnxX6n5.js → bot-D4oi44Nz.js} +1 -1
- package/dist/webdist/assets/{c4Diagram-5PPSVZJV-yQy5pOFU.js → c4Diagram-5PPSVZJV-CGWOFS9g.js} +1 -1
- package/dist/webdist/assets/channel-CAqIqLwF.js +1 -0
- package/dist/webdist/assets/{chat-api-Cm7puych.js → chat-api-fC2sf7Mj.js} +1 -1
- package/dist/webdist/assets/{chat-queries-flf3EhI8.js → chat-queries-qpktuERN.js} +1 -1
- package/dist/webdist/assets/{chevron-down-BMj_J4Z6.js → chevron-down-ChtnXh37.js} +1 -1
- package/dist/webdist/assets/{chevron-left-CcApbuPp.js → chevron-left-DXZuhCTN.js} +1 -1
- package/dist/webdist/assets/{chevron-right-DcT_N4lU.js → chevron-right-BSHofHoG.js} +1 -1
- package/dist/webdist/assets/{chunk-2GRJ4B5K-DGiFq5-O.js → chunk-2GRJ4B5K-BToCFJph.js} +1 -1
- package/dist/webdist/assets/{chunk-2Q5K7J3B-D3EdskXA.js → chunk-2Q5K7J3B-C2E2U_Wt.js} +1 -1
- package/dist/webdist/assets/{chunk-5RXB4S5H-BidckIKz.js → chunk-5RXB4S5H-Bt8_ImVV.js} +1 -1
- package/dist/webdist/assets/{chunk-5VM5RSS4-DOxfljEH.js → chunk-5VM5RSS4-BEfsXc2S.js} +1 -1
- package/dist/webdist/assets/{chunk-6Q2QTUOP-DAYq99TW.js → chunk-6Q2QTUOP-DHZTU_LD.js} +1 -1
- package/dist/webdist/assets/{chunk-GF5L2VYU-CRAn0Eq3.js → chunk-GF5L2VYU-DEUAN61L.js} +1 -1
- package/dist/webdist/assets/{chunk-JWPE2WC7-DHQMj5yT.js → chunk-JWPE2WC7-Dw2aRPzh.js} +1 -1
- package/dist/webdist/assets/{chunk-KBJHAD2P-CVzZvxJP.js → chunk-KBJHAD2P-Cxgw5S4G.js} +1 -1
- package/dist/webdist/assets/{chunk-RYQCIY6F-BmrJERxa.js → chunk-RYQCIY6F-Bv3rJwBY.js} +1 -1
- package/dist/webdist/assets/{chunk-XXDRQBXY-DEZG0EV3.js → chunk-XXDRQBXY-DOGwIQ-5.js} +1 -1
- package/dist/webdist/assets/{circle-check-BNjlHnHh.js → circle-check-PwESlMlu.js} +1 -1
- package/dist/webdist/assets/{circle-x-DV1nLTK3.js → circle-x-Cta68_gk.js} +1 -1
- package/dist/webdist/assets/classDiagram-JCYQIIEL-D8UwXHdu.js +1 -0
- package/dist/webdist/assets/classDiagram-v2-OCEON4UE-D8UwXHdu.js +1 -0
- package/dist/webdist/assets/{common-CaQP3vin.js → common-CJJrr1d6.js} +1 -1
- package/dist/webdist/assets/{cose-bilkent-JH36ORCC-Bq5B3ICk.js → cose-bilkent-JH36ORCC-DpQxukTC.js} +1 -1
- package/dist/webdist/assets/{cynefin-VYW2F7L2-DZle68dV.js → cynefin-VYW2F7L2-C4ao01h7.js} +1 -1
- package/dist/webdist/assets/{cynefinDiagram-MW4NZA55-CfM3dACl.js → cynefinDiagram-MW4NZA55-DkkKzRZl.js} +1 -1
- package/dist/webdist/assets/{dagre-VZM6K2ZE-DnxnfNsU.js → dagre-VZM6K2ZE-vSbclD6H.js} +1 -1
- package/dist/webdist/assets/{diagram-7IWD3JNH-j2-QzJMm.js → diagram-7IWD3JNH-BWofSihb.js} +1 -1
- package/dist/webdist/assets/{diagram-B4RE2ZJO-b38UCmx1.js → diagram-B4RE2ZJO-BF6NzW6i.js} +1 -1
- package/dist/webdist/assets/{diagram-LBJQPF4R-CdkW-WA-.js → diagram-LBJQPF4R-xr0rYyvY.js} +1 -1
- package/dist/webdist/assets/{diagram-Q27KOJAE-B0R9y_o4.js → diagram-Q27KOJAE-DY2EOYz8.js} +1 -1
- package/dist/webdist/assets/{diagram-UB23O5K3-ChZYNuxT.js → diagram-UB23O5K3-zrZF27ik.js} +1 -1
- package/dist/webdist/assets/{dropdown-menu-CzL84hjo.js → dropdown-menu-C7SX-XbP.js} +1 -1
- package/dist/webdist/assets/{ebnfDiagram-BXEA7PRR-Df2n-V3W.js → ebnfDiagram-BXEA7PRR-Cdqx9C3b.js} +1 -1
- package/dist/webdist/assets/{erDiagram-JOGREHBK-CJwWpaRB.js → erDiagram-JOGREHBK-DNOLDkDZ.js} +1 -1
- package/dist/webdist/assets/{external-link-Bqgcz-GW.js → external-link-MZUdNZic.js} +1 -1
- package/dist/webdist/assets/{file-text-CAqmQYG6.js → file-text-DtzC6GM1.js} +1 -1
- package/dist/webdist/assets/{flowDiagram-UKHOOZJN-Bd94ldad.js → flowDiagram-UKHOOZJN-ChbrkceS.js} +1 -1
- package/dist/webdist/assets/{folder-input-dy5PCMy4.js → folder-input-Czg0RwSd.js} +1 -1
- package/dist/webdist/assets/{folder-plus-YR4wA8PT.js → folder-plus-BndMFsaS.js} +1 -1
- package/dist/webdist/assets/{ganttDiagram-PKOTCBZU-DYeYOb2A.js → ganttDiagram-PKOTCBZU-BMW0DvB1.js} +1 -1
- package/dist/webdist/assets/{git-branch-BZWrq5B1.js → git-branch-CZQe8XJB.js} +1 -1
- package/dist/webdist/assets/{gitGraphDiagram-DS77QQ5N-CvZdup4u.js → gitGraphDiagram-DS77QQ5N-D1Wh4tzk.js} +1 -1
- package/dist/webdist/assets/{index-4QuGA7c6.js → index-6s1TR3Mg.js} +9 -9
- package/dist/webdist/assets/{infoDiagram-6WML65LV-jwAgJ0e9.js → infoDiagram-6WML65LV-VbzCs17L.js} +1 -1
- package/dist/webdist/assets/{ishikawaDiagram-WSZJBQD7-BEdaiV3h.js → ishikawaDiagram-WSZJBQD7-NXmrNE4M.js} +1 -1
- package/dist/webdist/assets/{journeyDiagram-NVQOT4AX-CdVLYVhh.js → journeyDiagram-NVQOT4AX-CT3eftG5.js} +1 -1
- package/dist/webdist/assets/{kanban-definition-27J2QSJJ-DT-DsTQr.js → kanban-definition-27J2QSJJ-CMLz2XNX.js} +1 -1
- package/dist/webdist/assets/{linear-BrxtevgR.js → linear-C8w6e5pr.js} +1 -1
- package/dist/webdist/assets/{link-queries-C3HTfth1.js → link-queries-CM-8kcuV.js} +1 -1
- package/dist/webdist/assets/{lock-zeDOBniP.js → lock-CtCTK4fi.js} +1 -1
- package/dist/webdist/assets/{mermaid.core-B9NxJSlE.js → mermaid.core-Dg3gzQXp.js} +4 -4
- package/dist/webdist/assets/{mindmap-definition-FAOFIHXS-BPQfqoP2.js → mindmap-definition-FAOFIHXS-CFA-t8Pv.js} +1 -1
- package/dist/webdist/assets/{monitor-BDzPa5YN.js → monitor-BnDu1JJe.js} +1 -1
- package/dist/webdist/assets/{pegDiagram-VL7TDLO6-CR4mTeP-.js → pegDiagram-VL7TDLO6-Cvrk_yjS.js} +1 -1
- package/dist/webdist/assets/{pencil-BtEhdGP-.js → pencil-CFuABcQS.js} +1 -1
- package/dist/webdist/assets/{personas-BK5wc_P3.js → personas-CdldzkmX.js} +1 -1
- package/dist/webdist/assets/{pieDiagram-7S7Q4E2Y-DPD5scZh.js → pieDiagram-7S7Q4E2Y-DspIfgvH.js} +1 -1
- package/dist/webdist/assets/{plus-D3Tv9cim.js → plus-BPDwshww.js} +1 -1
- package/dist/webdist/assets/{quadrantDiagram-CIZ2JOQS-DsESOJc6.js → quadrantDiagram-CIZ2JOQS-DlU5s8vy.js} +1 -1
- package/dist/webdist/assets/{railroadDiagram-AXF67PYL-U15r6DjT.js → railroadDiagram-AXF67PYL-CNaDw4Jn.js} +1 -1
- package/dist/webdist/assets/{refresh-cw-BemgDv3Q.js → refresh-cw-D8RZp8yK.js} +1 -1
- package/dist/webdist/assets/{remote-failure-Ddau3S9z.js → remote-failure-DrcbWSOc.js} +1 -1
- package/dist/webdist/assets/{requirementDiagram-LRYGKXZP-DDeRZQ__.js → requirementDiagram-LRYGKXZP-DR31pxOu.js} +1 -1
- package/dist/webdist/assets/{rocket-Uil5x1E9.js → rocket-CrQF04Ko.js} +1 -1
- package/dist/webdist/assets/{rotate-ccw-Bar4GXPb.js → rotate-ccw-Ao2f14qP.js} +1 -1
- package/dist/webdist/assets/{sankeyDiagram-W5VNT64P-BMTSd4xI.js → sankeyDiagram-W5VNT64P-CqFjXMeB.js} +1 -1
- package/dist/webdist/assets/{sequenceDiagram-SI44F4Z6-DdMCm5jm.js → sequenceDiagram-SI44F4Z6-Bxu2Mhjb.js} +1 -1
- package/dist/webdist/assets/{sizeCapture-X5ZJPWSS-2IYIZrFi.js → sizeCapture-X5ZJPWSS-Clu9P7P2.js} +1 -1
- package/dist/webdist/assets/{skeleton-MlF2228j.js → skeleton-WkEOMnX2.js} +1 -1
- package/dist/webdist/assets/{sliders-horizontal-DFahpoGu.js → sliders-horizontal-BMPLOqS8.js} +1 -1
- package/dist/webdist/assets/{sparkles-BYaOifNR.js → sparkles-DUmKhFVc.js} +1 -1
- package/dist/webdist/assets/{star-HYST5DWB.js → star-CHanzKtJ.js} +1 -1
- package/dist/webdist/assets/{stateDiagram-OKZ733FA-DgPdyEyJ.js → stateDiagram-OKZ733FA-CleTNrVM.js} +1 -1
- package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-BCsf9FS8.js +1 -0
- package/dist/webdist/assets/{swimlanes-SLNWSIFB-CxbQXrF7.js → swimlanes-SLNWSIFB-BOkmWRMZ.js} +2 -2
- package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-Da27rzM3.js +8 -0
- package/dist/webdist/assets/{switch-VYcKekwB.js → switch-DOWmW_HN.js} +1 -1
- package/dist/webdist/assets/{terminal-BXEMsYi1.js → terminal-Dsti4UEP.js} +1 -1
- package/dist/webdist/assets/{timeline-definition-Z64GVDOM-BN25-Wyy.js → timeline-definition-Z64GVDOM-DldeIhgX.js} +1 -1
- package/dist/webdist/assets/{trash-2-BNwq5WtQ.js → trash-2-BS-v4vnu.js} +1 -1
- package/dist/webdist/assets/{triangle-alert-DTK5P852.js → triangle-alert-CbnEc6nz.js} +1 -1
- package/dist/webdist/assets/{vennDiagram-T6HMQDX7-Cmn8MOEp.js → vennDiagram-T6HMQDX7-BfEil2zW.js} +1 -1
- package/dist/webdist/assets/{wardleyDiagram-T6FBY63Y-AS3obg9i.js → wardleyDiagram-T6FBY63Y-C5f7dizL.js} +1 -1
- package/dist/webdist/assets/{wrench-B5967UE3.js → wrench-RrT170se.js} +1 -1
- package/dist/webdist/assets/{xychartDiagram-ELKLHX3M-puQ_9bb2.js → xychartDiagram-ELKLHX3M-C0Caadm6.js} +1 -1
- package/dist/webdist/index.html +1 -1
- package/package.json +1 -1
- package/dist/webdist/assets/EnginesScreen-DjzBXrbU.js +0 -8
- package/dist/webdist/assets/SettingsScreen-CE211J25.js +0 -2
- package/dist/webdist/assets/WorkspaceScreen-82kXmjux.js +0 -1
- package/dist/webdist/assets/channel-CMLjxq8A.js +0 -1
- package/dist/webdist/assets/classDiagram-JCYQIIEL-BaxaaW6h.js +0 -1
- package/dist/webdist/assets/classDiagram-v2-OCEON4UE-BaxaaW6h.js +0 -1
- package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-Bi2zf8yv.js +0 -1
- package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-DvkgZzhL.js +0 -8
package/README.md
CHANGED
|
@@ -507,6 +507,10 @@ above.
|
|
|
507
507
|
llama.cpp-compatible fork's git URL (+ optional branch, defaults to the repo's own default) and
|
|
508
508
|
build it in-app with the same 1-click flow, no separate "point at a folder" step needed.
|
|
509
509
|
|
|
510
|
+
Branch pickers and engine update checks both read GitHub's API, which allows 60 anonymous
|
|
511
|
+
requests an hour. If you run into that ceiling, add a **GitHub token** in Settings → Models &
|
|
512
|
+
loading to raise it to 5,000/hour — it is write-only and never leaves your machine.
|
|
513
|
+
|
|
510
514
|
**Auto-provisioned default.** Don't want to fetch anything? On first run TurboLLM downloads
|
|
511
515
|
the right upstream prebuilt for your GPU automatically — and a **backend picker** lets you
|
|
512
516
|
switch between CUDA / ROCm / Metal / SYCL / Vulkan / CPU at any time (it downloads the variant
|
package/dist/cli.js
CHANGED
|
@@ -130,6 +130,7 @@ function defaultConfig() {
|
|
|
130
130
|
selectedRemoteModel: "",
|
|
131
131
|
autoLoadOnStart: false,
|
|
132
132
|
hf: { token: "" },
|
|
133
|
+
gh: { token: "" },
|
|
133
134
|
modelDefaults: { ctx: 8192, ngl: 99, imageMaxTokens: 0, maxTokens: 0 },
|
|
134
135
|
featuredOverrideUrl: "",
|
|
135
136
|
comfyui: { enabled: false, gatePath: "", url: "", reverseGate: false, cachePersist: false },
|
|
@@ -261,6 +262,7 @@ function normalize(c) {
|
|
|
261
262
|
c.daemon = { ...d.daemon, ...c.daemon ?? {} };
|
|
262
263
|
c.telemetry = { ...d.telemetry, ...c.telemetry ?? {} };
|
|
263
264
|
c.hf = { ...d.hf, ...c.hf ?? {} };
|
|
265
|
+
c.gh = { ...d.gh, ...c.gh ?? {} };
|
|
264
266
|
c.modelDefaults = { ...d.modelDefaults, ...c.modelDefaults ?? {} };
|
|
265
267
|
c.lastLoaded = { ...d.lastLoaded, ...c.lastLoaded ?? {} };
|
|
266
268
|
if (typeof c.selectedRemoteModel !== "string") c.selectedRemoteModel = "";
|
|
@@ -688,18 +690,6 @@ function clampMaxTokens(requested, limit) {
|
|
|
688
690
|
return Math.min(requested, limit);
|
|
689
691
|
}
|
|
690
692
|
|
|
691
|
-
// src/engines/manager.ts
|
|
692
|
-
import { execFile as execFile7, spawn, spawnSync } from "child_process";
|
|
693
|
-
import { createWriteStream as createWriteStream2, existsSync as existsSync11, mkdirSync as mkdirSync6, readdirSync as readdirSync3, readFileSync as readFileSync2, rmSync as rmSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
694
|
-
import { createConnection, createServer } from "net";
|
|
695
|
-
import { dirname as dirname2, join as join11 } from "path";
|
|
696
|
-
|
|
697
|
-
// src/engines/mlx.ts
|
|
698
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, rmSync as rmSync2 } from "fs";
|
|
699
|
-
import { execFile as execFile2 } from "child_process";
|
|
700
|
-
import { join as join3 } from "path";
|
|
701
|
-
import { promisify as promisify2 } from "util";
|
|
702
|
-
|
|
703
693
|
// src/engines/download.ts
|
|
704
694
|
import { createWriteStream, existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
705
695
|
import { execFile, execFileSync } from "child_process";
|
|
@@ -708,12 +698,29 @@ import { Readable } from "stream";
|
|
|
708
698
|
import { pipeline } from "stream/promises";
|
|
709
699
|
import { promisify } from "util";
|
|
710
700
|
var execFileP = promisify(execFile);
|
|
711
|
-
|
|
701
|
+
var ambientTokenFn = null;
|
|
702
|
+
function setGithubTokenProvider(fn) {
|
|
703
|
+
ambientTokenFn = fn;
|
|
704
|
+
}
|
|
705
|
+
function githubHeaders(extra, tokenFn) {
|
|
712
706
|
const base2 = {
|
|
713
707
|
Accept: "application/vnd.github+json",
|
|
714
708
|
"User-Agent": "turbollm"
|
|
715
709
|
};
|
|
716
|
-
|
|
710
|
+
let token = "";
|
|
711
|
+
try {
|
|
712
|
+
token = tokenFn?.() ?? "";
|
|
713
|
+
} catch {
|
|
714
|
+
token = "";
|
|
715
|
+
}
|
|
716
|
+
if (!token) {
|
|
717
|
+
try {
|
|
718
|
+
token = ambientTokenFn?.() ?? "";
|
|
719
|
+
} catch {
|
|
720
|
+
token = "";
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
if (!token) token = process.env.GITHUB_TOKEN?.trim() ?? "";
|
|
717
724
|
if (token) base2["Authorization"] = `Bearer ${token}`;
|
|
718
725
|
return { ...base2, ...extra };
|
|
719
726
|
}
|
|
@@ -982,12 +989,22 @@ function pickReleaseAsset(assets, platform = process.platform, archStr = process
|
|
|
982
989
|
}
|
|
983
990
|
return best;
|
|
984
991
|
}
|
|
992
|
+
var GithubRateLimitError = class extends Error {
|
|
993
|
+
constructor(repo) {
|
|
994
|
+
super(`GitHub API rate limit exhausted while querying ${repo}`);
|
|
995
|
+
this.name = "GithubRateLimitError";
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
function isRateLimited(res) {
|
|
999
|
+
return (res.status === 403 || res.status === 429) && res.headers.get("x-ratelimit-remaining") === "0";
|
|
1000
|
+
}
|
|
985
1001
|
async function latestGithubRelease(repo, signal) {
|
|
986
1002
|
const apiUrl = `https://api.github.com/repos/${repo}/releases/latest`;
|
|
987
1003
|
const res = await fetch(apiUrl, {
|
|
988
1004
|
headers: githubHeaders(),
|
|
989
1005
|
signal
|
|
990
1006
|
});
|
|
1007
|
+
if (isRateLimited(res)) throw new GithubRateLimitError(repo);
|
|
991
1008
|
if (!res.ok) throw new Error(`could not query ${repo} releases: HTTP ${res.status}`);
|
|
992
1009
|
return await res.json();
|
|
993
1010
|
}
|
|
@@ -995,12 +1012,35 @@ async function latestReleaseTag(repo, signal) {
|
|
|
995
1012
|
const rel = await latestGithubRelease(repo, signal);
|
|
996
1013
|
return rel.tag_name ?? "";
|
|
997
1014
|
}
|
|
1015
|
+
async function latestBuildTagRelease(repo, signal) {
|
|
1016
|
+
const res = await fetch(`https://api.github.com/repos/${repo}/releases?per_page=100`, {
|
|
1017
|
+
headers: githubHeaders(),
|
|
1018
|
+
signal
|
|
1019
|
+
});
|
|
1020
|
+
if (isRateLimited(res)) throw new GithubRateLimitError(repo);
|
|
1021
|
+
if (!res.ok) throw new Error(`could not list ${repo} releases: HTTP ${res.status}`);
|
|
1022
|
+
const data = await res.json();
|
|
1023
|
+
let best = "";
|
|
1024
|
+
let bestNum = -1;
|
|
1025
|
+
for (const rel of data) {
|
|
1026
|
+
const tag = (rel.tag_name ?? "").trim();
|
|
1027
|
+
const m = /^v?b(\d+)$/i.exec(tag);
|
|
1028
|
+
if (!m) continue;
|
|
1029
|
+
const n = Number(m[1]);
|
|
1030
|
+
if (Number.isInteger(n) && n > bestNum) {
|
|
1031
|
+
bestNum = n;
|
|
1032
|
+
best = tag;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
return best;
|
|
1036
|
+
}
|
|
998
1037
|
async function latestCommitSha(repo, branch = "", signal) {
|
|
999
1038
|
const ref = branch.trim() ? encodeURIComponent(branch.trim()) : "HEAD";
|
|
1000
1039
|
const res = await fetch(`https://api.github.com/repos/${repo}/commits/${ref}`, {
|
|
1001
1040
|
headers: githubHeaders(),
|
|
1002
1041
|
signal
|
|
1003
1042
|
});
|
|
1043
|
+
if (isRateLimited(res)) throw new GithubRateLimitError(repo);
|
|
1004
1044
|
if (!res.ok) throw new Error(`could not query ${repo} commits: HTTP ${res.status}`);
|
|
1005
1045
|
const data = await res.json();
|
|
1006
1046
|
return data.sha ?? "";
|
|
@@ -1051,7 +1091,17 @@ async function provisionTurboquant(enginesRoot, repo, onProgress, signal) {
|
|
|
1051
1091
|
return bin;
|
|
1052
1092
|
}
|
|
1053
1093
|
|
|
1094
|
+
// src/engines/manager.ts
|
|
1095
|
+
import { execFile as execFile7, spawn, spawnSync } from "child_process";
|
|
1096
|
+
import { createWriteStream as createWriteStream2, existsSync as existsSync11, mkdirSync as mkdirSync6, readdirSync as readdirSync3, readFileSync as readFileSync2, rmSync as rmSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
1097
|
+
import { createConnection, createServer } from "net";
|
|
1098
|
+
import { dirname as dirname2, join as join11 } from "path";
|
|
1099
|
+
|
|
1054
1100
|
// src/engines/mlx.ts
|
|
1101
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, rmSync as rmSync2 } from "fs";
|
|
1102
|
+
import { execFile as execFile2 } from "child_process";
|
|
1103
|
+
import { join as join3 } from "path";
|
|
1104
|
+
import { promisify as promisify2 } from "util";
|
|
1055
1105
|
var execFileP2 = promisify2(execFile2);
|
|
1056
1106
|
var UV_VERSION = "0.11.21";
|
|
1057
1107
|
var UV_REPO = "astral-sh/uv";
|
|
@@ -4405,6 +4455,13 @@ function resolveUpdateSource(engine) {
|
|
|
4405
4455
|
}
|
|
4406
4456
|
return null;
|
|
4407
4457
|
}
|
|
4458
|
+
async function latestTagForInstalled(repo, installed2, signal) {
|
|
4459
|
+
if (parseBuildTag(installed2) !== null) {
|
|
4460
|
+
const buildTag = await latestBuildTagRelease(repo, signal);
|
|
4461
|
+
if (buildTag) return buildTag;
|
|
4462
|
+
}
|
|
4463
|
+
return latestReleaseTag(repo, signal);
|
|
4464
|
+
}
|
|
4408
4465
|
async function fetchLatest(src, signal) {
|
|
4409
4466
|
if (src.source === "pip") {
|
|
4410
4467
|
const res = await fetch(`https://pypi.org/pypi/${src.ref}/json`, {
|
|
@@ -4416,7 +4473,7 @@ async function fetchLatest(src, signal) {
|
|
|
4416
4473
|
return data.info?.version ?? "";
|
|
4417
4474
|
}
|
|
4418
4475
|
if (src.source === "source") return latestCommitSha(src.ref, src.branch ?? "", signal);
|
|
4419
|
-
return
|
|
4476
|
+
return latestTagForInstalled(src.ref, src.installed, signal);
|
|
4420
4477
|
}
|
|
4421
4478
|
async function computeUpdateStatus(engine, fetcher = fetchLatest, signal) {
|
|
4422
4479
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4427,8 +4484,9 @@ async function computeUpdateStatus(engine, fetcher = fetchLatest, signal) {
|
|
|
4427
4484
|
let latest2;
|
|
4428
4485
|
try {
|
|
4429
4486
|
latest2 = await fetcher(src, signal);
|
|
4430
|
-
} catch {
|
|
4431
|
-
|
|
4487
|
+
} catch (e) {
|
|
4488
|
+
const error = e instanceof GithubRateLimitError ? "rate_limited" : "offline";
|
|
4489
|
+
return { installed: src.installed, latest: null, hasUpdate: false, checkedAt, error, comparable: false };
|
|
4432
4490
|
}
|
|
4433
4491
|
if (!latest2) {
|
|
4434
4492
|
return { installed: src.installed, latest: null, hasUpdate: false, checkedAt, error: "offline", comparable: false };
|
|
@@ -13553,7 +13611,7 @@ async function applyLlamaCppUpdate(d, engine, root, signal) {
|
|
|
13553
13611
|
const backendId = backendIdFromBinPath(engine.binPath);
|
|
13554
13612
|
if (!backendId) throw new Error("Could not determine the GPU backend of this build.");
|
|
13555
13613
|
const installedTag = tagFromManagedBinPath(engine.binPath);
|
|
13556
|
-
const latestTag = await
|
|
13614
|
+
const latestTag = await latestTagForInstalled(OFFICIAL_LLAMA_REPO2, installedTag, signal);
|
|
13557
13615
|
if (!latestTag) throw new Error("GitHub did not report a latest build.");
|
|
13558
13616
|
if (installedTag && installedTag === latestTag) return;
|
|
13559
13617
|
const newDef = backendDefAt(backendId, latestTag);
|
|
@@ -22845,7 +22903,8 @@ var ALL = [
|
|
|
22845
22903
|
installEndpoint: "",
|
|
22846
22904
|
// Its installed state comes from the separate backend-build detection (LlamaCppBackendRows),
|
|
22847
22905
|
// not the generic sourceRepo match below — see the field's own doc comment (ADR-388).
|
|
22848
|
-
excludeFromSourceMatch: true
|
|
22906
|
+
excludeFromSourceMatch: true,
|
|
22907
|
+
defaultBranch: "master"
|
|
22849
22908
|
},
|
|
22850
22909
|
{
|
|
22851
22910
|
// Upstream publishes NO Linux CUDA prebuilt (download.ts availableBackends() — Linux
|
|
@@ -22865,6 +22924,7 @@ var ALL = [
|
|
|
22865
22924
|
support: "experimental",
|
|
22866
22925
|
installEndpoint: "",
|
|
22867
22926
|
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).",
|
|
22927
|
+
defaultBranch: "master",
|
|
22868
22928
|
variants: [
|
|
22869
22929
|
{
|
|
22870
22930
|
id: "llama.cpp-cuda-source",
|
|
@@ -22897,6 +22957,7 @@ var ALL = [
|
|
|
22897
22957
|
support: "experimental",
|
|
22898
22958
|
installEndpoint: "",
|
|
22899
22959
|
note: "Run inside Termux (not the Android app store \u2014 get Termux from F-Droid or its GitHub releases). First install the toolchain: `pkg install git cmake clang`. Then use the guided build below. Real-device verified: toolchain install + partial compile confirmed live on a real Android 14 (4KB-page) emulator; a full clean build was not timed to completion in that session (GitHub #52 item 6).",
|
|
22960
|
+
defaultBranch: "master",
|
|
22900
22961
|
variants: [
|
|
22901
22962
|
{
|
|
22902
22963
|
id: "llama.cpp-android-source-cpu",
|
|
@@ -22927,6 +22988,7 @@ var ALL = [
|
|
|
22927
22988
|
support: "experimental",
|
|
22928
22989
|
installEndpoint: "",
|
|
22929
22990
|
note: "No prebuilt binary. Select a branch below and TurboLLM clones + compiles it for you. Each branch you build becomes a separate engine (e.g. Llama-main, Llama-my-feature).",
|
|
22991
|
+
defaultBranch: "master",
|
|
22930
22992
|
variants: [
|
|
22931
22993
|
{
|
|
22932
22994
|
id: "llama.cpp-source-branch",
|
|
@@ -22953,6 +23015,7 @@ var ALL = [
|
|
|
22953
23015
|
support: "experimental",
|
|
22954
23016
|
installEndpoint: "/api/v1/engines/vllm",
|
|
22955
23017
|
note: "Officially supported on Linux + NVIDIA/CUDA. macOS is CPU-only experimental; Windows is unsupported upstream. Installs a multi-GB Python environment.",
|
|
23018
|
+
defaultBranch: "main",
|
|
22956
23019
|
// Classification-only variant (its pip install path is unchanged). Lets the
|
|
22957
23020
|
// matcher/recommender reason about vLLM's fit on this box: Linux + NVIDIA.
|
|
22958
23021
|
variants: [
|
|
@@ -22979,6 +23042,7 @@ var ALL = [
|
|
|
22979
23042
|
support: "stable",
|
|
22980
23043
|
installEndpoint: "/api/v1/engines/mlx",
|
|
22981
23044
|
note: "macOS (Apple Silicon) only.",
|
|
23045
|
+
defaultBranch: "main",
|
|
22982
23046
|
// Classification-only variant (its pip install path is unchanged). Lets the
|
|
22983
23047
|
// matcher/recommender reason about MLX's fit on this box: macOS + Apple GPU.
|
|
22984
23048
|
variants: [
|
|
@@ -23005,6 +23069,7 @@ var ALL = [
|
|
|
23005
23069
|
support: "experimental",
|
|
23006
23070
|
installEndpoint: "/api/v1/engines/rapid-mlx",
|
|
23007
23071
|
note: "macOS (Apple Silicon) only. Loads the same MLX-format model directories as the MLX engine.",
|
|
23072
|
+
defaultBranch: "main",
|
|
23008
23073
|
variants: [
|
|
23009
23074
|
{
|
|
23010
23075
|
id: "rapid-mlx",
|
|
@@ -23029,6 +23094,7 @@ var ALL = [
|
|
|
23029
23094
|
support: "experimental",
|
|
23030
23095
|
installEndpoint: "/api/v1/engines/mlx-vlm",
|
|
23031
23096
|
note: 'macOS (Apple Silicon) only. Loads the same MLX-format model directories as the MLX engine. Some architectures (e.g. Qwen-VL, SmolVLM) additionally need torch + torchvision, which are not installed automatically. If a model fails to load with a "missing image processor" error, locate the bootstrapped uv binary (find ~/.turbollm/engines/uv -name uv -type f) and run: <that uv path> pip install --python <this engine\'s venv>/bin/python torch torchvision. Tool/function calling is architecture-dependent: mlx-vlm only turns a `tools` array into real tool calls for the handful of chat templates it has a matching parser for. Other models accept the request without error but never call a tool (confirmed live on Qwen2.5-VL: its own /health reports "loaded_tool_parser": null).',
|
|
23097
|
+
defaultBranch: "main",
|
|
23032
23098
|
variants: [
|
|
23033
23099
|
{
|
|
23034
23100
|
id: "mlx-vlm",
|
|
@@ -23053,6 +23119,7 @@ var ALL = [
|
|
|
23053
23119
|
support: "experimental",
|
|
23054
23120
|
installEndpoint: "/api/v1/engines/sglang",
|
|
23055
23121
|
note: "Officially supported on Linux + NVIDIA/CUDA 12+. macOS and Windows are unsupported upstream. Installs a multi-GB Python environment.",
|
|
23122
|
+
defaultBranch: "main",
|
|
23056
23123
|
variants: [
|
|
23057
23124
|
{
|
|
23058
23125
|
id: "sglang-cuda",
|
|
@@ -23081,6 +23148,7 @@ var ALL = [
|
|
|
23081
23148
|
support: "experimental",
|
|
23082
23149
|
installEndpoint: "",
|
|
23083
23150
|
note: 'No prebuilt binaries are published. Build llama-server from the fork, then use "Add your own engine" to point TurboLLM at it \u2014 it runs on the standard llama-server path.',
|
|
23151
|
+
defaultBranch: "main",
|
|
23084
23152
|
variants: [
|
|
23085
23153
|
{
|
|
23086
23154
|
id: "ik_llama.cpp-source",
|
|
@@ -23108,6 +23176,7 @@ var ALL = [
|
|
|
23108
23176
|
support: "experimental",
|
|
23109
23177
|
installEndpoint: "/api/v1/engines/llamafile",
|
|
23110
23178
|
note: "Downloads one portable executable that bundles llama.cpp. GPU acceleration depends on your platform/drivers; falls back to CPU.",
|
|
23179
|
+
defaultBranch: "main",
|
|
23111
23180
|
variants: [
|
|
23112
23181
|
{
|
|
23113
23182
|
id: "llamafile",
|
|
@@ -23134,6 +23203,7 @@ var ALL = [
|
|
|
23134
23203
|
support: "experimental",
|
|
23135
23204
|
installEndpoint: "/api/v1/engines/koboldcpp",
|
|
23136
23205
|
note: "Downloads a single KoboldCpp binary. The CUDA build is used on NVIDIA GPUs; the portable build (Vulkan/CPU) elsewhere. Windows/Linux are x64-only; macOS is Apple Silicon only.",
|
|
23206
|
+
defaultBranch: "concedo",
|
|
23137
23207
|
variants: [
|
|
23138
23208
|
{
|
|
23139
23209
|
id: "koboldcpp-cuda",
|
|
@@ -23183,6 +23253,7 @@ var ALL = [
|
|
|
23183
23253
|
support: "experimental",
|
|
23184
23254
|
installEndpoint: "/api/v1/engines/turboquant",
|
|
23185
23255
|
note: 'Prebuilt: macOS (Apple Silicon), Linux x64 (Vulkan). On Windows, build llama-server from the fork, then use "Add your own engine".',
|
|
23256
|
+
defaultBranch: "master",
|
|
23186
23257
|
variants: [
|
|
23187
23258
|
{
|
|
23188
23259
|
id: "turboquant-macos-metal",
|
|
@@ -23230,6 +23301,7 @@ var ALL = [
|
|
|
23230
23301
|
support: "experimental",
|
|
23231
23302
|
installEndpoint: "",
|
|
23232
23303
|
note: "Upstream publishes prebuilt binaries, but TurboLLM builds from source here (guided walkthrough) rather than resolving a specific release asset. Proven on a ternary/Bonsai-class model at 200K context (Q2_0 + q8 KV).",
|
|
23304
|
+
defaultBranch: "prism",
|
|
23233
23305
|
variants: [
|
|
23234
23306
|
{
|
|
23235
23307
|
id: "prism-source",
|
|
@@ -23257,6 +23329,7 @@ var ALL = [
|
|
|
23257
23329
|
support: "experimental",
|
|
23258
23330
|
installEndpoint: "",
|
|
23259
23331
|
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.",
|
|
23332
|
+
defaultBranch: "main",
|
|
23260
23333
|
variants: [
|
|
23261
23334
|
{
|
|
23262
23335
|
id: "beellama-source",
|
|
@@ -24737,14 +24810,14 @@ function registerApi(app2, d) {
|
|
|
24737
24810
|
const busy = engineWorkBusy(d);
|
|
24738
24811
|
if (busy) return err5(c, 409, "engine_already_running", busy);
|
|
24739
24812
|
}
|
|
24813
|
+
const installedTag = tagFromManagedBinPath(oldBin);
|
|
24740
24814
|
let latestTag;
|
|
24741
24815
|
try {
|
|
24742
|
-
latestTag = await
|
|
24816
|
+
latestTag = await latestTagForInstalled("ggml-org/llama.cpp", installedTag, AbortSignal.timeout(15e3));
|
|
24743
24817
|
} catch {
|
|
24744
24818
|
return err5(c, 503, "offline", "Couldn't reach GitHub to check for a newer build. Try again when online.");
|
|
24745
24819
|
}
|
|
24746
24820
|
if (!latestTag) return err5(c, 503, "offline", "GitHub didn't report a latest build. Try again later.");
|
|
24747
|
-
const installedTag = tagFromManagedBinPath(oldBin);
|
|
24748
24821
|
if (installedTag && installedTag === latestTag) {
|
|
24749
24822
|
return c.json({ accepted: false, alreadyLatest: true, build: latestTag });
|
|
24750
24823
|
}
|
|
@@ -24951,18 +25024,29 @@ function registerApi(app2, d) {
|
|
|
24951
25024
|
if (!raw) return err5(c, 400, "invalid_input", "repo is required.");
|
|
24952
25025
|
const repo = normRepoUrl(raw);
|
|
24953
25026
|
if (!repo) return err5(c, 400, "invalid_input", "repo must be a valid GitHub repo identifier.");
|
|
24954
|
-
const
|
|
24955
|
-
const offset = Math.max(parseInt(c.req.query("offset") ?? "0", 10) || 0, 0);
|
|
25027
|
+
const tokenSet = (d.store.snapshot().gh?.token ?? "").length > 0;
|
|
24956
25028
|
try {
|
|
24957
|
-
const
|
|
24958
|
-
|
|
24959
|
-
|
|
24960
|
-
|
|
24961
|
-
|
|
25029
|
+
const names = [];
|
|
25030
|
+
for (let page = 1; page <= 20; page++) {
|
|
25031
|
+
const res = await fetch(`https://api.github.com/repos/${repo}/branches?per_page=100&page=${page}`, {
|
|
25032
|
+
headers: githubHeaders({}, () => d.store.snapshot().gh?.token ?? "")
|
|
25033
|
+
});
|
|
25034
|
+
if (isRateLimited(res))
|
|
25035
|
+
return err5(
|
|
25036
|
+
c,
|
|
25037
|
+
403,
|
|
25038
|
+
"github_rate_limited",
|
|
25039
|
+
tokenSet ? "The configured GitHub token has exhausted its API rate limit (5,000 requests/hour). Branch lookups will work again after the limit resets." : "GitHub\u2019s unauthenticated API rate limit (60 requests/hour) is exhausted. Add a GitHub token in Settings to raise it to 5,000 requests/hour."
|
|
25040
|
+
);
|
|
25041
|
+
if (!res.ok) throw new Error(`GitHub API returned HTTP ${res.status}`);
|
|
25042
|
+
const data = await res.json();
|
|
25043
|
+
names.push(...data.map((b) => b.name));
|
|
25044
|
+
if (data.length < 100) break;
|
|
25045
|
+
}
|
|
24962
25046
|
let defaultBranch = "";
|
|
24963
25047
|
try {
|
|
24964
25048
|
const info = await fetch(`https://api.github.com/repos/${repo}`, {
|
|
24965
|
-
headers: githubHeaders()
|
|
25049
|
+
headers: githubHeaders({}, () => d.store.snapshot().gh?.token ?? "")
|
|
24966
25050
|
});
|
|
24967
25051
|
if (info.ok) {
|
|
24968
25052
|
const j = await info.json();
|
|
@@ -24970,11 +25054,8 @@ function registerApi(app2, d) {
|
|
|
24970
25054
|
}
|
|
24971
25055
|
} catch {
|
|
24972
25056
|
}
|
|
24973
|
-
const names = data.map((b) => b.name);
|
|
24974
25057
|
const sorted = defaultBranch ? [defaultBranch, ...names.filter((n) => n !== defaultBranch)] : names;
|
|
24975
|
-
|
|
24976
|
-
const page = sorted.slice(offset, offset + limit);
|
|
24977
|
-
return c.json({ total, branches: page });
|
|
25058
|
+
return c.json({ total: sorted.length, branches: sorted });
|
|
24978
25059
|
} catch (e) {
|
|
24979
25060
|
return err5(c, 503, "offline", `Could not fetch branches for ${repo}: ${e instanceof Error ? e.message : String(e)}`);
|
|
24980
25061
|
}
|
|
@@ -25844,6 +25925,7 @@ function registerApi(app2, d) {
|
|
|
25844
25925
|
if (b.experimental?.routines !== void 0) cfg2.daemon.experimental.routines = !!b.experimental.routines;
|
|
25845
25926
|
if (b.experimental?.turboLink !== void 0) cfg2.daemon.experimental.turboLink = !!b.experimental.turboLink;
|
|
25846
25927
|
if (b.hfToken !== void 0) cfg2.hf.token = String(b.hfToken).trim();
|
|
25928
|
+
if (b.ghToken !== void 0) (cfg2.gh ??= { token: "" }).token = String(b.ghToken).trim();
|
|
25847
25929
|
cfg2.tools.search ??= { provider: "tavily" };
|
|
25848
25930
|
const s = cfg2.tools.search;
|
|
25849
25931
|
if (b.search?.provider === "tavily" || b.search?.provider === "kagi" || b.search?.provider === "searxng") {
|
|
@@ -26225,6 +26307,8 @@ function settingsPayload(d) {
|
|
|
26225
26307
|
// The HF token is write-only over the wire (spec 10 §4): we never echo it back,
|
|
26226
26308
|
// only whether one is set, so the UI can show "configured" without leaking it.
|
|
26227
26309
|
hfTokenSet: cfg2.hf.token.length > 0,
|
|
26310
|
+
// GitHub token is write-only: expose only whether it is set.
|
|
26311
|
+
ghTokenSet: (cfg2.gh?.token ?? "").length > 0,
|
|
26228
26312
|
// Tavily API key is write-only: expose only whether it is set (legacy field, kept for compat).
|
|
26229
26313
|
tavilyKeySet: !!(cfg2.tools.search?.tavilyApiKey ?? cfg2.tools.tavily?.apiKey),
|
|
26230
26314
|
// Search provider config (F-020): provider + which credentials are set. Keys are write-only
|
|
@@ -34242,6 +34326,7 @@ var store = ConfigStore.load(argValue("--config", defaultConfigPath()));
|
|
|
34242
34326
|
if (store.brokenBackup()) {
|
|
34243
34327
|
console.warn(`config was reset; previous file backed up at ${store.brokenBackup()}`);
|
|
34244
34328
|
}
|
|
34329
|
+
setGithubTokenProvider(() => store.snapshot().gh?.token ?? "");
|
|
34245
34330
|
if (hasFlag("--stop")) {
|
|
34246
34331
|
const result = await stopDaemon(store.dir());
|
|
34247
34332
|
process.stdout.write(result.message + "\n");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./radix-DW4bWMkB.js";import{b as W,u as $,r as b}from"./vendor-C1I6euDx.js";import{u as G,d as H,e as Y,f as J,g as U,a as z,B as C,t as j,c as q,b as h,A as _}from"./index-4QuGA7c6.js";import{f as V}from"./chat-api-Cm7puych.js";import{f as X,a as Z}from"./agent-api-CNgD3AG5.js";import{P as B}from"./personas-BK5wc_P3.js";import{C as ee}from"./chevron-left-CcApbuPp.js";import{R as te}from"./rotate-ccw-Bar4GXPb.js";import{T as se}from"./trash-2-BNwq5WtQ.js";import{C as ne}from"./chevron-right-DcT_N4lU.js";import"./dropdown-menu-CzL84hjo.js";const ae=()=>({name:"",description:"",systemPrompt:"",skillIds:[],tools:[]});function oe(s){const d=[],x=new Map;for(const n of s){const a=/^mcp__([^_]+(?:_[^_]+)*)__/.exec(n.name);if(!a){d.push(n);continue}const i=a[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,a)=>n.label.localeCompare(a.label))}}function le(s){return s.replace(/^mcp__[^_]+(?:_[^_]+)*__/,"")}function re(s){return s.replace(/^\[[^\]]+\]\s*/,"")}function D({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:le(s.name)}),s.description&&e.jsx("span",{className:"text-faint",children:re(s.description)})]})]})}function ie({group:s,selected:d,onToggleAll:x,onToggleOne:n}){const[a,i]=b.useState(!1),p=s.tools.map(l=>l.name),c=p.filter(l=>d.has(l)).length,o=c===p.length,g=c>0&&!o,u=b.useRef(null);return b.useEffect(()=>{u.current&&(u.current.indeterminate=g)},[g]),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:o,onChange:()=>x(p,!o)}),e.jsxs("button",{type:"button",onClick:()=>{j("agents","toggle_agent_tool_group"),i(l=>!l)},className:"flex flex-1 items-center gap-1.5 text-left text-[13px] text-ink",children:[e.jsx(ne,{size:12,className:q("shrink-0 text-faint transition-transform",a&&"rotate-90")}),s.label,e.jsxs("span",{className:"text-[11px] text-faint",children:["(",c,"/",p.length,")"]})]})]}),a&&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(D,{tool:l,checked:d.has(l.name),onToggle:()=>n(l.name)},l.name))})]})}function ce({tools:s,selected:d,onChange:x}){const n=new Set(d),{builtin:a,groups:i}=oe(s),p=o=>x(n.has(o)?d.filter(g=>g!==o):[...d,o]),c=(o,g)=>{const u=d.filter(l=>!o.includes(l));x(g?[...u,...o]: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:[a.length>0&&e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:a.map(o=>e.jsx(D,{tool:o,checked:n.has(o.name),onToggle:()=>p(o.name)},o.name))}),i.map(o=>e.jsx(ie,{group:o,selected:n,onToggleAll:c,onToggleOne:p},o.key))]})}function je(){const{agentId:s="new"}=W(),d=$(),x=G(),n=s==="new",a=!n&&B.some(t=>t.id===s),i=a?B.find(t=>t.id===s):void 0,p=H(),c=!n&&!a?(p.data??[]).find(t=>t.id===s):void 0,o=Y(),g=J(),u=U(),l=a?g.data?.[s]:void 0,I=z({queryKey:Z.list(),queryFn:X,staleTime:0}),k=I.data??[],w=z({queryKey:["available-tools"],queryFn:V}),N=w.data??[],[m,f]=b.useState(ae()),[S,T]=b.useState(!1),[A,P]=b.useState(!1),[L,R]=b.useState(!1),[E,Q]=b.useState("skills");n&&!S&&(k.length||N.length)&&(f(t=>({...t,skillIds:k.map(r=>r.id),tools:N.map(r=>r.name)})),T(!0)),!n&&!a&&!S&&c&&(f({name:c.name,description:c.description,systemPrompt:c.systemPrompt,skillIds:c.skillIds,tools:c.tools}),T(!0)),a&&!S&&i&&g.isSuccess&&(k.length||N.length)&&(f({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??N.map(t=>t.name)}),T(!0));const y=()=>{j("agents","back_to_agents"),d("/customize")},O=t=>f(r=>({...r,skillIds:r.skillIds.includes(t)?r.skillIds.filter(v=>v!==t):[...r.skillIds,t]})),F=()=>{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(a){u.save.mutate({id:s,override:t},{onSuccess:()=>{h.success("Agent saved."),y()},onError:v=>{h.error(v instanceof _?v.message:"Could not save agent."),P(!1)}});return}const r={onSuccess:()=>{x.invalidateQueries({queryKey:["chat-agents"]}),h.success(n?"Agent created.":"Agent saved."),y()},onError:v=>{h.error(v instanceof _?v.message:"Could not save agent."),P(!1)}};n?o.add.mutate(t,r):o.update.mutate({id:s,patch:t},r)},K=()=>{u.reset.mutate(s,{onSuccess:()=>{h.success("Reset to default."),i&&f({name:i.name,description:i.description,systemPrompt:i.systemPrompt,skillIds:k.map(t=>t.id),tools:N.map(t=>t.name)})},onError:t=>h.error(t instanceof _?t.message:"Could not reset agent.")})},M=()=>{o.remove.mutate(s,{onSuccess:()=>{h.success("Agent deleted."),y()},onError:t=>h.error(t instanceof _?t.message:"Could not delete agent.")})};return!n&&!a&&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(C,{size:"sm",variant:"outline",onClick:y,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:y,className:"text-faint hover:text-ink",title:"Back to agents",children:e.jsx(ee,{size:18})}),e.jsx("span",{className:"text-[15px] font-medium text-ink",children:n?"New agent":a?l?"Edit agent (modified built-in)":"Edit agent (built-in)":"Edit agent"}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[a&&e.jsxs(C,{size:"sm",variant:"outline",onClick:()=>{j("agents","reset_agent_to_default"),K()},disabled:u.reset.isPending,children:[e.jsx(te,{size:13})," Reset to default"]}),e.jsx(C,{size:"sm",variant:"outline",onClick:y,children:"Cancel"}),e.jsx(C,{size:"sm",onClick:()=>{j("agents","save_agent"),F()},disabled:A||!m.name.trim(),children:A?"Saving…":"Save"})]})]}),a&&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=>f(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=>f(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=>f(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:()=>{j("agents","switch_agent_form_tab"),Q(t)},className:q("rounded px-3 py-1.5 text-[13px] font-medium transition-colors",E===t?"bg-accent/12 text-accent":"text-muted hover:text-ink"),children:t==="skills"?`Skills (${m.skillIds.length})`:`Tools (${m.tools.length})`},t))}),E==="skills"?I.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:()=>O(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))}):w.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):e.jsx(ce,{tools:N,selected:m.tools,onChange:t=>f(r=>({...r,tools:t}))})]}),!n&&!a&&(L?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:()=>{j("agents","delete_agent"),M()},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:()=>{j("agents","cancel_delete_agent"),R(!1)},className:"rounded px-2 py-1 text-faint hover:text-ink",children:"Cancel"})]}):e.jsxs("button",{type:"button",onClick:()=>R(!0),className:"flex items-center gap-1.5 self-start text-[12px] text-faint hover:text-[color:var(--err)]",children:[e.jsx(se,{size:13})," Delete agent"]}))]})}export{je as AgentEditPage};
|
|
1
|
+
import{j as e}from"./radix-DW4bWMkB.js";import{b as W,u as $,r as b}from"./vendor-C1I6euDx.js";import{u as G,d as H,e as Y,f as J,g as U,a as z,B as C,t as j,c as q,b as h,A as _}from"./index-6s1TR3Mg.js";import{f as V}from"./chat-api-fC2sf7Mj.js";import{f as X,a as Z}from"./agent-api-DZ1WgRmZ.js";import{P as B}from"./personas-CdldzkmX.js";import{C as ee}from"./chevron-left-DXZuhCTN.js";import{R as te}from"./rotate-ccw-Ao2f14qP.js";import{T as se}from"./trash-2-BS-v4vnu.js";import{C as ne}from"./chevron-right-BSHofHoG.js";import"./dropdown-menu-C7SX-XbP.js";const ae=()=>({name:"",description:"",systemPrompt:"",skillIds:[],tools:[]});function oe(s){const d=[],x=new Map;for(const n of s){const a=/^mcp__([^_]+(?:_[^_]+)*)__/.exec(n.name);if(!a){d.push(n);continue}const i=a[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,a)=>n.label.localeCompare(a.label))}}function le(s){return s.replace(/^mcp__[^_]+(?:_[^_]+)*__/,"")}function re(s){return s.replace(/^\[[^\]]+\]\s*/,"")}function D({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:le(s.name)}),s.description&&e.jsx("span",{className:"text-faint",children:re(s.description)})]})]})}function ie({group:s,selected:d,onToggleAll:x,onToggleOne:n}){const[a,i]=b.useState(!1),p=s.tools.map(l=>l.name),c=p.filter(l=>d.has(l)).length,o=c===p.length,g=c>0&&!o,u=b.useRef(null);return b.useEffect(()=>{u.current&&(u.current.indeterminate=g)},[g]),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:o,onChange:()=>x(p,!o)}),e.jsxs("button",{type:"button",onClick:()=>{j("agents","toggle_agent_tool_group"),i(l=>!l)},className:"flex flex-1 items-center gap-1.5 text-left text-[13px] text-ink",children:[e.jsx(ne,{size:12,className:q("shrink-0 text-faint transition-transform",a&&"rotate-90")}),s.label,e.jsxs("span",{className:"text-[11px] text-faint",children:["(",c,"/",p.length,")"]})]})]}),a&&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(D,{tool:l,checked:d.has(l.name),onToggle:()=>n(l.name)},l.name))})]})}function ce({tools:s,selected:d,onChange:x}){const n=new Set(d),{builtin:a,groups:i}=oe(s),p=o=>x(n.has(o)?d.filter(g=>g!==o):[...d,o]),c=(o,g)=>{const u=d.filter(l=>!o.includes(l));x(g?[...u,...o]: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:[a.length>0&&e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:a.map(o=>e.jsx(D,{tool:o,checked:n.has(o.name),onToggle:()=>p(o.name)},o.name))}),i.map(o=>e.jsx(ie,{group:o,selected:n,onToggleAll:c,onToggleOne:p},o.key))]})}function je(){const{agentId:s="new"}=W(),d=$(),x=G(),n=s==="new",a=!n&&B.some(t=>t.id===s),i=a?B.find(t=>t.id===s):void 0,p=H(),c=!n&&!a?(p.data??[]).find(t=>t.id===s):void 0,o=Y(),g=J(),u=U(),l=a?g.data?.[s]:void 0,I=z({queryKey:Z.list(),queryFn:X,staleTime:0}),k=I.data??[],w=z({queryKey:["available-tools"],queryFn:V}),N=w.data??[],[m,f]=b.useState(ae()),[S,T]=b.useState(!1),[A,P]=b.useState(!1),[L,R]=b.useState(!1),[E,Q]=b.useState("skills");n&&!S&&(k.length||N.length)&&(f(t=>({...t,skillIds:k.map(r=>r.id),tools:N.map(r=>r.name)})),T(!0)),!n&&!a&&!S&&c&&(f({name:c.name,description:c.description,systemPrompt:c.systemPrompt,skillIds:c.skillIds,tools:c.tools}),T(!0)),a&&!S&&i&&g.isSuccess&&(k.length||N.length)&&(f({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??N.map(t=>t.name)}),T(!0));const y=()=>{j("agents","back_to_agents"),d("/customize")},O=t=>f(r=>({...r,skillIds:r.skillIds.includes(t)?r.skillIds.filter(v=>v!==t):[...r.skillIds,t]})),F=()=>{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(a){u.save.mutate({id:s,override:t},{onSuccess:()=>{h.success("Agent saved."),y()},onError:v=>{h.error(v instanceof _?v.message:"Could not save agent."),P(!1)}});return}const r={onSuccess:()=>{x.invalidateQueries({queryKey:["chat-agents"]}),h.success(n?"Agent created.":"Agent saved."),y()},onError:v=>{h.error(v instanceof _?v.message:"Could not save agent."),P(!1)}};n?o.add.mutate(t,r):o.update.mutate({id:s,patch:t},r)},K=()=>{u.reset.mutate(s,{onSuccess:()=>{h.success("Reset to default."),i&&f({name:i.name,description:i.description,systemPrompt:i.systemPrompt,skillIds:k.map(t=>t.id),tools:N.map(t=>t.name)})},onError:t=>h.error(t instanceof _?t.message:"Could not reset agent.")})},M=()=>{o.remove.mutate(s,{onSuccess:()=>{h.success("Agent deleted."),y()},onError:t=>h.error(t instanceof _?t.message:"Could not delete agent.")})};return!n&&!a&&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(C,{size:"sm",variant:"outline",onClick:y,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:y,className:"text-faint hover:text-ink",title:"Back to agents",children:e.jsx(ee,{size:18})}),e.jsx("span",{className:"text-[15px] font-medium text-ink",children:n?"New agent":a?l?"Edit agent (modified built-in)":"Edit agent (built-in)":"Edit agent"}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[a&&e.jsxs(C,{size:"sm",variant:"outline",onClick:()=>{j("agents","reset_agent_to_default"),K()},disabled:u.reset.isPending,children:[e.jsx(te,{size:13})," Reset to default"]}),e.jsx(C,{size:"sm",variant:"outline",onClick:y,children:"Cancel"}),e.jsx(C,{size:"sm",onClick:()=>{j("agents","save_agent"),F()},disabled:A||!m.name.trim(),children:A?"Saving…":"Save"})]})]}),a&&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=>f(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=>f(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=>f(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:()=>{j("agents","switch_agent_form_tab"),Q(t)},className:q("rounded px-3 py-1.5 text-[13px] font-medium transition-colors",E===t?"bg-accent/12 text-accent":"text-muted hover:text-ink"),children:t==="skills"?`Skills (${m.skillIds.length})`:`Tools (${m.tools.length})`},t))}),E==="skills"?I.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:()=>O(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))}):w.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):e.jsx(ce,{tools:N,selected:m.tools,onChange:t=>f(r=>({...r,tools:t}))})]}),!n&&!a&&(L?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:()=>{j("agents","delete_agent"),M()},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:()=>{j("agents","cancel_delete_agent"),R(!1)},className:"rounded px-2 py-1 text-faint hover:text-ink",children:"Cancel"})]}):e.jsxs("button",{type:"button",onClick:()=>R(!0),className:"flex items-center gap-1.5 self-start text-[12px] text-faint hover:text-[color:var(--err)]",children:[e.jsx(se,{size:13})," Delete agent"]}))]})}export{je as AgentEditPage};
|