> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Table & Chart Blocks

> Portable table and chart blocks agents can send once and render natively per channel

Agents describe tabular or chart data once with a TABLE or CHART block, and every channel renders it natively where supported or degrades deterministically to a markdown table or text summary everywhere else.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Table / Chart Flow"
        A[🤖 Agent] -->|describe once| B[📊 TABLE / CHART block]
        B --> C{🔍 Channel supports?}
        C -->|Yes| D[✅ Native render]
        C -->|No| E[📝 Markdown table<br/>/ text summary]
    end

    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef block fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef check fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff

    class A agent
    class B block
    class C check
    class D,E result
```

## Quick Start

**1. Agent returns a table**

An agent returns a `MessagePresentation` with a TABLE block from a tool — pass numbers or ints freely, cells are stringified for you:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonaiagents.bots import MessagePresentation, PresentationBlock

def sales_table():
    return MessagePresentation(blocks=[
        PresentationBlock.make_text("Weekly sales:"),
        PresentationBlock.make_table(
            columns=["Product", "Units", "Revenue"],
            rows=[
                ["Widget",  120,  1440],
                ["Gadget",   85,  2550],
                ["Gizmo",    42,   630],
            ],
        ),
    ])

agent = Agent(
    name="Sales Reporter",
    instructions="Summarise weekly sales as a table.",
    tools=[sales_table],
)
agent.start("Show me this week's sales")
```

**2. Add a chart**

A CHART block carries a `chart_kind` and one or more `series`; each series is a `label` plus a list of numeric `points`:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.bots import PresentationBlock

PresentationBlock.make_chart(
    chart_kind="bar",
    series=[
        {"label": "Revenue", "points": [1440, 2550, 630]},
        {"label": "Target",  "points": [1500, 2000, 1000]},
    ],
    text="Weekly revenue vs target",
)
```

***

## How It Works

A TABLE block clamps to the channel's row and column caps, then either stays a native table or degrades to a markdown table inside a TEXT block. A CHART block stays native where charts are supported, or degrades to a one-line-per-series text summary.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant Agent
    participant Adapter as adapt_presentation
    participant Channel

    Agent->>Adapter: TABLE / CHART block + limits
    Adapter->>Adapter: clamp rows/cols to caps
    alt supports_tables / supports_charts
        Adapter->>Channel: native TABLE / CHART
    else default (False)
        Adapter->>Channel: TEXT block (markdown table / text summary)
    end
```

| Block | Native path | Degrade path |
| - | - | - |
| TABLE | Native table widget (clamped to `max_table_rows` / `max_table_cols`) | Markdown table via `table_to_markdown`, clamped to `max_text_length` |
| CHART | Native chart/visualisation | Text summary via `chart_to_text`, clamped to `max_text_length` |

**Every channel defaults to off** — Slack, Telegram, Discord, and WhatsApp preset `supports_tables=False` / `supports_charts=False`, so behaviour today is a deterministic markdown/text degrade until a channel opts in.

***

## Configuration Options

### `BlockType` — new members

| Member | Value | Use for |
| - | - | - |
| `TABLE` | `"table"` | Tabular data (columns + rows) |
| `CHART` | `"chart"` | Chart/visualisation (kind + series) |

### `PresentationBlock` — new fields

| Field | Type | Default | Used by |
| - | - | - | - |
| `columns` | `Optional[List[str]]` | `None` | TABLE |
| `rows` | `Optional[List[List[str]]]` | `None` | TABLE |
| `chart_kind` | `Optional[str]` | `None` | CHART |
| `series` | `Optional[List[Dict[str, Any]]]` | `None` | CHART |

### Factories

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
PresentationBlock.make_table(
    columns: List[str],
    rows: List[List[str]],
) -> PresentationBlock

PresentationBlock.make_chart(
    chart_kind: str,              # "bar" | "line" | "pie" | "area"
    series: List[Dict[str, Any]], # [{"label": str, "points": list[float]}, ...]
    text: Optional[str] = None,   # optional caption/title
) -> PresentationBlock
```

`make_table` coerces every column and cell to `str`, so agents pass numbers or ints freely. Chart `series` items are dicts with `label` (str) and `points` (list of numbers); any extra keys round-trip through `to_dict()` / `from_dict()`.

### `PresentationLimits` — new capability flags

| Field | Type | Default | Description |
| - | - | - | - |
| `supports_tables` | `bool` | `False` | Channel has a native table widget |
| `supports_charts` | `bool` | `False` | Channel has native chart/visualisation |
| `max_table_rows` | `int` | `50` | Maximum rows in a native TABLE block |
| `max_table_cols` | `int` | `10` | Maximum columns in a native TABLE block |

### Helpers

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.bots import table_to_markdown, chart_to_text

table_to_markdown(columns: List[str], rows: List[List[str]]) -> str
chart_to_text(chart_kind: Optional[str], series: List[Dict[str, Any]], caption: Optional[str] = None) -> str
```

`table_to_markdown` produces GitHub-flavoured markdown with `|` cells escaped and short rows padded to header width. `chart_to_text` renders `"<Caption or Kind chart>\n<label>: p1, p2, p3\n..."` — deterministic, one line per series.

***

## Common Patterns

**Agent returns a table from a tool** — describe the data once and let the channel pick the best rendering:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonaiagents.bots import MessagePresentation, PresentationBlock

def sales_table():
    return MessagePresentation(blocks=[
        PresentationBlock.make_table(
            columns=["Product", "Units", "Revenue"],
            rows=[["Widget", 120, 1440], ["Gadget", 85, 2550]],
        ),
    ])

agent = Agent(name="Sales Reporter", instructions="Report sales.", tools=[sales_table])
agent.start("This week's sales")
```

**Chart with caption** — the caption becomes the title on native renders and the first line of the text summary elsewhere:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.bots import PresentationBlock

PresentationBlock.make_chart(
    "line",
    series=[{"label": "p95", "points": [120, 118, 130, 125]}],
    text="Latency last 24h",
)
```

**Opt a custom channel into native tables** — return an updated `PresentationLimits` from your channel's capability method:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.bots import PresentationLimits

def get_limits() -> PresentationLimits:
    return PresentationLimits(
        supports_tables=True,
        max_table_rows=200,
        max_table_cols=12,
    )
```

***

## Best Practices

> [accordion] Keep tables small
>
> Native widgets typically cap rows well below 50 — set `max_table_rows` on your channel to reflect the true limit so `adapt_presentation` clamps before rendering.

> [accordion] Describe data once
>
> Do not pre-format a markdown table in a TEXT block. Send TABLE / CHART blocks and let each channel pick the best rendering.

> [accordion] Charts degrade to summaries, not silence
>
> Any chart is always readable as text via `chart_to_text`, so you never lose data on plain-text channels.

> [accordion] Cells are stringified
>
> Numbers and booleans are coerced to `str`. For a specific format (currency, %), format the value in your tool before passing it in.

***

## Related

> [card] [Message Presentation](https://praison.ai/docs/features/message-presentation.md)
>
> Attach buttons, menus, and blocks to agent replies

> [card] [Channel Capabilities](https://praison.ai/docs/features/channel-capabilities.md)
>
> What each channel can render natively


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.