From d1241cf6b7e9f70c624c53a4f13d8fe547c362f9 Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Tue, 27 Jan 2026 22:32:28 +0300 Subject: [PATCH] fix: add missing type extensions for engagement mode --- src/auto-reply/group-activation.ts | 3 +- src/auto-reply/reply/commands-status.ts | 2 +- src/auto-reply/reply/commands-types.ts | 2 +- src/auto-reply/reply/groups.ts | 6 ++-- src/auto-reply/status.ts | 2 +- src/config/group-policy.ts | 28 +++++++++++++++++++ src/config/sessions/types.ts | 4 ++- .../auto-reply/monitor/group-activation.ts | 27 ++++++++++++++++-- 8 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/auto-reply/group-activation.ts b/src/auto-reply/group-activation.ts index 7dcd2e696..3ccf1299c 100644 --- a/src/auto-reply/group-activation.ts +++ b/src/auto-reply/group-activation.ts @@ -1,11 +1,12 @@ import { normalizeCommandBody } from "./commands-registry.js"; -export type GroupActivationMode = "mention" | "always"; +export type GroupActivationMode = "mention" | "always" | "engagement"; export function normalizeGroupActivation(raw?: string | null): GroupActivationMode | undefined { const value = raw?.trim().toLowerCase(); if (value === "mention") return "mention"; if (value === "always") return "always"; + if (value === "engagement") return "engagement"; return undefined; } diff --git a/src/auto-reply/reply/commands-status.ts b/src/auto-reply/reply/commands-status.ts index a6f0b7348..9cb4269cf 100644 --- a/src/auto-reply/reply/commands-status.ts +++ b/src/auto-reply/reply/commands-status.ts @@ -111,7 +111,7 @@ export async function buildStatusReply(params: { resolvedElevatedLevel?: ElevatedLevel; resolveDefaultThinkingLevel: () => Promise; isGroup: boolean; - defaultGroupActivation: () => "always" | "mention"; + defaultGroupActivation: () => "always" | "mention" | "engagement"; mediaDecisions?: MediaUnderstandingDecision[]; }): Promise { const { diff --git a/src/auto-reply/reply/commands-types.ts b/src/auto-reply/reply/commands-types.ts index d8adb2353..2175585b6 100644 --- a/src/auto-reply/reply/commands-types.ts +++ b/src/auto-reply/reply/commands-types.ts @@ -39,7 +39,7 @@ export type HandleCommandsParams = { storePath?: string; sessionScope?: SessionScope; workspaceDir: string; - defaultGroupActivation: () => "always" | "mention"; + defaultGroupActivation: () => "always" | "mention" | "engagement"; resolvedThinkLevel?: ThinkLevel; resolvedVerboseLevel: VerboseLevel; resolvedReasoningLevel: ReasoningLevel; diff --git a/src/auto-reply/reply/groups.ts b/src/auto-reply/reply/groups.ts index 00011136a..b48a06de1 100644 --- a/src/auto-reply/reply/groups.ts +++ b/src/auto-reply/reply/groups.ts @@ -49,7 +49,9 @@ export function resolveGroupRequireMention(params: { return true; } -export function defaultGroupActivation(requireMention: boolean): "always" | "mention" { +export function defaultGroupActivation( + requireMention: boolean, +): "always" | "mention" | "engagement" { return requireMention === false ? "always" : "mention"; } @@ -57,7 +59,7 @@ export function buildGroupIntro(params: { cfg: MoltbotConfig; sessionCtx: TemplateContext; sessionEntry?: SessionEntry; - defaultActivation: "always" | "mention"; + defaultActivation: "always" | "mention" | "engagement"; silentToken: string; }): string { const activation = diff --git a/src/auto-reply/status.ts b/src/auto-reply/status.ts index e69941cd8..8c85e127f 100644 --- a/src/auto-reply/status.ts +++ b/src/auto-reply/status.ts @@ -59,7 +59,7 @@ type StatusArgs = { sessionEntry?: SessionEntry; sessionKey?: string; sessionScope?: SessionScope; - groupActivation?: "mention" | "always"; + groupActivation?: "mention" | "always" | "engagement"; resolvedThink?: ThinkLevel; resolvedVerbose?: VerboseLevel; resolvedReasoning?: ReasoningLevel; diff --git a/src/config/group-policy.ts b/src/config/group-policy.ts index ae8967192..3c5b0ba21 100644 --- a/src/config/group-policy.ts +++ b/src/config/group-policy.ts @@ -1,12 +1,15 @@ import type { ChannelId } from "../channels/plugins/types.js"; import { normalizeAccountId } from "../routing/session-key.js"; import type { MoltbotConfig } from "./config.js"; +import type { EngagementConfig } from "./engagement.js"; import type { GroupToolPolicyBySenderConfig, GroupToolPolicyConfig } from "./types.tools.js"; export type GroupPolicyChannel = ChannelId; export type ChannelGroupConfig = { requireMention?: boolean; + mode?: "mention" | "always" | "engagement"; + engagement?: EngagementConfig; tools?: GroupToolPolicyConfig; toolsBySender?: GroupToolPolicyBySenderConfig; }; @@ -154,6 +157,31 @@ export function resolveChannelGroupRequireMention(params: { return true; } +export function resolveChannelGroupMode(params: { + cfg: MoltbotConfig; + channel: GroupPolicyChannel; + groupId?: string | null; + accountId?: string | null; +}): "mention" | "always" | "engagement" { + const { groupConfig, defaultConfig } = resolveChannelGroupPolicy(params); + // Explicit mode takes precedence + if (groupConfig?.mode) return groupConfig.mode; + if (defaultConfig?.mode) return defaultConfig.mode; + // Fall back to legacy requireMention behavior + const requireMention = resolveChannelGroupRequireMention(params); + return requireMention ? "mention" : "always"; +} + +export function resolveChannelGroupEngagement(params: { + cfg: MoltbotConfig; + channel: GroupPolicyChannel; + groupId?: string | null; + accountId?: string | null; +}): EngagementConfig | undefined { + const { groupConfig, defaultConfig } = resolveChannelGroupPolicy(params); + return groupConfig?.engagement ?? defaultConfig?.engagement; +} + export function resolveChannelGroupToolsPolicy( params: { cfg: MoltbotConfig; diff --git a/src/config/sessions/types.ts b/src/config/sessions/types.ts index 48ce428c1..2e302accf 100644 --- a/src/config/sessions/types.ts +++ b/src/config/sessions/types.ts @@ -3,6 +3,7 @@ import crypto from "node:crypto"; import type { Skill } from "@mariozechner/pi-coding-agent"; import type { NormalizedChatType } from "../../channels/chat-type.js"; import type { ChannelId } from "../../channels/plugins/types.js"; +import type { EngagementState } from "../engagement.js"; import type { DeliveryContext } from "../../utils/delivery-context.js"; import type { TtsAutoMode } from "../types.tts.js"; @@ -54,8 +55,9 @@ export type SessionEntry = { authProfileOverride?: string; authProfileOverrideSource?: "auto" | "user"; authProfileOverrideCompactionCount?: number; - groupActivation?: "mention" | "always"; + groupActivation?: "mention" | "always" | "engagement"; groupActivationNeedsSystemIntro?: boolean; + engagementState?: EngagementState; sendPolicy?: "allow" | "deny"; queueMode?: | "steer" diff --git a/src/web/auto-reply/monitor/group-activation.ts b/src/web/auto-reply/monitor/group-activation.ts index 520671fec..8980fc820 100644 --- a/src/web/auto-reply/monitor/group-activation.ts +++ b/src/web/auto-reply/monitor/group-activation.ts @@ -1,6 +1,7 @@ import { normalizeGroupActivation } from "../../../auto-reply/group-activation.js"; import type { loadConfig } from "../../../config/config.js"; import { + resolveChannelGroupMode, resolveChannelGroupPolicy, resolveChannelGroupRequireMention, } from "../../../config/group-policy.js"; @@ -39,6 +40,19 @@ export function resolveGroupRequireMentionFor( }); } +export function resolveGroupModeFor(cfg: ReturnType, conversationId: string) { + const groupId = resolveGroupSessionKey({ + From: conversationId, + ChatType: "group", + Provider: "whatsapp", + })?.id; + return resolveChannelGroupMode({ + cfg, + channel: "whatsapp", + groupId: groupId ?? conversationId, + }); +} + export function resolveGroupActivationFor(params: { cfg: ReturnType; agentId: string; @@ -50,7 +64,16 @@ export function resolveGroupActivationFor(params: { }); const store = loadSessionStore(storePath); const entry = store[params.sessionKey]; + + // Session-level override takes precedence + const sessionActivation = normalizeGroupActivation(entry?.groupActivation); + if (sessionActivation) return sessionActivation; + + // Then check config mode (supports "engagement") + const configMode = resolveGroupModeFor(params.cfg, params.conversationId); + if (configMode) return configMode; + + // Legacy fallback const requireMention = resolveGroupRequireMentionFor(params.cfg, params.conversationId); - const defaultActivation = requireMention === false ? "always" : "mention"; - return normalizeGroupActivation(entry?.groupActivation) ?? defaultActivation; + return requireMention === false ? "always" : "mention"; }