memra 0.1.2__py3-none-any.whl → 0.2.0__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 +17 -21
- memra/discovery.py +15 -0
- memra/execution.py +19 -3
- memra/tool_registry.py +190 -0
- memra/tool_registry_client.py +3 -2
- memra-0.2.0.dist-info/METADATA +161 -0
- memra-0.2.0.dist-info/RECORD +19 -0
- memra-0.2.0.dist-info/entry_points.txt +2 -0
- memra-0.2.0.dist-info/top_level.txt +2 -0
- memra-sdk-package/examples/accounts_payable_client.py +207 -0
- memra-sdk-package/memra/__init__.py +28 -0
- memra-sdk-package/memra/discovery_client.py +49 -0
- memra-sdk-package/memra/execution.py +418 -0
- memra-sdk-package/memra/models.py +98 -0
- memra-sdk-package/memra/tool_registry_client.py +105 -0
- memra-0.1.2.dist-info/METADATA +0 -191
- memra-0.1.2.dist-info/RECORD +0 -10
- memra-0.1.2.dist-info/top_level.txt +0 -1
- {memra-0.1.2.dist-info → memra-0.2.0.dist-info}/WHEEL +0 -0
- {memra-0.1.2.dist-info → memra-0.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,207 @@
|
|
1
|
+
"""
|
2
|
+
Client-side Accounts Payable Example
|
3
|
+
This version calls the Memra API hosted on Fly.io instead of running tools locally
|
4
|
+
"""
|
5
|
+
|
6
|
+
import os
|
7
|
+
from memra import Agent, Department, LLM, check_api_health, get_api_status
|
8
|
+
from memra.execution import ExecutionEngine
|
9
|
+
|
10
|
+
# Set API configuration
|
11
|
+
os.environ["MEMRA_API_URL"] = "http://localhost:8080" # Use local API for testing
|
12
|
+
os.environ["MEMRA_API_KEY"] = "dev-key"
|
13
|
+
|
14
|
+
# Check API health before starting
|
15
|
+
print("🔍 Checking Memra API status...")
|
16
|
+
api_status = get_api_status()
|
17
|
+
print(f"API Health: {'✅ Healthy' if api_status['api_healthy'] else '❌ Unavailable'}")
|
18
|
+
print(f"API URL: {api_status['api_url']}")
|
19
|
+
print(f"Tools Available: {api_status['tools_available']}")
|
20
|
+
|
21
|
+
if not api_status['api_healthy']:
|
22
|
+
print("❌ Cannot proceed - Memra API is not available")
|
23
|
+
print("Make sure the API server is running on localhost:8080")
|
24
|
+
exit(1)
|
25
|
+
|
26
|
+
# Define LLMs (these are just metadata - actual LLM calls happen on the server)
|
27
|
+
default_llm = LLM(
|
28
|
+
model="llama-3.2-11b-vision-preview",
|
29
|
+
temperature=0.1,
|
30
|
+
max_tokens=2000
|
31
|
+
)
|
32
|
+
|
33
|
+
parsing_llm = LLM(
|
34
|
+
model="llama-3.2-11b-vision-preview",
|
35
|
+
temperature=0.0,
|
36
|
+
max_tokens=4000
|
37
|
+
)
|
38
|
+
|
39
|
+
manager_llm = LLM(
|
40
|
+
model="llama-3.2-11b-vision-preview",
|
41
|
+
temperature=0.2,
|
42
|
+
max_tokens=1000
|
43
|
+
)
|
44
|
+
|
45
|
+
# Define agents (same declarative interface as before)
|
46
|
+
etl_agent = Agent(
|
47
|
+
role="Data Engineer",
|
48
|
+
job="Extract invoice schema from database",
|
49
|
+
llm=default_llm,
|
50
|
+
sops=[
|
51
|
+
"Connect to database using credentials",
|
52
|
+
"Query information_schema for invoices table",
|
53
|
+
"Extract column names, types, and constraints",
|
54
|
+
"Return schema as structured JSON"
|
55
|
+
],
|
56
|
+
systems=["Database"],
|
57
|
+
tools=[
|
58
|
+
{"name": "DatabaseQueryTool", "hosted_by": "memra"}
|
59
|
+
],
|
60
|
+
output_key="invoice_schema"
|
61
|
+
)
|
62
|
+
|
63
|
+
parser_agent = Agent(
|
64
|
+
role="Invoice Parser",
|
65
|
+
job="Extract structured data from invoice PDF using schema",
|
66
|
+
llm=parsing_llm,
|
67
|
+
sops=[
|
68
|
+
"Load invoice PDF file",
|
69
|
+
"Convert to high-contrast images if needed",
|
70
|
+
"Run OCR to extract text",
|
71
|
+
"Use schema to identify and extract fields",
|
72
|
+
"Validate extracted data against schema types",
|
73
|
+
"Return structured invoice data"
|
74
|
+
],
|
75
|
+
systems=["InvoiceStore"],
|
76
|
+
tools=[
|
77
|
+
{"name": "PDFProcessor", "hosted_by": "memra"},
|
78
|
+
{"name": "OCRTool", "hosted_by": "memra"},
|
79
|
+
{"name": "InvoiceExtractionWorkflow", "hosted_by": "memra"}
|
80
|
+
],
|
81
|
+
input_keys=["file", "invoice_schema"],
|
82
|
+
output_key="invoice_data"
|
83
|
+
)
|
84
|
+
|
85
|
+
writer_agent = Agent(
|
86
|
+
role="Data Entry Specialist",
|
87
|
+
job="Write validated invoice data to database",
|
88
|
+
llm=default_llm,
|
89
|
+
sops=[
|
90
|
+
"Validate invoice data completeness",
|
91
|
+
"Map fields to database columns using schema",
|
92
|
+
"Connect to database",
|
93
|
+
"Insert record into invoices table",
|
94
|
+
"Return confirmation with record ID"
|
95
|
+
],
|
96
|
+
systems=["Database"],
|
97
|
+
tools=[
|
98
|
+
{"name": "DataValidator", "hosted_by": "memra"},
|
99
|
+
{"name": "PostgresInsert", "hosted_by": "memra"}
|
100
|
+
],
|
101
|
+
input_keys=["invoice_data", "invoice_schema"],
|
102
|
+
output_key="write_confirmation"
|
103
|
+
)
|
104
|
+
|
105
|
+
manager_agent = Agent(
|
106
|
+
role="Accounts Payable Manager",
|
107
|
+
job="Coordinate invoice processing pipeline and handle exceptions",
|
108
|
+
llm=manager_llm,
|
109
|
+
sops=[
|
110
|
+
"Check if schema extraction succeeded",
|
111
|
+
"Validate parsed invoice has required fields",
|
112
|
+
"Ensure invoice total matches line items before DB write",
|
113
|
+
"Handle and log any errors with appropriate escalation"
|
114
|
+
],
|
115
|
+
allow_delegation=True,
|
116
|
+
output_key="workflow_status"
|
117
|
+
)
|
118
|
+
|
119
|
+
# Create department
|
120
|
+
ap_department = Department(
|
121
|
+
name="Accounts Payable",
|
122
|
+
mission="Process invoices accurately into financial system per company data standards",
|
123
|
+
agents=[etl_agent, parser_agent, writer_agent],
|
124
|
+
manager_agent=manager_agent,
|
125
|
+
workflow_order=["Data Engineer", "Invoice Parser", "Data Entry Specialist"],
|
126
|
+
dependencies=["Database", "InvoiceStore"],
|
127
|
+
execution_policy={
|
128
|
+
"retry_on_fail": True,
|
129
|
+
"max_retries": 2,
|
130
|
+
"halt_on_validation_error": True,
|
131
|
+
"timeout_seconds": 300
|
132
|
+
},
|
133
|
+
context={
|
134
|
+
"company_id": "acme_corp",
|
135
|
+
"fiscal_year": "2024"
|
136
|
+
}
|
137
|
+
)
|
138
|
+
|
139
|
+
# Execute the department (tools will run on Fly.io)
|
140
|
+
print("\n🚀 Starting invoice processing workflow...")
|
141
|
+
print("📡 Tools will execute on Memra API server")
|
142
|
+
|
143
|
+
engine = ExecutionEngine()
|
144
|
+
input_data = {
|
145
|
+
"file": "invoices/10352259310.PDF",
|
146
|
+
"connection": "postgresql://tarpus@localhost:5432/memra_invoice_db"
|
147
|
+
}
|
148
|
+
|
149
|
+
result = engine.execute_department(ap_department, input_data)
|
150
|
+
|
151
|
+
# Display results (same as before)
|
152
|
+
if result.success:
|
153
|
+
print("✅ Invoice processing completed successfully!")
|
154
|
+
|
155
|
+
# Show manager validation results
|
156
|
+
if 'workflow_status' in result.data:
|
157
|
+
manager_report = result.data['workflow_status']
|
158
|
+
print(f"\n🔍 Manager Validation Report:")
|
159
|
+
print(f"Status: {manager_report.get('validation_status', 'unknown')}")
|
160
|
+
print(f"Summary: {manager_report.get('summary', 'No summary available')}")
|
161
|
+
|
162
|
+
# Show agent performance analysis
|
163
|
+
if 'agent_performance' in manager_report:
|
164
|
+
print(f"\n📊 Agent Performance Analysis:")
|
165
|
+
for agent_role, performance in manager_report['agent_performance'].items():
|
166
|
+
work_quality = performance['work_quality']
|
167
|
+
status_emoji = "✅" if work_quality == "real" else "🔄"
|
168
|
+
print(f"{status_emoji} {agent_role}: {performance['status']}")
|
169
|
+
if performance['tools_real_work']:
|
170
|
+
print(f" Real work: {', '.join(performance['tools_real_work'])}")
|
171
|
+
if performance['tools_mock_work']:
|
172
|
+
print(f" Mock work: {', '.join(performance['tools_mock_work'])}")
|
173
|
+
|
174
|
+
# Show workflow analysis
|
175
|
+
if 'workflow_analysis' in manager_report:
|
176
|
+
analysis = manager_report['workflow_analysis']
|
177
|
+
print(f"\n📈 Workflow Analysis:")
|
178
|
+
print(f"Overall Quality: {analysis['overall_quality']}")
|
179
|
+
print(f"Real Work: {analysis['real_work_agents']}/{analysis['total_agents']} agents ({analysis['real_work_percentage']:.1f}%)")
|
180
|
+
|
181
|
+
# Show recommendations
|
182
|
+
if 'recommendations' in manager_report and manager_report['recommendations']:
|
183
|
+
print(f"\n💡 Recommendations:")
|
184
|
+
for rec in manager_report['recommendations']:
|
185
|
+
print(f" • {rec}")
|
186
|
+
|
187
|
+
# Try to get record_id if it exists
|
188
|
+
if result.data and 'write_confirmation' in result.data:
|
189
|
+
confirmation = result.data['write_confirmation']
|
190
|
+
if isinstance(confirmation, dict) and 'record_id' in confirmation:
|
191
|
+
print(f"\n💾 Invoice processed successfully: Record ID {confirmation['record_id']}")
|
192
|
+
else:
|
193
|
+
print(f"\n💾 Write confirmation: {confirmation}")
|
194
|
+
|
195
|
+
print(f"\n📡 All tools executed remotely on Memra API server")
|
196
|
+
|
197
|
+
else:
|
198
|
+
print(f"❌ Processing failed: {result.error}")
|
199
|
+
|
200
|
+
# Show execution trace
|
201
|
+
print("\n=== Execution Trace ===")
|
202
|
+
print(f"Agents executed: {', '.join(result.trace.agents_executed)}")
|
203
|
+
print(f"Tools invoked: {', '.join(result.trace.tools_invoked)}")
|
204
|
+
if result.trace.errors:
|
205
|
+
print(f"Errors: {', '.join(result.trace.errors)}")
|
206
|
+
|
207
|
+
print(f"\n🌐 API Calls made to: {api_status['api_url']}")
|
@@ -0,0 +1,28 @@
|
|
1
|
+
"""
|
2
|
+
Memra SDK - A declarative orchestration framework for AI-powered business workflows
|
3
|
+
"""
|
4
|
+
|
5
|
+
from .models import (
|
6
|
+
Agent,
|
7
|
+
Department,
|
8
|
+
LLM,
|
9
|
+
Tool,
|
10
|
+
ExecutionPolicy,
|
11
|
+
ExecutionTrace,
|
12
|
+
DepartmentResult,
|
13
|
+
DepartmentAudit
|
14
|
+
)
|
15
|
+
from .discovery_client import discover_tools, check_api_health, get_api_status
|
16
|
+
|
17
|
+
__version__ = "0.1.2"
|
18
|
+
__all__ = [
|
19
|
+
"Agent",
|
20
|
+
"Department",
|
21
|
+
"LLM",
|
22
|
+
"Tool",
|
23
|
+
"ExecutionPolicy",
|
24
|
+
"ExecutionTrace",
|
25
|
+
"DepartmentResult",
|
26
|
+
"DepartmentAudit",
|
27
|
+
"discover_tools"
|
28
|
+
]
|
@@ -0,0 +1,49 @@
|
|
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
|
+
}
|