fix(opencode): process prompts queued during loop shutdown
This commit is contained in:
parent
dc216e8b03
commit
258fe1546c
2 changed files with 60 additions and 0 deletions
|
|
@ -1231,6 +1231,10 @@ export const layer = Layer.effect(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.noReply === true) return message
|
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 })
|
return yield* loop({ sessionID: input.sessionID })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1226,6 +1226,62 @@ it.instance(
|
||||||
3_000,
|
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(
|
it.instance(
|
||||||
"assertNotBusy fails with BusyError when loop running",
|
"assertNotBusy fails with BusyError when loop running",
|
||||||
() =>
|
() =>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue