fix(core): remove session import cycle (#37596)
Co-authored-by: James Long <17031+jlongster@users.noreply.github.com>
This commit is contained in:
parent
deb5b144c3
commit
529d55b1c3
6 changed files with 22 additions and 29 deletions
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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>>
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -108,10 +108,6 @@ 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",
|
||||
{
|
||||
|
|
@ -119,7 +115,7 @@ export class OperationUnavailableError extends Schema.TaggedErrorClass<Operation
|
|||
},
|
||||
) {}
|
||||
|
||||
export { MessageDecodeError } from "./session/error"
|
||||
export { MessageDecodeError, NotFoundError }
|
||||
|
||||
export class PromptConflictError extends Schema.TaggedErrorClass<PromptConflictError>()("Session.PromptConflictError", {
|
||||
sessionID: SessionSchema.ID,
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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] })
|
||||
|
||||
|
|
@ -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] })
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue