@fugood/buttress-server 2.26.0-beta.19 → 2.26.0-beta.20

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.
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import e from"node:path";import t from"node:os";import n from"bytes";import r from"ms";import i from"node-machine-id";const a=e=>{let t=e?.model?.repo_id||e?.type||``,n=e?.model?.filename;return n?`${t}:${n}`:t},o=({family:e,types:t})=>(n,r)=>{let i=(n.generators||[]).filter(e=>t.includes(e.type));if(i.length===0){let n=t.map(e=>`"${e}"`).join(` or `);throw Error(`No ${e} generator configured. Add a [[generators]] with type = ${n} to your config.`)}let o=i[0];if(r){let t=i.find(e=>a(e)===r)||i.find(e=>{let{repo_id:t,filename:n}=e?.model||{};return t===r||n===r});if(!t){let t=i.map(a).join(`, `);throw Error(`Unknown ${e} model "${r}". Configured models: ${t||`(none)`}`)}o=t}let{generators:s,server:c,...l}=n.global||{};return{type:o.type||t[0],repoId:a(o),mergedConfig:{...l,...o,model:{...o.model}}}},s=({max:e,resolve:t,prepare:n,dispose:r})=>{let i=new Map,a=new Map,o=(e,t)=>{i.delete(e),i.set(e,t)},s=(e,t)=>(t.activeRequests+=1,o(e,t),t),c=async(t,n)=>{for(;i.size>e;){let e=Array.from(i.entries()).find(([,e])=>e.activeRequests===0);if(!e)return;let[a,o]=e;i.delete(a);try{await r?.(t,o),await t.finalizeGenerator?.(o.id),console.log(`${n} Evicted idle generator: ${a}`)}catch(e){console.warn(`${n} Failed to evict idle generator ${a}:`,e?.message)}}};return{getOrCreate:async(e,r,o,l)=>{let{type:u,repoId:d,mergedConfig:f}=t(r,o),p=d,m=i.get(p);if(m?.initialized)return s(p,m);let h=a.get(p);if(h)return s(p,await h);console.log(`${l} Creating ${u} generator for ${p}`);let g=(async()=>{let{id:t}=await e.startGenerator(u,f),r={id:t,type:u,config:f,repoId:d,initialized:!1,activeRequests:0};return await n(e,r),r.initialized=!0,i.set(p,r),console.log(`${l} Generator ready: ${p}`),r})().finally(()=>{a.delete(p)});a.set(p,g);let _=s(p,await g);return await c(e,l),_},release:async(e,t,n)=>{t&&(t.activeRequests=Math.max(0,t.activeRequests-1),await c(e,n))}}};function c(e){e.cancel().catch(()=>{})}const l=(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]=l(n[e]||{},t):n[e]=t}),n},u=e=>e&&typeof e==`object`?structuredClone(e):null,d=(e,t)=>{let n=u(e)||{},r=u(t)||{};return l(n,r)},f=(e,t)=>l(structuredClone(e.global),t||{}),p=(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 f(e,a)}}return Object.keys(e.global).length>0?f(e,{}):null},m={udp:{port:8089,announcements:{enabled:!0,interval:5e3},requests:{enabled:!0,responseDelay:100}},http:{enabled:!0,path:`/buttress/info`,cors:!0}},h=e=>e?e===!0?{...m}:l(m,e):null,g=(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}))},_=(e,t,n)=>e===void 0?n:typeof e==`number`?e:t(e)??n,v=6e4,y=1024*1024*50,b=a=>{let o=i.machineIdSync(),s={server:{id:`buttress-${o}`,name:`Buttress Server (${o.slice(-8)})`,port:2080,temp_file_dir:e.join(t.tmpdir(),`.buttress`),session_timeout:v,max_body_size:y},autodiscover:!1},c=l(s,u(a)||{}),d=Array.isArray(c.generators)?c.generators:[],{server:f,generators:p,autodiscover:m,...g}=c;return{autodiscover:h(m),server:{id:f.id,name:f.name,port:f.port,log_level:f.log_level,temp_file_dir:f.temp_file_dir,max_body_size:_(f.max_body_size,n.parse,y),session_timeout:_(f.session_timeout,e=>r(e),v)},global:g,generators:d}},x=/^[A-Za-z0-9_-]{1,64}$/,S=n=>n===`~`||n.startsWith(`~/`)?e.join(t.homedir(),n.slice(1)):n;var C=class extends Error{constructor(e){super(`[Agents] ${e}`),this.name=`AgentsConfigError`}};const w=(e,t,n)=>{if(t==null)return n;if(t===0||t===!1)return null;if(typeof t==`number`){if(Number.isFinite(t)&&t>0)return t}else if(typeof t==`string`){let e;try{e=r(t)}catch{e=void 0}if(typeof e==`number`&&e>0)return e}throw new C(`agents_options.${e} must be a duration string (e.g. "30d") or a positive number of milliseconds; use 0 to disable it`)},T=[`direct`,`codemode`,`deferred`,`hidden`],E=new Set([`codemode`,`deferred`]),D=(e,t,n)=>{if(t==null)return{};if(typeof t!=`object`||Array.isArray(t))throw new C(`agent "${e}": mcp_servers must be a table`);let r={};for(let[i,a]of Object.entries(t)){if(!x.test(i))throw new C(`agent "${e}": MCP server name "${i}" must match ${x}`);let t=!!(typeof a?.url==`string`&&a.url),o=!!(typeof a?.command==`string`&&a.command);if(t===o)throw new C(`agent "${e}": MCP server "${i}" needs exactly one of url / command`);let s=`agent "${e}": MCP server "${i}"`;if(a?.timeout!=null&&!(typeof a.timeout==`number`&&a.timeout>0))throw new C(`${s}: timeout must be a positive number of seconds`);let c=a?.tool_exposure;if(c!=null&&(typeof c!=`object`||Array.isArray(c)))throw new C(`${s}: tool_exposure must map tool names to exposures`);for(let e of[a?.exposure,...Object.values(c??{})]){if(e!=null&&!T.includes(e))throw new C(`${s}: exposure must be one of ${T.map(e=>`"${e}"`).join(`, `)}`);if(!n&&E.has(e))throw new C(`${s}: exposure "${e}" needs codemode = true on the agent`)}r[i]={url:t?a.url:void 0,headers:a?.headers&&typeof a.headers==`object`?a.headers:void 0,command:o?a.command:void 0,args:Array.isArray(a?.args)?a.args.map(String):void 0,env:a?.env&&typeof a.env==`object`?a.env:void 0,optional:a?.optional===!0,timeout:a?.timeout??void 0,exposure:a?.exposure??void 0,toolExposure:c??void 0}}return r},O=(e,t,n)=>{let r=e?.name;if(typeof r!=`string`||!x.test(r))throw new C(`[[agents]] #${t+1}: name is required and must match ${x}`);let i=e?.model;if(typeof i!=`string`||!i.includes(`/`))throw new C(`agent "${r}": model must be "provider/model-id" (e.g. "buttress/ggml-org/gpt-oss-20b-GGUF")`);let o=i.indexOf(`/`),s=i.slice(0,o),c=i.slice(o+1);if(!s||!c)throw new C(`agent "${r}": invalid model reference "${i}"`);if(s===`buttress`&&!n.generators.filter(e=>e.type===`ggml-llm`||e.type===`mlx-llm`).some(e=>(e.model?.repo_id||e.model?.repository)===c))throw new C(`agent "${r}": model "${c}" does not match any configured [[generators]] ggml-llm/mlx-llm repo_id`);if(e?.system_prompt!=null&&e?.system_prompt_file!=null)throw new C(`agent "${r}": set system_prompt or system_prompt_file, not both`);let l=[];if(e?.tools!=null){if(!Array.isArray(e.tools))throw new C(`agent "${r}": tools must be an array of function names`);for(let t of e.tools){if(typeof t!=`string`||!x.test(t))throw new C(`agent "${r}": tool name "${t}" must match ${x} (local function names only)`);if(l.includes(t))throw new C(`agent "${r}": duplicate tool "${t}"`);l.push(t)}}if(e?.local_devices!==void 0&&typeof e.local_devices!=`boolean`)throw new C(`agent "${r}": local_devices must be a boolean`);if(e?.codemode!==void 0&&typeof e.codemode!=`boolean`)throw new C(`agent "${r}": codemode must be a boolean`);let u=Number(e?.max_turns??30);if(!Number.isInteger(u)||u<1)throw new C(`agent "${r}": max_turns must be a positive integer`);let d=null;if(e?.max_tokens_per_run!=null&&(d=Number(e.max_tokens_per_run),!Number.isInteger(d)||d<1))throw new C(`agent "${r}": max_tokens_per_run must be a positive integer`);let f=null;if(e?.decision_model!=null&&e.decision_model!==``){let t=e.decision_model,i=typeof t==`string`?t.indexOf(`/`):-1;if(i<=0||i===t.length-1)throw new C(`agent "${r}": decision_model must be "provider/model-id" (e.g. "buttress/<ggml-decision id>" or "typesafe/jev-latest")`);if(f={provider:t.slice(0,i),modelId:t.slice(i+1),modelRef:t},f.provider===`buttress`){let e=n.generators.filter(e=>e.type===`ggml-decision`).map(a);if(!e.includes(f.modelId))throw new C(`agent "${r}": decision_model "${f.modelId}" does not match any configured ggml-decision generator (${e.join(`, `)||`none`})`)}}if(e?.decision_assistance!==void 0&&typeof e.decision_assistance!=`boolean`)throw new C(`agent "${r}": decision_assistance must be a boolean`);if(e?.decision_assistance===!0&&!f)throw new C(`agent "${r}": decision_assistance needs a decision_model`);let p=e?.decision_timeout_ms??500;if(!Number.isInteger(p)||p<1)throw new C(`agent "${r}": decision_timeout_ms must be a positive integer`);let{name:m,model:h,system_prompt:g,system_prompt_file:_,tools:v,local_devices:y=!1,codemode:b=!1,mcp_servers:S,max_turns:w,max_tokens_per_run:T,thinking:E,decision_model:O,decision_assistance:k=!1,decision_timeout_ms:A,...j}=e;return{name:r,provider:s,modelId:c,modelRef:i,systemPrompt:typeof g==`string`?g:null,systemPromptFile:typeof _==`string`?_:null,tools:l,localDevices:y,codemode:b,mcpServers:D(r,S,b),maxTurns:u,maxTokensPerRun:d,thinking:typeof E==`string`?E:void 0,decisionModel:f,decisionAssistance:k,decisionTimeoutMs:p,generation:j}},k=(t,{configDir:n=process.cwd()}={})=>{let r=t.global||{},i=r.agents;if(i==null)return null;if(!Array.isArray(i))throw new C(`agents must be an array of tables ([[agents]])`);if(i.length===0)return null;let a=i.map((e,n)=>O(e,n,t)),o=new Set;for(let e of a){if(o.has(e.name))throw new C(`duplicate agent name "${e.name}"`);o.add(e.name)}let s=r.agents_options||{},c=typeof s.sessions_dir==`string`&&s.sessions_dir?s.sessions_dir:`./.buttress-agent/sessions`,l=S(c),u=e.isAbsolute(l)?l:e.resolve(n,l);for(let t of a)if(t.systemPromptFile){let r=S(t.systemPromptFile);t.systemPromptFile=e.isAbsolute(r)?r:e.resolve(n,r)}let d=Number(s.max_depth??2);if(!Number.isInteger(d)||d<1)throw new C(`agents_options.max_depth must be a positive integer`);let f=s.session_max_count,p=500;if(f===0||f===!1)p=null;else if(f!=null&&(p=Number(f),!Number.isInteger(p)||p<1))throw new C(`agents_options.session_max_count must be a positive integer`);return{agents:a,configDir:n,sessionsDir:u,runtimeTokenFile:e.join(e.dirname(u),`runtime-token`),sessionMaxAgeMs:w(`session_max_age`,s.session_max_age,2592e6),sessionMaxCount:p,maxDepth:d,allowUnauthenticated:s.allow_unauthenticated===!0}};export{b as a,c,s as d,u as i,a as l,k as n,p as o,d as r,g as s,C as t,o as u};