@routecraft/ai 0.6.0-canary.9 → 0.6.0
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.
- package/dist/index.cjs +7 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +949 -405
- package/dist/index.d.ts +949 -405
- package/dist/index.js +7 -7
- package/dist/index.js.map +1 -1
- package/package.json +27 -22
package/dist/index.cjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
'use strict';var routecraft=require('@routecraft/routecraft'),async_hooks=require('async_hooks'),http=require('http'),crypto$1=require('crypto'),ai=require('ai'),fs=require('fs'),path=require('path'),promises=require('fs/promises');var z=Symbol.for("routecraft.adapter.llm.providers"),pe=Symbol.for("routecraft.adapter.llm.options");var at={ollama:{baseURL:"http://localhost:11434/api"},lmstudio:{baseURL:"http://localhost:1234/v1"}};function N(t,e,n){if(t===null||typeof t!="object")throw new Error(`[${e}] Invalid model: expected an object, got ${typeof t}. Model id: ${n}`);let o=t;if(typeof o.doGenerate!="function")throw new Error(`[${e}] Invalid model: missing or invalid doGenerate method. Model id: ${n}. Ensure the provider returns an AI SDK-compatible language model.`);if(typeof o.doStream!="function")throw new Error(`[${e}] Invalid model: missing or invalid doStream method. Model id: ${n}. Ensure the provider returns an AI SDK-compatible language model.`)}function ve(t){return {...t.inputTokens!==void 0&&{inputTokens:t.inputTokens},...t.outputTokens!==void 0&&{outputTokens:t.outputTokens},...t.totalTokens!==void 0&&{totalTokens:t.totalTokens}}}function Dt(t){try{if("output"in t&&t.output!==void 0)return t.output}catch{}}function _t(t){let e=t;if(typeof e.reasoningText=="string"&&e.reasoningText.length>0)return e.reasoningText}function ke(t){if(t===null||typeof t!="object")return [];let e=t.steps;if(!Array.isArray(e))return [];let n=[];for(let o of e){if(o===null||typeof o!="object")continue;let r=o.toolCalls,i=o.toolResults;if(Array.isArray(r))for(let a of r){if(a===null||typeof a!="object")continue;let s=a,l=typeof s.toolCallId=="string"?s.toolCallId:"",d=typeof s.toolName=="string"?s.toolName:"",c=s.input??s.args,u={toolCallId:l,toolName:d,input:c};if(Array.isArray(i)){let p=i.find(m=>m.toolCallId===l);p&&(("output"in p||"result"in p)&&(u.output=p.output??p.result),"error"in p&&p.error!==void 0&&(u.error=p.error));}n.push(u);}}return n}function Ce(t){let e={};return t.output!==void 0&&(e.output=t.output),t.tools!==void 0&&Object.keys(t.tools).length>0&&(e.tools=t.tools,t.stopWhen!==void 0&&(e.stopWhen=t.stopWhen)),t.abortSignal!==void 0&&(e.abortSignal=t.abortSignal),e}function be(t,e,n,o,r){let i={model:t,prompt:o,temperature:e.temperature};return e.maxTokens!==void 0&&(i.maxOutputTokens=e.maxTokens),n&&(i.system=n),e.topP!==void 0&&(i.topP=e.topP),e.frequencyPenalty!==void 0&&(i.frequencyPenalty=e.frequencyPenalty),e.presencePenalty!==void 0&&(i.presencePenalty=e.presencePenalty),{...i,...r}}var Nt=["openai","anthropic","openrouter","ollama","gemini","lmstudio","custom"];function eo(t){return Nt.includes(t)}function lt(t){if(!t||typeof t!="object")throw new TypeError("llmPlugin: options must be an object");if(!t.providers||typeof t.providers!="object")throw new TypeError("llmPlugin: options.providers must be an object (record of provider id \u2192 options)");for(let[e,n]of Object.entries(t.providers))if(n!==void 0){if(!n||typeof n!="object")throw new TypeError(`llmPlugin: providers["${e}"] must be an object`);if(!eo(e))throw new TypeError(`llmPlugin: providers["${e}"] is not a supported provider. Supported: ${Nt.join(", ")}`);switch(e){case "openai":case "anthropic":case "openrouter":case "gemini":if(typeof n.apiKey!="string"||!n.apiKey.trim())throw new TypeError(`llmPlugin: providers["${e}"].apiKey is required`);break;case "ollama":case "lmstudio":if(n.baseURL!==void 0&&typeof n.baseURL!="string")throw new TypeError(`llmPlugin: providers["${e}"].baseURL must be a string when provided`);if(n.modelId!==void 0&&(typeof n.modelId!="string"||!n.modelId.trim()))throw new TypeError(`llmPlugin: providers["${e}"].modelId must be a non-empty string when provided`);if(e==="lmstudio"&&n.apiKey!==void 0&&typeof n.apiKey!="string")throw new TypeError('llmPlugin: providers["lmstudio"].apiKey must be a string when provided');break;case "custom":{let o=n.model;if(typeof o=="function")break;if(o===null||typeof o!="object")throw new TypeError('llmPlugin: providers["custom"].model must be an AI SDK language model or a factory function');N(o,"custom","(custom)");break}}}if(t.defaultOptions!==void 0&&(typeof t.defaultOptions!="object"||t.defaultOptions===null))throw new TypeError("llmPlugin: defaultOptions must be an object when provided")}var to=["openai","anthropic","openrouter","ollama","gemini","lmstudio","custom"];function no(t,e){return {provider:t,...e}}function Pe(t={providers:{}}){return lt(t),{apply(e){let n=new Map;for(let o of to){let r=t.providers[o];r!==void 0&&n.set(o,no(o,r));}e.setStore(z,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(pe,t.defaultOptions);}}}var me=Symbol.for("routecraft.mcp.plugin.registered"),M=Symbol.for("routecraft.mcp.client.servers"),J=Symbol.for("routecraft.mcp.tool.registry"),fe=Symbol.for("routecraft.mcp.stdio.managers"),E=Symbol.for("routecraft.mcp.local-tool-registry"),Oe=(n=>(n.TOOL="routecraft.mcp.tool",n.SESSION="routecraft.mcp.session",n))(Oe||{});function Ae(t){return "provider"in t&&t.provider==="oauth"}var oo="GET, POST, OPTIONS";var ro="WWW-Authenticate, Mcp-Session-Id, Last-Event-ID",io=new Set(["localhost","127.0.0.1","::1","[::1]"]);function so(t){if(!t||t==="null")return false;let e;try{e=new URL(t);}catch{return false}return e.protocol!=="http:"&&e.protocol!=="https:"||e.username||e.password||e.pathname!=="/"&&e.pathname!==""||e.search||e.hash?false:io.has(e.hostname)?t:false}function dt(t){if(t===false)return null;if(t===void 0)return {resolveOrigin:so,isWildcard:false};let{origin:e}=t;if(e==="*")return {resolveOrigin:()=>"*",isWildcard:true};if(typeof e=="string"){let n=e;return {resolveOrigin:o=>o===n?n:false,isWildcard:false}}if(Array.isArray(e)){let n=new Set(e);return {resolveOrigin:o=>o!==void 0&&n.has(o)?o:false,isWildcard:false}}if(typeof e=="function")return {resolveOrigin:e,isWildcard:false};throw new TypeError("mcpPlugin: cors.origin must be '*', a string, a string array, or a function")}function ao(t,e){try{return t.resolveOrigin(e)}catch{return false}}function lo(t,e,n){if(!t)return {};let o={};t.isWildcard||(o.Vary="Origin");let r=ao(t,e);return r===false||(o["Access-Control-Allow-Origin"]=r,n?(o["Access-Control-Allow-Methods"]=oo,o["Access-Control-Allow-Headers"]="*",o["Access-Control-Allow-Private-Network"]="true"):o["Access-Control-Expose-Headers"]=ro),o}function ge(t,e,n,o){if(!e)return;let{Vary:r,...i}=lo(e,n,o);for(let[a,s]of Object.entries(i))t.setHeader(a,s);r!==void 0&&t.appendHeader("Vary",r);}var Te="/.well-known/oauth-protected-resource";function ct(t){let e=new Set([Te]),n=t.pathname;return n&&n!=="/"&&n!==""&&e.add(`${Te}${n}`),{ownedPaths:new Set([...e,"/mcp","/mcp/"]),metadataPaths:e}}var $t=t=>`<svg width="200" height="200" viewBox="0 0 200 200" fill="${t}" xmlns="http://www.w3.org/2000/svg"><path d="M125 175H75V125L125 175ZM175 175H125V125L175 175ZM125 25C152.614 25 175 47.3858 175 75C175 102.614 152.614 125 125 125V75H75L125 125H75L25 75V25H125Z" /></svg>`,jt=t=>`data:image/svg+xml;base64,${Buffer.from(t,"utf8").toString("base64")}`,Ut=Object.freeze([Object.freeze({src:jt($t("#ffffff")),mimeType:"image/svg+xml",theme:"dark"}),Object.freeze({src:jt($t("#000000")),mimeType:"image/svg+xml",theme:"light"})]);var uo=["subject","issuer","audience","expiresAt","claims"],po=1e4,mo=3600,ut=class{entries=new Map;inFlight=new Map;maxEntries;constructor(e=po){this.maxEntries=e;}async getOrCompute(e,n,o){if(n===void 0||!Number.isFinite(n))return o();let r=fo(e),i=this.entries.get(r);if(i){if(Date.now()/1e3<i.expiresAt)return i.enrichment;this.entries.delete(r);}let a=this.inFlight.get(r);if(a)return a;let s=o().then(l=>(this.store(r,l,n),this.inFlight.delete(r),l),l=>{throw this.inFlight.delete(r),l});return this.inFlight.set(r,s),s}clear(){this.entries.clear(),this.inFlight.clear();}store(e,n,o){for(this.entries.has(e)&&this.entries.delete(e),this.entries.set(e,{enrichment:n,expiresAt:o});this.entries.size>this.maxEntries;){let r=this.entries.keys().next().value;if(r===void 0)break;this.entries.delete(r);}}};function fo(t){return crypto$1.createHash("sha256").update(t).digest("hex")}function go(t){if(!t)return;let e=t.match(/(?:^|,\s*)max-age=(\d+)/i);if(!e)return;let n=Number.parseInt(e[1],10);return Number.isFinite(n)&&n>=0?n:void 0}function ho(t,e){if(t!==true){let l=new URL(t.toString());return async()=>l}if(e===void 0)throw new TypeError('oauth: `userinfo: true` requires the verify helper to expose an `issuer`. Use `jwks({ issuer, ... })` / `jwt({ issuer, ... })`, pass an explicit `userinfo: "https://idp.example.com/oauth/userinfo"`, or use a function.');if(Array.isArray(e))throw new TypeError("oauth: `userinfo: true` requires a single-string `issuer`; got an array. OIDC Discovery resolves one issuer to one userinfo endpoint. Pass an explicit userinfo URL or function instead.");let n=e.endsWith("/")?e:`${e}/`,o=new URL(".well-known/openid-configuration",n),r=null,i=0,a=null,s=async()=>{let l;try{l=await fetch(o);}catch(p){throw routecraft.rcError("RC5021",p,{message:`OIDC Discovery fetch failed at ${o.toString()}`,suggestion:"Verify network access to the IdP and that the issuer URL is reachable. Pass an explicit `userinfo` URL or function if the IdP does not advertise discovery."})}if(!l.ok)throw routecraft.rcError("RC5021",new Error(`OIDC Discovery fetch returned ${l.status} ${l.statusText}`),{message:`OIDC Discovery fetch failed at ${o.toString()} (status ${l.status})`,suggestion:"Verify the issuer hosts an OIDC Discovery document. Pass an explicit `userinfo` URL or function if it does not."});let d;try{d=await l.json();}catch(p){throw routecraft.rcError("RC5021",p,{message:`OIDC Discovery document at ${o.toString()} is not valid JSON`,suggestion:"Inspect the discovery endpoint manually. Pass an explicit `userinfo` URL or function if the IdP is non-compliant."})}if(typeof d.userinfo_endpoint!="string"||!d.userinfo_endpoint)throw routecraft.rcError("RC5021",new Error("missing userinfo_endpoint in discovery document"),{message:`OIDC Discovery document at ${o.toString()} does not advertise a userinfo_endpoint`,suggestion:"Pass an explicit `userinfo` URL or function for this IdP; it does not advertise auto-discoverable userinfo."});let c=new URL(d.userinfo_endpoint),u=go(l.headers.get("cache-control"))??mo;return r=c,i=Date.now()/1e3+u,c};return async()=>r&&Date.now()/1e3<i?r:a||(a=s().finally(()=>{a=null;}),a)}async function yo(t,e){let n;try{n=await fetch(t,{headers:{Authorization:`Bearer ${e}`}});}catch(o){throw routecraft.rcError("RC5021",o,{message:`userinfo fetch failed at ${t.toString()}`,suggestion:"Verify network access to the IdP's userinfo endpoint and that the bearer token's scopes permit it."})}if(!n.ok)throw routecraft.rcError("RC5021",new Error(`userinfo returned ${n.status} ${n.statusText}`),{message:`userinfo fetch failed at ${t.toString()} (status ${n.status})`,suggestion:"Check the bearer token has the scopes required by the IdP's userinfo endpoint (typically `openid`, `email`, `profile`)."});try{return await n.json()}catch(o){throw routecraft.rcError("RC5021",o,{message:`userinfo response at ${t.toString()} is not valid JSON`,suggestion:"Inspect the userinfo endpoint manually; it must return a JSON object per OIDC Core \xA75.3.2."})}}function Bt(t,e){let n={...t};for(let[o,r]of Object.entries(e))uo.includes(o)||r!==void 0&&(n[o]=r);return n}function wo(t){let e={userinfoClaims:t};return typeof t.email=="string"&&(e.email=t.email),typeof t.name=="string"&&(e.name=t.name),Array.isArray(t.roles)&&(e.roles=t.roles.filter(n=>typeof n=="string")),e}function pt(t,e,n){let o=new ut;if(typeof e=="function")return async i=>{let a=await t(i),s=await o.getOrCompute(i,a.expiresAt,()=>e(a,i));return Bt(a,s)};let r=ho(e,n);return async i=>{let a=await t(i),s=await o.getOrCompute(i,a.expiresAt,async()=>{let l=await r(),d=await yo(l,i),c=d.sub;if(typeof c!="string"||c.length===0)throw routecraft.rcError("RC5022",new Error("userinfo response is missing `sub`"),{message:"userinfo response is missing `sub` (required per OIDC Core \xA75.3.2)",suggestion:"Inspect the userinfo endpoint manually; the response MUST include a `sub` claim. If the IdP returns a non-standard identifier, use a function-mode `userinfo` and map it yourself."});if(c!==a.subject)throw routecraft.rcError("RC5022",new Error(`userinfo \`sub\` (${c}) does not match token \`sub\` (${a.subject})`),{message:"userinfo response `sub` does not match the verified token's `sub` (OIDC Core \xA75.3.2 violation)",suggestion:"This indicates a compromised userinfo endpoint or a misconfigured userinfo URL. Verify the issuer / userinfo mapping; do not relax this check."});return wo(d)});return Bt(a,s)}}function mt(t){return typeof t=="object"&&t!==null&&t.code==="ERR_JWT_EXPIRED"}var Ro=new Set(["ERR_JWKS_TIMEOUT","ERR_JWKS_INVALID","ERR_JOSE_GENERIC"]),vo=new Set(["ECONNREFUSED","ECONNRESET","ENOTFOUND","EAI_AGAIN","ETIMEDOUT","UND_ERR_CONNECT_TIMEOUT","UND_ERR_HEADERS_TIMEOUT","UND_ERR_SOCKET"]);function Ft(t){let e=t;for(let n=0;n<5;n++){if(typeof e!="object"||e===null)return false;let o=e.code;if(typeof o=="string"&&(Ro.has(o)||vo.has(o)))return true;e=e.cause;}return false}var Vt=new async_hooks.AsyncLocalStorage,Y=class{context;options;server=null;transport=null;httpServer=null;httpSessions=new Map;running=false;toolsListLogged=false;validatorVerifier=null;constructor(e,n={}){this.context=e,this.options={name:"routecraft",version:"1.0.0",transport:"stdio",port:3001,host:"localhost",...n},this.validateResourceConfig();}resolveServerIcons(){return this.options.icons===void 0?Ut:this.options.icons}defaultUnlessEmpty(e,n){let o=e??n;return o===""?void 0:o}buildServerInfo(){let e={name:this.options.name,version:this.options.version};this.options.title!==void 0&&(e.title=this.options.title);let n=this.defaultUnlessEmpty(this.options.description,"Powered by Routecraft.dev");n!==void 0&&(e.description=n);let o=this.defaultUnlessEmpty(this.options.websiteUrl,"https://routecraft.dev");o!==void 0&&(e.websiteUrl=o);let r=this.resolveServerIcons();return r.length>0&&(e.icons=r),e}buildServerOptions(){let e={capabilities:{tools:{}}},n=this.defaultUnlessEmpty(this.options.instructions,"");return n!==void 0&&(e.instructions=n),e}validateResourceConfig(){let e=this.options.resource?.url;if(e===void 0)return;if(new URL(e.toString()).protocol!=="https:"&&process.env.NODE_ENV==="production")throw new TypeError("mcpPlugin: resource.url must use HTTPS in production")}async start(){if(this.running){this.context.logger.warn({},"MCP server already running");return}try{let e=this.options.transport;e==="http"?await this.startHttp():await this.startStdio(),this.running=!0,this.context.logger.info({name:this.options.name,version:this.options.version,transport:e},"MCP server started"),this.logExposedToolsOnce();}catch(e){let n=routecraft.isRoutecraftError(e)?e.meta.message:e instanceof Error?e.message:"Failed to start MCP server";throw this.context.logger.error({err:e},n),e}}async startStdio(){let n=(await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/server/index.js'),{adapterName:"mcp (stdio)",packageName:"@modelcontextprotocol/sdk"})).Server,r=(await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/server/stdio.js'),{adapterName:"mcp (stdio)",packageName:"@modelcontextprotocol/sdk"})).StdioServerTransport;this.server=new n(this.buildServerInfo(),this.buildServerOptions()),await this.setupRequestHandlers(),this.transport=new r,await this.server.connect(this.transport);}async startHttp(){this.options.auth&&Ae(this.options.auth)?await this.startHttpWithOAuth(this.options.auth):await this.startHttpWithValidator();}async importSdkHttp(){let n=(await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/server/index.js'),{adapterName:"mcp (http)",packageName:"@modelcontextprotocol/sdk"})).Server,r=(await import('@modelcontextprotocol/sdk/server/streamableHttp.js').catch(()=>null))?.StreamableHTTPServerTransport;if(!r)throw new Error("StreamableHTTPServerTransport not found in MCP SDK - ensure @modelcontextprotocol/sdk v1.26.0+ is installed");return {ServerCtor:n,TransportClass:r}}async createSession(e,n){let o=new e(this.buildServerInfo(),this.buildServerOptions());await this.setupRequestHandlersOn(o);let r=new n({sessionIdGenerator:()=>crypto.randomUUID(),onsessioninitialized:d=>{this.httpSessions.set(d,{server:o,transport:r}),this.context.logger.debug({sessionId:d},"MCP session created"),this.context.emit("plugin:mcp:session:created",{sessionId:d});},enableJsonResponse:true});await o.connect(r);let a=r,s=a.onclose;a.onclose=()=>{let d=r.sessionId;d&&(this.httpSessions.delete(d),this.context.logger.debug({sessionId:d},"MCP session closed"),this.context.emit("plugin:mcp:session:closed",{sessionId:d})),s?.();};let l=r.handleRequest;if(typeof l!="function")throw new Error("StreamableHTTPServerTransport.handleRequest not found - SDK may have changed");return {transport:r,handleRequest:l.bind(r)}}async handleMcpRequest(e,n,o,r){let i=e.headers["mcp-session-id"],a=s=>Vt.run(o,s);try{if(i&&this.httpSessions.has(i)){let s=this.httpSessions.get(i),l=s.transport.handleRequest;await a(()=>l.call(s.transport,e,n));}else if(!i||e.method==="POST"){let{handleRequest:s}=await r();await a(()=>s(e,n));}else n.writeHead(404,{"Content-Type":"application/json"}),n.end(JSON.stringify({error:"Session not found"}));}catch(s){let l=routecraft.isRoutecraftError(s)?s.meta.message:s instanceof Error?s.message:"MCP HTTP request error";this.context.logger.error({err:s},l),n.headersSent||(n.writeHead(500,{"Content-Type":"application/json"}),n.end(JSON.stringify({error:"Internal Server Error"})));}}resolveResourceUrl(){let e=this.options.resource?.url;if(e!==void 0)return e.toString();let n=this.options.host,o=this.getHttpPort()??this.options.port;return `http://${n}:${o}/mcp`}resolveResourceName(){return this.options.title??this.options.name}buildProtectedResourceMetadata(){let e={resource:this.resolveResourceUrl(),bearer_methods_supported:["header"]};e.resource_name=this.resolveResourceName();let n=this.options.auth;if(n&&!("provider"in n)&&"issuer"in n){let r=n.issuer;r!==void 0&&(e.authorization_servers=Array.isArray(r)?r:[r]);}let o=this.options.resource;return o?.scopesSupported&&o.scopesSupported.length>0&&(e.scopes_supported=o.scopesSupported),o?.documentationUrl!==void 0&&(e.resource_documentation=o.documentationUrl.toString()),e}resolveResourceMetadataUrl(){return new URL(Te,this.resolveResourceUrl()).toString()}buildWwwAuthenticateHeader(){return `Bearer realm="mcp", resource_metadata="${this.resolveResourceMetadataUrl()}"`}serveProtectedResourceMetadata(e){let n=this.buildProtectedResourceMetadata();e.writeHead(200,{"Content-Type":"application/json","Cache-Control":"public, max-age=3600"}),e.end(JSON.stringify(n));}async startHttpWithValidator(){let{ServerCtor:e,TransportClass:n}=await this.importSdkHttp(),o=this.options.port,r=this.options.host,i=dt(this.options.cors);this.validatorVerifier=this.buildValidatorVerifier();let a=()=>this.createSession(e,n);this.httpServer=http.createServer(async(s,l)=>{let d=s.url?.split("?")[0]??"",c=s.headers.origin,u=Array.isArray(c)?c[0]:c,p=new URL(this.resolveResourceUrl()),{ownedPaths:m,metadataPaths:f}=ct(p);if(s.method==="OPTIONS"&&i!==null&&m.has(d)){ge(l,i,u,true),l.writeHead(204),l.end();return}if(s.method!=="OPTIONS"&&ge(l,i,u,false),f.has(d)){this.serveProtectedResourceMetadata(l);return}if(d!=="/mcp"&&d!=="/mcp/"){l.writeHead(404,{"Content-Type":"application/json"}),l.end(JSON.stringify({error:"Not Found",path:d}));return}let h;if(this.options.auth){let g=await this.validateAuth(s);if(!g){l.writeHead(401,{"Content-Type":"application/json","WWW-Authenticate":this.buildWwwAuthenticateHeader()}),l.end(JSON.stringify({error:"Unauthorized"}));return}h=g;}await this.handleMcpRequest(s,l,h,a);}),await this.listenHttp(o,r);}async startHttpWithOAuth(e){let{ServerCtor:n,TransportClass:o}=await this.importSdkHttp(),r;try{let P=await import('express');r=P.default??P;}catch{throw new Error('OAuth auth requires "express" (optional peer dependency of @routecraft/ai). Install it with: bun add express')}let a=(await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/server/auth/router.js'),{adapterName:"mcp (oauth)",packageName:"@modelcontextprotocol/sdk"})).mcpAuthRouter,l=(await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js'),{adapterName:"mcp (oauth)",packageName:"@modelcontextprotocol/sdk"})).requireBearerAuth,c=(await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/server/auth/providers/proxyProvider.js'),{adapterName:"mcp (oauth)",packageName:"@modelcontextprotocol/sdk"})).ProxyOAuthServerProvider,p=(await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/server/auth/errors.js'),{adapterName:"mcp (oauth)",packageName:"@modelcontextprotocol/sdk"})).InvalidTokenError,m=this.options.userinfo===void 0?e.verifyAccessToken:pt(e.verifyAccessToken,this.options.userinfo,e.issuer),f=async P=>{let C;try{C=await m(P);}catch(R){let S=mt(R),T={reason:R instanceof Error?R.message:"invalid_token",scheme:"bearer",source:"mcp",path:"oauth"};throw S?this.context.logger.debug({err:R,...T},"Auth rejected: token expired"):this.context.logger.warn({err:R,...T},"Auth rejected: token validation failed"),this.context.emit("auth:rejected",T),routecraft.isRoutecraftError(R)||Ft(R)?R:new p(S?"Token has expired":"Invalid token")}if(C.expiresAt===void 0){let R={reason:"missing_expires_at",scheme:"bearer",source:"mcp",path:"oauth"};throw this.context.logger.warn(R,"Auth rejected: OAuth principal is missing expiresAt"),this.context.emit("auth:rejected",R),new Error("oauth: verifyAccessToken must return a principal with expiresAt (required by MCP SDK bearer middleware)")}return C.clientId||this.context.logger.debug({subject:C.subject},"oauth: principal missing clientId; using subject as fallback for AuthInfo.clientId"),{token:P,clientId:C.clientId??C.subject,scopes:C.scopes??[],expiresAt:C.expiresAt,extra:{principal:C}}},h=new c({endpoints:{authorizationUrl:e.endpoints.authorizationUrl,tokenUrl:e.endpoints.tokenUrl,revocationUrl:e.endpoints.revocationUrl,registrationUrl:e.endpoints.registrationUrl},verifyAccessToken:f,getClient:e.getClient}),g=this.options.port,w=this.options.host;if(g===0&&this.options.resource?.url===void 0)throw new TypeError('mcpPlugin: OAuth-proxy mode requires either a fixed `port` or an explicit `resource.url`. With `port: 0` (ephemeral) and no `resource.url`, the protected-resource metadata URL would advertise `:0`. Pass `resource: { url: "https://..." }` or a non-zero `port`.');let v=new URL(this.resolveResourceUrl()),{ownedPaths:A,metadataPaths:K}=ct(v),W=r(),st=dt(this.options.cors);st!==null&&W.use((P,C,Re)=>{let R=P,S=C,_=R.url?.split("?")[0]??"",T=R.headers.origin,It=Array.isArray(T)?T[0]:T;if(R.method==="OPTIONS"&&A.has(_)){ge(S,st,It,true),S.writeHead(204),S.end();return}R.method!=="OPTIONS"&&ge(S,st,It,false),Re();});let Zn=(P,C)=>{this.serveProtectedResourceMetadata(C);};for(let P of K)W.get(P,Zn);let ce={provider:h,issuerUrl:v};e.baseUrl&&(ce.baseUrl=new URL(e.baseUrl.toString()));let ue=this.options.resource;ue?.scopesSupported&&ue.scopesSupported.length>0&&(ce.scopesSupported=ue.scopesSupported),ue?.documentationUrl!==void 0&&(ce.serviceDocumentationUrl=new URL(ue.documentationUrl.toString()));let xt=this.resolveResourceName();xt&&(ce.resourceName=xt),W.use(a(ce));let Lt={verifier:h,resourceMetadataUrl:this.resolveResourceMetadataUrl()};e.requiredScopes&&(Lt.requiredScopes=e.requiredScopes),W.use("/mcp",l(Lt));let Qn=()=>this.createSession(n,o);W.all("/mcp",async(P,C)=>{let Re=P,R=C,S=P.auth,_=this.authInfoToPrincipal(S);if(_){let T={subject:_.subject,scheme:_.scheme,source:"mcp"};this.context.logger.info(T,"Auth succeeded"),this.context.emit("auth:success",T);}await this.handleMcpRequest(Re,R,_,Qn);}),this.httpServer=http.createServer(W),await this.listenHttp(g,w);}async listenHttp(e,n){await new Promise((i,a)=>{this.httpServer.listen(e,n,()=>i()),this.httpServer.on("error",s=>{let l=routecraft.isRoutecraftError(s)?s.meta.message:s instanceof Error?s.message:"MCP HTTP server listen failed";this.context.logger.error({err:s},l),a(s);});});let o=this.getHttpPort()??e,r={host:n,port:o,path:"/mcp"};this.context.logger.info(r,"MCP HTTP server listening"),this.context.emit("plugin:mcp:server:listening",r);}authInfoToPrincipal(e){if(!e)return;let n=e.extra?.principal;if(n)return n;let o={kind:"oauth",scheme:"bearer",subject:e.clientId,clientId:e.clientId,scopes:e.scopes};return e.expiresAt!==void 0&&(o.expiresAt=e.expiresAt),o}getHttpPort(){let e=this.httpServer?.address();if(e&&typeof e=="object"&&"port"in e)return e.port}buildValidatorVerifier(){let e=this.options.auth;if(!e||!("validator"in e))return null;let n=o=>Promise.resolve(e.validator(o));return this.options.userinfo===void 0?n:pt(n,this.options.userinfo,e.issuer)}async validateAuth(e){let n=this.options.auth;if(!n||!("validator"in n))return null;let o=this.validatorVerifier??this.buildValidatorVerifier();if(!o)return null;let r=e.headers.authorization;if(!r||Array.isArray(r)){let s={reason:"missing_header",scheme:"bearer",source:"mcp"};return this.context.logger.debug(s,"Auth rejected: missing or malformed Authorization header"),this.context.emit("auth:rejected",s),null}let i=/^bearer\s+(.+)$/i.exec(r);if(!i){let s={reason:"unsupported_scheme",scheme:"bearer",source:"mcp"};return this.context.logger.debug(s,"Auth rejected: unsupported authorization scheme"),this.context.emit("auth:rejected",s),null}let a=i[1];try{let s=await o(a),l={subject:s.subject,scheme:s.scheme,source:"mcp"};return this.context.logger.info(l,"Auth succeeded"),this.context.emit("auth:success",l),s}catch(s){let d={reason:s instanceof Error?s.message:"invalid_token",scheme:"bearer",source:"mcp"};return mt(s)?this.context.logger.debug({err:s,...d},"Auth rejected: token expired"):this.context.logger.warn({err:s,...d},"Auth rejected: token validation failed"),this.context.emit("auth:rejected",d),null}}async setupRequestHandlers(){await this.setupRequestHandlersOn(this.server);}async setupRequestHandlersOn(e){let o=await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/types.js'),{adapterName:"mcp",packageName:"@modelcontextprotocol/sdk"}),r=o.ListToolsRequestSchema,i=o.CallToolRequestSchema;if(!r||!i)throw new Error("MCP SDK types missing ListToolsRequestSchema or CallToolRequestSchema - ensure @modelcontextprotocol/sdk is installed");let a=e;a.setRequestHandler(r,async()=>{let s=this.getAvailableTools();return this.logExposedToolsOnce(),{tools:s}}),a.setRequestHandler(i,async s=>{let d=s.params;return await this.handleToolCall(d.name||"",d.arguments||{})});}async stop(){if(this.running)try{if(this.httpServer){for(let[,n]of this.httpSessions){let o=n.transport;typeof o.close=="function"&&await o.close();}this.httpSessions.clear();let e=this.httpServer;typeof e.closeAllConnections=="function"&&e.closeAllConnections(),await new Promise(n=>{this.httpServer.close(()=>n());}),this.httpServer=null;}if(this.transport){let e=this.transport;typeof e.close=="function"&&await e.close();}this.running=!1,this.context.logger.info({},"MCP server stopped");}catch(e){let n=routecraft.isRoutecraftError(e)?e.meta.message:e instanceof Error?e.message:"Error stopping MCP server";this.context.logger.error({err:e},n);}}logExposedToolsOnce(){if(this.toolsListLogged)return;let e=this.getAvailableTools();if(e.length===0)return;let n=e.map(r=>r.name),o={tools:n,count:n.length};this.context.logger.info(o,"Exposing MCP tools"),this.context.emit("plugin:mcp:server:tools:exposed",o),this.toolsListLogged=true;}getAvailableTools(){let e=this.context.getStore(E);if(!e)return [];let n=Array.from(e.values()),o=this.options.tools;if(o)if(Array.isArray(o)){let r=new Set(o);n=n.filter(i=>r.has(i.endpoint));}else typeof o=="function"&&(n=n.filter(o));return n.map(r=>this.entryToMcpTool(r))}entryToMcpTool(e){let n={name:e.endpoint,description:e.description,inputSchema:this.schemaToJsonSchema(e.input?.body)};e.title!==void 0&&(n.title=e.title),e.output?.body!==void 0&&(n.outputSchema=this.schemaToJsonSchema(e.output.body)),e.annotations!==void 0&&(n.annotations=e.annotations);let o=e.icons??this.resolveServerIcons();return o.length>0&&(n.icons=o),n}schemaToJsonSchema(e){if(!e||typeof e!="object")return {type:"object"};let n=e["~standard"];if(n?.jsonSchema?.input)try{let o=n.jsonSchema.input({target:"draft-2020-12"});return typeof o=="object"&&o!==null?o:{type:"object"}}catch(o){return this.context.logger.debug(o,"Standard JSON Schema conversion failed"),{type:"object"}}return "~standard"in e?{type:"object",additionalProperties:true}:{type:"object"}}async handleToolCall(e,n){try{let r=this.context.getStore(E)?.get(e);if(!r){let u=new Error(`Tool not found: ${e}`);return this.context.emit("plugin:mcp:tool:failed",{tool:e,error:u.message}),{isError:!0,content:[{type:"text",text:`Error: Tool not found: ${e}`}]}}let i=typeof n=="string"?(()=>{try{return JSON.parse(n)||{}}catch{return {input:n}}})():n&&typeof n=="object"?n:{};this.context.logger.debug({bodyType:typeof i,body:i},"MCP tool call exchange body");let a=Vt.getStore(),s={"routecraft.mcp.tool":e,"routecraft.mcp.session":`mcp-${Date.now()}`};a&&(s[routecraft.HeadersKeys.AUTH_PRINCIPAL]=routecraft.markAuthentic(a));let l=new routecraft.DefaultExchange(this.context,{body:i,headers:s});this.context.emit("plugin:mcp:tool:called",{tool:e,args:n});let d=await r.handler(l),c=typeof d.body=="string"?d.body:JSON.stringify(d.body);return this.context.emit("plugin:mcp:tool:completed",{tool:e}),{content:[{type:"text",text:c}]}}catch(o){let r=routecraft.isRoutecraftError(o)?o.meta.message:o instanceof Error?o.message:String(o);this.context.logger.error({tool:e,err:o},r),this.context.emit("plugin:mcp:tool:failed",{tool:e,error:r});let i=r;if(routecraft.isRoutecraftError(o)){let a=o.cause;a?.message&&(i=`${r}: ${a.message}`);}return {content:[{type:"text",text:`Error: ${i}`}],isError:true}}}};function Gt(t){if(t.transport==="http"){if(t.port!==void 0){if(typeof t.port!="number")throw new TypeError("mcpPlugin: when transport is 'http', port must be a number");if(t.port<0||t.port>65535)throw new RangeError("mcpPlugin: port must be between 0 and 65535 when transport is 'http'")}if(t.host!==void 0&&typeof t.host!="string")throw new TypeError("mcpPlugin: when provided, host must be a string")}if(t.transport==="http"&&t.cors!==void 0&&t.cors!==false){let{origin:e}=t.cors;if(!(e==="*"||typeof e=="string"||Array.isArray(e)||typeof e=="function"))throw new TypeError("mcpPlugin: cors.origin must be '*', a string, a string array, or a function")}if(t.auth!==void 0)if("provider"in t.auth){if(t.auth.provider!=="oauth")throw new TypeError('mcpPlugin: auth.provider must be "oauth". Use the oauth() helper.')}else if("validator"in t.auth){if(typeof t.auth.validator!="function")throw new TypeError("mcpPlugin: auth.validator must be a function that returns a Principal (throw to reject)")}else throw new TypeError("mcpPlugin: auth must have either a 'validator' function or 'provider' set to 'oauth'. Use jwt(), jwks(), oauth(), or a custom { validator } object.");if(t.clients){for(let[e,n]of Object.entries(t.clients))if(typeof n=="object"&&n!==null&&"transport"in n&&n.transport==="stdio"&&(!n.command||typeof n.command!="string"))throw new TypeError(`mcpPlugin: stdio client "${e}" must have a non-empty command string`)}if(t.maxRestarts!==void 0&&(typeof t.maxRestarts!="number"||!Number.isInteger(t.maxRestarts)||t.maxRestarts<0))throw new TypeError("mcpPlugin: maxRestarts must be a non-negative integer");if(t.restartDelayMs!==void 0&&(typeof t.restartDelayMs!="number"||t.restartDelayMs<=0))throw new TypeError("mcpPlugin: restartDelayMs must be a positive number");if(t.restartBackoffMultiplier!==void 0&&(typeof t.restartBackoffMultiplier!="number"||t.restartBackoffMultiplier<1))throw new TypeError("mcpPlugin: restartBackoffMultiplier must be >= 1");if(t.toolRefreshIntervalMs!==void 0&&(typeof t.toolRefreshIntervalMs!="number"||!Number.isInteger(t.toolRefreshIntervalMs)||t.toolRefreshIntervalMs<0))throw new TypeError("mcpPlugin: toolRefreshIntervalMs must be a non-negative integer")}async function qt(t,e){let n=e["~standard"];if(!n?.validate)throw new Error("mcpPlugin: schema must be a StandardSchemaV1 with ~standard.validate");let o=n.validate(t);if(o instanceof Promise&&(o=await o),o.issues)throw new Error(`mcpPlugin options validation failed: ${routecraft.formatSchemaIssues(o.issues)}`);if(o.value===void 0)throw new Error("mcpPlugin options validation failed: no value returned");return o.value}function Me(t){let e=t?.content;if(!Array.isArray(e)||e.length===0)return t;if(e.length===1){let n=e[0];if(n.type==="text"&&typeof n.text=="string")return n.text;if(typeof n.data=="string")return n.data}return e}var Se=class{constructor(e,n,o,r){this.options=e;this.logger=n;this.onEvent=o;this.onToolsUpdated=r;}options;logger;onEvent;onToolsUpdated;client=null;transport=null;running=false;stopping=false;restartCount=0;restartTimer=null;stabilityTimer=null;tools=[];async start(){if(this.running)return;this.stopping=false,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null);let e=await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/client/index.js'),{adapterName:"mcp (stdio client)",packageName:"@modelcontextprotocol/sdk"}),n=await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/client/stdio.js'),{adapterName:"mcp (stdio client)",packageName:"@modelcontextprotocol/sdk"}),{serverId:o,command:r,args:i,env:a,cwd:s}=this.options;this.transport=new n.StdioClientTransport({command:r,args:i??[],...a?{env:a}:{},...s?{cwd:s}:{},stderr:"pipe"});let l=this.transport;l.onerror=d=>{this.logger.error({err:d,serverId:o},"Stdio client transport error"),this.onEvent(`plugin:mcp:client:${o}:error`,{serverId:o,error:d});},l.onclose=()=>{this.stopping||(this.running=false,this.handleDisconnect());},l.stderr?.on&&l.stderr.on("data",d=>{this.logger.debug({serverId:o,stderr:String(d).trimEnd()},"Stdio client stderr output");}),this.client=new e.Client({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{},listChanged:{tools:{onChanged:(d,c)=>{c&&Array.isArray(c.tools)?(this.tools=c.tools,this.onToolsUpdated(o,this.tools),this.onEvent(`plugin:mcp:client:${o}:tools:listed`,{serverId:o,toolCount:this.tools.length})):this.refreshTools();}}}}),await this.client.connect(this.transport),this.running=true,await this.refreshTools(),this.logger.info({serverId:o,toolCount:this.tools.length},"Stdio client started"),this.onEvent(`plugin:mcp:client:${o}:started`,{serverId:o,toolCount:this.tools.length});}async stop(){this.stopping=true,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null),this.stabilityTimer&&(clearTimeout(this.stabilityTimer),this.stabilityTimer=null);let{serverId:e}=this.options;if(this.client){try{await this.client.close();}catch{}this.client=null;}if(this.transport){let n=this.transport;if(typeof n.close=="function")try{await Promise.resolve(n.close());}catch{}this.transport=null;}this.running=false,this.logger.info({serverId:e},"Stdio client stopped"),this.onEvent(`plugin:mcp:client:${e}:stopped`,{serverId:e,reason:"graceful"});}async callTool(e,n){if(!this.running||!this.client)throw new Error(`Stdio client "${this.options.serverId}" is not running. Cannot call tool "${e}".`);let o=await this.client.callTool({name:e,arguments:n});return Me(o)}getTools(){return [...this.tools]}isRunning(){return this.running}async refreshTools(){if(!this.client)return;let{serverId:e}=this.options;try{let n=await this.client.listTools();this.tools=n.tools??[],this.onToolsUpdated(e,this.tools),this.onEvent(`plugin:mcp:client:${e}:tools:listed`,{serverId:e,toolCount:this.tools.length});}catch(n){this.logger.warn({err:n,serverId:e},"Failed to list tools for stdio client");}}handleDisconnect(){let{serverId:e,maxRestarts:n,restartDelayMs:o,restartBackoffMultiplier:r}=this.options;if(this.tools.length>0&&(this.tools=[],this.onToolsUpdated(e,[])),this.logger.warn({serverId:e},"Stdio client disconnected unexpectedly"),this.onEvent(`plugin:mcp:client:${e}:stopped`,{serverId:e,reason:"unexpected"}),this.restartCount>=n){this.logger.error({serverId:e,restartCount:this.restartCount,maxRestarts:n},"Stdio client exceeded max restarts, giving up"),this.onEvent(`plugin:mcp:client:${e}:error`,{serverId:e,error:new Error(`Max restarts (${n}) exceeded for stdio client "${e}"`)});return}let i=o*Math.pow(r,this.restartCount);this.logger.info({serverId:e,restartCount:this.restartCount,delayMs:i},"Scheduling stdio client restart"),this.restartTimer=setTimeout(()=>{this.restartTimer=null,this.restart();},i);}async restart(){let{serverId:e}=this.options;this.restartCount++,this.client=null,this.transport=null;try{await this.start(),this.logger.info({serverId:e,restartCount:this.restartCount},"Stdio client restarted successfully"),this.onEvent(`plugin:mcp:client:${e}:restarted`,{serverId:e,restartCount:this.restartCount});let n=this.options.restartDelayMs*2;this.stabilityTimer=setTimeout(()=>{this.stabilityTimer=null,this.running&&(this.restartCount=0);},n);}catch(n){this.logger.error({err:n,serverId:e,restartCount:this.restartCount},"Stdio client restart failed"),this.onEvent(`plugin:mcp:client:${e}:error`,{serverId:e,error:n}),this.handleDisconnect();}}};function Ao(t){if(!t)return [];let e=[];return t.readOnlyHint&&e.push("read-only"),t.destructiveHint&&e.push("destructive"),t.idempotentHint&&e.push("idempotent"),t.openWorldHint&&e.push("open-world"),e}var X=class{tools=new Map;setToolsForSource(e,n,o){let r=new Map;for(let i of o){let a={name:i.name,inputSchema:i.inputSchema,source:e,transport:n};i.description!==void 0&&(a.description=i.description),i.annotations!==void 0&&(a.annotations=i.annotations);let s=Ao(i.annotations);s.length>0&&(a.tags=s),r.set(i.name,a);}this.tools.set(e,r);}removeSource(e){this.tools.delete(e);}getTools(){let e=[];for(let n of this.tools.values())for(let o of n.values())e.push(o);return e}getToolsByServer(e){let n=this.tools.get(e);return n?Array.from(n.values()):[]}getTool(e){for(let n of this.tools.values()){let o=n.get(e);if(o)return o}}getToolBySource(e,n){return this.tools.get(e)?.get(n)}};var Wt=new WeakMap;async function To(t){if(typeof t=="function")return t();if(Array.isArray(t)){if(t.length===0)throw new Error("McpClientAuthOptions.token array must not be empty");let e=(Wt.get(t)??0)%t.length;return Wt.set(t,e+1),t[e]}return t}async function Ee(t){if(!t)return;let e={},n=t.headers??{},o=Object.entries(n).find(([r])=>r.toLowerCase()==="authorization")?.[1];if(o)e.Authorization=o;else if(t.token!==void 0){let r=await To(t.token);if(r.length===0)throw new Error("McpClientAuthOptions.token must be a non-empty string when provided");e.Authorization=`Bearer ${r}`;}for(let[r,i]of Object.entries(n))r.toLowerCase()!=="authorization"&&(e[r]=i);return Object.keys(e).length>0?e:void 0}function Jt(t){return "transport"in t&&t.transport==="stdio"}function xe(t={}){Gt(t);let e=null,n=new Map,o=new Map,r=[],i=null;return {async apply(c){if(c.setStore(me,true),i=new X,c.setStore(J,i),c.setStore(fe,n),t.clients&&Object.keys(t.clients).length>0){let u=Object.entries(t.clients),p=new Map;for(let[m,f]of u)p.set(m,f);c.setStore(M,p);for(let[m,f]of u){if(Jt(f))await a(c,m,f,i);else {let g=f;await l(c,m,g.url,i,g.auth),d(c,m,g.url,i,g.auth);}let h=Jt(f)?"stdio":"http";c.emit(`plugin:mcp:client:${m}:registered`,{serverId:m,transport:h});}}e=new Y(c,t),await e.start();},async teardown(c){for(let u of r)clearInterval(u);r.length=0;for(let[u,p]of o)try{await p.close();}catch(m){c.logger.error({err:m,serverId:u,operation:"close"},"Failed to close HTTP client");}o.clear();for(let[u,p]of n)try{await p.stop();}catch(m){c.logger.error({err:m,serverId:u,operation:"stop"},"Failed to stop stdio client");}if(n.clear(),e){try{await e.stop();}catch(u){c.logger.error({err:u,operation:"stop"},"Failed to stop MCP server plugin");}e=null;}i=null;}};async function a(c,u,p,m){let f={serverId:u,command:p.command,args:p.args??[],maxRestarts:t.maxRestarts??5,restartDelayMs:t.restartDelayMs??1e3,restartBackoffMultiplier:t.restartBackoffMultiplier??2};p.env!==void 0&&(f.env=p.env),p.cwd!==void 0&&(f.cwd=p.cwd);let h=new Se(f,c.logger,(g,w)=>{c.emit(g,w);},(g,w)=>{m.setToolsForSource(g,"stdio",w);});n.set(u,h);try{await h.start();}catch(g){c.logger.error({err:g,serverId:u,operation:"start"},"Failed to start stdio client"),c.emit(`plugin:mcp:client:${u}:error`,{serverId:u,error:g});}}async function s(c,u,p){let m=o.get(c);if(m)return m;let{Client:f}=await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/client/index.js'),{adapterName:"mcp (http client)",packageName:"@modelcontextprotocol/sdk"}),{StreamableHTTPClientTransport:h}=await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/client/streamableHttp.js'),{adapterName:"mcp (http client)",packageName:"@modelcontextprotocol/sdk"}),g=await Ee(p),w=g?{requestInit:{headers:g}}:void 0,v=new h(new URL(u),w),A=new f({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{}});await A.connect(v);let K=A;return o.set(c,K),K}async function l(c,u,p,m,f){try{let w=(await(await s(u,p,f)).listTools()).tools??[];m.setToolsForSource(u,"http",w),c.emit(`plugin:mcp:client:${u}:tools:listed`,{serverId:u,toolCount:w.length});}catch(h){o.delete(u),c.logger.warn({err:h,serverId:u,url:p,operation:"listTools"},"Failed to list tools from HTTP client");}}function d(c,u,p,m,f){let h=t.toolRefreshIntervalMs??6e4;if(h<=0)return;let g=setInterval(()=>{l(c,u,p,m,f);},h);r.push(g);}}var Le=new Map;async function Ie(){let t=[...Le.entries()];Le.clear(),t.length!==0&&await Promise.all(t.map(async([,e])=>{try{typeof e.dispose=="function"&&await e.dispose();}catch{}}));}function So(t){return t.includes("/")?t:`Xenova/${t}`}async function Eo(t){let e=So(t),n=Le.get(e);if(n)return n.run;let r=await(await routecraft.loadOptionalPeer(()=>import('@huggingface/transformers'),{adapterName:"Hugging Face embedding",packageName:"@huggingface/transformers"})).pipeline("feature-extraction",e,{dtype:"fp32"}),i=(s,l)=>r(s,{pooling:l?.pooling??"mean",normalize:l?.normalize??true}),a={run:i,dispose:typeof r.dispose=="function"?()=>Promise.resolve(r.dispose()):void 0};return Le.set(e,a),i}function Yt(t){if(t===null)return "null";if(typeof t!="object")return String(t);if(Array.isArray(t))return `array(${t.length})`;try{let e=JSON.stringify(t);return e.length>100?e.slice(0,100)+"...":e}catch{return "object"}}function xo(t){if(Array.isArray(t))return t;if(t instanceof Float32Array)return Array.from(t);if(t&&typeof t=="object"&&"data"in t){let e=t.data;if(Array.isArray(e))return e;if(e instanceof Float32Array)return Array.from(e);throw new Error(`Embedding output .data must be an Array or Float32Array; got ${typeof e}: ${Yt(e)}`)}throw new Error(`Embedding output must be an Array, Float32Array, or object with .data; got ${typeof t}: ${Yt(t)}`)}async function Xt(t){let{config:e,modelName:n,text:o}=t;if(e.provider==="mock"){let i=[];for(let a=0;a<8;a++)i.push((o.length+a)%100/100);return i}if(e.provider==="huggingface"){let i=await(await Eo(n))(o,{pooling:"mean",normalize:true}),a=i&&typeof i=="object"&&"data"in i?i.data:i;return xo(a)}throw e.provider==="ollama"||e.provider==="openai"?new Error(`Embedding provider "${e.provider}" is not yet implemented. Use huggingface for now.`):new Error(`Unknown embedding provider: ${e.provider}`)}var De=Symbol.for("routecraft.adapter.embedding.providers"),_e=Symbol.for("routecraft.adapter.embedding.options");function Lo(t,e){return {...e,provider:t}}function Ne(t={providers:{}}){return {apply(e){let n=new Map;for(let[o,r]of Object.entries(t.providers))r!==void 0&&n.set(o,Lo(o,r));e.setStore(De,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(_e,t.defaultOptions);},async teardown(){await Ie();}}}function Zt(t){let e=routecraft.getExchangeRoute(t);return {forward:e?e.getForward():async()=>{throw routecraft.rcError("RC5025",void 0,{message:"Block resolver: client.forward() called but the exchange has no bound route. Block resolvers can only forward when invoked through a real route dispatch."})}}}var ft="__",nn=Symbol.for("routecraft.ai.block.loader-tool"),U="_block_",j="_block_load_";function on(t){return t[nn]===true}async function rn(t,e,n){if(!t)return {systemAppend:"",loaderTools:[]};let o=_o(t);if(o.size===0)return {systemAppend:"",loaderTools:[]};let r=Zt(e),i=[],a=[];for(let[s,l]of o){if(l.mode==="inject"){let d=await an(s,l,e,n,r);i.push(`
|
|
1
|
+
'use strict';var routecraft=require('@routecraft/routecraft'),http=require('http'),crypto$1=require('crypto'),ai$1=require('ai'),fs=require('fs'),path=require('path'),promises=require('fs/promises');var V=Symbol.for("routecraft.adapter.llm.providers"),ie=Symbol.for("routecraft.adapter.llm.options");var rt={ollama:{baseURL:"http://localhost:11434/api"},lmstudio:{baseURL:"http://localhost:1234/v1"}};function S(t,e,n){if(t===null||typeof t!="object")throw new Error(`[${e}] Invalid model: expected an object, got ${typeof t}. Model id: ${n}`);let o=t;if(typeof o.doGenerate!="function")throw new Error(`[${e}] Invalid model: missing or invalid doGenerate method. Model id: ${n}. Ensure the provider returns an AI SDK-compatible language model.`);if(typeof o.doStream!="function")throw new Error(`[${e}] Invalid model: missing or invalid doStream method. Model id: ${n}. Ensure the provider returns an AI SDK-compatible language model.`)}function he(t){return {...t.inputTokens!==void 0&&{inputTokens:t.inputTokens},...t.outputTokens!==void 0&&{outputTokens:t.outputTokens},...t.totalTokens!==void 0&&{totalTokens:t.totalTokens},...t.inputTokenDetails?.cacheReadTokens!==void 0&&{cacheReadTokens:t.inputTokenDetails.cacheReadTokens},...t.inputTokenDetails?.cacheWriteTokens!==void 0&&{cacheWriteTokens:t.inputTokenDetails.cacheWriteTokens}}}function Ft(t){try{if("output"in t&&t.output!==void 0)return t.output}catch{}}function Ut(t){let e=t;if(typeof e.reasoningText=="string"&&e.reasoningText.length>0)return e.reasoningText}function ye(t){if(t===null||typeof t!="object")return [];let e=t.steps;if(!Array.isArray(e))return [];let n=[];for(let o of e){if(o===null||typeof o!="object")continue;let r=o.toolCalls,s=o.toolResults;if(Array.isArray(r))for(let i of r){if(i===null||typeof i!="object")continue;let a=i,l=typeof a.toolCallId=="string"?a.toolCallId:"",u=typeof a.toolName=="string"?a.toolName:"",c=a.input??a.args,d={toolCallId:l,toolName:u,input:c};if(Array.isArray(s)){let p=s.find(m=>m.toolCallId===l);p&&(("output"in p||"result"in p)&&(d.output=p.output??p.result),"error"in p&&p.error!==void 0&&(d.error=p.error));}n.push(d);}}return n}function we(t){let e={};return t.output!==void 0&&(e.output=t.output),t.tools!==void 0&&Object.keys(t.tools).length>0&&(e.tools=t.tools,t.stopWhen!==void 0&&(e.stopWhen=t.stopWhen)),t.abortSignal!==void 0&&(e.abortSignal=t.abortSignal),e}function Te(t,e,n,o,r){let s={model:t,prompt:o,temperature:e.temperature};return e.maxTokens!==void 0&&(s.maxOutputTokens=e.maxTokens),n&&(s.system=n),e.topP!==void 0&&(s.topP=e.topP),e.frequencyPenalty!==void 0&&(s.frequencyPenalty=e.frequencyPenalty),e.presencePenalty!==void 0&&(s.presencePenalty=e.presencePenalty),{...s,...r}}var Ht=["openai","anthropic","openrouter","ollama","gemini","lmstudio","custom"];function wo(t){return Ht.includes(t)}function it(t){if(!t||typeof t!="object")throw new TypeError("llmPlugin: options must be an object");if(!t.providers||typeof t.providers!="object")throw new TypeError("llmPlugin: options.providers must be an object (record of provider id \u2192 options)");for(let[e,n]of Object.entries(t.providers))if(n!==void 0){if(!n||typeof n!="object")throw new TypeError(`llmPlugin: providers["${e}"] must be an object`);if(!wo(e))throw new TypeError(`llmPlugin: providers["${e}"] is not a supported provider. Supported: ${Ht.join(", ")}`);switch(e){case "openai":case "anthropic":case "openrouter":case "gemini":if(typeof n.apiKey!="string"||!n.apiKey.trim())throw new TypeError(`llmPlugin: providers["${e}"].apiKey is required`);if(e!=="openrouter"&&n.baseURL!==void 0&&typeof n.baseURL!="string")throw new TypeError(`llmPlugin: providers["${e}"].baseURL must be a string when provided`);break;case "ollama":case "lmstudio":if(n.baseURL!==void 0&&typeof n.baseURL!="string")throw new TypeError(`llmPlugin: providers["${e}"].baseURL must be a string when provided`);if(n.modelId!==void 0&&(typeof n.modelId!="string"||!n.modelId.trim()))throw new TypeError(`llmPlugin: providers["${e}"].modelId must be a non-empty string when provided`);if(e==="lmstudio"&&n.apiKey!==void 0&&typeof n.apiKey!="string")throw new TypeError('llmPlugin: providers["lmstudio"].apiKey must be a string when provided');break;case "custom":{let o=n.model;if(typeof o=="function")break;if(o===null||typeof o!="object")throw new TypeError('llmPlugin: providers["custom"].model must be an AI SDK language model or a factory function');S(o,"custom","(custom)");break}}}if(t.defaultOptions!==void 0&&(typeof t.defaultOptions!="object"||t.defaultOptions===null))throw new TypeError("llmPlugin: defaultOptions must be an object when provided")}var To=["openai","anthropic","openrouter","ollama","gemini","lmstudio","custom"];function vo(t,e){return {provider:t,...e}}function ve(t={providers:{}}){return it(t),{apply(e){let n=new Map;for(let o of To){let r=t.providers[o];r!==void 0&&n.set(o,vo(o,r));}e.setStore(V,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(ie,t.defaultOptions);}}}var st="[A-Za-z0-9_-]",Ro=new RegExp(st),at=new RegExp(`^${st}+$`),G=64,lt=new RegExp(`^${st}{1,${G}}$`),O=`/${lt.source}/`,v="__";function Re(t){if(t==="")return false;let e=v.slice(0,v.length/2);return !`${t}${e}`.includes(v)}function se(t){if(t.length===0)return "it is empty";if(t.length>G)return `it is ${t.length} characters, over the provider limit of ${G}`;if(!at.test(t))return `it contains ${[...new Set([...t].filter(n=>!Ro.test(n)))].map(n=>`"${n}"`).join(", ")}, outside the allowed set of letters, digits, "_", and "-"`}var L=lt,ae=Symbol.for("routecraft.mcp.plugin.registered"),A=Symbol.for("routecraft.mcp.client.servers"),k=Symbol.for("routecraft.mcp.tool.registry"),le=Symbol.for("routecraft.mcp.stdio.managers"),P=Symbol.for("routecraft.mcp.local-tool-registry"),be=(n=>(n.TOOL="routecraft.mcp.tool",n.REQUEST="routecraft.mcp.request",n))(be||{});var Vt="0.6.0";var Gt=new WeakMap;async function Co(t){if(typeof t=="function")return t();if(Array.isArray(t)){if(t.length===0)throw new Error("McpClientAuthOptions.token array must not be empty");let e=(Gt.get(t)??0)%t.length;return Gt.set(t,e+1),t[e]}return t}async function Kt(t){if(!t)return;let e={},n=t.headers??{},o=Object.entries(n).find(([r])=>r.toLowerCase()==="authorization")?.[1];if(o)e.Authorization=o;else if(t.token!==void 0){let r=await Co(t.token);if(r.length===0)throw new Error("McpClientAuthOptions.token must be a non-empty string when provided");e.Authorization=`Bearer ${r}`;}for(let[r,s]of Object.entries(n))r.toLowerCase()!=="authorization"&&(e[r]=s);return Object.keys(e).length>0?e:void 0}function ct(t){return routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/server'),{adapterName:t,packageName:"@modelcontextprotocol/server"})}function Wt(t){return routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/server/stdio'),{adapterName:t,packageName:"@modelcontextprotocol/server"})}function qt(t){return routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/node'),{adapterName:t,packageName:"@modelcontextprotocol/node"})}function dt(t){return routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/client'),{adapterName:t,packageName:"@modelcontextprotocol/client"})}function zt(t){return routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/client/stdio'),{adapterName:t,packageName:"@modelcontextprotocol/client"})}var ut={mode:"auto"},pt={name:"routecraft-mcp-client",version:Vt};async function Ce(t,e){let{Client:n,StreamableHTTPClientTransport:o}=await dt("mcp (http client)"),r=new o(t,{fetch:async(i,a)=>{let l=await Kt(e);if(!l)return fetch(i,a);let u=new Headers(a?.headers);for(let[c,d]of Object.entries(l))u.set(c,d);return fetch(i,{...a,headers:u})}}),s=new n(pt,{capabilities:{},versionNegotiation:ut});try{await s.connect(r);}catch(i){throw await r.close().catch(()=>{}),i}return {client:s,transport:r}}function de(t){let e=t?.content;if(!Array.isArray(e)||e.length===0)return t;if(e.length===1){let n=e[0];if(n.type==="text"&&typeof n.text=="string")return n.text;if(typeof n.data=="string")return n.data}return e}async function Ae(t,e,n,o){return de(await mt(t,e,n,o))}async function mt(t,e,n,o){let s=t.getStore(le)?.get(e);if(s)try{return await s.callToolRaw(n,o)}catch(a){throw routecraft.isRoutecraftError(a)?a:routecraft.rcError("RC5003",a,{message:`mcp dispatch: stdio call to "${e}:${n}" failed.`})}let i=Ao(t,e);return Xt(i.url,n,o,i.auth)}function Ao(t,e){let o=t.getStore(A)?.get(e);if(!o)throw routecraft.rcError("RC5003",void 0,{message:`mcp dispatch: server "${e}" is not registered. Register it via defineConfig.mcp / mcpPlugin({ clients }).`});if(typeof o!="object"||o===null)throw routecraft.rcError("RC5003",void 0,{message:`mcp dispatch: server "${e}" config is a string shorthand and cannot be called directly. Use a full HTTP config with a url.`});if("transport"in o&&o.transport==="stdio")throw routecraft.rcError("RC5003",void 0,{message:`mcp dispatch: stdio server "${e}" is registered but its client is not running. Ensure mcpPlugin started successfully.`});let r=o;if(typeof r.url!="string"||r.url.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`mcp dispatch: server "${e}" has no url. Cannot dispatch over HTTP.`});return r}async function Jt(t,e,n,o){return de(await Xt(t,e,n,o))}async function Xt(t,e,n,o){let r;try{return r=await Ce(new URL(t),o),await r.client.callTool({name:e,arguments:n})}catch(s){throw routecraft.isRoutecraftError(s)?s:routecraft.rcError("RC5003",s,{message:`mcp dispatch: failed to call tool "${e}" at "${t}".`})}finally{try{await r?.client.close();}catch{}try{await r?.transport.close();}catch{}}}function ke(t,e,n){return {logger:routecraft.logger.child({tool:t}),abortSignal:e,...n?{principal:Mo(n)}:{}}}function Mo(t){let e=routecraft.isAuthentic(t),n={...t};return n.audience&&(n.audience=[...n.audience]),n.scopes&&(n.scopes=[...n.scopes]),n.roles&&(n.roles=[...n.roles]),n.claims&&(n.claims=structuredClone(n.claims)),n.userinfoClaims&&(n.userinfoClaims=structuredClone(n.userinfoClaims)),n.actor&&(n.actor=structuredClone(n.actor)),n.mayAct&&(n.mayAct=structuredClone(n.mayAct)),Zt(n),e?routecraft.markAuthentic(n):n}function Zt(t,e=new WeakSet){if(t===null||typeof t!="object"||e.has(t)||ArrayBuffer.isView(t))return t;e.add(t);for(let n of Object.keys(t)){let o=t[n];o!==null&&typeof o=="object"&&Zt(o,e);}return Object.freeze(t)}function Pe(t,e){let n={...t,...e};return Object.keys(n).length>0?n:void 0}var Qt=[["read-only","readOnlyHint"],["destructive","destructiveHint"],["idempotent","idempotentHint"],["open-world","openWorldHint"]];function en(t){if(!t||t.length===0)return {};let e={};for(let[n,o]of Qt)t.includes(n)&&(e[o]=true);return e}function tn(t){if(!t)return [];let e=[];for(let[n,o]of Qt)t[o]&&e.push(n);return e}function ft(t){if(typeof t!="string"||t.trim()==="")throw new TypeError('mcpPlugin: proxy ref must be a non-empty string like "server:tool", "server:*", or "server"');let e=t.indexOf(":");if(e===-1)return {serverId:t,toolName:"*"};let n=t.slice(0,e),o=t.slice(e+1);if(n===""||o==="")throw new TypeError(`mcpPlugin: proxy ref "${t}" is malformed. Use "server:tool", "server:*", or "server".`);return {serverId:n,toolName:o}}function Oo(t){return t.map(e=>typeof e=="string"?{ref:e}:e)}function gt(t,e){return t.name??e}function nn(t,e,n){let o=new Map,r=t.getStore(k);if(!r)return n("proxy:no-registry","mcpPlugin proxy: no MCP tool registry present; proxied tools are unavailable."),o;let s=(i,a,l)=>{let u=gt(a,i.name);if(!L.test(u)){n(`proxy:invalid-name:${u}`,`mcpPlugin proxy: remote tool "${i.source}:${i.name}" has a name that does not match ${O} and is skipped. Proxy it with an exact ref and a "name" override to expose it.`);return}let c=o.get(u);if(c){if(!(c.serverId===i.source&&c.toolName===i.name)){n(`proxy:conflict:${u}`,`mcpPlugin proxy: tool name "${u}" from "${a.ref}" collides with "${c.serverId}:${c.toolName}"; first entry wins. Use a name override to expose both.`);return}if(!l)return}o.set(u,{exposedName:u,serverId:i.source,toolName:i.name,entry:i,config:a});};for(let i of Oo(e)){let{serverId:a,toolName:l}=ft(i.ref),u=r.getToolsByServer(a);if(u.length===0){n(`proxy:unresolved:${a}`,`mcpPlugin proxy: client "${a}" has no registered tools (not yet listed, or listing failed); its proxy entries are skipped until tools appear.`);continue}if(l==="*"){for(let d of u)s(d,i,false);continue}let c=u.find(d=>d.name===l);if(!c){n(`proxy:unresolved:${i.ref}`,`mcpPlugin proxy: tool "${l}" is not registered under client "${a}". Known tools: ${u.map(d=>`"${d.name}"`).sort().join(", ")}.`);continue}s(c,i,true);}return o}function on(t){let{entry:e,config:n}=t,o={name:t.exposedName,inputSchema:e.inputSchema},r=n.description??e.description;r!==void 0&&(o.description=r),e.title!==void 0&&(o.title=e.title),e.outputSchema!==void 0&&(o.outputSchema=e.outputSchema);let s=Pe(e.annotations,n.annotations);return s!==void 0&&(o.annotations=s),o}var Eo="GET, POST, OPTIONS";var So="WWW-Authenticate",Lo=new Set(["localhost","127.0.0.1","::1","[::1]"]);function Io(t){if(!t||t==="null")return false;let e;try{e=new URL(t);}catch{return false}return e.protocol!=="http:"&&e.protocol!=="https:"||e.username||e.password||e.pathname!=="/"&&e.pathname!==""||e.search||e.hash?false:Lo.has(e.hostname)?t:false}function rn(t){if(t===false)return null;if(t===void 0)return {resolveOrigin:Io,isWildcard:false};let{origin:e}=t;if(e==="*")return {resolveOrigin:()=>"*",isWildcard:true};if(typeof e=="string"){let n=e;return {resolveOrigin:o=>o===n?n:false,isWildcard:false}}if(Array.isArray(e)){let n=new Set(e);return {resolveOrigin:o=>o!==void 0&&n.has(o)?o:false,isWildcard:false}}if(typeof e=="function")return {resolveOrigin:e,isWildcard:false};throw new TypeError("mcpPlugin: cors.origin must be '*', a string, a string array, or a function")}function _o(t,e){try{return t.resolveOrigin(e)}catch{return false}}function No(t,e,n){if(!t)return {};let o={};t.isWildcard||(o.Vary="Origin");let r=_o(t,e);return r===false||(o["Access-Control-Allow-Origin"]=r,n?(o["Access-Control-Allow-Methods"]=Eo,o["Access-Control-Allow-Headers"]="*",o["Access-Control-Allow-Private-Network"]="true"):o["Access-Control-Expose-Headers"]=So),o}function ht(t,e,n,o){if(!e)return;let{Vary:r,...s}=No(e,n,o);for(let[i,a]of Object.entries(s))t.setHeader(i,a);r!==void 0&&t.appendHeader("Vary",r);}var xe="/.well-known/oauth-protected-resource";function sn(t){let e=new Set([xe]),n=t.pathname;return n&&n!=="/"&&n!==""&&e.add(`${xe}${n}`),{ownedPaths:new Set([...e,"/mcp","/mcp/"]),metadataPaths:e}}var an=t=>`<svg width="200" height="200" viewBox="0 0 200 200" fill="${t}" xmlns="http://www.w3.org/2000/svg"><path d="M125 175H75V125L125 175ZM175 175H125V125L175 175ZM125 25C152.614 25 175 47.3858 175 75C175 102.614 152.614 125 125 125V75H75L125 125H75L25 75V25H125Z" /></svg>`,ln=t=>`data:image/svg+xml;base64,${Buffer.from(t,"utf8").toString("base64")}`,cn=Object.freeze([Object.freeze({src:ln(an("#ffffff")),mimeType:"image/svg+xml",theme:"dark"}),Object.freeze({src:ln(an("#000000")),mimeType:"image/svg+xml",theme:"light"})]);var Do=["subject","issuer","audience","expiresAt","claims"],jo=1e4,Bo=3600,yt=class{entries=new Map;inFlight=new Map;maxEntries;constructor(e=jo){this.maxEntries=e;}async getOrCompute(e,n,o){if(n===void 0||!Number.isFinite(n))return o();let r=Fo(e),s=this.entries.get(r);if(s){if(Date.now()/1e3<s.expiresAt)return s.enrichment;this.entries.delete(r);}let i=this.inFlight.get(r);if(i)return i;let a=o().then(l=>(this.store(r,l,n),this.inFlight.delete(r),l),l=>{throw this.inFlight.delete(r),l});return this.inFlight.set(r,a),a}clear(){this.entries.clear(),this.inFlight.clear();}store(e,n,o){for(this.entries.has(e)&&this.entries.delete(e),this.entries.set(e,{enrichment:n,expiresAt:o});this.entries.size>this.maxEntries;){let r=this.entries.keys().next().value;if(r===void 0)break;this.entries.delete(r);}}};function Fo(t){return crypto$1.createHash("sha256").update(t).digest("hex")}function Uo(t){if(!t)return;let e=t.match(/(?:^|,\s*)max-age=(\d+)/i);if(!e)return;let n=Number.parseInt(e[1],10);return Number.isFinite(n)&&n>=0?n:void 0}function Ho(t,e){if(t!==true){let l=new URL(t.toString());return async()=>l}if(e===void 0)throw new TypeError('oauth: `userinfo: true` requires the verify helper to expose an `issuer`. Use `jwks({ issuer, ... })` / `jwt({ issuer, ... })`, pass an explicit `userinfo: "https://idp.example.com/oauth/userinfo"`, or use a function.');if(Array.isArray(e))throw new TypeError("oauth: `userinfo: true` requires a single-string `issuer`; got an array. OIDC Discovery resolves one issuer to one userinfo endpoint. Pass an explicit userinfo URL or function instead.");let n=e.endsWith("/")?e:`${e}/`,o=new URL(".well-known/openid-configuration",n),r=null,s=0,i=null,a=async()=>{let l;try{l=await fetch(o);}catch(p){throw routecraft.rcError("RC5021",p,{message:`OIDC Discovery fetch failed at ${o.toString()}`,suggestion:"Verify network access to the IdP and that the issuer URL is reachable. Pass an explicit `userinfo` URL or function if the IdP does not advertise discovery."})}if(!l.ok)throw routecraft.rcError("RC5021",new Error(`OIDC Discovery fetch returned ${l.status} ${l.statusText}`),{message:`OIDC Discovery fetch failed at ${o.toString()} (status ${l.status})`,suggestion:"Verify the issuer hosts an OIDC Discovery document. Pass an explicit `userinfo` URL or function if it does not."});let u;try{u=await l.json();}catch(p){throw routecraft.rcError("RC5021",p,{message:`OIDC Discovery document at ${o.toString()} is not valid JSON`,suggestion:"Inspect the discovery endpoint manually. Pass an explicit `userinfo` URL or function if the IdP is non-compliant."})}if(typeof u.userinfo_endpoint!="string"||!u.userinfo_endpoint)throw routecraft.rcError("RC5021",new Error("missing userinfo_endpoint in discovery document"),{message:`OIDC Discovery document at ${o.toString()} does not advertise a userinfo_endpoint`,suggestion:"Pass an explicit `userinfo` URL or function for this IdP; it does not advertise auto-discoverable userinfo."});let c=new URL(u.userinfo_endpoint),d=Uo(l.headers.get("cache-control"))??Bo;return r=c,s=Date.now()/1e3+d,c};return async()=>r&&Date.now()/1e3<s?r:i||(i=a().finally(()=>{i=null;}),i)}async function Vo(t,e){let n;try{n=await fetch(t,{headers:{Authorization:`Bearer ${e}`}});}catch(o){throw routecraft.rcError("RC5021",o,{message:`userinfo fetch failed at ${t.toString()}`,suggestion:"Verify network access to the IdP's userinfo endpoint and that the bearer token's scopes permit it."})}if(!n.ok)throw routecraft.rcError("RC5021",new Error(`userinfo returned ${n.status} ${n.statusText}`),{message:`userinfo fetch failed at ${t.toString()} (status ${n.status})`,suggestion:"Check the bearer token has the scopes required by the IdP's userinfo endpoint (typically `openid`, `email`, `profile`)."});try{return await n.json()}catch(o){throw routecraft.rcError("RC5021",o,{message:`userinfo response at ${t.toString()} is not valid JSON`,suggestion:"Inspect the userinfo endpoint manually; it must return a JSON object per OIDC Core \xA75.3.2."})}}function dn(t,e){let n={...t};for(let[o,r]of Object.entries(e))Do.includes(o)||r!==void 0&&(n[o]=r);return n}function Go(t){let e={userinfoClaims:t};return typeof t.email=="string"&&(e.email=t.email),typeof t.name=="string"&&(e.name=t.name),Array.isArray(t.roles)&&(e.roles=t.roles.filter(n=>typeof n=="string")),e}function un(t,e,n){let o=new yt;if(typeof e=="function")return async s=>{let i=await t(s),a=await o.getOrCompute(s,i.expiresAt,()=>e(i,s));return dn(i,a)};let r=Ho(e,n);return async s=>{let i=await t(s),a=await o.getOrCompute(s,i.expiresAt,async()=>{let l=await r(),u=await Vo(l,s),c=u.sub;if(typeof c!="string"||c.length===0)throw routecraft.rcError("RC5022",new Error("userinfo response is missing `sub`"),{message:"userinfo response is missing `sub` (required per OIDC Core \xA75.3.2)",suggestion:"Inspect the userinfo endpoint manually; the response MUST include a `sub` claim. If the IdP returns a non-standard identifier, use a function-mode `userinfo` and map it yourself."});if(c!==i.subject)throw routecraft.rcError("RC5022",new Error(`userinfo \`sub\` (${c}) does not match token \`sub\` (${i.subject})`),{message:"userinfo response `sub` does not match the verified token's `sub` (OIDC Core \xA75.3.2 violation)",suggestion:"This indicates a compromised userinfo endpoint or a misconfigured userinfo URL. Verify the issuer / userinfo mapping; do not relax this check."});return Go(u)});return dn(i,a)}}function wt(t){return typeof t=="object"&&t!==null&&t.code==="ERR_JWT_EXPIRED"}var Wo=new Set(["ERR_JWKS_TIMEOUT","ERR_JWKS_INVALID","ERR_JOSE_GENERIC"]),qo=new Set(["ECONNREFUSED","ECONNRESET","ENOTFOUND","EAI_AGAIN","ETIMEDOUT","UND_ERR_CONNECT_TIMEOUT","UND_ERR_HEADERS_TIMEOUT","UND_ERR_SOCKET"]);function zo(t){let e=t;for(let n=0;n<5;n++){if(typeof e!="object"||e===null)return false;let o=e.code;if(typeof o=="string"&&(Wo.has(o)||qo.has(o)))return true;e=e.cause;}return false}function pn(t){return wt(t)?"expired":routecraft.isRoutecraftError(t)||zo(t)?"infrastructure":"invalid_token"}var Qo=new AbortController().signal;function mn(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function er(t){if(typeof t=="string")try{let e=JSON.parse(t);return mn(e)?e:{input:t}}catch{return {input:t}}return mn(t)?t:{}}function fn(t){return routecraft.isRoutecraftError(t)?t.meta.message:t instanceof Error?t.message:String(t)}function tr(t,e){if(routecraft.isRoutecraftError(t)){let n=t.cause;if(n?.message)return `${e}: ${n.message}`}return e}var q=class{context;options;httpServer=null;mcpHandler=null;stdioHandle=null;sdkServerCtor=null;serverInfo=null;serverOptions=null;running=false;toolsListLogged=false;proxyWarnings=new Set;proxyResolvedVersion=-1;proxyResolved=new Map;validatorVerifier=null;constructor(e,n={}){this.context=e,this.options={name:"routecraft",version:"1.0.0",transport:"stdio",port:3001,host:"localhost",...n},this.validateResourceConfig();}resolveServerIcons(){return this.options.icons===void 0?cn:this.options.icons}defaultUnlessEmpty(e,n){let o=e??n;return o===""?void 0:o}buildServerInfo(){let e={name:this.options.name,version:this.options.version};this.options.title!==void 0&&(e.title=this.options.title);let n=this.defaultUnlessEmpty(this.options.description,"Powered by Routecraft.dev");n!==void 0&&(e.description=n);let o=this.defaultUnlessEmpty(this.options.websiteUrl,"https://routecraft.dev");o!==void 0&&(e.websiteUrl=o);let r=this.resolveServerIcons();return r.length>0&&(e.icons=r),e}buildServerOptions(){let e={capabilities:{tools:{}}},n=this.defaultUnlessEmpty(this.options.instructions,"");return n!==void 0&&(e.instructions=n),e}validateResourceConfig(){let e=this.options.resource?.url;if(e===void 0)return;if(new URL(e.toString()).protocol!=="https:"&&process.env.NODE_ENV==="production")throw new TypeError("mcpPlugin: resource.url must use HTTPS in production")}async start(){if(this.running){this.context.logger.warn({},"MCP server already running");return}try{let e=this.options.transport;e==="http"?await this.startHttp():await this.startStdio(),this.running=!0,this.context.logger.info({name:this.options.name,version:this.options.version,transport:e},"MCP server started"),this.logExposedToolsOnce();}catch(e){let n=routecraft.isRoutecraftError(e)?e.meta.message:e instanceof Error?e.message:"Failed to start MCP server";throw this.context.logger.error({err:e},n),e}}async startStdio(){let{serveStdio:e}=await Wt("mcp (stdio)");await this.prepareServerFactory(),this.stdioHandle=e(()=>this.createServerInstance(void 0));}async prepareServerFactory(){let{Server:e}=await ct("mcp");this.sdkServerCtor=e,this.serverInfo=this.buildServerInfo(),this.serverOptions=this.buildServerOptions();}createServerInstance(e){if(!this.sdkServerCtor||!this.serverInfo||!this.serverOptions)throw new Error("mcp: server factory used before prepareServerFactory() ran");let n=new this.sdkServerCtor(this.serverInfo,this.serverOptions);return n.setRequestHandler("tools/list",()=>{let o=this.getAvailableTools();return this.logExposedToolsOnce(),{tools:o}}),n.setRequestHandler("tools/call",async o=>{let r=await this.handleToolCall(o.params.name,o.params.arguments??{},e);return {...r,content:r.content}}),n}async buildHttpHandler(){let{createMcpHandler:e}=await ct("mcp (http)"),{toNodeHandler:n}=await qt("mcp (http)");await this.prepareServerFactory();let o=e(i=>this.createServerInstance(this.authInfoToPrincipal(i.authInfo)),{onerror:i=>{this.context.logger.error({err:i},"MCP handler error");}}),r=n(o,{onerror:i=>{this.context.logger.error({err:i},"MCP HTTP request error");}});return {handler:o,serve:(i,a)=>{r(i,a).catch(l=>{this.context.logger.error({err:l},"MCP HTTP request failed"),a.headersSent?a.writableEnded||a.end():(a.writeHead(500,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Internal Server Error"})));});}}}resolveResourceUrl(){let e=this.options.resource?.url;if(e!==void 0)return e.toString();let n=this.options.host,o=this.getHttpPort()??this.options.port;return `http://${n}:${o}/mcp`}resolveResourceName(){return this.options.title??this.options.name}buildProtectedResourceMetadata(){let e={resource:this.resolveResourceUrl(),bearer_methods_supported:["header"]};e.resource_name=this.resolveResourceName();let n=this.options.auth;if(n&&"issuer"in n){let r=n.issuer;r!==void 0&&(e.authorization_servers=Array.isArray(r)?r:[r]);}let o=this.options.resource;return o?.scopesSupported&&o.scopesSupported.length>0&&(e.scopes_supported=o.scopesSupported),o?.documentationUrl!==void 0&&(e.resource_documentation=o.documentationUrl.toString()),e}resolveResourceMetadataUrl(){return new URL(xe,this.resolveResourceUrl()).toString()}buildWwwAuthenticateHeader(e={}){let n=this.resolveResourceMetadataUrl();return `Bearer ${['realm="mcp"',...Object.entries(e).map(([r,s])=>`${r}="${s}"`),`resource_metadata="${n}"`].join(", ")}`}missingScopes(e){let n=this.options.auth?.requiredScopes;if(!n||n.length===0)return [];let o=new Set(e.scopes??[]);return n.filter(r=>!o.has(r))}serveProtectedResourceMetadata(e){let n=this.buildProtectedResourceMetadata();e.writeHead(200,{"Content-Type":"application/json","Cache-Control":"public, max-age=3600"}),e.end(JSON.stringify(n));}async startHttp(){let e=this.options.port,n=this.options.host,o=rn(this.options.cors);this.validatorVerifier=this.buildValidatorVerifier();let{handler:r,serve:s}=await this.buildHttpHandler();this.mcpHandler=r,this.httpServer=http.createServer(async(i,a)=>{let l=i.url?.split("?")[0]??"",u=i.headers.origin,c=Array.isArray(u)?u[0]:u,d=new URL(this.resolveResourceUrl()),{ownedPaths:p,metadataPaths:m}=sn(d);if(i.method==="OPTIONS"&&o!==null&&p.has(l)){ht(a,o,c,true),a.writeHead(204),a.end();return}if(i.method!=="OPTIONS"&&ht(a,o,c,false),m.has(l)){this.serveProtectedResourceMetadata(a);return}if(l!=="/mcp"&&l!=="/mcp/"){a.writeHead(404,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Not Found",path:l}));return}if(this.options.auth){let f=await this.validateAuth(i);if(!f.ok){if(f.status===500){a.writeHead(500,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Internal Server Error"}));return}a.writeHead(401,{"Content-Type":"application/json","WWW-Authenticate":this.buildWwwAuthenticateHeader(f.presented?{error:"invalid_token"}:{})}),a.end(JSON.stringify({error:"Unauthorized"}));return}let h=this.missingScopes(f.principal);if(h.length>0){let g={reason:"insufficient_scope",scheme:"bearer",source:"mcp"};this.context.logger.warn(g,"Auth rejected: insufficient scope"),this.context.emit("auth:rejected",g),a.writeHead(403,{"Content-Type":"application/json","WWW-Authenticate":this.buildWwwAuthenticateHeader({error:"insufficient_scope",scope:h.join(" ")})}),a.end(JSON.stringify({error:"insufficient_scope"}));return}i.auth=this.principalToAuthInfo(f.principal,f.token);}s(i,a);}),await this.listenHttp(e,n);}async listenHttp(e,n){await new Promise((s,i)=>{this.httpServer.listen(e,n,()=>s()),this.httpServer.on("error",a=>{let l=routecraft.isRoutecraftError(a)?a.meta.message:a instanceof Error?a.message:"MCP HTTP server listen failed";this.context.logger.error({err:a},l),i(a);});});let o=this.getHttpPort()??e,r={host:n,port:o,path:"/mcp"};this.context.logger.info(r,"MCP HTTP server listening"),this.context.emit("plugin:mcp:server:listening",r);}authInfoToPrincipal(e){if(!e)return;let n=e.extra?.principal;if(n)return n;let o={kind:"oauth",scheme:"bearer",subject:e.clientId,clientId:e.clientId,scopes:e.scopes};return e.expiresAt!==void 0&&(o.expiresAt=e.expiresAt),o}principalToAuthInfo(e,n){let o={token:n,clientId:e.clientId??e.subject,scopes:e.scopes??[],extra:{principal:e}};return e.expiresAt!==void 0&&(o.expiresAt=e.expiresAt),o}getHttpPort(){let e=this.httpServer?.address();if(e&&typeof e=="object"&&"port"in e)return e.port}buildValidatorVerifier(){let e=this.options.auth;if(!e||!("validator"in e))return null;let n=o=>Promise.resolve(e.validator(o));return this.options.userinfo===void 0?n:un(n,this.options.userinfo,e.issuer)}async validateAuth(e){let n=this.options.auth,o=n&&"validator"in n?this.validatorVerifier??this.buildValidatorVerifier():null;if(!o){let a={reason:"no_verifier",scheme:"bearer",source:"mcp"};return this.context.logger.error(a,"Auth rejected: auth is configured but resolved no verifier; every request will be refused"),this.context.emit("auth:rejected",a),{ok:false,status:401,presented:false}}let r=e.headers.authorization;if(!r||Array.isArray(r)){let a={reason:"missing_header",scheme:"bearer",source:"mcp"};return this.context.logger.debug(a,"Auth rejected: missing or malformed Authorization header"),this.context.emit("auth:rejected",a),{ok:false,status:401,presented:false}}let s=/^bearer\s+(.+)$/i.exec(r);if(!s){let a={reason:"unsupported_scheme",scheme:"bearer",source:"mcp"};return this.context.logger.debug(a,"Auth rejected: unsupported authorization scheme"),this.context.emit("auth:rejected",a),{ok:false,status:401,presented:false}}let i=s[1];try{let a=await o(i),l={subject:a.subject,scheme:a.scheme,source:"mcp"};if(a.expiresAt!==void 0){let u=Math.floor(Date.now()/1e3),c=this.options.auth?.clockToleranceSec??0;if(!Number.isFinite(a.expiresAt)||!Number.isFinite(c)||u>=a.expiresAt+c){let d={reason:"expired",scheme:"bearer",source:"mcp"};return this.context.logger.debug(d,"Auth rejected: principal expiry has passed"),this.context.emit("auth:rejected",d),{ok:!1,status:401,presented:!0}}}return this.context.logger.debug(l,"Auth succeeded"),this.context.emit("auth:success",l),{ok:!0,principal:a,token:i}}catch(a){let l=wt(a),u=pn(a),c={reason:u,scheme:"bearer",source:"mcp"};return l?this.context.logger.debug({err:a,...c},"Auth rejected: token expired"):this.context.logger.warn({err:a,...c},"Auth rejected: token validation failed"),this.context.emit("auth:rejected",c),u==="infrastructure"?{ok:false,status:500}:{ok:false,status:401,presented:true}}}async stop(){if(this.running)try{if(this.httpServer){if(this.mcpHandler)try{await this.mcpHandler.close();}catch(n){this.context.logger.error({err:n},"Failed to close MCP handler; continuing shutdown");}finally{this.mcpHandler=null;}let e=this.httpServer;typeof e.closeAllConnections=="function"&&e.closeAllConnections(),await new Promise(n=>{this.httpServer.close(()=>n());}),this.httpServer=null;}this.stdioHandle&&(await this.stdioHandle.close(),this.stdioHandle=null),this.running=!1,this.context.logger.info({},"MCP server stopped");}catch(e){let n=routecraft.isRoutecraftError(e)?e.meta.message:e instanceof Error?e.message:"Error stopping MCP server";this.context.logger.error({err:e},n);}}logExposedToolsOnce(){if(this.toolsListLogged)return;let e=this.getAvailableTools();if(e.length===0)return;let n=e.map(r=>r.name),o={tools:n,count:n.length};this.context.logger.info(o,"Exposing MCP tools"),this.context.emit("plugin:mcp:server:tools:exposed",o),this.toolsListLogged=true;}getAvailableTools(){let e=this.getExposedLocalEntries(),n=e.map(r=>this.entryToMcpTool(r)),o=new Set(e.map(r=>r.endpoint));for(let r of this.resolveProxied().values()){if(o.has(r.exposedName)){this.warnProxyOnce(`proxy:local-conflict:${r.exposedName}`,`mcpPlugin proxy: tool name "${r.exposedName}" from "${r.serverId}:${r.toolName}" collides with a local mcp() route; the route wins. Use a name override to expose both.`);continue}let s=on(r),i=r.entry.icons??this.resolveServerIcons();i.length>0&&(s.icons=i),n.push(s);}return n}passesToolsFilter(e){let n=this.options.tools;return n?Array.isArray(n)?n.includes(e.endpoint):n(e):true}getExposedLocalEntries(){let e=this.context.getStore(P);return e?Array.from(e.values()).filter(n=>this.passesToolsFilter(n)):[]}lookupLocalEntry(e){let o=this.context.getStore(P)?.get(e);if(!(!o||!this.passesToolsFilter(o)))return o}resolveProxied(){if(!this.options.proxy||this.options.proxy.length===0)return new Map;let e=this.context.getStore(k),n=e?.version??-1;if(e&&n===this.proxyResolvedVersion)return this.proxyResolved;e&&this.proxyWarnings.clear();let o=nn(this.context,this.options.proxy,(r,s)=>this.warnProxyOnce(r,s));return e&&(this.proxyResolvedVersion=n,this.proxyResolved=o),o}warnProxyOnce(e,n){this.proxyWarnings.has(e)||(this.proxyWarnings.add(e),this.context.logger.warn({},n));}entryToMcpTool(e){let n={name:e.endpoint,description:e.description,inputSchema:this.schemaToJsonSchema(e.input?.body)};e.title!==void 0&&(n.title=e.title),e.output?.body!==void 0&&(n.outputSchema=this.schemaToJsonSchema(e.output.body)),e.annotations!==void 0&&(n.annotations=e.annotations);let o=e.icons??this.resolveServerIcons();return o.length>0&&(n.icons=o),n}schemaToJsonSchema(e){if(!e||typeof e!="object")return {type:"object"};let n=e["~standard"];if(n?.jsonSchema?.input)try{let o=n.jsonSchema.input({target:"draft-2020-12"});return typeof o=="object"&&o!==null?o:{type:"object"}}catch(o){return this.context.logger.debug(o,"Standard JSON Schema conversion failed"),{type:"object"}}return "~standard"in e?{type:"object",additionalProperties:true}:{type:"object"}}async handleToolCall(e,n,o){try{let r=er(n),s=this.lookupLocalEntry(e);if(!s){let d=this.resolveProxied().get(e);if(d)return await this.handleProxiedToolCall(d,r,o);let p=new Error(`Tool not found: ${e}`);return this.context.emit("plugin:mcp:tool:failed",{tool:e,error:p.message}),{isError:!0,content:[{type:"text",text:`Error: Tool not found: ${e}`}]}}this.context.logger.debug({bodyType:typeof r,body:r},"MCP tool call exchange body");let i={"routecraft.mcp.tool":e,"routecraft.mcp.request":crypto.randomUUID()};o&&(i[routecraft.HeadersKeys.AUTH_PRINCIPAL]=routecraft.markAuthentic(o));let a=new routecraft.DefaultExchange(this.context,{body:r,headers:i});this.context.emit("plugin:mcp:tool:called",{tool:e,args:structuredClone(r)});let l=await s.handler(a),u=typeof l.body=="string"?l.body:JSON.stringify(l.body);this.context.emit("plugin:mcp:tool:completed",{tool:e});let c={content:[{type:"text",text:u}]};return s.output?.body!==void 0&&typeof l.body=="object"&&l.body!==null&&!Array.isArray(l.body)&&(c.structuredContent=l.body),c}catch(r){let s=fn(r);return this.context.logger.error({tool:e,err:r},s),this.context.emit("plugin:mcp:tool:failed",{tool:e,error:s}),{content:[{type:"text",text:`Error: ${tr(r,s)}`}],isError:true}}}async handleProxiedToolCall(e,n,o){let r={tool:e.exposedName,proxied:true,serverId:e.serverId,remoteTool:e.toolName};this.context.emit("plugin:mcp:tool:called",{...r,args:structuredClone(n)});try{let s=e.config.guard;if(s){let a=ke(e.exposedName,Qo,o);await s(n,a);}let i=await mt(this.context,e.serverId,e.toolName,n);return i.isError?this.context.emit("plugin:mcp:tool:failed",{...r,error:"Remote tool returned an error result"}):this.context.emit("plugin:mcp:tool:completed",r),{...i,content:Array.isArray(i.content)?i.content:[]}}catch(s){let i=fn(s);return this.context.logger.error({...r,err:s},i),this.context.emit("plugin:mcp:tool:failed",{...r,error:i}),{content:[{type:"text",text:`Error: ${routecraft.isRoutecraftError(s)?`Proxied tool "${e.exposedName}" could not be called.`:i}`}],isError:true}}}};function gn(){let t=new Map;return {getOrCreate(e,n){let o=t.get(e);if(o)return o;let r=n();return t.set(e,r),r.catch(()=>{t.get(e)===r&&t.delete(e);}),r},async evict(e,n){t.get(e)===n&&(t.delete(e),await n.then(o=>o.dispose(),()=>{}));},async disposeAll(e){for(let[n,o]of t)try{await(await o).dispose();}catch(r){e(r,n);}t.clear();}}}var rr=/^[\x21\x23-\x5B\x5D-\x7E]+$/;function hn(t){if(t.transport==="http"){if(t.port!==void 0){if(typeof t.port!="number")throw new TypeError("mcpPlugin: when transport is 'http', port must be a number");if(t.port<0||t.port>65535)throw new RangeError("mcpPlugin: port must be between 0 and 65535 when transport is 'http'")}if(t.host!==void 0&&typeof t.host!="string")throw new TypeError("mcpPlugin: when provided, host must be a string")}if(t.transport==="http"&&t.cors!==void 0&&t.cors!==false){let{origin:e}=t.cors;if(!(e==="*"||typeof e=="string"||Array.isArray(e)||typeof e=="function"))throw new TypeError("mcpPlugin: cors.origin must be '*', a string, a string array, or a function")}if(t.auth!==void 0){let e=t.auth;if("provider"in e||"endpoints"in e||"verifyAccessToken"in e||"getClient"in e)throw new TypeError("mcpPlugin: auth uses the removed OAuth authorization-server proxy shape ({ provider, endpoints, verifyAccessToken, getClient }). The MCP server is now a resource server: use oauth({ verify, issuer, requiredScopes }) and point clients at your IdP's own authorization and token endpoints, which they discover from the protected-resource metadata.");if("validator"in e){if(typeof e.validator!="function")throw new TypeError("mcpPlugin: auth.validator must be a function that returns a Principal (throw to reject)")}else throw new TypeError("mcpPlugin: auth must have a 'validator' function. Use jwt(), jwks(), oauth(), or a custom { validator } object.");let n=e.requiredScopes;if(n!==void 0){if(!Array.isArray(n))throw new TypeError("mcpPlugin: auth.requiredScopes must be an array of scope strings");for(let r of n)if(typeof r!="string"||!rr.test(r))throw new TypeError(`mcpPlugin: auth.requiredScopes contains an invalid scope ${JSON.stringify(r)}. A scope token is one or more visible ASCII characters excluding space, double quote and backslash (RFC 6749 \xA73.3).`)}let o=e.clockToleranceSec;if(o!==void 0&&(typeof o!="number"||!Number.isFinite(o)||o<0))throw new TypeError("mcpPlugin: auth.clockToleranceSec must be a finite, non-negative number of seconds")}if(t.clients)for(let[e,n]of Object.entries(t.clients)){if(!Re(e)){let o=e.replace(/_+/g,"_").replace(/^_+|_+$/g,""),r=o===""?"client":o;throw routecraft.rcError("RC5003",void 0,{message:`mcpPlugin: client name "${e}" must not be empty, contain "${v}", or end with "_". It becomes the server segment of the generated "mcp__<server>__<tool>" tool name, which is split at the first "${v}" after the prefix, so any of those makes the name ambiguous or collides with another client.`,suggestion:`Rename the client to something without "${v}" (a single underscore inside the name is fine, e.g. "${r}").`})}if(typeof n=="object"&&n!==null&&"transport"in n&&n.transport==="stdio"&&(!n.command||typeof n.command!="string"))throw new TypeError(`mcpPlugin: stdio client "${e}" must have a non-empty command string`)}if(t.proxy!==void 0){if(!Array.isArray(t.proxy))throw new TypeError("mcpPlugin: proxy must be an array of ref strings or { ref, ... } configs");let e=new Set,n=new Set;for(let o of t.proxy){let r=typeof o=="string",s=typeof o=="object"&&o!==null&&!Array.isArray(o);if(!r&&!s)throw new TypeError("mcpPlugin: each proxy entry must be a ref string or a { ref, ... } config object");let i=r?{ref:o}:o,{serverId:a,toolName:l}=ft(i.ref);if(!t.clients||!Object.hasOwn(t.clients,a))throw new TypeError(`mcpPlugin: proxy ref "${i.ref}" references unknown client "${a}". Register it under clients.`);let u=l==="*";if(u&&(i.name!==void 0||i.description!==void 0))throw new TypeError(`mcpPlugin: proxy ref "${i.ref}" is a wildcard and cannot set name or description overrides`);if(i.name!==void 0&&(typeof i.name!="string"||!L.test(i.name)))throw new TypeError(`mcpPlugin: proxy name override "${String(i.name)}" must be a string matching ${O}`);if(i.guard!==void 0&&typeof i.guard!="function")throw new TypeError(`mcpPlugin: proxy guard for "${i.ref}" must be a function (throw inside it to reject a call)`);let c=`${a}:${l}`;if(e.has(c))throw new TypeError(`mcpPlugin: duplicate proxy ref "${i.ref}" (resolves to "${c}")`);if(e.add(c),!u){let d=gt(i,l);if(n.has(d))throw new TypeError(`mcpPlugin: proxy entries expose the tool name "${d}" more than once. Use name overrides to disambiguate.`);n.add(d);}}}if(t.maxRestarts!==void 0&&(typeof t.maxRestarts!="number"||!Number.isInteger(t.maxRestarts)||t.maxRestarts<0))throw new TypeError("mcpPlugin: maxRestarts must be a non-negative integer");if(t.restartDelayMs!==void 0&&(typeof t.restartDelayMs!="number"||t.restartDelayMs<=0))throw new TypeError("mcpPlugin: restartDelayMs must be a positive number");if(t.restartBackoffMultiplier!==void 0&&(typeof t.restartBackoffMultiplier!="number"||t.restartBackoffMultiplier<1))throw new TypeError("mcpPlugin: restartBackoffMultiplier must be >= 1");if(t.toolRefreshIntervalMs!==void 0&&(typeof t.toolRefreshIntervalMs!="number"||!Number.isInteger(t.toolRefreshIntervalMs)||t.toolRefreshIntervalMs<0))throw new TypeError("mcpPlugin: toolRefreshIntervalMs must be a non-negative integer")}async function yn(t,e){let n=e["~standard"];if(!n?.validate)throw new Error("mcpPlugin: schema must be a StandardSchemaV1 with ~standard.validate");let o=n.validate(t);if(o instanceof Promise&&(o=await o),o.issues)throw new Error(`mcpPlugin options validation failed: ${routecraft.formatSchemaIssues(o.issues)}`);if(o.value===void 0)throw new Error("mcpPlugin options validation failed: no value returned");return o.value}var Me=class{constructor(e,n,o,r){this.options=e;this.logger=n;this.onEvent=o;this.onToolsUpdated=r;}options;logger;onEvent;onToolsUpdated;client=null;transport=null;running=false;stopping=false;restartCount=0;restartTimer=null;stabilityTimer=null;tools=[];async start(){if(this.running)return;this.stopping=false,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null);let e=await dt("mcp (stdio client)"),n=await zt("mcp (stdio client)"),{serverId:o,command:r,args:s,env:i,cwd:a}=this.options;this.transport=new n.StdioClientTransport({command:r,args:s??[],...i?{env:i}:{},...a?{cwd:a}:{},stderr:"pipe"});let l=this.transport;l.onerror=u=>{this.logger.error({err:u,serverId:o},"Stdio client transport error"),this.onEvent(`plugin:mcp:client:${o}:error`,{serverId:o,error:u});},l.onclose=()=>{this.stopping||(this.running=false,this.handleDisconnect());},l.stderr?.on&&l.stderr.on("data",u=>{this.logger.debug({serverId:o,stderr:String(u).trimEnd()},"Stdio client stderr output");}),this.client=new e.Client(pt,{capabilities:{},versionNegotiation:ut,listChanged:{tools:{onChanged:(u,c)=>{c&&Array.isArray(c.tools)?(this.tools=c.tools,this.onToolsUpdated(o,this.tools),this.onEvent(`plugin:mcp:client:${o}:tools:listed`,{serverId:o,toolCount:this.tools.length})):(this.logger.debug({err:u,serverId:o},"listChanged delivered no tools; re-listing manually"),this.refreshTools());}}}}),await this.client.connect(this.transport),this.running=true,await this.refreshTools(),this.logger.info({serverId:o,toolCount:this.tools.length},"Stdio client started"),this.onEvent(`plugin:mcp:client:${o}:started`,{serverId:o,toolCount:this.tools.length});}async stop(){this.stopping=true,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null),this.stabilityTimer&&(clearTimeout(this.stabilityTimer),this.stabilityTimer=null);let{serverId:e}=this.options;if(this.client){try{await this.client.close();}catch{}this.client=null;}if(this.transport){let n=this.transport;if(typeof n.close=="function")try{await Promise.resolve(n.close());}catch{}this.transport=null;}this.running=false,this.logger.info({serverId:e},"Stdio client stopped"),this.onEvent(`plugin:mcp:client:${e}:stopped`,{serverId:e,reason:"graceful"});}async callTool(e,n){return de(await this.callToolRaw(e,n))}async callToolRaw(e,n){if(!this.running||!this.client)throw new Error(`Stdio client "${this.options.serverId}" is not running. Cannot call tool "${e}".`);return await this.client.callTool({name:e,arguments:n})}getTools(){return [...this.tools]}isRunning(){return this.running}async refreshTools(){if(!this.client)return;let{serverId:e}=this.options;try{let n=await this.client.listTools();this.tools=n.tools??[],this.onToolsUpdated(e,this.tools),this.onEvent(`plugin:mcp:client:${e}:tools:listed`,{serverId:e,toolCount:this.tools.length});}catch(n){this.logger.warn({err:n,serverId:e},"Failed to list tools for stdio client");}}handleDisconnect(){let{serverId:e,maxRestarts:n,restartDelayMs:o,restartBackoffMultiplier:r}=this.options;if(this.tools.length>0&&(this.tools=[],this.onToolsUpdated(e,[])),this.logger.warn({serverId:e},"Stdio client disconnected unexpectedly"),this.onEvent(`plugin:mcp:client:${e}:stopped`,{serverId:e,reason:"unexpected"}),this.restartCount>=n){this.logger.error({serverId:e,restartCount:this.restartCount,maxRestarts:n},"Stdio client exceeded max restarts, giving up"),this.onEvent(`plugin:mcp:client:${e}:error`,{serverId:e,error:new Error(`Max restarts (${n}) exceeded for stdio client "${e}"`)});return}let s=o*Math.pow(r,this.restartCount);this.logger.info({serverId:e,restartCount:this.restartCount,delayMs:s},"Scheduling stdio client restart"),this.restartTimer=setTimeout(()=>{this.restartTimer=null,this.restart();},s);}async restart(){let{serverId:e}=this.options;this.restartCount++,this.client=null,this.transport=null;try{await this.start(),this.logger.info({serverId:e,restartCount:this.restartCount},"Stdio client restarted successfully"),this.onEvent(`plugin:mcp:client:${e}:restarted`,{serverId:e,restartCount:this.restartCount});let n=this.options.restartDelayMs*2;this.stabilityTimer=setTimeout(()=>{this.stabilityTimer=null,this.running&&(this.restartCount=0);},n);}catch(n){this.logger.error({err:n,serverId:e,restartCount:this.restartCount},"Stdio client restart failed"),this.onEvent(`plugin:mcp:client:${e}:error`,{serverId:e,error:n}),this.handleDisconnect();}}};var z=class{tools=new Map;changeVersion=0;fingerprints=new Map;reported=new Set;reportedVersion=-1;get version(){return this.changeVersion}setToolsForSource(e,n,o){let r=new Map;for(let i of o){let a={name:i.name,inputSchema:i.inputSchema,source:e,transport:n};i.title!==void 0&&(a.title=i.title),i.description!==void 0&&(a.description=i.description),i.outputSchema!==void 0&&(a.outputSchema=i.outputSchema),i.icons!==void 0&&(a.icons=i.icons),i.annotations!==void 0&&(a.annotations=i.annotations);let l=tn(i.annotations);l.length>0&&(a.tags=l),r.set(i.name,a);}this.tools.set(e,r);let s=JSON.stringify([n,o]);this.fingerprints.get(e)!==s&&(this.fingerprints.set(e,s),this.changeVersion++);}shouldReport(e){return this.reportedVersion!==this.changeVersion&&(this.reportedVersion=this.changeVersion,this.reported.clear()),this.reported.has(e)?false:(this.reported.add(e),true)}removeSource(e){this.tools.delete(e)&&(this.fingerprints.delete(e),this.changeVersion++);}getTools(){let e=[];for(let n of this.tools.values())for(let o of n.values())e.push(o);return e}getToolsByServer(e){let n=this.tools.get(e);return n?Array.from(n.values()):[]}getTool(e){for(let n of this.tools.values()){let o=n.get(e);if(o)return o}}getToolBySource(e,n){return this.tools.get(e)?.get(n)}};function wn(t){return "transport"in t&&t.transport==="stdio"}function Oe(t={}){hn(t);let e=null,n=new Map,o=gn(),r=[],s=null;return {async apply(c){if(c.setStore(ae,true),s=new z,c.setStore(k,s),c.setStore(le,n),t.clients&&Object.keys(t.clients).length>0){let d=Object.entries(t.clients),p=new Map;for(let[m,f]of d)p.set(m,f);c.setStore(A,p);for(let[m,f]of d){if(wn(f))await i(c,m,f,s);else {let g=f;await l(c,m,g.url,s,g.auth),u(c,m,g.url,s,g.auth);}let h=wn(f)?"stdio":"http";c.emit(`plugin:mcp:client:${m}:registered`,{serverId:m,transport:h});}}e=new q(c,t),await e.start();},async teardown(c){for(let d of r)clearInterval(d);r.length=0,await o.disposeAll((d,p)=>{c.logger.error({err:d,serverId:p,operation:"close"},"Failed to close HTTP client");});for(let[d,p]of n)try{await p.stop();}catch(m){c.logger.error({err:m,serverId:d,operation:"stop"},"Failed to stop stdio client");}if(n.clear(),e){try{await e.stop();}catch(d){c.logger.error({err:d,operation:"stop"},"Failed to stop MCP server plugin");}e=null;}s=null;}};async function i(c,d,p,m){let f={serverId:d,command:p.command,args:p.args??[],maxRestarts:t.maxRestarts??5,restartDelayMs:t.restartDelayMs??1e3,restartBackoffMultiplier:t.restartBackoffMultiplier??2};p.env!==void 0&&(f.env=p.env),p.cwd!==void 0&&(f.cwd=p.cwd);let h=new Me(f,c.logger,(g,b)=>{c.emit(g,b);},(g,b)=>{m.setToolsForSource(g,"stdio",b);});n.set(d,h);try{await h.start();}catch(g){c.logger.error({err:g,serverId:d,operation:"start"},"Failed to start stdio client"),c.emit(`plugin:mcp:client:${d}:error`,{serverId:d,error:g});}}function a(c,d,p){return o.getOrCreate(c,async()=>{let{client:m,transport:f}=await Ce(new URL(d),p),h=m;return {listTools:()=>h.listTools(),dispose:async()=>{try{await h.close();}catch{}try{await f.close();}catch{}}}})}async function l(c,d,p,m,f){let h;try{h=a(d,p,f);let R=(await(await h).listTools()).tools??[];m.setToolsForSource(d,"http",R),c.emit(`plugin:mcp:client:${d}:tools:listed`,{serverId:d,toolCount:R.length});}catch(g){h&&await o.evict(d,h),c.logger.warn({err:g,serverId:d,url:p,operation:"listTools"},"Failed to list tools from HTTP client");}}function u(c,d,p,m,f){let h=t.toolRefreshIntervalMs??6e4;if(h<=0)return;let g=setInterval(()=>{l(c,d,p,m,f);},h);r.push(g);}}var Ee=new Map;async function Se(){let t=[...Ee.entries()];Ee.clear(),t.length!==0&&await Promise.all(t.map(async([,e])=>{try{typeof e.dispose=="function"&&await e.dispose();}catch{}}));}function sr(t){return t.includes("/")?t:`Xenova/${t}`}async function ar(t){let e=sr(t),n=Ee.get(e);if(n)return n.run;let r=await(await routecraft.loadOptionalPeer(()=>import('@huggingface/transformers'),{adapterName:"Hugging Face embedding",packageName:"@huggingface/transformers"})).pipeline("feature-extraction",e,{dtype:"fp32"}),s=(a,l)=>r(a,{pooling:l?.pooling??"mean",normalize:l?.normalize??true}),i={run:s,dispose:typeof r.dispose=="function"?()=>Promise.resolve(r.dispose()):void 0};return Ee.set(e,i),s}function Tn(t){if(t===null)return "null";if(typeof t!="object")return String(t);if(Array.isArray(t))return `array(${t.length})`;try{let e=JSON.stringify(t);return e.length>100?e.slice(0,100)+"...":e}catch{return "object"}}function lr(t){if(Array.isArray(t))return t;if(t instanceof Float32Array)return Array.from(t);if(t&&typeof t=="object"&&"data"in t){let e=t.data;if(Array.isArray(e))return e;if(e instanceof Float32Array)return Array.from(e);throw new Error(`Embedding output .data must be an Array or Float32Array; got ${typeof e}: ${Tn(e)}`)}throw new Error(`Embedding output must be an Array, Float32Array, or object with .data; got ${typeof t}: ${Tn(t)}`)}async function vn(t){let{config:e,modelName:n,text:o}=t;if(e.provider==="mock"){let s=[];for(let i=0;i<8;i++)s.push((o.length+i)%100/100);return s}if(e.provider==="huggingface"){let s=await(await ar(n))(o,{pooling:"mean",normalize:true}),i=s&&typeof s=="object"&&"data"in s?s.data:s;return lr(i)}throw e.provider==="ollama"||e.provider==="openai"?new Error(`Embedding provider "${e.provider}" is not yet implemented. Use huggingface for now.`):new Error(`Unknown embedding provider: ${e.provider}`)}var Le=Symbol.for("routecraft.adapter.embedding.providers"),Ie=Symbol.for("routecraft.adapter.embedding.options");function cr(t,e){return {...e,provider:t}}function _e(t={providers:{}}){return {apply(e){let n=new Map;for(let[o,r]of Object.entries(t.providers))r!==void 0&&n.set(o,cr(o,r));e.setStore(Le,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(Ie,t.defaultOptions);},async teardown(){await Se();}}}function Rn(t){let e=routecraft.getExchangeRoute(t);return {forward:e?e.getForward():async()=>{throw routecraft.rcError("AI1001",void 0,{message:"Block resolver: client.forward() called but the exchange has no bound route. Block resolvers can only forward when invoked through a real route dispatch."})}}}var Tt=v,kn=Symbol.for("routecraft.ai.block.loader-tool"),_="_block_",I=`_block${v}load${v}`;function Pn(t){return t[kn]===true}async function xn(t,e,n){if(!t)return {systemAppend:"",loaderTools:[]};let o=pr(t);if(o.size===0)return {systemAppend:"",loaderTools:[]};let r=Rn(e),s=[],i=[];for(let[a,l]of o){if(l.mode==="inject"){let u=await On(a,l,e,n,r);s.push(`
|
|
2
2
|
|
|
3
|
-
## ${
|
|
3
|
+
## ${a}
|
|
4
4
|
|
|
5
|
-
${d}`);continue}a.push($o(s,l,e,n,r));}return {systemAppend:i.join(""),loaderTools:a}}function gt(t){return typeof t.mode!="string"}var ht=/^[A-Za-z0-9_-]+$/,yt=64;function wt(t){return routecraft.rcError("RC5026",void 0,{message:`Agent block "${t}": two blocks resolve to the same name after flattening nested groups. Rename one of them.`})}function Rt(t){return routecraft.rcError("RC5026",void 0,{message:`Agent block "${t}": blocks form a cycle (a group contains itself). Block trees must be finite.`})}function _o(t){let e=new Map;return sn(t,"",e,new WeakSet),e}function sn(t,e,n,o){if(o.has(t))throw Rt(e);o.add(t);for(let[r,i]of Object.entries(t)){if(i===false)continue;let a=e?`${e}${ft}${r}`:r;if(gt(i)){sn(i,a,n,o);continue}if(n.has(a))throw wt(a);n.set(a,i);}o.delete(t);}var Qt=new WeakMap;async function an(t,e,n,o,r){if((e.lifetime??"dispatch")==="context"&&o){let a=Qt.get(o);if(a?.has(e))return a.get(e);a||(a=new Map,Qt.set(o,a));let s=en(t,e,n,o,r);return a.set(e,s),s.catch(()=>a.delete(e)),s}return en(t,e,n,o,r)}async function en(t,e,n,o,r){let{value:i}=e;if(typeof i=="string")return i;if(typeof i!="function")throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${t}": "value" must be a string or a function returning a string.`});if(!o)throw routecraft.rcError("RC5025",void 0,{message:`Agent block "${t}": resolver function requires a CraftContext but the exchange has no bound context.`});let a;try{a=await Promise.resolve(i(n,o,[],r));}catch(s){throw routecraft.rcError("RC5025",s,{message:`Agent block "${t}": resolver function threw: ${s?.message??String(s)}`})}if(typeof a!="string")throw routecraft.rcError("RC5025",void 0,{message:`Agent block "${t}": resolver function must return a string (got ${typeof a}).`});return a}var tn={type:"object",properties:{},additionalProperties:false},No={"~standard":{version:1,vendor:"routecraft",validate(t){return t===null||typeof t!="object"||Array.isArray(t)||Object.keys(t).length>0?{issues:[{message:"Expected an empty object {}."}]}:{value:{}}},jsonSchema:{input:()=>tn,output:()=>tn}}};function $o(t,e,n,o,r){let i=typeof e.description=="string"&&e.description.trim()!==""?e.description:`Load the "${t}" block.`,a=async()=>an(t,e,n,o,r);return {name:`${j}${t}`,description:i,input:No,handler:a,[nn]:true,blockName:t}}function ln(t){let e=[];for(let n of t){if(!n.toolName.startsWith(j))continue;let r={blockName:n.toolName.slice(j.length),toolName:n.toolName,toolCallId:n.toolCallId};n.output!==void 0&&(r.output=n.output),n.error!==void 0&&(r.error=n.error),e.push(r);}return e}function dn(t){return t.startsWith(j)}function B(t){let e=t.indexOf(":");if(e<1||e===t.length-1)throw new Error(`LLM model id must be "providerId:modelName" (e.g. ollama:lfm2.5-thinking). Got: "${t}"`);return {providerId:t.slice(0,e),modelName:t.slice(e+1)}}function $e(t,e){if(typeof t!="string"){let a=t.modelId??"",s=t.provider==="custom"&&typeof t.model!="function";if(a.trim()===""&&!s)throw routecraft.rcError("RC5003",void 0,{message:`LLM model: inline LlmModelConfig for provider "${t.provider}" did not resolve to a model name. Either pass the model as a "providerId:modelName" string (e.g. "${t.provider}:<model>") or set "modelId" on the config.`});return {config:t,modelName:a}}if(!e)throw new Error(`LLM model id "${t}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${z.description}" can be read.`);let n=e.getStore(z);if(!n)throw new Error('LLM provider not found: no providers registered. Add llmPlugin({ providers: { ollama: { provider: "ollama" }, ... } }) to your config.');let{providerId:o,modelName:r}=B(t),i=n.get(o);if(!i)throw new Error(`LLM provider "${o}" not found. Register it with llmPlugin({ providers: { "${o}": { provider, apiKey?, baseURL? } } }).`);return {config:i,modelName:r}}function F(t,e){return t===void 0||t===""?"":typeof t=="function"?t(e):t}function je(t){let e=t.body;return typeof e=="string"?e:e==null?"":typeof e=="object"?JSON.stringify(e):String(e)}async function Ue(t,e){switch(t.provider){case "openai":return Uo(t,e);case "anthropic":return Bo(t,e);case "gemini":return Fo(t,e);case "openrouter":return Ho(t,e);case "ollama":return Vo(t,e);case "lmstudio":return Go(t,e);case "custom":return qo(t,e);default:{let n=t;throw new Error(`LLM provider not implemented: ${n.provider}`)}}}async function Uo(t,e){let n=await routecraft.loadOptionalPeer(()=>import('@ai-sdk/openai'),{adapterName:"OpenAI LLM",packageName:"@ai-sdk/openai"}),o={apiKey:t.apiKey};return t.baseURL!==void 0&&(o.baseURL=t.baseURL),n.createOpenAI(o)(e)}async function Bo(t,e){return (await routecraft.loadOptionalPeer(()=>import('@ai-sdk/anthropic'),{adapterName:"Anthropic LLM",packageName:"@ai-sdk/anthropic"})).createAnthropic({apiKey:t.apiKey})(e)}async function Fo(t,e){return (await routecraft.loadOptionalPeer(()=>import('@ai-sdk/google'),{adapterName:"Gemini LLM",packageName:"@ai-sdk/google"})).createGoogleGenerativeAI({apiKey:t.apiKey})(e)}async function Ho(t,e){let o=(await routecraft.loadOptionalPeer(()=>import('@openrouter/ai-sdk-provider'),{adapterName:"OpenRouter LLM",packageName:"@openrouter/ai-sdk-provider"})).createOpenRouter({apiKey:t.apiKey}),r=t.modelId??e,i=o.chat(r);return N(i,"OpenRouter",r),i}async function Vo(t,e){let o=(await routecraft.loadOptionalPeer(()=>import('ollama-ai-provider-v2'),{adapterName:"Ollama LLM",packageName:"ollama-ai-provider-v2"})).createOllama({baseURL:t.baseURL??at.ollama.baseURL}),r=t.modelId??e,i=o(r);return N(i,"Ollama",r),i}async function Go(t,e){let n=await routecraft.loadOptionalPeer(()=>import('@ai-sdk/openai-compatible'),{adapterName:"LM Studio LLM",packageName:"@ai-sdk/openai-compatible"}),o={name:"lmstudio",baseURL:t.baseURL??at.lmstudio.baseURL,includeUsage:true};t.apiKey!==void 0&&(o.apiKey=t.apiKey);let r=n.createOpenAICompatible(o),i=t.modelId??e,a=r(i);return N(a,"LM Studio",i),a}function qo(t,e){let{model:n}=t,o=typeof n=="function"?n(e):n;return N(o,"Custom",e||"(custom)"),o}function cn(t){if(t===null||typeof t!="object")return null;let e=t;switch(e.type){case "text-delta":{let o=Be(e,"text")??Be(e,"textDelta");return o===void 0||o.length===0?null:{type:"text-delta",text:o}}case "reasoning-delta":{let o=Be(e,"text")??Be(e,"delta");return o===void 0||o.length===0?null:{type:"reasoning-delta",text:o}}default:return null}}function Be(t,e){let n=t[e];return typeof n=="string"?n:void 0}async function pn(t){let{config:e,modelId:n,options:o,system:r,user:i,onDelta:a}=t,s=await Ue(e,n);return Ko(s,o,r,i,Ce(t),a)}async function Ko(t,e,n,o,r,i){let{streamText:a}=await import('ai'),s=be(t,e,n,o,r),l=a(s);for await(let v of l.fullStream){let A=cn(v);if(A!==null)try{await i(A);}catch(K){routecraft.logger.warn({err:K},"agent.onDelta listener threw; ignoring and continuing stream");}}let c={text:await l.text??"",raw:l},u=await ee(l.usage);u&&(c.usage=ve(u));let p=await ee(l.reasoningText);typeof p=="string"&&p.length>0&&(c.reasoning=p);let m=await ee(l.output);m!==void 0&&(c.output=m);let f=await ee(l.finishReason);typeof f=="string"&&(c.finishReason=f);let h=await ee(l.steps),g=ke({steps:h});g.length>0&&(c.toolCalls=g),Array.isArray(h)&&(c.stepsCount=h.length);let w=await ee(l.response);return w&&Array.isArray(w.messages)&&(c.responseMessages=w.messages),c}async function ee(t){if(t!==void 0)try{return await t}catch(e){routecraft.logger.debug({err:e},"llm.streamLlm: optional accessor rejected; treating as absent");return}}async function mn(t){return pn(t)}async function Fe(t){let{config:e,modelId:n,options:o,system:r,user:i}=t,a=await Ue(e,n);return Wo(a,o,r,i,Ce(t))}async function Wo(t,e,n,o,r){let{generateText:i}=await import('ai'),a=be(t,e,n,o,r),s=await i(a),l={text:s.text??"",raw:s};s.usage&&(l.usage=ve(s.usage));let d=Dt(s);d!==void 0&&(l.output=d);let c=_t(s);c&&(l.reasoning=c);let u=s.finishReason;typeof u=="string"&&(l.finishReason=u);let p=ke(s);p.length>0&&(l.toolCalls=p);let m=s.steps;Array.isArray(m)&&(l.stepsCount=m.length);let f=s.response?.messages;return Array.isArray(f)&&(l.responseMessages=f),l}function fn(t,e,n){let o=t["~standard"];if(!o?.validate)throw new Error(`${n} must be a StandardSchemaV1 with ~standard.validate`);let r=e==="input"?o.jsonSchema?.input:o.jsonSchema?.output,i=e==="input"?o.jsonSchema?.output:o.jsonSchema?.input,a=r?.({target:"draft-2020-12"})??i?.({target:"draft-2020-12"});if(!a||typeof a!="object")throw new Error(`${n} must expose ~standard.jsonSchema.input or .output for AI SDK use`);function s(l){let d;try{d=o.validate(l);}catch(u){return {success:false,error:u instanceof Error?u:new Error(String(u))}}return d instanceof Promise?{success:false,error:new Error(`${n}: async schema validation is not supported`)}:d.issues!=null&&(Array.isArray(d.issues)?d.issues.length>0:typeof d.issues=="object"&&d.issues!==null?Object.keys(d.issues).length>0:!!d.issues)?{success:false,error:new Error(routecraft.formatSchemaIssues(d.issues))}:{success:true,value:d.value}}return ai.jsonSchema(a,{validate:s})}function gn(t){return fn(t,"input","Tool input schema")}function He(t){let e=fn(t,"output","LLM output schema");return ai.Output.object({schema:e})}async function hn(t,e,n,o,r){if(t.length===0)return Object.create(null);let{tool:i}=await import('ai'),a=Object.create(null);for(let s of t){let l=s.guard,d=s.handler,c=tr(s.name,n,r),u=on(s),p=u?s.blockName:void 0;a[s.name]=i({description:s.description,inputSchema:gn(s.input),execute:async(m,f)=>{let h={...c,abortSignal:f?.abortSignal??c.abortSignal},g=f?.toolCallId??crypto$1.randomUUID(),w=Date.now();!u&&e&&o&&e.emit(`route:${o.routeId}:agent:tool:invoked`,{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,toolName:s.name,input:m});try{l&&await l(m,h);let v=await d(m,h);return e&&o&&(u?e.emit(`route:${o.routeId}:agent:block:loaded`,{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,blockName:p,output:v,duration:Date.now()-w}):e.emit(`route:${o.routeId}:agent:tool:result`,{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,toolName:s.name,output:v,duration:Date.now()-w})),v}catch(v){throw e&&o&&(u?e.emit(`route:${o.routeId}:agent:block:error`,{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,blockName:p,error:v,duration:Date.now()-w}):e.emit(`route:${o.routeId}:agent:tool:error`,{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,toolName:s.name,error:v,duration:Date.now()-w})),v}}});}return a}function tr(t,e,n){return {logger:routecraft.logger.child({tool:t}),abortSignal:e,...n?{principal:nr(n)}:{}}}function nr(t){let e=routecraft.isAuthentic(t),n={...t};return n.audience&&(n.audience=[...n.audience]),n.scopes&&(n.scopes=[...n.scopes]),n.roles&&(n.roles=[...n.roles]),n.claims&&(n.claims=structuredClone(n.claims)),yn(n),e?routecraft.markAuthentic(n):n}function yn(t,e=new WeakSet){if(t===null||typeof t!="object"||e.has(t)||ArrayBuffer.isView(t))return t;e.add(t);for(let n of Object.keys(t)){let o=t[n];o!==null&&typeof o=="object"&&yn(o,e);}return Object.freeze(t)}function Rn(t,e){if(e===void 0)return;let n=t.headers[routecraft.HeadersKeys.CORRELATION_ID];return {exchangeId:t.id,correlationId:typeof n=="string"?n:t.id,routeId:e}}var rr=0,ir=1024,sr=20,Ve=class{constructor(e){this.input=e;}input;async runUntilDone(e){return this.runWithValidation(e,void 0)}async runStream(e,n){return this.runWithValidation(e,n)}async runWithValidation(e,n){let{options:o,exchange:r}=this.input,i=o.validate,a=o.maxTurns??sr,s=await this.prepare(e),l=0,d=this.input.user,c,u=[];try{for(;;){let p=a-l;if(p<=0)throw routecraft.rcError("RC5003",void 0,{message:c?`agent: maxTurns (${a}) reached while "validate" was still rejecting; last validator message: "${c}"`:`agent: maxTurns (${a}) reached.`});let m=await ar(s,d,p,e,n);if(l+=m.stepsCount??1,m.toolCalls&&m.toolCalls.length>0&&u.push(...m.toolCalls),!i)return this.emitFinished(m),vt(m,u);let f=await Promise.resolve(i(vt(m,u),{exchange:r,turnsUsed:l}));if(f==null)return this.emitFinished(m),vt(m,u);if(typeof f!="string"||f.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agent: "validate" returned a non-string, non-void value (${typeof f}). Return void to accept, a non-empty string to retry.`});c=f,d=dr(this.input.user,d,m,f);}}catch(p){throw this.emitError(p),p}}emitFinished(e){let n=this.input.dispatchIdentity,o=this.input.context;if(!n||!o)return;let r=e.finishReason??"unknown";o.emit(`route:${n.routeId}:agent:finished`,{routeId:n.routeId,exchangeId:n.exchangeId,correlationId:n.correlationId,finishReason:r,...e.usage?.inputTokens!==void 0&&{inputTokens:e.usage.inputTokens},...e.usage?.outputTokens!==void 0&&{outputTokens:e.usage.outputTokens},...e.usage?.totalTokens!==void 0&&{totalTokens:e.usage.totalTokens}});}emitError(e){let n=this.input.dispatchIdentity,o=this.input.context;!n||!o||o.emit(`route:${n.routeId}:agent:error`,{routeId:n.routeId,exchangeId:n.exchangeId,correlationId:n.correlationId,error:e});}async prepare(e){let{options:n,modelConfig:o,modelName:r,tools:i,system:a,context:s,exchange:l,dispatchIdentity:d}=this.input,c=await hn(i,s,e,d,l.principal),u={modelConfig:o,modelName:r,system:a,vercelTools:c};return n.output!==void 0?{...u,output:He(n.output)}:u}};async function ar(t,e,n,o,r){let i=Object.keys(t.vercelTools).length>0?{tools:t.vercelTools,stopWhen:await lr(n)}:{},a={config:t.modelConfig,modelId:t.modelName,options:{temperature:rr,maxTokens:ir},system:t.system,user:e,abortSignal:o,...t.output!==void 0?{output:t.output}:{},...i};return r?mn({...a,onDelta:r}):Fe(a)}async function lr(t){let{stepCountIs:e}=await import('ai');return e(t)}function dr(t,e,n,o){let r=typeof e=="string"?[{role:"user",content:t}]:e,i=n.responseMessages??[];return [...r,...i,{role:"user",content:`Validator: ${o}`}]}function vt(t,e){let n={text:t.text};t.output!==void 0&&(n.output=t.output),t.reasoning!==void 0&&(n.reasoning=t.reasoning),t.usage&&(n.usage=t.usage);let o=[],r=[];for(let i of e)dn(i.toolName)?r.push(i):o.push(i);return o.length>0&&(n.toolCalls=o),r.length>0&&(n.blocksLoaded=ln(r)),n}function vn(t,e){return t.user!==void 0?F(t.user,e):je(e)}var H=Symbol.for("routecraft.adapter.agent.registry"),te=Symbol.for("routecraft.adapter.agent.default-options");var pr=H.description??"routecraft.adapter.agent.registry",G=class{constructor(e){this.binding=e;}binding;adapterId="routecraft.adapter.agent";async send(e){let n=routecraft.getExchangeContext(e),o=this.resolveOptions(n),r=mr(o,n);if(r.model===void 0)throw routecraft.rcError("RC5003",void 0,{message:'Agent: no "model" supplied and no agentPlugin({ defaultOptions: { model } }) is set on this context. Specify "model" on the agent or set a context-level default.'});let{config:i,modelName:a}=$e(r.model,n),s=hr(r,n),l=vn(r,e),d=F(r.system,e);if(d.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "system" resolved to an empty string. When "system" is a function, it must return a non-empty string for the incoming exchange.'});let{systemAppend:c,loaderTools:u}=await rn(r.blocks,e,n),p=gr(s,u),m=`${d}${c}`,f=yr(m,r.principal,e.principal,e),h=routecraft.getExchangeRoute(e),g=Rn(e,h?.definition.id),w=new Ve({options:r,modelConfig:i,modelName:a,tools:p,user:l,system:f,context:n,exchange:e,dispatchIdentity:g}),v=h?.signal??new AbortController().signal,A=this.binding.kind==="by-name"?this.binding.perCall?.onDelta??r.onDelta:r.onDelta;return A!==void 0?await w.runStream(v,A):await w.runUntilDone(v)}resolveOptions(e){if(this.binding.kind==="inline")return this.binding.options;if(!e)throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so the "${pr}" store can be read.`});let n=e.getStore(H);if(!n)throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" not found: no agents registered. Add agentPlugin({ agents: { "${this.binding.name}": {...} } }) to your config.`});let o=n.get(this.binding.name);if(!o){let r=Array.from(n.keys()).join(", ")||"<none>";throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" not found in registry. Known agents: ${r}.`})}return o}getMetadata(e){let n=e,o={};if(this.binding.kind==="by-name"&&(o.agent=this.binding.name),this.binding.kind==="inline"){let r=this.binding.options.model;typeof r=="string"&&(o.model=r);}return n.usage?.inputTokens!==void 0&&(o.inputTokens=n.usage.inputTokens),n.usage?.outputTokens!==void 0&&(o.outputTokens=n.usage.outputTokens),o}};function mr(t,e){let n=e?.getStore(te);if(!n)return t;let o={...t};return o.model===void 0&&n.model!==void 0&&(o.model=n.model),o.tools===void 0&&n.tools!==void 0&&(o.tools=n.tools),o.maxTurns===void 0&&n.maxTurns!==void 0&&(o.maxTurns=n.maxTurns),o.principal===void 0&&n.principal!==void 0&&(o.principal=n.principal),n.blocks!==void 0&&(o.blocks=fr(n.blocks,t.blocks)),o}function fr(t,e){let n=Object.create(null);if(!e){for(let[o,r]of Object.entries(t))n[o]=r;return n}for(let[o,r]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(e,o)){let i=e[o];if(i===false||i===void 0)continue;n[o]=i;}else n[o]=r;for(let[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(n,o)||r!==false&&(n[o]=r);return n}function gr(t,e){for(let n of t)if(n.name.startsWith(U))throw routecraft.rcError("RC5026",void 0,{message:`Agent tool "${n.name}": names starting with "${U}" are reserved for synthetic block tools. Rename the fn or route.`});return [...t,...e]}function hr(t,e){if(t.tools===void 0)return [];if(!e)throw routecraft.rcError("RC5003",void 0,{message:"Agent: cannot resolve tools without a CraftContext."});return t.tools.resolve(e)}function yr(t,e,n,o){if(e===void 0||e===false)return t;let r=typeof e=="function"?e(n,o):wr(n);return r.trim()===""?t:`${t}
|
|
5
|
+
${u}`);continue}i.push(fr(a,l,e,n,r));}return {systemAppend:s.join(""),loaderTools:i}}function vt(t){return typeof t.mode!="string"}var Rt=at;function bt(t){return routecraft.rcError("AI1002",void 0,{message:`Agent block "${t}": two blocks resolve to the same name after flattening nested groups. Rename one of them.`})}function Ct(t){return routecraft.rcError("AI1002",void 0,{message:`Agent block "${t}": blocks form a cycle (a group contains itself). Block trees must be finite.`})}function pr(t){let e=new Map;return Mn(t,"",e,new WeakSet),e}function Mn(t,e,n,o){if(o.has(t))throw Ct(e);o.add(t);for(let[r,s]of Object.entries(t)){if(s===false)continue;let i=e?`${e}${Tt}${r}`:r;if(vt(s)){Mn(s,i,n,o);continue}if(n.has(i))throw bt(i);n.set(i,s);}o.delete(t);}var bn=new WeakMap;async function On(t,e,n,o,r){if((e.lifetime??"dispatch")==="context"&&o){let i=bn.get(o);if(i?.has(e))return i.get(e);i||(i=new Map,bn.set(o,i));let a=Cn(t,e,n,o,r);return i.set(e,a),a.catch(()=>i.delete(e)),a}return Cn(t,e,n,o,r)}async function Cn(t,e,n,o,r){let{value:s}=e;if(typeof s=="string")return s;if(typeof s!="function")throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${t}": "value" must be a string or a function returning a string.`});if(!o)throw routecraft.rcError("AI1001",void 0,{message:`Agent block "${t}": resolver function requires a CraftContext but the exchange has no bound context.`});let i;try{i=await Promise.resolve(s(n,o,[],r));}catch(a){throw routecraft.rcError("AI1001",a,{message:`Agent block "${t}": resolver function threw: ${a?.message??String(a)}`})}if(typeof i!="string")throw routecraft.rcError("AI1001",void 0,{message:`Agent block "${t}": resolver function must return a string (got ${typeof i}).`});return i}var An={type:"object",properties:{},additionalProperties:false},mr={"~standard":{version:1,vendor:"routecraft",validate(t){return t===null||typeof t!="object"||Array.isArray(t)||Object.keys(t).length>0?{issues:[{message:"Expected an empty object {}."}]}:{value:{}}},jsonSchema:{input:()=>An,output:()=>An}}};function fr(t,e,n,o,r){let s=typeof e.description=="string"&&e.description.trim()!==""?e.description:`Load the "${t}" block.`,i=async()=>On(t,e,n,o,r);return {name:`${I}${t}`,description:s,input:mr,source:{kind:"block",name:t},handler:i,[kn]:true,blockName:t}}function En(t){let e=[];for(let n of t){if(!n.toolName.startsWith(I))continue;let r={blockName:n.toolName.slice(I.length),toolName:n.toolName,toolCallId:n.toolCallId};n.output!==void 0&&(r.output=n.output),n.error!==void 0&&(r.error=n.error),e.push(r);}return e}function Sn(t){return t.startsWith(I)}function N(t){let e=t.indexOf(":");if(e<1||e===t.length-1)throw new Error(`LLM model id must be "providerId:modelName" (e.g. ollama:lfm2.5-thinking). Got: "${t}"`);return {providerId:t.slice(0,e),modelName:t.slice(e+1)}}function Ne(t,e){if(typeof t!="string"){let i=t.modelId??"",a=t.provider==="custom"&&typeof t.model!="function";if(i.trim()===""&&!a)throw routecraft.rcError("RC5003",void 0,{message:`LLM model: inline LlmModelConfig for provider "${t.provider}" did not resolve to a model name. Either pass the model as a "providerId:modelName" string (e.g. "${t.provider}:<model>") or set "modelId" on the config.`});return {config:t,modelName:i}}if(!e)throw new Error(`LLM model id "${t}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${V.description}" can be read.`);let n=e.getStore(V);if(!n)throw new Error('LLM provider not found: no providers registered. Add llmPlugin({ providers: { ollama: { provider: "ollama" }, ... } }) to your config.');let{providerId:o,modelName:r}=N(t),s=n.get(o);if(!s)throw new Error(`LLM provider "${o}" not found. Register it with llmPlugin({ providers: { "${o}": { provider, apiKey?, baseURL? } } }).`);return {config:s,modelName:r}}function $(t,e){return t===void 0||t===""?"":typeof t=="function"?t(e):t}function $e(t){let e=t.body;return typeof e=="string"?e:e==null?"":typeof e=="object"?JSON.stringify(e):String(e)}async function De(t,e){switch(t.provider){case "openai":return hr(t,e);case "anthropic":return yr(t,e);case "gemini":return wr(t,e);case "openrouter":return Tr(t,e);case "ollama":return vr(t,e);case "lmstudio":return Rr(t,e);case "custom":return br(t,e);default:{let n=t;throw new Error(`LLM provider not implemented: ${n.provider}`)}}}function At(t){let e={apiKey:t.apiKey};return t.baseURL!==void 0&&(e.baseURL=t.baseURL),e}async function hr(t,e){return (await routecraft.loadOptionalPeer(()=>import('@ai-sdk/openai'),{adapterName:"OpenAI LLM",packageName:"@ai-sdk/openai"})).createOpenAI(At(t))(e)}async function yr(t,e){return (await routecraft.loadOptionalPeer(()=>import('@ai-sdk/anthropic'),{adapterName:"Anthropic LLM",packageName:"@ai-sdk/anthropic"})).createAnthropic(At(t))(e)}async function wr(t,e){return (await routecraft.loadOptionalPeer(()=>import('@ai-sdk/google'),{adapterName:"Gemini LLM",packageName:"@ai-sdk/google"})).createGoogleGenerativeAI(At(t))(e)}async function Tr(t,e){let o=(await routecraft.loadOptionalPeer(()=>import('@openrouter/ai-sdk-provider'),{adapterName:"OpenRouter LLM",packageName:"@openrouter/ai-sdk-provider"})).createOpenRouter({apiKey:t.apiKey}),r=t.modelId??e,s=o.chat(r);return S(s,"OpenRouter",r),s}async function vr(t,e){let o=(await routecraft.loadOptionalPeer(()=>import('ollama-ai-provider-v2'),{adapterName:"Ollama LLM",packageName:"ollama-ai-provider-v2"})).createOllama({baseURL:t.baseURL??rt.ollama.baseURL}),r=t.modelId??e,s=o(r);return S(s,"Ollama",r),s}async function Rr(t,e){let n=await routecraft.loadOptionalPeer(()=>import('@ai-sdk/openai-compatible'),{adapterName:"LM Studio LLM",packageName:"@ai-sdk/openai-compatible"}),o={name:"lmstudio",baseURL:t.baseURL??rt.lmstudio.baseURL,includeUsage:true};t.apiKey!==void 0&&(o.apiKey=t.apiKey);let r=n.createOpenAICompatible(o),s=t.modelId??e,i=r(s);return S(i,"LM Studio",s),i}function br(t,e){let{model:n}=t,o=typeof n=="function"?n(e):n;return S(o,"Custom",e||"(custom)"),o}function Ln(t){if(t===null||typeof t!="object")return null;let e=t;switch(e.type){case "text-delta":{let o=je(e,"text")??je(e,"textDelta");return o===void 0||o.length===0?null:{type:"text-delta",text:o}}case "reasoning-delta":{let o=je(e,"text")??je(e,"delta");return o===void 0||o.length===0?null:{type:"reasoning-delta",text:o}}default:return null}}function je(t,e){let n=t[e];return typeof n=="string"?n:void 0}async function _n(t){let{config:e,modelId:n,options:o,system:r,user:s,onDelta:i}=t,a=await De(e,n);return Cr(a,o,r,s,we(t),i)}async function Cr(t,e,n,o,r,s){let{streamText:i}=await import('ai'),a=Te(t,e,n,o,r),l=i(a);for await(let R of l.fullStream){let re=Ln(R);if(re!==null)try{await s(re);}catch(ge){routecraft.logger.warn({err:ge},"agent.onDelta listener threw; ignoring and continuing stream");}}let c={text:await l.text??"",raw:l},d=await X(l.usage);d&&(c.usage=he(d));let p=await X(l.reasoningText);typeof p=="string"&&p.length>0&&(c.reasoning=p);let m=await X(l.output);m!==void 0&&(c.output=m);let f=await X(l.finishReason);typeof f=="string"&&(c.finishReason=f);let h=await X(l.steps),g=ye({steps:h});g.length>0&&(c.toolCalls=g),Array.isArray(h)&&(c.stepsCount=h.length);let b=await X(l.response);return b&&Array.isArray(b.messages)&&(c.responseMessages=b.messages),c}async function X(t){if(t!==void 0)try{return await t}catch(e){routecraft.logger.debug({err:e},"llm.streamLlm: optional accessor rejected; treating as absent");return}}async function Nn(t){return _n(t)}async function Be(t){let{config:e,modelId:n,options:o,system:r,user:s}=t,i=await De(e,n);return Ar(i,o,r,s,we(t))}async function Ar(t,e,n,o,r){let{generateText:s}=await import('ai'),i=Te(t,e,n,o,r),a=await s(i),l={text:a.text??"",raw:a};a.usage&&(l.usage=he(a.usage));let u=Ft(a);u!==void 0&&(l.output=u);let c=Ut(a);c&&(l.reasoning=c);let d=a.finishReason;typeof d=="string"&&(l.finishReason=d);let p=ye(a);p.length>0&&(l.toolCalls=p);let m=a.steps;Array.isArray(m)&&(l.stepsCount=m.length);let f=a.response?.messages;return Array.isArray(f)&&(l.responseMessages=f),l}function $n(t,e,n){let o=t["~standard"];if(!o?.validate)throw new Error(`${n} must be a StandardSchemaV1 with ~standard.validate`);let r=e==="input"?o.jsonSchema?.input:o.jsonSchema?.output,s=e==="input"?o.jsonSchema?.output:o.jsonSchema?.input,i=r?.({target:"draft-2020-12"})??s?.({target:"draft-2020-12"});if(!i||typeof i!="object")throw new Error(`${n} must expose ~standard.jsonSchema.input or .output for AI SDK use`);function a(l){let u;try{u=o.validate(l);}catch(d){return {success:false,error:d instanceof Error?d:new Error(String(d))}}return u instanceof Promise?{success:false,error:new Error(`${n}: async schema validation is not supported`)}:u.issues!=null&&(Array.isArray(u.issues)?u.issues.length>0:typeof u.issues=="object"&&u.issues!==null?Object.keys(u.issues).length>0:!!u.issues)?{success:false,error:new Error(routecraft.formatSchemaIssues(u.issues))}:{success:true,value:u.value}}return ai$1.jsonSchema(i,{validate:a})}function Dn(t){return $n(t,"input","Tool input schema")}function Fe(t){let e=$n(t,"output","LLM output schema");return ai$1.Output.object({schema:e})}async function Bn(t,e,n,o,r){if(t.length===0)return Object.create(null);let{tool:s}=await import('ai'),i=Object.create(null);for(let a of t){let l=a.guard,u=a.handler,c=ke(a.name,n,r),d=Pn(a),p=d?a.blockName??a.name:void 0;i[a.name]=s({description:a.description,inputSchema:Dn(a.input),execute:async(m,f)=>{let h={...c,abortSignal:f?.abortSignal??c.abortSignal},g=f?.toolCallId??crypto$1.randomUUID(),b=Date.now();!d&&e&&o&&e.emit("route:agent:tool:invoked",{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,toolName:a.name,_snapshot:{input:m}});try{l&&await l(m,h);let R=await u(m,h);return e&&o&&(d?e.emit("route:agent:block:loaded",{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,blockName:p,_snapshot:{output:R},duration:Date.now()-b}):e.emit("route:agent:tool:result",{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,toolName:a.name,_snapshot:{output:R},duration:Date.now()-b})),R}catch(R){throw e&&o&&(d?e.emit("route:agent:block:error",{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,blockName:p,errorName:jn(R),_snapshot:{error:R},duration:Date.now()-b}):e.emit("route:agent:tool:error",{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,toolCallId:g,toolName:a.name,errorName:jn(R),_snapshot:{error:R},duration:Date.now()-b})),R}}});}return i}function jn(t){return t instanceof Error?t.name||"Error":typeof t}function Un(t,e){if(e===void 0)return;let n=t.headers[routecraft.HeadersKeys.CORRELATION_ID];return {exchangeId:t.id,correlationId:typeof n=="string"?n:t.id,routeId:e}}var Er=0,Sr=1024,Lr=20,Ue=class{constructor(e){this.input=e;}input;async runUntilDone(e){return this.runWithValidation(e,void 0)}async runStream(e,n){return this.runWithValidation(e,n)}async runWithValidation(e,n){let{options:o,exchange:r}=this.input,s=o.validate,i=o.maxTurns??Lr;this.emitStarted(i);let a=0,l=this.input.user,u,c=[];try{let d=await this.prepare(e);for(;;){let p=i-a;if(p<=0)throw routecraft.rcError("RC5003",void 0,{message:u?`agent: maxTurns (${i}) reached while "validate" was still rejecting; last validator message: "${u}"`:`agent: maxTurns (${i}) reached.`});let m=await Ir(d,l,p,e,n);if(a+=m.stepsCount??1,m.toolCalls&&m.toolCalls.length>0&&c.push(...m.toolCalls),!s)return this.emitFinished(m),kt(m,c);let f=await Promise.resolve(s(kt(m,c),{exchange:r,turnsUsed:a}));if(f==null)return this.emitFinished(m),kt(m,c);if(typeof f!="string"||f.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agent: "validate" returned a non-string, non-void value (${typeof f}). Return void to accept, a non-empty string to retry.`});u=f,l=Nr(this.input.user,l,m,f);}}catch(d){throw this.emitError(d),d}}emitStarted(e){let n=this.input.dispatchIdentity,o=this.input.context;!n||!o||o.emit("route:agent:started",{routeId:n.routeId,exchangeId:n.exchangeId,correlationId:n.correlationId,...this.input.agentName!==void 0&&{agentName:this.input.agentName},model:this.input.model,toolNames:this.input.tools.map(r=>r.name),maxTurns:e});}emitFinished(e){let n=this.input.dispatchIdentity,o=this.input.context;if(!n||!o)return;let r=e.finishReason??"unknown",s=this.input.agentName!==void 0?{agentName:this.input.agentName}:{},i={routeId:n.routeId,exchangeId:n.exchangeId,correlationId:n.correlationId,...s,model:this.input.model};o.emit("route:agent:finished",{...i,finishReason:r,...e.usage?.inputTokens!==void 0&&{inputTokens:e.usage.inputTokens},...e.usage?.outputTokens!==void 0&&{outputTokens:e.usage.outputTokens},...e.usage?.totalTokens!==void 0&&{totalTokens:e.usage.totalTokens}}),o.emit("route:agent:usage",{...i,...e.usage?.inputTokens!==void 0&&{inputTokens:e.usage.inputTokens},...e.usage?.outputTokens!==void 0&&{outputTokens:e.usage.outputTokens},...e.usage?.totalTokens!==void 0&&{totalTokens:e.usage.totalTokens},...e.usage?.cacheReadTokens!==void 0&&{cacheReadTokens:e.usage.cacheReadTokens},...e.usage?.cacheWriteTokens!==void 0&&{cacheWriteTokens:e.usage.cacheWriteTokens}});}emitError(e){let n=this.input.dispatchIdentity,o=this.input.context;!n||!o||o.emit("route:agent:error",{routeId:n.routeId,exchangeId:n.exchangeId,correlationId:n.correlationId,...this.input.agentName!==void 0&&{agentName:this.input.agentName},model:this.input.model,error:e});}async prepare(e){let{options:n,modelConfig:o,modelName:r,tools:s,system:i,context:a,exchange:l,dispatchIdentity:u}=this.input,c=await Bn(s,a,e,u,l.principal),d={modelConfig:o,modelName:r,system:i,vercelTools:c};return n.output!==void 0?{...d,output:Fe(n.output)}:d}};async function Ir(t,e,n,o,r){let s=Object.keys(t.vercelTools).length>0?{tools:t.vercelTools,stopWhen:await _r(n)}:{},i={config:t.modelConfig,modelId:t.modelName,options:{temperature:Er,maxTokens:Sr},system:t.system,user:e,abortSignal:o,...t.output!==void 0?{output:t.output}:{},...s};return r?Nn({...i,onDelta:r}):Be(i)}async function _r(t){let{stepCountIs:e}=await import('ai');return e(t)}function Nr(t,e,n,o){let r=typeof e=="string"?[{role:"user",content:t}]:e,s=n.responseMessages??[];return [...r,...s,{role:"user",content:`Validator: ${o}`}]}function kt(t,e){let n={text:t.text};t.output!==void 0&&(n.output=t.output),t.reasoning!==void 0&&(n.reasoning=t.reasoning),t.usage&&(n.usage=t.usage);let o=[],r=[];for(let s of e)Sn(s.toolName)?r.push(s):o.push(s);return o.length>0&&(n.toolCalls=o),r.length>0&&(n.blocksLoaded=En(r)),n}function Hn(t,e){return t.user!==void 0?$(t.user,e):$e(e)}var D=Symbol.for("routecraft.adapter.agent.registry"),Z=Symbol.for("routecraft.adapter.agent.default-options"),ue=Symbol.for("routecraft.adapter.agent.tool-policies");var Vn={fn:true,direct:true,mcp:true},Gn=Object.keys(Vn);function Pt(t){return typeof t=="string"&&Object.hasOwn(Vn,t)}function $r(t,e,n,o){if(t===void 0)return {admitted:false,reported:false};if(typeof t=="boolean")return {admitted:t,reported:false};try{return {admitted:t(e,n)===!0,reported:!1}}catch(r){let s=false;if(o!==void 0)try{o(e,r),s=!0;}catch{s=false;}return {admitted:false,reported:s}}}function Kn(t,e,n,o){if(t.length===0)return {admitted:true,reported:false};let r=e.source?.kind;if(r==="block")return {admitted:true,reported:false};if(!Pt(r))return {admitted:false,reported:false};for(let s of t){let i=s[r],a=$r(i,e,n,o);if(!a.admitted)return a}return {admitted:true,reported:false}}var Br=D.description??"routecraft.adapter.agent.registry",B=class{constructor(e){this.binding=e;}binding;adapterId="routecraft.adapter.agent";async fetch(e){let n=routecraft.getExchangeContext(e),o=this.resolveOptions(n),r=Fr(o,n);if(r.model===void 0)throw routecraft.rcError("RC5003",void 0,{message:'Agent: no "model" supplied and no agentPlugin({ defaultOptions: { model } }) is set on this context. Specify "model" on the agent or set a context-level default.'});let s=r.model,{config:i,modelName:a}=Ne(s,n),l=this.binding.kind==="by-name"?this.binding.name:void 0,u=routecraft.getExchangeRoute(e),c=Un(e,u?.definition.id),d=Vr(r,n,l,c),p=Hn(r,e),m=$(r.system,e);if(m.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "system" resolved to an empty string. When "system" is a function, it must return a non-empty string for the incoming exchange.'});let{systemAppend:f,loaderTools:h}=await xn(r.blocks,e,n),g=Hr(d,h),b=`${m}${f}`,R=qr(b,r.principal,e.principal,e),re=new Ue({options:r,modelConfig:i,modelName:a,model:s,...l!==void 0&&{agentName:l},tools:g,user:p,system:R,context:n,exchange:e,dispatchIdentity:c}),ge=u?.signal??new AbortController().signal,Bt=this.binding.kind==="by-name"?this.binding.perCall?.onDelta??r.onDelta:r.onDelta;return Bt!==void 0?await re.runStream(ge,Bt):await re.runUntilDone(ge)}resolveOptions(e){if(this.binding.kind==="inline")return this.binding.options;if(!e)throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so the "${Br}" store can be read.`});let n=e.getStore(D);if(!n)throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" not found: no agents registered. Add agentPlugin({ agents: { "${this.binding.name}": {...} } }) to your config.`});let o=n.get(this.binding.name);if(!o){let r=Array.from(n.keys()).join(", ")||"<none>";throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" not found in registry. Known agents: ${r}.`})}return o}getMetadata(e){let n=e,o={};if(this.binding.kind==="by-name"&&(o.agent=this.binding.name),this.binding.kind==="inline"){let r=this.binding.options.model;typeof r=="string"&&(o.model=r);}return n.usage?.inputTokens!==void 0&&(o.inputTokens=n.usage.inputTokens),n.usage?.outputTokens!==void 0&&(o.outputTokens=n.usage.outputTokens),o}};function Fr(t,e){let n=e?.getStore(Z);if(!n)return t;let o={...t};return o.model===void 0&&n.model!==void 0&&(o.model=n.model),o.tools===void 0&&n.tools!==void 0&&(o.tools=n.tools),o.maxTurns===void 0&&n.maxTurns!==void 0&&(o.maxTurns=n.maxTurns),o.principal===void 0&&n.principal!==void 0&&(o.principal=n.principal),n.blocks!==void 0&&(o.blocks=Ur(n.blocks,t.blocks)),o}function Ur(t,e){let n=Object.create(null);if(!e){for(let[o,r]of Object.entries(t))n[o]=r;return n}for(let[o,r]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(e,o)){let s=e[o];if(s===false||s===void 0)continue;n[o]=s;}else n[o]=r;for(let[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(n,o)||r!==false&&(n[o]=r);return n}function Hr(t,e){for(let n of t)if(n.name.startsWith(_))throw routecraft.rcError("AI1002",void 0,{message:`Agent tool "${n.name}": names starting with "${_}" are reserved for synthetic block tools. Rename the fn or route.`});return [...t,...e]}function Vr(t,e,n,o){if(t.tools===void 0)return [];if(!e)throw routecraft.rcError("RC5003",void 0,{message:"Agent: cannot resolve tools without a CraftContext."});return Gr(t.tools.resolve(e),e,n,o)}function Gr(t,e,n,o){let r=e.getStore(ue);if(!r||r.length===0)return t;let s={agentId:n},i=[],a=(u,c,d)=>{o&&e.emit("route:agent:tool:denied",{routeId:o.routeId,exchangeId:o.exchangeId,correlationId:o.correlationId,...n!==void 0&&{agentName:n},toolName:u.name,toolKind:d,reason:c});},l=(u,c)=>{e.logger.error({agent:n??"<inline>",tool:u.name,kind:u.source.kind,err:c},Kr(c)??"Agent tool policy predicate threw; denying the tool. Fix the predicate in agentPlugin({ toolPolicy })");};for(let u of t){let c=Wr(u);if(c===void 0){a(u,"unknown-provenance","unknown"),e.logger.warn({agent:n??"<inline>",tool:u.name,kind:"unknown"},"Agent tool carries no recognisable resolver-set provenance, so no policy can classify it; dropping it from the agent's tool list");continue}let d=Kn(r,c,s,l);if(d.admitted){i.push(u);continue}a(u,d.reported?"rule-error":"rule",c.source.kind),!d.reported&&e.logger.warn({agent:n??"<inline>",tool:u.name,kind:c.source.kind},"Agent tool denied by agentPlugin({ toolPolicy }) and dropped from the agent's tool list");}return i}function Kr(t){if(!(typeof t!="object"||t===null))try{let e=t.meta;if(typeof e?.message=="string"&&e.message!=="")return e.message;let n=t.message;return typeof n=="string"&&n!==""?n:void 0}catch{return}}function Wr(t){let e=t.source?.kind;if(e!=="block"&&!Pt(e))return;let n=t.source.kind==="mcp"&&t.source.annotations?{...t.source,annotations:Object.freeze({...t.source.annotations})}:{...t.source};return Object.freeze({name:t.name,description:t.description,tags:Object.freeze(t.tags?[...t.tags]:[]),source:Object.freeze(n)})}function qr(t,e,n,o){if(e===void 0||e===false)return t;let r=typeof e=="function"?e(n,o):zr(n);return r.trim()===""?t:`${t}
|
|
6
6
|
|
|
7
|
-
${r}`}function
|
|
7
|
+
${r}`}function zr(t){if(!t)return `## Caller
|
|
8
8
|
|
|
9
|
-
The current request is not authenticated. No verified user identity is available. Do not assume, infer, or invent the caller's name, email, or permissions.`;let e=[];t.name&&e.push(`- Name: ${
|
|
9
|
+
The current request is not authenticated. No verified user identity is available. Do not assume, infer, or invent the caller's name, email, or permissions.`;let e=[];t.name&&e.push(`- Name: ${He(t.name)}`),t.email&&e.push(`- Email: ${He(t.email)}`),e.push(`- Subject: ${He(t.subject)}`);let n=t.roles?.map(o=>He(o)).filter(o=>o.length>0);return n&&n.length>0&&e.push(`- Roles: ${n.join(", ")}`),`## Caller
|
|
10
10
|
|
|
11
11
|
The current request is authenticated.
|
|
12
12
|
${e.join(`
|
|
13
|
-
`)}`}function Ge(t){return t.replace(/\s*[\r\n]+\s*/g," ").trim()}var D=Symbol.for("routecraft.adapter.fn.registry");async function qe(t,e,n,o){let i=t.getStore(fe)?.get(e);if(i)try{return await i.callTool(n,o)}catch(d){throw routecraft.isRoutecraftError(d)?d:routecraft.rcError("RC5003",d,{message:`mcp dispatch: stdio call to "${e}:${n}" failed.`})}let s=t.getStore(M)?.get(e);if(!s)throw routecraft.rcError("RC5003",void 0,{message:`mcp dispatch: server "${e}" is not registered. Register it via defineConfig.mcp / mcpPlugin({ clients }).`});if(typeof s!="object"||s===null)throw routecraft.rcError("RC5003",void 0,{message:`mcp dispatch: server "${e}" config is a string shorthand and cannot be called directly. Use a full HTTP config with a url.`});if("transport"in s&&s.transport==="stdio")throw routecraft.rcError("RC5003",void 0,{message:`mcp dispatch: stdio server "${e}" is registered but its client is not running. Ensure mcpPlugin started successfully.`});let l=s;if(typeof l.url!="string"||l.url.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`mcp dispatch: server "${e}" has no url. Cannot dispatch over HTTP.`});return kt(l.url,n,o,l.auth)}async function kt(t,e,n,o){let r=await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/client/index.js'),{adapterName:"mcp (http client)",packageName:"@modelcontextprotocol/sdk"}),i=await routecraft.loadOptionalPeer(()=>import('@modelcontextprotocol/sdk/client/streamableHttp.js'),{adapterName:"mcp (http client)",packageName:"@modelcontextprotocol/sdk"}),a,s;try{let l=new URL(t),d=await Ee(o),c=d?{requestInit:{headers:d}}:void 0;a=new i.StreamableHTTPClientTransport(l,c),s=new r.Client({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{}}),await s.connect(a);let p=await s.callTool.call(s,{name:e,arguments:n});return Me(p)}catch(l){throw routecraft.isRoutecraftError(l)?l:routecraft.rcError("RC5003",l,{message:`mcp dispatch: failed to call tool "${e}" at "${t}".`})}finally{if(s){let l=s,d=l.close??l.disconnect;if(typeof d=="function")try{await Promise.resolve(d.call(s));}catch{}}if(a){let l=a,d=l.close??l.destroy;if(typeof d=="function")try{await Promise.resolve(d.call(a));}catch{}}}}var he=Symbol.for("routecraft.ai.fn.deferred");function oe(t){return typeof t=="object"&&t!==null&&he in t&&t[he]===true}function Or(t){let e={...t};return t.audience&&(e.audience=[...t.audience]),t.scopes&&(e.scopes=[...t.scopes]),t.roles&&(e.roles=[...t.roles]),t.claims&&(e.claims=structuredClone(t.claims)),routecraft.isAuthentic(t)?routecraft.markAuthentic(e):e}var Pn={type:"object",properties:{},additionalProperties:false},An={"~standard":{version:1,vendor:"routecraft",validate(t){return t===null||typeof t!="object"||Array.isArray(t)||Object.keys(t).length>0?{issues:[{message:"Expected an empty object {}."}]}:{value:{}}},jsonSchema:{input:()=>Pn,output:()=>Pn}}};function We(t,e){if(typeof t!="string"||t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"directTool: routeId must be a non-empty string."});return {[he]:true,kind:"direct",targetId:t,resolve(n,o){let r=Ar(n,t,o),i=e?.description??r.description;if(typeof i!="string"||i.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`directTool: route "${t}" has no .description() and no override was provided (referenced as fn "${o}").`});let a=e?.input??r.input?.body;if(!a)throw routecraft.rcError("RC5003",void 0,{message:`directTool: route "${t}" has no .input(...) schema and no override was provided (referenced as fn "${o}").`});let s=r.tags,l=((d,c)=>Tr(n,c,t,d));return {description:i,input:a,...s&&s.length>0?{tags:[...s]}:{},handler:l}}}}function Ar(t,e,n){let o=t.getStore(routecraft.ADAPTER_DIRECT_REGISTRY),r=routecraft.sanitizeEndpoint(e),i=o?.get(r);if(!i){let a=o?[...o.keys()].sort():[];throw routecraft.rcError("RC5003",void 0,{message:`directTool: unknown direct route id "${e}" (referenced as fn "${n}"). `+(a.length>0?`Known route ids: ${a.join(", ")}.`:"No direct routes are registered in this context.")})}return i}async function Tr(t,e,n,o){let r=routecraft.sanitizeEndpoint(n),i={};e.correlationId&&(i[routecraft.HeadersKeys.CORRELATION_ID]=e.correlationId),e.principal&&(i[routecraft.HeadersKeys.AUTH_PRINCIPAL]=Or(e.principal));let a=new routecraft.DefaultExchange(t,{body:o,...Object.keys(i).length>0?{headers:i}:{}});return (await routecraft.getDirectChannel(t,r,{}).send(r,a)).body}function Tn(){return {description:"Returns the current UTC timestamp in ISO 8601 format.",input:An,handler:()=>new Date().toISOString(),tags:["read-only","idempotent"]}}function Mn(){return {description:"Generates a fresh random UUID v4.",input:An,handler:()=>crypto$1.randomUUID(),tags:["read-only"]}}var ze=Symbol.for("routecraft.ai.tools.selection");function re(t){return typeof t=="object"&&t!==null&&ze in t&&t[ze]===true}function Je(t){if(typeof t!="function"&&!Array.isArray(t))throw routecraft.rcError("RC5003",void 0,{message:"tools(): argument must be an array of ToolsItem or a (catalog) => ToolsItem[] builder."});return {[ze]:true,resolve(e){let n=typeof t=="function"?Sr(t,Mr(e)):t,o=new Map;for(let r of n){if(typeof r=="string"){if(xn(r)&&!Sn(e,r)){for(let l of Ln(e,r,void 0))o.set(l.name,l);continue}let s=En(e,r,void 0);o.set(s.name,s);continue}if(r===null||typeof r!="object"||!("name"in r))throw routecraft.rcError("RC5003",void 0,{message:"tools(): each item must be a string or { name, guard?, description? }."});if(typeof r.name!="string"||r.name.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"tools(): { name } must be a non-empty string."});if(xn(r.name)&&!Sn(e,r.name)){if(r.description!==void 0)throw routecraft.rcError("RC5003",void 0,{message:`tools(): { name: "${r.name}", description } is not supported for MCP tools. The MCP server is the source of truth for description and schema; do not override.`});for(let s of Ln(e,r.name,r.guard))o.set(s.name,s);continue}if(r.description!==void 0&&(typeof r.description!="string"||r.description.trim()===""))throw routecraft.rcError("RC5003",void 0,{message:`tools(): { name: "${r.name}", description } must be a non-empty string when present.`});let i=En(e,r.name,r.guard),a=r.description!==void 0?{...i,description:r.description}:i;o.set(a.name,a);}return [...o.values()]}}}function Mr(t){let e=[],n=t.getStore(D);if(n)for(let[s,l]of n)if(oe(l))e.push(Object.freeze({name:s}));else {let d=l.tags&&l.tags.length>0?Object.freeze([...l.tags]):void 0;e.push(Object.freeze({name:s,description:l.description,...d!==void 0?{tags:d}:{}}));}let o=[],r=t.getStore(routecraft.ADAPTER_DIRECT_REGISTRY);if(r)for(let[s,l]of r){let d=l.tags&&l.tags.length>0?Object.freeze([...l.tags]):void 0,c=decodeURIComponent(s);o.push(Object.freeze({id:c,...l.description?{description:l.description}:{},...d!==void 0?{tags:d}:{}}));}let i=[],a=t.getStore(J);if(a)for(let s of a.getTools()){let l=s.tags&&s.tags.length>0?Object.freeze([...s.tags]):void 0;i.push(Object.freeze({server:s.source,tool:s.name,...s.description?{description:s.description}:{},...l!==void 0?{tags:l}:{}}));}return Object.freeze({fns:Object.freeze(e),routes:Object.freeze(o),mcp:Object.freeze(i)})}function Sr(t,e){let n;try{n=t(e);}catch(o){throw routecraft.rcError("RC5003",o,{message:`tools(builder): builder threw: ${o?.message??String(o)}`})}if(!Array.isArray(n))throw routecraft.rcError("RC5003",void 0,{message:`tools(builder): builder must return an array of ToolsItem (got ${typeof n}).`});return n}function Sn(t,e){return t.getStore(D)?.has(e)??false}function En(t,e,n){if(typeof e!="string"||e.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"tools(): tool name must be a non-empty string."});let r=t.getStore(D)?.get(e);if(r)return Er(t,e,r,n);let i=/^Direct\((.*)\)$/.exec(e);if(i){let s=i[1].trim();if(s==="")throw routecraft.rcError("RC5003",void 0,{message:`tools(): "${e}" has an empty route id; use "Direct(<routeId>)".`});let l=`direct_${s}`,c=We(s).resolve(t,l);return Ct(l,c,n)}let a=Dr(t);throw routecraft.rcError("RC5003",void 0,{message:`tools(): unknown tool "${e}". `+(a.length>0?`Available: ${a.join(", ")}.`:"No fns or direct routes are registered in this context.")})}function Er(t,e,n,o){if(oe(n)){let r=n.resolve(t,e);return Ct(e,r,o)}return Ct(e,n,o)}function Ct(t,e,n){return {name:t,description:e.description,input:e.input,...e.tags&&e.tags.length>0?{tags:e.tags}:{},...n?{guard:n}:{},handler:e.handler}}function xn(t){return t.startsWith("mcp__")?true:t.startsWith("MCP(")&&t.endsWith(")")}function xr(t){if(t.startsWith("MCP(")&&t.endsWith(")")){let e=t.slice(4,-1).trim(),n=e.indexOf(":"),o=n===-1?e:e.slice(0,n).trim(),r=n===-1?"*":e.slice(n+1).trim();if(o===""||r==="")throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${t}" must use "MCP(server:tool)" or "MCP(server)"; got an empty server or tool segment.`});return {clientName:o,toolName:r}}if(t.startsWith("mcp__")){let e=t.slice(5),n=e.indexOf("__"),o=n===-1?e:e.slice(0,n),r=n===-1?"*":e.slice(n+2);if(o.trim()===""||r.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${t}" must use "mcp__server__tool" or "mcp__server"; got an empty server or tool segment.`});return {clientName:o,toolName:r}}throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${t}" must use "MCP(server:tool)", "MCP(server)", or the raw "mcp__server__tool" form.`})}function Ln(t,e,n){let{clientName:o,toolName:r}=xr(e),i=t.getStore(J);if(!i)throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${e}" but no MCP_TOOL_REGISTRY is present. Install mcpPlugin (defineConfig.mcp) so external clients populate the registry.`});let a=i.getToolsByServer(o);if(a.length===0){let l=Ir(i);throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${e}" but client "${o}" has no registered tools. `+(l.length>0?`Known MCP clients: ${l.map(d=>`"${d}"`).join(", ")}.`:"No MCP clients are registered in this context.")})}if(r==="*")return a.map(l=>In(t,l,n));let s=a.find(l=>l.name===r);if(!s){let l=a.map(d=>d.name).sort();throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${e}" but tool "${r}" is not registered under client "${o}". Known tools on "${o}": ${l.map(d=>`"${d}"`).join(", ")}.`})}return [In(t,s,n)]}function In(t,e,n){let o=`mcp__${e.source}__${e.name}`,r=e.description&&e.description.trim()!==""?e.description:`MCP tool "${e.name}" on client "${e.source}".`,i=Lr(e.inputSchema),s={name:o,description:r,input:i,handler:async l=>{if(l==null||typeof l!="object"||Array.isArray(l))throw routecraft.rcError("RC5003",void 0,{message:`mcp tool "${o}" expects an object argument; received ${l===null?"null":Array.isArray(l)?"array":typeof l}.`});let d=l;return qe(t,e.source,e.name,d)}};return e.tags&&e.tags.length>0&&(s.tags=[...e.tags]),n&&(s.guard=n),s}function Lr(t){return {"~standard":{version:1,vendor:"routecraft",validate(e){return {value:e}},jsonSchema:{input:()=>t,output:()=>t}}}}function Ir(t){let e=new Set;for(let n of t.getTools())e.add(n.source);return [...e].sort()}function Dr(t){let e=[...(t.getStore(D)??new Map).keys()],n=[...(t.getStore(routecraft.ADAPTER_DIRECT_REGISTRY)??new Map).keys()].map(o=>`Direct(${o})`);return [...e,...n].sort()}function Pt(t){if(typeof t.system=="string"){if(t.system.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "system" is required and must be a non-empty string (or a function that returns one).'})}else if(typeof t.system!="function")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "system" must be a string or a function (exchange) => string.'});if(t.user!==void 0&&typeof t.user!="string"&&typeof t.user!="function")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "user" must be a string or a function (exchange) => string when present.'});if(t.model!==void 0){if(typeof t.model!="string"||t.model.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "model" must be a non-empty "providerId:modelName" string when present.'});try{B(t.model);}catch{throw routecraft.rcError("RC5003",void 0,{message:`Agent: "model" string must be in "providerId:modelName" form (e.g. ollama:llama3). Got: "${t.model}"`})}}if(t.tools!==void 0&&!re(t.tools))throw routecraft.rcError("RC5003",void 0,{message:'Agent: "tools" must be the result of tools([...]).'});if(t.principal!==void 0&&typeof t.principal!="boolean"&&typeof t.principal!="function")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "principal" must be a boolean or a function (principal, exchange) => string when present.'});if(t.output!==void 0){if(t.output===null||typeof t.output!="object")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "output" must be a Standard Schema (Zod/Valibot/ArkType/etc.).'});if(typeof t.output["~standard"]?.validate!="function")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "output" must be a Standard Schema (Zod/Valibot/ArkType/etc.).'})}t.blocks!==void 0&&Ot(t.blocks);}function Ot(t,e){let n={seenNames:new Set,seenObjects:new WeakSet,...e!==void 0?{defaultsLabel:e}:{}};Nn(t,"",n);}function Nn(t,e,n){if(t===null||typeof t!="object"||Array.isArray(t))throw routecraft.rcError("RC5027",void 0,{message:'Agent: "blocks" must be a Record<string, BlockBody | Blocks | false>.'});if(n.seenObjects.has(t))throw Rt(e);n.seenObjects.add(t);let o=0;for(let[r,i]of Object.entries(t)){let a=e?`${e}${ft}${r}`:r;if(r.trim()==="")throw routecraft.rcError("RC5026",void 0,{message:"Agent block: block name must be a non-empty string."});if(r.startsWith(U)||a.startsWith(U))throw routecraft.rcError("RC5026",void 0,{message:`Agent block "${a}": names starting with "${U}" are reserved for synthetic block tools. Rename the block or a parent group.`});if(i===false){if(n.defaultsLabel!==void 0)throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: "${n.defaultsLabel}.${a}" cannot be false. "false" is the per-agent removal sentinel; defaults cannot remove themselves. Drop the entry or replace it with a BlockBody.`});continue}if(i===null||typeof i!="object")throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${a}": value must be a BlockBody object (with mode and value), a nested Blocks group, or "false" to remove a default.`});if(gt(i)){let l=i.value;if(typeof l=="string"||typeof l=="function")throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${a}": "mode" must be "inject" or "progressive" (got ${JSON.stringify(i.mode)}).`});let d=Nn(i,a,n);if(d===0)throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${a}": a nested group must contain at least one block (got an empty group or only "false" members).`});o+=d;continue}if(n.seenNames.has(a))throw wt(a);n.seenNames.add(a),o+=1;let s=i;if(s.mode!=="inject"&&s.mode!=="progressive")throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${a}": "mode" must be "inject" or "progressive" (got ${JSON.stringify(s.mode)}).`});if(s.mode==="progressive"&&(typeof s.description!="string"||s.description.trim()===""))throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${a}": progressive-mode blocks require a non-empty "description" so the model can decide whether to load.`});if(s.mode==="progressive"){if(!ht.test(a))throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${a}": a progressive block becomes the loader tool "${j}${a}", so its flattened name must match ${ht.source} (letters, digits, "_", "-"). Rename the block or its parent group.`});let l=`${j}${a}`;if(l.length>yt)throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${a}": the loader tool name "${l}" is ${l.length} characters, over the provider limit of ${yt}. Shorten the block name or its parent group.`})}if(s.lifetime!==void 0&&s.lifetime!=="dispatch"&&s.lifetime!=="context")throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${a}": "lifetime" must be "dispatch" or "context" when present (got ${JSON.stringify(s.lifetime)}).`});if(typeof s.value!="string"&&typeof s.value!="function")throw routecraft.rcError("RC5027",void 0,{message:`Agent block "${a}": "value" must be a string or a function returning a string.`})}return n.seenObjects.delete(t),o}function Ye(t,e){if(typeof t=="string"){if(t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"Agent: name must be a non-empty string."});return routecraft.tagAdapter(new G({kind:"by-name",name:t,...e?{perCall:e}:{}}),Ye,e?routecraft.factoryArgs(t,e):routecraft.factoryArgs(t))}return Pt(t),routecraft.tagAdapter(new G({kind:"inline",options:t}),Ye,routecraft.factoryArgs(t))}function $n(t,e){if(e===null||typeof e!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" entry must be an object with description, input, and handler.`});if(typeof e.description!="string"||e.description.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" is missing a non-empty "description".`});if(e.input===null||typeof e.input!="object"||typeof e.input["~standard"]!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "input" is required and must be a Standard Schema value (Zod/Valibot/ArkType/etc.).`});if(typeof e.input["~standard"]?.validate!="function")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "input" must be a Standard Schema with a callable validate.`});if(typeof e.handler!="function")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "handler" is required and must be a function.`});if(e.tags!==void 0){if(!Array.isArray(e.tags))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "tags" must be an array of non-empty strings.`});for(let o=0;o<e.tags.length;o++){let r=e.tags[o];if(typeof r!="string"||r.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "tags" must contain only non-empty strings.`});e.tags[o]=r.trim();}}}function _r(t,e){if(typeof e.description!="string"||e.description.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${t}" is missing a non-empty "description". Registered agents carry their own description because they are not backed by a route.`});Pt(e);}function Xe(t={}){let e=t.agents??{},n=t.functions??{},o=Nr(t.defaultOptions);return {apply(r){let i=r.getStore(H),a=i??new Map;for(let[d,c]of Object.entries(e)){if(d.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"agentPlugin: agent id must be a non-empty string."});if(c===null||typeof c!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${d}" entry must be an object with description, model, and system.`});if(c.tools!==void 0&&!re(c.tools))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${d}" "tools" must be the result of tools([...]).`});if(_r(d,c),a.has(d))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: duplicate agent id "${d}". Each agent id must be unique within a context.`});a.set(d,c);}i||r.setStore(H,a);let s=r.getStore(D),l=s??new Map;for(let[d,c]of Object.entries(n)){if(d.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"agentPlugin: fn id must be a non-empty string."});if(c===null||typeof c!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${d}" entry must be an object with description, input, and handler.`});if(oe(c)||$n(d,c),l.has(d))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: duplicate fn id "${d}". Each fn id must be unique within a context.`});l.set(d,c);}if(s||r.setStore(D,l),o!==void 0){let d=r.getStore(te),c=$r(d,o);r.setStore(te,c);}}}}function Nr(t){if(t!==void 0){if(t===null||typeof t!="object"||Array.isArray(t))throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions" must be an object with optional "model" / "tools".'});if(t.model!==void 0){if(typeof t.model!="string"||t.model.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions.model" must be a non-empty "providerId:modelName" string.'});try{B(t.model);}catch{throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: "defaultOptions.model" must be in "providerId:modelName" form (e.g. anthropic:claude-opus-4-7). Got: "${t.model}"`})}}if(t.tools!==void 0&&!re(t.tools))throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions.tools" must be the result of tools([...]).'});return t.blocks!==void 0&&Ot(t.blocks,"defaultOptions.blocks"),t}}function $r(t,e){if(!t)return {...e};if(e.model!==void 0&&t.model!==void 0)throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions.model" is already set on this context. A context can have only one default model.'});if(e.tools!==void 0&&t.tools!==void 0)throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions.tools" is already set on this context. Combine selectors into a single tools([...]) call.'});let n;if((t.blocks!==void 0||e.blocks!==void 0)&&(n={...t.blocks??{}},e.blocks!==void 0))for(let[o,r]of Object.entries(e.blocks)){if(Object.prototype.hasOwnProperty.call(n,o))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: "defaultOptions.blocks" already contains "${o}" from a previous install. Each block name may be defined once across all installs.`});n[o]=r;}return {...t,...e.model!==void 0?{model:e.model}:{},...e.tools!==void 0?{tools:e.tools}:{},...n!==void 0?{blocks:n}:{}}}routecraft.registerConfigApplier("llm",t=>Pe(t));routecraft.registerConfigApplier("mcp",t=>xe(t));routecraft.registerConfigApplier("embedding",t=>Ne(t));routecraft.registerConfigApplier("agent",t=>Xe(t));var jn={McpAdapter:Symbol.for("routecraft.ai.McpAdapter")};function jr(t,e){return typeof t=="object"&&t!==null&&t[e]===true}function Ur(t){return jr(t,jn.McpAdapter)}async function Fr(t,e){let n;try{n=JSON.parse(t);}catch{return}let o=e["~standard"];if(!o?.validate)return;let r=o.validate(n);if(r instanceof Promise&&(r=await r),!(r&&typeof r=="object"&&"issues"in r&&r.issues))return r&&typeof r=="object"&&"value"in r?r.value:void 0}var Hr=0,Vr=1024,ie=class{constructor(e,n={}){this.modelId=e;this.options=n;}modelId;adapterId="routecraft.adapter.llm";options;mergedOptions(e){let n=e.getStore(pe);return {temperature:Hr,maxTokens:Vr,...n,...this.options}}async send(e){let n=routecraft.getExchangeContext(e),{config:o,modelName:r}=$e(this.modelId,n),i=this.mergedOptions(n),a=F(i.system,e),s=F(i.user,e)||je(e),l={temperature:i.temperature,maxTokens:i.maxTokens};i.topP!==void 0&&(l.topP=i.topP),i.frequencyPenalty!==void 0&&(l.frequencyPenalty=i.frequencyPenalty),i.presencePenalty!==void 0&&(l.presencePenalty=i.presencePenalty);let d=i.output!==void 0?He(i.output):void 0,c=await Fe({config:o,modelId:r,options:l,system:a,user:s,output:d});if(c.output===void 0&&c.text&&i.output!==void 0){let u=await Fr(c.text,i.output);u!==void 0&&(c.output=u);}return c}getMetadata(e){let n=e,{providerId:o}=B(this.modelId),r={model:this.modelId,provider:o};return n.usage&&(n.usage.inputTokens!==void 0&&(r.inputTokens=n.usage.inputTokens),n.usage.outputTokens!==void 0&&(r.outputTokens=n.usage.outputTokens)),r}};function Un(t,e){return new ie(t,e)}var se=Symbol.for("routecraft.mcp.adapter");var Gr=/^[A-Za-z0-9_-]{1,64}$/;function qr(t){if(!Gr.test(t))throw routecraft.rcError("RC5003",void 0,{message:`Invalid MCP tool name "${t}"`,suggestion:"MCP tool names must match /^[A-Za-z0-9_-]{1,64}$/ for client interoperability (OpenAI, Anthropic, etc.). Use alphanumerics, underscore, or hyphen in the route's .id()."})}var et=class{adapterId="routecraft.adapter.mcp";options;constructor(e={}){this[se]=true,this.options=e;}async subscribe(e,n,o,r,i){if(!i?.routeId)throw routecraft.rcError("RC5003",void 0,{message:"McpSourceAdapter requires a route id from the engine (missing SourceMeta.routeId)",suggestion:"MCP source adapters take their tool name from the route id. Call .id('tool-name') on the route before .from(mcp(...))."});let a=i.routeId;qr(a);let s=i.discovery,l=s?.description;if(typeof l!="string"||l.length===0)throw routecraft.rcError("RC5003",void 0,{message:`MCP route "${a}" requires a description`,suggestion:"Set .description('...') on the route builder before .from(mcp()); the MCP protocol requires a non-empty description for each tool."});if(e.getStore(me)!==true)throw new Error("MCP plugin required: routes using .from(mcp(...)) require the MCP plugin. Add mcpPlugin() to your config: plugins: [mcpPlugin()].");let c=e.getStore(E);if(c||(c=new Map,e.setStore(E,c)),c.has(a))throw routecraft.rcError("RC5003",void 0,{message:`Duplicate MCP tool endpoint "${a}": another .from(mcp(...)) route already registered this endpoint in the same context`,suggestion:"Each MCP tool endpoint must be unique within a context. Rename one of the mcp() routes to a different route id."});let p={endpoint:a,description:l,handler:async m=>n(m.body,m.headers,void 0,void 0,m.principal)};s?.title!==void 0&&(p.title=s.title),s?.input!==void 0&&(p.input=s.input),s?.output!==void 0&&(p.output=s.output),this.options.annotations!==void 0&&(p.annotations=this.options.annotations),this.options.icons!==void 0&&(p.icons=this.options.icons),o.signal.addEventListener("abort",()=>{e.getStore(E)?.delete(a);},{once:true}),!o.signal.aborted&&(c.set(a,p),r?.(),await new Promise(m=>{if(o.signal.aborted){m();return}o.signal.addEventListener("abort",()=>m(),{once:true});}));}};function Wr(t){let e=t.trim().toLowerCase();if(!e.startsWith("http://")&&!e.startsWith("https://"))throw new Error(`MCP client: url must be HTTP or HTTPS. Stdio is not supported in routes; register stdio clients via mcpPlugin({ clients: { name: { command, args } } }). Got: "${t.slice(0,50)}${t.length>50?"...":""}"`)}function zr(t,e){if(!t.serverId||!e)return;let o=e.getStore(M)?.get(t.serverId);if(!(o&&typeof o=="object"&&"transport"in o))return o}function Jr(t,e){if(t.url)return Wr(t.url),{url:t.url,auth:t.auth};if(t.serverId&&!e)throw new Error(`MCP client: serverId "${t.serverId}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${String(M)}" can be read.`);if(t.serverId&&e){let n=zr(t,e);if(!n)throw new Error(`MCP client: serverId "${t.serverId}" not found in context store. Register it with context store key "${String(M)}".`);let o=typeof n=="string"?n:n.url,r=t.auth??(typeof n=="object"&&"auth"in n?n.auth:void 0);return {url:o,auth:r}}throw new Error("MCP client: either url or serverId must be provided in McpClientOptions.")}var tt=t=>typeof t.body=="object"&&t.body!==null?t.body:{input:t.body},ye=class{constructor(e){this.options=e;if(this[se]=true,!e.url&&!e.serverId)throw new Error("MCP client: either url or serverId must be provided in McpClientOptions.");if(e.url&&e.serverId)throw new Error("MCP client: cannot provide both url and serverId. Use either url for direct HTTP or serverId for registered servers.")}options;adapterId="routecraft.adapter.mcp";async send(e){let n=routecraft.getExchangeContext(e),o=this.options.tool??(typeof e.body=="object"&&e.body!==null&&"tool"in e.body&&typeof e.body.tool=="string"?e.body.tool:void 0);if(!o)throw new Error("MCP client: tool name required. Set options.tool or exchange.body.tool.");let i=(this.options.args??tt)(e);if(this.options.serverId){if(!n)throw new Error(`MCP client: serverId "${this.options.serverId}" requires a context to resolve. Ensure the exchange has context (e.g. from a route).`);let d=Yr(n,this.options.serverId),c=await qe(n,this.options.serverId,o,i);return c&&typeof c=="object"&&(c.metadata={toolName:o,transport:d,serverId:this.options.serverId}),c}let{url:a,auth:s}=Jr(this.options,n),l=await kt(a,o,i,s);return l&&typeof l=="object"&&(l.metadata={toolName:o,url:a,transport:"http"}),l}getMetadata(e){return e&&typeof e=="object"&&"metadata"in e?e.metadata:{toolName:"unknown",transport:"unknown"}}};function Yr(t,e){let o=t.getStore(M)?.get(e);return o&&typeof o=="object"&&"transport"in o&&o.transport==="stdio"?"stdio":"http"}function we(t,e){if(typeof t=="object"&&t!==null&&("url"in t||"serverId"in t)){let n=t;if(typeof n.auth?.token=="string"&&n.auth.token.trim().length===0)throw new TypeError("mcp(): auth.token must be a non-empty string when provided");if(Array.isArray(n.auth?.token)){if(n.auth.token.length===0)throw new TypeError("mcp(): auth.token array must not be empty");for(let o=0;o<n.auth.token.length;o++){let r=n.auth.token[o];if(typeof r!="string"||r.trim().length===0)throw new TypeError(`mcp(): auth.token[${o}] must be a non-empty string`)}}return routecraft.tagAdapter(new ye(n),we,routecraft.factoryArgs(t,e))}if(typeof t=="string"&&t.includes(":")){let n=t.indexOf(":"),o=t.slice(0,n),r=t.slice(n+1),i={serverId:o,tool:r};return e!==void 0&&typeof e=="object"&&"args"in e&&e.args!==void 0&&(i.args=e.args),routecraft.tagAdapter(new ye(i),we,routecraft.factoryArgs(t,e))}if(typeof t=="string")throw routecraft.rcError("RC5003",void 0,{message:`mcp(${JSON.stringify(t)}) is not a valid call: a bare string without ":" is neither a client shorthand nor source options`,suggestion:"Use .from(mcp()) for a source (tool name comes from .id()), .to(mcp({ url, tool })) for a remote server, .to(mcp('server:tool')) for a registered shorthand, or direct('name') for in-process dispatch."});return routecraft.tagAdapter(new et(t??{}),we,routecraft.factoryArgs(t,e))}function Zr(t){if(typeof t=="function")return async n=>t(n);let e=t;return async n=>n===e.client_id?e:void 0}function Qr(t){if(!t)throw new TypeError("oauth: `verify` is required. Pass jwks(...), jwt(...), or a custom (token) => OAuthPrincipal function.");return typeof t=="function"?async e=>t(e):async e=>t.validator(e)}function Bn(t){if(!t.verify)throw new TypeError("oauth: `verify` is required. Pass jwks(...), jwt(...), or a custom (token) => OAuthPrincipal function.");let e=Qr(t.verify),n=Zr(t.client),o=typeof t.verify=="function"?void 0:t.verify.issuer;return {provider:"oauth",endpoints:t.endpoints,verifyAccessToken:e,getClient:n,...o!==void 0&&{issuer:o},...t.baseUrl!==void 0&&{baseUrl:t.baseUrl},...t.requiredScopes!==void 0&&{requiredScopes:t.requiredScopes}}}var nt;async function ni(){if(nt)return nt;try{return nt=(await import('yaml')).parse,nt}catch(t){throw t instanceof Error&&(t.message.includes("ERR_MODULE_NOT_FOUND")||t.message.includes("Cannot find module")||t.message.includes("Cannot find package"))&&t.message.includes("yaml")?new Error('The markdown loaders (agents() / skills()) require the "yaml" package. Install it with: bun add yaml'):t}}async function Et(t,e){let n=path.basename(e,path.extname(e));if(!t.startsWith("---"))return {path:e,filename:n,frontmatter:{},body:t.trim()};let o=t.indexOf(`
|
|
14
|
-
---`,3);if(o===-1)throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${e}": opened a YAML front-matter block with "---" but never closed it. Add a closing "---" line before the body.`});let r=t.slice(3,o).trim(),i=t.slice(o+4).trim(),a;try{r?a=(await ni())(r):a={};}catch(s){throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${e}": YAML front matter failed to parse. ${s.message}`})}if(a!==null&&typeof a!="object")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${e}": YAML front matter must parse to an object (got ${typeof a}).`});return {path:e,filename:n,frontmatter:a??{},body:i}}async function ot(t){let e=path.resolve(process.cwd(),t),n;try{n=fs.readFileSync(e,"utf-8");}catch(o){throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${t}" could not be read: ${o.message}`})}return Et(n,e)}async function rt(t,e={}){let n=path.resolve(process.cwd(),t),o;try{o=fs.statSync(n);}catch(i){throw routecraft.rcError("RC5003",void 0,{message:`Markdown directory "${t}" could not be opened: ${i.message}`})}if(!o.isDirectory())throw routecraft.rcError("RC5003",void 0,{message:`Markdown directory "${t}" is not a directory. Pass a path to a directory containing .md files.`});let r=[];for(let i of fs.readdirSync(n,{withFileTypes:true})){if(i.isFile()){if(path.extname(i.name).toLowerCase()!==".md")continue;r.push(await Et(fs.readFileSync(path.join(n,i.name),"utf-8"),path.join(n,i.name)));continue}if(i.isDirectory()&&e.sentinelFilename){let a=path.join(n,i.name,e.sentinelFilename),s;try{s=fs.statSync(a);}catch{continue}if(!s.isFile())continue;let l=await Et(fs.readFileSync(a,"utf-8"),a);l.filename=i.name,r.push(l);}}return r.sort((i,a)=>i.filename.localeCompare(a.filename)),r}function ae(t,e,n){if(typeof t!="string"||t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must be a non-empty string.`});return t}function Gn(t,e,n){if(t!==void 0){if(!Array.isArray(t))throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must be an array of strings.`});for(let o of t)if(typeof o!="string"||o.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must contain only non-empty strings.`});return t}}function qn(t,e,n){if(t!==void 0){if(typeof t!="boolean")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must be a boolean (true or false).`});return t}}function Kn(t,e,n){if(t!==void 0){if(typeof t!="number"||!Number.isFinite(t)||!Number.isInteger(t)||t<1)throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must be a positive integer.`});return t}}var Wn=new Set(["name","description","model","maxTurns","tools","principal"]);function oi(t,e,n,o){for(let u of Object.keys(e))if(!Wn.has(u))throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": frontmatter field "${u}" is not yet supported. Currently supported fields: ${[...Wn].sort().join(", ")}.`});let r=ae(e.name,"name",o);if(r!==t)throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": frontmatter "name" ("${r}") must match the filename ("${t}"). Rename one or the other.`});let i=ae(e.description,"description",o);if(n.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": agent body is empty. The body becomes the agent's system prompt; an empty system prompt is rejected at dispatch.`});let a=e.model;if(a!==void 0&&typeof a!="string")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": frontmatter "model" must be a string of the form "provider:model" (e.g. "anthropic:claude-sonnet-4-6").`});if(typeof a=="string"&&!a.includes(":"))throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": frontmatter "model" ("${a}") must use the full "provider:model" form. Bare model aliases like "sonnet" / "opus" / "haiku" are not yet supported by the markdown loader.`});let s=Kn(e.maxTurns,"maxTurns",o),l=Gn(e.tools,"tools",o),d=qn(e.principal,"principal",o),c={description:i,system:n};return a&&(c.model=a),s!==void 0&&(c.maxTurns=s),l!==void 0&&(c.tools=Je(l)),d!==void 0&&(c.principal=d),{name:r,agent:c}}function ri(t,e){if(!e)return t;let n={...t};return e.description!==void 0&&(n.description=e.description),e.model!==void 0&&(n.model=e.model),e.maxTurns!==void 0&&(n.maxTurns=e.maxTurns),e.tools!==void 0&&(n.tools=e.tools),e.principal!==void 0&&(n.principal=e.principal),e.blocks!==void 0&&(n.blocks=e.blocks),e.system!==void 0&&(n.system=e.system),n}async function zn(t,e={}){let n=Object.create(null),o=t.endsWith(".md")?[await ot(t)]:await rt(t);for(let r of o){let{name:i,agent:a}=oi(r.filename,r.frontmatter,r.body,r.path);n[i]=ri(a,e[i]);}for(let r of Object.keys(e))if(!Object.prototype.hasOwnProperty.call(n,r))throw routecraft.rcError("RC5003",void 0,{message:`agents("${t}"): override for "${r}" but no agent with that name was loaded from disk.`});return n}var it=class extends Error{name="SuspendError";reason;resumeChannel;constructor(e){super(e?.reason?`Agent suspended: ${e.reason}`:"Agent suspended pending external resumption."),e?.reason!==void 0&&(this.reason=e.reason),e?.resumeChannel!==void 0&&(this.resumeChannel=e.resumeChannel);}};async function Jn(t){if(!t||typeof t!="object")throw routecraft.rcError("RC5027",void 0,{message:"skills: options must be an object with at least { source }."});let{source:e,mode:n="progressive",lifetime:o}=t;if(typeof e!="string"||e.trim()==="")throw routecraft.rcError("RC5027",void 0,{message:'skills: "source" must be a non-empty path to a markdown file or directory.'});if(n!=="inject"&&n!=="progressive")throw routecraft.rcError("RC5027",void 0,{message:`skills: "mode" must be "inject" or "progressive" (got ${JSON.stringify(n)}).`});if(o!==void 0&&o!=="dispatch"&&o!=="context")throw routecraft.rcError("RC5027",void 0,{message:`skills: "lifetime" must be "dispatch" or "context" when present (got ${JSON.stringify(o)}).`});let r=e.endsWith(".md")?[await ot(e)]:await rt(e,{sentinelFilename:"SKILL.md"}),i=new Map,a={};for(let s of r){let l=ae(s.frontmatter.name,"name",s.path);if(l!==s.filename)throw routecraft.rcError("RC5027",void 0,{message:`skills: markdown file "${s.path}": frontmatter "name" ("${l}") must match the filename ("${s.filename}"). Rename one or the other.`});let d=ae(s.frontmatter.description,"description",s.path);if(s.body.trim()==="")throw routecraft.rcError("RC5027",void 0,{message:`skills: markdown file "${s.path}": skill body is empty. The body becomes the block's content; an empty body would not change the agent's behaviour.`});let c=i.get(l);if(c)throw routecraft.rcError("RC5026",void 0,{message:`skills("${e}"): duplicate skill name "${l}" loaded from both "${c}" and "${s.path}". Each skill name must be unique within a source; rename or remove one.`});i.set(l,s.path);let u={description:d,mode:n,value:s.body};o!==void 0&&(u.lifetime=o),a[l]=u;}return a}function Yn(t){if(typeof t!="string"||t.trim()==="")throw routecraft.rcError("RC5027",void 0,{message:'fromFile: "path" must be a non-empty string.'});return async()=>{let e=path.resolve(process.cwd(),t);try{return await promises.readFile(e,"utf-8")}catch(n){throw routecraft.rcError("RC5025",n,{message:`fromFile("${t}"): could not read file: ${n?.message??String(n)}`})}}}function li(t){let e=t.indexOf(":");if(e<1||e===t.length-1)throw new Error(`Embedding adapter: model id must be "providerId:modelName" (e.g. huggingface:all-MiniLM-L6-v2). Got: "${t}"`);return {providerId:t.slice(0,e),modelName:t.slice(e+1)}}function di(t,e){if(!e)throw new Error(`Embedding adapter: model id "${t}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so embedding providers can be read.`);let n=e.getStore(De);if(!n)throw new Error("Embedding provider not found: no providers registered. Add embeddingPlugin({ providers: { huggingface: {} } }) to your config.");let{providerId:o,modelName:r}=li(t),i=n.get(o);if(!i)throw new Error(`Embedding provider "${o}" not found. Register it with embeddingPlugin({ providers: { "${o}": {} } }).`);return {config:i,modelName:r}}function ci(t){return e=>{let n=t(e);return Array.isArray(n)?n.filter(Boolean).join(" | "):n}}var de=class{constructor(e,n){this.modelId=e;this.options=n;}modelId;adapterId="routecraft.adapter.embedding";options;mergedOptions(e){return {...e.getStore(_e),...this.options}}async send(e){let n=routecraft.getExchangeContext(e),{config:o,modelName:r}=di(this.modelId,n),i=this.mergedOptions(n),s=ci(i.using)(e);return {embedding:await Xt({config:o,modelName:r,text:s})}}};function Xn(t,e){return new de(t,e)}Object.defineProperty(exports,"jwks",{enumerable:true,get:function(){return routecraft.jwks}});Object.defineProperty(exports,"jwt",{enumerable:true,get:function(){return routecraft.jwt}});exports.AgentDestinationAdapter=G;exports.BRAND=jn;exports.EmbeddingDestinationAdapter=de;exports.LlmDestinationAdapter=ie;exports.MCP_LOCAL_TOOL_REGISTRY=E;exports.McpHeadersKeys=Oe;exports.McpServer=Y;exports.McpToolRegistry=X;exports.SuspendError=it;exports.agent=Ye;exports.agentPlugin=Xe;exports.agents=zn;exports.currentTime=Tn;exports.defaultArgs=tt;exports.directTool=We;exports.disposeEmbeddingPipelineCache=Ie;exports.embedding=Xn;exports.embeddingPlugin=Ne;exports.fromFile=Yn;exports.isMcpAdapter=Ur;exports.isOAuthAuth=Ae;exports.llm=Un;exports.llmPlugin=Pe;exports.mcp=we;exports.mcpPlugin=xe;exports.oauth=Bn;exports.randomUuid=Mn;exports.skills=Jn;exports.tools=Je;exports.validateWithSchema=qt;//# sourceMappingURL=index.cjs.map
|
|
13
|
+
`)}`}function He(t){return t.replace(/\s*[\r\n]+\s*/g," ").trim()}var E=Symbol.for("routecraft.adapter.fn.registry");var pe=Symbol.for("routecraft.ai.fn.deferred");function F(t){return typeof t=="object"&&t!==null&&pe in t&&t[pe]===true}function Qr(t){let e={...t};return t.audience&&(e.audience=[...t.audience]),t.scopes&&(e.scopes=[...t.scopes]),t.roles&&(e.roles=[...t.roles]),t.claims&&(e.claims=structuredClone(t.claims)),routecraft.isAuthentic(t)?routecraft.markAuthentic(e):e}var qn={type:"object",properties:{},additionalProperties:false},zn={"~standard":{version:1,vendor:"routecraft",validate(t){return t===null||typeof t!="object"||Array.isArray(t)||Object.keys(t).length>0?{issues:[{message:"Expected an empty object {}."}]}:{value:{}}},jsonSchema:{input:()=>qn,output:()=>qn}}};function Ge(t,e){if(typeof t!="string"||t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"directTool: routeId must be a non-empty string."});return {[pe]:true,kind:"direct",targetId:t,resolve(n,o){let r=ei(n,t,o),s=e?.description??r.description;if(typeof s!="string"||s.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`directTool: route "${t}" has no .description() and no override was provided (referenced as fn "${o}").`});let i=e?.input??r.input?.body;if(!i)throw routecraft.rcError("RC5003",void 0,{message:`directTool: route "${t}" has no .input(...) schema and no override was provided (referenced as fn "${o}").`});let a=r.tags,l=((u,c)=>ti(n,c,t,u));return {description:s,input:i,...a&&a.length>0?{tags:[...a]}:{},handler:l}}}}function ei(t,e,n){let o=t.capabilities(),r=o.find(s=>s.endpoint===e);if(!r){let s=o.map(i=>i.endpoint).sort();throw routecraft.rcError("RC5003",void 0,{message:`directTool: unknown direct route id "${e}" (referenced as fn "${n}"). `+(s.length>0?`Known route ids: ${s.join(", ")}.`:"No direct routes are registered in this context.")})}return r}async function ti(t,e,n,o){let r={};return e.correlationId&&(r[routecraft.HeadersKeys.CORRELATION_ID]=e.correlationId),e.principal&&(r[routecraft.HeadersKeys.AUTH_PRINCIPAL]=Qr(e.principal)),new routecraft.CraftClient(t).sendDirect(n,o,Object.keys(r).length>0?r:void 0)}function Yn(){return {description:"Returns the current UTC timestamp in ISO 8601 format.",input:zn,handler:()=>new Date().toISOString(),tags:["read-only","idempotent"]}}function Jn(){return {description:"Generates a fresh random UUID v4.",input:zn,handler:()=>crypto$1.randomUUID(),tags:["read-only"]}}var ni=`direct${v}`,Ke=`mcp${v}`;function oi(t,e,n){let o=se(n);if(o!==void 0)throw routecraft.rcError("RC5003",void 0,{message:`tools(): "${t}" resolves to the tool name "${n}", which the model provider will reject: ${o}.`,suggestion:`Route ids are unconstrained, but tool names must match ${O}. Expose this route under a tool-safe name instead: agentPlugin({ functions: { yourToolName: directTool("${e}") } }), then reference "yourToolName" in tools([...]).`})}var We=Symbol.for("routecraft.ai.tools.selection");function Q(t){return typeof t=="object"&&t!==null&&We in t&&t[We]===true}function qe(t){if(typeof t!="function"&&!Array.isArray(t))throw routecraft.rcError("RC5003",void 0,{message:"tools(): argument must be an array of ToolsItem or a (catalog) => ToolsItem[] builder."});return {[We]:true,resolve(e){let n=typeof t=="function"?ii(t,ri(e)):t,o=new Map;for(let r of n){if(typeof r=="string"){if(Qn(r)&&!Xn(e,r)){for(let l of eo(e,r,void 0))o.set(l.name,l);continue}let a=Zn(e,r,void 0);o.set(a.name,a);continue}if(r===null||typeof r!="object"||!("name"in r))throw routecraft.rcError("RC5003",void 0,{message:"tools(): each item must be a string or { name, guard?, description? }."});if(typeof r.name!="string"||r.name.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"tools(): { name } must be a non-empty string."});if(Qn(r.name)&&!Xn(e,r.name)){if(r.description!==void 0)throw routecraft.rcError("RC5003",void 0,{message:`tools(): { name: "${r.name}", description } is not supported for MCP tools. The MCP server is the source of truth for description and schema; do not override.`});for(let a of eo(e,r.name,r.guard))o.set(a.name,a);continue}if(r.description!==void 0&&(typeof r.description!="string"||r.description.trim()===""))throw routecraft.rcError("RC5003",void 0,{message:`tools(): { name: "${r.name}", description } must be a non-empty string when present.`});let s=Zn(e,r.name,r.guard),i=r.description!==void 0?{...s,description:r.description}:s;o.set(i.name,i);}return [...o.values()]}}}function ri(t){let e=[],n=t.getStore(E);if(n)for(let[i,a]of n)if(F(a))e.push(Object.freeze({name:i}));else {let l=a.tags&&a.tags.length>0?Object.freeze([...a.tags]):void 0;e.push(Object.freeze({name:i,description:a.description,...l!==void 0?{tags:l}:{}}));}let o=[];for(let i of t.capabilities()){let a=i.tags&&i.tags.length>0?Object.freeze([...i.tags]):void 0;o.push(Object.freeze({id:i.endpoint,...i.description?{description:i.description}:{},...a!==void 0?{tags:a}:{}}));}let r=[],s=t.getStore(k);if(s)for(let i of s.getTools()){let a=i.tags&&i.tags.length>0?Object.freeze([...i.tags]):void 0;r.push(Object.freeze({server:i.source,tool:i.name,...i.description?{description:i.description}:{},...a!==void 0?{tags:a}:{}}));}return Object.freeze({fns:Object.freeze(e),routes:Object.freeze(o),mcp:Object.freeze(r)})}function ii(t,e){let n;try{n=t(e);}catch(o){throw routecraft.rcError("RC5003",o,{message:`tools(builder): builder threw: ${o?.message??String(o)}`})}if(!Array.isArray(n))throw routecraft.rcError("RC5003",void 0,{message:`tools(builder): builder must return an array of ToolsItem (got ${typeof n}).`});return n}function Xn(t,e){return t.getStore(E)?.has(e)??false}function Zn(t,e,n){if(typeof e!="string"||e.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"tools(): tool name must be a non-empty string."});let r=t.getStore(E)?.get(e);if(r)return si(t,e,r,n);let s=/^Direct\((.*)\)$/.exec(e);if(s){let a=s[1].trim();if(a==="")throw routecraft.rcError("RC5003",void 0,{message:`tools(): "${e}" has an empty route id; use "Direct(<routeId>)".`});let l=`${ni}${a}`;oi(e,a,l);let c=Ge(a).resolve(t,l);return xt(l,c,n,{kind:"direct",routeId:a})}let i=di(t);throw routecraft.rcError("RC5003",void 0,{message:`tools(): unknown tool "${e}". `+(i.length>0?`Available: ${i.join(", ")}.`:"No fns or direct routes are registered in this context.")})}function si(t,e,n,o){if(F(n)){let r=n.resolve(t,e);if(n.kind==="direct")return xt(e,r,o,{kind:"direct",routeId:n.targetId});{let s=n.kind;throw routecraft.rcError("RC5003",void 0,{message:`tools(): fn "${e}" has an unsupported deferred kind "${String(s)}", so it carries no tool-policy provenance and cannot be resolved.`})}}return xt(e,n,o,{kind:"fn",id:e})}function xt(t,e,n,o){return {name:t,description:e.description,input:e.input,...e.tags&&e.tags.length>0?{tags:e.tags}:{},...n?{guard:n}:{},source:o,handler:e.handler}}function Qn(t){return t.startsWith(Ke)?true:t.startsWith("MCP(")&&t.endsWith(")")}function ai(t){if(t.startsWith("MCP(")&&t.endsWith(")")){let e=t.slice(4,-1).trim(),n=e.indexOf(":"),o=n===-1?e:e.slice(0,n).trim(),r=n===-1?"*":e.slice(n+1).trim();if(o===""||r==="")throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${t}" must use "MCP(server:tool)" or "MCP(server)"; got an empty server or tool segment.`});return {clientName:o,toolName:r}}if(t.startsWith(Ke)){let e=t.slice(Ke.length),n=e.indexOf(v),o=n===-1?e:e.slice(0,n),r=n===-1?"*":e.slice(n+v.length);if(o.trim()===""||r.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${t}" must use "mcp__server__tool" or "mcp__server"; got an empty server or tool segment.`});return {clientName:o,toolName:r}}throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${t}" must use "MCP(server:tool)", "MCP(server)", or the raw "mcp__server__tool" form.`})}function eo(t,e,n){let{clientName:o,toolName:r}=ai(e),s=t.getStore(k);if(!s)throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${e}" but no MCP_TOOL_REGISTRY is present. Install mcpPlugin (defineConfig.mcp) so external clients populate the registry.`});let i=s.getToolsByServer(o);if(i.length===0){let u=ci(s);throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${e}" but client "${o}" has no registered tools. `+(u.length>0?`Known MCP clients: ${u.map(c=>`"${c}"`).join(", ")}.`:"No MCP clients are registered in this context.")})}if(r==="*")return i.map(u=>to(t,s,u,n)).filter(u=>u!==void 0);let a=i.find(u=>u.name===r);if(!a){let u=i.map(c=>c.name).sort();throw routecraft.rcError("RC5003",void 0,{message:`tools(): MCP reference "${e}" but tool "${r}" is not registered under client "${o}". Known tools on "${o}": ${u.map(c=>`"${c}"`).join(", ")}.`})}let l=to(t,s,a,n);return l===void 0?[]:[l]}function to(t,e,n,o){let r=(d,p,m)=>{e.shouldReport(d)&&t.logger.warn(p,m);};if(!Re(n.source))return r(`mcp-server-separator:${n.source}`,{server:n.source},`MCP client name is empty, contains "${v}", or ends with "_", which makes the generated tool name ambiguous to parse and able to collide with another client; dropping its tools from the agent's tool list. Rename the client in mcpPlugin({ clients }).`);let s=`${Ke}${n.source}${v}${n.name}`,i=se(s);if(i!==void 0)return r(`mcp-tool-name:${s}`,{server:n.source,tool:n.name,toolName:s},`MCP tool name is not usable as a provider tool name (${i}); dropping it from the agent's tool list. Expose it through a capability under a tool-safe name if the agent needs it.`);let a=n.description&&n.description.trim()!==""?n.description:`MCP tool "${n.name}" on client "${n.source}".`,l=li(n.inputSchema),u=async d=>{if(d==null||typeof d!="object"||Array.isArray(d))throw routecraft.rcError("RC5003",void 0,{message:`mcp tool "${s}" expects an object argument; received ${d===null?"null":Array.isArray(d)?"array":typeof d}.`});let p=d;return Ae(t,n.source,n.name,p)},c={name:s,description:a,input:l,source:{kind:"mcp",server:n.source,tool:n.name,...n.annotations?{annotations:n.annotations}:{}},handler:u};return n.tags&&n.tags.length>0&&(c.tags=[...n.tags]),o&&(c.guard=o),c}function li(t){return {"~standard":{version:1,vendor:"routecraft",validate(e){return {value:e}},jsonSchema:{input:()=>t,output:()=>t}}}}function ci(t){let e=new Set;for(let n of t.getTools())e.add(n.source);return [...e].sort()}function di(t){let e=[...(t.getStore(E)??new Map).keys()],n=t.capabilities().map(o=>`Direct(${o.endpoint})`);return [...e,...n].sort()}function Ot(t){if(typeof t.system=="string"){if(t.system.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "system" is required and must be a non-empty string (or a function that returns one).'})}else if(typeof t.system!="function")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "system" must be a string or a function (exchange) => string.'});if(t.user!==void 0&&typeof t.user!="string"&&typeof t.user!="function")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "user" must be a string or a function (exchange) => string when present.'});if(t.model!==void 0){if(typeof t.model!="string"||t.model.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "model" must be a non-empty "providerId:modelName" string when present.'});try{N(t.model);}catch{throw routecraft.rcError("RC5003",void 0,{message:`Agent: "model" string must be in "providerId:modelName" form (e.g. ollama:llama3). Got: "${t.model}"`})}}if(t.tools!==void 0&&!Q(t.tools))throw routecraft.rcError("RC5003",void 0,{message:'Agent: "tools" must be the result of tools([...]).'});if(t.principal!==void 0&&typeof t.principal!="boolean"&&typeof t.principal!="function")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "principal" must be a boolean or a function (principal, exchange) => string when present.'});if(t.output!==void 0){if(t.output===null||typeof t.output!="object")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "output" must be a Standard Schema (Zod/Valibot/ArkType/etc.).'});if(typeof t.output["~standard"]?.validate!="function")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "output" must be a Standard Schema (Zod/Valibot/ArkType/etc.).'})}t.blocks!==void 0&&Et(t.blocks);}function Et(t,e){let n={seenNames:new Set,seenObjects:new WeakSet,...e!==void 0?{defaultsLabel:e}:{}};oo(t,"",n);}function oo(t,e,n){if(t===null||typeof t!="object"||Array.isArray(t))throw routecraft.rcError("AI1003",void 0,{message:'Agent: "blocks" must be a Record<string, BlockBody | Blocks | false>.'});if(n.seenObjects.has(t))throw Ct(e);n.seenObjects.add(t);let o=0;for(let[r,s]of Object.entries(t)){let i=e?`${e}${Tt}${r}`:r;if(r.trim()==="")throw routecraft.rcError("AI1002",void 0,{message:"Agent block: block name must be a non-empty string."});if(r.startsWith(_)||i.startsWith(_))throw routecraft.rcError("AI1002",void 0,{message:`Agent block "${i}": names starting with "${_}" are reserved for synthetic block tools. Rename the block or a parent group.`});if(s===false){if(n.defaultsLabel!==void 0)throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: "${n.defaultsLabel}.${i}" cannot be false. "false" is the per-agent removal sentinel; defaults cannot remove themselves. Drop the entry or replace it with a BlockBody.`});continue}if(s===null||typeof s!="object")throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${i}": value must be a BlockBody object (with mode and value), a nested Blocks group, or "false" to remove a default.`});if(vt(s)){let l=s.value;if(typeof l=="string"||typeof l=="function")throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${i}": "mode" must be "inject" or "progressive" (got ${JSON.stringify(s.mode)}).`});let u=oo(s,i,n);if(u===0)throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${i}": a nested group must contain at least one block (got an empty group or only "false" members).`});o+=u;continue}if(n.seenNames.has(i))throw bt(i);n.seenNames.add(i),o+=1;let a=s;if(a.mode!=="inject"&&a.mode!=="progressive")throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${i}": "mode" must be "inject" or "progressive" (got ${JSON.stringify(a.mode)}).`});if(a.mode==="progressive"&&(typeof a.description!="string"||a.description.trim()===""))throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${i}": progressive-mode blocks require a non-empty "description" so the model can decide whether to load.`});if(a.mode==="progressive"){if(!Rt.test(i))throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${i}": a progressive block becomes the loader tool "${I}${i}", so its flattened name must match ${Rt.source} (letters, digits, "_", "-"). Rename the block or its parent group.`});let l=`${I}${i}`;if(l.length>G)throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${i}": the loader tool name "${l}" is ${l.length} characters, over the provider limit of ${G}. Shorten the block name or its parent group.`})}if(a.lifetime!==void 0&&a.lifetime!=="dispatch"&&a.lifetime!=="context")throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${i}": "lifetime" must be "dispatch" or "context" when present (got ${JSON.stringify(a.lifetime)}).`});if(typeof a.value!="string"&&typeof a.value!="function")throw routecraft.rcError("AI1003",void 0,{message:`Agent block "${i}": "value" must be a string or a function returning a string.`})}return n.seenObjects.delete(t),o}function ze(t,e){if(typeof t=="string"){if(t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"Agent: name must be a non-empty string."});return routecraft.tagAdapter(new B({kind:"by-name",name:t,...e?{perCall:e}:{}}),ze,e?routecraft.factoryArgs(t,e):routecraft.factoryArgs(t))}return Ot(t),routecraft.tagAdapter(new B({kind:"inline",options:t}),ze,routecraft.factoryArgs(t))}function ro(t,e){if(e===null||typeof e!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" entry must be an object with description, input, and handler.`});if(typeof e.description!="string"||e.description.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" is missing a non-empty "description".`});if(e.input===null||typeof e.input!="object"||typeof e.input["~standard"]!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "input" is required and must be a Standard Schema value (Zod/Valibot/ArkType/etc.).`});if(typeof e.input["~standard"]?.validate!="function")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "input" must be a Standard Schema with a callable validate.`});if(typeof e.handler!="function")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "handler" is required and must be a function.`});if(e.tags!==void 0){if(!Array.isArray(e.tags))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "tags" must be an array of non-empty strings.`});for(let o=0;o<e.tags.length;o++){let r=e.tags[o];if(typeof r!="string"||r.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "tags" must contain only non-empty strings.`});e.tags[o]=r.trim();}}}function ui(t,e){if(typeof e.description!="string"||e.description.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${t}" is missing a non-empty "description". Registered agents carry their own description because they are not backed by a route.`});Ot(e);}function Ye(t={}){let e=t.agents??{},n=t.functions??{},o=mi(t.defaultOptions),r=fi(t.toolPolicy);return {apply(s){let i=s.getStore(D),a=i??new Map;for(let[c,d]of Object.entries(e)){if(c.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"agentPlugin: agent id must be a non-empty string."});if(d===null||typeof d!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${c}" entry must be an object with description, model, and system.`});if(d.tools!==void 0&&!Q(d.tools))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${c}" "tools" must be the result of tools([...]).`});if(ui(c,d),a.has(c))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: duplicate agent id "${c}". Each agent id must be unique within a context.`});a.set(c,d);}i||s.setStore(D,a);let l=s.getStore(E),u=l??new Map;for(let[c,d]of Object.entries(n)){if(c.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"agentPlugin: fn id must be a non-empty string."});let p=se(c);if(p!==void 0)throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn id "${c}" is not usable as a tool name: ${p}.`,suggestion:`A fn id reaches the model provider verbatim as the tool name, so it must match ${O}. Rename the fn.`});if(d===null||typeof d!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${c}" entry must be an object with description, input, and handler.`});if(F(d)||ro(c,d),u.has(c))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: duplicate fn id "${c}". Each fn id must be unique within a context.`});u.set(c,d);}if(l||s.setStore(E,u),o!==void 0){let c=s.getStore(Z),d=gi(c,o);s.setStore(Z,d);}if(r!==void 0){let c=s.getStore(ue);c?c.push(r):s.setStore(ue,[r]);}pi(s,e,n);}}}function pi(t,e,n){let o=Object.entries(e),r=Object.entries(n);o.length===0&&r.length===0||t.once("context:started",()=>{for(let[s,i]of o)t.emit("agent:registered",{agentId:s,description:i.description,...typeof i.model=="string"&&{model:i.model},source:"registered"});for(let[s,i]of r){let a=F(i)?void 0:i;t.emit("agent:tool:registered",{toolName:s,...a&&{description:a.description},...a&&Array.isArray(a.tags)&&a.tags.length>0&&{tags:a.tags},source:"registered"});}});}function mi(t){if(t!==void 0){if(t===null||typeof t!="object"||Array.isArray(t))throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions" must be an object with optional "model" / "tools".'});if(t.model!==void 0){if(typeof t.model!="string"||t.model.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions.model" must be a non-empty "providerId:modelName" string.'});try{N(t.model);}catch{throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: "defaultOptions.model" must be in "providerId:modelName" form (e.g. anthropic:claude-opus-4-7). Got: "${t.model}"`})}}if(t.tools!==void 0&&!Q(t.tools))throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions.tools" must be the result of tools([...]).'});return t.blocks!==void 0&&Et(t.blocks,"defaultOptions.blocks"),t}}function fi(t){if(t===void 0)return;if(t===null||typeof t!="object"||Array.isArray(t))throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "toolPolicy" must be an object carrying a rule for each of "fn" / "direct" / "mcp".'});let e=Gn,n=e.filter(o=>!Object.prototype.hasOwnProperty.call(t,o));if(n.length>0)throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: "toolPolicy" is missing a rule for ${n.map(o=>`"${o}"`).join(", ")}.`,suggestion:"A policy is an allowlist, so an unlisted kind is denied. Decide each kind explicitly (`true`, `false`, or a predicate) rather than omitting it, so a partial policy cannot silently strip tools you meant to keep."});for(let o of Object.keys(t)){if(!e.includes(o))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: "toolPolicy.${o}" is not a known tool kind. Valid keys: ${e.join(", ")}.`,suggestion:'Block loader tools are framework machinery and are deliberately not policy-governed, so there is no "block" key.'});let r=t[o];if(typeof r!="boolean"&&typeof r!="function")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: "toolPolicy.${o}" must be a boolean or a (tool, ctx) => boolean predicate (got ${typeof r}).`})}return {...t}}function gi(t,e){if(!t)return {...e};if(e.model!==void 0&&t.model!==void 0)throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions.model" is already set on this context. A context can have only one default model.'});if(e.tools!==void 0&&t.tools!==void 0)throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "defaultOptions.tools" is already set on this context. Combine selectors into a single tools([...]) call.'});let n;if((t.blocks!==void 0||e.blocks!==void 0)&&(n={...t.blocks??{}},e.blocks!==void 0))for(let[o,r]of Object.entries(e.blocks)){if(Object.prototype.hasOwnProperty.call(n,o))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: "defaultOptions.blocks" already contains "${o}" from a previous install. Each block name may be defined once across all installs.`});n[o]=r;}return {...t,...e.model!==void 0?{model:e.model}:{},...e.tools!==void 0?{tools:e.tools}:{},...n!==void 0?{blocks:n}:{}}}routecraft.registerConfigApplier("llm",t=>ve(t));routecraft.registerConfigApplier("mcp",t=>Oe(t));routecraft.registerConfigApplier("embedding",t=>_e(t));routecraft.registerConfigApplier("agent",t=>Ye(t));var St="https://routecraft.dev/docs/reference/errors";routecraft.registerErrorCodes("AI",{AI1001:{category:"Adapter",message:"Agent block resolution failed",suggestion:"A block resolver threw or returned a non-string. Check the resolver function for the named block; inject-mode failures abort the dispatch, progressive-mode failures surface back to the model as a loader-tool error.",docs:`${St}#ai1001`,retryable:false},AI1002:{category:"Adapter",message:"Agent block name collision",suggestion:"A block name duplicates another block, collides with a user tool, or starts with the reserved `_block_` prefix used by synthetic loader tools. Rename the block (or the tool) so every name in the agent's surface is unique.",docs:`${St}#ai1002`,retryable:false},AI1003:{category:"Adapter",message:"Agent block misconfigured",suggestion:"A block is missing required fields or has an invalid shape: every block needs a non-empty `name`, a `mode` of `inject` or `progressive`, and a string-or-function `value`. Progressive blocks additionally require a non-empty `description` so the model can decide whether to load them.",docs:`${St}#ai1003`,retryable:false}},"@routecraft/ai");var io={McpAdapter:Symbol.for("routecraft.ai.McpAdapter")};function yi(t,e){return typeof t=="object"&&t!==null&&t[e]===true}function wi(t){return yi(t,io.McpAdapter)}async function vi(t,e){let n;try{n=JSON.parse(t);}catch{return}let o=e["~standard"];if(!o?.validate)return;let r=o.validate(n);if(r instanceof Promise&&(r=await r),!(r&&typeof r=="object"&&"issues"in r&&r.issues))return r&&typeof r=="object"&&"value"in r?r.value:void 0}var Ri=0,bi=1024,ee=class{constructor(e,n={}){this.modelId=e;this.options=n;}modelId;adapterId="routecraft.adapter.llm";options;mergedOptions(e){let n=e.getStore(ie);return {temperature:Ri,maxTokens:bi,...n,...this.options}}async fetch(e){let n=routecraft.getExchangeContext(e),{config:o,modelName:r}=Ne(this.modelId,n),s=this.mergedOptions(n),i=$(s.system,e),a=$(s.user,e)||$e(e),l={temperature:s.temperature,maxTokens:s.maxTokens};s.topP!==void 0&&(l.topP=s.topP),s.frequencyPenalty!==void 0&&(l.frequencyPenalty=s.frequencyPenalty),s.presencePenalty!==void 0&&(l.presencePenalty=s.presencePenalty);let u=s.output!==void 0?Fe(s.output):void 0,c=await Be({config:o,modelId:r,options:l,system:i,user:a,output:u});if(c.output===void 0&&c.text&&s.output!==void 0){let d=await vi(c.text,s.output);d!==void 0&&(c.output=d);}return c}getMetadata(e){let n=e,{providerId:o}=N(this.modelId),r={model:this.modelId,provider:o};return n.usage&&(n.usage.inputTokens!==void 0&&(r.inputTokens=n.usage.inputTokens),n.usage.outputTokens!==void 0&&(r.outputTokens=n.usage.outputTokens)),r}};function Lt(t,e){return routecraft.tagAdapter(new ee(t,e),Lt,routecraft.factoryArgs(t,e))}var te=Symbol.for("routecraft.mcp.adapter");function ki(t){if(!L.test(t))throw routecraft.rcError("RC5003",void 0,{message:`Invalid MCP tool name "${t}"`,suggestion:"MCP tool names must match /^[A-Za-z0-9_-]{1,64}$/ for client interoperability (OpenAI, Anthropic, etc.). Use alphanumerics, underscore, or hyphen in the route's .id()."})}var Ze=class{adapterId="routecraft.adapter.mcp";options;constructor(e={}){this[te]=true,this.options=e;}async subscribe(e){let{context:n,meta:o}=e;if(!o?.routeId)throw routecraft.rcError("RC5003",void 0,{message:"McpSourceAdapter requires a route id from the engine (missing SourceMeta.routeId)",suggestion:"MCP source adapters take their tool name from the route id. Call .id('tool-name') on the route before .from(mcp(...))."});let r=o.routeId;ki(r);let s=o.discovery,i=s?.description;if(typeof i!="string"||i.length===0)throw routecraft.rcError("RC5003",void 0,{message:`MCP route "${r}" requires a description`,suggestion:"Set .description('...') on the route builder before .from(mcp()); the MCP protocol requires a non-empty description for each tool."});if(n.getStore(ae)!==true)throw new Error("MCP plugin required: routes using .from(mcp(...)) require the MCP plugin. Add mcpPlugin() to your config: plugins: [mcpPlugin()].");let l=n.getStore(P);if(l||(l=new Map,n.setStore(P,l)),l.has(r))throw routecraft.rcError("RC5003",void 0,{message:`Duplicate MCP tool endpoint "${r}": another .from(mcp(...)) route already registered this endpoint in the same context`,suggestion:"Each MCP tool endpoint must be unique within a context. Rename one of the mcp() routes to a different route id."});let c={endpoint:r,description:i,handler:async p=>e.emit({message:p.body,headers:p.headers})};s?.title!==void 0&&(c.title=s.title),s?.input!==void 0&&(c.input=s.input),s?.output!==void 0&&(c.output=s.output);let d=Pe(en(s?.tags),this.options.annotations);d!==void 0&&(c.annotations=d),this.options.icons!==void 0&&(c.icons=this.options.icons),e.signal.addEventListener("abort",()=>{n.getStore(P)?.delete(r);},{once:true}),!e.signal.aborted&&(l.set(r,c),e.ready(),await new Promise(p=>{if(e.signal.aborted){p();return}e.signal.addEventListener("abort",()=>p(),{once:true});}));}};function xi(t){let e=t.trim().toLowerCase();if(!e.startsWith("http://")&&!e.startsWith("https://"))throw new Error(`MCP client: url must be HTTP or HTTPS. Stdio is not supported in routes; register stdio clients via mcpPlugin({ clients: { name: { command, args } } }). Got: "${t.slice(0,50)}${t.length>50?"...":""}"`)}function Mi(t,e){if(!t.serverId||!e)return;let o=e.getStore(A)?.get(t.serverId);if(!(o&&typeof o=="object"&&"transport"in o))return o}function Oi(t,e){if(t.url)return xi(t.url),{url:t.url,auth:t.auth};if(t.serverId&&!e)throw new Error(`MCP client: serverId "${t.serverId}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${String(A)}" can be read.`);if(t.serverId&&e){let n=Mi(t,e);if(!n)throw new Error(`MCP client: serverId "${t.serverId}" not found in context store. Register it with context store key "${String(A)}".`);let o=typeof n=="string"?n:n.url,r=t.auth??(typeof n=="object"&&"auth"in n?n.auth:void 0);return {url:o,auth:r}}throw new Error("MCP client: either url or serverId must be provided in McpClientOptions.")}var Qe=t=>typeof t.body=="object"&&t.body!==null?t.body:{input:t.body},me=class{constructor(e){this.options=e;if(this[te]=true,!e.url&&!e.serverId)throw new Error("MCP client: either url or serverId must be provided in McpClientOptions.");if(e.url&&e.serverId)throw new Error("MCP client: cannot provide both url and serverId. Use either url for direct HTTP or serverId for registered servers.")}options;adapterId="routecraft.adapter.mcp";async fetch(e){let n=routecraft.getExchangeContext(e),o=this.options.tool??(typeof e.body=="object"&&e.body!==null&&"tool"in e.body&&typeof e.body.tool=="string"?e.body.tool:void 0);if(!o)throw new Error("MCP client: tool name required. Set options.tool or exchange.body.tool.");let s=(this.options.args??Qe)(e);if(this.options.serverId){if(!n)throw new Error(`MCP client: serverId "${this.options.serverId}" requires a context to resolve. Ensure the exchange has context (e.g. from a route).`);let u=Ei(n,this.options.serverId),c=await Ae(n,this.options.serverId,o,s);return c&&typeof c=="object"&&(c.metadata={toolName:o,transport:u,serverId:this.options.serverId}),c}let{url:i,auth:a}=Oi(this.options,n),l=await Jt(i,o,s,a);return l&&typeof l=="object"&&(l.metadata={toolName:o,url:i,transport:"http"}),l}getMetadata(e){return e&&typeof e=="object"&&"metadata"in e?e.metadata:{toolName:"unknown",transport:"unknown"}}};function Ei(t,e){let o=t.getStore(A)?.get(e);return o&&typeof o=="object"&&"transport"in o&&o.transport==="stdio"?"stdio":"http"}function fe(t,e){if(typeof t=="object"&&t!==null&&("url"in t||"serverId"in t)){let n=t;if(typeof n.auth?.token=="string"&&n.auth.token.trim().length===0)throw new TypeError("mcp(): auth.token must be a non-empty string when provided");if(Array.isArray(n.auth?.token)){if(n.auth.token.length===0)throw new TypeError("mcp(): auth.token array must not be empty");for(let o=0;o<n.auth.token.length;o++){let r=n.auth.token[o];if(typeof r!="string"||r.trim().length===0)throw new TypeError(`mcp(): auth.token[${o}] must be a non-empty string`)}}return routecraft.tagAdapter(new me(n),fe,routecraft.factoryArgs(t,e))}if(typeof t=="string"&&t.includes(":")){let n=t.indexOf(":"),o=t.slice(0,n),r=t.slice(n+1),s={serverId:o,tool:r};return e!==void 0&&typeof e=="object"&&"args"in e&&e.args!==void 0&&(s.args=e.args),routecraft.tagAdapter(new me(s),fe,routecraft.factoryArgs(t,e))}if(typeof t=="string")throw routecraft.rcError("RC5003",void 0,{message:`mcp(${JSON.stringify(t)}) is not a valid call: a bare string without ":" is neither a client shorthand nor source options`,suggestion:"Use .from(mcp()) for a source (tool name comes from .id()), .to(mcp({ url, tool })) for a remote server, .to(mcp('server:tool')) for a registered shorthand, or direct('name') for in-process dispatch."});return routecraft.tagAdapter(new Ze(t??{}),fe,routecraft.factoryArgs(t,e))}function Li(t){return typeof t=="string"?t.trim().length>0:t.length>0&&t.every(e=>e.trim().length>0)}function Ii(t){let e=typeof t=="function"?async n=>t(n):async n=>t.validator(n);return async n=>{let o=await e(n);if(o.expiresAt===void 0)throw new TypeError("oauth: `verify` returned a principal with no `expiresAt`. A credential with no expiry never expires; populate it from the token's `exp` claim or introspection response.");return o}}function so(t){if(!t.verify)throw new TypeError("oauth: `verify` is required. Pass jwks(...), jwt(...), or a custom (token) => OAuthPrincipal function.");let e=t.issuer??(typeof t.verify=="function"?void 0:t.verify.issuer);if(e===void 0||!Li(e))throw new TypeError("oauth: a non-empty `issuer` is required. Pass the Authorization Server issuer explicitly, or use jwks(...) / jwt(...), which carry their own. Without it the RFC 9728 metadata document advertises no authorization server and clients cannot discover where to authenticate.");let n=t.clockToleranceSec??(typeof t.verify=="function"?void 0:t.verify.clockToleranceSec),o={validator:Ii(t.verify),issuer:e};return t.requiredScopes&&t.requiredScopes.length>0&&(o.requiredScopes=t.requiredScopes),n!==void 0&&(o.clockToleranceSec=n),o}var et;async function Di(){return et||(et=(await routecraft.loadOptionalPeer(()=>import('yaml'),{adapterName:"Markdown loader (agents() / skills())",packageName:"yaml"})).parse,et)}async function Dt(t,e){let n=path.basename(e,path.extname(e));if(!t.startsWith("---"))return {path:e,filename:n,frontmatter:{},body:t.trim()};let o=t.indexOf(`
|
|
14
|
+
---`,3);if(o===-1)throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${e}": opened a YAML front-matter block with "---" but never closed it. Add a closing "---" line before the body.`});let r=t.slice(3,o).trim(),s=t.slice(o+4).trim(),i;if(r){let a=await Di();try{i=a(r);}catch(l){throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${e}": YAML front matter failed to parse. ${l.message}`})}}else i={};if(i!==null&&typeof i!="object")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${e}": YAML front matter must parse to an object (got ${typeof i}).`});return {path:e,filename:n,frontmatter:i??{},body:s}}async function tt(t){let e=path.resolve(process.cwd(),t),n;try{n=fs.readFileSync(e,"utf-8");}catch(o){throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${t}" could not be read: ${o.message}`})}return Dt(n,e)}async function nt(t,e={}){let n=path.resolve(process.cwd(),t),o;try{o=fs.statSync(n);}catch(s){throw routecraft.rcError("RC5003",void 0,{message:`Markdown directory "${t}" could not be opened: ${s.message}`})}if(!o.isDirectory())throw routecraft.rcError("RC5003",void 0,{message:`Markdown directory "${t}" is not a directory. Pass a path to a directory containing .md files.`});let r=[];for(let s of fs.readdirSync(n,{withFileTypes:true})){if(s.isFile()){if(path.extname(s.name).toLowerCase()!==".md")continue;r.push(await Dt(fs.readFileSync(path.join(n,s.name),"utf-8"),path.join(n,s.name)));continue}if(s.isDirectory()&&e.sentinelFilename){let i=path.join(n,s.name,e.sentinelFilename),a;try{a=fs.statSync(i);}catch{continue}if(!a.isFile())continue;let l=await Dt(fs.readFileSync(i,"utf-8"),i);l.filename=s.name,r.push(l);}}return r.sort((s,i)=>s.filename.localeCompare(i.filename)),r}function ne(t,e,n){if(typeof t!="string"||t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must be a non-empty string.`});return t}function uo(t,e,n){if(t!==void 0){if(!Array.isArray(t))throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must be an array of strings.`});for(let o of t)if(typeof o!="string"||o.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must contain only non-empty strings.`});return t}}function po(t,e,n){if(t!==void 0){if(typeof t!="boolean")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must be a boolean (true or false).`});return t}}function mo(t,e,n){if(t!==void 0){if(typeof t!="number"||!Number.isFinite(t)||!Number.isInteger(t)||t<1)throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${n}": frontmatter field "${e}" must be a positive integer.`});return t}}var fo=new Set(["name","description","model","maxTurns","tools","principal"]),ji=new Set(["blocks","output"]);function Bi(t,e,n,o){for(let d of Object.keys(e)){if(ji.has(d))throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": frontmatter field "${d}" is override-only; YAML cannot express its value. Supply it via the override map instead: agents(path, { ${JSON.stringify(t)}: { ${d}: ... } }).`});if(!fo.has(d))throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": frontmatter field "${d}" is not yet supported. Currently supported fields: ${[...fo].sort().join(", ")}.`})}let r=ne(e.name,"name",o);if(r!==t)throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": frontmatter "name" ("${r}") must match the filename ("${t}"). Rename one or the other.`});let s=ne(e.description,"description",o);if(n.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": agent body is empty. The body becomes the agent's system prompt; an empty system prompt is rejected at dispatch.`});let i=e.model;if(i!==void 0&&typeof i!="string")throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": frontmatter "model" must be a string of the form "provider:model" (e.g. "anthropic:claude-sonnet-4-6").`});if(typeof i=="string"&&!i.includes(":"))throw routecraft.rcError("RC5003",void 0,{message:`Markdown file "${o}": frontmatter "model" ("${i}") must use the full "provider:model" form. Bare model aliases like "sonnet" / "opus" / "haiku" are not yet supported by the markdown loader.`});let a=mo(e.maxTurns,"maxTurns",o),l=uo(e.tools,"tools",o),u=po(e.principal,"principal",o),c={description:s,system:n};return i&&(c.model=i),a!==void 0&&(c.maxTurns=a),l!==void 0&&(c.tools=qe(l)),u!==void 0&&(c.principal=u),{name:r,agent:c}}function Fi(t,e){if(!e)return t;let n={...t};return e.description!==void 0&&(n.description=e.description),e.model!==void 0&&(n.model=e.model),e.maxTurns!==void 0&&(n.maxTurns=e.maxTurns),e.tools!==void 0&&(n.tools=e.tools),e.principal!==void 0&&(n.principal=e.principal),e.blocks!==void 0&&(n.blocks=e.blocks),e.output!==void 0&&(n.output=e.output),e.system!==void 0&&(n.system=e.system),n}async function go(t,e={}){let n=Object.create(null),o=t.endsWith(".md")?[await tt(t)]:await nt(t);for(let r of o){let{name:s,agent:i}=Bi(r.filename,r.frontmatter,r.body,r.path);n[s]=Fi(i,e[s]);}for(let r of Object.keys(e))if(!Object.prototype.hasOwnProperty.call(n,r))throw routecraft.rcError("RC5003",void 0,{message:`agents("${t}"): override for "${r}" but no agent with that name was loaded from disk.`});return n}var ot=class extends Error{name="SuspendError";reason;resumeChannel;constructor(e){super(e?.reason?`Agent suspended: ${e.reason}`:"Agent suspended pending external resumption."),e?.reason!==void 0&&(this.reason=e.reason),e?.resumeChannel!==void 0&&(this.resumeChannel=e.resumeChannel);}};async function ho(t){if(!t||typeof t!="object")throw routecraft.rcError("AI1003",void 0,{message:"skills: options must be an object with at least { source }."});let{source:e,mode:n="progressive",lifetime:o}=t;if(typeof e!="string"||e.trim()==="")throw routecraft.rcError("AI1003",void 0,{message:'skills: "source" must be a non-empty path to a markdown file or directory.'});if(n!=="inject"&&n!=="progressive")throw routecraft.rcError("AI1003",void 0,{message:`skills: "mode" must be "inject" or "progressive" (got ${JSON.stringify(n)}).`});if(o!==void 0&&o!=="dispatch"&&o!=="context")throw routecraft.rcError("AI1003",void 0,{message:`skills: "lifetime" must be "dispatch" or "context" when present (got ${JSON.stringify(o)}).`});let r=e.endsWith(".md")?[await tt(e)]:await nt(e,{sentinelFilename:"SKILL.md"}),s=new Map,i={};for(let a of r){let l=ne(a.frontmatter.name,"name",a.path);if(l!==a.filename)throw routecraft.rcError("AI1003",void 0,{message:`skills: markdown file "${a.path}": frontmatter "name" ("${l}") must match the filename ("${a.filename}"). Rename one or the other.`});let u=ne(a.frontmatter.description,"description",a.path);if(a.body.trim()==="")throw routecraft.rcError("AI1003",void 0,{message:`skills: markdown file "${a.path}": skill body is empty. The body becomes the block's content; an empty body would not change the agent's behaviour.`});let c=s.get(l);if(c)throw routecraft.rcError("AI1002",void 0,{message:`skills("${e}"): duplicate skill name "${l}" loaded from both "${c}" and "${a.path}". Each skill name must be unique within a source; rename or remove one.`});s.set(l,a.path);let d={description:u,mode:n,value:a.body};o!==void 0&&(d.lifetime=o),i[l]=d;}return i}function yo(t){if(typeof t!="string"||t.trim()==="")throw routecraft.rcError("AI1003",void 0,{message:'fromFile: "path" must be a non-empty string.'});return async()=>{let e=path.resolve(process.cwd(),t);try{return await promises.readFile(e,"utf-8")}catch(n){throw routecraft.rcError("AI1001",n,{message:`fromFile("${t}"): could not read file: ${n?.message??String(n)}`})}}}function Gi(t){let e=t.indexOf(":");if(e<1||e===t.length-1)throw new Error(`Embedding adapter: model id must be "providerId:modelName" (e.g. huggingface:all-MiniLM-L6-v2). Got: "${t}"`);return {providerId:t.slice(0,e),modelName:t.slice(e+1)}}function Ki(t,e){if(!e)throw new Error(`Embedding adapter: model id "${t}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so embedding providers can be read.`);let n=e.getStore(Le);if(!n)throw new Error("Embedding provider not found: no providers registered. Add embeddingPlugin({ providers: { huggingface: {} } }) to your config.");let{providerId:o,modelName:r}=Gi(t),s=n.get(o);if(!s)throw new Error(`Embedding provider "${o}" not found. Register it with embeddingPlugin({ providers: { "${o}": {} } }).`);return {config:s,modelName:r}}function Wi(t){return e=>{let n=t(e);return Array.isArray(n)?n.filter(Boolean).join(" | "):n}}var oe=class{constructor(e,n){this.modelId=e;this.options=n;}modelId;adapterId="routecraft.adapter.embedding";options;mergedOptions(e){return {...e.getStore(Ie),...this.options}}async fetch(e){let n=routecraft.getExchangeContext(e),{config:o,modelName:r}=Ki(this.modelId,n),s=this.mergedOptions(n),a=Wi(s.using)(e);return {embedding:await vn({config:o,modelName:r,text:a})}}};function jt(t,e){return routecraft.tagAdapter(new oe(t,e),jt,routecraft.factoryArgs(t,e))}Object.defineProperty(exports,"jwks",{enumerable:true,get:function(){return routecraft.jwks}});Object.defineProperty(exports,"jwt",{enumerable:true,get:function(){return routecraft.jwt}});exports.AgentEnricherAdapter=B;exports.BRAND=io;exports.EmbeddingEnricherAdapter=oe;exports.LlmEnricherAdapter=ee;exports.MCP_LOCAL_TOOL_REGISTRY=P;exports.McpHeadersKeys=be;exports.McpServer=q;exports.McpToolRegistry=z;exports.SuspendError=ot;exports.agent=ze;exports.agentPlugin=Ye;exports.agents=go;exports.currentTime=Yn;exports.defaultArgs=Qe;exports.directTool=Ge;exports.disposeEmbeddingPipelineCache=Se;exports.embedding=jt;exports.embeddingPlugin=_e;exports.fromFile=yo;exports.isMcpAdapter=wi;exports.llm=Lt;exports.llmPlugin=ve;exports.mcp=fe;exports.mcpPlugin=Oe;exports.oauth=so;exports.randomUuid=Jn;exports.skills=ho;exports.tools=qe;exports.validateWithSchema=yn;//# sourceMappingURL=index.cjs.map
|
|
15
15
|
//# sourceMappingURL=index.cjs.map
|