---
title: "ADR-020: Backend Output Format Rendering"
manual: "TYPO3 LLM Extension"
version: "0.35"
permalink: "https://docs.typo3.org/permalink/netresearch/nr-llm:adr-020@0.35"
source: "Adr/Adr020BackendOutputFormatRendering.rst"
modified: "2026-09-16T22:09:16+00:00"
---

# ADR-020: Backend Output Format Rendering

-   *Status:* Accepted
-   *Date:* 2025-12
-   *Authors:* Netresearch DTT GmbH

## Context

LLM responses can contain markdown, HTML, JSON, or plain text depending on the
task's output format. Users need to view output in an appropriate rendering
mode without re-executing the (potentially expensive) LLM call.

## Decision

Store raw LLM output and handle format rendering entirely client-side. The
toggle between formats is ephemeral (not persisted) and operates on the
cached raw content.

Four rendering modes in
`Resources/Public/JavaScript/Backend/TaskExecute.js`:

**Format rendering dispatch**

```javascript
renderOutput() {
    const content = this._rawContent;
    const escaped = this.escapeHtml(content);
    switch (this._activeFormat) {
        case 'html':     this.renderHtmlOutput(content);    break;
        case 'markdown': this.renderMarkdownOutput(escaped); break;
        case 'json':     this.renderJsonOutput(content);     break;
        default:         this.renderPlainOutput();            break;
    }
}
```

### Rendering modes

| Mode | Technique | Security |
| --- | --- | --- |
| Plain | `<pre>` with `textContent` assignment | Fully escaped (DOM API) |
| Markdown | Regex transforms on HTML-escaped content | Pre-escaped before transform |
| JSON | `JSON.stringify` pretty-print in `<pre>` | `textContent` assignment |
| HTML | Sandboxed iframe (`sandbox=\"\"`) | No script execution, no parent DOM access |

### Security approach

LLM responses are untrusted external content. Each mode uses a different
security strategy:

-   **Plain/JSON:** Content set via `textContent`
    (automatic HTML escaping by the DOM).
-   **Markdown:** Content is first HTML-escaped via
    `escapeHtml()` (`textContent` assignment to a
    temporary element, then read back via
    `innerHTML`). Markdown regex transforms operate on
    already-escaped content, making injection safe.
-   **HTML:** Rendered inside a fully sandboxed
    `<iframe sandbox="">` which blocks all scripting,
    form submission, and parent page access. A fixed
    height of 400px is used since `contentDocument` is
    inaccessible in sandbox mode.

**XSS-safe HTML escaping**

```javascript
escapeHtml(text) {
    this._escapeEl.textContent = text;
    return this._escapeEl.innerHTML;
}
```

### Format toggle

The active format is initialized from the task's `output_format` setting
(returned by the server in the AJAX response) and can be switched by clicking
format toggle buttons. The toggle updates `_activeFormat`, re-renders from
`_rawContent`, and highlights the active button. Clipboard copy always uses
the raw content regardless of active rendering mode.

## Consequences

**Positive:**

-   ●● No server round-trip needed to switch display formats.
-   ● XSS prevention for all four rendering modes via
    distinct security strategies.
-   ● Raw content preserved for clipboard copy regardless of rendering.
-   ◐ Format toggle state is ephemeral, avoiding unnecessary persistence.
-   ◐ Markdown renderer is lightweight (regex-based, no external library).

**Negative:**

-   ◑ Markdown regex renderer is simplified (no tables,
    no nested lists, no links).
-   ◑ HTML iframe height is fixed at 400px (cannot auto-resize in sandboxed mode).
-   ◑ No syntax highlighting for JSON or code blocks.

**Net Score:** +4.5 (Positive)

## Files changed

**Added:**

-   `Resources/Public/JavaScript/Backend/TaskExecute.js`

**Modified:**

-   `Resources/Private/Templates/Backend/Task/Execute.html`
    -- Format toggle UI and output container.
-   `Classes/Controller/Backend/TaskExecutionController.php`
    -- Returns `outputFormat` in the AJAX response (the monolithic
    `TaskController` was split per [ADR-027](https://docs.typo3.org/permalink/netresearch/nr-llm:adr-027@0.35)).
-   `Classes/Domain/Enum/TaskOutputFormat.php`
    -- Defines valid output formats with content types.
