AgentSessionManager.Ports.ProviderAdapter behaviour
(AgentSessionManager v0.8.0)
Copy Markdown
View Source
Port (interface) for AI provider adapters.
This behaviour defines the contract that all provider adapter implementations must fulfill. It follows the ports and adapters pattern, allowing different AI providers (Anthropic, OpenAI, etc.) to be swapped without changing the core business logic.
Design Principles
- Provider-agnostic: Core logic doesn't depend on provider specifics
- Capability-based: Adapters declare what they support
- Event-driven: Execution emits normalized events via callbacks
- Cancellable: Long-running operations can be cancelled
Implementation Requirements
Implementations must:
- Return a unique provider name
- Declare supported capabilities
- Execute runs and emit events via callback
- Support cancellation of in-progress runs
- Validate provider-specific configuration
Event Emission
During execute/4, adapters should call the :event_callback option (if provided)
with normalized event maps containing:
:type- Event type (e.g.,:run_started,:message_received):session_id- The session ID:run_id- The run ID:data- Event-specific payload:timestamp- When the event occurred
Usage
Adapters are typically used through the SessionManager:
# The SessionManager handles adapter lifecycle
{:ok, manager} = SessionManager.start_link(
adapter: MyAdapter,
adapter_opts: [api_key: "..."]
)
# Or directly for testing
{:ok, adapter} = MyAdapter.start_link(api_key: "...")
{:ok, capabilities} = ProviderAdapter.capabilities(adapter)
{:ok, result} = ProviderAdapter.execute(adapter, run, session, event_callback: fn e -> ... end)
Summary
Callbacks
Cancels an in-progress run.
Returns the list of capabilities supported by this provider.
Executes a run against the AI provider.
Returns the unique name of this provider.
Validates provider-specific configuration.
Functions
Cancels a run.
Returns the list of capabilities.
Executes a run.
Returns the provider name.
Resolves execute call timeout from options, including a grace period for asynchronous result handoff back to callers.
Validates configuration.
Types
@type adapter() :: GenServer.server() | pid() | atom() | module()
@type execute_opts() :: [ event_callback: (map() -> any()), timeout: pos_integer() | :unbounded | :infinity | String.t() ]
Callbacks
@callback cancel(adapter(), String.t()) :: {:ok, String.t()} | {:error, AgentSessionManager.Core.Error.t()}
Cancels an in-progress run.
Providers should attempt to gracefully cancel the run. After cancellation,
the run should emit a :run_cancelled event.
Parameters
adapter- The adapter instancerun_id- The ID of the run to cancel
Returns
{:ok, run_id}- Cancellation initiated (run will emit cancelled event){:error, Error.t()}- Cancellation failed
Examples
iex> MyAdapter.cancel(adapter, "run_123")
{:ok, "run_123"}
@callback capabilities(adapter()) :: {:ok, [AgentSessionManager.Core.Capability.t()]} | {:error, AgentSessionManager.Core.Error.t()}
Returns the list of capabilities supported by this provider.
Capabilities define what the provider can do - tools, resources, sampling modes, etc. The SessionManager uses this to validate that required capabilities are available before starting runs.
Returns
{:ok, [Capability.t()]}- List of supported capabilities{:error, Error.t()}- If capabilities cannot be determined
Examples
iex> MyAdapter.capabilities(adapter)
{:ok, [
%Capability{name: "chat", type: :tool, enabled: true},
%Capability{name: "sampling", type: :sampling, enabled: true}
]}
@callback execute( adapter(), AgentSessionManager.Core.Run.t(), AgentSessionManager.Core.Session.t(), execute_opts() ) :: {:ok, run_result()} | {:error, AgentSessionManager.Core.Error.t()}
Executes a run against the AI provider.
This is the main execution entry point. The adapter should:
- Emit a
:run_startedevent - Send the request to the provider
- Emit events as responses come in (
:message_received,:tool_call_started, etc.) - Emit
:run_completedor:run_failedwhen done - Return the final result
Parameters
adapter- The adapter instancerun- The run to execute (contains input, session_id, etc.)session- The parent session (contains context, metadata)opts- Execution options::event_callback- Function called for each event emitted:timeout- Maximum execution time in milliseconds
Returns
{:ok, result}- Execution completed successfullyresult.output- The final output from the providerresult.token_usage- Token usage statisticsresult.events- All events emitted during execution
{:error, Error.t()}- Execution failed
Examples
iex> callback = fn event -> Logger.info("Event: #{inspect(event)}") end
iex> MyAdapter.execute(adapter, run, session, event_callback: callback)
{:ok, %{
output: %{content: "Hello!"},
token_usage: %{input_tokens: 10, output_tokens: 20},
events: [...]
}}
Returns the unique name of this provider.
This name is used for logging, metrics, and identifying the provider in multi-provider configurations.
Examples
iex> MyAdapter.name(adapter)
"anthropic"
@callback validate_config(adapter() | module(), map()) :: :ok | {:error, AgentSessionManager.Core.Error.t()}
Validates provider-specific configuration.
This is called before the adapter starts to ensure all required configuration is present and valid.
Parameters
adapter- The adapter instance (or module for static validation)config- Configuration map to validate
Returns
:ok- Configuration is valid{:error, Error.t()}- Configuration is invalid
Examples
iex> MyAdapter.validate_config(adapter, %{api_key: "sk-..."})
:ok
iex> MyAdapter.validate_config(adapter, %{})
{:error, %Error{code: :validation_error, message: "api_key is required"}}
Functions
@spec cancel(adapter(), String.t()) :: {:ok, String.t()} | {:error, AgentSessionManager.Core.Error.t()}
Cancels a run.
@spec capabilities(adapter()) :: {:ok, [AgentSessionManager.Core.Capability.t()]} | {:error, AgentSessionManager.Core.Error.t()}
Returns the list of capabilities.
@spec execute( adapter(), AgentSessionManager.Core.Run.t(), AgentSessionManager.Core.Session.t(), execute_opts() ) :: {:ok, run_result()} | {:error, AgentSessionManager.Core.Error.t()}
Executes a run.
Returns the provider name.
@spec resolve_execute_timeout(keyword()) :: pos_integer()
Resolves execute call timeout from options, including a grace period for asynchronous result handoff back to callers.
@spec validate_config(adapter() | module(), map()) :: :ok | {:error, AgentSessionManager.Core.Error.t()}
Validates configuration.