Skip to content

ClientBuilder has no fallback to AgentCard#additionalInterfaces()/preferredTransport() (legacy 0.3 cards) when supportedInterfaces() is absent #1121

Description

@carlesarnal

Describe the bug

ClientBuilder#getServerInterfacesMap() builds its list of candidate transports from AgentCard#supportedInterfaces() only:

private Map<String, AgentInterface> getServerInterfacesMap() throws A2AClientException {
    List<AgentInterface> interfaces = agentCard.supportedInterfaces();
    if (interfaces == null || interfaces.isEmpty()) {
        throw new A2AClientException("No server interface available in the AgentCard");
    }
    ...
}

If an AgentCard was produced by an A2A "0.3" server (e.g. anything built on io.a2a.spec.AgentCard from io.github.a2asdk:a2a-java-sdk-reference-jsonrpc, which only has additionalInterfaces/preferredTransport, not supportedInterfaces), Client.builder(agentCard) / ClientBuilder#build() always throws A2AClientException: No server interface available in the AgentCard, even though AgentCard itself models exactly this legacy shape via additionalInterfaces():

private final List<AgentInterface> supportedInterfaces;
private final List<Legacy_0_3_AgentInterface> additionalInterfaces;
...
public List<AgentInterface> supportedInterfaces();
public List<Legacy_0_3_AgentInterface> additionalInterfaces();

Since Legacy_0_3_AgentInterface exists specifically to deserialize the older additionalInterfaces/preferredTransport shape, I'd expect ClientBuilder to fall back to it (converting each Legacy_0_3_AgentInterface + the card's preferredTransport into an AgentInterface) when supportedInterfaces is absent, so that clients built against the current SDK can still talk to agents that only publish a 0.3-style card.

How to reproduce

  1. Stand up any A2A server that only serves a 0.3-style card, e.g.:
    {
      "name": "Summarizer Agent",
      "url": "http://localhost:10010",
      "version": "1.0.0",
      "capabilities": {"streaming": false, "pushNotifications": false, "stateTransitionHistory": false},
      "defaultInputModes": ["text"],
      "defaultOutputModes": ["text"],
      "skills": [...],
      "additionalInterfaces": [{"transport": "JSONRPC", "url": "http://localhost:10010"}],
      "preferredTransport": "JSONRPC",
      "protocolVersion": "0.3.0"
    }
    (this is exactly what io.a2a.spec.AgentCard.Builder from a2a-java-sdk-reference-jsonrpc 0.3.0.Beta1/0.3.2.Final produces — there's no supportedInterfaces() builder method on that class at all, so no 0.3-based server can add it)
  2. AgentCard card = A2A.getAgentCard("http://localhost:10010");
  3. Client.builder(card).withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()).build();
  4. Observe A2AClientException: No server interface available in the AgentCard, even though the server is reachable and does support JSON-RPC.

I confirmed via a minimal Jackson round-trip that a supportedInterfaces entry must use the field name protocolBinding (not transport) to deserialize into AgentInterface, and that capabilities.stateTransitionHistory (present on all 0.3-style cards) is silently ignored rather than rejected — so the parsing itself is otherwise lenient, it's specifically this transport-selection step that has no legacy fallback.

Expected behavior

ClientBuilder should be able to build a working client against an agent that only publishes a 0.3-style card (additionalInterfaces + preferredTransport), by falling back to AgentCard#additionalInterfaces() (converting Legacy_0_3_AgentInterfaceAgentInterface, using preferredTransport() to pick the client's preferred one) when supportedInterfaces() is null/empty.

Context

Found this while wiring up langchain4j-agentic-a2a's AgenticServices.a2aBuilder(url) (used by quarkus-langchain4j-a2a-apicurio-registry's ApicurioAgentsRegistry) against real A2A agents built with a2a-java-sdk-reference-jsonrpc 0.3.0.Beta1/0.3.2.Final for a demo project (https://github.com/carlesarnal/agent-discovery-demo). As things stand, no agent built on the "0.3" reference server can be reached by any client built on the current org.a2aproject.sdk Client/ClientBuilder, regardless of how the client obtains the AgentCard.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions