11// Whatsapp plugin module implements group activation behavior.
22import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts" ;
33import { DEFAULT_ACCOUNT_ID , normalizeAccountId } from "openclaw/plugin-sdk/routing" ;
4- import { updateSessionStore } from "openclaw/plugin-sdk/session-store-runtime" ;
4+ import {
5+ getSessionEntry ,
6+ patchSessionEntry ,
7+ resolveStorePath ,
8+ type SessionEntry ,
9+ } from "openclaw/plugin-sdk/session-store-runtime" ;
510import { resolveWhatsAppLegacyGroupSessionKey } from "../../group-session-key.js" ;
611import { resolveWhatsAppInboundPolicy } from "../../inbound-policy.js" ;
7- import { loadSessionStore , resolveStorePath } from "../config.runtime.js" ;
812import { normalizeGroupActivation } from "./group-activation.runtime.js" ;
913
1014function hasNamedWhatsAppAccounts ( cfg : OpenClawConfig ) {
@@ -28,6 +32,7 @@ function isActivationOnlyEntry(
2832 ) ;
2933}
3034
35+ /** Resolves group activation for a WhatsApp conversation and backfills scoped session metadata. */
3136export async function resolveGroupActivationFor ( params : {
3237 cfg : OpenClawConfig ;
3338 accountId ?: string | null ;
@@ -38,13 +43,15 @@ export async function resolveGroupActivationFor(params: {
3843 const storePath = resolveStorePath ( params . cfg . session ?. store , {
3944 agentId : params . agentId ,
4045 } ) ;
41- const store = loadSessionStore ( storePath ) ;
46+ const sessionScope = { storePath, agentId : params . agentId } ;
4247 const legacySessionKey = resolveWhatsAppLegacyGroupSessionKey ( {
4348 sessionKey : params . sessionKey ,
4449 accountId : params . accountId ,
4550 } ) ;
46- const legacyEntry = legacySessionKey ? store [ legacySessionKey ] : undefined ;
47- const scopedEntry = store [ params . sessionKey ] ;
51+ const legacyEntry = legacySessionKey
52+ ? getSessionEntry ( { ...sessionScope , sessionKey : legacySessionKey } )
53+ : undefined ;
54+ const scopedEntry = getSessionEntry ( { ...sessionScope , sessionKey : params . sessionKey } ) ;
4855 const normalizedAccountId = normalizeAccountId ( params . accountId ) ;
4956 const ignoreScopedActivation =
5057 normalizedAccountId === DEFAULT_ACCOUNT_ID &&
@@ -54,15 +61,22 @@ export async function resolveGroupActivationFor(params: {
5461 ( ignoreScopedActivation ? undefined : scopedEntry ?. groupActivation ) ??
5562 legacyEntry ?. groupActivation ;
5663 if ( activation !== undefined && scopedEntry ?. groupActivation === undefined ) {
57- await updateSessionStore ( storePath , ( nextStore ) => {
58- const nextScopedEntry = nextStore [ params . sessionKey ] ;
59- if ( nextScopedEntry ?. groupActivation !== undefined ) {
60- return ;
61- }
62- nextStore [ params . sessionKey ] = {
63- ...nextScopedEntry ,
64- groupActivation : activation ,
65- } ;
64+ // Activation-only backfills must not synthesize session ids or activity.
65+ // replaceEntry preserves existing scoped metadata while keeping fallback writes sparse.
66+ await patchSessionEntry ( {
67+ ...sessionScope ,
68+ sessionKey : params . sessionKey ,
69+ fallbackEntry : { } as SessionEntry ,
70+ replaceEntry : true ,
71+ update : ( entry ) => {
72+ if ( entry . groupActivation !== undefined ) {
73+ return null ;
74+ }
75+ return {
76+ ...entry ,
77+ groupActivation : activation ,
78+ } ;
79+ } ,
6680 } ) ;
6781 }
6882 const requireMention = resolveWhatsAppInboundPolicy ( {
0 commit comments