lex-apollo 0.4.21 → 0.4.23
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 +4 -4
- data/CHANGELOG.md +13 -0
- data/lib/legion/extensions/apollo/actors/corroboration_checker.rb +3 -1
- data/lib/legion/extensions/apollo/actors/decay.rb +3 -1
- data/lib/legion/extensions/apollo/actors/entity_watchdog.rb +10 -21
- data/lib/legion/extensions/apollo/actors/expertise_aggregator.rb +3 -1
- data/lib/legion/extensions/apollo/actors/gas_subscriber.rb +1 -1
- data/lib/legion/extensions/apollo/actors/ingest.rb +1 -1
- data/lib/legion/extensions/apollo/actors/query_responder.rb +1 -1
- data/lib/legion/extensions/apollo/actors/writeback_store.rb +1 -1
- data/lib/legion/extensions/apollo/actors/writeback_vectorize.rb +2 -2
- data/lib/legion/extensions/apollo/api.rb +56 -30
- data/lib/legion/extensions/apollo/gaia_integration.rb +13 -11
- data/lib/legion/extensions/apollo/helpers/capability.rb +12 -13
- data/lib/legion/extensions/apollo/helpers/confidence.rb +5 -8
- data/lib/legion/extensions/apollo/helpers/data_models.rb +61 -0
- data/lib/legion/extensions/apollo/helpers/entity_watchdog.rb +8 -15
- data/lib/legion/extensions/apollo/helpers/similarity.rb +5 -6
- data/lib/legion/extensions/apollo/helpers/writeback.rb +13 -14
- data/lib/legion/extensions/apollo/runners/expertise.rb +10 -8
- data/lib/legion/extensions/apollo/runners/gas.rb +18 -14
- data/lib/legion/extensions/apollo/runners/knowledge.rb +77 -62
- data/lib/legion/extensions/apollo/runners/maintenance.rb +5 -4
- data/lib/legion/extensions/apollo/runners/request.rb +7 -1
- data/lib/legion/extensions/apollo/version.rb +1 -1
- data/lib/legion/extensions/apollo.rb +96 -0
- data/spec/legion/extensions/apollo/actors/writeback_vectorize_spec.rb +3 -3
- data/spec/legion/extensions/apollo/api_spec.rb +84 -0
- data/spec/legion/extensions/apollo/helpers/capability_spec.rb +4 -4
- data/spec/legion/extensions/apollo/runners/gas_anticipate_spec.rb +0 -3
- data/spec/legion/extensions/apollo/runners/gas_relate_spec.rb +0 -4
- data/spec/legion/extensions/apollo/runners/gas_synthesize_spec.rb +0 -11
- data/spec/legion/extensions/apollo/runners/knowledge_spec.rb +19 -9
- data/spec/legion/extensions/apollo/runners/request_spec.rb +4 -4
- data/spec/spec_helper.rb +4 -0
- metadata +2 -1
|
@@ -12,9 +12,8 @@ module Legion
|
|
|
12
12
|
}.freeze
|
|
13
13
|
|
|
14
14
|
class << self
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
end
|
|
15
|
+
include Legion::Logging::Helper
|
|
16
|
+
include Legion::Settings::Helper
|
|
18
17
|
|
|
19
18
|
def detect_entities(text:, types: nil)
|
|
20
19
|
return [] if text.nil? || text.empty?
|
|
@@ -23,11 +22,13 @@ module Legion
|
|
|
23
22
|
entities = []
|
|
24
23
|
|
|
25
24
|
types.each do |type_sym|
|
|
26
|
-
|
|
25
|
+
entity_type = type_sym == :repository ? :repo : type_sym
|
|
26
|
+
pattern = entity_type == :concept ? concept_pattern : ENTITY_PATTERNS[entity_type]
|
|
27
27
|
next unless pattern
|
|
28
28
|
|
|
29
29
|
text.scan(pattern).each do |match|
|
|
30
|
-
entities << { type:
|
|
30
|
+
entities << { type: entity_type, value: match.strip,
|
|
31
|
+
confidence: Confidence.apollo_setting(:entity_watchdog, :detect_confidence, default: 0.5) }
|
|
31
32
|
end
|
|
32
33
|
end
|
|
33
34
|
|
|
@@ -55,11 +56,7 @@ module Legion
|
|
|
55
56
|
end
|
|
56
57
|
|
|
57
58
|
def concept_pattern
|
|
58
|
-
keywords =
|
|
59
|
-
Legion::Settings.dig(:apollo, :entity_watchdog, :concept_keywords) || []
|
|
60
|
-
else
|
|
61
|
-
[]
|
|
62
|
-
end
|
|
59
|
+
keywords = settings[:entity_watchdog][:concept_keywords]
|
|
63
60
|
return nil if keywords.empty?
|
|
64
61
|
|
|
65
62
|
Regexp.new("\\b(?:#{keywords.map { |k| Regexp.escape(k) }.join('|')})\\b", Regexp::IGNORECASE)
|
|
@@ -68,11 +65,7 @@ module Legion
|
|
|
68
65
|
private
|
|
69
66
|
|
|
70
67
|
def default_types
|
|
71
|
-
|
|
72
|
-
Legion::Settings.dig(:apollo, :entity_watchdog, :types) || %w[person service repo concept]
|
|
73
|
-
else
|
|
74
|
-
%w[person service repo concept]
|
|
75
|
-
end
|
|
68
|
+
settings[:entity_watchdog][:types]
|
|
76
69
|
end
|
|
77
70
|
|
|
78
71
|
def find_existing(_entity)
|
|
@@ -7,11 +7,10 @@ module Legion
|
|
|
7
7
|
module Apollo
|
|
8
8
|
module Helpers
|
|
9
9
|
module Similarity
|
|
10
|
-
|
|
10
|
+
extend Legion::Logging::Helper
|
|
11
|
+
extend Legion::JSON::Helper
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
Legion::Logging
|
|
14
|
-
end
|
|
13
|
+
module_function
|
|
15
14
|
|
|
16
15
|
def cosine_similarity(vec_a:, vec_b:, **)
|
|
17
16
|
vec_a = parse_vector(vec_a)
|
|
@@ -30,9 +29,9 @@ module Legion
|
|
|
30
29
|
return vec if vec.is_a?(Array)
|
|
31
30
|
return nil unless vec.is_a?(String)
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
json_parse(vec)
|
|
34
33
|
rescue StandardError => e
|
|
35
|
-
|
|
34
|
+
handle_exception(e, level: :warn, operation: 'apollo.similarity.parse_vector')
|
|
36
35
|
nil
|
|
37
36
|
end
|
|
38
37
|
|
|
@@ -8,16 +8,15 @@ module Legion
|
|
|
8
8
|
module Apollo
|
|
9
9
|
module Helpers
|
|
10
10
|
module Writeback
|
|
11
|
+
extend Legion::Logging::Helper
|
|
12
|
+
extend Legion::Settings::Helper
|
|
13
|
+
|
|
11
14
|
RESEARCH_TOOLS = %w[read_file search_files search_content run_command].freeze
|
|
12
15
|
MAX_CONTENT_LENGTH = 4000
|
|
13
16
|
MIN_CONTENT_LENGTH = 50
|
|
14
17
|
|
|
15
18
|
module_function
|
|
16
19
|
|
|
17
|
-
def log
|
|
18
|
-
Legion::Logging
|
|
19
|
-
end
|
|
20
|
-
|
|
21
20
|
def evaluate_and_route(request:, response:, enrichments: {})
|
|
22
21
|
return unless writeback_enabled?
|
|
23
22
|
return unless should_capture?(request, response, enrichments)
|
|
@@ -25,7 +24,7 @@ module Legion
|
|
|
25
24
|
payload = build_payload(request: request, response: response)
|
|
26
25
|
route_payload(payload)
|
|
27
26
|
rescue StandardError => e
|
|
28
|
-
|
|
27
|
+
handle_exception(e, level: :warn, operation: 'apollo.writeback.evaluate_and_route')
|
|
29
28
|
end
|
|
30
29
|
|
|
31
30
|
def should_capture?(_request, response, enrichments)
|
|
@@ -68,7 +67,7 @@ module Legion
|
|
|
68
67
|
can_write = Helpers::Capability.can_write?
|
|
69
68
|
|
|
70
69
|
if can_embed
|
|
71
|
-
result = Legion::LLM::Embeddings.generate(text: payload[:content])
|
|
70
|
+
result = Legion::LLM::Call::Embeddings.generate(text: payload[:content])
|
|
72
71
|
vector = result.is_a?(Hash) ? result[:vector] : result
|
|
73
72
|
payload[:embedding] = vector.is_a?(Array) && vector.any? ? vector : Array.new(1024, 0.0)
|
|
74
73
|
end
|
|
@@ -87,7 +86,7 @@ module Legion
|
|
|
87
86
|
Runners::Knowledge.handle_ingest(**payload)
|
|
88
87
|
end
|
|
89
88
|
rescue StandardError => e
|
|
90
|
-
|
|
89
|
+
handle_exception(e, level: :warn, operation: 'apollo.writeback.write_directly')
|
|
91
90
|
publish_to_transport(payload, has_embedding: !payload[:embedding].nil?)
|
|
92
91
|
end
|
|
93
92
|
|
|
@@ -98,20 +97,20 @@ module Legion
|
|
|
98
97
|
**payload, has_embedding: has_embedding
|
|
99
98
|
).publish
|
|
100
99
|
rescue StandardError => e
|
|
101
|
-
|
|
100
|
+
handle_exception(e, level: :warn, operation: 'apollo.writeback.publish_to_transport')
|
|
102
101
|
end
|
|
103
102
|
|
|
104
103
|
def writeback_enabled?
|
|
105
|
-
|
|
104
|
+
settings[:writeback][:enabled] != false
|
|
106
105
|
rescue StandardError => e
|
|
107
|
-
|
|
106
|
+
handle_exception(e, level: :warn, operation: 'apollo.writeback.writeback_enabled')
|
|
108
107
|
true
|
|
109
108
|
end
|
|
110
109
|
|
|
111
110
|
def min_content_length
|
|
112
|
-
|
|
111
|
+
settings[:writeback][:min_content_length]
|
|
113
112
|
rescue StandardError => e
|
|
114
|
-
|
|
113
|
+
handle_exception(e, level: :warn, operation: 'apollo.writeback.min_content_length')
|
|
115
114
|
MIN_CONTENT_LENGTH
|
|
116
115
|
end
|
|
117
116
|
|
|
@@ -132,7 +131,7 @@ module Legion
|
|
|
132
131
|
|
|
133
132
|
request.caller.dig(:requested_by, :identity) || 'unknown'
|
|
134
133
|
rescue StandardError => e
|
|
135
|
-
|
|
134
|
+
handle_exception(e, level: :warn, operation: 'apollo.writeback.extract_identity')
|
|
136
135
|
'unknown'
|
|
137
136
|
end
|
|
138
137
|
|
|
@@ -142,7 +141,7 @@ module Legion
|
|
|
142
141
|
user_msgs = Array(request.messages).select { |m| m[:role] == 'user' || m['role'] == 'user' }
|
|
143
142
|
(user_msgs.last || {})[:content] || ''
|
|
144
143
|
rescue StandardError => e
|
|
145
|
-
|
|
144
|
+
handle_exception(e, level: :warn, operation: 'apollo.writeback.extract_user_query')
|
|
146
145
|
''
|
|
147
146
|
end
|
|
148
147
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../helpers/data_models'
|
|
4
|
+
|
|
3
5
|
module Legion
|
|
4
6
|
module Extensions
|
|
5
7
|
module Apollo
|
|
@@ -18,15 +20,15 @@ module Legion
|
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def aggregate(**)
|
|
21
|
-
unless
|
|
23
|
+
unless Helpers::DataModels.apollo_entry_available?
|
|
22
24
|
log.warn('Apollo Expertise.aggregate skipped: apollo_data_not_available')
|
|
23
25
|
return { success: false, error: 'apollo_data_not_available' }
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
entries =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
entries = Helpers::DataModels.apollo_entry
|
|
29
|
+
.select(:source_agent, :tags, :confidence)
|
|
30
|
+
.exclude(source_agent: nil)
|
|
31
|
+
.all
|
|
30
32
|
log.debug("Apollo Expertise.aggregate entries=#{entries.size}")
|
|
31
33
|
|
|
32
34
|
agent_set = Set.new
|
|
@@ -58,13 +60,13 @@ module Legion
|
|
|
58
60
|
def upsert_expertise_group(group)
|
|
59
61
|
count = group[:confidences].size
|
|
60
62
|
proficiency = expertise_proficiency(group[:confidences])
|
|
61
|
-
existing =
|
|
62
|
-
|
|
63
|
+
existing = Helpers::DataModels.apollo_expertise
|
|
64
|
+
.where(agent_id: group[:agent_id], domain: group[:domain]).first
|
|
63
65
|
|
|
64
66
|
if existing
|
|
65
67
|
existing.update(proficiency: proficiency, entry_count: count, last_active_at: Time.now)
|
|
66
68
|
else
|
|
67
|
-
|
|
69
|
+
Helpers::DataModels.apollo_expertise.create(
|
|
68
70
|
agent_id: group[:agent_id], domain: group[:domain],
|
|
69
71
|
proficiency: proficiency, entry_count: count, last_active_at: Time.now
|
|
70
72
|
)
|
|
@@ -6,7 +6,11 @@ module Legion
|
|
|
6
6
|
module Runners
|
|
7
7
|
module Gas
|
|
8
8
|
include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
9
|
+
include Legion::Logging::Helper
|
|
10
|
+
include Legion::JSON::Helper
|
|
9
11
|
extend Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
12
|
+
extend Legion::Logging::Helper
|
|
13
|
+
extend Legion::JSON::Helper
|
|
10
14
|
|
|
11
15
|
RELATION_TYPES = %w[
|
|
12
16
|
similar_to contradicts depends_on causes
|
|
@@ -20,7 +24,7 @@ module Legion
|
|
|
20
24
|
module_function
|
|
21
25
|
|
|
22
26
|
def json_load(str)
|
|
23
|
-
|
|
27
|
+
json_parse(str)
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
def relate_confidence_gate = Helpers::Confidence.apollo_setting(:gas, :relate_confidence_gate, default: RELATE_CONFIDENCE_GATE)
|
|
@@ -56,7 +60,7 @@ module Legion
|
|
|
56
60
|
log.info("GAS process complete facts=#{result[:facts]} entities=#{result[:entities]} relations=#{result[:relations]} synthesis=#{result[:synthesis]} anticipations=#{result[:anticipations]}") # rubocop:disable Layout/LineLength
|
|
57
61
|
result
|
|
58
62
|
rescue StandardError => e
|
|
59
|
-
|
|
63
|
+
handle_exception(e, level: :error, operation: 'apollo.gas.process')
|
|
60
64
|
{ phases_completed: 0, error: e.message }
|
|
61
65
|
end
|
|
62
66
|
|
|
@@ -88,7 +92,7 @@ module Legion
|
|
|
88
92
|
log.debug("GAS phase_extract success=#{result[:success]} entities=#{entities.size}")
|
|
89
93
|
entities
|
|
90
94
|
rescue StandardError => e
|
|
91
|
-
|
|
95
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.phase_extract')
|
|
92
96
|
[]
|
|
93
97
|
end
|
|
94
98
|
|
|
@@ -131,7 +135,7 @@ module Legion
|
|
|
131
135
|
log.debug("GAS phase_synthesize synthesis=#{synthesis.size}")
|
|
132
136
|
synthesis
|
|
133
137
|
rescue StandardError => e
|
|
134
|
-
|
|
138
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.phase_synthesize')
|
|
135
139
|
[]
|
|
136
140
|
end
|
|
137
141
|
|
|
@@ -155,7 +159,7 @@ module Legion
|
|
|
155
159
|
)
|
|
156
160
|
deposited += 1
|
|
157
161
|
rescue StandardError => e
|
|
158
|
-
|
|
162
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.phase_deposit_fact')
|
|
159
163
|
end
|
|
160
164
|
log.info("GAS phase_deposit deposited=#{deposited} facts=#{facts.size}")
|
|
161
165
|
{ deposited: deposited }
|
|
@@ -176,7 +180,7 @@ module Legion
|
|
|
176
180
|
log.debug("GAS phase_anticipate anticipations=#{anticipations.size}")
|
|
177
181
|
anticipations
|
|
178
182
|
rescue StandardError => e
|
|
179
|
-
|
|
183
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.phase_anticipate')
|
|
180
184
|
[]
|
|
181
185
|
end
|
|
182
186
|
|
|
@@ -188,7 +192,7 @@ module Legion
|
|
|
188
192
|
result = Runners::Knowledge.retrieve_relevant(query: fact[:content], limit: lim, min_confidence: min_conf)
|
|
189
193
|
entries.concat(result[:entries]) if result[:success] && result[:entries]&.any?
|
|
190
194
|
rescue StandardError => e
|
|
191
|
-
|
|
195
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.fetch_similar_entries')
|
|
192
196
|
next
|
|
193
197
|
end
|
|
194
198
|
unique = entries.uniq { |e| e[:id] }
|
|
@@ -204,7 +208,7 @@ module Legion
|
|
|
204
208
|
{ from_content: fact[:content], to_id: entry[:id], relation_type: 'similar_to', confidence: fb_conf }
|
|
205
209
|
end
|
|
206
210
|
rescue StandardError => e
|
|
207
|
-
|
|
211
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.classify_relation')
|
|
208
212
|
{ from_content: fact[:content], to_id: entry[:id], relation_type: 'similar_to', confidence: fallback_confidence }
|
|
209
213
|
end
|
|
210
214
|
|
|
@@ -254,7 +258,7 @@ module Legion
|
|
|
254
258
|
|
|
255
259
|
{ from_content: fact[:content], to_id: entry[:id], relation_type: rtype, confidence: conf }
|
|
256
260
|
rescue StandardError => e
|
|
257
|
-
|
|
261
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.llm_classify_relation')
|
|
258
262
|
fallback_relation(fact, entry)
|
|
259
263
|
end
|
|
260
264
|
|
|
@@ -304,7 +308,7 @@ module Legion
|
|
|
304
308
|
|
|
305
309
|
items.map { |item| build_synthesis_entry(item, facts) }
|
|
306
310
|
rescue StandardError => e
|
|
307
|
-
|
|
311
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.llm_synthesize')
|
|
308
312
|
[]
|
|
309
313
|
end
|
|
310
314
|
|
|
@@ -364,7 +368,7 @@ module Legion
|
|
|
364
368
|
{ question: q }
|
|
365
369
|
end
|
|
366
370
|
rescue StandardError => e
|
|
367
|
-
|
|
371
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.llm_anticipate')
|
|
368
372
|
[]
|
|
369
373
|
end
|
|
370
374
|
|
|
@@ -377,14 +381,14 @@ module Legion
|
|
|
377
381
|
confidence: fallback_confidence
|
|
378
382
|
)
|
|
379
383
|
rescue StandardError => e
|
|
380
|
-
|
|
384
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.promote_to_pattern_store')
|
|
381
385
|
nil
|
|
382
386
|
end
|
|
383
387
|
|
|
384
388
|
def llm_available?
|
|
385
389
|
defined?(Legion::LLM::Pipeline::GaiaCaller)
|
|
386
390
|
rescue StandardError => e
|
|
387
|
-
|
|
391
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.llm_available')
|
|
388
392
|
false
|
|
389
393
|
end
|
|
390
394
|
|
|
@@ -432,7 +436,7 @@ module Legion
|
|
|
432
436
|
}
|
|
433
437
|
end
|
|
434
438
|
rescue StandardError => e
|
|
435
|
-
|
|
439
|
+
handle_exception(e, level: :warn, operation: 'apollo.gas.llm_comprehend')
|
|
436
440
|
mechanical_comprehend(messages, response)
|
|
437
441
|
end
|
|
438
442
|
end
|