Packages
a2a_elixir_sdk
1.0.1
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
Current section
Files
lib/a2a_ex/event.ex
defmodule A2AEx.TaskStatusUpdateEvent do
@moduledoc """
Event sent by the agent to notify the client of a change in a task's status.
"""
@type t :: %__MODULE__{
task_id: String.t(),
context_id: String.t(),
status: A2AEx.TaskStatus.t(),
final: boolean(),
metadata: map() | nil
}
@enforce_keys [:task_id, :context_id, :status]
defstruct [:task_id, :context_id, :status, :metadata, final: false]
@doc "Create a new status update event."
@spec new(String.t(), String.t(), A2AEx.TaskState.t(), A2AEx.Message.t() | nil) :: t()
def new(task_id, context_id, state, message \\ nil) do
%__MODULE__{
task_id: task_id,
context_id: context_id,
status: %A2AEx.TaskStatus{
state: state,
message: message,
timestamp: DateTime.utc_now()
}
}
end
@spec from_map(map()) :: {:ok, t()} | {:error, String.t()}
def from_map(map) when is_map(map) do
with {:ok, status} <- A2AEx.TaskStatus.from_map(map["status"] || %{}) do
{:ok,
%__MODULE__{
task_id: map["taskId"],
context_id: map["contextId"],
status: status,
final: map["final"] || false,
metadata: map["metadata"]
}}
end
end
@spec to_map(t()) :: map()
def to_map(%__MODULE__{} = event) do
%{
"kind" => "status-update",
"taskId" => event.task_id,
"contextId" => event.context_id,
"status" => A2AEx.TaskStatus.to_map(event.status),
"final" => event.final
}
|> maybe_put("metadata", event.metadata)
end
defp maybe_put(map, _key, nil), do: map
defp maybe_put(map, key, value), do: Map.put(map, key, value)
end
defmodule A2AEx.TaskArtifactUpdateEvent do
@moduledoc """
Event sent by the agent to notify the client that an artifact has been generated or updated.
"""
@type t :: %__MODULE__{
task_id: String.t(),
context_id: String.t(),
artifact: A2AEx.Artifact.t(),
append: boolean(),
last_chunk: boolean(),
metadata: map() | nil
}
@enforce_keys [:task_id, :context_id, :artifact]
defstruct [:task_id, :context_id, :artifact, :metadata, append: false, last_chunk: false]
@spec from_map(map()) :: {:ok, t()} | {:error, String.t()}
def from_map(map) when is_map(map) do
with {:ok, artifact} <- A2AEx.Artifact.from_map(map["artifact"] || %{}) do
{:ok,
%__MODULE__{
task_id: map["taskId"],
context_id: map["contextId"],
artifact: artifact,
append: map["append"] || false,
last_chunk: map["lastChunk"] || false,
metadata: map["metadata"]
}}
end
end
@spec to_map(t()) :: map()
def to_map(%__MODULE__{} = event) do
%{
"kind" => "artifact-update",
"taskId" => event.task_id,
"contextId" => event.context_id,
"artifact" => A2AEx.Artifact.to_map(event.artifact)
}
|> maybe_put_bool("append", event.append)
|> maybe_put_bool("lastChunk", event.last_chunk)
|> maybe_put("metadata", event.metadata)
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
defmodule A2AEx.Event do
@moduledoc """
Union type for A2A events that can be sent over streaming connections.
"""
@type t ::
A2AEx.Message.t()
| A2AEx.Task.t()
| A2AEx.TaskStatusUpdateEvent.t()
| A2AEx.TaskArtifactUpdateEvent.t()
@doc "Decode an event from a JSON-decoded map, dispatching on the `kind` field."
@spec from_map(map()) :: {:ok, t()} | {:error, String.t()}
def from_map(%{"kind" => "message"} = map), do: A2AEx.Message.from_map(map)
def from_map(%{"kind" => "task"} = map), do: A2AEx.Task.from_map(map)
def from_map(%{"kind" => "status-update"} = map), do: A2AEx.TaskStatusUpdateEvent.from_map(map)
def from_map(%{"kind" => "artifact-update"} = map),
do: A2AEx.TaskArtifactUpdateEvent.from_map(map)
def from_map(%{"kind" => kind}), do: {:error, "unknown event kind: #{kind}"}
def from_map(_), do: {:error, "missing event kind"}
@doc "Encode any event to a JSON-ready map."
@spec to_map(t()) :: map()
def to_map(%A2AEx.Message{} = e), do: A2AEx.Message.to_map(e)
def to_map(%A2AEx.Task{} = e), do: A2AEx.Task.to_map(e)
def to_map(%A2AEx.TaskStatusUpdateEvent{} = e), do: A2AEx.TaskStatusUpdateEvent.to_map(e)
def to_map(%A2AEx.TaskArtifactUpdateEvent{} = e), do: A2AEx.TaskArtifactUpdateEvent.to_map(e)
end
defimpl Jason.Encoder, for: A2AEx.TaskStatusUpdateEvent do
def encode(event, opts) do
A2AEx.TaskStatusUpdateEvent.to_map(event) |> Jason.Encode.map(opts)
end
end
defimpl Jason.Encoder, for: A2AEx.TaskArtifactUpdateEvent do
def encode(event, opts) do
A2AEx.TaskArtifactUpdateEvent.to_map(event) |> Jason.Encode.map(opts)
end
end