turbollm 1.10.5 → 1.10.6

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.
Files changed (118) hide show
  1. package/dist/cli.js +162 -30
  2. package/dist/webdist/assets/{AgentEditPage-Bq0To2Kn.js → AgentEditPage-Cjrahm7d.js} +1 -1
  3. package/dist/webdist/assets/{ChatScreen-JfS4dp94.js → ChatScreen-BE2j_M7n.js} +1 -1
  4. package/dist/webdist/assets/{CodeComposer-BPcKbMuH.js → CodeComposer-CB0nORiZ.js} +1 -1
  5. package/dist/webdist/assets/{CodeHomeScreen-CbY_UCs6.js → CodeHomeScreen-Bh0BY6aY.js} +1 -1
  6. package/dist/webdist/assets/{CodeSessionScreen-nU50H3fR.js → CodeSessionScreen-MM4gt_kH.js} +1 -1
  7. package/dist/webdist/assets/{CustomizeScreen-jI99vrYL.js → CustomizeScreen-zvF_dtiC.js} +1 -1
  8. package/dist/webdist/assets/{DeveloperScreen-BfYnTO7e.js → DeveloperScreen-DXzdDB5X.js} +1 -1
  9. package/dist/webdist/assets/{EnginesScreen-CU8ZNHcl.js → EnginesScreen-CLkBmRVD.js} +1 -1
  10. package/dist/webdist/assets/{ModelDetailDialog-DKUMTU2w.js → ModelDetailDialog-CL8_8e9a.js} +1 -1
  11. package/dist/webdist/assets/{ModelLoadMenu-CBj32oEE.js → ModelLoadMenu-C6W2D_HT.js} +1 -1
  12. package/dist/webdist/assets/{ModelsScreen-CTYIbZyc.js → ModelsScreen-CMEUd2XW.js} +1 -1
  13. package/dist/webdist/assets/{RoutineEditPage-gqLu8cXv.js → RoutineEditPage-DNt9jwLQ.js} +1 -1
  14. package/dist/webdist/assets/{RoutinesPanel-Dv9Shubg.js → RoutinesPanel-APLk8zAj.js} +1 -1
  15. package/dist/webdist/assets/{SettingsScreen-C7LQLNGe.js → SettingsScreen-CNEhuloT.js} +1 -1
  16. package/dist/webdist/assets/{SidebarResizeHandle-Djhjx6qR.js → SidebarResizeHandle-BGh24zM4.js} +1 -1
  17. package/dist/webdist/assets/{SkillEditPage-ClBJXbC3.js → SkillEditPage-QktxVVZP.js} +1 -1
  18. package/dist/webdist/assets/{TokensScreen-gk_Mqi5g.js → TokensScreen-BQu-wJ5j.js} +1 -1
  19. package/dist/webdist/assets/{ToolApprovalBar-B3WSFcyU.js → ToolApprovalBar-WuURxg64.js} +3 -3
  20. package/dist/webdist/assets/WorkspaceScreen-DR9iCevI.js +1 -0
  21. package/dist/webdist/assets/{abnfDiagram-N423BO3Z-QSevWJ37.js → abnfDiagram-N423BO3Z-Xdm1Ge5Z.js} +1 -1
  22. package/dist/webdist/assets/{agent-api-CpgzOfg0.js → agent-api-Dsb2M3gT.js} +1 -1
  23. package/dist/webdist/assets/{alert-dialog-CMvNzcK0.js → alert-dialog-CLYOFUQB.js} +1 -1
  24. package/dist/webdist/assets/{arc-BWbVGHju.js → arc-D2e7_fvj.js} +1 -1
  25. package/dist/webdist/assets/{architectureDiagram-T3A2C74G-Boh67Blv.js → architectureDiagram-T3A2C74G-NOGk06k9.js} +1 -1
  26. package/dist/webdist/assets/{arrow-left-CU7vJBtU.js → arrow-left-Be5kJCK_.js} +1 -1
  27. package/dist/webdist/assets/{badge-BOGctZvx.js → badge-ZKEdg9KY.js} +1 -1
  28. package/dist/webdist/assets/{blockDiagram-VBNYF7ZC-BkIBotfv.js → blockDiagram-VBNYF7ZC-DmcFoOYB.js} +1 -1
  29. package/dist/webdist/assets/{bot-CwYS2B1G.js → bot-oaBq4kgz.js} +1 -1
  30. package/dist/webdist/assets/{c4Diagram-5PPSVZJV-CWCZQHIc.js → c4Diagram-5PPSVZJV-zzYM53Qc.js} +1 -1
  31. package/dist/webdist/assets/channel-BdTqTBNl.js +1 -0
  32. package/dist/webdist/assets/{chat-api-BTcC6kED.js → chat-api-D7WunS4X.js} +1 -1
  33. package/dist/webdist/assets/{chat-queries-D9fFhHaQ.js → chat-queries-DfV_X46e.js} +1 -1
  34. package/dist/webdist/assets/{chevron-left-BVxkM758.js → chevron-left-DqcpOb9h.js} +1 -1
  35. package/dist/webdist/assets/{chevron-right-BJZRbTUj.js → chevron-right-D7i8peZR.js} +1 -1
  36. package/dist/webdist/assets/{chunk-2GRJ4B5K-C5CXDrO_.js → chunk-2GRJ4B5K-tWNhRyV6.js} +1 -1
  37. package/dist/webdist/assets/{chunk-2Q5K7J3B-Bk_wrlB0.js → chunk-2Q5K7J3B-jT4PFPv5.js} +1 -1
  38. package/dist/webdist/assets/{chunk-5RXB4S5H-BAT4FnUI.js → chunk-5RXB4S5H-CBgg6cvO.js} +1 -1
  39. package/dist/webdist/assets/{chunk-5VM5RSS4-C9eEV1Kl.js → chunk-5VM5RSS4-Do3-h3Xi.js} +1 -1
  40. package/dist/webdist/assets/{chunk-6Q2QTUOP-CJDFqmYe.js → chunk-6Q2QTUOP-Y4iDp1I8.js} +1 -1
  41. package/dist/webdist/assets/{chunk-GF5L2VYU-CsgBXjfk.js → chunk-GF5L2VYU-Bj41431x.js} +1 -1
  42. package/dist/webdist/assets/{chunk-JWPE2WC7-CRt7uW9O.js → chunk-JWPE2WC7-CufywS1e.js} +1 -1
  43. package/dist/webdist/assets/{chunk-KBJHAD2P-CSsVpcf6.js → chunk-KBJHAD2P-BPLIKhbV.js} +1 -1
  44. package/dist/webdist/assets/{chunk-RYQCIY6F-eTll7wC1.js → chunk-RYQCIY6F-CmcnhnsQ.js} +1 -1
  45. package/dist/webdist/assets/{chunk-XXDRQBXY-D2-Dj7EK.js → chunk-XXDRQBXY-onzm5o_Q.js} +1 -1
  46. package/dist/webdist/assets/{circle-check-g29PWBwU.js → circle-check-BY8jczPf.js} +1 -1
  47. package/dist/webdist/assets/{circle-x-BgFrKCxR.js → circle-x-BUlKg2cZ.js} +1 -1
  48. package/dist/webdist/assets/classDiagram-JCYQIIEL-R1cuP_Pr.js +1 -0
  49. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-R1cuP_Pr.js +1 -0
  50. package/dist/webdist/assets/{common-Fwu8t36v.js → common-BsHtz98M.js} +1 -1
  51. package/dist/webdist/assets/{cose-bilkent-JH36ORCC-DXafCcEB.js → cose-bilkent-JH36ORCC-8JLhJahr.js} +1 -1
  52. package/dist/webdist/assets/{cynefin-VYW2F7L2-CecX93d_.js → cynefin-VYW2F7L2-CBL5ANhm.js} +1 -1
  53. package/dist/webdist/assets/{cynefinDiagram-MW4NZA55-tu8xDmsR.js → cynefinDiagram-MW4NZA55-Cmwj48UP.js} +1 -1
  54. package/dist/webdist/assets/{dagre-VZM6K2ZE-UG2o94YJ.js → dagre-VZM6K2ZE-DngjyEsb.js} +1 -1
  55. package/dist/webdist/assets/{diagram-7IWD3JNH-3DRTAZAF.js → diagram-7IWD3JNH-OQyUakUJ.js} +1 -1
  56. package/dist/webdist/assets/{diagram-B4RE2ZJO-CwH0bQ2A.js → diagram-B4RE2ZJO-uWCxDSmb.js} +1 -1
  57. package/dist/webdist/assets/{diagram-LBJQPF4R-DuybxKFU.js → diagram-LBJQPF4R-BYhk_VPg.js} +1 -1
  58. package/dist/webdist/assets/{diagram-Q27KOJAE-BwoB84ui.js → diagram-Q27KOJAE-CzML3pPm.js} +1 -1
  59. package/dist/webdist/assets/{diagram-UB23O5K3-DEjbnHCQ.js → diagram-UB23O5K3-DIL750-6.js} +1 -1
  60. package/dist/webdist/assets/{dropdown-menu-D25-JVEy.js → dropdown-menu-CCRmjOB8.js} +1 -1
  61. package/dist/webdist/assets/{ebnfDiagram-BXEA7PRR-DG9Xbpyw.js → ebnfDiagram-BXEA7PRR-IOFFHUjP.js} +1 -1
  62. package/dist/webdist/assets/{erDiagram-JOGREHBK-eysaP8yv.js → erDiagram-JOGREHBK-CsYREjU2.js} +1 -1
  63. package/dist/webdist/assets/{external-link-Xn8kJljc.js → external-link-CwcqLXeC.js} +1 -1
  64. package/dist/webdist/assets/{file-text-BmAkLphS.js → file-text-CfktJNKt.js} +1 -1
  65. package/dist/webdist/assets/{flowDiagram-UKHOOZJN-Bfha7bpG.js → flowDiagram-UKHOOZJN-D8V23snk.js} +1 -1
  66. package/dist/webdist/assets/{folder-input-BRjaJam7.js → folder-input-CAX7jGqy.js} +1 -1
  67. package/dist/webdist/assets/{folder-plus-DBJ9oQjK.js → folder-plus-DRH9A_nf.js} +1 -1
  68. package/dist/webdist/assets/{ganttDiagram-PKOTCBZU-CJotaSgm.js → ganttDiagram-PKOTCBZU-BNFLscau.js} +1 -1
  69. package/dist/webdist/assets/{git-branch-DerJ3eCK.js → git-branch-D3SWa_HB.js} +1 -1
  70. package/dist/webdist/assets/{gitGraphDiagram-DS77QQ5N-C8za5q5H.js → gitGraphDiagram-DS77QQ5N-CACE08jS.js} +1 -1
  71. package/dist/webdist/assets/{index-CRd__4R1.js → index-C3DcPrhr.js} +2 -2
  72. package/dist/webdist/assets/{infoDiagram-6WML65LV-C95kKxPZ.js → infoDiagram-6WML65LV-Bgac4fco.js} +1 -1
  73. package/dist/webdist/assets/{ishikawaDiagram-WSZJBQD7-DOIqcMyH.js → ishikawaDiagram-WSZJBQD7-B-Gx-xHY.js} +1 -1
  74. package/dist/webdist/assets/{journeyDiagram-NVQOT4AX-BBirkGE7.js → journeyDiagram-NVQOT4AX-HkIDa9gF.js} +1 -1
  75. package/dist/webdist/assets/{kanban-definition-27J2QSJJ-CPhjxJyV.js → kanban-definition-27J2QSJJ-D9fCO--l.js} +1 -1
  76. package/dist/webdist/assets/{linear-BWhxZFqF.js → linear-BCzUyXir.js} +1 -1
  77. package/dist/webdist/assets/{lock-CpPOIG8p.js → lock-DU6baFK9.js} +1 -1
  78. package/dist/webdist/assets/{mermaid.core-DocKtbj4.js → mermaid.core-DKhj1zV1.js} +4 -4
  79. package/dist/webdist/assets/{mindmap-definition-FAOFIHXS-wL4xGOU_.js → mindmap-definition-FAOFIHXS-DStYIFGn.js} +1 -1
  80. package/dist/webdist/assets/{pegDiagram-VL7TDLO6-D19VvRVO.js → pegDiagram-VL7TDLO6-CMkk8HUV.js} +1 -1
  81. package/dist/webdist/assets/{pencil-c-PJkJes.js → pencil-Bt-RSZUH.js} +1 -1
  82. package/dist/webdist/assets/{personas-B0p0BX69.js → personas-DLa9ZPoi.js} +4 -4
  83. package/dist/webdist/assets/{pieDiagram-7S7Q4E2Y-Doy7WZyw.js → pieDiagram-7S7Q4E2Y-BaK0uEYv.js} +1 -1
  84. package/dist/webdist/assets/{plus-CP7d5krT.js → plus-CFBywfW5.js} +1 -1
  85. package/dist/webdist/assets/{quadrantDiagram-CIZ2JOQS-BO535Mye.js → quadrantDiagram-CIZ2JOQS-C34UZIt1.js} +1 -1
  86. package/dist/webdist/assets/{railroadDiagram-AXF67PYL-C_F6C_-j.js → railroadDiagram-AXF67PYL-Ckb23iRj.js} +1 -1
  87. package/dist/webdist/assets/{refresh-cw-CUFncOr4.js → refresh-cw-BjYW1yib.js} +1 -1
  88. package/dist/webdist/assets/{requirementDiagram-LRYGKXZP-COStqNVI.js → requirementDiagram-LRYGKXZP-CG2IfNZ8.js} +1 -1
  89. package/dist/webdist/assets/{rotate-ccw-gR3mMTRM.js → rotate-ccw-CDrolPd6.js} +1 -1
  90. package/dist/webdist/assets/{sankeyDiagram-W5VNT64P-DrpcfTw1.js → sankeyDiagram-W5VNT64P-C37_2Ghs.js} +1 -1
  91. package/dist/webdist/assets/{sequenceDiagram-SI44F4Z6-CQ1WUoj0.js → sequenceDiagram-SI44F4Z6-Cbd9Ydzi.js} +1 -1
  92. package/dist/webdist/assets/{sizeCapture-X5ZJPWSS-CExk2dPw.js → sizeCapture-X5ZJPWSS-Db4VW9lY.js} +1 -1
  93. package/dist/webdist/assets/{skeleton-CapS3LhZ.js → skeleton-C8GLzn0j.js} +1 -1
  94. package/dist/webdist/assets/{sliders-horizontal-VjLq-9i0.js → sliders-horizontal-ChT1DRyQ.js} +1 -1
  95. package/dist/webdist/assets/{sparkles-BS98k72s.js → sparkles-BgaRXk3Z.js} +1 -1
  96. package/dist/webdist/assets/{star-Ce5Pu8jP.js → star-CVPXfTy4.js} +1 -1
  97. package/dist/webdist/assets/{stateDiagram-OKZ733FA-6IQ9pQNr.js → stateDiagram-OKZ733FA-RgxA3rS_.js} +1 -1
  98. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-DW4K46xR.js +1 -0
  99. package/dist/webdist/assets/{swimlanes-SLNWSIFB-0AoFXo4W.js → swimlanes-SLNWSIFB-PmBwCiF3.js} +2 -2
  100. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC--nEBdjnh.js +8 -0
  101. package/dist/webdist/assets/{switch-BVPOy4cS.js → switch-CjDd4avM.js} +1 -1
  102. package/dist/webdist/assets/{terminal-WfRPZiaW.js → terminal-z7vkSxg1.js} +1 -1
  103. package/dist/webdist/assets/{timeline-definition-Z64GVDOM-LPqGGX5H.js → timeline-definition-Z64GVDOM-vxaLdkHH.js} +1 -1
  104. package/dist/webdist/assets/{trash-2-DZYSgl2R.js → trash-2-BNqXKVdk.js} +1 -1
  105. package/dist/webdist/assets/{useIsDesktop-CjFyl6hu.js → useIsDesktop-CRP_qB3o.js} +1 -1
  106. package/dist/webdist/assets/{vennDiagram-T6HMQDX7--BcdXECz.js → vennDiagram-T6HMQDX7-CY5Ha4JW.js} +1 -1
  107. package/dist/webdist/assets/{vram-DlcIXX82.js → vram-C6uGfhzc.js} +1 -1
  108. package/dist/webdist/assets/{wardleyDiagram-T6FBY63Y-Cdki47W1.js → wardleyDiagram-T6FBY63Y-DQzV926_.js} +1 -1
  109. package/dist/webdist/assets/{wrench-DOaBHWWN.js → wrench-Db816rX1.js} +1 -1
  110. package/dist/webdist/assets/{xychartDiagram-ELKLHX3M-3hkxEbMo.js → xychartDiagram-ELKLHX3M-B7OfhEpC.js} +1 -1
  111. package/dist/webdist/index.html +1 -1
  112. package/package.json +1 -1
  113. package/dist/webdist/assets/WorkspaceScreen-jL5YURRX.js +0 -1
  114. package/dist/webdist/assets/channel-Yxxa5Jtv.js +0 -1
  115. package/dist/webdist/assets/classDiagram-JCYQIIEL-Cr7eMrK7.js +0 -1
  116. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-Cr7eMrK7.js +0 -1
  117. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-D-qEGyyy.js +0 -1
  118. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-DJV5Gciz.js +0 -8
