turbollm 1.7.3 → 1.7.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 +10 -9
- package/dist/cli.js +19 -18
- package/dist/webdist/assets/AgentEditPage-BOnwuNEo.js +1 -0
- package/dist/webdist/assets/{ChatScreen-BOZjtqGu.js → ChatScreen-C-etPxFP.js} +16 -16
- package/dist/webdist/assets/CustomizeScreen-CBS-4CGF.js +4 -0
- package/dist/webdist/assets/DeveloperScreen-Dm9p8rsC.js +1 -0
- package/dist/webdist/assets/EnginesScreen-KF8kClsH.js +7 -0
- package/dist/webdist/assets/FsBrowser-Un46d4qe.js +1 -0
- package/dist/webdist/assets/{MessageBubble-mJwFfOab.js → MessageBubble-5F87qAxY.js} +4 -4
- package/dist/webdist/assets/ModelsScreen-6VbHhlyf.js +2 -0
- package/dist/webdist/assets/SettingsScreen-DjoLkPpP.js +1 -0
- package/dist/webdist/assets/SkillEditPage-C5Evktgw.js +1 -0
- package/dist/webdist/assets/WorkspaceScreen-CiKb7f1I.js +1 -0
- package/dist/webdist/assets/{agent-api-B3GXwr4Y.js → agent-api-D3hMsrHk.js} +1 -1
- package/dist/webdist/assets/{arc-CRcL8nar.js → arc-BhnuNjta.js} +1 -1
- package/dist/webdist/assets/{architectureDiagram-3BPJPVTR-BmOKGMd0.js → architectureDiagram-3BPJPVTR-c3DASz95.js} +1 -1
- package/dist/webdist/assets/arrow-left-BZ7U2kS9.js +1 -0
- package/dist/webdist/assets/{blockDiagram-GPEHLZMM-C4vusmQ-.js → blockDiagram-GPEHLZMM-CkpfHyuv.js} +1 -1
- package/dist/webdist/assets/bot-B3GTFQ2J.js +1 -0
- package/dist/webdist/assets/{c4Diagram-AAUBKEIU-DdY0YXKs.js → c4Diagram-AAUBKEIU-B5dn9Zuf.js} +1 -1
- package/dist/webdist/assets/channel-CJpy6WaL.js +1 -0
- package/dist/webdist/assets/{chat-api-DrMO_g5m.js → chat-api-Dz6qvO1a.js} +1 -1
- package/dist/webdist/assets/check-C39bHy3w.js +1 -0
- package/dist/webdist/assets/{chevron-left-CfyO2AXW.js → chevron-left-Bm2f38an.js} +1 -1
- package/dist/webdist/assets/{chevron-right--1OIa5uV.js → chevron-right-DGQJG4QN.js} +1 -1
- package/dist/webdist/assets/{chunk-2J33WTMH-DzCJsNN1.js → chunk-2J33WTMH-_x1EGF5n.js} +1 -1
- package/dist/webdist/assets/{chunk-4BX2VUAB-BNPfO47j.js → chunk-4BX2VUAB-pQD6zp-n.js} +1 -1
- package/dist/webdist/assets/{chunk-55IACEB6-_vELiE2B.js → chunk-55IACEB6-DIsjXVDw.js} +1 -1
- package/dist/webdist/assets/{chunk-727SXJPM-CsQCgUxY.js → chunk-727SXJPM-CHDF4RtM.js} +1 -1
- package/dist/webdist/assets/{chunk-AQP2D5EJ-G0waQ7sq.js → chunk-AQP2D5EJ-CaQFwmUk.js} +1 -1
- package/dist/webdist/assets/{chunk-FMBD7UC4-CkNtvlrw.js → chunk-FMBD7UC4-DENyT0Cw.js} +1 -1
- package/dist/webdist/assets/{chunk-ND2GUHAM-DGnw4n1I.js → chunk-ND2GUHAM-Cv6Yek6j.js} +1 -1
- package/dist/webdist/assets/{chunk-QZHKN3VN-BpJ4HH0V.js → chunk-QZHKN3VN-9ATQymUl.js} +1 -1
- package/dist/webdist/assets/circle-x-DsCSoQSk.js +1 -0
- package/dist/webdist/assets/classDiagram-4FO5ZUOK-BwNVmSJo.js +1 -0
- package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-BwNVmSJo.js +1 -0
- package/dist/webdist/assets/collapsible-Bqsm-UEI.js +1 -0
- package/dist/webdist/assets/common-DHHaSVnF.js +1 -0
- package/dist/webdist/assets/{cose-bilkent-S5V4N54A-fol9bGNP.js → cose-bilkent-S5V4N54A-r9UktTKw.js} +1 -1
- package/dist/webdist/assets/{dagre-BM42HDAG-kyg4YiiE.js → dagre-BM42HDAG-BnhFpJ0u.js} +1 -1
- package/dist/webdist/assets/{diagram-2AECGRRQ-CK_mQs9l.js → diagram-2AECGRRQ-C8R_FKFE.js} +1 -1
- package/dist/webdist/assets/{diagram-5GNKFQAL-MBl66jsh.js → diagram-5GNKFQAL-Cy3ObA7-.js} +1 -1
- package/dist/webdist/assets/{diagram-KO2AKTUF-IxjaUqTu.js → diagram-KO2AKTUF-BKMSyIfH.js} +1 -1
- package/dist/webdist/assets/{diagram-LMA3HP47-Cc_fuuLo.js → diagram-LMA3HP47-M3eYUN5j.js} +1 -1
- package/dist/webdist/assets/{diagram-OG6HWLK6-DvprGLFT.js → diagram-OG6HWLK6-9mfuWNo6.js} +1 -1
- package/dist/webdist/assets/dialog-DTDvWQ5-.js +1 -0
- package/dist/webdist/assets/{erDiagram-TEJ5UH35-BEebeQO0.js → erDiagram-TEJ5UH35-3pYBvVYw.js} +1 -1
- package/dist/webdist/assets/{flowDiagram-I6XJVG4X--NtrYHee.js → flowDiagram-I6XJVG4X-DkeUYo0c.js} +1 -1
- package/dist/webdist/assets/{folder-input-C5Td4Oz0.js → folder-input-CjdiPWWo.js} +1 -1
- package/dist/webdist/assets/{ganttDiagram-6RSMTGT7-DOx3A2YH.js → ganttDiagram-6RSMTGT7-Co8G6rQq.js} +1 -1
- package/dist/webdist/assets/{gitGraphDiagram-PVQCEYII-BEY69HKU.js → gitGraphDiagram-PVQCEYII-BeKTVG6x.js} +1 -1
- package/dist/webdist/assets/{index-Tpho8qZ0.js → index-BiJl342p.js} +17 -17
- package/dist/webdist/assets/index-CxonSCte.css +1 -0
- package/dist/webdist/assets/{index-tVO2x-Rw.js → index-MBZ7hSNo.js} +3 -3
- package/dist/webdist/assets/{infoDiagram-5YYISTIA-C4X5I5eI.js → infoDiagram-5YYISTIA-CSNZJB_2.js} +1 -1
- package/dist/webdist/assets/{ishikawaDiagram-YF4QCWOH-BhUZzSmP.js → ishikawaDiagram-YF4QCWOH-Bl5G3Tv8.js} +1 -1
- package/dist/webdist/assets/{journeyDiagram-JHISSGLW-R-rmKLZ-.js → journeyDiagram-JHISSGLW-8vGboHEi.js} +1 -1
- package/dist/webdist/assets/{kanban-definition-UN3LZRKU-DUcDGDiT.js → kanban-definition-UN3LZRKU-Exhgn-QL.js} +1 -1
- package/dist/webdist/assets/{linear-Cbr5iYFb.js → linear-BQ7-Rkhb.js} +1 -1
- package/dist/webdist/assets/{mermaid.core-DJVxydy1.js → mermaid.core-CQX56k_o.js} +4 -4
- package/dist/webdist/assets/{mindmap-definition-RKZ34NQL-BSOgl-Cn.js → mindmap-definition-RKZ34NQL-Bo7PZvAB.js} +1 -1
- package/dist/webdist/assets/{pencil-Blh_Q7or.js → pencil-D52zQ528.js} +1 -1
- package/dist/webdist/assets/{personas-Dm0JD8kn.js → personas-BvApKJbI.js} +23 -23
- package/dist/webdist/assets/{pieDiagram-4H26LBE5-BwQ854zg.js → pieDiagram-4H26LBE5-q8hQguI2.js} +1 -1
- package/dist/webdist/assets/{quadrantDiagram-W4KKPZXB-BOQGjhZD.js → quadrantDiagram-W4KKPZXB-D7oJYa2u.js} +1 -1
- package/dist/webdist/assets/{radix-DVGeLgPN.js → radix-DHuxYtIT.js} +1 -1
- package/dist/webdist/assets/refresh-cw-CCa9KASO.js +1 -0
- package/dist/webdist/assets/{requirementDiagram-4Y6WPE33-b3dNYy6K.js → requirementDiagram-4Y6WPE33-BB3AxfxX.js} +1 -1
- package/dist/webdist/assets/{rotate-ccw-B7QiZxpr.js → rotate-ccw-CjT25zbE.js} +1 -1
- package/dist/webdist/assets/{sankeyDiagram-5OEKKPKP-C26ntsbR.js → sankeyDiagram-5OEKKPKP-rBs95ARp.js} +1 -1
- package/dist/webdist/assets/{sequenceDiagram-3UESZ5HK-Bp8i1DIR.js → sequenceDiagram-3UESZ5HK-Dl8lIjVG.js} +1 -1
- package/dist/webdist/assets/{star-BCxsXqcv.js → star-CGoRw01k.js} +1 -1
- package/dist/webdist/assets/{stateDiagram-AJRCARHV-CmZpIELB.js → stateDiagram-AJRCARHV-CLoQmP-w.js} +1 -1
- package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-ByjTcwsY.js +1 -0
- package/dist/webdist/assets/{timeline-definition-PNZ67QCA-slNuxmat.js → timeline-definition-PNZ67QCA-xQjF3Uja.js} +1 -1
- package/dist/webdist/assets/{trash-2-DGVXsIsP.js → trash-2-DtSyrOcz.js} +1 -1
- package/dist/webdist/assets/useIsDesktop-BFaxGM2l.js +1 -0
- package/dist/webdist/assets/{vennDiagram-CIIHVFJN-Lf4xPS3i.js → vennDiagram-CIIHVFJN-CAcPzo7k.js} +1 -1
- package/dist/webdist/assets/{wardley-L42UT6IY-DbEeYkcX.js → wardley-L42UT6IY-BPakyqHF.js} +1 -1
- package/dist/webdist/assets/{wardleyDiagram-YWT4CUSO-WNGbDcCj.js → wardleyDiagram-YWT4CUSO-DFeQJlAo.js} +1 -1
- package/dist/webdist/assets/wrench-BhEqkhsG.js +1 -0
- package/dist/webdist/assets/{xychartDiagram-2RQKCTM6-D2kBZ8cG.js → xychartDiagram-2RQKCTM6-CmW19GSM.js} +1 -1
- package/dist/webdist/index.html +3 -3
- package/package.json +1 -1
- package/dist/webdist/assets/AgentEditPage-DLuckXeR.js +0 -1
- package/dist/webdist/assets/CustomizeScreen-DoVGTM4C.js +0 -4
- package/dist/webdist/assets/DeveloperScreen-BJ7m4ZxK.js +0 -1
- package/dist/webdist/assets/EnginesScreen-D3b9VNx0.js +0 -7
- package/dist/webdist/assets/ModelDetailDialog-M2tPWvP4.js +0 -1
- package/dist/webdist/assets/ModelDirs-CaIf1TUh.js +0 -1
- package/dist/webdist/assets/ModelsScreen--sPDS_sx.js +0 -2
- package/dist/webdist/assets/SettingsScreen-lBpo_MAD.js +0 -1
- package/dist/webdist/assets/SkillEditPage-B5S9Gtlh.js +0 -1
- package/dist/webdist/assets/WorkspaceScreen-Cpm-gLG1.js +0 -1
- package/dist/webdist/assets/channel-BB6NPD_B.js +0 -1
- package/dist/webdist/assets/check-BLFw3EpE.js +0 -1
- package/dist/webdist/assets/circle-check-ByN99MCf.js +0 -1
- package/dist/webdist/assets/classDiagram-4FO5ZUOK-DwCs4wFr.js +0 -1
- package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-DwCs4wFr.js +0 -1
- package/dist/webdist/assets/collapsible-B_M28W08.js +0 -1
- package/dist/webdist/assets/common-Cy1uxtS_.js +0 -1
- package/dist/webdist/assets/copy-button-DgYGL35x.js +0 -1
- package/dist/webdist/assets/dialog-d6eLRBbl.js +0 -1
- package/dist/webdist/assets/index-B8H9eSFq.css +0 -1
- package/dist/webdist/assets/plus-D4IwdkJ3.js +0 -1
- package/dist/webdist/assets/refresh-cw-BVSLL9xa.js +0 -1
- package/dist/webdist/assets/save-DI4M5kP-.js +0 -1
- package/dist/webdist/assets/skeleton-D6toQA7p.js +0 -1
- package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-CswfYrBO.js +0 -1
- package/dist/webdist/assets/vram-DVAmNgRC.js +0 -1
- package/dist/webdist/assets/wrench-DzoqtmhJ.js +0 -1
package/README.md
CHANGED
|
@@ -177,8 +177,8 @@ the detail:
|
|
|
177
177
|
- **Saved per-model profiles, per engine** — tune once per (model, engine) pair, so
|
|
178
178
|
switching engines (or between two installs of the same engine, e.g. a fork) never
|
|
179
179
|
overwrites another engine's tuning for the same model.
|
|
180
|
-
- **Configurable VRAM headroom** (Settings →
|
|
181
|
-
how much VRAM to keep free for other GPU workloads instead of a fixed margin.
|
|
180
|
+
- **Configurable VRAM headroom** (Settings → Models & loading → Advanced, 300 MB–2 GB, default
|
|
181
|
+
1 GB) — tell auto-tune how much VRAM to keep free for other GPU workloads instead of a fixed margin.
|
|
182
182
|
|
|
183
183
|
</details>
|
|
184
184
|
|
|
@@ -216,7 +216,7 @@ the detail:
|
|
|
216
216
|
in every chat with no restart. A **Research** persona forces multi-step web search and cites sources inline.
|
|
217
217
|
- **Tool-call approval gate** — every tool call asks for your approval by default before it runs,
|
|
218
218
|
with **Deny**, **Allow**, **Allow for this chat**, or **Always Allow** on an inline bar above the
|
|
219
|
-
composer. Set per-tool defaults globally from
|
|
219
|
+
composer. Set per-tool defaults globally from Settings → Tools & safety.
|
|
220
220
|
|
|
221
221
|
</details>
|
|
222
222
|
|
|
@@ -255,7 +255,7 @@ curl http://127.0.0.1:6996/v1/chat/completions \
|
|
|
255
255
|
- **Anthropic-compatible** `/v1/messages` — including **tool use and streaming** — which powers
|
|
256
256
|
Claude Code below. No other local host offers this.
|
|
257
257
|
- **Structured output** — constrain any response to a **GBNF grammar** (or JSON shape).
|
|
258
|
-
- **API-key auth** you can require when sharing over a LAN (Settings → Network).
|
|
258
|
+
- **API-key auth** you can require when sharing over a LAN (Settings → Network & sharing).
|
|
259
259
|
|
|
260
260
|
**The gateway loads models for you.** Most local hosts make you load a model first, then call it.
|
|
261
261
|
TurboLLM's gateway reads the `model` field of any incoming request, **fuzzy-matches it to your
|
|
@@ -267,7 +267,7 @@ coding model, a vision model, and an embedder just names each one and it works
|
|
|
267
267
|
`opencode`, `kilo`, `openclaw`, and `hermes` — each gets pointed at TurboLLM the way that tool
|
|
268
268
|
expects (config file merge, or its own CLI command) instead of a manual copy-paste setup. Inside
|
|
269
269
|
Claude Code, `/model` lists your local models directly (with **Auto Model Swap** on in Settings →
|
|
270
|
-
|
|
270
|
+
Models & loading) so you can switch mid-session instead of only at launch.
|
|
271
271
|
|
|
272
272
|
</details>
|
|
273
273
|
|
|
@@ -285,7 +285,7 @@ fight for memory (and one usually OOMs). TurboLLM can hand the GPU over automati
|
|
|
285
285
|
It's **push-based, not polling** — ComfyUI signals TurboLLM the moment a job starts/ends, so the
|
|
286
286
|
handoff is immediate and deterministic (the model is gone *before* ComfyUI executes).
|
|
287
287
|
|
|
288
|
-
**One-time setup** (Settings → ComfyUI): turn on **Pause for ComfyUI**, enter your ComfyUI folder
|
|
288
|
+
**One-time setup** (Settings → Network & sharing → ComfyUI): turn on **Pause for ComfyUI**, enter your ComfyUI folder
|
|
289
289
|
(the one containing `custom_nodes`), click **Install gate** (it writes a small custom node wired to
|
|
290
290
|
this daemon), then **restart ComfyUI** once. The panel shows a live indicator (rendering / idle /
|
|
291
291
|
connected); **Remove** undoes it.
|
|
@@ -333,7 +333,7 @@ daemon any time with **Ctrl+C**.
|
|
|
333
333
|
No other local-LLM app lets you run **whatever inference engine you want**. TurboLLM treats
|
|
334
334
|
the engine as a swappable component.
|
|
335
335
|
|
|
336
|
-
**Add a custom engine** (Engines screen → **Add engine**):
|
|
336
|
+
**Add a custom engine** (Engines screen → **Add your own engine**):
|
|
337
337
|
|
|
338
338
|
1. Compile or download any `llama-server`-compatible binary — stock
|
|
339
339
|
[llama.cpp](https://github.com/ggml-org/llama.cpp), a community fork, or your own build.
|
|
@@ -398,13 +398,14 @@ any OpenAI- or Anthropic-compatible tool (Open WebUI, Kilo Code, opencode, …).
|
|
|
398
398
|
## Use it from any device on your network
|
|
399
399
|
|
|
400
400
|
The UI runs in the browser, so any phone, tablet, or laptop on your LAN can use the model on
|
|
401
|
-
your GPU box
|
|
401
|
+
your GPU box — every screen is responsive down to phone widths, with the desktop layout
|
|
402
|
+
untouched:
|
|
402
403
|
|
|
403
404
|
```bash
|
|
404
405
|
turbollm --addr 0.0.0.0:6996 # bind all interfaces, then open http://<your-ip>:6996
|
|
405
406
|
```
|
|
406
407
|
|
|
407
|
-
Turn on **Require API key** in Settings → Network when you expose it.
|
|
408
|
+
Turn on **Require API key** in Settings → Network & sharing when you expose it.
|
|
408
409
|
|
|
409
410
|
---
|
|
410
411
|
|
package/dist/cli.js
CHANGED
|
@@ -8086,7 +8086,7 @@ import { Agent, setGlobalDispatcher } from "undici";
|
|
|
8086
8086
|
// src/api/routes.ts
|
|
8087
8087
|
import { streamSSE as streamSSE2 } from "hono/streaming";
|
|
8088
8088
|
import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync10, readdirSync as readdirSync8, realpathSync, rmSync as rmSync11, statSync as statSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
8089
|
-
import { basename as basename3, dirname as dirname9, join as join24, resolve
|
|
8089
|
+
import { basename as basename3, dirname as dirname9, join as join24, resolve } from "path";
|
|
8090
8090
|
|
|
8091
8091
|
// src/comfyui/gate-template.ts
|
|
8092
8092
|
var GATE_VERSION = 2;
|
|
@@ -11722,18 +11722,19 @@ function registerApi(app2, d) {
|
|
|
11722
11722
|
}
|
|
11723
11723
|
});
|
|
11724
11724
|
app2.get("/api/v1/fs/browse", (c) => {
|
|
11725
|
-
|
|
11725
|
+
if (!isLocalRequest(c, d))
|
|
11726
|
+
return err2(c, 403, "forbidden", "Browsing the filesystem is only available on the machine running TurboLLM.");
|
|
11726
11727
|
const raw = (c.req.query("path") ?? "").trim();
|
|
11727
|
-
|
|
11728
|
+
if (raw === FS_DRIVES_ROOT && process.platform === "win32") {
|
|
11729
|
+
return c.json({ path: FS_DRIVES_ROOT, parent: null, entries: listWindowsDrives() });
|
|
11730
|
+
}
|
|
11731
|
+
const target = raw ? resolve(raw) : homedir4();
|
|
11728
11732
|
let real;
|
|
11729
11733
|
try {
|
|
11730
11734
|
real = realpathSync(target);
|
|
11731
11735
|
} catch {
|
|
11732
11736
|
real = target;
|
|
11733
11737
|
}
|
|
11734
|
-
if (!isWithinHome(real, home)) {
|
|
11735
|
-
return err2(c, 403, "path_outside_home", "That folder is outside your home directory.");
|
|
11736
|
-
}
|
|
11737
11738
|
let entries;
|
|
11738
11739
|
try {
|
|
11739
11740
|
entries = readdirSync8(real, { withFileTypes: true }).filter((d2) => !d2.name.startsWith(".")).map((d2) => {
|
|
@@ -11750,8 +11751,8 @@ function registerApi(app2, d) {
|
|
|
11750
11751
|
} catch {
|
|
11751
11752
|
return err2(c, 400, "fs_read_failed", "Could not read that folder (permission denied or not a directory).");
|
|
11752
11753
|
}
|
|
11753
|
-
const parentDir =
|
|
11754
|
-
const parent = parentDir
|
|
11754
|
+
const parentDir = dirname9(real);
|
|
11755
|
+
const parent = parentDir === real ? process.platform === "win32" ? FS_DRIVES_ROOT : null : parentDir;
|
|
11755
11756
|
return c.json({ path: real, parent, entries });
|
|
11756
11757
|
});
|
|
11757
11758
|
app2.post("/api/v1/engine/start", async (c) => {
|
|
@@ -12644,17 +12645,17 @@ function readTail2(path, n) {
|
|
|
12644
12645
|
return [];
|
|
12645
12646
|
}
|
|
12646
12647
|
}
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12648
|
+
var FS_DRIVES_ROOT = "::drives";
|
|
12649
|
+
function listWindowsDrives() {
|
|
12650
|
+
const drives = [];
|
|
12651
|
+
for (let i = 65; i <= 90; i++) {
|
|
12652
|
+
const root = `${String.fromCharCode(i)}:\\`;
|
|
12653
|
+
try {
|
|
12654
|
+
if (existsSync21(root)) drives.push({ name: root, path: root, isDir: true });
|
|
12655
|
+
} catch {
|
|
12656
|
+
}
|
|
12653
12657
|
}
|
|
12654
|
-
|
|
12655
|
-
function isWithinHome(p, home) {
|
|
12656
|
-
if (p === home) return true;
|
|
12657
|
-
return p.startsWith(home.endsWith(sep) ? home : home + sep);
|
|
12658
|
+
return drives;
|
|
12658
12659
|
}
|
|
12659
12660
|
function getLanIp() {
|
|
12660
12661
|
const nets = networkInterfaces2();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{j as e}from"./radix-DHuxYtIT.js";import{u as M,b as W,r as b}from"./vendor-BE0HADM8.js";import{u as $,b as G,c as H,d as Y,e as J,a as E,B as y,f as B,t as h,A as C}from"./index-MBZ7hSNo.js";import{f as U}from"./chat-api-Dz6qvO1a.js";import{f as V,a as X}from"./agent-api-D3hMsrHk.js";import{P as z}from"./personas-BvApKJbI.js";import{C as Z}from"./chevron-left-Bm2f38an.js";import{R as ee}from"./rotate-ccw-CjT25zbE.js";import{T as te}from"./trash-2-DtSyrOcz.js";import{C as se}from"./chevron-right-DGQJG4QN.js";const ne=()=>({name:"",description:"",systemPrompt:"",skillIds:[],tools:[]});function oe(s){const d=[],x=new Map;for(const n of s){const o=/^mcp__([^_]+(?:_[^_]+)*)__/.exec(n.name);if(!o){d.push(n);continue}const i=o[1],p=/^\[([^\]]+)\]/.exec(n.description),c=p?p[1]:i.replace(/_/g," ");x.has(i)||x.set(i,{key:i,label:c,tools:[]}),x.get(i).tools.push(n)}return{builtin:d,groups:[...x.values()].sort((n,o)=>n.label.localeCompare(o.label))}}function ae(s){return s.replace(/^mcp__[^_]+(?:_[^_]+)*__/,"")}function le(s){return s.replace(/^\[[^\]]+\]\s*/,"")}function q({tool:s,checked:d,onToggle:x}){return e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-[12px]",children:[e.jsx("input",{type:"checkbox",className:"mt-0.5",checked:d,onChange:x}),e.jsxs("span",{className:"flex flex-col",children:[e.jsx("span",{className:"font-mono text-ink",children:ae(s.name)}),s.description&&e.jsx("span",{className:"text-faint",children:le(s.description)})]})]})}function re({group:s,selected:d,onToggleAll:x,onToggleOne:n}){const[o,i]=b.useState(!1),p=s.tools.map(l=>l.name),c=p.filter(l=>d.has(l)).length,a=c===p.length,f=c>0&&!a,u=b.useRef(null);return b.useEffect(()=>{u.current&&(u.current.indeterminate=f)},[f]),e.jsxs("div",{className:"rounded-md border border-border",children:[e.jsxs("div",{className:"flex items-center gap-2 px-2.5 py-2",children:[e.jsx("input",{ref:u,type:"checkbox",checked:a,onChange:()=>x(p,!a)}),e.jsxs("button",{type:"button",onClick:()=>i(l=>!l),className:"flex flex-1 items-center gap-1.5 text-left text-[13px] text-ink",children:[e.jsx(se,{size:12,className:B("shrink-0 text-faint transition-transform",o&&"rotate-90")}),s.label,e.jsxs("span",{className:"text-[11px] text-faint",children:["(",c,"/",p.length,")"]})]})]}),o&&e.jsx("div",{className:"flex flex-col gap-1.5 border-t border-border px-3 py-2 pl-9",children:s.tools.map(l=>e.jsx(q,{tool:l,checked:d.has(l.name),onToggle:()=>n(l.name)},l.name))})]})}function ie({tools:s,selected:d,onChange:x}){const n=new Set(d),{builtin:o,groups:i}=oe(s),p=a=>x(n.has(a)?d.filter(f=>f!==a):[...d,a]),c=(a,f)=>{const u=d.filter(l=>!a.includes(l));x(f?[...u,...a]:u)};return s.length===0?e.jsx("p",{className:"text-[12px] text-faint",children:"No tools available yet."}):e.jsxs("div",{className:"flex flex-col gap-2",children:[o.length>0&&e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:o.map(a=>e.jsx(q,{tool:a,checked:n.has(a.name),onToggle:()=>p(a.name)},a.name))}),i.map(a=>e.jsx(re,{group:a,selected:n,onToggleAll:c,onToggleOne:p},a.key))]})}function ke(){const{agentId:s="new"}=M(),d=W(),x=$(),n=s==="new",o=!n&&z.some(t=>t.id===s),i=o?z.find(t=>t.id===s):void 0,p=G(),c=!n&&!o?(p.data??[]).find(t=>t.id===s):void 0,a=H(),f=Y(),u=J(),l=o?f.data?.[s]:void 0,_=E({queryKey:X.list(),queryFn:V,staleTime:0}),k=_.data??[],I=E({queryKey:["available-tools"],queryFn:U}),j=I.data??[],[m,g]=b.useState(ne()),[S,T]=b.useState(!1),[A,P]=b.useState(!1),[D,w]=b.useState(!1),[R,L]=b.useState("skills");n&&!S&&(k.length||j.length)&&(g(t=>({...t,skillIds:k.map(r=>r.id),tools:j.map(r=>r.name)})),T(!0)),!n&&!o&&!S&&c&&(g({name:c.name,description:c.description,systemPrompt:c.systemPrompt,skillIds:c.skillIds,tools:c.tools}),T(!0)),o&&!S&&i&&f.isSuccess&&(k.length||j.length)&&(g({name:l?.name??i.name,description:l?.description??i.description,systemPrompt:l?.systemPrompt??i.systemPrompt,skillIds:l?.skillIds??k.map(t=>t.id),tools:l?.tools??j.map(t=>t.name)}),T(!0));const N=()=>d("/customize"),Q=t=>g(r=>({...r,skillIds:r.skillIds.includes(t)?r.skillIds.filter(v=>v!==t):[...r.skillIds,t]})),O=()=>{if(!m.name.trim()){h.error("Name is required.");return}P(!0);const t={name:m.name.trim(),description:m.description.trim(),systemPrompt:m.systemPrompt,skillIds:m.skillIds,tools:m.tools};if(o){u.save.mutate({id:s,override:t},{onSuccess:()=>{h.success("Agent saved."),N()},onError:v=>{h.error(v instanceof C?v.message:"Could not save agent."),P(!1)}});return}const r={onSuccess:()=>{x.invalidateQueries({queryKey:["chat-agents"]}),h.success(n?"Agent created.":"Agent saved."),N()},onError:v=>{h.error(v instanceof C?v.message:"Could not save agent."),P(!1)}};n?a.add.mutate(t,r):a.update.mutate({id:s,patch:t},r)},F=()=>{u.reset.mutate(s,{onSuccess:()=>{h.success("Reset to default."),i&&g({name:i.name,description:i.description,systemPrompt:i.systemPrompt,skillIds:k.map(t=>t.id),tools:j.map(t=>t.name)})},onError:t=>h.error(t instanceof C?t.message:"Could not reset agent.")})},K=()=>{a.remove.mutate(s,{onSuccess:()=>{h.success("Agent deleted."),N()},onError:t=>h.error(t instanceof C?t.message:"Could not delete agent.")})};return!n&&!o&&p.isSuccess&&!c?e.jsxs("div",{className:"flex w-full flex-col items-center gap-3 px-8 py-16",children:[e.jsx("p",{className:"text-[14px] text-muted",children:"That agent no longer exists."}),e.jsx(y,{size:"sm",variant:"outline",onClick:N,children:"Back to agents"})]}):e.jsxs("div",{className:"flex w-full max-w-4xl flex-col gap-5 px-4 py-6 md:px-8",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",onClick:N,className:"text-faint hover:text-ink",title:"Back to agents",children:e.jsx(Z,{size:18})}),e.jsx("span",{className:"text-[15px] font-medium text-ink",children:n?"New agent":o?l?"Edit agent (modified built-in)":"Edit agent (built-in)":"Edit agent"}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[o&&e.jsxs(y,{size:"sm",variant:"outline",onClick:F,disabled:u.reset.isPending,children:[e.jsx(ee,{size:13})," Reset to default"]}),e.jsx(y,{size:"sm",variant:"outline",onClick:N,children:"Cancel"}),e.jsx(y,{size:"sm",onClick:O,disabled:A||!m.name.trim(),children:A?"Saving…":"Save"})]})]}),o&&e.jsx("p",{className:"rounded-md border border-border bg-panel px-3 py-2 text-[12px] text-muted",children:"Built-in agents can be edited in place — Reset to default discards your changes and restores TurboLLM's original prompt and access."}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"Name"}),e.jsx("input",{className:"rounded-md border border-border bg-bg px-3 py-1.5 text-[13px] text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"Release Notes Writer",value:m.name,onChange:t=>g(r=>({...r,name:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"Description"}),e.jsx("input",{className:"rounded-md border border-border bg-bg px-3 py-1.5 text-[13px] text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"What this agent is for, in one line",value:m.description,onChange:t=>g(r=>({...r,description:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx("label",{className:"text-[12px] font-medium text-muted",children:"System prompt"}),e.jsx("textarea",{className:"min-h-[160px] resize-y rounded-md border border-border bg-bg px-3 py-2 font-mono text-[12px] leading-relaxed text-ink outline-none focus:border-accent placeholder:text-faint",placeholder:"You are…",value:m.systemPrompt,onChange:t=>g(r=>({...r,systemPrompt:t.target.value}))})]}),e.jsxs("div",{className:"flex flex-col gap-2.5",children:[e.jsx("div",{className:"inline-flex w-fit rounded-md border border-border p-0.5",children:["skills","tools"].map(t=>e.jsx("button",{type:"button",onClick:()=>L(t),className:B("rounded px-3 py-1.5 text-[13px] font-medium transition-colors",R===t?"bg-accent/12 text-accent":"text-muted hover:text-ink"),children:t==="skills"?`Skills (${m.skillIds.length})`:`Tools (${m.tools.length})`},t))}),R==="skills"?_.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):k.length===0?e.jsx("p",{className:"text-[12px] text-faint",children:"No skills yet — create one under Customize → Skills."}):e.jsx("div",{className:"flex flex-col gap-2 rounded-md border border-border bg-panel-2 p-3",children:k.map(t=>e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-[13px]",children:[e.jsx("input",{type:"checkbox",className:"mt-0.5",checked:m.skillIds.includes(t.id),onChange:()=>Q(t.id)}),e.jsxs("span",{className:"flex flex-col",children:[e.jsx("span",{className:"text-ink",children:t.name}),t.description&&e.jsx("span",{className:"text-[12px] text-muted",children:t.description})]})]},t.id))}):I.isLoading?e.jsx("p",{className:"text-[12px] text-faint",children:"Loading…"}):e.jsx(ie,{tools:j,selected:m.tools,onChange:t=>g(r=>({...r,tools:t}))})]}),!n&&!o&&(D?e.jsxs("div",{className:"flex items-center gap-2 self-start rounded-md border border-border bg-panel p-2 text-[12px]",children:[e.jsx("span",{className:"flex-1 text-muted",children:"Delete this agent?"}),e.jsx("button",{type:"button",onClick:K,className:"rounded px-2 py-1 text-[color:var(--err)] hover:bg-[color:color-mix(in_srgb,var(--err)_12%,transparent)]",children:"Delete"}),e.jsx("button",{type:"button",onClick:()=>w(!1),className:"rounded px-2 py-1 text-faint hover:text-ink",children:"Cancel"})]}):e.jsxs("button",{type:"button",onClick:()=>w(!0),className:"flex items-center gap-1.5 self-start text-[12px] text-faint hover:text-[color:var(--err)]",children:[e.jsx(te,{size:13})," Delete agent"]}))]})}export{ke as AgentEditPage};
|