lex-cognitive-lighthouse 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/.github/workflows/ci.yml +16 -0
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +37 -0
- data/CLAUDE.md +107 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +78 -0
- data/README.md +47 -0
- data/lex-cognitive-lighthouse.gemspec +33 -0
- data/lib/legion/extensions/cognitive_lighthouse/client.rb +21 -0
- data/lib/legion/extensions/cognitive_lighthouse/helpers/beacon.rb +72 -0
- data/lib/legion/extensions/cognitive_lighthouse/helpers/constants.rb +45 -0
- data/lib/legion/extensions/cognitive_lighthouse/helpers/fog.rb +70 -0
- data/lib/legion/extensions/cognitive_lighthouse/helpers/lighthouse_engine.rb +123 -0
- data/lib/legion/extensions/cognitive_lighthouse/runners/cognitive_lighthouse.rb +76 -0
- data/lib/legion/extensions/cognitive_lighthouse/version.rb +9 -0
- data/lib/legion/extensions/cognitive_lighthouse.rb +19 -0
- metadata +79 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 7f54885694491e600f6aee8f9b1e3457bb8919ee8a8cc6161139038c7997abdb
|
|
4
|
+
data.tar.gz: f834c005573627c985321c9c27a31853bc124ebf7d354a3dce8a779671536c37
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 860f2ba190a71695e20be6d7583008a7978ccd564bedb4623e81011434b50d8eb20d1ac02367dd2f653ffcee740bb9d3d94a0c94daeab65529cedc1bade4b5aa
|
|
7
|
+
data.tar.gz: 3e7c288083585b04cb5e3f7ed7be3979d26e76b168c14cf8c79a93ab0e3e9eafe472ea8edeab3e755b5243eb4cb6d1ac62445e848b380f20033495e2adbae157
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
ci:
|
|
9
|
+
uses: LegionIO/.github/.github/workflows/ci.yml@main
|
|
10
|
+
|
|
11
|
+
release:
|
|
12
|
+
needs: ci
|
|
13
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
14
|
+
uses: LegionIO/.github/.github/workflows/release.yml@main
|
|
15
|
+
secrets:
|
|
16
|
+
rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
NewCops: enable
|
|
3
|
+
TargetRubyVersion: 3.4
|
|
4
|
+
|
|
5
|
+
Style/Documentation:
|
|
6
|
+
Enabled: false
|
|
7
|
+
|
|
8
|
+
Naming/PredicateMethod:
|
|
9
|
+
Enabled: false
|
|
10
|
+
|
|
11
|
+
Naming/PredicatePrefix:
|
|
12
|
+
Enabled: false
|
|
13
|
+
|
|
14
|
+
Metrics/ClassLength:
|
|
15
|
+
Max: 150
|
|
16
|
+
|
|
17
|
+
Metrics/MethodLength:
|
|
18
|
+
Max: 25
|
|
19
|
+
|
|
20
|
+
Metrics/AbcSize:
|
|
21
|
+
Max: 25
|
|
22
|
+
|
|
23
|
+
Metrics/ParameterLists:
|
|
24
|
+
Max: 8
|
|
25
|
+
MaxOptionalParameters: 8
|
|
26
|
+
|
|
27
|
+
Layout/HashAlignment:
|
|
28
|
+
EnforcedColonStyle: table
|
|
29
|
+
EnforcedHashRocketStyle: table
|
|
30
|
+
|
|
31
|
+
Metrics/BlockLength:
|
|
32
|
+
Exclude:
|
|
33
|
+
- 'spec/**/*'
|
|
34
|
+
|
|
35
|
+
Style/OneClassPerFile:
|
|
36
|
+
Exclude:
|
|
37
|
+
- 'spec/spec_helper.rb'
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# lex-cognitive-lighthouse
|
|
2
|
+
|
|
3
|
+
**Level 3 Leaf Documentation**
|
|
4
|
+
- **Parent**: `/Users/miverso2/rubymine/legion/extensions-agentic/CLAUDE.md`
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Beacon and fog metaphor for navigational clarity in cognitive processing. Beacons represent sources of truth, clarity, warning, guidance, and hope — each with a luminosity level. Fog banks represent confusion, uncertainty, ambiguity, doubt, and overwhelm — each with a density level. The sweep operation actively disperses fog using beacon luminosity, modeling how clarity-producing cognition reduces confusion.
|
|
9
|
+
|
|
10
|
+
## Gem Info
|
|
11
|
+
|
|
12
|
+
- **Gem name**: `lex-cognitive-lighthouse`
|
|
13
|
+
- **Module**: `Legion::Extensions::CognitiveLighthouse`
|
|
14
|
+
- **Version**: `0.1.0`
|
|
15
|
+
- **Ruby**: `>= 3.4`
|
|
16
|
+
- **License**: MIT
|
|
17
|
+
|
|
18
|
+
## File Structure
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
lib/legion/extensions/cognitive_lighthouse/
|
|
22
|
+
version.rb
|
|
23
|
+
client.rb
|
|
24
|
+
helpers/
|
|
25
|
+
constants.rb
|
|
26
|
+
beacon.rb
|
|
27
|
+
fog.rb
|
|
28
|
+
lighthouse_engine.rb
|
|
29
|
+
runners/
|
|
30
|
+
cognitive_lighthouse.rb
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Key Constants
|
|
34
|
+
|
|
35
|
+
| Constant | Value | Purpose |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `BEACON_TYPES` | `%i[truth clarity warning guidance hope]` | Valid beacon categories |
|
|
38
|
+
| `FOG_TYPES` | `%i[confusion uncertainty ambiguity doubt overwhelm]` | Valid fog categories |
|
|
39
|
+
| `MAX_BEACONS` | `100` | Per-engine beacon capacity |
|
|
40
|
+
| `MAX_FOG_BANKS` | `50` | Per-engine fog capacity |
|
|
41
|
+
| `LUMINOSITY_RATE` | `0.1` | Default brightness change per brighten/dim operation |
|
|
42
|
+
| `FOG_DENSITY_RATE` | `0.05` | Default density change per thicken/disperse operation |
|
|
43
|
+
| `VISIBILITY_LABELS` | range hash | From `:blind` to `:crystal_clear` |
|
|
44
|
+
| `LUMINOSITY_LABELS` | range hash | From `:dark` to `:blazing` |
|
|
45
|
+
|
|
46
|
+
## Helpers
|
|
47
|
+
|
|
48
|
+
### `Helpers::Beacon`
|
|
49
|
+
Emits light to cut through cognitive fog. Has `id`, `beacon_type`, `luminosity`, `domain`, `content`, and `created_at`.
|
|
50
|
+
|
|
51
|
+
- `brighten!(rate)` — increases luminosity
|
|
52
|
+
- `dim!(rate)` — decreases luminosity
|
|
53
|
+
- `extinguished?` — luminosity at or below zero
|
|
54
|
+
- `blazing?` — luminosity at maximum
|
|
55
|
+
- `luminosity_label`
|
|
56
|
+
- `to_h`
|
|
57
|
+
|
|
58
|
+
### `Helpers::Fog`
|
|
59
|
+
Represents a cloud of cognitive obscuration. Has `id`, `fog_type`, `density`, `domain`, `content`, and `created_at`.
|
|
60
|
+
|
|
61
|
+
- `thicken!(rate)` — increases density
|
|
62
|
+
- `disperse!(rate)` — decreases density
|
|
63
|
+
- `impenetrable?` — density at maximum
|
|
64
|
+
- `clearing?` — density below a low threshold
|
|
65
|
+
- `visibility_label` — based on inverse of density
|
|
66
|
+
- `to_h`
|
|
67
|
+
|
|
68
|
+
### `Helpers::LighthouseEngine`
|
|
69
|
+
Manages beacons and fog banks, enforces capacity limits.
|
|
70
|
+
|
|
71
|
+
- `light_beacon(beacon_type:, luminosity:, domain:, content:)` → beacon or capacity error
|
|
72
|
+
- `create_fog(fog_type:, density:, domain:, content:)` → fog or capacity error
|
|
73
|
+
- `sweep` — for each beacon, disperses fog banks in the same domain; dispersion amount = `beacon.luminosity * 0.5`; extinguished beacons are pruned
|
|
74
|
+
- `dim_all!(rate:)` — dims all beacons, prunes extinguished ones
|
|
75
|
+
- `thicken_all!(rate:)` — thickens all fog banks
|
|
76
|
+
- `brightest_beacons(limit:)` → top N by luminosity
|
|
77
|
+
- `densest_fogs(limit:)` → top N by density
|
|
78
|
+
- `visibility_report` → aggregate stats hash
|
|
79
|
+
|
|
80
|
+
## Runners
|
|
81
|
+
|
|
82
|
+
Module: `Runners::CognitiveLighthouse`
|
|
83
|
+
|
|
84
|
+
| Runner Method | Description |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `light_beacon(beacon_type:, luminosity:, domain:, content:)` | Create a new beacon |
|
|
87
|
+
| `create_fog(fog_type:, density:, domain:, content:)` | Create a new fog bank |
|
|
88
|
+
| `sweep` | Beacons disperse fog in matching domains |
|
|
89
|
+
| `list_beacons(limit:)` | Brightest beacons |
|
|
90
|
+
| `navigation_status` | Full visibility report |
|
|
91
|
+
|
|
92
|
+
All runners return `{success: true/false, ...}` hashes.
|
|
93
|
+
|
|
94
|
+
## Integration Points
|
|
95
|
+
|
|
96
|
+
- No direct dependencies on other agentic LEX gems
|
|
97
|
+
- Can integrate with `lex-tick` phase handlers: low overall visibility → switch to sentinel mode
|
|
98
|
+
- Beacon luminosity can be boosted when `lex-emotion` valence is positive
|
|
99
|
+
- Fog density can be increased on `lex-conflict` escalation events
|
|
100
|
+
- `sweep` is the natural action for the agent's clarification-seeking behavior
|
|
101
|
+
|
|
102
|
+
## Development Notes
|
|
103
|
+
|
|
104
|
+
- `Client` instantiates `@lighthouse_engine = Helpers::LighthouseEngine.new`
|
|
105
|
+
- `sweep` prunes beacons that become extinguished after dispersion calculations
|
|
106
|
+
- Beacon and fog domains are matched for targeted dispersion — a `:truth` beacon only disperses fog in its own domain
|
|
107
|
+
- `MAX_BEACONS = 100` and `MAX_FOG_BANKS = 50` are hard engine-level caps
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
lex-cognitive-lighthouse (0.1.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
addressable (2.8.9)
|
|
10
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
11
|
+
ast (2.4.3)
|
|
12
|
+
bigdecimal (4.0.1)
|
|
13
|
+
diff-lcs (1.6.2)
|
|
14
|
+
json (2.19.1)
|
|
15
|
+
json-schema (6.2.0)
|
|
16
|
+
addressable (~> 2.8)
|
|
17
|
+
bigdecimal (>= 3.1, < 5)
|
|
18
|
+
language_server-protocol (3.17.0.5)
|
|
19
|
+
lint_roller (1.1.0)
|
|
20
|
+
mcp (0.8.0)
|
|
21
|
+
json-schema (>= 4.1)
|
|
22
|
+
parallel (1.27.0)
|
|
23
|
+
parser (3.3.10.2)
|
|
24
|
+
ast (~> 2.4.1)
|
|
25
|
+
racc
|
|
26
|
+
prism (1.9.0)
|
|
27
|
+
public_suffix (7.0.5)
|
|
28
|
+
racc (1.8.1)
|
|
29
|
+
rainbow (3.1.1)
|
|
30
|
+
regexp_parser (2.11.3)
|
|
31
|
+
rspec (3.13.2)
|
|
32
|
+
rspec-core (~> 3.13.0)
|
|
33
|
+
rspec-expectations (~> 3.13.0)
|
|
34
|
+
rspec-mocks (~> 3.13.0)
|
|
35
|
+
rspec-core (3.13.6)
|
|
36
|
+
rspec-support (~> 3.13.0)
|
|
37
|
+
rspec-expectations (3.13.5)
|
|
38
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
39
|
+
rspec-support (~> 3.13.0)
|
|
40
|
+
rspec-mocks (3.13.8)
|
|
41
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
42
|
+
rspec-support (~> 3.13.0)
|
|
43
|
+
rspec-support (3.13.7)
|
|
44
|
+
rubocop (1.85.1)
|
|
45
|
+
json (~> 2.3)
|
|
46
|
+
language_server-protocol (~> 3.17.0.2)
|
|
47
|
+
lint_roller (~> 1.1.0)
|
|
48
|
+
mcp (~> 0.6)
|
|
49
|
+
parallel (~> 1.10)
|
|
50
|
+
parser (>= 3.3.0.2)
|
|
51
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
52
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
53
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
54
|
+
ruby-progressbar (~> 1.7)
|
|
55
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
56
|
+
rubocop-ast (1.49.1)
|
|
57
|
+
parser (>= 3.3.7.2)
|
|
58
|
+
prism (~> 1.7)
|
|
59
|
+
rubocop-rspec (3.9.0)
|
|
60
|
+
lint_roller (~> 1.1)
|
|
61
|
+
rubocop (~> 1.81)
|
|
62
|
+
ruby-progressbar (1.13.0)
|
|
63
|
+
unicode-display_width (3.2.0)
|
|
64
|
+
unicode-emoji (~> 4.1)
|
|
65
|
+
unicode-emoji (4.2.0)
|
|
66
|
+
|
|
67
|
+
PLATFORMS
|
|
68
|
+
arm64-darwin-25
|
|
69
|
+
ruby
|
|
70
|
+
|
|
71
|
+
DEPENDENCIES
|
|
72
|
+
lex-cognitive-lighthouse!
|
|
73
|
+
rspec (~> 3.13)
|
|
74
|
+
rubocop (~> 1.75)
|
|
75
|
+
rubocop-rspec
|
|
76
|
+
|
|
77
|
+
BUNDLED WITH
|
|
78
|
+
2.6.9
|
data/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# lex-cognitive-lighthouse
|
|
2
|
+
|
|
3
|
+
Beacon and fog navigation model for LegionIO cognitive agents. Beacons (truth, clarity, warning, guidance, hope) actively disperse fog banks (confusion, uncertainty, ambiguity, doubt, overwhelm) through sweep operations.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
- Light beacons with luminosity levels to represent sources of cognitive clarity
|
|
8
|
+
- Create fog banks with density levels to represent sources of cognitive obscuration
|
|
9
|
+
- Run `sweep` to have beacons disperse fog in their matching domains
|
|
10
|
+
- Track overall visibility across all fog banks
|
|
11
|
+
- Monitor brightest beacons and densest fog clusters
|
|
12
|
+
- Beacons that dim to zero are pruned automatically during sweep
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
# Light a beacon
|
|
18
|
+
runner.light_beacon(beacon_type: :clarity, luminosity: 0.8,
|
|
19
|
+
domain: :reasoning, content: 'Root cause identified')
|
|
20
|
+
|
|
21
|
+
# Create a fog bank
|
|
22
|
+
runner.create_fog(fog_type: :uncertainty, density: 0.6,
|
|
23
|
+
domain: :reasoning, content: 'Multiple conflicting hypotheses')
|
|
24
|
+
|
|
25
|
+
# Sweep: beacons disperse fog in their domain
|
|
26
|
+
runner.sweep
|
|
27
|
+
# => { success: true, swept: 1, beacons_dimmed: 0, beacons_pruned: 0 }
|
|
28
|
+
|
|
29
|
+
# Check navigation status
|
|
30
|
+
runner.navigation_status
|
|
31
|
+
# => { success: true, total_beacons: 1, total_fog_banks: 1, avg_luminosity: 0.8, avg_density: ..., ... }
|
|
32
|
+
|
|
33
|
+
# List brightest beacons
|
|
34
|
+
runner.list_beacons(limit: 5)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Development
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bundle install
|
|
41
|
+
bundle exec rspec
|
|
42
|
+
bundle exec rubocop
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## License
|
|
46
|
+
|
|
47
|
+
MIT
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/cognitive_lighthouse/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-cognitive-lighthouse'
|
|
7
|
+
spec.version = Legion::Extensions::CognitiveLighthouse::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
spec.license = 'MIT'
|
|
11
|
+
|
|
12
|
+
spec.summary = 'Cognitive lighthouse LEX — guiding beacons that cut through cognitive fog'
|
|
13
|
+
spec.description = 'Models guiding beacons that periodically sweep their beam to illuminate areas ' \
|
|
14
|
+
'of uncertainty, helping navigate complex decision spaces. Beacons can be steady ' \
|
|
15
|
+
'or rotating, can dim in fog, and can guide other agents through ambiguity.'
|
|
16
|
+
spec.homepage = 'https://github.com/LegionIO/lex-cognitive-lighthouse'
|
|
17
|
+
|
|
18
|
+
spec.required_ruby_version = '>= 3.4'
|
|
19
|
+
|
|
20
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
21
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
|
22
|
+
spec.metadata['documentation_uri'] = "#{spec.homepage}#readme"
|
|
23
|
+
spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
24
|
+
spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
|
|
25
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
26
|
+
|
|
27
|
+
spec.files = Dir.chdir(__dir__) do
|
|
28
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(test|spec|features)/}) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
spec.require_paths = ['lib']
|
|
32
|
+
spec.add_development_dependency 'legion-gaia'
|
|
33
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveLighthouse
|
|
6
|
+
class Client
|
|
7
|
+
include Runners::CognitiveLighthouse
|
|
8
|
+
|
|
9
|
+
def initialize(engine: nil, **)
|
|
10
|
+
@engine = engine || Helpers::LighthouseEngine.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def default_engine
|
|
16
|
+
@engine
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveLighthouse
|
|
6
|
+
module Helpers
|
|
7
|
+
class Beacon
|
|
8
|
+
attr_reader :id, :beacon_type, :domain, :content, :sweep_angle, :lit_at
|
|
9
|
+
attr_accessor :luminosity
|
|
10
|
+
|
|
11
|
+
def initialize(beacon_type:, domain:, content:, luminosity: nil, sweep_angle: nil)
|
|
12
|
+
validate_beacon_type!(beacon_type)
|
|
13
|
+
@id = SecureRandom.uuid
|
|
14
|
+
@beacon_type = beacon_type.to_sym
|
|
15
|
+
@domain = domain.to_s
|
|
16
|
+
@content = content.to_s
|
|
17
|
+
@luminosity = (luminosity || 0.7).to_f.clamp(0.0, 1.0).round(10)
|
|
18
|
+
@sweep_angle = (sweep_angle || 0.0).to_f.clamp(0.0, 360.0).round(10)
|
|
19
|
+
@lit_at = Time.now.utc
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def brighten!(rate: Constants::LUMINOSITY_RATE)
|
|
23
|
+
@luminosity = (@luminosity + rate).clamp(0.0, 1.0).round(10)
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def dim!(rate: Constants::LUMINOSITY_RATE)
|
|
28
|
+
@luminosity = (@luminosity - rate).clamp(0.0, 1.0).round(10)
|
|
29
|
+
self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def extinguished?
|
|
33
|
+
@luminosity <= 0.0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def blazing?
|
|
37
|
+
@luminosity >= 0.9
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def luminosity_label
|
|
41
|
+
Constants.label_for(Constants::LUMINOSITY_LABELS, @luminosity)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_h
|
|
45
|
+
{
|
|
46
|
+
id: @id,
|
|
47
|
+
beacon_type: @beacon_type,
|
|
48
|
+
domain: @domain,
|
|
49
|
+
content: @content,
|
|
50
|
+
luminosity: @luminosity,
|
|
51
|
+
sweep_angle: @sweep_angle,
|
|
52
|
+
luminosity_label: luminosity_label,
|
|
53
|
+
extinguished: extinguished?,
|
|
54
|
+
blazing: blazing?,
|
|
55
|
+
lit_at: @lit_at
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def validate_beacon_type!(type)
|
|
62
|
+
sym = type.to_sym
|
|
63
|
+
return if Constants::BEACON_TYPES.include?(sym)
|
|
64
|
+
|
|
65
|
+
raise ArgumentError,
|
|
66
|
+
"unknown beacon_type: #{type.inspect}; must be one of #{Constants::BEACON_TYPES.inspect}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveLighthouse
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
BEACON_TYPES = %i[truth clarity warning guidance hope].freeze
|
|
9
|
+
FOG_TYPES = %i[confusion uncertainty ambiguity doubt overwhelm].freeze
|
|
10
|
+
|
|
11
|
+
MAX_BEACONS = 100
|
|
12
|
+
MAX_FOG_BANKS = 50
|
|
13
|
+
|
|
14
|
+
LUMINOSITY_RATE = 0.1
|
|
15
|
+
FOG_DENSITY_RATE = 0.05
|
|
16
|
+
|
|
17
|
+
# Visibility labels (fog density: high density = low visibility)
|
|
18
|
+
VISIBILITY_LABELS = [
|
|
19
|
+
[(0.0...0.1), :crystal_clear],
|
|
20
|
+
[(0.1...0.3), :clear],
|
|
21
|
+
[(0.3...0.5), :hazy],
|
|
22
|
+
[(0.5...0.7), :foggy],
|
|
23
|
+
[(0.7...0.9), :dense_fog],
|
|
24
|
+
[(0.9..), :blind]
|
|
25
|
+
].freeze
|
|
26
|
+
|
|
27
|
+
# Luminosity labels (beacon luminosity: high = bright)
|
|
28
|
+
LUMINOSITY_LABELS = [
|
|
29
|
+
[(0.9..), :blazing],
|
|
30
|
+
[(0.7...0.9), :bright],
|
|
31
|
+
[(0.5...0.7), :steady],
|
|
32
|
+
[(0.3...0.5), :dim],
|
|
33
|
+
[(0.1...0.3), :faint],
|
|
34
|
+
[(..0.1), :dark]
|
|
35
|
+
].freeze
|
|
36
|
+
|
|
37
|
+
def self.label_for(table, value)
|
|
38
|
+
table.each { |range, label| return label if range.cover?(value) }
|
|
39
|
+
table.last.last
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveLighthouse
|
|
6
|
+
module Helpers
|
|
7
|
+
class Fog
|
|
8
|
+
attr_reader :id, :fog_type, :domain, :extent, :formed_at
|
|
9
|
+
attr_accessor :density
|
|
10
|
+
|
|
11
|
+
def initialize(fog_type:, domain:, density: nil, extent: nil)
|
|
12
|
+
validate_fog_type!(fog_type)
|
|
13
|
+
@id = SecureRandom.uuid
|
|
14
|
+
@fog_type = fog_type.to_sym
|
|
15
|
+
@domain = domain.to_s
|
|
16
|
+
@density = (density || 0.5).to_f.clamp(0.0, 1.0).round(10)
|
|
17
|
+
@extent = (extent || 1.0).to_f.clamp(0.0, 1.0).round(10)
|
|
18
|
+
@formed_at = Time.now.utc
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def thicken!(rate: Constants::FOG_DENSITY_RATE)
|
|
22
|
+
@density = (@density + rate).clamp(0.0, 1.0).round(10)
|
|
23
|
+
self
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def disperse!(rate: Constants::FOG_DENSITY_RATE)
|
|
27
|
+
@density = (@density - rate).clamp(0.0, 1.0).round(10)
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def impenetrable?
|
|
32
|
+
@density >= 1.0
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def clearing?
|
|
36
|
+
@density < 0.2
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def visibility_label
|
|
40
|
+
Constants.label_for(Constants::VISIBILITY_LABELS, @density)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_h
|
|
44
|
+
{
|
|
45
|
+
id: @id,
|
|
46
|
+
fog_type: @fog_type,
|
|
47
|
+
domain: @domain,
|
|
48
|
+
density: @density,
|
|
49
|
+
extent: @extent,
|
|
50
|
+
visibility_label: visibility_label,
|
|
51
|
+
impenetrable: impenetrable?,
|
|
52
|
+
clearing: clearing?,
|
|
53
|
+
formed_at: @formed_at
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def validate_fog_type!(type)
|
|
60
|
+
sym = type.to_sym
|
|
61
|
+
return if Constants::FOG_TYPES.include?(sym)
|
|
62
|
+
|
|
63
|
+
raise ArgumentError,
|
|
64
|
+
"unknown fog_type: #{type.inspect}; must be one of #{Constants::FOG_TYPES.inspect}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveLighthouse
|
|
6
|
+
module Helpers
|
|
7
|
+
class LighthouseEngine
|
|
8
|
+
def initialize
|
|
9
|
+
@beacons = {}
|
|
10
|
+
@fog_banks = {}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def light_beacon(beacon_type:, domain:, content:, luminosity: nil, sweep_angle: nil)
|
|
14
|
+
raise ArgumentError, 'too many beacons' if @beacons.size >= Constants::MAX_BEACONS
|
|
15
|
+
|
|
16
|
+
beacon = Beacon.new(
|
|
17
|
+
beacon_type: beacon_type,
|
|
18
|
+
domain: domain,
|
|
19
|
+
content: content,
|
|
20
|
+
luminosity: luminosity,
|
|
21
|
+
sweep_angle: sweep_angle
|
|
22
|
+
)
|
|
23
|
+
@beacons[beacon.id] = beacon
|
|
24
|
+
beacon
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def create_fog(fog_type:, domain:, density: nil, extent: nil)
|
|
28
|
+
raise ArgumentError, 'too many fog banks' if @fog_banks.size >= Constants::MAX_FOG_BANKS
|
|
29
|
+
|
|
30
|
+
fog = Fog.new(fog_type: fog_type, domain: domain, density: density, extent: extent)
|
|
31
|
+
@fog_banks[fog.id] = fog
|
|
32
|
+
fog
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def sweep(beacon_id:, fog_id:)
|
|
36
|
+
beacon = fetch_beacon(beacon_id)
|
|
37
|
+
fog = fetch_fog(fog_id)
|
|
38
|
+
|
|
39
|
+
reduction = (beacon.luminosity * 0.5).round(10)
|
|
40
|
+
fog.disperse!(rate: reduction)
|
|
41
|
+
|
|
42
|
+
{ beacon: beacon.to_h, fog: fog.to_h, reduction: reduction }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def dim_all!(rate: Constants::LUMINOSITY_RATE)
|
|
46
|
+
@beacons.each_value { |b| b.dim!(rate: rate) }
|
|
47
|
+
pruned = @beacons.select { |_, b| b.extinguished? }.keys
|
|
48
|
+
pruned.each { |id| @beacons.delete(id) }
|
|
49
|
+
{ remaining: @beacons.size, pruned: pruned.size }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def thicken_all!(rate: Constants::FOG_DENSITY_RATE)
|
|
53
|
+
@fog_banks.each_value { |f| f.thicken!(rate: rate) }
|
|
54
|
+
{ fog_banks: @fog_banks.size }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def brightest_beacons(limit: 5)
|
|
58
|
+
@beacons.values
|
|
59
|
+
.reject(&:extinguished?)
|
|
60
|
+
.sort_by { |b| -b.luminosity }
|
|
61
|
+
.first(limit)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def densest_fogs(limit: 5)
|
|
65
|
+
@fog_banks.values
|
|
66
|
+
.sort_by { |f| -f.density }
|
|
67
|
+
.first(limit)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def visibility_report
|
|
71
|
+
avg_luminosity = compute_average_luminosity
|
|
72
|
+
avg_density = compute_average_density
|
|
73
|
+
net_visibility = (avg_luminosity - avg_density).clamp(0.0, 1.0).round(10)
|
|
74
|
+
|
|
75
|
+
{
|
|
76
|
+
total_beacons: @beacons.size,
|
|
77
|
+
total_fog_banks: @fog_banks.size,
|
|
78
|
+
avg_luminosity: avg_luminosity,
|
|
79
|
+
avg_density: avg_density,
|
|
80
|
+
net_visibility: net_visibility,
|
|
81
|
+
blazing_beacons: @beacons.count { |_, b| b.blazing? },
|
|
82
|
+
extinguished: @beacons.count { |_, b| b.extinguished? },
|
|
83
|
+
impenetrable_fog: @fog_banks.count { |_, f| f.impenetrable? },
|
|
84
|
+
clearing_fog: @fog_banks.count { |_, f| f.clearing? }
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def all_beacons
|
|
89
|
+
@beacons.values
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def all_fog_banks
|
|
93
|
+
@fog_banks.values
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def fetch_beacon(id)
|
|
99
|
+
@beacons.fetch(id) { raise ArgumentError, "beacon not found: #{id}" }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def fetch_fog(id)
|
|
103
|
+
@fog_banks.fetch(id) { raise ArgumentError, "fog bank not found: #{id}" }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def compute_average_luminosity
|
|
107
|
+
return 0.0 if @beacons.empty?
|
|
108
|
+
|
|
109
|
+
total = @beacons.values.sum(&:luminosity)
|
|
110
|
+
(total / @beacons.size).round(10)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def compute_average_density
|
|
114
|
+
return 0.0 if @fog_banks.empty?
|
|
115
|
+
|
|
116
|
+
total = @fog_banks.values.sum(&:density)
|
|
117
|
+
(total / @fog_banks.size).round(10)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveLighthouse
|
|
6
|
+
module Runners
|
|
7
|
+
module CognitiveLighthouse
|
|
8
|
+
extend self
|
|
9
|
+
|
|
10
|
+
include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
11
|
+
|
|
12
|
+
def light_beacon(beacon_type:, domain:, content:, luminosity: nil,
|
|
13
|
+
sweep_angle: nil, engine: nil, **)
|
|
14
|
+
eng = resolve_engine(engine)
|
|
15
|
+
beacon = eng.light_beacon(
|
|
16
|
+
beacon_type: beacon_type,
|
|
17
|
+
domain: domain,
|
|
18
|
+
content: content,
|
|
19
|
+
luminosity: luminosity,
|
|
20
|
+
sweep_angle: sweep_angle
|
|
21
|
+
)
|
|
22
|
+
Legion::Logging.debug "[lighthouse] lit beacon: type=#{beacon_type} domain=#{domain} " \
|
|
23
|
+
"luminosity=#{beacon.luminosity}"
|
|
24
|
+
{ success: true, beacon: beacon.to_h }
|
|
25
|
+
rescue ArgumentError => e
|
|
26
|
+
{ success: false, error: e.message }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def create_fog(fog_type:, domain:, density: nil, extent: nil, engine: nil, **)
|
|
30
|
+
eng = resolve_engine(engine)
|
|
31
|
+
fog = eng.create_fog(fog_type: fog_type, domain: domain,
|
|
32
|
+
density: density, extent: extent)
|
|
33
|
+
Legion::Logging.debug "[lighthouse] created fog: type=#{fog_type} domain=#{domain} " \
|
|
34
|
+
"density=#{fog.density}"
|
|
35
|
+
{ success: true, fog: fog.to_h }
|
|
36
|
+
rescue ArgumentError => e
|
|
37
|
+
{ success: false, error: e.message }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def sweep(beacon_id:, fog_id:, engine: nil, **)
|
|
41
|
+
eng = resolve_engine(engine)
|
|
42
|
+
result = eng.sweep(beacon_id: beacon_id, fog_id: fog_id)
|
|
43
|
+
Legion::Logging.debug "[lighthouse] sweep: beacon=#{beacon_id} fog=#{fog_id} " \
|
|
44
|
+
"reduction=#{result[:reduction]}"
|
|
45
|
+
{ success: true, **result }
|
|
46
|
+
rescue ArgumentError => e
|
|
47
|
+
{ success: false, error: e.message }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def list_beacons(engine: nil, domain: nil, beacon_type: nil, **)
|
|
51
|
+
eng = resolve_engine(engine)
|
|
52
|
+
results = eng.all_beacons
|
|
53
|
+
results = results.select { |b| b.domain == domain.to_s } if domain
|
|
54
|
+
results = results.select { |b| b.beacon_type == beacon_type.to_sym } if beacon_type
|
|
55
|
+
{ success: true, beacons: results.map(&:to_h), count: results.size }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def navigation_status(engine: nil, **)
|
|
59
|
+
eng = resolve_engine(engine)
|
|
60
|
+
{ success: true, report: eng.visibility_report }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def resolve_engine(engine)
|
|
66
|
+
engine || default_engine
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def default_engine
|
|
70
|
+
@default_engine ||= Helpers::LighthouseEngine.new
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
require_relative 'cognitive_lighthouse/version'
|
|
6
|
+
require_relative 'cognitive_lighthouse/helpers/constants'
|
|
7
|
+
require_relative 'cognitive_lighthouse/helpers/beacon'
|
|
8
|
+
require_relative 'cognitive_lighthouse/helpers/fog'
|
|
9
|
+
require_relative 'cognitive_lighthouse/helpers/lighthouse_engine'
|
|
10
|
+
require_relative 'cognitive_lighthouse/runners/cognitive_lighthouse'
|
|
11
|
+
require_relative 'cognitive_lighthouse/client'
|
|
12
|
+
|
|
13
|
+
module Legion
|
|
14
|
+
module Extensions
|
|
15
|
+
module CognitiveLighthouse
|
|
16
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-cognitive-lighthouse
|
|
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: Models guiding beacons that periodically sweep their beam to illuminate
|
|
27
|
+
areas of uncertainty, helping navigate complex decision spaces. Beacons can be steady
|
|
28
|
+
or rotating, can dim in fog, and can guide other agents through ambiguity.
|
|
29
|
+
email:
|
|
30
|
+
- matthewdiverson@gmail.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- ".github/workflows/ci.yml"
|
|
36
|
+
- ".gitignore"
|
|
37
|
+
- ".rspec"
|
|
38
|
+
- ".rubocop.yml"
|
|
39
|
+
- CLAUDE.md
|
|
40
|
+
- Gemfile
|
|
41
|
+
- Gemfile.lock
|
|
42
|
+
- README.md
|
|
43
|
+
- lex-cognitive-lighthouse.gemspec
|
|
44
|
+
- lib/legion/extensions/cognitive_lighthouse.rb
|
|
45
|
+
- lib/legion/extensions/cognitive_lighthouse/client.rb
|
|
46
|
+
- lib/legion/extensions/cognitive_lighthouse/helpers/beacon.rb
|
|
47
|
+
- lib/legion/extensions/cognitive_lighthouse/helpers/constants.rb
|
|
48
|
+
- lib/legion/extensions/cognitive_lighthouse/helpers/fog.rb
|
|
49
|
+
- lib/legion/extensions/cognitive_lighthouse/helpers/lighthouse_engine.rb
|
|
50
|
+
- lib/legion/extensions/cognitive_lighthouse/runners/cognitive_lighthouse.rb
|
|
51
|
+
- lib/legion/extensions/cognitive_lighthouse/version.rb
|
|
52
|
+
homepage: https://github.com/LegionIO/lex-cognitive-lighthouse
|
|
53
|
+
licenses:
|
|
54
|
+
- MIT
|
|
55
|
+
metadata:
|
|
56
|
+
homepage_uri: https://github.com/LegionIO/lex-cognitive-lighthouse
|
|
57
|
+
source_code_uri: https://github.com/LegionIO/lex-cognitive-lighthouse
|
|
58
|
+
documentation_uri: https://github.com/LegionIO/lex-cognitive-lighthouse#readme
|
|
59
|
+
changelog_uri: https://github.com/LegionIO/lex-cognitive-lighthouse/blob/main/CHANGELOG.md
|
|
60
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-cognitive-lighthouse/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: Cognitive lighthouse LEX — guiding beacons that cut through cognitive fog
|
|
79
|
+
test_files: []
|