ADR-007: Selection Plugin Architecture
Status
Accepted
Context
The agent selection system (aragora/routing/selection.py) determines which agents participate in debates and what roles they play. The original implementation hardcoded:
- Scoring algorithm (ELO + domain expertise + calibration)
- Team selection strategy (quality-diversity balance)
- Role assignment logic (domain-based)
This made it difficult to:
- Experiment with alternative selection strategies
- A/B test different algorithms
- Allow users to customize selection behavior
- Add ML-based selection without modifying core code
Decision
Implement a Protocol-based plugin architecture in aragora/plugins/selection/:
Core Protocols
class ScorerProtocol(Protocol):
def score_agent(self, agent, requirements, context) -> float: ...
class TeamSelectorProtocol(Protocol):
def select_team(self, scored_agents, requirements, context) -> list: ...
class RoleAssignerProtocol(Protocol):
def assign_roles(self, team, requirements, context, phase) -> dict: ...
Plugin Registry
@register_scorer("my-scorer")
class MyScorer:
def score_agent(self, agent, requirements, context):
return agent.elo_rating / 2000 # Custom logic
Built-in Strategies
ELOWeightedScorer: Default ELO + expertise scoringDiverseTeamSelector: Quality-diversity balanced selectionGreedyTeamSelector: Simple top-N selectionRandomTeamSelector: Weighted random for explorationDomainBasedRoleAssigner: Expertise-based role assignmentSimpleRoleAssigner: Positional role assignment
SelectionContext
Plugins receive a SelectionContext with:
- Agent pool and profiles
- System integrations (ELO, calibration, probes)
- Performance insights
- Selection history for meta-learning
Consequences
Positive
- Extensibility: New strategies without core changes
- Testability: Strategies can be tested in isolation
- A/B testing: Easy to swap strategies for experiments
- Type safety: Protocol-based design catches errors early
- Discovery: Registry provides introspection of available plugins
Negative
- Complexity: Additional abstraction layer
- Learning curve: Contributors must understand Protocol pattern
- State management: Context must be properly populated
Neutral
- Default behavior unchanged (existing strategies registered as defaults)
- Decorator-based registration is optional (manual registration also works)
- Protocols use
runtime_checkablefor flexibility
Example: Custom ML-Based Scorer
from aragora.plugins.selection import register_scorer, SelectionContext
@register_scorer("ml-scorer")
class MLScorer:
def __init__(self):
self.model = load_model("selection_model.pt")
@property
def name(self) -> str:
return "ml-scorer"
@property
def description(self) -> str:
return "ML-based agent scoring using historical debate outcomes"
def score_agent(self, agent, requirements, context):
features = self._extract_features(agent, requirements)
return self.model.predict(features)
Related
aragora/plugins/selection/- Plugin implementationaragora/routing/selection.py- Original selection systemtests/plugins/test_selection_plugins.py- Plugin tests