From 2200937f1a36a9581154f307f47067654b08f63d Mon Sep 17 00:00:00 2001 From: Esity Date: Wed, 15 Apr 2026 09:59:50 -0500 Subject: [PATCH] fix two knowledge CLI crashes: query TypeError and health nil path - retrieve_chunks now extracts entries array from retrieve_relevant's Hash response instead of returning the raw Hash, preventing TypeError: no implicit conversion of Symbol into Integer on legionio knowledge query - health now guards against nil path by falling back to Legion::Settings.dig(:knowledge, :corpus_path) and returning success: false with a clear error when no path is available, preventing TypeError: no implicit conversion of nil into String on legionio knowledge health - bump to 0.6.7 --- CHANGELOG.md | 6 ++++ .../knowledge/runners/maintenance.rb | 11 +++--- .../extensions/knowledge/runners/query.rb | 3 +- lib/legion/extensions/knowledge/version.rb | 2 +- .../knowledge/runners/maintenance_spec.rb | 30 ++++++++++++++++ .../knowledge/runners/query_spec.rb | 34 +++++++++++++++++++ 6 files changed, 80 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3aa5c66..0ac2e58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [0.6.7] - 2026-04-15 + +### Fixed +- `Runners::Query.retrieve_chunks` now extracts the `entries` array from `retrieve_relevant`'s Hash response instead of returning the Hash directly, preventing `TypeError: no implicit conversion of Symbol into Integer` on `knowledge query` +- `Runners::Maintenance.health` now returns `{ success: false, error: 'corpus_path is required' }` when called with `path: nil` and no settings fallback, instead of raising `TypeError: no implicit conversion of nil into String`; falls back to `Legion::Settings.dig(:knowledge, :corpus_path)` when available + ## [0.6.6] - 2026-03-31 ### Fixed diff --git a/lib/legion/extensions/knowledge/runners/maintenance.rb b/lib/legion/extensions/knowledge/runners/maintenance.rb index ad1bef1..49fcc50 100644 --- a/lib/legion/extensions/knowledge/runners/maintenance.rb +++ b/lib/legion/extensions/knowledge/runners/maintenance.rb @@ -47,16 +47,19 @@ def reindex(path:) end def health(path:) - scan_entries = Helpers::Manifest.scan(path: path) - store_path = Helpers::ManifestStore.store_path(corpus_path: path) + resolved = path || (Legion::Settings.dig(:knowledge, :corpus_path) if defined?(Legion::Settings)) + return { success: false, error: 'corpus_path is required' } if resolved.nil? || resolved.to_s.empty? + + scan_entries = Helpers::Manifest.scan(path: resolved) + store_path = Helpers::ManifestStore.store_path(corpus_path: resolved) manifest_file = ::File.exist?(store_path) last_ingest = manifest_file ? ::File.mtime(store_path).iso8601 : nil { success: true, - local: build_local_stats(path, scan_entries, manifest_file, last_ingest), + local: build_local_stats(resolved, scan_entries, manifest_file, last_ingest), apollo: build_apollo_stats, - sync: build_sync_stats(path, scan_entries) + sync: build_sync_stats(resolved, scan_entries) } rescue StandardError => e { success: false, error: e.message } diff --git a/lib/legion/extensions/knowledge/runners/query.rb b/lib/legion/extensions/knowledge/runners/query.rb index a4d8c45..0c1269f 100644 --- a/lib/legion/extensions/knowledge/runners/query.rb +++ b/lib/legion/extensions/knowledge/runners/query.rb @@ -69,11 +69,12 @@ def record_feedback(question:, chunk_ids:, retrieval_score:, synthesized: true, def retrieve_chunks(question, top_k) return [] unless defined?(Legion::Extensions::Apollo) - Legion::Extensions::Apollo::Runners::Knowledge.retrieve_relevant( + result = Legion::Extensions::Apollo::Runners::Knowledge.retrieve_relevant( query: question, limit: top_k, tags: ['document_chunk'] ) + result.is_a?(Hash) && result[:success] ? Array(result[:entries]) : [] rescue StandardError => _e [] end diff --git a/lib/legion/extensions/knowledge/version.rb b/lib/legion/extensions/knowledge/version.rb index b235bb2..745579b 100644 --- a/lib/legion/extensions/knowledge/version.rb +++ b/lib/legion/extensions/knowledge/version.rb @@ -3,7 +3,7 @@ module Legion module Extensions module Knowledge - VERSION = '0.6.6' + VERSION = '0.6.7' end end end diff --git a/spec/legion/extensions/knowledge/runners/maintenance_spec.rb b/spec/legion/extensions/knowledge/runners/maintenance_spec.rb index c9bce04..373a6bf 100644 --- a/spec/legion/extensions/knowledge/runners/maintenance_spec.rb +++ b/spec/legion/extensions/knowledge/runners/maintenance_spec.rb @@ -265,6 +265,36 @@ end end + describe '.health with nil path' do + it 'returns success: false when path is nil and no settings corpus_path' do + result = described_class.health(path: nil) + expect(result[:success]).to be false + expect(result[:error]).to eq('corpus_path is required') + end + + it 'uses settings corpus_path when path is nil and settings are present' do + stub_const('Legion::Settings', Module.new do + def self.dig(*keys) + { knowledge: { corpus_path: nil } }.dig(*keys) + end + end) + result = described_class.health(path: nil) + expect(result[:success]).to be false + expect(result[:error]).to eq('corpus_path is required') + end + + it 'falls back to settings corpus_path when set' do + stub_const('Legion::Settings', Module.new do + def self.dig(*_keys) + Dir.pwd + end + end) + result = described_class.health(path: nil) + expect(result[:success]).to be true + expect(result).to include(:local, :apollo, :sync) + end + end + describe '.quality_report' do it 'returns all report sections' do result = described_class.quality_report diff --git a/spec/legion/extensions/knowledge/runners/query_spec.rb b/spec/legion/extensions/knowledge/runners/query_spec.rb index 2a76e68..a06d2e1 100644 --- a/spec/legion/extensions/knowledge/runners/query_spec.rb +++ b/spec/legion/extensions/knowledge/runners/query_spec.rb @@ -46,6 +46,40 @@ end end + describe '.retrieve_chunks (via .query)' do + context 'when retrieve_relevant returns a Hash (not an Array)' do + before do + stub_const('Legion::Extensions::Apollo', Module.new) + runners_mod = Module.new + knowledge_mod = Module.new + knowledge_mod.define_singleton_method(:retrieve_relevant) do |**| + { success: true, entries: [ + { id: 1, content: 'chunk text', content_type: 'document_chunk', + confidence: 0.8, distance: 0.2, tags: [], source_agent: 'test', + knowledge_domain: 'general' } + ], count: 1 } + end + runners_mod.const_set(:Knowledge, knowledge_mod) + stub_const('Legion::Extensions::Apollo::Runners', runners_mod) + end + + it 'returns success without TypeError on query' do + result = described_class.query(question: 'legion', synthesize: false) + expect(result[:success]).to be true + end + + it 'extracts entries array from retrieve_relevant Hash response' do + result = described_class.query(question: 'legion', synthesize: false) + expect(result[:sources]).to be_an(Array) + expect(result[:sources].size).to eq(1) + end + + it 'does not raise no implicit conversion of Symbol into Integer' do + expect { described_class.query(question: 'legion', synthesize: false) }.not_to raise_error + end + end + end + describe '.record_feedback' do it 'returns success with question_hash' do result = described_class.record_feedback(