Dashboard › opencode › Distillation
97495835-2e7f-48dd-919e-0be4f59d846d["lore_tm_v1_DdfrdqlNUruddpzOy9bs49VYifIIBfa3XbmuGtBOFhI","lore_tm_v1_0BBo-81I9o4yLpDgLX5HuvWQmJfBmk46lJtmFUItYZs","lore_tm_v1_Honv1n1oigVowSuenBzG78lq8iodE3DsYwPoenIb640","lore_tm_v1_xt2luhAc0YZQPi236I20iKXfvSE-zYNmO1-AbvKw-_c","lore_tm_v1_BPbfdEnxehMMvAdFeUcQ0mwi_G11D1hUK56ReVZ29XY"]
Date: Sep 15, 2026
packages/core/src/session/runner/publish-llm-event.ts Input requires sessionID, agent, model, optional snapshot, and commit hooks startCommit(assistantMessageID), terminalCommit(assistantMessageID), interruptedCommit(assistantMessageID), and eventCommit().packages/core/src/session/runner/publish-llm-event.ts:20-32 normalizes token usage with safe(), clamping undefined, non-finite, and negative values to 0; tokens() returns input from nonCachedInputTokens, output from visibleOutputTokens, reasoning, and cache: { read, write }.packages/core/src/session/runner/publish-llm-event.ts:34-55 converts non-array objects to records and wraps other structured values as { value }; message() preserves strings, otherwise tries JSON.stringify and falls back to String. settledOutput() maps error results to { error: { type: "unknown", message } }, otherwise uses the supplied ToolOutput or ToolOutput.fromResultValue(result), dying with Unsupported tool result: ... when conversion fails.createLLMEventPublisher() uses publishEvent() so durable events call events.publish(definition, data, { commit }), while non-durable events commit first and then publish. Its per-tool state stores assistantMessageID, name, inputEnded, called, settled, providerExecuted, and optional providerMetadata.packages/core/src/session/runner/publish-llm-event.ts:86-110 startAssistant() is idempotent: it creates one SessionMessage.ID, marks the assistant active, and publishes SessionEvent.Step.Started with sessionID, agent, model, timestamp, optional snapshot, and a commit invoking input.startCommit(created). Tool events before this step die with Tool event before assistant step start.packages/core/src/session/runner/publish-llm-event.ts:112-184 implements fragment accumulation for text, reasoning, and tool input using ID-keyed chunk arrays. It rejects duplicate starts, deltas before starts, and ends before starts; joins chunks on end; and flushFragments() ends all open text, reasoning, and tool-input fragments.SessionEvent.Text.Ended with textID and joined text; ended reasoning fragments publish SessionEvent.Reasoning.Ended with reasoningID, joined text, and optional providerMetadata; ended tool-input fragments publish SessionEvent.Tool.Input.Ended, then set tool.inputEnded = true.startToolInput() rejects duplicate call IDs with Duplicate tool input start: ${event.id}, starts the assistant if needed, initializes tool state with inputEnded, called, settled, and providerExecuted all false, starts fragment collection, and publishes SessionEvent.Tool.Input.Started with callID and tool name.endToolInput() requires an existing tool, rejects name changes with Tool input name changed for ${event.id}: ${tool.name} -> ${event.name}, rejects repeated endings with Duplicate tool input end: ${event.id}, and then ends the stored fragment.packages/core/src/session/runner/publish-llm-event.ts:220-238 failAssistant(message) is idempotent once assistantFailed is true; otherwise it flushes fragments, starts the assistant if necessary, marks it inactive and failed, and publishes SessionEvent.Step.Failed with an unknown error through input.terminalCommit(assistantMessageID).packages/core/src/session/runner/publish-llm-event.ts:240-256 interruptAssistant(message) similarly flushes, ensures an assistant exists, marks it inactive and failed, and publishes SessionEvent.Step.Interrupted with { type: "unknown", message } through input.interruptedCommit(assistantMessageID).packages/core/src/session/runner/publish-llm-event.ts:258-277 failUnsettledTools(message, hostedOnly = false) marks each unsettled tool failed, optionally limiting handling to provider-executed tools, and publishes SessionEvent.Tool.Failed with the tool’s assistantMessageID, callID, unknown error, provider.executed, and optional provider metadata.packages/core/src/session/compaction.ts:184-246 compactAfterOverflow() returns false when model context is absent/nonpositive, no selectable head and no prior compaction exists, the summary prompt exceeds context - summaryOutput, the summary stream throws LLM.Error, a provider error occurs, or the produced summary is blank.compactAfterOverflow() derives output capacity from input.request.generation?.maxTokens, then model default output, then 0; selects entries using config.tokens; incorporates a prior compaction’s summary and recent context; and caps summary generation at Math.min(output || SUMMARY_OUTPUT_TOKENS, SUMMARY_OUTPUT_TOKENS).SessionMessage.ID, publishes SessionEvent.Compaction.Started with reason "auto" and optional input.eventCommit, optionally invokes beforeStream(), streams one user summaryPrompt with no tools and generation.maxTokens = summaryOutput, collects textDelta chunks, and publishes SessionEvent.Compaction.Ended with the joined summary, selected.recent, reason "auto", and { commit: input.commit }.packages/core/src/session/compaction.ts:247-258 compactIfNeeded() skips compaction when config.auto is false, context is absent/nonpositive, or estimated system/messages/tools tokens are at most context - Math.max(output, config.buffer); otherwise it delegates to compactAfterOverflow(input). make() exposes compactIfNeeded and compactAfterOverflow.packages/core/src/session/execution/local.ts provides current-process routing for implicit-local locations. make() creates a random ownerID, converts SESSION_EXECUTION_LEASE_MS to milliseconds, tracks active claims by SessionSchema.ID, and uses SessionRunCoordinator.drain(sessionID, force), local execution creates a random executionID, inserts a "ready" SessionExecutionTable claim with owner_id, creation time, and expires_at = now + leaseDuration using onConflictDoNothing(), and exits if another claim prevented insertion.SessionRecoveryTable row for the session where wake_pending = true and recovery_error IS NULL, ordered by time_created then execution_id, and passes its continuation_message_id to input.run(claim, force, recoveryInputID).SessionExecutionClaim.update(db, claim) repeated every leaseDuration / 3. Non-interrupt failures are logged as Failed to drain Session with sessionID."unknown" or "continue".SessionExecution.Service exposes coordinator active, resume, and wake; interrupt(sessionID) clears an active claim before coordinator interruption and suppresses only the SessionExecutionClaim.Lost defect. The layer loads the session from SessionStore, dies with Session not found: ${claim.sessionID} if absent, runs SessionRunner.Service.use((runner) => runner.run({ ...claim, force, recoveryInputID })), and provides the location-specific service from LocationServiceMap.packages/core/src/session/projector.ts:338-355 projects SessionEvent.AgentSwitched and SessionEvent.ModelSwitched by updating the session’s agent or model, setting time_updated from the event timestamp, and then running the common event projection.SessionEvent.Prompted and SessionEvent.PromptAdmitted require a durable aggregate sequence or die with Durable Session event is missing aggregate sequence. Prompted calls SessionInput.projectPrompted() with promotedSeq = event.durable.seq and then run(db, event); PromptAdmitted calls SessionInput.projectAdmitted() with admittedSeq = event.durable.seq.packages/core/src/session/projector.ts routes ContextUpdated, Synthetic, Shell.Started, Shell.Ended, Step.Started, Step.Ended, Step.Failed, and Step.Interrupted through the common run(db, event) projection.SessionEvent.Step.Recovered requires a durable sequence and derives a continuation message ID from continuation(event.data.executionID). If an assistantMessageID is supplied, it verifies that this ID is the latest assistant message and that decoding still yields type "assistant", otherwise dying with Recovery target is not the latest assistant: ... or Recovery target is not an assistant: ....Step.Recovered, the projector admits a queued synthetic prompt Prompt.make({ text: "continue" }) using the recovery event’s durable sequence and timestamp, then inserts SessionRecoveryTable data containing session_id, execution_id, nullable assistant_message_id, continuation_message_id, recovery phase, wake_pending: true, and time_created.Text.Started, Text.Ended, Tool.Input.Started, Tool.Input.Ended, Tool.Called, Tool.Progress, Tool.Success, Tool.Failed, Reasoning.Started, Reasoning.Ended, and Compaction.Ended through run(db, event); the SessionEvent.Retried projection remains commented out.SessionEvent.RevertEvent.Staged updates the session’s revert value, defensively copies revert.files when present, and updates time_updated; SessionEvent.RevertEvent.Cleared sets revert: null and updates time_updated.