lex-apollo 0.4.22 → 0.4.24

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -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 +28 -22
  13. data/lib/legion/extensions/apollo/gaia_integration.rb +16 -13
  14. data/lib/legion/extensions/apollo/helpers/capability.rb +19 -17
  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 +47 -27
  22. data/lib/legion/extensions/apollo/runners/knowledge.rb +95 -80
  23. data/lib/legion/extensions/apollo/runners/maintenance.rb +7 -5
  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 +20 -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 +25 -15
  34. data/spec/legion/extensions/apollo/runners/maintenance_spec.rb +8 -8
  35. data/spec/legion/extensions/apollo/runners/request_spec.rb +8 -8
  36. data/spec/spec_helper.rb +4 -0
  37. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a3e0ff5897e31c3f8e91f5b71eb96fd9ee90a15a041a5034ae936e2188806ae
4
- data.tar.gz: c3aba4e4e156c940298dde9c54da46b77e87ffa05db60b7f4b3877307fa20c1c
3
+ metadata.gz: 2dceee29e5b2af12bab5833beac8b837d2366eaf9509c7e4ce04e88b44a5c28f
4
+ data.tar.gz: 97d62a6385f375b19a6f48b1881fef8525e5949c4348bfe0cd07581d9ff710f2
5
5
  SHA512:
6
- metadata.gz: e8d3000ec6c34b23c5f49eea11b2a03d8ef117d395f9134782cf1c2fe91650b569b036571aaafd023d36d3fbd74725d492e44b98ed701348717b3221a7e45986
7
- data.tar.gz: 811fd837e8370dde5d998daadad819f648da2f4b1aae3258c82573efb773a4901c6aff8b6cbcbe60eb9f964cee9146b81288d923429321cc7e70e046cd14371b
6
+ metadata.gz: 90065729231f3322eeaaeaa0e44e03b9b79350157674bec30f174fa6447d74bc53b4794e3385eee9d617c13c62cb22198de39fc21ebece7d2d512e7b1dd09ba6
7
+ data.tar.gz: f1c1b607fd9d9d244c0937b654ea95ca361980f5732c6e513719a6163004595ce0aaa9baab4181db56c8e6e8d1c511c1d6695c9110905e2094a252ba06e5a2c6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.24] - 2026-05-07
4
+
5
+ ### Fixed
6
+ - Prevent zero-vector embeddings from being stored as valid semantic vectors when LLM embedding is unavailable.
7
+ - Avoid self-referential corroboration relations, bound corroboration maintenance scans, and preserve valid decay age filtering.
8
+ - Parse structured GAS LLM phase responses from `result[:data]` before falling back to JSON strings.
9
+ - Make Apollo write-privilege memoization thread-safe.
10
+
11
+ ## [0.4.23] - 2026-05-06
12
+
13
+ ### Fixed
14
+ - Apollo data model access now prefers the namespaced `Legion::Data::Model::Apollo::*` classes introduced by the legion-data schema cleanup while retaining fallback compatibility with the legacy `ApolloEntry`, `ApolloRelation`, `ApolloAccessLog`, and `ApolloExpertise` constants.
15
+
16
+ ### Changed
17
+ - Apollo defaults are now declared directly in `Apollo.default_settings`, and Apollo helpers, runners, actors, and API paths use `Legion::Logging::Helper`, `Legion::Settings::Helper`, and `Legion::JSON` helper methods instead of direct logging/settings/JSON calls.
18
+
3
19
  ## [0.4.22] - 2026-04-28
4
20
 
5
21
  ### Fixed
@@ -8,9 +8,11 @@ module Legion
8
8
  module Apollo
9
9
  module Actor
10
10
  class CorroborationChecker < Legion::Extensions::Actors::Every
11
+ include Legion::Settings::Helper
12
+
11
13
  def runner_class = Legion::Extensions::Apollo::Runners::Maintenance
12
14
  def runner_function = 'check_corroboration'
13
- def time = (defined?(Legion::Settings) && Legion::Settings.dig(:apollo, :actors, :corroboration_interval)) || 900
15
+ def time = settings[:actors][:corroboration_interval]
14
16
  def run_now? = false
