diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts index d5163cf883..afffeea8fd 100644 --- a/packages/core/src/session.ts +++ b/packages/core/src/session.ts @@ -3,6 +3,7 @@ export * from "./session/schema" import { Cause, DateTime, Effect, Layer, Schema, Context, Stream } from "effect" import { and, asc, desc, eq, gt, like, lt, or, type SQL } from "drizzle-orm" +import { LayerNode } from "./effect/layer-node" import { ProjectV2 } from "./project" import { WorkspaceV2 } from "./workspace" import { ModelV2 } from "./model" @@ -434,3 +435,11 @@ export const defaultLayer = layer.pipe( Layer.provide(ProjectV2.defaultLayer), Layer.orDie, ) +export const node = LayerNode.make(layer.pipe(Layer.orDie), [ + Database.node, + EventV2.node, + ProjectV2.node, + SessionExecution.noopNode, + SessionProjector.node, + SessionStore.node, +]) diff --git a/packages/core/src/session/execution.ts b/packages/core/src/session/execution.ts index 9a99145bfb..34af8bce9c 100644 --- a/packages/core/src/session/execution.ts +++ b/packages/core/src/session/execution.ts @@ -1,6 +1,7 @@ export * as SessionExecution from "./execution" import { Context, Effect, Layer } from "effect" +import { LayerNode } from "../effect/layer-node" import { SessionRunner } from "./runner/index" import { SessionSchema } from "./schema" @@ -21,3 +22,4 @@ export const noopLayer = Layer.succeed( Service, Service.of({ resume: () => Effect.void, wake: () => Effect.void, interrupt: () => Effect.void }), ) +export const noopNode = LayerNode.make(noopLayer, []) diff --git a/packages/core/src/session/store.ts b/packages/core/src/session/store.ts index 1cff231306..b3199eb9ec 100644 --- a/packages/core/src/session/store.ts +++ b/packages/core/src/session/store.ts @@ -3,6 +3,7 @@ export * as SessionStore from "./store" import { eq } from "drizzle-orm" import { Context, Effect, Layer, Schema } from "effect" import { Database } from "../database/database" +import { LayerNode } from "../effect/layer-node" import { SessionHistory } from "./history" import { MessageDecodeError } from "./error" import { SessionMessage } from "./message" @@ -60,3 +61,4 @@ export const layer = Layer.effect( ) export const defaultLayer = layer.pipe(Layer.provide(Database.defaultLayer)) +export const node = LayerNode.make(layer, [Database.node]) diff --git a/packages/core/test/session-projector.test.ts b/packages/core/test/session-projector.test.ts index f84f60f308..9978dee927 100644 --- a/packages/core/test/session-projector.test.ts +++ b/packages/core/test/session-projector.test.ts @@ -1,7 +1,8 @@ import { describe, expect } from "bun:test" -import { DateTime, Effect, Layer, Schema } from "effect" +import { DateTime, Effect, Schema } from "effect" import { asc, eq } from "drizzle-orm" import { Database } from "@opencode-ai/core/database/database" +import { LayerNode } from "@opencode-ai/core/effect/layer-node" import { EventV2 } from "@opencode-ai/core/event" import { EventTable } from "@opencode-ai/core/event/sql" import { ModelV2 } from "@opencode-ai/core/model" @@ -15,16 +16,15 @@ import { SessionMessage } from "@opencode-ai/core/session/message" import { Prompt } from "@opencode-ai/core/session/prompt" import { SessionMessageUpdater } from "@opencode-ai/core/session/message-updater" import { SessionProjector } from "@opencode-ai/core/session/projector" -import { SessionExecution } from "@opencode-ai/core/session/execution" import { SessionInput } from "@opencode-ai/core/session/input" -import { SessionStore } from "@opencode-ai/core/session/store" import { SessionInputTable, SessionMessageTable, SessionTable } from "@opencode-ai/core/session/sql" import { testEffect } from "./lib/effect" -const database = Database.layerFromPath(":memory:") -const events = EventV2.layer.pipe(Layer.provide(database)) -const projector = SessionProjector.layer.pipe(Layer.provide(events), Layer.provide(database)) -const it = testEffect(Layer.mergeAll(database, events, projector)) +const it = testEffect( + LayerNode.buildLayer(LayerNode.group([SessionV2.node, Database.node, EventV2.node, SessionProjector.node]), { + replacements: [LayerNode.replace(Database.node, Database.layerFromPath(":memory:"))], + }), +) const sessionID = SessionV2.ID.make("ses_projector_test") const created = DateTime.makeUnsafe(0) const model = { id: ModelV2.ID.make("model"), providerID: ProviderV2.ID.make("provider") } @@ -110,17 +110,7 @@ describe("SessionProjector", () => { expect( (yield* sessions.context(sessionID)).map((message) => (message.type === "user" ? message.text : message.type)), ).toEqual(["first", "second"]) - }).pipe( - Effect.provide( - SessionV2.layer.pipe( - Layer.provide(events), - Layer.provide(database), - Layer.provide(Project.defaultLayer), - Layer.provide(SessionStore.layer.pipe(Layer.provide(database))), - Layer.provide(SessionExecution.noopLayer), - ), - ), - ), + }), ) it.effect("marks an admitted lifecycle row promoted with the PromptPromoted event sequence", () =>