mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 20:20:42 +00:00
WhatsApp: add group and direct system prompt support (#59553)
Merged via squash.
Prepared head SHA: 63e2b50e01
Co-authored-by: Bluetegu <1525690+Bluetegu@users.noreply.github.com>
Co-authored-by: omarshahine <10343873+omarshahine@users.noreply.github.com>
Reviewed-by: @omarshahine
This commit is contained in:
@@ -36,6 +36,7 @@ export type ResolvedWhatsAppAccount = {
|
||||
ackReaction?: WhatsAppAccountConfig["ackReaction"];
|
||||
reactionLevel?: WhatsAppAccountConfig["reactionLevel"];
|
||||
groups?: WhatsAppAccountConfig["groups"];
|
||||
direct?: WhatsAppAccountConfig["direct"];
|
||||
debounceMs?: number;
|
||||
};
|
||||
|
||||
@@ -150,6 +151,7 @@ export function resolveWhatsAppAccount(params: {
|
||||
ackReaction: merged.ackReaction,
|
||||
reactionLevel: merged.reactionLevel,
|
||||
groups: merged.groups,
|
||||
direct: merged.direct,
|
||||
debounceMs: merged.debounceMs,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -194,6 +194,44 @@ describe("whatsapp inbound dispatch", () => {
|
||||
expect(ctx.To).toBe("+2000");
|
||||
});
|
||||
|
||||
it("passes groupSystemPrompt into GroupSystemPrompt for group chats", () => {
|
||||
const ctx = buildWhatsAppInboundContext({
|
||||
combinedBody: "hi",
|
||||
conversationId: "123@g.us",
|
||||
groupSystemPrompt: "Specific group prompt",
|
||||
msg: makeMsg({ from: "123@g.us", chatType: "group", groupParticipants: [] }),
|
||||
route: makeRoute({ sessionKey: "agent:main:whatsapp:group:123@g.us" }),
|
||||
sender: { e164: "+15550002222" },
|
||||
});
|
||||
|
||||
expect(ctx.GroupSystemPrompt).toBe("Specific group prompt");
|
||||
});
|
||||
|
||||
it("passes groupSystemPrompt into GroupSystemPrompt for direct chats", () => {
|
||||
const ctx = buildWhatsAppInboundContext({
|
||||
combinedBody: "hi",
|
||||
conversationId: "+1555",
|
||||
groupSystemPrompt: "Specific direct prompt",
|
||||
msg: makeMsg({ from: "+1555", chatType: "direct" }),
|
||||
route: makeRoute({ sessionKey: "agent:main:whatsapp:direct:+1555" }),
|
||||
sender: { e164: "+1555" },
|
||||
});
|
||||
|
||||
expect(ctx.GroupSystemPrompt).toBe("Specific direct prompt");
|
||||
});
|
||||
|
||||
it("omits GroupSystemPrompt when groupSystemPrompt is not provided", () => {
|
||||
const ctx = buildWhatsAppInboundContext({
|
||||
combinedBody: "hi",
|
||||
conversationId: "123@g.us",
|
||||
msg: makeMsg({ from: "123@g.us", chatType: "group", groupParticipants: [] }),
|
||||
route: makeRoute({ sessionKey: "agent:main:whatsapp:group:123@g.us" }),
|
||||
sender: { e164: "+15550002222" },
|
||||
});
|
||||
|
||||
expect(ctx.GroupSystemPrompt).toBeUndefined();
|
||||
});
|
||||
|
||||
it("defaults responsePrefix to identity name in self-chats when unset", () => {
|
||||
const responsePrefix = resolveWhatsAppResponsePrefix({
|
||||
cfg: {
|
||||
|
||||
@@ -87,6 +87,7 @@ export function buildWhatsAppInboundContext(params: {
|
||||
conversationId: string;
|
||||
groupHistory?: GroupHistoryEntry[];
|
||||
groupMemberRoster?: Map<string, string>;
|
||||
groupSystemPrompt?: string;
|
||||
msg: WebInboundMsg;
|
||||
route: ReturnType<typeof resolveAgentRoute>;
|
||||
sender: SenderContext;
|
||||
@@ -132,6 +133,7 @@ export function buildWhatsAppInboundContext(params: {
|
||||
SenderE164: params.sender.e164,
|
||||
CommandAuthorized: params.commandAuthorized,
|
||||
WasMentioned: params.msg.wasMentioned,
|
||||
GroupSystemPrompt: params.groupSystemPrompt,
|
||||
...(params.msg.location ? toLocationContext(params.msg.location) : {}),
|
||||
Provider: "whatsapp",
|
||||
Surface: "whatsapp",
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
resolveWhatsAppDirectSystemPrompt,
|
||||
resolveWhatsAppGroupSystemPrompt,
|
||||
} from "../../system-prompt.js";
|
||||
import { getPrimaryIdentityId, getSelfIdentity, getSenderIdentity } from "../../identity.js";
|
||||
import {
|
||||
resolveWhatsAppCommandAuthorized,
|
||||
@@ -227,12 +231,25 @@ export async function processMessage(params: {
|
||||
pipelineResponsePrefix: replyPipeline.responsePrefix,
|
||||
});
|
||||
|
||||
// Resolve combined conversation system prompt using the group or direct surface.
|
||||
const conversationSystemPrompt =
|
||||
params.msg.chatType === "group"
|
||||
? resolveWhatsAppGroupSystemPrompt({
|
||||
accountConfig: account,
|
||||
groupId: conversationId,
|
||||
})
|
||||
: resolveWhatsAppDirectSystemPrompt({
|
||||
accountConfig: account,
|
||||
peerId: dmRouteTarget ?? params.msg.from,
|
||||
});
|
||||
|
||||
const ctxPayload = buildWhatsAppInboundContext({
|
||||
combinedBody,
|
||||
commandAuthorized,
|
||||
conversationId,
|
||||
groupHistory: visibleGroupHistory,
|
||||
groupMemberRoster: params.groupMemberNames.get(params.groupHistoryKey),
|
||||
groupSystemPrompt: conversationSystemPrompt,
|
||||
msg: params.msg,
|
||||
route: params.route,
|
||||
sender: {
|
||||
|
||||
29
extensions/whatsapp/src/system-prompt.ts
Normal file
29
extensions/whatsapp/src/system-prompt.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export function resolveWhatsAppGroupSystemPrompt(params: {
|
||||
accountConfig?: { groups?: Record<string, { systemPrompt?: string }> } | null;
|
||||
groupId?: string | null;
|
||||
}): string | undefined {
|
||||
if (!params.groupId) {
|
||||
return undefined;
|
||||
}
|
||||
const groups = params.accountConfig?.groups;
|
||||
return (
|
||||
groups?.[params.groupId]?.systemPrompt?.trim() ||
|
||||
groups?.["*"]?.systemPrompt?.trim() ||
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveWhatsAppDirectSystemPrompt(params: {
|
||||
accountConfig?: { direct?: Record<string, { systemPrompt?: string }> } | null;
|
||||
peerId?: string | null;
|
||||
}): string | undefined {
|
||||
if (!params.peerId) {
|
||||
return undefined;
|
||||
}
|
||||
const direct = params.accountConfig?.direct;
|
||||
return (
|
||||
direct?.[params.peerId]?.systemPrompt?.trim() ||
|
||||
direct?.["*"]?.systemPrompt?.trim() ||
|
||||
undefined
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user