Formatting API

Formatting variants, text nodes, tables, attachments, embeds, interactive components, builders, parsing, and conversion.

Format variant definitions for chatom.

This module defines the different output formats supported by chatom.

class chatom.format.variant.Format(value)[source]

Bases: str, Enum

Supported output formats.

PLAINTEXT = 'plaintext'

Plain text with no formatting.

MARKDOWN = 'markdown'

Standard CommonMark Markdown.

SLACK_MARKDOWN = 'slack-markdown'

Slack’s mrkdwn format (differs from standard Markdown).

DISCORD_MARKDOWN = 'discord-markdown'

Discord’s flavor of Markdown.

HTML = 'html'

Standard HTML.

TELEGRAM_HTML = 'telegram-html'

Telegram Bot API HTML subset.

SYMPHONY_MESSAGEML = 'symphony-messageml'

Symphony’s MessageML format (XML-based).

Text formatting nodes for chatom.

This module provides a composable system for building formatted text that can be rendered to different output formats (Markdown, HTML, etc.).

pydantic model chatom.format.text.Bold[source]

Bases: TextNode

Bold formatted text.

child

The content to make bold.

field child: TextNode [Required]

The content to make bold.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.ChannelMention[source]

Bases: TextNode

Channel mention.

channel_id

Platform-specific channel ID.

display_name

Fallback display name.

field channel_id: str [Required]

Platform-specific channel ID.

field display_name: str = ''

Fallback display name.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Code[source]

Bases: TextNode

Inline code.

content

The code content.

field content: str [Required]

The code content.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.CodeBlock[source]

Bases: TextNode

Code block with optional language specification.

content

The code content.

language

The programming language for syntax highlighting.

field content: str [Required]

The code content.

field language: str = ''

Programming language for syntax highlighting.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Document[source]

Bases: TextNode

Top-level document containing multiple nodes.

children

The document content nodes.

field children: list[TextNode] [Optional]

Document content nodes.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

append(node: TextNode) Document[source]

Append a node to the document.

Parameters:

node – The node to append.

Returns:

Self for method chaining.

pydantic model chatom.format.text.Emoji[source]

Bases: TextNode

Emoji.

name

Emoji name (without colons).

unicode

Unicode representation if standard emoji.

custom_id

Platform-specific ID for custom emoji.

field name: str [Required]

Emoji name (without colons).

field unicode: str = ''

Unicode representation.

field custom_id: str = ''

Platform-specific custom emoji ID.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Heading[source]

Bases: TextNode

Heading.

child

The heading content.

level

Heading level (1-6).

field child: TextNode [Required]

The heading content.

field level: int = 1

Heading level (1-6).

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.HorizontalRule[source]

Bases: TextNode

Horizontal rule/divider.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Italic[source]

Bases: TextNode

Italic formatted text.

child

The content to italicize.

field child: TextNode [Required]

The content to italicize.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.LineBreak[source]

Bases: TextNode

Line break.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

Bases: TextNode

Hyperlink.

text

The link text.

url

The URL to link to.

title

Optional title attribute.

field text: str [Required]

The link text.

field url: str [Required]

The URL to link to.

field title: str = ''

Optional title attribute.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.ListItem[source]

Bases: TextNode

List item.

child

The item content.

field child: TextNode [Required]

The item content.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.OrderedList[source]

Bases: TextNode

Ordered (numbered) list.

items

List items.

start

Starting number.

field items: list[ListItem] [Optional]

List items.

field start: int = 1

Starting number.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Paragraph[source]

Bases: TextNode

Paragraph of text.

children

The content nodes within the paragraph.

field children: list[TextNode] [Optional]

Content nodes within the paragraph.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Quote[source]

Bases: TextNode

Block quote.

child

The quoted content.

field child: TextNode [Required]

The quoted content.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Raw[source]

Bases: TextNode

Raw content that is not escaped.

Use this for inserting platform-specific markup that should not be escaped, such as Symphony hashtags, cashtags, or mentions.

content

The raw content (will be inserted as-is).

field content: str = ''

The raw content (not escaped).

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render raw content without any escaping.

pydantic model chatom.format.text.Span[source]

Bases: TextNode

Container for multiple text nodes.

children

The child nodes.

field children: list[TextNode] [Optional]

Child nodes.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Strikethrough[source]

Bases: TextNode

