mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:00:42 +00:00
fix(discord): allow configured application ids
This commit is contained in:
@@ -60,7 +60,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Ollama: keep explicit local model runs on target-provider runtime hooks when PI discovery is skipped, so one-shot Ollama calls no longer cold-load unrelated provider runtimes before streaming. Fixes #74078. Thanks @sakalaboator.
|
||||
- Slack/prompts: rely on Slack `interactiveReplies` guidance instead of generic `inlineButtons` config hints so enabled Slack button directives are not contradicted. Fixes #46647. Thanks @jeremykoerber.
|
||||
- Slack/reactions: treat duplicate `already_reacted` responses as idempotent success so repeated agent reaction adds no longer surface as tool failures. Fixes #69005. Thanks @shipitsteven and @martingarramon.
|
||||
- Channels/Discord: cool down Cloudflare/Error 1015 HTML 429 REST failures during startup application lookup and gateway metadata fetches, sanitizing HTML bodies before logging and honoring Retry-After before falling back to a conservative cooldown. Fixes #38853. Thanks @djgeorg3 and @Garyko0730.
|
||||
- Channels/Discord: cool down Cloudflare/Error 1015 HTML 429 REST failures during startup application lookup and gateway metadata fetches, add `channels.discord.applicationId` as an app-id lookup bypass, sanitize HTML bodies before logging, and honor Retry-After before falling back to a conservative cooldown. Fixes #38853. Thanks @djgeorg3 and @Garyko0730.
|
||||
- Slack/tools: expose `fileId` in the shared message tool schema so `download-file` can receive Slack attachment IDs from inbound placeholders. Fixes #45574. Thanks @chadvegas.
|
||||
- Exec: reject invalid per-call `host` values instead of silently falling back to the default target, so hostname-like values fail before commands run. Fixes #74426. Thanks @scr00ge-00 and @vyctorbrzezowski.
|
||||
- Google/Gemini: send non-empty placeholder content when a Gemini run is triggered with empty or filtered user content, avoiding `contents is not specified` API errors. Thanks @CaoYuhaoCarl.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
b095536aeeb273b029a7a96cd8406cbcbc315dfd67dc45f469782ce1ccbc9e08 config-baseline.json
|
||||
7bf720f6d9040c53323553b1bd351f688137c6b352c4cf2acfd7f7d252644b38 config-baseline.json
|
||||
ab9a004ec78ed51e646be29eb10aa6700de1d47fee77331a85ca5e2cd15b6e93 config-baseline.core.json
|
||||
fab66aa304db5697e87259165ad261006719eb6e6cdbd25f957fcba2b7b324e9 config-baseline.channel.json
|
||||
92712871defa92eeda8161b516db85574681f2b70678b940508a808b987aeae2 config-baseline.channel.json
|
||||
c4231c2194206547af8ad94342dc00aadb734f43cb49cc79d4c46bdbb80c3f95 config-baseline.plugin.json
|
||||
|
||||
@@ -115,6 +115,7 @@ openclaw gateway
|
||||
|
||||
If OpenClaw is already running as a background service, restart it via the OpenClaw Mac app or by stopping and restarting the `openclaw gateway run` process.
|
||||
For managed service installs, run `openclaw gateway install` from a shell where `DISCORD_BOT_TOKEN` is present, or store the variable in `~/.openclaw/.env`, so the service can resolve the env SecretRef after restart.
|
||||
If your host is blocked or rate-limited by Discord's startup application lookup, set `channels.discord.applicationId` to the application's client ID from the Developer Portal so startup can skip that REST call.
|
||||
|
||||
</Step>
|
||||
|
||||
|
||||
@@ -76,6 +76,30 @@ describe("discord config schema", () => {
|
||||
expect(cfg.historyLimit).toBe(3);
|
||||
});
|
||||
|
||||
it("accepts Discord application IDs at top-level and account scope", () => {
|
||||
const cfg = expectValidDiscordConfig({
|
||||
applicationId: "123456789012345678",
|
||||
accounts: {
|
||||
work: {
|
||||
applicationId: 234567890123456,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(cfg.applicationId).toBe("123456789012345678");
|
||||
expect(cfg.accounts?.work?.applicationId).toBe("234567890123456");
|
||||
});
|
||||
|
||||
it("rejects unsafe numeric Discord application IDs", () => {
|
||||
const issues = expectInvalidDiscordConfig({
|
||||
applicationId: 106232522769186816,
|
||||
});
|
||||
|
||||
expect(
|
||||
issues.some((issue) => issue.message.includes("not a valid non-negative safe integer")),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("loads guild map and dm group settings", () => {
|
||||
const cfg = expectValidDiscordConfig({
|
||||
enabled: true,
|
||||
|
||||
@@ -222,4 +222,8 @@ export const discordChannelConfigUiHints = {
|
||||
help: "Discord bot token used for gateway and REST API authentication for this provider account. Keep this secret out of committed config and rotate immediately after any leak.",
|
||||
sensitive: true,
|
||||
},
|
||||
applicationId: {
|
||||
label: "Discord Application ID",
|
||||
help: "Optional Discord application/client ID. Set this when hosted environments cannot reach Discord's application lookup endpoint during startup.",
|
||||
},
|
||||
} satisfies Record<string, ChannelConfigUiHint>;
|
||||
|
||||
@@ -887,6 +887,30 @@ describe("monitorDiscordProvider", () => {
|
||||
expect(getConstructedClientOptions().clientId).toBe("123");
|
||||
});
|
||||
|
||||
it("uses configured application id before token parsing or REST lookup", async () => {
|
||||
const fetchApplicationId = vi.fn(async () => "network-app");
|
||||
providerTesting.setFetchDiscordApplicationId(fetchApplicationId);
|
||||
resolveDiscordAccountMock.mockReturnValue({
|
||||
accountId: "default",
|
||||
token: "MTIz.abc.def",
|
||||
config: {
|
||||
applicationId: "987654321098765432",
|
||||
commands: { native: true, nativeSkills: false },
|
||||
voice: { enabled: false },
|
||||
agentComponents: { enabled: false },
|
||||
execApprovals: { enabled: false },
|
||||
},
|
||||
});
|
||||
|
||||
await monitorDiscordProvider({
|
||||
config: baseConfig(),
|
||||
runtime: baseRuntime(),
|
||||
});
|
||||
|
||||
expect(fetchApplicationId).not.toHaveBeenCalled();
|
||||
expect(getConstructedClientOptions().clientId).toBe("987654321098765432");
|
||||
});
|
||||
|
||||
it("reports connected status on startup and shutdown", async () => {
|
||||
const setStatus = vi.fn();
|
||||
clientGetPluginMock.mockImplementation((name: string) =>
|
||||
|
||||
@@ -317,7 +317,11 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
||||
phase: "fetch-application-id:start",
|
||||
startAt: startupStartedAt,
|
||||
});
|
||||
const parsedApplicationId = parseApplicationIdFromToken(token);
|
||||
const configuredApplicationId =
|
||||
typeof discordCfg.applicationId === "string" && discordCfg.applicationId.trim()
|
||||
? discordCfg.applicationId.trim()
|
||||
: undefined;
|
||||
const parsedApplicationId = configuredApplicationId ?? parseApplicationIdFromToken(token);
|
||||
const applicationId =
|
||||
parsedApplicationId ??
|
||||
(await (fetchDiscordApplicationIdForTesting ?? fetchDiscordApplicationId)(
|
||||
|
||||
@@ -789,6 +789,9 @@ export const GENERATED_BUNDLED_CHANNEL_CONFIG_METADATA = [
|
||||
},
|
||||
],
|
||||
},
|
||||
applicationId: {
|
||||
type: "string",
|
||||
},
|
||||
proxy: {
|
||||
type: "string",
|
||||
},
|
||||
@@ -2152,6 +2155,9 @@ export const GENERATED_BUNDLED_CHANNEL_CONFIG_METADATA = [
|
||||
},
|
||||
],
|
||||
},
|
||||
applicationId: {
|
||||
type: "string",
|
||||
},
|
||||
proxy: {
|
||||
type: "string",
|
||||
},
|
||||
@@ -3622,6 +3628,10 @@ export const GENERATED_BUNDLED_CHANNEL_CONFIG_METADATA = [
|
||||
help: "Discord bot token used for gateway and REST API authentication for this provider account. Keep this secret out of committed config and rotate immediately after any leak.",
|
||||
sensitive: true,
|
||||
},
|
||||
applicationId: {
|
||||
label: "Discord Application ID",
|
||||
help: "Optional Discord application/client ID. Set this when hosted environments cannot reach Discord's application lookup endpoint during startup.",
|
||||
},
|
||||
},
|
||||
unsupportedSecretRefSurfacePatterns: [
|
||||
"channels.discord.accounts.*.threadBindings.webhookToken",
|
||||
|
||||
@@ -241,6 +241,8 @@ export type DiscordAccountConfig = {
|
||||
/** If false, do not start this Discord account. Default: true. */
|
||||
enabled?: boolean;
|
||||
token?: SecretInput;
|
||||
/** Optional Discord application/client ID. Set this when REST application lookup is blocked. */
|
||||
applicationId?: string;
|
||||
/** HTTP(S) proxy URL for Discord gateway WebSocket connections. */
|
||||
proxy?: string;
|
||||
/** Timeout for Discord /gateway/bot metadata lookup before falling back to the default gateway URL. Default: 30000. */
|
||||
|
||||
@@ -527,6 +527,7 @@ export const DiscordAccountSchema = z
|
||||
commands: ProviderCommandsSchema,
|
||||
configWrites: z.boolean().optional(),
|
||||
token: SecretInputSchema.optional().register(sensitive),
|
||||
applicationId: DiscordIdSchema.optional(),
|
||||
proxy: z.string().optional(),
|
||||
gatewayInfoTimeoutMs: z.number().int().positive().max(120_000).optional(),
|
||||
allowBots: z.union([z.boolean(), z.literal("mentions")]).optional(),
|
||||
|
||||
Reference in New Issue
Block a user