15
17
  def use_runner? = false
16
18
  def check_subtask? = false
@@ -8,9 +8,11 @@ module Legion
8
8
  module Apollo
9
9
  module Actor
10
10
  class Decay < Legion::Extensions::Actors::Every
11
+ include Legion::Settings::Helper
12
+
11
13
  def runner_class = Legion::Extensions::Apollo::Runners::Maintenance
12
14
  def runner_function = 'run_decay_cycle'
13
- def time = (defined?(Legion::Settings) && Legion::Settings.dig(:apollo, :actors, :decay_interval)) || 3600
15
+ def time = settings[:actors][:decay_interval]
14
16
  def run_now? = false
15
17
  def use_runner? = false
16
18
  def check_subtask? = false
@@ -11,6 +11,7 @@ module Legion
11
11
  class EntityWatchdog < Legion::Extensions::Actors::Every
12
12
  include Legion::Extensions::Apollo::Runners::Knowledge
13
13
  include Legion::Extensions::Apollo::Runners::EntityExtractor
14
+ include Legion::Settings::Helper
14
15
 
15
16
  DEDUP_THRESHOLD_DEFAULT = 0.92
16
17
  TASK_LOG_LOOKBACK_SECONDS = 300
@@ -18,7 +19,7 @@ module Legion
18
19
 
19
20
  def runner_class = self.class
20
21
  def runner_function = 'scan_and_ingest'
21
- def time = (defined?(Legion::Settings) && Legion::Settings.dig(:apollo, :actors, :entity_watchdog_interval)) || 120
22
+ def time = settings[:actors][:entity_watchdog_interval]
22
23
  def run_now? = false
23
24
  def use_runner? = false
24
25
  def check_subtask? = false
@@ -28,7 +29,7 @@ module Legion
28
29
  defined?(Legion::Extensions::Apollo::Runners::EntityExtractor) &&
29
30
  Legion.const_defined?(:Transport, false)
30
31
  rescue StandardError => e
31
- log.warn("EntityWatchdog enabled? check failed: #{e.message}")
32
+ handle_exception(e, level: :warn, operation: 'apollo.entity_watchdog.enabled')
32
33
  false
33
34
  end
34
35
 
@@ -64,8 +65,8 @@ module Legion
64
65
  def recent_task_log_texts
65
66
  return [] unless defined?(Legion::Data) && defined?(Legion::Data::Model::TaskLog)
66
67
 
67
- lookback = (defined?(Legion::Settings) && Legion::Settings.dig(:apollo, :entity_watchdog, :lookback_seconds)) || TASK_LOG_LOOKBACK_SECONDS
68
- log_limit = (defined?(Legion::Settings) && Legion::Settings.dig(:apollo, :entity_watchdog, :log_limit)) || TASK_LOG_LIMIT
68
+ lookback = settings[:entity_watchdog][:lookback_seconds]
69
+ log_limit = settings[:entity_watchdog][:log_limit]
69
70
  cutoff = Time.now - lookback
70
71
  logs = Legion::Data::Model::TaskLog
71
72
  .where { created_at >= cutoff }
@@ -76,7 +77,7 @@ module Legion
76
77
  log.debug("EntityWatchdog recent_task_log_texts lookback=#{lookback} limit=#{log_limit} raw=#{logs.size} unique=#{texts.size}")
77
78
  texts
78
79
  rescue StandardError => e
79
- log.warn("EntityWatchdog recent_task_log_texts failed: #{e.message}")
80
+ handle_exception(e, level: :warn, operation: 'apollo.entity_watchdog.recent_task_log_texts')
80
81
  []
81
82
  end
82
83
 
@@ -93,7 +94,7 @@ module Legion
93
94
  distance = closest[:distance].to_f
94
95
  distance <= (1.0 - dedup_similarity_threshold)
95
96
  rescue StandardError => e
96
- log.warn("EntityWatchdog entity_exists_in_apollo? failed: #{e.message}")
97
+ handle_exception(e, level: :warn, operation: 'apollo.entity_watchdog.entity_exists_in_apollo')
97
98
  false