package/dist/cli.js CHANGED
@@ -15602,6 +15602,17 @@ import { execFile as execFile10 } from "child_process";
15602
15602
  import { readFileSync as readFileSync12 } from "fs";
15603
15603
  import { randomUUID as randomUUID6 } from "crypto";
15604
15604
 
15605
+ // src/bench/spill.ts
15606
+ var SPILL_TOLERANCE_MB = 512;
15607
+ function spillMb(baselineSharedMb, loadedSharedMb) {
15608
+ if (baselineSharedMb === null || loadedSharedMb === null) return null;
15609
+ return Math.max(0, loadedSharedMb - baselineSharedMb);
15610
+ }
15611
+ function isSpilling(spill) {
15612
+ if (spill === null) return false;
15613
+ return spill > SPILL_TOLERANCE_MB;
15614
+ }
15615
+
15605
15616
  // src/api/path-utils.ts
15606
15617
  function inferRepoFromPath(filePath, modelDirs) {
15607
15618
  const norm = (p) => p.replace(/\\/g, "/").replace(/\/+$/, "");
@@ -16529,7 +16540,6 @@ var PREFILL_GRACE_MS = 8e3;
16529
16540
  var TOTAL_BUDGET_MS = 45 * 6e4;
16530
16541
  var OOM_RE = /out of memory|cudaMalloc|failed to allocate|unable to allocate|device not ready|CUDA error/i;
16531
16542
  var QUALITY_KV = ["f16", "q8_0", "turbo4"];
16532
- var OUTPUT_TIE = 0.05;
16533
16543
  var KV_BYTES = {
16534
16544
  f32: 4,
16535
16545
  f16: 2,
@@ -16802,16 +16812,28 @@ var BenchRunner = class {
16802
16812
  const probe2 = await this.probeVram(entry, sys, { ...base2, ngl: mid }, caps);
16803
16813
  this.pushProbe(results, base2, "ngl", mid, probe2);
16804
16814
  await this.settleGpu(sys);
16805
- if (probe2.outcome === "ok" && !overHeadroom(probe2.vramAbsMb, budgetMb, headroomMb)) {
16815
+ const verdict = probeVerdict(probe2, budgetMb, headroomMb);
16816
+ if (verdict.decision === "fits") {
16806
16817
  bestNgl = mid;
16807
16818
  lo = mid + 1;
16808
16819
  } else {
16820
+ if (verdict.reason === "spill") {
16821
+ this.emit(`ngl=${mid} spilling ${Math.round(verdict.shortfallMb ?? 0)} MB to system RAM \u2014 using fewer GPU layers`);
16822
+ }
16809
16823
  hi = mid - 1;
16810
16824
  }
16811
16825
  }
16812
16826
  }
16813
16827
  if (bestNgl === null) return null;
16814
16828
  let found = await this.benchAt(entry, sys, { ...base2, ngl: bestNgl }, caps, results, `ngl=${bestNgl}`);
16829
+ if (found && isSpilling(found.cand.spillMb) && bestNgl > 0) {
16830
+ this.emit(`ngl=${bestNgl} spilled ${Math.round(found.cand.spillMb)} MB once actually generating (the load-only probe could not see this) \u2014 retrying at ngl=${bestNgl - 1}`);
16831
+ const safer = await this.benchAt(entry, sys, { ...base2, ngl: bestNgl - 1 }, caps, results, `ngl=${bestNgl - 1} (spill backoff)`);
16832
+ if (safer) {
16833
+ found = safer;
16834
+ bestNgl = bestNgl - 1;
16835
+ }
16836
+ }
16815
16837
  if (found && overHeadroom(found.cand.vramAbsMb, budgetMb, headroomMb) && bestNgl > 0) {
16816
16838
  this.emit(`ngl=${bestNgl} exceeded headroom after generation (${found.cand.vramAbsMb} MB) \u2014 retrying at ngl=${bestNgl - 1}`);
16817
16839
  const safer = await this.benchAt(entry, sys, { ...base2, ngl: bestNgl - 1 }, caps, results, `ngl=${bestNgl - 1} (headroom backoff)`);
@@ -16845,32 +16867,61 @@ var BenchRunner = class {
16845
16867
  const probe2 = await this.probeVram(entry, sys, { ...base2, nCpuMoe: mid }, caps);
16846
16868
  this.pushProbe(results, base2, "nCpuMoe", mid, probe2);
16847
16869
  await this.settleGpu(sys);
16848
- if (probe2.outcome === "oom" || overHeadroom(probe2.vramAbsMb, budgetMb, headroomMb)) {
16849
- lo = mid + 1;
16850
- } else if (probe2.outcome === "ok") {
16870
+ const verdict = probeVerdict(probe2, budgetMb, headroomMb);
16871
+ if (verdict.decision === "fits") {
16851
16872
  bestN = mid;
16852
16873
  hi = mid - 1;
16853
16874
  } else {
16875
+ if (verdict.reason === "spill") {
16876
+ this.emit(`nCpuMoe=${mid} spilling ${Math.round(verdict.shortfallMb ?? 0)} MB to system RAM \u2014 offloading more`);
16877
+ }
16854
16878
  lo = mid + 1;
16855
16879
  }
16856
16880
  }
16857
16881
  if (bestN === null) return null;
16858
- let found = await this.benchAt(entry, sys, { ...base2, nCpuMoe: bestN }, caps, results, `nCpuMoe=${bestN}`);
16859
- if (found && overHeadroom(found.cand.vramAbsMb, budgetMb, headroomMb) && bestN < maxN) {
16860
- this.emit(`nCpuMoe=${bestN} exceeded headroom after generation (${found.cand.vramAbsMb} MB) \u2014 retrying at nCpuMoe=${bestN + 1}`);
16861
- const safer = await this.benchAt(entry, sys, { ...base2, nCpuMoe: bestN + 1 }, caps, results, `nCpuMoe=${bestN + 1} (headroom backoff)`);
16862
- if (safer) found = safer;
16882
+ let found = null;
16883
+ let foundN = bestN;
16884
+ for (let n = bestN; n <= maxN; n++) {
16885
+ const label = n === bestN ? `nCpuMoe=${n}` : `nCpuMoe=${n} (crash backoff)`;
16886
+ found = await this.benchAt(entry, sys, { ...base2, nCpuMoe: n }, caps, results, label);
16887
+ if (found) {
16888
+ foundN = n;
16889
+ break;
16890
+ }
16891
+ const stopped = this.cancelled || Date.now() > this.deadline;
16892
+ if (stopped) {
16893
+ this.emit(`nCpuMoe=${n} failed to bench (${results[results.length - 1]?.outcome ?? "crash"}) \u2014 run ${this.cancelled ? "cancelled" : "out of time budget"}, stopping`);
16894
+ break;
16895
+ }
16896
+ if (n < maxN) this.emit(`nCpuMoe=${n} failed to bench (${results[results.length - 1]?.outcome ?? "crash"}) \u2014 retrying at nCpuMoe=${n + 1}`);
16897
+ }
16898
+ if (found && isSpilling(found.cand.spillMb) && foundN < maxN) {
16899
+ this.emit(`nCpuMoe=${foundN} spilled ${Math.round(found.cand.spillMb)} MB once actually generating (the load-only probe could not see this) \u2014 retrying at nCpuMoe=${foundN + 1}`);
16900
+ const safer = await this.benchAt(entry, sys, { ...base2, nCpuMoe: foundN + 1 }, caps, results, `nCpuMoe=${foundN + 1} (spill backoff)`);
16901
+ if (safer) {
16902
+ found = safer;
16903
+ foundN = foundN + 1;
16904
+ }
16905
+ }
16906
+ if (found && overHeadroom(found.cand.vramAbsMb, budgetMb, headroomMb) && foundN < maxN) {
16907
+ this.emit(`nCpuMoe=${foundN} exceeded headroom after generation (${found.cand.vramAbsMb} MB) \u2014 retrying at nCpuMoe=${foundN + 1}`);
16908
+ const safer = await this.benchAt(entry, sys, { ...base2, nCpuMoe: foundN + 1 }, caps, results, `nCpuMoe=${foundN + 1} (headroom backoff)`);
16909
+ if (safer) {
16910
+ found = safer;
16911
+ foundN = foundN + 1;
16912
+ }
16863
16913
  }
16864
16914
  if (headroomMb === VRAM_HEADROOM_SPILL_MB && found && found.cand.tps !== null) {
16865
16915
  let current = found;
16866
16916
  while (current.cand.params.nCpuMoe > 0 && !this.cancelled && Date.now() <= this.deadline) {
16867
16917
  const spillN = current.cand.params.nCpuMoe - 1;
16868
- const prev = { tps: current.cand.tps, prefillTps: current.cand.prefillTps };
16869
- const prevLabel = `${prev.tps.toFixed(1)} tok/s (prefill ${prev.prefillTps !== null ? prev.prefillTps.toFixed(1) : "n/a"} tok/s)`;
16918
+ const prev = { ttftMs: current.cand.ttftMs, tps: current.cand.tps };
16919
+ const prevTtf = ttfMs(prev);
16920
+ const prevLabel = prevTtf !== null ? `${(prevTtf / 1e3).toFixed(1)}s to ${TTF_OUTPUT_TOKENS} tokens` : "an unmeasurable result";
16870
16921
  this.emit(`nCpuMoe=${current.cand.params.nCpuMoe} measured ${prevLabel} \u2014 trying VRAM-spill nCpuMoe=${spillN}`);
16871
16922
  const spillFound = await this.benchAt(entry, sys, { ...base2, nCpuMoe: spillN }, caps, results, `nCpuMoe=${spillN} (VRAM-spill hill-climb)`);
16872
16923
  if (!spillImproves(prev, spillFound?.cand ?? null)) {
16873
- this.emit(`nCpuMoe=${spillN} spill did not improve on ${prevLabel} (generation or prefill speed decreased) \u2014 stopping climb, keeping nCpuMoe=${current.cand.params.nCpuMoe}`);
16924
+ this.emit(`nCpuMoe=${spillN} did not beat ${prevLabel} \u2014 stopping climb, keeping nCpuMoe=${current.cand.params.nCpuMoe}`);
16874
16925
  break;
16875
16926
  }
16876
16927
  current = spillFound;
@@ -16887,7 +16938,7 @@ var BenchRunner = class {
16887
16938
  * measuring t/s at every search step would be wasted — we bench ONCE, at the chosen config. */
16888
16939
  async probeVram(entry, sys, profile, caps) {
16889
16940
  const active = this.registry.active();
16890
- if (!active) return { outcome: "crash", vramAbsMb: null };
16941
+ if (!active) return { outcome: "crash", vramAbsMb: null, spillMb: null };
16891
16942
  const testDeadline = Math.min(Date.now() + READY_TIMEOUT_MS + 5e3, this.deadline);
16892
16943
  const opts = {
16893
16944
  engine: active,
@@ -16895,19 +16946,22 @@ var BenchRunner = class {
16895
16946
  modelPath: entry.path,
16896
16947
  extraArgs: profileToArgs(profile, entry, caps, sys.cores, sys, active.binPath)
16897
16948
  };
16949
+ const sharedBefore = await readGpuSharedMb(sys);
16898
16950
  try {
16899
16951
  await this.manager.start(opts);
16900
16952
  } catch {
16901
- return { outcome: "crash", vramAbsMb: null };
16953
+ return { outcome: "crash", vramAbsMb: null, spillMb: null };
16902
16954
  }
16903
16955
  const outcome = await this.awaitReady(testDeadline);
16904
16956
  let vramAbsMb = null;
16957
+ let spill = null;
16905
16958
  if (outcome === "ok") {
16906
16959
  await sleep3(800);
16907
16960
  vramAbsMb = await readGpuVramMb(sys);
16961
+ spill = spillMb(sharedBefore, await readGpuSharedMb(sys));
16908
16962
  }
16909
16963
  await this.stopEngine();
16910
- return { outcome, vramAbsMb };
16964
+ return { outcome, vramAbsMb, spillMb: spill };
16911
16965
  }
16912
16966
  /** Record a VRAM-probe trial in the candidate list (tps/prefill are null — nothing was generated;
16913
16967
  * only the load outcome and absolute VRAM are known). */
@@ -16927,7 +16981,8 @@ var BenchRunner = class {
16927
16981
  prefillTps: null,
16928
16982
  ttftMs: null,
16929
16983
  vramMb: null,
16930
- vramAbsMb: probe2.vramAbsMb
16984
+ vramAbsMb: probe2.vramAbsMb,
16985
+ spillMb: probe2.spillMb
16931
16986
  };
16932
16987
  results.push(probeCand);
16933
16988
  this.emit(`${probeCand.label} \u2192 ${probe2.outcome}${probe2.vramAbsMb != null ? ` (${probe2.vramAbsMb} MB)` : ""}`, probeCand);
@@ -16958,7 +17013,7 @@ var BenchRunner = class {
16958
17013
  kvTypeK: profile.kvTypeK,
16959
17014
  flashAttn: profile.flashAttn
16960
17015
  };
16961
- const fail = (outcome2) => ({ label, params, outcome: outcome2, tps: null, prefillTps: null, ttftMs: null, vramMb: null, vramAbsMb: null });
17016
+ const fail = (outcome2) => ({ label, params, outcome: outcome2, tps: null, prefillTps: null, ttftMs: null, vramMb: null, vramAbsMb: null, spillMb: null });
16962
17017
  const phase = (p) => {
16963
17018
  this.state = { ...this.state, step: `${stepPrefix} \u2014 ${p}` };
16964
17019
  };
@@ -16973,6 +17028,7 @@ var BenchRunner = class {
16973
17028
  extraArgs: profileToArgs(profile, entry, caps, sys.cores, sys, active.binPath)
16974
17029
  };
16975
17030
  const vramBefore = await readGpuVramMb(sys);
17031
+ const sharedBefore = await readGpuSharedMb(sys);
16976
17032
  phase("loading model\u2026");
16977
17033
  try {
16978
17034
  await this.manager.start(opts);
@@ -17000,10 +17056,11 @@ var BenchRunner = class {
17000
17056
  phase("measuring t/s\u2026");
17001
17057
  const measured = await this.runChatWatched(target, benchMessages, 128, remaining(), logPath);
17002
17058
  const vramAfter = await readGpuVramMb(sys);
17059
+ const sharedAfter = await readGpuSharedMb(sys);
17003
17060
  await this.stopEngine();
17004
17061
  if ("fault" in measured) return fail(measured.fault);
17005
17062
  const vramMb = vramBefore !== null && vramAfter !== null ? Math.max(0, vramAfter - vramBefore) : vramAfter;
17006
- return { label, params, outcome: "ok", tps: measured.tps, prefillTps: measured.prefillTps, ttftMs: measured.ttftMs, vramMb, vramAbsMb: vramAfter };
17063
+ return { label, params, outcome: "ok", tps: measured.tps, prefillTps: measured.prefillTps, ttftMs: measured.ttftMs, vramMb, vramAbsMb: vramAfter, spillMb: spillMb(sharedBefore, sharedAfter) };
17007
17064
  }
17008
17065
  /** Poll the manager state until the engine is running, the readiness window
17009
17066
  * elapses (timeout), the process exits (crash), or an OOM line appears in the
@@ -17512,20 +17569,35 @@ function pickKvQuants(baseKv, kvTypes) {
17512
17569
  for (const t of [baseKv, ...QUALITY_KV]) if (supported(t) && !out.includes(t)) out.push(t);
17513
17570
  return out;
17514
17571
  }
17572
+ function probeVerdict(probe2, budgetMb, headroomMb) {
17573
+ if (probe2.outcome === "oom") return { decision: "offload-more", reason: "oom" };
17574
+ if (isSpilling(probe2.spillMb)) {
17575
+ return { decision: "offload-more", reason: "spill", shortfallMb: probe2.spillMb };
17576
+ }
17577
+ if (overHeadroom(probe2.vramAbsMb, budgetMb, headroomMb)) {
17578
+ return { decision: "offload-more", reason: "headroom" };
17579
+ }
17580
+ if (probe2.outcome === "ok") return { decision: "fits" };
17581
+ return { decision: "offload-more", reason: "failed" };
17582
+ }
17583
+ var TTF_OUTPUT_TOKENS = 1e3;
17584
+ function ttfMs(c, outputTokens = TTF_OUTPUT_TOKENS) {
17585
+ if (c.ttftMs === null || c.tps === null || c.tps <= 0) return null;
17586
+ return c.ttftMs + outputTokens / c.tps * 1e3;
17587
+ }
17515
17588
  function betterBySpeed(a, b) {
17516
- const at = a.tps ?? 0;
17517
- const bt = b.tps ?? 0;
17518
- if (bt <= 0) return at > 0;
17519
- const rel = (at - bt) / bt;
17520
- if (rel > OUTPUT_TIE) return true;
17521
- if (rel < -OUTPUT_TIE) return false;
17522
- return (a.prefillTps ?? 0) > (b.prefillTps ?? 0);
17589
+ const at = ttfMs(a);
17590
+ const bt = ttfMs(b);
17591
+ if (at === null) return false;
17592
+ if (bt === null) return true;
17593
+ return at < bt;
17523
17594
  }
17524
17595
  function spillImproves(previous, candidate) {
17525
- if (!candidate || candidate.outcome !== "ok" || candidate.tps === null) return false;
17526
- if (candidate.tps < previous.tps) return false;
17527
- if (previous.prefillTps !== null && (candidate.prefillTps === null || candidate.prefillTps < previous.prefillTps)) return false;
17528
- return true;
17596
+ if (!candidate || candidate.outcome !== "ok") return false;
17597
+ const next = ttfMs(candidate);
17598
+ const prev = ttfMs(previous);
17599
+ if (next === null || prev === null) return false;
17600
+ return next < prev;
17529
17601
  }
17530
17602
  function kvBytes(t) {
17531
17603
  return KV_BYTES[t] ?? 2;
@@ -17591,6 +17663,66 @@ async function readGpuVramMb(sys) {
17591
17663
  if (sys.gpus.some((g) => g.vendor === "amd")) return readRocmVramMb();
17592
17664
  return null;
17593
17665
  }
17666
+ var WDDM_SHARED_PS = "$s=(Get-Counter '\\GPU Adapter Memory(*)\\Shared Usage' -ErrorAction SilentlyContinue).CounterSamples;if(-not $s){exit 1};[math]::Round((($s|Measure-Object CookedValue -Sum).Sum)/1MB,1)";
17667
+ var wddmSharedUnsupported = false;
17668
+ function readWddmSharedMb() {
17669
+ if (process.platform !== "win32" || wddmSharedUnsupported) return Promise.resolve(null);
17670
+ return new Promise((resolve5) => {
17671
+ try {
17672
+ execFile10(
17673
+ "powershell",
17674
+ ["-NoProfile", "-NonInteractive", "-Command", WDDM_SHARED_PS],
17675
+ { timeout: 1e4, windowsHide: true },
17676
+ (err8, stdout) => {
17677
+ if (err8) {
17678
+ if (!err8.killed) wddmSharedUnsupported = true;
17679
+ return resolve5(null);
17680
+ }
17681
+ const mb = parseFloat((stdout || "").trim());
17682
+ if (!Number.isFinite(mb) || mb < 0) {
17683
+ wddmSharedUnsupported = true;
17684
+ return resolve5(null);
17685
+ }
17686
+ resolve5(Math.round(mb));
17687
+ }
17688
+ );
17689
+ } catch {
17690
+ wddmSharedUnsupported = true;
17691
+ resolve5(null);
17692
+ }
17693
+ });
17694
+ }
17695
+ function parseRocmGttUsed(memJson) {
17696
+ try {
17697
+ const mem = JSON.parse(memJson);
17698
+ let total = 0;
17699
+ for (const fields of Object.values(mem)) {
17700
+ const usedKey = Object.keys(fields).find((k) => /GTT Total Used Memory/i.test(k));
17701
+ total += usedKey ? parseInt(String(fields[usedKey]).trim(), 10) || 0 : 0;
17702
+ }
17703
+ return Number.isFinite(total) ? Math.round(total / 1e6) : null;
17704
+ } catch {
17705
+ return null;
17706
+ }
17707
+ }
17708
+ function readRocmGttMb() {
17709
+ return new Promise((resolve5) => {
17710
+ try {
17711
+ execFile10("rocm-smi", ["--showmeminfo", "gtt", "--json"], { timeout: 8e3, windowsHide: true }, (err8, stdout) => {
17712
+ if (err8 || !stdout) return resolve5(null);
17713
+ resolve5(parseRocmGttUsed(stdout));
17714
+ });
17715
+ } catch {
17716
+ resolve5(null);
17717
+ }
17718
+ });
17719
+ }
17720
+ async function readGpuSharedMb(sys) {
17721
+ const win = await readWddmSharedMb();
17722
+ if (win !== null) return win;
17723
+ if (sys.gpus.some((g) => g.vendor === "amd")) return readRocmGttMb();
17724
+ return null;
17725
+ }
17594
17726
  function sleep3(ms) {
17595
17727
  return new Promise((r) => setTimeout(r, ms));
17596
17728
  }
@@ -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-CRd__4R1.js";import{f as V}from"./chat-api-BTcC6kED.js";import{f as X,a as Z}from"./agent-api-CpgzOfg0.js";import{P as B}from"./personas-B0p0BX69.js";import{C as ee}from"./chevron-left-BVxkM758.js";import{R as te}from"./rotate-ccw-gR3mMTRM.js";import{T as se}from"./trash-2-DZYSgl2R.js";import{C as ne}from"./chevron-right-BJZRbTUj.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 ve(){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{ve 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-C3DcPrhr.js";import{f as V}from"./chat-api-D7WunS4X.js";import{f as X,a as Z}from"./agent-api-Dsb2M3gT.js";import{P as B}from"./personas-DLa9ZPoi.js";import{C as ee}from"./chevron-left-DqcpOb9h.js";import{R as te}from"./rotate-ccw-CDrolPd6.js";import{T as se}from"./trash-2-BNqXKVdk.js";import{C as ne}from"./chevron-right-D7i8peZR.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 ve(){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{ve as AgentEditPage};