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,266 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Complete Text-to-SQL System
|
4
|
-
Demonstrates the full pipeline: English Question → Schema → SQL Generation → Execution → Real Results
|
5
|
-
"""
|
6
|
-
|
7
|
-
import os
|
8
|
-
import sys
|
9
|
-
import json
|
10
|
-
from pathlib import Path
|
11
|
-
|
12
|
-
# Add the parent directory to the path so we can import memra
|
13
|
-
sys.path.insert(0, str(Path(__file__).parent.parent))
|
14
|
-
|
15
|
-
from memra import ExecutionEngine, Agent, Tool
|
16
|
-
|
17
|
-
def create_text_to_sql_system():
|
18
|
-
"""Create a complete text-to-SQL system with real database integration"""
|
19
|
-
|
20
|
-
# Initialize execution engine
|
21
|
-
engine = ExecutionEngine()
|
22
|
-
|
23
|
-
# Schema Extraction Agent
|
24
|
-
schema_agent = Agent(
|
25
|
-
role="Database Schema Analyst",
|
26
|
-
job="Extract and analyze database schemas",
|
27
|
-
output_key="schema_data",
|
28
|
-
tools=[
|
29
|
-
Tool(
|
30
|
-
name="DatabaseQueryTool",
|
31
|
-
hosted_by="memra",
|
32
|
-
description="Query database schemas and structure"
|
33
|
-
)
|
34
|
-
]
|
35
|
-
)
|
36
|
-
|
37
|
-
# SQL Generation Agent
|
38
|
-
sql_generator_agent = Agent(
|
39
|
-
role="SQL Generator",
|
40
|
-
job="Convert natural language to SQL queries",
|
41
|
-
output_key="generated_sql",
|
42
|
-
tools=[
|
43
|
-
Tool(
|
44
|
-
name="TextToSQLGenerator",
|
45
|
-
hosted_by="mcp",
|
46
|
-
description="Generate SQL from natural language questions",
|
47
|
-
config={
|
48
|
-
"bridge_url": "http://localhost:8081",
|
49
|
-
"bridge_secret": "test-secret-for-development"
|
50
|
-
}
|
51
|
-
)
|
52
|
-
]
|
53
|
-
)
|
54
|
-
|
55
|
-
# SQL Execution Agent
|
56
|
-
sql_executor_agent = Agent(
|
57
|
-
role="SQL Executor",
|
58
|
-
job="Execute SQL queries and return results",
|
59
|
-
output_key="query_results",
|
60
|
-
tools=[
|
61
|
-
Tool(
|
62
|
-
name="SQLExecutor",
|
63
|
-
hosted_by="mcp",
|
64
|
-
description="Execute SQL queries against PostgreSQL database",
|
65
|
-
config={
|
66
|
-
"bridge_url": "http://localhost:8081",
|
67
|
-
"bridge_secret": "test-secret-for-development"
|
68
|
-
}
|
69
|
-
)
|
70
|
-
]
|
71
|
-
)
|
72
|
-
|
73
|
-
return engine, schema_agent, sql_generator_agent, sql_executor_agent
|
74
|
-
|
75
|
-
def extract_database_schema(engine, schema_agent):
|
76
|
-
"""Extract the database schema for context"""
|
77
|
-
print("🔍 Extracting database schema...")
|
78
|
-
|
79
|
-
schema_task = {
|
80
|
-
"task": "Extract the complete schema for the invoices table including column names, types, and sample data",
|
81
|
-
"table_name": "invoices",
|
82
|
-
"include_sample_data": True
|
83
|
-
}
|
84
|
-
|
85
|
-
result = engine.execute_task(schema_agent, schema_task)
|
86
|
-
|
87
|
-
if result.get("success"):
|
88
|
-
print(f"✅ Schema extracted successfully ({result.get('execution_time', 0):.1f}s)")
|
89
|
-
schema_data = result.get("result", {})
|
90
|
-
|
91
|
-
# Display schema info
|
92
|
-
if "schema" in schema_data:
|
93
|
-
print("\n📊 Database Schema:")
|
94
|
-
schema = schema_data["schema"]
|
95
|
-
for table_name, table_info in schema.items():
|
96
|
-
print(f" Table: {table_name}")
|
97
|
-
if "columns" in table_info:
|
98
|
-
for col in table_info["columns"]:
|
99
|
-
print(f" - {col['name']} ({col['type']})")
|
100
|
-
|
101
|
-
return schema_data
|
102
|
-
else:
|
103
|
-
print(f"❌ Schema extraction failed: {result.get('error', 'Unknown error')}")
|
104
|
-
return {}
|
105
|
-
|
106
|
-
def generate_sql_from_question(engine, sql_generator_agent, question, schema_info):
|
107
|
-
"""Generate SQL from natural language question"""
|
108
|
-
print(f"\n🤖 Generating SQL for: '{question}'")
|
109
|
-
|
110
|
-
sql_generation_task = {
|
111
|
-
"question": question,
|
112
|
-
"schema_info": schema_info,
|
113
|
-
"context": "Generate SQL query for invoice database analysis"
|
114
|
-
}
|
115
|
-
|
116
|
-
result = engine.execute_task(sql_generator_agent, sql_generation_task)
|
117
|
-
|
118
|
-
if result.get("success"):
|
119
|
-
print(f"✅ SQL generated successfully ({result.get('execution_time', 0):.1f}s)")
|
120
|
-
sql_data = result.get("result", {})
|
121
|
-
|
122
|
-
generated_sql = sql_data.get("generated_sql", "")
|
123
|
-
print(f"\n📝 Generated SQL:")
|
124
|
-
print(f" {generated_sql}")
|
125
|
-
|
126
|
-
return generated_sql
|
127
|
-
else:
|
128
|
-
print(f"❌ SQL generation failed: {result.get('error', 'Unknown error')}")
|
129
|
-
return None
|
130
|
-
|
131
|
-
def execute_sql_query(engine, sql_executor_agent, sql_query):
|
132
|
-
"""Execute the generated SQL query"""
|
133
|
-
print(f"\n⚡ Executing SQL query...")
|
134
|
-
|
135
|
-
execution_task = {
|
136
|
-
"sql_query": sql_query,
|
137
|
-
"timeout": 30
|
138
|
-
}
|
139
|
-
|
140
|
-
result = engine.execute_task(sql_executor_agent, execution_task)
|
141
|
-
|
142
|
-
if result.get("success"):
|
143
|
-
print(f"✅ SQL executed successfully ({result.get('execution_time', 0):.1f}s)")
|
144
|
-
query_results = result.get("result", {})
|
145
|
-
|
146
|
-
# Display results
|
147
|
-
results = query_results.get("results", [])
|
148
|
-
row_count = query_results.get("row_count", 0)
|
149
|
-
|
150
|
-
print(f"\n📋 Query Results ({row_count} rows):")
|
151
|
-
if results:
|
152
|
-
# Display first few results
|
153
|
-
for i, row in enumerate(results[:5]):
|
154
|
-
print(f" Row {i+1}: {row}")
|
155
|
-
|
156
|
-
if len(results) > 5:
|
157
|
-
print(f" ... and {len(results) - 5} more rows")
|
158
|
-
else:
|
159
|
-
print(" No results found")
|
160
|
-
|
161
|
-
return query_results
|
162
|
-
else:
|
163
|
-
print(f"❌ SQL execution failed: {result.get('error', 'Unknown error')}")
|
164
|
-
return {}
|
165
|
-
|
166
|
-
def run_text_to_sql_query(engine, schema_agent, sql_generator_agent, sql_executor_agent, question):
|
167
|
-
"""Run the complete text-to-SQL pipeline"""
|
168
|
-
print(f"\n{'='*60}")
|
169
|
-
print(f"🎯 Processing Question: {question}")
|
170
|
-
print(f"{'='*60}")
|
171
|
-
|
172
|
-
# Step 1: Extract schema (cached after first run)
|
173
|
-
if not hasattr(run_text_to_sql_query, 'cached_schema'):
|
174
|
-
run_text_to_sql_query.cached_schema = extract_database_schema(engine, schema_agent)
|
175
|
-
|
176
|
-
schema_info = run_text_to_sql_query.cached_schema
|
177
|
-
|
178
|
-
# Step 2: Generate SQL
|
179
|
-
sql_query = generate_sql_from_question(engine, sql_generator_agent, question, schema_info)
|
180
|
-
|
181
|
-
if not sql_query:
|
182
|
-
return None
|
183
|
-
|
184
|
-
# Step 3: Execute SQL
|
185
|
-
results = execute_sql_query(engine, sql_executor_agent, sql_query)
|
186
|
-
|
187
|
-
return {
|
188
|
-
"question": question,
|
189
|
-
"sql_query": sql_query,
|
190
|
-
"results": results
|
191
|
-
}
|
192
|
-
|
193
|
-
def main():
|
194
|
-
"""Main function to demonstrate the complete text-to-SQL system"""
|
195
|
-
print("🚀 Starting Complete Text-to-SQL System")
|
196
|
-
print("=" * 60)
|
197
|
-
|
198
|
-
# Create the system
|
199
|
-
engine, schema_agent, sql_generator_agent, sql_executor_agent = create_text_to_sql_system()
|
200
|
-
|
201
|
-
# Example questions to test
|
202
|
-
test_questions = [
|
203
|
-
"Show me all invoices from Air Liquide",
|
204
|
-
"What is the total amount of all invoices?",
|
205
|
-
"How many invoices do we have in the database?",
|
206
|
-
"Show me the most recent 5 invoices",
|
207
|
-
"What is the average invoice amount?",
|
208
|
-
]
|
209
|
-
|
210
|
-
print("📝 Available test questions:")
|
211
|
-
for i, question in enumerate(test_questions, 1):
|
212
|
-
print(f" {i}. {question}")
|
213
|
-
|
214
|
-
print("\n" + "="*60)
|
215
|
-
|
216
|
-
# Interactive mode
|
217
|
-
while True:
|
218
|
-
print("\n🤔 What would you like to know about the invoices?")
|
219
|
-
print(" (Enter a question, number 1-5 for examples, or 'quit' to exit)")
|
220
|
-
|
221
|
-
user_input = input("\n❓ Your question: ").strip()
|
222
|
-
|
223
|
-
if user_input.lower() in ['quit', 'exit', 'q']:
|
224
|
-
print("\n👋 Goodbye!")
|
225
|
-
break
|
226
|
-
|
227
|
-
# Check if it's a number for example questions
|
228
|
-
if user_input.isdigit():
|
229
|
-
question_num = int(user_input)
|
230
|
-
if 1 <= question_num <= len(test_questions):
|
231
|
-
question = test_questions[question_num - 1]
|
232
|
-
else:
|
233
|
-
print(f"❌ Please enter a number between 1 and {len(test_questions)}")
|
234
|
-
continue
|
235
|
-
else:
|
236
|
-
question = user_input
|
237
|
-
|
238
|
-
if not question:
|
239
|
-
print("❌ Please enter a question")
|
240
|
-
continue
|
241
|
-
|
242
|
-
# Run the complete pipeline
|
243
|
-
try:
|
244
|
-
result = run_text_to_sql_query(
|
245
|
-
engine, schema_agent, sql_generator_agent, sql_executor_agent, question
|
246
|
-
)
|
247
|
-
|
248
|
-
if result:
|
249
|
-
print(f"\n✨ Query completed successfully!")
|
250
|
-
|
251
|
-
# Check if results are real or mock
|
252
|
-
results_data = result.get("results", {})
|
253
|
-
if results_data.get("_mock"):
|
254
|
-
print("ℹ️ Note: Results are mocked (MCP bridge not fully connected)")
|
255
|
-
else:
|
256
|
-
print("🎉 Real database results!")
|
257
|
-
else:
|
258
|
-
print("❌ Query failed")
|
259
|
-
|
260
|
-
except KeyboardInterrupt:
|
261
|
-
print("\n\n⏹️ Query interrupted by user")
|
262
|
-
except Exception as e:
|
263
|
-
print(f"\n❌ Error: {str(e)}")
|
264
|
-
|
265
|
-
if __name__ == "__main__":
|
266
|
-
main()
|
@@ -1,156 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
File Discovery and Management Demo
|
4
|
-
Simple demonstration of intelligent file discovery tools
|
5
|
-
"""
|
6
|
-
|
7
|
-
import os
|
8
|
-
import sys
|
9
|
-
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
10
|
-
|
11
|
-
from memra import Agent, Department
|
12
|
-
from memra.execution import ExecutionEngine
|
13
|
-
|
14
|
-
# Set up environment
|
15
|
-
os.environ['MEMRA_API_KEY'] = 'memra-prod-2024-001'
|
16
|
-
|
17
|
-
def create_file_discovery_department():
|
18
|
-
"""Create a simple department for file discovery"""
|
19
|
-
file_manager_agent = Agent(
|
20
|
-
role="File Manager",
|
21
|
-
job="Discover and manage files in directories",
|
22
|
-
sops=[
|
23
|
-
"Scan specified directory for files matching pattern",
|
24
|
-
"List all discovered files with metadata",
|
25
|
-
"Copy files from external locations to standard directories",
|
26
|
-
"Provide file selection interface for multiple files"
|
27
|
-
],
|
28
|
-
systems=["FileSystem"],
|
29
|
-
tools=[
|
30
|
-
{"name": "FileDiscovery", "hosted_by": "mcp"}
|
31
|
-
],
|
32
|
-
input_keys=["directory", "pattern"],
|
33
|
-
output_key="file_operations"
|
34
|
-
)
|
35
|
-
|
36
|
-
return Department(
|
37
|
-
name="File Discovery",
|
38
|
-
mission="Discover files in directories",
|
39
|
-
agents=[file_manager_agent],
|
40
|
-
workflow_order=["File Manager"],
|
41
|
-
context={
|
42
|
-
"mcp_bridge_url": "http://localhost:8081",
|
43
|
-
"mcp_bridge_secret": "test-secret-for-development"
|
44
|
-
}
|
45
|
-
)
|
46
|
-
|
47
|
-
def create_file_copy_department():
|
48
|
-
"""Create a simple department for file copying"""
|
49
|
-
file_copy_agent = Agent(
|
50
|
-
role="File Copier",
|
51
|
-
job="Copy files from external locations to standard directories",
|
52
|
-
sops=[
|
53
|
-
"Accept source file path and destination directory",
|
54
|
-
"Copy file to destination with proper naming",
|
55
|
-
"Verify copy operation success",
|
56
|
-
"Return copy confirmation with metadata"
|
57
|
-
],
|
58
|
-
systems=["FileSystem"],
|
59
|
-
tools=[
|
60
|
-
{"name": "FileCopy", "hosted_by": "mcp"}
|
61
|
-
],
|
62
|
-
input_keys=["source_path", "destination_dir"],
|
63
|
-
output_key="file_operations"
|
64
|
-
)
|
65
|
-
|
66
|
-
return Department(
|
67
|
-
name="File Copy",
|
68
|
-
mission="Copy files to standard directories",
|
69
|
-
agents=[file_copy_agent],
|
70
|
-
workflow_order=["File Copier"],
|
71
|
-
context={
|
72
|
-
"mcp_bridge_url": "http://localhost:8081",
|
73
|
-
"mcp_bridge_secret": "test-secret-for-development"
|
74
|
-
}
|
75
|
-
)
|
76
|
-
|
77
|
-
def main():
|
78
|
-
print("📁 File Discovery and Management Demo")
|
79
|
-
print("=" * 50)
|
80
|
-
|
81
|
-
engine = ExecutionEngine()
|
82
|
-
|
83
|
-
# Demo 1: Discover files in invoices directory
|
84
|
-
print("\n🔍 Demo 1: Discover files in invoices/ directory")
|
85
|
-
|
86
|
-
discovery_dept = create_file_discovery_department()
|
87
|
-
discovery_input = {
|
88
|
-
"directory": "invoices",
|
89
|
-
"pattern": "*.pdf"
|
90
|
-
}
|
91
|
-
|
92
|
-
result = engine.execute_department(discovery_dept, discovery_input)
|
93
|
-
|
94
|
-
if result.success:
|
95
|
-
print("✅ File discovery completed!")
|
96
|
-
file_data = result.data.get('file_operations', {})
|
97
|
-
|
98
|
-
if 'files' in file_data:
|
99
|
-
print(f"\n📄 Found {file_data['files_found']} files:")
|
100
|
-
for file_info in file_data['files']:
|
101
|
-
print(f" • {file_info['filename']} ({file_info['size']}) - {file_info['modified']}")
|
102
|
-
else:
|
103
|
-
print(f"📊 Scanned: {file_data.get('directory', 'unknown')} directory")
|
104
|
-
print(f"🔍 Pattern: {file_data.get('pattern', 'unknown')}")
|
105
|
-
print(f"📁 Files found: {file_data.get('files_found', 0)}")
|
106
|
-
else:
|
107
|
-
print(f"❌ Discovery failed: {result.error}")
|
108
|
-
|
109
|
-
print("\n" + "="*50)
|
110
|
-
|
111
|
-
# Demo 2: Copy external file
|
112
|
-
print("\n📋 Demo 2: Copy external file to invoices/ directory")
|
113
|
-
|
114
|
-
copy_dept = create_file_copy_department()
|
115
|
-
copy_input = {
|
116
|
-
"source_path": "/Users/tarpus/Downloads/new_invoice.pdf",
|
117
|
-
"destination_dir": "invoices"
|
118
|
-
}
|
119
|
-
|
120
|
-
result = engine.execute_department(copy_dept, copy_input)
|
121
|
-
|
122
|
-
if result.success:
|
123
|
-
print("✅ File copy completed!")
|
124
|
-
copy_data = result.data.get('file_operations', {})
|
125
|
-
|
126
|
-
print(f"\n📁 Copy Details:")
|
127
|
-
print(f" Source: {copy_data.get('source_path', 'unknown')}")
|
128
|
-
print(f" Destination: {copy_data.get('destination_path', 'unknown')}")
|
129
|
-
print(f" Size: {copy_data.get('file_size', 'unknown')}")
|
130
|
-
print(f" Status: {copy_data.get('message', 'unknown')}")
|
131
|
-
else:
|
132
|
-
print(f"❌ Copy failed: {result.error}")
|
133
|
-
|
134
|
-
print("\n" + "="*50)
|
135
|
-
|
136
|
-
# Demo 3: Discover files in different directory
|
137
|
-
print("\n🗂 Demo 3: Discover files in documents/ directory")
|
138
|
-
|
139
|
-
docs_input = {
|
140
|
-
"directory": "documents",
|
141
|
-
"pattern": "*.*"
|
142
|
-
}
|
143
|
-
|
144
|
-
result = engine.execute_department(discovery_dept, docs_input)
|
145
|
-
|
146
|
-
if result.success:
|
147
|
-
print("✅ Document discovery completed!")
|
148
|
-
doc_data = result.data.get('file_operations', {})
|
149
|
-
print(f"📊 Scanned: {doc_data.get('directory', 'unknown')} directory")
|
150
|
-
print(f"🔍 Pattern: {doc_data.get('pattern', 'unknown')}")
|
151
|
-
print(f"📁 Files found: {doc_data.get('files_found', 0)}")
|
152
|
-
else:
|
153
|
-
print(f"❌ Document discovery failed: {result.error}")
|
154
|
-
|
155
|
-
if __name__ == "__main__":
|
156
|
-
main()
|
File without changes
|
File without changes
|
File without changes
|