memra 0.2.2__py3-none-any.whl → 0.2.4__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/__init__.py +6 -2
- memra/execution.py +53 -0
- memra/tool_registry.py +162 -0
- memra-0.2.4.dist-info/METADATA +145 -0
- memra-0.2.4.dist-info/RECORD +58 -0
- {memra-0.2.2.dist-info → memra-0.2.4.dist-info}/WHEEL +1 -1
- memra-0.2.4.dist-info/top_level.txt +4 -0
- memra-ops/app.py +710 -0
- memra-ops/config/config.py +25 -0
- memra-ops/config.py +34 -0
- memra-ops/scripts/release.py +133 -0
- memra-ops/scripts/start_memra.py +334 -0
- memra-ops/scripts/stop_memra.py +132 -0
- memra-ops/server_tool_registry.py +188 -0
- memra-ops/tests/test_llm_text_to_sql.py +115 -0
- memra-ops/tests/test_llm_vs_pattern.py +130 -0
- memra-ops/tests/test_mcp_schema_aware.py +124 -0
- memra-ops/tests/test_schema_aware_sql.py +139 -0
- memra-ops/tests/test_schema_aware_sql_simple.py +66 -0
- memra-ops/tests/test_text_to_sql_demo.py +140 -0
- memra-ops/tools/mcp_bridge_server.py +851 -0
- memra-sdk/examples/accounts_payable.py +215 -0
- memra-sdk/examples/accounts_payable_client.py +217 -0
- memra-sdk/examples/accounts_payable_mcp.py +200 -0
- memra-sdk/examples/ask_questions.py +123 -0
- memra-sdk/examples/invoice_processing.py +116 -0
- memra-sdk/examples/propane_delivery.py +87 -0
- memra-sdk/examples/simple_text_to_sql.py +158 -0
- memra-sdk/memra/__init__.py +31 -0
- memra-sdk/memra/discovery.py +15 -0
- memra-sdk/memra/discovery_client.py +49 -0
- memra-sdk/memra/execution.py +481 -0
- memra-sdk/memra/models.py +99 -0
- memra-sdk/memra/tool_registry.py +343 -0
- memra-sdk/memra/tool_registry_client.py +106 -0
- memra-sdk/scripts/release.py +133 -0
- memra-sdk/setup.py +52 -0
- memra-workflows/accounts_payable/accounts_payable.py +215 -0
- memra-workflows/accounts_payable/accounts_payable_client.py +216 -0
- memra-workflows/accounts_payable/accounts_payable_mcp.py +200 -0
- memra-workflows/accounts_payable/accounts_payable_smart.py +221 -0
- memra-workflows/invoice_processing/invoice_processing.py +116 -0
- memra-workflows/invoice_processing/smart_invoice_processor.py +220 -0
- memra-workflows/logic/__init__.py +1 -0
- memra-workflows/logic/file_tools.py +50 -0
- memra-workflows/logic/invoice_tools.py +501 -0
- memra-workflows/logic/propane_agents.py +52 -0
- memra-workflows/mcp_bridge_server.py +230 -0
- memra-workflows/propane_delivery/propane_delivery.py +87 -0
- memra-workflows/text_to_sql/complete_invoice_workflow_with_queries.py +208 -0
- memra-workflows/text_to_sql/complete_text_to_sql_system.py +266 -0
- memra-workflows/text_to_sql/file_discovery_demo.py +156 -0
- memra-0.2.2.dist-info/METADATA +0 -148
- memra-0.2.2.dist-info/RECORD +0 -13
- memra-0.2.2.dist-info/top_level.txt +0 -1
- {memra-0.2.2.dist-info → memra-0.2.4.dist-info}/entry_points.txt +0 -0
- {memra-0.2.2.dist-info → memra-0.2.4.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
"""
|
2
|
+
Configuration for Memra SDK examples
|
3
|
+
Contains LLM configurations for different agent types
|
4
|
+
"""
|
5
|
+
|
6
|
+
# Default LLM configuration for general use
|
7
|
+
DEFAULT_LLM_CONFIG = {
|
8
|
+
"model": "llama-3.2-11b-vision-preview",
|
9
|
+
"temperature": 0.1,
|
10
|
+
"max_tokens": 2000
|
11
|
+
}
|
12
|
+
|
13
|
+
# Specialized LLM configurations for different agent types
|
14
|
+
AGENT_LLM_CONFIG = {
|
15
|
+
"parsing": {
|
16
|
+
"model": "llama-3.2-11b-vision-preview",
|
17
|
+
"temperature": 0.0,
|
18
|
+
"max_tokens": 4000
|
19
|
+
},
|
20
|
+
"manager": {
|
21
|
+
"model": "llama-3.2-11b-vision-preview",
|
22
|
+
"temperature": 0.2,
|
23
|
+
"max_tokens": 1000
|
24
|
+
}
|
25
|
+
}
|
memra-ops/config.py
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Memra SDK Configuration
|
2
|
+
# LLM API Configuration for agent processing
|
3
|
+
|
4
|
+
API_CONFIG = {
|
5
|
+
"huggingface": {
|
6
|
+
"api_key": "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",
|
7
|
+
"model": "meta-llama/Llama-4-Maverick-17B-128E-Instruct",
|
8
|
+
"max_tokens": 2000
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
# Default LLM settings for agents
|
13
|
+
DEFAULT_LLM_CONFIG = {
|
14
|
+
"provider": "huggingface",
|
15
|
+
"model": "meta-llama/Llama-4-Maverick-17B-128E-Instruct",
|
16
|
+
"temperature": 0.1,
|
17
|
+
"max_tokens": 2000
|
18
|
+
}
|
19
|
+
|
20
|
+
# Agent-specific LLM configurations
|
21
|
+
AGENT_LLM_CONFIG = {
|
22
|
+
"parsing": {
|
23
|
+
"provider": "huggingface",
|
24
|
+
"model": "meta-llama/Llama-4-Maverick-17B-128E-Instruct",
|
25
|
+
"temperature": 0.0, # More deterministic for data extraction
|
26
|
+
"max_tokens": 2000
|
27
|
+
},
|
28
|
+
"manager": {
|
29
|
+
"provider": "huggingface",
|
30
|
+
"model": "meta-llama/Llama-4-Maverick-17B-128E-Instruct",
|
31
|
+
"temperature": 0.3, # More flexible for decision making
|
32
|
+
"max_tokens": 1500
|
33
|
+
}
|
34
|
+
}
|
@@ -0,0 +1,133 @@
|
|
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()
|
@@ -0,0 +1,334 @@
|
|
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()
|
@@ -0,0 +1,132 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Memra System Stop Script
|
4
|
+
Gracefully stops all Memra system dependencies
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
import sys
|
9
|
+
import subprocess
|
10
|
+
import requests
|
11
|
+
import signal
|
12
|
+
from pathlib import Path
|
13
|
+
|
14
|
+
class MemraStop:
|
15
|
+
def __init__(self):
|
16
|
+
self.project_root = Path(__file__).parent.parent
|
17
|
+
|
18
|
+
def print_banner(self):
|
19
|
+
"""Print stop banner"""
|
20
|
+
print("=" * 60)
|
21
|
+
print("🛑 MEMRA SYSTEM SHUTDOWN")
|
22
|
+
print("=" * 60)
|
23
|
+
print("Stopping all Memra system dependencies...")
|
24
|
+
print()
|
25
|
+
|
26
|
+
def stop_mcp_bridge(self):
|
27
|
+
"""Stop the MCP bridge server"""
|
28
|
+
print("🌉 Stopping MCP Bridge Server...")
|
29
|
+
|
30
|
+
try:
|
31
|
+
# Try to send a graceful shutdown signal
|
32
|
+
response = requests.get('http://localhost:8081/health', timeout=5)
|
33
|
+
if response.status_code == 200:
|
34
|
+
print(" MCP Bridge Server is running, stopping...")
|
35
|
+
|
36
|
+
# Find and kill the MCP bridge process
|
37
|
+
result = subprocess.run(['pkill', '-f', 'mcp_bridge_server.py'],
|
38
|
+
capture_output=True, text=True)
|
39
|
+
|
40
|
+
if result.returncode == 0:
|
41
|
+
print("✅ MCP Bridge Server stopped")
|
42
|
+
else:
|
43
|
+
print("⚠️ MCP Bridge Server process not found (may already be stopped)")
|
44
|
+
else:
|
45
|
+
print("✅ MCP Bridge Server is not running")
|
46
|
+
|
47
|
+
except requests.RequestException:
|
48
|
+
print("✅ MCP Bridge Server is not running")
|
49
|
+
|
50
|
+
def stop_postgresql(self):
|
51
|
+
"""Stop PostgreSQL using Docker Compose"""
|
52
|
+
print("🐘 Stopping PostgreSQL...")
|
53
|
+
|
54
|
+
try:
|
55
|
+
# Check if PostgreSQL container is running
|
56
|
+
result = subprocess.run(['docker', 'ps', '--filter', 'name=memra-postgres'],
|
57
|
+
capture_output=True, text=True)
|
58
|
+
|
59
|
+
if 'memra-postgres' in result.stdout:
|
60
|
+
print(" PostgreSQL container is running, stopping...")
|
61
|
+
|
62
|
+
# Stop PostgreSQL container
|
63
|
+
result = subprocess.run(['docker-compose', 'stop', 'postgres'],
|
64
|
+
cwd=self.project_root, capture_output=True, text=True)
|
65
|
+
|
66
|
+
if result.returncode == 0:
|
67
|
+
print("✅ PostgreSQL stopped")
|
68
|
+
else:
|
69
|
+
print(f"⚠️ Warning: Failed to stop PostgreSQL: {result.stderr}")
|
70
|
+
else:
|
71
|
+
print("✅ PostgreSQL is not running")
|
72
|
+
|
73
|
+
except Exception as e:
|
74
|
+
print(f"⚠️ Warning: Error stopping PostgreSQL: {e}")
|
75
|
+
|
76
|
+
def cleanup_docker(self):
|
77
|
+
"""Clean up any orphaned Docker containers"""
|
78
|
+
print("🧹 Cleaning up Docker containers...")
|
79
|
+
|
80
|
+
try:
|
81
|
+
# Remove any stopped containers
|
82
|
+
result = subprocess.run(['docker', 'container', 'prune', '-f'],
|
83
|
+
capture_output=True, text=True)
|
84
|
+
|
85
|
+
if result.returncode == 0:
|
86
|
+
print("✅ Docker containers cleaned up")
|
87
|
+
else:
|
88
|
+
print("⚠️ Warning: Failed to clean up Docker containers")
|
89
|
+
|
90
|
+
except Exception as e:
|
91
|
+
print(f"⚠️ Warning: Error cleaning up Docker: {e}")
|
92
|
+
|
93
|
+
def stop(self):
|
94
|
+
"""Main stop sequence"""
|
95
|
+
try:
|
96
|
+
self.print_banner()
|
97
|
+
|
98
|
+
# Stop MCP bridge server
|
99
|
+
self.stop_mcp_bridge()
|
100
|
+
|
101
|
+
# Stop PostgreSQL
|
102
|
+
self.stop_postgresql()
|
103
|
+
|
104
|
+
# Clean up Docker
|
105
|
+
self.cleanup_docker()
|
106
|
+
|
107
|
+
print("\n" + "=" * 60)
|
108
|
+
print("✅ MEMRA SYSTEM STOPPED SUCCESSFULLY!")
|
109
|
+
print("=" * 60)
|
110
|
+
print("All services have been stopped:")
|
111
|
+
print(" • MCP Bridge Server")
|
112
|
+
print(" • PostgreSQL Database")
|
113
|
+
print(" • Docker containers cleaned up")
|
114
|
+
print()
|
115
|
+
print("💡 To start the system again, run:")
|
116
|
+
print(" ./scripts/start_memra.sh")
|
117
|
+
print("=" * 60)
|
118
|
+
|
119
|
+
except Exception as e:
|
120
|
+
print(f"❌ Stop failed: {e}")
|
121
|
+
return False
|
122
|
+
|
123
|
+
return True
|
124
|
+
|
125
|
+
def main():
|
126
|
+
"""Main entry point"""
|
127
|
+
stop = MemraStop()
|
128
|
+
success = stop.stop()
|
129
|
+
sys.exit(0 if success else 1)
|
130
|
+
|
131
|
+
if __name__ == "__main__":
|
132
|
+
main()
|