include::{mod-loc}shared/all-attributes.adoc[]

:_mod-docs-content-type: ASSEMBLY
[id="assembly-a2a-features_{context}"]
= A2A protocol features in {registry}

[role="_abstract"]
{registry} implements the A2A (Agent-to-Agent) protocol for AI agent discovery, orchestration, and lifecycle management.

ifdef::service-registry-downstream[]
WARNING: This section describes Developer Preview features. Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA. For more information about the support scope of Red Hat Developer Preview features, see link:https://access.redhat.com/support/offerings/devpreview[Developer Preview Support Scope].
endif::[]

* xref:a2a-overview_{context}[]
* xref:a2a-configuration_{context}[]
* xref:a2a-well-known-endpoints_{context}[]
* xref:a2a-discovery-endpoints_{context}[]
* xref:a2a-visibility-model_{context}[]
* xref:a2a-agent-card-artifact-type_{context}[]
* xref:a2a-validation-rules_{context}[]
* xref:a2a-compatibility-checking_{context}[]
* xref:a2a-automatic-label-extraction_{context}[]
* xref:a2a-registry-built-in-skills_{context}[]
* xref:a2a-llm-lifecycle-management_{context}[]
* xref:a2a-multi-agent-workflow-example_{context}[]
* xref:a2a-java-sdk-usage_{context}[]
* xref:a2a-rest-api-reference_{context}[]
* xref:a2a-troubleshooting_{context}[]

// con-a2a-overview
:_mod-docs-content-type: CONCEPT
[id="a2a-overview_{context}"]
== A2A protocol overview

[role="_abstract"]
With the A2A protocol, AI agents can discover and communicate with each other through standardized endpoints. {registry} serves as both an A2A agent and an agent registry.

.{registry} as an A2A agent
{registry} provides its own capabilities, including schema validation, search, and artifact management.

.{registry} as an agent registry
{registry} stores and discovers other agents' Agent Cards.

.{registry} dual-role A2A architecture
[cols="1,1",options="header"]
|===
|{registry} as an A2A agent
|{registry} as an agent card registry

a|Endpoint: `/.well-known/agent.json`

Built-in skills:

* `schema-validation`
* `schema-search`
* `artifact-management`
* `compatibility-check`
* `agent-discovery`

a|Endpoints:

* `/.well-known/agents`
* `/.well-known/agents/\{groupId}/\{artifactId}`

Capabilities:

* Store agent cards as `AGENT_CARD` artifacts
* Search by skill, capability, or input/output mode
* Version management and compatibility checking
|===

// ref-a2a-configuration
:_mod-docs-content-type: REFERENCE
[id="a2a-configuration_{context}"]
== A2A configuration properties

[role="_abstract"]
You can control A2A features by using the following configuration properties.

[cols="2,1,3"]
|===
|Property |Default |Description

|`apicurio.a2a.enabled`
|`false`
|Enable or disable A2A protocol support

|`apicurio.a2a.agent.name`
|`Apicurio Registry`
|Name of the registry as an A2A agent

|`apicurio.a2a.agent.description`
|_varies_
|Description of the registry agent

|`apicurio.a2a.agent.version`
|_app version_
|Agent version (defaults to application version)

|`apicurio.a2a.agent.url`
|_base URL_
|Base URL for A2A endpoint

|`apicurio.a2a.agent.provider.organization`
|`Apicurio`
|Provider organization name

|`apicurio.a2a.agent.provider.url`
|`https://www.apicur.io`
|Provider organization URL

|`apicurio.a2a.agent.capabilities.streaming`
|`false`
|Whether streaming is supported

|`apicurio.a2a.agent.capabilities.push-notifications`
|`false`
|Whether push notifications are supported
|===

// ref-a2a-well-known-endpoints
:_mod-docs-content-type: REFERENCE
[id="a2a-well-known-endpoints_{context}"]
== A2A well-known endpoints

[role="_abstract"]
{registry} provides the following well-known endpoints for A2A agent discovery and retrieval.

.GET /.well-known/agent.json
Retrieves the Agent Card for the {registry} instance.

Response: Agent Card JSON document

[source,json]
----
{
  "name": "Apicurio Registry",
  "description": "Central registry for AI agents and schemas",
  "version": "3.1.0",
  "url": "http://localhost:8080",
  "provider": {
    "organization": "Apicurio",
    "url": "https://www.apicur.io"
  },
  "skills": [
    {
      "id": "schema-validation",
      "name": "Schema Validation",
      "description": "Validate schemas against format specifications"
    },
    {
      "id": "schema-search",
      "name": "Schema Search",
      "description": "Search for schemas and APIs in the registry"
    }
  ],
  "capabilities": {
    "streaming": false,
    "pushNotifications": false
  },
  "defaultInputModes": ["text"],
  "defaultOutputModes": ["text"]
}
----

