BeamAgent.Runtime (beam_agent_ex v0.1.0)

Copy Markdown View Source

Runtime state management for providers and agents.

This module is the public API for the BeamAgent runtime layer. It manages per-session provider selection, provider configuration, default agent selection, and query option merging. All state is ETS-backed, keyed by session pid or session ID binary, and persists for the node lifetime or until explicitly cleared.

The runtime layer is backend-agnostic. It stores canonical defaults that can be merged into future requests regardless of which backend transport is active.

When to use directly vs through BeamAgent

Use this module directly when you need to inspect or change provider/agent selection at runtime — for example, in a multi-provider orchestrator, a dynamic model-switching workflow, or a test that validates provider routing.

Quick example

# Query the current provider for a session:
{:ok, "anthropic"} = BeamAgent.Runtime.current_provider(session)

# Switch provider at runtime:
:ok = BeamAgent.Runtime.set_provider(session, "openai")

# Validate a provider config before storing it:
:ok = BeamAgent.Runtime.validate_provider_config("anthropic", %{api_key: "sk-ant-..."})

# List all providers visible through the unified runtime layer:
{:ok, providers} = BeamAgent.Runtime.list_providers(session)

Core concepts

  • Providers: API key sources that supply model access. Each provider has an ID (e.g., "anthropic", "openai", "google"), authentication methods, capabilities, and configuration keys.

  • Agents: AI model identities used for queries. The runtime tracks the currently selected default agent per session and merges it into query options automatically.

  • Session State: an ETS-backed map per session holding :provider_id, :provider config, :model_id, :agent, :mode, :system, and :tools.

Architecture deep dive

This module delegates every call to :beam_agent_runtime. The underlying implementation (:beam_agent_runtime_core) queries the ETS-backed runtime state first, then falls back to native provider listings (for OpenCode) or session info inference via :gen_statem.call.

See also: BeamAgent.Catalog, BeamAgent.Control, BeamAgent.

Summary

Functions

Abort the currently active query and reset the session to ready state.

Cancel an in-progress account login flow.

Retrieve account and authentication information for the session's backend.

Initiate an account login flow.

Log out of the current account.

Get rate limit information for the current account.

Clear all app registry data.

Ensure the unified runtime ETS table exists.

Get information about the current app or project context.

Initialize the app/project context by scanning the working directory.

Append a log entry to the session's app log.

List available app modes for the session.

Register or update an app entry for a session.

Remove an app entry for a session.

List apps and projects registered for the session.

List apps and projects for the session with filter options.

Clear all runtime state across every session.

Clear any default agent selection for a session.

Clear any default provider selection for a session.

Delete all runtime state for a session.

Return the currently selected default agent for a session.

Return the currently selected provider for a session.

Ensure the runtime ETS table exists.

Get the authentication status for the session's active provider.

Get the backend's own session identifier for a running session.

Read the provider configuration view for a session.

Return the current runtime state map for a session.

Get the overall status of a session including health and metadata.

Interrupt the currently active query on a session.

List providers visible through the unified runtime layer.

Merge runtime defaults into query parameters.

Return high-level provider status for the session's current provider.

Return status for a specific provider by ID.

Prime runtime state from session options.

Send a backend-specific control message to a session.

Set the default agent for future queries on a session.

Set the maximum number of thinking tokens for the session.

Change the LLM model for a running session.

Change the permission mode for a running session.

Set the default provider for future queries on a session.

Set provider configuration for future queries on a session.

Stop a running task by its identifier.

Validate a provider configuration map.

Start the Windows sandbox setup process.

Functions

abort(session)

@spec abort(pid()) :: :ok | {:error, :not_supported | term()}

Abort the currently active query and reset the session to ready state.

Stronger than interrupt/1: forcibly cancels the query and transitions the session engine back to the ready state.

Parameters

  • session -- pid of a running session.

Returns

  • :ok or {:error, reason}.

account_cancel(session, opts)

@spec account_cancel(pid(), map()) :: {:ok, map()} | {:error, term()}

Cancel an in-progress account login flow.

Parameters

  • session -- pid of a running session.
  • opts -- should match the original login parameters.

Returns

  • {:ok, result} or {:error, reason}.

account_info(session)

