Skip to content

Commit c0c2be9

Browse files
committed
fix(whatsapp): deliver final error payloads so incomplete-turn errors reach users
1 parent aef9388 commit c0c2be9

4 files changed

Lines changed: 28 additions & 11 deletions

File tree

extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.test.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ describe("whatsapp inbound dispatch", () => {
816816
expect(rememberSentText).not.toHaveBeenCalled();
817817
});
818818

819-
it("suppresses error payload text", async () => {
819+
it("delivers final error payload text so incomplete-turn errors reach users (#84569)", async () => {
820820
const deliverReply = vi.fn(async () => acceptedDeliveryResult());
821821
const rememberSentText = vi.fn();
822822

@@ -825,7 +825,22 @@ describe("whatsapp inbound dispatch", () => {
825825
const deliver = getCapturedDeliver();
826826
expect(deliver).toBeTypeOf("function");
827827

828-
await deliver?.({ text: "provider exploded", isError: true }, { kind: "final" });
828+
await deliver?.({ text: "incomplete turn error", isError: true }, { kind: "final" });
829+
830+
expect(deliverReply).toHaveBeenCalled();
831+
expect(rememberSentText).toHaveBeenCalled();
832+
});
833+
834+
it("still suppresses non-final error payloads", async () => {
835+
const deliverReply = vi.fn(async () => acceptedDeliveryResult());
836+
const rememberSentText = vi.fn();
837+
838+
await dispatchBufferedReply({ deliverReply, rememberSentText });
839+
840+
const deliver = getCapturedDeliver();
841+
expect(deliver).toBeTypeOf("function");
842+
843+
await deliver?.({ text: "tool error", isError: true }, { kind: "tool" });
829844

830845
expect(deliverReply).not.toHaveBeenCalled();
831846
expect(rememberSentText).not.toHaveBeenCalled();

extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ function resolveWhatsAppDeliverablePayload(
116116
if (payload.isReasoning === true || payload.isCompactionNotice === true) {
117117
return null;
118118
}
119-
if (payload.isError === true) {
119+
// Allow isError payloads with user-facing text through for final delivery.
120+
// Incomplete-turn error messages (payloads=0) must reach the user (#84569).
121+
if (payload.isError === true && info.kind !== "final") {
120122
return null;
121123
}
122124
if (info.kind === "tool") {

extensions/whatsapp/src/outbound-adapter.sendpayload.test.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,19 +163,22 @@ describe("whatsappOutbound sendPayload", () => {
163163
expect(sendWhatsApp).not.toHaveBeenCalled();
164164
});
165165

166-
it("suppresses routed error payloads", async () => {
167-
const sendWhatsApp = vi.fn();
166+
it("delivers routed error payloads so incomplete-turn errors reach users (#84569)", async () => {
167+
const sendWhatsApp = vi.fn().mockResolvedValue({
168+
channel: "whatsapp",
169+
messageId: "msg-error-001",
170+
});
168171

169172
const result = await whatsappOutbound.sendPayload!({
170173
cfg: {},
171174
to: "5511999999999@c.us",
172175
text: "",
173-
payload: { text: "provider exploded", isError: true },
176+
payload: { text: "incomplete turn error", isError: true },
174177
deps: { sendWhatsApp },
175178
});
176179

177-
expect(result).toEqual({ channel: "whatsapp", messageId: "" });
178-
expect(sendWhatsApp).not.toHaveBeenCalled();
180+
expect(sendWhatsApp).toHaveBeenCalled();
181+
expect(result).toEqual({ channel: "whatsapp", messageId: "msg-error-001" });
179182
});
180183

181184
it("sanitizes HTML-only text to whitespace-only payload", () => {

extensions/whatsapp/src/outbound-base.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,6 @@ export function createWhatsAppOutboundBase({
231231
return {
232232
...outbound,
233233
sendPayload: async (ctx) => {
234-
if (ctx.payload.isError === true) {
235-
return { channel: "whatsapp", messageId: "" };
236-
}
237234
const payload = normalizeWhatsAppOutboundPayload(ctx.payload, { normalizeText });
238235
if (!payload.text && !(payload.mediaUrl || payload.mediaUrls?.length)) {
239236
if (ctx.payload.interactive || ctx.payload.presentation || ctx.payload.channelData) {

0 commit comments

Comments
 (0)