turbollm 1.10.3 → 1.10.5

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 (121) hide show
  1. package/dist/cli.js +275 -108
  2. package/dist/webdist/assets/{AgentEditPage-DZU5Ps30.js → AgentEditPage-Bq0To2Kn.js} +1 -1
  3. package/dist/webdist/assets/{ChatScreen-CWjg1zrs.js → ChatScreen-JfS4dp94.js} +9 -9
  4. package/dist/webdist/assets/{CodeComposer-C8c0eQe4.js → CodeComposer-BPcKbMuH.js} +1 -1
  5. package/dist/webdist/assets/CodeHomeScreen-CbY_UCs6.js +1 -0
  6. package/dist/webdist/assets/{CodeSessionScreen-DOVBiJIZ.js → CodeSessionScreen-nU50H3fR.js} +11 -11
  7. package/dist/webdist/assets/{CustomizeScreen-Dg69A2mU.js → CustomizeScreen-jI99vrYL.js} +1 -1
  8. package/dist/webdist/assets/{DeveloperScreen-CwW1Z3BJ.js → DeveloperScreen-BfYnTO7e.js} +1 -1
  9. package/dist/webdist/assets/{EnginesScreen-CiMymt2y.js → EnginesScreen-CU8ZNHcl.js} +1 -1
  10. package/dist/webdist/assets/{ModelDetailDialog-Ch1FFdDi.js → ModelDetailDialog-DKUMTU2w.js} +1 -1
  11. package/dist/webdist/assets/{ModelLoadMenu-DmJ6pW_S.js → ModelLoadMenu-CBj32oEE.js} +1 -1
  12. package/dist/webdist/assets/{ModelsScreen-Ch83Gnvx.js → ModelsScreen-CTYIbZyc.js} +1 -1
  13. package/dist/webdist/assets/RoutineEditPage-gqLu8cXv.js +1 -0
  14. package/dist/webdist/assets/RoutinesPanel-Dv9Shubg.js +1 -0
  15. package/dist/webdist/assets/{SettingsScreen-fWaRXbXZ.js → SettingsScreen-C7LQLNGe.js} +1 -1
  16. package/dist/webdist/assets/SidebarResizeHandle-Djhjx6qR.js +2 -0
  17. package/dist/webdist/assets/{SkillEditPage-Cpg3YkPw.js → SkillEditPage-ClBJXbC3.js} +1 -1
  18. package/dist/webdist/assets/{TokensScreen-CYGdXUbH.js → TokensScreen-gk_Mqi5g.js} +1 -1
  19. package/dist/webdist/assets/{ToolApprovalBar-Ba2BoF9X.js → ToolApprovalBar-B3WSFcyU.js} +3 -3
  20. package/dist/webdist/assets/WorkspaceScreen-jL5YURRX.js +1 -0
  21. package/dist/webdist/assets/{abnfDiagram-N423BO3Z-CxAZuY4F.js → abnfDiagram-N423BO3Z-QSevWJ37.js} +1 -1
  22. package/dist/webdist/assets/{agent-api-BdnGAV-Y.js → agent-api-CpgzOfg0.js} +1 -1
  23. package/dist/webdist/assets/{alert-dialog-CEf-XUyg.js → alert-dialog-CMvNzcK0.js} +1 -1
  24. package/dist/webdist/assets/{arc-DEU8Rl3Q.js → arc-BWbVGHju.js} +1 -1
  25. package/dist/webdist/assets/{architectureDiagram-T3A2C74G-DFWEfaYa.js → architectureDiagram-T3A2C74G-Boh67Blv.js} +1 -1
  26. package/dist/webdist/assets/{arrow-left-BHr6DbXW.js → arrow-left-CU7vJBtU.js} +1 -1
  27. package/dist/webdist/assets/{badge-DiZD__AA.js → badge-BOGctZvx.js} +1 -1
  28. package/dist/webdist/assets/{blockDiagram-VBNYF7ZC-BhTU3G_O.js → blockDiagram-VBNYF7ZC-BkIBotfv.js} +1 -1
  29. package/dist/webdist/assets/{bot-BR1o3u2z.js → bot-CwYS2B1G.js} +1 -1
  30. package/dist/webdist/assets/{c4Diagram-5PPSVZJV-CJNhzTh5.js → c4Diagram-5PPSVZJV-CWCZQHIc.js} +1 -1
  31. package/dist/webdist/assets/channel-Yxxa5Jtv.js +1 -0
  32. package/dist/webdist/assets/{chat-api-WdKnt_cR.js → chat-api-BTcC6kED.js} +1 -1
  33. package/dist/webdist/assets/{chat-queries--BKqKvZT.js → chat-queries-D9fFhHaQ.js} +1 -1
  34. package/dist/webdist/assets/{chevron-left-tBRMVkX5.js → chevron-left-BVxkM758.js} +1 -1
  35. package/dist/webdist/assets/{chevron-right-B16ur-An.js → chevron-right-BJZRbTUj.js} +1 -1
  36. package/dist/webdist/assets/{chunk-2GRJ4B5K-Y-VLx_rW.js → chunk-2GRJ4B5K-C5CXDrO_.js} +1 -1
  37. package/dist/webdist/assets/{chunk-2Q5K7J3B-BUKWb833.js → chunk-2Q5K7J3B-Bk_wrlB0.js} +1 -1
  38. package/dist/webdist/assets/{chunk-5RXB4S5H-BV3L2yyf.js → chunk-5RXB4S5H-BAT4FnUI.js} +1 -1
  39. package/dist/webdist/assets/{chunk-5VM5RSS4-xI1dTTCA.js → chunk-5VM5RSS4-C9eEV1Kl.js} +1 -1
  40. package/dist/webdist/assets/{chunk-6Q2QTUOP-C3F611uv.js → chunk-6Q2QTUOP-CJDFqmYe.js} +1 -1
  41. package/dist/webdist/assets/{chunk-GF5L2VYU-xzyWIvtP.js → chunk-GF5L2VYU-CsgBXjfk.js} +1 -1
  42. package/dist/webdist/assets/{chunk-JWPE2WC7-PCn1DNAq.js → chunk-JWPE2WC7-CRt7uW9O.js} +1 -1
  43. package/dist/webdist/assets/{chunk-KBJHAD2P-B2V4Qn1_.js → chunk-KBJHAD2P-CSsVpcf6.js} +1 -1
  44. package/dist/webdist/assets/{chunk-RYQCIY6F-BXnb7awQ.js → chunk-RYQCIY6F-eTll7wC1.js} +1 -1
  45. package/dist/webdist/assets/{chunk-XXDRQBXY-BjzDsMy6.js → chunk-XXDRQBXY-D2-Dj7EK.js} +1 -1
  46. package/dist/webdist/assets/{circle-check-BHQ4Ky5u.js → circle-check-g29PWBwU.js} +1 -1
  47. package/dist/webdist/assets/{circle-x-BbJarEnu.js → circle-x-BgFrKCxR.js} +1 -1
  48. package/dist/webdist/assets/classDiagram-JCYQIIEL-Cr7eMrK7.js +1 -0
  49. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-Cr7eMrK7.js +1 -0
  50. package/dist/webdist/assets/{common-B_Ugw5Ue.js → common-Fwu8t36v.js} +1 -1
  51. package/dist/webdist/assets/{cose-bilkent-JH36ORCC-8GVWCg2F.js → cose-bilkent-JH36ORCC-DXafCcEB.js} +1 -1
  52. package/dist/webdist/assets/{cynefin-VYW2F7L2-D4EwNxuN.js → cynefin-VYW2F7L2-CecX93d_.js} +1 -1
  53. package/dist/webdist/assets/{cynefinDiagram-MW4NZA55-BchWtjzK.js → cynefinDiagram-MW4NZA55-tu8xDmsR.js} +1 -1
  54. package/dist/webdist/assets/{dagre-VZM6K2ZE-C-tKBzor.js → dagre-VZM6K2ZE-UG2o94YJ.js} +1 -1
  55. package/dist/webdist/assets/{diagram-7IWD3JNH-CIzXwEou.js → diagram-7IWD3JNH-3DRTAZAF.js} +1 -1
  56. package/dist/webdist/assets/{diagram-B4RE2ZJO-B0-fu81p.js → diagram-B4RE2ZJO-CwH0bQ2A.js} +1 -1
  57. package/dist/webdist/assets/{diagram-LBJQPF4R-DKUCmHSn.js → diagram-LBJQPF4R-DuybxKFU.js} +1 -1
  58. package/dist/webdist/assets/{diagram-Q27KOJAE-BMVmaaBq.js → diagram-Q27KOJAE-BwoB84ui.js} +1 -1
  59. package/dist/webdist/assets/{diagram-UB23O5K3-C-GsMRNn.js → diagram-UB23O5K3-DEjbnHCQ.js} +1 -1
  60. package/dist/webdist/assets/{dropdown-menu-BHlT_PrH.js → dropdown-menu-D25-JVEy.js} +1 -1
  61. package/dist/webdist/assets/{ebnfDiagram-BXEA7PRR-D2cgRlFo.js → ebnfDiagram-BXEA7PRR-DG9Xbpyw.js} +1 -1
  62. package/dist/webdist/assets/{erDiagram-JOGREHBK-MG0Qt0Dc.js → erDiagram-JOGREHBK-eysaP8yv.js} +1 -1
  63. package/dist/webdist/assets/{external-link-BYsIzaRn.js → external-link-Xn8kJljc.js} +1 -1
  64. package/dist/webdist/assets/{file-text-D5LVQPdf.js → file-text-BmAkLphS.js} +1 -1
  65. package/dist/webdist/assets/{flowDiagram-UKHOOZJN-wAus-SqB.js → flowDiagram-UKHOOZJN-Bfha7bpG.js} +1 -1
  66. package/dist/webdist/assets/{folder-input-CPFYQQYm.js → folder-input-BRjaJam7.js} +1 -1
  67. package/dist/webdist/assets/{folder-plus-BS4MX3uc.js → folder-plus-DBJ9oQjK.js} +1 -1
  68. package/dist/webdist/assets/{ganttDiagram-PKOTCBZU-iFTGTcny.js → ganttDiagram-PKOTCBZU-CJotaSgm.js} +1 -1
  69. package/dist/webdist/assets/{git-branch-CH_JRbeH.js → git-branch-DerJ3eCK.js} +1 -1
  70. package/dist/webdist/assets/{gitGraphDiagram-DS77QQ5N-B3Lim-un.js → gitGraphDiagram-DS77QQ5N-C8za5q5H.js} +1 -1
  71. package/dist/webdist/assets/{index-m7O9h-cc.js → index-CRd__4R1.js} +6 -6
  72. package/dist/webdist/assets/{infoDiagram-6WML65LV-2U3_w76t.js → infoDiagram-6WML65LV-C95kKxPZ.js} +1 -1
  73. package/dist/webdist/assets/{ishikawaDiagram-WSZJBQD7-8qFZeY06.js → ishikawaDiagram-WSZJBQD7-DOIqcMyH.js} +1 -1
  74. package/dist/webdist/assets/{journeyDiagram-NVQOT4AX-BiQ4W5bp.js → journeyDiagram-NVQOT4AX-BBirkGE7.js} +1 -1
  75. package/dist/webdist/assets/{kanban-definition-27J2QSJJ-xUKbXLDF.js → kanban-definition-27J2QSJJ-CPhjxJyV.js} +1 -1
  76. package/dist/webdist/assets/{linear-Cfppb_KP.js → linear-BWhxZFqF.js} +1 -1
  77. package/dist/webdist/assets/{lock-_kPFqMMF.js → lock-CpPOIG8p.js} +1 -1
  78. package/dist/webdist/assets/{mermaid.core-Cqc4S48f.js → mermaid.core-DocKtbj4.js} +4 -4
  79. package/dist/webdist/assets/{mindmap-definition-FAOFIHXS-DfAXBfEp.js → mindmap-definition-FAOFIHXS-wL4xGOU_.js} +1 -1
  80. package/dist/webdist/assets/{pegDiagram-VL7TDLO6-BDnh7A9L.js → pegDiagram-VL7TDLO6-D19VvRVO.js} +1 -1
  81. package/dist/webdist/assets/{pencil-B65o2Xsj.js → pencil-c-PJkJes.js} +1 -1
  82. package/dist/webdist/assets/{pieDiagram-7S7Q4E2Y-BoEHVtTF.js → pieDiagram-7S7Q4E2Y-Doy7WZyw.js} +1 -1
  83. package/dist/webdist/assets/{plus-BCCJyhZC.js → plus-CP7d5krT.js} +1 -1
  84. package/dist/webdist/assets/{quadrantDiagram-CIZ2JOQS-BvKFv-w0.js → quadrantDiagram-CIZ2JOQS-BO535Mye.js} +1 -1
  85. package/dist/webdist/assets/{railroadDiagram-AXF67PYL-BLrX-HQS.js → railroadDiagram-AXF67PYL-C_F6C_-j.js} +1 -1
  86. package/dist/webdist/assets/{refresh-cw-BMe9yq9k.js → refresh-cw-CUFncOr4.js} +1 -1
  87. package/dist/webdist/assets/{requirementDiagram-LRYGKXZP-r4LjKdJa.js → requirementDiagram-LRYGKXZP-COStqNVI.js} +1 -1
  88. package/dist/webdist/assets/{rotate-ccw-QlaGmqOe.js → rotate-ccw-gR3mMTRM.js} +1 -1
  89. package/dist/webdist/assets/{sankeyDiagram-W5VNT64P-CbTbNO1R.js → sankeyDiagram-W5VNT64P-DrpcfTw1.js} +1 -1
  90. package/dist/webdist/assets/{sequenceDiagram-SI44F4Z6-C3cZYRGT.js → sequenceDiagram-SI44F4Z6-CQ1WUoj0.js} +1 -1
  91. package/dist/webdist/assets/{sizeCapture-X5ZJPWSS-CYYQ8wtn.js → sizeCapture-X5ZJPWSS-CExk2dPw.js} +1 -1
  92. package/dist/webdist/assets/{skeleton-CC9ODrk4.js → skeleton-CapS3LhZ.js} +1 -1
  93. package/dist/webdist/assets/{sliders-horizontal-BFSPlX5c.js → sliders-horizontal-VjLq-9i0.js} +1 -1
  94. package/dist/webdist/assets/{sparkles-CmEUYmzj.js → sparkles-BS98k72s.js} +1 -1
  95. package/dist/webdist/assets/{star-CyudL0Do.js → star-Ce5Pu8jP.js} +1 -1
  96. package/dist/webdist/assets/{stateDiagram-OKZ733FA-Bdj39Nof.js → stateDiagram-OKZ733FA-6IQ9pQNr.js} +1 -1
  97. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-D-qEGyyy.js +1 -0
  98. package/dist/webdist/assets/{swimlanes-SLNWSIFB-W3xWeGOJ.js → swimlanes-SLNWSIFB-0AoFXo4W.js} +2 -2
  99. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-DJV5Gciz.js +8 -0
  100. package/dist/webdist/assets/{switch-BDarVW8W.js → switch-BVPOy4cS.js} +1 -1
  101. package/dist/webdist/assets/{terminal-Bvnu3OHJ.js → terminal-WfRPZiaW.js} +1 -1
  102. package/dist/webdist/assets/{timeline-definition-Z64GVDOM-DnavzBwI.js → timeline-definition-Z64GVDOM-LPqGGX5H.js} +1 -1
  103. package/dist/webdist/assets/{trash-2-C43ex79G.js → trash-2-DZYSgl2R.js} +1 -1
  104. package/dist/webdist/assets/{useIsDesktop-BC85xPnA.js → useIsDesktop-CjFyl6hu.js} +1 -1
  105. package/dist/webdist/assets/{vennDiagram-T6HMQDX7-DdJs_uLj.js → vennDiagram-T6HMQDX7--BcdXECz.js} +1 -1
  106. package/dist/webdist/assets/{vram-BWaHTGD0.js → vram-DlcIXX82.js} +1 -1
  107. package/dist/webdist/assets/{wardleyDiagram-T6FBY63Y-91gPbjKx.js → wardleyDiagram-T6FBY63Y-Cdki47W1.js} +1 -1
  108. package/dist/webdist/assets/{wrench-Dlm2fJiY.js → wrench-DOaBHWWN.js} +1 -1
  109. package/dist/webdist/assets/{xychartDiagram-ELKLHX3M-DDKDUQ8u.js → xychartDiagram-ELKLHX3M-3hkxEbMo.js} +1 -1
  110. package/dist/webdist/index.html +1 -1
  111. package/package.json +1 -1
  112. package/dist/webdist/assets/CodeHomeScreen-BbrTdGuL.js +0 -1
  113. package/dist/webdist/assets/RoutineEditPage-DqDEDN7O.js +0 -1
  114. package/dist/webdist/assets/RoutinesPanel-C0CgIiju.js +0 -1
  115. package/dist/webdist/assets/SidebarResizeHandle-eJlzaNXV.js +0 -2
  116. package/dist/webdist/assets/WorkspaceScreen-CLXpSocV.js +0 -1
  117. package/dist/webdist/assets/channel-D7Or72nc.js +0 -1
  118. package/dist/webdist/assets/classDiagram-JCYQIIEL-CoD8BgVw.js +0 -1
  119. package/dist/webdist/assets/classDiagram-v2-OCEON4UE-CoD8BgVw.js +0 -1
  120. package/dist/webdist/assets/stateDiagram-v2-UEYNNEHI-B3xKgUl_.js +0 -1
  121. package/dist/webdist/assets/swimlanesDiagram-ULZ7WXOC-DSpzEq_Q.js +0 -8
