lex-apollo 0.4.2 → 0.4.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 +14 -0
- data/lib/legion/extensions/apollo/actors/decay.rb +1 -1
- data/lib/legion/extensions/apollo/actors/gas_subscriber.rb +10 -0
- data/lib/legion/extensions/apollo/helpers/embedding.rb +19 -6
- data/lib/legion/extensions/apollo/transport/exchanges/llm_audit.rb +19 -0
- data/lib/legion/extensions/apollo/transport/queues/gas.rb +1 -1
- data/lib/legion/extensions/apollo/transport/queues/query.rb +1 -1
- data/lib/legion/extensions/apollo/version.rb +1 -1
- data/lib/legion/extensions/apollo.rb +3 -16
- data/spec/legion/extensions/apollo/actors/decay_spec.rb +2 -2
- data/spec/legion/extensions/apollo/gaia_integration_spec.rb +2 -3
- data/spec/legion/extensions/apollo/helpers/embedding_spec.rb +49 -9
- 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: 37b431f37cdc8eb57e8a6ebdd1961a73e8259c2dff9f3cbb8c62f00d468b7355
|
|
4
|
+
data.tar.gz: ebc63f21a7076df86cc10b6e68bda68fa0bbfa661fa242eb09dddb2f7502f431
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3945caccdf6763705e4f0bd9064b638a8c10920a5c802b2dfe3fde93822569af6fd70bd32097987a60a81f209ad844bc0248f92fbc096f68a30857eeee999cf6
|
|
7
|
+
data.tar.gz: cc44d3e686c933d4d662ce2c03e2ccb2a1b10a58992e354d94bd5f805d99f676abafdcca047539b22505cf35ccb85306b785e56c65f9aca19e8548a8492b8b87
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.3] - 2026-03-24
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Embedding `generate()` now calls `Legion::LLM.embed(text)` with positional arg and extracts `:vector` from the returned Hash (was passing keyword arg to positional param and checking for Array instead of Hash — zero vectors on every call)
|
|
7
|
+
- Added warning logging when embeddings fall back to zero vectors (was completely silent)
|
|
8
|
+
- GasSubscriber now overrides `create_queue` to bind `apollo.gas` queue to `llm.audit` exchange with routing key `llm.audit.complete` (was bound to the wrong exchange with wrong routing key — GAS pipeline never received messages)
|
|
9
|
+
- Renamed `Queues::Gas` to `Queues::GasSubscriber` and `Queues::Query` to `Queues::QueryResponder` to match Subscription actor constant lookup convention
|
|
10
|
+
- Added `Transport::Exchanges::LlmAudit` exchange class for the `llm.audit` exchange
|
|
11
|
+
- Decay actor `runner_function` changed from `'force_decay'` (a no-op message builder) to `'run_decay_cycle'` (the actual DB decay implementation — confidence decay was never running)
|
|
12
|
+
- Removed dead `PhaseWiring.register_handler(:post_tick_reflection)` call from entry point (method does not exist in legion-gaia; entity watchdog runs independently as an Every actor)
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- Embedding dimension is now configurable via `Legion::Settings[:apollo][:embedding][:dimension]` (default: 1536)
|
|
16
|
+
|
|
3
17
|
## [0.4.2] - 2026-03-24
|
|
4
18
|
|
|
5
19
|
### Fixed
|
|
@@ -9,7 +9,7 @@ module Legion
|
|
|
9
9
|
module Actor
|
|
10
10
|
class Decay < Legion::Extensions::Actors::Every
|
|
11
11
|
def runner_class = Legion::Extensions::Apollo::Runners::Maintenance
|
|
12
|
-
def runner_function = '
|
|
12
|
+
def runner_function = 'run_decay_cycle'
|
|
13
13
|
def time = 3600
|
|
14
14
|
def run_now? = false
|
|
15
15
|
def use_runner? = false
|
|
@@ -11,6 +11,7 @@ module Legion
|
|
|
11
11
|
def runner_function = 'process'
|
|
12
12
|
def check_subtask? = false
|
|
13
13
|
def generate_task? = false
|
|
14
|
+
def use_runner? = false
|
|
14
15
|
|
|
15
16
|
def enabled?
|
|
16
17
|
defined?(Legion::Extensions::Apollo::Runners::Gas) &&
|
|
@@ -18,6 +19,15 @@ module Legion
|
|
|
18
19
|
rescue StandardError
|
|
19
20
|
false
|
|
20
21
|
end
|
|
22
|
+
|
|
23
|
+
def create_queue
|
|
24
|
+
return if queues.const_defined?(:GasSubscriber, false)
|
|
25
|
+
|
|
26
|
+
queues.const_set(:GasSubscriber, Apollo::Transport::Queues::GasSubscriber) unless queues.const_defined?(:GasSubscriber, false)
|
|
27
|
+
exchange_object = Apollo::Transport::Exchanges::LlmAudit.new
|
|
28
|
+
queue_object = Apollo::Transport::Queues::GasSubscriber.new
|
|
29
|
+
queue_object.bind(exchange_object, routing_key: 'llm.audit.complete')
|
|
30
|
+
end
|
|
21
31
|
end
|
|
22
32
|
end
|
|
23
33
|
end
|
|
@@ -10,19 +10,32 @@ module Legion
|
|
|
10
10
|
module_function
|
|
11
11
|
|
|
12
12
|
def generate(text:, **)
|
|
13
|
-
|
|
13
|
+
unless defined?(Legion::LLM) && Legion::LLM.started?
|
|
14
|
+
Legion::Logging.debug('[apollo] embedding fallback: LLM not started') if defined?(Legion::Logging)
|
|
15
|
+
return zero_vector
|
|
16
|
+
end
|
|
14
17
|
|
|
15
|
-
result = Legion::LLM.embed(text
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
result = Legion::LLM.embed(text)
|
|
19
|
+
vector = result.is_a?(Hash) ? result[:vector] : result
|
|
20
|
+
if vector.is_a?(Array) && vector.any?
|
|
21
|
+
@dimension = vector.size
|
|
22
|
+
vector
|
|
19
23
|
else
|
|
24
|
+
Legion::Logging.warn('[apollo] embedding fallback: LLM returned no vector') if defined?(Legion::Logging)
|
|
20
25
|
zero_vector
|
|
21
26
|
end
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
def dimension
|
|
25
|
-
@dimension ||
|
|
30
|
+
@dimension || configured_dimension
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def configured_dimension
|
|
34
|
+
return DEFAULT_DIMENSION unless defined?(Legion::Settings) && !Legion::Settings[:apollo].nil?
|
|
35
|
+
|
|
36
|
+
Legion::Settings[:apollo].dig(:embedding, :dimension) || DEFAULT_DIMENSION
|
|
37
|
+
rescue StandardError
|
|
38
|
+
DEFAULT_DIMENSION
|
|
26
39
|
end
|
|
27
40
|
|
|
28
41
|
def zero_vector
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/transport/exchange' if defined?(Legion::Transport)
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Apollo
|
|
8
|
+
module Transport
|
|
9
|
+
module Exchanges
|
|
10
|
+
class LlmAudit < Legion::Transport::Exchange
|
|
11
|
+
def exchange_name
|
|
12
|
+
'llm.audit'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -12,6 +12,7 @@ require 'legion/extensions/apollo/runners/gas'
|
|
|
12
12
|
|
|
13
13
|
if defined?(Legion::Transport)
|
|
14
14
|
require 'legion/extensions/apollo/transport/exchanges/apollo'
|
|
15
|
+
require 'legion/extensions/apollo/transport/exchanges/llm_audit'
|
|
15
16
|
require 'legion/extensions/apollo/transport/queues/ingest'
|
|
16
17
|
require 'legion/extensions/apollo/transport/queues/query'
|
|
17
18
|
require 'legion/extensions/apollo/transport/queues/gas'
|
|
@@ -27,19 +28,5 @@ module Legion
|
|
|
27
28
|
end
|
|
28
29
|
end
|
|
29
30
|
|
|
30
|
-
# Entity watchdog
|
|
31
|
-
|
|
32
|
-
Legion::Settings.dig(:apollo, :entity_watchdog, :enabled)
|
|
33
|
-
rescue StandardError
|
|
34
|
-
false
|
|
35
|
-
end
|
|
36
|
-
require 'legion/extensions/apollo/helpers/entity_watchdog'
|
|
37
|
-
Legion::Gaia::PhaseWiring.register_handler(:post_tick_reflection) do |tick_results|
|
|
38
|
-
text = tick_results.is_a?(Hash) ? (tick_results[:content] || tick_results[:output] || '').to_s : tick_results.to_s
|
|
39
|
-
entities = Legion::Extensions::Apollo::Helpers::EntityWatchdog.detect_entities(text: text)
|
|
40
|
-
if entities.any?
|
|
41
|
-
Legion::Extensions::Apollo::Helpers::EntityWatchdog.link_or_create(entities: entities,
|
|
42
|
-
source_context: tick_results[:tick_id])
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
31
|
+
# Entity watchdog runs as Actor::EntityWatchdog (Every actor, 120s interval).
|
|
32
|
+
# PhaseWiring.register_handler was removed — the watchdog scans task logs independently.
|
|
@@ -23,8 +23,8 @@ RSpec.describe Legion::Extensions::Apollo::Actor::Decay do
|
|
|
23
23
|
expect(actor.runner_class).to eq(Legion::Extensions::Apollo::Runners::Maintenance)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
it 'runs
|
|
27
|
-
expect(actor.runner_function).to eq('
|
|
26
|
+
it 'runs run_decay_cycle function' do
|
|
27
|
+
expect(actor.runner_function).to eq('run_decay_cycle')
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
it 'runs every 3600 seconds' do
|
|
@@ -64,10 +64,9 @@ RSpec.describe Legion::Extensions::Apollo::GaiaIntegration do
|
|
|
64
64
|
expect(result[:success]).to be true
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
it 'entry point
|
|
67
|
+
it 'entry point documents entity watchdog actor' do
|
|
68
68
|
entry_point = File.read(File.expand_path('../../../../lib/legion/extensions/apollo.rb', __dir__))
|
|
69
|
-
expect(entry_point).to include('
|
|
70
|
-
expect(entry_point).to include('PhaseWiring.register_handler(:post_tick_reflection)')
|
|
69
|
+
expect(entry_point).to include('Entity watchdog runs as Actor::EntityWatchdog')
|
|
71
70
|
end
|
|
72
71
|
end
|
|
73
72
|
end
|
|
@@ -29,22 +29,22 @@ RSpec.describe Legion::Extensions::Apollo::Helpers::Embedding do
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
context 'when Legion::LLM is available and started' do
|
|
32
|
-
let(:
|
|
32
|
+
let(:mock_vector) { Array.new(1536) { rand(-1.0..1.0) } }
|
|
33
33
|
|
|
34
34
|
before do
|
|
35
35
|
llm = Module.new do
|
|
36
36
|
define_method(:started?) { true }
|
|
37
|
-
define_method(:embed) { |_text
|
|
37
|
+
define_method(:embed) { |_text, **| nil }
|
|
38
38
|
extend self
|
|
39
39
|
end
|
|
40
40
|
stub_const('Legion::LLM', llm)
|
|
41
|
-
allow(Legion::LLM).to receive(:embed).and_return(
|
|
41
|
+
allow(Legion::LLM).to receive(:embed).and_return({ vector: mock_vector, model: 'text-embedding-3-small' })
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
it 'returns the
|
|
44
|
+
it 'returns the vector from the LLM response hash' do
|
|
45
45
|
result = described_class.generate(text: 'hello world')
|
|
46
|
-
expect(result).to eq(
|
|
47
|
-
expect(Legion::LLM).to have_received(:embed).with(
|
|
46
|
+
expect(result).to eq(mock_vector)
|
|
47
|
+
expect(Legion::LLM).to have_received(:embed).with('hello world')
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
@@ -52,11 +52,11 @@ RSpec.describe Legion::Extensions::Apollo::Helpers::Embedding do
|
|
|
52
52
|
before do
|
|
53
53
|
llm = Module.new do
|
|
54
54
|
define_method(:started?) { true }
|
|
55
|
-
define_method(:embed) { |_text
|
|
55
|
+
define_method(:embed) { |_text, **| nil }
|
|
56
56
|
extend self
|
|
57
57
|
end
|
|
58
58
|
stub_const('Legion::LLM', llm)
|
|
59
|
-
allow(Legion::LLM).to receive(:embed).and_return([0.1, 0.2])
|
|
59
|
+
allow(Legion::LLM).to receive(:embed).and_return({ vector: [0.1, 0.2], model: 'test' })
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
it 'accepts the embedding and updates dimension' do
|
|
@@ -66,11 +66,29 @@ RSpec.describe Legion::Extensions::Apollo::Helpers::Embedding do
|
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
context 'when Legion::LLM returns nil vector' do
|
|
70
|
+
before do
|
|
71
|
+
llm = Module.new do
|
|
72
|
+
define_method(:started?) { true }
|
|
73
|
+
define_method(:embed) { |_text, **| nil }
|
|
74
|
+
extend self
|
|
75
|
+
end
|
|
76
|
+
stub_const('Legion::LLM', llm)
|
|
77
|
+
allow(Legion::LLM).to receive(:embed).and_return({ vector: nil, model: 'test', error: 'failed' })
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'returns a zero vector as fallback' do
|
|
81
|
+
result = described_class.generate(text: 'hello world')
|
|
82
|
+
expect(result).to be_an(Array)
|
|
83
|
+
expect(result.all?(&:zero?)).to be true
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
69
87
|
context 'when Legion::LLM returns nil' do
|
|
70
88
|
before do
|
|
71
89
|
llm = Module.new do
|
|
72
90
|
define_method(:started?) { true }
|
|
73
|
-
define_method(:embed) { |_text
|
|
91
|
+
define_method(:embed) { |_text, **| nil }
|
|
74
92
|
extend self
|
|
75
93
|
end
|
|
76
94
|
stub_const('Legion::LLM', llm)
|
|
@@ -84,4 +102,26 @@ RSpec.describe Legion::Extensions::Apollo::Helpers::Embedding do
|
|
|
84
102
|
end
|
|
85
103
|
end
|
|
86
104
|
end
|
|
105
|
+
|
|
106
|
+
describe '.configured_dimension' do
|
|
107
|
+
context 'when Settings has apollo.embedding.dimension' do
|
|
108
|
+
before do
|
|
109
|
+
stub_const('Legion::Settings', { apollo: { embedding: { dimension: 768 } } })
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'returns the configured dimension' do
|
|
113
|
+
expect(described_class.configured_dimension).to eq(768)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context 'when Settings has no apollo key' do
|
|
118
|
+
before do
|
|
119
|
+
stub_const('Legion::Settings', { apollo: nil })
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'returns the default dimension' do
|
|
123
|
+
expect(described_class.configured_dimension).to eq(1536)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
87
127
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-apollo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -167,6 +167,7 @@ files:
|
|
|
167
167
|
- lib/legion/extensions/apollo/runners/maintenance.rb
|
|
168
168
|
- lib/legion/extensions/apollo/transport.rb
|
|
169
169
|
- lib/legion/extensions/apollo/transport/exchanges/apollo.rb
|
|
170
|
+
- lib/legion/extensions/apollo/transport/exchanges/llm_audit.rb
|
|
170
171
|
- lib/legion/extensions/apollo/transport/messages/ingest.rb
|
|
171
172
|
- lib/legion/extensions/apollo/transport/messages/query.rb
|
|
172
173
|
- lib/legion/extensions/apollo/transport/queues/gas.rb
|