lex-knowledge 0.5.0 → 0.6.0

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: 8d512db91b31e6d8a9747a3987aa90dd406d04f8987400787f6de27b13eb10c5
4
- data.tar.gz: 2d9df5e1289bb80f603dbd882863d1802bf942e8ff12940d259ba44e25b728f3
3
+ metadata.gz: 93e36e27a559476697a65f659e5c5a21db2e061b40877db6ea467875642d3232
4
+ data.tar.gz: dfae368bcc8db4eba0c6b41da9bb79537ed3a9b4fd898b189905fb1ca58a6bc7
5
5
  SHA512:
6
- metadata.gz: 2022e4654a3a815e8c5433daaad7c2e9767b039c51513e12d9cd6c71a2de47e3ee883c6e0624aa9ac8f6108439c19d4552260694482db4e2da9d58851fa093bd
7
- data.tar.gz: d1afc8cb8fdcd0317ee9fa416c91827ca3536e40fed404791a355b4b4662360211e3c064dc09e8504d0ed5eb359f1dc906edaa57277f205b1aa9eafedcf261da
6
+ metadata.gz: c9d11bdbcc27f14431c6e900c703a02cea7389bf2220c6e8c2fb1c920a97d7a86993d11e207453ef79ab928da68629a98aa711d51d009dd04d1f5215337dc4a6
7
+ data.tar.gz: 9fe9dc96f91a19aca0d58b4ad49abbcf0876797bba5ddea6984cff0d51b7a577ce0f165fa8d54d9271b185da84d6a267d7c9883903e99937f7b084454b1affcc
@@ -21,23 +21,21 @@ module Legion
21
21
  end
22
22
 
23
23
  def enabled?
24
- corpus_path && !corpus_path.empty?
24
+ resolve_monitors.any?
25
25
  rescue StandardError
26
26
  false
27
27
  end
28
28
 
29
29
  def args
30
- { path: corpus_path }
30
+ { monitors: resolve_monitors }
31
31
  end
32
32
 
33
33
  private
34
34
 
35
- def corpus_path
36
- return nil unless defined?(Legion::Settings) && !Legion::Settings[:knowledge].nil?
37
-
38
- Legion::Settings.dig(:knowledge, :corpus_path)
35
+ def resolve_monitors
36
+ Runners::Monitor.resolve_monitors
39
37
  rescue StandardError
40
- nil
38
+ []
41
39
  end
42
40
  end
43
41
  end
@@ -8,6 +8,7 @@ module Legion
8
8
  include Runners::Query
9
9
  include Runners::Corpus
10
10
  include Runners::Maintenance
11
+ include Runners::Monitor
11
12
  end
12
13
  end
13
14
  end
@@ -22,7 +22,16 @@ module Legion
22
22
  }
23
23
  end
24
24
 
25
- def ingest_corpus(path:, dry_run: false, force: false)
25
+ def ingest_corpus(path: nil, monitors: nil, dry_run: false, force: false)
26
+ return ingest_monitors(monitors: monitors, dry_run: dry_run, force: force) if monitors&.any?
27
+ raise ArgumentError, 'path is required when monitors is not provided' if path.nil?
28
+
29
+ ingest_corpus_path(path: path, dry_run: dry_run, force: force)
30
+ rescue ArgumentError => e
31
+ { success: false, error: e.message }
32
+ end
33
+
34
+ def ingest_corpus_path(path:, dry_run: false, force: false)
26
35
  current = Helpers::Manifest.scan(path: path)
27
36
  previous = force ? [] : Helpers::ManifestStore.load(corpus_path: path)
28
37
  delta = Helpers::Manifest.diff(current: current, previous: previous)
@@ -56,6 +65,35 @@ module Legion
56
65
  rescue StandardError => e
57
66
  { success: false, error: e.message }
58
67
  end
68
+ private_class_method :ingest_corpus_path
69
+
70
+ def ingest_monitors(monitors:, dry_run: false, force: false)
71
+ results = monitors.map do |monitor|
72
+ ingest_corpus(path: monitor[:path], dry_run: dry_run, force: force)
73
+ rescue StandardError => e
74
+ { success: false, path: monitor[:path], error: e.message }
75
+ end
76
+
77
+ total = {
78
+ files_scanned: 0,
79
+ files_added: 0,
80
+ files_changed: 0,
81
+ files_removed: 0,
82
+ chunks_created: 0,
83
+ chunks_skipped: 0,
84
+ chunks_updated: 0
85
+ }
86
+ results.each do |r|
87
+ next unless r[:success]
88
+
89
+ total.each_key { |k| total[k] += r[k].to_i }
90
+ end
91
+
92
+ { success: true, monitors_processed: results.size, **total }
93
+ rescue StandardError => e
94
+ { success: false, error: e.message }
95
+ end
96
+ private_class_method :ingest_monitors
59
97
 
60
98
  def ingest_file(file_path:, force: false)
