Group Chat
Team group chat: GroupChatBroadcaster fan-out, three storm-prevention gates (chain depth / fanout width / total activations), team event topics, and three-panel attribution UI.
Group chat is how a team of agents holds a shared, durable conversation. A user message is dispatched to the team, strategy fires once, @-targets are resolved, the addressed members run, and each member's reply fans out as a team.<id>.message event that the panel renders as an attribution bubble.
Group chat is a team surface.
src/group_chat/provides the multi-persona collaboration session primitive (group_chat.*RPCs) — distinct fromsrc/teams/broadcast/(teams.chat.*RPCs). For how teams, leaders, and Coord Tasks are defined, see Teams.
Overview
Group chat enables:
- Multi-agent conversations — Several agents in one team participate in a single shared thread
- Leader-led strategy — On the team's first message the leader plans first (strategy round 2); the plan is welded into every member's prompt (see Team Strata)
- Targeted addressing —
@<id>addresses one member;@all/@everyoneaddresses the whole roster - Per-agent attribution — Every reply carries its author (agent emoji + display name + a stable per-agent color), replayed from durable history
The GroupChatBroadcaster (src/teams/broadcast/)
GroupChatBroadcaster (src/teams/broadcast/mod.rs) is the engine. A single user message flows through it as a deterministic pipeline — the broadcaster does the routing (state to dispatch); the cognition stays in the leader's and members' prompts.
User message → team
│
▼
GroupChatBroadcaster::dispatch_user
│
├─① Strategy fire-once (round 2)
│ If the team strategy slot is empty, the leader plans first
│ (plan_strategy minted once via atomic put_if_absent) and is
│ welded into every member's prompt for the team's lifetime.
│
├─② Resolve @targets (targets::resolve_targets)
│ @<id> → that member · @all / @everyone → whole roster · tokens
│ not in the roster are dropped. While the strategy slot is empty
│ and `leader_first` is true, the hard gate routes to the leader
│ alone and surfaces the discarded @. Self-@ and `@user` are
│ dropped to prevent self-loops.
│
├─③ Per-member runs (run_member, fan-out)
│ Each addressed member runs with the team strategy + live kanban
│ welded in. Bounded by the three gates:
│ • MAX_CHAIN_DEPTH = 6 (max depth per chain)
│ • MAX_FANOUT_WIDTH = 5 (max agents awakened per round)
│ • MAX_TOTAL_ACTIVATIONS = 32 (global activation cap on the
│ entire fan-out tree)
│ • MEMBER_RUN_TIMEOUT_SECS = 600 (single member run timeout)
│
└─④ Event fan-out
Each member reply is published as team.<id>.message (via
TeamFanoutEmitter / publish_team_event) and persisted to the
team chat history (powers attribution-bubble replay).All three gates are tunable through
BroadcastConfig(src/teams/broadcast/mod.rs); defaults match the bareconsts. The broadcaster is pure scaffolding — it never reasons (R10).
Leader review re-dispatch
When a member submits a deliverable, its Coord Task flips to WaitingReview. The broadcaster diffs the member's tasks against a pre-turn snapshot and, for any newly submitted task, issues a synthetic re-dispatch addressed back to the leader. The accept/reject judgment itself is the leader's task_review turn — the broadcaster only does the deterministic state-to-routing plumbing.
Two RPC layers
Group chat spans two complementary RPC surfaces. They are not merged — each owns a distinct concern:
| Layer | Methods | Owns |
|---|---|---|
| Group-chat session primitive | group_chat.start, group_chat.continue, group_chat.mention, group_chat.end, group_chat.list, group_chat.history | Multi-persona session lifecycle: src/group_chat/orchestrator.rs::GroupChatOrchestrator + session.rs::GroupChatSession |
| Team work-thread | teams.chat.send, teams.chat.thread, teams.chat.history, teams.chat.cancel | Durable per-team thread: src/teams/messages/ (store.rs, inbox.rs, router.rs, mentions.rs, aggregator.rs) |
teams.chat.history(bubbles) andteams.chat.thread(deliverables) are deliberately separate: the panel hydrates the message flow fromhistoryand the workspace pane fromthread. For the fullteams.*surface (create, tasks, snapshots, workflow), see Teams.
At startup the two layers are wired by independent registrars:
src/bin/aleph-server/commands/start/builder/handlers/system.rs::register_group_chat_handlersregistersgroup_chat.*src/bin/aleph-server/commands/start/builder/handlers/agents.rs(team-related RPCs) registersteams.*
Team event topics
The Panel subscribes to team.<id>.* via TeamFanoutEmitter (src/gateway/event_emitter/team_fanout.rs) and renders each subtopic into a different surface:
| Topic | Carries | Rendered as |
|---|---|---|
team.<id>.message | A member reply emitted by the broadcaster fan-out | An attribution bubble in the message flow |
team.<id>.activity | Roster / run status changes | Status dots on the left roster |
team.<id>.task | Coord Task lifecycle updates (CoordTaskStore publishes task.<verb>) | The right workspace (tasks / kanban) |
Panel rendering
The group-chat window is a three-panel layout:
┌──────────────┬───────────────────────────┬──────────────────┐
│ Roster │ Message flow │ Workspace │
│ (left) │ (middle) │ (right, collapsible)
│ │ │ │
│ • leader │ 🐙 Atlas │ ┌ Artifacts ─┐ │
│ badge │ per-agent bubble │ └────────────┘ │
│ • status │ (emoji + display_name + │ ┌ Tasks / ───┐ │
│ dots │ stable hash(agent_id) │ │ Kanban │ │
│ │ color; consecutive │ └────────────┘ │
│ │ same-agent msgs merge) │ │
└──────────────┴───────────────────────────┴──────────────────┘- Left — roster. Team members with a leader badge and live status dots fed by
team.<id>.activity. - Middle — message flow. Attribution bubbles: each shows the author's emoji,
display_name, and a stable color derived fromhash(agent_id); consecutive messages from the same agent merge into one bubble. - Right — workspace (collapsible). Artifacts and a tasks / kanban tab, fed by
team.<id>.taskandteams.chat.thread.
Sidebar and composer
- Group Chats history. The sidebar lists each team chat with a
members_preview(member icons) and last-message snippet. This summary comes fromagents.teams, which augments the team list withmembers_preview+last_message. @auto-complete. Typing@in the composer opens a roster auto-complete palette (@<id>,@all). Mentions resolve byagent_id— tokens not in the roster are dropped.- Auto-naming. A blank-named team (with
set_name_auto=true) is given an LLM-generated name on its first message viatake_auto_name_flag.
src/group_chat/ (multi-persona session primitive)
| Module | Responsibility |
|---|---|
mod.rs | Entry; re-exports GroupChatOrchestrator / GroupChatSession / GroupChatExecutor / PersonaRegistry |
orchestrator.rs | GroupChatOrchestrator + SharedSession: cross-session orchestration |
session.rs | GroupChatSession: single-session state machine |
executor.rs | GroupChatExecutor: turn execution, LLM invocation |
persona.rs | PersonaRegistry: persona metadata |
channel.rs | GroupChatCommandParser / GroupChatRenderer: command parsing + rendering |
protocol.rs | Protocol message types |
coordinator.rs | Multi-persona coordination |
See Also
- Teams — Teams, leader, Coord Tasks, Team Strata, and the full
teams.*RPC surface - A2A — Agent-to-Agent protocol
- Gateway — Channel interfaces
- Teams Concept
- Group Chat Concept
- Gateway RPC
teams.*