@fugood/buttress-server 2.26.0-beta.23 → 2.26.0-beta.25

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.
@@ -3,58 +3,68 @@ import type { ReadableStream } from 'node:stream/web';
3
3
  import type { DecisionResult, ServiceContext, EventStream, Expand } from '../types';
4
4
  export declare const decideProperty: z.ZodObject<{
5
5
  request: z.ZodObject<{
6
- state: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodUnknown, "many">, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
6
+ state: z.ZodOptional<z.ZodNullable<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodUnknown, "many">, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
7
7
  questions: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
8
8
  images: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
10
  }, "strip", z.ZodTypeAny, {
10
- state: string | unknown[] | Record<string, unknown>;
11
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
11
12
  questions: Record<string, Record<string, unknown>>;
12
13
  images?: string[] | undefined;
14
+ files?: string[] | undefined;
13
15
  }, {
14
- state: string | unknown[] | Record<string, unknown>;
16
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
15
17
  questions: Record<string, Record<string, unknown>>;
16
18
  images?: string[] | undefined;
19
+ files?: string[] | undefined;
17
20
  }>;
18
21
  }, "strip", z.ZodTypeAny, {
19
22
  request: {
20
- state: string | unknown[] | Record<string, unknown>;
23
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
21
24
  questions: Record<string, Record<string, unknown>>;
22
25
  images?: string[] | undefined;
26
+ files?: string[] | undefined;
23
27
  };
24
28
  }, {
25
29
  request: {
26
- state: string | unknown[] | Record<string, unknown>;
30
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
27
31
  questions: Record<string, Record<string, unknown>>;
28
32
  images?: string[] | undefined;
33
+ files?: string[] | undefined;
29
34
  };
30
35
  }>;
31
36
  export declare const schemas: {
32
37
  initContext: z.ZodTuple<[z.ZodString, z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>], null>;
33
38
  decide: z.ZodTuple<[z.ZodString, z.ZodObject<{
34
39
  request: z.ZodObject<{
35
- state: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodUnknown, "many">, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
40
+ state: z.ZodOptional<z.ZodNullable<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodUnknown, "many">, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
36
41
  questions: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
37
42
  images: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
43
+ files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
38
44
  }, "strip", z.ZodTypeAny, {
39
- state: string | unknown[] | Record<string, unknown>;
45
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
40
46
  questions: Record<string, Record<string, unknown>>;
41
47
  images?: string[] | undefined;
48
+ files?: string[] | undefined;
42
49
  }, {
43
- state: string | unknown[] | Record<string, unknown>;
50
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
44
51
  questions: Record<string, Record<string, unknown>>;
45
52
  images?: string[] | undefined;
53
+ files?: string[] | undefined;
46
54
  }>;
47
55
  }, "strip", z.ZodTypeAny, {
48
56
  request: {
49
- state: string | unknown[] | Record<string, unknown>;
57
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
50
58
  questions: Record<string, Record<string, unknown>>;
51
59
  images?: string[] | undefined;
60
+ files?: string[] | undefined;
52
61
  };
53
62
  }, {
54
63
  request: {
55
- state: string | unknown[] | Record<string, unknown>;
64
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
56
65
  questions: Record<string, Record<string, unknown>>;
57
66
  images?: string[] | undefined;
67
+ files?: string[] | undefined;
58
68
  };
59
69
  }>], null>;
60
70
  releaseContext: z.ZodTuple<[z.ZodString], null>;
@@ -68,13 +78,14 @@ export interface Service {
68
78
  }>;
69
79
  }
70
80
  /**
71
- * Clients upload local images first (like STT audio) and send their names;
72
- * data URLs pass through.
81
+ * Clients upload local media (images, audio clips) first, like STT audio,
82
+ * and send their names; data URLs pass through.
73
83
  */