Strikethrough formatted text.

child

The content to strike through.

field child: TextNode [Required]

The content to strike through.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Text[source]

Bases: TextNode

Plain text content.

content

The text content.

field content: str = ''

The text content.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render plain text, escaping special characters as needed.

pydantic model chatom.format.text.TextNode[source]

Bases: BaseModel, ABC

Base class for all text formatting nodes.

TextNodes represent semantic text content that can be rendered to different output formats. They form a tree structure allowing complex nested formatting.

abstractmethod render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.Underline[source]

Bases: TextNode

Underlined text.

Note: Not all formats support underline.

child

The content to underline.

field child: TextNode [Required]

The content to underline.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.UnorderedList[source]

Bases: TextNode

Unordered (bulleted) list.

items

List items.

field items: list[ListItem] [Optional]

List items.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

pydantic model chatom.format.text.UserMention[source]

Bases: TextNode

User mention.

user_id

Platform-specific user ID.

display_name

Fallback display name.

field user_id: str [Required]

Platform-specific user ID.

field display_name: str = ''

Fallback display name.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render this node to the specified format.

Parameters:

format – The output format to render to.

Returns:

The rendered string.

Return type:

str

Table formatting for chatom.

This module provides table representation that can be rendered to different output formats.

pydantic model chatom.format.table.Table[source]

Bases: BaseModel

A table that can be rendered to different formats.

Supports Markdown, HTML, Symphony MessageML, and plaintext output.

headers

Optional header row.

rows

Data rows.

caption

Optional table caption.

alignments

Column alignments.

field headers: TableRow | None = None

Header row.

field rows: list[TableRow] [Optional]

Data rows.

field caption: str = ''

Table caption.

field alignments: list[str] [Optional]

Column alignments.

classmethod from_data(data: list[list[Any]], headers: list[str] | None = None, caption: str = '', alignments: list[str] | None = None) Table[source]

Create a table from a 2D list of data.

Parameters:
  • data – 2D list of cell values.

  • headers – Optional list of header values.

  • caption – Optional table caption.

  • alignments – Optional list of column alignments.

Returns:

The created table.

Return type:

Table

classmethod from_dict_list(data: list[dict], columns: list[str] | None = None, caption: str = '') Table[source]

Create a table from a list of dictionaries.

Parameters:
  • data – List of dictionaries, each representing a row.

  • columns – Optional list of column keys to include. Defaults to all keys.

  • caption – Optional table caption.

Returns:

The created table.

Return type:

Table

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render the table to the specified format.

Parameters:

format – The output format.

Returns:

The rendered table.

Return type:

str

class chatom.format.table.TableAlignment[source]

Bases: object

Table column alignment constants.

pydantic model chatom.format.table.TableCell[source]

Bases: BaseModel

A single cell in a table.

content

The cell content.

is_header

Whether this is a header cell.

colspan

Number of columns this cell spans.

rowspan

Number of rows this cell spans.

alignment

Text alignment within the cell.

field content: str = ''

The cell content.

field is_header: bool = False

Whether this is a header cell.

field colspan: int = 1

Number of columns to span.

field rowspan: int = 1

Number of rows to span.

field alignment: str = 'left'

Text alignment.

pydantic model chatom.format.table.TableRow[source]

Bases: BaseModel

A row in a table.

cells

The cells in this row.

is_header

Whether this is a header row.

field cells: list[TableCell] [Optional]

Cells in the row.

field is_header: bool = False

Whether this is a header row.

classmethod from_values(values: list[str], is_header: bool = False) TableRow[source]

Create a row from a list of string values.

Parameters:
  • values – Cell values as strings.

  • is_header – Whether this is a header row.

Returns:

The created row.

Return type:

TableRow

Attachment formatting for chatom.

This module provides attachment and media rendering for different formats. Attachments can reference files by URL or hold in-memory binary data for direct upload to backend APIs.

pydantic model chatom.format.attachment.FormattedAttachment[source]

Bases: BaseModel

An attachment that can be rendered to different formats.

Attachments can reference a URL or hold raw bytes for upload. When data is set, the publish path will use the backend’s file upload API instead of rendering a URL link.

filename

Name of the file.

url

URL to the attachment.

data

Raw file bytes for direct upload.

size

File size in bytes.

content_type

MIME type.

field filename: str = ''

Name of the file.

field url: str = ''

