Skip to content

Renderers

Format-specific renderer implementations for message analytics display.

Quick Example

from mamba_agents.agent.display import RichRenderer, PlainTextRenderer, HtmlRenderer
from mamba_agents.agent.display import DETAILED

renderer = RichRenderer()
output = renderer.render_stats(stats, DETAILED)

# Plain text for logs
plain = PlainTextRenderer()
output = plain.render_stats(stats, DETAILED)

# HTML for Jupyter notebooks
html = HtmlRenderer()
output = html.render_stats(stats, DETAILED)

Renderer Comparison

Renderer Output Use Case
RichRenderer Rich Console tables and panels Terminal display
PlainTextRenderer ASCII text with aligned columns Log files, CI output
HtmlRenderer Semantic HTML tables and sections Jupyter notebooks

API Reference

MessageRenderer (ABC)

MessageRenderer

Bases: ABC

Abstract base class for message display renderers.

Implementations produce formatted string output for three data types: message statistics, conversation timeline, and tool call summaries. Each method receives the data and a DisplayPreset that controls how much detail to include.

Concrete implementations include RichRenderer, PlainTextRenderer, and HtmlRenderer.

render_stats abstractmethod

render_stats(
    stats: MessageStats, preset: DisplayPreset
) -> str

Render message statistics as a formatted string.

PARAMETER DESCRIPTION
stats

Token and message count statistics to render.

TYPE: MessageStats

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

RETURNS DESCRIPTION
str

Formatted string representation of the statistics.

Source code in src/mamba_agents/agent/display/renderer.py
@abstractmethod
def render_stats(self, stats: MessageStats, preset: DisplayPreset) -> str:
    """Render message statistics as a formatted string.

    Args:
        stats: Token and message count statistics to render.
        preset: Display configuration controlling detail level.

    Returns:
        Formatted string representation of the statistics.
    """
    ...

render_timeline abstractmethod

render_timeline(
    turns: list[Turn], preset: DisplayPreset
) -> str

Render a conversation timeline as a formatted string.

PARAMETER DESCRIPTION
turns

List of conversation turns to render.

TYPE: list[Turn]

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

RETURNS DESCRIPTION
str

Formatted string representation of the timeline.

Source code in src/mamba_agents/agent/display/renderer.py
@abstractmethod
def render_timeline(self, turns: list[Turn], preset: DisplayPreset) -> str:
    """Render a conversation timeline as a formatted string.

    Args:
        turns: List of conversation turns to render.
        preset: Display configuration controlling detail level.

    Returns:
        Formatted string representation of the timeline.
    """
    ...

render_tools abstractmethod

render_tools(
    tools: list[ToolCallInfo], preset: DisplayPreset
) -> str

Render a tool usage summary as a formatted string.

PARAMETER DESCRIPTION
tools

List of tool call summaries to render.

TYPE: list[ToolCallInfo]

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

RETURNS DESCRIPTION
str

Formatted string representation of the tool summary.

Source code in src/mamba_agents/agent/display/renderer.py
@abstractmethod
def render_tools(self, tools: list[ToolCallInfo], preset: DisplayPreset) -> str:
    """Render a tool usage summary as a formatted string.

    Args:
        tools: List of tool call summaries to render.
        preset: Display configuration controlling detail level.

    Returns:
        Formatted string representation of the tool summary.
    """
    ...

RichRenderer

RichRenderer

Bases: MessageRenderer

Rich Console renderer for message analytics data.

Produces formatted Rich Console output with tables, panels, and styled text for message statistics, conversation timelines, and tool call summaries. Output detail is controlled by a DisplayPreset.

Each render method accepts an optional console parameter. When provided, the method prints to that console and captures the output. When omitted, a new Console(record=True) is created internally.

Example::

from mamba_agents.agent.display.rich_renderer import RichRenderer
from mamba_agents.agent.display.presets import DETAILED

