mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-27 04:07:48 +00:00
fix(telegram): keep room events fully quiet
This commit is contained in:
committed by
Peter Steinberger
parent
c2e659472a
commit
fb0f29b9cc
@@ -62,6 +62,52 @@ describe("buildTelegramMessageContext reactions", () => {
|
||||
inboundBodyMock.mockClear();
|
||||
});
|
||||
|
||||
it("does not create ack or status reactions for room events", async () => {
|
||||
const setMessageReaction = vi.fn(async () => undefined);
|
||||
const { createStatusReactionController } = createStatusReactionControllerStub();
|
||||
|
||||
const ctx = await buildTelegramMessageContextForTest({
|
||||
message: {
|
||||
message_id: 12,
|
||||
chat: { id: -1001234567890, type: "group", title: "Ops" },
|
||||
date: 1_700_000_000,
|
||||
text: "hello",
|
||||
from: { id: 42, first_name: "Alice" },
|
||||
},
|
||||
cfg: {
|
||||
agents: {
|
||||
defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" },
|
||||
},
|
||||
channels: {
|
||||
telegram: {
|
||||
groupPolicy: "open",
|
||||
groups: { "*": { requireMention: false } },
|
||||
},
|
||||
},
|
||||
messages: {
|
||||
ackReaction: "👀",
|
||||
groupChat: { mentionPatterns: [] },
|
||||
statusReactions: { enabled: true },
|
||||
},
|
||||
},
|
||||
ackReactionScope: "all",
|
||||
botApi: { setMessageReaction },
|
||||
runtime: { createStatusReactionController },
|
||||
resolveGroupActivation: () => false,
|
||||
resolveGroupRequireMention: () => false,
|
||||
resolveTelegramGroupConfig: () => ({
|
||||
groupConfig: { requireMention: false },
|
||||
topicConfig: undefined,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(ctx?.ctxPayload.InboundTurnKind).toBe("room_event");
|
||||
expect(ctx?.ackReactionPromise).toBeNull();
|
||||
expect(ctx?.statusReactionController).toBeNull();
|
||||
expect(createStatusReactionController).not.toHaveBeenCalled();
|
||||
expect(setMessageReaction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not create status reactions when the ack gate blocks an unmentioned group message", async () => {
|
||||
const setMessageReaction = vi.fn(async () => undefined);
|
||||
const { createStatusReactionController } = createStatusReactionControllerStub();
|
||||
|
||||
@@ -475,6 +475,45 @@ export const buildTelegramMessageContext = async ({
|
||||
return null;
|
||||
}
|
||||
|
||||
const { ctxPayload, skillFilter, turn } = await buildTelegramInboundContextPayload({
|
||||
cfg,
|
||||
primaryCtx,
|
||||
msg,
|
||||
allMedia,
|
||||
replyMedia,
|
||||
replyChain,
|
||||
promptContext,
|
||||
isGroup,
|
||||
isForum,
|
||||
chatId,
|
||||
senderId,
|
||||
senderUsername,
|
||||
resolvedThreadId,
|
||||
dmThreadId,
|
||||
threadSpec,
|
||||
route,
|
||||
rawBody: bodyResult.rawBody,
|
||||
bodyText: bodyResult.bodyText,
|
||||
historyKey: bodyResult.historyKey ?? "",
|
||||
historyLimit,
|
||||
groupHistories,
|
||||
groupConfig,
|
||||
topicConfig,
|
||||
stickerCacheHit: bodyResult.stickerCacheHit,
|
||||
effectiveWasMentioned: bodyResult.effectiveWasMentioned,
|
||||
hasControlCommand: bodyResult.hasControlCommand,
|
||||
...(bodyResult.audioTranscribedMediaIndex !== undefined
|
||||
? { audioTranscribedMediaIndex: bodyResult.audioTranscribedMediaIndex }
|
||||
: {}),
|
||||
locationData: bodyResult.locationData,
|
||||
options,
|
||||
dmAllowFrom: dmAllow.allowFrom,
|
||||
effectiveGroupAllow,
|
||||
commandAuthorized: bodyResult.commandAuthorized,
|
||||
topicName,
|
||||
sessionRuntime,
|
||||
});
|
||||
const canShowStatusReaction = ctxPayload.InboundTurnKind !== "room_event";
|
||||
const ackReaction = resolveAckReaction(cfg, route.agentId, {
|
||||
channel: "telegram",
|
||||
accountId: account.accountId,
|
||||
@@ -483,6 +522,7 @@ export const buildTelegramMessageContext = async ({
|
||||
ackReaction && isTelegramSupportedReactionEmoji(ackReaction) ? ackReaction : undefined;
|
||||
const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false;
|
||||
const shouldSendAckReaction = Boolean(
|
||||
canShowStatusReaction &&
|
||||
ackReaction &&
|
||||
shouldAckReactionGate({
|
||||
scope: ackReactionScope,
|
||||
@@ -577,45 +617,6 @@ export const buildTelegramMessageContext = async ({
|
||||
)
|
||||
: null;
|
||||
|
||||
const { ctxPayload, skillFilter, turn } = await buildTelegramInboundContextPayload({
|
||||
cfg,
|
||||
primaryCtx,
|
||||
msg,
|
||||
allMedia,
|
||||
replyMedia,
|
||||
replyChain,
|
||||
promptContext,
|
||||
isGroup,
|
||||
isForum,
|
||||
chatId,
|
||||
senderId,
|
||||
senderUsername,
|
||||
resolvedThreadId,
|
||||
dmThreadId,
|
||||
threadSpec,
|
||||
route,
|
||||
rawBody: bodyResult.rawBody,
|
||||
bodyText: bodyResult.bodyText,
|
||||
historyKey: bodyResult.historyKey ?? "",
|
||||
historyLimit,
|
||||
groupHistories,
|
||||
groupConfig,
|
||||
topicConfig,
|
||||
stickerCacheHit: bodyResult.stickerCacheHit,
|
||||
effectiveWasMentioned: bodyResult.effectiveWasMentioned,
|
||||
hasControlCommand: bodyResult.hasControlCommand,
|
||||
...(bodyResult.audioTranscribedMediaIndex !== undefined
|
||||
? { audioTranscribedMediaIndex: bodyResult.audioTranscribedMediaIndex }
|
||||
: {}),
|
||||
locationData: bodyResult.locationData,
|
||||
options,
|
||||
dmAllowFrom: dmAllow.allowFrom,
|
||||
effectiveGroupAllow,
|
||||
commandAuthorized: bodyResult.commandAuthorized,
|
||||
topicName,
|
||||
sessionRuntime,
|
||||
});
|
||||
|
||||
return {
|
||||
ctxPayload,
|
||||
turn,
|
||||
|
||||
@@ -1503,14 +1503,25 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
const groupHistories = new Map([
|
||||
[historyKey, [{ sender: "Alice", body: "side chatter", timestamp: 1 }]],
|
||||
]);
|
||||
dispatchReplyWithBufferedBlockDispatcher.mockResolvedValue({
|
||||
queuedFinal: false,
|
||||
counts: { block: 0, final: 0, tool: 0 },
|
||||
sourceReplyDeliveryMode: "message_tool_only",
|
||||
const statusReactionController = createStatusReactionController();
|
||||
loadSessionStore.mockReturnValue({
|
||||
"agent:main:telegram:group:-100123": { reasoningLevel: "stream" },
|
||||
});
|
||||
dispatchReplyWithBufferedBlockDispatcher.mockImplementation(async ({ replyOptions }) => {
|
||||
await replyOptions?.onReasoningStream?.({ text: "<think>ambient reasoning</think>" });
|
||||
await replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
|
||||
await replyOptions?.onCompactionStart?.();
|
||||
await replyOptions?.onCompactionEnd?.();
|
||||
return {
|
||||
queuedFinal: false,
|
||||
counts: { block: 0, final: 0, tool: 0 },
|
||||
sourceReplyDeliveryMode: "message_tool_only",
|
||||
};
|
||||
});
|
||||
|
||||
await dispatchWithContext({
|
||||
context: createContext({
|
||||
statusReactionController: statusReactionController as never,
|
||||
ctxPayload: {
|
||||
InboundTurnKind: "room_event",
|
||||
SessionKey: "agent:main:telegram:group:-100123",
|
||||
@@ -1539,6 +1550,9 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
sourceReplyDeliveryMode?: string;
|
||||
suppressTyping?: boolean;
|
||||
allowProgressCallbacksWhenSourceDeliverySuppressed?: boolean;
|
||||
onReasoningStream?: unknown;
|
||||
onCompactionStart?: unknown;
|
||||
onCompactionEnd?: unknown;
|
||||
};
|
||||
};
|
||||
expect(dispatchParams.replyOptions?.sourceReplyDeliveryMode).toBe("message_tool_only");
|
||||
@@ -1546,7 +1560,13 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
expect(dispatchParams.replyOptions?.allowProgressCallbacksWhenSourceDeliverySuppressed).toBe(
|
||||
false,
|
||||
);
|
||||
expect(dispatchParams.replyOptions?.onReasoningStream).toBeUndefined();
|
||||
expect(dispatchParams.replyOptions?.onCompactionStart).toBeUndefined();
|
||||
expect(dispatchParams.replyOptions?.onCompactionEnd).toBeUndefined();
|
||||
expect(createTelegramDraftStream).not.toHaveBeenCalled();
|
||||
expect(statusReactionController.setTool).not.toHaveBeenCalled();
|
||||
expect(statusReactionController.setCompacting).not.toHaveBeenCalled();
|
||||
expect(statusReactionController.setThinking).not.toHaveBeenCalled();
|
||||
expect(deliverReplies).not.toHaveBeenCalled();
|
||||
expect(groupHistories.get(historyKey)).toHaveLength(1);
|
||||
});
|
||||
|
||||
@@ -403,8 +403,10 @@ export const dispatchTelegramMessage = async ({
|
||||
ackReactionPromise,
|
||||
reactionApi,
|
||||
removeAckAfterReply,
|
||||
statusReactionController,
|
||||
statusReactionController: rawStatusReactionController,
|
||||
} = context;
|
||||
const isRoomEvent = ctxPayload.InboundTurnKind === "room_event";
|
||||
const statusReactionController = isRoomEvent ? null : rawStatusReactionController;
|
||||
const statusReactionTiming = {
|
||||
...DEFAULT_TIMING,
|
||||
...cfg.messages?.statusReactions?.timing,
|
||||
@@ -480,7 +482,6 @@ export const dispatchTelegramMessage = async ({
|
||||
const accountBlockStreamingEnabled =
|
||||
resolveChannelStreamingBlockEnabled(telegramCfg) ??
|
||||
cfg.agents?.defaults?.blockStreamingDefault === "on";
|
||||
const isRoomEvent = ctxPayload.InboundTurnKind === "room_event";
|
||||
const resolvedReasoningLevel = resolveTelegramReasoningLevel({
|
||||
cfg,
|
||||
sessionKey: ctxPayload.SessionKey,
|
||||
@@ -542,7 +543,7 @@ export const dispatchTelegramMessage = async ({
|
||||
!hasTelegramQuoteReply &&
|
||||
!accountBlockStreamingEnabled &&
|
||||
!forceBlockStreamingForReasoning;
|
||||
const canStreamReasoningDraft = streamReasoningDraft;
|
||||
const canStreamReasoningDraft = !isRoomEvent && streamReasoningDraft;
|
||||
const draftReplyToMessageId =
|
||||
replyToMode !== "off" && typeof msg.message_id === "number"
|
||||
? (replyQuoteMessageId ?? msg.message_id)
|
||||
|
||||
Reference in New Issue
Block a user