Skip to content

ChannelAdapter

autogen.beta.network.adapters.base.ChannelAdapter #

Bases: Protocol

Code half of the manifest/adapter split.

Adapters are looked up at channel-create time by (manifest.type, manifest.version). Re-registering an adapter at a new version does not retroactively change in-flight channels — they keep their original manifest snapshot.

manifest instance-attribute #

manifest

initial_state #

initial_state(metadata)

Empty state for a fresh channel.

Source code in autogen/beta/network/adapters/base.py
def initial_state(self, metadata: ChannelMetadata) -> AdapterState:
    """Empty state for a fresh channel."""
    ...

fold #

fold(envelope, state)

Append envelope into the derived state. Pure function.

Called once per WAL append by the hub. Must be deterministic so Hub.hydrate() can re-fold from disk.

Source code in autogen/beta/network/adapters/base.py
def fold(self, envelope: Envelope, state: AdapterState) -> AdapterState:
    """Append ``envelope`` into the derived state. Pure function.

    Called once per WAL append by the hub. Must be deterministic so
    ``Hub.hydrate()`` can re-fold from disk.
    """
    ...

validate_create #

validate_create(metadata)

Raise on invalid creation (bad participant count, missing knobs, ...).

Source code in autogen/beta/network/adapters/base.py
def validate_create(self, metadata: ChannelMetadata) -> None:
    """Raise on invalid creation (bad participant count, missing knobs, ...)."""
    ...

validate_send #

validate_send(metadata, envelope, state)

Raise if this envelope is not allowed by the protocol at this point.

Receives state BEFORE fold(envelope, ...) runs.

Source code in autogen/beta/network/adapters/base.py
def validate_send(
    self,
    metadata: ChannelMetadata,
    envelope: Envelope,
    state: AdapterState,
) -> None:
    """Raise if this envelope is not allowed by the protocol at this point.

    Receives state BEFORE ``fold(envelope, ...)`` runs.
    """
    ...

on_accepted #

on_accepted(metadata, envelope, state)

Decide post-accept transitions.

Receives state AFTER fold(envelope, ...) has run.

Source code in autogen/beta/network/adapters/base.py
def on_accepted(
    self,
    metadata: ChannelMetadata,
    envelope: Envelope,
    state: AdapterState,
) -> AdapterResult:
    """Decide post-accept transitions.

    Receives state AFTER ``fold(envelope, ...)`` has run.
    """
    ...

expected_next #

expected_next(metadata, state)

Identify the participant the protocol expects to act next.

Free-form channels (no turn ordering) and channels that have completed their protocol cycle return None. Turn-taking adapters return ExpectedTurn(agent_id, triggering_envelope_id) so the hub can answer pending_turns_for(agent_id) and a reconnecting client can re-fire its notify handler against the triggering envelope.

Source code in autogen/beta/network/adapters/base.py
def expected_next(
    self,
    metadata: ChannelMetadata,
    state: AdapterState,
) -> "ExpectedTurn | None":
    """Identify the participant the protocol expects to act next.

    Free-form channels (no turn ordering) and channels that have
    completed their protocol cycle return ``None``. Turn-taking
    adapters return ``ExpectedTurn(agent_id, triggering_envelope_id)``
    so the hub can answer ``pending_turns_for(agent_id)`` and a
    reconnecting client can re-fire its notify handler against the
    triggering envelope.
    """
    ...

default_view_policy #

default_view_policy(metadata, participant_id)

Per-participant default projection for this channel type.

Source code in autogen/beta/network/adapters/base.py
def default_view_policy(
    self,
    metadata: ChannelMetadata,
    participant_id: str,
) -> ViewPolicy:
    """Per-participant default projection for this channel type."""
    ...

extract_turn_input #

extract_turn_input(envelope)

Decode an inbound substantive envelope into the input the next speaker's LLM should receive on its turn.

Return None (or empty string) for envelopes this adapter doesn't act on — the handler will skip the round.

The default behaviour (default_extract_turn_input) handles EV_TEXT. Adapters that emit additional substantive event types (e.g. EV_PACKET for the workflow adapter) override to decode those.

Source code in autogen/beta/network/adapters/base.py
def extract_turn_input(self, envelope: Envelope) -> "str | Input | list[Input] | None":
    """Decode an inbound substantive envelope into the input the
    next speaker's LLM should receive on its turn.

    Return ``None`` (or empty string) for envelopes this adapter
    doesn't act on — the handler will skip the round.

    The default behaviour (``default_extract_turn_input``) handles
    ``EV_TEXT``. Adapters that emit additional substantive event
    types (e.g. ``EV_PACKET`` for the workflow adapter) override
    to decode those.
    """
    ...

build_round_envelope #

build_round_envelope(metadata, sender_id, reply, events, state, hub)

Build the envelope that captures one Agent.ask round.

Called by the handler after Agent.ask returns. Adapters encode the round result into the envelope shape they expect: the default (default_build_round_envelope) emits EV_TEXT(reply.body) if non-empty, else None (silent round, no envelope posted).

Returning None means "this round produced nothing worth recording" — the caller skips the post.

