Dashboard › opencode › Distillation
38d02b7e-a08a-495c-b8d9-256d83260888["lore_tm_v1_SuHJWjf97_GbC1fD4MidpjjOI8n8KUdHyPL0jPAVeXk","lore_tm_v1_yTOhr2u2I4Ajz5n4xPJkvtG4aFa7V9QIeT_S-3pJemY","lore_tm_v1_1PJF5stp10UOvSZMzSS3I6MbIcQ-GoPCMEbHKf_3N1s","lore_tm_v1_Br8IGbQfXQsj85ozlYqe1OuP6vGOGHtxGE5hiFqyOx8","lore_tm_v1_sdaino-ahtcw8vVuS2-ZvBqAlcCR4-bKmfp3C497OTw"]
Date: Sep 16, 2026
packages/core/src/session/compaction.ts showed compaction defaults: DEFAULT_BUFFER = 20_000, DEFAULT_KEEP_TOKENS = 8_000, TOOL_OUTPUT_MAX_CHARS = 2_000, and SUMMARY_OUTPUT_TOKENS = 4_096; document configuration can override auto, buffer, and keep.tokens, with later configured documents winning through reduction.packages/core/src/session/compaction.ts requires summaries to preserve the exact ordered Markdown sections ## Objective, ## Important Details, ## Work State with ### Completed, ### Active, and ### Blocked, then ## Next Move with 2 numbered items, and ## Relevant Files; rules require every section, terse bullets, exact technical artifacts, and no mention of compaction or the summary process.buildPrompt() combines <prior-summary> with the newer <conversation>; the newer conversation wins on conflicts, while objectives, constraints, directives, decisions, and parallel workstreams must be carried forward unless finished and no longer needed.serializeToolContent() in packages/core/src/session/compaction.ts emits text directly and non-text content as [Attached MIME] or [Attached MIME: 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 use [Attached MIME: name-or-URI].compaction messages, walks backward to retain up to the configured recent-token budget, and returns older serialized history as head and retained history as recent.compactIfNeeded() skips automatic compaction when auto is false, model context is absent/nonpositive, or estimated request usage fits within context - Math.max(output, config.buffer); otherwise it delegates to compactAfterOverflow().compactAfterOverflow() uses the latest existing compactionβs summary and recent, refuses to proceed if there is no summarizable head or if the summary prompt would exceed context - summaryOutput, and caps summary generation at exactly 4_096 tokens using Math.min(output || SUMMARY_OUTPUT_TOKENS, SUMMARY_OUTPUT_TOKENS).SessionEvent.Compaction.Started before streaming and SessionEvent.Compaction.Ended afterward with the same generated messageID, reason: "auto", summary text, and retained recent; provider errors, LLM.Error, or blank summary output cause a false result without publishing the ended event.packages/core/src/session/context-epoch.ts showed SessionContextEpoch.initialize() and prepare() require a SessionExecutionClaim.Claim, and all inserts, replacements, and snapshot advances execute through SessionExecutionClaim.transaction() to validate ownership.SessionContextEpoch.prepare() concurrently obtains the current SystemContext, stored epoch, and SessionHistory.latestCompaction() with unbounded concurrency; absent stored state is initialized and inserted with baseline_seq = EventV2.latestSequence(db, sessionID).SystemContext.Snapshot; decode failures become ContextSnapshotDecodeError containing sessionID and stringified details.SystemContext.replace() only when the latest compaction sequence is newer than stored.baseline_seq; otherwise it uses SystemContext.reconcile(). Unchanged and ReplacementBlocked retain the stored baseline, while ReplacementReady replaces baseline, snapshot, and baseline sequence.SessionContextEpoch.prepare() publishes SessionEvent.ContextUpdated with a newly created SessionMessage.ID; its commit callback advances only the stored snapshot under the execution claim. Missing rows during replace() or advance() terminate with Effect.die("Context Epoch not found").SessionContextEpoch.reset() deletes the epoch row for the specified sessionID; initializeOnce() is idempotent and returns without generating context when an epoch already exists.packages/core/src/session/runner/index.ts showed SessionRunner.Interface.run() performs one local continuation from already-recorded Session history and accepts sessionID, force, executionID, ownerID, and optional recoveryInputID; explicit runs perform one provider attempt even when no durable work is eligible.SessionRunner.RunError is the union of LLMError, SessionRunnerModel.Error, MessageDecodeError, ContextSnapshotDecodeError, SystemContext.InitializationBlocked, and ToolOutputStore.Error; the service identifier is @opencode/v2/SessionRunner.