mirror of https://github.com/openclaw/openclaw.git
Telegram: fix named-account DM topic session keys (#48773)
This commit is contained in:
parent
9053f551cb
commit
1eb810a5e3
|
|
@ -64,7 +64,10 @@ import {
|
|||
resolveTelegramGroupAllowFromContext,
|
||||
} from "./bot/helpers.js";
|
||||
import type { TelegramContext } from "./bot/types.js";
|
||||
import { resolveTelegramConversationRoute } from "./conversation-route.js";
|
||||
import {
|
||||
resolveTelegramConversationBaseSessionKey,
|
||||
resolveTelegramConversationRoute,
|
||||
} from "./conversation-route.js";
|
||||
import { enforceTelegramDmAccess } from "./dm-access.js";
|
||||
import {
|
||||
isTelegramExecApprovalApprover,
|
||||
|
|
@ -331,7 +334,13 @@ export const registerTelegramHandlers = ({
|
|||
senderId: params.senderId,
|
||||
topicAgentId: topicConfig?.agentId,
|
||||
});
|
||||
const baseSessionKey = route.sessionKey;
|
||||
const baseSessionKey = resolveTelegramConversationBaseSessionKey({
|
||||
cfg,
|
||||
route,
|
||||
chatId: params.chatId,
|
||||
isGroup: params.isGroup,
|
||||
senderId: params.senderId,
|
||||
});
|
||||
const threadKeys =
|
||||
dmThreadId != null
|
||||
? resolveThreadSessionKeys({ baseSessionKey, threadId: `${params.chatId}:${dmThreadId}` })
|
||||
|
|
|
|||
|
|
@ -6,9 +6,13 @@ import {
|
|||
import { buildTelegramMessageContextForTest } from "./bot-message-context.test-harness.js";
|
||||
|
||||
const recordInboundSessionMock = vi.fn().mockResolvedValue(undefined);
|
||||
vi.mock("../../../src/channels/session.js", () => ({
|
||||
recordInboundSession: (...args: unknown[]) => recordInboundSessionMock(...args),
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/channel-runtime", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/channel-runtime")>();
|
||||
return {
|
||||
...actual,
|
||||
recordInboundSession: (...args: unknown[]) => recordInboundSessionMock(...args),
|
||||
};
|
||||
});
|
||||
|
||||
describe("buildTelegramMessageContext named-account DM fallback", () => {
|
||||
const baseCfg = {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { loadConfig } from "openclaw/plugin-sdk/config-runtime";
|
|||
import type { TelegramDirectConfig, TelegramGroupConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { ensureConfiguredAcpRouteReady } from "openclaw/plugin-sdk/conversation-runtime";
|
||||
import { recordChannelActivity } from "openclaw/plugin-sdk/infra-runtime";
|
||||
import { buildAgentSessionKey, deriveLastRoutePolicy } from "openclaw/plugin-sdk/routing";
|
||||
import { deriveLastRoutePolicy } from "openclaw/plugin-sdk/routing";
|
||||
import { DEFAULT_ACCOUNT_ID, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
|
||||
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { withTelegramApiErrorLogging } from "./api-logging.js";
|
||||
|
|
@ -17,12 +17,11 @@ import { firstDefined, normalizeAllowFrom, normalizeDmAllowFromWithStore } from
|
|||
import { resolveTelegramInboundBody } from "./bot-message-context.body.js";
|
||||
import { buildTelegramInboundContextPayload } from "./bot-message-context.session.js";
|
||||
import type { BuildTelegramMessageContextParams } from "./bot-message-context.types.js";
|
||||
import { buildTypingThreadParams, resolveTelegramThreadSpec } from "./bot/helpers.js";
|
||||
import {
|
||||
buildTypingThreadParams,
|
||||
resolveTelegramDirectPeerId,
|
||||
resolveTelegramThreadSpec,
|
||||
} from "./bot/helpers.js";
|
||||
import { resolveTelegramConversationRoute } from "./conversation-route.js";
|
||||
resolveTelegramConversationBaseSessionKey,
|
||||
resolveTelegramConversationRoute,
|
||||
} from "./conversation-route.js";
|
||||
import { enforceTelegramDmAccess } from "./dm-access.js";
|
||||
import { evaluateTelegramGroupBaseAccess } from "./group-access.js";
|
||||
import {
|
||||
|
|
@ -224,22 +223,13 @@ export const buildTelegramMessageContext = async ({
|
|||
return false;
|
||||
};
|
||||
|
||||
const baseSessionKey = isNamedAccountFallback
|
||||
? buildAgentSessionKey({
|
||||
agentId: route.agentId,
|
||||
channel: "telegram",
|
||||
accountId: route.accountId,
|
||||
peer: {
|
||||
kind: "direct",
|
||||
id: resolveTelegramDirectPeerId({
|
||||
chatId,
|
||||
senderId,
|
||||
}),
|
||||
},
|
||||
dmScope: "per-account-channel-peer",
|
||||
identityLinks: freshCfg.session?.identityLinks,
|
||||
}).toLowerCase()
|
||||
: route.sessionKey;
|
||||
const baseSessionKey = resolveTelegramConversationBaseSessionKey({
|
||||
cfg: freshCfg,
|
||||
route,
|
||||
chatId,
|
||||
isGroup,
|
||||
senderId,
|
||||
});
|
||||
// DMs: use thread suffix for session isolation (works regardless of dmScope)
|
||||
const threadKeys =
|
||||
dmThreadId != null
|
||||
|
|
|
|||
|
|
@ -63,7 +63,10 @@ import {
|
|||
resolveTelegramThreadSpec,
|
||||
} from "./bot/helpers.js";
|
||||
import type { TelegramContext } from "./bot/types.js";
|
||||
import { resolveTelegramConversationRoute } from "./conversation-route.js";
|
||||
import {
|
||||
resolveTelegramConversationBaseSessionKey,
|
||||
resolveTelegramConversationRoute,
|
||||
} from "./conversation-route.js";
|
||||
import { shouldSuppressLocalTelegramExecApprovalPrompt } from "./exec-approvals.js";
|
||||
import type { TelegramTransport } from "./fetch.js";
|
||||
import {
|
||||
|
|
@ -650,7 +653,13 @@ export const registerTelegramNativeCommands = ({
|
|||
});
|
||||
return;
|
||||
}
|
||||
const baseSessionKey = route.sessionKey;
|
||||
const baseSessionKey = resolveTelegramConversationBaseSessionKey({
|
||||
cfg,
|
||||
route,
|
||||
chatId,
|
||||
isGroup,
|
||||
senderId,
|
||||
});
|
||||
// DMs: use raw messageThreadId for thread sessions (not resolvedThreadId which is for forums)
|
||||
const dmThreadId = threadSpec.scope === "dm" ? threadSpec.id : undefined;
|
||||
const threadKeys =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveTelegramConversationBaseSessionKey } from "./conversation-route.js";
|
||||
|
||||
describe("resolveTelegramConversationBaseSessionKey", () => {
|
||||
const cfg: OpenClawConfig = {};
|
||||
|
||||
it("keeps the routed session key for the default account", () => {
|
||||
expect(
|
||||
resolveTelegramConversationBaseSessionKey({
|
||||
cfg,
|
||||
route: {
|
||||
agentId: "main",
|
||||
accountId: "default",
|
||||
matchedBy: "default",
|
||||
sessionKey: "agent:main:main",
|
||||
},
|
||||
chatId: 12345,
|
||||
isGroup: false,
|
||||
senderId: 12345,
|
||||
}),
|
||||
).toBe("agent:main:main");
|
||||
});
|
||||
|
||||
it("uses the per-account fallback key for named-account DMs without an explicit binding", () => {
|
||||
expect(
|
||||
resolveTelegramConversationBaseSessionKey({
|
||||
cfg,
|
||||
route: {
|
||||
agentId: "main",
|
||||
accountId: "personal",
|
||||
matchedBy: "default",
|
||||
sessionKey: "agent:main:main",
|
||||
},
|
||||
chatId: 12345,
|
||||
isGroup: false,
|
||||
senderId: 12345,
|
||||
}),
|
||||
).toBe("agent:main:telegram:personal:direct:12345");
|
||||
});
|
||||
|
||||
it("keeps DM topic isolation on the named-account fallback key", () => {
|
||||
const baseSessionKey = resolveTelegramConversationBaseSessionKey({
|
||||
cfg,
|
||||
route: {
|
||||
agentId: "main",
|
||||
accountId: "personal",
|
||||
matchedBy: "default",
|
||||
sessionKey: "agent:main:main",
|
||||
},
|
||||
chatId: 12345,
|
||||
isGroup: false,
|
||||
senderId: 12345,
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveThreadSessionKeys({
|
||||
baseSessionKey,
|
||||
threadId: "12345:99",
|
||||
}).sessionKey,
|
||||
).toBe("agent:main:telegram:personal:direct:12345:thread:12345:99");
|
||||
});
|
||||
});
|
||||
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from "openclaw/plugin-sdk/routing";
|
||||
import {
|
||||
buildAgentMainSessionKey,
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
resolveAgentIdFromSessionKey,
|
||||
sanitizeAgentId,
|
||||
} from "openclaw/plugin-sdk/routing";
|
||||
|
|
@ -148,3 +149,34 @@ export function resolveTelegramConversationRoute(params: {
|
|||
configuredBindingSessionKey,
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveTelegramConversationBaseSessionKey(params: {
|
||||
cfg: OpenClawConfig;
|
||||
route: Pick<
|
||||
ReturnType<typeof resolveTelegramConversationRoute>["route"],
|
||||
"agentId" | "accountId" | "matchedBy" | "sessionKey"
|
||||
>;
|
||||
chatId: number | string;
|
||||
isGroup: boolean;
|
||||
senderId?: string | number | null;
|
||||
}): string {
|
||||
const isNamedAccountFallback =
|
||||
params.route.accountId !== DEFAULT_ACCOUNT_ID && params.route.matchedBy === "default";
|
||||
if (!isNamedAccountFallback || params.isGroup) {
|
||||
return params.route.sessionKey;
|
||||
}
|
||||
return buildAgentSessionKey({
|
||||
agentId: params.route.agentId,
|
||||
channel: "telegram",
|
||||
accountId: params.route.accountId,
|
||||
peer: {
|
||||
kind: "direct",
|
||||
id: resolveTelegramDirectPeerId({
|
||||
chatId: params.chatId,
|
||||
senderId: params.senderId,
|
||||
}),
|
||||
},
|
||||
dmScope: "per-account-channel-peer",
|
||||
identityLinks: params.cfg.session?.identityLinks,
|
||||
}).toLowerCase();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue