lex-cognitive-control 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/lib/legion/extensions/cognitive_control/client.rb +15 -0
- data/lib/legion/extensions/cognitive_control/helpers/constants.rb +41 -0
- data/lib/legion/extensions/cognitive_control/helpers/control_signal.rb +75 -0
- data/lib/legion/extensions/cognitive_control/helpers/controller.rb +136 -0
- data/lib/legion/extensions/cognitive_control/helpers/goal.rb +68 -0
- data/lib/legion/extensions/cognitive_control/runners/cognitive_control.rb +70 -0
- data/lib/legion/extensions/cognitive_control/version.rb +9 -0
- metadata +68 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c1de8aff56a2e7595c43898c5be6dad98608ee3d6ddbcb23e100700c54d0bc83
|
|
4
|
+
data.tar.gz: ff3b7fb5e6eabf9ba94f8c0dc9c2ce0165bbffc045776651189ff6ca97ea60d6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 588b9b7b395a0a32a0daa14b02b5f92bb6f37fde9baa1330e26e01a25e5476bbf68b418e054356d18c411929c61f56e068d83303877b0c662f0ce1be2dd73e8a
|
|
7
|
+
data.tar.gz: b2bf9c9f8efc0f0572c958e072cc24301e0180030e8d0a4a2cabcc59ae502f6a97b5896d94f541c86fb68f165b4b99f3b751327a1ad542a68b4d788ed53c25ff
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveControl
|
|
6
|
+
class Client
|
|
7
|
+
include Runners::CognitiveControl
|
|
8
|
+
|
|
9
|
+
def initialize(controller: nil)
|
|
10
|
+
@controller = controller || Helpers::Controller.new
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveControl
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
MAX_GOALS = 20
|
|
9
|
+
MAX_POLICIES = 50
|
|
10
|
+
MAX_HISTORY = 200
|
|
11
|
+
|
|
12
|
+
DEFAULT_EFFORT = 0.5
|
|
13
|
+
EFFORT_FLOOR = 0.1
|
|
14
|
+
EFFORT_CEILING = 1.0
|
|
15
|
+
EFFORT_DECAY = 0.02
|
|
16
|
+
EFFORT_RECOVERY = 0.03
|
|
17
|
+
|
|
18
|
+
AUTOMATIC_THRESHOLD = 0.3
|
|
19
|
+
CONTROLLED_THRESHOLD = 0.6
|
|
20
|
+
OVERRIDE_THRESHOLD = 0.8
|
|
21
|
+
|
|
22
|
+
CONFLICT_BOOST = 0.2
|
|
23
|
+
ERROR_BOOST = 0.15
|
|
24
|
+
NOVELTY_BOOST = 0.1
|
|
25
|
+
ADAPTATION_ALPHA = 0.1
|
|
26
|
+
|
|
27
|
+
CONTROL_MODES = %i[automatic controlled override].freeze
|
|
28
|
+
GOAL_STATES = %i[active suspended completed abandoned].freeze
|
|
29
|
+
|
|
30
|
+
EFFORT_LABELS = {
|
|
31
|
+
(0.8..) => :maximal,
|
|
32
|
+
(0.6...0.8) => :effortful,
|
|
33
|
+
(0.4...0.6) => :moderate,
|
|
34
|
+
(0.2...0.4) => :low,
|
|
35
|
+
(..0.2) => :automatic
|
|
36
|
+
}.freeze
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveControl
|
|
6
|
+
module Helpers
|
|
7
|
+
class ControlSignal
|
|
8
|
+
include Constants
|
|
9
|
+
|
|
10
|
+
attr_reader :effort_level, :conflict_detected, :error_detected,
|
|
11
|
+
:novelty_detected
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
@effort_level = DEFAULT_EFFORT
|
|
15
|
+
@conflict_detected = false
|
|
16
|
+
@error_detected = false
|
|
17
|
+
@novelty_detected = false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def detect_conflict
|
|
21
|
+
@conflict_detected = true
|
|
22
|
+
@effort_level = [@effort_level + CONFLICT_BOOST, EFFORT_CEILING].min
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def detect_error
|
|
26
|
+
@error_detected = true
|
|
27
|
+
@effort_level = [@effort_level + ERROR_BOOST, EFFORT_CEILING].min
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def detect_novelty
|
|
31
|
+
@novelty_detected = true
|
|
32
|
+
@effort_level = [@effort_level + NOVELTY_BOOST, EFFORT_CEILING].min
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def reset_detections
|
|
36
|
+
@conflict_detected = false
|
|
37
|
+
@error_detected = false
|
|
38
|
+
@novelty_detected = false
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def mode
|
|
42
|
+
return :override if @effort_level >= OVERRIDE_THRESHOLD
|
|
43
|
+
return :controlled if @effort_level >= CONTROLLED_THRESHOLD
|
|
44
|
+
|
|
45
|
+
:automatic
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def effort_label
|
|
49
|
+
EFFORT_LABELS.each { |range, lbl| return lbl if range.cover?(@effort_level) }
|
|
50
|
+
:automatic
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def decay
|
|
54
|
+
@effort_level = [@effort_level - EFFORT_DECAY, EFFORT_FLOOR].max
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def recover(amount: EFFORT_RECOVERY)
|
|
58
|
+
@effort_level = [@effort_level + amount, EFFORT_CEILING].min
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def to_h
|
|
62
|
+
{
|
|
63
|
+
effort_level: @effort_level.round(4),
|
|
64
|
+
mode: mode,
|
|
65
|
+
effort_label: effort_label,
|
|
66
|
+
conflict_detected: @conflict_detected,
|
|
67
|
+
error_detected: @error_detected,
|
|
68
|
+
novelty_detected: @novelty_detected
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveControl
|
|
6
|
+
module Helpers
|
|
7
|
+
class Controller
|
|
8
|
+
include Constants
|
|
9
|
+
|
|
10
|
+
attr_reader :goals, :signal, :history
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@goals = {}
|
|
14
|
+
@counter = 0
|
|
15
|
+
@signal = ControlSignal.new
|
|
16
|
+
@history = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def set_goal(description:, domain: :general, priority: 0.5)
|
|
20
|
+
return nil if @goals.size >= MAX_GOALS
|
|
21
|
+
|
|
22
|
+
@counter += 1
|
|
23
|
+
goal_id = :"goal_#{@counter}"
|
|
24
|
+
goal = Goal.new(id: goal_id, description: description, domain: domain, priority: priority)
|
|
25
|
+
@goals[goal_id] = goal
|
|
26
|
+
goal
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def advance_goal(goal_id:, amount: 0.1)
|
|
30
|
+
goal = @goals[goal_id]
|
|
31
|
+
return nil unless goal
|
|
32
|
+
|
|
33
|
+
goal.advance(amount: amount)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def suspend_goal(goal_id:)
|
|
37
|
+
goal = @goals[goal_id]
|
|
38
|
+
return nil unless goal
|
|
39
|
+
|
|
40
|
+
goal.suspend!
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def resume_goal(goal_id:)
|
|
44
|
+
goal = @goals[goal_id]
|
|
45
|
+
return nil unless goal
|
|
46
|
+
|
|
47
|
+
goal.resume!
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def abandon_goal(goal_id:)
|
|
51
|
+
goal = @goals[goal_id]
|
|
52
|
+
return nil unless goal
|
|
53
|
+
|
|
54
|
+
goal.abandon!
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def evaluate_control_demand(conflict: false, error: false, novelty: false)
|
|
58
|
+
@signal.reset_detections
|
|
59
|
+
@signal.detect_conflict if conflict
|
|
60
|
+
@signal.detect_error if error
|
|
61
|
+
@signal.detect_novelty if novelty
|
|
62
|
+
record_evaluation
|
|
63
|
+
@signal.to_h
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def current_mode
|
|
67
|
+
@signal.mode
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def should_override?
|
|
71
|
+
@signal.mode == :override
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def should_control?
|
|
75
|
+
%i[controlled override].include?(@signal.mode)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def active_goals
|
|
79
|
+
@goals.values.select(&:active?).sort_by { |g| -g.priority }.map(&:to_h)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def top_goal
|
|
83
|
+
active = @goals.values.select(&:active?)
|
|
84
|
+
return nil if active.empty?
|
|
85
|
+
|
|
86
|
+
active.max_by(&:priority).to_h
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def goal_conflict?
|
|
90
|
+
active = @goals.values.select(&:active?)
|
|
91
|
+
return false if active.size < 2
|
|
92
|
+
|
|
93
|
+
priorities = active.map(&:priority)
|
|
94
|
+
(priorities.max - priorities.min) < 0.2 && active.size > 1
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def tick
|
|
98
|
+
@signal.decay
|
|
99
|
+
check_goal_conflicts
|
|
100
|
+
@signal.to_h
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def to_h
|
|
104
|
+
{
|
|
105
|
+
goal_count: @goals.size,
|
|
106
|
+
active_goals: @goals.values.count(&:active?),
|
|
107
|
+
effort_level: @signal.effort_level.round(4),
|
|
108
|
+
mode: current_mode,
|
|
109
|
+
effort_label: @signal.effort_label,
|
|
110
|
+
goal_conflict: goal_conflict?,
|
|
111
|
+
history_size: @history.size
|
|
112
|
+
}
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def check_goal_conflicts
|
|
118
|
+
@signal.detect_conflict if goal_conflict?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def record_evaluation
|
|
122
|
+
@history << {
|
|
123
|
+
mode: @signal.mode,
|
|
124
|
+
effort: @signal.effort_level.round(4),
|
|
125
|
+
conflict: @signal.conflict_detected,
|
|
126
|
+
error: @signal.error_detected,
|
|
127
|
+
novelty: @signal.novelty_detected,
|
|
128
|
+
at: Time.now.utc
|
|
129
|
+
}
|
|
130
|
+
@history.shift while @history.size > MAX_HISTORY
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveControl
|
|
6
|
+
module Helpers
|
|
7
|
+
class Goal
|
|
8
|
+
include Constants
|
|
9
|
+
|
|
10
|
+
attr_reader :id, :description, :domain, :priority, :state, :progress, :created_at
|
|
11
|
+
|
|
12
|
+
def initialize(id:, description:, domain: :general, priority: 0.5)
|
|
13
|
+
@id = id
|
|
14
|
+
@description = description
|
|
15
|
+
@domain = domain
|
|
16
|
+
@priority = priority.to_f.clamp(0.0, 1.0)
|
|
17
|
+
@state = :active
|
|
18
|
+
@progress = 0.0
|
|
19
|
+
@created_at = Time.now.utc
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def advance(amount: 0.1)
|
|
23
|
+
return nil unless @state == :active
|
|
24
|
+
|
|
25
|
+
@progress = [@progress + amount, 1.0].min
|
|
26
|
+
complete! if @progress >= 1.0
|
|
27
|
+
@progress
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def complete!
|
|
31
|
+
@state = :completed
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def suspend!
|
|
35
|
+
@state = :suspended if @state == :active
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def resume!
|
|
39
|
+
@state = :active if @state == :suspended
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def abandon!
|
|
43
|
+
@state = :abandoned unless @state == :completed
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def active?
|
|
47
|
+
@state == :active
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def completed?
|
|
51
|
+
@state == :completed
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def to_h
|
|
55
|
+
{
|
|
56
|
+
id: @id,
|
|
57
|
+
description: @description,
|
|
58
|
+
domain: @domain,
|
|
59
|
+
priority: @priority.round(4),
|
|
60
|
+
state: @state,
|
|
61
|
+
progress: @progress.round(4)
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveControl
|
|
6
|
+
module Runners
|
|
7
|
+
module CognitiveControl
|
|
8
|
+
include Helpers::Constants
|
|
9
|
+
include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
10
|
+
|
|
11
|
+
def set_control_goal(description:, domain: :general, priority: 0.5, **)
|
|
12
|
+
goal = controller.set_goal(description: description, domain: domain, priority: priority)
|
|
13
|
+
return { success: false, reason: :limit_reached } unless goal
|
|
14
|
+
|
|
15
|
+
{ success: true, goal_id: goal.id, priority: goal.priority }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def advance_control_goal(goal_id:, amount: 0.1, **)
|
|
19
|
+
result = controller.advance_goal(goal_id: goal_id, amount: amount)
|
|
20
|
+
return { success: false, reason: :not_found } unless result
|
|
21
|
+
|
|
22
|
+
{ success: true, goal_id: goal_id, progress: result.round(4) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def suspend_control_goal(goal_id:, **)
|
|
26
|
+
controller.suspend_goal(goal_id: goal_id)
|
|
27
|
+
{ success: true, goal_id: goal_id }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def evaluate_control(conflict: false, error: false, novelty: false, **)
|
|
31
|
+
result = controller.evaluate_control_demand(conflict: conflict, error: error, novelty: novelty)
|
|
32
|
+
{ success: true }.merge(result)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def current_control_mode(**)
|
|
36
|
+
{ success: true, mode: controller.current_mode, should_override: controller.should_override?,
|
|
37
|
+
should_control: controller.should_control? }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def active_control_goals(**)
|
|
41
|
+
goals = controller.active_goals
|
|
42
|
+
{ success: true, goals: goals, count: goals.size }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def top_control_goal(**)
|
|
46
|
+
goal = controller.top_goal
|
|
47
|
+
return { success: false, reason: :no_active_goals } unless goal
|
|
48
|
+
|
|
49
|
+
{ success: true }.merge(goal)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def update_cognitive_control(**)
|
|
53
|
+
result = controller.tick
|
|
54
|
+
{ success: true }.merge(result)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def cognitive_control_stats(**)
|
|
58
|
+
{ success: true }.merge(controller.to_h)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def controller
|
|
64
|
+
@controller ||= Helpers::Controller.new
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-cognitive-control
|
|
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: Cognitive control for LegionIO — automatic vs. controlled processing,
|
|
27
|
+
goal management, and effort allocation
|
|
28
|
+
email:
|
|
29
|
+
- matthewdiverson@gmail.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- lib/legion/extensions/cognitive_control/client.rb
|
|
35
|
+
- lib/legion/extensions/cognitive_control/helpers/constants.rb
|
|
36
|
+
- lib/legion/extensions/cognitive_control/helpers/control_signal.rb
|
|
37
|
+
- lib/legion/extensions/cognitive_control/helpers/controller.rb
|
|
38
|
+
- lib/legion/extensions/cognitive_control/helpers/goal.rb
|
|
39
|
+
- lib/legion/extensions/cognitive_control/runners/cognitive_control.rb
|
|
40
|
+
- lib/legion/extensions/cognitive_control/version.rb
|
|
41
|
+
homepage: https://github.com/LegionIO/lex-cognitive-control
|
|
42
|
+
licenses:
|
|
43
|
+
- MIT
|
|
44
|
+
metadata:
|
|
45
|
+
homepage_uri: https://github.com/LegionIO/lex-cognitive-control
|
|
46
|
+
source_code_uri: https://github.com/LegionIO/lex-cognitive-control
|
|
47
|
+
documentation_uri: https://github.com/LegionIO/lex-cognitive-control/blob/master/README.md
|
|
48
|
+
changelog_uri: https://github.com/LegionIO/lex-cognitive-control/blob/master/CHANGELOG.md
|
|
49
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-cognitive-control/issues
|
|
50
|
+
rubygems_mfa_required: 'true'
|
|
51
|
+
rdoc_options: []
|
|
52
|
+
require_paths:
|
|
53
|
+
- lib
|
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '3.4'
|
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '0'
|
|
64
|
+
requirements: []
|
|
65
|
+
rubygems_version: 3.6.9
|
|
66
|
+
specification_version: 4
|
|
67
|
+
summary: Cognitive control meta-controller for LegionIO
|
|
68
|
+
test_files: []
|