Applies agent→renderer messages to a set of surfaces.
A processor is plain data: process/2 takes a processor and a raw
payload (a message, a list of messages, a {"messages": [...]}
wrapper) and returns the updated processor together with the effects a
host may react to. Nothing is delivered by callback and no process is
involved; the host owns the processor value.
catalog = A2UICore.Catalog.Basic.catalog("v0.9")
processor = A2UICore.Processor.new([catalog])
{:ok, processor, effects} =
A2UICore.Processor.process(processor, %{
"version" => "v0.9",
"createSurface" => %{"surfaceId" => "main", "catalogId" => catalog.catalog_id}
})Semantics
Messages are decoded (A2UICore.Message.decode/2) and their operations
applied in order. There is no rollback across operations: when one
fails, the operations before it stay applied and process/2 returns
{:error, error, processor} with that partially updated processor.
Within one updateComponents the update is atomic — a failing batch
leaves the surface untouched.
createSurface— the surface's default catalog is the one named bycatalogId. A v1.0 surface may name none and then has no default catalog; before v1.0 the processor's first catalog is the fallback. The message's version must be compatible with the catalog (A2UICore.Version) and a theme is validated against it. The surface can use every catalog of its protocol version. InlinedataModelandcomponentsare applied right after the surface is created.updateComponents— each component takes the catalog named by itscatalogId, else the one it already has (when its type is unchanged), else the surface's default; from v1.0 a component that names none on a surface without a default catalog is an error, and so is a function call nested in it whose catalog does not resolve. With a validation configuration the batch is validated as a whole before it is committed (A2UICore.Validation.ComponentsUpdate).updateDataModel— writes into the surface's data model.deleteSurface— removes the surface; an unknown id is ignored.callRendererFunction— runs the function (seeA2UICore.RPC) against the data of the surface itssurfaceIdnames, or of no surface when it names none, and comes back as an{:rpc_response, message}effect: therendererFunctionResponseto send to the agent. Calls that require user activation need the:user_activatedoption.agentFunctionResponse— settles the pending agent call it answers and comes back as an{:rpc_settled, call_id, outcome}effect. Neither changes surface state.
Without a validation configuration (:validation option) component
batches are committed unchecked.
Effects
{:surface_created, surface_id}{:surface_deleted, surface_id}{:components_updated, surface_id, component_ids}{:data_model_updated, surface_id, path}{:rpc_response, message}{:rpc_settled, call_id, {:ok, value} | {:error, error}}
Calling the agent
call_agent_function/4 registers a call and returns the
callAgentFunction message. The call is settled by an
agentFunctionResponse message, by timeout_agent_call/2 when the
host's timer for it fires, by cancel_agent_call/3, or by dispose/1;
the settlements come back as {:rpc_settled, …} effects.
Summary
Functions
The timeout, in milliseconds, of a pending agent call: the host starts a
timer for it and reports the expiry with timeout_agent_call/2.
nil for a call that is not pending or has no timeout.
Applies one operation.
Applies already-decoded operations in order, as process/2 does.
Registers a call to an agent function on surface_id and returns the
callAgentFunction message to send; see A2UICore.RPC.call_agent_function/4
for the call and its options.
Rejects a pending agent call the host abandoned, with CANCELLED.
Rejects every pending agent call with CANCELLED and stops answering
function calls. Surfaces are left as they are.
Creates a processor over catalogs. The first catalog is the default
for surfaces that name none.
Decodes payload and applies its operations in order.
The renderer capabilities for the processor's catalogs, keyed by protocol version.
The data models of the surfaces that asked for them (sendDataModel),
as %{"version" => …, "surfaces" => %{id => data}}, or nil when no
surface did.
Writes value at path of a surface's data model on the renderer's
behalf — user input reaching a two-way binding. It is the same write as
an updateDataModel message, but not one the agent sent, so the
validation configuration's allowed_messages does not apply.
The surface with id, or nil.
All surfaces, sorted by id.
Rejects a pending agent call whose timer fired, with TIMEOUT.
Types
@type t() :: %A2UICore.Processor{ catalogs: [A2UICore.Catalog.t()], group: A2UICore.State.SurfaceGroup.t(), rpc: A2UICore.RPC.t(), validation: A2UICore.Validation.Config.t() | nil }
Functions
The timeout, in milliseconds, of a pending agent call: the host starts a
timer for it and reports the expiry with timeout_agent_call/2.
nil for a call that is not pending or has no timeout.
@spec apply_operation(t(), A2UICore.Message.Operation.t(), keyword()) :: {:ok, t(), [effect()]} | {:error, A2UICore.Error.t(), t()}
Applies one operation.
@spec apply_operations(t(), [A2UICore.Message.Operation.t()], keyword()) :: {:ok, t(), [effect()]} | {:error, A2UICore.Error.t(), t()}
Applies already-decoded operations in order, as process/2 does.
@spec call_agent_function(t(), String.t(), map(), keyword()) :: {:ok, t(), map()} | {:error, A2UICore.Error.t()}
Registers a call to an agent function on surface_id and returns the
callAgentFunction message to send; see A2UICore.RPC.call_agent_function/4
for the call and its options.
Rejects a pending agent call the host abandoned, with CANCELLED.
Rejects every pending agent call with CANCELLED and stops answering
function calls. Surfaces are left as they are.
@spec new([A2UICore.Catalog.t()], keyword()) :: t()
Creates a processor over catalogs. The first catalog is the default
for surfaces that name none.
Options: :validation — an A2UICore.Validation.Config applied to
component batches (none by default); :default_timeout_ms — the
timeout of agent calls that name none (30 000).
Raises ArgumentError when catalogs is empty.
Decodes payload and applies its operations in order.
Returns {:ok, processor, effects}, or {:error, error, processor}
where processor holds whatever was applied before the failure.
Options: :user_activated — the messages are processed inside a user
gesture (functions that require activation run only then).
@spec renderer_capabilities(t(), keyword()) :: {:ok, map()} | {:error, A2UICore.Error.t()}
The renderer capabilities for the processor's catalogs, keyed by protocol version.
Options:
:versions— the protocol versions to describe (required);:include_inline_catalogs— add each catalog's definition under"inlineCatalogs": its document (A2UICore.Catalog.to_json/2) from v1.0 on, else a legacy inline catalog whose components areallOfenvelopes over:component_envelope_ref(defaultcommon_types.json#/$defs/ComponentCommon), built from the resolved schemas.
Returns {:error, error} when no version is given.
@spec renderer_data_model(t(), String.t() | nil) :: {:ok, map() | nil} | {:error, A2UICore.Error.t()}
The data models of the surfaces that asked for them (sendDataModel),
as %{"version" => …, "surfaces" => %{id => data}}, or nil when no
surface did.
With version, only surfaces whose catalog is compatible with it are
included. Without, the version is the one all such surfaces share
("v1.0" when none declares one); surfaces on different versions are
an error.
@spec set_data(t(), String.t(), String.t(), term()) :: {:ok, t(), [effect()]} | {:error, A2UICore.Error.t()}
Writes value at path of a surface's data model on the renderer's
behalf — user input reaching a two-way binding. It is the same write as
an updateDataModel message, but not one the agent sent, so the
validation configuration's allowed_messages does not apply.
Returns {:ok, processor, [{:data_model_updated, surface_id, path}]},
or {:error, error} for an unknown surface or an invalid path.
@spec surface(t(), String.t()) :: A2UICore.State.Surface.t() | nil
The surface with id, or nil.
@spec surfaces(t()) :: [A2UICore.State.Surface.t()]
All surfaces, sorted by id.
Rejects a pending agent call whose timer fired, with TIMEOUT.