74
- export declare const resolveDecisionImages: (session: ServiceContext['session'], request: z.infer<typeof decideProperty>['request']) => {
75
- state: string | unknown[] | Record<string, unknown>;
84
+ export declare const resolveDecisionMedia: (session: ServiceContext['session'], request: z.infer<typeof decideProperty>['request']) => {
85
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
76
86
  questions: Record<string, Record<string, unknown>>;
77
87
  images: string[] | undefined;
88
+ files: string[] | undefined;
78
89
  };
79
90
  declare const _default: Service;
80
91
  export default _default;
@@ -11,29 +11,34 @@ export declare const schemas: {
11
11
  embedding: z.ZodTuple<[z.ZodString, z.ZodAny], null>;
12
12
  decide: z.ZodTuple<[z.ZodString, z.ZodObject<{
13
13
  request: z.ZodObject<{
14
- state: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodUnknown, "many">, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
14
+ state: z.ZodOptional<z.ZodNullable<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodUnknown, "many">, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
15
15
  questions: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
16
16
  images: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
17
+ files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
17
18
  }, "strip", z.ZodTypeAny, {
18
- state: string | unknown[] | Record<string, unknown>;
19
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
19
20
  questions: Record<string, Record<string, unknown>>;
20
21
  images?: string[] | undefined;
22
+ files?: string[] | undefined;
21
23
  }, {
22
- state: string | unknown[] | Record<string, unknown>;
24
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
23
25
  questions: Record<string, Record<string, unknown>>;
24
26
  images?: string[] | undefined;
27
+ files?: string[] | undefined;
25
28
  }>;
26
29
  }, "strip", z.ZodTypeAny, {
27
30
  request: {
28
- state: string | unknown[] | Record<string, unknown>;
31
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
29
32
  questions: Record<string, Record<string, unknown>>;
30
33
  images?: string[] | undefined;
34
+ files?: string[] | undefined;
31
35
  };
32
36
  }, {
33
37
  request: {
34
- state: string | unknown[] | Record<string, unknown>;
38
+ state?: string | unknown[] | Record<string, unknown> | null | undefined;
35
39
  questions: Record<string, Record<string, unknown>>;
36
40
  images?: string[] | undefined;
41
+ files?: string[] | undefined;
37
42
  };
38
43
  }>], null>;
39
44
  };
package/lib/types.d.ts CHANGED
@@ -29,12 +29,20 @@ export type RuntimeConfig = {
29
29
  export type GeneratorType = 'ggml-llm' | 'ggml-stt' | 'ggml-tts' | 'ggml-decision' | 'mlx-llm' | 'onnx-stt' | 'onnx-tts';
30
30
  /** A TypeSafe `/v1/systemone` request, answered by a `ggml-decision` generator. */
31
31
  export type DecisionRequest = {
32
- /** A string, or any JSON object/array (given to the model as JSON text). */
32
+ /**
33
+ * A string, or any JSON object/array (given to the model as JSON text).
34
+ * `null` asks about the media only (`lfm2-d1`, `lfm2-d1-omni`); it needs media.
35
+ */
33
36
  state: unknown;
34
37
  /** Question id → `{ type: 'choice' | 'score' | 'noul', instructions, criteria }`. */
35
38
  questions: Record<string, Record<string, any>>;
36
- /** Local file paths or data URLs; needs a model with an mmproj configured. */
39
+ /**
40
+ * Images, or audio clips for a model that takes audio, as local file paths
41
+ * or data URLs; needs a model with an mmproj configured.
42
+ */
37
43
  images?: string[];
44
+ /** Alias of `images`; both lists are used. */
45
+ files?: string[];
38
46
  };
39
47
  export type DecisionResult = {
40
48
  model: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fugood/buttress-server",
3
- "version": "2.26.0-beta.23",
3
+ "version": "2.26.0-beta.25",
4
4
  "main": "lib/index.mjs",
5
5
  "types": "lib/index.d.ts",
6
6
  "type": "module",
@@ -42,7 +42,7 @@
42
42
  "@earendil-works/pi-tui": "^1.1.0",
43
43
  "@elysiajs/cors": "^1.1.1",
44
44
  "@elysiajs/node": "^1.4.2",
45
- "@fugood/llama.node": "^1.8.0-rc.9",
45
+ "@fugood/llama.node": "^1.8.0-rc.10",
46
46
  "@fugood/whisper.node": "^1.2.0-rc.1",
47
47
  "@huggingface/gguf": "^0.3.2",
48
48
  "@iarna/toml": "^3.0.0",
@@ -69,13 +69,13 @@
69
69
  "zod": "^3.25.76"
70
70
  },
71
71
  "devDependencies": {
72
- "@fugood/agent-tool-runtime": "^2.26.0-beta.19",
73
- "@fugood/bricks-cli": "^2.26.0-beta.23",
74
- "@fugood/bricks-devtools-core": "^2.26.0-beta.23",
72
+ "@fugood/agent-tool-runtime": "^2.26.0-beta.24",
73
+ "@fugood/bricks-cli": "^2.26.0-beta.25",
74
+ "@fugood/bricks-devtools-core": "^2.26.0-beta.24",
75
75
  "@fugood/buttress-config": "^2.26.0-beta.20",
76
- "@fugood/buttress-ui": "^2.26.0-beta.21",
76
+ "@fugood/buttress-ui": "^2.26.0-beta.25",
77
77
  "tsdown": "^0.22.4",
78
78
  "typescript": "^7.0.2"
79
79
  },
80
- "gitHead": "05478f8d02f45fdf791f590c9fb5462e76b4238d"
80
+ "gitHead": "c9d8319f19143d3f489c4bd8709abb495f0c7e42"
81
81
  }
@@ -181,7 +181,7 @@ td .primary { font-weight: 500; }
181
181
  <body>
182
182
  <div id="app"><main><p class="empty-page">Loading status…</p></main></div>
183
183
  <noscript><p class="empty-page">This page needs JavaScript. The raw data is at <a href="/buttress/status">/buttress/status</a>.</p></noscript>
184
- <script type="module">var Mt=Object.create;var{getPrototypeOf:At,defineProperty:et,getOwnPropertyNames:It}=Object;var tt=Object.prototype.hasOwnProperty;function Rt(e){return this[e]}var Vt,Nt,Ot=(e,t,n)=>{var s=e!=null&&typeof e==="object";if(s){var r=t?Vt??=new WeakMap:Nt??=new WeakMap,o=r.get(e);if(o)return o}n=e!=null?Mt(At(e)):{};let i=t||!e||!e.__esModule||!tt.call(e,"default")?et(n,"default",{value:e,enumerable:!0}):n;if(e&&typeof e==="object"||typeof e==="function"){for(let u of It(e))if(!tt.call(i,u))et(i,u,{get:Rt.bind(e,u),enumerable:!0})}if(s)r.set(e,i);return i};var Dt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var ot=Dt(function(Wn,st){var se=1000,oe=se*60,re=oe*60,Q=re*24,Bt=Q*7,qt=Q*365.25;st.exports=function(e,t){t=t||{};var n=typeof e;if(n==="string"&&e.length>0)return Et(e);else if(n==="number"&&isFinite(e))return t.long?Gt(e):Pt(e);throw Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function Et(e){if(e=String(e),e.length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var n=parseFloat(t[1]),s=(t[2]||"ms").toLowerCase();switch(s){case"years":case"year":case"yrs":case"yr":case"y":return n*qt;case"weeks":case"week":case"w":return n*Bt;case"days":case"day":case"d":return n*Q;case"hours":case"hour":case"hrs":case"hr":case"h":return n*re;case"minutes":case"minute":case"mins":case"min":case"m":return n*oe;case"seconds":case"second":case"secs":case"sec":case"s":return n*se;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}function Pt(e){var t=Math.abs(e);if(t>=Q)return Math.round(e/Q)+"d";if(t>=re)return Math.round(e/re)+"h";if(t>=oe)return Math.round(e/oe)+"m";if(t>=se)return Math.round(e/se)+"s";return e+"ms"}function Gt(e){var t=Math.abs(e);if(t>=Q)return Ce(e,t,Q,"day");if(t>=re)return Ce(e,t,re,"hour");if(t>=oe)return Ce(e,t,oe,"minute");if(t>=se)return Ce(e,t,se,"second");return e+" ms"}function Ce(e,t,n,s){var r=t>=n*1.5;return Math.round(e/n)+" "+s+(r?"s":"")}});var G=(e)=>typeof e==="object"&&e!==null&&!Array.isArray(e)&&!(e instanceof Date);var Se={"ggml-llm":"LLM · GGML","mlx-llm":"LLM · MLX","ggml-stt":"STT · GGML","ggml-tts":"TTS · GGML","ggml-decision":"Decision · GGML","onnx-stt":"STT · ONNX","onnx-tts":"TTS · ONNX"},Ee=0.85,nt=0.5;var Ft=Ot(ot(),1),Le=1024,Ge=Le*1024,be=Ge*1024,Kn={b:1,kb:Le,mb:Ge,gb:be,tb:be*1024,pb:be*1024*1024};function j(e){if(!Number.isFinite(e))return"—";if(e<0)return`-${j(-e)}`;if(e>=0.1*be){let t=e/be;return`${Number(t.toFixed(2))>=10?t.toFixed(1):t.toFixed(2)} GB`}if(Math.round(e/Le)>=1024)return`${rt(e/Ge)} MB`;if(Math.round(e)>=1024)return`${rt(e/Le)} KB`;return`${Math.round(e)} B`}var rt=(e)=>{let t=e.toFixed(1);return Number(t)>=10?String(Math.round(e)):t};function ae(e){if(!Number.isFinite(e))return"—";if(e<0)return`-${ae(-e)}`;if(Math.round(e)<1000)return`${Math.round(e)} ms`;let t=Number((e/1000).toFixed(1));if(t<60)return`${t} s`;let n=Math.round(e/1000),[s,r,o,i]=[Math.floor(n/86400),Math.floor(n/3600)%24,Math.floor(n/60)%60,n%60];if(s>0)return Pe([s,"d"],[r,"h"]);if(r>0)return Pe([r,"h"],[o,"m"]);return Pe([o,"m"],[i,"s"])}var Pe=(e,t)=>t[0]>0?`${e[0]} ${e[1]} ${t[0]} ${t[1]}`:`${e[0]} ${e[1]}`;var F="—",_t=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],Fe=(e)=>String(e).padStart(2,"0"),Ht=(e,t)=>e.getFullYear()===t.getFullYear()&&e.getMonth()===t.getMonth()&&e.getDate()===t.getDate();function z(e){if(typeof e==="number")return Number.isFinite(e)?e:null;if(typeof e!=="string"||e.length===0)return null;let t=Date.parse(e);return Number.isNaN(t)?null:t}function Y(e,t,n={}){let s=new Date(e),r=`${Fe(s.getHours())}:${Fe(s.getMinutes())}`;if(!Ht(s,new Date(t)))return`${_t[s.getMonth()]} ${s.getDate()} ${r}`;return n.seconds===!1?r:`${r}:${Fe(s.getSeconds())}`}function at(e,t){let n=Math.floor((t-e)/1000);if(n<1)return"just now";if(n<60)return`${n} s ago`;if(n<3600)return`${Math.floor(n/60)} m ago`;if(n<86400)return`${Math.floor(n/3600)} h ago`;return`${Math.floor(n/86400)} d ago`}function ye(e){if(!Number.isFinite(e)||e<0)return F;if(e<1000)return`${Number((e/1000).toFixed(2))} s`;if(e<60000)return`${(e/1000).toFixed(1)} s`;return ae(e)}function it(e){if(e<60000)return`${Math.max(0,Math.floor(e/1000))} s`;return ae(e)}function _e(e){return j(e).replace(/(\.\d*?)0+ GB$/,"$1 GB").replace(". GB"," GB")}function L(e){return e.toLocaleString("en-US",{maximumFractionDigits:0})}function He(e){return e!==null&&Number.isFinite(e)&&e>0?e.toFixed(1):F}function Me(e){let t=He(e);return t===F?F:`${t} t/s`}function Je(e){return`${Math.floor(Math.min(1,Math.max(0,e))*100)} %`}function X(e,t,n=`${t}s`){return`${L(e)} ${e===1?t:n}`}function ie(e){let t=e.slice(e.lastIndexOf("/")+1);return t.replace(/[-_.]gguf$/i,"")||t}function Ue(e,t=120){return e.length>t?`${e.slice(0,t-1)}…`:e}function lt(e){return e.slice(Math.max(e.lastIndexOf("/"),e.lastIndexOf("\\"))+1)}var Te=3000,Jt="port answered, but not with a Buttress id",$e=`every ${Te/1000} s`,Ut=20,jt=3,zt=600000,Ae=["ggml-llm","ggml-stt","ggml-tts","mlx-llm","ggml-decision","onnx-stt","onnx-tts"],Yt={"ggml-llm":"ggmlLlm","ggml-stt":"ggmlStt","ggml-tts":"ggmlTts","mlx-llm":"mlxLlm","ggml-decision":"ggmlDecision","onnx-stt":"onnxStt","onnx-tts":"onnxTts"},T=(e)=>G(e)?e:{},S=(e)=>Array.isArray(e)?e.map(T):[],a=(e)=>typeof e==="string"&&e.length>0?e:null,mt=(e)=>Array.isArray(e)?e.map(a).filter((t)=>t!==null):[],v=(e)=>typeof e==="number"&&Number.isFinite(e)?e:null,ce=(e)=>Ae.includes(e),Z=(e,t)=>e.reduce((n,s)=>n+(v(s[t])??0),0),k=(...e)=>e.filter(Boolean).join(" · "),E=(e,t={})=>({text:e??F,...t}),m=(e)=>E(e,{mono:!0}),M=(e)=>{let t=v(e);return m(t===null?null:L(t))},x=(e,t,n)=>({text:e,badge:{text:e,tone:t},...n?{sub:n}:{}}),I=(e,t)=>{let n=z(e);return{text:n===null?F:Y(n,t),mono:!0,tone:"muted"}},P=(e)=>{let t=v(e);return m(t===null?null:ye(t))},Ye=(e)=>{let t=v(e);return m(t?j(t):null)},Ie=(e)=>{let t=v(e);return m(t===null?null:`${L(t)} chars`)},C=(e,t)=>{let n=a(e);return E(n?ie(n):null,t?{sub:t}:{})},Re=(e)=>e===!0?x("yes","ok"):x("no","neutral"),Oe=(e)=>{let t=a(e.error);return t?Ue(t):null},B=(e,t="ok")=>e.success===!1?x("failed","err",Oe(e)):x(t,"ok"),ut=(e)=>m(a(e)??(e&&typeof e==="object"?JSON.stringify(e):null)),ct=(e)=>{let t=a(e);return t?x(t,t==="cpu"?"neutral":"ok"):E(null)},de=x("Loaded","ok"),Wt=x("Loading","accent"),ee=x("Not loaded","muted"),l=(e,t,n={})=>({key:e,label:t,...n}),g={mono:!0},V=l("when","When",g),A=l("model","Model",{grow:!0}),U=l("quant","Quant",g),_=l("variant","Variant",g),W=l("state","State"),q=l("took","Took",g),O=l("result","Result"),Ve=l("gpu","GPU"),we=l("size","Size",g),gt=(e)=>{let t=new Map;return e.map((n)=>{let s=t.get(n.key)??0;return t.set(n.key,s+1),s===0?n:{...n,key:`${n.key}~${s}`}})},ue=(e,t,n)=>gt(e.map((s)=>({key:t(s),cells:n(s)}))),N=(e,t,n,s,r)=>({title:e,table:{columns:n,rows:ue(S(t).slice(0,Ut),(o)=>`${a(o.timestamp)??""}|${a(o.id)??""}`,s),emptyText:r}}),Kt=(e)=>e.generators.rows.length>0||e.histories.some(({table:t})=>t.rows.length>0),Qt=(e)=>{if(e.success===!1)return x("failed","err",Oe(e));if(e.interrupted===!0)return x("interrupted","warn");if(e.contextFull===!0)return x("context full","warn");return x("ok","ok")},ft=(e,t,n)=>N("Recent completions",e,[V,A,l("prompt","Prompt",g),l("generated","Generated",g),l("speed","Speed",g),q,O,l("cache","Cache",g),l("total","Total",g),l("promptSpeed","Prompt speed",g),...n?[U]:[]],(s)=>{let r=[s.cacheTokens,s.promptTokens,s.tokensGenerated].map(v),o=r.every((i)=>i===null)?null:r.reduce((i,u)=>i+(u??0),0);return{when:I(s.timestamp,t),model:C(s.repoId),quant:m(a(s.quantization)),cache:M(s.cacheTokens),prompt:M(s.promptTokens),generated:M(s.tokensGenerated),total:M(o),speed:m(Me(v(s.tokensPerSecond))),promptSpeed:m(Me(v(s.promptPerSecond))),took:P(s.durationMs),result:Qt(s)}},"No completions yet"),pe="Model loads",me="No model loads yet",je=(e,t)=>e===null||t===null||e.toLowerCase()===t.toLowerCase(),ht=(e,t,n)=>je(e.repoId,t)&&je(e.quantization,n);function Xt(e){if(e.overBudget)return x("Over budget","err",e.overBudget);if(e.cached===!0)return x("Not loaded · in cache","muted");if(e.cached===!1)return x("Not loaded · not downloaded","muted");return ee}var Zt=(e)=>x(e.progress===null?"Downloading":`Downloading ${Je(e.progress)}`,"accent");function ge(e,t,n){let s=new Set(n.generators.map((f)=>a(f.repoId))),r=t.downloads.filter((f)=>!s.has(f.repoId)),o=Object.fromEntries(n.columns.map(({key:f})=>[f,E(null)])),i=t.configured.filter((f)=>!n.generators.some((R)=>ht(f,a(R.repoId),a(R.quantization)))&&!t.downloads.some((R)=>je(f.repoId,R.repoId))),u=n.columns.some((f)=>f.key==="quant"),h=[...ue(n.generators,(f)=>a(f.id)??"",n.cellsOf),...ue(r,(f)=>`download|${f.repoId}|${f.filename??""}`,(f)=>({...o,model:C(f.repoId,k(f.repoId,f.filename)),state:Zt(f)})),...ue(i,(f)=>`configured|${f.repoId??""}|${f.quantization??""}`,(f)=>({...o,model:f.repoId?C(f.repoId,f.repoId):E("Default model"),...u?{quant:m(f.quantization)}:{},state:Xt(f)}))],c=n.generators.filter(n.isLoaded).length,d=k(h.length>0&&X(h.length,"generator"),c>0&&`${c} loaded`,r.length>0&&`${r.length} downloading`);return{key:e,title:Se[e],...d?{subtitle:d}:{},...n.badge?{badge:n.badge}:{},generators:{columns:n.columns,rows:h,emptyText:"No generators loaded yet. A client loads them on first use."},...n.stats?{stats:n.stats}:{},...n.requests?{requests:n.requests}:{},histories:n.histories}}var en=(e,t)=>{let n=a(t.id),s=`${e}:${a(t.repoId)??""}:`;return n?.startsWith(s)?n.slice(s.length):null},Ne=(e)=>S(e.contexts).some((t)=>t.hasModel===!0),tn={generating:{text:"generating",tone:"ok"},processing_prompt:{text:"prompt",tone:"accent"},queued:{text:"queued",tone:"muted"},done:{text:"done",tone:"neutral"}},nn=(e)=>S(e.parallelStatuses).flatMap((t)=>S(t.requests)).filter((t)=>t.state==="generating");function sn(e,t){return{columns:[l("request","Request",g),A,l("type","Type"),W,l("prompt","Prompt",g),l("tokens","Tokens",g),l("speed","Speed",g),l("elapsed","Elapsed",g)],rows:ue(e,(n)=>`${a(n.generatorId)??""}|${String(n.request_id??"")}`,(n)=>{let s=a(n.state)??"",r=tn[s]??{text:s||F,tone:"neutral"},o=(v(n.prompt_ms)??0)+(v(n.generation_ms)??0);return{request:m(n.request_id===void 0?null:`#${String(n.request_id)}`),model:C(t.get(n.generatorId)),type:E(a(n.type)),state:x(r.text,r.tone),prompt:M(n.prompt_length),tokens:M(n.tokens_generated),speed:m(Me(v(n.tokens_per_second))),elapsed:m(o>0?ye(o):null)}}),emptyText:"No requests in flight"}}function on(e){let{data:t,now:n}=e,s=S(t.generators),r=S(t.parallelStatuses),o=(y)=>r.filter((w)=>w.generatorId===y.id),i=new Map(s.map((y)=>[y.id,y.repoId])),u=T(t.history),h=r.flatMap((y)=>S(y.requests).map((w)=>({...w,generatorId:y.generatorId}))),c=h.filter((y)=>y.state==="generating"),d=Z(r,"queued_requests"),f;if(c.length>0)f={text:`${c.length} generating`,tone:"ok"};else if(d>0)f={text:`${L(d)} queued`,tone:"accent"};let R=r.length>0?[{value:L(Z(r,"n_parallel")),label:"parallel slots"},{value:L(Z(r,"active_slots")),label:"active"},{value:L(d),label:"queued"},{value:He(c.length>0?Z(c,"tokens_per_second"):null),label:"tokens / s now"}]:void 0;return ge("ggml-llm",e,{columns:[A,U,_,l("context","Context",g),l("slots","Slots",g),l("sessions","Sessions",g),W],generators:s,cellsOf:(y)=>{let w=o(y),H=ee;if(Ne(y))H=de;else if(S(y.contexts).length>0)H=Wt;return{model:C(y.repoId,k(a(y.repoId),en("ggml-llm",y))),quant:m(a(y.quantization)),variant:m(a(y.variant)),context:M(y.nCtx),slots:m(w.length>0?`${Z(w,"active_slots")} / ${Z(w,"n_parallel")}`:null),sessions:M(y.refCount),state:H}},isLoaded:Ne,badge:f,stats:R,requests:r.length>0?sn(h,i):void 0,histories:[ft(u.completions,n,!0),N(pe,u.modelLoads,[V,A,_,q,O,U,l("context","Context",g),l("gpuLayers","GPU layers",g)],(y)=>({when:I(y.timestamp,n),model:C(y.repoId),quant:m(a(y.quantization)),variant:m(a(y.variant)),context:M(y.nCtx),gpuLayers:M(y.nGpuLayers),took:P(y.durationMs),result:B(y)}),me)]})}function rn(e){let{data:t,now:n}=e,s=S(t.generators),r=s.map((c)=>T(c.queueStatus)),o=r.filter((c)=>c.processing===!0).length,i=Z(r,"queuedCount"),u=T(t.history),h=(c)=>{let d=v(c.queuedCount)??0;if(c.processing===!0)return k("busy",d>0&&`${d} queued`);return d>0?`${d} queued`:"idle"};return ge("ggml-stt",e,{columns:[A,l("modelType","Type",g),U,_,l("queue","Queue",g),W],generators:s,cellsOf:(c)=>({model:C(c.repoId,a(c.repoId)),modelType:m(a(c.modelType)),quant:m(a(c.quantization)),variant:m(a(c.variant)),queue:m(h(T(c.queueStatus))),state:c.hasContext===!0?de:ee}),isLoaded:(c)=>c.hasContext===!0,badge:s.length>0?{text:`queue ${L(i)}`,tone:i>0?"accent":"muted"}:void 0,stats:s.length>0?[{value:L(o),label:"processing"},{value:L(i),label:"queued"}]:void 0,histories:[N("Recent transcriptions",u.transcriptions,[V,A,l("text","Text",g),q,O,l("segments","Segments",g),l("modelType","Type",g),U,_],(c)=>({when:I(c.timestamp,n),model:C(c.repoId),modelType:m(a(c.modelType)),quant:m(a(c.quantization)),variant:m(a(c.variant)),segments:M(c.segmentCount),text:Ie(c.textLength),took:P(c.durationMs),result:B(c)}),"No transcriptions yet"),N(pe,u.modelLoads,[V,A,_,q,O,l("modelType","Type",g),U,Ve],(c)=>({when:I(c.timestamp,n),model:C(c.repoId),modelType:m(a(c.modelType)),quant:m(a(c.quantization)),variant:m(a(c.variant)),gpu:Re(c.useGpu),took:P(c.durationMs),result:B(c)}),me)]})}var bt=(e)=>({took:e.cached===!0?E(null):P(e.durationMs),result:e.cached===!0?B(e,"ok · cached"):B(e)});function an(e){let{data:t,now:n}=e,s=T(t.history),r=(o)=>{let i=a(o);return m(i?ie(i):null)};return ge("ggml-tts",e,{columns:[A,U,l("vocoder","Vocoder",g),_,Ve,we,W],generators:S(t.generators),cellsOf:(o)=>({model:C(o.repoId,k(a(o.repoId),a(o.family))),quant:m(a(o.quantization)),vocoder:r(o.vocoderRepoId),variant:m(a(o.variant)),gpu:Re(o.useGpu),size:Ye(o.modelBytes),state:o.hasContext===!0?de:ee}),isLoaded:(o)=>o.hasContext===!0,histories:[N("Recent syntheses",s.syntheses,[V,A,l("text","Text",g),l("audio","Audio",g),q,O,_],(o)=>{let i=v(o.audioLength),u=v(o.samplingRate);return{when:I(o.timestamp,n),model:C(o.repoId),variant:m(a(o.variant)),text:Ie(o.textLength),audio:m(i!==null&&u?ye(i/u*1000):null),...bt(o)}},"No syntheses yet"),N(pe,s.modelLoads,[V,A,_,q,O,U,l("vocoder","Vocoder",g),Ve],(o)=>({when:I(o.timestamp,n),model:C(o.repoId),quant:m(a(o.quantization)),variant:m(a(o.variant)),vocoder:r(o.vocoderRepoId),gpu:Re(o.useGpu),took:P(o.durationMs),result:B(o)}),me)]})}function ln(e){let{data:t,now:n}=e,s=T(t.history);return ge("mlx-llm",e,{columns:[A,_,l("contexts","Contexts",g),l("sessions","Sessions",g),W],generators:S(t.generators),cellsOf:(r)=>({model:C(r.repoId,a(r.repoId)),variant:m(a(r.variant)??"mlx"),contexts:M(S(r.contexts).length),sessions:M(r.refCount),state:Ne(r)?de:ee}),isLoaded:Ne,histories:[ft(s.completions,n,!1),N(pe,s.modelLoads,[V,A,_,q,O],(r)=>({when:I(r.timestamp,n),model:C(r.repoId),variant:m(a(r.variant)??"mlx"),took:P(r.durationMs),result:B(r)}),me)]})}function un(e){let{data:t,now:n}=e,s=T(t.history);return ge("ggml-decision",e,{columns:[A,l("decisionType","Type",g),U,_,Ve,we,W],generators:S(t.generators),cellsOf:(r)=>{let o=a(r.mmprojFilename);return{model:C(r.repoId,k(a(r.repoId),o&&`+ ${o}`)),decisionType:m(a(r.decisionType)),quant:m(a(r.quantization)),variant:m(a(r.variant)),gpu:Re(r.useGpu),size:Ye(r.modelBytes),state:r.hasContext===!0?de:ee}},isLoaded:(r)=>r.hasContext===!0,histories:[N("Recent decisions",s.decisions,[V,A,l("questions","Questions",g),q,O,l("images","Images",g),l("tokens","Tokens",g)],(r)=>({when:I(r.timestamp,n),model:C(r.repoId),questions:M(r.questionCount),images:M(v(r.imageCount)||null),tokens:M(r.inputTokens),took:P(r.durationMs),result:B(r)}),"No decisions yet"),N(pe,s.modelLoads,[V,A,_,q,O,l("decisionType","Type",g),U],(r)=>({when:I(r.timestamp,n),model:C(r.repoId),decisionType:m(a(r.decisionType)),quant:m(a(r.quantization)),variant:m(a(r.variant)),took:P(r.durationMs),result:B(r)}),me)]})}function dt(e,t){let{data:n,now:s}=t,r=T(n.history),o=e==="onnx-tts",i=(d)=>{let f=a(d);return f?ie(f):null},u=l("provider","Provider"),h=o?N("Recent syntheses",r.syntheses,[V,A,l("text","Text",g),q,O,u],(d)=>({when:I(d.timestamp,s),model:C(d.repoId),provider:E(a(d.provider)),text:Ie(d.textLength),...bt(d)}),"No syntheses yet"):N("Recent transcriptions",r.transcriptions,[V,A,l("text","Text",g),q,O,l("segments","Segments",g),u],(d)=>({when:I(d.timestamp,s),model:C(d.repoId),provider:E(a(d.provider)),segments:M(d.segmentCount),text:Ie(d.textLength),took:P(d.durationMs),result:B(d)}),"No transcriptions yet"),c=(d)=>(v(d.pipelines)??0)>0;return ge(e,t,{columns:[A,l("dtype","DType",g),u,l("device","Device",g),we,l("pipelines","Pipelines",g),W],generators:S(n.generators),cellsOf:(d)=>{let f=i(d.vocoderRepoId);return{model:C(d.repoId,k(a(d.repoId),f&&`+ ${f}`)),dtype:ut(d.dtype),provider:ct(d.provider),device:m(a(d.device)),size:Ye(d.modelBytes),pipelines:M(d.pipelines??0),state:c(d)?de:ee}},isLoaded:c,histories:[h,N(pe,r.modelLoads,[V,A,u,q,O,l("dtype","DType",g),...o?[l("vocoder","Vocoder",g)]:[]],(d)=>({when:I(d.timestamp,s),model:C(d.repoId),dtype:ut(d.dtype),provider:ct(d.provider),vocoder:m(i(d.vocoderRepoId)),took:P(d.durationMs),result:B(d)}),me)]})}var cn={"ggml-llm":on,"ggml-stt":rn,"ggml-tts":an,"mlx-llm":ln,"ggml-decision":un,"onnx-stt":(e)=>dt("onnx-stt",e),"onnx-tts":(e)=>dt("onnx-tts",e)},ve=(e,t,n,s)=>({value:L(e),label:k(t,n>0&&`${L(n)} ${s}`)}),dn={connected:"ok",connecting:"accent"};function pn(e,t,n){let s=T(e.counters),[r,o,i,u,h]=["calls","daemons","uploads","downloads","auth"].map((p)=>T(s[p])),c=S(e.daemons),d=T(e.history),f=S(d.daemons),R=v(e.count)??0,y=v(e.daemonCount)??0,w=(p,D)=>v(p[D])??0,H=l("name","Function",{mono:!0,grow:!0});return{key:"functions",title:"Local functions",subtitle:k(X(R,"function"),y>0&&X(y,"daemon"),n&&"hot reload on"),badge:{text:"experimental",tone:"warn"},generators:{columns:[l("name","Daemon",{mono:!0,grow:!0}),W,l("started","Started",g),l("timers","Timers",g),l("bank","Bank"),l("events","Events"),l("runs","Runs",g)],rows:ue(c,(p)=>a(p.name)??"",(p)=>{let D=T(p.counts),J=w(D,"failed"),he=w(p,"bankSubscriptions"),ne=a(p.bank)??"connecting",Ze=a(p.description);return{name:E(a(p.name),{mono:!0,...Ze?{sub:Ze}:{}}),state:p.state==="running"?x("running","ok"):x("error","err",Oe(p)),started:I(p.startedAt,t),timers:M(w(p,"timers")),bank:he>0?x(`${ne} · ${he}`,dn[ne]??"warn"):E(null),events:p.listening===!0?x("listening","accent"):E(null),runs:E(k(L(w(D,"runs")),J>0&&`${L(J)} failed`),{mono:!0,...J>0?{tone:"err"}:{}})}}),emptyText:"No daemons running"},stats:[ve(w(r,"total"),"calls",w(r,"failed"),"failed"),ve(w(o,"invocations"),"daemon runs",w(o,"failed"),"failed"),ve(w(i,"total"),`uploads · ${j(w(i,"bytes"))}`,w(i,"failed"),"failed"),ve(w(u,"total"),`downloads · ${j(w(u,"bytes"))}`,w(u,"missed"),"missed"),ve(w(h,"total"),"auth checks",w(h,"denied"),"denied")],histories:[...c.length>0||f.length>0?[N("Daemon activity",f,[V,l("name","Daemon",g),l("event","Event"),q,O],(p)=>({when:I(p.timestamp,t),name:m(a(p.name)),event:x(a(p.event)??F,"accent"),took:P(p.durationMs),result:B(p)}),"No daemon activity yet")]:[],N("Function calls",d.calls,[V,H,l("surface","Surface"),q,O],(p)=>({when:I(p.timestamp,t),name:m(a(p.name)),surface:x(a(p.surface)??F,"accent"),took:P(p.durationMs),result:B(p)}),"No function calls yet"),N("Uploads",d.uploads,[V,l("name","Name",{mono:!0,grow:!0}),l("via","Via"),we,O],(p)=>({when:I(p.timestamp,t),name:m(a(p.name)),via:x(p.source==="call"?"multipart call":"upload","neutral"),size:m(j(w(p,"size"))),result:B(p)}),"No uploads yet"),N("Downloads",d.downloads,[V,l("path","Path",{mono:!0,grow:!0}),we,O],(p)=>({when:I(p.timestamp,t),path:m(a(p.path)),size:m(p.success===!1?null:j(w(p,"size"))),result:p.success===!1?x("not found","err"):x("served","ok")}),"No downloads yet"),N("Auth checks",d.auth,[V,l("request","Request",{mono:!0,grow:!0}),l("mode","Mode",g),l("subject","Subject",g),l("outcome","Outcome")],(p)=>{let D=a(p.outcome)??"denied";return{when:I(p.timestamp,t),request:m([a(p.method),a(p.path)].filter(Boolean).join(" ")||null),mode:m(a(p.mode)),subject:m(a(p.subject)),outcome:D==="allowed"?x("allowed","ok"):x(D,"err")}},"No auth checks yet")]}}function mn(e){let{probe:t,config:n,now:s}=e,r=n?`:${n.port}`:"";switch(t.state){case"live":return{state:"live",label:`Live · polling ${$e}`,tone:"ok",lastUpdatedLabel:t.lastAt===null?null:Y(t.lastAt,s)};case"connecting":return{state:"connecting",label:n?`Connecting · ${r}`:"Connecting…",tone:"muted",lastUpdatedLabel:null};case"mismatch":return{state:"mismatch",label:n?`Port ${n.port} used by another server`:"Another server answered",tone:"warn",lastUpdatedLabel:null};case"unreachable":return n?{state:"unreachable",label:`Not running · probing ${r}`,tone:"muted",lastUpdatedLabel:null}:{state:"unreachable",label:`Disconnected · retrying ${$e}`,tone:"err",lastUpdatedLabel:null}}}function gn(e,t){let{probe:n,config:s,now:r}=e,o=[],i=z(T(t?.server).startedAt);if(n.state==="live"&&s){let{mtimeMs:u}=s,h=u!==null&&i!==null&&u>i?`${lt(s.path)} was saved at ${Y(u,r,{seconds:!1})}; the server loaded it at ${Y(i,r,{seconds:!1})}.`:null,c=s.pendingTarget??null,d=c?`The saved file moves the server ${[c.port!==s.port&&`to :${c.port}`,c.expectedId!==s.expectedId&&`to id ${c.expectedId}`].filter(Boolean).join(" and ")}; this window follows the running one until it stops.`:null;if(h||d)o.push({key:"config-changed",tone:"accent",title:"Config changed since this server started.",body:[h,d,"Restart to apply."].filter(Boolean).join(" "),command:s.startCommand})}if(s&&n.state==="unreachable"&&n.error===Jt)o.push({key:"port-busy",tone:"warn",title:`Port ${s.port} is used by another program`,body:"Something answers HTTP on this port without a Buttress id: another app, or a Buttress too old to report one. Change [server] port in the config, or stop that program."});if(n.state==="mismatch"){let u=n.otherServer,h=s?` This config expects ${s.expectedId}.`:"";o.push({key:"port-in-use",tone:"warn",title:s?`Port ${s.port} is used by another Buttress`:"This port is used by another Buttress",body:u?`It reports id ${u.id}, name "${u.name}", version ${u.version}.${h} Change [server] port in the config, or stop that server.`:`Another server answers on this port.${h} Change [server] port in the config, or stop that server.`})}if(!s&&n.state==="unreachable"){let u=z(t?.timestamp);o.push(t?{key:"disconnected",tone:"err",title:"Lost connection to the server.",body:k(u!==null&&`Showing data from ${Y(u,r)}`,`retrying ${$e}`)}:{key:"disconnected",tone:"err",title:"Cannot reach the server.",body:k(n.error,`retrying ${$e}`)})}return o}var fn=(e)=>S(e).flatMap((t)=>ce(t.type)?[{type:t.type,repoId:a(t.repoId),quantization:a(t.quantization)}]:[]);function hn(e,t){if(!e)return t??[];if(!t)return e;return e.map((n)=>{let s=t.find((r)=>r.type===n.type&&ht(r,n.repoId,n.quantization));return s?{...n,cached:s.cached,overBudget:s.overBudget}:n})}function bn(e){let t=T(e?.server),n=T(t.host),s=a(n.cpuModel),r=v(n.totalMemoryBytes),o=a(n.gpuName);return{generatorTypes:Array.isArray(t.generatorTypes)?t.generatorTypes.filter(ce):null,features:G(t.features)?t.features:null,caps:Array.isArray(t.caps)?ze(t.caps):null,generators:Array.isArray(t.generators)?fn(t.generators):null,host:s&&r!==null?{cpuModel:s,cpuCores:v(n.cpuCores)??0,totalMemoryBytes:r,appleSilicon:n.appleSilicon===!0,...o?{gpuName:o}:{}}:null}}var le=(e)=>({label:e,value:"off",tone:"muted"}),yn=[{key:"openaiCompat",label:"OpenAI-compatible",path:"/oai-compat/v1"},{key:"anthropicMessages",label:"Anthropic Messages",path:"/anthropic-messages"},{key:"typesafeCompat",label:"TypeSafe System One",path:"/typesafe-compat"}];function vn(e){let t=[],n=e.autodiscover;if(G(n)){let o=v(n.udpPort),i=a(n.httpPath),u=o!==null&&(n.udpAnnouncing===!1?`UDP ${o} (not announcing: unbound)`:`UDP ${o}`);t.push({label:"Autodiscover",value:k(u,i&&`HTTP ${i}`)||"on · no transport enabled"})}else t.push(le("Autodiscover"));for(let o of yn)t.push(e[o.key]===!0?{label:o.label,value:"on",tone:"ok",detail:o.path}:le(o.label));let s=T(e.functions);if(s.enabled===!0){let o=v(s.daemons)??0;t.push({label:"Local functions",value:k(`${L(v(s.count)??0)} loaded`,o>0&&X(o,"daemon"),s.hotReload===!0&&"hot reload")})}else t.push(le("Local functions"));let r=e.agents;if(G(r)&&r.enabled===!0){let o=mt(r.names);t.push({label:"Agents",value:k(`${L(v(r.count)??o.length)} configured`,o.length>0&&Ue(o.join(", "),80))})}else t.push(le("Agents"));return t}function $n(e,t){let n=[{label:"Autodiscover",value:e?"HTTP /buttress/info":"HTTP info not found at /buttress/info"}],s=T(t?.functions);if(t){let o=v(s.daemonCount)??0;n.push(s.enabled===!0?{label:"Local functions",value:k(`${L(v(s.count)??0)} loaded`,o>0&&X(o,"daemon"))}:le("Local functions"))}let r=e?.agents;if(G(r))n.push(r.enabled===!0?{label:"Agents",value:`${L(v(r.count)??0)} configured`}:le("Agents"));return n}function wn(e,t,n,s){let r=T(t?.server),o=a(e?.id)??a(r.id);if(!o)return null;let{now:i}=s,u=v(e?.port)??v(r.port)??s.config?.port??0,h=T(e?.authentication),c=T(e?.workspace),d=z(r.startedAt),f=v(r.uptimeMs),R=v(T(r.sessions).open),y=nn(T(t?.ggmlLlm)).length,w=mt(e?.addresses),H=[];if(e)H.push({label:"Authentication",value:h.required===!0?"JWT required on data paths":"none",tone:h.required===!0?"ok":"muted"});return H.push(...n.features?vn(n.features):$n(e,t)),{name:a(e?.name)??a(r.name)??o,id:o,version:`v${a(e?.version)??a(r.version)??"?"}`,addresses:w.map((p)=>`http://${p}:${u}`),port:u,bound:e?h.bound===!0:null,workspaceLabel:a(c.name)??a(c.id),kid:a(h.kid),startedLabel:d===null?null:Y(d,i,{seconds:!1}),uptimeLabel:f===null?null:`up ${it(f)}`,sessionsLabel:R===null?null:k(`${L(R)} open`,y>0&&`${y} generating`),features:H}}function Tn(e,t){if(e.score<=0||!t)return e.usableBytes;if(t.appleSilicon&&e.type==="mlx-llm")return t.totalMemoryBytes;if(t.appleSilicon&&e.hasGpu)return t.totalMemoryBytes*Ee;if(e.hasGpu||e.usableBytes>0)return e.usableBytes;return t.totalMemoryBytes*nt}var xn=(e,t)=>{if(e.deviceName)return e.deviceName;if(e.hasGpu)return t?.gpuName??"GPU";return t?.cpuModel??"CPU only"};function kn(e,t,n){return[...e].sort((s,r)=>Ae.indexOf(s.type)-Ae.indexOf(r.type)).map((s)=>{let r=t.has(s.type),o=s.score>0,i;if(!r)i=o?"Available; no generator configured":"Not available on this host";else if(!o)i="Not detected on this host";else if(s.variant)i=`variant ${s.variant}`;let u="neutral";if(!r)u="muted";else if(!o)u="err";else if(s.hasGpu)u="ok";let h=Tn(s,n);return{type:s.type,title:Se[s.type],score:r?s.score:null,hasGpu:s.hasGpu,usableLabel:h>0?_e(h):F,deviceLabel:xn(s,n),...i?{note:i}:{},tone:u}})}function Sn(e,t){if(!e)return;let n=_e(e.totalMemoryBytes);if(e.appleSilicon)return k(e.gpuName??e.cpuModel,`${n} unified`,t&&`usable at the backend default fraction ${Ee}`);return k(e.cpuModel,e.cpuCores>0&&X(e.cpuCores,"core"),`${n} RAM`)}var ze=(e)=>S(e).flatMap((t)=>ce(t.type)?[{type:t.type,score:v(t.score)??0,hasGpu:t.hasGpu===!0,usableBytes:v(t.usableBytes)??0}]:[]),yt=(e)=>S(e.active).flatMap((t)=>{let n=a(t.repoId);if(!n)return[];let s=v(t.progress);return[{type:ce(t.type)?t.type:null,repoId:n,filename:a(t.filename),progress:s===null?null:Math.min(1,Math.max(0,s)),startedAt:z(t.startedAt)}]}),pt=(e,t)=>k(t,e&&Se[e]);function Cn(e,t){let n=yt(e).map((o)=>{let i=o.startedAt!==null&&`running ${ae(Math.max(0,t-o.startedAt))}`;return{key:`active|${o.repoId}|${o.filename??""}`,title:o.filename??ie(o.repoId),subtitle:pt(o.type,o.repoId),progress:o.progress,detail:k(o.progress===null?"waiting for the first progress report":Je(o.progress),i),tone:"accent"}}),r=S(e.recent).filter((o)=>{if(o.success===!1)return!0;let i=z(o.finishedAt);return i!==null&&t-i<zt}).slice(0,jt).map((o)=>{let i=a(o.repoId)??F,u=z(o.finishedAt),h=v(o.durationMs),c=o.success!==!1;return{key:`recent|${a(o.finishedAt)??""}|${i}`,title:a(o.filename)??ie(i),subtitle:pt(ce(o.type)?o.type:null,i),progress:null,detail:k(c?"done":"failed",h!==null&&`${c?"in":"after"} ${ye(h)}`,u!==null&&Y(u,t),!c&&Oe(o)),tone:c?"ok":"err"}});return gt([...n,...r])}function Ln(e){let{probe:t,config:n,now:s}=e;if(!n||t.state==="live")return null;let r=t.otherServer??null,o=t.error??"no answer";if(t.state==="connecting")o="probing…";else if(t.state==="mismatch")o=`answered by ${r?`"${r.name}" (${r.id})`:"another server"}`;return{probeUrl:`http://127.0.0.1:${n.port}/buttress/info`,resultLabel:t.state==="connecting"?o:k(o,t.lastAt!==null&&at(t.lastAt,s),$e),expectedId:n.expectedId,command:n.startCommand,otherServer:r}}function vt(e){let{probe:t,config:n,now:s}=e,r=t.state==="live"||n===null&&e.status!==null,o=r&&e.status!==null?T(e.status):null,i=r&&e.info!==null?T(e.info):null,u=bn(o),h=T(o?.downloads),c=yt(h),d=new Set([...u.generatorTypes??[...n?.generatorTypes??[],...i?ze(i.generators).map((D)=>D.type):[]],...[...S(h.active),...S(h.recent)].map((D)=>D.type).filter(ce)]),f=i?ze(i.generators):[],R=[];if(u.caps&&u.caps.length>0)R=u.caps;else if(f.length>0)R=f;else if(e.localCaps)R=e.localCaps;let y=u.host??e.hostInfo??null,w=Sn(y,R.length>0),H=hn(u.generators,n?.generators),p=[];if(o){for(let J of Ae){let he=cn[J]({data:T(o[Yt[J]]),downloads:c.filter((ne)=>ne.type===J),configured:H.filter((ne)=>ne.type===J),now:s});if(d.has(J)||Kt(he))p.push(he)}let D=T(o.functions);if(D.enabled===!0){let J=T(u.features?.functions).hotReload===!0;p.push(pn(D,s,J))}}return{connection:mn(e),banners:gn(e,o),identity:r?wn(i,o,u,e):null,hardware:kn(R,d,y),...w?{hardwareSummary:w}:{},downloads:o?Cn(h,s):[],sections:p,notRunning:Ln(e)}}var Mn=new Set(["ggml-llm","mlx-llm","functions"]),fe={logo:'<svg width="18" height="18" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="2.5" y="3" width="15" height="6" rx="1.5"/><rect x="2.5" y="11" width="15" height="6" rx="1.5"/><circle cx="6" cy="6" r="0.8" fill="currentColor"/><circle cx="6" cy="14" r="0.8" fill="currentColor"/></svg>',refresh:'<svg width="16" height="16" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M16 10a6 6 0 1 1-1.8-4.3"/><path d="M16 3v4h-4"/></svg>',chevron:'<svg class="chev" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>',info:'<svg class="banner-icon" width="18" height="18" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="10" cy="10" r="7.5"/><path d="M10 9v5"/><circle cx="10" cy="6.5" r="0.6" fill="currentColor"/></svg>',warning:'<svg class="banner-icon" width="18" height="18" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M10 3.5 2.5 16.5h15L10 3.5Z"/><path d="M10 8v4"/><circle cx="10" cy="14.2" r="0.6" fill="currentColor"/></svg>',stopped:'<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="10" cy="10" r="7"/><path d="M5.5 5.5l9 9"/></svg>'},An={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},b=(e)=>String(e).replace(/[&<>"']/g,(t)=>An[t]),$t=(e)=>e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),K=(e,t)=>`<span class="badge tone-${t}">${b(e)}</span>`;function In(e){let[t,...n]=e.label.split(" · "),s=[...n,e.lastUpdatedLabel].filter(Boolean).join(" · "),r=s?`<span class="pill-detail"> · ${b(s)}</span>`:"";return`<header class="top">
184
+ <script type="module">var Mt=Object.create;var{getPrototypeOf:At,defineProperty:et,getOwnPropertyNames:It}=Object;var tt=Object.prototype.hasOwnProperty;function Rt(e){return this[e]}var Vt,Nt,Ot=(e,t,n)=>{var s=e!=null&&typeof e==="object";if(s){var r=t?Vt??=new WeakMap:Nt??=new WeakMap,o=r.get(e);if(o)return o}n=e!=null?Mt(At(e)):{};let i=t||!e||!e.__esModule||!tt.call(e,"default")?et(n,"default",{value:e,enumerable:!0}):n;if(e&&typeof e==="object"||typeof e==="function"){for(let u of It(e))if(!tt.call(i,u))et(i,u,{get:Rt.bind(e,u),enumerable:!0})}if(s)r.set(e,i);return i};var Dt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var ot=Dt(function(Wn,st){var se=1000,oe=se*60,re=oe*60,Q=re*24,Bt=Q*7,qt=Q*365.25;st.exports=function(e,t){t=t||{};var n=typeof e;if(n==="string"&&e.length>0)return Et(e);else if(n==="number"&&isFinite(e))return t.long?Gt(e):Pt(e);throw Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function Et(e){if(e=String(e),e.length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var n=parseFloat(t[1]),s=(t[2]||"ms").toLowerCase();switch(s){case"years":case"year":case"yrs":case"yr":case"y":return n*qt;case"weeks":case"week":case"w":return n*Bt;case"days":case"day":case"d":return n*Q;case"hours":case"hour":case"hrs":case"hr":case"h":return n*re;case"minutes":case"minute":case"mins":case"min":case"m":return n*oe;case"seconds":case"second":case"secs":case"sec":case"s":return n*se;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}function Pt(e){var t=Math.abs(e);if(t>=Q)return Math.round(e/Q)+"d";if(t>=re)return Math.round(e/re)+"h";if(t>=oe)return Math.round(e/oe)+"m";if(t>=se)return Math.round(e/se)+"s";return e+"ms"}function Gt(e){var t=Math.abs(e);if(t>=Q)return Ce(e,t,Q,"day");if(t>=re)return Ce(e,t,re,"hour");if(t>=oe)return Ce(e,t,oe,"minute");if(t>=se)return Ce(e,t,se,"second");return e+" ms"}function Ce(e,t,n,s){var r=t>=n*1.5;return Math.round(e/n)+" "+s+(r?"s":"")}});var G=(e)=>typeof e==="object"&&e!==null&&!Array.isArray(e)&&!(e instanceof Date);var Se={"ggml-llm":"LLM · GGML","mlx-llm":"LLM · MLX","ggml-stt":"STT · GGML","ggml-tts":"TTS · GGML","ggml-decision":"Decision · GGML","onnx-stt":"STT · ONNX","onnx-tts":"TTS · ONNX"},Ee=0.85,nt=0.5;var Ft=Ot(ot(),1),Le=1024,Ge=Le*1024,be=Ge*1024,Kn={b:1,kb:Le,mb:Ge,gb:be,tb:be*1024,pb:be*1024*1024};function j(e){if(!Number.isFinite(e))return"—";if(e<0)return`-${j(-e)}`;if(e>=0.1*be){let t=e/be;return`${Number(t.toFixed(2))>=10?t.toFixed(1):t.toFixed(2)} GB`}if(Math.round(e/Le)>=1024)return`${rt(e/Ge)} MB`;if(Math.round(e)>=1024)return`${rt(e/Le)} KB`;return`${Math.round(e)} B`}var rt=(e)=>{let t=e.toFixed(1);return Number(t)>=10?String(Math.round(e)):t};function ae(e){if(!Number.isFinite(e))return"—";if(e<0)return`-${ae(-e)}`;if(Math.round(e)<1000)return`${Math.round(e)} ms`;let t=Number((e/1000).toFixed(1));if(t<60)return`${t} s`;let n=Math.round(e/1000),[s,r,o,i]=[Math.floor(n/86400),Math.floor(n/3600)%24,Math.floor(n/60)%60,n%60];if(s>0)return Pe([s,"d"],[r,"h"]);if(r>0)return Pe([r,"h"],[o,"m"]);return Pe([o,"m"],[i,"s"])}var Pe=(e,t)=>t[0]>0?`${e[0]} ${e[1]} ${t[0]} ${t[1]}`:`${e[0]} ${e[1]}`;var F="—",_t=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],Fe=(e)=>String(e).padStart(2,"0"),Ht=(e,t)=>e.getFullYear()===t.getFullYear()&&e.getMonth()===t.getMonth()&&e.getDate()===t.getDate();function z(e){if(typeof e==="number")return Number.isFinite(e)?e:null;if(typeof e!=="string"||e.length===0)return null;let t=Date.parse(e);return Number.isNaN(t)?null:t}function Y(e,t,n={}){let s=new Date(e),r=`${Fe(s.getHours())}:${Fe(s.getMinutes())}`;if(!Ht(s,new Date(t)))return`${_t[s.getMonth()]} ${s.getDate()} ${r}`;return n.seconds===!1?r:`${r}:${Fe(s.getSeconds())}`}function at(e,t){let n=Math.floor((t-e)/1000);if(n<1)return"just now";if(n<60)return`${n} s ago`;if(n<3600)return`${Math.floor(n/60)} m ago`;if(n<86400)return`${Math.floor(n/3600)} h ago`;return`${Math.floor(n/86400)} d ago`}function ye(e){if(!Number.isFinite(e)||e<0)return F;if(e<1000)return`${Number((e/1000).toFixed(2))} s`;if(e<60000)return`${(e/1000).toFixed(1)} s`;return ae(e)}function it(e){if(e<60000)return`${Math.max(0,Math.floor(e/1000))} s`;return ae(e)}function _e(e){return j(e).replace(/(\.\d*?)0+ GB$/,"$1 GB").replace(". GB"," GB")}function L(e){return e.toLocaleString("en-US",{maximumFractionDigits:0})}function He(e){return e!==null&&Number.isFinite(e)&&e>0?e.toFixed(1):F}function Me(e){let t=He(e);return t===F?F:`${t} t/s`}function Je(e){return`${Math.floor(Math.min(1,Math.max(0,e))*100)} %`}function X(e,t,n=`${t}s`){return`${L(e)} ${e===1?t:n}`}function ie(e){let t=e.slice(e.lastIndexOf("/")+1);return t.replace(/[-_.]gguf$/i,"")||t}function Ue(e,t=120){return e.length>t?`${e.slice(0,t-1)}…`:e}function lt(e){return e.slice(Math.max(e.lastIndexOf("/"),e.lastIndexOf("\\"))+1)}var Te=3000,Jt="port answered, but not with a Buttress id",$e=`every ${Te/1000} s`,Ut=20,jt=3,zt=600000,Ae=["ggml-llm","ggml-stt","ggml-tts","mlx-llm","ggml-decision","onnx-stt","onnx-tts"],Yt={"ggml-llm":"ggmlLlm","ggml-stt":"ggmlStt","ggml-tts":"ggmlTts","mlx-llm":"mlxLlm","ggml-decision":"ggmlDecision","onnx-stt":"onnxStt","onnx-tts":"onnxTts"},T=(e)=>G(e)?e:{},S=(e)=>Array.isArray(e)?e.map(T):[],a=(e)=>typeof e==="string"&&e.length>0?e:null,mt=(e)=>Array.isArray(e)?e.map(a).filter((t)=>t!==null):[],v=(e)=>typeof e==="number"&&Number.isFinite(e)?e:null,ce=(e)=>Ae.includes(e),Z=(e,t)=>e.reduce((n,s)=>n+(v(s[t])??0),0),k=(...e)=>e.filter(Boolean).join(" · "),E=(e,t={})=>({text:e??F,...t}),m=(e)=>E(e,{mono:!0}),M=(e)=>{let t=v(e);return m(t===null?null:L(t))},x=(e,t,n)=>({text:e,badge:{text:e,tone:t},...n?{sub:n}:{}}),I=(e,t)=>{let n=z(e);return{text:n===null?F:Y(n,t),mono:!0,tone:"muted"}},P=(e)=>{let t=v(e);return m(t===null?null:ye(t))},Ye=(e)=>{let t=v(e);return m(t?j(t):null)},Ie=(e)=>{let t=v(e);return m(t===null?null:`${L(t)} chars`)},C=(e,t)=>{let n=a(e);return E(n?ie(n):null,t?{sub:t}:{})},Re=(e)=>e===!0?x("yes","ok"):x("no","neutral"),Oe=(e)=>{let t=a(e.error);return t?Ue(t):null},B=(e,t="ok")=>e.success===!1?x("failed","err",Oe(e)):x(t,"ok"),ut=(e)=>m(a(e)??(e&&typeof e==="object"?JSON.stringify(e):null)),ct=(e)=>{let t=a(e);return t?x(t,t==="cpu"?"neutral":"ok"):E(null)},de=x("Loaded","ok"),Wt=x("Loading","accent"),ee=x("Not loaded","muted"),l=(e,t,n={})=>({key:e,label:t,...n}),g={mono:!0},V=l("when","When",g),A=l("model","Model",{grow:!0}),U=l("quant","Quant",g),_=l("variant","Variant",g),W=l("state","State"),q=l("took","Took",g),O=l("result","Result"),Ve=l("gpu","GPU"),we=l("size","Size",g),gt=(e)=>{let t=new Map;return e.map((n)=>{let s=t.get(n.key)??0;return t.set(n.key,s+1),s===0?n:{...n,key:`${n.key}~${s}`}})},ue=(e,t,n)=>gt(e.map((s)=>({key:t(s),cells:n(s)}))),N=(e,t,n,s,r)=>({title:e,table:{columns:n,rows:ue(S(t).slice(0,Ut),(o)=>`${a(o.timestamp)??""}|${a(o.id)??""}`,s),emptyText:r}}),Kt=(e)=>e.generators.rows.length>0||e.histories.some(({table:t})=>t.rows.length>0),Qt=(e)=>{if(e.success===!1)return x("failed","err",Oe(e));if(e.interrupted===!0)return x("interrupted","warn");if(e.contextFull===!0)return x("context full","warn");return x("ok","ok")},ft=(e,t,n)=>N("Recent completions",e,[V,A,l("prompt","Prompt",g),l("generated","Generated",g),l("speed","Speed",g),q,O,l("cache","Cache",g),l("total","Total",g),l("promptSpeed","Prompt speed",g),...n?[U]:[]],(s)=>{let r=[s.cacheTokens,s.promptTokens,s.tokensGenerated].map(v),o=r.every((i)=>i===null)?null:r.reduce((i,u)=>i+(u??0),0);return{when:I(s.timestamp,t),model:C(s.repoId),quant:m(a(s.quantization)),cache:M(s.cacheTokens),prompt:M(s.promptTokens),generated:M(s.tokensGenerated),total:M(o),speed:m(Me(v(s.tokensPerSecond))),promptSpeed:m(Me(v(s.promptPerSecond))),took:P(s.durationMs),result:Qt(s)}},"No completions yet"),pe="Model loads",me="No model loads yet",je=(e,t)=>e===null||t===null||e.toLowerCase()===t.toLowerCase(),ht=(e,t,n)=>je(e.repoId,t)&&je(e.quantization,n);function Xt(e){if(e.overBudget)return x("Over budget","err",e.overBudget);if(e.cached===!0)return x("Not loaded · in cache","muted");if(e.cached===!1)return x("Not loaded · not downloaded","muted");return ee}var Zt=(e)=>x(e.progress===null?"Downloading":`Downloading ${Je(e.progress)}`,"accent");function ge(e,t,n){let s=new Set(n.generators.map((f)=>a(f.repoId))),r=t.downloads.filter((f)=>!s.has(f.repoId)),o=Object.fromEntries(n.columns.map(({key:f})=>[f,E(null)])),i=t.configured.filter((f)=>!n.generators.some((R)=>ht(f,a(R.repoId),a(R.quantization)))&&!t.downloads.some((R)=>je(f.repoId,R.repoId))),u=n.columns.some((f)=>f.key==="quant"),h=[...ue(n.generators,(f)=>a(f.id)??"",n.cellsOf),...ue(r,(f)=>`download|${f.repoId}|${f.filename??""}`,(f)=>({...o,model:C(f.repoId,k(f.repoId,f.filename)),state:Zt(f)})),...ue(i,(f)=>`configured|${f.repoId??""}|${f.quantization??""}`,(f)=>({...o,model:f.repoId?C(f.repoId,f.repoId):E("Default model"),...u?{quant:m(f.quantization)}:{},state:Xt(f)}))],c=n.generators.filter(n.isLoaded).length,d=k(h.length>0&&X(h.length,"generator"),c>0&&`${c} loaded`,r.length>0&&`${r.length} downloading`);return{key:e,title:Se[e],...d?{subtitle:d}:{},...n.badge?{badge:n.badge}:{},generators:{columns:n.columns,rows:h,emptyText:"No generators loaded yet. A client loads them on first use."},...n.stats?{stats:n.stats}:{},...n.requests?{requests:n.requests}:{},histories:n.histories}}var en=(e,t)=>{let n=a(t.id),s=`${e}:${a(t.repoId)??""}:`;return n?.startsWith(s)?n.slice(s.length):null},Ne=(e)=>S(e.contexts).some((t)=>t.hasModel===!0),tn={generating:{text:"generating",tone:"ok"},processing_prompt:{text:"prompt",tone:"accent"},queued:{text:"queued",tone:"muted"},done:{text:"done",tone:"neutral"}},nn=(e)=>S(e.parallelStatuses).flatMap((t)=>S(t.requests)).filter((t)=>t.state==="generating");function sn(e,t){return{columns:[l("request","Request",g),A,l("type","Type"),W,l("prompt","Prompt",g),l("tokens","Tokens",g),l("speed","Speed",g),l("elapsed","Elapsed",g)],rows:ue(e,(n)=>`${a(n.generatorId)??""}|${String(n.request_id??"")}`,(n)=>{let s=a(n.state)??"",r=tn[s]??{text:s||F,tone:"neutral"},o=(v(n.prompt_ms)??0)+(v(n.generation_ms)??0);return{request:m(n.request_id===void 0?null:`#${String(n.request_id)}`),model:C(t.get(n.generatorId)),type:E(a(n.type)),state:x(r.text,r.tone),prompt:M(n.prompt_length),tokens:M(n.tokens_generated),speed:m(Me(v(n.tokens_per_second))),elapsed:m(o>0?ye(o):null)}}),emptyText:"No requests in flight"}}function on(e){let{data:t,now:n}=e,s=S(t.generators),r=S(t.parallelStatuses),o=(y)=>r.filter((w)=>w.generatorId===y.id),i=new Map(s.map((y)=>[y.id,y.repoId])),u=T(t.history),h=r.flatMap((y)=>S(y.requests).map((w)=>({...w,generatorId:y.generatorId}))),c=h.filter((y)=>y.state==="generating"),d=Z(r,"queued_requests"),f;if(c.length>0)f={text:`${c.length} generating`,tone:"ok"};else if(d>0)f={text:`${L(d)} queued`,tone:"accent"};let R=r.length>0?[{value:L(Z(r,"n_parallel")),label:"parallel slots"},{value:L(Z(r,"active_slots")),label:"active"},{value:L(d),label:"queued"},{value:He(c.length>0?Z(c,"tokens_per_second"):null),label:"tokens / s now"}]:void 0;return ge("ggml-llm",e,{columns:[A,U,_,l("context","Context",g),l("slots","Slots",g),l("sessions","Sessions",g),W],generators:s,cellsOf:(y)=>{let w=o(y),H=ee;if(Ne(y))H=de;else if(S(y.contexts).length>0)H=Wt;return{model:C(y.repoId,k(a(y.repoId),en("ggml-llm",y))),quant:m(a(y.quantization)),variant:m(a(y.variant)),context:M(y.nCtx),slots:m(w.length>0?`${Z(w,"active_slots")} / ${Z(w,"n_parallel")}`:null),sessions:M(y.refCount),state:H}},isLoaded:Ne,badge:f,stats:R,requests:r.length>0?sn(h,i):void 0,histories:[ft(u.completions,n,!0),N(pe,u.modelLoads,[V,A,_,q,O,U,l("context","Context",g),l("gpuLayers","GPU layers",g)],(y)=>({when:I(y.timestamp,n),model:C(y.repoId),quant:m(a(y.quantization)),variant:m(a(y.variant)),context:M(y.nCtx),gpuLayers:M(y.nGpuLayers),took:P(y.durationMs),result:B(y)}),me)]})}function rn(e){let{data:t,now:n}=e,s=S(t.generators),r=s.map((c)=>T(c.queueStatus)),o=r.filter((c)=>c.processing===!0).length,i=Z(r,"queuedCount"),u=T(t.history),h=(c)=>{let d=v(c.queuedCount)??0;if(c.processing===!0)return k("busy",d>0&&`${d} queued`);return d>0?`${d} queued`:"idle"};return ge("ggml-stt",e,{columns:[A,l("modelType","Type",g),U,_,l("queue","Queue",g),W],generators:s,cellsOf:(c)=>({model:C(c.repoId,a(c.repoId)),modelType:m(a(c.modelType)),quant:m(a(c.quantization)),variant:m(a(c.variant)),queue:m(h(T(c.queueStatus))),state:c.hasContext===!0?de:ee}),isLoaded:(c)=>c.hasContext===!0,badge:s.length>0?{text:`queue ${L(i)}`,tone:i>0?"accent":"muted"}:void 0,stats:s.length>0?[{value:L(o),label:"processing"},{value:L(i),label:"queued"}]:void 0,histories:[N("Recent transcriptions",u.transcriptions,[V,A,l("text","Text",g),q,O,l("segments","Segments",g),l("modelType","Type",g),U,_],(c)=>({when:I(c.timestamp,n),model:C(c.repoId),modelType:m(a(c.modelType)),quant:m(a(c.quantization)),variant:m(a(c.variant)),segments:M(c.segmentCount),text:Ie(c.textLength),took:P(c.durationMs),result:B(c)}),"No transcriptions yet"),N(pe,u.modelLoads,[V,A,_,q,O,l("modelType","Type",g),U,Ve],(c)=>({when:I(c.timestamp,n),model:C(c.repoId),modelType:m(a(c.modelType)),quant:m(a(c.quantization)),variant:m(a(c.variant)),gpu:Re(c.useGpu),took:P(c.durationMs),result:B(c)}),me)]})}var bt=(e)=>({took:e.cached===!0?E(null):P(e.durationMs),result:e.cached===!0?B(e,"ok · cached"):B(e)});function an(e){let{data:t,now:n}=e,s=T(t.history),r=(o)=>{let i=a(o);return m(i?ie(i):null)};return ge("ggml-tts",e,{columns:[A,U,l("vocoder","Vocoder",g),_,Ve,we,W],generators:S(t.generators),cellsOf:(o)=>({model:C(o.repoId,k(a(o.repoId),a(o.family))),quant:m(a(o.quantization)),vocoder:r(o.vocoderRepoId),variant:m(a(o.variant)),gpu:Re(o.useGpu),size:Ye(o.modelBytes),state:o.hasContext===!0?de:ee}),isLoaded:(o)=>o.hasContext===!0,histories:[N("Recent syntheses",s.syntheses,[V,A,l("text","Text",g),l("audio","Audio",g),q,O,_],(o)=>{let i=v(o.audioLength),u=v(o.samplingRate);return{when:I(o.timestamp,n),model:C(o.repoId),variant:m(a(o.variant)),text:Ie(o.textLength),audio:m(i!==null&&u?ye(i/u*1000):null),...bt(o)}},"No syntheses yet"),N(pe,s.modelLoads,[V,A,_,q,O,U,l("vocoder","Vocoder",g),Ve],(o)=>({when:I(o.timestamp,n),model:C(o.repoId),quant:m(a(o.quantization)),variant:m(a(o.variant)),vocoder:r(o.vocoderRepoId),gpu:Re(o.useGpu),took:P(o.durationMs),result:B(o)}),me)]})}function ln(e){let{data:t,now:n}=e,s=T(t.history);return ge("mlx-llm",e,{columns:[A,_,l("contexts","Contexts",g),l("sessions","Sessions",g),W],generators:S(t.generators),cellsOf:(r)=>({model:C(r.repoId,a(r.repoId)),variant:m(a(r.variant)??"mlx"),contexts:M(S(r.contexts).length),sessions:M(r.refCount),state:Ne(r)?de:ee}),isLoaded:Ne,histories:[ft(s.completions,n,!1),N(pe,s.modelLoads,[V,A,_,q,O],(r)=>({when:I(r.timestamp,n),model:C(r.repoId),variant:m(a(r.variant)??"mlx"),took:P(r.durationMs),result:B(r)}),me)]})}function un(e){let{data:t,now:n}=e,s=T(t.history);return ge("ggml-decision",e,{columns:[A,l("decisionType","Type",g),U,_,Ve,we,W],generators:S(t.generators),cellsOf:(r)=>{let o=a(r.mmprojFilename);return{model:C(r.repoId,k(a(r.repoId),o&&`+ ${o}`)),decisionType:m(a(r.decisionType)),quant:m(a(r.quantization)),variant:m(a(r.variant)),gpu:Re(r.useGpu),size:Ye(r.modelBytes),state:r.hasContext===!0?de:ee}},isLoaded:(r)=>r.hasContext===!0,histories:[N("Recent decisions",s.decisions,[V,A,l("questions","Questions",g),q,O,l("media","Media",g),l("tokens","Tokens",g)],(r)=>({when:I(r.timestamp,n),model:C(r.repoId),questions:M(r.questionCount),media:M(v(r.mediaCount??r.imageCount)||null),tokens:M(r.inputTokens),took:P(r.durationMs),result:B(r)}),"No decisions yet"),N(pe,s.modelLoads,[V,A,_,q,O,l("decisionType","Type",g),U],(r)=>({when:I(r.timestamp,n),model:C(r.repoId),decisionType:m(a(r.decisionType)),quant:m(a(r.quantization)),variant:m(a(r.variant)),took:P(r.durationMs),result:B(r)}),me)]})}function dt(e,t){let{data:n,now:s}=t,r=T(n.history),o=e==="onnx-tts",i=(d)=>{let f=a(d);return f?ie(f):null},u=l("provider","Provider"),h=o?N("Recent syntheses",r.syntheses,[V,A,l("text","Text",g),q,O,u],(d)=>({when:I(d.timestamp,s),model:C(d.repoId),provider:E(a(d.provider)),text:Ie(d.textLength),...bt(d)}),"No syntheses yet"):N("Recent transcriptions",r.transcriptions,[V,A,l("text","Text",g),q,O,l("segments","Segments",g),u],(d)=>({when:I(d.timestamp,s),model:C(d.repoId),provider:E(a(d.provider)),segments:M(d.segmentCount),text:Ie(d.textLength),took:P(d.durationMs),result:B(d)}),"No transcriptions yet"),c=(d)=>(v(d.pipelines)??0)>0;return ge(e,t,{columns:[A,l("dtype","DType",g),u,l("device","Device",g),we,l("pipelines","Pipelines",g),W],generators:S(n.generators),cellsOf:(d)=>{let f=i(d.vocoderRepoId);return{model:C(d.repoId,k(a(d.repoId),f&&`+ ${f}`)),dtype:ut(d.dtype),provider:ct(d.provider),device:m(a(d.device)),size:Ye(d.modelBytes),pipelines:M(d.pipelines??0),state:c(d)?de:ee}},isLoaded:c,histories:[h,N(pe,r.modelLoads,[V,A,u,q,O,l("dtype","DType",g),...o?[l("vocoder","Vocoder",g)]:[]],(d)=>({when:I(d.timestamp,s),model:C(d.repoId),dtype:ut(d.dtype),provider:ct(d.provider),vocoder:m(i(d.vocoderRepoId)),took:P(d.durationMs),result:B(d)}),me)]})}var cn={"ggml-llm":on,"ggml-stt":rn,"ggml-tts":an,"mlx-llm":ln,"ggml-decision":un,"onnx-stt":(e)=>dt("onnx-stt",e),"onnx-tts":(e)=>dt("onnx-tts",e)},ve=(e,t,n,s)=>({value:L(e),label:k(t,n>0&&`${L(n)} ${s}`)}),dn={connected:"ok",connecting:"accent"};function pn(e,t,n){let s=T(e.counters),[r,o,i,u,h]=["calls","daemons","uploads","downloads","auth"].map((p)=>T(s[p])),c=S(e.daemons),d=T(e.history),f=S(d.daemons),R=v(e.count)??0,y=v(e.daemonCount)??0,w=(p,D)=>v(p[D])??0,H=l("name","Function",{mono:!0,grow:!0});return{key:"functions",title:"Local functions",subtitle:k(X(R,"function"),y>0&&X(y,"daemon"),n&&"hot reload on"),badge:{text:"experimental",tone:"warn"},generators:{columns:[l("name","Daemon",{mono:!0,grow:!0}),W,l("started","Started",g),l("timers","Timers",g),l("bank","Bank"),l("events","Events"),l("runs","Runs",g)],rows:ue(c,(p)=>a(p.name)??"",(p)=>{let D=T(p.counts),J=w(D,"failed"),he=w(p,"bankSubscriptions"),ne=a(p.bank)??"connecting",Ze=a(p.description);return{name:E(a(p.name),{mono:!0,...Ze?{sub:Ze}:{}}),state:p.state==="running"?x("running","ok"):x("error","err",Oe(p)),started:I(p.startedAt,t),timers:M(w(p,"timers")),bank:he>0?x(`${ne} · ${he}`,dn[ne]??"warn"):E(null),events:p.listening===!0?x("listening","accent"):E(null),runs:E(k(L(w(D,"runs")),J>0&&`${L(J)} failed`),{mono:!0,...J>0?{tone:"err"}:{}})}}),emptyText:"No daemons running"},stats:[ve(w(r,"total"),"calls",w(r,"failed"),"failed"),ve(w(o,"invocations"),"daemon runs",w(o,"failed"),"failed"),ve(w(i,"total"),`uploads · ${j(w(i,"bytes"))}`,w(i,"failed"),"failed"),ve(w(u,"total"),`downloads · ${j(w(u,"bytes"))}`,w(u,"missed"),"missed"),ve(w(h,"total"),"auth checks",w(h,"denied"),"denied")],histories:[...c.length>0||f.length>0?[N("Daemon activity",f,[V,l("name","Daemon",g),l("event","Event"),q,O],(p)=>({when:I(p.timestamp,t),name:m(a(p.name)),event:x(a(p.event)??F,"accent"),took:P(p.durationMs),result:B(p)}),"No daemon activity yet")]:[],N("Function calls",d.calls,[V,H,l("surface","Surface"),q,O],(p)=>({when:I(p.timestamp,t),name:m(a(p.name)),surface:x(a(p.surface)??F,"accent"),took:P(p.durationMs),result:B(p)}),"No function calls yet"),N("Uploads",d.uploads,[V,l("name","Name",{mono:!0,grow:!0}),l("via","Via"),we,O],(p)=>({when:I(p.timestamp,t),name:m(a(p.name)),via:x(p.source==="call"?"multipart call":"upload","neutral"),size:m(j(w(p,"size"))),result:B(p)}),"No uploads yet"),N("Downloads",d.downloads,[V,l("path","Path",{mono:!0,grow:!0}),we,O],(p)=>({when:I(p.timestamp,t),path:m(a(p.path)),size:m(p.success===!1?null:j(w(p,"size"))),result:p.success===!1?x("not found","err"):x("served","ok")}),"No downloads yet"),N("Auth checks",d.auth,[V,l("request","Request",{mono:!0,grow:!0}),l("mode","Mode",g),l("subject","Subject",g),l("outcome","Outcome")],(p)=>{let D=a(p.outcome)??"denied";return{when:I(p.timestamp,t),request:m([a(p.method),a(p.path)].filter(Boolean).join(" ")||null),mode:m(a(p.mode)),subject:m(a(p.subject)),outcome:D==="allowed"?x("allowed","ok"):x(D,"err")}},"No auth checks yet")]}}function mn(e){let{probe:t,config:n,now:s}=e,r=n?`:${n.port}`:"";switch(t.state){case"live":return{state:"live",label:`Live · polling ${$e}`,tone:"ok",lastUpdatedLabel:t.lastAt===null?null:Y(t.lastAt,s)};case"connecting":return{state:"connecting",label:n?`Connecting · ${r}`:"Connecting…",tone:"muted",lastUpdatedLabel:null};case"mismatch":return{state:"mismatch",label:n?`Port ${n.port} used by another server`:"Another server answered",tone:"warn",lastUpdatedLabel:null};case"unreachable":return n?{state:"unreachable",label:`Not running · probing ${r}`,tone:"muted",lastUpdatedLabel:null}:{state:"unreachable",label:`Disconnected · retrying ${$e}`,tone:"err",lastUpdatedLabel:null}}}function gn(e,t){let{probe:n,config:s,now:r}=e,o=[],i=z(T(t?.server).startedAt);if(n.state==="live"&&s){let{mtimeMs:u}=s,h=u!==null&&i!==null&&u>i?`${lt(s.path)} was saved at ${Y(u,r,{seconds:!1})}; the server loaded it at ${Y(i,r,{seconds:!1})}.`:null,c=s.pendingTarget??null,d=c?`The saved file moves the server ${[c.port!==s.port&&`to :${c.port}`,c.expectedId!==s.expectedId&&`to id ${c.expectedId}`].filter(Boolean).join(" and ")}; this window follows the running one until it stops.`:null;if(h||d)o.push({key:"config-changed",tone:"accent",title:"Config changed since this server started.",body:[h,d,"Restart to apply."].filter(Boolean).join(" "),command:s.startCommand})}if(s&&n.state==="unreachable"&&n.error===Jt)o.push({key:"port-busy",tone:"warn",title:`Port ${s.port} is used by another program`,body:"Something answers HTTP on this port without a Buttress id: another app, or a Buttress too old to report one. Change [server] port in the config, or stop that program."});if(n.state==="mismatch"){let u=n.otherServer,h=s?` This config expects ${s.expectedId}.`:"";o.push({key:"port-in-use",tone:"warn",title:s?`Port ${s.port} is used by another Buttress`:"This port is used by another Buttress",body:u?`It reports id ${u.id}, name "${u.name}", version ${u.version}.${h} Change [server] port in the config, or stop that server.`:`Another server answers on this port.${h} Change [server] port in the config, or stop that server.`})}if(!s&&n.state==="unreachable"){let u=z(t?.timestamp);o.push(t?{key:"disconnected",tone:"err",title:"Lost connection to the server.",body:k(u!==null&&`Showing data from ${Y(u,r)}`,`retrying ${$e}`)}:{key:"disconnected",tone:"err",title:"Cannot reach the server.",body:k(n.error,`retrying ${$e}`)})}return o}var fn=(e)=>S(e).flatMap((t)=>ce(t.type)?[{type:t.type,repoId:a(t.repoId),quantization:a(t.quantization)}]:[]);function hn(e,t){if(!e)return t??[];if(!t)return e;return e.map((n)=>{let s=t.find((r)=>r.type===n.type&&ht(r,n.repoId,n.quantization));return s?{...n,cached:s.cached,overBudget:s.overBudget}:n})}function bn(e){let t=T(e?.server),n=T(t.host),s=a(n.cpuModel),r=v(n.totalMemoryBytes),o=a(n.gpuName);return{generatorTypes:Array.isArray(t.generatorTypes)?t.generatorTypes.filter(ce):null,features:G(t.features)?t.features:null,caps:Array.isArray(t.caps)?ze(t.caps):null,generators:Array.isArray(t.generators)?fn(t.generators):null,host:s&&r!==null?{cpuModel:s,cpuCores:v(n.cpuCores)??0,totalMemoryBytes:r,appleSilicon:n.appleSilicon===!0,...o?{gpuName:o}:{}}:null}}var le=(e)=>({label:e,value:"off",tone:"muted"}),yn=[{key:"openaiCompat",label:"OpenAI-compatible",path:"/oai-compat/v1"},{key:"anthropicMessages",label:"Anthropic Messages",path:"/anthropic-messages"},{key:"typesafeCompat",label:"TypeSafe System One",path:"/typesafe-compat"}];function vn(e){let t=[],n=e.autodiscover;if(G(n)){let o=v(n.udpPort),i=a(n.httpPath),u=o!==null&&(n.udpAnnouncing===!1?`UDP ${o} (not announcing: unbound)`:`UDP ${o}`);t.push({label:"Autodiscover",value:k(u,i&&`HTTP ${i}`)||"on · no transport enabled"})}else t.push(le("Autodiscover"));for(let o of yn)t.push(e[o.key]===!0?{label:o.label,value:"on",tone:"ok",detail:o.path}:le(o.label));let s=T(e.functions);if(s.enabled===!0){let o=v(s.daemons)??0;t.push({label:"Local functions",value:k(`${L(v(s.count)??0)} loaded`,o>0&&X(o,"daemon"),s.hotReload===!0&&"hot reload")})}else t.push(le("Local functions"));let r=e.agents;if(G(r)&&r.enabled===!0){let o=mt(r.names);t.push({label:"Agents",value:k(`${L(v(r.count)??o.length)} configured`,o.length>0&&Ue(o.join(", "),80))})}else t.push(le("Agents"));return t}function $n(e,t){let n=[{label:"Autodiscover",value:e?"HTTP /buttress/info":"HTTP info not found at /buttress/info"}],s=T(t?.functions);if(t){let o=v(s.daemonCount)??0;n.push(s.enabled===!0?{label:"Local functions",value:k(`${L(v(s.count)??0)} loaded`,o>0&&X(o,"daemon"))}:le("Local functions"))}let r=e?.agents;if(G(r))n.push(r.enabled===!0?{label:"Agents",value:`${L(v(r.count)??0)} configured`}:le("Agents"));return n}function wn(e,t,n,s){let r=T(t?.server),o=a(e?.id)??a(r.id);if(!o)return null;let{now:i}=s,u=v(e?.port)??v(r.port)??s.config?.port??0,h=T(e?.authentication),c=T(e?.workspace),d=z(r.startedAt),f=v(r.uptimeMs),R=v(T(r.sessions).open),y=nn(T(t?.ggmlLlm)).length,w=mt(e?.addresses),H=[];if(e)H.push({label:"Authentication",value:h.required===!0?"JWT required on data paths":"none",tone:h.required===!0?"ok":"muted"});return H.push(...n.features?vn(n.features):$n(e,t)),{name:a(e?.name)??a(r.name)??o,id:o,version:`v${a(e?.version)??a(r.version)??"?"}`,addresses:w.map((p)=>`http://${p}:${u}`),port:u,bound:e?h.bound===!0:null,workspaceLabel:a(c.name)??a(c.id),kid:a(h.kid),startedLabel:d===null?null:Y(d,i,{seconds:!1}),uptimeLabel:f===null?null:`up ${it(f)}`,sessionsLabel:R===null?null:k(`${L(R)} open`,y>0&&`${y} generating`),features:H}}function Tn(e,t){if(e.score<=0||!t)return e.usableBytes;if(t.appleSilicon&&e.type==="mlx-llm")return t.totalMemoryBytes;if(t.appleSilicon&&e.hasGpu)return t.totalMemoryBytes*Ee;if(e.hasGpu||e.usableBytes>0)return e.usableBytes;return t.totalMemoryBytes*nt}var xn=(e,t)=>{if(e.deviceName)return e.deviceName;if(e.hasGpu)return t?.gpuName??"GPU";return t?.cpuModel??"CPU only"};function kn(e,t,n){return[...e].sort((s,r)=>Ae.indexOf(s.type)-Ae.indexOf(r.type)).map((s)=>{let r=t.has(s.type),o=s.score>0,i;if(!r)i=o?"Available; no generator configured":"Not available on this host";else if(!o)i="Not detected on this host";else if(s.variant)i=`variant ${s.variant}`;let u="neutral";if(!r)u="muted";else if(!o)u="err";else if(s.hasGpu)u="ok";let h=Tn(s,n);return{type:s.type,title:Se[s.type],score:r?s.score:null,hasGpu:s.hasGpu,usableLabel:h>0?_e(h):F,deviceLabel:xn(s,n),...i?{note:i}:{},tone:u}})}function Sn(e,t){if(!e)return;let n=_e(e.totalMemoryBytes);if(e.appleSilicon)return k(e.gpuName??e.cpuModel,`${n} unified`,t&&`usable at the backend default fraction ${Ee}`);return k(e.cpuModel,e.cpuCores>0&&X(e.cpuCores,"core"),`${n} RAM`)}var ze=(e)=>S(e).flatMap((t)=>ce(t.type)?[{type:t.type,score:v(t.score)??0,hasGpu:t.hasGpu===!0,usableBytes:v(t.usableBytes)??0}]:[]),yt=(e)=>S(e.active).flatMap((t)=>{let n=a(t.repoId);if(!n)return[];let s=v(t.progress);return[{type:ce(t.type)?t.type:null,repoId:n,filename:a(t.filename),progress:s===null?null:Math.min(1,Math.max(0,s)),startedAt:z(t.startedAt)}]}),pt=(e,t)=>k(t,e&&Se[e]);function Cn(e,t){let n=yt(e).map((o)=>{let i=o.startedAt!==null&&`running ${ae(Math.max(0,t-o.startedAt))}`;return{key:`active|${o.repoId}|${o.filename??""}`,title:o.filename??ie(o.repoId),subtitle:pt(o.type,o.repoId),progress:o.progress,detail:k(o.progress===null?"waiting for the first progress report":Je(o.progress),i),tone:"accent"}}),r=S(e.recent).filter((o)=>{if(o.success===!1)return!0;let i=z(o.finishedAt);return i!==null&&t-i<zt}).slice(0,jt).map((o)=>{let i=a(o.repoId)??F,u=z(o.finishedAt),h=v(o.durationMs),c=o.success!==!1;return{key:`recent|${a(o.finishedAt)??""}|${i}`,title:a(o.filename)??ie(i),subtitle:pt(ce(o.type)?o.type:null,i),progress:null,detail:k(c?"done":"failed",h!==null&&`${c?"in":"after"} ${ye(h)}`,u!==null&&Y(u,t),!c&&Oe(o)),tone:c?"ok":"err"}});return gt([...n,...r])}function Ln(e){let{probe:t,config:n,now:s}=e;if(!n||t.state==="live")return null;let r=t.otherServer??null,o=t.error??"no answer";if(t.state==="connecting")o="probing…";else if(t.state==="mismatch")o=`answered by ${r?`"${r.name}" (${r.id})`:"another server"}`;return{probeUrl:`http://127.0.0.1:${n.port}/buttress/info`,resultLabel:t.state==="connecting"?o:k(o,t.lastAt!==null&&at(t.lastAt,s),$e),expectedId:n.expectedId,command:n.startCommand,otherServer:r}}function vt(e){let{probe:t,config:n,now:s}=e,r=t.state==="live"||n===null&&e.status!==null,o=r&&e.status!==null?T(e.status):null,i=r&&e.info!==null?T(e.info):null,u=bn(o),h=T(o?.downloads),c=yt(h),d=new Set([...u.generatorTypes??[...n?.generatorTypes??[],...i?ze(i.generators).map((D)=>D.type):[]],...[...S(h.active),...S(h.recent)].map((D)=>D.type).filter(ce)]),f=i?ze(i.generators):[],R=[];if(u.caps&&u.caps.length>0)R=u.caps;else if(f.length>0)R=f;else if(e.localCaps)R=e.localCaps;let y=u.host??e.hostInfo??null,w=Sn(y,R.length>0),H=hn(u.generators,n?.generators),p=[];if(o){for(let J of Ae){let he=cn[J]({data:T(o[Yt[J]]),downloads:c.filter((ne)=>ne.type===J),configured:H.filter((ne)=>ne.type===J),now:s});if(d.has(J)||Kt(he))p.push(he)}let D=T(o.functions);if(D.enabled===!0){let J=T(u.features?.functions).hotReload===!0;p.push(pn(D,s,J))}}return{connection:mn(e),banners:gn(e,o),identity:r?wn(i,o,u,e):null,hardware:kn(R,d,y),...w?{hardwareSummary:w}:{},downloads:o?Cn(h,s):[],sections:p,notRunning:Ln(e)}}var Mn=new Set(["ggml-llm","mlx-llm","functions"]),fe={logo:'<svg width="18" height="18" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="2.5" y="3" width="15" height="6" rx="1.5"/><rect x="2.5" y="11" width="15" height="6" rx="1.5"/><circle cx="6" cy="6" r="0.8" fill="currentColor"/><circle cx="6" cy="14" r="0.8" fill="currentColor"/></svg>',refresh:'<svg width="16" height="16" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M16 10a6 6 0 1 1-1.8-4.3"/><path d="M16 3v4h-4"/></svg>',chevron:'<svg class="chev" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>',info:'<svg class="banner-icon" width="18" height="18" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="10" cy="10" r="7.5"/><path d="M10 9v5"/><circle cx="10" cy="6.5" r="0.6" fill="currentColor"/></svg>',warning:'<svg class="banner-icon" width="18" height="18" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M10 3.5 2.5 16.5h15L10 3.5Z"/><path d="M10 8v4"/><circle cx="10" cy="14.2" r="0.6" fill="currentColor"/></svg>',stopped:'<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="10" cy="10" r="7"/><path d="M5.5 5.5l9 9"/></svg>'},An={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},b=(e)=>String(e).replace(/[&<>"']/g,(t)=>An[t]),$t=(e)=>e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),K=(e,t)=>`<span class="badge tone-${t}">${b(e)}</span>`;function In(e){let[t,...n]=e.label.split(" · "),s=[...n,e.lastUpdatedLabel].filter(Boolean).join(" · "),r=s?`<span class="pill-detail"> · ${b(s)}</span>`:"";return`<header class="top">
185
185
  <div class="brand">${fe.logo}<h1>Buttress Status</h1></div>
186
186
  <span class="pill tone-${e.tone}"><span class="dot" aria-hidden="true"></span><span>${b(t)}</span>${r}</span>
187
187
  <button type="button" class="btn" id="refresh" data-action="refresh" aria-label="Refresh now">${fe.refresh}<span class="btn-label">Refresh</span></button>