aiecs 1.0.1__py3-none-any.whl → 1.7.17__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.

Potentially problematic release.


This version of aiecs might be problematic. Click here for more details.

Files changed (340) hide show
  1. aiecs/__init__.py +13 -16
  2. aiecs/__main__.py +7 -7
  3. aiecs/aiecs_client.py +269 -75
  4. aiecs/application/executors/operation_executor.py +79 -54
  5. aiecs/application/knowledge_graph/__init__.py +7 -0
  6. aiecs/application/knowledge_graph/builder/__init__.py +37 -0
  7. aiecs/application/knowledge_graph/builder/data_quality.py +302 -0
  8. aiecs/application/knowledge_graph/builder/data_reshaping.py +293 -0
  9. aiecs/application/knowledge_graph/builder/document_builder.py +369 -0
  10. aiecs/application/knowledge_graph/builder/graph_builder.py +490 -0
  11. aiecs/application/knowledge_graph/builder/import_optimizer.py +396 -0
  12. aiecs/application/knowledge_graph/builder/schema_inference.py +462 -0
  13. aiecs/application/knowledge_graph/builder/schema_mapping.py +563 -0
  14. aiecs/application/knowledge_graph/builder/structured_pipeline.py +1384 -0
  15. aiecs/application/knowledge_graph/builder/text_chunker.py +317 -0
  16. aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
  17. aiecs/application/knowledge_graph/extractors/base.py +98 -0
  18. aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +422 -0
  19. aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +347 -0
  20. aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +241 -0
  21. aiecs/application/knowledge_graph/fusion/__init__.py +78 -0
  22. aiecs/application/knowledge_graph/fusion/ab_testing.py +395 -0
  23. aiecs/application/knowledge_graph/fusion/abbreviation_expander.py +327 -0
  24. aiecs/application/knowledge_graph/fusion/alias_index.py +597 -0
  25. aiecs/application/knowledge_graph/fusion/alias_matcher.py +384 -0
  26. aiecs/application/knowledge_graph/fusion/cache_coordinator.py +343 -0
  27. aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +433 -0
  28. aiecs/application/knowledge_graph/fusion/entity_linker.py +511 -0
  29. aiecs/application/knowledge_graph/fusion/evaluation_dataset.py +240 -0
  30. aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +632 -0
  31. aiecs/application/knowledge_graph/fusion/matching_config.py +489 -0
  32. aiecs/application/knowledge_graph/fusion/name_normalizer.py +352 -0
  33. aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +183 -0
  34. aiecs/application/knowledge_graph/fusion/semantic_name_matcher.py +464 -0
  35. aiecs/application/knowledge_graph/fusion/similarity_pipeline.py +534 -0
  36. aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
  37. aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +342 -0
  38. aiecs/application/knowledge_graph/pattern_matching/query_executor.py +366 -0
  39. aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
  40. aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +195 -0
  41. aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
  42. aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
  43. aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +341 -0
  44. aiecs/application/knowledge_graph/reasoning/inference_engine.py +500 -0
  45. aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +163 -0
  46. aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
  47. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
  48. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +913 -0
  49. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +866 -0
  50. aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +475 -0
  51. aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +396 -0
  52. aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +208 -0
  53. aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +170 -0
  54. aiecs/application/knowledge_graph/reasoning/query_planner.py +855 -0
  55. aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +518 -0
  56. aiecs/application/knowledge_graph/retrieval/__init__.py +27 -0
  57. aiecs/application/knowledge_graph/retrieval/query_intent_classifier.py +211 -0
  58. aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +592 -0
  59. aiecs/application/knowledge_graph/retrieval/strategy_types.py +23 -0
  60. aiecs/application/knowledge_graph/search/__init__.py +59 -0
  61. aiecs/application/knowledge_graph/search/hybrid_search.py +457 -0
  62. aiecs/application/knowledge_graph/search/reranker.py +293 -0
  63. aiecs/application/knowledge_graph/search/reranker_strategies.py +535 -0
  64. aiecs/application/knowledge_graph/search/text_similarity.py +392 -0
  65. aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
  66. aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +305 -0
  67. aiecs/application/knowledge_graph/traversal/path_scorer.py +271 -0
  68. aiecs/application/knowledge_graph/validators/__init__.py +13 -0
  69. aiecs/application/knowledge_graph/validators/relation_validator.py +239 -0
  70. aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
  71. aiecs/application/knowledge_graph/visualization/graph_visualizer.py +313 -0
  72. aiecs/common/__init__.py +9 -0
  73. aiecs/common/knowledge_graph/__init__.py +17 -0
  74. aiecs/common/knowledge_graph/runnable.py +471 -0
  75. aiecs/config/__init__.py +20 -5
  76. aiecs/config/config.py +762 -31
  77. aiecs/config/graph_config.py +131 -0
  78. aiecs/config/tool_config.py +435 -0
  79. aiecs/core/__init__.py +29 -13
  80. aiecs/core/interface/__init__.py +2 -2
  81. aiecs/core/interface/execution_interface.py +22 -22
  82. aiecs/core/interface/storage_interface.py +37 -88
  83. aiecs/core/registry/__init__.py +31 -0
  84. aiecs/core/registry/service_registry.py +92 -0
  85. aiecs/domain/__init__.py +270 -1
  86. aiecs/domain/agent/__init__.py +191 -0
  87. aiecs/domain/agent/base_agent.py +3949 -0
  88. aiecs/domain/agent/exceptions.py +99 -0
  89. aiecs/domain/agent/graph_aware_mixin.py +569 -0
  90. aiecs/domain/agent/hybrid_agent.py +1731 -0
  91. aiecs/domain/agent/integration/__init__.py +29 -0
  92. aiecs/domain/agent/integration/context_compressor.py +216 -0
  93. aiecs/domain/agent/integration/context_engine_adapter.py +587 -0
  94. aiecs/domain/agent/integration/protocols.py +281 -0
  95. aiecs/domain/agent/integration/retry_policy.py +218 -0
  96. aiecs/domain/agent/integration/role_config.py +213 -0
  97. aiecs/domain/agent/knowledge_aware_agent.py +1892 -0
  98. aiecs/domain/agent/lifecycle.py +291 -0
  99. aiecs/domain/agent/llm_agent.py +692 -0
  100. aiecs/domain/agent/memory/__init__.py +12 -0
  101. aiecs/domain/agent/memory/conversation.py +1124 -0
  102. aiecs/domain/agent/migration/__init__.py +14 -0
  103. aiecs/domain/agent/migration/conversion.py +163 -0
  104. aiecs/domain/agent/migration/legacy_wrapper.py +86 -0
  105. aiecs/domain/agent/models.py +894 -0
  106. aiecs/domain/agent/observability.py +479 -0
  107. aiecs/domain/agent/persistence.py +449 -0
  108. aiecs/domain/agent/prompts/__init__.py +29 -0
  109. aiecs/domain/agent/prompts/builder.py +159 -0
  110. aiecs/domain/agent/prompts/formatters.py +187 -0
  111. aiecs/domain/agent/prompts/template.py +255 -0
  112. aiecs/domain/agent/registry.py +253 -0
  113. aiecs/domain/agent/tool_agent.py +444 -0
  114. aiecs/domain/agent/tools/__init__.py +15 -0
  115. aiecs/domain/agent/tools/schema_generator.py +377 -0
  116. aiecs/domain/community/__init__.py +155 -0
  117. aiecs/domain/community/agent_adapter.py +469 -0
  118. aiecs/domain/community/analytics.py +432 -0
  119. aiecs/domain/community/collaborative_workflow.py +648 -0
  120. aiecs/domain/community/communication_hub.py +634 -0
  121. aiecs/domain/community/community_builder.py +320 -0
  122. aiecs/domain/community/community_integration.py +796 -0
  123. aiecs/domain/community/community_manager.py +803 -0
  124. aiecs/domain/community/decision_engine.py +849 -0
  125. aiecs/domain/community/exceptions.py +231 -0
  126. aiecs/domain/community/models/__init__.py +33 -0
  127. aiecs/domain/community/models/community_models.py +234 -0
  128. aiecs/domain/community/resource_manager.py +461 -0
  129. aiecs/domain/community/shared_context_manager.py +589 -0
  130. aiecs/domain/context/__init__.py +40 -10
  131. aiecs/domain/context/context_engine.py +1910 -0
  132. aiecs/domain/context/conversation_models.py +87 -53
  133. aiecs/domain/context/graph_memory.py +582 -0
  134. aiecs/domain/execution/model.py +12 -4
  135. aiecs/domain/knowledge_graph/__init__.py +19 -0
  136. aiecs/domain/knowledge_graph/models/__init__.py +52 -0
  137. aiecs/domain/knowledge_graph/models/entity.py +148 -0
  138. aiecs/domain/knowledge_graph/models/evidence.py +178 -0
  139. aiecs/domain/knowledge_graph/models/inference_rule.py +184 -0
  140. aiecs/domain/knowledge_graph/models/path.py +171 -0
  141. aiecs/domain/knowledge_graph/models/path_pattern.py +171 -0
  142. aiecs/domain/knowledge_graph/models/query.py +261 -0
  143. aiecs/domain/knowledge_graph/models/query_plan.py +181 -0
  144. aiecs/domain/knowledge_graph/models/relation.py +202 -0
  145. aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
  146. aiecs/domain/knowledge_graph/schema/entity_type.py +131 -0
  147. aiecs/domain/knowledge_graph/schema/graph_schema.py +253 -0
  148. aiecs/domain/knowledge_graph/schema/property_schema.py +143 -0
  149. aiecs/domain/knowledge_graph/schema/relation_type.py +163 -0
  150. aiecs/domain/knowledge_graph/schema/schema_manager.py +691 -0
  151. aiecs/domain/knowledge_graph/schema/type_enums.py +209 -0
  152. aiecs/domain/task/dsl_processor.py +172 -56
  153. aiecs/domain/task/model.py +20 -8
  154. aiecs/domain/task/task_context.py +27 -24
  155. aiecs/infrastructure/__init__.py +0 -2
  156. aiecs/infrastructure/graph_storage/__init__.py +11 -0
  157. aiecs/infrastructure/graph_storage/base.py +837 -0
  158. aiecs/infrastructure/graph_storage/batch_operations.py +458 -0
  159. aiecs/infrastructure/graph_storage/cache.py +424 -0
  160. aiecs/infrastructure/graph_storage/distributed.py +223 -0
  161. aiecs/infrastructure/graph_storage/error_handling.py +380 -0
  162. aiecs/infrastructure/graph_storage/graceful_degradation.py +294 -0
  163. aiecs/infrastructure/graph_storage/health_checks.py +378 -0
  164. aiecs/infrastructure/graph_storage/in_memory.py +1197 -0
  165. aiecs/infrastructure/graph_storage/index_optimization.py +446 -0
  166. aiecs/infrastructure/graph_storage/lazy_loading.py +431 -0
  167. aiecs/infrastructure/graph_storage/metrics.py +344 -0
  168. aiecs/infrastructure/graph_storage/migration.py +400 -0
  169. aiecs/infrastructure/graph_storage/pagination.py +483 -0
  170. aiecs/infrastructure/graph_storage/performance_monitoring.py +456 -0
  171. aiecs/infrastructure/graph_storage/postgres.py +1563 -0
  172. aiecs/infrastructure/graph_storage/property_storage.py +353 -0
  173. aiecs/infrastructure/graph_storage/protocols.py +76 -0
  174. aiecs/infrastructure/graph_storage/query_optimizer.py +642 -0
  175. aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
  176. aiecs/infrastructure/graph_storage/sqlite.py +1373 -0
  177. aiecs/infrastructure/graph_storage/streaming.py +487 -0
  178. aiecs/infrastructure/graph_storage/tenant.py +412 -0
  179. aiecs/infrastructure/messaging/celery_task_manager.py +92 -54
  180. aiecs/infrastructure/messaging/websocket_manager.py +51 -35
  181. aiecs/infrastructure/monitoring/__init__.py +22 -0
  182. aiecs/infrastructure/monitoring/executor_metrics.py +45 -11
  183. aiecs/infrastructure/monitoring/global_metrics_manager.py +212 -0
  184. aiecs/infrastructure/monitoring/structured_logger.py +3 -7
  185. aiecs/infrastructure/monitoring/tracing_manager.py +63 -35
  186. aiecs/infrastructure/persistence/__init__.py +14 -1
  187. aiecs/infrastructure/persistence/context_engine_client.py +184 -0
  188. aiecs/infrastructure/persistence/database_manager.py +67 -43
  189. aiecs/infrastructure/persistence/file_storage.py +180 -103
  190. aiecs/infrastructure/persistence/redis_client.py +74 -21
  191. aiecs/llm/__init__.py +73 -25
  192. aiecs/llm/callbacks/__init__.py +11 -0
  193. aiecs/llm/{custom_callbacks.py → callbacks/custom_callbacks.py} +26 -19
  194. aiecs/llm/client_factory.py +230 -37
  195. aiecs/llm/client_resolver.py +155 -0
  196. aiecs/llm/clients/__init__.py +38 -0
  197. aiecs/llm/clients/base_client.py +328 -0
  198. aiecs/llm/clients/google_function_calling_mixin.py +415 -0
  199. aiecs/llm/clients/googleai_client.py +314 -0
  200. aiecs/llm/clients/openai_client.py +158 -0
  201. aiecs/llm/clients/openai_compatible_mixin.py +367 -0
  202. aiecs/llm/clients/vertex_client.py +1186 -0
  203. aiecs/llm/clients/xai_client.py +201 -0
  204. aiecs/llm/config/__init__.py +51 -0
  205. aiecs/llm/config/config_loader.py +272 -0
  206. aiecs/llm/config/config_validator.py +206 -0
  207. aiecs/llm/config/model_config.py +143 -0
  208. aiecs/llm/protocols.py +149 -0
  209. aiecs/llm/utils/__init__.py +10 -0
  210. aiecs/llm/utils/validate_config.py +89 -0
  211. aiecs/main.py +140 -121
  212. aiecs/scripts/aid/VERSION_MANAGEMENT.md +138 -0
  213. aiecs/scripts/aid/__init__.py +19 -0
  214. aiecs/scripts/aid/module_checker.py +499 -0
  215. aiecs/scripts/aid/version_manager.py +235 -0
  216. aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +1 -0
  217. aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +1 -0
  218. aiecs/scripts/dependance_check/__init__.py +15 -0
  219. aiecs/scripts/dependance_check/dependency_checker.py +1835 -0
  220. aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +192 -90
  221. aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +203 -71
  222. aiecs/scripts/dependance_patch/__init__.py +7 -0
  223. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
  224. aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +21 -14
  225. aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +1 -1
  226. aiecs/scripts/knowledge_graph/__init__.py +3 -0
  227. aiecs/scripts/knowledge_graph/run_threshold_experiments.py +212 -0
  228. aiecs/scripts/migrations/multi_tenancy/README.md +142 -0
  229. aiecs/scripts/tools_develop/README.md +671 -0
  230. aiecs/scripts/tools_develop/README_CONFIG_CHECKER.md +273 -0
  231. aiecs/scripts/tools_develop/TOOLS_CONFIG_GUIDE.md +1287 -0
  232. aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
  233. aiecs/scripts/tools_develop/__init__.py +21 -0
  234. aiecs/scripts/tools_develop/check_all_tools_config.py +548 -0
  235. aiecs/scripts/tools_develop/check_type_annotations.py +257 -0
  236. aiecs/scripts/tools_develop/pre-commit-schema-coverage.sh +66 -0
  237. aiecs/scripts/tools_develop/schema_coverage.py +511 -0
  238. aiecs/scripts/tools_develop/validate_tool_schemas.py +475 -0
  239. aiecs/scripts/tools_develop/verify_executor_config_fix.py +98 -0
  240. aiecs/scripts/tools_develop/verify_tools.py +352 -0
  241. aiecs/tasks/__init__.py +0 -1
  242. aiecs/tasks/worker.py +115 -47
  243. aiecs/tools/__init__.py +194 -72
  244. aiecs/tools/apisource/__init__.py +99 -0
  245. aiecs/tools/apisource/intelligence/__init__.py +19 -0
  246. aiecs/tools/apisource/intelligence/data_fusion.py +632 -0
  247. aiecs/tools/apisource/intelligence/query_analyzer.py +417 -0
  248. aiecs/tools/apisource/intelligence/search_enhancer.py +385 -0
  249. aiecs/tools/apisource/monitoring/__init__.py +9 -0
  250. aiecs/tools/apisource/monitoring/metrics.py +330 -0
  251. aiecs/tools/apisource/providers/__init__.py +112 -0
  252. aiecs/tools/apisource/providers/base.py +671 -0
  253. aiecs/tools/apisource/providers/census.py +397 -0
  254. aiecs/tools/apisource/providers/fred.py +535 -0
  255. aiecs/tools/apisource/providers/newsapi.py +409 -0
  256. aiecs/tools/apisource/providers/worldbank.py +352 -0
  257. aiecs/tools/apisource/reliability/__init__.py +12 -0
  258. aiecs/tools/apisource/reliability/error_handler.py +363 -0
  259. aiecs/tools/apisource/reliability/fallback_strategy.py +376 -0
  260. aiecs/tools/apisource/tool.py +832 -0
  261. aiecs/tools/apisource/utils/__init__.py +9 -0
  262. aiecs/tools/apisource/utils/validators.py +334 -0
  263. aiecs/tools/base_tool.py +415 -21
  264. aiecs/tools/docs/__init__.py +121 -0
  265. aiecs/tools/docs/ai_document_orchestrator.py +607 -0
  266. aiecs/tools/docs/ai_document_writer_orchestrator.py +2350 -0
  267. aiecs/tools/docs/content_insertion_tool.py +1320 -0
  268. aiecs/tools/docs/document_creator_tool.py +1464 -0
  269. aiecs/tools/docs/document_layout_tool.py +1160 -0
  270. aiecs/tools/docs/document_parser_tool.py +1016 -0
  271. aiecs/tools/docs/document_writer_tool.py +2008 -0
  272. aiecs/tools/knowledge_graph/__init__.py +17 -0
  273. aiecs/tools/knowledge_graph/graph_reasoning_tool.py +807 -0
  274. aiecs/tools/knowledge_graph/graph_search_tool.py +944 -0
  275. aiecs/tools/knowledge_graph/kg_builder_tool.py +524 -0
  276. aiecs/tools/langchain_adapter.py +300 -138
  277. aiecs/tools/schema_generator.py +455 -0
  278. aiecs/tools/search_tool/__init__.py +100 -0
  279. aiecs/tools/search_tool/analyzers.py +581 -0
  280. aiecs/tools/search_tool/cache.py +264 -0
  281. aiecs/tools/search_tool/constants.py +128 -0
  282. aiecs/tools/search_tool/context.py +224 -0
  283. aiecs/tools/search_tool/core.py +778 -0
  284. aiecs/tools/search_tool/deduplicator.py +119 -0
  285. aiecs/tools/search_tool/error_handler.py +242 -0
  286. aiecs/tools/search_tool/metrics.py +343 -0
  287. aiecs/tools/search_tool/rate_limiter.py +172 -0
  288. aiecs/tools/search_tool/schemas.py +275 -0
  289. aiecs/tools/statistics/__init__.py +80 -0
  290. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +646 -0
  291. aiecs/tools/statistics/ai_insight_generator_tool.py +508 -0
  292. aiecs/tools/statistics/ai_report_orchestrator_tool.py +684 -0
  293. aiecs/tools/statistics/data_loader_tool.py +555 -0
  294. aiecs/tools/statistics/data_profiler_tool.py +638 -0
  295. aiecs/tools/statistics/data_transformer_tool.py +580 -0
  296. aiecs/tools/statistics/data_visualizer_tool.py +498 -0
  297. aiecs/tools/statistics/model_trainer_tool.py +507 -0
  298. aiecs/tools/statistics/statistical_analyzer_tool.py +472 -0
  299. aiecs/tools/task_tools/__init__.py +49 -36
  300. aiecs/tools/task_tools/chart_tool.py +200 -184
  301. aiecs/tools/task_tools/classfire_tool.py +268 -267
  302. aiecs/tools/task_tools/image_tool.py +220 -141
  303. aiecs/tools/task_tools/office_tool.py +226 -146
  304. aiecs/tools/task_tools/pandas_tool.py +477 -121
  305. aiecs/tools/task_tools/report_tool.py +390 -142
  306. aiecs/tools/task_tools/research_tool.py +149 -79
  307. aiecs/tools/task_tools/scraper_tool.py +339 -145
  308. aiecs/tools/task_tools/stats_tool.py +448 -209
  309. aiecs/tools/temp_file_manager.py +26 -24
  310. aiecs/tools/tool_executor/__init__.py +18 -16
  311. aiecs/tools/tool_executor/tool_executor.py +364 -52
  312. aiecs/utils/LLM_output_structor.py +74 -48
  313. aiecs/utils/__init__.py +14 -3
  314. aiecs/utils/base_callback.py +0 -3
  315. aiecs/utils/cache_provider.py +696 -0
  316. aiecs/utils/execution_utils.py +50 -31
  317. aiecs/utils/prompt_loader.py +1 -0
  318. aiecs/utils/token_usage_repository.py +37 -11
  319. aiecs/ws/socket_server.py +14 -4
  320. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/METADATA +52 -15
  321. aiecs-1.7.17.dist-info/RECORD +337 -0
  322. aiecs-1.7.17.dist-info/entry_points.txt +13 -0
  323. aiecs/config/registry.py +0 -19
  324. aiecs/domain/context/content_engine.py +0 -982
  325. aiecs/llm/base_client.py +0 -99
  326. aiecs/llm/openai_client.py +0 -125
  327. aiecs/llm/vertex_client.py +0 -186
  328. aiecs/llm/xai_client.py +0 -184
  329. aiecs/scripts/dependency_checker.py +0 -857
  330. aiecs/scripts/quick_dependency_check.py +0 -269
  331. aiecs/tools/task_tools/search_api.py +0 -7
  332. aiecs-1.0.1.dist-info/RECORD +0 -90
  333. aiecs-1.0.1.dist-info/entry_points.txt +0 -7
  334. /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
  335. /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
  336. /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
  337. /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
  338. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/WHEEL +0 -0
  339. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/licenses/LICENSE +0 -0
  340. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,849 @@