package/dist/cli.js CHANGED
@@ -5753,6 +5753,12 @@ var SUPPORTED = {
5753
5753
  hermes: { bin: "hermes", label: "Hermes Agent", install: "npm install -g hermes-agent", prepareConfig: prepareHermes },
5754
5754
  pi: { bin: "pi", label: "pi", install: "npm install -g @earendil-works/pi-coding-agent", prepareConfig: preparePi }
5755
5755
  };
5756
+ var CLAUDE_AUTO_COMPACT_WINDOW_MIN = 1e5;
5757
+ var CLAUDE_AUTO_COMPACT_WINDOW_MAX = 1e6;
5758
+ function clampAutoCompactWindow(ctx) {
5759
+ return Math.min(CLAUDE_AUTO_COMPACT_WINDOW_MAX, Math.max(CLAUDE_AUTO_COMPACT_WINDOW_MIN, Math.round(ctx)));
5760
+ }
5761
+ var CLAUDE_AUTOCOMPACT_PCT_OVERRIDE = "80";
5756
5762
  var realSpawn = (cmd, args, opts) => {
5757
5763
  if (!opts?.shell) return spawn4(cmd, args, opts);
5758
5764
  const resolved = resolveExecutable(cmd);
@@ -6180,6 +6186,15 @@ Open ${base2} \u2192 Models \u2192 Load a model, then run this again.
6180
6186
  // Opt into gateway model discovery: Claude Code queries our /v1/models at startup and
6181
6187
  // populates the /model picker with the local library (gateway synthesises the entries).
6182
6188
  CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: "1",
6189
+ // Founder-reported: the ctx-fill display "jumps between full and empty" and the CLI "never
6190
+ // auto-compacts at 80%, always reaches 100% and fails". The second half is Claude Code
6191
+ // assuming a generic ~200K context window for our unrecognized model id and only compacting
6192
+ // near THAT — see clampAutoCompactWindow's own doc comment for the full root cause and its
6193
+ // documented [100_000, 1_000_000] floor/ceiling. Only set when the daemon actually reports a
6194
+ // real ctx (status.model.ctx) — an absent/zero value means "don't know", and guessing a
6195
+ // window here would be worse than leaving the CLI's own generic default in place.
6196
+ ...status.model?.ctx ? { CLAUDE_CODE_AUTO_COMPACT_WINDOW: String(clampAutoCompactWindow(status.model.ctx)) } : {},
6197
+ CLAUDE_AUTOCOMPACT_PCT_OVERRIDE,
6183
6198
  // Cap background-agent fan-out at what the engine can actually run concurrently.
6184
6199
  //
6185
6200
  // Claude Code spawns subagents in parallel, and each is a full, independent request to the
@@ -7140,13 +7155,16 @@ var AUTO_MODE_ALLOWED_TOOLS = {
7140
7155
  claude: ["WebSearch", "WebFetch"]
7141
7156
  };
7142
7157
  var MAX_SEEDED_MESSAGE_CHARS = 4e3;
7143
- var UNSEEDABLE = /["\u0000-\u001f]/;
7158
+ var UNSEEDABLE = /["\u0000-\u0008\u000b\u000c\u000e-\u001f]/;
7159
+ function normalizeSeededMessage(message) {
7160
+ return message.replace(/[\r\n\t]+/g, " ").trim();
7161
+ }
7144
7162
  function canSeedFirstMessage(message, agent) {
7145
7163
  if (agent !== "claude") return false;
7146
- const trimmed = message.trim();
7147
- if (trimmed.length === 0 || trimmed.length > MAX_SEEDED_MESSAGE_CHARS) return false;
7148
- if (UNSEEDABLE.test(trimmed)) return false;
7149
- if (trimmed.endsWith("\\")) return false;
7164
+ const normalized = normalizeSeededMessage(message);
7165
+ if (normalized.length === 0 || normalized.length > MAX_SEEDED_MESSAGE_CHARS) return false;
7166
+ if (UNSEEDABLE.test(normalized)) return false;
7167
+ if (normalized.endsWith("\\")) return false;
7150
7168
  return true;
7151
7169
  }
7152
7170
  function buildTerminalLaunchCommand(agent, port2, token, sessionId, launchedOnce, permissionMode, mode, firstMessage) {
@@ -7155,7 +7173,7 @@ function buildTerminalLaunchCommand(agent, port2, token, sessionId, launchedOnce
7155
7173
  const modeArg = permissionMode ? ` --permission-mode ${permissionMode}` : "";
7156
7174
  const allowed = mode === "auto" ? AUTO_MODE_ALLOWED_TOOLS[agent] : void 0;
7157
7175
  const allowedArg = allowed?.length ? ` --allowedTools ${allowed.join(",")}` : "";
7158
- const promptArg = firstMessage && canSeedFirstMessage(firstMessage, agent) ? ` ${quotePtyShellArg(firstMessage.trim())}` : "";
7176
+ const promptArg = firstMessage && canSeedFirstMessage(firstMessage, agent) ? ` ${quotePtyShellArg(normalizeSeededMessage(firstMessage))}` : "";
7159
7177
  return `turbollm launch ${agent}${promptArg} --port ${port2} --token ${token}${sessionArg}${modeArg}${allowedArg}`;
7160
7178
  }
7161
7179
  function err(c, s, code, msg2) {
@@ -8188,7 +8206,7 @@ function profileToArgs(p, m, caps, cores = 0, sys, binPath) {
8188
8206
  }
8189
8207
  if (has("--parallel")) a.push("--parallel", String(p.parallel));
8190
8208
  if (p.parallel > 1 && p.kvUnified && has("--kv-unified")) a.push("--kv-unified");
8191
- if (m.moe && !p.nCpuMoeFit && p.nCpuMoe > 0 && has("--n-cpu-moe")) a.push("--n-cpu-moe", String(p.nCpuMoe));
8209
+ if (m.moe && !p.nCpuMoeFit && p.ngl > 0 && has("--n-cpu-moe")) a.push("--n-cpu-moe", String(p.nCpuMoe));
8192
8210
  const kvOk = (t) => caps.kvTypes.includes(t);
8193
8211
  if (p.kvTypeK !== "f16" && has("--cache-type-k") && kvOk(p.kvTypeK)) a.push("--cache-type-k", p.kvTypeK);
8194
8212
  if (p.kvTypeV !== "f16" && has("--cache-type-v") && kvOk(p.kvTypeV)) a.push("--cache-type-v", p.kvTypeV);
@@ -13488,6 +13506,10 @@ var ConversationStore = class {
13488
13506
  if (!this.hasColumn("api_usage", "harness")) this.db.exec(`ALTER TABLE api_usage ADD COLUMN harness TEXT;`);
13489
13507
  this.db.exec(`PRAGMA user_version = 43;`);
13490
13508
  }
13509
+ if (v < 44) {
13510
+ this.db.exec(`CREATE INDEX IF NOT EXISTS idx_api_usage_code_session_tokens ON api_usage(code_session_id, prompt_tokens);`);
13511
+ this.db.exec(`PRAGMA user_version = 44;`);
13512
+ }
13491
13513
  }
13492
13514
  listConversations(q, kind = "all") {
13493
13515
  if (q) {
@@ -13874,10 +13896,37 @@ var ConversationStore = class {
13874
13896
  $harness: rec.harness ?? null
13875
13897
  });
13876
13898
  }
13877
- /** Most recent completed gateway request attributed to a terminal-agent Code session
13878
- * (ADR-284) — powers TerminalToolbar.tsx's composer-parity stats row the same way
13879
- * `lastRealStats` already does for a 'turbollm' chat session's last turn. null when the
13880
- * session has made no gateway requests yet (fresh session, or a non-terminal-agent one). */
13899
+ /** The session's own gateway-request stats (ADR-284, revised twice — founder-reported "ctx
13900
+ * fill jumps between full and empty in the same session", then a review pass on that same fix
13901
+ * catching that it had gone on to freeze the LAST-TURN stats too). Two different questions,
13902
+ * two different rows:
13903
+ *
13904
+ * `ctxUsed` is the MAX prompt_tokens row, not literally the most-recently-INSERTED one. Every
13905
+ * request a real `claude` CLI process makes — the main conversation's own turn AND every
13906
+ * parallel Task-tool sub-agent it spawns — shares the SAME code_session_id: `resolveCodeSession`
13907
+ * (gateway.ts) derives it purely from the bearer token, and the CLI mints exactly one token
13908
+ * (ANTHROPIC_AUTH_TOKEN, set once at launch) for its whole process, sub-agents included. A
13909
+ * sub-agent's own prompt is a small, isolated sub-task — nothing like the full resent
13910
+ * conversation — so whichever of the two finishes last used to decide what the ring showed:
13911
+ * the real, large, ever-growing main-turn prompt one poll, a tiny sub-agent prompt the next,
13912
+ * with no change to the actual conversation in between. The MAX is the honest answer to "how
13913
+ * full has this session's context gotten" — a real Claude Code CLI resends the whole
13914
+ * conversation every turn, so its size only grows within one continuous conversation, and a
13915
+ * sub-agent (always smaller) can never legitimately raise that high-water mark. Trade-off,
13916
+ * accepted: after a real `/clear` inside the CLI (invisible to the daemon — a terminal-agent
13917
+ * session's turns are never persisted here, see ADR-297), this keeps reporting the pre-clear
13918
+ * high-water mark until the new conversation grows past it. A temporarily-stale-high ring
13919
+ * reading after a rare, deliberate user action beats an unpredictable full/empty flicker on
13920
+ * every ordinary agentic turn with sub-agents.
13921
+ *
13922
+ * `promptTokens`/`genTokens`/`promptTps`/`genTps` are the temporally-LAST row instead — these
13923
+ * power TerminalToolbar.tsx's composer-parity stats row, which reads as "your last turn", not
13924
+ * "session high-water mark". Sharing the MAX row here (the original version of this fix) meant
13925
+ * a sub-agent call landing after the real turn hid its own genTokens/tps behind the earlier,
13926
+ * larger turn's numbers, and after a `/clear` these froze at the pre-clear turn's numbers
13927
+ * forever, same failure shape as the ctxUsed bug this method was written to fix in the first
13928
+ * place. null when the session has made no gateway requests yet (fresh session, or a
13929
+ * non-terminal-agent one). */
13881
13930
  getLastApiUsageForSession(codeSessionId) {
13882
13931
  const row = this.db.prepare(`
13883
13932
  SELECT prompt_tokens, gen_tokens, duration_ms, prompt_tps, gen_tps FROM api_usage
@@ -13885,8 +13934,12 @@ var ConversationStore = class {
13885
13934
  ORDER BY created_at DESC LIMIT 1
13886
13935
  `).get({ $codeSessionId: codeSessionId });
13887
13936
  if (!row) return null;
13937
+ const ctxUsed = this.db.prepare(`
13938
+ SELECT MAX(prompt_tokens) as maxPromptTokens FROM api_usage WHERE code_session_id = $codeSessionId
13939
+ `).get({ $codeSessionId: codeSessionId }).maxPromptTokens;
13888
13940
  const seconds = row.duration_ms != null && row.duration_ms > 0 ? row.duration_ms / 1e3 : null;
13889
13941
  return {
13942
+ ctxUsed,
13890
13943
  promptTokens: row.prompt_tokens,
13891
13944
  genTokens: row.gen_tokens,
13892
13945
  promptTps: row.prompt_tps ?? (seconds ? row.prompt_tokens / seconds : null),
@@ -22019,6 +22072,9 @@ function registerApi(app2, d) {
22019
22072
  return err4(c, 400, "invalid_profile_value", "gpu.tensorParallelSize must be an integer \u2265 1.");
22020
22073
  }
22021
22074
  }
22075
+ if (p.nCpuMoe !== void 0 && (typeof p.nCpuMoe !== "number" || !Number.isFinite(p.nCpuMoe) || p.nCpuMoe < 0)) {
22076
+ return err4(c, 400, "invalid_profile_value", "nCpuMoe must be a non-negative number.");
22077
+ }
22022
22078
  const engineId = c.req.query("engine") || d.registry.active()?.id || "*";
22023
22079
  d.store.update((cfg2) => {
22024
22080
  setModelProfile(cfg2, key, engineId, p);
@@ -24249,7 +24305,59 @@ function mapFromOpenAI(oai, modelName) {
24249
24305
  usage: { input_tokens: usage?.prompt_tokens ?? 0, output_tokens: usage?.completion_tokens ?? 0 }
24250
24306
  };
24251
24307
  }
24252
- async function* streamToAnthropic(oaiStream, modelName, msgId, onUsage, onLive, onToolCalls) {
24308
+ var DEFAULT_PING_INTERVAL_MS = 1e4;
24309
+ function waitOrPing(pending2, ms) {
24310
+ return new Promise((resolve5) => {
24311
+ const timer = setTimeout(() => resolve5("ping"), ms);
24312
+ pending2.then(
24313
+ () => {
24314
+ clearTimeout(timer);
24315
+ resolve5("data");
24316
+ },
24317
+ () => {
24318
+ clearTimeout(timer);
24319
+ resolve5("data");
24320
+ }
24321
+ );
24322
+ });
24323
+ }
24324
+ async function pingWhilePending(pending2, emitPing, pingIntervalMs = DEFAULT_PING_INTERVAL_MS, onOrphan) {
24325
+ pending2.catch(() => {
24326
+ });
24327
+ let nextPingAt = Date.now() + pingIntervalMs;
24328
+ while (true) {
24329
+ const remaining = Math.max(0, nextPingAt - Date.now());
24330
+ const outcome = remaining === 0 ? "ping" : await waitOrPing(pending2, remaining);
24331
+ if (outcome === "ping") {
24332
+ try {
24333
+ await emitPing();
24334
+ } catch (e) {
24335
+ if (onOrphan) pending2.then(onOrphan).catch(() => {
24336
+ });
24337
+ throw e;
24338
+ }
24339
+ nextPingAt = Date.now() + pingIntervalMs;
24340
+ continue;
24341
+ }
24342
+ return pending2;
24343
+ }
24344
+ }
24345
+ function messageStartEvent(msgId, modelName) {
24346
+ return sse("message_start", {
24347
+ message: {
24348
+ id: msgId,
24349
+ type: "message",
24350
+ role: "assistant",
24351
+ content: [],
24352
+ model: modelName,
24353
+ stop_reason: null,
24354
+ stop_sequence: null,
24355
+ usage: { input_tokens: 0, output_tokens: 1 }
24356
+ }
24357
+ });
24358
+ }
24359
+ async function* streamToAnthropic(oaiStream, modelName, msgId, opts = {}) {
24360
+ const { onUsage, onLive, onToolCalls, pingIntervalMs = DEFAULT_PING_INTERVAL_MS, skipMessageStart = false } = opts;
24253
24361
  let blockIdx = 0;
24254
24362
  let inThinking = false;
24255
24363
  let inText = false;
@@ -24262,25 +24370,30 @@ async function* streamToAnthropic(oaiStream, modelName, msgId, onUsage, onLive,
24262
24370
  let promptTps = 0;
24263
24371
  let genTps = 0;
24264
24372
  let liveOut = 0;
24265
- yield sse("message_start", {
24266
- message: {
24267
- id: msgId,
24268
- type: "message",
24269
- role: "assistant",
24270
- content: [],
24271
- model: modelName,
24272
- stop_reason: null,
24273
- stop_sequence: null,
24274
- usage: { input_tokens: 0, output_tokens: 1 }
24275
- }
24276
- });
24373
+ if (!skipMessageStart) yield messageStartEvent(msgId, modelName);
24277
24374
  const reader = oaiStream.getReader();
24278
24375
  const dec = new TextDecoder();
24279
24376
  let buf = "";
24280
24377
  let failed = false;
24378
+ let nextPingAt = Date.now() + pingIntervalMs;
24281
24379
  try {
24282
24380
  outer: while (true) {
24283
- const { done, value } = await reader.read();
24381
+ const readPromise = reader.read();
24382
+ readPromise.catch(() => {
24383
+ });
24384
+ let result;
24385
+ while (true) {
24386
+ const remaining = Math.max(0, nextPingAt - Date.now());
24387
+ const outcome = remaining === 0 ? "ping" : await waitOrPing(readPromise, remaining);
24388
+ if (outcome === "ping") {
24389
+ yield sse("ping", {});
24390
+ nextPingAt = Date.now() + pingIntervalMs;
24391
+ continue;
24392
+ }
24393
+ result = await readPromise;
24394
+ break;
24395
+ }
24396
+ const { done, value } = result;
24284
24397
  if (done) break;
24285
24398
  buf += dec.decode(value, { stream: true });
24286
24399
  const lines = buf.split("\n");
@@ -24825,7 +24938,23 @@ function anthropicErrorType(status) {
24825
24938
  function asClientStatus(status) {
24826
24939
  return status >= 400 && status <= 599 ? status : 500;
24827
24940
  }
24828
- function registerGateway(app2, d) {
24941
+ function classifyGateError(e) {
24942
+ const aborted = e.message === "gate_acquire_aborted";
24943
+ return aborted ? { status: 400, type: "invalid_request_error", message: "Client disconnected while queued for the engine." } : { status: 503, type: "overloaded_error", message: "Timed out waiting for a free engine slot." };
24944
+ }
24945
+ function classifyFetchError(e, ac) {
24946
+ const err8 = e;
24947
+ const isAbort = err8.name === "AbortError" || ac.signal.aborted;
24948
+ const cause = err8.cause instanceof Error ? `: ${err8.cause.message}` : "";
24949
+ return {
24950
+ status: 500,
24951
+ type: "api_error",
24952
+ message: isAbort ? "Client disconnected before the engine responded." : `${err8.message || "Engine unreachable."}${cause}`
24953
+ };
24954
+ }
24955
+ function registerGateway(app2, d, opts = {}) {
24956
+ const pingIntervalMs = opts.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
24957
+ const gateAcquireTimeoutMs = opts.gateAcquireTimeoutMs ?? 6e5;
24829
24958
  app2.post("/v1/messages", async (c) => {
24830
24959
  let req;
24831
24960
  try {
@@ -24885,23 +25014,131 @@ function registerGateway(app2, d) {
24885
25014
  if (guidance?.forceTextOnly) oaiBody.tool_choice = "none";
24886
25015
  const oaiAlias = engineModelAlias(d.registry.active()?.kind ?? "");
24887
25016
  if (oaiAlias) oaiBody.model = oaiAlias;
25017
+ const ac = clientAbort(c);
25018
+ if (req.stream) {
25019
+ const msgId = `msg_${randomUUID13().replace(/-/g, "")}`;
25020
+ return streamSSE4(c, async (stream) => {
25021
+ let gateRelease2 = null;
25022
+ let generationStarted = false;
25023
+ stream.onAbort(() => ac.abort());
25024
+ const ping = () => stream.writeSSE({ event: "ping", data: JSON.stringify({ type: "ping" }) });
25025
+ try {
25026
+ try {
25027
+ await stream.writeSSE(messageStartEvent(msgId, modelName));
25028
+ if (d.gate) {
25029
+ try {
25030
+ gateRelease2 = await pingWhilePending(
25031
+ d.gate.acquire("bg", { signal: c.req.raw.signal, timeoutMs: gateAcquireTimeoutMs }),
25032
+ ping,
25033
+ pingIntervalMs,
25034
+ (release) => release()
25035
+ );
25036
+ } catch (e) {
25037
+ const { type, message } = classifyGateError(e);
25038
+ await stream.writeSSE({ event: "error", data: JSON.stringify({ type: "error", error: { type, message } }) });
25039
+ return;
25040
+ }
25041
+ }
25042
+ d.manager.generationStart();
25043
+ generationStarted = true;
25044
+ const requestStart2 = Date.now();
25045
+ let res2;
25046
+ try {
25047
+ res2 = await pingWhilePending(
25048
+ fetch(`${target}/v1/chat/completions`, {
25049
+ method: "POST",
25050
+ headers: { "Content-Type": "application/json" },
25051
+ body: JSON.stringify(oaiBody),
25052
+ signal: ac.signal
25053
+ }),
25054
+ ping,
25055
+ pingIntervalMs
25056
+ // No onOrphan: an orphaned Response has nothing to release — its body is simply
25057
+ // never read and gets garbage-collected, unlike gate.acquire()'s grant above.
25058
+ );
25059
+ } catch (e) {
25060
+ const { type, message } = classifyFetchError(e, ac);
25061
+ await stream.writeSSE({ event: "error", data: JSON.stringify({ type: "error", error: { type, message } }) });
25062
+ return;
25063
+ }
25064
+ if (!res2.ok || !res2.body) {
25065
+ const { message, type } = await describeEngineError(res2);
25066
+ await stream.writeSSE({
25067
+ event: "error",
25068
+ data: JSON.stringify({ type: "error", error: { type: type ?? anthropicErrorType(res2.status), message } })
25069
+ });
25070
+ return;
25071
+ }
25072
+ const gen = streamToAnthropic(res2.body, modelName, msgId, {
25073
+ onUsage: (u) => {
25074
+ try {
25075
+ d.manager.recordCompletion({
25076
+ inputTokens: u.inputTokens,
25077
+ outputTokens: u.outputTokens,
25078
+ promptTps: u.promptTps,
25079
+ genTps: u.genTps
25080
+ });
25081
+ d.db.recordApiUsage({
25082
+ source: "anthropic",
25083
+ modelKey: req.model ?? null,
25084
+ promptTokens: u.inputTokens,
25085
+ genTokens: u.outputTokens,
25086
+ codeSessionId: anthropicCodeSessionId,
25087
+ durationMs: Date.now() - requestStart2,
25088
+ promptTps: u.promptTps,
25089
+ genTps: u.genTps,
25090
+ harness: anthropicHarness
25091
+ });
25092
+ } catch {
25093
+ }
25094
+ },
25095
+ // Live per-request progress for the engine card (prefill % + token count),
25096
+ // so Claude Code traffic shows the same live row as in-app chat.
25097
+ onLive: (live) => {
25098
+ try {
25099
+ d.manager.setLiveGen(live);
25100
+ } catch {
25101
+ }
25102
+ },
25103
+ // Coding-activity attribution for terminal-agent sessions — see
25104
+ // observeCodeSessionTurn. Nothing to attribute for any other client.
25105
+ onToolCalls: (calls) => {
25106
+ if (!anthropicCodeSessionId) return;
25107
+ try {
25108
+ observeCodeSessionTurn(d, anthropicCodeSessionId, calls);
25109
+ } catch {
25110
+ }
25111
+ },
25112
+ skipMessageStart: true
25113
+ // already sent above, before the queue wait
25114
+ });
25115
+ for await (const evt of gen) {
25116
+ await stream.writeSSE({ event: evt.event, data: evt.data });
25117
+ }
25118
+ } finally {
25119
+ ac.abort();
25120
+ if (generationStarted) d.manager.generationEnd();
25121
+ gateRelease2?.();
25122
+ }
25123
+ } catch (e) {
25124
+ await stream.writeSSE({
25125
+ event: "error",
25126
+ data: JSON.stringify({ type: "error", error: { type: "api_error", message: e?.message || "Internal gateway error." } })
25127
+ }).catch(() => {
25128
+ });
25129
+ }
25130
+ });
25131
+ }
24888
25132
  let gateRelease = null;
24889
25133
  if (d.gate) {
24890
25134
  try {
24891
- gateRelease = await d.gate.acquire("bg", { signal: c.req.raw.signal, timeoutMs: 6e5 });
25135
+ gateRelease = await d.gate.acquire("bg", { signal: c.req.raw.signal, timeoutMs: gateAcquireTimeoutMs });
24892
25136
  } catch (e) {
24893
- const aborted = e.message === "gate_acquire_aborted";
24894
- return c.json(
24895
- {
24896
- type: "error",
24897
- error: aborted ? { type: "invalid_request_error", message: "Client disconnected while queued for the engine." } : { type: "overloaded_error", message: "Timed out waiting for a free engine slot." }
24898
- },
24899
- aborted ? 400 : 503
24900
- );
25137
+ const { status: status2, type, message } = classifyGateError(e);
25138
+ return c.json({ type: "error", error: { type, message } }, status2);
24901
25139
  }
24902
25140
  }
24903
25141
  d.manager.generationStart();
24904
- const ac = clientAbort(c);
24905
25142
  const requestStart = Date.now();
24906
25143
  let res;
24907
25144
  try {
@@ -24914,19 +25151,8 @@ function registerGateway(app2, d) {
24914
25151
  } catch (e) {
24915
25152
  d.manager.generationEnd();
24916
25153
  gateRelease?.();
24917
- const err8 = e;
24918
- const isAbort = err8.name === "AbortError" || ac.signal.aborted;
24919
- const cause = err8.cause instanceof Error ? `: ${err8.cause.message}` : "";
24920
- return c.json(
24921
- {
24922
- type: "error",
24923
- error: {
24924
- type: "api_error",
24925
- message: isAbort ? "Client disconnected before the engine responded." : `${err8.message || "Engine unreachable."}${cause}`
24926
- }
24927
- },
24928
- 500
24929
- );
25154
+ const { status: status2, type, message } = classifyFetchError(e, ac);
25155
+ return c.json({ type: "error", error: { type, message } }, status2);
24930
25156
  }
24931
25157
  if (!res.ok || !res.body) {
24932
25158
  d.manager.generationEnd();
@@ -24937,65 +25163,6 @@ function registerGateway(app2, d) {
24937
25163
  asClientStatus(res.status)
24938
25164
  );
24939
25165
  }
24940
- if (req.stream) {
24941
- const msgId = `msg_${randomUUID13().replace(/-/g, "")}`;
24942
- const gen = streamToAnthropic(
24943
- res.body,
24944
- modelName,
24945
- msgId,
24946
- (u) => {
24947
- try {
24948
- d.manager.recordCompletion({
24949
- inputTokens: u.inputTokens,
24950
- outputTokens: u.outputTokens,
24951
- promptTps: u.promptTps,
24952
- genTps: u.genTps
24953
- });
24954
- d.db.recordApiUsage({
24955
- source: "anthropic",
24956
- modelKey: req.model ?? null,
24957
- promptTokens: u.inputTokens,
24958
- genTokens: u.outputTokens,
24959
- codeSessionId: anthropicCodeSessionId,
24960
- durationMs: Date.now() - requestStart,
24961
- promptTps: u.promptTps,
24962
- genTps: u.genTps,
24963
- harness: anthropicHarness
24964
- });
24965
- } catch {
24966
- }
24967
- },
24968
- // Live per-request progress for the engine card (prefill % + token count),
24969
- // so Claude Code traffic shows the same live row as in-app chat.
24970
- (live) => {
24971
- try {
24972
- d.manager.setLiveGen(live);
24973
- } catch {
24974
- }
24975
- },
24976
- // Coding-activity attribution for terminal-agent sessions — see
24977
- // observeCodeSessionTurn. Nothing to attribute for any other client.
24978
- (calls) => {
24979
- if (!anthropicCodeSessionId) return;
24980
- try {
24981
- observeCodeSessionTurn(d, anthropicCodeSessionId, calls);
24982
- } catch {
24983
- }
24984
- }
24985
- );
24986
- return streamSSE4(c, async (stream) => {
24987
- stream.onAbort(() => ac.abort());
24988
- try {
24989
- for await (const evt of gen) {
24990
- await stream.writeSSE({ event: evt.event, data: evt.data });
24991
- }
24992
- } finally {
24993
- ac.abort();
24994
- d.manager.generationEnd();
24995
- gateRelease?.();
24996
- }
24997
- });
24998
- }
24999
25166
  try {
25000
25167
  const oaiRes = await res.json();
25001
25168
  recordOpenAiUsage(d, oaiRes, "anthropic", req.model ?? null, anthropicCodeSessionId, Date.now() - requestStart, anthropicHarness);
@@ -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-m7O9h-cc.js";import{f as V}from"./chat-api-WdKnt_cR.js";import{f as X,a as Z}from"./agent-api-BdnGAV-Y.js";import{P as B}from"./personas-B0p0BX69.js";import{C as ee}from"./chevron-left-tBRMVkX5.js";import{R as te}from"./rotate-ccw-QlaGmqOe.js";import{T as se}from"./trash-2-C43ex79G.js";import{C as ne}from"./chevron-right-B16ur-An.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-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};