UNPKG

eve

Version:

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

1 lines 5.68 kB
import{createFrameworkUserMessage,isFrameworkUserMessage,isUserModelMessage}from"#harness/messages.js";import{generateText}from"ai";import{COMPACTION_CHECKPOINT_MARKER,COMPACTION_PROMPT_ENVELOPE,COMPACTION_RESUMPTION_MESSAGE,TRANSCRIPT_PAYLOAD_LIMIT,createCompactionPrompt,sliceUtf16Safe,stubContentOutputFileParts}from"#harness/compaction-prompt.js";import{estimateTokens}from"#harness/token-estimate.js";const COMPACTION_PROMPT_OVERHEAD_TOKENS=estimateTokens([{content:COMPACTION_PROMPT_ENVELOPE.system,role:`system`},createFrameworkUserMessage(`context.compaction`,COMPACTION_PROMPT_ENVELOPE.prompt)]);function getInputTokenCount(e,t){let n=t.lastKnownInputTokens,r=t.lastKnownPromptMessageCount;return n===void 0||r===void 0||!Number.isInteger(r)||r<0||r>e.length?estimateTokens(e):n+estimateTokens(e.slice(r))}function shouldCompact(e,t){return e.length>0&&getInputTokenCount(e,t)+COMPACTION_PROMPT_OVERHEAD_TOKENS>t.threshold}async function resolveCompactionModel(e){let t=e.compactionModelReference??e.modelReference;return{model:t===e.modelReference?e.model:await e.resolveModel(t),providerOptions:t.providerOptions}}const COMPACTION_HEURISTICS=[toolResultCapHeuristic];function toolResultCapHeuristic(e){let t=withResumptionGuard([...e.previousCheckpoint===void 0?[]:[createFrameworkUserMessage(`context.compaction`,COMPACTION_CHECKPOINT_MARKER),{content:e.previousCheckpoint,role:`assistant`}],...capToolResults(e.older),...e.recent],e.conversation,e.config.threshold);return evaluateThreshold(t,e.config,`should-compact`,e.tokenEstimateAdjustment).type===`within-limit`?{messages:t,type:`within-limit`}:{type:`insufficient`}}function evaluateThreshold(e,t,n,r=0){let i=n===`should-compact`?COMPACTION_PROMPT_OVERHEAD_TOKENS:0,a=estimateTokens(e)+i+r;return{estimatedTokens:a,type:a<=t.threshold?`within-limit`:`over-limit`}}async function compactMessages(e,t,n,r,i,a,o,s=!1){let{conversation:c,previousCheckpoint:l}=extractPreviousCheckpoint(e),u=selectRecentWindowSize(c,s?{...n,recentWindowSize:1}:n);if(!s){let{older:t,recent:r}=splitMessagesForCompaction(c,u);if(t.length===0&&l===void 0)return keepNonToolResultMessages(r);let i=Math.max(0,getInputTokenCount(e,n)-estimateTokens(e));for(let e of COMPACTION_HEURISTICS){let a=e({config:n,conversation:c,older:t,previousCheckpoint:l,recent:r,tokenEstimateAdjustment:i});if(a.type===`within-limit`)return a.messages}}for(;;){let{older:e,recent:s}=splitMessagesForCompaction(c,u),d=createCompactionPrompt({messages:e,previousCheckpoint:l,transcriptBudgetTokens:n.threshold}),f=await generateText({abortSignal:o,headers:a,messages:[createFrameworkUserMessage(`context.compaction`,d.prompt)],model:t,providerOptions:r,system:d.system,telemetry:i?{...i,functionId:`eve.compaction`}:void 0,temperature:0});if(f.text.trim().length===0)throw Error(`The compaction model returned an empty summary. Finish reason: ${f.finishReason}.`);let p=[createFrameworkUserMessage(`context.compaction`,COMPACTION_CHECKPOINT_MARKER),{content:f.text,role:`assistant`}],m=withResumptionGuard([...p,...s],c,n.threshold);if(evaluateThreshold(m,n,`estimate`).type===`within-limit`)return m;let h=withResumptionGuard([...p,...keepNonToolResultMessages(s)],c,n.threshold);if(evaluateThreshold(h,n,`estimate`).type===`within-limit`||u===0)return h;--u}}function capToolResults(e){return e.map(e=>{if(e.role!==`tool`||typeof e.content==`string`)return e;let t=!1,n=e.content.map(e=>{if(e.type!==`tool-result`)return e;let n=stubContentOutputFileParts(e.output),r=JSON.stringify(n)??``;return r.length<=TRANSCRIPT_PAYLOAD_LIMIT?n===e.output?e:(t=!0,{...e,output:n}):(t=!0,{...e,output:{type:`text`,value:`[Truncated by eve: tool result reduced during context compaction. Re-run the tool if you need the full output.]\n\n${sliceUtf16Safe(r,TRANSCRIPT_PAYLOAD_LIMIT)}`}})});return t?{...e,content:n}:e})}function withResumptionGuard(e,t,n){let r=e.at(-1)?.role,i=findLastRealUserMessage(t),a=i!==void 0&&e.some(e=>e.role===`user`&&e.content===i.content);return r!==void 0&&r!==`assistant`?r===`tool`&&i!==void 0&&!a&&estimateTokens([i])<=n?[...e,i]:e:[...e,i!==void 0&&!a?i:createFrameworkUserMessage(`execution.continuation`,COMPACTION_RESUMPTION_MESSAGE)]}function findLastRealUserMessage(e){for(let t=e.length-1;t>=0;--t){let n=e[t];if(n?.role===`user`&&typeof n.content==`string`&&!(isFrameworkUserMessage(n)||isUserModelMessage(n)&&n.kind===`legacy.unknown`))return n}}function extractPreviousCheckpoint(e){let t=e[0],n=e[1];return t?.role!==`user`||t.content!==COMPACTION_CHECKPOINT_MARKER||n?.role!==`assistant`?{conversation:[...e],previousCheckpoint:void 0}:{conversation:e.slice(2),previousCheckpoint:assistantMessageText(n)}}function keepNonToolResultMessages(e){let t=[];for(let n of e)if(n.role!==`tool`){if(n.role===`assistant`){let e=assistantMessageText(n);e.length>0&&t.push({content:e,role:`assistant`});continue}t.push(n)}return t}function assistantMessageText(e){return typeof e.content==`string`?e.content.trim():e.content.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim()}function selectRecentWindowSize(e,t){let n=Math.min(t.recentWindowSize,Math.max(e.length-1,0)),r=resolveCompactionSummaryReserve(t),i=0,a=0;for(let o=e.length-1;o>=0&&i<n;--o){let n=e[o];if(n===void 0)continue;let s=estimateTokens([n]);if(a+s+r>t.threshold)break;a+=s,i+=1}return i}function resolveCompactionSummaryReserve(e){return Math.min(2048,Math.max(64,Math.floor(e.threshold/4)))}function splitMessagesForCompaction(e,t){if(t<=0)return{older:[...e],recent:[]};let n=e.length-t;for(;n<e.length&&e[n]?.role===`tool`;)n+=1;return{older:e.slice(0,n),recent:e.slice(n)}}export{compactMessages,getInputTokenCount,resolveCompactionModel,shouldCompact};