lex-cognitive-metabolism 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 +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +58 -0
- data/CLAUDE.md +95 -0
- data/Gemfile +12 -0
- data/LICENSE +21 -0
- data/README.md +51 -0
- data/lex-cognitive-metabolism.gemspec +29 -0
- data/lib/legion/extensions/cognitive_metabolism/client.rb +25 -0
- data/lib/legion/extensions/cognitive_metabolism/helpers/constants.rb +45 -0
- data/lib/legion/extensions/cognitive_metabolism/helpers/energy_reserve.rb +81 -0
- data/lib/legion/extensions/cognitive_metabolism/helpers/metabolic_cycle.rb +64 -0
- data/lib/legion/extensions/cognitive_metabolism/helpers/metabolism_engine.rb +121 -0
- data/lib/legion/extensions/cognitive_metabolism/runners/cognitive_metabolism.rb +83 -0
- data/lib/legion/extensions/cognitive_metabolism/version.rb +9 -0
- data/lib/legion/extensions/cognitive_metabolism.rb +18 -0
- metadata +78 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 19eba116503c91b42ca676c5b7a5252973d32f83a8772a52c1c653af91da343b
|
|
4
|
+
data.tar.gz: d0f46b89bb8b79e725f43472ca8df65c30fe2053cefc2376d2d3d2f044631cfc
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d574a9365e90c4113e59f6f41663b7acc5329cab7ed0f0557c28b466f70d34fb91fc3f49342bae457104f5bc47349a3b3a862cf1805caf2faced0f693466063a
|
|
7
|
+
data.tar.gz: c8d3ef82f31d6270c0928961d5bf00b5413738ca33d2252148cbb15d3aaf93d19bcb308a6b0975ea890eb5d92136b71c876b6efe1a8031b1fdf21e5cea29f0e2
|
|
@@ -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,58 @@
|
|
|
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: 25
|
|
18
|
+
|
|
19
|
+
Metrics/ClassLength:
|
|
20
|
+
Max: 150
|
|
21
|
+
|
|
22
|
+
Metrics/ModuleLength:
|
|
23
|
+
Max: 150
|
|
24
|
+
|
|
25
|
+
Metrics/BlockLength:
|
|
26
|
+
Max: 40
|
|
27
|
+
Exclude:
|
|
28
|
+
- 'spec/**/*'
|
|
29
|
+
|
|
30
|
+
Metrics/AbcSize:
|
|
31
|
+
Max: 25
|
|
32
|
+
|
|
33
|
+
Metrics/ParameterLists:
|
|
34
|
+
Max: 8
|
|
35
|
+
MaxOptionalParameters: 8
|
|
36
|
+
|
|
37
|
+
Style/Documentation:
|
|
38
|
+
Enabled: false
|
|
39
|
+
|
|
40
|
+
Style/SymbolArray:
|
|
41
|
+
Enabled: true
|
|
42
|
+
|
|
43
|
+
Style/FrozenStringLiteralComment:
|
|
44
|
+
Enabled: true
|
|
45
|
+
EnforcedStyle: always
|
|
46
|
+
|
|
47
|
+
Style/OneClassPerFile:
|
|
48
|
+
Exclude:
|
|
49
|
+
- 'spec/spec_helper.rb'
|
|
50
|
+
|
|
51
|
+
Naming/FileName:
|
|
52
|
+
Enabled: false
|
|
53
|
+
|
|
54
|
+
Naming/PredicateMethod:
|
|
55
|
+
Enabled: false
|
|
56
|
+
|
|
57
|
+
Naming/PredicatePrefix:
|
|
58
|
+
Enabled: false
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# lex-cognitive-metabolism
|
|
2
|
+
|
|
3
|
+
**Level 3 Leaf Documentation**
|
|
4
|
+
- **Parent**: `/Users/miverso2/rubymine/legion/extensions-agentic/CLAUDE.md`
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Energy reserve model for cognitive processing. Inspired by biological metabolism: spending energy on operations depletes reserves and degrades efficiency; recovery restores both. Catabolism converts complex structures into energy (breakdown for fuel); anabolism converts energy into structural value (building). Metabolic cycles track sequences of operations with timing and energy-per-operation metrics. Six operation types with defined costs: `perception` (5), `reasoning` (15), `creativity` (20), and others.
|
|
9
|
+
|
|
10
|
+
## Gem Info
|
|
11
|
+
|
|
12
|
+
- **Gem name**: `lex-cognitive-metabolism`
|
|
13
|
+
- **Module**: `Legion::Extensions::CognitiveMetabolism`
|
|
14
|
+
- **Version**: `0.1.0`
|
|
15
|
+
- **Ruby**: `>= 3.4`
|
|
16
|
+
- **License**: MIT
|
|
17
|
+
|
|
18
|
+
## File Structure
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
lib/legion/extensions/cognitive_metabolism/
|
|
22
|
+
version.rb
|
|
23
|
+
client.rb
|
|
24
|
+
helpers/
|
|
25
|
+
constants.rb
|
|
26
|
+
energy_reserve.rb
|
|
27
|
+
metabolic_cycle.rb
|
|
28
|
+
runners/
|
|
29
|
+
cognitive_metabolism.rb
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Key Constants
|
|
33
|
+
|
|
34
|
+
| Constant | Value | Purpose |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `MAX_ENERGY` | `1000.0` | Maximum energy reserve |
|
|
37
|
+
| `RESTING_METABOLIC_RATE` | `0.5` | Baseline energy consumed per idle cycle |
|
|
38
|
+
| `RECOVERY_RATE` | `2.0` | Energy restored per recovery unit |
|
|
39
|
+
| `EFFICIENCY_DECAY` | `0.01` | Efficiency reduction per energy-spending operation |
|
|
40
|
+
| `OPERATION_COSTS` | hash | Per-type energy costs (perception=5, reasoning=15, creativity=20, etc.) |
|
|
41
|
+
| `METABOLIC_STATES` | symbol array | `%i[hyperactive active resting recovering depleted]` |
|
|
42
|
+
| `STATE_THRESHOLDS` | hash | Energy ratio thresholds for each metabolic state |
|
|
43
|
+
|
|
44
|
+
## Helpers
|
|
45
|
+
|
|
46
|
+
### `Helpers::EnergyReserve`
|
|
47
|
+
Core energy tracker with efficiency modulator.
|
|
48
|
+
|
|
49
|
+
- `energy_ratio` — `energy / MAX_ENERGY`
|
|
50
|
+
- `state` — current metabolic state based on `energy_ratio` vs `STATE_THRESHOLDS`
|
|
51
|
+
- `depleted?` — energy at or below zero
|
|
52
|
+
- `spend!(operation_type)` — deducts operation cost divided by current efficiency; degrades efficiency by `EFFICIENCY_DECAY`
|
|
53
|
+
- `recover!(amount)` — restores energy by `amount * RECOVERY_RATE`; partially restores efficiency at `0.5x` rate
|
|
54
|
+
- `catabolize!(complexity)` — converts complexity * 10 into energy (breakdown)
|
|
55
|
+
- `anabolize!(energy_amount)` — converts energy_amount to `structure_value` via efficiency ratio
|
|
56
|
+
|
|
57
|
+
### `Helpers::MetabolicCycle`
|
|
58
|
+
Records an operational cycle.
|
|
59
|
+
|
|
60
|
+
- `record_operation(type:, cost:)` — appends operation record
|
|
61
|
+
- `complete!` — marks cycle done, sets `completed_at`
|
|
62
|
+
- `duration_seconds` — wall-clock duration
|
|
63
|
+
- `average_energy_per_operation` — total cost / operation count
|
|
64
|
+
|
|
65
|
+
## Runners
|
|
66
|
+
|
|
67
|
+
Module: `Runners::CognitiveMetabolism`
|
|
68
|
+
|
|
69
|
+
| Runner Method | Description |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `create_reserve(initial_energy:)` | Initialize an energy reserve |
|
|
72
|
+
| `spend_energy(operation_type:)` | Spend energy on an operation |
|
|
73
|
+
| `recover(amount:)` | Restore energy and partial efficiency |
|
|
74
|
+
| `catabolize(complexity:)` | Convert complexity to energy |
|
|
75
|
+
| `anabolize(energy_amount:)` | Convert energy to structural value |
|
|
76
|
+
| `metabolic_status` | Current reserve state |
|
|
77
|
+
| `run_cycle(operations:)` | Execute a sequence of operations as a cycle |
|
|
78
|
+
|
|
79
|
+
All runners return `{success: true/false, ...}` hashes.
|
|
80
|
+
|
|
81
|
+
## Integration Points
|
|
82
|
+
|
|
83
|
+
- `lex-tick` integration: `metabolic_status` can gate whether full-active mode is available (depleted reserve → fallback to sentinel)
|
|
84
|
+
- `lex-cognitive-load`: extraneous load maps to energy overhead; reducing extraneous load = recovering energy
|
|
85
|
+
- `lex-emotion` arousal correlates with energy level: depleted → low arousal
|
|
86
|
+
- `lex-dream` dormant_active cycle can trigger `recover` operations during idle consolidation
|
|
87
|
+
- Catabolism (breaking down old structures) parallels `lex-memory` decay: pruned traces release conceptual energy
|
|
88
|
+
|
|
89
|
+
## Development Notes
|
|
90
|
+
|
|
91
|
+
- `Client` instantiates a single `EnergyReserve`; runners operate on it
|
|
92
|
+
- `spend!` cost is divided by efficiency: at `efficiency = 0.5`, operations cost double
|
|
93
|
+
- `recover!` restores efficiency at `0.5x` rate to prevent instant full reset after recovery
|
|
94
|
+
- `OPERATION_COSTS` keys must match the `operation_type:` argument to `spend_energy`; unknown types raise or return error
|
|
95
|
+
- `MetabolicCycle` is a lightweight record object; it does not hold a reference to the reserve
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
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 all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# lex-cognitive-metabolism
|
|
2
|
+
|
|
3
|
+
Energy reserve and metabolic cycle model for LegionIO cognitive agents. Operations consume energy and degrade efficiency; recovery restores both. Catabolism breaks down complexity into energy; anabolism converts energy into structural value.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
- Energy reserve with 5 metabolic states: hyperactive, active, resting, recovering, depleted
|
|
8
|
+
- Six operation types with defined costs (perception=5, reasoning=15, creativity=20)
|
|
9
|
+
- Efficiency modulator: spending energy degrades efficiency; higher operations cost more when efficiency is low
|
|
10
|
+
- Recovery restores energy and partially restores efficiency
|
|
11
|
+
- Catabolism: convert cognitive complexity into energy (useful during restructuring)
|
|
12
|
+
- Anabolism: convert energy into structural value (useful when building new patterns)
|
|
13
|
+
- Metabolic cycles: group sequences of operations with timing and cost metrics
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
# Create a reserve
|
|
19
|
+
runner.create_reserve(initial_energy: 500.0)
|
|
20
|
+
|
|
21
|
+
# Spend energy on operations
|
|
22
|
+
runner.spend_energy(operation_type: :reasoning)
|
|
23
|
+
# => { success: true, spent: 15.0, remaining: 485.0, efficiency: 0.49, state: :active }
|
|
24
|
+
|
|
25
|
+
runner.spend_energy(operation_type: :creativity)
|
|
26
|
+
# => { success: true, spent: 20.0 / efficiency, ... }
|
|
27
|
+
|
|
28
|
+
# Recover
|
|
29
|
+
runner.recover(amount: 10.0)
|
|
30
|
+
# => { success: true, restored: 20.0, efficiency_restored: 10.0, state: :active }
|
|
31
|
+
|
|
32
|
+
# Catabolize to gain energy from complexity
|
|
33
|
+
runner.catabolize(complexity: 5.0)
|
|
34
|
+
# => { success: true, energy_gained: 50.0 }
|
|
35
|
+
|
|
36
|
+
# Current status
|
|
37
|
+
runner.metabolic_status
|
|
38
|
+
# => { success: true, energy: 485.0, energy_ratio: 0.485, state: :active, efficiency: 0.49, ... }
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Development
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
bundle install
|
|
45
|
+
bundle exec rspec
|
|
46
|
+
bundle exec rubocop
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
MIT
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/cognitive_metabolism/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-cognitive-metabolism'
|
|
7
|
+
spec.version = Legion::Extensions::CognitiveMetabolism::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'LEX Cognitive Metabolism'
|
|
12
|
+
spec.description = 'ATP-like cognitive energy system with metabolic cycles, catabolism, and anabolism for brain-modeled agentic AI'
|
|
13
|
+
spec.homepage = 'https://github.com/LegionIO/lex-cognitive-metabolism'
|
|
14
|
+
spec.license = 'MIT'
|
|
15
|
+
spec.required_ruby_version = '>= 3.4'
|
|
16
|
+
|
|
17
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
18
|
+
spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-cognitive-metabolism'
|
|
19
|
+
spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-cognitive-metabolism'
|
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-cognitive-metabolism'
|
|
21
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-cognitive-metabolism/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,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/cognitive_metabolism/helpers/constants'
|
|
4
|
+
require 'legion/extensions/cognitive_metabolism/helpers/energy_reserve'
|
|
5
|
+
require 'legion/extensions/cognitive_metabolism/helpers/metabolic_cycle'
|
|
6
|
+
require 'legion/extensions/cognitive_metabolism/helpers/metabolism_engine'
|
|
7
|
+
require 'legion/extensions/cognitive_metabolism/runners/cognitive_metabolism'
|
|
8
|
+
|
|
9
|
+
module Legion
|
|
10
|
+
module Extensions
|
|
11
|
+
module CognitiveMetabolism
|
|
12
|
+
class Client
|
|
13
|
+
include Runners::CognitiveMetabolism
|
|
14
|
+
|
|
15
|
+
def initialize(**)
|
|
16
|
+
@engine = Helpers::MetabolismEngine.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
attr_reader :engine
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveMetabolism
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
MAX_ENERGY = 1000.0
|
|
9
|
+
RESTING_METABOLIC_RATE = 0.5
|
|
10
|
+
RECOVERY_RATE = 2.0
|
|
11
|
+
EFFICIENCY_DECAY = 0.01
|
|
12
|
+
|
|
13
|
+
OPERATION_COSTS = {
|
|
14
|
+
perception: 5.0,
|
|
15
|
+
memory_retrieval: 8.0,
|
|
16
|
+
reasoning: 15.0,
|
|
17
|
+
creativity: 20.0,
|
|
18
|
+
decision: 12.0,
|
|
19
|
+
communication: 10.0
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
METABOLIC_STATES = %i[optimal efficient normal strained depleted].freeze
|
|
23
|
+
|
|
24
|
+
STATE_THRESHOLDS = {
|
|
25
|
+
optimal: (0.8..),
|
|
26
|
+
efficient: (0.6...0.8),
|
|
27
|
+
normal: (0.4...0.6),
|
|
28
|
+
strained: (0.15...0.4),
|
|
29
|
+
depleted: (..0.15)
|
|
30
|
+
}.freeze
|
|
31
|
+
|
|
32
|
+
module_function
|
|
33
|
+
|
|
34
|
+
def label_for(energy_ratio)
|
|
35
|
+
ratio = energy_ratio.clamp(0.0, 1.0)
|
|
36
|
+
STATE_THRESHOLDS.each do |state, range|
|
|
37
|
+
return state if range.cover?(ratio)
|
|
38
|
+
end
|
|
39
|
+
:depleted
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module CognitiveMetabolism
|
|
8
|
+
module Helpers
|
|
9
|
+
class EnergyReserve
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :current_energy, :max_energy, :metabolic_rate, :efficiency, :created_at
|
|
13
|
+
|
|
14
|
+
def initialize(max_energy: MAX_ENERGY, metabolic_rate: RESTING_METABOLIC_RATE, efficiency: 1.0)
|
|
15
|
+
@id = SecureRandom.uuid
|
|
16
|
+
@max_energy = max_energy.clamp(1.0, Float::INFINITY)
|
|
17
|
+
@current_energy = @max_energy
|
|
18
|
+
@metabolic_rate = metabolic_rate.clamp(0.0, Float::INFINITY)
|
|
19
|
+
@efficiency = efficiency.clamp(0.0, 1.0)
|
|
20
|
+
@created_at = Time.now.utc
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def energy_ratio
|
|
24
|
+
(@current_energy / @max_energy).clamp(0.0, 1.0)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def state
|
|
28
|
+
Constants.label_for(energy_ratio)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def depleted?
|
|
32
|
+
state == :depleted
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def spend!(amount)
|
|
36
|
+
effective_cost = amount / @efficiency.clamp(0.01, 1.0)
|
|
37
|
+
before = @current_energy
|
|
38
|
+
@current_energy = (@current_energy - effective_cost).clamp(0.0, @max_energy)
|
|
39
|
+
@efficiency = (@efficiency - EFFICIENCY_DECAY).clamp(0.0, 1.0)
|
|
40
|
+
before - @current_energy
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def recover!(amount)
|
|
44
|
+
before = @current_energy
|
|
45
|
+
@current_energy = (@current_energy + amount).clamp(0.0, @max_energy)
|
|
46
|
+
@efficiency = (@efficiency + (EFFICIENCY_DECAY * 0.5)).clamp(0.0, 1.0)
|
|
47
|
+
@current_energy - before
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def catabolize!(complexity: 1.0)
|
|
51
|
+
energy_gained = (complexity * 10.0).round(10)
|
|
52
|
+
@current_energy = (@current_energy + energy_gained).clamp(0.0, @max_energy)
|
|
53
|
+
{ energy_gained: energy_gained, current_energy: @current_energy.round(10), state: state }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def anabolize!(energy_cost: 5.0)
|
|
57
|
+
raise ArgumentError, 'insufficient energy for anabolism' if @current_energy < energy_cost
|
|
58
|
+
|
|
59
|
+
@current_energy = (@current_energy - energy_cost).clamp(0.0, @max_energy)
|
|
60
|
+
structure_value = (energy_cost * @efficiency).round(10)
|
|
61
|
+
{ energy_spent: energy_cost, structure_value: structure_value, current_energy: @current_energy.round(10), state: state }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def to_h
|
|
65
|
+
{
|
|
66
|
+
id: @id,
|
|
67
|
+
current_energy: @current_energy.round(10),
|
|
68
|
+
max_energy: @max_energy,
|
|
69
|
+
metabolic_rate: @metabolic_rate,
|
|
70
|
+
efficiency: @efficiency.round(10),
|
|
71
|
+
energy_ratio: energy_ratio.round(10),
|
|
72
|
+
state: state,
|
|
73
|
+
depleted: depleted?,
|
|
74
|
+
created_at: @created_at
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module CognitiveMetabolism
|
|
8
|
+
module Helpers
|
|
9
|
+
class MetabolicCycle
|
|
10
|
+
attr_reader :id, :cycle_count, :operations_log, :energy_spent_this_cycle, :started_at, :completed_at
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@id = SecureRandom.uuid
|
|
14
|
+
@cycle_count = 0
|
|
15
|
+
@operations_log = []
|
|
16
|
+
@energy_spent_this_cycle = 0.0
|
|
17
|
+
@started_at = Time.now.utc
|
|
18
|
+
@completed_at = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def record_operation(operation_type:, energy_spent:)
|
|
22
|
+
@operations_log << {
|
|
23
|
+
operation_type: operation_type,
|
|
24
|
+
energy_spent: energy_spent.round(10),
|
|
25
|
+
recorded_at: Time.now.utc
|
|
26
|
+
}
|
|
27
|
+
@energy_spent_this_cycle += energy_spent
|
|
28
|
+
@cycle_count += 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def complete!
|
|
32
|
+
@completed_at = Time.now.utc
|
|
33
|
+
to_h
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def duration_seconds
|
|
37
|
+
return nil unless @completed_at
|
|
38
|
+
|
|
39
|
+
(@completed_at - @started_at).round(4)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def average_energy_per_operation
|
|
43
|
+
return 0.0 if @cycle_count.zero?
|
|
44
|
+
|
|
45
|
+
(@energy_spent_this_cycle / @cycle_count).round(10)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_h
|
|
49
|
+
{
|
|
50
|
+
id: @id,
|
|
51
|
+
cycle_count: @cycle_count,
|
|
52
|
+
energy_spent_this_cycle: @energy_spent_this_cycle.round(10),
|
|
53
|
+
average_per_operation: average_energy_per_operation,
|
|
54
|
+
operations_log: @operations_log,
|
|
55
|
+
started_at: @started_at,
|
|
56
|
+
completed_at: @completed_at,
|
|
57
|
+
duration_seconds: duration_seconds
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveMetabolism
|
|
6
|
+
module Helpers
|
|
7
|
+
class MetabolismEngine
|
|
8
|
+
include Constants
|
|
9
|
+
|
|
10
|
+
MAX_EFFICIENCY_HISTORY = 200
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@reserves = {}
|
|
14
|
+
@efficiency_history = []
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def create_reserve(max_energy: MAX_ENERGY, metabolic_rate: RESTING_METABOLIC_RATE, efficiency: 1.0)
|
|
18
|
+
reserve = EnergyReserve.new(max_energy: max_energy, metabolic_rate: metabolic_rate, efficiency: efficiency)
|
|
19
|
+
@reserves[reserve.id] = reserve
|
|
20
|
+
reserve
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def spend_energy(reserve_id:, operation_type:)
|
|
24
|
+
reserve = fetch_reserve(reserve_id)
|
|
25
|
+
cost = OPERATION_COSTS.fetch(operation_type) do
|
|
26
|
+
raise ArgumentError, "Unknown operation type: #{operation_type.inspect}"
|
|
27
|
+
end
|
|
28
|
+
actual_spent = reserve.spend!(cost)
|
|
29
|
+
record_efficiency(reserve)
|
|
30
|
+
{
|
|
31
|
+
reserve_id: reserve_id,
|
|
32
|
+
operation_type: operation_type,
|
|
33
|
+
base_cost: cost,
|
|
34
|
+
actual_spent: actual_spent.round(10),
|
|
35
|
+
current_energy: reserve.current_energy.round(10),
|
|
36
|
+
state: reserve.state
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def recover(reserve_id:, duration: 1.0)
|
|
41
|
+
reserve = fetch_reserve(reserve_id)
|
|
42
|
+
amount = (RECOVERY_RATE * duration.clamp(0.0, Float::INFINITY)).round(10)
|
|
43
|
+
gained = reserve.recover!(amount)
|
|
44
|
+
record_efficiency(reserve)
|
|
45
|
+
{
|
|
46
|
+
reserve_id: reserve_id,
|
|
47
|
+
duration: duration,
|
|
48
|
+
energy_gained: gained.round(10),
|
|
49
|
+
current_energy: reserve.current_energy.round(10),
|
|
50
|
+
state: reserve.state
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def catabolize(reserve_id:, complexity: 1.0)
|
|
55
|
+
reserve = fetch_reserve(reserve_id)
|
|
56
|
+
result = reserve.catabolize!(complexity: complexity)
|
|
57
|
+
result.merge(reserve_id: reserve_id)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def anabolize(reserve_id:, energy_cost: 5.0)
|
|
61
|
+
reserve = fetch_reserve(reserve_id)
|
|
62
|
+
result = reserve.anabolize!(energy_cost: energy_cost)
|
|
63
|
+
result.merge(reserve_id: reserve_id)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def run_cycle(reserve_id:, operations: [])
|
|
67
|
+
reserve = fetch_reserve(reserve_id)
|
|
68
|
+
cycle = MetabolicCycle.new
|
|
69
|
+
|
|
70
|
+
operations.each do |op_type|
|
|
71
|
+
cost_base = OPERATION_COSTS.fetch(op_type, 0.0)
|
|
72
|
+
reserve.spend!(cost_base) if cost_base > 0.0
|
|
73
|
+
cycle.record_operation(operation_type: op_type, energy_spent: cost_base)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
reserve.spend!(reserve.metabolic_rate)
|
|
77
|
+
cycle.record_operation(operation_type: :resting_rate, energy_spent: reserve.metabolic_rate)
|
|
78
|
+
|
|
79
|
+
cycle.complete!.merge(reserve_state: reserve.state, reserve_energy: reserve.current_energy.round(10))
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def metabolic_report(reserve_id:)
|
|
83
|
+
reserve = fetch_reserve(reserve_id)
|
|
84
|
+
{
|
|
85
|
+
reserve: reserve.to_h,
|
|
86
|
+
efficiency_history: efficiency_history_for(reserve_id)
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def efficiency_history
|
|
91
|
+
@efficiency_history.dup
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def all_reserves
|
|
95
|
+
@reserves.transform_values(&:to_h)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def fetch_reserve(id)
|
|
101
|
+
@reserves.fetch(id) { raise ArgumentError, "Unknown reserve: #{id.inspect}" }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def record_efficiency(reserve)
|
|
105
|
+
@efficiency_history << {
|
|
106
|
+
reserve_id: reserve.id,
|
|
107
|
+
efficiency: reserve.efficiency.round(10),
|
|
108
|
+
state: reserve.state,
|
|
109
|
+
recorded_at: Time.now.utc
|
|
110
|
+
}
|
|
111
|
+
@efficiency_history.shift while @efficiency_history.size > MAX_EFFICIENCY_HISTORY
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def efficiency_history_for(reserve_id)
|
|
115
|
+
@efficiency_history.select { |e| e[:reserve_id] == reserve_id }
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveMetabolism
|
|
6
|
+
module Runners
|
|
7
|
+
module CognitiveMetabolism
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
|
|
11
|
+
def create_reserve(max_energy: Helpers::Constants::MAX_ENERGY,
|
|
12
|
+
metabolic_rate: Helpers::Constants::RESTING_METABOLIC_RATE,
|
|
13
|
+
efficiency: 1.0, **)
|
|
14
|
+
reserve = engine.create_reserve(max_energy: max_energy, metabolic_rate: metabolic_rate, efficiency: efficiency)
|
|
15
|
+
Legion::Logging.debug "[cognitive_metabolism] reserve created: id=#{reserve.id} max_energy=#{reserve.max_energy}"
|
|
16
|
+
{ success: true, reserve: reserve.to_h }
|
|
17
|
+
rescue ArgumentError => e
|
|
18
|
+
{ success: false, error: e.message }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def spend_energy(reserve_id:, operation_type:, **)
|
|
22
|
+
result = engine.spend_energy(reserve_id: reserve_id, operation_type: operation_type)
|
|
23
|
+
Legion::Logging.debug "[cognitive_metabolism] spend: reserve=#{reserve_id} op=#{operation_type} " \
|
|
24
|
+
"spent=#{result[:actual_spent]} state=#{result[:state]}"
|
|
25
|
+
{ success: true }.merge(result)
|
|
26
|
+
rescue ArgumentError => e
|
|
27
|
+
{ success: false, error: e.message }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def recover(reserve_id:, duration: 1.0, **)
|
|
31
|
+
result = engine.recover(reserve_id: reserve_id, duration: duration)
|
|
32
|
+
Legion::Logging.debug "[cognitive_metabolism] recover: reserve=#{reserve_id} " \
|
|
33
|
+
"gained=#{result[:energy_gained]} state=#{result[:state]}"
|
|
34
|
+
{ success: true }.merge(result)
|
|
35
|
+
rescue ArgumentError => e
|
|
36
|
+
{ success: false, error: e.message }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def catabolize(reserve_id:, complexity: 1.0, **)
|
|
40
|
+
result = engine.catabolize(reserve_id: reserve_id, complexity: complexity)
|
|
41
|
+
Legion::Logging.debug "[cognitive_metabolism] catabolize: reserve=#{reserve_id} " \
|
|
42
|
+
"complexity=#{complexity} gained=#{result[:energy_gained]}"
|
|
43
|
+
{ success: true }.merge(result)
|
|
44
|
+
rescue ArgumentError => e
|
|
45
|
+
{ success: false, error: e.message }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def anabolize(reserve_id:, energy_cost: 5.0, **)
|
|
49
|
+
result = engine.anabolize(reserve_id: reserve_id, energy_cost: energy_cost)
|
|
50
|
+
Legion::Logging.debug "[cognitive_metabolism] anabolize: reserve=#{reserve_id} " \
|
|
51
|
+
"cost=#{energy_cost} value=#{result[:structure_value]}"
|
|
52
|
+
{ success: true }.merge(result)
|
|
53
|
+
rescue ArgumentError => e
|
|
54
|
+
{ success: false, error: e.message }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def metabolic_status(reserve_id:, **)
|
|
58
|
+
result = engine.metabolic_report(reserve_id: reserve_id)
|
|
59
|
+
Legion::Logging.debug "[cognitive_metabolism] status: reserve=#{reserve_id} state=#{result[:reserve][:state]}"
|
|
60
|
+
{ success: true }.merge(result)
|
|
61
|
+
rescue ArgumentError => e
|
|
62
|
+
{ success: false, error: e.message }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def run_cycle(reserve_id:, operations: [], **)
|
|
66
|
+
result = engine.run_cycle(reserve_id: reserve_id, operations: operations)
|
|
67
|
+
Legion::Logging.debug "[cognitive_metabolism] cycle: reserve=#{reserve_id} " \
|
|
68
|
+
"ops=#{result[:cycle_count]} spent=#{result[:energy_spent_this_cycle]} state=#{result[:reserve_state]}"
|
|
69
|
+
{ success: true }.merge(result)
|
|
70
|
+
rescue ArgumentError => e
|
|
71
|
+
{ success: false, error: e.message }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def engine
|
|
77
|
+
@engine ||= Helpers::MetabolismEngine.new
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
require 'legion/extensions/cognitive_metabolism/version'
|
|
5
|
+
require 'legion/extensions/cognitive_metabolism/helpers/constants'
|
|
6
|
+
require 'legion/extensions/cognitive_metabolism/helpers/energy_reserve'
|
|
7
|
+
require 'legion/extensions/cognitive_metabolism/helpers/metabolic_cycle'
|
|
8
|
+
require 'legion/extensions/cognitive_metabolism/helpers/metabolism_engine'
|
|
9
|
+
require 'legion/extensions/cognitive_metabolism/runners/cognitive_metabolism'
|
|
10
|
+
require 'legion/extensions/cognitive_metabolism/client'
|
|
11
|
+
|
|
12
|
+
module Legion
|
|
13
|
+
module Extensions
|
|
14
|
+
module CognitiveMetabolism
|
|
15
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-cognitive-metabolism
|
|
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: ATP-like cognitive energy system with metabolic cycles, catabolism, and
|
|
27
|
+
anabolism for brain-modeled agentic AI
|
|
28
|
+
email:
|
|
29
|
+
- matthewdiverson@gmail.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- ".github/workflows/ci.yml"
|
|
35
|
+
- ".gitignore"
|
|
36
|
+
- ".rspec"
|
|
37
|
+
- ".rubocop.yml"
|
|
38
|
+
- CLAUDE.md
|
|
39
|
+
- Gemfile
|
|
40
|
+
- LICENSE
|
|
41
|
+
- README.md
|
|
42
|
+
- lex-cognitive-metabolism.gemspec
|
|
43
|
+
- lib/legion/extensions/cognitive_metabolism.rb
|
|
44
|
+
- lib/legion/extensions/cognitive_metabolism/client.rb
|
|
45
|
+
- lib/legion/extensions/cognitive_metabolism/helpers/constants.rb
|
|
46
|
+
- lib/legion/extensions/cognitive_metabolism/helpers/energy_reserve.rb
|
|
47
|
+
- lib/legion/extensions/cognitive_metabolism/helpers/metabolic_cycle.rb
|
|
48
|
+
- lib/legion/extensions/cognitive_metabolism/helpers/metabolism_engine.rb
|
|
49
|
+
- lib/legion/extensions/cognitive_metabolism/runners/cognitive_metabolism.rb
|
|
50
|
+
- lib/legion/extensions/cognitive_metabolism/version.rb
|
|
51
|
+
homepage: https://github.com/LegionIO/lex-cognitive-metabolism
|
|
52
|
+
licenses:
|
|
53
|
+
- MIT
|
|
54
|
+
metadata:
|
|
55
|
+
homepage_uri: https://github.com/LegionIO/lex-cognitive-metabolism
|
|
56
|
+
source_code_uri: https://github.com/LegionIO/lex-cognitive-metabolism
|
|
57
|
+
documentation_uri: https://github.com/LegionIO/lex-cognitive-metabolism
|
|
58
|
+
changelog_uri: https://github.com/LegionIO/lex-cognitive-metabolism
|
|
59
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-cognitive-metabolism/issues
|
|
60
|
+
rubygems_mfa_required: 'true'
|
|
61
|
+
rdoc_options: []
|
|
62
|
+
require_paths:
|
|
63
|
+
- lib
|
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.4'
|
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '0'
|
|
74
|
+
requirements: []
|
|
75
|
+
rubygems_version: 3.6.9
|
|
76
|
+
specification_version: 4
|
|
77
|
+
summary: LEX Cognitive Metabolism
|
|
78
|
+
test_files: []
|