mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 23:14:47 +00:00
fix(discord): harden read message results (#82276)
Validate Discord read message results before normalizing channel history, preserving the Discord array contract while replacing opaque map crashes with a clear boundary error. Fixes #82252.
This commit is contained in:
committed by
GitHub
parent
8ba0bb2a8a
commit
4add9bab77
@@ -18,6 +18,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Plugin releases: require external package compatibility metadata in the npm plugin publish plan, matching the ClawHub package contract before packages ship.
|
||||
- Agents/OpenAI-compatible: honor per-model `max_completion_tokens`/`max_tokens` params in embedded OpenAI-completions runs so high-token Kimi-style routes keep their configured completion cap. Fixes #82230. Thanks @albert-zen.
|
||||
- Agents/local: install a local gateway request scope around trusted `openclaw agent --local` runs, so subagent completion announces can use in-process gateway dispatch without crashing. Fixes #82140. Thanks @Kushmaro.
|
||||
- Discord: validate message-read results before normalizing channel history and report unexpected payloads with a Discord boundary error instead of `map is not a function`. Fixes #82252. Thanks @jessewunderlich.
|
||||
- Telegram/active-memory: run blocking memory recall through the Telegram provider for direct-message turns even when the hook context carries the raw chat id, preventing embedded recall from launching against an invalid numeric channel. Fixes #82177. Thanks @cslash-zz.
|
||||
- Control UI/WebChat: keep optimistic image messages from embedding large inline `data:` previews and preserve image-only user turns in chat history, avoiding browser stack overflows when sending image attachments. Fixes #82182. Thanks @ExploreSheep.
|
||||
- Agents/media: preserve message-tool-only delivery for generated music and video completion handoffs, so group/channel completions do not finish without posting the generated attachment.
|
||||
|
||||
@@ -24,6 +24,29 @@ function parseDiscordMessageLink(link: string) {
|
||||
};
|
||||
}
|
||||
|
||||
function describeDiscordMessageListResult(value: unknown): string {
|
||||
if (Array.isArray(value)) {
|
||||
return "array";
|
||||
}
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
if (value && typeof value === "object") {
|
||||
const keys = Object.keys(value).toSorted();
|
||||
return keys.length ? `object with keys ${keys.join(", ")}` : "object";
|
||||
}
|
||||
return typeof value;
|
||||
}
|
||||
|
||||
function assertDiscordMessageListResult(value: unknown): Array<unknown> {
|
||||
if (Array.isArray(value)) {
|
||||
return value;
|
||||
}
|
||||
throw new Error(
|
||||
`Discord message read returned ${describeDiscordMessageListResult(value)} instead of an array.`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function handleDiscordMessageManagementAction(ctx: DiscordMessagingActionContext) {
|
||||
switch (ctx.action) {
|
||||
case "permissions": {
|
||||
@@ -80,10 +103,8 @@ export async function handleDiscordMessageManagementAction(ctx: DiscordMessaging
|
||||
after: readStringParam(ctx.params, "after"),
|
||||
around: readStringParam(ctx.params, "around"),
|
||||
};
|
||||
const messages = await discordMessagingActionRuntime.readMessagesDiscord(
|
||||
channelId,
|
||||
query,
|
||||
ctx.withOpts(),
|
||||
const messages = assertDiscordMessageListResult(
|
||||
await discordMessagingActionRuntime.readMessagesDiscord(channelId, query, ctx.withOpts()),
|
||||
);
|
||||
return jsonResult({
|
||||
ok: true,
|
||||
|
||||
@@ -389,6 +389,14 @@ describe("handleDiscordMessagingAction", () => {
|
||||
expect(payload.messages[0].timestampUtc).toBe(new Date(expectedMs).toISOString());
|
||||
});
|
||||
|
||||
it("rejects unexpected readMessages payloads with a boundary error", async () => {
|
||||
readMessagesDiscord.mockResolvedValueOnce({ ok: true } as never);
|
||||
|
||||
await expect(
|
||||
handleMessagingAction("readMessages", { channelId: "C1" }, enableAllActions),
|
||||
).rejects.toThrow("Discord message read returned object with keys ok instead of an array.");
|
||||
});
|
||||
|
||||
it("threads provided cfg into readMessages calls", async () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
|
||||
Reference in New Issue
Block a user