From aeb7d99d208bdd5e72278d16ed49c17479196a80 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Tue, 14 Apr 2026 17:33:44 -0400 Subject: [PATCH] fix(effect): preserve logger context in prompt runs (#22496) --- packages/opencode/src/effect/app-runtime.ts | 4 +- packages/opencode/src/session/prompt.ts | 6 +-- .../test/effect/app-runtime-logger.test.ts | 42 +++++++++++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 packages/opencode/test/effect/app-runtime-logger.test.ts diff --git a/packages/opencode/src/effect/app-runtime.ts b/packages/opencode/src/effect/app-runtime.ts index 9e1fb8bd24..674ca1a2ac 100644 --- a/packages/opencode/src/effect/app-runtime.ts +++ b/packages/opencode/src/effect/app-runtime.ts @@ -49,7 +49,7 @@ import { ShareNext } from "@/share/share-next" import { SessionShare } from "@/share/session" export const AppLayer = Layer.mergeAll( - // Observability.layer, + Observability.layer, AppFileSystem.defaultLayer, Bus.defaultLayer, Auth.defaultLayer, @@ -95,6 +95,6 @@ export const AppLayer = Layer.mergeAll( Installation.defaultLayer, ShareNext.defaultLayer, SessionShare.defaultLayer, -).pipe(Layer.provide(Observability.layer)) +) export const AppRuntime = ManagedRuntime.make(AppLayer, { memoMap }) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 4b0c30802b..a763b27b97 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -104,11 +104,11 @@ export namespace SessionPrompt { const summary = yield* SessionSummary.Service const sys = yield* SystemPrompt.Service const llm = yield* LLM.Service + const ctx = yield* Effect.context() const run = { - promise: (effect: Effect.Effect) => - Effect.runPromise(effect.pipe(Effect.provide(EffectLogger.layer))), - fork: (effect: Effect.Effect) => Effect.runFork(effect.pipe(Effect.provide(EffectLogger.layer))), + promise: (effect: Effect.Effect) => Effect.runPromiseWith(ctx)(effect), + fork: (effect: Effect.Effect) => Effect.runForkWith(ctx)(effect), } const cancel = Effect.fn("SessionPrompt.cancel")(function* (sessionID: SessionID) { diff --git a/packages/opencode/test/effect/app-runtime-logger.test.ts b/packages/opencode/test/effect/app-runtime-logger.test.ts new file mode 100644 index 0000000000..c09775be3a --- /dev/null +++ b/packages/opencode/test/effect/app-runtime-logger.test.ts @@ -0,0 +1,42 @@ +import { expect, test } from "bun:test" +import { Context, Effect, Layer, Logger } from "effect" +import { AppRuntime } from "../../src/effect/app-runtime" +import { EffectLogger } from "../../src/effect/logger" +import { makeRuntime } from "../../src/effect/run-service" + +function check(loggers: ReadonlySet>) { + return { + defaultLogger: loggers.has(Logger.defaultLogger), + tracerLogger: loggers.has(Logger.tracerLogger), + effectLogger: loggers.has(EffectLogger.logger), + size: loggers.size, + } +} + +test("makeRuntime installs EffectLogger through Observability.layer", async () => { + class Dummy extends Context.Service Effect.Effect> }>()( + "@test/Dummy", + ) {} + + const layer = Layer.effect( + Dummy, + Effect.gen(function* () { + return Dummy.of({ + current: () => Effect.map(Effect.service(Logger.CurrentLoggers), check), + }) + }), + ) + + const rt = makeRuntime(Dummy, layer) + const current = await rt.runPromise((svc) => svc.current()) + + expect(current.effectLogger).toBe(true) + expect(current.defaultLogger).toBe(false) +}) + +test("AppRuntime also installs EffectLogger through Observability.layer", async () => { + const current = await AppRuntime.runPromise(Effect.map(Effect.service(Logger.CurrentLoggers), check)) + + expect(current.effectLogger).toBe(true) + expect(current.defaultLogger).toBe(false) +})