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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: af5cbbe35e69f28430c0c4d2862294024e465b79a7fdba279bb50562bc0d81d4
|
|
4
|
+
data.tar.gz: d2cf12984c06eb60752f7202935649a411377ca141e20d719d2faa2ec4c05b3b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a2bf398b3f6df58ec0e84f810f7ba4e48e68991c88f95ae8e5614ba4510ae7ab9be3994dc757f34138073797cb2af99c795d532f4e24dc9fb2f09ffa0b18d13f
|
|
7
|
+
data.tar.gz: fad944b5457ef0574bb53b1d88251d5d4dce1a70b3cbe8ffadb25b3938877a0170cd36adbf41705d066d84f7036043914efa6b7473db5999daf24badde8a7f5d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.23] - 2026-05-06
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- 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.
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- 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.
|
|
10
|
+
|
|
11
|
+
## [0.4.22] - 2026-04-28
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- `/api/apollo/stats` now returns the health UI metrics Interlink expects: `recent_24h`, `avg_confidence`, and a synthesized `by_status["active"]` count for non-archived entries. This keeps the Knowledge Health cards populated instead of rendering missing values. Fixes #16.
|
|
15
|
+
|
|
3
16
|
## [0.4.21] - 2026-04-27
|
|
4
17
|
|
|
5
18
|
### Changed
|
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
68
|
-
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 '
|
|
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
|
|
@@ -9,18 +11,53 @@ module Legion
|
|
|
9
11
|
class Api < Sinatra::Base
|
|
10
12
|
set :host_authorization, permitted: :any
|
|
11
13
|
|
|
14
|
+
class << self
|
|
15
|
+
def stats_payload(now: Time.now)
|
|
16
|
+
return { error: 'apollo_data_not_available' } unless Helpers::DataModels.apollo_entry_available?
|
|
17
|
+
|
|
18
|
+
entries = Helpers::DataModels.apollo_entry
|
|
19
|
+
by_status = grouped_counts(entries, :status)
|
|
20
|
+
by_status['active'] = entries.exclude(status: 'archived').count
|
|
21
|
+
|
|
22
|
+
stats = {
|
|
23
|
+
total_entries: entries.count,
|
|
24
|
+
recent_24h: entries.where { created_at >= (now - 86_400) }.count,
|
|
25
|
+
avg_confidence: average_confidence(entries),
|
|
26
|
+
by_status: by_status,
|
|
27
|
+
by_content_type: grouped_counts(entries, :content_type)
|
|
28
|
+
}
|
|
29
|
+
stats[:total_relations] = Helpers::DataModels.apollo_relation.count if Helpers::DataModels.apollo_relation_available?
|
|
30
|
+
stats
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def grouped_counts(entries, column)
|
|
36
|
+
entries.group_and_count(column).all.to_h { |row| [row[column].to_s, row[:count]] }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def average_confidence(entries)
|
|
40
|
+
avg = entries.avg(:confidence)
|
|
41
|
+
avg&.to_f&.round(3)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
12
45
|
before do
|
|
13
46
|
content_type :json
|
|
14
47
|
end
|
|
15
48
|
|
|
16
49
|
helpers do
|
|
50
|
+
include Legion::Logging::Helper
|
|
51
|
+
include Legion::JSON::Helper
|
|
52
|
+
|
|
17
53
|
def json_body
|
|
18
54
|
body = request.body.read
|
|
19
55
|
return {} if body.empty?
|
|
20
56
|
|
|
21
|
-
|
|
22
|
-
rescue ::JSON::
|
|
23
|
-
|
|
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}")
|
|
24
61
|
end
|
|
25
62
|
|
|
26
63
|
def runner
|
|
@@ -42,14 +79,14 @@ module Legion
|
|
|
42
79
|
|
|
43
80
|
# Health check
|
|
44
81
|
get '/api/apollo/health' do
|
|
45
|
-
available =
|
|
46
|
-
|
|
82
|
+
available = Helpers::DataModels.apollo_entry_available?
|
|
83
|
+
json_dump(status: available ? 'ok' : 'degraded', data_available: available)
|
|
47
84
|
end
|
|
48
85
|
|
|
49
86
|
# Query knowledge (semantic search)
|
|
50
87
|
post '/api/apollo/query' do
|
|
51
88
|
req = json_body
|
|
52
|
-
halt 400,
|
|
89
|
+
halt 400, json_dump(error: 'query is required') unless req[:query]
|
|
53
90
|
|
|
54
91
|
query_options = {
|
|
55
92
|
query: req[:query],
|
|
@@ -63,14 +100,14 @@ module Legion
|
|
|
63
100
|
|
|
64
101
|
result = runner.handle_query(**query_options)
|
|
65
102
|
status result[:success] ? 200 : 500
|
|
66
|
-
result
|
|
103
|
+
json_dump(result)
|
|
67
104
|
end
|
|
68
105
|
|
|
69
106
|
# Ingest knowledge
|
|
70
107
|
post '/api/apollo/ingest' do
|
|
71
108
|
req = json_body
|
|
72
|
-
halt 400,
|
|
73
|
-
halt 400,
|
|
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]
|
|
74
111
|
|
|
75
112
|
result = runner.handle_ingest(
|
|
76
113
|
content: req[:content],
|
|
@@ -83,13 +120,13 @@ module Legion
|
|
|
83
120
|
context: req[:context] || {}
|
|
84
121
|
)
|
|
85
122
|
status result[:success] ? 201 : 500
|
|
86
|
-
result
|
|
123
|
+
json_dump(result)
|
|
87
124
|
end
|
|
88
125
|
|
|
89
126
|
# Graph traversal
|
|
90
127
|
post '/api/apollo/traverse' do
|
|
91
128
|
req = json_body
|
|
92
|
-
halt 400,
|
|
129
|
+
halt 400, json_dump(error: 'entry_id is required') unless req[:entry_id]
|
|
93
130
|
|
|
94
131
|
result = runner.handle_traverse(
|
|
95
132
|
entry_id: req[:entry_id],
|
|
@@ -98,13 +135,13 @@ module Legion
|
|
|
98
135
|
agent_id: req[:agent_id] || 'api'
|
|
99
136
|
)
|
|
100
137
|
status result[:success] ? 200 : 500
|
|
101
|
-
result
|
|
138
|
+
json_dump(result)
|
|
102
139
|
end
|
|
103
140
|
|
|
104
141
|
# Retrieve relevant (GAIA-compatible)
|
|
105
142
|
post '/api/apollo/retrieve' do
|
|
106
143
|
req = json_body
|
|
107
|
-
halt 400,
|
|
144
|
+
halt 400, json_dump(error: 'query is required') unless req[:query]
|
|
108
145
|
|
|
109
146
|
result = runner.retrieve_relevant(
|
|
110
147
|
query: req[:query],
|
|
@@ -114,7 +151,7 @@ module Legion
|
|
|
114
151
|
domain: req[:domain]
|
|
115
152
|
)
|
|
116
153
|
status result[:success] ? 200 : 500
|
|
117
|
-
result
|
|
154
|
+
json_dump(result)
|
|
118
155
|
end
|
|
119
156
|
|
|
120
157
|
# Deprecate entry
|
|
@@ -123,35 +160,24 @@ module Legion
|
|
|
123
160
|
entry_id: params[:id],
|
|
124
161
|
reason: json_body[:reason] || 'deprecated via API'
|
|
125
162
|
)
|
|
126
|
-
result
|
|
163
|
+
json_dump(result)
|
|
127
164
|
end
|
|
128
165
|
|
|
129
166
|
# Domains at risk — must be declared before /:agent_id to avoid routing conflict
|
|
130
167
|
get '/api/apollo/expertise/at-risk' do
|
|
131
168
|
result = expertise_runner.domains_at_risk
|
|
132
|
-
result
|
|
169
|
+
json_dump(result)
|
|
133
170
|
end
|
|
134
171
|
|
|
135
172
|
# Expertise for an agent
|
|
136
173
|
get '/api/apollo/expertise/:agent_id' do
|
|
137
174
|
result = expertise_runner.agent_profile(agent_id: params[:agent_id])
|
|
138
|
-
result
|
|
175
|
+
json_dump(result)
|
|
139
176
|
end
|
|
140
177
|
|
|
141
178
|
# Statistics
|
|
142
179
|
get '/api/apollo/stats' do
|
|
143
|
-
|
|
144
|
-
if defined?(Legion::Data::Model::ApolloEntry)
|
|
145
|
-
stats[:total_entries] = Legion::Data::Model::ApolloEntry.count
|
|
146
|
-
stats[:by_status] = Legion::Data::Model::ApolloEntry.group_and_count(:status).all
|
|
147
|
-
.to_h { |r| [r[:status], r[:count]] }
|
|
148
|
-
stats[:by_content_type] = Legion::Data::Model::ApolloEntry.group_and_count(:content_type).all
|
|
149
|
-
.to_h { |r| [r[:content_type], r[:count]] }
|
|
150
|
-
stats[:total_relations] = Legion::Data::Model::ApolloRelation.count if defined?(Legion::Data::Model::ApolloRelation)
|
|
151
|
-
else
|
|
152
|
-
stats[:error] = 'apollo_data_not_available'
|
|
153
|
-
end
|
|
154
|
-
stats.to_json
|
|
180
|
+
json_dump(self.class.stats_payload)
|
|
155
181
|
end
|
|
156
182
|
end
|
|
157
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
|
|
@@ -27,13 +29,13 @@ module Legion
|
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
def handle_mesh_departure(agent_id:)
|
|
30
|
-
return nil unless
|
|
32
|
+
return nil unless Helpers::DataModels.apollo_expertise_available?
|
|
31
33
|
|
|
32
|
-
sole_expert_domains =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
sole_expert_domains = Helpers::DataModels.apollo_expertise
|
|
35
|
+
.where(agent_id: agent_id)
|
|
36
|
+
.all
|
|
37
|
+
.select { |e| sole_expert?(e.domain, agent_id) }
|
|
38
|
+
.map(&:domain)
|
|
37
39
|
|
|
38
40
|
return nil if sole_expert_domains.empty?
|
|
39
41
|
|
|
@@ -48,12 +50,12 @@ module Legion
|
|
|
48
50
|
private
|
|
49
51
|
|
|
50
52
|
def sole_expert?(domain, agent_id)
|
|
51
|
-
return false unless
|
|
53
|
+
return false unless Helpers::DataModels.apollo_expertise_available?
|
|
52
54
|
|
|
53
|
-
count =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
count = Helpers::DataModels.apollo_expertise
|
|
56
|
+
.where(domain: domain)
|
|
57
|
+
.exclude(agent_id: agent_id)
|
|
58
|
+
.count
|
|
57
59
|
count.zero?
|
|
58
60
|
end
|
|
59
61
|
end
|
|
@@ -5,20 +5,19 @@ 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
|
|
9
12
|
|
|
10
13
|
module_function
|
|
11
14
|
|
|
12
|
-
def log
|
|
13
|
-
Legion::Logging
|
|
14
|
-
end
|
|
15
|
-
|
|
16
15
|
def can_embed?
|
|
17
16
|
return false unless defined?(Legion::LLM) && Legion::LLM.started?
|
|
18
17
|
|
|
19
18
|
ollama_embedding_available? || cloud_embedding_configured?
|
|
20
19
|
rescue StandardError => e
|
|
21
|
-
|
|
20
|
+
handle_exception(e, level: :warn, operation: 'apollo.capability.can_embed')
|
|
22
21
|
false
|
|
23
22
|
end
|
|
24
23
|
|
|
@@ -28,14 +27,14 @@ module Legion
|
|
|
28
27
|
|
|
29
28
|
check_db_write_privilege
|
|
30
29
|
rescue StandardError => e
|
|
31
|
-
|
|
30
|
+
handle_exception(e, level: :warn, operation: 'apollo.capability.can_write')
|
|
32
31
|
false
|
|
33
32
|
end
|
|
34
33
|
|
|
35
34
|
def apollo_write_enabled?
|
|
36
|
-
|
|
35
|
+
settings[:data][:apollo_write] == true
|
|
37
36
|
rescue StandardError => e
|
|
38
|
-
|
|
37
|
+
handle_exception(e, level: :warn, operation: 'apollo.capability.apollo_write_enabled')
|
|
39
38
|
false
|
|
40
39
|
end
|
|
41
40
|
|
|
@@ -44,16 +43,16 @@ module Legion
|
|
|
44
43
|
|
|
45
44
|
EMBEDDING_MODELS.any? { |m| Legion::LLM::Discovery::Ollama.model_available?(m) }
|
|
46
45
|
rescue StandardError => e
|
|
47
|
-
|
|
46
|
+
handle_exception(e, level: :warn, operation: 'apollo.capability.ollama_embedding_available')
|
|
48
47
|
false
|
|
49
48
|
end
|
|
50
49
|
|
|
51
50
|
def cloud_embedding_configured?
|
|
52
|
-
provider =
|
|
53
|
-
model =
|
|
51
|
+
provider = settings[:embedding][:provider]
|
|
52
|
+
model = settings[:embedding][:model]
|
|
54
53
|
!provider.nil? && !model.nil?
|
|
55
54
|
rescue StandardError => e
|
|
56
|
-
|
|
55
|
+
handle_exception(e, level: :warn, operation: 'apollo.capability.cloud_embedding_configured')
|
|
57
56
|
false
|
|
58
57
|
end
|
|
59
58
|
|
|
@@ -64,7 +63,7 @@ module Legion
|
|
|
64
63
|
.fetch("SELECT has_table_privilege(current_user, 'apollo_entries', 'INSERT') AS can_insert")
|
|
65
64
|
.first[:can_insert] == true
|
|
66
65
|
rescue StandardError => e
|
|
67
|
-
|
|
66
|
+
handle_exception(e, level: :warn, operation: 'apollo.capability.check_db_write_privilege')
|
|
68
67
|
@apollo_write_privilege = false
|
|
69
68
|
end
|
|
70
69
|
|
|
@@ -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
|
-
|
|
30
|
-
|
|
31
|
-
Legion::Settings[:apollo].dig(*keys) || default
|
|
28
|
+
settings.dig(*keys)
|
|
32
29
|
rescue StandardError => e
|
|
33
|
-
|
|
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
|