memra 0.2.12__py3-none-any.whl → 0.2.14__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 (115) hide show
  1. memra/cli.py +143 -9
  2. memra/demos/etl_invoice_processing/check_after_workflow.py +50 -0
  3. memra/demos/etl_invoice_processing/check_database.py +44 -0
  4. memra/demos/etl_invoice_processing/check_recent_db.py +42 -0
  5. memra/demos/etl_invoice_processing/data/README.md +112 -0
  6. memra/demos/etl_invoice_processing/data/invoices/10352259401.PDF +0 -0
  7. memra/demos/etl_invoice_processing/data/invoices/10352259823.PDF +0 -0
  8. memra/demos/etl_invoice_processing/data/invoices/10352260169.PDF +0 -0
  9. memra/demos/etl_invoice_processing/data/invoices/10352260417.PDF +0 -0
  10. memra/demos/etl_invoice_processing/data/invoices/10352260599.PDF +0 -0
  11. memra/demos/etl_invoice_processing/data/invoices/10352260912.PDF +0 -0
  12. memra/demos/etl_invoice_processing/data/invoices/10352261134.PDF +0 -0
  13. memra/demos/etl_invoice_processing/data/invoices/10352261563.PDF +0 -0
  14. memra/demos/etl_invoice_processing/data/invoices/10352261647.PDF +0 -0
  15. memra/demos/etl_invoice_processing/data/invoices/10352261720.PDF +0 -0
  16. memra/demos/etl_invoice_processing/data/invoices/10352261811.PDF +0 -0
  17. memra/demos/etl_invoice_processing/data/invoices/10352262025.PDF +0 -0
  18. memra/demos/etl_invoice_processing/data/invoices/10352262454.PDF +0 -0
  19. memra/demos/etl_invoice_processing/data/invoices/10352262702.PDF +0 -0
  20. memra/demos/etl_invoice_processing/data/invoices/10352262884.PDF +0 -0
  21. memra/demos/etl_invoice_processing/data/invoices/10352263346.PDF +0 -0
  22. memra/demos/etl_invoice_processing/data/invoices/10352263429.PDF +0 -0
  23. memra/demos/etl_invoice_processing/database_monitor_agent.py +89 -0
  24. memra/demos/etl_invoice_processing/debug_mcp.py +66 -0
  25. memra/demos/etl_invoice_processing/debug_schema.py +45 -0
  26. memra/demos/etl_invoice_processing/etl_invoice_demo.py +1233 -0
  27. memra/demos/etl_invoice_processing/modify_database.py +65 -0
  28. memra/demos/etl_invoice_processing/run_etl_batch.py +60 -0
  29. memra/demos/etl_invoice_processing/setup_demo_data.py +154 -0
  30. memra/demos/etl_invoice_processing/simple_pdf_processor.py +181 -0
  31. memra/demos/etl_invoice_processing/test_agent3.py +56 -0
  32. memra/demos/etl_invoice_processing/test_agent3_v2.py +32 -0
  33. memra/demos/etl_invoice_processing/test_api.py +28 -0
  34. memra/demos/etl_invoice_processing/test_api_client_direct.py +89 -0
  35. memra/demos/etl_invoice_processing/test_conversion.py +172 -0
  36. memra/demos/etl_invoice_processing/test_debug.py +41 -0
  37. memra/demos/etl_invoice_processing/test_direct_vision.py +114 -0
  38. memra/demos/etl_invoice_processing/test_full_response.py +22 -0
  39. memra/demos/etl_invoice_processing/test_memra_response.py +124 -0
  40. memra/demos/etl_invoice_processing/test_pdf_processor_response.py +118 -0
  41. memra/demos/etl_invoice_processing/test_pdfprocessor_direct.py +96 -0
  42. memra/demos/etl_invoice_processing/test_postgres_insert.py +120 -0
  43. memra/demos/etl_invoice_processing/test_remote_upload.py +143 -0
  44. memra/demos/etl_invoice_processing/test_schema_format.py +39 -0
  45. memra/demos/etl_invoice_processing/test_sql_executor.py +58 -0
  46. memra/demos/etl_invoice_processing/test_sql_executor_extra_fields.py +61 -0
  47. memra/demos/etl_invoice_processing/test_sql_executor_fix.py +40 -0
  48. memra/demos/etl_invoice_processing/test_updated_server.py +50 -0
  49. memra/demos/etl_invoice_processing/test_upload_functionality.py +156 -0
  50. memra/demos/etl_invoice_processing/test_upload_server.py +232 -0
  51. memra/demos/etl_invoice_processing/test_vision_output.py +75 -0
  52. memra/demos/etl_invoice_processing/test_vision_prompt.py +43 -0
  53. memra/demos/etl_invoice_processing/test_vision_simple.py +60 -0
  54. {memra-0.2.12.dist-info → memra-0.2.14.dist-info}/METADATA +53 -78
  55. memra-0.2.14.dist-info/RECORD +66 -0
  56. {memra-0.2.12.dist-info → memra-0.2.14.dist-info}/WHEEL +1 -1
  57. memra-0.2.14.dist-info/top_level.txt +1 -0
  58. memra-0.2.12.dist-info/RECORD +0 -68
  59. memra-0.2.12.dist-info/top_level.txt +0 -4
  60. memra-ops/app.py +0 -808
  61. memra-ops/config/config.py +0 -25
  62. memra-ops/config.py +0 -34
  63. memra-ops/logic/__init__.py +0 -1
  64. memra-ops/logic/file_tools.py +0 -43
  65. memra-ops/logic/invoice_tools.py +0 -668
  66. memra-ops/logic/invoice_tools_fix.py +0 -66
  67. memra-ops/mcp_bridge_server.py +0 -1178
  68. memra-ops/scripts/check_database.py +0 -37
  69. memra-ops/scripts/clear_database.py +0 -48
  70. memra-ops/scripts/monitor_database.py +0 -67
  71. memra-ops/scripts/release.py +0 -133
  72. memra-ops/scripts/reset_database.py +0 -65
  73. memra-ops/scripts/start_memra.py +0 -334
  74. memra-ops/scripts/stop_memra.py +0 -132
  75. memra-ops/server_tool_registry.py +0 -190
  76. memra-ops/tests/test_llm_text_to_sql.py +0 -115
  77. memra-ops/tests/test_llm_vs_pattern.py +0 -130
  78. memra-ops/tests/test_mcp_schema_aware.py +0 -124
  79. memra-ops/tests/test_schema_aware_sql.py +0 -139
  80. memra-ops/tests/test_schema_aware_sql_simple.py +0 -66
  81. memra-ops/tests/test_text_to_sql_demo.py +0 -140
  82. memra-ops/tools/mcp_bridge_server.py +0 -851
  83. memra-sdk/examples/accounts_payable.py +0 -215
  84. memra-sdk/examples/accounts_payable_client.py +0 -217
  85. memra-sdk/examples/accounts_payable_mcp.py +0 -200
  86. memra-sdk/examples/ask_questions.py +0 -123
  87. memra-sdk/examples/invoice_processing.py +0 -116
  88. memra-sdk/examples/propane_delivery.py +0 -87
  89. memra-sdk/examples/simple_text_to_sql.py +0 -158
  90. memra-sdk/memra/__init__.py +0 -31
  91. memra-sdk/memra/discovery.py +0 -15
  92. memra-sdk/memra/discovery_client.py +0 -49
  93. memra-sdk/memra/execution.py +0 -481
  94. memra-sdk/memra/models.py +0 -99
  95. memra-sdk/memra/tool_registry.py +0 -343
  96. memra-sdk/memra/tool_registry_client.py +0 -106
  97. memra-sdk/scripts/release.py +0 -133
  98. memra-sdk/setup.py +0 -52
  99. memra-workflows/accounts_payable/accounts_payable.py +0 -215
  100. memra-workflows/accounts_payable/accounts_payable_client.py +0 -216
  101. memra-workflows/accounts_payable/accounts_payable_mcp.py +0 -200
  102. memra-workflows/accounts_payable/accounts_payable_smart.py +0 -221
  103. memra-workflows/invoice_processing/invoice_processing.py +0 -116
  104. memra-workflows/invoice_processing/smart_invoice_processor.py +0 -220
  105. memra-workflows/logic/__init__.py +0 -1
  106. memra-workflows/logic/file_tools.py +0 -50
  107. memra-workflows/logic/invoice_tools.py +0 -501
  108. memra-workflows/logic/propane_agents.py +0 -52
  109. memra-workflows/mcp_bridge_server.py +0 -230
  110. memra-workflows/propane_delivery/propane_delivery.py +0 -87
  111. memra-workflows/text_to_sql/complete_invoice_workflow_with_queries.py +0 -208
  112. memra-workflows/text_to_sql/complete_text_to_sql_system.py +0 -266
  113. memra-workflows/text_to_sql/file_discovery_demo.py +0 -156
  114. {memra-0.2.12.dist-info/licenses → memra-0.2.14.dist-info}/LICENSE +0 -0
  115. {memra-0.2.12.dist-info → memra-0.2.14.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test PostgresInsert tool with new invoice_json table
4
+ """
5
+
6
+ import os
7
+ import sys
8
+ import json
9
+ import requests
10
+
11
+ # Add the parent directory to the path to import memra
12
+ sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
13
+
14
+ from memra.tool_registry import ToolRegistry
15
+
16
+ def test_postgres_insert():
17
+ """Test PostgresInsert tool with sample invoice data"""
18
+
19
+ # Sample invoice data that includes due date
20
+ sample_invoice_data = {
21
+ "headerSection": {
22
+ "vendorName": "Test Vendor Inc.",
23
+ "subtotal": 1500.00
24
+ },
25
+ "billingDetails": {
26
+ "invoiceNumber": "TEST-001",
27
+ "invoiceDate": "2024-12-01",
28
+ "dueDate": "2024-12-31" # This was previously lost!
29
+ },
30
+ "chargesSummary": {
31
+ "document_total": 1695.00,
32
+ "secondary_tax": 195.00,
33
+ "lineItemsBreakdown": [
34
+ {
35
+ "description": "Test Service",
36
+ "quantity": 1,
37
+ "unit_price": 1500.00,
38
+ "amount": 1500.00
39
+ }
40
+ ]
41
+ }
42
+ }
43
+
44
+ print("🔧 Testing PostgresInsert tool with new invoice_json table...")
45
+ print(f"📄 Sample data includes due date: {sample_invoice_data['billingDetails']['dueDate']}")
46
+
47
+ # Test input data
48
+ input_data = {
49
+ "invoice_data": sample_invoice_data,
50
+ "table_name": "invoice_json"
51
+ }
52
+
53
+ # Execute the tool
54
+ try:
55
+ registry = ToolRegistry()
56
+ result = registry.execute_tool(
57
+ tool_name="PostgresInsert",
58
+ hosted_by="mcp",
59
+ input_data=input_data,
60
+ config={
61
+ "bridge_url": "http://localhost:8081",
62
+ "bridge_secret": "test-secret-for-development"
63
+ }
64
+ )
65
+
66
+ print(f"📊 Result: {json.dumps(result, indent=2)}")
67
+
68
+ if result.get("success"):
69
+ print("✅ PostgresInsert executed successfully!")
70
+ print(f"📝 Record ID: {result['data']['record_id']}")
71
+ print(f"📊 JSON size: {result['data']['inserted_data']['raw_json_size']} bytes")
72
+ print(f"🔑 JSON keys: {result['data']['inserted_data']['json_keys']}")
73
+
74
+ # Now let's verify the data was stored correctly
75
+ print("\n🔍 Verifying stored data...")
76
+ verify_stored_data(result['data']['record_id'])
77
+
78
+ else:
79
+ print(f"❌ PostgresInsert failed: {result.get('error')}")
80
+
81
+ except Exception as e:
82
+ print(f"❌ Error executing PostgresInsert: {str(e)}")
83
+
84
+ def verify_stored_data(record_id):
85
+ """Verify that the data was stored correctly in the database"""
86
+
87
+ # Query to get the stored JSON
88
+ query = f"SELECT raw_json FROM invoice_json WHERE id = {record_id}"
89
+
90
+ try:
91
+ registry = ToolRegistry()
92
+ result = registry.execute_tool(
93
+ tool_name="SQLExecutor",
94
+ hosted_by="mcp",
95
+ input_data={"sql_query": query},
96
+ config={
97
+ "bridge_url": "http://localhost:8081",
98
+ "bridge_secret": "test-secret-for-development"
99
+ }
100
+ )
101
+
102
+ if result.get("success") and result["data"]["results"]:
103
+ stored_json = result["data"]["results"][0]["raw_json"]
104
+ print(f"📄 Stored JSON: {json.dumps(stored_json, indent=2)}")
105
+
106
+ # Check if due date is preserved
107
+ due_date = stored_json.get("billingDetails", {}).get("dueDate")
108
+ if due_date:
109
+ print(f"✅ Due date preserved: {due_date}")
110
+ else:
111
+ print("❌ Due date not found in stored data")
112
+
113
+ else:
114
+ print(f"❌ Failed to retrieve stored data: {result.get('error')}")
115
+
116
+ except Exception as e:
117
+ print(f"❌ Error verifying stored data: {str(e)}")
118
+
119
+ if __name__ == "__main__":
120
+ test_postgres_insert()
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script to verify file upload functionality with remote API
4
+ """
5
+
6
+ import os
7
+ import base64
8
+ import requests
9
+ import json
10
+
11
+ def test_remote_upload():
12
+ """Test the complete upload and processing workflow with remote API"""
13
+
14
+ # Remote API URL
15
+ API_BASE = "https://api.memra.co"
16
+ API_KEY = "test-secret-for-development"
17
+
18
+ print("🧪 Testing Remote API File Upload Functionality")
19
+ print("=" * 50)
20
+
21
+ # Step 1: Check server health
22
+ print("\n1️⃣ Checking server health...")
23
+ try:
24
+ response = requests.get(f"{API_BASE}/health")
25
+ if response.status_code == 200:
26
+ print("✅ Server is healthy")
27
+ else:
28
+ print(f"❌ Server health check failed: {response.status_code}")
29
+ return
30
+ except Exception as e:
31
+ print(f"❌ Cannot connect to server: {e}")
32
+ return
33
+
34
+ # Step 2: Discover available tools
35
+ print("\n2️⃣ Discovering available tools...")
36
+ try:
37
+ response = requests.get(f"{API_BASE}/tools/discover", headers={"X-API-Key": API_KEY})
38
+ if response.status_code == 200:
39
+ tools = response.json().get("tools", [])
40
+ print(f"✅ Found {len(tools)} tools:")
41
+ for tool in tools:
42
+ print(f" - {tool['name']}: {tool['description']}")
43
+ else:
44
+ print(f"❌ Tool discovery failed: {response.status_code}")
45
+ print(f" Response: {response.text}")
46
+ return
47
+ except Exception as e:
48
+ print(f"❌ Tool discovery error: {e}")
49
+ return
50
+
51
+ # Step 3: Test with a real PDF file
52
+ print("\n3️⃣ Testing with real PDF file...")
53
+ pdf_path = "data/invoices/10352260169.PDF"
54
+
55
+ if not os.path.exists(pdf_path):
56
+ print(f"❌ PDF file not found: {pdf_path}")
57
+ return
58
+
59
+ print(f"✅ Found PDF file: {pdf_path}")
60
+
61
+ # Step 4: Upload the file
62
+ print("\n4️⃣ Uploading file to remote API...")
63
+ try:
64
+ with open(pdf_path, 'rb') as f:
65
+ file_content = f.read()
66
+
67
+ file_b64 = base64.b64encode(file_content).decode('utf-8')
68
+
69
+ upload_data = {
70
+ "filename": os.path.basename(pdf_path),
71
+ "content": file_b64,
72
+ "content_type": "application/pdf"
73
+ }
74
+
75
+ response = requests.post(
76
+ f"{API_BASE}/upload",
77
+ json=upload_data,
78
+ headers={
79
+ "X-API-Key": API_KEY,
80
+ "Content-Type": "application/json"
81
+ }
82
+ )
83
+
84
+ print(f"Upload response status: {response.status_code}")
85
+ print(f"Upload response: {response.text}")
86
+
87
+ if response.status_code == 200:
88
+ result = response.json()
89
+ if result.get("success"):
90
+ remote_path = result["data"]["remote_path"]
91
+ print(f"✅ File uploaded successfully")
92
+ print(f" Remote path: {remote_path}")
93
+ print(f" File ID: {result['data']['file_id']}")
94
+
95
+ # Step 5: Process the uploaded file
96
+ print("\n5️⃣ Processing uploaded file...")
97
+ process_data = {
98
+ "tool_name": "PDFProcessor",
99
+ "hosted_by": "memra",
100
+ "input_data": {
101
+ "file": remote_path
102
+ }
103
+ }
104
+
105
+ response = requests.post(
106
+ f"{API_BASE}/tools/execute",
107
+ json=process_data,
108
+ headers={
109
+ "X-API-Key": API_KEY,
110
+ "Content-Type": "application/json"
111
+ }
112
+ )
113
+
114
+ print(f"Processing response status: {response.status_code}")
115
+ print(f"Processing response: {response.text}")
116
+
117
+ if response.status_code == 200:
118
+ result = response.json()
119
+ if result.get("success") and result.get("data", {}).get("success"):
120
+ extracted_data = result["data"]["data"].get("extracted_data", {})
121
+ print("✅ File processed successfully")
122
+ print("📄 Extracted data:")
123
+ print(f" Vendor: {extracted_data.get('headerSection', {}).get('vendorName', 'N/A')}")
124
+ print(f" Invoice: {extracted_data.get('billingDetails', {}).get('invoiceNumber', 'N/A')}")
125
+ print(f" Amount: ${extracted_data.get('chargesSummary', {}).get('document_total', 'N/A')}")
126
+ else:
127
+ print(f"❌ Processing failed: {result.get('data', {}).get('error', 'Unknown error')}")
128
+ else:
129
+ print(f"❌ Processing request failed: {response.status_code}")
130
+ print(f" Response: {response.text}")
131
+ else:
132
+ print(f"❌ Upload failed: {result.get('error')}")
133
+ else:
134
+ print(f"❌ Upload request failed: {response.status_code}")
135
+ print(f" Response: {response.text}")
136
+
137
+ except Exception as e:
138
+ print(f"❌ Upload/Processing error: {e}")
139
+
140
+ print("\n🎉 Test completed!")
141
+
142
+ if __name__ == "__main__":
143
+ test_remote_upload()
@@ -0,0 +1,39 @@
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 with a more detailed schema format
9
+ schema = {
10
+ "fields": [
11
+ {"name": "invoice_number", "type": "string", "required": True},
12
+ {"name": "vendor_name", "type": "string", "required": True},
13
+ {"name": "invoice_date", "type": "date", "required": True},
14
+ {"name": "total_amount", "type": "numeric", "required": True}
15
+ ]
16
+ }
17
+
18
+ print("Testing PDFProcessor with schema:")
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
+ if resp.status_code == 200:
35
+ result = resp.json()
36
+ if result.get('success') and 'data' in result and 'data' in result['data']:
37
+ prompt = result['data']['data'].get('vision_prompt', '')
38
+ print("\nVision prompt generated:")
39
+ print(prompt[:500])
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test SQLExecutor tool execution directly
4
+ """
5
+
6
+ import sys
7
+ import os
8
+ sys.path.insert(0, '/Users/tarpus/memra')
9
+
10
+ from memra.tool_registry import ToolRegistry
11
+ import logging
12
+
13
+ # Set up logging
14
+ logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(name)s:%(message)s')
15
+ logger = logging.getLogger(__name__)
16
+
17
+ def test_sql_executor():
18
+ """Test SQLExecutor tool execution"""
19
+
20
+ # Create tool registry
21
+ registry = ToolRegistry()
22
+
23
+ # Test configuration
24
+ config = {
25
+ "bridge_url": "http://localhost:8081",
26
+ "bridge_secret": "test-secret-for-development"
27
+ }
28
+
29
+ # Test input data
30
+ input_data = {
31
+ "sql_query": "SELECT COUNT(*) as row_count FROM invoices"
32
+ }
33
+
34
+ print("🔧 Testing SQLExecutor tool execution...")
35
+ print(f"Config: {config}")
36
+ print(f"Input: {input_data}")
37
+
38
+ # Execute the tool
39
+ result = registry.execute_tool(
40
+ tool_name="SQLExecutor",
41
+ hosted_by="mcp",
42
+ input_data=input_data,
43
+ config=config
44
+ )
45
+
46
+ print(f"\n📊 Result: {result}")
47
+
48
+ if result.get("success"):
49
+ print("✅ SQLExecutor executed successfully!")
50
+ if "_mock" in result.get("data", {}):
51
+ print("⚠️ But returned mock data")
52
+ else:
53
+ print("🎉 Real data returned!")
54
+ else:
55
+ print(f"❌ SQLExecutor failed: {result.get('error')}")
56
+
57
+ if __name__ == "__main__":
58
+ test_sql_executor()
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test SQLExecutor tool execution with extra fields (like agent_input)
4
+ """
5
+
6
+ import sys
7
+ import os
8
+ sys.path.insert(0, '/Users/tarpus/memra')
9
+
10
+ from memra.tool_registry import ToolRegistry
11
+ import logging
12
+
13
+ # Set up logging
14
+ logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(name)s:%(message)s')
15
+ logger = logging.getLogger(__name__)
16
+
17
+ def test_sql_executor_with_extra_fields():
18
+ """Test SQLExecutor tool execution with extra fields like agent_input"""
19
+
20
+ # Create tool registry
21
+ registry = ToolRegistry()
22
+
23
+ # Test configuration
24
+ config = {
25
+ "bridge_url": "http://localhost:8081",
26
+ "bridge_secret": "test-secret-for-development"
27
+ }
28
+
29
+ # Test input data with extra fields (like agent_input)
30
+ input_data = {
31
+ "sql_query": "SELECT COUNT(*) as row_count FROM invoices",
32
+ "table_name": "invoices",
33
+ "connection": "postgresql://memra:memra123@localhost:5432/memra_invoice_db",
34
+ "monitoring_phase": "before"
35
+ }
36
+
37
+ print("🔧 Testing SQLExecutor tool execution with extra fields...")
38
+ print(f"Config: {config}")
39
+ print(f"Input: {input_data}")
40
+
41
+ # Execute the tool
42
+ result = registry.execute_tool(
43
+ tool_name="SQLExecutor",
44
+ hosted_by="mcp",
45
+ input_data=input_data,
46
+ config=config
47
+ )
48
+
49
+ print(f"\n📊 Result: {result}")
50
+
51
+ if result.get("success"):
52
+ print("✅ SQLExecutor executed successfully!")
53
+ if "_mock" in result.get("data", {}):
54
+ print("⚠️ But returned mock data")
55
+ else:
56
+ print("🎉 Real data returned!")
57
+ else:
58
+ print(f"❌ SQLExecutor failed: {result.get('error')}")
59
+
60
+ if __name__ == "__main__":
61
+ test_sql_executor_with_extra_fields()
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test SQLExecutor fix in execution engine
4
+ """
5
+
6
+ import sys
7
+ import os
8
+ sys.path.insert(0, '/Users/tarpus/memra')
9
+
10
+ from memra.execution import ExecutionEngine
11
+
12
+ def test_sql_executor_real_work():
13
+ """Test that SQLExecutor is correctly identified as real work"""
14
+
15
+ engine = ExecutionEngine()
16
+
17
+ # Mock SQLExecutor result (what the MCP bridge returns)
18
+ sql_executor_result = {
19
+ "query": "SELECT COUNT(*) as row_count FROM invoices",
20
+ "results": [{"row_count": 3}],
21
+ "row_count": 1,
22
+ "columns": ["row_count"],
23
+ "success": True
24
+ }
25
+
26
+ print("🔧 Testing SQLExecutor real work detection...")
27
+ print(f"SQLExecutor result: {sql_executor_result}")
28
+
29
+ # Test the _is_real_work method
30
+ is_real = engine._is_real_work("SQLExecutor", sql_executor_result)
31
+
32
+ print(f"✅ Is real work: {is_real}")
33
+
34
+ if is_real:
35
+ print("🎉 SQLExecutor fix is working!")
36
+ else:
37
+ print("❌ SQLExecutor fix is not working!")
38
+
39
+ if __name__ == "__main__":
40
+ test_sql_executor_real_work()
@@ -0,0 +1,50 @@
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 with the schema format the client sends
9
+ schema = [
10
+ {"column_name": "invoice_number", "data_type": "character varying", "is_nullable": "NO"},
11
+ {"column_name": "vendor_name", "data_type": "character varying", "is_nullable": "NO"},
12
+ {"column_name": "invoice_date", "data_type": "date", "is_nullable": "NO"},
13
+ {"column_name": "total_amount", "data_type": "numeric", "is_nullable": "NO"}
14
+ ]
15
+
16
+ print("Testing updated server with client schema format:")
17
+ print(json.dumps(schema[:2], indent=2)) # Show first 2 fields
18
+
19
+ resp = requests.post(
20
+ f"{api_url}/tools/execute",
21
+ json={
22
+ "tool_name": "PDFProcessor",
23
+ "hosted_by": "memra",
24
+ "input_data": {
25
+ "file": "/uploads/6f4538c0-8fce-4488-be49-1a78afc58a4a.pdf",
26
+ "schema": schema
27
+ }
28
+ },
29
+ headers={"X-API-Key": api_key}
30
+ )
31
+
32
+ print(f"\nResponse status: {resp.status_code}")
33
+ if resp.status_code == 200:
34
+ result = resp.json()
35
+ if result.get('success') and 'data' in result and 'data' in result['data']:
36
+ data = result['data']['data']
37
+ vision_prompt = data.get('vision_prompt', '')
38
+ print(f"\nVision prompt generated (first 500 chars):")
39
+ print(vision_prompt[:500])
40
+
41
+ # Check if vendor_name is in the prompt
42
+ if 'vendor_name' in vision_prompt:
43
+ print("\n✅ SUCCESS: vendor_name is now in the vision prompt\!")
44
+ else:
45
+ print("\n❌ FAIL: vendor_name is NOT in the vision prompt")
46
+
47
+ # Check vision response
48
+ vision_resp = data.get('vision_response', '')
49
+ if vision_resp:
50
+ print(f"\nVision response includes vendor info: {'vendor' in vision_resp.lower()}")
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script to verify file upload functionality
4
+ """
5
+
6
+ import os
7
+ import base64
8
+ import requests
9
+ import json
10
+
11
+ def test_upload_functionality():
12
+ """Test the complete upload and processing workflow"""
13
+
14
+ # Test server URL (change this to api.memra.co when implementing on remote)
15
+ API_BASE = "http://localhost:8000"
16
+
17
+ print("🧪 Testing File Upload Functionality")
18
+ print("=" * 50)
19
+
20
+ # Step 1: Check server health
21
+ print("\n1️⃣ Checking server health...")
22
+ try:
23
+ response = requests.get(f"{API_BASE}/health")
24
+ if response.status_code == 200:
25
+ print("✅ Server is healthy")
26
+ else:
27
+ print(f"❌ Server health check failed: {response.status_code}")
28
+ return
29
+ except Exception as e:
30
+ print(f"❌ Cannot connect to server: {e}")
31
+ print("💡 Make sure to start the test server: python3 test_upload_server.py")
32
+ return
33
+
34
+ # Step 2: Discover available tools
35
+ print("\n2️⃣ Discovering available tools...")
36
+ try:
37
+ response = requests.get(f"{API_BASE}/tools/discover")
38
+ if response.status_code == 200:
39
+ tools = response.json().get("tools", [])
40
+ print(f"✅ Found {len(tools)} tools:")
41
+ for tool in tools:
42
+ print(f" - {tool['name']}: {tool['description']}")
43
+ else:
44
+ print(f"❌ Tool discovery failed: {response.status_code}")
45
+ return
46
+ except Exception as e:
47
+ print(f"❌ Tool discovery error: {e}")
48
+ return
49
+
50
+ # Step 3: Create a test PDF file
51
+ print("\n3️⃣ Creating test PDF file...")
52
+ test_pdf_path = "test_invoice.pdf"
53
+
54
+ # Create a simple test PDF (this is just for testing - in real usage you'd use actual PDFs)
55
+ try:
56
+ # For testing, we'll create a simple text file and pretend it's a PDF
57
+ with open(test_pdf_path, 'w') as f:
58
+ f.write("Test Invoice\nVendor: Test Corp\nAmount: $1234.56\n")
59
+ print(f"✅ Created test file: {test_pdf_path}")
60
+ except Exception as e:
61
+ print(f"❌ Failed to create test file: {e}")
62
+ return
63
+
64
+ # Step 4: Upload the file
65
+ print("\n4️⃣ Uploading file to server...")
66
+ try:
67
+ with open(test_pdf_path, 'rb') as f:
68
+ file_content = f.read()
69
+
70
+ file_b64 = base64.b64encode(file_content).decode('utf-8')
71
+
72
+ upload_data = {
73
+ "filename": os.path.basename(test_pdf_path),
74
+ "content": file_b64,
75
+ "content_type": "application/pdf"
76
+ }
77
+
78
+ response = requests.post(
79
+ f"{API_BASE}/upload",
80
+ json=upload_data,
81
+ headers={"Content-Type": "application/json"}
82
+ )
83
+
84
+ if response.status_code == 200:
85
+ result = response.json()
86
+ if result.get("success"):
87
+ remote_path = result["data"]["remote_path"]
88
+ print(f"✅ File uploaded successfully")
89
+ print(f" Remote path: {remote_path}")
90
+ print(f" File ID: {result['data']['file_id']}")
91
+ else:
92
+ print(f"❌ Upload failed: {result.get('error')}")
93
+ return
94
+ else:
95
+ print(f"❌ Upload request failed: {response.status_code}")
96
+ print(f" Response: {response.text}")
97
+ return
98
+
99
+ except Exception as e:
100
+ print(f"❌ Upload error: {e}")
101
+ return
102
+
103
+ # Step 5: Process the uploaded file
104
+ print("\n5️⃣ Processing uploaded file...")
105
+ try:
106
+ process_data = {
107
+ "tool_name": "PDFProcessor",
108
+ "hosted_by": "memra",
109
+ "input_data": {
110
+ "file": remote_path
111
+ }
112
+ }
113
+
114
+ response = requests.post(
115
+ f"{API_BASE}/tools/execute",
116
+ json=process_data,
117
+ headers={"Content-Type": "application/json"}
118
+ )
119
+
120
+ if response.status_code == 200:
121
+ result = response.json()
122
+ if result.get("success"):
123
+ extracted_data = result["data"]["extracted_data"]
124
+ print("✅ File processed successfully")
125
+ print("📄 Extracted data:")
126
+ print(f" Vendor: {extracted_data['headerSection']['vendorName']}")
127
+ print(f" Invoice: {extracted_data['billingDetails']['invoiceNumber']}")
128
+ print(f" Amount: ${extracted_data['chargesSummary']['document_total']}")
129
+ else:
130
+ print(f"❌ Processing failed: {result.get('error')}")
131
+ return
132
+ else:
133
+ print(f"❌ Processing request failed: {response.status_code}")
134
+ print(f" Response: {response.text}")
135
+ return
136
+
137
+ except Exception as e:
138
+ print(f"❌ Processing error: {e}")
139
+ return
140
+
141
+ # Step 6: Cleanup
142
+ print("\n6️⃣ Cleaning up...")
143
+ try:
144
+ os.remove(test_pdf_path)
145
+ print("✅ Test file removed")
146
+ except:
147
+ pass
148
+
149
+ print("\n🎉 All tests passed! File upload functionality is working correctly.")
150
+ print("\n📋 Next Steps:")
151
+ print("1. Implement the upload endpoint on the remote API (api.memra.co)")
152
+ print("2. Update the demo to use the real remote API")
153
+ print("3. Test with actual PDF files")
154
+
155
+ if __name__ == "__main__":
156
+ test_upload_functionality()