memra 0.2.11__py3-none-any.whl → 0.2.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. memra/__init__.py +1 -1
  2. memra/cli.py +129 -9
  3. memra/demos/etl_invoice_processing/check_after_workflow.py +50 -0
  4. memra/demos/etl_invoice_processing/check_database.py +44 -0
  5. memra/demos/etl_invoice_processing/check_recent_db.py +42 -0
  6. memra/demos/etl_invoice_processing/data/README.md +112 -0
  7. memra/demos/etl_invoice_processing/data/invoices/10352259401.PDF +0 -0
  8. memra/demos/etl_invoice_processing/data/invoices/10352259823.PDF +0 -0
  9. memra/demos/etl_invoice_processing/data/invoices/10352260169.PDF +0 -0
  10. memra/demos/etl_invoice_processing/data/invoices/10352260417.PDF +0 -0
  11. memra/demos/etl_invoice_processing/data/invoices/10352260599.PDF +0 -0
  12. memra/demos/etl_invoice_processing/data/invoices/10352260912.PDF +0 -0
  13. memra/demos/etl_invoice_processing/data/invoices/10352261134.PDF +0 -0
  14. memra/demos/etl_invoice_processing/data/invoices/10352261563.PDF +0 -0
  15. memra/demos/etl_invoice_processing/data/invoices/10352261647.PDF +0 -0
  16. memra/demos/etl_invoice_processing/data/invoices/10352261720.PDF +0 -0
  17. memra/demos/etl_invoice_processing/data/invoices/10352261811.PDF +0 -0
  18. memra/demos/etl_invoice_processing/data/invoices/10352262025.PDF +0 -0
  19. memra/demos/etl_invoice_processing/data/invoices/10352262454.PDF +0 -0
  20. memra/demos/etl_invoice_processing/data/invoices/10352262702.PDF +0 -0
  21. memra/demos/etl_invoice_processing/data/invoices/10352262884.PDF +0 -0
  22. memra/demos/etl_invoice_processing/data/invoices/10352263346.PDF +0 -0
  23. memra/demos/etl_invoice_processing/data/invoices/10352263429.PDF +0 -0
  24. memra/demos/etl_invoice_processing/database_monitor_agent.py +89 -0
  25. memra/demos/etl_invoice_processing/debug_mcp.py +66 -0
  26. memra/demos/etl_invoice_processing/debug_schema.py +45 -0
  27. memra/demos/etl_invoice_processing/etl_invoice_demo.py +1233 -0
  28. memra/demos/etl_invoice_processing/modify_database.py +65 -0
  29. memra/demos/etl_invoice_processing/run_etl_batch.py +60 -0
  30. memra/demos/etl_invoice_processing/setup_demo_data.py +154 -0
  31. memra/demos/etl_invoice_processing/simple_pdf_processor.py +181 -0
  32. memra/demos/etl_invoice_processing/test_agent3.py +56 -0
  33. memra/demos/etl_invoice_processing/test_agent3_v2.py +32 -0
  34. memra/demos/etl_invoice_processing/test_api.py +28 -0
  35. memra/demos/etl_invoice_processing/test_api_client_direct.py +89 -0
  36. memra/demos/etl_invoice_processing/test_conversion.py +172 -0
  37. memra/demos/etl_invoice_processing/test_debug.py +41 -0
  38. memra/demos/etl_invoice_processing/test_direct_vision.py +114 -0
  39. memra/demos/etl_invoice_processing/test_full_response.py +22 -0
  40. memra/demos/etl_invoice_processing/test_memra_response.py +124 -0
  41. memra/demos/etl_invoice_processing/test_pdf_processor_response.py +118 -0
  42. memra/demos/etl_invoice_processing/test_pdfprocessor_direct.py +96 -0
  43. memra/demos/etl_invoice_processing/test_postgres_insert.py +120 -0
  44. memra/demos/etl_invoice_processing/test_remote_upload.py +143 -0
  45. memra/demos/etl_invoice_processing/test_schema_format.py +39 -0
  46. memra/demos/etl_invoice_processing/test_sql_executor.py +58 -0
  47. memra/demos/etl_invoice_processing/test_sql_executor_extra_fields.py +61 -0
  48. memra/demos/etl_invoice_processing/test_sql_executor_fix.py +40 -0
  49. memra/demos/etl_invoice_processing/test_updated_server.py +50 -0
  50. memra/demos/etl_invoice_processing/test_upload_functionality.py +156 -0
  51. memra/demos/etl_invoice_processing/test_upload_server.py +232 -0
  52. memra/demos/etl_invoice_processing/test_vision_output.py +75 -0
  53. memra/demos/etl_invoice_processing/test_vision_prompt.py +43 -0
  54. memra/demos/etl_invoice_processing/test_vision_simple.py +60 -0
  55. {memra-0.2.11.dist-info → memra-0.2.13.dist-info}/METADATA +53 -78
  56. memra-0.2.13.dist-info/RECORD +120 -0
  57. {memra-0.2.11.dist-info → memra-0.2.13.dist-info}/WHEEL +1 -1
  58. memra-0.2.11.dist-info/RECORD +0 -68
  59. {memra-0.2.11.dist-info/licenses → memra-0.2.13.dist-info}/LICENSE +0 -0
  60. {memra-0.2.11.dist-info → memra-0.2.13.dist-info}/entry_points.txt +0 -0
  61. {memra-0.2.11.dist-info → memra-0.2.13.dist-info}/top_level.txt +0 -0
