lex-somatic-marker 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/Gemfile +12 -0
- data/LICENSE +21 -0
- data/README.md +61 -0
- data/lex-somatic-marker.gemspec +29 -0
- data/lib/legion/extensions/somatic_marker/actors/decay.rb +41 -0
- data/lib/legion/extensions/somatic_marker/client.rb +25 -0
- data/lib/legion/extensions/somatic_marker/helpers/body_state.rb +65 -0
- data/lib/legion/extensions/somatic_marker/helpers/constants.rb +39 -0
- data/lib/legion/extensions/somatic_marker/helpers/marker_store.rb +156 -0
- data/lib/legion/extensions/somatic_marker/helpers/somatic_marker.rb +70 -0
- data/lib/legion/extensions/somatic_marker/runners/somatic_marker.rb +128 -0
- data/lib/legion/extensions/somatic_marker/version.rb +9 -0
- data/lib/legion/extensions/somatic_marker.rb +16 -0
- data/spec/legion/extensions/somatic_marker/client_spec.rb +83 -0
- data/spec/legion/extensions/somatic_marker/helpers/body_state_spec.rb +155 -0
- data/spec/legion/extensions/somatic_marker/helpers/marker_store_spec.rb +233 -0
- data/spec/legion/extensions/somatic_marker/helpers/somatic_marker_spec.rb +172 -0
- data/spec/legion/extensions/somatic_marker/runners/somatic_marker_spec.rb +181 -0
- data/spec/spec_helper.rb +33 -0
- metadata +79 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/somatic_marker/client'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Legion::Extensions::SomaticMarker::Runners::SomaticMarker do
|
|
6
|
+
let(:client) { Legion::Extensions::SomaticMarker::Client.new }
|
|
7
|
+
|
|
8
|
+
describe '#register_marker' do
|
|
9
|
+
it 'returns success: true with marker hash' do
|
|
10
|
+
result = client.register_marker(action: :deploy, domain: :ops, valence: 0.7)
|
|
11
|
+
expect(result[:success]).to be true
|
|
12
|
+
expect(result[:marker]).to include(:id, :action, :domain, :valence)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'returns success: false on error' do
|
|
16
|
+
allow(client).to receive(:store).and_raise(StandardError, 'boom')
|
|
17
|
+
result = client.register_marker(action: :deploy, domain: :ops, valence: 0.7)
|
|
18
|
+
expect(result[:success]).to be false
|
|
19
|
+
expect(result[:error]).to eq('boom')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'accepts extra keyword args via **' do
|
|
23
|
+
result = client.register_marker(action: :deploy, domain: :ops, valence: 0.5, extra: 'ignored')
|
|
24
|
+
expect(result[:success]).to be true
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe '#evaluate_option' do
|
|
29
|
+
it 'returns success: true with signal' do
|
|
30
|
+
result = client.evaluate_option(action: :deploy, domain: :ops)
|
|
31
|
+
expect(result[:success]).to be true
|
|
32
|
+
expect(result[:signal]).to be_a(Symbol)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'returns neutral when no markers exist' do
|
|
36
|
+
result = client.evaluate_option(action: :unknown_action, domain: :unknown_domain)
|
|
37
|
+
expect(result[:signal]).to eq(:neutral)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'returns approach after registering positive marker' do
|
|
41
|
+
client.register_marker(action: :submit, domain: :forms, valence: 0.9)
|
|
42
|
+
result = client.evaluate_option(action: :submit, domain: :forms)
|
|
43
|
+
expect(result[:signal]).to eq(:approach)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '#make_decision' do
|
|
48
|
+
it 'returns success: true with ranked options' do
|
|
49
|
+
client.register_marker(action: :approve, domain: :risk, valence: 0.8)
|
|
50
|
+
client.register_marker(action: :reject, domain: :risk, valence: -0.8)
|
|
51
|
+
|
|
52
|
+
result = client.make_decision(options: %i[approve reject], domain: :risk)
|
|
53
|
+
expect(result[:success]).to be true
|
|
54
|
+
expect(result[:decision][:ranked]).to be_an(Array)
|
|
55
|
+
expect(result[:decision][:ranked].first[:action]).to eq(:approve)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'ranks by valence descending' do
|
|
59
|
+
client.register_marker(action: :high, domain: :d, valence: 0.9)
|
|
60
|
+
client.register_marker(action: :low, domain: :d, valence: -0.5)
|
|
61
|
+
|
|
62
|
+
result = client.make_decision(options: %i[high low neutral], domain: :d)
|
|
63
|
+
valences = result[:decision][:ranked].map { |r| r[:valence] }
|
|
64
|
+
expect(valences).to eq(valences.sort.reverse)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'returns success: false on error' do
|
|
68
|
+
allow(client).to receive(:store).and_raise(StandardError, 'store_error')
|
|
69
|
+
result = client.make_decision(options: %i[a b], domain: :d)
|
|
70
|
+
expect(result[:success]).to be false
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe '#reinforce' do
|
|
75
|
+
it 'returns success: true when marker found' do
|
|
76
|
+
reg = client.register_marker(action: :deploy, domain: :ops, valence: 0.0)
|
|
77
|
+
result = client.reinforce(marker_id: reg[:marker][:id], outcome_valence: 1.0)
|
|
78
|
+
expect(result[:success]).to be true
|
|
79
|
+
expect(result[:marker][:valence]).to be > 0.0
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'returns success: false when marker not found' do
|
|
83
|
+
result = client.reinforce(marker_id: 'nonexistent', outcome_valence: 0.5)
|
|
84
|
+
expect(result[:success]).to be false
|
|
85
|
+
expect(result[:error]).to include('not found')
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe '#update_body' do
|
|
90
|
+
it 'returns success: true with updated body state' do
|
|
91
|
+
result = client.update_body(arousal: 0.8, tension: 0.7)
|
|
92
|
+
expect(result[:success]).to be true
|
|
93
|
+
expect(result[:body_state][:arousal]).to eq(0.8)
|
|
94
|
+
expect(result[:body_state][:tension]).to eq(0.7)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'accepts nil values without error' do
|
|
98
|
+
result = client.update_body(arousal: nil, tension: nil)
|
|
99
|
+
expect(result[:success]).to be true
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe '#body_state' do
|
|
104
|
+
it 'returns success: true with body state hash' do
|
|
105
|
+
result = client.body_state
|
|
106
|
+
expect(result[:success]).to be true
|
|
107
|
+
expect(result[:body_state]).to include(:arousal, :tension, :comfort, :gut_signal)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it 'reflects updates made via update_body' do
|
|
111
|
+
client.update_body(comfort: 0.9)
|
|
112
|
+
result = client.body_state
|
|
113
|
+
expect(result[:body_state][:comfort]).to eq(0.9)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe '#markers_for_action' do
|
|
118
|
+
it 'returns success: true with marker list' do
|
|
119
|
+
client.register_marker(action: :click, domain: :ui, valence: 0.3)
|
|
120
|
+
result = client.markers_for_action(action: :click, domain: :ui)
|
|
121
|
+
expect(result[:success]).to be true
|
|
122
|
+
expect(result[:count]).to eq(1)
|
|
123
|
+
expect(result[:markers].first[:action]).to eq(:click)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'returns empty list for unknown action' do
|
|
127
|
+
result = client.markers_for_action(action: :unknown, domain: :unknown)
|
|
128
|
+
expect(result[:success]).to be true
|
|
129
|
+
expect(result[:count]).to eq(0)
|
|
130
|
+
expect(result[:markers]).to be_empty
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe '#recent_decisions' do
|
|
135
|
+
it 'returns success: true with decision list' do
|
|
136
|
+
client.make_decision(options: %i[go stop], domain: :ops)
|
|
137
|
+
result = client.recent_decisions
|
|
138
|
+
expect(result[:success]).to be true
|
|
139
|
+
expect(result[:count]).to eq(1)
|
|
140
|
+
expect(result[:decisions]).to be_an(Array)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it 'respects the limit parameter' do
|
|
144
|
+
5.times { client.make_decision(options: %i[go stop], domain: :ops) }
|
|
145
|
+
result = client.recent_decisions(limit: 3)
|
|
146
|
+
expect(result[:count]).to eq(3)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
describe '#update_somatic_markers' do
|
|
151
|
+
it 'returns success: true with decay stats' do
|
|
152
|
+
client.register_marker(action: :deploy, domain: :ops, valence: 0.5)
|
|
153
|
+
result = client.update_somatic_markers
|
|
154
|
+
expect(result[:success]).to be true
|
|
155
|
+
expect(result).to have_key(:markers_decayed)
|
|
156
|
+
expect(result).to have_key(:markers_removed)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'returns success: false on error' do
|
|
160
|
+
allow(client).to receive(:store).and_raise(StandardError, 'decay_error')
|
|
161
|
+
result = client.update_somatic_markers
|
|
162
|
+
expect(result[:success]).to be false
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
describe '#somatic_marker_stats' do
|
|
167
|
+
it 'returns success: true with stats' do
|
|
168
|
+
client.register_marker(action: :deploy, domain: :ops, valence: 0.5)
|
|
169
|
+
result = client.somatic_marker_stats
|
|
170
|
+
expect(result[:success]).to be true
|
|
171
|
+
expect(result[:marker_count]).to eq(1)
|
|
172
|
+
expect(result[:decision_count]).to eq(0)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it 'reflects decision count after decisions' do
|
|
176
|
+
client.make_decision(options: %i[go stop], domain: :ops)
|
|
177
|
+
result = client.somatic_marker_stats
|
|
178
|
+
expect(result[:decision_count]).to eq(1)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Helpers
|
|
8
|
+
module Lex; end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Actors
|
|
12
|
+
class Every
|
|
13
|
+
def initialize(*); end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module Logging
|
|
19
|
+
def self.debug(_msg); end
|
|
20
|
+
def self.info(_msg); end
|
|
21
|
+
def self.warn(_msg); end
|
|
22
|
+
def self.error(_msg); end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
require 'legion/extensions/somatic_marker'
|
|
27
|
+
require 'legion/extensions/somatic_marker/client'
|
|
28
|
+
|
|
29
|
+
RSpec.configure do |config|
|
|
30
|
+
config.example_status_persistence_file_path = '.rspec_status'
|
|
31
|
+
config.disable_monkey_patching!
|
|
32
|
+
config.expect_with(:rspec) { |c| c.syntax = :expect }
|
|
33
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-somatic-marker
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Esity
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: legion-gaia
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
description: Damasio's Somatic Marker Hypothesis for brain-modeled agentic AI decision-making
|
|
27
|
+
email:
|
|
28
|
+
- matthewdiverson@gmail.com
|
|
29
|
+
executables: []
|
|
30
|
+
extensions: []
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
files:
|
|
33
|
+
- Gemfile
|
|
34
|
+
- LICENSE
|
|
35
|
+
- README.md
|
|
36
|
+
- lex-somatic-marker.gemspec
|
|
37
|
+
- lib/legion/extensions/somatic_marker.rb
|
|
38
|
+
- lib/legion/extensions/somatic_marker/actors/decay.rb
|
|
39
|
+
- lib/legion/extensions/somatic_marker/client.rb
|
|
40
|
+
- lib/legion/extensions/somatic_marker/helpers/body_state.rb
|
|
41
|
+
- lib/legion/extensions/somatic_marker/helpers/constants.rb
|
|
42
|
+
- lib/legion/extensions/somatic_marker/helpers/marker_store.rb
|
|
43
|
+
- lib/legion/extensions/somatic_marker/helpers/somatic_marker.rb
|
|
44
|
+
- lib/legion/extensions/somatic_marker/runners/somatic_marker.rb
|
|
45
|
+
- lib/legion/extensions/somatic_marker/version.rb
|
|
46
|
+
- spec/legion/extensions/somatic_marker/client_spec.rb
|
|
47
|
+
- spec/legion/extensions/somatic_marker/helpers/body_state_spec.rb
|
|
48
|
+
- spec/legion/extensions/somatic_marker/helpers/marker_store_spec.rb
|
|
49
|
+
- spec/legion/extensions/somatic_marker/helpers/somatic_marker_spec.rb
|
|
50
|
+
- spec/legion/extensions/somatic_marker/runners/somatic_marker_spec.rb
|
|
51
|
+
- spec/spec_helper.rb
|
|
52
|
+
homepage: https://github.com/LegionIO/lex-somatic-marker
|
|
53
|
+
licenses:
|
|
54
|
+
- MIT
|
|
55
|
+
metadata:
|
|
56
|
+
homepage_uri: https://github.com/LegionIO/lex-somatic-marker
|
|
57
|
+
source_code_uri: https://github.com/LegionIO/lex-somatic-marker
|
|
58
|
+
documentation_uri: https://github.com/LegionIO/lex-somatic-marker
|
|
59
|
+
changelog_uri: https://github.com/LegionIO/lex-somatic-marker
|
|
60
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-somatic-marker/issues
|
|
61
|
+
rubygems_mfa_required: 'true'
|
|
62
|
+
rdoc_options: []
|
|
63
|
+
require_paths:
|
|
64
|
+
- lib
|
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '3.4'
|
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
requirements: []
|
|
76
|
+
rubygems_version: 3.6.9
|
|
77
|
+
specification_version: 4
|
|
78
|
+
summary: LEX Somatic Marker
|
|
79
|
+
test_files: []
|