diff --git a/packages/tui/src/mini/runtime.queue.ts b/packages/tui/src/mini/runtime.queue.ts index f7b61b9cf9e2..a30e70039a79 100644 --- a/packages/tui/src/mini/runtime.queue.ts +++ b/packages/tui/src/mini/runtime.queue.ts @@ -191,6 +191,7 @@ export async function runPromptQueue(input: QueueInput): Promise { if (next.type === "error") { throw next.error } + admission.resolve() if (sent.mode !== "shell" && admissionVersion !== version) { do { const current = admissionVersion diff --git a/packages/tui/test/mini/runtime.queue.test.ts b/packages/tui/test/mini/runtime.queue.test.ts index 111ef4feaad0..4ea0a7547af7 100644 --- a/packages/tui/test/mini/runtime.queue.test.ts +++ b/packages/tui/test/mini/runtime.queue.test.ts @@ -362,6 +362,45 @@ describe("run runtime queue", () => { expect(admitted).toEqual(["three"]) }) + test.each([false, true])( + "releases follow-ups after a handled prompt failure (admission fails: %s)", + async (fails) => { + const ui = createFooterApiFixture() + const started = Promise.withResolvers() + const request = Promise.withResolvers() + const admitted: string[] = [] + const errors: string[] = [] + const task = runPromptQueue({ + footer: ui.api, + run: async () => { + started.resolve() + // The interactive runtime displays transport errors and returns without admission. + await request.promise.catch((error: Error) => { + errors.push(error.message) + }) + }, + admit: async (prompt) => { + admitted.push(prompt.text) + if (fails) throw new Error("follow-up failed") + }, + onAdmissionError: (_prompt, error) => { + errors.push(error instanceof Error ? error.message : String(error)) + }, + settle: async () => ui.api.close(), + }) + + ui.submit("one") + await started.promise + ui.submit("two") + request.reject(new Error("transport failed")) + await task + + expect(admitted).toEqual(["two"]) + expect(errors).toEqual(fails ? ["transport failed", "follow-up failed"] : ["transport failed"]) + expect(ui.api.isClosed).toBe(true) + }, + ) + test("close aborts an in-flight durable admission", async () => { const ui = createFooterApiFixture() let admissionHit = false