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

Inherits:
Object
  • Object
show all
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.



53
54
55
# File 'lib/legion/llm/skills/base.rb', line 53

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’ }‘



57
58
59
# File 'lib/legion/llm/skills/base.rb', line 57

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

.content(context: {}) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



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

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



16
17
18
# File 'lib/legion/llm/skills/base.rb', line 16

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

.file_change_trigger_patternsObject



45
46
47
# File 'lib/legion/llm/skills/base.rb', line 45

def file_change_trigger_patterns
  @file_change_trigger_patterns || []
end

.file_change_triggers(*patterns) ⇒ Object



41
42
43
# File 'lib/legion/llm/skills/base.rb', line 41

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



49
50
51
# File 'lib/legion/llm/skills/base.rb', line 49

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

.namespace(nsp = nil) ⇒ Object



24
25
26
# File 'lib/legion/llm/skills/base.rb', line 24

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

.skill_name(name = nil) ⇒ Object



12
13
14
# File 'lib/legion/llm/skills/base.rb', line 12

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

.steps(*names) ⇒ Object



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

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

.trigger(type = nil) ⇒ Object



20
21
22
# File 'lib/legion/llm/skills/base.rb', line 20

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

.trigger_words(*words) ⇒ Object



37
38
39
# File 'lib/legion/llm/skills/base.rb', line 37

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

.when_conditionsObject



61
62
63
# File 'lib/legion/llm/skills/base.rb', line 61

def when_conditions
  @when_conditions || {}
end

Instance Method Details

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



107
108
109
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
# File 'lib/legion/llm/skills/base.rb', line 107

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::ConversationStore.skill_cancelled?(conv_id)
      Legion::LLM::ConversationStore.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::ConversationStore.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