memra 0.2.13__py3-none-any.whl → 0.2.15__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.
- memra/cli.py +322 -51
- {memra-0.2.13.dist-info → memra-0.2.15.dist-info}/METADATA +1 -1
- {memra-0.2.13.dist-info → memra-0.2.15.dist-info}/RECORD +7 -61
- memra-0.2.15.dist-info/top_level.txt +1 -0
- memra-0.2.13.dist-info/top_level.txt +0 -4
- memra-ops/app.py +0 -808
- memra-ops/config/config.py +0 -25
- memra-ops/config.py +0 -34
- memra-ops/logic/__init__.py +0 -1
- memra-ops/logic/file_tools.py +0 -43
- memra-ops/logic/invoice_tools.py +0 -668
- memra-ops/logic/invoice_tools_fix.py +0 -66
- memra-ops/mcp_bridge_server.py +0 -1178
- memra-ops/scripts/check_database.py +0 -37
- memra-ops/scripts/clear_database.py +0 -48
- memra-ops/scripts/monitor_database.py +0 -67
- memra-ops/scripts/release.py +0 -133
- memra-ops/scripts/reset_database.py +0 -65
- memra-ops/scripts/start_memra.py +0 -334
- memra-ops/scripts/stop_memra.py +0 -132
- memra-ops/server_tool_registry.py +0 -190
- memra-ops/tests/test_llm_text_to_sql.py +0 -115
- memra-ops/tests/test_llm_vs_pattern.py +0 -130
- memra-ops/tests/test_mcp_schema_aware.py +0 -124
- memra-ops/tests/test_schema_aware_sql.py +0 -139
- memra-ops/tests/test_schema_aware_sql_simple.py +0 -66
- memra-ops/tests/test_text_to_sql_demo.py +0 -140
- memra-ops/tools/mcp_bridge_server.py +0 -851
- memra-sdk/examples/accounts_payable.py +0 -215
- memra-sdk/examples/accounts_payable_client.py +0 -217
- memra-sdk/examples/accounts_payable_mcp.py +0 -200
- memra-sdk/examples/ask_questions.py +0 -123
- memra-sdk/examples/invoice_processing.py +0 -116
- memra-sdk/examples/propane_delivery.py +0 -87
- memra-sdk/examples/simple_text_to_sql.py +0 -158
- memra-sdk/memra/__init__.py +0 -31
- memra-sdk/memra/discovery.py +0 -15
- memra-sdk/memra/discovery_client.py +0 -49
- memra-sdk/memra/execution.py +0 -481
- memra-sdk/memra/models.py +0 -99
- memra-sdk/memra/tool_registry.py +0 -343
- memra-sdk/memra/tool_registry_client.py +0 -106
- memra-sdk/scripts/release.py +0 -133
- memra-sdk/setup.py +0 -52
- memra-workflows/accounts_payable/accounts_payable.py +0 -215
- memra-workflows/accounts_payable/accounts_payable_client.py +0 -216
- memra-workflows/accounts_payable/accounts_payable_mcp.py +0 -200
- memra-workflows/accounts_payable/accounts_payable_smart.py +0 -221
- memra-workflows/invoice_processing/invoice_processing.py +0 -116
- memra-workflows/invoice_processing/smart_invoice_processor.py +0 -220
- memra-workflows/logic/__init__.py +0 -1
- memra-workflows/logic/file_tools.py +0 -50
- memra-workflows/logic/invoice_tools.py +0 -501
- memra-workflows/logic/propane_agents.py +0 -52
- memra-workflows/mcp_bridge_server.py +0 -230
- memra-workflows/propane_delivery/propane_delivery.py +0 -87
- memra-workflows/text_to_sql/complete_invoice_workflow_with_queries.py +0 -208
- memra-workflows/text_to_sql/complete_text_to_sql_system.py +0 -266
- memra-workflows/text_to_sql/file_discovery_demo.py +0 -156
- {memra-0.2.13.dist-info → memra-0.2.15.dist-info}/LICENSE +0 -0
- {memra-0.2.13.dist-info → memra-0.2.15.dist-info}/WHEEL +0 -0
- {memra-0.2.13.dist-info → memra-0.2.15.dist-info}/entry_points.txt +0 -0
@@ -1,37 +0,0 @@
|
|
1
|
-
import psycopg2
|
2
|
-
from prettytable import PrettyTable
|
3
|
-
import time
|
4
|
-
|
5
|
-
def check_database():
|
6
|
-
# Connect to the Postgres database
|
7
|
-
conn = psycopg2.connect(
|
8
|
-
dbname="memra_invoice_db",
|
9
|
-
user="memra", # From docker-compose.yml
|
10
|
-
password="memra123", # From docker-compose.yml
|
11
|
-
host="localhost",
|
12
|
-
port=5432
|
13
|
-
)
|
14
|
-
|
15
|
-
# Create a cursor and run the query
|
16
|
-
cur = conn.cursor()
|
17
|
-
cur.execute("SELECT * FROM invoices ORDER BY created_at DESC LIMIT 10;")
|
18
|
-
rows = cur.fetchall()
|
19
|
-
columns = [desc[0] for desc in cur.description]
|
20
|
-
|
21
|
-
# Create and populate the pretty table
|
22
|
-
table = PrettyTable()
|
23
|
-
table.field_names = columns
|
24
|
-
for row in rows:
|
25
|
-
table.add_row(row)
|
26
|
-
|
27
|
-
# Print the table
|
28
|
-
print(f"\n📊 Current invoices in database (as of {time.strftime('%H:%M:%S')}):")
|
29
|
-
print(table)
|
30
|
-
print(f"Total rows: {len(rows)}")
|
31
|
-
|
32
|
-
# Clean up
|
33
|
-
cur.close()
|
34
|
-
conn.close()
|
35
|
-
|
36
|
-
if __name__ == "__main__":
|
37
|
-
check_database()
|
@@ -1,48 +0,0 @@
|
|
1
|
-
import psycopg2
|
2
|
-
|
3
|
-
def clear_database():
|
4
|
-
"""Clear all data from the invoices table"""
|
5
|
-
|
6
|
-
# Connect to the Postgres database
|
7
|
-
conn = psycopg2.connect(
|
8
|
-
dbname="memra_invoice_db",
|
9
|
-
user="memra", # From docker-compose.yml
|
10
|
-
password="memra123", # From docker-compose.yml
|
11
|
-
host="localhost",
|
12
|
-
port=5432
|
13
|
-
)
|
14
|
-
|
15
|
-
try:
|
16
|
-
# Create a cursor and run the query
|
17
|
-
cur = conn.cursor()
|
18
|
-
|
19
|
-
# First, let's see how many rows we have
|
20
|
-
cur.execute("SELECT COUNT(*) FROM invoices;")
|
21
|
-
count_before = cur.fetchone()[0]
|
22
|
-
print(f"📊 Current invoice count: {count_before}")
|
23
|
-
|
24
|
-
if count_before > 0:
|
25
|
-
# Clear all data from the invoices table
|
26
|
-
cur.execute("DELETE FROM invoices;")
|
27
|
-
conn.commit()
|
28
|
-
|
29
|
-
# Verify the deletion
|
30
|
-
cur.execute("SELECT COUNT(*) FROM invoices;")
|
31
|
-
count_after = cur.fetchone()[0]
|
32
|
-
|
33
|
-
print(f"🗑️ Deleted {count_before} invoice records")
|
34
|
-
print(f"📊 New invoice count: {count_after}")
|
35
|
-
print("✅ Database cleared successfully!")
|
36
|
-
else:
|
37
|
-
print("📊 Database is already empty")
|
38
|
-
|
39
|
-
cur.close()
|
40
|
-
|
41
|
-
except Exception as e:
|
42
|
-
print(f"❌ Error: {e}")
|
43
|
-
conn.rollback()
|
44
|
-
finally:
|
45
|
-
conn.close()
|
46
|
-
|
47
|
-
if __name__ == "__main__":
|
48
|
-
clear_database()
|
@@ -1,67 +0,0 @@
|
|
1
|
-
import psycopg2
|
2
|
-
from prettytable import PrettyTable
|
3
|
-
import time
|
4
|
-
import os
|
5
|
-
|
6
|
-
def monitor_database():
|
7
|
-
"""Continuously monitor the database for new invoice rows"""
|
8
|
-
|
9
|
-
# Connect to the Postgres database
|
10
|
-
conn = psycopg2.connect(
|
11
|
-
dbname="memra_invoice_db",
|
12
|
-
user="memra", # From docker-compose.yml
|
13
|
-
password="memra123", # From docker-compose.yml
|
14
|
-
host="localhost",
|
15
|
-
port=5432
|
16
|
-
)
|
17
|
-
|
18
|
-
print("🔍 Monitoring database for new invoice rows...")
|
19
|
-
print("Press Ctrl+C to stop monitoring\n")
|
20
|
-
|
21
|
-
last_count = 0
|
22
|
-
|
23
|
-
try:
|
24
|
-
while True:
|
25
|
-
# Create a cursor and run the query
|
26
|
-
cur = conn.cursor()
|
27
|
-
cur.execute("SELECT COUNT(*) FROM invoices;")
|
28
|
-
current_count = cur.fetchone()[0]
|
29
|
-
|
30
|
-
# Get the latest invoices
|
31
|
-
cur.execute("SELECT id, invoice_number, vendor_name, total_amount, created_at FROM invoices ORDER BY created_at DESC LIMIT 5;")
|
32
|
-
rows = cur.fetchall()
|
33
|
-
|
34
|
-
# Clear screen (works on Unix-like systems)
|
35
|
-
os.system('clear' if os.name == 'posix' else 'cls')
|
36
|
-
|
37
|
-
print(f"📊 Database Monitor - {time.strftime('%Y-%m-%d %H:%M:%S')}")
|
38
|
-
print(f"Total invoices: {current_count}")
|
39
|
-
|
40
|
-
if current_count > last_count:
|
41
|
-
print(f"🆕 New invoices detected! (+{current_count - last_count})")
|
42
|
-
last_count = current_count
|
43
|
-
|
44
|
-
if rows:
|
45
|
-
# Create and populate the pretty table
|
46
|
-
table = PrettyTable()
|
47
|
-
table.field_names = ["ID", "Invoice #", "Vendor", "Amount", "Created"]
|
48
|
-
for row in rows:
|
49
|
-
table.add_row(row)
|
50
|
-
print("\nLatest invoices:")
|
51
|
-
print(table)
|
52
|
-
else:
|
53
|
-
print("\nNo invoices found in database.")
|
54
|
-
|
55
|
-
print(f"\nMonitoring... (refresh every 2 seconds)")
|
56
|
-
cur.close()
|
57
|
-
time.sleep(2)
|
58
|
-
|
59
|
-
except KeyboardInterrupt:
|
60
|
-
print("\n\n🛑 Monitoring stopped by user.")
|
61
|
-
except Exception as e:
|
62
|
-
print(f"\n❌ Error: {e}")
|
63
|
-
finally:
|
64
|
-
conn.close()
|
65
|
-
|
66
|
-
if __name__ == "__main__":
|
67
|
-
monitor_database()
|
memra-ops/scripts/release.py
DELETED
@@ -1,133 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Release script for Memra SDK
|
4
|
-
Builds and uploads the package to PyPI
|
5
|
-
"""
|
6
|
-
|
7
|
-
import os
|
8
|
-
import sys
|
9
|
-
import subprocess
|
10
|
-
import shutil
|
11
|
-
from pathlib import Path
|
12
|
-
|
13
|
-
def run_command(cmd, description):
|
14
|
-
"""Run a command and handle errors"""
|
15
|
-
print(f"🔄 {description}...")
|
16
|
-
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
17
|
-
if result.returncode != 0:
|
18
|
-
print(f"❌ {description} failed:")
|
19
|
-
print(result.stderr)
|
20
|
-
sys.exit(1)
|
21
|
-
print(f"✅ {description} completed")
|
22
|
-
return result.stdout
|
23
|
-
|
24
|
-
def clean_build_artifacts():
|
25
|
-
"""Clean up build artifacts"""
|
26
|
-
print("🧹 Cleaning build artifacts...")
|
27
|
-
|
28
|
-
# Remove build directories
|
29
|
-
for dir_name in ['build', 'dist', 'memra.egg-info']:
|
30
|
-
if os.path.exists(dir_name):
|
31
|
-
shutil.rmtree(dir_name)
|
32
|
-
print(f" Removed {dir_name}/")
|
33
|
-
|
34
|
-
# Remove __pycache__ directories
|
35
|
-
for root, dirs, files in os.walk('.'):
|
36
|
-
for dir_name in dirs:
|
37
|
-
if dir_name == '__pycache__':
|
38
|
-
pycache_path = os.path.join(root, dir_name)
|
39
|
-
shutil.rmtree(pycache_path)
|
40
|
-
print(f" Removed {pycache_path}")
|
41
|
-
|
42
|
-
print("✅ Build artifacts cleaned")
|
43
|
-
|
44
|
-
def run_tests():
|
45
|
-
"""Run tests before release"""
|
46
|
-
print("🧪 Running tests...")
|
47
|
-
|
48
|
-
# Check if pytest is available
|
49
|
-
try:
|
50
|
-
subprocess.run(['pytest', '--version'], check=True, capture_output=True)
|
51
|
-
run_command('pytest tests/', 'Running pytest')
|
52
|
-
except (subprocess.CalledProcessError, FileNotFoundError):
|
53
|
-
print("⚠️ pytest not found, skipping tests")
|
54
|
-
|
55
|
-
# Run basic import test
|
56
|
-
run_command('python -c "import memra; print(f\'Memra SDK version: {memra.__version__ if hasattr(memra, \"__version__\") else \"unknown\"}\')"', 'Testing basic import')
|
57
|
-
|
58
|
-
def build_package():
|
59
|
-
"""Build the package"""
|
60
|
-
print("📦 Building package...")
|
61
|
-
|
62
|
-
# Install build dependencies
|
63
|
-
run_command('pip install build twine', 'Installing build tools')
|
64
|
-
|
65
|
-
# Build the package
|
66
|
-
run_command('python -m build', 'Building wheel and source distribution')
|
67
|
-
|
68
|
-
# Check the package
|
69
|
-
run_command('twine check dist/*', 'Checking package')
|
70
|
-
|
71
|
-
def upload_package(test=False):
|
72
|
-
"""Upload package to PyPI"""
|
73
|
-
if test:
|
74
|
-
print("🚀 Uploading to Test PyPI...")
|
75
|
-
run_command('twine upload --repository testpypi dist/*', 'Uploading to Test PyPI')
|
76
|
-
print("📍 Package uploaded to Test PyPI: https://test.pypi.org/project/memra/")
|
77
|
-
else:
|
78
|
-
print("🚀 Uploading to PyPI...")
|
79
|
-
run_command('twine upload dist/*', 'Uploading to PyPI')
|
80
|
-
print("📍 Package uploaded to PyPI: https://pypi.org/project/memra/")
|
81
|
-
|
82
|
-
def main():
|
83
|
-
"""Main release process"""
|
84
|
-
print("🎯 Memra SDK Release Process")
|
85
|
-
print("=" * 40)
|
86
|
-
|
87
|
-
# Parse arguments
|
88
|
-
test_release = '--test' in sys.argv
|
89
|
-
skip_tests = '--skip-tests' in sys.argv
|
90
|
-
|
91
|
-
if test_release:
|
92
|
-
print("🧪 Test release mode enabled")
|
93
|
-
|
94
|
-
# Ensure we're in the right directory
|
95
|
-
if not os.path.exists('setup.py'):
|
96
|
-
print("❌ setup.py not found. Please run from the project root.")
|
97
|
-
sys.exit(1)
|
98
|
-
|
99
|
-
try:
|
100
|
-
# Clean up
|
101
|
-
clean_build_artifacts()
|
102
|
-
|
103
|
-
# Run tests
|
104
|
-
if not skip_tests:
|
105
|
-
run_tests()
|
106
|
-
else:
|
107
|
-
print("⚠️ Skipping tests")
|
108
|
-
|
109
|
-
# Build package
|
110
|
-
build_package()
|
111
|
-
|
112
|
-
# Upload package
|
113
|
-
upload_package(test=test_release)
|
114
|
-
|
115
|
-
print("\n🎉 Release completed successfully!")
|
116
|
-
|
117
|
-
if test_release:
|
118
|
-
print("\n📋 Next steps:")
|
119
|
-
print("1. Test the package: pip install -i https://test.pypi.org/simple/ memra")
|
120
|
-
print("2. If everything works, run: python scripts/release.py")
|
121
|
-
else:
|
122
|
-
print("\n📋 Package is now available on PyPI!")
|
123
|
-
print("Install with: pip install memra")
|
124
|
-
|
125
|
-
except KeyboardInterrupt:
|
126
|
-
print("\n❌ Release cancelled by user")
|
127
|
-
sys.exit(1)
|
128
|
-
except Exception as e:
|
129
|
-
print(f"\n❌ Release failed: {e}")
|
130
|
-
sys.exit(1)
|
131
|
-
|
132
|
-
if __name__ == '__main__':
|
133
|
-
main()
|
@@ -1,65 +0,0 @@
|
|
1
|
-
import psycopg2
|
2
|
-
|
3
|
-
def reset_database():
|
4
|
-
"""Clear all data from the invoices table and reset the sequence"""
|
5
|
-
|
6
|
-
# Connect to the Postgres database
|
7
|
-
conn = psycopg2.connect(
|
8
|
-
dbname="memra_invoice_db",
|
9
|
-
user="memra", # From docker-compose.yml
|
10
|
-
password="memra123", # From docker-compose.yml
|
11
|
-
host="localhost",
|
12
|
-
port=5432
|
13
|
-
)
|
14
|
-
|
15
|
-
try:
|
16
|
-
# Create a cursor and run the query
|
17
|
-
cur = conn.cursor()
|
18
|
-
|
19
|
-
# First, let's see how many rows we have and current sequence value
|
20
|
-
cur.execute("SELECT COUNT(*) FROM invoices;")
|
21
|
-
count_before = cur.fetchone()[0]
|
22
|
-
|
23
|
-
cur.execute("SELECT last_value FROM invoices_id_seq;")
|
24
|
-
sequence_before = cur.fetchone()[0]
|
25
|
-
|
26
|
-
print(f"📊 Current invoice count: {count_before}")
|
27
|
-
print(f"🔢 Current sequence value: {sequence_before}")
|
28
|
-
|
29
|
-
if count_before > 0:
|
30
|
-
# Clear all data from the invoices table
|
31
|
-
cur.execute("DELETE FROM invoices;")
|
32
|
-
|
33
|
-
# Reset the sequence to start from 1
|
34
|
-
cur.execute("ALTER SEQUENCE invoices_id_seq RESTART WITH 1;")
|
35
|
-
|
36
|
-
conn.commit()
|
37
|
-
|
38
|
-
# Verify the deletion and sequence reset
|
39
|
-
cur.execute("SELECT COUNT(*) FROM invoices;")
|
40
|
-
count_after = cur.fetchone()[0]
|
41
|
-
|
42
|
-
cur.execute("SELECT last_value FROM invoices_id_seq;")
|
43
|
-
sequence_after = cur.fetchone()[0]
|
44
|
-
|
45
|
-
print(f"🗑️ Deleted {count_before} invoice records")
|
46
|
-
print(f"🔄 Reset sequence from {sequence_before} to {sequence_after}")
|
47
|
-
print(f"📊 New invoice count: {count_after}")
|
48
|
-
print("✅ Database reset successfully!")
|
49
|
-
else:
|
50
|
-
print("📊 Database is already empty")
|
51
|
-
# Still reset the sequence
|
52
|
-
cur.execute("ALTER SEQUENCE invoices_id_seq RESTART WITH 1;")
|
53
|
-
conn.commit()
|
54
|
-
print("🔄 Reset sequence to start from 1")
|
55
|
-
|
56
|
-
cur.close()
|
57
|
-
|
58
|
-
except Exception as e:
|
59
|
-
print(f"❌ Error: {e}")
|
60
|
-
conn.rollback()
|
61
|
-
finally:
|
62
|
-
conn.close()
|
63
|
-
|
64
|
-
if __name__ == "__main__":
|
65
|
-
reset_database()
|
memra-ops/scripts/start_memra.py
DELETED
@@ -1,334 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Memra System Startup Script
|
4
|
-
Starts all dependencies required for the Memra system to run
|
5
|
-
"""
|
6
|
-
|
7
|
-
import os
|
8
|
-
import sys
|
9
|
-
import time
|
10
|
-
import subprocess
|
11
|
-
import requests
|
12
|
-
import signal
|
13
|
-
from pathlib import Path
|
14
|
-
|
15
|
-
# Add the project root to the path
|
16
|
-
project_root = Path(__file__).parent.parent
|
17
|
-
sys.path.insert(0, str(project_root))
|
18
|
-
|
19
|
-
class MemraStartup:
|
20
|
-
def __init__(self):
|
21
|
-
self.project_root = project_root
|
22
|
-
self.docker_compose_file = project_root / "docker-compose.yml"
|
23
|
-
self.mcp_bridge_script = project_root / "mcp_bridge_server.py"
|
24
|
-
self.processes = []
|
25
|
-
|
26
|
-
def print_banner(self):
|
27
|
-
"""Print startup banner"""
|
28
|
-
print("=" * 60)
|
29
|
-
print("🚀 MEMRA SYSTEM STARTUP")
|
30
|
-
print("=" * 60)
|
31
|
-
print("Starting all dependencies for Memra AI workflow system...")
|
32
|
-
print()
|
33
|
-
|
34
|
-
def check_conda_environment(self):
|
35
|
-
"""Check if we're in the correct conda environment"""
|
36
|
-
print("🔍 Checking conda environment...")
|
37
|
-
|
38
|
-
# Check if we're in the memra environment
|
39
|
-
conda_env = os.getenv('CONDA_DEFAULT_ENV')
|
40
|
-
if conda_env != 'memra':
|
41
|
-
print(f"❌ Warning: Not in 'memra' conda environment (current: {conda_env})")
|
42
|
-
print(" Please run: conda activate memra")
|
43
|
-
print(" Then run this script again.")
|
44
|
-
return False
|
45
|
-
|
46
|
-
print(f"✅ Conda environment: {conda_env}")
|
47
|
-
return True
|
48
|
-
|
49
|
-
def check_docker(self):
|
50
|
-
"""Check if Docker is running"""
|
51
|
-
print("🐳 Checking Docker...")
|
52
|
-
try:
|
53
|
-
result = subprocess.run(['docker', 'info'],
|
54
|
-
capture_output=True, text=True, timeout=10)
|
55
|
-
if result.returncode == 0:
|
56
|
-
print("✅ Docker is running")
|
57
|
-
return True
|
58
|
-
else:
|
59
|
-
print("❌ Docker is not running")
|
60
|
-
return False
|
61
|
-
except (subprocess.TimeoutExpired, FileNotFoundError):
|
62
|
-
print("❌ Docker is not running or not installed")
|
63
|
-
return False
|
64
|
-
|
65
|
-
def start_postgresql(self):
|
66
|
-
"""Start PostgreSQL using Docker Compose"""
|
67
|
-
print("🐘 Starting PostgreSQL...")
|
68
|
-
|
69
|
-
try:
|
70
|
-
# Check if containers are already running
|
71
|
-
result = subprocess.run(['docker', 'ps', '--filter', 'name=memra-postgres'],
|
72
|
-
capture_output=True, text=True)
|
73
|
-
|
74
|
-
if 'memra-postgres' in result.stdout:
|
75
|
-
print("✅ PostgreSQL is already running")
|
76
|
-
return True
|
77
|
-
|
78
|
-
# Start PostgreSQL
|
79
|
-
print(" Starting PostgreSQL container...")
|
80
|
-
result = subprocess.run(['docker-compose', 'up', '-d', 'postgres'],
|
81
|
-
cwd=self.project_root, capture_output=True, text=True)
|
82
|
-
|
83
|
-
if result.returncode == 0:
|
84
|
-
print("✅ PostgreSQL started successfully")
|
85
|
-
return True
|
86
|
-
else:
|
87
|
-
print(f"❌ Failed to start PostgreSQL: {result.stderr}")
|
88
|
-
return False
|
89
|
-
|
90
|
-
except Exception as e:
|
91
|
-
print(f"❌ Error starting PostgreSQL: {e}")
|
92
|
-
return False
|
93
|
-
|
94
|
-
def wait_for_postgresql(self, max_attempts=30):
|
95
|
-
"""Wait for PostgreSQL to be ready"""
|
96
|
-
print("⏳ Waiting for PostgreSQL to be ready...")
|
97
|
-
|
98
|
-
for attempt in range(max_attempts):
|
99
|
-
try:
|
100
|
-
# Try to connect to PostgreSQL
|
101
|
-
result = subprocess.run([
|
102
|
-
'docker', 'exec', 'memra-postgres',
|
103
|
-
'pg_isready', '-U', 'memra', '-d', 'memra_invoice_db'
|
104
|
-
], capture_output=True, text=True, timeout=5)
|
105
|
-
|
106
|
-
if result.returncode == 0:
|
107
|
-
print("✅ PostgreSQL is ready")
|
108
|
-
return True
|
109
|
-
|
110
|
-
except (subprocess.TimeoutExpired, subprocess.CalledProcessError):
|
111
|
-
pass
|
112
|
-
|
113
|
-
print(f" Attempt {attempt + 1}/{max_attempts}...")
|
114
|
-
time.sleep(2)
|
115
|
-
|
116
|
-
print("❌ PostgreSQL failed to start within timeout")
|
117
|
-
return False
|
118
|
-
|
119
|
-
def check_memra_api_key(self):
|
120
|
-
"""Check if MEMRA_API_KEY is set"""
|
121
|
-
print("🔑 Checking Memra API key...")
|
122
|
-
|
123
|
-
api_key = os.getenv('MEMRA_API_KEY')
|
124
|
-
if not api_key:
|
125
|
-
print("❌ MEMRA_API_KEY environment variable is not set")
|
126
|
-
print(" Please set: export MEMRA_API_KEY='your-key-here'")
|
127
|
-
return False
|
128
|
-
|
129
|
-
print(f"✅ Memra API key is set: {api_key[:8]}...")
|
130
|
-
return True
|
131
|
-
|
132
|
-
def start_mcp_bridge(self):
|
133
|
-
"""Start the MCP bridge server"""
|
134
|
-
print("🌉 Starting MCP Bridge Server...")
|
135
|
-
|
136
|
-
try:
|
137
|
-
# Check if MCP bridge is already running
|
138
|
-
try:
|
139
|
-
response = requests.get('http://localhost:8081/health', timeout=5)
|
140
|
-
if response.status_code == 200:
|
141
|
-
print("✅ MCP Bridge Server is already running")
|
142
|
-
return True
|
143
|
-
except requests.RequestException:
|
144
|
-
pass
|
145
|
-
|
146
|
-
# Start MCP bridge server in background
|
147
|
-
print(" Starting MCP bridge server...")
|
148
|
-
process = subprocess.Popen([
|
149
|
-
sys.executable, str(self.mcp_bridge_script)
|
150
|
-
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
151
|
-
|
152
|
-
self.processes.append(process)
|
153
|
-
|
154
|
-
# Wait a moment for server to start
|
155
|
-
time.sleep(3)
|
156
|
-
|
157
|
-
# Check if server started successfully
|
158
|
-
try:
|
159
|
-
response = requests.get('http://localhost:8081/health', timeout=5)
|
160
|
-
if response.status_code == 200:
|
161
|
-
print("✅ MCP Bridge Server started successfully")
|
162
|
-
return True
|
163
|
-
else:
|
164
|
-
print(f"❌ MCP Bridge Server returned status {response.status_code}")
|
165
|
-
return False
|
166
|
-
except requests.RequestException as e:
|
167
|
-
print(f"❌ MCP Bridge Server failed to start: {e}")
|
168
|
-
return False
|
169
|
-
|
170
|
-
except Exception as e:
|
171
|
-
print(f"❌ Error starting MCP Bridge Server: {e}")
|
172
|
-
return False
|
173
|
-
|
174
|
-
def test_memra_api(self):
|
175
|
-
"""Test the Memra API connection"""
|
176
|
-
print("🌐 Testing Memra API connection...")
|
177
|
-
|
178
|
-
try:
|
179
|
-
from memra import get_api_status
|
180
|
-
api_status = get_api_status()
|
181
|
-
|
182
|
-
if api_status['api_healthy']:
|
183
|
-
print(f"✅ Memra API is healthy")
|
184
|
-
print(f" URL: {api_status['api_url']}")
|
185
|
-
print(f" Tools Available: {api_status['tools_available']}")
|
186
|
-
return True
|
187
|
-
else:
|
188
|
-
print("❌ Memra API is not healthy")
|
189
|
-
return False
|
190
|
-
|
191
|
-
except Exception as e:
|
192
|
-
print(f"❌ Error testing Memra API: {e}")
|
193
|
-
return False
|
194
|
-
|
195
|
-
def run_test_workflow(self):
|
196
|
-
"""Run a quick test to verify everything works"""
|
197
|
-
print("🧪 Running system test...")
|
198
|
-
|
199
|
-
try:
|
200
|
-
# Import and run a simple test
|
201
|
-
from memra import Agent, Department, LLM
|
202
|
-
from memra.execution import ExecutionEngine
|
203
|
-
|
204
|
-
# Create a simple test agent
|
205
|
-
test_agent = Agent(
|
206
|
-
role="Test Agent",
|
207
|
-
job="Verify system is working",
|
208
|
-
llm=LLM(model="llama-3.2-11b-vision-preview", temperature=0.1),
|
209
|
-
sops=["Return a simple success message"],
|
210
|
-
output_key="test_result"
|
211
|
-
)
|
212
|
-
|
213
|
-
# Create test department
|
214
|
-
test_dept = Department(
|
215
|
-
name="Test Department",
|
216
|
-
mission="Verify Memra system is working",
|
217
|
-
agents=[test_agent],
|
218
|
-
workflow_order=["Test Agent"]
|
219
|
-
)
|
220
|
-
|
221
|
-
# Run test
|
222
|
-
engine = ExecutionEngine()
|
223
|
-
result = engine.execute_department(test_dept, {})
|
224
|
-
|
225
|
-
if result.success:
|
226
|
-
print("✅ System test passed - Memra is ready!")
|
227
|
-
return True
|
228
|
-
else:
|
229
|
-
print(f"❌ System test failed: {result.error}")
|
230
|
-
return False
|
231
|
-
|
232
|
-
except Exception as e:
|
233
|
-
print(f"❌ Error running system test: {e}")
|
234
|
-
return False
|
235
|
-
|
236
|
-
def cleanup(self):
|
237
|
-
"""Cleanup processes on exit"""
|
238
|
-
print("\n🧹 Cleaning up processes...")
|
239
|
-
for process in self.processes:
|
240
|
-
try:
|
241
|
-
process.terminate()
|
242
|
-
process.wait(timeout=5)
|
243
|
-
except:
|
244
|
-
try:
|
245
|
-
process.kill()
|
246
|
-
except:
|
247
|
-
pass
|
248
|
-
|
249
|
-
def signal_handler(self, signum, frame):
|
250
|
-
"""Handle interrupt signals"""
|
251
|
-
print("\n🛑 Received interrupt signal, shutting down...")
|
252
|
-
self.cleanup()
|
253
|
-
sys.exit(0)
|
254
|
-
|
255
|
-
def start(self):
|
256
|
-
"""Main startup sequence"""
|
257
|
-
try:
|
258
|
-
self.print_banner()
|
259
|
-
|
260
|
-
# Set up signal handlers
|
261
|
-
signal.signal(signal.SIGINT, self.signal_handler)
|
262
|
-
signal.signal(signal.SIGTERM, self.signal_handler)
|
263
|
-
|
264
|
-
# Check environment
|
265
|
-
if not self.check_conda_environment():
|
266
|
-
return False
|
267
|
-
|
268
|
-
# Check Docker
|
269
|
-
if not self.check_docker():
|
270
|
-
print("❌ Please start Docker Desktop and try again")
|
271
|
-
return False
|
272
|
-
|
273
|
-
# Start PostgreSQL
|
274
|
-
if not self.start_postgresql():
|
275
|
-
return False
|
276
|
-
|
277
|
-
if not self.wait_for_postgresql():
|
278
|
-
return False
|
279
|
-
|
280
|
-
# Check API key
|
281
|
-
if not self.check_memra_api_key():
|
282
|
-
return False
|
283
|
-
|
284
|
-
# Start MCP bridge
|
285
|
-
if not self.start_mcp_bridge():
|
286
|
-
return False
|
287
|
-
|
288
|
-
# Test API
|
289
|
-
if not self.test_memra_api():
|
290
|
-
return False
|
291
|
-
|
292
|
-
# Run system test
|
293
|
-
if not self.run_test_workflow():
|
294
|
-
return False
|
295
|
-
|
296
|
-
print("\n" + "=" * 60)
|
297
|
-
print("🎉 MEMRA SYSTEM STARTED SUCCESSFULLY!")
|
298
|
-
print("=" * 60)
|
299
|
-
print("✅ All dependencies are running:")
|
300
|
-
print(" • PostgreSQL Database (Docker)")
|
301
|
-
print(" • MCP Bridge Server (localhost:8081)")
|
302
|
-
print(" • Memra API (https://api.memra.co)")
|
303
|
-
print()
|
304
|
-
print("🚀 Ready to run workflows!")
|
305
|
-
print(" Example: python3 examples/accounts_payable_client.py")
|
306
|
-
print()
|
307
|
-
print("💡 Keep this terminal open to maintain the MCP bridge server")
|
308
|
-
print(" Press Ctrl+C to stop all services")
|
309
|
-
print("=" * 60)
|
310
|
-
|
311
|
-
# Keep the script running to maintain the MCP bridge server
|
312
|
-
try:
|
313
|
-
while True:
|
314
|
-
time.sleep(1)
|
315
|
-
except KeyboardInterrupt:
|
316
|
-
print("\n🛑 Shutting down Memra system...")
|
317
|
-
self.cleanup()
|
318
|
-
print("✅ Memra system stopped")
|
319
|
-
|
320
|
-
except Exception as e:
|
321
|
-
print(f"❌ Startup failed: {e}")
|
322
|
-
self.cleanup()
|
323
|
-
return False
|
324
|
-
|
325
|
-
return True
|
326
|
-
|
327
|
-
def main():
|
328
|
-
"""Main entry point"""
|
329
|
-
startup = MemraStartup()
|
330
|
-
success = startup.start()
|
331
|
-
sys.exit(0 if success else 1)
|
332
|
-
|
333
|
-
if __name__ == "__main__":
|
334
|
-
main()
|