telegram: use dm thread hook session for plugin commands

This commit is contained in:
Vincent Koc
2026-03-09 11:36:36 -07:00
parent 712821e87d
commit 5d4771e91e
2 changed files with 79 additions and 12 deletions

View File

@@ -270,4 +270,58 @@ describe("registerTelegramNativeCommands", () => {
);
expect(sendMessage).not.toHaveBeenCalledWith(123, "Command not found.");
});
it("uses the DM thread session key for plugin command internal sent hooks", async () => {
const commandHandlers = new Map<string, (ctx: unknown) => Promise<void>>();
pluginCommandMocks.getPluginCommandSpecs.mockReturnValue([
{
name: "plug",
description: "Plugin command",
},
] as never);
pluginCommandMocks.matchPluginCommand.mockReturnValue({
command: { key: "plug", requireAuth: false },
args: undefined,
} as never);
registerTelegramNativeCommands({
...buildParams({
channels: {
telegram: {
dmPolicy: "open",
},
},
}),
bot: {
api: {
setMyCommands: vi.fn().mockResolvedValue(undefined),
sendMessage: vi.fn().mockResolvedValue(undefined),
},
command: vi.fn((name: string, cb: (ctx: unknown) => Promise<void>) => {
commandHandlers.set(name, cb);
}),
} as unknown as Parameters<typeof registerTelegramNativeCommands>[0]["bot"],
});
const handler = commandHandlers.get("plug");
expect(handler).toBeTruthy();
await handler?.({
match: "",
message: {
message_id: 42,
date: Math.floor(Date.now() / 1000),
chat: { id: 12345, type: "private" },
from: { id: 12345, username: "alice" },
message_thread_id: 99,
},
});
expect(deliveryMocks.deliverReplies).toHaveBeenCalledWith(
expect.objectContaining({
sessionKeyForInternalHooks: "agent:main:main:thread:12345:99",
}),
);
});
});

View File

@@ -540,6 +540,20 @@ export const registerTelegramNativeCommands = ({
chunkMode: params.chunkMode,
linkPreview: telegramCfg.linkPreview,
});
const resolveDmThreadSessionKey = (params: {
baseSessionKey: string;
chatId: string | number;
threadSpec: ReturnType<typeof resolveTelegramThreadSpec>;
}): string => {
const dmThreadId = params.threadSpec.scope === "dm" ? params.threadSpec.id : undefined;
if (dmThreadId == null) {
return params.baseSessionKey;
}
return resolveThreadSessionKeys({
baseSessionKey: params.baseSessionKey,
threadId: `${params.chatId}:${dmThreadId}`,
}).sessionKey;
};
if (commandsToRegister.length > 0 || pluginCatalog.commands.length > 0) {
if (typeof (bot as unknown as { command?: unknown }).command !== "function") {
@@ -647,17 +661,11 @@ export const registerTelegramNativeCommands = ({
});
return;
}
const baseSessionKey = route.sessionKey;
// DMs: use raw messageThreadId for thread sessions (not resolvedThreadId which is for forums)
const dmThreadId = threadSpec.scope === "dm" ? threadSpec.id : undefined;
const threadKeys =
dmThreadId != null
? resolveThreadSessionKeys({
baseSessionKey,
threadId: `${chatId}:${dmThreadId}`,
})
: null;
const sessionKey = threadKeys?.sessionKey ?? baseSessionKey;
const sessionKey = resolveDmThreadSessionKey({
baseSessionKey: route.sessionKey,
chatId,
threadSpec,
});
const { skillFilter, groupSystemPrompt } = resolveTelegramGroupPromptSettings({
groupConfig,
topicConfig,
@@ -833,10 +841,15 @@ export const registerTelegramNativeCommands = ({
return;
}
const { threadSpec, route, mediaLocalRoots, tableMode, chunkMode } = runtimeContext;
const sessionKeyForInternalHooks = resolveDmThreadSessionKey({
baseSessionKey: route.sessionKey,
chatId,
threadSpec,
});
const deliveryBaseOptions = buildCommandDeliveryBaseOptions({
chatId,
accountId: route.accountId,
sessionKeyForInternalHooks: route.sessionKey,
sessionKeyForInternalHooks,
mirrorIsGroup: isGroup,
mirrorGroupId: isGroup ? String(chatId) : undefined,
mediaLocalRoots,