renderer = RichRenderer()
output = renderer.render_stats(stats, DETAILED)
print(output)  # already printed to console; string also returned

render_stats

render_stats(
    stats: MessageStats,
    preset: DisplayPreset,
    *,
    console: Console | None = None,
) -> str

Render message statistics as a Rich table.

Produces a table with columns for Role, Messages, and Tokens (when preset.show_tokens is True). Includes a totals row and an average tokens-per-message summary line beneath the table.

Token numbers are formatted with thousands separators (e.g., 1,234).

PARAMETER DESCRIPTION
stats

Token and message count statistics to render.

TYPE: MessageStats

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

console

Optional Rich Console instance. When provided, output is printed to this console. When omitted, a new recording console is created.

TYPE: Console | None DEFAULT: None

RETURNS DESCRIPTION
str

The rendered string captured from the console.

Source code in src/mamba_agents/agent/display/rich_renderer.py
def render_stats(
    self,
    stats: MessageStats,
    preset: DisplayPreset,
    *,
    console: Console | None = None,
) -> str:
    """Render message statistics as a Rich table.

    Produces a table with columns for Role, Messages, and Tokens (when
    ``preset.show_tokens`` is True). Includes a totals row and an
    average tokens-per-message summary line beneath the table.

    Token numbers are formatted with thousands separators (e.g.,
    ``1,234``).

    Args:
        stats: Token and message count statistics to render.
        preset: Display configuration controlling detail level.
        console: Optional Rich Console instance. When provided, output
            is printed to this console. When omitted, a new recording
            console is created.

    Returns:
        The rendered string captured from the console.
    """
    console = self._ensure_console(console)

    for renderable in self.render_stats_renderables(stats, preset):
        console.print(renderable)

    return console.export_text()

render_timeline

render_timeline(
    turns: list[Turn],
    preset: DisplayPreset,
    *,
    console: Console | None = None,
) -> str

Render a conversation timeline as Rich panels.

Each turn is rendered as a Rich Panel containing role-labelled content sections. Tool interactions are shown as a nested summary (tool name and call count). Content is truncated according to the preset's max_content_length unless expand is True or max_content_length is None.

PARAMETER DESCRIPTION
turns

List of conversation turns to render.

TYPE: list[Turn]

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

console

Optional Rich Console instance.

TYPE: Console | None DEFAULT: None

RETURNS DESCRIPTION
str

The rendered string captured from the console.

Source code in src/mamba_agents/agent/display/rich_renderer.py
def render_timeline(
    self,
    turns: list[Turn],
    preset: DisplayPreset,
    *,
    console: Console | None = None,
) -> str:
    """Render a conversation timeline as Rich panels.

    Each turn is rendered as a Rich Panel containing role-labelled
    content sections. Tool interactions are shown as a nested summary
    (tool name and call count). Content is truncated according to the
    preset's ``max_content_length`` unless ``expand`` is True or
    ``max_content_length`` is None.

    Args:
        turns: List of conversation turns to render.
        preset: Display configuration controlling detail level.
        console: Optional Rich Console instance.

    Returns:
        The rendered string captured from the console.
    """
    console = self._ensure_console(console)

    # Empty state.
    if not turns:
        panel = Panel("No conversation turns found", title="Timeline", expand=False)
        console.print(panel)
        return console.export_text()

    # Apply limit for pagination.
    display_turns = turns
    if preset.limit is not None:
        display_turns = turns[: preset.limit]

    for turn in display_turns:
        console.print(self.render_turn_renderable(turn, preset))

    # Show pagination indicator when turns were limited.
    if preset.limit is not None and len(turns) > preset.limit:
        remaining = len(turns) - preset.limit
        console.print(
            Text(f"... {remaining} more turn(s) not shown", style="dim italic"),
        )

    return console.export_text()

render_tools

render_tools(
    tools: list[ToolCallInfo],
    preset: DisplayPreset,
    *,
    console: Console | None = None,
) -> str

