lex-cognitive-offloading 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/Gemfile +11 -0
- data/lex-cognitive-offloading.gemspec +29 -0
- data/lib/legion/extensions/cognitive_offloading/client.rb +25 -0
- data/lib/legion/extensions/cognitive_offloading/helpers/constants.rb +51 -0
- data/lib/legion/extensions/cognitive_offloading/helpers/external_store.rb +78 -0
- data/lib/legion/extensions/cognitive_offloading/helpers/offloaded_item.rb +61 -0
- data/lib/legion/extensions/cognitive_offloading/helpers/offloading_engine.rb +134 -0
- data/lib/legion/extensions/cognitive_offloading/runners/cognitive_offloading.rb +98 -0
- data/lib/legion/extensions/cognitive_offloading/version.rb +9 -0
- data/lib/legion/extensions/cognitive_offloading.rb +16 -0
- data/spec/legion/extensions/cognitive_offloading/client_spec.rb +30 -0
- data/spec/legion/extensions/cognitive_offloading/helpers/constants_spec.rb +71 -0
- data/spec/legion/extensions/cognitive_offloading/helpers/external_store_spec.rb +158 -0
- data/spec/legion/extensions/cognitive_offloading/helpers/offloaded_item_spec.rb +123 -0
- data/spec/legion/extensions/cognitive_offloading/helpers/offloading_engine_spec.rb +250 -0
- data/spec/legion/extensions/cognitive_offloading/runners/cognitive_offloading_spec.rb +194 -0
- data/spec/spec_helper.rb +20 -0
- metadata +78 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f8942fc76e24c051b63e26f5ed53f408a22bf9c97cb442dd4c5808ccbf24d1ed
|
|
4
|
+
data.tar.gz: 0e3b27ef6d00e2cf9d41f13ad354c7b8c3973b78dd30f8c414b9171fe31c9a5a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 162c624136fbedff1e2f7f319c1b83399fca03a891bc6c4ecd7f28c16feeba70197e86836c1301fd6a996535e72d9c0e98bbfc8c8a3295277a5428371a3db430
|
|
7
|
+
data.tar.gz: 8a9a349b69e99aa01d9ce4b6f2d17595a76d8d88f15a8c93c8f272d49b81e127b88e5a6f94f0454224c93615c41563760812de716af4ce209cc5891a829bc543
|
data/Gemfile
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/cognitive_offloading/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-cognitive-offloading'
|
|
7
|
+
spec.version = Legion::Extensions::CognitiveOffloading::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'LEX Cognitive Offloading'
|
|
12
|
+
spec.description = 'Strategic externalization of cognitive tasks — offloading decisions, store trust, and retrieval tracking for brain-modeled agentic AI'
|
|
13
|
+
spec.homepage = 'https://github.com/LegionIO/lex-cognitive-offloading'
|
|
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-offloading'
|
|
19
|
+
spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-cognitive-offloading'
|
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-cognitive-offloading'
|
|
21
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-cognitive-offloading/issues'
|
|
22
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
23
|
+
|
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
25
|
+
Dir.glob('{lib,spec}/**/*') + %w[lex-cognitive-offloading.gemspec Gemfile]
|
|
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_offloading/helpers/constants'
|
|
4
|
+
require 'legion/extensions/cognitive_offloading/helpers/external_store'
|
|
5
|
+
require 'legion/extensions/cognitive_offloading/helpers/offloaded_item'
|
|
6
|
+
require 'legion/extensions/cognitive_offloading/helpers/offloading_engine'
|
|
7
|
+
require 'legion/extensions/cognitive_offloading/runners/cognitive_offloading'
|
|
8
|
+
|
|
9
|
+
module Legion
|
|
10
|
+
module Extensions
|
|
11
|
+
module CognitiveOffloading
|
|
12
|
+
class Client
|
|
13
|
+
include Runners::CognitiveOffloading
|
|
14
|
+
|
|
15
|
+
def initialize(engine: nil, **)
|
|
16
|
+
@offloading_engine = engine || Helpers::OffloadingEngine.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
attr_reader :offloading_engine
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveOffloading
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
MAX_ITEMS = 500
|
|
9
|
+
MAX_STORES = 50
|
|
10
|
+
DEFAULT_STORE_TRUST = 0.7
|
|
11
|
+
TRUST_DECAY = 0.02
|
|
12
|
+
TRUST_BOOST = 0.05
|
|
13
|
+
|
|
14
|
+
ITEM_TYPES = %i[
|
|
15
|
+
fact procedure plan context delegation reminder calculation reference
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
STORE_TYPES = %i[
|
|
19
|
+
database file agent tool memory_aid external_service notes
|
|
20
|
+
].freeze
|
|
21
|
+
|
|
22
|
+
TRUST_LABELS = {
|
|
23
|
+
(0.8..) => :highly_trusted,
|
|
24
|
+
(0.6...0.8) => :trusted,
|
|
25
|
+
(0.4...0.6) => :cautious,
|
|
26
|
+
(0.2...0.4) => :distrusted,
|
|
27
|
+
(..0.2) => :unreliable
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
IMPORTANCE_LABELS = {
|
|
31
|
+
(0.8..) => :critical,
|
|
32
|
+
(0.6...0.8) => :important,
|
|
33
|
+
(0.4...0.6) => :moderate,
|
|
34
|
+
(0.2...0.4) => :low,
|
|
35
|
+
(..0.2) => :trivial
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
OFFLOAD_LABELS = {
|
|
39
|
+
(0.8..) => :heavily_offloaded,
|
|
40
|
+
(0.6...0.8) => :mostly_offloaded,
|
|
41
|
+
(0.4...0.6) => :balanced,
|
|
42
|
+
(0.2...0.4) => :mostly_internal,
|
|
43
|
+
(..0.2) => :self_reliant
|
|
44
|
+
}.freeze
|
|
45
|
+
|
|
46
|
+
RETRIEVAL_SUCCESS_THRESHOLD = 0.7
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
require_relative 'constants'
|
|
5
|
+
|
|
6
|
+
module Legion
|
|
7
|
+
module Extensions
|
|
8
|
+
module CognitiveOffloading
|
|
9
|
+
module Helpers
|
|
10
|
+
class ExternalStore
|
|
11
|
+
include Constants
|
|
12
|
+
|
|
13
|
+
attr_reader :id, :name, :store_type, :trust, :items_stored,
|
|
14
|
+
:successful_retrievals, :failed_retrievals, :created_at
|
|
15
|
+
|
|
16
|
+
def initialize(name:, store_type:)
|
|
17
|
+
@id = ::SecureRandom.uuid
|
|
18
|
+
@name = name
|
|
19
|
+
@store_type = store_type
|
|
20
|
+
@trust = DEFAULT_STORE_TRUST
|
|
21
|
+
@items_stored = 0
|
|
22
|
+
@successful_retrievals = 0
|
|
23
|
+
@failed_retrievals = 0
|
|
24
|
+
@created_at = Time.now.utc
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def increment_items!
|
|
28
|
+
@items_stored += 1
|
|
29
|
+
self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def record_success!
|
|
33
|
+
@successful_retrievals += 1
|
|
34
|
+
@trust = (@trust + TRUST_BOOST).clamp(0.0, 1.0).round(10)
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def record_failure!
|
|
39
|
+
@failed_retrievals += 1
|
|
40
|
+
@trust = (@trust - TRUST_DECAY).clamp(0.0, 1.0).round(10)
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def retrieval_rate
|
|
45
|
+
total = @successful_retrievals + @failed_retrievals
|
|
46
|
+
return 0.0 if total.zero?
|
|
47
|
+
|
|
48
|
+
(@successful_retrievals.to_f / total).round(10)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def reliable?
|
|
52
|
+
@trust >= RETRIEVAL_SUCCESS_THRESHOLD
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def trust_label
|
|
56
|
+
TRUST_LABELS.find { |range, _| range.cover?(@trust) }&.last || :unreliable
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def to_h
|
|
60
|
+
{
|
|
61
|
+
id: @id,
|
|
62
|
+
name: @name,
|
|
63
|
+
store_type: @store_type,
|
|
64
|
+
trust: @trust.round(10),
|
|
65
|
+
trust_label: trust_label,
|
|
66
|
+
items_stored: @items_stored,
|
|
67
|
+
successful_retrievals: @successful_retrievals,
|
|
68
|
+
failed_retrievals: @failed_retrievals,
|
|
69
|
+
retrieval_rate: retrieval_rate,
|
|
70
|
+
reliable: reliable?,
|
|
71
|
+
created_at: @created_at
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
require_relative 'constants'
|
|
5
|
+
|
|
6
|
+
module Legion
|
|
7
|
+
module Extensions
|
|
8
|
+
module CognitiveOffloading
|
|
9
|
+
module Helpers
|
|
10
|
+
class OffloadedItem
|
|
11
|
+
include Constants
|
|
12
|
+
|
|
13
|
+
attr_reader :id, :content, :item_type, :importance, :store_id,
|
|
14
|
+
:offloaded_at, :retrieved_count, :last_retrieved_at
|
|
15
|
+
|
|
16
|
+
def initialize(content:, item_type:, importance:, store_id:)
|
|
17
|
+
@id = ::SecureRandom.uuid
|
|
18
|
+
@content = content
|
|
19
|
+
@item_type = item_type
|
|
20
|
+
@importance = importance.clamp(0.0, 1.0)
|
|
21
|
+
@store_id = store_id
|
|
22
|
+
@offloaded_at = Time.now.utc
|
|
23
|
+
@retrieved_count = 0
|
|
24
|
+
@last_retrieved_at = nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def retrieve!
|
|
28
|
+
@retrieved_count += 1
|
|
29
|
+
@last_retrieved_at = Time.now.utc
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def stale?(threshold_seconds: 3600)
|
|
34
|
+
return false if @last_retrieved_at.nil? && @retrieved_count.zero?
|
|
35
|
+
|
|
36
|
+
reference = @last_retrieved_at || @offloaded_at
|
|
37
|
+
(Time.now.utc - reference) > threshold_seconds
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def importance_label
|
|
41
|
+
IMPORTANCE_LABELS.find { |range, _| range.cover?(@importance) }&.last || :trivial
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_h
|
|
45
|
+
{
|
|
46
|
+
id: @id,
|
|
47
|
+
content: @content,
|
|
48
|
+
item_type: @item_type,
|
|
49
|
+
importance: @importance.round(10),
|
|
50
|
+
importance_label: importance_label,
|
|
51
|
+
store_id: @store_id,
|
|
52
|
+
offloaded_at: @offloaded_at,
|
|
53
|
+
retrieved_count: @retrieved_count,
|
|
54
|
+
last_retrieved_at: @last_retrieved_at
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'constants'
|
|
4
|
+
require_relative 'external_store'
|
|
5
|
+
require_relative 'offloaded_item'
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Extensions
|
|
9
|
+
module CognitiveOffloading
|
|
10
|
+
module Helpers
|
|
11
|
+
class OffloadingEngine
|
|
12
|
+
include Constants
|
|
13
|
+
|
|
14
|
+
attr_reader :items, :stores
|
|
15
|
+
|
|
16
|
+
def initialize
|
|
17
|
+
@items = {}
|
|
18
|
+
@stores = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def register_store(name:, store_type:)
|
|
22
|
+
return nil if @stores.size >= MAX_STORES
|
|
23
|
+
|
|
24
|
+
store = ExternalStore.new(name: name, store_type: store_type)
|
|
25
|
+
@stores[store.id] = store
|
|
26
|
+
store
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def offload(content:, item_type:, importance:, store_id:)
|
|
30
|
+
return nil if @items.size >= MAX_ITEMS
|
|
31
|
+
return nil unless @stores.key?(store_id)
|
|
32
|
+
|
|
33
|
+
item = OffloadedItem.new(
|
|
34
|
+
content: content,
|
|
35
|
+
item_type: item_type,
|
|
36
|
+
importance: importance,
|
|
37
|
+
store_id: store_id
|
|
38
|
+
)
|
|
39
|
+
@items[item.id] = item
|
|
40
|
+
@stores[store_id].increment_items!
|
|
41
|
+
item
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def retrieve(item_id:)
|
|
45
|
+
item = @items[item_id]
|
|
46
|
+
return nil unless item
|
|
47
|
+
|
|
48
|
+
store = @stores[item.store_id]
|
|
49
|
+
store&.record_success!
|
|
50
|
+
item.retrieve!
|
|
51
|
+
item
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def retrieve_failed(item_id:)
|
|
55
|
+
item = @items[item_id]
|
|
56
|
+
return nil unless item
|
|
57
|
+
|
|
58
|
+
store = @stores[item.store_id]
|
|
59
|
+
store&.record_failure!
|
|
60
|
+
item
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def items_in_store(store_id:)
|
|
64
|
+
@items.values.select { |i| i.store_id == store_id }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def items_by_type(item_type:)
|
|
68
|
+
@items.values.select { |i| i.item_type == item_type }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def most_important_offloaded(limit: 10)
|
|
72
|
+
@items.values
|
|
73
|
+
.sort_by { |i| -i.importance }
|
|
74
|
+
.first(limit)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def offloading_ratio
|
|
78
|
+
return 0.0 if MAX_ITEMS.zero?
|
|
79
|
+
|
|
80
|
+
(@items.size.to_f / MAX_ITEMS).round(10)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def overall_store_trust
|
|
84
|
+
return 0.0 if @stores.empty?
|
|
85
|
+
|
|
86
|
+
total = @stores.values.sum(&:trust)
|
|
87
|
+
(total / @stores.size).round(10)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def most_trusted_store
|
|
91
|
+
@stores.values.max_by(&:trust)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def least_trusted_store
|
|
95
|
+
@stores.values.min_by(&:trust)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def offloading_report
|
|
99
|
+
{
|
|
100
|
+
total_items: @items.size,
|
|
101
|
+
total_stores: @stores.size,
|
|
102
|
+
offloading_ratio: offloading_ratio,
|
|
103
|
+
offloading_label: offloading_label,
|
|
104
|
+
overall_store_trust: overall_store_trust,
|
|
105
|
+
most_trusted_store: most_trusted_store&.to_h,
|
|
106
|
+
least_trusted_store: least_trusted_store&.to_h,
|
|
107
|
+
items_by_type: items_type_summary,
|
|
108
|
+
stores_summary: @stores.values.map(&:to_h)
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def to_h
|
|
113
|
+
{
|
|
114
|
+
items: @items.transform_values(&:to_h),
|
|
115
|
+
stores: @stores.transform_values(&:to_h)
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
def offloading_label
|
|
122
|
+
OFFLOAD_LABELS.find { |range, _| range.cover?(offloading_ratio) }&.last || :self_reliant
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def items_type_summary
|
|
126
|
+
ITEM_TYPES.to_h do |type|
|
|
127
|
+
[type, @items.values.count { |i| i.item_type == type }]
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveOffloading
|
|
6
|
+
module Runners
|
|
7
|
+
module CognitiveOffloading
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
|
|
11
|
+
def register_store(name:, store_type:, engine: nil, **)
|
|
12
|
+
eng = engine || offloading_engine
|
|
13
|
+
store = eng.register_store(name: name, store_type: store_type)
|
|
14
|
+
if store
|
|
15
|
+
Legion::Logging.info "[cognitive_offloading] registered store name=#{name} type=#{store_type} id=#{store.id}"
|
|
16
|
+
{ success: true, store: store.to_h }
|
|
17
|
+
else
|
|
18
|
+
Legion::Logging.warn '[cognitive_offloading] register_store failed: limit reached or invalid store_type'
|
|
19
|
+
{ success: false, reason: :limit_reached }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def offload_item(content:, item_type:, importance:, store_id:, engine: nil, **)
|
|
24
|
+
eng = engine || offloading_engine
|
|
25
|
+
item = eng.offload(content: content, item_type: item_type, importance: importance, store_id: store_id)
|
|
26
|
+
if item
|
|
27
|
+
Legion::Logging.info "[cognitive_offloading] offloaded item=#{item.id} type=#{item_type} importance=#{importance.round(2)} store=#{store_id}"
|
|
28
|
+
{ success: true, item: item.to_h }
|
|
29
|
+
else
|
|
30
|
+
Legion::Logging.warn "[cognitive_offloading] offload failed: limit reached or store not found store_id=#{store_id}"
|
|
31
|
+
{ success: false, reason: :offload_failed }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def retrieve_item(item_id:, engine: nil, **)
|
|
36
|
+
eng = engine || offloading_engine
|
|
37
|
+
item = eng.retrieve(item_id: item_id)
|
|
38
|
+
if item
|
|
39
|
+
Legion::Logging.debug "[cognitive_offloading] retrieved item=#{item_id} count=#{item.retrieved_count}"
|
|
40
|
+
{ success: true, item: item.to_h }
|
|
41
|
+
else
|
|
42
|
+
Legion::Logging.warn "[cognitive_offloading] retrieve failed: item not found item_id=#{item_id}"
|
|
43
|
+
{ success: false, reason: :not_found }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def report_retrieval_failure(item_id:, engine: nil, **)
|
|
48
|
+
eng = engine || offloading_engine
|
|
49
|
+
item = eng.retrieve_failed(item_id: item_id)
|
|
50
|
+
if item
|
|
51
|
+
store = eng.stores[item.store_id]
|
|
52
|
+
trust = store&.trust&.round(2)
|
|
53
|
+
Legion::Logging.warn "[cognitive_offloading] retrieval failure item=#{item_id} store_trust=#{trust}"
|
|
54
|
+
{ success: true, item_id: item_id, store_trust: trust }
|
|
55
|
+
else
|
|
56
|
+
{ success: false, reason: :not_found }
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def items_in_store(store_id:, engine: nil, **)
|
|
61
|
+
eng = engine || offloading_engine
|
|
62
|
+
items = eng.items_in_store(store_id: store_id)
|
|
63
|
+
Legion::Logging.debug "[cognitive_offloading] items_in_store store=#{store_id} count=#{items.size}"
|
|
64
|
+
{ success: true, items: items.map(&:to_h), count: items.size }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def items_by_type(item_type:, engine: nil, **)
|
|
68
|
+
eng = engine || offloading_engine
|
|
69
|
+
items = eng.items_by_type(item_type: item_type)
|
|
70
|
+
Legion::Logging.debug "[cognitive_offloading] items_by_type type=#{item_type} count=#{items.size}"
|
|
71
|
+
{ success: true, items: items.map(&:to_h), count: items.size }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def most_important_offloaded(limit: 10, engine: nil, **)
|
|
75
|
+
eng = engine || offloading_engine
|
|
76
|
+
items = eng.most_important_offloaded(limit: limit)
|
|
77
|
+
Legion::Logging.debug "[cognitive_offloading] most_important limit=#{limit} count=#{items.size}"
|
|
78
|
+
{ success: true, items: items.map(&:to_h), count: items.size }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def offloading_status(engine: nil, **)
|
|
82
|
+
eng = engine || offloading_engine
|
|
83
|
+
report = eng.offloading_report
|
|
84
|
+
ratio = report[:offloading_ratio]
|
|
85
|
+
Legion::Logging.debug "[cognitive_offloading] status items=#{report[:total_items]} stores=#{report[:total_stores]} ratio=#{ratio}"
|
|
86
|
+
{ success: true, report: report }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def offloading_engine
|
|
92
|
+
@offloading_engine ||= Helpers::OffloadingEngine.new
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/cognitive_offloading/version'
|
|
4
|
+
require 'legion/extensions/cognitive_offloading/helpers/constants'
|
|
5
|
+
require 'legion/extensions/cognitive_offloading/helpers/external_store'
|
|
6
|
+
require 'legion/extensions/cognitive_offloading/helpers/offloaded_item'
|
|
7
|
+
require 'legion/extensions/cognitive_offloading/helpers/offloading_engine'
|
|
8
|
+
require 'legion/extensions/cognitive_offloading/runners/cognitive_offloading'
|
|
9
|
+
|
|
10
|
+
module Legion
|
|
11
|
+
module Extensions
|
|
12
|
+
module CognitiveOffloading
|
|
13
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/cognitive_offloading/client'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Legion::Extensions::CognitiveOffloading::Client do
|
|
6
|
+
let(:client) { described_class.new }
|
|
7
|
+
|
|
8
|
+
it 'responds to all runner methods' do
|
|
9
|
+
expect(client).to respond_to(:register_store)
|
|
10
|
+
expect(client).to respond_to(:offload_item)
|
|
11
|
+
expect(client).to respond_to(:retrieve_item)
|
|
12
|
+
expect(client).to respond_to(:report_retrieval_failure)
|
|
13
|
+
expect(client).to respond_to(:items_in_store)
|
|
14
|
+
expect(client).to respond_to(:items_by_type)
|
|
15
|
+
expect(client).to respond_to(:most_important_offloaded)
|
|
16
|
+
expect(client).to respond_to(:offloading_status)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'accepts an injected engine' do
|
|
20
|
+
engine = Legion::Extensions::CognitiveOffloading::Helpers::OffloadingEngine.new
|
|
21
|
+
c = described_class.new(engine: engine)
|
|
22
|
+
result = c.register_store(name: 'test', store_type: :file)
|
|
23
|
+
expect(result[:success]).to be true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'creates its own engine when none injected' do
|
|
27
|
+
result = client.register_store(name: 'auto', store_type: :notes)
|
|
28
|
+
expect(result[:success]).to be true
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveOffloading::Helpers::Constants do
|
|
4
|
+
subject(:constants) { described_class }
|
|
5
|
+
|
|
6
|
+
it 'defines MAX_ITEMS as 500' do
|
|
7
|
+
expect(constants::MAX_ITEMS).to eq(500)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'defines MAX_STORES as 50' do
|
|
11
|
+
expect(constants::MAX_STORES).to eq(50)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'defines DEFAULT_STORE_TRUST as 0.7' do
|
|
15
|
+
expect(constants::DEFAULT_STORE_TRUST).to eq(0.7)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'defines TRUST_DECAY as 0.02' do
|
|
19
|
+
expect(constants::TRUST_DECAY).to eq(0.02)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'defines TRUST_BOOST as 0.05' do
|
|
23
|
+
expect(constants::TRUST_BOOST).to eq(0.05)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'defines RETRIEVAL_SUCCESS_THRESHOLD as 0.7' do
|
|
27
|
+
expect(constants::RETRIEVAL_SUCCESS_THRESHOLD).to eq(0.7)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'defines ITEM_TYPES as frozen array of symbols' do
|
|
31
|
+
expect(constants::ITEM_TYPES).to include(:fact, :procedure, :plan, :context, :delegation,
|
|
32
|
+
:reminder, :calculation, :reference)
|
|
33
|
+
expect(constants::ITEM_TYPES).to be_frozen
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'defines STORE_TYPES as frozen array of symbols' do
|
|
37
|
+
expect(constants::STORE_TYPES).to include(:database, :file, :agent, :tool, :memory_aid,
|
|
38
|
+
:external_service, :notes)
|
|
39
|
+
expect(constants::STORE_TYPES).to be_frozen
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'maps high trust to :highly_trusted' do
|
|
43
|
+
label = constants::TRUST_LABELS.find { |range, _| range.cover?(0.9) }&.last
|
|
44
|
+
expect(label).to eq(:highly_trusted)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'maps moderate trust to :trusted' do
|
|
48
|
+
label = constants::TRUST_LABELS.find { |range, _| range.cover?(0.7) }&.last
|
|
49
|
+
expect(label).to eq(:trusted)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'maps low trust to :unreliable' do
|
|
53
|
+
label = constants::TRUST_LABELS.find { |range, _| range.cover?(0.1) }&.last
|
|
54
|
+
expect(label).to eq(:unreliable)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'maps high importance to :critical' do
|
|
58
|
+
label = constants::IMPORTANCE_LABELS.find { |range, _| range.cover?(0.9) }&.last
|
|
59
|
+
expect(label).to eq(:critical)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'maps high offloading ratio to :heavily_offloaded' do
|
|
63
|
+
label = constants::OFFLOAD_LABELS.find { |range, _| range.cover?(0.9) }&.last
|
|
64
|
+
expect(label).to eq(:heavily_offloaded)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'maps low offloading ratio to :self_reliant' do
|
|
68
|
+
label = constants::OFFLOAD_LABELS.find { |range, _| range.cover?(0.1) }&.last
|
|
69
|
+
expect(label).to eq(:self_reliant)
|
|
70
|
+
end
|
|
71
|
+
end
|