{% extends "base.html" %} {% from '_ui.html' import page_header, empty_state, id_chip %} {% from '_learning_tabs.html' import learning_tabs %} {% block title %}Learning control plane - Memorizz{% endblock %} {% block body_attrs %} data-sidebar-scope="learning" data-sidebar-default="collapsed"{% endblock %} {% block head %}{% endblock %} {% block content %} {#- Links out of an event: its trace, and the exact scope its compile stream covers. -#} {% macro trace_url(row) -%} {%- if row.trace_id -%}/traces?agent_id={{ selected_agent_id|urlencode }}&root_trace_id={{ row.trace_id|urlencode }}#trace-timeline {%- elif row.run_id -%}/traces?agent_id={{ selected_agent_id|urlencode }}&run_id={{ row.run_id|urlencode }}#trace-timeline {%- endif -%} {%- endmacro %} {% macro scope_url(scope) -%} /learning-control-plane?{{ {'agent_id': selected_agent_id, 'memory_id': scope.memory_id, 'user_id': scope.user_id, 'thread_id': scope.thread_id}|urlencode }} {%- endmacro %} {% set lcp_description = 'Inspect bounded retrieval evidence, immutable learning events, incremental compilation and reversible forgetting for one agent scope.' %} {% set tabs = learning_tabs('learning-control-plane', selected_agent_id) %} {% if selected_agent_id and view and not ui_read_only %} {% call page_header('Learning control plane', lcp_description, 'Continual learning', nav=tabs) %}
{% endcall %} {% else %} {{ page_header('Learning control plane', lcp_description, 'Continual learning', nav=tabs) }} {% endif %} {% set scoped = memory_id or user_id or thread_id %} {% if error %}{% endif %} {% if action %}{% endif %} {% if selected_agent_id and view %} {% set plan = view.plan %} {% set to_forget = plan.candidate_count if plan and plan.state == 'awaiting' else 0 %}Compile works on one exact scope. {{ view.pending_in_scope }} of {{ view.pending_count }} uncompiled events are in this scope{% if not scoped %} (no memory, user or thread){% endif %}. Pick a stream under Compile streams, or select an event and use Inspect this scope, then compile.
{% endif %} {% if not ui_read_only and action and action.kind == 'forget-plan' and action.report.candidate_count > 0 %}The dry run found {{ action.report.candidate_count }} candidate(s). Applying writes tombstones only; immutable events are kept.
| Summary | Run | ||||||
|---|---|---|---|---|---|---|---|
| {% if row.recorded %}{{ row.recorded[5:] }}{{ row.recorded[5:16] }}{% else %}—{% endif %} | {{ row.label }} | {{ row.summary }} | {{ row.scope.memory_id or '—' }} | {{ row.scope.user_id or '—' }} | {{ row.scope.thread_id or '—' }} | {{ row.run_ref or '—' }} | {{ 'Compiled' if row.compiled else 'Uncompiled' }} |
No events match this filter.
Showing the newest {{ view.events|length }} of {{ '{:,}'.format(view.event_count) }} events. Narrow the memory, user or thread scope to see older ones.
{% endif %} {% else %} {{ empty_state('No learning events in this scope', 'This scope holds compiled artifacts or checkpoints but no events. Clear the memory, user or thread filter to see the events they were built from.', '/learning-control-plane?agent_id=' ~ selected_agent_id|urlencode, 'Clear scope') }} {% endif %}| Scope | Events | Uncompiled | Last compile | Inspect |
|---|---|---|---|---|
| {{ s.memory_id or '—' }} · {{ s.user_id or '—' }} · {{ s.thread_id or '—' }} | {{ stream.events }} | {{ stream.pending }} | {{ stream.last_compile[5:16] if stream.last_compile else 'Never' }} | {% if current %}In scope{% else %}Inspect{% endif %} |
No event streams in this scope.
{% endif %}| Artifact | Reason | Utility | Age |
|---|---|---|---|
| {{ id_chip(item.target_id, 16) }} | {{ item.reason }} | {{ '%.2f'|format(item.utility) if item.utility is not none else '—' }} | {{ '%.0f'|format(item.age_days) ~ 'd' if item.age_days is not none else '—' }} |
{{ plan.candidates|length - 8 }} more in the plan.
{% endif %} {% endif %} {% if plan.state == 'awaiting' and not (action and action.kind == 'forget-plan') %}Nothing has been removed. {{ 'Select Plan forgetting (dry run) for this scope to review the latest candidates and approve them.' if not ui_read_only else 'This console is read-only; apply the plan from the SDK with agent.apply_forgetting().' }}
{% endif %} {% else %}No dry run yet. A plan lists compiled artifacts that are duplicates or whose utility has decayed, so they can be tombstoned. Nothing is removed until an operator approves, and immutable events are always kept.{% if ui_read_only %} This console is read-only; plan forgetting from the SDK with agent.plan_forgetting().{% else %} Select Plan forgetting (dry run) to create one.{% endif %}
{% endif %}| Updated | Kind | Verification | Utility | Sources | Content | Artifact ID |
|---|---|---|---|---|---|---|
| {{ artifact.updated[5:16] or '—' }} | {{ artifact.kind_label }} | {% if artifact.tombstoned %}Tombstoned{% elif artifact.verified %}Verified{% else %}Unverified{% endif %} | {{ '%.2f'|format(artifact.utility) if artifact.utility is not none else '—' }} | {{ artifact.sources or '—' }} | {{ artifact.content or '—' }} | {% if artifact.artifact_id %}{{ id_chip(artifact.artifact_id|string, 20) }}{% else %}—{% endif %} |