diff --git a/src/channels/session.test.ts b/src/channels/session.test.ts new file mode 100644 index 00000000000..8053a801087 --- /dev/null +++ b/src/channels/session.test.ts @@ -0,0 +1,78 @@ +import type { MsgContext } from "../auto-reply/templating.js"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const recordSessionMetaFromInboundMock = vi.fn(() => Promise.resolve(undefined)); +const updateLastRouteMock = vi.fn(() => Promise.resolve(undefined)); + +vi.mock("../config/sessions.js", () => ({ + recordSessionMetaFromInbound: (...args: unknown[]) => recordSessionMetaFromInboundMock(...args), + updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args), +})); + +describe("recordInboundSession", () => { + const ctx: MsgContext = { + Provider: "telegram", + From: "telegram:1234", + SessionKey: "agent:main:telegram:1234:thread:42", + OriginatingTo: "telegram:1234", + }; + + beforeEach(() => { + recordSessionMetaFromInboundMock.mockClear(); + updateLastRouteMock.mockClear(); + }); + + it("does not pass ctx when updating a different session key", async () => { + const { recordInboundSession } = await import("./session.js"); + + await recordInboundSession({ + storePath: "/tmp/openclaw-session-store.json", + sessionKey: "agent:main:telegram:1234:thread:42", + ctx, + updateLastRoute: { + sessionKey: "agent:main:main", + channel: "telegram", + to: "telegram:1234", + }, + onRecordError: vi.fn(), + }); + + expect(updateLastRouteMock).toHaveBeenCalledWith( + expect.objectContaining({ + sessionKey: "agent:main:main", + ctx: undefined, + deliveryContext: expect.objectContaining({ + channel: "telegram", + to: "telegram:1234", + }), + }), + ); + }); + + it("passes ctx when updating the same session key", async () => { + const { recordInboundSession } = await import("./session.js"); + + await recordInboundSession({ + storePath: "/tmp/openclaw-session-store.json", + sessionKey: "agent:main:telegram:1234:thread:42", + ctx, + updateLastRoute: { + sessionKey: "agent:main:telegram:1234:thread:42", + channel: "telegram", + to: "telegram:1234", + }, + onRecordError: vi.fn(), + }); + + expect(updateLastRouteMock).toHaveBeenCalledWith( + expect.objectContaining({ + sessionKey: "agent:main:telegram:1234:thread:42", + ctx, + deliveryContext: expect.objectContaining({ + channel: "telegram", + to: "telegram:1234", + }), + }), + ); + }); +}); diff --git a/src/channels/session.ts b/src/channels/session.ts index 8aeb371dbb6..c2f2433be2a 100644 --- a/src/channels/session.ts +++ b/src/channels/session.ts @@ -45,7 +45,8 @@ export async function recordInboundSession(params: { accountId: update.accountId, threadId: update.threadId, }, - ctx, + // Avoid leaking inbound origin metadata into a different target session. + ctx: update.sessionKey === sessionKey ? ctx : undefined, groupResolution, }); } diff --git a/src/telegram/bot-message-context.dm-topic-threadid.test.ts b/src/telegram/bot-message-context.dm-topic-threadid.test.ts index 54d962141c9..ba566898db8 100644 --- a/src/telegram/bot-message-context.dm-topic-threadid.test.ts +++ b/src/telegram/bot-message-context.dm-topic-threadid.test.ts @@ -41,8 +41,9 @@ describe("buildTelegramMessageContext DM topic threadId in deliveryContext (#889 expect(recordInboundSessionMock).toHaveBeenCalled(); // Check that updateLastRoute includes threadId - const updateLastRoute = getUpdateLastRoute() as { threadId?: string } | undefined; + const updateLastRoute = getUpdateLastRoute() as { threadId?: string; to?: string } | undefined; expect(updateLastRoute).toBeDefined(); + expect(updateLastRoute?.to).toBe("telegram:1234"); expect(updateLastRoute?.threadId).toBe("42"); }); @@ -57,8 +58,9 @@ describe("buildTelegramMessageContext DM topic threadId in deliveryContext (#889 expect(recordInboundSessionMock).toHaveBeenCalled(); // Check that updateLastRoute does NOT include threadId - const updateLastRoute = getUpdateLastRoute() as { threadId?: string } | undefined; + const updateLastRoute = getUpdateLastRoute() as { threadId?: string; to?: string } | undefined; expect(updateLastRoute).toBeDefined(); + expect(updateLastRoute?.to).toBe("telegram:1234"); expect(updateLastRoute?.threadId).toBeUndefined(); }); diff --git a/src/telegram/bot-message-context.ts b/src/telegram/bot-message-context.ts index 312f12f8efc..ea32380b1f7 100644 --- a/src/telegram/bot-message-context.ts +++ b/src/telegram/bot-message-context.ts @@ -765,7 +765,7 @@ export const buildTelegramMessageContext = async ({ ? { sessionKey: route.mainSessionKey, channel: "telegram", - to: String(chatId), + to: `telegram:${chatId}`, accountId: route.accountId, // Preserve DM topic threadId for replies (fixes #8891) threadId: dmThreadId != null ? String(dmThreadId) : undefined,