Skip to content

DiscussionAdapter

autogen.beta.network.adapters.discussion.DiscussionAdapter #

DiscussionAdapter()

Multi-participant turn-taking channel with round_robin ordering.

Participants: 2+ (no upper bound). Initiator (order=0) speaks first; turns rotate through metadata.participants in order, cycling back after the last participant.

Knobs: {"ordering": "round_robin"} (default). Unsupported orderings are rejected at create time.

Default view: :class:NamedWindowedSummary(recent_n=N*2) where N = participant count — keeps prompt size bounded at any turn count AND prefixes each non-self projection line with the sender's name so the LLM can tell its peers apart in a 3+ party chat (the assistant/user role bit alone collapses every "other" into one indistinguishable stream).

Source code in autogen/beta/network/adapters/discussion.py
def __init__(self) -> None:
    self.manifest = ChannelManifest(
        type=DISCUSSION_TYPE,
        version=1,
        participants=ParticipantSchema(min=2),
        knobs_schema={"ordering": "str"},
        default_view_policy=NamedWindowedSummary.name,
        expectations=[
            Expectation(
                name="turn_within",
                on_violation="warn",
                params={"seconds": 120},
            ),
            Expectation(
                name="turn_within",
                on_violation="hide",
                params={"seconds": 600},
            ),
        ],
    )

manifest instance-attribute #

manifest = ChannelManifest(type=DISCUSSION_TYPE, version=1, participants=ParticipantSchema(min=2), knobs_schema={'ordering': 'str'}, default_view_policy=name, expectations=[Expectation(name='turn_within', on_violation='warn', params={'seconds': 120}), Expectation(name='turn_within', on_violation='hide', params={'seconds': 600})])

initial_state #

initial_state(metadata)
Source code in autogen/beta/network/adapters/discussion.py
def initial_state(self, metadata: ChannelMetadata) -> DiscussionState:
    order = [p.agent_id for p in sorted(metadata.participants, key=lambda p: p.order)]
    return DiscussionState(
        participant_order=order,
        expected_next_speaker=metadata.creator_id,
    )

fold #

fold(envelope, state)
Source code in autogen/beta/network/adapters/discussion.py
def fold(self, envelope: Envelope, state: DiscussionState) -> DiscussionState:
    if _is_channel_protocol_event(envelope) or _is_task_event(envelope):
        return state
    if envelope.event_type != EV_TEXT:
        return state
    try:
        idx = state.participant_order.index(envelope.sender_id)
    except ValueError:
        # Sender not in the rotation (shouldn't happen — validate_send
        # gates this) — leave state untouched rather than crash.
        return state
    next_idx = (idx + 1) % len(state.participant_order)
    return DiscussionState(
        participant_order=state.participant_order,
        expected_next_speaker=state.participant_order[next_idx],
        last_speaker_id=envelope.sender_id,
        last_envelope_id=envelope.envelope_id,
        turn_count=state.turn_count + 1,
    )

validate_create #

validate_create(metadata)
Source code in autogen/beta/network/adapters/discussion.py
def validate_create(self, metadata: ChannelMetadata) -> None:
    if len(metadata.participants) < 2:
        raise ProtocolError(f"discussion requires at least 2 participants, got {len(metadata.participants)}")
    ordering = metadata.knobs.get("ordering", _DEFAULT_ORDERING)
    if ordering not in _SUPPORTED_ORDERINGS:
        raise ProtocolError(
            f"discussion knobs.ordering={ordering!r} not supported; choose from {sorted(_SUPPORTED_ORDERINGS)}"
        )

validate_send #

validate_send(metadata, envelope, state)
Source code in autogen/beta/network/adapters/discussion.py
def validate_send(
    self,
    metadata: ChannelMetadata,
    envelope: Envelope,
    state: DiscussionState,
) -> None:
    if _is_channel_protocol_event(envelope) or _is_task_event(envelope):
        return
    if envelope.event_type != EV_TEXT:
        return
    if envelope.sender_id != state.expected_next_speaker:
        raise ProtocolError(
            f"discussion channel {metadata.channel_id!r} expects "
            f"{state.expected_next_speaker!r} to speak, got {envelope.sender_id!r}"
        )

on_accepted #

on_accepted(metadata, envelope, state)
Source code in autogen/beta/network/adapters/discussion.py
def on_accepted(
    self,
    metadata: ChannelMetadata,
    envelope: Envelope,
    state: DiscussionState,
) -> AdapterResult:
    # Discussions end via explicit ``Hub.close_channel`` or TTL.
    # Speaker rotation happens entirely in ``fold``.
    return AdapterResult()

expected_next #

expected_next(metadata, state)
Source code in autogen/beta/network/adapters/discussion.py
def expected_next(
    self,
    metadata: ChannelMetadata,
    state: DiscussionState,
) -> ExpectedTurn | None:
    if state.expected_next_speaker is None:
        return None
    return ExpectedTurn(
        agent_id=state.expected_next_speaker,
        triggering_envelope_id=state.last_envelope_id,
    )

default_view_policy #

default_view_policy(metadata, participant_id)
Source code in autogen/beta/network/adapters/discussion.py
def default_view_policy(
    self,
    metadata: ChannelMetadata,
    participant_id: str,
) -> ViewPolicy:
    recent_n = max(len(metadata.participants) * 2, 4)
    return NamedWindowedSummary(recent_n=recent_n)

extract_turn_input #

extract_turn_input(envelope)
Source code in autogen/beta/network/adapters/discussion.py
def extract_turn_input(self, envelope):
    return default_extract_turn_input(envelope)

build_round_envelope #

build_round_envelope(metadata, sender_id, reply, events, state, hub)
Source code in autogen/beta/network/adapters/discussion.py
def build_round_envelope(self, metadata, sender_id, reply, events, state, hub):
    return default_build_round_envelope(metadata, sender_id, reply, events, state, hub)

render_envelope #

render_envelope(envelope)
Source code in autogen/beta/network/adapters/discussion.py
def render_envelope(self, envelope):
    return default_render_envelope(envelope)

tools_for #

tools_for(client, metadata, state, participant_id)
Source code in autogen/beta/network/adapters/discussion.py
def tools_for(self, client, metadata, state, participant_id):
    return []

build_text_envelope #

build_text_envelope(channel_id, sender_id, text, *, audience=None, causation_id=None)
Source code in autogen/beta/network/adapters/discussion.py
def build_text_envelope(self, channel_id, sender_id, text, *, audience=None, causation_id=None):
    return default_build_text_envelope(channel_id, sender_id, text, audience=audience, causation_id=causation_id)

build_packet_envelope #

build_packet_envelope(channel_id, sender_id, body, *, handoff=None, context_set=None, audience=None, causation_id=None)
Source code in autogen/beta/network/adapters/discussion.py
def build_packet_envelope(
    self,
    channel_id,
    sender_id,
    body,
    *,
    handoff=None,
    context_set=None,
    audience=None,
    causation_id=None,
):
    return default_build_packet_envelope(
        channel_id,
        sender_id,
        body,
        handoff=handoff,
        context_set=context_set,
        audience=audience,
        causation_id=causation_id,
    )