From 8112b276c0e6be24581a8b39a0222e8b68c288cd Mon Sep 17 00:00:00 2001 From: Richard Poelderl Date: Fri, 9 Jan 2026 15:45:18 +0100 Subject: [PATCH] feat(messages): derive messagePrefix from identity.name When identity.name is configured, use it for the default messagePrefix instead of hardcoded '[clawdbot]'. Falls back to 'clawdbot' if not set. This allows users to customize how their bot identifies itself in messages by setting identity.name in their config or IDENTITY.md. --- src/config/types.ts | 2 +- src/web/auto-reply.test.ts | 41 ++++++++++++++++++++++++++++++++++++++ src/web/auto-reply.ts | 5 +++-- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/config/types.ts b/src/config/types.ts index 45413dfb9..aa971f707 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -891,7 +891,7 @@ export type AudioConfig = { }; export type MessagesConfig = { - messagePrefix?: string; // Prefix added to all inbound messages (default: "[clawdbot]" if no allowFrom, else "") + messagePrefix?: string; // Prefix added to all inbound messages (default: "[{identity.name}]" or "[clawdbot]" if no allowFrom, else "") responsePrefix?: string; // Prefix auto-added to all outbound replies (e.g., "🦞") groupChat?: GroupChatConfig; queue?: QueueConfig; diff --git a/src/web/auto-reply.test.ts b/src/web/auto-reply.test.ts index cff460ad9..03cf9f2c5 100644 --- a/src/web/auto-reply.test.ts +++ b/src/web/auto-reply.test.ts @@ -1959,4 +1959,45 @@ describe("web auto-reply", () => { expect(replies).toEqual(["🦞 🧩 tool1", "🦞 🧩 tool2", "🦞 final"]); resetLoadConfigMock(); }); + + it("uses identity.name for messagePrefix when set", async () => { + setLoadConfigMock(() => ({ + identity: { name: "Richbot", emoji: "🦁" }, + })); + + let capturedOnMessage: + | ((msg: import("./inbound.js").WebInboundMessage) => Promise) + | undefined; + const reply = vi.fn(); + const listenerFactory = async (opts: { + onMessage: ( + msg: import("./inbound.js").WebInboundMessage, + ) => Promise; + }) => { + capturedOnMessage = opts.onMessage; + return { close: vi.fn() }; + }; + + const resolver = vi.fn().mockResolvedValue({ text: "hello" }); + + await monitorWebProvider(false, listenerFactory, false, resolver); + expect(capturedOnMessage).toBeDefined(); + + await capturedOnMessage?.({ + body: "hi", + from: "+1555", + to: "+2666", + id: "msg1", + sendComposing: vi.fn(), + reply, + sendMedia: vi.fn(), + }); + + // Check that resolver received the message with identity-based prefix + expect(resolver).toHaveBeenCalled(); + const resolverArg = resolver.mock.calls[0][0]; + expect(resolverArg.Body).toContain("[Richbot]"); + expect(resolverArg.Body).not.toContain("[clawdbot]"); + resetLoadConfigMock(); + }); }); diff --git a/src/web/auto-reply.ts b/src/web/auto-reply.ts index dc1050443..cc3435fb1 100644 --- a/src/web/auto-reply.ts +++ b/src/web/auto-reply.ts @@ -1033,11 +1033,12 @@ export async function monitorWebProvider( }; const buildLine = (msg: WebInboundMsg) => { - // Build message prefix: explicit config > default based on allowFrom + // Build message prefix: explicit config > identity name > default "clawdbot" let messagePrefix = cfg.messages?.messagePrefix; if (messagePrefix === undefined) { const hasAllowFrom = (cfg.whatsapp?.allowFrom?.length ?? 0) > 0; - messagePrefix = hasAllowFrom ? "" : "[clawdbot]"; + const identityName = cfg.identity?.name?.trim() || "clawdbot"; + messagePrefix = hasAllowFrom ? "" : `[${identityName}]`; } const prefixStr = messagePrefix ? `${messagePrefix} ` : ""; const senderLabel =