Skip to content

Channels API

The channels module provides functionality for formatting responses across different communication channels like SMS, web chat, and voice interfaces. Each channel has specific constraints and capabilities that are handled automatically.

Overview

lex-helper supports multiple channels with automatic formatting based on the channel's capabilities:

  • SMS: Text-only with length constraints and link handling
  • Web/Lex: Rich formatting with buttons, cards, and media
  • Voice: Speech-optimized responses with SSML support

Channel Formatting

The main entry point for channel-aware formatting.

Classes

Functions

Base Channel

Abstract base class for all channel implementations.

Base channel interface for message formatting.

Classes

Channel

Bases: ABC

Abstract base class for channel-specific message formatting.

Functions

format_message abstractmethod
format_message(message: LexMessages) -> LexBaseResponse

Format a single message for the specific channel.

Parameters:

Name Type Description Default
message LexMessages

The Lex message to format

required

Returns:

Type Description
LexBaseResponse

The formatted message string

Source code in lex_helper/channels/base.py
@abstractmethod
def format_message(self, message: LexMessages) -> LexBaseResponse:
    """Format a single message for the specific channel.

    Args:
        message: The Lex message to format

    Returns:
        The formatted message string
    """
    pass
format_messages abstractmethod
format_messages(messages: list[LexMessages]) -> list[LexBaseResponse]

Format a list of messages for the specific channel.

Parameters:

Name Type Description Default
messages list[LexMessages]

List of Lex messages to format

required

Returns:

Type Description
list[LexBaseResponse]

List of formatted message strings

Source code in lex_helper/channels/base.py
@abstractmethod
def format_messages(self, messages: list[LexMessages]) -> list[LexBaseResponse]:
    """Format a list of messages for the specific channel.

    Args:
        messages: List of Lex messages to format

    Returns:
        List of formatted message strings
    """
    pass
format_plain_text
format_plain_text(message: LexPlainText) -> LexBaseResponse

Format a plain text message.

Parameters:

Name Type Description Default
message LexPlainText

The plain text message to format

required

Returns:

Type Description
LexBaseResponse

The formatted plain text

Source code in lex_helper/channels/base.py
def format_plain_text(self, message: LexPlainText) -> LexBaseResponse:
    """Format a plain text message.

    Args:
        message: The plain text message to format

    Returns:
        The formatted plain text
    """
    return LexPlainText(content=message.content or "")
format_image_card
format_image_card(card: LexImageResponseCard) -> LexBaseResponse

Format an image response card.

Parameters:

Name Type Description Default
card LexImageResponseCard

The image card to format

required

Returns:

Type Description
LexBaseResponse

The formatted card text

Source code in lex_helper/channels/base.py
def format_image_card(self, card: LexImageResponseCard) -> LexBaseResponse:
    """Format an image response card.

    Args:
        card: The image card to format

    Returns:
        The formatted card text
    """
    parts = [card.imageResponseCard.title]
    if card.imageResponseCard.subtitle:
        parts.append(card.imageResponseCard.subtitle)
    if card.imageResponseCard.imageUrl:
        parts.append(f"Image: {card.imageResponseCard.imageUrl}")
    if card.imageResponseCard.buttons:
        button_texts = [f"[{btn.text}]" for btn in card.imageResponseCard.buttons]
        parts.append("Buttons: " + " ".join(button_texts))
    return LexPlainText(content="\n".join(parts))
format_custom_payload
format_custom_payload(payload: LexCustomPayload) -> LexBaseResponse

Format a custom payload message.

Parameters:

Name Type Description Default
payload LexCustomPayload

The custom payload to format

required

Returns:

Type Description
LexBaseResponse

The formatted payload text, or None if payload cannot be formatted

Source code in lex_helper/channels/base.py
def format_custom_payload(self, payload: LexCustomPayload) -> LexBaseResponse:
    """Format a custom payload message.

    Args:
        payload: The custom payload to format

    Returns:
        The formatted payload text, or None if payload cannot be formatted
    """
    if isinstance(payload.content, str):
        return LexCustomPayload(content=payload.content)
    elif isinstance(payload.content, dict) and "text" in payload.content:  # type: ignore[unreachable]
        return LexCustomPayload(content=str(payload.content["text"]))
    return LexCustomPayload(content=str(payload.content))

Lex Channel

Default Lex channel with full rich formatting support.

Lex-specific channel implementation.

Classes

LexChannel

Bases: Channel

Channel implementation for Lex-specific message formatting.

Functions

format_message
format_message(message: LexMessages) -> LexBaseResponse

Format a single Lex message.

Parameters:

Name Type Description Default
message LexMessages

The Lex message to format

required

Returns:

Type Description
LexBaseResponse

The formatted message string

