aiecs 1.0.4__py3-none-any.whl → 1.0.6__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.
- aiecs/__init__.py +1 -1
- aiecs/config/config.py +1 -0
- aiecs/domain/community/collaborative_workflow.py +407 -0
- aiecs/domain/community/community_integration.py +439 -0
- aiecs/domain/community/community_manager.py +337 -0
- aiecs/domain/community/decision_engine.py +354 -0
- aiecs/domain/community/models/community_models.py +204 -0
- aiecs/domain/community/resource_manager.py +438 -0
- aiecs/infrastructure/persistence/__init__.py +12 -0
- aiecs/infrastructure/persistence/context_engine_client.py +176 -0
- aiecs/llm/base_client.py +1 -0
- aiecs/llm/client_factory.py +4 -0
- aiecs/llm/custom_callbacks.py +3 -3
- aiecs/llm/googleai_client.py +165 -0
- aiecs/llm/openai_client.py +1 -1
- aiecs/llm/vertex_client.py +72 -34
- aiecs/llm/xai_client.py +1 -1
- aiecs/main.py +2 -2
- aiecs/utils/token_usage_repository.py +1 -1
- {aiecs-1.0.4.dist-info → aiecs-1.0.6.dist-info}/METADATA +2 -2
- {aiecs-1.0.4.dist-info → aiecs-1.0.6.dist-info}/RECORD +25 -17
- {aiecs-1.0.4.dist-info → aiecs-1.0.6.dist-info}/WHEEL +0 -0
- {aiecs-1.0.4.dist-info → aiecs-1.0.6.dist-info}/entry_points.txt +0 -0
- {aiecs-1.0.4.dist-info → aiecs-1.0.6.dist-info}/licenses/LICENSE +0 -0
- {aiecs-1.0.4.dist-info → aiecs-1.0.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Community Manager
|
|
3
|
+
|
|
4
|
+
Core component for managing agent communities, including governance,
|
|
5
|
+
resource sharing, and collaborative decision-making.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from datetime import datetime, timedelta
|
|
10
|
+
from typing import Dict, List, Any, Optional, Set
|
|
11
|
+
import uuid
|
|
12
|
+
|
|
13
|
+
from .models.community_models import (
|
|
14
|
+
AgentCommunity, CommunityMember, CommunityResource, CommunityDecision,
|
|
15
|
+
CollaborationSession, CommunityRole, GovernanceType, DecisionStatus, ResourceType
|
|
16
|
+
)
|
|
17
|
+
from ..core.exceptions.task_exceptions import TaskValidationError
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CommunityManager:
|
|
23
|
+
"""
|
|
24
|
+
Manager for agent communities, handling governance, collaboration, and resource sharing.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, context_engine=None):
|
|
28
|
+
"""
|
|
29
|
+
Initialize the community manager.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
context_engine: Optional context engine for persistent storage
|
|
33
|
+
"""
|
|
34
|
+
self.context_engine = context_engine
|
|
35
|
+
|
|
36
|
+
# In-memory storage (should be replaced with persistent storage)
|
|
37
|
+
self.communities: Dict[str, AgentCommunity] = {}
|
|
38
|
+
self.members: Dict[str, CommunityMember] = {}
|
|
39
|
+
self.resources: Dict[str, CommunityResource] = {}
|
|
40
|
+
self.decisions: Dict[str, CommunityDecision] = {}
|
|
41
|
+
self.sessions: Dict[str, CollaborationSession] = {}
|
|
42
|
+
|
|
43
|
+
# Community relationships
|
|
44
|
+
self.member_communities: Dict[str, Set[str]] = {} # member_id -> set of community_ids
|
|
45
|
+
self.community_members: Dict[str, Set[str]] = {} # community_id -> set of member_ids
|
|
46
|
+
|
|
47
|
+
self._initialized = False
|
|
48
|
+
logger.info("Community manager initialized")
|
|
49
|
+
|
|
50
|
+
async def initialize(self) -> None:
|
|
51
|
+
"""Initialize the community manager."""
|
|
52
|
+
if self._initialized:
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
# Load existing communities and members from persistent storage if available
|
|
56
|
+
if self.context_engine:
|
|
57
|
+
await self._load_from_storage()
|
|
58
|
+
|
|
59
|
+
self._initialized = True
|
|
60
|
+
logger.info("Community manager initialization completed")
|
|
61
|
+
|
|
62
|
+
async def create_community(
|
|
63
|
+
self,
|
|
64
|
+
name: str,
|
|
65
|
+
description: Optional[str] = None,
|
|
66
|
+
governance_type: GovernanceType = GovernanceType.DEMOCRATIC,
|
|
67
|
+
governance_rules: Optional[Dict[str, Any]] = None,
|
|
68
|
+
creator_agent_id: Optional[str] = None
|
|
69
|
+
) -> str:
|
|
70
|
+
"""
|
|
71
|
+
Create a new agent community.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
name: Name of the community
|
|
75
|
+
description: Optional description
|
|
76
|
+
governance_type: Type of governance
|
|
77
|
+
governance_rules: Governance rules and policies
|
|
78
|
+
creator_agent_id: ID of the agent creating the community
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Community ID
|
|
82
|
+
"""
|
|
83
|
+
community = AgentCommunity(
|
|
84
|
+
name=name,
|
|
85
|
+
description=description,
|
|
86
|
+
governance_type=governance_type,
|
|
87
|
+
governance_rules=governance_rules or {}
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
self.communities[community.community_id] = community
|
|
91
|
+
self.community_members[community.community_id] = set()
|
|
92
|
+
|
|
93
|
+
# Add creator as the first leader if provided
|
|
94
|
+
if creator_agent_id:
|
|
95
|
+
await self.add_member_to_community(
|
|
96
|
+
community.community_id,
|
|
97
|
+
creator_agent_id,
|
|
98
|
+
community_role=CommunityRole.LEADER
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
logger.info(f"Created community: {name} ({community.community_id})")
|
|
102
|
+
return community.community_id
|
|
103
|
+
|
|
104
|
+
async def add_member_to_community(
|
|
105
|
+
self,
|
|
106
|
+
community_id: str,
|
|
107
|
+
agent_id: str,
|
|
108
|
+
agent_role: str = "general",
|
|
109
|
+
community_role: CommunityRole = CommunityRole.CONTRIBUTOR,
|
|
110
|
+
specializations: Optional[List[str]] = None
|
|
111
|
+
) -> str:
|
|
112
|
+
"""
|
|
113
|
+
Add a member to a community.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
community_id: ID of the community
|
|
117
|
+
agent_id: ID of the agent to add
|
|
118
|
+
agent_role: Functional role of the agent
|
|
119
|
+
community_role: Role within the community
|
|
120
|
+
specializations: Areas of specialization
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Member ID
|
|
124
|
+
"""
|
|
125
|
+
if community_id not in self.communities:
|
|
126
|
+
raise TaskValidationError(f"Community not found: {community_id}")
|
|
127
|
+
|
|
128
|
+
# Check if agent is already a member
|
|
129
|
+
existing_member = self._find_member_by_agent_id(community_id, agent_id)
|
|
130
|
+
if existing_member:
|
|
131
|
+
logger.warning(f"Agent {agent_id} is already a member of community {community_id}")
|
|
132
|
+
return existing_member.member_id
|
|
133
|
+
|
|
134
|
+
member = CommunityMember(
|
|
135
|
+
member_id=str(uuid.uuid4()),
|
|
136
|
+
agent_id=agent_id,
|
|
137
|
+
agent_role=agent_role,
|
|
138
|
+
community_role=community_role,
|
|
139
|
+
specializations=specializations or []
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
self.members[member.member_id] = member
|
|
143
|
+
|
|
144
|
+
# Update relationships
|
|
145
|
+
if agent_id not in self.member_communities:
|
|
146
|
+
self.member_communities[agent_id] = set()
|
|
147
|
+
self.member_communities[agent_id].add(community_id)
|
|
148
|
+
self.community_members[community_id].add(member.member_id)
|
|
149
|
+
|
|
150
|
+
# Update community
|
|
151
|
+
community = self.communities[community_id]
|
|
152
|
+
community.members.append(member.member_id)
|
|
153
|
+
|
|
154
|
+
if community_role == CommunityRole.LEADER:
|
|
155
|
+
community.leaders.append(member.member_id)
|
|
156
|
+
elif community_role == CommunityRole.COORDINATOR:
|
|
157
|
+
community.coordinators.append(member.member_id)
|
|
158
|
+
|
|
159
|
+
logger.info(f"Added member {agent_id} to community {community_id} as {community_role}")
|
|
160
|
+
return member.member_id
|
|
161
|
+
|
|
162
|
+
async def create_community_resource(
|
|
163
|
+
self,
|
|
164
|
+
community_id: str,
|
|
165
|
+
owner_member_id: str,
|
|
166
|
+
name: str,
|
|
167
|
+
resource_type: ResourceType,
|
|
168
|
+
content: Dict[str, Any],
|
|
169
|
+
description: Optional[str] = None,
|
|
170
|
+
access_level: str = "public",
|
|
171
|
+
tags: Optional[List[str]] = None
|
|
172
|
+
) -> str:
|
|
173
|
+
"""
|
|
174
|
+
Create a shared community resource.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
community_id: ID of the community
|
|
178
|
+
owner_member_id: ID of the member creating the resource
|
|
179
|
+
name: Name of the resource
|
|
180
|
+
resource_type: Type of resource
|
|
181
|
+
content: Resource content/data
|
|
182
|
+
description: Optional description
|
|
183
|
+
access_level: Access level (public, restricted, private)
|
|
184
|
+
tags: Tags for categorization
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Resource ID
|
|
188
|
+
"""
|
|
189
|
+
if community_id not in self.communities:
|
|
190
|
+
raise TaskValidationError(f"Community not found: {community_id}")
|
|
191
|
+
|
|
192
|
+
if owner_member_id not in self.members:
|
|
193
|
+
raise TaskValidationError(f"Member not found: {owner_member_id}")
|
|
194
|
+
|
|
195
|
+
resource = CommunityResource(
|
|
196
|
+
name=name,
|
|
197
|
+
resource_type=resource_type,
|
|
198
|
+
description=description,
|
|
199
|
+
owner_id=owner_member_id,
|
|
200
|
+
access_level=access_level,
|
|
201
|
+
content=content,
|
|
202
|
+
tags=tags or []
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
self.resources[resource.resource_id] = resource
|
|
206
|
+
|
|
207
|
+
# Update community
|
|
208
|
+
community = self.communities[community_id]
|
|
209
|
+
community.shared_resources.append(resource.resource_id)
|
|
210
|
+
community.resource_count += 1
|
|
211
|
+
|
|
212
|
+
logger.info(f"Created resource {name} in community {community_id}")
|
|
213
|
+
return resource.resource_id
|
|
214
|
+
|
|
215
|
+
async def propose_decision(
|
|
216
|
+
self,
|
|
217
|
+
community_id: str,
|
|
218
|
+
proposer_member_id: str,
|
|
219
|
+
title: str,
|
|
220
|
+
description: str,
|
|
221
|
+
decision_type: str,
|
|
222
|
+
implementation_plan: Optional[str] = None,
|
|
223
|
+
deadline: Optional[datetime] = None
|
|
224
|
+
) -> str:
|
|
225
|
+
"""
|
|
226
|
+
Propose a decision for community consideration.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
community_id: ID of the community
|
|
230
|
+
proposer_member_id: ID of the member proposing
|
|
231
|
+
title: Title of the proposal
|
|
232
|
+
description: Detailed description
|
|
233
|
+
decision_type: Type of decision
|
|
234
|
+
implementation_plan: Plan for implementation
|
|
235
|
+
deadline: Implementation deadline
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Decision ID
|
|
239
|
+
"""
|
|
240
|
+
if community_id not in self.communities:
|
|
241
|
+
raise TaskValidationError(f"Community not found: {community_id}")
|
|
242
|
+
|
|
243
|
+
if proposer_member_id not in self.members:
|
|
244
|
+
raise TaskValidationError(f"Member not found: {proposer_member_id}")
|
|
245
|
+
|
|
246
|
+
decision = CommunityDecision(
|
|
247
|
+
title=title,
|
|
248
|
+
description=description,
|
|
249
|
+
proposer_id=proposer_member_id,
|
|
250
|
+
decision_type=decision_type,
|
|
251
|
+
implementation_plan=implementation_plan,
|
|
252
|
+
deadline=deadline,
|
|
253
|
+
voting_ends_at=datetime.utcnow() + timedelta(days=3) # Default 3-day voting period
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
self.decisions[decision.decision_id] = decision
|
|
257
|
+
|
|
258
|
+
# Update community
|
|
259
|
+
community = self.communities[community_id]
|
|
260
|
+
community.decision_count += 1
|
|
261
|
+
|
|
262
|
+
logger.info(f"Proposed decision '{title}' in community {community_id}")
|
|
263
|
+
return decision.decision_id
|
|
264
|
+
|
|
265
|
+
async def vote_on_decision(
|
|
266
|
+
self,
|
|
267
|
+
decision_id: str,
|
|
268
|
+
member_id: str,
|
|
269
|
+
vote: str # "for", "against", "abstain"
|
|
270
|
+
) -> bool:
|
|
271
|
+
"""
|
|
272
|
+
Cast a vote on a community decision.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
decision_id: ID of the decision
|
|
276
|
+
member_id: ID of the voting member
|
|
277
|
+
vote: Vote choice ("for", "against", "abstain")
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
True if vote was cast successfully
|
|
281
|
+
"""
|
|
282
|
+
if decision_id not in self.decisions:
|
|
283
|
+
raise TaskValidationError(f"Decision not found: {decision_id}")
|
|
284
|
+
|
|
285
|
+
if member_id not in self.members:
|
|
286
|
+
raise TaskValidationError(f"Member not found: {member_id}")
|
|
287
|
+
|
|
288
|
+
decision = self.decisions[decision_id]
|
|
289
|
+
|
|
290
|
+
# Check if voting is still open
|
|
291
|
+
if decision.status != DecisionStatus.VOTING and decision.status != DecisionStatus.PROPOSED:
|
|
292
|
+
raise TaskValidationError(f"Voting is closed for decision {decision_id}")
|
|
293
|
+
|
|
294
|
+
if decision.voting_ends_at and datetime.utcnow() > decision.voting_ends_at:
|
|
295
|
+
raise TaskValidationError(f"Voting period has ended for decision {decision_id}")
|
|
296
|
+
|
|
297
|
+
# Remove previous vote if exists
|
|
298
|
+
if member_id in decision.votes_for:
|
|
299
|
+
decision.votes_for.remove(member_id)
|
|
300
|
+
if member_id in decision.votes_against:
|
|
301
|
+
decision.votes_against.remove(member_id)
|
|
302
|
+
if member_id in decision.abstentions:
|
|
303
|
+
decision.abstentions.remove(member_id)
|
|
304
|
+
|
|
305
|
+
# Cast new vote
|
|
306
|
+
if vote.lower() == "for":
|
|
307
|
+
decision.votes_for.append(member_id)
|
|
308
|
+
elif vote.lower() == "against":
|
|
309
|
+
decision.votes_against.append(member_id)
|
|
310
|
+
elif vote.lower() == "abstain":
|
|
311
|
+
decision.abstentions.append(member_id)
|
|
312
|
+
else:
|
|
313
|
+
raise TaskValidationError(f"Invalid vote choice: {vote}")
|
|
314
|
+
|
|
315
|
+
# Update decision status
|
|
316
|
+
if decision.status == DecisionStatus.PROPOSED:
|
|
317
|
+
decision.status = DecisionStatus.VOTING
|
|
318
|
+
|
|
319
|
+
logger.info(f"Member {member_id} voted '{vote}' on decision {decision_id}")
|
|
320
|
+
return True
|
|
321
|
+
|
|
322
|
+
def _find_member_by_agent_id(self, community_id: str, agent_id: str) -> Optional[CommunityMember]:
|
|
323
|
+
"""Find a community member by agent ID."""
|
|
324
|
+
if community_id not in self.community_members:
|
|
325
|
+
return None
|
|
326
|
+
|
|
327
|
+
for member_id in self.community_members[community_id]:
|
|
328
|
+
member = self.members.get(member_id)
|
|
329
|
+
if member and member.agent_id == agent_id:
|
|
330
|
+
return member
|
|
331
|
+
|
|
332
|
+
return None
|
|
333
|
+
|
|
334
|
+
async def _load_from_storage(self) -> None:
|
|
335
|
+
"""Load communities and members from persistent storage."""
|
|
336
|
+
# TODO: Implement loading from context_engine or database
|
|
337
|
+
pass
|
|
@@ -0,0 +1,354 @@
|
|
|
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
|
+
import asyncio
|
|
13
|
+
|
|
14
|
+
from .models.community_models import (
|
|
15
|
+
CommunityDecision, CommunityMember, AgentCommunity,
|
|
16
|
+
DecisionStatus, GovernanceType
|
|
17
|
+
)
|
|
18
|
+
from ..core.exceptions.task_exceptions import TaskValidationError
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ConsensusAlgorithm(str, Enum):
|
|
24
|
+
"""Types of consensus algorithms."""
|
|
25
|
+
SIMPLE_MAJORITY = "simple_majority"
|
|
26
|
+
SUPERMAJORITY = "supermajority"
|
|
27
|
+
UNANIMOUS = "unanimous"
|
|
28
|
+
WEIGHTED_VOTING = "weighted_voting"
|
|
29
|
+
DELEGATED_PROOF = "delegated_proof"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ConflictResolutionStrategy(str, Enum):
|
|
33
|
+
"""Strategies for resolving conflicts."""
|
|
34
|
+
MEDIATION = "mediation"
|
|
35
|
+
ARBITRATION = "arbitration"
|
|
36
|
+
COMPROMISE = "compromise"
|
|
37
|
+
ESCALATION = "escalation"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class DecisionEngine:
|
|
41
|
+
"""
|
|
42
|
+
Engine for collective decision-making in agent communities.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, community_manager=None):
|
|
46
|
+
"""
|
|
47
|
+
Initialize the decision engine.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
community_manager: Reference to the community manager
|
|
51
|
+
"""
|
|
52
|
+
self.community_manager = community_manager
|
|
53
|
+
|
|
54
|
+
# Decision algorithms configuration
|
|
55
|
+
self.consensus_algorithms = {
|
|
56
|
+
ConsensusAlgorithm.SIMPLE_MAJORITY: self._simple_majority_consensus,
|
|
57
|
+
ConsensusAlgorithm.SUPERMAJORITY: self._supermajority_consensus,
|
|
58
|
+
ConsensusAlgorithm.UNANIMOUS: self._unanimous_consensus,
|
|
59
|
+
ConsensusAlgorithm.WEIGHTED_VOTING: self._weighted_voting_consensus,
|
|
60
|
+
ConsensusAlgorithm.DELEGATED_PROOF: self._delegated_proof_consensus
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Conflict resolution strategies
|
|
64
|
+
self.conflict_resolvers = {
|
|
65
|
+
ConflictResolutionStrategy.MEDIATION: self._mediation_resolution,
|
|
66
|
+
ConflictResolutionStrategy.ARBITRATION: self._arbitration_resolution,
|
|
67
|
+
ConflictResolutionStrategy.COMPROMISE: self._compromise_resolution,
|
|
68
|
+
ConflictResolutionStrategy.ESCALATION: self._escalation_resolution
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
logger.info("Decision engine initialized")
|
|
72
|
+
|
|
73
|
+
async def evaluate_decision(
|
|
74
|
+
self,
|
|
75
|
+
decision_id: str,
|
|
76
|
+
community_id: str,
|
|
77
|
+
algorithm: ConsensusAlgorithm = ConsensusAlgorithm.SIMPLE_MAJORITY
|
|
78
|
+
) -> Tuple[bool, Dict[str, Any]]:
|
|
79
|
+
"""
|
|
80
|
+
Evaluate a community decision using the specified consensus algorithm.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
decision_id: ID of the decision to evaluate
|
|
84
|
+
community_id: ID of the community
|
|
85
|
+
algorithm: Consensus algorithm to use
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Tuple of (decision_passed, evaluation_details)
|
|
89
|
+
"""
|
|
90
|
+
if not self.community_manager:
|
|
91
|
+
raise TaskValidationError("Community manager not available")
|
|
92
|
+
|
|
93
|
+
decision = self.community_manager.decisions.get(decision_id)
|
|
94
|
+
if not decision:
|
|
95
|
+
raise TaskValidationError(f"Decision not found: {decision_id}")
|
|
96
|
+
|
|
97
|
+
community = self.community_manager.communities.get(community_id)
|
|
98
|
+
if not community:
|
|
99
|
+
raise TaskValidationError(f"Community not found: {community_id}")
|
|
100
|
+
|
|
101
|
+
# Get consensus algorithm function
|
|
102
|
+
consensus_func = self.consensus_algorithms.get(algorithm)
|
|
103
|
+
if not consensus_func:
|
|
104
|
+
raise TaskValidationError(f"Unknown consensus algorithm: {algorithm}")
|
|
105
|
+
|
|
106
|
+
# Evaluate decision
|
|
107
|
+
result, details = await consensus_func(decision, community)
|
|
108
|
+
|
|
109
|
+
# Update decision status based on result
|
|
110
|
+
if result:
|
|
111
|
+
decision.status = DecisionStatus.APPROVED
|
|
112
|
+
logger.info(f"Decision {decision_id} approved by {algorithm}")
|
|
113
|
+
else:
|
|
114
|
+
decision.status = DecisionStatus.REJECTED
|
|
115
|
+
logger.info(f"Decision {decision_id} rejected by {algorithm}")
|
|
116
|
+
|
|
117
|
+
return result, details
|
|
118
|
+
|
|
119
|
+
async def _simple_majority_consensus(
|
|
120
|
+
self,
|
|
121
|
+
decision: CommunityDecision,
|
|
122
|
+
community: AgentCommunity
|
|
123
|
+
) -> Tuple[bool, Dict[str, Any]]:
|
|
124
|
+
"""Simple majority voting (>50%)."""
|
|
125
|
+
total_votes = len(decision.votes_for) + len(decision.votes_against)
|
|
126
|
+
votes_for = len(decision.votes_for)
|
|
127
|
+
votes_against = len(decision.votes_against)
|
|
128
|
+
|
|
129
|
+
if total_votes == 0:
|
|
130
|
+
return False, {"reason": "No votes cast", "votes_for": 0, "votes_against": 0}
|
|
131
|
+
|
|
132
|
+
majority_threshold = total_votes / 2
|
|
133
|
+
passed = votes_for > majority_threshold
|
|
134
|
+
|
|
135
|
+
details = {
|
|
136
|
+
"algorithm": "simple_majority",
|
|
137
|
+
"votes_for": votes_for,
|
|
138
|
+
"votes_against": votes_against,
|
|
139
|
+
"abstentions": len(decision.abstentions),
|
|
140
|
+
"total_votes": total_votes,
|
|
141
|
+
"threshold": majority_threshold,
|
|
142
|
+
"passed": passed
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return passed, details
|
|
146
|
+
|
|
147
|
+
async def _supermajority_consensus(
|
|
148
|
+
self,
|
|
149
|
+
decision: CommunityDecision,
|
|
150
|
+
community: AgentCommunity,
|
|
151
|
+
threshold: float = 0.67
|
|
152
|
+
) -> Tuple[bool, Dict[str, Any]]:
|
|
153
|
+
"""Supermajority voting (default 67%)."""
|
|
154
|
+
total_votes = len(decision.votes_for) + len(decision.votes_against)
|
|
155
|
+
votes_for = len(decision.votes_for)
|
|
156
|
+
|
|
157
|
+
if total_votes == 0:
|
|
158
|
+
return False, {"reason": "No votes cast", "threshold": threshold}
|
|
159
|
+
|
|
160
|
+
support_ratio = votes_for / total_votes
|
|
161
|
+
passed = support_ratio >= threshold
|
|
162
|
+
|
|
163
|
+
details = {
|
|
164
|
+
"algorithm": "supermajority",
|
|
165
|
+
"votes_for": votes_for,
|
|
166
|
+
"votes_against": len(decision.votes_against),
|
|
167
|
+
"abstentions": len(decision.abstentions),
|
|
168
|
+
"total_votes": total_votes,
|
|
169
|
+
"support_ratio": support_ratio,
|
|
170
|
+
"threshold": threshold,
|
|
171
|
+
"passed": passed
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return passed, details
|
|
175
|
+
|
|
176
|
+
async def _unanimous_consensus(
|
|
177
|
+
self,
|
|
178
|
+
decision: CommunityDecision,
|
|
179
|
+
community: AgentCommunity
|
|
180
|
+
) -> Tuple[bool, Dict[str, Any]]:
|
|
181
|
+
"""Unanimous consensus (all votes must be 'for')."""
|
|
182
|
+
votes_for = len(decision.votes_for)
|
|
183
|
+
votes_against = len(decision.votes_against)
|
|
184
|
+
total_members = len(community.members)
|
|
185
|
+
|
|
186
|
+
# For unanimous consensus, we need all active members to vote 'for'
|
|
187
|
+
# and no votes 'against'
|
|
188
|
+
passed = votes_against == 0 and votes_for > 0
|
|
189
|
+
|
|
190
|
+
details = {
|
|
191
|
+
"algorithm": "unanimous",
|
|
192
|
+
"votes_for": votes_for,
|
|
193
|
+
"votes_against": votes_against,
|
|
194
|
+
"abstentions": len(decision.abstentions),
|
|
195
|
+
"total_members": total_members,
|
|
196
|
+
"passed": passed
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return passed, details
|
|
200
|
+
|
|
201
|
+
async def _weighted_voting_consensus(
|
|
202
|
+
self,
|
|
203
|
+
decision: CommunityDecision,
|
|
204
|
+
community: AgentCommunity
|
|
205
|
+
) -> Tuple[bool, Dict[str, Any]]:
|
|
206
|
+
"""Weighted voting based on member reputation and contribution."""
|
|
207
|
+
if not self.community_manager:
|
|
208
|
+
return False, {"reason": "Community manager not available"}
|
|
209
|
+
|
|
210
|
+
weighted_for = 0.0
|
|
211
|
+
weighted_against = 0.0
|
|
212
|
+
total_weight = 0.0
|
|
213
|
+
|
|
214
|
+
# Calculate weights for all votes
|
|
215
|
+
for member_id in decision.votes_for:
|
|
216
|
+
member = self.community_manager.members.get(member_id)
|
|
217
|
+
if member:
|
|
218
|
+
weight = self._calculate_member_weight(member)
|
|
219
|
+
weighted_for += weight
|
|
220
|
+
total_weight += weight
|
|
221
|
+
|
|
222
|
+
for member_id in decision.votes_against:
|
|
223
|
+
member = self.community_manager.members.get(member_id)
|
|
224
|
+
if member:
|
|
225
|
+
weight = self._calculate_member_weight(member)
|
|
226
|
+
weighted_against += weight
|
|
227
|
+
total_weight += weight
|
|
228
|
+
|
|
229
|
+
if total_weight == 0:
|
|
230
|
+
return False, {"reason": "No weighted votes", "total_weight": 0}
|
|
231
|
+
|
|
232
|
+
support_ratio = weighted_for / total_weight
|
|
233
|
+
passed = support_ratio > 0.5 # Weighted majority
|
|
234
|
+
|
|
235
|
+
details = {
|
|
236
|
+
"algorithm": "weighted_voting",
|
|
237
|
+
"weighted_for": weighted_for,
|
|
238
|
+
"weighted_against": weighted_against,
|
|
239
|
+
"total_weight": total_weight,
|
|
240
|
+
"support_ratio": support_ratio,
|
|
241
|
+
"passed": passed
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return passed, details
|
|
245
|
+
|
|
246
|
+
async def _delegated_proof_consensus(
|
|
247
|
+
self,
|
|
248
|
+
decision: CommunityDecision,
|
|
249
|
+
community: AgentCommunity
|
|
250
|
+
) -> Tuple[bool, Dict[str, Any]]:
|
|
251
|
+
"""Delegated proof consensus (leaders and coordinators have more weight)."""
|
|
252
|
+
if not self.community_manager:
|
|
253
|
+
return False, {"reason": "Community manager not available"}
|
|
254
|
+
|
|
255
|
+
leader_votes_for = 0
|
|
256
|
+
leader_votes_against = 0
|
|
257
|
+
coordinator_votes_for = 0
|
|
258
|
+
coordinator_votes_against = 0
|
|
259
|
+
regular_votes_for = 0
|
|
260
|
+
regular_votes_against = 0
|
|
261
|
+
|
|
262
|
+
# Count votes by role
|
|
263
|
+
for member_id in decision.votes_for:
|
|
264
|
+
member = self.community_manager.members.get(member_id)
|
|
265
|
+
if member:
|
|
266
|
+
if member_id in community.leaders:
|
|
267
|
+
leader_votes_for += 1
|
|
268
|
+
elif member_id in community.coordinators:
|
|
269
|
+
coordinator_votes_for += 1
|
|
270
|
+
else:
|
|
271
|
+
regular_votes_for += 1
|
|
272
|
+
|
|
273
|
+
for member_id in decision.votes_against:
|
|
274
|
+
member = self.community_manager.members.get(member_id)
|
|
275
|
+
if member:
|
|
276
|
+
if member_id in community.leaders:
|
|
277
|
+
leader_votes_against += 1
|
|
278
|
+
elif member_id in community.coordinators:
|
|
279
|
+
coordinator_votes_against += 1
|
|
280
|
+
else:
|
|
281
|
+
regular_votes_against += 1
|
|
282
|
+
|
|
283
|
+
# Calculate weighted score (leaders: 3x, coordinators: 2x, regular: 1x)
|
|
284
|
+
score_for = (leader_votes_for * 3) + (coordinator_votes_for * 2) + regular_votes_for
|
|
285
|
+
score_against = (leader_votes_against * 3) + (coordinator_votes_against * 2) + regular_votes_against
|
|
286
|
+
|
|
287
|
+
total_score = score_for + score_against
|
|
288
|
+
passed = total_score > 0 and score_for > score_against
|
|
289
|
+
|
|
290
|
+
details = {
|
|
291
|
+
"algorithm": "delegated_proof",
|
|
292
|
+
"leader_votes_for": leader_votes_for,
|
|
293
|
+
"leader_votes_against": leader_votes_against,
|
|
294
|
+
"coordinator_votes_for": coordinator_votes_for,
|
|
295
|
+
"coordinator_votes_against": coordinator_votes_against,
|
|
296
|
+
"regular_votes_for": regular_votes_for,
|
|
297
|
+
"regular_votes_against": regular_votes_against,
|
|
298
|
+
"score_for": score_for,
|
|
299
|
+
"score_against": score_against,
|
|
300
|
+
"passed": passed
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return passed, details
|
|
304
|
+
|
|
305
|
+
def _calculate_member_weight(self, member: CommunityMember) -> float:
|
|
306
|
+
"""Calculate voting weight for a member based on reputation and contribution."""
|
|
307
|
+
base_weight = 1.0
|
|
308
|
+
reputation_bonus = member.reputation * 0.5 # Up to 50% bonus for reputation
|
|
309
|
+
contribution_bonus = member.contribution_score * 0.3 # Up to 30% bonus for contribution
|
|
310
|
+
|
|
311
|
+
return base_weight + reputation_bonus + contribution_bonus
|
|
312
|
+
|
|
313
|
+
async def resolve_conflict(
|
|
314
|
+
self,
|
|
315
|
+
decision_id: str,
|
|
316
|
+
community_id: str,
|
|
317
|
+
strategy: ConflictResolutionStrategy = ConflictResolutionStrategy.MEDIATION
|
|
318
|
+
) -> Dict[str, Any]:
|
|
319
|
+
"""
|
|
320
|
+
Resolve conflicts in community decisions.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
decision_id: ID of the decision with conflict
|
|
324
|
+
community_id: ID of the community
|
|
325
|
+
strategy: Conflict resolution strategy
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
Resolution details
|
|
329
|
+
"""
|
|
330
|
+
resolver_func = self.conflict_resolvers.get(strategy)
|
|
331
|
+
if not resolver_func:
|
|
332
|
+
raise TaskValidationError(f"Unknown conflict resolution strategy: {strategy}")
|
|
333
|
+
|
|
334
|
+
return await resolver_func(decision_id, community_id)
|
|
335
|
+
|
|
336
|
+
async def _mediation_resolution(self, decision_id: str, community_id: str) -> Dict[str, Any]:
|
|
337
|
+
"""Mediation-based conflict resolution."""
|
|
338
|
+
# TODO: Implement mediation logic
|
|
339
|
+
return {"strategy": "mediation", "status": "pending", "mediator": None}
|
|
340
|
+
|
|
341
|
+
async def _arbitration_resolution(self, decision_id: str, community_id: str) -> Dict[str, Any]:
|
|
342
|
+
"""Arbitration-based conflict resolution."""
|
|
343
|
+
# TODO: Implement arbitration logic
|
|
344
|
+
return {"strategy": "arbitration", "status": "pending", "arbitrator": None}
|
|
345
|
+
|
|
346
|
+
async def _compromise_resolution(self, decision_id: str, community_id: str) -> Dict[str, Any]:
|
|
347
|
+
"""Compromise-based conflict resolution."""
|
|
348
|
+
# TODO: Implement compromise logic
|
|
349
|
+
return {"strategy": "compromise", "status": "pending", "compromise_proposal": None}
|
|
350
|
+
|
|
351
|
+
async def _escalation_resolution(self, decision_id: str, community_id: str) -> Dict[str, Any]:
|
|
352
|
+
"""Escalation-based conflict resolution."""
|
|
353
|
+
# TODO: Implement escalation logic
|
|
354
|
+
return {"strategy": "escalation", "status": "pending", "escalation_level": 1}
|