refactor: prune room legacy

This commit is contained in:
Peter Steinberger
2026-01-17 07:41:01 +00:00
parent 6d969fe58e
commit d5fdda8e28
15 changed files with 43 additions and 34 deletions

View File

@@ -16,14 +16,14 @@ export function resolveMatrixGroupRequireMention(params: ChannelGroupContext): b
if (roomId.toLowerCase().startsWith("room:")) {
roomId = roomId.slice("room:".length).trim();
}
const groupRoom = params.groupRoom?.trim() ?? "";
const aliases = groupRoom ? [groupRoom] : [];
const groupChannel = params.groupChannel?.trim() ?? "";
const aliases = groupChannel ? [groupChannel] : [];
const cfg = params.cfg as CoreConfig;
const resolved = resolveMatrixRoomConfig({
rooms: cfg.channels?.matrix?.rooms,
roomId,
aliases,
name: groupRoom || undefined,
name: groupChannel || undefined,
}).config;
if (resolved) {
if (resolved.autoReply === true) return false;

View File

@@ -379,7 +379,7 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
SenderId: senderId,
SenderUsername: senderId.split(":")[0]?.replace(/^@/, ""),
GroupSubject: isRoom ? (roomName ?? roomId) : undefined,
GroupRoom: isRoom ? (room.getCanonicalAlias?.() ?? roomId) : undefined,
GroupChannel: isRoom ? (room.getCanonicalAlias?.() ?? roomId) : undefined,
GroupSystemPrompt: isRoom ? groupSystemPrompt : undefined,
Provider: "matrix" as const,
Surface: "matrix" as const,

View File

@@ -23,7 +23,7 @@ describe("resolveGroupRequireMention", () => {
const ctx: TemplateContext = {
Provider: "discord",
From: "group:123",
GroupRoom: "#general",
GroupChannel: "#general",
GroupSpace: "145",
};
const groupResolution: GroupKeyResolution = {

View File

@@ -16,12 +16,12 @@ export function resolveGroupRequireMention(params: {
const channel = normalizeChannelId(rawChannel);
if (!channel) return true;
const groupId = groupResolution?.id ?? ctx.From?.replace(/^group:/, "");
const groupRoom = ctx.GroupRoom?.trim() ?? ctx.GroupSubject?.trim();
const groupChannel = ctx.GroupChannel?.trim() ?? ctx.GroupSubject?.trim();
const groupSpace = ctx.GroupSpace?.trim();
const requireMention = getChannelDock(channel)?.groups?.resolveRequireMention?.({
cfg,
groupId,
groupRoom,
groupChannel,
groupSpace,
accountId: ctx.AccountId,
});
@@ -62,13 +62,13 @@ export function buildGroupIntro(params: {
? "Activation: always-on (you receive every group message)."
: "Activation: trigger-only (you are invoked only when explicitly mentioned; recent context may be included).";
const groupId = params.sessionCtx.From?.replace(/^group:/, "");
const groupRoom = params.sessionCtx.GroupRoom?.trim() ?? subject;
const groupChannel = params.sessionCtx.GroupChannel?.trim() ?? subject;
const groupSpace = params.sessionCtx.GroupSpace?.trim();
const providerIdsLine = providerId
? getChannelDock(providerId)?.groups?.resolveGroupIntroHint?.({
cfg: params.cfg,
groupId,
groupRoom,
groupChannel,
groupSpace,
accountId: params.sessionCtx.AccountId,
})

View File

@@ -242,14 +242,19 @@ export async function initSessionState(params: {
const channel = groupResolution.channel;
const subject = ctx.GroupSubject?.trim();
const space = ctx.GroupSpace?.trim();
const explicitRoom = ctx.GroupRoom?.trim();
const explicitChannel = ctx.GroupChannel?.trim();
const normalizedChannel = normalizeChannelId(channel);
const isRoomProvider = Boolean(
const isChannelProvider = Boolean(
normalizedChannel &&
getChannelDock(normalizedChannel)?.capabilities.chatTypes.includes("channel"),
);
const nextRoom =
explicitRoom ?? (isRoomProvider && subject && subject.startsWith("#") ? subject : undefined);
explicitChannel ??
((groupResolution.chatType === "channel" || isChannelProvider) &&
subject &&
subject.startsWith("#")
? subject
: undefined);
const nextSubject = nextRoom ? undefined : subject;
sessionEntry.chatType = groupResolution.chatType ?? "group";
sessionEntry.channel = channel;

View File

@@ -63,7 +63,8 @@ export type MsgContext = {
/** Human label for envelope headers (conversation label, not sender). */
ConversationLabel?: string;
GroupSubject?: string;
GroupRoom?: string;
/** Human label for channel-like group conversations (e.g. #general, #support). */
GroupChannel?: string;
GroupSpace?: string;
GroupMembers?: string;
GroupSystemPrompt?: string;

View File

@@ -27,7 +27,7 @@ export function resolveConversationLabel(ctx: MsgContext): string | undefined {
}
const base =
ctx.GroupRoom?.trim() ||
ctx.GroupChannel?.trim() ||
ctx.GroupSubject?.trim() ||
ctx.GroupSpace?.trim() ||
ctx.From?.trim() ||

View File

@@ -6,7 +6,7 @@ import { resolveSlackAccount } from "../../slack/accounts.js";
type GroupMentionParams = {
cfg: ClawdbotConfig;
groupId?: string | null;
groupRoom?: string | null;
groupChannel?: string | null;
groupSpace?: string | null;
accountId?: string | null;
};
@@ -133,13 +133,14 @@ export function resolveDiscordGroupRequireMention(params: GroupMentionParams): b
);
const channelEntries = guildEntry?.channels;
if (channelEntries && Object.keys(channelEntries).length > 0) {
const channelSlug = normalizeDiscordSlug(params.groupRoom);
const groupChannel = params.groupChannel;
const channelSlug = normalizeDiscordSlug(groupChannel);
const entry =
(params.groupId ? channelEntries[params.groupId] : undefined) ??
(channelSlug
? (channelEntries[channelSlug] ?? channelEntries[`#${channelSlug}`])
: undefined) ??
(params.groupRoom ? channelEntries[normalizeDiscordSlug(params.groupRoom)] : undefined);
(groupChannel ? channelEntries[normalizeDiscordSlug(groupChannel)] : undefined);
if (entry && typeof entry.requireMention === "boolean") {
return entry.requireMention;
}
@@ -159,7 +160,8 @@ export function resolveSlackGroupRequireMention(params: GroupMentionParams): boo
const keys = Object.keys(channels);
if (keys.length === 0) return true;
const channelId = params.groupId?.trim();
const channelName = params.groupRoom?.replace(/^#/, "");
const groupChannel = params.groupChannel;
const channelName = groupChannel?.replace(/^#/, "");
const normalizedName = normalizeSlackSlug(channelName);
const candidates = [
channelId ?? "",

View File

@@ -133,7 +133,8 @@ export type ChannelLogSink = {
export type ChannelGroupContext = {
cfg: ClawdbotConfig;
groupId?: string | null;
groupRoom?: string | null;
/** Human label for channel-like group conversations (e.g. #general). */
groupChannel?: string | null;
groupSpace?: string | null;
accountId?: string | null;
};

View File

@@ -124,8 +124,8 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
senderDisplay && senderTag && senderDisplay !== senderTag
? `${senderDisplay} (${senderTag})`
: (senderDisplay ?? senderTag ?? author.id);
const groupRoom = isGuildMessage && displayChannelSlug ? `#${displayChannelSlug}` : undefined;
const groupSubject = isDirectMessage ? undefined : groupRoom;
const groupChannel = isGuildMessage && displayChannelSlug ? `#${displayChannelSlug}` : undefined;
const groupSubject = isDirectMessage ? undefined : groupChannel;
const channelDescription = channelInfo?.topic?.trim();
const systemPromptParts = [
channelDescription ? `Channel topic: ${channelDescription}` : null,
@@ -245,7 +245,7 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
SenderUsername: author.username,
SenderTag: formatDiscordUserTag(author),
GroupSubject: groupSubject,
GroupRoom: groupRoom,
GroupChannel: groupChannel,
GroupSystemPrompt: isGuildMessage ? groupSystemPrompt : undefined,
GroupSpace: isGuildMessage ? (guildInfo?.id ?? guildSlug) || undefined : undefined,
Provider: "discord" as const,

View File

@@ -2,14 +2,14 @@ import { describe, expect, it } from "vitest";
import {
buildSlackSlashCommandMatcher,
isSlackRoomAllowedByPolicy,
isSlackChannelAllowedByPolicy,
resolveSlackThreadTs,
} from "./monitor.js";
describe("slack groupPolicy gating", () => {
it("allows when policy is open", () => {
expect(
isSlackRoomAllowedByPolicy({
isSlackChannelAllowedByPolicy({
groupPolicy: "open",
channelAllowlistConfigured: false,
channelAllowed: false,
@@ -19,7 +19,7 @@ describe("slack groupPolicy gating", () => {
it("blocks when policy is disabled", () => {
expect(
isSlackRoomAllowedByPolicy({
isSlackChannelAllowedByPolicy({
groupPolicy: "disabled",
channelAllowlistConfigured: true,
channelAllowed: true,
@@ -29,7 +29,7 @@ describe("slack groupPolicy gating", () => {
it("blocks allowlist when no channel allowlist configured", () => {
expect(
isSlackRoomAllowedByPolicy({
isSlackChannelAllowedByPolicy({
groupPolicy: "allowlist",
channelAllowlistConfigured: false,
channelAllowed: true,
@@ -39,7 +39,7 @@ describe("slack groupPolicy gating", () => {
it("allows allowlist when channel is allowed", () => {
expect(
isSlackRoomAllowedByPolicy({
isSlackChannelAllowedByPolicy({
groupPolicy: "allowlist",
channelAllowlistConfigured: true,
channelAllowed: true,
@@ -49,7 +49,7 @@ describe("slack groupPolicy gating", () => {
it("blocks allowlist when channel is not allowed", () => {
expect(
isSlackRoomAllowedByPolicy({
isSlackChannelAllowedByPolicy({
groupPolicy: "allowlist",
channelAllowlistConfigured: true,
channelAllowed: false,

View File

@@ -1,5 +1,5 @@
export { buildSlackSlashCommandMatcher } from "./monitor/commands.js";
export { isSlackRoomAllowedByPolicy } from "./monitor/policy.js";
export { isSlackChannelAllowedByPolicy } from "./monitor/policy.js";
export { monitorSlackProvider } from "./monitor/provider.js";
export { resolveSlackThreadTs } from "./monitor/replies.js";
export type { MonitorSlackOpts } from "./monitor/types.js";

View File

@@ -11,7 +11,7 @@ import type { SlackMessageEvent } from "../types.js";
import { normalizeAllowList, normalizeAllowListLower, normalizeSlackSlug } from "./allow-list.js";
import { resolveSlackChannelConfig } from "./channel-config.js";
import { isSlackRoomAllowedByPolicy } from "./policy.js";
import { isSlackChannelAllowedByPolicy } from "./policy.js";
export function inferSlackChannelType(
channelId?: string | null,
@@ -314,7 +314,7 @@ export function createSlackMonitorContext(params: {
const channelAllowlistConfigured =
Boolean(params.channelsConfig) && Object.keys(params.channelsConfig ?? {}).length > 0;
if (
!isSlackRoomAllowedByPolicy({
!isSlackChannelAllowedByPolicy({
groupPolicy: params.groupPolicy,
channelAllowlistConfigured,
channelAllowed,

View File

@@ -1,4 +1,4 @@
export function isSlackRoomAllowedByPolicy(params: {
export function isSlackChannelAllowedByPolicy(params: {
groupPolicy: "open" | "disabled" | "allowlist";
channelAllowlistConfigured: boolean;
channelAllowed: boolean;

View File

@@ -33,7 +33,7 @@ import {
import { resolveSlackChannelConfig, type SlackChannelConfigResolved } from "./channel-config.js";
import { buildSlackSlashCommandMatcher, resolveSlackSlashCommandConfig } from "./commands.js";
import type { SlackMonitorContext } from "./context.js";
import { isSlackRoomAllowedByPolicy } from "./policy.js";
import { isSlackChannelAllowedByPolicy } from "./policy.js";
import { deliverSlackSlashReplies } from "./replies.js";
type SlackBlock = { type: string; [key: string]: unknown };
@@ -247,7 +247,7 @@ export function registerSlackMonitorSlashCommands(params: {
Boolean(ctx.channelsConfig) && Object.keys(ctx.channelsConfig ?? {}).length > 0;
const channelAllowed = channelConfig?.allowed !== false;
if (
!isSlackRoomAllowedByPolicy({
!isSlackChannelAllowedByPolicy({
groupPolicy: ctx.groupPolicy,
channelAllowlistConfigured,
channelAllowed,