genxai-framework 0.1.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.
Files changed (156) hide show
  1. cli/__init__.py +3 -0
  2. cli/commands/__init__.py +6 -0
  3. cli/commands/approval.py +85 -0
  4. cli/commands/audit.py +127 -0
  5. cli/commands/metrics.py +25 -0
  6. cli/commands/tool.py +389 -0
  7. cli/main.py +32 -0
  8. genxai/__init__.py +81 -0
  9. genxai/api/__init__.py +5 -0
  10. genxai/api/app.py +21 -0
  11. genxai/config/__init__.py +5 -0
  12. genxai/config/settings.py +37 -0
  13. genxai/connectors/__init__.py +19 -0
  14. genxai/connectors/base.py +122 -0
  15. genxai/connectors/kafka.py +92 -0
  16. genxai/connectors/postgres_cdc.py +95 -0
  17. genxai/connectors/registry.py +44 -0
  18. genxai/connectors/sqs.py +94 -0
  19. genxai/connectors/webhook.py +73 -0
  20. genxai/core/__init__.py +37 -0
  21. genxai/core/agent/__init__.py +32 -0
  22. genxai/core/agent/base.py +206 -0
  23. genxai/core/agent/config_io.py +59 -0
  24. genxai/core/agent/registry.py +98 -0
  25. genxai/core/agent/runtime.py +970 -0
  26. genxai/core/communication/__init__.py +6 -0
  27. genxai/core/communication/collaboration.py +44 -0
  28. genxai/core/communication/message_bus.py +192 -0
  29. genxai/core/communication/protocols.py +35 -0
  30. genxai/core/execution/__init__.py +22 -0
  31. genxai/core/execution/metadata.py +181 -0
  32. genxai/core/execution/queue.py +201 -0
  33. genxai/core/graph/__init__.py +30 -0
  34. genxai/core/graph/checkpoints.py +77 -0
  35. genxai/core/graph/edges.py +131 -0
  36. genxai/core/graph/engine.py +813 -0
  37. genxai/core/graph/executor.py +516 -0
  38. genxai/core/graph/nodes.py +161 -0
  39. genxai/core/graph/trigger_runner.py +40 -0
  40. genxai/core/memory/__init__.py +19 -0
  41. genxai/core/memory/base.py +72 -0
  42. genxai/core/memory/embedding.py +327 -0
  43. genxai/core/memory/episodic.py +448 -0
  44. genxai/core/memory/long_term.py +467 -0
  45. genxai/core/memory/manager.py +543 -0
  46. genxai/core/memory/persistence.py +297 -0
  47. genxai/core/memory/procedural.py +461 -0
  48. genxai/core/memory/semantic.py +526 -0
  49. genxai/core/memory/shared.py +62 -0
  50. genxai/core/memory/short_term.py +303 -0
  51. genxai/core/memory/vector_store.py +508 -0
  52. genxai/core/memory/working.py +211 -0
  53. genxai/core/state/__init__.py +6 -0
  54. genxai/core/state/manager.py +293 -0
  55. genxai/core/state/schema.py +115 -0
  56. genxai/llm/__init__.py +14 -0
  57. genxai/llm/base.py +150 -0
  58. genxai/llm/factory.py +329 -0
  59. genxai/llm/providers/__init__.py +1 -0
  60. genxai/llm/providers/anthropic.py +249 -0
  61. genxai/llm/providers/cohere.py +274 -0
  62. genxai/llm/providers/google.py +334 -0
  63. genxai/llm/providers/ollama.py +147 -0
  64. genxai/llm/providers/openai.py +257 -0
  65. genxai/llm/routing.py +83 -0
  66. genxai/observability/__init__.py +6 -0
  67. genxai/observability/logging.py +327 -0
  68. genxai/observability/metrics.py +494 -0
  69. genxai/observability/tracing.py +372 -0
  70. genxai/performance/__init__.py +39 -0
  71. genxai/performance/cache.py +256 -0
  72. genxai/performance/pooling.py +289 -0
  73. genxai/security/audit.py +304 -0
  74. genxai/security/auth.py +315 -0
  75. genxai/security/cost_control.py +528 -0
  76. genxai/security/default_policies.py +44 -0
  77. genxai/security/jwt.py +142 -0
  78. genxai/security/oauth.py +226 -0
  79. genxai/security/pii.py +366 -0
  80. genxai/security/policy_engine.py +82 -0
  81. genxai/security/rate_limit.py +341 -0
  82. genxai/security/rbac.py +247 -0
  83. genxai/security/validation.py +218 -0
  84. genxai/tools/__init__.py +21 -0
  85. genxai/tools/base.py +383 -0
  86. genxai/tools/builtin/__init__.py +131 -0
  87. genxai/tools/builtin/communication/__init__.py +15 -0
  88. genxai/tools/builtin/communication/email_sender.py +159 -0
  89. genxai/tools/builtin/communication/notification_manager.py +167 -0
  90. genxai/tools/builtin/communication/slack_notifier.py +118 -0
  91. genxai/tools/builtin/communication/sms_sender.py +118 -0
  92. genxai/tools/builtin/communication/webhook_caller.py +136 -0
  93. genxai/tools/builtin/computation/__init__.py +15 -0
  94. genxai/tools/builtin/computation/calculator.py +101 -0
  95. genxai/tools/builtin/computation/code_executor.py +183 -0
  96. genxai/tools/builtin/computation/data_validator.py +259 -0
  97. genxai/tools/builtin/computation/hash_generator.py +129 -0
  98. genxai/tools/builtin/computation/regex_matcher.py +201 -0
  99. genxai/tools/builtin/data/__init__.py +15 -0
  100. genxai/tools/builtin/data/csv_processor.py +213 -0
  101. genxai/tools/builtin/data/data_transformer.py +299 -0
  102. genxai/tools/builtin/data/json_processor.py +233 -0
  103. genxai/tools/builtin/data/text_analyzer.py +288 -0
  104. genxai/tools/builtin/data/xml_processor.py +175 -0
  105. genxai/tools/builtin/database/__init__.py +15 -0
  106. genxai/tools/builtin/database/database_inspector.py +157 -0
  107. genxai/tools/builtin/database/mongodb_query.py +196 -0
  108. genxai/tools/builtin/database/redis_cache.py +167 -0
  109. genxai/tools/builtin/database/sql_query.py +145 -0
  110. genxai/tools/builtin/database/vector_search.py +163 -0
  111. genxai/tools/builtin/file/__init__.py +17 -0
  112. genxai/tools/builtin/file/directory_scanner.py +214 -0
  113. genxai/tools/builtin/file/file_compressor.py +237 -0
  114. genxai/tools/builtin/file/file_reader.py +102 -0
  115. genxai/tools/builtin/file/file_writer.py +122 -0
  116. genxai/tools/builtin/file/image_processor.py +186 -0
  117. genxai/tools/builtin/file/pdf_parser.py +144 -0
  118. genxai/tools/builtin/test/__init__.py +15 -0
  119. genxai/tools/builtin/test/async_simulator.py +62 -0
  120. genxai/tools/builtin/test/data_transformer.py +99 -0
  121. genxai/tools/builtin/test/error_generator.py +82 -0
  122. genxai/tools/builtin/test/simple_math.py +94 -0
  123. genxai/tools/builtin/test/string_processor.py +72 -0
  124. genxai/tools/builtin/web/__init__.py +15 -0
  125. genxai/tools/builtin/web/api_caller.py +161 -0
  126. genxai/tools/builtin/web/html_parser.py +330 -0
  127. genxai/tools/builtin/web/http_client.py +187 -0
  128. genxai/tools/builtin/web/url_validator.py +162 -0
  129. genxai/tools/builtin/web/web_scraper.py +170 -0
  130. genxai/tools/custom/my_test_tool_2.py +9 -0
  131. genxai/tools/dynamic.py +105 -0
  132. genxai/tools/mcp_server.py +167 -0
  133. genxai/tools/persistence/__init__.py +6 -0
  134. genxai/tools/persistence/models.py +55 -0
  135. genxai/tools/persistence/service.py +322 -0
  136. genxai/tools/registry.py +227 -0
  137. genxai/tools/security/__init__.py +11 -0
  138. genxai/tools/security/limits.py +214 -0
  139. genxai/tools/security/policy.py +20 -0
  140. genxai/tools/security/sandbox.py +248 -0
  141. genxai/tools/templates.py +435 -0
  142. genxai/triggers/__init__.py +19 -0
  143. genxai/triggers/base.py +104 -0
  144. genxai/triggers/file_watcher.py +75 -0
  145. genxai/triggers/queue.py +68 -0
  146. genxai/triggers/registry.py +82 -0
  147. genxai/triggers/schedule.py +66 -0
  148. genxai/triggers/webhook.py +68 -0
  149. genxai/utils/__init__.py +1 -0
  150. genxai/utils/tokens.py +295 -0
  151. genxai_framework-0.1.0.dist-info/METADATA +495 -0
  152. genxai_framework-0.1.0.dist-info/RECORD +156 -0
  153. genxai_framework-0.1.0.dist-info/WHEEL +5 -0
  154. genxai_framework-0.1.0.dist-info/entry_points.txt +2 -0
  155. genxai_framework-0.1.0.dist-info/licenses/LICENSE +21 -0
  156. genxai_framework-0.1.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,303 @@