Render a tool usage summary as a Rich table.

Default (collapsed) view shows tool name and call count only. When preset.show_tool_details is True, expanded rows show arguments and results per call.

PARAMETER DESCRIPTION
tools

List of tool call summaries to render.

TYPE: list[ToolCallInfo]

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

console

Optional Rich Console instance.

TYPE: Console | None DEFAULT: None

RETURNS DESCRIPTION
str

The rendered string captured from the console.

Source code in src/mamba_agents/agent/display/rich_renderer.py
def render_tools(
    self,
    tools: list[ToolCallInfo],
    preset: DisplayPreset,
    *,
    console: Console | None = None,
) -> str:
    """Render a tool usage summary as a Rich table.

    Default (collapsed) view shows tool name and call count only.
    When ``preset.show_tool_details`` is True, expanded rows show
    arguments and results per call.

    Args:
        tools: List of tool call summaries to render.
        preset: Display configuration controlling detail level.
        console: Optional Rich Console instance.

    Returns:
        The rendered string captured from the console.
    """
    console = self._ensure_console(console)

    for renderable in self.render_tools_renderables(tools, preset):
        console.print(renderable)

    return console.export_text()

render_stats_renderables

render_stats_renderables(
    stats: MessageStats, preset: DisplayPreset
) -> list[Table | Panel | Text]

Build Rich renderable objects for message statistics.

Used by MessageStats.__rich_console__ to yield Rich objects directly to the console without creating an intermediate recording console.

PARAMETER DESCRIPTION
stats

Token and message count statistics to render.

TYPE: MessageStats

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

RETURNS DESCRIPTION
list[Table | Panel | Text]

A list of Rich renderable objects (Table, Panel, or Text).

Source code in src/mamba_agents/agent/display/rich_renderer.py
def render_stats_renderables(
    self,
    stats: MessageStats,
    preset: DisplayPreset,
) -> list[Table | Panel | Text]:
    """Build Rich renderable objects for message statistics.

    Used by ``MessageStats.__rich_console__`` to yield Rich objects
    directly to the console without creating an intermediate recording
    console.

    Args:
        stats: Token and message count statistics to render.
        preset: Display configuration controlling detail level.

    Returns:
        A list of Rich renderable objects (Table, Panel, or Text).
    """
    # Empty state.
    if stats.total_messages == 0:
        return [Panel("No messages recorded", title="Message Statistics", expand=False)]

    # Build the table.
    table = Table(title="Message Statistics")
    table.add_column("Role", style="bold cyan")
    table.add_column("Messages", justify="right")

    if preset.show_tokens:
        table.add_column("Tokens", justify="right")

    for role in sorted(stats.messages_by_role):
        msg_count = str(stats.messages_by_role[role])
        if preset.show_tokens:
            token_count = f"{stats.tokens_by_role.get(role, 0):,}"
            table.add_row(role, msg_count, token_count)
        else:
            table.add_row(role, msg_count)

    # Totals row.
    table.add_section()
    if preset.show_tokens:
        table.add_row(
            "Total",
            str(stats.total_messages),
            f"{stats.total_tokens:,}",
            style="bold",
        )
    else:
        table.add_row(
            "Total",
            str(stats.total_messages),
            style="bold",
        )

    renderables: list[Table | Panel | Text] = [table]

    # Average tokens/message summary.
    if preset.show_tokens:
        avg = stats.avg_tokens_per_message
        renderables.append(
            Text(f"Average tokens/message: {avg:,.1f}", style="dim"),
        )

    return renderables

render_tools_renderables

render_tools_renderables(
    tools: list[ToolCallInfo], preset: DisplayPreset
) -> list[Table | Panel]

Build Rich renderable objects for a tool usage summary.

Used by ToolCallInfo.__rich_console__ to yield Rich objects directly to the console.

PARAMETER DESCRIPTION
tools

List of tool call summaries to render.

