lex-cortex 0.2.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 +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +53 -0
- data/CHANGELOG.md +22 -0
- data/CLAUDE.md +114 -0
- data/Dockerfile +6 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +87 -0
- data/LICENSE +21 -0
- data/README.md +85 -0
- data/lex-cortex.gemspec +29 -0
- data/lib/legion/extensions/cortex/actors/think.rb +43 -0
- data/lib/legion/extensions/cortex/helpers/runner_host.rb +24 -0
- data/lib/legion/extensions/cortex/helpers/signal_buffer.rb +51 -0
- data/lib/legion/extensions/cortex/helpers/wiring.rb +130 -0
- data/lib/legion/extensions/cortex/runners/cortex.rb +154 -0
- data/lib/legion/extensions/cortex/version.rb +9 -0
- data/lib/legion/extensions/cortex.rb +15 -0
- metadata +79 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: e6bcca0ab85d1848f298f00ddfda8c6709580d140a32dde790e54d7434c0f7cc
|
|
4
|
+
data.tar.gz: 93255dd1da0af08c6841e7d5df7ac61625d576b4eefcea4cfd860ee3b34be0ac
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 88b4fecfa6ecfd91e6bc5c8a693bc8ea256df36f03672b290423d27174914c31de14c2c6c507dc164b71c1672d9d8d6f9e301ddbd2065ca7caf8a293dc66fcd0
|
|
7
|
+
data.tar.gz: 25b9cccbdaf46214f450c378fc326d9fea87ff419343a314834371a8a1dc05bf9dbc3af6cc709190c640a24568ddfe6979ab3a86b57ac94183fd6896d13eb51a
|
|
@@ -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,53 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 3.4
|
|
3
|
+
NewCops: enable
|
|
4
|
+
SuggestExtensions: false
|
|
5
|
+
|
|
6
|
+
Layout/LineLength:
|
|
7
|
+
Max: 160
|
|
8
|
+
|
|
9
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
|
10
|
+
EnforcedStyle: space
|
|
11
|
+
|
|
12
|
+
Layout/HashAlignment:
|
|
13
|
+
EnforcedHashRocketStyle: table
|
|
14
|
+
EnforcedColonStyle: table
|
|
15
|
+
|
|
16
|
+
Metrics/MethodLength:
|
|
17
|
+
Max: 50
|
|
18
|
+
|
|
19
|
+
Metrics/ClassLength:
|
|
20
|
+
Max: 1500
|
|
21
|
+
|
|
22
|
+
Metrics/ModuleLength:
|
|
23
|
+
Max: 1500
|
|
24
|
+
|
|
25
|
+
Metrics/BlockLength:
|
|
26
|
+
Max: 40
|
|
27
|
+
Exclude:
|
|
28
|
+
- 'spec/**/*'
|
|
29
|
+
|
|
30
|
+
Metrics/AbcSize:
|
|
31
|
+
Max: 60
|
|
32
|
+
|
|
33
|
+
Metrics/CyclomaticComplexity:
|
|
34
|
+
Max: 15
|
|
35
|
+
|
|
36
|
+
Metrics/PerceivedComplexity:
|
|
37
|
+
Max: 17
|
|
38
|
+
|
|
39
|
+
Style/Documentation:
|
|
40
|
+
Enabled: false
|
|
41
|
+
|
|
42
|
+
Style/SymbolArray:
|
|
43
|
+
Enabled: true
|
|
44
|
+
|
|
45
|
+
Style/FrozenStringLiteralComment:
|
|
46
|
+
Enabled: true
|
|
47
|
+
EnforcedStyle: always
|
|
48
|
+
|
|
49
|
+
Naming/FileName:
|
|
50
|
+
Enabled: false
|
|
51
|
+
|
|
52
|
+
Naming/PredicateMethod:
|
|
53
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.0] - 2026-03-15
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- All runner methods delegate to `Legion::Gaia` when available (deprecation shim)
|
|
7
|
+
- Think actor skips execution when GAIA heartbeat is active (`run_now?` returns `false`)
|
|
8
|
+
- Deprecation warnings emitted on all delegated calls
|
|
9
|
+
|
|
10
|
+
### Deprecated
|
|
11
|
+
- This extension is deprecated in favor of `legion-gaia`. All functionality has been absorbed into the GAIA cognitive coordination layer.
|
|
12
|
+
|
|
13
|
+
## [0.1.1] - 2026-03-15
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- `spec/legion/extensions/cortex/actors/think_spec.rb` (7 examples) — tests for the Think actor (Every 1s)
|
|
17
|
+
- `spec/legion/extensions/cortex/integration/cortex_tick_spec.rb` (12 examples) — integration tests for the cortex→tick critical path: real RunnerHost wiring, signal ingestion, mode transitions, phase handler invocation, budget enforcement, and rewire
|
|
18
|
+
|
|
19
|
+
## [0.1.0] - 2026-03-13
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- Initial release
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# lex-cortex
|
|
2
|
+
|
|
3
|
+
**Level 3 Documentation**
|
|
4
|
+
- **Parent**: `/Users/miverso2/rubymine/legion/extensions-agentic/CLAUDE.md`
|
|
5
|
+
- **Grandparent**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
Cognitive wiring layer for the LegionIO agentic architecture. Cortex discovers loaded agentic extensions at runtime, builds phase handlers from their runners, and drives the tick cycle through `lex-tick`. It replaces standalone tick usage — when cortex is loaded, the tick actor disables itself and cortex's Think actor becomes the sole tick driver.
|
|
10
|
+
|
|
11
|
+
## Gem Info
|
|
12
|
+
|
|
13
|
+
- **Gem name**: `lex-cortex`
|
|
14
|
+
- **Version**: `0.2.0`
|
|
15
|
+
- **Module**: `Legion::Extensions::Cortex`
|
|
16
|
+
- **Ruby**: `>= 3.4`
|
|
17
|
+
- **License**: MIT
|
|
18
|
+
- **Status**: DEPRECATED — functionality absorbed by `legion-gaia`. This gem is a thin delegation shim.
|
|
19
|
+
|
|
20
|
+
## File Structure
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
lib/legion/extensions/cortex/
|
|
24
|
+
version.rb
|
|
25
|
+
helpers/
|
|
26
|
+
wiring.rb # PHASE_MAP, PHASE_ARGS, resolve_runner_class, build_phase_handlers
|
|
27
|
+
signal_buffer.rb # Thread-safe signal queue (Mutex + Array, max 1000)
|
|
28
|
+
runner_host.rb # Wraps runner modules into instantiable objects with persistent state
|
|
29
|
+
runners/
|
|
30
|
+
cortex.rb # think, ingest_signal, cortex_status, rewire
|
|
31
|
+
actors/
|
|
32
|
+
think.rb # Every 1s actor driving the think loop
|
|
33
|
+
spec/
|
|
34
|
+
legion/extensions/cortex/
|
|
35
|
+
helpers/
|
|
36
|
+
wiring_spec.rb
|
|
37
|
+
signal_buffer_spec.rb
|
|
38
|
+
runner_host_spec.rb
|
|
39
|
+
runners/
|
|
40
|
+
cortex_spec.rb
|
|
41
|
+
client_spec.rb
|
|
42
|
+
spec_helper.rb
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Key Concepts
|
|
46
|
+
|
|
47
|
+
### Phase Handler Wiring
|
|
48
|
+
|
|
49
|
+
`Helpers::Wiring::PHASE_MAP` maps each tick phase to an extension runner method. At startup, cortex discovers which extensions are loaded via `const_defined?` checks and builds a `phase_handlers` hash that `lex-tick`'s `execute_tick` consumes.
|
|
50
|
+
|
|
51
|
+
19 phases mapped:
|
|
52
|
+
- **Active tick** (12 phases): sensory_processing (`Attention:filter_signals`), emotional_evaluation (`Emotion:Valence:evaluate_valence`), memory_retrieval (`Memory:Traces:retrieve_and_reinforce`), identity_entropy_check (`Identity:Identity:check_entropy`), working_memory_integration (`Curiosity:detect_gaps`), procedural_check (`Coldstart:coldstart_progress`), prediction_engine (`Prediction:predict`), mesh_interface (`Mesh:mesh_status`), gut_instinct (`Emotion:Gut:gut_instinct`), action_selection (`Volition:form_intentions`), memory_consolidation (`Memory:Consolidation:decay_cycle`), post_tick_reflection (`Reflection:reflect`)
|
|
53
|
+
- **Dream cycle** (7 phases): memory_audit, association_walk, contradiction_resolution, agenda_formation (`Curiosity:form_agenda`), consolidation_commit, dream_reflection (`Reflection:reflect`), dream_narration (`Narrator:narrate`)
|
|
54
|
+
|
|
55
|
+
### RunnerHost Pattern
|
|
56
|
+
|
|
57
|
+
Runner modules (like `Memory::Runners::Consolidation`) can't be instantiated directly — they're modules, not classes. `RunnerHost` is a plain object that `extend`s the module, giving it persistent instance state (`@default_store`, `@trust_map`, etc.) across ticks. One RunnerHost per unique extension+runner pair.
|
|
58
|
+
|
|
59
|
+
### Signal Buffer
|
|
60
|
+
|
|
61
|
+
Thread-safe `Mutex + Array` queue (max 1000 entries). External stimuli are pushed via `ingest_signal`, drained each tick by `think`. Signals are normalized with `received_at`, `salience`, and `source_type` defaults.
|
|
62
|
+
|
|
63
|
+
### Memoization with Retry
|
|
64
|
+
|
|
65
|
+
`runner_instances` is memoized for performance but cleared when `lex-tick` isn't found yet (race condition during extension loading). This allows cortex to retry discovery on the next tick rather than permanently failing.
|
|
66
|
+
|
|
67
|
+
## Runner Methods
|
|
68
|
+
|
|
69
|
+
All in `Runners::Cortex`:
|
|
70
|
+
- `think` — drain signal buffer, lazy-wire phase handlers, delegate to tick orchestrator
|
|
71
|
+
- `ingest_signal(signal:, source_type:, salience:)` — push external stimulus into buffer
|
|
72
|
+
- `cortex_status` — discovery info, wired phases, buffer depth
|
|
73
|
+
- `rewire` — clear memoized state, rediscover extensions, rebuild phase handlers
|
|
74
|
+
|
|
75
|
+
## Cortex vs Standalone Tick
|
|
76
|
+
|
|
77
|
+
| | Standalone Tick | Cortex |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| Actor | `Tick::Actor::Tick` (Every 1s) | `Cortex::Actor::Think` (Every 1s) |
|
|
80
|
+
| Phase handlers | Empty `{}` — all phases return `{ status: :no_handler }` | Wired from discovered extensions |
|
|
81
|
+
| Signal input | None (args: `{ signals: [] }`) | Signal buffer drained each tick |
|
|
82
|
+
| Enabled when | Cortex NOT loaded | Always (cortex is the default) |
|
|
83
|
+
|
|
84
|
+
The tick actor checks `!Legion::Extensions.const_defined?(:Cortex)` in `enabled?` and skips `initialize` (no timer created) when cortex is present.
|
|
85
|
+
|
|
86
|
+
## Integration Points
|
|
87
|
+
|
|
88
|
+
Cortex wires these extensions when available:
|
|
89
|
+
- **lex-tick**: Orchestrator (core dependency — cortex cannot function without it)
|
|
90
|
+
- **lex-attention**: Sensory signal filtering (`sensory_processing` phase)
|
|
91
|
+
- **lex-emotion**: Valence evaluation + gut instinct
|
|
92
|
+
- **lex-memory**: Trace retrieval+reinforce, decay cycle, Hebbian linking, tier migration
|
|
93
|
+
- **lex-identity**: Entropy anomaly detection
|
|
94
|
+
- **lex-curiosity**: Working memory integration + dream agenda formation
|
|
95
|
+
- **lex-coldstart**: Bootstrap progress check
|
|
96
|
+
- **lex-prediction**: Forward-model prediction
|
|
97
|
+
- **lex-mesh**: Agent mesh status
|
|
98
|
+
- **lex-volition**: Action intention formation (`action_selection` phase)
|
|
99
|
+
- **lex-reflection**: Post-tick and dream reflection (`post_tick_reflection`, `dream_reflection` phases)
|
|
100
|
+
- **lex-narrator**: Dream narration (`dream_narration` phase)
|
|
101
|
+
- **lex-conflict**: Dream contradiction resolution
|
|
102
|
+
|
|
103
|
+
All are optional — missing extensions result in `{ status: :no_handler }` for their phases.
|
|
104
|
+
|
|
105
|
+
## Development Notes
|
|
106
|
+
|
|
107
|
+
- `PHASE_ARGS` lambdas build kwargs from cortex context (signals, prior_results, valences)
|
|
108
|
+
- `association_walk` extracts trace IDs from `memory_audit` prior results; returns `{ linked: false }` if no traces available
|
|
109
|
+
- Specs stub `Legion::Logging` since it won't be available in test
|
|
110
|
+
- `rubocop:disable` not needed — all methods are within configured limits
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
**Maintained By**: Matthew Iverson (@Esity)
|
data/Dockerfile
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
lex-cortex (0.2.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
|
+
docile (1.4.1)
|
|
15
|
+
json (2.19.1)
|
|
16
|
+
json-schema (6.2.0)
|
|
17
|
+
addressable (~> 2.8)
|
|
18
|
+
bigdecimal (>= 3.1, < 5)
|
|
19
|
+
language_server-protocol (3.17.0.5)
|
|
20
|
+
lint_roller (1.1.0)
|
|
21
|
+
mcp (0.8.0)
|
|
22
|
+
json-schema (>= 4.1)
|
|
23
|
+
parallel (1.27.0)
|
|
24
|
+
parser (3.3.10.2)
|
|
25
|
+
ast (~> 2.4.1)
|
|
26
|
+
racc
|
|
27
|
+
prism (1.9.0)
|
|
28
|
+
public_suffix (7.0.5)
|
|
29
|
+
racc (1.8.1)
|
|
30
|
+
rainbow (3.1.1)
|
|
31
|
+
rake (13.3.1)
|
|
32
|
+
regexp_parser (2.11.3)
|
|
33
|
+
rspec (3.13.2)
|
|
34
|
+
rspec-core (~> 3.13.0)
|
|
35
|
+
rspec-expectations (~> 3.13.0)
|
|
36
|
+
rspec-mocks (~> 3.13.0)
|
|
37
|
+
rspec-core (3.13.6)
|
|
38
|
+
rspec-support (~> 3.13.0)
|
|
39
|
+
rspec-expectations (3.13.5)
|
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
41
|
+
rspec-support (~> 3.13.0)
|
|
42
|
+
rspec-mocks (3.13.8)
|
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
44
|
+
rspec-support (~> 3.13.0)
|
|
45
|
+
rspec-support (3.13.7)
|
|
46
|
+
rspec_junit_formatter (0.6.0)
|
|
47
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
|
48
|
+
rubocop (1.85.1)
|
|
49
|
+
json (~> 2.3)
|
|
50
|
+
language_server-protocol (~> 3.17.0.2)
|
|
51
|
+
lint_roller (~> 1.1.0)
|
|
52
|
+
mcp (~> 0.6)
|
|
53
|
+
parallel (~> 1.10)
|
|
54
|
+
parser (>= 3.3.0.2)
|
|
55
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
56
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
57
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
58
|
+
ruby-progressbar (~> 1.7)
|
|
59
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
60
|
+
rubocop-ast (1.49.1)
|
|
61
|
+
parser (>= 3.3.7.2)
|
|
62
|
+
prism (~> 1.7)
|
|
63
|
+
ruby-progressbar (1.13.0)
|
|
64
|
+
simplecov (0.22.0)
|
|
65
|
+
docile (~> 1.1)
|
|
66
|
+
simplecov-html (~> 0.11)
|
|
67
|
+
simplecov_json_formatter (~> 0.1)
|
|
68
|
+
simplecov-html (0.13.2)
|
|
69
|
+
simplecov_json_formatter (0.1.4)
|
|
70
|
+
unicode-display_width (3.2.0)
|
|
71
|
+
unicode-emoji (~> 4.1)
|
|
72
|
+
unicode-emoji (4.2.0)
|
|
73
|
+
|
|
74
|
+
PLATFORMS
|
|
75
|
+
arm64-darwin-25
|
|
76
|
+
ruby
|
|
77
|
+
|
|
78
|
+
DEPENDENCIES
|
|
79
|
+
lex-cortex!
|
|
80
|
+
rake
|
|
81
|
+
rspec
|
|
82
|
+
rspec_junit_formatter
|
|
83
|
+
rubocop
|
|
84
|
+
simplecov
|
|
85
|
+
|
|
86
|
+
BUNDLED WITH
|
|
87
|
+
2.6.9
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# lex-cortex
|
|
2
|
+
|
|
3
|
+
Cognitive wiring layer for the [LegionIO](https://github.com/LegionIO/LegionIO) agentic architecture. Discovers loaded agentic extensions at runtime, builds phase handlers from their runners, and drives the tick cycle through [lex-tick](https://github.com/LegionIO/lex-tick).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add to your Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'lex-cortex'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## How It Works
|
|
14
|
+
|
|
15
|
+
Cortex sits between the tick orchestrator and all other agentic extensions. On each 1-second tick cycle it:
|
|
16
|
+
|
|
17
|
+
1. Drains the signal buffer (external stimuli pushed via `ingest_signal`)
|
|
18
|
+
2. Discovers which agentic extensions are loaded
|
|
19
|
+
3. Builds phase handlers that map tick phases to extension runner methods
|
|
20
|
+
4. Delegates to `lex-tick`'s `execute_tick` with the wired handlers
|
|
21
|
+
|
|
22
|
+
When cortex is loaded, the standalone tick actor automatically disables itself.
|
|
23
|
+
|
|
24
|
+
### Wired Phases
|
|
25
|
+
|
|
26
|
+
Active tick phases (12):
|
|
27
|
+
|
|
28
|
+
| Phase | Extension | Runner Method |
|
|
29
|
+
|-------|-----------|---------------|
|
|
30
|
+
| `sensory_processing` | lex-attention | `filter_signals` |
|
|
31
|
+
| `emotional_evaluation` | lex-emotion | `evaluate_valence` |
|
|
32
|
+
| `memory_retrieval` | lex-memory | `retrieve_and_reinforce` |
|
|
33
|
+
| `identity_entropy_check` | lex-identity | `check_entropy` |
|
|
34
|
+
| `working_memory_integration` | lex-curiosity | `detect_gaps` |
|
|
35
|
+
| `procedural_check` | lex-coldstart | `coldstart_progress` |
|
|
36
|
+
| `prediction_engine` | lex-prediction | `predict` |
|
|
37
|
+
| `mesh_interface` | lex-mesh | `mesh_status` |
|
|
38
|
+
| `gut_instinct` | lex-emotion | `gut_instinct` |
|
|
39
|
+
| `action_selection` | lex-volition | `form_intentions` |
|
|
40
|
+
| `memory_consolidation` | lex-memory | `decay_cycle` |
|
|
41
|
+
| `post_tick_reflection` | lex-reflection | `reflect` |
|
|
42
|
+
|
|
43
|
+
Dream cycle phases (7):
|
|
44
|
+
|
|
45
|
+
| Phase | Extension | Runner Method |
|
|
46
|
+
|-------|-----------|---------------|
|
|
47
|
+
| `memory_audit` | lex-memory | `retrieve_ranked` |
|
|
48
|
+
| `association_walk` | lex-memory | `hebbian_link` |
|
|
49
|
+
| `contradiction_resolution` | lex-conflict | `active_conflicts` |
|
|
50
|
+
| `agenda_formation` | lex-curiosity | `form_agenda` |
|
|
51
|
+
| `consolidation_commit` | lex-memory | `migrate_tier` |
|
|
52
|
+
| `dream_reflection` | lex-reflection | `reflect` |
|
|
53
|
+
| `dream_narration` | lex-narrator | `narrate` |
|
|
54
|
+
|
|
55
|
+
All extensions are optional. Missing extensions result in `{ status: :no_handler }` for their phases.
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
Cortex runs automatically as a Legion extension. To interact with it programmatically:
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
# Inject a signal
|
|
63
|
+
cortex.ingest_signal(signal: { event: 'user_message', text: 'hello' },
|
|
64
|
+
source_type: :human_direct,
|
|
65
|
+
salience: 0.8)
|
|
66
|
+
|
|
67
|
+
# Check status
|
|
68
|
+
cortex.cortex_status
|
|
69
|
+
# => { extensions_available: 8, wired_phases: 13, buffer_depth: 0, ... }
|
|
70
|
+
|
|
71
|
+
# Force rediscovery of extensions
|
|
72
|
+
cortex.rewire
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Development
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
bundle install
|
|
79
|
+
bundle exec rspec
|
|
80
|
+
bundle exec rubocop
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
MIT
|
data/lex-cortex.gemspec
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/cortex/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-cortex'
|
|
7
|
+
spec.version = Legion::Extensions::Cortex::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'LEX Cortex'
|
|
12
|
+
spec.description = 'Cognitive wiring layer for LegionIO agentic architecture'
|
|
13
|
+
spec.homepage = 'https://github.com/LegionIO/lex-cortex'
|
|
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-cortex'
|
|
19
|
+
spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-cortex'
|
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-cortex'
|
|
21
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-cortex/issues'
|
|
22
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
23
|
+
|
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
26
|
+
end
|
|
27
|
+
spec.require_paths = ['lib']
|
|
28
|
+
spec.add_development_dependency 'legion-gaia'
|
|
29
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/actors/every'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Cortex
|
|
8
|
+
module Actor
|
|
9
|
+
class Think < Legion::Extensions::Actors::Every
|
|
10
|
+
def runner_class
|
|
11
|
+
Legion::Extensions::Cortex::Runners::Cortex
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def runner_function
|
|
15
|
+
'think'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def time
|
|
19
|
+
1
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run_now?
|
|
23
|
+
return false if defined?(Legion::Gaia) && Legion::Gaia.started?
|
|
24
|
+
|
|
25
|
+
true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def use_runner?
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def check_subtask?
|
|
33
|
+
false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def generate_task?
|
|
37
|
+
false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Cortex
|
|
6
|
+
module Helpers
|
|
7
|
+
class RunnerHost
|
|
8
|
+
def initialize(runner_module)
|
|
9
|
+
@runner_module = runner_module
|
|
10
|
+
extend runner_module
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_s
|
|
14
|
+
"RunnerHost(#{@runner_module})"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def inspect
|
|
18
|
+
"#<#{self.class} module=#{@runner_module}>"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Cortex
|
|
6
|
+
module Helpers
|
|
7
|
+
class SignalBuffer
|
|
8
|
+
MAX_BUFFER_SIZE = 1000
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@mutex = Mutex.new
|
|
12
|
+
@buffer = []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def push(signal)
|
|
16
|
+
@mutex.synchronize do
|
|
17
|
+
@buffer.shift if @buffer.size >= MAX_BUFFER_SIZE
|
|
18
|
+
@buffer << normalize_signal(signal)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def drain
|
|
23
|
+
@mutex.synchronize do
|
|
24
|
+
signals = @buffer.dup
|
|
25
|
+
@buffer.clear
|
|
26
|
+
signals
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def size
|
|
31
|
+
@mutex.synchronize { @buffer.size }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def empty?
|
|
35
|
+
@mutex.synchronize { @buffer.empty? }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def normalize_signal(signal)
|
|
41
|
+
signal = { value: signal } unless signal.is_a?(Hash)
|
|
42
|
+
signal[:received_at] ||= Time.now.utc
|
|
43
|
+
signal[:salience] ||= 0.0
|
|
44
|
+
signal[:source_type] ||= :ambient
|
|
45
|
+
signal
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Cortex
|
|
6
|
+
module Helpers
|
|
7
|
+
module Wiring
|
|
8
|
+
# Maps tick phases to the extension runner that handles them.
|
|
9
|
+
# Each entry: { ext: ModuleName, runner: RunnerModule, fn: :method_name }
|
|
10
|
+
# nil entries are intentionally unwired (future or handled inline).
|
|
11
|
+
PHASE_MAP = {
|
|
12
|
+
sensory_processing: { ext: :Attention, runner: :Attention, fn: :filter_signals },
|
|
13
|
+
emotional_evaluation: { ext: :Emotion, runner: :Valence, fn: :evaluate_valence },
|
|
14
|
+
memory_retrieval: { ext: :Memory, runner: :Traces, fn: :retrieve_and_reinforce },
|
|
15
|
+
identity_entropy_check: { ext: :Identity, runner: :Identity, fn: :check_entropy },
|
|
16
|
+
working_memory_integration: { ext: :Curiosity, runner: :Curiosity, fn: :detect_gaps },
|
|
17
|
+
procedural_check: { ext: :Coldstart, runner: :Coldstart, fn: :coldstart_progress },
|
|
18
|
+
prediction_engine: { ext: :Prediction, runner: :Prediction, fn: :predict },
|
|
19
|
+
mesh_interface: { ext: :Mesh, runner: :Mesh, fn: :mesh_status },
|
|
20
|
+
gut_instinct: { ext: :Emotion, runner: :Gut, fn: :gut_instinct },
|
|
21
|
+
action_selection: { ext: :Volition, runner: :Volition, fn: :form_intentions },
|
|
22
|
+
memory_consolidation: { ext: :Memory, runner: :Consolidation, fn: :decay_cycle },
|
|
23
|
+
post_tick_reflection: { ext: :Reflection, runner: :Reflection, fn: :reflect },
|
|
24
|
+
|
|
25
|
+
# Dream cycle phases
|
|
26
|
+
memory_audit: { ext: :Memory, runner: :Traces, fn: :retrieve_ranked },
|
|
27
|
+
association_walk: { ext: :Memory, runner: :Consolidation, fn: :hebbian_link },
|
|
28
|
+
contradiction_resolution: { ext: :Conflict, runner: :Conflict, fn: :active_conflicts },
|
|
29
|
+
agenda_formation: { ext: :Curiosity, runner: :Curiosity, fn: :form_agenda },
|
|
30
|
+
consolidation_commit: { ext: :Memory, runner: :Consolidation, fn: :migrate_tier },
|
|
31
|
+
dream_reflection: { ext: :Reflection, runner: :Reflection, fn: :reflect },
|
|
32
|
+
dream_narration: { ext: :Narrator, runner: :Narrator, fn: :narrate }
|
|
33
|
+
}.freeze
|
|
34
|
+
|
|
35
|
+
# Phase-specific argument builders.
|
|
36
|
+
# Each proc receives the cortex context and returns kwargs for the runner method.
|
|
37
|
+
PHASE_ARGS = {
|
|
38
|
+
sensory_processing: ->(ctx) { { signals: ctx[:signals] || [], active_wonders: ctx.dig(:prior_results, :agenda_formation, :agenda) || [] } },
|
|
39
|
+
emotional_evaluation: ->(ctx) { { signal: ctx[:current_signal] || {}, source_type: :ambient } },
|
|
40
|
+
memory_retrieval: ->(_ctx) { { limit: 10 } },
|
|
41
|
+
identity_entropy_check: ->(_ctx) { {} },
|
|
42
|
+
procedural_check: ->(_ctx) { {} },
|
|
43
|
+
prediction_engine: ->(ctx) { { mode: :functional_mapping, context: ctx[:prior_results] || {} } },
|
|
44
|
+
mesh_interface: ->(_ctx) { {} },
|
|
45
|
+
gut_instinct: ->(ctx) { { valences: ctx[:valences] || [] } },
|
|
46
|
+
action_selection: ->(ctx) { { tick_results: ctx[:prior_results] || {}, cognitive_state: {} } },
|
|
47
|
+
working_memory_integration: ->(ctx) { { prior_results: ctx[:prior_results] || {} } },
|
|
48
|
+
memory_consolidation: ->(_ctx) { {} },
|
|
49
|
+
post_tick_reflection: ->(ctx) { { tick_results: ctx[:prior_results] || {} } },
|
|
50
|
+
memory_audit: ->(_ctx) { { limit: 20 } },
|
|
51
|
+
association_walk: lambda { |ctx|
|
|
52
|
+
audit = ctx.dig(:prior_results, :memory_audit)
|
|
53
|
+
traces = audit.is_a?(Hash) ? audit[:traces] : nil
|
|
54
|
+
traces = [] unless traces.is_a?(Array) && traces.size >= 2
|
|
55
|
+
{ trace_id_a: traces.dig(0, :trace_id), trace_id_b: traces.dig(1, :trace_id) }
|
|
56
|
+
},
|
|
57
|
+
contradiction_resolution: ->(_ctx) { {} },
|
|
58
|
+
agenda_formation: ->(_ctx) { {} },
|
|
59
|
+
consolidation_commit: ->(_ctx) { {} },
|
|
60
|
+
dream_reflection: ->(ctx) { { tick_results: ctx[:prior_results] || {} } },
|
|
61
|
+
dream_narration: ->(ctx) { { tick_results: ctx[:prior_results] || {}, cognitive_state: { source: :dream } } }
|
|
62
|
+
}.freeze
|
|
63
|
+
|
|
64
|
+
module_function
|
|
65
|
+
|
|
66
|
+
def resolve_runner_class(ext_sym, runner_sym)
|
|
67
|
+
return nil unless Legion::Extensions.const_defined?(ext_sym)
|
|
68
|
+
|
|
69
|
+
ext_mod = Legion::Extensions.const_get(ext_sym)
|
|
70
|
+
return nil unless ext_mod.const_defined?(:Runners)
|
|
71
|
+
|
|
72
|
+
runners_mod = ext_mod.const_get(:Runners)
|
|
73
|
+
return nil unless runners_mod.const_defined?(runner_sym)
|
|
74
|
+
|
|
75
|
+
runners_mod.const_get(runner_sym)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def build_phase_handlers(runner_instances)
|
|
79
|
+
handlers = {}
|
|
80
|
+
|
|
81
|
+
PHASE_MAP.each do |phase, mapping|
|
|
82
|
+
next if mapping.nil?
|
|
83
|
+
|
|
84
|
+
instance_key = :"#{mapping[:ext]}_#{mapping[:runner]}"
|
|
85
|
+
instance = runner_instances[instance_key]
|
|
86
|
+
next unless instance
|
|
87
|
+
|
|
88
|
+
fn = mapping[:fn]
|
|
89
|
+
arg_builder = PHASE_ARGS[phase]
|
|
90
|
+
|
|
91
|
+
handlers[phase] = lambda { |state:, signals:, prior_results:|
|
|
92
|
+
ctx = { state: state, signals: signals, prior_results: prior_results,
|
|
93
|
+
current_signal: signals&.last, valences: collect_valences(prior_results) }
|
|
94
|
+
args = arg_builder ? arg_builder.call(ctx) : {}
|
|
95
|
+
instance.send(fn, **args)
|
|
96
|
+
}
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
handlers
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def discover_available_extensions
|
|
103
|
+
available = {}
|
|
104
|
+
|
|
105
|
+
PHASE_MAP.each_value do |mapping|
|
|
106
|
+
next if mapping.nil?
|
|
107
|
+
|
|
108
|
+
key = :"#{mapping[:ext]}_#{mapping[:runner]}"
|
|
109
|
+
next if available.key?(key)
|
|
110
|
+
|
|
111
|
+
runner_class = resolve_runner_class(mapping[:ext], mapping[:runner])
|
|
112
|
+
available[key] = { ext: mapping[:ext], runner: mapping[:runner], loaded: !runner_class.nil? }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
available
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def collect_valences(prior_results)
|
|
119
|
+
return [] unless prior_results.is_a?(Hash)
|
|
120
|
+
|
|
121
|
+
valence_result = prior_results[:emotional_evaluation]
|
|
122
|
+
return [] unless valence_result.is_a?(Hash) && valence_result[:valence]
|
|
123
|
+
|
|
124
|
+
[valence_result[:valence]]
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Cortex
|
|
6
|
+
module Runners
|
|
7
|
+
module Cortex
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
|
|
11
|
+
def think(**)
|
|
12
|
+
if defined?(Legion::Gaia) && Legion::Gaia.started?
|
|
13
|
+
warn '[DEPRECATION] lex-cortex is deprecated. Use legion-gaia directly. (think)'
|
|
14
|
+
return Legion::Gaia.heartbeat
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
signals = signal_buffer.drain
|
|
18
|
+
|
|
19
|
+
# Lazy-wire on first tick or after rewire
|
|
20
|
+
wire_phase_handlers if @phase_handlers.nil?
|
|
21
|
+
|
|
22
|
+
# Resolve the tick orchestrator
|
|
23
|
+
tick_host = runner_instances[:Tick_Orchestrator]
|
|
24
|
+
unless tick_host
|
|
25
|
+
@runner_instances = nil
|
|
26
|
+
@phase_handlers = nil
|
|
27
|
+
Legion::Logging.warn '[cortex] lex-tick not available yet, will retry next tick'
|
|
28
|
+
return { error: :no_tick_extension }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
wired_count = @phase_handlers.size
|
|
32
|
+
Legion::Logging.debug "[cortex] think: signals=#{signals.size} wired_phases=#{wired_count}"
|
|
33
|
+
|
|
34
|
+
result = tick_host.execute_tick(signals: signals, phase_handlers: @phase_handlers)
|
|
35
|
+
|
|
36
|
+
# Collect valences for next tick's gut instinct
|
|
37
|
+
if result.is_a?(Hash) && result[:results]
|
|
38
|
+
valence_result = result[:results][:emotional_evaluation]
|
|
39
|
+
@last_valences = [valence_result[:valence]] if valence_result.is_a?(Hash) && valence_result[:valence]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
result
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def ingest_signal(signal: {}, source_type: :ambient, salience: 0.0, **)
|
|
46
|
+
if defined?(Legion::Gaia) && Legion::Gaia.started?
|
|
47
|
+
warn '[DEPRECATION] lex-cortex is deprecated. Use legion-gaia directly. (ingest_signal)'
|
|
48
|
+
frame = Legion::Gaia::InputFrame.new(
|
|
49
|
+
id: SecureRandom.uuid,
|
|
50
|
+
content: signal.is_a?(Hash) ? signal[:content] || signal.to_s : signal.to_s,
|
|
51
|
+
content_type: :text,
|
|
52
|
+
channel_id: :internal,
|
|
53
|
+
channel_capabilities: {},
|
|
54
|
+
device_context: {},
|
|
55
|
+
session_continuity_id: nil,
|
|
56
|
+
auth_context: {},
|
|
57
|
+
metadata: { source_type: source_type, salience: salience },
|
|
58
|
+
received_at: Time.now.utc
|
|
59
|
+
)
|
|
60
|
+
Legion::Gaia.ingest(frame)
|
|
61
|
+
return { ingested: true, buffer_depth: Legion::Gaia.sensory_buffer&.size || 0 }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
normalized = signal.is_a?(Hash) ? signal : { value: signal }
|
|
65
|
+
normalized[:source_type] = source_type
|
|
66
|
+
normalized[:salience] = salience
|
|
67
|
+
|
|
68
|
+
signal_buffer.push(normalized)
|
|
69
|
+
Legion::Logging.debug "[cortex] signal ingested: source=#{source_type} salience=#{salience} buffer=#{signal_buffer.size}"
|
|
70
|
+
{ ingested: true, buffer_depth: signal_buffer.size }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def cortex_status(**)
|
|
74
|
+
if defined?(Legion::Gaia) && Legion::Gaia.started?
|
|
75
|
+
warn '[DEPRECATION] lex-cortex is deprecated. Use legion-gaia directly. (cortex_status)'
|
|
76
|
+
return Legion::Gaia.status
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
discovery = Helpers::Wiring.discover_available_extensions
|
|
80
|
+
loaded = discovery.count { |_, v| v[:loaded] }
|
|
81
|
+
total = discovery.size
|
|
82
|
+
wired = @phase_handlers&.size || 0
|
|
83
|
+
|
|
84
|
+
Legion::Logging.debug "[cortex] status: extensions=#{loaded}/#{total} wired_phases=#{wired} buffer=#{signal_buffer.size}"
|
|
85
|
+
{
|
|
86
|
+
extensions_available: loaded,
|
|
87
|
+
extensions_total: total,
|
|
88
|
+
wired_phases: wired,
|
|
89
|
+
phase_list: @phase_handlers&.keys || [],
|
|
90
|
+
buffer_depth: signal_buffer.size,
|
|
91
|
+
discovery: discovery
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def rewire(**)
|
|
96
|
+
if defined?(Legion::Gaia) && Legion::Gaia.started?
|
|
97
|
+
warn '[DEPRECATION] lex-cortex is deprecated. Use legion-gaia directly. (rewire)'
|
|
98
|
+
return { rewired: true, delegated_to: :gaia }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
@runner_instances = nil
|
|
102
|
+
@phase_handlers = nil
|
|
103
|
+
wire_phase_handlers
|
|
104
|
+
|
|
105
|
+
wired = @phase_handlers.size
|
|
106
|
+
Legion::Logging.info "[cortex] rewired: #{wired} phases connected"
|
|
107
|
+
{ rewired: true, wired_phases: wired, phase_list: @phase_handlers.keys }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def signal_buffer
|
|
113
|
+
@signal_buffer ||= Helpers::SignalBuffer.new
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def runner_instances
|
|
117
|
+
@runner_instances ||= build_runner_instances
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def build_runner_instances
|
|
121
|
+
instances = {}
|
|
122
|
+
|
|
123
|
+
# Always wire tick orchestrator
|
|
124
|
+
tick_class = Helpers::Wiring.resolve_runner_class(:Tick, :Orchestrator)
|
|
125
|
+
instances[:Tick_Orchestrator] = Helpers::RunnerHost.new(tick_class) if tick_class
|
|
126
|
+
|
|
127
|
+
# Wire all phase map entries
|
|
128
|
+
Helpers::Wiring::PHASE_MAP.each_value do |mapping|
|
|
129
|
+
next if mapping.nil?
|
|
130
|
+
|
|
131
|
+
key = :"#{mapping[:ext]}_#{mapping[:runner]}"
|
|
132
|
+
next if instances.key?(key)
|
|
133
|
+
|
|
134
|
+
runner_class = Helpers::Wiring.resolve_runner_class(mapping[:ext], mapping[:runner])
|
|
135
|
+
if runner_class
|
|
136
|
+
instances[key] = Helpers::RunnerHost.new(runner_class)
|
|
137
|
+
Legion::Logging.debug "[cortex] wired: #{mapping[:ext]}::#{mapping[:runner]}"
|
|
138
|
+
else
|
|
139
|
+
Legion::Logging.debug "[cortex] skipped: #{mapping[:ext]}::#{mapping[:runner]} (not loaded)"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
instances
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def wire_phase_handlers
|
|
147
|
+
@phase_handlers = Helpers::Wiring.build_phase_handlers(runner_instances)
|
|
148
|
+
Legion::Logging.info "[cortex] phase handlers built: #{@phase_handlers.keys.join(', ')}"
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/cortex/version'
|
|
4
|
+
require 'legion/extensions/cortex/helpers/wiring'
|
|
5
|
+
require 'legion/extensions/cortex/helpers/signal_buffer'
|
|
6
|
+
require 'legion/extensions/cortex/helpers/runner_host'
|
|
7
|
+
require 'legion/extensions/cortex/runners/cortex'
|
|
8
|
+
|
|
9
|
+
module Legion
|
|
10
|
+
module Extensions
|
|
11
|
+
module Cortex
|
|
12
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-cortex
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.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: Cognitive wiring layer for LegionIO agentic architecture
|
|
27
|
+
email:
|
|
28
|
+
- matthewdiverson@gmail.com
|
|
29
|
+
executables: []
|
|
30
|
+
extensions: []
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
files:
|
|
33
|
+
- ".github/workflows/ci.yml"
|
|
34
|
+
- ".gitignore"
|
|
35
|
+
- ".rspec"
|
|
36
|
+
- ".rubocop.yml"
|
|
37
|
+
- CHANGELOG.md
|
|
38
|
+
- CLAUDE.md
|
|
39
|
+
- Dockerfile
|
|
40
|
+
- Gemfile
|
|
41
|
+
- Gemfile.lock
|
|
42
|
+
- LICENSE
|
|
43
|
+
- README.md
|
|
44
|
+
- lex-cortex.gemspec
|
|
45
|
+
- lib/legion/extensions/cortex.rb
|
|
46
|
+
- lib/legion/extensions/cortex/actors/think.rb
|
|
47
|
+
- lib/legion/extensions/cortex/helpers/runner_host.rb
|
|
48
|
+
- lib/legion/extensions/cortex/helpers/signal_buffer.rb
|
|
49
|
+
- lib/legion/extensions/cortex/helpers/wiring.rb
|
|
50
|
+
- lib/legion/extensions/cortex/runners/cortex.rb
|
|
51
|
+
- lib/legion/extensions/cortex/version.rb
|
|
52
|
+
homepage: https://github.com/LegionIO/lex-cortex
|
|
53
|
+
licenses:
|
|
54
|
+
- MIT
|
|
55
|
+
metadata:
|
|
56
|
+
homepage_uri: https://github.com/LegionIO/lex-cortex
|
|
57
|
+
source_code_uri: https://github.com/LegionIO/lex-cortex
|
|
58
|
+
documentation_uri: https://github.com/LegionIO/lex-cortex
|
|
59
|
+
changelog_uri: https://github.com/LegionIO/lex-cortex
|
|
60
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-cortex/issues
|
|
61
|
+
rubygems_mfa_required: 'true'
|
|
62
|
+
rdoc_options: []
|
|
63
|
+
require_paths:
|
|
64
|
+
- lib
|
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '3.4'
|
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
requirements: []
|
|
76
|
+
rubygems_version: 3.6.9
|
|
77
|
+
specification_version: 4
|
|
78
|
+
summary: LEX Cortex
|
|
79
|
+
test_files: []
|