Class: RubyLLM::Template::Loader

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_llm/template/loader.rb

Constant Summary collapse

SUPPORTED_ROLES =
%w[system user assistant schema].freeze

Instance Method Summary collapse

Constructor Details

#initialize(template_name, template_directory: nil) ⇒ Loader

Returns a new instance of Loader.



17
18
19
20
21
# File 'lib/ruby_llm/template/loader.rb', line 17

def initialize(template_name, template_directory: nil)
  @template_name = template_name.to_s
  @template_directory = Pathname.new(template_directory || RubyLLM::Template.configuration.template_directory)
  @template_path = @template_directory.join(@template_name)
end

Instance Method Details

#available_roles ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/ruby_llm/template/loader.rb', line 47

def available_roles
  return [] unless Dir.exist?(@template_path)

  roles = []

  # Check for ERB templates (excluding schema.txt.erb)
  Dir.glob("*.txt.erb", base: @template_path).each do |file|
    role = File.basename(file, ".txt.erb")
    next if role == "schema" # Skip schema.txt.erb files
    roles << role if SUPPORTED_ROLES.include?(role)
  end

  # Check for schema.rb file
  if File.exist?(@template_path.join("schema.rb"))
    roles << "schema" unless roles.include?("schema")
  end

  roles.uniq
end

#load_schema_class(context = {}) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/ruby_llm/template/loader.rb', line 71

def load_schema_class(context = {})
  schema_file = @template_path.join("schema.rb")
  return nil unless File.exist?(schema_file)
  return nil unless defined?(RubyLLM::Schema)

  schema_content = File.read(schema_file)
  schema_context = create_schema_context(context)

  # Evaluate the schema file
  result = schema_context.instance_eval(schema_content, schema_file.to_s)

  # Handle different patterns:
  # 1. RubyLLM::Schema.create { } pattern - returns instance
  if result.is_a?(RubyLLM::Schema) || result.respond_to?(:to_json_schema)
    return result
  end

  # 2. Class definition pattern - look for TemplateClass::Schema
  template_class_name = @template_name.to_s.split("_").map(&:capitalize).join
  schema_class_name = "#{template_class_name}::Schema"

  schema_class = constantize_safe(schema_class_name)
  return schema_class if schema_class

  raise Error, "Schema file must return a RubyLLM::Schema instance or define class '#{schema_class_name}'"
rescue => e
  raise Error, "Failed to load schema from '#{@template_name}/schema.rb': #{e.message}"
end

#render_template(role, context = {}) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/ruby_llm/template/loader.rb', line 23

def render_template(role, context = {})
  return nil unless SUPPORTED_ROLES.include?(role.to_s)

  # Handle schema role specially - only support .rb files
  if role.to_s == "schema"
    return render_schema_template(context)
  end

  # Handle regular ERB template
  file_name = "#{role}.txt.erb"
  template_file = @template_path.join(file_name)

  return nil unless File.exist?(template_file)

  template_content = File.read(template_file)
  erb = ERB.new(template_content)

  # Create a binding with the context variables
  binding_context = create_binding_context(context)
  erb.result(binding_context)
rescue => e
  raise Error, "Failed to render template '#{@template_name}/#{file_name}': #{e.message}"
end

#template_exists? ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/ruby_llm/template/loader.rb', line 67

def template_exists?
  Dir.exist?(@template_path) && !available_roles.empty?
end