Source code in lex_helper/channels/lex.py
def format_message(self, message: LexMessages) -> LexBaseResponse:
    """Format a single Lex message.

    Args:
        message: The Lex message to format

    Returns:
        The formatted message string
    """
    if isinstance(message, LexPlainText):
        return self.format_plain_text(message)
    if isinstance(message, LexImageResponseCard):
        return self.format_image_card(message)
    if isinstance(message, LexCustomPayload):  # type: ignore
        return self.format_custom_payload(message)
    return LexPlainText(content="Unsupported message type")
format_messages
format_messages(messages: list[LexMessages]) -> list[LexBaseResponse]

Format a list of Lex messages.

Parameters:

Name Type Description Default
messages list[LexMessages]

List of Lex messages to format

required

Returns:

Type Description
list[LexBaseResponse]

List of formatted message strings

Source code in lex_helper/channels/lex.py
def format_messages(self, messages: list[LexMessages]) -> list[LexBaseResponse]:
    """Format a list of Lex messages.

    Args:
        messages: List of Lex messages to format

    Returns:
        List of formatted message strings
    """
    return [self.format_message(message) for message in messages]
format_plain_text
format_plain_text(message: LexPlainText) -> LexBaseResponse

Format a Lex plain text message.

Overrides the base implementation to handle Lex-specific formatting.

Parameters:

Name Type Description Default
message LexPlainText

The plain text message to format

required

Returns:

Type Description
LexBaseResponse

The formatted plain text

Source code in lex_helper/channels/lex.py
def format_plain_text(self, message: LexPlainText) -> LexBaseResponse:
    """Format a Lex plain text message.

    Overrides the base implementation to handle Lex-specific formatting.

    Args:
        message: The plain text message to format

    Returns:
        The formatted plain text
    """
    # For Lex, we can just use the base implementation
    return super().format_plain_text(message)
format_image_card
format_image_card(card: LexImageResponseCard) -> LexBaseResponse

Format a Lex image response card.

Overrides the base implementation to handle Lex-specific formatting.

Parameters:

Name Type Description Default
card LexImageResponseCard

The image card to format

required

Returns:

Type Description
LexBaseResponse

The formatted card text

Source code in lex_helper/channels/lex.py
def format_image_card(self, card: LexImageResponseCard) -> LexBaseResponse:
    """Format a Lex image response card.

    Overrides the base implementation to handle Lex-specific formatting.

    Args:
        card: The image card to format

    Returns:
        The formatted card text
    """
    # For Lex, we want to format buttons with their value rather than text
    parts = [card.imageResponseCard.title]
    if card.imageResponseCard.subtitle:
        parts.append(card.imageResponseCard.subtitle)
    if card.imageResponseCard.imageUrl:
        parts.append(f"Image: {card.imageResponseCard.imageUrl}")
    if card.imageResponseCard.buttons:
        button_texts = [f"[{btn.text} -> {btn.value}]" for btn in card.imageResponseCard.buttons]
        parts.append("Buttons: " + " ".join(button_texts))
    return LexPlainText(content="\n".join(parts))
format_custom_payload
format_custom_payload(payload: LexCustomPayload) -> LexBaseResponse

Format a Lex custom payload message.

Overrides the base implementation to handle Lex-specific formatting.

Parameters:

Name Type Description Default
payload LexCustomPayload

The custom payload to format

required

Returns:

Type Description
LexBaseResponse

The formatted payload text

Source code in lex_helper/channels/lex.py
def format_custom_payload(self, payload: LexCustomPayload) -> LexBaseResponse:
    """Format a Lex custom payload message.

    Overrides the base implementation to handle Lex-specific formatting.

    Args:
        payload: The custom payload to format

    Returns:
        The formatted payload text
    """
    content = payload.content
    if isinstance(content, dict):
        if "text" in content:
            return str(content["text"])  # type: ignore
        if "message" in content:
            return str(content["message"])  # type: ignore
        return LexCustomPayload(content=str(content))
    return LexCustomPayload(content=str(content))

SMS Channel

SMS-specific formatting with text constraints and optimizations.

SMS-specific channel implementation.

Classes

SMSChannel

Bases: Channel

Channel implementation for SMS-specific message formatting.

Functions

format_message
format_message(message: LexMessages) -> LexBaseResponse

Format a single message for SMS.

Parameters:

Name Type Description Default
message LexMessages

The Lex message to format

required

Returns:

Type Description
LexBaseResponse

The formatted message string

Source code in lex_helper/channels/sms.py
def format_message(self, message: LexMessages) -> LexBaseResponse:
    """Format a single message for SMS.

    Args:
        message: The Lex message to format

    Returns:
        The formatted message string
    """
    if isinstance(message, LexPlainText):
        return self.format_plain_text(message)
    if isinstance(message, LexImageResponseCard):
        return self.format_image_card(message)
    if isinstance(message, LexCustomPayload):
        return self.format_custom_payload(message)
    return LexPlainText(content="Unsupported message type")
