lex-attention-schema 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: 26066d98d084abc8e93fce8bfe09e7ef1e5c9ce0f26178264c869700de98f425
4
+ data.tar.gz: 2e9e273d38e278b3798d426c778fe030e4819edd1197a8ecf88f7ced1f16d64e
5
+ SHA512:
6
+ metadata.gz: 856518fd4426d3a60e16a1616c054225fa949e7ad839da093f07c321dd538e258cdbcf1c10143e84b57a808f0cc62619a1c9731ccaff71d1e5cc4733e374f258
7
+ data.tar.gz: 99e3002b9ee3cb8260cdec4d4c3a144c0949d43327a889144209ebf57cdcbb126b1b8ea383bb658f5f4cb40c8e859bda546329751a6498f81df6dec5e2bd21e1
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ gem 'rspec', '~> 3.13'
8
+ gem 'rubocop', '~> 1.75', require: false
9
+ gem 'rubocop-rspec', require: false
10
+
11
+ gem 'legion-gaia', path: '../../legion-gaia'
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/legion/extensions/attention_schema/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'lex-attention-schema'
7
+ spec.version = Legion::Extensions::AttentionSchema::VERSION
8
+ spec.authors = ['Esity']
9
+ spec.email = ['matthewdiverson@gmail.com']
10
+
11
+ spec.summary = 'LEX Attention Schema'
12
+ spec.description = "Graziano's Attention Schema Theory for brain-modeled agentic AI — the agent " \
13
+ 'maintains a simplified internal model of its own attention process, enabling ' \
14
+ 'awareness attribution, social attention modeling, meta-attention monitoring, ' \
15
+ 'and natural-language attention reports.'
16
+ spec.homepage = 'https://github.com/LegionIO/lex-attention-schema'
17
+ spec.license = 'MIT'
18
+ spec.required_ruby_version = '>= 3.4'
19
+
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-attention-schema'
22
+ spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-attention-schema'
23
+ spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-attention-schema'
24
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-attention-schema/issues'
25
+ spec.metadata['rubygems_mfa_required'] = 'true'
26
+
27
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
28
+ Dir.glob('{lib,spec}/**/*') + %w[lex-attention-schema.gemspec Gemfile]
29
+ end
30
+ spec.require_paths = ['lib']
31
+ spec.add_development_dependency 'legion-gaia'
32
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/actors/every'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module AttentionSchema
8
+ module Actor
9
+ class Decay < Legion::Extensions::Actors::Every
10
+ def runner_class
11
+ Legion::Extensions::AttentionSchema::Runners::AttentionSchema
12
+ end
13
+
14
+ def runner_function
15
+ 'decay_schema'
16
+ end
17
+
18
+ def time
19
+ 30
20
+ end
21
+
22
+ def run_now?
23
+ false
24
+ end
25
+
26
+ def use_runner?
27
+ false
28
+ end
29
+
30
+ def check_subtask?
31
+ false
32
+ end
33
+
34
+ def generate_task?
35
+ false
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/attention_schema/helpers/constants'
4
+ require 'legion/extensions/attention_schema/helpers/schema_item'
5
+ require 'legion/extensions/attention_schema/helpers/attention_schema_model'
6
+ require 'legion/extensions/attention_schema/runners/attention_schema'
7
+
8
+ module Legion
9
+ module Extensions
10
+ module AttentionSchema
11
+ class Client
12
+ include Runners::AttentionSchema
13
+
14
+ def initialize(schema_model: nil, **)
15
+ @schema_model = schema_model || Helpers::AttentionSchemaModel.new
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :schema_model
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module AttentionSchema
6
+ module Helpers
7
+ class AttentionSchemaModel
8
+ include Constants
9
+
10
+ attr_reader :schema_items, :social_models, :meta_accuracy, :attention_history
11
+
12
+ def initialize
13
+ @schema_items = {} # target => SchemaItem
14
+ @social_models = {} # agent_id => { target:, awareness:, updated_at: }
15
+ @meta_accuracy = 0.5 # EMA confidence in schema self-accuracy
16
+ @attention_history = [] # ring buffer of { target:, event:, at: }
17
+ end
18
+
19
+ # --- Focus Management ---
20
+
21
+ # Add or boost an item in the attention schema
22
+ def focus_on(target:, domain:, reason:, source:)
23
+ target = target.to_s
24
+ if @schema_items.key?(target)
25
+ @schema_items[target].boost
26
+ record_history(target, :refocused)
27
+ else
28
+ prune_to_capacity if @schema_items.size >= MAX_SCHEMA_ITEMS
29
+ @schema_items[target] = SchemaItem.new(
30
+ target: target,
31
+ domain: domain,
32
+ reason: reason,
33
+ source: source,
34
+ awareness_level: DEFAULT_AWARENESS + AWARENESS_BOOST
35
+ )
36
+ record_history(target, :focused)
37
+ end
38
+ @schema_items[target]
39
+ end
40
+
41
+ # Remove an item from the schema entirely
42
+ def defocus(target:)
43
+ target = target.to_s
44
+ removed = @schema_items.delete(target)
45
+ record_history(target, :defocused) if removed
46
+ !removed.nil?
47
+ end
48
+
49
+ # --- Awareness Query (core AST operation) ---
50
+
51
+ # "Am I aware of X?" — the central Graziano query
52
+ def am_i_aware_of(target:)
53
+ item = @schema_items[target.to_s]
54
+ return { aware: false, awareness_level: 0.0, label: :unconscious } unless item
55
+
56
+ { aware: item.awareness_level > AWARENESS_FLOOR, awareness_level: item.awareness_level.round(4), label: item.label }
57
+ end
58
+
59
+ # --- Attention Report ---
60
+
61
+ # Natural-language-style summary of current attention state
62
+ def report_awareness
63
+ state = attention_state
64
+ state_str = ATTENTION_STATE_LABELS[state] || 'in an unknown state'
65
+ top_items = top_schema_items(3)
66
+
67
+ return { state: state, state_label: state_str, report: 'No active attention targets.', items: [] } if top_items.empty?
68
+
69
+ primary = top_items.first
70
+ summary = "I am #{state_str}, primarily attending to '#{primary[:target]}' " \
71
+ "(#{primary[:label]}, #{primary[:awareness_level]}). " \
72
+ "Reason: #{primary[:reason]}."
73
+
74
+ if top_items.size > 1
75
+ secondary = top_items[1..]
76
+ .map { |i| "'#{i[:target]}' (#{i[:label]})" }
77
+ .join(', ')
78
+ summary += " Also attending to: #{secondary}."
79
+ end
80
+
81
+ { state: state, state_label: state_str, report: summary, items: top_items }
82
+ end
83
+
84
+ # --- Attention State Classification ---
85
+
86
+ # Overall qualitative attention state
87
+ def attention_state
88
+ return :distracted if @schema_items.empty?
89
+
90
+ top = top_awareness
91
+ avg = average_awareness
92
+
93
+ if top >= HYPERFOCUS_THRESHOLD
94
+ :hyperfocused
95
+ elsif avg < DRIFT_THRESHOLD && @schema_items.size > 3
96
+ :distracted
97
+ elsif avg < DRIFT_THRESHOLD
98
+ :drifting
99
+ elsif top >= 0.6
100
+ :focused
101
+ else
102
+ :normal
103
+ end
104
+ end
105
+
106
+ # --- Social Attention Modeling ---
107
+
108
+ # Record what another agent appears to be attending to
109
+ def model_other_attention(agent_id:, target:, awareness:)
110
+ agent_id = agent_id.to_s
111
+ prune_social_models if @social_models.size >= MAX_SOCIAL_MODELS && !@social_models.key?(agent_id)
112
+ @social_models[agent_id] = {
113
+ target: target.to_s,
114
+ awareness: awareness.clamp(0.0, 1.0),
115
+ updated_at: Time.now.utc
116
+ }
117
+ end
118
+
119
+ # Query what another agent is modeled as attending to
120
+ def query_other_attention(agent_id:)
121
+ @social_models[agent_id.to_s]
122
+ end
123
+
124
+ # --- Meta-Attention ---
125
+
126
+ # Assess whether meta-attention signals are active
127
+ def meta_check
128
+ state = attention_state
129
+ signals = []
130
+
131
+ signals << :drifting if %i[drifting distracted].include?(state)
132
+ signals << :hyperfocus if state == :hyperfocused
133
+ signals << :normal if signals.empty?
134
+
135
+ top = top_awareness
136
+ avg = average_awareness
137
+
138
+ {
139
+ state: state,
140
+ signals: signals,
141
+ top_awareness: top.round(4),
142
+ avg_awareness: avg.round(4),
143
+ schema_size: @schema_items.size,
144
+ meta_accuracy: @meta_accuracy.round(4)
145
+ }
146
+ end
147
+
148
+ # Update the EMA tracking how well the schema predicted actual attention
149
+ def update_meta_accuracy(was_correct:)
150
+ correction = was_correct ? 1.0 : 0.0
151
+ @meta_accuracy += (META_ATTENTION_ALPHA * (correction - @meta_accuracy))
152
+ end
153
+
154
+ # --- Decay ---
155
+
156
+ # Apply per-tick decay to all schema items and prune faded ones
157
+ def decay_all
158
+ @schema_items.each_value(&:decay)
159
+ @schema_items.reject! { |_, item| item.faded? }
160
+ end
161
+
162
+ # --- Accessors ---
163
+
164
+ def schema_size
165
+ @schema_items.size
166
+ end
167
+
168
+ def to_h
169
+ {
170
+ state: attention_state,
171
+ state_label: ATTENTION_STATE_LABELS[attention_state],
172
+ schema_size: schema_size,
173
+ meta_accuracy: @meta_accuracy.round(4),
174
+ top_awareness: top_awareness.round(4),
175
+ avg_awareness: average_awareness.round(4),
176
+ social_models: @social_models.size,
177
+ items: @schema_items.values.map(&:to_h)
178
+ }
179
+ end
180
+
181
+ private
182
+
183
+ def top_awareness
184
+ return 0.0 if @schema_items.empty?
185
+
186
+ @schema_items.values.map(&:awareness_level).max
187
+ end
188
+
189
+ def average_awareness
190
+ return 0.0 if @schema_items.empty?
191
+
192
+ vals = @schema_items.values.map(&:awareness_level)
193
+ vals.sum / vals.size
194
+ end
195
+
196
+ def top_schema_items(n = 3)
197
+ @schema_items.values
198
+ .sort_by { |i| -i.awareness_level }
199
+ .first(n)
200
+ .map(&:to_h)
201
+ end
202
+
203
+ def prune_to_capacity
204
+ # Remove the item with the lowest awareness
205
+ weakest = @schema_items.min_by { |_, item| item.awareness_level }&.first
206
+ @schema_items.delete(weakest) if weakest
207
+ end
208
+
209
+ def prune_social_models
210
+ oldest = @social_models.min_by { |_, v| v[:updated_at] }&.first
211
+ @social_models.delete(oldest) if oldest
212
+ end
213
+
214
+ def record_history(target, event)
215
+ @attention_history << { target: target, event: event, at: Time.now.utc }
216
+ @attention_history.shift while @attention_history.size > MAX_HISTORY
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module AttentionSchema
6
+ module Helpers
7
+ module Constants
8
+ # Maximum items the schema can model simultaneously
9
+ MAX_SCHEMA_ITEMS = 15
10
+
11
+ # Maximum other agents whose attention we model socially
12
+ MAX_SOCIAL_MODELS = 10
13
+
14
+ # EMA alpha for schema update speed
15
+ SCHEMA_UPDATE_ALPHA = 0.15
16
+
17
+ # Default awareness level for newly focused items
18
+ DEFAULT_AWARENESS = 0.3
19
+
20
+ # Minimum awareness before item is pruned from schema
21
+ AWARENESS_FLOOR = 0.05
22
+
23
+ # Per-tick decay applied to all schema items
24
+ AWARENESS_DECAY = 0.02
25
+
26
+ # Awareness boost applied when re-focusing an existing item
27
+ AWARENESS_BOOST = 0.15
28
+
29
+ # Below this awareness average: attention is drifting
30
+ DRIFT_THRESHOLD = 0.3
31
+
32
+ # Above this awareness (for top item): attention is hyper-focused
33
+ HYPERFOCUS_THRESHOLD = 0.85
34
+
35
+ # EMA alpha for meta-attention accuracy tracking
36
+ META_ATTENTION_ALPHA = 0.1
37
+
38
+ # Maximum entries kept in attention history ring buffer
39
+ MAX_HISTORY = 200
40
+
41
+ # Human-readable labels keyed by awareness level range
42
+ AWARENESS_LABELS = {
43
+ (0.8..) => :vivid,
44
+ (0.6...0.8) => :clear,
45
+ (0.4...0.6) => :dim,
46
+ (0.2...0.4) => :peripheral,
47
+ (..0.2) => :unconscious
48
+ }.freeze
49
+
50
+ # Human-readable attention-state labels
51
+ ATTENTION_STATE_LABELS = {
52
+ hyperfocused: 'deeply engaged',
53
+ focused: 'actively attending',
54
+ normal: 'casually aware',
55
+ drifting: 'attention waning',
56
+ distracted: 'attention scattered'
57
+ }.freeze
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module AttentionSchema
6
+ module Helpers
7
+ class SchemaItem
8
+ include Constants
9
+
10
+ attr_reader :target, :domain, :reason, :source, :created_at
11
+ attr_accessor :awareness_level
12
+
13
+ def initialize(target:, domain:, reason:, source:, awareness_level: DEFAULT_AWARENESS)
14
+ @target = target
15
+ @domain = domain
16
+ @reason = reason
17
+ @source = source
18
+ @awareness_level = awareness_level.clamp(0.0, 1.0)
19
+ @created_at = Time.now.utc
20
+ end
21
+
22
+ # Duration in seconds since this item entered the schema
23
+ def duration
24
+ Time.now.utc - @created_at
25
+ end
26
+
27
+ # Apply a one-time boost (re-focus event)
28
+ def boost
29
+ @awareness_level = [@awareness_level + AWARENESS_BOOST, 1.0].min
30
+ end
31
+
32
+ # Apply per-tick decay
33
+ def decay
34
+ @awareness_level = [@awareness_level - AWARENESS_DECAY, AWARENESS_FLOOR].max
35
+ end
36
+
37
+ # True when awareness has dropped to the pruning floor
38
+ def faded?
39
+ @awareness_level <= AWARENESS_FLOOR
40
+ end
41
+
42
+ # Symbolic label describing current awareness intensity
43
+ def label
44
+ AWARENESS_LABELS.each { |range, lbl| return lbl if range.cover?(@awareness_level) }
45
+ :unconscious
46
+ end
47
+
48
+ def to_h
49
+ {
50
+ target: @target,
51
+ domain: @domain,
52
+ awareness_level: @awareness_level.round(4),
53
+ label: label,
54
+ reason: @reason,
55
+ source: @source,
56
+ duration: duration.round(2),
57
+ created_at: @created_at
58
+ }
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module AttentionSchema
6
+ module Runners
7
+ module AttentionSchema
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex)
10
+
11
+ # Focus attention on a target — adds or boosts it in the schema
12
+ def focus_on(target:, domain:, reason:, source: :external, **)
13
+ Legion::Logging.debug "[attention_schema] focus_on: target=#{target} domain=#{domain} source=#{source}"
14
+ item = schema_model.focus_on(target: target, domain: domain, reason: reason, source: source)
15
+ {
16
+ success: true,
17
+ target: item.target,
18
+ domain: item.domain,
19
+ awareness_level: item.awareness_level.round(4),
20
+ label: item.label,
21
+ schema_size: schema_model.schema_size
22
+ }
23
+ end
24
+
25
+ # Remove a target from the attention schema
26
+ def defocus(target:, **)
27
+ Legion::Logging.debug "[attention_schema] defocus: target=#{target}"
28
+ removed = schema_model.defocus(target: target)
29
+ { success: true, target: target, removed: removed, schema_size: schema_model.schema_size }
30
+ end
31
+
32
+ # Core AST query: "am I aware of X?"
33
+ def am_i_aware_of(target:, **)
34
+ result = schema_model.am_i_aware_of(target: target)
35
+ Legion::Logging.debug "[attention_schema] am_i_aware_of: target=#{target} aware=#{result[:aware]} level=#{result[:awareness_level]}"
36
+ result.merge(success: true)
37
+ end
38
+
39
+ # Generate a natural-language attention awareness report
40
+ def report_awareness(**)
41
+ report = schema_model.report_awareness
42
+ Legion::Logging.debug "[attention_schema] report_awareness: state=#{report[:state]} items=#{report[:items].size}"
43
+ report.merge(success: true)
44
+ end
45
+
46
+ # Return the current qualitative attention state symbol
47
+ def attention_state(**)
48
+ state = schema_model.attention_state
49
+ label = Helpers::Constants::ATTENTION_STATE_LABELS[state]
50
+ Legion::Logging.debug "[attention_schema] attention_state: state=#{state}"
51
+ { success: true, state: state, label: label }
52
+ end
53
+
54
+ # Model another agent's attention (social attention modeling)
55
+ def model_other_attention(agent_id:, target:, awareness:, **)
56
+ Legion::Logging.debug "[attention_schema] model_other: agent=#{agent_id} target=#{target} awareness=#{awareness}"
57
+ schema_model.model_other_attention(agent_id: agent_id, target: target, awareness: awareness.to_f)
58
+ { success: true, agent_id: agent_id, target: target, awareness: awareness.to_f.clamp(0.0, 1.0).round(4) }
59
+ end
60
+
61
+ # Query what another agent is modeled as attending to
62
+ def query_other_attention(agent_id:, **)
63
+ model = schema_model.query_other_attention(agent_id: agent_id)
64
+ Legion::Logging.debug "[attention_schema] query_other: agent=#{agent_id} found=#{!model.nil?}"
65
+ { success: true, agent_id: agent_id, model: model }
66
+ end
67
+
68
+ # Run meta-attention check: detect drifting, hyper-focus, etc.
69
+ def meta_check(**)
70
+ result = schema_model.meta_check
71
+ Legion::Logging.debug "[attention_schema] meta_check: state=#{result[:state]} signals=#{result[:signals]}"
72
+ result.merge(success: true)
73
+ end
74
+
75
+ # Record whether the schema accurately predicted actual attention (accuracy feedback)
76
+ def update_meta_accuracy(was_correct:, **)
77
+ schema_model.update_meta_accuracy(was_correct: was_correct)
78
+ accuracy = schema_model.meta_accuracy
79
+ Legion::Logging.debug "[attention_schema] meta_accuracy: was_correct=#{was_correct} accuracy=#{accuracy.round(3)}"
80
+ { success: true, was_correct: was_correct, meta_accuracy: accuracy.round(4) }
81
+ end
82
+
83
+ # Tick decay: decay all schema items and prune faded ones
84
+ def decay_schema(**)
85
+ before = schema_model.schema_size
86
+ schema_model.decay_all
87
+ after = schema_model.schema_size
88
+ Legion::Logging.debug "[attention_schema] decay: before=#{before} after=#{after} pruned=#{before - after}"
89
+ {
90
+ success: true,
91
+ before: before,
92
+ after: after,
93
+ pruned: before - after,
94
+ state: schema_model.attention_state
95
+ }
96
+ end
97
+
98
+ # Return full schema stats snapshot
99
+ def schema_stats(**)
100
+ Legion::Logging.debug "[attention_schema] stats: size=#{schema_model.schema_size}"
101
+ { success: true, stats: schema_model.to_h }
102
+ end
103
+
104
+ private
105
+
106
+ def schema_model
107
+ @schema_model ||= Helpers::AttentionSchemaModel.new
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module AttentionSchema
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/attention_schema/version'
4
+ require 'legion/extensions/attention_schema/helpers/constants'
5
+ require 'legion/extensions/attention_schema/helpers/schema_item'
6
+ require 'legion/extensions/attention_schema/helpers/attention_schema_model'
7
+ require 'legion/extensions/attention_schema/runners/attention_schema'
8
+ require 'legion/extensions/attention_schema/client'
9
+
10
+ module Legion
11
+ module Extensions
12
+ module AttentionSchema
13
+ extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::AttentionSchema::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ it 'includes Runners::AttentionSchema' do
7
+ expect(described_class.ancestors).to include(Legion::Extensions::AttentionSchema::Runners::AttentionSchema)
8
+ end
9
+
10
+ it 'supports full attention lifecycle' do
11
+ # Focus on items
12
+ client.focus_on(target: :code_review, domain: :work, reason: 'PR needs review', source: :external)
13
+ client.focus_on(target: :test_results, domain: :ci, reason: 'tests running', source: :internal)
14
+
15
+ # Query awareness
16
+ aware = client.am_i_aware_of(target: :code_review)
17
+ expect(aware[:aware]).to be true
18
+
19
+ # Report
20
+ report = client.report_awareness
21
+ expect(report[:items].size).to eq(2)
22
+
23
+ # Model another agent
24
+ client.model_other_attention(agent_id: :validator, target: :code_review, awareness: 0.9)
25
+ other = client.query_other_attention(agent_id: :validator)
26
+ expect(other[:model]).not_to be_nil
27
+
28
+ # Meta-check
29
+ meta = client.meta_check
30
+ expect(meta[:schema_size]).to eq(2)
31
+
32
+ # Meta-accuracy feedback
33
+ client.update_meta_accuracy(was_correct: true)
34
+
35
+ # Decay
36
+ client.decay_schema
37
+
38
+ # Stats
39
+ stats = client.schema_stats
40
+ expect(stats[:success]).to be true
41
+
42
+ # Defocus
43
+ client.defocus(target: :test_results)
44
+ final = client.am_i_aware_of(target: :test_results)
45
+ expect(final[:aware]).to be false
46
+ end
47
+ end
@@ -0,0 +1,219 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::AttentionSchema::Helpers::AttentionSchemaModel do
4
+ subject(:model) { described_class.new }
5
+
6
+ let(:constants) { Legion::Extensions::AttentionSchema::Helpers::Constants }
7
+
8
+ describe '#focus_on' do
9
+ it 'adds an item to the schema' do
10
+ item = model.focus_on(target: :task, domain: :work, reason: 'priority', source: :external)
11
+ expect(item.target).to eq('task')
12
+ expect(model.schema_size).to eq(1)
13
+ end
14
+
15
+ it 'boosts existing items on re-focus' do
16
+ model.focus_on(target: :task, domain: :work, reason: 'init', source: :external)
17
+ first_level = model.schema_items['task'].awareness_level
18
+ model.focus_on(target: :task, domain: :work, reason: 'again', source: :external)
19
+ expect(model.schema_items['task'].awareness_level).to be > first_level
20
+ expect(model.schema_size).to eq(1)
21
+ end
22
+
23
+ it 'prunes to capacity when full' do
24
+ constants::MAX_SCHEMA_ITEMS.times do |i|
25
+ model.focus_on(target: "item_#{i}", domain: :d, reason: :r, source: :s)
26
+ end
27
+ expect(model.schema_size).to eq(constants::MAX_SCHEMA_ITEMS)
28
+ model.focus_on(target: :overflow, domain: :d, reason: :r, source: :s)
29
+ expect(model.schema_size).to eq(constants::MAX_SCHEMA_ITEMS)
30
+ end
31
+
32
+ it 'records focus event in history' do
33
+ model.focus_on(target: :task, domain: :work, reason: 'test', source: :external)
34
+ expect(model.attention_history.size).to eq(1)
35
+ expect(model.attention_history.first[:event]).to eq(:focused)
36
+ end
37
+
38
+ it 'records refocused event on re-focus' do
39
+ model.focus_on(target: :task, domain: :work, reason: 'init', source: :external)
40
+ model.focus_on(target: :task, domain: :work, reason: 'again', source: :external)
41
+ expect(model.attention_history.last[:event]).to eq(:refocused)
42
+ end
43
+ end
44
+
45
+ describe '#defocus' do
46
+ it 'removes an item from the schema' do
47
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
48
+ removed = model.defocus(target: :task)
49
+ expect(removed).to be true
50
+ expect(model.schema_size).to eq(0)
51
+ end
52
+
53
+ it 'returns false for unknown target' do
54
+ expect(model.defocus(target: :missing)).to be false
55
+ end
56
+ end
57
+
58
+ describe '#am_i_aware_of' do
59
+ it 'returns aware: true for focused items' do
60
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
61
+ result = model.am_i_aware_of(target: :task)
62
+ expect(result[:aware]).to be true
63
+ expect(result[:awareness_level]).to be > 0
64
+ end
65
+
66
+ it 'returns aware: false for unknown targets' do
67
+ result = model.am_i_aware_of(target: :unknown)
68
+ expect(result[:aware]).to be false
69
+ expect(result[:awareness_level]).to eq(0.0)
70
+ expect(result[:label]).to eq(:unconscious)
71
+ end
72
+ end
73
+
74
+ describe '#attention_state' do
75
+ it 'returns :distracted when empty' do
76
+ expect(model.attention_state).to eq(:distracted)
77
+ end
78
+
79
+ it 'returns :focused with a moderate item' do
80
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
81
+ model.schema_items['task'].awareness_level = 0.7
82
+ expect(model.attention_state).to eq(:focused)
83
+ end
84
+
85
+ it 'returns :hyperfocused with high awareness' do
86
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
87
+ model.schema_items['task'].awareness_level = 0.9
88
+ expect(model.attention_state).to eq(:hyperfocused)
89
+ end
90
+
91
+ it 'returns :drifting when average is low with few items' do
92
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
93
+ model.schema_items['task'].awareness_level = 0.15
94
+ expect(model.attention_state).to eq(:drifting)
95
+ end
96
+
97
+ it 'returns :distracted with many low-awareness items' do
98
+ 5.times { |i| model.focus_on(target: "t_#{i}", domain: :d, reason: :r, source: :s) }
99
+ model.schema_items.each_value { |v| v.awareness_level = 0.15 }
100
+ expect(model.attention_state).to eq(:distracted)
101
+ end
102
+ end
103
+
104
+ describe '#report_awareness' do
105
+ it 'reports no items when empty' do
106
+ report = model.report_awareness
107
+ expect(report[:state]).to eq(:distracted)
108
+ expect(report[:items]).to be_empty
109
+ expect(report[:report]).to include('No active')
110
+ end
111
+
112
+ it 'generates summary with items' do
113
+ model.focus_on(target: :task, domain: :work, reason: 'priority', source: :external)
114
+ report = model.report_awareness
115
+ expect(report[:report]).to include('task')
116
+ expect(report[:items].size).to eq(1)
117
+ end
118
+
119
+ it 'includes secondary items in report' do
120
+ model.focus_on(target: :a, domain: :work, reason: 'r', source: :s)
121
+ model.focus_on(target: :b, domain: :play, reason: 'r', source: :s)
122
+ report = model.report_awareness
123
+ expect(report[:items].size).to eq(2)
124
+ expect(report[:report]).to include('Also attending to')
125
+ end
126
+ end
127
+
128
+ describe '#model_other_attention' do
129
+ it 'records another agent attention model' do
130
+ model.model_other_attention(agent_id: :agent_a, target: :task, awareness: 0.8)
131
+ result = model.query_other_attention(agent_id: :agent_a)
132
+ expect(result[:target]).to eq('task')
133
+ expect(result[:awareness]).to eq(0.8)
134
+ end
135
+
136
+ it 'clamps awareness' do
137
+ model.model_other_attention(agent_id: :agent_a, target: :task, awareness: 1.5)
138
+ result = model.query_other_attention(agent_id: :agent_a)
139
+ expect(result[:awareness]).to eq(1.0)
140
+ end
141
+
142
+ it 'returns nil for unknown agent' do
143
+ expect(model.query_other_attention(agent_id: :unknown)).to be_nil
144
+ end
145
+
146
+ it 'prunes oldest social model when full' do
147
+ constants::MAX_SOCIAL_MODELS.times do |i|
148
+ model.model_other_attention(agent_id: "agent_#{i}", target: :t, awareness: 0.5)
149
+ end
150
+ model.model_other_attention(agent_id: :overflow, target: :t, awareness: 0.5)
151
+ expect(model.social_models.size).to eq(constants::MAX_SOCIAL_MODELS)
152
+ end
153
+ end
154
+
155
+ describe '#meta_check' do
156
+ it 'returns meta-attention state' do
157
+ result = model.meta_check
158
+ expect(result).to include(:state, :signals, :top_awareness, :avg_awareness, :schema_size, :meta_accuracy)
159
+ end
160
+
161
+ it 'includes :drifting signal when distracted' do
162
+ result = model.meta_check
163
+ expect(result[:signals]).to include(:drifting)
164
+ end
165
+
166
+ it 'includes :hyperfocus signal when hyperfocused' do
167
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
168
+ model.schema_items['task'].awareness_level = 0.9
169
+ result = model.meta_check
170
+ expect(result[:signals]).to include(:hyperfocus)
171
+ end
172
+
173
+ it 'includes :normal when state is normal' do
174
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
175
+ model.schema_items['task'].awareness_level = 0.5
176
+ result = model.meta_check
177
+ expect(result[:signals]).to include(:normal)
178
+ end
179
+ end
180
+
181
+ describe '#update_meta_accuracy' do
182
+ it 'increases accuracy when correct' do
183
+ before = model.meta_accuracy
184
+ model.update_meta_accuracy(was_correct: true)
185
+ expect(model.meta_accuracy).to be > before
186
+ end
187
+
188
+ it 'decreases accuracy when incorrect' do
189
+ before = model.meta_accuracy
190
+ model.update_meta_accuracy(was_correct: false)
191
+ expect(model.meta_accuracy).to be < before
192
+ end
193
+ end
194
+
195
+ describe '#decay_all' do
196
+ it 'decays all items' do
197
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
198
+ before = model.schema_items['task'].awareness_level
199
+ model.decay_all
200
+ expect(model.schema_items['task']&.awareness_level || 0).to be < before
201
+ end
202
+
203
+ it 'prunes faded items' do
204
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
205
+ model.schema_items['task'].awareness_level = constants::AWARENESS_FLOOR + 0.01
206
+ model.decay_all
207
+ expect(model.schema_size).to eq(0)
208
+ end
209
+ end
210
+
211
+ describe '#to_h' do
212
+ it 'returns stats hash' do
213
+ model.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
214
+ h = model.to_h
215
+ expect(h).to include(:state, :state_label, :schema_size, :meta_accuracy, :top_awareness, :avg_awareness, :social_models, :items)
216
+ expect(h[:schema_size]).to eq(1)
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::AttentionSchema::Helpers::SchemaItem do
4
+ subject(:item) do
5
+ described_class.new(target: 'task_queue', domain: :work, reason: 'priority', source: :external)
6
+ end
7
+
8
+ let(:constants) { Legion::Extensions::AttentionSchema::Helpers::Constants }
9
+
10
+ describe '#initialize' do
11
+ it 'sets attributes' do
12
+ expect(item.target).to eq('task_queue')
13
+ expect(item.domain).to eq(:work)
14
+ expect(item.reason).to eq('priority')
15
+ expect(item.source).to eq(:external)
16
+ end
17
+
18
+ it 'uses default awareness level' do
19
+ expect(item.awareness_level).to eq(constants::DEFAULT_AWARENESS)
20
+ end
21
+
22
+ it 'clamps awareness to 0..1' do
23
+ high = described_class.new(target: :x, domain: :d, reason: :r, source: :s, awareness_level: 1.5)
24
+ low = described_class.new(target: :y, domain: :d, reason: :r, source: :s, awareness_level: -0.5)
25
+ expect(high.awareness_level).to eq(1.0)
26
+ expect(low.awareness_level).to eq(0.0)
27
+ end
28
+
29
+ it 'records created_at' do
30
+ expect(item.created_at).to be_a(Time)
31
+ end
32
+ end
33
+
34
+ describe '#duration' do
35
+ it 'returns elapsed time' do
36
+ expect(item.duration).to be >= 0.0
37
+ end
38
+ end
39
+
40
+ describe '#boost' do
41
+ it 'increases awareness by AWARENESS_BOOST' do
42
+ before = item.awareness_level
43
+ item.boost
44
+ expect(item.awareness_level).to eq(before + constants::AWARENESS_BOOST)
45
+ end
46
+
47
+ it 'caps at 1.0' do
48
+ item.awareness_level = 0.95
49
+ item.boost
50
+ expect(item.awareness_level).to eq(1.0)
51
+ end
52
+ end
53
+
54
+ describe '#decay' do
55
+ it 'decreases awareness by AWARENESS_DECAY' do
56
+ item.awareness_level = 0.5
57
+ item.decay
58
+ expect(item.awareness_level).to eq(0.5 - constants::AWARENESS_DECAY)
59
+ end
60
+
61
+ it 'does not drop below AWARENESS_FLOOR' do
62
+ item.awareness_level = constants::AWARENESS_FLOOR + 0.001
63
+ item.decay
64
+ expect(item.awareness_level).to eq(constants::AWARENESS_FLOOR)
65
+ end
66
+ end
67
+
68
+ describe '#faded?' do
69
+ it 'returns true at floor' do
70
+ item.awareness_level = constants::AWARENESS_FLOOR
71
+ expect(item.faded?).to be true
72
+ end
73
+
74
+ it 'returns false above floor' do
75
+ item.awareness_level = constants::AWARENESS_FLOOR + 0.01
76
+ expect(item.faded?).to be false
77
+ end
78
+ end
79
+
80
+ describe '#label' do
81
+ it 'returns :vivid for high awareness' do
82
+ item.awareness_level = 0.9
83
+ expect(item.label).to eq(:vivid)
84
+ end
85
+
86
+ it 'returns :unconscious for very low awareness' do
87
+ item.awareness_level = 0.1
88
+ expect(item.label).to eq(:unconscious)
89
+ end
90
+
91
+ it 'returns :clear for mid-high awareness' do
92
+ item.awareness_level = 0.7
93
+ expect(item.label).to eq(:clear)
94
+ end
95
+
96
+ it 'returns :dim for mid awareness' do
97
+ item.awareness_level = 0.5
98
+ expect(item.label).to eq(:dim)
99
+ end
100
+
101
+ it 'returns :peripheral for low awareness' do
102
+ item.awareness_level = 0.25
103
+ expect(item.label).to eq(:peripheral)
104
+ end
105
+ end
106
+
107
+ describe '#to_h' do
108
+ it 'returns hash with all fields' do
109
+ h = item.to_h
110
+ expect(h).to include(:target, :domain, :awareness_level, :label, :reason, :source, :duration, :created_at)
111
+ expect(h[:target]).to eq('task_queue')
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::AttentionSchema::Runners::AttentionSchema do
4
+ let(:client) { Legion::Extensions::AttentionSchema::Client.new }
5
+
6
+ describe '#focus_on' do
7
+ it 'focuses on a target' do
8
+ result = client.focus_on(target: :task, domain: :work, reason: 'priority', source: :external)
9
+ expect(result[:success]).to be true
10
+ expect(result[:target]).to eq('task')
11
+ expect(result[:awareness_level]).to be > 0
12
+ expect(result[:label]).to be_a(Symbol)
13
+ end
14
+
15
+ it 'boosts on re-focus' do
16
+ first = client.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
17
+ second = client.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
18
+ expect(second[:awareness_level]).to be > first[:awareness_level]
19
+ end
20
+ end
21
+
22
+ describe '#defocus' do
23
+ it 'removes a target' do
24
+ client.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
25
+ result = client.defocus(target: :task)
26
+ expect(result[:success]).to be true
27
+ expect(result[:removed]).to be true
28
+ end
29
+
30
+ it 'returns removed: false for unknown' do
31
+ result = client.defocus(target: :missing)
32
+ expect(result[:removed]).to be false
33
+ end
34
+ end
35
+
36
+ describe '#am_i_aware_of' do
37
+ it 'returns aware: true for focused target' do
38
+ client.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
39
+ result = client.am_i_aware_of(target: :task)
40
+ expect(result[:success]).to be true
41
+ expect(result[:aware]).to be true
42
+ end
43
+
44
+ it 'returns aware: false for unknown target' do
45
+ result = client.am_i_aware_of(target: :unknown)
46
+ expect(result[:aware]).to be false
47
+ end
48
+ end
49
+
50
+ describe '#report_awareness' do
51
+ it 'returns awareness report' do
52
+ client.focus_on(target: :task, domain: :work, reason: 'priority', source: :external)
53
+ result = client.report_awareness
54
+ expect(result[:success]).to be true
55
+ expect(result[:report]).to be_a(String)
56
+ expect(result[:items]).to be_an(Array)
57
+ end
58
+ end
59
+
60
+ describe '#attention_state' do
61
+ it 'returns current state' do
62
+ result = client.attention_state
63
+ expect(result[:success]).to be true
64
+ expect(result[:state]).to be_a(Symbol)
65
+ expect(result[:label]).to be_a(String)
66
+ end
67
+ end
68
+
69
+ describe '#model_other_attention' do
70
+ it 'records other agent attention' do
71
+ result = client.model_other_attention(agent_id: :agent_a, target: :task, awareness: 0.8)
72
+ expect(result[:success]).to be true
73
+ expect(result[:agent_id]).to eq(:agent_a)
74
+ end
75
+ end
76
+
77
+ describe '#query_other_attention' do
78
+ it 'queries modeled attention' do
79
+ client.model_other_attention(agent_id: :agent_a, target: :task, awareness: 0.8)
80
+ result = client.query_other_attention(agent_id: :agent_a)
81
+ expect(result[:success]).to be true
82
+ expect(result[:model]).not_to be_nil
83
+ end
84
+
85
+ it 'returns nil model for unknown agent' do
86
+ result = client.query_other_attention(agent_id: :unknown)
87
+ expect(result[:model]).to be_nil
88
+ end
89
+ end
90
+
91
+ describe '#meta_check' do
92
+ it 'returns meta-attention signals' do
93
+ result = client.meta_check
94
+ expect(result[:success]).to be true
95
+ expect(result[:state]).to be_a(Symbol)
96
+ expect(result[:signals]).to be_an(Array)
97
+ end
98
+ end
99
+
100
+ describe '#update_meta_accuracy' do
101
+ it 'updates meta-accuracy with feedback' do
102
+ result = client.update_meta_accuracy(was_correct: true)
103
+ expect(result[:success]).to be true
104
+ expect(result[:meta_accuracy]).to be > 0.5
105
+ end
106
+ end
107
+
108
+ describe '#decay_schema' do
109
+ it 'decays and reports' do
110
+ client.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
111
+ result = client.decay_schema
112
+ expect(result[:success]).to be true
113
+ expect(result[:before]).to eq(1)
114
+ expect(result).to have_key(:after)
115
+ expect(result).to have_key(:pruned)
116
+ end
117
+ end
118
+
119
+ describe '#schema_stats' do
120
+ it 'returns stats hash' do
121
+ result = client.schema_stats
122
+ expect(result[:success]).to be true
123
+ expect(result[:stats]).to include(:state, :schema_size, :meta_accuracy)
124
+ end
125
+
126
+ it 'reports zero schema_size when empty' do
127
+ result = client.schema_stats
128
+ expect(result[:stats][:schema_size]).to eq(0)
129
+ end
130
+
131
+ it 'includes items array in stats' do
132
+ client.focus_on(target: :task, domain: :work, reason: 'r', source: :s)
133
+ result = client.schema_stats
134
+ expect(result[:stats][:items]).to be_an(Array)
135
+ expect(result[:stats][:items].size).to eq(1)
136
+ end
137
+ end
138
+
139
+ describe '#focus_on schema_size tracking' do
140
+ it 'tracks schema_size correctly through multiple targets' do
141
+ client.focus_on(target: :a, domain: :d, reason: 'r', source: :s)
142
+ r2 = client.focus_on(target: :b, domain: :d, reason: 'r', source: :s)
143
+ r3 = client.focus_on(target: :c, domain: :d, reason: 'r', source: :s)
144
+ expect(r2[:schema_size]).to eq(2)
145
+ expect(r3[:schema_size]).to eq(3)
146
+ end
147
+ end
148
+
149
+ describe '#report_awareness empty state' do
150
+ it 'returns empty items when nothing focused' do
151
+ result = client.report_awareness
152
+ expect(result[:items]).to be_empty
153
+ end
154
+
155
+ it 'includes state_label string' do
156
+ result = client.report_awareness
157
+ expect(result[:state_label]).to be_a(String)
158
+ end
159
+ end
160
+
161
+ describe '#meta_check state labeling' do
162
+ it 'returns :distracted state with empty schema' do
163
+ result = client.meta_check
164
+ expect(result[:state]).to eq(:distracted)
165
+ end
166
+
167
+ it 'returns numeric top_awareness and avg_awareness' do
168
+ result = client.meta_check
169
+ expect(result[:top_awareness]).to be_a(Float)
170
+ expect(result[:avg_awareness]).to be_a(Float)
171
+ end
172
+ end
173
+
174
+ describe '#update_meta_accuracy boundary behavior' do
175
+ it 'correct=false reduces meta_accuracy below initial' do
176
+ result = client.update_meta_accuracy(was_correct: false)
177
+ expect(result[:meta_accuracy]).to be < 0.5
178
+ end
179
+
180
+ it 'returns the was_correct value echoed back' do
181
+ result = client.update_meta_accuracy(was_correct: false)
182
+ expect(result[:was_correct]).to be false
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ module Legion
6
+ module Logging
7
+ def self.debug(_msg); end
8
+ def self.info(_msg); end
9
+ def self.warn(_msg); end
10
+ def self.error(_msg); end
11
+ end
12
+ end
13
+
14
+ require 'legion/extensions/attention_schema'
15
+
16
+ RSpec.configure do |config|
17
+ config.example_status_persistence_file_path = '.rspec_status'
18
+ config.disable_monkey_patching!
19
+ config.expect_with(:rspec) { |c| c.syntax = :expect }
20
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lex-attention-schema
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: Graziano's Attention Schema Theory for brain-modeled agentic AI — the
27
+ agent maintains a simplified internal model of its own attention process, enabling
28
+ awareness attribution, social attention modeling, meta-attention monitoring, and
29
+ natural-language attention reports.
30
+ email:
31
+ - matthewdiverson@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - Gemfile
37
+ - lex-attention-schema.gemspec
38
+ - lib/legion/extensions/attention_schema.rb
39
+ - lib/legion/extensions/attention_schema/actors/decay.rb
40
+ - lib/legion/extensions/attention_schema/client.rb
41
+ - lib/legion/extensions/attention_schema/helpers/attention_schema_model.rb
42
+ - lib/legion/extensions/attention_schema/helpers/constants.rb
43
+ - lib/legion/extensions/attention_schema/helpers/schema_item.rb
44
+ - lib/legion/extensions/attention_schema/runners/attention_schema.rb
45
+ - lib/legion/extensions/attention_schema/version.rb
46
+ - spec/legion/extensions/attention_schema/client_spec.rb
47
+ - spec/legion/extensions/attention_schema/helpers/attention_schema_model_spec.rb
48
+ - spec/legion/extensions/attention_schema/helpers/schema_item_spec.rb
49
+ - spec/legion/extensions/attention_schema/runners/attention_schema_spec.rb
50
+ - spec/spec_helper.rb
51
+ homepage: https://github.com/LegionIO/lex-attention-schema
52
+ licenses:
53
+ - MIT
54
+ metadata:
55
+ homepage_uri: https://github.com/LegionIO/lex-attention-schema
56
+ source_code_uri: https://github.com/LegionIO/lex-attention-schema
57
+ documentation_uri: https://github.com/LegionIO/lex-attention-schema
58
+ changelog_uri: https://github.com/LegionIO/lex-attention-schema
59
+ bug_tracker_uri: https://github.com/LegionIO/lex-attention-schema/issues
60
+ rubygems_mfa_required: 'true'
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.6.9
76
+ specification_version: 4
77
+ summary: LEX Attention Schema
78
+ test_files: []