eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
1 lines • 3.33 kB
JavaScript
import{createLogger}from"#internal/logging.js";import{DynamicInstructionResolveMessagesKey,PendingDynamicInstructionUserMessagesKey,SessionDynamicInstructionsKey,TurnDynamicInstructionsKey}from"#context/keys.js";import{toErrorMessage}from"#shared/errors.js";import{normalizeInstructionsDefinition}from"#internal/authored-definition/core.js";import{ALLOWED_DYNAMIC_INSTRUCTION_EVENTS}from"#dynamic/definition.js";import{isBrandedInstructionsEntry}from"#shared/instructions-definition.js";import{buildResolveContext}from"#context/dynamic-resolve-context.js";import{createFrameworkUserMessage}from"#harness/messages.js";const log=createLogger(`dynamic-instructions`);function lowerInstruction(e){let t=normalizeInstructionsDefinition(e,`Expected dynamic instructions to match the public eve shape.`),n=t.content.trim();if(n.length!==0)return t.role===`system`?{role:`system`,message:{role:`system`,content:n}}:{role:`user`,message:createFrameworkUserMessage(`context.instruction`,n)}}function durableKeyForEvent(e){switch(e){case`session.started`:return SessionDynamicInstructionsKey;case`turn.started`:return TurnDynamicInstructionsKey;default:return}}function buildDynamicInstructionMessages(e){let t=e.get(SessionDynamicInstructionsKey)??{},n=e.get(TurnDynamicInstructionsKey)??{};return[...Object.values(t).flat(),...Object.values(n).flat()]}function prepareDynamicInstructionPreamble(e,t){e.setVirtualContext(DynamicInstructionResolveMessagesKey,[...t]),e.setVirtualContext(PendingDynamicInstructionUserMessagesKey,[])}function drainDynamicInstructionUserMessages(e){let t=[...e.get(PendingDynamicInstructionUserMessagesKey)??[]];return e.delete(DynamicInstructionResolveMessagesKey),e.delete(PendingDynamicInstructionUserMessagesKey),t}async function dispatchDynamicInstructionEvent(e){let{ctx:t,resolvers:n,event:r,messages:i}=e;if(!ALLOWED_DYNAMIC_INSTRUCTION_EVENTS.has(r.type))return;r.type===`turn.started`&&t.set(TurnDynamicInstructionsKey,{});let a=n.filter(e=>e.eventNames.includes(r.type));if(a.length===0)return;let o=durableKeyForEvent(r.type);if(o===void 0)return;let s=t.get(DynamicInstructionResolveMessagesKey)??i,c=t.get(PendingDynamicInstructionUserMessagesKey)??[],l=buildResolveContext(t,[...s,...c]),u=await Promise.allSettled(a.map(async e=>{let t=e.events[r.type];if(t===void 0)return null;let n=await t(r,l);if(n==null)return{resolver:e,instruction:void 0};if(!isBrandedInstructionsEntry(n))return log.error(`Dynamic instructions resolver "${e.slug}" returned an unbranded value — wrap with defineInstructions().`),null;try{return{resolver:e,instruction:lowerInstruction(n)}}catch(t){return log.error(`Dynamic instructions resolver "${e.slug}" returned an invalid value.`,{error:toErrorMessage(t)}),null}})),d={...t.get(o)};for(let e of u){if(e.status===`rejected`){log.error(`Dynamic instructions resolver (${r.type}) threw — skipping.`,{error:toErrorMessage(e.reason)});continue}if(e.value===null)continue;let{resolver:n,instruction:i}=e.value;delete d[n.slug],i?.role===`system`?d[n.slug]=[i.message]:i?.role===`user`&&t.setVirtualContext(PendingDynamicInstructionUserMessagesKey,[...t.get(PendingDynamicInstructionUserMessagesKey)??[],i.message])}t.set(o,d)}export{buildDynamicInstructionMessages,dispatchDynamicInstructionEvent,drainDynamicInstructionUserMessages,prepareDynamicInstructionPreamble};