Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions packages/core/src/effect/layer-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ type MakeInput<
T extends Tag | undefined = undefined,
> = NodeIdentity & {
readonly layer: Implementation
readonly deps: (Items | (() => Items)) & CheckDependencies<Implementation, NoInfer<Items>>
readonly deps: Items & CheckDependencies<Implementation, NoInfer<Items>>
readonly tag?: T
}

Expand All @@ -90,9 +90,7 @@ export function make<
name: input.service !== undefined ? input.service.key : input.name,
service: input.service,
implementation: input.layer,
get dependencies() {
return typeof input.deps === "function" ? input.deps() : input.deps
},
dependencies: input.deps,
tag: input.tag,
}
}
Expand Down
18 changes: 11 additions & 7 deletions packages/core/src/permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { Permission } from "@opencode-ai/schema/permission"
import { EventV2 } from "./event"
import { Location } from "./location"
import { AgentV2 } from "./agent"
import { SessionV2 } from "./session"
import { SessionErrors } from "./session/error"
import { SessionSchema } from "./session/schema"
import { SessionStore } from "./session/store"
import { Wildcard } from "./util/wildcard"
import { PermissionSaved } from "./permission/saved"
Expand Down Expand Up @@ -98,11 +99,11 @@ export function merge(...rulesets: Permission.Ruleset[]): Permission.Ruleset {
}

export interface Interface {
readonly ask: (input: AssertInput) => Effect.Effect<AskResult, SessionV2.NotFoundError>
readonly assert: (input: AssertInput) => Effect.Effect<void, Error | SessionV2.NotFoundError>
readonly ask: (input: AssertInput) => Effect.Effect<AskResult, SessionErrors.NotFoundError>
readonly assert: (input: AssertInput) => Effect.Effect<void, Error | SessionErrors.NotFoundError>
readonly reply: (input: ReplyInput) => Effect.Effect<void, NotFoundError>
readonly get: (id: ID) => Effect.Effect<Request | undefined>
readonly forSession: (sessionID: SessionV2.ID) => Effect.Effect<ReadonlyArray<Request>>
readonly forSession: (sessionID: SessionSchema.ID) => Effect.Effect<ReadonlyArray<Request>>
readonly list: () => Effect.Effect<ReadonlyArray<Request>>
}

Expand Down Expand Up @@ -142,9 +143,12 @@ const layer = Layer.effect(
)
})

const configured = Effect.fn("PermissionV2.configured")(function* (sessionID: SessionV2.ID, agentID?: AgentV2.ID) {
const configured = Effect.fn("PermissionV2.configured")(function* (
sessionID: SessionSchema.ID,
agentID?: AgentV2.ID,
) {
const session = yield* sessions.get(sessionID)
if (!session) return yield* new SessionV2.NotFoundError({ sessionID })
if (!session) return yield* new SessionErrors.NotFoundError({ sessionID })
const agent = yield* agents.resolve(agentID ?? session.agent)
return agent?.permissions ?? missingAgentPermissions
})
Expand Down Expand Up @@ -301,7 +305,7 @@ const layer = Layer.effect(
return pending.get(id)?.request
})

const forSession = Effect.fn("PermissionV2.forSession")(function* (sessionID: SessionV2.ID) {
const forSession = Effect.fn("PermissionV2.forSession")(function* (sessionID: SessionSchema.ID) {
return Array.from(pending.values(), (item) => item.request).filter((request) => request.sessionID === sessionID)
})

Expand Down
11 changes: 3 additions & 8 deletions packages/core/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ import { fromRow } from "./session/info"
import { SessionRunner } from "./session/runner/index"
import { SessionStore } from "./session/store"
import { SessionExecution } from "./session/execution"
import { MessageDecodeError, NotFoundError } from "./session/error"
import { makeGlobalNode } from "./effect/app-node"
import { LocationServiceMap } from "./location-service-map"
import { MessageDecodeError } from "./session/error"
import { SessionEvent } from "./session/event"
import { SessionPending } from "./session/pending"
import { SessionGenerate } from "./session/generate"
Expand Down Expand Up @@ -108,18 +108,14 @@ type ForkInput = {
messageID?: SessionMessage.ID
}

export class NotFoundError extends Schema.TaggedErrorClass<NotFoundError>()("Session.NotFoundError", {
sessionID: SessionSchema.ID,
}) {}

export class OperationUnavailableError extends Schema.TaggedErrorClass<OperationUnavailableError>()(
"Session.OperationUnavailableError",
{
operation: Schema.Literals(["move", "skill", "switchAgent", "compact"]),
},
) {}

export { MessageDecodeError } from "./session/error"
export { MessageDecodeError, NotFoundError }

export class PromptConflictError extends Schema.TaggedErrorClass<PromptConflictError>()("Session.PromptConflictError", {
sessionID: SessionSchema.ID,
Expand Down Expand Up @@ -1033,8 +1029,7 @@ const SHELL_MAX_CAPTURE_BYTES = 1024 * 1024
export const node = makeGlobalNode({
service: Service,
layer: layer.pipe(Layer.orDie),
// Defer the execution node across the Session/runner module cycle until the graph is compiled.
deps: () => [
deps: [
Job.node,
Database.node,
EventV2.node,
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/session/error.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
export * as SessionErrors from "./error"

import { Schema } from "effect"
import { Agent } from "@opencode-ai/schema/agent"
import { SessionMessage } from "./message"
import { SessionSchema } from "./schema"
import { SessionError } from "@opencode-ai/schema/session-error"

export class NotFoundError extends Schema.TaggedErrorClass<NotFoundError>()("Session.NotFoundError", {
sessionID: SessionSchema.ID,
}) {}

export class MessageDecodeError extends Schema.TaggedErrorClass<MessageDecodeError>()("Session.MessageDecodeError", {
sessionID: SessionSchema.ID,
messageID: SessionMessage.ID,
Expand Down
4 changes: 0 additions & 4 deletions packages/core/test/effect/layer-node/layer-node-types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const b = make({ service: B, layer: bLayer, deps: [a] })
const c = make({ service: C, layer: cLayer, deps: [a, b] })
const failing = make({ service: A, layer: failingA, deps: [] })
const dependent = make({ service: B, layer: bLayer, deps: [failing] })
make({ service: B, layer: bLayer, deps: () => [a] })
const inputA = LayerNode.unbound(A, tags.values.app)
const inputDependent = make({ service: B, layer: bLayer, deps: [inputA] })

Expand All @@ -47,9 +46,6 @@ make({ service: A, name: "a", layer: aLayer, deps: [] })
// @ts-expect-error B requires A
make({ service: B, layer: bLayer, deps: [] })

// @ts-expect-error Lazy dependencies must still provide A
make({ service: B, layer: bLayer, deps: () => [] })

// @ts-expect-error C requires A and B
make({ service: C, layer: cLayer, deps: [a] })

Expand Down
6 changes: 0 additions & 6 deletions packages/core/test/effect/layer-node/layer-node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ describe("layer node", () => {
expect(await Effect.runPromise(program)).toBe("hello production")
})

test("resolves lazy dependencies when compiling", async () => {
const greeting = make({ service: Greeting, layer: greetingLayer, deps: () => [value] })
const program = Effect.map(Greeting, (item) => item.value).pipe(Effect.provide(build(greeting)))
expect(await Effect.runPromise(program)).toBe("hello production")
})

test("exposes roots but hides transitive dependencies", () => {
const layer = build(LayerNode.group([greeting]))
const check: Layer.Layer<Greeting> = layer
Expand Down
Loading