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,123 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Simple interactive script to ask questions about invoices
|
4
|
-
"""
|
5
|
-
|
6
|
-
import requests
|
7
|
-
import json
|
8
|
-
|
9
|
-
def ask_question(question):
|
10
|
-
"""Ask a question and get SQL + results"""
|
11
|
-
bridge_url = "http://localhost:8081"
|
12
|
-
bridge_secret = "test-secret-for-development"
|
13
|
-
|
14
|
-
# No hard-coded schema - let the server fetch it dynamically
|
15
|
-
schema_info = {}
|
16
|
-
|
17
|
-
headers = {
|
18
|
-
"Content-Type": "application/json",
|
19
|
-
"X-Bridge-Secret": bridge_secret
|
20
|
-
}
|
21
|
-
|
22
|
-
print(f"\n🤖 Processing: {question}")
|
23
|
-
print("-" * 50)
|
24
|
-
|
25
|
-
# Step 1: Generate SQL
|
26
|
-
sql_request = {
|
27
|
-
"tool_name": "TextToSQLGenerator",
|
28
|
-
"input_data": {
|
29
|
-
"question": question,
|
30
|
-
"schema_info": schema_info
|
31
|
-
}
|
32
|
-
}
|
33
|
-
|
34
|
-
try:
|
35
|
-
response = requests.post(f"{bridge_url}/execute_tool", json=sql_request, headers=headers, timeout=60)
|
36
|
-
|
37
|
-
if response.status_code != 200:
|
38
|
-
print(f"❌ SQL generation failed: HTTP {response.status_code}")
|
39
|
-
return
|
40
|
-
|
41
|
-
result = response.json()
|
42
|
-
if not result.get("success"):
|
43
|
-
print(f"❌ SQL generation failed: {result.get('error')}")
|
44
|
-
return
|
45
|
-
|
46
|
-
data = result.get("data", {})
|
47
|
-
sql_query = data.get("generated_sql", "")
|
48
|
-
method = data.get("method", "unknown")
|
49
|
-
|
50
|
-
# Check if SQL is incomplete
|
51
|
-
if not sql_query or sql_query.strip() == "SELECT" or len(sql_query.strip()) < 10:
|
52
|
-
print(f"❌ Generated incomplete SQL: '{sql_query}'")
|
53
|
-
print("💡 Try rephrasing your question more simply")
|
54
|
-
return
|
55
|
-
|
56
|
-
print(f"📝 Generated SQL: {sql_query}")
|
57
|
-
print(f"💡 Method: {method}")
|
58
|
-
|
59
|
-
# Step 2: Execute SQL
|
60
|
-
exec_request = {
|
61
|
-
"tool_name": "SQLExecutor",
|
62
|
-
"input_data": {
|
63
|
-
"sql_query": sql_query
|
64
|
-
}
|
65
|
-
}
|
66
|
-
|
67
|
-
response = requests.post(f"{bridge_url}/execute_tool", json=exec_request, headers=headers, timeout=60)
|
68
|
-
|
69
|
-
if response.status_code != 200:
|
70
|
-
print(f"❌ SQL execution failed: HTTP {response.status_code}")
|
71
|
-
return
|
72
|
-
|
73
|
-
result = response.json()
|
74
|
-
if not result.get("success"):
|
75
|
-
print(f"❌ SQL execution failed: {result.get('error')}")
|
76
|
-
return
|
77
|
-
|
78
|
-
exec_data = result.get("data", {})
|
79
|
-
results = exec_data.get("results", [])
|
80
|
-
row_count = exec_data.get("row_count", 0)
|
81
|
-
|
82
|
-
print(f"\n📊 Results ({row_count} rows):")
|
83
|
-
if results:
|
84
|
-
# Show first 5 results
|
85
|
-
for i, row in enumerate(results[:5], 1):
|
86
|
-
print(f" {i}. {row}")
|
87
|
-
|
88
|
-
if len(results) > 5:
|
89
|
-
print(f" ... and {len(results) - 5} more rows")
|
90
|
-
else:
|
91
|
-
print(" No results found")
|
92
|
-
|
93
|
-
except Exception as e:
|
94
|
-
print(f"❌ Error: {str(e)}")
|
95
|
-
|
96
|
-
def main():
|
97
|
-
"""Interactive question asking"""
|
98
|
-
print("🎯 Invoice Question Assistant")
|
99
|
-
print("=" * 50)
|
100
|
-
print("Ask questions about your invoices in natural language!")
|
101
|
-
print("Examples:")
|
102
|
-
print(" - Show me all invoices from Air Liquide")
|
103
|
-
print(" - Find invoices with amounts greater than 1000")
|
104
|
-
print(" - What is the total amount of all invoices?")
|
105
|
-
print(" - How many invoices do we have?")
|
106
|
-
print("\nType 'quit' to exit")
|
107
|
-
|
108
|
-
while True:
|
109
|
-
print("\n" + "="*50)
|
110
|
-
question = input("❓ Your question: ").strip()
|
111
|
-
|
112
|
-
if question.lower() in ['quit', 'exit', 'q']:
|
113
|
-
print("👋 Goodbye!")
|
114
|
-
break
|
115
|
-
|
116
|
-
if not question:
|
117
|
-
print("Please enter a question")
|
118
|
-
continue
|
119
|
-
|
120
|
-
ask_question(question)
|
121
|
-
|
122
|
-
if __name__ == "__main__":
|
123
|
-
main()
|
@@ -1,116 +0,0 @@
|
|
1
|
-
from memra import Agent, Department, LLM
|
2
|
-
|
3
|
-
# Define LLMs that agents can use
|
4
|
-
default_llm = LLM(model="gpt-4", temperature=0.1)
|
5
|
-
parsing_llm = LLM(model="claude-3-opus", temperature=0) # More accurate for structured extraction
|
6
|
-
manager_llm = LLM(model="gpt-4-turbo", temperature=0.3) # Balanced for decision-making
|
7
|
-
|
8
|
-
# Define agents with specific LLMs
|
9
|
-
etl_agent = Agent(
|
10
|
-
role="Data Engineer",
|
11
|
-
job="Extract invoice schema from Postgres database",
|
12
|
-
llm=default_llm, # Standard LLM for SQL generation
|
13
|
-
sops=[
|
14
|
-
"Connect to PostgresDB using credentials",
|
15
|
-
"Query information_schema for invoices table",
|
16
|
-
"Extract column names, types, and constraints",
|
17
|
-
"Return schema as structured JSON"
|
18
|
-
],
|
19
|
-
systems=["PostgresDB"],
|
20
|
-
tools=[
|
21
|
-
{"name": "DatabaseQueryTool", "hosted_by": "memra"}
|
22
|
-
],
|
23
|
-
output_key="invoice_schema"
|
24
|
-
)
|
25
|
-
|
26
|
-
parser_agent = Agent(
|
27
|
-
role="Invoice Parser",
|
28
|
-
job="Extract structured data from invoice PDF using schema",
|
29
|
-
llm=parsing_llm, # High-accuracy LLM for document parsing
|
30
|
-
sops=[
|
31
|
-
"Load invoice PDF file",
|
32
|
-
"Convert to high-contrast images if needed",
|
33
|
-
"Run OCR to extract text",
|
34
|
-
"Use schema to identify and extract fields",
|
35
|
-
"Validate extracted data against schema types",
|
36
|
-
"Return structured invoice data"
|
37
|
-
],
|
38
|
-
systems=["InvoiceStore"],
|
39
|
-
tools=[
|
40
|
-
{"name": "PDFProcessor", "hosted_by": "memra"},
|
41
|
-
{"name": "OCRTool", "hosted_by": "memra"},
|
42
|
-
{"name": "InvoiceExtractionWorkflow", "hosted_by": "memra"}
|
43
|
-
],
|
44
|
-
input_keys=["file", "invoice_schema"],
|
45
|
-
output_key="invoice_data"
|
46
|
-
)
|
47
|
-
|
48
|
-
writer_agent = Agent(
|
49
|
-
role="Data Entry Specialist",
|
50
|
-
job="Write validated invoice data to Postgres database",
|
51
|
-
llm=default_llm,
|
52
|
-
sops=[
|
53
|
-
"Validate invoice data completeness",
|
54
|
-
"Map fields to database columns using schema",
|
55
|
-
"Connect to PostgresDB",
|
56
|
-
"Insert record into invoices table",
|
57
|
-
"Return confirmation with record ID"
|
58
|
-
],
|
59
|
-
systems=["PostgresDB"],
|
60
|
-
tools=[
|
61
|
-
{"name": "DataValidator", "hosted_by": "memra"},
|
62
|
-
{"name": "PostgresInsert", "hosted_by": "mcp"}
|
63
|
-
],
|
64
|
-
input_keys=["invoice_data", "invoice_schema"],
|
65
|
-
output_key="write_confirmation"
|
66
|
-
)
|
67
|
-
|
68
|
-
# Manager with its own LLM
|
69
|
-
manager_agent = Agent(
|
70
|
-
role="Accounts Payable Manager",
|
71
|
-
job="Coordinate invoice processing pipeline and handle exceptions",
|
72
|
-
llm=manager_llm, # Manager gets a more flexible LLM
|
73
|
-
sops=[
|
74
|
-
"Check if schema extraction succeeded",
|
75
|
-
"If schema missing, delegate to Schema Loader",
|
76
|
-
"Validate parsed invoice has required fields",
|
77
|
-
"Ensure invoice total matches line items before DB write",
|
78
|
-
"Handle and log any errors with appropriate escalation"
|
79
|
-
],
|
80
|
-
allow_delegation=True,
|
81
|
-
fallback_agents={
|
82
|
-
"Data Engineer": "Schema Loader"
|
83
|
-
},
|
84
|
-
output_key="workflow_status"
|
85
|
-
)
|
86
|
-
|
87
|
-
# Create the Accounts Payable Department
|
88
|
-
ap_department = Department(
|
89
|
-
name="Accounts Payable",
|
90
|
-
mission="Process invoices accurately into financial system per company data standards",
|
91
|
-
agents=[etl_agent, parser_agent, writer_agent],
|
92
|
-
manager_agent=manager_agent,
|
93
|
-
default_llm=default_llm, # Fallback for any agent without explicit LLM
|
94
|
-
workflow_order=["Data Engineer", "Invoice Parser", "Data Entry Specialist"]
|
95
|
-
)
|
96
|
-
|
97
|
-
# Example usage
|
98
|
-
if __name__ == "__main__":
|
99
|
-
from memra.execution import ExecutionEngine
|
100
|
-
|
101
|
-
# This is how a developer would use the department
|
102
|
-
engine = ExecutionEngine()
|
103
|
-
input_data = {
|
104
|
-
"file": "path/to/invoice.pdf",
|
105
|
-
"connection": "postgres://ap_user:password@localhost:5432/finance"
|
106
|
-
}
|
107
|
-
|
108
|
-
result = engine.execute_department(ap_department, input_data)
|
109
|
-
|
110
|
-
if result.success:
|
111
|
-
print("✅ Invoice processing completed!")
|
112
|
-
print(f"Result: {result.data}")
|
113
|
-
else:
|
114
|
-
print(f"❌ Processing failed: {result.error}")
|
115
|
-
|
116
|
-
print(f"Workflow result: {result}")
|
@@ -1,87 +0,0 @@
|
|
1
|
-
from memra.sdk.models import Agent, Department, Tool
|
2
|
-
|
3
|
-
# Define the tools that our agents will use
|
4
|
-
data_extraction_tool = Tool(
|
5
|
-
name="PropaneDataExtractor",
|
6
|
-
description="Extracts propane-related data from various sources",
|
7
|
-
hosted_by="memra"
|
8
|
-
)
|
9
|
-
|
10
|
-
planning_tool = Tool(
|
11
|
-
name="PropaneDeliveryPlanner",
|
12
|
-
description="Plans optimal propane delivery routes and schedules",
|
13
|
-
hosted_by="memra"
|
14
|
-
)
|
15
|
-
|
16
|
-
execution_tool = Tool(
|
17
|
-
name="PropaneDeliveryExecutor",
|
18
|
-
description="Executes and tracks propane deliveries",
|
19
|
-
hosted_by="memra"
|
20
|
-
)
|
21
|
-
|
22
|
-
# Define our agents
|
23
|
-
data_extractor = Agent(
|
24
|
-
role="Data Extraction Specialist",
|
25
|
-
job="Extract and validate propane delivery data",
|
26
|
-
tools=[data_extraction_tool],
|
27
|
-
systems=["CustomerDatabase", "PropaneLevelsAPI"],
|
28
|
-
input_keys=["customer_ids", "date_range"],
|
29
|
-
output_key="extracted_data"
|
30
|
-
)
|
31
|
-
|
32
|
-
delivery_planner = Agent(
|
33
|
-
role="Delivery Route Planner",
|
34
|
-
job="Plan optimal delivery routes and schedules",
|
35
|
-
tools=[planning_tool],
|
36
|
-
systems=["RouteOptimizationEngine"],
|
37
|
-
input_keys=["extracted_data"],
|
38
|
-
output_key="delivery_plan"
|
39
|
-
)
|
40
|
-
|
41
|
-
delivery_executor = Agent(
|
42
|
-
role="Delivery Coordinator",
|
43
|
-
job="Execute and monitor propane deliveries",
|
44
|
-
tools=[execution_tool],
|
45
|
-
systems=["DeliveryTrackingSystem"],
|
46
|
-
input_keys=["delivery_plan"],
|
47
|
-
output_key="delivery_status"
|
48
|
-
)
|
49
|
-
|
50
|
-
# Define the manager agent that oversees the workflow
|
51
|
-
manager = Agent(
|
52
|
-
role="Propane Operations Manager",
|
53
|
-
job="Oversee and coordinate the propane delivery workflow",
|
54
|
-
llm={"model": "claude-3-opus"},
|
55
|
-
sops=[
|
56
|
-
"Validate data quality",
|
57
|
-
"Handle delivery exceptions",
|
58
|
-
"Optimize resource allocation"
|
59
|
-
],
|
60
|
-
input_keys=["extracted_data", "delivery_plan", "delivery_status"],
|
61
|
-
output_key="workflow_status"
|
62
|
-
)
|
63
|
-
|
64
|
-
# Create the Propane Delivery Department
|
65
|
-
propane_department = Department(
|
66
|
-
name="Propane Delivery Operations",
|
67
|
-
mission="Efficiently manage and execute propane deliveries",
|
68
|
-
agents=[data_extractor, delivery_planner, delivery_executor],
|
69
|
-
manager_agent=manager,
|
70
|
-
workflow_order=[
|
71
|
-
"Data Extraction Specialist",
|
72
|
-
"Delivery Route Planner",
|
73
|
-
"Delivery Coordinator"
|
74
|
-
]
|
75
|
-
)
|
76
|
-
|
77
|
-
# Example usage
|
78
|
-
if __name__ == "__main__":
|
79
|
-
# This is how a developer would use the department
|
80
|
-
result = propane_department.run({
|
81
|
-
"customer_ids": ["CUST001", "CUST002"],
|
82
|
-
"date_range": {
|
83
|
-
"start": "2024-03-20",
|
84
|
-
"end": "2024-03-27"
|
85
|
-
}
|
86
|
-
})
|
87
|
-
print(f"Workflow result: {result}")
|
@@ -1,158 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Simple Text-to-SQL Interface
|
4
|
-
Direct connection to MCP bridge for asking questions about invoices
|
5
|
-
"""
|
6
|
-
|
7
|
-
import requests
|
8
|
-
import json
|
9
|
-
|
10
|
-
def ask_question(question):
|
11
|
-
"""Ask a question and get SQL + results"""
|
12
|
-
bridge_url = "http://localhost:8081"
|
13
|
-
bridge_secret = "test-secret-for-development"
|
14
|
-
|
15
|
-
# Simulated schema info (in real system this would come from schema extraction)
|
16
|
-
schema_info = {
|
17
|
-
"schema": {
|
18
|
-
"invoices": {
|
19
|
-
"columns": [
|
20
|
-
{"name": "id", "type": "integer"},
|
21
|
-
{"name": "vendor_name", "type": "text"},
|
22
|
-
{"name": "invoice_number", "type": "text"},
|
23
|
-
{"name": "invoice_date", "type": "date"},
|
24
|
-
{"name": "total_amount", "type": "numeric"},
|
25
|
-
{"name": "tax_amount", "type": "numeric"},
|
26
|
-
{"name": "line_items", "type": "jsonb"},
|
27
|
-
{"name": "status", "type": "text"}
|
28
|
-
]
|
29
|
-
}
|
30
|
-
}
|
31
|
-
}
|
32
|
-
|
33
|
-
headers = {
|
34
|
-
"Content-Type": "application/json",
|
35
|
-
"X-Bridge-Secret": bridge_secret
|
36
|
-
}
|
37
|
-
|
38
|
-
print(f"\n🤖 Processing: {question}")
|
39
|
-
print("-" * 50)
|
40
|
-
|
41
|
-
# Step 1: Generate SQL
|
42
|
-
sql_request = {
|
43
|
-
"tool_name": "TextToSQLGenerator",
|
44
|
-
"input_data": {
|
45
|
-
"question": question,
|
46
|
-
"schema_info": schema_info
|
47
|
-
}
|
48
|
-
}
|
49
|
-
|
50
|
-
try:
|
51
|
-
response = requests.post(f"{bridge_url}/execute_tool", json=sql_request, headers=headers, timeout=10)
|
52
|
-
|
53
|
-
if response.status_code != 200:
|
54
|
-
print(f"❌ SQL generation failed: HTTP {response.status_code}")
|
55
|
-
return
|
56
|
-
|
57
|
-
result = response.json()
|
58
|
-
if not result.get("success"):
|
59
|
-
print(f"❌ SQL generation failed: {result.get('error')}")
|
60
|
-
return
|
61
|
-
|
62
|
-
data = result.get("data", {})
|
63
|
-
sql_query = data.get("generated_sql", "")
|
64
|
-
explanation = data.get("explanation", "")
|
65
|
-
|
66
|
-
print(f"📝 Generated SQL: {sql_query}")
|
67
|
-
print(f"💡 Explanation: {explanation}")
|
68
|
-
|
69
|
-
# Step 2: Execute SQL
|
70
|
-
exec_request = {
|
71
|
-
"tool_name": "SQLExecutor",
|
72
|
-
"input_data": {
|
73
|
-
"sql_query": sql_query
|
74
|
-
}
|
75
|
-
}
|
76
|
-
|
77
|
-
response = requests.post(f"{bridge_url}/execute_tool", json=exec_request, headers=headers, timeout=10)
|
78
|
-
|
79
|
-
if response.status_code != 200:
|
80
|
-
print(f"❌ SQL execution failed: HTTP {response.status_code}")
|
81
|
-
return
|
82
|
-
|
83
|
-
result = response.json()
|
84
|
-
if not result.get("success"):
|
85
|
-
print(f"❌ SQL execution failed: {result.get('error')}")
|
86
|
-
return
|
87
|
-
|
88
|
-
exec_data = result.get("data", {})
|
89
|
-
results = exec_data.get("results", [])
|
90
|
-
row_count = exec_data.get("row_count", 0)
|
91
|
-
|
92
|
-
print(f"\n📊 Results ({row_count} rows):")
|
93
|
-
if results:
|
94
|
-
# Show first 10 results
|
95
|
-
for i, row in enumerate(results[:10], 1):
|
96
|
-
print(f" {i}. {row}")
|
97
|
-
|
98
|
-
if len(results) > 10:
|
99
|
-
print(f" ... and {len(results) - 10} more rows")
|
100
|
-
else:
|
101
|
-
print(" No results found")
|
102
|
-
|
103
|
-
except Exception as e:
|
104
|
-
print(f"❌ Error: {str(e)}")
|
105
|
-
|
106
|
-
def main():
|
107
|
-
"""Interactive text-to-SQL interface"""
|
108
|
-
print("🚀 Simple Text-to-SQL Interface")
|
109
|
-
print("=" * 50)
|
110
|
-
print("Ask questions about your invoice database!")
|
111
|
-
print("Examples:")
|
112
|
-
print(" • Show me all invoices from Air Liquide")
|
113
|
-
print(" • What is the total amount of all invoices?")
|
114
|
-
print(" • How many invoices do we have?")
|
115
|
-
print(" • Show me the 5 most recent invoices")
|
116
|
-
print(" • What is the average invoice amount?")
|
117
|
-
print("\nType 'quit' to exit")
|
118
|
-
print("=" * 50)
|
119
|
-
|
120
|
-
# Check if MCP bridge is running
|
121
|
-
try:
|
122
|
-
response = requests.get("http://localhost:8081/health", timeout=5)
|
123
|
-
if response.status_code == 200:
|
124
|
-
print("✅ MCP Bridge server is running")
|
125
|
-
else:
|
126
|
-
print("❌ MCP Bridge server is not responding")
|
127
|
-
return
|
128
|
-
except Exception as e:
|
129
|
-
print(f"❌ Cannot connect to MCP Bridge server: {str(e)}")
|
130
|
-
print("💡 Make sure to start the MCP bridge server first:")
|
131
|
-
print(" source /Users/tarpus/miniconda3/bin/activate memra && \\")
|
132
|
-
print(" export MCP_POSTGRES_URL=\"postgresql://tarpus@localhost:5432/memra_invoice_db\" && \\")
|
133
|
-
print(" export MCP_BRIDGE_SECRET=\"test-secret-for-development\" && \\")
|
134
|
-
print(" python3 mcp_bridge_server.py")
|
135
|
-
return
|
136
|
-
|
137
|
-
while True:
|
138
|
-
try:
|
139
|
-
question = input("\n❓ Your question: ").strip()
|
140
|
-
|
141
|
-
if question.lower() in ['quit', 'exit', 'q']:
|
142
|
-
print("\n👋 Goodbye!")
|
143
|
-
break
|
144
|
-
|
145
|
-
if not question:
|
146
|
-
print("Please enter a question")
|
147
|
-
continue
|
148
|
-
|
149
|
-
ask_question(question)
|
150
|
-
|
151
|
-
except KeyboardInterrupt:
|
152
|
-
print("\n\n👋 Goodbye!")
|
153
|
-
break
|
154
|
-
except Exception as e:
|
155
|
-
print(f"\n❌ Error: {str(e)}")
|
156
|
-
|
157
|
-
if __name__ == "__main__":
|
158
|
-
main()
|
memra-sdk/memra/__init__.py
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Memra SDK - Declarative AI Workflows
|
3
|
-
|
4
|
-
A framework for building AI-powered business workflows using a declarative approach.
|
5
|
-
Think of it as "Kubernetes for business logic" where agents are the pods and
|
6
|
-
departments are the deployments.
|
7
|
-
"""
|
8
|
-
|
9
|
-
__version__ = "0.2.4"
|
10
|
-
|
11
|
-
# Core imports
|
12
|
-
from .models import Agent, Department, Tool, LLM
|
13
|
-
from .execution import ExecutionEngine
|
14
|
-
from .discovery_client import check_api_health, get_api_status
|
15
|
-
|
16
|
-
# Make key classes available at package level
|
17
|
-
__all__ = [
|
18
|
-
"Agent",
|
19
|
-
"Department",
|
20
|
-
"Tool",
|
21
|
-
"LLM",
|
22
|
-
"ExecutionEngine",
|
23
|
-
"check_api_health",
|
24
|
-
"get_api_status",
|
25
|
-
"__version__"
|
26
|
-
]
|
27
|
-
|
28
|
-
# Optional: Add version check for compatibility
|
29
|
-
import sys
|
30
|
-
if sys.version_info < (3, 8):
|
31
|
-
raise RuntimeError("Memra requires Python 3.8 or higher")
|
memra-sdk/memra/discovery.py
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
from typing import List, Dict, Any, Optional
|
2
|
-
from .tool_registry import ToolRegistry
|
3
|
-
|
4
|
-
def discover_tools(hosted_by: Optional[str] = None) -> List[Dict[str, Any]]:
|
5
|
-
"""
|
6
|
-
Discover available tools in the Memra platform.
|
7
|
-
|
8
|
-
Args:
|
9
|
-
hosted_by: Filter tools by host ("memra" or "mcp"). If None, returns all tools.
|
10
|
-
|
11
|
-
Returns:
|
12
|
-
List of available tools with their metadata
|
13
|
-
"""
|
14
|
-
registry = ToolRegistry()
|
15
|
-
return registry.discover_tools(hosted_by)
|
@@ -1,49 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Client-side tool discovery for Memra SDK
|
3
|
-
Queries the Memra API to discover available tools
|
4
|
-
"""
|
5
|
-
|
6
|
-
from typing import List, Dict, Any, Optional
|
7
|
-
from .tool_registry_client import ToolRegistryClient
|
8
|
-
|
9
|
-
def discover_tools(hosted_by: Optional[str] = None) -> List[Dict[str, Any]]:
|
10
|
-
"""
|
11
|
-
Discover available tools from the Memra API
|
12
|
-
|
13
|
-
Args:
|
14
|
-
hosted_by: Filter tools by hosting provider ("memra" or "mcp")
|
15
|
-
|
16
|
-
Returns:
|
17
|
-
List of available tools with their descriptions
|
18
|
-
"""
|
19
|
-
registry = ToolRegistryClient()
|
20
|
-
return registry.discover_tools(hosted_by)
|
21
|
-
|
22
|
-
def check_api_health() -> bool:
|
23
|
-
"""
|
24
|
-
Check if the Memra API is available
|
25
|
-
|
26
|
-
Returns:
|
27
|
-
True if API is healthy, False otherwise
|
28
|
-
"""
|
29
|
-
registry = ToolRegistryClient()
|
30
|
-
return registry.health_check()
|
31
|
-
|
32
|
-
def get_api_status() -> Dict[str, Any]:
|
33
|
-
"""
|
34
|
-
Get detailed API status information
|
35
|
-
|
36
|
-
Returns:
|
37
|
-
Dictionary with API status details
|
38
|
-
"""
|
39
|
-
registry = ToolRegistryClient()
|
40
|
-
|
41
|
-
is_healthy = registry.health_check()
|
42
|
-
tools = registry.discover_tools() if is_healthy else []
|
43
|
-
|
44
|
-
return {
|
45
|
-
"api_healthy": is_healthy,
|
46
|
-
"api_url": registry.api_base,
|
47
|
-
"tools_available": len(tools),
|
48
|
-
"tools": tools
|
49
|
-
}
|