98
99
  end
99
100
 
@@ -113,27 +114,15 @@ module Legion
113
114
  end
114
115
 
115
116
  def entity_types
116
- if defined?(Legion::Settings)
117
- types = Legion::Settings.dig(:apollo, :entity_watchdog, :types)
118
- return Array(types).map(&:to_s) if types
119
- end
120
- %w[person service repository concept]
117
+ Array(settings[:entity_watchdog][:types]).map(&:to_s)
121
118
  end
122
119
 
123
120
  def min_entity_confidence
124
- if defined?(Legion::Settings)
125
- val = Legion::Settings.dig(:apollo, :entity_watchdog, :min_confidence)
126
- return val.to_f if val
127
- end
128
- 0.7
121
+ settings[:entity_watchdog][:min_confidence].to_f
129
122
  end
130
123
 
131
124
  def dedup_similarity_threshold
132
- if defined?(Legion::Settings)
133
- val = Legion::Settings.dig(:apollo, :entity_watchdog, :dedup_threshold)
134
- return val.to_f if val
135
- end
136
- DEDUP_THRESHOLD_DEFAULT
125
+ settings[:entity_watchdog][:dedup_threshold].to_f
137
126
  end
138
127
  end
139
128
  end
@@ -8,9 +8,11 @@ module Legion
8
8
  module Apollo
9
9
  module Actor
10
10
  class ExpertiseAggregator < Legion::Extensions::Actors::Every
11
+ include Legion::Settings::Helper
12
+
11
13
  def runner_class = Legion::Extensions::Apollo::Runners::Expertise
12
14
  def runner_function = 'aggregate'
13
- def time = (defined?(Legion::Settings) && Legion::Settings.dig(:apollo, :actors, :expertise_interval)) || 1800
15
+ def time = settings[:actors][:expertise_interval]
14
16
  def run_now? = false
15
17
  def use_runner? = false
16
18
  def check_subtask? = false
@@ -17,7 +17,7 @@ module Legion
17
17
  defined?(Legion::Extensions::Apollo::Runners::Gas) &&
18
18
  Legion.const_defined?(:Transport, false)
19
19
  rescue StandardError => e
20
- log.warn("GasSubscriber enabled? check failed: #{e.message}")
20
+ handle_exception(e, level: :warn, operation: 'apollo.gas_subscriber.enabled')
21
21
  false
22
22
  end
23
23
 
@@ -16,7 +16,7 @@ module Legion
16
16
  defined?(Legion::Extensions::Apollo::Runners::Knowledge) &&
17
17
  Legion.const_defined?(:Transport, false)
18
18
  rescue StandardError => e
19
- log.warn("Ingest enabled? check failed: #{e.message}")
19
+ handle_exception(e, level: :warn, operation: 'apollo.ingest.enabled')
20
20
  false
21
21
  end
22
22
  end
@@ -16,7 +16,7 @@ module Legion
16
16
  defined?(Legion::Extensions::Apollo::Runners::Knowledge) &&
17
17
  Legion.const_defined?(:Transport, false)
18
18
  rescue StandardError => e
19
- log.warn("QueryResponder enabled? check failed: #{e.message}")
19
+ handle_exception(e, level: :warn, operation: 'apollo.query_responder.enabled')
20
20
  false
21
21
  end
22
22
  end
@@ -17,7 +17,7 @@ module Legion
17
17
  Legion.const_defined?(:Transport, false) &&
18
18
  Helpers::Capability.apollo_write_enabled?
19
19
  rescue StandardError => e
20
- log.warn("WritebackStore enabled? check failed: #{e.message}")
20
+ handle_exception(e, level: :warn, operation: 'apollo.writeback_store.enabled')
21
21
  false
22
22
  end
23
23
  end
@@ -15,7 +15,7 @@ module Legion
15
15
  def handle_vectorize(payload)
16
16
  payload = symbolize(payload)
17
17
  log.debug("WritebackVectorize handle_vectorize content_length=#{payload[:content].to_s.length} content_type=#{payload[:content_type] || 'nil'}")
