Packages

Elixir implementation of the Agent-to-Agent (A2A) protocol. Exposes ADK agents as A2A-compatible HTTP endpoints and consumes remote A2A agents as local ADK agents.

Current section

Files

Jump to
a2a_elixir_sdk lib a2a_ex agent_card.ex
Raw

lib/a2a_ex/agent_card.ex

defmodule A2AEx.AgentProvider do
@moduledoc "Information about the agent's service provider."
@type t :: %__MODULE__{
organization: String.t(),
url: String.t()
}
@enforce_keys [:organization, :url]
defstruct [:organization, :url]
end
defmodule A2AEx.AgentCapabilities do
@moduledoc "Optional capabilities supported by an agent."
@type t :: %__MODULE__{
streaming: boolean(),
push_notifications: boolean(),
state_transition_history: boolean()
}
defstruct streaming: false, push_notifications: false, state_transition_history: false
@spec from_map(map()) :: t()
def from_map(map) when is_map(map) do
%__MODULE__{
streaming: map["streaming"] || false,
push_notifications: map["pushNotifications"] || false,
state_transition_history: map["stateTransitionHistory"] || false
}
end
@spec to_map(t()) :: map()
def to_map(%__MODULE__{} = caps) do
map = %{}
map = if caps.streaming, do: Map.put(map, "streaming", true), else: map
map =
if caps.push_notifications, do: Map.put(map, "pushNotifications", true), else: map
if caps.state_transition_history,
do: Map.put(map, "stateTransitionHistory", true),
else: map
end
end
defmodule A2AEx.AgentSkill do
@moduledoc "A distinct capability or function that an agent can perform."
@type t :: %__MODULE__{
id: String.t(),
name: String.t(),
description: String.t(),
tags: [String.t()],
examples: [String.t()] | nil,
input_modes: [String.t()] | nil,
output_modes: [String.t()] | nil
}
@enforce_keys [:id, :name, :description]
defstruct [:id, :name, :description, :examples, :input_modes, :output_modes, tags: []]
@spec from_map(map()) :: t()
def from_map(map) when is_map(map) do
%__MODULE__{
id: map["id"],
name: map["name"],
description: map["description"],
tags: map["tags"] || [],
examples: map["examples"],
input_modes: map["inputModes"],
output_modes: map["outputModes"]
}
end
@spec to_map(t()) :: map()
def to_map(%__MODULE__{} = skill) do
%{
"id" => skill.id,
"name" => skill.name,
"description" => skill.description,
"tags" => skill.tags
}
|> maybe_put("examples", skill.examples)
|> maybe_put("inputModes", skill.input_modes)
|> maybe_put("outputModes", skill.output_modes)
end
defp maybe_put(map, _key, nil), do: map
defp maybe_put(map, key, value), do: Map.put(map, key, value)
end
defmodule A2AEx.AgentCard do
@moduledoc """
A self-describing manifest for an agent. Provides essential metadata including
the agent's identity, capabilities, skills, and supported communication methods.
"""
@type t :: %__MODULE__{
name: String.t(),
description: String.t(),
url: String.t(),
version: String.t(),
protocol_version: String.t(),
capabilities: A2AEx.AgentCapabilities.t(),
skills: [A2AEx.AgentSkill.t()],
default_input_modes: [String.t()],
default_output_modes: [String.t()],
provider: A2AEx.AgentProvider.t() | nil,
documentation_url: String.t() | nil,
icon_url: String.t() | nil,
supports_authenticated_extended_card: boolean(),
security_schemes: map() | nil,
security: [map()] | nil,
preferred_transport: String.t() | nil
}
@enforce_keys [:name, :description, :url, :version]
defstruct [
:name,
:description,
:url,
:version,
:provider,
:documentation_url,
:icon_url,
protocol_version: "0.3.0",
capabilities: %A2AEx.AgentCapabilities{},
skills: [],
default_input_modes: ["text/plain"],
default_output_modes: ["text/plain"],
supports_authenticated_extended_card: false,
security_schemes: nil,
security: nil,
preferred_transport: nil
]
@spec from_map(map()) :: {:ok, t()} | {:error, String.t()}
def from_map(map) when is_map(map) do
provider =
case map["provider"] do
%{"organization" => org, "url" => url} ->
%A2AEx.AgentProvider{organization: org, url: url}
_ ->
nil
end
{:ok,
%__MODULE__{
name: map["name"],
description: map["description"],
url: map["url"],
version: map["version"],
protocol_version: map["protocolVersion"] || "0.3.0",
capabilities: A2AEx.AgentCapabilities.from_map(map["capabilities"] || %{}),
skills: Enum.map(map["skills"] || [], &A2AEx.AgentSkill.from_map/1),
default_input_modes: map["defaultInputModes"] || ["text/plain"],
default_output_modes: map["defaultOutputModes"] || ["text/plain"],
provider: provider,
documentation_url: map["documentationUrl"],
icon_url: map["iconUrl"],
supports_authenticated_extended_card:
map["supportsAuthenticatedExtendedCard"] || false,
security_schemes: map["securitySchemes"],
security: map["security"],
preferred_transport: map["preferredTransport"]
}}
end
@spec to_map(t()) :: map()
def to_map(%__MODULE__{} = card) do
%{
"name" => card.name,
"description" => card.description,
"url" => card.url,
"version" => card.version,
"protocolVersion" => card.protocol_version,
"capabilities" => A2AEx.AgentCapabilities.to_map(card.capabilities),
"skills" => Enum.map(card.skills, &A2AEx.AgentSkill.to_map/1),
"defaultInputModes" => card.default_input_modes,
"defaultOutputModes" => card.default_output_modes
}
|> maybe_put_provider(card.provider)
|> maybe_put("documentationUrl", card.documentation_url)
|> maybe_put("iconUrl", card.icon_url)
|> maybe_put_bool(
"supportsAuthenticatedExtendedCard",
card.supports_authenticated_extended_card
)
|> maybe_put("securitySchemes", card.security_schemes)
|> maybe_put("security", card.security)
|> maybe_put("preferredTransport", card.preferred_transport)
end
defp maybe_put_provider(map, nil), do: map
defp maybe_put_provider(map, %A2AEx.AgentProvider{} = p) do
Map.put(map, "provider", %{"organization" => p.organization, "url" => p.url})
end
defp maybe_put(map, _key, nil), do: map
defp maybe_put(map, key, value), do: Map.put(map, key, value)
defp maybe_put_bool(map, _key, false), do: map
defp maybe_put_bool(map, key, true), do: Map.put(map, key, true)
end
defimpl Jason.Encoder, for: A2AEx.AgentCard do
def encode(card, opts) do
A2AEx.AgentCard.to_map(card) |> Jason.Encode.map(opts)
end
end