fix(discord): surface silent reply-delivery skips and remove runtime.error optional-chain

This commit is contained in:
UB
2026-05-23 20:47:24 -06:00
committed by Peter Steinberger
parent 75c6cf2966
commit 3a48366f3e
2 changed files with 110 additions and 1 deletions
@@ -0,0 +1,64 @@
import { describe, expect, it } from "vitest";
import { formatDiscordReplySkip } from "./message-handler.process.js";
describe("formatDiscordReplySkip", () => {
it("includes target and session when both are present for an aborted skip", () => {
expect(
formatDiscordReplySkip({
kind: "final",
reason: "aborted before delivery",
target: "channel:123",
sessionKey: "agent:main:discord:channel:123",
}),
).toBe(
"discord final reply skipped (aborted before delivery): target=channel:123 session=agent:main:discord:channel:123",
);
});
it("renders the reasoning-payload reason with the same shape", () => {
expect(
formatDiscordReplySkip({
kind: "block",
reason: "reasoning payload",
target: "channel:456",
sessionKey: "agent:friday:discord:channel:456",
}),
).toBe(
"discord block reply skipped (reasoning payload): target=channel:456 session=agent:friday:discord:channel:456",
);
});
it("omits the session tag when sessionKey is undefined", () => {
expect(
formatDiscordReplySkip({
kind: "tool",
reason: "aborted before delivery",
target: "channel:456",
}),
).toBe("discord tool reply skipped (aborted before delivery): target=channel:456");
});
it("treats an empty-string sessionKey the same as undefined", () => {
expect(
formatDiscordReplySkip({
kind: "tool",
reason: "reasoning payload",
target: "channel:c1",
sessionKey: "",
}),
).toBe("discord tool reply skipped (reasoning payload): target=channel:c1");
});
it("preserves the kind discriminant in the message prefix", () => {
for (const kind of ["tool", "block", "final"] as const) {
expect(
formatDiscordReplySkip({
kind,
reason: "aborted before delivery",
target: "channel:1",
sessionKey: "s",
}),
).toContain(`discord ${kind} reply skipped`);
}
});
});
@@ -104,6 +104,23 @@ function formatDiscordReplyDeliveryFailure(params: {
return `discord ${params.kind} reply failed (${context}): ${String(params.err)}`;
}
type DiscordReplySkipReason = "aborted before delivery" | "reasoning payload";
export function formatDiscordReplySkip(params: {
kind: "tool" | "block" | "final";
reason: DiscordReplySkipReason;
target: string;
sessionKey?: string;
}) {
const context = [
`target=${params.target}`,
params.sessionKey ? `session=${params.sessionKey}` : undefined,
]
.filter(Boolean)
.join(" ");
return `discord ${params.kind} reply skipped (${params.reason}): ${context}`;
}
type DiscordMessageProcessObserver = {
onFinalReplyStart?: () => void;
onFinalReplyDelivered?: () => void;
@@ -528,11 +545,29 @@ export async function processDiscordMessage(
humanDelay: resolveHumanDelayConfig(cfg, route.agentId),
deliver: async (payload: ReplyPayload, info) => {
if (isProcessAborted(abortSignal)) {
// Surface so operators don't chase missing replies when an abort
// drops a model-produced text payload (see PR for the incident).
logVerbose(
formatDiscordReplySkip({
kind: info.kind,
reason: "aborted before delivery",
target: deliverTarget,
sessionKey: ctxPayload.SessionKey,
}),
);
return;
}
const isFinal = info.kind === "final";
if (payload.isReasoning) {
// Reasoning/thinking payloads should not be delivered to Discord.
logVerbose(
formatDiscordReplySkip({
kind: info.kind,
reason: "reasoning payload",
target: deliverTarget,
sessionKey: ctxPayload.SessionKey,
}),
);
return;
}
if (isFinal) {
@@ -699,6 +734,16 @@ export async function processDiscordMessage(
}
}
if (isProcessAborted(abortSignal)) {
// Mirror the entry-point abort log so a mid-deliver abort (after
// the preview path bowed out) does not silently drop the reply.
logVerbose(
formatDiscordReplySkip({
kind: info.kind,
reason: "aborted before delivery",
target: deliverTarget,
sessionKey: ctxPayload.SessionKey,
}),
);
return;
}
@@ -732,7 +777,7 @@ export async function processDiscordMessage(
}
},
onError: (err, info) => {
runtime.error?.(
runtime.error(
danger(
formatDiscordReplyDeliveryFailure({
kind: info.kind,