AFD Plugin Explained

connectors/base.py, factory.py, metadata.py: the connector core

IntermediateCode mapabout 4 min read

Code version: afd-plugin @ 7452d52 · 2026-10-27 · vLLM @ ced6857

In one sentence

Three files form the connector core: base.py (the contract), factory.py (name to class) and metadata.py (the shared data objects).

Purpose#

These files hold the parts every connector shares. The contract and the factory are explained on the The connector contract: the Attention/FFN transport page; this page maps the three files and reads the metadata objects and the factory loader.

ItemValue
Files (lines, origin)base.py (310), factory.py (105), metadata.py (438); AFD-owned
Main typesAFDConnectorBase, AFDControlPlane, AFDConnectorFactory, the AFD* metadata dataclasses
Runs inevery attention and FFN worker process; metadata encode/decode on the CPU
Called bythe role runners and the model wrappers (afd_plugin/v1/worker/ffn_model_runner.py:80-85)
Callsimportlib, torch, json, and the AFD config helpers
Not in this filethe transports: the GPU P2P connector is in connectors/gpu/p2p.py, the NPU ones in connectors/npu/

Where it sits#

Who calls it#

The factory builds a connector for a runner. The FFN runner calls create_connector at construction (afd_plugin/v1/worker/ffn_model_runner.py:80-85); the attention runner does the same. The model wrappers build the metadata objects for each transfer (afd_plugin/model_executor/models/deepseek_v2.py:140-145).

What it calls#

base.py reads the AFD config helper connector_extra_config_from_source (afd_plugin/connectors/base.py:105-107). factory.py imports the connector module lazily with importlib (afd_plugin/connectors/factory.py:38-45). metadata.py encodes the control payload with json (afd_plugin/connectors/metadata.py:344-346).

Key classes and functions#

NameLineRole
AFDConnectorBaseafd_plugin/connectors/base.py:37the connector contract (see The connector contract: the Attention/FFN transport)
AFDControlPlaneafd_plugin/connectors/base.py:258the control-plane contract
AFDConnectorFactoryafd_plugin/connectors/factory.py:23name → class, build an instance
AFDDPMetadataafd_plugin/connectors/metadata.py:23per-DP-rank token counts for the control plane
AFDControlPayloadafd_plugin/connectors/metadata.py:107the control-plane envelope (per-stage metadata + flags)
AFDTransferMetadataafd_plugin/connectors/metadata.py:171layer, stage and per-peer lengths for one transfer
AFDTransferContextafd_plugin/connectors/metadata.py:234transfer metadata plus optional backend state
AFDA2FTransferPayloadafd_plugin/connectors/metadata.py:261the FFN-side receive payload (hidden states + extras)
encode_control_payloadafd_plugin/connectors/metadata.py:320payload → compact JSON bytes
send_control_payloadafd_plugin/connectors/metadata.py:376send the size tensor and the byte tensor

Walk through the main methods#

AFDTransferMetadata: the per-transfer record#

This dataclass describes one layer-and-stage transfer. It validates its lengths and derives the total token count (afd_plugin/connectors/metadata.py:171-200).

    layer_idx: int
    stage_idx: int
    seq_lens: list[int]

    def __post_init__(self) -> None:
        if not self.seq_lens:
            raise ValueError("seq_lens cannot be empty")
        if any(length <= 0 for length in self.seq_lens):
            raise ValueError("all sequence lengths must be positive")

    @property
    def total_tokens(self) -> int:
        return sum(self.seq_lens)
The fields, the validation and total_tokens.
  1. Line 188-190. The fields: layer_idx, stage_idx, and the per-peer seq_lens list.
  2. Line 192-196. __post_init__ rejects an empty list and any non-positive length.
  3. Line 198-200. total_tokens is the sum of the lengths; it is the expected leading dimension.

Two class methods build the attention form (one length) and the FFN form (a list of lengths) (afd_plugin/connectors/metadata.py:202-228). The shape check is validate_tensor_shape (afd_plugin/connectors/metadata.py:230-231).