TYPE: list[ToolCallInfo]

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

RETURNS DESCRIPTION
list[Table | Panel]

A list of Rich renderable objects (Table or Panel).

Source code in src/mamba_agents/agent/display/rich_renderer.py
def render_tools_renderables(
    self,
    tools: list[ToolCallInfo],
    preset: DisplayPreset,
) -> list[Table | Panel]:
    """Build Rich renderable objects for a tool usage summary.

    Used by ``ToolCallInfo.__rich_console__`` to yield Rich objects
    directly to the console.

    Args:
        tools: List of tool call summaries to render.
        preset: Display configuration controlling detail level.

    Returns:
        A list of Rich renderable objects (Table or Panel).
    """
    # Empty state.
    if not tools:
        return [Panel("No tool calls recorded", title="Tool Summary", expand=False)]

    table = Table(title="Tool Summary")
    table.add_column("Tool Name", style="bold green")
    table.add_column("Calls", justify="right")

    if preset.show_tool_details:
        table.add_column("Details", no_wrap=False)

    for tool in tools:
        if preset.show_tool_details:
            details = self._format_tool_details(tool, preset)
            table.add_row(tool.tool_name, str(tool.call_count), details)
        else:
            table.add_row(tool.tool_name, str(tool.call_count))

    return [table]

render_turn_renderable

render_turn_renderable(
    turn: Turn, preset: DisplayPreset
) -> Panel

Build a Rich Panel for a single conversation turn.

Used by Turn.__rich_console__ to yield a Panel directly to the console.

PARAMETER DESCRIPTION
turn

A Turn instance to render.

TYPE: Turn

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

RETURNS DESCRIPTION
Panel

A Rich Panel containing the formatted turn display.

Source code in src/mamba_agents/agent/display/rich_renderer.py
def render_turn_renderable(
    self,
    turn: Turn,
    preset: DisplayPreset,
) -> Panel:
    """Build a Rich Panel for a single conversation turn.

    Used by ``Turn.__rich_console__`` to yield a Panel directly to
    the console.

    Args:
        turn: A ``Turn`` instance to render.
        preset: Display configuration controlling detail level.

    Returns:
        A Rich Panel containing the formatted turn display.
    """
    sections = Text()

    # System context.
    if turn.system_context is not None:
        sections.append("[System] ", style="bold magenta")
        content = self._truncate(turn.system_context, preset)
        sections.append(content)
        sections.append("\n")

    # User content.
    if turn.user_content is not None:
        sections.append("[User] ", style="bold blue")
        content = self._truncate(turn.user_content, preset)
        sections.append(content)
        sections.append("\n")

    # Assistant content.
    if turn.assistant_content is not None:
        sections.append("[Assistant] ", style="bold yellow")
        content = self._truncate(turn.assistant_content, preset)
        sections.append(content)
        sections.append("\n")

    # Tool interactions.
    if turn.tool_interactions:
        self._render_tool_interactions(sections, turn.tool_interactions, preset)

    # Trim trailing newline if present.
    plain = sections.plain
    if plain.endswith("\n"):
        sections.truncate(len(plain) - 1)

    return Panel(sections, title=f"Turn {turn.index}", expand=False)

PlainTextRenderer

PlainTextRenderer

Bases: MessageRenderer

Plain text renderer for message analytics data.

Produces formatted ASCII text output with aligned columns for message statistics, conversation timelines, and tool call summaries. Output detail is controlled by a DisplayPreset.

Each render method prints to stdout and returns the output as a string. An optional file parameter can redirect output to a different stream.

Example::

from mamba_agents.agent.display.plain_renderer import PlainTextRenderer
from mamba_agents.agent.display.presets import DETAILED

renderer = PlainTextRenderer()
output = renderer.render_stats(stats, DETAILED)
# Output has already been printed to stdout; string also returned.

render_stats

