{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "agent-memory-inspector",
  "title": "Agent Memory Inspector",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/agent-memory-inspector/agent-memory-inspector.component.ts",
      "content": "import { Component, DestroyRef, Input, OnInit, computed, inject, signal, ChangeDetectionStrategy } from '@angular/core'\nimport {\n  Activity,\n  AlertCircle,\n  Brain,\n  Check,\n  Clock,\n  Cpu,\n  Database,\n  LucideAngularModule,\n  Network,\n  Pencil,\n  Plus,\n  RefreshCw,\n  Search,\n  Star,\n  Trash2,\n  X,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiAvatarComponent, UiAvatarFallbackComponent } from '@/ui/avatar/avatar.component'\nimport { UiBadgeComponent, type BadgeVariant } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardFooterComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\nimport {\n  UiTabsComponent,\n  UiTabsContentComponent,\n  UiTabsListComponent,\n  UiTabsTriggerComponent,\n} from '@/ui/tabs/tabs.component'\nimport { UiAgentContextBufferComponent } from './agent-context-buffer.component'\nimport { UiAgentEntityGraphComponent } from './agent-entity-graph.component'\nimport {\n  INITIAL_ENTITY_NODES,\n  INITIAL_GRAPH_TRIPLETS,\n  INITIAL_MEMORY_FACTS,\n  INITIAL_MESSAGE_TURNS,\n} from './agent-memory-data'\nimport type { EntityNode, EpisodicMemory, GraphTriplet, MemoryCategory, MessageTurn } from './agent-memory-types'\n\nexport type { EpisodicMemory, MessageTurn, EntityNode, GraphTriplet, MemoryCategory } from './agent-memory-types'\n\ntype CategoryFilter = 'all' | MemoryCategory\n\ninterface FactForm {\n  content: string\n  category: MemoryCategory\n  confidence: number\n}\n\nconst EMPTY_FORM: FactForm = { content: '', category: 'User Preference', confidence: 0.95 }\n\nconst CATEGORY_FILTERS: { value: CategoryFilter; label: string }[] = [\n  { value: 'User Preference', label: 'Preference' },\n  { value: 'Architecture Rule', label: 'Architecture' },\n  { value: 'System Constraint', label: 'Constraint' },\n]\n\n/**\n * AgentMemoryInspector -- the React block, 1:1: an agent header (wipe / add actions), an\n * inline add/edit fact form, and three tabs: the short-term context buffer, the long-term\n * episodic memory table (search, category filter, pin, edit, delete) and the entity graph.\n * `initialMemories` seeds the episodic facts; edits after that live in the component.\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-agent-memory-inspector, [ui-agent-memory-inspector]',\n  standalone: true,\n  host: { class: 'contents' },\n  imports: [\n    LucideAngularModule,\n    UiAvatarComponent,\n    UiAvatarFallbackComponent,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardFooterComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiProgressComponent,\n    UiTableComponent,\n    UiTableHeaderComponent,\n    UiTableBodyComponent,\n    UiTableRowComponent,\n    UiTableHeadComponent,\n    UiTableCellComponent,\n    UiTabsComponent,\n    UiTabsListComponent,\n    UiTabsTriggerComponent,\n    UiTabsContentComponent,\n    UiAgentContextBufferComponent,\n    UiAgentEntityGraphComponent,\n  ],\n  template: `\n    <div [class]=\"rootClass\">\n      <!-- Header Block -->\n      <div ui-card class=\"border-border shadow-xs\">\n        <div ui-card-header class=\"p-6 pb-4\">\n          <div class=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n            <!-- Left: Agent Identity & Engine Details -->\n            <div class=\"flex items-start gap-4\">\n              <div class=\"relative\">\n                <span ui-avatar class=\"border-border bg-muted/60 h-12 w-12 rounded-xl border p-1\">\n                  <span ui-avatar-fallback class=\"bg-primary/10 text-primary rounded-lg font-mono text-sm font-bold\">\n                    <lucide-icon [img]=\"Brain\" class=\"text-primary h-6 w-6\" />\n                  </span>\n                </span>\n                <span\n                  class=\"bg-background absolute -right-0.5 -bottom-0.5 flex h-3.5 w-3.5 items-center justify-center rounded-full\"\n                >\n                  <span class=\"bg-success ring-success/20 h-2 w-2 rounded-full ring-2\"></span>\n                </span>\n              </div>\n\n              <div class=\"space-y-1\">\n                <div class=\"flex flex-wrap items-center gap-2\">\n                  <h2 class=\"text-foreground text-lg font-semibold tracking-tight\">\n                    Senior Engineering Co-Pilot Agent\n                  </h2>\n                  <span ui-badge variant=\"outline\" class=\"gap-1 px-2 py-0.5 text-xs font-medium\">\n                    <lucide-icon [img]=\"Cpu\" class=\"text-warning h-3 w-3\" />\n                    Autonomous Sync\n                  </span>\n                </div>\n\n                <!-- makes the svg itself the flex item (as in React), so it can\n                     shrink the same way when the label wraps on narrow screens. -->\n                <div class=\"text-muted-foreground flex flex-wrap items-center gap-x-3 gap-y-1 text-xs\">\n                  <span class=\"text-foreground flex items-center gap-1.5 font-medium\">\n                    <lucide-icon [img]=\"Database\" class=\"text-primary h-3.5 w-3.5\" />\n                    Mem0 Vector + Neo4j Entity Graph\n                  </span>\n                  <span class=\"flex items-center gap-1\">\n                    <lucide-icon [img]=\"Network\" class=\"h-3.5 w-3.5\" />\n                    142 Episodic Memories · 28 Entity Nodes\n                  </span>\n                  <span class=\"text-muted-foreground flex items-center gap-1 font-mono\">\n                    <lucide-icon [img]=\"Activity\" class=\"text-success h-3 w-3\" />\n                    Recall: 12ms\n                  </span>\n                </div>\n              </div>\n            </div>\n\n            <!-- Right: Actions -->\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <button\n                ui-button\n                variant=\"ghost\"\n                size=\"sm\"\n                class=\"text-muted-foreground hover:text-destructive h-9 gap-1.5 text-xs font-medium\"\n                (click)=\"wipeWorkingMemory()\"\n              >\n                <lucide-icon [img]=\"Trash2\" class=\"h-3.5 w-3.5\" />\n                Wipe Working Memory\n              </button>\n\n              <button ui-button size=\"sm\" class=\"h-9 gap-1.5 text-xs font-medium shadow-xs\" (click)=\"startAddFact()\">\n                <lucide-icon [img]=\"Plus\" class=\"h-3.5 w-3.5\" />\n                Add Memory Fact\n              </button>\n            </div>\n          </div>\n        </div>\n\n        <!-- Wipe State Feedback Banner -->\n        @if (wipeToastVisible()) {\n          <div class=\"border-destructive/20 bg-destructive/5 border-t px-6 py-2.5\">\n            <div class=\"text-destructive flex items-center justify-between gap-2 text-xs\">\n              <div class=\"flex items-center gap-2\">\n                <lucide-icon [img]=\"AlertCircle\" class=\"h-4 w-4 shrink-0\" />\n                <span>Working context buffer cache cleared. Persistent episodic facts remain intact.</span>\n              </div>\n              <button\n                ui-button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"border-destructive/30 text-destructive hover:bg-destructive/10 h-7 text-xs\"\n                (click)=\"restoreWorkingMemory()\"\n              >\n                <!-- [class] (not class=) feeds only the svg, so mr-1 is not applied twice (host + svg). -->\n                <lucide-icon [img]=\"RefreshCw\" [class]=\"'mr-1 h-3 w-3'\" />\n                Restore\n              </button>\n            </div>\n          </div>\n        }\n      </div>\n\n      <!-- Inline Add/Edit Memory Fact Modal / Drawer -->\n      @if (isAddingFact()) {\n        <div ui-card class=\"border-primary/30 bg-card ring-primary/20 shadow-sm ring-1\">\n          <div ui-card-header class=\"p-4 pb-2\">\n            <div class=\"flex items-center justify-between\">\n              <div class=\"flex items-center gap-2\">\n                <lucide-icon [img]=\"Brain\" class=\"text-primary h-4 w-4\" />\n                <h3 ui-card-title class=\"text-sm font-semibold\">\n                  {{ editingFactId() ? 'Edit Memory Fact' : 'Add Episodic Memory Fact' }}\n                </h3>\n              </div>\n              <button\n                ui-button\n                variant=\"ghost\"\n                size=\"sm\"\n                class=\"h-7 w-7 p-0\"\n                aria-label=\"Cancel adding fact\"\n                (click)=\"cancelAddFact()\"\n              >\n                <lucide-icon [img]=\"X\" class=\"h-4 w-4\" />\n              </button>\n            </div>\n            <p ui-card-description class=\"text-xs\">\n              Inject a verified truth into the persistent Mem0 vector embedding space.\n            </p>\n          </div>\n\n          <div ui-card-content class=\"space-y-3 p-4 pt-2\">\n            <div class=\"space-y-1.5\">\n              <label class=\"text-foreground text-xs font-medium\">Fact Content</label>\n              <textarea\n                [value]=\"form().content\"\n                (input)=\"onContentInput($event)\"\n                placeholder=\"e.g. User enforces strict 120-character printWidth in Prettier...\"\n                rows=\"2\"\n                class=\"border-input bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring w-full rounded-md border px-3 py-2 text-xs focus-visible:ring-1 focus-visible:outline-none\"\n              ></textarea>\n            </div>\n\n            <div class=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n              <div class=\"space-y-1.5\">\n                <label class=\"text-foreground text-xs font-medium\">Memory Category</label>\n                <select\n                  [value]=\"form().category\"\n                  (change)=\"onCategoryChange($event)\"\n                  class=\"border-input bg-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-xs focus-visible:ring-1 focus-visible:outline-none\"\n                >\n                  <option value=\"User Preference\">User Preference</option>\n                  <option value=\"Architecture Rule\">Architecture Rule</option>\n                  <option value=\"System Constraint\">System Constraint</option>\n                </select>\n              </div>\n\n              <div class=\"space-y-1.5\">\n                <label class=\"text-foreground text-xs font-medium\">Confidence Score (0.0 - 1.0)</label>\n                <input\n                  type=\"number\"\n                  step=\"0.01\"\n                  min=\"0\"\n                  max=\"1\"\n                  [value]=\"form().confidence\"\n                  (input)=\"onConfidenceInput($event)\"\n                  class=\"border-input bg-background text-foreground focus-visible:ring-ring w-full rounded-md border px-3 py-1.5 font-mono text-xs focus-visible:ring-1 focus-visible:outline-none\"\n                />\n              </div>\n            </div>\n          </div>\n\n          <div ui-card-footer class=\"border-border flex justify-end gap-2 border-t p-3\">\n            <button\n              ui-button\n              aria-label=\"Cancel adding fact\"\n              variant=\"ghost\"\n              size=\"sm\"\n              class=\"h-8 text-xs\"\n              (click)=\"cancelAddFact()\"\n            >\n              Cancel\n            </button>\n            <button ui-button size=\"sm\" class=\"h-8 text-xs font-medium\" (click)=\"saveNewFact()\">\n              <lucide-icon [img]=\"Check\" [class]=\"'mr-1 h-3.5 w-3.5'\" />\n              {{ editingFactId() ? 'Save Changes' : 'Store Fact' }}\n            </button>\n          </div>\n        </div>\n      }\n\n      <!-- Main Tabs Section -->\n      <div ui-tabs [value]=\"activeTab()\" (valueChange)=\"activeTab.set($event)\" class=\"w-full space-y-4\">\n        <div ui-tabs-list class=\"border-border bg-muted/40 grid h-10 w-full grid-cols-3 rounded-lg border p-1\">\n          <button ui-tabs-trigger value=\"context\" class=\"gap-2 text-xs font-medium\">\n            <lucide-icon [img]=\"Cpu\" class=\"h-3.5 w-3.5\" />\n            <span>Short-Term Context Buffer</span>\n            <span ui-badge variant=\"secondary\" class=\"ml-1 px-1.5 py-0 font-mono text-xs font-normal\">\n              {{ isWiped() ? '0 turns' : '4 turns' }}\n            </span>\n          </button>\n\n          <button ui-tabs-trigger value=\"episodic\" class=\"gap-2 text-xs font-medium\">\n            <lucide-icon [img]=\"Database\" class=\"h-3.5 w-3.5\" />\n            <span>Long-Term Episodic Memory</span>\n            <span ui-badge variant=\"secondary\" class=\"ml-1 px-1.5 py-0 font-mono text-xs font-normal\">\n              {{ memoryFacts().length }} Facts\n            </span>\n          </button>\n\n          <button ui-tabs-trigger value=\"graph\" class=\"gap-2 text-xs font-medium\">\n            <lucide-icon [img]=\"Network\" class=\"h-3.5 w-3.5\" />\n            <span>Entity Knowledge Graph</span>\n            <span ui-badge variant=\"secondary\" class=\"ml-1 px-1.5 py-0 font-mono text-xs font-normal\">\n              {{ entityNodes.length }} Nodes\n            </span>\n          </button>\n        </div>\n\n        <!-- TAB 1: SHORT-TERM CONTEXT BUFFER -->\n        <div ui-tabs-content value=\"context\" class=\"space-y-4 outline-none\">\n          <ui-agent-context-buffer\n            [isWiped]=\"isWiped()\"\n            [turns]=\"messageTurns\"\n            [selectedTurnId]=\"selectedTurnId()\"\n            (selectTurn)=\"selectedTurnId.set($event)\"\n            (restore)=\"restoreWorkingMemory()\"\n          />\n        </div>\n\n        <!-- TAB 2: LONG-TERM EPISODIC MEMORY TABLE -->\n        <div ui-tabs-content value=\"episodic\" class=\"space-y-4 outline-none\">\n          <div ui-card class=\"border-border shadow-xs\">\n            <!-- Filter and Search Header -->\n            <div ui-card-header class=\"p-5 pb-3\">\n              <div class=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n                <div>\n                  <h3 ui-card-title class=\"text-sm font-semibold\">Persistent Episodic Facts</h3>\n                  <p ui-card-description class=\"text-xs\">\n                    Distilled knowledge facts retrieved via Mem0 vector cosine similarity search.\n                  </p>\n                </div>\n\n                <!-- Search & Category Filters -->\n                <div class=\"flex flex-wrap items-center gap-2\">\n                  <div class=\"relative w-full sm:w-64\">\n                    <!-- [class] (not class=) keeps absolute/top/left on the svg only, not doubled on the host. -->\n                    <lucide-icon\n                      [img]=\"Search\"\n                      [class]=\"'text-muted-foreground absolute top-2.5 left-2.5 h-3.5 w-3.5'\"\n                    />\n                    <input\n                      type=\"text\"\n                      [value]=\"searchQuery()\"\n                      (input)=\"onSearchInput($event)\"\n                      placeholder=\"Search memory facts or tags...\"\n                      class=\"border-input bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border pr-3 pl-8 text-xs focus-visible:ring-1 focus-visible:outline-none\"\n                    />\n                  </div>\n\n                  <div class=\"border-border bg-muted/40 flex items-center gap-1 rounded-lg border p-0.5\">\n                    <button type=\"button\" [class]=\"filterClass('all')\" (click)=\"selectedCategory.set('all')\">\n                      All ({{ memoryFacts().length }})\n                    </button>\n                    @for (f of categoryFilters; track f.value) {\n                      <button type=\"button\" [class]=\"filterClass(f.value)\" (click)=\"selectedCategory.set(f.value)\">\n                        {{ f.label }}\n                      </button>\n                    }\n                  </div>\n                </div>\n              </div>\n            </div>\n\n            <!-- Memory Table -->\n            <div ui-card-content class=\"p-0\">\n              <div class=\"overflow-x-auto\">\n                <div ui-table>\n                  <thead ui-table-header>\n                    <tr ui-table-row class=\"hover:bg-transparent\">\n                      <th ui-table-head class=\"w-8\"></th>\n                      <th ui-table-head class=\"min-w-[280px]\">Memory Fact Content</th>\n                      <th ui-table-head class=\"w-[160px]\">Category</th>\n                      <th ui-table-head class=\"w-[130px]\">Confidence</th>\n                      <th ui-table-head class=\"w-[140px]\">Last Recalled</th>\n                      <th ui-table-head class=\"w-[100px] text-right\">Actions</th>\n                    </tr>\n                  </thead>\n\n                  <tbody ui-table-body>\n                    @for (fact of filteredMemories(); track fact.id) {\n                      <tr ui-table-row class=\"group hover:bg-muted/40\">\n                        <!-- Pin / Star Icon -->\n                        <td ui-table-cell class=\"py-3 pr-1 pl-4\">\n                          <button\n                            type=\"button\"\n                            class=\"text-muted-foreground hover:text-warning focus-visible:outline-none\"\n                            [title]=\"fact.isPinned ? 'Unpin fact' : 'Pin fact'\"\n                            (click)=\"togglePinFact(fact.id)\"\n                          >\n                            <lucide-icon [img]=\"Star\" [class]=\"starClass(fact)\" />\n                          </button>\n                        </td>\n\n                        <!-- Content & Source Details -->\n                        <td ui-table-cell class=\"py-3\">\n                          <div class=\"space-y-1\">\n                            <div class=\"text-foreground text-xs leading-relaxed font-medium\">{{ fact.content }}</div>\n                            <div class=\"text-muted-foreground flex flex-wrap items-center gap-1.5 text-xs\">\n                              <span class=\"text-muted-foreground font-mono\">{{ fact.sourceTurn }}</span>\n                              <span>·</span>\n                              <div class=\"flex items-center gap-1\">\n                                @for (tag of fact.tags; track tag) {\n                                  <span class=\"bg-muted py-0.2 text-muted-foreground rounded px-1.5 font-mono text-xs\">\n                                    #{{ tag }}\n                                  </span>\n                                }\n                              </div>\n                            </div>\n                          </div>\n                        </td>\n\n                        <!-- Category Badge -->\n                        <td ui-table-cell class=\"py-3\">\n                          <span ui-badge [variant]=\"getCategoryVariant(fact.category)\" class=\"text-xs font-normal\">\n                            {{ fact.category }}\n                          </span>\n                        </td>\n\n                        <!-- Confidence Meter -->\n                        <td ui-table-cell class=\"py-3\">\n                          <div class=\"space-y-1\">\n                            <div class=\"flex items-center justify-between font-mono text-xs\">\n                              <span class=\"text-foreground font-semibold\"\n                                >{{ confidencePercent(fact.confidence) }}%</span\n                              >\n                              <span class=\"text-muted-foreground\">({{ fact.confidence }})</span>\n                            </div>\n                            <div ui-progress [value]=\"fact.confidence * 100\" class=\"bg-muted h-1.5 w-20\"></div>\n                          </div>\n                        </td>\n\n                        <!-- Last Recalled & Recalls Count -->\n                        <td ui-table-cell class=\"py-3\">\n                          <div class=\"space-y-0.5 text-xs\">\n                            <div class=\"text-foreground flex items-center gap-1 font-medium\">\n                              <lucide-icon [img]=\"Clock\" class=\"text-muted-foreground h-3 w-3\" />\n                              <span>{{ fact.lastRecalled }}</span>\n                            </div>\n                            <div class=\"text-muted-foreground font-mono text-xs\">Recalled {{ fact.recallsCount }}×</div>\n                          </div>\n                        </td>\n\n                        <!-- Actions -->\n                        <td ui-table-cell class=\"py-3 pr-4 text-right\">\n                          <div class=\"flex items-center justify-end gap-1\">\n                            <button\n                              ui-button\n                              variant=\"ghost\"\n                              size=\"sm\"\n                              class=\"text-muted-foreground hover:text-foreground h-7 w-7 p-0\"\n                              title=\"Edit fact\"\n                              (click)=\"editFact(fact)\"\n                            >\n                              <lucide-icon [img]=\"Pencil\" class=\"h-3.5 w-3.5\" />\n                            </button>\n\n                            <button\n                              ui-button\n                              variant=\"ghost\"\n                              size=\"sm\"\n                              class=\"text-muted-foreground hover:text-destructive h-7 w-7 p-0\"\n                              title=\"Delete fact\"\n                              (click)=\"deleteFact(fact.id)\"\n                            >\n                              <lucide-icon [img]=\"Trash2\" class=\"h-3.5 w-3.5\" />\n                            </button>\n                          </div>\n                        </td>\n                      </tr>\n                    } @empty {\n                      <tr ui-table-row>\n                        <td ui-table-cell colspan=\"6\" class=\"text-muted-foreground h-28 text-center text-xs\">\n                          No matching memory facts found for the current query.\n                        </td>\n                      </tr>\n                    }\n                  </tbody>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- TAB 3: SEMANTIC ENTITY GRAPH -->\n        <div ui-tabs-content value=\"graph\" class=\"space-y-4 outline-none\">\n          <ui-agent-entity-graph\n            [triplets]=\"graphTriplets\"\n            [nodes]=\"entityNodes\"\n            [selectedNodeId]=\"selectedNodeId()\"\n            (selectNode)=\"selectedNodeId.set($event)\"\n          />\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiAgentMemoryInspectorComponent implements OnInit {\n  protected readonly Activity = Activity\n  protected readonly AlertCircle = AlertCircle\n  protected readonly Brain = Brain\n  protected readonly Check = Check\n  protected readonly Clock = Clock\n  protected readonly Cpu = Cpu\n  protected readonly Database = Database\n  protected readonly Network = Network\n  protected readonly Pencil = Pencil\n  protected readonly Plus = Plus\n  protected readonly RefreshCw = RefreshCw\n  protected readonly Search = Search\n  protected readonly Star = Star\n  protected readonly Trash2 = Trash2\n  protected readonly X = X\n  protected readonly categoryFilters = CATEGORY_FILTERS\n\n  @Input('class') className?: string\n  /** Seeds the episodic facts (React `initialMemories`); later changes to the input are not re-applied. */\n  @Input() initialMemories: EpisodicMemory[] = INITIAL_MEMORY_FACTS\n\n  readonly memoryFacts = signal<EpisodicMemory[]>(INITIAL_MEMORY_FACTS)\n  readonly messageTurns: MessageTurn[] = INITIAL_MESSAGE_TURNS\n  readonly entityNodes: EntityNode[] = INITIAL_ENTITY_NODES\n  readonly graphTriplets: GraphTriplet[] = INITIAL_GRAPH_TRIPLETS\n  readonly activeTab = signal('context')\n  readonly selectedCategory = signal<CategoryFilter>('all')\n  readonly searchQuery = signal('')\n  readonly selectedTurnId = signal('turn-4')\n  readonly selectedNodeId = signal('node-2')\n  readonly isWiped = signal(false)\n  readonly wipeToastVisible = signal(false)\n  readonly isAddingFact = signal(false)\n  readonly editingFactId = signal<string | null>(null)\n  readonly form = signal<FactForm>({ ...EMPTY_FORM })\n\n  private wipeTimer?: ReturnType<typeof setTimeout>\n\n  readonly filteredMemories = computed(() => {\n    const category = this.selectedCategory()\n    const query = this.searchQuery()\n    return this.memoryFacts().filter((fact) => {\n      const matchesCategory = category === 'all' || fact.category === category\n      const matchesSearch =\n        query.trim() === '' ||\n        fact.content.toLowerCase().includes(query.toLowerCase()) ||\n        fact.tags.some((t) => t.toLowerCase().includes(query.toLowerCase()))\n      return matchesCategory && matchesSearch\n    })\n  })\n\n  constructor() {\n    inject(DestroyRef).onDestroy(() => clearTimeout(this.wipeTimer))\n  }\n\n  ngOnInit(): void {\n    this.memoryFacts.set(this.initialMemories)\n  }\n\n  get rootClass(): string {\n    return cn('w-full space-y-6 font-sans antialiased', this.className)\n  }\n\n  wipeWorkingMemory(): void {\n    this.isWiped.set(true)\n    this.wipeToastVisible.set(true)\n    clearTimeout(this.wipeTimer)\n    this.wipeTimer = setTimeout(() => this.wipeToastVisible.set(false), 4000)\n  }\n\n  restoreWorkingMemory(): void {\n    this.isWiped.set(false)\n    this.wipeToastVisible.set(false)\n  }\n\n  deleteFact(id: string): void {\n    this.memoryFacts.update((prev) => prev.filter((f) => f.id !== id))\n  }\n\n  togglePinFact(id: string): void {\n    this.memoryFacts.update((prev) => prev.map((f) => (f.id === id ? { ...f, isPinned: !f.isPinned } : f)))\n  }\n\n  startAddFact(): void {\n    this.isAddingFact.set(true)\n    this.editingFactId.set(null)\n    this.form.set({ ...EMPTY_FORM })\n  }\n\n  editFact(fact: EpisodicMemory): void {\n    this.editingFactId.set(fact.id)\n    this.form.set({ content: fact.content, category: fact.category, confidence: fact.confidence })\n    this.isAddingFact.set(true)\n  }\n\n  saveNewFact(): void {\n    const form = this.form()\n    if (!form.content.trim()) return\n\n    const editingId = this.editingFactId()\n    if (editingId) {\n      this.memoryFacts.update((prev) =>\n        prev.map((f) =>\n          f.id === editingId\n            ? {\n                ...f,\n                content: form.content,\n                category: form.category,\n                confidence: Number(form.confidence),\n                lastRecalled: 'Just now',\n              }\n            : f,\n        ),\n      )\n    } else {\n      const newId = `fact-${Date.now()}`\n      this.memoryFacts.update((prev) => [\n        {\n          id: newId,\n          content: form.content,\n          category: form.category,\n          confidence: Number(form.confidence),\n          lastRecalled: 'Just now',\n          recallsCount: 1,\n          sourceTurn: 'Manual Injection',\n          tags: [form.category.toLowerCase().replace(/\\s+/g, '-')],\n          isPinned: false,\n        },\n        ...prev,\n      ])\n    }\n\n    this.isAddingFact.set(false)\n    this.editingFactId.set(null)\n  }\n\n  cancelAddFact(): void {\n    this.isAddingFact.set(false)\n    this.editingFactId.set(null)\n  }\n\n  onContentInput(event: Event): void {\n    const content = (event.target as HTMLTextAreaElement).value\n    this.form.update((f) => ({ ...f, content }))\n  }\n\n  onCategoryChange(event: Event): void {\n    const category = (event.target as HTMLSelectElement).value as MemoryCategory\n    this.form.update((f) => ({ ...f, category }))\n  }\n\n  onConfidenceInput(event: Event): void {\n    const confidence = parseFloat((event.target as HTMLInputElement).value) || 0\n    this.form.update((f) => ({ ...f, confidence }))\n  }\n\n  onSearchInput(event: Event): void {\n    this.searchQuery.set((event.target as HTMLInputElement).value)\n  }\n\n  getCategoryVariant(category: MemoryCategory): BadgeVariant {\n    switch (category) {\n      case 'User Preference':\n        return 'default'\n      case 'Architecture Rule':\n        return 'secondary'\n      case 'System Constraint':\n        return 'outline'\n    }\n  }\n\n  filterClass(value: CategoryFilter): string {\n    return cn(\n      'rounded px-2.5 py-1 text-xs font-medium transition-colors',\n      this.selectedCategory() === value\n        ? 'bg-background text-foreground shadow-xs'\n        : 'text-muted-foreground hover:text-foreground',\n    )\n  }\n\n  starClass(fact: EpisodicMemory): string {\n    return cn('h-4 w-4', fact.isPinned ? 'fill-warning text-warning' : 'text-muted-foreground/40')\n  }\n\n  confidencePercent(confidence: number): string {\n    return (confidence * 100).toFixed(0)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/agent-memory-inspector/agent-memory-inspector.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/agent-memory-inspector/agent-context-buffer.component.ts",
      "content": "import { Component, EventEmitter, Input, Output, booleanAttribute, ChangeDetectionStrategy } from '@angular/core'\nimport { AlertCircle, CornerDownRight, LucideAngularModule } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiAvatarComponent, UiAvatarFallbackComponent } from '@/ui/avatar/avatar.component'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport type { MessageTurn } from './agent-memory-types'\n\n/**\n * Short-term context buffer tab of the agent memory inspector (React `AgentContextBuffer`):\n * token utilisation overview plus the sliding window of recent turns. Selecting a turn emits\n * `selectTurn`; the \"Restore Message Turns\" button of the wiped state emits `restore`.\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-agent-context-buffer, [ui-agent-context-buffer]',\n  standalone: true,\n  host: { class: 'contents' },\n  imports: [\n    LucideAngularModule,\n    UiAvatarComponent,\n    UiAvatarFallbackComponent,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiProgressComponent,\n  ],\n  template: `\n    <div class=\"space-y-4\">\n      <!-- Token Utilization Overview Card -->\n      <div ui-card class=\"border-border shadow-xs\">\n        <div ui-card-header class=\"p-5 pb-3\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div class=\"space-y-0.5\">\n              <div class=\"flex items-center gap-2\">\n                <h3 ui-card-title class=\"text-sm font-semibold\">Session Context Window Utilization</h3>\n                <span ui-badge variant=\"outline\" class=\"text-muted-foreground font-mono text-xs\">\n                  128k Model Window\n                </span>\n              </div>\n              <p ui-card-description class=\"text-xs\">\n                Active in-memory token allocation for the current autonomous execution session.\n              </p>\n            </div>\n\n            <div class=\"flex items-baseline gap-1.5 font-mono\">\n              <span class=\"text-foreground text-base font-bold\">{{ isWiped ? '0' : '6,420' }}</span>\n              <span class=\"text-muted-foreground text-xs\">/ 128,000 tokens</span>\n              <span ui-badge variant=\"secondary\" class=\"ml-1 font-mono text-xs font-semibold\">\n                {{ isWiped ? '0.0%' : '5.0%' }}\n              </span>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card-content class=\"space-y-4 p-5 pt-0\">\n          <!-- Progress Bar -->\n          <div ui-progress [value]=\"isWiped ? 0 : 5.0\" class=\"bg-muted h-2 w-full\"></div>\n\n          <!-- Detailed Token Allocation Breakdown Grid -->\n          <div class=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n            <div class=\"border-border/80 bg-card/60 rounded-lg border p-3\">\n              <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                <span>System Prompt</span>\n                <span class=\"text-foreground font-mono\">{{ isWiped ? '0' : '2,140' }}</span>\n              </div>\n              <div class=\"text-foreground mt-1 text-xs font-medium\">33.3% allocated</div>\n            </div>\n\n            <div class=\"border-border/80 bg-card/60 rounded-lg border p-3\">\n              <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                <span>Episodic Injections</span>\n                <span class=\"text-foreground font-mono\">{{ isWiped ? '0' : '1,850' }}</span>\n              </div>\n              <div class=\"text-foreground mt-1 text-xs font-medium\">28.8% allocated</div>\n            </div>\n\n            <div class=\"border-border/80 bg-card/60 rounded-lg border p-3\">\n              <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                <span>Message History</span>\n                <span class=\"text-foreground font-mono\">{{ isWiped ? '0' : '2,430' }}</span>\n              </div>\n              <div class=\"text-foreground mt-1 text-xs font-medium\">37.9% allocated</div>\n            </div>\n\n            <div class=\"border-border/80 bg-card/60 rounded-lg border p-3\">\n              <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                <span>Available Headroom</span>\n                <span class=\"text-success font-mono\">{{ isWiped ? '128,000' : '121,580' }}</span>\n              </div>\n              <div class=\"text-success mt-1 text-xs font-medium\">{{ isWiped ? '100% free' : '95.0% free' }}</div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Sliding Message Window Buffer (Recent Conversation Turns) -->\n      <div class=\"space-y-3\">\n        <div class=\"flex items-center justify-between px-1\">\n          <div class=\"flex items-center gap-2\">\n            <h3 class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n              Sliding Message Window Buffer\n            </h3>\n            <span ui-badge variant=\"outline\" class=\"font-mono text-xs\"\n              >FIFO Window: {{ turns.length }} Turns Active</span\n            >\n          </div>\n          <span class=\"text-muted-foreground text-xs\">Click turn to inspect vector payload</span>\n        </div>\n\n        @if (isWiped) {\n          <div class=\"border-border rounded-xl border border-dashed p-8 text-center\">\n            <lucide-icon [img]=\"AlertCircle\" class=\"text-muted-foreground/60 mx-auto h-8 w-8\" />\n            <h4 class=\"text-foreground mt-2 text-sm font-semibold\">Working Buffer Cleared</h4>\n            <p class=\"text-muted-foreground mt-1 text-xs\">\n              Working memory is empty. Start typing or restore the test buffer.\n            </p>\n            <button ui-button size=\"sm\" variant=\"outline\" class=\"mt-3 text-xs\" (click)=\"restore.emit()\">\n              Restore Message Turns\n            </button>\n          </div>\n        } @else {\n          <div class=\"space-y-3\">\n            @for (turn of turns; track turn.id) {\n              <div\n                role=\"button\"\n                tabindex=\"0\"\n                [attr.aria-pressed]=\"selectedTurnId === turn.id\"\n                [class]=\"turnClass(turn)\"\n                (click)=\"selectTurn.emit(turn.id)\"\n                (keydown)=\"onTurnKeydown($event, turn)\"\n              >\n                <!-- Turn Header -->\n                <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n                  <div class=\"flex items-center gap-3\">\n                    <span ui-avatar class=\"border-border bg-muted h-7 w-7 rounded-md border\">\n                      <span ui-avatar-fallback [class]=\"avatarFallbackClass(turn)\">{{ turn.avatarText }}</span>\n                    </span>\n                    <div>\n                      <div class=\"flex items-center gap-2\">\n                        <span class=\"text-foreground text-xs font-semibold\">{{ turn.authorName }}</span>\n                        <span ui-badge variant=\"outline\" class=\"text-muted-foreground font-mono text-xs\">\n                          Turn #{{ turn.turnNumber }}\n                        </span>\n                        <span class=\"text-muted-foreground text-xs\">{{ turn.timestamp }}</span>\n                      </div>\n                    </div>\n                  </div>\n\n                  <div class=\"flex items-center gap-2\">\n                    <span ui-badge variant=\"secondary\" [class]=\"importanceClass(turn)\">\n                      {{ turn.importanceLevel }} ({{ percent(turn.importanceScore) }}%)\n                    </span>\n                    <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">{{ turn.tokens }} tok</span>\n                  </div>\n                </div>\n\n                <!-- Message Text -->\n                <p class=\"text-foreground/90 mt-2.5 font-mono text-xs leading-relaxed\">{{ turn.content }}</p>\n\n                <!-- Extracted Facts & Embedding Preview -->\n                @if (turn.extractedFacts.length > 0) {\n                  <div class=\"border-border/60 bg-muted/40 mt-3 rounded-lg border p-2.5\">\n                    <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs font-medium\">\n                      <lucide-icon [img]=\"CornerDownRight\" class=\"h-3 w-3\" />\n                      <span>Extracted Persistent Declarations:</span>\n                    </div>\n                    <ul class=\"mt-1 space-y-1\">\n                      @for (f of turn.extractedFacts; track $index) {\n                        <li class=\"text-foreground flex items-center gap-2 text-xs\">\n                          <span class=\"bg-primary inline-block h-1 w-1 rounded-full\"></span>\n                          <span>{{ f }}</span>\n                        </li>\n                      }\n                    </ul>\n                  </div>\n                }\n              </div>\n            }\n          </div>\n        }\n      </div>\n    </div>\n  `,\n})\nexport class UiAgentContextBufferComponent {\n  protected readonly AlertCircle = AlertCircle\n  protected readonly CornerDownRight = CornerDownRight\n\n  @Input({ transform: booleanAttribute }) isWiped = false\n  @Input() turns: MessageTurn[] = []\n  @Input() selectedTurnId = ''\n  @Output() readonly selectTurn = new EventEmitter<string>()\n  @Output() readonly restore = new EventEmitter<void>()\n\n  turnClass(turn: MessageTurn): string {\n    return cn(\n      'group bg-card hover:border-primary/40 focus-visible:ring-ring relative cursor-pointer rounded-xl border p-4.5 transition-colors hover:shadow-xs focus-visible:ring-2 focus-visible:outline-none',\n      this.selectedTurnId === turn.id ? 'border-primary/60 bg-accent/20 ring-primary/30 ring-1' : 'border-border',\n    )\n  }\n\n  avatarFallbackClass(turn: MessageTurn): string {\n    return cn(\n      'text-xs font-bold',\n      turn.role === 'assistant' ? 'bg-primary/10 text-primary' : 'bg-success/10 text-success',\n    )\n  }\n\n  importanceClass(turn: MessageTurn): string {\n    return cn(\n      'font-mono text-xs',\n      turn.importanceLevel === 'Critical' && 'bg-destructive/10 text-destructive',\n      turn.importanceLevel === 'High' && 'bg-warning/10 text-warning',\n      turn.importanceLevel === 'Action Item' && 'bg-info/10 text-info',\n    )\n  }\n\n  percent(score: number): number {\n    return Math.round(score * 100)\n  }\n\n  onTurnKeydown(event: KeyboardEvent, turn: MessageTurn): void {\n    if (event.key === 'Enter' || event.key === ' ') {\n      event.preventDefault()\n      this.selectTurn.emit(turn.id)\n    }\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/agent-memory-inspector/agent-context-buffer.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/agent-memory-inspector/agent-entity-graph.component.ts",
      "content": "import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from '@angular/core'\nimport { ArrowRight, Database, LucideAngularModule, Network } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\nimport type { EntityNode, GraphTriplet } from './agent-memory-types'\n\n/**\n * Entity knowledge graph tab of the agent memory inspector (React `AgentEntityGraph`):\n * node selector, the selected node's connected triplets, and the full triplet table.\n * Clicking a node emits `selectNode` with its id.\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-agent-entity-graph, [ui-agent-entity-graph]',\n  standalone: true,\n  host: { class: 'contents' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiProgressComponent,\n    UiTableComponent,\n    UiTableHeaderComponent,\n    UiTableBodyComponent,\n    UiTableRowComponent,\n    UiTableHeadComponent,\n    UiTableCellComponent,\n  ],\n  template: `\n    <div class=\"space-y-4\">\n      <!-- Top Row: Active Graph Topology Summary -->\n      <div class=\"grid grid-cols-1 gap-4 lg:grid-cols-3\">\n        <!-- Node Selector Card -->\n        <div ui-card class=\"border-border shadow-xs lg:col-span-1\">\n          <div ui-card-header class=\"p-4 pb-2\">\n            <div class=\"flex items-center justify-between\">\n              <h3 ui-card-title class=\"text-xs font-semibold\">Entity Nodes ({{ nodes.length }})</h3>\n              <span ui-badge variant=\"outline\" class=\"text-xs font-normal\">Active Subgraph</span>\n            </div>\n            <p ui-card-description class=\"text-xs\">Select node to inspect relational edges</p>\n          </div>\n          <div ui-card-content class=\"space-y-1.5 p-4 pt-0\">\n            @for (node of nodes; track node.id) {\n              <button type=\"button\" [class]=\"nodeClass(node)\" (click)=\"selectNode.emit(node.id)\">\n                <div class=\"flex items-center justify-between\">\n                  <span class=\"text-foreground font-semibold\">{{ node.label }}</span>\n                  <span ui-badge variant=\"secondary\" class=\"h-4.5 px-1.5 text-xs\">{{ node.entityType }}</span>\n                </div>\n                <p class=\"text-muted-foreground mt-1 line-clamp-1 text-xs\">{{ node.description }}</p>\n                <div class=\"text-muted-foreground mt-1.5 flex items-center gap-3 text-xs\">\n                  <span>Degree: {{ node.degree }} edges</span>\n                  <span>·</span>\n                  <span class=\"text-success font-mono\">Status: {{ node.status }}</span>\n                </div>\n              </button>\n            }\n          </div>\n        </div>\n\n        <!-- Selected Node Semantic Deep Dive -->\n        @if (selectedNode; as node) {\n          <div ui-card class=\"border-border shadow-xs lg:col-span-2\">\n            <div ui-card-header class=\"p-4 pb-2\">\n              <div class=\"flex items-center justify-between\">\n                <div class=\"flex items-center gap-2\">\n                  <lucide-icon [img]=\"Network\" class=\"text-primary h-4 w-4\" />\n                  <h3 ui-card-title class=\"text-sm font-semibold\">{{ node.label }}</h3>\n                  <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">{{ node.entityType }}</span>\n                </div>\n                <span ui-badge variant=\"secondary\" class=\"font-mono text-xs\">Degree {{ node.degree }}</span>\n              </div>\n              <p ui-card-description class=\"text-xs\">{{ node.description }}</p>\n            </div>\n            <div ui-card-content class=\"space-y-4 p-4 pt-2\">\n              <!-- Embedding Reference -->\n              <div\n                class=\"border-border/60 bg-muted/40 flex items-center justify-between rounded-lg border p-2.5 text-xs\"\n              >\n                <div class=\"flex items-center gap-2\">\n                  <lucide-icon [img]=\"Database\" class=\"text-muted-foreground h-3.5 w-3.5\" />\n                  <span class=\"text-muted-foreground\">Vector Index ID:</span>\n                  <span class=\"text-foreground font-mono font-medium\">{{ node.embeddingId }}</span>\n                </div>\n                <span class=\"text-success font-mono text-xs\">Cosine Cos: 0.962</span>\n              </div>\n\n              <!-- Associated Triplet Edges -->\n              <div class=\"space-y-2\">\n                <span class=\"text-foreground text-xs font-semibold\">\n                  Connected Graph Triplets ({{ filteredTriplets.length }})\n                </span>\n                <div class=\"space-y-2\">\n                  @for (trip of filteredTriplets; track trip.id) {\n                    <div\n                      class=\"border-border bg-card flex flex-col gap-2 rounded-lg border p-3 sm:flex-row sm:items-center sm:justify-between\"\n                    >\n                      <div class=\"flex flex-wrap items-center gap-2 text-xs\">\n                        <span class=\"text-foreground font-semibold\">{{ trip.subject }}</span>\n                        <span ui-badge variant=\"outline\" class=\"text-warning h-5 px-1.5 font-mono text-xs font-bold\">\n                          {{ trip.predicate }}\n                        </span>\n                        <lucide-icon [img]=\"ArrowRight\" class=\"text-muted-foreground h-3 w-3\" />\n                        <span class=\"text-foreground font-semibold\">{{ trip.object }}</span>\n                      </div>\n                      <div class=\"flex items-center gap-3 text-xs\">\n                        <span class=\"text-muted-foreground font-mono text-xs\">Weight: {{ trip.weight }}</span>\n                        <span ui-badge variant=\"secondary\" class=\"font-mono text-xs\">\n                          {{ percent(trip.confidence) }}% conf\n                        </span>\n                        <span class=\"text-muted-foreground text-xs\">{{ trip.lastTraversed }}</span>\n                      </div>\n                    </div>\n                  }\n                </div>\n              </div>\n            </div>\n          </div>\n        }\n      </div>\n\n      <!-- Complete Graph Relations Table -->\n      <div ui-card class=\"border-border shadow-xs\">\n        <div ui-card-header class=\"p-5 pb-3\">\n          <div class=\"flex items-center justify-between\">\n            <div>\n              <h3 ui-card-title class=\"text-sm font-semibold\">Semantic Graph Triplets</h3>\n              <p ui-card-description class=\"text-xs\">\n                Subject-Predicate-Object directional triples stored in Neo4j / GraphRAG engine.\n              </p>\n            </div>\n            <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">{{ triplets.length }} Total Triplets</span>\n          </div>\n        </div>\n        <div ui-card-content class=\"p-0\">\n          <div ui-table>\n            <thead ui-table-header>\n              <tr ui-table-row class=\"hover:bg-transparent\">\n                <th ui-table-head class=\"text-xs font-semibold\">Subject</th>\n                <th ui-table-head class=\"text-xs font-semibold\">Predicate</th>\n                <th ui-table-head class=\"text-xs font-semibold\">Object</th>\n                <th ui-table-head class=\"text-xs font-semibold\">Confidence</th>\n                <th ui-table-head class=\"text-xs font-semibold\">Weight</th>\n                <th ui-table-head class=\"text-right text-xs font-semibold\">Last Traversed</th>\n              </tr>\n            </thead>\n            <tbody ui-table-body>\n              @for (trip of triplets; track trip.id) {\n                <tr ui-table-row class=\"text-xs\">\n                  <td ui-table-cell class=\"font-medium\">\n                    <div class=\"flex items-center gap-1.5\">\n                      <span class=\"text-foreground font-semibold\">{{ trip.subject }}</span>\n                      <span class=\"text-muted-foreground text-xs\">({{ trip.subjectType }})</span>\n                    </div>\n                  </td>\n                  <td ui-table-cell>\n                    <span ui-badge variant=\"outline\" class=\"text-warning font-mono text-xs font-bold\">\n                      {{ trip.predicate }}\n                    </span>\n                  </td>\n                  <td ui-table-cell class=\"font-medium\">\n                    <div class=\"flex items-center gap-1.5\">\n                      <span class=\"text-foreground font-semibold\">{{ trip.object }}</span>\n                      <span class=\"text-muted-foreground text-xs\">({{ trip.objectType }})</span>\n                    </div>\n                  </td>\n                  <td ui-table-cell>\n                    <div class=\"flex items-center gap-2\">\n                      <div ui-progress [value]=\"trip.confidence * 100\" class=\"h-1.5 w-12\"></div>\n                      <span class=\"font-mono text-xs\">{{ percent(trip.confidence) }}%</span>\n                    </div>\n                  </td>\n                  <td ui-table-cell class=\"font-mono text-xs\">{{ trip.weight }}</td>\n                  <td ui-table-cell class=\"text-muted-foreground text-right text-xs\">{{ trip.lastTraversed }}</td>\n                </tr>\n              }\n            </tbody>\n          </div>\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiAgentEntityGraphComponent {\n  protected readonly ArrowRight = ArrowRight\n  protected readonly Database = Database\n  protected readonly Network = Network\n\n  @Input() triplets: GraphTriplet[] = []\n  @Input() nodes: EntityNode[] = []\n  @Input() selectedNodeId = ''\n  @Output() readonly selectNode = new EventEmitter<string>()\n\n  get selectedNode(): EntityNode | undefined {\n    return this.nodes.find((n) => n.id === this.selectedNodeId) || this.nodes[0]\n  }\n\n  get filteredTriplets(): GraphTriplet[] {\n    const node = this.selectedNode\n    if (!node) return this.triplets\n    return this.triplets.filter((t) => t.subject === node.label || t.object === node.label)\n  }\n\n  nodeClass(node: EntityNode): string {\n    return cn(\n      'w-full cursor-pointer rounded-lg border p-2.5 text-left text-xs transition-colors',\n      this.selectedNodeId === node.id\n        ? 'bg-primary/10 border-primary/30 text-foreground font-medium shadow-xs'\n        : 'bg-muted/30 hover:bg-muted/60 text-muted-foreground hover:text-foreground border-transparent',\n    )\n  }\n\n  percent(value: number): number {\n    return Math.round(value * 100)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/agent-memory-inspector/agent-entity-graph.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/agent-memory-inspector/agent-memory-types.ts",
      "content": "export type MemoryCategory = 'User Preference' | 'Architecture Rule' | 'System Constraint'\n\nexport interface EpisodicMemory {\n  id: string\n  content: string\n  category: MemoryCategory\n  confidence: number\n  lastRecalled: string\n  recallsCount: number\n  sourceTurn: string\n  tags: string[]\n  isPinned: boolean\n}\n\nexport interface MessageTurn {\n  id: string\n  turnNumber: number\n  role: 'user' | 'assistant'\n  authorName: string\n  avatarText: string\n  timestamp: string\n  importanceScore: number\n  importanceLevel: 'Critical' | 'High' | 'Standard' | 'Action Item'\n  tokens: number\n  content: string\n  extractedFacts: string[]\n  embeddingHash: string\n}\n\nexport interface EntityNode {\n  id: string\n  label: string\n  entityType: 'Person' | 'Repository' | 'CSS Engine' | 'Design System' | 'Framework' | 'Standard'\n  description: string\n  degree: number\n  status: 'active' | 'synced' | 'cached'\n  embeddingId: string\n}\n\nexport interface GraphTriplet {\n  id: string\n  subject: string\n  subjectType: string\n  predicate: 'MAINTAINS' | 'USES' | 'CONFIGURES' | 'IMPLEMENTS' | 'MIRRORS' | 'ENFORCES'\n  object: string\n  objectType: string\n  confidence: number\n  weight: string\n  lastTraversed: string\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/agent-memory-inspector/agent-memory-types.ts"
    },
    {
      "path": "packages/registry-angular/blocks/agent-memory-inspector/agent-memory-data.ts",
      "content": "import type { EpisodicMemory, MessageTurn, EntityNode, GraphTriplet } from './agent-memory-types'\n\nexport const INITIAL_MEMORY_FACTS: EpisodicMemory[] = [\n  {\n    id: 'fact-1',\n    content: 'User prefers Vue 3.5 SFC with <script setup lang=\"ts\">',\n    category: 'User Preference',\n    confidence: 0.98,\n    lastRecalled: '2m ago',\n    recallsCount: 42,\n    sourceTurn: 'Turn #1 (Workspace Init)',\n    tags: ['vue3', 'sfc', 'typescript'],\n    isPinned: true,\n  },\n  {\n    id: 'fact-2',\n    content: 'User repository uses Tailwind v4 with OKLCH theme tokens',\n    category: 'Architecture Rule',\n    confidence: 0.95,\n    lastRecalled: '14m ago',\n    recallsCount: 89,\n    sourceTurn: 'Turn #3 (CSS System)',\n    tags: ['tailwind4', 'oklch', 'tokens'],\n    isPinned: true,\n  },\n  {\n    id: 'fact-3',\n    content: 'User enforces strict 120-character printWidth in Prettier',\n    category: 'System Constraint',\n    confidence: 0.99,\n    lastRecalled: '1h ago',\n    recallsCount: 126,\n    sourceTurn: 'Turn #1 (Code Standards)',\n    tags: ['prettier', 'formatting'],\n    isPinned: false,\n  },\n  {\n    id: 'fact-4',\n    content: 'Company domain is uipkge.dev',\n    category: 'System Constraint',\n    confidence: 0.97,\n    lastRecalled: '3h ago',\n    recallsCount: 31,\n    sourceTurn: 'Turn #3 (Domain Policy)',\n    tags: ['domain', 'hosting'],\n    isPinned: false,\n  },\n  {\n    id: 'fact-5',\n    content: 'Never publish to npm; components distributed as unbundled raw source registries',\n    category: 'Architecture Rule',\n    confidence: 0.96,\n    lastRecalled: '4h ago',\n    recallsCount: 67,\n    sourceTurn: 'Turn #2 (Architecture Rules)',\n    tags: ['no-npm', 'shadcn', 'registry'],\n    isPinned: true,\n  },\n]\n\n// Message Window Buffer\n\nexport const INITIAL_MESSAGE_TURNS: MessageTurn[] = [\n  {\n    id: 'turn-1',\n    turnNumber: 1,\n    role: 'user',\n    authorName: 'Elena Rostova (Lead Architect)',\n    avatarText: 'ER',\n    timestamp: '12m ago',\n    importanceScore: 0.94,\n    importanceLevel: 'Critical',\n    tokens: 142,\n    content:\n      'We are configuring the UIPKGE monorepo for Vue 3.5 and React 19. All Vue components must use <script setup lang=\"ts\"> and strict 120-character printWidth in Prettier. Do not output semicolons.',\n    extractedFacts: ['User prefers Vue 3.5 SFC', '120-char printWidth enforced'],\n    embeddingHash: '0x7f8a91c4',\n  },\n  {\n    id: 'turn-2',\n    turnNumber: 2,\n    role: 'assistant',\n    authorName: 'Senior Engineering Co-Pilot',\n    avatarText: 'AI',\n    timestamp: '11m ago',\n    importanceScore: 0.78,\n    importanceLevel: 'Standard',\n    tokens: 512,\n    content:\n      'Understood. I have recorded the formatting rules (no semicolons, single quotes, 120 width) and dual-framework targets. All component scaffolding will adhere strictly to Vue 3.5 script setup standards and OKLCH color token architecture.',\n    extractedFacts: ['Single-quote formatting indexed', 'Vue 3.5 + React dual pipeline'],\n    embeddingHash: '0x3b1d84e2',\n  },\n  {\n    id: 'turn-3',\n    turnNumber: 3,\n    role: 'user',\n    authorName: 'Elena Rostova (Lead Architect)',\n    avatarText: 'ER',\n    timestamp: '4m ago',\n    importanceScore: 0.98,\n    importanceLevel: 'High',\n    tokens: 286,\n    content:\n      'Remember that company domain is uipkge.dev and we do NOT publish npm packages. Components are distributed directly as unbundled registry JSON files via shadcn CLI. Tailwind v4 with OKLCH theme tokens must be used across all blocks.',\n    extractedFacts: ['Company domain is uipkge.dev', 'Zero npm publishing policy', 'Tailwind v4 OKLCH token model'],\n    embeddingHash: '0x92e4ca10',\n  },\n  {\n    id: 'turn-4',\n    turnNumber: 4,\n    role: 'assistant',\n    authorName: 'Senior Engineering Co-Pilot',\n    avatarText: 'AI',\n    timestamp: 'Just now',\n    importanceScore: 0.91,\n    importanceLevel: 'Action Item',\n    tokens: 1490,\n    content:\n      'Memory updated. Synced \"uipkge.dev\" and registry-first unbundled distribution architecture into Mem0 vector collection and Neo4j dependency graph. Short-term context buffer is currently utilizing 6,420 / 128,000 tokens (5.0%). Ready for task execution.',\n    extractedFacts: ['Neo4j triplets linked', 'Mem0 vector index synced'],\n    embeddingHash: '0x48c71bf9',\n  },\n]\n\n// Entity Knowledge Graph Nodes & Triplets\n\nexport const INITIAL_ENTITY_NODES: EntityNode[] = [\n  {\n    id: 'node-1',\n    label: 'Elena Rostova',\n    entityType: 'Person',\n    description: 'Lead Maintainer & Core Architect',\n    degree: 2,\n    status: 'active',\n    embeddingId: 'emb_981a',\n  },\n  {\n    id: 'node-2',\n    label: 'uipkge-ui',\n    entityType: 'Repository',\n    description: 'Dual-Framework UI Registry Monorepo',\n    degree: 5,\n    status: 'active',\n    embeddingId: 'emb_432b',\n  },\n  {\n    id: 'node-3',\n    label: 'Tailwind v4',\n    entityType: 'CSS Engine',\n    description: 'CSS-first @theme inline styling layer',\n    degree: 2,\n    status: 'synced',\n    embeddingId: 'emb_771c',\n  },\n  {\n    id: 'node-4',\n    label: 'OKLCH Tokens',\n    entityType: 'Design System',\n    description: 'Perceptually uniform color model palette',\n    degree: 1,\n    status: 'synced',\n    embeddingId: 'emb_118d',\n  },\n  {\n    id: 'node-5',\n    label: 'Vue 3.5 SFC',\n    entityType: 'Framework',\n    description: 'Primary component authoring standard',\n    degree: 1,\n    status: 'active',\n    embeddingId: 'emb_554e',\n  },\n  {\n    id: 'node-6',\n    label: 'React 19 Components',\n    entityType: 'Framework',\n    description: 'Headless mirror registry implementation',\n    degree: 1,\n    status: 'active',\n    embeddingId: 'emb_229f',\n  },\n  {\n    id: 'node-7',\n    label: '120-char printWidth',\n    entityType: 'Standard',\n    description: 'Prettier wrap limit constraint',\n    degree: 1,\n    status: 'cached',\n    embeddingId: 'emb_883g',\n  },\n]\n\nexport const INITIAL_GRAPH_TRIPLETS: GraphTriplet[] = [\n  {\n    id: 'trip-1',\n    subject: 'Elena Rostova',\n    subjectType: 'Person',\n    predicate: 'MAINTAINS',\n    object: 'uipkge-ui',\n    objectType: 'Repository',\n    confidence: 0.99,\n    weight: '1.00',\n    lastTraversed: '12s ago',\n  },\n  {\n    id: 'trip-2',\n    subject: 'uipkge-ui',\n    subjectType: 'Repository',\n    predicate: 'USES',\n    object: 'Tailwind v4',\n    objectType: 'CSS Engine',\n    confidence: 0.98,\n    weight: '0.96',\n    lastTraversed: '45s ago',\n  },\n  {\n    id: 'trip-3',\n    subject: 'Tailwind v4',\n    subjectType: 'CSS Engine',\n    predicate: 'CONFIGURES',\n    object: 'OKLCH Tokens',\n    objectType: 'Design System',\n    confidence: 0.97,\n    weight: '0.94',\n    lastTraversed: '2m ago',\n  },\n  {\n    id: 'trip-4',\n    subject: 'uipkge-ui',\n    subjectType: 'Repository',\n    predicate: 'IMPLEMENTS',\n    object: 'Vue 3.5 SFC',\n    objectType: 'Framework',\n    confidence: 0.99,\n    weight: '0.98',\n    lastTraversed: '1m ago',\n  },\n  {\n    id: 'trip-5',\n    subject: 'uipkge-ui',\n    subjectType: 'Repository',\n    predicate: 'MIRRORS',\n    object: 'React 19 Components',\n    objectType: 'Framework',\n    confidence: 0.96,\n    weight: '0.91',\n    lastTraversed: '3m ago',\n  },\n  {\n    id: 'trip-6',\n    subject: 'Elena Rostova',\n    subjectType: 'Person',\n    predicate: 'ENFORCES',\n    object: '120-char printWidth',\n    objectType: 'Standard',\n    confidence: 0.95,\n    weight: '0.89',\n    lastTraversed: '5m ago',\n  },\n]\n\n// UI Controls State\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/agent-memory-inspector/agent-memory-data.ts"
    },
    {
      "path": "packages/registry-angular/blocks/agent-memory-inspector/index.ts",
      "content": "export {\n  UiAgentMemoryInspectorComponent,\n  type EpisodicMemory,\n  type MessageTurn,\n  type EntityNode,\n  type GraphTriplet,\n  type MemoryCategory,\n} from './agent-memory-inspector.component'\nexport { UiAgentContextBufferComponent } from './agent-context-buffer.component'\nexport { UiAgentEntityGraphComponent } from './agent-entity-graph.component'\nexport {\n  INITIAL_MEMORY_FACTS,\n  INITIAL_MESSAGE_TURNS,\n  INITIAL_ENTITY_NODES,\n  INITIAL_GRAPH_TRIPLETS,\n} from './agent-memory-data'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/agent-memory-inspector/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/avatar.json",
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/progress.json",
    "https://uipkge.dev/r/angular/table.json",
    "https://uipkge.dev/r/angular/tabs.json"
  ],
  "description": "Autonomous AI agent memory inspector featuring short-term context buffer utilization, long-term episodic vector memories with confidence scoring, and Neo4j-style entity relationship knowledge graph.",
  "categories": [
    "ai",
    "app"
  ]
}