fix(messaging): preserve group inbound media URLs in fan-out (#66)

Group channel fan-out used event.content only, dropping mediaUrl that
DM handling already merges into message text. Photos with empty captions
in SendBlue groups reached member bots with blank prompts and blocks.

Also skip fan-out when the merged text is empty, matching DM tapback
behavior.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
This commit is contained in:
cynarAI 2026-09-22 12:00:07 +02:00 committed by GitHub
parent 33af336516
commit b4a0dbc74d
2 changed files with 36 additions and 2 deletions

View File

@ -911,6 +911,36 @@ describe("createMessagingInboundHandler channel routing", () => {
expect(runJobs).toHaveLength(2);
});
it("appends inbound media links to group fan-out text and prompt", async () => {
const senderMember = {
id: "cm-1",
channelId: "ch-1",
address: "+15551111111",
identityId: "mi-1",
status: "approved",
};
const deps = createDeps({ members: [senderMember] });
const handle = createMessagingInboundHandler(deps);
await handle({
...groupEvent,
content: "",
mediaUrl: "https://cdn.example.com/group-photo.jpg",
});
expect(deps.sendUserMessage).toHaveBeenCalledWith(
expect.objectContaining({
prompt: `[Group "Family", Alice]: https://cdn.example.com/group-photo.jpg`,
blocks: [
expect.objectContaining({
kind: "channel_message",
text: "https://cdn.example.com/group-photo.jpg",
}),
],
}),
);
});
it("wakes matching routines only after a channel member is approved", async () => {
const approved = {
id: "cm-1",

View File

@ -581,6 +581,10 @@ async function handleChannelEvent(
const approved = await deps.prisma.messagingChannelMember.findMany({
where: { channelId: channel.id, status: "approved", identityId: { not: null } },
});
// Same v1 media-as-text merge as DMs: group photos often arrive with an
// empty caption and only a CDN URL.
const text = [event.content, event.mediaUrl].filter(Boolean).join("\n");
if (!text) return;
const block: MessageBlock = {
kind: "channel_message",
provider: event.provider,
@ -588,10 +592,10 @@ async function handleChannelEvent(
channelId: channel.id,
fromAddress: event.from,
fromLabel,
text: event.content,
text,
hop: 0,
};
const prompt = `[Group "${channel.name ?? "group"}", ${fromLabel}]: ${event.content}`;
const prompt = `[Group "${channel.name ?? "group"}", ${fromLabel}]: ${text}`;
for (const member of approved) {
const identity = await deps.prisma.messagingIdentity.findUnique({
where: { id: member.identityId! },