Skip to content

build_card

autogen.beta.a2a.card.build_card #

build_card(agent, *, url, transports=('jsonrpc',), rest_url=None, rest_path_prefix='', grpc_url=None, version=_DEFAULT_VERSION, description=None, push_notifications=False, skills=None, security=(), provider=None, documentation_url=None, icon_url=None, tenants=None)

Construct an AgentCard describing an AG2 agent for A2A discovery.

Always declares the urn:ag2:client-tools:v1 extension as required=False — the server can transparently fall back to a plain text exchange when the client doesn't speak the extension.

supported_interfaces is built from transports — one AgentInterface per enabled binding. JSON-RPC URL is url; REST URL defaults to url + rest_path_prefix (same host:port, different path) but can be overridden via rest_url when REST lives on a different host:port; gRPC lives on its own grpc_url.

When skills is supplied, it replaces all auto-detection. When it is None, build_card walks agent.tools for any :class:SkillsToolkit and publishes its agentskills.io-style local skills as AgentSkill entries; if none are found, falls back to a single skill derived from agent.name / agent._system_prompt so the card stays spec-compliant.

security is a sequence of :class:Requirement objects built via require(scheme, ...). Each entry is an AND-set of schemes; the list itself is OR-ed (any one requirement suffices). Underlying security_schemes on the card are auto-derived from the schemes referenced in security — no duplicate declarations needed. tenants maps a transport name to a tenant string surfaced on the corresponding AgentInterface.tenant.

Source code in autogen/beta/a2a/card.py
def build_card(
    agent: Agent,
    *,
    url: str,
    transports: Sequence[TransportName] = ("jsonrpc",),
    rest_url: str | None = None,
    rest_path_prefix: str = "",
    grpc_url: str | None = None,
    version: str = _DEFAULT_VERSION,
    description: str | None = None,
    push_notifications: bool = False,
    skills: Sequence[AgentSkill] | None = None,
    security: Sequence[Requirement] = (),
    provider: AgentProvider | None = None,
    documentation_url: str | None = None,
    icon_url: str | None = None,
    tenants: Mapping[TransportName, str] | None = None,
) -> AgentCard:
    """Construct an ``AgentCard`` describing an AG2 agent for A2A discovery.

    Always declares the ``urn:ag2:client-tools:v1`` extension as
    ``required=False`` — the server can transparently fall back to a
    plain text exchange when the client doesn't speak the extension.

    ``supported_interfaces`` is built from ``transports`` — one
    ``AgentInterface`` per enabled binding. JSON-RPC URL is ``url``;
    REST URL defaults to ``url + rest_path_prefix`` (same host:port,
    different path) but can be overridden via ``rest_url`` when REST
    lives on a different host:port; gRPC lives on its own ``grpc_url``.

    When ``skills`` is supplied, it replaces all auto-detection. When it
    is ``None``, ``build_card`` walks ``agent.tools`` for any
    :class:`SkillsToolkit` and publishes its ``agentskills.io``-style
    local skills as ``AgentSkill`` entries; if none are found, falls
    back to a single skill derived from ``agent.name`` /
    ``agent._system_prompt`` so the card stays spec-compliant.

    ``security`` is a sequence of :class:`Requirement` objects built via
    ``require(scheme, ...)``. Each entry is an AND-set of schemes; the
    list itself is OR-ed (any one requirement suffices). Underlying
    ``security_schemes`` on the card are auto-derived from the schemes
    referenced in ``security`` — no duplicate declarations needed.
    ``tenants`` maps a transport name to a tenant string surfaced on the
    corresponding ``AgentInterface.tenant``.
    """
    if "grpc" in transports and grpc_url is None:
        raise ValueError("grpc_url is required when 'grpc' is in transports")

    description_text = description or _agent_description(agent)
    resolved_skills = _resolve_skills(agent, skills, description_text)
    capabilities = AgentCapabilities(
        streaming=True,
        push_notifications=push_notifications,
        extensions=[
            AgentExtension(
                uri=EXTENSION_URI,
                description="AG2 client-side tool execution",
                required=False,
            ),
        ],
    )
    card_kwargs: dict[str, object] = {
        "name": agent.name,
        "description": description_text,
        "version": version,
        "default_input_modes": list(_DEFAULT_INPUT_MODES),
        "default_output_modes": list(_DEFAULT_OUTPUT_MODES),
        "capabilities": capabilities,
        "skills": resolved_skills,
        "supported_interfaces": _build_interfaces(
            transports=transports,
            url=url,
            rest_url=rest_url,
            rest_path_prefix=rest_path_prefix,
            grpc_url=grpc_url,
            tenants=tenants,
        ),
    }
    if security:
        seen: dict[str, Scheme] = {}
        for req in security:
            for scheme in req.schemes:
                seen[scheme.name] = scheme
        card_kwargs["security_schemes"] = {name: s.scheme for name, s in seen.items()}
        card_kwargs["security_requirements"] = [r.to_proto() for r in security]
    if provider is not None:
        card_kwargs["provider"] = provider
    if documentation_url is not None:
        card_kwargs["documentation_url"] = documentation_url
    if icon_url is not None:
        card_kwargs["icon_url"] = icon_url
    return AgentCard(**card_kwargs)