render_stats(
    stats: MessageStats,
    preset: DisplayPreset,
    *,
    file: Any | None = None,
) -> str

Render message statistics as an ASCII table.

Produces a table with columns for Role, Messages, and Tokens (when preset.show_tokens is True). Includes a totals row and an average tokens-per-message summary line beneath the table.

Token numbers are formatted with thousands separators (e.g., 1,234).

PARAMETER DESCRIPTION
stats

Token and message count statistics to render.

TYPE: MessageStats

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

file

Optional output stream. Defaults to sys.stdout.

TYPE: Any | None DEFAULT: None

RETURNS DESCRIPTION
str

The rendered string.

Source code in src/mamba_agents/agent/display/plain_renderer.py
def render_stats(
    self,
    stats: MessageStats,
    preset: DisplayPreset,
    *,
    file: Any | None = None,
) -> str:
    """Render message statistics as an ASCII table.

    Produces a table with columns for Role, Messages, and Tokens (when
    ``preset.show_tokens`` is True). Includes a totals row and an
    average tokens-per-message summary line beneath the table.

    Token numbers are formatted with thousands separators (e.g.,
    ``1,234``).

    Args:
        stats: Token and message count statistics to render.
        preset: Display configuration controlling detail level.
        file: Optional output stream. Defaults to ``sys.stdout``.

    Returns:
        The rendered string.
    """
    output_file = file if file is not None else sys.stdout

    # Empty state.
    if stats.total_messages == 0:
        text = "No messages recorded"
        print(text, file=output_file)
        return text

    lines: list[str] = []
    lines.append("Message Statistics")
    lines.append("")

    # Collect rows: (role, message_count, token_count).
    rows: list[tuple[str, str, str]] = []
    for role in sorted(stats.messages_by_role):
        msg_count = str(stats.messages_by_role[role])
        token_count = f"{stats.tokens_by_role.get(role, 0):,}"
        rows.append((role, msg_count, token_count))

    # Totals row.
    total_msg = str(stats.total_messages)
    total_tok = f"{stats.total_tokens:,}"

    # Calculate column widths.
    role_header = "Role"
    msg_header = "Messages"
    tok_header = "Tokens"

    role_width = max(
        len(role_header),
        max((len(r[0]) for r in rows), default=0),
        len("Total"),
    )
    msg_width = max(
        len(msg_header),
        max((len(r[1]) for r in rows), default=0),
        len(total_msg),
    )

    if preset.show_tokens:
        tok_width = max(
            len(tok_header),
            max((len(r[2]) for r in rows), default=0),
            len(total_tok),
        )
        header = (
            f"  {role_header:<{role_width}}"
            f"  {msg_header:>{msg_width}}"
            f"  {tok_header:>{tok_width}}"
        )
        separator = f"  {'-' * role_width}  {'-' * msg_width}  {'-' * tok_width}"
    else:
        header = f"  {role_header:<{role_width}}  {msg_header:>{msg_width}}"
        separator = f"  {'-' * role_width}  {'-' * msg_width}"

    lines.append(header)
    lines.append(separator)

    # Data rows.
    for role, msg_count, token_count in rows:
        if preset.show_tokens:
            lines.append(
                f"  {role:<{role_width}}  {msg_count:>{msg_width}}  {token_count:>{tok_width}}"
            )
        else:
            lines.append(f"  {role:<{role_width}}  {msg_count:>{msg_width}}")

    # Totals separator and row.
    lines.append(separator)
    if preset.show_tokens:
        lines.append(
            f"  {'Total':<{role_width}}  {total_msg:>{msg_width}}  {total_tok:>{tok_width}}"
        )
    else:
        lines.append(f"  {'Total':<{role_width}}  {total_msg:>{msg_width}}")

    # Average tokens/message summary.
    if preset.show_tokens:
        avg = stats.avg_tokens_per_message
        lines.append("")
        lines.append(f"Average tokens/message: {avg:,.1f}")

    text = "\n".join(lines)
    print(text, file=output_file)
    return text

render_timeline

render_timeline(
    turns: list[Turn],
    preset: DisplayPreset,
    *,
    file: Any | None = None,
) -> str

Render a conversation timeline as formatted text.

Each turn is rendered with role-labelled content sections and separators. Tool interactions are shown as a summary (tool name and call count). Content is truncated according to the preset's max_content_length unless expand is True or max_content_length is None.

PARAMETER DESCRIPTION
turns

List of conversation turns to render.

TYPE: list[Turn]

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

file

Optional output stream. Defaults to sys.stdout.

TYPE: Any | None DEFAULT: None

RETURNS DESCRIPTION
str

The rendered string.

Source code in src/mamba_agents/agent/display/plain_renderer.py
def render_timeline(
    self,
    turns: list[Turn],
    preset: DisplayPreset,
    *,
    file: Any | None = None,
) -> str:
    """Render a conversation timeline as formatted text.

    Each turn is rendered with role-labelled content sections and
    separators. Tool interactions are shown as a summary (tool name
    and call count). Content is truncated according to the preset's
    ``max_content_length`` unless ``expand`` is True or
    ``max_content_length`` is None.

    Args:
        turns: List of conversation turns to render.
        preset: Display configuration controlling detail level.
        file: Optional output stream. Defaults to ``sys.stdout``.

    Returns:
        The rendered string.
    """
    output_file = file if file is not None else sys.stdout

    # Empty state.
    if not turns:
        text = "No conversation turns found"
        print(text, file=output_file)
        return text

    # Apply limit for pagination.
    display_turns = turns
    if preset.limit is not None:
        display_turns = turns[: preset.limit]

    parts: list[str] = []
    for turn in display_turns:
        parts.append(self._format_turn(turn, preset))

    # Show pagination indicator when turns were limited.
    if preset.limit is not None and len(turns) > preset.limit:
        remaining = len(turns) - preset.limit
        parts.append(f"... {remaining} more turn(s) not shown")

    text = "\n".join(parts)
    print(text, file=output_file)
    return text

render_tools

render_tools(
    tools: list[ToolCallInfo],
    preset: DisplayPreset,
    *,
    file: Any | None = None,
) -> str

Render a tool usage summary as an ASCII table.

Default (collapsed) view shows tool name and call count only. When preset.show_tool_details is True, expanded rows show arguments and results per call.

PARAMETER DESCRIPTION
tools

List of tool call summaries to render.

TYPE: list[ToolCallInfo]

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

file

Optional output stream. Defaults to sys.stdout.

TYPE: Any | None DEFAULT: None

RETURNS DESCRIPTION
str

The rendered string.

Source code in src/mamba_agents/agent/display/plain_renderer.py
def render_tools(
    self,
    tools: list[ToolCallInfo],
    preset: DisplayPreset,
    *,
    file: Any | None = None,
) -> str:
    """Render a tool usage summary as an ASCII table.

    Default (collapsed) view shows tool name and call count only.
    When ``preset.show_tool_details`` is True, expanded rows show
    arguments and results per call.

    Args:
        tools: List of tool call summaries to render.
        preset: Display configuration controlling detail level.
        file: Optional output stream. Defaults to ``sys.stdout``.

    Returns:
        The rendered string.
    """
    output_file = file if file is not None else sys.stdout

    # Empty state.
    if not tools:
        text = "No tool calls recorded"
        print(text, file=output_file)
        return text

    lines: list[str] = []
    lines.append("Tool Summary")
    lines.append("")

    # Calculate column widths.
    name_header = "Tool Name"
    calls_header = "Calls"

    name_width = max(
        len(name_header),
        max((len(t.tool_name) for t in tools), default=0),
    )
    calls_width = max(
        len(calls_header),
        max((len(str(t.call_count)) for t in tools), default=0),
    )

    header = f"  {name_header:<{name_width}}  {calls_header:>{calls_width}}"
    separator = f"  {'-' * name_width}  {'-' * calls_width}"

    lines.append(header)
    lines.append(separator)

    for tool in tools:
        lines.append(f"  {tool.tool_name:<{name_width}}  {tool.call_count!s:>{calls_width}}")

        if preset.show_tool_details:
            detail_lines = self._format_tool_details(tool, preset)
            lines.extend(detail_lines)

    text = "\n".join(lines)
    print(text, file=output_file)
    return text

