mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 04:15:48 -06:00
fix(telegram): preserve direct-topic self-history (#127050)
This commit is contained in:
committed by
GitHub
parent
d15f570742
commit
f1723c757b
@@ -300,7 +300,7 @@ export function createTelegramBotCore(
|
||||
}
|
||||
recordTelegramGroupHistoryEntry({
|
||||
historyMap: groupHistories,
|
||||
historyKey: buildTelegramGroupPeerId(record.chatId, record.messageThreadId),
|
||||
historyKey: buildTelegramGroupPeerId(record.chatId, record.threadSpec),
|
||||
limit: historyLimit,
|
||||
entry: {
|
||||
sender: botHistorySender,
|
||||
@@ -331,23 +331,21 @@ export function createTelegramBotCore(
|
||||
groupId: String(chatId),
|
||||
});
|
||||
const resolveGroupActivation = (params: {
|
||||
chatId: string | number;
|
||||
agentId?: string;
|
||||
messageThreadId?: number;
|
||||
sessionKey?: string;
|
||||
sessionKey: string;
|
||||
cfg: OpenClawConfig;
|
||||
}) => {
|
||||
const agentId = params.agentId ?? ownerAgentId;
|
||||
const sessionKey =
|
||||
params.sessionKey ??
|
||||
`agent:${agentId}:telegram:group:${buildTelegramGroupPeerId(params.chatId, params.messageThreadId)}`;
|
||||
const storePath = telegramDeps.resolveStorePath(params.cfg.session?.store, { agentId });
|
||||
try {
|
||||
const getSessionEntry = telegramDeps.getSessionEntry;
|
||||
if (!getSessionEntry) {
|
||||
return undefined;
|
||||
}
|
||||
const storedActivation = getSessionEntry({ storePath, sessionKey })?.groupActivation;
|
||||
const storedActivation = getSessionEntry({
|
||||
storePath,
|
||||
sessionKey: params.sessionKey,
|
||||
})?.groupActivation;
|
||||
const activation =
|
||||
storedActivation === "mention" || storedActivation === "always"
|
||||
? normalizeGroupActivation(storedActivation)
|
||||
|
||||
@@ -159,8 +159,6 @@ export function createTelegramInboundMedia({
|
||||
runtimeCfg: authorization.authorizationCfg,
|
||||
});
|
||||
const activationOverride = resolveGroupActivation({
|
||||
chatId,
|
||||
messageThreadId: resolvedThreadId,
|
||||
sessionKey: sessionState.sessionKey,
|
||||
agentId: sessionState.agentId,
|
||||
cfg: authorization.authorizationCfg,
|
||||
|
||||
@@ -83,10 +83,8 @@ export type RegisterTelegramHandlerParams = {
|
||||
telegramDeps: TelegramBotDeps;
|
||||
resolveGroupPolicy: (chatId: string | number, cfg: OpenClawConfig) => ChannelGroupPolicy;
|
||||
resolveGroupActivation: (params: {
|
||||
chatId: string | number;
|
||||
agentId?: string;
|
||||
messageThreadId?: number;
|
||||
sessionKey?: string;
|
||||
sessionKey: string;
|
||||
cfg: OpenClawConfig;
|
||||
}) => boolean | undefined;
|
||||
resolveGroupRequireMention: (chatId: string | number, cfg: OpenClawConfig) => boolean;
|
||||
|
||||
@@ -380,13 +380,11 @@ describe("buildTelegramMessageContext requireMention precedence", () => {
|
||||
if (!ctx?.ctxPayload) {
|
||||
throw new Error("expected Telegram context payload when topic disables requireMention");
|
||||
}
|
||||
const activationCalls = resolveGroupActivation.mock.calls as unknown as Array<
|
||||
[{ chatId: number; messageThreadId?: number; sessionKey: string }]
|
||||
>;
|
||||
const [activationOptions] = activationCalls[0] ?? [];
|
||||
expect(activationOptions?.chatId).toBe(-1001234567890);
|
||||
expect(activationOptions?.messageThreadId).toBe(99);
|
||||
expect(activationOptions?.sessionKey).toBe("agent:main:telegram:group:-1001234567890:topic:99");
|
||||
expect(resolveGroupActivation).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sessionKey: "agent:main:telegram:group:-1001234567890:topic:99",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("lets explicit topic requireMention=true override always activation", async () => {
|
||||
|
||||
@@ -434,8 +434,6 @@ export const buildTelegramMessageContext = async ({
|
||||
}),
|
||||
};
|
||||
const activationOverride = resolveGroupActivation({
|
||||
chatId,
|
||||
messageThreadId: resolvedThreadId,
|
||||
sessionKey,
|
||||
agentId: route.agentId,
|
||||
cfg,
|
||||
|
||||
@@ -72,10 +72,8 @@ type ResolveTelegramGroupConfig = (
|
||||
};
|
||||
|
||||
type ResolveGroupActivation = (params: {
|
||||
chatId: string | number;
|
||||
agentId?: string;
|
||||
messageThreadId?: number;
|
||||
sessionKey?: string;
|
||||
sessionKey: string;
|
||||
cfg: OpenClawConfig;
|
||||
}) => boolean | undefined;
|
||||
|
||||
|
||||
@@ -6,12 +6,17 @@ import {
|
||||
} from "openclaw/plugin-sdk/plugin-state-test-runtime";
|
||||
import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { buildTelegramGroupPeerId } from "./bot/helpers.js";
|
||||
import { recordTelegramGroupHistoryEntry } from "./group-history-window.js";
|
||||
import { resolveTelegramMessageCacheScope } from "./message-cache-persistence.js";
|
||||
import {
|
||||
createTelegramMessageCache,
|
||||
hasProviderObservedTelegramThreadBinding,
|
||||
} from "./message-cache.js";
|
||||
import { recordOutboundMessageForPromptContext } from "./outbound-message-context.js";
|
||||
import {
|
||||
recordOutboundMessageForPromptContext,
|
||||
registerTelegramOutboundGroupHistoryRecorder,
|
||||
} from "./outbound-message-context.js";
|
||||
import { setTelegramRuntime } from "./runtime.js";
|
||||
import {
|
||||
clearTelegramRuntimeForTest as clearTelegramRuntime,
|
||||
@@ -172,6 +177,59 @@ describe("recordOutboundMessageForPromptContext", () => {
|
||||
expect(cached?.threadBinding?.threadSpec).toEqual({ scope: "direct-messages", id: 77 });
|
||||
});
|
||||
|
||||
it("records forum and channel Direct Messages replies with the same topic ID in separate histories", async () => {
|
||||
const chatId = -1001;
|
||||
const history = new Map<string, Array<{ sender: string; body: string; messageId: string }>>();
|
||||
const unregister = registerTelegramOutboundGroupHistoryRecorder({
|
||||
accountId: "default",
|
||||
recorder: (record) =>
|
||||
recordTelegramGroupHistoryEntry({
|
||||
historyMap: history,
|
||||
historyKey: buildTelegramGroupPeerId(record.chatId, record.threadSpec),
|
||||
limit: 10,
|
||||
entry: {
|
||||
sender: "Configured Agent (you)",
|
||||
body: record.text ?? "<media>",
|
||||
messageId: String(record.messageId),
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
try {
|
||||
for (const { scope, messageId, body } of [
|
||||
{ scope: "forum", messageId: 710, body: "Forum reply" },
|
||||
{ scope: "direct-messages", messageId: 711, body: "Direct-topic reply" },
|
||||
] as const) {
|
||||
await recordOutboundMessageForPromptContext({
|
||||
cfg,
|
||||
account: { accountId: "default", name: "Configured Agent" },
|
||||
chatId,
|
||||
messageId,
|
||||
messageThreadId: 77,
|
||||
successfulSendThread: { scope, id: 77 },
|
||||
message: {
|
||||
chat: { id: chatId, type: "supergroup" },
|
||||
date: 1_736_380_700,
|
||||
message_id: messageId,
|
||||
...(scope === "forum"
|
||||
? { message_thread_id: 77 }
|
||||
: { direct_messages_topic: { topic_id: 77 } }),
|
||||
text: body,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
expect(history.get("-1001:direct-topic:77")).toEqual([
|
||||
expect.objectContaining({ body: "Direct-topic reply", messageId: "711" }),
|
||||
]);
|
||||
expect(history.get("-1001:topic:77")).toEqual([
|
||||
expect.objectContaining({ body: "Forum reply", messageId: "710" }),
|
||||
]);
|
||||
} finally {
|
||||
unregister();
|
||||
}
|
||||
});
|
||||
|
||||
it("binds a successful General-topic response from trusted send context", async () => {
|
||||
const cached = await recordAndRead({
|
||||
account: { accountId: "default", name: "Configured Agent" },
|
||||
|
||||
@@ -43,7 +43,7 @@ type TelegramOutboundGroupHistoryRecord = {
|
||||
chatId: string | number;
|
||||
messageId: number;
|
||||
text?: string;
|
||||
messageThreadId?: number;
|
||||
threadSpec?: TelegramThreadSpec;
|
||||
timestamp?: number;
|
||||
};
|
||||
|
||||
@@ -179,11 +179,12 @@ export async function recordOutboundMessageForPromptContext(params: {
|
||||
});
|
||||
if (params.recordGroupHistory !== false) {
|
||||
const timestamp = resolveOutboundCacheMessageTimestamp(cacheMessage);
|
||||
const threadSpec = providerObservedThread ?? params.successfulSendThread;
|
||||
outboundGroupHistoryRecorders.get(params.account.accountId)?.({
|
||||
chatId: params.chatId,
|
||||
messageId: params.messageId,
|
||||
text: params.text ?? cacheMessage.text ?? cacheMessage.caption,
|
||||
...(messageThreadId !== undefined ? { messageThreadId } : {}),
|
||||
...(threadSpec ? { threadSpec } : {}),
|
||||
...(timestamp !== undefined ? { timestamp } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user