Discord: keep DM component sessions

This commit is contained in:
Shadow
2026-02-20 17:33:28 -06:00
parent 0f1b2ad962
commit 086af56867
3 changed files with 112 additions and 3 deletions

View File

@@ -8,6 +8,7 @@ import type { APIChannel } from "discord-api-types/v10";
import { ChannelType, Routes } from "discord-api-types/v10";
import { loadConfig } from "../config/config.js";
import { recordChannelActivity } from "../infra/channel-activity.js";
import { buildAgentSessionKey } from "../routing/resolve-route.js";
import { loadWebMedia } from "../web/media.js";
import { resolveDiscordAccount } from "./accounts.js";
import { registerDiscordComponentEntries } from "./components-registry.js";
@@ -29,6 +30,50 @@ import type { DiscordSendResult } from "./send.types.js";
const DISCORD_FORUM_LIKE_TYPES = new Set<number>([ChannelType.GuildForum, ChannelType.GuildMedia]);
type DiscordRecipient = Awaited<ReturnType<typeof parseAndResolveRecipient>>;
function resolveDiscordDmRecipientId(channel?: APIChannel): string | undefined {
if (!channel || channel.type !== ChannelType.DM) {
return undefined;
}
const recipients = (channel as { recipients?: Array<{ id?: string }> }).recipients;
const recipientId = recipients?.[0]?.id;
if (typeof recipientId !== "string") {
return undefined;
}
const trimmed = recipientId.trim();
return trimmed ? trimmed : undefined;
}
function resolveDiscordComponentSessionKey(params: {
cfg: ReturnType<typeof loadConfig>;
accountId: string;
agentId?: string;
sessionKey?: string;
recipient: DiscordRecipient;
channel?: APIChannel;
}): string | undefined {
if (!params.sessionKey || !params.agentId) {
return params.sessionKey;
}
if (params.recipient.kind !== "channel") {
return params.sessionKey;
}
const recipientId = resolveDiscordDmRecipientId(params.channel);
if (!recipientId) {
return params.sessionKey;
}
// DM channel IDs should map back to the user session for component interactions.
return buildAgentSessionKey({
agentId: params.agentId,
channel: "discord",
accountId: params.accountId,
peer: { kind: "direct", id: recipientId },
dmScope: params.cfg.session?.dmScope,
identityLinks: params.cfg.session?.identityLinks,
});
}
function extractComponentAttachmentNames(spec: DiscordComponentMessageSpec): string[] {
const names: string[] = [];
for (const block of spec.blocks ?? []) {
@@ -63,9 +108,10 @@ export async function sendDiscordComponentMessage(
const recipient = await parseAndResolveRecipient(to, opts.accountId);
const { channelId } = await resolveChannelId(rest, recipient, request);
let channel: APIChannel | undefined;
let channelType: number | undefined;
try {
const channel = (await rest.get(Routes.channel(channelId))) as APIChannel | undefined;
channel = (await rest.get(Routes.channel(channelId))) as APIChannel | undefined;
channelType = channel?.type;
} catch {
channelType = undefined;
@@ -75,9 +121,18 @@ export async function sendDiscordComponentMessage(
throw new Error("Discord components are not supported in forum-style channels");
}
const componentSessionKey = resolveDiscordComponentSessionKey({
cfg,
accountId: accountInfo.accountId,
agentId: opts.agentId,
sessionKey: opts.sessionKey,
recipient,
channel,
});
const buildResult = buildDiscordComponentMessage({
spec,
sessionKey: opts.sessionKey,
sessionKey: componentSessionKey,
agentId: opts.agentId,
accountId: accountInfo.accountId,
});