{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "rag-pipeline-visualizer",
  "title": "Rag Pipeline Visualizer",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/rag-pipeline-visualizer/RagPipelineVisualizer.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  BookOpen,\n  Bot,\n  Check,\n  ChevronRight,\n  Code2,\n  Copy,\n  Cpu,\n  Database,\n  FileCode,\n  Filter,\n  Layers,\n  Play,\n  RefreshCw,\n  Search,\n  ShieldCheck,\n  SlidersHorizontal,\n  Sparkles,\n  Terminal,\n  ThumbsDown,\n  ThumbsUp,\n  Workflow,\n  Zap,\n} from 'lucide-vue-next'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Progress } from '@/components/ui/progress'\nimport { Separator } from '@/components/ui/separator'\nimport { Slider } from '@/components/ui/slider'\nimport { Switch } from '@/components/ui/switch'\nimport { cn } from '@/lib/utils'\n\ninterface Props {\n  class?: HTMLAttributes['class']\n}\n\ndefineProps<Props>()\n\ninterface PipelineStage {\n  id: number\n  name: string\n  subtitle: string\n  latency: string\n  durationMs: number\n  status: 'completed' | 'active' | 'queued' | 'bypassed'\n  icon: any\n  tag: string\n  details: {\n    description: string\n    metrics: { label: string; value: string }[]\n    codeOrData?: { title: string; content: string }\n  }\n}\n\ninterface RetrievedChunk {\n  id: string\n  citationIndex: number\n  relevanceScore: number\n  rerankBoost: number\n  cosineScore: number\n  bm25Score: number\n  documentPath: string\n  namespace: string\n  chunkOffset: string\n  tokenCount: number\n  updatedAgo: string\n  title: string\n  snippetPrefix: string\n  highlightedText: string\n  snippetSuffix: string\n  fullSnippet: string\n}\n\n// Preset Queries\nconst presetQueries = [\n  'How do I configure OKLCH color palettes in Tailwind v4 with UIPKGE?',\n  'Cross-Encoder vs Bi-Encoder reranker score calibration',\n  'HyDE prompt expansion for zero-shot semantic retrieval',\n  'Pinecone HNSW index tuning: efSearch & M parameter tradeoffs',\n]\n\nconst currentQuery = ref('How do I configure OKLCH color palettes in Tailwind v4 with UIPKGE?')\nconst topK = ref(3)\nconst rerankerEnabled = ref(true)\nconst selectedStageId = ref<number>(3)\nconst isExecuting = ref(false)\nconst copiedChunkId = ref<string | null>(null)\nconst copiedResponse = ref(false)\nconst copiedTrace = ref(false)\nconst activeCitationHover = ref<number | null>(null)\nconst showTraceJson = ref(false)\nconst userFeedback = ref<'up' | 'down' | null>(null)\n\n// 5-Stage Architecture Flow Data\nconst stages = computed<PipelineStage[]>(() => [\n  {\n    id: 1,\n    name: '1. User Query & HyDE Expansion',\n    subtitle: 'Query rewritten with hypothetical document embedding · 42ms',\n    latency: '42ms',\n    durationMs: 42,\n    status: 'completed',\n    icon: Sparkles,\n    tag: 'Prompt Rewriting',\n    details: {\n      description:\n        'Generates a synthetic hypothetical answer using Claude 3.5 Haiku to bridge vocabulary mismatch between conversational queries and technical documentation.',\n      metrics: [\n        { label: 'Expansion Model', value: 'Claude 3.5 Haiku' },\n        { label: 'Latency', value: '42ms' },\n        { label: 'Prompt Tokens', value: '48 tokens' },\n        { label: 'Hypothesis Length', value: '112 tokens' },\n      ],\n      codeOrData: {\n        title: 'Generated Hypothetical Document (HyDE)',\n        content:\n          'Tailwind CSS v4 defines color tokens using CSS variables inside `@theme inline` with `oklch(L C H)` functions. In dual-framework component registries like UIPKGE, OKLCH ensures uniform perceptual lightness across hue shifts in light and dark variants without breaking WCAG AA contrast.',\n      },\n    },\n  },\n  {\n    id: 2,\n    name: '2. Hybrid Dense + Sparse Search',\n    subtitle: 'Dense Cosine + BM25 Lexical search across 480k chunks · 64ms',\n    latency: '64ms',\n    durationMs: 64,\n    status: 'completed',\n    icon: Database,\n    tag: 'Reciprocal Rank Fusion',\n    details: {\n      description:\n        'Performs vector similarity search on 1536-dim embeddings combined with sparse BM25 keyword matching across 482,910 document chunks.',\n      metrics: [\n        { label: 'Vector Index', value: 'Pinecone Serverless (HNSW)' },\n        { label: 'Dimension', value: '1536-dim (text-embedding-3-small)' },\n        { label: 'Fusion Weight', value: 'α = 0.70 Dense + 0.30 Sparse' },\n        { label: 'Candidate Pool', value: '20 Candidate Chunks' },\n      ],\n      codeOrData: {\n        title: 'Dense Vector Projection (32-float slice)',\n        content:\n          '[-0.048, 0.135, 0.092, -0.018, 0.245, -0.110, 0.049, 0.174, -0.082, 0.001, 0.325, -0.059, 0.097, 0.191, -0.149, 0.068, -0.024, 0.212, 0.082, -0.094, 0.121, -0.037, 0.156, 0.031, -0.172, 0.099, 0.056, -0.078, 0.195, -0.013, 0.072, 0.141]',\n      },\n    },\n  },\n  {\n    id: 3,\n    name: '3. Cross-Encoder Reranker',\n    subtitle: rerankerEnabled.value\n      ? 'Cohere Rerank v3: re-scores Top 20 -> Top 3 · 28ms'\n      : 'Bypassed (Using raw hybrid search ranking) · 0ms',\n    latency: rerankerEnabled.value ? '28ms' : '0ms',\n    durationMs: rerankerEnabled.value ? 28 : 0,\n    status: rerankerEnabled.value ? 'completed' : 'bypassed',\n    icon: Filter,\n    tag: rerankerEnabled.value ? 'Cross-Attention Re-Scoring' : 'Bypassed',\n    details: {\n      description: rerankerEnabled.value\n        ? 'Applies deep transformer cross-attention to score query-document pairs simultaneously, eliminating false-positive semantic matches.'\n        : 'Reranker is currently bypassed. Chunks are ordered purely by initial hybrid reciprocal rank scores.',\n      metrics: [\n        { label: 'Model', value: 'cohere-rerank-v3.0-multilingual' },\n        { label: 'Top-K Retained', value: `Top ${topK.value} of 20` },\n        { label: 'Relevance Cutoff', value: '≥ 0.800 score' },\n        { label: 'Max Rank Shift', value: '+3 positions (Chunk #3)' },\n      ],\n      codeOrData: {\n        title: 'Reranker Score Calibration Delta',\n        content:\n          'Chunk #1: 0.800 (Cosine) -> 0.942 (Rerank)  [+0.142 boost]\\nChunk #2: 0.792 (Cosine) -> 0.887 (Rerank)  [+0.095 boost]\\nChunk #3: 0.776 (Cosine) -> 0.824 (Rerank)  [+0.048 boost]\\n17 candidates pruned below 0.800 relevance threshold',\n      },\n    },\n  },\n  {\n    id: 4,\n    name: '4. Context Window Assembly',\n    subtitle: '1,248 tokens packed, 98% prompt density · 8ms',\n    latency: '8ms',\n    durationMs: 8,\n    status: 'completed',\n    icon: Layers,\n    tag: 'Token Packaging',\n    details: {\n      description:\n        'Deduplicates overlapping chunk boundaries, injects citation boundary anchors `[1]`, `[2]`, `[3]`, and formats system directives for zero-hallucination grounding.',\n      metrics: [\n        { label: 'Window Budget', value: '1,248 / 8,192 tokens (15.2%)' },\n        { label: 'Prompt Density', value: '98.4% relevance tokens' },\n        { label: 'Chunks Packaged', value: `${Math.min(topK.value, 3)} chunks` },\n        { label: 'Delimiter Format', value: '<context_document_id>' },\n      ],\n      codeOrData: {\n        title: 'Assembled Prompt Context Envelope',\n        content:\n          '<system>\\nYou are a Lead Design Systems Architect. Synthesize answers strictly from provided context chunks.\\nAlways ground every technical claim with an inline citation key [1], [2], or [3].\\n</system>\\n\\n<context>\\n[1] doc: docs/styling/tailwind-v4-oklch.md (score: 0.942)\\n[2] doc: docs/tokens/color-derivation.md (score: 0.887)\\n[3] doc: blog/2026/design-systems-monorepo.md (score: 0.824)\\n</context>',\n      },\n    },\n  },\n  {\n    id: 5,\n    name: '5. LLM Synthesis & Grounding',\n    subtitle: 'Claude 3.5 Sonnet streaming generation · 820ms',\n    latency: '820ms',\n    durationMs: 820,\n    status: 'completed',\n    icon: Bot,\n    tag: 'Streaming Synthesis',\n    details: {\n      description:\n        'Generates final structured markdown answer with streaming tokens, verifies every claim against citation sources, and produces grounded output.',\n      metrics: [\n        { label: 'Model', value: 'claude-3-5-sonnet-20241022' },\n        { label: 'Time to First Token', value: '180ms' },\n        { label: 'Generation Speed', value: '68.2 tokens/sec' },\n        { label: 'Grounding Verification', value: '100% (3/3 facts grounded)' },\n      ],\n      codeOrData: {\n        title: 'Telemetry & Cost Summary',\n        content:\n          'Prompt Tokens: 1,248 ($0.00374)\\nCompletion Tokens: 214 ($0.00064)\\nTotal Cost: $0.00438\\nHallucination Detection: 0 violations detected',\n      },\n    },\n  },\n])\n\n// Retrieved Context Chunks (Top-K)\nconst allChunks: RetrievedChunk[] = [\n  {\n    id: 'chunk-1',\n    citationIndex: 1,\n    relevanceScore: 0.942,\n    rerankBoost: 0.142,\n    cosineScore: 0.8,\n    bm25Score: 0.785,\n    documentPath: 'docs/styling/tailwind-v4-oklch.md',\n    namespace: 'docs',\n    chunkOffset: 'Chunk #3 · Lines 42–78',\n    tokenCount: 384,\n    updatedAgo: '2 hours ago',\n    title: 'Tailwind v4 OKLCH Architecture & @theme Configuration',\n    snippetPrefix: 'Tailwind CSS v4 introduces native CSS-first token configuration with ',\n    highlightedText:\n      '@theme inline and OKLCH color spaces. In contrast to RGB/HSL, OKLCH ensures perceptually uniform lightness across hues',\n    snippetSuffix:\n      ', preventing contrast degradation in dark mode variants while preserving single-source token truth.',\n    fullSnippet:\n      'Tailwind CSS v4 introduces native CSS-first token configuration with `@theme inline` and OKLCH color spaces. In contrast to RGB/HSL, OKLCH ensures perceptually uniform lightness across hues, preventing contrast degradation in dark mode variants while preserving single-source token truth.',\n  },\n  {\n    id: 'chunk-2',\n    citationIndex: 2,\n    relevanceScore: 0.887,\n    rerankBoost: 0.095,\n    cosineScore: 0.792,\n    bm25Score: 0.71,\n    documentPath: 'docs/tokens/color-derivation.md',\n    namespace: 'docs',\n    chunkOffset: 'Chunk #1 · Lines 1–36',\n    tokenCount: 412,\n    updatedAgo: '1 day ago',\n    title: 'Color Tokens Derivation & Contrast Calibration',\n    snippetPrefix: 'Deriving consistent dark-mode contrasts requires ',\n    highlightedText:\n      'anchoring chroma and shifting lightness along the OKLCH L-axis. Use --color-primary: oklch(0.65 0.22 260) for vibrant interactive states',\n    snippetSuffix:\n      ' and calibrate border contrast with `--color-border: oklch(0.28 0.01 260)` for WCAG AA compliance across both frameworks.',\n    fullSnippet:\n      'Deriving consistent dark-mode contrasts requires anchoring chroma and shifting lightness along the OKLCH L-axis. Use `--color-primary: oklch(0.65 0.22 260)` for vibrant interactive states and calibrate border contrast with `--color-border: oklch(0.28 0.01 260)` for WCAG AA compliance across both frameworks.',\n  },\n  {\n    id: 'chunk-3',\n    citationIndex: 3,\n    relevanceScore: 0.824,\n    rerankBoost: 0.048,\n    cosineScore: 0.776,\n    bm25Score: 0.65,\n    documentPath: 'blog/2026/design-systems-monorepo.md',\n    namespace: 'blog',\n    chunkOffset: 'Chunk #5 · Lines 112–164',\n    tokenCount: 526,\n    updatedAgo: '3 days ago',\n    title: 'Dual-Framework Component Registry Architecture',\n    snippetPrefix: 'When architecting a dual-framework registry (Vue + React), ',\n    highlightedText:\n      'shared design tokens must compile cleanly without runtime overhead. We leverage CSS custom properties to mirror CVA component variants',\n    snippetSuffix: ' across both frameworks with zero extra runtime.',\n    fullSnippet:\n      'When architecting a dual-framework registry (Vue + React), shared design tokens must compile cleanly without runtime overhead. We leverage modern CSS custom properties and PostCSS pipelines to mirror CVA component variants across both frameworks with zero extra runtime.',\n  },\n]\n\n// Displayed chunks based on Top-K slider\nconst displayedChunks = computed(() => {\n  const count = Math.min(Math.max(1, topK.value), allChunks.length)\n  return allChunks.slice(0, count)\n})\n\n// Active Stage for inspection\nconst currentStage = computed(() => {\n  return stages.value.find((s) => s.id === selectedStageId.value) ?? stages.value[0]\n})\n\n// Total Pipeline Latency\nconst totalPipelineLatency = computed(() => {\n  const sum = stages.value.reduce((acc, s) => acc + s.durationMs, 0)\n  return `${sum}ms`\n})\n\n// Execution Trace JSON\nconst traceJson = computed(() => {\n  return JSON.stringify(\n    {\n      traceId: 'trc_rag_948201a4',\n      pipeline: 'enterprise_knowledge_rag_v3',\n      timestamp: new Date().toISOString(),\n      query: currentQuery.value,\n      config: {\n        embeddingModel: 'text-embedding-3-small',\n        dimensions: 1536,\n        vectorDb: 'Pinecone Serverless',\n        topK: topK.value,\n        reranker: rerankerEnabled.value ? 'cohere-rerank-v3' : 'none',\n        alphaFusion: 0.7,\n      },\n      stages: stages.value.map((s) => ({\n        id: s.id,\n        name: s.name,\n        durationMs: s.durationMs,\n        status: s.status,\n      })),\n      retrievedChunks: displayedChunks.value.map((c) => ({\n        citation: c.citationIndex,\n        docPath: c.documentPath,\n        relevance: rerankerEnabled.value ? c.relevanceScore : c.cosineScore,\n        rerankBoost: rerankerEnabled.value ? c.rerankBoost : 0,\n        tokenCount: c.tokenCount,\n      })),\n      synthesis: {\n        model: 'claude-3-5-sonnet-20241022',\n        promptTokens: 1248,\n        completionTokens: 214,\n        groundedFactRatio: 1.0,\n        latencyMs: 820,\n      },\n    },\n    null,\n    2,\n  )\n})\n\n// Actions\nfunction handleRunPipeline() {\n  if (isExecuting.value) return\n  isExecuting.value = true\n  selectedStageId.value = 1\n\n  setTimeout(() => {\n    selectedStageId.value = 2\n  }, 200)\n\n  setTimeout(() => {\n    selectedStageId.value = 3\n  }, 450)\n\n  setTimeout(() => {\n    selectedStageId.value = 4\n  }, 700)\n\n  setTimeout(() => {\n    selectedStageId.value = 5\n    isExecuting.value = false\n  }, 950)\n}\n\nfunction handleSelectPreset(preset: string) {\n  currentQuery.value = preset\n  handleRunPipeline()\n}\n\nfunction handleCopyChunk(id: string, text: string) {\n  navigator.clipboard.writeText(text)\n  copiedChunkId.value = id\n  setTimeout(() => {\n    copiedChunkId.value = null\n  }, 2000)\n}\n\nfunction handleCopyResponse(text: string) {\n  navigator.clipboard.writeText(text)\n  copiedResponse.value = true\n  setTimeout(() => {\n    copiedResponse.value = false\n  }, 2000)\n}\n\nfunction handleCopyTrace() {\n  navigator.clipboard.writeText(traceJson.value)\n  copiedTrace.value = true\n  setTimeout(() => {\n    copiedTrace.value = false\n  }, 2000)\n}\n\nfunction handleSliderUpdate(val: number | number[] | [number, number]) {\n  if (typeof val === 'number') {\n    topK.value = val\n  } else if (Array.isArray(val) && typeof val[0] === 'number') {\n    topK.value = val[0]\n  }\n}\n</script>\n\n<template>\n  <div :class=\"cn('w-full space-y-6 font-sans', $props.class)\">\n    <!-- 1. Pipeline Header -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"pb-4\">\n        <div class=\"flex flex-col gap-4 md:flex-row md:items-center md:justify-between\">\n          <div class=\"space-y-1.5\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <div class=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-lg\">\n                <Workflow class=\"size-4.5\" />\n              </div>\n              <h2 class=\"text-foreground text-lg font-semibold tracking-tight sm:text-xl\">\n                enterprise_knowledge_rag_v3\n              </h2>\n              <Badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success\">\n                <span class=\"bg-success mr-1.5 size-1.5 rounded-full motion-safe:animate-pulse\" />\n                Pipeline Active\n              </Badge>\n              <Badge variant=\"secondary\" class=\"font-mono text-xs\"> p99 {{ totalPipelineLatency }} </Badge>\n            </div>\n            <p class=\"text-muted-foreground text-sm\">\n              Production Retrieval-Augmented Generation pipeline with HyDE query rewriting, hybrid reciprocal rank\n              fusion, and cross-encoder validation.\n            </p>\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <Button variant=\"outline\" size=\"sm\" class=\"gap-1.5 shadow-xs\" @click=\"showTraceJson = !showTraceJson\">\n              <FileCode class=\"size-4\" />\n              <span>{{ showTraceJson ? 'Hide Trace' : 'Export Trace JSON' }}</span>\n            </Button>\n            <Button size=\"sm\" class=\"gap-1.5 shadow-xs\" :disabled=\"isExecuting\" @click=\"handleRunPipeline\">\n              <RefreshCw v-if=\"isExecuting\" class=\"size-4 motion-safe:animate-spin\" />\n              <Play v-else class=\"size-4 fill-current\" />\n              <span>{{ isExecuting ? 'Executing Pipeline...' : 'Test Query Pipeline' }}</span>\n            </Button>\n          </div>\n        </div>\n\n        <!-- Pipeline Metadata Specs Bar -->\n        <div class=\"border-border mt-4 grid grid-cols-2 gap-2 border-t pt-4 text-xs sm:grid-cols-4\">\n          <div class=\"text-muted-foreground flex items-center gap-2\">\n            <Cpu class=\"text-primary size-3.5 shrink-0\" />\n            <span class=\"truncate\">\n              <strong class=\"text-foreground font-medium\">Embedding:</strong> OpenAI text-embedding-3-small · 1536-dim\n            </span>\n          </div>\n          <div class=\"text-muted-foreground flex items-center gap-2\">\n            <Database class=\"text-primary size-3.5 shrink-0\" />\n            <span class=\"truncate\">\n              <strong class=\"text-foreground font-medium\">Vector DB:</strong> Pinecone Serverless · HNSW\n            </span>\n          </div>\n          <div class=\"text-muted-foreground flex items-center gap-2\">\n            <Layers class=\"text-primary size-3.5 shrink-0\" />\n            <span class=\"truncate\">\n              <strong class=\"text-foreground font-medium\">Index Space:</strong> 482,910 chunks · 4 namespaces\n            </span>\n          </div>\n          <div class=\"text-muted-foreground flex items-center gap-2\">\n            <ShieldCheck class=\"text-success size-3.5 shrink-0\" />\n            <span class=\"truncate\">\n              <strong class=\"text-foreground font-medium\">Grounding:</strong> 100% strict context citation\n            </span>\n          </div>\n        </div>\n      </CardHeader>\n    </Card>\n\n    <!-- Optional Trace JSON Drawer/Modal -->\n    <Card v-if=\"showTraceJson\" class=\"border-border bg-card/95 shadow-xs\">\n      <CardHeader class=\"pb-2\">\n        <div class=\"flex items-center justify-between\">\n          <div class=\"flex items-center gap-2\">\n            <Terminal class=\"text-primary size-4\" />\n            <CardTitle class=\"text-sm font-medium\">OpenTelemetry Pipeline Execution Trace</CardTitle>\n          </div>\n          <Button variant=\"ghost\" size=\"xs\" class=\"gap-1\" @click=\"handleCopyTrace\">\n            <Check v-if=\"copiedTrace\" class=\"text-success size-3.5\" />\n            <Copy v-else class=\"size-3.5\" />\n            <span>{{ copiedTrace ? 'Copied JSON' : 'Copy Trace' }}</span>\n          </Button>\n        </div>\n      </CardHeader>\n      <CardContent>\n        <pre class=\"bg-muted/70 text-foreground max-h-64 overflow-x-auto rounded-md p-3 font-mono text-xs\">{{\n          traceJson\n        }}</pre>\n      </CardContent>\n    </Card>\n\n    <!-- 2. Query Input & Runtime Controls Bar -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardContent class=\"space-y-4 p-4 sm:p-6\">\n        <div class=\"space-y-2\">\n          <div class=\"flex items-center justify-between\">\n            <label for=\"rag-query-input\" class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n              Interactive Test Query\n            </label>\n            <span class=\"text-muted-foreground text-xs\"> Press Enter or click Test Query to simulate </span>\n          </div>\n\n          <div class=\"relative flex items-center\">\n            <Input\n              id=\"rag-query-input\"\n              v-model=\"currentQuery\"\n              class=\"pr-20 text-sm font-medium shadow-xs\"\n              placeholder=\"Enter search prompt or technical query...\"\n              @keydown.enter=\"handleRunPipeline\"\n            >\n              <template #prefix>\n                <Search class=\"text-muted-foreground size-4\" />\n              </template>\n            </Input>\n            <Button size=\"xs\" class=\"absolute right-1.5 gap-1\" :disabled=\"isExecuting\" @click=\"handleRunPipeline\">\n              <Zap class=\"size-3\" />\n              <span>Run</span>\n            </Button>\n          </div>\n        </div>\n\n        <!-- Query Presets Chips -->\n        <div class=\"flex flex-wrap items-center gap-1.5\">\n          <span class=\"text-muted-foreground text-xs font-medium\">Presets:</span>\n          <button\n            v-for=\"preset in presetQueries\"\n            :key=\"preset\"\n            type=\"button\"\n            :class=\"\n              cn(\n                'focus-visible:ring-ring min-h-6 cursor-pointer rounded-full border px-2.5 py-0.5 text-xs transition-colors focus-visible:ring-2 focus-visible:outline-hidden',\n                currentQuery === preset\n                  ? 'border-primary bg-primary/10 text-primary font-medium'\n                  : 'border-border bg-muted/40 text-muted-foreground hover:bg-muted hover:text-foreground',\n              )\n            \"\n            @click=\"handleSelectPreset(preset)\"\n          >\n            {{ preset }}\n          </button>\n        </div>\n\n        <Separator />\n\n        <!-- Controls Toolbar: Top-K Slider + Reranker Switch + Metrics -->\n        <div class=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n          <!-- Top-K Slider -->\n          <div class=\"space-y-2\">\n            <div class=\"flex items-center justify-between\">\n              <div class=\"flex items-center gap-1.5\">\n                <SlidersHorizontal class=\"text-primary size-3.5\" />\n                <span class=\"text-foreground text-xs font-medium\">Top-K Chunks</span>\n              </div>\n              <Badge variant=\"secondary\" class=\"font-mono text-xs\"> Top {{ topK }} Chunks </Badge>\n            </div>\n            <Slider\n              :model-value=\"topK\"\n              :min=\"1\"\n              :max=\"3\"\n              :step=\"1\"\n              :tooltip=\"false\"\n              class=\"w-full\"\n              @update:model-value=\"handleSliderUpdate\"\n            />\n            <div class=\"text-muted-foreground flex justify-between font-mono text-xs\">\n              <span>k=1</span>\n              <span>k=2</span>\n              <span>k=3</span>\n            </div>\n          </div>\n\n          <!-- Reranker Toggle -->\n          <div class=\"border-border/80 bg-muted/20 flex flex-col justify-between space-y-2 rounded-lg border p-3\">\n            <div class=\"flex items-center justify-between\">\n              <div class=\"space-y-0.5\">\n                <div class=\"flex items-center gap-1.5\">\n                  <Filter class=\"text-primary size-3.5\" />\n                  <span class=\"text-foreground text-xs font-semibold\">Cohere Rerank v3</span>\n                </div>\n                <p class=\"text-muted-foreground text-xs\">Cross-encoder contextual re-scoring</p>\n              </div>\n              <Switch :model-value=\"rerankerEnabled\" @update:model-value=\"(val) => (rerankerEnabled = val)\" />\n            </div>\n            <div class=\"flex items-center gap-2\">\n              <Badge\n                :variant=\"rerankerEnabled ? 'outline' : 'secondary'\"\n                :class=\"\n                  cn(\n                    'font-mono text-xs',\n                    rerankerEnabled ? 'border-success/30 bg-success/10 text-success' : 'text-muted-foreground',\n                  )\n                \"\n              >\n                {{ rerankerEnabled ? 'Active (+0.142 boost)' : 'Bypassed (Cosine only)' }}\n              </Badge>\n            </div>\n          </div>\n\n          <!-- Pipeline Telemetry Overview -->\n          <div\n            class=\"border-border/80 bg-muted/20 flex flex-col justify-between space-y-1.5 rounded-lg border p-3 sm:col-span-2 lg:col-span-1\"\n          >\n            <div class=\"flex items-center justify-between\">\n              <span class=\"text-foreground text-xs font-semibold\">Execution Latency</span>\n              <span class=\"text-primary font-mono text-xs font-medium\">{{ totalPipelineLatency }} total</span>\n            </div>\n            <div class=\"space-y-1\">\n              <div class=\"text-muted-foreground flex justify-between text-xs\">\n                <span>Dense + BM25</span>\n                <span class=\"font-mono\">106ms</span>\n              </div>\n              <Progress :model-value=\"15\" class=\"h-1.5\" />\n            </div>\n            <div class=\"space-y-1\">\n              <div class=\"text-muted-foreground flex justify-between text-xs\">\n                <span>LLM Synthesis</span>\n                <span class=\"font-mono\">820ms (85%)</span>\n              </div>\n              <Progress :model-value=\"85\" class=\"h-1.5\" />\n            </div>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n\n    <!-- 3. Interactive RAG 5-Stage Architecture Flow -->\n    <div class=\"space-y-3\">\n      <div class=\"flex items-center justify-between\">\n        <div>\n          <h3 class=\"text-foreground text-sm text-xs font-semibold tracking-tight tracking-wider uppercase\">\n            RAG Pipeline Execution Graph\n          </h3>\n          <p class=\"text-muted-foreground text-xs\">\n            Click any stage node to inspect low-level telemetry, prompt variables, and intermediate embeddings.\n          </p>\n        </div>\n        <Badge variant=\"outline\" class=\"font-mono text-xs\"> 5 Connected Stages </Badge>\n      </div>\n\n      <!-- 5-Stage Connected Cards -->\n      <div class=\"grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-5\">\n        <div\n          v-for=\"stage in stages\"\n          :key=\"stage.id\"\n          :class=\"\n            cn(\n              'group focus-visible:ring-ring relative flex cursor-pointer flex-col justify-between rounded-lg border p-3.5 transition-colors focus-visible:ring-2 focus-visible:outline-hidden',\n              selectedStageId === stage.id\n                ? 'border-primary bg-primary/5 ring-primary/40 shadow-xs ring-1'\n                : 'border-border bg-card hover:border-primary/40 hover:bg-muted/30',\n            )\n          \"\n          tabindex=\"0\"\n          role=\"button\"\n          :aria-pressed=\"selectedStageId === stage.id\"\n          @click=\"selectedStageId = stage.id\"\n          @keydown.enter=\"selectedStageId = stage.id\"\n          @keydown.space.prevent=\"selectedStageId = stage.id\"\n        >\n          <div class=\"space-y-2\">\n            <div class=\"flex items-center justify-between\">\n              <div\n                :class=\"\n                  cn(\n                    'flex size-7 items-center justify-center rounded-md text-xs font-semibold',\n                    selectedStageId === stage.id\n                      ? 'bg-primary text-primary-foreground'\n                      : 'bg-muted text-foreground group-hover:bg-primary/20 group-hover:text-primary',\n                  )\n                \"\n              >\n                <component :is=\"stage.icon\" class=\"size-3.5\" />\n              </div>\n              <Badge\n                variant=\"secondary\"\n                :class=\"\n                  cn(\n                    'font-mono text-xs',\n                    stage.status === 'bypassed' && 'text-muted-foreground line-through opacity-70',\n                  )\n                \"\n              >\n                {{ stage.latency }}\n              </Badge>\n            </div>\n\n            <div>\n              <p class=\"text-foreground text-xs leading-tight font-semibold\">\n                {{ stage.name }}\n              </p>\n              <p class=\"text-muted-foreground mt-1 line-clamp-2 text-xs leading-relaxed\">\n                {{ stage.subtitle }}\n              </p>\n            </div>\n          </div>\n\n          <div\n            class=\"border-border/60 text-muted-foreground mt-3 flex items-center justify-between border-t pt-2 text-xs\"\n          >\n            <span class=\"truncate font-medium\">{{ stage.tag }}</span>\n            <ChevronRight\n              :class=\"\n                cn(\n                  'size-3.5 transition-transform',\n                  selectedStageId === stage.id ? 'text-primary translate-x-0.5' : 'text-muted-foreground',\n                )\n              \"\n            />\n          </div>\n        </div>\n      </div>\n\n      <!-- Stage Detail Drill-down Panel -->\n      <Card class=\"border-border bg-card/60 shadow-xs\">\n        <CardHeader class=\"pb-3\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div class=\"flex items-center gap-2\">\n              <div class=\"bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md\">\n                <component :is=\"currentStage.icon\" class=\"size-4\" />\n              </div>\n              <div>\n                <CardTitle class=\"text-foreground text-sm font-semibold\">\n                  {{ currentStage.name }} — Inspector\n                </CardTitle>\n                <CardDescription class=\"text-xs\">\n                  {{ currentStage.details.description }}\n                </CardDescription>\n              </div>\n            </div>\n            <Badge variant=\"outline\" class=\"w-fit font-mono text-xs\">\n              Stage {{ currentStage.id }} of 5 · {{ currentStage.latency }}\n            </Badge>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-4 pt-0\">\n          <!-- Metrics Grid for Stage -->\n          <div class=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n            <div\n              v-for=\"metric in currentStage.details.metrics\"\n              :key=\"metric.label\"\n              class=\"border-border/80 bg-muted/40 rounded-md border p-2.5\"\n            >\n              <p class=\"text-muted-foreground text-xs\">{{ metric.label }}</p>\n              <p class=\"text-foreground mt-0.5 truncate font-mono text-xs font-semibold\">{{ metric.value }}</p>\n            </div>\n          </div>\n\n          <!-- Code or Data Artifact Preview -->\n          <div v-if=\"currentStage.details.codeOrData\" class=\"space-y-1.5\">\n            <div class=\"text-muted-foreground flex items-center justify-between text-xs font-medium\">\n              <span class=\"flex items-center gap-1.5\">\n                <Code2 class=\"text-primary size-3.5\" />\n                {{ currentStage.details.codeOrData.title }}\n              </span>\n              <span class=\"font-mono text-xs\">read-only buffer</span>\n            </div>\n            <pre\n              class=\"bg-muted/80 text-foreground max-h-40 overflow-x-auto rounded-md p-3 font-mono text-xs leading-relaxed whitespace-pre-wrap\"\n              >{{ currentStage.details.codeOrData.content }}</pre\n            >\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n\n    <!-- 4. Retrieved Context Chunks Inspector -->\n    <div class=\"space-y-3\">\n      <div class=\"flex items-center justify-between\">\n        <div>\n          <h3 class=\"text-foreground text-xs font-semibold tracking-wider uppercase\">\n            Retrieved Context Chunks ({{ displayedChunks.length }} Active Chunks)\n          </h3>\n          <p class=\"text-muted-foreground text-xs\">\n            Ranked by cross-encoder relevance score. Keyword spans matching user intent are highlighted.\n          </p>\n        </div>\n        <div class=\"flex items-center gap-2\">\n          <Badge variant=\"secondary\" class=\"font-mono text-xs\"> Fusion: Dense (70%) + Sparse (30%) </Badge>\n        </div>\n      </div>\n\n      <div class=\"space-y-3\">\n        <Card\n          v-for=\"chunk in displayedChunks\"\n          :key=\"chunk.id\"\n          :class=\"\n            cn(\n              'border-border bg-card shadow-xs transition-colors',\n              activeCitationHover === chunk.citationIndex && 'border-primary/80 ring-primary/20 bg-primary/5 ring-2',\n            )\n          \"\n        >\n          <CardHeader class=\"p-4 pb-2\">\n            <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <!-- Citation Badge Pill -->\n                <span\n                  :class=\"\n                    cn(\n                      'flex size-6 items-center justify-center rounded-md font-mono text-xs font-bold transition-colors',\n                      activeCitationHover === chunk.citationIndex\n                        ? 'bg-primary text-primary-foreground'\n                        : 'bg-muted text-foreground',\n                    )\n                  \"\n                >\n                  [{{ chunk.citationIndex }}]\n                </span>\n\n                <!-- Relevancy Score Badge -->\n                <Badge\n                  variant=\"outline\"\n                  :class=\"\n                    cn(\n                      'font-mono text-xs font-semibold',\n                      chunk.relevanceScore >= 0.9\n                        ? 'border-success/30 bg-success/10 text-success'\n                        : chunk.relevanceScore >= 0.85\n                          ? 'border-success/30 bg-success/10 text-success'\n                          : 'border-info/30 bg-info/10 text-info',\n                    )\n                  \"\n                >\n                  Score: {{ rerankerEnabled ? chunk.relevanceScore.toFixed(3) : chunk.cosineScore.toFixed(3) }}\n                </Badge>\n\n                <!-- Rerank Delta Badge -->\n                <Badge v-if=\"rerankerEnabled\" variant=\"secondary\" class=\"text-muted-foreground font-mono text-xs\">\n                  +{{ chunk.rerankBoost.toFixed(3) }} boost (Rank #{{ chunk.citationIndex }})\n                </Badge>\n\n                <!-- Document Path -->\n                <span class=\"text-foreground font-mono text-xs font-medium\">\n                  {{ chunk.documentPath }}\n                </span>\n              </div>\n\n              <!-- Metadata & Copy Action -->\n              <div class=\"flex items-center gap-2\">\n                <span class=\"text-muted-foreground hidden font-mono text-xs sm:inline\">\n                  {{ chunk.chunkOffset }} · {{ chunk.tokenCount }} tok\n                </span>\n                <Button\n                  variant=\"ghost\"\n                  size=\"xs\"\n                  class=\"text-muted-foreground hover:text-foreground gap-1\"\n                  @click=\"handleCopyChunk(chunk.id, chunk.fullSnippet)\"\n                >\n                  <Check v-if=\"copiedChunkId === chunk.id\" class=\"text-success size-3\" />\n                  <Copy v-else class=\"size-3\" />\n                  <span class=\"text-xs\">{{ copiedChunkId === chunk.id ? 'Copied' : 'Copy' }}</span>\n                </Button>\n              </div>\n            </div>\n          </CardHeader>\n\n          <CardContent class=\"p-4 pt-2\">\n            <!-- Chunk Text with Highlighted Spans -->\n            <div\n              class=\"border-border/70 bg-muted/40 text-foreground rounded-md border p-3 font-mono text-xs leading-relaxed\"\n            >\n              <span>{{ chunk.snippetPrefix }}</span>\n              <mark class=\"bg-primary/20 text-primary dark:bg-primary/30 rounded px-1 py-0.5 font-semibold\">\n                {{ chunk.highlightedText }}\n              </mark>\n              <span>{{ chunk.snippetSuffix }}</span>\n            </div>\n\n            <!-- Scoring Breakdown Sub-bar -->\n            <div class=\"text-muted-foreground mt-2.5 flex flex-wrap items-center justify-between gap-2 text-xs\">\n              <div class=\"flex flex-wrap items-center gap-3 font-mono\">\n                <span\n                  >Dense Cosine:\n                  <strong class=\"text-foreground font-semibold\">{{ chunk.cosineScore.toFixed(3) }}</strong></span\n                >\n                <span\n                  >Sparse BM25:\n                  <strong class=\"text-foreground font-semibold\">{{ chunk.bm25Score.toFixed(3) }}</strong></span\n                >\n                <span v-if=\"rerankerEnabled\"\n                  >Cross-Encoder:\n                  <strong class=\"text-success font-semibold\">{{ chunk.relevanceScore.toFixed(3) }}</strong></span\n                >\n              </div>\n              <span class=\"text-muted-foreground text-xs\">Updated {{ chunk.updatedAgo }}</span>\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n    </div>\n\n    <!-- 5. Final Synthesized Output Card with Citations -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"pb-3\">\n        <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n          <div class=\"flex items-center gap-2\">\n            <div class=\"bg-primary text-primary-foreground flex size-7 items-center justify-center rounded-md\">\n              <Sparkles class=\"size-4\" />\n            </div>\n            <div>\n              <CardTitle class=\"text-foreground text-base font-semibold\"> Synthesized Grounded Response </CardTitle>\n              <CardDescription class=\"text-xs\">\n                Generated via Claude 3.5 Sonnet streaming with verified inline citations.\n              </CardDescription>\n            </div>\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <Badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success font-mono text-xs\">\n              <ShieldCheck class=\"mr-1 size-3\" />\n              100% Grounded · 0 Hallucinations\n            </Badge>\n            <Badge variant=\"secondary\" class=\"font-mono text-xs\"> 820ms (TTFT 180ms) </Badge>\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"space-y-4\">\n        <!-- Markdown Formatted Synthesized Body -->\n        <div\n          class=\"border-border/80 bg-muted/20 text-foreground space-y-3 rounded-lg border p-4 text-sm leading-relaxed sm:p-5\"\n        >\n          <p class=\"text-foreground font-medium\">To configure OKLCH color palettes in Tailwind CSS v4 with UIPKGE:</p>\n\n          <ol class=\"text-foreground/90 list-decimal space-y-2.5 pl-5 text-sm\">\n            <li class=\"leading-relaxed\">\n              <strong>Define Theme Tokens in CSS:</strong> Use\n              <code class=\"bg-muted text-foreground rounded px-1.5 py-0.5 font-mono text-xs\">@theme inline</code>\n              in your root stylesheet to declare single-source-of-truth OKLCH variables\n              <button\n                type=\"button\"\n                class=\"bg-primary/10 py-0.2 text-primary hover:bg-primary hover:text-primary-foreground mx-1 inline-flex min-h-6 cursor-pointer items-center rounded px-1 font-mono text-xs font-bold transition-colors\"\n                @mouseenter=\"activeCitationHover = 1\"\n                @mouseleave=\"activeCitationHover = null\"\n              >\n                [1]</button\n              >. Unlike legacy RGB/HSL, OKLCH ensures perceptually uniform lightness across hue shifts\n              <button\n                type=\"button\"\n                class=\"bg-primary/10 py-0.2 text-primary hover:bg-primary hover:text-primary-foreground mx-1 inline-flex min-h-6 cursor-pointer items-center rounded px-1 font-mono text-xs font-bold transition-colors\"\n                @mouseenter=\"activeCitationHover = 1\"\n                @mouseleave=\"activeCitationHover = null\"\n              >\n                [1]</button\n              >.\n            </li>\n\n            <li class=\"leading-relaxed\">\n              <strong>Calibrate Dark Mode Contrasts:</strong> Anchor chroma and shift lightness along the OKLCH L-axis\n              (e.g.,\n              <code class=\"bg-muted rounded px-1.5 py-0.5 font-mono text-xs\"\n                >--color-primary: oklch(0.65 0.22 260)</code\n              >\n              and\n              <code class=\"bg-muted rounded px-1.5 py-0.5 font-mono text-xs\">--color-border: oklch(0.28 0.01 260)</code\n              >) to maintain WCAG AA compliance across both light and dark modes\n              <button\n                type=\"button\"\n                class=\"bg-primary/10 py-0.2 text-primary hover:bg-primary hover:text-primary-foreground mx-1 inline-flex min-h-6 cursor-pointer items-center rounded px-1 font-mono text-xs font-bold transition-colors\"\n                @mouseenter=\"activeCitationHover = 2\"\n                @mouseleave=\"activeCitationHover = null\"\n              >\n                [2]</button\n              >.\n            </li>\n\n            <li class=\"leading-relaxed\">\n              <strong>Maintain Dual-Framework CVA Parity:</strong> Wire CSS tokens directly through Class Variance\n              Authority (<code class=\"bg-muted rounded px-1.5 py-0.5 font-mono text-xs\">cva()</code>) variants so that\n              both Vue and React registry components share identical token namespaces with zero runtime bundle overhead\n              <button\n                type=\"button\"\n                class=\"bg-primary/10 py-0.2 text-primary hover:bg-primary hover:text-primary-foreground mx-1 inline-flex min-h-6 cursor-pointer items-center rounded px-1 font-mono text-xs font-bold transition-colors\"\n                @mouseenter=\"activeCitationHover = 3\"\n                @mouseleave=\"activeCitationHover = null\"\n              >\n                [3]</button\n              >.\n            </li>\n          </ol>\n\n          <!-- Streaming cursor pulse -->\n          <div class=\"text-muted-foreground flex items-center gap-1.5 pt-1 font-mono text-xs\">\n            <span class=\"bg-success size-2 rounded-full motion-safe:animate-ping\" />\n            <span>Generation Complete · 214 tokens streamed</span>\n          </div>\n        </div>\n\n        <!-- Citation Footnotes Bar -->\n        <div class=\"border-border/70 bg-muted/40 space-y-1.5 rounded-md border p-3 text-xs\">\n          <span class=\"text-foreground flex items-center gap-1.5 font-semibold\">\n            <BookOpen class=\"text-primary size-3.5\" />\n            Referenced Citations (Hover citation to locate chunk):\n          </span>\n          <div class=\"grid grid-cols-1 gap-1.5 sm:grid-cols-3\">\n            <div\n              v-for=\"chunk in displayedChunks\"\n              :key=\"chunk.id\"\n              :class=\"\n                cn(\n                  'flex cursor-pointer items-center justify-between rounded border p-1.5 font-mono text-xs transition-colors',\n                  activeCitationHover === chunk.citationIndex\n                    ? 'border-primary bg-primary/10 text-primary'\n                    : 'border-border/60 bg-card text-muted-foreground hover:bg-muted',\n                )\n              \"\n              @mouseenter=\"activeCitationHover = chunk.citationIndex\"\n              @mouseleave=\"activeCitationHover = null\"\n            >\n              <span class=\"truncate\">[{{ chunk.citationIndex }}] {{ chunk.documentPath.split('/').pop() }}</span>\n              <span class=\"font-semibold\">{{ chunk.relevanceScore.toFixed(3) }}</span>\n            </div>\n          </div>\n        </div>\n\n        <!-- Telemetry Footer & Action Buttons -->\n        <div\n          class=\"border-border text-muted-foreground flex flex-col gap-3 border-t pt-2 text-xs sm:flex-row sm:items-center sm:justify-between\"\n        >\n          <div class=\"flex flex-wrap items-center gap-3 font-mono\">\n            <span>Input: <strong class=\"text-foreground\">1,248 tok</strong></span>\n            <span>Output: <strong class=\"text-foreground\">214 tok</strong></span>\n            <span>Cost: <strong class=\"text-foreground\">$0.00438</strong></span>\n            <span>Grounding: <strong class=\"text-success\">99.4%</strong></span>\n          </div>\n\n          <div class=\"flex items-center gap-2\">\n            <div class=\"border-border bg-card flex items-center rounded-md border p-0.5\">\n              <Button\n                aria-label=\"Thumbs up\"\n                variant=\"ghost\"\n                size=\"xs\"\n                :class=\"cn('px-2', userFeedback === 'up' && 'text-success')\"\n                @click=\"userFeedback = userFeedback === 'up' ? null : 'up'\"\n              >\n                <ThumbsUp class=\"size-3.5\" />\n              </Button>\n              <Separator orientation=\"vertical\" class=\"h-4\" />\n              <Button\n                aria-label=\"Thumbs down\"\n                variant=\"ghost\"\n                size=\"xs\"\n                :class=\"cn('px-2', userFeedback === 'down' && 'text-destructive')\"\n                @click=\"userFeedback = userFeedback === 'down' ? null : 'down'\"\n              >\n                <ThumbsDown class=\"size-3.5\" />\n              </Button>\n            </div>\n\n            <Button variant=\"outline\" size=\"xs\" class=\"gap-1\" @click=\"handleRunPipeline\">\n              <RefreshCw class=\"size-3\" />\n              <span>Regenerate</span>\n            </Button>\n\n            <Button\n              size=\"xs\"\n              class=\"gap-1\"\n              @click=\"\n                handleCopyResponse(\n                  'To configure OKLCH color palettes in Tailwind CSS v4 with UIPKGE: 1. Define Theme Tokens in CSS (@theme inline)... 2. Calibrate Dark Mode Contrasts... 3. Maintain Dual-Framework CVA Parity...',\n                )\n              \"\n            >\n              <Check v-if=\"copiedResponse\" class=\"size-3\" />\n              <Copy v-else class=\"size-3\" />\n              <span>{{ copiedResponse ? 'Copied' : 'Copy Answer' }}</span>\n            </Button>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/RagPipelineVisualizer.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/input.json",
    "https://uipkge.dev/r/vue/progress.json",
    "https://uipkge.dev/r/vue/separator.json",
    "https://uipkge.dev/r/vue/slider.json",
    "https://uipkge.dev/r/vue/switch.json"
  ],
  "description": "LlamaIndex and LangChain style Retrieval-Augmented Generation (RAG) pipeline debugger and chunk retrieval inspector. Features 5-stage interactive DAG flow, HyDE expansion preview, hybrid dense/sparse search telemetry, cross-encoder reranking, and grounded response synthesis.",
  "categories": [
    "ai",
    "dashboard",
    "database",
    "app"
  ]
}