mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-02 10:46:46 +00:00
refactor(effect): extract session run state service (#21744)
This commit is contained in:
@@ -5,6 +5,7 @@ import { Session } from "../../src/session"
|
||||
import { ModelID, ProviderID } from "../../src/provider/schema"
|
||||
import { MessageID, PartID, type SessionID } from "../../src/session/schema"
|
||||
import { SessionPrompt } from "../../src/session/prompt"
|
||||
import { SessionRunState } from "../../src/session/run-state"
|
||||
import { Log } from "../../src/util/log"
|
||||
import { tmpdir } from "../fixture/fixture"
|
||||
|
||||
@@ -64,7 +65,7 @@ describe("session action routes", () => {
|
||||
fn: async () => {
|
||||
const session = await Session.create({})
|
||||
const msg = await user(session.id, "hello")
|
||||
const busy = spyOn(SessionPrompt, "assertNotBusy").mockRejectedValue(new Session.BusyError(session.id))
|
||||
const busy = spyOn(SessionRunState, "assertNotBusy").mockRejectedValue(new Session.BusyError(session.id))
|
||||
const remove = spyOn(Session, "removeMessage").mockResolvedValue(msg.id)
|
||||
const app = Server.Default().app
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import { SessionCompaction } from "../../src/session/compaction"
|
||||
import { Instruction } from "../../src/session/instruction"
|
||||
import { SessionProcessor } from "../../src/session/processor"
|
||||
import { SessionPrompt } from "../../src/session/prompt"
|
||||
import { SessionRunState } from "../../src/session/run-state"
|
||||
import { MessageID, PartID, SessionID } from "../../src/session/schema"
|
||||
import { SessionStatus } from "../../src/session/status"
|
||||
import { Shell } from "../../src/shell/shell"
|
||||
@@ -143,6 +144,7 @@ const filetime = Layer.succeed(
|
||||
)
|
||||
|
||||
const status = SessionStatus.layer.pipe(Layer.provideMerge(Bus.layer))
|
||||
const run = SessionRunState.layer.pipe(Layer.provide(status))
|
||||
const infra = Layer.mergeAll(NodeFileSystem.layer, CrossSpawnSpawner.defaultLayer)
|
||||
function makeHttp() {
|
||||
const deps = Layer.mergeAll(
|
||||
@@ -174,6 +176,7 @@ function makeHttp() {
|
||||
return Layer.mergeAll(
|
||||
TestLLMServer.layer,
|
||||
SessionPrompt.layer.pipe(
|
||||
Layer.provideMerge(run),
|
||||
Layer.provideMerge(compact),
|
||||
Layer.provideMerge(proc),
|
||||
Layer.provideMerge(registry),
|
||||
@@ -300,9 +303,10 @@ const addSubtask = (sessionID: SessionID, messageID: MessageID, model = ref) =>
|
||||
|
||||
const boot = Effect.fn("test.boot")(function* (input?: { title?: string }) {
|
||||
const prompt = yield* SessionPrompt.Service
|
||||
const run = yield* SessionRunState.Service
|
||||
const sessions = yield* Session.Service
|
||||
const chat = yield* sessions.create(input ?? { title: "Pinned" })
|
||||
return { prompt, sessions, chat }
|
||||
return { prompt, run, sessions, chat }
|
||||
})
|
||||
|
||||
// Loop semantics
|
||||
@@ -800,7 +804,7 @@ it.live("concurrent loop callers get same result", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
const { prompt, chat } = yield* boot()
|
||||
const { prompt, run, chat } = yield* boot()
|
||||
yield* seed(chat.id, { finish: "stop" })
|
||||
|
||||
const [a, b] = yield* Effect.all([prompt.loop({ sessionID: chat.id }), prompt.loop({ sessionID: chat.id })], {
|
||||
@@ -809,7 +813,7 @@ it.live("concurrent loop callers get same result", () =>
|
||||
|
||||
expect(a.info.id).toBe(b.info.id)
|
||||
expect(a.info.role).toBe("assistant")
|
||||
yield* prompt.assertNotBusy(chat.id)
|
||||
yield* run.assertNotBusy(chat.id)
|
||||
}),
|
||||
{ git: true },
|
||||
),
|
||||
@@ -913,6 +917,7 @@ it.live(
|
||||
provideTmpdirServer(
|
||||
Effect.fnUntraced(function* ({ llm }) {
|
||||
const prompt = yield* SessionPrompt.Service
|
||||
const run = yield* SessionRunState.Service
|
||||
const sessions = yield* Session.Service
|
||||
yield* llm.hang
|
||||
|
||||
@@ -922,7 +927,7 @@ it.live(
|
||||
const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild)
|
||||
yield* llm.wait(1)
|
||||
|
||||
const exit = yield* prompt.assertNotBusy(chat.id).pipe(Effect.exit)
|
||||
const exit = yield* run.assertNotBusy(chat.id).pipe(Effect.exit)
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
if (Exit.isFailure(exit)) {
|
||||
expect(Cause.squash(exit.cause)).toBeInstanceOf(Session.BusyError)
|
||||
@@ -940,11 +945,11 @@ it.live("assertNotBusy succeeds when idle", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
const prompt = yield* SessionPrompt.Service
|
||||
const run = yield* SessionRunState.Service
|
||||
const sessions = yield* Session.Service
|
||||
|
||||
const chat = yield* sessions.create({})
|
||||
const exit = yield* prompt.assertNotBusy(chat.id).pipe(Effect.exit)
|
||||
const exit = yield* run.assertNotBusy(chat.id).pipe(Effect.exit)
|
||||
expect(Exit.isSuccess(exit)).toBe(true)
|
||||
}),
|
||||
{ git: true },
|
||||
@@ -985,7 +990,7 @@ unix("shell captures stdout and stderr in completed tool output", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
const { prompt, chat } = yield* boot()
|
||||
const { prompt, run, chat } = yield* boot()
|
||||
const result = yield* prompt.shell({
|
||||
sessionID: chat.id,
|
||||
agent: "build",
|
||||
@@ -1000,7 +1005,7 @@ unix("shell captures stdout and stderr in completed tool output", () =>
|
||||
expect(tool.state.output).toContain("err")
|
||||
expect(tool.state.metadata.output).toContain("out")
|
||||
expect(tool.state.metadata.output).toContain("err")
|
||||
yield* prompt.assertNotBusy(chat.id)
|
||||
yield* run.assertNotBusy(chat.id)
|
||||
}),
|
||||
{ git: true, config: cfg },
|
||||
),
|
||||
@@ -1010,7 +1015,7 @@ unix("shell completes a fast command on the preferred shell", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
const { prompt, chat } = yield* boot()
|
||||
const { prompt, run, chat } = yield* boot()
|
||||
const result = yield* prompt.shell({
|
||||
sessionID: chat.id,
|
||||
agent: "build",
|
||||
@@ -1024,7 +1029,7 @@ unix("shell completes a fast command on the preferred shell", () =>
|
||||
expect(tool.state.input.command).toBe("pwd")
|
||||
expect(tool.state.output).toContain(dir)
|
||||
expect(tool.state.metadata.output).toContain(dir)
|
||||
yield* prompt.assertNotBusy(chat.id)
|
||||
yield* run.assertNotBusy(chat.id)
|
||||
}),
|
||||
{ git: true, config: cfg },
|
||||
),
|
||||
@@ -1034,7 +1039,7 @@ unix("shell lists files from the project directory", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
const { prompt, chat } = yield* boot()
|
||||
const { prompt, run, chat } = yield* boot()
|
||||
yield* Effect.promise(() => Bun.write(path.join(dir, "README.md"), "# e2e\n"))
|
||||
|
||||
const result = yield* prompt.shell({
|
||||
@@ -1050,7 +1055,7 @@ unix("shell lists files from the project directory", () =>
|
||||
expect(tool.state.input.command).toBe("command ls")
|
||||
expect(tool.state.output).toContain("README.md")
|
||||
expect(tool.state.metadata.output).toContain("README.md")
|
||||
yield* prompt.assertNotBusy(chat.id)
|
||||
yield* run.assertNotBusy(chat.id)
|
||||
}),
|
||||
{ git: true, config: cfg },
|
||||
),
|
||||
@@ -1060,7 +1065,7 @@ unix("shell captures stderr from a failing command", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
const { prompt, chat } = yield* boot()
|
||||
const { prompt, run, chat } = yield* boot()
|
||||
const result = yield* prompt.shell({
|
||||
sessionID: chat.id,
|
||||
agent: "build",
|
||||
@@ -1073,7 +1078,7 @@ unix("shell captures stderr from a failing command", () =>
|
||||
|
||||
expect(tool.state.output).toContain("not found")
|
||||
expect(tool.state.metadata.output).toContain("not found")
|
||||
yield* prompt.assertNotBusy(chat.id)
|
||||
yield* run.assertNotBusy(chat.id)
|
||||
}),
|
||||
{ git: true, config: cfg },
|
||||
),
|
||||
@@ -1198,7 +1203,7 @@ unix(
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
const { prompt, chat } = yield* boot()
|
||||
const { prompt, run, chat } = yield* boot()
|
||||
|
||||
const sh = yield* prompt
|
||||
.shell({ sessionID: chat.id, agent: "build", command: "sleep 30" })
|
||||
@@ -1209,7 +1214,7 @@ unix(
|
||||
|
||||
const status = yield* SessionStatus.Service
|
||||
expect((yield* status.get(chat.id)).type).toBe("idle")
|
||||
const busy = yield* prompt.assertNotBusy(chat.id).pipe(Effect.exit)
|
||||
const busy = yield* run.assertNotBusy(chat.id).pipe(Effect.exit)
|
||||
expect(Exit.isSuccess(busy)).toBe(true)
|
||||
|
||||
const exit = yield* Fiber.await(sh)
|
||||
|
||||
@@ -43,6 +43,7 @@ import { Todo } from "../../src/session/todo"
|
||||
import { SessionCompaction } from "../../src/session/compaction"
|
||||
import { Instruction } from "../../src/session/instruction"
|
||||
import { SessionProcessor } from "../../src/session/processor"
|
||||
import { SessionRunState } from "../../src/session/run-state"
|
||||
import { SessionStatus } from "../../src/session/status"
|
||||
import { Shell } from "../../src/shell/shell"
|
||||
import { Snapshot } from "../../src/snapshot"
|
||||
@@ -107,6 +108,7 @@ const filetime = Layer.succeed(
|
||||
)
|
||||
|
||||
const status = SessionStatus.layer.pipe(Layer.provideMerge(Bus.layer))
|
||||
const run = SessionRunState.layer.pipe(Layer.provide(status))
|
||||
const infra = Layer.mergeAll(NodeFileSystem.layer, CrossSpawnSpawner.defaultLayer)
|
||||
|
||||
function makeHttp() {
|
||||
@@ -139,6 +141,7 @@ function makeHttp() {
|
||||
return Layer.mergeAll(
|
||||
TestLLMServer.layer,
|
||||
SessionPrompt.layer.pipe(
|
||||
Layer.provideMerge(run),
|
||||
Layer.provideMerge(compact),
|
||||
Layer.provideMerge(proc),
|
||||
Layer.provideMerge(registry),
|
||||
|
||||
Reference in New Issue
Block a user