memra 0.2.14__py3-none-any.whl → 0.2.16__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 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.12"
9
+ __version__ = "0.2.15"
10
10
 
11
11
  # Core imports
12
12
  from .models import Agent, Department, Tool, LLM
memra/cli.py CHANGED
@@ -24,9 +24,6 @@ def run_demo():
24
24
  print("🔧 Configuring environment...")
25
25
  setup_environment()
26
26
 
27
- # Step 2.5: Install dependencies
28
- install_dependencies()
29
-
30
27
  # Step 3: Start Docker containers
31
28
  print("🐳 Starting Docker services...")
32
29
  if not start_docker_services(demo_dir):
@@ -79,121 +76,15 @@ def setup_demo_environment():
79
76
  def extract_bundled_files(demo_dir):
80
77
  """Extract files bundled with the PyPI package"""
81
78
  try:
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")
79
+ # Extract from package data
80
+ with pkg_resources.path('memra', 'demo_files') as demo_files_path:
81
+ if demo_files_path.exists():
82
+ # Copy all files from the bundled demo_files directory
83
+ shutil.copytree(demo_files_path, demo_dir, dirs_exist_ok=True)
125
84
  else:
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
-
85
+ # Fallback: create minimal demo structure
86
+ create_minimal_demo(demo_dir)
87
+
197
88
  except Exception as e:
198
89
  print(f"⚠️ Could not extract bundled files: {e}")
199
90
  print("Creating minimal demo structure...")
@@ -268,41 +159,9 @@ if __name__ == '__main__':
268
159
  with open(ops_dir / "mcp_bridge_server.py", "w") as f:
269
160
  f.write(mcp_content)
270
161
 
271
- # Copy the real ETL demo if available
162
+ # Create demo workflow
272
163
  demo_dir.mkdir(exist_ok=True)
273
- import shutil
274
-
275
- try:
276
- # Try to copy from demos directory
277
- source_demo = Path("demos/etl_invoice_processing/etl_invoice_demo.py")
278
- if source_demo.exists():
279
- # Copy the main demo script
280
- shutil.copy2(source_demo, demo_dir / "etl_invoice_demo.py")
281
- print("✅ Copied real ETL demo script")
282
-
283
- # Copy all necessary Python dependencies
284
- demo_files = [
285
- "database_monitor_agent.py",
286
- "simple_pdf_processor.py",
287
- "setup_demo_data.py"
288
- ]
289
-
290
- for file_name in demo_files:
291
- source_file = Path(f"demos/etl_invoice_processing/{file_name}")
292
- if source_file.exists():
293
- shutil.copy2(source_file, demo_dir / file_name)
294
- print(f"✅ Copied {file_name}")
295
-
296
- # Copy sample data
297
- data_dir = demo_dir / "data"
298
- data_dir.mkdir(exist_ok=True)
299
- source_data = Path("demos/etl_invoice_processing/data")
300
- if source_data.exists():
301
- shutil.copytree(source_data, data_dir, dirs_exist_ok=True)
302
- print("✅ Copied sample invoice data")
303
- else:
304
- # Create a basic demo if real one not found
305
- demo_content = """#!/usr/bin/env python3
164
+ demo_content = """#!/usr/bin/env python3
306
165
  import os
307
166
  import sys
308
167
  import time
@@ -335,47 +194,9 @@ def main():
335
194
  if __name__ == "__main__":
336
195
  main()
337
196
  """
338
- with open(demo_dir / "etl_demo.py", "w") as f:
339
- f.write(demo_content)
340
- print("⚠️ Using simplified demo (real demo not found)")
341
- except Exception as e:
342
- print(f"Warning: Could not copy ETL demo: {e}")
343
- # Fallback to basic demo
344
- demo_content = """#!/usr/bin/env python3
345
- import os
346
- import sys
347
- import time
348
-
349
- def main():
350
- print("🚀 Starting ETL Invoice Processing Demo...")
351
- print("🏢 Starting ETL Invoice Processing Department")
352
- print("📋 Mission: Complete end-to-end ETL process with comprehensive monitoring")
353
- print("👥 Team: Pre-ETL Database Monitor, Data Engineer, Invoice Parser, Data Entry Specialist, Post-ETL Database Monitor")
354
- print("👔 Manager: ETL Process Manager")
355
197
 
