fleet-memory/memora/web/templates/index.html
2025-11-07 16:12:59 +01:00

365 lines
23 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>Memory Graph - Live Visualization</title>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.28.1/cytoscape.min.js"></script>
<link rel="stylesheet" href="./static/css/styles.css">
</head>
<body>
<div class="breadcrumb-container">
<div class="breadcrumb">
<span class="breadcrumb-item">Memory Graph</span>
<span class="breadcrumb-separator">/</span>
<span class="breadcrumb-item">Agent:</span>
<select id="global-agent-selector" class="agent-selector">
<option value="">Select an agent...</option>
</select>
</div>
</div>
<div class="tab-container">
<div class="tab-buttons">
<button class="tab-button active" onclick="switchMainTab('data')">Data</button>
<button class="tab-button" onclick="switchMainTab('debug')">Search Debug</button>
<button class="tab-button" onclick="switchMainTab('think')">Think</button>
</div>
<!-- Data Tab -->
<div id="data-tab" class="tab-content active">
<!-- Statistics Section -->
<div id="stats-section" class="stats-section" style="display: none;">
<h3>📊 Memory Statistics</h3>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">Total Nodes</div>
<div class="stat-value" id="stat-total-nodes">-</div>
</div>
<div class="stat-card">
<div class="stat-label">World Facts</div>
<div class="stat-value" id="stat-world-nodes">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Agent Facts</div>
<div class="stat-value" id="stat-agent-nodes">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Opinions</div>
<div class="stat-value" id="stat-opinion-nodes">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Total Links</div>
<div class="stat-value" id="stat-total-links">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Temporal Links</div>
<div class="stat-value" id="stat-temporal-links">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Semantic Links</div>
<div class="stat-value" id="stat-semantic-links">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Entity Links</div>
<div class="stat-value" id="stat-entity-links">-</div>
</div>
<div class="stat-card">
<div class="stat-label">Documents</div>
<div class="stat-value" id="stat-documents">-</div>
</div>
</div>
</div>
<div class="data-sub-tabs">
<button class="data-sub-tab-button active" onclick="switchDataSubTab('world')">World</button>
<button class="data-sub-tab-button" onclick="switchDataSubTab('agent')">Agent</button>
<button class="data-sub-tab-button" onclick="switchDataSubTab('opinion')">Opinions</button>
<button class="data-sub-tab-button" onclick="switchDataSubTab('documents')">Documents</button>
</div>
<!-- World, Agent, and Opinions subtabs share the same structure -->
<div id="world-subtab" class="data-subtab-content active">
<div id="world-no-agent-message" class="no-agent-message">
<h3>No Agent Selected</h3>
<p>Please select an agent from the dropdown above to view world facts.</p>
</div>
<div id="world-content" style="display: none;">
<div class="data-controls" style="margin-bottom: 15px; padding: 10px; background: #f5f5f5; border-radius: 4px;">
<button onclick="loadDataView('world')" class="load-button">📊 Load World Facts</button>
<button onclick="loadDataView('world')" class="refresh-button">🔄 Refresh</button>
<span id="world-node-count" class="node-count"></span>
</div>
<div class="view-toggle">
<button class="view-toggle-button active" onclick="switchDataView('world', 'graph')">Graph</button>
<button class="view-toggle-button" onclick="switchDataView('world', 'table')">Table</button>
</div>
<div id="world-graph-view" class="data-view">
<div class="data-controls">
<div>
<label>Limit nodes:</label>
<input type="number" id="world-node-limit" value="50" min="10" max="1000" step="10" class="control-input">
</div>
<div>
<label>Layout:</label>
<select id="world-layout-select" class="control-select">
<option value="circle">Circle (fast)</option>
<option value="grid">Grid (fast)</option>
<option value="cose">Force-directed (slow)</option>
</select>
</div>
<button onclick="reloadDataGraph('world')" class="apply-button">Apply</button>
</div>
<div id="world-cy" class="graph-canvas"></div>
<div class="legend">
<h3>Legend</h3>
<h4>Link Types:</h4>
<div class="legend-item"><div class="legend-line temporal"></div><span><b>Temporal</b></span></div>
<div class="legend-item"><div class="legend-line semantic"></div><span><b>Semantic</b></span></div>
<div class="legend-item"><div class="legend-line entity"></div><span><b>Entity</b></span></div>
<h4>Nodes:</h4>
<div class="legend-item"><div class="legend-node no-entities"></div><span>No entities</span></div>
<div class="legend-item"><div class="legend-node one-entity"></div><span>1 entity</span></div>
<div class="legend-item"><div class="legend-node multi-entities"></div><span>2+ entities</span></div>
</div>
</div>
<div id="world-table-view" class="data-view" style="display: none;">
<input type="text" id="world-table-filter" placeholder="Search memories (text, context)..." class="table-filter">
<div class="table-container">
<table class="memory-table">
<thead>
<tr><th>ID</th><th>Text</th><th>Context</th><th>Date</th><th>Entities</th><th>Actions</th></tr>
</thead>
<tbody id="world-table-body">
<tr><td colspan="6" class="empty-message">Click "Load World Facts" to view data</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div id="agent-subtab" class="data-subtab-content">
<div id="agent-no-agent-message" class="no-agent-message">
<h3>No Agent Selected</h3>
<p>Please select an agent from the dropdown above to view agent facts.</p>
</div>
<div id="agent-content" style="display: none;">
<div class="data-controls" style="margin-bottom: 15px; padding: 10px; background: #f5f5f5; border-radius: 4px;">
<button onclick="loadDataView('agent')" class="load-button">📊 Load Agent Facts</button>
<button onclick="loadDataView('agent')" class="refresh-button">🔄 Refresh</button>
<span id="agent-node-count" class="node-count"></span>
</div>
<div class="view-toggle">
<button class="view-toggle-button active" onclick="switchDataView('agent', 'graph')">Graph</button>
<button class="view-toggle-button" onclick="switchDataView('agent', 'table')">Table</button>
</div>
<div id="agent-graph-view" class="data-view">
<div class="data-controls">
<div>
<label>Limit nodes:</label>
<input type="number" id="agent-node-limit" value="50" min="10" max="1000" step="10" class="control-input">
</div>
<div>
<label>Layout:</label>
<select id="agent-layout-select" class="control-select">
<option value="circle">Circle (fast)</option>
<option value="grid">Grid (fast)</option>
<option value="cose">Force-directed (slow)</option>
</select>
</div>
<button onclick="reloadDataGraph('agent')" class="apply-button">Apply</button>
</div>
<div id="agent-cy" class="graph-canvas"></div>
<div class="legend">
<h3>Legend</h3>
<h4>Link Types:</h4>
<div class="legend-item"><div class="legend-line temporal"></div><span><b>Temporal</b></span></div>
<div class="legend-item"><div class="legend-line semantic"></div><span><b>Semantic</b></span></div>
<div class="legend-item"><div class="legend-line entity"></div><span><b>Entity</b></span></div>
<h4>Nodes:</h4>
<div class="legend-item"><div class="legend-node no-entities"></div><span>No entities</span></div>
<div class="legend-item"><div class="legend-node one-entity"></div><span>1 entity</span></div>
<div class="legend-item"><div class="legend-node multi-entities"></div><span>2+ entities</span></div>
</div>
</div>
<div id="agent-table-view" class="data-view" style="display: none;">
<input type="text" id="agent-table-filter" placeholder="Search memories (text, context)..." class="table-filter">
<div class="table-container">
<table class="memory-table">
<thead>
<tr><th>ID</th><th>Text</th><th>Context</th><th>Date</th><th>Entities</th><th>Actions</th></tr>
</thead>
<tbody id="agent-table-body">
<tr><td colspan="6" class="empty-message">Click "Load Agent Facts" to view data</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div id="opinion-subtab" class="data-subtab-content">
<div id="opinion-no-agent-message" class="no-agent-message">
<h3>No Agent Selected</h3>
<p>Please select an agent from the dropdown above to view opinions.</p>
</div>
<div id="opinion-content" style="display: none;">
<div class="data-controls" style="margin-bottom: 15px; padding: 10px; background: #f5f5f5; border-radius: 4px;">
<button onclick="loadDataView('opinion')" class="load-button">📊 Load Opinions</button>
<button onclick="loadDataView('opinion')" class="refresh-button">🔄 Refresh</button>
<span id="opinion-node-count" class="node-count"></span>
</div>
<div class="view-toggle">
<button class="view-toggle-button active" onclick="switchDataView('opinion', 'graph')">Graph</button>
<button class="view-toggle-button" onclick="switchDataView('opinion', 'table')">Table</button>
</div>
<div id="opinion-graph-view" class="data-view">
<div class="data-controls">
<div>
<label>Limit nodes:</label>
<input type="number" id="opinion-node-limit" value="50" min="10" max="1000" step="10" class="control-input">
</div>
<div>
<label>Layout:</label>
<select id="opinion-layout-select" class="control-select">
<option value="circle">Circle (fast)</option>
<option value="grid">Grid (fast)</option>
<option value="cose">Force-directed (slow)</option>
</select>
</div>
<button onclick="reloadDataGraph('opinion')" class="apply-button">Apply</button>
</div>
<div id="opinion-cy" class="graph-canvas"></div>
<div class="legend">
<h3>Legend</h3>
<h4>Link Types:</h4>
<div class="legend-item"><div class="legend-line temporal"></div><span><b>Temporal</b></span></div>
<div class="legend-item"><div class="legend-line semantic"></div><span><b>Semantic</b></span></div>
<div class="legend-item"><div class="legend-line entity"></div><span><b>Entity</b></span></div>
<h4>Nodes:</h4>
<div class="legend-item"><div class="legend-node no-entities"></div><span>No entities</span></div>
<div class="legend-item"><div class="legend-node one-entity"></div><span>1 entity</span></div>
<div class="legend-item"><div class="legend-node multi-entities"></div><span>2+ entities</span></div>
</div>
</div>
<div id="opinion-table-view" class="data-view" style="display: none;">
<input type="text" id="opinion-table-filter" placeholder="Search memories (text, context)..." class="table-filter">
<div class="table-container">
<table class="memory-table">
<thead>
<tr><th>ID</th><th>Text</th><th>Context</th><th>Date</th><th>Entities</th><th>Actions</th></tr>
</thead>
<tbody id="opinion-table-body">
<tr><td colspan="6" class="empty-message">Click "Load Opinions" to view data</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div id="documents-subtab" class="data-subtab-content">
<div id="documents-no-agent-message" class="no-agent-message">
<h3>No Agent Selected</h3>
<p>Please select an agent from the dropdown above to view documents.</p>
</div>
<div id="documents-content" style="display: none;">
<div class="data-controls" style="margin-bottom: 15px; padding: 10px; background: #f5f5f5; border-radius: 4px;">
<button onclick="loadDocumentsView()" class="load-button">📄 Load Documents</button>
<button onclick="loadDocumentsView()" class="refresh-button">🔄 Refresh</button>
<span id="documents-count" class="node-count"></span>
</div>
<div class="data-view">
<input type="text" id="documents-filter" placeholder="Search documents (ID, metadata)..." class="table-filter">
<div class="table-container">
<table class="memory-table">
<thead>
<tr>
<th>Document ID</th>
<th>Created</th>
<th>Updated</th>
<th>Text Length</th>
<th>Memory Units</th>
<th>Metadata</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="documents-table-body">
<tr><td colspan="7" class="empty-message">Click "Load Documents" to view data</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div id="debug-tab" class="tab-content">
<h2>Search Debug</h2>
<div style="margin-bottom: 15px;">
<button class="debug-button secondary" onclick="addDebugPane()">+ Add Search Pane</button>
</div>
<div id="debug-panes-container" class="debug-container">
<!-- Debug panes will be added here dynamically -->
</div>
</div>
<div id="think-tab" class="tab-content">
<h2>Think - AI-Powered Answers</h2>
<p style="color: #666; margin-bottom: 15px;">
Ask questions and get AI-generated answers based on agent identity and world facts.
</p>
<div class="think-controls">
<div style="display: flex; gap: 15px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 15px;">
<div style="flex: 1; min-width: 300px;">
<label style="font-weight: bold; display: block; margin-bottom: 5px;">Question:</label>
<input type="text" id="think-query" placeholder="Enter your question..." style="width: 100%; padding: 10px; border: 2px solid #ccc; border-radius: 4px; font-size: 14px;">
</div>
<div>
<label style="font-weight: bold; display: block; margin-bottom: 5px;">Budget:</label>
<input type="number" id="think-budget" value="50" min="10" max="1000" style="width: 80px; padding: 10px; border: 2px solid #ccc; border-radius: 4px; font-size: 14px;">
</div>
<button id="think-button" onclick="runThink()" style="padding: 10px 24px; background: #66bb6a; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; font-size: 14px;">
💭 Think
</button>
</div>
</div>
<div id="think-result" style="display: none; margin-top: 20px;">
<div class="think-answer">
<h3 style="margin-top: 0; color: #333; border-bottom: 2px solid #333; padding-bottom: 10px;">Answer</h3>
<div id="think-answer-text" style="padding: 15px; background: #f9f9f9; border-left: 4px solid #66bb6a; font-size: 15px; line-height: 1.6; white-space: pre-wrap;"></div>
</div>
<div class="think-sources" style="margin-top: 30px;">
<h3 style="margin-top: 0; color: #333; border-bottom: 2px solid #333; padding-bottom: 10px;">Based On</h3>
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 20px; margin-top: 15px;">
<div>
<h4 style="margin: 0 0 10px 0; color: #1976d2;">World Facts (General Knowledge)</h4>
<div id="think-world-facts" style="background: #e3f2fd; padding: 15px; border-radius: 4px; border: 2px solid #1976d2; min-height: 100px;"></div>
</div>
<div>
<h4 style="margin: 0 0 10px 0; color: #f57c00;">Agent Facts (Identity)</h4>
<div id="think-agent-facts" style="background: #fff3e0; padding: 15px; border-radius: 4px; border: 2px solid #f57c00; min-height: 100px;"></div>
</div>
<div>
<h4 style="margin: 0 0 10px 0; color: #7b1fa2;">Opinions (Agent Beliefs)</h4>
<div id="think-opinions" style="background: #f3e5f5; padding: 15px; border-radius: 4px; border: 2px solid #7b1fa2; min-height: 100px;"></div>
</div>
</div>
</div>
<div id="think-new-opinions" style="display: none; margin-top: 30px;">
<div style="background: #e8f5e9; padding: 20px; border-radius: 8px; border: 2px solid #4caf50;">
<h3 style="margin-top: 0; color: #2e7d32; border-bottom: 2px solid #4caf50; padding-bottom: 10px;">✨ New Opinions Formed</h3>
<div id="think-new-opinion-list" style="margin-top: 15px;"></div>
</div>
</div>
</div>
<div id="think-loading" style="display: none; text-align: center; padding: 40px; color: #666;">
<div style="font-size: 48px; margin-bottom: 10px;">💭</div>
<div style="font-size: 18px;">Thinking...</div>
</div>
</div>
</div>
<script src="./static/js/app.js"></script>
</body>
</html>