@fugood/buttress-server 2.24.10 → 2.24.12

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 (2) hide show
  1. package/lib/index.mjs +1 -1
  2. package/package.json +1 -1
package/lib/index.mjs CHANGED
@@ -33,7 +33,7 @@ print(path)
33
33
  === Hardware Information ===`);let t=null;if(process.platform!==`win32`)try{t=O(`uname -a`,{encoding:`utf8`}).trim()}catch{}t?console.log(`System: ${t}`):(console.log(`Hostname: ${x.hostname()}`),console.log(`OS: ${x.type()} ${x.release()}`)),console.log(`Platform: ${e.platform}`),console.log(`CPU Cores: ${x.cpus().length}`),console.log(`Total System Memory: ${(x.totalmem()/1024/1024/1024).toFixed(2)} GB`);let n=e.cpuTotalBytes>0?(e.cpuUsableBytes/e.cpuTotalBytes*100).toFixed(0):0;console.log(`Usable CPU Memory: ${(e.cpuUsableBytes/1024/1024/1024).toFixed(2)} GB (${n}% of ${(e.cpuTotalBytes/1024/1024/1024).toFixed(2)} GB)`),e.hasGpu?(console.log(`
34
34
  --- GPU Details ---`),e.devices.filter(e=>e.type===`gpu`).forEach(t=>{console.log(`GPU Backend: ${t.backend}`),console.log(`GPU Name: ${t.deviceName}`),console.log(`GPU Total Memory: ${(t.maxMemorySize/1024/1024/1024).toFixed(2)} GB`);let n=e.gpuTotalBytes>0?(e.gpuUsableBytes/e.gpuTotalBytes*100).toFixed(0):0;console.log(`GPU Usable Memory: ${(e.gpuUsableBytes/1024/1024/1024).toFixed(2)} GB (${n}% of ${(e.gpuTotalBytes/1024/1024/1024).toFixed(2)} GB)`),t.metadata&&(t.metadata.hasBFloat16&&console.log(`Supports BFloat16: Yes`),t.metadata.hasUnifiedMemory&&console.log(`Unified Memory: Yes`))})):console.log(`GPU: Not available`),console.log(`\nBackend Variant: ${e.variant}`),console.log(`Performance Score: ${e.score}`),e.fit&&(console.log(`
35
35
  --- Model Fit Analysis ---`),console.log(`Fits in GPU: ${e.fit.fitsInGpu?`Yes`:`No`}`),console.log(`Fits in CPU: ${e.fit.fitsInCpu?`Yes`:`No`}`),console.log(`Limiting Factor: ${e.fit.limiting}`))}console.log(`
