diff --git a/CHANGELOG.md b/CHANGELOG.md index 70379cbc890..aa89b51d524 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Docs: https://docs.openclaw.ai - Cron: treat isolated run-level agent failures as job errors even when no reply payload is produced, synthesizing a safe error payload so model/provider failures increment error counters and trigger failure notifications instead of clearing as successful. Fixes #43604; carries forward #43631. Thanks @SPFAdvisors. - Cron: preserve exact `NO_REPLY` tool results from isolated jobs with empty final assistant turns as quiet successes instead of surfacing incomplete-turn errors. Fixes #68452; carries forward #68453. Thanks @anyech. - Cron: resolve failure alerts and failure-destination announcements against `session:` targets before falling back to the creator session, so jobs created from group chats can notify the targeted direct session without cross-account routing errors. Refs #62777; carries forward #68535. Thanks @slideshow-dingo and @likewen-tech. +- Discord: preserve explicit `user:` and `channel:` delivery targets through plugin routing so cron announcements and failure alerts keep their intended recipient kind. Refs #62777; carries forward #62798. Thanks @neeravmakwana. - Cron: classify isolated runs as errors from structured embedded-run execution-denial metadata, with final-output marker fallback for `SYSTEM_RUN_DENIED`, `INVALID_REQUEST`, and approval-binding refusals, so blocked commands no longer appear green in cron history. Fixes #67172; carries forward #67186. Thanks @oc-gh-dr, @hclsys, and @1yihui. - Onboarding/GitHub Copilot: add manifest-owned `--github-copilot-token` support for non-interactive setup, including env fallback, tokenRef storage in ref mode, saved-profile reuse, and current Copilot default-model wiring. Refs #50002 and supersedes #50003. Thanks @scottgl9. - Gateway/install: add a validated `--wrapper`/`OPENCLAW_WRAPPER` service install path that persists executable LaunchAgent/systemd wrappers across forced reinstalls, updates, and doctor repairs instead of falling back to raw node/bun `ProgramArguments`. Fixes #69400. (#72445) Thanks @willtmc. diff --git a/extensions/discord/src/channel.test.ts b/extensions/discord/src/channel.test.ts index 91499f1a0cf..028481b2e41 100644 --- a/extensions/discord/src/channel.test.ts +++ b/extensions/discord/src/channel.test.ts @@ -119,6 +119,30 @@ describe("discordPlugin outbound", () => { expect(discordPlugin.outbound?.preferFinalAssistantVisibleText).toBe(true); }); + it("preserves normalized explicit Discord targets for delivery routing", () => { + const parseExplicitTarget = discordPlugin.messaging?.parseExplicitTarget; + if (!parseExplicitTarget) { + throw new Error("Expected discordPlugin.messaging.parseExplicitTarget to be defined"); + } + + expect(parseExplicitTarget({ raw: "user:123" })).toEqual({ + to: "user:123", + chatType: "direct", + }); + expect(parseExplicitTarget({ raw: "<@!456>" })).toEqual({ + to: "user:456", + chatType: "direct", + }); + expect(parseExplicitTarget({ raw: "channel:789" })).toEqual({ + to: "channel:789", + chatType: "channel", + }); + expect(parseExplicitTarget({ raw: "1470130713209602050" })).toEqual({ + to: "channel:1470130713209602050", + chatType: "channel", + }); + }); + it("honors per-account replyToMode overrides", () => { const resolveReplyToMode = discordPlugin.threading?.resolveReplyToMode; if (!resolveReplyToMode) { diff --git a/extensions/discord/src/channel.ts b/extensions/discord/src/channel.ts index 5f4b3603422..365b5552afa 100644 --- a/extensions/discord/src/channel.ts +++ b/extensions/discord/src/channel.ts @@ -353,7 +353,7 @@ function parseDiscordExplicitTarget(raw: string) { return null; } return { - to: target.id, + to: target.normalized, chatType: target.kind === "user" ? ("direct" as const) : ("channel" as const), }; } catch {