feat: add broadcast groups for multi-agent responses
Enables multiple agents to process the same message simultaneously,
allowing teams of specialized agents with atomic tasks to work together
in the same group using one phone number.
Key features:
- Configure multiple agents per WhatsApp group/DM via routing.broadcast
- Parallel (default) or sequential processing strategies
- Full session isolation (separate history, workspace, tools per agent)
- Minimal code changes (~50 lines in auto-reply.ts)
- Backward compatible with existing routing
Use cases:
- Specialized agent teams (code reviewer + security scanner + docs)
- Multi-language support (EN + DE + ES agents)
- Quality assurance workflows (support + QA agents)
- Task automation (tracker + logger + reporter)
Example config:
{
"routing": {
"broadcast": {
"strategy": "parallel",
"120363403215116621@g.us": ["alfred", "baerbel", "assistant3"]
}
}
}
This enables scaling to hundreds of focused micro-agents on a single
phone number, each handling specific atomic tasks.
This commit is contained in:
committed by
Peter Steinberger
parent
2469384643
commit
09769d127f
@@ -49,6 +49,13 @@ import { registerUnhandledRejectionHandler } from "../infra/unhandled-rejections
|
||||
import { createSubsystemLogger, getChildLogger } from "../logging.js";
|
||||
import { toLocationContext } from "../providers/location.js";
|
||||
import { resolveAgentRoute } from "../routing/resolve-route.js";
|
||||
import {
|
||||
buildAgentMainSessionKey,
|
||||
buildAgentPeerSessionKey,
|
||||
DEFAULT_MAIN_KEY,
|
||||
normalizeAgentId,
|
||||
normalizeId,
|
||||
} from "../routing/session-key.js";
|
||||
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
||||
import { isSelfChatMode, jidToE164, normalizeE164 } from "../utils.js";
|
||||
import { resolveWhatsAppAccount } from "./accounts.js";
|
||||
@@ -1453,6 +1460,55 @@ export async function monitorWebProvider(
|
||||
}
|
||||
}
|
||||
|
||||
// Check for broadcast groups
|
||||
const broadcastAgents = cfg.routing?.broadcast?.[peerId];
|
||||
if (
|
||||
broadcastAgents &&
|
||||
Array.isArray(broadcastAgents) &&
|
||||
broadcastAgents.length > 0
|
||||
) {
|
||||
const strategy = cfg.routing?.broadcast?.strategy || "parallel";
|
||||
whatsappInboundLog.info(
|
||||
`Broadcasting message to ${broadcastAgents.length} agents (${strategy})`,
|
||||
);
|
||||
|
||||
const processForAgent = (agentId: string) => {
|
||||
const normalizedAgentId = normalizeAgentId(agentId);
|
||||
const agentRoute = {
|
||||
...route,
|
||||
agentId: normalizedAgentId,
|
||||
sessionKey: buildAgentPeerSessionKey({
|
||||
agentId: normalizedAgentId,
|
||||
mainKey: DEFAULT_MAIN_KEY,
|
||||
provider: "whatsapp",
|
||||
peerKind: msg.chatType === "group" ? "group" : "dm",
|
||||
peerId: normalizeId(peerId),
|
||||
}),
|
||||
mainSessionKey: buildAgentMainSessionKey({
|
||||
agentId: normalizedAgentId,
|
||||
mainKey: DEFAULT_MAIN_KEY,
|
||||
}),
|
||||
};
|
||||
|
||||
return processMessage(msg, agentRoute).catch((err) => {
|
||||
whatsappInboundLog.error(
|
||||
`Broadcast agent ${agentId} failed: ${formatError(err)}`,
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
if (strategy === "sequential") {
|
||||
for (const agentId of broadcastAgents) {
|
||||
await processForAgent(agentId);
|
||||
}
|
||||
} else {
|
||||
// Parallel processing (default)
|
||||
await Promise.allSettled(broadcastAgents.map(processForAgent));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return processMessage(msg, route);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user