Module: OllamaAgent::PromptSkills

Defined in:
lib/ollama_agent/prompt_skills.rb

Overview

Bundled Markdown skills under lib/ollama_agent/prompt_skills plus optional paths (env / Agent kwargs). rubocop:disable Metrics/ModuleLength – single cohesive loader; split only if it grows further

Constant Summary collapse

BUNDLED_DIR =
File.join(__dir__, "prompt_skills")
MANIFEST_PATH =
File.join(BUNDLED_DIR, "manifest.yml")

Class Method Summary collapse

Class Method Details

.bundled_enabled?(skills_enabled) ⇒ Boolean

rubocop:enable Metrics/ParameterLists

Returns:

  • (Boolean)


47
48
49
# File 'lib/ollama_agent/prompt_skills.rb', line 47

def bundled_enabled?(skills_enabled)
  truthy?(skills_enabled, default: true)
end

.bundled_text(skills_include: nil, skills_exclude: nil) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
# File 'lib/ollama_agent/prompt_skills.rb', line 72

def bundled_text(skills_include: nil, skills_exclude: nil)
  entries = manifest_entries
  return "" if entries.empty?

  filter_ids(entries, skills_include: skills_include, skills_exclude: skills_exclude).filter_map do |entry|
    body = read_skill_file(File.join(BUNDLED_DIR, entry.fetch("file")))
    next if body.empty?

    "## #{entry.fetch("id")}\n\n#{body}"
  end.join("\n\n---\n\n")
end

.compose(base:, skills_enabled: nil, skills_include: nil, skills_exclude: nil, skill_paths: nil, external_skills_enabled: nil) ⇒ Object

rubocop:disable Metrics/ParameterLists – mirrors Agent keyword surface



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/ollama_agent/prompt_skills.rb', line 34

def compose(base:, skills_enabled: nil, skills_include: nil, skills_exclude: nil,
            skill_paths: nil, external_skills_enabled: nil)
  parts = [base.to_s.strip]
  if bundled_enabled?(skills_enabled)
    bundled = bundled_text(skills_include: skills_include, skills_exclude: skills_exclude)
    parts << bundled unless bundled.empty?
  end
  ext = external_text(skill_paths: skill_paths, external_skills_enabled: external_skills_enabled)
  parts << ext unless ext.empty?
  parts.reject(&:empty?).join("\n\n---\n\n")
end

.env_truthy(env_key, default: true) ⇒ Object



134
135
136
137
138
139
# File 'lib/ollama_agent/prompt_skills.rb', line 134

def env_truthy(env_key, default: true)
  raw = ENV.fetch(env_key, nil)
  return default if raw.nil? || raw.to_s.strip.empty?

  parse_string_truthy(raw.to_s, default: default)
end

.external_enabled?(external_skills_enabled) ⇒ Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/ollama_agent/prompt_skills.rb', line 51

def external_enabled?(external_skills_enabled)
  truthy?(external_skills_enabled, default: true)
end

.external_text(skill_paths: nil, external_skills_enabled: nil) ⇒ Object



55
56
57
58
59
60
61
# File 'lib/ollama_agent/prompt_skills.rb', line 55

def external_text(skill_paths: nil, external_skills_enabled: nil)
  return "" unless external_enabled?(external_skills_enabled)

  merged = merge_skill_paths(skill_paths)
  bodies = merged.flat_map { |segment| bodies_for_path_segment(segment) }
  bodies.reject(&:empty?).join("\n\n---\n\n")
end

.filter_ids(entries, skills_include: nil, skills_exclude: nil) ⇒ Object

rubocop:disable Metrics/AbcSize – straightforward filter + optional reorder



142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/ollama_agent/prompt_skills.rb', line 142

def filter_ids(entries, skills_include: nil, skills_exclude: nil)
  include_list = parse_id_list(skills_include)
  exclude_ids = parse_id_list(skills_exclude) || []

  ordered = entries.dup
  if include_list
    id_index = include_list.each_with_index.to_h
    ordered = ordered.select { |e| id_index.key?(e.fetch("id").downcase) }
    ordered.sort_by! { |e| id_index[e.fetch("id").downcase] }
  end

  ordered.reject { |e| exclude_ids.include?(e.fetch("id").downcase) }
end

.manifest_entriesObject

rubocop:enable Metrics/AbcSize



157
158
159
160
161
162
163
164
165
166
# File 'lib/ollama_agent/prompt_skills.rb', line 157

def manifest_entries
  return [] unless File.file?(MANIFEST_PATH)

  data = YAML.safe_load(
    File.read(MANIFEST_PATH, encoding: Encoding::UTF_8),
    permitted_classes: [],
    aliases: true
  )
  Array(data&.fetch("skills", nil))
end

.merge_skill_paths(paths) ⇒ Object



84
85
86
87
88
89
90
91
92
93
# File 'lib/ollama_agent/prompt_skills.rb', line 84

def merge_skill_paths(paths)
  env = split_paths(ENV.fetch("OLLAMA_AGENT_SKILL_PATHS", nil))
  extra =
    case paths
    when nil then []
    when Array then paths.compact.map(&:to_s)
    else split_paths(paths.to_s)
    end
  (env + extra).uniq
end

.parse_id_list(raw) ⇒ Object



125
126
127
128
129
130
131
132
# File 'lib/ollama_agent/prompt_skills.rb', line 125

def parse_id_list(raw)
  return nil if raw.nil?

  s = raw.to_s.strip
  return nil if s.empty?

  s.split(",").map(&:strip).reject(&:empty?).map(&:downcase)
end

.parse_string_truthy(str, default:) ⇒ Object



115
116
117
118
119
120
121
122
123
# File 'lib/ollama_agent/prompt_skills.rb', line 115

def parse_string_truthy(str, default:)
  s = str.strip.downcase
  return default if s.empty?

  return false if %w[0 false no off].include?(s)
  return true if %w[1 true yes on].include?(s)

  default
end

.read_skill_file(path) ⇒ Object



27
28
29
30
31
# File 'lib/ollama_agent/prompt_skills.rb', line 27

def read_skill_file(path)
  strip_frontmatter(File.read(path, encoding: Encoding::UTF_8))
rescue Errno::ENOENT
  ""
end

.split_paths(raw) ⇒ Object



95
96
97
98
99
100
101
102
# File 'lib/ollama_agent/prompt_skills.rb', line 95

def split_paths(raw)
  return [] if raw.nil?

  s = raw.to_s.strip
  return [] if s.empty?

  s.split(File::PATH_SEPARATOR).map(&:strip).reject(&:empty?)
end

.strip_frontmatter(text) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/ollama_agent/prompt_skills.rb', line 14

def strip_frontmatter(text)
  return "" if text.nil?

  s = text.to_s
  lines = s.lines
  return s unless lines.first&.strip == "---"

  closing = (1...lines.size).find { |i| lines[i].strip == "---" }
  return s if closing.nil?

  lines[(closing + 1)..].join.lstrip
end

.truthy?(value, default:) ⇒ Boolean

Returns:

  • (Boolean)


104
105
106
107
108
109
110
111
112
113
# File 'lib/ollama_agent/prompt_skills.rb', line 104

def truthy?(value, default:)
  return default if value.nil?

  case value
  when true then true
  when false then false
  else
    parse_string_truthy(value.to_s, default: default)
  end
end