@spec account_info(pid()) :: {:ok, map()} | {:error, term()}

Retrieve account and authentication information for the session's backend.

Returns details about the authenticated user including identity, subscription plan, usage quotas, and the authentication method in use.

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, info_map} or {:error, reason}.

account_login(session, opts)

@spec account_login(pid(), map()) :: {:ok, map()} | {:error, term()}

Initiate an account login flow.

Parameters

  • session -- pid of a running session.
  • opts -- credentials/OAuth parameters map.

Returns

  • {:ok, result} or {:error, reason}.

account_logout(session)

@spec account_logout(pid()) :: {:ok, map()} | {:error, term()}

Log out of the current account.

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, result} or {:error, reason}.

account_rate_limits(session)

@spec account_rate_limits(pid()) :: {:ok, map()} | {:error, term()}

Get rate limit information for the current account.

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, rate_limit_info} or {:error, reason}.

app_clear()

@spec app_clear() :: :ok

Clear all app registry data.

app_ensure_tables()

@spec app_ensure_tables() :: :ok

Ensure the unified runtime ETS table exists.

Idempotent. Used by the app registry before any ETS access.

app_info(session)

@spec app_info(pid()) ::
  {:ok, :beam_agent_runtime.app_entry()} | {:error, :no_app | term()}

Get information about the current app or project context.

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, app_info} or {:error, reason}.

app_init(session)

@spec app_init(pid()) :: {:ok, :beam_agent_runtime.app_entry()} | {:error, term()}

Initialize the app/project context by scanning the working directory.

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, result_map} or {:error, reason}.

app_log(session, body)

@spec app_log(pid(), map()) :: {:ok, map()} | {:error, term()}

Append a log entry to the session's app log.

Parameters

  • session -- pid of a running session.
  • body -- log entry map.

Returns

  • {:ok, result} or {:error, reason}.

app_modes(session)

@spec app_modes(pid()) :: {:ok, [binary()]} | {:error, term()}

List available app modes for the session.

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, modes} or {:error, reason}.

app_register(session, app_id, opts)

@spec app_register(pid() | binary(), binary(), map()) ::
  {:ok, :beam_agent_runtime.app_entry()}

Register or update an app entry for a session.

Creates a new entry if app_id is not yet registered under session. Updates the existing entry (merging opts) if it already exists.

opts may include :name (binary), :modes (list of binaries), and :metadata (map).

app_unregister(session, app_id)

@spec app_unregister(pid() | binary(), binary()) :: :ok

Remove an app entry for a session.

No-op if the entry does not exist.

apps_list(session)

@spec apps_list(pid()) :: {:ok, [:beam_agent_runtime.app_entry()]} | {:error, term()}

List apps and projects registered for the session.

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, apps} or {:error, reason}.

apps_list(session, opts)

@spec apps_list(pid(), map()) ::
  {:ok, [:beam_agent_runtime.app_entry()]} | {:error, term()}

List apps and projects for the session with filter options.

Parameters

  • session -- pid of a running session.
  • opts -- filter options map.

Returns

  • {:ok, apps} or {:error, reason}.

clear()

@spec clear() :: :ok

Clear all runtime state across every session.

Deletes all objects from the runtime ETS table. Use this for test cleanup or node-wide reset.

clear_agent(session)

@spec clear_agent(pid() | binary()) :: :ok

Clear any default agent selection for a session.

After clearing, current_agent/1 will attempt inference from session metadata.

clear_provider(session)

@spec clear_provider(pid() | binary()) :: :ok

Clear any default provider selection for a session.

Removes both the provider ID and provider config from the runtime state. After clearing, current_provider/1 will attempt inference from session metadata.

clear_session(session)

@spec clear_session(pid() | binary()) :: :ok

Delete all runtime state for a session.

Removes the session's entry from the runtime ETS table entirely.

current_agent(session)

@spec current_agent(pid() | binary()) :: {:ok, binary()} | {:error, :not_set}

Return the currently selected default agent for a session.

Checks the runtime state first. If no agent is explicitly set, attempts to infer the agent from the session's backend metadata.

Returns {:ok, agent_id} or {:error, :not_set}.

Example

{:ok, "claude-sonnet-4-6"} = BeamAgent.Runtime.current_agent(session)

