lex-agentic-affect 0.1.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +13 -0
- data/lex-agentic-affect.gemspec +30 -0
- data/lib/legion/extensions/agentic/affect/appraisal/client.rb +20 -0
- data/lib/legion/extensions/agentic/affect/appraisal/helpers/appraisal.rb +112 -0
- data/lib/legion/extensions/agentic/affect/appraisal/helpers/appraisal_engine.rb +129 -0
- data/lib/legion/extensions/agentic/affect/appraisal/helpers/constants.rb +43 -0
- data/lib/legion/extensions/agentic/affect/appraisal/runners/appraisal.rb +105 -0
- data/lib/legion/extensions/agentic/affect/appraisal/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/appraisal.rb +19 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/client.rb +19 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/helpers/constants.rb +37 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/helpers/empathy_engine.rb +151 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/helpers/perspective.rb +92 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/runners/cognitive_empathy.rb +93 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/cognitive_empathy.rb +20 -0
- data/lib/legion/extensions/agentic/affect/contagion/client.rb +28 -0
- data/lib/legion/extensions/agentic/affect/contagion/helpers/constants.rb +34 -0
- data/lib/legion/extensions/agentic/affect/contagion/helpers/contagion_engine.rb +184 -0
- data/lib/legion/extensions/agentic/affect/contagion/helpers/meme.rb +97 -0
- data/lib/legion/extensions/agentic/affect/contagion/runners/cognitive_contagion.rb +125 -0
- data/lib/legion/extensions/agentic/affect/contagion/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/contagion.rb +19 -0
- data/lib/legion/extensions/agentic/affect/defusion/client.rb +28 -0
- data/lib/legion/extensions/agentic/affect/defusion/helpers/constants.rb +64 -0
- data/lib/legion/extensions/agentic/affect/defusion/helpers/defusion_engine.rb +167 -0
- data/lib/legion/extensions/agentic/affect/defusion/helpers/thought.rb +92 -0
- data/lib/legion/extensions/agentic/affect/defusion/runners/cognitive_defusion.rb +127 -0
- data/lib/legion/extensions/agentic/affect/defusion/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/defusion.rb +19 -0
- data/lib/legion/extensions/agentic/affect/emotion/actors/momentum_decay.rb +45 -0
- data/lib/legion/extensions/agentic/affect/emotion/client.rb +36 -0
- data/lib/legion/extensions/agentic/affect/emotion/helpers/baseline.rb +52 -0
- data/lib/legion/extensions/agentic/affect/emotion/helpers/momentum.rb +52 -0
- data/lib/legion/extensions/agentic/affect/emotion/helpers/valence.rb +92 -0
- data/lib/legion/extensions/agentic/affect/emotion/runners/gut.rb +102 -0
- data/lib/legion/extensions/agentic/affect/emotion/runners/valence.rb +120 -0
- data/lib/legion/extensions/agentic/affect/emotion/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/emotion.rb +20 -0
- data/lib/legion/extensions/agentic/affect/empathy/client.rb +21 -0
- data/lib/legion/extensions/agentic/affect/empathy/helpers/constants.rb +54 -0
- data/lib/legion/extensions/agentic/affect/empathy/helpers/mental_model.rb +185 -0
- data/lib/legion/extensions/agentic/affect/empathy/helpers/model_store.rb +88 -0
- data/lib/legion/extensions/agentic/affect/empathy/runners/empathy.rb +173 -0
- data/lib/legion/extensions/agentic/affect/empathy/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/empathy.rb +20 -0
- data/lib/legion/extensions/agentic/affect/fatigue/client.rb +26 -0
- data/lib/legion/extensions/agentic/affect/fatigue/helpers/constants.rb +54 -0
- data/lib/legion/extensions/agentic/affect/fatigue/helpers/energy_model.rb +181 -0
- data/lib/legion/extensions/agentic/affect/fatigue/helpers/fatigue_store.rb +146 -0
- data/lib/legion/extensions/agentic/affect/fatigue/runners/fatigue.rb +89 -0
- data/lib/legion/extensions/agentic/affect/fatigue/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/fatigue.rb +19 -0
- data/lib/legion/extensions/agentic/affect/flow/client.rb +25 -0
- data/lib/legion/extensions/agentic/affect/flow/helpers/constants.rb +84 -0
- data/lib/legion/extensions/agentic/affect/flow/helpers/flow_detector.rb +166 -0
- data/lib/legion/extensions/agentic/affect/flow/runners/flow.rb +129 -0
- data/lib/legion/extensions/agentic/affect/flow/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/flow.rb +18 -0
- data/lib/legion/extensions/agentic/affect/interoception/actors/decay.rb +45 -0
- data/lib/legion/extensions/agentic/affect/interoception/client.rb +28 -0
- data/lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb +152 -0
- data/lib/legion/extensions/agentic/affect/interoception/helpers/constants.rb +68 -0
- data/lib/legion/extensions/agentic/affect/interoception/helpers/somatic_marker.rb +75 -0
- data/lib/legion/extensions/agentic/affect/interoception/runners/interoception.rb +101 -0
- data/lib/legion/extensions/agentic/affect/interoception/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/interoception.rb +20 -0
- data/lib/legion/extensions/agentic/affect/mood/client.rb +21 -0
- data/lib/legion/extensions/agentic/affect/mood/helpers/constants.rb +78 -0
- data/lib/legion/extensions/agentic/affect/mood/helpers/mood_state.rb +154 -0
- data/lib/legion/extensions/agentic/affect/mood/runners/mood.rb +122 -0
- data/lib/legion/extensions/agentic/affect/mood/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/mood.rb +18 -0
- data/lib/legion/extensions/agentic/affect/motivation/client.rb +26 -0
- data/lib/legion/extensions/agentic/affect/motivation/helpers/constants.rb +48 -0
- data/lib/legion/extensions/agentic/affect/motivation/helpers/drive_state.rb +98 -0
- data/lib/legion/extensions/agentic/affect/motivation/helpers/motivation_store.rb +106 -0
- data/lib/legion/extensions/agentic/affect/motivation/runners/motivation.rb +165 -0
- data/lib/legion/extensions/agentic/affect/motivation/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/motivation.rb +19 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/actors/auto_regulate.rb +45 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/client.rb +28 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/helpers/constants.rb +82 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/helpers/emotional_event.rb +98 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/helpers/llm_enhancer.rb +88 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/helpers/reappraisal_engine.rb +153 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/runners/cognitive_reappraisal.rb +164 -0
- data/lib/legion/extensions/agentic/affect/reappraisal/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/reappraisal.rb +20 -0
- data/lib/legion/extensions/agentic/affect/regulation/client.rb +25 -0
- data/lib/legion/extensions/agentic/affect/regulation/helpers/constants.rb +71 -0
- data/lib/legion/extensions/agentic/affect/regulation/helpers/regulation_model.rb +175 -0
- data/lib/legion/extensions/agentic/affect/regulation/runners/emotional_regulation.rb +127 -0
- data/lib/legion/extensions/agentic/affect/regulation/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/regulation.rb +18 -0
- data/lib/legion/extensions/agentic/affect/resilience/client.rb +27 -0
- data/lib/legion/extensions/agentic/affect/resilience/helpers/adversity_tracker.rb +130 -0
- data/lib/legion/extensions/agentic/affect/resilience/helpers/constants.rb +79 -0
- data/lib/legion/extensions/agentic/affect/resilience/helpers/resilience_model.rb +165 -0
- data/lib/legion/extensions/agentic/affect/resilience/runners/resilience.rb +150 -0
- data/lib/legion/extensions/agentic/affect/resilience/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/resilience.rb +19 -0
- data/lib/legion/extensions/agentic/affect/resonance/client.rb +24 -0
- data/lib/legion/extensions/agentic/affect/resonance/helpers/category.rb +75 -0
- data/lib/legion/extensions/agentic/affect/resonance/helpers/constants.rb +47 -0
- data/lib/legion/extensions/agentic/affect/resonance/helpers/resonance_engine.rb +115 -0
- data/lib/legion/extensions/agentic/affect/resonance/runners/cognitive_resonance.rb +94 -0
- data/lib/legion/extensions/agentic/affect/resonance/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/resonance.rb +19 -0
- data/lib/legion/extensions/agentic/affect/reward/client.rb +26 -0
- data/lib/legion/extensions/agentic/affect/reward/helpers/constants.rb +67 -0
- data/lib/legion/extensions/agentic/affect/reward/helpers/reward_signal.rb +178 -0
- data/lib/legion/extensions/agentic/affect/reward/helpers/reward_store.rb +142 -0
- data/lib/legion/extensions/agentic/affect/reward/runners/reward.rb +92 -0
- data/lib/legion/extensions/agentic/affect/reward/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/reward.rb +19 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/actors/decay.rb +45 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/client.rb +29 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/body_state.rb +69 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/constants.rb +43 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb +160 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/somatic_marker.rb +74 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/runners/somatic_marker.rb +132 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker/version.rb +13 -0
- data/lib/legion/extensions/agentic/affect/somatic_marker.rb +20 -0
- data/lib/legion/extensions/agentic/affect/version.rb +11 -0
- data/lib/legion/extensions/agentic/affect.rb +34 -0
- data/spec/legion/extensions/agentic/affect/appraisal/client_spec.rb +52 -0
- data/spec/legion/extensions/agentic/affect/appraisal/helpers/appraisal_engine_spec.rb +161 -0
- data/spec/legion/extensions/agentic/affect/appraisal/helpers/appraisal_spec.rb +175 -0
- data/spec/legion/extensions/agentic/affect/appraisal/helpers/constants_spec.rb +49 -0
- data/spec/legion/extensions/agentic/affect/appraisal/runners/appraisal_spec.rb +116 -0
- data/spec/legion/extensions/agentic/affect/cognitive_empathy/client_spec.rb +62 -0
- data/spec/legion/extensions/agentic/affect/cognitive_empathy/helpers/empathy_engine_spec.rb +316 -0
- data/spec/legion/extensions/agentic/affect/cognitive_empathy/helpers/perspective_spec.rb +132 -0
- data/spec/legion/extensions/agentic/affect/cognitive_empathy/runners/cognitive_empathy_spec.rb +200 -0
- data/spec/legion/extensions/agentic/affect/contagion/client_spec.rb +63 -0
- data/spec/legion/extensions/agentic/affect/contagion/helpers/constants_spec.rb +86 -0
- data/spec/legion/extensions/agentic/affect/contagion/helpers/contagion_engine_spec.rb +241 -0
- data/spec/legion/extensions/agentic/affect/contagion/helpers/meme_spec.rb +160 -0
- data/spec/legion/extensions/agentic/affect/contagion/runners/cognitive_contagion_spec.rb +211 -0
- data/spec/legion/extensions/agentic/affect/defusion/client_spec.rb +80 -0
- data/spec/legion/extensions/agentic/affect/defusion/helpers/constants_spec.rb +84 -0
- data/spec/legion/extensions/agentic/affect/defusion/helpers/defusion_engine_spec.rb +250 -0
- data/spec/legion/extensions/agentic/affect/defusion/helpers/thought_spec.rb +178 -0
- data/spec/legion/extensions/agentic/affect/defusion/runners/cognitive_defusion_spec.rb +185 -0
- data/spec/legion/extensions/agentic/affect/emotion/actors/momentum_decay_spec.rb +46 -0
- data/spec/legion/extensions/agentic/affect/emotion/client_spec.rb +46 -0
- data/spec/legion/extensions/agentic/affect/emotion/helpers/baseline_spec.rb +48 -0
- data/spec/legion/extensions/agentic/affect/emotion/helpers/momentum_spec.rb +45 -0
- data/spec/legion/extensions/agentic/affect/emotion/helpers/valence_spec.rb +91 -0
- data/spec/legion/extensions/agentic/affect/emotion/runners/gut_spec.rb +73 -0
- data/spec/legion/extensions/agentic/affect/emotion/runners/valence_spec.rb +67 -0
- data/spec/legion/extensions/agentic/affect/empathy/client_spec.rb +20 -0
- data/spec/legion/extensions/agentic/affect/empathy/helpers/constants_spec.rb +23 -0
- data/spec/legion/extensions/agentic/affect/empathy/helpers/mental_model_spec.rb +150 -0
- data/spec/legion/extensions/agentic/affect/empathy/helpers/model_store_spec.rb +94 -0
- data/spec/legion/extensions/agentic/affect/empathy/runners/empathy_spec.rb +127 -0
- data/spec/legion/extensions/agentic/affect/fatigue/client_spec.rb +66 -0
- data/spec/legion/extensions/agentic/affect/fatigue/helpers/constants_spec.rb +130 -0
- data/spec/legion/extensions/agentic/affect/fatigue/helpers/energy_model_spec.rb +281 -0
- data/spec/legion/extensions/agentic/affect/fatigue/helpers/fatigue_store_spec.rb +157 -0
- data/spec/legion/extensions/agentic/affect/fatigue/runners/fatigue_spec.rb +127 -0
- data/spec/legion/extensions/agentic/affect/flow/client_spec.rb +58 -0
- data/spec/legion/extensions/agentic/affect/flow/helpers/constants_spec.rb +112 -0
- data/spec/legion/extensions/agentic/affect/flow/helpers/flow_detector_spec.rb +268 -0
- data/spec/legion/extensions/agentic/affect/flow/runners/flow_spec.rb +222 -0
- data/spec/legion/extensions/agentic/affect/interoception/client_spec.rb +52 -0
- data/spec/legion/extensions/agentic/affect/interoception/helpers/body_budget_spec.rb +178 -0
- data/spec/legion/extensions/agentic/affect/interoception/helpers/somatic_marker_spec.rb +120 -0
- data/spec/legion/extensions/agentic/affect/interoception/runners/interoception_spec.rb +108 -0
- data/spec/legion/extensions/agentic/affect/mood/client_spec.rb +20 -0
- data/spec/legion/extensions/agentic/affect/mood/helpers/constants_spec.rb +29 -0
- data/spec/legion/extensions/agentic/affect/mood/helpers/mood_state_spec.rb +94 -0
- data/spec/legion/extensions/agentic/affect/mood/runners/mood_spec.rb +71 -0
- data/spec/legion/extensions/agentic/affect/motivation/client_spec.rb +35 -0
- data/spec/legion/extensions/agentic/affect/motivation/helpers/constants_spec.rb +111 -0
- data/spec/legion/extensions/agentic/affect/motivation/helpers/drive_state_spec.rb +183 -0
- data/spec/legion/extensions/agentic/affect/motivation/helpers/motivation_store_spec.rb +185 -0
- data/spec/legion/extensions/agentic/affect/motivation/runners/motivation_spec.rb +248 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/actors/auto_regulate_spec.rb +46 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/client_spec.rb +64 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/helpers/constants_spec.rb +102 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/helpers/emotional_event_spec.rb +177 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/helpers/llm_enhancer_spec.rb +161 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/helpers/reappraisal_engine_spec.rb +211 -0
- data/spec/legion/extensions/agentic/affect/reappraisal/runners/cognitive_reappraisal_spec.rb +312 -0
- data/spec/legion/extensions/agentic/affect/regulation/client_spec.rb +61 -0
- data/spec/legion/extensions/agentic/affect/regulation/helpers/constants_spec.rb +108 -0
- data/spec/legion/extensions/agentic/affect/regulation/helpers/regulation_model_spec.rb +200 -0
- data/spec/legion/extensions/agentic/affect/regulation/runners/emotional_regulation_spec.rb +190 -0
- data/spec/legion/extensions/agentic/affect/resilience/client_spec.rb +36 -0
- data/spec/legion/extensions/agentic/affect/resilience/helpers/adversity_tracker_spec.rb +164 -0
- data/spec/legion/extensions/agentic/affect/resilience/helpers/constants_spec.rb +78 -0
- data/spec/legion/extensions/agentic/affect/resilience/helpers/resilience_model_spec.rb +133 -0
- data/spec/legion/extensions/agentic/affect/resilience/runners/resilience_spec.rb +150 -0
- data/spec/legion/extensions/agentic/affect/resonance/client_spec.rb +66 -0
- data/spec/legion/extensions/agentic/affect/resonance/cognitive_resonance_spec.rb +27 -0
- data/spec/legion/extensions/agentic/affect/resonance/helpers/category_spec.rb +146 -0
- data/spec/legion/extensions/agentic/affect/resonance/helpers/constants_spec.rb +104 -0
- data/spec/legion/extensions/agentic/affect/resonance/helpers/resonance_engine_spec.rb +189 -0
- data/spec/legion/extensions/agentic/affect/resonance/runners/cognitive_resonance_spec.rb +197 -0
- data/spec/legion/extensions/agentic/affect/reward/client_spec.rb +42 -0
- data/spec/legion/extensions/agentic/affect/reward/helpers/constants_spec.rb +91 -0
- data/spec/legion/extensions/agentic/affect/reward/helpers/reward_signal_spec.rb +296 -0
- data/spec/legion/extensions/agentic/affect/reward/helpers/reward_store_spec.rb +167 -0
- data/spec/legion/extensions/agentic/affect/reward/runners/reward_spec.rb +149 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/client_spec.rb +83 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/helpers/body_state_spec.rb +155 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store_spec.rb +233 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/helpers/somatic_marker_spec.rb +172 -0
- data/spec/legion/extensions/agentic/affect/somatic_marker/runners/somatic_marker_spec.rb +181 -0
- data/spec/spec_helper.rb +46 -0
- metadata +302 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::Appraisal::Helpers::AppraisalEngine do
|
|
4
|
+
let(:engine) { described_class.new }
|
|
5
|
+
|
|
6
|
+
let(:primary_joy) { { relevance: 0.9, goal_congruence: 0.9, goal_importance: 0.8 } }
|
|
7
|
+
let(:primary_threat) { { relevance: 0.9, goal_congruence: 0.3, goal_importance: 0.8 } }
|
|
8
|
+
let(:secondary_low) { { coping_potential: 0.2, control_expectation: 0.3, future_expectancy: 0.4 } }
|
|
9
|
+
let(:secondary_high) { { coping_potential: 0.8, control_expectation: 0.7, future_expectancy: 0.6 } }
|
|
10
|
+
|
|
11
|
+
describe '#appraise' do
|
|
12
|
+
it 'creates and returns an appraisal' do
|
|
13
|
+
record = engine.appraise(event: 'test', primary: primary_joy, secondary: secondary_high)
|
|
14
|
+
expect(record).to be_a(Legion::Extensions::Agentic::Affect::Appraisal::Helpers::Appraisal)
|
|
15
|
+
expect(record.event).to eq('test')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'stores appraisals by id' do
|
|
19
|
+
record = engine.appraise(event: 'test', primary: primary_joy, secondary: secondary_high)
|
|
20
|
+
expect(engine.to_h[:appraisals]).to have_key(record.id)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'computes emotional_outcome' do
|
|
24
|
+
record = engine.appraise(event: 'test', primary: primary_joy, secondary: secondary_high)
|
|
25
|
+
expect(record.emotional_outcome).to eq(:joy)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '#reappraise' do
|
|
30
|
+
it 'updates an existing appraisal' do
|
|
31
|
+
record = engine.appraise(event: 'test', primary: primary_threat, secondary: secondary_low)
|
|
32
|
+
expect(record.emotional_outcome).to eq(:anxiety)
|
|
33
|
+
updated = engine.reappraise(appraisal_id: record.id, new_primary: primary_joy, new_secondary: secondary_high)
|
|
34
|
+
expect(updated.emotional_outcome).to eq(:joy)
|
|
35
|
+
expect(updated.reappraised).to be(true)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'returns nil for unknown id' do
|
|
39
|
+
result = engine.reappraise(appraisal_id: 'unknown', new_primary: primary_joy, new_secondary: secondary_high)
|
|
40
|
+
expect(result).to be_nil
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe '#select_coping' do
|
|
45
|
+
it 'assigns coping to appraisal' do
|
|
46
|
+
record = engine.appraise(event: 'test', primary: primary_threat, secondary: secondary_low)
|
|
47
|
+
updated = engine.select_coping(appraisal_id: record.id, coping_type: :problem_focused)
|
|
48
|
+
expect(updated.coping_strategy).not_to be_nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'prefers registered strategies for the coping type' do
|
|
52
|
+
engine.add_coping_strategy(name: 'action_plan', coping_type: :problem_focused, effectiveness: 0.9)
|
|
53
|
+
record = engine.appraise(event: 'test', primary: primary_threat, secondary: secondary_low)
|
|
54
|
+
updated = engine.select_coping(appraisal_id: record.id, coping_type: :problem_focused)
|
|
55
|
+
expect(updated.coping_strategy).to eq('action_plan')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'returns nil for unknown appraisal' do
|
|
59
|
+
result = engine.select_coping(appraisal_id: 'unknown', coping_type: :problem_focused)
|
|
60
|
+
expect(result).to be_nil
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe '#add_coping_strategy' do
|
|
65
|
+
it 'registers a strategy and returns true' do
|
|
66
|
+
result = engine.add_coping_strategy(name: 'reframing', coping_type: :emotion_focused, effectiveness: 0.7)
|
|
67
|
+
expect(result).to be(true)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'clamps effectiveness to [0, 1]' do
|
|
71
|
+
engine.add_coping_strategy(name: 'over', coping_type: :problem_focused, effectiveness: 1.5)
|
|
72
|
+
data = engine.to_h
|
|
73
|
+
# Strategy stored (engine is internal, test via evaluate_coping behavior)
|
|
74
|
+
expect(data).to be_a(Hash)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe '#evaluate_coping' do
|
|
79
|
+
it 'returns effectiveness 0.0 when no coping assigned' do
|
|
80
|
+
record = engine.appraise(event: 'test', primary: primary_threat, secondary: secondary_low)
|
|
81
|
+
result = engine.evaluate_coping(appraisal_id: record.id)
|
|
82
|
+
expect(result[:effectiveness]).to eq(0.0)
|
|
83
|
+
expect(result[:resolved]).to be(false)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'uses registered strategy effectiveness' do
|
|
87
|
+
engine.add_coping_strategy(name: 'mindfulness', coping_type: :emotion_focused, effectiveness: 0.85)
|
|
88
|
+
record = engine.appraise(event: 'test', primary: primary_threat, secondary: secondary_low)
|
|
89
|
+
engine.select_coping(appraisal_id: record.id, coping_type: :emotion_focused)
|
|
90
|
+
result = engine.evaluate_coping(appraisal_id: record.id)
|
|
91
|
+
expect(result[:effectiveness]).to be_within(0.01).of(0.85)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'returns defaults for unknown appraisal' do
|
|
95
|
+
result = engine.evaluate_coping(appraisal_id: 'unknown')
|
|
96
|
+
expect(result[:effectiveness]).to eq(0.0)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe '#by_emotion' do
|
|
101
|
+
it 'filters appraisals by emotional outcome' do
|
|
102
|
+
engine.appraise(event: 'a', primary: primary_joy, secondary: secondary_high)
|
|
103
|
+
engine.appraise(event: 'b', primary: primary_threat, secondary: secondary_low)
|
|
104
|
+
joy_list = engine.by_emotion(emotion: :joy)
|
|
105
|
+
expect(joy_list.size).to eq(1)
|
|
106
|
+
expect(joy_list.first.event).to eq('a')
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe '#by_domain' do
|
|
111
|
+
it 'filters appraisals by domain' do
|
|
112
|
+
engine.appraise(event: 'a', primary: primary_joy, secondary: secondary_high, domain: 'work')
|
|
113
|
+
engine.appraise(event: 'b', primary: primary_joy, secondary: secondary_high, domain: 'personal')
|
|
114
|
+
work_list = engine.by_domain(domain: 'work')
|
|
115
|
+
expect(work_list.size).to eq(1)
|
|
116
|
+
expect(work_list.first.event).to eq('a')
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe '#unresolved' do
|
|
121
|
+
it 'returns appraisals without coping strategy' do
|
|
122
|
+
rec1 = engine.appraise(event: 'a', primary: primary_joy, secondary: secondary_high)
|
|
123
|
+
rec2 = engine.appraise(event: 'b', primary: primary_joy, secondary: secondary_high)
|
|
124
|
+
engine.select_coping(appraisal_id: rec1.id, coping_type: :problem_focused)
|
|
125
|
+
unresolved = engine.unresolved
|
|
126
|
+
expect(unresolved.map(&:id)).to include(rec2.id)
|
|
127
|
+
expect(unresolved.map(&:id)).not_to include(rec1.id)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe '#emotional_pattern' do
|
|
132
|
+
it 'returns emotion counts sorted by frequency' do
|
|
133
|
+
3.times { engine.appraise(event: 'a', primary: primary_joy, secondary: secondary_high) }
|
|
134
|
+
engine.appraise(event: 'b', primary: primary_threat, secondary: secondary_low)
|
|
135
|
+
pattern = engine.emotional_pattern
|
|
136
|
+
expect(pattern.first.first).to eq(:joy)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it 'returns empty hash when no appraisals' do
|
|
140
|
+
expect(engine.emotional_pattern).to eq({})
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe '#decay_all' do
|
|
145
|
+
it 'reduces intensity for all appraisals' do
|
|
146
|
+
rec = engine.appraise(event: 'test', primary: primary_joy, secondary: secondary_high)
|
|
147
|
+
engine.decay_all
|
|
148
|
+
expect(rec.intensity).to be < 0.5
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
describe '#to_h' do
|
|
153
|
+
it 'returns hash with appraisals, coping_strategies, history_size' do
|
|
154
|
+
engine.appraise(event: 'test', primary: primary_joy, secondary: secondary_high)
|
|
155
|
+
result = engine.to_h
|
|
156
|
+
expect(result).to have_key(:appraisals)
|
|
157
|
+
expect(result).to have_key(:coping_strategies)
|
|
158
|
+
expect(result).to have_key(:history_size)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::Appraisal::Helpers::Appraisal do
|
|
4
|
+
let(:primary_low) { { relevance: 0.2, goal_congruence: 0.2, goal_importance: 0.5 } }
|
|
5
|
+
let(:primary_high) { { relevance: 0.8, goal_congruence: 0.8, goal_importance: 0.9 } }
|
|
6
|
+
let(:secondary_low) { { coping_potential: 0.2, control_expectation: 0.3, future_expectancy: 0.4 } }
|
|
7
|
+
let(:secondary_high) { { coping_potential: 0.8, control_expectation: 0.7, future_expectancy: 0.6 } }
|
|
8
|
+
|
|
9
|
+
def build(primary: primary_high, secondary: secondary_high, domain: 'work')
|
|
10
|
+
described_class.new(event: 'test event', primary: primary, secondary: secondary, domain: domain)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#initialize' do
|
|
14
|
+
it 'sets id, event, domain' do
|
|
15
|
+
appraisal = build
|
|
16
|
+
expect(appraisal.id).to be_a(String)
|
|
17
|
+
expect(appraisal.event).to eq('test event')
|
|
18
|
+
expect(appraisal.domain).to eq('work')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'normalizes primary dimensions' do
|
|
22
|
+
appraisal = build
|
|
23
|
+
expect(appraisal.primary.keys).to contain_exactly(:relevance, :goal_congruence, :goal_importance)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'normalizes secondary dimensions' do
|
|
27
|
+
appraisal = build
|
|
28
|
+
expect(appraisal.secondary.keys).to contain_exactly(:coping_potential, :control_expectation, :future_expectancy)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'clamps out-of-range values' do
|
|
32
|
+
appraisal = described_class.new(
|
|
33
|
+
event: 'e',
|
|
34
|
+
primary: { relevance: 2.0, goal_congruence: -0.5, goal_importance: 0.5 },
|
|
35
|
+
secondary: secondary_high
|
|
36
|
+
)
|
|
37
|
+
expect(appraisal.primary[:relevance]).to eq(1.0)
|
|
38
|
+
expect(appraisal.primary[:goal_congruence]).to eq(0.0)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'sets default intensity' do
|
|
42
|
+
expect(build.intensity).to eq(0.5)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'sets reappraised to false' do
|
|
46
|
+
expect(build.reappraised).to be(false)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe '#compute_emotion' do
|
|
51
|
+
it 'returns :indifference when relevance is low' do
|
|
52
|
+
appraisal = described_class.new(
|
|
53
|
+
event: 'e',
|
|
54
|
+
primary: { relevance: 0.2, goal_congruence: 0.5, goal_importance: 0.5 },
|
|
55
|
+
secondary: secondary_high
|
|
56
|
+
)
|
|
57
|
+
expect(appraisal.emotional_outcome).to eq(:indifference)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'returns :anxiety for threat with low coping' do
|
|
61
|
+
appraisal = described_class.new(
|
|
62
|
+
event: 'e',
|
|
63
|
+
primary: { relevance: 0.9, goal_congruence: 0.3, goal_importance: 0.8 },
|
|
64
|
+
secondary: { coping_potential: 0.2, control_expectation: 0.3, future_expectancy: 0.4 }
|
|
65
|
+
)
|
|
66
|
+
expect(appraisal.emotional_outcome).to eq(:anxiety)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'returns :challenge for threat with high coping' do
|
|
70
|
+
appraisal = described_class.new(
|
|
71
|
+
event: 'e',
|
|
72
|
+
primary: { relevance: 0.9, goal_congruence: 0.3, goal_importance: 0.8 },
|
|
73
|
+
secondary: { coping_potential: 0.8, control_expectation: 0.7, future_expectancy: 0.6 }
|
|
74
|
+
)
|
|
75
|
+
expect(appraisal.emotional_outcome).to eq(:challenge)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'returns :anger for very low goal_congruence' do
|
|
79
|
+
appraisal = described_class.new(
|
|
80
|
+
event: 'e',
|
|
81
|
+
primary: { relevance: 0.9, goal_congruence: 0.2, goal_importance: 0.8 },
|
|
82
|
+
secondary: { coping_potential: 0.5, control_expectation: 0.5, future_expectancy: 0.5 }
|
|
83
|
+
)
|
|
84
|
+
expect(appraisal.emotional_outcome).to eq(:anger)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'returns :joy for high goal_congruence' do
|
|
88
|
+
appraisal = described_class.new(
|
|
89
|
+
event: 'e',
|
|
90
|
+
primary: { relevance: 0.9, goal_congruence: 0.9, goal_importance: 0.8 },
|
|
91
|
+
secondary: secondary_high
|
|
92
|
+
)
|
|
93
|
+
expect(appraisal.emotional_outcome).to eq(:joy)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'returns :sadness as fallback' do
|
|
97
|
+
appraisal = described_class.new(
|
|
98
|
+
event: 'e',
|
|
99
|
+
primary: { relevance: 0.9, goal_congruence: 0.5, goal_importance: 0.5 },
|
|
100
|
+
secondary: { coping_potential: 0.5, control_expectation: 0.5, future_expectancy: 0.5 }
|
|
101
|
+
)
|
|
102
|
+
expect(appraisal.emotional_outcome).to eq(:sadness)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe '#reappraise' do
|
|
107
|
+
it 'updates emotion and reduces intensity' do
|
|
108
|
+
appraisal = described_class.new(
|
|
109
|
+
event: 'e', primary: primary_low, secondary: secondary_low
|
|
110
|
+
)
|
|
111
|
+
original_intensity = appraisal.intensity
|
|
112
|
+
appraisal.reappraise(new_primary: primary_high, new_secondary: secondary_high)
|
|
113
|
+
expect(appraisal.reappraised).to be(true)
|
|
114
|
+
expect(appraisal.intensity).to be < original_intensity
|
|
115
|
+
expect(appraisal.reappraised_at).not_to be_nil
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'recomputes emotional_outcome' do
|
|
119
|
+
appraisal = described_class.new(
|
|
120
|
+
event: 'e',
|
|
121
|
+
primary: { relevance: 0.2, goal_congruence: 0.5, goal_importance: 0.5 },
|
|
122
|
+
secondary: secondary_high
|
|
123
|
+
)
|
|
124
|
+
expect(appraisal.emotional_outcome).to eq(:indifference)
|
|
125
|
+
appraisal.reappraise(
|
|
126
|
+
new_primary: { relevance: 0.9, goal_congruence: 0.9, goal_importance: 0.8 },
|
|
127
|
+
new_secondary: secondary_high
|
|
128
|
+
)
|
|
129
|
+
expect(appraisal.emotional_outcome).to eq(:joy)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it 'applies REAPPRAISAL_DISCOUNT to intensity' do
|
|
133
|
+
appraisal = build
|
|
134
|
+
appraisal.reappraise(new_primary: primary_high, new_secondary: secondary_high)
|
|
135
|
+
expected = 0.5 * (1 - Legion::Extensions::Agentic::Affect::Appraisal::Helpers::Constants::REAPPRAISAL_DISCOUNT)
|
|
136
|
+
expect(appraisal.intensity).to be_within(0.001).of(expected)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
describe '#decay!' do
|
|
141
|
+
it 'reduces intensity by DECAY_RATE' do
|
|
142
|
+
appraisal = build
|
|
143
|
+
appraisal.decay!
|
|
144
|
+
expected = 0.5 - Legion::Extensions::Agentic::Affect::Appraisal::Helpers::Constants::DECAY_RATE
|
|
145
|
+
expect(appraisal.intensity).to be_within(0.001).of(expected)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it 'does not go below INTENSITY_FLOOR' do
|
|
149
|
+
appraisal = described_class.new(
|
|
150
|
+
event: 'e',
|
|
151
|
+
primary: { relevance: 0.9, goal_congruence: 0.9, goal_importance: 0.9 },
|
|
152
|
+
secondary: secondary_high
|
|
153
|
+
)
|
|
154
|
+
60.times { appraisal.decay! }
|
|
155
|
+
expect(appraisal.intensity).to eq(0.0)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
describe '#assign_coping' do
|
|
160
|
+
it 'sets coping_strategy' do
|
|
161
|
+
appraisal = build
|
|
162
|
+
appraisal.assign_coping('reframing')
|
|
163
|
+
expect(appraisal.coping_strategy).to eq('reframing')
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
describe '#to_h' do
|
|
168
|
+
it 'returns a hash with expected keys' do
|
|
169
|
+
appraisal = build
|
|
170
|
+
keys = appraisal.to_h.keys
|
|
171
|
+
expect(keys).to include(:id, :event, :domain, :primary, :secondary, :emotional_outcome,
|
|
172
|
+
:intensity, :coping_strategy, :reappraised, :created_at, :reappraised_at)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::Appraisal::Helpers::Constants do
|
|
4
|
+
let(:mod) { described_class }
|
|
5
|
+
|
|
6
|
+
it 'defines MAX_APPRAISALS' do
|
|
7
|
+
expect(mod::MAX_APPRAISALS).to eq(200)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'defines MAX_COPING_STRATEGIES' do
|
|
11
|
+
expect(mod::MAX_COPING_STRATEGIES).to eq(50)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'defines MAX_HISTORY' do
|
|
15
|
+
expect(mod::MAX_HISTORY).to eq(300)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'defines intensity bounds' do
|
|
19
|
+
expect(mod::INTENSITY_FLOOR).to eq(0.0)
|
|
20
|
+
expect(mod::INTENSITY_CEILING).to eq(1.0)
|
|
21
|
+
expect(mod::DEFAULT_INTENSITY).to eq(0.5)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'defines DECAY_RATE' do
|
|
25
|
+
expect(mod::DECAY_RATE).to eq(0.02)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'defines REAPPRAISAL_DISCOUNT' do
|
|
29
|
+
expect(mod::REAPPRAISAL_DISCOUNT).to eq(0.3)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'defines PRIMARY_DIMENSIONS' do
|
|
33
|
+
expect(mod::PRIMARY_DIMENSIONS).to contain_exactly(:relevance, :goal_congruence, :goal_importance)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'defines SECONDARY_DIMENSIONS' do
|
|
37
|
+
expect(mod::SECONDARY_DIMENSIONS).to contain_exactly(:coping_potential, :control_expectation, :future_expectancy)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'maps APPRAISAL_EMOTIONS' do
|
|
41
|
+
expect(mod::APPRAISAL_EMOTIONS[:threat_low_coping]).to eq(:anxiety)
|
|
42
|
+
expect(mod::APPRAISAL_EMOTIONS[:goal_congruent]).to eq(:joy)
|
|
43
|
+
expect(mod::APPRAISAL_EMOTIONS[:irrelevant]).to eq(:indifference)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'defines COPING_TYPES' do
|
|
47
|
+
expect(mod::COPING_TYPES).to include(:problem_focused, :emotion_focused, :meaning_focused)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/agentic/affect/appraisal/client'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::Appraisal::Runners::Appraisal do
|
|
6
|
+
let(:client) { Legion::Extensions::Agentic::Affect::Appraisal::Client.new }
|
|
7
|
+
|
|
8
|
+
let(:primary_joy) { { relevance: 0.9, goal_congruence: 0.9, goal_importance: 0.8 } }
|
|
9
|
+
let(:primary_threat) { { relevance: 0.9, goal_congruence: 0.3, goal_importance: 0.8 } }
|
|
10
|
+
let(:secondary_low) { { coping_potential: 0.2, control_expectation: 0.3, future_expectancy: 0.4 } }
|
|
11
|
+
let(:secondary_high) { { coping_potential: 0.8, control_expectation: 0.7, future_expectancy: 0.6 } }
|
|
12
|
+
|
|
13
|
+
describe '#appraise_event' do
|
|
14
|
+
it 'returns success: true with an appraisal' do
|
|
15
|
+
result = client.appraise_event(event: 'deadline', primary: primary_joy, secondary: secondary_high)
|
|
16
|
+
expect(result[:success]).to be(true)
|
|
17
|
+
expect(result[:appraisal]).to include(:id, :emotional_outcome)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'assigns emotional_outcome based on appraisal pattern' do
|
|
21
|
+
result = client.appraise_event(event: 'win', primary: primary_joy, secondary: secondary_high)
|
|
22
|
+
expect(result[:appraisal][:emotional_outcome]).to eq(:joy)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'accepts optional domain' do
|
|
26
|
+
result = client.appraise_event(event: 'test', primary: primary_joy, secondary: secondary_high,
|
|
27
|
+
domain: 'work')
|
|
28
|
+
expect(result[:appraisal][:domain]).to eq('work')
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe '#reappraise_event' do
|
|
33
|
+
it 'updates existing appraisal' do
|
|
34
|
+
appraisal_id = client.appraise_event(event: 'e', primary: primary_threat,
|
|
35
|
+
secondary: secondary_low)[:appraisal][:id]
|
|
36
|
+
result = client.reappraise_event(appraisal_id: appraisal_id, new_primary: primary_joy,
|
|
37
|
+
new_secondary: secondary_high)
|
|
38
|
+
expect(result[:success]).to be(true)
|
|
39
|
+
expect(result[:appraisal][:reappraised]).to be(true)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'returns failure for unknown id' do
|
|
43
|
+
result = client.reappraise_event(appraisal_id: 'unknown', new_primary: primary_joy,
|
|
44
|
+
new_secondary: secondary_high)
|
|
45
|
+
expect(result[:success]).to be(false)
|
|
46
|
+
expect(result[:error]).to include('not found')
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe '#select_coping_strategy' do
|
|
51
|
+
it 'assigns a coping strategy to the appraisal' do
|
|
52
|
+
appraisal_id = client.appraise_event(event: 'e', primary: primary_threat,
|
|
53
|
+
secondary: secondary_low)[:appraisal][:id]
|
|
54
|
+
result = client.select_coping_strategy(appraisal_id: appraisal_id, coping_type: :problem_focused)
|
|
55
|
+
expect(result[:success]).to be(true)
|
|
56
|
+
expect(result[:appraisal][:coping_strategy]).not_to be_nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'returns failure for unknown appraisal' do
|
|
60
|
+
result = client.select_coping_strategy(appraisal_id: 'unknown', coping_type: :problem_focused)
|
|
61
|
+
expect(result[:success]).to be(false)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe '#add_coping_strategy' do
|
|
66
|
+
it 'registers a strategy' do
|
|
67
|
+
result = client.add_coping_strategy(name: 'journaling', coping_type: :emotion_focused,
|
|
68
|
+
effectiveness: 0.75)
|
|
69
|
+
expect(result[:success]).to be(true)
|
|
70
|
+
expect(result[:name]).to eq('journaling')
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe '#evaluate_coping' do
|
|
75
|
+
it 'returns effectiveness for an appraisal with coping' do
|
|
76
|
+
client.add_coping_strategy(name: 'breathing', coping_type: :emotion_focused, effectiveness: 0.8)
|
|
77
|
+
appraisal_id = client.appraise_event(event: 'e', primary: primary_threat,
|
|
78
|
+
secondary: secondary_low)[:appraisal][:id]
|
|
79
|
+
client.select_coping_strategy(appraisal_id: appraisal_id, coping_type: :emotion_focused)
|
|
80
|
+
result = client.evaluate_coping(appraisal_id: appraisal_id)
|
|
81
|
+
expect(result[:success]).to be(true)
|
|
82
|
+
expect(result[:effectiveness]).to be_a(Float)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe '#emotional_pattern' do
|
|
87
|
+
it 'returns success with pattern hash' do
|
|
88
|
+
client.appraise_event(event: 'a', primary: primary_joy, secondary: secondary_high)
|
|
89
|
+
client.appraise_event(event: 'b', primary: primary_joy, secondary: secondary_high)
|
|
90
|
+
result = client.emotional_pattern
|
|
91
|
+
expect(result[:success]).to be(true)
|
|
92
|
+
expect(result[:pattern]).to be_a(Hash)
|
|
93
|
+
expect(result[:pattern][:joy]).to eq(2)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe '#update_appraisal' do
|
|
98
|
+
it 'runs decay and returns success' do
|
|
99
|
+
client.appraise_event(event: 'e', primary: primary_joy, secondary: secondary_high)
|
|
100
|
+
result = client.update_appraisal
|
|
101
|
+
expect(result[:success]).to be(true)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe '#appraisal_stats' do
|
|
106
|
+
it 'returns stats hash with totals' do
|
|
107
|
+
client.appraise_event(event: 'a', primary: primary_joy, secondary: secondary_high)
|
|
108
|
+
client.appraise_event(event: 'b', primary: primary_threat, secondary: secondary_low)
|
|
109
|
+
result = client.appraisal_stats
|
|
110
|
+
expect(result[:success]).to be(true)
|
|
111
|
+
expect(result[:total]).to eq(2)
|
|
112
|
+
expect(result[:unresolved]).to eq(2)
|
|
113
|
+
expect(result[:history_size]).to be >= 2
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Affect::CognitiveEmpathy::Client do
|
|
4
|
+
subject(:client) { described_class.new }
|
|
5
|
+
|
|
6
|
+
it 'full lifecycle: take perspective, record outcome, check accuracy, stats' do
|
|
7
|
+
p1 = client.take_empathic_perspective(
|
|
8
|
+
agent_id: :person_a,
|
|
9
|
+
perspective_type: :cognitive,
|
|
10
|
+
predicted_state: { valence: 0.7, arousal: 0.4 },
|
|
11
|
+
confidence: 0.8
|
|
12
|
+
)
|
|
13
|
+
expect(p1[:success]).to be true
|
|
14
|
+
perspective_id = p1[:perspective_id]
|
|
15
|
+
|
|
16
|
+
outcome = client.record_empathic_outcome(
|
|
17
|
+
perspective_id: perspective_id,
|
|
18
|
+
actual_state: { valence: 0.7, arousal: 0.4 }
|
|
19
|
+
)
|
|
20
|
+
expect(outcome[:success]).to be true
|
|
21
|
+
|
|
22
|
+
acc = client.empathic_accuracy_for(agent_id: :person_a)
|
|
23
|
+
expect(acc[:accuracy]).to be_a(Float)
|
|
24
|
+
|
|
25
|
+
client.apply_emotional_contagion(emotion_valence: 0.8, intensity: 0.6)
|
|
26
|
+
state = client.current_empathic_state
|
|
27
|
+
expect(Legion::Extensions::Agentic::Affect::CognitiveEmpathy::Helpers::Constants::EMPATHIC_STATES)
|
|
28
|
+
.to include(state[:empathic_state])
|
|
29
|
+
|
|
30
|
+
stats = client.cognitive_empathy_stats
|
|
31
|
+
expect(stats[:perspective_count]).to eq(1)
|
|
32
|
+
expect(stats[:resolved_count]).to eq(1)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'accepts an injected engine' do
|
|
36
|
+
engine = Legion::Extensions::Agentic::Affect::CognitiveEmpathy::Helpers::EmpathyEngine.new
|
|
37
|
+
c = described_class.new(engine: engine)
|
|
38
|
+
c.take_empathic_perspective(
|
|
39
|
+
agent_id: :bob,
|
|
40
|
+
perspective_type: :affective,
|
|
41
|
+
predicted_state: {},
|
|
42
|
+
confidence: 0.5
|
|
43
|
+
)
|
|
44
|
+
expect(engine.perspectives.size).to eq(1)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'blind spots returns nil agents on fresh client' do
|
|
48
|
+
result = client.empathic_blind_spots
|
|
49
|
+
expect(result[:success]).to be true
|
|
50
|
+
expect(result[:least_accurate_agent]).to be_nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'overall accuracy is at default on fresh client' do
|
|
54
|
+
result = client.overall_empathic_accuracy
|
|
55
|
+
expect(result[:accuracy]).to eq(Legion::Extensions::Agentic::Affect::CognitiveEmpathy::Helpers::Constants::DEFAULT_ACCURACY)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'perspectives_for_agent returns empty list for unknown agent' do
|
|
59
|
+
result = client.perspectives_for_agent(agent_id: :ghost)
|
|
60
|
+
expect(result[:count]).to eq(0)
|
|
61
|
+
end
|
|
62
|
+
end
|