.GET /.well-known/agents
Searches for registered Agent Cards with filtering support.

.Query parameters for /.well-known/agents
[cols="1,1,3"]
|===
|Parameter |Type |Description

|`name`
|string
|Filter by agent name (partial match)

|`skill`
|string (repeatable)
|Filter by skill ID

|`capability`
|string
|Filter by capability (for example, `streaming:true`)

|`inputMode`
|string
|Filter by input mode (for example, `text`, `image`)

|`outputMode`
|string
|Filter by output mode

|`offset`
|integer
|Pagination offset (default: 0)

|`limit`
|integer
|Pagination limit (default: 20)
|===

.Example request
[source,bash]
----
curl "http://localhost:8080/.well-known/agents?skill=translation&capability=streaming:true"
----

.Example response: AgentSearchResults
[source,json]
----
{
  "count": 2,
  "agents": [
    {
      "groupId": "ai-agents",
      "artifactId": "translator-agent",
      "name": "Translation Agent",
      "description": "Translates text between languages",
      "version": "1.0.0",
      "url": "http://translator:9001",
      "skills": [{"id": "translation", "name": "Translation"}],
      "capabilities": {"streaming": true}
    }
  ]
}
----

.GET /.well-known/agents/\{groupId}/\{artifactId}
Retrieves a specific registered Agent Card.

.Path parameters
* `groupId` - The group containing the agent card
* `artifactId` - The artifact ID of the agent card

.Query parameters
* `version` (optional) - Specific version (defaults to latest)

Response: Agent Card JSON document

// ref-a2a-discovery-endpoints
:_mod-docs-content-type: REFERENCE
[id="a2a-discovery-endpoints_{context}"]
== Agent discovery and entitlement endpoints

[role="_abstract"]
{registry} provides a three-tier agent discovery model for enterprise agent catalogs, based on the link:https://github.com/a2aproject/A2A/discussions/741[A2A community proposal].

.GET /.well-known/agents/public
Returns agents explicitly marked as public. No authentication required.

Only Agent Card artifacts labeled with `apicurio.agent.visibility=public` are returned.

.Query parameters
* `offset` (integer) - Pagination offset (default: 0)
* `limit` (integer) - Pagination limit (default: 20)

.Example request
[source,bash]
----
curl "http://localhost:8080/.well-known/agents/public"
----

.GET /.well-known/agents/entitled
Returns agents the authenticated caller is entitled to access, filtered by visibility:

* `public` agents are always included
* `entitled` agents (default) are included for any authenticated user
* `private` agents are included only for the artifact owner or admins

.Query parameters
* `offset` (integer) - Pagination offset (default: 0)
* `limit` (integer) - Pagination limit (default: 20)

.Example request
[source,bash]
----
curl -H "Authorization: Bearer <token>" \
  "http://localhost:8080/.well-known/agents/entitled"
----

.POST /.well-known/agents/search
Advanced agent search with combined text query and structured filters. Respects the caller's entitlements when entitlement filtering is enabled.

.Example request body
[source,json]
----
{
  "query": "customer support",
  "filters": {
    "capabilities": { "streaming": true },
    "skills": ["ticket-creation"],
    "labels": { "department": "engineering" },
    "inputModes": ["text"],
    "outputModes": ["text"],
    "protocolBindings": ["http+json"]
  },
  "limit": 20,
  "offset": 0
}
----

All filter fields are optional. When multiple filters are specified, results must match all of them.

NOTE: The `query` field matches artifact metadata name and artifact ID, not Agent Card JSON content. Full-text content search is planned for a future release.

// ref-a2a-visibility-model
:_mod-docs-content-type: REFERENCE
[id="a2a-visibility-model_{context}"]
== Agent visibility model

[role="_abstract"]
Agent Cards support three visibility levels, controlled by the `apicurio.agent.visibility` artifact label.

.Agent visibility levels
[cols="1,3"]
|===
|Visibility |Behavior

|`public`
|Visible to everyone, including unauthenticated clients via `/.well-known/agents/public`

|`entitled`
|Visible to any authenticated user (this is the default)

|`private`
|Visible only to the artifact owner and registry admins
|===

