feat(captain-memory): add PromptInjectionService formatting memories as XML

This commit is contained in:
Rodribm10 2026-04-19 00:05:11 -03:00
parent e1273f142b
commit 5d15f55a29
2 changed files with 51 additions and 0 deletions

View File

@ -0,0 +1,21 @@
class Captain::ContactMemories::PromptInjectionService
def initialize(memories:)
@memories = memories
end
def call
return '' if @memories.blank?
lines = @memories.map do |memory|
%( <#{memory.memory_type} confidence="#{format('%.2f', memory.confidence)}">#{escape(memory.content)}</#{memory.memory_type}>)
end
"<memoria_cliente>\n#{lines.join("\n")}\n</memoria_cliente>"
end
private
def escape(text)
text.to_s.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;')
end
end

View File

@ -0,0 +1,30 @@
require 'rails_helper'
RSpec.describe Captain::ContactMemories::PromptInjectionService do
describe '#call' do
it 'returns empty string when memories empty' do
result = described_class.new(memories: []).call
expect(result).to eq('')
end
it 'formats memories as XML block' do
memories = [
build_stubbed(:captain_contact_memory, memory_type: 'preferencia', content: 'Prefere Stilo', confidence: 0.92),
build_stubbed(:captain_contact_memory, memory_type: 'data_comemorativa', content: 'Aniversário 14/02', confidence: 0.88)
]
result = described_class.new(memories: memories).call
expect(result).to include('<memoria_cliente>')
expect(result).to include('<preferencia confidence="0.92">Prefere Stilo</preferencia>')
expect(result).to include('<data_comemorativa confidence="0.88">Aniversário 14/02</data_comemorativa>')
expect(result).to include('</memoria_cliente>')
end
it 'escapes XML-unsafe chars in content' do
memories = [build_stubbed(:captain_contact_memory, content: 'texto com <tag> & ampersand')]
result = described_class.new(memories: memories).call
expect(result).to include('texto com &lt;tag&gt; &amp; ampersand')
end
end
end