Skip to content

Commit aeb7d99

Browse files
authored
fix(effect): preserve logger context in prompt runs (#22496)
1 parent 3695057 commit aeb7d99

3 files changed

Lines changed: 47 additions & 5 deletions

File tree

packages/opencode/src/effect/app-runtime.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import { ShareNext } from "@/share/share-next"
4949
import { SessionShare } from "@/share/session"
5050

5151
export const AppLayer = Layer.mergeAll(
52-
// Observability.layer,
52+
Observability.layer,
5353
AppFileSystem.defaultLayer,
5454
Bus.defaultLayer,
5555
Auth.defaultLayer,
@@ -95,6 +95,6 @@ export const AppLayer = Layer.mergeAll(
9595
Installation.defaultLayer,
9696
ShareNext.defaultLayer,
9797
SessionShare.defaultLayer,
98-
).pipe(Layer.provide(Observability.layer))
98+
)
9999

100100
export const AppRuntime = ManagedRuntime.make(AppLayer, { memoMap })

packages/opencode/src/session/prompt.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ export namespace SessionPrompt {
104104
const summary = yield* SessionSummary.Service
105105
const sys = yield* SystemPrompt.Service
106106
const llm = yield* LLM.Service
107+
const ctx = yield* Effect.context()
107108

108109
const run = {
109-
promise: <A, E>(effect: Effect.Effect<A, E>) =>
110-
Effect.runPromise(effect.pipe(Effect.provide(EffectLogger.layer))),
111-
fork: <A, E>(effect: Effect.Effect<A, E>) => Effect.runFork(effect.pipe(Effect.provide(EffectLogger.layer))),
110+
promise: <A, E>(effect: Effect.Effect<A, E>) => Effect.runPromiseWith(ctx)(effect),
111+
fork: <A, E>(effect: Effect.Effect<A, E>) => Effect.runForkWith(ctx)(effect),
112112
}
113113

114114
const cancel = Effect.fn("SessionPrompt.cancel")(function* (sessionID: SessionID) {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { expect, test } from "bun:test"
2+
import { Context, Effect, Layer, Logger } from "effect"
3+
import { AppRuntime } from "../../src/effect/app-runtime"
4+
import { EffectLogger } from "../../src/effect/logger"
5+
import { makeRuntime } from "../../src/effect/run-service"
6+
7+
function check(loggers: ReadonlySet<Logger.Logger<unknown, any>>) {
8+
return {
9+
defaultLogger: loggers.has(Logger.defaultLogger),
10+
tracerLogger: loggers.has(Logger.tracerLogger),
11+
effectLogger: loggers.has(EffectLogger.logger),
12+
size: loggers.size,
13+
}
14+
}
15+
16+
test("makeRuntime installs EffectLogger through Observability.layer", async () => {
17+
class Dummy extends Context.Service<Dummy, { readonly current: () => Effect.Effect<ReturnType<typeof check>> }>()(
18+
"@test/Dummy",
19+
) {}
20+
21+
const layer = Layer.effect(
22+
Dummy,
23+
Effect.gen(function* () {
24+
return Dummy.of({
25+
current: () => Effect.map(Effect.service(Logger.CurrentLoggers), check),
26+
})
27+
}),
28+
)
29+
30+
const rt = makeRuntime(Dummy, layer)
31+
const current = await rt.runPromise((svc) => svc.current())
32+
33+
expect(current.effectLogger).toBe(true)
34+
expect(current.defaultLogger).toBe(false)
35+
})
36+
37+
test("AppRuntime also installs EffectLogger through Observability.layer", async () => {
38+
const current = await AppRuntime.runPromise(Effect.map(Effect.service(Logger.CurrentLoggers), check))
39+
40+
expect(current.effectLogger).toBe(true)
41+
expect(current.defaultLogger).toBe(false)
42+
})

0 commit comments

Comments
 (0)