18
- result = Legion::LLM::Embeddings.generate(text: payload[:content])
18
+ result = Legion::LLM::Call::Embeddings.generate(text: payload[:content])
19
19
  vector = result.is_a?(Hash) ? result[:vector] : result
20
20
  embedding = vector.is_a?(Array) && vector.any? ? vector : Array.new(1024, 0.0)
21
21
  log.debug("WritebackVectorize embedding_dimensions=#{embedding.length} vector_generated=#{vector.is_a?(Array) && vector.any?}")
@@ -41,7 +41,7 @@ module Legion
41
41
  def enabled? # rubocop:disable Legion/Extension/ActorEnabledSideEffects
42
42
  Legion.const_defined?(:Transport, false) && Helpers::Capability.can_embed?
43
43
  rescue StandardError => e
44
- log.warn("WritebackVectorize enabled? check failed: #{e.message}")
44
+ handle_exception(e, level: :warn, operation: 'apollo.writeback_vectorize.enabled')
45
45
  false
46
46
  end
47
47
 
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'sinatra/base' unless defined?(Sinatra)
4
- require 'json'
4
+ require 'legion/logging'
5
+ require 'legion/json'
6
+ require 'legion/extensions/apollo/helpers/data_models'
5
7
 
6
8
  module Legion
7
9
  module Extensions
@@ -11,9 +13,9 @@ module Legion
11
13
 
12
14
  class << self
13
15
  def stats_payload(now: Time.now)
14
- return { error: 'apollo_data_not_available' } unless defined?(Legion::Data::Model::ApolloEntry)
16
+ return { error: 'apollo_data_not_available' } unless Helpers::DataModels.apollo_entry_available?
15
17
 
16
- entries = Legion::Data::Model::ApolloEntry
18
+ entries = Helpers::DataModels.apollo_entry
17
19
  by_status = grouped_counts(entries, :status)
18
20
  by_status['active'] = entries.exclude(status: 'archived').count
19
21
 
@@ -24,7 +26,7 @@ module Legion
24
26
  by_status: by_status,
25
27
  by_content_type: grouped_counts(entries, :content_type)
26
28
  }
27
- stats[:total_relations] = Legion::Data::Model::ApolloRelation.count if defined?(Legion::Data::Model::ApolloRelation)
29
+ stats[:total_relations] = Helpers::DataModels.apollo_relation.count if Helpers::DataModels.apollo_relation_available?
28
30
  stats
29
31
  end
30
32
 
@@ -45,13 +47,17 @@ module Legion
45
47
  end
46
48
 
47
49
  helpers do
50
+ include Legion::Logging::Helper
51
+ include Legion::JSON::Helper
52
+
48
53
  def json_body
49
54
  body = request.body.read
50
55
  return {} if body.empty?
51
56
 
52
- ::JSON.parse(body, symbolize_names: true)
53
- rescue ::JSON::ParserError => e
54
- halt 400, { error: "invalid JSON: #{e.message}" }.to_json
57
+ json_parse(body)
58
+ rescue Legion::JSON::ParseError => e
59
+ handle_exception(e, level: :warn, operation: 'apollo.api.json_body')
60
+ halt 400, json_dump(error: "invalid JSON: #{e.message}")
55
61
  end
56
62
 
57
63
  def runner
@@ -73,14 +79,14 @@ module Legion
73
79
 
74
80
  # Health check
75
81
  get '/api/apollo/health' do
76
- available = defined?(Legion::Data::Model::ApolloEntry) ? true : false
77
- { status: available ? 'ok' : 'degraded', data_available: available }.to_json
82
+ available = Helpers::DataModels.apollo_entry_available?
83
+ json_dump(status: available ? 'ok' : 'degraded', data_available: available)
78
84
  end
79
85
 
80
86
  # Query knowledge (semantic search)
81
87
  post '/api/apollo/query' do
82
88
  req = json_body
83
- halt 400, { error: 'query is required' }.to_json unless req[:query]
89
+ halt 400, json_dump(error: 'query is required') unless req[:query]
84
90
 
85
91
  query_options = {
86
92
  query: req[:query],
@@ -94,14 +100,14 @@ module Legion
94
100
 
95
101
  result = runner.handle_query(**query_options)
96
102
  status result[:success] ? 200 : 500
97
- result.to_json
103
+ json_dump(result)
98
104
  end
99
105
 
100
106
  # Ingest knowledge
101
107
  post '/api/apollo/ingest' do
102
108
  req = json_body
103
- halt 400, { error: 'content is required' }.to_json unless req[:content]
104
- halt 400, { error: 'content_type is required' }.to_json unless req[:content_type]
109
+ halt 400, json_dump(error: 'content is required') unless req[:content]
110
+ halt 400, json_dump(error: 'content_type is required') unless req[:content_type]
105
111
 
106
112
  result = runner.handle_ingest(
107
113
  content: req[:content],
@@ -114,13 +120,13 @@ module Legion
114
120
  context: req[:context] || {}
115
121
  )
116
122
  status result[:success] ? 201 : 500
117
- result.to_json
123
+ json_dump(result)
118
124
  end
119
125
 
120
126
  # Graph traversal
121
127
  post '/api/apollo/traverse' do
122
128
  req = json_body
123
- halt 400, { error: 'entry_id is required' }.to_json unless req[:entry_id]
129
+ halt 400, json_dump(error: 'entry_id is required') unless req[:entry_id]
124
130
 
125
131
  result = runner.handle_traverse(
126
132
  entry_id: req[:entry_id],
@@ -129,13 +135,13 @@ module Legion
129
135
  agent_id: req[:agent_id] || 'api'
130
136
  )
131
137
  status result[:success] ? 200 : 500
132
- result.to_json
138
+ json_dump(result)
133
139
  end
134
140
 
135
141
  # Retrieve relevant (GAIA-compatible)
136
142
  post '/api/apollo/retrieve' do
137
143
  req = json_body
138
- halt 400, { error: 'query is required' }.to_json unless req[:query]
144
+ halt 400, json_dump(error: 'query is required') unless req[:query]
139
145
 
140
146
  result = runner.retrieve_relevant(
141
147
  query: req[:query],
@@ -145,7 +151,7 @@ module Legion
145
151
  domain: req[:domain]
146
152
  )
147
153
  status result[:success] ? 200 : 500
148
- result.to_json
154
+ json_dump(result)
149
155
  end
150
156
 
151
157
  # Deprecate entry
@@ -154,24 +160,24 @@ module Legion
154
160
  entry_id: params[:id],
155
161
  reason: json_body[:reason] || 'deprecated via API'
156
162
  )
157
- result.to_json
163
+ json_dump(result)
158
164
  end
159
165
 
160
166
  # Domains at risk — must be declared before /:agent_id to avoid routing conflict
161
167
  get '/api/apollo/expertise/at-risk' do
162
168
  result = expertise_runner.domains_at_risk
163
- result.to_json
169
+ json_dump(result)
164
170
  end
165
171
 
166
172
  # Expertise for an agent
167
173
  get '/api/apollo/expertise/:agent_id' do
168
174
  result = expertise_runner.agent_profile(agent_id: params[:agent_id])
169
- result.to_json
175
+ json_dump(result)
170
176
  end
171
177
 
172
178
  # Statistics
173
179
  get '/api/apollo/stats' do
174
- self.class.stats_payload.to_json
180
+ json_dump(self.class.stats_payload)
175
181
  end
176
182
  end
177
183
  end
@@ -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
@@ -22,18 +24,19 @@ module Legion
22
24
  end
23
25
 
24
26
  def publishable?(insight)
25
- (insight[:confidence] || 0) > PUBLISH_CONFIDENCE_THRESHOLD &&
26
- (insight[:novelty] || 0) > PUBLISH_NOVELTY_THRESHOLD
27
+ confidence = (insight[:confidence] || 0).to_f
28
+ novelty = insight[:novelty] ? insight[:novelty].to_f : (1.0 - confidence)
29
+ confidence > PUBLISH_CONFIDENCE_THRESHOLD && novelty > PUBLISH_NOVELTY_THRESHOLD
27
30
  end
28
31
 
29
32
  def handle_mesh_departure(agent_id:)
30
- return nil unless defined?(Legion::Data::Model::ApolloExpertise)
33
+ return nil unless Helpers::DataModels.apollo_expertise_available?
31
34
 
32
- sole_expert_domains = Legion::Data::Model::ApolloExpertise
33
- .where(agent_id: agent_id)
34
- .all
35
- .select { |e| sole_expert?(e.domain, agent_id) }
36
- .map(&:domain)
35
+ sole_expert_domains = Helpers::DataModels.apollo_expertise
36
+ .where(agent_id: agent_id)
37
+ .all
38
+ .select { |e| sole_expert?(e.domain, agent_id) }
39
+ .map(&:domain)
37
40
 
38
41
  return nil if sole_expert_domains.empty?
39
42
 
@@ -48,12 +51,12 @@ module Legion
48
51
  private
49
52
 
50
53
  def sole_expert?(domain, agent_id)
51
- return false unless defined?(Legion::Data::Model::ApolloExpertise)
54
+ return false unless Helpers::DataModels.apollo_expertise_available?
52
55
 
53
- count = Legion::Data::Model::ApolloExpertise
54
- .where(domain: domain)
55
- .exclude(agent_id: agent_id)
56
- .count
56
+ count = Helpers::DataModels.apollo_expertise
57
+ .where(domain: domain)
58
+ .exclude(agent_id: agent_id)
59
+ .count
57
60
  count.zero?
58
61
  end
59
62
  end
@@ -5,20 +5,20 @@ module Legion
5
5
  module Apollo
6
6
  module Helpers
7
7
  module Capability
8
+ extend Legion::Logging::Helper
9
+ extend Legion::Settings::Helper
10
+
8
11
  EMBEDDING_MODELS = %w[mxbai-embed-large bge-large snowflake-arctic-embed].freeze
12
+ PRIVILEGE_MUTEX = Mutex.new
9
13
 
10
14
  module_function
11
15
 
12
- def log
13
- Legion::Logging
14
- end
15
-
16
16
  def can_embed?
17
17
  return false unless defined?(Legion::LLM) && Legion::LLM.started?
18
18
 
19
19
  ollama_embedding_available? || cloud_embedding_configured?
20
20
  rescue StandardError => e
21
- log.warn("Apollo Capability.can_embed? failed: #{e.message}")
21
+ handle_exception(e, level: :warn, operation: 'apollo.capability.can_embed')
22
22
  false
23
23
  end
24
24
 
@@ -28,14 +28,14 @@ module Legion
28
28
 
29
29
  check_db_write_privilege
30
30
  rescue StandardError => e
31
- log.warn("Apollo Capability.can_write? failed: #{e.message}")
31
+ handle_exception(e, level: :warn, operation: 'apollo.capability.can_write')
32
32
  false
33
33
  end
34
34
 
35
35
  def apollo_write_enabled?
36
- Legion::Settings.dig(:data, :apollo_write) == true
36
+ settings[:data][:apollo_write] == true
37
37
  rescue StandardError => e
38
- log.warn("Apollo Capability.apollo_write_enabled? failed: #{e.message}")
38
+ handle_exception(e, level: :warn, operation: 'apollo.capability.apollo_write_enabled')
39
39
  false
40
40
  end
41
41
 
@@ -44,27 +44,29 @@ module Legion
44
44
 
45
45
  EMBEDDING_MODELS.any? { |m| Legion::LLM::Discovery::Ollama.model_available?(m) }
46
46
  rescue StandardError => e
47
- log.warn("Apollo Capability.ollama_embedding_available? failed: #{e.message}")
47
+ handle_exception(e, level: :warn, operation: 'apollo.capability.ollama_embedding_available')
48
48
  false
49
49
  end
50
50
 
51
51
  def cloud_embedding_configured?
52
- provider = Legion::Settings.dig(:apollo, :embedding, :provider)
53
- model = Legion::Settings.dig(:apollo, :embedding, :model)
52
+ provider = settings[:embedding][:provider]
53
+ model = settings[:embedding][:model]
54
54
  !provider.nil? && !model.nil?
55
55
  rescue StandardError => e
