Merge cc4afb26869e81429f9fc43ebcddb58cefb2f3b4 into 5e417b44e1540f528d2ae63e3e20229a902d1db2

This commit is contained in:
StriderX 2026-03-21 05:00:17 +03:00 committed by GitHub
commit bab5c8575e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 102 additions and 1 deletions

View File

@ -414,6 +414,11 @@ export async function handleFeishuMessage(params: {
({ requireMention } = resolveFeishuReplyPolicy({
isDirectMessage: false,
isThreadReply:
groupSession?.threadReply &&
(groupSession?.groupSessionScope === "group_topic" ||
groupSession?.groupSessionScope === "group_topic_sender" ||
groupSession?.replyInThread),
globalConfig: feishuCfg,
groupConfig,
}));

View File

@ -141,6 +141,7 @@ const ReplyInThreadSchema = z.enum(["disabled", "enabled"]).optional();
export const FeishuGroupSchema = z
.object({
requireMention: z.boolean().optional(),
requireMentionInThread: z.boolean().optional(),
tools: ToolPolicySchema,
skills: z.array(z.string()).optional(),
enabled: z.boolean().optional(),
@ -164,6 +165,7 @@ const FeishuSharedConfigShape = {
groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
groupSenderAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
requireMention: z.boolean().optional(),
requireMentionInThread: z.boolean().optional(),
groups: z.record(z.string(), FeishuGroupSchema.optional()).optional(),
historyLimit: z.number().int().min(0).optional(),
dmHistoryLimit: z.number().int().min(0).optional(),

View File

@ -3,8 +3,9 @@ import {
isFeishuGroupAllowed,
resolveFeishuAllowlistMatch,
resolveFeishuGroupConfig,
resolveFeishuReplyPolicy,
} from "./policy.js";
import type { FeishuConfig } from "./types.js";
import type { FeishuConfig, FeishuGroupConfig } from "./types.js";
describe("feishu policy", () => {
describe("resolveFeishuGroupConfig", () => {
@ -100,6 +101,90 @@ describe("feishu policy", () => {
});
});
describe("resolveFeishuReplyPolicy", () => {
it("does not require mention for DMs", () => {
expect(resolveFeishuReplyPolicy({ isDirectMessage: true })).toEqual({
requireMention: false,
});
});
it("requires mention in group by default", () => {
expect(resolveFeishuReplyPolicy({ isDirectMessage: false })).toEqual({
requireMention: true,
});
});
it("respects group-level requireMention override", () => {
expect(
resolveFeishuReplyPolicy({
isDirectMessage: false,
groupConfig: { requireMention: false } as FeishuGroupConfig,
}),
).toEqual({ requireMention: false });
});
it("still requires mention for thread replies when no thread override is set", () => {
expect(
resolveFeishuReplyPolicy({
isDirectMessage: false,
isThreadReply: true,
}),
).toEqual({ requireMention: true });
});
it("skips mention for thread replies when requireMentionInThread is false (global)", () => {
expect(
resolveFeishuReplyPolicy({
isDirectMessage: false,
isThreadReply: true,
globalConfig: { requireMentionInThread: false } as FeishuConfig,
}),
).toEqual({ requireMention: false });
});
it("skips mention for thread replies when requireMentionInThread is false (group)", () => {
expect(
resolveFeishuReplyPolicy({
isDirectMessage: false,
isThreadReply: true,
groupConfig: { requireMentionInThread: false } as FeishuGroupConfig,
}),
).toEqual({ requireMention: false });
});
it("group-level requireMentionInThread overrides global", () => {
expect(
resolveFeishuReplyPolicy({
isDirectMessage: false,
isThreadReply: true,
globalConfig: { requireMentionInThread: false } as FeishuConfig,
groupConfig: { requireMentionInThread: true } as FeishuGroupConfig,
}),
).toEqual({ requireMention: true });
});
it("requireMentionInThread tightens when base requireMention is false", () => {
expect(
resolveFeishuReplyPolicy({
isDirectMessage: false,
isThreadReply: true,
globalConfig: { requireMention: false } as FeishuConfig,
groupConfig: { requireMentionInThread: true } as FeishuGroupConfig,
}),
).toEqual({ requireMention: true });
});
it("does not apply thread override for non-thread messages", () => {
expect(
resolveFeishuReplyPolicy({
isDirectMessage: false,
isThreadReply: false,
globalConfig: { requireMentionInThread: false } as FeishuConfig,
}),
).toEqual({ requireMention: true });
});
});
describe("isFeishuGroupAllowed", () => {
it("matches group IDs with chat: prefix", () => {
expect(

View File

@ -105,6 +105,7 @@ export function isFeishuGroupAllowed(params: {
export function resolveFeishuReplyPolicy(params: {
isDirectMessage: boolean;
isThreadReply?: boolean;
globalConfig?: FeishuConfig;
groupConfig?: FeishuGroupConfig;
}): { requireMention: boolean } {
@ -115,5 +116,13 @@ export function resolveFeishuReplyPolicy(params: {
const requireMention =
params.groupConfig?.requireMention ?? params.globalConfig?.requireMention ?? true;
if (params.isThreadReply) {
const threadOverride =
params.groupConfig?.requireMentionInThread ?? params.globalConfig?.requireMentionInThread;
if (threadOverride !== undefined) {
return { requireMention: threadOverride };
}
}
return { requireMention };
}