BasePlatformAdapter to add a new chat channel: implement four methods, declare capabilities, and inherit robust chunking, retry, typing, and edit-fallback delivery.
Quick Start
A minimal adapter implements four methods and callsdeliver() to send.
Minimal adapter (4 methods)
Subclass
BasePlatformAdapter, declare capabilities, and implement connect, disconnect, send, and get_chat_info.How It Works
deliver() formats, chunks, sends a typing heartbeat, then sends each chunk with retry — all keyed off capabilities.
What Do I Need to Override?
Start with the four abstract methods, then reach for defaults only when the platform can do better.User Interaction Flow
A long user reply flows throughdeliver() as three chunks, with one retry honouring retry_after.
Four behaviours are worth calling out:
- Chunking is text-only. Dict content passes straight through to
send()without chunking or formatting — ideal for rich payloads like attachments or buttons. - Reply-to only on the first chunk. In a multi-chunk reply, chunk #1 carries
reply_to; chunks 2..N are unthreaded follow-ups.SendResult.message_idsgives you every chunk’s id in order. - Typing is best-effort. Failures in
send_typing()are swallowed, so a broken indicator never breaks delivery. edit_messagedeclares “not supported” instead of crashing. Callers on channels without edits use theedit_not_supportedfallback to decide whether to re-send.
Configuration Options
SendResult is the transport-neutral value returned by every send/edit path.
| Field | Type | Default | Description |
|---|---|---|---|
ok | bool | True | Whether the send succeeded. |
message_id | Optional[str] | None | Platform message id of the last message sent. For chunked delivery this is the final chunk. |
chat_id | Optional[str] | None | The chat/channel the message was delivered to. |
message_ids | List[str] | [] | Ids of every chunk that landed, in send order. On a partial failure the ids of chunks that landed before the error are preserved. |
error | Optional[str] | None | Human-readable error string when ok=False. |
retry_after | Optional[float] | None | Suggested seconds to wait before retrying, from the platform’s rate-limit response. Honoured by the default retry loop. |
metadata | Dict[str, Any] | {} | Additional platform-specific result details. On a successful multi-chunk deliver() this includes {"chunks": N}. |
SendResult.to_dict() returns a plain dict for logging and observability.
BasePlatformAdapter class attributes declare adapter behaviour.
| Attribute | Type | Default | Description |
|---|---|---|---|
capabilities | PlatformCapabilities | PlatformCapabilities() | Platform features. Every default behaviour keys off this, degrading gracefully when a flag is absent. |
max_retries | int | 3 | Retry attempts for the default resilient delivery loop. |
retry_base_delay | float | 0.5 | Base backoff (seconds) for exponential retry when retry_after is not supplied. |
retry_after first, then exponential backoff:
send() implementation that raises is treated as a failure and retried — you do not have to catch transport errors yourself.
The four abstract methods every subclass must implement:
| Method | Signature | Purpose |
|---|---|---|
connect | async def connect(*, is_reconnect: bool = False) -> bool | Establish the platform connection. |
disconnect | async def disconnect() -> None | Tear down the connection and release resources. |
send | async def send(chat_id, content, *, reply_to=None, metadata=None) -> SendResult | Send one message (no chunking, no retry). |
get_chat_info | async def get_chat_info(chat_id) -> Dict[str, Any] | Return chat/channel metadata (at least an id key). |
BasePlatformAdapter SDK Reference
Full auto-generated Python API surface for
BasePlatformAdapter and SendResult.Common Patterns
Overridechunk() when the platform needs code-fence-aware splitting.
deliver() skips chunking and formatting.
register_platform(name, cls).
Best Practices
Keep send() a single API call
Keep send() a single API call
Chunking, retry, and typing belong to
deliver(). Keep send() a thin wrapper around one platform API call so the shared machinery stays in control.Return retry_after when the platform tells you to
Return retry_after when the platform tells you to
Populate
SendResult(ok=False, retry_after=X) from send() when the platform reports a rate limit. The default retry loop honours it and beats fixed backoff.Declare only what your platform actually does
Declare only what your platform actually does
A truthful
PlatformCapabilities gives the shared code the best information for graceful degradation. Overstating a capability breaks the fallback path.Don't override edit_message unless supports_edit=True
Don't override edit_message unless supports_edit=True
Callers rely on the built-in
edit_not_supported fallback to decide whether to re-send. Setting supports_edit=True without an override raises NotImplementedError.Advanced: override format_message for markup
Advanced: override format_message for markup
Slack
mrkdwn, Telegram MarkdownV2, and Discord embeds each have quirks. format_message is the single method to apply platform-specific markup.Related
Bot Platform Capabilities
The
PlatformCapabilities descriptor that gates adapter defaults.Bot Platform Plugins
Runtime registration and discovery of platform adapters.
Run Status Controller
Transport-agnostic run-progress state machine for your adapter.

