eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
1 lines • 3.51 kB
JavaScript
import{escapeForQuote,isAstNode,keyMatches,lineAt,parseAgentObject,unwrapExpression}from"./agent-config-ast.js";import{MODEL_HELPERS,parseModelHelper}from"#shared/model-helper.js";async function readModelSelectionFromSource(e){let t=await parseAgentObject(e);if(t.kind===`bail`)return;let n=findModelValue(t.object);return n===void 0?void 0:currentSelection(n,t.program)}async function applyModelSelectionToSource(e,t){let n=await parseAgentObject(e);if(n.kind===`bail`)return n;let r=findModelValue(n.object);if(r===void 0||r.start===void 0||r.end===void 0)return{kind:`bail`,reason:"`model` is absent or cannot be edited safely",line:lineAt(e,n.object.start)};let i=currentSelection(r,n.program);if(i===void 0)return{kind:`bail`,reason:"`model` is neither a string literal nor an eve model helper",line:lineAt(e,r.start)};let a=parseModelHelper(t);if(a){let t=a.helper;if(!hasHelperImport(n.program,t)&&hasIdentifier(n.program,t))return{kind:`bail`,reason:`Cannot safely introduce the ${t} import; that name is already used`,line:lineAt(e,r.start)}}let o=a===void 0?`${e[r.start]===`'`?`'`:`"`}${escapeForQuote(t,e[r.start]===`'`?`'`:`"`)}${e[r.start]===`'`?`'`:`"`}`:`${a.helper}(${JSON.stringify(a.id)})`,s=e.slice(0,r.start)+o+e.slice(r.end);a!==void 0&&(s=hasHelperImport(n.program,a.helper)?s:`import { ${a.helper} } from "${MODEL_HELPERS[a.helper].module}";\n${s}`);let c=parseModelHelper(i);if(c&&c.helper!==a?.helper){let e=await parseAgentObject(s),t=e.kind===`ok`?helperImport(e.program,c.helper):void 0,n=t?.start!==void 0&&t.end!==void 0?s.slice(0,t.start)+removeHelperImport(s.slice(t.start,t.end),c.helper)+s.slice(t.end):s,r=await parseAgentObject(n);r.kind===`ok`&&!hasIdentifier(r.program,c.helper)&&(s=n)}return{kind:`applied`,from:i,to:t,nextSource:s}}function findModelValue(e){for(let t of e.properties)if(t.type===`Property`&&!t.computed&&keyMatches(t.key,`model`))return isAstNode(t.value)?unwrapExpression(t.value):void 0}function currentSelection(e,t){if(e.type===`Literal`&&typeof e.value==`string`)return e.value;if(e.type!==`CallExpression`||!isAstNode(e.callee))return;let n=unwrapExpression(e.callee);if(n.type!==`Identifier`||typeof n.name!=`string`||!(n.name in MODEL_HELPERS))return;let r=n.name,i=MODEL_HELPERS[r];if(!hasHelperImport(t,r)||(e.arguments?.length??0)>1)return;let a=e.arguments?.[0];if(a===void 0)return i.prefix+i.defaultModel;if(!isAstNode(a))return;let o=unwrapExpression(a);if(o.type!==`Literal`||typeof o.value!=`string`)return;let s=o.value.trim().replace(RegExp(`^${r===`chatgpt`?`openai`:r}/`,`u`),``);return s&&!s.includes(`/`)?i.prefix+s:void 0}function helperImportPattern(e){return RegExp(`import\\s*\\{([^}]*)\\}\\s*from\\s*["']${MODEL_HELPERS[e].module}["'];?`,`u`)}function removeHelperImport(e,t){return e.replace(helperImportPattern(t),(e,n)=>{let r=n.split(`,`).map(e=>e.trim()).filter(Boolean),i=r.filter(e=>e!==t);return i.length===r.length?e:i.length===0?``:`import { ${i.join(`, `)} } from "${MODEL_HELPERS[t].module}";`})}function hasIdentifier(e,t){return typeof e!=`object`||!e?!1:isAstNode(e)&&e.type===`Identifier`&&e.name===t?!0:Object.values(e).some(e=>hasIdentifier(e,t))}function helperImport(e,t){return e.body?.find(e=>e.type===`ImportDeclaration`&&e.source?.value===MODEL_HELPERS[t].module&&e.importKind!==`type`&&e.specifiers?.some(e=>e.imported?.name===t&&e.local?.name===t&&e.importKind!==`type`))}function hasHelperImport(e,t){return helperImport(e,t)!==void 0}export{applyModelSelectionToSource,readModelSelectionFromSource};