.Setting visibility
[source,bash]
----
curl -X PUT "http://localhost:8080/apis/registry/v3/groups/my-agents/artifacts/my-agent" \
  -H "Content-Type: application/json" \
  -d '{"labels": {"apicurio.agent.visibility": "public"}}'
----

.How entitlements work
{registry} maps the A2A community entitlement concept to its existing RBAC model:

* *Groups* act as organizational namespaces
* *Entitling a client* = granting read access to the group containing the Agent Card artifacts
* *Client authentication* is delegated to the external IdP (Keycloak, OIDC)
* No new authorization primitives are required

.Discovery and entitlement configuration properties
[cols="2,1,3"]
|===
|Property |Default |Description

|`apicurio.a2a.public-discovery.enabled`
|`true`
|Enable the public (unauthenticated) agent discovery endpoint

|`apicurio.a2a.entitlements.enabled`
|`true`
|Enable entitlement-based agent filtering

|`apicurio.a2a.default-visibility`
|`entitled`
|Default visibility for new Agent Card artifacts (`public`, `entitled`, or `private`)
|===

NOTE: When authentication is not configured, visibility filtering is skipped and all agents are visible to all users.

// ref-a2a-agent-card-artifact-type
:_mod-docs-content-type: REFERENCE
[id="a2a-agent-card-artifact-type_{context}"]
== Agent Card artifact type

[role="_abstract"]
Agent Cards are stored as artifacts with type `AGENT_CARD`. You can create Agent Cards by using the REST API and you can validate them against the A2A specification JSON schema.

.Agent Card creation example
[source,bash]
----
curl -X POST "http://localhost:8080/apis/registry/v3/groups/ai-agents/artifacts" \
  -H "Content-Type: application/json" \
  -d '{
    "artifactId": "my-agent",
    "artifactType": "AGENT_CARD",
    "firstVersion": {
      "version": "1.0.0",
      "content": {
        "contentType": "application/json",
        "content": "{\"name\": \"My Agent\", \"skills\": [{\"id\": \"task\", \"name\": \"Task Execution\"}]}"
      }
    }
  }'
----

.Agent Card JSON schema
Agent Cards must conform to the A2A specification:

[source,json]
----
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["name"],
  "properties": {
    "name": {"type": "string"},
    "description": {"type": "string"},
    "version": {"type": "string"},
    "url": {"type": "string", "format": "uri"},
    "provider": {
      "type": "object",
      "properties": {
        "organization": {"type": "string"},
        "url": {"type": "string", "format": "uri"}
      }
    },
    "capabilities": {
      "type": "object",
      "properties": {
        "streaming": {"type": "boolean"},
        "pushNotifications": {"type": "boolean"}
      }
    },
    "skills": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["id", "name"],
        "properties": {
          "id": {"type": "string"},
          "name": {"type": "string"},
          "description": {"type": "string"},
          "tags": {"type": "array", "items": {"type": "string"}},
          "examples": {"type": "array", "items": {"type": "string"}}
        }
      }
    },
    "defaultInputModes": {"type": "array", "items": {"type": "string"}},
    "defaultOutputModes": {"type": "array", "items": {"type": "string"}},
    "authentication": {
      "type": "object",
      "properties": {
        "schemes": {"type": "array", "items": {"type": "string"}}
      }
    }
  }
}
----

// ref-a2a-validation-rules
:_mod-docs-content-type: REFERENCE
[id="a2a-validation-rules_{context}"]
== Agent Card validation rules

[role="_abstract"]
Agent Cards have three validation levels that control how much validation occurs when you create or update an Agent Card.

[cols="1,3"]
|===
|Level |Description

|`NONE`
|No validation.

|`SYNTAX_ONLY`
|Validates that the content is syntactically valid JSON and is a JSON object.

|`FULL`
a|Complete schema validation including:

* Required `name` field (non-empty string)
* `description` and `version` fields
* `supportedInterfaces` array, where each interface has `url`, `protocolBinding`, and `protocolVersion`
* `provider` object with `organization` and `url`
* `skills` array, where each skill has `id` and `name`
* `capabilities` object with boolean values
* `defaultInputModes` and `defaultOutputModes` arrays
* Authentication and security scheme validation
* Valid JSON structure
|===

// ref-a2a-compatibility-checking
:_mod-docs-content-type: REFERENCE
[id="a2a-compatibility-checking_{context}"]
== Agent Card compatibility rules

[role="_abstract"]
When you version Agent Cards, {registry} enforces compatibility rules to ensure that changes do not break existing clients.

.Compatible changes (allowed)
* Adding new skills
* Adding new capabilities
* Adding authentication schemes
* Adding input or output modes

