Dashboard › opencode › Distillation
9aae8338-87fe-4f54-8661-dce14877403e["lore_tm_v1_zX7xiigPEudZlqHqdV07zlsw5wKBIqaYzPPaEjiVuEc","lore_tm_v1_QeP_VoaR2t_DmoQP-udV-KLWi_vPUrXuofETO7b9agU","lore_tm_v1_DRb0jTtuI85C1annLI3dHncULQ60l-i9lPA_9YYhgnc","lore_tm_v1_doBULLBXVHI7_-1sDAESL0DenDXm7KldkdWOvIAWuRs"]
Date: Sep 17, 2026
packages/core/src/session/context-epoch.ts defines SessionContextEpoch.initialize() and SessionContextEpoch.prepare() around durable context epochs, using SessionExecutionClaim.Claim to fence database mutations.SessionContextEpoch.prepareOnce() concurrently loads the current SystemContext.SystemContext, stored SessionContextEpochTable row, and SessionHistory.latestCompaction(db, sessionID) with { concurrency: "unbounded" }.SystemContext.initialize(value), inserts the generation, and returns { baseline, baselineSeq }; otherwise it decodes stored.snapshot with Schema.decodeUnknownEffect(SystemContext.Snapshot) and maps failures to ContextSnapshotDecodeError({ sessionID, details: String(error) }).stored.baseline_seq. SystemContext.replace(value, snapshot) is used in that case; otherwise SystemContext.reconcile(value, snapshot) is used.packages/core/src/session/context-epoch.ts: Unchanged and ReplacementBlocked retain the stored baseline; ReplacementReady replaces the epoch using the compaction sequence or EventV2.latestSequence(db, sessionID); an incremental update publishes SessionEvent.ContextUpdated and commits advance(db, sessionID, result.snapshot, claim).SessionContextEpoch.insert(), replace(), and advance() execute writes through SessionExecutionClaim.transaction(db, claim, ...); replace() and advance() die with "Context Epoch not found" when no row is updated. SessionContextEpoch.reset() deletes the epoch row for the session.packages/core/src/session/compaction.ts uses compaction defaults DEFAULT_BUFFER = 20_000, DEFAULT_KEEP_TOKENS = 8_000, TOOL_OUTPUT_MAX_CHARS = 2_000, and SUMMARY_OUTPUT_TOKENS = 4_096.## Objective; ## Important Details; ## Work State with ### Completed, ### Active, and ### Blocked; ## Next Move with items 1. and 2.; and ## Relevant Files. Rules require every section, terse bullets, preservation of exact paths/symbols/commands/errors/URLs/identifiers, and no mention of compaction or the summary process.SUMMARY_UPDATE_INSTRUCTIONS tells the summarizer to combine <prior-summary> with newer <conversation>, carry forward objectives, constraints, directives, decisions, and parallel workstreams, let newer conversation win conflicts, move completed work from Active to Completed, update resolved blockers, and refresh Objective and Next Move.serializeToolContent() renders text items verbatim and non-text items as [Attached ${item.mime}] or [Attached ${item.mime}: ${item.name}]; serialized tool and shell output is truncated after exactly 2_000 characters with \n[truncated].[User], [Assistant], [Assistant reasoning], [Assistant tool call], [Tool result], [Tool error], [System update], [Synthetic context], and [Shell]; user file attachments are represented as [Attached ${file.mime}: ${file.name ?? file.uri}].info.compaction settings in order, supporting auto, buffer, and keep.tokens, with defaults { auto: true, buffer: 20_000, tokens: 8_000 }.select() excludes messages of type "compaction", serializes the remaining conversation, and walks backward to retain the newest messages within the configured token budget, returning older content as head and retained content as recent.buildPrompt() either requests a new anchored summary from <conversation> or combines <conversation> with <prior-summary> using SUMMARY_UPDATE_INSTRUCTIONS; in both cases it appends SUMMARY_TEMPLATE.SessionCompaction.compactIfNeeded() skips compaction when automatic compaction is disabled, the model context limit is absent/nonpositive, or the estimated request fits within context - Math.max(output, config.buffer); otherwise it delegates to compactAfterOverflow().SessionCompaction.compactAfterOverflow() limits summary output to Math.min(output || 4_096, 4_096), refuses to compact if the prompt exceeds context - summaryOutput, publishes SessionEvent.Compaction.Started with reason: "auto", streams an LLM request with no tools, and publishes SessionEvent.Compaction.Ended only when streaming succeeds, no provider error occurs, and the assembled summary is nonblank.input.request.http, use messages: [Message.user(summaryPrompt)], tools: [], and generation: { maxTokens: summaryOutput }; LLMEvent.is.providerError(event) marks failure, while LLMEvent.is.textDelta(event) appends text chunks.