format_messages
format_messages(messages: list[LexMessages]) -> list[LexBaseResponse]

Format a list of messages for SMS.

Parameters:

Name Type Description Default
messages list[LexMessages]

List of Lex messages to format

required

Returns:

Type Description
list[LexBaseResponse]

List of formatted message strings

Source code in lex_helper/channels/sms.py
def format_messages(self, messages: list[LexMessages]) -> list[LexBaseResponse]:
    """Format a list of messages for SMS.

    Args:
        messages: List of Lex messages to format

    Returns:
        List of formatted message strings
    """
    return [self.format_message(message) for message in messages]
format_plain_text
format_plain_text(message: LexPlainText) -> LexBaseResponse

Format a plain text message for SMS.

Parameters:

Name Type Description Default
message LexPlainText

The plain text message to format

required

Returns:

Type Description
LexBaseResponse

The formatted plain text

Source code in lex_helper/channels/sms.py
def format_plain_text(self, message: LexPlainText) -> LexBaseResponse:
    """Format a plain text message for SMS.

    Args:
        message: The plain text message to format

    Returns:
        The formatted plain text
    """
    # For SMS, we want to ensure URLs are properly formatted
    text = message.content
    if text is None:
        return LexPlainText(content="")
    words = text.split()
    formatted_words = []

    for word in words:
        # Check if word might be a URL
        if "." in word and "/" in word:
            try:
                result = urlparse(word)
                if not result.scheme:
                    # Add https:// if no scheme
                    word = "https://" + word
            except:
                pass
        formatted_words.append(word)

    return LexPlainText(content=" ".join(formatted_words))
format_image_card
format_image_card(card: LexImageResponseCard) -> LexBaseResponse

Format an image response card for SMS.

Parameters:

Name Type Description Default
card LexImageResponseCard

The image card to format

required

Returns:

Type Description
LexBaseResponse

The formatted card text

Source code in lex_helper/channels/sms.py
def format_image_card(self, card: LexImageResponseCard) -> LexBaseResponse:
    """Format an image response card for SMS.

    Args:
        card: The image card to format

    Returns:
        The formatted card text
    """
    # For SMS, we want a more compact format
    parts = []
    if card.imageResponseCard.title:
        parts.append(card.imageResponseCard.title)
    if card.imageResponseCard.subtitle:
        parts.append(card.imageResponseCard.subtitle)
    if card.imageResponseCard.imageUrl:
        parts.append(card.imageResponseCard.imageUrl)  # Include raw URL for SMS
    if card.imageResponseCard.buttons:
        # For SMS, we only include the button text, not values
        button_texts = [btn.text for btn in card.imageResponseCard.buttons]
        parts.append("Options: " + ", ".join(button_texts))

    return LexPlainText(content=" | ".join(parts))
format_custom_payload
format_custom_payload(payload: LexCustomPayload) -> LexBaseResponse

Format a custom payload message for SMS.

Parameters:

Name Type Description Default
payload LexCustomPayload

The custom payload to format

required

Returns:

Type Description
LexBaseResponse

The formatted payload text

Source code in lex_helper/channels/sms.py
def format_custom_payload(self, payload: LexCustomPayload) -> LexBaseResponse:
    """Format a custom payload message for SMS.

    Args:
        payload: The custom payload to format

    Returns:
        The formatted payload text
    """
    content = payload.content
    # Ensure content is treated as a dictionary
    if isinstance(content, dict):
        if "text" in content:
            return LexCustomPayload(content=str(content.get("text")))
        if "message" in content:
            return LexCustomPayload(content=str(content.get("message")))
        # For SMS, we don't want to dump the entire dict
        return LexCustomPayload(content="Message received")
    return LexCustomPayload(content=str(content))

Usage Examples

Basic Channel Formatting

from lex_helper.channels.channel_formatting import format_for_channel
from lex_helper.core.types import LexResponse

# Create a response
response = LexResponse(...)

# Format for SMS (will strip rich formatting)
sms_response = format_for_channel(response, "sms")

# Format for web (preserves rich formatting)
web_response = format_for_channel(response, "lex")

Channel-Specific Responses

from lex_helper.channels.sms import SmsChannel
from lex_helper.channels.lex import LexChannel

# SMS channel automatically handles text length limits
sms_channel = SmsChannel()
formatted_sms = sms_channel.format_response(response)

# Lex channel supports rich formatting
lex_channel = LexChannel()
formatted_lex = lex_channel.format_response(response)

Channel Detection

The library automatically detects the channel from the Lex request and applies appropriate formatting. You can also explicitly specify the channel when needed.


Next: Explore the Formatters API for message formatting utilities.