Communication Coordination¶
How agents coordinate during multi-agent interactions: delegation loops are blocked, and known multi-agent failure modes carry explicit guardrails.
See also: Communication (transport), A2A Gateway (federation), Event Stream (SSE + HITL).
Delegation Depth and Cycle Guard¶
Blocking sub-agent delegation (engine/delegation/) is bounded by one guard
rather than a persisted per-pair state machine. Before a supervisor's
delegate_and_await tool spawns a child agent, InProcessSubAgentRunner
(engine/delegation/runner.py) walks the task's parent-task chain and
refuses when either condition holds:
| Condition | Check | Default |
|---|---|---|
| Chain depth | Refuse at or past engine.delegation_max_depth |
5 |
| Cycle | The target agent already appears as an ancestor task's assignee (including self-delegation) | Always on |
Both checks run in one pass over the parent-task chain, bounded by
max_depth + 1 iterations. There is no separate persisted state to expire
or rehydrate: the chain itself, walked from the task graph, is the state. A
refusal raises SubAgentDelegationDepthExceededError, surfaced to the
supervisor as an ordinary tool failure on its next turn.
Two further caps apply to the child run itself, both read live per
delegation: engine.delegation_max_turns bounds the child's own turn count,
and engine.delegation_timeout_seconds bounds its wall-clock run (0
means no limit). engine.delegation_enabled is the feature's kill switch.
Delegation depth configuration
This mechanism is unrelated to coordination.max_delegation_rounds, which
bounds the coordinator's own re-planning rounds rather than sub-agent
delegation depth.
MCP Service Facades¶
The communication domain exposes four service facades on AppState for
MCP handler shims. Each is a thin wrapper; audit logging lives in the
facade rather than in the handler or the repository.
| Facade | Module | Tools shimmed |
|---|---|---|
MessageService |
synthorg.communication.messages.service |
synthorg_messages_list/_get/_send/_delete |
ConnectionService |
synthorg.integrations.connections.mcp_service |
synthorg_connections_list/_get/_create/_delete/_check_health |
WebhookService |
synthorg.integrations.webhooks.service |
synthorg_webhooks_list/_get/_create/_update/_delete |
TunnelService |
synthorg.integrations.tunnel.mcp_service |
synthorg_tunnel_get_status/_connect |
See docs/design/tools.md "SynthOrg MCP Tool Surface" for the handler
envelope contract. Deep-schema writes (create / update) use the Pydantic
pass-through pattern: the MCP tool's inputSchema is generated from the
same model the REST controller uses, so the wire contracts cannot drift.
Multi-Agent Failure Pattern Guardrails¶
See also: Multi-Agent Failure Audit and S1 Multi-Agent Architecture Decision.
External research on multi-agent failure modes reports swarm topologies (agents coordinating with no fixed structure) failing markedly more often than orchestrated ones with defined agent boundaries. The guardrails below exist because the same drift can appear inside an orchestrated system too when those boundaries are not maintained: they reduce the drift rather than removing it. This section documents the guardrails and the known risks.
Group Conversation Safety¶
Multi-party agent conversations are bounded by TokenTracker
(communication/multi_agent/token_tracker.py), which holds a hard per-round
token budget and refuses the next turn once it is spent. The caller contract
(communication/multi_agent/protocol.py) is explicit about a missing
dependency: an unconfigured caller raises rather than returning an empty
response, so a wiring gap surfaces instead of producing meaningless
participation.
Delegation Guard¶
Swarm drift via sub-agent delegation is bounded by the ancestry + depth guard
described above (engine/delegation/runner.py): a chain deeper than
engine.delegation_max_depth, or a target that already appears as an
ancestor's assignee, is refused before the child agent is spawned.
Microservices Anti-Patterns: Assessment¶
| Pattern | SynthOrg Risk | Mitigation |
|---|---|---|
| Chatty interfaces | Low; detected via MessageOverhead.is_quadratic |
Detection exists; no enforcement circuit breaker |
| Distributed monolith | None; async pull message bus, no synchronous coupling | |
| Ownership ambiguity | None; TaskEngine single-writer actor | |
| Cascading failure | Low; fail_fast bounds wave propagation |
No upstream contamination detection |