chore(core): merge dev into session subpath fix
This commit is contained in:
commit
2d550aac46
22 changed files with 220 additions and 1384 deletions
|
|
@ -1,30 +0,0 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import { Cause, Effect, Logger } from "effect"
|
||||
import { logFailure } from "@opencode-ai/core/session/logging"
|
||||
import { SessionSchema } from "@opencode-ai/core/session/schema"
|
||||
|
||||
describe("Session logging", () => {
|
||||
for (const message of ["Failed to drain Session", "Failed to wake Session"] as const) {
|
||||
test(`renders the cause for ${message}`, async () => {
|
||||
const entries: Array<ReturnType<typeof Logger.formatStructured.log>> = []
|
||||
const logger = Logger.formatStructured.pipe(
|
||||
Logger.map((entry): void => {
|
||||
entries.push(entry)
|
||||
}),
|
||||
)
|
||||
|
||||
await logFailure(
|
||||
message,
|
||||
SessionSchema.ID.make("session-123"),
|
||||
Cause.fail({ _tag: "SessionFailure", detail: { code: "nested-code" } }),
|
||||
).pipe(Effect.provide(Logger.layer([logger])), Effect.runPromise)
|
||||
|
||||
expect(entries).toHaveLength(1)
|
||||
expect(entries[0]?.message).toBe(message)
|
||||
expect(entries[0]?.annotations).toEqual({ sessionID: "session-123" })
|
||||
expect(entries[0]?.cause).toContain("SessionFailure")
|
||||
expect(entries[0]?.cause).toContain("nested-code")
|
||||
expect(entries[0]?.cause).not.toContain("[Object")
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
@ -20,9 +20,7 @@ import { testEffect } from "./lib/effect"
|
|||
|
||||
const executionCalls: SessionV2.ID[] = []
|
||||
const interruptCalls: SessionV2.ID[] = []
|
||||
const interruptSeqs: Array<number | undefined> = []
|
||||
const wakeCalls: SessionV2.ID[] = []
|
||||
const wakeSeqs: Array<number | undefined> = []
|
||||
const execution = Layer.succeed(
|
||||
SessionExecution.Service,
|
||||
SessionExecution.Service.of({
|
||||
|
|
@ -30,15 +28,13 @@ const execution = Layer.succeed(
|
|||
Effect.sync(() => {
|
||||
executionCalls.push(sessionID)
|
||||
}),
|
||||
interrupt: (sessionID, seq) =>
|
||||
interrupt: (sessionID) =>
|
||||
Effect.sync(() => {
|
||||
interruptCalls.push(sessionID)
|
||||
interruptSeqs.push(seq)
|
||||
}),
|
||||
wake: (sessionID, seq) =>
|
||||
wake: (sessionID) =>
|
||||
Effect.sync(() => {
|
||||
wakeCalls.push(sessionID)
|
||||
wakeSeqs.push(seq)
|
||||
}),
|
||||
}),
|
||||
)
|
||||
|
|
@ -109,15 +105,6 @@ const eventCount = (type: string) =>
|
|||
),
|
||||
)
|
||||
|
||||
const interruptEvent = Database.Service.use(({ db }) =>
|
||||
db
|
||||
.select()
|
||||
.from(EventTable)
|
||||
.where(eq(EventTable.type, "session.next.interrupt.requested.1"))
|
||||
.get()
|
||||
.pipe(Effect.orDie),
|
||||
)
|
||||
|
||||
describe("SessionV2.prompt", () => {
|
||||
it.effect("delegates execution continuation through SessionExecution", () =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -131,19 +118,14 @@ describe("SessionV2.prompt", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("delegates interruption through SessionExecution", () =>
|
||||
it.effect("delegates process-local interruption through SessionExecution", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
const session = yield* SessionV2.Service
|
||||
interruptCalls.length = 0
|
||||
interruptSeqs.length = 0
|
||||
|
||||
yield* session.interrupt(sessionID)
|
||||
expect(interruptCalls).toEqual([sessionID])
|
||||
expect(interruptSeqs).toHaveLength(1)
|
||||
expect(typeof interruptSeqs[0]).toBe("number")
|
||||
expect(yield* eventCount("session.next.interrupt.requested.1")).toBe(1)
|
||||
expect(yield* interruptEvent).toMatchObject({ aggregate_id: sessionID, seq: interruptSeqs[0] })
|
||||
expect(yield* session.messages({ sessionID })).toEqual([])
|
||||
}),
|
||||
)
|
||||
|
|
@ -152,11 +134,9 @@ describe("SessionV2.prompt", () => {
|
|||
Effect.gen(function* () {
|
||||
const session = yield* SessionV2.Service
|
||||
interruptCalls.length = 0
|
||||
interruptSeqs.length = 0
|
||||
|
||||
yield* session.interrupt(SessionV2.ID.make("ses_missing"))
|
||||
expect(interruptCalls).toEqual([SessionV2.ID.make("ses_missing")])
|
||||
expect(interruptSeqs).toEqual([undefined])
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -515,13 +495,11 @@ describe("SessionV2.prompt", () => {
|
|||
const session = yield* SessionV2.Service
|
||||
executionCalls.length = 0
|
||||
wakeCalls.length = 0
|
||||
wakeSeqs.length = 0
|
||||
|
||||
const admitted = yield* session.prompt({ sessionID, prompt: new Prompt({ text: "Run by default" }) })
|
||||
yield* session.prompt({ sessionID, prompt: new Prompt({ text: "Run by default" }) })
|
||||
|
||||
expect(executionCalls).toEqual([])
|
||||
expect(wakeCalls).toEqual([sessionID])
|
||||
expect(wakeSeqs).toEqual([admitted.admittedSeq])
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -531,9 +509,8 @@ describe("SessionV2.prompt", () => {
|
|||
const session = yield* SessionV2.Service
|
||||
executionCalls.length = 0
|
||||
wakeCalls.length = 0
|
||||
wakeSeqs.length = 0
|
||||
|
||||
const admitted = yield* session.prompt({
|
||||
yield* session.prompt({
|
||||
sessionID,
|
||||
prompt: new Prompt({ text: "Run explicitly" }),
|
||||
resume: true,
|
||||
|
|
@ -541,7 +518,6 @@ describe("SessionV2.prompt", () => {
|
|||
|
||||
expect(executionCalls).toEqual([])
|
||||
expect(wakeCalls).toEqual([sessionID])
|
||||
expect(wakeSeqs).toEqual([admitted.admittedSeq])
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -551,13 +527,11 @@ describe("SessionV2.prompt", () => {
|
|||
const session = yield* SessionV2.Service
|
||||
executionCalls.length = 0
|
||||
wakeCalls.length = 0
|
||||
wakeSeqs.length = 0
|
||||
|
||||
yield* session.prompt({ sessionID, prompt: new Prompt({ text: "Do not run" }), resume: false })
|
||||
|
||||
expect(executionCalls).toEqual([])
|
||||
expect(wakeCalls).toEqual([])
|
||||
expect(wakeSeqs).toEqual([])
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -16,6 +16,7 @@ import { Prompt } from "@opencode-ai/core/session/prompt"
|
|||
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
||||
import { SessionExecution } from "@opencode-ai/core/session/execution"
|
||||
import { SessionRunCoordinator } from "@opencode-ai/core/session/run-coordinator"
|
||||
import { SessionRunner } from "@opencode-ai/core/session/runner"
|
||||
import * as SessionRunnerLLM from "@opencode-ai/core/session/runner/llm"
|
||||
import { SessionRunnerModel } from "@opencode-ai/core/session/runner/model"
|
||||
import { ToolRegistry } from "@opencode-ai/core/tool/registry"
|
||||
|
|
@ -83,19 +84,20 @@ const runner = SessionRunnerLLM.defaultLayer.pipe(
|
|||
Layer.provide(referenceGuidance),
|
||||
Layer.provide(config),
|
||||
)
|
||||
const coordinator = SessionRunCoordinator.layer.pipe(Layer.provide(runner))
|
||||
const execution = Layer.effect(
|
||||
SessionExecution.Service,
|
||||
SessionRunCoordinator.Service.pipe(
|
||||
Effect.map((coordinator) =>
|
||||
SessionExecution.Service.of({
|
||||
resume: coordinator.run,
|
||||
wake: coordinator.wake,
|
||||
interrupt: coordinator.interrupt,
|
||||
}),
|
||||
),
|
||||
),
|
||||
).pipe(Layer.provide(coordinator))
|
||||
Effect.gen(function* () {
|
||||
const sessionRunner = yield* SessionRunner.Service
|
||||
const coordinator = yield* SessionRunCoordinator.make<SessionV2.ID, SessionRunner.RunError>({
|
||||
drain: (sessionID, force) => sessionRunner.run({ sessionID, force }),
|
||||
})
|
||||
return SessionExecution.Service.of({
|
||||
resume: coordinator.run,
|
||||
wake: coordinator.wake,
|
||||
interrupt: coordinator.interrupt,
|
||||
})
|
||||
}),
|
||||
).pipe(Layer.provide(runner))
|
||||
const sessions = SessionV2.layer.pipe(
|
||||
Layer.provide(EventV2.defaultLayer),
|
||||
Layer.provide(Database.defaultLayer),
|
||||
|
|
@ -120,7 +122,6 @@ const it = testEffect(
|
|||
skillGuidance,
|
||||
config,
|
||||
runner,
|
||||
coordinator,
|
||||
execution,
|
||||
sessions,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -244,19 +244,20 @@ const runner = SessionRunnerLLM.layer.pipe(
|
|||
Layer.provide(referenceGuidance),
|
||||
Layer.provide(config),
|
||||
)
|
||||
const coordinator = SessionRunCoordinator.layer.pipe(Layer.provide(runner))
|
||||
const execution = Layer.effect(
|
||||
SessionExecution.Service,
|
||||
SessionRunCoordinator.Service.pipe(
|
||||
Effect.map((coordinator) =>
|
||||
SessionExecution.Service.of({
|
||||
resume: coordinator.run,
|
||||
wake: coordinator.wake,
|
||||
interrupt: coordinator.interrupt,
|
||||
}),
|
||||
),
|
||||
),
|
||||
).pipe(Layer.provide(coordinator))
|
||||
Effect.gen(function* () {
|
||||
const sessionRunner = yield* SessionRunner.Service
|
||||
const coordinator = yield* SessionRunCoordinator.make<SessionV2.ID, SessionRunner.RunError>({
|
||||
drain: (sessionID, force) => sessionRunner.run({ sessionID, force }),
|
||||
})
|
||||
return SessionExecution.Service.of({
|
||||
resume: coordinator.run,
|
||||
wake: coordinator.wake,
|
||||
interrupt: coordinator.interrupt,
|
||||
})
|
||||
}),
|
||||
).pipe(Layer.provide(runner))
|
||||
const sessions = SessionV2.layer.pipe(
|
||||
Layer.provide(EventV2.defaultLayer),
|
||||
Layer.provide(Database.defaultLayer),
|
||||
|
|
@ -283,7 +284,6 @@ const it = testEffect(
|
|||
skillGuidance,
|
||||
config,
|
||||
runner,
|
||||
coordinator,
|
||||
execution,
|
||||
sessions,
|
||||
),
|
||||
|
|
@ -681,7 +681,6 @@ describe("SessionRunnerLLM", () => {
|
|||
|
||||
systemUnavailable = false
|
||||
yield* session.prompt({ id: messageID, sessionID, prompt: new Prompt({ text: "First" }) })
|
||||
yield* (yield* SessionRunCoordinator.Service).awaitIdle(sessionID)
|
||||
|
||||
expect(requests).toHaveLength(1)
|
||||
expect(requests[0]?.messages.map((message) => message.role)).toEqual(["user"])
|
||||
|
|
@ -2161,7 +2160,7 @@ describe("SessionRunnerLLM", () => {
|
|||
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(userTexts(requests[1]!)).toEqual(["Start working", "First steer", "Second steer"])
|
||||
yield* (yield* SessionRunCoordinator.Service).wake(sessionID)
|
||||
yield* (yield* SessionExecution.Service).wake(sessionID)
|
||||
yield* Effect.yieldNow
|
||||
expect(requests).toHaveLength(2)
|
||||
}),
|
||||
|
|
@ -2367,7 +2366,7 @@ describe("SessionRunnerLLM", () => {
|
|||
})
|
||||
|
||||
requests.length = 0
|
||||
yield* (yield* SessionRunCoordinator.Service).wake(sessionID)
|
||||
yield* (yield* SessionExecution.Service).wake(sessionID)
|
||||
yield* Effect.yieldNow
|
||||
|
||||
expect(requests).toHaveLength(1)
|
||||
|
|
@ -2417,7 +2416,7 @@ describe("SessionRunnerLLM", () => {
|
|||
LLMEvent.finish({ reason: "stop" }),
|
||||
]
|
||||
|
||||
yield* (yield* SessionRunCoordinator.Service).wake(sessionID)
|
||||
yield* (yield* SessionExecution.Service).wake(sessionID)
|
||||
while (requests.length === 0) yield* Effect.yieldNow
|
||||
|
||||
expect(userTexts(requests[0]!)).toEqual(["Recover promoted input"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue