Compare commits

...

1 Commits

Author SHA1 Message Date
Aiden Cline 258fe1546c fix(opencode): process prompts queued during loop shutdown 2026-06-02 21:08:32 -05:00
2 changed files with 60 additions and 0 deletions
+4
View File
@@ -1231,6 +1231,10 @@ export const layer = Layer.effect(
}
if (input.noReply === true) return message
const result = yield* loop({ sessionID: input.sessionID })
if (result.info.id > message.info.id) return result
// The prompt may have joined a loop that was already exiting after its
// last message snapshot. Run once more so the saved message is consumed.
return yield* loop({ sessionID: input.sessionID })
})
@@ -1226,6 +1226,62 @@ it.instance(
3_000,
)
it.instance(
"prompt submitted while an active run exits starts another loop pass",
() =>
Effect.gen(function* () {
const { llm } = yield* useServerConfig(providerCfg)
const prompt = yield* SessionPrompt.Service
const run = yield* SessionRunState.Service
const sessions = yield* Session.Service
const chat = yield* sessions.create({ title: "Pinned" })
yield* seed(chat.id, { finish: "stop" })
const stale = (yield* sessions.messages({ sessionID: chat.id })).findLast((msg) => msg.info.role === "assistant")
if (!stale) throw new Error("expected seeded assistant")
const started = yield* Deferred.make<void>()
const release = yield* Deferred.make<void>()
const active = yield* run
.ensureRunning(
chat.id,
Effect.succeed(stale),
Deferred.succeed(started, void 0).pipe(Effect.andThen(Deferred.await(release)), Effect.as(stale)),
)
.pipe(Effect.forkChild)
yield* Deferred.await(started)
yield* llm.text("second")
const id = MessageID.ascending()
const queued = yield* prompt
.prompt({
sessionID: chat.id,
messageID: id,
agent: "build",
model: ref,
parts: [{ type: "text", text: "second" }],
})
.pipe(Effect.forkChild)
yield* pollWithTimeout(
sessions
.messages({ sessionID: chat.id })
.pipe(Effect.map((msgs) => (msgs.some((msg) => msg.info.id === id) ? true : undefined))),
"timed out waiting for queued prompt to save",
)
yield* Deferred.succeed(release, void 0)
yield* Fiber.await(active)
const exit = yield* Fiber.await(queued)
expect(Exit.isSuccess(exit)).toBe(true)
if (!Exit.isSuccess(exit)) return
expect(exit.value.info.role).toBe("assistant")
if (exit.value.info.role !== "assistant") return
expect(exit.value.info.parentID).toBe(id)
expect(exit.value.parts.some((part) => part.type === "text" && part.text === "second")).toBe(true)
expect(yield* llm.calls).toBe(1)
}),
3_000,
)
it.instance(
"assertNotBusy fails with BusyError when loop running",
() =>