{#- The polled region of /history (#refresh-region): htmx re-fetches the view every 5s and the alpine-morph extension morphs the fresh fragment over the region in place, so only the region's content ever changes. The filter form lives OUTSIDE the region (history.html) โ€” in-progress filter input survives every poll and every filter swap by construction, and window scroll is re-anchored by the app.js swap listeners. The route renders THIS template alone on an HX-Request, so a poll is a cheap region render, never a full page. Each request's params ride from the form's live fields (hx-include on the region serializes the form; the hidden store and window fields come with it), so the region always re-renders exactly the slice the page is showing. The page cursor (before/after โ€” paging state, not a filter) rides the region's hx-get URL, baked at render time, so a poll of a cursor-paged slice re-requests that page instead of reverting to page 1. -#} {% import "_links.html" as links with context %} {% import "_table.html" as tables with context %} {% import "_cards.html" as cards with context %} {%- set poll_q = {} %} {%- if before %}{% set _ = poll_q.update({'before': before}) %}{% endif %} {%- if after %}{% set _ = poll_q.update({'after': after}) %}{% endif %}

History

{{ cards.stat_row([ {"value": calls | length, "label": "calls shown"}, {"value": window, "label": "time window"}, {"value": calls | selectattr('status', 'equalto', 'error') | list | length, "label": "error calls"}, ]) }} {% include "window_control.html" %} {#- FR-005: exports ride the view's current filters (the selected store rides links.url); before/after are page cursors, not filters. -#} {%- set export_q = {} %} {%- if tool %}{% set _ = export_q.update({'tool': tool}) %}{% endif %} {%- if session %}{% set _ = export_q.update({'session': session}) %}{% endif %} {%- if source %}{% set _ = export_q.update({'source': source}) %}{% endif %} {%- if window != "all" %}{% set _ = export_q.update({'window': window}) %}{% endif %}

Export: CSV JSON

{% if calls %} {% call tables.table(['Tool', 'Timestamp', 'Duration', 'Status', 'Session', 'Source', 'Est. tokens (req/resp)', 'Arguments']) %} {% for h in calls %} {{ h.tool_name }} {{ h.invoked_at | epoch }} {{ h.duration_ms | duration }} {{ h.status }} {{ links.view_link('chains', 'session', h.session_id, window) }} {{ h.source }} {{ h | tokens }} {{ h.args_summary or "โ€”" }} {% endfor %} {% endcall %} {% if prev_cursor or next_cursor %} {#- FR-003/FR-006: paging links keep the active filters AND the selected store (links.url); empty selection keeps the bare hrefs. -#}

{%- if prev_cursor %} {%- set q = {'after': prev_cursor} %} {%- if tool %}{% set _ = q.update({'tool': tool}) %}{% endif %} {%- if session %}{% set _ = q.update({'session': session}) %}{% endif %} {%- if source %}{% set _ = q.update({'source': source}) %}{% endif %} {%- if window != "all" %}{% set _ = q.update({'window': window}) %}{% endif %} Newer {%- endif %} {%- if prev_cursor and next_cursor %} ยท {% endif %} {%- if next_cursor %} {%- set q = {'before': next_cursor} %} {%- if tool %}{% set _ = q.update({'tool': tool}) %}{% endif %} {%- if session %}{% set _ = q.update({'session': session}) %}{% endif %} {%- if source %}{% set _ = q.update({'source': source}) %}{% endif %} {%- if window != "all" %}{% set _ = q.update({'window': window}) %}{% endif %} Older {%- endif %}

{% endif %} {% else %} {{ tables.empty_state('No matching calls' ~ (' recorded yet' if not tool and not session and not source else '')) }} {% endif %}