fix(discord): use user target for DM inbound context

This commit is contained in:
Peter Steinberger
2026-05-02 02:10:50 +01:00
parent 47c020bfc4
commit 9e9b3f9e0c
3 changed files with 21 additions and 5 deletions

View File

@@ -30,6 +30,7 @@ Docs: https://docs.openclaw.ai
- Plugins/CLI: redact authenticated git URLs from git install command failure details, so failed clone or checkout output cannot leak credentials during plugin installs. Thanks @vincentkoc.
- Channels/status reactions: remove stale non-terminal lifecycle reactions when a run reaches done or error, so Discord does not leave a permanent thinking emoji after completion. Fixes #75458. Thanks @davelutztx.
- Discord/doctor: migrate unsupported per-channel `agentId` entries under guild channel config into top-level `bindings[]` routes, so `openclaw doctor --fix` preserves the intended agent route instead of stripping it as an unknown key. Fixes #62455. Thanks @lobster-biscuit.
- Discord/DMs: set inbound direct-message `ctx.To` to the semantic `user:<id>` target while keeping delivery routed through the DM channel, so mirror and recovery paths do not treat DMs as channel conversations. Fixes #68126. Thanks @illuminate0623.
- Gateway/config: log config health-state write failures instead of silently hiding config observe-recovery write errors. Thanks @sallyom.
- Diagnostics: reset stuck-session timers on reply, tool, status, block, and ACP progress events, and back off repeated `session.stuck` diagnostics while a session remains unchanged. Supersedes #72010. Thanks @rubencu.

View File

@@ -274,17 +274,17 @@ export async function buildDiscordMessageProcessContext(params: {
const effectiveFrom = isDirectMessage
? `discord:${author.id}`
: (autoThreadContext?.From ?? `discord:channel:${messageChannelId}`);
const effectiveTo = autoThreadContext?.To ?? replyTarget;
if (!effectiveTo) {
runtime.error?.(danger("discord: missing reply target"));
return null;
}
const dmConversationTarget = isDirectMessage
? resolveDiscordConversationIdentity({
isDirectMessage,
userId: author.id,
})
: undefined;
const effectiveTo = autoThreadContext?.To ?? dmConversationTarget ?? replyTarget;
if (!effectiveTo) {
runtime.error?.(danger("discord: missing reply target"));
return null;
}
const lastRouteTo = dmConversationTarget ?? effectiveTo;
const inboundHistory =
shouldIncludeChannelHistory && historyLimit > 0

View File

@@ -353,12 +353,16 @@ function getLastRouteUpdate():
function getLastDispatchCtx():
| {
BodyForAgent?: string;
ChatType?: string;
CommandBody?: string;
From?: string;
MediaTranscribedIndexes?: number[];
MessageThreadId?: string | number;
ModelParentSessionKey?: string;
OriginatingTo?: string;
ParentSessionKey?: string;
SessionKey?: string;
To?: string;
Transcript?: string;
}
| undefined {
@@ -367,12 +371,16 @@ function getLastDispatchCtx():
| {
ctx?: {
BodyForAgent?: string;
ChatType?: string;
CommandBody?: string;
From?: string;
MediaTranscribedIndexes?: number[];
MessageThreadId?: string | number;
ModelParentSessionKey?: string;
OriginatingTo?: string;
ParentSessionKey?: string;
SessionKey?: string;
To?: string;
Transcript?: string;
};
}
@@ -808,6 +816,13 @@ describe("processDiscordMessage session routing", () => {
to: "user:U1",
accountId: "default",
});
expect(getLastDispatchCtx()).toMatchObject({
ChatType: "direct",
From: "discord:U1",
To: "user:U1",
OriginatingTo: "user:U1",
SessionKey: "agent:main:discord:direct:u1",
});
});
it("pins Discord text DM main-route updates to the single configured DM owner", async () => {