mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 13:07:39 +00:00
refactor(channels): dedupe message routing and telegram helpers
This commit is contained in:
@@ -3,6 +3,27 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
let collectTelegramUnmentionedGroupIds: typeof import("./audit.js").collectTelegramUnmentionedGroupIds;
|
||||
let auditTelegramGroupMembership: typeof import("./audit.js").auditTelegramGroupMembership;
|
||||
|
||||
function mockGetChatMemberStatus(status: string) {
|
||||
vi.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn().mockResolvedValueOnce(
|
||||
new Response(JSON.stringify({ ok: true, result: { status } }), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async function auditSingleGroup() {
|
||||
return auditTelegramGroupMembership({
|
||||
token: "t",
|
||||
botId: 123,
|
||||
groupIds: ["-1001"],
|
||||
timeoutMs: 5000,
|
||||
});
|
||||
}
|
||||
|
||||
describe("telegram audit", () => {
|
||||
beforeAll(async () => {
|
||||
({ collectTelegramUnmentionedGroupIds, auditTelegramGroupMembership } =
|
||||
@@ -27,42 +48,16 @@ describe("telegram audit", () => {
|
||||
});
|
||||
|
||||
it("audits membership via getChatMember", async () => {
|
||||
vi.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn().mockResolvedValueOnce(
|
||||
new Response(JSON.stringify({ ok: true, result: { status: "member" } }), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}),
|
||||
),
|
||||
);
|
||||
const res = await auditTelegramGroupMembership({
|
||||
token: "t",
|
||||
botId: 123,
|
||||
groupIds: ["-1001"],
|
||||
timeoutMs: 5000,
|
||||
});
|
||||
mockGetChatMemberStatus("member");
|
||||
const res = await auditSingleGroup();
|
||||
expect(res.ok).toBe(true);
|
||||
expect(res.groups[0]?.chatId).toBe("-1001");
|
||||
expect(res.groups[0]?.status).toBe("member");
|
||||
});
|
||||
|
||||
it("reports bot not in group when status is left", async () => {
|
||||
vi.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn().mockResolvedValueOnce(
|
||||
new Response(JSON.stringify({ ok: true, result: { status: "left" } }), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}),
|
||||
),
|
||||
);
|
||||
const res = await auditTelegramGroupMembership({
|
||||
token: "t",
|
||||
botId: 123,
|
||||
groupIds: ["-1001"],
|
||||
timeoutMs: 5000,
|
||||
});
|
||||
mockGetChatMemberStatus("left");
|
||||
const res = await auditSingleGroup();
|
||||
expect(res.ok).toBe(false);
|
||||
expect(res.groups[0]?.ok).toBe(false);
|
||||
expect(res.groups[0]?.status).toBe("left");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { buildTelegramMessageContext } from "./bot-message-context.js";
|
||||
import { buildTelegramMessageContextForTest } from "./bot-message-context.test-harness.js";
|
||||
|
||||
const transcribeFirstAudioMock = vi.fn();
|
||||
|
||||
@@ -11,39 +11,22 @@ describe("buildTelegramMessageContext audio transcript body", () => {
|
||||
it("uses preflight transcript as BodyForAgent for mention-gated group voice messages", async () => {
|
||||
transcribeFirstAudioMock.mockResolvedValueOnce("hey bot please help");
|
||||
|
||||
const ctx = await buildTelegramMessageContext({
|
||||
primaryCtx: {
|
||||
message: {
|
||||
message_id: 1,
|
||||
chat: { id: -1001234567890, type: "supergroup", title: "Test Group" },
|
||||
date: 1700000000,
|
||||
from: { id: 42, first_name: "Alice" },
|
||||
voice: { file_id: "voice-1" },
|
||||
},
|
||||
me: { id: 7, username: "bot" },
|
||||
} as never,
|
||||
const ctx = await buildTelegramMessageContextForTest({
|
||||
message: {
|
||||
message_id: 1,
|
||||
chat: { id: -1001234567890, type: "supergroup", title: "Test Group" },
|
||||
date: 1700000000,
|
||||
text: undefined,
|
||||
from: { id: 42, first_name: "Alice" },
|
||||
voice: { file_id: "voice-1" },
|
||||
},
|
||||
allMedia: [{ path: "/tmp/voice.ogg", contentType: "audio/ogg" }],
|
||||
storeAllowFrom: [],
|
||||
options: { forceWasMentioned: true },
|
||||
bot: {
|
||||
api: {
|
||||
sendChatAction: vi.fn(),
|
||||
setMessageReaction: vi.fn(),
|
||||
},
|
||||
} as never,
|
||||
cfg: {
|
||||
agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } },
|
||||
channels: { telegram: {} },
|
||||
messages: { groupChat: { mentionPatterns: ["\\bbot\\b"] } },
|
||||
} as never,
|
||||
account: { accountId: "default" } as never,
|
||||
historyLimit: 0,
|
||||
groupHistories: new Map(),
|
||||
dmPolicy: "open",
|
||||
allowFrom: [],
|
||||
groupAllowFrom: [],
|
||||
ackReactionScope: "off",
|
||||
logger: { info: vi.fn() },
|
||||
},
|
||||
resolveGroupActivation: () => true,
|
||||
resolveGroupRequireMention: () => true,
|
||||
resolveTelegramGroupConfig: () => ({
|
||||
|
||||
@@ -1,50 +1,17 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { buildTelegramMessageContext } from "./bot-message-context.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildTelegramMessageContextForTest } from "./bot-message-context.test-harness.js";
|
||||
|
||||
describe("buildTelegramMessageContext sender prefix", () => {
|
||||
async function buildCtx(params: {
|
||||
messageId: number;
|
||||
options?: Record<string, unknown>;
|
||||
}): Promise<Awaited<ReturnType<typeof buildTelegramMessageContext>>> {
|
||||
return await buildTelegramMessageContext({
|
||||
primaryCtx: {
|
||||
message: {
|
||||
message_id: params.messageId,
|
||||
chat: { id: -99, type: "supergroup", title: "Dev Chat" },
|
||||
date: 1700000000,
|
||||
text: "hello",
|
||||
from: { id: 42, first_name: "Alice" },
|
||||
},
|
||||
me: { id: 7, username: "bot" },
|
||||
} as never,
|
||||
allMedia: [],
|
||||
storeAllowFrom: [],
|
||||
options: params.options ?? {},
|
||||
bot: {
|
||||
api: {
|
||||
sendChatAction: vi.fn(),
|
||||
setMessageReaction: vi.fn(),
|
||||
},
|
||||
} as never,
|
||||
cfg: {
|
||||
agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } },
|
||||
channels: { telegram: {} },
|
||||
messages: { groupChat: { mentionPatterns: [] } },
|
||||
} as never,
|
||||
account: { accountId: "default" } as never,
|
||||
historyLimit: 0,
|
||||
groupHistories: new Map(),
|
||||
dmPolicy: "open",
|
||||
allowFrom: [],
|
||||
groupAllowFrom: [],
|
||||
ackReactionScope: "off",
|
||||
logger: { info: vi.fn() },
|
||||
resolveGroupActivation: () => undefined,
|
||||
resolveGroupRequireMention: () => false,
|
||||
resolveTelegramGroupConfig: () => ({
|
||||
groupConfig: { requireMention: false },
|
||||
topicConfig: undefined,
|
||||
}),
|
||||
async function buildCtx(params: { messageId: number; options?: Record<string, unknown> }) {
|
||||
return await buildTelegramMessageContextForTest({
|
||||
message: {
|
||||
message_id: params.messageId,
|
||||
chat: { id: -99, type: "supergroup", title: "Dev Chat" },
|
||||
date: 1700000000,
|
||||
text: "hello",
|
||||
from: { id: 42, first_name: "Alice" },
|
||||
},
|
||||
options: params.options,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,15 @@ export const baseTelegramMessageContextConfig = {
|
||||
|
||||
type BuildTelegramMessageContextForTestParams = {
|
||||
message: Record<string, unknown>;
|
||||
allMedia?: Array<Record<string, unknown>>;
|
||||
options?: Record<string, unknown>;
|
||||
cfg?: Record<string, unknown>;
|
||||
resolveGroupActivation?: () => boolean | undefined;
|
||||
resolveGroupRequireMention?: () => boolean;
|
||||
resolveTelegramGroupConfig?: () => {
|
||||
groupConfig?: { requireMention?: boolean };
|
||||
topicConfig?: unknown;
|
||||
};
|
||||
};
|
||||
|
||||
export async function buildTelegramMessageContextForTest(
|
||||
@@ -27,7 +34,7 @@ export async function buildTelegramMessageContextForTest(
|
||||
},
|
||||
me: { id: 7, username: "bot" },
|
||||
} as never,
|
||||
allMedia: [],
|
||||
allMedia: params.allMedia ?? [],
|
||||
storeAllowFrom: [],
|
||||
options: params.options ?? {},
|
||||
bot: {
|
||||
@@ -36,7 +43,7 @@ export async function buildTelegramMessageContextForTest(
|
||||
setMessageReaction: vi.fn(),
|
||||
},
|
||||
} as never,
|
||||
cfg: baseTelegramMessageContextConfig,
|
||||
cfg: (params.cfg ?? baseTelegramMessageContextConfig) as never,
|
||||
account: { accountId: "default" } as never,
|
||||
historyLimit: 0,
|
||||
groupHistories: new Map(),
|
||||
@@ -46,10 +53,12 @@ export async function buildTelegramMessageContextForTest(
|
||||
ackReactionScope: "off",
|
||||
logger: { info: vi.fn() },
|
||||
resolveGroupActivation: params.resolveGroupActivation ?? (() => undefined),
|
||||
resolveGroupRequireMention: () => false,
|
||||
resolveTelegramGroupConfig: () => ({
|
||||
groupConfig: { requireMention: false },
|
||||
topicConfig: undefined,
|
||||
}),
|
||||
resolveGroupRequireMention: params.resolveGroupRequireMention ?? (() => false),
|
||||
resolveTelegramGroupConfig:
|
||||
params.resolveTelegramGroupConfig ??
|
||||
(() => ({
|
||||
groupConfig: { requireMention: false },
|
||||
topicConfig: undefined,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ import {
|
||||
} from "./bot/helpers.js";
|
||||
import type { StickerMetadata, TelegramContext } from "./bot/types.js";
|
||||
import { evaluateTelegramGroupBaseAccess } from "./group-access.js";
|
||||
import { resolveTelegramGroupPromptSettings } from "./group-config-helpers.js";
|
||||
import {
|
||||
buildTelegramStatusReactionVariants,
|
||||
resolveTelegramAllowedEmojiReactions,
|
||||
@@ -675,13 +676,10 @@ export const buildTelegramMessageContext = async ({
|
||||
});
|
||||
}
|
||||
|
||||
const skillFilter = firstDefined(topicConfig?.skills, groupConfig?.skills);
|
||||
const systemPromptParts = [
|
||||
groupConfig?.systemPrompt?.trim() || null,
|
||||
topicConfig?.systemPrompt?.trim() || null,
|
||||
].filter((entry): entry is string => Boolean(entry));
|
||||
const groupSystemPrompt =
|
||||
systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
|
||||
const { skillFilter, groupSystemPrompt } = resolveTelegramGroupPromptSettings({
|
||||
groupConfig,
|
||||
topicConfig,
|
||||
});
|
||||
const commandBody = normalizeCommandBody(rawBody, { botUsername });
|
||||
const inboundHistory =
|
||||
isGroup && historyKey && historyLimit > 0
|
||||
|
||||
@@ -36,6 +36,20 @@ vi.mock("./bot/delivery.js", () => ({
|
||||
}));
|
||||
|
||||
describe("registerTelegramNativeCommands", () => {
|
||||
type RegisteredCommand = {
|
||||
command: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
async function waitForRegisteredCommands(
|
||||
setMyCommands: ReturnType<typeof vi.fn>,
|
||||
): Promise<RegisteredCommand[]> {
|
||||
await vi.waitFor(() => {
|
||||
expect(setMyCommands).toHaveBeenCalled();
|
||||
});
|
||||
return setMyCommands.mock.calls[0]?.[0] as RegisteredCommand[];
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
listSkillCommandsForAgents.mockClear();
|
||||
listSkillCommandsForAgents.mockReturnValue([]);
|
||||
@@ -166,14 +180,7 @@ describe("registerTelegramNativeCommands", () => {
|
||||
} as unknown as Parameters<typeof registerTelegramNativeCommands>[0]["bot"],
|
||||
});
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(setMyCommands).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const registeredCommands = setMyCommands.mock.calls[0]?.[0] as Array<{
|
||||
command: string;
|
||||
description: string;
|
||||
}>;
|
||||
const registeredCommands = await waitForRegisteredCommands(setMyCommands);
|
||||
expect(registeredCommands.some((entry) => entry.command === "export_session")).toBe(true);
|
||||
expect(registeredCommands.some((entry) => entry.command === "export-session")).toBe(false);
|
||||
|
||||
@@ -207,14 +214,7 @@ describe("registerTelegramNativeCommands", () => {
|
||||
} as TelegramAccountConfig,
|
||||
});
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(setMyCommands).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const registeredCommands = setMyCommands.mock.calls[0]?.[0] as Array<{
|
||||
command: string;
|
||||
description: string;
|
||||
}>;
|
||||
const registeredCommands = await waitForRegisteredCommands(setMyCommands);
|
||||
|
||||
expect(registeredCommands.length).toBeGreaterThan(0);
|
||||
for (const entry of registeredCommands) {
|
||||
|
||||
@@ -41,7 +41,7 @@ import { resolveAgentRoute } from "../routing/resolve-route.js";
|
||||
import { resolveThreadSessionKeys } from "../routing/session-key.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { withTelegramApiErrorLogging } from "./api-logging.js";
|
||||
import { firstDefined, isSenderAllowed, normalizeAllowFromWithStore } from "./bot-access.js";
|
||||
import { isSenderAllowed, normalizeAllowFromWithStore } from "./bot-access.js";
|
||||
import {
|
||||
buildCappedTelegramMenuCommands,
|
||||
buildPluginTelegramMenuCommands,
|
||||
@@ -64,6 +64,7 @@ import {
|
||||
evaluateTelegramGroupBaseAccess,
|
||||
evaluateTelegramGroupPolicyAccess,
|
||||
} from "./group-access.js";
|
||||
import { resolveTelegramGroupPromptSettings } from "./group-config-helpers.js";
|
||||
import { buildInlineKeyboard } from "./send.js";
|
||||
|
||||
const EMPTY_RESPONSE_FALLBACK = "No response generated. Please try again.";
|
||||
@@ -552,13 +553,10 @@ export const registerTelegramNativeCommands = ({
|
||||
})
|
||||
: null;
|
||||
const sessionKey = threadKeys?.sessionKey ?? baseSessionKey;
|
||||
const skillFilter = firstDefined(topicConfig?.skills, groupConfig?.skills);
|
||||
const systemPromptParts = [
|
||||
groupConfig?.systemPrompt?.trim() || null,
|
||||
topicConfig?.systemPrompt?.trim() || null,
|
||||
].filter((entry): entry is string => Boolean(entry));
|
||||
const groupSystemPrompt =
|
||||
systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
|
||||
const { skillFilter, groupSystemPrompt } = resolveTelegramGroupPromptSettings({
|
||||
groupConfig,
|
||||
topicConfig,
|
||||
});
|
||||
const conversationLabel = isGroup
|
||||
? msg.chat.title
|
||||
? `${msg.chat.title} id:${chatId}`
|
||||
|
||||
@@ -17,6 +17,11 @@ async function createMessageHandlerAndReplySpy() {
|
||||
return { handler, replySpy };
|
||||
}
|
||||
|
||||
function expectSingleReplyPayload(replySpy: ReturnType<typeof vi.fn>) {
|
||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||
return replySpy.mock.calls[0][0] as Record<string, unknown>;
|
||||
}
|
||||
|
||||
describe("telegram inbound media", () => {
|
||||
const _INBOUND_MEDIA_TEST_TIMEOUT_MS = process.platform === "win32" ? 30_000 : 20_000;
|
||||
it(
|
||||
@@ -40,8 +45,7 @@ describe("telegram inbound media", () => {
|
||||
getFile: async () => ({ file_path: "unused" }),
|
||||
});
|
||||
|
||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||
const payload = replySpy.mock.calls[0][0];
|
||||
const payload = expectSingleReplyPayload(replySpy);
|
||||
expect(payload.Body).toContain("Meet here");
|
||||
expect(payload.Body).toContain("48.858844");
|
||||
expect(payload.LocationLat).toBe(48.858844);
|
||||
@@ -72,8 +76,7 @@ describe("telegram inbound media", () => {
|
||||
getFile: async () => ({ file_path: "unused" }),
|
||||
});
|
||||
|
||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||
const payload = replySpy.mock.calls[0][0];
|
||||
const payload = expectSingleReplyPayload(replySpy);
|
||||
expect(payload.Body).toContain("Eiffel Tower");
|
||||
expect(payload.LocationName).toBe("Eiffel Tower");
|
||||
expect(payload.LocationAddress).toBe("Champ de Mars, Paris");
|
||||
|
||||
@@ -61,6 +61,16 @@ function mockMediaLoad(fileName: string, contentType: string, data: string) {
|
||||
});
|
||||
}
|
||||
|
||||
function createSendMessageHarness(messageId = 4) {
|
||||
const runtime = createRuntime();
|
||||
const sendMessage = vi.fn().mockResolvedValue({
|
||||
message_id: messageId,
|
||||
chat: { id: "123" },
|
||||
});
|
||||
const bot = createBot({ sendMessage });
|
||||
return { runtime, sendMessage, bot };
|
||||
}
|
||||
|
||||
describe("deliverReplies", () => {
|
||||
beforeEach(() => {
|
||||
loadWebMedia.mockReset();
|
||||
@@ -178,12 +188,7 @@ describe("deliverReplies", () => {
|
||||
});
|
||||
|
||||
it("includes message_thread_id for DM topics", async () => {
|
||||
const runtime = createRuntime();
|
||||
const sendMessage = vi.fn().mockResolvedValue({
|
||||
message_id: 4,
|
||||
chat: { id: "123" },
|
||||
});
|
||||
const bot = createBot({ sendMessage });
|
||||
const { runtime, sendMessage, bot } = createSendMessageHarness();
|
||||
|
||||
await deliverWith({
|
||||
replies: [{ text: "Hello" }],
|
||||
@@ -202,12 +207,7 @@ describe("deliverReplies", () => {
|
||||
});
|
||||
|
||||
it("does not include link_preview_options when linkPreview is true", async () => {
|
||||
const runtime = createRuntime();
|
||||
const sendMessage = vi.fn().mockResolvedValue({
|
||||
message_id: 4,
|
||||
chat: { id: "123" },
|
||||
});
|
||||
const bot = createBot({ sendMessage });
|
||||
const { runtime, sendMessage, bot } = createSendMessageHarness();
|
||||
|
||||
await deliverWith({
|
||||
replies: [{ text: "Check https://example.com" }],
|
||||
|
||||
19
src/telegram/group-config-helpers.ts
Normal file
19
src/telegram/group-config-helpers.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type { TelegramGroupConfig, TelegramTopicConfig } from "../config/types.js";
|
||||
import { firstDefined } from "./bot-access.js";
|
||||
|
||||
export function resolveTelegramGroupPromptSettings(params: {
|
||||
groupConfig?: TelegramGroupConfig;
|
||||
topicConfig?: TelegramTopicConfig;
|
||||
}): {
|
||||
skillFilter: string[] | undefined;
|
||||
groupSystemPrompt: string | undefined;
|
||||
} {
|
||||
const skillFilter = firstDefined(params.topicConfig?.skills, params.groupConfig?.skills);
|
||||
const systemPromptParts = [
|
||||
params.groupConfig?.systemPrompt?.trim() || null,
|
||||
params.topicConfig?.systemPrompt?.trim() || null,
|
||||
].filter((entry): entry is string => Boolean(entry));
|
||||
const groupSystemPrompt =
|
||||
systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
|
||||
return { skillFilter, groupSystemPrompt };
|
||||
}
|
||||
@@ -2,9 +2,44 @@ import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveTelegramReactionLevel } from "./reaction-level.js";
|
||||
|
||||
type ReactionResolution = ReturnType<typeof resolveTelegramReactionLevel>;
|
||||
|
||||
describe("resolveTelegramReactionLevel", () => {
|
||||
const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN;
|
||||
|
||||
const expectReactionFlags = (
|
||||
result: ReactionResolution,
|
||||
expected: {
|
||||
level: "off" | "ack" | "minimal" | "extensive";
|
||||
ackEnabled: boolean;
|
||||
agentReactionsEnabled: boolean;
|
||||
agentReactionGuidance?: "minimal" | "extensive";
|
||||
},
|
||||
) => {
|
||||
expect(result.level).toBe(expected.level);
|
||||
expect(result.ackEnabled).toBe(expected.ackEnabled);
|
||||
expect(result.agentReactionsEnabled).toBe(expected.agentReactionsEnabled);
|
||||
expect(result.agentReactionGuidance).toBe(expected.agentReactionGuidance);
|
||||
};
|
||||
|
||||
const expectMinimalFlags = (result: ReactionResolution) => {
|
||||
expectReactionFlags(result, {
|
||||
level: "minimal",
|
||||
ackEnabled: false,
|
||||
agentReactionsEnabled: true,
|
||||
agentReactionGuidance: "minimal",
|
||||
});
|
||||
};
|
||||
|
||||
const expectExtensiveFlags = (result: ReactionResolution) => {
|
||||
expectReactionFlags(result, {
|
||||
level: "extensive",
|
||||
ackEnabled: false,
|
||||
agentReactionsEnabled: true,
|
||||
agentReactionGuidance: "extensive",
|
||||
});
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
process.env.TELEGRAM_BOT_TOKEN = "test-token";
|
||||
});
|
||||
@@ -23,10 +58,7 @@ describe("resolveTelegramReactionLevel", () => {
|
||||
};
|
||||
|
||||
const result = resolveTelegramReactionLevel({ cfg });
|
||||
expect(result.level).toBe("minimal");
|
||||
expect(result.ackEnabled).toBe(false);
|
||||
expect(result.agentReactionsEnabled).toBe(true);
|
||||
expect(result.agentReactionGuidance).toBe("minimal");
|
||||
expectMinimalFlags(result);
|
||||
});
|
||||
|
||||
it("returns off level with no reactions enabled", () => {
|
||||
@@ -35,10 +67,11 @@ describe("resolveTelegramReactionLevel", () => {
|
||||
};
|
||||
|
||||
const result = resolveTelegramReactionLevel({ cfg });
|
||||
expect(result.level).toBe("off");
|
||||
expect(result.ackEnabled).toBe(false);
|
||||
expect(result.agentReactionsEnabled).toBe(false);
|
||||
expect(result.agentReactionGuidance).toBeUndefined();
|
||||
expectReactionFlags(result, {
|
||||
level: "off",
|
||||
ackEnabled: false,
|
||||
agentReactionsEnabled: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns ack level with only ackEnabled", () => {
|
||||
@@ -47,10 +80,11 @@ describe("resolveTelegramReactionLevel", () => {
|
||||
};
|
||||
|
||||
const result = resolveTelegramReactionLevel({ cfg });
|
||||
expect(result.level).toBe("ack");
|
||||
expect(result.ackEnabled).toBe(true);
|
||||
expect(result.agentReactionsEnabled).toBe(false);
|
||||
expect(result.agentReactionGuidance).toBeUndefined();
|
||||
expectReactionFlags(result, {
|
||||
level: "ack",
|
||||
ackEnabled: true,
|
||||
agentReactionsEnabled: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns minimal level with agent reactions enabled and minimal guidance", () => {
|
||||
@@ -59,10 +93,7 @@ describe("resolveTelegramReactionLevel", () => {
|
||||
};
|
||||
|
||||
const result = resolveTelegramReactionLevel({ cfg });
|
||||
expect(result.level).toBe("minimal");
|
||||
expect(result.ackEnabled).toBe(false);
|
||||
expect(result.agentReactionsEnabled).toBe(true);
|
||||
expect(result.agentReactionGuidance).toBe("minimal");
|
||||
expectMinimalFlags(result);
|
||||
});
|
||||
|
||||
it("returns extensive level with agent reactions enabled and extensive guidance", () => {
|
||||
@@ -71,10 +102,7 @@ describe("resolveTelegramReactionLevel", () => {
|
||||
};
|
||||
|
||||
const result = resolveTelegramReactionLevel({ cfg });
|
||||
expect(result.level).toBe("extensive");
|
||||
expect(result.ackEnabled).toBe(false);
|
||||
expect(result.agentReactionsEnabled).toBe(true);
|
||||
expect(result.agentReactionGuidance).toBe("extensive");
|
||||
expectExtensiveFlags(result);
|
||||
});
|
||||
|
||||
it("resolves reaction level from a specific account", () => {
|
||||
@@ -90,10 +118,7 @@ describe("resolveTelegramReactionLevel", () => {
|
||||
};
|
||||
|
||||
const result = resolveTelegramReactionLevel({ cfg, accountId: "work" });
|
||||
expect(result.level).toBe("extensive");
|
||||
expect(result.ackEnabled).toBe(false);
|
||||
expect(result.agentReactionsEnabled).toBe(true);
|
||||
expect(result.agentReactionGuidance).toBe("extensive");
|
||||
expectExtensiveFlags(result);
|
||||
});
|
||||
|
||||
it("falls back to global level when account has no reactionLevel", () => {
|
||||
@@ -109,8 +134,6 @@ describe("resolveTelegramReactionLevel", () => {
|
||||
};
|
||||
|
||||
const result = resolveTelegramReactionLevel({ cfg, accountId: "work" });
|
||||
expect(result.level).toBe("minimal");
|
||||
expect(result.agentReactionsEnabled).toBe(true);
|
||||
expect(result.agentReactionGuidance).toBe("minimal");
|
||||
expectMinimalFlags(result);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user