Class: Legion::Extensions::Apollo::Actor::EntityWatchdog

Inherits:
Legion::Extensions::Actors::Every
  • Object
show all
Includes:
Runners::EntityExtractor, Runners::Knowledge
Defined in:
lib/legion/extensions/apollo/actors/entity_watchdog.rb

Constant Summary collapse

DEDUP_THRESHOLD_DEFAULT =
0.92
TASK_LOG_LOOKBACK_SECONDS =
300
TASK_LOG_LIMIT =
50

Constants included from Runners::EntityExtractor

Runners::EntityExtractor::DEFAULT_ENTITY_TYPES, Runners::EntityExtractor::DEFAULT_MIN_CONFIDENCE

Constants included from Runners::Knowledge

Runners::Knowledge::DOMAIN_ISOLATION

Instance Method Summary collapse

Methods included from Runners::EntityExtractor

#entity_extraction_prompt, #entity_schema, #extract_entities

Methods included from Runners::Knowledge

#deprecate_entry, #handle_erasure_request, #handle_ingest, #handle_query, #handle_traverse, #prepare_mesh_export, #query_knowledge, #redistribute_knowledge, #related_entries, #retrieve_relevant, #store_knowledge

Instance Method Details

#check_subtask?Boolean

Returns:

  • (Boolean)


24
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 24

def check_subtask?  = false

#dedup_similarity_thresholdObject



127
128
129
130
131
132
133
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 127

def dedup_similarity_threshold
  if defined?(Legion::Settings)
    val = Legion::Settings.dig(:apollo, :entity_watchdog, :dedup_threshold)
    return val.to_f if val
  end
  DEDUP_THRESHOLD_DEFAULT
end

#enabled?Boolean

rubocop:disable Legion/Extension/ActorEnabledSideEffects

Returns:

  • (Boolean)


27
28
29
30
31
32
33
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 27

def enabled? # rubocop:disable Legion/Extension/ActorEnabledSideEffects
  defined?(Legion::Extensions::Apollo::Runners::EntityExtractor) &&
    Legion.const_defined?(:Transport, false)
rescue StandardError => e
  log.warn("EntityWatchdog enabled? check failed: #{e.message}")
  false
end

#entity_exists_in_apollo?(entity) ⇒ Boolean

Returns:

  • (Boolean)


80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 80

def entity_exists_in_apollo?(entity)
  result = retrieve_relevant(
    query:          entity[:name].to_s,
    limit:          1,
    min_confidence: Helpers::Confidence.apollo_setting(:entity_watchdog, :exists_min_confidence, default: 0.1),
    tags:           [entity[:type].to_s]
  )
  return false unless result[:success] && result[:count].positive?

  closest = result[:entries].first
  distance = closest[:distance].to_f
  distance <= (1.0 - dedup_similarity_threshold)
rescue StandardError => e
  log.warn("EntityWatchdog entity_exists_in_apollo? failed: #{e.message}")
  false
end

#entity_typesObject



111
112
113
114
115
116
117
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 111

def entity_types
  if defined?(Legion::Settings)
    types = Legion::Settings.dig(:apollo, :entity_watchdog, :types)
    return Array(types).map(&:to_s) if types
  end
  %w[person service repository concept]
end

#generate_task?Boolean

Returns:

  • (Boolean)


25
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 25

def generate_task?  = false

#min_entity_confidenceObject



119
120
121
122
123
124
125
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 119

def min_entity_confidence
  if defined?(Legion::Settings)
    val = Legion::Settings.dig(:apollo, :entity_watchdog, :min_confidence)
    return val.to_f if val
  end
  0.7
end

#publish_entity_ingest(entity) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 97

def publish_entity_ingest(entity)
  return unless defined?(Legion::Extensions::Apollo::Transport::Messages::Ingest)

  Legion::Extensions::Apollo::Transport::Messages::Ingest.new(
    content:      "#{entity[:type].to_s.capitalize}: #{entity[:name]}",
    content_type: 'concept',
    tags:         [entity[:type].to_s, 'entity_watchdog'],
    source_agent: 'lex-apollo:entity_watchdog',
    context:      { entity_type: entity[:type], original_name: entity[:name] }
  ).publish
rescue StandardError => e
  log.error("EntityWatchdog publish failed: #{e.message}")
end

#recent_task_log_textsObject



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 63

def recent_task_log_texts
  return [] unless defined?(Legion::Data) && defined?(Legion::Data::Model::TaskLog)

  lookback = (defined?(Legion::Settings) && Legion::Settings.dig(:apollo, :entity_watchdog, :lookback_seconds)) || TASK_LOG_LOOKBACK_SECONDS
  log_limit = (defined?(Legion::Settings) && Legion::Settings.dig(:apollo, :entity_watchdog, :log_limit)) || TASK_LOG_LIMIT
  cutoff = Time.now - lookback
  logs = Legion::Data::Model::TaskLog
         .where { created_at >= cutoff }
         .order(Sequel.desc(:created_at))
         .limit(log_limit)
         .select_map(:message)
  logs.map(&:to_s).reject(&:empty?).uniq
rescue StandardError => e
  log.warn("EntityWatchdog recent_task_log_texts failed: #{e.message}")
  []
end

#run_now?Boolean

Returns:

  • (Boolean)


22
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 22

def run_now?        = false

#runner_classObject



19
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 19

def runner_class    = self.class

#runner_functionObject



20
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 20

def runner_function = 'scan_and_ingest'

#scan_and_ingestObject



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 35

def scan_and_ingest
  texts = recent_task_log_texts
  return { success: true, ingested: 0, reason: :no_logs } if texts.empty?

  ingested = 0
  texts.each do |text|
    result = extract_entities(
      text:           text,
      entity_types:   entity_types,
      min_confidence: min_entity_confidence
    )
    next unless result[:success]

    result[:entities].each do |entity|
      next if entity_exists_in_apollo?(entity)

      publish_entity_ingest(entity)
      ingested += 1
    end
  end

  log.debug("EntityWatchdog: ingested #{ingested} new entities from #{texts.size} log entries")
  { success: true, ingested: ingested, logs_scanned: texts.size }
rescue StandardError => e
  log.error("EntityWatchdog scan_and_ingest failed: #{e.message}")
  { success: false, error: e.message }
end

#timeObject



21
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 21

def time            = (defined?(Legion::Settings) && Legion::Settings.dig(:apollo, :actors, :entity_watchdog_interval)) || 120

#use_runner?Boolean

Returns:

  • (Boolean)


23
# File 'lib/legion/extensions/apollo/actors/entity_watchdog.rb', line 23

def use_runner?     = false