Class: Legion::LLM::Skills::Base

Inherits:
Object
  • Object
show all
Extended by:
Legion::Logging::Helper
Defined in:
lib/legion/llm/skills/base.rb

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.follows_skillObject (readonly)

Returns the value of attribute follows_skill.



55
56
57
# File 'lib/legion/llm/skills/base.rb', line 55

def follows_skill
  @follows_skill
end

Class Method Details

.condition(**conds) ⇒ Object

‘condition` is used instead of `when` because `when` is a Ruby reserved keyword. DSL: `condition classification: { level: ’internal’ }‘



59
60
61
# File 'lib/legion/llm/skills/base.rb', line 59

def condition(**conds)
  @when_conditions = conds
end

.content(context: {}) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



67
68
69
70
71
72
# File 'lib/legion/llm/skills/base.rb', line 67

def content(context: {}) # rubocop:disable Lint/UnusedMethodArgument
  path = content_path
  return ::File.read(path) if path && ::File.exist?(path)

  generate_content_from_step_names
end

.description(text = nil) ⇒ Object



18
19
20
# File 'lib/legion/llm/skills/base.rb', line 18

def description(text = nil)
  text ? (@description = text) : @description
end

.file_change_trigger_patternsObject



47
48
49
# File 'lib/legion/llm/skills/base.rb', line 47

def file_change_trigger_patterns
  @file_change_trigger_patterns || []
end

.file_change_triggers(*patterns) ⇒ Object



43
44
45
# File 'lib/legion/llm/skills/base.rb', line 43

def file_change_triggers(*patterns)
  patterns.any? ? (@file_change_trigger_patterns = patterns.map(&:to_s)) : (@file_change_trigger_patterns || [])
end

.follows(skill_key = nil) ⇒ Object



51
52
53
# File 'lib/legion/llm/skills/base.rb', line 51

def follows(skill_key = nil)
  skill_key ? (@follows_skill = skill_key.to_s) : @follows_skill
end

.namespace(nsp = nil) ⇒ Object



26
27
28
# File 'lib/legion/llm/skills/base.rb', line 26

def namespace(nsp = nil)
  nsp ? (@namespace = nsp.to_s) : @namespace
end

.skill_name(name = nil) ⇒ Object



14
15
16
# File 'lib/legion/llm/skills/base.rb', line 14

def skill_name(name = nil)
  name ? (@skill_name = name.to_s) : @skill_name
end

.steps(*names) ⇒ Object



30
31
32
33
34
35
36
37
# File 'lib/legion/llm/skills/base.rb', line 30

def steps(*names)
  if names.any?
    @steps = names
    validate_steps!
  else
    @steps || []
  end
end

.trigger(type = nil) ⇒ Object



22
23
24
# File 'lib/legion/llm/skills/base.rb', line 22

def trigger(type = nil)
  type ? (@trigger = type) : (@trigger || :on_demand)
end

.trigger_words(*words) ⇒ Object



39
40
41
# File 'lib/legion/llm/skills/base.rb', line 39

def trigger_words(*words)
  words.any? ? (@trigger_words_list = words.map(&:to_s)) : (@trigger_words_list || [])
end

.when_conditionsObject



63
64
65
# File 'lib/legion/llm/skills/base.rb', line 63

def when_conditions
  @when_conditions || {}
end

Instance Method Details

#run(from_step: 0, context: {}) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/legion/llm/skills/base.rb', line 110

def run(from_step: 0, context: {})
  inject_parts   = []
  total_duration = 0
  classification = context[:classification]
  conv_id        = context[:conversation_id]
  self_key       = "#{self.class.namespace}:#{self.class.skill_name}"

  emit_event(conv_id, 'skill.started',
             skill_name: self.class.skill_name, namespace: self.class.namespace,
             total_steps: self.class.steps.length)

  remaining_steps = self.class.steps[from_step..] || []

  remaining_steps.each_with_index do |method_name, offset|
    step_idx = from_step + offset
    if conv_id && Legion::LLM::Inference::Conversation.skill_cancelled?(conv_id)
      Legion::LLM::Inference::Conversation.clear_cancel_flag(conv_id)
      return SkillRunResult.build(inject: inject_parts.join("\n\n"),
                                  gated: false, gate: nil, resume_at: nil, complete: false)
    end

    result, duration_ms = execute_step(method_name, step_idx, context, conv_id, classification)
    total_duration += duration_ms
    inject_parts << result.inject if result.inject

    emit_step_success(conv_id, method_name, step_idx, duration_ms, result, classification)

    next unless result.gate

    if conv_id
      Legion::LLM::Inference::Conversation.set_skill_state(
        conv_id, skill_key: self_key, resume_at: step_idx + 1
      )
    end
    emit_event(conv_id, 'skill.step.gated',
               step_name: method_name, gate_type: result.gate)
    return SkillRunResult.build(
      inject: inject_parts.join("\n\n"), gated: true,
      gate: result.gate, resume_at: step_idx + 1, complete: false
    )
  end

  finalize_run(conv_id, self_key, inject_parts, total_duration, context)
end