fix: preserve discord argument reply visibility

This commit is contained in:
Gustavo Madeira Santana
2026-04-21 19:55:57 -04:00
parent fbe6595266
commit 0f5ab77156
2 changed files with 99 additions and 1 deletions

View File

@@ -35,6 +35,7 @@ import {
withTimeout,
} from "openclaw/plugin-sdk/text-runtime";
import { resolveDiscordChannelNameSafe } from "./channel-access.js";
import { resolveDiscordSlashCommandConfig } from "./commands.js";
import { resolveDiscordChannelInfo } from "./message-utils.js";
import {
readDiscordModelPickerRecentModels,
@@ -919,7 +920,7 @@ export async function handleDiscordCommandArgInteraction(params: {
sessionPrefix: ctx.sessionPrefix,
preferFollowUp: true,
threadBindings: ctx.threadBindings,
responseEphemeral: true,
responseEphemeral: resolveDiscordSlashCommandConfig(ctx.discordConfig?.slashCommand).ephemeral,
});
}

View File

@@ -0,0 +1,97 @@
import type { ChatCommandDefinition } from "openclaw/plugin-sdk/command-auth";
import * as commandRegistryModule from "openclaw/plugin-sdk/command-auth";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
createDiscordCommandArgFallbackButton,
type DispatchDiscordCommandInteraction,
} from "./native-command-ui.js";
import { createNoopThreadBindingManager } from "./thread-bindings.js";
type CommandArgContext = Parameters<typeof createDiscordCommandArgFallbackButton>[0]["ctx"];
type CommandArgButton = ReturnType<typeof createDiscordCommandArgFallbackButton>;
type CommandArgInteraction = Parameters<CommandArgButton["run"]>[0];
type CommandArgData = Parameters<CommandArgButton["run"]>[1];
function createCommandDefinition(): ChatCommandDefinition {
return {
key: "think",
nativeName: "think",
description: "Set thinking level",
textAliases: ["/think"],
acceptsArgs: true,
args: [
{
name: "level",
description: "Thinking level",
type: "string",
required: true,
},
],
argsParsing: "none",
scope: "native",
};
}
function createContext(
discordConfig: NonNullable<OpenClawConfig["channels"]>["discord"],
): CommandArgContext {
const cfg = {
channels: {
discord: discordConfig,
},
} as OpenClawConfig;
return {
cfg,
discordConfig,
accountId: "default",
sessionPrefix: "discord:slash",
threadBindings: createNoopThreadBindingManager("default"),
};
}
function createInteraction(): CommandArgInteraction {
return {
user: {
id: "owner",
username: "tester",
globalName: "Tester",
},
update: vi.fn().mockResolvedValue({ ok: true }),
} as unknown as CommandArgInteraction;
}
async function safeInteractionCall<T>(_label: string, fn: () => Promise<T>): Promise<T | null> {
return await fn();
}
describe("discord command argument fallback", () => {
afterEach(() => {
vi.restoreAllMocks();
});
it("preserves public slash command visibility for selected argument follow-ups", async () => {
const commandDefinition = createCommandDefinition();
vi.spyOn(commandRegistryModule, "findCommandByNativeName").mockReturnValue(commandDefinition);
const dispatchSpy = vi.fn<DispatchDiscordCommandInteraction>().mockResolvedValue();
const button = createDiscordCommandArgFallbackButton({
ctx: createContext({ slashCommand: { ephemeral: false } }),
safeInteractionCall,
dispatchCommandInteraction: dispatchSpy,
});
await button.run(createInteraction(), {
command: "think",
arg: "level",
value: "high",
user: "owner",
} satisfies CommandArgData);
expect(dispatchSpy).toHaveBeenCalledWith(
expect.objectContaining({
prompt: "/think high",
responseEphemeral: false,
}),
);
});
});