36
- === Full Capabilities JSON ===`),console.log(JSON.stringify(s,null,2)),process.exit(0)}catch(e){console.error(`Failed to get capabilities:`,e.message),process.exit(1)}}var $r=e({createTestCapsDefaultConfigResolver:()=>q,finalizeGenerator:()=>ri,generatorRegistry:()=>X,getCapabilities:()=>K,getModelIdentifier:()=>si,ggmlLlm:()=>ii,ggmlStt:()=>oi,globalDownloadManager:()=>ei,mlxLlm:()=>ai,showModelsTable:()=>Yr,showSttModelsTable:()=>Zr,startGenerator:()=>ni,startModelDownload:()=>li,status:()=>ci,testGgmlLlmCapabilities:()=>Xr,testGgmlSttCapabilities:()=>Qr});const X=new Map,ei={downloads:new Map,getDownload(e){return this.downloads.get(e)||null},setDownload(e,t){this.downloads.set(e,t)},deleteDownload(e){this.downloads.delete(e)},isDownloading(e){return this.downloads.has(e)},getActiveDownloads(){return Array.from(this.downloads.entries()).map(([e,t])=>({localPath:e,promise:t}))}},ti=e=>{let t=X.get(e);if(!t)throw Error(`Unknown generator id "${e}"`);return t},Z=(e,t)=>{let n=ti(e);if(n.type!==t)throw Error(`Generator "${e}" does not support ${t} backend`);return n.instance};async function ni(e,t){let n={"ggml-llm":{create:vn,getId:yn},"ggml-stt":{create:or,getId:sr},"mlx-llm":{create:Hr,getId:Ur}}[e];if(!n)throw Error(`Unsupported backend type: ${e}`);let r=n.getId(t);if(!r)throw Error(`Buttress generator config missing repo identifier`);let i=`${e}:${r}`,a=X.get(i);if(a)return a.refCount+=1,a.instance.resetFinalized?.(),{id:a.id,info:a.instance.info};let o=await n.create(i,t,{globalDownloadManager:ei}),s={id:i,type:o.type,instance:o,refCount:1};return X.set(i,s),{id:i,info:o.info}}async function ri(e){let t=X.get(e);return t?(--t.refCount,t.refCount<=0&&(await t.instance.finalize(),(t.instance.hasPendingReleases?.()??!1)||X.delete(e)),!0):!1}const ii={async initContext(e,t){return Z(e,`ggml-llm`).initContext(t)},async completion(e,t){return Z(e,`ggml-llm`).completion(t)},async tokenize(e,t){return Z(e,`ggml-llm`).tokenize(t)},async detokenize(e,t){return Z(e,`ggml-llm`).detokenize(t)},async applyChatTemplate(e,t){return Z(e,`ggml-llm`).applyChatTemplate(t)},async releaseContext(e,t){let n=X.get(e);if(!n)return{released:!0,alreadyReleased:!0};if(n.type!==`ggml-llm`)throw Error(`Generator "${e}" does not support ggml-llm backend`);return n.instance.releaseContext(t)}},ai={async initContext(e,t){return Z(e,`mlx-llm`).initContext(t)},async completion(e,t){return Z(e,`mlx-llm`).completion(t)},async tokenize(e,t){return Z(e,`mlx-llm`).tokenize(t)},async detokenize(e,t){return Z(e,`mlx-llm`).detokenize(t)},async applyChatTemplate(e,t){return Z(e,`mlx-llm`).applyChatTemplate(t)},async releaseContext(e,t){let n=X.get(e);if(!n)return{released:!0,alreadyReleased:!0};if(n.type!==`mlx-llm`)throw Error(`Generator "${e}" does not support mlx-llm backend`);return n.instance.releaseContext(t)}},oi={async initContext(e,t){return Z(e,`ggml-stt`).initContext(t)},async transcribe(e,t){return Z(e,`ggml-stt`).transcribe(t)},async transcribeData(e,t){return Z(e,`ggml-stt`).transcribeData(t)},async releaseContext(e,t){let n=X.get(e);if(!n)return{released:!0,alreadyReleased:!0};if(n.type!==`ggml-stt`)throw Error(`Generator "${e}" does not support ggml-stt backend`);return n.instance.releaseContext(t)}};function si(e,t){return e===`ggml-llm`?yn(t):e===`ggml-stt`?sr(t):e===`mlx-llm`?Ur(t):null}const ci={getFullStatus:()=>lt(X),getGgmlLlmStatus:()=>ot(X),getGgmlSttStatus:()=>st(X),getMlxLlmStatus:()=>ct(X),subscribeToStatus:it,subscribeToStatusWithId:at,llmStatusTracker:B,sttStatusTracker:V,statusEmitter:z};async function li(e,t,n={}){let r={"ggml-llm":bn,"ggml-stt":cr,"mlx-llm":Gr}[e];return r?r(t,ei,n):{started:!1,localPath:null,repoId:null,error:`Unknown backend type: ${e}`}}let ui=null;const di={name:`@fugood/buttress-server`,version:`0.0.0`},fi=()=>{if(ui)return ui;try{let e=te(new URL(`../package.json`,import.meta.url)),t=JSON.parse(k.readFileSync(e,`utf8`));ui={name:t.name||di.name,version:t.version||di.version,description:t.description}}catch{ui=di}return ui},pi=!(`Bun`in globalThis),mi=e=>new n({adapter:pi?t():void 0,...e}),hi=a.Object({id:a.String(),name:a.String(),version:a.String(),generators:a.Array(a.Object({type:a.String(),score:a.Optional(a.Number()),hasGpu:a.Optional(a.Boolean()),usableBytes:a.Optional(a.Number())})),authentication:a.Object({required:a.Boolean(),type:a.String(),kid:a.Optional(a.String()),bound:a.Optional(a.Boolean())}),workspace:a.Optional(a.Object({id:a.String(),name:a.Optional(a.String())}))}),gi=({store:{serverInfo:e}})=>({id:e.id,name:e.name,version:e.version,generators:e.generators,authentication:e.authentication,workspace:e.workspace});var _i=e=>{let t=mi(),n=e.autodiscover?.http?.path??`/buttress/info`;return t.get(n,gi,{response:hi}),t};let vi=null;const yi=async e=>{if(vi&&vi.kid===e.kid)return vi.key;let t=await N(e.issuerPublicKey,`EdDSA`);return vi={kid:e.kid,key:t},t},bi=/^Bearer\s+(.+)$/i,xi=(e,t)=>{if(e){let t=e.authorization||e.Authorization;if(t){let e=t.match(bi);return e?e[1].trim():t.trim()}}if(t){let e=t.access_token??t.token;if(typeof e==`string`&&e)return e}return null},Si=async(e,t)=>{if(!e||!t)return null;try{let{payload:n}=await P(e,await yi(t),{algorithms:[`EdDSA`]}),r=n;return r.k!==`ba`||r.w_id!==t.id||r.st!==`ws`&&r.st!==`dev`||!r.sid||!r.exp?null:{workspaceId:r.w_id,subjectType:r.st,subjectId:r.sid,jti:r.jti,exp:r.exp}}catch{return null}},Ci=async({headers:e,query:t,set:n,store:r})=>{let i=r.workspaceState?.workspace;if(i&&!await Si(xi(e,t),i))return n.status=401,n.headers&&(n.headers[`WWW-Authenticate`]=`Bearer`),{error:{code:`UNAUTHORIZED`,message:`Invalid or missing workspace access token`}}},wi=e=>{if(!e)return null;let t=e[`x-buttress-sess-id`]??e[`X-BUTTRESS-SESS-ID`];return t?t.trim():null},Ti=async({headers:e,query:t,set:n,store:r})=>{let i=r.sessions,a=wi(e);if(!a||!i)return n.status=401,{error:{code:`SESSION_REQUIRED`,message:`Missing buttress session id`}};let o=i.get(a);if(!o)return n.status=401,{error:{code:`SESSION_INVALID`,message:`Unknown or expired buttress session`}};let s=r.workspaceState?.workspace;if(s&&o.identity){let r=await Si(xi(e,t),s);if(!r||r.subjectId!==o.identity.subjectId||r.subjectType!==o.identity.subjectType)return n.status=403,{error:{code:`SESSION_FORBIDDEN`,message:`Token identity mismatch for this session`}}}},Ei=(e,t)=>{let n=e.sessions,r=wi(t);if(!r||!n)return null;let i=n.get(r);return i?{sessionId:r,session:i}:null},Di=(e,t,n)=>{let r=l.join(e,t),i=l.join(r,n),a=l.relative(r,i);return{sessionDir:r,filePath:i,safe:a!==``&&!a.startsWith(`..`)&&!l.isAbsolute(a)}},Oi=typeof process<`u`&&process.versions!=null&&process.versions.node!=null;var ki=mi().onBeforeHandle(Ci).onBeforeHandle(Ti).post(`/buttress/upload`,async({body:{file:e},headers:t,store:n})=>{let r=Ei(n,t);if(!r)return{ok:!1,error:`Session guard mis-wired`};let{sessionId:i}=r,{config:a}=n,o=`${Date.now()}-${e.name.replace(/[^\dA-Za-z]/g,`_`)}`,{sessionDir:s,filePath:c,safe:l}=Di(a.server.temp_file_dir,i,o);if(!l)return{ok:!1,error:`Invalid file path`};try{return await p(s,{recursive:!0}),Oi?await b(c,await e.stream()):await b(c,await e.arrayBuffer()),{ok:!0,filename:o}}catch(e){return{ok:!1,error:String(e)}}},{body:a.Object({file:a.File()}),response:a.Object({ok:a.Boolean(),filename:a.Optional(a.String()),error:a.Optional(a.String())})}).get(`/buttress/download/:filename`,async({params:{filename:e},headers:t,store:n,status:i})=>{let a=Ei(n,t);if(!a)return i(500),`Session guard mis-wired`;let{sessionId:o}=a,{config:s}=n,{filePath:c,safe:l}=Di(s.server.temp_file_dir,o,e);return l?r(c):(i(400),`Invalid file path`)},{params:a.Object({filename:a.String()})});const Ai=l.dirname(te(import.meta.url)),ji=async()=>{let e=[l.join(Ai,`..`,`public`,`status.html`),l.join(Ai,`..`,`..`,`public`,`status.html`)];return(await Promise.all(e.map(e=>f.access(e).then(()=>e,()=>null)))).find(e=>e!==null)??null},Mi=e=>{let{status:t}=e;return t?.getFullStatus?t.getFullStatus():{timestamp:new Date().toISOString(),ggmlLlm:{generators:[],history:{}},ggmlStt:{generators:[],history:{}}}},Ni=async()=>{let e=await ji();if(!e)return console.error(`[Status] Failed to find status.html in candidate paths`),new Response(`Status page not found`,{status:404,headers:{"Content-Type":`text/plain`}});try{let t=await f.readFile(e,`utf-8`);return new Response(t,{headers:{"Content-Type":`text/html; charset=utf-8`}})}catch(e){return console.error(`[Status] Failed to serve status page:`,e),new Response(`Status page not found`,{status:404,headers:{"Content-Type":`text/plain`}})}};var Pi=mi().get(`/status`,Ni).get(`/status/`,Ni).get(`/buttress/status`,({store:{backend:e}})=>Mi(e));const Fi=[`ggml-llm`,`mlx-llm`],Q=new Map,Ii=new Map;function Li(e){e.cancel().catch(()=>{})}function Ri(e,t){Q.delete(e),Q.set(e,t)}function zi(e,t){return t.activeRequests+=1,Ri(e,t),t}async function Bi(e,t){for(;Q.size>4;){let n=Array.from(Q.entries()).find(([,e])=>e.activeRequests===0);if(!n)return;let[r,i]=n;Q.delete(r);try{await e.finalizeGenerator?.(i.id),console.log(`${t} Evicted idle generator: ${r}`)}catch(e){console.warn(`${t} Failed to evict idle generator ${r}:`,e?.message)}}}async function Vi(e,t,n=`[LLM]`){t&&(t.activeRequests=Math.max(0,t.activeRequests-1),await Bi(e,n))}function Hi(e,t){return t===`mlx-llm`?e.mlxLlm:e.ggmlLlm}async function Ui(e,t,n,r=`[LLM]`){let i=(t.generators||[]).filter(e=>Fi.includes(e.type));if(i.length===0)throw Error(`No LLM generator configured. Add a [[generators]] with type = "ggml-llm" or "mlx-llm" to your config.`);let a=i[0],o=n||a.model?.repo_id;if(n){let e=i.find(e=>e.model?.repo_id===n);e&&(a=e)}else o=a.model?.repo_id;let s=a.type||`ggml-llm`,c=o,l=Q.get(c);if(l?.initialized)return zi(c,l);let u=Ii.get(c);if(u)return zi(c,await u);let{generators:d,server:f,...p}=t.global||{},m={...p,...a,model:{...a.model,repo_id:o}};console.log(`${r} Creating ${s} generator for ${c}`);let h=(async()=>{let{id:t}=await e.startGenerator(s,m),n={id:t,type:s,config:m,repoId:o,initialized:!1,activeRequests:0};return await Hi(e,s).initContext(t,{}),n.initialized=!0,Q.set(c,n),console.log(`${r} Generator ready: ${c}`),n})().finally(()=>{Ii.delete(c)});Ii.set(c,h);let g=zi(c,await h);return await Bi(e,r),g}function Wi(e){let t=e.timings||{},n=t.prompt_n??t.promptN??0,r=t.cache_n??t.cacheN??0,i=t.predicted_n??t.predictedN??0;return{promptTokens:n||e.prompt_tokens||e.promptTokens||0,cachedTokens:r,completionTokens:i||e.tokens_evaluated||e.tokensEvaluated||e.tokens_predicted||e.tokensPredicted||0}}function Gi(e){let{promptTokens:t,cachedTokens:n,completionTokens:r}=Wi(e),i=t+n;return{prompt_tokens:i,completion_tokens:r,total_tokens:i+r}}const Ki=()=>`chatcmpl-${Date.now()}-${Math.random().toString(36).slice(2,9)}`;async function qi(e,t,n,r){let i=e.getReader(),a=``,o=null,s=null,c=`stop`,l={prompt_tokens:0,completion_tokens:0,total_tokens:0};try{let e=!1;for(;!e;){let n=await i.read();if({done:e}=n,e)break;let{event:r,data:u}=n.value;if(r===`token`)u.content!=null&&(a=u.content),u.reasoning_content!=null&&(o=u.reasoning_content);else if(r===`result`)u.content==null?u.text&&(a=u.text):a=u.content,u.reasoning_content!=null&&(o=u.reasoning_content),u.tool_calls?.length>0?(s=u.tool_calls.map((e,n)=>({id:e.id||`call_${t}_${n}`,type:`function`,function:{name:e.function?.name||``,arguments:e.function?.arguments||``}})),c=`tool_calls`):c=u.interrupted?`length`:`stop`,l=Gi(u);else if(r===`error`)throw Error(u.message)}}finally{Li(i)}let u={role:`assistant`,content:a||null};return o&&(u.reasoning_content=o),s&&(u.tool_calls=s),{id:t,object:`chat.completion`,created:n,model:r,choices:[{index:0,message:u,finish_reason:c}],usage:l}}function Ji(e,t,n,r){let i=[];return e.forEach((e,a)=>{let o={index:a};n.has(a)||(n.set(a,e.id||`call_${t}_${a}`),o.id=n.get(a),o.type=`function`);let s=e.function?.arguments||``,c=r.get(a)||``,l={};!r.has(a)&&e.function?.name&&(l.name=e.function.name),s.length>c.length&&(l.arguments=s.slice(c.length),r.set(a,s)),Object.keys(l).length>0?(o.function=l,i.push(o)):o.id&&(o.function={name:e.function?.name||``,arguments:``},i.push(o))}),i}async function*Yi(e,t,n,r,a){let o=e.getReader(),s=``,c=``,l=new Map,u=new Map;try{let e=!1;for(;!e;){let d=await o.read();if({done:e}=d,e)break;let{event:f,data:p}=d.value;if(f===`token`){let e={};if(p.content!=null){let t=p.content;t.length>s.length&&(e.content=t.slice(s.length),s=t)}if(p.reasoning_content!=null){let t=p.reasoning_content;t.length>c.length&&(e.reasoning_content=t.slice(c.length),c=t)}if(p.tool_calls?.length>0){let n=Ji(p.tool_calls,t,u,l);n.length>0&&(e.tool_calls=n)}Object.keys(e).length>0&&(yield i({data:JSON.stringify({id:t,object:`chat.completion.chunk`,created:n,model:r,choices:[{index:0,delta:e,finish_reason:null}]})}))}else if(f===`result`){if(p.tool_calls?.length>0){let e=Ji(p.tool_calls,t,u,l);e.length>0&&(yield i({data:JSON.stringify({id:t,object:`chat.completion.chunk`,created:n,model:r,choices:[{index:0,delta:{tool_calls:e},finish_reason:null}]})}))}let e=`stop`;p.tool_calls?.length>0||u.size>0?e=`tool_calls`:p.interrupted&&(e=`length`);let o={id:t,object:`chat.completion.chunk`,created:n,model:r,choices:[{index:0,delta:{},finish_reason:e}]};a&&(o.usage=Gi(p)),yield i({data:JSON.stringify(o)})}else f===`error`&&(yield i({data:JSON.stringify({error:{message:p.message,type:`server_error`}})}))}yield i({data:`[DONE]`})}finally{Li(o)}}function Xi({global:e}){let t=mi({prefix:`/oai-compat`});return t.use(ie({origin:e?.openai_compat?.cors_allowed_origins??!1,methods:[`GET`,`POST`,`OPTIONS`],allowedHeaders:[`Content-Type`,`Authorization`],maxAge:86400,preflight:!0})),t.onBeforeHandle(Ci),t.get(`/v1/models`,({store:e})=>{let{config:t}=e,n=(t.generators||[]).filter(e=>Fi.includes(e.type)).map(e=>({id:e.model?.repo_id||e.type,object:`model`,created:Math.floor(Date.now()/1e3),owned_by:`local`}));return n.length===0&&n.push({id:`ggml-llm`,object:`model`,created:Math.floor(Date.now()/1e3),owned_by:`local`}),{object:`list`,data:n}}),t.post(`/v1/chat/completions`,async function*({body:e,set:t,store:n}){let{config:r,backend:i}=n,{messages:a=[],stream:o=!1,model:s,tools:c,temperature:l,stop:u,top_p:d,max_tokens:f,presence_penalty:p,frequency_penalty:m,tool_choice:h,stream_options:g,enable_thinking:_}=e;if(!a||a.length===0)return t.status=400,{error:{message:`messages is required and must not be empty`,type:`invalid_request_error`}};let v=null;try{v=await Ui(i,r,s,`[OpenAI]`);let e=Ki(),t=Math.floor(Date.now()/1e3),n=v.repoId||`ggml-llm`,y={reasoning_format:`auto`,messages:a,jinja:!0,add_generation_prompt:!0};l!=null&&(y.temperature=l),d!=null&&(y.top_p=d),f!=null&&(y.n_predict=f),u!=null&&(y.stop=Array.isArray(u)?u:[u]),p!=null&&(y.presence_penalty=p),m!=null&&(y.frequency_penalty=m),c!=null&&(y.tools=c),h!=null&&(y.tool_choice=h),y.enable_thinking=_??!1;let b=await Hi(i,v.type).completion(v.id,{options:y});if(!o)return await qi(b,e,t,n);yield*Yi(b,e,t,n,g?.include_usage===!0)}catch(e){return console.error(`[OpenAI] Chat completion error:`,e),t.status=500,{error:{message:e.message||`Internal server error`,type:`server_error`}}}finally{await Vi(i,v,`[OpenAI]`)}},{body:a.Object({model:a.Optional(a.String()),messages:a.Array(a.Any()),stream:a.Optional(a.Boolean()),temperature:a.Optional(a.Number()),top_p:a.Optional(a.Number()),max_tokens:a.Optional(a.Number()),stop:a.Optional(a.Union([a.String(),a.Array(a.String())])),presence_penalty:a.Optional(a.Number()),frequency_penalty:a.Optional(a.Number()),tools:a.Optional(a.Array(a.Any())),tool_choice:a.Optional(a.Any()),stream_options:a.Optional(a.Object({include_usage:a.Optional(a.Boolean())})),enable_thinking:a.Optional(a.Boolean())})}),t}const Zi=()=>`msg_${Date.now()}${Math.random().toString(36).slice(2,11)}`;function Qi(e){let t={},n=[];if(e.system!=null){let t=``;if(typeof e.system==`string`)t=e.system;else if(Array.isArray(e.system))for(let n of e.system)n?.type===`text`&&typeof n.text==`string`&&(t+=n.text);t&&n.push({role:`system`,content:t})}if(!Array.isArray(e.messages))throw Error(`'messages' is required and must be an array`);for(let t of e.messages){let e=t?.role||`user`;if(t?.content==null){if(e===`assistant`)continue;n.push(t);continue}if(typeof t.content==`string`){n.push({role:e,content:t.content});continue}if(!Array.isArray(t.content)){n.push(t);continue}let r=[],i=[],a=[],o=``,s=!1;for(let e of t.content){let t=e?.type||``;if(t===`text`)i.push({type:`text`,text:e.text||``});else if(t===`thinking`)o+=e.thinking||``;else if(t===`image`){let t=e.source||{};if(t.type===`base64`){let e=t.media_type||`image/jpeg`,n=t.data||``;i.push({type:`image_url`,image_url:{url:`data:${e};base64,${n}`}})}else t.type===`url`&&i.push({type:`image_url`,image_url:{url:t.url||``}})}else if(t===`tool_use`)r.push({id:e.id||``,type:`function`,function:{name:e.name||``,arguments:JSON.stringify(e.input??{})}}),s=!0;else if(t===`tool_result`){let t=e.tool_use_id||``,n=``,r=e.content;if(typeof r==`string`)n=r;else if(Array.isArray(r))for(let e of r)e?.type===`text`&&(n+=e.text||``);a.push({role:`tool`,tool_call_id:t,content:n})}}if(i.length>0||s||o){let t={role:e};i.length>0?t.content=i:(s||o)&&(t.content=``),r.length>0&&(t.tool_calls=r),o&&(t.reasoning_content=o),n.push(t)}for(let e of a)n.push(e)}if(t.messages=n,Array.isArray(e.tools)&&(t.tools=e.tools.map(e=>({type:`function`,function:{name:e.name||``,description:e.description||``,parameters:e.input_schema||{}}}))),e.tool_choice&&typeof e.tool_choice==`object`){let n=e.tool_choice.type;n===`auto`?t.tool_choice=`auto`:n===`any`||n===`tool`?t.tool_choice=`required`:n===`none`&&(t.tool_choice=`none`)}else Array.isArray(t.tools)&&t.tools.length>0&&(t.tool_choice=`auto`);e.stop_sequences!=null&&(t.stop=Array.isArray(e.stop_sequences)?e.stop_sequences:[e.stop_sequences]),t.max_tokens=e.max_tokens??4096;for(let n of[`temperature`,`top_p`,`top_k`,`stream`])e[n]!=null&&(t[n]=e[n]);return e.thinking&&typeof e.thinking==`object`&&e.thinking.type===`enabled`&&(t.enable_thinking=!0,e.thinking.budget_tokens!=null&&(t.thinking_budget_tokens=e.thinking.budget_tokens)),t}function $i(e,t){return t?`tool_use`:e.stopping_word||e.stoppingWord?`stop_sequence`:e.interrupted||e.truncated?`max_tokens`:`end_turn`}function ea(e){let{promptTokens:t,cachedTokens:n,completionTokens:r}=Wi(e);return{cache_read_input_tokens:n,input_tokens:t,output_tokens:r}}async function ta(e,t,n){let r=e.getReader(),i=``,a=``,o=[],s={cache_read_input_tokens:0,input_tokens:0,output_tokens:0},c=`end_turn`,l=null;try{let e=!1;for(;!e;){let t=await r.read();if({done:e}=t,e)break;let{event:n,data:u}=t.value;if(n===`token`)u.content!=null&&(i=u.content),u.reasoning_content!=null&&(a=u.reasoning_content);else if(n===`result`)u.content==null?u.text&&u.reasoning_content==null&&(i=u.text):i=u.content,u.reasoning_content!=null&&(a=u.reasoning_content),Array.isArray(u.tool_calls)&&(o=u.tool_calls),s=ea(u),l=u.stopping_word||u.stoppingWord||null,c=$i(u,o.length>0);else if(n===`error`)throw Error(u.message||`completion error`)}}finally{Li(r)}let u=[];a&&u.push({type:`thinking`,thinking:a,signature:``}),i&&u.push({type:`text`,text:i});for(let e of o){let t={};try{t=JSON.parse(e.function?.arguments||`{}`)}catch{t={}}u.push({type:`tool_use`,id:e.id||`toolu_${Math.random().toString(36).slice(2,11)}`,name:e.function?.name||``,input:t})}return{id:t,type:`message`,role:`assistant`,content:u,model:n,stop_reason:c,stop_sequence:l,usage:s}}async function*na(e,t,n){let r=e.getReader(),a=``,o=``,s=new Map,c=new Map,l=new Map,u=new Set,d=!1,f=!1,p=0,m={cache_read_input_tokens:0,input_tokens:0,output_tokens:0},h=`end_turn`,g=null,_=!1,v=e=>(d?1:0)+(f?1:0)+e;function*y(e){for(let n=0;n<e.length;n+=1){let r=e[n],a=v(n),o=r?.function?.arguments||``,d=s.get(n)||``;if(!u.has(n)){let e=r?.id||`toolu_${t}_${n}`,o=r?.function?.name||l.get(n)||``;c.set(n,e),l.set(n,o),u.add(n),yield i({event:`content_block_start`,data:JSON.stringify({type:`content_block_start`,index:a,content_block:{type:`tool_use`,id:e,name:o,input:{}}})})}o.length>d.length&&(yield i({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:a,delta:{type:`input_json_delta`,partial_json:o.slice(d.length)}})}),s.set(n,o))}}try{let e=!1;for(;!e;){let s=await r.read();if({done:e}=s,e)break;let{event:c,data:l}=s.value;if(c===`token`){if(!_){let e=ea(l);yield i({event:`message_start`,data:JSON.stringify({type:`message_start`,message:{id:t,type:`message`,role:`assistant`,content:[],model:n,stop_reason:null,stop_sequence:null,usage:e}})}),_=!0}if(l.reasoning_content!=null){let e=l.reasoning_content;e.length>o.length&&(d||(yield i({event:`content_block_start`,data:JSON.stringify({type:`content_block_start`,index:0,content_block:{type:`thinking`,thinking:``}})}),d=!0,p=1),yield i({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:0,delta:{type:`thinking_delta`,thinking:e.slice(o.length)}})}),o=e)}if(l.content!=null){let e=l.content;e.length>a.length&&(f||=(yield i({event:`content_block_start`,data:JSON.stringify({type:`content_block_start`,index:p,content_block:{type:`text`,text:``}})}),!0),yield i({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:p,delta:{type:`text_delta`,text:e.slice(a.length)}})}),a=e)}Array.isArray(l.tool_calls)&&l.tool_calls.length>0&&(yield*y(l.tool_calls))}else if(c===`result`){if(!_){let e=ea(l);yield i({event:`message_start`,data:JSON.stringify({type:`message_start`,message:{id:t,type:`message`,role:`assistant`,content:[],model:n,stop_reason:null,stop_sequence:null,usage:e}})}),_=!0}Array.isArray(l.tool_calls)&&l.tool_calls.length>0&&(yield*y(l.tool_calls)),m=ea(l),g=l.stopping_word||l.stoppingWord||null,h=$i(l,u.size>0)}else if(c===`error`){yield i({event:`error`,data:JSON.stringify({type:`error`,error:{type:`api_error`,message:l.message||`completion error`}})});return}}d&&(yield i({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:0,delta:{type:`signature_delta`,signature:``}})}),yield i({event:`content_block_stop`,data:JSON.stringify({type:`content_block_stop`,index:0})})),f&&(yield i({event:`content_block_stop`,data:JSON.stringify({type:`content_block_stop`,index:p})}));for(let e of[...u].sort((e,t)=>e-t))yield i({event:`content_block_stop`,data:JSON.stringify({type:`content_block_stop`,index:v(e)})});yield i({event:`message_delta`,data:JSON.stringify({type:`message_delta`,delta:{stop_reason:h,stop_sequence:g},usage:{output_tokens:m.output_tokens}})}),yield i({event:`message_stop`,data:JSON.stringify({type:`message_stop`})})}finally{Li(r)}}function ra({global:e}){let t=mi({prefix:`/anthropic-messages`});return t.use(ie({origin:e?.anthropic_messages?.cors_allowed_origins??!1,methods:[`GET`,`POST`,`OPTIONS`],allowedHeaders:[`Content-Type`,`Authorization`,`x-api-key`,`anthropic-version`],maxAge:86400,preflight:!0})),t.onBeforeHandle(Ci),t.post(`/v1/messages`,async function*({body:e,set:t,store:n}){let{config:r,backend:i}=n,a=e,o=null;try{if(!Array.isArray(a.messages)||a.messages.length===0)return t.status=400,{type:`error`,error:{type:`invalid_request_error`,message:`messages is required and must not be empty`}};let e=Qi(a);o=await Ui(i,r,a.model,`[Anthropic]`);let n=Zi(),s=o.repoId||`ggml-llm`,c={reasoning_format:`auto`,messages:e.messages,jinja:!0,add_generation_prompt:!0};e.temperature!=null&&(c.temperature=e.temperature),e.top_p!=null&&(c.top_p=e.top_p),e.top_k!=null&&(c.top_k=e.top_k),e.max_tokens!=null&&(c.n_predict=e.max_tokens),e.stop!=null&&(c.stop=e.stop),e.tools!=null&&(c.tools=e.tools),e.tool_choice!=null&&(c.tool_choice=e.tool_choice),c.enable_thinking=e.enable_thinking??!1,e.thinking_budget_tokens!=null&&(c.thinking_budget_tokens=e.thinking_budget_tokens);let l=await Hi(i,o.type).completion(o.id,{options:c});if(!a.stream)return await ta(l,n,s);yield*na(l,n,s)}catch(e){return console.error(`[Anthropic] Messages error:`,e),t.status=500,{type:`error`,error:{type:`api_error`,message:e?.message||`Internal server error`}}}finally{await Vi(i,o,`[Anthropic]`)}},{body:a.Object({model:a.Optional(a.String()),messages:a.Array(a.Any()),system:a.Optional(a.Any()),max_tokens:a.Optional(a.Number()),stream:a.Optional(a.Boolean()),temperature:a.Optional(a.Number()),top_p:a.Optional(a.Number()),top_k:a.Optional(a.Number()),stop_sequences:a.Optional(a.Union([a.String(),a.Array(a.String())])),tools:a.Optional(a.Array(a.Any())),tool_choice:a.Optional(a.Any()),thinking:a.Optional(a.Any()),metadata:a.Optional(a.Any())})}),t.post(`/v1/messages/count_tokens`,async({body:e,set:t,store:n})=>{let{config:r,backend:i}=n,a=e,o=null;try{let e=Qi(a);o=await Ui(i,r,a.model,`[Anthropic]`);let t=Hi(i,o.type),n={messages:e.messages,add_generation_prompt:!0,jinja:!0};e.tools!=null&&(n.tools=e.tools);let s=await t.applyChatTemplate(o.id,n),c=typeof s==`string`?s:s?.prompt||``,l=await t.tokenize(o.id,{text:c,add_special:!0,parse_special:!0});return{input_tokens:(Array.isArray(l)?l:l?.tokens||[]).length}}catch(e){return console.error(`[Anthropic] count_tokens error:`,e),t.status=500,{type:`error`,error:{type:`api_error`,message:e?.message||`Internal server error`}}}finally{await Vi(i,o,`[Anthropic]`)}},{body:a.Object({model:a.Optional(a.String()),messages:a.Array(a.Any()),system:a.Optional(a.Any()),tools:a.Optional(a.Array(a.Any())),tool_choice:a.Optional(a.Any())})}),t.get(`/v1/models`,({store:e})=>{let{config:t}=e,n=(t.generators||[]).filter(e=>Fi.includes(e.type)).map(e=>{let t=e.model?.repo_id||e.type;return{id:t,type:`model`,display_name:t,created_at:new Date().toISOString()}});return n.length===0&&n.push({id:`ggml-llm`,type:`model`,display_name:`ggml-llm`,created_at:new Date().toISOString()}),{data:n,has_more:!1,first_id:n[0]?.id,last_id:n.at(-1)?.id}}),t}const ia=(e={},t={})=>{let n=Array.isArray(e)?[...e]:{...e};return Object.entries(t||{}).forEach(([e,t])=>{t&&typeof t==`object`&&!Array.isArray(t)?n[e]=ia(n[e]||{},t):n[e]=t}),n},aa=e=>e&&typeof e==`object`?structuredClone(e):null,oa=(e,t)=>ia(aa(e)||{},aa(t)||{}),sa=(e,t)=>ia(structuredClone(e.global),t||{}),ca=(e,t,n,r)=>{if(e.generators.length>0){let i=e.generators.filter(e=>e?.type===n);if(i.length>0&&r){let a=i.find(e=>t.getModelIdentifier(n,e)===r);if(a)return sa(e,a)}}return Object.keys(e.global).length>0?sa(e,{}):null},la={udp:{port:8089,announcements:{enabled:!0,interval:5e3},requests:{enabled:!0,responseDelay:100}},http:{enabled:!0,path:`/buttress/info`,cors:!0}},ua=e=>e?e===!0?{...la}:ia(la,e):null,da=(e,t)=>{if(!e.generators||e.generators.length===0)return t.map(e=>({type:e}));let n=new Set;return e.generators.forEach(e=>{e.type&&n.add(e.type)}),n.size===0?t.map(e=>({type:e})):Array.from(n).map(e=>({type:e}))},fa=(e,t,n)=>e===void 0?n:typeof e==`number`?e:t(e)??n,pa=6e4,ma=1024*1024*50,ha=e=>{let t=ae.machineIdSync(),n=ia({server:{id:`buttress-${t}`,name:`Buttress Server (${t.slice(-8)})`,port:2080,temp_file_dir:l.join(x.tmpdir(),`.buttress`),session_timeout:pa,max_body_size:ma},autodiscover:!1},aa(e)||{}),r=Array.isArray(n.generators)?n.generators:[],{server:i,generators:a,autodiscover:o,...s}=n;return{autodiscover:ua(o),server:{id:i.id,name:i.name,port:i.port,log_level:i.log_level,temp_file_dir:i.temp_file_dir,max_body_size:fa(i.max_body_size,E.parse,ma),session_timeout:fa(i.session_timeout,F,pa)},global:s,generators:r}},ga={getCapabilities:M.tuple([M.object({type:M.string().optional().default(`ggml-llm`),config:M.any().optional(),currentClientCapabilities:M.any().optional(),options:M.any().optional()}).nullable().optional()]),startGenerator:M.tuple([M.string(),M.any().optional()]),finalizeGenerator:M.tuple([M.string()])};var _a={async getCapabilities({backend:e,config:t},n=null){console.log(`[Server] Get Capabilities:`,n);let{type:r=`ggml-llm`,config:i,currentClientCapabilities:a=null,options:o={}}=n||{type:`ggml-llm`},s=aa(i),c=oa(ca(t,e,r,e.getModelIdentifier(r,s)),i);if(Object.keys(c).length===0)throw Error(`Buttress server missing generator configuration`);return c.backend=c.backend||{},c.backend.type||(c.backend.type=r),e.getCapabilities(r,a,{...o,config:c})},async startGenerator({backend:e,config:t,session:n},r,i){console.log(`[Server] Start Generator:`,r,i);let a=aa(i),o=oa(ca(t,e,r,e.getModelIdentifier(r,a)),i);if(Object.keys(o).length===0)throw Error(`Buttress server missing generator configuration`);o.backend=o.backend||{},o.backend.type||(o.backend.type=r);let s=await e.startGenerator(r,o);return n.generators.add(s.id),s},async finalizeGenerator({backend:e,session:t},n){return console.log(`[Server] Finalize Generator:`,n),t.generators.delete(n),e.finalizeGenerator(n)}};const va={initContext:M.tuple([M.string(),M.any().optional()]),completion:M.tuple([M.string(),M.any().optional()]),tokenize:M.tuple([M.string(),M.any()]),detokenize:M.tuple([M.string(),M.any()]),applyChatTemplate:M.tuple([M.string(),M.any()]),releaseContext:M.tuple([M.string()])};function ya(e){return function({backend:t,session:n},r,i){return new d({async start(a){try{let o=await e(t).initContext(r,{...i,onProgress:e=>{a.enqueue({event:`progress`,data:{progress:e}})}});n.initializedContexts.add(r),await new Promise(e=>setTimeout(e,1e3));let{download:s,...c}=o||{};a.enqueue({event:`result`,data:{result:c}}),a.close()}catch(e){a.error(e)}}})}}function ba(e,t){return async function({backend:n,session:r},i,a){return console.log(`[Server] ${t}:`,{id:i,force:a}),r.initializedContexts.has(i)?(r.initializedContexts.delete(i),e(n).releaseContext(i,{force:a})):(console.log(`[Server] ${t} skipped - not initialized by this session:`,{id:i}),{released:!1,skipped:!0})}}function xa(e,t){return{initContext:ya(e),completion({backend:n},r,i){return console.log(`[Server] ${t}Completion:`,{id:r,property:i}),e(n).completion(r,i)},async tokenize({backend:n},r,i){return console.log(`[Server] ${t}Tokenize:`,{id:r,property:i}),e(n).tokenize(r,i)},async detokenize({backend:n},r,i){return console.log(`[Server] ${t}Detokenize:`,{id:r,property:i}),e(n).detokenize(r,i)},async applyChatTemplate({backend:n},r,i){return console.log(`[Server] ${t}Apply Chat Template:`,{id:r,property:i}),e(n).applyChatTemplate(r,i)},releaseContext:ba(e,`${t}Release Context`)}}var Sa=xa(e=>e.ggmlLlm,``);const Ca={initContext:M.tuple([M.string(),M.any().optional()]),transcribe:M.tuple([M.string(),M.string(),M.any().optional()]),transcribeData:M.tuple([M.string(),M.union([M.instanceof(Buffer),M.instanceof(Uint8Array)]),M.any().optional()]),releaseContext:M.tuple([M.string()])},wa=e=>e.ggmlStt,Ta={common:_a,ggmlLlm:Sa,ggmlStt:{initContext:ya(wa),async transcribe({backend:e,config:{server:t},peerId:n},r,i,a){console.log(`[Server] Transcribe:`,{id:r,audioPath:i,options:a});let{filePath:o,safe:s}=Di(t.temp_file_dir,n,i);if(!s)throw Error(`Invalid audioPath`);return e.ggmlStt.transcribe(r,{audioPath:o,options:a})},async transcribeData({backend:e},t,n,r){return console.log(`[Server] Transcribe Data:`,{id:t,audioDataLength:n?.length||0,options:r}),e.ggmlStt.transcribeData(t,{audioData:n,options:r})},releaseContext:ba(wa,`Release STT Context`)},mlxLlm:xa(e=>e.mlxLlm,`MLX `)},Ea={common:ga,ggmlLlm:va,ggmlStt:Ca,mlxLlm:va};var Da=Ta;const Oa=e=>{try{return JSON.parse(e,(e,t)=>t&&(t?.type===`Buffer`&&t?.data||t?.type===`Uint8Array`&&t?.data?I.from(t.data,`base64`):t?.type===`Error`&&t?.name&&t?.message?Error(t.name,t.message):t))}catch{return e}},ka=e=>{try{return JSON.stringify(e,(e,t)=>t instanceof Error?{type:`Error`,name:t.name,message:t.message}:t instanceof I?{type:`Buffer`,data:t.toString(`base64`)}:t instanceof Uint8Array?{type:`Uint8Array`,data:I.from(t).toString(`base64`)}:t)}catch{return e}},Aa={score:0,hasGpu:!1,usableBytes:0},ja=e=>e?{score:Number(e.score)||0,hasGpu:!!e.hasGpu,usableBytes:Number(e.gpuUsableBytes||e.cpuUsableBytes||0)}:Aa,Ma=async e=>{let t=[];for(let n of e){let e=Aa;try{e=ja((await K(n.type,null,{}))?.buttress?.selected)}catch(e){console.warn(`[Caps] Failed to detect capabilities for "${n.type}":`,e instanceof Error?e.message:e)}t.push({...n,...e})}return t},Na=()=>{let e=x.networkInterfaces();return Object.values(e).flat().find(e=>e?.family===`IPv4`&&!e?.internal)?.address||null},Pa=e=>{let t=e.split(`.`).map(Number);return t.length!==4||t.some(e=>Number.isNaN(e))?0:(t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0},Fa=e=>[e>>>24&255,e>>>16&255,e>>>8&255,e&255].join(`.`),Ia=()=>{let e=[],t=new Set;for(let n of Object.values(x.networkInterfaces()))for(let r of n??[]){if(r.family!==`IPv4`||r.internal||!r.address||!r.netmask)continue;let n=Pa(r.address),i=Pa(r.netmask);if(!n||!i||i===4294967295)continue;let a=Fa((n&i|~i>>>0)>>>0);if(a===r.address)continue;let o=`${r.address}->${a}`;t.has(o)||(t.add(o),e.push({address:r.address,broadcast:a}))}return e},La=e=>{if(!e)return!1;let t=e;return t.code===`ENOTSUP`||/Failed to bind socket/i.test(t.message??``)};var Ra=class e{name=`udp`;receiver=null;senders=[];announcementTimer=null;config;getServerInfo;port;signer;constructor(e,t,n){this.config=e,this.getServerInfo=t,this.port=e.port??8089,this.signer=n}async start(){this.receiver=await this.bindReceiver(!0).catch(e=>{if(!La(e))throw e;return console.warn(`[Autodiscover UDP] SO_REUSEPORT not supported by this runtime; falling back to REUSEADDR only (multiple buttress instances on one host will not coexist on the discovery port).`),this.bindReceiver(!1)}),this.receiver.on(`message`,(e,t)=>{this.handleMessage(e,t)}),this.receiver.on(`error`,e=>{console.error(`[Autodiscover UDP] Receiver error:`,e.message)}),this.receiver.setBroadcast(!0),this.senders=await this.createSenders();let e=this.senders.map(e=>`${e.address}->${e.broadcast}`).join(`, `)||`<none>`;if(console.log(`[Autodiscover UDP] Listening on port ${this.port}; announce interfaces: ${e}`),this.config.announcements.enabled){let e=this.config.announcements.interval??5e3;this.announcementTimer=setInterval(()=>{this.sendAnnouncement()},e),this.sendAnnouncement()}}async stop(){this.announcementTimer&&=(clearInterval(this.announcementTimer),null),await Promise.all(this.senders.map(({socket:e})=>new Promise(t=>{e.close(()=>t())}))),this.senders=[],this.receiver&&=(await new Promise(e=>{this.receiver.close(()=>e())}),null)}async bindReceiver(e){let t=oe.createSocket(e?{type:`udp4`,reuseAddr:!0,reusePort:!0}:{type:`udp4`,reuseAddr:!0});return new Promise((e,n)=>{let r=e=>{t.close(),n(e)};t.once(`error`,r),t.bind(this.port,()=>{t.off(`error`,r),e(t)})})}async createSenders(){let e=Ia();return(await Promise.all(e.map(async e=>{try{let t=oe.createSocket({type:`udp4`});return await new Promise((n,r)=>{let i=e=>{t.close(),r(e)};t.once(`error`,i),t.bind({port:0,address:e.address},()=>{t.off(`error`,i),t.setBroadcast(!0),n()})}),t.on(`error`,t=>{console.error(`[Autodiscover UDP] Sender ${e.address} error:`,t.message)}),{...e,socket:t}}catch(t){return console.warn(`[Autodiscover UDP] Failed to bind sender on ${e.address}:`,t.message),null}}))).filter(e=>e!==null)}handleMessage(e,t){try{let n=JSON.parse(e.toString());if(n.t===`QUERY`&&this.config.requests.enabled){let e=n.d,r=this.config.requests.responseDelay??0,i=r>0?Math.random()*r:0;setTimeout(()=>{this.sendResponse(e.id,t)},i)}}catch{}}static canonicalBytes(e,t,n){return Buffer.from(JSON.stringify({t:e,d:t,ts:n}),`utf8`)}signEnvelope(t,n){if(!this.signer)return null;let r=Math.floor(Date.now()/1e3),i=o.sign(null,e.canonicalBytes(t,n,r),this.signer.privateKey).toString(`base64`);return{t,v:`2.0`,d:n,ts:r,kid:this.signer.kid,sig:i}}sendAnnouncement(){if(this.senders.length===0)return;let e=this.getServerInfo(),t=this.signEnvelope(`ANNOUNCE`,{info:e});if(!t){console.warn("[Autodiscover UDP] no per-server keypair; skipping announcement. Run `bricks buttress bind` to register a key.");return}let n=Buffer.from(JSON.stringify(t));for(let{broadcast:e,socket:t,address:r}of this.senders)t.send(n,0,n.length,this.port,e,t=>{t&&console.error(`[Autodiscover UDP] Announcement ${r}->${e} error:`,t.message)})}sendResponse(e,t){if(!this.receiver)return;let n=this.getServerInfo(),r=this.signEnvelope(`RESPONSE`,{request_id:e,info:n});if(!r)return;let i=Buffer.from(JSON.stringify(r));this.receiver.send(i,0,i.length,t.port,t.address,e=>{e&&console.error(`[Autodiscover UDP] Response error:`,e.message)})}},za=class{transports=[];started=!1;constructor(e,t,n){this.config=e,this.getServerInfo=t,this.signer=n,(e.udp?.announcements?.enabled||e.udp?.requests?.enabled)&&this.transports.push(new Ra(e.udp,t,n))}async start(){this.started||=((await Promise.allSettled(this.transports.map(e=>e.start()))).forEach((e,t)=>{e.status===`rejected`&&console.error(`[Autodiscover] Failed to start ${this.transports[t].name}:`,e.reason)}),!0)}async stop(){this.started&&=(await Promise.allSettled(this.transports.map(e=>e.stop())),!1)}};const Ba=()=>process.env.BRICKS_BUTTRESS_STATE_DIR||l.join(x.homedir(),`.bricks-cli`,`buttress`),Va=()=>l.join(Ba(),`state.json`),Ha=e=>{if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.id==`string`&&typeof t.serverId==`string`&&typeof t.issuerPublicKey==`string`&&typeof t.kid==`string`},Ua=e=>{if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.publicKeySpki==`string`&&typeof t.privateKeyPkcs8==`string`&&typeof t.kid==`string`},Wa=()=>{let e=Va();try{let t=k.readFileSync(e,`utf8`),n=JSON.parse(t);return{workspace:Ha(n?.workspace)?n.workspace:null,serverKeyPair:Ua(n?.serverKeyPair)?n.serverKeyPair:null}}catch(e){return e.code!==`ENOENT`&&console.warn(`[Buttress] Failed to read workspace state:`,e.message),{workspace:null,serverKeyPair:null}}},$=fi(),Ga=e=>{if(!e)return{repoId:null,filename:null};let[t,n]=e.split(`:`);return{repoId:t,filename:n||null}};async function Ka({modelIds:e=[],defaultConfig:t=null}={}){let n=[];console.log(`${$.name} v${$.version}`),console.log(`Generating model capabilities comparison...
36
+ === Full Capabilities JSON ===`),console.log(JSON.stringify(s,null,2)),process.exit(0)}catch(e){console.error(`Failed to get capabilities:`,e.message),process.exit(1)}}var $r=e({createTestCapsDefaultConfigResolver:()=>q,finalizeGenerator:()=>ri,generatorRegistry:()=>X,getCapabilities:()=>K,getModelIdentifier:()=>si,ggmlLlm:()=>ii,ggmlStt:()=>oi,globalDownloadManager:()=>ei,mlxLlm:()=>ai,showModelsTable:()=>Yr,showSttModelsTable:()=>Zr,startGenerator:()=>ni,startModelDownload:()=>li,status:()=>ci,testGgmlLlmCapabilities:()=>Xr,testGgmlSttCapabilities:()=>Qr});const X=new Map,ei={downloads:new Map,getDownload(e){return this.downloads.get(e)||null},setDownload(e,t){this.downloads.set(e,t)},deleteDownload(e){this.downloads.delete(e)},isDownloading(e){return this.downloads.has(e)},getActiveDownloads(){return Array.from(this.downloads.entries()).map(([e,t])=>({localPath:e,promise:t}))}},ti=e=>{let t=X.get(e);if(!t)throw Error(`Unknown generator id "${e}"`);return t},Z=(e,t)=>{let n=ti(e);if(n.type!==t)throw Error(`Generator "${e}" does not support ${t} backend`);return n.instance};async function ni(e,t){let n={"ggml-llm":{create:vn,getId:yn},"ggml-stt":{create:or,getId:sr},"mlx-llm":{create:Hr,getId:Ur}}[e];if(!n)throw Error(`Unsupported backend type: ${e}`);let r=n.getId(t);if(!r)throw Error(`Buttress generator config missing repo identifier`);let i=`${e}:${r}`,a=X.get(i);if(a)return a.refCount+=1,a.instance.resetFinalized?.(),{id:a.id,info:a.instance.info};let o=await n.create(i,t,{globalDownloadManager:ei}),s={id:i,type:o.type,instance:o,refCount:1};return X.set(i,s),{id:i,info:o.info}}async function ri(e){let t=X.get(e);return t?(--t.refCount,t.refCount<=0&&(await t.instance.finalize(),(t.instance.hasPendingReleases?.()??!1)||X.delete(e)),!0):!1}const ii={async initContext(e,t){return Z(e,`ggml-llm`).initContext(t)},async completion(e,t){return Z(e,`ggml-llm`).completion(t)},async tokenize(e,t){return Z(e,`ggml-llm`).tokenize(t)},async detokenize(e,t){return Z(e,`ggml-llm`).detokenize(t)},async applyChatTemplate(e,t){return Z(e,`ggml-llm`).applyChatTemplate(t)},async releaseContext(e,t){let n=X.get(e);if(!n)return{released:!0,alreadyReleased:!0};if(n.type!==`ggml-llm`)throw Error(`Generator "${e}" does not support ggml-llm backend`);return n.instance.releaseContext(t)}},ai={async initContext(e,t){return Z(e,`mlx-llm`).initContext(t)},async completion(e,t){return Z(e,`mlx-llm`).completion(t)},async tokenize(e,t){return Z(e,`mlx-llm`).tokenize(t)},async detokenize(e,t){return Z(e,`mlx-llm`).detokenize(t)},async applyChatTemplate(e,t){return Z(e,`mlx-llm`).applyChatTemplate(t)},async releaseContext(e,t){let n=X.get(e);if(!n)return{released:!0,alreadyReleased:!0};if(n.type!==`mlx-llm`)throw Error(`Generator "${e}" does not support mlx-llm backend`);return n.instance.releaseContext(t)}},oi={async initContext(e,t){return Z(e,`ggml-stt`).initContext(t)},async transcribe(e,t){return Z(e,`ggml-stt`).transcribe(t)},async transcribeData(e,t){return Z(e,`ggml-stt`).transcribeData(t)},async releaseContext(e,t){let n=X.get(e);if(!n)return{released:!0,alreadyReleased:!0};if(n.type!==`ggml-stt`)throw Error(`Generator "${e}" does not support ggml-stt backend`);return n.instance.releaseContext(t)}};function si(e,t){return e===`ggml-llm`?yn(t):e===`ggml-stt`?sr(t):e===`mlx-llm`?Ur(t):null}const ci={getFullStatus:()=>lt(X),getGgmlLlmStatus:()=>ot(X),getGgmlSttStatus:()=>st(X),getMlxLlmStatus:()=>ct(X),subscribeToStatus:it,subscribeToStatusWithId:at,llmStatusTracker:B,sttStatusTracker:V,statusEmitter:z};async function li(e,t,n={}){let r={"ggml-llm":bn,"ggml-stt":cr,"mlx-llm":Gr}[e];return r?r(t,ei,n):{started:!1,localPath:null,repoId:null,error:`Unknown backend type: ${e}`}}let ui=null;const di={name:`@fugood/buttress-server`,version:`0.0.0`},fi=()=>{if(ui)return ui;try{let e=te(new URL(`../package.json`,import.meta.url)),t=JSON.parse(k.readFileSync(e,`utf8`));ui={name:t.name||di.name,version:t.version||di.version,description:t.description}}catch{ui=di}return ui},pi=!(`Bun`in globalThis),mi=e=>new n({adapter:pi?t():void 0,...e}),hi=a.Object({id:a.String(),name:a.String(),version:a.String(),generators:a.Array(a.Object({type:a.String(),score:a.Optional(a.Number()),hasGpu:a.Optional(a.Boolean()),usableBytes:a.Optional(a.Number())})),authentication:a.Object({required:a.Boolean(),type:a.String(),kid:a.Optional(a.String()),bound:a.Optional(a.Boolean())}),workspace:a.Optional(a.Object({id:a.String(),name:a.Optional(a.String())}))}),gi=({store:{serverInfo:e}})=>({id:e.id,name:e.name,version:e.version,generators:e.generators,authentication:e.authentication,workspace:e.workspace});var _i=e=>{let t=mi(),n=e.autodiscover?.http?.path??`/buttress/info`;return t.get(n,gi,{response:hi}),t};let vi=null;const yi=async e=>{if(vi&&vi.kid===e.kid)return vi.key;let t=await N(e.issuerPublicKey,`EdDSA`);return vi={kid:e.kid,key:t},t},bi=/^Bearer\s+(.+)$/i,xi=(e,t)=>{if(e){let t=e.authorization||e.Authorization;if(t){let e=t.match(bi);return e?e[1].trim():t.trim()}}if(t){let e=t.access_token??t.token;if(typeof e==`string`&&e)return e}return null},Si=async(e,t)=>{if(!e||!t)return null;try{let{payload:n}=await P(e,await yi(t),{algorithms:[`EdDSA`]}),r=n;return r.k!==`ba`||r.w_id!==t.id||r.st!==`ws`&&r.st!==`dev`||!r.sid||!r.exp?null:{workspaceId:r.w_id,subjectType:r.st,subjectId:r.sid,jti:r.jti,exp:r.exp}}catch{return null}},Ci=async({headers:e,query:t,set:n,store:r})=>{let i=r.workspaceState?.workspace;if(i&&!await Si(xi(e,t),i))return n.status=401,n.headers&&(n.headers[`WWW-Authenticate`]=`Bearer`),{error:{code:`UNAUTHORIZED`,message:`Invalid or missing workspace access token`}}},wi=e=>{if(!e)return null;let t=e[`x-buttress-sess-id`]??e[`X-BUTTRESS-SESS-ID`];return t?t.trim():null},Ti=async({headers:e,query:t,set:n,store:r})=>{let i=r.sessions,a=wi(e);if(!a||!i)return n.status=401,{error:{code:`SESSION_REQUIRED`,message:`Missing buttress session id`}};let o=i.get(a);if(!o)return n.status=401,{error:{code:`SESSION_INVALID`,message:`Unknown or expired buttress session`}};let s=r.workspaceState?.workspace;if(s&&o.identity){let r=await Si(xi(e,t),s);if(!r||r.subjectId!==o.identity.subjectId||r.subjectType!==o.identity.subjectType)return n.status=403,{error:{code:`SESSION_FORBIDDEN`,message:`Token identity mismatch for this session`}}}},Ei=(e,t)=>{let n=e.sessions,r=wi(t);if(!r||!n)return null;let i=n.get(r);return i?{sessionId:r,session:i}:null},Di=(e,t,n)=>{let r=l.join(e,t),i=l.join(r,n),a=l.relative(r,i);return{sessionDir:r,filePath:i,safe:a!==``&&!a.startsWith(`..`)&&!l.isAbsolute(a)}},Oi=typeof process<`u`&&process.versions!=null&&process.versions.node!=null;var ki=mi().onBeforeHandle(Ci).onBeforeHandle(Ti).post(`/buttress/upload`,async({body:{file:e},headers:t,store:n})=>{let r=Ei(n,t);if(!r)return{ok:!1,error:`Session guard mis-wired`};let{sessionId:i}=r,{config:a}=n,o=`${Date.now()}-${e.name.replace(/[^\dA-Za-z]/g,`_`)}`,{sessionDir:s,filePath:c,safe:l}=Di(a.server.temp_file_dir,i,o);if(!l)return{ok:!1,error:`Invalid file path`};try{return await p(s,{recursive:!0}),Oi?await b(c,await e.stream()):await b(c,await e.arrayBuffer()),{ok:!0,filename:o}}catch(e){return{ok:!1,error:String(e)}}},{body:a.Object({file:a.File()}),response:a.Object({ok:a.Boolean(),filename:a.Optional(a.String()),error:a.Optional(a.String())})}).get(`/buttress/download/:filename`,async({params:{filename:e},headers:t,store:n,status:i})=>{let a=Ei(n,t);if(!a)return i(500),`Session guard mis-wired`;let{sessionId:o}=a,{config:s}=n,{filePath:c,safe:l}=Di(s.server.temp_file_dir,o,e);return l?r(c):(i(400),`Invalid file path`)},{params:a.Object({filename:a.String()})});const Ai=l.dirname(te(import.meta.url)),ji=async()=>{let e=[l.join(Ai,`..`,`public`,`status.html`),l.join(Ai,`..`,`..`,`public`,`status.html`)];return(await Promise.all(e.map(e=>f.access(e).then(()=>e,()=>null)))).find(e=>e!==null)??null},Mi=e=>{let{status:t}=e;return t?.getFullStatus?t.getFullStatus():{timestamp:new Date().toISOString(),ggmlLlm:{generators:[],history:{}},ggmlStt:{generators:[],history:{}}}},Ni=async()=>{let e=await ji();if(!e)return console.error(`[Status] Failed to find status.html in candidate paths`),new Response(`Status page not found`,{status:404,headers:{"Content-Type":`text/plain`}});try{let t=await f.readFile(e,`utf-8`);return new Response(t,{headers:{"Content-Type":`text/html; charset=utf-8`}})}catch(e){return console.error(`[Status] Failed to serve status page:`,e),new Response(`Status page not found`,{status:404,headers:{"Content-Type":`text/plain`}})}};var Pi=mi().get(`/status`,Ni).get(`/status/`,Ni).get(`/buttress/status`,({store:{backend:e}})=>Mi(e));const Fi=[`ggml-llm`,`mlx-llm`],Q=new Map,Ii=new Map;function Li(e){e.cancel().catch(()=>{})}function Ri(e,t){Q.delete(e),Q.set(e,t)}function zi(e,t){return t.activeRequests+=1,Ri(e,t),t}async function Bi(e,t){for(;Q.size>4;){let n=Array.from(Q.entries()).find(([,e])=>e.activeRequests===0);if(!n)return;let[r,i]=n;Q.delete(r);try{await e.finalizeGenerator?.(i.id),console.log(`${t} Evicted idle generator: ${r}`)}catch(e){console.warn(`${t} Failed to evict idle generator ${r}:`,e?.message)}}}async function Vi(e,t,n=`[LLM]`){t&&(t.activeRequests=Math.max(0,t.activeRequests-1),await Bi(e,n))}function Hi(e,t){return t===`mlx-llm`?e.mlxLlm:e.ggmlLlm}async function Ui(e,t,n,r=`[LLM]`){let i=(t.generators||[]).filter(e=>Fi.includes(e.type));if(i.length===0)throw Error(`No LLM generator configured. Add a [[generators]] with type = "ggml-llm" or "mlx-llm" to your config.`);let a=i[0],o=n||a.model?.repo_id;if(n){let e=i.find(e=>e.model?.repo_id===n);e&&(a=e)}else o=a.model?.repo_id;let s=a.type||`ggml-llm`,c=o,l=Q.get(c);if(l?.initialized)return zi(c,l);let u=Ii.get(c);if(u)return zi(c,await u);let{generators:d,server:f,...p}=t.global||{},m={...p,...a,model:{...a.model,repo_id:o}};console.log(`${r} Creating ${s} generator for ${c}`);let h=(async()=>{let{id:t}=await e.startGenerator(s,m),n={id:t,type:s,config:m,repoId:o,initialized:!1,activeRequests:0};return await Hi(e,s).initContext(t,{}),n.initialized=!0,Q.set(c,n),console.log(`${r} Generator ready: ${c}`),n})().finally(()=>{Ii.delete(c)});Ii.set(c,h);let g=zi(c,await h);return await Bi(e,r),g}function Wi(e){let t=e.timings||{},n=t.prompt_n??t.promptN??0,r=t.cache_n??t.cacheN??0,i=t.predicted_n??t.predictedN??0;return{promptTokens:n||e.prompt_tokens||e.promptTokens||0,cachedTokens:r,completionTokens:i||e.tokens_evaluated||e.tokensEvaluated||e.tokens_predicted||e.tokensPredicted||0}}function Gi(e){let{promptTokens:t,cachedTokens:n,completionTokens:r}=Wi(e),i=t+n;return{prompt_tokens:i,completion_tokens:r,total_tokens:i+r}}const Ki=()=>`chatcmpl-${Date.now()}-${Math.random().toString(36).slice(2,9)}`;async function qi(e,t,n,r){let i=e.getReader(),a=``,o=null,s=null,c=`stop`,l={prompt_tokens:0,completion_tokens:0,total_tokens:0};try{let e=!1;for(;!e;){let n=await i.read();if({done:e}=n,e)break;let{event:r,data:u}=n.value;if(r===`token`)u.content!=null&&(a=u.content),u.reasoning_content!=null&&(o=u.reasoning_content);else if(r===`result`)u.content==null?u.text&&(a=u.text):a=u.content,u.reasoning_content!=null&&(o=u.reasoning_content),u.tool_calls?.length>0?(s=u.tool_calls.map((e,n)=>({id:e.id||`call_${t}_${n}`,type:`function`,function:{name:e.function?.name||``,arguments:e.function?.arguments||``}})),c=`tool_calls`):c=u.interrupted?`length`:`stop`,l=Gi(u);else if(r===`error`)throw Error(u.message)}}finally{Li(i)}let u={role:`assistant`,content:a||null};return o&&(u.reasoning_content=o),s&&(u.tool_calls=s),{id:t,object:`chat.completion`,created:n,model:r,choices:[{index:0,message:u,finish_reason:c}],usage:l}}function Ji(e,t,n,r){let i=[];return e.forEach((e,a)=>{let o={index:a};n.has(a)||(n.set(a,e.id||`call_${t}_${a}`),o.id=n.get(a),o.type=`function`);let s=e.function?.arguments||``,c=r.get(a)||``,l={};!r.has(a)&&e.function?.name&&(l.name=e.function.name),s.length>c.length&&(l.arguments=s.slice(c.length),r.set(a,s)),Object.keys(l).length>0?(o.function=l,i.push(o)):o.id&&(o.function={name:e.function?.name||``,arguments:``},i.push(o))}),i}async function*Yi(e,t,n,r,a){let o=e.getReader(),s=``,c=``,l=new Map,u=new Map;try{let e=!1;for(;!e;){let d=await o.read();if({done:e}=d,e)break;let{event:f,data:p}=d.value;if(f===`token`){let e={};if(p.content!=null){let t=p.content;t.length>s.length&&(e.content=t.slice(s.length),s=t)}if(p.reasoning_content!=null){let t=p.reasoning_content;t.length>c.length&&(e.reasoning_content=t.slice(c.length),c=t)}if(p.tool_calls?.length>0){let n=Ji(p.tool_calls,t,u,l);n.length>0&&(e.tool_calls=n)}Object.keys(e).length>0&&(yield i({data:JSON.stringify({id:t,object:`chat.completion.chunk`,created:n,model:r,choices:[{index:0,delta:e,finish_reason:null}]})}))}else if(f===`result`){if(p.tool_calls?.length>0){let e=Ji(p.tool_calls,t,u,l);e.length>0&&(yield i({data:JSON.stringify({id:t,object:`chat.completion.chunk`,created:n,model:r,choices:[{index:0,delta:{tool_calls:e},finish_reason:null}]})}))}let e=`stop`;p.tool_calls?.length>0||u.size>0?e=`tool_calls`:p.interrupted&&(e=`length`);let o={id:t,object:`chat.completion.chunk`,created:n,model:r,choices:[{index:0,delta:{},finish_reason:e}]};a&&(o.usage=Gi(p)),yield i({data:JSON.stringify(o)})}else f===`error`&&(yield i({data:JSON.stringify({error:{message:p.message,type:`server_error`}})}))}yield i({data:`[DONE]`})}finally{Li(o)}}function Xi({global:e}){let t=mi({prefix:`/oai-compat`});return t.use(ie({origin:e?.openai_compat?.cors_allowed_origins??!1,methods:[`GET`,`POST`,`OPTIONS`],allowedHeaders:[`Content-Type`,`Authorization`],maxAge:86400,preflight:!0})),t.onBeforeHandle(Ci),t.get(`/v1/models`,({store:e})=>{let{config:t}=e,n=(t.generators||[]).filter(e=>Fi.includes(e.type)).map(e=>({id:e.model?.repo_id||e.type,object:`model`,created:Math.floor(Date.now()/1e3),owned_by:`local`}));return n.length===0&&n.push({id:`ggml-llm`,object:`model`,created:Math.floor(Date.now()/1e3),owned_by:`local`}),{object:`list`,data:n}}),t.post(`/v1/chat/completions`,async function*({body:e,set:t,store:n}){let{config:r,backend:i}=n,{messages:a=[],stream:o=!1,model:s,tools:c,temperature:l,stop:u,top_p:d,max_tokens:f,presence_penalty:p,frequency_penalty:m,tool_choice:h,stream_options:g,enable_thinking:_}=e;if(!a||a.length===0)return t.status=400,{error:{message:`messages is required and must not be empty`,type:`invalid_request_error`}};let v=null;try{v=await Ui(i,r,s,`[OpenAI]`);let e=Ki(),t=Math.floor(Date.now()/1e3),n=v.repoId||`ggml-llm`,y={reasoning_format:`auto`,messages:a,jinja:!0,add_generation_prompt:!0};l!=null&&(y.temperature=l),d!=null&&(y.top_p=d),f!=null&&(y.n_predict=f),u!=null&&(y.stop=Array.isArray(u)?u:[u]),p!=null&&(y.presence_penalty=p),m!=null&&(y.frequency_penalty=m),c!=null&&(y.tools=c),h!=null&&(y.tool_choice=h),y.enable_thinking=_??!1;let b=await Hi(i,v.type).completion(v.id,{options:y});if(!o)return await qi(b,e,t,n);yield*Yi(b,e,t,n,g?.include_usage===!0)}catch(e){return console.error(`[OpenAI] Chat completion error:`,e),t.status=500,{error:{message:e.message||`Internal server error`,type:`server_error`}}}finally{await Vi(i,v,`[OpenAI]`)}},{body:a.Object({model:a.Optional(a.String()),messages:a.Array(a.Any()),stream:a.Optional(a.Boolean()),temperature:a.Optional(a.Number()),top_p:a.Optional(a.Number()),max_tokens:a.Optional(a.Number()),stop:a.Optional(a.Union([a.String(),a.Array(a.String())])),presence_penalty:a.Optional(a.Number()),frequency_penalty:a.Optional(a.Number()),tools:a.Optional(a.Array(a.Any())),tool_choice:a.Optional(a.Any()),stream_options:a.Optional(a.Object({include_usage:a.Optional(a.Boolean())})),enable_thinking:a.Optional(a.Boolean())})}),t}const Zi=()=>`msg_${Date.now()}${Math.random().toString(36).slice(2,11)}`;function Qi(e){let t={},n=[];if(e.system!=null){let t=``;if(typeof e.system==`string`)t=e.system;else if(Array.isArray(e.system))for(let n of e.system)n?.type===`text`&&typeof n.text==`string`&&(t+=n.text);t&&n.push({role:`system`,content:t})}if(!Array.isArray(e.messages))throw Error(`'messages' is required and must be an array`);for(let t of e.messages){let e=t?.role||`user`;if(t?.content==null){if(e===`assistant`)continue;n.push(t);continue}if(typeof t.content==`string`){n.push({role:e,content:t.content});continue}if(!Array.isArray(t.content)){n.push(t);continue}let r=[],i=[],a=[],o=``,s=!1;for(let e of t.content){let t=e?.type||``;if(t===`text`)i.push({type:`text`,text:e.text||``});else if(t===`thinking`)o+=e.thinking||``;else if(t===`image`){let t=e.source||{};if(t.type===`base64`){let e=t.media_type||`image/jpeg`,n=t.data||``;i.push({type:`image_url`,image_url:{url:`data:${e};base64,${n}`}})}else t.type===`url`&&i.push({type:`image_url`,image_url:{url:t.url||``}})}else if(t===`tool_use`)r.push({id:e.id||``,type:`function`,function:{name:e.name||``,arguments:JSON.stringify(e.input??{})}}),s=!0;else if(t===`tool_result`){let t=e.tool_use_id||``,n=``,r=e.content;if(typeof r==`string`)n=r;else if(Array.isArray(r))for(let e of r)e?.type===`text`&&(n+=e.text||``);a.push({role:`tool`,tool_call_id:t,content:n})}}if(i.length>0||s||o){let t={role:e};i.length>0?t.content=i:(s||o)&&(t.content=``),r.length>0&&(t.tool_calls=r),o&&(t.reasoning_content=o),n.push(t)}for(let e of a)n.push(e)}if(t.messages=n,Array.isArray(e.tools)&&(t.tools=e.tools.map(e=>({type:`function`,function:{name:e.name||``,description:e.description||``,parameters:e.input_schema||{}}}))),e.tool_choice&&typeof e.tool_choice==`object`){let n=e.tool_choice.type;n===`auto`?t.tool_choice=`auto`:n===`any`||n===`tool`?t.tool_choice=`required`:n===`none`&&(t.tool_choice=`none`)}else Array.isArray(t.tools)&&t.tools.length>0&&(t.tool_choice=`auto`);e.stop_sequences!=null&&(t.stop=Array.isArray(e.stop_sequences)?e.stop_sequences:[e.stop_sequences]),t.max_tokens=e.max_tokens??4096;for(let n of[`temperature`,`top_p`,`top_k`,`stream`])e[n]!=null&&(t[n]=e[n]);return e.thinking&&typeof e.thinking==`object`&&e.thinking.type===`enabled`&&(t.enable_thinking=!0,e.thinking.budget_tokens!=null&&(t.thinking_budget_tokens=e.thinking.budget_tokens)),t}function $i(e,t){return t?`tool_use`:e.stopping_word||e.stoppingWord?`stop_sequence`:e.interrupted||e.truncated?`max_tokens`:`end_turn`}function ea(e){let{promptTokens:t,cachedTokens:n,completionTokens:r}=Wi(e);return{cache_read_input_tokens:n,input_tokens:t,output_tokens:r}}async function ta(e,t,n){let r=e.getReader(),i=``,a=``,o=[],s={cache_read_input_tokens:0,input_tokens:0,output_tokens:0},c=`end_turn`,l=null;try{let e=!1;for(;!e;){let t=await r.read();if({done:e}=t,e)break;let{event:n,data:u}=t.value;if(n===`token`)u.content!=null&&(i=u.content),u.reasoning_content!=null&&(a=u.reasoning_content);else if(n===`result`)u.content==null?u.text&&u.reasoning_content==null&&(i=u.text):i=u.content,u.reasoning_content!=null&&(a=u.reasoning_content),Array.isArray(u.tool_calls)&&(o=u.tool_calls),s=ea(u),l=u.stopping_word||u.stoppingWord||null,c=$i(u,o.length>0);else if(n===`error`)throw Error(u.message||`completion error`)}}finally{Li(r)}let u=[];a&&u.push({type:`thinking`,thinking:a,signature:``}),i&&u.push({type:`text`,text:i});for(let e of o){let t={};try{t=JSON.parse(e.function?.arguments||`{}`)}catch{t={}}u.push({type:`tool_use`,id:e.id||`toolu_${Math.random().toString(36).slice(2,11)}`,name:e.function?.name||``,input:t})}return{id:t,type:`message`,role:`assistant`,content:u,model:n,stop_reason:c,stop_sequence:l,usage:s}}async function*na(e,t,n){let r=e.getReader(),a=``,o=``,s=new Map,c=new Map,l=new Map,u=new Set,d=!1,f=!1,p=0,m=-1,h=-1,g=new Map,_={cache_read_input_tokens:0,input_tokens:0,output_tokens:0},v=`end_turn`,y=null,b=!1;function*x(e){for(let n=0;n<e.length;n+=1){let r=e[n],a=r?.function?.arguments||``,o=s.get(n)||``;if(!u.has(n)){let e=r?.id||`toolu_${t}_${n}`,a=r?.function?.name||l.get(n)||``;c.set(n,e),l.set(n,a),g.set(n,p),u.add(n),yield i({event:`content_block_start`,data:JSON.stringify({type:`content_block_start`,index:p,content_block:{type:`tool_use`,id:e,name:a,input:{}}})}),p+=1}let d=g.get(n);a.length>o.length&&(yield i({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:d,delta:{type:`input_json_delta`,partial_json:a.slice(o.length)}})}),s.set(n,a))}}try{let e=!1;for(;!e;){let s=await r.read();if({done:e}=s,e)break;let{event:c,data:l}=s.value;if(c===`token`){if(!b){let e=ea(l);yield i({event:`message_start`,data:JSON.stringify({type:`message_start`,message:{id:t,type:`message`,role:`assistant`,content:[],model:n,stop_reason:null,stop_sequence:null,usage:e}})}),b=!0}if(l.reasoning_content!=null){let e=l.reasoning_content;e.length>o.length&&(d||(m=p,p+=1,d=!0,yield i({event:`content_block_start`,data:JSON.stringify({type:`content_block_start`,index:m,content_block:{type:`thinking`,thinking:``}})})),yield i({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:m,delta:{type:`thinking_delta`,thinking:e.slice(o.length)}})}),o=e)}if(l.content!=null){let e=l.content;e.length>a.length&&(f||(h=p,p+=1,f=!0,yield i({event:`content_block_start`,data:JSON.stringify({type:`content_block_start`,index:h,content_block:{type:`text`,text:``}})})),yield i({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:h,delta:{type:`text_delta`,text:e.slice(a.length)}})}),a=e)}Array.isArray(l.tool_calls)&&l.tool_calls.length>0&&(yield*x(l.tool_calls))}else if(c===`result`){if(!b){let e=ea(l);yield i({event:`message_start`,data:JSON.stringify({type:`message_start`,message:{id:t,type:`message`,role:`assistant`,content:[],model:n,stop_reason:null,stop_sequence:null,usage:e}})}),b=!0}Array.isArray(l.tool_calls)&&l.tool_calls.length>0&&(yield*x(l.tool_calls)),_=ea(l),y=l.stopping_word||l.stoppingWord||null,v=$i(l,u.size>0)}else if(c===`error`){yield i({event:`error`,data:JSON.stringify({type:`error`,error:{type:`api_error`,message:l.message||`completion error`}})});return}}d&&(yield i({event:`content_block_delta`,data:JSON.stringify({type:`content_block_delta`,index:m,delta:{type:`signature_delta`,signature:``}})}),yield i({event:`content_block_stop`,data:JSON.stringify({type:`content_block_stop`,index:m})})),f&&(yield i({event:`content_block_stop`,data:JSON.stringify({type:`content_block_stop`,index:h})}));for(let e of[...u].sort((e,t)=>e-t))yield i({event:`content_block_stop`,data:JSON.stringify({type:`content_block_stop`,index:g.get(e)})});yield i({event:`message_delta`,data:JSON.stringify({type:`message_delta`,delta:{stop_reason:v,stop_sequence:y},usage:{output_tokens:_.output_tokens}})}),yield i({event:`message_stop`,data:JSON.stringify({type:`message_stop`})})}finally{Li(r)}}function ra({global:e}){let t=mi({prefix:`/anthropic-messages`});return t.use(ie({origin:e?.anthropic_messages?.cors_allowed_origins??!1,methods:[`GET`,`POST`,`OPTIONS`],allowedHeaders:[`Content-Type`,`Authorization`,`x-api-key`,`anthropic-version`],maxAge:86400,preflight:!0})),t.onBeforeHandle(Ci),t.post(`/v1/messages`,async function*({body:e,set:t,store:n}){let{config:r,backend:i}=n,a=e,o=null;try{if(!Array.isArray(a.messages)||a.messages.length===0)return t.status=400,{type:`error`,error:{type:`invalid_request_error`,message:`messages is required and must not be empty`}};let e=Qi(a);o=await Ui(i,r,a.model,`[Anthropic]`);let n=Zi(),s=o.repoId||`ggml-llm`,c={reasoning_format:`auto`,messages:e.messages,jinja:!0,add_generation_prompt:!0};e.temperature!=null&&(c.temperature=e.temperature),e.top_p!=null&&(c.top_p=e.top_p),e.top_k!=null&&(c.top_k=e.top_k),e.max_tokens!=null&&(c.n_predict=e.max_tokens),e.stop!=null&&(c.stop=e.stop),e.tools!=null&&(c.tools=e.tools),e.tool_choice!=null&&(c.tool_choice=e.tool_choice),c.enable_thinking=e.enable_thinking??!1,e.thinking_budget_tokens!=null&&(c.thinking_budget_tokens=e.thinking_budget_tokens);let l=await Hi(i,o.type).completion(o.id,{options:c});if(!a.stream)return await ta(l,n,s);yield*na(l,n,s)}catch(e){return console.error(`[Anthropic] Messages error:`,e),t.status=500,{type:`error`,error:{type:`api_error`,message:e?.message||`Internal server error`}}}finally{await Vi(i,o,`[Anthropic]`)}},{body:a.Object({model:a.Optional(a.String()),messages:a.Array(a.Any()),system:a.Optional(a.Any()),max_tokens:a.Optional(a.Number()),stream:a.Optional(a.Boolean()),temperature:a.Optional(a.Number()),top_p:a.Optional(a.Number()),top_k:a.Optional(a.Number()),stop_sequences:a.Optional(a.Union([a.String(),a.Array(a.String())])),tools:a.Optional(a.Array(a.Any())),tool_choice:a.Optional(a.Any()),thinking:a.Optional(a.Any()),metadata:a.Optional(a.Any())})}),t.post(`/v1/messages/count_tokens`,async({body:e,set:t,store:n})=>{let{config:r,backend:i}=n,a=e,o=null;try{let e=Qi(a);o=await Ui(i,r,a.model,`[Anthropic]`);let t=Hi(i,o.type),n={messages:e.messages,add_generation_prompt:!0,jinja:!0};e.tools!=null&&(n.tools=e.tools);let s=await t.applyChatTemplate(o.id,n),c=typeof s==`string`?s:s?.prompt||``,l=await t.tokenize(o.id,{text:c,add_special:!0,parse_special:!0});return{input_tokens:(Array.isArray(l)?l:l?.tokens||[]).length}}catch(e){return console.error(`[Anthropic] count_tokens error:`,e),t.status=500,{type:`error`,error:{type:`api_error`,message:e?.message||`Internal server error`}}}finally{await Vi(i,o,`[Anthropic]`)}},{body:a.Object({model:a.Optional(a.String()),messages:a.Array(a.Any()),system:a.Optional(a.Any()),tools:a.Optional(a.Array(a.Any())),tool_choice:a.Optional(a.Any())})}),t.get(`/v1/models`,({store:e})=>{let{config:t}=e,n=(t.generators||[]).filter(e=>Fi.includes(e.type)).map(e=>{let t=e.model?.repo_id||e.type;return{id:t,type:`model`,display_name:t,created_at:new Date().toISOString()}});return n.length===0&&n.push({id:`ggml-llm`,type:`model`,display_name:`ggml-llm`,created_at:new Date().toISOString()}),{data:n,has_more:!1,first_id:n[0]?.id,last_id:n.at(-1)?.id}}),t}const ia=(e={},t={})=>{let n=Array.isArray(e)?[...e]:{...e};return Object.entries(t||{}).forEach(([e,t])=>{t&&typeof t==`object`&&!Array.isArray(t)?n[e]=ia(n[e]||{},t):n[e]=t}),n},aa=e=>e&&typeof e==`object`?structuredClone(e):null,oa=(e,t)=>ia(aa(e)||{},aa(t)||{}),sa=(e,t)=>ia(structuredClone(e.global),t||{}),ca=(e,t,n,r)=>{if(e.generators.length>0){let i=e.generators.filter(e=>e?.type===n);if(i.length>0&&r){let a=i.find(e=>t.getModelIdentifier(n,e)===r);if(a)return sa(e,a)}}return Object.keys(e.global).length>0?sa(e,{}):null},la={udp:{port:8089,announcements:{enabled:!0,interval:5e3},requests:{enabled:!0,responseDelay:100}},http:{enabled:!0,path:`/buttress/info`,cors:!0}},ua=e=>e?e===!0?{...la}:ia(la,e):null,da=(e,t)=>{if(!e.generators||e.generators.length===0)return t.map(e=>({type:e}));let n=new Set;return e.generators.forEach(e=>{e.type&&n.add(e.type)}),n.size===0?t.map(e=>({type:e})):Array.from(n).map(e=>({type:e}))},fa=(e,t,n)=>e===void 0?n:typeof e==`number`?e:t(e)??n,pa=6e4,ma=1024*1024*50,ha=e=>{let t=ae.machineIdSync(),n=ia({server:{id:`buttress-${t}`,name:`Buttress Server (${t.slice(-8)})`,port:2080,temp_file_dir:l.join(x.tmpdir(),`.buttress`),session_timeout:pa,max_body_size:ma},autodiscover:!1},aa(e)||{}),r=Array.isArray(n.generators)?n.generators:[],{server:i,generators:a,autodiscover:o,...s}=n;return{autodiscover:ua(o),server:{id:i.id,name:i.name,port:i.port,log_level:i.log_level,temp_file_dir:i.temp_file_dir,max_body_size:fa(i.max_body_size,E.parse,ma),session_timeout:fa(i.session_timeout,F,pa)},global:s,generators:r}},ga={getCapabilities:M.tuple([M.object({type:M.string().optional().default(`ggml-llm`),config:M.any().optional(),currentClientCapabilities:M.any().optional(),options:M.any().optional()}).nullable().optional()]),startGenerator:M.tuple([M.string(),M.any().optional()]),finalizeGenerator:M.tuple([M.string()])};var _a={async getCapabilities({backend:e,config:t},n=null){console.log(`[Server] Get Capabilities:`,n);let{type:r=`ggml-llm`,config:i,currentClientCapabilities:a=null,options:o={}}=n||{type:`ggml-llm`},s=aa(i),c=oa(ca(t,e,r,e.getModelIdentifier(r,s)),i);if(Object.keys(c).length===0)throw Error(`Buttress server missing generator configuration`);return c.backend=c.backend||{},c.backend.type||(c.backend.type=r),e.getCapabilities(r,a,{...o,config:c})},async startGenerator({backend:e,config:t,session:n},r,i){console.log(`[Server] Start Generator:`,r,i);let a=aa(i),o=oa(ca(t,e,r,e.getModelIdentifier(r,a)),i);if(Object.keys(o).length===0)throw Error(`Buttress server missing generator configuration`);o.backend=o.backend||{},o.backend.type||(o.backend.type=r);let s=await e.startGenerator(r,o);return n.generators.add(s.id),s},async finalizeGenerator({backend:e,session:t},n){return console.log(`[Server] Finalize Generator:`,n),t.generators.delete(n),e.finalizeGenerator(n)}};const va={initContext:M.tuple([M.string(),M.any().optional()]),completion:M.tuple([M.string(),M.any().optional()]),tokenize:M.tuple([M.string(),M.any()]),detokenize:M.tuple([M.string(),M.any()]),applyChatTemplate:M.tuple([M.string(),M.any()]),releaseContext:M.tuple([M.string()])};function ya(e){return function({backend:t,session:n},r,i){return new d({async start(a){try{let o=await e(t).initContext(r,{...i,onProgress:e=>{a.enqueue({event:`progress`,data:{progress:e}})}});n.initializedContexts.add(r),await new Promise(e=>setTimeout(e,1e3));let{download:s,...c}=o||{};a.enqueue({event:`result`,data:{result:c}}),a.close()}catch(e){a.error(e)}}})}}function ba(e,t){return async function({backend:n,session:r},i,a){return console.log(`[Server] ${t}:`,{id:i,force:a}),r.initializedContexts.has(i)?(r.initializedContexts.delete(i),e(n).releaseContext(i,{force:a})):(console.log(`[Server] ${t} skipped - not initialized by this session:`,{id:i}),{released:!1,skipped:!0})}}function xa(e,t){return{initContext:ya(e),completion({backend:n},r,i){return console.log(`[Server] ${t}Completion:`,{id:r,property:i}),e(n).completion(r,i)},async tokenize({backend:n},r,i){return console.log(`[Server] ${t}Tokenize:`,{id:r,property:i}),e(n).tokenize(r,i)},async detokenize({backend:n},r,i){return console.log(`[Server] ${t}Detokenize:`,{id:r,property:i}),e(n).detokenize(r,i)},async applyChatTemplate({backend:n},r,i){return console.log(`[Server] ${t}Apply Chat Template:`,{id:r,property:i}),e(n).applyChatTemplate(r,i)},releaseContext:ba(e,`${t}Release Context`)}}var Sa=xa(e=>e.ggmlLlm,``);const Ca={initContext:M.tuple([M.string(),M.any().optional()]),transcribe:M.tuple([M.string(),M.string(),M.any().optional()]),transcribeData:M.tuple([M.string(),M.union([M.instanceof(Buffer),M.instanceof(Uint8Array)]),M.any().optional()]),releaseContext:M.tuple([M.string()])},wa=e=>e.ggmlStt,Ta={common:_a,ggmlLlm:Sa,ggmlStt:{initContext:ya(wa),async transcribe({backend:e,config:{server:t},peerId:n},r,i,a){console.log(`[Server] Transcribe:`,{id:r,audioPath:i,options:a});let{filePath:o,safe:s}=Di(t.temp_file_dir,n,i);if(!s)throw Error(`Invalid audioPath`);return e.ggmlStt.transcribe(r,{audioPath:o,options:a})},async transcribeData({backend:e},t,n,r){return console.log(`[Server] Transcribe Data:`,{id:t,audioDataLength:n?.length||0,options:r}),e.ggmlStt.transcribeData(t,{audioData:n,options:r})},releaseContext:ba(wa,`Release STT Context`)},mlxLlm:xa(e=>e.mlxLlm,`MLX `)},Ea={common:ga,ggmlLlm:va,ggmlStt:Ca,mlxLlm:va};var Da=Ta;const Oa=e=>{try{return JSON.parse(e,(e,t)=>t&&(t?.type===`Buffer`&&t?.data||t?.type===`Uint8Array`&&t?.data?I.from(t.data,`base64`):t?.type===`Error`&&t?.name&&t?.message?Error(t.name,t.message):t))}catch{return e}},ka=e=>{try{return JSON.stringify(e,(e,t)=>t instanceof Error?{type:`Error`,name:t.name,message:t.message}:t instanceof I?{type:`Buffer`,data:t.toString(`base64`)}:t instanceof Uint8Array?{type:`Uint8Array`,data:I.from(t).toString(`base64`)}:t)}catch{return e}},Aa={score:0,hasGpu:!1,usableBytes:0},ja=e=>e?{score:Number(e.score)||0,hasGpu:!!e.hasGpu,usableBytes:Number(e.gpuUsableBytes||e.cpuUsableBytes||0)}:Aa,Ma=async e=>{let t=[];for(let n of e){let e=Aa;try{e=ja((await K(n.type,null,{}))?.buttress?.selected)}catch(e){console.warn(`[Caps] Failed to detect capabilities for "${n.type}":`,e instanceof Error?e.message:e)}t.push({...n,...e})}return t},Na=()=>{let e=x.networkInterfaces();return Object.values(e).flat().find(e=>e?.family===`IPv4`&&!e?.internal)?.address||null},Pa=e=>{let t=e.split(`.`).map(Number);return t.length!==4||t.some(e=>Number.isNaN(e))?0:(t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0},Fa=e=>[e>>>24&255,e>>>16&255,e>>>8&255,e&255].join(`.`),Ia=()=>{let e=[],t=new Set;for(let n of Object.values(x.networkInterfaces()))for(let r of n??[]){if(r.family!==`IPv4`||r.internal||!r.address||!r.netmask)continue;let n=Pa(r.address),i=Pa(r.netmask);if(!n||!i||i===4294967295)continue;let a=Fa((n&i|~i>>>0)>>>0);if(a===r.address)continue;let o=`${r.address}->${a}`;t.has(o)||(t.add(o),e.push({address:r.address,broadcast:a}))}return e},La=e=>{if(!e)return!1;let t=e;return t.code===`ENOTSUP`||/Failed to bind socket/i.test(t.message??``)};var Ra=class e{name=`udp`;receiver=null;senders=[];announcementTimer=null;config;getServerInfo;port;signer;constructor(e,t,n){this.config=e,this.getServerInfo=t,this.port=e.port??8089,this.signer=n}async start(){this.receiver=await this.bindReceiver(!0).catch(e=>{if(!La(e))throw e;return console.warn(`[Autodiscover UDP] SO_REUSEPORT not supported by this runtime; falling back to REUSEADDR only (multiple buttress instances on one host will not coexist on the discovery port).`),this.bindReceiver(!1)}),this.receiver.on(`message`,(e,t)=>{this.handleMessage(e,t)}),this.receiver.on(`error`,e=>{console.error(`[Autodiscover UDP] Receiver error:`,e.message)}),this.receiver.setBroadcast(!0),this.senders=await this.createSenders();let e=this.senders.map(e=>`${e.address}->${e.broadcast}`).join(`, `)||`<none>`;if(console.log(`[Autodiscover UDP] Listening on port ${this.port}; announce interfaces: ${e}`),this.config.announcements.enabled){let e=this.config.announcements.interval??5e3;this.announcementTimer=setInterval(()=>{this.sendAnnouncement()},e),this.sendAnnouncement()}}async stop(){this.announcementTimer&&=(clearInterval(this.announcementTimer),null),await Promise.all(this.senders.map(({socket:e})=>new Promise(t=>{e.close(()=>t())}))),this.senders=[],this.receiver&&=(await new Promise(e=>{this.receiver.close(()=>e())}),null)}async bindReceiver(e){let t=oe.createSocket(e?{type:`udp4`,reuseAddr:!0,reusePort:!0}:{type:`udp4`,reuseAddr:!0});return new Promise((e,n)=>{let r=e=>{t.close(),n(e)};t.once(`error`,r),t.bind(this.port,()=>{t.off(`error`,r),e(t)})})}async createSenders(){let e=Ia();return(await Promise.all(e.map(async e=>{try{let t=oe.createSocket({type:`udp4`});return await new Promise((n,r)=>{let i=e=>{t.close(),r(e)};t.once(`error`,i),t.bind({port:0,address:e.address},()=>{t.off(`error`,i),t.setBroadcast(!0),n()})}),t.on(`error`,t=>{console.error(`[Autodiscover UDP] Sender ${e.address} error:`,t.message)}),{...e,socket:t}}catch(t){return console.warn(`[Autodiscover UDP] Failed to bind sender on ${e.address}:`,t.message),null}}))).filter(e=>e!==null)}handleMessage(e,t){try{let n=JSON.parse(e.toString());if(n.t===`QUERY`&&this.config.requests.enabled){let e=n.d,r=this.config.requests.responseDelay??0,i=r>0?Math.random()*r:0;setTimeout(()=>{this.sendResponse(e.id,t)},i)}}catch{}}static canonicalBytes(e,t,n){return Buffer.from(JSON.stringify({t:e,d:t,ts:n}),`utf8`)}signEnvelope(t,n){if(!this.signer)return null;let r=Math.floor(Date.now()/1e3),i=o.sign(null,e.canonicalBytes(t,n,r),this.signer.privateKey).toString(`base64`);return{t,v:`2.0`,d:n,ts:r,kid:this.signer.kid,sig:i}}sendAnnouncement(){if(this.senders.length===0)return;let e=this.getServerInfo(),t=this.signEnvelope(`ANNOUNCE`,{info:e});if(!t){console.warn("[Autodiscover UDP] no per-server keypair; skipping announcement. Run `bricks buttress bind` to register a key.");return}let n=Buffer.from(JSON.stringify(t));for(let{broadcast:e,socket:t,address:r}of this.senders)t.send(n,0,n.length,this.port,e,t=>{t&&console.error(`[Autodiscover UDP] Announcement ${r}->${e} error:`,t.message)})}sendResponse(e,t){if(!this.receiver)return;let n=this.getServerInfo(),r=this.signEnvelope(`RESPONSE`,{request_id:e,info:n});if(!r)return;let i=Buffer.from(JSON.stringify(r));this.receiver.send(i,0,i.length,t.port,t.address,e=>{e&&console.error(`[Autodiscover UDP] Response error:`,e.message)})}},za=class{transports=[];started=!1;constructor(e,t,n){this.config=e,this.getServerInfo=t,this.signer=n,(e.udp?.announcements?.enabled||e.udp?.requests?.enabled)&&this.transports.push(new Ra(e.udp,t,n))}async start(){this.started||=((await Promise.allSettled(this.transports.map(e=>e.start()))).forEach((e,t)=>{e.status===`rejected`&&console.error(`[Autodiscover] Failed to start ${this.transports[t].name}:`,e.reason)}),!0)}async stop(){this.started&&=(await Promise.allSettled(this.transports.map(e=>e.stop())),!1)}};const Ba=()=>process.env.BRICKS_BUTTRESS_STATE_DIR||l.join(x.homedir(),`.bricks-cli`,`buttress`),Va=()=>l.join(Ba(),`state.json`),Ha=e=>{if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.id==`string`&&typeof t.serverId==`string`&&typeof t.issuerPublicKey==`string`&&typeof t.kid==`string`},Ua=e=>{if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.publicKeySpki==`string`&&typeof t.privateKeyPkcs8==`string`&&typeof t.kid==`string`},Wa=()=>{let e=Va();try{let t=k.readFileSync(e,`utf8`),n=JSON.parse(t);return{workspace:Ha(n?.workspace)?n.workspace:null,serverKeyPair:Ua(n?.serverKeyPair)?n.serverKeyPair:null}}catch(e){return e.code!==`ENOENT`&&console.warn(`[Buttress] Failed to read workspace state:`,e.message),{workspace:null,serverKeyPair:null}}},$=fi(),Ga=e=>{if(!e)return{repoId:null,filename:null};let[t,n]=e.split(`:`);return{repoId:t,filename:n||null}};async function Ka({modelIds:e=[],defaultConfig:t=null}={}){let n=[];console.log(`${$.name} v${$.version}`),console.log(`Generating model capabilities comparison...
37
37
  `),n.push(`${$.name} v${$.version}`),n.push(`## Model Capabilities Comparison
