feat(discord): add configurable ephemeral option for slash commands

This commit is contained in:
Wei He
2026-02-14 10:33:36 -05:00
committed by Shadow
parent b294342d7f
commit 122bdfa4e1
6 changed files with 54 additions and 2 deletions

View File

@@ -534,6 +534,10 @@ Use `bindings[].match.roles` to route Discord guild members to different agents
See [Slash commands](/tools/slash-commands) for command catalog and behavior.
Default slash command settings:
- `ephemeral: true`
## Feature details
<AccordionGroup>
@@ -969,7 +973,7 @@ High-signal Discord fields:
- startup/auth: `enabled`, `token`, `accounts.*`, `allowBots`
- policy: `groupPolicy`, `dm.*`, `guilds.*`, `guilds.*.channels.*`
- command: `commands.native`, `commands.useAccessGroups`, `configWrites`
- command: `commands.native`, `commands.useAccessGroups`, `configWrites`, `slashCommand.*`
- reply/history: `replyToMode`, `historyLimit`, `dmHistoryLimit`, `dms.*.historyLimit`
- delivery: `textChunkLimit`, `chunkMode`, `maxLinesPerMessage`
- streaming: `streamMode`, `draftChunk`, `blockStreaming`, `blockStreamingCoalesce`

View File

@@ -142,6 +142,11 @@ export type DiscordUiConfig = {
components?: DiscordUiComponentsConfig;
};
export type DiscordSlashCommandConfig = {
/** Reply ephemerally (default: true). */
ephemeral?: boolean;
};
export type DiscordAccountConfig = {
/** Optional display name for this account (used in CLI/UI lists). */
name?: string;
@@ -226,6 +231,8 @@ export type DiscordAccountConfig = {
agentComponents?: DiscordAgentComponentsConfig;
/** Discord UI customization (components, modals, etc.). */
ui?: DiscordUiConfig;
/** Slash command configuration. */
slashCommand?: DiscordSlashCommandConfig;
/** Privileged Gateway Intents (must also be enabled in Discord Developer Portal). */
intents?: DiscordIntentsConfig;
/** Voice channel conversation settings. */

View File

@@ -357,6 +357,12 @@ export const DiscordAccountSchema = z
.strict()
.optional(),
ui: DiscordUiSchema,
slashCommand: z
.object({
ephemeral: z.boolean().optional(),
})
.strict()
.optional(),
intents: z
.object({
presence: z.boolean().optional(),

View File

@@ -0,0 +1,24 @@
import { describe, expect, it } from "vitest";
import { resolveDiscordSlashCommandConfig } from "./commands.js";
describe("resolveDiscordSlashCommandConfig", () => {
it("defaults ephemeral to true when undefined", () => {
const result = resolveDiscordSlashCommandConfig(undefined);
expect(result.ephemeral).toBe(true);
});
it("defaults ephemeral to true when not explicitly false", () => {
const result = resolveDiscordSlashCommandConfig({});
expect(result.ephemeral).toBe(true);
});
it("sets ephemeral to false when explicitly false", () => {
const result = resolveDiscordSlashCommandConfig({ ephemeral: false });
expect(result.ephemeral).toBe(false);
});
it("keeps ephemeral true when explicitly true", () => {
const result = resolveDiscordSlashCommandConfig({ ephemeral: true });
expect(result.ephemeral).toBe(true);
});
});

View File

@@ -0,0 +1,9 @@
import type { DiscordSlashCommandConfig } from "../../config/types.discord.js";
export function resolveDiscordSlashCommandConfig(
raw?: DiscordSlashCommandConfig,
): Required<DiscordSlashCommandConfig> {
return {
ephemeral: raw?.ephemeral !== false,
};
}

View File

@@ -54,6 +54,7 @@ import {
createDiscordComponentStringSelect,
createDiscordComponentUserSelect,
} from "./agent-components.js";
import { resolveDiscordSlashCommandConfig } from "./commands.js";
import { createExecApprovalButton, DiscordExecApprovalHandler } from "./exec-approvals.js";
import { createDiscordGatewayPlugin } from "./gateway-plugin.js";
import { registerGateway, unregisterGateway } from "./gateway-registry.js";
@@ -246,8 +247,9 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
globalSetting: cfg.commands?.native,
});
const useAccessGroups = cfg.commands?.useAccessGroups !== false;
const slashCommand = resolveDiscordSlashCommandConfig(discordCfg.slashCommand);
const sessionPrefix = "discord:slash";
const ephemeralDefault = true;
const ephemeralDefault = slashCommand.ephemeral;
const voiceEnabled = discordCfg.voice?.enabled !== false;
if (token) {