Dashboard › opencode › Distillation
8e853ae3-10c6-40d3-9c60-e606ddb14f20["lore_tm_v1_LlQvRDBxSzfpCp0iFnWSplPtaHjYX1qt9jZbdGSh9KY","lore_tm_v1_Vko3xWVprwoj-vxaeXithZYyiv_U4rSFx-aqjfCetqY","lore_tm_v1_uTTkI-x1PU7ka6NlO9_kGZl2nT1WkPC9ErQFAvAHyss","lore_tm_v1_kD3UFfdX50Il9JJ4J3RHz_n8DKgVDS3K9cz-wS2-u-0","lore_tm_v1_ZUvA-cDkPcvysComQnBa4obcDmZSaSYEy_MWTJ-B918","lore_tm_v1_JXIGKBe3MH_Ssv2wSBWOo3y2NwAYARtBghYCODjtkt0","lore_tm_v1_SGwv0EhDuTQFSO3Q2ECEGCUhPO9V5wqW43NJ4hZry78","lore_tm_v1__30I8l2qH6nRPRn-C17Fdix-YqirZHV0yYEhhV4Kzeo","lore_tm_v1_Mqo9MeaSWH123uDh6ipnB64koWX7Pj0dVkIZ-vhTDCI"]
packages/opencode/src/session/run-state.ts defines SessionRunState.Interface with assertNotBusy(sessionID), cancel(sessionID), ensureRunning(sessionID, onInterrupt, work), and startShell(sessionID, onInterrupt, work, ready?); startShell(...) may fail with Session.BusyError.SessionRunState.Service is registered as "@opencode/SessionRunState" and its layer depends on BackgroundJob.node and SessionStatus.node.SessionRunState.state stores Map<SessionID, Runner.Runner<SessionV1.WithParts>> in InstanceState; its scope finalizer cancels every runner concurrently with { concurrency: "unbounded", discard: true } and then clears the map.SessionRunState.runner(sessionID, onInterrupt) reuses an existing per-session runner or creates one with Runner.make(...); onBusy sets { type: "busy" }, while onIdle removes the runner and sets { type: "idle" }.SessionRunState.assertNotBusy(sessionID) checks existing?.busy and raises new Session.BusyError({ sessionID }); startShell(...) maps RunnerBusy to the same session-specific busy error.SessionRunState.cancel(sessionID) first calls cancelBackgroundJobs(background, sessionID). If no runner exists, it explicitly sets session status to { type: "idle" }; otherwise it executes existing.cancel.SessionRunState.cancelBackgroundJobs(...) begins with pending = new Set<string>([sessionID]), considers only running and not-yet-cancelled jobs, and matches jobs by job ID, metadata.sessionId, or metadata.parentSessionId. It repeatedly cancels matching batches concurrently, adds cancelled job IDs and child metadata.sessionId values to pending, and continues until no matching jobs remain.packages/opencode/src/effect/runner.ts defines Runner<A, E> with observable state, busy, ensureRunning(work), startShell(work, ready?), and cancel; tagged errors are Cancelled with tag "RunnerCancelled" and Busy with tag "RunnerBusy".Runner.State<A, E> has exactly 4 variants: "Idle", "Running" with RunHandle, "Shell" with ShellHandle, and "ShellThenRun" with both a shell and pending run.RunHandle contains done: Deferred.Deferred<A, E | Cancelled> and a fiber; ShellHandle contains cancelled: Deferred.Deferred<void>, optional ready?: Latch.Latch, and a fiber; PendingHandle retains work and its completion deferred.Runner.complete(...) converts interrupt-only failed exits into RunnerCancelled; other exits complete the deferred unchanged. awaitDone(...) catches RunnerCancelled and runs configured onInterrupt, or dies with the cancellation error when no handler exists.Runner.ensureRunning(work) behavior by state: 1. "Running" and "ShellThenRun" await the existing run; 2. "Shell" queues one PendingHandle and transitions to "ShellThenRun"; 3. "Idle" starts the work in the supplied scope and transitions to "Running".finishShell(id) transitions a matching "Shell" to "Idle" and runs idle; for matching "ShellThenRun", it starts the queued work and transitions to "Running" without running idle.Runner.startShell(work, ready?) rejects every non-"Idle" state with new Busy(). From "Idle", it runs onBusy, creates a cancellation deferred, forks work as a child with Effect.ensuring(finishShell(id)), and transitions to "Shell".onInterrupt when configured; otherwise it dies with new Cancelled(). Other shell failures preserve the original cause via Effect.failCause(exit.cause).Runner.stopShell(shell) waits for shell.ready.await as an exit when a latch exists, succeeds shell.cancelled, and interrupts the shell fiber.Runner.cancel behavior by state: "Idle" does nothing; "Running" interrupts the run fiber, fails its deferred with Cancelled, and invokes idleIfCurrent(); "Shell" calls stopShell(...) and idleIfCurrent(); "ShellThenRun" stops the shell, fails the queued run deferred with Cancelled, and invokes idleIfCurrent(). All active cases transition the synchronized state to "Idle".Runner.busy is exactly state()._tag !== "Idle"; state synchronization uses SynchronizedRef.packages/opencode/src/session/status.ts defines SessionStatus.Interface with get(sessionID), list(), and set(sessionID, status), and re-exports SessionStatusEvent.Info and SessionStatusEvent as Info and Event.SessionStatus.state stores a Map<SessionID, Info> in InstanceState; get(...) defaults absent entries to { type: "idle" }, and list() returns a defensive new Map(...) copy.SessionStatus.set(...) always publishes Event.Status with { sessionID, status }. For "idle", it additionally publishes deprecated Event.Idle, deletes the map entry, and returns; non-idle statuses are stored in the map.SessionStatus.Service is registered as "@opencode/SessionStatus" and its node depends on EventV2Bridge.node.packages/schema/src/session-status-event.ts defines SessionStatusEvent.Info as a union of: 1. { type: "idle" }; 2. { type: "retry", attempt: NonNegativeInt, message: string, action?: { reason, provider, title, message, label, link?: string }, next: NonNegativeInt }; 3. { type: "busy" }. The union identifier is "SessionStatus", and optional fields use the package optional(...) helper.SessionStatusEvent.Status defines event type "session.status" with sessionID: SessionID and status: Info; deprecated SessionStatusEvent.Idle defines "session.idle" with sessionID. Definitions inventories Status and Idle.packages/schema/AGENTS.md establishes schema-package rules: browser-safe serializable contracts only; dependency direction @opencode-ai/schema <- @opencode-ai/protocol <- @opencode-ai/server; current contracts remain unversioned while legacy contracts use V1; current code must not depend on the future src/v1/ subtree; clearly V1-only events such as message.updated and message.part.* stay out of current Protocol/SDK Next surfaces unless required; public contracts use one canonical schema identity and namespace projection; exported schema values use PascalCase, combinators use camelCase, and the static combinator is statics(...).packages/schema/AGENTS.md requirements: use optional(...) unless encoded undefined is intentional; public Schema.Struct records use same-name interfaces, while unions/scalars/arrays/branded types/event helpers use aliases; public contracts are readonly; current contracts avoid Schema.Any; IDs use create() unless directional ordering is semantically required; generated ID validators must match emitted prefixes including _; public schema identifiers/brands must be stable and unique; focused contract tests cover omission of optional undefined, absence of accidental current-contract Schema.Any, identifier uniqueness, facade/schema identity, and exclusion of V1-only events from current protocol manifests.packages/opencode/src/session/processor.ts defines DOOM_LOOP_THRESHOLD = 3, Result = "compact" | "stop" | "continue", and a Handle exposing message, updateToolCall(toolCallID, update), completeToolCall(toolCallID, output), and process(streamInput).SessionProcessor.Service is registered as "@opencode/SessionProcessor"; its layer depends on Session.node, Config.node, Snapshot.node, Agent.node, LLM.node, Permission.node, Plugin.node, SessionSummary.node, SessionStatus.node, Image.node, EventV2Bridge.node, and Database.node.SessionProcessor.create(input) captures initialSnapshot = yield* snapshot.track() before starting the LLM stream because the AI SDK may execute tools before emitting start-step events. Its mutable context tracks toolcalls, shouldBreak, snapshot, blocked, needsCompaction, currentText, and reasoningMap; aborted initially equals false.MessageV2.fromError(e, { providerID: input.model.providerID, aborted }).SessionProcessor.settleToolCall(toolCallID) removes the tracked call and succeeds its completion deferred with errors ignored. readToolCall(toolCallID) reloads the persisted part via session.getPart(...); missing or non-tool parts cause the tracking entry to be deleted.SessionProcessor.updateToolCall(...) reloads the tracked tool part, applies the supplied updater, persists it through session.updatePart(...), and refreshes the tracked partID, messageID, and sessionID.SessionProcessor.completeToolCall(...) only completes a tracked tool part whose current state is "running"; it writes state "completed" with the original input, supplied output, metadata, title, optional attachments, and time { start: existingStart, end: Date.now() }.SessionV1.TextPart on "text-start" with PartID.ascending(), empty text, time.start = Date.now(), and provider metadata. "text-delta" mutates accumulated text, updates metadata when supplied, and emits session.updatePartDelta(...) for field "text". "text-end" passes completed text through plugin hook "experimental.text.complete", sets an end time, persists the part, and clears ctx.currentText.SessionProcessor.cleanup() computes snapshot.patch(ctx.snapshot) and, when patch.files.length > 0, creates a "patch" part with PartID.ascending(), patch.hash, and patch.files; it then clears ctx.snapshot.ctx.reasoningMap with end timestamps, then clears the reasoning map.Effect.timeout("250 millis") and ignored failures, concurrently with { concurrency: "unbounded" }. Remaining tracked tool parts are persisted as state "error" with exact error text "Tool execution aborted", metadata merged with { interrupted: true }, and an end timestamp; then ctx.toolcalls is cleared.ctx.assistantMessage.time.completed = Date.now() and persists the assistant message.SessionProcessor.halt(e) logs "process" with "session.id", messageID, normalized error text, and optional stack. For SessionV1.ContextOverflowError, if config.compaction?.auto === false and the assistant is not a summary, it stores the error, sets finish reason "error", publishes Session.Event.Error, and sets status idle; otherwise it sets ctx.needsCompaction = true and publishes the error. Other errors are stored on the assistant, published, and followed by idle status.SessionProcessor.process(streamInput) resets ctx.needsCompaction, sets ctx.shouldBreak according to whether experimental.continue_loop_on_deny !== true, clears current text and reasoning state, sets session status to "busy", consumes llm.stream(streamInput) through Stream.tap(handleEvent), and stops stream consumption when ctx.needsCompaction becomes true.aborted becomes true; if the assistant has no existing error, it calls halt(new DOMException("Aborted", "AbortError")). Non-interrupt-only causes are squashed and failed, retries use SessionRetry.policy(...), and retry updates set status { type: "retry", attempt, message, action, next }.Effect.catch(halt) and always runs cleanup(). Final result precedence is: return "compact" when ctx.needsCompaction; otherwise return "stop" when blocked or the assistant has an error; otherwise return "continue".!ctx.assistantMessage.summary && isOverflow({ cfg: yield* config.get(), tokens: usage.tokens, model: ctx.model }); when true, it sets ctx.needsCompaction = true./home/byk/Code/opencode/packages/opencode/src/session/llm/index.ts failed with File not found; the located LLM implementation path is /home/byk/Code/opencode/packages/opencode/src/session/llm.ts.