{# Spec 153 - /chat page. Renders both states from a single template, branched on ``key_configured``: * State A - no LLM key set: empty pane + "Configure LLM" CTA linking to /admin/settings/llm. No chat input rendered. * State B - key set: streaming chat surface backed by Server-Sent Events from /chat/turn. Egress disclosure banner ALWAYS rendered above whichever state shows (FR-010). #} {% extends "layout.html" %} {% block content %}

Audit AI

Ask your audit data in plain English. Backed by the same tools the audit dashboard uses; numbers cited here match what the rest of the audit shows for the same metric.

{# Persistent egress disclosure - FR-010. Visible regardless of state so the user always knows what enabling chat means. #}

Heads up: Using Audit AI sends conversation content to your configured LLM provider {% if key_configured %} ({{ provider }}). {% else %} once you configure one. {% endif %} Conversation history is browser-local only — the audit never persists chat content to disk.

{% if not key_configured %} {# ── State A - empty / unconfigured ────────────────────────── #}

Audit AI is disabled

To enable Audit AI, configure an LLM provider + API key in Settings. The audit will send your conversation content to that provider on every turn; nothing leaves your machine until you configure a key.

{% else %} {# ── State B - configured ────────────────────────────────── #} {% if scan_status_summary %}

{{ scan_status_summary }}

{% endif %}
{# Transcript area. Populated by the inline JS handler below. Sized so the scrollbar lives inside the panel; the input stays anchored at the bottom regardless of conversation length. #}

Try: What's my most expensive flagged model right now?, Did I have slot contention this week?, or What's the partition recommendation for a table?

{# Cost strip - server's CostEvent populates this. #}
Session cost: $0.0000 {% if chat_session_cap_usd > 0 %} / ${{ '%.2f' | format(chat_session_cap_usd) }} cap {% else %} (no cap) {% endif %}
{# Cap-reached overlay - initially hidden; shown when a turn comes back with DoneEvent(finish_reason="cost_cap"). #}
{% endif %}
{% endblock %}