prompt-version-manager
Version:
Centralized prompt management system for Human Behavior AI agents
211 lines • 7.4 kB
JavaScript
;
/**
* Simplified prompt loading and rendering for TypeScript
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.prompts = prompts;
exports.getCurrentPromptFile = getCurrentPromptFile;
exports.getParentExecutionId = getParentExecutionId;
exports.clearPromptContext = clearPromptContext;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const yaml = __importStar(require("js-yaml"));
// Global state for tracking current prompt file
let currentPromptFile;
// Global state for tracking parent execution ID from ModelResponse
let parentExecutionId;
/**
* Load and render a prompt template with positional variables.
*
* Variables are matched to {{variable}} placeholders in order of appearance.
*
* @param templateName - Name of the template file (with or without .md extension)
* @param variables - List of values to substitute in order of appearance
* @returns Rendered prompt string
*
* @example
* // If template has {{role}} and {{task}}
* const prompt = prompts("assistant.md", ["expert", "analyze data"]);
*/
function prompts(templateName, variables) {
// Find .pvm directory
const pvmDir = findPvmDirectory();
if (!pvmDir) {
throw new Error("No .pvm directory found. Run 'pvm init' first.");
}
// Ensure template name has .md extension
if (!templateName.endsWith('.md')) {
templateName += '.md';
}
// Load template file
const templatePath = path.join(pvmDir, 'prompts', templateName);
if (!fs.existsSync(templatePath)) {
throw new Error(`Template not found: ${templatePath}`);
}
const content = fs.readFileSync(templatePath, 'utf-8');
// Parse frontmatter and template
const { templateContent } = parseTemplate(content);
// Extract variables in order of appearance
const variableNames = extractVariables(templateContent);
// Create variable mapping
if (variables.length !== variableNames.length) {
throw new Error(`Expected ${variableNames.length} variables ${JSON.stringify(variableNames)}, ` +
`but got ${variables.length} values`);
}
// Process variables and detect ModelResponse objects
const processedVariables = [];
parentExecutionId = undefined; // Reset parent ID
for (const variable of variables) {
// Check if this is a ModelResponse object
if (variable && typeof variable === 'object' && '_isPvmResponse' in variable && variable._isPvmResponse) {
// Extract content from ModelResponse
processedVariables.push(variable.content);
// Store the execution ID for chaining (use the first one found)
if (!parentExecutionId) {
parentExecutionId = variable.executionId;
}
}
else {
processedVariables.push(variable);
}
}
const variableMap = {};
variableNames.forEach((name, index) => {
variableMap[name] = processedVariables[index];
});
// Render template
const rendered = renderTemplate(templateContent, variableMap);
// Track current prompt file for execution tracking
currentPromptFile = templateName;
return rendered;
}
/**
* Find the .pvm directory by searching up from current directory
*/
function findPvmDirectory() {
let current = process.cwd();
while (current !== path.dirname(current)) {
const pvmDir = path.join(current, '.pvm');
if (fs.existsSync(pvmDir) && fs.statSync(pvmDir).isDirectory()) {
return pvmDir;
}
current = path.dirname(current);
}
// Check current directory one more time
const pvmDir = path.join(process.cwd(), '.pvm');
if (fs.existsSync(pvmDir) && fs.statSync(pvmDir).isDirectory()) {
return pvmDir;
}
return null;
}
/**
* Parse template content into frontmatter and body
*/
function parseTemplate(content) {
if (content.startsWith('---')) {
const parts = content.split('---', 3);
if (parts.length >= 3) {
const frontmatterStr = parts[1].trim();
const templateContent = parts[2].trim();
// Parse YAML frontmatter
let frontmatter = {};
try {
frontmatter = yaml.load(frontmatterStr) || {};
}
catch (e) {
// Ignore YAML errors
}
return { frontmatter, templateContent };
}
}
return { frontmatter: {}, templateContent: content };
}
/**
* Extract variable names from template in order of appearance
*/
function extractVariables(template) {
// Find all {{variable}} patterns
const pattern = /\{\{(\w+)\}\}/g;
const matches = [...template.matchAll(pattern)];
// Remove duplicates while preserving order
const seen = new Set();
const uniqueVars = [];
for (const match of matches) {
const varName = match[1];
if (!seen.has(varName)) {
seen.add(varName);
uniqueVars.push(varName);
}
}
return uniqueVars;
}
/**
* Render template by replacing variables
*/
function renderTemplate(template, variables) {
let rendered = template;
for (const [varName, value] of Object.entries(variables)) {
const pattern = new RegExp(`\\{\\{${escapeRegExp(varName)}\\}\\}`, 'g');
rendered = rendered.replace(pattern, String(value));
}
return rendered;
}
/**
* Escape special regex characters
*/
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
/**
* Get the current prompt file being used
*/
function getCurrentPromptFile() {
return currentPromptFile;
}
/**
* Get the parent execution ID if a ModelResponse was passed to prompts()
*/
function getParentExecutionId() {
return parentExecutionId;
}
/**
* Clear the prompt context (used after model execution)
*/
function clearPromptContext() {
currentPromptFile = undefined;
parentExecutionId = undefined;
}
//# sourceMappingURL=prompts.js.map