lex-salience 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2c9ffd1698dd5b992b73679b28677974b343656d2131df48d5f893eb08ef1312
4
+ data.tar.gz: a792f5c3144f2fd7af78423326620246b8a89ee48bbc17762c2b5b83abb218da
5
+ SHA512:
6
+ metadata.gz: 9566aac35355ff3119937b074d1afead3440df0625ae4128b0de8030b5e0820b23b6feb8734900ce23db8f18d0aa27b4194a64f54001a14f845aa2a46c71550f
7
+ data.tar.gz: 04aa1f807506a0514d19ca87b1edbc6fd9a3c2a8ddbb7b54ca32ab5f47cba61283658c89fa4aab123eb2b8a9a72f17444abf1634462bb23f943528873512f2a5
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Salience
6
+ class Client
7
+ include Runners::Salience
8
+
9
+ attr_reader :salience_map
10
+
11
+ def initialize(salience_map: nil, **)
12
+ @salience_map = salience_map || Helpers::SalienceMap.new
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Salience
6
+ module Helpers
7
+ module Constants
8
+ SALIENCE_SOURCES = %i[emotion mood attention curiosity homeostasis trust empathy volition].freeze
9
+
10
+ SOURCE_WEIGHTS = {
11
+ emotion: 0.20,
12
+ mood: 0.10,
13
+ attention: 0.15,
14
+ curiosity: 0.15,
15
+ homeostasis: 0.15,
16
+ trust: 0.10,
17
+ empathy: 0.05,
18
+ volition: 0.10
19
+ }.freeze
20
+
21
+ URGENCY_LEVELS = %i[critical high moderate low background].freeze
22
+
23
+ URGENCY_THRESHOLDS = {
24
+ critical: 0.9,
25
+ high: 0.7,
26
+ moderate: 0.4,
27
+ low: 0.2,
28
+ background: 0.0
29
+ }.freeze
30
+
31
+ MAX_SALIENCE_ITEMS = 10
32
+ SALIENCE_DECAY_RATE = 0.05
33
+ INTEGRATION_ALPHA = 0.3
34
+ NOVELTY_BOOST = 0.2
35
+ CONFLICT_AMPLIFIER = 1.5
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Salience
6
+ module Helpers
7
+ class SalienceMap
8
+ attr_reader :current_map, :baseline, :history
9
+
10
+ MAX_HISTORY = 50
11
+ TREND_WINDOW = 5
12
+ TREND_DELTA = 0.02
13
+
14
+ def initialize
15
+ @current_map = {}
16
+ @baseline = 0.0
17
+ @history = []
18
+ @novel_sources = {}
19
+ end
20
+
21
+ def update(integrated_signals)
22
+ @current_map = integrated_signals.transform_values { |v| v[:weighted] }
23
+ apply_novelty_boost(integrated_signals)
24
+ overall = overall_salience
25
+ @baseline = (Constants::INTEGRATION_ALPHA * overall) + ((1.0 - Constants::INTEGRATION_ALPHA) * @baseline)
26
+ snapshot = {
27
+ timestamp: Time.now.utc.to_f,
28
+ overall: overall,
29
+ urgency: urgency_level,
30
+ dominant: dominant_source,
31
+ map_snapshot: @current_map.dup
32
+ }
33
+ @history << snapshot
34
+ @history.shift while @history.size > MAX_HISTORY
35
+ snapshot
36
+ end
37
+
38
+ def overall_salience
39
+ @current_map.values.sum.round(6)
40
+ end
41
+
42
+ def urgency_level
43
+ score = overall_salience
44
+ Constants::URGENCY_LEVELS.find do |level|
45
+ score >= Constants::URGENCY_THRESHOLDS[level]
46
+ end || :background
47
+ end
48
+
49
+ def dominant_source
50
+ return nil if @current_map.empty?
51
+
52
+ @current_map.max_by { |_k, v| v }&.first
53
+ end
54
+
55
+ def above_baseline?
56
+ overall_salience > @baseline
57
+ end
58
+
59
+ def conflict_signals
60
+ values = @current_map.values
61
+ return [] if values.size < 2
62
+
63
+ pairs = []
64
+ keys = @current_map.keys
65
+ keys.each_with_index do |key_a, i|
66
+ keys[(i + 1)..].each do |key_b|
67
+ diff = (@current_map[key_a] - @current_map[key_b]).abs
68
+ pairs << [key_a, key_b] if diff > 0.3
69
+ end
70
+ end
71
+ pairs
72
+ end
73
+
74
+ def salience_trend
75
+ return :stable if @history.size < 2
76
+
77
+ window = @history.last([TREND_WINDOW, @history.size].min).map { |h| h[:overall] }
78
+ delta = window.last - window.first
79
+ if delta > TREND_DELTA
80
+ :rising
81
+ elsif delta < -TREND_DELTA
82
+ :falling
83
+ else
84
+ :stable
85
+ end
86
+ end
87
+
88
+ def to_h
89
+ {
90
+ current_map: @current_map,
91
+ overall: overall_salience,
92
+ baseline: @baseline,
93
+ urgency: urgency_level,
94
+ dominant: dominant_source,
95
+ above_baseline: above_baseline?,
96
+ conflicts: conflict_signals,
97
+ trend: salience_trend,
98
+ history_size: @history.size
99
+ }
100
+ end
101
+
102
+ private
103
+
104
+ def apply_novelty_boost(integrated_signals)
105
+ integrated_signals.each_key do |source|
106
+ next if @novel_sources.key?(source)
107
+
108
+ @novel_sources[source] = true
109
+ current = @current_map[source] || 0.0
110
+ boosted = [current + Constants::NOVELTY_BOOST, 1.0].min
111
+ @current_map[source] = boosted
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Salience
6
+ module Helpers
7
+ module SignalIntegrator
8
+ module_function
9
+
10
+ def integrate(tick_results: {})
11
+ Constants::SALIENCE_SOURCES.each_with_object({}) do |source, result|
12
+ data = tick_results.fetch(source, {}) || {}
13
+ raw = extract_raw(source, data)
14
+ weight = Constants::SOURCE_WEIGHTS.fetch(source, 0.0)
15
+
16
+ result[source] = {
17
+ raw_salience: raw,
18
+ weighted: (raw * weight).round(6),
19
+ signal_data: data
20
+ }
21
+ end
22
+ end
23
+
24
+ def extract_raw(source, data)
25
+ case source
26
+ when :emotion then extract_emotion(data)
27
+ when :mood then extract_mood(data)
28
+ when :attention then extract_attention(data)
29
+ when :curiosity then extract_curiosity(data)
30
+ when :homeostasis then extract_homeostasis(data)
31
+ when :trust then extract_trust(data)
32
+ when :empathy then extract_empathy(data)
33
+ when :volition then extract_volition(data)
34
+ else 0.0
35
+ end
36
+ end
37
+
38
+ def extract_emotion(data)
39
+ arousal = (data[:arousal] || 0.0).to_f
40
+ gut_strength = (data[:gut_strength] || 0.0).to_f
41
+ clamp([arousal, gut_strength].max)
42
+ end
43
+
44
+ def extract_mood(data)
45
+ stability = (data[:stability] || 1.0).to_f
46
+ clamp(1.0 - stability)
47
+ end
48
+
49
+ def extract_attention(data)
50
+ spotlight_count = (data[:spotlight_count] || 0).to_f
51
+ total = [(data[:total] || 0).to_f, 1.0].max
52
+ clamp(spotlight_count / total)
53
+ end
54
+
55
+ def extract_curiosity(data)
56
+ top_salience = (data[:top_salience] || 0.0).to_f
57
+ clamp(top_salience)
58
+ end
59
+
60
+ def extract_homeostasis(data)
61
+ worst_deviation = (data[:worst_deviation] || 0.0).to_f
62
+ clamp(worst_deviation)
63
+ end
64
+
65
+ def extract_trust(data)
66
+ violation_count = (data[:violation_count] || 0).to_f
67
+ clamp(violation_count * 0.3)
68
+ end
69
+
70
+ EMPATHY_CLIMATE_SCORES = {
71
+ adversarial: 1.0,
72
+ tense: 0.5,
73
+ neutral: 0.1,
74
+ harmonious: 0.0
75
+ }.freeze
76
+
77
+ def extract_empathy(data)
78
+ EMPATHY_CLIMATE_SCORES.fetch(data[:climate], 0.0)
79
+ end
80
+
81
+ def extract_volition(data)
82
+ intention_salience = (data[:intention_salience] || 0.0).to_f
83
+ clamp(intention_salience)
84
+ end
85
+
86
+ def clamp(value, min = 0.0, max = 1.0)
87
+ value.clamp(min, max)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Salience
6
+ module Runners
7
+ module Salience
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex)
10
+
11
+ def compute_salience(tick_results: {}, **)
12
+ integrated = Helpers::SignalIntegrator.integrate(tick_results: tick_results)
13
+ salience_map.update(integrated)
14
+
15
+ Legion::Logging.debug "[salience] compute: overall=#{salience_map.overall_salience.round(3)} " \
16
+ "urgency=#{salience_map.urgency_level} dominant=#{salience_map.dominant_source}"
17
+
18
+ {
19
+ overall: salience_map.overall_salience,
20
+ urgency: salience_map.urgency_level,
21
+ dominant_source: salience_map.dominant_source,
22
+ above_baseline: salience_map.above_baseline?,
23
+ conflicts: salience_map.conflict_signals,
24
+ sources: integrated,
25
+ trend: salience_map.salience_trend
26
+ }
27
+ end
28
+
29
+ def salience_status(**)
30
+ Legion::Logging.debug "[salience] status: urgency=#{salience_map.urgency_level} trend=#{salience_map.salience_trend}"
31
+ {
32
+ overall: salience_map.overall_salience,
33
+ urgency: salience_map.urgency_level,
34
+ dominant: salience_map.dominant_source,
35
+ baseline: salience_map.baseline,
36
+ trend: salience_map.salience_trend,
37
+ above_baseline: salience_map.above_baseline?
38
+ }
39
+ end
40
+
41
+ def salience_for(source:, **)
42
+ data = salience_map.current_map[source]
43
+ Legion::Logging.debug "[salience] salience_for: source=#{source} salience=#{data || 0.0}"
44
+ { source: source, salience: data || 0.0, urgency: salience_map.urgency_level }
45
+ end
46
+
47
+ def salience_history(limit: 10, **)
48
+ { entries: salience_map.history.last(limit) }
49
+ end
50
+
51
+ def salience_stats(**)
52
+ {
53
+ overall: salience_map.overall_salience,
54
+ baseline: salience_map.baseline,
55
+ urgency: salience_map.urgency_level,
56
+ dominant: salience_map.dominant_source,
57
+ history_size: salience_map.history.size,
58
+ conflict_count: salience_map.conflict_signals.size,
59
+ trend: salience_map.salience_trend
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Salience
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/salience/version'
4
+ require 'legion/extensions/salience/helpers/constants'
5
+ require 'legion/extensions/salience/helpers/signal_integrator'
6
+ require 'legion/extensions/salience/helpers/salience_map'
7
+ require 'legion/extensions/salience/runners/salience'
8
+ require 'legion/extensions/salience/client'
9
+
10
+ module Legion
11
+ module Extensions
12
+ module Salience
13
+ extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
14
+ end
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lex-salience
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: Unified salience network for brain-modeled agentic AI — integrates signals
27
+ from all cognitive subsystems
28
+ email:
29
+ - matthewdiverson@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/legion/extensions/salience.rb
35
+ - lib/legion/extensions/salience/client.rb
36
+ - lib/legion/extensions/salience/helpers/constants.rb
37
+ - lib/legion/extensions/salience/helpers/salience_map.rb
38
+ - lib/legion/extensions/salience/helpers/signal_integrator.rb
39
+ - lib/legion/extensions/salience/runners/salience.rb
40
+ - lib/legion/extensions/salience/version.rb
41
+ homepage: https://github.com/LegionIO/lex-salience
42
+ licenses:
43
+ - MIT
44
+ metadata:
45
+ homepage_uri: https://github.com/LegionIO/lex-salience
46
+ source_code_uri: https://github.com/LegionIO/lex-salience
47
+ documentation_uri: https://github.com/LegionIO/lex-salience
48
+ changelog_uri: https://github.com/LegionIO/lex-salience
49
+ bug_tracker_uri: https://github.com/LegionIO/lex-salience/issues
50
+ rubygems_mfa_required: 'true'
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '3.4'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.6.9
66
+ specification_version: 4
67
+ summary: LEX Salience
68
+ test_files: []