61
99
  result = process_file(file_path, dry_run: false, force: force)
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Knowledge
6
+ module Runners
7
+ module Monitor
8
+ module_function
9
+
10
+ DEFAULT_EXTENSIONS = %w[.md .txt].freeze
11
+
12
+ def resolve_monitors
13
+ monitors = Array(read_monitors_setting)
14
+ legacy = read_legacy_corpus_path
15
+
16
+ if legacy && !legacy.empty? && monitors.none? { |m| m[:path] == legacy }
17
+ monitors << { path: legacy, extensions: %w[.md .txt .docx .pdf], label: 'legacy' }
18
+ end
19
+
20
+ monitors
21
+ rescue StandardError
22
+ []
23
+ end
24
+
25
+ def add_monitor(path:, extensions: nil, label: nil)
26
+ abs_path = File.expand_path(path)
27
+ return { success: false, error: "Path #{abs_path} does not exist or is not a directory" } unless File.directory?(abs_path)
28
+
29
+ existing = Array(read_monitors_setting)
30
+ return { success: false, error: "Path #{abs_path} is already registered" } if existing.any? { |m| m[:path] == abs_path }
31
+
32
+ entry = {
33
+ path: abs_path,
34
+ extensions: extensions || DEFAULT_EXTENSIONS.dup,
35
+ label: label || File.basename(abs_path),
36
+ added_at: Time.now.utc.iso8601
37
+ }
38
+
39
+ existing << entry
40
+ persist_monitors(existing)
41
+
42
+ { success: true, monitor: entry }
43
+ rescue StandardError => e
44
+ { success: false, error: e.message }
45
+ end
46
+
47
+ def remove_monitor(identifier:)
48
+ existing = Array(read_monitors_setting)
49
+ found = existing.find { |m| m[:path] == identifier || m[:label] == identifier }
50
+ return { success: false, error: "Monitor '#{identifier}' not found" } unless found
51
+
52
+ existing.delete(found)
53
+ persist_monitors(existing)
54
+
55
+ { success: true, removed: found }
56
+ rescue StandardError => e
57
+ { success: false, error: e.message }
58
+ end
59
+
60
+ def list_monitors
61
+ { success: true, monitors: resolve_monitors }
62
+ rescue StandardError => e
63
+ { success: false, error: e.message }
64
+ end
65
+
66
+ def monitor_status
67
+ monitors = resolve_monitors
68
+ total_files = 0
69
+
70
+ monitors.each do |m|
71
+ scan = Helpers::Manifest.scan(path: m[:path], extensions: m[:extensions])
72
+ total_files += scan.size
73
+ rescue StandardError
74
+ next
75
+ end
76
+
77
+ { success: true, total_monitors: monitors.size, total_files: total_files }
78
+ rescue StandardError => e
79
+ { success: false, error: e.message }
80
+ end
81
+
82
+ # --- private helpers ---
83
+
84
+ def read_monitors_setting
85
+ return nil unless defined?(Legion::Settings) && !Legion::Settings[:knowledge].nil?
86
+
87
+ Legion::Settings.dig(:knowledge, :monitors)
88
+ rescue StandardError
89
+ nil
90
+ end
91
+ private_class_method :read_monitors_setting
92
+
93
+ def read_legacy_corpus_path
94
+ return nil unless defined?(Legion::Settings) && !Legion::Settings[:knowledge].nil?
95
+
96
+ Legion::Settings.dig(:knowledge, :corpus_path)
97
+ rescue StandardError
98
+ nil
99
+ end
100
+ private_class_method :read_legacy_corpus_path
101
+
102
+ def persist_monitors(monitors)
103
+ return false unless defined?(Legion::Settings)
104
+
105
+ loader = Legion::Settings.loader
106
+ knowledge = loader.settings[:knowledge] || {}
107
+ knowledge[:monitors] = monitors
108
+ loader.settings[:knowledge] = knowledge
109
+ true
110
+ rescue StandardError
111
+ false
112
+ end
113
+ private_class_method :persist_monitors
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Knowledge
6
+ module Transport
7
+ module Messages
8
+ class MonitorReload < Legion::Transport::Message
9
+ def exchange_name = 'knowledge'
10
+ def routing_key = 'knowledge.monitor.reload'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Knowledge
6
- VERSION = '0.5.0'
6
+ VERSION = '0.6.0'
7
7
  end
8
8
  end
9
9
  end
@@ -9,12 +9,14 @@ require_relative 'knowledge/runners/ingest'
9
9
  require_relative 'knowledge/runners/query'
10
10
  require_relative 'knowledge/runners/corpus'
11
11
  require_relative 'knowledge/runners/maintenance'
12
+ require_relative 'knowledge/runners/monitor'
12
13
  require_relative 'knowledge/client'
13
14
 
14
15
  if defined?(Legion::Transport)
15
16
  require_relative 'knowledge/transport/exchanges/knowledge'
16
17
  require_relative 'knowledge/transport/queues/ingest'
17
18
  require_relative 'knowledge/transport/messages/ingest_message'
19
+ require_relative 'knowledge/transport/messages/monitor_reload'
18
20
  end
19
21
 
20
22
  require_relative 'knowledge/actors/corpus_watcher' if defined?(Legion::Extensions::Actors::Every)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-knowledge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Iverson
@@ -127,9 +127,11 @@ files:
127
127
  - lib/legion/extensions/knowledge/runners/corpus.rb
128
128
  - lib/legion/extensions/knowledge/runners/ingest.rb
129
129
  - lib/legion/extensions/knowledge/runners/maintenance.rb
130
+ - lib/legion/extensions/knowledge/runners/monitor.rb
130
131
  - lib/legion/extensions/knowledge/runners/query.rb
131
132
  - lib/legion/extensions/knowledge/transport/exchanges/knowledge.rb
132
133
  - lib/legion/extensions/knowledge/transport/messages/ingest_message.rb
134
+ - lib/legion/extensions/knowledge/transport/messages/monitor_reload.rb
133
135
  - lib/legion/extensions/knowledge/transport/queues/ingest.rb
134
136
  - lib/legion/extensions/knowledge/version.rb
135
137
  homepage: https://github.com/LegionIO/lex-knowledge