mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-29 09:41:08 +00:00
telegram: route dm sessions by sender id
This commit is contained in:
committed by
Peter Steinberger
parent
2c39731846
commit
317075ef3d
@@ -1,4 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { afterEach, describe, expect, it } from "vitest";
|
||||||
|
import { clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot } from "../config/config.js";
|
||||||
import { buildTelegramMessageContextForTest } from "./bot-message-context.test-harness.js";
|
import { buildTelegramMessageContextForTest } from "./bot-message-context.test-harness.js";
|
||||||
|
|
||||||
describe("buildTelegramMessageContext dm thread sessions", () => {
|
describe("buildTelegramMessageContext dm thread sessions", () => {
|
||||||
@@ -104,3 +105,45 @@ describe("buildTelegramMessageContext group sessions without forum", () => {
|
|||||||
expect(ctx?.ctxPayload?.MessageThreadId).toBe(99);
|
expect(ctx?.ctxPayload?.MessageThreadId).toBe(99);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("buildTelegramMessageContext direct peer routing", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
clearRuntimeConfigSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("isolates dm sessions by sender id when chat id differs", async () => {
|
||||||
|
const runtimeCfg = {
|
||||||
|
agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } },
|
||||||
|
channels: { telegram: {} },
|
||||||
|
messages: { groupChat: { mentionPatterns: [] } },
|
||||||
|
session: { dmScope: "per-channel-peer" as const },
|
||||||
|
};
|
||||||
|
setRuntimeConfigSnapshot(runtimeCfg);
|
||||||
|
|
||||||
|
const baseMessage = {
|
||||||
|
chat: { id: 777777777, type: "private" as const },
|
||||||
|
date: 1700000000,
|
||||||
|
text: "hello",
|
||||||
|
};
|
||||||
|
|
||||||
|
const first = await buildTelegramMessageContextForTest({
|
||||||
|
cfg: runtimeCfg,
|
||||||
|
message: {
|
||||||
|
...baseMessage,
|
||||||
|
message_id: 1,
|
||||||
|
from: { id: 123456789, first_name: "Alice" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const second = await buildTelegramMessageContextForTest({
|
||||||
|
cfg: runtimeCfg,
|
||||||
|
message: {
|
||||||
|
...baseMessage,
|
||||||
|
message_id: 2,
|
||||||
|
from: { id: 987654321, first_name: "Bob" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(first?.ctxPayload?.SessionKey).toBe("agent:main:telegram:direct:123456789");
|
||||||
|
expect(second?.ctxPayload?.SessionKey).toBe("agent:main:telegram:direct:987654321");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import {
|
|||||||
buildGroupLabel,
|
buildGroupLabel,
|
||||||
buildSenderLabel,
|
buildSenderLabel,
|
||||||
buildSenderName,
|
buildSenderName,
|
||||||
|
resolveTelegramDirectPeerId,
|
||||||
buildTelegramGroupFrom,
|
buildTelegramGroupFrom,
|
||||||
buildTelegramGroupPeerId,
|
buildTelegramGroupPeerId,
|
||||||
buildTelegramParentPeer,
|
buildTelegramParentPeer,
|
||||||
@@ -174,6 +175,7 @@ export const buildTelegramMessageContext = async ({
|
|||||||
const msg = primaryCtx.message;
|
const msg = primaryCtx.message;
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
const isGroup = msg.chat.type === "group" || msg.chat.type === "supergroup";
|
const isGroup = msg.chat.type === "group" || msg.chat.type === "supergroup";
|
||||||
|
const senderId = msg.from?.id ? String(msg.from.id) : "";
|
||||||
const messageThreadId = (msg as { message_thread_id?: number }).message_thread_id;
|
const messageThreadId = (msg as { message_thread_id?: number }).message_thread_id;
|
||||||
const isForum = (msg.chat as { is_forum?: boolean }).is_forum === true;
|
const isForum = (msg.chat as { is_forum?: boolean }).is_forum === true;
|
||||||
const threadSpec = resolveTelegramThreadSpec({
|
const threadSpec = resolveTelegramThreadSpec({
|
||||||
@@ -191,7 +193,9 @@ export const buildTelegramMessageContext = async ({
|
|||||||
!isGroup && groupConfig && "dmPolicy" in groupConfig
|
!isGroup && groupConfig && "dmPolicy" in groupConfig
|
||||||
? (groupConfig.dmPolicy ?? dmPolicy)
|
? (groupConfig.dmPolicy ?? dmPolicy)
|
||||||
: dmPolicy;
|
: dmPolicy;
|
||||||
const peerId = isGroup ? buildTelegramGroupPeerId(chatId, resolvedThreadId) : String(chatId);
|
const peerId = isGroup
|
||||||
|
? buildTelegramGroupPeerId(chatId, resolvedThreadId)
|
||||||
|
: resolveTelegramDirectPeerId({ chatId, senderId });
|
||||||
const parentPeer = buildTelegramParentPeer({ isGroup, resolvedThreadId, chatId });
|
const parentPeer = buildTelegramParentPeer({ isGroup, resolvedThreadId, chatId });
|
||||||
// Fresh config for bindings lookup; other routing inputs are payload-derived.
|
// Fresh config for bindings lookup; other routing inputs are payload-derived.
|
||||||
const route = resolveAgentRoute({
|
const route = resolveAgentRoute({
|
||||||
@@ -235,7 +239,6 @@ export const buildTelegramMessageContext = async ({
|
|||||||
// Group sender checks are explicit and must not inherit DM pairing-store entries.
|
// Group sender checks are explicit and must not inherit DM pairing-store entries.
|
||||||
const effectiveGroupAllow = normalizeAllowFrom(groupAllowOverride ?? groupAllowFrom);
|
const effectiveGroupAllow = normalizeAllowFrom(groupAllowOverride ?? groupAllowFrom);
|
||||||
const hasGroupAllowOverride = typeof groupAllowOverride !== "undefined";
|
const hasGroupAllowOverride = typeof groupAllowOverride !== "undefined";
|
||||||
const senderId = msg.from?.id ? String(msg.from.id) : "";
|
|
||||||
const senderUsername = msg.from?.username ?? "";
|
const senderUsername = msg.from?.username ?? "";
|
||||||
const baseAccess = evaluateTelegramGroupBaseAccess({
|
const baseAccess = evaluateTelegramGroupBaseAccess({
|
||||||
isGroup,
|
isGroup,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
describeReplyTarget,
|
describeReplyTarget,
|
||||||
expandTextLinks,
|
expandTextLinks,
|
||||||
normalizeForwardedContext,
|
normalizeForwardedContext,
|
||||||
|
resolveTelegramDirectPeerId,
|
||||||
resolveTelegramForumThreadId,
|
resolveTelegramForumThreadId,
|
||||||
} from "./helpers.js";
|
} from "./helpers.js";
|
||||||
|
|
||||||
@@ -53,6 +54,20 @@ describe("buildTypingThreadParams", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("resolveTelegramDirectPeerId", () => {
|
||||||
|
it("prefers sender id when available", () => {
|
||||||
|
expect(resolveTelegramDirectPeerId({ chatId: 777777777, senderId: 123456789 })).toBe(
|
||||||
|
"123456789",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to chat id when sender id is missing", () => {
|
||||||
|
expect(resolveTelegramDirectPeerId({ chatId: 777777777, senderId: undefined })).toBe(
|
||||||
|
"777777777",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("thread id normalization", () => {
|
describe("thread id normalization", () => {
|
||||||
it.each([
|
it.each([
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -175,6 +175,24 @@ export function buildTelegramGroupPeerId(chatId: number | string, messageThreadI
|
|||||||
return messageThreadId != null ? `${chatId}:topic:${messageThreadId}` : String(chatId);
|
return messageThreadId != null ? `${chatId}:topic:${messageThreadId}` : String(chatId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the direct-message peer identifier for Telegram routing/session keys.
|
||||||
|
*
|
||||||
|
* In some Telegram DM deliveries (for example certain business/chat bridge flows),
|
||||||
|
* `chat.id` can differ from the actual sender user id. Prefer sender id when present
|
||||||
|
* so per-peer DM scopes isolate users correctly.
|
||||||
|
*/
|
||||||
|
export function resolveTelegramDirectPeerId(params: {
|
||||||
|
chatId: number | string;
|
||||||
|
senderId?: number | string | null;
|
||||||
|
}) {
|
||||||
|
const senderId = params.senderId != null ? String(params.senderId).trim() : "";
|
||||||
|
if (senderId) {
|
||||||
|
return senderId;
|
||||||
|
}
|
||||||
|
return String(params.chatId);
|
||||||
|
}
|
||||||
|
|
||||||
export function buildTelegramGroupFrom(chatId: number | string, messageThreadId?: number) {
|
export function buildTelegramGroupFrom(chatId: number | string, messageThreadId?: number) {
|
||||||
return `telegram:group:${buildTelegramGroupPeerId(chatId, messageThreadId)}`;
|
return `telegram:group:${buildTelegramGroupPeerId(chatId, messageThreadId)}`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user