Skip to content

Commit 6d05fd4

Browse files
committed
Fix Discord native empty reply fallback
1 parent bb8192f commit 6d05fd4

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

extensions/discord/src/monitor/native-command-agent-reply.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,24 @@ type NativeCommandEffectiveRoute = {
2828
agentId: string;
2929
};
3030

31+
function shouldSendNoVisibleReplyFallback(dispatchResult: {
32+
counts: { final?: number; block?: number; tool?: number };
33+
noVisibleReplyFallbackEligible?: boolean;
34+
queuedFinal?: boolean;
35+
sendPolicyDenied?: boolean;
36+
sourceReplyDeliveryMode?: string;
37+
}): boolean {
38+
return (
39+
dispatchResult.noVisibleReplyFallbackEligible === true &&
40+
dispatchResult.queuedFinal !== true &&
41+
dispatchResult.sendPolicyDenied !== true &&
42+
dispatchResult.sourceReplyDeliveryMode !== "message_tool_only" &&
43+
(dispatchResult.counts.final ?? 0) === 0 &&
44+
(dispatchResult.counts.block ?? 0) === 0 &&
45+
(dispatchResult.counts.tool ?? 0) === 0
46+
);
47+
}
48+
3149
export async function dispatchDiscordNativeAgentReply(params: {
3250
cfg: OpenClawConfig;
3351
discordConfig: DiscordConfig;
@@ -106,7 +124,8 @@ export async function dispatchDiscordNativeAgentReply(params: {
106124
dispatchResult.queuedFinal ||
107125
dispatchResult.counts.final !== 0 ||
108126
dispatchResult.counts.block !== 0 ||
109-
dispatchResult.counts.tool !== 0
127+
dispatchResult.counts.tool !== 0 ||
128+
!shouldSendNoVisibleReplyFallback(dispatchResult)
110129
) {
111130
return;
112131
}

extensions/discord/src/monitor/native-command.plugin-dispatch.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,7 @@ describe("Discord native plugin command dispatch", () => {
901901
runtimeModuleMocks.dispatchReplyWithDispatcher.mockResolvedValue({
902902
counts: { final: 0, block: 0, tool: 0 },
903903
queuedFinal: false,
904+
noVisibleReplyFallbackEligible: true,
904905
} as never);
905906
const command = await createNativeCommand(cfg, {
906907
name: "new",
@@ -917,6 +918,27 @@ describe("Discord native plugin command dispatch", () => {
917918
expect(interaction.reply).not.toHaveBeenCalled();
918919
});
919920

921+
it("does not warn when dispatch completes without a fallback-eligible visible reply", async () => {
922+
const cfg = createConfig();
923+
const interaction = createInteraction();
924+
runtimeModuleMocks.matchPluginCommand.mockReturnValue(null);
925+
runtimeModuleMocks.dispatchReplyWithDispatcher.mockResolvedValue({
926+
counts: { final: 0, block: 0, tool: 0 },
927+
queuedFinal: false,
928+
noVisibleReplyFallbackEligible: false,
929+
} as never);
930+
const command = await createNativeCommand(cfg, {
931+
name: "compact",
932+
description: "Compact the active session.",
933+
acceptsArgs: false,
934+
});
935+
936+
await (command as { run: (interaction: unknown) => Promise<void> }).run(interaction as unknown);
937+
938+
expectNoFollowUpContent(interaction, "Command produced no visible reply.");
939+
expect(interaction.reply).not.toHaveBeenCalled();
940+
});
941+
920942
it("does not warn when dispatch reports a queued final without visible counts", async () => {
921943
const cfg = createConfig();
922944
const interaction = createInteraction();

0 commit comments

Comments
 (0)