UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

1 lines 5.86 kB
import{isObject}from"#shared/guards.js";import{jsonSchema,tool}from"ai";import{passesToolFilter,resolveHeaders}from"#runtime/connections/mcp-client.js";import{HTTP_METHODS,operationDescription,operationName,uniqueName}from"#runtime/connections/openapi-operations.js";import{buildInputSchema,deref,derefSchema,isArray}from"#runtime/connections/openapi-schema.js";import{applySecurity,resolveSecurity}from"#runtime/connections/openapi-security.js";import{extractServerUrl,parseSpecDocument}from"#runtime/connections/openapi-spec.js";const SWAGGER_PARAMETER_SCHEMA_KEYS=[`default`,`enum`,`exclusiveMaximum`,`exclusiveMinimum`,`format`,`items`,`maximum`,`maxItems`,`maxLength`,`minimum`,`minItems`,`minLength`,`multipleOf`,`pattern`,`type`,`uniqueItems`];var OpenApiConnectionClient=class{#e;#t;#n;constructor(e){this.#n=e}async connect(){return this.#r()}async getToolMetadata(){return(await this.#r()).metadata}async getTools(){return(await this.#r()).tools}async executeTool(t,n){let r=await this.#r(),i=r.operations.get(t);if(i===void 0)throw Error(`Tool "${t}" not found in connection "${this.#n.connectionName}".`);return this.#f(i,r.baseUrl,isObject(n)?n:{})}async close(){this.#e=void 0,this.#t=void 0}async#r(){if(this.#t!==void 0)return this.#t;if(this.#e!==void 0)return this.#e;this.#e=this.#i();try{return this.#t=await this.#e,this.#t}catch(e){throw this.#e=void 0,e}}async#i(){let i=await this.#o(),a=this.#a(i),o=this.#s(i),s=this.#n.tools,c=s===void 0?o:o.filter(e=>passesToolFilter(e.toolName,s)),l=[],u=new Map,d={};for(let r of c)u.set(r.toolName,r),l.push({description:r.description,inputSchema:r.inputSchema,name:r.toolName}),d[r.toolName]=tool({description:r.description,inputSchema:jsonSchema(r.inputSchema),execute:async t=>this.#f(r,a,isObject(t)?t:{})});return{metadata:l,operations:u,tools:d,baseUrl:a}}#a(e){let t=this.#n.url;if(typeof t==`string`&&t.trim().length>0)return t;let n=extractServerUrl(e,this.#n.spec);if(n!==void 0)return n;throw Error(`OpenAPI connection "${this.#n.connectionName}" has no base URL: set "baseUrl" or ensure the document declares an absolute "servers" entry or Swagger "host".`)}async#o(){let t=this.#n.spec;if(t===void 0)throw Error(`OpenAPI connection "${this.#n.connectionName}" is missing its "spec" source.`);if(typeof t!=`string`)return t;let n;try{n=await fetch(t,{headers:{accept:`application/json, application/yaml, text/yaml, */*`}})}catch(e){throw Error(`OpenAPI connection "${this.#n.connectionName}" failed to fetch its spec from "${t}": ${String(e)}`)}if(!n.ok)throw Error(`OpenAPI connection "${this.#n.connectionName}" failed to fetch its spec from "${t}": HTTP ${n.status}.`);let r=await n.text(),i;try{i=parseSpecDocument(r)}catch(e){throw Error(`OpenAPI connection "${this.#n.connectionName}" spec at "${t}" could not be parsed as JSON or YAML: ${String(e)}`)}if(!isObject(i))throw Error(`OpenAPI connection "${this.#n.connectionName}" spec at "${t}" is not an OpenAPI document object.`);return i}#s(t){let n=t.paths;if(!isObject(n))return[];let r=[],i=new Set;for(let[u,d]of Object.entries(n)){if(!isObject(d))continue;let n=isArray(d.parameters)?d.parameters:[];for(let f of HTTP_METHODS){let a=d[f];if(!isObject(a))continue;let p=uniqueName(operationName(a,f,u),i),m=isArray(a.parameters)?a.parameters:[],h=[...n,...m],g=this.#c(t,h),_=this.#l(t,a.requestBody,h);r.push({toolName:p,method:f,pathTemplate:u,description:operationDescription(a),parameters:g,requestBody:_,inputSchema:buildInputSchema(g,_),security:resolveSecurity(t,a)})}}return r}#c(t,n){let r=[];for(let i of n){let n=isObject(i)?deref(t,i):i;if(!isObject(n))continue;let a=n.in;if(a!==`path`&&a!==`query`&&a!==`header`&&a!==`cookie`||typeof n.name!=`string`)continue;let o=this.#u(t,n);r.push({name:n.name,location:a,required:n.required===!0||a===`path`,schema:o,description:typeof n.description==`string`?n.description:void 0})}return r}#l(t,n,r=[]){if(isObject(n)){let r=deref(t,n);if(isObject(r)&&isObject(r.content)){let n=r.content,i=`application/json`in n?`application/json`:Object.keys(n)[0];if(i!==void 0){let a=n[i],o=isObject(a)&&isObject(a.schema)?derefSchema(t,a.schema):{};return{required:r.required===!0,contentType:i,schema:o}}}}return this.#d(t,r)}#u(t,n){if(isObject(n.schema))return derefSchema(t,n.schema);let r={};for(let e of SWAGGER_PARAMETER_SCHEMA_KEYS)n[e]!==void 0&&(r[e]=n[e]);return derefSchema(t,r)}#d(t,n){for(let r of n){let n=isObject(r)?deref(t,r):r;if(!isObject(n)||n.in!==`body`)continue;let i=isObject(n.schema)?derefSchema(t,n.schema):{};return{required:n.required===!0,contentType:`application/json`,schema:i}}}async#f(e,t,n){let r=await resolveHeaders(this.#n),a=e.pathTemplate,o=new URLSearchParams,s=[];for(let t of e.parameters){let e=n[t.name];e!=null&&(t.location===`path`?a=a.replace(`{${t.name}}`,encodeURIComponent(String(e))):t.location===`query`?appendQuery(o,t.name,e):t.location===`cookie`?s.push(`${t.name}=${encodeURIComponent(String(e))}`):r[t.name]=String(e))}if(applySecurity(e.security,this.#n,r,o,s),s.length>0){let e=r.cookie??r.Cookie;delete r.Cookie,r.cookie=[e,...s].filter(e=>!!e).join(`; `)}let c=new URL(joinPath(t,a));c.search=o.toString();let l;e.requestBody!==void 0&&n.body!==void 0&&(l=JSON.stringify(n.body),r[`content-type`]=e.requestBody.contentType);let u=await fetch(c,{method:e.method.toUpperCase(),headers:r,body:l});return{status:u.status,statusText:u.statusText,body:await readResponseBody(u)}}};function appendQuery(e,t,n){if(isArray(n)){for(let r of n)e.append(t,String(r));return}e.append(t,String(n))}function joinPath(e,t){return`${e.endsWith(`/`)?e.slice(0,-1):e}${t.startsWith(`/`)?t:`/${t}`}`}async function readResponseBody(e){let t=await e.text();if(t.length===0)return null;if((e.headers.get(`content-type`)??``).includes(`application/json`))try{return JSON.parse(t)}catch{return t}return t}export{OpenApiConnectionClient};