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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/lib/legion/extensions/apollo/actors/corroboration_checker.rb +3 -1
  4. data/lib/legion/extensions/apollo/actors/decay.rb +3 -1
  5. data/lib/legion/extensions/apollo/actors/entity_watchdog.rb +10 -21
  6. data/lib/legion/extensions/apollo/actors/expertise_aggregator.rb +3 -1
  7. data/lib/legion/extensions/apollo/actors/gas_subscriber.rb +1 -1
  8. data/lib/legion/extensions/apollo/actors/ingest.rb +1 -1
  9. data/lib/legion/extensions/apollo/actors/query_responder.rb +1 -1
  10. data/lib/legion/extensions/apollo/actors/writeback_store.rb +1 -1
  11. data/lib/legion/extensions/apollo/actors/writeback_vectorize.rb +2 -2
  12. data/lib/legion/extensions/apollo/api.rb +56 -30
  13. data/lib/legion/extensions/apollo/gaia_integration.rb +13 -11
  14. data/lib/legion/extensions/apollo/helpers/capability.rb +12 -13
  15. data/lib/legion/extensions/apollo/helpers/confidence.rb +5 -8
  16. data/lib/legion/extensions/apollo/helpers/data_models.rb +61 -0
  17. data/lib/legion/extensions/apollo/helpers/entity_watchdog.rb +8 -15
  18. data/lib/legion/extensions/apollo/helpers/similarity.rb +5 -6
  19. data/lib/legion/extensions/apollo/helpers/writeback.rb +13 -14
  20. data/lib/legion/extensions/apollo/runners/expertise.rb +10 -8
  21. data/lib/legion/extensions/apollo/runners/gas.rb +18 -14
  22. data/lib/legion/extensions/apollo/runners/knowledge.rb +77 -62
  23. data/lib/legion/extensions/apollo/runners/maintenance.rb +5 -4
  24. data/lib/legion/extensions/apollo/runners/request.rb +7 -1
  25. data/lib/legion/extensions/apollo/version.rb +1 -1
  26. data/lib/legion/extensions/apollo.rb +96 -0
  27. data/spec/legion/extensions/apollo/actors/writeback_vectorize_spec.rb +3 -3
  28. data/spec/legion/extensions/apollo/api_spec.rb +84 -0
  29. data/spec/legion/extensions/apollo/helpers/capability_spec.rb +4 -4
  30. data/spec/legion/extensions/apollo/runners/gas_anticipate_spec.rb +0 -3
  31. data/spec/legion/extensions/apollo/runners/gas_relate_spec.rb +0 -4
  32. data/spec/legion/extensions/apollo/runners/gas_synthesize_spec.rb +0 -11
  33. data/spec/legion/extensions/apollo/runners/knowledge_spec.rb +19 -9
  34. data/spec/legion/extensions/apollo/runners/request_spec.rb +4 -4
  35. data/spec/spec_helper.rb +4 -0
  36. metadata +2 -1
@@ -12,9 +12,8 @@ module Legion
12
12
  }.freeze
13
13
 
14
14
  class << self
15
- def log
16
- Legion::Logging
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
- pattern = type_sym == :concept ? concept_pattern : ENTITY_PATTERNS[type_sym]
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: type_sym, value: match.strip, confidence: Confidence.apollo_setting(:entity_watchdog, :detect_confidence, default: 0.5) }
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 = if defined?(Legion::Settings)
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
- if defined?(Legion::Settings)
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
- module_function
10
+ extend Legion::Logging::Helper
11
+ extend Legion::JSON::Helper
11
12
 
12
- def log
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
- ::JSON.parse(vec)
32
+ json_parse(vec)
34
33
  rescue StandardError => e
35
- log.warn("Apollo Similarity.parse_vector failed: #{e.message}")
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
- log.warn("apollo writeback failed: #{e.message}")
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
- log.warn("apollo direct write failed, falling back to transport: #{e.message}")
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
- log.warn("apollo writeback publish failed: #{e.message}")
100
+ handle_exception(e, level: :warn, operation: 'apollo.writeback.publish_to_transport')
102
101
  end
103
102
 
104
103
  def writeback_enabled?
105
- Legion::Settings.dig(:apollo, :writeback, :enabled) != false
104
+ settings[:writeback][:enabled] != false
106
105
  rescue StandardError => e
107
- log.warn("Apollo Writeback.writeback_enabled? failed: #{e.message}")
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
- Legion::Settings.dig(:apollo, :writeback, :min_content_length) || MIN_CONTENT_LENGTH
111
+ settings[:writeback][:min_content_length]
113
112
  rescue StandardError => e
114
- log.warn("Apollo Writeback.min_content_length failed: #{e.message}")
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
- log.warn("Apollo Writeback.extract_identity failed: #{e.message}")
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
- log.warn("Apollo Writeback.extract_user_query failed: #{e.message}")
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 defined?(Legion::Data::Model::ApolloEntry)
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 = Legion::Data::Model::ApolloEntry
27
- .select(:source_agent, :tags, :confidence)
28
- .exclude(source_agent: nil)
29
- .all
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 = Legion::Data::Model::ApolloExpertise
62
- .where(agent_id: group[:agent_id], domain: group[:domain]).first
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
- Legion::Data::Model::ApolloExpertise.create(
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
- ::JSON.parse(str, symbolize_names: true)
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
- log.error("GAS pipeline error: #{e.message}")
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
- log.warn("GAS phase_extract failed: #{e.message}")
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
- log.warn("GAS phase_synthesize failed: #{e.message}")
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
- log.warn("GAS deposit error: #{e.message}")
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
- log.warn("GAS phase_anticipate failed: #{e.message}")
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
- log.warn("GAS fetch_similar_entries failed for fact: #{e.message}")
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
- log.warn("GAS classify_relation failed: #{e.message}")
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
- log.warn("GAS llm_classify_relation failed: #{e.message}")
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
- log.warn("GAS llm_synthesize failed: #{e.message}")
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
- log.warn("GAS llm_anticipate failed: #{e.message}")
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
- log.warn("GAS promote_to_pattern_store failed: #{e.message}")
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
- log.warn("GAS llm_available? check failed: #{e.message}")
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
- log.warn("GAS llm_comprehend failed: #{e.message}")
439
+ handle_exception(e, level: :warn, operation: 'apollo.gas.llm_comprehend')
436
440
  mechanical_comprehend(messages, response)
437
441
  end
438
442
  end