memra 0.2.2__py3-none-any.whl → 0.2.4__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 (57) hide show
  1. memra/__init__.py +6 -2
  2. memra/execution.py +53 -0
  3. memra/tool_registry.py +162 -0
  4. memra-0.2.4.dist-info/METADATA +145 -0
  5. memra-0.2.4.dist-info/RECORD +58 -0
  6. {memra-0.2.2.dist-info → memra-0.2.4.dist-info}/WHEEL +1 -1
  7. memra-0.2.4.dist-info/top_level.txt +4 -0
  8. memra-ops/app.py +710 -0
  9. memra-ops/config/config.py +25 -0
  10. memra-ops/config.py +34 -0
  11. memra-ops/scripts/release.py +133 -0
  12. memra-ops/scripts/start_memra.py +334 -0
  13. memra-ops/scripts/stop_memra.py +132 -0
  14. memra-ops/server_tool_registry.py +188 -0
  15. memra-ops/tests/test_llm_text_to_sql.py +115 -0
  16. memra-ops/tests/test_llm_vs_pattern.py +130 -0
  17. memra-ops/tests/test_mcp_schema_aware.py +124 -0
  18. memra-ops/tests/test_schema_aware_sql.py +139 -0
  19. memra-ops/tests/test_schema_aware_sql_simple.py +66 -0
  20. memra-ops/tests/test_text_to_sql_demo.py +140 -0
  21. memra-ops/tools/mcp_bridge_server.py +851 -0
  22. memra-sdk/examples/accounts_payable.py +215 -0
  23. memra-sdk/examples/accounts_payable_client.py +217 -0
  24. memra-sdk/examples/accounts_payable_mcp.py +200 -0
  25. memra-sdk/examples/ask_questions.py +123 -0
  26. memra-sdk/examples/invoice_processing.py +116 -0
  27. memra-sdk/examples/propane_delivery.py +87 -0
  28. memra-sdk/examples/simple_text_to_sql.py +158 -0
  29. memra-sdk/memra/__init__.py +31 -0
  30. memra-sdk/memra/discovery.py +15 -0
  31. memra-sdk/memra/discovery_client.py +49 -0
  32. memra-sdk/memra/execution.py +481 -0
  33. memra-sdk/memra/models.py +99 -0
  34. memra-sdk/memra/tool_registry.py +343 -0
  35. memra-sdk/memra/tool_registry_client.py +106 -0
  36. memra-sdk/scripts/release.py +133 -0
  37. memra-sdk/setup.py +52 -0
  38. memra-workflows/accounts_payable/accounts_payable.py +215 -0
  39. memra-workflows/accounts_payable/accounts_payable_client.py +216 -0
  40. memra-workflows/accounts_payable/accounts_payable_mcp.py +200 -0
  41. memra-workflows/accounts_payable/accounts_payable_smart.py +221 -0
  42. memra-workflows/invoice_processing/invoice_processing.py +116 -0
  43. memra-workflows/invoice_processing/smart_invoice_processor.py +220 -0
  44. memra-workflows/logic/__init__.py +1 -0
  45. memra-workflows/logic/file_tools.py +50 -0
  46. memra-workflows/logic/invoice_tools.py +501 -0
  47. memra-workflows/logic/propane_agents.py +52 -0
  48. memra-workflows/mcp_bridge_server.py +230 -0
  49. memra-workflows/propane_delivery/propane_delivery.py +87 -0
  50. memra-workflows/text_to_sql/complete_invoice_workflow_with_queries.py +208 -0
  51. memra-workflows/text_to_sql/complete_text_to_sql_system.py +266 -0
  52. memra-workflows/text_to_sql/file_discovery_demo.py +156 -0
  53. memra-0.2.2.dist-info/METADATA +0 -148
  54. memra-0.2.2.dist-info/RECORD +0 -13
  55. memra-0.2.2.dist-info/top_level.txt +0 -1
  56. {memra-0.2.2.dist-info → memra-0.2.4.dist-info}/entry_points.txt +0 -0
  57. {memra-0.2.2.dist-info → memra-0.2.4.dist-info/licenses}/LICENSE +0 -0