1
+ """
2
+ Community Decision Engine
3
+
4
+ Implements collective decision-making algorithms for agent communities,
5
+ including consensus building, voting mechanisms, and conflict resolution.
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime, timedelta
10
+ from typing import Dict, List, Any, Optional, Tuple
11
+ from enum import Enum
12
+
13
+ from .models.community_models import (
14
+ CommunityDecision,
15
+ CommunityMember,
16
+ AgentCommunity,
17
+ DecisionStatus,
18
+ )
19
+ from .exceptions import CommunityValidationError as TaskValidationError
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ class ConsensusAlgorithm(str, Enum):
25
+ """Types of consensus algorithms."""
26
+
27
+ SIMPLE_MAJORITY = "simple_majority"
28
+ SUPERMAJORITY = "supermajority"
29
+ UNANIMOUS = "unanimous"
30
+ WEIGHTED_VOTING = "weighted_voting"
31
+ DELEGATED_PROOF = "delegated_proof"
32
+
33
+
34
+ class ConflictResolutionStrategy(str, Enum):
35
+ """Strategies for resolving conflicts."""
36
+
37
+ MEDIATION = "mediation"
38
+ ARBITRATION = "arbitration"
39
+ COMPROMISE = "compromise"
40
+ ESCALATION = "escalation"
41
+
42
+
43
+ class DecisionEngine:
44
+ """
45
+ Engine for collective decision-making in agent communities.
46
+ """
47
+
48
+ def __init__(self, community_manager=None):
49
+ """
50
+ Initialize the decision engine.
51
+
52
+ Args:
53
+ community_manager: Reference to the community manager
54
+ """
55
+ self.community_manager = community_manager
56
+
57
+ # Decision algorithms configuration
58
+ self.consensus_algorithms = {
59
+ ConsensusAlgorithm.SIMPLE_MAJORITY: self._simple_majority_consensus,
60
+ ConsensusAlgorithm.SUPERMAJORITY: self._supermajority_consensus,
61
+ ConsensusAlgorithm.UNANIMOUS: self._unanimous_consensus,
62
+ ConsensusAlgorithm.WEIGHTED_VOTING: self._weighted_voting_consensus,
63
+ ConsensusAlgorithm.DELEGATED_PROOF: self._delegated_proof_consensus,
64
+ }
65
+
66
+ # Conflict resolution strategies
67
+ self.conflict_resolvers = {
68
+ ConflictResolutionStrategy.MEDIATION: self._mediation_resolution,
69
+ ConflictResolutionStrategy.ARBITRATION: self._arbitration_resolution,
70
+ ConflictResolutionStrategy.COMPROMISE: self._compromise_resolution,
71
+ ConflictResolutionStrategy.ESCALATION: self._escalation_resolution,
72
+ }
73
+
74
+ logger.info("Decision engine initialized")
75
+
76
+ async def evaluate_decision(
77
+ self,
78
+ decision_id: str,
79
+ community_id: str,
80
+ algorithm: ConsensusAlgorithm = ConsensusAlgorithm.SIMPLE_MAJORITY,
81
+ ) -> Tuple[bool, Dict[str, Any]]:
82
+ """
83
+ Evaluate a community decision using the specified consensus algorithm.
84
+
85
+ Args:
86
+ decision_id: ID of the decision to evaluate
87
+ community_id: ID of the community
88
+ algorithm: Consensus algorithm to use
89
+
90
+ Returns:
91
+ Tuple of (decision_passed, evaluation_details)
92
+ """
93
+ if not self.community_manager:
94
+ raise TaskValidationError("Community manager not available")
95
+
96
+ decision = self.community_manager.decisions.get(decision_id)
97
+ if not decision:
98
+ raise TaskValidationError(f"Decision not found: {decision_id}")
99
+
100
+ community = self.community_manager.communities.get(community_id)
101
+ if not community:
102
+ raise TaskValidationError(f"Community not found: {community_id}")
103
+
104
+ # Get consensus algorithm function
105
+ consensus_func = self.consensus_algorithms.get(algorithm)
106
+ if not consensus_func:
107
+ raise TaskValidationError(f"Unknown consensus algorithm: {algorithm}")
108
+
109
+ # Evaluate decision
110
+ result, details = await consensus_func(decision, community)
111
+
112
+ # Update decision status based on result
113
+ if result:
114
+ decision.status = DecisionStatus.APPROVED
115
+ logger.info(f"Decision {decision_id} approved by {algorithm}")
116
+ else:
117
+ decision.status = DecisionStatus.REJECTED
118
+ logger.info(f"Decision {decision_id} rejected by {algorithm}")
119
+
120
+ return result, details
121
+
122
+ async def _simple_majority_consensus(self, decision: CommunityDecision, community: AgentCommunity) -> Tuple[bool, Dict[str, Any]]:
123
+ """Simple majority voting (>50%)."""
124
+ total_votes = len(decision.votes_for) + len(decision.votes_against)
125
+ votes_for = len(decision.votes_for)
126
+ votes_against = len(decision.votes_against)
127
+
128
+ if total_votes == 0:
129
+ return False, {
130
+ "reason": "No votes cast",
131
+ "votes_for": 0,
132
+ "votes_against": 0,
133
+ }
134
+
135
+ majority_threshold = total_votes / 2
136
+ passed = votes_for > majority_threshold
137
+
138
+ details = {
139
+ "algorithm": "simple_majority",
140
+ "votes_for": votes_for,
141
+ "votes_against": votes_against,
142
+ "abstentions": len(decision.abstentions),
143
+ "total_votes": total_votes,
144
+ "threshold": majority_threshold,
145
+ "passed": passed,
146
+ }
147
+
148
+ return passed, details
149
+
150
+ async def _supermajority_consensus(
151
+ self,
152
+ decision: CommunityDecision,
153
+ community: AgentCommunity,
154
+ threshold: float = 0.67,
155
+ ) -> Tuple[bool, Dict[str, Any]]:
156
+ """Supermajority voting (default 67%)."""
157
+ total_votes = len(decision.votes_for) + len(decision.votes_against)
158
+ votes_for = len(decision.votes_for)
159
+
160
+ if total_votes == 0:
161
+ return False, {"reason": "No votes cast", "threshold": threshold}
162
+
163
+ support_ratio = votes_for / total_votes
164
+ passed = support_ratio >= threshold
165
+
166
+ details = {
167
+ "algorithm": "supermajority",
168
+ "votes_for": votes_for,
169
+ "votes_against": len(decision.votes_against),
170
+ "abstentions": len(decision.abstentions),
171
+ "total_votes": total_votes,
172
+ "support_ratio": support_ratio,
173
+ "threshold": threshold,
174
+ "passed": passed,
175
+ }
176
+
177
+ return passed, details
178
+
179
+ async def _unanimous_consensus(self, decision: CommunityDecision, community: AgentCommunity) -> Tuple[bool, Dict[str, Any]]:
180
+ """Unanimous consensus (all votes must be 'for')."""
181
+ votes_for = len(decision.votes_for)
182
+ votes_against = len(decision.votes_against)
183
+ total_members = len(community.members)
184
+
185
+ # For unanimous consensus, we need all active members to vote 'for'
186
+ # and no votes 'against'
187
+ passed = votes_against == 0 and votes_for > 0
188
+
189
+ details = {
190
+ "algorithm": "unanimous",
191
+ "votes_for": votes_for,
192
+ "votes_against": votes_against,
193
+ "abstentions": len(decision.abstentions),
194
+ "total_members": total_members,
195
+ "passed": passed,
196
+ }
197
+
198
+ return passed, details
199
+
200
+ async def _weighted_voting_consensus(self, decision: CommunityDecision, community: AgentCommunity) -> Tuple[bool, Dict[str, Any]]:
201
+ """Weighted voting based on member reputation and contribution."""
202
+ if not self.community_manager:
203
+ return False, {"reason": "Community manager not available"}
204
+
205
+ weighted_for = 0.0
206
+ weighted_against = 0.0
207
+ total_weight = 0.0
208
+
209
+ # Calculate weights for all votes
210
+ for member_id in decision.votes_for:
211
+ member = self.community_manager.members.get(member_id)
212
+ if member:
213
+ weight = self._calculate_member_weight(member)
214
+ weighted_for += weight
215
+ total_weight += weight
216
+
217
+ for member_id in decision.votes_against:
218
+ member = self.community_manager.members.get(member_id)
219
+ if member:
220
+ weight = self._calculate_member_weight(member)
221
+ weighted_against += weight
222
+ total_weight += weight
223
+
224
+ if total_weight == 0:
225
+ return False, {"reason": "No weighted votes", "total_weight": 0}
226
+
227
+ support_ratio = weighted_for / total_weight
228
+ passed = support_ratio > 0.5 # Weighted majority
229
+
230
+ details = {
231
+ "algorithm": "weighted_voting",
232
+ "weighted_for": weighted_for,
233
+ "weighted_against": weighted_against,
234
+ "total_weight": total_weight,
235
+ "support_ratio": support_ratio,
236
+ "passed": passed,
237
+ }
238
+
239
+ return passed, details
240
+
241
+ async def _delegated_proof_consensus(self, decision: CommunityDecision, community: AgentCommunity) -> Tuple[bool, Dict[str, Any]]:
242
+ """Delegated proof consensus (leaders and coordinators have more weight)."""
243
+ if not self.community_manager:
244
+ return False, {"reason": "Community manager not available"}
245
+
246
+ leader_votes_for = 0
247
+ leader_votes_against = 0
248
+ coordinator_votes_for = 0
249
+ coordinator_votes_against = 0
250
+ regular_votes_for = 0
251
+ regular_votes_against = 0
252
+
253
+ # Count votes by role
254
+ for member_id in decision.votes_for:
255
+ member = self.community_manager.members.get(member_id)
256
+ if member:
257
+ if member_id in community.leaders:
258
+ leader_votes_for += 1
259
+ elif member_id in community.coordinators:
260
+ coordinator_votes_for += 1
261
+ else:
262
+ regular_votes_for += 1
263
+
264
+ for member_id in decision.votes_against:
265
+ member = self.community_manager.members.get(member_id)
266
+ if member:
267
+ if member_id in community.leaders:
268
+ leader_votes_against += 1
269
+ elif member_id in community.coordinators:
270
+ coordinator_votes_against += 1
271
+ else:
272
+ regular_votes_against += 1
273
+
274
+ # Calculate weighted score (leaders: 3x, coordinators: 2x, regular: 1x)
275
+ score_for = (leader_votes_for * 3) + (coordinator_votes_for * 2) + regular_votes_for
276
+ score_against = (leader_votes_against * 3) + (coordinator_votes_against * 2) + regular_votes_against
277
+
278
+ total_score = score_for + score_against
279
+ passed = total_score > 0 and score_for > score_against
280
+
281
+ details = {
282
+ "algorithm": "delegated_proof",
283
+ "leader_votes_for": leader_votes_for,
284
+ "leader_votes_against": leader_votes_against,
285
+ "coordinator_votes_for": coordinator_votes_for,
286
+ "coordinator_votes_against": coordinator_votes_against,
287
+ "regular_votes_for": regular_votes_for,
288
+ "regular_votes_against": regular_votes_against,
289
+ "score_for": score_for,
290
+ "score_against": score_against,
291
+ "passed": passed,
292
+ }
293
+
294
+ return passed, details
295
+
296
+ def _calculate_member_weight(self, member: CommunityMember) -> float:
297
+ """Calculate voting weight for a member based on reputation and contribution."""
298
+ base_weight = 1.0
299
+ reputation_bonus = member.reputation * 0.5 # Up to 50% bonus for reputation
300
+ contribution_bonus = member.contribution_score * 0.3 # Up to 30% bonus for contribution
301
+
302
+ return base_weight + reputation_bonus + contribution_bonus
303
+
304
+ async def resolve_conflict(
305
+ self,
306
+ decision_id: str,
307
+ community_id: str,
308
+ strategy: ConflictResolutionStrategy = ConflictResolutionStrategy.MEDIATION,
309
+ ) -> Dict[str, Any]:
310
+ """
311
+ Resolve conflicts in community decisions.
312
+
313
+ Args:
314
+ decision_id: ID of the decision with conflict
315
+ community_id: ID of the community
316
+ strategy: Conflict resolution strategy
317
+
318
+ Returns:
319
+ Resolution details
320
+ """
321
+ resolver_func = self.conflict_resolvers.get(strategy)
322
+ if not resolver_func:
323
+ raise TaskValidationError(f"Unknown conflict resolution strategy: {strategy}")
324
+
325
+ return await resolver_func(decision_id, community_id)
326
+
327
+ async def _mediation_resolution(self, decision_id: str, community_id: str) -> Dict[str, Any]:
328
+ """
329
+ Mediation-based conflict resolution.
330
+
331
+ Process:
332
+ 1. Select neutral mediator (high reputation, not involved in voting)
333
+ 2. Facilitate structured discussion between opposing sides
334
+ 3. Identify core concerns and interests
335
+ 4. Propose compromise solutions
336
+ 5. Build consensus on mediated outcome
337
+ """
338
+ if not self.community_manager:
339
+ return {
340
+ "strategy": "mediation",
341
+ "status": "failed",
342
+ "reason": "Community manager not available",
343
+ }
344
+
345
+ decision = self.community_manager.decisions.get(decision_id)
346
+ community = self.community_manager.communities.get(community_id)
347
+
348
+ if not decision or not community:
349
+ return {
350
+ "strategy": "mediation",
351
+ "status": "failed",
352
+ "reason": "Decision or community not found",
353
+ }
354
+
355
+ # Step 1: Select mediator
356
+ mediator_id = await self._select_mediator(decision, community)
357
+ if not mediator_id:
358
+ return {
359
+ "strategy": "mediation",
360
+ "status": "failed",
361
+ "reason": "No suitable mediator found",
362
+ }
363
+
364
+ # Step 2: Identify opposing sides
365
+ for_side = decision.votes_for
366
+ against_side = decision.votes_against
367
+
368
+ # Step 3: Analyze core concerns (simulate by examining vote
369
+ # distribution)
370
+ concerns = {
371
+ "support_concerns": self._extract_concerns(for_side, community),
372
+ "opposition_concerns": self._extract_concerns(against_side, community),
373
+ }
374
+
375
+ # Step 4: Propose compromise
376
+ compromise_proposal = {
377
+ "original_proposal": decision.title,
378
+ "modifications": [
379
+ "Address key concerns from opposition",
380
+ "Maintain core value from supporters",
381
+ "Add safeguards or conditions",
382
+ "Phased implementation approach",
383
+ ],
384
+ "mediator_recommendation": "Modified proposal with balanced approach",
385
+ }
386
+
387
+ # Step 5: Set up for re-vote
388
+ result = {
389
+ "strategy": "mediation",
390
+ "status": "mediation_completed",
391
+ "mediator_id": mediator_id,
392
+ "mediator": (self.community_manager.members.get(mediator_id).agent_id if mediator_id else None),
393
+ "concerns_identified": concerns,
394
+ "compromise_proposal": compromise_proposal,
395
+ "next_steps": "Re-vote on mediated proposal",
396
+ "recommended_threshold": "simple_majority",
397
+ }
398
+
399
+ logger.info(f"Mediation completed for decision {decision_id} by mediator {mediator_id}")
400
+ return result
401
+
402
+ async def _select_mediator(self, decision: CommunityDecision, community: AgentCommunity) -> Optional[str]:
403
+ """Select a neutral mediator for conflict resolution."""
404
+ # Find members who didn't vote or abstained, with high reputation
405
+ candidates = []
406
+
407
+ all_voters = set(decision.votes_for + decision.votes_against)
408
+
409
+ for member_id in community.members:
410
+ if member_id not in all_voters:
411
+ member = self.community_manager.members.get(member_id)
412
+ if member and member.reputation > 0.5: # High reputation threshold
413
+ candidates.append((member_id, member.reputation))
414
+
415
+ # Also consider abstentions with very high reputation
416
+ for member_id in decision.abstentions:
417
+ member = self.community_manager.members.get(member_id)
418
+ if member and member.reputation > 0.7:
419
+ candidates.append((member_id, member.reputation))
420
+
421
+ if not candidates:
422
+ return None
423
+
424
+ # Select highest reputation member
425
+ candidates.sort(key=lambda x: x[1], reverse=True)
426
+ return candidates[0][0]
427
+
428
+ def _extract_concerns(self, voter_ids: List[str], community: AgentCommunity) -> List[str]:
429
+ """Extract concerns from voter groups based on their roles and specializations."""
430
+ concerns = []
431
+ role_distribution: Dict[str, int] = {}
432
+
433
+ for voter_id in voter_ids:
434
+ member = self.community_manager.members.get(voter_id) if self.community_manager else None
435
+ if member:
436
+ role = member.community_role.value
437
+ role_distribution[role] = role_distribution.get(role, 0) + 1
438
+
439
+ # Generate concerns based on roles
440
+ if "leader" in role_distribution:
441
+ concerns.append("Strategic alignment and governance impact")
442
+ if "specialist" in role_distribution:
443
+ concerns.append("Technical feasibility and implementation details")
444
+ if "contributor" in role_distribution:
445
+ concerns.append("Practical implications and workload impact")
446
+
447
+ return concerns if concerns else ["General concerns about proposal"]
448
+
449
+ async def _arbitration_resolution(self, decision_id: str, community_id: str) -> Dict[str, Any]:
450
+ """
451
+ Arbitration-based conflict resolution.
452
+
453
+ Process:
454
+ 1. Select authoritative arbitrator (leader or senior coordinator)
455
+ 2. Review all arguments and evidence
456
+ 3. Make binding decision
457
+ 4. Provide detailed rationale
458
+ """
459
+ if not self.community_manager:
460
+ return {
461
+ "strategy": "arbitration",
462
+ "status": "failed",
463
+ "reason": "Community manager not available",
464
+ }
465
+
466
+ decision = self.community_manager.decisions.get(decision_id)
467
+ community = self.community_manager.communities.get(community_id)
468
+
469
+ if not decision or not community:
470
+ return {
471
+ "strategy": "arbitration",
472
+ "status": "failed",
473
+ "reason": "Decision or community not found",
474
+ }
475
+
476
+ # Step 1: Select arbitrator (prefer leader, then coordinator with
477
+ # highest reputation)
478
+ arbitrator_id = await self._select_arbitrator(community)
479
+ if not arbitrator_id:
480
+ return {
481
+ "strategy": "arbitration",
482
+ "status": "failed",
483
+ "reason": "No suitable arbitrator found",
484
+ }
485
+
486
+ # Step 2: Analyze decision context
487
+ votes_for = len(decision.votes_for)
488
+ votes_against = len(decision.votes_against)
489
+ total_votes = votes_for + votes_against
490
+
491
+ # Step 3: Make arbitration decision (simulate based on vote distribution and priority)
492
+ # In practice, this would involve the actual arbitrator's judgment
493
+ support_ratio = votes_for / total_votes if total_votes > 0 else 0
494
+
495
+ # Arbitrator considers: vote distribution, decision priority, community
496
+ # impact
497
+ # Lower threshold with rationale
498
+ arbitration_decision = "approved" if support_ratio >= 0.4 else "rejected"
499
+
500
+ # Step 4: Provide rationale
501
+ rationale = self._generate_arbitration_rationale(arbitration_decision, support_ratio, decision, community)
502
+
503
+ result = {
504
+ "strategy": "arbitration",
505
+ "status": "arbitration_completed",
506
+ "arbitrator_id": arbitrator_id,
507
+ "arbitrator": (self.community_manager.members.get(arbitrator_id).agent_id if arbitrator_id else None),
508
+ "binding_decision": arbitration_decision,
509
+ "rationale": rationale,
510
+ "votes_for": votes_for,
511
+ "votes_against": votes_against,
512
+ "support_ratio": support_ratio,
513
+ "is_binding": True,
514
+ "appeal_allowed": False,
515
+ }
516
+
517
+ # Update decision status based on arbitration
518
+ if arbitration_decision == "approved":
519
+ decision.status = DecisionStatus.APPROVED
520
+ else:
521
+ decision.status = DecisionStatus.REJECTED
522
+
523
+ logger.info(f"Arbitration completed for decision {decision_id}: {arbitration_decision}")
524
+ return result
525
+
526
+ async def _select_arbitrator(self, community: AgentCommunity) -> Optional[str]:
527
+ """Select an authoritative arbitrator."""
528
+ # Prefer leaders first
529
+ if community.leaders:
530
+ # Select leader with highest reputation
531
+ best_leader = None
532
+ best_reputation = -1
533
+
534
+ for leader_id in community.leaders:
535
+ member = self.community_manager.members.get(leader_id)
536
+ if member and member.reputation > best_reputation:
537
+ best_reputation = member.reputation
538
+ best_leader = leader_id
539
+
540
+ if best_leader:
541
+ return best_leader
542
+
543
+ # Fall back to coordinators
544
+ if community.coordinators:
545
+ best_coordinator = None
546
+ best_reputation = -1
547
+
548
+ for coordinator_id in community.coordinators:
549
+ member = self.community_manager.members.get(coordinator_id)
550
+ if member and member.reputation > best_reputation:
551
+ best_reputation = member.reputation
552
+ best_coordinator = coordinator_id
553
+
554
+ if best_coordinator:
555
+ return best_coordinator
556
+
557
+ return None
558
+
559
+ def _generate_arbitration_rationale(
560
+ self,
561
+ decision: str,
562
+ support_ratio: float,
563
+ proposal: CommunityDecision,
564
+ community: AgentCommunity,
565
+ ) -> str:
566
+ """Generate detailed rationale for arbitration decision."""
567
+ rationale_parts = []
568
+
569
+ rationale_parts.append(f"After careful review of the proposal '{proposal.title}', ")
570
+ rationale_parts.append(f"with {support_ratio:.1%} support from voting members, ")
571
+
572
+ if decision == "approved":
573
+ rationale_parts.append("this arbitration approves the proposal. ")
574
+ rationale_parts.append("The decision aligns with community interests and demonstrates sufficient support. ")
575
+ if support_ratio < 0.5:
576
+ rationale_parts.append("While not achieving majority, the strategic importance warrants approval. ")
577
+ else:
578
+ rationale_parts.append("this arbitration rejects the proposal. ")
579
+ rationale_parts.append("The concerns raised outweigh the benefits, and insufficient consensus exists. ")
580
+
581
+ rationale_parts.append(f"Priority level: {proposal.priority}. ")
582
+ rationale_parts.append("This decision is binding and final.")
583
+
584
+ return "".join(rationale_parts)
585
+
586
+ async def _compromise_resolution(self, decision_id: str, community_id: str) -> Dict[str, Any]:
587
+ """
588
+ Compromise-based conflict resolution.
589
+
590
+ Process:
591
+ 1. Analyze opposing positions
592
+ 2. Identify negotiable vs non-negotiable elements
593
+ 3. Generate compromise alternatives
594
+ 4. Create hybrid solution
595
+ 5. Test acceptance with stakeholders
596
+ """
597
+ if not self.community_manager:
598
+ return {
599
+ "strategy": "compromise",
600
+ "status": "failed",
601
+ "reason": "Community manager not available",
602
+ }
603
+
604
+ decision = self.community_manager.decisions.get(decision_id)
605
+ community = self.community_manager.communities.get(community_id)
606
+
607
+ if not decision or not community:
608
+ return {
609
+ "strategy": "compromise",
610
+ "status": "failed",
611
+ "reason": "Decision or community not found",
612
+ }
613
+
614
+ votes_for = len(decision.votes_for)
615
+ votes_against = len(decision.votes_against)
616
+ total_votes = votes_for + votes_against
617
+
618
+ if total_votes == 0:
619
+ return {
620
+ "strategy": "compromise",
621
+ "status": "failed",
622
+ "reason": "No votes to analyze",
623
+ }
624
+
625
+ # Step 1: Analyze positions
626
+ support_ratio = votes_for / total_votes
627
+ opposition_ratio = votes_against / total_votes
628
+
629
+ position_analysis = {
630
+ "support_strength": support_ratio,
631
+ "opposition_strength": opposition_ratio,
632
+ "balance": ("balanced" if 0.4 <= support_ratio <= 0.6 else "polarized"),
633
+ }
634
+
635
+ # Step 2: Identify elements
636
+ elements = {
637
+ "core_proposal": decision.title,
638
+ "negotiable_elements": [
639
+ "Implementation timeline",
640
+ "Resource allocation",
641
+ "Scope limitations",
642
+ "Review checkpoints",
643
+ ],
644
+ "non_negotiable_elements": [
645
+ "Core objectives",
646
+ "Safety requirements",
647
+ "Community values alignment",
648
+ ],
649
+ }
650
+
651
+ # Step 3 & 4: Generate compromise alternatives
652
+ compromise_options = []
653
+
654
+ # Option 1: Phased approach
655
+ compromise_options.append(
656
+ {
657
+ "option": "phased_implementation",
658
+ "description": "Implement in phases with review points",
659
+ "modifications": [
660
+ "Start with pilot/trial phase",
661
+ "Review after initial phase",
662
+ "Full rollout conditional on pilot success",
663
+ ],
664
+ "acceptance_probability": 0.75,
665
+ }
666
+ )
667
+
668
+ # Option 2: Conditional approval
669
+ compromise_options.append(
670
+ {
671
+ "option": "conditional_approval",
672
+ "description": "Approve with conditions addressing concerns",
673
+ "modifications": [
674
+ "Add oversight committee",
675
+ "Include opposition representatives",
676
+ "Establish success metrics and review schedule",
677
+ ],
678
+ "acceptance_probability": 0.70,
679
+ }
680
+ )
681
+
682
+ # Option 3: Scaled-down version
683
+ compromise_options.append(
684
+ {
685
+ "option": "scaled_down",
686
+ "description": "Reduced scope addressing primary concerns",
687
+ "modifications": [
688
+ "Limit scope to less contentious areas",
689
+ "Reduce resource commitment",
690
+ "Extend timeline for gradual adoption",
691
+ ],
692
+ "acceptance_probability": 0.65,
693
+ }
694
+ )
695
+
696
+ # Select best compromise based on vote distribution
697
+ recommended_option = compromise_options[0] if support_ratio > 0.45 else compromise_options[2]
698
+
699
+ result = {
700
+ "strategy": "compromise",
701
+ "status": "compromise_proposed",
702
+ "position_analysis": position_analysis,
703
+ "elements": elements,
704
+ "compromise_options": compromise_options,
705
+ "recommended_option": recommended_option,
706
+ "next_steps": "Review compromise options and vote on preferred alternative",
707
+ "requires_revote": True,
708
+ "expected_consensus": recommended_option["acceptance_probability"],
709
+ }
710
+
711
+ logger.info(f"Compromise resolution generated for decision {decision_id}")
712
+ return result
713
+
714
+ async def _escalation_resolution(self, decision_id: str, community_id: str) -> Dict[str, Any]:
715
+ """
716
+ Escalation-based conflict resolution.
717
+
718
+ Process:
719
+ 1. Determine current escalation level
720
+ 2. Escalate to higher authority/broader group
721
+ 3. Apply progressively stronger resolution mechanisms
722
+ 4. Track escalation path and outcomes
723
+
724
+ Escalation Levels:
725
+ - Level 1: Community-wide discussion and re-vote
726
+ - Level 2: Coordinator council review
727
+ - Level 3: Leader decision
728
+ - Level 4: External arbitration or parent community
729
+ """
730
+ if not self.community_manager:
731
+ return {
732
+ "strategy": "escalation",
733
+ "status": "failed",
734
+ "reason": "Community manager not available",
735
+ }
736
+
737
+ decision = self.community_manager.decisions.get(decision_id)
738
+ community = self.community_manager.communities.get(community_id)
739
+
740
+ if not decision or not community:
741
+ return {
742
+ "strategy": "escalation",
743
+ "status": "failed",
744
+ "reason": "Decision or community not found",
745
+ }
746
+
747
+ # Determine current escalation level from metadata
748
+ current_level = decision.metadata.get("escalation_level", 0)
749
+ next_level = current_level + 1
750
+
751
+ # Define escalation path
752
+ escalation_path = {
753
+ 1: {
754
+ "level": 1,
755
+ "name": "Community Discussion",
756
+ "authority": "All active members",
757
+ "process": "Open discussion with extended voting period",
758
+ "threshold": "supermajority (67%)",
759
+ "timeline": "7 days",
760
+ },
761
+ 2: {
762
+ "level": 2,
763
+ "name": "Coordinator Council",
764
+ "authority": "Community coordinators",
765
+ "process": "Coordinator review and recommendation",
766
+ "threshold": "coordinator consensus",
767
+ "timeline": "3 days",
768
+ },
769
+ 3: {
770
+ "level": 3,
771
+ "name": "Leadership Decision",
772
+ "authority": "Community leaders",
773
+ "process": "Leadership panel makes binding decision",
774
+ "threshold": "leader majority or single leader decision",
775
+ "timeline": "1 day",
776
+ },
777
+ 4: {
778
+ "level": 4,
779
+ "name": "External Review",
780
+ "authority": "External arbitrator or parent community",
781
+ "process": "Independent third-party review",
782
+ "threshold": "external arbitrator decision",
783
+ "timeline": "As needed",
784
+ },
785
+ }
786
+
787
+ if next_level > 4:
788
+ return {
789
+ "strategy": "escalation",
790
+ "status": "max_escalation_reached",
791
+ "message": "Maximum escalation level reached. Decision must be resolved or abandoned.",
792
+ "recommendation": "Consider abandoning or significantly revising the proposal",
793
+ }
794
+
795
+ current_escalation = escalation_path[next_level]
796
+
797
+ # Determine escalation authority
798
+ authority_members = []
799
+ if next_level == 1:
800
+ authority_members = community.members
801
+ elif next_level == 2:
802
+ authority_members = community.coordinators
803
+ elif next_level == 3:
804
+ authority_members = community.leaders
805
+ elif next_level == 4:
806
+ authority_members = [] # External
807
+
808
+ # Update decision metadata
809
+ decision.metadata["escalation_level"] = next_level
810
+ decision.metadata["escalation_timestamp"] = datetime.utcnow().isoformat()
811
+ decision.metadata["escalation_history"] = decision.metadata.get("escalation_history", [])
812
+ decision.metadata["escalation_history"].append(
813
+ {
814
+ "from_level": current_level,
815
+ "to_level": next_level,
816
+ "timestamp": datetime.utcnow().isoformat(),
817
+ "reason": "Unresolved conflict",
818
+ }
819
+ )
820
+
821
+ result = {
822
+ "strategy": "escalation",
823
+ "status": "escalated",
824
+ "previous_level": current_level,
825
+ "current_level": next_level,
826
+ "escalation_details": current_escalation,
827
+ "authority_members": authority_members,
828
+ "authority_count": len(authority_members),
829
+ "escalation_history": decision.metadata["escalation_history"],
830
+ "next_steps": f"Proceed with {current_escalation['name']} process",
831
+ "required_action": current_escalation["process"],
832
+ "decision_threshold": current_escalation["threshold"],
833
+ "timeline": current_escalation["timeline"],
834
+ }
835
+
836
+ # Reset voting for re-evaluation at new level
837
+ if next_level < 4:
838
+ decision.votes_for = []
839
+ decision.votes_against = []
840
+ decision.abstentions = []
841
+ decision.status = DecisionStatus.PROPOSED
842
+ timeline_str = current_escalation.get("timeline", "0 days")
843
+ if isinstance(timeline_str, str):
844
+ decision.voting_ends_at = datetime.utcnow() + timedelta(days=int(timeline_str.split()[0]))
845
+ else:
846
+ decision.voting_ends_at = datetime.utcnow() + timedelta(days=7) # Default to 7 days
847
+
848
+ logger.info(f"Decision {decision_id} escalated to level {next_level}: {current_escalation['name']}")
849
+ return result