356
- steps = [
357
- ("Pre-ETL Database Monitor", "Database state captured: 2 rows"),
358
- ("Data Engineer", "Schema extracted successfully"),
359
- ("Invoice Parser", "Invoice data extracted: $270.57"),
360
- ("Data Entry Specialist", "Record inserted: ID 1"),
361
- ("Post-ETL Database Monitor", "Database state captured: 3 rows")
362
- ]
363
-
364
- for i, (step, result) in enumerate(steps, 1):
365
- print(f"\\n🔄 Step {i}/5: {step}")
366
- time.sleep(1)
367
- print(f"✅ {result}")
368
-
369
- print("\\n🎉 ETL Invoice Processing Department workflow completed!")
370
- print("⏱️ Total time: 5.2s")
371
- print("\\n📊 Demo completed successfully!")
372
- print("This was a simplified demo. For the full experience, check out the complete ETL workflow.")
373
-
374
- if __name__ == "__main__":
375
- main()
376
- """
377
- with open(demo_dir / "etl_demo.py", "w") as f:
378
- f.write(demo_content)
198
+ with open(demo_dir / "etl_demo.py", "w") as f:
199
+ f.write(demo_content)
379
200
 
380
201
  def setup_environment():
381
202
  """Set up environment variables for the demo"""
@@ -388,38 +209,6 @@ def setup_environment():
388
209
  os.environ['DATABASE_URL'] = 'postgresql://postgres:postgres@localhost:5432/local_workflow'
389
210
  print("✅ Set DATABASE_URL")
390
211
 
391
- def install_dependencies():
392
- """Install required dependencies for the demo"""
393
- try:
394
- print("📦 Installing demo dependencies...")
395
- dependencies = [
396
- 'requests==2.31.0',
397
- 'fastapi==0.104.1',
398
- 'uvicorn[standard]==0.24.0',
399
- 'pydantic==2.5.0',
400
- 'aiohttp',
401
- 'psycopg2-binary',
402
- 'httpx',
403
- 'huggingface_hub'
404
- ]
405
-
406
- for dep in dependencies:
407
- print(f" Installing {dep}...")
408
- result = subprocess.run([
409
- sys.executable, '-m', 'pip', 'install', dep
410
- ], capture_output=True, text=True)
411
-
412
- if result.returncode != 0:
413
- print(f"⚠️ Warning: Failed to install {dep}: {result.stderr}")
414
- else:
415
- print(f" ✅ {dep} installed")
416
-
417
- print("✅ Dependencies installed")
418
-
419
- except Exception as e:
420
- print(f"⚠️ Warning: Could not install dependencies: {e}")
421
- print(" You may need to install them manually: pip install requests fastapi uvicorn pydantic")
422
-
423
212
  def start_docker_services(demo_dir):
424
213
  """Start Docker containers using docker-compose"""
425
214
  try:
@@ -457,23 +246,9 @@ def wait_for_services():
457
246
  """Wait for services to be ready"""
458
247
  print("⏳ Waiting for PostgreSQL to be ready...")
459
248
 
460
- # Wait for PostgreSQL - try both possible container names
249
+ # Wait for PostgreSQL
461
250
  for i in range(30): # Wait up to 30 seconds
462
251
  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
477
252
  result = subprocess.run([
478
253
  'docker', 'exec', 'memra_postgres',
479
254
  'pg_isready', '-U', 'postgres', '-d', 'local_workflow'
@@ -494,56 +269,15 @@ def wait_for_services():
494
269
  def run_etl_workflow(demo_dir):
495
270
  """Run the ETL workflow"""
496
271
  try:
497
- # Try to run the real ETL demo first
498
- real_demo_script = demo_dir / "etl_invoice_demo.py"
499
- if real_demo_script.exists():
500
- print("🎯 Running real ETL workflow...")
501
- print(f"📁 Working directory: {demo_dir}")
502
- print(f"📄 Demo script: {real_demo_script}")
503
-
504
- # Check if data directory exists
505
- data_dir = demo_dir / "data"
506
- invoices_dir = data_dir / "invoices"
507
- if invoices_dir.exists():
508
- pdf_files = list(invoices_dir.glob("*.PDF"))
509
- print(f"📊 Found {len(pdf_files)} PDF files in {invoices_dir}")
510
- if pdf_files:
511
- print(f" First few files: {[f.name for f in pdf_files[:3]]}")
512
- else:
513
- print(f"⚠️ Warning: {invoices_dir} does not exist")
514
- print(f" Available directories in {demo_dir}:")
515
- for item in demo_dir.iterdir():
516
- if item.is_dir():
517
- print(f" - {item.name}/")
518
-
519
- print("⏱️ Processing 15 files with delays - this may take 10-15 minutes")
520
-
521
- # Set the working directory to the demo directory so the script can find data/invoices/
522
- result = subprocess.run(
523
- [sys.executable, str(real_demo_script)],
524
- cwd=demo_dir, # This is crucial - sets working directory
525
- timeout=1800 # 30 minute timeout
526
- )
272
+ # Run the demo script
273
+ demo_script = demo_dir / "etl_demo.py"
274
+ if demo_script.exists():
275
+ result = subprocess.run([sys.executable, str(demo_script)], cwd=demo_dir)
527
276
  return result.returncode == 0
528
277
  else:
529
- # Fallback to simplified demo
530
- demo_script = demo_dir / "etl_demo.py"
531
- if demo_script.exists():
532
- print("🎯 Running simplified demo...")
533
- result = subprocess.run([sys.executable, str(demo_script)], cwd=demo_dir)
534
- return result.returncode == 0
535
- else:
536
- print("❌ No demo script found")
537
- print(f" Looking for: {real_demo_script}")
538
- print(f" Available files in {demo_dir}:")
539
- for item in demo_dir.iterdir():
540
- print(f" - {item.name}")
541
- return False
278
+ print("❌ Demo script not found")
279
+ return False
542
280
 
543
- except subprocess.TimeoutExpired:
544
- print("⏰ ETL workflow timed out after 30 minutes")
545
- print("This is normal for large batches - the demo processes 15 files with delays")
546
- return False
547
281
  except Exception as e:
548
282
  print(f"❌ Error running ETL workflow: {e}")
549
283
  return False
@@ -791,8 +791,10 @@ def process_database_insertion(agent, tool_results, **kwargs):
791
791
  # Inject the properly formatted data into the tool parameters
792
792
  if 'parameters' not in result:
793
793
  result['parameters'] = {}
794
- result['parameters']['data'] = db_data
795
- print(f"\n✅ [AGENT 4] Injected transformed data into PostgresInsert parameters")
794
+ # Pass the data in the format expected by PostgresInsert tool
795
+ result['parameters']['invoice_data'] = invoice_data # Pass the original invoice_data
796
+ result['parameters']['table_name'] = 'invoices'
797
+ print(f"\n✅ [AGENT 4] Injected invoice_data into PostgresInsert parameters")
796
798
 
797
799
  # Call the original print function for debugging
798
800
  print_database_data(agent, tool_results, invoice_data)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: memra
3
- Version: 0.2.14
3
+ Version: 0.2.16
4
4
  Summary: Declarative framework for enterprise workflows with MCP integration - Client SDK
5
5
  Home-page: https://github.com/memra/memra-sdk
6
6
  Author: Memra
@@ -20,18 +20,22 @@ Classifier: Programming Language :: Python :: 3.11
20
20
  Requires-Python: >=3.8
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: pydantic >=1.8.0
24
- Requires-Dist: httpx >=0.24.0
25
- Requires-Dist: typing-extensions >=4.0.0
26
- Requires-Dist: aiohttp >=3.8.0
27
- Requires-Dist: aiohttp-cors >=0.7.0
23
+ Requires-Dist: pydantic>=1.8.0
24
+ Requires-Dist: httpx>=0.24.0
25
+ Requires-Dist: typing-extensions>=4.0.0
26
+ Requires-Dist: aiohttp>=3.8.0
27
+ Requires-Dist: aiohttp-cors>=0.7.0
28
28
  Provides-Extra: dev
29
- Requires-Dist: pytest >=6.0 ; extra == 'dev'
30
- Requires-Dist: pytest-asyncio ; extra == 'dev'
31
- Requires-Dist: black ; extra == 'dev'
32
- Requires-Dist: flake8 ; extra == 'dev'
29
+ Requires-Dist: pytest>=6.0; extra == "dev"
30
+ Requires-Dist: pytest-asyncio; extra == "dev"
31
+ Requires-Dist: black; extra == "dev"
32
+ Requires-Dist: flake8; extra == "dev"
33
33
  Provides-Extra: mcp
34
- Requires-Dist: psycopg2-binary >=2.9.0 ; extra == 'mcp'
34
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "mcp"
35
+ Dynamic: author
36
+ Dynamic: home-page
37
+ Dynamic: license-file
38
+ Dynamic: requires-python
35
39
 
36
40
  # Memra SDK
37
41
 
@@ -1,5 +1,5 @@
1
- memra/__init__.py,sha256=6i82jodsWZPgtRhUaDF3wuQuRDSaboIpew8D3zDN__s,1109
2
- memra/cli.py,sha256=UcLaBUOlLVZRhLCVzzSBLPxGAKLsLNuDmoFAvXLl2gc,20413
1
+ memra/__init__.py,sha256=DEOu1dmnPnJWyfCgmarnjSFZZSgiUiv3VdGA7thdxYs,1109
2
+ memra/cli.py,sha256=DSkgwlko8NqUMdXxt-_Y7hMdqMGkGmF6PuzhQqCyjto,10310
3
3
  memra/discovery.py,sha256=yJIQnrDQu1nyzKykCIuzG_5SW5dIXHCEBLLKRWacIoY,480
4
4
  memra/discovery_client.py,sha256=AbnKn6qhyrf7vmOvknEeDzH4tiGHsqPHtDaein_qaW0,1271
5
5
  memra/execution.py,sha256=OXpBKxwBIjhACWL_qh8KHNndO8HUgB6gBF81AiQBBm0,34751
@@ -12,7 +12,7 @@ memra/demos/etl_invoice_processing/check_recent_db.py,sha256=tyO47DfwJkFH6IsdoM7
12
12
  memra/demos/etl_invoice_processing/database_monitor_agent.py,sha256=_A2mqweJTDOtbf57GCt20F5JG8RoH2UyUxET104dgAI,3497
13
13
  memra/demos/etl_invoice_processing/debug_mcp.py,sha256=xga1xzI0wycqF7aF5dsp3bL_o8aTnBYjOH0ZnjUZUtM,2066
14
14
  memra/demos/etl_invoice_processing/debug_schema.py,sha256=zirxgrgEtvE56oLNXvk4rL_kopIT53fIviKUQg1Ise4,1416
15
- memra/demos/etl_invoice_processing/etl_invoice_demo.py,sha256=6wVEAS8OMKwy4EPvDKoCov0r0QmgnfJ_Xz8zAs75haU,52813
15
+ memra/demos/etl_invoice_processing/etl_invoice_demo.py,sha256=_ogkYQpiG95a1Sc-JCgjP9zRp8HbPQL_wlc2LHIFXCE,52998
16
16
  memra/demos/etl_invoice_processing/modify_database.py,sha256=qHzBf8ukeHouaOsy0kjsfR00xCbvPUOrt1gwc4y7Xkc,1939
17
17
  memra/demos/etl_invoice_processing/run_etl_batch.py,sha256=czX-gfUuVnYb1ZjzirK7w9aa1fAUuIRCs3044AucT_Y,1928
18
18
  memra/demos/etl_invoice_processing/setup_demo_data.py,sha256=aeOZtFBBl5SZFZ5IqM35Tcc_PjEJHuc2cfY_LRWXkBM,4875
@@ -58,9 +58,9 @@ memra/demos/etl_invoice_processing/data/invoices/10352262702.PDF,sha256=aNWnxbYq
58
58
  memra/demos/etl_invoice_processing/data/invoices/10352262884.PDF,sha256=G0eszEhpTOS15hIlMyPMM6iyVw6UZPKycXvS3P42xRc,1010830
59
59
  memra/demos/etl_invoice_processing/data/invoices/10352263346.PDF,sha256=NMfsgrmaNtvNu6xk2aLtubI05I9cuVIbwJMxv_pYPhQ,1089624
60
60
  memra/demos/etl_invoice_processing/data/invoices/10352263429.PDF,sha256=1IzJbmnsKDE1cV6CtyNMENn0Rmpq2tA_BDnZYTYhNhQ,1082893
61
- memra-0.2.14.dist-info/LICENSE,sha256=8OrnTd8DWwLWmUEj5srSLvT4PREfW1Qo1T5gEUIHPws,1062
62
- memra-0.2.14.dist-info/METADATA,sha256=PlO1Afxj26BmFMIyInuh79JXmkzy929YxNa72poNPKg,9427
63
- memra-0.2.14.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
64
- memra-0.2.14.dist-info/entry_points.txt,sha256=LBVjwWoxWJRzNLgeByPn6xUvWFIRnqnemvAZgIoSt08,41
65
- memra-0.2.14.dist-info/top_level.txt,sha256=pXWcTRS1zctdiSUivW4iyKpJ4tcfIu-1BW_fpbal3OY,6
66
- memra-0.2.14.dist-info/RECORD,,
61
+ memra-0.2.16.dist-info/licenses/LICENSE,sha256=8OrnTd8DWwLWmUEj5srSLvT4PREfW1Qo1T5gEUIHPws,1062
62
+ memra-0.2.16.dist-info/METADATA,sha256=u-MAjWfwdJ9f79TA7SSGouLxrKm-RDkX12GsXR-HnXI,9497
63
+ memra-0.2.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
64
+ memra-0.2.16.dist-info/entry_points.txt,sha256=LBVjwWoxWJRzNLgeByPn6xUvWFIRnqnemvAZgIoSt08,41
65
+ memra-0.2.16.dist-info/top_level.txt,sha256=pXWcTRS1zctdiSUivW4iyKpJ4tcfIu-1BW_fpbal3OY,6
66
+ memra-0.2.16.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5