lex-dream 0.1.1
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 +56 -0
- data/CHANGELOG.md +19 -0
- data/CLAUDE.md +152 -0
- data/Gemfile +17 -0
- data/README.md +56 -0
- data/lex-dream.gemspec +30 -0
- data/lib/legion/extensions/dream/actors/dream_cycle.rb +41 -0
- data/lib/legion/extensions/dream/client.rb +25 -0
- data/lib/legion/extensions/dream/helpers/agenda.rb +70 -0
- data/lib/legion/extensions/dream/helpers/association_walker.rb +55 -0
- data/lib/legion/extensions/dream/helpers/constants.rb +30 -0
- data/lib/legion/extensions/dream/helpers/contradiction_detector.rb +82 -0
- data/lib/legion/extensions/dream/helpers/dream_journal.rb +227 -0
- data/lib/legion/extensions/dream/helpers/dream_store.rb +87 -0
- data/lib/legion/extensions/dream/helpers/llm_enhancer.rb +269 -0
- data/lib/legion/extensions/dream/runners/dream_cycle.rb +324 -0
- data/lib/legion/extensions/dream/version.rb +9 -0
- data/lib/legion/extensions/dream.rb +20 -0
- data/logs/dreams/dream-2026-03-14_064520.md +49 -0
- data/logs/dreams/dream-2026-03-14_064546.md +49 -0
- data/logs/dreams/dream-2026-03-14_065244.md +49 -0
- data/logs/dreams/dream-2026-03-14_065358.md +49 -0
- data/logs/dreams/dream-2026-03-14_065435.md +49 -0
- metadata +87 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 18c812c7de44c6dd1a06bc41c54e04cc03d88d745f47da1d72765c4d399a342f
|
|
4
|
+
data.tar.gz: 90f655a9201fe82647715d70564df33e6a29b633e2cea4857bb04316719780b6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 98b2744be8165cda9ed07087ba01ad57acb3b2dcf3179071923d265a71688c1b478e8ca5b0a029224db09254b756b856bf07de63c3ac321f85b3419ce0bbe675
|
|
7
|
+
data.tar.gz: 4cb73181be977b2681afa77002849ac000c6758b9d716d7064d507358a07cfaafd1cca30ca6fc061f247ef93bd639401a1a111d403a2815aeee6b87fff59f77a
|
|
@@ -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,56 @@
|
|
|
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
|
|
54
|
+
|
|
55
|
+
Gemspec/DevelopmentDependencies:
|
|
56
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.1.1] - 2026-03-16
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Guard `DreamCycle#memory` with `defined?` check and use `Memory::Client.new` instead of fragile `Object.new.extend` pattern
|
|
9
|
+
- Guard `DreamCycle#identity` with `defined?` check to prevent `NoMethodError` when lex-identity is not loaded
|
|
10
|
+
- Early return in `execute_dream_cycle` when lex-memory is unavailable (logs warning instead of crashing every 5 minutes)
|
|
11
|
+
- Guard `Dream::Client#initialize` against missing Memory, Identity, and Emotion extensions
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- `spec/legion/extensions/dream/actors/dream_cycle_spec.rb` (7 examples) — tests for the DreamCycle actor (Every 300s)
|
|
15
|
+
|
|
16
|
+
## [0.1.0] - 2026-03-13
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- Initial release
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# lex-dream
|
|
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
|
+
Autonomous dream cycle for the LegionIO cognitive architecture. When the agent is idle, it enters `dormant_active` mode and runs an eight-phase internal consolidation cycle: memory audit, association walking, contradiction resolution, identity entropy assessment, agenda formation, consolidation commit, dream reflection, and dream narration. Dream output feeds back into lex-memory as semantic traces that surface organically through normal retrieval — no explicit surfacing mechanism.
|
|
10
|
+
|
|
11
|
+
## Gem Info
|
|
12
|
+
|
|
13
|
+
- **Gem name**: `lex-dream`
|
|
14
|
+
- **Version**: `0.1.1`
|
|
15
|
+
- **Module**: `Legion::Extensions::Dream`
|
|
16
|
+
- **Ruby**: `>= 3.4`
|
|
17
|
+
- **License**: MIT
|
|
18
|
+
|
|
19
|
+
## File Structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
lib/legion/extensions/dream/
|
|
23
|
+
version.rb
|
|
24
|
+
actors/
|
|
25
|
+
dream_cycle.rb # Periodic actor (Every 300s) — calls execute_dream_cycle
|
|
26
|
+
helpers/
|
|
27
|
+
constants.rb # Configuration defaults, DREAM_CYCLE_PHASES list, agenda item types
|
|
28
|
+
dream_store.rb # In-memory store for agenda, walk results, contradictions, entropy
|
|
29
|
+
association_walker.rb # Novelty-scored multi-hop association traversal + start trace selection
|
|
30
|
+
contradiction_detector.rb # Domain-tag overlap + valence divergence detection and resolution
|
|
31
|
+
agenda.rb # Phase output synthesis and semantic trace conversion
|
|
32
|
+
llm_enhancer.rb # Optional LLM integration for contradiction resolution, agenda synthesis, and journal narration
|
|
33
|
+
dream_journal.rb # Writes human-readable dream journal entries to logs/dreams/
|
|
34
|
+
runners/
|
|
35
|
+
dream_cycle.rb # Eight-phase dream cycle runner (all phase methods)
|
|
36
|
+
client.rb # Client with dependency injection for memory/identity/emotion
|
|
37
|
+
spec/
|
|
38
|
+
legion/extensions/dream/
|
|
39
|
+
actors/
|
|
40
|
+
dream_cycle_spec.rb
|
|
41
|
+
helpers/
|
|
42
|
+
dream_store_spec.rb
|
|
43
|
+
association_walker_spec.rb
|
|
44
|
+
contradiction_detector_spec.rb
|
|
45
|
+
agenda_spec.rb
|
|
46
|
+
runners/
|
|
47
|
+
dream_cycle_spec.rb
|
|
48
|
+
client_spec.rb
|
|
49
|
+
integration_spec.rb
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Key Constants (Helpers::Constants)
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
ASSOCIATION_WALK_HOPS = 12 # max BFS depth
|
|
56
|
+
ASSOCIATION_NOVELTY_THRESHOLD = 0.65 # min novelty to log a walk result
|
|
57
|
+
CONTRADICTION_RESOLUTION_STRATEGY = :recency_weighted # or :intensity_weighted
|
|
58
|
+
ENTROPY_WINDOW = 7 # sessions for identity entropy trend
|
|
59
|
+
AGENDA_MAX_ITEMS = 5 # max agenda items carried forward
|
|
60
|
+
DREAM_PARTITION_TTL = 604_800 # 7 days before unrecalled items expire
|
|
61
|
+
AGENDA_ITEM_TYPES = %i[unresolved surfacing curious corrective]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## The Eight Dream Phases
|
|
65
|
+
|
|
66
|
+
All phases execute sequentially via direct Ruby method calls (not queued through transport). Phases are defined in `Constants::DREAM_CYCLE_PHASES`.
|
|
67
|
+
|
|
68
|
+
| Phase | Method | What It Does |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| 1. Memory Audit | `phase_memory_audit` | Runs decay + tier migration, marks consolidation candidates, collects unresolved traces using `EMERGENT_UNRESOLVED` heuristics |
|
|
71
|
+
| 2. Association Walk | `phase_association_walk` | Selects highest-salience unresolved trace, BFS walks associations with novelty scoring, materializes novel links via `hebbian_link` |
|
|
72
|
+
| 3. Contradiction Resolution | `phase_contradiction_resolution` | Detects opposing-valence traces by domain overlap; resolves via LLM if available, otherwise falls back to recency/intensity weighting |
|
|
73
|
+
| 4. Identity Entropy Check | `phase_identity_entropy_check` | Calls `identity.check_entropy`, records result in DreamStore, flags drift as corrective agenda item |
|
|
74
|
+
| 5. Agenda Formation | `phase_agenda_formation` | Synthesizes phases 1-4 into typed, weighted agenda items; uses LLM synthesis if available, mechanical fallback otherwise |
|
|
75
|
+
| 6. Consolidation Commit | `phase_consolidation_commit` | Converts agenda to semantic traces in lex-memory, clears unresolved flags, expires stale dream state, flushes cache store |
|
|
76
|
+
| 7. Dream Reflection | `phase_dream_reflection` | Calls `lex-reflection` to assess cognitive health of the dream cycle (skipped if extension not loaded) |
|
|
77
|
+
| 8. Dream Narration | `phase_dream_narration` | Calls `lex-narrator` to produce a narrative summary (skipped if extension not loaded) |
|
|
78
|
+
|
|
79
|
+
## DreamStore
|
|
80
|
+
|
|
81
|
+
In-memory store owned entirely by lex-dream. The agent's private journal:
|
|
82
|
+
|
|
83
|
+
- `agenda` — weighted orientation items (`:unresolved`, `:surfacing`, `:curious`, `:corrective`)
|
|
84
|
+
- `walk_results` — novel association paths with novelty scores
|
|
85
|
+
- `contradictions` — resolution logs with domain and outcome
|
|
86
|
+
- `entropy_history` — identity entropy snapshots
|
|
87
|
+
|
|
88
|
+
Items expire via `DREAM_PARTITION_TTL`. Oldest agenda items drop when `AGENDA_MAX_ITEMS` exceeded.
|
|
89
|
+
|
|
90
|
+
## LLM Enhancement
|
|
91
|
+
|
|
92
|
+
`Helpers::LlmEnhancer` provides optional LLM-enhanced processing:
|
|
93
|
+
- `available?` — returns true when `Legion::LLM` is started
|
|
94
|
+
- `resolve_contradiction(trace_a, trace_b, strategy:)` — prompts LLM to reason about which trace is more reliable; falls back to mechanical resolution if unavailable or on error
|
|
95
|
+
- `synthesize_agenda(unresolved_traces:, contradictions:, walk_results:, entropy:)` — prompts LLM to synthesize agenda items from all phase data; mechanical fallback via `Helpers::Agenda.build_from_phases`
|
|
96
|
+
- `narrate_journal(results, phase_data)` — prompts LLM to write a 3-5 paragraph analytical narrative for the dream journal; called by `DreamJournal.section_narrative` when LLM is available
|
|
97
|
+
|
|
98
|
+
The system prompt instructs the LLM to act as the agent's internal dream processor: concise, analytical, structured reasoning only.
|
|
99
|
+
|
|
100
|
+
## Dream Journal
|
|
101
|
+
|
|
102
|
+
`Helpers::DreamJournal.write_entry(results:, phase_data:, dream_store:)` is called after all phases complete but before dream state is cleared. It writes a human-readable Markdown journal entry to `<Dir.pwd>/logs/dreams/dream-<timestamp>.md`. When LLM is available, `LlmEnhancer.narrate_journal` prepends an analytical reflection section before the phase-by-phase breakdown.
|
|
103
|
+
|
|
104
|
+
## Client
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
Client.new(memory:, identity:, emotion:)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Dependency clients initialized once at boot, held for process lifetime. Defaults to creating its own instances if none injected. The `dream_store` is public (`attr_reader`). All other state is private.
|
|
111
|
+
|
|
112
|
+
## Organic Recall — How Dream Output Reaches Active Sessions
|
|
113
|
+
|
|
114
|
+
No explicit surfacing mechanism. Dream output feeds back through normal lex-memory retrieval:
|
|
115
|
+
|
|
116
|
+
- Novel associations materialized as Hebbian links → participate in `retrieve_ranked`
|
|
117
|
+
- Agenda items become semantic traces with `dream:*` domain tags and high emotional intensity
|
|
118
|
+
- Reinforced traces have boosted strength → win retrieval ranking
|
|
119
|
+
- The agent doesn't "decide to bring something up" — relevant dream-formed knowledge surfaces contextually
|
|
120
|
+
|
|
121
|
+
## Integration Points
|
|
122
|
+
|
|
123
|
+
- **lex-tick**: Dream runs in `dormant_active` mode. Eight dream phases registered in `MODE_PHASES[:dormant_active]`. Tick budget is uncapped (`Float::INFINITY`).
|
|
124
|
+
- **lex-memory**: Direct calls to `decay_cycle`, `migrate_tier`, `hebbian_link`. Calls `CacheStore#reload` before the cycle starts (picks up traces written by other processes). Calls `CacheStore#flush` after the cycle completes.
|
|
125
|
+
- **lex-identity**: Calls `check_entropy` during phase 4 for drift detection.
|
|
126
|
+
- **lex-emotion**: Uses emotional intensity/valence from traces for salience ranking and contradiction detection.
|
|
127
|
+
- **lex-reflection**: Phase 7 delegates to `lex-reflection` for cognitive health assessment (optional, skipped if not loaded).
|
|
128
|
+
- **lex-narrator**: Phase 8 delegates to `lex-narrator` for dream narrative generation (optional, skipped if not loaded).
|
|
129
|
+
- **legion-llm**: LlmEnhancer checks `Legion::LLM.started?` to determine if LLM-enhanced resolution/synthesis is available.
|
|
130
|
+
|
|
131
|
+
## Transition Rules (in lex-tick)
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
dormant → dormant_active: no signals for 1800s (DREAM_IDLE_THRESHOLD)
|
|
135
|
+
dormant_active → sentinel: high-salience signal (>= 0.7) or human_direct
|
|
136
|
+
dormant_active → dormant: dream cycle completes (dream_complete: true)
|
|
137
|
+
sentinel → dormant_active: no signals for 600s (SENTINEL_TO_DREAM_THRESHOLD)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Development Notes
|
|
141
|
+
|
|
142
|
+
- Actor namespace is `module Actor` (singular), matching the pattern used in other agentic extensions
|
|
143
|
+
- Actor runner function is `execute_dream_cycle` (not `run_dream_cycle`)
|
|
144
|
+
- `memory.send(:default_store)` needed because `default_store` is private on the memory runner
|
|
145
|
+
- `store.reload` and `store.flush` are called defensively with `respond_to?` guards (only implemented by `CacheStore`, not `Store`)
|
|
146
|
+
- `EMERGENT_UNRESOLVED` lambda defines five heuristics for finding unprocessed traces beyond the simple `unresolved: true` flag — episodic with zero reinforcement and high emotion, low-confidence unreinforced, negative-valence semantic/procedural, high-intensity unreinforced
|
|
147
|
+
- Phase methods collect data into `@phase_data` for use by later phases and for the dream journal
|
|
148
|
+
- `@phase_data[:agenda_snapshot]` is taken at the start of `phase_consolidation_commit` before `dream_store.clear` is called, preserving the snapshot for the dream journal
|
|
149
|
+
- `dream_store.clear` is called at the end of `consolidation_commit` to reset state for the next dream cycle
|
|
150
|
+
- Dream reflection and narration phases return `{ status: :skipped, reason: :extension_not_loaded }` when their dependencies are absent — the cycle completes normally
|
|
151
|
+
- Guards: `memory` uses `defined?(Legion::Extensions::Memory::Client)`, `identity` uses `defined?(Legion::Extensions::Identity::Runners::Identity)` — avoids crashes when extensions are not loaded
|
|
152
|
+
- All state is in-memory (consistent with v0.1.1 pattern across agentic extensions)
|
data/Gemfile
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
|
+
|
|
5
|
+
gemspec
|
|
6
|
+
|
|
7
|
+
group :test do
|
|
8
|
+
gem 'lex-emotion', path: '../lex-emotion'
|
|
9
|
+
gem 'lex-identity', path: '../lex-identity'
|
|
10
|
+
gem 'lex-memory', path: '../lex-memory'
|
|
11
|
+
gem 'lex-tick', path: '../lex-tick'
|
|
12
|
+
gem 'rspec', '~> 3.0'
|
|
13
|
+
gem 'rubocop', require: false
|
|
14
|
+
gem 'rubocop-rspec', require: false
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
gem 'legion-gaia', path: '../../legion-gaia'
|
data/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# lex-dream
|
|
2
|
+
|
|
3
|
+
Autonomous dream cycle for the [LegionIO](https://github.com/LegionIO/LegionIO) cognitive architecture. When the agent is idle, it runs an eight-phase internal consolidation cycle: memory audit, association walking, contradiction resolution, identity entropy assessment, agenda formation, consolidation commit, dream reflection, and dream narration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add to your Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'lex-dream'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## How It Works
|
|
14
|
+
|
|
15
|
+
Dream output feeds back into lex-memory as semantic traces with `dream:*` domain tags. These surface organically through normal retrieval ranking -- no explicit surfacing mechanism needed.
|
|
16
|
+
|
|
17
|
+
### The Eight Dream Phases
|
|
18
|
+
|
|
19
|
+
| Phase | What It Does |
|
|
20
|
+
|-------|-------------|
|
|
21
|
+
| Memory Audit | Runs decay + tier migration, marks consolidation candidates, collects unresolved traces |
|
|
22
|
+
| Association Walk | BFS walks associations from highest-salience unresolved trace, materializes novel Hebbian links |
|
|
23
|
+
| Contradiction Resolution | Detects opposing-valence traces by domain; resolves via LLM if available, else mechanical fallback |
|
|
24
|
+
| Identity Entropy Check | Calls lex-identity entropy assessment, flags drift as corrective agenda item |
|
|
25
|
+
| Agenda Formation | Synthesizes phases 1-4 into typed, weighted agenda items (LLM synthesis when available) |
|
|
26
|
+
| Consolidation Commit | Converts agenda to semantic traces in lex-memory, clears dream state |
|
|
27
|
+
| Dream Reflection | Assesses cognitive health of the dream cycle via lex-reflection (skipped if not loaded) |
|
|
28
|
+
| Dream Narration | Produces a narrative summary via lex-narrator (skipped if not loaded) |
|
|
29
|
+
|
|
30
|
+
### Agenda Item Types
|
|
31
|
+
|
|
32
|
+
- `:unresolved` -- traces that need attention
|
|
33
|
+
- `:surfacing` -- unresolvable contradictions
|
|
34
|
+
- `:curious` -- novel associations discovered during walk
|
|
35
|
+
- `:corrective` -- identity entropy drift detected
|
|
36
|
+
|
|
37
|
+
## Dependencies
|
|
38
|
+
|
|
39
|
+
- `lex-memory` -- trace storage, decay, Hebbian linking, cache reload/flush
|
|
40
|
+
- `lex-identity` -- entropy assessment
|
|
41
|
+
- `lex-emotion` -- emotional intensity for salience ranking
|
|
42
|
+
- `lex-reflection` -- optional cognitive health assessment (dream_reflection phase)
|
|
43
|
+
- `lex-narrator` -- optional narrative generation (dream_narration phase)
|
|
44
|
+
- `legion-llm` -- optional LLM enhancement for contradiction resolution, agenda synthesis, and journal narration
|
|
45
|
+
|
|
46
|
+
## Development
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
bundle install
|
|
50
|
+
bundle exec rspec
|
|
51
|
+
bundle exec rubocop
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT
|
data/lex-dream.gemspec
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/dream/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-dream'
|
|
7
|
+
spec.version = Legion::Extensions::Dream::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'LEX Dream'
|
|
12
|
+
spec.description = 'Autonomous dream cycle for brain-modeled agentic AI — memory consolidation, ' \
|
|
13
|
+
'association walking, contradiction resolution, and agenda formation'
|
|
14
|
+
spec.homepage = 'https://github.com/LegionIO/lex-dream'
|
|
15
|
+
spec.license = 'MIT'
|
|
16
|
+
spec.required_ruby_version = '>= 3.4'
|
|
17
|
+
|
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-dream'
|
|
20
|
+
spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-dream'
|
|
21
|
+
spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-dream'
|
|
22
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-dream/issues'
|
|
23
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
24
|
+
|
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
27
|
+
end
|
|
28
|
+
spec.require_paths = ['lib']
|
|
29
|
+
spec.add_development_dependency 'legion-gaia'
|
|
30
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/actors/every'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Dream
|
|
8
|
+
module Actor
|
|
9
|
+
class DreamCycle < Legion::Extensions::Actors::Every
|
|
10
|
+
def runner_class
|
|
11
|
+
Legion::Extensions::Dream::Runners::DreamCycle
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def runner_function
|
|
15
|
+
'execute_dream_cycle'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def time
|
|
19
|
+
300
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run_now?
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def use_runner?
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def check_subtask?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def generate_task?
|
|
35
|
+
false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Dream
|
|
6
|
+
class Client
|
|
7
|
+
include Runners::DreamCycle
|
|
8
|
+
|
|
9
|
+
attr_reader :dream_store
|
|
10
|
+
|
|
11
|
+
def initialize(memory: nil, identity: nil, emotion: nil, **)
|
|
12
|
+
@memory = memory || (Legion::Extensions::Memory::Client.new if defined?(Legion::Extensions::Memory::Client))
|
|
13
|
+
@identity = identity || (Legion::Extensions::Identity::Client.new if defined?(Legion::Extensions::Identity::Client))
|
|
14
|
+
@emotion = emotion || (Legion::Extensions::Emotion::Client.new if defined?(Legion::Extensions::Emotion::Client))
|
|
15
|
+
@dream_store = Helpers::DreamStore.new
|
|
16
|
+
@phase_data = {}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
attr_reader :memory, :identity, :emotion, :phase_data
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Dream
|
|
6
|
+
module Helpers
|
|
7
|
+
module Agenda
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def build_from_phases(phase_outputs)
|
|
11
|
+
now = Time.now.utc
|
|
12
|
+
|
|
13
|
+
items = Array(phase_outputs[:unresolved_traces]).map do |trace|
|
|
14
|
+
{
|
|
15
|
+
type: :unresolved,
|
|
16
|
+
content: { trace_id: trace[:trace_id] },
|
|
17
|
+
weight: trace[:emotional_intensity],
|
|
18
|
+
created_at: now
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Array(phase_outputs[:contradictions]).each do |contradiction|
|
|
23
|
+
next unless contradiction[:resolution] == :unresolvable
|
|
24
|
+
|
|
25
|
+
items << {
|
|
26
|
+
type: :surfacing,
|
|
27
|
+
content: { trace_ids: contradiction[:trace_ids], domain: contradiction[:domain] },
|
|
28
|
+
weight: 0.7,
|
|
29
|
+
created_at: now
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Array(phase_outputs[:walk_results]).each do |result|
|
|
34
|
+
items << {
|
|
35
|
+
type: :curious,
|
|
36
|
+
content: { trace_id: result[:trace_id], path: result[:path] },
|
|
37
|
+
weight: result[:novelty_score],
|
|
38
|
+
created_at: now
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
entropy = phase_outputs[:entropy] || {}
|
|
43
|
+
if entropy[:classification] == :high_entropy && entropy[:trend] == :rising
|
|
44
|
+
items << {
|
|
45
|
+
type: :corrective,
|
|
46
|
+
content: { classification: entropy[:classification], trend: entropy[:trend] },
|
|
47
|
+
weight: entropy[:entropy],
|
|
48
|
+
created_at: now
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
items
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_semantic_traces(agenda_items)
|
|
56
|
+
agenda_items.map do |item|
|
|
57
|
+
Legion::Extensions::Memory::Helpers::Trace.new_trace(
|
|
58
|
+
type: :semantic,
|
|
59
|
+
content_payload: { dream_agenda: item[:type], **item[:content] },
|
|
60
|
+
emotional_intensity: item[:weight],
|
|
61
|
+
domain_tags: ["dream:#{item[:type]}"],
|
|
62
|
+
origin: :direct_experience
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Dream
|
|
6
|
+
module Helpers
|
|
7
|
+
module AssociationWalker
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def walk(store:, start_id:, max_hops: Constants::ASSOCIATION_WALK_HOPS, # rubocop:disable Metrics/ParameterLists
|
|
11
|
+
novelty_threshold: Constants::ASSOCIATION_NOVELTY_THRESHOLD,
|
|
12
|
+
known_paths: Set.new, **)
|
|
13
|
+
raw = store.walk_associations(start_id: start_id, max_hops: max_hops)
|
|
14
|
+
|
|
15
|
+
raw.filter_map do |result|
|
|
16
|
+
score = compute_novelty(
|
|
17
|
+
path: result[:path],
|
|
18
|
+
depth: result[:depth],
|
|
19
|
+
store: store,
|
|
20
|
+
known_paths: known_paths
|
|
21
|
+
)
|
|
22
|
+
next if score < novelty_threshold
|
|
23
|
+
|
|
24
|
+
result.merge(novelty_score: score)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def select_start_trace(store:)
|
|
29
|
+
# Prefer episodic unresolved traces, fall back to any high-intensity unresolved
|
|
30
|
+
candidates = store.all_traces.select do |t|
|
|
31
|
+
t[:unresolved] == true ||
|
|
32
|
+
(t[:trace_type] == :episodic && t[:reinforcement_count].zero? && t[:emotional_intensity] >= 0.5) ||
|
|
33
|
+
(t[:confidence].is_a?(Numeric) && t[:confidence] < 0.4 && t[:reinforcement_count].zero?)
|
|
34
|
+
end
|
|
35
|
+
candidates.max_by { |t| t[:emotional_intensity] }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def compute_novelty(path:, depth:, store:, known_paths:)
|
|
39
|
+
path_key = path.join('->')
|
|
40
|
+
return 0.0 if known_paths.include?(path_key)
|
|
41
|
+
|
|
42
|
+
depth_factor = depth / Constants::ASSOCIATION_WALK_HOPS.to_f
|
|
43
|
+
|
|
44
|
+
type_diversity = path.map { |id| store.get(id)&.dig(:trace_type) }.compact.uniq.size
|
|
45
|
+
type_factor = type_diversity / path.size.to_f
|
|
46
|
+
|
|
47
|
+
((depth_factor * 0.4) + (type_factor * 0.6)).clamp(0.0, 1.0)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private :compute_novelty
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Dream
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
ASSOCIATION_WALK_HOPS = 12
|
|
9
|
+
ASSOCIATION_NOVELTY_THRESHOLD = 0.65
|
|
10
|
+
CONTRADICTION_RESOLUTION_STRATEGY = :recency_weighted
|
|
11
|
+
ENTROPY_WINDOW = 7
|
|
12
|
+
AGENDA_MAX_ITEMS = 5
|
|
13
|
+
DREAM_PARTITION_TTL = 604_800
|
|
14
|
+
AGENDA_ITEM_TYPES = %i[unresolved surfacing curious corrective].freeze
|
|
15
|
+
|
|
16
|
+
DREAM_CYCLE_PHASES = %i[
|
|
17
|
+
memory_audit
|
|
18
|
+
association_walk
|
|
19
|
+
contradiction_resolution
|
|
20
|
+
identity_entropy_check
|
|
21
|
+
agenda_formation
|
|
22
|
+
consolidation_commit
|
|
23
|
+
dream_reflection
|
|
24
|
+
dream_narration
|
|
25
|
+
].freeze
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|