HtmlRenderer

HtmlRenderer

Bases: MessageRenderer

HTML renderer for message analytics data.

Produces self-contained HTML string output with semantic markup (<table>, <th>, <td>, <caption>) for message statistics, conversation timelines, and tool call summaries. Output detail is controlled by a DisplayPreset.

The generated HTML uses no external CSS or JavaScript dependencies and is designed to render cleanly in Jupyter notebooks via IPython.display.HTML.

Example::

from mamba_agents.agent.display.html_renderer import HtmlRenderer
from mamba_agents.agent.display.presets import DETAILED

renderer = HtmlRenderer()
html_str = renderer.render_stats(stats, DETAILED)
# In Jupyter: IPython.display.HTML(html_str)

render_stats

render_stats(
    stats: MessageStats, preset: DisplayPreset
) -> str

Render message statistics as an HTML table.

Produces a <table> with columns for Role, Messages, and Tokens (when preset.show_tokens is True). Includes a totals row and an average tokens-per-message summary paragraph beneath the table.

Token numbers are formatted with thousands separators (e.g., 1,234).

PARAMETER DESCRIPTION
stats

Token and message count statistics to render.

TYPE: MessageStats

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

RETURNS DESCRIPTION
str

A self-contained HTML string.

Source code in src/mamba_agents/agent/display/html_renderer.py
def render_stats(self, stats: MessageStats, preset: DisplayPreset) -> str:
    """Render message statistics as an HTML table.

    Produces a ``<table>`` with columns for Role, Messages, and Tokens
    (when ``preset.show_tokens`` is True). Includes a totals row and
    an average tokens-per-message summary paragraph beneath the table.

    Token numbers are formatted with thousands separators (e.g.,
    ``1,234``).

    Args:
        stats: Token and message count statistics to render.
        preset: Display configuration controlling detail level.

    Returns:
        A self-contained HTML string.
    """
    # Empty state.
    if stats.total_messages == 0:
        return "<p>No messages recorded</p>"

    parts: list[str] = []
    parts.append("<table>")
    parts.append("<caption>Message Statistics</caption>")

    # Header row.
    parts.append("<thead>")
    parts.append("<tr>")
    parts.append("<th>Role</th>")
    parts.append("<th>Messages</th>")
    if preset.show_tokens:
        parts.append("<th>Tokens</th>")
    parts.append("</tr>")
    parts.append("</thead>")

    # Body rows, sorted alphabetically by role.
    parts.append("<tbody>")
    for role in sorted(stats.messages_by_role):
        msg_count = stats.messages_by_role[role]
        parts.append("<tr>")
        parts.append(f"<td>{html.escape(role)}</td>")
        parts.append(f"<td>{msg_count}</td>")
        if preset.show_tokens:
            token_count = stats.tokens_by_role.get(role, 0)
            parts.append(f"<td>{token_count:,}</td>")
        parts.append("</tr>")
    parts.append("</tbody>")

    # Totals row in tfoot.
    parts.append("<tfoot>")
    parts.append("<tr>")
    parts.append("<td><strong>Total</strong></td>")
    parts.append(f"<td><strong>{stats.total_messages}</strong></td>")
    if preset.show_tokens:
        parts.append(f"<td><strong>{stats.total_tokens:,}</strong></td>")
    parts.append("</tr>")
    parts.append("</tfoot>")

    parts.append("</table>")

    # Average tokens/message summary.
    if preset.show_tokens:
        avg = stats.avg_tokens_per_message
        parts.append(f"<p>Average tokens/message: {avg:,.1f}</p>")

    return "\n".join(parts)

