eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
26 lines (18 loc) • 4.5 kB
JavaScript
import{estimateTokens}from"#harness/token-estimate.js";const COMPACTION_CHECKPOINT_MARKER=`Summary of our conversation so far:`,COMPACTION_RESUMPTION_MESSAGE=`Continue.`,TODO_COMPACTION_PRESERVATION_LABEL=`[Your task list was preserved across context compaction]`,COMPACTION_SYSTEM_PROMPT=`You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.
Include:
- Current progress and key decisions made
- Important context, constraints, or user preferences
- What remains to be done, with clear next steps
- Any critical data, examples, or references needed to continue
Be concise, structured, and focused on helping the next LLM seamlessly continue the work. Write in the same language as the conversation. Do not continue the conversation, answer its questions, or invent facts. Only output the handoff summary.`,COMPACTION_PROMPT_ENVELOPE={prompt:formatCompactionPrompt({previousCheckpoint:``,transcript:``}),system:COMPACTION_SYSTEM_PROMPT};function createCompactionPrompt(e){let t=e.messages.map(e=>({content:renderCompactionMessageContent(e),role:e.role}));return degradeOversizedTranscript(e,t),{prompt:formatCompactionPrompt({previousCheckpoint:e.previousCheckpoint?.trim()??`(none)`,transcript:formatCompactionTranscript(t)}),system:COMPACTION_SYSTEM_PROMPT}}function degradeOversizedTranscript(t,n){let r=t.transcriptBudgetTokens;if(r===void 0)return;let i=estimateTokens(formatCompactionPrompt({previousCheckpoint:t.previousCheckpoint?.trim()??`(none)`,transcript:formatCompactionTranscript(n)}))-r;for(let e=0;e<n.length&&i>0;e+=1){let r=n[e],a=t.messages[e];if(r===void 0||a===void 0)continue;let o=renderCompactionMessageContent(a,2e3);o.length>=r.content.length||(i-=(r.content.length-o.length)/4,n[e]={content:o,role:r.role})}}function formatCompactionPrompt(e){return`<previous-checkpoint>
${e.previousCheckpoint}
</previous-checkpoint>
<conversation>
Conversation transcript:
${e.transcript}
</conversation>
Update the previous checkpoint with the newer information in the conversation. If there is no previous checkpoint, create one from the conversation.
Make completed work explicit so the next model does not repeat it. Keep completed work separate from current and remaining work, and do not describe completed work as pending unless later messages show it must be redone. Preserve exact file paths, function names, commands, error messages, identifiers, and measured values when they are needed to continue.
Large tool outputs are the main thing to compress: reduce each to the findings the next model needs — what was searched or read, what it established, and the exact identifiers involved — rather than reproducing the output. The next model cannot see the originals, so nothing it would need to act on may be lost.`}function formatCompactionTranscript(e){let t=e.filter(e=>e.content.trim().length>0).map(e=>`### ${e.role}\n${e.content.trim()}`);return t.length===0?`(empty)`:t.join(`
`)}function renderCompactionMessageContent(e,t){return typeof e.content==`string`?renderConversationText(e.content,t):e.content.map(e=>renderCompactionContentPart(e,t)).filter(e=>e.length>0).join(`
`).trim()}function renderCompactionContentPart(e,t){switch(e.type){case`text`:return renderConversationText(e.text,t);case`reasoning`:return``;case`file`:return e.filename?`Attached file ${e.filename} (${e.mediaType})`:`Attached file attachment (${e.mediaType})`;case`tool-call`:return renderTranscriptToolCall(e,t);case`tool-result`:return renderTranscriptToolResult(e,t);default:return``}}const TRANSCRIPT_PAYLOAD_LIMIT=2e3;function renderTranscriptToolCall(e,t){return renderToolCall(e,t===void 0?TRANSCRIPT_PAYLOAD_LIMIT:280)}function renderTranscriptToolResult(e,t){let n=t===void 0?TRANSCRIPT_PAYLOAD_LIMIT:280,r=e.isError?`errored`:`returned`,i=renderPayload(e.output,n);return i?`Tool ${e.toolName} ${r} ${i}`:`Tool ${e.toolName} ${r}`}function renderToolCall(e,t){let n=renderPayload(e.input,t);return n?`Called ${e.toolName} with ${n}`:`Called ${e.toolName}`}function renderPayload(e,t){return e===void 0?``:capText(JSON.stringify(e)??``,t)}function renderConversationText(e,t){return t===void 0?e.trim():capText(e,t)}function capText(e,t){let n=e.replace(/\s+/g,` `).trim();return n.length<=t?n:`${n.slice(0,t).trimEnd()}…`}export{COMPACTION_CHECKPOINT_MARKER,COMPACTION_PROMPT_ENVELOPE,COMPACTION_RESUMPTION_MESSAGE,TODO_COMPACTION_PRESERVATION_LABEL,TRANSCRIPT_PAYLOAD_LIMIT,createCompactionPrompt};