diff --git a/ts/packages/dispatcher/dispatcher/src/dispatcher.ts b/ts/packages/dispatcher/dispatcher/src/dispatcher.ts index 5684b2052..aa07097e1 100644 --- a/ts/packages/dispatcher/dispatcher/src/dispatcher.ts +++ b/ts/packages/dispatcher/dispatcher/src/dispatcher.ts @@ -550,6 +550,7 @@ export function createDispatcherFromContext( // Use original requestId so display appends to same message group context.currentRequestId = pending.requestId; context.commandResult = undefined; + let commandResult: CommandResult | undefined; try { const appAgent = context.agents.getAppAgent( pending.agentName, @@ -611,11 +612,11 @@ export function createDispatcherFromContext( } } } finally { - const result = context.commandResult; + commandResult = context.commandResult; context.commandResult = undefined; context.currentRequestId = undefined; - return result; } + return commandResult; }); }, async respondToInteraction( diff --git a/ts/packages/dispatcher/dispatcher/test/chainedChoice.spec.ts b/ts/packages/dispatcher/dispatcher/test/chainedChoice.spec.ts index fb61d02ec..908bc402e 100644 --- a/ts/packages/dispatcher/dispatcher/test/chainedChoice.spec.ts +++ b/ts/packages/dispatcher/dispatcher/test/chainedChoice.spec.ts @@ -51,6 +51,13 @@ const handlers = { ), ), }, + fail: { + description: "Returns a choice whose callback fails", + run: async () => + createYesNoChoiceResult(choiceManager, "fail?", async () => { + throw new Error("choice callback failed"); + }), + }, }, } as const; @@ -140,4 +147,19 @@ describe("Chained choice cards", () => { expect(captured[1].message).toBe("second?"); expect(captured[1].choiceId).not.toBe(captured[0].choiceId); }, 10_000); + + it("propagates choice callback failures without blocking later choices", async () => { + await awaitCommand(dispatcher, "@choicechain fail"); + const choice = captured.at(-1)!; + + await expect( + dispatcher.respondToChoice(choice.choiceId, true), + ).rejects.toThrow("choice callback failed"); + + await awaitCommand(dispatcher, "@choicechain chain"); + const nextChoice = captured.at(-1)!; + await dispatcher.respondToChoice(nextChoice.choiceId, true); + + expect(captured.at(-1)!.message).toBe("second?"); + }); });