Skip to content
tnsaiDocs
GitHub

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.

TopologyBuilderRuns work with
TeamTeam.builder()execute(task), executeAsync(task)
PipelinePipelineOrganization.builder()execute(input)
Hub and spokeHubSpoke.builder()routeToSpoke(task)
HierarchyHierarchy.builder()delegate(task, level), escalate(task, fromAgentId)
SwarmSwarm.builder()explore(task), solve(problem)
CoalitionCoalition.builder()negotiate(), then achieve()
MatrixMatrixOrganization.builder()executeInDimension(dimension, task)
Network meshNetworkMesh.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.

RoleAuthorityParticipatesDescription
LEADYesYesCoordinates and delegates, final decision authority
CO_LEADYesYesAssists lead, takes over if lead unavailable
MEMBERNoYesExecutes assigned tasks
EXPERTNoYesSubject matter expert, consulted for specialized knowledge
REVIEWERNoYesValidates output, quality control
OBSERVERNoNoMonitors but does not participate
FACILITATORYesYesCoordinates discussions

Team formations

The formation controls how the team runs a task.

FormationDescriptionRequires LeadOrdered
PARALLELAll members work simultaneouslyNoNo
SEQUENTIALMembers work in sequence, passing contextNoYes
HIERARCHICALLead coordinates and delegatesYesNo
ADAPTIVEAdapts based on task complexityNoNo
DEBATEMembers discuss and debate to consensusNoNo
ROUND_ROBINMembers take turns adding perspectiveNoYes

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

StrategyDescription
ROUND_ROBINCycles through spokes in order
LEAST_LOADEDPicks spoke with fewest active tasks
RANDOMRandom 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, timestamp

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

BehaviorUses PheromonesRequires NeighborsBest For
EXPLORATIONYesNoInformation gathering, search
FORAGINGYesYesResource collection, optimization
FLOCKINGNoYesCoordinated movement
AGGREGATIONYesYesConsensus building, clustering
TASK_ALLOCATIONNoNoDivision of labor
DIFFUSIONNoYesDistributed computation
QUORUM_SENSINGNoYesCollective 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.

TypeDefault IntensityPurpose
ATTRACTION1.0Marks interesting locations
REPULSION0.8Marks areas to avoid
TRAIL0.9Path markers for ACO
COMPLETION0.5Prevents redundant work
RECRUITMENT1.2Calls for help
WARNING0.7Signals potential issues
QUALITY1.0Indicates solution quality
CUSTOM1.0User-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

FormationSelection-BasedDescription
VOLUNTARYNoAgents choose to participate
CAPABILITY_BASEDYesSelected by matching capabilities
REPUTATION_BASEDYesSelected by past performance
AUCTIONNoAgents bid for participation
RANDOMNoRandom selection from pool
INVITATIONYesCoordinator invites specific agents
MERIT_BASEDYesCombined capability + reputation score

Reward distribution

StrategyDescription
EQUALSame share for all members
PROPORTIONALBased on contribution ratio
SHAPLEYFair division based on marginal contribution to all sub-coalitions
NUCLEOLUSMinimizes maximum dissatisfaction (10% floor + 90% proportional)
PERFORMANCE_BASEDBased on task performance quality
SENIORITY_BASEDHigher share for earlier joiners
WINNER_TAKE_ALLBest 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.

TopologyConnections
FULL_MESHEvery agent to every other
PARTIAL_MESHEach agent to the next two members
RINGEach agent to the next, in a circle
STARThe first member to all others