56
- log.warn("Apollo Capability.cloud_embedding_configured? failed: #{e.message}")
56
+ handle_exception(e, level: :warn, operation: 'apollo.capability.cloud_embedding_configured')
57
57
  false
58
58
  end
59
59
 
60
60
  def check_db_write_privilege
61
- return @apollo_write_privilege unless @apollo_write_privilege.nil?
61
+ PRIVILEGE_MUTEX.synchronize do
62
+ return @apollo_write_privilege unless @apollo_write_privilege.nil?
62
63
 
63
- @apollo_write_privilege = Legion::Data.connection
64
- .fetch("SELECT has_table_privilege(current_user, 'apollo_entries', 'INSERT') AS can_insert")
65
- .first[:can_insert] == true
64
+ @apollo_write_privilege = Legion::Data.connection
65
+ .fetch("SELECT has_table_privilege(current_user, 'apollo_entries', 'INSERT') AS can_insert")
66
+ .first[:can_insert] == true
67
+ end
66
68
  rescue StandardError => e
67
- log.warn("Apollo Capability.check_db_write_privilege failed: #{e.message}")
69
+ handle_exception(e, level: :warn, operation: 'apollo.capability.check_db_write_privilege')
68
70
  @apollo_write_privilege = false
69
71
  end
70
72
 
@@ -5,6 +5,9 @@ module Legion
5
5
  module Apollo
6
6
  module Helpers
7
7
  module Confidence
8
+ extend Legion::Logging::Helper
9
+ extend Legion::Settings::Helper
10
+
8
11
  INITIAL_CONFIDENCE = 0.5
9
12
  CORROBORATION_BOOST = 0.3
10
13
  RETRIEVAL_BOOST = 0.02
@@ -21,16 +24,10 @@ module Legion
21
24
 
22
25
  module_function
23
26
 
24
- def log
25
- Legion::Logging
26
- end
27
-
28
27
  def apollo_setting(*keys, default:)
29
- return default unless defined?(Legion::Settings) && !Legion::Settings[:apollo].nil?
30
-
31
- Legion::Settings[:apollo].dig(*keys) || default
28
+ settings.dig(*keys)
32
29
  rescue StandardError => e
33
- log.warn("Apollo Confidence.apollo_setting failed: #{e.message}")
30
+ handle_exception(e, level: :warn, operation: 'apollo.confidence.apollo_setting', keys: keys)
34
31
  default
35
32
  end
36
33
 
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Apollo
6
+ module Helpers
7
+ module DataModels
8
+ class << self
9
+ def apollo_entry
10
+ namespaced_apollo_model(:Entry) || legacy_model(:ApolloEntry)
11
+ end
12
+
13
+ def apollo_relation
14
+ namespaced_apollo_model(:Relation) || legacy_model(:ApolloRelation)
15
+ end
16
+
17
+ def apollo_access_log
18
+ namespaced_apollo_model(:AccessLog) || legacy_model(:ApolloAccessLog)
19
+ end
20
+
21
+ def apollo_expertise
22
+ namespaced_apollo_model(:Expertise) || legacy_model(:ApolloExpertise)
23
+ end
24
+
25
+ def apollo_entry_available?
26
+ !apollo_entry.nil?
27
+ end
28
+
29
+ def apollo_relation_available?
30
+ !apollo_relation.nil?
31
+ end
32
+
33
+ def apollo_access_log_available?
34
+ !apollo_access_log.nil?
35
+ end
36
+
37
+ def apollo_expertise_available?
38
+ !apollo_expertise.nil?
39
+ end
40
+
41
+ private
42
+
43
+ def namespaced_apollo_model(name)
44
+ return nil unless defined?(Legion::Data::Model::Apollo)
45
+ return nil unless Legion::Data::Model::Apollo.const_defined?(name, false)
46
+
47
+ Legion::Data::Model::Apollo.const_get(name, false)
48
+ end
49
+
50
+ def legacy_model(name)
51
+ return nil unless defined?(Legion::Data::Model)
52
+ return nil unless Legion::Data::Model.const_defined?(name, false)
53
+
54
+ Legion::Data::Model.const_get(name, false)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end