URL to the attachment.

field data: bytes | None = None

Raw file bytes for direct upload.

field size: int | None = None

File size in bytes.

field content_type: str = ''

MIME type.

property has_data: bool

Whether this attachment carries in-memory binary data.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render the attachment to the specified format.

Parameters:

format – The output format.

Returns:

The rendered attachment.

Return type:

str

pydantic model chatom.format.attachment.FormattedImage[source]

Bases: BaseModel

An image that can be rendered to different formats.

Images can reference a URL or hold raw bytes for upload. When data is set, the publish path will use the backend’s image/file upload API instead of rendering a URL.

url

URL to the image.

data

Raw image bytes for direct upload.

alt_text

Alternative text for accessibility.

title

Image title.

filename

Filename for the upload (derived from url if empty).

content_type

MIME type (e.g. image/png).

width

Width in pixels.

height

Height in pixels.

field url: str = ''

URL to the image.

field data: bytes | None = None

Raw image bytes for direct upload.

field alt_text: str = ''

Alternative text.

field title: str = ''

Image title.

field filename: str = ''

Filename for the upload.

field content_type: str = ''

MIME type (e.g. image/png).

field width: int | None = None

Width in pixels.

field height: int | None = None

Height in pixels.

property has_data: bool

Whether this image carries in-memory binary data.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render the image to the specified format.

Parameters:

format – The output format.

Returns:

The rendered image.

Return type:

str

Embed formatting for chatom.

This module provides the FormattedEmbed class — a content node that wraps the base Embed model and can be placed inside a FormattedMessage content tree. It renders a text fallback for all formats and exposes per-backend structured payloads via to_discord_dict(), to_slack_attachment(), and to_symphony_messageml().

pydantic model chatom.format.embed.FormattedEmbed[source]

Bases: BaseModel

A renderable embed content node for FormattedMessage.

Wraps the base Embed model so that embeds can appear alongside Text, Table, and FormattedImage nodes in a message’s content list.

render() produces a reasonable text fallback (bold title, field list) for backends that don’t support native embeds. For backends that do, callers should use the structured-payload methods instead:

  • to_discord_dict() — Discord embed object

  • to_slack_attachment() — Slack Block Kit attachment

  • to_symphony_messageml() — Symphony <card> MessageML

embed

The underlying Embed data model.

field embed: Embed [Optional]

The underlying embed data.

classmethod from_embed(embed: Embed) FormattedEmbed[source]

Create a FormattedEmbed from an existing Embed instance.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render the embed as a text fallback.

This is used when the embed appears in the content list and needs to be converted to a flat string. Backends that support native embeds should use the structured-payload methods instead.

to_discord_dict() dict[str, Any][source]

Convert to a Discord embed dict suitable for the API.

to_slack_attachment() dict[str, Any][source]

Convert to a Slack Block Kit attachment dict.

to_symphony_messageml() str[source]

Convert to Symphony MessageML <card> markup.

to_telegram_html() str[source]

Convert to Telegram-compatible HTML.

Interactive components for chatom.

This module provides interactive UI components like buttons, select menus, and forms that can be rendered to platform-specific formats.

Supported platforms: - Slack: Block Kit (buttons, select menus, modals) - Discord: Components (buttons, select menus) - Symphony: Symphony Elements (buttons, forms)

pydantic model chatom.format.components.ActionRow[source]

Bases: BaseModel

A row of interactive components.

Components are laid out horizontally. Most platforms limit the number of components per row (e.g., Discord allows 5 buttons).

components

List of components in this row.

field components: list[Button | SelectMenu] [Optional]

Components in this row.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) dict[str, Any][source]

Render the action row to platform-specific format.

add_button(label: str, action_id: str = '', style: ButtonStyle = ButtonStyle.PRIMARY, url: str | None = None, value: str | None = None) ActionRow[source]

Add a button to the row.

Parameters:
  • label – Button text.

  • action_id – Callback action identifier.

  • style – Button style.

  • url – URL for link buttons.

  • value – Value sent with callback.

Returns:

Self for chaining.

add_select(action_id: str, options: list[SelectOption], placeholder: str = 'Select an option') ActionRow[source]

Add a select menu to the row.

Parameters:
  • action_id – Callback action identifier.

  • options – List of options.

  • placeholder – Placeholder text.

Returns:

Self for chaining.

