lex-cognitive-lens 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: 3557d980fea6c8eea142c7b190c7a7f0f24063a9a3388a557f1376925111628a
4
+ data.tar.gz: de477b2d12901914644e5bc8ff9ac7e817a8cc64df9a92463f1b9c88102be293
5
+ SHA512:
6
+ metadata.gz: d9fb3b07164d57fae3bf711262028284c59c08f61351b33b77ab8e8bd5abf1aea186057832df802a2600f1708536dd67565bd4608523577e743610c324019ffc
7
+ data.tar.gz: 7e6e69debebafc78146271ed8f976e1cca0741aa3516d84ba874059dbde9a7986898e4243dedc8b7a205cee00c21c4a51dc286efd1555b70d0ebd3db0b98f98f
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rake'
8
+ gem 'rspec', '~> 3.13'
9
+ gem 'rspec_junit_formatter'
10
+ gem 'rubocop', '~> 1.75', require: false
11
+ gem 'rubocop-rspec', require: false
12
+ gem 'simplecov'
13
+ end
14
+
15
+ gem 'legion-gaia', path: '../../legion-gaia'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Esity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # lex-cognitive-lens
2
+
3
+ Optical perspective filtering for LegionIO cognitive agents. Models cognitive viewpoints as lenses that can be stacked to produce combined magnification, distortion, and clarity effects on any content.
4
+
5
+ ## What It Does
6
+
7
+ - Six lens types: `magnifying`, `wide_angle`, `fish_eye`, `polarized`, `telescopic`, `microscopic`
8
+ - Each lens has magnification, aperture, distortion, and clarity attributes
9
+ - Lenses can be focused/defocused, smudged/cleaned
10
+ - Stack multiple lenses: combined effects use diminishing-return magnification and weighted distortion blending
11
+ - `view_through_stack` applies the full pipeline to any content string
12
+ - `degrade_all` simulates environmental smudging across all lenses
13
+
14
+ ## Usage
15
+
16
+ ```ruby
17
+ # Create lenses
18
+ mag = runner.create_lens(lens_type: :magnifying, magnification: 2.5, aperture: 0.7,
19
+ distortion: 0.1, clarity: 0.9)
20
+ wide = runner.create_lens(lens_type: :wide_angle, magnification: 0.5, aperture: 0.9,
21
+ distortion: 0.2, clarity: 0.8)
22
+
23
+ # View content through a stack
24
+ result = runner.view_through_stack(
25
+ lens_ids: [mag[:lens][:id], wide[:lens][:id]],
26
+ content: 'The root cause is a missing validation layer'
27
+ )
28
+ # => { success: true, magnified_content: ..., distortion_applied: ..., clarity_score: ..., filtered_view: ... }
29
+
30
+ # Get clearest lenses
31
+ runner.clearest_lenses(limit: 3)
32
+
33
+ # Degrade all lenses over time
34
+ runner.degrade_all(rate: 0.05)
35
+
36
+ # Full report
37
+ runner.lens_report
38
+ ```
39
+
40
+ ## Development
41
+
42
+ ```bash
43
+ bundle install
44
+ bundle exec rspec
45
+ bundle exec rubocop
46
+ ```
47
+
48
+ ## License
49
+
50
+ MIT
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/legion/extensions/cognitive_lens/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'lex-cognitive-lens'
7
+ spec.version = Legion::Extensions::CognitiveLens::VERSION
8
+ spec.authors = ['Esity']
9
+ spec.email = ['matthewdiverson@gmail.com']
10
+
11
+ spec.summary = 'LEX Cognitive Lens'
12
+ spec.description = 'Cognitive lenses that filter, focus, or distort perception for brain-modeled agentic AI'
13
+ spec.homepage = 'https://github.com/LegionIO/lex-cognitive-lens'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = '>= 3.4'
16
+
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-cognitive-lens'
19
+ spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-cognitive-lens'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-cognitive-lens'
21
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-cognitive-lens/issues'
22
+ spec.metadata['rubygems_mfa_required'] = 'true'
23
+
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ Dir.glob('{lib,spec}/**/*') + %w[lex-cognitive-lens.gemspec Gemfile LICENSE README.md]
26
+ end
27
+ spec.require_paths = ['lib']
28
+ spec.add_development_dependency 'legion-gaia'
29
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/cognitive_lens/helpers/constants'
4
+ require 'legion/extensions/cognitive_lens/helpers/lens'
5
+ require 'legion/extensions/cognitive_lens/helpers/lens_stack'
6
+ require 'legion/extensions/cognitive_lens/helpers/lens_engine'
7
+ require 'legion/extensions/cognitive_lens/runners/cognitive_lens'
8
+
9
+ module Legion
10
+ module Extensions
11
+ module CognitiveLens
12
+ class Client
13
+ include Runners::CognitiveLens
14
+
15
+ def initialize(**)
16
+ @lens_engine = Helpers::LensEngine.new
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :lens_engine
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveLens
6
+ module Helpers
7
+ module Constants
8
+ LENS_TYPES = %i[magnifying wide_angle fish_eye polarized telescopic microscopic].freeze
9
+
10
+ DISTORTION_TYPES = %i[none barrel pincushion mustache wave spiral].freeze
11
+
12
+ MAX_LENSES = 8
13
+
14
+ CLARITY_LABELS = [
15
+ [0.0..0.2, :opaque],
16
+ [0.2..0.4, :foggy],
17
+ [0.4..0.6, :hazy],
18
+ [0.6..0.8, :clear],
19
+ [0.8..1.0, :crystal]
20
+ ].freeze
21
+
22
+ MAGNIFICATION_LABELS = [
23
+ [0.1..0.5, :micro],
24
+ [0.5..1.0, :normal],
25
+ [1.0..2.0, :zoom],
26
+ [2.0..5.0, :telephoto],
27
+ [5.0..10.0, :extreme]
28
+ ].freeze
29
+
30
+ # Default optical properties per lens type
31
+ LENS_DEFAULTS = {
32
+ magnifying: { magnification: 2.0, aperture: 0.6, distortion: 0.1 },
33
+ wide_angle: { magnification: 0.5, aperture: 0.9, distortion: 0.2 },
34
+ fish_eye: { magnification: 0.3, aperture: 1.0, distortion: 0.8 },
35
+ polarized: { magnification: 1.0, aperture: 0.4, distortion: 0.0 },
36
+ telescopic: { magnification: 8.0, aperture: 0.3, distortion: 0.15 },
37
+ microscopic: { magnification: 9.0, aperture: 0.5, distortion: 0.05 }
38
+ }.freeze
39
+
40
+ # Smudge degrades clarity; clean restores it
41
+ SMUDGE_RATE_DEFAULT = 0.05
42
+ CLEAN_BOOST_DEFAULT = 0.1
43
+ CLARITY_SHARP_THRESHOLD = 0.7
44
+ CLARITY_BLURRY_THRESHOLD = 0.35
45
+
46
+ # Stack combination weights
47
+ STACK_MAGNIFICATION_EXPONENT = 0.8 # sub-linear compounding prevents extremes
48
+ STACK_DISTORTION_BLEND = 0.6 # weight toward worst distortion
49
+ STACK_CLARITY_DECAY = 0.9 # each additional lens costs 10% clarity
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveLens
6
+ module Helpers
7
+ class Lens
8
+ include Constants
9
+
10
+ attr_reader :id, :lens_type, :magnification, :clarity, :distortion, :aperture,
11
+ :focus_target, :created_at
12
+
13
+ def initialize(lens_type:, magnification: nil, clarity: 1.0, distortion: nil, aperture: nil)
14
+ raise ArgumentError, "unknown lens_type: #{lens_type}" unless Constants::LENS_TYPES.include?(lens_type)
15
+
16
+ defaults = Constants::LENS_DEFAULTS.fetch(lens_type)
17
+
18
+ @id = SecureRandom.uuid
19
+ @lens_type = lens_type
20
+ @magnification = (magnification || defaults[:magnification]).clamp(0.1, 10.0).round(10)
21
+ @clarity = clarity.clamp(0.0, 1.0).round(10)
22
+ @distortion = (distortion || defaults[:distortion]).clamp(0.0, 1.0).round(10)
23
+ @aperture = (aperture || defaults[:aperture]).clamp(0.0, 1.0).round(10)
24
+ @focus_target = nil
25
+ @created_at = Time.now.utc
26
+ end
27
+
28
+ def focus!(target)
29
+ @focus_target = target
30
+ self
31
+ end
32
+
33
+ def defocus!
34
+ @focus_target = nil
35
+ self
36
+ end
37
+
38
+ def smudge!(rate = Constants::SMUDGE_RATE_DEFAULT)
39
+ @clarity = (@clarity - rate.clamp(0.0, 1.0)).clamp(0.0, 1.0).round(10)
40
+ self
41
+ end
42
+
43
+ def clean!(boost = Constants::CLEAN_BOOST_DEFAULT)
44
+ @clarity = (@clarity + boost.clamp(0.0, 1.0)).clamp(0.0, 1.0).round(10)
45
+ self
46
+ end
47
+
48
+ def sharp?
49
+ @clarity >= Constants::CLARITY_SHARP_THRESHOLD
50
+ end
51
+
52
+ def blurry?
53
+ @clarity <= Constants::CLARITY_BLURRY_THRESHOLD
54
+ end
55
+
56
+ def clarity_label
57
+ Constants::CLARITY_LABELS.find { |range, _| range.cover?(@clarity) }&.last || :crystal
58
+ end
59
+
60
+ def magnification_label
61
+ Constants::MAGNIFICATION_LABELS.find { |range, _| range.cover?(@magnification) }&.last || :extreme
62
+ end
63
+
64
+ def focused?
65
+ !@focus_target.nil?
66
+ end
67
+
68
+ def depth_of_field
69
+ # Larger aperture = shallower depth of field; higher magnification = shallower
70
+ base = 1.0 - @aperture
71
+ mag_factor = 1.0 / [magnification, 0.1].max
72
+ ((base * 0.6) + (mag_factor * 0.4)).clamp(0.0, 1.0).round(10)
73
+ end
74
+
75
+ def to_h
76
+ {
77
+ id: @id,
78
+ lens_type: @lens_type,
79
+ magnification: @magnification,
80
+ clarity: @clarity,
81
+ distortion: @distortion,
82
+ aperture: @aperture,
83
+ focus_target: @focus_target,
84
+ sharp: sharp?,
85
+ blurry: blurry?,
86
+ clarity_label: clarity_label,
87
+ magnification_label: magnification_label,
88
+ depth_of_field: depth_of_field
89
+ }
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveLens
6
+ module Helpers
7
+ class LensEngine
8
+ include Constants
9
+
10
+ attr_reader :lenses, :stacks
11
+
12
+ def initialize
13
+ @lenses = {}
14
+ @stacks = {}
15
+ end
16
+
17
+ def create_lens(lens_type:, magnification: nil, clarity: 1.0, distortion: nil, aperture: nil, **)
18
+ lens = Lens.new(
19
+ lens_type: lens_type,
20
+ magnification: magnification,
21
+ clarity: clarity,
22
+ distortion: distortion,
23
+ aperture: aperture
24
+ )
25
+ @lenses[lens.id] = lens
26
+ lens
27
+ end
28
+
29
+ def stack_lenses(lens_ids:, stack_id: nil, **)
30
+ stack_id ||= SecureRandom.uuid
31
+ stack = LensStack.new
32
+
33
+ lens_ids.each do |lid|
34
+ lens = @lenses[lid]
35
+ raise ArgumentError, "lens not found: #{lid}" unless lens
36
+
37
+ stack.push_lens(lens)
38
+ end
39
+
40
+ @stacks[stack_id] = stack
41
+ { stack_id: stack_id, stack: stack }
42
+ end
43
+
44
+ def view_through_stack(stack_id:, content:, **)
45
+ stack = @stacks[stack_id]
46
+ raise ArgumentError, "stack not found: #{stack_id}" unless stack
47
+
48
+ result = stack.view_through(content)
49
+ Legion::Logging.debug "[cognitive_lens] view_through stack=#{stack_id} " \
50
+ "perceived=#{result[:perceived].round(4)} " \
51
+ "magnification=#{result[:combined_magnification].round(2)} " \
52
+ "distortion=#{result[:combined_distortion].round(2)} " \
53
+ "clarity=#{result[:stack_clarity].round(2)}"
54
+ result
55
+ end
56
+
57
+ def degrade_all!(rate: Constants::SMUDGE_RATE_DEFAULT)
58
+ @lenses.each_value { |l| l.smudge!(rate) }
59
+ { degraded: @lenses.size, rate: rate }
60
+ end
61
+
62
+ def clearest_lenses(limit: 3)
63
+ @lenses.values
64
+ .sort_by { |l| -l.clarity }
65
+ .first(limit)
66
+ .map(&:to_h)
67
+ end
68
+
69
+ def most_distorted(limit: 3)
70
+ @lenses.values
71
+ .sort_by { |l| -l.distortion }
72
+ .first(limit)
73
+ .map(&:to_h)
74
+ end
75
+
76
+ def lens_report
77
+ return { lens_count: 0, stack_count: 0, lenses: [], stacks: [] } if @lenses.empty?
78
+
79
+ avg_clarity = (@lenses.values.sum(&:clarity) / @lenses.size).round(10)
80
+ avg_distortion = (@lenses.values.sum(&:distortion) / @lenses.size).round(10)
81
+
82
+ {
83
+ lens_count: @lenses.size,
84
+ stack_count: @stacks.size,
85
+ avg_clarity: avg_clarity,
86
+ avg_distortion: avg_distortion,
87
+ sharp_count: @lenses.values.count(&:sharp?),
88
+ blurry_count: @lenses.values.count(&:blurry?),
89
+ lenses: @lenses.values.map(&:to_h),
90
+ stacks: @stacks.transform_values(&:to_h)
91
+ }
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveLens
6
+ module Helpers
7
+ class LensStack
8
+ include Constants
9
+
10
+ attr_reader :lenses
11
+
12
+ def initialize
13
+ @lenses = []
14
+ end
15
+
16
+ def push_lens(lens)
17
+ raise ArgumentError, 'expected a Lens instance' unless lens.is_a?(Lens)
18
+ raise ArgumentError, "stack is full (max #{Constants::MAX_LENSES})" if @lenses.size >= Constants::MAX_LENSES
19
+
20
+ @lenses << lens
21
+ self
22
+ end
23
+
24
+ def pop_lens
25
+ @lenses.pop
26
+ end
27
+
28
+ def size
29
+ @lenses.size
30
+ end
31
+
32
+ def empty?
33
+ @lenses.empty?
34
+ end
35
+
36
+ def combined_magnification
37
+ return 1.0 if @lenses.empty?
38
+
39
+ # Sub-linear compounding via exponent to avoid extreme values
40
+ base = @lenses.reduce(1.0) { |acc, l| acc * l.magnification }
41
+ base**Constants::STACK_MAGNIFICATION_EXPONENT
42
+ end
43
+
44
+ def combined_distortion
45
+ return 0.0 if @lenses.empty?
46
+
47
+ max_dist = @lenses.map(&:distortion).max
48
+ mean_dist = @lenses.sum(&:distortion) / @lenses.size
49
+ # Blend toward worst distortion
50
+ ((max_dist * Constants::STACK_DISTORTION_BLEND) +
51
+ (mean_dist * (1.0 - Constants::STACK_DISTORTION_BLEND))).clamp(0.0, 1.0).round(10)
52
+ end
53
+
54
+ def stack_clarity
55
+ return 1.0 if @lenses.empty?
56
+
57
+ base = @lenses.map(&:clarity).min
58
+ decay = Constants::STACK_CLARITY_DECAY**(@lenses.size - 1)
59
+ (base * decay).clamp(0.0, 1.0).round(10)
60
+ end
61
+
62
+ # Apply all lenses to a content value (numeric 0.0-1.0) or hash with :value key
63
+ def view_through(content)
64
+ return content if @lenses.empty?
65
+
66
+ raw_value = extract_value(content)
67
+ magnified = apply_magnification(raw_value)
68
+ distorted = apply_distortion(magnified)
69
+ filtered = apply_clarity(distorted)
70
+
71
+ {
72
+ original: raw_value,
73
+ perceived: filtered.round(10),
74
+ combined_magnification: combined_magnification.round(10),
75
+ combined_distortion: combined_distortion.round(10),
76
+ stack_clarity: stack_clarity.round(10),
77
+ lens_count: @lenses.size,
78
+ focus_active: @lenses.any?(&:focused?)
79
+ }
80
+ end
81
+
82
+ def to_h
83
+ {
84
+ lens_count: @lenses.size,
85
+ combined_magnification: combined_magnification.round(10),
86
+ combined_distortion: combined_distortion.round(10),
87
+ stack_clarity: stack_clarity.round(10),
88
+ lenses: @lenses.map(&:to_h)
89
+ }
90
+ end
91
+
92
+ private
93
+
94
+ def extract_value(content)
95
+ if content.is_a?(Hash)
96
+ content.fetch(:value, 0.5).clamp(0.0, 1.0)
97
+ else
98
+ content.to_f.clamp(0.0, 1.0)
99
+ end
100
+ end
101
+
102
+ def apply_magnification(value)
103
+ mag = combined_magnification
104
+ # Magnification centers around 0.5; scale distance from center
105
+ center = 0.5
106
+ distance = value - center
107
+ (center + (distance * mag)).clamp(0.0, 1.0)
108
+ end
109
+
110
+ def apply_distortion(value)
111
+ dist = combined_distortion
112
+ return value if dist.zero?
113
+
114
+ # Barrel distortion pushes values toward extremes
115
+ noise = (value - 0.5).abs * dist * 0.2
116
+ sign = value >= 0.5 ? 1 : -1
117
+ (value + (sign * noise)).clamp(0.0, 1.0)
118
+ end
119
+
120
+ def apply_clarity(value)
121
+ clarity = stack_clarity
122
+ # Low clarity pulls perceived value toward neutral (0.5)
123
+ center = 0.5
124
+ (center + ((value - center) * clarity)).clamp(0.0, 1.0)
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveLens
6
+ module Runners
7
+ module CognitiveLens
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex)
10
+
11
+ def create_lens(lens_type:, magnification: nil, clarity: 1.0, distortion: nil, aperture: nil,
12
+ engine: nil, **)
13
+ raise ArgumentError, "unknown lens_type: #{lens_type}" unless Helpers::Constants::LENS_TYPES.include?(lens_type)
14
+
15
+ eng = engine || lens_engine
16
+ lens = eng.create_lens(
17
+ lens_type: lens_type,
18
+ magnification: magnification,
19
+ clarity: clarity,
20
+ distortion: distortion,
21
+ aperture: aperture
22
+ )
23
+ Legion::Logging.debug "[cognitive_lens] created lens id=#{lens.id} type=#{lens_type} " \
24
+ "mag=#{lens.magnification.round(2)} clarity=#{lens.clarity.round(2)}"
25
+ { success: true, lens: lens.to_h }
26
+ rescue ArgumentError => e
27
+ Legion::Logging.warn "[cognitive_lens] create_lens failed: #{e.message}"
28
+ { success: false, error: e.message }
29
+ end
30
+
31
+ def stack_lenses(lens_ids:, stack_id: nil, engine: nil, **)
32
+ raise ArgumentError, 'lens_ids must be an array' unless lens_ids.is_a?(Array)
33
+
34
+ eng = engine || lens_engine
35
+ result = eng.stack_lenses(lens_ids: lens_ids, stack_id: stack_id)
36
+ Legion::Logging.debug "[cognitive_lens] stacked #{lens_ids.size} lenses stack_id=#{result[:stack_id]}"
37
+ { success: true, stack_id: result[:stack_id], stack: result[:stack].to_h }
38
+ rescue ArgumentError => e
39
+ Legion::Logging.warn "[cognitive_lens] stack_lenses failed: #{e.message}"
40
+ { success: false, error: e.message }
41
+ end
42
+
43
+ def view_through_stack(stack_id:, content:, engine: nil, **)
44
+ eng = engine || lens_engine
45
+ result = eng.view_through_stack(stack_id: stack_id, content: content)
46
+ { success: true, **result }
47
+ rescue ArgumentError => e
48
+ Legion::Logging.warn "[cognitive_lens] view_through_stack failed: #{e.message}"
49
+ { success: false, error: e.message }
50
+ end
51
+
52
+ def degrade_all(rate: Helpers::Constants::SMUDGE_RATE_DEFAULT, engine: nil, **)
53
+ eng = engine || lens_engine
54
+ result = eng.degrade_all!(rate: rate)
55
+ Legion::Logging.debug "[cognitive_lens] degraded #{result[:degraded]} lenses at rate=#{rate}"
56
+ { success: true, **result }
57
+ end
58
+
59
+ def lens_report(engine: nil, **)
60
+ eng = engine || lens_engine
61
+ report = eng.lens_report
62
+ { success: true, **report }
63
+ end
64
+
65
+ def clearest_lenses(limit: 3, engine: nil, **)
66
+ eng = engine || lens_engine
67
+ lenses = eng.clearest_lenses(limit: limit)
68
+ { success: true, lenses: lenses }
69
+ end
70
+
71
+ def most_distorted(limit: 3, engine: nil, **)
72
+ eng = engine || lens_engine
73
+ lenses = eng.most_distorted(limit: limit)
74
+ { success: true, lenses: lenses }
75
+ end
76
+
77
+ private
78
+
79
+ def lens_engine
80
+ @lens_engine ||= Helpers::LensEngine.new
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module CognitiveLens
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ require_relative 'cognitive_lens/version'
6
+ require_relative 'cognitive_lens/helpers/constants'
7
+ require_relative 'cognitive_lens/helpers/lens'
8
+ require_relative 'cognitive_lens/helpers/lens_stack'
9
+ require_relative 'cognitive_lens/helpers/lens_engine'
10
+ require_relative 'cognitive_lens/runners/cognitive_lens'
11
+ require_relative 'cognitive_lens/client'
12
+
13
+ module Legion
14
+ module Extensions
15
+ module CognitiveLens
16
+ extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
17
+ end
18
+ end
19
+ end