.Incompatible changes (can break clients)
* Removing skills
* Removing or disabling capabilities
* Removing supported interfaces (matched by URL and protocol binding)
* Changing the protocol version on an existing interface
* Removing security schemes
* Removing input or output modes

// ref-a2a-automatic-label-extraction
:_mod-docs-content-type: REFERENCE
[id="a2a-automatic-label-extraction_{context}"]
== Automatic label extraction for Agent Cards

[role="_abstract"]
{registry} automatically extracts labels from Agent Cards for search. You can use these labels for efficient capability-based discovery by using the {registry} label search.

[cols="2,3"]
|===
|Label pattern |Source

|`agent_card:skill:<id>`
|Each skill ID in the `skills` array

|`agent_card:capability:<name>`
|Each enabled capability in the `capabilities` object (where value is `true`)

|`agent_card:inputmode:<mode>`
|Each value in the `defaultInputModes` array

|`agent_card:outputmode:<mode>`
|Each value in the `defaultOutputModes` array

|`agent_card:protocolbinding:<binding>`
|Each `protocolBinding` value in the `supportedInterfaces` array

|`agent_card:securityscheme:<name>`
|Each key in the `securitySchemes` object

|`agent_card:tag:<value>`
|Each value in the `tags` array within each skill (deduplicated across skills)
|===

// ref-a2a-registry-built-in-skills
:_mod-docs-content-type: REFERENCE
[id="a2a-registry-built-in-skills_{context}"]
== {registry} built-in A2A skills

[role="_abstract"]
{registry} operates as an A2A agent with the following built-in skills.

[cols="1,2"]
|===
|Skill ID |Description

|`schema-validation`
|Validate schemas against format specifications (Avro, JSON Schema, Protobuf, OpenAPI, AsyncAPI, GraphQL, Thrift, WSDL, XSD)

|`schema-search`
|Search for schemas and APIs in the registry by name, labels, or content

|`artifact-management`
|Create, update, and manage schema artifacts with full versioning

|`compatibility-check`
|Check schema compatibility between versions by using configurable rules

|`agent-discovery`
|Discover and manage A2A agent cards stored in the registry
|===

// con-a2a-llm-lifecycle-management
:_mod-docs-content-type: CONCEPT
[id="a2a-llm-lifecycle-management_{context}"]
== LLM lifecycle management

[role="_abstract"]
A2A integration includes full LLM lifecycle management with additional artifact types, including MODEL_SCHEMA and PROMPT_TEMPLATE.

.MODEL_SCHEMA artifact type
The MODEL_SCHEMA artifact type defines input and output schemas for LLM agents:

[source,json]
----
{
  "$schema": "https://apicurio.io/schemas/model-schema/v1",
  "modelId": "sentiment-analysis-output",
  "provider": "a2a-demo",
  "version": "1.0.0",
  "output": {
    "type": "object",
    "required": ["sentiment", "confidence"],
    "properties": {
      "sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]},
      "confidence": {"type": "number", "minimum": 0, "maximum": 1}
    }
  }
}
----

.PROMPT_TEMPLATE artifact type
The PROMPT_TEMPLATE artifact type stores versioned prompt templates with variable support:

[source,yaml]
----
templateId: sentiment-analysis
name: Sentiment Analysis Prompt
version: "1.0.0"

template: |
  Analyze the sentiment of the following message:

  MESSAGE: {{customerMessage}}

  Respond with JSON containing sentiment and confidence.

variables:
  customerMessage:
    type: string
    required: true
    description: The message to analyze

metadata:
  outputSchema: urn:apicurio:llm-agents.schemas/sentiment-output
----

.Artifact links
Agent Cards can reference their schemas and prompts by using URN references:

[source,json]
----
{
  "name": "Sentiment Agent",
  "skills": [
    {
      "id": "sentiment-analysis",
      "name": "Sentiment Analysis",
      "outputSchema": "urn:apicurio:llm-agents.schemas/sentiment-agent-output",
      "promptTemplate": "urn:apicurio:llm-agents.prompts/sentiment-agent-prompt"
    }
  ]
}
----

// con-a2a-multi-agent-workflow-example
:_mod-docs-content-type: CONCEPT
[id="a2a-multi-agent-workflow-example_{context}"]
== Multi-agent workflow example

[role="_abstract"]
You can chain context across multiple agents in a pipeline. The link:https://github.com/Apicurio/apicurio-registry/tree/main/examples/a2a-real-world-integration[a2a-real-world-integration example] in the {registry} repository demonstrates this pattern.