pydantic model chatom.format.components.Button[source]

Bases: BaseModel

An interactive button component.

Buttons can trigger actions or open URLs. They have a label, style, and either an action_id (for callbacks) or url (for links).

label

The button text.

action_id

Unique identifier for this button action (for callbacks).

style

Visual style of the button.

url

URL to open (for link buttons).

disabled

Whether the button is disabled.

emoji

Optional emoji to display with the label.

value

Optional value sent with the callback.

field label: str [Required]

Button text label.

field action_id: str = ''

Unique identifier for button action (used in callbacks).

field style: ButtonStyle = ButtonStyle.PRIMARY

Visual style of the button.

field url: str | None = None

URL to open (for link buttons).

field disabled: bool = False

Whether the button is disabled.

field emoji: str | None = None

Emoji to display with the label.

field value: str | None = None

Value sent with the callback.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) dict[str, Any][source]

Render the button to platform-specific format.

Parameters:

format – The output format.

Returns:

Dict representation for the platform’s API.

class chatom.format.components.ButtonStyle(value)[source]

Bases: str, Enum

Button visual styles.

PRIMARY = 'primary'

Primary action button (usually colored).

SECONDARY = 'secondary'

Secondary action button (neutral).

SUCCESS = 'success'

Success/positive action (green).

DANGER = 'danger'

Destructive/negative action (red).

Link button (opens URL).

pydantic model chatom.format.components.ComponentContainer[source]

Bases: BaseModel

Container for interactive components attached to a message.

This wraps action rows and can be attached to a FormattedMessage.

rows

List of action rows.

field rows: list[ActionRow] [Optional]

Action rows containing components.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) list[dict[str, Any]][source]

Render all rows to platform-specific format.

add_row() ActionRow[source]

Add a new action row and return it.

Returns:

The new action row for adding components.

add_button(label: str, action_id: str = '', style: ButtonStyle = ButtonStyle.PRIMARY, url: str | None = None) ComponentContainer[source]

Add a button to the last row (creates row if needed).

Parameters:
  • label – Button text.

  • action_id – Callback action identifier.

  • style – Button style.

  • url – URL for link buttons.

Returns:

Self for chaining.

add_select(action_id: str, options: list[SelectOption], placeholder: str = 'Select an option') ComponentContainer[source]

Add a select menu (creates new row for it).

Parameters:
  • action_id – Callback action identifier.

  • options – List of options.

  • placeholder – Placeholder text.

Returns:

Self for chaining.

pydantic model chatom.format.components.Modal[source]

Bases: BaseModel

A modal dialog with form inputs.

Modals are opened in response to interactions and contain form elements for user input.

callback_id

Unique identifier for form submission.

title

Modal title.

submit_label

Submit button text.

close_label

Close/cancel button text.

inputs

List of input elements.

field callback_id: str [Required]

Unique identifier for form submission.

field title: str [Required]

Modal title.

field submit_label: str = 'Submit'

Submit button text.

field close_label: str = 'Cancel'

Close button text.

field inputs: list[TextInput] [Optional]

Form input elements.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) dict[str, Any][source]

Render the modal to platform-specific format.

add_text_input(action_id: str, label: str, placeholder: str = '', style: TextInputStyle = TextInputStyle.SHORT, required: bool = True) Modal[source]

Add a text input to the modal.

Parameters:
  • action_id – Unique identifier.

  • label – Input label.

  • placeholder – Placeholder text.

  • style – Short or paragraph.

  • required – Whether required.

Returns:

Self for chaining.

pydantic model chatom.format.components.SelectMenu[source]

Bases: BaseModel

A dropdown select menu component.

action_id

Unique identifier for this select action.

placeholder

Placeholder text when no option is selected.

options

List of selectable options.

min_values

Minimum number of selections required.

max_values

Maximum number of selections allowed.

disabled

Whether the select is disabled.

field action_id: str [Required]

Unique identifier for select action.

field placeholder: str = 'Select an option'

Placeholder text.

field options: list[SelectOption] [Optional]

Selectable options.

field min_values: int = 1

Minimum selections required.

field max_values: int = 1

Maximum selections allowed.

field disabled: bool = False

Whether the select is disabled.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) dict[str, Any][source]

Render the select menu to platform-specific format.

pydantic model chatom.format.components.SelectOption[source]

Bases: BaseModel

An option in a select menu.

