turbollm 1.7.1 → 1.7.3
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 +16 -14
- package/bin/turbollm.mjs +29 -25
- package/dist/chunk-TPYU5ZAX.js +175 -0
- package/dist/cli.js +2232 -1971
- package/dist/distiller-UROKYEBN.js +9 -0
- package/dist/webdist/assets/AgentEditPage-DLuckXeR.js +1 -0
- package/dist/webdist/assets/ChatScreen-BOZjtqGu.js +65 -0
- package/dist/webdist/assets/CustomizeScreen-DoVGTM4C.js +4 -0
- package/dist/webdist/assets/DeveloperScreen-BJ7m4ZxK.js +1 -0
- package/dist/webdist/assets/EnginesScreen-D3b9VNx0.js +7 -0
- package/dist/webdist/assets/{MessageBubble-DG7ZWPCw.js → MessageBubble-mJwFfOab.js} +15 -16
- package/dist/webdist/assets/ModelDetailDialog-M2tPWvP4.js +1 -0
- package/dist/webdist/assets/ModelDirs-CaIf1TUh.js +1 -0
- package/dist/webdist/assets/{ModelsScreen-Bl0OP-BY.js → ModelsScreen--sPDS_sx.js} +2 -2
- package/dist/webdist/assets/SettingsScreen-lBpo_MAD.js +1 -0
- package/dist/webdist/assets/SkillEditPage-B5S9Gtlh.js +1 -0
- package/dist/webdist/assets/WorkspaceScreen-Cpm-gLG1.js +1 -0
- package/dist/webdist/assets/agent-api-B3GXwr4Y.js +1 -0
- package/dist/webdist/assets/{arc-DVrcAJc9.js → arc-CRcL8nar.js} +1 -1
- package/dist/webdist/assets/{architectureDiagram-3BPJPVTR-BaL05OA8.js → architectureDiagram-3BPJPVTR-BmOKGMd0.js} +1 -1
- package/dist/webdist/assets/{blockDiagram-GPEHLZMM-D8aCVMG0.js → blockDiagram-GPEHLZMM-C4vusmQ-.js} +1 -1
- package/dist/webdist/assets/{c4Diagram-AAUBKEIU-Bpj96pxf.js → c4Diagram-AAUBKEIU-DdY0YXKs.js} +1 -1
- package/dist/webdist/assets/channel-BB6NPD_B.js +1 -0
- package/dist/webdist/assets/chat-api-DrMO_g5m.js +3 -0
- package/dist/webdist/assets/check-BLFw3EpE.js +1 -0
- package/dist/webdist/assets/chevron-left-CfyO2AXW.js +1 -0
- package/dist/webdist/assets/chevron-right--1OIa5uV.js +1 -0
- package/dist/webdist/assets/{chunk-2J33WTMH-DA6mFoN-.js → chunk-2J33WTMH-DzCJsNN1.js} +1 -1
- package/dist/webdist/assets/{chunk-4BX2VUAB-B_fmKUNu.js → chunk-4BX2VUAB-BNPfO47j.js} +1 -1
- package/dist/webdist/assets/{chunk-55IACEB6-3cWMWgYr.js → chunk-55IACEB6-_vELiE2B.js} +1 -1
- package/dist/webdist/assets/{chunk-727SXJPM-Cwb5Sv7F.js → chunk-727SXJPM-CsQCgUxY.js} +1 -1
- package/dist/webdist/assets/{chunk-AQP2D5EJ-7QIg1x7-.js → chunk-AQP2D5EJ-G0waQ7sq.js} +1 -1
- package/dist/webdist/assets/{chunk-FMBD7UC4-D_Qfl5Jc.js → chunk-FMBD7UC4-CkNtvlrw.js} +1 -1
- package/dist/webdist/assets/{chunk-ND2GUHAM-pgqeq7NP.js → chunk-ND2GUHAM-DGnw4n1I.js} +1 -1
- package/dist/webdist/assets/{chunk-QZHKN3VN-EUqDaxxx.js → chunk-QZHKN3VN-BpJ4HH0V.js} +1 -1
- package/dist/webdist/assets/circle-check-ByN99MCf.js +1 -0
- package/dist/webdist/assets/classDiagram-4FO5ZUOK-DwCs4wFr.js +1 -0
- package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-DwCs4wFr.js +1 -0
- package/dist/webdist/assets/collapsible-B_M28W08.js +1 -0
- package/dist/webdist/assets/{common-Dn21s6g5.js → common-Cy1uxtS_.js} +1 -1
- package/dist/webdist/assets/{copy-button-D6JkFOO9.js → copy-button-DgYGL35x.js} +1 -1
- package/dist/webdist/assets/{cose-bilkent-S5V4N54A-BzxdTTj-.js → cose-bilkent-S5V4N54A-fol9bGNP.js} +1 -1
- package/dist/webdist/assets/{dagre-BM42HDAG-YQn0mFsV.js → dagre-BM42HDAG-kyg4YiiE.js} +1 -1
- package/dist/webdist/assets/{diagram-2AECGRRQ-DtSRGaVH.js → diagram-2AECGRRQ-CK_mQs9l.js} +1 -1
- package/dist/webdist/assets/{diagram-5GNKFQAL-Dko3hF44.js → diagram-5GNKFQAL-MBl66jsh.js} +1 -1
- package/dist/webdist/assets/{diagram-KO2AKTUF-CQAm-tYF.js → diagram-KO2AKTUF-IxjaUqTu.js} +1 -1
- package/dist/webdist/assets/{diagram-LMA3HP47-gz5BqFhM.js → diagram-LMA3HP47-Cc_fuuLo.js} +1 -1
- package/dist/webdist/assets/{diagram-OG6HWLK6-BqsSoNIn.js → diagram-OG6HWLK6-DvprGLFT.js} +1 -1
- package/dist/webdist/assets/{dialog-B_Yd5di3.js → dialog-d6eLRBbl.js} +1 -1
- package/dist/webdist/assets/{erDiagram-TEJ5UH35-D8rPsHw-.js → erDiagram-TEJ5UH35-BEebeQO0.js} +1 -1
- package/dist/webdist/assets/{flowDiagram-I6XJVG4X-DhGWyp50.js → flowDiagram-I6XJVG4X--NtrYHee.js} +1 -1
- package/dist/webdist/assets/folder-input-C5Td4Oz0.js +1 -0
- package/dist/webdist/assets/{ganttDiagram-6RSMTGT7-WEinw7mP.js → ganttDiagram-6RSMTGT7-DOx3A2YH.js} +1 -1
- package/dist/webdist/assets/{gitGraphDiagram-PVQCEYII-BJ-BzBFO.js → gitGraphDiagram-PVQCEYII-BEY69HKU.js} +1 -1
- package/dist/webdist/assets/index-B8H9eSFq.css +1 -0
- package/dist/webdist/assets/{index-DHmOrvk5.js → index-Tpho8qZ0.js} +1 -1
- package/dist/webdist/assets/index-tVO2x-Rw.js +10 -0
- package/dist/webdist/assets/{infoDiagram-5YYISTIA-BA9oHMe2.js → infoDiagram-5YYISTIA-C4X5I5eI.js} +1 -1
- package/dist/webdist/assets/{ishikawaDiagram-YF4QCWOH-BJ5McdEJ.js → ishikawaDiagram-YF4QCWOH-BhUZzSmP.js} +1 -1
- package/dist/webdist/assets/{journeyDiagram-JHISSGLW-Bu6WJyQy.js → journeyDiagram-JHISSGLW-R-rmKLZ-.js} +1 -1
- package/dist/webdist/assets/{kanban-definition-UN3LZRKU-C_Y8cJ9D.js → kanban-definition-UN3LZRKU-DUcDGDiT.js} +1 -1
- package/dist/webdist/assets/{linear-BssoHTW-.js → linear-Cbr5iYFb.js} +1 -1
- package/dist/webdist/assets/{mermaid.core-C331Qhyf.js → mermaid.core-DJVxydy1.js} +4 -4
- package/dist/webdist/assets/{mindmap-definition-RKZ34NQL-B6NCYWu3.js → mindmap-definition-RKZ34NQL-BSOgl-Cn.js} +1 -1
- package/dist/webdist/assets/pencil-Blh_Q7or.js +1 -0
- package/dist/webdist/assets/personas-Dm0JD8kn.js +305 -0
- package/dist/webdist/assets/{pieDiagram-4H26LBE5-CV23vNlv.js → pieDiagram-4H26LBE5-BwQ854zg.js} +1 -1
- package/dist/webdist/assets/plus-D4IwdkJ3.js +1 -0
- package/dist/webdist/assets/{quadrantDiagram-W4KKPZXB-DxWTWFL7.js → quadrantDiagram-W4KKPZXB-BOQGjhZD.js} +1 -1
- package/dist/webdist/assets/{radix-BY-fjzwm.js → radix-DVGeLgPN.js} +2 -2
- package/dist/webdist/assets/{refresh-cw-Cl7RshCH.js → refresh-cw-BVSLL9xa.js} +1 -1
- package/dist/webdist/assets/{requirementDiagram-4Y6WPE33-DRRulwpq.js → requirementDiagram-4Y6WPE33-b3dNYy6K.js} +1 -1
- package/dist/webdist/assets/rotate-ccw-B7QiZxpr.js +1 -0
- package/dist/webdist/assets/{sankeyDiagram-5OEKKPKP-BTBSg_uE.js → sankeyDiagram-5OEKKPKP-C26ntsbR.js} +1 -1
- package/dist/webdist/assets/{save-YXge1rTt.js → save-DI4M5kP-.js} +1 -1
- package/dist/webdist/assets/{sequenceDiagram-3UESZ5HK-HiTl9dyH.js → sequenceDiagram-3UESZ5HK-Bp8i1DIR.js} +1 -1
- package/dist/webdist/assets/{skeleton-BMhnZFjx.js → skeleton-D6toQA7p.js} +1 -1
- package/dist/webdist/assets/star-BCxsXqcv.js +1 -0
- package/dist/webdist/assets/{stateDiagram-AJRCARHV-SGw6a8ke.js → stateDiagram-AJRCARHV-CmZpIELB.js} +1 -1
- package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-CswfYrBO.js +1 -0
- package/dist/webdist/assets/{timeline-definition-PNZ67QCA-B_X3zBz0.js → timeline-definition-PNZ67QCA-slNuxmat.js} +1 -1
- package/dist/webdist/assets/{trash-2-BNQkpp4n.js → trash-2-DGVXsIsP.js} +1 -1
- package/dist/webdist/assets/{vendor-W5GIuFcv.js → vendor-BE0HADM8.js} +1 -1
- package/dist/webdist/assets/{vennDiagram-CIIHVFJN-C8ibsbKD.js → vennDiagram-CIIHVFJN-Lf4xPS3i.js} +1 -1
- package/dist/webdist/assets/{vram-D4ttIJVy.js → vram-DVAmNgRC.js} +1 -1
- package/dist/webdist/assets/{wardley-L42UT6IY-ClFBGt2Y.js → wardley-L42UT6IY-DbEeYkcX.js} +1 -1
- package/dist/webdist/assets/{wardleyDiagram-YWT4CUSO-1iaMKpVQ.js → wardleyDiagram-YWT4CUSO-WNGbDcCj.js} +1 -1
- package/dist/webdist/assets/wrench-DzoqtmhJ.js +1 -0
- package/dist/webdist/assets/{xychartDiagram-2RQKCTM6-FIIVikoF.js → xychartDiagram-2RQKCTM6-D2kBZ8cG.js} +1 -1
- package/dist/webdist/index.html +4 -4
- package/package.json +2 -2
- package/dist/webdist/assets/AgentsScreen-BToQ_CZg.js +0 -2
- package/dist/webdist/assets/ChatScreen-B4T7fIcx.js +0 -65
- package/dist/webdist/assets/CustomizeScreen-IL-QlVq2.js +0 -4
- package/dist/webdist/assets/DeveloperScreen-DN-FWjXV.js +0 -1
- package/dist/webdist/assets/EnginesScreen-GZYaJJNx.js +0 -7
- package/dist/webdist/assets/ModelDetailDialog-DhCCmMnp.js +0 -1
- package/dist/webdist/assets/ModelDirs-D0d7xetP.js +0 -1
- package/dist/webdist/assets/SettingsScreen-DXy_TCXo.js +0 -1
- package/dist/webdist/assets/arrow-left-nmoUPZoB.js +0 -1
- package/dist/webdist/assets/channel-M9YFYffr.js +0 -1
- package/dist/webdist/assets/check-CD6cKVwJ.js +0 -1
- package/dist/webdist/assets/chevron-down-DgTSOyZG.js +0 -1
- package/dist/webdist/assets/chevron-right-BshRZEvM.js +0 -1
- package/dist/webdist/assets/circle-check-Dey3SdiG.js +0 -1
- package/dist/webdist/assets/circle-x-M54_eiYo.js +0 -1
- package/dist/webdist/assets/classDiagram-4FO5ZUOK-BtQ5UIn2.js +0 -1
- package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-BtQ5UIn2.js +0 -1
- package/dist/webdist/assets/collapsible-CwqYFc9v.js +0 -1
- package/dist/webdist/assets/index-B_WtFoLC.css +0 -1
- package/dist/webdist/assets/index-C-xjjrht.js +0 -10
- package/dist/webdist/assets/pencil-bwNY7waZ.js +0 -1
- package/dist/webdist/assets/personas-C_q63e_2.js +0 -75
- package/dist/webdist/assets/plus-12BmUfjg.js +0 -1
- package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-C7Pv9LnA.js +0 -1
- package/dist/webdist/assets/wrench-Chhk_zTw.js +0 -1
package/README.md
CHANGED
|
@@ -196,9 +196,11 @@ the detail:
|
|
|
196
196
|
the model draws when a comparison, trend, or hierarchy is genuinely worth a visual.
|
|
197
197
|
- **Live artifacts** — `html`, `svg`, and `mermaid` replies render as **sandboxed, offline
|
|
198
198
|
previews** shown as an image, with one-click export to **PNG / JPEG / SVG / animated GIF / HTML**.
|
|
199
|
-
- **
|
|
200
|
-
Creative · Research) per conversation, no prompt-wrangling required. The
|
|
201
|
-
produces polished, self-contained, previewable designs by default
|
|
199
|
+
- **Agents** — pick a style (Default · **Designer** · Concise · Detailed · Blunt · Formal · Tutor ·
|
|
200
|
+
Creative · Research · **Lite** · **Code**) per conversation, no prompt-wrangling required. The
|
|
201
|
+
**Designer** persona produces polished, self-contained, previewable designs by default; **Lite**
|
|
202
|
+
strips the hidden prompt to the bare minimum for the fastest responses. See below for editing
|
|
203
|
+
built-ins or creating your own.
|
|
202
204
|
- **Edit, regenerate, delete, copy** any message; **persistent, searchable conversations**
|
|
203
205
|
with rename, delete, and **auto-generated titles**, organized into **drag-resizable,
|
|
204
206
|
collapsible folders** you create/rename/move conversations into.
|
|
@@ -219,17 +221,17 @@ the detail:
|
|
|
219
221
|
</details>
|
|
220
222
|
|
|
221
223
|
<details>
|
|
222
|
-
<summary><strong>🤖
|
|
224
|
+
<summary><strong>🤖 Customize → Agents — edit any built-in, or build your own</strong></summary>
|
|
223
225
|
|
|
224
226
|
<br/>
|
|
225
227
|
|
|
226
|
-
- **
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
228
|
+
- **Edit any built-in agent in place** — system prompt, which shared skills it uses, and which
|
|
229
|
+
tools it may call — with a one-click **Reset** back to the original.
|
|
230
|
+
- **Create your own agent** from scratch: a name, description, and system prompt, plus a
|
|
231
|
+
checklist of which shared skills and which tools it's allowed to use (everything on by
|
|
232
|
+
default). Pick it from the same in-chat agent picker as the built-ins.
|
|
233
|
+
- **MCP tools grouped by server** in the tool checklist — one toggle selects or deselects an
|
|
234
|
+
entire server's tools at once, or expand it to pick individually.
|
|
233
235
|
|
|
234
236
|
</details>
|
|
235
237
|
|
|
@@ -446,7 +448,7 @@ Use `--config <file>` to point at an alternate config (its directory becomes the
|
|
|
446
448
|
|
|
447
449
|
## Requirements
|
|
448
450
|
|
|
449
|
-
- **Node.js 22 or newer** — enforced at startup with a clear message. <https://nodejs.org>
|
|
451
|
+
- **Node.js 22.13.0 or newer** — enforced at startup with a clear message. <https://nodejs.org>
|
|
450
452
|
- **Windows, macOS, or Linux.**
|
|
451
453
|
- A GPU is recommended but **not required** — a CPU build is provisioned as a fallback.
|
|
452
454
|
- On Windows, the first time the auto-downloaded `llama-server` runs, SmartScreen/Defender may
|
|
@@ -492,7 +494,7 @@ Prefer Open WebUI's chat breadth? It works great pointed at TurboLLM's OpenAI en
|
|
|
492
494
|
|
|
493
495
|
## Troubleshooting
|
|
494
496
|
|
|
495
|
-
- **`TurboLLM requires Node.js 22 or newer`** — upgrade Node: <https://nodejs.org>.
|
|
497
|
+
- **`TurboLLM requires Node.js 22.13.0 or newer`** — upgrade Node: <https://nodejs.org>.
|
|
496
498
|
- **Model won't load / OOM** — pick a smaller quant (the VRAM verdict warns you), lower GPU
|
|
497
499
|
offload, or close other GPU apps. Failures surface in the Engines screen with the engine log.
|
|
498
500
|
- **Windows Defender / SmartScreen prompt** — that's the upstream `llama-server` binary on
|
|
@@ -519,7 +521,7 @@ node dist/cli.js --port 6996
|
|
|
519
521
|
Frontend hot-reload: `cd web && npm run dev` (proxies `/api` and `/v1` to the daemon on
|
|
520
522
|
:6996).
|
|
521
523
|
|
|
522
|
-
**Stack:** Node ≥22 · TypeScript · Hono · `node:sqlite` · tsup — and a React 19 + Tailwind v4 +
|
|
524
|
+
**Stack:** Node ≥22.13 · TypeScript · Hono · `node:sqlite` · tsup — and a React 19 + Tailwind v4 +
|
|
523
525
|
shadcn/ui frontend. One TypeScript codebase, shipped as an npm package.
|
|
524
526
|
|
|
525
527
|
---
|
package/bin/turbollm.mjs
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Hand-written launcher shim — NOT bundled by tsup. It runs before the bundled
|
|
3
|
-
// daemon (dist/cli.js) loads, so it can do two things that must happen before
|
|
4
|
-
// node:sqlite is imported (the bundle hoists that import, emitting an experimental
|
|
5
|
-
// warning that PowerShell renders as a scary red error block on every run):
|
|
6
|
-
// 1. Guard the Node version with a friendly message (node:sqlite needs Node 22+
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Hand-written launcher shim — NOT bundled by tsup. It runs before the bundled
|
|
3
|
+
// daemon (dist/cli.js) loads, so it can do two things that must happen before
|
|
4
|
+
// node:sqlite is imported (the bundle hoists that import, emitting an experimental
|
|
5
|
+
// warning that PowerShell renders as a scary red error block on every run):
|
|
6
|
+
// 1. Guard the Node version with a friendly message (node:sqlite needs Node 22.13+ —
|
|
7
|
+
// that's when node:sqlite became available WITHOUT the --experimental-sqlite flag;
|
|
8
|
+
// on 22.5.0-22.12.x it's registered only behind that flag, so importing it bare
|
|
9
|
+
// throws ERR_UNKNOWN_BUILTIN_MODULE: "No such built-in module: node:sqlite"
|
|
10
|
+
// (GitHub #40) even though `node -v` reports 22.x).
|
|
11
|
+
// 2. Register a 'warning' filter that swallows the node:sqlite experimental notice
|
|
12
|
+
// while still printing every other warning.
|
|
13
|
+
// Then it hands off to the real CLI via dynamic import (same process; argv intact).
|
|
14
|
+
const [major, minor] = process.versions.node.split('.').map(Number)
|
|
15
|
+
if (major < 22 || (major === 22 && minor < 13)) {
|
|
16
|
+
process.stderr.write(
|
|
17
|
+
`TurboLLM requires Node.js 22.13.0 or newer (needs node:sqlite unflagged).\n` +
|
|
18
|
+
`You are running Node.js ${process.versions.node}.\n` +
|
|
19
|
+
`Please upgrade: https://nodejs.org\n`,
|
|
20
|
+
)
|
|
21
|
+
process.exit(1)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
process.on('warning', (w) => {
|
|
25
|
+
if (w.name === 'ExperimentalWarning' && /SQLite/i.test(w.message)) return
|
|
26
|
+
process.stderr.write(`${w.stack ?? `${w.name}: ${w.message}`}\n`)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
await import('../dist/cli.js')
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/agents/distiller.ts
|
|
4
|
+
import { readFileSync, readdirSync, statSync, existsSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
|
|
7
|
+
// src/engines/compat.ts
|
|
8
|
+
function engineAcceptsFormat(engineKind, format) {
|
|
9
|
+
if (engineKind === "mlx") return format === "mlx";
|
|
10
|
+
if (engineKind === "vllm") return format === "mlx";
|
|
11
|
+
return format === "gguf";
|
|
12
|
+
}
|
|
13
|
+
var ENGINE_MODEL_ALIAS = "default_model";
|
|
14
|
+
function engineModelAlias(engineKind) {
|
|
15
|
+
return engineKind === "mlx" || engineKind === "vllm" || engineKind === "sglang" ? ENGINE_MODEL_ALIAS : null;
|
|
16
|
+
}
|
|
17
|
+
var VENDOR_DISPLAY = {
|
|
18
|
+
nvidia: "NVIDIA",
|
|
19
|
+
amd: "AMD",
|
|
20
|
+
intel: "Intel",
|
|
21
|
+
apple: "Apple Silicon",
|
|
22
|
+
unknown: "no detected GPU"
|
|
23
|
+
};
|
|
24
|
+
var PLATFORM_DISPLAY = {
|
|
25
|
+
darwin: "macOS",
|
|
26
|
+
win32: "Windows",
|
|
27
|
+
linux: "Linux"
|
|
28
|
+
};
|
|
29
|
+
function platformName(p) {
|
|
30
|
+
return PLATFORM_DISPLAY[p] ?? p;
|
|
31
|
+
}
|
|
32
|
+
function platformReason(allowed) {
|
|
33
|
+
const names = allowed.map(platformName);
|
|
34
|
+
const joined = names.length <= 1 ? names.join("") : `${names.slice(0, -1).join(", ")} & ${names[names.length - 1]}`;
|
|
35
|
+
return `${joined} only`;
|
|
36
|
+
}
|
|
37
|
+
function evaluateVariant(p, r) {
|
|
38
|
+
if (r.platform && !r.platform.includes(p.platform)) {
|
|
39
|
+
return { ok: false, reason: platformReason(r.platform) };
|
|
40
|
+
}
|
|
41
|
+
if (r.arch && !r.arch.includes(p.arch)) {
|
|
42
|
+
return { ok: false, reason: `Needs ${r.arch.join(" / ")}` };
|
|
43
|
+
}
|
|
44
|
+
if (r.gpuVendor && !r.gpuVendor.includes(p.gpuVendor)) {
|
|
45
|
+
const needs = r.gpuVendor.map((v) => VENDOR_DISPLAY[v]).join(" / ");
|
|
46
|
+
const article = /^[NAEIO]/.test(needs) ? "an" : "a";
|
|
47
|
+
return { ok: false, reason: `Needs ${article} ${needs} GPU \u2014 you have ${VENDOR_DISPLAY[p.gpuVendor]}` };
|
|
48
|
+
}
|
|
49
|
+
if (r.minVramMb !== void 0 && p.vramMb > 0 && p.vramMb < r.minVramMb) {
|
|
50
|
+
const gb = Math.round(r.minVramMb / 1024);
|
|
51
|
+
return { ok: false, reason: `Needs ~${gb} GB VRAM` };
|
|
52
|
+
}
|
|
53
|
+
return { ok: true };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/agents/distiller.ts
|
|
57
|
+
var DISTILL_SYSTEM = `You write a single reusable SKILL from the material provided. A skill captures a repeatable approach so it can be applied to similar future tasks.
|
|
58
|
+
|
|
59
|
+
Output a JSON object: {"name": <short kebab-case id>, "description": <one sentence: when to use this skill>, "procedure": <concise step-by-step procedure, markdown>}
|
|
60
|
+
|
|
61
|
+
Rules:
|
|
62
|
+
- The skill must be GENERAL and reusable, not a one-off answer to this specific input.
|
|
63
|
+
- "name" is a short kebab-case identifier (e.g. "csv-summary", "extract-config-values").
|
|
64
|
+
- "description" is one sentence describing WHEN to apply it.
|
|
65
|
+
- "procedure" is a concise, numbered set of steps \u2014 the how.
|
|
66
|
+
- If the material does not contain a clear reusable approach, output {"name": null, "description": null, "procedure": null}.
|
|
67
|
+
Respond with ONLY the JSON object, nothing else.`;
|
|
68
|
+
async function distill(d, material) {
|
|
69
|
+
const ms = d.manager.status();
|
|
70
|
+
const target = d.manager.target();
|
|
71
|
+
if (ms.state !== "running" || !ms.model || !target) return { name: null, description: null, procedure: null };
|
|
72
|
+
const model = engineModelAlias(d.registry.active()?.kind ?? "") ?? ms.model.key;
|
|
73
|
+
try {
|
|
74
|
+
const res = await fetch(`${target}/v1/chat/completions`, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: { "Content-Type": "application/json" },
|
|
77
|
+
body: JSON.stringify({
|
|
78
|
+
model,
|
|
79
|
+
messages: [
|
|
80
|
+
{ role: "system", content: DISTILL_SYSTEM },
|
|
81
|
+
{ role: "user", content: `Material:
|
|
82
|
+
|
|
83
|
+
${material.slice(0, 24e3)}
|
|
84
|
+
|
|
85
|
+
Write ONE reusable skill as raw JSON \u2014 no markdown fences.` }
|
|
86
|
+
],
|
|
87
|
+
temperature: 0.3,
|
|
88
|
+
max_tokens: 800,
|
|
89
|
+
reasoning_budget: 0,
|
|
90
|
+
chat_template_kwargs: { enable_thinking: false },
|
|
91
|
+
response_format: { type: "json_object" },
|
|
92
|
+
stream: false
|
|
93
|
+
}),
|
|
94
|
+
signal: AbortSignal.timeout(9e4)
|
|
95
|
+
});
|
|
96
|
+
if (!res.ok) return { name: null, description: null, procedure: null };
|
|
97
|
+
const data = await res.json();
|
|
98
|
+
let txt = data.choices?.[0]?.message?.content ?? "";
|
|
99
|
+
txt = txt.replace(/<think>[\s\S]*?<\/think>/gi, "").replace(/```json|```/gi, "").trim();
|
|
100
|
+
const m = txt.match(/\{[\s\S]*\}/);
|
|
101
|
+
if (!m) return { name: null, description: null, procedure: null };
|
|
102
|
+
const j = JSON.parse(m[0]);
|
|
103
|
+
const valid = (s) => typeof s === "string" && s.trim() && s.toLowerCase() !== "null" ? s.trim() : null;
|
|
104
|
+
const name = valid(j.name);
|
|
105
|
+
const procedure = valid(j.procedure);
|
|
106
|
+
if (!name || !procedure) return { name: null, description: null, procedure: null };
|
|
107
|
+
return { name: name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64), description: valid(j.description) ?? "", procedure };
|
|
108
|
+
} catch {
|
|
109
|
+
return { name: null, description: null, procedure: null };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function distillFromConversation(d, transcript) {
|
|
113
|
+
const text = transcript.map((m) => `${m.role.toUpperCase()}: ${m.content}`).join("\n");
|
|
114
|
+
return distill(d, `A successful completed task:
|
|
115
|
+
|
|
116
|
+
${text}`);
|
|
117
|
+
}
|
|
118
|
+
var FOLDER_TEXT = /\.(md|txt|json|ya?ml|csv|js|ts|py|sh|html?|css)$/i;
|
|
119
|
+
function collectFolderFiles(folder, max) {
|
|
120
|
+
const files = [];
|
|
121
|
+
const walk = (dir, depth) => {
|
|
122
|
+
if (depth > 4 || files.length >= max) return;
|
|
123
|
+
let entries;
|
|
124
|
+
try {
|
|
125
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
126
|
+
} catch {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
for (const e of entries) {
|
|
130
|
+
if (files.length >= max) return;
|
|
131
|
+
const p = join(dir, e.name);
|
|
132
|
+
if (e.isDirectory()) {
|
|
133
|
+
walk(p, depth + 1);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (!FOLDER_TEXT.test(e.name)) continue;
|
|
137
|
+
try {
|
|
138
|
+
if (statSync(p).size > 2e5) continue;
|
|
139
|
+
const content = readFileSync(p, "utf8").slice(0, 6e3).trim();
|
|
140
|
+
if (content) files.push({ name: e.name, content });
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
walk(folder, 0);
|
|
146
|
+
return files;
|
|
147
|
+
}
|
|
148
|
+
async function distillSkillsFromFolder(d, folder, opts = {}) {
|
|
149
|
+
if (!existsSync(folder) || !statSync(folder).isDirectory()) return [];
|
|
150
|
+
const max = opts.max ?? 12;
|
|
151
|
+
const files = collectFolderFiles(folder, max);
|
|
152
|
+
if (!files.length) return [];
|
|
153
|
+
const out = [];
|
|
154
|
+
const seen = /* @__PURE__ */ new Set();
|
|
155
|
+
for (let i = 0; i < files.length; i++) {
|
|
156
|
+
const f = files[i];
|
|
157
|
+
opts.onProgress?.(i, files.length, f.name);
|
|
158
|
+
const s = await distill(d, `A reusable approach captured in "${f.name}":
|
|
159
|
+
|
|
160
|
+
${f.content}`);
|
|
161
|
+
if (s.name && s.procedure && !seen.has(s.name)) {
|
|
162
|
+
seen.add(s.name);
|
|
163
|
+
out.push(s);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export {
|
|
170
|
+
engineAcceptsFormat,
|
|
171
|
+
engineModelAlias,
|
|
172
|
+
evaluateVariant,
|
|
173
|
+
distillFromConversation,
|
|
174
|
+
distillSkillsFromFolder
|
|
175
|
+
};
|