Communication¶
Inter-agent messaging: bus, dispatcher, hierarchy resolution, and the multi-agent conversation primitives.
Conversation Enums¶
enums
¶
Conversation domain enumerations.
ConversationRole
¶
Bases: StrEnum
Author of a single conversational turn.
Attributes:
| Name | Type | Description |
|---|---|---|
USER |
A human message into the conversation. |
|
ASSISTANT |
A Chief of Staff reply (generic 1:1 + routed paths). |
|
AGENT |
A named role agent's group-chat contribution; the author
is recorded in the turn's |
ConversationStatus
¶
Bases: StrEnum
Lifecycle state of a Chief of Staff conversation.
Attributes:
| Name | Type | Description |
|---|---|---|
ACTIVE |
Open for further turns; the clarify loop may continue. |
|
PROPOSED |
At least one work item proposed into the approval queue from this conversation. |
|
CLOSED |
Terminal; no further turns are accepted. |
Message¶
message
¶
Message domain models (see Communication design page).
Part
module-attribute
¶
Discriminated union of message content parts.
Pydantic uses the type literal field on each part to determine
which subtype to deserialize into.
TextPart
pydantic-model
¶
Bases: BaseModel
Plain text message content.
Attributes:
| Name | Type | Description |
|---|---|---|
type |
Literal['text']
|
Discriminator literal (always |
text |
NotBlankStr
|
The text content (must not be blank). |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
type(Literal['text']) -
text(NotBlankStr)
DataPart
pydantic-model
¶
Bases: BaseModel
Structured JSON data attached to a message.
The data field is deep-copied and recursively frozen at
construction (dict -> MappingProxyType, list ->
tuple, set -> frozenset) to preserve the immutability
contract of frozen Pydantic models.
Attributes:
| Name | Type | Description |
|---|---|---|
type |
Literal['data']
|
Discriminator literal (always |
data |
MappingProxyType[str, object]
|
Structured JSON content (read-only after construction). |
Config:
frozen:Trueallow_inf_nan:Falsearbitrary_types_allowed:Trueextra:forbid
Fields:
Validators:
-
_deep_copy_and_freeze_data→data
model_copy
¶
Override to re-freeze data when model_copy updates it.
Returns:
| Type | Description |
|---|---|
Self
|
The copied model, with |
Self
|
replaced it. |
Source code in src/synthorg/communication/message.py
FilePart
pydantic-model
¶
Bases: BaseModel
Reference to a file resource.
Attributes:
| Name | Type | Description |
|---|---|---|
type |
Literal['file']
|
Discriminator literal (always |
uri |
NotBlankStr
|
File URI or path. |
mime_type |
NotBlankStr | None
|
Optional MIME type of the file. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
type(Literal['file']) -
uri(NotBlankStr) -
mime_type(NotBlankStr | None)
UriPart
pydantic-model
¶
Bases: BaseModel
Reference to an external URI resource.
Attributes:
| Name | Type | Description |
|---|---|---|
type |
Literal['uri']
|
Discriminator literal (always |
uri |
NotBlankStr
|
The URI or URL. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
type(Literal['uri']) -
uri(NotBlankStr)
MessageMetadata
pydantic-model
¶
Bases: BaseModel
Optional metadata carried with a message.
Extends the Communication design page metadata with an additional extra
field for arbitrary key-value pairs.
Attributes:
| Name | Type | Description |
|---|---|---|
task_id |
NotBlankStr | None
|
Related task identifier. |
project_id |
NotBlankStr | None
|
Related project identifier. |
tokens_used |
int | None
|
LLM tokens consumed producing the message. |
cost |
float | None
|
Estimated cost of the message in the configured currency. |
extra |
tuple[tuple[str, str], ...]
|
Immutable key-value pairs for arbitrary metadata (extension). |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
task_id(NotBlankStr | None) -
project_id(NotBlankStr | None) -
tokens_used(int | None) -
cost(float | None) -
extra(tuple[tuple[str, str], ...])
Validators:
-
_validate_extra
Message
pydantic-model
¶
Bases: BaseModel
An inter-agent message.
Field schema is based on the Communication design page with typed
refinements. The sender field is aliased to "from" for
JSON compatibility with the spec format.
Content is represented as a tuple of typed Part objects
(text, data, file, URI) rather than a flat string, enabling rich
multi-part messages.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
UUID
|
Unique message identifier. |
timestamp |
AwareDatetime
|
When the message was created (must be timezone-aware). |
sender |
NotBlankStr
|
Agent ID of the sender (aliased to |
to |
NotBlankStr
|
Recipient agent or channel identifier. |
type |
MessageType
|
Message type classification. |
priority |
MessagePriority
|
Message priority level. |
channel |
NotBlankStr
|
Channel the message is sent through. |
parts |
tuple[Part, ...]
|
Ordered content parts (text, data, files, URIs). |
metadata |
MessageMetadata
|
Optional message metadata. |
Config:
frozen:Truepopulate_by_name:Trueallow_inf_nan:Falsearbitrary_types_allowed:True
Fields:
-
id(UUID) -
timestamp(AwareDatetime) -
sender(NotBlankStr) -
to(NotBlankStr) -
type(MessageType) -
priority(MessagePriority) -
channel(NotBlankStr) -
parts(tuple[Part, ...]) -
attachments(tuple[Part, ...]) -
metadata(MessageMetadata)
attachments
pydantic-field
¶
Out-of-band parts attached to the message (files, data blobs, URIs) that are not part of the primary content flow. Persisted alongside the message and round-tripped by both backends.
text
property
¶
Extract the first TextPart text, or empty string.
Convenience accessor for consumers that only need the primary text content of a message.
Dispatcher¶
dispatcher
¶
Message dispatcher -- routes incoming messages to registered handlers.
See the Communication design page.
DispatchResult
pydantic-model
¶
Bases: BaseModel
Immutable outcome of dispatching a single message.
Attributes:
| Name | Type | Description |
|---|---|---|
message_id |
UUID
|
The dispatched message's identifier. |
handlers_matched |
int
|
Derived count (succeeded + failed). |
handlers_succeeded |
int
|
Number of handlers that completed without error. |
handlers_failed |
int
|
Number of handlers that raised an exception. |
errors |
tuple[str, ...]
|
Error descriptions from failed handlers. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
message_id(UUID) -
handlers_succeeded(int) -
handlers_failed(int) -
errors(tuple[str, ...])
MessageDispatcher
¶
Per-agent dispatcher that routes messages to registered handlers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
str
|
Identifier of the owning agent (for logging context). |
'unknown'
|
Source code in src/synthorg/communication/dispatcher.py
register
¶
Register a handler for incoming messages.
If handler is a bare async function, it is automatically wrapped
in a :class:FunctionHandler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
handler
|
MessageHandler | MessageHandlerFunc
|
The handler instance or async function. |
required |
message_types
|
frozenset[MessageType] | None
|
Message types to match (empty/None = all). |
None
|
min_priority
|
MessagePriority
|
Minimum priority to accept. |
LOW
|
name
|
str
|
Human-readable label for debugging. |
'unnamed'
|
Returns:
| Type | Description |
|---|---|
str
|
The unique handler registration ID. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If a |
Source code in src/synthorg/communication/dispatcher.py
deregister
¶
Remove a previously registered handler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
handler_id
|
str
|
The registration ID returned by :meth: |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the handler was found and removed, False otherwise. |
Source code in src/synthorg/communication/dispatcher.py
dispatch
async
¶
Route a message to all matching handlers concurrently.
Most handler Exception subclasses are isolated; their
errors are captured into the per-handler errors slot
without affecting siblings. MemoryError and
RecursionError are deliberate carve-outs: the interpreter
is in catastrophic state, so they re-raise to abort the
TaskGroup and cancel all remaining handlers rather than
being absorbed silently. BaseException subclasses (e.g.
KeyboardInterrupt, asyncio.CancelledError) likewise
propagate through the TaskGroup, cancelling all remaining
handlers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
Message
|
The message to dispatch. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
DispatchResult
|
class: |
Source code in src/synthorg/communication/dispatcher.py
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | |
Bus Protocol¶
bus_protocol
¶
Message bus protocol (see Communication design page).
Defines the swappable interface for message bus backends. The
default implementation is :class:InMemoryMessageBus in
synthorg.communication.bus.memory.
QuadraticAlertSink
¶
Bases: Protocol
Receives a human-readable alert when a quadratic window is detected.
alert
async
¶
Deliver an operator alert.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
title
|
str
|
Short alert title. |
required |
body
|
str
|
Human-readable alert body. |
required |
MessageBus
¶
Bases: Protocol
Protocol for message bus backends.
All implementations must support the full lifecycle (start/stop), channel management, pub/sub messaging, direct messaging, and channel history.
Uses a pull model: consumers call :meth:receive to get the
next message rather than registering push callbacks.
is_running
property
¶
Whether the bus client thinks it is running.
Local state check: flipped by :meth:start / :meth:stop.
Does not reflect live server reachability -- use
:meth:health_check for that.
start
async
¶
Start the bus and create pre-configured channels.
Raises:
| Type | Description |
|---|---|
MessageBusAlreadyRunningError
|
If the bus is already running. |
stop
async
¶
health_check
async
¶
Live liveness probe against the underlying transport.
Unlike :attr:is_running, this performs an actual
round-trip to confirm the broker is reachable and the
connection is healthy. Implementations return False
rather than raising when the probe fails, so the caller
can treat the bus as degraded without a try/except.
Source code in src/synthorg/communication/bus_protocol.py
publish
async
¶
Publish a message to its channel.
The target channel is determined by message.channel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
Message
|
The message to publish. |
required |
ttl_seconds
|
float | None
|
Optional per-message TTL in seconds. When set,
the message expires after this duration on the server.
Requires the NATS stream to have |
None
|
Raises:
| Type | Description |
|---|---|
MessageBusNotRunningError
|
If the bus is not running. |
ChannelNotFoundError
|
If the target channel does not exist. |
Source code in src/synthorg/communication/bus_protocol.py
send_direct
async
¶
Send a direct message between two agents.
Lazily creates a DIRECT channel named @{a}:{b} (where
a, b are the sorted agent IDs) and subscribes both agents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
Message
|
The message to send ( |
required |
recipient
|
NotBlankStr
|
The recipient agent ID. |
required |
ttl_seconds
|
float | None
|
Optional per-message TTL in seconds. |
None
|
Raises:
| Type | Description |
|---|---|
MessageBusNotRunningError
|
If the bus is not running. |
ValueError
|
If the recipient does not match
|
Source code in src/synthorg/communication/bus_protocol.py
subscribe
async
¶
Subscribe an agent to a channel.
Idempotent -- returns a fresh subscription record if already subscribed (the channel's subscriber list is not duplicated).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channel_name
|
NotBlankStr
|
Channel to subscribe to. |
required |
subscriber_id
|
NotBlankStr
|
Agent ID of the subscriber. |
required |
Returns:
| Type | Description |
|---|---|
Subscription
|
The subscription record. |
Raises:
| Type | Description |
|---|---|
MessageBusNotRunningError
|
If the bus is not running. |
ChannelNotFoundError
|
If the channel does not exist. |
Source code in src/synthorg/communication/bus_protocol.py
unsubscribe
async
¶
Remove an agent's subscription from a channel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channel_name
|
NotBlankStr
|
Channel to unsubscribe from. |
required |
subscriber_id
|
NotBlankStr
|
Agent ID to remove. |
required |
Raises:
| Type | Description |
|---|---|
MessageBusNotRunningError
|
If the bus is not running. |
NotSubscribedError
|
If the agent is not subscribed. |
Source code in src/synthorg/communication/bus_protocol.py
receive
async
¶
Receive the next message from a channel.
Awaits until a message is available, the timeout expires, or
the bus is stopped. When timeout is None, awaits
indefinitely (or until shutdown).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channel_name
|
NotBlankStr
|
Channel to receive from. |
required |
subscriber_id
|
NotBlankStr
|
Agent ID receiving. |
required |
timeout
|
float | None
|
Seconds to wait before returning |
None
|
Returns:
| Type | Description |
|---|---|
DeliveryEnvelope | None
|
A delivery envelope, or |
Raises:
| Type | Description |
|---|---|
MessageBusNotRunningError
|
If the bus is not running. |
ChannelNotFoundError
|
If the channel does not exist. |
NotSubscribedError
|
If the subscriber is not subscribed (for TOPIC and DIRECT channels). |
Source code in src/synthorg/communication/bus_protocol.py
create_channel
async
¶
Create a new channel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channel
|
Channel
|
Channel definition to create. |
required |
Returns:
| Type | Description |
|---|---|
Channel
|
The created channel. |
Raises:
| Type | Description |
|---|---|
MessageBusNotRunningError
|
If the bus is not running. |
ChannelAlreadyExistsError
|
If a channel with that name already exists. |
Source code in src/synthorg/communication/bus_protocol.py
get_channel
async
¶
Get a channel by name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channel_name
|
NotBlankStr
|
Name of the channel. |
required |
Returns:
| Type | Description |
|---|---|
Channel
|
The channel. |
Raises:
| Type | Description |
|---|---|
ChannelNotFoundError
|
If the channel does not exist. |
Source code in src/synthorg/communication/bus_protocol.py
publish_batch
async
¶
Publish multiple messages in a batch.
Optimised for throughput. In NATS backends, uses pipelined async publishes for reduced round-trip overhead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
Sequence[Message]
|
Messages to publish. An empty sequence is a no-op. |
required |
ttl_seconds
|
float | None
|
Optional per-message TTL applied to every message in the batch. |
None
|
Raises:
| Type | Description |
|---|---|
MessageBusNotRunningError
|
If the bus is not running. |
ChannelNotFoundError
|
If any target channel does not exist. |
Source code in src/synthorg/communication/bus_protocol.py
list_channels
async
¶
set_quadratic_alert_sink
¶
Late-bind an alert sink to the bus's quadratic enforcer, if any.
Boot wiring calls this once the notification dispatcher exists (the bus is built earlier, in the construction phase, so its enforcer starts sink-less). Backends without a quadratic enforcer implement it as a no-op, so wiring never branches on the concrete backend type to reach an enforcer that may not exist.
Source code in src/synthorg/communication/bus_protocol.py
get_channel_history
async
¶
Get message history for a channel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channel_name
|
NotBlankStr
|
Channel to query. |
required |
limit
|
int | None
|
Maximum number of most recent messages to return.
Values |
None
|
Returns:
| Type | Description |
|---|---|
tuple[Message, ...]
|
Messages in chronological order. |
Raises:
| Type | Description |
|---|---|
ChannelNotFoundError
|
If the channel does not exist. |
Source code in src/synthorg/communication/bus_protocol.py
Config¶
config
¶
Communication configuration models (see Communication design page).
MessageRetentionConfig
pydantic-model
¶
Bases: BaseModel
Retention settings for channel message history and subscriber delivery.
Attributes:
| Name | Type | Description |
|---|---|---|
max_messages_per_channel |
int
|
Maximum messages kept per channel
for both in-memory and NATS backends. In-memory backend:
|
max_subscriber_queue_size |
int
|
Maximum in-flight envelopes per
(channel, subscriber). In-memory backend applies a
drop-newest policy with |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
max_messages_per_channel(int) -
max_subscriber_queue_size(int)
NatsConfig
pydantic-model
¶
Bases: BaseModel
NATS JetStream backend configuration.
Only applicable when MessageBusConfig.backend == NATS. See
docs/design/distributed-runtime.md for stream layout and
subject naming.
Attributes:
| Name | Type | Description |
|---|---|---|
url |
NotBlankStr
|
NATS server URL (e.g. |
credentials_path |
str | None
|
Optional path to a credentials file for secured clusters (creds file or jwt+seed). |
stream_name_prefix |
NotBlankStr
|
Prefix for JetStream stream names. The
bus stream is |
connect_timeout_seconds |
float
|
Seconds to wait for the initial connection before raising. |
reconnect_time_wait_seconds |
float
|
Seconds between reconnect attempts. |
max_reconnect_attempts |
int
|
Maximum reconnect attempts before
giving up ( |
publish_ack_wait_seconds |
float
|
Seconds to wait for a JetStream publish ack before considering the publish failed. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
url(NotBlankStr) -
credentials_path(str | None) -
stream_name_prefix(NotBlankStr) -
connect_timeout_seconds(float) -
reconnect_time_wait_seconds(float) -
max_reconnect_attempts(int) -
publish_ack_wait_seconds(float) -
health_flush_timeout_seconds(float)
Validators:
-
_apply_mirrors -
_validate_url→url
stream_name_prefix
pydantic-field
¶
Prefix for JetStream stream names
reconnect_time_wait_seconds
pydantic-field
¶
Seconds between reconnect attempts
max_reconnect_attempts
pydantic-field
¶
Max reconnect attempts (-1 = unlimited)
health_flush_timeout_seconds
pydantic-field
¶
Timeout in seconds for the NATS health-check flush probe. Deliberately tight so a stuck probe fails fast rather than blocking the /healthz endpoint.
QuadraticEnforcementConfig
pydantic-model
¶
Bases: BaseModel
O(n^2) message-overhead enforcement settings for the message bus.
Detection compares the windowed inter-agent message count against
team_size^2 * quadratic_threshold. The strategy decides
what happens when that threshold is crossed (see
:class:~synthorg.communication.enums.QuadraticEnforcementStrategy).
Attributes:
| Name | Type | Description |
|---|---|---|
strategy |
QuadraticEnforcementStrategy
|
Enforcement mode (default |
quadratic_threshold |
float
|
Fraction of |
window_seconds |
float
|
Sliding window over which inter-agent publishes are counted. |
max_agent_connections |
int
|
Participant ceiling enforced under
|
throttle_delay_seconds |
float
|
Publish backpressure delay applied under
|
min_team_size |
int
|
Smallest team for which detection runs; below this the quadratic comparison is noise and is skipped. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
strategy(QuadraticEnforcementStrategy) -
quadratic_threshold(float) -
window_seconds(float) -
max_agent_connections(int) -
throttle_delay_seconds(float) -
min_team_size(int)
strategy
pydantic-field
¶
Quadratic enforcement mode
quadratic_threshold
pydantic-field
¶
Fraction of team_size^2 that marks a window quadratic
window_seconds
pydantic-field
¶
Sliding window for counting inter-agent publishes
max_agent_connections
pydantic-field
¶
Participant ceiling enforced under hard_block
throttle_delay_seconds
pydantic-field
¶
Publish backpressure delay under soft_throttle
MessageBusConfig
pydantic-model
¶
Bases: BaseModel
Message bus backend configuration.
Maps to the Communication design page message_bus.
Attributes:
| Name | Type | Description |
|---|---|---|
backend |
MessageBusBackend
|
Transport backend to use. |
channels |
tuple[NotBlankStr, ...]
|
Pre-defined channel names. |
retention |
MessageRetentionConfig
|
Message retention settings. |
nats |
NatsConfig | None
|
NATS-specific configuration (required when
|
quadratic_enforcement |
QuadraticEnforcementConfig
|
O(n^2) message-overhead enforcement. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
backend(MessageBusBackend) -
channels(tuple[NotBlankStr, ...]) -
retention(MessageRetentionConfig) -
nats(NatsConfig | None) -
quadratic_enforcement(QuadraticEnforcementConfig)
Validators:
-
_validate_channels -
_validate_backend_config
quadratic_enforcement
pydantic-field
¶
O(n^2) message-overhead enforcement settings
HierarchyConfig
pydantic-model
¶
Bases: BaseModel
Hierarchy enforcement configuration.
Maps to the Communication design page hierarchy.
Attributes:
| Name | Type | Description |
|---|---|---|
enforce_chain_of_command |
bool
|
Whether chain-of-command is enforced. |
allow_skip_level |
bool
|
Whether skip-level messaging is allowed. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
enforce_chain_of_command(bool) -
allow_skip_level(bool)
CommunicationConfig
pydantic-model
¶
Bases: BaseModel
Top-level communication configuration.
Aggregates the Communication design page sections under a single model.
Attributes:
| Name | Type | Description |
|---|---|---|
default_pattern |
CommunicationPattern
|
High-level communication pattern. |
message_bus |
MessageBusConfig
|
Message bus configuration. |
hierarchy |
HierarchyConfig
|
Hierarchy enforcement settings. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
default_pattern(CommunicationPattern) -
message_bus(MessageBusConfig) -
hierarchy(HierarchyConfig)
Errors¶
errors
¶
Communication error hierarchy (see Communication design page).
All communication errors carry an immutable context mapping for
structured metadata, following the same pattern as ToolError.
CommunicationError
¶
Bases: DomainError
Base exception for all communication-layer errors.
Attributes:
| Name | Type | Description |
|---|---|---|
message |
Human-readable error description. |
|
context |
MappingProxyType[str, object]
|
Immutable metadata about the error. |
Class Attributes
status_code: HTTP 500 default.
error_code: COMMUNICATION_ERROR.
error_category: INTERNAL.
retryable: False.
is_retryable: False (instance-checkable alias of retryable,
matching the provider / integration error hierarchies so a
retry-decision site can read exc.is_retryable uniformly).
default_message: Generic 5xx-safe message.
Initialize a communication error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
Human-readable error description. |
required |
context
|
Mapping[str, object] | None
|
Arbitrary metadata about the error. Stored as an immutable mapping; defaults to empty if not provided. |
None
|
Source code in src/synthorg/communication/errors.py
__str__
¶
Format error with optional context metadata.
Returns:
| Type | Description |
|---|---|
str
|
The message, suffixed with |
str
|
present. |
Source code in src/synthorg/communication/errors.py
ChannelNotFoundError
¶
Bases: CommunicationError
Requested channel does not exist.
Source code in src/synthorg/communication/errors.py
ChannelAlreadyExistsError
¶
Bases: CommunicationError
Channel with the given name already exists.
Source code in src/synthorg/communication/errors.py
NotSubscribedError
¶
Bases: CommunicationError
Agent is not subscribed to the specified channel.
Source code in src/synthorg/communication/errors.py
MessageBusNotRunningError
¶
Bases: CommunicationError
Operation attempted on a message bus that is not running.
Source code in src/synthorg/communication/errors.py
MessageBusAlreadyRunningError
¶
Bases: CommunicationError
start() called on a message bus that is already running.
Source code in src/synthorg/communication/errors.py
QuadraticConnectionBlockedError
¶
Bases: CommunicationError
A new agent connection is rejected under quadratic hard_block.
Raised by the message bus when the hard_block quadratic
enforcement strategy is active and admitting another agent would
push the live participant count past max_agent_connections.
The category is rate-limit (HTTP 429) so a caller treats it as a
capacity rejection to retry later, not a permanent fault.
Source code in src/synthorg/communication/errors.py
HierarchyResolutionError
¶
Bases: CommunicationError
Error resolving organizational hierarchy.
Source code in src/synthorg/communication/errors.py
Hierarchy¶
delegation_types
¶
The delegation-request model engine classification routes through.
A core domain type (it depends only on :mod:core.task and
:mod:core.types), so it lives in core rather than
communication. Keeping it here lets the engine classification
loaders reference a delegation request without importing the
communication package hub, which would otherwise close an
engine <-> communication cold-import cycle.
DelegationRequest
pydantic-model
¶
Bases: BaseModel
Request to delegate a task down the hierarchy.
Attributes:
| Name | Type | Description |
|---|---|---|
delegator_id |
NotBlankStr
|
Agent ID of the delegator. |
delegatee_id |
NotBlankStr
|
Agent ID of the target agent. |
task |
Task
|
The task to delegate. |
refinement |
str
|
Additional context from the delegator. |
constraints |
tuple[NotBlankStr, ...]
|
Extra constraints for the delegatee. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
delegator_id(NotBlankStr) -
delegatee_id(NotBlankStr) -
task(Task) -
refinement(str) -
constraints(tuple[NotBlankStr, ...]) -
entity_versions(Mapping[str, int] | None)
Validators:
-
_validate_self_delegation
hierarchy
¶
Hierarchy resolver for organizational structure.
HierarchyResolver
¶
Resolves org hierarchy from a Company structure (read-only).
Built from three sources, in priority order:
- Explicit
ReportingLineentries (most specific) -- usessubordinate_key/supervisor_key(which resolve to the_idfield when set, falling back to the name) and overrides team-derived relationships. Team.leadfor team membersDepartment.headfor team leads without explicit reporting (skipped when head isNone)
Detects cycles at construction time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
company
|
Company
|
Frozen company structure to resolve hierarchy from. |
required |
Raises:
| Type | Description |
|---|---|
HierarchyResolutionError
|
If a cycle is detected. |
Source code in src/synthorg/communication/hierarchy.py
get_supervisor
¶
Get the direct supervisor of an agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_name
|
str
|
Agent name or ID (matching the key used by
|
required |
Returns:
| Type | Description |
|---|---|
str | None
|
Supervisor name/ID or |
Source code in src/synthorg/communication/hierarchy.py
get_direct_reports
¶
Get all direct reports of an agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_name
|
str
|
Supervisor agent name or ID. |
required |
Returns:
| Type | Description |
|---|---|
tuple[str, ...]
|
Tuple of direct report agent names/IDs. |
Source code in src/synthorg/communication/hierarchy.py
is_direct_report
¶
Check if subordinate directly reports to supervisor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
supervisor
|
str
|
Supervisor agent name or ID. |
required |
subordinate
|
str
|
Potential subordinate agent name or ID. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if subordinate is a direct report. |
Source code in src/synthorg/communication/hierarchy.py
is_subordinate
¶
Check if subordinate is anywhere below supervisor.
Walks up the hierarchy from subordinate to root.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
supervisor
|
str
|
Supervisor agent name or ID. |
required |
subordinate
|
str
|
Potential subordinate agent name or ID. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if subordinate is below supervisor at any depth. |
Source code in src/synthorg/communication/hierarchy.py
get_ancestors
¶
Get all ancestors from agent up to root.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_name
|
str
|
Agent name or ID to start from. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Tuple of ancestor names/IDs, bottom-up (immediate |
...
|
supervisor first, root last). |
Source code in src/synthorg/communication/hierarchy.py
get_lowest_common_manager
¶
Find the lowest common manager of two agents.
If one agent is an ancestor of the other, that agent is returned as the LCM. When both arguments refer to the same agent, that agent is returned directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_a
|
str
|
First agent name or ID. |
required |
agent_b
|
str
|
Second agent name or ID. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
Name/ID of the lowest common manager, or |
str | None
|
common manager exists. |
Source code in src/synthorg/communication/hierarchy.py
get_delegation_depth
¶
Get hierarchy levels between two agents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_agent
|
str
|
Higher-level agent name or ID (potential supervisor). |
required |
to_agent
|
str
|
Lower-level agent name or ID (potential subordinate). |
required |
Returns:
| Type | Description |
|---|---|
int | None
|
Number of hierarchy levels between them, or None if |
int | None
|
to_agent is not below from_agent. |
Source code in src/synthorg/communication/hierarchy.py
Multi-Agent Conversation¶
protocol
¶
The contract for invoking an agent inside a multi-party conversation.
AgentCaller is the seam between a conversation and the execution
engine: a conversation decides who speaks and with what prompt, and the
caller turns that into a real LLM dispatch. Keeping it a callable rather
than a service means a conversation never imports the engine layer.
AgentCaller
module-attribute
¶
AgentCaller = Callable[[str, str, int, str], Awaitable[AgentResponse]]
Callback to invoke an agent during a conversation.
Signature: (agent_id, prompt, max_tokens, conversation_id) ->
AgentResponse
conversation_id is threaded through so cost-recording attribution
carries the real conversation identifier per turn instead of a synthetic
placeholder.
models
¶
What one agent returned from a single invocation.
AgentResponse
pydantic-model
¶
Bases: BaseModel
Result of a single agent invocation.
Attributes:
| Name | Type | Description |
|---|---|---|
agent_id |
NotBlankStr
|
Identifier of the agent that responded. |
content |
str
|
Text content of the response. |
input_tokens |
int
|
Tokens consumed by the prompt. |
output_tokens |
int
|
Tokens generated in the response. |
cost |
float
|
Estimated cost of the invocation. |
Config:
frozen:Trueallow_inf_nan:Falseextra:forbid
Fields:
-
agent_id(NotBlankStr) -
content(str) -
input_tokens(int) -
output_tokens(int) -
cost(float)
token_tracker
¶
Per-round token budget for a multi-party conversation.
Concurrency note: TokenTracker is safe for use within a single
asyncio event loop (cooperative multitasking). record() runs
to completion without suspension, so concurrent coroutines sharing a
tracker will not interleave reads and writes. However, intermediate
values of remaining during a parallel TaskGroup phase reflect
only the tasks that have completed so far -- callers should pre-divide
budgets before launching parallel work rather than checking
remaining inside concurrent tasks.
TokenTracker
¶
Token budget scoped to a single conversation run.
Consumption only ever grows, and only through :meth:record, which
is where the non-negative check lives. The totals are therefore read
through properties rather than exposed as writable attributes: an
assignment could otherwise move a tally backwards and leave every
later remaining reading a budget nothing spent.
Open a run with budget tokens to spend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
budget
|
int
|
Total token budget for the conversation. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/synthorg/communication/multi_agent/token_tracker.py
record
¶
Record token usage from an agent call.
Logs a warning when token usage exceeds the budget after recording.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_tokens
|
int
|
Prompt tokens consumed (must be >= 0). |
required |
output_tokens
|
int
|
Response tokens generated (must be >= 0). |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If either token count is negative. |
Source code in src/synthorg/communication/multi_agent/token_tracker.py
__repr__
¶
Return the budget and what has been spent against it.
Returns:
| Type | Description |
|---|---|
str
|
A |
Source code in src/synthorg/communication/multi_agent/token_tracker.py
agent_caller
¶
:data:AgentCaller factory for multi-party conversations.
A conversation invokes agents through an :data:AgentCaller callable.
:func:build_agent_caller composes an agent registry (for identity
lookup) with a :class:ProviderRegistry (for LLM dispatch) and runs one
provider.complete() call per invocation.
One turn is one LLM call. Sequencing turns belongs to the conversation; this module runs a single agent's inference.
UnknownConversationAgentError
¶
Bases: NotFoundError
Raised when a conversation invokes an unregistered agent.
Attributes:
| Name | Type | Description |
|---|---|---|
agent_id |
NotBlankStr
|
The agent identifier that was not found in the registry. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If agent_id is blank. The annotation alone binds only inside a Pydantic model. |
Source code in src/synthorg/communication/multi_agent/agent_caller.py
build_agent_caller
¶
Construct an :data:AgentCaller backed by real services.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_registry
|
AgentRegistryProtocol
|
Source of truth for agent identities. |
required |
provider_registry
|
ProviderRegistry
|
Source of truth for LLM providers. |
required |
cost_tracker
|
CostTrackerProtocol | None
|
Optional cost tracker; when wired each turn records via the chokepoint. |
None
|
Returns:
| Type | Description |
|---|---|
AgentCaller
|
An async callback matching the :data: |
Source code in src/synthorg/communication/multi_agent/agent_caller.py
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | |