Aleph
Architecture

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 from src/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 / @everyone addresses 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 bare consts. 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:

LayerMethodsOwns
Group-chat session primitivegroup_chat.start, group_chat.continue, group_chat.mention, group_chat.end, group_chat.list, group_chat.historyMulti-persona session lifecycle: src/group_chat/orchestrator.rs::GroupChatOrchestrator + session.rs::GroupChatSession
Team work-threadteams.chat.send, teams.chat.thread, teams.chat.history, teams.chat.cancelDurable per-team thread: src/teams/messages/ (store.rs, inbox.rs, router.rs, mentions.rs, aggregator.rs)

teams.chat.history (bubbles) and teams.chat.thread (deliverables) are deliberately separate: the panel hydrates the message flow from history and the workspace pane from thread. For the full teams.* 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_handlers registers group_chat.*
  • src/bin/aleph-server/commands/start/builder/handlers/agents.rs (team-related RPCs) registers teams.*

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:

TopicCarriesRendered as
team.<id>.messageA member reply emitted by the broadcaster fan-outAn attribution bubble in the message flow
team.<id>.activityRoster / run status changesStatus dots on the left roster
team.<id>.taskCoord 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 from hash(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>.task and teams.chat.thread.
  • Group Chats history. The sidebar lists each team chat with a members_preview (member icons) and last-message snippet. This summary comes from agents.teams, which augments the team list with members_preview + last_message.
  • @ auto-complete. Typing @ in the composer opens a roster auto-complete palette (@<id>, @all). Mentions resolve by agent_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 via take_auto_name_flag.

src/group_chat/ (multi-persona session primitive)

ModuleResponsibility
mod.rsEntry; re-exports GroupChatOrchestrator / GroupChatSession / GroupChatExecutor / PersonaRegistry
orchestrator.rsGroupChatOrchestrator + SharedSession: cross-session orchestration
session.rsGroupChatSession: single-session state machine
executor.rsGroupChatExecutor: turn execution, LLM invocation
persona.rsPersonaRegistry: persona metadata
channel.rsGroupChatCommandParser / GroupChatRenderer: command parsing + rendering
protocol.rsProtocol message types
coordinator.rsMulti-persona coordination

See Also

On this page