From 8f719e541ab60f6478c857ee38ccb59d9362770e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 8 Mar 2026 01:15:56 +0000 Subject: [PATCH] refactor(discord): extract native command session targets --- .../native-command-session-targets.test.ts | 37 +++++++++++++++++++ .../monitor/native-command-session-targets.ts | 22 +++++++++++ src/discord/monitor/native-command.ts | 11 +++++- 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/discord/monitor/native-command-session-targets.test.ts create mode 100644 src/discord/monitor/native-command-session-targets.ts diff --git a/src/discord/monitor/native-command-session-targets.test.ts b/src/discord/monitor/native-command-session-targets.test.ts new file mode 100644 index 00000000000..08e3dd9a395 --- /dev/null +++ b/src/discord/monitor/native-command-session-targets.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from "vitest"; +import { resolveDiscordNativeCommandSessionTargets } from "./native-command-session-targets.js"; + +describe("resolveDiscordNativeCommandSessionTargets", () => { + it("uses the bound session for both targets when present", () => { + expect( + resolveDiscordNativeCommandSessionTargets({ + boundSessionKey: "agent:codex:acp:binding:discord:default:seed", + effectiveRoute: { + agentId: "codex", + sessionKey: "agent:codex:discord:channel:chan-1", + }, + sessionPrefix: "discord:slash", + userId: "user-1", + }), + ).toEqual({ + sessionKey: "agent:codex:acp:binding:discord:default:seed", + commandTargetSessionKey: "agent:codex:acp:binding:discord:default:seed", + }); + }); + + it("falls back to the routed slash and command target session keys", () => { + expect( + resolveDiscordNativeCommandSessionTargets({ + effectiveRoute: { + agentId: "qwen", + sessionKey: "agent:qwen:discord:channel:chan-1", + }, + sessionPrefix: "discord:slash", + userId: "user-1", + }), + ).toEqual({ + sessionKey: "agent:qwen:discord:slash:user-1", + commandTargetSessionKey: "agent:qwen:discord:channel:chan-1", + }); + }); +}); diff --git a/src/discord/monitor/native-command-session-targets.ts b/src/discord/monitor/native-command-session-targets.ts new file mode 100644 index 00000000000..4430a2140d8 --- /dev/null +++ b/src/discord/monitor/native-command-session-targets.ts @@ -0,0 +1,22 @@ +export type ResolveDiscordNativeCommandSessionTargetsParams = { + boundSessionKey?: string; + effectiveRoute: { + agentId: string; + sessionKey: string; + }; + sessionPrefix: string; + userId: string; +}; + +export function resolveDiscordNativeCommandSessionTargets( + params: ResolveDiscordNativeCommandSessionTargetsParams, +) { + const sessionKey = + params.boundSessionKey ?? + `agent:${params.effectiveRoute.agentId}:${params.sessionPrefix}:${params.userId}`; + const commandTargetSessionKey = params.boundSessionKey ?? params.effectiveRoute.sessionKey; + return { + sessionKey, + commandTargetSessionKey, + }; +} diff --git a/src/discord/monitor/native-command.ts b/src/discord/monitor/native-command.ts index 3ec8bfa03fd..7c1f2772f29 100644 --- a/src/discord/monitor/native-command.ts +++ b/src/discord/monitor/native-command.ts @@ -83,6 +83,7 @@ import { type DiscordModelPickerCommandContext, } from "./model-picker.js"; import { buildDiscordNativeCommandContext } from "./native-command-context.js"; +import { resolveDiscordNativeCommandSessionTargets } from "./native-command-session-targets.js"; import { buildDiscordRoutePeer, resolveDiscordConversationRoute, @@ -1651,11 +1652,17 @@ async function dispatchDiscordCommandInteraction(params: { configuredRoute, matchedBy: configuredBinding ? "binding.channel" : undefined, }); + const { sessionKey, commandTargetSessionKey } = resolveDiscordNativeCommandSessionTargets({ + boundSessionKey, + effectiveRoute, + sessionPrefix, + userId: user.id, + }); const ctxPayload = buildDiscordNativeCommandContext({ prompt, commandArgs, - sessionKey: boundSessionKey ?? `agent:${effectiveRoute.agentId}:${sessionPrefix}:${user.id}`, - commandTargetSessionKey: boundSessionKey ?? effectiveRoute.sessionKey, + sessionKey, + commandTargetSessionKey, accountId: effectiveRoute.accountId, interactionId, channelId,