Group topologies
tnsai-coordination provides eight group topologies. Each has a builder, and every group shares the AgentGroup lifecycle: start(), stop() and dissolve(). Pick the topology from the task, not from an org chart; Choose a topology explains how.
| Topology | Builder | Runs work with |
|---|---|---|
| Team | Team.builder() | execute(task), executeAsync(task) |
| Pipeline | PipelineOrganization.builder() | execute(input) |
| Hub and spoke | HubSpoke.builder() | routeToSpoke(task) |
| Hierarchy | Hierarchy.builder() | delegate(task, level), escalate(task, fromAgentId) |
| Swarm | Swarm.builder() | explore(task), solve(problem) |
| Coalition | Coalition.builder() | negotiate(), then achieve() |
| Matrix | MatrixOrganization.builder() | executeInDimension(dimension, task) |
| Network mesh | NetworkMesh.builder() | routeMessage(from, to, message), broadcastMessage(message) |
Team
A team groups agents by role and runs a task with a formation.
Team roles
A role sets an agent's authority and whether it takes part in execution.
| Role | Authority | Participates | Description |
|---|---|---|---|
LEAD | Yes | Yes | Coordinates and delegates, final decision authority |
CO_LEAD | Yes | Yes | Assists lead, takes over if lead unavailable |
MEMBER | No | Yes | Executes assigned tasks |
EXPERT | No | Yes | Subject matter expert, consulted for specialized knowledge |
REVIEWER | No | Yes | Validates output, quality control |
OBSERVER | No | No | Monitors but does not participate |
FACILITATOR | Yes | Yes | Coordinates discussions |
Team formations
The formation controls how the team runs a task.
| Formation | Description | Requires Lead | Ordered |
|---|---|---|---|
PARALLEL | All members work simultaneously | No | No |
SEQUENTIAL | Members work in sequence, passing context | No | Yes |
HIERARCHICAL | Lead coordinates and delegates | Yes | No |
ADAPTIVE | Adapts based on task complexity | No | No |
DEBATE | Members discuss and debate to consensus | No | No |
ROUND_ROBIN | Members take turns adding perspective | No | Yes |
Building a team
Team team = Team.builder()
.name("Analysis Team")
.mission("Analyze customer data and produce insights")
.timeout(Duration.ofMinutes(30))
.formation(TeamFormation.PARALLEL)
.lead(coordinatorAgent)
.member(analystAgent, TeamRole.EXPERT)
.member(writerAgent, TeamRole.MEMBER)
.member(reviewerAgent, TeamRole.REVIEWER)
.autoStart(true)
.build();With the HIERARCHICAL formation and no lead set, the first member becomes the lead.
Pipeline
A pipeline runs stages in a fixed order, and each stage's output becomes the next stage's input.
PipelineOrganization pipeline = PipelineOrganization.builder()
.name("ETL Pipeline")
.addStage("extract", extractorAgent)
.addStage("transform", transformerAgent)
.addStage("validate", validatorAgent)
.addStage("load", loaderAgent)
.autoStart(true)
.build();getStages() returns the stages as Stage(name, agentId, index, transformFunction) records.
Pipeline metrics
The pipeline records each stage's duration, run count and failure count.
PipelineMetrics metrics = pipeline.getPipelineMetrics();
// Per-stage stats
Optional<Duration> avgDuration = metrics.getAverageDuration("transform");
int executions = metrics.getExecutionCount("transform");
int failures = metrics.getFailureCount("transform");
// Bottleneck detection
Optional<String> bottleneck = metrics.getBottleneck(); // stage with highest avg duration
// Full summary
Map<String, String> summary = metrics.getSummary();
// {"extract": "executions=10, failures=0, avgMs=250", ...}Hub and spoke
A hub agent routes each task to one spoke agent, chosen by a load-balancing strategy.
HubSpoke hs = HubSpoke.builder()
.name("Task Distributor")
.hub(coordinatorAgent)
.spoke(worker1)
.spoke(worker2)
.spoke(worker3)
.loadBalancing(LoadBalancer.Strategy.LEAST_LOADED)
.autoStart(true)
.build();Load-balancing strategies
| Strategy | Description |
|---|---|
ROUND_ROBIN | Cycles through spokes in order |
LEAST_LOADED | Picks spoke with fewest active tasks |
RANDOM | Random spoke selection |
The LoadBalancer tracks active task counts per agent via recordTaskAssigned() and recordTaskCompleted().
Hierarchy
A hierarchy is a tree of reporting lines. Tasks flow down by delegation and issues flow up by escalation.
Hierarchy hierarchy = Hierarchy.builder()
.name("Engineering Org")
.root(ctoAgent)
.member(ctoAgent, teamLead1)
.member(ctoAgent, teamLead2)
.member(teamLead1, dev1)
.member(teamLead1, dev2)
.member(teamLead2, dev3)
.autoStart(true)
.build();Delegation chain
getDelegationChain() returns a log of delegations and escalations.
DelegationChain chain = hierarchy.getDelegationChain();
chain.record("cto", "team-lead-1", "Review the API design", DelegationChain.Type.DELEGATION);
chain.record("dev-1", "team-lead-1", "Need architecture review", DelegationChain.Type.ESCALATION);
List<DelegationChain.Entry> entries = chain.getEntries();
// Each entry: fromAgentId, toAgentId, task, type, timestampParent and child links on an agent
Each Agent also keeps its own parent and children. addChild and addChildren set both sides of the link. delegateToChild and escalateToParent send a REQUEST message naming an action and its parameters, and the receiving agent runs the action and replies with a RESPONSE. Both need a communication manager: HierarchyBuilder.from(root) gives every agent in the tree the same one.
package com.example.tnsai.docs;
import com.tnsai.agents.Agent;
import com.tnsai.agents.hierarchy.HierarchyBuilder;
import com.tnsai.communication.AgentCommunicationManager;
import java.util.Map;
public final class HierarchyDelegationExample {
private HierarchyDelegationExample() {}
static AgentCommunicationManager link(Agent supervisor, Agent developer, Agent tester) {
// Sets both sides of each link: developer.getParent() == supervisor.
supervisor.addChildren(developer, tester);
// Gives every agent in the tree one shared communication manager.
return HierarchyBuilder.from(supervisor);
}
static void delegate(Agent supervisor, Agent developer) {
// The child runs the action and replies with a RESPONSE message.
supervisor.delegateToChild(developer.id(), "writeCode",
Map.of("task", "Implement authentication"));
}
static void escalate(Agent developer) {
developer.escalateToParent("requestApproval",
Map.of("reason", "Production deployment needs sign-off"));
}
}delegateToChild throws NoSuchElementException when the id is not a child. Both methods throw IllegalStateException when the agent has no communication manager, and escalateToParent also throws it when the agent has no parent.
Swarm
A swarm has no central coordinator. Agents coordinate through pheromones and their neighbors.
Swarm swarm = Swarm.builder()
.name("Explorer Swarm")
.behavior(SwarmBehavior.EXPLORATION)
.intelligence(SwarmIntelligence.antColony(0.5, 0.3))
.neighborDetection(NeighborDetection.random())
.neighborRadius(5)
.pheromoneDecay(0.15)
.add(agent1, agent2, agent3, agent4, agent5)
.build();Swarm behaviors
| Behavior | Uses Pheromones | Requires Neighbors | Best For |
|---|---|---|---|
EXPLORATION | Yes | No | Information gathering, search |
FORAGING | Yes | Yes | Resource collection, optimization |
FLOCKING | No | Yes | Coordinated movement |
AGGREGATION | Yes | Yes | Consensus building, clustering |
TASK_ALLOCATION | No | No | Division of labor |
DIFFUSION | No | Yes | Distributed computation |
QUORUM_SENSING | No | Yes | Collective decision making |
Swarm intelligence
The intelligence combines the agents' results into one answer.
SwarmIntelligence.voting() // Simple voting, first complete solution wins
SwarmIntelligence.consensus() // Weighted averaging (max 10 iterations)
SwarmIntelligence.bestSelection() // Best-of-N based on quality scores
SwarmIntelligence.antColony(0.5, 0.3) // ACO with pheromoneWeight and explorationRate
SwarmIntelligence.iterativeRefinement() // Each agent improves on previous (max 5 iterations)Pheromone types
Pheromones are signals left at a location for other agents.
| Type | Default Intensity | Purpose |
|---|---|---|
ATTRACTION | 1.0 | Marks interesting locations |
REPULSION | 0.8 | Marks areas to avoid |
TRAIL | 0.9 | Path markers for ACO |
COMPLETION | 0.5 | Prevents redundant work |
RECRUITMENT | 1.2 | Calls for help |
WARNING | 0.7 | Signals potential issues |
QUALITY | 1.0 | Indicates solution quality |
CUSTOM | 1.0 | User-defined |
Coalition
A coalition is a temporary group formed around one goal. It negotiates membership, works toward the goal and splits a reward by contribution.
Coalition coalition = Coalition.builder()
.goal("Complete market analysis")
.formation(CoalitionFormation.CAPABILITY_BASED)
.rewardDistribution(RewardDistribution.SHAPLEY)
.coalitionValue(100.0)
.minMembers(2)
.maxMembers(5)
.add(agent1, agent2, agent3)
.autoNegotiate(true)
.build();Coalition formations
| Formation | Selection-Based | Description |
|---|---|---|
VOLUNTARY | No | Agents choose to participate |
CAPABILITY_BASED | Yes | Selected by matching capabilities |
REPUTATION_BASED | Yes | Selected by past performance |
AUCTION | No | Agents bid for participation |
RANDOM | No | Random selection from pool |
INVITATION | Yes | Coordinator invites specific agents |
MERIT_BASED | Yes | Combined capability + reputation score |
Reward distribution
| Strategy | Description |
|---|---|
EQUAL | Same share for all members |
PROPORTIONAL | Based on contribution ratio |
SHAPLEY | Fair division based on marginal contribution to all sub-coalitions |
NUCLEOLUS | Minimizes maximum dissatisfaction (10% floor + 90% proportional) |
PERFORMANCE_BASED | Based on task performance quality |
SENIORITY_BASED | Higher share for earlier joiners |
WINNER_TAKE_ALL | Best performer gets 70%, rest share 30% |
Map<String, Double> contributions = Map.of("agent-1", 40.0, "agent-2", 35.0, "agent-3", 25.0);
Map<String, Double> rewards = RewardDistribution.SHAPLEY.calculate(100.0, contributions);Matrix
In a matrix, an agent can belong to several dimensions at once, each with its own lead.
MatrixOrganization matrix = MatrixOrganization.builder()
.name("Product Org")
.member(dev1)
.member(dev2)
.member(engLead)
.member(productLead)
.assign(dev1, "Engineering", engLead)
.assign(dev1, "Product-A", productLead)
.assign(dev2, "Engineering", engLead)
.assign(dev2, "Product-B", productLead)
.autoStart(true)
.build();Agents can be assigned to a dimension with or without a lead: .assign(agent, "QA") omits the lead parameter.
Network mesh
A network mesh connects agents peer to peer. The topology sets which agents connect directly.
NetworkMesh mesh = NetworkMesh.builder()
.name("Agent Network")
.topology(Topology.FULL_MESH)
.add(agent1, agent2, agent3, agent4)
.autoStart(true)
.build();Mesh shapes
build() wires the connections for the chosen shape.
Topology | Connections |
|---|---|
FULL_MESH | Every agent to every other |
PARTIAL_MESH | Each agent to the next two members |
RING | Each agent to the next, in a circle |
STAR | The first member to all others |