mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-07 07:58:36 +00:00
Summary: - The PR removes the auto-reply runtime warning for visible-reply defaults, adds doctor preview warnings and tests for message-tool visibility policy mismatches, and updates the group/channel docs and changelog wording. ClawSweeper fixups: - No separate fixup commits were needed after automerge opt-in. Validation: - ClawSweeper review passed for head1f96b3b568. - Required merge gates passed before the squash merge. Prepared head SHA:1f96b3b568Review: https://github.com/openclaw/openclaw/pull/75367#issuecomment-4357475980 Co-authored-by: Peter Steinberger <steipete@gmail.com>
295 lines
8.7 KiB
TypeScript
295 lines
8.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
|
import {
|
|
resolveSourceReplyDeliveryMode,
|
|
resolveSourceReplyVisibilityPolicy,
|
|
} from "./source-reply-delivery-mode.js";
|
|
|
|
const emptyConfig = {} as OpenClawConfig;
|
|
const automaticGroupReplyConfig = {
|
|
messages: {
|
|
groupChat: {
|
|
visibleReplies: "automatic",
|
|
},
|
|
},
|
|
} as const satisfies OpenClawConfig;
|
|
const globalToolOnlyReplyConfig = {
|
|
messages: {
|
|
visibleReplies: "message_tool",
|
|
},
|
|
} as const satisfies OpenClawConfig;
|
|
|
|
describe("resolveSourceReplyDeliveryMode", () => {
|
|
it("defaults groups and channels to message-tool-only delivery", () => {
|
|
expect(resolveSourceReplyDeliveryMode({ cfg: emptyConfig, ctx: { ChatType: "channel" } })).toBe(
|
|
"message_tool_only",
|
|
);
|
|
expect(resolveSourceReplyDeliveryMode({ cfg: emptyConfig, ctx: { ChatType: "group" } })).toBe(
|
|
"message_tool_only",
|
|
);
|
|
expect(resolveSourceReplyDeliveryMode({ cfg: emptyConfig, ctx: { ChatType: "direct" } })).toBe(
|
|
"automatic",
|
|
);
|
|
});
|
|
|
|
it("honors config and explicit requested mode", () => {
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({
|
|
cfg: automaticGroupReplyConfig,
|
|
ctx: { ChatType: "group" },
|
|
}),
|
|
).toBe("automatic");
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "channel" },
|
|
requested: "automatic",
|
|
}),
|
|
).toBe("automatic");
|
|
});
|
|
|
|
it("allows message-tool-only delivery for any source chat via global config", () => {
|
|
for (const ChatType of ["direct", "group", "channel"] as const) {
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({ cfg: globalToolOnlyReplyConfig, ctx: { ChatType } }),
|
|
).toBe("message_tool_only");
|
|
}
|
|
});
|
|
|
|
it("lets group/channel config override the global visible reply mode", () => {
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({
|
|
cfg: {
|
|
messages: {
|
|
visibleReplies: "message_tool",
|
|
groupChat: { visibleReplies: "automatic" },
|
|
},
|
|
},
|
|
ctx: { ChatType: "channel" },
|
|
}),
|
|
).toBe("automatic");
|
|
});
|
|
|
|
it("treats native commands as explicit replies in groups", () => {
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "group", CommandSource: "native" },
|
|
}),
|
|
).toBe("automatic");
|
|
});
|
|
|
|
it("falls back to automatic when message tool is unavailable", () => {
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "group" },
|
|
messageToolAvailable: false,
|
|
}),
|
|
).toBe("automatic");
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({
|
|
cfg: globalToolOnlyReplyConfig,
|
|
ctx: { ChatType: "direct" },
|
|
messageToolAvailable: false,
|
|
}),
|
|
).toBe("automatic");
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "channel" },
|
|
requested: "message_tool_only",
|
|
messageToolAvailable: false,
|
|
}),
|
|
).toBe("automatic");
|
|
});
|
|
|
|
it("keeps message-tool-only delivery when message tool availability is unknown", () => {
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "group" },
|
|
messageToolAvailable: true,
|
|
}),
|
|
).toBe("message_tool_only");
|
|
expect(
|
|
resolveSourceReplyDeliveryMode({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "channel" },
|
|
}),
|
|
).toBe("message_tool_only");
|
|
});
|
|
});
|
|
|
|
describe("resolveSourceReplyVisibilityPolicy", () => {
|
|
it("allows direct automatic delivery without suppressing typing", () => {
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "direct" },
|
|
sendPolicy: "allow",
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "automatic",
|
|
sendPolicyDenied: false,
|
|
suppressAutomaticSourceDelivery: false,
|
|
suppressDelivery: false,
|
|
suppressHookUserDelivery: false,
|
|
suppressHookReplyLifecycle: false,
|
|
suppressTyping: false,
|
|
deliverySuppressionReason: "",
|
|
});
|
|
});
|
|
|
|
it("suppresses automatic source delivery for default group turns without suppressing typing", () => {
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "group" },
|
|
sendPolicy: "allow",
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "message_tool_only",
|
|
sendPolicyDenied: false,
|
|
suppressAutomaticSourceDelivery: true,
|
|
suppressDelivery: true,
|
|
suppressHookUserDelivery: true,
|
|
suppressHookReplyLifecycle: false,
|
|
suppressTyping: false,
|
|
deliverySuppressionReason: "sourceReplyDeliveryMode: message_tool_only",
|
|
});
|
|
});
|
|
|
|
it("keeps native command replies visible in groups", () => {
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "group", CommandSource: "native" },
|
|
sendPolicy: "allow",
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "automatic",
|
|
suppressAutomaticSourceDelivery: false,
|
|
suppressDelivery: false,
|
|
suppressHookReplyLifecycle: false,
|
|
suppressTyping: false,
|
|
});
|
|
});
|
|
|
|
it("keeps configured automatic group delivery visible", () => {
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: automaticGroupReplyConfig,
|
|
ctx: { ChatType: "channel" },
|
|
sendPolicy: "allow",
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "automatic",
|
|
suppressAutomaticSourceDelivery: false,
|
|
suppressDelivery: false,
|
|
suppressHookReplyLifecycle: false,
|
|
suppressTyping: false,
|
|
});
|
|
});
|
|
|
|
it("supports explicit message-tool-only delivery for direct chats without suppressing typing", () => {
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "direct" },
|
|
requested: "message_tool_only",
|
|
sendPolicy: "allow",
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "message_tool_only",
|
|
suppressAutomaticSourceDelivery: true,
|
|
suppressDelivery: true,
|
|
suppressHookReplyLifecycle: false,
|
|
suppressTyping: false,
|
|
deliverySuppressionReason: "sourceReplyDeliveryMode: message_tool_only",
|
|
});
|
|
});
|
|
|
|
it("lets sendPolicy deny suppress delivery and typing", () => {
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "group" },
|
|
sendPolicy: "deny",
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "message_tool_only",
|
|
sendPolicyDenied: true,
|
|
suppressDelivery: true,
|
|
suppressHookUserDelivery: true,
|
|
suppressHookReplyLifecycle: true,
|
|
suppressTyping: true,
|
|
deliverySuppressionReason: "sendPolicy: deny",
|
|
});
|
|
});
|
|
|
|
it("keeps explicit typing suppression separate from delivery suppression", () => {
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "direct" },
|
|
sendPolicy: "allow",
|
|
explicitSuppressTyping: true,
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "automatic",
|
|
suppressDelivery: false,
|
|
suppressHookUserDelivery: false,
|
|
suppressHookReplyLifecycle: true,
|
|
suppressTyping: true,
|
|
});
|
|
});
|
|
|
|
it("keeps ACP child user delivery suppression separate from source delivery", () => {
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "direct" },
|
|
sendPolicy: "allow",
|
|
suppressAcpChildUserDelivery: true,
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "automatic",
|
|
suppressDelivery: false,
|
|
suppressHookUserDelivery: true,
|
|
suppressHookReplyLifecycle: true,
|
|
suppressTyping: false,
|
|
});
|
|
});
|
|
it("keeps delivery automatic when message-tool-only mode cannot send visibly", () => {
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "group" },
|
|
sendPolicy: "allow",
|
|
messageToolAvailable: false,
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "automatic",
|
|
suppressAutomaticSourceDelivery: false,
|
|
suppressDelivery: false,
|
|
suppressHookUserDelivery: false,
|
|
deliverySuppressionReason: "",
|
|
});
|
|
expect(
|
|
resolveSourceReplyVisibilityPolicy({
|
|
cfg: emptyConfig,
|
|
ctx: { ChatType: "channel" },
|
|
requested: "message_tool_only",
|
|
sendPolicy: "allow",
|
|
messageToolAvailable: false,
|
|
}),
|
|
).toMatchObject({
|
|
sourceReplyDeliveryMode: "automatic",
|
|
suppressAutomaticSourceDelivery: false,
|
|
suppressDelivery: false,
|
|
deliverySuppressionReason: "",
|
|
});
|
|
});
|
|
});
|