| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import fs from 'fs'; |
| import path from 'path'; |
| import type { PromptId, LoadedPrompt, SnippetId } from './types'; |
| import { createLogger } from '@/lib/logger'; |
| const log = createLogger('PromptLoader'); |
|
|
| |
| |
| |
| function getPromptsDir(): string { |
| |
| return path.join(process.cwd(), 'lib', 'prompts'); |
| } |
|
|
| |
| |
| |
| export function loadSnippet(snippetId: SnippetId): string { |
| const snippetPath = path.join(getPromptsDir(), 'snippets', `${snippetId}.md`); |
|
|
| try { |
| return fs.readFileSync(snippetPath, 'utf-8').trim(); |
| } catch { |
| |
| |
| throw new Error(`Snippet not found: ${snippetId}`); |
| } |
| } |
|
|
| |
| |
| |
| |
| export function processSnippets(template: string): string { |
| return template.replace(/\{\{snippet:(\w[\w-]*)\}\}/g, (_, snippetId) => { |
| return loadSnippet(snippetId as SnippetId); |
| }); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export function processConditionalBlocks( |
| template: string, |
| conditions: Record<string, unknown>, |
| ): string { |
| return template.replace( |
| /\{\{#if (\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g, |
| (_, conditionName: string, content: string) => { |
| return conditions[conditionName] ? content : ''; |
| }, |
| ); |
| } |
|
|
| |
| |
| |
| export function loadPrompt(promptId: PromptId): LoadedPrompt | null { |
| const promptDir = path.join(getPromptsDir(), 'templates', promptId); |
|
|
| try { |
| |
| const systemPath = path.join(promptDir, 'system.md'); |
| let systemPrompt = fs.readFileSync(systemPath, 'utf-8').trim(); |
| systemPrompt = processSnippets(systemPrompt); |
|
|
| |
| const userPath = path.join(promptDir, 'user.md'); |
| let userPromptTemplate = ''; |
| try { |
| userPromptTemplate = fs.readFileSync(userPath, 'utf-8').trim(); |
| userPromptTemplate = processSnippets(userPromptTemplate); |
| } catch { |
| |
| } |
|
|
| return { |
| id: promptId, |
| systemPrompt, |
| userPromptTemplate, |
| }; |
| } catch (error) { |
| log.error(`Failed to load prompt ${promptId}:`, error); |
| return null; |
| } |
| } |
|
|
| |
| |
| |
| |
| export function interpolateVariables(template: string, variables: Record<string, unknown>): string { |
| |
| |
| |
| |
| return template.replace(/\{\{(\w+)\}\}/g, (match, key) => { |
| const value = variables[key]; |
| if (value === undefined) return match; |
| if (typeof value === 'object') return JSON.stringify(value, null, 2); |
| return String(value); |
| }); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export function buildPrompt( |
| promptId: PromptId, |
| variables: Record<string, unknown>, |
| ): { system: string; user: string } | null { |
| const prompt = loadPrompt(promptId); |
| if (!prompt) return null; |
|
|
| return { |
| system: interpolateVariables( |
| processConditionalBlocks(prompt.systemPrompt, variables), |
| variables, |
| ), |
| user: interpolateVariables( |
| processConditionalBlocks(prompt.userPromptTemplate, variables), |
| variables, |
| ), |
| }; |
| } |
|
|