openclaw/src/telegram/bot/helpers.test.ts
Dylan Neve 915497114e fix(telegram): ignore message_thread_id for non-forum group sessions
Regular Telegram groups (without Topics/Forums enabled) can send
message_thread_id when users reply to messages. This was incorrectly
being used to create separate session keys like '-123:topic:42',
causing each reply chain to get its own conversation context.

Now resolveTelegramForumThreadId only returns a thread ID when the
chat is actually a forum (is_forum=true). For regular groups, the
thread ID is ignored, ensuring all messages share the same session.

DMs continue to use messageThreadId for thread sessions as before.
2026-01-28 09:32:20 +05:30

119 lines
4.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
buildTelegramThreadParams,
buildTypingThreadParams,
normalizeForwardedContext,
resolveTelegramForumThreadId,
} from "./helpers.js";
describe("resolveTelegramForumThreadId", () => {
it("returns undefined for non-forum groups even with messageThreadId", () => {
// Reply threads in regular groups should not create separate sessions
expect(resolveTelegramForumThreadId({ isForum: false, messageThreadId: 42 })).toBeUndefined();
});
it("returns undefined for non-forum groups without messageThreadId", () => {
expect(resolveTelegramForumThreadId({ isForum: false, messageThreadId: undefined })).toBeUndefined();
expect(resolveTelegramForumThreadId({ isForum: undefined, messageThreadId: 99 })).toBeUndefined();
});
it("returns General topic (1) for forum groups without messageThreadId", () => {
expect(resolveTelegramForumThreadId({ isForum: true, messageThreadId: undefined })).toBe(1);
expect(resolveTelegramForumThreadId({ isForum: true, messageThreadId: null })).toBe(1);
});
it("returns the topic id for forum groups with messageThreadId", () => {
expect(resolveTelegramForumThreadId({ isForum: true, messageThreadId: 99 })).toBe(99);
});
});
describe("buildTelegramThreadParams", () => {
it("omits General topic thread id for message sends", () => {
expect(buildTelegramThreadParams(1)).toBeUndefined();
});
it("includes non-General topic thread ids", () => {
expect(buildTelegramThreadParams(99)).toEqual({ message_thread_id: 99 });
});
it("normalizes thread ids to integers", () => {
expect(buildTelegramThreadParams(42.9)).toEqual({ message_thread_id: 42 });
});
});
describe("buildTypingThreadParams", () => {
it("returns undefined when no thread id is provided", () => {
expect(buildTypingThreadParams(undefined)).toBeUndefined();
});
it("includes General topic thread id for typing indicators", () => {
expect(buildTypingThreadParams(1)).toEqual({ message_thread_id: 1 });
});
it("normalizes thread ids to integers", () => {
expect(buildTypingThreadParams(42.9)).toEqual({ message_thread_id: 42 });
});
});
describe("normalizeForwardedContext", () => {
it("handles forward_origin users", () => {
const ctx = normalizeForwardedContext({
forward_origin: {
type: "user",
sender_user: { first_name: "Ada", last_name: "Lovelace", username: "ada", id: 42 },
date: 123,
},
} as any);
expect(ctx).not.toBeNull();
expect(ctx?.from).toBe("Ada Lovelace (@ada)");
expect(ctx?.fromType).toBe("user");
expect(ctx?.fromId).toBe("42");
expect(ctx?.fromUsername).toBe("ada");
expect(ctx?.fromTitle).toBe("Ada Lovelace");
expect(ctx?.date).toBe(123);
});
it("handles hidden forward_origin names", () => {
const ctx = normalizeForwardedContext({
forward_origin: { type: "hidden_user", sender_user_name: "Hidden Name", date: 456 },
} as any);
expect(ctx).not.toBeNull();
expect(ctx?.from).toBe("Hidden Name");
expect(ctx?.fromType).toBe("hidden_user");
expect(ctx?.fromTitle).toBe("Hidden Name");
expect(ctx?.date).toBe(456);
});
it("handles legacy forwards with signatures", () => {
const ctx = normalizeForwardedContext({
forward_from_chat: {
title: "Moltbot Updates",
username: "moltbot",
id: 99,
type: "channel",
},
forward_signature: "Stan",
forward_date: 789,
} as any);
expect(ctx).not.toBeNull();
expect(ctx?.from).toBe("Moltbot Updates (Stan)");
expect(ctx?.fromType).toBe("legacy_channel");
expect(ctx?.fromId).toBe("99");
expect(ctx?.fromUsername).toBe("moltbot");
expect(ctx?.fromTitle).toBe("Moltbot Updates");
expect(ctx?.fromSignature).toBe("Stan");
expect(ctx?.date).toBe(789);
});
it("handles legacy hidden sender names", () => {
const ctx = normalizeForwardedContext({
forward_sender_name: "Legacy Hidden",
forward_date: 111,
} as any);
expect(ctx).not.toBeNull();
expect(ctx?.from).toBe("Legacy Hidden");
expect(ctx?.fromType).toBe("legacy_hidden_user");
expect(ctx?.date).toBe(111);
});
});