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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58044db4866170db60e7607b6dd9d5afcf56118c5d8373c180d9618480b59c82
4
- data.tar.gz: c29bca810b4c41aed2093ee2ee64d12608d53a12d0401a47911b25ca2b9c3705
3
+ metadata.gz: 37b431f37cdc8eb57e8a6ebdd1961a73e8259c2dff9f3cbb8c62f00d468b7355
4
+ data.tar.gz: ebc63f21a7076df86cc10b6e68bda68fa0bbfa661fa242eb09dddb2f7502f431
5
5
  SHA512:
6
- metadata.gz: 2f72472b867e644ca58175c5fb7d3d0300a44e2e52fca0d75fd8000d2deae5ef524a29a93418f3be20d074037493d541bd2ddeb7c3b4c0cbdaf0869934147ec6
7
- data.tar.gz: 0aeee79c5734195652092460791ea4089a8c4e71bcf141f33bb01c0c478dc4ddb44e26410e0d7607270f7fec172131687b58c794c0b9f60bad95a44c676257b2
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 = 'force_decay'
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
- return zero_vector unless defined?(Legion::LLM) && Legion::LLM.started?
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: text)
16
- if result.is_a?(Array) && result.any?
17
- @dimension = result.size
18
- result
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 || DEFAULT_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
@@ -7,7 +7,7 @@ module Legion
7
7
  module Apollo
8
8
  module Transport
9
9
  module Queues
10
- class Gas < Legion::Transport::Queue
10
+ class GasSubscriber < Legion::Transport::Queue
11
11
  def queue_name
12
12
  'apollo.gas'
13
13
  end
@@ -7,7 +7,7 @@ module Legion
7
7
  module Apollo
8
8
  module Transport
9
9
  module Queues
10
- class Query < Legion::Transport::Queue
10
+ class QueryResponder < Legion::Transport::Queue
11
11
  def queue_name
12
12
  'apollo.query'
13
13
  end
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Apollo
6
- VERSION = '0.4.2'
6
+ VERSION = '0.4.3'
7
7
  end
8
8
  end
9
9
  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 on post_tick_reflection
31
- if defined?(Legion::Gaia::PhaseWiring) && begin
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 force_decay function' do
27
- expect(actor.runner_function).to eq('force_decay')
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 has entity watchdog registration block' do
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('entity_watchdog')
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(:mock_embedding) { Array.new(1536) { rand(-1.0..1.0) } }
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:| nil }
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(mock_embedding)
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 embedding from LLM' do
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(mock_embedding)
47
- expect(Legion::LLM).to have_received(:embed).with(text: 'hello world')
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:| nil }
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:| nil }
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.2
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