aiecs 1.5.1__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 (302) hide show
  1. aiecs/__init__.py +72 -0
  2. aiecs/__main__.py +41 -0
  3. aiecs/aiecs_client.py +469 -0
  4. aiecs/application/__init__.py +10 -0
  5. aiecs/application/executors/__init__.py +10 -0
  6. aiecs/application/executors/operation_executor.py +363 -0
  7. aiecs/application/knowledge_graph/__init__.py +7 -0
  8. aiecs/application/knowledge_graph/builder/__init__.py +37 -0
  9. aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
  10. aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
  11. aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
  12. aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
  13. aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
  14. aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
  15. aiecs/application/knowledge_graph/extractors/base.py +100 -0
  16. aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
  17. aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
  18. aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
  19. aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
  20. aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
  21. aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
  22. aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
  23. aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
  24. aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
  25. aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
  26. aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
  27. aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
  28. aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -0
  29. aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
  30. aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
  31. aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +347 -0
  32. aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
  33. aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -0
  34. aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
  35. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
  36. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +630 -0
  37. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
  38. aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
  39. aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
  40. aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
  41. aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
  42. aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
  43. aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
  44. aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
  45. aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
  46. aiecs/application/knowledge_graph/search/__init__.py +59 -0
  47. aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
  48. aiecs/application/knowledge_graph/search/reranker.py +295 -0
  49. aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
  50. aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
  51. aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
  52. aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
  53. aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
  54. aiecs/application/knowledge_graph/validators/__init__.py +13 -0
  55. aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
  56. aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
  57. aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
  58. aiecs/common/__init__.py +9 -0
  59. aiecs/common/knowledge_graph/__init__.py +17 -0
  60. aiecs/common/knowledge_graph/runnable.py +484 -0
  61. aiecs/config/__init__.py +16 -0
  62. aiecs/config/config.py +498 -0
  63. aiecs/config/graph_config.py +137 -0
  64. aiecs/config/registry.py +23 -0
  65. aiecs/core/__init__.py +46 -0
  66. aiecs/core/interface/__init__.py +34 -0
  67. aiecs/core/interface/execution_interface.py +152 -0
  68. aiecs/core/interface/storage_interface.py +171 -0
  69. aiecs/domain/__init__.py +289 -0
  70. aiecs/domain/agent/__init__.py +189 -0
  71. aiecs/domain/agent/base_agent.py +697 -0
  72. aiecs/domain/agent/exceptions.py +103 -0
  73. aiecs/domain/agent/graph_aware_mixin.py +559 -0
  74. aiecs/domain/agent/hybrid_agent.py +490 -0
  75. aiecs/domain/agent/integration/__init__.py +26 -0
  76. aiecs/domain/agent/integration/context_compressor.py +222 -0
  77. aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
  78. aiecs/domain/agent/integration/retry_policy.py +219 -0
  79. aiecs/domain/agent/integration/role_config.py +213 -0
  80. aiecs/domain/agent/knowledge_aware_agent.py +646 -0
  81. aiecs/domain/agent/lifecycle.py +296 -0
  82. aiecs/domain/agent/llm_agent.py +300 -0
  83. aiecs/domain/agent/memory/__init__.py +12 -0
  84. aiecs/domain/agent/memory/conversation.py +197 -0
  85. aiecs/domain/agent/migration/__init__.py +14 -0
  86. aiecs/domain/agent/migration/conversion.py +160 -0
  87. aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
  88. aiecs/domain/agent/models.py +317 -0
  89. aiecs/domain/agent/observability.py +407 -0
  90. aiecs/domain/agent/persistence.py +289 -0
  91. aiecs/domain/agent/prompts/__init__.py +29 -0
  92. aiecs/domain/agent/prompts/builder.py +161 -0
  93. aiecs/domain/agent/prompts/formatters.py +189 -0
  94. aiecs/domain/agent/prompts/template.py +255 -0
  95. aiecs/domain/agent/registry.py +260 -0
  96. aiecs/domain/agent/tool_agent.py +257 -0
  97. aiecs/domain/agent/tools/__init__.py +12 -0
  98. aiecs/domain/agent/tools/schema_generator.py +221 -0
  99. aiecs/domain/community/__init__.py +155 -0
  100. aiecs/domain/community/agent_adapter.py +477 -0
  101. aiecs/domain/community/analytics.py +481 -0
  102. aiecs/domain/community/collaborative_workflow.py +642 -0
  103. aiecs/domain/community/communication_hub.py +645 -0
  104. aiecs/domain/community/community_builder.py +320 -0
  105. aiecs/domain/community/community_integration.py +800 -0
  106. aiecs/domain/community/community_manager.py +813 -0
  107. aiecs/domain/community/decision_engine.py +879 -0
  108. aiecs/domain/community/exceptions.py +225 -0
  109. aiecs/domain/community/models/__init__.py +33 -0
  110. aiecs/domain/community/models/community_models.py +268 -0
  111. aiecs/domain/community/resource_manager.py +457 -0
  112. aiecs/domain/community/shared_context_manager.py +603 -0
  113. aiecs/domain/context/__init__.py +58 -0
  114. aiecs/domain/context/context_engine.py +989 -0
  115. aiecs/domain/context/conversation_models.py +354 -0
  116. aiecs/domain/context/graph_memory.py +467 -0
  117. aiecs/domain/execution/__init__.py +12 -0
  118. aiecs/domain/execution/model.py +57 -0
  119. aiecs/domain/knowledge_graph/__init__.py +19 -0
  120. aiecs/domain/knowledge_graph/models/__init__.py +52 -0
  121. aiecs/domain/knowledge_graph/models/entity.py +130 -0
  122. aiecs/domain/knowledge_graph/models/evidence.py +194 -0
  123. aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
  124. aiecs/domain/knowledge_graph/models/path.py +179 -0
  125. aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
  126. aiecs/domain/knowledge_graph/models/query.py +272 -0
  127. aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
  128. aiecs/domain/knowledge_graph/models/relation.py +136 -0
  129. aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
  130. aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
  131. aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
  132. aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
  133. aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
  134. aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
  135. aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
  136. aiecs/domain/task/__init__.py +13 -0
  137. aiecs/domain/task/dsl_processor.py +613 -0
  138. aiecs/domain/task/model.py +62 -0
  139. aiecs/domain/task/task_context.py +268 -0
  140. aiecs/infrastructure/__init__.py +24 -0
  141. aiecs/infrastructure/graph_storage/__init__.py +11 -0
  142. aiecs/infrastructure/graph_storage/base.py +601 -0
  143. aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
  144. aiecs/infrastructure/graph_storage/cache.py +429 -0
  145. aiecs/infrastructure/graph_storage/distributed.py +226 -0
  146. aiecs/infrastructure/graph_storage/error_handling.py +390 -0
  147. aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
  148. aiecs/infrastructure/graph_storage/health_checks.py +378 -0
  149. aiecs/infrastructure/graph_storage/in_memory.py +514 -0
  150. aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
  151. aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
  152. aiecs/infrastructure/graph_storage/metrics.py +357 -0
  153. aiecs/infrastructure/graph_storage/migration.py +413 -0
  154. aiecs/infrastructure/graph_storage/pagination.py +471 -0
  155. aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
  156. aiecs/infrastructure/graph_storage/postgres.py +871 -0
  157. aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
  158. aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
  159. aiecs/infrastructure/graph_storage/sqlite.py +623 -0
  160. aiecs/infrastructure/graph_storage/streaming.py +495 -0
  161. aiecs/infrastructure/messaging/__init__.py +13 -0
  162. aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
  163. aiecs/infrastructure/messaging/websocket_manager.py +298 -0
  164. aiecs/infrastructure/monitoring/__init__.py +34 -0
  165. aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
  166. aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
  167. aiecs/infrastructure/monitoring/structured_logger.py +48 -0
  168. aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
  169. aiecs/infrastructure/persistence/__init__.py +24 -0
  170. aiecs/infrastructure/persistence/context_engine_client.py +187 -0
  171. aiecs/infrastructure/persistence/database_manager.py +333 -0
  172. aiecs/infrastructure/persistence/file_storage.py +754 -0
  173. aiecs/infrastructure/persistence/redis_client.py +220 -0
  174. aiecs/llm/__init__.py +86 -0
  175. aiecs/llm/callbacks/__init__.py +11 -0
  176. aiecs/llm/callbacks/custom_callbacks.py +264 -0
  177. aiecs/llm/client_factory.py +420 -0
  178. aiecs/llm/clients/__init__.py +33 -0
  179. aiecs/llm/clients/base_client.py +193 -0
  180. aiecs/llm/clients/googleai_client.py +181 -0
  181. aiecs/llm/clients/openai_client.py +131 -0
  182. aiecs/llm/clients/vertex_client.py +437 -0
  183. aiecs/llm/clients/xai_client.py +184 -0
  184. aiecs/llm/config/__init__.py +51 -0
  185. aiecs/llm/config/config_loader.py +275 -0
  186. aiecs/llm/config/config_validator.py +236 -0
  187. aiecs/llm/config/model_config.py +151 -0
  188. aiecs/llm/utils/__init__.py +10 -0
  189. aiecs/llm/utils/validate_config.py +91 -0
  190. aiecs/main.py +363 -0
  191. aiecs/scripts/__init__.py +3 -0
  192. aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
  193. aiecs/scripts/aid/__init__.py +19 -0
  194. aiecs/scripts/aid/version_manager.py +215 -0
  195. aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
  196. aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
  197. aiecs/scripts/dependance_check/__init__.py +17 -0
  198. aiecs/scripts/dependance_check/dependency_checker.py +938 -0
  199. aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
  200. aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
  201. aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
  202. aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
  203. aiecs/scripts/dependance_patch/__init__.py +7 -0
  204. aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
  205. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
  206. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
  207. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
  208. aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
  209. aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
  210. aiecs/scripts/tools_develop/README.md +449 -0
  211. aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
  212. aiecs/scripts/tools_develop/__init__.py +21 -0
  213. aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
  214. aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
  215. aiecs/scripts/tools_develop/verify_tools.py +356 -0
  216. aiecs/tasks/__init__.py +1 -0
  217. aiecs/tasks/worker.py +172 -0
  218. aiecs/tools/__init__.py +299 -0
  219. aiecs/tools/apisource/__init__.py +99 -0
  220. aiecs/tools/apisource/intelligence/__init__.py +19 -0
  221. aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
  222. aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
  223. aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
  224. aiecs/tools/apisource/monitoring/__init__.py +9 -0
  225. aiecs/tools/apisource/monitoring/metrics.py +303 -0
  226. aiecs/tools/apisource/providers/__init__.py +115 -0
  227. aiecs/tools/apisource/providers/base.py +664 -0
  228. aiecs/tools/apisource/providers/census.py +401 -0
  229. aiecs/tools/apisource/providers/fred.py +564 -0
  230. aiecs/tools/apisource/providers/newsapi.py +412 -0
  231. aiecs/tools/apisource/providers/worldbank.py +357 -0
  232. aiecs/tools/apisource/reliability/__init__.py +12 -0
  233. aiecs/tools/apisource/reliability/error_handler.py +375 -0
  234. aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
  235. aiecs/tools/apisource/tool.py +850 -0
  236. aiecs/tools/apisource/utils/__init__.py +9 -0
  237. aiecs/tools/apisource/utils/validators.py +338 -0
  238. aiecs/tools/base_tool.py +201 -0
  239. aiecs/tools/docs/__init__.py +121 -0
  240. aiecs/tools/docs/ai_document_orchestrator.py +599 -0
  241. aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
  242. aiecs/tools/docs/content_insertion_tool.py +1333 -0
  243. aiecs/tools/docs/document_creator_tool.py +1317 -0
  244. aiecs/tools/docs/document_layout_tool.py +1166 -0
  245. aiecs/tools/docs/document_parser_tool.py +994 -0
  246. aiecs/tools/docs/document_writer_tool.py +1818 -0
  247. aiecs/tools/knowledge_graph/__init__.py +17 -0
  248. aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
  249. aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
  250. aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
  251. aiecs/tools/langchain_adapter.py +542 -0
  252. aiecs/tools/schema_generator.py +275 -0
  253. aiecs/tools/search_tool/__init__.py +100 -0
  254. aiecs/tools/search_tool/analyzers.py +589 -0
  255. aiecs/tools/search_tool/cache.py +260 -0
  256. aiecs/tools/search_tool/constants.py +128 -0
  257. aiecs/tools/search_tool/context.py +216 -0
  258. aiecs/tools/search_tool/core.py +749 -0
  259. aiecs/tools/search_tool/deduplicator.py +123 -0
  260. aiecs/tools/search_tool/error_handler.py +271 -0
  261. aiecs/tools/search_tool/metrics.py +371 -0
  262. aiecs/tools/search_tool/rate_limiter.py +178 -0
  263. aiecs/tools/search_tool/schemas.py +277 -0
  264. aiecs/tools/statistics/__init__.py +80 -0
  265. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
  266. aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
  267. aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
  268. aiecs/tools/statistics/data_loader_tool.py +564 -0
  269. aiecs/tools/statistics/data_profiler_tool.py +658 -0
  270. aiecs/tools/statistics/data_transformer_tool.py +573 -0
  271. aiecs/tools/statistics/data_visualizer_tool.py +495 -0
  272. aiecs/tools/statistics/model_trainer_tool.py +487 -0
  273. aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
  274. aiecs/tools/task_tools/__init__.py +86 -0
  275. aiecs/tools/task_tools/chart_tool.py +732 -0
  276. aiecs/tools/task_tools/classfire_tool.py +922 -0
  277. aiecs/tools/task_tools/image_tool.py +447 -0
  278. aiecs/tools/task_tools/office_tool.py +684 -0
  279. aiecs/tools/task_tools/pandas_tool.py +635 -0
  280. aiecs/tools/task_tools/report_tool.py +635 -0
  281. aiecs/tools/task_tools/research_tool.py +392 -0
  282. aiecs/tools/task_tools/scraper_tool.py +715 -0
  283. aiecs/tools/task_tools/stats_tool.py +688 -0
  284. aiecs/tools/temp_file_manager.py +130 -0
  285. aiecs/tools/tool_executor/__init__.py +37 -0
  286. aiecs/tools/tool_executor/tool_executor.py +881 -0
  287. aiecs/utils/LLM_output_structor.py +445 -0
  288. aiecs/utils/__init__.py +34 -0
  289. aiecs/utils/base_callback.py +47 -0
  290. aiecs/utils/cache_provider.py +695 -0
  291. aiecs/utils/execution_utils.py +184 -0
  292. aiecs/utils/logging.py +1 -0
  293. aiecs/utils/prompt_loader.py +14 -0
  294. aiecs/utils/token_usage_repository.py +323 -0
  295. aiecs/ws/__init__.py +0 -0
  296. aiecs/ws/socket_server.py +52 -0
  297. aiecs-1.5.1.dist-info/METADATA +608 -0
  298. aiecs-1.5.1.dist-info/RECORD +302 -0
  299. aiecs-1.5.1.dist-info/WHEEL +5 -0
  300. aiecs-1.5.1.dist-info/entry_points.txt +10 -0
  301. aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
  302. aiecs-1.5.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,645 @@
