memra 0.2.0__py3-none-any.whl → 0.2.2__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
@@ -1,24 +1,27 @@
1
1
  """
2
- Memra SDK - Declarative framework for enterprise workflows with MCP integration
2
+ Memra SDK - Declarative AI Workflows
3
3
 
4
- A powerful orchestration framework that allows you to build AI-powered business workflows
5
- with hybrid cloud/local execution capabilities.
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.
6
7
  """
7
8
 
8
- __version__ = "0.2.0"
9
- __author__ = "Memra"
10
- __email__ = "info@memra.co"
9
+ __version__ = "0.2.2"
11
10
 
12
11
  # Core imports
13
- from .models import Agent, Department, LLM, Tool
12
+ from .models import Agent, Department, Tool
14
13
  from .execution import ExecutionEngine
15
14
 
16
15
  # Make key classes available at package level
17
16
  __all__ = [
18
17
  "Agent",
19
18
  "Department",
20
- "LLM",
21
19
  "Tool",
22
20
  "ExecutionEngine",
23
21
  "__version__"
24
- ]
22
+ ]
23
+
24
+ # Optional: Add version check for compatibility
25
+ import sys
26
+ if sys.version_info < (3, 8):
27
+ raise RuntimeError("Memra requires Python 3.8 or higher")
memra/execution.py CHANGED
@@ -1,8 +1,9 @@
1
1
  import time
2
2
  import logging
3
- import os
4
3
  from typing import Dict, Any, List, Optional
5
4
  from .models import Department, Agent, DepartmentResult, ExecutionTrace, DepartmentAudit
5
+ from .tool_registry import ToolRegistry
6
+ from .tool_registry_client import ToolRegistryClient
6
7
 
7
8
  logger = logging.getLogger(__name__)
8
9
 
@@ -10,16 +11,8 @@ class ExecutionEngine:
10
11
  """Engine that executes department workflows by coordinating agents and tools"""
11
12
 
12
13
  def __init__(self):
13
- # Use API client if MEMRA_API_KEY is set, otherwise use local tools
14
- if os.getenv('MEMRA_API_KEY'):
15
- from .tool_registry_client import ToolRegistryClient
16
- self.tool_registry = ToolRegistryClient()
17
- logger.info("Using API client for tool execution")
18
- else:
19
- from .tool_registry import ToolRegistry
20
- self.tool_registry = ToolRegistry()
21
- logger.info("Using local tool registry")
22
-
14
+ self.tool_registry = ToolRegistry()
15
+ self.api_client = ToolRegistryClient()
23
16
  self.last_execution_audit: Optional[DepartmentAudit] = None
24
17
 
25
18
  def execute_department(self, department: Department, input_data: Dict[str, Any]) -> DepartmentResult:
@@ -203,24 +196,33 @@ class ExecutionEngine:
203
196
  tool_name = tool_spec["name"] if isinstance(tool_spec, dict) else tool_spec.name
204
197
  hosted_by = tool_spec.get("hosted_by", "memra") if isinstance(tool_spec, dict) else tool_spec.hosted_by
205
198
 
206
- # Extract tool-level config if available, otherwise use agent config
207
- tool_config = None
208
- if isinstance(tool_spec, dict) and "config" in tool_spec:
209
- tool_config = tool_spec["config"]
210
- elif agent.config:
211
- tool_config = agent.config
212
-
213
199
  print(f"⚡ {agent.role}: Using tool {i}/{len(agent.tools)}: {tool_name}")
214
200
 
215
201
  trace.tools_invoked.append(tool_name)
216
202
 
217
203
  # Get tool from registry and execute