memra/__init__.py CHANGED
@@ -6,7 +6,7 @@ Think of it as "Kubernetes for business logic" where agents are the pods and
6
6
  departments are the deployments.
7
7
  """
8
8
 
9
- __version__ = "0.2.11"
9
+ __version__ = "0.2.12"
10
10
 
11
11
  # Core imports
12
12
  from .models import Agent, Department, Tool, LLM
memra/cli.py CHANGED
@@ -79,15 +79,121 @@ def setup_demo_environment():
79
79
  def extract_bundled_files(demo_dir):
80
80
  """Extract files bundled with the PyPI package"""
81
81
  try:
82
- # Extract from package data
83
- with pkg_resources.path('memra', 'demo_files') as demo_files_path:
84
- if demo_files_path.exists():
85
- # Copy all files from the bundled demo_files directory
86
- shutil.copytree(demo_files_path, demo_dir, dirs_exist_ok=True)
82
+ import pkg_resources
83
+ import shutil
84
+ from pathlib import Path
85
+
86
+ # Extract demo files from package data
87
+ demo_dir.mkdir(exist_ok=True)
88
+
89
+ # Copy the main ETL demo script
90
+ try:
91
+ demo_script = pkg_resources.resource_filename('memra', 'demos/etl_invoice_processing/etl_invoice_demo.py')
92
+ if Path(demo_script).exists():
93
+ shutil.copy2(demo_script, demo_dir / "etl_invoice_demo.py")
94
+ print("✅ Copied ETL demo script")
95
+ else:
96
+ print("⚠️ ETL demo script not found in package")
97
+ except Exception as e:
98
+ print(f"⚠️ Could not copy ETL demo script: {e}")
99
+
100
+ # Copy supporting Python files
101
+ demo_files = [
102
+ "database_monitor_agent.py",
103
+ "simple_pdf_processor.py",
104
+ "setup_demo_data.py"
105
+ ]
106
+
107
+ for file_name in demo_files:
108
+ try:
109
+ file_path = pkg_resources.resource_filename('memra', f'demos/etl_invoice_processing/{file_name}')
110
+ if Path(file_path).exists():
111
+ shutil.copy2(file_path, demo_dir / file_name)
112
+ print(f"✅ Copied {file_name}")
113
+ else:
114
+ print(f"⚠️ {file_name} not found in package")
115
+ except Exception as e:
116
+ print(f"⚠️ Could not copy {file_name}: {e}")
117
+
118
+ # Copy sample data directory
119
+ try:
120
+ data_source = pkg_resources.resource_filename('memra', 'demos/etl_invoice_processing/data')
121
+ if Path(data_source).exists():
122
+ data_dir = demo_dir / "data"
123
+ shutil.copytree(data_source, data_dir, dirs_exist_ok=True)
124
+ print("✅ Copied sample invoice data")
87
125
  else:
88
- # Fallback: create minimal demo structure
89
- create_minimal_demo(demo_dir)
90
-
126
+ print("⚠️ Sample data not found in package")
127
+ except Exception as e:
128
+ print(f"⚠️ Could not copy sample data: {e}")
129
+
130
+ # Create memra-ops directory with docker-compose
131
+ ops_dir = demo_dir / "memra-ops"
132
+ ops_dir.mkdir(exist_ok=True)
133
+
134
+ # Create basic docker-compose.yml
135
+ compose_content = """version: '3.8'
136
+ services:
137
+ postgres:
138
+ image: postgres:15
139
+ environment:
140
+ POSTGRES_DB: local_workflow
141
+ POSTGRES_USER: postgres
142
+ POSTGRES_PASSWORD: postgres
143
+ ports:
144
+ - "5432:5432"
145
+ volumes:
146
+ - postgres_data:/var/lib/postgresql/data
147
+
148
+ volumes:
149
+ postgres_data:
150
+ """
151
+
152
+ with open(ops_dir / "docker-compose.yml", "w") as f:
153
+ f.write(compose_content)
154
+
155
+ # Create basic MCP bridge server
156
+ mcp_content = """#!/usr/bin/env python3
157
+ import asyncio
158
+ import aiohttp
159
+ from aiohttp import web
160
+ import json
161
+
162
+ async def health_handler(request):
163
+ return web.json_response({"status": "healthy"})
164
+
165
+ async def execute_tool_handler(request):
166
+ data = await request.json()
167
+ tool_name = data.get('tool_name', 'unknown')
168
+
169
+ # Mock responses for demo
170
+ if tool_name == 'SQLExecutor':
171
+ return web.json_response({
172
+ "success": True,
173
+ "results": [{"message": "Demo SQL executed"}]
174
+ })
175
+ elif tool_name == 'PostgresInsert':
176
+ return web.json_response({
177
+ "success": True,
178
+ "id": 1
179
+ })
180
+ else:
181
+ return web.json_response({
182
+ "success": True,
183
+ "message": f"Demo {tool_name} executed"
184
+ })
185
+
186
+ app = web.Application()
187
+ app.router.add_get('/health', health_handler)
188
+ app.router.add_post('/execute_tool', execute_tool_handler)
189
+
190
+ if __name__ == '__main__':
191
+ web.run_app(app, host='0.0.0.0', port=8081)
192
+ """
193
+
194
+ with open(ops_dir / "mcp_bridge_server.py", "w") as f:
195
+ f.write(mcp_content)
196
+
91
197
  except Exception as e:
92
198
  print(f"⚠️ Could not extract bundled files: {e}")
93
199
  print("Creating minimal demo structure...")
@@ -351,9 +457,23 @@ def wait_for_services():
351
457
  """Wait for services to be ready"""
352
458
  print("⏳ Waiting for PostgreSQL to be ready...")
353
459
 
354
- # Wait for PostgreSQL
460
+ # Wait for PostgreSQL - try both possible container names
355
461
  for i in range(30): # Wait up to 30 seconds
356
462
  try:
463
+ # Try the memra-ops container name first
464
+ result = subprocess.run([
465
+ 'docker', 'exec', 'memra-ops_postgres_1',
466
+ 'pg_isready', '-U', 'postgres', '-d', 'local_workflow'
467
+ ], capture_output=True, text=True)
468
+
469
+ if result.returncode == 0:
470
+ print("✅ PostgreSQL is ready")
471
+ break
472
+ except:
473
+ pass
474
+
475
+ try:
476
+ # Fallback to the old container name
357
477
  result = subprocess.run([
358
478
  'docker', 'exec', 'memra_postgres',
359
479
  'pg_isready', '-U', 'postgres', '-d', 'local_workflow'
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Check database after workflow
4
+ """
5
+
6
+ import requests
7
+ import json
8
+
9
+ def check_database_after():
10
+ """Show table contents after workflow"""
11
+
12
+ bridge_url = "http://localhost:8081"
13
+ bridge_secret = "test-secret-for-development"
14
+
15
+ headers = {
16
+ "Content-Type": "application/json",
17
+ "X-Bridge-Secret": bridge_secret
18
+ }
19
+
20
+ print("📊 Database contents AFTER workflow:")
21
+ payload = {
22
+ "tool_name": "SQLExecutor",
23
+ "input_data": {
24
+ "sql_query": "SELECT * FROM invoices ORDER BY id;"
25
+ }
26
+ }
27
+
28
+ response = requests.post(f"{bridge_url}/execute_tool", json=payload, headers=headers)
29
+ if response.status_code == 200:
30
+ result = response.json()
31
+ if result.get("success"):
32
+ data = result["data"]
33
+ print(f"Query: {data['query']}")
34
+ print(f"Total Rows: {data['row_count']}")
35
+ print("\nAll records:")
36
+ for i, row in enumerate(data['results'], 1):
37
+ print(f"\n{i}. ID: {row['id']}")
38
+ print(f" Invoice Number: {row['invoice_number']}")
39
+ print(f" Vendor: {row['vendor_name']}")
40
+ print(f" Date: {row['invoice_date']}")
41
+ print(f" Amount: ${row['total_amount']}")
42
+ print(f" Status: {row['status']}")
43
+ print(f" Created: {row['created_at']}")
44
+ else:
45
+ print(f"Error: {result.get('error')}")
46
+ else:
47
+ print(f"HTTP Error: {response.status_code}")
48
+
49
+ if __name__ == "__main__":
50
+ check_database_after()
@@ -0,0 +1,44 @@
1
+ import psycopg2
2
+ import json
3
+
4
+ try:
5
+ conn = psycopg2.connect(
6
+ host='localhost',
7
+ port=5432,
8
+ database='memra_invoice_db',
9
+ user='memra',
10
+ password='memra123'
11
+ )
12
+
13
+ cursor = conn.cursor()
14
+
15
+ # Get detailed records
16
+ cursor.execute('SELECT * FROM invoices ORDER BY created_at DESC LIMIT 5;')
17
+ rows = cursor.fetchall()
18
+
19
+ print('📄 Detailed Invoice Records:')
20
+ for row in rows:
21
+ print(f'\nID: {row[0]}')
22
+ print(f' Invoice Number: {row[1]}')
23
+ print(f' Vendor: {row[2]}')
24
+ print(f' Invoice Date: {row[3]}')
25
+ print(f' Due Date: {row[4]}')
26
+ print(f' Total Amount: ${row[5]}')
27
+ print(f' Tax Amount: ${row[6]}')
28
+ print(f' Status: {row[8]}')
29
+ print(f' Created: {row[9]}')
30
+
31
+ if row[7]: # line_items
32
+ try:
33
+ line_items = json.loads(row[7])
34
+ print(f' Line Items: {len(line_items)} items')
35
+ for i, item in enumerate(line_items[:2]): # Show first 2 items
36
+ print(f' {i+1}. {item.get("description", "N/A")} - Qty: {item.get("quantity", "N/A")} @ ${item.get("unit_price", "N/A")}')
37
+ except:
38
+ print(f' Line Items: {row[7]}')
39
+
40
+ cursor.close()
41
+ conn.close()
42
+
43
+ except Exception as e:
44
+ print(f'❌ Database connection failed: {e}')
@@ -0,0 +1,42 @@
1
+ import psycopg2
2
+ from datetime import datetime
3
+
4
+ # Database connection
5
+ conn = psycopg2.connect(
6
+ host="localhost",
7
+ database="local_workflow",
8
+ user="postgres",
9
+ password="postgres",
10
+ port=5433
11
+ )
12
+
13
+ try:
14
+ with conn.cursor() as cur:
15
+ # Get the 10 most recent records
16
+ cur.execute("""
17
+ SELECT id, vendor_name, invoice_number, invoice_date, due_date,
18
+ total_amount, tax_amount, created_at
19
+ FROM invoices
20
+ ORDER BY id DESC
21
+ LIMIT 10
22
+ """)
23
+
24
+ records = cur.fetchall()
25
+
26
+ if records:
27
+ print("🔍 Most Recent Invoice Records:\n")
28
+ for record in records:
29
+ id, vendor, invoice_num, inv_date, due_date, total, tax, created = record
30
+ print(f"ID: {id} (Created: {created})")
31
+ print(f" Vendor: {vendor}")
32
+ print(f" Invoice #: {invoice_num}")
33
+ print(f" Invoice Date: {inv_date}")
34
+ print(f" Due Date: {due_date}")
35
+ print(f" Total: ${total:.2f}")
36
+ print(f" Tax: ${tax:.2f}")
37
+ print("-" * 40)
38
+ else:
39
+ print("No records found in database")
40
+
41
+ finally:
42
+ conn.close()
@@ -0,0 +1,112 @@
1
+ # Demo Data Files
2
+
3
+ This directory contains sample data files for the ETL Invoice Processing demo.
4
+
5
+ ## 📁 Directory Structure
6
+
7
+ ```
8
+ data/
9
+ ├── invoices/ # PDF invoice files for processing
10
+ │ ├── invoice_001.pdf
11
+ │ ├── invoice_002.pdf
12
+ │ └── ...
13
+ └── README.md # This file
14
+ ```
15
+
16
+ ## 📄 Invoice Files
17
+
18
+ The `invoices/` directory contains sample PDF invoice files that demonstrate:
19
+
20
+ - **Various invoice formats** from different vendors
21
+ - **Different data structures** (line items, totals, tax calculations)
22
+ - **Real-world scenarios** (missing data, edge cases)
23
+ - **Multiple currencies** and payment terms
24
+
25
+ ## 🚀 Using the Demo Data
26
+
27
+ ### Option 1: Auto-Discovery (Recommended)
28
+ The demo will automatically scan the `invoices/` directory:
29
+
30
+ ```python
31
+ # The demo will find and process all PDF files
32
+ python etl_invoice_demo.py
33
+ ```
34
+
35
+ ### Option 2: Specific File Processing
36
+ Process a specific invoice file:
37
+
38
+ ```python
39
+ # Update the demo to process a specific file
40
+ input_data = {
41
+ "invoice_file": "data/invoices/invoice_001.pdf",
42
+ "connection": "postgresql://memra:memra123@localhost:5432/memra_invoice_db"
43
+ }
44
+ ```
45
+
46
+ ### Option 3: External File Processing
47
+ Copy files from external locations:
48
+
49
+ ```python
50
+ # The demo can copy files from Downloads or other locations
51
+ input_data = {
52
+ "source_path": "~/Downloads/new_invoice.pdf",
53
+ "connection": "postgresql://memra:memra123@localhost:5432/memra_invoice_db"
54
+ }
55
+ ```
56
+
57
+ ## 📊 Expected Data Structure
58
+
59
+ Each invoice file should contain:
60
+
61
+ - **Vendor Information**: Company name, address, contact details
62
+ - **Invoice Details**: Invoice number, date, due date
63
+ - **Line Items**: Description, quantity, unit price, total
64
+ - **Totals**: Subtotal, tax, shipping, grand total
65
+ - **Payment Terms**: Due date, payment methods
66
+
67
+ ## 🔧 Customizing the Data
68
+
69
+ ### Adding New Invoice Files
70
+ 1. Place new PDF files in the `invoices/` directory
71
+ 2. Ensure they follow the expected invoice format
72
+ 3. Test with the demo to verify processing
73
+
74
+ ### Modifying Existing Files
75
+ - Files are processed using AI vision models
76
+ - No specific format requirements
77
+ - The system adapts to different invoice layouts
78
+
79
+ ## 📈 Demo Scenarios
80
+
81
+ The included files demonstrate:
82
+
83
+ | Scenario | Description |
84
+ |----------|-------------|
85
+ | **Standard Invoice** | Typical business invoice with line items |
86
+ | **Complex Invoice** | Multiple pages, detailed line items |
87
+ | **Simple Invoice** | Basic invoice with minimal details |
88
+ | **International** | Different currencies and formats |
89
+ | **Edge Cases** | Missing data, unusual formats |
90
+
91
+ ## 🚨 Important Notes
92
+
93
+ - **File Size**: Each file is approximately 1MB
94
+ - **Total Size**: ~20MB for all demo files
95
+ - **Git LFS**: Not required for these file sizes
96
+ - **Version Control**: Files are tracked in Git for demo consistency
97
+
98
+ ## 🔄 Updating Demo Data
99
+
100
+ When adding new invoice files:
101
+
102
+ 1. **Test locally** first
103
+ 2. **Verify processing** with the demo
104
+ 3. **Update this README** if adding new scenarios
105
+ 4. **Commit changes** with descriptive messages
106
+
107
+ ## 📚 Related Documentation
108
+
109
+ - [ETL Demo Guide](../README.md)
110
+ - [Database Schema](../../../docs/database_schema.sql)
111
+ - [Sample Data](../../../docs/sample_data.sql)
112
+ - [Quick Start Guide](../../../QUICK_START.md)
@@ -0,0 +1,89 @@
1
+ """
2
+ Database Monitor Agent
3
+ Monitors database state before and after ETL processes
4
+ """
5
+
6
+ from memra import Agent, LLM
7
+
8
+ def create_database_monitor_agent():
9
+ """Create a database monitoring agent"""
10
+
11
+ monitor_llm = LLM(
12
+ model="llama-3.2-11b-vision-preview",
13
+ temperature=0.1,
14
+ max_tokens=1000
15
+ )
16
+
17
+ monitor_agent = Agent(
18
+ role="Database Monitor",
19
+ job="Monitor database state and validate data integrity",
20
+ llm=monitor_llm,
21
+ sops=[
22
+ "Connect to database using provided credentials",
23
+ "Execute monitoring queries to count rows and validate data",
24
+ "Generate comprehensive monitoring report with statistics",
25
+ "Flag any data integrity issues or anomalies",
26
+ "Return structured monitoring results"
27
+ ],
28
+ systems=["Database"],
29
+ tools=[
30
+ {"name": "SQLExecutor", "hosted_by": "mcp"}
31
+ ],
32
+ input_keys=["table_name", "connection", "monitoring_phase"],
33
+ output_key="monitoring_report"
34
+ )
35
+
36
+ return monitor_agent
37
+
38
+ def get_monitoring_queries(table_name: str, phase: str):
39
+ """Get appropriate SQL queries for monitoring phase"""
40
+
41
+ queries = {
42
+ "before": [
43
+ f"SELECT COUNT(*) as row_count FROM {table_name}",
44
+ f"SELECT COUNT(*) as null_vendor_count FROM {table_name} WHERE vendor_name IS NULL",
45
+ f"SELECT COUNT(*) as null_invoice_count FROM {table_name} WHERE invoice_number IS NULL",
46
+ f"SELECT COUNT(*) as null_amount_count FROM {table_name} WHERE total_amount IS NULL"
47
+ ],
48
+ "after": [
49
+ f"SELECT COUNT(*) as row_count FROM {table_name}",
50
+ f"SELECT COUNT(*) as null_vendor_count FROM {table_name} WHERE vendor_name IS NULL",
51
+ f"SELECT COUNT(*) as null_invoice_count FROM {table_name} WHERE invoice_number IS NULL",
52
+ f"SELECT COUNT(*) as null_amount_count FROM {table_name} WHERE total_amount IS NULL",
53
+ f"SELECT COUNT(*) as duplicate_invoices FROM (SELECT invoice_number, COUNT(*) as cnt FROM {table_name} GROUP BY invoice_number HAVING COUNT(*) > 1) as dups",
54
+ f"SELECT MIN(total_amount) as min_amount, MAX(total_amount) as max_amount, AVG(total_amount) as avg_amount FROM {table_name}",
55
+ f"SELECT COUNT(*) as recent_records FROM {table_name} WHERE created_at >= NOW() - INTERVAL '1 hour'"
56
+ ]
57
+ }
58
+
59
+ return queries.get(phase, queries["after"])
60
+
61
+ def create_simple_monitor_agent():
62
+ """Create a simple database monitoring agent that works with the framework"""
63
+
64
+ monitor_llm = LLM(
65
+ model="llama-3.2-11b-vision-preview",
66
+ temperature=0.1,
67
+ max_tokens=1500
68
+ )
69
+
70
+ monitor_agent = Agent(
71
+ role="Database Monitor",
72
+ job="Monitor database state and validate data integrity",
73
+ llm=monitor_llm,
74
+ sops=[
75
+ "Connect to database using provided credentials",
76
+ "Execute monitoring query using sql_query input",
77
+ "Generate monitoring report with current statistics",
78
+ "Flag any data integrity issues",
79
+ "Return structured monitoring results"
80
+ ],
81
+ systems=["Database"],
82
+ tools=[
83
+ {"name": "SQLExecutor", "hosted_by": "mcp", "input_keys": ["sql_query"]}
84
+ ],
85
+ input_keys=["table_name", "connection", "monitoring_phase", "sql_query"],
86
+ output_key="monitoring_report"
87
+ )
88
+
89
+ return monitor_agent
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Debug script to test MCP bridge connection
4
+ """
5
+
6
+ import httpx
7
+ import json
8
+ import logging
9
+
10
+ # Set up logging
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ def test_mcp_bridge():
15
+ """Test MCP bridge connection using httpx"""
16
+
17
+ bridge_url = "http://localhost:8081"
18
+ bridge_secret = "test-secret-for-development"
19
+
20
+ # Prepare request
21
+ payload = {
22
+ "tool_name": "SQLExecutor",
23
+ "input_data": {
24
+ "sql_query": "SELECT COUNT(*) as row_count FROM invoices"
25
+ }
26
+ }
27
+
28
+ headers = {
29
+ "Content-Type": "application/json",
30
+ "X-Bridge-Secret": bridge_secret
31
+ }
32
+
33
+ logger.info(f"Testing MCP bridge at {bridge_url}")
34
+ logger.info(f"Payload: {json.dumps(payload, indent=2)}")
35
+ logger.info(f"Headers: {headers}")
36
+
37
+ try:
38
+ with httpx.Client(timeout=60.0) as client:
39
+ logger.info("Making HTTP request...")
40
+ response = client.post(f"{bridge_url}/execute_tool", json=payload, headers=headers)
41
+
42
+ logger.info(f"Response status: {response.status_code}")
43
+ logger.info(f"Response headers: {dict(response.headers)}")
44
+
45
+ if response.status_code == 200:
46
+ result = response.json()
47
+ logger.info(f"Success! Result: {json.dumps(result, indent=2)}")
48
+ return True
49
+ else:
50
+ logger.error(f"HTTP error: {response.status_code}")
51
+ logger.error(f"Response text: {response.text}")
52
+ return False
53
+
54
+ except httpx.TimeoutException:
55
+ logger.error("Request timed out")
56
+ return False
57
+ except httpx.HTTPStatusError as e:
58
+ logger.error(f"HTTP error: {e.response.status_code} - {e.response.text}")
59
+ return False
60
+ except Exception as e:
61
+ logger.error(f"Unexpected error: {str(e)}")
62
+ return False
63
+
64
+ if __name__ == "__main__":
65
+ success = test_mcp_bridge()
66
+ print(f"\n{'✅ SUCCESS' if success else '❌ FAILED'}")
@@ -0,0 +1,45 @@
1
+ import os
2
+ import requests
3
+ import json
4
+
5
+ api_url = "https://api.memra.co"
6
+ api_key = os.getenv("MEMRA_API_KEY", "test-secret-for-development")
7
+
8
+ # Test the exact format we're sending
9
+ schema = {
10
+ "columns": [
11
+ {"name": "invoice_number", "type": "character varying"},
12
+ {"name": "vendor_name", "type": "character varying"},
13
+ {"name": "invoice_date", "type": "date"},
14
+ {"name": "total_amount", "type": "numeric"}
15
+ ]
16
+ }
17
+
18
+ print("Schema being sent:")
19
+ print(json.dumps(schema, indent=2))
20
+
21
+ resp = requests.post(
22
+ f"{api_url}/tools/execute",
23
+ json={
24
+ "tool_name": "PDFProcessor",
25
+ "hosted_by": "memra",
26
+ "input_data": {
27
+ "file": "/uploads/6f4538c0-8fce-4488-be49-1a78afc58a4a.pdf",
28
+ "schema": schema
29
+ }
30
+ },
31
+ headers={"X-API-Key": api_key}
32
+ )
33
+
34
+ print(f"\nResponse status: {resp.status_code}")
35
+ if resp.status_code == 200:
36
+ result = resp.json()
37
+ if result.get('success') and 'data' in result and 'data' in result['data']:
38
+ data = result['data']['data']
39
+ print(f"\nVision prompt length: {len(data.get('vision_prompt', ''))}")
40
+ print("Vision prompt preview:")
41
+ print(data.get('vision_prompt', '')[:500])
42
+
43
+ # Check if vendor was mentioned in response
44
+ vision_resp = data.get('vision_response', '')
45
+ print(f"\nVision response includes 'vendor': {'vendor' in vision_resp.lower()}")