1
+ """
2
+ Communication Hub
3
+
4
+ Provides agent-to-agent messaging, event bus, and pub/sub system
5
+ for community communication and collaboration.
6
+ """
7
+
8
+ import logging
9
+ import asyncio
10
+ from datetime import datetime
11
+ from typing import Dict, List, Any, Optional, Set, Callable
12
+ from enum import Enum
13
+ from collections import defaultdict, deque
14
+ import uuid
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class MessageType(str, Enum):
20
+ """Types of messages in the community."""
21
+
22
+ REQUEST = "request"
23
+ RESPONSE = "response"
24
+ NOTIFICATION = "notification"
25
+ SHARE = "share"
26
+ BROADCAST = "broadcast"
27
+
28
+
29
+ class EventType(str, Enum):
30
+ """Types of community events."""
31
+
32
+ COMMUNITY_CREATED = "community_created"
33
+ COMMUNITY_UPDATED = "community_updated"
34
+ MEMBER_JOINED = "member_joined"
35
+ MEMBER_EXITED = "member_exited"
36
+ MEMBER_UPDATED = "member_updated"
37
+ DECISION_PROPOSED = "decision_proposed"
38
+ DECISION_VOTED = "decision_voted"
39
+ DECISION_APPROVED = "decision_approved"
40
+ DECISION_REJECTED = "decision_rejected"
41
+ RESOURCE_CREATED = "resource_created"
42
+ RESOURCE_UPDATED = "resource_updated"
43
+ RESOURCE_SHARED = "resource_shared"
44
+ SESSION_STARTED = "session_started"
45
+ SESSION_ENDED = "session_ended"
46
+ CUSTOM = "custom"
47
+
48
+
49
+ class Message:
50
+ """Represents a message between agents."""
51
+
52
+ def __init__(
53
+ self,
54
+ sender_id: str,
55
+ recipient_ids: List[str],
56
+ message_type: MessageType,
57
+ content: Any,
58
+ metadata: Optional[Dict[str, Any]] = None,
59
+ ):
60
+ """
61
+ Initialize a message.
62
+
63
+ Args:
64
+ sender_id: ID of the sending agent
65
+ recipient_ids: List of recipient agent IDs (empty for broadcast)
66
+ message_type: Type of message
67
+ content: Message content
68
+ metadata: Optional metadata
69
+ """
70
+ self.message_id = str(uuid.uuid4())
71
+ self.sender_id = sender_id
72
+ self.recipient_ids = recipient_ids
73
+ self.message_type = message_type
74
+ self.content = content
75
+ self.metadata = metadata or {}
76
+ self.timestamp = datetime.utcnow()
77
+ self.delivered_to: Set[str] = set()
78
+ self.read_by: Set[str] = set()
79
+
80
+
81
+ class Event:
82
+ """Represents a community event."""
83
+
84
+ def __init__(
85
+ self,
86
+ event_type: EventType,
87
+ source_id: str,
88
+ data: Dict[str, Any],
89
+ community_id: Optional[str] = None,
90
+ metadata: Optional[Dict[str, Any]] = None,
91
+ ):
92
+ """
93
+ Initialize an event.
94
+
95
+ Args:
96
+ event_type: Type of event
97
+ source_id: ID of the source (community, member, etc.)
98
+ data: Event data
99
+ community_id: Optional community ID
100
+ metadata: Optional metadata
101
+ """
102
+ self.event_id = str(uuid.uuid4())
103
+ self.event_type = event_type
104
+ self.source_id = source_id
105
+ self.data = data
106
+ self.community_id = community_id
107
+ self.metadata = metadata or {}
108
+ self.timestamp = datetime.utcnow()
109
+
110
+
111
+ class CommunicationHub:
112
+ """
113
+ Central hub for agent communication and event distribution.
114
+ Provides messaging, pub/sub, and event broadcasting capabilities.
115
+ """
116
+
117
+ def __init__(self, max_queue_size: int = 1000):
118
+ """
119
+ Initialize the communication hub.
120
+
121
+ Args:
122
+ max_queue_size: Maximum size for message queues
123
+ """
124
+ self.max_queue_size = max_queue_size
125
+
126
+ # Message queues per agent
127
+ self.message_queues: Dict[str, deque] = defaultdict(lambda: deque(maxlen=max_queue_size))
128
+
129
+ # Event subscriptions: event_type -> set of subscriber_ids
130
+ self.event_subscriptions: Dict[EventType, Set[str]] = defaultdict(set)
131
+
132
+ # Topic subscriptions: topic -> set of subscriber_ids
133
+ self.topic_subscriptions: Dict[str, Set[str]] = defaultdict(set)
134
+
135
+ # Event handlers: subscriber_id -> handler_function
136
+ self.event_handlers: Dict[str, Callable] = {}
137
+
138
+ # Message history (limited)
139
+ self.message_history: deque = deque(maxlen=max_queue_size * 2)
140
+ self.event_history: deque = deque(maxlen=max_queue_size * 2)
141
+
142
+ # Output streams: agent_id -> list of subscriber_callback
143
+ self.output_streams: Dict[str, List[Callable]] = defaultdict(list)
144
+
145
+ # Active connections
146
+ self.active_agents: Set[str] = set()
147
+
148
+ logger.info("Communication hub initialized")
149
+
150
+ # ========== Agent Messaging ==========
151
+
152
+ async def send_message(
153
+ self,
154
+ sender_id: str,
155
+ recipient_ids: List[str],
156
+ message_type: MessageType,
157
+ content: Any,
158
+ metadata: Optional[Dict[str, Any]] = None,
159
+ ) -> str:
160
+ """
161
+ Send a message to one or more recipients (unicast/multicast).
162
+
163
+ Args:
164
+ sender_id: ID of the sending agent
165
+ recipient_ids: List of recipient agent IDs
166
+ message_type: Type of message
167
+ content: Message content
168
+ metadata: Optional metadata
169
+
170
+ Returns:
171
+ Message ID
172
+ """
173
+ message = Message(sender_id, recipient_ids, message_type, content, metadata)
174
+
175
+ # Deliver to each recipient's queue
176
+ for recipient_id in recipient_ids:
177
+ if (
178
+ recipient_id in self.active_agents
179
+ or len(self.message_queues[recipient_id]) < self.max_queue_size
180
+ ):
181
+ self.message_queues[recipient_id].append(message)
182
+ message.delivered_to.add(recipient_id)
183
+
184
+ # Store in history
185
+ self.message_history.append(message)
186
+
187
+ logger.debug(
188
+ f"Message {message.message_id} from {sender_id} to {len(recipient_ids)} recipients"
189
+ )
190
+ return message.message_id
191
+
192
+ async def broadcast_message(
193
+ self,
194
+ sender_id: str,
195
+ content: Any,
196
+ community_id: Optional[str] = None,
197
+ metadata: Optional[Dict[str, Any]] = None,
198
+ ) -> str:
199
+ """
200
+ Broadcast a message to all active agents or community members.
201
+
202
+ Args:
203
+ sender_id: ID of the sending agent
204
+ content: Message content
205
+ community_id: Optional community to limit broadcast
206
+ metadata: Optional metadata
207
+
208
+ Returns:
209
+ Message ID
210
+ """
211
+ # Get recipients (all active agents or community members)
212
+ recipients = list(self.active_agents)
213
+
214
+ message = Message(sender_id, recipients, MessageType.BROADCAST, content, metadata)
215
+
216
+ # Deliver to all recipients
217
+ for recipient_id in recipients:
218
+ if recipient_id != sender_id: # Don't send to self
219
+ self.message_queues[recipient_id].append(message)
220
+ message.delivered_to.add(recipient_id)
221
+
222
+ # Store in history
223
+ self.message_history.append(message)
224
+
225
+ logger.info(
226
+ f"Broadcast message {message.message_id} from {sender_id} to {len(recipients)} agents"
227
+ )
228
+ return message.message_id
229
+
230
+ async def receive_messages(
231
+ self,
232
+ agent_id: str,
233
+ mark_as_read: bool = True,
234
+ limit: Optional[int] = None,
235
+ ) -> List[Message]:
236
+ """
237
+ Receive messages for an agent.
238
+
239
+ Args:
240
+ agent_id: ID of the agent receiving messages
241
+ mark_as_read: Whether to mark messages as read
242
+ limit: Optional limit on number of messages to retrieve
243
+
244
+ Returns:
245
+ List of messages
246
+ """
247
+ queue = self.message_queues[agent_id]
248
+
249
+ if not queue:
250
+ return []
251
+
252
+ # Get messages
253
+ count = min(limit, len(queue)) if limit else len(queue)
254
+ messages = []
255
+
256
+ for _ in range(count):
257
+ if queue:
258
+ message = queue.popleft()
259
+ if mark_as_read:
260
+ message.read_by.add(agent_id)
261
+ messages.append(message)
262
+
263
+ logger.debug(f"Agent {agent_id} received {len(messages)} messages")
264
+ return messages
265
+
266
+ async def peek_messages(self, agent_id: str, limit: Optional[int] = None) -> List[Message]:
267
+ """
268
+ Peek at messages without removing them from queue.
269
+
270
+ Args:
271
+ agent_id: ID of the agent
272
+ limit: Optional limit on number of messages
273
+
274
+ Returns:
275
+ List of messages
276
+ """
277
+ queue = self.message_queues[agent_id]
278
+ count = min(limit, len(queue)) if limit else len(queue)
279
+ return list(queue)[:count] if count > 0 else []
280
+
281
+ def get_unread_count(self, agent_id: str) -> int:
282
+ """
283
+ Get count of unread messages for an agent.
284
+
285
+ Args:
286
+ agent_id: ID of the agent
287
+
288
+ Returns:
289
+ Number of unread messages
290
+ """
291
+ return len(self.message_queues[agent_id])
292
+
293
+ # ========== Event Bus & Pub/Sub ==========
294
+
295
+ async def subscribe_to_event(
296
+ self,
297
+ subscriber_id: str,
298
+ event_type: EventType,
299
+ handler: Optional[Callable] = None,
300
+ ) -> bool:
301
+ """
302
+ Subscribe to a specific event type.
303
+
304
+ Args:
305
+ subscriber_id: ID of the subscriber
306
+ event_type: Type of event to subscribe to
307
+ handler: Optional handler function for the event
308
+
309
+ Returns:
310
+ True if subscription was successful
311
+ """
312
+ self.event_subscriptions[event_type].add(subscriber_id)
313
+
314
+ if handler:
315
+ self.event_handlers[f"{subscriber_id}:{event_type.value}"] = handler
316
+
317
+ logger.debug(f"Agent {subscriber_id} subscribed to {event_type.value}")
318
+ return True
319
+
320
+ async def unsubscribe_from_event(self, subscriber_id: str, event_type: EventType) -> bool:
321
+ """
322
+ Unsubscribe from an event type.
323
+
324
+ Args:
325
+ subscriber_id: ID of the subscriber
326
+ event_type: Type of event to unsubscribe from
327
+
328
+ Returns:
329
+ True if unsubscription was successful
330
+ """
331
+ if event_type in self.event_subscriptions:
332
+ self.event_subscriptions[event_type].discard(subscriber_id)
333
+
334
+ handler_key = f"{subscriber_id}:{event_type.value}"
335
+ if handler_key in self.event_handlers:
336
+ del self.event_handlers[handler_key]
337
+
338
+ logger.debug(f"Agent {subscriber_id} unsubscribed from {event_type.value}")
339
+ return True
340
+
341
+ async def subscribe_to_topic(
342
+ self,
343
+ subscriber_id: str,
344
+ topic: str,
345
+ handler: Optional[Callable] = None,
346
+ ) -> bool:
347
+ """
348
+ Subscribe to a custom topic.
349
+
350
+ Args:
351
+ subscriber_id: ID of the subscriber
352
+ topic: Topic name
353
+ handler: Optional handler function
354
+
355
+ Returns:
356
+ True if subscription was successful
357
+ """
358
+ self.topic_subscriptions[topic].add(subscriber_id)
359
+
360
+ if handler:
361
+ self.event_handlers[f"{subscriber_id}:topic:{topic}"] = handler
362
+
363
+ logger.debug(f"Agent {subscriber_id} subscribed to topic '{topic}'")
364
+ return True
365
+
366
+ async def unsubscribe_from_topic(self, subscriber_id: str, topic: str) -> bool:
367
+ """
368
+ Unsubscribe from a topic.
369
+
370
+ Args:
371
+ subscriber_id: ID of the subscriber
372
+ topic: Topic name
373
+
374
+ Returns:
375
+ True if unsubscription was successful
376
+ """
377
+ if topic in self.topic_subscriptions:
378
+ self.topic_subscriptions[topic].discard(subscriber_id)
379
+
380
+ handler_key = f"{subscriber_id}:topic:{topic}"
381
+ if handler_key in self.event_handlers:
382
+ del self.event_handlers[handler_key]
383
+
384
+ logger.debug(f"Agent {subscriber_id} unsubscribed from topic '{topic}'")
385
+ return True
386
+
387
+ async def publish_event(
388
+ self,
389
+ event_type: EventType,
390
+ source_id: str,
391
+ data: Dict[str, Any],
392
+ community_id: Optional[str] = None,
393
+ metadata: Optional[Dict[str, Any]] = None,
394
+ ) -> str:
395
+ """
396
+ Publish an event to all subscribers.
397
+
398
+ Args:
399
+ event_type: Type of event
400
+ source_id: ID of the event source
401
+ data: Event data
402
+ community_id: Optional community ID
403
+ metadata: Optional metadata
404
+
405
+ Returns:
406
+ Event ID
407
+ """
408
+ event = Event(event_type, source_id, data, community_id, metadata)
409
+
410
+ # Store in history
411
+ self.event_history.append(event)
412
+
413
+ # Get subscribers
414
+ subscribers = self.event_subscriptions.get(event_type, set())
415
+
416
+ # Execute handlers
417
+ for subscriber_id in subscribers:
418
+ handler_key = f"{subscriber_id}:{event_type.value}"
419
+ handler = self.event_handlers.get(handler_key)
420
+
421
+ if handler:
422
+ try:
423
+ if asyncio.iscoroutinefunction(handler):
424
+ await handler(event)
425
+ else:
426
+ handler(event)
427
+ except Exception as e:
428
+ logger.error(f"Error executing event handler for {subscriber_id}: {e}")
429
+
430
+ logger.debug(f"Published event {event_type.value} to {len(subscribers)} subscribers")
431
+ return event.event_id
432
+
433
+ async def publish_to_topic(
434
+ self,
435
+ topic: str,
436
+ source_id: str,
437
+ data: Dict[str, Any],
438
+ metadata: Optional[Dict[str, Any]] = None,
439
+ ) -> str:
440
+ """
441
+ Publish data to a topic.
442
+
443
+ Args:
444
+ topic: Topic name
445
+ source_id: ID of the publisher
446
+ data: Data to publish
447
+ metadata: Optional metadata
448
+
449
+ Returns:
450
+ Event ID
451
+ """
452
+ event = Event(EventType.CUSTOM, source_id, data, None, metadata)
453
+ event.metadata["topic"] = topic
454
+
455
+ # Store in history
456
+ self.event_history.append(event)
457
+
458
+ # Get subscribers
459
+ subscribers = self.topic_subscriptions.get(topic, set())
460
+
461
+ # Execute handlers
462
+ for subscriber_id in subscribers:
463
+ handler_key = f"{subscriber_id}:topic:{topic}"
464
+ handler = self.event_handlers.get(handler_key)
465
+
466
+ if handler:
467
+ try:
468
+ if asyncio.iscoroutinefunction(handler):
469
+ await handler(event)
470
+ else:
471
+ handler(event)
472
+ except Exception as e:
473
+ logger.error(f"Error executing topic handler for {subscriber_id}: {e}")
474
+
475
+ logger.debug(f"Published to topic '{topic}' for {len(subscribers)} subscribers")
476
+ return event.event_id
477
+
478
+ # ========== Output Streaming ==========
479
+
480
+ async def subscribe_to_output(
481
+ self,
482
+ publisher_id: str,
483
+ subscriber_callback: Callable[[Dict[str, Any]], None],
484
+ ) -> bool:
485
+ """
486
+ Subscribe to an agent's output stream.
487
+
488
+ Args:
489
+ publisher_id: ID of the agent publishing output
490
+ subscriber_callback: Callback function for output data
491
+
492
+ Returns:
493
+ True if subscription was successful
494
+ """
495
+ self.output_streams[publisher_id].append(subscriber_callback)
496
+ logger.debug(f"Subscribed to output stream of {publisher_id}")
497
+ return True
498
+
499
+ async def unsubscribe_from_output(
500
+ self,
501
+ publisher_id: str,
502
+ subscriber_callback: Callable[[Dict[str, Any]], None],
503
+ ) -> bool:
504
+ """
505
+ Unsubscribe from an agent's output stream.
506
+
507
+ Args:
508
+ publisher_id: ID of the agent
509
+ subscriber_callback: Callback function to remove
510
+
511
+ Returns:
512
+ True if unsubscription was successful
513
+ """
514
+ if publisher_id in self.output_streams:
515
+ if subscriber_callback in self.output_streams[publisher_id]:
516
+ self.output_streams[publisher_id].remove(subscriber_callback)
517
+ logger.debug(f"Unsubscribed from output stream of {publisher_id}")
518
+ return True
519
+ return False
520
+
521
+ async def stream_output(
522
+ self,
523
+ publisher_id: str,
524
+ output_data: Dict[str, Any],
525
+ stream_type: str = "result",
526
+ ) -> int:
527
+ """
528
+ Stream output to all subscribers with backpressure handling.
529
+
530
+ Args:
531
+ publisher_id: ID of the publishing agent
532
+ output_data: Output data to stream
533
+ stream_type: Type of output (result, progress, partial, etc.)
534
+
535
+ Returns:
536
+ Number of subscribers notified
537
+ """
538
+ if publisher_id not in self.output_streams:
539
+ return 0
540
+
541
+ stream_data = {
542
+ "publisher_id": publisher_id,
543
+ "stream_type": stream_type,
544
+ "data": output_data,
545
+ "timestamp": datetime.utcnow().isoformat(),
546
+ }
547
+
548
+ subscribers = self.output_streams[publisher_id]
549
+ notified_count = 0
550
+
551
+ for callback in subscribers:
552
+ try:
553
+ if asyncio.iscoroutinefunction(callback):
554
+ await callback(stream_data)
555
+ else:
556
+ callback(stream_data)
557
+ notified_count += 1
558
+ except Exception as e:
559
+ logger.error(f"Error streaming output to subscriber: {e}")
560
+
561
+ return notified_count
562
+
563
+ # ========== Connection Management ==========
564
+
565
+ async def register_agent(self, agent_id: str) -> bool:
566
+ """
567
+ Register an agent as active in the hub.
568
+
569
+ Args:
570
+ agent_id: ID of the agent
571
+
572
+ Returns:
573
+ True if registration was successful
574
+ """
575
+ self.active_agents.add(agent_id)
576
+ logger.info(f"Registered agent {agent_id} in communication hub")
577
+ return True
578
+
579
+ async def unregister_agent(self, agent_id: str) -> bool:
580
+ """
581
+ Unregister an agent from the hub.
582
+
583
+ Args:
584
+ agent_id: ID of the agent
585
+
586
+ Returns:
587
+ True if unregistration was successful
588
+ """
589
+ self.active_agents.discard(agent_id)
590
+
591
+ # Clean up subscriptions
592
+ for event_type in self.event_subscriptions:
593
+ self.event_subscriptions[event_type].discard(agent_id)
594
+
595
+ for topic in self.topic_subscriptions:
596
+ self.topic_subscriptions[topic].discard(agent_id)
597
+
598
+ # Clean up output streams
599
+ if agent_id in self.output_streams:
600
+ del self.output_streams[agent_id]
601
+
602
+ logger.info(f"Unregistered agent {agent_id} from communication hub")
603
+ return True
604
+
605
+ # ========== Statistics & Monitoring ==========
606
+
607
+ def get_statistics(self) -> Dict[str, Any]:
608
+ """
609
+ Get communication hub statistics.
610
+
611
+ Returns:
612
+ Statistics dictionary
613
+ """
614
+ return {
615
+ "active_agents": len(self.active_agents),
616
+ "total_messages": len(self.message_history),
617
+ "total_events": len(self.event_history),
618
+ "pending_messages": sum(len(q) for q in self.message_queues.values()),
619
+ "event_subscriptions": sum(len(s) for s in self.event_subscriptions.values()),
620
+ "topic_subscriptions": sum(len(s) for s in self.topic_subscriptions.values()),
621
+ "output_streams": len(self.output_streams),
622
+ }
623
+
624
+ def get_agent_status(self, agent_id: str) -> Dict[str, Any]:
625
+ """
626
+ Get status for a specific agent.
627
+
628
+ Args:
629
+ agent_id: ID of the agent
630
+
631
+ Returns:
632
+ Agent status dictionary
633
+ """
634
+ return {
635
+ "agent_id": agent_id,
636
+ "is_active": agent_id in self.active_agents,
637
+ "unread_messages": len(self.message_queues[agent_id]),
638
+ "event_subscriptions": [
639
+ et.value for et, subs in self.event_subscriptions.items() if agent_id in subs
640
+ ],
641
+ "topic_subscriptions": [
642
+ topic for topic, subs in self.topic_subscriptions.items() if agent_id in subs
643
+ ],
644
+ "output_subscribers": len(self.output_streams.get(agent_id, [])),
645
+ }