mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
refactor: centralize inbound mention policy
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveMentionGating, resolveMentionGatingWithBypass } from "./mention-gating.js";
|
||||
import {
|
||||
implicitMentionKindWhen,
|
||||
resolveInboundMentionDecision,
|
||||
resolveMentionGating,
|
||||
resolveMentionGatingWithBypass,
|
||||
} from "./mention-gating.js";
|
||||
|
||||
describe("resolveMentionGating", () => {
|
||||
it("combines explicit, implicit, and bypass mentions", () => {
|
||||
@@ -65,3 +70,192 @@ describe("resolveMentionGatingWithBypass", () => {
|
||||
expect(res.shouldSkip).toBe(shouldSkip);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveInboundMentionDecision", () => {
|
||||
it("allows matching implicit mention kinds by default", () => {
|
||||
const res = resolveInboundMentionDecision({
|
||||
facts: {
|
||||
canDetectMention: true,
|
||||
wasMentioned: false,
|
||||
implicitMentionKinds: ["reply_to_bot"],
|
||||
},
|
||||
policy: {
|
||||
isGroup: true,
|
||||
requireMention: true,
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: false,
|
||||
commandAuthorized: false,
|
||||
},
|
||||
});
|
||||
expect(res.implicitMention).toBe(true);
|
||||
expect(res.matchedImplicitMentionKinds).toEqual(["reply_to_bot"]);
|
||||
expect(res.effectiveWasMentioned).toBe(true);
|
||||
expect(res.shouldSkip).toBe(false);
|
||||
});
|
||||
|
||||
it("filters implicit mention kinds through the allowlist", () => {
|
||||
const res = resolveInboundMentionDecision({
|
||||
facts: {
|
||||
canDetectMention: true,
|
||||
wasMentioned: false,
|
||||
implicitMentionKinds: ["reply_to_bot", "bot_thread_participant"],
|
||||
},
|
||||
policy: {
|
||||
isGroup: true,
|
||||
requireMention: true,
|
||||
allowedImplicitMentionKinds: ["reply_to_bot"],
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: false,
|
||||
commandAuthorized: false,
|
||||
},
|
||||
});
|
||||
expect(res.implicitMention).toBe(true);
|
||||
expect(res.matchedImplicitMentionKinds).toEqual(["reply_to_bot"]);
|
||||
expect(res.shouldSkip).toBe(false);
|
||||
});
|
||||
|
||||
it("blocks implicit mention kinds excluded by policy", () => {
|
||||
const res = resolveInboundMentionDecision({
|
||||
facts: {
|
||||
canDetectMention: true,
|
||||
wasMentioned: false,
|
||||
implicitMentionKinds: ["reply_to_bot"],
|
||||
},
|
||||
policy: {
|
||||
isGroup: true,
|
||||
requireMention: true,
|
||||
allowedImplicitMentionKinds: [],
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: false,
|
||||
commandAuthorized: false,
|
||||
},
|
||||
});
|
||||
expect(res.implicitMention).toBe(false);
|
||||
expect(res.matchedImplicitMentionKinds).toEqual([]);
|
||||
expect(res.effectiveWasMentioned).toBe(false);
|
||||
expect(res.shouldSkip).toBe(true);
|
||||
});
|
||||
|
||||
it("dedupes repeated implicit mention kinds", () => {
|
||||
const res = resolveInboundMentionDecision({
|
||||
facts: {
|
||||
canDetectMention: true,
|
||||
wasMentioned: false,
|
||||
implicitMentionKinds: ["reply_to_bot", "reply_to_bot", "native"],
|
||||
},
|
||||
policy: {
|
||||
isGroup: true,
|
||||
requireMention: true,
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: false,
|
||||
commandAuthorized: false,
|
||||
},
|
||||
});
|
||||
expect(res.matchedImplicitMentionKinds).toEqual(["reply_to_bot", "native"]);
|
||||
});
|
||||
|
||||
it("keeps command bypass behavior unchanged", () => {
|
||||
const res = resolveInboundMentionDecision({
|
||||
facts: {
|
||||
canDetectMention: true,
|
||||
wasMentioned: false,
|
||||
hasAnyMention: false,
|
||||
implicitMentionKinds: [],
|
||||
},
|
||||
policy: {
|
||||
isGroup: true,
|
||||
requireMention: true,
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: true,
|
||||
commandAuthorized: true,
|
||||
},
|
||||
});
|
||||
expect(res.shouldBypassMention).toBe(true);
|
||||
expect(res.effectiveWasMentioned).toBe(true);
|
||||
expect(res.shouldSkip).toBe(false);
|
||||
});
|
||||
|
||||
it("does not allow command bypass when some other mention is present", () => {
|
||||
const res = resolveInboundMentionDecision({
|
||||
facts: {
|
||||
canDetectMention: true,
|
||||
wasMentioned: false,
|
||||
hasAnyMention: true,
|
||||
implicitMentionKinds: [],
|
||||
},
|
||||
policy: {
|
||||
isGroup: true,
|
||||
requireMention: true,
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: true,
|
||||
commandAuthorized: true,
|
||||
},
|
||||
});
|
||||
expect(res.shouldBypassMention).toBe(false);
|
||||
expect(res.effectiveWasMentioned).toBe(false);
|
||||
expect(res.shouldSkip).toBe(true);
|
||||
});
|
||||
|
||||
it("does not allow command bypass outside groups", () => {
|
||||
const res = resolveInboundMentionDecision({
|
||||
facts: {
|
||||
canDetectMention: true,
|
||||
wasMentioned: false,
|
||||
hasAnyMention: false,
|
||||
implicitMentionKinds: [],
|
||||
},
|
||||
policy: {
|
||||
isGroup: false,
|
||||
requireMention: true,
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: true,
|
||||
commandAuthorized: true,
|
||||
},
|
||||
});
|
||||
expect(res.shouldBypassMention).toBe(false);
|
||||
expect(res.effectiveWasMentioned).toBe(false);
|
||||
expect(res.shouldSkip).toBe(true);
|
||||
});
|
||||
|
||||
it("does not skip when mention detection is unavailable", () => {
|
||||
const res = resolveInboundMentionDecision({
|
||||
facts: {
|
||||
canDetectMention: false,
|
||||
wasMentioned: false,
|
||||
implicitMentionKinds: [],
|
||||
},
|
||||
policy: {
|
||||
isGroup: true,
|
||||
requireMention: true,
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: false,
|
||||
commandAuthorized: false,
|
||||
},
|
||||
});
|
||||
expect(res.shouldSkip).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps the flat call shape for compatibility", () => {
|
||||
const res = resolveInboundMentionDecision({
|
||||
isGroup: true,
|
||||
requireMention: true,
|
||||
canDetectMention: true,
|
||||
wasMentioned: false,
|
||||
implicitMentionKinds: ["reply_to_bot"],
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: false,
|
||||
commandAuthorized: false,
|
||||
});
|
||||
expect(res.effectiveWasMentioned).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("implicitMentionKindWhen", () => {
|
||||
it("returns a one-item list when enabled", () => {
|
||||
expect(implicitMentionKindWhen("reply_to_bot", true)).toEqual(["reply_to_bot"]);
|
||||
});
|
||||
|
||||
it("returns an empty list when disabled", () => {
|
||||
expect(implicitMentionKindWhen("reply_to_bot", false)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** @deprecated Prefer `resolveInboundMentionDecision({ facts, policy })`. */
|
||||
export type MentionGateParams = {
|
||||
requireMention: boolean;
|
||||
canDetectMention: boolean;
|
||||
@@ -6,11 +7,13 @@ export type MentionGateParams = {
|
||||
shouldBypassMention?: boolean;
|
||||
};
|
||||
|
||||
/** @deprecated Prefer `InboundMentionDecision`. */
|
||||
export type MentionGateResult = {
|
||||
effectiveWasMentioned: boolean;
|
||||
shouldSkip: boolean;
|
||||
};
|
||||
|
||||
/** @deprecated Prefer `resolveInboundMentionDecision({ facts, policy })`. */
|
||||
export type MentionGateWithBypassParams = {
|
||||
isGroup: boolean;
|
||||
requireMention: boolean;
|
||||
@@ -23,37 +26,207 @@ export type MentionGateWithBypassParams = {
|
||||
commandAuthorized: boolean;
|
||||
};
|
||||
|
||||
/** @deprecated Prefer `InboundMentionDecision`. */
|
||||
export type MentionGateWithBypassResult = MentionGateResult & {
|
||||
shouldBypassMention: boolean;
|
||||
};
|
||||
|
||||
export function resolveMentionGating(params: MentionGateParams): MentionGateResult {
|
||||
const implicit = params.implicitMention === true;
|
||||
const bypass = params.shouldBypassMention === true;
|
||||
const effectiveWasMentioned = params.wasMentioned || implicit || bypass;
|
||||
const shouldSkip = params.requireMention && params.canDetectMention && !effectiveWasMentioned;
|
||||
return { effectiveWasMentioned, shouldSkip };
|
||||
export type InboundImplicitMentionKind =
|
||||
| "reply_to_bot"
|
||||
| "quoted_bot"
|
||||
| "bot_thread_participant"
|
||||
| "native";
|
||||
|
||||
export type InboundMentionFacts = {
|
||||
canDetectMention: boolean;
|
||||
wasMentioned: boolean;
|
||||
hasAnyMention?: boolean;
|
||||
implicitMentionKinds?: readonly InboundImplicitMentionKind[];
|
||||
};
|
||||
|
||||
export type InboundMentionPolicy = {
|
||||
isGroup: boolean;
|
||||
requireMention: boolean;
|
||||
allowedImplicitMentionKinds?: readonly InboundImplicitMentionKind[];
|
||||
allowTextCommands: boolean;
|
||||
hasControlCommand: boolean;
|
||||
commandAuthorized: boolean;
|
||||
};
|
||||
|
||||
/** @deprecated Prefer the nested `{ facts, policy }` call shape for new code. */
|
||||
export type ResolveInboundMentionDecisionFlatParams = InboundMentionFacts & InboundMentionPolicy;
|
||||
|
||||
export type ResolveInboundMentionDecisionNestedParams = {
|
||||
facts: InboundMentionFacts;
|
||||
policy: InboundMentionPolicy;
|
||||
};
|
||||
|
||||
export type ResolveInboundMentionDecisionParams =
|
||||
| ResolveInboundMentionDecisionFlatParams
|
||||
| ResolveInboundMentionDecisionNestedParams;
|
||||
|
||||
export type InboundMentionDecision = MentionGateResult & {
|
||||
implicitMention: boolean;
|
||||
matchedImplicitMentionKinds: InboundImplicitMentionKind[];
|
||||
shouldBypassMention: boolean;
|
||||
};
|
||||
|
||||
export function implicitMentionKindWhen(
|
||||
kind: InboundImplicitMentionKind,
|
||||
enabled: boolean,
|
||||
): InboundImplicitMentionKind[] {
|
||||
return enabled ? [kind] : [];
|
||||
}
|
||||
|
||||
function resolveMatchedImplicitMentionKinds(params: {
|
||||
implicitMentionKinds?: readonly InboundImplicitMentionKind[];
|
||||
allowedImplicitMentionKinds?: readonly InboundImplicitMentionKind[];
|
||||
}): InboundImplicitMentionKind[] {
|
||||
const inputKinds = params.implicitMentionKinds ?? [];
|
||||
if (inputKinds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const allowedKinds = params.allowedImplicitMentionKinds
|
||||
? new Set(params.allowedImplicitMentionKinds)
|
||||
: null;
|
||||
const matched: InboundImplicitMentionKind[] = [];
|
||||
for (const kind of inputKinds) {
|
||||
if (allowedKinds && !allowedKinds.has(kind)) {
|
||||
continue;
|
||||
}
|
||||
if (!matched.includes(kind)) {
|
||||
matched.push(kind);
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
function resolveMentionDecisionCore(params: {
|
||||
requireMention: boolean;
|
||||
canDetectMention: boolean;
|
||||
wasMentioned: boolean;
|
||||
implicitMentionKinds?: readonly InboundImplicitMentionKind[];
|
||||
allowedImplicitMentionKinds?: readonly InboundImplicitMentionKind[];
|
||||
shouldBypassMention: boolean;
|
||||
}): InboundMentionDecision {
|
||||
const matchedImplicitMentionKinds = resolveMatchedImplicitMentionKinds({
|
||||
implicitMentionKinds: params.implicitMentionKinds,
|
||||
allowedImplicitMentionKinds: params.allowedImplicitMentionKinds,
|
||||
});
|
||||
const implicitMention = matchedImplicitMentionKinds.length > 0;
|
||||
const effectiveWasMentioned =
|
||||
params.wasMentioned || implicitMention || params.shouldBypassMention;
|
||||
const shouldSkip = params.requireMention && params.canDetectMention && !effectiveWasMentioned;
|
||||
return {
|
||||
implicitMention,
|
||||
matchedImplicitMentionKinds,
|
||||
effectiveWasMentioned,
|
||||
shouldBypassMention: params.shouldBypassMention,
|
||||
shouldSkip,
|
||||
};
|
||||
}
|
||||
|
||||
function hasNestedMentionDecisionParams(
|
||||
params: ResolveInboundMentionDecisionParams,
|
||||
): params is ResolveInboundMentionDecisionNestedParams {
|
||||
return "facts" in params && "policy" in params;
|
||||
}
|
||||
|
||||
function normalizeMentionDecisionParams(
|
||||
params: ResolveInboundMentionDecisionParams,
|
||||
): ResolveInboundMentionDecisionNestedParams {
|
||||
if (hasNestedMentionDecisionParams(params)) {
|
||||
return params;
|
||||
}
|
||||
const {
|
||||
canDetectMention,
|
||||
wasMentioned,
|
||||
hasAnyMention,
|
||||
implicitMentionKinds,
|
||||
isGroup,
|
||||
requireMention,
|
||||
allowedImplicitMentionKinds,
|
||||
allowTextCommands,
|
||||
hasControlCommand,
|
||||
commandAuthorized,
|
||||
} = params;
|
||||
return {
|
||||
facts: {
|
||||
canDetectMention,
|
||||
wasMentioned,
|
||||
hasAnyMention,
|
||||
implicitMentionKinds,
|
||||
},
|
||||
policy: {
|
||||
isGroup,
|
||||
requireMention,
|
||||
allowedImplicitMentionKinds,
|
||||
allowTextCommands,
|
||||
hasControlCommand,
|
||||
commandAuthorized,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveInboundMentionDecision(
|
||||
params: ResolveInboundMentionDecisionParams,
|
||||
): InboundMentionDecision {
|
||||
const { facts, policy } = normalizeMentionDecisionParams(params);
|
||||
const shouldBypassMention =
|
||||
policy.isGroup &&
|
||||
policy.requireMention &&
|
||||
!facts.wasMentioned &&
|
||||
!(facts.hasAnyMention ?? false) &&
|
||||
policy.allowTextCommands &&
|
||||
policy.commandAuthorized &&
|
||||
policy.hasControlCommand;
|
||||
return resolveMentionDecisionCore({
|
||||
requireMention: policy.requireMention,
|
||||
canDetectMention: facts.canDetectMention,
|
||||
wasMentioned: facts.wasMentioned,
|
||||
implicitMentionKinds: facts.implicitMentionKinds,
|
||||
allowedImplicitMentionKinds: policy.allowedImplicitMentionKinds,
|
||||
shouldBypassMention,
|
||||
});
|
||||
}
|
||||
|
||||
/** @deprecated Prefer `resolveInboundMentionDecision({ facts, policy })`. */
|
||||
export function resolveMentionGating(params: MentionGateParams): MentionGateResult {
|
||||
const result = resolveMentionDecisionCore({
|
||||
requireMention: params.requireMention,
|
||||
canDetectMention: params.canDetectMention,
|
||||
wasMentioned: params.wasMentioned,
|
||||
implicitMentionKinds: implicitMentionKindWhen("native", params.implicitMention === true),
|
||||
shouldBypassMention: params.shouldBypassMention === true,
|
||||
});
|
||||
return {
|
||||
effectiveWasMentioned: result.effectiveWasMentioned,
|
||||
shouldSkip: result.shouldSkip,
|
||||
};
|
||||
}
|
||||
|
||||
/** @deprecated Prefer `resolveInboundMentionDecision({ facts, policy })`. */
|
||||
export function resolveMentionGatingWithBypass(
|
||||
params: MentionGateWithBypassParams,
|
||||
): MentionGateWithBypassResult {
|
||||
const shouldBypassMention =
|
||||
params.isGroup &&
|
||||
params.requireMention &&
|
||||
!params.wasMentioned &&
|
||||
!(params.hasAnyMention ?? false) &&
|
||||
params.allowTextCommands &&
|
||||
params.commandAuthorized &&
|
||||
params.hasControlCommand;
|
||||
return {
|
||||
...resolveMentionGating({
|
||||
requireMention: params.requireMention,
|
||||
const result = resolveInboundMentionDecision({
|
||||
facts: {
|
||||
canDetectMention: params.canDetectMention,
|
||||
wasMentioned: params.wasMentioned,
|
||||
implicitMention: params.implicitMention,
|
||||
shouldBypassMention,
|
||||
}),
|
||||
shouldBypassMention,
|
||||
hasAnyMention: params.hasAnyMention,
|
||||
implicitMentionKinds: implicitMentionKindWhen("native", params.implicitMention === true),
|
||||
},
|
||||
policy: {
|
||||
isGroup: params.isGroup,
|
||||
requireMention: params.requireMention,
|
||||
allowTextCommands: params.allowTextCommands,
|
||||
hasControlCommand: params.hasControlCommand,
|
||||
commandAuthorized: params.commandAuthorized,
|
||||
},
|
||||
});
|
||||
return {
|
||||
effectiveWasMentioned: result.effectiveWasMentioned,
|
||||
shouldSkip: result.shouldSkip,
|
||||
shouldBypassMention: result.shouldBypassMention,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,13 +26,24 @@ export {
|
||||
shouldDebounceTextInbound,
|
||||
} from "../channels/inbound-debounce-policy.js";
|
||||
export type {
|
||||
InboundMentionFacts,
|
||||
InboundMentionPolicy,
|
||||
InboundImplicitMentionKind,
|
||||
InboundMentionDecision,
|
||||
MentionGateParams,
|
||||
MentionGateResult,
|
||||
MentionGateWithBypassParams,
|
||||
MentionGateWithBypassResult,
|
||||
ResolveInboundMentionDecisionFlatParams,
|
||||
ResolveInboundMentionDecisionNestedParams,
|
||||
ResolveInboundMentionDecisionParams,
|
||||
} from "../channels/mention-gating.js";
|
||||
export {
|
||||
implicitMentionKindWhen,
|
||||
resolveInboundMentionDecision,
|
||||
// @deprecated Prefer `resolveInboundMentionDecision({ facts, policy })`.
|
||||
resolveMentionGating,
|
||||
// @deprecated Prefer `resolveInboundMentionDecision({ facts, policy })`.
|
||||
resolveMentionGatingWithBypass,
|
||||
} from "../channels/mention-gating.js";
|
||||
export type { NormalizedLocation } from "../channels/location.js";
|
||||
|
||||
@@ -11,7 +11,11 @@ export {
|
||||
readReactionParams,
|
||||
readStringParam,
|
||||
} from "../agents/tools/common.js";
|
||||
export { resolveMentionGatingWithBypass } from "../channels/mention-gating.js";
|
||||
export {
|
||||
resolveMentionGating,
|
||||
resolveMentionGatingWithBypass,
|
||||
resolveInboundMentionDecision,
|
||||
} from "../channels/mention-gating.js";
|
||||
export {
|
||||
deleteAccountFromConfigSection,
|
||||
setAccountEnabledInConfigSection,
|
||||
|
||||
@@ -19,7 +19,11 @@ export {
|
||||
resolveDualTextControlCommandGate,
|
||||
} from "../channels/command-gating.js";
|
||||
export { logInboundDrop, logTypingFailure } from "../channels/logging.js";
|
||||
export { resolveMentionGating } from "../channels/mention-gating.js";
|
||||
export {
|
||||
resolveInboundMentionDecision,
|
||||
resolveMentionGating,
|
||||
resolveMentionGatingWithBypass,
|
||||
} from "../channels/mention-gating.js";
|
||||
export type { AllowlistMatch } from "../channels/plugins/allowlist-match.js";
|
||||
export {
|
||||
formatAllowlistMatchMeta,
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
|
||||
export { logInboundDrop } from "../channels/logging.js";
|
||||
export { createAuthRateLimiter } from "../gateway/auth-rate-limit.js";
|
||||
export { resolveMentionGatingWithBypass } from "../channels/mention-gating.js";
|
||||
export {
|
||||
resolveMentionGating,
|
||||
resolveMentionGatingWithBypass,
|
||||
resolveInboundMentionDecision,
|
||||
} from "../channels/mention-gating.js";
|
||||
export type { AllowlistMatch } from "../channels/plugins/allowlist-match.js";
|
||||
export {
|
||||
buildChannelKeyCandidates,
|
||||
|
||||
@@ -5,7 +5,11 @@ import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||
|
||||
export type { ReplyPayload } from "../auto-reply/types.js";
|
||||
export { mergeAllowlist, summarizeMapping } from "../channels/allowlists/resolve-utils.js";
|
||||
export { resolveMentionGatingWithBypass } from "../channels/mention-gating.js";
|
||||
export {
|
||||
resolveMentionGating,
|
||||
resolveMentionGatingWithBypass,
|
||||
resolveInboundMentionDecision,
|
||||
} from "../channels/mention-gating.js";
|
||||
export {
|
||||
deleteAccountFromConfigSection,
|
||||
setAccountEnabledInConfigSection,
|
||||
|
||||
@@ -82,7 +82,7 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";',
|
||||
'export { GoogleChatConfigSchema, type GoogleChatAccountConfig, type GoogleChatConfig } from "openclaw/plugin-sdk/googlechat-runtime-shared";',
|
||||
'export { extractToolSend } from "openclaw/plugin-sdk/tool-send";',
|
||||
'export { resolveMentionGatingWithBypass } from "openclaw/plugin-sdk/channel-inbound";',
|
||||
'export { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound";',
|
||||
'export { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";',
|
||||
'export { resolveWebhookPath } from "openclaw/plugin-sdk/webhook-path";',
|
||||
'export { registerWebhookTargetWithPluginRoute, resolveWebhookTargetWithAuthOrReject, withResolvedWebhookRequestPipeline } from "openclaw/plugin-sdk/webhook-targets";',
|
||||
|
||||
@@ -290,6 +290,13 @@ describe("plugin-sdk subpath exports", () => {
|
||||
]) {
|
||||
expectSourceMentions(subpath, ["chunkTextForOutbound"]);
|
||||
}
|
||||
for (const subpath of ["googlechat", "msteams", "nextcloud-talk", "zalouser"]) {
|
||||
expectSourceMentions(subpath, [
|
||||
"resolveInboundMentionDecision",
|
||||
"resolveMentionGating",
|
||||
"resolveMentionGatingWithBypass",
|
||||
]);
|
||||
}
|
||||
expectSourceMentions("approval-auth-runtime", [
|
||||
"createResolvedApproverActionAuthAdapter",
|
||||
"resolveApprovalApprovers",
|
||||
@@ -453,6 +460,7 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"recordInboundSession",
|
||||
"recordInboundSessionMetaSafe",
|
||||
"resolveInboundSessionEnvelopeContext",
|
||||
"resolveInboundMentionDecision",
|
||||
"resolveMentionGating",
|
||||
"resolveMentionGatingWithBypass",
|
||||
"resolveOutboundSendDep",
|
||||
@@ -536,9 +544,11 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"formatInboundEnvelope",
|
||||
"formatInboundFromLabel",
|
||||
"formatLocationText",
|
||||
"implicitMentionKindWhen",
|
||||
"logInboundDrop",
|
||||
"matchesMentionPatterns",
|
||||
"matchesMentionWithExplicit",
|
||||
"resolveInboundMentionDecision",
|
||||
"normalizeMentionText",
|
||||
"resolveInboundDebounceMs",
|
||||
"resolveEnvelopeFormatOptions",
|
||||
|
||||
@@ -35,6 +35,10 @@ import { dispatchReplyWithBufferedBlockDispatcher } from "../../auto-reply/reply
|
||||
import { createReplyDispatcherWithTyping } from "../../auto-reply/reply/reply-dispatcher.js";
|
||||
import { removeAckReactionAfterReply, shouldAckReaction } from "../../channels/ack-reactions.js";
|
||||
import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
|
||||
import {
|
||||
implicitMentionKindWhen,
|
||||
resolveInboundMentionDecision,
|
||||
} from "../../channels/mention-gating.js";
|
||||
import {
|
||||
setChannelConversationBindingIdleTimeoutBySessionKey,
|
||||
setChannelConversationBindingMaxAgeBySessionKey,
|
||||
@@ -128,6 +132,8 @@ export function createRuntimeChannel(): PluginRuntime["channel"] {
|
||||
buildMentionRegexes,
|
||||
matchesMentionPatterns,
|
||||
matchesMentionWithExplicit,
|
||||
implicitMentionKindWhen,
|
||||
resolveInboundMentionDecision,
|
||||
},
|
||||
reactions: {
|
||||
shouldAckReaction,
|
||||
|
||||
@@ -83,6 +83,8 @@ export type PluginRuntimeChannel = {
|
||||
buildMentionRegexes: typeof import("../../auto-reply/reply/mentions.js").buildMentionRegexes;
|
||||
matchesMentionPatterns: typeof import("../../auto-reply/reply/mentions.js").matchesMentionPatterns;
|
||||
matchesMentionWithExplicit: typeof import("../../auto-reply/reply/mentions.js").matchesMentionWithExplicit;
|
||||
implicitMentionKindWhen: typeof import("../../channels/mention-gating.js").implicitMentionKindWhen;
|
||||
resolveInboundMentionDecision: typeof import("../../channels/mention-gating.js").resolveInboundMentionDecision;
|
||||
};
|
||||
reactions: {
|
||||
shouldAckReaction: typeof import("../../channels/ack-reactions.js").shouldAckReaction;
|
||||
|
||||
Reference in New Issue
Block a user