Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Kit Langton
d57adec496 remove makeRuntime facade for Permission.Service from llm.ts
Yield Permission.Service directly from the LLM layer context instead of
creating a separate ManagedRuntime via makeRuntime. The approvalHandler
callback now uses Effect.runPromise(perm.ask(...)) on the captured
implementation, avoiding the extra runtime and its duplicated memoMap.
2026-04-15 10:57:38 -04:00

View file

@ -20,13 +20,11 @@ import { Wildcard } from "@/util/wildcard"
import { SessionID } from "@/session/schema" import { SessionID } from "@/session/schema"
import { Auth } from "@/auth" import { Auth } from "@/auth"
import { Installation } from "@/installation" import { Installation } from "@/installation"
import { makeRuntime } from "@/effect/run-service"
import * as Option from "effect/Option" import * as Option from "effect/Option"
import * as OtelTracer from "@effect/opentelemetry/Tracer" import * as OtelTracer from "@effect/opentelemetry/Tracer"
export namespace LLM { export namespace LLM {
const log = Log.create({ service: "llm" }) const log = Log.create({ service: "llm" })
const perms = makeRuntime(Permission.Service, Permission.defaultLayer)
export const OUTPUT_TOKEN_MAX = ProviderTransform.OUTPUT_TOKEN_MAX export const OUTPUT_TOKEN_MAX = ProviderTransform.OUTPUT_TOKEN_MAX
type Result = Awaited<ReturnType<typeof streamText>> type Result = Awaited<ReturnType<typeof streamText>>
@ -57,14 +55,18 @@ export namespace LLM {
export class Service extends Context.Service<Service, Interface>()("@opencode/LLM") {} export class Service extends Context.Service<Service, Interface>()("@opencode/LLM") {}
export const layer: Layer.Layer<Service, never, Auth.Service | Config.Service | Provider.Service | Plugin.Service> = const live: Layer.Layer<
Layer.effect( Service,
never,
Auth.Service | Config.Service | Provider.Service | Plugin.Service | Permission.Service
> = Layer.effect(
Service, Service,
Effect.gen(function* () { Effect.gen(function* () {
const auth = yield* Auth.Service const auth = yield* Auth.Service
const config = yield* Config.Service const config = yield* Config.Service
const provider = yield* Provider.Service const provider = yield* Provider.Service
const plugin = yield* Plugin.Service const plugin = yield* Plugin.Service
const perm = yield* Permission.Service
const run = Effect.fn("LLM.run")(function* (input: StreamRequest) { const run = Effect.fn("LLM.run")(function* (input: StreamRequest) {
const l = log const l = log
@ -289,8 +291,8 @@ export namespace LLM {
} }
}) })
const uniquePatterns = [...new Set(toolPatterns)] as string[] const uniquePatterns = [...new Set(toolPatterns)] as string[]
await perms.runPromise((svc) => await Effect.runPromise(
svc.ask({ perm.ask({
id, id,
sessionID: SessionID.make(input.sessionID), sessionID: SessionID.make(input.sessionID),
permission: "workflow_tool_approval", permission: "workflow_tool_approval",
@ -301,10 +303,7 @@ export namespace LLM {
}), }),
) )
for (const name of uniqueNames) approvedToolsForSession.add(name) for (const name of uniqueNames) approvedToolsForSession.add(name)
workflowModel.sessionPreapprovedTools = [ workflowModel.sessionPreapprovedTools = [...(workflowModel.sessionPreapprovedTools ?? []), ...uniqueNames]
...(workflowModel.sessionPreapprovedTools ?? []),
...uniqueNames,
]
return { approved: true } return { approved: true }
} catch { } catch {
return { approved: false } return { approved: false }
@ -410,9 +409,7 @@ export namespace LLM {
const result = yield* run({ ...input, abort: ctrl.signal }) const result = yield* run({ ...input, abort: ctrl.signal })
return Stream.fromAsyncIterable(result.fullStream, (e) => return Stream.fromAsyncIterable(result.fullStream, (e) => (e instanceof Error ? e : new Error(String(e))))
e instanceof Error ? e : new Error(String(e)),
)
}), }),
), ),
) )
@ -421,6 +418,8 @@ export namespace LLM {
}), }),
) )
export const layer = live.pipe(Layer.provide(Permission.defaultLayer))
export const defaultLayer = Layer.suspend(() => export const defaultLayer = Layer.suspend(() =>
layer.pipe( layer.pipe(
Layer.provide(Auth.defaultLayer), Layer.provide(Auth.defaultLayer),