218
- tool_result = self.tool_registry.execute_tool(
219
- tool_name,
220
- hosted_by,
221
- agent_input,
222
- tool_config
223
- )
204
+ print(f"🔍 {agent.role}: Tool {tool_name} is hosted by: {hosted_by}")
205
+ if hosted_by == "memra":
206
+ # Use API client for server-hosted tools
207
+ print(f"🌐 {agent.role}: Using API client for {tool_name}")
208
+ config_to_pass = tool_spec.get("config") if isinstance(tool_spec, dict) else tool_spec.config
209
+ tool_result = self.api_client.execute_tool(
210
+ tool_name,
211
+ hosted_by,
212
+ agent_input,
213
+ config_to_pass
214
+ )
215
+ else:
216
+ # Use local registry for MCP and other local tools
217
+ print(f"🏠 {agent.role}: Using local registry for {tool_name}")
218
+ config_to_pass = tool_spec.get("config") if isinstance(tool_spec, dict) else tool_spec.config
219
+ print(f"🔧 {agent.role}: Config for {tool_name}: {config_to_pass}")
220
+ tool_result = self.tool_registry.execute_tool(
221
+ tool_name,
222
+ hosted_by,
223
+ agent_input,
224
+ config_to_pass
225
+ )
224
226
 
225
227
  if not tool_result.get("success", False):
226
228
  print(f"😟 {agent.role}: Oh no! Tool {tool_name} failed: {tool_result.get('error', 'Unknown error')}")
@@ -308,7 +310,8 @@ class ExecutionEngine:
308
310
  isinstance(tool_data["validation_errors"], list) and
309
311
  "is_valid" in tool_data and
310
312
  # Check if it's validating real extracted data (not just mock data)
311
- len(str(tool_data)) > 100 # Real validation results are more substantial
313
+ len(str(tool_data)) > 100 and # Real validation results are more substantial
314
+ not tool_data.get("_mock", False) # Not mock data
312
315
  )
313
316
 
314
317
  elif tool_name == "PostgresInsert":
@@ -318,7 +321,8 @@ class ExecutionEngine:
318
321
  tool_data["success"] == True and
319
322
  "record_id" in tool_data and
320
323
  isinstance(tool_data["record_id"], int) and # Real DB returns integer IDs
321
- "database_table" in tool_data # Real implementation includes table name
324
+ "database_table" in tool_data and # Real implementation includes table name
325
+ not tool_data.get("_mock", False) # Not mock data
322
326
  )
323
327
 
324
328
  # Default to mock work
memra/models.py CHANGED
@@ -12,6 +12,7 @@ class Tool(BaseModel):
12
12
  hosted_by: str = "memra" # or "mcp" for customer's Model Context Protocol
13
13
  description: Optional[str] = None
14
14
  parameters: Optional[Dict[str, Any]] = None
15
+ config: Optional[Dict[str, Any]] = None
15
16
 
16
17
  class Agent(BaseModel):
17
18
  role: str
memra/tool_registry.py CHANGED
@@ -2,65 +2,48 @@ import importlib
2
2
  import logging
3
3
  import sys
4
4
  import os
5
+ import httpx
5
6
  from typing import Dict, Any, List, Optional, Callable
6
7
  from pathlib import Path
7
8
 
8
9
  logger = logging.getLogger(__name__)
9
10
 
10
11
  class ToolRegistry:
11
- """Registry for managing and executing tools"""
12
+ """Registry for managing and executing tools via API calls only"""
12
13
 
13
14
  def __init__(self):
14
15
  self.tools: Dict[str, Dict[str, Any]] = {}
15
- self._add_project_to_path()
16
- self._load_builtin_tools()
16
+ self._register_known_tools()
17
17
 
18
- def _add_project_to_path(self):
19
- """Add the project root to Python path so we can import logic modules"""
20
- # Get the directory containing this file (memra package)
21
- current_dir = Path(__file__).parent
22
- # Go up one level to get the project root
23
- project_root = current_dir.parent
18
+ def _register_known_tools(self):
19
+ """Register known tools with their metadata (no actual implementations)"""
20
+ # Server-hosted tools (executed via Memra API)
21
+ server_tools = [
22
+ ("DatabaseQueryTool", "Query database schemas and data"),
23
+ ("PDFProcessor", "Process PDF files and extract content"),
24
+ ("OCRTool", "Perform OCR on images and documents"),
25
+ ("InvoiceExtractionWorkflow", "Extract structured data from invoices"),
26
+ ("FileReader", "Read files from the filesystem"),
27
+ ]
24
28
 