label

Display text for the option.

value

Value sent when option is selected.

description

Optional description text.

emoji

Optional emoji to display.

default

Whether this is the default selection.

field label: str [Required]

Display text for the option.

field value: str [Required]

Value sent when option is selected.

field description: str | None = None

Optional description text.

field emoji: str | None = None

Optional emoji to display.

field default: bool = False

Whether this is the default selection.

pydantic model chatom.format.components.TextInput[source]

Bases: BaseModel

A text input field for modals/forms.

action_id

Unique identifier for this input.

label

Label displayed above the input.

placeholder

Placeholder text.

style

Input style (short or paragraph).

min_length

Minimum input length.

max_length

Maximum input length.

required

Whether input is required.

default_value

Default value.

field action_id: str [Required]

Unique identifier for this input.

field label: str [Required]

Label displayed above the input.

field placeholder: str = ''

Placeholder text.

field style: TextInputStyle = TextInputStyle.SHORT

Input style.

field min_length: int | None = None

Minimum input length.

field max_length: int | None = None

Maximum input length.

field required: bool = True

Whether input is required.

field default_value: str = ''

Default value.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) dict[str, Any][source]

Render the text input to platform-specific format.

class chatom.format.components.TextInputStyle(value)[source]

Bases: str, Enum

Text input styles for modals.

SHORT = 'short'

Single-line input.

PARAGRAPH = 'paragraph'

Multi-line input.

chatom.format.components.attach_components_for_backend(kwargs: dict[str, Any], container: ComponentContainer, backend_format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str) dict[str, Any][source]

Populate send_message keyword args for interactive components.

Writes the correct kwarg for the target backend format into kwargs in-place, rendering container exactly once. Returns kwargs for chaining.

  • SLACK_MARKDOWN -> blocks (Block Kit action blocks)

  • DISCORD_MARKDOWN -> components (Discord component objects)

  • SYMPHONY_MESSAGEML -> merged into content inline

  • anything else -> components as a generic fallback

Message formatting and conversion utilities.

This module provides utilities for building and converting messages between different chat platform formats.

pydantic model chatom.format.message.FormattedMessage[source]

Bases: BaseModel

A message with formatted content that can be rendered to different formats.

This is the main class for building rich messages that can be converted to platform-specific formats.

content

List of content nodes (text, tables, images, etc.).

attachments

File attachments.

metadata

Additional platform-specific metadata.

field content: list[TextNode | Table | FormattedImage | FormattedAttachment | FormattedEmbed] [Optional]

Content nodes.

field attachments: list[FormattedAttachment] [Optional]

File attachments.

field embeds: list[FormattedEmbed] [Optional]

Rich embeds (rendered natively on supported backends).

field components: ComponentContainer | None = None

Interactive components (buttons, menus, etc.).

field metadata: dict[str, Any] [Optional]

Platform-specific metadata.

