turbollm 1.11.9 → 1.12.1
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 +1 -1
- package/dist/cli.js +166 -65
- package/dist/webdist/.omc/state/agent-replay-d4811781-2640-44e0-8399-662ec162ff43.jsonl +10 -0
- package/dist/webdist/.omc/state/subagent-tracking.json +7 -0
- package/dist/webdist/assets/{AgentEditPage-Cfbfakkc.js → AgentEditPage-B9mKK6Ob.js} +1 -1
- package/dist/webdist/assets/{ChatScreen-CYggEGs5.js → ChatScreen-DLD1CDS1.js} +1 -1
- package/dist/webdist/assets/{CodeComposer-CPq9MB0A.js → CodeComposer-DHE_iTkC.js} +1 -1
- package/dist/webdist/assets/{CodeHomeScreen-DJd7UNqS.js → CodeHomeScreen-6CKrrrZ5.js} +1 -1
- package/dist/webdist/assets/{CodeSessionScreen-DANRbQym.js → CodeSessionScreen-JUpzeYHF.js} +1 -1
- package/dist/webdist/assets/{CustomizeScreen-BHsYmBrR.js → CustomizeScreen-C7f4ZRSa.js} +1 -1
- package/dist/webdist/assets/{DeveloperScreen-C_m-yLRt.js → DeveloperScreen-n6gJC3-E.js} +1 -1
- package/dist/webdist/assets/{EnginesScreen-WNm64lCr.js → EnginesScreen-BWRix4d7.js} +1 -1
- package/dist/webdist/assets/ModelDetailDialog-BdPGMTTz.js +1 -0
- package/dist/webdist/assets/{ModelLoadMenu-BoD8vGEb.js → ModelLoadMenu-D3zo79dw.js} +1 -1
- package/dist/webdist/assets/ModelsScreen-7AJUC2wa.js +2 -0
- package/dist/webdist/assets/{OnboardingScreen-Dp2_T3xE.js → OnboardingScreen-CGbbx6bS.js} +1 -1
- package/dist/webdist/assets/{RoutineEditPage-_ego0aCV.js → RoutineEditPage-Dd_snYdQ.js} +1 -1
- package/dist/webdist/assets/{RoutinesPanel-DHwZQ9Gk.js → RoutinesPanel-5M00XOUM.js} +1 -1
- package/dist/webdist/assets/{SettingsScreen-DbKvB_mp.js → SettingsScreen-B489HDiC.js} +1 -1
- package/dist/webdist/assets/{SidebarResizeHandle-Bc3QBs84.js → SidebarResizeHandle-B0wgsZJ6.js} +1 -1
- package/dist/webdist/assets/{SkillEditPage-CwGusPDb.js → SkillEditPage-CVYFfzLc.js} +1 -1
- package/dist/webdist/assets/{TokensScreen-UaGvsqtF.js → TokensScreen-CQ4m20pP.js} +1 -1
- package/dist/webdist/assets/{ToolApprovalBar-Chx2y-tr.js → ToolApprovalBar-B2nX56dI.js} +3 -3
- package/dist/webdist/assets/WorkspaceScreen-RLGQrw5_.js +1 -0
- package/dist/webdist/assets/{abnfDiagram-N423BO3Z-iiGkfE9c.js → abnfDiagram-N423BO3Z-DoOYvhD1.js} +1 -1
- package/dist/webdist/assets/{agent-api-CmhXBBT6.js → agent-api-BAMDY8-v.js} +1 -1
- package/dist/webdist/assets/{alert-dialog-B7ASyTxr.js → alert-dialog-rMeq-XIF.js} +1 -1
- package/dist/webdist/assets/{arc-CitM3TjF.js → arc-BmVPVvg0.js} +1 -1
- package/dist/webdist/assets/{architectureDiagram-T3A2C74G-B81sGCwi.js → architectureDiagram-T3A2C74G-Bh4HLM3j.js} +1 -1
- package/dist/webdist/assets/{arrow-left-Cx0V34bU.js → arrow-left-Bawx_G0m.js} +1 -1
- package/dist/webdist/assets/{badge-BJPgZflb.js → badge-BK8Xn6K3.js} +1 -1
- package/dist/webdist/assets/{blockDiagram-VBNYF7ZC-StpQormu.js → blockDiagram-VBNYF7ZC-D4dEMw56.js} +1 -1
- package/dist/webdist/assets/{bot-XI_iobdp.js → bot-DmBk_i45.js} +1 -1
- package/dist/webdist/assets/{c4Diagram-5PPSVZJV-Csa8aK4v.js → c4Diagram-5PPSVZJV-cnPwu_pX.js} +1 -1
- package/dist/webdist/assets/channel-BoFujHnv.js +1 -0
- package/dist/webdist/assets/{chat-api-Zyxy4wka.js → chat-api-Bgrb0rnf.js} +1 -1
- package/dist/webdist/assets/{chat-queries-DIm_a9NN.js → chat-queries-zz2ch8OT.js} +1 -1
- package/dist/webdist/assets/{chevron-down-BWfjeD2C.js → chevron-down-CNDC69O9.js} +1 -1
- package/dist/webdist/assets/{chevron-left-CBtdrcDZ.js → chevron-left-CxvUI3ck.js} +1 -1
- package/dist/webdist/assets/{chevron-right-DRLCoDa8.js → chevron-right-CpdnK5S2.js} +1 -1
- package/dist/webdist/assets/{chunk-2GRJ4B5K-2MKQX9Og.js → chunk-2GRJ4B5K-CtDLA9D7.js} +1 -1
- package/dist/webdist/assets/{chunk-2Q5K7J3B-B_27rm1N.js → chunk-2Q5K7J3B-CclvIDBO.js} +1 -1
- package/dist/webdist/assets/{chunk-5RXB4S5H-BlhTP0-3.js → chunk-5RXB4S5H-DFYQzU9L.js} +1 -1
- package/dist/webdist/assets/{chunk-5VM5RSS4-C7IJCBfZ.js → chunk-5VM5RSS4-CGpXaRvE.js} +1 -1
- package/dist/webdist/assets/{chunk-6Q2QTUOP-Bj14OW8u.js → chunk-6Q2QTUOP-CI7s7JEA.js} +1 -1
- package/dist/webdist/assets/{chunk-GF5L2VYU-aT8ppbPL.js → chunk-GF5L2VYU-y-SeWQKo.js} +1 -1
- package/dist/webdist/assets/{chunk-JWPE2WC7-Bt4dl9CN.js → chunk-JWPE2WC7-BvVsBdrN.js} +1 -1
- package/dist/webdist/assets/{chunk-KBJHAD2P-J4coc1ol.js → chunk-KBJHAD2P-CUc-YWns.js} +1 -1
- package/dist/webdist/assets/{chunk-RYQCIY6F-Dv_7Q2hX.js → chunk-RYQCIY6F-CABY0N-y.js} +1 -1
- package/dist/webdist/assets/{chunk-XXDRQBXY-zQnucktD.js → chunk-XXDRQBXY-ChEtYkzy.js} +1 -1
- package/dist/webdist/assets/{circle-check-loUJak9B.js → circle-check-D-vn9nY2.js} +1 -1
- package/dist/webdist/assets/{circle-x-Bgnj4qQZ.js → circle-x-BcnmRVTe.js} +1 -1
- package/dist/webdist/assets/classDiagram-JCYQIIEL-CWuM4mUX.js +1 -0
- package/dist/webdist/assets/classDiagram-v2-OCEON4UE-CWuM4mUX.js +1 -0
- package/dist/webdist/assets/{common-B5JH_OFR.js → common-xWkNwbHY.js} +1 -1
- package/dist/webdist/assets/{cose-bilkent-JH36ORCC-CvYv-f5s.js → cose-bilkent-JH36ORCC-CJpKH0B3.js} +1 -1
- package/dist/webdist/assets/{cynefin-VYW2F7L2-DVwHpekX.js → cynefin-VYW2F7L2-B97tFXrq.js} +1 -1
- package/dist/webdist/assets/{cynefinDiagram-MW4NZA55-BcdPKvtX.js → cynefinDiagram-MW4NZA55-CTmmk7Xt.js} +1 -1
- package/dist/webdist/assets/{dagre-VZM6K2ZE-4sSe5M8W.js → dagre-VZM6K2ZE-BMkcnGJJ.js} +1 -1
- package/dist/webdist/assets/{diagram-7IWD3JNH-COLSWeIR.js → diagram-7IWD3JNH-DxA708mT.js} +1 -1
- package/dist/webdist/assets/{diagram-B4RE2ZJO-ER5prsGm.js → diagram-B4RE2ZJO-Bkjy34TD.js} +1 -1
- package/dist/webdist/assets/{diagram-LBJQPF4R-FfvD4Hay.js → diagram-LBJQPF4R-BorjsNJT.js} +1 -1
- package/dist/webdist/assets/{diagram-Q27KOJAE-DnwPL2tG.js → diagram-Q27KOJAE-hW5SDR9k.js} +1 -1
- package/dist/webdist/assets/{diagram-UB23O5K3-B6lZME5q.js → diagram-UB23O5K3-c07HJJ5p.js} +1 -1
- package/dist/webdist/assets/{dropdown-menu-DRRO0ftt.js → dropdown-menu-CaecUWTU.js} +1 -1
- package/dist/webdist/assets/{ebnfDiagram-BXEA7PRR-DLx8zqdK.js → ebnfDiagram-BXEA7PRR-CvgAWjhG.js} +1 -1
- package/dist/webdist/assets/{erDiagram-JOGREHBK-DdSmD2ix.js → erDiagram-JOGREHBK-C66LM90T.js} +1 -1
- package/dist/webdist/assets/{external-link-dolckdL9.js → external-link-NvytYVfT.js} +1 -1
- package/dist/webdist/assets/{file-text-BJHbdxSm.js → file-text-BsC3M8zz.js} +1 -1
- package/dist/webdist/assets/{flowDiagram-UKHOOZJN-C71SbKr7.js → flowDiagram-UKHOOZJN-BcXu-_m9.js} +1 -1
- package/dist/webdist/assets/{folder-input-ubj-7_tQ.js → folder-input-B5dvV2Rt.js} +1 -1
- package/dist/webdist/assets/{folder-plus-Bz7B7UnH.js → folder-plus-CfgNM2Bq.js} +1 -1
- package/dist/webdist/assets/{ganttDiagram-PKOTCBZU-C5doF3y3.js → ganttDiagram-PKOTCBZU-DtorJ7JE.js} +1 -1
- package/dist/webdist/assets/{git-branch-CNpNkvMr.js → git-branch-BRH6t3pJ.js} +1 -1
- package/dist/webdist/assets/{gitGraphDiagram-DS77QQ5N-iCuj4BOQ.js → gitGraphDiagram-DS77QQ5N-krn_sqdS.js} +1 -1
- package/dist/webdist/assets/index-B2S9teij.css +1 -0
- package/dist/webdist/assets/{index-D0Emka7d.js → index-C9ZXfFYo.js} +2 -2
- package/dist/webdist/assets/{infoDiagram-6WML65LV-CVbutaQs.js → infoDiagram-6WML65LV-DdSRJqp_.js} +1 -1
- package/dist/webdist/assets/{ishikawaDiagram-WSZJBQD7-CZyy_met.js → ishikawaDiagram-WSZJBQD7-CXU7wA7v.js} +1 -1
- package/dist/webdist/assets/{journeyDiagram-NVQOT4AX-BIwZvXA4.js → journeyDiagram-NVQOT4AX-CIzJLnh4.js} +1 -1
- package/dist/webdist/assets/{kanban-definition-27J2QSJJ-DOERNBKz.js → kanban-definition-27J2QSJJ-D7PciwFU.js} +1 -1
- package/dist/webdist/assets/{linear-Bf8xCMRw.js → linear-DJzOvrgv.js} +1 -1
- package/dist/webdist/assets/{link-queries-DBf0L0p4.js → link-queries-BfuN5xQI.js} +1 -1
- package/dist/webdist/assets/{lock-CnmBV2sW.js → lock-BpNNUDlH.js} +1 -1
- package/dist/webdist/assets/{mermaid.core-DcQR7vsm.js → mermaid.core-DEfoMsry.js} +4 -4
- package/dist/webdist/assets/{mindmap-definition-FAOFIHXS-C3T3OIGM.js → mindmap-definition-FAOFIHXS-B-p8gHME.js} +1 -1
- package/dist/webdist/assets/{monitor-Dj5hVZG9.js → monitor-3-JqrGh0.js} +1 -1
- package/dist/webdist/assets/{pegDiagram-VL7TDLO6-J5nkSsO9.js → pegDiagram-VL7TDLO6-CVN-UtZ2.js} +1 -1
- package/dist/webdist/assets/{pencil-CJDKBSrc.js → pencil-CLBnFmc5.js} +1 -1
- package/dist/webdist/assets/{personas-CeAQ6niU.js → personas-Dkq9JD72.js} +1 -1
- package/dist/webdist/assets/{pieDiagram-7S7Q4E2Y-2RGDZc8u.js → pieDiagram-7S7Q4E2Y-Cyowg7jU.js} +1 -1
- package/dist/webdist/assets/{plus-CtCCCtT9.js → plus-BsBN79CH.js} +1 -1
- package/dist/webdist/assets/{quadrantDiagram-CIZ2JOQS-DsYpj2qg.js → quadrantDiagram-CIZ2JOQS-CLEre7Bo.js} +1 -1
- package/dist/webdist/assets/{railroadDiagram-AXF67PYL-DvObbGSI.js → railroadDiagram-AXF67PYL-CstFYJPW.js} +1 -1
- package/dist/webdist/assets/{refresh-cw-Qd40C8Nj.js → refresh-cw-DHnSGytz.js} +1 -1
- package/dist/webdist/assets/{remote-failure-B7wlj-_A.js → remote-failure-DQsv9RYM.js} +1 -1
- package/dist/webdist/assets/{requirementDiagram-LRYGKXZP-CdeOzUDb.js → requirementDiagram-LRYGKXZP-BVS10AjP.js} +1 -1
- package/dist/webdist/assets/{rocket-D2AvWWtP.js → rocket-0CLawS4F.js} +1 -1
- package/dist/webdist/assets/{rotate-ccw-BpPatpxx.js → rotate-ccw-kHM_pFpt.js} +1 -1
- package/dist/webdist/assets/{sankeyDiagram-W5VNT64P-DVrYRLqU.js → sankeyDiagram-W5VNT64P-DWg6hEFJ.js} +1 -1
- package/dist/webdist/assets/{sequenceDiagram-SI44F4Z6-BZAK6xg6.js → sequenceDiagram-SI44F4Z6-CPe4ECQK.js} +1 -1
- package/dist/webdist/assets/{sizeCapture-X5ZJPWSS-BHOY8h1t.js → sizeCapture-X5ZJPWSS-tYK0sN8k.js} +1 -1
- package/dist/webdist/assets/{skeleton-C1KITEIJ.js → skeleton-1pxWnguF.js} +1 -1
- package/dist/webdist/assets/{sliders-horizontal-D48--I0k.js → sliders-horizontal-CJnL4ema.js} +1 -1
- package/dist/webdist/assets/{sparkles-DDOla5js.js → sparkles-CtVbnpZt.js} +1 -1
- package/dist/webdist/assets/{star-B2buMvXV.js → star-BWg7n83j.js} +1 -1
- package/dist/webdist/assets/{stateDiagram-OKZ733FA-VUJTdkvj.js → stateDiagram-OKZ733FA-DdMFYbZ9.js} +1 -1
- package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-Pg2RCR6-.js +1 -0
- package/dist/webdist/assets/{swimlanes-SLNWSIFB-MjxXyCvR.js → swimlanes-SLNWSIFB-DgWqKJOe.js} +2 -2
- package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-D-HgKzxH.js +8 -0
- package/dist/webdist/assets/{switch-Cs9dlnwb.js → switch-ChtEKTkl.js} +1 -1
- package/dist/webdist/assets/{terminal-CiOZKaJb.js → terminal-BksEQh4H.js} +1 -1
- package/dist/webdist/assets/{timeline-definition-Z64GVDOM-Bw8Iivgn.js → timeline-definition-Z64GVDOM-CrwOPdAi.js} +1 -1
- package/dist/webdist/assets/{trash-2-DbQqCHSH.js → trash-2-BXZkODa0.js} +1 -1
- package/dist/webdist/assets/{triangle-alert-Buguln0S.js → triangle-alert-tsQmbLn8.js} +1 -1
- package/dist/webdist/assets/{useIsDesktop-BdbkbmUH.js → useIsDesktop-BKLpQjiw.js} +1 -1
- package/dist/webdist/assets/{vennDiagram-T6HMQDX7-UptwMBTb.js → vennDiagram-T6HMQDX7-B7_yA6Pn.js} +1 -1
- package/dist/webdist/assets/{wardleyDiagram-T6FBY63Y-DBzcNfG5.js → wardleyDiagram-T6FBY63Y-CImMUYg_.js} +1 -1
- package/dist/webdist/assets/{wrench-ByDKNN2K.js → wrench-CuSXx_Zn.js} +1 -1
- package/dist/webdist/assets/{xychartDiagram-ELKLHX3M-DrO-tWl0.js → xychartDiagram-ELKLHX3M-B2wGD83d.js} +1 -1
- package/dist/webdist/index.html +2 -2
- package/package.json +1 -1
- package/dist/webdist/assets/ModelDetailDialog-CCmZhT_-.js +0 -1
- package/dist/webdist/assets/ModelsScreen-B1eaJCK_.js +0 -2
- package/dist/webdist/assets/WorkspaceScreen-a7V07mMZ.js +0 -1
- package/dist/webdist/assets/channel-DS6QHRxP.js +0 -1
- package/dist/webdist/assets/classDiagram-JCYQIIEL-DmMoUKDN.js +0 -1
- package/dist/webdist/assets/classDiagram-v2-OCEON4UE-DmMoUKDN.js +0 -1
- package/dist/webdist/assets/index-D44YD6EJ.css +0 -1
- package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-DslkN__b.js +0 -1
- package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-CQoli8MP.js +0 -8
package/README.md
CHANGED
|
@@ -208,7 +208,7 @@ the detail:
|
|
|
208
208
|
- **Full load-parameter UI**, a superset of what other tools expose: context length, GPU offload
|
|
209
209
|
(`-ngl`), **MoE CPU-offload (`--n-cpu-moe`)**, parallel slots, **independent K and V cache-quant
|
|
210
210
|
type** (incl. low-bit on supporting forks), CPU threads, flash attention, **speculative decoding
|
|
211
|
-
(NextN / MTP / draft, with a configurable draft min/max window)**, a **pinned engine port** per
|
|
211
|
+
(NextN / MTP / draft / DFlash, with a configurable draft min/max window)**, a **pinned engine port** per
|
|
212
212
|
model, and a **custom/raw flags** field for anything not exposed as its own control.
|
|
213
213
|
- **Copy the exact launch command** for a loaded model — runs the same config standalone with
|
|
214
214
|
llama.cpp/the fork directly, no TurboLLM required.
|
package/dist/cli.js
CHANGED
|
@@ -2637,9 +2637,12 @@ function detectKvTypes(helpText, hasCacheTypeFlag) {
|
|
|
2637
2637
|
return kvTypes;
|
|
2638
2638
|
}
|
|
2639
2639
|
function parseEnumList(blockText) {
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2640
|
+
let raw = /allowed values:\s*([\s\S]+)/i.exec(blockText)?.[1] ?? /(?:^|[ \t])\[([^\]\n]+)\]/.exec(blockText)?.[1];
|
|
2641
|
+
if (!raw) {
|
|
2642
|
+
const braceMatch = /(?:^|[ \t])\{([^}]+)\}/.exec(blockText);
|
|
2643
|
+
const parenMatch = /(?:^|[ \t])\(([^)|]+)\)/.exec(blockText);
|
|
2644
|
+
raw = braceMatch?.[1] ?? parenMatch?.[1];
|
|
2645
|
+
}
|
|
2643
2646
|
if (!raw) return [];
|
|
2644
2647
|
const values = raw.split(/[,|]/).map((s) => s.trim()).filter((s) => /^[a-z][a-z0-9_-]*$/i.test(s));
|
|
2645
2648
|
return values.length >= 2 ? values : [];
|
|
@@ -2648,7 +2651,7 @@ function classifyFlag(flagName, helpText) {
|
|
|
2648
2651
|
const escaped = flagName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2649
2652
|
const ALIAS = "-{1,2}[a-zA-Z][a-zA-Z0-9-]*";
|
|
2650
2653
|
const re = new RegExp(
|
|
2651
|
-
`(?:^|\\n)[ \\t]*(?:${ALIAS}[ \\t]*,[ \\t]*)*${escaped}(?![-a-zA-Z0-9])(?:[ \\t]*,[ \\t]*${ALIAS})*( *)(\\S+)?([\\s\\S]
|
|
2654
|
+
`(?:^|\\n)[ \\t]*(?:${ALIAS}[ \\t]*,[ \\t]*)*${escaped}(?![-a-zA-Z0-9])(?:[ \\t]*,[ \\t]*${ALIAS})*( *)(\\S+)?([\\s\\S]+?)(?=\\n\\s*\\(default|\\n[ \\t]*${ALIAS}|\\n\\n|$)`,
|
|
2652
2655
|
"i"
|
|
2653
2656
|
);
|
|
2654
2657
|
const m = re.exec(helpText);
|
|
@@ -2656,11 +2659,24 @@ function classifyFlag(flagName, helpText) {
|
|
|
2656
2659
|
const gap = m[1] ?? "";
|
|
2657
2660
|
const placeholder = m[2] ?? "";
|
|
2658
2661
|
const block = m[3] ?? "";
|
|
2659
|
-
const
|
|
2662
|
+
const nextFlagLine = block.match(/\n[ \t]*-{1,2}[a-zA-Z][a-zA-Z0-9-]*/);
|
|
2663
|
+
const ownBlock = nextFlagLine ? block.slice(0, nextFlagLine.index) : block;
|
|
2664
|
+
const scanText = placeholder + "\n" + ownBlock;
|
|
2665
|
+
const enumValues = parseEnumList(scanText);
|
|
2660
2666
|
if (enumValues.length > 0) return { name: flagName, kind: "enum", enumValues };
|
|
2667
|
+
const bracket = parseEnumBrackets(scanText);
|
|
2668
|
+
if (bracket.length > 0) return { name: flagName, kind: "enum", enumValues: bracket };
|
|
2661
2669
|
if (gap.length !== 1 || !placeholder) return { name: flagName, kind: "boolean" };
|
|
2662
2670
|
return { name: flagName, kind: "valued" };
|
|
2663
2671
|
}
|
|
2672
|
+
function parseEnumBrackets(blockText) {
|
|
2673
|
+
const braceMatch = /(?:^|[ \t])\{([^}]+)\}/.exec(blockText);
|
|
2674
|
+
const parenMatch = /(?:^|[ \t])\(([^)|]+)\)/.exec(blockText);
|
|
2675
|
+
const raw = braceMatch?.[1] ?? parenMatch?.[1];
|
|
2676
|
+
if (!raw) return [];
|
|
2677
|
+
const values = raw.split(/[|,]/).map((s) => s.trim()).filter((s) => /^[a-z][a-z0-9_-]*$/i.test(s));
|
|
2678
|
+
return values.length >= 2 ? values : [];
|
|
2679
|
+
}
|
|
2664
2680
|
function firstNonEmptyLine(s) {
|
|
2665
2681
|
for (const ln of s.split("\n")) {
|
|
2666
2682
|
const t = ln.trim();
|
|
@@ -2887,9 +2903,11 @@ function suggestEngineName(binPath, version2) {
|
|
|
2887
2903
|
|
|
2888
2904
|
// src/engines/build-runner.ts
|
|
2889
2905
|
var execFileP8 = promisify8(execFile10);
|
|
2906
|
+
function chooseEngineName(name, priorName) {
|
|
2907
|
+
return name ?? priorName ?? "";
|
|
2908
|
+
}
|
|
2890
2909
|
function buildDirName(repoUrl, branch, commit) {
|
|
2891
|
-
const
|
|
2892
|
-
const repo = last.replace(/\.git$/i, "").trim() || "engine";
|
|
2910
|
+
const repo = normRepoUrl(repoUrl) || "engine";
|
|
2893
2911
|
const b = (branch ?? "").trim();
|
|
2894
2912
|
const sha = (commit ?? "").trim();
|
|
2895
2913
|
const raw = sha ? `${repo}-${sha.slice(0, 12)}` : b ? `${repo}-${b}` : repo;
|
|
@@ -2900,7 +2918,7 @@ function sameRepo(a, b) {
|
|
|
2900
2918
|
return na !== "" && na === normRepoUrl(b);
|
|
2901
2919
|
}
|
|
2902
2920
|
function normRepoUrl(s) {
|
|
2903
|
-
return (s ?? "").trim().toLowerCase().replace(/^https?:\/\//, "").replace(/^github\.com\//, "").replace(
|
|
2921
|
+
return (s ?? "").trim().toLowerCase().replace(/^https?:\/\//, "").replace(/^github\.com\//, "").replace(/\/+$/, "").replace(/\.git$/, "");
|
|
2904
2922
|
}
|
|
2905
2923
|
function sourceBuildBinary(enginesRoot, repoUrl, branch, commit) {
|
|
2906
2924
|
const root = join13(enginesRoot, "build", buildDirName(repoUrl, branch, commit));
|
|
@@ -3662,7 +3680,11 @@ function customSourceKey(s) {
|
|
|
3662
3680
|
}
|
|
3663
3681
|
function isStaleCapabilities(flags, flagInfo) {
|
|
3664
3682
|
if (flags.includes("--spec-type") && !flags.some((f2) => f2.startsWith("spec-type:"))) return true;
|
|
3665
|
-
|
|
3683
|
+
const removed = ["--draft-max", "--draft-min", "--draft", "--draft-n", "--draft-n-min"];
|
|
3684
|
+
const successor = ["--spec-draft-n-max", "--spec-draft-n-min"];
|
|
3685
|
+
const hasRemoved = removed.some((f2) => flags.includes(f2));
|
|
3686
|
+
const hasSuccessor = successor.some((f2) => flags.includes(f2));
|
|
3687
|
+
if (hasRemoved && hasSuccessor) return true;
|
|
3666
3688
|
if (flagInfo === void 0) return true;
|
|
3667
3689
|
return false;
|
|
3668
3690
|
}
|
|
@@ -3830,7 +3852,7 @@ var modelLoad = defineEvent({
|
|
|
3830
3852
|
batchSize: f.int({ optional: true }),
|
|
3831
3853
|
uBatchSize: f.int({ optional: true }),
|
|
3832
3854
|
cacheReuse: f.int(),
|
|
3833
|
-
speculative: f.enum(["off", "mtp", "nextn", "draft"]),
|
|
3855
|
+
speculative: f.enum(["off", "mtp", "nextn", "draft", "dflash"]),
|
|
3834
3856
|
contextOverflow: f.enum(["shift", "keep"]),
|
|
3835
3857
|
nKeep: f.int(),
|
|
3836
3858
|
ropeScalingType: f.enum(["none", "linear", "yarn"]),
|
|
@@ -4614,7 +4636,20 @@ import { EventEmitter as EventEmitter2 } from "events";
|
|
|
4614
4636
|
|
|
4615
4637
|
// src/chat/chat-routes.ts
|
|
4616
4638
|
import { streamSSE } from "hono/streaming";
|
|
4639
|
+
|
|
4640
|
+
// src/net.ts
|
|
4617
4641
|
import { networkInterfaces } from "os";
|
|
4642
|
+
var VIRTUAL_ADAPTER_NAME = /^(vEthernet|Loopback|Virtual|VMware|VirtualBox|Hyper-V|Docker|WSL|Tailscale|ZeroTier|Npcap|TAP-|PPP|Bluetooth)/i;
|
|
4643
|
+
function getLanIp() {
|
|
4644
|
+
const candidates = [];
|
|
4645
|
+
for (const [name, ifaces] of Object.entries(networkInterfaces())) {
|
|
4646
|
+
for (const iface of ifaces ?? []) {
|
|
4647
|
+
if (iface.family === "IPv4" && !iface.internal) candidates.push({ name, address: iface.address });
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
const real = candidates.find((c) => !VIRTUAL_ADAPTER_NAME.test(c.name));
|
|
4651
|
+
return (real ?? candidates[0])?.address ?? null;
|
|
4652
|
+
}
|
|
4618
4653
|
|
|
4619
4654
|
// src/chat/parser.ts
|
|
4620
4655
|
var THINK_OPEN = "<think>";
|
|
@@ -5617,7 +5652,11 @@ async function withPinnedModel(deps2, pinnedModel, fn) {
|
|
|
5617
5652
|
return { outcome: "ran" };
|
|
5618
5653
|
}
|
|
5619
5654
|
const swapResult = await deps2.modelRouter.loadExplicit(pinnedModel);
|
|
5620
|
-
if ("status" in swapResult)
|
|
5655
|
+
if ("status" in swapResult) {
|
|
5656
|
+
if (swapResult.message.includes("ComfyUI is rendering"))
|
|
5657
|
+
return { outcome: "skip-comfyui-busy" };
|
|
5658
|
+
return { outcome: "skip-load-failed", message: swapResult.message };
|
|
5659
|
+
}
|
|
5621
5660
|
try {
|
|
5622
5661
|
await fn();
|
|
5623
5662
|
} finally {
|
|
@@ -8474,6 +8513,10 @@ function finalizeSwapOutcome(d, runId, swap, ranStatus) {
|
|
|
8474
8513
|
d.db.updateRoutineRun(runId, { status: "skipped", skipReason: "model_busy", endedAt });
|
|
8475
8514
|
return "skipped";
|
|
8476
8515
|
}
|
|
8516
|
+
if (swap.outcome === "skip-comfyui-busy") {
|
|
8517
|
+
d.db.updateRoutineRun(runId, { status: "skipped", skipReason: "comfyui_busy", endedAt });
|
|
8518
|
+
return "skipped";
|
|
8519
|
+
}
|
|
8477
8520
|
d.db.updateRoutineRun(runId, { status: "errored", error: swap.message, endedAt });
|
|
8478
8521
|
return "errored";
|
|
8479
8522
|
}
|
|
@@ -9098,7 +9141,7 @@ function estimateVramPerGpu(p, m, sys) {
|
|
|
9098
9141
|
const blocks = m.blockCount > 0 ? m.blockCount : 1;
|
|
9099
9142
|
const sizeMb = m.sizeBytes / 1e6;
|
|
9100
9143
|
const perLayerMb = sizeMb * GPU_WEIGHT_FRACTION / blocks;
|
|
9101
|
-
const residentLayers =
|
|
9144
|
+
const residentLayers = Math.max(0, Math.min(p.ngl, blocks));
|
|
9102
9145
|
const nCpuMoe = m.moe ? Math.max(0, Math.min(p.nCpuMoe, blocks)) : 0;
|
|
9103
9146
|
const layers = new Array(n).fill(0);
|
|
9104
9147
|
if (p.gpu?.splitMode === "none" || n === 1) {
|
|
@@ -9305,6 +9348,10 @@ function profileToArgs(p, m, caps, cores = 0, sys, binPath) {
|
|
|
9305
9348
|
if (specType) a.push("--spec-type", "draft");
|
|
9306
9349
|
a.push("--model-draft", p.draftModelPath);
|
|
9307
9350
|
specActive = true;
|
|
9351
|
+
} else if (p.speculative === "dflash" && p.draftModelPath && specType && specAccepts("draft-dflash") && has("--spec-draft-model")) {
|
|
9352
|
+
a.push("--spec-type", "draft-dflash");
|
|
9353
|
+
a.push("--spec-draft-model", p.draftModelPath);
|
|
9354
|
+
specActive = true;
|
|
9308
9355
|
}
|
|
9309
9356
|
if (specActive) {
|
|
9310
9357
|
if (has("--draft-max")) a.push("--draft-max", String(p.draftMax ?? 16));
|
|
@@ -10142,14 +10189,7 @@ function importOpenAiMessages(c, db2, messages, titleField, modelField) {
|
|
|
10142
10189
|
return c.json({ id: newConv.id }, 201);
|
|
10143
10190
|
}
|
|
10144
10191
|
function getLanIpForShare() {
|
|
10145
|
-
|
|
10146
|
-
for (const ifaces of Object.values(nets)) {
|
|
10147
|
-
if (!ifaces) continue;
|
|
10148
|
-
for (const iface of ifaces) {
|
|
10149
|
-
if (iface.family === "IPv4" && !iface.internal) return iface.address;
|
|
10150
|
-
}
|
|
10151
|
-
}
|
|
10152
|
-
return "127.0.0.1";
|
|
10192
|
+
return getLanIp() ?? "127.0.0.1";
|
|
10153
10193
|
}
|
|
10154
10194
|
function reportChatBenchResult(d, ms, stats) {
|
|
10155
10195
|
try {
|
|
@@ -10816,6 +10856,7 @@ import {
|
|
|
10816
10856
|
SettingsManager,
|
|
10817
10857
|
isEditToolResult
|
|
10818
10858
|
} from "@earendil-works/pi-coding-agent";
|
|
10859
|
+
import { estimateTokens, calculateContextTokens } from "@earendil-works/pi-coding-agent";
|
|
10819
10860
|
|
|
10820
10861
|
// src/code/robust-bash.ts
|
|
10821
10862
|
import { access as fsAccess } from "fs/promises";
|
|
@@ -12574,7 +12615,35 @@ ${lines.join("\n")}${more}]`
|
|
|
12574
12615
|
}
|
|
12575
12616
|
const finalText = session.getLastAssistantText() ?? "";
|
|
12576
12617
|
const stats = session.getSessionStats();
|
|
12577
|
-
|
|
12618
|
+
let contextUsed;
|
|
12619
|
+
if (stats.contextUsage?.tokens != null) {
|
|
12620
|
+
contextUsed = stats.contextUsage.tokens;
|
|
12621
|
+
} else {
|
|
12622
|
+
let lastUsage;
|
|
12623
|
+
let lastUsageIdx = -1;
|
|
12624
|
+
for (let i = session.messages.length - 1; i >= 0; i--) {
|
|
12625
|
+
const m = session.messages[i];
|
|
12626
|
+
if (m.role === "assistant" && "usage" in m) {
|
|
12627
|
+
const u = m.usage;
|
|
12628
|
+
if (u && calculateContextTokens(u) > 0) {
|
|
12629
|
+
lastUsage = u;
|
|
12630
|
+
lastUsageIdx = i;
|
|
12631
|
+
break;
|
|
12632
|
+
}
|
|
12633
|
+
}
|
|
12634
|
+
}
|
|
12635
|
+
if (lastUsage) {
|
|
12636
|
+
contextUsed = calculateContextTokens(lastUsage);
|
|
12637
|
+
for (let i = lastUsageIdx + 1; i < session.messages.length; i++) {
|
|
12638
|
+
contextUsed += estimateTokens(session.messages[i]);
|
|
12639
|
+
}
|
|
12640
|
+
} else {
|
|
12641
|
+
contextUsed = 0;
|
|
12642
|
+
for (const m of session.messages) {
|
|
12643
|
+
contextUsed += estimateTokens(m);
|
|
12644
|
+
}
|
|
12645
|
+
}
|
|
12646
|
+
}
|
|
12578
12647
|
const contextMax = stats.contextUsage?.contextWindow ?? contextWindow;
|
|
12579
12648
|
const usage = foldTurnUsage(stats.tokens, { promptMsTotal, genMsTotal, ttftMs, totalMs: Date.now() - turnStartedAt });
|
|
12580
12649
|
session.dispose();
|
|
@@ -12674,7 +12743,10 @@ async function compactCodeSession(params) {
|
|
|
12674
12743
|
compactionUpToMessageId: upToMessageId,
|
|
12675
12744
|
compactionTokensBefore: result.tokensBefore
|
|
12676
12745
|
});
|
|
12677
|
-
|
|
12746
|
+
const summaryTokens = Math.ceil(result.summary.length / 4);
|
|
12747
|
+
const ctxUsed = compactionSettings.keepRecentTokens + summaryTokens;
|
|
12748
|
+
d.db.setCodeSessionCtxUsed(sessionId, ctxUsed);
|
|
12749
|
+
return { summary: result.summary, upToMessageId, tokensBefore: result.tokensBefore, ctxUsed };
|
|
12678
12750
|
}
|
|
12679
12751
|
async function lookbackPreCompactionHistory(params) {
|
|
12680
12752
|
const { d, convId, sessionId, repoRoot, question, signal } = params;
|
|
@@ -13758,7 +13830,7 @@ var EMBED_ARCHS = /* @__PURE__ */ new Set([
|
|
|
13758
13830
|
"xlm-roberta",
|
|
13759
13831
|
"electra"
|
|
13760
13832
|
]);
|
|
13761
|
-
var EMBED_FILE_RE = /\b(bge[-_]|nomic[-_]embed|all[-_]minilm|e5[-_]|gte[-_]|stella[-_]embed|jina[-_]embed|mxbai[-_]embed)\b/i;
|
|
13833
|
+
var EMBED_FILE_RE = /\b(bge[-_]|nomic[-_]embed|all[-_]minilm|e5[-_]|gte[-_]|stella[-_]embed|jina[-_]embed|mxbai[-_]embed|embed(ding)?)\b/i;
|
|
13762
13834
|
function isEmbeddingModel(arch2, name) {
|
|
13763
13835
|
return EMBED_ARCHS.has(arch2.toLowerCase()) || EMBED_FILE_RE.test(name);
|
|
13764
13836
|
}
|
|
@@ -15318,6 +15390,10 @@ var ConversationStore = class {
|
|
|
15318
15390
|
`);
|
|
15319
15391
|
this.db.exec(`PRAGMA user_version = 48;`);
|
|
15320
15392
|
}
|
|
15393
|
+
if (v < 49) {
|
|
15394
|
+
if (!this.hasColumn("api_usage", "ctx_used")) this.db.exec(`ALTER TABLE api_usage ADD COLUMN ctx_used INTEGER DEFAULT 0;`);
|
|
15395
|
+
this.db.exec(`PRAGMA user_version = 49;`);
|
|
15396
|
+
}
|
|
15321
15397
|
}
|
|
15322
15398
|
listConversations(q, kind = "all") {
|
|
15323
15399
|
if (q) {
|
|
@@ -15688,8 +15764,8 @@ var ConversationStore = class {
|
|
|
15688
15764
|
recordApiUsage(rec) {
|
|
15689
15765
|
const rate = (v) => v != null && Number.isFinite(v) && v > 0 ? v : null;
|
|
15690
15766
|
this.db.prepare(`
|
|
15691
|
-
INSERT INTO api_usage (id, created_at, source, model_key, prompt_tokens, gen_tokens, code_session_id, duration_ms, prompt_tps, gen_tps, harness)
|
|
15692
|
-
VALUES ($id, $createdAt, $source, $modelKey, $promptTokens, $genTokens, $codeSessionId, $durationMs, $promptTps, $genTps, $harness)
|
|
15767
|
+
INSERT INTO api_usage (id, created_at, source, model_key, prompt_tokens, gen_tokens, code_session_id, duration_ms, prompt_tps, gen_tps, harness, ctx_used)
|
|
15768
|
+
VALUES ($id, $createdAt, $source, $modelKey, $promptTokens, $genTokens, $codeSessionId, $durationMs, $promptTps, $genTps, $harness, $ctxUsed)
|
|
15693
15769
|
`).run({
|
|
15694
15770
|
$id: randomUUID6(),
|
|
15695
15771
|
$createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15701,9 +15777,40 @@ var ConversationStore = class {
|
|
|
15701
15777
|
$durationMs: rec.durationMs != null && Number.isFinite(rec.durationMs) ? Math.max(0, Math.floor(rec.durationMs)) : null,
|
|
15702
15778
|
$promptTps: rate(rec.promptTps),
|
|
15703
15779
|
$genTps: rate(rec.genTps),
|
|
15704
|
-
$harness: rec.harness ?? null
|
|
15780
|
+
$harness: rec.harness ?? null,
|
|
15781
|
+
$ctxUsed: Math.max(0, Math.floor(rec.promptTokens) || 0)
|
|
15705
15782
|
});
|
|
15706
15783
|
}
|
|
15784
|
+
/** Lower the current context size for a Code session after /compact, so the ctx gauge
|
|
15785
|
+
* reflects post-compaction reality (ADR-386). Updates the row with the MAX ctx_used
|
|
15786
|
+
* to the new value — this is what allows /compact to lower the ring's frozen ceiling.
|
|
15787
|
+
* If no row exists yet (fresh session compacted before first gateway request), creates one. */
|
|
15788
|
+
setCodeSessionCtxUsed(codeSessionId, ctxUsed) {
|
|
15789
|
+
const maxRow = this.db.prepare(`
|
|
15790
|
+
SELECT id FROM api_usage
|
|
15791
|
+
WHERE code_session_id = $codeSessionId AND ctx_used = (
|
|
15792
|
+
SELECT MAX(ctx_used) FROM api_usage WHERE code_session_id = $codeSessionId
|
|
15793
|
+
)
|
|
15794
|
+
LIMIT 1
|
|
15795
|
+
`).get({ $codeSessionId: codeSessionId });
|
|
15796
|
+
if (maxRow) {
|
|
15797
|
+
this.db.prepare(`
|
|
15798
|
+
UPDATE api_usage SET ctx_used = $ctxUsed, prompt_tokens = $promptTokens, created_at = $createdAt
|
|
15799
|
+
WHERE id = $id
|
|
15800
|
+
`).run({ $ctxUsed: ctxUsed, $promptTokens: ctxUsed, $createdAt: (/* @__PURE__ */ new Date()).toISOString(), $id: maxRow.id });
|
|
15801
|
+
} else {
|
|
15802
|
+
this.db.prepare(`
|
|
15803
|
+
INSERT INTO api_usage (id, created_at, source, prompt_tokens, gen_tokens, code_session_id, ctx_used)
|
|
15804
|
+
VALUES ($id, $createdAt, 'compact', $promptTokens, 0, $codeSessionId, $ctxUsed)
|
|
15805
|
+
`).run({
|
|
15806
|
+
$id: randomUUID6(),
|
|
15807
|
+
$createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15808
|
+
$promptTokens: ctxUsed,
|
|
15809
|
+
$codeSessionId: codeSessionId,
|
|
15810
|
+
$ctxUsed: ctxUsed
|
|
15811
|
+
});
|
|
15812
|
+
}
|
|
15813
|
+
}
|
|
15707
15814
|
/** The session's own gateway-request stats (ADR-284, revised twice — founder-reported "ctx
|
|
15708
15815
|
* fill jumps between full and empty in the same session", then a review pass on that same fix
|
|
15709
15816
|
* catching that it had gone on to freeze the LAST-TURN stats too). Two different questions,
|
|
@@ -15737,14 +15844,14 @@ var ConversationStore = class {
|
|
|
15737
15844
|
* non-terminal-agent one). */
|
|
15738
15845
|
getLastApiUsageForSession(codeSessionId) {
|
|
15739
15846
|
const row = this.db.prepare(`
|
|
15740
|
-
SELECT prompt_tokens, gen_tokens, duration_ms, prompt_tps, gen_tps FROM api_usage
|
|
15847
|
+
SELECT prompt_tokens, gen_tokens, duration_ms, prompt_tps, gen_tps, ctx_used FROM api_usage
|
|
15741
15848
|
WHERE code_session_id = $codeSessionId
|
|
15742
15849
|
ORDER BY created_at DESC LIMIT 1
|
|
15743
15850
|
`).get({ $codeSessionId: codeSessionId });
|
|
15744
15851
|
if (!row) return null;
|
|
15745
15852
|
const ctxUsed = this.db.prepare(`
|
|
15746
|
-
SELECT MAX(
|
|
15747
|
-
`).get({ $codeSessionId: codeSessionId }).
|
|
15853
|
+
SELECT MAX(ctx_used) as maxCtxUsed FROM api_usage WHERE code_session_id = $codeSessionId
|
|
15854
|
+
`).get({ $codeSessionId: codeSessionId }).maxCtxUsed;
|
|
15748
15855
|
const seconds = row.duration_ms != null && row.duration_ms > 0 ? row.duration_ms / 1e3 : null;
|
|
15749
15856
|
return {
|
|
15750
15857
|
ctxUsed,
|
|
@@ -19915,12 +20022,12 @@ var ModelRouter = class {
|
|
|
19915
20022
|
* skipped. Callers are responsible for their OWN idle-vs-busy decision before calling this
|
|
19916
20023
|
* (see routines/model-swap.ts) — this method has no opinion on whether now is a safe time to
|
|
19917
20024
|
* swap, only on HOW to swap once that's decided. */
|
|
19918
|
-
async loadExplicit(modelKey) {
|
|
20025
|
+
async loadExplicit(modelKey, overrides) {
|
|
19919
20026
|
const remote = this.resolveRemote(modelKey);
|
|
19920
20027
|
if (remote) return remote;
|
|
19921
20028
|
const entry = this.resolveEntry(modelKey);
|
|
19922
20029
|
if (!entry) return { status: 503, message: `No model matching '${modelKey}' found. Add one in TurboLLM.` };
|
|
19923
|
-
return this.withSwapLock(() => this.doLoad(entry));
|
|
20030
|
+
return this.withSwapLock(() => this.doLoad(entry, overrides));
|
|
19924
20031
|
}
|
|
19925
20032
|
/** Acquire the SAME swap-serialization queue `route()` uses, then run `fn` exclusively with
|
|
19926
20033
|
* respect to any other swap (manual or auto). `route()` itself is just this wrapping
|
|
@@ -19983,7 +20090,7 @@ var ModelRouter = class {
|
|
|
19983
20090
|
return keys;
|
|
19984
20091
|
}
|
|
19985
20092
|
// ── internal ──────────────────────────────────────────────────────────────
|
|
19986
|
-
async doLoad(entry) {
|
|
20093
|
+
async doLoad(entry, overrides) {
|
|
19987
20094
|
{
|
|
19988
20095
|
const ms = this.manager.status();
|
|
19989
20096
|
if (ms.state === "running" && ms.model && this.keysMatch(ms.model.key, entry)) {
|
|
@@ -20006,7 +20113,7 @@ var ModelRouter = class {
|
|
|
20006
20113
|
if (!engineAcceptsFormat(active.kind, entry.format)) {
|
|
20007
20114
|
return { status: 503, message: `Active engine cannot load model format '${entry.format}'.` };
|
|
20008
20115
|
}
|
|
20009
|
-
const opts = this.buildOpts(entry, active);
|
|
20116
|
+
const opts = this.buildOpts(entry, active, overrides);
|
|
20010
20117
|
if (!opts) return { status: 503, message: "Model is incomplete or unreadable." };
|
|
20011
20118
|
const keepN = Math.max(1, this.store.snapshot().gateway.keepN);
|
|
20012
20119
|
const needsNewSlot = entry.embedding || this.chatSlotCount() < keepN;
|
|
@@ -20144,13 +20251,13 @@ var ModelRouter = class {
|
|
|
20144
20251
|
keysMatch(loadedKey, entry) {
|
|
20145
20252
|
return loadedKey === entry.key || loadedKey === entry.path;
|
|
20146
20253
|
}
|
|
20147
|
-
buildOpts(entry, engine) {
|
|
20254
|
+
buildOpts(entry, engine, overrides) {
|
|
20148
20255
|
if (entry.incomplete || entry.parseError) return null;
|
|
20149
20256
|
const cfg2 = this.store.snapshot();
|
|
20150
20257
|
const sys = getSysInfo();
|
|
20151
20258
|
if (entry.format !== "gguf") {
|
|
20152
20259
|
const savedProfile = getModelProfile(cfg2, entry.key, engine.id);
|
|
20153
|
-
const profile2 = resolveProfile(entry, sys, savedProfile,
|
|
20260
|
+
const profile2 = resolveProfile(entry, sys, savedProfile, overrides, cfg2.modelDefaults);
|
|
20154
20261
|
return {
|
|
20155
20262
|
engine,
|
|
20156
20263
|
model: { key: entry.key, name: entry.name, quant: entry.quant, ctx: entry.nativeCtx, vision: entry.vision },
|
|
@@ -20163,7 +20270,7 @@ var ModelRouter = class {
|
|
|
20163
20270
|
};
|
|
20164
20271
|
}
|
|
20165
20272
|
const saved = getModelProfile(cfg2, entry.key, engine.id);
|
|
20166
|
-
const profile = resolveProfile(entry, sys, saved,
|
|
20273
|
+
const profile = resolveProfile(entry, sys, saved, overrides, cfg2.modelDefaults);
|
|
20167
20274
|
const extraArgs = engine.kind === "koboldcpp" ? koboldcppProfileToArgs(profile, sys.gpus[0]?.vendor ?? "unknown", sys.gpus.length > 0) : profileToArgs(profile, entry, engine.capabilities, sys.cores, sys, engine.binPath);
|
|
20168
20275
|
return {
|
|
20169
20276
|
engine,
|
|
@@ -22400,7 +22507,7 @@ __all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
|
|
|
22400
22507
|
|
|
22401
22508
|
// src/api/routes.ts
|
|
22402
22509
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
22403
|
-
import { homedir as homedir4
|
|
22510
|
+
import { homedir as homedir4 } from "os";
|
|
22404
22511
|
|
|
22405
22512
|
// src/config/config-bounds.ts
|
|
22406
22513
|
var CONFIG_BOUNDS = {
|
|
@@ -22506,7 +22613,10 @@ var ALL = [
|
|
|
22506
22613
|
support: "stable",
|
|
22507
22614
|
// llama.cpp expands into the backend sub-picker (existing UI); it has no single
|
|
22508
22615
|
// install endpoint of its own.
|
|
22509
|
-
installEndpoint: ""
|
|
22616
|
+
installEndpoint: "",
|
|
22617
|
+
// Its installed state comes from the separate backend-build detection (LlamaCppBackendRows),
|
|
22618
|
+
// not the generic sourceRepo match below — see the field's own doc comment (ADR-388).
|
|
22619
|
+
excludeFromSourceMatch: true
|
|
22510
22620
|
},
|
|
22511
22621
|
{
|
|
22512
22622
|
// Upstream publishes NO Linux CUDA prebuilt (download.ts availableBackends() — Linux
|
|
@@ -23972,9 +24082,6 @@ async function startEngine(c, d, b) {
|
|
|
23972
24082
|
const active = d.registry.active();
|
|
23973
24083
|
if (!active) return err4(c, 409, "no_active_engine", "Register and select an engine first.");
|
|
23974
24084
|
if (d.comfy?.isBlocked()) return err4(c, 409, "comfyui_busy", "ComfyUI is rendering \u2014 model loading is paused until its queue finishes.");
|
|
23975
|
-
d.bench.cancel();
|
|
23976
|
-
abortAllInFlightChats();
|
|
23977
|
-
await d.bench.waitIdle();
|
|
23978
24085
|
const cfg2 = d.store.snapshot();
|
|
23979
24086
|
const sys = getSysInfo();
|
|
23980
24087
|
let key = b.modelKey ?? "";
|
|
@@ -23997,6 +24104,13 @@ async function startEngine(c, d, b) {
|
|
|
23997
24104
|
`${engineLabel} cannot load models with an audio tower \u2014 the audio encoder ${certainty} due to an upstream mlx-vlm bug in the sanitizer for these architectures. Switch to the MLX engine instead.`
|
|
23998
24105
|
);
|
|
23999
24106
|
}
|
|
24107
|
+
if (entry.embedding) {
|
|
24108
|
+
void d.modelRouter.loadExplicit(entry.key, b.profileOverrides).catch((e) => console.warn(`engine load failed: ${e}`));
|
|
24109
|
+
return c.json({ ok: true }, 202);
|
|
24110
|
+
}
|
|
24111
|
+
d.bench.cancel();
|
|
24112
|
+
abortAllInFlightChats();
|
|
24113
|
+
await d.bench.waitIdle();
|
|
24000
24114
|
let opts2;
|
|
24001
24115
|
if (entry.format !== "gguf") {
|
|
24002
24116
|
const savedProfile = getModelProfile(cfg2, entry.key, active.id);
|
|
@@ -24041,6 +24155,9 @@ async function startEngine(c, d, b) {
|
|
|
24041
24155
|
name = cfg2.devModel.label;
|
|
24042
24156
|
}
|
|
24043
24157
|
if (!modelPath) return err4(c, 409, "no_such_model", "No model specified. Pick one from the Models screen.");
|
|
24158
|
+
d.bench.cancel();
|
|
24159
|
+
abortAllInFlightChats();
|
|
24160
|
+
await d.bench.waitIdle();
|
|
24044
24161
|
const opts = { engine: active, model: deriveModel(modelPath, name, extra), modelPath, extraArgs: extra };
|
|
24045
24162
|
void d.modelRouter.withSwapLock(() => d.manager.load(opts, { beforeStart: () => d.comfy?.freeComfyUIBeforeLoad() ?? Promise.resolve() })).then(() => d.modelRouter.markPrimaryLoaded()).catch((e) => console.warn(`engine load failed: ${e}`));
|
|
24046
24163
|
return c.json({ ok: true }, 202);
|
|
@@ -24501,11 +24618,11 @@ function registerApi(app2, d) {
|
|
|
24501
24618
|
installed2 = existsSync26(llamafileBinPath(enginesRoot));
|
|
24502
24619
|
enabled = regEngines.some((x) => x.kind === "llamafile");
|
|
24503
24620
|
}
|
|
24504
|
-
const srcEng = regEngines.find(
|
|
24621
|
+
const srcEng = e.excludeFromSourceMatch ? void 0 : regEngines.find(
|
|
24505
24622
|
(x) => sameRepo(x.sourceRepo, e.homepage) && (x.sourceCommit ?? "") === (e.sourceCommit ?? "") && (x.sourcePatchUrl ?? "") === (e.patchUrl ?? "")
|
|
24506
24623
|
);
|
|
24507
24624
|
let sourceBinPath = srcEng?.binPath;
|
|
24508
|
-
if (!srcEng) sourceBinPath = sourceBuildBinary(enginesRoot, e.homepage, void 0, e.sourceCommit) ?? void 0;
|
|
24625
|
+
if (!srcEng && !e.excludeFromSourceMatch) sourceBinPath = sourceBuildBinary(enginesRoot, e.homepage, void 0, e.sourceCommit) ?? void 0;
|
|
24509
24626
|
const sourceBuilt = !!srcEng || !!sourceBinPath;
|
|
24510
24627
|
if (srcEng) {
|
|
24511
24628
|
installed2 = true;
|
|
@@ -24604,7 +24721,7 @@ function registerApi(app2, d) {
|
|
|
24604
24721
|
} catch {
|
|
24605
24722
|
}
|
|
24606
24723
|
}
|
|
24607
|
-
const eng = (await d.registry.add(prior?.name
|
|
24724
|
+
const eng = (await d.registry.add(chooseEngineName(name, prior?.name), out.binPath, {
|
|
24608
24725
|
sourceRepo: repoUrl,
|
|
24609
24726
|
sourceBranch: branch,
|
|
24610
24727
|
sourceCommit: commit,
|
|
@@ -25501,7 +25618,7 @@ function registerApi(app2, d) {
|
|
|
25501
25618
|
const cfg2 = d.store.snapshot();
|
|
25502
25619
|
return c.json({
|
|
25503
25620
|
lanBind: cfg2.daemon.lanBind,
|
|
25504
|
-
lanUrl: `http://${getLanIp()}:${cfg2.daemon.port}`,
|
|
25621
|
+
lanUrl: `http://${getLanIp() ?? "127.0.0.1"}:${cfg2.daemon.port}`,
|
|
25505
25622
|
hasApiKey: cfg2.apiKeys.length > 0,
|
|
25506
25623
|
requireApiKey: cfg2.daemon.requireApiKey,
|
|
25507
25624
|
isHost: isLocalRequest(c, d)
|
|
@@ -25671,7 +25788,7 @@ function registerApi(app2, d) {
|
|
|
25671
25788
|
const cli = c.req.param("cli");
|
|
25672
25789
|
const cfg2 = d.store.snapshot();
|
|
25673
25790
|
const { port: port2, lanBind } = cfg2.daemon;
|
|
25674
|
-
const host2 = lanBind ? getLanIp() : "127.0.0.1";
|
|
25791
|
+
const host2 = lanBind ? getLanIp() ?? "127.0.0.1" : "127.0.0.1";
|
|
25675
25792
|
const base2 = `http://${host2}:${port2}`;
|
|
25676
25793
|
const ms = d.manager.status();
|
|
25677
25794
|
const modelName = ms.state === "running" ? ms.model?.name ?? "local" : "local";
|
|
@@ -25989,16 +26106,6 @@ function listWindowsDrives() {
|
|
|
25989
26106
|
}
|
|
25990
26107
|
return drives;
|
|
25991
26108
|
}
|
|
25992
|
-
function getLanIp() {
|
|
25993
|
-
const nets = networkInterfaces2();
|
|
25994
|
-
for (const ifaces of Object.values(nets)) {
|
|
25995
|
-
if (!ifaces) continue;
|
|
25996
|
-
for (const iface of ifaces) {
|
|
25997
|
-
if (iface.family === "IPv4" && !iface.internal) return iface.address;
|
|
25998
|
-
}
|
|
25999
|
-
}
|
|
26000
|
-
return "127.0.0.1";
|
|
26001
|
-
}
|
|
26002
26109
|
function buildConnectSnippets(cli, base2, apiKey, modelName, modelKey = modelName) {
|
|
26003
26110
|
switch (cli) {
|
|
26004
26111
|
case "claude-code":
|
|
@@ -26162,7 +26269,6 @@ function buildConnectSnippets(cli, base2, apiKey, modelName, modelKey = modelNam
|
|
|
26162
26269
|
|
|
26163
26270
|
// src/api/link-admin-routes.ts
|
|
26164
26271
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
26165
|
-
import { networkInterfaces as networkInterfaces3 } from "os";
|
|
26166
26272
|
|
|
26167
26273
|
// src/link/link-state.ts
|
|
26168
26274
|
function nextStatus(current, probe2) {
|
|
@@ -27134,12 +27240,7 @@ function remoteFailure(c, rec, probe2) {
|
|
|
27134
27240
|
);
|
|
27135
27241
|
}
|
|
27136
27242
|
function lanHost() {
|
|
27137
|
-
|
|
27138
|
-
for (const a of iface ?? []) {
|
|
27139
|
-
if (a.family === "IPv4" && !a.internal) return a.address;
|
|
27140
|
-
}
|
|
27141
|
-
}
|
|
27142
|
-
return "localhost";
|
|
27243
|
+
return getLanIp() ?? "localhost";
|
|
27143
27244
|
}
|
|
27144
27245
|
|
|
27145
27246
|
// src/chat/chat-agent-routes.ts
|
|
@@ -31148,14 +31249,14 @@ import { streamSSE as streamSSE5 } from "hono/streaming";
|
|
|
31148
31249
|
// src/ext/context-limit.ts
|
|
31149
31250
|
var CHARS_PER_TOKEN2 = 3.5;
|
|
31150
31251
|
var REPLY_HEADROOM = 512;
|
|
31151
|
-
function
|
|
31252
|
+
function estimateTokens2(messages) {
|
|
31152
31253
|
let chars = 0;
|
|
31153
31254
|
for (const m of messages) chars += m.content.length + m.role.length + 4;
|
|
31154
31255
|
return Math.ceil(chars / CHARS_PER_TOKEN2);
|
|
31155
31256
|
}
|
|
31156
31257
|
function checkContextFits(d, messages) {
|
|
31157
31258
|
const limit = d.manager.status().model?.ctx ?? 0;
|
|
31158
|
-
const estimated =
|
|
31259
|
+
const estimated = estimateTokens2(messages);
|
|
31159
31260
|
if (!limit) return { fits: true, estimated, limit: 0 };
|
|
31160
31261
|
return { fits: estimated + REPLY_HEADROOM <= limit, estimated, limit };
|
|
31161
31262
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
2
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
3
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
4
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
5
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
6
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
7
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
8
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
9
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
10
|
+
{"t":0,"agent":"a0686ab","agent_type":"unknown","event":"agent_stop","success":true}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./radix-B0YBjihE.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-D0Emka7d.js";import{f as V}from"./chat-api-Zyxy4wka.js";import{f as X,a as Z}from"./agent-api-CmhXBBT6.js";import{P as B}from"./personas-CeAQ6niU.js";import{C as ee}from"./chevron-left-CBtdrcDZ.js";import{R as te}from"./rotate-ccw-BpPatpxx.js";import{T as se}from"./trash-2-DbQqCHSH.js";import{C as ne}from"./chevron-right-DRLCoDa8.js";import"./dropdown-menu-DRRO0ftt.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-B0YBjihE.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-C9ZXfFYo.js";import{f as V}from"./chat-api-Bgrb0rnf.js";import{f as X,a as Z}from"./agent-api-BAMDY8-v.js";import{P as B}from"./personas-Dkq9JD72.js";import{C as ee}from"./chevron-left-CxvUI3ck.js";import{R as te}from"./rotate-ccw-kHM_pFpt.js";import{T as se}from"./trash-2-BXZkODa0.js";import{C as ne}from"./chevron-right-CpdnK5S2.js";import"./dropdown-menu-CaecUWTU.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};
|