






















@@ -1,6 +1,27 @@
1-import { describe, expect, it } from "vitest";
1+import { beforeEach, describe, expect, it, vi } from "vitest";
22import type { OpenClawConfig } from "../../config/types.openclaw.js";
3+4+const loggerMocks = vi.hoisted(() => ({
5+warn: vi.fn(),
6+}));
7+8+vi.mock("../../logging/subsystem.js", () => ({
9+createSubsystemLogger: () => ({
10+subsystem: "auto-reply",
11+isEnabled: () => false,
12+trace: vi.fn(),
13+debug: vi.fn(),
14+info: vi.fn(),
15+warn: loggerMocks.warn,
16+error: vi.fn(),
17+fatal: vi.fn(),
18+raw: vi.fn(),
19+child: vi.fn(),
20+}),
21+}));
22+323import {
24+resetVisibleRepliesPrivateDefaultWarningForTest,
425resolveSourceReplyDeliveryMode,
526resolveSourceReplyVisibilityPolicy,
627} from "./source-reply-delivery-mode.js";
@@ -19,6 +40,11 @@ const globalToolOnlyReplyConfig = {
1940},
2041} as const satisfies OpenClawConfig;
214243+beforeEach(() => {
44+loggerMocks.warn.mockClear();
45+resetVisibleRepliesPrivateDefaultWarningForTest();
46+});
47+2248describe("resolveSourceReplyDeliveryMode", () => {
2349it("defaults groups and channels to message-tool-only delivery", () => {
2450expect(resolveSourceReplyDeliveryMode({ cfg: emptyConfig, ctx: { ChatType: "channel" } })).toBe(
@@ -30,6 +56,10 @@ describe("resolveSourceReplyDeliveryMode", () => {
3056expect(resolveSourceReplyDeliveryMode({ cfg: emptyConfig, ctx: { ChatType: "direct" } })).toBe(
3157"automatic",
3258);
59+expect(loggerMocks.warn).toHaveBeenCalledTimes(1);
60+expect(loggerMocks.warn).toHaveBeenCalledWith(
61+expect.stringContaining("Group/channel replies are private by default"),
62+);
3363});
34643565it("honors config and explicit requested mode", () => {
@@ -77,6 +107,42 @@ describe("resolveSourceReplyDeliveryMode", () => {
77107ctx: { ChatType: "group", CommandSource: "native" },
78108}),
79109).toBe("automatic");
110+expect(loggerMocks.warn).not.toHaveBeenCalled();
111+});
112+113+it("falls back to automatic when message tool is unavailable", () => {
114+expect(
115+resolveSourceReplyDeliveryMode({
116+cfg: emptyConfig,
117+ctx: { ChatType: "group" },
118+messageToolAvailable: false,
119+}),
120+).toBe("automatic");
121+expect(
122+resolveSourceReplyDeliveryMode({
123+cfg: globalToolOnlyReplyConfig,
124+ctx: { ChatType: "direct" },
125+messageToolAvailable: false,
126+}),
127+).toBe("automatic");
128+expect(loggerMocks.warn).not.toHaveBeenCalled();
129+});
130+131+it("keeps message-tool-only delivery when message tool availability is unknown", () => {
132+expect(
133+resolveSourceReplyDeliveryMode({
134+cfg: emptyConfig,
135+ctx: { ChatType: "group" },
136+messageToolAvailable: true,
137+}),
138+).toBe("message_tool_only");
139+expect(
140+resolveSourceReplyDeliveryMode({
141+cfg: emptyConfig,
142+ctx: { ChatType: "channel" },
143+}),
144+).toBe("message_tool_only");
145+expect(loggerMocks.warn).toHaveBeenCalledTimes(1);
80146});
81147});
82148@@ -220,4 +286,21 @@ describe("resolveSourceReplyVisibilityPolicy", () => {
220286suppressTyping: false,
221287});
222288});
289+290+it("keeps delivery automatic when message-tool-only mode cannot send visibly", () => {
291+expect(
292+resolveSourceReplyVisibilityPolicy({
293+cfg: emptyConfig,
294+ctx: { ChatType: "group" },
295+sendPolicy: "allow",
296+messageToolAvailable: false,
297+}),
298+).toMatchObject({
299+sourceReplyDeliveryMode: "automatic",
300+suppressAutomaticSourceDelivery: false,
301+suppressDelivery: false,
302+suppressHookUserDelivery: false,
303+deliverySuppressionReason: "",
304+});
305+});
223306});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。