render(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render the message to the specified format.

Parameters:

format – The output format.

Returns:

The rendered message.

Return type:

str

render_for(backend: str) str[source]

Render the message for a specific backend.

Uses the backend’s preferred format automatically.

Parameters:

backend – The backend identifier (e.g., ‘slack’, ‘discord’).

Returns:

The rendered message in the backend’s format.

Return type:

str

Example

>>> msg = FormattedMessage().add_bold("Hello")
>>> msg.render_for("slack")
'*Hello*'
>>> msg.render_for("discord")
'**Hello**'
append(item: TextNode | Table | FormattedImage | FormattedAttachment | str) FormattedMessage[source]

Append content to the message.

Parameters:

item – The content to append.

Returns:

Self for method chaining.

add_text(text: str) FormattedMessage[source]

Add plain text.

add_bold(text: str) FormattedMessage[source]

Add bold text.

add_italic(text: str) FormattedMessage[source]

Add italic text.

add_code(code: str) FormattedMessage[source]

Add inline code.

add_code_block(code: str, language: str = '') FormattedMessage[source]

Add a code block.

Add a hyperlink.

add_line_break() FormattedMessage[source]

Add a line break.

add_table(table: Table) FormattedMessage[source]

Add a table.

add_image(url: str, alt_text: str = '', title: str = '') FormattedMessage[source]

Add an image.

add_mention(user_id: str, display_name: str = '') FormattedMessage[source]

Add a user mention.

Parameters:
  • user_id – Platform-specific user ID.

  • display_name – Fallback display name (used for plain text rendering).

Returns:

Self for method chaining.

mention(user: User) FormattedMessage[source]

Add a user mention from a User object.

This is a convenience method that extracts the user’s ID and display name automatically. The mention will render correctly for each backend format.

Parameters:

user – The User object to mention.

Returns:

Self for method chaining.

Example

>>> from chatom import User
>>> user = User(id="U123", name="Alice")
>>> msg = FormattedMessage().mention(user).add_text(" check this!")
>>> msg.render_for("slack")   # '<@U123> check this!'
>>> msg.render_for("discord") # '<@U123> check this!'
channel_mention(channel: Channel) FormattedMessage[source]

Add a channel mention from a Channel object.

This is a convenience method that extracts the channel’s ID and name automatically. The mention will render correctly for each backend format.

Parameters:

channel – The Channel object to mention.

Returns:

Self for method chaining.

Example

>>> from chatom import Channel
>>> channel = Channel(id="C123", name="general")
>>> msg = FormattedMessage().add_text("Join ").channel_mention(channel)
>>> msg.render_for("slack")   # 'Join <#C123>'
>>> msg.render_for("discord") # 'Join <#C123>'
add_raw(content: str) FormattedMessage[source]

Add raw content that will not be escaped.

Use this for platform-specific markup that should be inserted as-is, such as Symphony hashtags (<hash tag=”…”/>), cashtags (<cash tag=”…”/>), or mentions (<mention uid=”…”/>).

Parameters:

content – The raw content to insert (will not be escaped).

Returns:

Self for method chaining.

Example

>>> msg = FormattedMessage()
>>> msg.add_text("Check out ").add_raw('<hash tag="chatom"/>').add_text("!")
add_button(label: str, action_id: str = '', style: ButtonStyle = ButtonStyle.PRIMARY, url: str | None = None, value: str | None = None) FormattedMessage[source]

Add an interactive button to the message.

Creates a component container if needed and adds a button.

Parameters:
  • label – Button text.

  • action_id – Unique identifier for button callback.

  • style – Visual style (PRIMARY, SECONDARY, SUCCESS, DANGER, LINK).

  • url – URL to open (for LINK style buttons).

  • value – Value sent with callback.

Returns:

Self for method chaining.

Example

>>> msg = FormattedMessage()
>>> msg.add_text("Click here: ").add_button("Submit", action_id="submit_form")
add_select(action_id: str, options: list[SelectOption], placeholder: str = 'Select an option') FormattedMessage[source]

Add a select menu to the message.

Parameters:
  • action_id – Unique identifier for select callback.

  • options – List of SelectOption objects.

  • placeholder – Placeholder text.

Returns:

Self for method chaining.

Example

>>> options = [
...     SelectOption(label="Option A", value="a"),
...     SelectOption(label="Option B", value="b"),
... ]
>>> msg = FormattedMessage()
>>> msg.add_text("Choose:").add_select("my_select", options)
add_action_row() ActionRow[source]

Add a new action row for components.

Returns the ActionRow for direct component addition.

Returns:

The new ActionRow.

Example

>>> msg = FormattedMessage()
>>> row = msg.add_action_row()
>>> row.add_button("Yes", "yes").add_button("No", "no")
add_embed(embed: Embed | None = None, *, title: str = '', description: str = '', color: int | None = None, url: str = '', inline: bool = False) FormattedMessage[source]

Add a rich embed to the message.

You can pass an existing Embed instance, or provide keyword arguments to create one.

Parameters:
  • embed – An existing Embed to wrap.

  • title – Embed title (used when embed is None).

  • description – Embed description.

  • color – Sidebar colour as a hex integer.

  • url – URL the title links to.

  • inline – If True the embed is also appended to content so it appears inline in the text fallback.

Returns:

Self for method chaining.

get_embeds(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) list[dict[str, Any]][source]

Get structured embed payloads for the specified format.

Returns a list of dicts suitable for passing to the backend API. For formats/backends that do not support structured embeds the list is empty — use render() for the text fallback.

Parameters:

format – The target output format.

Returns:

List of backend-specific embed dicts.

get_embeds_for(backend: str) list[dict[str, Any]][source]

Get structured embed payloads for a specific backend.

Parameters:

backend – Backend identifier (e.g. ‘discord’, ‘slack’).

Returns:

List of backend-specific embed dicts.

get_components(format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) list[dict[str, Any]][source]

Get rendered components for the specified format.

Parameters:

format – The output format.

Returns:

List of component dicts for the platform API.

class chatom.format.message.MessageBuilder[source]

Bases: object

Builder for constructing formatted messages fluently.

Example

>>> msg = (
...     MessageBuilder()
...     .text("Hello, ")
...     .bold("world")
...     .text("!")
...     .build()
... )
>>> msg.render(Format.MARKDOWN)
'Hello, **world**!'
text(content: str) MessageBuilder[source]

Add plain text.

bold(content: str) MessageBuilder[source]

Add bold text.

italic(content: str) MessageBuilder[source]

Add italic text.

strikethrough(content: str) MessageBuilder[source]

Add strikethrough text.

code(content: str) MessageBuilder[source]

Add inline code.

code_block(content: str, language: str = '') MessageBuilder[source]

Add a code block.

Add a link.

quote(content: str) MessageBuilder[source]

Add a block quote.

heading(content: str, level: int = 1) MessageBuilder[source]

Add a heading.

line_break() MessageBuilder[source]

Add a line break.

paragraph(content: str) MessageBuilder[source]

Add a paragraph.

bullet_list(items: list[str]) MessageBuilder[source]

Add a bullet list.

numbered_list(items: list[str], start: int = 1) MessageBuilder[source]

Add a numbered list.

table(data: list[list[Any]], headers: list[str] | None = None, caption: str = '') MessageBuilder[source]

Add a table from data.

table_from_dicts(data: list[dict], columns: list[str] | None = None, caption: str = '') MessageBuilder[source]

Add a table from a list of dictionaries.

image(url: str, alt_text: str = '', title: str = '') MessageBuilder[source]

Add an image.

attachment(filename: str, url: str, content_type: str = '') MessageBuilder[source]

Add an attachment.

node(node: TextNode) MessageBuilder[source]

Add a custom text node.

embed(embed: Embed) MessageBuilder[source]

Add a rich embed.

metadata(key: str, value: Any) MessageBuilder[source]

Add metadata.

build() FormattedMessage[source]

Build the formatted message.

Returns:

The constructed message.

Return type:

FormattedMessage

chatom.format.message.format_message(content: str, format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.PLAINTEXT, *, escape_html: bool = True, escape_symphony: bool = True) str[source]

Format a plain text message for a specific platform.

This is a simple utility for converting plain text to a format-safe string. For rich formatting, use MessageBuilder instead.

Parameters:
  • content – The plain text content.

  • format – The target format.

  • escape_html – Whether to escape HTML characters.

  • escape_symphony – Whether to apply Symphony-specific escaping.

Returns:

The formatted message.

Return type:

str

chatom.format.message.get_format_for_backend(backend: str) Format[source]

Get the preferred format for a backend.

This function first checks the BackendRegistry for registered backends, then falls back to the BACKEND_FORMAT_MAP for backwards compatibility.

Parameters:

backend – The backend identifier.

Returns:

The preferred format for that backend.

chatom.format.message.render_message(message: FormattedMessage, format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str = Format.MARKDOWN) str[source]

Render a formatted message to a specific format.

Parameters:
  • message – The message to render.

  • format – The output format.

Returns:

The rendered message content.

Return type:

str

Markdown parser for chatom format system.

Uses mistune (a proper markdown parser) to produce an AST, then converts to chatom TextNode trees for multi-format rendering.

chatom.format.parse.convert_format(text: str, from_format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str, to_format: Literal['plaintext', 'markdown', 'slack-markdown', 'discord-markdown', 'html', 'telegram-html', 'symphony-messageml'] | Format | str) str[source]

Convert text from one format to another.

Currently supports converting FROM markdown to any target format.

Parameters:
  • text – The source text.

  • from_format – The format of the input text.

  • to_format – The desired output format.

Returns:

The converted text.

Return type:

str

Raises:

ValueError – If conversion from the specified format is not supported.

chatom.format.parse.parse_markdown(text: str) Document[source]

Parse a markdown string into a Document of TextNode objects.

Uses mistune to parse the markdown into an AST, then converts to chatom’s TextNode tree for multi-format rendering.

Parameters:

text – Markdown-formatted string.

Returns:

Document containing the parsed TextNode tree.