render_timeline

render_timeline(
    turns: list[Turn], preset: DisplayPreset
) -> str

Render a conversation timeline as HTML sections.

Each turn is rendered as a <section> containing role-labelled content. Tool interactions are shown as nested summaries. Content is truncated according to the preset's max_content_length unless expand is True or max_content_length is None.

PARAMETER DESCRIPTION
turns

List of conversation turns to render.

TYPE: list[Turn]

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

RETURNS DESCRIPTION
str

A self-contained HTML string.

Source code in src/mamba_agents/agent/display/html_renderer.py
def render_timeline(self, turns: list[Turn], preset: DisplayPreset) -> str:
    """Render a conversation timeline as HTML sections.

    Each turn is rendered as a ``<section>`` containing role-labelled
    content. Tool interactions are shown as nested summaries.
    Content is truncated according to the preset's
    ``max_content_length`` unless ``expand`` is True or
    ``max_content_length`` is None.

    Args:
        turns: List of conversation turns to render.
        preset: Display configuration controlling detail level.

    Returns:
        A self-contained HTML string.
    """
    # Empty state.
    if not turns:
        return "<p>No conversation turns found</p>"

    # Apply limit for pagination.
    display_turns = turns
    if preset.limit is not None:
        display_turns = turns[: preset.limit]

    parts: list[str] = []
    for turn in display_turns:
        parts.append(self._render_turn(turn, preset))

    # Show pagination indicator when turns were limited.
    if preset.limit is not None and len(turns) > preset.limit:
        remaining = len(turns) - preset.limit
        parts.append(f"<p><em>... {remaining} more turn(s) not shown</em></p>")

    return "\n".join(parts)

render_tools

render_tools(
    tools: list[ToolCallInfo], preset: DisplayPreset
) -> str

Render a tool usage summary as an HTML table.

Default (collapsed) view shows tool name and call count only. When preset.show_tool_details is True, a third Details column shows arguments and results per call.

PARAMETER DESCRIPTION
tools

List of tool call summaries to render.

TYPE: list[ToolCallInfo]

preset

Display configuration controlling detail level.

TYPE: DisplayPreset

RETURNS DESCRIPTION
str

A self-contained HTML string.

Source code in src/mamba_agents/agent/display/html_renderer.py
def render_tools(self, tools: list[ToolCallInfo], preset: DisplayPreset) -> str:
    """Render a tool usage summary as an HTML table.

    Default (collapsed) view shows tool name and call count only.
    When ``preset.show_tool_details`` is True, a third Details column
    shows arguments and results per call.

    Args:
        tools: List of tool call summaries to render.
        preset: Display configuration controlling detail level.

    Returns:
        A self-contained HTML string.
    """
    # Empty state.
    if not tools:
        return "<p>No tool calls recorded</p>"

    parts: list[str] = []
    parts.append("<table>")
    parts.append("<caption>Tool Summary</caption>")

    # Header row.
    parts.append("<thead>")
    parts.append("<tr>")
    parts.append("<th>Tool Name</th>")
    parts.append("<th>Calls</th>")
    if preset.show_tool_details:
        parts.append("<th>Details</th>")
    parts.append("</tr>")
    parts.append("</thead>")

    # Body rows.
    parts.append("<tbody>")
    for tool in tools:
        parts.append("<tr>")
        parts.append(f"<td>{html.escape(tool.tool_name)}</td>")
        parts.append(f"<td>{tool.call_count}</td>")
        if preset.show_tool_details:
            details = self._format_tool_details(tool, preset)
            parts.append(f"<td>{details}</td>")
        parts.append("</tr>")
    parts.append("</tbody>")

    parts.append("</table>")

    return "\n".join(parts)