38
38
  `),(!e||e.length===0)&&(console.error(`Error: No model IDs provided`),process.exit(1));try{let{globalDefaults:r,resolveDefaultConfig:i}=q(t,`ggml-llm`),a=[];for(let t=0;t<e.length;t+=1){let n=e[t];console.log(`[${t+1}/${e.length}] Analyzing ${n}...`);let o=i(n);o={...o||{},model:{...r.runtime,...o?.model||{},repo_id:n}};let s=await K(`ggml-llm`,null,{config:o,includeBreakdown:!0});a.push({modelId:n,capabilities:s,modelInfo:s.buttress?.selected||null,modelConfig:s.modelConfig||null})}let o=e=>e?(e/1024/1024/1024).toFixed(2):`N/A`,s=e=>e?`✅`:`🚫`;n.push(`| Model ID | Size (GB) | Context Size | KV Cache Size (GB) | Recurrent Mem (GB) | Total Required Memory (GB) | Fits GPU (Full) | Fits CPU (Full) |`),n.push(`|----------|-----------|--------------|--------------------|--------------------|----------------------------|-----------------|-----------------|`),a.forEach(({modelId:e,modelInfo:t,modelConfig:r})=>{let i=o(t?.modelBytes),a=r?.nCtx||t?.kvInfo?.nCtxTrain||`N/A`,c=Ye(t),l=Number(a),u=t?.kvCacheBytes||(c&&Number.isFinite(l)&&l>0?c(l):c&&c(t?.kvInfo?.nCtxTrain||0))||null,d=o(u),f=t?.recurrentMemoryBytes||0,p=f>0?o(f):`-`,m=o(t?.modelBytes&&(u!=null||f>0)?t.modelBytes+(u||0)+f:t?.fit?.totalRequiredBytes),h=s(t?.fit?.fitsInGpu),g=s(t?.fit?.fitsInCpu);n.push(`| ${e} | ${i} | ${a} | ${d} | ${p} | ${m} | ${h} | ${g} |`);let _=t?.memoryLimitedCtx!=null||t?.limitedFit!=null,v=!t?.fit?.fitsInGpu||!t?.fit?.fitsInCpu;if(_&&v){let e=t?.memoryLimitedCtx||a,r=Number(e),l=t?.limitedKvCacheBytes||c&&Number.isFinite(r)&&r>0&&c(r)||null,u=o(l),h=o(t?.modelBytes&&(l!=null||f>0)?t.modelBytes+(l||0)+f:t?.limitedFit?.totalRequiredBytes),g=s(t?.limitedFit?.fitsInGpu),_=s(t?.limitedFit?.fitsInCpu);(e!==a||u!==d||h!==m)&&n.push(`| ↳ Limited | ${i} | ${e} | ${u} | ${p} | ${h} | ${g} | ${_} |`)}}),n.push(`
39
39
  ---`),n.push(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fugood/buttress-server",
3
- "version": "2.24.10",
3
+ "version": "2.24.12",
4
4
  "main": "lib/index.mjs",
5
5
  "types": "lib/index.d.mts",
6
6
  "type": "module",