Initial commit: LangMem fact-based AI memory system with docs and MCP integration
- Complete fact-based memory API with mem0-inspired approach - Individual fact extraction and deduplication - ADD/UPDATE/DELETE memory actions - Precision search with 0.86+ similarity scores - MCP server for Claude Code integration - Neo4j graph relationships and PostgreSQL vector storage - Comprehensive documentation with architecture and API docs - Matrix communication integration - Production-ready Docker setup with Ollama and Supabase 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
353
docs/assets/js/main.js
Normal file
353
docs/assets/js/main.js
Normal file
@@ -0,0 +1,353 @@
|
||||
// LangMem Documentation JavaScript
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize all components
|
||||
initializeNavigation();
|
||||
initializeAnimations();
|
||||
initializeDiagrams();
|
||||
initializeCodeBlocks();
|
||||
initializeSmoothScroll();
|
||||
initializeProgressTracking();
|
||||
});
|
||||
|
||||
// Navigation functionality
|
||||
function initializeNavigation() {
|
||||
const currentPath = window.location.pathname;
|
||||
const navLinks = document.querySelectorAll('.nav-links a');
|
||||
|
||||
navLinks.forEach(link => {
|
||||
if (link.getAttribute('href') === currentPath) {
|
||||
link.classList.add('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fade-in animations for cards
|
||||
function initializeAnimations() {
|
||||
const observerOptions = {
|
||||
threshold: 0.1,
|
||||
rootMargin: '0px 0px -100px 0px'
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('fade-in');
|
||||
}
|
||||
});
|
||||
}, observerOptions);
|
||||
|
||||
document.querySelectorAll('.card, .phase-card, .diagram-container').forEach(el => {
|
||||
observer.observe(el);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize Mermaid diagrams
|
||||
function initializeDiagrams() {
|
||||
if (typeof mermaid !== 'undefined') {
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'default',
|
||||
flowchart: {
|
||||
useMaxWidth: true,
|
||||
htmlLabels: true
|
||||
},
|
||||
securityLevel: 'loose'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Code block enhancements
|
||||
function initializeCodeBlocks() {
|
||||
const codeBlocks = document.querySelectorAll('.code-block');
|
||||
|
||||
codeBlocks.forEach(block => {
|
||||
// Add copy button
|
||||
const copyBtn = document.createElement('button');
|
||||
copyBtn.className = 'copy-btn';
|
||||
copyBtn.innerHTML = '📋 Copy';
|
||||
copyBtn.onclick = () => copyToClipboard(block.textContent, copyBtn);
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.className = 'code-container';
|
||||
container.appendChild(copyBtn);
|
||||
|
||||
block.parentNode.insertBefore(container, block);
|
||||
container.appendChild(block);
|
||||
});
|
||||
}
|
||||
|
||||
// Copy to clipboard functionality
|
||||
function copyToClipboard(text, button) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
const originalText = button.innerHTML;
|
||||
button.innerHTML = '✅ Copied!';
|
||||
setTimeout(() => {
|
||||
button.innerHTML = originalText;
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
// Smooth scrolling for anchor links
|
||||
function initializeSmoothScroll() {
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
target.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Progress tracking for implementation phases
|
||||
function initializeProgressTracking() {
|
||||
const phaseCards = document.querySelectorAll('.phase-card');
|
||||
const progressBar = document.querySelector('.progress-bar');
|
||||
|
||||
if (progressBar && phaseCards.length > 0) {
|
||||
updateProgressBar();
|
||||
}
|
||||
}
|
||||
|
||||
function updateProgressBar() {
|
||||
const totalPhases = document.querySelectorAll('.phase-card').length;
|
||||
const completedPhases = document.querySelectorAll('.status-completed').length;
|
||||
const progress = (completedPhases / totalPhases) * 100;
|
||||
|
||||
const progressBar = document.querySelector('.progress-fill');
|
||||
if (progressBar) {
|
||||
progressBar.style.width = `${progress}%`;
|
||||
}
|
||||
}
|
||||
|
||||
// Architecture diagram interactions
|
||||
function showDiagramDetails(diagramId) {
|
||||
const modal = document.getElementById('diagram-modal');
|
||||
const content = document.getElementById('diagram-details');
|
||||
|
||||
const diagramDetails = {
|
||||
'system-overview': {
|
||||
title: 'System Architecture Overview',
|
||||
description: 'This diagram shows the high-level architecture of the LangMem system, including the main components and their relationships.',
|
||||
components: [
|
||||
'LangMem SDK - Core memory management layer',
|
||||
'Supabase - Vector storage with pgvector',
|
||||
'Neo4j - Graph database for relationships',
|
||||
'Ollama - Local LLM and embedding models',
|
||||
'Docker Network - Container orchestration'
|
||||
]
|
||||
},
|
||||
'data-flow': {
|
||||
title: 'Data Flow Architecture',
|
||||
description: 'Shows how data flows through the system during ingestion and retrieval operations.',
|
||||
components: [
|
||||
'Input Processing - Text chunking and preprocessing',
|
||||
'Embedding Generation - Vector creation via Ollama',
|
||||
'Storage Layer - Dual storage in Supabase and Neo4j',
|
||||
'Retrieval Engine - Hybrid search capabilities',
|
||||
'Context Assembly - Final context preparation'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const details = diagramDetails[diagramId];
|
||||
if (details && modal && content) {
|
||||
content.innerHTML = `
|
||||
<h3>${details.title}</h3>
|
||||
<p>${details.description}</p>
|
||||
<ul>
|
||||
${details.components.map(comp => `<li>${comp}</li>`).join('')}
|
||||
</ul>
|
||||
`;
|
||||
modal.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function closeDiagramModal() {
|
||||
const modal = document.getElementById('diagram-modal');
|
||||
if (modal) {
|
||||
modal.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Search functionality
|
||||
function initializeSearch() {
|
||||
const searchInput = document.querySelector('.search-input');
|
||||
const searchResults = document.querySelector('.search-results');
|
||||
|
||||
if (searchInput && searchResults) {
|
||||
searchInput.addEventListener('input', debounce(performSearch, 300));
|
||||
}
|
||||
}
|
||||
|
||||
function performSearch(event) {
|
||||
const query = event.target.value.toLowerCase();
|
||||
const searchResults = document.querySelector('.search-results');
|
||||
|
||||
if (query.length < 2) {
|
||||
searchResults.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
// Simple search implementation
|
||||
const searchableElements = document.querySelectorAll('h1, h2, h3, p, li');
|
||||
const results = [];
|
||||
|
||||
searchableElements.forEach(element => {
|
||||
if (element.textContent.toLowerCase().includes(query)) {
|
||||
results.push({
|
||||
title: element.textContent,
|
||||
url: `#${element.id || ''}`,
|
||||
type: element.tagName.toLowerCase()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
displaySearchResults(results);
|
||||
}
|
||||
|
||||
function displaySearchResults(results) {
|
||||
const searchResults = document.querySelector('.search-results');
|
||||
|
||||
if (results.length === 0) {
|
||||
searchResults.innerHTML = '<p>No results found</p>';
|
||||
} else {
|
||||
searchResults.innerHTML = results.map(result => `
|
||||
<div class="search-result">
|
||||
<a href="${result.url}">${result.title}</a>
|
||||
<span class="result-type">${result.type}</span>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
searchResults.style.display = 'block';
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(timeout);
|
||||
func(...args);
|
||||
};
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// Mobile menu toggle
|
||||
function toggleMobileMenu() {
|
||||
const navLinks = document.querySelector('.nav-links');
|
||||
navLinks.classList.toggle('mobile-open');
|
||||
}
|
||||
|
||||
// Theme toggle functionality
|
||||
function toggleTheme() {
|
||||
const body = document.body;
|
||||
const currentTheme = body.getAttribute('data-theme');
|
||||
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
||||
|
||||
body.setAttribute('data-theme', newTheme);
|
||||
localStorage.setItem('theme', newTheme);
|
||||
}
|
||||
|
||||
// Initialize theme from localStorage
|
||||
function initializeTheme() {
|
||||
const savedTheme = localStorage.getItem('theme') || 'light';
|
||||
document.body.setAttribute('data-theme', savedTheme);
|
||||
}
|
||||
|
||||
// Component status updates
|
||||
function updateComponentStatus(componentId, status) {
|
||||
const statusElement = document.querySelector(`[data-component="${componentId}"] .status`);
|
||||
if (statusElement) {
|
||||
statusElement.className = `status status-${status}`;
|
||||
statusElement.textContent = status.replace('-', ' ').toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
// Progress tracking for implementation
|
||||
function trackImplementationProgress() {
|
||||
const phases = {
|
||||
'phase-1': 'in-progress',
|
||||
'phase-2': 'planning',
|
||||
'phase-3': 'planning',
|
||||
'phase-4': 'planning'
|
||||
};
|
||||
|
||||
Object.entries(phases).forEach(([phaseId, status]) => {
|
||||
updateComponentStatus(phaseId, status);
|
||||
});
|
||||
}
|
||||
|
||||
// Add CSS for additional interactive elements
|
||||
const additionalStyles = `
|
||||
.copy-btn {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.code-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-results {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: var(--shadow-md);
|
||||
display: none;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.search-result {
|
||||
padding: 1rem;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.search-result:hover {
|
||||
background: var(--code-bg);
|
||||
}
|
||||
|
||||
.mobile-open {
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--primary-color);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.nav-links {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
// Inject additional styles
|
||||
const styleSheet = document.createElement('style');
|
||||
styleSheet.textContent = additionalStyles;
|
||||
document.head.appendChild(styleSheet);
|
||||
Reference in New Issue
Block a user