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