Skip to main content
Glama

MCP Agent Tracker

by Big0290
context_ui_refactored.py52.6 kB
#!/usr/bin/env python3 """ Refactored Context Management UI - INTUITIVE NAVIGATION VERSION A clean, user-friendly interface with tab-based navigation and button controls """ import streamlit as st import pandas as pd import sqlite3 import json from datetime import datetime, timedelta import plotly.express as px import plotly.graph_objects as go from pathlib import Path import sys import os import time # Add current directory to Python path sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # Import our context system try: from context_manager import SeamlessContextManager CONTEXT_SYSTEM_AVAILABLE = True except ImportError as e: st.error(f"Context system not available: {e}") st.info("💡 Make sure all dependencies are installed: pip install -r requirements_ui.txt") CONTEXT_SYSTEM_AVAILABLE = False try: from models_unified import get_database_url, get_session_factory MODELS_AVAILABLE = True except ImportError as e: st.warning(f"Models not available: {e}") MODELS_AVAILABLE = False # Page configuration st.set_page_config( page_title="Context Manager", page_icon="🧠", layout="wide", initial_sidebar_state="collapsed" # Hide sidebar for cleaner look ) # Enhanced CSS for modern UI st.markdown(""" <style> /* Modern dark theme with better contrast */ .stApp { background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%) !important; } .main .block-container { background: rgba(30, 41, 59, 0.95) !important; color: #f8fafc !important; border-radius: 15px; padding: 2rem; backdrop-filter: blur(10px); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); } /* Tab styling */ .stTabs [data-baseweb="tab-list"] { gap: 8px; background: rgba(15, 23, 42, 0.8); border-radius: 12px; padding: 8px; margin-bottom: 2rem; } .stTabs [data-baseweb="tab"] { background: rgba(71, 85, 105, 0.3); border-radius: 8px; color: #cbd5e1; font-weight: 600; padding: 12px 24px; border: none; transition: all 0.3s ease; } .stTabs [aria-selected="true"] { background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%) !important; color: white !important; box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4); } /* Button styling */ .stButton > button { background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); color: white; border: none; border-radius: 8px; padding: 0.5rem 1rem; font-weight: 600; transition: all 0.3s ease; box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3); } .stButton > button:hover { background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%); transform: translateY(-2px); box-shadow: 0 4px 16px rgba(59, 130, 246, 0.4); } /* Card styling for better organization */ .metric-card { background: rgba(71, 85, 105, 0.2); border-radius: 12px; padding: 1.5rem; margin: 0.5rem 0; border: 1px solid rgba(148, 163, 184, 0.2); transition: all 0.3s ease; } .metric-card:hover { background: rgba(71, 85, 105, 0.3); border-color: rgba(59, 130, 246, 0.5); transform: translateY(-2px); } /* Filter button grid */ .filter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin: 1rem 0; } .filter-button { background: rgba(71, 85, 105, 0.3); border: 1px solid rgba(148, 163, 184, 0.3); border-radius: 8px; padding: 1rem; text-align: center; cursor: pointer; transition: all 0.3s ease; } .filter-button:hover { background: rgba(59, 130, 246, 0.2); border-color: rgba(59, 130, 246, 0.5); } .filter-button.active { background: rgba(59, 130, 246, 0.3); border-color: #3b82f6; } /* Headers */ h1, h2, h3, h4, h5, h6, p, span, div { color: #f8fafc !important; } .main-header { color: #f8fafc !important; font-size: 3rem !important; text-align: center; margin: 2rem 0; background: linear-gradient(135deg, #3b82f6, #8b5cf6); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .section-header { color: #f8fafc !important; font-size: 1.5rem !important; margin: 1.5rem 0 1rem 0; padding: 0.5rem 0; border-bottom: 2px solid rgba(59, 130, 246, 0.5); } /* Tool grid styling */ .tool-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem; margin: 2rem 0; } .tool-card { background: rgba(71, 85, 105, 0.2); border-radius: 12px; padding: 1.5rem; border: 1px solid rgba(148, 163, 184, 0.2); cursor: pointer; transition: all 0.3s ease; } .tool-card:hover { background: rgba(59, 130, 246, 0.1); border-color: rgba(59, 130, 246, 0.5); transform: translateY(-4px); box-shadow: 0 8px 24px rgba(59, 130, 246, 0.2); } .tool-card.active { background: rgba(59, 130, 246, 0.2); border-color: #3b82f6; } /* Session cards */ .session-card { background: rgba(71, 85, 105, 0.2); border-radius: 12px; padding: 1rem; margin: 0.5rem 0; border: 1px solid rgba(148, 163, 184, 0.2); cursor: pointer; transition: all 0.3s ease; } .session-card:hover { background: rgba(59, 130, 246, 0.1); border-color: rgba(59, 130, 246, 0.5); } .session-card.selected { background: rgba(59, 130, 246, 0.2); border-color: #3b82f6; } /* Viewport-based content display */ .content-display-large { min-height: 50vh; max-height: 70vh; } .content-display-medium { min-height: 30vh; max-height: 50vh; } .content-display-small { min-height: 20vh; max-height: 30vh; } /* Custom text area styling for large content */ .stTextArea > div > div > textarea { font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important; font-size: 14px !important; line-height: 1.5 !important; } /* Large content text areas */ .large-content-area textarea { min-height: 50vh !important; max-height: 70vh !important; } /* Medium content text areas */ .medium-content-area textarea { min-height: 30vh !important; max-height: 50vh !important; } /* Small content text areas */ .small-content-area textarea { min-height: 20vh !important; max-height: 30vh !important; } /* Extra large content text areas */ .extra-large-content-area textarea { min-height: 70vh !important; max-height: 85vh !important; } </style> """, unsafe_allow_html=True) def init_database_connection(): """Initialize database connection""" try: # Use unified database (agent_tracker.db) first db_path = "./data/agent_tracker.db" if os.path.exists(db_path): conn = sqlite3.connect(db_path) return conn # Fallback to local database if main doesn't exist db_path = "./data/agent_tracker_local.db" if os.path.exists(db_path): conn = sqlite3.connect(db_path) return conn return None except Exception as e: st.error(f"Database connection failed: {e}") return None def get_system_stats(conn): """Get system statistics""" if not conn: return None try: stats = {} # Total interactions result = conn.execute("SELECT COUNT(*) FROM interactions") stats['total_interactions'] = result.fetchone()[0] # Total sessions result = conn.execute("SELECT COUNT(*) FROM sessions") stats['total_sessions'] = result.fetchone()[0] # Total contexts (from interactions metadata) result = conn.execute(""" SELECT COUNT(DISTINCT session_id) FROM interactions WHERE session_id IS NOT NULL """) stats['total_contexts'] = result.fetchone()[0] # Recent activity (last hour) result = conn.execute(""" SELECT COUNT(*) FROM interactions WHERE timestamp > datetime('now', '-1 hour') """) stats['recent_activity'] = result.fetchone()[0] # Error rate result = conn.execute(""" SELECT COUNT(*) FROM interactions WHERE status = 'error' OR error_message IS NOT NULL """) error_count = result.fetchone()[0] stats['error_rate'] = error_count return stats except Exception as e: st.error(f"Error getting system stats: {e}") return None def show_dashboard_tab(): """Show main dashboard with modern cards""" st.markdown('<div class="section-header">📊 System Overview</div>', unsafe_allow_html=True) # Initialize database connection conn = init_database_connection() # Refresh button col1, col2, col3 = st.columns([2, 1, 1]) with col2: if st.button("🔄 Refresh Data", type="primary", use_container_width=True): st.rerun() with col3: auto_refresh = st.checkbox("Auto-refresh", value=False) # Get system stats stats = get_system_stats(conn) if not stats: st.warning("Unable to load system statistics") return # Metrics in cards col1, col2, col3, col4, col5 = st.columns(5) with col1: st.markdown(""" <div class="metric-card"> <h3>📊 Total Interactions</h3> <h2>{}</h2> </div> """.format(stats.get('total_interactions', 0)), unsafe_allow_html=True) with col2: st.markdown(""" <div class="metric-card"> <h3>🔄 Active Sessions</h3> <h2>{}</h2> </div> """.format(stats.get('total_sessions', 0)), unsafe_allow_html=True) with col3: st.markdown(""" <div class="metric-card"> <h3>🧠 Context Objects</h3> <h2>{}</h2> </div> """.format(stats.get('total_contexts', 0)), unsafe_allow_html=True) with col4: st.markdown(""" <div class="metric-card"> <h3>⚡ Recent Activity</h3> <h2>{}</h2> </div> """.format(stats.get('recent_activity', 0)), unsafe_allow_html=True) with col5: error_rate = stats.get('error_rate', 0) st.markdown(""" <div class="metric-card"> <h3>❌ Errors</h3> <h2>{}</h2> </div> """.format(error_rate), unsafe_allow_html=True) # Charts section st.markdown('<div class="section-header">📈 Analytics</div>', unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: # Activity timeline if conn: try: query = """ SELECT strftime('%H', timestamp) as hour, COUNT(*) as count FROM interactions WHERE timestamp > datetime('now', '-1 day') GROUP BY hour ORDER BY hour """ hourly_data = pd.read_sql(query, conn) if not hourly_data.empty: fig = px.bar(hourly_data, x='hour', y='count', title="Interactions by Hour (Last 24h)") fig.update_traces(marker_color='#3b82f6') fig.update_layout( plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', font=dict(color='#f8fafc'), title=dict(font=dict(color='#f8fafc')) ) st.plotly_chart(fig, use_container_width=True) else: st.info("No recent activity data available") except Exception as e: st.error(f"Error loading activity data: {e}") with col2: # Interaction types if conn: try: query = """ SELECT interaction_type, COUNT(*) as count FROM interactions GROUP BY interaction_type """ type_data = pd.read_sql(query, conn) if not type_data.empty: fig = px.pie(type_data, values='count', names='interaction_type', title="Interaction Type Distribution") fig.update_layout( plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', font=dict(color='#f8fafc'), title=dict(font=dict(color='#f8fafc')) ) st.plotly_chart(fig, use_container_width=True) else: st.info("No interaction type data available") except Exception as e: st.error(f"Error loading type data: {e}") def calculate_content_height(content_text, size_preference, content_type="normal"): """Calculate content height based on size preference and content""" content_lines = len(content_text.split('\n')) # Base heights for different size preferences (in pixels) size_mappings = { "Small (20% viewport)": {"min": 150, "max": 250, "line_height": 15}, "Medium (30% viewport)": {"min": 250, "max": 400, "line_height": 18}, "Large (50% viewport)": {"min": 400, "max": 600, "line_height": 20}, "Extra Large (70% viewport)": {"min": 500, "max": 800, "line_height": 22} } # Adjust for content type if content_type == "full_content": # Full content gets extra height for size in size_mappings: size_mappings[size]["max"] += 100 elif content_type == "metadata": # Metadata gets reduced height for size in size_mappings: size_mappings[size]["min"] = max(100, size_mappings[size]["min"] - 100) size_mappings[size]["max"] = max(200, size_mappings[size]["max"] - 200) settings = size_mappings.get(size_preference, size_mappings["Large (50% viewport)"]) calculated_height = max(settings["min"], min(content_lines * settings["line_height"], settings["max"])) return calculated_height def show_interactions_tab(): """Show interactions with button-based filters and full data display""" st.markdown('<div class="section-header">💬 Interactions</div>', unsafe_allow_html=True) conn = init_database_connection() if not conn: st.error("Database connection not available") return # Initialize session state for filters and pagination if 'interaction_filter' not in st.session_state: st.session_state.interaction_filter = "All" if 'status_filter' not in st.session_state: st.session_state.status_filter = "All" if 'interactions_page' not in st.session_state: st.session_state.interactions_page = 1 if 'show_full_content' not in st.session_state: st.session_state.show_full_content = True # Display options st.markdown("### ⚙️ Display Options") col1, col2, col3, col4 = st.columns(4) with col1: page_size = st.selectbox("Items per page:", [10, 25, 50, 100], index=1) with col2: st.session_state.show_full_content = st.checkbox("Show full content", value=st.session_state.show_full_content) with col3: show_metadata = st.checkbox("Show metadata", value=True) # Add content size option st.markdown("### 📐 Content Display Size") col1, col2, col3, col4 = st.columns(4) # Initialize content size preference if 'content_size' not in st.session_state: st.session_state.content_size = "Large (50% viewport)" with col1: if st.button("📏 Small (20% viewport)", type="primary" if st.session_state.content_size == "Small (20% viewport)" else "secondary", use_container_width=True): st.session_state.content_size = "Small (20% viewport)" st.rerun() with col2: if st.button("📐 Medium (30% viewport)", type="primary" if st.session_state.content_size == "Medium (30% viewport)" else "secondary", use_container_width=True): st.session_state.content_size = "Medium (30% viewport)" st.rerun() with col3: if st.button("📊 Large (50% viewport)", type="primary" if st.session_state.content_size == "Large (50% viewport)" else "secondary", use_container_width=True): st.session_state.content_size = "Large (50% viewport)" st.rerun() with col4: if st.button("📈 Extra Large (70% viewport)", type="primary" if st.session_state.content_size == "Extra Large (70% viewport)" else "secondary", use_container_width=True): st.session_state.content_size = "Extra Large (70% viewport)" st.rerun() # Refresh button in separate row col1, col2, col3, col4 = st.columns(4) with col4: if st.button("🔄 Refresh All", type="primary", use_container_width=True): st.rerun() # Filter buttons instead of dropdowns st.markdown("### 🔍 Filter Options") # Interaction type filter buttons col1, col2, col3, col4, col5, col6 = st.columns(6) with col1: if st.button("🔄 All Types", type="primary" if st.session_state.interaction_filter == "All" else "secondary", use_container_width=True): st.session_state.interaction_filter = "All" st.session_state.interactions_page = 1 st.rerun() with col2: if st.button("💬 Conversations", type="primary" if st.session_state.interaction_filter == "conversation_turn" else "secondary", use_container_width=True): st.session_state.interaction_filter = "conversation_turn" st.session_state.interactions_page = 1 st.rerun() with col3: if st.button("📤 Requests", type="primary" if st.session_state.interaction_filter == "client_request" else "secondary", use_container_width=True): st.session_state.interaction_filter = "client_request" st.session_state.interactions_page = 1 st.rerun() with col4: if st.button("📥 Responses", type="primary" if st.session_state.interaction_filter == "agent_response" else "secondary", use_container_width=True): st.session_state.interaction_filter = "agent_response" st.session_state.interactions_page = 1 st.rerun() with col5: if st.button("❌ Errors", type="primary" if st.session_state.interaction_filter == "error" else "secondary", use_container_width=True): st.session_state.interaction_filter = "error" st.session_state.interactions_page = 1 st.rerun() with col6: if st.button("🔍 Search", use_container_width=True): st.info("Search functionality - enter keywords to filter interactions") # Status filter buttons st.markdown("### 📊 Status Filter") col1, col2, col3, col4 = st.columns(4) with col1: if st.button("🔄 All Status", type="primary" if st.session_state.status_filter == "All" else "secondary", use_container_width=True): st.session_state.status_filter = "All" st.session_state.interactions_page = 1 st.rerun() with col2: if st.button("✅ Success", type="primary" if st.session_state.status_filter == "success" else "secondary", use_container_width=True): st.session_state.status_filter = "success" st.session_state.interactions_page = 1 st.rerun() with col3: if st.button("❌ Error", type="primary" if st.session_state.status_filter == "error" else "secondary", use_container_width=True): st.session_state.status_filter = "error" st.session_state.interactions_page = 1 st.rerun() with col4: if st.button("⏱️ Timeout", type="primary" if st.session_state.status_filter == "timeout" else "secondary", use_container_width=True): st.session_state.status_filter = "timeout" st.session_state.interactions_page = 1 st.rerun() # Build query based on filters base_query = "SELECT * FROM interactions WHERE 1=1" count_query = "SELECT COUNT(*) as total FROM interactions WHERE 1=1" params = [] if st.session_state.interaction_filter != "All": base_query += " AND interaction_type = ?" count_query += " AND interaction_type = ?" params.append(st.session_state.interaction_filter) if st.session_state.status_filter != "All": base_query += " AND status = ?" count_query += " AND status = ?" params.append(st.session_state.status_filter) # Get total count for pagination try: total_count = pd.read_sql(count_query, conn, params=params).iloc[0]['total'] total_pages = (total_count + page_size - 1) // page_size # Pagination controls st.markdown("### 📄 Pagination") col1, col2, col3, col4, col5 = st.columns(5) with col1: if st.button("⏮️ First", disabled=(st.session_state.interactions_page <= 1)): st.session_state.interactions_page = 1 st.rerun() with col2: if st.button("⬅️ Previous", disabled=(st.session_state.interactions_page <= 1)): st.session_state.interactions_page -= 1 st.rerun() with col3: st.write(f"Page {st.session_state.interactions_page} of {total_pages}") st.write(f"Total: {total_count} interactions") with col4: if st.button("Next ➡️", disabled=(st.session_state.interactions_page >= total_pages)): st.session_state.interactions_page += 1 st.rerun() with col5: if st.button("Last ⏭️", disabled=(st.session_state.interactions_page >= total_pages)): st.session_state.interactions_page = total_pages st.rerun() # Add pagination to query offset = (st.session_state.interactions_page - 1) * page_size base_query += f" ORDER BY timestamp DESC LIMIT {page_size} OFFSET {offset}" # Execute query and display results interactions = pd.read_sql(base_query, conn, params=params) if not interactions.empty: st.success(f"Showing {len(interactions)} of {total_count} interactions") # Display as expandable cards with full content for idx, interaction in interactions.iterrows(): # Create unique key for this interaction interaction_key = f"interaction_{interaction['id']}_{st.session_state.interactions_page}" with st.expander(f"🔄 {interaction['interaction_type']} - ID:{interaction['id']} - {interaction['timestamp'][:19]}", expanded=False): # Basic info row col1, col2, col3 = st.columns(3) with col1: st.markdown("**📋 Basic Info**") st.write(f"**ID**: {interaction['id']}") st.write(f"**Type**: {interaction['interaction_type']}") st.write(f"**Status**: {interaction['status']}") st.write(f"**Timestamp**: {interaction['timestamp']}") with col2: st.markdown("**👤 Session Info**") st.write(f"**User**: {interaction.get('user_id', 'N/A')}") session_id = interaction.get('session_id', 'N/A') if session_id != 'N/A': st.write(f"**Session**: {session_id}") else: st.write("**Session**: N/A") st.write(f"**Execution Time**: {interaction.get('execution_time_ms', 'N/A')}ms") with col3: st.markdown("**📊 Content Stats**") prompt_len = len(str(interaction.get('prompt', ''))) if interaction.get('prompt') else 0 response_len = len(str(interaction.get('response', ''))) if interaction.get('response') else 0 st.write(f"**Prompt Length**: {prompt_len:,} chars") st.write(f"**Response Length**: {response_len:,} chars") if interaction.get('error_message'): st.error(f"**Error**: {interaction['error_message']}") # Content display - NO TRUNCATION st.markdown("---") # Show full content in tabs for better organization if interaction.get('prompt') or interaction.get('response') or interaction.get('full_content'): content_tab1, content_tab2, content_tab3 = st.tabs(["📤 Prompt", "📥 Response", "📄 Full Content"]) with content_tab1: if interaction.get('prompt'): prompt_content = str(interaction['prompt']) st.markdown("**📤 Full Prompt Content:**") if st.session_state.show_full_content: # Use dynamic height calculation based on user preference content_height = calculate_content_height(prompt_content, st.session_state.content_size, "normal") content_lines = len(prompt_content.split('\n')) # Add CSS class based on size preference css_class = "large-content-area" if "Small" in st.session_state.content_size: css_class = "small-content-area" elif "Medium" in st.session_state.content_size: css_class = "medium-content-area" elif "Extra Large" in st.session_state.content_size: css_class = "extra-large-content-area" st.markdown(f'<div class="{css_class}">', unsafe_allow_html=True) st.text_area( "Complete Prompt:", prompt_content, height=content_height, key=f"prompt_full_{interaction_key}", help=f"Full prompt content ({len(prompt_content):,} characters, {content_lines:,} lines) - {st.session_state.content_size}" ) st.markdown('</div>', unsafe_allow_html=True) # Add copy button functionality if st.button(f"📋 Copy Prompt", key=f"copy_prompt_{interaction_key}"): st.info("Prompt content ready to copy (select all text above)") else: st.text_area( "Prompt Preview:", prompt_content[:200] + "..." if len(prompt_content) > 200 else prompt_content, height=100, key=f"prompt_preview_{interaction_key}" ) else: st.info("No prompt data available") with content_tab2: if interaction.get('response'): response_content = str(interaction['response']) st.markdown("**📥 Full Response Content:**") if st.session_state.show_full_content: # Use dynamic height calculation based on user preference content_height = calculate_content_height(response_content, st.session_state.content_size, "normal") content_lines = len(response_content.split('\n')) # Add CSS class based on size preference css_class = "large-content-area" if "Small" in st.session_state.content_size: css_class = "small-content-area" elif "Medium" in st.session_state.content_size: css_class = "medium-content-area" elif "Extra Large" in st.session_state.content_size: css_class = "extra-large-content-area" st.markdown(f'<div class="{css_class}">', unsafe_allow_html=True) st.text_area( "Complete Response:", response_content, height=content_height, key=f"response_full_{interaction_key}", help=f"Full response content ({len(response_content):,} characters, {content_lines:,} lines) - {st.session_state.content_size}" ) st.markdown('</div>', unsafe_allow_html=True) # Add copy button functionality if st.button(f"📋 Copy Response", key=f"copy_response_{interaction_key}"): st.info("Response content ready to copy (select all text above)") else: st.text_area( "Response Preview:", response_content[:200] + "..." if len(response_content) > 200 else response_content, height=100, key=f"response_preview_{interaction_key}" ) else: st.info("No response data available") with content_tab3: if interaction.get('full_content'): full_content = str(interaction['full_content']) st.markdown("**📄 Complete Interaction Content:**") if st.session_state.show_full_content: # Use dynamic height calculation based on user preference content_height = calculate_content_height(full_content, st.session_state.content_size, "full_content") content_lines = len(full_content.split('\n')) # Add CSS class based on size preference css_class = "large-content-area" if "Small" in st.session_state.content_size: css_class = "small-content-area" elif "Medium" in st.session_state.content_size: css_class = "medium-content-area" elif "Extra Large" in st.session_state.content_size: css_class = "extra-large-content-area" st.markdown(f'<div class="{css_class}">', unsafe_allow_html=True) st.text_area( "Full Content:", full_content, height=content_height, key=f"full_content_{interaction_key}", help=f"Complete interaction content ({len(full_content):,} characters, {content_lines:,} lines) - {st.session_state.content_size}" ) st.markdown('</div>', unsafe_allow_html=True) else: st.text_area( "Full Content Preview:", full_content[:300] + "..." if len(full_content) > 300 else full_content, height=150, key=f"full_preview_{interaction_key}" ) else: st.info("No full content data available") # Metadata display if show_metadata: st.markdown("---") st.markdown("**🔍 Additional Metadata:**") metadata_cols = ['tool_name', 'parameters', 'interaction_metadata', 'context_summary', 'client_request', 'agent_response'] metadata_found = False for col in metadata_cols: if interaction.get(col): metadata_found = True st.markdown(f"**{col.replace('_', ' ').title()}:**") # Handle JSON data if col in ['parameters', 'interaction_metadata']: try: if isinstance(interaction[col], str): parsed_data = json.loads(interaction[col]) st.json(parsed_data) else: st.json(interaction[col]) except (json.JSONDecodeError, TypeError): st.text(str(interaction[col])) else: content = str(interaction[col]) if len(content) > 500 and not st.session_state.show_full_content: st.text_area(f"{col}:", content[:500] + "...", height=150, key=f"meta_{col}_{interaction_key}") else: # Use dynamic height calculation for metadata meta_height = calculate_content_height(content, st.session_state.content_size, "metadata") # Add CSS class based on size preference css_class = "medium-content-area" # Default to medium for metadata if "Small" in st.session_state.content_size: css_class = "small-content-area" elif "Large" in st.session_state.content_size or "Extra Large" in st.session_state.content_size: css_class = "medium-content-area" # Keep metadata reasonable even for large settings st.markdown(f'<div class="{css_class}">', unsafe_allow_html=True) st.text_area(f"{col}:", content, height=meta_height, key=f"meta_full_{col}_{interaction_key}") st.markdown('</div>', unsafe_allow_html=True) if not metadata_found: st.info("No additional metadata available") else: st.info("No interactions found with the selected filters") except Exception as e: st.error(f"Error loading interactions: {e}") st.write("Debug info:", str(e)) def show_sessions_tab(): """Show sessions with card-based selection""" st.markdown('<div class="section-header">🔄 Sessions</div>', unsafe_allow_html=True) conn = init_database_connection() if not conn: st.error("Database connection not available") return # Refresh button col1, col2 = st.columns([3, 1]) with col2: if st.button("🔄 Refresh Sessions", type="primary", use_container_width=True): st.rerun() try: # Get recent sessions query = """ SELECT id, started_at, last_activity, total_interactions, user_id FROM sessions ORDER BY last_activity DESC LIMIT 20 """ sessions = pd.read_sql(query, conn) if not sessions.empty: st.success(f"Found {len(sessions)} sessions") # Display sessions as cards for idx, session in sessions.iterrows(): col1, col2, col3, col4 = st.columns(4) with col1: st.markdown(f""" <div class="session-card"> <h4>📱 Session {session['id'][:8]}...</h4> <p><strong>User:</strong> {session.get('user_id', 'N/A')}</p> <p><strong>Started:</strong> {session['started_at'][:16]}</p> <p><strong>Last Activity:</strong> {session['last_activity'][:16]}</p> <p><strong>Interactions:</strong> {session['total_interactions']}</p> </div> """, unsafe_allow_html=True) else: st.info("No sessions found") except Exception as e: st.error(f"Error loading sessions: {e}") def show_prompt_tools_tab(): """Show prompt crafting tools with grid layout""" st.markdown('<div class="section-header">🛠️ Prompt Crafting Tools</div>', unsafe_allow_html=True) # Initialize session state for tool selection if 'selected_tool' not in st.session_state: st.session_state.selected_tool = None # Tool grid instead of dropdown st.markdown("### 🔧 Available Tools") tools = [ {"id": "smart_context", "name": "🤖 Smart Context Injector", "desc": "Automatically detect tech stack and inject intelligent context"}, {"id": "basic_enhancement", "name": "📝 Basic Prompt Enhancement", "desc": "Enhance prompts with basic context injection"}, {"id": "enhanced_chat", "name": "🚀 Enhanced Chat", "desc": "Chat with AI using enhanced context"}, {"id": "realtime_context", "name": "⚡ Real-time Context", "desc": "Inject context directly into prompts"}, {"id": "auto_wrapper", "name": "🧠 Auto Context Wrapper", "desc": "Wrap prompts in context-aware structure"}, {"id": "debug_tool", "name": "🔍 MCP Server Debug", "desc": "Debug MCP server communication flow"}, {"id": "history_browser", "name": "📋 History Browser", "desc": "Browse interaction history with details"}, {"id": "analytics", "name": "📊 Prompt Analytics", "desc": "Analyze prompt performance metrics"}, {"id": "conversation_analysis", "name": "💬 Conversation Analysis", "desc": "Full visibility into Cursor agent interactions"} ] # Display tools in a grid cols = st.columns(3) for idx, tool in enumerate(tools): with cols[idx % 3]: if st.button( f"{tool['name']}\n{tool['desc']}", key=f"tool_{tool['id']}", use_container_width=True, type="primary" if st.session_state.selected_tool == tool['id'] else "secondary" ): st.session_state.selected_tool = tool['id'] st.rerun() # Show selected tool interface if st.session_state.selected_tool: st.markdown("---") if st.session_state.selected_tool == "smart_context": show_smart_context_tool() elif st.session_state.selected_tool == "basic_enhancement": show_basic_enhancement_tool() elif st.session_state.selected_tool == "enhanced_chat": show_enhanced_chat_tool() elif st.session_state.selected_tool == "realtime_context": show_realtime_context_tool() elif st.session_state.selected_tool == "auto_wrapper": show_auto_wrapper_tool() elif st.session_state.selected_tool == "debug_tool": show_debug_tool() elif st.session_state.selected_tool == "history_browser": show_history_browser_tool() elif st.session_state.selected_tool == "analytics": show_analytics_tool() elif st.session_state.selected_tool == "conversation_analysis": show_conversation_analysis_tool() def show_smart_context_tool(): """Smart context injector tool interface""" st.markdown("### 🤖 Smart Context Injector") st.info(""" **Revolutionary AI Context Enhancement** 🚀 This tool automatically detects your project's tech stack and injects intelligent, project-specific context while maintaining portable user preferences. """) # Project path input project_path = st.text_input( "Project Path:", value=os.getcwd(), help="Path to analyze for tech stack detection" ) col1, col2 = st.columns(2) with col1: if st.button("🔍 Detect Tech Stack", type="primary", use_container_width=True): with st.spinner("Analyzing project..."): # Simulate tech stack detection st.success("✅ Tech stack detected!") col1, col2, col3 = st.columns(3) with col1: st.metric("Project Type", "Python") with col2: st.metric("Framework", "Streamlit") with col3: st.metric("Database", "SQLite") with col2: if st.button("🚀 Inject Context", type="secondary", use_container_width=True): st.info("Select a message to enhance with smart context") # Message input user_message = st.text_area( "Enter your message:", placeholder="e.g., How do I optimize my database queries?", height=100 ) if user_message and st.button("✨ Enhance with Smart Context", type="primary"): with st.spinner("Enhancing with intelligent context..."): time.sleep(1) # Simulate processing st.success("Message enhanced with smart context!") enhanced = f""" === ENHANCED PROMPT WITH SMART CONTEXT === Original Message: {user_message} === DETECTED TECH STACK === - Primary Language: Python 3.x - Framework: Streamlit - Database: SQLite - Architecture: MCP (Model Context Protocol) === PROJECT CONTEXT === - Context management system with intelligent caching - Real-time conversation tracking - Advanced prompt enhancement pipeline === SMART RECOMMENDATIONS === Based on your tech stack, here are optimized suggestions for your query. === END ENHANCED PROMPT === """ st.text_area("Enhanced Prompt:", enhanced, height=300) def show_basic_enhancement_tool(): """Basic prompt enhancement tool""" st.markdown("### 📝 Basic Prompt Enhancement") user_message = st.text_area( "Enter message to enhance:", placeholder="Enter a simple message...", height=100 ) if user_message and st.button("🔧 Enhance Prompt", type="primary"): enhanced = f"Enhanced: {user_message} (with basic context injection)" st.text_area("Enhanced Prompt:", enhanced, height=150) def show_enhanced_chat_tool(): """Enhanced chat tool""" st.markdown("### 🚀 Enhanced Chat with Context") user_message = st.text_area( "Chat message:", placeholder="Enter a message to chat with enhanced context...", height=100 ) if user_message and st.button("💬 Chat with Context", type="primary"): response = f"AI Response to: {user_message}\n\n(Enhanced with conversation history and project context)" st.text_area("AI Response:", response, height=150) def show_realtime_context_tool(): """Real-time context injection tool""" st.markdown("### ⚡ Real-time Context Injection") user_message = st.text_area( "Message for context injection:", placeholder="Enter message to inject real-time context...", height=100 ) if user_message and st.button("⚡ Inject Context", type="primary"): injected = f"[CONTEXT INJECTED] {user_message} [WITH REAL-TIME DATA]" st.text_area("Context Injected:", injected, height=150) def show_auto_wrapper_tool(): """Auto context wrapper tool""" st.markdown("### 🧠 Auto Context Wrapper") user_message = st.text_area( "Message to wrap:", placeholder="Enter message to wrap in context...", height=100 ) if user_message and st.button("🧠 Wrap in Context", type="primary"): wrapped = f"=== CONTEXT WRAPPER ===\n{user_message}\n=== END WRAPPER ===" st.text_area("Wrapped Message:", wrapped, height=150) def show_debug_tool(): """MCP server debug tool""" st.markdown("### 🔍 MCP Server Debug Tool") st.info("Debug MCP server request/response flow") test_input = st.text_area( "Test input:", placeholder="Enter test input for MCP server...", height=100 ) if test_input and st.button("🔍 Debug Flow", type="primary"): st.json({ "request": test_input, "processing": "MCP server processing...", "response": f"Debug response for: {test_input}", "status": "success" }) def show_history_browser_tool(): """Interaction history browser""" st.markdown("### 📋 Interaction History Browser") conn = init_database_connection() if not conn: st.error("Database connection not available") return # Quick filter buttons col1, col2, col3 = st.columns(3) with col1: if st.button("📊 All Interactions", use_container_width=True): st.info("Showing all interactions") with col2: if st.button("💬 Conversations Only", use_container_width=True): st.info("Showing conversations only") with col3: if st.button("⚙️ System Only", use_container_width=True): st.info("Showing system interactions only") st.info("History browser interface - showing recent interactions") def show_analytics_tool(): """Prompt performance analytics""" st.markdown("### 📊 Prompt Performance Analytics") col1, col2, col3 = st.columns(3) with col1: st.metric("Total Prompts Enhanced", "150") with col2: st.metric("Avg Enhancement Ratio", "2.8x") with col3: st.metric("Success Rate", "98.5%") st.info("Analytics dashboard showing prompt enhancement performance") def show_conversation_analysis_tool(): """Conversation analysis tool""" st.markdown("### 💬 Conversation Analysis Tool") st.info("Full visibility into Cursor agent interactions") # Session selection with cards st.markdown("#### 🎯 Select Session") col1, col2, col3 = st.columns(3) with col1: if st.button("📱 Session ABC123", use_container_width=True): st.success("Selected session ABC123") with col2: if st.button("📱 Session DEF456", use_container_width=True): st.success("Selected session DEF456") with col3: if st.button("📱 Session GHI789", use_container_width=True): st.success("Selected session GHI789") def show_system_status_tab(): """Show system status with modern layout""" st.markdown('<div class="section-header">⚙️ System Status</div>', unsafe_allow_html=True) # System health cards col1, col2, col3 = st.columns(3) with col1: st.markdown(""" <div class="metric-card"> <h3>🧠 Context System</h3> <h4 style="color: #10b981;">✅ Available</h4> <p>All context systems operational</p> </div> """, unsafe_allow_html=True) with col2: st.markdown(""" <div class="metric-card"> <h3>🗄️ Database</h3> <h4 style="color: #10b981;">✅ Connected</h4> <p>SQLite database operational</p> </div> """, unsafe_allow_html=True) with col3: st.markdown(""" <div class="metric-card"> <h3>🔧 MCP Server</h3> <h4 style="color: #10b981;">✅ Running</h4> <p>Model Context Protocol active</p> </div> """, unsafe_allow_html=True) # System information st.markdown("### ℹ️ System Information") col1, col2 = st.columns(2) with col1: st.info(f""" **Environment Details:** - Python Version: {sys.version.split()[0]} - Working Directory: {os.getcwd()} - Streamlit Version: {st.__version__} """) with col2: st.info(f""" **System Status:** - Current Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - Context System: Available - Database: Connected """) def main(): """Main application with tab-based navigation""" st.markdown('<h1 class="main-header">🧠 Context Manager</h1>', unsafe_allow_html=True) # Tab-based navigation instead of sidebar dropdown tab1, tab2, tab3, tab4, tab5 = st.tabs([ "📊 Dashboard", "💬 Interactions", "🔄 Sessions", "🛠️ Prompt Tools", "⚙️ System Status" ]) with tab1: show_dashboard_tab() with tab2: show_interactions_tab() with tab3: show_sessions_tab() with tab4: show_prompt_tools_tab() with tab5: show_system_status_tab() if __name__ == "__main__": main()

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Big0290/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server