feat: add prompt template system for LLM variable substitution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { PromptTemplate, renderTemplate } from '../promptTemplate.js';
|
||||
|
||||
describe('promptTemplate', () => {
|
||||
it('renders a template with variable substitution', () => {
|
||||
const template: PromptTemplate = {
|
||||
name: 'test',
|
||||
systemPrompt: 'You are a narrator for {{setting}}.',
|
||||
userPrompt: '{{npcName}} is feeling {{mood}}. Describe their thoughts.',
|
||||
};
|
||||
const result = renderTemplate(template, {
|
||||
setting: 'a medieval village',
|
||||
npcName: 'Elara',
|
||||
mood: 'anxious',
|
||||
});
|
||||
expect(result.system).toBe('You are a narrator for a medieval village.');
|
||||
expect(result.user).toBe('Elara is feeling anxious. Describe their thoughts.');
|
||||
});
|
||||
|
||||
it('leaves unmatched variables as-is', () => {
|
||||
const template: PromptTemplate = {
|
||||
name: 'test',
|
||||
systemPrompt: 'Hello {{name}}, welcome to {{place}}.',
|
||||
userPrompt: '',
|
||||
};
|
||||
const result = renderTemplate(template, { name: 'Brynn' });
|
||||
expect(result.system).toBe('Hello Brynn, welcome to {{place}}.');
|
||||
});
|
||||
|
||||
it('handles empty variables object', () => {
|
||||
const template: PromptTemplate = {
|
||||
name: 'test',
|
||||
systemPrompt: 'No vars here.',
|
||||
userPrompt: 'Also none.',
|
||||
};
|
||||
const result = renderTemplate(template, {});
|
||||
expect(result.system).toBe('No vars here.');
|
||||
expect(result.user).toBe('Also none.');
|
||||
});
|
||||
|
||||
it('replaces multiple occurrences of same variable', () => {
|
||||
const template: PromptTemplate = {
|
||||
name: 'test',
|
||||
systemPrompt: '{{name}} meets {{name}}.',
|
||||
userPrompt: '',
|
||||
};
|
||||
const result = renderTemplate(template, { name: 'Thom' });
|
||||
expect(result.system).toBe('Thom meets Thom.');
|
||||
});
|
||||
|
||||
it('handles multiline templates', () => {
|
||||
const template: PromptTemplate = {
|
||||
name: 'test',
|
||||
systemPrompt: 'Line 1: {{a}}\nLine 2: {{b}}',
|
||||
userPrompt: '{{c}}',
|
||||
};
|
||||
const result = renderTemplate(template, { a: 'x', b: 'y', c: 'z' });
|
||||
expect(result.system).toBe('Line 1: x\nLine 2: y');
|
||||
expect(result.user).toBe('z');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
export interface PromptTemplate {
|
||||
name: string;
|
||||
systemPrompt: string;
|
||||
userPrompt: string;
|
||||
}
|
||||
|
||||
export interface RenderedPrompt {
|
||||
system: string;
|
||||
user: string;
|
||||
}
|
||||
|
||||
export function renderTemplate(
|
||||
template: PromptTemplate,
|
||||
variables: Record<string, string>,
|
||||
): RenderedPrompt {
|
||||
let system = template.systemPrompt;
|
||||
let user = template.userPrompt;
|
||||
|
||||
for (const [key, value] of Object.entries(variables)) {
|
||||
const pattern = `{{${key}}}`;
|
||||
system = system.replaceAll(pattern, value);
|
||||
user = user.replaceAll(pattern, value);
|
||||
}
|
||||
|
||||
return { system, user };
|
||||
}
|
||||
Reference in New Issue
Block a user