Spaces:
No application file
No application file
Timothy Eastridge
commited on
Commit
Β·
da2713e
1
Parent(s):
ead5455
clean up on seeding and system overview
Browse files- SYSTEM_OVERVIEW.md +263 -0
- app_requirements/6_feature_Streamlit.md +64 -0
- app_requirements/{6_feature_parking_lot_items.txt β 99_feature_parking_lot_items.txt} +0 -0
- ops/scripts/demo.ps1 +2 -1
- ops/scripts/fresh_start.ps1 +170 -0
- ops/scripts/fresh_start_check.py +256 -0
- ops/scripts/seed_comprehensive.py +387 -0
SYSTEM_OVERVIEW.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Graph-Driven Agentic System with Human-in-the-Loop Controls
|
| 2 |
+
|
| 3 |
+
## What This System Is
|
| 4 |
+
|
| 5 |
+
This is a **production-ready agentic workflow orchestration system** that demonstrates how to build AI agents with human oversight and complete audit trails. The system combines:
|
| 6 |
+
|
| 7 |
+
- **π€ Autonomous AI Agent**: Processes natural language queries and generates SQL
|
| 8 |
+
- **π Graph Database**: Neo4j stores all workflow metadata and audit trails
|
| 9 |
+
- **βΈοΈ Human-in-the-Loop**: Configurable pause points for human review and intervention
|
| 10 |
+
- **π― Single API Gateway**: All operations routed through MCP (Model Context Protocol) server
|
| 11 |
+
- **π Real-time Interface**: React frontend with live workflow visualization
|
| 12 |
+
- **π Complete Observability**: Every action logged with timestamps and relationships
|
| 13 |
+
|
| 14 |
+
## What It Does
|
| 15 |
+
|
| 16 |
+
### Core Workflow
|
| 17 |
+
1. **User asks a question** in natural language via the web interface
|
| 18 |
+
2. **System creates a workflow** with multiple instruction steps in Neo4j
|
| 19 |
+
3. **Agent discovers the question** and begins processing
|
| 20 |
+
4. **Pause for human review** (5 minutes by default, configurable)
|
| 21 |
+
5. **Human can edit instructions** during pause via Neo4j Browser
|
| 22 |
+
6. **Agent generates SQL** from natural language using LLM
|
| 23 |
+
7. **Agent executes SQL** against PostgreSQL database
|
| 24 |
+
8. **Results displayed** in formatted table with complete audit trail
|
| 25 |
+
|
| 26 |
+
### Architecture Components
|
| 27 |
+
```
|
| 28 |
+
βββββββββββββββ βββββββββββββββ βββββββββββββββ
|
| 29 |
+
β Frontend ββββββ MCP Server ββββββ Neo4j β
|
| 30 |
+
β (Next.js) β β (FastAPI) β β (Graph) β
|
| 31 |
+
βββββββββββββββ βββββββββββββββ βββββββββββββββ
|
| 32 |
+
β
|
| 33 |
+
βββββββββββββββ βββββββββββββββ
|
| 34 |
+
β Agent ββββββ PostgreSQL β
|
| 35 |
+
β (Python) β β (Data) β
|
| 36 |
+
βββββββββββββββ βββββββββββββββ
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
- **Neo4j Graph Database**: Stores workflows, instructions, executions, and logs
|
| 40 |
+
- **MCP Server**: FastAPI gateway for all Neo4j operations with parameter fixing
|
| 41 |
+
- **Python Agent**: Polls for instructions, pauses for human input, executes tasks
|
| 42 |
+
- **PostgreSQL**: Sample data source for SQL generation and execution
|
| 43 |
+
- **Next.js Frontend**: Chat interface with Cytoscape.js graph visualization
|
| 44 |
+
|
| 45 |
+
## Why It's Valuable
|
| 46 |
+
|
| 47 |
+
### π― **Demonstrates Production Patterns**
|
| 48 |
+
- **Human Oversight**: Shows how to build AI systems with meaningful human control
|
| 49 |
+
- **Audit Trails**: Complete graph-based logging of all operations and decisions
|
| 50 |
+
- **Error Recovery**: System continues gracefully after interruptions or edits
|
| 51 |
+
- **Scalable Architecture**: Clean separation of concerns, containerized deployment
|
| 52 |
+
|
| 53 |
+
### π **Agentic Workflow Orchestration**
|
| 54 |
+
- **Graph-Driven**: Workflows stored as connected nodes, not brittle state machines
|
| 55 |
+
- **Dynamic Editing**: Instructions can be modified during execution
|
| 56 |
+
- **Sequence Management**: Proper instruction chaining and dependency handling
|
| 57 |
+
- **Status Tracking**: Real-time visibility into workflow progress
|
| 58 |
+
|
| 59 |
+
### π‘οΈ **Human-in-the-Loop Controls**
|
| 60 |
+
- **Configurable Pauses**: Built-in review periods before critical operations
|
| 61 |
+
- **Live Editing**: Modify AI behavior during execution via graph database
|
| 62 |
+
- **Stop Controls**: Terminate workflows at any point
|
| 63 |
+
- **Parameter Updates**: Change questions, settings, or instructions mid-flight
|
| 64 |
+
|
| 65 |
+
### π **Complete Observability**
|
| 66 |
+
- **Graph Visualization**: Real-time workflow progress with color-coded status
|
| 67 |
+
- **Audit Logging**: Every MCP operation logged with timestamps
|
| 68 |
+
- **Execution Tracking**: Full history of what was generated and executed
|
| 69 |
+
- **Result Storage**: All outputs preserved in queryable graph format
|
| 70 |
+
|
| 71 |
+
### π **Production Ready**
|
| 72 |
+
- **Containerized**: Full Docker Compose setup with health checks
|
| 73 |
+
- **Environment Configuration**: Flexible .env-based configuration
|
| 74 |
+
- **Error Handling**: Graceful failures and recovery mechanisms
|
| 75 |
+
- **Documentation**: Comprehensive setup, usage, and troubleshooting guides
|
| 76 |
+
|
| 77 |
+
## How to Make It Run
|
| 78 |
+
|
| 79 |
+
### Quick Start (5 minutes)
|
| 80 |
+
|
| 81 |
+
```bash
|
| 82 |
+
# 1. Clone and navigate to the repo
|
| 83 |
+
git clone <repository-url>
|
| 84 |
+
cd <repository-name>
|
| 85 |
+
|
| 86 |
+
# 2. Copy environment template
|
| 87 |
+
cp .env.example .env
|
| 88 |
+
|
| 89 |
+
# 3. Add your LLM API key to .env
|
| 90 |
+
# Edit .env and set: LLM_API_KEY=your-openai-or-anthropic-key-here
|
| 91 |
+
|
| 92 |
+
# 4. Start everything
|
| 93 |
+
docker-compose up -d
|
| 94 |
+
|
| 95 |
+
# 5. Seed Neo4j with demo data (IMPORTANT!)
|
| 96 |
+
docker-compose exec mcp python /app/ops/scripts/seed.py
|
| 97 |
+
|
| 98 |
+
# 6. Open the interface
|
| 99 |
+
# Frontend: http://localhost:3000
|
| 100 |
+
# Neo4j Browser: http://localhost:7474 (neo4j/password)
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
### Database Seeding Options
|
| 104 |
+
|
| 105 |
+
**Basic Seeding** (Quick demo):
|
| 106 |
+
```bash
|
| 107 |
+
docker-compose exec mcp python /app/ops/scripts/seed.py
|
| 108 |
+
```
|
| 109 |
+
Creates:
|
| 110 |
+
- **Demo Workflow**: A 3-step process (discover schema β generate SQL β review results)
|
| 111 |
+
- **Query Examples**: 3 basic SQL templates for testing
|
| 112 |
+
- **Graph Structure**: Proper relationships between components
|
| 113 |
+
|
| 114 |
+
**Comprehensive Seeding** (Full system):
|
| 115 |
+
```bash
|
| 116 |
+
docker-compose exec mcp python /app/ops/scripts/seed_comprehensive.py
|
| 117 |
+
```
|
| 118 |
+
Creates:
|
| 119 |
+
- **Workflow Templates**: Multiple workflow patterns (basic query, analysis, reporting)
|
| 120 |
+
- **Instruction Type Library**: 6 different instruction types with schemas
|
| 121 |
+
- **Query Library**: 6+ categorized SQL examples (basic, analytics, detailed)
|
| 122 |
+
- **Demo Workflows**: Ready-to-run and template workflows
|
| 123 |
+
- **System Configuration**: Default settings and supported features
|
| 124 |
+
|
| 125 |
+
**β οΈ Fresh Installation**: On a brand-new machine, Neo4j starts completely empty. You MUST run a seed script to have any workflows or instructions to interact with.
|
| 126 |
+
|
| 127 |
+
**π‘ Recommendation**: Use comprehensive seeding for full system exploration, basic seeding for quick demos.
|
| 128 |
+
|
| 129 |
+
### PowerShell Fresh Start (Windows)
|
| 130 |
+
```powershell
|
| 131 |
+
# Fresh deployment with API key
|
| 132 |
+
powershell -ExecutionPolicy Bypass -File ops/scripts/fresh_start.ps1 -ApiKey "your-api-key-here"
|
| 133 |
+
|
| 134 |
+
# Or run the demo (assumes system is already running)
|
| 135 |
+
powershell -ExecutionPolicy Bypass -File ops/scripts/demo.ps1
|
| 136 |
+
```
|
| 137 |
+
|
| 138 |
+
### Manual Health Check
|
| 139 |
+
```bash
|
| 140 |
+
# Check all services
|
| 141 |
+
docker-compose ps
|
| 142 |
+
|
| 143 |
+
# Validate system
|
| 144 |
+
docker-compose exec mcp python /app/ops/scripts/validate.py
|
| 145 |
+
|
| 146 |
+
# Monitor logs
|
| 147 |
+
docker-compose logs -f agent
|
| 148 |
+
```
|
| 149 |
+
|
| 150 |
+
### Test the System
|
| 151 |
+
|
| 152 |
+
1. **Open http://localhost:3000**
|
| 153 |
+
2. **Ask a question**: "How many customers do we have?"
|
| 154 |
+
3. **Watch the workflow**:
|
| 155 |
+
- Graph visualization shows progress
|
| 156 |
+
- Agent pauses for 5 minutes
|
| 157 |
+
- You can edit instructions in Neo4j Browser
|
| 158 |
+
- Results appear in formatted table
|
| 159 |
+
|
| 160 |
+
### Clean Reset
|
| 161 |
+
```bash
|
| 162 |
+
# Stop and clean everything
|
| 163 |
+
docker-compose down
|
| 164 |
+
docker-compose up -d
|
| 165 |
+
docker-compose exec mcp python /app/ops/scripts/seed.py
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
## Key Features for Developers
|
| 169 |
+
|
| 170 |
+
### Graph Database Schema
|
| 171 |
+
- **Workflow** nodes: High-level process containers
|
| 172 |
+
- **Instruction** nodes: Individual tasks with parameters and status
|
| 173 |
+
- **Execution** nodes: Results of instruction processing
|
| 174 |
+
- **Log** nodes: Audit trail of all MCP operations
|
| 175 |
+
- **Relationships**: `HAS_INSTRUCTION`, `EXECUTED_AS`, `NEXT_INSTRUCTION`
|
| 176 |
+
|
| 177 |
+
### Configuration Options
|
| 178 |
+
- **Pause Duration**: `PAUSE_DURATION` in .env (default: 300 seconds)
|
| 179 |
+
- **Polling Interval**: `AGENT_POLL_INTERVAL` in .env (default: 30 seconds)
|
| 180 |
+
- **LLM Model**: `LLM_MODEL` in .env (gpt-4, claude-3-sonnet, etc.)
|
| 181 |
+
|
| 182 |
+
### Extension Points
|
| 183 |
+
- **New Instruction Types**: Add handlers in `agent/main.py`
|
| 184 |
+
- **Custom Data Sources**: Extend MCP server with new connectors
|
| 185 |
+
- **Frontend Customization**: Modify React components in `frontend/app/`
|
| 186 |
+
- **Workflow Templates**: Create reusable instruction sequences
|
| 187 |
+
|
| 188 |
+
### Human Intervention Examples
|
| 189 |
+
```cypher
|
| 190 |
+
// Find pending instructions
|
| 191 |
+
MATCH (i:Instruction {status: 'pending'}) RETURN i
|
| 192 |
+
|
| 193 |
+
// Change a question
|
| 194 |
+
MATCH (i:Instruction {type: 'generate_sql', status: 'pending'})
|
| 195 |
+
SET i.parameters = '{"question": "Show me top 10 customers by revenue"}'
|
| 196 |
+
|
| 197 |
+
// Stop a workflow
|
| 198 |
+
MATCH (w:Workflow {status: 'active'})
|
| 199 |
+
SET w.status = 'stopped'
|
| 200 |
+
```
|
| 201 |
+
|
| 202 |
+
## Development Setup
|
| 203 |
+
|
| 204 |
+
### Prerequisites
|
| 205 |
+
- Docker & Docker Compose
|
| 206 |
+
- OpenAI or Anthropic API key
|
| 207 |
+
- Modern web browser
|
| 208 |
+
|
| 209 |
+
### Project Structure
|
| 210 |
+
```
|
| 211 |
+
βββ agent/ # Python agent that executes instructions
|
| 212 |
+
βββ frontend/ # Next.js chat interface
|
| 213 |
+
βββ mcp/ # FastAPI server for Neo4j operations
|
| 214 |
+
βββ neo4j/ # Neo4j configuration
|
| 215 |
+
βββ postgres/ # PostgreSQL setup with sample data
|
| 216 |
+
βββ ops/scripts/ # Operational scripts (seed, validate, demo)
|
| 217 |
+
βββ docker-compose.yml
|
| 218 |
+
βββ Makefile # Convenience commands
|
| 219 |
+
βββ README.md # Detailed documentation
|
| 220 |
+
```
|
| 221 |
+
|
| 222 |
+
### Available Commands
|
| 223 |
+
```bash
|
| 224 |
+
# If you have make installed
|
| 225 |
+
make up # Start all services
|
| 226 |
+
make seed # Create demo data
|
| 227 |
+
make health # Check service health
|
| 228 |
+
make logs # View all logs
|
| 229 |
+
make clean # Reset everything
|
| 230 |
+
|
| 231 |
+
# Using docker-compose directly
|
| 232 |
+
docker-compose up -d
|
| 233 |
+
docker-compose exec mcp python /app/ops/scripts/seed.py
|
| 234 |
+
docker-compose ps
|
| 235 |
+
docker-compose logs -f
|
| 236 |
+
docker-compose down
|
| 237 |
+
```
|
| 238 |
+
|
| 239 |
+
## Use Cases
|
| 240 |
+
|
| 241 |
+
### π’ **Enterprise AI Governance**
|
| 242 |
+
- Audit trails for compliance
|
| 243 |
+
- Human oversight for critical decisions
|
| 244 |
+
- Risk management in AI operations
|
| 245 |
+
|
| 246 |
+
### π¬ **Research & Development**
|
| 247 |
+
- Experiment with agentic workflows
|
| 248 |
+
- Study human-AI collaboration patterns
|
| 249 |
+
- Prototype autonomous systems with safety controls
|
| 250 |
+
|
| 251 |
+
### π **Educational Examples**
|
| 252 |
+
- Demonstrate production AI architecture
|
| 253 |
+
- Teach graph database concepts
|
| 254 |
+
- Show containerized deployment patterns
|
| 255 |
+
|
| 256 |
+
### π οΈ **Template for New Projects**
|
| 257 |
+
- Fork as starting point for agentic systems
|
| 258 |
+
- Adapt components for specific domains
|
| 259 |
+
- Scale architecture for production workloads
|
| 260 |
+
|
| 261 |
+
---
|
| 262 |
+
|
| 263 |
+
**This system demonstrates that AI agents can be both autonomous and controllable, providing the benefits of automation while maintaining human oversight and complete transparency.**
|
app_requirements/6_feature_Streamlit.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Feature 6: Lightweight Streamlit MCP Monitor & Query Tester
|
| 2 |
+
6. Feature: Streamlit MCP Monitor & Query Tester
|
| 3 |
+
6.1 Story: As a developer, I need a lightweight Streamlit app to monitor MCP connections and test the agentic query engine.
|
| 4 |
+
|
| 5 |
+
6.1.1 Task: Create /streamlit/requirements.txt with streamlit==1.28.0, requests==2.31.0, pandas==2.1.0, python-dotenv==1.0.0 - NO neo4j driver as all Neo4j access MUST go through MCP server
|
| 6 |
+
6.1.2 Task: Create /streamlit/app.py that ONLY communicates with MCP server at http://mcp:8000/mcp, never directly to Neo4j - use st.set_page_config(page_title="MCP Monitor", layout="wide"), create two tabs using st.tabs(["π Connection Status", "π€ Query Tester"])
|
| 7 |
+
6.1.3 Task: Create /streamlit/Dockerfile with FROM python:3.11-slim, WORKDIR /app, install requirements, expose port 8501, CMD ["streamlit", "run", "app.py", "--server.address=0.0.0.0"]
|
| 8 |
+
6.1.4 Task: Add streamlit service to docker-compose.yml with build: ./streamlit, ports: 8501:8501, depends_on: mcp, environment: MCP_URL=http://mcp:8000/mcp, MCP_API_KEY=dev-key-123, explicitly NOT including NEO4J_BOLT_URL as direct access is forbidden
|
| 9 |
+
|
| 10 |
+
6.2 Story: As a user, I need to monitor the health and performance of all MCP connections in real-time.
|
| 11 |
+
|
| 12 |
+
6.2.1 Task: Create connection test function that calls MCP tools ONLY - test Neo4j via call_mcp("get_schema"), test PostgreSQL via call_mcp("query_postgres", {"query": "SELECT 1"}), never use direct database connections
|
| 13 |
+
6.2.2 Task: Display connection status in 3-column layout using st.columns(), show Neo4j (via MCP), PostgreSQL (via MCP), MCP Server status with st.metric(label, value="Online"/"Offline", delta=f"{response_ms}ms")
|
| 14 |
+
6.2.3 Task: Implement auto-refresh using st.empty() placeholder with while True loop, time.sleep(5), st.rerun() to update every 5 seconds, show "Last checked: {timestamp}" with st.caption()
|
| 15 |
+
6.2.4 Task: Add manual refresh button with st.button("π Refresh Now") that immediately re-runs all MCP-based connection tests and updates metrics
|
| 16 |
+
6.2.5 Task: Query performance stats via MCP call_mcp("query_graph", {"query": "MATCH (l:Log) WHERE l.timestamp > datetime() - duration('PT1H') RETURN count(l) as count"}), display with st.info() - emphasize this is the ONLY way to query Neo4j
|
| 17 |
+
|
| 18 |
+
6.3 Story: As a user, I need to test natural language queries through the agentic engine without using the main chat interface.
|
| 19 |
+
|
| 20 |
+
6.3.1 Task: Create query input section with st.text_area("Enter your question:", height=100), st.button("π Execute Query", type="primary") to trigger workflow creation via MCP server only
|
| 21 |
+
6.3.2 Task: On execute, create workflow via call_mcp("write_graph", {action: "create_node", label: "Workflow", properties: {...}}), then create instructions via MCP write_graph, store workflow_id in st.session_state - all graph writes MUST use MCP
|
| 22 |
+
6.3.3 Task: Poll workflow status via call_mcp("query_graph", {"query": "MATCH (i:Instruction) WHERE i.workflow_id=$id RETURN i.status", "parameters": {"id": workflow_id}}) every 2 seconds, update st.progress() based on results
|
| 23 |
+
6.3.4 Task: Fetch results via call_mcp("query_graph", {"query": "MATCH (e:Execution) WHERE e.workflow_id=$id RETURN e.result", "parameters": {"id": workflow_id}}), display SQL in st.code() and data in st.dataframe()
|
| 24 |
+
6.3.5 Task: Add "Clear Results" button that resets st.session_state.workflow_id and clears displayed results, ready for next query
|
| 25 |
+
|
| 26 |
+
6.4 Story: As a developer, I need to examine the agentic process flow to understand how answers are derived.
|
| 27 |
+
|
| 28 |
+
6.4.1 Task: Fetch execution trace via call_mcp("query_graph", {"query": "MATCH (w:Workflow {id: $id})-[:HAS_INSTRUCTION]->(i)-[:EXECUTED_AS]->(e) RETURN i, e ORDER BY i.sequence", "parameters": {"id": workflow_id}}) - this is the ONLY way to get execution data
|
| 29 |
+
6.4.2 Task: Display each step in expandable sections using st.expander(f"Step {i.sequence}: {i.type}"), show instruction parameters, execution times, and status from MCP query results
|
| 30 |
+
6.4.3 Task: For SQL generation steps, query schema context via call_mcp("query_graph", {"query": "MATCH (t:Table)-[:HAS_COLUMN]->(c:Column) RETURN t.name, collect(c.name)"}), display in st.code() to show what LLM received
|
| 31 |
+
6.4.4 Task: Show execution timeline by calculating time differences from execution nodes returned by MCP query_graph, display as: "Schema Discovery (5s) β [Pause 30s] β SQL Generation (3s) β Results (1s)"
|
| 32 |
+
6.4.5 Task: Add "View Raw Execution Data" toggle that shows full JSON response from call_mcp("query_graph", {"query": "MATCH (e:Execution {workflow_id: $id}) RETURN e"}), displayed with st.json()
|
| 33 |
+
|
| 34 |
+
6.5 Story: As a developer, I need the Streamlit app to handle errors gracefully and provide useful debugging information.
|
| 35 |
+
|
| 36 |
+
6.5.1 Task: Wrap all call_mcp() invocations in try/except blocks, on exception show st.error(f"MCP Server Error: {str(e)}") emphasizing no direct database access is possible
|
| 37 |
+
6.5.2 Task: Implement retry logic for failed MCP calls with 3 attempts and exponential backoff, show st.warning("Retrying MCP connection...") during retries, cache last successful response
|
| 38 |
+
6.5.3 Task: Add debug panel with st.expander("π§ Debug Information") showing last 5 MCP requests/responses from st.session_state.debug_log, emphasize all database operations go through MCP
|
| 39 |
+
6.5.4 Task: On workflow execution failure, query error details via call_mcp("query_graph", {"query": "MATCH (e:Execution {status: 'failed'}) RETURN e.error"}), display with suggestions for common issues
|
| 40 |
+
6.5.5 Task: Create MCP diagnostics on startup - if call_mcp("get_schema") fails, show st.error("Cannot reach Neo4j through MCP server. The app cannot directly connect to Neo4j - all access must go through MCP at {MCP_URL}")
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
Critical Implementation Notes
|
| 44 |
+
The Streamlit app MUST:
|
| 45 |
+
|
| 46 |
+
NEVER import or use neo4j Python driver
|
| 47 |
+
NEVER import or use psycopg2 directly
|
| 48 |
+
ONLY communicate with databases through MCP server endpoints
|
| 49 |
+
ALWAYS use call_mcp() for any data retrieval or storage
|
| 50 |
+
EXPLICITLY show in error messages that direct database access is not permitted
|
| 51 |
+
|
| 52 |
+
Example of CORRECT implementation:
|
| 53 |
+
python# β
CORRECT - All Neo4j access through MCP
|
| 54 |
+
def get_workflow_status(workflow_id):
|
| 55 |
+
result, _ = call_mcp("query_graph", {
|
| 56 |
+
"query": "MATCH (w:Workflow {id: $id}) RETURN w.status",
|
| 57 |
+
"parameters": {"id": workflow_id}
|
| 58 |
+
})
|
| 59 |
+
return result['data'][0]['status'] if result else None
|
| 60 |
+
Example of INCORRECT implementation:
|
| 61 |
+
python# β WRONG - Direct Neo4j access is forbidden
|
| 62 |
+
from neo4j import GraphDatabase
|
| 63 |
+
driver = GraphDatabase.driver("bolt://neo4j:7687") # NEVER DO THIS
|
| 64 |
+
This ensures the Streamlit app respects the architecture principle that all Neo4j access MUST go through the MCP server gateway, maintaining the single point of control and audit trail.
|
app_requirements/{6_feature_parking_lot_items.txt β 99_feature_parking_lot_items.txt}
RENAMED
|
File without changes
|
ops/scripts/demo.ps1
CHANGED
|
@@ -60,7 +60,8 @@ if ($agentStatus) {
|
|
| 60 |
}
|
| 61 |
|
| 62 |
Write-Host ""
|
| 63 |
-
Write-Host "Step 3: Seeding
|
|
|
|
| 64 |
docker-compose exec mcp python /app/ops/scripts/seed.py
|
| 65 |
|
| 66 |
Write-Host ""
|
|
|
|
| 60 |
}
|
| 61 |
|
| 62 |
Write-Host ""
|
| 63 |
+
Write-Host "Step 3: Seeding Neo4j database..." -ForegroundColor Blue
|
| 64 |
+
Write-Host " (This populates the empty graph with demo workflows)" -ForegroundColor Gray
|
| 65 |
docker-compose exec mcp python /app/ops/scripts/seed.py
|
| 66 |
|
| 67 |
Write-Host ""
|
ops/scripts/fresh_start.ps1
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Fresh Start Script for Graph-Driven Agentic System (Windows PowerShell)
|
| 2 |
+
# Run this script to deploy the system from scratch
|
| 3 |
+
|
| 4 |
+
param(
|
| 5 |
+
[string]$ApiKey = "",
|
| 6 |
+
[string]$Model = "gpt-4"
|
| 7 |
+
)
|
| 8 |
+
|
| 9 |
+
Write-Host "π Fresh Start Deployment" -ForegroundColor Green
|
| 10 |
+
Write-Host "=========================" -ForegroundColor Green
|
| 11 |
+
Write-Host ""
|
| 12 |
+
|
| 13 |
+
# Step 1: Check prerequisites
|
| 14 |
+
Write-Host "π Step 1: Checking prerequisites..." -ForegroundColor Blue
|
| 15 |
+
|
| 16 |
+
try {
|
| 17 |
+
docker --version | Out-Null
|
| 18 |
+
Write-Host "β
Docker found" -ForegroundColor Green
|
| 19 |
+
} catch {
|
| 20 |
+
Write-Host "β Docker not found. Please install Docker Desktop" -ForegroundColor Red
|
| 21 |
+
exit 1
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
try {
|
| 25 |
+
docker-compose --version | Out-Null
|
| 26 |
+
Write-Host "β
Docker Compose found" -ForegroundColor Green
|
| 27 |
+
} catch {
|
| 28 |
+
Write-Host "β Docker Compose not found" -ForegroundColor Red
|
| 29 |
+
exit 1
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
# Step 2: Setup environment
|
| 33 |
+
Write-Host ""
|
| 34 |
+
Write-Host "βοΈ Step 2: Setting up environment..." -ForegroundColor Blue
|
| 35 |
+
|
| 36 |
+
if (Test-Path ".env") {
|
| 37 |
+
Write-Host "β οΈ .env file already exists, backing up to .env.backup" -ForegroundColor Yellow
|
| 38 |
+
Copy-Item ".env" ".env.backup"
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
Copy-Item ".env.example" ".env"
|
| 42 |
+
Write-Host "β
Created .env from template" -ForegroundColor Green
|
| 43 |
+
|
| 44 |
+
# Update API key if provided
|
| 45 |
+
if ($ApiKey -ne "") {
|
| 46 |
+
(Get-Content ".env") -replace "LLM_API_KEY=.*", "LLM_API_KEY=$ApiKey" | Set-Content ".env"
|
| 47 |
+
(Get-Content ".env") -replace "LLM_MODEL=.*", "LLM_MODEL=$Model" | Set-Content ".env"
|
| 48 |
+
Write-Host "β
Updated LLM configuration in .env" -ForegroundColor Green
|
| 49 |
+
} else {
|
| 50 |
+
Write-Host "β οΈ No API key provided. You'll need to edit .env manually" -ForegroundColor Yellow
|
| 51 |
+
Write-Host " Add your OpenAI or Anthropic API key to the LLM_API_KEY variable" -ForegroundColor Gray
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
# Step 3: Clean existing containers
|
| 55 |
+
Write-Host ""
|
| 56 |
+
Write-Host "π§Ή Step 3: Cleaning existing containers..." -ForegroundColor Blue
|
| 57 |
+
|
| 58 |
+
docker-compose down 2>$null
|
| 59 |
+
docker system prune -f 2>$null
|
| 60 |
+
Write-Host "β
Cleaned existing containers" -ForegroundColor Green
|
| 61 |
+
|
| 62 |
+
# Step 4: Build services
|
| 63 |
+
Write-Host ""
|
| 64 |
+
Write-Host "π¨ Step 4: Building services..." -ForegroundColor Blue
|
| 65 |
+
|
| 66 |
+
docker-compose build
|
| 67 |
+
if ($LASTEXITCODE -ne 0) {
|
| 68 |
+
Write-Host "β Build failed" -ForegroundColor Red
|
| 69 |
+
exit 1
|
| 70 |
+
}
|
| 71 |
+
Write-Host "β
All services built successfully" -ForegroundColor Green
|
| 72 |
+
|
| 73 |
+
# Step 5: Start services
|
| 74 |
+
Write-Host ""
|
| 75 |
+
Write-Host "π Step 5: Starting services..." -ForegroundColor Blue
|
| 76 |
+
|
| 77 |
+
docker-compose up -d
|
| 78 |
+
if ($LASTEXITCODE -ne 0) {
|
| 79 |
+
Write-Host "β Failed to start services" -ForegroundColor Red
|
| 80 |
+
exit 1
|
| 81 |
+
}
|
| 82 |
+
Write-Host "β
All services started" -ForegroundColor Green
|
| 83 |
+
|
| 84 |
+
# Step 6: Wait for health checks
|
| 85 |
+
Write-Host ""
|
| 86 |
+
Write-Host "β³ Step 6: Waiting for services to be healthy (60 seconds)..." -ForegroundColor Blue
|
| 87 |
+
|
| 88 |
+
$healthyServices = 0
|
| 89 |
+
$maxWait = 60
|
| 90 |
+
$elapsed = 0
|
| 91 |
+
|
| 92 |
+
while ($elapsed -lt $maxWait -and $healthyServices -lt 3) {
|
| 93 |
+
Start-Sleep 5
|
| 94 |
+
$elapsed += 5
|
| 95 |
+
|
| 96 |
+
$healthyServices = 0
|
| 97 |
+
|
| 98 |
+
# Check Neo4j
|
| 99 |
+
try {
|
| 100 |
+
docker-compose exec neo4j cypher-shell -u neo4j -p password "MATCH (n) RETURN count(n) LIMIT 1" 2>$null | Out-Null
|
| 101 |
+
if ($LASTEXITCODE -eq 0) { $healthyServices++ }
|
| 102 |
+
} catch {}
|
| 103 |
+
|
| 104 |
+
# Check PostgreSQL
|
| 105 |
+
try {
|
| 106 |
+
docker-compose exec postgres pg_isready -U postgres 2>$null | Out-Null
|
| 107 |
+
if ($LASTEXITCODE -eq 0) { $healthyServices++ }
|
| 108 |
+
} catch {}
|
| 109 |
+
|
| 110 |
+
# Check MCP
|
| 111 |
+
try {
|
| 112 |
+
$response = Invoke-WebRequest -Uri "http://localhost:8000/health" -UseBasicParsing -TimeoutSec 2 2>$null
|
| 113 |
+
if ($response.StatusCode -eq 200) { $healthyServices++ }
|
| 114 |
+
} catch {}
|
| 115 |
+
|
| 116 |
+
Write-Host " Healthy services: $healthyServices/3 (${elapsed}s elapsed)" -ForegroundColor Gray
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
if ($healthyServices -eq 3) {
|
| 120 |
+
Write-Host "β
All core services are healthy" -ForegroundColor Green
|
| 121 |
+
} else {
|
| 122 |
+
Write-Host "β οΈ Some services may not be fully ready, but continuing..." -ForegroundColor Yellow
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
# Step 7: Seed database
|
| 126 |
+
Write-Host ""
|
| 127 |
+
Write-Host "π± Step 7: Seeding Neo4j database..." -ForegroundColor Blue
|
| 128 |
+
|
| 129 |
+
docker-compose exec mcp python /app/ops/scripts/seed.py
|
| 130 |
+
if ($LASTEXITCODE -eq 0) {
|
| 131 |
+
Write-Host "β
Database seeded successfully" -ForegroundColor Green
|
| 132 |
+
} else {
|
| 133 |
+
Write-Host "β Database seeding failed" -ForegroundColor Red
|
| 134 |
+
Write-Host " You can try manual seeding later with:" -ForegroundColor Gray
|
| 135 |
+
Write-Host " docker-compose exec mcp python /app/ops/scripts/seed.py" -ForegroundColor Gray
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
# Step 8: Final status check
|
| 139 |
+
Write-Host ""
|
| 140 |
+
Write-Host "π Step 8: Final status check..." -ForegroundColor Blue
|
| 141 |
+
|
| 142 |
+
docker-compose ps
|
| 143 |
+
|
| 144 |
+
# Step 9: Success message
|
| 145 |
+
Write-Host ""
|
| 146 |
+
Write-Host "π DEPLOYMENT COMPLETE!" -ForegroundColor Green
|
| 147 |
+
Write-Host "======================" -ForegroundColor Green
|
| 148 |
+
Write-Host ""
|
| 149 |
+
Write-Host "π± Access Points:" -ForegroundColor Yellow
|
| 150 |
+
Write-Host " β’ Frontend Interface: http://localhost:3000" -ForegroundColor White
|
| 151 |
+
Write-Host " β’ Neo4j Browser: http://localhost:7474" -ForegroundColor White
|
| 152 |
+
Write-Host " Login: neo4j / password" -ForegroundColor Gray
|
| 153 |
+
Write-Host ""
|
| 154 |
+
Write-Host "π§ Management Commands:" -ForegroundColor Yellow
|
| 155 |
+
Write-Host " β’ View logs: docker-compose logs -f" -ForegroundColor White
|
| 156 |
+
Write-Host " β’ Stop system: docker-compose down" -ForegroundColor White
|
| 157 |
+
Write-Host " β’ Check health: docker-compose ps" -ForegroundColor White
|
| 158 |
+
Write-Host ""
|
| 159 |
+
Write-Host "π― Quick Test:" -ForegroundColor Yellow
|
| 160 |
+
Write-Host " 1. Open http://localhost:3000" -ForegroundColor White
|
| 161 |
+
Write-Host " 2. Ask: 'How many customers do we have?'" -ForegroundColor White
|
| 162 |
+
Write-Host " 3. Watch the agent process the workflow!" -ForegroundColor White
|
| 163 |
+
Write-Host ""
|
| 164 |
+
|
| 165 |
+
if ($ApiKey -eq "") {
|
| 166 |
+
Write-Host "β οΈ REMINDER: Update your LLM API key in .env before testing!" -ForegroundColor Yellow
|
| 167 |
+
Write-Host ""
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
Write-Host "System is ready for use! π" -ForegroundColor Green
|
ops/scripts/fresh_start_check.py
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Fresh Start Validation Script
|
| 4 |
+
Checks all requirements for launching the system from scratch
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
import sys
|
| 9 |
+
import subprocess
|
| 10 |
+
import json
|
| 11 |
+
|
| 12 |
+
def check_file_exists(filepath, description):
|
| 13 |
+
"""Check if a critical file exists"""
|
| 14 |
+
if os.path.exists(filepath):
|
| 15 |
+
print(f"β
{description}: {filepath}")
|
| 16 |
+
return True
|
| 17 |
+
else:
|
| 18 |
+
print(f"β MISSING {description}: {filepath}")
|
| 19 |
+
return False
|
| 20 |
+
|
| 21 |
+
def check_docker_files():
|
| 22 |
+
"""Check all Docker-related files"""
|
| 23 |
+
print("π³ Checking Docker files...")
|
| 24 |
+
files = [
|
| 25 |
+
("docker-compose.yml", "Main orchestration file"),
|
| 26 |
+
("agent/Dockerfile", "Agent service Docker config"),
|
| 27 |
+
("mcp/Dockerfile", "MCP service Docker config"),
|
| 28 |
+
("frontend/Dockerfile", "Frontend service Docker config"),
|
| 29 |
+
("neo4j/Dockerfile", "Neo4j service Docker config"),
|
| 30 |
+
(".env.example", "Environment template")
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
all_good = True
|
| 34 |
+
for filepath, desc in files:
|
| 35 |
+
all_good &= check_file_exists(filepath, desc)
|
| 36 |
+
|
| 37 |
+
return all_good
|
| 38 |
+
|
| 39 |
+
def check_frontend_files():
|
| 40 |
+
"""Check frontend critical files"""
|
| 41 |
+
print("\nπ Checking Frontend files...")
|
| 42 |
+
files = [
|
| 43 |
+
("frontend/package.json", "Frontend dependencies"),
|
| 44 |
+
("frontend/tsconfig.json", "TypeScript config"),
|
| 45 |
+
("frontend/tailwind.config.js", "Tailwind CSS config"),
|
| 46 |
+
("frontend/next.config.js", "Next.js config"),
|
| 47 |
+
("frontend/app/page.tsx", "Main chat interface"),
|
| 48 |
+
("frontend/app/layout.tsx", "Root layout"),
|
| 49 |
+
("frontend/types/cytoscape-fcose.d.ts", "Cytoscape types")
|
| 50 |
+
]
|
| 51 |
+
|
| 52 |
+
all_good = True
|
| 53 |
+
for filepath, desc in files:
|
| 54 |
+
all_good &= check_file_exists(filepath, desc)
|
| 55 |
+
|
| 56 |
+
return all_good
|
| 57 |
+
|
| 58 |
+
def check_backend_files():
|
| 59 |
+
"""Check backend service files"""
|
| 60 |
+
print("\nπ§ Checking Backend files...")
|
| 61 |
+
files = [
|
| 62 |
+
("agent/main.py", "Agent service main file"),
|
| 63 |
+
("agent/requirements.txt", "Agent dependencies"),
|
| 64 |
+
("mcp/main.py", "MCP service main file"),
|
| 65 |
+
("mcp/requirements.txt", "MCP dependencies"),
|
| 66 |
+
("postgres/init.sql", "PostgreSQL initialization"),
|
| 67 |
+
]
|
| 68 |
+
|
| 69 |
+
all_good = True
|
| 70 |
+
for filepath, desc in files:
|
| 71 |
+
all_good &= check_file_exists(filepath, desc)
|
| 72 |
+
|
| 73 |
+
return all_good
|
| 74 |
+
|
| 75 |
+
def check_operational_files():
|
| 76 |
+
"""Check operational scripts"""
|
| 77 |
+
print("\nπ οΈ Checking Operational files...")
|
| 78 |
+
files = [
|
| 79 |
+
("ops/scripts/seed.py", "Basic seeding script"),
|
| 80 |
+
("ops/scripts/seed_comprehensive.py", "Comprehensive seeding script"),
|
| 81 |
+
("ops/scripts/validate.py", "System validation script"),
|
| 82 |
+
("ops/scripts/demo.ps1", "PowerShell demo script"),
|
| 83 |
+
("Makefile", "Build automation"),
|
| 84 |
+
("README.md", "Main documentation"),
|
| 85 |
+
("SYSTEM_OVERVIEW.md", "System overview")
|
| 86 |
+
]
|
| 87 |
+
|
| 88 |
+
all_good = True
|
| 89 |
+
for filepath, desc in files:
|
| 90 |
+
all_good &= check_file_exists(filepath, desc)
|
| 91 |
+
|
| 92 |
+
return all_good
|
| 93 |
+
|
| 94 |
+
def check_env_variables():
|
| 95 |
+
"""Check if .env.example has all required variables"""
|
| 96 |
+
print("\nβοΈ Checking Environment variables...")
|
| 97 |
+
|
| 98 |
+
if not os.path.exists(".env.example"):
|
| 99 |
+
print("β .env.example file missing")
|
| 100 |
+
return False
|
| 101 |
+
|
| 102 |
+
with open(".env.example", "r") as f:
|
| 103 |
+
env_content = f.read()
|
| 104 |
+
|
| 105 |
+
required_vars = [
|
| 106 |
+
"NEO4J_AUTH",
|
| 107 |
+
"NEO4J_BOLT_URL",
|
| 108 |
+
"POSTGRES_PASSWORD",
|
| 109 |
+
"POSTGRES_CONNECTION",
|
| 110 |
+
"MCP_API_KEYS",
|
| 111 |
+
"MCP_PORT",
|
| 112 |
+
"AGENT_POLL_INTERVAL",
|
| 113 |
+
"PAUSE_DURATION",
|
| 114 |
+
"LLM_API_KEY",
|
| 115 |
+
"LLM_MODEL"
|
| 116 |
+
]
|
| 117 |
+
|
| 118 |
+
all_good = True
|
| 119 |
+
for var in required_vars:
|
| 120 |
+
if var in env_content:
|
| 121 |
+
print(f"β
Environment variable: {var}")
|
| 122 |
+
else:
|
| 123 |
+
print(f"β MISSING environment variable: {var}")
|
| 124 |
+
all_good = False
|
| 125 |
+
|
| 126 |
+
return all_good
|
| 127 |
+
|
| 128 |
+
def check_docker_compose_structure():
|
| 129 |
+
"""Check docker-compose.yml structure"""
|
| 130 |
+
print("\nπ Checking Docker Compose structure...")
|
| 131 |
+
|
| 132 |
+
if not os.path.exists("docker-compose.yml"):
|
| 133 |
+
print("β docker-compose.yml missing")
|
| 134 |
+
return False
|
| 135 |
+
|
| 136 |
+
try:
|
| 137 |
+
import yaml
|
| 138 |
+
with open("docker-compose.yml", "r") as f:
|
| 139 |
+
compose = yaml.safe_load(f)
|
| 140 |
+
|
| 141 |
+
required_services = ["neo4j", "postgres", "mcp", "agent", "frontend"]
|
| 142 |
+
all_good = True
|
| 143 |
+
|
| 144 |
+
for service in required_services:
|
| 145 |
+
if service in compose.get("services", {}):
|
| 146 |
+
print(f"β
Service defined: {service}")
|
| 147 |
+
else:
|
| 148 |
+
print(f"β MISSING service: {service}")
|
| 149 |
+
all_good = False
|
| 150 |
+
|
| 151 |
+
return all_good
|
| 152 |
+
|
| 153 |
+
except ImportError:
|
| 154 |
+
print("β οΈ PyYAML not available, skipping structure check")
|
| 155 |
+
return True
|
| 156 |
+
except Exception as e:
|
| 157 |
+
print(f"β Error parsing docker-compose.yml: {e}")
|
| 158 |
+
return False
|
| 159 |
+
|
| 160 |
+
def check_package_json():
|
| 161 |
+
"""Check frontend package.json for required dependencies"""
|
| 162 |
+
print("\nπ¦ Checking Frontend dependencies...")
|
| 163 |
+
|
| 164 |
+
if not os.path.exists("frontend/package.json"):
|
| 165 |
+
print("β frontend/package.json missing")
|
| 166 |
+
return False
|
| 167 |
+
|
| 168 |
+
with open("frontend/package.json", "r") as f:
|
| 169 |
+
package = json.load(f)
|
| 170 |
+
|
| 171 |
+
required_deps = [
|
| 172 |
+
"next", "react", "react-dom", "typescript",
|
| 173 |
+
"cytoscape", "cytoscape-fcose", "tailwindcss"
|
| 174 |
+
]
|
| 175 |
+
|
| 176 |
+
all_deps = {**package.get("dependencies", {}), **package.get("devDependencies", {})}
|
| 177 |
+
all_good = True
|
| 178 |
+
|
| 179 |
+
for dep in required_deps:
|
| 180 |
+
if dep in all_deps:
|
| 181 |
+
print(f"β
Frontend dependency: {dep}")
|
| 182 |
+
else:
|
| 183 |
+
print(f"β MISSING frontend dependency: {dep}")
|
| 184 |
+
all_good = False
|
| 185 |
+
|
| 186 |
+
return all_good
|
| 187 |
+
|
| 188 |
+
def generate_startup_commands():
|
| 189 |
+
"""Generate the exact commands for fresh startup"""
|
| 190 |
+
print("\nπ Fresh Startup Commands:")
|
| 191 |
+
print("=" * 50)
|
| 192 |
+
print("# 1. Copy environment file")
|
| 193 |
+
print("cp .env.example .env")
|
| 194 |
+
print("")
|
| 195 |
+
print("# 2. Edit .env and add your LLM API key")
|
| 196 |
+
print("# LLM_API_KEY=your-openai-or-anthropic-key-here")
|
| 197 |
+
print("")
|
| 198 |
+
print("# 3. Clean any existing containers")
|
| 199 |
+
print("docker-compose down")
|
| 200 |
+
print("docker system prune -f")
|
| 201 |
+
print("")
|
| 202 |
+
print("# 4. Build and start services")
|
| 203 |
+
print("docker-compose build")
|
| 204 |
+
print("docker-compose up -d")
|
| 205 |
+
print("")
|
| 206 |
+
print("# 5. Wait for services to be healthy (30 seconds)")
|
| 207 |
+
print("Start-Sleep 30")
|
| 208 |
+
print("")
|
| 209 |
+
print("# 6. Seed the database")
|
| 210 |
+
print("docker-compose exec mcp python /app/ops/scripts/seed.py")
|
| 211 |
+
print("")
|
| 212 |
+
print("# 7. Open the interface")
|
| 213 |
+
print("# Frontend: http://localhost:3000")
|
| 214 |
+
print("# Neo4j Browser: http://localhost:7474 (neo4j/password)")
|
| 215 |
+
print("=" * 50)
|
| 216 |
+
|
| 217 |
+
def main():
|
| 218 |
+
print("π FRESH START VALIDATION")
|
| 219 |
+
print("========================")
|
| 220 |
+
print("")
|
| 221 |
+
|
| 222 |
+
checks = [
|
| 223 |
+
("Docker Files", check_docker_files),
|
| 224 |
+
("Frontend Files", check_frontend_files),
|
| 225 |
+
("Backend Files", check_backend_files),
|
| 226 |
+
("Operational Files", check_operational_files),
|
| 227 |
+
("Environment Variables", check_env_variables),
|
| 228 |
+
("Docker Compose Structure", check_docker_compose_structure),
|
| 229 |
+
("Frontend Dependencies", check_package_json)
|
| 230 |
+
]
|
| 231 |
+
|
| 232 |
+
all_passed = True
|
| 233 |
+
|
| 234 |
+
for check_name, check_func in checks:
|
| 235 |
+
try:
|
| 236 |
+
result = check_func()
|
| 237 |
+
all_passed &= result
|
| 238 |
+
except Exception as e:
|
| 239 |
+
print(f"β ERROR in {check_name}: {e}")
|
| 240 |
+
all_passed = False
|
| 241 |
+
|
| 242 |
+
print("\n" + "=" * 50)
|
| 243 |
+
if all_passed:
|
| 244 |
+
print("β
ALL CHECKS PASSED!")
|
| 245 |
+
print("System is ready for fresh deployment")
|
| 246 |
+
generate_startup_commands()
|
| 247 |
+
else:
|
| 248 |
+
print("β SOME CHECKS FAILED")
|
| 249 |
+
print("Please fix the missing files/configurations before deploying")
|
| 250 |
+
|
| 251 |
+
print("=" * 50)
|
| 252 |
+
return all_passed
|
| 253 |
+
|
| 254 |
+
if __name__ == "__main__":
|
| 255 |
+
success = main()
|
| 256 |
+
sys.exit(0 if success else 1)
|
ops/scripts/seed_comprehensive.py
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Comprehensive seed script for the agentic system.
|
| 4 |
+
Creates multiple workflow templates and instruction types for various scenarios.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import requests
|
| 8 |
+
import json
|
| 9 |
+
import time
|
| 10 |
+
import os
|
| 11 |
+
|
| 12 |
+
# Configuration
|
| 13 |
+
MCP_URL = os.getenv("MCP_URL", "http://localhost:8000/mcp")
|
| 14 |
+
API_KEY = os.getenv("MCP_API_KEY", "dev-key-123")
|
| 15 |
+
|
| 16 |
+
def call_mcp(tool, params=None):
|
| 17 |
+
"""Call the MCP API"""
|
| 18 |
+
response = requests.post(
|
| 19 |
+
MCP_URL,
|
| 20 |
+
headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
|
| 21 |
+
json={"tool": tool, "params": params or {}}
|
| 22 |
+
)
|
| 23 |
+
return response.json()
|
| 24 |
+
|
| 25 |
+
def create_workflow_templates():
|
| 26 |
+
"""Create different workflow templates for various use cases"""
|
| 27 |
+
print("π± Creating workflow templates...")
|
| 28 |
+
|
| 29 |
+
workflows = [
|
| 30 |
+
{
|
| 31 |
+
"id": "template-basic-query",
|
| 32 |
+
"name": "Basic Data Query",
|
| 33 |
+
"description": "Simple question-to-SQL workflow",
|
| 34 |
+
"status": "template"
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"id": "template-analysis",
|
| 38 |
+
"name": "Data Analysis Workflow",
|
| 39 |
+
"description": "Multi-step analysis with validation",
|
| 40 |
+
"status": "template"
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"id": "template-report",
|
| 44 |
+
"name": "Report Generation",
|
| 45 |
+
"description": "Generate formatted reports from data",
|
| 46 |
+
"status": "template"
|
| 47 |
+
}
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
for workflow in workflows:
|
| 51 |
+
result = call_mcp("write_graph", {
|
| 52 |
+
"action": "create_node",
|
| 53 |
+
"label": "WorkflowTemplate",
|
| 54 |
+
"properties": {
|
| 55 |
+
**workflow,
|
| 56 |
+
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
| 57 |
+
}
|
| 58 |
+
})
|
| 59 |
+
print(f"β
Created workflow template: {workflow['name']}")
|
| 60 |
+
|
| 61 |
+
def create_instruction_types():
|
| 62 |
+
"""Create instruction type definitions"""
|
| 63 |
+
print("π§ Creating instruction type definitions...")
|
| 64 |
+
|
| 65 |
+
instruction_types = [
|
| 66 |
+
{
|
| 67 |
+
"type": "discover_schema",
|
| 68 |
+
"name": "Schema Discovery",
|
| 69 |
+
"description": "Discover and analyze database schema",
|
| 70 |
+
"default_pause": 60,
|
| 71 |
+
"parameters_schema": "{}"
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"type": "generate_sql",
|
| 75 |
+
"name": "SQL Generation",
|
| 76 |
+
"description": "Convert natural language to SQL",
|
| 77 |
+
"default_pause": 300,
|
| 78 |
+
"parameters_schema": json.dumps({
|
| 79 |
+
"question": "string",
|
| 80 |
+
"context": "string (optional)"
|
| 81 |
+
})
|
| 82 |
+
},
|
| 83 |
+
{
|
| 84 |
+
"type": "execute_sql",
|
| 85 |
+
"name": "SQL Execution",
|
| 86 |
+
"description": "Execute SQL query against database",
|
| 87 |
+
"default_pause": 120,
|
| 88 |
+
"parameters_schema": json.dumps({
|
| 89 |
+
"query": "string",
|
| 90 |
+
"limit": "integer (optional)"
|
| 91 |
+
})
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"type": "validate_results",
|
| 95 |
+
"name": "Result Validation",
|
| 96 |
+
"description": "Validate and check query results",
|
| 97 |
+
"default_pause": 60,
|
| 98 |
+
"parameters_schema": json.dumps({
|
| 99 |
+
"validation_rules": "array (optional)"
|
| 100 |
+
})
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"type": "format_output",
|
| 104 |
+
"name": "Output Formatting",
|
| 105 |
+
"description": "Format results for presentation",
|
| 106 |
+
"default_pause": 30,
|
| 107 |
+
"parameters_schema": json.dumps({
|
| 108 |
+
"format": "string (table|chart|json)",
|
| 109 |
+
"title": "string (optional)"
|
| 110 |
+
})
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"type": "review_results",
|
| 114 |
+
"name": "Human Review",
|
| 115 |
+
"description": "Human review checkpoint",
|
| 116 |
+
"default_pause": 300,
|
| 117 |
+
"parameters_schema": "{}"
|
| 118 |
+
}
|
| 119 |
+
]
|
| 120 |
+
|
| 121 |
+
for inst_type in instruction_types:
|
| 122 |
+
result = call_mcp("write_graph", {
|
| 123 |
+
"action": "create_node",
|
| 124 |
+
"label": "InstructionType",
|
| 125 |
+
"properties": {
|
| 126 |
+
**inst_type,
|
| 127 |
+
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
| 128 |
+
}
|
| 129 |
+
})
|
| 130 |
+
print(f"β
Created instruction type: {inst_type['name']}")
|
| 131 |
+
|
| 132 |
+
def create_query_library():
|
| 133 |
+
"""Create a library of common queries"""
|
| 134 |
+
print("π Creating query library...")
|
| 135 |
+
|
| 136 |
+
queries = [
|
| 137 |
+
{
|
| 138 |
+
"id": "query-customer-count",
|
| 139 |
+
"category": "basic",
|
| 140 |
+
"question": "How many customers do we have?",
|
| 141 |
+
"sql": "SELECT COUNT(*) as customer_count FROM customers",
|
| 142 |
+
"description": "Total customer count"
|
| 143 |
+
},
|
| 144 |
+
{
|
| 145 |
+
"id": "query-recent-orders",
|
| 146 |
+
"category": "basic",
|
| 147 |
+
"question": "Show me recent orders",
|
| 148 |
+
"sql": "SELECT o.id, o.order_date, c.name, o.total_amount FROM orders o JOIN customers c ON o.customer_id = c.id ORDER BY o.order_date DESC LIMIT 10",
|
| 149 |
+
"description": "Last 10 orders with customer info"
|
| 150 |
+
},
|
| 151 |
+
{
|
| 152 |
+
"id": "query-revenue-total",
|
| 153 |
+
"category": "analytics",
|
| 154 |
+
"question": "What's our total revenue?",
|
| 155 |
+
"sql": "SELECT SUM(total_amount) as total_revenue FROM orders",
|
| 156 |
+
"description": "Sum of all order amounts"
|
| 157 |
+
},
|
| 158 |
+
{
|
| 159 |
+
"id": "query-top-customers",
|
| 160 |
+
"category": "analytics",
|
| 161 |
+
"question": "Who are our top customers by revenue?",
|
| 162 |
+
"sql": "SELECT c.name, c.email, SUM(o.total_amount) as total_spent FROM customers c JOIN orders o ON c.id = o.customer_id GROUP BY c.id, c.name, c.email ORDER BY total_spent DESC LIMIT 5",
|
| 163 |
+
"description": "Top 5 customers by total spending"
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"id": "query-monthly-trend",
|
| 167 |
+
"category": "analytics",
|
| 168 |
+
"question": "Show monthly revenue trend",
|
| 169 |
+
"sql": "SELECT DATE_TRUNC('month', order_date) as month, SUM(total_amount) as monthly_revenue FROM orders GROUP BY DATE_TRUNC('month', order_date) ORDER BY month",
|
| 170 |
+
"description": "Revenue by month"
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"id": "query-customer-orders",
|
| 174 |
+
"category": "detailed",
|
| 175 |
+
"question": "Show customers with their order details",
|
| 176 |
+
"sql": "SELECT c.name, c.email, o.order_date, o.total_amount, o.status FROM customers c LEFT JOIN orders o ON c.id = o.customer_id ORDER BY c.name, o.order_date DESC",
|
| 177 |
+
"description": "Customer and order details"
|
| 178 |
+
}
|
| 179 |
+
]
|
| 180 |
+
|
| 181 |
+
for query in queries:
|
| 182 |
+
result = call_mcp("write_graph", {
|
| 183 |
+
"action": "create_node",
|
| 184 |
+
"label": "QueryTemplate",
|
| 185 |
+
"properties": {
|
| 186 |
+
**query,
|
| 187 |
+
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
| 188 |
+
}
|
| 189 |
+
})
|
| 190 |
+
print(f"β
Created query: {query['description']}")
|
| 191 |
+
|
| 192 |
+
def create_demo_workflows():
|
| 193 |
+
"""Create ready-to-run demo workflows"""
|
| 194 |
+
print("π― Creating demo workflows...")
|
| 195 |
+
|
| 196 |
+
# Demo Workflow 1: Simple Query
|
| 197 |
+
workflow1 = call_mcp("write_graph", {
|
| 198 |
+
"action": "create_node",
|
| 199 |
+
"label": "Workflow",
|
| 200 |
+
"properties": {
|
| 201 |
+
"id": "demo-simple-query",
|
| 202 |
+
"name": "Simple Customer Count",
|
| 203 |
+
"description": "Demo: Count total customers",
|
| 204 |
+
"status": "active",
|
| 205 |
+
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
| 206 |
+
}
|
| 207 |
+
})
|
| 208 |
+
|
| 209 |
+
# Instructions for workflow 1
|
| 210 |
+
inst1 = call_mcp("write_graph", {
|
| 211 |
+
"action": "create_node",
|
| 212 |
+
"label": "Instruction",
|
| 213 |
+
"properties": {
|
| 214 |
+
"id": "demo-simple-1",
|
| 215 |
+
"type": "generate_sql",
|
| 216 |
+
"sequence": 1,
|
| 217 |
+
"status": "pending",
|
| 218 |
+
"pause_duration": 60, # 1 minute for demo
|
| 219 |
+
"parameters": json.dumps({"question": "How many customers do we have?"}),
|
| 220 |
+
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
| 221 |
+
}
|
| 222 |
+
})
|
| 223 |
+
|
| 224 |
+
# Link instruction to workflow
|
| 225 |
+
call_mcp("query_graph", {
|
| 226 |
+
"query": "MATCH (w:Workflow {id: 'demo-simple-query'}), (i:Instruction {id: 'demo-simple-1'}) CREATE (w)-[:HAS_INSTRUCTION]->(i)"
|
| 227 |
+
})
|
| 228 |
+
|
| 229 |
+
print("β
Created simple demo workflow")
|
| 230 |
+
|
| 231 |
+
# Demo Workflow 2: Multi-step Analysis
|
| 232 |
+
workflow2 = call_mcp("write_graph", {
|
| 233 |
+
"action": "create_node",
|
| 234 |
+
"label": "Workflow",
|
| 235 |
+
"properties": {
|
| 236 |
+
"id": "demo-analysis",
|
| 237 |
+
"name": "Customer Revenue Analysis",
|
| 238 |
+
"description": "Demo: Multi-step customer analysis",
|
| 239 |
+
"status": "template", # Not active by default
|
| 240 |
+
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
| 241 |
+
}
|
| 242 |
+
})
|
| 243 |
+
|
| 244 |
+
# Multi-step instructions
|
| 245 |
+
analysis_instructions = [
|
| 246 |
+
{
|
| 247 |
+
"id": "demo-analysis-1",
|
| 248 |
+
"type": "discover_schema",
|
| 249 |
+
"sequence": 1,
|
| 250 |
+
"description": "Discover customer and order tables",
|
| 251 |
+
"parameters": "{}"
|
| 252 |
+
},
|
| 253 |
+
{
|
| 254 |
+
"id": "demo-analysis-2",
|
| 255 |
+
"type": "generate_sql",
|
| 256 |
+
"sequence": 2,
|
| 257 |
+
"description": "Generate customer revenue query",
|
| 258 |
+
"parameters": json.dumps({"question": "Show me top customers by total revenue"})
|
| 259 |
+
},
|
| 260 |
+
{
|
| 261 |
+
"id": "demo-analysis-3",
|
| 262 |
+
"type": "review_results",
|
| 263 |
+
"sequence": 3,
|
| 264 |
+
"description": "Review results before final output",
|
| 265 |
+
"parameters": "{}"
|
| 266 |
+
}
|
| 267 |
+
]
|
| 268 |
+
|
| 269 |
+
for inst in analysis_instructions:
|
| 270 |
+
call_mcp("write_graph", {
|
| 271 |
+
"action": "create_node",
|
| 272 |
+
"label": "Instruction",
|
| 273 |
+
"properties": {
|
| 274 |
+
**inst,
|
| 275 |
+
"status": "template",
|
| 276 |
+
"pause_duration": 120,
|
| 277 |
+
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
| 278 |
+
}
|
| 279 |
+
})
|
| 280 |
+
|
| 281 |
+
# Link to workflow
|
| 282 |
+
call_mcp("query_graph", {
|
| 283 |
+
"query": "MATCH (w:Workflow {id: 'demo-analysis'}), (i:Instruction {id: $iid}) CREATE (w)-[:HAS_INSTRUCTION]->(i)",
|
| 284 |
+
"parameters": {"iid": inst["id"]}
|
| 285 |
+
})
|
| 286 |
+
|
| 287 |
+
# Create instruction chain
|
| 288 |
+
for i in range(len(analysis_instructions) - 1):
|
| 289 |
+
current = analysis_instructions[i]["id"]
|
| 290 |
+
next_inst = analysis_instructions[i + 1]["id"]
|
| 291 |
+
call_mcp("query_graph", {
|
| 292 |
+
"query": "MATCH (i1:Instruction {id: $id1}), (i2:Instruction {id: $id2}) CREATE (i1)-[:NEXT_INSTRUCTION]->(i2)",
|
| 293 |
+
"parameters": {"id1": current, "id2": next_inst}
|
| 294 |
+
})
|
| 295 |
+
|
| 296 |
+
print("β
Created multi-step analysis workflow")
|
| 297 |
+
|
| 298 |
+
def create_system_config():
|
| 299 |
+
"""Create system configuration nodes"""
|
| 300 |
+
print("βοΈ Creating system configuration...")
|
| 301 |
+
|
| 302 |
+
config = {
|
| 303 |
+
"system_version": "1.0.0",
|
| 304 |
+
"default_pause_duration": 300,
|
| 305 |
+
"max_retry_attempts": 3,
|
| 306 |
+
"default_polling_interval": 30,
|
| 307 |
+
"supported_instruction_types": json.dumps([
|
| 308 |
+
"discover_schema", "generate_sql", "execute_sql",
|
| 309 |
+
"validate_results", "format_output", "review_results"
|
| 310 |
+
]),
|
| 311 |
+
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
result = call_mcp("write_graph", {
|
| 315 |
+
"action": "create_node",
|
| 316 |
+
"label": "SystemConfig",
|
| 317 |
+
"properties": config
|
| 318 |
+
})
|
| 319 |
+
|
| 320 |
+
print("β
Created system configuration")
|
| 321 |
+
|
| 322 |
+
def verify_seeding():
|
| 323 |
+
"""Verify all seeded data"""
|
| 324 |
+
print("\nπ Verifying seeded data...")
|
| 325 |
+
|
| 326 |
+
# Count nodes by type
|
| 327 |
+
counts = call_mcp("query_graph", {
|
| 328 |
+
"query": """
|
| 329 |
+
MATCH (n)
|
| 330 |
+
RETURN labels(n)[0] as label, count(n) as count
|
| 331 |
+
ORDER BY count DESC
|
| 332 |
+
"""
|
| 333 |
+
})
|
| 334 |
+
|
| 335 |
+
print("\nπ Node Statistics:")
|
| 336 |
+
for item in counts.get("data", []):
|
| 337 |
+
print(f" - {item['label']}: {item['count']} nodes")
|
| 338 |
+
|
| 339 |
+
# Check active workflows
|
| 340 |
+
active_workflows = call_mcp("query_graph", {
|
| 341 |
+
"query": "MATCH (w:Workflow {status: 'active'}) RETURN w.name as name"
|
| 342 |
+
})
|
| 343 |
+
|
| 344 |
+
if active_workflows.get("data"):
|
| 345 |
+
print(f"\nπ― Active Workflows:")
|
| 346 |
+
for wf in active_workflows["data"]:
|
| 347 |
+
print(f" - {wf['name']}")
|
| 348 |
+
|
| 349 |
+
print(f"\nβ
Comprehensive seeding completed successfully!")
|
| 350 |
+
|
| 351 |
+
def main():
|
| 352 |
+
print("π Starting comprehensive seed process...")
|
| 353 |
+
|
| 354 |
+
# Check services first
|
| 355 |
+
try:
|
| 356 |
+
health_response = requests.get(f"{MCP_URL.replace('/mcp', '/health')}", timeout=5)
|
| 357 |
+
if health_response.status_code != 200:
|
| 358 |
+
print("β MCP service not available")
|
| 359 |
+
return False
|
| 360 |
+
except Exception as e:
|
| 361 |
+
print(f"β Service check failed: {e}")
|
| 362 |
+
return False
|
| 363 |
+
|
| 364 |
+
print("β
Services are available\n")
|
| 365 |
+
|
| 366 |
+
# Run all seeding functions
|
| 367 |
+
create_workflow_templates()
|
| 368 |
+
create_instruction_types()
|
| 369 |
+
create_query_library()
|
| 370 |
+
create_demo_workflows()
|
| 371 |
+
create_system_config()
|
| 372 |
+
verify_seeding()
|
| 373 |
+
|
| 374 |
+
print("\nπ What's Available:")
|
| 375 |
+
print("1. Open http://localhost:3000 - Frontend interface")
|
| 376 |
+
print("2. Open http://localhost:7474 - Neo4j Browser (neo4j/password)")
|
| 377 |
+
print("3. Try asking: 'How many customers do we have?'")
|
| 378 |
+
print("4. Check the 'Customer Revenue Analysis' workflow template")
|
| 379 |
+
print("5. Explore the query library for more examples")
|
| 380 |
+
|
| 381 |
+
return True
|
| 382 |
+
|
| 383 |
+
if __name__ == "__main__":
|
| 384 |
+
if main():
|
| 385 |
+
exit(0)
|
| 386 |
+
else:
|
| 387 |
+
exit(1)
|