refactor: align channel chatType
This commit is contained in:
@@ -41,7 +41,7 @@ export type HumanDelayConfig = {
|
|||||||
export type SessionSendPolicyAction = "allow" | "deny";
|
export type SessionSendPolicyAction = "allow" | "deny";
|
||||||
export type SessionSendPolicyMatch = {
|
export type SessionSendPolicyMatch = {
|
||||||
channel?: string;
|
channel?: string;
|
||||||
chatType?: "direct" | "group" | "room";
|
chatType?: "direct" | "group" | "channel" | "room";
|
||||||
keyPrefix?: string;
|
keyPrefix?: string;
|
||||||
};
|
};
|
||||||
export type SessionSendPolicyRule = {
|
export type SessionSendPolicyRule = {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { AgentElevatedAllowFromConfig, SessionSendPolicyAction } from "./ty
|
|||||||
|
|
||||||
export type MediaUnderstandingScopeMatch = {
|
export type MediaUnderstandingScopeMatch = {
|
||||||
channel?: string;
|
channel?: string;
|
||||||
chatType?: "direct" | "group" | "room";
|
chatType?: "direct" | "group" | "channel" | "room";
|
||||||
keyPrefix?: string;
|
keyPrefix?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -251,7 +251,12 @@ export const MediaUnderstandingScopeSchema = z
|
|||||||
.object({
|
.object({
|
||||||
channel: z.string().optional(),
|
channel: z.string().optional(),
|
||||||
chatType: z
|
chatType: z
|
||||||
.union([z.literal("direct"), z.literal("group"), z.literal("room")])
|
.union([
|
||||||
|
z.literal("direct"),
|
||||||
|
z.literal("group"),
|
||||||
|
z.literal("channel"),
|
||||||
|
z.literal("room"),
|
||||||
|
])
|
||||||
.optional(),
|
.optional(),
|
||||||
keyPrefix: z.string().optional(),
|
keyPrefix: z.string().optional(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,46 +1,27 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { resolveMediaUnderstandingScope } from "./scope.js";
|
|
||||||
|
|
||||||
describe("resolveMediaUnderstandingScope", () => {
|
import { normalizeMediaUnderstandingChatType, resolveMediaUnderstandingScope } from "./scope.js";
|
||||||
it("defaults to allow when scope is undefined", () => {
|
|
||||||
expect(resolveMediaUnderstandingScope({})).toBe("allow");
|
describe("media understanding scope", () => {
|
||||||
|
it("normalizes channel/room", () => {
|
||||||
|
expect(normalizeMediaUnderstandingChatType("channel")).toBe("channel");
|
||||||
|
expect(normalizeMediaUnderstandingChatType("room")).toBe("channel");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses first matching rule", () => {
|
it("treats room match as channel", () => {
|
||||||
const decision = resolveMediaUnderstandingScope({
|
const scope = {
|
||||||
scope: {
|
rules: [{ action: "deny", match: { chatType: "room" } }],
|
||||||
default: "deny",
|
} as const;
|
||||||
rules: [
|
|
||||||
{ action: "allow", match: { channel: "whatsapp" } },
|
expect(resolveMediaUnderstandingScope({ scope, chatType: "channel" })).toBe("deny");
|
||||||
{ action: "deny", match: { channel: "whatsapp", chatType: "direct" } },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
channel: "whatsapp",
|
|
||||||
chatType: "direct",
|
|
||||||
sessionKey: "whatsapp:direct:123",
|
|
||||||
});
|
|
||||||
expect(decision).toBe("allow");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("matches keyPrefix when provided", () => {
|
it("matches channel chatType explicitly", () => {
|
||||||
const decision = resolveMediaUnderstandingScope({
|
const scope = {
|
||||||
scope: {
|
rules: [{ action: "deny", match: { chatType: "channel" } }],
|
||||||
default: "deny",
|
} as const;
|
||||||
rules: [{ action: "allow", match: { keyPrefix: "agent:main:" } }],
|
|
||||||
},
|
|
||||||
sessionKey: "agent:main:whatsapp:group:123",
|
|
||||||
});
|
|
||||||
expect(decision).toBe("allow");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("matches keyPrefix case-insensitively", () => {
|
expect(resolveMediaUnderstandingScope({ scope, chatType: "channel" })).toBe("deny");
|
||||||
const decision = resolveMediaUnderstandingScope({
|
|
||||||
scope: {
|
|
||||||
default: "deny",
|
|
||||||
rules: [{ action: "allow", match: { keyPrefix: "agent:main:" } }],
|
|
||||||
},
|
|
||||||
sessionKey: "AGENT:MAIN:WHATSAPP:GROUP:123",
|
|
||||||
});
|
|
||||||
expect(decision).toBe("allow");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export function normalizeMediaUnderstandingChatType(raw?: string | null): string
|
|||||||
if (!value) return undefined;
|
if (!value) return undefined;
|
||||||
if (value === "dm" || value === "direct_message" || value === "private") return "direct";
|
if (value === "dm" || value === "direct_message" || value === "private") return "direct";
|
||||||
if (value === "groups") return "group";
|
if (value === "groups") return "group";
|
||||||
if (value === "channel") return "room";
|
if (value === "room") return "channel";
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ export function resolveMediaUnderstandingScope(params: {
|
|||||||
if (!scope) return "allow";
|
if (!scope) return "allow";
|
||||||
|
|
||||||
const channel = normalizeMatch(params.channel);
|
const channel = normalizeMatch(params.channel);
|
||||||
const chatType = normalizeMatch(params.chatType);
|
const chatType = normalizeMediaUnderstandingChatType(params.chatType) ?? normalizeMatch(params.chatType);
|
||||||
const sessionKey = normalizeMatch(params.sessionKey) ?? "";
|
const sessionKey = normalizeMatch(params.sessionKey) ?? "";
|
||||||
|
|
||||||
for (const rule of scope.rules ?? []) {
|
for (const rule of scope.rules ?? []) {
|
||||||
@@ -41,7 +41,8 @@ export function resolveMediaUnderstandingScope(params: {
|
|||||||
const action = normalizeDecision(rule.action) ?? "allow";
|
const action = normalizeDecision(rule.action) ?? "allow";
|
||||||
const match = rule.match ?? {};
|
const match = rule.match ?? {};
|
||||||
const matchChannel = normalizeMatch(match.channel);
|
const matchChannel = normalizeMatch(match.channel);
|
||||||
const matchChatType = normalizeMatch(match.chatType);
|
const matchChatType =
|
||||||
|
normalizeMediaUnderstandingChatType(match.chatType) ?? normalizeMatch(match.chatType);
|
||||||
const matchPrefix = normalizeMatch(match.keyPrefix);
|
const matchPrefix = normalizeMatch(match.keyPrefix);
|
||||||
|
|
||||||
if (matchChannel && matchChannel !== channel) continue;
|
if (matchChannel && matchChannel !== channel) continue;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { ClawdbotConfig } from "../config/config.js";
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
import type { SessionChatType, SessionEntry } from "../config/sessions.js";
|
import type { SessionChatType, SessionEntry } from "../config/sessions.js";
|
||||||
|
import { normalizeChatType } from "../channels/chat-type.js";
|
||||||
|
|
||||||
export type SessionSendPolicyDecision = "allow" | "deny";
|
export type SessionSendPolicyDecision = "allow" | "deny";
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ function deriveChannelFromKey(key?: string) {
|
|||||||
function deriveChatTypeFromKey(key?: string): SessionChatType | undefined {
|
function deriveChatTypeFromKey(key?: string): SessionChatType | undefined {
|
||||||
if (!key) return undefined;
|
if (!key) return undefined;
|
||||||
if (key.startsWith("group:") || key.includes(":group:")) return "group";
|
if (key.startsWith("group:") || key.includes(":group:")) return "group";
|
||||||
if (key.includes(":channel:")) return "room";
|
if (key.includes(":channel:")) return "channel";
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,8 +51,8 @@ export function resolveSendPolicy(params: {
|
|||||||
normalizeMatchValue(params.entry?.lastChannel) ??
|
normalizeMatchValue(params.entry?.lastChannel) ??
|
||||||
deriveChannelFromKey(params.sessionKey);
|
deriveChannelFromKey(params.sessionKey);
|
||||||
const chatType =
|
const chatType =
|
||||||
normalizeMatchValue(params.chatType ?? params.entry?.chatType) ??
|
normalizeChatType(params.chatType ?? params.entry?.chatType) ??
|
||||||
normalizeMatchValue(deriveChatTypeFromKey(params.sessionKey));
|
normalizeChatType(deriveChatTypeFromKey(params.sessionKey));
|
||||||
const sessionKey = params.sessionKey ?? "";
|
const sessionKey = params.sessionKey ?? "";
|
||||||
|
|
||||||
let allowedMatch = false;
|
let allowedMatch = false;
|
||||||
@@ -60,7 +61,7 @@ export function resolveSendPolicy(params: {
|
|||||||
const action = normalizeSendPolicy(rule.action) ?? "allow";
|
const action = normalizeSendPolicy(rule.action) ?? "allow";
|
||||||
const match = rule.match ?? {};
|
const match = rule.match ?? {};
|
||||||
const matchChannel = normalizeMatchValue(match.channel);
|
const matchChannel = normalizeMatchValue(match.channel);
|
||||||
const matchChatType = normalizeMatchValue(match.chatType);
|
const matchChatType = normalizeChatType(match.chatType);
|
||||||
const matchPrefix = normalizeMatchValue(match.keyPrefix);
|
const matchPrefix = normalizeMatchValue(match.keyPrefix);
|
||||||
|
|
||||||
if (matchChannel && matchChannel !== channel) continue;
|
if (matchChannel && matchChannel !== channel) continue;
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export function createSlackMonitorContext(params: {
|
|||||||
: isGroup
|
: isGroup
|
||||||
? `slack:group:${channelId}`
|
? `slack:group:${channelId}`
|
||||||
: `slack:channel:${channelId}`;
|
: `slack:channel:${channelId}`;
|
||||||
const chatType = isDirectMessage ? "direct" : isGroup ? "group" : "room";
|
const chatType = isDirectMessage ? "direct" : isGroup ? "group" : "channel";
|
||||||
return resolveSessionKey(
|
return resolveSessionKey(
|
||||||
params.sessionScope,
|
params.sessionScope,
|
||||||
{ From: from, ChatType: chatType, Provider: "slack" },
|
{ From: from, ChatType: chatType, Provider: "slack" },
|
||||||
|
|||||||
Reference in New Issue
Block a user