Protocol-first (Recommended)
Define typing.Protocol interfaces for every boundary. Implementations plug in. No inheritance coupling. Maximum TDD ergonomics.
class LLMProvider(Protocol):
async def complete(self, messages, **kw) -> str: ...
class Agent(Protocol):
async def run(self, task, ctx) -> AgentResult: ...
class Pattern(Protocol):
async def execute(self, agents, task, ctx) -> SwarmResult: ...
# Test with simple mock — no mocking framework needed
class FakeProvider:
async def complete(self, messages, **kw): return "ok"
Pros
- TDD-native: mock = any object with right methods
- Zero coupling between layers
- Add providers/patterns without touching core
Cons
- No IDE autocomplete on Protocol attrs (minor)
- Slightly less familiar to beginners