@fugood/buttress-server 2.26.0-beta.17 → 2.26.0-beta.18

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.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import{i as e,r as t,t as n}from"./rolldown-runtime-dTnj95Mm.mjs";import{createHash as r}from"node:crypto";import i from"node:path";import{spawn as a}from"node:child_process";import o from"node:process";import{createServer as s}from"node:http";const c=[`codemode`,`deferred`,`direct`,`hidden`],l={"codemode-deferred":`codemode`},u=[`localhost`,`127.0.0.1`,`[::1]`],d=e=>typeof e==`object`&&!!e&&!Array.isArray(e),f=e=>d(e)&&Object.values(e).every(e=>typeof e==`string`),p=e=>typeof e==`string`?l[e]??e:e,m=e=>c.includes(e);function h(e){return`mcp__${String(e).replace(/[^A-Za-z0-9_]/g,`_`)}`}const ee=e=>RegExp(`^${e.split(`*`).map(e=>e.replace(/[.+?^${}()|[\]\\]/g,`\\$&`)).join(`.*`)}$`);function g(e,t,n=`deferred`){let r=d(e?.toolExposure)?e.toolExposure:{},i=Object.hasOwn(r,t)?r[t]:void 0;if(i!==void 0)return i;for(let[e,n]of Object.entries(r))if(e.includes(`*`)&&ee(e).test(t))return n;return e?.exposure??n}const te=e=>{if(!URL.canParse(e))return!1;let t=new URL(e);return t.protocol===`http:`&&u.includes(t.hostname)&&t.search===``&&t.hash===``};function ne(e){if(e===void 0)return;if(!d(e))return`oauth must be an object`;for(let t of[`clientId`,`clientSecret`,`scope`])if(e[t]!==void 0&&typeof e[t]!=`string`)return`oauth.${t} must be a string`;let t=e.callbackPort;if(t!==void 0&&(typeof t!=`number`||!Number.isInteger(t)||t<1||t>65535))return`oauth.callbackPort must be a port number`;if(e.callbackUrl!==void 0){if(typeof e.callbackUrl!=`string`||!te(e.callbackUrl))return`oauth.callbackUrl must be an http URI on localhost, 127.0.0.1, or [::1] without query or fragment`;let n=new URL(e.callbackUrl).port;if(n&&t!==void 0&&Number(n)!==t)return`oauth.callbackUrl and oauth.callbackPort name different ports`}if(e.clientName!==void 0&&(typeof e.clientName!=`string`||!e.clientName.trim()))return`oauth.clientName must be a non-empty string`;let n=e.authServerMetadataUrl;if(n!==void 0){let e=typeof n==`string`&&URL.canParse(n)?new URL(n):null;if(!(e&&(e.protocol===`https:`||e.protocol===`http:`&&u.includes(e.hostname))))return`oauth.authServerMetadataUrl must be an https URL, or http on localhost, 127.0.0.1, or [::1]`}}function re(e,t){if(typeof e!=`string`||!e)return`server names must be non-empty strings`;if(!d(t))return`server "${e}" must be an object`;let n={...t};n.exposure!==void 0&&(n.exposure=p(n.exposure)),d(n.toolExposure)&&(n.toolExposure=Object.fromEntries(Object.entries(n.toolExposure).map(([e,t])=>[e,p(t)])));let r=c.map(e=>`"${e}"`).join(`, `);if(n.exposure!==void 0&&!m(n.exposure))return`server "${e}": exposure must be one of ${r}`;if(n.toolExposure!==void 0){if(!d(n.toolExposure))return`server "${e}": toolExposure must map tool names to exposures`;for(let[t,i]of Object.entries(n.toolExposure))if(!m(i))return`server "${e}": toolExposure "${t}" must be one of ${r}`}if(n.enabled!==void 0&&typeof n.enabled!=`boolean`)return`server "${e}": enabled must be a boolean`;if(n.description!==void 0&&typeof n.description!=`string`)return`server "${e}": description must be a string`;if(n.timeout!==void 0&&(typeof n.timeout!=`number`||!(n.timeout>0)))return`server "${e}": timeout must be a positive number of seconds`;let{type:i}=n;if(i===`sse`)return`server "${e}": the legacy SSE transport is not supported; use the streamable HTTP URL`;if(typeof n.url==`string`&&(i===void 0||i===`http`||i===`streamable-http`)){if(!URL.canParse(n.url)||!/^https?:$/.test(new URL(n.url).protocol))return`server "${e}": url must be an http or https URL`;if(n.headers!==void 0&&!f(n.headers))return`server "${e}": headers must map names to strings`;let t=ne(n.oauth);return t?`server "${e}": ${t}`:n}return typeof n.command==`string`&&(i===void 0||i===`stdio`)?n.args!==void 0&&!(Array.isArray(n.args)&&n.args.every(e=>typeof e==`string`))?`server "${e}": args must be an array of strings`:n.env!==void 0&&!f(n.env)?`server "${e}": env must map names to strings`:n.cwd!==void 0&&typeof n.cwd!=`string`?`server "${e}": cwd must be a string`:n:`server "${e}" needs either "command" (stdio) or "url" (streamable HTTP)`}const _={parseError:-32700,invalidRequest:-32600,methodNotFound:-32601,invalidParams:-32602,internalError:-32603};var v=class extends Error{code;data;constructor(e,t,n){super(t),this.name=`McpError`,this.code=e,this.data=n}},y=class extends Error{constructor(e=`MCP connection closed`){super(e),this.name=`McpConnectionClosedError`}},ie=class extends Error{timeoutMs;constructor(e){super(`MCP request timed out after ${e}ms`),this.name=`McpTimeoutError`,this.timeoutMs=e}},ae=class extends Error{constructor(e=`MCP request aborted`){super(e),this.name=`AbortError`}};function b(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function x(e){return e instanceof Error?e:Error(String(e))}function S(e){return typeof e==`string`||typeof e==`number`&&Number.isFinite(e)}function C(e){return b(e)&&e.jsonrpc===`2.0`&&S(e.id)&&typeof e.method==`string`}function w(e){return b(e)&&e.jsonrpc===`2.0`&&!(`id`in e)&&typeof e.method==`string`}function T(e){return!b(e)||e.jsonrpc!==`2.0`||!S(e.id)?!1:`result`in e?!(`error`in e):!(`error`in e)||!b(e.error)?!1:typeof e.error.code==`number`&&typeof e.error.message==`string`}function E(e){if(C(e)||w(e)||T(e))return e;throw new v(_.invalidRequest,`Invalid JSON-RPC message`)}const oe=`2025-11-25`,se=[oe,`2025-06-18`,`2025-03-26`,`2024-11-05`],ce=1e3;function le(e){if(!b(e)||typeof e.protocolVersion!=`string`||!b(e.capabilities)||!b(e.serverInfo)||typeof e.serverInfo.name!=`string`||typeof e.serverInfo.version!=`string`||e.instructions!==void 0&&typeof e.instructions!=`string`)throw new v(_.invalidRequest,`Invalid MCP initialize result`);return e}function D(e){return new v(_.invalidRequest,e)}function ue(e,t,n,r){let i=b(n)?n[t]:void 0;if(!b(n)||!Array.isArray(i))throw D(`Invalid MCP ${e} result`);for(let t of i)if(!b(t)||!r(t))throw D(`Invalid entry in MCP ${e} result`);let a=n.nextCursor===null||n.nextCursor===``?void 0:n.nextCursor;if(a!==void 0&&typeof a!=`string`)throw D(`Invalid MCP ${e} cursor`);return{items:i,...a===void 0?{}:{nextCursor:a}}}const de=e=>typeof e.name==`string`&&b(e.inputSchema),fe=e=>typeof e.uri==`string`&&(e.name===void 0||typeof e.name==`string`),pe=e=>typeof e.uriTemplate==`string`&&(e.name===void 0||typeof e.name==`string`);function me(e){return{...e,name:e.name??e.uri}}function he(e){return{...e,name:e.name??e.uriTemplate}}function ge(e){return e.nextCursor===void 0?{}:{nextCursor:e.nextCursor}}function _e(e){if(!b(e)||!Array.isArray(e.contents))throw D(`Invalid MCP resources/read result`);for(let t of e.contents)if(!b(t)||typeof t.uri!=`string`||typeof t.text!=`string`&&typeof t.blob!=`string`)throw D(`Invalid contents in MCP resources/read result`);return e}function ve(e){if(!b(e)||e.content!==void 0&&!Array.isArray(e.content))throw new v(_.invalidRequest,`Invalid MCP tools/call result`);if(e.structuredContent!==void 0&&!b(e.structuredContent))throw new v(_.invalidRequest,`Invalid MCP tools/call structured content`);return e.content===void 0?{...e,content:[]}:e}var ye=class{options;state=`idle`;transport;nextRequestId=1;serverInfoValue;serverCapabilitiesValue;instructionsValue;protocolVersionValue;pending=new Map;progressRequests=new Map;incoming=new Map;requestHandlers=new Map;notificationListeners=new Map;errorListeners=new Set;closeListeners=new Set;disposers=[];constructor(e){this.options=Object.freeze({...e}),this.requestHandlers.set(`ping`,()=>({}));let t=e.roots;t&&this.requestHandlers.set(`roots/list`,async()=>({roots:[...typeof t==`function`?await t():t]}))}get connectionState(){return this.state}get serverInfo(){return this.serverInfoValue}get serverCapabilities(){return this.serverCapabilitiesValue}get instructions(){return this.instructionsValue}get protocolVersion(){return this.protocolVersionValue}async connect(e){if(this.state!==`idle`)throw Error(`Cannot connect MCP client in ${this.state} state`);this.state=`connecting`,this.transport=e,this.disposers=[e.onMessage(e=>this.handleMessage(e)),e.onError(e=>this.emitError(e)),e.onClose(()=>this.handleTransportClose())];try{await e.start();let t={...this.options.capabilities};this.options.roots&&t.roots===void 0&&(t.roots={});let n=le(await this.requestInternal(`initialize`,{protocolVersion:this.options.protocolVersion??`2025-11-25`,capabilities:t,clientInfo:{name:this.options.name,version:this.options.version,...this.options.title===void 0?{}:{title:this.options.title}}},{},!0));if(!se.includes(n.protocolVersion))throw Error(`MCP server selected unsupported protocol version ${n.protocolVersion}`);return this.protocolVersionValue=n.protocolVersion,this.serverInfoValue=n.serverInfo,this.serverCapabilitiesValue=n.capabilities,this.instructionsValue=n.instructions,e.setProtocolVersion?.(n.protocolVersion),await this.notifyInternal(`notifications/initialized`,void 0,!0),this.state=`connected`,n}catch(e){throw await this.close().catch(()=>{}),e}}request(e,t,n={}){return this.requestInternal(e,t,n,!1)}notify(e,t){return this.notifyInternal(e,t,!1)}setRequestHandler(e,t){return this.requestHandlers.set(e,t),()=>{this.requestHandlers.get(e)===t&&this.requestHandlers.delete(e)}}onNotification(e,t){let n=this.notificationListeners.get(e)??new Set;return this.notificationListeners.set(e,n),n.add(t),()=>{n.delete(t),n.size===0&&this.notificationListeners.delete(e)}}onError(e){return this.errorListeners.add(e),()=>this.errorListeners.delete(e)}onClose(e){return this.closeListeners.add(e),()=>this.closeListeners.delete(e)}async ping(e={}){await this.request(`ping`,void 0,e)}async listTools(e={}){return await this.listAll(`tools/list`,`tools`,de,e)}async listResources(e={}){return(await this.listAll(`resources/list`,`resources`,fe,e)).map(me)}async listResourcesPage(e,t={}){let n=await this.listPage(`resources/list`,`resources`,fe,e,t);return{resources:n.items.map(me),...ge(n)}}async listResourceTemplates(e={}){return(await this.listAll(`resources/templates/list`,`resourceTemplates`,pe,e)).map(he)}async listResourceTemplatesPage(e,t={}){let n=await this.listPage(`resources/templates/list`,`resourceTemplates`,pe,e,t);return{resourceTemplates:n.items.map(he),...ge(n)}}async readResource(e,t={}){return _e(await this.request(`resources/read`,{uri:e},t))}async listPage(e,t,n,r,i){return ue(e,t,await this.request(e,r===void 0?void 0:{cursor:r},i),n)}async listAll(e,t,n,r){let i=[],a=new Set,o;for(let s=0;s<ce;s++){let s=await this.listPage(e,t,n,o,r);if(i.push(...s.items),s.nextCursor===void 0)return i;if(a.has(s.nextCursor))throw Error(`MCP ${e} returned duplicate cursor: ${s.nextCursor}`);a.add(s.nextCursor),o=s.nextCursor}throw Error(`MCP ${e} exceeded ${ce} pages`)}async callTool(e,t,n={}){return ve(await this.request(`tools/call`,{name:e,...t===void 0?{}:{arguments:t}},n))}async close(){let e=this.transport;this.transport=void 0,this.disposeTransportListeners(),this.markClosed(new y),await e?.close()}async requestInternal(e,t,n,r){let i=this.requireTransport(r);if(n.signal?.aborted)throw new ae;let a=this.nextRequestId++,o=n.onProgress?a:void 0,s=o===void 0?t:{...t,_meta:{...b(t?._meta)?t._meta:{},progressToken:o}},c={jsonrpc:`2.0`,id:a,method:e,...s===void 0?{}:{params:s}};return new Promise((t,r)=>{let s={resolve:t,reject:r,timeoutMs:n.timeoutMs??this.options.requestTimeoutMs??3e4,timer:void 0,signal:n.signal,onAbort:()=>this.cancelPending(a,new ae,e!==`initialize`,String(n.signal?.reason??`Aborted`)),cancellable:e!==`initialize`,onProgress:n.onProgress,progressToken:o};this.pending.set(a,s),o!==void 0&&this.progressRequests.set(o,a),n.signal?.addEventListener(`abort`,s.onAbort,{once:!0}),this.armTimeout(a,s),i.send(c).catch(e=>this.cancelPending(a,e,!1))})}async notifyInternal(e,t,n){await this.requireTransport(n).send({jsonrpc:`2.0`,method:e,...t===void 0?{}:{params:t}})}requireTransport(e){if(this.transport&&(this.state===`connected`||e&&this.state===`connecting`))return this.transport;throw new y(`MCP client is ${this.state}`)}handleMessage(e){if(T(e)){this.handleResponse(e);return}if(C(e)){this.handleRequest(e);return}if(w(e)){this.handleNotification(e.method,e.params);return}this.emitError(new v(_.invalidRequest,`Received invalid JSON-RPC message`))}handleResponse(e){let t=this.pending.get(e.id);if(!t){this.emitError(Error(`Received response for unknown MCP request ${String(e.id)}`));return}this.removePending(e.id,t),`error`in e?t.reject(new v(e.error.code,e.error.message,e.error.data)):t.resolve(e.result)}async handleRequest(e){let t=this.transport;if(!t)return;let n=this.requestHandlers.get(e.method);if(!n){await t.send({jsonrpc:`2.0`,id:e.id,error:{code:_.methodNotFound,message:`Method not found: ${e.method}`}}).catch(e=>this.emitError(e));return}let r=new AbortController;this.incoming.set(e.id,r);try{let i=await n(e.params,{signal:r.signal});await t.send({jsonrpc:`2.0`,id:e.id,result:i??{}})}catch(n){let r=n instanceof v?{code:n.code,message:n.message,data:n.data}:{code:_.internalError,message:x(n).message};await t.send({jsonrpc:`2.0`,id:e.id,error:r}).catch(e=>this.emitError(e))}finally{this.incoming.delete(e.id)}}handleNotification(e,t){e===`notifications/progress`?this.handleProgress(t):e===`notifications/cancelled`&&this.handleCancelled(t);for(let n of this.notificationListeners.get(e)??[])try{n(t)}catch(e){this.emitError(e)}}handleProgress(e){if(!b(e)||!S(e.progressToken)||typeof e.progress!=`number`)return;let t=this.progressRequests.get(e.progressToken),n=t===void 0?void 0:this.pending.get(t);if(!(t===void 0||!n)){this.armTimeout(t,n);try{n.onProgress?.(e)}catch(e){this.emitError(e)}}}handleCancelled(e){b(e)&&S(e.requestId)&&this.incoming.get(e.requestId)?.abort(e.reason)}armTimeout(e,t){t.timer&&clearTimeout(t.timer),!(!Number.isFinite(t.timeoutMs)||t.timeoutMs<=0)&&(t.timer=setTimeout(()=>{this.cancelPending(e,new ie(t.timeoutMs),t.cancellable,`Request timed out`)},t.timeoutMs))}cancelPending(e,t,n,r){let i=this.pending.get(e);i&&(this.removePending(e,i),i.reject(t),n&&this.transport&&this.transport.send({jsonrpc:`2.0`,method:`notifications/cancelled`,params:{requestId:e,...r?{reason:r}:{}}}).catch(e=>this.emitError(e)))}removePending(e,t){this.pending.delete(e),t.timer&&clearTimeout(t.timer),t.progressToken!==void 0&&this.progressRequests.delete(t.progressToken),t.signal?.removeEventListener(`abort`,t.onAbort)}rejectPending(e){for(let[t,n]of this.pending)this.removePending(t,n),n.reject(e)}handleTransportClose(){this.markClosed(new y)}markClosed(e){let t=this.state===`closed`;this.state=`closed`,this.rejectPending(e);for(let t of this.incoming.values())t.abort(e);if(this.incoming.clear(),!t)for(let e of[...this.closeListeners])try{e()}catch(e){this.emitError(e)}}emitError(e){let t=x(e);for(let e of this.errorListeners)e(t)}disposeTransportListeners(){for(let e of this.disposers.splice(0))e()}};function be(e){switch(e.type){case`text`:return{type:`text`,text:e.text};case`image`:return{type:`image`,data:e.data,mimeType:e.mimeType};case`audio`:return{type:`text`,text:`[audio ${e.mimeType} omitted]`};case`resource_link`:return{type:`text`,text:`${e.name}: ${e.uri}`};case`resource`:{let t=e.resource;return`text`in t?{type:`text`,text:t.text}:t.mimeType?.startsWith(`image/`)?{type:`image`,data:t.blob,mimeType:t.mimeType}:{type:`text`,text:`[binary resource ${t.uri} (${t.mimeType??`unknown type`}) omitted]`}}default:return{type:`text`,text:`[unsupported MCP content ${e.type}]`}}}function xe(e){let t=(e.content??[]).map(be);return t.length===0&&e.structuredContent!==void 0&&t.push({type:`text`,text:JSON.stringify(e.structuredContent,null,2)}),t}var Se=n(((e,n)=>{n.exports=o,o.sync=s;var r=t(`fs`);function i(e,t){var n=t.pathExt===void 0?process.env.PATHEXT:t.pathExt;if(!n||(n=n.split(`;`),n.indexOf(``)!==-1))return!0;for(var r=0;r<n.length;r++){var i=n[r].toLowerCase();if(i&&e.substr(-i.length).toLowerCase()===i)return!0}return!1}function a(e,t,n){return!e.isSymbolicLink()&&!e.isFile()?!1:i(t,n)}function o(e,t,n){r.stat(e,function(r,i){n(r,!r&&a(i,e,t))})}function s(e,t){return a(r.statSync(e),e,t)}})),Ce=n(((e,n)=>{n.exports=i,i.sync=a;var r=t(`fs`);function i(e,t,n){r.stat(e,function(e,r){n(e,!e&&o(r,t))})}function a(e,t){return o(r.statSync(e),t)}function o(e,t){return e.isFile()&&s(e,t)}function s(e,t){var n=e.mode,r=e.uid,i=e.gid,a=t.uid===void 0?process.getuid&&process.getuid():t.uid,o=t.gid===void 0?process.getgid&&process.getgid():t.gid,s=64,c=8,l=1,u=s|c;return n&l||n&c&&i===o||n&s&&r===a||n&u&&a===0}})),we=n(((e,n)=>{t(`fs`);var r=process.platform===`win32`||global.TESTING_WINDOWS?Se():Ce();n.exports=i,i.sync=a;function i(e,t,n){if(typeof t==`function`&&(n=t,t={}),!n){if(typeof Promise!=`function`)throw TypeError(`callback not provided`);return new Promise(function(n,r){i(e,t||{},function(e,t){e?r(e):n(t)})})}r(e,t||{},function(e,r){e&&(e.code===`EACCES`||t&&t.ignoreErrors)&&(e=null,r=!1),n(e,r)})}function a(e,t){try{return r.sync(e,t||{})}catch(e){if(t&&t.ignoreErrors||e.code===`EACCES`)return!1;throw e}}})),Te=n(((e,n)=>{let r=process.platform===`win32`||process.env.OSTYPE===`cygwin`||process.env.OSTYPE===`msys`,i=t(`path`),a=r?`;`:`:`,o=we(),s=e=>Object.assign(Error(`not found: ${e}`),{code:`ENOENT`}),c=(e,t)=>{let n=t.colon||a,i=e.match(/\//)||r&&e.match(/\\/)?[``]:[...r?[process.cwd()]:[],...(t.path||process.env.PATH||``).split(n)],o=r?t.pathExt||process.env.PATHEXT||`.EXE;.CMD;.BAT;.COM`:``,s=r?o.split(n):[``];return r&&e.indexOf(`.`)!==-1&&s[0]!==``&&s.unshift(``),{pathEnv:i,pathExt:s,pathExtExe:o}},l=(e,t,n)=>{typeof t==`function`&&(n=t,t={}),t||={};let{pathEnv:r,pathExt:a,pathExtExe:l}=c(e,t),u=[],d=n=>new Promise((a,o)=>{if(n===r.length)return t.all&&u.length?a(u):o(s(e));let c=r[n],l=/^".*"$/.test(c)?c.slice(1,-1):c,d=i.join(l,e),p=!l&&/^\.[\\\/]/.test(e)?e.slice(0,2)+d:d;a(f(p,n,0))}),f=(e,n,r)=>new Promise((i,s)=>{if(r===a.length)return i(d(n+1));let c=a[r];o(e+c,{pathExt:l},(a,o)=>{if(!a&&o)if(t.all)u.push(e+c);else return i(e+c);return i(f(e,n,r+1))})});return n?d(0).then(e=>n(null,e),n):d(0)};n.exports=l,l.sync=(e,t)=>{t||={};let{pathEnv:n,pathExt:r,pathExtExe:a}=c(e,t),l=[];for(let s=0;s<n.length;s++){let c=n[s],u=/^".*"$/.test(c)?c.slice(1,-1):c,d=i.join(u,e),f=!u&&/^\.[\\\/]/.test(e)?e.slice(0,2)+d:d;for(let e=0;e<r.length;e++){let n=f+r[e];try{if(o.sync(n,{pathExt:a}))if(t.all)l.push(n);else return n}catch{}}}if(t.all&&l.length)return l;if(t.nothrow)return null;throw s(e)}})),Ee=n(((e,t)=>{let n=(e={})=>{let t=e.env||process.env;return(e.platform||process.platform)===`win32`?Object.keys(t).reverse().find(e=>e.toUpperCase()===`PATH`)||`Path`:`PATH`};t.exports=n,t.exports.default=n})),De=n(((e,n)=>{let r=t(`path`),i=Te(),a=Ee();function o(e,t){let n=e.options.env||process.env,o=process.cwd(),s=e.options.cwd!=null,c=s&&process.chdir!==void 0&&!process.chdir.disabled;if(c)try{process.chdir(e.options.cwd)}catch{}let l;try{l=i.sync(e.command,{path:n[a({env:n})],pathExt:t?r.delimiter:void 0})}catch{}finally{c&&process.chdir(o)}return l&&=r.resolve(s?e.options.cwd:``,l),l}function s(e){return o(e)||o(e,!0)}n.exports=s})),Oe=n(((e,t)=>{let n=/([()\][%!^"`<>&|;, *?])/g;function r(e){return e=e.replace(n,`^$1`),e}function i(e,t){return e=`${e}`,e=e.replace(/(?=(\\+?)?)\1"/g,`$1$1\\"`),e=e.replace(/(?=(\\+?)?)\1$/,`$1$1`),e=`"${e}"`,e=e.replace(n,`^$1`),t&&(e=e.replace(n,`^$1`)),e}t.exports.command=r,t.exports.argument=i})),ke=n(((e,t)=>{t.exports=/^#!(.*)/})),Ae=n(((e,t)=>{let n=ke();t.exports=(e=``)=>{let t=e.match(n);if(!t)return null;let[r,i]=t[0].replace(/#! ?/,``).split(` `),a=r.split(`/`).pop();return a===`env`?i:i?`${a} ${i}`:a}})),je=n(((e,n)=>{let r=t(`fs`),i=Ae();function a(e){let t=Buffer.alloc(150),n;try{n=r.openSync(e,`r`),r.readSync(n,t,0,150,0),r.closeSync(n)}catch{}return i(t.toString())}n.exports=a})),Me=n(((e,n)=>{let r=t(`path`),i=De(),a=Oe(),o=je(),s=process.platform===`win32`,c=/\.(?:com|exe)$/i,l=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function u(e){e.file=i(e);let t=e.file&&o(e.file);return t?(e.args.unshift(e.file),e.command=t,i(e)):e.file}function d(e){if(!s)return e;let t=u(e),n=!c.test(t);if(e.options.forceShell||n){let n=l.test(t);e.command=r.normalize(e.command),e.command=a.command(e.command),e.args=e.args.map(e=>a.argument(e,n)),e.args=[`/d`,`/s`,`/c`,`"${[e.command].concat(e.args).join(` `)}"`],e.command=process.env.comspec||`cmd.exe`,e.options.windowsVerbatimArguments=!0}return e}function f(e,t,n){t&&!Array.isArray(t)&&(n=t,t=null),t=t?t.slice(0):[],n=Object.assign({},n);let r={command:e,args:t,options:n,file:void 0,original:{command:e,args:t}};return n.shell?r:d(r)}n.exports=f})),Ne=n(((e,t)=>{let n=process.platform===`win32`;function r(e,t){return Object.assign(Error(`${t} ${e.command} ENOENT`),{code:`ENOENT`,errno:`ENOENT`,syscall:`${t} ${e.command}`,path:e.command,spawnargs:e.args})}function i(e,t){if(!n)return;let r=e.emit;e.emit=function(n,i){if(n===`exit`){let n=a(i,t);if(n)return r.call(e,`error`,n)}return r.apply(e,arguments)}}function a(e,t){return n&&e===1&&!t.file?r(t.original,`spawn`):null}function o(e,t){return n&&e===1&&!t.file?r(t.original,`spawnSync`):null}t.exports={hookChildProcess:i,verifyENOENT:a,verifyENOENTSync:o,notFoundError:r}})),Pe=n(((e,n)=>{let r=t(`child_process`),i=Me(),a=Ne();function o(e,t,n){let o=i(e,t,n),s=r.spawn(o.command,o.args,o.options);return a.hookChildProcess(s,o),s}function s(e,t,n){let o=i(e,t,n),s=r.spawnSync(o.command,o.args,o.options);return s.error=s.error||a.verifyENOENTSync(s.status,o),s}n.exports=o,n.exports.spawn=o,n.exports.sync=s,n.exports._parse=i,n.exports._enoent=a})),Fe=class{messageListeners=new Set;errorListeners=new Set;closeListeners=new Set;closeEmitted=!1;onMessage(e){return this.messageListeners.add(e),()=>this.messageListeners.delete(e)}onError(e){return this.errorListeners.add(e),()=>this.errorListeners.delete(e)}onClose(e){return this.closeListeners.add(e),()=>this.closeListeners.delete(e)}emitMessage(e){for(let t of this.messageListeners)t(e)}emitError(e){let t=x(e);for(let e of this.errorListeners)e(t)}emitClose(){if(!this.closeEmitted){this.closeEmitted=!0;for(let e of this.closeListeners)e()}}},Ie=e(Pe(),1);const O=o.platform!==`win32`,k=new Set;let Le=!1;function A(e,t){let n=e.pid;if(o.platform===`win32`&&n!==void 0){if(e.exitCode!==null)return;a(`taskkill`,[`/pid`,String(n),`/T`,`/F`],{stdio:`ignore`,windowsHide:!0}).on(`error`,()=>{});return}if(O&&n!==void 0)try{o.kill(-n,t);return}catch{}try{e.kill(t)}catch{}}function Re(){Le||(Le=!0,o.once(`exit`,()=>{for(let e of k)try{o.kill(-e,`SIGTERM`)}catch{}}))}var ze=class extends Fe{options;child;stdoutBuffer=Buffer.alloc(0);stderrBuffer=Buffer.alloc(0);started=!1;closed=!1;constructor(e){super(),this.options=Object.freeze({...e,args:e.args?[...e.args]:void 0})}get pid(){return this.child?.pid}get stderr(){return this.stderrBuffer.toString(`utf8`)}async start(){if(this.started)throw Error(`MCP stdio transport already started`);if(this.closed)throw new y;this.started=!0;let e=this.options.inheritEnv===!1?{...this.options.env}:{...o.env,...this.options.env},t=(0,Ie.default)(this.options.command,this.options.args??[],{cwd:this.options.cwd,env:e,stdio:[`pipe`,`pipe`,this.options.stderr===`inherit`?`inherit`:`pipe`],windowsHide:!0,detached:O});this.child=t;let n=t.pid;O&&n!==void 0&&(Re(),k.add(n),t.once(`exit`,()=>k.delete(n))),t.stdout?.on(`data`,e=>this.handleStdout(e)),t.stdout?.on(`error`,e=>this.emitError(e)),t.stdin?.on(`error`,e=>{this.closed||this.emitError(e)}),t.stderr?.on(`data`,e=>this.handleStderr(e)),t.stderr?.on(`error`,e=>this.emitError(e)),t.on(`close`,()=>{this.child=void 0,this.stdoutBuffer.toString(`utf8`).trim()&&this.emitError(Error(`MCP stdio server closed with an incomplete JSON-RPC message`)),this.stdoutBuffer=Buffer.alloc(0),this.emitClose()}),await new Promise((e,n)=>{let r=()=>{t.off(`error`,i),e()},i=e=>{t.off(`spawn`,r),n(e)};t.once(`spawn`,r),t.once(`error`,i)}),t.on(`error`,e=>{this.closed||this.emitError(e)})}async send(e){let t=this.child?.stdin;if(!this.started||this.closed||!t?.writable)throw new y;let n=`${JSON.stringify(e)}\n`;await new Promise((e,r)=>{t.write(n,t=>t?r(t):e())})}async close(){if(this.closed)return;this.closed=!0;let e=this.child;if(!e){this.emitClose();return}if(e.exitCode!==null||e.signalCode!==null){e.stdin?.end();return}let t=this.options.closeTimeoutMs??2e3;await new Promise(n=>{let r=[];e.once(`close`,()=>{for(let e of r)clearTimeout(e);A(e,`SIGTERM`),n()});let i=Math.min(500,t);r.push(setTimeout(()=>A(e,`SIGTERM`),i)),r.push(setTimeout(()=>A(e,`SIGKILL`),i+t)),e.stdin?.end()})}handleStdout(e){this.stdoutBuffer=Buffer.concat([this.stdoutBuffer,Buffer.isBuffer(e)?e:Buffer.from(e)]);let t=this.options.maxMessageBytes??16777216;for(;;){let e=this.stdoutBuffer.indexOf(10);if(e<0){this.stdoutBuffer.length>t&&(this.stdoutBuffer=Buffer.alloc(0),this.emitError(Error(`MCP stdio message exceeds ${t} bytes`)));return}let n=this.stdoutBuffer.subarray(0,e);if(this.stdoutBuffer=this.stdoutBuffer.subarray(e+1),n.length>t){this.emitError(Error(`MCP stdio message exceeds ${t} bytes`));continue}let r=n.toString(`utf8`).replace(/\r$/,``);if(r.trim())try{this.emitMessage(E(JSON.parse(r)))}catch(e){this.emitError(e)}}}handleStderr(e){let t=Buffer.isBuffer(e)?e:Buffer.from(e),n=this.options.maxStderrBytes??65536;this.stderrBuffer=Buffer.concat([this.stderrBuffer,t]),this.stderrBuffer.length>n&&(this.stderrBuffer=this.stderrBuffer.subarray(-n)),this.options.onStderr?.(t.toString(`utf8`))}};async function Be(e,t){let n=e.getReader(),r=new TextDecoder,i=``,a,o,s=[],c=0,l=t.maxEventBytes??16777216,u=()=>{if(s.length===0){a=void 0,o=void 0;return}let e=s.join(`
3
+ `);t.onEvent({...a?{event:a}:{},data:e,...o?{id:o}:{}}),a=void 0,o=void 0,s=[],c=0},d=e=>{let n=e.endsWith(`\r`)?e.slice(0,-1):e;if(n===``){u();return}if(n.startsWith(`:`))return;let r=n.indexOf(`:`),i=r<0?n:n.slice(0,r),d=r<0?``:n.slice(r+1);if(d.startsWith(` `)&&(d=d.slice(1)),i===`data`){if(c+=Buffer.byteLength(d)+ +(s.length>0),c>l)throw Error(`MCP SSE event exceeds ${l} bytes`);s.push(d)}else i===`event`?a=d:i===`id`&&!d.includes(`\0`)?(o=d,t.onId?.(d)):i===`retry`&&/^\d+$/.test(d)&&t.onRetry?.(Number(d))};try{for(;;){let{done:e,value:t}=await n.read();if(e)break;i+=r.decode(t,{stream:!0});let a=i.indexOf(`
4
+ `);for(;a>=0;)d(i.slice(0,a)),i=i.slice(a+1),a=i.indexOf(`
5
+ `);if(Buffer.byteLength(i)>l)throw Error(`MCP SSE event exceeds ${l} bytes`)}i+=r.decode(),i&&d(i),u()}finally{n.releaseLock()}}var j=class extends Error{status;body;constructor(e,t,n=``){super(t),this.name=`McpHttpError`,this.status=e,this.body=n}},Ve=class extends j{wwwAuthenticate;constructor(e,t=``){super(401,`MCP server requires authentication`,t),this.name=`McpAuthRequiredError`,this.wwwAuthenticate=e.headers.get(`www-authenticate`)}},He=class extends j{constructor(e=``){super(404,`MCP session expired`,e),this.name=`McpSessionExpiredError`}};function Ue(e){return e.headers.get(`content-type`)?.split(`;`,1)[0]?.trim().toLowerCase()}function We(e){return e.status===401||e.status===403&&/(?:^|[\s,])error="?insufficient_scope"?/i.test(e.headers.get(`www-authenticate`)??``)}function Ge(e){return e===408||e===429||e>=500}function M(e){return e.body?.cancel().catch(()=>{})??Promise.resolve()}function Ke(e,t){let n=t.trim(),r=n.length>500?`${n.slice(0,497)}...`:n;return`MCP HTTP request failed with status ${e}${r?`: ${r}`:``}`}var qe=class extends Fe{url;options;fetch;controller=new AbortController;started=!1;closed=!1;sessionIdValue;protocolVersion;getStreamStarted=!1;constructor(e){super(),this.options=Object.freeze({...e,headers:e.headers?{...e.headers}:void 0}),this.url=new URL(e.url);let t=e.fetch??globalThis.fetch;this.fetch=(e,n)=>t(e,n)}get sessionId(){return this.sessionIdValue}async start(){if(this.started)throw Error(`MCP Streamable HTTP transport already started`);if(this.closed)throw new y;this.started=!0}setProtocolVersion(e){this.protocolVersion=e}async send(e){if(!this.started||this.closed)throw new y;let t=await this.authorizedFetch(`POST`,{headers:{accept:`application/json, text/event-stream`,"content-type":`application/json`},body:JSON.stringify(e)});if(await this.checkResponse(t),this.captureSession(t),!C(e)){await M(t),`method`in e&&e.method===`notifications/initialized`&&this.startGetStream();return}if(t.status===202||t.status===204)throw new j(t.status,`MCP server accepted request ${e.method} without a response`);let n=Ue(t);if(n===`application/json`){let e=await t.json();for(let t of Array.isArray(e)?e:[e])this.emitMessage(E(t));return}if(n===`text/event-stream`&&t.body){this.consumeResponseStream(t.body,e.id);return}throw await M(t),new j(t.status,`Unsupported MCP response content type: ${n??`missing`}`)}async close(){if(!this.closed){if(this.closed=!0,this.controller.abort(),this.started&&this.sessionIdValue){let e=new AbortController,t=setTimeout(()=>e.abort(),1e3);try{let{headers:t}=await this.headers();await this.fetch(this.url,{method:`DELETE`,headers:t,signal:e.signal}).then(M).catch(()=>void 0)}catch{}finally{clearTimeout(t)}}this.emitClose()}}async authorizedFetch(e,t){let n=this.options.authProvider?.onUnauthorized?.bind(this.options.authProvider);for(let r=0;;r++){let{headers:i,token:a}=await this.headers(t.headers),o=await this.fetch(this.url,{method:e,headers:i,body:t.body,signal:this.controller.signal});if(r>0||!n||!We(o))return o;try{await n({response:o,serverUrl:this.url,fetch:this.fetch,token:a})}finally{await M(o)}}}async headers(e={}){let t=new Headers(this.options.headers);for(let[n,r]of Object.entries(e))t.set(n,r);this.sessionIdValue&&t.set(`Mcp-Session-Id`,this.sessionIdValue),this.protocolVersion&&t.set(`MCP-Protocol-Version`,this.protocolVersion);let n=await this.options.authProvider?.token();return n&&t.set(`Authorization`,`Bearer ${n}`),{headers:t,...n?{token:n}:{}}}captureSession(e){let t=e.headers.get(`mcp-session-id`);t&&(this.sessionIdValue=t)}async checkResponse(e){if(e.ok)return;let t=(await e.text().catch(()=>``)).slice(0,8192);throw e.status===401?new Ve(e,t):e.status===404&&this.sessionIdValue?new He(t):new j(e.status,Ke(e.status,t),t)}async consumeSse(e,t,n){await Be(e,{maxEventBytes:this.options.maxMessageBytes??16777216,onId:e=>{t.lastEventId=e},onRetry:e=>{t.retryMs=e},onEvent:e=>{if(t.received=!0,!e.data.trim()||e.event!==void 0&&e.event!==`message`)return;let r;try{r=E(JSON.parse(e.data))}catch(e){this.emitError(e);return}n?.(r),this.emitMessage(r)}})}async consumeResponseStream(e,t){let n={lastEventId:void 0,retryMs:void 0,received:!1},r=!1,i=e=>{T(e)&&e.id===t&&(r=!0)},a=e,o;for(let e=0;;){if(a)try{await this.consumeSse(a,n,i),o=void 0}catch(e){o=e}if(r||this.closed)return;if(o!==void 0&&!this.isRetryable(o)||n.lastEventId===void 0||e>=this.maxRetries())break;if(n.received&&(e=0),n.received=!1,!await this.sleep(this.reconnectDelay(e++,n.retryMs)))return;try{a=await this.openSseStream(n.lastEventId)}catch(e){if(o=e,!this.isRetryable(e))break;a=void 0}}if(this.closed)return;let s=o===void 0?`stream ended without a response`:x(o).message;this.emitMessage({jsonrpc:`2.0`,id:t,error:{code:_.internalError,message:`MCP response stream failed: ${s}`}})}startGetStream(){this.options.openGetStream===!1||this.getStreamStarted||this.closed||(this.getStreamStarted=!0,this.runGetStream())}async runGetStream(){let e={lastEventId:void 0,retryMs:void 0,received:!1};for(let t=0;!this.closed;){try{let n=await this.openSseStream(e.lastEventId);if(!n)return;let r=Date.now();await this.consumeSse(n,e),(e.received||Date.now()-r>this.maxDelay())&&(t=0)}catch(e){if(this.closed)return;if(!this.isRetryable(e)){this.emitError(e);return}}if(e.received=!1,t>=this.maxRetries()){this.emitError(Error(`MCP server-to-client stream dropped and could not be reopened`));return}if(!await this.sleep(this.reconnectDelay(t++,e.retryMs)))return}}async openSseStream(e){let t=await this.authorizedFetch(`GET`,{headers:{accept:`text/event-stream`,...e===void 0?{}:{"last-event-id":e}}});if(t.status===405){await M(t);return}await this.checkResponse(t),this.captureSession(t);let n=Ue(t);if(n!==`text/event-stream`||!t.body)throw await M(t),new j(t.status,`Unsupported MCP GET response content type: ${n??`missing`}`);return t.body}isRetryable(e){if(e instanceof j)return Ge(e.status);if(e instanceof TypeError)return!0;let t=e?.code;return typeof t==`string`&&(t.startsWith(`E`)||t.startsWith(`UND_ERR`))}reconnectDelay(e,t){if(t!==void 0)return t;let n=this.options.reconnect?.initialDelayMs??1e3;return Math.min(n*2**e,this.maxDelay())}maxDelay(){return this.options.reconnect?.maxDelayMs??3e4}maxRetries(){return this.options.reconnect?.maxRetries??5}sleep(e){let t=this.controller.signal;return t.aborted?Promise.resolve(!1):new Promise(n=>{let r=()=>{clearTimeout(i),n(!1)},i=setTimeout(()=>{t.removeEventListener(`abort`,r),n(!0)},e);i.unref?.(),t.addEventListener(`abort`,r,{once:!0})})}};const Je=6e4;function N(e){return typeof e?.timeout==`number`&&e.timeout>0?e.timeout*1e3:Je}function Ye(e,{cwd:t,env:n,authProvider:r,fetch:a}){return typeof e.url==`string`&&e.type!==`stdio`?new qe({url:e.url,...e.headers?{headers:e.headers}:{},...r?{authProvider:r}:{},...a?{fetch:a}:{}}):new ze({command:e.command,args:e.args??[],cwd:e.cwd?i.resolve(t??process.cwd(),e.cwd):t,...n?{env:n,inheritEnv:!1}:{env:e.env??{}}})}async function Xe({name:e,config:t,cwd:n,env:r,clientName:i,clientVersion:a=`1.0.0`,authProvider:o,fetch:s}){let c=Ye(t,{cwd:n,env:r,authProvider:o,fetch:s}),l=new ye({name:i,version:a,requestTimeoutMs:N(t)});try{return await l.connect(c),{name:e,config:t,client:l,tools:await l.listTools(),instructions:l.instructions,close:()=>l.close()}}catch(e){await l.close().catch(()=>{});let t=c instanceof ze?c.stderr.trim():``;throw t&&e instanceof Error&&(e.message=`${e.message}\n${t.slice(-2e3)}`),e}}function Ze(e,t){return`mcp__${e}__${t}`.replace(/[^A-Za-z0-9_]/g,`_`)}function Qe(e,t,n){let i=r(`sha256`).update(`${t}\0${n}`).digest(`hex`).slice(0,8);return`${e.slice(0,64-i.length-1)}_${i}`}function $e(e,{reserved:t=new Set}={}){let n=e.map(({server:e,tool:t})=>Ze(e,t)),r=new Map;for(let[t,i]of n.entries()){let{server:n,tool:a}=e[t],o=`${n}\0${a}`;r.has(i)||r.set(i,new Set),r.get(i).add(o)}return n.map((n,i)=>{let{server:a,tool:o}=e[i],s=r.get(n).size>1;return n.length<=64&&!s&&!t.has(n)?n:Qe(n,a,o)})}function et(e){return`mcp_${e}`}const tt=48*1024;function P(e){if(e.length<=65536)return e;let t=e.length-tt-16384;return`${e.slice(0,tt)}\n[... ${t} characters truncated ...]\n${e.slice(-16384)}`}const nt=e=>e.some(e=>e.type===`text`&&e.text.trim()!==``);function rt(e,t,n,{limitText:r=P}={}){let i=xe(n).map(e=>e.type===`text`?{type:`text`,text:r(e.text)}:e);n.isError&&!nt(i)&&i.push({type:`text`,text:`MCP tool ${e}/${t} returned an error`});let{_meta:a,...o}=n;return{content:i,details:{server:e,tool:t},structuredContent:o,...n.isError?{isError:!0}:{}}}function it(e,t,n,{limitText:r=P}={}){return{content:[{type:`text`,text:`MCP tool error: ${r(n instanceof Error?n.message:String(n))}`}],details:{server:e,tool:t},isError:!0}}function at(e){return e.ok?`Authorization complete. You may close this window.`:e.details?`${e.message}\n\n${e.details}`:e.message}var F=class e{redirectUrl;server;path;timeoutMs;renderPage;pending=new Map;constructor(e,t,n,r,i){this.server=e,this.redirectUrl=t,this.path=n,this.timeoutMs=r,this.renderPage=i}static async listen(t={}){let n=t.host??`127.0.0.1`,r=t.redirectHost??n,i=t.path??`/callback`,a,o=s((e,t)=>a?.handle(e.url??`/`,t));await new Promise((e,r)=>{o.once(`error`,r),o.listen(t.port??0,n,()=>{o.off(`error`,r),e()})});let c=o.address();if(!c||typeof c==`string`)throw Error(`OAuth callback server did not bind to TCP`);return a=new e(o,`http://${r.includes(`:`)?`[${r}]`:r}:${c.port}${i}`,i,t.timeoutMs??5*6e4,t.renderPage),a}waitForCallback(e){if(this.pending.has(e))throw Error(`OAuth state is already pending`);return new Promise((t,n)=>{let r=setTimeout(()=>{this.pending.delete(e),n(Error(`OAuth callback timed out`))},this.timeoutMs);this.pending.set(e,{resolve:t,reject:n,timer:r})})}async close(){for(let e of this.pending.values())clearTimeout(e.timer),e.reject(Error(`OAuth callback server closed`));this.pending.clear(),await new Promise((e,t)=>{this.server.close(n=>n?t(n):e())})}reply(e,t,n){this.renderPage?(e.writeHead(t,{"content-type":`text/html; charset=utf-8`,"cache-control":`no-store`}),e.end(this.renderPage(n))):e.writeHead(t,{"content-type":`text/plain; charset=utf-8`}).end(at(n))}handle(e,t){let n=new URL(e,this.redirectUrl);if(n.pathname!==this.path){this.reply(t,404,{ok:!1,message:`Not found`});return}let r=n.searchParams.get(`state`),i=r?this.pending.get(r):void 0;if(!r||!i){this.reply(t,400,{ok:!1,message:`Invalid or expired OAuth state`});return}clearTimeout(i.timer),this.pending.delete(r);let a=n.searchParams.get(`error`);if(a){let e=n.searchParams.get(`error_description`)??a;i.reject(Error(e)),this.reply(t,200,{ok:!1,message:`Authorization failed. You may close this window.`,details:e});return}let o=n.searchParams.get(`code`);if(!o){i.reject(Error(`OAuth callback did not include an authorization code`)),this.reply(t,400,{ok:!1,message:`Missing authorization code`});return}let s=n.searchParams.get(`iss`);i.resolve({code:o,state:r,...s?{iss:s}:{}}),this.reply(t,200,{ok:!0})}},I=class extends Error{code;errorUri;constructor(e,t,n){super(t||e),this.name=`OAuthError`,this.code=e,this.errorUri=n}},ot=class extends Error{expected;received;constructor(e,t){super(`OAuth issuer mismatch: expected ${JSON.stringify(e)}, received ${t===void 0?`none`:JSON.stringify(t)}`),this.name=`OAuthIssuerMismatchError`,this.expected=e,this.received=t}},st=class extends Error{endpoint;constructor(e){super(`Refusing to send OAuth credentials to non-HTTPS endpoint ${e}`),this.name=`OAuthInsecureEndpointError`,this.endpoint=e}},ct=class extends Error{status;body;constructor(e,t){super(`OAuth dynamic client registration failed with status ${e}: ${t}`),this.name=`OAuthRegistrationError`,this.status=e,this.body=t}},L=class extends Error{constructor(){super(`MCP OAuth authorization requires user interaction`),this.name=`McpOAuthAuthorizationRequiredError`}};function R(e,t){if(!b(e))throw Error(`Invalid ${t}`);return e}function z(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0))}function B(e,t){if(typeof e!=`string`||e.length===0)throw Error(`Invalid ${t}`);return e}function V(e){return e==null||e===``}function H(e,t){if(!V(e))return B(e,t)}function U(e,t){if(e!=null){if(!Array.isArray(e)||e.some(e=>typeof e!=`string`))throw Error(`Invalid ${t}`);return[...e]}}function W(e,t){let n=B(e,t);if(!URL.canParse(n))throw Error(`Invalid ${t}`);let r=new URL(n);if([`javascript:`,`data:`,`vbscript:`].includes(r.protocol))throw Error(`Invalid ${t}`);return n}function lt(e,t){return V(e)?void 0:W(e,t)}function ut(e){let t=R(e,`OAuth protected resource metadata`);return z({...t,resource:W(t.resource,`OAuth protected resource metadata resource`),authorization_servers:U(t.authorization_servers,`authorization_servers`)?.map(e=>W(e,`authorization server URL`)),scopes_supported:U(t.scopes_supported,`scopes_supported`)})}function dt(e){let t=R(e,`authorization server metadata`),n=U(t.response_types_supported,`response_types_supported`);if(!n)throw Error(`Invalid response_types_supported`);return z({...t,issuer:W(t.issuer,`authorization server issuer`),authorization_endpoint:W(t.authorization_endpoint,`authorization endpoint`),token_endpoint:W(t.token_endpoint,`token endpoint`),registration_endpoint:lt(t.registration_endpoint,`registration endpoint`),scopes_supported:U(t.scopes_supported,`scopes_supported`),response_types_supported:n,grant_types_supported:U(t.grant_types_supported,`grant_types_supported`),token_endpoint_auth_methods_supported:U(t.token_endpoint_auth_methods_supported,`token_endpoint_auth_methods_supported`),code_challenge_methods_supported:U(t.code_challenge_methods_supported,`code_challenge_methods_supported`),client_id_metadata_document_supported:typeof t.client_id_metadata_document_supported==`boolean`?t.client_id_metadata_document_supported:void 0,authorization_response_iss_parameter_supported:typeof t.authorization_response_iss_parameter_supported==`boolean`?t.authorization_response_iss_parameter_supported:void 0})}function ft(e){let t=R(e,`OAuth token response`),n=V(t.expires_in)?void 0:Number(t.expires_in);if(n!==void 0&&!Number.isFinite(n))throw Error(`Invalid expires_in`);return z({access_token:B(t.access_token,`access_token`),token_type:B(t.token_type,`token_type`),expires_in:n,scope:H(t.scope,`scope`),refresh_token:H(t.refresh_token,`refresh_token`),id_token:H(t.id_token,`id_token`)})}function pt(e){let t=R(e,`OAuth client registration response`);return z({...t,client_id:B(t.client_id,`client_id`),client_secret:H(t.client_secret,`client_secret`),client_id_issued_at:typeof t.client_id_issued_at==`number`?t.client_id_issued_at:void 0,client_secret_expires_at:typeof t.client_secret_expires_at==`number`?t.client_secret_expires_at:void 0,redirect_uris:U(t.redirect_uris,`redirect_uris`)??[]})}function G(e){e?.body?.cancel().catch(()=>{})}function K(e){return e>=400&&e<500||e===502}function mt(e){return e.endsWith(`/`)?e.slice(0,-1):e}function q(e,t){let n=e.match(new RegExp(String.raw`(?:^|[,\s])${t}=(?:"([^"]*)"|([^\s,]+))`,`i`));return n?.[1]||n?.[2]||void 0}function ht(e){if(!e)return{};let t=e.trimStart().split(/\s+/,1)[0]?.toLowerCase();if(t!==`bearer`&&t!==`dpop`)return{};let n=q(e,`resource_metadata`),r;if(n)try{r=new URL(n)}catch{}return{resourceMetadataUrl:r,scope:q(e,`scope`),error:q(e,`error`),errorDescription:q(e,`error_description`)}}async function J(e,t,n){return t(e,{headers:{Accept:`application/json`,"MCP-Protocol-Version":n}})}async function gt(e,t={}){let n=new URL(e),r=t.fetch??globalThis.fetch,i=t.protocolVersion??`2025-11-25`,a=await J(t.resourceMetadataUrl?new URL(t.resourceMetadataUrl):new URL(`/.well-known/oauth-protected-resource${mt(n.pathname)}`,n.origin),r,i);if(!t.resourceMetadataUrl&&n.pathname!==`/`&&K(a.status)&&(G(a),a=await J(new URL(`/.well-known/oauth-protected-resource`,n.origin),r,i)),!a.ok)throw G(a),Error(`HTTP ${a.status} loading OAuth protected resource metadata`);return ut(await a.json())}function _t(e){let t=new URL(e),n=mt(t.pathname),r=[{url:new URL(`/.well-known/oauth-authorization-server${n}`,t.origin),type:`oauth`},{url:new URL(`/.well-known/openid-configuration${n}`,t.origin),type:`oidc`}];return n&&r.push({url:new URL(`${n}/.well-known/openid-configuration`,t.origin),type:`oidc`}),r}async function vt(e,t={}){let n=t.fetch??globalThis.fetch;for(let{url:r}of _t(e)){let i=await J(r,n,t.protocolVersion??`2025-11-25`);if(!i.ok){if(G(i),K(i.status))continue;throw Error(`HTTP ${i.status} loading authorization server metadata from ${r}`)}let a=dt(await i.json());if(!t.skipIssuerValidation){let t=String(e),n=e=>e.endsWith(`/`)?e.slice(0,-1):e;if(n(a.issuer)!==n(t))throw new ot(t,a.issuer)}return a}}async function yt(e,t={}){let n;try{n=await gt(e,{resourceMetadataUrl:t.resourceMetadataUrl,fetch:t.fetch})}catch(e){if(e instanceof TypeError)throw e}if(t.authorizationServerMetadataUrl){let e=t.authorizationServerMetadataUrl,r=await J(e,t.fetch??globalThis.fetch,oe);if(!r.ok)throw G(r),Error(`HTTP ${r.status} loading authorization server metadata from ${e}`);let i=dt(await r.json());return{authorizationServerUrl:i.issuer,authorizationServerMetadata:i,resourceMetadata:n}}let r=n?.authorization_servers?.[0]??String(new URL(`/`,e));return{authorizationServerUrl:r,authorizationServerMetadata:await vt(r,{fetch:t.fetch,skipIssuerValidation:t.skipIssuerValidation}),resourceMetadata:n}}function bt(e){let t=new URL(e);return t.hash=``,t}function xt(e,t){if(!t)return;let n=bt(e),r=new URL(t.resource);if(n.origin!==r.origin)throw Error(`Protected resource ${t.resource} does not match MCP server ${n}`);let i=n.pathname.endsWith(`/`)?n.pathname:`${n.pathname}/`,a=r.pathname.endsWith(`/`)?r.pathname:`${r.pathname}/`;if(!i.startsWith(a))throw Error(`Protected resource ${t.resource} does not match MCP server ${n}`);return t.resource}function St(e){return e===`localhost`||e===`127.0.0.1`||e===`[::1]`||e===`::1`}function Ct(e){let t=new URL(e);if(t.protocol!==`https:`&&!St(t.hostname))throw new st(t.href);return t}function wt(e,t){let n=`token_endpoint_auth_method`in e?e.token_endpoint_auth_method:void 0;return n&&[`client_secret_basic`,`client_secret_post`,`none`].includes(n)&&(t.length===0||t.includes(n))?n:t.length===0?e.client_secret?`client_secret_basic`:`none`:e.client_secret&&t.includes(`client_secret_basic`)?`client_secret_basic`:e.client_secret&&t.includes(`client_secret_post`)?`client_secret_post`:t.includes(`none`)?`none`:e.client_secret?`client_secret_post`:`none`}function Tt(e,t,n,r){if(e===`client_secret_basic`){if(!t.client_secret)throw Error(`client_secret_basic requires a client secret`);n.set(`Authorization`,`Basic ${Buffer.from(`${t.client_id}:${t.client_secret}`).toString(`base64`)}`)}else r.set(`client_id`,t.client_id),e===`client_secret_post`&&t.client_secret&&r.set(`client_secret`,t.client_secret)}async function Et(){let e=crypto.getRandomValues(new Uint8Array(32)),t=Buffer.from(e).toString(`base64url`),n=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(t));return{verifier:t,challenge:Buffer.from(n).toString(`base64url`)}}async function Dt(e,t){let n=t.metadata;if(n&&!n.response_types_supported.includes(`code`))throw Error(`Authorization server does not support authorization codes`);if(n?.code_challenge_methods_supported&&!n.code_challenge_methods_supported.includes(`S256`))throw Error(`Authorization server does not support PKCE S256`);let r=new URL(n?.authorization_endpoint??new URL(`/authorize`,e)),{verifier:i,challenge:a}=await Et();return r.searchParams.set(`response_type`,`code`),r.searchParams.set(`client_id`,t.clientInformation.client_id),r.searchParams.set(`code_challenge`,a),r.searchParams.set(`code_challenge_method`,`S256`),r.searchParams.set(`redirect_uri`,String(t.redirectUrl)),t.state&&r.searchParams.set(`state`,t.state),t.scope&&r.searchParams.set(`scope`,t.scope),t.scope?.split(/\s+/).includes(`offline_access`)&&r.searchParams.set(`prompt`,`consent`),t.resource&&r.searchParams.set(`resource`,t.resource),{authorizationUrl:r,codeVerifier:i}}async function Ot(e,t,n){let r=Ct(t.metadata?.token_endpoint??new URL(`/token`,e)),i=new Headers({Accept:`application/json`,"content-type":`application/x-www-form-urlencoded`});t.resource&&n.set(`resource`,t.resource),t.addClientAuthentication?await t.addClientAuthentication(i,n,r,t.metadata):Tt(wt(t.clientInformation,t.metadata?.token_endpoint_auth_methods_supported??[]),t.clientInformation,i,n);let a=await(t.fetch??globalThis.fetch)(r,{method:`POST`,headers:i,body:n}),o=await a.text(),s;try{s=JSON.parse(o)}catch{}if(b(s)&&typeof s.error==`string`)throw new I(s.error,typeof s.error_description==`string`?s.error_description:s.error,typeof s.error_uri==`string`?s.error_uri:void 0);if(!a.ok)throw new I(`server_error`,`HTTP ${a.status}: ${o}`);return ft(s)}async function kt(e,t){let n=t.metadata?.registration_endpoint;if(t.metadata&&!n)throw Error(`Authorization server does not support dynamic client registration`);let r=await(t.fetch??globalThis.fetch)(new URL(n??new URL(`/register`,e)),{method:`POST`,headers:{Accept:`application/json`,"content-type":`application/json`},body:JSON.stringify({...t.clientMetadata,...t.scope?{scope:t.scope}:{}})});if(!r.ok)throw new ct(r.status,await r.text());return pt(await r.json())}async function At(e,t){return Ot(e,t,new URLSearchParams({grant_type:`authorization_code`,code:t.code,code_verifier:t.codeVerifier,redirect_uri:String(t.redirectUrl)}))}async function jt(e,t){let n=await Ot(e,t,new URLSearchParams({grant_type:`refresh_token`,refresh_token:t.refreshToken}));return{refresh_token:t.refreshToken,...n}}function Mt(e,t){return e.scope===void 0&&t?{...e,scope:t}:e}function Nt(e,t){if(!t)return;let n=[e,t].flatMap(e=>e?.split(/\s+/).filter(Boolean)??[]);return[...new Set(n)].join(` `)}async function Y(e,t){let n=t.authorizationServerMetadataUrl&&Ct(t.authorizationServerMetadataUrl),r=n?void 0:await e.discoveryState?.(),i=r?.authorizationServerUrl?{authorizationServerUrl:r.authorizationServerUrl,authorizationServerMetadata:r.authorizationServerMetadata??await vt(r.authorizationServerUrl,{fetch:t.fetch,skipIssuerValidation:t.skipIssuerValidation}),resourceMetadata:r.resourceMetadata}:await yt(t.serverUrl,{resourceMetadataUrl:t.resourceMetadataUrl,authorizationServerMetadataUrl:n,fetch:t.fetch,skipIssuerValidation:t.skipIssuerValidation});n||await e.saveDiscoveryState?.({...i,...t.resourceMetadataUrl?{resourceMetadataUrl:t.resourceMetadataUrl.href}:{}});let a=i.authorizationServerMetadata,o=xt(t.serverUrl,i.resourceMetadata),s=t.scope||i.resourceMetadata?.scopes_supported?.join(` `)||e.clientMetadata.scope,c=await e.clientInformation();if(!c){if(t.authorizationCode)throw Error(`OAuth client information is missing during code exchange`);if(a?.client_id_metadata_document_supported&&e.clientMetadataUrl){let t=new URL(e.clientMetadataUrl);if(t.protocol!==`https:`||t.pathname===`/`)throw Error(`Invalid OAuth client metadata URL`);c={client_id:e.clientMetadataUrl},await e.saveClientInformation?.(c)}else{if(!e.saveClientInformation)throw Error(`OAuth client information cannot be persisted`);c=await kt(i.authorizationServerUrl,{metadata:a,clientMetadata:e.clientMetadata,scope:s,fetch:t.fetch}),await e.saveClientInformation(c)}}let l={metadata:a,clientInformation:c,resource:o,addClientAuthentication:e.addClientAuthentication,fetch:t.fetch};if(t.authorizationCode){let n=t.iss;if(a&&(n!==void 0||a.authorization_response_iss_parameter_supported)&&n!==a.issuer)throw new ot(a.issuer,n);let r=await At(i.authorizationServerUrl,{...l,code:t.authorizationCode,codeVerifier:await e.codeVerifier(),redirectUrl:e.redirectUrl});return await e.saveTokens(Mt(r,s)),`AUTHORIZED`}let u=t.skipRefresh?void 0:await e.tokens();if(u?.refresh_token)try{let t=await jt(i.authorizationServerUrl,{...l,refreshToken:u.refresh_token});return await e.saveTokens(Mt(t,u.scope)),`AUTHORIZED`}catch(e){if(e instanceof st||e instanceof I&&e.code!==`server_error`)throw e}let d=await e.state?.(),f=await Dt(i.authorizationServerUrl,{metadata:a,clientInformation:c,redirectUrl:e.redirectUrl,scope:s,state:d,resource:o});return await e.saveCodeVerifier(f.codeVerifier),await e.redirectToAuthorization(f.authorizationUrl),`REDIRECT`}async function X(e,t){try{return await Y(e,t)}catch(n){if(n instanceof I&&[`invalid_client`,`unauthorized_client`].includes(n.code))return await e.invalidateCredentials?.(`all`),Y(e,t);if(n instanceof I&&n.code===`invalid_grant`)return await e.invalidateCredentials?.(`tokens`),Y(e,t);throw n}}var Pt=class{value;load(){return this.value===void 0?void 0:structuredClone(this.value)}save(e){this.value=structuredClone(e)}},Ft=class{redirectUrl;clientMetadata;serverUrl;configuredClient;store;onRedirect;writes=Promise.resolve();constructor(e){this.serverUrl=String(new URL(e.serverUrl)),this.redirectUrl=String(e.redirectUrl),this.clientMetadata={...e.clientMetadata,redirect_uris:e.clientMetadata.redirect_uris??[this.redirectUrl],grant_types:e.clientMetadata.grant_types??[`authorization_code`,`refresh_token`],response_types:e.clientMetadata.response_types??[`code`],token_endpoint_auth_method:e.clientMetadata.token_endpoint_auth_method??(e.clientSecret?`client_secret_post`:`none`)},this.configuredClient=e.clientId?{client_id:e.clientId,...e.clientSecret?{client_secret:e.clientSecret}:{}}:void 0,this.store=e.store??new Pt,this.onRedirect=e.onRedirect}async state(){let e=(await this.load()).oauthState;if(e)return e;let t=Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString(`hex`);return await this.update(e=>({...e,oauthState:t})),t}async clientInformation(){return this.configuredClient??(await this.load()).clientInformation}async saveClientInformation(e){this.configuredClient||await this.update(t=>({...t,clientInformation:e}))}async tokens(){return(await this.load()).tokens}async saveTokens(e){let t=e.expires_in===void 0?void 0:Date.now()+e.expires_in*1e3;await this.update(n=>{let r={...n,tokens:e};return t===void 0?delete r.tokensExpireAt:r.tokensExpireAt=t,r})}async redirectToAuthorization(e){await this.onRedirect(e)}async saveCodeVerifier(e){await this.update(t=>({...t,codeVerifier:e}))}async codeVerifier(){let e=(await this.load()).codeVerifier;if(!e)throw Error(`No OAuth PKCE code verifier is stored`);return e}async invalidateCredentials(e){await this.update(t=>{let n={...t};return(e===`all`||e===`client`)&&delete n.clientInformation,(e===`all`||e===`tokens`)&&(delete n.tokens,delete n.tokensExpireAt),(e===`all`||e===`verifier`)&&delete n.codeVerifier,(e===`all`||e===`discovery`)&&delete n.discovery,e===`all`&&delete n.oauthState,n})}async saveDiscoveryState(e){await this.update(t=>({...t,discovery:e}))}async discoveryState(){return(await this.load()).discovery}async load(){return await this.writes,this.own(await this.store.load())}async update(e){this.writes=this.writes.then(async()=>{await this.store.save(e(this.own(await this.store.load())))}),await this.writes}own(e){return e?.serverUrl===this.serverUrl?e:{serverUrl:this.serverUrl}}};const Z=`127.0.0.1`,It=`/callback`,Lt=`http://${Z}${It}`;function Rt(e){return typeof e?.url!=`string`||e.type===`stdio`?!1:!Object.keys(e.headers??{}).some(e=>e.toLowerCase()===`authorization`)}function zt(e,t){return`${e}|${String(new URL(t))}`}function Bt(e){let t=new URL(e.callbackUrl??`http://${Z}${It}`),n=t.hostname.replace(/^\[|\]$/g,``),r=t.port?Number(t.port):e.callbackPort,i;return t.port?i=e.callbackUrl:r!==void 0&&(t.port=String(r),i=t.href),{host:n===`localhost`?Z:n,redirectHost:n,port:r,path:t.pathname,fixedRedirectUrl:i}}function Vt(...e){let t=[...new Set(e.flatMap(e=>e?.split(/\s+/).filter(Boolean)??[]))];return t.length>0?t.join(` `):void 0}const Q=e=>e&&`redirect_uris`in e?e.redirect_uris:[];function Ht(e,t,n,r,i,a){return new Ft({serverUrl:e,redirectUrl:i,clientMetadata:{client_name:n.clientName??r},clientId:n.clientId,clientSecret:n.clientSecret,store:t,onRedirect:a})}const $=new Map;function Ut({serverUrl:e,storeKey:t,store:n,settings:r={},clientName:i,onChallenge:a}){let o=(a,o=globalThis.fetch,s)=>{let c=$.get(t);return c||(c=(async()=>{let t=await n.load();if(t?.tokens?.access_token===a&&(!t?.tokens?.refresh_token||await X(Ht(e,n,r,i,Bt(r).fixedRedirectUrl??Q(t.clientInformation)[0]??Lt,()=>{}),{serverUrl:e,resourceMetadataUrl:s?.resourceMetadataUrl,authorizationServerMetadataUrl:r.authServerMetadataUrl,scope:s?.scope,fetch:(e,t)=>o(e,{...t,signal:AbortSignal.timeout(15e3)})})===`REDIRECT`))throw new L})().finally(()=>$.delete(t)),$.set(t,c)),c};return{token:async()=>{await $.get(t)?.catch(()=>void 0);let e=await n.load(),r=e?.tokens?.access_token;return!(e?.tokensExpireAt!==void 0&&e.tokensExpireAt-3e4<=Date.now())||!e?.tokens?.refresh_token?r:(await o(r).catch(()=>void 0),(await n.load())?.tokens?.access_token)},onUnauthorized:async e=>{let t=ht(e.response.headers.get(`www-authenticate`));if(a?.(t),t.error===`insufficient_scope`)throw new L;await o(e.token,e.fetch,t)}}}async function Wt(e,t,n,r){let i={host:e.host,redirectHost:e.redirectHost,path:e.path,...r?{renderPage:r}:{}};try{return await F.listen({...i,port:t??0})}catch(e){if(n||t===void 0)throw e;return F.listen(i)}}async function Gt(e,t){if(!t)return e;let n,r=new Promise((e,r)=>{n=()=>r(t.reason??Error(`Sign-in cancelled`)),t.aborted?n():t.addEventListener(`abort`,n,{once:!0})});try{let n=await Promise.race([e,r]);return t.throwIfAborted(),n}finally{t.removeEventListener(`abort`,n)}}async function Kt({serverUrl:e,store:t,settings:n={},clientName:r,challenge:i,openUrl:a,signal:o,renderPage:s}){o?.throwIfAborted();let c=await t.load();o?.throwIfAborted();let l={load:()=>t.load(),save:e=>(o?.throwIfAborted(),t.save(e))},u=i?.error===`insufficient_scope`,d=Bt(n),f=Q(c?.clientInformation)[0],p=await Wt(d,d.port??(f&&Number(new URL(f).port)||void 0),d.port!==void 0,s),m=d.fixedRedirectUrl??p.redirectUrl;try{if(o?.throwIfAborted(),c){let e={...c};delete e.oauthState,!n.clientId&&!Q(c.clientInformation).includes(m)&&(delete e.clientInformation,delete e.tokens,delete e.tokensExpireAt),await l.save(e)}let t,s=Ht(e,l,n,r,m,e=>{t=e}),d={serverUrl:e,resourceMetadataUrl:i?.resourceMetadataUrl,authorizationServerMetadataUrl:n.authServerMetadataUrl,scope:Vt(n.scope,u?Nt(c?.tokens?.scope,i?.scope):i?.scope),fetch:(e,t)=>(o?.throwIfAborted(),fetch(e,{...t,signal:o&&t?.signal?AbortSignal.any([o,t.signal]):o??t?.signal}))},f=await X(s,{...d,skipRefresh:u});if(o?.throwIfAborted(),f===`AUTHORIZED`)return;if(!t)throw Error(`OAuth flow did not produce an authorization URL`);let h=p.waitForCallback(await s.state());h.catch(()=>void 0),o?.throwIfAborted(),await Gt(a(t),o);let{code:ee,iss:g}=await Gt(h,o);await X(s,{...d,authorizationCode:ee,iss:g}),o?.throwIfAborted()}finally{await p.close()}}const qt=[`readOnlyHint`,`destructiveHint`,`idempotentHint`,`openWorldHint`];function Jt(e){let t=e&&typeof e==`object`?e:{};return{...t,type:t.type??`object`,...t.properties===void 0?{properties:{}}:{}}}function Yt(e){return{type:`object`,properties:{content:{type:`array`,items:{type:`object`}},...e?{structuredContent:e}:{},isError:{type:`boolean`},_meta:{type:`object`}},required:[`content`]}}function Xt(e){let t={};for(let n of qt){let r=e.annotations?.[n];typeof r==`boolean`&&(t[n]=r)}return Object.keys(t).length>0?t:void 0}function Zt({server:e,client:t,tool:n,name:r,exposure:i,config:a,instructions:o,limitText:s}){let c=n.title??n.annotations?.title,l=Xt(n),u=N(a);return{name:r,label:`${e}/${n.name}`,description:n.description?.trim()||c||`MCP tool ${n.name} from server ${e}`,parameters:Jt(n.inputSchema),outputSchema:Yt(n.outputSchema),execute:async(r,i,a,o)=>{try{let r=await t.callTool(n.name,i??{},{signal:a,timeoutMs:u,onProgress:t=>{let r=t.total===void 0?``:`/${t.total}`;o?.({content:[{type:`text`,text:t.message??`Progress ${t.progress}${r}`}],details:{server:e,tool:n.name}})}});return rt(e,n.name,r,{limitText:s})}catch(t){if(a?.aborted)throw t;return it(e,n.name,t,{limitText:s})}},_mcpServer:e,_mcpToolName:n.name,_mcpExposure:i,_mcpNamespace:h(e),...typeof a.description==`string`&&a.description.trim()?{_mcpServerDescription:a.description.trim()}:{},...o?{_mcpServerInstructions:o}:{},...l?{_mcpAnnotations:l}:{},_client:t}}function Qt(e,{defaultExposure:t=`deferred`,reservedNames:n,limitText:r=P}={}){let i=e.flatMap(e=>e.tools.map(n=>({connection:e,tool:n,exposure:g(e.config,n.name,t)}))),a=$e(i.map(({connection:e,tool:t})=>({server:e.name,tool:t.name})),{reserved:n});return i.flatMap(({connection:e,tool:t,exposure:n},i)=>n===`hidden`?[]:[Zt({server:e.name,client:e.client,tool:t,name:a[i],exposure:n,config:e.config,instructions:e.instructions?.trim(),limitText:r})])}export{Je as DEFAULT_MCP_TIMEOUT_MS,c as MCP_EXPOSURES,L as McpOAuthAuthorizationRequiredError,$e as assignMcpToolNames,Xe as connectMcpServer,rt as convertMcpResult,Qt as createMcpAgentTools,Ut as createMcpAuthProvider,g as getMcpToolExposure,et as legacyMcpToolName,P as limitMcpTextDefault,it as mcpCallErrorResult,h as mcpNamespace,zt as mcpOAuthStoreKey,N as mcpRequestTimeoutMs,Ze as mcpToolBaseName,Kt as signInMcpServer,Rt as usesMcpOAuth,re as validateMcpServerConfig};
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Typed decisions on the sessionless paths (local functions, the
3
+ * TypeSafe-compatible endpoint).
4
+ *
5
+ * Mirrors tts-shared: a module-scoped warm-generator cache, reference-counted
6
+ * by in-flight requests. An unmatched model is an error rather than a
7
+ * substitution — another decision model would answer with different
8
+ * calibration, which the caller cannot detect.
9
+ *
10
+ * A decision model that is also configured as a `ggml-llm` runs on that
11
+ * generator's context (see utils/decision-sharing.ts).
12
+ */
13
+ import type { DecisionRequest, DecisionResult } from '../types';
14
+ /** Configured generators that answer decisions, in config order. */
15
+ export declare const isDecisionGenerator: (generator: any) => boolean;
16
+ /**
17
+ * Decision model ids configured more than once. Sessions tell such entries
18
+ * apart (revision, rank pooling, projector), but the sessionless paths select
19
+ * by id and always resolve to the first, so this is a startup warning only.
20
+ */
21
+ export declare const findDuplicateDecisionIds: (config: any) => string[];
22
+ /**
23
+ * Answer typed questions about a state with a warm decision generator,
24
+ * releasing it afterwards. The backend validates the request.
25
+ */
26
+ export declare function decideWith(backend: any, config: any, { model, ...request }: DecisionRequest & {
27
+ model?: string;
28
+ }, logPrefix?: string): Promise<DecisionResult>;
@@ -31,6 +31,8 @@ export type GeneratorCacheOptions = {
31
31
  resolve: (config: any, requestedModel?: string) => ResolvedGeneratorRequest;
32
32
  /** Post-start preparation (typically `initContext`). */
33
33
  prepare: (backend: any, entry: GeneratorCacheEntry) => Promise<void>;
34
+ /** Undo `prepare` before an evicted entry is finalized, when finalizing alone does not. */
35
+ dispose?: (backend: any, entry: GeneratorCacheEntry) => Promise<void>;
34
36
  };
35
37
  type ConfiguredGeneratorResolverOptions = {
36
38
  family: string;
@@ -47,7 +49,7 @@ export declare const configuredGeneratorModelId: (generatorConfig: any) => strin
47
49
  * of silently loading different weights or voices.
48
50
  */
49
51
  export declare const createConfiguredGeneratorResolver: ({ family, types }: ConfiguredGeneratorResolverOptions) => (config: any, requestedModel?: string) => ResolvedGeneratorRequest;
50
- export declare const createGeneratorCache: ({ max, resolve, prepare }: GeneratorCacheOptions) => {
52
+ export declare const createGeneratorCache: ({ max, resolve, prepare, dispose }: GeneratorCacheOptions) => {
51
53
  getOrCreate: (backend: any, config: any, requestedModel: string | undefined, logPrefix: string) => Promise<GeneratorCacheEntry>;
52
54
  release: (backend: any, entry: GeneratorCacheEntry | null | undefined, logPrefix: string) => Promise<void>;
53
55
  };
@@ -3,5 +3,6 @@ export { default as file } from './file';
3
3
  export { default as status } from './status';
4
4
  export { default as openaiCompatFactory } from './openai-compat';
5
5
  export { default as anthropicMessagesFactory } from './anthropic-messages';
6
+ export { default as typesafeCompatFactory } from './typesafe-compat';
6
7
  export { default as functionsFactory } from './functions';
7
8
  export { default as agentsFactory } from './agents';
@@ -9,6 +9,7 @@ import type { GeneratorCacheEntry } from './generator-cache';
9
9
  export type { GeneratorCacheEntry };
10
10
  export { cancelReaderBestEffort } from './generator-cache';
11
11
  export declare const LLM_TYPES: string[];
12
+ export declare const resolveConfiguredLlm: (config: any, requestedModel?: string) => import("./generator-cache").ResolvedGeneratorRequest;
12
13
  /**
13
14
  * Backend options every `messages`-shaped completion needs.
14
15
  *
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ /**
2
+ * TypeSafe-compatible System One API (EXPERIMENTAL)
3
+ *
4
+ * Serves `/typesafe-compat/v1/systemone` and `/typesafe-compat/v1/models` in
5
+ * the shape of the hosted TypeSafe API (https://docs.typesafe.ai/api), so the
6
+ * TypeSafe SDKs reach this server's decision generators with
7
+ * `TYPESAFE_BASE_URL=http://<host>:<port>/typesafe-compat` — the same way
8
+ * they reach OpenRouter's System One API under its own path.
9
+ *
10
+ * Enable via TOML config: [typesafe_compat] enabled = true
11
+ *
12
+ * `model` selects a configured decision generator by its published id, or by
13
+ * a name mapped in `[typesafe_compat.models]` (SDKs send `jev-latest` unless
14
+ * told otherwise). An unknown model is rejected, never substituted: another
15
+ * model answers with different calibration, which the caller cannot detect.
16
+ */
17
+ type ValidationIssue = {
18
+ loc: (string | number)[];
19
+ msg: string;
20
+ type: string;
21
+ };
22
+ /**
23
+ * Structural checks with the hosted API's limits. llama.node validates the
24
+ * questions again and has the final word; these catch what it reports less
25
+ * precisely, with the field location the SDKs print.
26
+ */
27
+ export declare const validateSystemOneRequest: (body: any) => ValidationIssue[];
28
+ /** Published id -> generator id, for the configured decision generators and the aliases. */
29
+ export declare const buildModelTable: (config: any) => Map<string, string>;
30
+ export default function factory(): import("../types").ButtressApp;
31
+ export {};
@@ -0,0 +1,80 @@
1
+ import { z } from 'zod';
2
+ import type { ReadableStream } from 'node:stream/web';
3
+ import type { DecisionResult, ServiceContext, EventStream, Expand } from '../types';
4
+ export declare const decideProperty: z.ZodObject<{
5
+ request: z.ZodObject<{
6
+ state: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodUnknown, "many">, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
7
+ questions: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
8
+ images: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ state: string | unknown[] | Record<string, unknown>;
11
+ questions: Record<string, Record<string, unknown>>;
12
+ images?: string[] | undefined;
13
+ }, {
14
+ state: string | unknown[] | Record<string, unknown>;
15
+ questions: Record<string, Record<string, unknown>>;
16
+ images?: string[] | undefined;
17
+ }>;
18
+ }, "strip", z.ZodTypeAny, {
19
+ request: {
20
+ state: string | unknown[] | Record<string, unknown>;
21
+ questions: Record<string, Record<string, unknown>>;
22
+ images?: string[] | undefined;
23
+ };
24
+ }, {
25
+ request: {
26
+ state: string | unknown[] | Record<string, unknown>;
27
+ questions: Record<string, Record<string, unknown>>;
28
+ images?: string[] | undefined;
29
+ };
30
+ }>;
31
+ export declare const schemas: {
32
+ initContext: z.ZodTuple<[z.ZodString, z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>], null>;
33
+ decide: z.ZodTuple<[z.ZodString, z.ZodObject<{
34
+ request: z.ZodObject<{
35
+ state: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodUnknown, "many">, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
36
+ questions: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
37
+ images: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
38
+ }, "strip", z.ZodTypeAny, {
39
+ state: string | unknown[] | Record<string, unknown>;
40
+ questions: Record<string, Record<string, unknown>>;
41
+ images?: string[] | undefined;
42
+ }, {
43
+ state: string | unknown[] | Record<string, unknown>;
44
+ questions: Record<string, Record<string, unknown>>;
45
+ images?: string[] | undefined;
46
+ }>;
47
+ }, "strip", z.ZodTypeAny, {
48
+ request: {
49
+ state: string | unknown[] | Record<string, unknown>;
50
+ questions: Record<string, Record<string, unknown>>;
51
+ images?: string[] | undefined;
52
+ };
53
+ }, {
54
+ request: {
55
+ state: string | unknown[] | Record<string, unknown>;
56
+ questions: Record<string, Record<string, unknown>>;
57
+ images?: string[] | undefined;
58
+ };
59
+ }>], null>;
60
+ releaseContext: z.ZodTuple<[z.ZodString], null>;
61
+ };
62
+ export interface Service {
63
+ initContext: (ctx: ServiceContext, ...args: z.infer<typeof schemas.initContext>) => ReadableStream<Expand<EventStream>>;
64
+ decide: (ctx: ServiceContext, ...args: z.infer<typeof schemas.decide>) => Promise<DecisionResult>;
65
+ releaseContext: (ctx: ServiceContext, ...args: z.infer<typeof schemas.releaseContext>) => Promise<{
66
+ released: boolean;
67
+ alreadyReleased?: boolean;
68
+ }>;
69
+ }
70
+ /**
71
+ * Clients upload local images first (like STT audio) and send their names;
72
+ * data URLs pass through.
73
+ */
74
+ export declare const resolveDecisionImages: (session: ServiceContext['session'], request: z.infer<typeof decideProperty>['request']) => {
75
+ state: string | unknown[] | Record<string, unknown>;
76
+ questions: Record<string, Record<string, unknown>>;
77
+ images: string[] | undefined;
78
+ };
79
+ declare const _default: Service;
80
+ export default _default;
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { type Service as LlmService } from './create-llm-service';
3
- import type { ServiceContext } from '../types';
3
+ import type { DecisionResult, ServiceContext } from '../types';
4
4
  export declare const schemas: {
5
5
  initContext: z.ZodTuple<[z.ZodString, z.ZodOptional<z.ZodAny>], null>;
6
6
  completion: z.ZodTuple<[z.ZodString, z.ZodOptional<z.ZodAny>], null>;
@@ -9,9 +9,37 @@ export declare const schemas: {
9
9
  applyChatTemplate: z.ZodTuple<[z.ZodString, z.ZodAny], null>;
10
10
  releaseContext: z.ZodTuple<[z.ZodString], null>;
11
11
  embedding: z.ZodTuple<[z.ZodString, z.ZodAny], null>;
12
+ decide: z.ZodTuple<[z.ZodString, z.ZodObject<{
13
+ request: z.ZodObject<{
14
+ state: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodUnknown, "many">, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
15
+ questions: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
16
+ images: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
17
+ }, "strip", z.ZodTypeAny, {
18
+ state: string | unknown[] | Record<string, unknown>;
19
+ questions: Record<string, Record<string, unknown>>;
20
+ images?: string[] | undefined;
21
+ }, {
22
+ state: string | unknown[] | Record<string, unknown>;
23
+ questions: Record<string, Record<string, unknown>>;
24
+ images?: string[] | undefined;
25
+ }>;
26
+ }, "strip", z.ZodTypeAny, {
27
+ request: {
28
+ state: string | unknown[] | Record<string, unknown>;
29
+ questions: Record<string, Record<string, unknown>>;
30
+ images?: string[] | undefined;
31
+ };
32
+ }, {
33
+ request: {
34
+ state: string | unknown[] | Record<string, unknown>;
35
+ questions: Record<string, Record<string, unknown>>;
36
+ images?: string[] | undefined;
37
+ };
38
+ }>], null>;
12
39
  };
13
40
  export interface Service extends LlmService {
14
41
  embedding: (ctx: ServiceContext, ...args: z.infer<typeof schemas.embedding>) => Promise<any>;
42
+ decide: (ctx: ServiceContext, ...args: z.infer<typeof schemas.decide>) => Promise<DecisionResult>;
15
43
  }
16
44
  declare const _default: Service;
17
45
  export default _default;
@@ -3,6 +3,7 @@ import type { Service as CommonService } from './common';
3
3
  import type { Service as GgmlLlmService } from './ggml-llm';
4
4
  import type { Service as GgmlSttService } from './ggml-stt';
5
5
  import type { Service as GgmlTtsService } from './ggml-tts';
6
+ import type { Service as GgmlDecisionService } from './ggml-decision';
6
7
  import type { Service as MlxLlmService } from './mlx-llm';
7
8
  import type { Service as OnnxSttService } from './onnx-stt';
8
9
  import type { Service as OnnxTtsService } from './onnx-tts';
@@ -21,6 +22,7 @@ declare const services: {
21
22
  releaseContext: ({ backend, session }: ServiceContext, id: any, force: any) => Promise<any>;
22
23
  };
23
24
  ggmlTts: GgmlTtsService;
25
+ ggmlDecision: GgmlDecisionService;
24
26
  mlxLlm: MlxLlmService;
25
27
  onnxStt: OnnxSttService;
26
28
  onnxTts: OnnxTtsService;
@@ -35,6 +37,7 @@ export type Services = {
35
37
  ggmlLlm: ClientService<GgmlLlmService>;
36
38
  ggmlStt: ClientService<GgmlSttService>;
37
39
  ggmlTts: ClientService<GgmlTtsService>;
40
+ ggmlDecision: ClientService<GgmlDecisionService>;
38
41
  mlxLlm: ClientService<MlxLlmService>;
39
42
  onnxStt: ClientService<OnnxSttService>;
40
43
  onnxTts: ClientService<OnnxTtsService>;
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{a as e,t}from"./client-DEUSDK5d.mjs";import{Container as n,Editor as r,Loader as i,Markdown as a,ProcessTerminal as o,Text as s,TuiMainScreen as c}from"@earendil-works/pi-tui";const l=e=>t=>`\x1b[${e}m${t}\x1b[0m`,u=l(`2`),d=l(`1`),f=l(`36`),p=l(`33`),m=l(`31`),h=l(`32`),g=l(`35`),_={heading:e=>d(f(e)),link:f,linkUrl:e=>u(f(e)),code:p,codeBlock:p,codeBlockBorder:u,quote:u,quoteBorder:u,hr:u,listBullet:f,bold:d,italic:l(`3`),strikethrough:l(`9`),underline:l(`4`)},v={borderColor:u,selectList:{selectedPrefix:f,selectedText:d,description:u,scrollInfo:u,noMatch:u}},y=(e,t)=>e.length>t?`${e.slice(0,t)}…`:e;var b=class{tui;chat;thinking=null;thinkingBuffer=``;answer=null;answerBuffer=``;constructor(e,t){this.tui=e,this.chat=t}touch(){this.tui.requestRender()}appendThinking(e){this.thinking||(this.thinking=new s(``,0,0),this.chat.addChild(this.thinking)),this.thinkingBuffer+=e,this.thinking.setText(u(this.thinkingBuffer.trimEnd())),this.touch()}appendAnswer(e){this.answer||(this.answer=new a(``,0,0,_),this.chat.addChild(this.answer)),this.answerBuffer+=e,this.answer.setText(this.answerBuffer),this.touch()}addLine(e){this.answer=null,this.answerBuffer=``,this.chat.addChild(new s(e,0,0)),this.touch()}};const x=async({connection:a,agentName:l,sessionId:_,fork:x})=>{let S=new o,C=new c(S);S.setTitle(`buttress agent · ${l}`);let w=new n,T=new s(``,0,0),E=new r(C,v);C.addChild(w),C.addChild(T),C.addChild(E),C.setFocus(E);let D=_,O=x,k=null,A=null,j=e=>{T.setText(e),C.requestRender()},M=()=>{A||(A=new i(C,f,u,`thinking…`),w.addChild(A),C.requestRender())},N=()=>{A&&(w.removeChild(A),A=null,C.requestRender())},P=`${d(l)} ${u(`@ ${a.baseUrl}`)}`+(D?` ${u(`(${O?`forking`:`continuing`} ${D})`)}`:``);w.addChild(new s(P,0,0)),j(u(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`));let F=async()=>{C.stop(),await S.drainInput().catch(()=>{}),process.exit(0)};C.addInputListener(e=>{if(e===``)return k?(k.abort(),k=null,{consume:!0}):(F(),{consume:!0})});let I=async n=>{w.addChild(new s(`${f(`>`)} ${n}`,0,0));let r=new b(C,w),i=D;k=new AbortController,M(),j(u(`running · Ctrl+C aborts this turn`));let o;try{o=await e(a,l,{prompt:n,sessionId:D??void 0,fork:O},{signal:k.signal,onFrame:({event:e,payload:t})=>{if(e===`session`&&t?.sessionId){t.sessionId!==D&&(D=t.sessionId,w.addChild(new s(u(`session ${D}`),0,0)));return}if(e!==`agent`)return;N();let n=t?.event;if(t?.type===`message_update`&&n)n.type===`thinking_delta`?r.appendThinking(n.delta??``):n.type===`text_delta`&&r.appendAnswer(n.delta??``);else if(t?.type===`tool_execution_start`){let e=JSON.stringify(t.args??{});r.addLine(`${p(`⚙ ${t.toolName}`)}${u(`(${y(e,120)})`)}`)}else t?.type===`tool_execution_end`?r.addLine(t.isError?m(`✗ ${t.toolName} failed`):u(`✓ ${t.toolName}`)):t?.type===`tool_emit`&&r.addLine(u(` ${t.toolName} → ${t.event}`))}})}catch(e){o={kind:`error`,message:e?.message||String(e),sessionId:D}}if(N(),k=null,o.kind===`result`){let{result:e}=o;D=e.sessionId??D;let t=e.usage||{};w.addChild(new s(u(`— ${e.stopReason} · ${t.totalTurns??`?`} turn(s) · ${t.input??0} in / ${t.output??0} out · session ${D}`),0,0))}else o.kind===`aborted`?(D=o.sessionId??D,w.addChild(new s(p(`(aborted — session is continuable)`),0,0))):o.kind===`error`?(D=o.sessionId??D,w.addChild(new s(m(`Run failed: ${o.message}`),0,0))):w.addChild(new s(m(`Connection lost mid-run.`),0,0));t(i,D)&&(O=!1),j(u(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`)),C.requestRender()};E.onSubmit=e=>{let t=e.trim();if(E.setText(``),t){if(k){j(p(`A turn is still running — Ctrl+C aborts it.`));return}if(t===`/exit`||t===`/quit`){F();return}if(t===`/new`){D=null,O=!1,w.addChild(new s(`${h(`•`)} ${u(`started a fresh session`)}`,0,0)),C.requestRender();return}if(t===`/session`){w.addChild(new s(u(D?`session ${D}`:`no session yet`),0,0)),C.requestRender();return}I(t)}},w.addChild(new s(u(g(`ready`)),0,0)),C.start(),await new Promise(()=>{})};export{x as runAgentTui};
2
+ import{a as e,t}from"./client-BVyIuSyr.mjs";import{Container as n,Editor as r,Loader as i,Markdown as a,ProcessTerminal as o,Text as s,TuiMainScreen as c}from"@earendil-works/pi-tui";const l=e=>t=>`\x1b[${e}m${t}\x1b[0m`,u=l(`2`),d=l(`1`),f=l(`36`),p=l(`33`),m=l(`31`),h=l(`32`),g=l(`35`),_={heading:e=>d(f(e)),link:f,linkUrl:e=>u(f(e)),code:p,codeBlock:p,codeBlockBorder:u,quote:u,quoteBorder:u,hr:u,listBullet:f,bold:d,italic:l(`3`),strikethrough:l(`9`),underline:l(`4`)},v={borderColor:u,selectList:{selectedPrefix:f,selectedText:d,description:u,scrollInfo:u,noMatch:u}},y=(e,t)=>e.length>t?`${e.slice(0,t)}…`:e;var b=class{tui;chat;thinking=null;thinkingBuffer=``;answer=null;answerBuffer=``;constructor(e,t){this.tui=e,this.chat=t}touch(){this.tui.requestRender()}appendThinking(e){this.thinking||(this.thinking=new s(``,0,0),this.chat.addChild(this.thinking)),this.thinkingBuffer+=e,this.thinking.setText(u(this.thinkingBuffer.trimEnd())),this.touch()}appendAnswer(e){this.answer||(this.answer=new a(``,0,0,_),this.chat.addChild(this.answer)),this.answerBuffer+=e,this.answer.setText(this.answerBuffer),this.touch()}addLine(e){this.answer=null,this.answerBuffer=``,this.chat.addChild(new s(e,0,0)),this.touch()}};const x=async({connection:a,agentName:l,sessionId:_,fork:x})=>{let S=new o,C=new c(S);S.setTitle(`buttress agent · ${l}`);let w=new n,T=new s(``,0,0),E=new r(C,v);C.addChild(w),C.addChild(T),C.addChild(E),C.setFocus(E);let D=_,O=x,k=null,A=null,j=e=>{T.setText(e),C.requestRender()},M=()=>{A||(A=new i(C,f,u,`thinking…`),w.addChild(A),C.requestRender())},N=()=>{A&&(w.removeChild(A),A=null,C.requestRender())},P=`${d(l)} ${u(`@ ${a.baseUrl}`)}`+(D?` ${u(`(${O?`forking`:`continuing`} ${D})`)}`:``);w.addChild(new s(P,0,0)),j(u(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`));let F=async()=>{C.stop(),await S.drainInput().catch(()=>{}),process.exit(0)};C.addInputListener(e=>{if(e===``)return k?(k.abort(),k=null,{consume:!0}):(F(),{consume:!0})});let I=async n=>{w.addChild(new s(`${f(`>`)} ${n}`,0,0));let r=new b(C,w),i=D;k=new AbortController,M(),j(u(`running · Ctrl+C aborts this turn`));let o;try{o=await e(a,l,{prompt:n,sessionId:D??void 0,fork:O},{signal:k.signal,onFrame:({event:e,payload:t})=>{if(e===`session`&&t?.sessionId){t.sessionId!==D&&(D=t.sessionId,w.addChild(new s(u(`session ${D}`),0,0)));return}if(e!==`agent`)return;N();let n=t?.event;if(t?.type===`message_update`&&n)n.type===`thinking_delta`?r.appendThinking(n.delta??``):n.type===`text_delta`&&r.appendAnswer(n.delta??``);else if(t?.type===`tool_execution_start`){let e=JSON.stringify(t.args??{});r.addLine(`${p(`⚙ ${t.toolName}`)}${u(`(${y(e,120)})`)}`)}else t?.type===`tool_execution_end`?r.addLine(t.isError?m(`✗ ${t.toolName} failed`):u(`✓ ${t.toolName}`)):t?.type===`tool_emit`&&r.addLine(u(` ${t.toolName} → ${t.event}`))}})}catch(e){o={kind:`error`,message:e?.message||String(e),sessionId:D}}if(N(),k=null,o.kind===`result`){let{result:e}=o;D=e.sessionId??D;let t=e.usage||{};w.addChild(new s(u(`— ${e.stopReason} · ${t.totalTurns??`?`} turn(s) · ${t.input??0} in / ${t.output??0} out · session ${D}`),0,0))}else o.kind===`aborted`?(D=o.sessionId??D,w.addChild(new s(p(`(aborted — session is continuable)`),0,0))):o.kind===`error`?(D=o.sessionId??D,w.addChild(new s(m(`Run failed: ${o.message}`),0,0))):w.addChild(new s(m(`Connection lost mid-run.`),0,0));t(i,D)&&(O=!1),j(u(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`)),C.requestRender()};E.onSubmit=e=>{let t=e.trim();if(E.setText(``),t){if(k){j(p(`A turn is still running — Ctrl+C aborts it.`));return}if(t===`/exit`||t===`/quit`){F();return}if(t===`/new`){D=null,O=!1,w.addChild(new s(`${h(`•`)} ${u(`started a fresh session`)}`,0,0)),C.requestRender();return}if(t===`/session`){w.addChild(new s(u(D?`session ${D}`:`no session yet`),0,0)),C.requestRender();return}I(t)}},w.addChild(new s(u(g(`ready`)),0,0)),C.start(),await new Promise(()=>{})};export{x as runAgentTui};
package/lib/types.d.ts CHANGED
@@ -26,7 +26,25 @@ export type RuntimeConfig = {
26
26
  huggingface_token?: string;
27
27
  session_cache?: SessionCacheConfig;
28
28
  } & Record<string, any>;
29
- export type GeneratorType = 'ggml-llm' | 'ggml-stt' | 'ggml-tts' | 'mlx-llm' | 'onnx-stt' | 'onnx-tts';
29
+ export type GeneratorType = 'ggml-llm' | 'ggml-stt' | 'ggml-tts' | 'ggml-decision' | 'mlx-llm' | 'onnx-stt' | 'onnx-tts';
30
+ /** A TypeSafe `/v1/systemone` request, answered by a `ggml-decision` generator. */
31
+ export type DecisionRequest = {
32
+ /** A string, or any JSON object/array (given to the model as JSON text). */
33
+ state: unknown;
34
+ /** Question id → `{ type: 'choice' | 'score' | 'noul', instructions, criteria }`. */
35
+ questions: Record<string, Record<string, any>>;
36
+ /** Local file paths or data URLs; needs a model with an mmproj configured. */
37
+ images?: string[];
38
+ };
39
+ export type DecisionResult = {
40
+ model: string;
41
+ /** Question id → the answer for its type (`choice`, `score` or `noul`). */
42
+ answers: Record<string, any>;
43
+ usage: {
44
+ input_tokens: number;
45
+ output_tokens: number;
46
+ };
47
+ };
30
48
  export type GeneratorConfig = {
31
49
  type: GeneratorType;
32
50
  } & Record<string, any>;
@@ -40,6 +58,12 @@ export type GlobalConfig = {
40
58
  enabled?: boolean;
41
59
  cors_allowed_origins?: string | string[];
42
60
  };
61
+ typesafe_compat?: {
62
+ enabled?: boolean;
63
+ cors_allowed_origins?: string | string[];
64
+ /** Request `model` names (e.g. `jev-latest`) mapped to a decision generator id. */
65
+ models?: Record<string, string>;
66
+ };
43
67
  functions?: {
44
68
  enabled?: boolean;
45
69
  /** Directory holding local function files, relative to the config file. */
@@ -56,6 +56,7 @@ export type CorsPolicy = {
56
56
  export declare const buildCorsPolicies: (config: Config, enabled?: {
57
57
  openaiCompat?: boolean;
58
58
  anthropicMessages?: boolean;
59
+ typesafeCompat?: boolean;
59
60
  functions?: boolean;
60
61
  }) => CorsPolicy[];
61
62
  /**
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Decision models that share an LLM generator's context.
3
+ *
4
+ * A model that both generates and answers typed decisions (Jevling, for one)
5
+ * is often configured twice: as a `ggml-llm` and as a `ggml-decision`. With
6
+ * `[generators.backend] share_llm_context = true` on the decision entry, and
7
+ * both entries naming the same weights, decisions run on the LLM's context
8
+ * (`parallel.decide()` on a slot beside its completions) instead of loading
9
+ * the weights a second time. The LLM config always loads the model, so the
10
+ * result does not depend on which generator starts first.
11
+ *
12
+ * It is opt-in because it trades throughput for memory: a decision takes one
13
+ * of the LLM's `n_parallel` slots, and its forward passes run in the slot
14
+ * loop between two shared batches, so concurrent completions stop generating
15
+ * while it runs (a 128-token completion took 2x as long beside six decisions,
16
+ * unchanged with a separate decision context). Results are not affected: the
17
+ * slot's sequence and prompt cache are cleared after each decision.
18
+ *
19
+ * Sharing is skipped when the decision needs a context the LLM cannot give:
20
+ * rank pooling (an embedding context), or a different projector.
21
+ */
22
+ /**
23
+ * The configured `ggml-llm` generator whose context serves this configured
24
+ * decision generator, or null. For a client's request use
25
+ * `findSharedLlmForClient`: the opt-in must come from the server config.
26
+ */
27
+ export declare const findSharedLlmGenerator: (config: any, decisionConfig: any) => any | null;
28
+ /**
29
+ * The shared LLM for a decision generator a client starts over RPC, or null.
30
+ * Sharing needs a configured `ggml-decision` entry with the same weights that
31
+ * opted in; the client's own `share_llm_context` is ignored, since it would
32
+ * let a client put its decisions on the LLM's slots. The client's merged
33
+ * model (rank pooling, projector) still decides whether the LLM can serve it.
34
+ */
35
+ export declare const findSharedLlmForClient: (config: any, clientModel: any) => any | null;
36
+ /** Startup report: which decision generators share an LLM, and why others do not. */
37
+ export declare const describeDecisionSharing: (config: any) => string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fugood/buttress-server",
3
- "version": "2.26.0-beta.17",
3
+ "version": "2.26.0-beta.18",
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.0.0",
43
43
  "@elysiajs/cors": "^1.1.1",
44
44
  "@elysiajs/node": "^1.4.2",
45
- "@fugood/llama.node": "^1.8.0-rc.8",
45
+ "@fugood/llama.node": "^1.8.0-rc.9",
46
46
  "@fugood/whisper.node": "^1.2.0-rc.0",
47
47
  "@huggingface/gguf": "^0.3.2",
48
48
  "@iarna/toml": "^3.0.0",
@@ -69,11 +69,11 @@
69
69
  "zod": "^3.25.76"
70
70
  },
71
71
  "devDependencies": {
72
- "@fugood/agent-tool-runtime": "^2.26.0-beta.17",
73
- "@fugood/bricks-cli": "^2.26.0-beta.17",
74
- "@fugood/bricks-devtools-core": "^2.26.0-beta.17",
72
+ "@fugood/agent-tool-runtime": "^2.26.0-beta.18",
73
+ "@fugood/bricks-cli": "^2.26.0-beta.18",
74
+ "@fugood/bricks-devtools-core": "^2.26.0-beta.18",
75
75
  "tsdown": "^0.22.4",
76
76
  "typescript": "^7.0.2"
77
77
  },
78
- "gitHead": "40afa429fd4da51508318825f097533c38e9c541"
78
+ "gitHead": "56a905825a9905fbcf48a3ee7dcc689759b7f1f4"
79
79
  }