refactor: normalize group session keys
This commit is contained in:
@@ -220,6 +220,7 @@ describe("trigger handling", () => {
|
||||
From: "123@g.us",
|
||||
To: "+2000",
|
||||
ChatType: "group",
|
||||
Surface: "whatsapp",
|
||||
SenderE164: "+2000",
|
||||
},
|
||||
{},
|
||||
@@ -230,7 +231,7 @@ describe("trigger handling", () => {
|
||||
const store = JSON.parse(
|
||||
await fs.readFile(cfg.session.store, "utf-8"),
|
||||
) as Record<string, { groupActivation?: string }>;
|
||||
expect(store["group:123@g.us"]?.groupActivation).toBe("always");
|
||||
expect(store["whatsapp:group:123@g.us"]?.groupActivation).toBe("always");
|
||||
expect(runEmbeddedPiAgent).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -244,6 +245,7 @@ describe("trigger handling", () => {
|
||||
From: "123@g.us",
|
||||
To: "+2000",
|
||||
ChatType: "group",
|
||||
Surface: "whatsapp",
|
||||
SenderE164: "+999",
|
||||
},
|
||||
{},
|
||||
@@ -270,6 +272,7 @@ describe("trigger handling", () => {
|
||||
From: "123@g.us",
|
||||
To: "+2000",
|
||||
ChatType: "group",
|
||||
Surface: "whatsapp",
|
||||
SenderE164: "+2000",
|
||||
GroupSubject: "Test Group",
|
||||
GroupMembers: "Alice (+1), Bob (+2)",
|
||||
|
||||
@@ -29,7 +29,9 @@ import { type ClawdisConfig, loadConfig } from "../config/config.js";
|
||||
import {
|
||||
DEFAULT_IDLE_MINUTES,
|
||||
DEFAULT_RESET_TRIGGERS,
|
||||
buildGroupDisplayName,
|
||||
loadSessionStore,
|
||||
resolveGroupSessionKey,
|
||||
resolveSessionKey,
|
||||
resolveSessionTranscriptPath,
|
||||
resolveStorePath,
|
||||
@@ -364,9 +366,9 @@ export async function getReplyFromConfig(
|
||||
let persistedModelOverride: string | undefined;
|
||||
let persistedProviderOverride: string | undefined;
|
||||
|
||||
const groupResolution = resolveGroupSessionKey(ctx);
|
||||
const isGroup =
|
||||
typeof ctx.From === "string" &&
|
||||
(ctx.From.includes("@g.us") || ctx.From.startsWith("group:"));
|
||||
ctx.ChatType?.trim().toLowerCase() === "group" || Boolean(groupResolution);
|
||||
const triggerBodyNormalized = stripStructuralPrefixes(ctx.Body ?? "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
@@ -399,6 +401,16 @@ export async function getReplyFromConfig(
|
||||
|
||||
sessionKey = resolveSessionKey(sessionScope, ctx, mainKey);
|
||||
sessionStore = loadSessionStore(storePath);
|
||||
if (
|
||||
groupResolution?.legacyKey &&
|
||||
groupResolution.legacyKey !== sessionKey
|
||||
) {
|
||||
const legacyEntry = sessionStore[groupResolution.legacyKey];
|
||||
if (legacyEntry && !sessionStore[sessionKey]) {
|
||||
sessionStore[sessionKey] = legacyEntry;
|
||||
delete sessionStore[groupResolution.legacyKey];
|
||||
}
|
||||
}
|
||||
const entry = sessionStore[sessionKey];
|
||||
const idleMs = idleMinutes * 60_000;
|
||||
const freshEntry = entry && Date.now() - entry.updatedAt <= idleMs;
|
||||
@@ -431,7 +443,35 @@ export async function getReplyFromConfig(
|
||||
modelOverride: persistedModelOverride ?? baseEntry?.modelOverride,
|
||||
providerOverride: persistedProviderOverride ?? baseEntry?.providerOverride,
|
||||
queueMode: baseEntry?.queueMode,
|
||||
displayName: baseEntry?.displayName,
|
||||
chatType: baseEntry?.chatType,
|
||||
surface: baseEntry?.surface,
|
||||
subject: baseEntry?.subject,
|
||||
room: baseEntry?.room,
|
||||
space: baseEntry?.space,
|
||||
};
|
||||
if (groupResolution?.surface) {
|
||||
const surface = groupResolution.surface;
|
||||
const subject = ctx.GroupSubject?.trim();
|
||||
const isRoomSurface = surface === "discord" || surface === "slack";
|
||||
const nextRoom =
|
||||
isRoomSurface && subject && subject.startsWith("#") ? subject : undefined;
|
||||
const nextSubject = nextRoom ? undefined : subject;
|
||||
sessionEntry.chatType = groupResolution.chatType ?? "group";
|
||||
sessionEntry.surface = surface;
|
||||
if (nextSubject) sessionEntry.subject = nextSubject;
|
||||
if (nextRoom) sessionEntry.room = nextRoom;
|
||||
sessionEntry.displayName = buildGroupDisplayName({
|
||||
surface: sessionEntry.surface,
|
||||
subject: sessionEntry.subject,
|
||||
room: sessionEntry.room,
|
||||
space: sessionEntry.space,
|
||||
id: groupResolution.id,
|
||||
key: sessionKey,
|
||||
});
|
||||
} else if (!sessionEntry.chatType) {
|
||||
sessionEntry.chatType = "direct";
|
||||
}
|
||||
sessionStore[sessionKey] = sessionEntry;
|
||||
await saveSessionStore(storePath, sessionStore);
|
||||
|
||||
@@ -1038,8 +1078,7 @@ export async function getReplyFromConfig(
|
||||
// Prepend queued system events (transitions only) and (for new main sessions) a provider snapshot.
|
||||
// Token efficiency: we filter out periodic/heartbeat noise and keep the lines compact.
|
||||
const isGroupSession =
|
||||
typeof ctx.From === "string" &&
|
||||
(ctx.From.includes("@g.us") || ctx.From.startsWith("group:"));
|
||||
sessionEntry?.chatType === "group" || sessionEntry?.chatType === "room";
|
||||
const isMainSession =
|
||||
!isGroupSession && sessionKey === (sessionCfg?.mainKey ?? "main");
|
||||
if (isMainSession) {
|
||||
|
||||
@@ -63,8 +63,9 @@ describe("buildStatusMessage", () => {
|
||||
sessionId: "g1",
|
||||
updatedAt: 0,
|
||||
groupActivation: "always",
|
||||
chatType: "group",
|
||||
},
|
||||
sessionKey: "group:123@g.us",
|
||||
sessionKey: "whatsapp:group:123@g.us",
|
||||
sessionScope: "per-sender",
|
||||
webLinked: true,
|
||||
});
|
||||
|
||||
@@ -191,7 +191,13 @@ export function buildStatusMessage(args: StatusArgs): string {
|
||||
.filter(Boolean)
|
||||
.join(" • ");
|
||||
|
||||
const groupActivationLine = args.sessionKey?.startsWith("group:")
|
||||
const isGroupSession =
|
||||
entry?.chatType === "group" ||
|
||||
entry?.chatType === "room" ||
|
||||
Boolean(args.sessionKey?.includes(":group:")) ||
|
||||
Boolean(args.sessionKey?.includes(":channel:")) ||
|
||||
Boolean(args.sessionKey?.startsWith("group:"));
|
||||
const groupActivationLine = isGroupSession
|
||||
? `Group activation: ${entry?.groupActivation ?? "mention"}`
|
||||
: undefined;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user