Class: Legion::Extensions::Agentic::Social::MoralReasoning::Helpers::MoralEngine

Inherits:
Object
  • Object
show all
Includes:
Constants, FrameworkEvaluators
Defined in:
lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb

Constant Summary collapse

KOHLBERG_STAGE_DESCRIPTIONS =
{
  obedience:        'Avoid punishment; obey authority unconditionally',
  self_interest:    'Act for direct reward; reciprocal exchange',
  conformity:       'Conform to social norms; be a good person',
  law_and_order:    'Follow rules, laws, and authority to maintain social order',
  social_contract:  'Uphold democratic principles; greatest good for greatest number',
  universal_ethics: 'Follow self-chosen universal ethical principles'
}.freeze
FRAMEWORK_STRATEGIES =
{
  utilitarian:   :evaluate_by_utility,
  deontological: :evaluate_by_duty,
  virtue:        :evaluate_by_virtue,
  care:          :evaluate_by_care,
  justice:       :evaluate_by_justice,
  rights:        :evaluate_by_rights
}.freeze

Constants included from FrameworkEvaluators

FrameworkEvaluators::CARE_FOUNDATIONS, FrameworkEvaluators::DUTY_FOUNDATIONS, FrameworkEvaluators::JUSTICE_FOUNDATIONS, FrameworkEvaluators::RIGHTS_FOUNDATIONS

Constants included from Constants

Constants::DECAY_RATE, Constants::DEFAULT_WEIGHT, Constants::ETHICAL_FRAMEWORKS, Constants::KOHLBERG_LEVELS, Constants::KOHLBERG_STAGES, Constants::MAX_DILEMMAS, Constants::MAX_HISTORY, Constants::MAX_PRINCIPLES, Constants::MORAL_FOUNDATIONS, Constants::REINFORCEMENT_RATE, Constants::SEVERITY_LABELS, Constants::WEIGHT_CEILING, Constants::WEIGHT_FLOOR

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMoralEngine

Returns a new instance of MoralEngine.



86
87
88
89
90
91
92
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 86

def initialize
  @foundations = MORAL_FOUNDATIONS.to_h { |f| [f, MoralFoundation.new(id: f)] }
  @principles  = []
  @dilemmas    = {}
  @stage       = :social_contract
  @history     = []
end

Instance Attribute Details

#dilemmasObject (readonly)

Returns the value of attribute dilemmas.



84
85
86
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 84

def dilemmas
  @dilemmas
end

#historyObject (readonly)

Returns the value of attribute history.



84
85
86
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 84

def history
  @history
end

#principlesObject (readonly)

Returns the value of attribute principles.



84
85
86
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 84

def principles
  @principles
end

#stageObject (readonly)

Returns the value of attribute stage.



84
85
86
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 84

def stage
  @stage
end

Instance Method Details

#add_principle(name:, description:, foundation:, weight: DEFAULT_WEIGHT) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 137

def add_principle(name:, description:, foundation:, weight: DEFAULT_WEIGHT)
  return { success: false, reason: :max_principles_reached } if @principles.size >= MAX_PRINCIPLES
  return { success: false, reason: :unknown_foundation } unless MORAL_FOUNDATIONS.include?(foundation)

  principle = {
    id:          generate_id('principle'),
    name:        name,
    description: description,
    foundation:  foundation,
    weight:      weight.clamp(WEIGHT_FLOOR, WEIGHT_CEILING),
    created_at:  Time.now.utc
  }
  @principles << principle
  { success: true, principle: principle }
end

#apply_framework(dilemma_id:, framework:) ⇒ Object



127
128
129
130
131
132
133
134
135
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 127

def apply_framework(dilemma_id:, framework:)
  dilemma = @dilemmas[dilemma_id]
  return { success: false, reason: :not_found } unless dilemma
  return { success: false, reason: :unknown_framework } unless ETHICAL_FRAMEWORKS.include?(framework)

  strategy  = FRAMEWORK_STRATEGIES.fetch(framework)
  rankings  = send(strategy, dilemma)
  { success: true, dilemma_id: dilemma_id, framework: framework, rankings: rankings }