Source code in autogen/beta/network/adapters/base.py
def build_round_envelope(
    self,
    metadata: ChannelMetadata,
    sender_id: str,
    reply: "AgentReply",
    events: "list[BaseEvent]",
    state: AdapterState,
    hub: "Hub",
) -> Envelope | None:
    """Build the envelope that captures one ``Agent.ask`` round.

    Called by the handler after ``Agent.ask`` returns. Adapters
    encode the round result into the envelope shape they expect:
    the default (``default_build_round_envelope``) emits
    ``EV_TEXT(reply.body)`` if non-empty, else ``None`` (silent
    round, no envelope posted).

    Returning ``None`` means "this round produced nothing worth
    recording" — the caller skips the post.
    """
    ...

render_envelope #

render_envelope(envelope)

Project envelope to its LLM-visible string for view policies.

Called by ViewPolicy.project once per envelope in the WAL slice the participant should see. Adapters that emit only EV_TEXT delegate to default_render_envelope; adapters with richer round-end shapes (e.g. WorkflowAdapter with EV_PACKET) handle their own types and fall through to the default for the universal cases.

Returning None means "skip this envelope in the projection" (non-substantive event types, malformed payload, etc.).

Source code in autogen/beta/network/adapters/base.py
def render_envelope(self, envelope: Envelope) -> str | None:
    """Project ``envelope`` to its LLM-visible string for view policies.

    Called by ``ViewPolicy.project`` once per envelope in the WAL
    slice the participant should see. Adapters that emit only
    ``EV_TEXT`` delegate to ``default_render_envelope``; adapters
    with richer round-end shapes (e.g. ``WorkflowAdapter`` with
    ``EV_PACKET``) handle their own types and fall through to
    the default for the universal cases.

    Returning ``None`` means "skip this envelope in the projection"
    (non-substantive event types, malformed payload, etc.).
    """
    ...

tools_for #

tools_for(client, metadata, state, participant_id)

Return the LLM tools this adapter offers a participant.

Resolved per turn by the default notify handler and merged into the per-call tools= override passed to agent.ask. Adapters that take no LLM input (e.g. workflow, where handoff tools are user-authored) return [].

Adapters gate on state and participant_id — e.g. the discussion adapter offers say only when it is this participant's round; consulting offers say only to the participant whose turn it is in the 1Q1R handshake.

Source code in autogen/beta/network/adapters/base.py
def tools_for(
    self,
    client: "AgentClient",
    metadata: ChannelMetadata,
    state: AdapterState,
    participant_id: str,
) -> "list[Tool]":
    """Return the LLM tools this adapter offers a participant.

    Resolved per turn by the default notify handler and merged
    into the per-call ``tools=`` override passed to ``agent.ask``.
    Adapters that take no LLM input (e.g. workflow, where handoff
    tools are user-authored) return ``[]``.

    Adapters gate on ``state`` and ``participant_id`` — e.g. the
    discussion adapter offers ``say`` only when it is this
    participant's round; consulting offers ``say`` only to the
    participant whose turn it is in the 1Q1R handshake.
    """
    ...

build_text_envelope #

build_text_envelope(channel_id, sender_id, text, *, audience=None, causation_id=None)

Construct an EV_TEXT envelope shaped for this adapter.

Layer-2 helper — any client (AG2 AgentClient, HumanClient, non-AG2 bridge) uses this to build correctly-shaped envelopes without going through the LLM tool decorator system. Default impl (default_build_text_envelope) is what consulting / conversation / discussion adapters use; workflow overrides to wrap text in EV_PACKET.

Source code in autogen/beta/network/adapters/base.py
def build_text_envelope(
    self,
    channel_id: str,
    sender_id: str,
    text: str,
    *,
    audience: list[str] | None = None,
    causation_id: str | None = None,
) -> Envelope:
    """Construct an ``EV_TEXT`` envelope shaped for this adapter.

    Layer-2 helper — any client (AG2 ``AgentClient``, ``HumanClient``,
    non-AG2 bridge) uses this to build correctly-shaped envelopes
    without going through the LLM tool decorator system. Default
    impl (``default_build_text_envelope``) is what consulting /
    conversation / discussion adapters use; workflow overrides to
    wrap text in ``EV_PACKET``.
    """
    ...

build_packet_envelope #

build_packet_envelope(channel_id, sender_id, body, *, handoff=None, context_set=None, audience=None, causation_id=None)

Construct an EV_PACKET envelope shaped for this adapter.

Layer-2 helper. Workflow uses handoff / context_set to encode routing + variable mutations into one atomic round capture; other adapters typically delegate to default_build_packet_envelope (no handoff, no context_set).

Source code in autogen/beta/network/adapters/base.py
def build_packet_envelope(
    self,
    channel_id: str,
    sender_id: str,
    body: str,
    *,
    handoff: "Handoff | None" = None,
    context_set: dict | None = None,
    audience: list[str] | None = None,
    causation_id: str | None = None,
) -> Envelope:
    """Construct an ``EV_PACKET`` envelope shaped for this adapter.

    Layer-2 helper. Workflow uses ``handoff`` / ``context_set`` to
    encode routing + variable mutations into one atomic round
    capture; other adapters typically delegate to
    ``default_build_packet_envelope`` (no handoff, no context_set).
    """
    ...