Dashboard › opencode › Distillation
24dea857-c6a3-4d1a-aac8-41ce34f0c353["lore_tm_v1_KNgXRlxLqfp0BwO28D5WcVmUEKG9WIOnFUdowqz9184","lore_tm_v1_-I2VaLAuoLYOhqRiqD8pQoiAatMc-s_Mj3g5Q_tpO6Q","lore_tm_v1_RZcLRc5audvoxrDwagS6Av3Upa76UUz-4At4UfQkh-g","lore_tm_v1_L6qV3JV2Tmafo-p0x2_OwA5sJ7aF9SmRk2IDlBp8zy8","lore_tm_v1_r7j57RiZ9jfoU9W7g9Kf19kcYD7AtPFHGD6ddHZ7wFw","lore_tm_v1_HkjSGatIAW3MEeUbff0WcO07eBuU4PRHtMgS_2T1aPg"]
Date: Sep 15, 2026
packages/core/src/session/run-coordinator.ts defines SessionRunCoordinator.Coordinator<Key, E> with active, run(key), wake(key), and interrupt(key, cleanup?); it serializes execution per key while allowing different keys to run concurrently.SessionRunCoordinator entries track done: Deferred.Deferred<void, E>, optional owner and exit, plus pendingWake and stopping; active entries are stored in Map<Key, Entry<E>>, and fibers are launched through FiberSet.makeRuntime<never, void, never>().SessionRunCoordinator.run(key) starts options.drain(key, true) when idle, joins the existing Deferred when active, and, if the entry is stopping, waits for completion before recursively retrying run(key).SessionRunCoordinator.wake(key) coalesces follow-up work by setting entry.pendingWake = true; if idle, it starts options.drain(key, false).pendingWake clears the flag and starts a yielded successor drain on the same entry; otherwise it deletes the active key or creates a successor entry, then completes entry.done with the original Exit.SessionRunCoordinator.interrupt(key, cleanup) marks an entry stopping, clears its preexisting pendingWake, interrupts its owner, runs cleanup, requires a captured exit or throws "Interrupted Session execution did not settle", and starts a successor if new work set pendingWake during stopping.Effect.yieldNow; initial starts use a Deferred readiness barrier so entry.owner is assigned before options.drain(...) can settle.packages/core/src/session/compaction.ts compaction defaults are DEFAULT_BUFFER = 20_000, DEFAULT_KEEP_TOKENS = 8_000, TOOL_OUTPUT_MAX_CHARS = 2_000, and SUMMARY_OUTPUT_TOKENS = 4_096; config documents may override auto, buffer, and keep.tokens.SessionCompaction.serializeToolContent() joins text parts directly and renders attachments as [Attached ${item.mime}] or [Attached ${item.mime}: ${item.name}]; oversized tool and shell output is truncated to 2,000 characters followed by \n[truncated].[User], [Assistant], [Assistant reasoning], [Assistant tool call], [Tool result], [Tool error], [System update], [Synthetic context], and [Shell]; user file attachments use [Attached ${file.mime}: ${file.name ?? file.uri}].## Objective, ## Important Details, ## Work State with ### Completed, ### Active, and ### Blocked, then ## Next Move with 2 numbered entries, and ## Relevant Files; rules require terse bullets and preservation of exact paths, symbols, commands, errors, URLs, and identifiers.<conversation> newer and authoritative over <prior-summary>, require carrying forward still-needed objectives, constraints, directives, decisions, and parallel workstreams, moving finished active work to completed, resolving blockers, and updating Objective and Next Move.SessionCompaction.select(entries, tokens) excludes messages of type "compaction", serializes remaining messages, and scans backward to split them into head for summarization and token-limited recent history.SessionCompaction.compactIfNeeded() skips when auto-compaction is disabled or context limits are absent/nonpositive; it compacts when the estimated request payload exceeds context - Math.max(output, config.buffer).SessionCompaction.compactAfterOverflow() uses the latest compaction summary plus its preserved recent content when present, limits summary output to Math.min(output || 4_096, 4_096), and refuses compaction if the summary prompt estimate exceeds context - summaryOutput.SessionEvent.Compaction.Started before streaming with reason: "auto" and a generated SessionMessage.ID; it streams an LLM request with no tools and { maxTokens: summaryOutput }, collects text deltas, treats provider errors or LLM.Error as failure, and publishes SessionEvent.Compaction.Ended only for a successful nonblank summary, preserving selected.recent.packages/core/src/session/context-epoch.ts changed context-epoch initialization and preparation to require SessionExecutionClaim.Claim; database writes in insert, replace, and advance are fenced through SessionExecutionClaim.transaction(db, claim, ...).SessionContextEpoch.prepare() concurrently loads current SystemContext, the stored epoch, and SessionHistory.latestCompaction(db, sessionID) with { concurrency: "unbounded" }; absent state is initialized and inserted with the latest event sequence as baselineSeq.SystemContext.Snapshot; decode failures map to ContextSnapshotDecodeError({ sessionID, details: String(error) }).SystemContext.replace(value, snapshot) when the latest compaction sequence exceeds stored.baseline_seq; otherwise it uses SystemContext.reconcile(value, snapshot)."Unchanged" and "ReplacementBlocked" retain the stored baseline; "ReplacementReady" replaces the epoch using the compaction sequence or EventV2.latestSequence(db, sessionID); reconciliation updates publish SessionEvent.ContextUpdated and commit advance(...).pipe(Effect.orDie).SessionContextEpoch.replace() and advance() fatally fail with the exact error "Context Epoch not found" if their fenced update returns no row; reset() deletes the epoch by session_id.packages/core/src/database/migration/20260914170650_session-recovery.ts, ID "20260914170650_session-recovery", was consolidated to add session_input.wake_pending integer DEFAULT false NOT NULL and create session_execution and session_recovery in one migration.session_execution schema has columns id text NOT NULL, session_id text NOT NULL, owner_id text NOT NULL, nullable assistant_message_id text, phase text NOT NULL, time_created integer NOT NULL, expires_at integer NOT NULL, and nullable recovery_error text; its primary key is session_execution_pk, phase is constrained to 'ready', 'safe', or 'unknown', and session_id references session(id) with ON DELETE CASCADE.session_recovery schema has session_id, execution_id, assistant_message_id, continuation_message_id, wake_pending integer DEFAULT true NOT NULL, and time_created; primary key is (session_id, assistant_message_id), and foreign keys cascade from session, assistant message, and continuation input deletions.session_execution_session_idx (unique on session_execution.session_id), session_execution_owner_idx (on owner_id), session_input_wake_pending_promoted_time_created_id_idx (on wake_pending, promoted_seq, time_created, id), session_recovery_execution_idx (unique on execution_id), and session_recovery_continuation_message_idx (unique on continuation_message_id).packages/core/src/database/migration.gen.ts now ends with only import("./migration/20260914170650_session-recovery"); registrations for ./migration/20260914214636_session-execution and ./migration/20260914222526_session-execution-phase were removed.packages/core/src/database/migration/20260914214636_session-execution.ts and packages/core/src/database/migration/20260914222526_session-execution-phase.ts were deleted after their table, execution_id, index, and phase changes were folded into 20260914170650_session-recovery.ts.