diff --git a/extensions/telegram/src/message-cache.test.ts b/extensions/telegram/src/message-cache.test.ts index 77920877e2e3..58dd96ee3ada 100644 --- a/extensions/telegram/src/message-cache.test.ts +++ b/extensions/telegram/src/message-cache.test.ts @@ -1,4 +1,4 @@ -import { readFile, rm } from "node:fs/promises"; +import { readFile, rm, writeFile } from "node:fs/promises"; import type { Message } from "@grammyjs/types"; import { describe, expect, it, vi } from "vitest"; import { @@ -8,6 +8,28 @@ import { resolveTelegramMessageCachePath, } from "./message-cache.js"; +type PersistedCacheEntry = { + key: string; + node: { + sourceMessage: Message; + }; +}; + +function persistedCacheEntry(messageId: number, text: string): PersistedCacheEntry { + return { + key: `default:7:${messageId}`, + node: { + sourceMessage: { + chat: { id: 7, type: "group", title: "Ops" }, + message_id: messageId, + date: 1736380000 + messageId, + text, + from: { id: messageId, is_bot: false, first_name: `User ${messageId}` }, + } as Message, + }, + }; +} + describe("telegram message cache", () => { it("hydrates reply chains from persisted cached messages", async () => { const storePath = `/tmp/openclaw-telegram-message-cache-${process.pid}-${Date.now()}.json`; @@ -253,6 +275,54 @@ describe("telegram message cache", () => { } }); + it("loads mixed legacy array caches and rewrites them as line-delimited entries", async () => { + const storePath = `/tmp/openclaw-telegram-message-cache-legacy-${process.pid}-${Date.now()}.json`; + const persistedPath = resolveTelegramMessageCachePath(storePath); + await rm(persistedPath, { force: true }); + try { + const legacyEntries = [ + persistedCacheEntry(35033, "ocdbg-5818 one"), + persistedCacheEntry(35034, "ocdbg-5818 two"), + persistedCacheEntry(35035, "ocdbg-5818 three"), + ]; + const appendedEntries = [ + persistedCacheEntry(35036, "ocdbg-5818 four"), + persistedCacheEntry(35037, "ocdbg-5818 five"), + ]; + await writeFile( + persistedPath, + `${JSON.stringify(legacyEntries)}${appendedEntries.map((entry) => JSON.stringify(entry)).join("\n")}\n`, + ); + + const cache = createTelegramMessageCache({ persistedPath }); + + expect( + cache + .around({ + accountId: "default", + chatId: 7, + messageId: "35035", + before: 2, + after: 2, + }) + .map((entry) => entry.messageId), + ).toEqual(["35033", "35034", "35035", "35036", "35037"]); + + const canonical = await readFile(persistedPath, "utf-8"); + expect(canonical.startsWith("[")).toBe(false); + const lines = canonical.trim().split("\n"); + expect(lines).toHaveLength(5); + expect( + lines.map((line) => { + const entry = JSON.parse(line) as PersistedCacheEntry; + return entry.node.sourceMessage.message_id; + }), + ).toEqual([35033, 35034, 35035, 35036, 35037]); + } finally { + await rm(persistedPath, { force: true }); + } + }); + it("returns recent chat messages before the current message", () => { const cache = createTelegramMessageCache(); for (const id of [41, 42, 43, 44]) {