memra-ops/app.py ADDED
@@ -0,0 +1,710 @@
1
+ from fastapi import FastAPI, HTTPException, Depends, Header
2
+ from fastapi.responses import HTMLResponse
3
+ from pydantic import BaseModel
4
+ from typing import Dict, Any, Optional, List
5
+ import importlib
6
+ import logging
7
+ import os
8
+ import sys
9
+ from pathlib import Path
10
+ import json
11
+ import asyncio
12
+ import hashlib
13
+ import hmac
14
+ import aiohttp
15
+ from server_tool_registry import ServerToolRegistry
16
+
17
+ # Add current directory to path for imports
18
+ sys.path.append(str(Path(__file__).parent))
19
+
20
+ # Configure logging
21
+ logging.basicConfig(level=logging.INFO)
22
+ logger = logging.getLogger(__name__)
23
+
24
+ app = FastAPI(
25
+ title="Memra Tool Execution API",
26
+ description="API for executing Memra workflow tools",
27
+ version="1.0.0"
28
+ )
29
+
30
+ # Initialize server-side tool registry
31
+ tool_registry = ServerToolRegistry()
32
+
33
+ # Request/Response models
34
+ class ToolExecutionRequest(BaseModel):
35
+ tool_name: str
36
+ hosted_by: str
37
+ input_data: Dict[str, Any]
38
+ config: Optional[Dict[str, Any]] = None
39
+
40
+ class ToolExecutionResponse(BaseModel):
41
+ success: bool
42
+ data: Optional[Dict[str, Any]] = None
43
+ error: Optional[str] = None
44
+
45
+ class ToolDiscoveryResponse(BaseModel):
46
+ tools: List[Dict[str, str]]
47
+
48
+ # Authentication
49
+ def verify_api_key(api_key: str) -> bool:
50
+ """Verify if the provided API key is valid"""
51
+ # Get valid keys from environment variable only - no defaults
52
+ valid_keys_str = os.getenv("MEMRA_API_KEYS")
53
+ if not valid_keys_str:
54
+ # If no keys are set, deny all access
55
+ return False
56
+
57
+ valid_keys = valid_keys_str.split(",")
58
+ return api_key.strip() in [key.strip() for key in valid_keys]
59
+
60
+ # FastAPI dependency for API key verification
61
+ async def get_api_key(x_api_key: Optional[str] = Header(None)):
62
+ """FastAPI dependency to verify API key from header"""
63
+ if not x_api_key:
64
+ raise HTTPException(
65
+ status_code=401,
66
+ detail="Missing API key. Please provide X-API-Key header."
67
+ )
68
+
69
+ if not verify_api_key(x_api_key):
70
+ raise HTTPException(
71
+ status_code=401,
72
+ detail="Invalid API key. Please contact info@memra.co for access."
73
+ )
74
+
75
+ logger.info(f"Valid API key used: {x_api_key}")
76
+ return x_api_key
77
+
78
+ @app.get("/", response_class=HTMLResponse)
79
+ async def landing_page():
80
+ """API documentation landing page"""
81
+ return """
82
+ <!DOCTYPE html>
83
+ <html lang="en">
84
+ <head>
85
+ <meta charset="UTF-8">
86
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
87
+ <title>memra API - Declarative AI Workflows</title>
88
+ <style>
89
+ @import url('https://fonts.cdnfonts.com/css/effra');
90
+
91
+ * {
92
+ margin: 0;
93
+ padding: 0;
94
+ box-sizing: border-box;
95
+ }
96
+
97
+ body {
98
+ font-family: 'Effra', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
99
+ line-height: 1.6;
100
+ color: #ffffff;
101
+ background: #0f0f23;
102
+ min-height: 100vh;
103
+ overflow-x: hidden;
104
+ }
105
+
106
+ /* Animated gradient background */
107
+ .bg-gradient {
108
+ position: fixed;
109
+ top: 0;
110
+ left: 0;
111
+ right: 0;
112
+ bottom: 0;
113
+ background: radial-gradient(ellipse at top left, rgba(88, 28, 135, 0.8) 0%, transparent 40%),
114
+ radial-gradient(ellipse at bottom right, rgba(59, 130, 246, 0.6) 0%, transparent 40%),
115
+ radial-gradient(ellipse at center, rgba(147, 51, 234, 0.4) 0%, transparent 60%),
116
+ #1a1a2e;
117
+ z-index: -2;
118
+ }
119
+
120
+ /* Navigation */
121
+ nav {
122
+ position: fixed;
123
+ top: 0;
124
+ left: 0;
125
+ right: 0;
126
+ background: rgba(15, 15, 35, 0.7);
127
+ backdrop-filter: blur(20px);
128
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
129
+ z-index: 1000;
130
+ padding: 1.5rem 2rem;
131
+ }
132
+
133
+ .nav-content {
134
+ max-width: 1400px;
135
+ margin: 0 auto;
136
+ display: flex;
137
+ justify-content: space-between;
138
+ align-items: center;
139
+ }
140
+
141
+ .logo {
142
+ font-size: 1.75rem;
143
+ font-weight: 300;
144
+ color: #ffffff;
145
+ letter-spacing: -0.02em;
146
+ }
147
+
148
+ .status-badge {
149
+ background: rgba(34, 197, 94, 0.15);
150
+ border: 1px solid rgba(34, 197, 94, 0.3);
151
+ color: #22c55e;
152
+ padding: 0.4rem 1rem;
153
+ border-radius: 999px;
154
+ font-size: 0.875rem;
155
+ font-weight: 400;
156
+ animation: pulse 3s ease-in-out infinite;
157
+ }
158
+
159
+ @keyframes pulse {
160
+ 0%, 100% { opacity: 1; }
161
+ 50% { opacity: 0.7; }
162
+ }
163
+
164
+ /* Main content */
165
+ .container {
166
+ max-width: 1200px;
167
+ margin: 0 auto;
168
+ padding: 10rem 2rem 4rem;
169
+ }
170
+
171
+ /* Hero section */
172
+ .hero {
173
+ text-align: center;
174
+ margin-bottom: 8rem;
175
+ }
176
+
177
+ .hero h1 {
178
+ font-size: clamp(2.5rem, 6vw, 4rem);
179
+ font-weight: 300;
180
+ margin-bottom: 1.5rem;
181
+ color: #ffffff;
182
+ letter-spacing: -0.02em;
183
+ }
184
+
185
+ .hero .tagline {
186
+ font-size: 1.25rem;
187
+ color: rgba(255, 255, 255, 0.6);
188
+ margin-bottom: 4rem;
189
+ font-weight: 300;
190
+ max-width: 600px;
191
+ margin-left: auto;
192
+ margin-right: auto;
193
+ }
194
+
195
+ /* Glass card effect */
196
+ .glass-card {
197
+ background: rgba(255, 255, 255, 0.03);
198
+ backdrop-filter: blur(20px);
199
+ border: 1px solid rgba(255, 255, 255, 0.08);
200
+ border-radius: 20px;
201
+ padding: 2.5rem;
202
+ margin-bottom: 2rem;
203
+ transition: all 0.3s ease;
204
+ }
205
+
206
+ .glass-card:hover {
207
+ background: rgba(255, 255, 255, 0.05);
208
+ border-color: rgba(255, 255, 255, 0.12);
209
+ }
210
+
211
+ /* Code blocks */
212
+ .code-block {
213
+ background: rgba(0, 0, 0, 0.5);
214
+ border: 1px solid rgba(255, 255, 255, 0.1);
215
+ border-radius: 16px;
216
+ padding: 1.5rem;
217
+ font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
218
+ font-size: 0.9rem;
219
+ color: rgba(255, 255, 255, 0.9);
220
+ overflow-x: auto;
221
+ margin: 1.5rem 0;
222
+ }
223
+
224
+ /* Use cases grid */
225
+ .use-cases-grid {
226
+ display: grid;
227
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
228
+ gap: 1.5rem;
229
+ margin: 2rem 0 4rem 0;
230
+ }
231
+
232
+ .use-case-card {
233
+ background: rgba(147, 51, 234, 0.05);
234
+ border: 1px solid rgba(147, 51, 234, 0.2);
235
+ border-radius: 16px;
236
+ padding: 2rem;
237
+ transition: all 0.3s ease;
238
+ }
239
+
240
+ .use-case-card:hover {
241
+ background: rgba(147, 51, 234, 0.08);
242
+ border-color: rgba(147, 51, 234, 0.4);
243
+ transform: translateY(-2px);
244
+ }
245
+
246
+ .use-case-header {
247
+ display: flex;
248
+ align-items: center;
249
+ gap: 1rem;
250
+ margin-bottom: 1rem;
251
+ }
252
+
253
+ .use-case-icon {
254
+ font-size: 2rem;
255
+ }
256
+
257
+ .use-case-card h3 {
258
+ font-size: 1.25rem;
259
+ font-weight: 400;
260
+ color: #ffffff;
261
+ }
262
+
263
+ .use-case-card p {
264
+ color: rgba(255, 255, 255, 0.7);
265
+ margin-bottom: 1rem;
266
+ line-height: 1.6;
267
+ }
268
+
269
+ .code-snippet {
270
+ background: rgba(0, 0, 0, 0.3);
271
+ border-radius: 8px;
272
+ padding: 0.75rem;
273
+ font-size: 0.8rem;
274
+ overflow-x: auto;
275
+ }
276
+
277
+ .code-snippet code {
278
+ color: #a78bfa;
279
+ font-family: 'Monaco', 'Menlo', monospace;
280
+ }
281
+
282
+ /* Features grid */
283
+ .features-grid {
284
+ display: grid;
285
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
286
+ gap: 2rem;
287
+ margin: 3rem 0;
288
+ }
289
+
290
+ .feature-card {
291
+ background: rgba(255, 255, 255, 0.02);
292
+ border: 1px solid rgba(255, 255, 255, 0.06);
293
+ border-radius: 16px;
294
+ padding: 2.5rem;
295
+ text-align: center;
296
+ transition: all 0.3s ease;
297
+ }
298
+
299
+ .feature-card:hover {
300
+ background: rgba(255, 255, 255, 0.04);
301
+ border-color: rgba(147, 51, 234, 0.3);
302
+ transform: translateY(-4px);
303
+ }
304
+
305
+ .feature-icon {
306
+ font-size: 2.5rem;
307
+ margin-bottom: 1rem;
308
+ opacity: 0.8;
309
+ }
310
+
311
+ .feature-title {
312
+ font-size: 1.25rem;
313
+ font-weight: 400;
314
+ margin-bottom: 0.5rem;
315
+ color: #ffffff;
316
+ }
317
+
318
+ .feature-desc {
319
+ color: rgba(255, 255, 255, 0.6);
320
+ font-size: 0.95rem;
321
+ line-height: 1.5;
322
+ }
323
+
324
+ /* Endpoints section */
325
+ .endpoint {
326
+ background: rgba(0, 0, 0, 0.2);
327
+ border-left: 3px solid rgba(147, 51, 234, 0.5);
328
+ padding: 1.5rem;
329
+ margin: 1rem 0;
330
+ border-radius: 0 12px 12px 0;
331
+ transition: all 0.3s ease;
332
+ }
333
+
334
+ .endpoint:hover {
335
+ background: rgba(0, 0, 0, 0.3);
336
+ border-left-color: rgba(147, 51, 234, 0.8);
337
+ }
338
+
339
+ .method {
340
+ display: inline-block;
341
+ background: rgba(147, 51, 234, 0.15);
342
+ color: #a78bfa;
343
+ padding: 0.3rem 0.8rem;
344
+ border-radius: 8px;
345
+ font-weight: 500;
346
+ font-size: 0.875rem;
347
+ margin-right: 1rem;
348
+ }
349
+
350
+ /* CTA section */
351
+ .cta-section {
352
+ background: rgba(255, 255, 255, 0.02);
353
+ border: 1px solid rgba(255, 255, 255, 0.08);
354
+ border-radius: 24px;
355
+ padding: 4rem;
356
+ text-align: center;
357
+ margin: 4rem 0;
358
+ }
359
+
360
+ .cta-button {
361
+ display: inline-block;
362
+ background: #e879f9;
363
+ color: #0f0f23;
364
+ padding: 1rem 2.5rem;
365
+ border-radius: 12px;
366
+ text-decoration: none;
367
+ font-weight: 500;
368
+ transition: all 0.3s ease;
369
+ font-size: 1rem;
370
+ }
371
+
372
+ .cta-button:hover {
373
+ transform: translateY(-2px);
374
+ box-shadow: 0 10px 30px rgba(232, 121, 249, 0.3);
375
+ background: #f0abfc;
376
+ }
377
+
378
+ /* Section headers */
379
+ h2 {
380
+ font-size: 2rem;
381
+ font-weight: 300;
382
+ margin-bottom: 2rem;
383
+ color: #ffffff;
384
+ letter-spacing: -0.02em;
385
+ }
386
+
387
+ /* Accent text */
388
+ .accent {
389
+ color: #e879f9;
390
+ }
391
+
392
+ /* Warning box */
393
+ .warning-box {
394
+ background: rgba(251, 191, 36, 0.1);
395
+ border: 1px solid rgba(251, 191, 36, 0.3);
396
+ border-radius: 12px;
397
+ padding: 1rem 1.5rem;
398
+ margin: 1.5rem 0;
399
+ color: #fbbf24;
400
+ }
401
+
402
+ .warning-box strong {
403
+ color: #f59e0b;
404
+ }
405
+
406
+ /* Links */
407
+ a {
408
+ color: #a78bfa;
409
+ text-decoration: none;
410
+ transition: color 0.3s ease;
411
+ }
412
+
413
+ a:hover {
414
+ color: #e879f9;
415
+ }
416
+
417
+ /* Footer links */
418
+ .footer-links {
419
+ text-align: center;
420
+ margin-top: 6rem;
421
+ padding-top: 3rem;
422
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
423
+ }
424
+
425
+ .footer-links a {
426
+ margin: 0 1.5rem;
427
+ color: rgba(255, 255, 255, 0.5);
428
+ font-size: 0.95rem;
429
+ }
430
+
431
+ .footer-links a:hover {
432
+ color: rgba(255, 255, 255, 0.8);
433
+ }
434
+
435
+ /* Responsive */
436
+ @media (max-width: 768px) {
437
+ .hero h1 {
438
+ font-size: 2.5rem;
439
+ }
440
+
441
+ .hero .tagline {
442
+ font-size: 1.1rem;
443
+ }
444
+
445
+ .container {
446
+ padding: 7rem 1.5rem 2rem;
447
+ }
448
+
449
+ .glass-card {
450
+ padding: 2rem;
451
+ }
452
+
453
+ .cta-section {
454
+ padding: 3rem 2rem;
455
+ }
456
+ }
457
+ </style>
458
+ </head>
459
+ <body>
460
+ <div class="bg-gradient"></div>
461
+
462
+ <nav>
463
+ <div class="nav-content">
464
+ <div class="logo">
465
+ <span>memra API</span>
466
+ </div>
467
+ <div class="status-badge">● API Running</div>
468
+ </div>
469
+ </nav>
470
+
471
+ <div class="container">
472
+ <section class="hero">
473
+ <h1>Build AI Agents That Actually Do Work</h1>
474
+ <p class="tagline">Stop writing boilerplate. Define what you want done, not how to do it. memra handles the AI orchestration so you can ship faster.</p>
475
+
476
+ <div class="glass-card">
477
+ <h2>🚀 Quick Start</h2>
478
+ <div class="code-block">pip install memra</div>
479
+ <div class="warning-box">
480
+ <strong>🔑 API Access Required:</strong>
481
+ Contact <a href="mailto:info@memra.co">info@memra.co</a> for early access to the memra API
482
+ </div>
483
+ <div style="margin-top: 2rem; padding-top: 2rem; border-top: 1px solid rgba(255, 255, 255, 0.1);">
484
+ <h3 style="font-size: 1.25rem; margin-bottom: 1rem; color: #e879f9;">Next Steps:</h3>
485
+ <ol style="color: rgba(255, 255, 255, 0.8); line-height: 2;">
486
+ <li>Install the SDK: <code style="background: rgba(0,0,0,0.3); padding: 0.2rem 0.5rem; border-radius: 4px;">pip install memra</code></li>
487
+ <li>Get your API key from <a href="mailto:info@memra.co">info@memra.co</a></li>
488
+ <li>Check out the examples below to see what you can build</li>
489
+ <li>Start with a simple agent and expand from there</li>
490
+ </ol>
491
+ </div>
492
+ </div>
493
+ </section>
494
+
495
+ <section>
496
+ <h2>🛠️ What Can You Build?</h2>
497
+ <div class="use-cases-grid">
498
+ <div class="use-case-card">
499
+ <div class="use-case-header">
500
+ <span class="use-case-icon">📄</span>
501
+ <h3>Document Processing Pipeline</h3>
502
+ </div>
503
+ <p>Auto-extract data from PDFs, invoices, contracts. Parse, validate, and push to your database.</p>
504
+ <div class="code-snippet">
505
+ <code>Agent(role="Invoice Parser", tools=["PDFProcessor", "DatabaseWriter"])</code>
506
+ </div>
507
+ </div>
508
+ <div class="use-case-card">
509
+ <div class="use-case-header">
510
+ <span class="use-case-icon">📧</span>
511
+ <h3>Customer Support Automation</h3>
512
+ </div>
513
+ <p>Handle support tickets, categorize issues, draft responses, and escalate complex cases.</p>
514
+ <div class="code-snippet">
515
+ <code>Agent(role="Support Analyst", tools=["EmailReader", "TicketClassifier"])</code>
516
+ </div>
517
+ </div>
518
+ <div class="use-case-card">
519
+ <div class="use-case-header">
520
+ <span class="use-case-icon">📊</span>
521
+ <h3>Data Analysis Workflows</h3>
522
+ </div>
523
+ <p>Connect to databases, run analysis, generate reports, and send insights to Slack.</p>
524
+ <div class="code-snippet">
525
+ <code>Agent(role="Data Analyst", tools=["SQLQuery", "ChartGenerator", "SlackNotifier"])</code>
526
+ </div>
527
+ </div>
528
+ <div class="use-case-card">
529
+ <div class="use-case-header">
530
+ <span class="use-case-icon">🔄</span>
531
+ <h3>API Integration Chains</h3>
532
+ </div>
533
+ <p>Chain multiple APIs together with AI decision-making between steps.</p>
534
+ <div class="code-snippet">
535
+ <code>Agent(role="Integration Expert", tools=["HTTPClient", "JSONTransformer"])</code>
536
+ </div>
537
+ </div>
538
+ <div class="use-case-card">
539
+ <div class="use-case-header">
540
+ <span class="use-case-icon">🔍</span>
541
+ <h3>Content Moderation Pipeline</h3>
542
+ </div>
543
+ <p>Review user content, flag issues, apply policies, and maintain compliance automatically.</p>
544
+ <div class="code-snippet">
545
+ <code>Agent(role="Content Reviewer", tools=["TextAnalyzer", "PolicyEngine", "FlagSystem"])</code>
546
+ </div>
547
+ </div>
548
+ <div class="use-case-card">
549
+ <div class="use-case-header">
550
+ <span class="use-case-icon">🚀</span>
551
+ <h3>Lead Qualification System</h3>
552
+ </div>
553
+ <p>Score leads, enrich data from multiple sources, and route to the right sales team.</p>
554
+ <div class="code-snippet">
555
+ <code>Agent(role="Lead Scorer", tools=["CRMConnector", "DataEnricher", "RouterAgent"])</code>
556
+ </div>
557
+ </div>
558
+ </div>
559
+ </section>
560
+
561
+ <section>
562
+ <h2>✨ Why <span class="accent">memra</span>?</h2>
563
+ <div class="features-grid">
564
+ <div class="feature-card">
565
+ <div class="feature-icon">📋</div>
566
+ <div class="feature-title">Declarative Design</div>
567
+ <div class="feature-desc">Define workflows like Kubernetes YAML. Version control your AI business logic.</div>
568
+ </div>
569
+ <div class="feature-card">
570
+ <div class="feature-icon">🤖</div>
571
+ <div class="feature-title">Multi-LLM Support</div>
572
+ <div class="feature-desc">Seamlessly integrate OpenAI, Anthropic, and other providers with zero config changes.</div>
573
+ </div>
574
+ <div class="feature-card">
575
+ <div class="feature-icon">💬</div>
576
+ <div class="feature-title">Self-Documenting</div>
577
+ <div class="feature-desc">Agents explain their decisions in natural language for full transparency.</div>
578
+ </div>
579
+ <div class="feature-card">
580
+ <div class="feature-icon">🏗️</div>
581
+ <div class="feature-title">Enterprise Ready</div>
582
+ <div class="feature-desc">Battle-tested on real databases, files, and complex business workflows.</div>
583
+ </div>
584
+ </div>
585
+ </section>
586
+
587
+ <section>
588
+ <h2>📡 API Endpoints</h2>
589
+ <div class="glass-card">
590
+ <div class="endpoint">
591
+ <span class="method">GET</span>/health
592
+ <div>Health check and API status verification</div>
593
+ </div>
594
+ <div class="endpoint">
595
+ <span class="method">GET</span>/tools/discover
596
+ <div>Discover available workflow tools and their capabilities</div>
597
+ </div>
598
+ <div class="endpoint">
599
+ <span class="method">POST</span>/tools/execute
600
+ <div>Execute workflow tools with structured input data</div>
601
+ </div>
602
+ </div>
603
+ </section>
604
+
605
+ <section>
606
+ <h2>📚 Full Example: Invoice Processing</h2>
607
+ <div class="glass-card">
608
+ <p style="color: rgba(255, 255, 255, 0.7); margin-bottom: 1.5rem;">
609
+ Here's how you'd build an invoice processing system that extracts data and updates your database:
610
+ </p>
611
+ <div class="code-block">from memra import Agent, Department
612
+ from memra.execution import ExecutionEngine
613
+
614
+ # 1. Define what you want done (not how)
615
+ invoice_processor = Agent(
616
+ role="Invoice Processor",
617
+ job="Extract vendor, amount, and line items from PDF invoices",
618
+ tools=[
619
+ {"name": "PDFProcessor", "hosted_by": "memra"},
620
+ {"name": "DataValidator", "hosted_by": "memra"},
621
+ {"name": "DatabaseWriter", "hosted_by": "memra"}
622
+ ]
623
+ )
624
+
625
+ # 2. Create a department (group related agents)
626
+ finance_dept = Department(
627
+ name="Accounts Payable",
628
+ agents=[invoice_processor]
629
+ )
630
+
631
+ # 3. Execute - memra handles the AI orchestration
632
+ engine = ExecutionEngine()
633
+ result = engine.execute_department(
634
+ finance_dept,
635
+ {"file": "invoice.pdf", "database": "postgresql://..."}
636
+ )
637
+
638
+ # Result: Structured data extracted and saved to your DB
639
+ print(result.summary) # "Extracted invoice #INV-001 for $1,234.56 from Acme Corp"</div>
640
+ </div>
641
+ </section>
642
+
643
+ <div class="cta-section">
644
+ <h2>Ready to Build Your AI Workforce?</h2>
645
+ <p style="color: rgba(255, 255, 255, 0.6); margin-bottom: 2rem;">Join innovative teams automating their workflows with memra</p>
646
+ <a href="mailto:info@memra.co" class="cta-button">Get Started Now</a>
647
+ </div>
648
+
649
+ <div class="footer-links">
650
+ <a href="https://pypi.org/project/memra/">PyPI Package</a>
651
+ <a href="https://github.com/memra-platform/memra-sdk">GitHub</a>
652
+ <a href="https://memra.co">Website</a>
653
+ <a href="mailto:info@memra.co">Contact</a>
654
+ </div>
655
+ </div>
656
+ </body>
657
+ </html>
658
+ """
659
+
660
+ @app.get("/health")
661
+ async def health_check():
662
+ """Health check for Fly.io"""
663
+ return {"status": "healthy"}
664
+
665
+ @app.post("/tools/execute", response_model=ToolExecutionResponse)
666
+ async def execute_tool(
667
+ request: ToolExecutionRequest,
668
+ api_key: Optional[str] = Depends(get_api_key)
669
+ ):
670
+ """Execute a tool with the given input data"""
671
+ try:
672
+ logger.info(f"Executing tool: {request.tool_name}")
673
+
674
+ # Create registry and execute tool
675
+ result = tool_registry.execute_tool(
676
+ request.tool_name,
677
+ request.hosted_by,
678
+ request.input_data,
679
+ request.config
680
+ )
681
+
682
+ return ToolExecutionResponse(
683
+ success=result.get("success", False),
684
+ data=result.get("data"),
685
+ error=result.get("error")
686
+ )
687
+
688
+ except Exception as e:
689
+ logger.error(f"Tool execution failed: {str(e)}")
690
+ return ToolExecutionResponse(
691
+ success=False,
692
+ error=str(e)
693
+ )
694
+
695
+ @app.get("/tools/discover", response_model=ToolDiscoveryResponse)
696
+ async def discover_tools(api_key: Optional[str] = Depends(get_api_key)):
697
+ """Discover available tools"""
698
+ try:
699
+ tools = tool_registry.discover_tools()
700
+
701
+ return ToolDiscoveryResponse(tools=tools)
702
+
703
+ except Exception as e:
704
+ logger.error(f"Tool discovery failed: {str(e)}")
705
+ raise HTTPException(status_code=500, detail=str(e))
706
+
707
+ if __name__ == "__main__":
708
+ import uvicorn
709
+ port = int(os.getenv("PORT", 8080))
710
+ uvicorn.run(app, host="0.0.0.0", port=port)