fix: unify inbound sender labels

This commit is contained in:
Peter Steinberger
2026-01-17 05:21:02 +00:00
parent 572e04d5fb
commit f7089cde54
20 changed files with 587 additions and 40 deletions

View File

@@ -369,6 +369,97 @@ describe("discord tool result dispatch", () => {
expect(capturedCtx?.SessionKey).toBe("agent:main:discord:channel:c1");
});
it("prefixes group bodies with sender label", async () => {
const { createDiscordMessageHandler } = await import("./monitor.js");
let capturedBody = "";
dispatchMock.mockImplementationOnce(async ({ ctx, dispatcher }) => {
capturedBody = ctx.Body ?? "";
dispatcher.sendFinalReply({ text: "ok" });
return { queuedFinal: true, counts: { final: 1 } };
});
const cfg = {
agents: {
defaults: {
model: "anthropic/claude-opus-4-5",
workspace: "/tmp/clawd",
},
},
session: { store: "/tmp/clawdbot-sessions.json" },
channels: {
discord: {
dm: { enabled: true, policy: "open" },
guilds: {
"*": {
requireMention: false,
channels: { c1: { allow: true } },
},
},
},
},
routing: { allowFrom: [] },
} as ReturnType<typeof import("../config/config.js").loadConfig>;
const handler = createDiscordMessageHandler({
cfg,
discordConfig: cfg.channels.discord,
accountId: "default",
token: "token",
runtime: {
log: vi.fn(),
error: vi.fn(),
exit: (code: number): never => {
throw new Error(`exit ${code}`);
},
},
botUserId: "bot-id",
guildHistories: new Map(),
historyLimit: 0,
mediaMaxBytes: 10_000,
textLimit: 2000,
replyToMode: "off",
dmEnabled: true,
groupDmEnabled: false,
guildEntries: {
"*": { requireMention: false, channels: { c1: { allow: true } } },
},
});
const client = {
fetchChannel: vi.fn().mockResolvedValue({
type: ChannelType.GuildText,
name: "general",
parentId: "category-1",
}),
rest: { get: vi.fn() },
} as unknown as Client;
await handler(
{
message: {
id: "m-prefix",
content: "hello",
channelId: "c1",
timestamp: new Date("2026-01-17T00:00:00Z").toISOString(),
type: MessageType.Default,
attachments: [],
embeds: [],
mentionedEveryone: false,
mentionedUsers: [],
mentionedRoles: [],
author: { id: "u1", bot: false, username: "Ada", discriminator: "1234" },
},
author: { id: "u1", bot: false, username: "Ada", discriminator: "1234" },
member: { displayName: "Ada" },
guild: { id: "g1", name: "Guild" },
guild_id: "g1",
},
client,
);
expect(capturedBody).toContain("Ada (Ada#1234): hello");
});
it("replies with pairing code and sender id when dmPolicy is pairing", async () => {
const { createDiscordMessageHandler } = await import("./monitor.js");
const cfg = {

View File

@@ -8,7 +8,10 @@ import {
extractShortModelName,
type ResponsePrefixContext,
} from "../../auto-reply/reply/response-prefix-template.js";
import { formatAgentEnvelope, formatThreadStarterEnvelope } from "../../auto-reply/envelope.js";
import {
formatInboundEnvelope,
formatThreadStarterEnvelope,
} from "../../auto-reply/envelope.js";
import { dispatchReplyFromConfig } from "../../auto-reply/reply/dispatch-from-config.js";
import {
buildPendingHistoryContextFromMap,
@@ -118,6 +121,12 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
channelName: channelName ?? message.channelId,
channelId: message.channelId,
});
const senderTag = formatDiscordUserTag(author);
const senderDisplay = data.member?.nickname ?? author.globalName ?? author.username;
const senderLabel =
senderDisplay && senderTag && senderDisplay !== senderTag
? `${senderDisplay} (${senderTag})`
: senderDisplay ?? senderTag ?? author.id;
const groupRoom = isGuildMessage && displayChannelSlug ? `#${displayChannelSlug}` : undefined;
const groupSubject = isDirectMessage ? undefined : groupRoom;
const channelDescription = channelInfo?.topic?.trim();
@@ -127,11 +136,13 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
].filter((entry): entry is string => Boolean(entry));
const groupSystemPrompt =
systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
let combinedBody = formatAgentEnvelope({
let combinedBody = formatInboundEnvelope({
channel: "Discord",
from: fromLabel,
timestamp: resolveTimestampMs(message.timestamp),
body: text,
chatType: isDirectMessage ? "direct" : "channel",
senderLabel,
});
const shouldIncludeChannelHistory =
!isDirectMessage && !(isGuildMessage && channelConfig?.autoThread && !threadChannel);
@@ -142,11 +153,13 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
limit: historyLimit,
currentMessage: combinedBody,
formatEntry: (entry) =>
formatAgentEnvelope({
formatInboundEnvelope({
channel: "Discord",
from: fromLabel,
timestamp: entry.timestamp,
body: `${entry.sender}: ${entry.body} [id:${entry.messageId ?? "unknown"} channel:${message.channelId}]`,
body: `${entry.body} [id:${entry.messageId ?? "unknown"} channel:${message.channelId}]`,
chatType: "channel",
senderLabel: entry.sender,
}),
});
}