aiecs 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (58) hide show
  1. aiecs/__init__.py +1 -1
  2. aiecs/config/config.py +2 -0
  3. aiecs/domain/__init__.py +95 -0
  4. aiecs/domain/community/__init__.py +159 -0
  5. aiecs/domain/community/agent_adapter.py +516 -0
  6. aiecs/domain/community/analytics.py +465 -0
  7. aiecs/domain/community/collaborative_workflow.py +99 -7
  8. aiecs/domain/community/communication_hub.py +649 -0
  9. aiecs/domain/community/community_builder.py +322 -0
  10. aiecs/domain/community/community_integration.py +365 -12
  11. aiecs/domain/community/community_manager.py +481 -5
  12. aiecs/domain/community/decision_engine.py +459 -13
  13. aiecs/domain/community/exceptions.py +238 -0
  14. aiecs/domain/community/models/__init__.py +36 -0
  15. aiecs/domain/community/resource_manager.py +1 -1
  16. aiecs/domain/community/shared_context_manager.py +621 -0
  17. aiecs/domain/context/context_engine.py +37 -33
  18. aiecs/main.py +2 -2
  19. aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
  20. aiecs/scripts/aid/__init__.py +15 -0
  21. aiecs/scripts/aid/version_manager.py +224 -0
  22. aiecs/scripts/dependance_check/download_nlp_data.py +1 -0
  23. aiecs/tools/__init__.py +23 -23
  24. aiecs/tools/docs/__init__.py +5 -2
  25. aiecs/tools/docs/ai_document_orchestrator.py +39 -26
  26. aiecs/tools/docs/ai_document_writer_orchestrator.py +61 -38
  27. aiecs/tools/docs/content_insertion_tool.py +48 -28
  28. aiecs/tools/docs/document_creator_tool.py +47 -29
  29. aiecs/tools/docs/document_layout_tool.py +35 -20
  30. aiecs/tools/docs/document_parser_tool.py +56 -36
  31. aiecs/tools/docs/document_writer_tool.py +115 -62
  32. aiecs/tools/schema_generator.py +56 -56
  33. aiecs/tools/statistics/__init__.py +82 -0
  34. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +581 -0
  35. aiecs/tools/statistics/ai_insight_generator_tool.py +473 -0
  36. aiecs/tools/statistics/ai_report_orchestrator_tool.py +629 -0
  37. aiecs/tools/statistics/data_loader_tool.py +518 -0
  38. aiecs/tools/statistics/data_profiler_tool.py +599 -0
  39. aiecs/tools/statistics/data_transformer_tool.py +531 -0
  40. aiecs/tools/statistics/data_visualizer_tool.py +460 -0
  41. aiecs/tools/statistics/model_trainer_tool.py +470 -0
  42. aiecs/tools/statistics/statistical_analyzer_tool.py +426 -0
  43. aiecs/tools/task_tools/chart_tool.py +2 -1
  44. aiecs/tools/task_tools/image_tool.py +43 -43
  45. aiecs/tools/task_tools/office_tool.py +39 -36
  46. aiecs/tools/task_tools/pandas_tool.py +37 -33
  47. aiecs/tools/task_tools/report_tool.py +67 -56
  48. aiecs/tools/task_tools/research_tool.py +32 -31
  49. aiecs/tools/task_tools/scraper_tool.py +53 -46
  50. aiecs/tools/task_tools/search_tool.py +1123 -0
  51. aiecs/tools/task_tools/stats_tool.py +20 -15
  52. {aiecs-1.1.0.dist-info → aiecs-1.2.0.dist-info}/METADATA +5 -1
  53. {aiecs-1.1.0.dist-info → aiecs-1.2.0.dist-info}/RECORD +57 -36
  54. {aiecs-1.1.0.dist-info → aiecs-1.2.0.dist-info}/entry_points.txt +1 -0
  55. aiecs/tools/task_tools/search_api.py +0 -7
  56. {aiecs-1.1.0.dist-info → aiecs-1.2.0.dist-info}/WHEEL +0 -0
  57. {aiecs-1.1.0.dist-info → aiecs-1.2.0.dist-info}/licenses/LICENSE +0 -0
  58. {aiecs-1.1.0.dist-info → aiecs-1.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,465 @@
1
+ """
2
+ Community Analytics
3
+
4
+ Tracks decision patterns, member participation, community health metrics,
5
+ and collaboration effectiveness.
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime, timedelta
10
+ from typing import Dict, List, Any, Optional
11
+ from collections import defaultdict
12
+
13
+ from .models.community_models import (
14
+ AgentCommunity, CommunityMember, CommunityDecision, DecisionStatus
15
+ )
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class CommunityAnalytics:
21
+ """
22
+ Analytics engine for tracking community health and effectiveness.
23
+ """
24
+
25
+ def __init__(self, community_manager=None):
26
+ """
27
+ Initialize community analytics.
28
+
29
+ Args:
30
+ community_manager: Reference to the community manager
31
+ """
32
+ self.community_manager = community_manager
33
+
34
+ # Analytics caches
35
+ self._decision_patterns_cache: Dict[str, Any] = {}
36
+ self._participation_cache: Dict[str, Any] = {}
37
+ self._health_metrics_cache: Dict[str, Any] = {}
38
+
39
+ logger.info("Community analytics initialized")
40
+
41
+ def get_decision_analytics(
42
+ self,
43
+ community_id: str,
44
+ time_range_days: int = 30
45
+ ) -> Dict[str, Any]:
46
+ """
47
+ Get decision analytics for a community.
48
+
49
+ Args:
50
+ community_id: ID of the community
51
+ time_range_days: Time range for analytics in days
52
+
53
+ Returns:
54
+ Decision analytics data
55
+ """
56
+ if not self.community_manager:
57
+ return {}
58
+
59
+ community = self.community_manager.communities.get(community_id)
60
+ if not community:
61
+ return {}
62
+
63
+ cutoff_date = datetime.utcnow() - timedelta(days=time_range_days)
64
+
65
+ # Collect decisions within time range
66
+ decisions = []
67
+ for decision in self.community_manager.decisions.values():
68
+ if decision.created_at >= cutoff_date:
69
+ # Check if decision belongs to this community
70
+ if decision.proposer_id in community.members:
71
+ decisions.append(decision)
72
+
73
+ # Calculate decision metrics
74
+ total_decisions = len(decisions)
75
+ approved = sum(1 for d in decisions if d.status == DecisionStatus.APPROVED)
76
+ rejected = sum(1 for d in decisions if d.status == DecisionStatus.REJECTED)
77
+ pending = sum(1 for d in decisions if d.status in [DecisionStatus.PROPOSED, DecisionStatus.VOTING])
78
+
79
+ # Calculate average time to decision
80
+ decision_times = []
81
+ for decision in decisions:
82
+ if decision.status in [DecisionStatus.APPROVED, DecisionStatus.REJECTED]:
83
+ if decision.implemented_at or decision.created_at:
84
+ end_time = decision.implemented_at or datetime.utcnow()
85
+ duration = (end_time - decision.created_at).total_seconds() / 3600 # hours
86
+ decision_times.append(duration)
87
+
88
+ avg_decision_time = sum(decision_times) / len(decision_times) if decision_times else 0
89
+
90
+ # Decision types distribution
91
+ decision_types = defaultdict(int)
92
+ for decision in decisions:
93
+ decision_types[decision.decision_type] += 1
94
+
95
+ # Approval rate by type
96
+ approval_by_type = {}
97
+ for dtype in decision_types.keys():
98
+ type_decisions = [d for d in decisions if d.decision_type == dtype]
99
+ type_approved = sum(1 for d in type_decisions if d.status == DecisionStatus.APPROVED)
100
+ approval_by_type[dtype] = type_approved / len(type_decisions) if type_decisions else 0
101
+
102
+ analytics = {
103
+ "community_id": community_id,
104
+ "time_range_days": time_range_days,
105
+ "total_decisions": total_decisions,
106
+ "approved": approved,
107
+ "rejected": rejected,
108
+ "pending": pending,
109
+ "approval_rate": approved / total_decisions if total_decisions > 0 else 0,
110
+ "rejection_rate": rejected / total_decisions if total_decisions > 0 else 0,
111
+ "average_decision_time_hours": avg_decision_time,
112
+ "decision_types": dict(decision_types),
113
+ "approval_rate_by_type": approval_by_type,
114
+ "decision_velocity": total_decisions / time_range_days if time_range_days > 0 else 0
115
+ }
116
+
117
+ return analytics
118
+
119
+ def get_member_participation_analytics(
120
+ self,
121
+ community_id: str,
122
+ time_range_days: int = 30
123
+ ) -> Dict[str, Any]:
124
+ """
125
+ Get member participation analytics.
126
+
127
+ Args:
128
+ community_id: ID of the community
129
+ time_range_days: Time range for analytics in days
130
+
131
+ Returns:
132
+ Participation analytics data
133
+ """
134
+ if not self.community_manager:
135
+ return {}
136
+
137
+ community = self.community_manager.communities.get(community_id)
138
+ if not community:
139
+ return {}
140
+
141
+ cutoff_date = datetime.utcnow() - timedelta(days=time_range_days)
142
+
143
+ # Member participation metrics
144
+ member_metrics = {}
145
+ for member_id in community.members:
146
+ member = self.community_manager.members.get(member_id)
147
+ if not member:
148
+ continue
149
+
150
+ # Count votes
151
+ votes_cast = 0
152
+ proposals_made = 0
153
+
154
+ for decision in self.community_manager.decisions.values():
155
+ if decision.created_at >= cutoff_date:
156
+ if member_id in decision.votes_for or member_id in decision.votes_against or member_id in decision.abstentions:
157
+ votes_cast += 1
158
+ if decision.proposer_id == member_id:
159
+ proposals_made += 1
160
+
161
+ # Count resources contributed
162
+ resources_created = sum(
163
+ 1 for resource in self.community_manager.resources.values()
164
+ if resource.owner_id == member_id and resource.created_at >= cutoff_date
165
+ )
166
+
167
+ member_metrics[member_id] = {
168
+ "agent_id": member.agent_id,
169
+ "community_role": member.community_role.value,
170
+ "votes_cast": votes_cast,
171
+ "proposals_made": proposals_made,
172
+ "resources_created": resources_created,
173
+ "contribution_score": member.contribution_score,
174
+ "reputation": member.reputation,
175
+ "is_active": member.is_active,
176
+ "participation_level": member.participation_level
177
+ }
178
+
179
+ # Calculate aggregate metrics
180
+ total_members = len(member_metrics)
181
+ active_members = sum(1 for m in member_metrics.values() if m["is_active"])
182
+ total_votes = sum(m["votes_cast"] for m in member_metrics.values())
183
+ total_proposals = sum(m["proposals_made"] for m in member_metrics.values())
184
+ total_resources = sum(m["resources_created"] for m in member_metrics.values())
185
+
186
+ # Identify top contributors
187
+ top_voters = sorted(
188
+ member_metrics.items(),
189
+ key=lambda x: x[1]["votes_cast"],
190
+ reverse=True
191
+ )[:5]
192
+
193
+ top_proposers = sorted(
194
+ member_metrics.items(),
195
+ key=lambda x: x[1]["proposals_made"],
196
+ reverse=True
197
+ )[:5]
198
+
199
+ top_contributors = sorted(
200
+ member_metrics.items(),
201
+ key=lambda x: x[1]["contribution_score"],
202
+ reverse=True
203
+ )[:5]
204
+
205
+ analytics = {
206
+ "community_id": community_id,
207
+ "time_range_days": time_range_days,
208
+ "total_members": total_members,
209
+ "active_members": active_members,
210
+ "activity_rate": active_members / total_members if total_members > 0 else 0,
211
+ "total_votes_cast": total_votes,
212
+ "total_proposals_made": total_proposals,
213
+ "total_resources_created": total_resources,
214
+ "average_votes_per_member": total_votes / total_members if total_members > 0 else 0,
215
+ "average_proposals_per_member": total_proposals / total_members if total_members > 0 else 0,
216
+ "member_metrics": member_metrics,
217
+ "top_voters": [{"member_id": mid, **metrics} for mid, metrics in top_voters],
218
+ "top_proposers": [{"member_id": mid, **metrics} for mid, metrics in top_proposers],
219
+ "top_contributors": [{"member_id": mid, **metrics} for mid, metrics in top_contributors]
220
+ }
221
+
222
+ return analytics
223
+
224
+ def get_community_health_metrics(
225
+ self,
226
+ community_id: str
227
+ ) -> Dict[str, Any]:
228
+ """
229
+ Get comprehensive community health metrics.
230
+
231
+ Args:
232
+ community_id: ID of the community
233
+
234
+ Returns:
235
+ Health metrics data
236
+ """
237
+ if not self.community_manager:
238
+ return {}
239
+
240
+ community = self.community_manager.communities.get(community_id)
241
+ if not community:
242
+ return {}
243
+
244
+ # Member health
245
+ total_members = len(community.members)
246
+ active_members = sum(
247
+ 1 for mid in community.members
248
+ if self.community_manager.members.get(mid) and self.community_manager.members[mid].is_active
249
+ )
250
+
251
+ # Leadership health
252
+ has_leaders = len(community.leaders) > 0
253
+ has_coordinators = len(community.coordinators) > 0
254
+ leadership_ratio = (len(community.leaders) + len(community.coordinators)) / total_members if total_members > 0 else 0
255
+
256
+ # Activity health
257
+ recent_activity_days = 7
258
+ recent_cutoff = datetime.utcnow() - timedelta(days=recent_activity_days)
259
+
260
+ recent_decisions = sum(
261
+ 1 for d in self.community_manager.decisions.values()
262
+ if d.created_at >= recent_cutoff and d.proposer_id in community.members
263
+ )
264
+
265
+ recent_resources = sum(
266
+ 1 for rid in community.shared_resources
267
+ if self.community_manager.resources.get(rid) and
268
+ self.community_manager.resources[rid].created_at >= recent_cutoff
269
+ )
270
+
271
+ # Diversity metrics
272
+ role_distribution = defaultdict(int)
273
+ for member_id in community.members:
274
+ member = self.community_manager.members.get(member_id)
275
+ if member:
276
+ role_distribution[member.community_role.value] += 1
277
+
278
+ role_diversity = len(role_distribution) / 5 # Max 5 role types
279
+
280
+ # Collaboration score (from community model)
281
+ collaboration_score = community.collaboration_score
282
+
283
+ # Calculate overall health score (0-100)
284
+ health_components = {
285
+ "member_activity": (active_members / total_members * 100) if total_members > 0 else 0,
286
+ "leadership": (100 if has_leaders and has_coordinators else 50 if has_leaders or has_coordinators else 0),
287
+ "recent_activity": min((recent_decisions + recent_resources) * 10, 100),
288
+ "role_diversity": role_diversity * 100,
289
+ "collaboration": collaboration_score * 100
290
+ }
291
+
292
+ overall_health = sum(health_components.values()) / len(health_components)
293
+
294
+ # Determine health status
295
+ if overall_health >= 80:
296
+ health_status = "excellent"
297
+ elif overall_health >= 60:
298
+ health_status = "good"
299
+ elif overall_health >= 40:
300
+ health_status = "fair"
301
+ elif overall_health >= 20:
302
+ health_status = "poor"
303
+ else:
304
+ health_status = "critical"
305
+
306
+ # Recommendations
307
+ recommendations = []
308
+ if total_members == 0:
309
+ recommendations.append("Add members to the community to begin collaboration")
310
+ elif active_members / total_members < 0.5:
311
+ recommendations.append("Increase member engagement through targeted activities")
312
+ if not has_leaders:
313
+ recommendations.append("Assign community leaders for better coordination")
314
+ if recent_decisions + recent_resources < 3:
315
+ recommendations.append("Encourage more community activity and collaboration")
316
+ if role_diversity < 0.6:
317
+ recommendations.append("Improve role diversity by adding members with different roles")
318
+
319
+ metrics = {
320
+ "community_id": community_id,
321
+ "community_name": community.name,
322
+ "overall_health_score": round(overall_health, 2),
323
+ "health_status": health_status,
324
+ "health_components": health_components,
325
+ "member_statistics": {
326
+ "total": total_members,
327
+ "active": active_members,
328
+ "inactive": total_members - active_members,
329
+ "leaders": len(community.leaders),
330
+ "coordinators": len(community.coordinators)
331
+ },
332
+ "activity_statistics": {
333
+ "recent_decisions": recent_decisions,
334
+ "recent_resources": recent_resources,
335
+ "total_decisions": community.decision_count,
336
+ "total_resources": community.resource_count
337
+ },
338
+ "diversity_metrics": {
339
+ "role_distribution": dict(role_distribution),
340
+ "role_diversity_score": round(role_diversity, 2)
341
+ },
342
+ "collaboration_score": collaboration_score,
343
+ "recommendations": recommendations,
344
+ "timestamp": datetime.utcnow().isoformat()
345
+ }
346
+
347
+ return metrics
348
+
349
+ def get_collaboration_effectiveness(
350
+ self,
351
+ community_id: str,
352
+ time_range_days: int = 30
353
+ ) -> Dict[str, Any]:
354
+ """
355
+ Get collaboration effectiveness metrics.
356
+
357
+ Args:
358
+ community_id: ID of the community
359
+ time_range_days: Time range for analytics in days
360
+
361
+ Returns:
362
+ Collaboration effectiveness data
363
+ """
364
+ if not self.community_manager:
365
+ return {}
366
+
367
+ # Get decision and participation analytics
368
+ decision_analytics = self.get_decision_analytics(community_id, time_range_days)
369
+ participation_analytics = self.get_member_participation_analytics(community_id, time_range_days)
370
+
371
+ # Calculate effectiveness metrics
372
+ decision_efficiency = decision_analytics.get("decision_velocity", 0) * 10
373
+ approval_effectiveness = decision_analytics.get("approval_rate", 0) * 100
374
+ participation_rate = participation_analytics.get("activity_rate", 0) * 100
375
+
376
+ # Combined effectiveness score
377
+ effectiveness_score = (
378
+ decision_efficiency * 0.3 +
379
+ approval_effectiveness * 0.4 +
380
+ participation_rate * 0.3
381
+ )
382
+
383
+ # Determine effectiveness level
384
+ if effectiveness_score >= 80:
385
+ effectiveness_level = "highly_effective"
386
+ elif effectiveness_score >= 60:
387
+ effectiveness_level = "effective"
388
+ elif effectiveness_score >= 40:
389
+ effectiveness_level = "moderately_effective"
390
+ else:
391
+ effectiveness_level = "needs_improvement"
392
+
393
+ # Identify strengths and weaknesses
394
+ strengths = []
395
+ weaknesses = []
396
+
397
+ if decision_efficiency >= 8:
398
+ strengths.append("High decision velocity")
399
+ else:
400
+ weaknesses.append("Low decision-making speed")
401
+
402
+ if approval_effectiveness >= 70:
403
+ strengths.append("High approval rate")
404
+ else:
405
+ weaknesses.append("Low approval rate - may indicate alignment issues")
406
+
407
+ if participation_rate >= 70:
408
+ strengths.append("Strong member participation")
409
+ else:
410
+ weaknesses.append("Low member participation")
411
+
412
+ metrics = {
413
+ "community_id": community_id,
414
+ "time_range_days": time_range_days,
415
+ "effectiveness_score": round(effectiveness_score, 2),
416
+ "effectiveness_level": effectiveness_level,
417
+ "component_scores": {
418
+ "decision_efficiency": round(decision_efficiency, 2),
419
+ "approval_effectiveness": round(approval_effectiveness, 2),
420
+ "participation_rate": round(participation_rate, 2)
421
+ },
422
+ "strengths": strengths,
423
+ "weaknesses": weaknesses,
424
+ "decision_summary": {
425
+ "velocity": decision_analytics.get("decision_velocity", 0),
426
+ "approval_rate": decision_analytics.get("approval_rate", 0),
427
+ "avg_time_hours": decision_analytics.get("average_decision_time_hours", 0)
428
+ },
429
+ "participation_summary": {
430
+ "active_members": participation_analytics.get("active_members", 0),
431
+ "total_members": participation_analytics.get("total_members", 0),
432
+ "avg_votes_per_member": participation_analytics.get("average_votes_per_member", 0)
433
+ },
434
+ "timestamp": datetime.utcnow().isoformat()
435
+ }
436
+
437
+ return metrics
438
+
439
+ def get_comprehensive_report(
440
+ self,
441
+ community_id: str,
442
+ time_range_days: int = 30
443
+ ) -> Dict[str, Any]:
444
+ """
445
+ Get comprehensive analytics report for a community.
446
+
447
+ Args:
448
+ community_id: ID of the community
449
+ time_range_days: Time range for analytics in days
450
+
451
+ Returns:
452
+ Comprehensive analytics report
453
+ """
454
+ report = {
455
+ "community_id": community_id,
456
+ "report_date": datetime.utcnow().isoformat(),
457
+ "time_range_days": time_range_days,
458
+ "decision_analytics": self.get_decision_analytics(community_id, time_range_days),
459
+ "participation_analytics": self.get_member_participation_analytics(community_id, time_range_days),
460
+ "health_metrics": self.get_community_health_metrics(community_id),
461
+ "collaboration_effectiveness": self.get_collaboration_effectiveness(community_id, time_range_days)
462
+ }
463
+
464
+ return report
465
+
@@ -12,7 +12,7 @@ import uuid
12
12
  import asyncio
13
13
 
14
14
  from .models.community_models import CollaborationSession
15
- from ..core.exceptions.task_exceptions import TaskValidationError
15
+ from .exceptions import CommunityValidationError as TaskValidationError
16
16
 
17
17
  logger = logging.getLogger(__name__)
18
18
 
@@ -317,18 +317,110 @@ class CollaborativeWorkflowEngine:
317
317
  })
318
318
 
319
319
  async def _peer_review_workflow(self, session: CollaborationSession) -> None:
320
- """Execute peer review workflow."""
320
+ """
321
+ Execute peer review workflow.
322
+
323
+ Phases:
324
+ 1. Reviewer assignment
325
+ 2. Individual review
326
+ 3. Review collection and synthesis
327
+ 4. Feedback integration
328
+ 5. Final approval
329
+ """
321
330
  logger.info(f"Starting peer review workflow for session {session.session_id}")
322
331
 
323
- # Implementation for peer review workflow
324
- pass
332
+ # Phase 1: Reviewer Assignment
333
+ await self._execute_phase(session, "reviewer_assignment", {
334
+ "instructions": "Assign reviewers based on expertise and availability",
335
+ "time_limit_minutes": 5,
336
+ "min_reviewers": 2,
337
+ "max_reviewers": 5
338
+ })
339
+
340
+ # Phase 2: Individual Review
341
+ await self._execute_phase(session, "individual_review", {
342
+ "instructions": "Conduct independent review of the material",
343
+ "time_limit_minutes": 30,
344
+ "review_criteria": ["accuracy", "completeness", "clarity", "quality"],
345
+ "parallel_reviews": True
346
+ })
347
+
348
+ # Phase 3: Review Collection
349
+ await self._execute_phase(session, "review_collection", {
350
+ "instructions": "Collect and synthesize all review feedback",
351
+ "time_limit_minutes": 15,
352
+ "identify_conflicts": True,
353
+ "aggregate_scores": True
354
+ })
355
+
356
+ # Phase 4: Feedback Integration
357
+ await self._execute_phase(session, "feedback_integration", {
358
+ "instructions": "Integrate reviewer feedback into the material",
359
+ "time_limit_minutes": 20,
360
+ "collaborative_editing": True,
361
+ "track_changes": True
362
+ })
363
+
364
+ # Phase 5: Final Approval
365
+ await self._execute_phase(session, "final_approval", {
366
+ "instructions": "Reviewers provide final approval or request changes",
367
+ "time_limit_minutes": 10,
368
+ "require_consensus": True,
369
+ "approval_threshold": 0.8
370
+ })
325
371
 
326
372
  async def _consensus_building_workflow(self, session: CollaborationSession) -> None:
327
- """Execute consensus building workflow."""
373
+ """
374
+ Execute consensus building workflow.
375
+
376
+ Phases:
377
+ 1. Issue presentation and clarification
378
+ 2. Discussion round 1 - Position sharing
379
+ 3. Common ground identification
380
+ 4. Proposal refinement
381
+ 5. Convergence check and agreement
382
+ """
328
383
  logger.info(f"Starting consensus building workflow for session {session.session_id}")
329
384
 
330
- # Implementation for consensus building workflow
331
- pass
385
+ # Phase 1: Issue Presentation
386
+ await self._execute_phase(session, "issue_presentation", {
387
+ "instructions": "Present the issue clearly and allow clarification questions",
388
+ "time_limit_minutes": 15,
389
+ "clarification_enabled": True
390
+ })
391
+
392
+ # Phase 2: Position Sharing
393
+ await self._execute_phase(session, "position_sharing", {
394
+ "instructions": "Each member shares their position and rationale",
395
+ "time_limit_minutes": 20,
396
+ "equal_participation": True,
397
+ "capture_positions": True
398
+ })
399
+
400
+ # Phase 3: Common Ground Identification
401
+ await self._execute_phase(session, "common_ground_identification", {
402
+ "instructions": "Identify areas of agreement and shared values",
403
+ "time_limit_minutes": 15,
404
+ "find_overlaps": True,
405
+ "identify_blockers": True
406
+ })
407
+
408
+ # Phase 4: Proposal Refinement
409
+ await self._execute_phase(session, "proposal_refinement", {
410
+ "instructions": "Refine proposals to address concerns and maximize agreement",
411
+ "time_limit_minutes": 25,
412
+ "iterative_refinement": True,
413
+ "test_proposals": True
414
+ })
415
+
416
+ # Phase 5: Convergence Check
417
+ await self._execute_phase(session, "convergence_check", {
418
+ "instructions": "Check for consensus and finalize agreement",
419
+ "time_limit_minutes": 15,
420
+ "consensus_threshold": 0.9,
421
+ "allow_dissent": True,
422
+ "document_agreement": True
423
+ })
332
424
 
333
425
  async def _execute_phase(
334
426
  self,