legion-apollo 0.3.2 → 0.3.3
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 +9 -0
- data/lib/legion/apollo/routes.rb +242 -0
- data/lib/legion/apollo/version.rb +1 -1
- data/lib/legion/apollo.rb +11 -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: 56d4a2af4184bafd3474940f42a2b4e918490470b8faa3e5334f96bf27baff02
|
|
4
|
+
data.tar.gz: 6b4e4b7fcf9b93331de7e32214bee5415b0d6a47b20d4624894247c8350cc62c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 05a8fc891f57c4e9d71619c993c343753cc7674984847224957aa7f5621faa240b9d9017bdf9bd277a17ed1ef39d626229ac9058e66da55d7a477a47aa8b5c51
|
|
7
|
+
data.tar.gz: d80855fc0f2026c2035fd2b411a2d6daaa3684125455fa46ab161dbae0e9831d00437be0faa171718cbf811d5834a1ddd138e491891c96ad87d428ae4ce2f15d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.3] - 2026-03-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `Legion::Apollo::Routes` Sinatra extension module (`lib/legion/apollo/routes.rb`): all `/api/apollo/*` route definitions extracted from `LegionIO/lib/legion/api/apollo.rb`. Self-registers with `Legion::API.register_library_routes('apollo', Legion::Apollo::Routes)` during `Legion::Apollo.start`, immediately after `@started` is set (before `Local.start` / `seed_self_knowledge`).
|
|
7
|
+
- `register_routes` private method on `Legion::Apollo` module.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- `Legion::Apollo.start` now calls `register_routes` after setting `@started = true`.
|
|
11
|
+
|
|
3
12
|
## [0.3.2] - 2026-03-26
|
|
4
13
|
|
|
5
14
|
### Added
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'helpers/tag_normalizer'
|
|
4
|
+
|
|
5
|
+
# Self-registering route module for legion-apollo.
|
|
6
|
+
# All routes previously defined in LegionIO/lib/legion/api/apollo.rb now live here
|
|
7
|
+
# and are mounted via Legion::API.register_library_routes when legion-apollo boots.
|
|
8
|
+
#
|
|
9
|
+
# LegionIO/lib/legion/api/apollo.rb is preserved for backward compatibility but guards
|
|
10
|
+
# its registration with defined?(Legion::Apollo::Routes) so double-registration is avoided.
|
|
11
|
+
|
|
12
|
+
module Legion
|
|
13
|
+
module Apollo
|
|
14
|
+
# Sinatra route module for Apollo API endpoints. Self-registers at boot.
|
|
15
|
+
module Routes # rubocop:disable Metrics/ModuleLength
|
|
16
|
+
def self.registered(app)
|
|
17
|
+
app.helpers ApolloHelpers
|
|
18
|
+
register_status_route(app)
|
|
19
|
+
register_stats_route(app)
|
|
20
|
+
register_query_route(app)
|
|
21
|
+
register_ingest_route(app)
|
|
22
|
+
register_related_route(app)
|
|
23
|
+
register_maintenance_route(app)
|
|
24
|
+
register_graph_route(app)
|
|
25
|
+
register_expertise_route(app)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.register_status_route(app)
|
|
29
|
+
app.get '/api/apollo/status' do
|
|
30
|
+
available = apollo_runner_available?
|
|
31
|
+
data_connected = apollo_data_connected?
|
|
32
|
+
status_code = available && data_connected ? 200 : 503
|
|
33
|
+
|
|
34
|
+
json_response({ available: available, data_connected: data_connected },
|
|
35
|
+
status_code: status_code)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.register_stats_route(app)
|
|
40
|
+
app.get '/api/apollo/stats' do
|
|
41
|
+
halt 503, json_error('apollo_unavailable', 'apollo is not available', status_code: 503) unless apollo_loaded?
|
|
42
|
+
|
|
43
|
+
stats = apollo_stats
|
|
44
|
+
if stats[:error]
|
|
45
|
+
halt 503, json_error('apollo_stats_unavailable', stats[:error], status_code: 503)
|
|
46
|
+
else
|
|
47
|
+
json_response(stats)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.register_query_route(app) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
53
|
+
app.post '/api/apollo/query' do
|
|
54
|
+
halt 503, json_error('apollo_unavailable', 'apollo is not available', status_code: 503) unless apollo_loaded?
|
|
55
|
+
|
|
56
|
+
body = parse_request_body
|
|
57
|
+
default_limit = defined?(Legion::Settings) ? (Legion::Settings[:apollo]&.dig(:default_limit) || 5) : 5
|
|
58
|
+
result = apollo_runner.handle_query(
|
|
59
|
+
query: body[:query],
|
|
60
|
+
limit: body[:limit] || default_limit,
|
|
61
|
+
min_confidence: body[:min_confidence] || 0.3,
|
|
62
|
+
status: body[:status] || [:confirmed],
|
|
63
|
+
tags: body[:tags],
|
|
64
|
+
domain: body[:domain],
|
|
65
|
+
agent_id: body[:agent_id] || 'api'
|
|
66
|
+
)
|
|
67
|
+
json_response(result)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.register_ingest_route(app) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
72
|
+
app.post '/api/apollo/ingest' do
|
|
73
|
+
halt 503, json_error('apollo_unavailable', 'apollo is not available', status_code: 503) unless apollo_loaded?
|
|
74
|
+
|
|
75
|
+
body = parse_request_body
|
|
76
|
+
max_tags = defined?(Legion::Settings) ? (Legion::Settings[:apollo]&.dig(:max_tags) || 20) : 20
|
|
77
|
+
# TagNormalizer hard-caps to MAX_TAGS=20 internally; clamp here to make that limit explicit.
|
|
78
|
+
effective_max_tags = [max_tags, Legion::Apollo::Helpers::TagNormalizer::MAX_TAGS].min
|
|
79
|
+
tags = Legion::Apollo::Helpers::TagNormalizer.normalize(Array(body[:tags])).first(effective_max_tags)
|
|
80
|
+
result = apollo_runner.handle_ingest(
|
|
81
|
+
content: body[:content],
|
|
82
|
+
content_type: body[:content_type] || :observation,
|
|
83
|
+
tags: tags,
|
|
84
|
+
source_agent: body[:source_agent] || 'api',
|
|
85
|
+
source_provider: body[:source_provider],
|
|
86
|
+
source_channel: body[:source_channel] || 'rest_api',
|
|
87
|
+
knowledge_domain: body[:knowledge_domain],
|
|
88
|
+
context: body[:context] || {}
|
|
89
|
+
)
|
|
90
|
+
json_response(result, status_code: 201)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def self.register_related_route(app)
|
|
95
|
+
app.get '/api/apollo/entries/:id/related' do
|
|
96
|
+
halt 503, json_error('apollo_unavailable', 'apollo is not available', status_code: 503) unless apollo_loaded?
|
|
97
|
+
|
|
98
|
+
result = apollo_runner.related_entries(
|
|
99
|
+
entry_id: params[:id].to_i,
|
|
100
|
+
relation_types: params[:relation_types]&.split(','),
|
|
101
|
+
depth: (params[:depth] || 2).to_i
|
|
102
|
+
)
|
|
103
|
+
json_response(result)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.register_maintenance_route(app) # rubocop:disable Metrics/MethodLength
|
|
108
|
+
app.post '/api/apollo/maintenance' do
|
|
109
|
+
halt 503, json_error('apollo_unavailable', 'apollo is not available', status_code: 503) unless apollo_loaded?
|
|
110
|
+
|
|
111
|
+
body = parse_request_body
|
|
112
|
+
action_str = body[:action]
|
|
113
|
+
unless %w[
|
|
114
|
+
decay_cycle corroboration
|
|
115
|
+
].include?(action_str)
|
|
116
|
+
halt 400,
|
|
117
|
+
json_error('invalid_action', 'action must be decay_cycle or corroboration', status_code: 400)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
action = action_str.to_sym
|
|
121
|
+
|
|
122
|
+
result = run_maintenance(action)
|
|
123
|
+
json_response(result)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def self.register_graph_route(app)
|
|
128
|
+
app.get '/api/apollo/graph' do
|
|
129
|
+
halt 503, json_error('apollo_unavailable', 'apollo is not available', status_code: 503) unless apollo_loaded?
|
|
130
|
+
|
|
131
|
+
json_response(apollo_graph_topology)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def self.register_expertise_route(app)
|
|
136
|
+
app.get '/api/apollo/expertise' do
|
|
137
|
+
halt 503, json_error('apollo_unavailable', 'apollo is not available', status_code: 503) unless apollo_loaded?
|
|
138
|
+
|
|
139
|
+
json_response(apollo_expertise_map)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
class << self
|
|
144
|
+
private :register_status_route, :register_stats_route, :register_query_route,
|
|
145
|
+
:register_ingest_route, :register_related_route, :register_maintenance_route,
|
|
146
|
+
:register_graph_route, :register_expertise_route
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Helper methods mixed into the Sinatra app context
|
|
150
|
+
module ApolloHelpers
|
|
151
|
+
def apollo_runner_available?
|
|
152
|
+
return false unless defined?(Legion::Extensions::Apollo::Runners::Knowledge)
|
|
153
|
+
|
|
154
|
+
required = %i[handle_query handle_ingest related_entries]
|
|
155
|
+
required.all? { |m| Legion::Extensions::Apollo::Runners::Knowledge.respond_to?(m) }
|
|
156
|
+
rescue StandardError => e
|
|
157
|
+
if defined?(Legion::Logging)
|
|
158
|
+
Legion::Logging.debug("Apollo#apollo_runner_available? check failed: #{e.message}")
|
|
159
|
+
end
|
|
160
|
+
false
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def apollo_loaded?
|
|
164
|
+
apollo_runner_available? && apollo_data_connected?
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def apollo_data_connected?
|
|
168
|
+
defined?(Legion::Data) && Legion::Data.respond_to?(:connection) && !Legion::Data.connection.nil?
|
|
169
|
+
rescue StandardError => e
|
|
170
|
+
Legion::Logging.debug("Apollo#apollo_data_connected? check failed: #{e.message}") if defined?(Legion::Logging)
|
|
171
|
+
false
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def apollo_runner
|
|
175
|
+
Legion::Extensions::Apollo::Runners::Knowledge
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def apollo_maintenance_runner # rubocop:disable Metrics/MethodLength
|
|
179
|
+
@apollo_maintenance_runner ||= begin
|
|
180
|
+
unless defined?(Legion::Extensions::Apollo::Runners::Maintenance)
|
|
181
|
+
halt 503, json_error('maintenance_unavailable', 'Apollo maintenance runner is not loaded')
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
runner = Object.new.extend(Legion::Extensions::Apollo::Runners::Maintenance)
|
|
185
|
+
required = %i[run_decay_cycle check_corroboration]
|
|
186
|
+
unless required.all? { |m| runner.respond_to?(m) }
|
|
187
|
+
halt 503, json_error('maintenance_unavailable', 'Apollo maintenance runner is missing required actions')
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
runner
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def run_maintenance(action)
|
|
195
|
+
case action
|
|
196
|
+
when :decay_cycle
|
|
197
|
+
apollo_maintenance_runner.run_decay_cycle
|
|
198
|
+
when :corroboration
|
|
199
|
+
apollo_maintenance_runner.check_corroboration
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def apollo_graph_topology
|
|
204
|
+
return { error: 'Apollo runner unavailable' } unless apollo_runner_available?
|
|
205
|
+
unless apollo_runner.respond_to?(:graph_topology)
|
|
206
|
+
return { error: 'Apollo graph_topology not supported by runner' }
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
apollo_runner.graph_topology
|
|
210
|
+
rescue StandardError => e
|
|
211
|
+
Legion::Logging.debug("Apollo#apollo_graph_topology failed: #{e.message}") if defined?(Legion::Logging)
|
|
212
|
+
{ error: 'apollo_graph_topology unavailable' }
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def apollo_expertise_map
|
|
216
|
+
return { error: 'Apollo runner unavailable' } unless apollo_runner_available?
|
|
217
|
+
unless apollo_runner.respond_to?(:expertise_map)
|
|
218
|
+
return { error: 'Apollo expertise_map not supported by runner' }
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
apollo_runner.expertise_map
|
|
222
|
+
rescue StandardError => e
|
|
223
|
+
Legion::Logging.debug("Apollo#apollo_expertise_map failed: #{e.message}") if defined?(Legion::Logging)
|
|
224
|
+
{ error: 'apollo_expertise_map unavailable' }
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def apollo_stats
|
|
228
|
+
return { total_entries: 0, error: 'Apollo runner unavailable' } unless apollo_runner_available?
|
|
229
|
+
unless apollo_runner.respond_to?(:stats)
|
|
230
|
+
return { total_entries: 0,
|
|
231
|
+
error: 'Apollo stats not supported by runner' }
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
apollo_runner.stats
|
|
235
|
+
rescue StandardError => e
|
|
236
|
+
Legion::Logging.debug("Apollo#apollo_stats failed: #{e.message}") if defined?(Legion::Logging)
|
|
237
|
+
{ total_entries: 0, error: 'apollo_stats unavailable' }
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
data/lib/legion/apollo.rb
CHANGED
|
@@ -5,6 +5,7 @@ require_relative 'apollo/version'
|
|
|
5
5
|
require_relative 'apollo/settings'
|
|
6
6
|
require_relative 'apollo/local'
|
|
7
7
|
require_relative 'apollo/runners'
|
|
8
|
+
require_relative 'apollo/routes'
|
|
8
9
|
|
|
9
10
|
module Legion
|
|
10
11
|
# Apollo client library — query, ingest, and retrieve with smart routing.
|
|
@@ -23,6 +24,7 @@ module Legion
|
|
|
23
24
|
@started = true
|
|
24
25
|
Legion::Logging.info 'Legion::Apollo started' if defined?(Legion::Logging)
|
|
25
26
|
|
|
27
|
+
register_routes
|
|
26
28
|
Legion::Apollo::Local.start
|
|
27
29
|
seed_self_knowledge
|
|
28
30
|
end
|
|
@@ -307,6 +309,15 @@ module Legion
|
|
|
307
309
|
def not_started_error
|
|
308
310
|
{ success: false, error: :not_started }
|
|
309
311
|
end
|
|
312
|
+
|
|
313
|
+
def register_routes
|
|
314
|
+
return unless defined?(Legion::API) && Legion::API.respond_to?(:register_library_routes)
|
|
315
|
+
|
|
316
|
+
Legion::API.register_library_routes('apollo', Legion::Apollo::Routes)
|
|
317
|
+
Legion::Logging.debug 'Legion::Apollo routes registered with API' if defined?(Legion::Logging)
|
|
318
|
+
rescue StandardError => e
|
|
319
|
+
Legion::Logging.warn "Legion::Apollo route registration failed: #{e.message}" if defined?(Legion::Logging)
|
|
320
|
+
end
|
|
310
321
|
end
|
|
311
322
|
end
|
|
312
323
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legion-apollo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -86,6 +86,7 @@ files:
|
|
|
86
86
|
- lib/legion/apollo/messages/ingest.rb
|
|
87
87
|
- lib/legion/apollo/messages/query.rb
|
|
88
88
|
- lib/legion/apollo/messages/writeback.rb
|
|
89
|
+
- lib/legion/apollo/routes.rb
|
|
89
90
|
- lib/legion/apollo/runners.rb
|
|
90
91
|
- lib/legion/apollo/runners/request.rb
|
|
91
92
|
- lib/legion/apollo/settings.rb
|