1
+ """Short-term memory implementation with LRU eviction."""
2
+
3
+ from typing import Any, Dict, List, Optional
4
+ from datetime import datetime
5
+ from collections import OrderedDict
6
+ import logging
7
+
8
+ from genxai.core.memory.base import Memory, MemoryType, MemoryConfig
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class ShortTermMemory:
14
+ """Short-term memory with limited capacity and LRU eviction.
15
+
16
+ This memory type stores recent interactions and automatically evicts
17
+ the least recently used items when capacity is reached.
18
+ """
19
+
20
+ def __init__(self, config: Optional[MemoryConfig] = None, capacity: Optional[int] = None) -> None:
21
+ """Initialize short-term memory.
22
+
23
+ Args:
24
+ config: Memory configuration (uses defaults if not provided)
25
+ capacity: Override capacity (for backward compatibility)
26
+ """
27
+ self.config = config or MemoryConfig()
28
+ self.capacity = capacity if capacity is not None else self.config.short_term_capacity
29
+
30
+ # Use OrderedDict for LRU behavior
31
+ self._memories: OrderedDict[str, Memory] = OrderedDict()
32
+ self._access_count = 0
33
+
34
+ logger.info(f"Initialized short-term memory with capacity: {self.capacity}")
35
+
36
+ def store(self, memory: Memory) -> None:
37
+ """Store a memory item.
38
+
39
+ If capacity is reached, evicts the least recently used item.
40
+
41
+ Args:
42
+ memory: Memory to store
43
+ """
44
+ # If memory already exists, remove it (will be re-added at end)
45
+ if memory.id in self._memories:
46
+ del self._memories[memory.id]
47
+
48
+ # If at capacity, remove oldest (least recently used)
49
+ if len(self._memories) >= self.capacity:
50
+ oldest_id = next(iter(self._memories))
51
+ evicted = self._memories.pop(oldest_id)
52
+ logger.debug(f"Evicted memory {oldest_id} (importance: {evicted.importance})")
53
+
54
+ # Add new memory at end (most recently used)
55
+ self._memories[memory.id] = memory
56
+ logger.debug(f"Stored memory {memory.id} in short-term memory")
57
+
58
+ def retrieve(self, memory_id: str) -> Optional[Memory]:
59
+ """Retrieve a memory by ID.
60
+
61
+ Accessing a memory moves it to the end (most recently used).
62
+
63
+ Args:
64
+ memory_id: ID of memory to retrieve
65
+
66
+ Returns:
67
+ Memory if found, None otherwise
68
+ """
69
+ if memory_id not in self._memories:
70
+ return None
71
+
72
+ # Move to end (mark as recently used)
73
+ memory = self._memories.pop(memory_id)
74
+ self._memories[memory_id] = memory
75
+
76
+ # Update access tracking
77
+ memory.access_count += 1
78
+ memory.last_accessed = datetime.now()
79
+ self._access_count += 1
80
+
81
+ logger.debug(f"Retrieved memory {memory_id} (access count: {memory.access_count})")
82
+ return memory
83
+
84
+ def retrieve_recent(self, limit: int = 10) -> List[Memory]:
85
+ """Retrieve the most recent memories.
86
+
87
+ Args:
88
+ limit: Maximum number of memories to retrieve
89
+
90
+ Returns:
91
+ List of recent memories (most recent first)
92
+ """
93
+ # Get last N items (most recent)
94
+ recent_items = list(self._memories.values())[-limit:]
95
+
96
+ # Reverse to get most recent first
97
+ recent_items.reverse()
98
+
99
+ logger.debug(f"Retrieved {len(recent_items)} recent memories")
100
+ return recent_items
101
+
102
+ def retrieve_by_importance(self, threshold: float = 0.5, limit: int = 10) -> List[Memory]:
103
+ """Retrieve memories above an importance threshold.
104
+
105
+ Args:
106
+ threshold: Minimum importance score (0.0 to 1.0)
107
+ limit: Maximum number of memories to retrieve
108
+
109
+ Returns:
110
+ List of important memories (sorted by importance, descending)
111
+ """
112
+ # Filter by importance
113
+ important = [m for m in self._memories.values() if m.importance >= threshold]
114
+
115
+ # Sort by importance (descending)
116
+ important.sort(key=lambda m: m.importance, reverse=True)
117
+
118
+ # Limit results
119
+ result = important[:limit]
120
+
121
+ logger.debug(
122
+ f"Retrieved {len(result)} memories with importance >= {threshold}"
123
+ )
124
+ return result
125
+
126
+ def search(self, query: str, limit: int = 5) -> List[Memory]:
127
+ """Search memories by content.
128
+
129
+ Simple text-based search. For semantic search, use long-term memory.
130
+
131
+ Args:
132
+ query: Search query
133
+ limit: Maximum number of results
134
+
135
+ Returns:
136
+ List of matching memories
137
+ """
138
+ query_lower = query.lower()
139
+ matches = []
140
+
141
+ for memory in self._memories.values():
142
+ # Convert content to string for searching
143
+ content_str = str(memory.content).lower()
144
+
145
+ if query_lower in content_str:
146
+ matches.append(memory)
147
+
148
+ # Sort by recency (most recent first)
149
+ matches.reverse()
150
+
151
+ # Limit results
152
+ result = matches[:limit]
153
+
154
+ logger.debug(f"Found {len(result)} memories matching '{query}'")
155
+ return result
156
+
157
+ def delete(self, memory_id: str) -> bool:
158
+ """Delete a memory by ID.
159
+
160
+ Args:
161
+ memory_id: ID of memory to delete
162
+
163
+ Returns:
164
+ True if deleted, False if not found
165
+ """
166
+ if memory_id in self._memories:
167
+ del self._memories[memory_id]
168
+ logger.debug(f"Deleted memory {memory_id}")
169
+ return True
170
+ return False
171
+
172
+ def clear(self) -> None:
173
+ """Clear all memories."""
174
+ count = len(self._memories)
175
+ self._memories.clear()
176
+ logger.info(f"Cleared {count} memories from short-term memory")
177
+
178
+ def get_size(self) -> int:
179
+ """Get current number of stored memories.
180
+
181
+ Returns:
182
+ Number of memories
183
+ """
184
+ return len(self._memories)
185
+
186
+ def get_capacity(self) -> int:
187
+ """Get maximum capacity.
188
+
189
+ Returns:
190
+ Maximum number of memories
191
+ """
192
+ return self.capacity
193
+
194
+ def is_full(self) -> bool:
195
+ """Check if memory is at capacity.
196
+
197
+ Returns:
198
+ True if at capacity
199
+ """
200
+ return len(self._memories) >= self.capacity
201
+
202
+ def get_stats(self) -> Dict[str, Any]:
203
+ """Get memory statistics.
204
+
205
+ Returns:
206
+ Statistics dictionary
207
+ """
208
+ if not self._memories:
209
+ return {
210
+ "size": 0,
211
+ "capacity": self.capacity,
212
+ "utilization": 0.0,
213
+ "total_accesses": self._access_count,
214
+ "avg_importance": 0.0,
215
+ "avg_access_count": 0.0,
216
+ }
217
+
218
+ memories = list(self._memories.values())
219
+
220
+ return {
221
+ "size": len(memories),
222
+ "capacity": self.capacity,
223
+ "utilization": len(memories) / self.capacity,
224
+ "total_accesses": self._access_count,
225
+ "avg_importance": sum(m.importance for m in memories) / len(memories),
226
+ "avg_access_count": sum(m.access_count for m in memories) / len(memories),
227
+ "oldest_memory": memories[0].timestamp.isoformat() if memories else None,
228
+ "newest_memory": memories[-1].timestamp.isoformat() if memories else None,
229
+ }
230
+
231
+ def __len__(self) -> int:
232
+ """Get number of stored memories."""
233
+ return len(self._memories)
234
+
235
+ def __contains__(self, memory_id: str) -> bool:
236
+ """Check if memory exists."""
237
+ return memory_id in self._memories
238
+
239
+ async def add(self, content: Any, metadata: Optional[Dict[str, Any]] = None) -> str:
240
+ """Add content to short-term memory.
241
+
242
+ Args:
243
+ content: Content to store
244
+ metadata: Optional metadata
245
+
246
+ Returns:
247
+ Memory ID
248
+ """
249
+ import uuid
250
+ from genxai.core.memory.base import Memory, MemoryType
251
+ from datetime import datetime
252
+
253
+ memory = Memory(
254
+ id=str(uuid.uuid4()),
255
+ content=content,
256
+ type=MemoryType.SHORT_TERM,
257
+ importance=0.5,
258
+ timestamp=datetime.now(),
259
+ metadata=metadata or {},
260
+ )
261
+
262
+ self.store(memory)
263
+ return memory.id
264
+
265
+ async def get_context(self, max_tokens: int = 4000) -> str:
266
+ """Get formatted context string for LLM.
267
+
268
+ Args:
269
+ max_tokens: Maximum tokens to include
270
+
271
+ Returns:
272
+ Formatted context string
273
+ """
274
+ recent = self.retrieve_recent(limit=10)
275
+
276
+ if not recent:
277
+ return ""
278
+
279
+ context_parts = ["Recent context:"]
280
+ for memory in recent:
281
+ # Keep this robust: if content is a dict, stringify it so unit tests
282
+ # can find values like "Hello" in the context.
283
+ if isinstance(memory.content, dict):
284
+ context_parts.append(f"- {memory.content}")
285
+ else:
286
+ context_parts.append(f"- {memory.content}")
287
+
288
+ return "\n".join(context_parts)
289
+
290
+ async def clear_async(self) -> None:
291
+ """Clear all memories (async version)."""
292
+ count = len(self._memories)
293
+ self._memories.clear()
294
+ logger.info(f"Cleared {count} memories from short-term memory")
295
+
296
+ @property
297
+ def memories(self) -> List[Memory]:
298
+ """Get all memories as a list."""
299
+ return list(self._memories.values())
300
+
301
+ def __repr__(self) -> str:
302
+ """String representation."""
303
+ return f"ShortTermMemory(size={len(self._memories)}, capacity={self.capacity})"