turbollm 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +9 -0
  2. package/dist/cli.js +39 -36
  3. package/dist/webdist/assets/{AgentsScreen-C8ijrgPm.js → AgentsScreen-oDn4ZkM1.js} +1 -1
  4. package/dist/webdist/assets/{ChatScreen-BLAaAAkO.js → ChatScreen-CX4ra3WN.js} +37 -30
  5. package/dist/webdist/assets/{CustomizeScreen-BvwLXcaF.js → CustomizeScreen-uhKz3ulx.js} +1 -1
  6. package/dist/webdist/assets/{DeveloperScreen-Cf_BjtjZ.js → DeveloperScreen-C2117jSw.js} +1 -1
  7. package/dist/webdist/assets/{EnginesScreen-C-ny7PFc.js → EnginesScreen-Dl1lF8qJ.js} +3 -3
  8. package/dist/webdist/assets/ModelDetailDialog-Da2p6itL.js +1 -0
  9. package/dist/webdist/assets/{ModelDirs-V6R_2wmI.js → ModelDirs-iqZFpRga.js} +1 -1
  10. package/dist/webdist/assets/ModelsScreen-BsS0TO6W.js +1 -0
  11. package/dist/webdist/assets/SettingsScreen-QwzKX1gb.js +1 -0
  12. package/dist/webdist/assets/{arc-C-BB3uXs.js → arc-BPL4VCUo.js} +1 -1
  13. package/dist/webdist/assets/{architectureDiagram-3BPJPVTR-CcJ0ZOqZ.js → architectureDiagram-3BPJPVTR-V8Zd2JHr.js} +1 -1
  14. package/dist/webdist/assets/{blockDiagram-GPEHLZMM-ALJWfOwg.js → blockDiagram-GPEHLZMM-C6pGJDrs.js} +1 -1
  15. package/dist/webdist/assets/{c4Diagram-AAUBKEIU-BaIxyDOO.js → c4Diagram-AAUBKEIU-_hXk5ziz.js} +1 -1
  16. package/dist/webdist/assets/channel-YTLuIsBj.js +1 -0
  17. package/dist/webdist/assets/check-BwuGRwaM.js +1 -0
  18. package/dist/webdist/assets/{chunk-2J33WTMH-EWXF5El7.js → chunk-2J33WTMH-CGL1puVz.js} +1 -1
  19. package/dist/webdist/assets/{chunk-4BX2VUAB-B01XIIl5.js → chunk-4BX2VUAB-DrYe7x90.js} +1 -1
  20. package/dist/webdist/assets/{chunk-55IACEB6-CAORK4LB.js → chunk-55IACEB6-CGuQ4vHT.js} +1 -1
  21. package/dist/webdist/assets/{chunk-727SXJPM-Bow98gCW.js → chunk-727SXJPM-B8Wrrhxb.js} +1 -1
  22. package/dist/webdist/assets/{chunk-AQP2D5EJ-D3ihkUfL.js → chunk-AQP2D5EJ-BbTLSwHS.js} +1 -1
  23. package/dist/webdist/assets/{chunk-FMBD7UC4-B3pZV5W8.js → chunk-FMBD7UC4-CRaaHdZE.js} +1 -1
  24. package/dist/webdist/assets/{chunk-ND2GUHAM-Bpfzzi3w.js → chunk-ND2GUHAM-EDheV6SO.js} +1 -1
  25. package/dist/webdist/assets/{chunk-QZHKN3VN-BAr49pW1.js → chunk-QZHKN3VN-TQwy40rm.js} +1 -1
  26. package/dist/webdist/assets/{circle-check-Bxq6YJMS.js → circle-check-DW1zSzW1.js} +1 -1
  27. package/dist/webdist/assets/{circle-x-DEBqweG-.js → circle-x-BVCygJX_.js} +1 -1
  28. package/dist/webdist/assets/classDiagram-4FO5ZUOK-CK-He-ZA.js +1 -0
  29. package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-CK-He-ZA.js +1 -0
  30. package/dist/webdist/assets/{common-BSLr1MvR.js → common-BajDwLu1.js} +1 -1
  31. package/dist/webdist/assets/{copy-button-SltJUQtH.js → copy-button-CcOL_21W.js} +1 -1
  32. package/dist/webdist/assets/{cose-bilkent-S5V4N54A-BEX523vE.js → cose-bilkent-S5V4N54A-BDrO96pv.js} +1 -1
  33. package/dist/webdist/assets/{dagre-BM42HDAG-De5xizkB.js → dagre-BM42HDAG-CPU31zPQ.js} +1 -1
  34. package/dist/webdist/assets/{diagram-2AECGRRQ-Dlcd7uUE.js → diagram-2AECGRRQ-Bx8fkRjV.js} +1 -1
  35. package/dist/webdist/assets/{diagram-5GNKFQAL-CflK9di5.js → diagram-5GNKFQAL-BBYjy9Zt.js} +1 -1
  36. package/dist/webdist/assets/{diagram-KO2AKTUF-Fbl7G2bU.js → diagram-KO2AKTUF-Dos-X-ZR.js} +1 -1
  37. package/dist/webdist/assets/{diagram-LMA3HP47-BC3FH92a.js → diagram-LMA3HP47-wkj6OULt.js} +1 -1
  38. package/dist/webdist/assets/{diagram-OG6HWLK6-DkL3gfhn.js → diagram-OG6HWLK6-CmYjdk0L.js} +1 -1
  39. package/dist/webdist/assets/{dialog-D1-Zlj1l.js → dialog-hJPYu2Ov.js} +1 -1
  40. package/dist/webdist/assets/{erDiagram-TEJ5UH35-DGD3ClXg.js → erDiagram-TEJ5UH35-CsbNDTPD.js} +1 -1
  41. package/dist/webdist/assets/{flowDiagram-I6XJVG4X-CHzMVGFr.js → flowDiagram-I6XJVG4X-BsFFxJiw.js} +1 -1
  42. package/dist/webdist/assets/{ganttDiagram-6RSMTGT7-CAB-ravM.js → ganttDiagram-6RSMTGT7-U9sAiXNQ.js} +1 -1
  43. package/dist/webdist/assets/{gitGraphDiagram-PVQCEYII-DmhgBW8a.js → gitGraphDiagram-PVQCEYII-CxJIMHUV.js} +1 -1
  44. package/dist/webdist/assets/index-B52Brf0-.css +1 -0
  45. package/dist/webdist/assets/{index-B7LTDUDR.js → index-Cj_l2rh0.js} +3 -3
  46. package/dist/webdist/assets/{infoDiagram-5YYISTIA-BswUlelU.js → infoDiagram-5YYISTIA-D4lI1s8i.js} +1 -1
  47. package/dist/webdist/assets/{ishikawaDiagram-YF4QCWOH-DZENhuS5.js → ishikawaDiagram-YF4QCWOH-D4mglNig.js} +1 -1
  48. package/dist/webdist/assets/{journeyDiagram-JHISSGLW-D4BKn3fd.js → journeyDiagram-JHISSGLW-CdEi7F6r.js} +1 -1
  49. package/dist/webdist/assets/{kanban-definition-UN3LZRKU-C4uVyQVS.js → kanban-definition-UN3LZRKU-DVLhy_z6.js} +1 -1
  50. package/dist/webdist/assets/{linear-BwE47XoP.js → linear-d5BrNoO6.js} +1 -1
  51. package/dist/webdist/assets/{mermaid.core-DdEuSeXx.js → mermaid.core-fgLyIScK.js} +4 -4
  52. package/dist/webdist/assets/{mindmap-definition-RKZ34NQL-DxPkmqjP.js → mindmap-definition-RKZ34NQL-D8Ucx5YR.js} +1 -1
  53. package/dist/webdist/assets/{pencil-BavbRBL9.js → pencil-IA-fj275.js} +1 -1
  54. package/dist/webdist/assets/personas-fLJwmnEe.js +278 -0
  55. package/dist/webdist/assets/{pieDiagram-4H26LBE5-CUdk_VXR.js → pieDiagram-4H26LBE5-BBnuZwji.js} +1 -1
  56. package/dist/webdist/assets/{plus-BEY4GU1K.js → plus-Ct3egKtH.js} +1 -1
  57. package/dist/webdist/assets/{quadrantDiagram-W4KKPZXB-MT8mFTQj.js → quadrantDiagram-W4KKPZXB-5_Ip_nW9.js} +1 -1
  58. package/dist/webdist/assets/{radix-DX0vbZxT.js → radix-4XwKfE88.js} +1 -1
  59. package/dist/webdist/assets/{refresh-cw-B2qwQZOz.js → refresh-cw-BBcxwtP-.js} +1 -1
  60. package/dist/webdist/assets/{requirementDiagram-4Y6WPE33-C5lcbiaL.js → requirementDiagram-4Y6WPE33-XC0l0R7d.js} +1 -1
  61. package/dist/webdist/assets/{sankeyDiagram-5OEKKPKP-gCtNl8Ay.js → sankeyDiagram-5OEKKPKP-DJ-RNVjW.js} +1 -1
  62. package/dist/webdist/assets/{save-B5yXIJpT.js → save-BhQrytFt.js} +1 -1
  63. package/dist/webdist/assets/{sequenceDiagram-3UESZ5HK-CZm2Qqlo.js → sequenceDiagram-3UESZ5HK-CNvMsl4g.js} +1 -1
  64. package/dist/webdist/assets/skeleton-CW1R2F_M.js +1 -0
  65. package/dist/webdist/assets/{stateDiagram-AJRCARHV-BBf-D1_B.js → stateDiagram-AJRCARHV-CN9hLd2j.js} +1 -1
  66. package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-CQwepdnn.js +1 -0
  67. package/dist/webdist/assets/{timeline-definition-PNZ67QCA-pZHclsB5.js → timeline-definition-PNZ67QCA-D64WOfwg.js} +1 -1
  68. package/dist/webdist/assets/{trash-2-BOk5wJqV.js → trash-2-BY2m3pE3.js} +1 -1
  69. package/dist/webdist/assets/{vendor-Bhj2wMgn.js → vendor-CKtmMAvG.js} +1 -1
  70. package/dist/webdist/assets/{vennDiagram-CIIHVFJN-D0G0bNDg.js → vennDiagram-CIIHVFJN-FYpgKg2e.js} +1 -1
  71. package/dist/webdist/assets/{wardley-L42UT6IY-CVfbre9P.js → wardley-L42UT6IY-B4qclGl3.js} +1 -1
  72. package/dist/webdist/assets/{wardleyDiagram-YWT4CUSO-DpJ-M6Rq.js → wardleyDiagram-YWT4CUSO-CdYxwShW.js} +1 -1
  73. package/dist/webdist/assets/{wrench-B_UtGGtF.js → wrench-_vB8fZmT.js} +1 -1
  74. package/dist/webdist/assets/{xychartDiagram-2RQKCTM6-D1Ye9Jsh.js → xychartDiagram-2RQKCTM6-bI3ZqIAG.js} +1 -1
  75. package/dist/webdist/index.html +4 -4
  76. package/package.json +1 -1
  77. package/dist/webdist/assets/ModelDetailDialog-64XpCDO6.js +0 -1
  78. package/dist/webdist/assets/ModelsScreen-D8EkblWt.js +0 -1
  79. package/dist/webdist/assets/SettingsScreen-khqKELRg.js +0 -1
  80. package/dist/webdist/assets/channel-xWwBhwfN.js +0 -1
  81. package/dist/webdist/assets/check-Dg0H4Og5.js +0 -1
  82. package/dist/webdist/assets/classDiagram-4FO5ZUOK-CWFRccJj.js +0 -1
  83. package/dist/webdist/assets/classDiagram-v2-Q7XG4LA2-CWFRccJj.js +0 -1
  84. package/dist/webdist/assets/index-DnCwNfT4.css +0 -1
  85. package/dist/webdist/assets/personas-uLVxW5Bm.js +0 -77
  86. package/dist/webdist/assets/skeleton-CrqR3g7t.js +0 -1
  87. package/dist/webdist/assets/sparkles-DlKKkTEa.js +0 -1
  88. package/dist/webdist/assets/stateDiagram-v2-BHNVJYJU-DG-bUrT1.js +0 -1