current_provider(session)

@spec current_provider(pid() | binary()) :: {:ok, binary()} | {:error, :not_set}

Return the currently selected provider for a session.

Checks the runtime state first. If no provider is explicitly set, attempts to infer the provider from the session's backend metadata.

Returns {:ok, provider_id} or {:error, :not_set}.

ensure_tables()

@spec ensure_tables() :: :ok

Ensure the runtime ETS table exists.

Creates the runtime state table if it does not already exist. Idempotent.

get_auth_status(session)

@spec get_auth_status(pid()) :: {:ok, map()} | {:error, term()}

Get the authentication status for the session's active provider.

Returns whether the session is currently authenticated, which authentication method is in use, and token expiration details.

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, auth_status} containing :authenticated, :auth_method, and :expires_at.
  • {:error, reason} on failure.

get_last_session_id(session)

@spec get_last_session_id(pid()) :: {:ok, binary()} | {:error, term()}

Get the backend's own session identifier for a running session.

Returns the session ID as assigned by the backend (not the BEAM pid).

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, session_id} where session_id is a binary.
  • {:error, reason} on failure.

get_provider_config(session)

@spec get_provider_config(pid() | binary()) :: {:ok, map()}

Read the provider configuration view for a session.

Returns a redacted config map suitable for display and status surfaces. Secret values such as API keys and OAuth callback fields are replaced with :redacted markers. Returns {:ok, config} or an empty map when no config is stored.

get_state(session)

@spec get_state(pid() | binary()) :: {:ok, :beam_agent_runtime_core.runtime_state()}

Return the current runtime state map for a session.

Returns {:ok, state} — always succeeds, returning an empty map if no state has been registered. Secret-bearing provider fields are redacted in the public view.

get_status(session)

@spec get_status(pid()) :: {:ok, map()} | {:error, term()}

Get the overall status of a session including health and metadata.

Assembles a comprehensive status snapshot combining the session's health state, connection status, backend identifier, model, and session metadata.

Parameters

  • session -- pid of a running session.

Returns

  • {:ok, status_map} containing keys such as :health, :backend, :session_id, :model, and :connected.
  • {:error, reason} on failure.

interrupt(session)

@spec interrupt(pid()) :: :ok | {:error, :no_active_query | :not_supported | term()}

Interrupt the currently active query on a session.

Sends an interrupt signal to the backend. If the backend supports native interrupts, it uses that; otherwise falls back to an OS-level signal for port-based transports.

Parameters

  • session -- pid of a running session.

Returns

  • :ok if the interrupt was sent.
  • {:error, :not_supported} if the backend does not support interrupts.
  • {:error, reason} on failure.

list_providers(session)

@spec list_providers(pid() | binary()) :: {:ok, [map()]}

List providers visible through the unified runtime layer.