encode_control_payload: the wire format#

The control payload is serialized to compact JSON, with only the fields the FFN side reads back (afd_plugin/connectors/metadata.py:320-346).

    metadata_payload: dict[str, dict[str, int | list[int]]] = {}
    for stage_idx, dp_metadata in payload.dp_metadata_list.items():
        stage_payload: dict[str, int | list[int]] = {
            "num_tokens_across_dp_cpu": dp_metadata.num_tokens_across_dp_cpu.tolist(),
            "max_tokens_across_dp_cpu": _to_int(dp_metadata.max_tokens_across_dp_cpu),
        }
        metadata_payload[str(int(stage_idx))] = stage_payload

    wire_payload = {
        "dp_metadata_list": metadata_payload,
        "is_graph_capturing": bool(payload.is_graph_capturing),
        "is_warmup": bool(payload.is_warmup),
        "is_graph_replaying": bool(payload.is_graph_replaying),
        "is_profile": bool(payload.is_profile),
    }
    return json.dumps(wire_payload, separators=(",", ":"), sort_keys=True).encode(
        "utf-8",
    )
Per-stage token counts and the flags, as sorted compact JSON.
  1. Line 329-335. One entry per stage: the per-DP-rank token list and its max.
  2. Line 337-343. The graph-capture, warm-up, replay and profile flags.
  3. Line 344-346. json.dumps with sorted keys and no spaces. The The control plane: DP metadata once per step page reads the send and receive.

AFDConnectorFactory: name to class#

The factory keeps a registry of loaders. register_connector stores a loader that imports the module lazily (afd_plugin/connectors/factory.py:26-47); create_connector looks the name up, resolves the role rank, and builds the instance (afd_plugin/connectors/factory.py:49-68).

        def loader() -> type[AFDConnectorBase]:
            module = importlib.import_module(module_path)
            connector_cls = vars(module)[class_name]
            if not issubclass(connector_cls, AFDConnectorBase):
                raise TypeError(
                    f"{module_path}.{class_name} is not an AFDConnectorBase",
                )
            return connector_cls

        cls._registry[name] = loader
The lazy loader: import the module, check the subclass, return the class.

Three connectors are registered at import time; an unknown name raises (afd_plugin/connectors/factory.py:58-59, afd_plugin/connectors/factory.py:88-102).

Deep dive#

Deep dive

The metadata objects at a glance

The dataclasses split the control plane from the data plane.

ObjectPlaneCarries
AFDDPMetadatacontrolper-DP-rank token counts (afd_plugin/connectors/metadata.py:23-44)
AFDControlPayloadcontrolper-stage DP metadata + flags (afd_plugin/connectors/metadata.py:135-139)
AFDTransferMetadatadatalayer, stage, per-peer lengths (afd_plugin/connectors/metadata.py:188-190)
AFDTransferContextdatametadata + optional backend state (afd_plugin/connectors/metadata.py:257-258)
AFDA2FTransferPayloaddatahidden states, context, optional logits and IDs (afd_plugin/connectors/metadata.py:279-282)

AFDTransferContext.states defaults to None so the generated __init__ stays traceable by torch.compile (afd_plugin/connectors/metadata.py:244-249).

Check yourself#

  1. 1
    Which file holds the shared metadata dataclasses?
    easy
    Show answer

    connectors/metadata.py. It defines AFDDPMetadata, AFDControlPayload, AFDTransferMetadata and the transfer payloads (afd_plugin/connectors/metadata.py:23, afd_plugin/connectors/metadata.py:171).

  2. 2
    How does the factory load a connector class?
    medium
    Show answer

    Lazily. register_connector stores a loader that imports the module with importlib and checks the subclass only when the name is first used (afd_plugin/connectors/factory.py:38-47).

  3. 3
    What is total_tokens, and where is it checked?
    hard
    Show answer

    It is the sum of the per-peer seq_lens (afd_plugin/connectors/metadata.py:198-200). validate_tensor_shape checks that a tensor's leading dimension equals it (afd_plugin/connectors/metadata.py:230-231).