25
- if str(project_root) not in sys.path:
26
- sys.path.insert(0, str(project_root))
27
-
28
- def _load_builtin_tools(self):
29
- """Load tools from the logic directory"""
30
- try:
31
- # Load invoice tools
32
- from logic.invoice_tools import (
33
- DatabaseQueryTool, PDFProcessor, OCRTool,
34
- InvoiceExtractionWorkflow, DataValidator, PostgresInsert
35
- )
36
-
37
- self.register_tool("DatabaseQueryTool", DatabaseQueryTool, "memra",
38
- "Query database schemas and data")
39
- self.register_tool("PDFProcessor", PDFProcessor, "memra",
40
- "Process PDF files and extract content")
41
- self.register_tool("OCRTool", OCRTool, "memra",
42
- "Perform OCR on images and documents")
43
- self.register_tool("InvoiceExtractionWorkflow", InvoiceExtractionWorkflow, "memra",
44
- "Extract structured data from invoices")
45
- self.register_tool("DataValidator", DataValidator, "memra",
46
- "Validate data against schemas")
47
- self.register_tool("PostgresInsert", PostgresInsert, "memra",
48
- "Insert data into PostgreSQL database")
49
-
50
- # Load file tools
51
- from logic.file_tools import FileReader
52
- self.register_tool("FileReader", FileReader, "memra",
53
- "Read files from the filesystem")
54
-
55
- logger.info(f"Loaded {len(self.tools)} builtin tools")
56
-
57
- except ImportError as e:
58
- logger.warning(f"Could not load some tools: {e}")
29
+ for tool_name, description in server_tools:
30
+ self.register_tool(tool_name, None, "memra", description)
31
+
32
+ # MCP-hosted tools (executed via MCP bridge)
33
+ mcp_tools = [
34
+ ("DataValidator", "Validate data against schemas"),
35
+ ("PostgresInsert", "Insert data into PostgreSQL database"),
36
+ ]
37
+
38
+ for tool_name, description in mcp_tools:
39
+ self.register_tool(tool_name, None, "mcp", description)
40
+
41
+ logger.info(f"Registered {len(self.tools)} tool definitions")
59
42
 
60
- def register_tool(self, name: str, tool_class: type, hosted_by: str, description: str):
61
- """Register a tool in the registry"""
43
+ def register_tool(self, name: str, tool_class: Optional[type], hosted_by: str, description: str):
44
+ """Register a tool in the registry (metadata only)"""
62
45
  self.tools[name] = {
63
- "class": tool_class,
46
+ "class": tool_class, # Will be None for API-based tools
64
47
  "hosted_by": hosted_by,
65
48
  "description": description
66
49
  }
@@ -80,111 +63,127 @@ class ToolRegistry:
80
63
 