.Context chaining pipeline
[cols="1,3,3",options="header"]
|===
|Step
|Input context
|Output

|1. Sentiment agent
|`\{{original}}`
|`{"sentiment": "very_negative", "urgency": "critical"}`

|2. Issue analyzer
|`\{{original}}` + `\{{sentiment}}`
|`{"priority": "P1", "issue_type": "delayed_delivery"}`

|3. Response generator
|`\{{original}}` + `\{{sentiment}}` + `\{{analysis}}`
|`{"response": "Dear customer, I sincerely apologize..."}`

|4. Translation agent
|`\{{response}}`
|`{"translated": "Estimado cliente, le pido disculpas..."}`
|===

ifndef::service-registry-downstream[]
.Example commands
To run the example application locally, clone the {registry} repository and run the following commands:

[source,bash]
----
cd examples/a2a-real-world-integration
docker-compose up -d
mvn clean compile exec:java
----

The Web UI is available at http://localhost:9000.
endif::[]

// ref-a2a-java-sdk-usage
:_mod-docs-content-type: REFERENCE
[id="a2a-java-sdk-usage_{context}"]
== Java SDK usage for A2A

[role="_abstract"]
You can use the Java SDK to discover agents and register Agent Cards programmatically.

.Agent discovery example
[source,java]
----
RegistryClient client = RegistryClientFactory.create(
    RegistryClientOptions.create("http://localhost:8080/apis/registry/v3"));

// Search for agents with specific skill
var agents = client.wellKnown().agents()
    .get(config -> {
        config.queryParameters.skill = List.of("translation");
        config.queryParameters.limit = 10;
    });

for (var agent : agents.getAgents()) {
    System.out.println("Found: " + agent.getName() + " @ " + agent.getUrl());
}
----

.Agent Card registration example
[source,java]
----
CreateArtifact artifact = new CreateArtifact();
artifact.setArtifactId("my-agent");
artifact.setArtifactType("AGENT_CARD");

CreateVersion version = new CreateVersion();
version.setVersion("1.0.0");

VersionContent content = new VersionContent();
content.setContentType("application/json");
content.setContent(agentCardJson);
version.setContent(content);

artifact.setFirstVersion(version);

client.groups().byGroupId("ai-agents").artifacts()
    .post(artifact, config -> {
        config.queryParameters.ifExists = IfArtifactExists.FIND_OR_CREATE_VERSION;
    });
----

// ref-a2a-rest-api-reference
:_mod-docs-content-type: REFERENCE
[id="a2a-rest-api-reference_{context}"]
== A2A REST API endpoints

[role="_abstract"]
The following table describes the core A2A endpoints available in {registry}.

[cols="2,1,4"]
|===
|Endpoint |Method |Description

|`/.well-known/agent.json`
|GET
|Get the registry's own Agent Card

|`/.well-known/agents`
|GET
|Search registered Agent Cards

|`/.well-known/agents/{groupId}/{artifactId}`
|GET
|Get a specific Agent Card by artifact ID

|`/apis/registry/v3/groups/{groupId}/artifacts`
|POST
|Create an Agent Card artifact (type: AGENT_CARD)

|`/apis/registry/v3/groups/{groupId}/artifacts/{artifactId}`
|GET
|Get Agent Card artifact metadata

|`/apis/registry/v3/groups/{groupId}/artifacts/{artifactId}/versions/{version}/content`
|GET
|Get Agent Card content
|===

// ref-a2a-troubleshooting
:_mod-docs-content-type: REFERENCE
[id="a2a-troubleshooting_{context}"]
== A2A troubleshooting

[role="_abstract"]
Use the following information to troubleshoot common issues with A2A features in {registry}.

.A2A endpoints return 404
Ensure A2A is enabled in your configuration:
[source,properties]
----
apicurio.a2a.enabled=true
----

.Agent Card validation fails
Verify the following conditions:

* The `name` field is present and non-empty.
* Skills have both `id` and `name` fields.
* Capabilities are boolean values.
* The JSON is well-formed.

.Search returns no results
Verify the following conditions:

* Agent Cards are stored with type `AGENT_CARD`.
* The registry extracted labels correctly (check artifact labels).
* Search filters match stored values exactly.

[role="_additional-resources"]
.Additional resources
* xref:getting-started/assembly-llm-artifact-types-implementation.adoc[LLM Artifact Types]
* link:https://google.github.io/A2A/[A2A Protocol Specification]
* xref:getting-started/assembly-configuring-the-registry.adoc[{registry} configuration]
