refactor(discord): require explicit outbound target hints

This commit is contained in:
Peter Steinberger
2026-03-08 01:12:26 +00:00
parent 74e3c071b2
commit 189cd99377
2 changed files with 57 additions and 2 deletions

View File

@@ -4,7 +4,7 @@ import { getChannelPlugin } from "../../channels/plugins/index.js";
import type { ChannelId } from "../../channels/plugins/types.js";
import type { OpenClawConfig } from "../../config/config.js";
import { recordSessionMetaFromInbound, resolveStorePath } from "../../config/sessions.js";
import { parseDiscordTarget } from "../../discord/targets.js";
import { parseDiscordTarget, type DiscordTargetKind } from "../../discord/targets.js";
import { parseIMessageTarget, normalizeIMessageHandle } from "../../imessage/targets.js";
import { buildAgentSessionKey, type RoutePeer } from "../../routing/resolve-route.js";
import { resolveThreadSessionKeys } from "../../routing/session-key.js";
@@ -239,7 +239,9 @@ async function resolveSlackSession(
function resolveDiscordSession(
params: ResolveOutboundSessionRouteParams,
): OutboundSessionRoute | null {
const parsed = parseDiscordTarget(params.target, { defaultKind: "channel" });
const parsed = parseDiscordTarget(params.target, {
defaultKind: resolveDiscordOutboundTargetKindHint(params),
});
if (!parsed) {
return null;
}
@@ -274,6 +276,27 @@ function resolveDiscordSession(
};
}
function resolveDiscordOutboundTargetKindHint(
params: ResolveOutboundSessionRouteParams,
): DiscordTargetKind | undefined {
const resolvedKind = params.resolvedTarget?.kind;
if (resolvedKind === "user") {
return "user";
}
if (resolvedKind === "group" || resolvedKind === "channel") {
return "channel";
}
const target = params.target.trim();
if (/^channel:/i.test(target)) {
return "channel";
}
if (/^(user:|discord:|@|<@!?)/i.test(target)) {
return "user";
}
return undefined;
}
function resolveTelegramSession(
params: ResolveOutboundSessionRouteParams,
): OutboundSessionRoute | null {

View File

@@ -1120,6 +1120,38 @@ describe("resolveOutboundSessionRoute", () => {
}
}
});
it("uses resolved Discord user targets to route bare numeric ids as DMs", async () => {
const route = await resolveOutboundSessionRoute({
cfg: { session: { dmScope: "per-channel-peer" } } as OpenClawConfig,
channel: "discord",
agentId: "main",
target: "123",
resolvedTarget: {
to: "user:123",
kind: "user",
source: "directory",
},
});
expect(route).toMatchObject({
sessionKey: "agent:main:discord:direct:123",
from: "discord:123",
to: "user:123",
chatType: "direct",
});
});
it("rejects bare numeric Discord targets when the caller has no kind hint", async () => {
await expect(
resolveOutboundSessionRoute({
cfg: { session: { dmScope: "per-channel-peer" } } as OpenClawConfig,
channel: "discord",
agentId: "main",
target: "123",
}),
).rejects.toThrow(/Ambiguous Discord recipient/);
});
});
describe("normalizeOutboundPayloadsForJson", () => {