81
64
  def execute_tool(self, tool_name: str, hosted_by: str, input_data: Dict[str, Any],
82
65
  config: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
83
- """Execute a tool with the given input data"""
84
- if tool_name not in self.tools:
85
- return {
86
- "success": False,
87
- "error": f"Tool '{tool_name}' not found in registry"
88
- }
89
-
90
- tool_info = self.tools[tool_name]
91
- if tool_info["hosted_by"] != hosted_by:
66
+ """Execute a tool - handles MCP tools via bridge, rejects direct server tool execution"""
67
+ if hosted_by == "mcp":
68
+ return self._execute_mcp_tool(tool_name, input_data, config)
69
+ else:
70
+ logger.warning(f"Direct tool execution attempted for {tool_name}. Use API client instead.")
92
71
  return {
93
72
  "success": False,
94
- "error": f"Tool '{tool_name}' is hosted by '{tool_info['hosted_by']}', not '{hosted_by}'"
73
+ "error": "Direct tool execution not supported. Use API client for tool execution."
95
74
  }
96
-
75
+
76
+ def _execute_mcp_tool(self, tool_name: str, input_data: Dict[str, Any],
77
+ config: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
78
+ """Execute an MCP tool via the bridge"""
97
79
  try:
98
- # Instantiate tool
99
- tool_class = tool_info["class"]
80
+ # Debug logging
81
+ logger.info(f"Executing MCP tool {tool_name} with config: {config}")
100
82
 
101
- # Some tools need credentials/config for initialization
102
- if tool_name in ["DatabaseQueryTool", "PostgresInsert"]:
103
- if "connection" in input_data:
104
- # Parse connection string or use credentials
105
- credentials = self._parse_connection(input_data["connection"])
106
- tool_instance = tool_class(credentials)
107
- else:
108
- return {
109
- "success": False,
110
- "error": f"Tool '{tool_name}' requires database credentials"
111
- }
112
- elif tool_name == "InvoiceExtractionWorkflow":
113
- # This tool needs to be instantiated to initialize the LLM client
114
- tool_instance = tool_class()
115
- else:
116
- tool_instance = tool_class()
83
+ # Get bridge configuration
84
+ if not config:
85
+ logger.error(f"MCP tool {tool_name} requires bridge configuration")
86
+ return {
87
+ "success": False,
88
+ "error": "MCP bridge configuration required"
89
+ }
117
90
 
118
- # Execute tool based on its type
119
- result = self._execute_tool_method(tool_instance, tool_name, input_data, config)
91
+ bridge_url = config.get("bridge_url", "http://localhost:8081")
92
+ bridge_secret = config.get("bridge_secret")
120
93
 
121
- return {
122
- "success": True,
123
- "data": result
94
+ if not bridge_secret:
95
+ logger.error(f"MCP tool {tool_name} requires bridge_secret in config")
96
+ return {
97
+ "success": False,
98
+ "error": "MCP bridge secret required"
99
+ }
100
+
101
+ # Try different endpoint patterns that might exist
102
+ endpoints_to_try = [
103
+ f"{bridge_url}/execute_tool",
104
+ f"{bridge_url}/tool/{tool_name}",
105
+ f"{bridge_url}/mcp/execute",
106
+ f"{bridge_url}/api/execute"
107
+ ]
108
+
109
+ # Prepare request
110
+ payload = {
111
+ "tool_name": tool_name,
112
+ "input_data": input_data
124
113
  }
125
114
 
126
- except Exception as e:
127
- logger.error(f"Tool execution failed for {tool_name}: {str(e)}")
128
- return {
129
- "success": False,
130
- "error": str(e)
115
+ headers = {
116
+ "Content-Type": "application/json",
117
+ "X-Bridge-Secret": bridge_secret
131
118
  }
132
-
133
- def _execute_tool_method(self, tool_instance: Any, tool_name: str,
134
- input_data: Dict[str, Any], config: Optional[Dict[str, Any]]) -> Dict[str, Any]:
135
- """Execute the appropriate method on the tool instance"""
136
-
137
- if tool_name == "DatabaseQueryTool":
138
- return tool_instance.get_schema("invoices") # Default to invoices table
139
-
140
- elif tool_name == "PDFProcessor":
141
- file_path = input_data.get("file", "")
142
- return tool_instance.process_pdf(file_path)
143
-
144
- elif tool_name == "OCRTool":
145
- # Assume PDF processor output is passed as input
146
- return {"extracted_text": tool_instance.extract_text(input_data)}
147
-
148
- elif tool_name == "InvoiceExtractionWorkflow":
149
- text = input_data.get("extracted_text", "")
150
- schema = input_data.get("invoice_schema", {})
151
- return tool_instance.extract_data(text, schema)
152
-
153
- elif tool_name == "DataValidator":
154
- data = input_data.get("invoice_data", {})
155
- schema = input_data.get("invoice_schema", {})
156
- return tool_instance.validate(data, schema)
157
-
158
- elif tool_name == "PostgresInsert":
159
- data = input_data.get("invoice_data", {})
160
- return tool_instance.insert_record("invoices", data)
161
-
162
- elif tool_name == "FileReader":
163
- file_path = config.get("path") if config else input_data.get("file_path")
164
- if not file_path:
165
- raise ValueError("FileReader requires a file path")
166
- return tool_instance.read_file(file_path)
167
-
168
- else:
169
- raise ValueError(f"Unknown tool execution method for {tool_name}")
170
-
171
- def _parse_connection(self, connection_string: str) -> Dict[str, Any]:
172
- """Parse a connection string into credentials"""
173
- # Simple parser for postgres://user:pass@host:port/database
174
- if connection_string.startswith("postgres://"):
175
- # This is a simplified parser - in production you'd use a proper URL parser
176
- parts = connection_string.replace("postgres://", "").split("/")
177
- db_part = parts[1] if len(parts) > 1 else "finance"
178
- auth_host = parts[0].split("@")
179
- host_port = auth_host[1].split(":") if len(auth_host) > 1 else ["localhost", "5432"]
180
- user_pass = auth_host[0].split(":") if len(auth_host) > 1 else ["user", "pass"]
181
119
 
120
+ # Try each endpoint
121
+ logger.info(f"Executing MCP tool {tool_name} via bridge at {bridge_url}")
122
+
123
+ last_error = None
124
+ for endpoint in endpoints_to_try:
125
+ try:
126
+ with httpx.Client(timeout=60.0) as client:
127
+ response = client.post(endpoint, json=payload, headers=headers)
128
+
129
+ if response.status_code == 200:
130
+ result = response.json()
131
+ logger.info(f"MCP tool {tool_name} executed successfully via {endpoint}")
132
+ return result
133
+ elif response.status_code == 404:
134
+ continue # Try next endpoint
135
+ else:
136
+ response.raise_for_status()
137
+
138
+ except httpx.HTTPStatusError as e:
139
+ if e.response.status_code == 404:
140
+ continue # Try next endpoint
141
+ last_error = e
142
+ continue
143
+ except Exception as e:
144
+ last_error = e
145
+ continue
146
+
147
+ # If we get here, none of the endpoints worked
148
+ # For now, return mock data to keep the workflow working
149
+ logger.warning(f"MCP bridge endpoints not available, returning mock data for {tool_name}")
150
+
151
+ if tool_name == "DataValidator":
152
+ return {
153
+ "success": True,
154
+ "data": {
155
+ "is_valid": True,
156
+ "validation_errors": [],
157
+ "validated_data": input_data.get("invoice_data", {}),
158
+ "_mock": True
159
+ }
160
+ }
161
+ elif tool_name == "PostgresInsert":
162
+ return {
163
+ "success": True,
164
+ "data": {
165
+ "success": True,
166
+ "record_id": 999, # Mock ID
167
+ "database_table": "invoices",
168
+ "inserted_data": input_data.get("invoice_data", {}),
169
+ "_mock": True
170
+ }
171
+ }
172
+ else:
173
+ return {
174
+ "success": False,
175
+ "error": f"MCP bridge not available and no mock data for {tool_name}"
176
+ }
177
+
178
+ except httpx.TimeoutException:
179
+ logger.error(f"MCP tool {tool_name} execution timed out")
182
180
  return {
183
- "host": host_port[0],
184
- "port": int(host_port[1]) if len(host_port) > 1 else 5432,
185
- "database": db_part,
186
- "user": user_pass[0],
187
- "password": user_pass[1] if len(user_pass) > 1 else ""
181
+ "success": False,
182
+ "error": f"MCP tool execution timed out after 60 seconds"
188
183
  }
189
-
190
- return {"connection_string": connection_string}
184
+ except Exception as e:
185
+ logger.error(f"MCP tool execution failed for {tool_name}: {str(e)}")
186
+ return {
187
+ "success": False,
188
+ "error": str(e)
189
+ }
@@ -1,10 +1,10 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.1
2
2
  Name: memra
3
- Version: 0.2.0
4
- Summary: Declarative framework for enterprise workflows with MCP integration
3
+ Version: 0.2.2
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
7
- Author-email: Memra <info@memra.co>
7
+ Author-email: Memra <support@memra.com>
8
8
  License: MIT
9
9
  Project-URL: Homepage, https://memra.co
10
10
  Project-URL: Repository, https://github.com/memra-platform/memra-sdk
@@ -25,16 +25,13 @@ Requires-Dist: httpx>=0.24.0
25
25
  Requires-Dist: typing-extensions>=4.0.0
26
26
  Requires-Dist: aiohttp>=3.8.0
27
27
  Requires-Dist: aiohttp-cors>=0.7.0
28
- Requires-Dist: psycopg2-binary>=2.9.0
29
28
  Provides-Extra: dev
30
29
  Requires-Dist: pytest>=6.0; extra == "dev"
31
30
  Requires-Dist: pytest-asyncio; extra == "dev"
32
31
  Requires-Dist: black; extra == "dev"
33
32
  Requires-Dist: flake8; extra == "dev"
34
- Dynamic: author
35
- Dynamic: home-page
36
- Dynamic: license-file
37
- Dynamic: requires-python
33
+ Provides-Extra: mcp
34
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "mcp"
38
35
 
39
36
  # Memra SDK
40
37
 
@@ -102,6 +99,16 @@ echo 'export MEMRA_API_KEY="your-api-key-here"' >> ~/.zshrc
102
99
  python examples/accounts_payable_client.py
103
100
  ```
104
101
 
102
+ ## Architecture
103
+
104
+ The Memra platform consists of three main components:
105
+
106
+ - **Memra SDK** (this repository): Client library for building and executing workflows
107
+ - **Memra Server**: Hosted infrastructure for heavy AI processing tools
108
+ - **MCP Bridge**: Local execution environment for database operations
109
+
110
+ Tools are automatically routed between server and local execution based on their `hosted_by` configuration.
111
+
105
112
  ## Documentation
106
113
 
107
114
  Documentation is coming soon. For now, see the examples below and in the `examples/` directory.
@@ -118,44 +125,24 @@ We welcome contributions! Please see our [contributing guide](CONTRIBUTING.md) f
118
125
 
119
126
  This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
120
127
 
121
- ## Examples
128
+ ## Repository Structure
122
129
 
123
130
  ```
124
- ├── examples/
125
- │ ├── accounts_payable_client.py # API-based example
126
- │ ├── accounts_payable.py # Local example
127
- │ ├── invoice_processing.py # Simple workflow
128
- │ └── propane_delivery.py # Domain example
129
- ├── memra/ # Core SDK
130
- ├── logic/ # Tool implementations
131
- ├── local/dependencies/ # Database setup & schemas
132
- └── docker-compose.yml # Database setup
133
- ```
134
-
135
- ## New: MCP Integration
136
-
137
- Memra now supports **Model Context Protocol (MCP)** integration, allowing you to execute operations on your local infrastructure while leveraging Memra's cloud-based AI processing.
138
-
139
- **Key Benefits:**
140
- - 🔒 **Keep sensitive data local** - Your databases stay on your infrastructure
141
- - ⚡ **Hybrid processing** - AI processing in the cloud, data operations locally
142
- - 🔐 **Secure communication** - HMAC-authenticated requests between cloud and local
143
- - 🛠️ **Easy setup** - Simple bridge server connects your local resources
144
-
145
- **Quick Example:**
146
- ```python
147
- # Agent that uses local database via MCP
148
- agent = Agent(
149
- role="Data Writer",
150
- tools=[{
151
- "name": "PostgresInsert",
152
- "hosted_by": "mcp", # Routes to your local infrastructure
153
- "config": {
154
- "bridge_url": "http://localhost:8081",
155
- "bridge_secret": "your-secret"
156
- }
157
- }]
158
- )
131
+ ├── examples/ # Example workflows and use cases
132
+ │ ├── accounts_payable_client.py # API-based accounts payable workflow
133
+ │ ├── accounts_payable_mcp.py # MCP-enabled accounts payable workflow
134
+ │ ├── invoice_processing.py # Simple invoice processing example
135
+ │ └── propane_delivery.py # Propane delivery domain example
136
+ ├── memra/ # Core SDK package
137
+ ├── __init__.py # Package initialization
138
+ ├── tool_registry.py # Tool discovery and routing
139
+ └── sdk/ # SDK components
140
+ │ ├── __init__.py
141
+ │ ├── client.py # API client
142
+ │ ├── execution_engine.py # Workflow execution
143
+ │ └── models.py # Core data models
144
+ ├── docs/ # Documentation
145
+ ├── tests/ # Test suite
146
+ ├── local/dependencies/ # Local development setup
147
+ └── scripts/ # Utility scripts
159
148
  ```
160
-
161
- 📖 **[Complete MCP Integration Guide →](docs/mcp_integration.md)**
@@ -0,0 +1,13 @@
1
+ memra/__init__.py,sha256=5WPh9vku8_ZV4T6WayAqArKAj1RDkbL47SsnA9GWD7A,662
2
+ memra/discovery.py,sha256=yJIQnrDQu1nyzKykCIuzG_5SW5dIXHCEBLLKRWacIoY,480
3
+ memra/discovery_client.py,sha256=AbnKn6qhyrf7vmOvknEeDzH4tiGHsqPHtDaein_qaW0,1271
4
+ memra/execution.py,sha256=bg822ED6yYN7APjPac1LRhv48gtxV4DUPvzpyLyBa2I,21443
5
+ memra/models.py,sha256=sXMPRnMB_mUVtJdBFyd0ElCf_uh1yqx7iLssIYNm0vI,3333
6
+ memra/tool_registry.py,sha256=N7kpYQxgJcSMDDCX-_6og1-of3QKEaoz6H16ptCCg48,7784
7
+ memra/tool_registry_client.py,sha256=uzMQ4COvRams9vuPLcqcdljUpDlAYU_tyFxrRhrA0Lc,4009
8
+ memra-0.2.2.dist-info/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ memra-0.2.2.dist-info/METADATA,sha256=jrZ9AwcGtPK-pc9TGGGoi1oJzXxcGx7LUsbsd6NxcxA,4856
10
+ memra-0.2.2.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
11
+ memra-0.2.2.dist-info/entry_points.txt,sha256=LBVjwWoxWJRzNLgeByPn6xUvWFIRnqnemvAZgIoSt08,41
12
+ memra-0.2.2.dist-info/top_level.txt,sha256=pXWcTRS1zctdiSUivW4iyKpJ4tcfIu-1BW_fpbal3OY,6
13
+ memra-0.2.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (75.7.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1 @@
1
+ memra
@@ -1,19 +0,0 @@
1
- memra/__init__.py,sha256=XLSWpo42Ffp_pi5mvk4xvdYBZ8eNLAJF4_3Oi102i90,560
2
- memra/discovery.py,sha256=yJIQnrDQu1nyzKykCIuzG_5SW5dIXHCEBLLKRWacIoY,480
3
- memra/discovery_client.py,sha256=AbnKn6qhyrf7vmOvknEeDzH4tiGHsqPHtDaein_qaW0,1271
4
- memra/execution.py,sha256=5NIyFVtQEeatYQ-fxexT0eWMtCh28k1hRC2Y6cfQaac,20917
5
- memra/models.py,sha256=nTaYLAp0tRzQ0CQaBLNBURfhBQ5_gyty0ams4mghyIc,3289
6
- memra/tool_registry.py,sha256=zdyKRShcmKtG7BVfmAHflW9FDl7rooPPAgbdVV4gJ8o,8268
7
- memra/tool_registry_client.py,sha256=uzMQ4COvRams9vuPLcqcdljUpDlAYU_tyFxrRhrA0Lc,4009
8
- memra-0.2.0.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- memra-sdk-package/examples/accounts_payable_client.py,sha256=Vu_h5C-qc6_80uz5dXJH4G3zfIbgUNAhQ2y8mWauao0,7401
10
- memra-sdk-package/memra/__init__.py,sha256=QRk72YETLgL15GVt26tN_rBraCQkhZO7UB9T6d4u_uU,543
11
- memra-sdk-package/memra/discovery_client.py,sha256=AbnKn6qhyrf7vmOvknEeDzH4tiGHsqPHtDaein_qaW0,1271
12
- memra-sdk-package/memra/execution.py,sha256=UJ_MJ4getuSk4HJW1sCi7lc26avX-G6-GxnvE-DiSwk,20191
13
- memra-sdk-package/memra/models.py,sha256=nTaYLAp0tRzQ0CQaBLNBURfhBQ5_gyty0ams4mghyIc,3289
14
- memra-sdk-package/memra/tool_registry_client.py,sha256=KyNNxj84248E-8MoWNj6pJmlllUG8s0lmeXXmbu0U7o,3996
15
- memra-0.2.0.dist-info/METADATA,sha256=eOuvH39VFUh-QxTdE5RwT6isgRIJkptEC2lsqlF2AA4,4816
16
- memra-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- memra-0.2.0.dist-info/entry_points.txt,sha256=LBVjwWoxWJRzNLgeByPn6xUvWFIRnqnemvAZgIoSt08,41
18
- memra-0.2.0.dist-info/top_level.txt,sha256=5dqePB77aj_pPFavlwxtBvdkUM-kP-WiQD3LRbQswwc,24
19
- memra-0.2.0.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- memra
2
- memra-sdk-package