-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce Social Dynamics Simulation System module with LLMs #38
Conversation
Add sophisticated group decision-making and emotional simulation components: - Add AdvancedDeliberation class for multi-phase group discussions - Implement EmotionalAftermath for handling post-decision effects - Add EmotionalLearning for agent adaptation over time - Create comprehensive deliberation prompts and templates - Add simulation scenario runner with complex agent interactions The implementation includes: - Multi-phase deliberation process - Emotional pattern recognition - Dynamic relationship adjustments - Consensus building mechanics - Detailed aftermath processing - Agent learning and adaptation This enhancement provides a more realistic simulation of group dynamics and emotional intelligence in social agent interactions.
feat: Implement advanced group deliberation and emotional dynamics
Reviewer's Guide by SourceryThis PR introduces a sophisticated multi-agent social simulation system that models complex interpersonal dynamics, emotional states, and group decision-making processes. The system uses LLMs to generate realistic social interactions based on personality traits, emotional states, and social status. The implementation includes detailed classes for handling social agents, emotional states, group dynamics, decision-making processes, and conflict resolution. Class diagram for Social Dynamics Simulation SystemclassDiagram
class SocialAgent {
+String id
+SocialStatus status
+Dict relationships
+InteractionMemory memory
+LLMInterface llm
+PersonalityTraits personality
+decide_interaction(other_agent, context) InteractionType
+generate_interaction_text(other_agent, strategy, context) str
+interact(other_agent, context) InteractionOutcome
}
class EnhancedSocialAgent {
+EmotionalState emotional_state
+InteractionStyle interaction_style
+generate_interaction_text(other_agent, strategy, context) str
+process_interaction_outcome(outcome, other_agent)
}
EnhancedSocialAgent --|> SocialAgent
class SocialStatus {
+float formal_rank
+float influence
+float respect
+Dict expertise
+compute_effective_status(context) float
}
class PersonalityTraits {
+float extraversion
+float agreeableness
+float dominance
+float openness
+float stability
+to_dict() Dict
}
class EmotionalState {
+Enum Emotion
+Dict current_emotions
+update_emotion(emotion, intensity)
+get_dominant_emotion() Tuple
}
class InteractionMemory {
+List interactions
+add_interaction(other_agent_id, interaction_text, outcome, emotional_state)
+get_recent_interactions(n) List
+get_interactions_with(agent_id) List
}
class LLMInterface {
+String model
+List conversation_history
+generate(prompt) str
}
class GroupEmotionalDynamics {
+List agents
+Dict emotional_network
+Dict group_emotion
+List subgroups
+List emotional_history
+process_group_interaction(interaction) Dict
}
class AdvancedDeliberation {
+GroupEmotionalDynamics group
+DeliberationPhase current_phase
+List phase_history
+Dict emotional_insights
+facilitate_phase(phase, context) PhaseOutcome
}
class EmotionalDecisionMaking {
+GroupEmotionalDynamics group
+List decision_history
+Dict current_proposals
+make_group_decision(proposal) DecisionOutcome
}
class EmotionalAftermath {
+GroupEmotionalDynamics group
+Dict active_effects
+Dict learning_history
+process_aftermath(event)
}
class DecisionProposal {
+String topic
+List options
+EnhancedSocialAgent initiator
+String context
+float urgency
}
class DecisionOutcome {
+String decision
+float confidence
+float consensus_level
+Dict emotional_impact
+List dissenting_agents
}
class GroupInteraction {
+Type interaction_type
+EnhancedSocialAgent initiator
+Set participants
+String context
+execute()
}
class Conflict {
+String id
+Set participants
+String trigger
+Dict emotional_states
+float intensity
+String context
}
class AftermathEffect {
+AftermathType effect_type
+Tuple agents
+float intensity
+int duration
}
class EmotionalLearning {
+EnhancedSocialAgent agent
+Dict learned_patterns
+float adaptation_rate
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @leonvanbokhorst - I've reviewed your changes - here's some feedback:
Overall Comments:
- Consider adding comprehensive test coverage to validate the emotional and social dynamics models. Unit tests for individual components and integration tests for multi-agent scenarios would help verify realistic behavior.
Here's what I looked at during the review
- 🟡 General issues: 1 issue found
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟡 Complexity: 2 issues found
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
# Normalize other emotions to maintain total intensity | ||
self._normalize_emotions(emotion) | ||
|
||
def _normalize_emotions(self, primary_emotion: Emotion) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: Add check for division by zero when normalizing emotions
When primary_emotion has the only non-zero value, total - self.current_emotions[primary_emotion] will be zero, causing a division by zero. Add a check to handle this case.
} | ||
|
||
|
||
class EmotionalDecisionMaking: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (complexity): Consider extracting emotional processing logic into a dedicated EmotionalProcessor class to handle the emotional dynamics separately from decision making.
The EmotionalDecisionMaking class mixes emotional processing, agent interaction and decision logic in ways that make the code hard to follow. Consider extracting the emotional processing into a separate EmotionalProcessor class:
class EmotionalProcessor:
def __init__(self, group: GroupEmotionalDynamics):
self.group = group
async def process_dynamics(
self,
contributions: List[Dict[str, Any]]
) -> Dict[str, Dict[EmotionalState.Emotion, float]]:
emotional_shifts = self._process_agent_emotions(contributions)
await self._process_emotional_contagion(emotional_shifts)
return emotional_shifts
def _process_agent_emotions(
self,
contributions: List[Dict[str, Any]]
) -> Dict[str, Dict[EmotionalState.Emotion, float]]:
shifts = {}
for agent_id, agent_contribs in self._group_by_agent(contributions).items():
shifts[agent_id] = self._calculate_agent_shift(agent_contribs)
return shifts
Then simplify EmotionalDecisionMaking to use this processor:
class EmotionalDecisionMaking:
def __init__(self, group: GroupEmotionalDynamics):
self.group = group
self.emotional_processor = EmotionalProcessor(group)
async def _process_emotional_dynamics(
self,
contributions: List[Dict[str, Any]]
) -> Dict[str, Dict[EmotionalState.Emotion, float]]:
return await self.emotional_processor.process_dynamics(contributions)
This separation of concerns makes the code more maintainable while preserving all functionality.
self.phase_history: List[Dict] = [] | ||
self.emotional_insights: Dict[str, List[str]] = {} | ||
|
||
async def facilitate_phase( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (complexity): Consider extracting emotional processing logic into a dedicated service class to improve separation of concerns.
The AdvancedDeliberation
class could be simplified by extracting the emotional processing into a separate service. This would reduce coupling and make the phase facilitation flow clearer. Consider:
class EmotionalProcessingService:
def __init__(self, group: GroupEmotionalDynamics):
self.group = group
async def process_contributions(
self,
contributions: List[Dict[str, Any]]
) -> Dict[str, Dict[EmotionalState.Emotion, float]]:
emotional_shifts = {}
for contribution in contributions:
shifts = await self._process_single_contribution(contribution)
emotional_shifts[contribution["agent_id"]] = shifts
return emotional_shifts
class AdvancedDeliberation:
def __init__(self, group: GroupEmotionalDynamics):
self.group = group
self.emotional_processor = EmotionalProcessingService(group)
async def facilitate_phase(self, phase: DeliberationPhase, context: Dict) -> PhaseOutcome:
prompts = self._generate_phase_prompts(phase, context)
contributions = await self._gather_phase_contributions(prompts)
# Cleaner emotional processing through dedicated service
emotional_shifts = await self.emotional_processor.process_contributions(contributions)
return self._evaluate_phase_outcome(contributions, emotional_shifts)
This refactoring:
- Separates emotional processing concerns
- Reduces method complexity in facilitate_phase
- Makes the code flow more linear and easier to follow
- Improves testability of emotional processing logic
for emotion in group_emotions: | ||
group_emotions[emotion] /= total_influence |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (code-quality): We've found these issues:
- Use items() to directly unpack dictionary values (
use-dict-items
) - Replace calls to
dict.items
withdict.values
when the keys are not used (replace-dict-items-with-values
)
for emotion in group_emotions: | |
group_emotions[emotion] /= total_influence | |
for value in group_emotions.values(): | |
value /= total_influence |
pass | ||
|
||
async def _propagate_emotions( | ||
self, interaction: "GroupInteraction" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): We've found these issues:
- Move assignment closer to its usage within a block (
move-assign-in-block
) - Merge dictionary assignment with declaration (
merge-dict-assign
)
# Determine phase outcome | ||
outcome = self._evaluate_phase_outcome(contributions, emotional_shifts) | ||
|
||
return outcome |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable
)
# Determine phase outcome | |
outcome = self._evaluate_phase_outcome(contributions, emotional_shifts) | |
return outcome | |
return self._evaluate_phase_outcome(contributions, emotional_shifts) |
contextualized_prompts = [] | ||
for prompt in base_prompts: | ||
contextualized_prompts.append( | ||
f"Context: {context['situation']}\n" | ||
f"Stakes: {context['stakes']}\n" | ||
f"Timeline: {context['timeline']}\n\n" | ||
f"{prompt}" | ||
) | ||
|
||
return contextualized_prompts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (code-quality): We've found these issues:
- Convert for loop into list comprehension (
list-comprehension
) - Inline variable that is immediately returned (
inline-immediately-returned-variable
)
contextualized_prompts = [] | |
for prompt in base_prompts: | |
contextualized_prompts.append( | |
f"Context: {context['situation']}\n" | |
f"Stakes: {context['stakes']}\n" | |
f"Timeline: {context['timeline']}\n\n" | |
f"{prompt}" | |
) | |
return contextualized_prompts | |
return [ | |
f"Context: {context['situation']}\nStakes: {context['stakes']}\nTimeline: {context['timeline']}\n\n{prompt}" | |
for prompt in base_prompts | |
] |
emotional_similarity = self._calculate_emotional_similarity( | ||
contributions1[-1]["emotional_state"], contributions2[-1]["emotional_state"] | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable
)
patterns = {} | ||
|
||
# Pattern: Response to interaction types | ||
patterns["interaction_response"] = self._calculate_interaction_response( | ||
interaction | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (code-quality): Merge dictionary assignment with declaration (merge-dict-assign
)
patterns = {} | |
# Pattern: Response to interaction types | |
patterns["interaction_response"] = self._calculate_interaction_response( | |
interaction | |
) | |
patterns = { | |
"interaction_response": self._calculate_interaction_response( | |
interaction | |
) | |
} |
patterns = {} | ||
|
||
# Pattern: Decision acceptance | ||
patterns["decision_acceptance"] = ( | ||
1.0 if self.agent.id not in decision.dissenting_agents else 0.0 | ||
) | ||
|
||
# Pattern: Consensus alignment | ||
patterns["consensus_alignment"] = decision.consensus_level | ||
|
||
return patterns |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (code-quality): We've found these issues:
- Merge dictionary assignment with declaration [×2] (
merge-dict-assign
) - Inline variable that is immediately returned (
inline-immediately-returned-variable
)
patterns = {} | |
# Pattern: Decision acceptance | |
patterns["decision_acceptance"] = ( | |
1.0 if self.agent.id not in decision.dissenting_agents else 0.0 | |
) | |
# Pattern: Consensus alignment | |
patterns["consensus_alignment"] = decision.consensus_level | |
return patterns | |
return { | |
"decision_acceptance": ( | |
1.0 if self.agent.id not in decision.dissenting_agents else 0.0 | |
), | |
"consensus_alignment": decision.consensus_level, | |
} |
Summary by Sourcery
New Features: