Dashboard › opencode › Session 18Gn2EanHFBy
18Gn2EanHFByxfKBDRead-only independent security review frozen v16. Base ab9408c81cc9916177641ae8e9f08624fc27b5b9. Patch /tmp/opencode/session-recovery-final-v16.patch SHA-256 b0e9fdde553e70f6f606c33c555f9e37bb52d6827dd1aad8d5a932b76cd2ee30. SEA /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server SHA-256 a0eea521a58325461d7e533e5f3be05fccf2714a90a444eb67ac21b153f53c2f. Verify exact immutable inputs/clean apply/34 paths and inspect all. No mutations/tests/builds/services. Focus monotonic cancellation: ordinary update rejects cancelling/cancelled; renew only execution adapter heartbeat; settleCancellation exact live cancelling; reconciliation switches all partial fragments/tool failures to cancellation-only fence before final durable Step.Interrupted sets cancelled; cleanup only clears cancelled or pre-assistant cancelling, publication defect retains cancelling; deterministic overwrite race. Reassess explicit resume intent, stale-owner/identity/replay/fairness/tools/schemas/client/auth/dependencies. Accepted check-call/process-local/skew residuals. Evidence typecheck; 228 non-migration recovery pass; 2 migration upgrade pass and script check pass despite 30s wrapper timeout; full Core 1183 pass + two contention timeouts passing alone; prior 1185/0 before final guard; exact smoke pass. Exact PASS/CONCERN/MUST-FIX file:line, end MERGE or DO-NOT-MERGE. Empty invalid; no recall.
b0e9fdde553e70f6f606c33c555f9e37bb52d6827dd1aad8d5a932b76cd2ee30 /tmp/opencode/session-recovery-final-v16.patch a0eea521a58325461d7e533e5f3be05fccf2714a90a444eb67ac21b153f53c2f /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server dc661f30cb2055ad6248fdc59b14998d834497be 261416647ae3fcff79038dddd095b0c8136e0f45 ab9408c81cc9916177641ae8e9f08624fc27b5b9 d3323b963b9ef2de41a7ff9884299c74b93886ba ## byk/cumulative...origin/dev [ahead 22] M .lore.md M AGENTS.md M packages/client/src/generated/types.ts M packages/core/schema.json M packages/core/src/database/migration.gen.ts M packages/core/src/database/migration/20260914170650_session-recovery.ts D packages/core/src/database/migration/20260914214636_session-execution.ts D packages/core/src/database/migration/20260914222526_session-execution-phase.ts M packages/core/src/database/schema.gen.ts M packages/core/src/session.ts M packages/core/src/session/compaction.ts M packages/core/src/session/context-epoch.ts M ...
ab9408c81cc9916177641ae8e9f08624fc27b5b9 dc661f30cb (HEAD -> byk/cumulative) feat(core): recover interrupted sessions packages/client/src/generated/types.ts | 72 + packages/core/schema.json | 615 ++++ packages/core/src/database/migration.gen.ts | 1 .../migration/20260914170650_session-recovery.ts | 62 packages/core/src/database/schema.gen.ts | 53 packages/core/src/session.ts | 10 packages/core/src/session/compaction.ts | 47 packages/core/src/session/context-epoch.ts | 88 - packages/core/src/session/execution/local.ts | 184 + packages/core/src/session/input.ts | 422 +++ packages/core/src/session/message-updater.ts | 69 packages/core/src/session/projector.ts | 89 + packages/core/src/session/recovery.ts | 504 ++++ packages/core/src/session/run-coordinator.ts | 35 ...
Found 73 matches /tmp/opencode/session-recovery-final-v16.patch: Line 1: diff --git a/packages/client/src/generated/types.ts b/packages/client/src/generated/types.ts Line 2: index 3b3188c874..5130fa9496 100644 Line 109: diff --git a/packages/core/schema.json b/packages/core/schema.json Line 110: index d0eeeebd5c..81e5eca808 100644 Line 1025: diff --git a/packages/core/src/database/migration.gen.ts b/packages/core/src/database/migration.gen.ts Line 1026: index e6ea4eaa14..77948f1529 100644 Line 1036: diff --git a/packages/core/src/database/migration/20260914170650_session-recovery.ts b/packages/core/src/database/migration/20260914170650_session-recovery.ts Line 1037: new file mode 100644 Line 1038: index 0000000000..20eb1a4373 Line 1104: diff --git a/packages/core/src/database/schema.gen.ts b/packages/core/src/database/schema.gen.ts Line 1105: index ed60fde6c5..94881e7038 100644 Line 1210: diff --git a/packages/core/src/session.ts ...
paths 34 blob_mismatches 0 fatal: path 'packages/core/src/database/migration/20260914170650_session-recovery.ts' exists on disk, but not in 'ab9408c81cc9916177641ae8e9f08624fc27b5b9' fatal: path 'packages/core/src/session/recovery.ts' exists on disk, but not in 'ab9408c81cc9916177641ae8e9f08624fc27b5b9' fatal: path 'packages/core/test/session-execution-local.test.ts' exists on disk, but not in 'ab9408c81cc9916177641ae8e9f08624fc27b5b9' fatal: path 'packages/core/src/session/execution/claim.ts' exists on disk, but not in 'ab9408c81cc9916177641ae8e9f08624fc27b5b9' fatal: path 'packages/core/src/session/recovery-id.ts' exists on disk, but not in 'ab9408c81cc9916177641ae8e9f08624fc27b5b9'
<path>/home/byk/Code/opencode/packages/core/src/session/execution/claim.ts</path>
<type>file</type>
<content>
1: export * as SessionExecutionClaim from "./claim"
2:
3: import { and, eq, gt, notInArray } from "drizzle-orm"
4: import { Clock, Effect } from "effect"
5: import type { Database } from "../../database/database"
6: import type { SessionSchema } from "../schema"
7: import { SESSION_EXECUTION_LEASE_MS, SessionExecutionTable } from "../sql"
8:
9: type DatabaseService = Database.Interface["db"]
10:
11: export type Claim = {
12: readonly sessionID: SessionSchema.ID
13: readonly executionID: string
14: readonly ownerID: string
15: }
16:
17: export type Values = Partial<
18: Pick<typeof SessionExecutionTable.$inferInsert, "assistant_message_id" | "assistant_seq" | "phase">
19: >
20:
21: export class Lost extends Error {
22: constructor(readonly claim: Claim) {
23: super(`Session execution claim lost: ${claim.executionID}`)
24: }
25: }
26:
27: const where = ...
<path>/home/byk/Code/opencode/packages/core/src/session/execution/local.ts</path>
<type>file</type>
<content>
1: import { and, asc, desc, eq, isNull } from "drizzle-orm"
2: import { Cause, Clock, Duration, Effect, Exit, Layer, Schedule } from "effect"
3: import { Database } from "../../database/database"
4: import { LocationServiceMap } from "../../location-service-map"
5: import { makeGlobalNode } from "../../effect/app-node"
6: import { SessionRunCoordinator } from "../run-coordinator"
7: import { SessionRunner } from "../runner"
8: import { SessionMessage } from "../message"
9: import { SessionSchema } from "../schema"
10: import { SessionStore } from "../store"
11: import { SessionExecution } from "../execution"
12: import { SessionExecutionClaim } from "./claim"
13: import {
14: SESSION_EXECUTION_LEASE_MS,
15: SessionExecutionTable,
16: SessionMessageTable,
17: SessionRecoveryTable,
18: } from "../sql"
19:
20: /** Current-process routing for implicit-local Locations. ...
<path>/home/byk/Code/opencode/packages/core/src/session/recovery.ts</path>
<type>file</type>
<content>
1: export * as SessionRecovery from "./recovery"
2:
3: import { and, asc, desc, eq, exists, gt, isNull, lte, or, sql } from "drizzle-orm"
4: import { Clock, DateTime, Effect, Layer, Option, Schedule, Schema } from "effect"
5: import { Database } from "../database/database"
6: import { makeGlobalNode } from "../effect/app-node"
7: import { EventV2 } from "../event"
8: import { SessionEvent } from "./event"
9: import { SessionExecution } from "./execution"
10: import { SessionProjector } from "./projector"
11: import { SessionExecutionClaim } from "./execution/claim"
12: import { SessionInput } from "./input"
13: import { continuation } from "./recovery-id"
14: import { SessionSchema } from "./schema"
15: import {
16: MAX_WAKE_ATTEMPTS,
17: SESSION_EXECUTION_LEASE_MS,
18: SessionExecutionTable,
19: SessionInputTable,
20: SessionRecoveryTable,
21: SessionMessageTable,
22: ...
<path>/home/byk/Code/opencode/packages/core/src/session/input.ts</path>
<type>file</type>
<content>
1: export * as SessionInput from "./input"
2:
3: import { and, asc, desc, eq, isNull, lte } from "drizzle-orm"
4: import { DateTime, Effect, Option, Schema } from "effect"
5: import { Admitted, Delivery } from "@opencode-ai/schema/session-input"
6: import type { Database } from "../database/database"
7: import { EventV2 } from "../event"
8: import { SessionEvent } from "./event"
9: import { SessionMessage } from "./message"
10: import { Prompt } from "./prompt"
11: import { continuation, message } from "./recovery-id"
12: import { SessionSchema } from "./schema"
13: import { SessionInputTable, SessionMessageTable, SessionRecoveryTable, SessionTable } from "./sql"
14:
15: type DatabaseService = Database.Interface["db"]
16:
17: export { Admitted, Delivery }
18:
19: const decodePrompt = Schema.decodeUnknownSync(Prompt)
20: const encodePrompt = Schema.encodeSync(Prompt)
21: const ...
<path>/home/byk/Code/opencode/packages/core/src/session/runner/llm.ts</path>
<type>file</type>
<content>
1: import {
2: LLM,
3: LLMClient,
4: LLMError,
5: LLMEvent,
6: Message,
7: SystemPart,
8: isContextOverflowFailure,
9: type ProviderErrorEvent,
10: } from "@opencode-ai/llm"
11: import { Cause, DateTime, Effect, Exit, Fiber, Layer, Option, Semaphore, Stream } from "effect"
12: import { and, eq } from "drizzle-orm"
13: import { AgentV2 } from "../../agent"
14: import { Config } from "../../config"
15: import { Database } from "../../database/database"
16: import { EventV2 } from "../../event"
17: import { Location } from "../../location"
18: import { ModelV2 } from "../../model"
19: import { PermissionV2 } from "../../permission"
20: import { ProviderV2 } from "../../provider"
21: import { QuestionV2 } from "../../question"
22: import { SystemContext } from "../../system-context/index"
23: import { SystemContextRegistry } from "../../system-context/registry"
24: ...
<path>/home/byk/Code/opencode/packages/core/src/session/runner/publish-llm-event.ts</path>
<type>file</type>
<content>
1: import { ToolOutput, type LLMEvent, type ProviderMetadata, type ToolResultValue, type Usage } from "@opencode-ai/llm"
2: import { DateTime, Effect } from "effect"
3: import { EventV2 } from "../../event"
4: import { ModelV2 } from "../../model"
5: import { SessionEvent } from "../event"
6: import { SessionMessage } from "../message"
7: import { SessionSchema } from "../schema"
8:
9: type Input = {
10: readonly sessionID: SessionSchema.ID
11: readonly agent: string
12: readonly model: ModelV2.Ref
13: readonly snapshot?: string
14: readonly startCommit: (assistantMessageID: SessionMessage.ID, seq: number) => Effect.Effect<void>
15: readonly eventCommit: () => Effect.Effect<void>
16: }
17:
18: const safe = (value: number | undefined) => Math.max(0, Number.isFinite(value) ? (value ?? ...
<path>/home/byk/Code/opencode/packages/core/src/session/context-epoch.ts</path>
<type>file</type>
<content>
1: export * as SessionContextEpoch from "./context-epoch"
2:
3: import { eq } from "drizzle-orm"
4: import { DateTime, Effect, Schema } from "effect"
5: import type { Database } from "../database/database"
6: import { EventV2 } from "../event"
7: import { SystemContext } from "../system-context/index"
8: import { ContextSnapshotDecodeError } from "./error"
9: import { SessionEvent } from "./event"
10: import { SessionHistory } from "./history"
11: import { SessionInput } from "./input"
12: import { SessionMessage } from "./message"
13: import { SessionSchema } from "./schema"
14: import { SessionContextEpochTable } from "./sql"
15: import { SessionExecutionClaim } from "./execution/claim"
16:
17: type DatabaseService = Database.Interface["db"]
18:
19: interface Prepared {
20: readonly baseline: string
21: readonly baselineSeq: number
22: }
23:
24: export function ...
<path>/home/byk/Code/opencode/packages/core/src/session/projector.ts</path>
<type>file</type>
<content>
1: export * as SessionProjector from "./projector"
2:
3: import { and, desc, eq, gt, or, sql } from "drizzle-orm"
4: import { DateTime, Effect, Layer, Schema } from "effect"
5: import { Database } from "../database/database"
6: import { EventV2 } from "../event"
7: import { makeGlobalNode } from "../effect/app-node"
8: import { SessionEvent } from "./event"
9: import { SessionV1 } from "../v1/session"
10: import { WorkspaceTable } from "../control-plane/workspace.sql"
11: import { SessionMessage } from "./message"
12: import { SessionMessageUpdater } from "./message-updater"
13: import { SessionInput } from "./input"
14: import { Prompt } from "./prompt"
15: import { continuation } from "./recovery-id"
16: import { WorkspaceV2 } from "../workspace"
17: import {
18: MessageTable,
19: PartTable,
20: SessionInputTable,
21: SessionMessageTable,
22: SessionRecoveryTable,
23: ...
<path>/home/byk/Code/opencode/packages/core/src/session/message-updater.ts</path>
<type>file</type>
<content>
1: import { castDraft, produce, type WritableDraft } from "immer"
2: import { Effect } from "effect"
3: import { SessionEvent } from "./event"
4: import { SessionMessage } from "./message"
5: import { message } from "./recovery-id"
6:
7: export type MemoryState = {
8: messages: SessionMessage.Message[]
9: }
10:
11: export interface Adapter {
12: readonly getCurrentAssistant: () => Effect.Effect<SessionMessage.Assistant | undefined>
13: readonly getAssistant: (messageID: SessionMessage.ID) => Effect.Effect<SessionMessage.Assistant | undefined>
14: readonly getCurrentShell: (callID: string) => Effect.Effect<SessionMessage.Shell | undefined>
15: readonly updateAssistant: (assistant: SessionMessage.Assistant) => Effect.Effect<void>
16: readonly updateShell: (shell: SessionMessage.Shell) => Effect.Effect<void>
17: readonly appendMessage: (message: ...
<path>/home/byk/Code/opencode/packages/core/src/session/compaction.ts</path>
<type>file</type>
<content>
1: export * as SessionCompaction from "./compaction"
2:
3: import { LLM, LLMError, LLMEvent, Message, type LLMRequest, type Model } from "@opencode-ai/llm"
4: import { DateTime, Effect, Stream } from "effect"
5: import type { Config } from "../config"
6: import type { EventV2 } from "../event"
7: import { SessionEvent } from "./event"
8: import { SessionMessage } from "./message"
9: import { SessionSchema } from "./schema"
10: import { Token } from "../util/token"
11:
12: const DEFAULT_BUFFER = 20_000
13: const DEFAULT_KEEP_TOKENS = 8_000
14: const TOOL_OUTPUT_MAX_CHARS = 2_000
15: const SUMMARY_OUTPUT_TOKENS = 4_096
16: const SUMMARY_TEMPLATE = `Output exactly the Markdown structure shown inside <template> and keep the section order unchanged. Do not include the <template> tags in your response. ...
<path>/home/byk/Code/opencode/packages/core/src/session.ts</path>
<type>file</type>
<content>
1: export * as SessionV2 from "./session"
2: export * from "./session/schema"
3:
4: import { DateTime, Effect, Layer, Schema, Context, Stream } from "effect"
5: import { ListAnchor } from "@opencode-ai/schema/session"
6: import { and, asc, desc, eq, gt, like, lt, or, type SQL } from "drizzle-orm"
7: import { ProjectV2 } from "./project"
8: import { WorkspaceV2 } from "./workspace"
9: import { ModelV2 } from "./model"
10: import { Location } from "./location"
11: import { SessionMessage } from "./session/message"
12: import { Prompt } from "./session/prompt"
13: import { PromptInput } from "@opencode-ai/schema/prompt-input"
14: import { EventV2 } from "./event"
15: import { Database } from "./database/database"
16: import { SessionProjector } from "./session/projector"
17: import { SessionMessageTable, SessionTable } from "./session/sql"
18: import { SessionSchema } from ...
<path>/home/byk/Code/opencode/packages/core/src/session.ts</path>
<type>file</type>
<content>
401: })
402: }),
403: switchModel: Effect.fn("V2Session.switchModel")(function* (input) {
404: const session = yield* result.get(input.sessionID)
405: if (
406: session.model?.providerID === input.model.providerID &&
407: session.model.id === input.model.id &&
408: (session.model.variant ?? "default") === (input.model.variant ?? "default")
409: )
410: return
411: yield* events.publish(SessionEvent.ModelSwitched, {
412: sessionID: input.sessionID,
413: messageID: SessionMessage.ID.create(),
414: timestamp: yield* DateTime.now,
415: model: input.model,
416: })
417: }),
418: compact: Effect.fn("V2Session.compact")(function* (input) {
419: yield* result.get(input.sessionID)
420: return yield* new OperationUnavailableError({ ...
<path>/home/byk/Code/opencode/packages/core/src/session/sql.ts</path>
<type>file</type>
<content>
1: import { sql } from "drizzle-orm"
2: import { check, sqliteTable, text, integer, index, primaryKey, real, uniqueIndex } from "drizzle-orm/sqlite-core"
3: import * as DatabasePath from "../database/path"
4: import { ProjectTable } from "../project/sql"
5: import type { SessionMessage } from "./message"
6: import type { Prompt } from "./prompt"
7: import type { SessionInput } from "./input"
8: import type { Snapshot } from "../snapshot"
9: import { PermissionV1 } from "../v1/permission"
10: import { ProjectV2 } from "../project"
11: import type { SessionSchema } from "./schema"
12: import type { MessageID, PartID, SessionV1 } from "../v1/session"
13: import { WorkspaceV2 } from "../workspace"
14: import { Timestamps } from "../database/schema.sql"
15: import type { SystemContext } from "../system-context/index"
16: import { AgentV2 } from "../agent"
17: import type { Revert } from ...
<path>/home/byk/Code/opencode/packages/core/src/database/migration/20260914170650_session-recovery.ts</path>
<type>file</type>
<content>
1: import { Effect } from "effect"
2: import type { DatabaseMigration } from "../migration"
3:
4: export default {
5: id: "20260914170650_session-recovery",
6: up(tx) {
7: return Effect.gen(function* () {
8: yield* tx.run(`ALTER TABLE \`session_input\` ADD \`wake_pending\` integer DEFAULT false NOT NULL;`)
9: yield* tx.run(
10: `ALTER TABLE \`session\` ADD \`wake_attempts\` integer DEFAULT 0 NOT NULL CONSTRAINT \`session_wake_attempts_check\` CHECK(\`wake_attempts\` >= 0 AND \`wake_attempts\` <= 9007199254740991);`,
11: )
12: yield* tx.run(`
13: CREATE TABLE \`session_execution\` (
14: \`id\` text NOT NULL,
15: \`session_id\` text NOT NULL,
16: \`owner_id\` text NOT NULL,
17: \`assistant_message_id\` text,
18: \`phase\` text NOT NULL,
19: ...
Found 21 matches
/home/byk/Code/opencode/packages/core/src/database/schema.gen.ts:
Line 158: CREATE TABLE \`session_execution\` (
Line 168: CONSTRAINT \`session_execution_pk\` PRIMARY KEY(\`id\`),
Line 169: CONSTRAINT \`fk_session_execution_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE,
Line 170: CONSTRAINT "session_execution_phase_check" CHECK("phase" IN ('ready', 'safe', 'unknown', 'continue', 'cancelling', 'cancelled'))
Line 181: \`wake_pending\` integer DEFAULT false NOT NULL,
Line 199: CREATE TABLE \`session_recovery\` (
Line 205: \`wake_pending\` integer DEFAULT true NOT NULL,
Line 206: \`wake_attempts\` integer DEFAULT 0 NOT NULL,
Line 209: CONSTRAINT \`session_recovery_pk\` PRIMARY KEY(\`execution_id\`),
Line 210: CONSTRAINT \`fk_session_recovery_session_id_session_id_fk\` FOREIGN KEY ...
<path>/home/byk/Code/opencode/packages/core/src/database/schema.gen.ts</path> <type>file</type> <content> 145: CONSTRAINT \`fk_part_message_id_message_id_fk\` FOREIGN KEY (\`message_id\`) REFERENCES \`message\`(\`id\`) ON DELETE CASCADE 146: ); 147: `) 148: yield* tx.run(` 149: CREATE TABLE \`session_context_epoch\` ( 150: \`session_id\` text PRIMARY KEY, 151: \`baseline\` text NOT NULL, 152: \`snapshot\` text NOT NULL, 153: \`baseline_seq\` integer NOT NULL, 154: CONSTRAINT \`fk_session_context_epoch_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE 155: ); 156: `) 157: yield* tx.run(` 158: CREATE TABLE \`session_execution\` ( 159: \`id\` text NOT NULL, 160: \`session_id\` text NOT NULL, 161: \`owner_id\` text NOT NULL, 162: \`assistant_message_id\` text, 163: ...
<path>/home/byk/Code/opencode/packages/core/src/database/migration.gen.ts</path>
<type>file</type>
<content>
1: import type { DatabaseMigration } from "./migration"
2:
3: export const migrations = (
4: await Promise.all([
5: import("./migration/20260127222353_familiar_lady_ursula"),
6: import("./migration/20260211171708_add_project_commands"),
7: import("./migration/20260213144116_wakeful_the_professor"),
8: import("./migration/20260225215848_workspace"),
9: import("./migration/20260227213759_add_session_workspace_id"),
10: import("./migration/20260228203230_blue_harpoon"),
11: import("./migration/20260303231226_add_workspace_fields"),
12: import("./migration/20260309230000_move_org_to_state"),
13: import("./migration/20260312043431_session_message_cursor"),
14: import("./migration/20260323234822_events"),
15: import("./migration/20260410174513_workspace-name"),
16: import("./migration/20260413175956_chief_energizer"),
17: ...
<path>/home/byk/Code/opencode/packages/core/src/session/run-coordinator.ts</path>
<type>file</type>
<content>
1: export * as SessionRunCoordinator from "./run-coordinator"
2:
3: import { Deferred, Effect, Exit, Fiber, FiberSet, Scope } from "effect"
4:
5: /** Serializes execution for each key while allowing different keys to run concurrently. */
6: export interface Coordinator<Key, E> {
7: /** Snapshots keys with an execution owned by this coordinator. */
8: readonly active: Effect.Effect<ReadonlySet<Key>>
9: /** Starts execution while idle or joins the active execution. */
10: readonly run: (key: Key) => Effect.Effect<void, E>
11: /** Registers one coalesced follow-up after newly recorded work. */
12: readonly wake: (key: Key) => Effect.Effect<void>
13: /** Stops active execution, runs cleanup, then starts work that arrived while stopping. */
14: readonly interrupt: (key: Key, cleanup?: Effect.Effect<void>) => Effect.Effect<void>
15: }
16:
17: type Entry<E> = {
18: ...
<path>/home/byk/Code/opencode/packages/core/src/session/runner/index.ts</path>
<type>file</type>
<content>
1: export * as SessionRunner from "./index"
2:
3: import type { LLMError } from "@opencode-ai/llm"
4: import { Context, Effect } from "effect"
5: import { SessionSchema } from "../schema"
6: import type { SessionMessage } from "../message"
7: import type { ContextSnapshotDecodeError, MessageDecodeError } from "../error"
8: import { SessionRunnerModel } from "./model"
9: import type { SystemContext } from "../../system-context/index"
10: import type { ToolOutputStore } from "../../tool-output-store"
11:
12: export type RunError =
13: | LLMError
14: | SessionRunnerModel.Error
15: | MessageDecodeError
16: | ContextSnapshotDecodeError
17: | SystemContext.InitializationBlocked
18: | ToolOutputStore.Error
19:
20: /** Runs one local continuation from already-recorded Session history. */
21: export interface Interface {
22: /** Drains eligible durable work. ...
<path>/home/byk/Code/opencode/packages/core/src/session/execution.ts</path>
<type>file</type>
<content>
1: export * as SessionExecution from "./execution"
2:
3: import { Context, Effect, Layer } from "effect"
4: import { LayerNode } from "../effect/layer-node"
5: import { Node } from "../effect/app-node"
6: import { SessionRunner } from "./runner/index"
7: import { SessionSchema } from "./schema"
8:
9: export interface Interface {
10: /** Snapshots active execution owned by this process. */
11: readonly active: Effect.Effect<ReadonlySet<SessionSchema.ID>>
12: /** Starts execution while idle or joins the active execution. */
13: readonly resume: (sessionID: SessionSchema.ID) => Effect.Effect<void, SessionRunner.RunError>
14: /** Registers newly recorded work. Repeated wakeups may coalesce. */
15: readonly wake: (sessionID: SessionSchema.ID) => Effect.Effect<void>
16: /** Interrupt active work owned by this process. Idle interruption is a no-op. ...
<path>/home/byk/Code/opencode/packages/schema/src/session-event.ts</path>
<type>file</type>
<content>
1: export * as SessionEvent from "./session-event"
2:
3: import { Schema } from "effect"
4: import { optional } from "./schema"
5: import { Event } from "./event"
6: import { ProviderMetadata, ToolContent } from "./llm"
7: import { Delivery } from "./session-delivery"
8: import { Model } from "./model"
9: import { DateTimeUtcFromMillis, NonNegativeInt, RelativePath } from "./schema"
10: import { FileAttachment, Prompt } from "./prompt"
11: import { SessionID } from "./session-id"
12: import { Location } from "./location"
13: import { SessionMessage } from "./session-message"
14: import { Revert } from "./revert"
15:
16: export { FileAttachment }
17:
18: export const Source = Schema.Struct({
19: start: NonNegativeInt,
20: end: NonNegativeInt,
21: text: Schema.String,
22: }).annotate({
23: identifier: "session.next.event.source",
24: })
25: export interface Source extends ...
<path>/home/byk/Code/opencode/packages/schema/src/session-event.ts</path> <type>file</type> <content> 484: export const DurableDefinitions = Event.inventory( 485: AgentSwitched, 486: ModelSwitched, 487: Moved, 488: Prompted, 489: PromptAdmitted, 490: PromptExecutionRequested, 491: ContextUpdated, 492: Synthetic, 493: Shell.Started, 494: Shell.Ended, 495: Step.Started, 496: Step.Ended, 497: Step.Failed, 498: Step.Interrupted, 499: Step.Recovered, 500: Text.Started, 501: Text.Ended, 502: Tool.Input.Started, 503: Tool.Input.Ended, 504: Tool.Called, 505: Tool.Progress, 506: Tool.Success, 507: Tool.Failed, 508: Reasoning.Started, 509: Reasoning.Ended, 510: Retried, 511: Compaction.Started, 512: Compaction.Ended, 513: RevertEvent.Staged, 514: RevertEvent.Cleared, 515: RevertEvent.Committed, 516: ) 517: 518: export const Definitions = Event.inventory( 519: AgentSwitched, 520: ModelSwitched, 521: Moved, 522: Prompted, 523: ...
<path>/home/byk/Code/opencode/packages/opencode/src/server/routes/instance/httpapi/server.ts</path>
<type>file</type>
<content>
1: import { Config as EffectConfig, Context, Effect, Layer } from "effect"
2: import { HttpApiBuilder, OpenApi } from "effect/unstable/httpapi"
3: import { HttpClient, HttpMiddleware, HttpRouter, HttpServer, HttpServerResponse } from "effect/unstable/http"
4: import * as Socket from "effect/unstable/socket/Socket"
5: import { FSUtil } from "@opencode-ai/core/fs-util"
6: import * as Observability from "@opencode-ai/core/observability"
7: import { Account } from "@/account/account"
8: import { Agent } from "@/agent/agent"
9: import { Auth } from "@/auth"
10: import { BackgroundJob } from "@/background/job"
11: import { Command } from "@/command"
12: import { Config } from "@/config/config"
13: import { Workspace } from "@/control-plane/workspace"
14: import { Env } from "@/env"
15: import { EventV2Bridge } from "@/event-v2-bridge"
16: import { Format } from ...
<path>/home/byk/Code/opencode/packages/opencode/src/server/routes/instance/httpapi/server.ts</path> <type>file</type> <content> 213: const app = LayerNode.group([ 214: Npm.node, 215: FSUtil.node, 216: Database.node, 217: Auth.node, 218: Account.node, 219: Config.node, 220: Env.node, 221: Git.node, 222: Ripgrep.node, 223: Storage.node, 224: Snapshot.node, 225: Plugin.node, 226: ModelsDev.node, 227: Provider.node, 228: ProviderAuth.node, 229: Agent.node, 230: Skill.node, 231: Discovery.node, 232: Question.node, 233: Permission.node, 234: PermissionSaved.node, 235: Todo.node, 236: Session.node, 237: SessionProjector.node, 238: SessionStatus.node, 239: BackgroundJob.node, 240: RuntimeFlags.node, 241: EventV2Bridge.node, 242: SessionRunState.node, 243: SessionProcessor.node, 244: SessionCompaction.node, 245: SessionRevert.node, 246: SessionSummary.node, 247: SessionPrompt.node, 248: Instruction.node, 249: ...
<path>/home/byk/Code/opencode/packages/server/src/routes.ts</path>
<type>file</type>
<content>
1: import { Database } from "@opencode-ai/core/database/database"
2: import { LayerNode } from "@opencode-ai/core/effect/layer-node"
3: import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
4: import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
5: import { EventV2 } from "@opencode-ai/core/event"
6: import { Credential } from "@opencode-ai/core/credential"
7: import { PermissionSaved } from "@opencode-ai/core/permission/saved"
8: import { PtyTicket } from "@opencode-ai/core/pty/ticket"
9: import { SessionV2 } from "@opencode-ai/core/session"
10: import { SessionExecution } from "@opencode-ai/core/session/execution"
11: import { LocationServiceMap } from "@opencode-ai/core/location-service-map"
12: import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
13: import { SessionRecovery } from ...
Found 38 matches /home/byk/Code/opencode/packages/client/src/generated/types.ts: Line 778: readonly requestExecution?: boolean Line 784: readonly type: "session.next.prompt.execution_requested" Line 851: readonly assistantMessageID: string Line 866: readonly assistantMessageID: string Line 888: readonly assistantMessageID: string Line 901: readonly assistantMessageID: string Line 908: readonly type: "session.next.step.recovered" Line 914: readonly executionID: string Line 915: readonly assistantMessageID?: string Line 928: readonly assistantMessageID: string Line 941: readonly assistantMessageID: string Line 955: readonly assistantMessageID: string Line 969: readonly assistantMessageID: string Line 983: readonly assistantMessageID: string Line 1002: readonly assistantMessageID: string Line 1020: ...
<path>/home/byk/Code/opencode/packages/client/src/generated/types.ts</path>
<type>file</type>
<content>
740: readonly mime: string
741: readonly name?: string
742: readonly description?: string
743: readonly source?: { readonly start: number; readonly end: number; readonly text: string }
744: }>
745: readonly agents?: ReadonlyArray<{
746: readonly name: string
747: readonly source?: { readonly start: number; readonly end: number; readonly text: string }
748: }>
749: }
750: readonly delivery: "steer" | "queue"
751: }
752: }
753: | {
754: readonly id: string
755: readonly metadata?: { readonly [x: string]: JsonValue }
756: readonly type: "session.next.prompt.admitted"
757: readonly durable?: { readonly aggregateID: string; readonly seq: number; readonly version: number }
758: readonly ...
Found 12 matches /home/byk/Code/opencode/packages/sdk/js/src/v2/gen/types.gen.ts: Line 874: requestExecution?: boolean Line 879: type: "session.next.prompt.execution_requested" Line 983: type: "session.next.step.recovered" Line 3430: requestExecution?: boolean Line 3439: type: "session.next.prompt.execution_requested.1" Line 3606: type: "session.next.step.recovered.1" Line 4362: requestExecution?: boolean Line 4371: type: "session.next.prompt.execution_requested" Line 4565: type: "session.next.step.recovered" Line 6464: requestExecution?: boolean Line 6470: type: "session.next.prompt.execution_requested" Line 6583: type: "session.next.step.recovered"
<path>/home/byk/Code/opencode/packages/sdk/js/src/v2/gen/types.gen.ts</path>
<type>file</type>
<content>
840: messageID: string
841: model: ModelRef
842: }
843: }
844: | {
845: id: string
846: type: "session.next.moved"
847: properties: {
848: timestamp: number
849: sessionID: string
850: location: LocationRef
851: subdirectory?: string
852: }
853: }
854: | {
855: id: string
856: type: "session.next.prompted"
857: properties: {
858: timestamp: number
859: sessionID: string
860: messageID: string
861: prompt: Prompt
862: delivery: "steer" | "queue"
863: }
864: }
865: | {
866: id: string
867: type: "session.next.prompt.admitted"
868: properties: {
869: timestamp: number
870: sessionID: string
871: messageID: string
872: ...
Found 1 matches
/home/byk/Code/opencode/packages/core/schema.json:
Line 2571: "value": "\"phase\" IN ('ready', 'safe', 'unknown', 'continue', 'cancelling', 'cancelled')",
<path>/home/byk/Code/opencode/packages/core/schema.json</path>
<type>file</type>
<content>
2380: "isExpression": false
2381: },
2382: {
2383: "value": "session_id",
2384: "isExpression": false
2385: }
2386: ],
2387: "isUnique": false,
2388: "where": null,
2389: "origin": "manual",
2390: "name": "session_input_wake_pending_promoted_session_idx",
2391: "entityType": "indexes",
2392: "table": "session_input"
2393: },
2394: {
2395: "columns": [
2396: {
2397: "value": "session_id",
2398: "isExpression": false
2399: },
2400: {
2401: "value": "seq",
2402: "isExpression": false
2403: }
2404: ],
2405: "isUnique": true,
2406: "where": null,
2407: "origin": "manual",
2408: "name": "session_message_session_seq_idx",
2409: "entityType": "indexes",
2410: "table": ...
Found 3 matches /home/byk/Code/opencode/packages/core/schema.json: Line 66: "name": "session_execution", Line 70: "name": "session_input", Line 78: "name": "session_recovery",
Found 10 matches /home/byk/Code/opencode/packages/core/schema.json: Line 499: "name": "owner_id", Line 959: "name": "owner_id", Line 989: "name": "assistant_seq", Line 1019: "name": "recovery_error", Line 1089: "name": "wake_pending", Line 1209: "name": "continuation_message_id", Line 1229: "name": "wake_pending", Line 1239: "name": "wake_attempts", Line 1249: "name": "recovery_error", Line 1559: "name": "wake_attempts",
<path>/home/byk/Code/opencode/packages/core/schema.json</path>
<type>file</type>
<content>
900: "entityType": "columns",
901: "table": "session_context_epoch"
902: },
903: {
904: "type": "text",
905: "notNull": true,
906: "autoincrement": false,
907: "default": null,
908: "generated": null,
909: "name": "baseline",
910: "entityType": "columns",
911: "table": "session_context_epoch"
912: },
913: {
914: "type": "text",
915: "notNull": true,
916: "autoincrement": false,
917: "default": null,
918: "generated": null,
919: "name": "snapshot",
920: "entityType": "columns",
921: "table": "session_context_epoch"
922: },
923: {
924: "type": "integer",
925: "notNull": true,
926: "autoincrement": false,
927: "default": null,
928: "generated": null,
929: "name": "baseline_seq",
930: "entityType": "columns",
931: "table": ...
<path>/home/byk/Code/opencode/packages/core/src/session/recovery-id.ts</path>
<type>file</type>
<content>
1: import { SessionMessage } from "./message"
2:
3: export const message = (executionID: string, assistantMessageID?: SessionMessage.ID) =>
4: assistantMessageID ?? SessionMessage.ID.make(`msg_recovery_${executionID}`)
5:
6: export const continuation = (executionID: string) => SessionMessage.ID.make(`msg_recovery_continue_${executionID}`)
(End of file - total 6 lines)
</content>
Found 84 matches
/tmp/opencode/session-recovery-final-v16.patch:
Line 4223: + test("adds final recovery ownership tables to a populated predecessor", async () => {
Line 4340: + it.effect("clears the claim after a successful drain", () =>
Line 4349: + it.effect("snapshots the latest assistant sequence when acquiring a claim", () =>
Line 4381: + it.effect("preserves the claim when its scope closes", () =>
Line 4397: + it.effect("clears the claim after explicit interruption", () =>
Line 4411: + it.effect("never starts a second owner while the lease is live", () =>
Line 4434: + it.effect("never overwrites an expired lease", () =>
Line 4461: + it.effect("never re-enters its own uncertain live lease", () =>
Line 4488: + it.effect("renews heartbeat expiry from the current clock", () =>
Line 4511: + it.effect("never revives an expired claim on heartbeat", () =>
Line 4529: + it.effect("settles cancellation before starting a pending successor", () =>
...
<path>/home/byk/Code/opencode/packages/core/test/session-execution-local.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect } from "bun:test"
2: import { Deferred, Effect, Exit, Fiber, Scope } from "effect"
3: import { TestClock } from "effect/testing"
4: import { eq, sql } from "drizzle-orm"
5: import { Database } from "@opencode-ai/core/database/database"
6: import { Project } from "@opencode-ai/core/project"
7: import { ProjectTable } from "@opencode-ai/core/project/sql"
8: import { AbsolutePath } from "@opencode-ai/core/schema"
9: import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
10: import { SessionExecutionClaim } from "@opencode-ai/core/session/execution/claim"
11: import { SessionMessage } from "@opencode-ai/core/session/message"
12: import { SessionSchema } from "@opencode-ai/core/session/schema"
13: import { SessionExecutionTable, SessionTable } from "@opencode-ai/core/session/sql"
14: import { testEffect } from ...
<path>/home/byk/Code/opencode/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
3000: yield* (yield* SessionExecution.Service).wake(sessionID)
3001: yield* Effect.yieldNow
3002: expect(requests).toHaveLength(2)
3003: }),
3004: )
3005:
3006: it.effect("runs steering input accepted while the active provider turn fails", () =>
3007: Effect.gen(function* () {
3008: yield* setup
3009: const session = yield* SessionV2.Service
3010: yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Start working" }), resume: false })
3011:
3012: requests.length = 0
3013: responses = undefined
3014: response = []
3015: streamFailure = providerUnavailable()
3016: streamGate = yield* Deferred.make<void>()
3017: streamStarted = yield* Deferred.make<void>()
3018:
3019: const first = yield* session.resume(sessionID).pipe(Effect.forkChild)
3020: yield* ...
<path>/home/byk/Code/opencode/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
3680: ]
3681:
3682: yield* session.resume(sessionID)
3683:
3684: expect(requests).toHaveLength(2)
3685: expect(yield* session.context(sessionID)).toMatchObject([
3686: { type: "user", text: "Call corrected" },
3687: {
3688: type: "assistant",
3689: content: [
3690: { type: "tool", id: "call-corrected", state: { status: "error", error: { message: "Use another tool" } } },
3691: ],
3692: },
3693: { type: "assistant", finish: "stop" },
3694: ])
3695: }),
3696: )
3697:
3698: it.effect("interrupts runner continuation when a question is dismissed", () =>
3699: Effect.gen(function* () {
3700: yield* setup
3701: const session = yield* SessionV2.Service
3702: const registry = yield* ToolRegistry.Service
3703: const questions = yield* ...
Found 7 matches
/home/byk/Code/opencode/packages/core/test/session-runner.test.ts:
Line 572: const verifyPartialFlushOnInterruption = (kind: FragmentKind) =>
Line 2055: it.effect("keeps a running assistant recoverable when Step failure publication defects", () =>
Line 2091: it.effect("never records assistant start state when Step start publication defects", () =>
Line 2128: it.effect("durably reconciles a local tool when success publication defects", () =>
Line 3906: it.effect("retains cancellation ownership when interrupted tool publication defects", () =>
Line 3940: expect(yield* db.select().from(SessionExecutionTable).get()).toMatchObject({ phase: "cancelling" })
Line 4426: verifyPartialFlushOnInterruption(kind),
<path>/home/byk/Code/opencode/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
430: readonly delta: EventV2.Definition
431: readonly completeEvents: LLMEvent[]
432: readonly partialEvents: LLMEvent[]
433: readonly expectedAssistant: unknown
434: readonly expectedContent: unknown
435: }
436:
437: const fragmentKinds: readonly FragmentKind[] = ["text", "reasoning", "tool input"]
438:
439: const fragmentID = (kind: FragmentKind, suffix: string) => `${kind === "tool input" ? "call" : kind}-${suffix}`
440:
441: const fragmentFixture = (kind: FragmentKind, id: string, chunks: readonly string[]): FragmentFixture => {
442: const text = chunks.join("")
443: switch (kind) {
444: case "text": {
445: const partialEvents = [
446: LLMEvent.stepStart({ index: 0 }),
447: LLMEvent.textStart({ id }),
448: ...chunks.map((text) => LLMEvent.textDelta({ id, text })),
449: ]
450: const expectedContent = { type: ...
<path>/home/byk/Code/opencode/packages/schema/test/event-manifest.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect, test } from "bun:test"
2: import { FileSystem, Integration, Permission, Project, Reference, Session, Workspace } from "../src"
3: import { EventManifest } from "../src/event-manifest"
4: import { IdeEvent } from "../src/ide-event"
5: import { SessionEvent } from "../src/session-event"
6: import { SessionTodo } from "../src/session-todo"
7: import { SessionV1 } from "../src/session-v1"
8: import { WorkspaceEvent } from "../src/workspace-event"
9:
10: describe("public event manifest", () => {
11: test("owns the complete public event surface", () => {
12: expect(EventManifest.ServerDefinitions.length).toBe(61)
13: expect(EventManifest.Definitions.length).toBe(91)
14: expect(SessionV1.Event.Definitions).toEqual([
15: SessionV1.Event.Created,
16: SessionV1.Event.Updated,
17: SessionV1.Event.Deleted,
18: ...
<path>/home/byk/Code/opencode/packages/core/test/database-migration.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect, test } from "bun:test"
2: import { $ } from "bun"
3: import { fileURLToPath } from "url"
4: import path from "path"
5: import { SqliteClient } from "@effect/sql-sqlite-bun"
6: import { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
7: import { Effect, Exit, Layer } from "effect"
8: import { eq, inArray, sql } from "drizzle-orm"
9: import { DatabaseMigration } from "@opencode-ai/core/database/migration"
10: import { migrations } from "@opencode-ai/core/database/migration.gen"
11: import workspaceNameMigration from "@opencode-ai/core/database/migration/20260410174513_workspace-name"
12: import sessionUsageMigration from "@opencode-ai/core/database/migration/20260510033149_session_usage"
13: import normalizeStoragePathsMigration from "@opencode-ai/core/database/migration/20260601010001_normalize_storage_paths"
14: import ...
<path>/home/byk/Code/opencode/packages/core/test/session-prompt.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect } from "bun:test"
2: import { DateTime, Effect, Fiber, Layer, Stream } from "effect"
3: import { asc, eq } from "drizzle-orm"
4: import { Database } from "@opencode-ai/core/database/database"
5: import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
6: import { LayerNode } from "@opencode-ai/core/effect/layer-node"
7: import { EventV2 } from "@opencode-ai/core/event"
8: import { EventTable } from "@opencode-ai/core/event/sql"
9: import { SessionEvent } from "@opencode-ai/core/session/event"
10: import { Project } from "@opencode-ai/core/project"
11: import { ProjectTable } from "@opencode-ai/core/project/sql"
12: import { AbsolutePath } from "@opencode-ai/core/schema"
13: import { SessionV2 } from "@opencode-ai/core/session"
14: import { Prompt } from "@opencode-ai/core/session/prompt"
15: import { SessionMessage } from ...
<path>/home/byk/Code/opencode/packages/core/test/session-prompt.test.ts</path>
<type>file</type>
<content>
489: it.effect("rejects reuse of one ID with a different prompt", () =>
490: Effect.gen(function* () {
491: yield* setup
492: const session = yield* SessionV2.Service
493:
494: yield* session.prompt({
495: sessionID,
496: id: messageID,
497: prompt: Prompt.make({ text: "Fix the failing tests" }),
498: })
499: const failure = yield* session
500: .prompt({
501: sessionID,
502: id: messageID,
503: prompt: Prompt.make({ text: "Delete the failing tests" }),
504: resume: false,
505: })
506: .pipe(Effect.flip)
507:
508: expect(failure._tag).toBe("Session.PromptConflictError")
509: expect(yield* session.messages({ sessionID })).toHaveLength(0)
510: expect(yield* admittedCount).toBe(1)
511: }),
512: )
513:
514: it.effect("never arms ...
Found 6 matches
/home/byk/Code/opencode/packages/core/test/session-projector.test.ts:
Line 1966: it.effect("quarantines a malformed claim without blocking a valid claim", () =>
Line 2018: it.effect("never recovers an expired cancellation claim", () =>
Line 2069: it.effect("never quarantines cancellation after recovery ownership expires", () =>
Line 2121: it.effect("never quarantines cancellation after recovery ownership transfers", () =>
Line 2450: it.effect("bounds each deterministic recovery scan", () =>
Line 2739: it.effect("fences a paused owner after expiry, reconciliation, and takeover", () =>
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1900: expect(
1901: yield* db
1902: .select({ type: EventTable.type })
1903: .from(EventTable)
1904: .where(eq(EventTable.type, "session.next.prompted.1"))
1905: .all(),
1906: ).toEqual([])
1907: }),
1908: )
1909:
1910: it.effect("never promotes a quarantined recovery continuation as an ordinary steer", () =>
1911: Effect.gen(function* () {
1912: const { db } = yield* Database.Service
1913: const events = yield* EventV2.Service
1914: yield* db
1915: .insert(ProjectTable)
1916: .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
1917: .run()
1918: yield* db
1919: .insert(SessionTable)
1920: .values({
1921: id: sessionID,
1922: project_id: Project.ID.global,
1923: slug: ...
<path>/home/byk/Code/opencode/packages/core/test/session-runner-recorded.test.ts</path>
<type>file</type>
<content>
1: import { HttpRecorder } from "@opencode-ai/http-recorder"
2: import { HttpRecorderInternal } from "@opencode-ai/http-recorder/internal"
3: import * as OpenAIChat from "@opencode-ai/llm/protocols/openai-chat"
4: import { Auth, LLMClient, RequestExecutor } from "@opencode-ai/llm/route"
5: import { Database } from "@opencode-ai/core/database/database"
6: import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
7: import { LayerNodePlatform } from "@opencode-ai/core/effect/app-node-platform"
8: import { LayerNode } from "@opencode-ai/core/effect/layer-node"
9: import { EventV2 } from "@opencode-ai/core/event"
10: import { EventTable } from "@opencode-ai/core/event/sql"
11: import { PermissionV2 } from "@opencode-ai/core/permission"
12: import { AgentV2 } from "@opencode-ai/core/agent"
13: import { Config } from "@opencode-ai/core/config"
14: import { ...
<path>/home/byk/Code/opencode/packages/core/test/session-run-coordinator.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect } from "bun:test"
2: import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
3: import { SessionRunCoordinator } from "@opencode-ai/core/session/run-coordinator"
4: import { testEffect } from "./lib/effect"
5:
6: const it = testEffect(Layer.empty)
7:
8: describe("SessionRunCoordinator", () => {
9: it.effect("joins concurrent resumes for one key", () =>
10: Effect.scoped(
11: Effect.gen(function* () {
12: const gate = yield* Deferred.make<void>()
13: let runs = 0
14: const coordinator = yield* SessionRunCoordinator.make({
15: drain: () => Effect.sync(() => runs++).pipe(Effect.andThen(Deferred.await(gate))),
16: })
17:
18: const first = yield* coordinator.run("session").pipe(Effect.forkChild)
19: yield* Effect.yieldNow
20: const second = yield* ...
<path>/home/byk/Code/opencode/packages/core/test/session-runner-tool-events.test.ts</path>
<type>file</type>
<content>
1: import { expect, test } from "bun:test"
2: import { Effect, Schema, Stream } from "effect"
3: import { LLMEvent } from "@opencode-ai/llm"
4: import { EventV2 } from "@opencode-ai/core/event"
5: import { SessionEvent } from "@opencode-ai/core/session/event"
6: import { SessionMessage } from "@opencode-ai/core/session/message"
7: import { SessionV2 } from "@opencode-ai/core/session"
8: import { ModelV2 } from "@opencode-ai/core/model"
9: import { ProviderV2 } from "@opencode-ai/core/provider"
10: import { createLLMEventPublisher } from "@opencode-ai/core/session/runner/publish-llm-event"
11:
12: const sessionID = SessionV2.ID.make("ses_tool_event_test")
13: const base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB"
14:
15: const capture = () => {
16: const published: Array<{ readonly type: string; readonly data: unknown }> = []
17: const events = ...
Found 12 matches
/home/byk/Code/opencode/packages/sdk/openapi.json:
Line 17899: "requestExecution": {
Line 17919: "enum": ["session.next.prompt.execution_requested"]
Line 18289: "enum": ["session.next.step.recovered"]
Line 25709: "requestExecution": {
Line 25740: "enum": ["session.next.prompt.execution_requested.1"]
Line 26299: "enum": ["session.next.step.recovered.1"]
Line 28599: "requestExecution": {
Line 28622: "enum": ["session.next.prompt.execution_requested"]
Line 29190: "enum": ["session.next.step.recovered"]
Line 34811: "requestExecution": {
Line 34831: "enum": ["session.next.prompt.execution_requested"]
Line 35201: "enum": ["session.next.step.recovered"]
<path>/home/byk/Code/opencode/packages/sdk/openapi.json</path>
<type>file</type>
<content>
17840: "properties": {
17841: "timestamp": {
17842: "type": "number"
17843: },
17844: "sessionID": {
17845: "type": "string",
17846: "pattern": "^ses"
17847: },
17848: "messageID": {
17849: "type": "string",
17850: "pattern": "^msg_"
17851: },
17852: "prompt": {
17853: "$ref": "#/components/schemas/Prompt"
17854: },
17855: "delivery": {
17856: "type": "string",
17857: "enum": ["steer", "queue"]
17858: }
17859: },
17860: "required": ...
Found 83 matches
/tmp/opencode/session-recovery-final-v16.patch:
Line 2598: + : sql`${SessionRecoveryTable.execution_id} <> ${excludeRecoveryExecutionID}`,
Line 2831: + desc(sql`${SessionRecoveryTable.wake_attempts} = ${MAX_WAKE_ATTEMPTS}`),
Line 2879: + desc(sql`${SessionRecoveryTable.wake_attempts} = ${MAX_WAKE_ATTEMPTS}`),
Line 2947: + desc(sql`${SessionTable.wake_attempts} = ${MAX_WAKE_ATTEMPTS}`),
Line 2980: + desc(sql`${SessionTable.wake_attempts} = ${MAX_WAKE_ATTEMPTS}`),
Line 3568: + tokens: stepSettlement.tokens,
Line 4097: + sql`${table.wake_attempts} >= 0 AND ${table.wake_attempts} <= ${sql.raw(String(MAX_WAKE_ATTEMPTS))}`,
Line 4155: + sql`${table.wake_attempts} >= 0 AND ${table.wake_attempts} <= ${sql.raw(String(MAX_WAKE_ATTEMPTS))}`,
Line 4188: + sql`${table.phase} IN ('ready', 'safe', 'unknown', 'continue', 'cancelling', 'cancelled')`,
Line 4227: + yield* ...
Found 77 matches
/tmp/opencode/session-recovery-final-v16.patch:
Line 1042: +import { Effect } from "effect"
Line 1043: +import type { DatabaseMigration } from "../migration"
Line 1347: +import { SessionExecutionClaim } from "./execution/claim"
Line 1521: +import { and, asc, desc, eq, isNull } from "drizzle-orm"
Line 1522: +import { Cause, Clock, Duration, Effect, Exit, Layer, Schedule } from "effect"
Line 1523: +import { Database } from "../../database/database"
Line 1528: +import { SessionMessage } from "../message"
Line 1532: +import { SessionExecutionClaim } from "./claim"
Line 1533: +import {
Line 1740: +import { and, asc, desc, eq, isNull, lte } from "drizzle-orm"
Line 1741: +import { DateTime, Effect, Option, Schema } from "effect"
Line 1745: +import { EventV2 } from "../event"
Line 1749: +import { continuation, message } from "./recovery-id"
Line 1752: +import { SessionInputTable, SessionMessageTable, SessionRecoveryTable, SessionTable ...
Found 3 matches /home/byk/Code/opencode/packages/core/src/session/execution/local.ts: Line 88: SessionExecutionClaim.renew(db, claim).pipe( Line 137: SessionExecutionClaim.renew(db, claim).pipe( Line 158: SessionExecutionClaim.renew(db, claim).pipe(
Found 22 matches
/home/byk/Code/opencode/packages/core/test/session-runner.test.ts:
Line 376: reason: new TransportReason({ message: "Provider unavailable" }),
Line 566: error: { type: "unknown", message: "Provider unavailable" },
Line 1757: it.effect("interrupts overflow recovery while the summary provider is running", () =>
Line 2061: response = [LLMEvent.stepStart({ index: 0 }), LLMEvent.providerError({ message: "Provider unavailable" })]
Line 2204: LLMEvent.providerError({ message: "Provider unavailable" }),
Line 3135: provider: { executed: true, metadata: { openai: { itemId: "call-hosted-interrupted" } } },
Line 3148: providerMetadata: { openai: { itemId: "call-hosted-interrupted" } },
Line 3150: { type: "tool-result", id: "call-hosted-interrupted", providerExecuted: true, result: { type: "error" } },
Line 3845: it.effect("durably fails blocked local tools when a provider turn is interrupted", () ...
<path>/home/byk/Code/opencode/packages/sdk/openapi.json</path>
<type>file</type>
<content>
26270: }
26271: },
26272: "required": ["timestamp", "sessionID", "assistantMessageID", "error"],
26273: "additionalProperties": false
26274: }
26275: },
26276: "required": ["type", "id", "seq", "aggregateID", "data"],
26277: "additionalProperties": false
26278: }
26279: },
26280: "required": ["type", "id", "syncEvent"],
26281: "additionalProperties": false
26282: },
26283: "SyncEventSessionNextStepRecovered": {
26284: "type": "object",
26285: "properties": {
26286: "type": {
26287: "type": "string",
26288: "enum": ["sync"]
26289: },
26290: "id": {
26291: "type": "string",
26292: "pattern": "^evt_"
26293: },
26294: ...
ab9408c81cc9916177641ae8e9f08624fc27b5b9.b0e9fdde553e70f6f606c33c555f9e37bb52d6827dd1aad8d5a932b76cd2ee30.a0eea521a58325461d7e533e5f3be05fccf2714a90a444eb67ac21b153f53c2f.packages/core/src/session/runner/publish-llm-event.ts:222-240 durably publishes Step.Failed, retains the assistant claim, and sets assistantFailed = true. The runner may remain active while local tools settle at packages/core/src/session/runner/llm.ts:400-405.
If cancellation arrives during that period:
packages/core/src/session/execution/local.ts:133 moves the claim to cancelling.packages/core/src/session/runner/llm.ts:429-435.settleCancellation to interruptAssistant at packages/core/src/session/runner/llm.ts:436-440.interruptAssistant returns immediately when assistantFailed is already true at packages/core/src/session/runner/publish-llm-event.ts:242-247. It never invokes the supplied cancellation commit.cancelling with a non-null assistant ID. Drain cleanup preserves it at packages/core/src/session/execution/local.ts:104-119, and interruption cleanup rejects it at ...