Prefers native provider listings when the backend exposes them (e.g., OpenCode's provider_list). Falls back to a best-effort catalog derived from the built-in provider registry and current runtime state.

merge_query_opts(session, params)

@spec merge_query_opts(pid() | binary(), map()) :: map()

Merge runtime defaults into query parameters.

Combines stored runtime state (:provider_id, :provider, :model_id, :agent, :mode, :system, :tools) with the explicit query params. Explicit params always take precedence. Nested provider config maps are merged shallowly.

provider_status(session)

@spec provider_status(pid() | binary()) :: {:ok, %{provider_id: nil | binary()}}

Return high-level provider status for the session's current provider.

Returns {:ok, status_map} with :provider_id and current state details. If no provider is set, :provider_id is nil and any config in the public view remains redacted.

provider_status(session, provider_id)

@spec provider_status(pid() | binary(), binary()) :: {:ok, %{provider_id: binary()}}

Return status for a specific provider by ID.

Includes configured state, authentication methods, capabilities, config keys, and whether the provider is the current selection.

Returns {:ok, status_map} with :provider_id set.

register_session(session, opts)

@spec register_session(pid() | binary(), map()) :: :ok

Prime runtime state from session options.

Extracts canonical runtime keys (:provider_id, :provider, :model_id, :agent, :mode, :system, :tools) from the options map and persists them in ETS. Keys with nil or undefined values are filtered out. Typically called once during session initialization.

send_control(session, method, params)

@spec send_control(pid(), binary(), map()) ::
  {:ok, map()} | {:error, :not_supported | term()}

Send a backend-specific control message to a session.

Control messages provide a generic extension point for features not covered by the typed API.

Parameters

  • session -- pid of a running session.
  • method -- binary method name (e.g., "mcp_message", "set_config").
  • params -- map of method-specific parameters.

Returns

  • {:ok, result} on success.
  • {:error, :not_supported} if the backend does not handle this method.
  • {:error, reason} on failure.

set_agent(session, agent_id)

@spec set_agent(pid() | binary(), binary()) :: :ok

Set the default agent for future queries on a session.

set_max_thinking_tokens(session, max_tokens)

@spec set_max_thinking_tokens(pid(), pos_integer()) :: {:ok, map()} | {:error, term()}

Set the maximum number of thinking tokens for the session.

Controls how many tokens the backend's reasoning model may use for internal chain-of-thought before producing a visible response.

Parameters

  • session -- pid of a running session.
  • max_tokens -- positive integer token limit.

Returns

  • {:ok, result} or {:error, reason}.

set_model(session, model)

@spec set_model(pid(), binary()) ::
  {:ok, binary()} | {:error, :not_supported | term()}

Change the LLM model for a running session.

Sends a model-switch command to the backend. If the backend supports native model switching, it is used directly; otherwise the runtime core stores it in its own state.

Parameters

  • session -- pid of a running session.
  • model -- binary model identifier (e.g., "claude-sonnet-4-20250514").

Returns

  • {:ok, model} on success.
  • {:error, reason} on failure.

set_permission_mode(session, mode)

@spec set_permission_mode(pid(), binary()) ::
  {:ok, binary() | map()} | {:error, :not_supported | term()}

Change the permission mode for a running session.

Controls how the backend handles tool execution and file edit approval.

Parameters

  • session -- pid of a running session.
  • mode -- binary permission mode (e.g., "default", "accept_edits").

Returns

  • {:ok, mode} on success.
  • {:error, reason} on failure.

set_provider(session, provider_id)

@spec set_provider(pid() | binary(), binary()) :: :ok

Set the default provider for future queries on a session.

Example

:ok = BeamAgent.Runtime.set_provider(session, "anthropic")
{:ok, "anthropic"} = BeamAgent.Runtime.current_provider(session)

set_provider_config(session, config)

@spec set_provider_config(pid() | binary(), map()) ::
  :ok | {:error, :invalid_api_key | :invalid_provider_config}

Set provider configuration for future queries on a session.

Stores a structured provider config map (API keys, base URLs, etc.) and attempts to infer the provider ID from the config.

Returns {:error, :invalid_api_key} if the config contains a malformed API key.

stop_task(session, task_id)

@spec stop_task(pid(), binary()) :: {:ok, map()} | {:error, term()}

Stop a running task by its identifier.

Sends an interrupt to the session and marks the task as stopped.

Parameters

  • session -- pid of a running session.
  • task_id -- binary task identifier.

Returns

  • {:ok, result} or {:error, reason}.

validate_provider_config(provider_id, config)

@spec validate_provider_config(binary() | nil, map()) ::
  :ok | {:error, :invalid_api_key | :invalid_provider_config}

Validate a provider configuration map.

Performs conservative validation — checks shape and obvious type errors without overfitting to a single backend's schema. Currently validates that any :api_key present is a non-empty binary.

Returns :ok for valid configs, or {:error, reason} for invalid ones.

Example

:ok = BeamAgent.Runtime.validate_provider_config("anthropic", %{api_key: "sk-ant-..."})

{:error, :invalid_api_key} =
  BeamAgent.Runtime.validate_provider_config("anthropic", %{api_key: ""})

windows_sandbox_setup_start(session, opts)

@spec windows_sandbox_setup_start(pid(), map()) :: {:ok, map()} | {:error, term()}

Start the Windows sandbox setup process.

Initiates sandbox configuration for backends that run in a Windows environment. On non-Windows platforms the universal fallback returns status: :not_applicable.

Parameters

  • session -- pid of a running session.
  • opts -- setup options map.

Returns

  • {:ok, result} or {:error, reason}.