Canonical adapter behavior for Chat SDK style integrations.
Thread-aware channel contract for Chat SDK integrations.
Adapters return message edits and deletes from parse_event/2 as
Jido.Chat.EventEnvelope values with event type :message_updated or
:message_deleted. The payload must include the provider message_id and
should include channel, thread, author, timestamp, metadata, and raw provider
context when available. An update should include the changed message when
available. A delete must leave message as nil when the provider omits the
deleted content. Core does not fetch missing deleted content.
Summary
Callbacks
Fetches the bytes behind an inbound media reference.
Returns the resource subject for a room or thread.
Returns the canonical participants for a room or thread.
Returns normalized information for one provider user.
Optional listener child-spec callback for adapter-owned ingress workers.
Marks a provider message as read. Repeated calls must be safe.
Functions
Returns adapter channel type with fallback to module name.
Adds a reaction when supported by adapter.
Returns capability matrix for adapter-native vs fallback support.
Returns a normalized typed capability matrix.
Returns operations that always have a core fallback.
Deletes a previously-sent message when supported by adapter.
Normalizes adapter edit results to Jido.Chat.Response.
Fetches channel-level history when supported by adapter.
Fetches media bytes when supported by the adapter.
Fetches a normalized message by id when supported.
Fetches thread-level history when supported by adapter.
Fetches channel metadata as Jido.Chat.ChannelInfo.
Fetches the normalized resource subject for a room or thread.
Fetches thread metadata as a normalized Jido.Chat.Thread.
Formats a typed webhook response using adapter callback when available.
Gets normalized canonical participants for a room or thread.
Gets normalized provider user information when supported.
Default helper to normalize webhook payload through transform_incoming/1.
Initializes adapter resources when supported.
Lists channel thread summaries when supported by adapter.
Loads options for an external or dynamic select.
Marks a provider message as read when supported.
Opens adapter-native modal when supported.
Opens a native platform thread from an existing room message when supported.
Parses request into a normalized event envelope.
Posts a channel-level message using adapter callback or send fallback.
Posts an ephemeral message when supported, with optional DM fallback.
Posts an ephemeral payload using the canonical outbound payload contract.
Posts a normalized outbound payload using adapter-native or core fallback behavior.
Removes a reaction when supported by adapter.
Returns a stable adapter-facing card payload.
Returns a stable adapter-facing Markdown representation.
Returns a stable adapter-facing modal payload.
Renders a finite stream with the canonical provider-independent Markdown rules.
Uploads and sends a file when supported by the adapter.
Normalizes adapter send results to Jido.Chat.Response.
Shuts down adapter resources when supported.
Starts typing indicator when supported by adapter.
Streams chunked text with the adapter's native callback or a core fallback.
Normalizes adapter inbound transformation to Jido.Chat.Incoming.
Validates capability declaration coherence with implemented callbacks.
Verifies webhook request integrity when adapter exposes validation callback.
Types
@type capability_matrix() :: %{optional(atom()) => capability_status()}
@type capability_status() :: :native | :fallback | :unsupported
@type delete_result() :: :ok | {:error, term()}
@type ephemeral_result() :: {:ok, Jido.Chat.EphemeralMessage.t()} | {:error, term()}
@type file_input() :: Jido.Chat.FileUpload.input()
@type incoming_result() :: {:ok, Jido.Chat.Incoming.t()} | {:error, term()}
@type listener_opts() :: keyword()
@type media_reference() :: String.t() | Jido.Chat.Media.t() | map()
@type message_page_result() :: {:ok, Jido.Chat.MessagePage.t()} | {:error, term()}
@type message_result() :: {:ok, Jido.Chat.Message.t()} | {:error, term()}
@type metadata_result() :: {:ok, Jido.Chat.ChannelInfo.t()} | {:error, term()}
@type modal_result() :: {:ok, Jido.Chat.ModalResult.t()} | {:error, term()}
@type options_load_result() :: {:ok, Jido.Chat.OptionsLoadResult.t()} | {:error, Jido.Chat.OptionsLoadError.t()}
@type participants_result() :: {:ok, [Jido.Chat.Participant.t()]} | {:error, term()}
@type raw_payload() :: map()
@type reaction_result() :: :ok | {:error, term()}
@type read_result() :: :ok | {:error, term()}
@type send_result() :: {:ok, Jido.Chat.Response.t()} | {:error, term()}
@type subject_result() :: {:ok, Jido.Chat.MessageSubject.t()} | {:error, term()}
@type thread_page_result() :: {:ok, Jido.Chat.ThreadPage.t()} | {:error, term()}
@type thread_result() :: {:ok, Jido.Chat.Thread.t()} | {:error, term()}
@type typing_result() :: :ok | {:error, term()}
@type user_result() :: {:ok, Jido.Chat.UserInfo.t()} | {:error, term()}
Callbacks
@callback add_reaction( external_room_id(), external_message_id(), emoji :: String.t(), opts :: keyword() ) :: :ok | {:ok, term()} | {:error, term()}
@callback capabilities() :: capability_matrix()
@callback channel_type() :: atom()
@callback delete_message(external_room_id(), external_message_id(), opts :: keyword()) :: :ok | {:ok, term()} | {:error, term()}
@callback edit_message( external_room_id(), external_message_id(), text :: String.t(), opts :: keyword() ) :: send_result() | {:ok, map()} | {:error, term()}
@callback fetch_channel_messages(external_room_id(), opts :: keyword()) :: {:ok, Jido.Chat.MessagePage.t() | map()} | {:error, term()}
@callback fetch_media(reference :: media_reference(), opts :: keyword()) :: media_result()
Fetches the bytes behind an inbound media reference.
The inbound counterpart to send_file/3. The reference is the one the adapter itself
minted on the incoming message, so the adapter that created it is the one that resolves
it — no caller ever learns a provider's reference scheme.
@callback fetch_message(external_room_id(), external_message_id(), opts :: keyword()) :: {:ok, Jido.Chat.Message.t() | Jido.Chat.Incoming.t() | map()} | {:error, term()}
@callback fetch_messages(external_room_id(), opts :: keyword()) :: {:ok, Jido.Chat.MessagePage.t() | map()} | {:error, term()}
@callback fetch_metadata(external_room_id(), opts :: keyword()) :: {:ok, Jido.Chat.ChannelInfo.t() | map()} | {:error, term()}
@callback fetch_subject(external_room_id(), opts :: keyword()) :: {:ok, Jido.Chat.MessageSubject.t() | map()} | {:error, term()}
Returns the resource subject for a room or thread.
@callback fetch_thread(external_room_id(), opts :: keyword()) :: {:ok, Jido.Chat.Thread.t() | map()} | {:error, term()}
@callback format_webhook_response(term(), opts :: keyword()) :: Jido.Chat.WebhookResponse.t() | map() | {:ok, Jido.Chat.WebhookResponse.t() | map()} | {:error, term()}
@callback get_thread_participants(external_room_id(), opts :: keyword()) :: {:ok, [ Jido.Chat.Participant.t() | Jido.Chat.UserInfo.t() | Jido.Chat.Author.t() | map() ]} | {:error, term()}
Returns the canonical participants for a room or thread.
@callback get_user(external_user_id(), opts :: keyword()) :: {:ok, Jido.Chat.UserInfo.t() | map()} | {:error, term()}
Returns normalized information for one provider user.
@callback handle_webhook(chat :: Jido.Chat.t(), raw_payload(), opts :: keyword()) :: {:ok, Jido.Chat.t(), Jido.Chat.Incoming.t()} | {:error, term()}
@callback list_threads(external_room_id(), opts :: keyword()) :: {:ok, Jido.Chat.ThreadPage.t() | map()} | {:error, term()}
@callback listener_child_specs(bridge_id :: String.t(), opts :: listener_opts()) :: {:ok, [Supervisor.child_spec()]} | {:error, term()}
Optional listener child-spec callback for adapter-owned ingress workers.
Listener workers should emit inbound payloads/events through a sink MFA provided
in opts to avoid coupling adapter packages to runtime implementations.
Expected listener opts keys:
:sink_mfa- sink callback MFA, typically{Module, :function, [base_args...]}:bridge_id- configured bridge identifier:bridge_config- resolved bridge config struct/map:instance_module- runtime instance module (opaque to adapters):settings- adapter-specific ingress settings map:ingress- normalized ingress mode/settings map
@callback load_options(Jido.Chat.OptionsLoadEvent.t(), opts :: keyword()) :: {:ok, Jido.Chat.OptionsLoadResult.t() | map()} | {:error, Jido.Chat.OptionsLoadError.t() | map() | :timeout | term()}
@callback mark_as_read( external_room_id(), external_message_id(), opts :: keyword() ) :: :ok | {:ok, term()} | {:error, term()}
Marks a provider message as read. Repeated calls must be safe.
@callback open_dm(external_user_id(), opts :: keyword()) :: {:ok, external_room_id()} | {:error, term()}
@callback open_modal(external_room_id(), payload :: map(), opts :: keyword()) :: {:ok, Jido.Chat.ModalResult.t() | map()} | {:error, term()}
@callback open_thread(external_room_id(), external_message_id(), opts :: keyword()) :: {:ok, Jido.Chat.Thread.t() | map()} | {:error, term()}
@callback parse_event(Jido.Chat.WebhookRequest.t() | map(), opts :: keyword()) :: {:ok, Jido.Chat.EventEnvelope.t() | map() | :noop | nil} | {:error, term()}
@callback post_channel_message(external_room_id(), text :: String.t(), opts :: keyword()) :: send_result() | {:ok, map()} | {:error, term()}
@callback post_ephemeral( external_room_id(), external_user_id(), text :: String.t(), opts :: keyword() ) :: {:ok, Jido.Chat.EphemeralMessage.t() | map()} | {:error, term()}
@callback post_message( external_room_id(), payload :: Jido.Chat.PostPayload.t(), opts :: keyword() ) :: send_result() | {:ok, map()} | {:error, term()}
@callback remove_reaction( external_room_id(), external_message_id(), emoji :: String.t(), opts :: keyword() ) :: :ok | {:ok, term()} | {:error, term()}
@callback send_file(external_room_id(), file :: file_input(), opts :: keyword()) :: send_result() | {:ok, map()} | {:error, term()}
@callback send_message(external_room_id(), text :: String.t(), opts :: keyword()) :: send_result() | {:ok, map()} | {:error, term()}
@callback start_typing(external_room_id(), opts :: keyword()) :: :ok | {:ok, term()} | {:error, term()}
@callback stream(external_room_id(), stream :: Enumerable.t(), opts :: keyword()) :: send_result() | {:ok, map()} | {:error, term()}
@callback transform_incoming(raw_payload()) :: incoming_result() | {:ok, map()}
@callback verify_webhook(Jido.Chat.WebhookRequest.t() | map(), opts :: keyword()) :: :ok | {:error, term()}
Functions
Returns adapter channel type with fallback to module name.
@spec add_reaction( module(), external_room_id(), external_message_id(), String.t(), keyword() ) :: reaction_result()
Adds a reaction when supported by adapter.
@spec capabilities(module()) :: capability_matrix()
Returns capability matrix for adapter-native vs fallback support.
@spec capability_matrix(module()) :: Jido.Chat.CapabilityMatrix.t()
Returns a normalized typed capability matrix.
@spec core_fallback_capabilities() :: [atom()]
Returns operations that always have a core fallback.
@spec delete_message(module(), external_room_id(), external_message_id(), keyword()) :: delete_result()
Deletes a previously-sent message when supported by adapter.
@spec edit_message( module(), external_room_id(), external_message_id(), String.t(), keyword() ) :: send_result()
Normalizes adapter edit results to Jido.Chat.Response.
@spec fetch_channel_messages(module(), external_room_id(), keyword()) :: message_page_result()
Fetches channel-level history when supported by adapter.
@spec fetch_media(module(), media_reference(), keyword()) :: media_result()
Fetches media bytes when supported by the adapter.
@spec fetch_message(module(), external_room_id(), external_message_id(), keyword()) :: message_result()
Fetches a normalized message by id when supported.
@spec fetch_messages(module(), external_room_id(), keyword()) :: message_page_result()
Fetches thread-level history when supported by adapter.
@spec fetch_metadata(module(), external_room_id(), keyword()) :: metadata_result()
Fetches channel metadata as Jido.Chat.ChannelInfo.
@spec fetch_subject(module(), external_room_id(), keyword()) :: subject_result()
Fetches the normalized resource subject for a room or thread.
@spec fetch_thread(module(), external_room_id(), keyword()) :: thread_result()
Fetches thread metadata as a normalized Jido.Chat.Thread.
@spec format_webhook_response(module(), term(), keyword()) :: {:ok, Jido.Chat.WebhookResponse.t()} | {:error, term()}
Formats a typed webhook response using adapter callback when available.
@spec get_thread_participants(module(), external_room_id(), keyword()) :: participants_result()
Gets normalized canonical participants for a room or thread.
@spec get_user(module(), external_user_id(), keyword()) :: user_result()
Gets normalized provider user information when supported.
@spec handle_webhook(module(), Jido.Chat.t(), raw_payload(), keyword()) :: {:ok, Jido.Chat.t(), Jido.Chat.Incoming.t()} | {:error, term()}
Default helper to normalize webhook payload through transform_incoming/1.
Initializes adapter resources when supported.
@spec list_threads(module(), external_room_id(), keyword()) :: thread_page_result()
Lists channel thread summaries when supported by adapter.
@spec load_options(module(), Jido.Chat.OptionsLoadEvent.t() | map(), keyword()) :: options_load_result()
Loads options for an external or dynamic select.
Adapters must validate provider-specific option and option-group limits. The canonical result has no provider-specific maximum.
@spec mark_as_read(module(), external_room_id(), external_message_id(), keyword()) :: read_result()
Marks a provider message as read when supported.
@spec open_modal(module(), external_room_id(), Jido.Chat.Modal.t() | map(), keyword()) :: modal_result()
Opens adapter-native modal when supported.
@spec open_thread(module(), external_room_id(), external_message_id(), keyword()) :: thread_result()
Opens a native platform thread from an existing room message when supported.
@spec parse_event(module(), Jido.Chat.WebhookRequest.t() | map(), keyword()) :: {:ok, Jido.Chat.EventEnvelope.t() | :noop} | {:error, term()}
Parses request into a normalized event envelope.
@spec post_channel_message(module(), external_room_id(), String.t(), keyword()) :: send_result()
Posts a channel-level message using adapter callback or send fallback.
@spec post_ephemeral( module(), external_room_id(), external_user_id(), String.t(), keyword() ) :: ephemeral_result()
Posts an ephemeral message when supported, with optional DM fallback.
@spec post_ephemeral_message( module(), external_room_id(), external_user_id(), String.t() | Jido.Chat.Postable.t() | Jido.Chat.PostPayload.t() | map(), keyword() ) :: ephemeral_result()
Posts an ephemeral payload using the canonical outbound payload contract.
@spec post_message( module(), external_room_id(), Jido.Chat.PostPayload.t() | map(), keyword() ) :: send_result()
Posts a normalized outbound payload using adapter-native or core fallback behavior.
@spec remove_reaction( module(), external_room_id(), external_message_id(), String.t(), keyword() ) :: reaction_result()
Removes a reaction when supported by adapter.
@spec render_card( Jido.Chat.Card.t() | map(), keyword() ) :: map()
Returns a stable adapter-facing card payload.
@spec render_markdown( Jido.Chat.Markdown.t() | map() | String.t(), keyword() ) :: String.t()
Returns a stable adapter-facing Markdown representation.
@spec render_modal( Jido.Chat.Modal.t() | map(), keyword() ) :: map()
Returns a stable adapter-facing modal payload.
@spec render_stream(Enumerable.t()) :: String.t() | nil
Renders a finite stream with the canonical provider-independent Markdown rules.
@spec send_file(module(), external_room_id(), file_input(), keyword()) :: send_result()
Uploads and sends a file when supported by the adapter.
@spec send_message(module(), external_room_id(), String.t(), keyword()) :: send_result()
Normalizes adapter send results to Jido.Chat.Response.
Shuts down adapter resources when supported.
@spec start_typing(module(), external_room_id(), keyword()) :: typing_result()
Starts typing indicator when supported by adapter.
@spec stream(module(), external_room_id(), Enumerable.t(), keyword()) :: send_result()
Streams chunked text with the adapter's native callback or a core fallback.
Adapters with native or append-only transport receive the original enumerable and
can use Jido.Chat.Markdown.StreamRenderer to build safe snapshots. Core fallback
mode :post_edit posts once and edits safe snapshots. Mode :final posts the exact
final Markdown once.
@spec transform_incoming(module(), raw_payload()) :: incoming_result()
Normalizes adapter inbound transformation to Jido.Chat.Incoming.
Validates capability declaration coherence with implemented callbacks.
@spec verify_webhook(module(), Jido.Chat.WebhookRequest.t() | map(), keyword()) :: :ok | {:error, term()}
Verifies webhook request integrity when adapter exposes validation callback.