package/README.md CHANGED
@@ -17,6 +17,8 @@
17
17
  <img src="https://img.shields.io/badge/node-%E2%89%A522-3c873a.svg" alt="node >= 22" />
18
18
  <img src="https://img.shields.io/badge/license-FSL--1.1--ALv2-blue.svg" alt="license" />
19
19
  <img src="https://img.shields.io/badge/platform-Windows%20%C2%B7%20macOS%20%C2%B7%20Linux-555.svg" alt="platforms" />
20
+ <a href="https://ko-fi.com/mohitsoni"><img src="https://img.shields.io/badge/Ko--fi-support%20us-FF5E5B?logo=kofi&logoColor=white" alt="Ko-fi" /></a>
21
+ <a href="https://discord.gg/v6kRbV7nC"><img src="https://img.shields.io/badge/Discord-join%20chat-5865F2?logo=discord&logoColor=white" alt="Discord" /></a>
20
22
  </p>
21
23
 
22
24
  <!-- Brand: shipped app icon web/public/brand/turbollm-icon-512.jpeg · high-res masters web/brand-assets/ (unshipped) · in-app mark web/src/components/Logo.tsx · favicon web/public/favicon.svg -->
@@ -51,6 +53,7 @@ LLMs** — built for people who today hand-compile forks and hunt forums for the
51
53
  - [How TurboLLM compares](#how-turbollm-compares)
52
54
  - [Troubleshooting](#troubleshooting)
53
55
  - [Develop from source](#develop-from-source)
56
+ - [Community](#community)
54
57
  - [License](#license)
55
58
 
56
59
  ---
@@ -482,6 +485,12 @@ shadcn/ui frontend. One TypeScript codebase, shipped as an npm package.
482
485
 
483
486
  ---
484
487
 
488
+ ## Community
489
+
490
+ Questions, ideas, and show-and-tell — join the [Discord](https://discord.gg/v6kRbV7nC).
491
+
492
+ ---
493
+
485
494
  ## License
486
495
 
487
496
  Source-available under the **Functional Source License 1.1 (Apache-2.0 future grant)** — SPDX
package/dist/cli.js CHANGED
@@ -4767,6 +4767,9 @@ var BenchRunner = class {
4767
4767
  // stop/restart/load (kill switches) interrupts auto-tune immediately rather than
4768
4768
  // waiting out the current candidate's request.
4769
4769
  abort = null;
4770
+ runLog = [];
4771
+ runLogMeta = null;
4772
+ logWinner = null;
4770
4773
  // The finished run's winning candidate, held (not persisted) until the user clicks Save.
4771
4774
  winning = null;
4772
4775
  /** Live state for GET /status. */
@@ -4805,6 +4808,24 @@ var BenchRunner = class {
4805
4808
  const deadline = Date.now() + timeoutMs;
4806
4809
  while (this.state.running && Date.now() < deadline) await sleep2(150);
4807
4810
  }
4811
+ getLog() {
4812
+ if (!this.runLogMeta) return null;
4813
+ const { modelKey, startedAt: startedAt2, sys } = this.runLogMeta;
4814
+ return {
4815
+ modelKey,
4816
+ startedAt: startedAt2,
4817
+ hardware: {
4818
+ gpus: sys.gpus.map((g) => ({ name: g.name, vramMb: g.vramMb })),
4819
+ ramMb: sys.ramMB,
4820
+ os: sys.os
4821
+ },
4822
+ entries: [...this.runLog],
4823
+ winner: this.logWinner
4824
+ };
4825
+ }
4826
+ emit(step, candidate) {
4827
+ this.runLog.push({ ts: (/* @__PURE__ */ new Date()).toISOString(), step, ...candidate ? { candidate } : {} });
4828
+ }
4808
4829
  /** Start a run for `modelKey`. Rejects (throws BenchError) when a run is already
4809
4830
  * active, the engine is busy, or the model isn't a benchmarkable GGUF. The run
4810
4831
  * itself proceeds in the background; callers get 202 + poll /status. */
@@ -4826,6 +4847,9 @@ var BenchRunner = class {
4826
4847
  this.cancelled = false;
4827
4848
  this.abort = new AbortController();
4828
4849
  this.winning = null;
4850
+ this.runLog = [];
4851
+ this.runLogMeta = null;
4852
+ this.logWinner = null;
4829
4853
  this.deadline = Date.now() + TOTAL_BUDGET_MS;
4830
4854
  this.state = { running: true, modelKey, step: "Preparing\u2026", candidates: [] };
4831
4855
  void this.run(modelKey, entry, base2).catch((e) => {
@@ -4837,6 +4861,7 @@ var BenchRunner = class {
4837
4861
  // ---- the run ------------------------------------------------------------
4838
4862
  async run(modelKey, entry, base2) {
4839
4863
  const sys = getSysInfo();
4864
+ this.runLogMeta = { modelKey, startedAt: (/* @__PURE__ */ new Date()).toISOString(), sys };
4840
4865
  const active = this.registry.active();
4841
4866
  const caps = active?.capabilities ?? { flags: [], kvTypes: [] };
4842
4867
  const saved = this.store.snapshot().modelProfiles[modelKey];
@@ -4852,6 +4877,7 @@ var BenchRunner = class {
4852
4877
  kvToTune = decideKvToBench(spread, kvCandidates);
4853
4878
  const swing = spread < 0 ? "unknown" : spread >= Number.MAX_SAFE_INTEGER ? "huge" : `${Math.round(spread)} MB`;
4854
4879
  this.state = { ...this.state, step: `KV cache swing ${swing} \u2192 tuning ${kvToTune.join(" + ")}`, candidates: results };
4880
+ this.emit(`KV spread ${swing} \u2192 tuning ${kvToTune.join(" + ")}`);
4855
4881
  }
4856
4882
  for (let i = 0; i < kvToTune.length && !this.cancelled && Date.now() <= this.deadline; i++) {
4857
4883
  const kv = kvToTune[i];
@@ -4875,6 +4901,7 @@ var BenchRunner = class {
4875
4901
  }
4876
4902
  const profile = recommended && hasAnySampling(recommended) ? { ...best.profile, sampling: { ...best.profile.sampling, ...recommended } } : best.profile;
4877
4903
  this.winning = { modelKey, profile, cand: best.cand, entry, sys, engineVersion: active?.version ?? "" };
4904
+ this.logWinner = { params: best.cand.params, tps: best.cand.tps ?? 0, prefillTps: best.cand.prefillTps, ttftMs: best.cand.ttftMs ?? 0, vramMb: best.cand.vramMb };
4878
4905
  this.state = {
4879
4906
  running: false,
4880
4907
  modelKey,
@@ -5021,7 +5048,7 @@ var BenchRunner = class {
5021
5048
  /** Record a VRAM-probe trial in the candidate list (tps/prefill are null — nothing was generated;
5022
5049
  * only the load outcome and absolute VRAM are known). */
5023
5050
  pushProbe(results, base2, knob, value, probe2) {
5024
- results.push({
5051
+ const probeCand = {
5025
5052
  label: `probe ${knob}=${value}`,
5026
5053
  params: {
5027
5054
  ctx: base2.ctx,
@@ -5037,7 +5064,9 @@ var BenchRunner = class {
5037
5064
  ttftMs: null,
5038
5065
  vramMb: null,
5039
5066
  vramAbsMb: probe2.vramAbsMb
5040
- });
5067
+ };
5068
+ results.push(probeCand);
5069
+ this.emit(`${probeCand.label} \u2192 ${probe2.outcome}${probe2.vramAbsMb != null ? ` (${probe2.vramAbsMb} MB)` : ""}`, probeCand);
5041
5070
  this.state = { ...this.state, candidates: results };
5042
5071
  }
5043
5072
  /** Phase 2: the single full prefill + t/s benchmark, at the offload the VRAM probe chose. Pushes
@@ -5046,6 +5075,7 @@ var BenchRunner = class {
5046
5075
  this.state = { ...this.state, step: `KV ${profile.kvTypeK}: measuring best (${label})\u2026`, candidates: results };
5047
5076
  const cand = await this.measure(entry, sys, profile, caps, label, `Measuring ${label}`);
5048
5077
  results.push(cand);
5078
+ this.emit(`bench ${label} \u2192 ${cand.outcome}${cand.tps != null ? ` (${cand.tps.toFixed(1)} tok/s)` : ""}`, cand);
5049
5079
  this.state = { ...this.state, candidates: results, bestTps: cand.tps ?? this.state.bestTps };
5050
5080
  await this.settleGpu();
5051
5081
  return cand.outcome === "ok" && cand.tps !== null ? { cand, profile } : null;
@@ -8021,30 +8051,6 @@ function abortAllInFlightChats() {
8021
8051
  inflight.clear();
8022
8052
  return n;
8023
8053
  }
8024
- var EXPERT_SYSTEM_PROMPT = `You are the TurboLLM in-app expert assistant \u2014 a knowledgeable, friendly guide built into TurboLLM, a local-first desktop app for running large language models on the user's own machine.
8025
-
8026
- Your job is to help the user get the most out of TurboLLM:
8027
- - Explain what TurboLLM features do and how to use them: chatting with local models, the Models screen (discover, download, load, and tune models), the Engines screen (install and manage inference backends like llama.cpp), and Settings (idle timeout, model defaults such as context length and GPU layers, auto-load, theme, network/LAN exposure, and privacy/telemetry).
8028
- - Help the user configure things: picking and loading a model, adjusting sampling (temperature, top-p, top-k, min-p), setting context length and GPU offload, and managing per-thread system prompts and sampling overrides.
8029
- - Troubleshoot common problems: a model that won't load, slow generation, running out of context, missing or failed engine installs, and GPU/CPU offload questions. Reason from the symptoms the user describes and the hardware they mention.
8030
-
8031
- Guidelines:
8032
- - Keep answers practical, concise, and actionable. Prefer concrete steps ("Open the Models screen, click \u2026") over abstract advice.
8033
- - When something depends on the user's hardware or which model is loaded, say so and ask a brief clarifying question if needed.
8034
- - Everything runs locally and offline; never suggest sending the user's data to external services.
8035
- - If you are unsure or a feature may not exist, say so honestly rather than inventing details.`;
8036
- function buildExpertPrompt() {
8037
- const sys = getSysInfo();
8038
- const ramGb = Math.round(sys.ramMB / 1024);
8039
- const gpuLines = sys.gpus.length ? sys.gpus.map((g) => `- GPU: ${g.name}${g.vramMb ? ` (${Math.round(g.vramMb / 1024)} GB VRAM)` : ""}`).join("\n") : "- GPU: none detected";
8040
- const hw = [
8041
- "\n\n## User's hardware",
8042
- `- CPU: ${sys.cpu}${sys.cores ? ` (${sys.cores} cores)` : ""}`,
8043
- `- RAM: ${ramGb} GB`,
8044
- gpuLines
8045
- ].join("\n");
8046
- return EXPERT_SYSTEM_PROMPT + hw;
8047
- }
8048
8054
  function err(c, s, code, msg2) {
8049
8055
  return c.json({ error: { code, message: msg2 } }, s);
8050
8056
  }
@@ -8066,16 +8072,6 @@ function registerChatRoutes(app2, d) {
8066
8072
  const conv = db2.createConversation({ title: b.title, systemPrompt: b.systemPrompt, modelKey: b.modelKey, toolPolicy: b.toolPolicy });
8067
8073
  return c.json(conv, 201);
8068
8074
  });
8069
- app2.post("/api/v1/conversations/expert", async (c) => {
8070
- const ms = d.manager.status();
8071
- const conv = db2.createConversation({
8072
- title: "TurboLLM Expert",
8073
- systemPrompt: buildExpertPrompt(),
8074
- modelKey: ms.model?.key ?? "",
8075
- expertMode: true
8076
- });
8077
- return c.json(conv, 201);
8078
- });
8079
8075
  app2.get("/api/v1/conversations/:id", (c) => {
8080
8076
  const conv = db2.getConversation(c.req.param("id"), true);
8081
8077
  if (!conv) return err(c, 404, "not_found", "Conversation not found.");
@@ -10650,6 +10646,13 @@ function registerApi(app2, d) {
10650
10646
  if (!saved) return err2(c, 409, "no_bench_result", "No auto-tune result to save.");
10651
10647
  return c.json({ ok: true });
10652
10648
  });
10649
+ app2.get("/api/v1/bench/log", (c) => {
10650
+ const log = d.bench.getLog();
10651
+ if (!log) return err2(c, 404, "no_bench_log", "No auto-tune log available.");
10652
+ const slug = log.modelKey.replace(/[^a-z0-9]/gi, "-").replace(/-+/g, "-").slice(0, 60);
10653
+ c.header("Content-Disposition", `attachment; filename="autotune-${slug}-${log.startedAt.slice(0, 10)}.json"`);
10654
+ return c.json(log);
10655
+ });
10653
10656
  app2.get("/api/v1/models", (c) => {
10654
10657
  const { models, scanning, lastScanAt } = d.scanner.list();
10655
10658
  const lastTps = d.db.lastGenTpsByModel();
@@ -1,2 +1,2 @@
1
- import{j as e}from"./radix-DX0vbZxT.js";import{r as u}from"./vendor-Bhj2wMgn.js";import{c as w,e as k,A as T,h as v,L as h,i as S,b,f as C,g as q,X as A}from"./index-B7LTDUDR.js";import{P as N}from"./plus-BEY4GU1K.js";import{C as y}from"./circle-x-DEBqweG-.js";import{C as O}from"./circle-check-Bxq6YJMS.js";import{W as E}from"./wrench-B_UtGGtF.js";const _=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}]],D=w("circle-dot",_);const L=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 6v6l4 2",key:"mmk7yg"}]],P=w("clock",L),p={all:["agent-runs"],list:()=>[...p.all,"list"],detail:t=>[...p.all,"detail",t]};async function g(t,a){const l={Accept:"application/json",...k(),...a?.headers??{}},r=await fetch(t,{...a,headers:l});if(r.status===204)return;const i=await r.text(),o=i?JSON.parse(i):void 0;if(!r.ok){const d=o;throw new T(d?.error?.code??"http_error",d?.error?.message??`Request failed with status ${r.status}.`,r.status)}return o}async function $(){return g("/api/v1/agents/runs")}async function I(t){return g(`/api/v1/agents/runs/${t}`)}async function Q(t){return g("/api/v1/agents/runs",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}async function K(t){await g(`/api/v1/agents/runs/${t}`,{method:"DELETE"})}async function*F(t,a=0,l){const r=`/api/v1/agents/runs/${t}/stream?fromSeq=${a}`,i=await fetch(r,{headers:{Accept:"text/event-stream",...k()},signal:l});if(!i.ok||!i.body)throw new Error(`Stream error: ${i.status}`);const o=i.body.getReader(),d=new TextDecoder;let m="";try{for(;;){const{done:s,value:x}=await o.read();if(s)break;m+=d.decode(x,{stream:!0});const c=m.split(`
1
+ import{j as e}from"./radix-4XwKfE88.js";import{r as u}from"./vendor-CKtmMAvG.js";import{c as w,d as k,A as T,e as v,L as h,f as S,b,g as C,h as q,X as A}from"./index-Cj_l2rh0.js";import{P as N}from"./plus-Ct3egKtH.js";import{C as y}from"./circle-x-BVCygJX_.js";import{C as O}from"./circle-check-DW1zSzW1.js";import{W as E}from"./wrench-_vB8fZmT.js";const _=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}]],D=w("circle-dot",_);const L=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 6v6l4 2",key:"mmk7yg"}]],P=w("clock",L),p={all:["agent-runs"],list:()=>[...p.all,"list"],detail:t=>[...p.all,"detail",t]};async function g(t,a){const l={Accept:"application/json",...k(),...a?.headers??{}},r=await fetch(t,{...a,headers:l});if(r.status===204)return;const i=await r.text(),o=i?JSON.parse(i):void 0;if(!r.ok){const d=o;throw new T(d?.error?.code??"http_error",d?.error?.message??`Request failed with status ${r.status}.`,r.status)}return o}async function $(){return g("/api/v1/agents/runs")}async function I(t){return g(`/api/v1/agents/runs/${t}`)}async function Q(t){return g("/api/v1/agents/runs",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}async function K(t){await g(`/api/v1/agents/runs/${t}`,{method:"DELETE"})}async function*F(t,a=0,l){const r=`/api/v1/agents/runs/${t}/stream?fromSeq=${a}`,i=await fetch(r,{headers:{Accept:"text/event-stream",...k()},signal:l});if(!i.ok||!i.body)throw new Error(`Stream error: ${i.status}`);const o=i.body.getReader(),d=new TextDecoder;let m="";try{for(;;){const{done:s,value:x}=await o.read();if(s)break;m+=d.decode(x,{stream:!0});const c=m.split(`
2
2
  `);m=c.pop()??"";let n="message";for(const f of c){if(f.startsWith("event: ")){n=f.slice(7).trim();continue}if(f.startsWith("data: ")){const j=f.slice(6).trim();if(j==="[DONE]")return;try{const R=JSON.parse(j);if(yield{event:n,data:R},n==="done"||n==="error")return}catch{}n="message"}}}}finally{o.cancel()}}const J={queued:e.jsx(P,{size:12}),running:e.jsx(h,{size:12,className:"animate-spin"}),done:e.jsx(O,{size:12}),failed:e.jsx(y,{size:12}),cancelled:e.jsx(y,{size:12}),interrupted:e.jsx(y,{size:12})},M={queued:"text-muted",running:"text-accent",done:"text-green-500",failed:"text-red-500",cancelled:"text-muted",interrupted:"text-orange-500"};function z({status:t}){return e.jsxs("span",{className:b("flex items-center gap-1 text-[11px] capitalize",M[t]),children:[J[t],t]})}function W(t){const a=Date.now()-new Date(t).getTime();return a<6e4?"just now":a<36e5?`${Math.floor(a/6e4)}m ago`:a<864e5?`${Math.floor(a/36e5)}h ago`:new Date(t).toLocaleDateString()}const U=[{id:"web_search",label:"Web search",hint:"Search the web (needs a provider configured in Settings)"},{id:"fetch_url",label:"Fetch URL",hint:"Read the contents of a web page"},{id:"run_code",label:"Run code",hint:"Execute JS in a sandbox — no mid-run confirmation, opt in only if you trust the task"}];function B({onClose:t,onCreated:a}){const[l,r]=u.useState(""),[i,o]=u.useState(""),[d,m]=u.useState({web_search:!0,fetch_url:!0,run_code:!1}),s=C(),x=n=>m(f=>({...f,[n]:!f[n]})),c=q({mutationFn:()=>Q({title:l.slice(0,60)||"Agent run",systemPrompt:i||void 0,userMessage:l,allowedTools:Object.entries(d).filter(([,n])=>n).map(([n])=>n)}),onSuccess:n=>{s.invalidateQueries({queryKey:p.list()}),a(n.id),t()}});return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/40",onClick:t,children:e.jsxs("div",{className:"w-full max-w-lg rounded-xl border border-border bg-panel p-5 shadow-xl",onClick:n=>n.stopPropagation(),children:[e.jsxs("div",{className:"mb-4 flex items-center justify-between",children:[e.jsx("h2",{className:"text-[15px] font-semibold",children:"New agent run"}),e.jsx("button",{type:"button",onClick:t,className:"text-faint hover:text-ink",children:e.jsx(A,{size:16})})]}),e.jsx("label",{className:"mb-1 block text-[12px] text-muted",children:"Task"}),e.jsx("textarea",{autoFocus:!0,value:l,onChange:n=>r(n.target.value),placeholder:"Describe what the agent should do…",rows:4,className:"mb-3 w-full resize-none rounded-lg border border-border bg-input px-3 py-2 text-[13px] text-ink placeholder:text-faint focus:border-accent focus:outline-none"}),e.jsxs("label",{className:"mb-1 block text-[12px] text-muted",children:["System prompt ",e.jsx("span",{className:"text-faint",children:"(optional)"})]}),e.jsx("textarea",{value:i,onChange:n=>o(n.target.value),placeholder:"You are a helpful assistant…",rows:2,className:"mb-4 w-full resize-none rounded-lg border border-border bg-input px-3 py-2 text-[13px] text-ink placeholder:text-faint focus:border-accent focus:outline-none"}),e.jsx("label",{className:"mb-1.5 block text-[12px] text-muted",children:"Tools"}),e.jsx("div",{className:"mb-4 space-y-1.5",children:U.map(n=>e.jsxs("label",{className:"flex cursor-pointer items-start gap-2 rounded-lg border border-border px-2.5 py-2 hover:bg-panel-2",children:[e.jsx("input",{type:"checkbox",checked:d[n.id],onChange:()=>x(n.id),className:"mt-0.5 accent-[var(--accent)]"}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-[13px] font-medium text-ink",children:n.label}),e.jsx("span",{className:"block text-[11px] leading-snug text-faint",children:n.hint})]})]},n.id))}),e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx("button",{type:"button",onClick:t,className:"rounded-lg px-3 py-1.5 text-[13px] text-muted hover:text-ink",children:"Cancel"}),e.jsxs("button",{type:"button",disabled:!l.trim()||c.isPending,onClick:()=>c.mutate(),className:"flex items-center gap-1.5 rounded-lg bg-accent px-3 py-1.5 text-[13px] font-medium text-white disabled:opacity-50",children:[c.isPending?e.jsx(h,{size:13,className:"animate-spin"}):e.jsx(S,{size:13}),"Run agent"]})]}),c.isError&&e.jsx("p",{className:"mt-2 text-[12px]",style:{color:"var(--err)"},children:c.error.message})]})})}function X({call:t}){const[a,l]=u.useState(!1),r=typeof t.args?.query=="string"?t.args.query:typeof t.args?.url=="string"?t.args.url:JSON.stringify(t.args??{});return e.jsxs("div",{className:"w-full max-w-[85%] rounded-lg border border-border bg-panel px-2.5 py-1.5 text-[12px]",children:[e.jsxs("button",{type:"button",onClick:()=>l(i=>!i),className:"flex w-full items-center gap-1.5 text-left text-muted hover:text-ink",children:[e.jsx(E,{size:12,className:"shrink-0 text-accent"}),e.jsx("span",{className:"font-medium text-ink",children:t.name}),e.jsx("span",{className:"truncate text-faint",children:r})]}),a&&e.jsx("pre",{className:"mt-1.5 max-h-48 overflow-auto whitespace-pre-wrap break-words rounded bg-panel-2 p-2 text-[11px] text-muted",children:t.result})]})}function H({run:t}){const a=C(),l=u.useRef(null),[r,i]=u.useState(""),o=u.useRef(null),d=q({mutationFn:()=>K(t.id),onSuccess:()=>{a.invalidateQueries({queryKey:p.list()})}});u.useEffect(()=>{if(t.status!=="running"&&t.status!=="queued")return;const s=new AbortController;l.current=s;let x="";return(async()=>{try{for await(const c of F(t.id,0,s.signal))if(c.event==="delta")x+=c.data.delta,i(x);else if(c.event==="done"||c.event==="error"){a.invalidateQueries({queryKey:p.detail(t.id)}),a.invalidateQueries({queryKey:p.list()});break}}catch{}})(),()=>{s.abort(),l.current=null}},[t.id,t.status,a]),u.useEffect(()=>{o.current?.scrollIntoView({behavior:"smooth"})},[r,t.messages?.length]);const m=t.messages??[];return e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-border px-4 py-2.5",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[14px] font-medium text-ink",children:t.title}),e.jsx(z,{status:t.status})]}),(t.status==="running"||t.status==="queued")&&e.jsx("button",{type:"button",onClick:()=>d.mutate(),className:"rounded-lg border border-border px-3 py-1 text-[12px] text-muted transition-colors hover:border-red-400 hover:text-red-500",children:d.isPending?e.jsx(h,{size:12,className:"inline animate-spin"}):"Cancel"})]}),e.jsxs("div",{className:"flex-1 space-y-3 overflow-y-auto p-4",children:[m.map(s=>e.jsxs("div",{className:b("flex flex-col gap-1.5",s.role==="user"?"items-end":"items-start"),children:[s.toolCalls?.map(x=>e.jsx(X,{call:x},x.id)),(s.content||s.role==="user"||t.status==="running")&&e.jsx("div",{className:b("max-w-[85%] rounded-xl px-3 py-2 text-[13px] leading-relaxed",s.role==="user"?"bg-accent/15 text-ink":"bg-panel-2 text-ink"),children:e.jsx("p",{className:"whitespace-pre-wrap break-words",children:s.content||(s.role==="assistant"&&t.status==="running"?"…":"")})})]},s.id)),r&&e.jsx("div",{className:"flex gap-2",children:e.jsx("div",{className:"max-w-[85%] rounded-xl bg-panel-2 px-3 py-2 text-[13px] leading-relaxed text-ink",children:e.jsx("p",{className:"whitespace-pre-wrap break-words",children:r})})}),t.error&&e.jsxs("div",{className:"rounded-lg bg-red-500/10 px-3 py-2 text-[12px] text-red-500",children:["Error: ",t.error]}),e.jsx("div",{ref:o})]})]})}function ne(){const[t,a]=u.useState(null),[l,r]=u.useState(!1),i=v({queryKey:p.list(),queryFn:$,refetchInterval:s=>(s.state.data??[]).some(n=>n.status==="queued"||n.status==="running")?3e3:!1}),o=v({queryKey:p.detail(t??""),queryFn:()=>I(t),enabled:!!t,refetchInterval:s=>{const x=s.state.data;return x?.status==="queued"||x?.status==="running"?5e3:!1}}),d=i.data??[],m=o.data;return e.jsxs("div",{className:"flex h-full",children:[e.jsxs("div",{className:"flex w-64 shrink-0 flex-col border-r border-border",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-border px-3 py-2.5",children:[e.jsx("span",{className:"text-[13px] font-semibold text-ink",children:"Agents"}),e.jsxs("button",{type:"button",title:"New agent run",onClick:()=>r(!0),className:"flex items-center gap-1 rounded-lg bg-accent px-2 py-1 text-[11px] font-medium text-white transition-opacity hover:opacity-90",children:[e.jsx(N,{size:11})," New"]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[i.isLoading&&e.jsx("div",{className:"flex h-20 items-center justify-center",children:e.jsx(h,{size:16,className:"animate-spin text-faint"})}),d.length===0&&!i.isLoading&&e.jsxs("div",{className:"px-4 py-8 text-center",children:[e.jsx(S,{size:28,className:"mx-auto mb-2 text-faint"}),e.jsx("p",{className:"text-[12px] text-muted",children:"No agent runs yet."}),e.jsx("p",{className:"mt-0.5 text-[11px] text-faint",children:"Click “New” to start one."})]}),d.map(s=>e.jsxs("button",{type:"button",onClick:()=>a(s.id),className:b("w-full border-b border-border px-3 py-2.5 text-left transition-colors hover:bg-panel-2",t===s.id&&"bg-panel-2"),children:[e.jsx("p",{className:"mb-0.5 truncate text-[13px] font-medium text-ink",children:s.title}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(z,{status:s.status}),e.jsx("span",{className:"text-[10px] text-faint",children:W(s.createdAt)})]})]},s.id))]})]}),e.jsx("div",{className:"flex min-w-0 flex-1 flex-col",children:t?o.isLoading?e.jsx("div",{className:"flex h-full items-center justify-center",children:e.jsx(h,{size:20,className:"animate-spin text-faint"})}):m?e.jsx(H,{run:m}):null:e.jsxs("div",{className:"flex h-full flex-col items-center justify-center text-center",children:[e.jsx(D,{size:32,className:"mb-3 text-faint"}),e.jsx("p",{className:"text-[14px] font-medium text-ink",children:"Select a run"}),e.jsx("p",{className:"mt-1 text-[12px] text-muted",children:"or create a new agent run to get started"}),e.jsxs("button",{type:"button",onClick:()=>r(!0),className:"mt-4 flex items-center gap-1.5 rounded-lg bg-accent px-3 py-1.5 text-[13px] font-medium text-white hover:opacity-90",children:[e.jsx(N,{size:13})," New agent run"]})]})}),l&&e.jsx(B,{onClose:()=>r(!1),onCreated:s=>{a(s),i.refetch()}})]})}export{ne as AgentsScreen};