end

#decay_allObject



186
187
188
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 186

def decay_all
  @foundations.each_value(&:decay)
end

#evaluate_action(action:, affected_foundations:, domain: :general) ⇒ Object



94
95
96
97
98
99
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 94

def evaluate_action(action:, affected_foundations:, domain: :general)
  score = score_foundations(affected_foundations)
  normalized = affected_foundations.empty? ? 0.0 : score / affected_foundations.size
  add_history(type: :evaluation, action: action, domain: domain, score: normalized)
  { action: action, domain: domain, score: normalized, foundations: affected_foundations }
end

#foundation_profileObject



169
170
171
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 169

def foundation_profile
  @foundations.transform_values(&:to_h)
end

#moral_developmentObject



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 153

def moral_development
  resolved = resolved_dilemmas
  return { advanced: false, stage: @stage, reason: :insufficient_resolutions } if resolved.size < 3

  avg_severity = resolved.sum(&:severity) / resolved.size.to_f
  complexity_met = avg_severity >= 0.4 && resolved.size >= 5
  current_idx = KOHLBERG_STAGES.index(@stage)

  if complexity_met && current_idx < KOHLBERG_STAGES.size - 1
    @stage = KOHLBERG_STAGES[current_idx + 1]
    { advanced: true, stage: @stage, previous_stage: KOHLBERG_STAGES[current_idx] }
  else
    { advanced: false, stage: @stage, reason: :complexity_threshold_not_met }
  end
end

#pose_dilemma(description:, options:, domain: :general, severity: 0.5) ⇒ Object



101
102
103
104
105
106
107
108
109
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 101

def pose_dilemma(description:, options:, domain: :general, severity: 0.5)
  return { success: false, reason: :max_dilemmas_reached } if @dilemmas.size >= MAX_DILEMMAS

  id = generate_id('dilemma')
  dilemma = Dilemma.new(id: id, description: description, options: options,
                        domain: domain, severity: severity)
  @dilemmas[id] = dilemma
  { success: true, dilemma: dilemma.to_h }
end

#resolve_dilemma(dilemma_id:, option_id:, reasoning:, framework:) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 111

def resolve_dilemma(dilemma_id:, option_id:, reasoning:, framework:)
  dilemma = @dilemmas[dilemma_id]
  return { success: false, reason: :not_found } unless dilemma
  return { success: false, reason: :already_resolved } if dilemma.resolved?

  chosen = dilemma.options.find { |o| o[:id] == option_id }
  return { success: false, reason: :invalid_option } unless chosen

  dilemma.resolve(option_id: option_id, reasoning: reasoning, framework: framework)
  reinforce_chosen_foundations(chosen)
  weaken_unchosen_foundations(dilemma.options, option_id)
  add_history(type: :resolution, dilemma_id: dilemma_id, option_id: option_id,
              framework: framework, severity: dilemma.severity)
  { success: true, dilemma: dilemma.to_h }
end

#resolved_dilemmasObject



182
183
184
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 182

def resolved_dilemmas
  @dilemmas.values.select(&:resolved?)
end

#stage_infoObject



173
174
175
176
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 173

def stage_info
  level = KOHLBERG_LEVELS.find { |_, stages| stages.include?(@stage) }&.first
  { stage: @stage, level: level, description: KOHLBERG_STAGE_DESCRIPTIONS.fetch(@stage, 'Unknown') }
end

#to_hObject



190
191
192
193
194
195
196
197
198
199
200
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 190

def to_h
  {
    stage:               @stage,
    total_dilemmas:      @dilemmas.size,
    resolved_dilemmas:   resolved_dilemmas.size,
    unresolved_dilemmas: unresolved_dilemmas.size,
    principles:          @principles.size,
    history_entries:     @history.size,
    foundation_profile:  foundation_profile
  }
end

#unresolved_dilemmasObject



178
179
180
# File 'lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb', line 178

def unresolved_dilemmas
  @dilemmas.values.reject(&:resolved?)
end