feat: add prompt template system for LLM variable substitution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-03-08 16:17:56 +00:00
parent 98ec288caf
commit 5f5bf24d64
2 changed files with 87 additions and 0 deletions
@@ -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');
});
});
+26
View File
@@ -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 };
}