A thread-safe registry for storing and retrieving provider manifests.
The Registry provides deterministic operations for managing provider manifests, including registration, retrieval, update, and filtering capabilities.
Thread Safety
The Registry uses immutable data structures, making all operations inherently thread-safe. Each operation returns a new Registry struct without mutating the original, enabling safe concurrent access patterns.
Determinism
All operations are deterministic - the same inputs will always produce the
same outputs. The list/1 function returns manifests in a consistent order
(sorted alphabetically by name).
Usage
# Create a registry
registry = Registry.new()
# Register a manifest
{:ok, manifest} = Manifest.new(%{name: "my-agent", version: "1.0.0"})
{:ok, registry} = Registry.register(registry, manifest)
# Retrieve a manifest
{:ok, retrieved} = Registry.get(registry, "my-agent")
# List all manifests
manifests = Registry.list(registry)
# Filter by provider
anthropic_agents = Registry.filter_by_provider(registry, "anthropic")
# Filter by capability
tool_agents = Registry.filter_by_capability(registry, :tool)Validation
The Registry validates manifests before registration, providing helpful error messages for common issues:
result = Registry.validate_manifest(manifest)
case result do
:ok -> IO.puts("Valid!")
{:error, error} -> IO.puts("Error: #{error.message}")
end
Summary
Functions
Returns the count of registered manifests.
Checks if a manifest with the given name exists in the registry.
Filters manifests by capability type.
Filters manifests by provider.
Reconstructs a registry from a map.
Retrieves a manifest by name.
Lists all registered manifests in deterministic order (sorted by name).
Creates a new empty registry.
Creates a new registry with the given options.
Registers a new manifest in the registry.
Converts the registry to a map suitable for JSON serialization.
Removes a manifest from the registry by name.
Updates an existing manifest in the registry.
Validates a manifest, returning :ok if valid or {:error, error} with
a helpful error message if invalid.
Types
@type t() :: %AgentSessionManager.Core.Registry{ manifests: %{required(String.t()) => AgentSessionManager.Core.Manifest.t()}, metadata: map() }
Functions
@spec count(t()) :: non_neg_integer()
Returns the count of registered manifests.
Examples
iex> Registry.count(registry)
3
Checks if a manifest with the given name exists in the registry.
Examples
iex> Registry.exists?(registry, "my-agent")
true
@spec filter_by_capability(t(), atom()) :: [AgentSessionManager.Core.Manifest.t()]
Filters manifests by capability type.
Returns all manifests that have at least one enabled capability of the specified type.
Examples
iex> tool_agents = Registry.filter_by_capability(registry, :tool)
@spec filter_by_provider(t(), String.t()) :: [AgentSessionManager.Core.Manifest.t()]
Filters manifests by provider.
Returns all manifests that have the specified provider.
Examples
iex> anthropic_agents = Registry.filter_by_provider(registry, "anthropic")
@spec from_map(map()) :: {:ok, t()} | {:error, AgentSessionManager.Core.Error.t()}
Reconstructs a registry from a map.
Examples
iex> {:ok, registry} = Registry.from_map(map)
@spec get(t(), String.t()) :: {:ok, AgentSessionManager.Core.Manifest.t()} | {:error, AgentSessionManager.Core.Error.t()}
Retrieves a manifest by name.
Returns an error if the manifest does not exist.
Examples
iex> {:ok, retrieved} = Registry.get(registry, "my-agent")
iex> retrieved.name
"my-agent"
@spec list(t()) :: [AgentSessionManager.Core.Manifest.t()]
Lists all registered manifests in deterministic order (sorted by name).
Examples
iex> manifests = Registry.list(registry)
iex> length(manifests)
2
@spec new() :: t()
Creates a new empty registry.
Examples
iex> Registry.new()
%Registry{manifests: %{}, metadata: %{}}
Creates a new registry with the given options.
Options
:metadata- Optional metadata map for the registry
Examples
iex> Registry.new(metadata: %{version: "1.0"})
%Registry{manifests: %{}, metadata: %{version: "1.0"}}
@spec register(t(), AgentSessionManager.Core.Manifest.t()) :: {:ok, t()} | {:error, AgentSessionManager.Core.Error.t()}
Registers a new manifest in the registry.
Returns an error if:
- A manifest with the same name already exists
- The manifest fails validation
Examples
iex> registry = Registry.new()
iex> {:ok, manifest} = Manifest.new(%{name: "agent", version: "1.0.0"})
iex> {:ok, updated} = Registry.register(registry, manifest)
iex> Registry.exists?(updated, "agent")
true
Converts the registry to a map suitable for JSON serialization.
Examples
iex> map = Registry.to_map(registry)
%{"manifests" => [...], "metadata" => %{}}
@spec unregister(t(), String.t()) :: {:ok, t()} | {:error, AgentSessionManager.Core.Error.t()}
Removes a manifest from the registry by name.
Returns an error if the manifest does not exist.
Examples
iex> {:ok, registry} = Registry.register(Registry.new(), manifest)
iex> {:ok, updated} = Registry.unregister(registry, "my-agent")
iex> Registry.exists?(updated, "my-agent")
false
@spec update(t(), AgentSessionManager.Core.Manifest.t()) :: {:ok, t()} | {:error, AgentSessionManager.Core.Error.t()}
Updates an existing manifest in the registry.
The manifest must already exist (matched by name). Returns an error if the manifest does not exist.
Examples
iex> {:ok, updated_registry} = Registry.update(registry, updated_manifest)
@spec validate_manifest(AgentSessionManager.Core.Manifest.t()) :: :ok | {:error, AgentSessionManager.Core.Error.t()}
Validates a manifest, returning :ok if valid or {:error, error} with
a helpful error message if invalid.
Validation Rules
- Name must be present and non-empty
- Version must be present and non-empty
- All capabilities must be valid
Examples
iex> Registry.validate_manifest(valid_manifest)
:ok
iex> Registry.validate_manifest(%Manifest{})
{:error, %Error{code: :validation_error, message: "Manifest name is required..."}}