fix: captain liquid render file system (#13647)
This commit is contained in:
@@ -5,7 +5,7 @@ class Captain::PromptRenderer
|
|||||||
def render(template_name, context = {})
|
def render(template_name, context = {})
|
||||||
template = load_template(template_name)
|
template = load_template(template_name)
|
||||||
liquid_template = Liquid::Template.parse(template)
|
liquid_template = Liquid::Template.parse(template)
|
||||||
liquid_template.render(stringify_keys(context))
|
liquid_template.render(stringify_keys(context), registers: { file_system: snippet_file_system })
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -18,6 +18,13 @@ class Captain::PromptRenderer
|
|||||||
File.read(template_path)
|
File.read(template_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def snippet_file_system
|
||||||
|
@snippet_file_system ||= Liquid::LocalFileSystem.new(
|
||||||
|
Rails.root.join('enterprise/lib/captain/prompts/snippets'),
|
||||||
|
'%s.liquid'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def stringify_keys(hash)
|
def stringify_keys(hash)
|
||||||
hash.deep_stringify_keys
|
hash.deep_stringify_keys
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ Don't digress away from your instructions, and use all the available tools at yo
|
|||||||
Here's the metadata we have about the current conversation and the contact associated with it:
|
Here's the metadata we have about the current conversation and the contact associated with it:
|
||||||
|
|
||||||
{% if conversation -%}
|
{% if conversation -%}
|
||||||
{% render 'conversation' %}
|
{% render 'conversation', conversation: conversation %}
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
{% if contact -%}
|
{% if contact -%}
|
||||||
{% render 'contact' %}
|
{% render 'contact', contact: contact %}
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
{% if campaign.id -%}
|
{% if campaign.id -%}
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ If you believe the user's request is not within the scope of your role, you can
|
|||||||
Here's the metadata we have about the current conversation and the contact associated with it:
|
Here's the metadata we have about the current conversation and the contact associated with it:
|
||||||
|
|
||||||
{% if conversation -%}
|
{% if conversation -%}
|
||||||
{% render 'conversation' %}
|
{% render 'conversation', conversation: conversation %}
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
{% if contact -%}
|
{% if contact -%}
|
||||||
{% render 'contact' %}
|
{% render 'contact', contact: contact %}
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
{% if campaign.id -%}
|
{% if campaign.id -%}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ RSpec.describe Captain::PromptRenderer do
|
|||||||
it 'loads and parses liquid template' do
|
it 'loads and parses liquid template' do
|
||||||
liquid_template_double = instance_double(Liquid::Template)
|
liquid_template_double = instance_double(Liquid::Template)
|
||||||
allow(Liquid::Template).to receive(:parse).with(template_content).and_return(liquid_template_double)
|
allow(Liquid::Template).to receive(:parse).with(template_content).and_return(liquid_template_double)
|
||||||
allow(liquid_template_double).to receive(:render).with(hash_including('name', 'balance')).and_return('rendered')
|
allow(liquid_template_double).to receive(:render).with(hash_including('name', 'balance'), anything).and_return('rendered')
|
||||||
|
|
||||||
result = described_class.render(template_name, context)
|
result = described_class.render(template_name, context)
|
||||||
|
|
||||||
@@ -67,6 +67,36 @@ RSpec.describe Captain::PromptRenderer do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'snippet rendering' do
|
||||||
|
let(:snippets_dir) { Rails.root.join('enterprise/lib/captain/prompts/snippets') }
|
||||||
|
let(:snippet_path) { snippets_dir.join('greeting.liquid') }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(File).to receive(:exist?).and_call_original
|
||||||
|
allow(File).to receive(:read).and_call_original
|
||||||
|
allow(File).to receive(:exist?).with(template_path).and_return(true)
|
||||||
|
# Create a controlled snippet to decouple from real snippet content
|
||||||
|
allow(File).to receive(:exist?).with(snippet_path.to_s).and_return(true)
|
||||||
|
allow(File).to receive(:read).with(snippet_path.to_s).and_return('Hello {{ name }}')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'resolves render tags from the snippets directory' do
|
||||||
|
allow(File).to receive(:read).with(template_path).and_return("{% render 'greeting', name: name %}")
|
||||||
|
|
||||||
|
result = described_class.render(template_name, { name: 'World' })
|
||||||
|
|
||||||
|
expect(result).to eq('Hello World')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'outputs a liquid error for missing snippets' do
|
||||||
|
allow(File).to receive(:read).with(template_path).and_return("{% render 'nonexistent' %}")
|
||||||
|
|
||||||
|
result = described_class.render(template_name, {})
|
||||||
|
|
||||||
|
expect(result).to include('Liquid error')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '.load_template' do
|
describe '.load_template' do
|
||||||
it 'reads template file from correct path' do
|
it 'reads template file from correct path' do
|
||||||
described_class.send(:load_template, template_name)
|
described_class.send(:load_template, template_name)
|
||||||
|
|||||||
Reference in New Issue
Block a user