ADR 020 · Accepted

Backend Output Format Rendering

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:

Rendering modes

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.

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).

  • Classes/Domain/Enum/TaskOutputFormat.php -- Defines valid output formats with content types.

← All ADRs