UNPKG

pit-manager

Version:

Centralized prompt management system for Human Behavior AI agents

241 lines 10 kB
"use strict"; 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.PromptTracker = void 0; const fs = __importStar(require("fs/promises")); const fsSync = __importStar(require("fs")); const path = __importStar(require("path")); const crypto = __importStar(require("crypto")); const yaml = __importStar(require("js-yaml")); class PromptTracker { promptsDir; executionsDir; templates = new Map(); sharedPromptsDir; constructor(repoPath = '.pit') { // Prompts are tracked in the prompts directory created by pit init this.promptsDir = path.join(repoPath, 'prompts'); this.executionsDir = path.join(repoPath, 'executions'); // Also check for shared prompts in parent directory const parentPrompts = path.join(path.dirname(repoPath), 'prompts'); if (fsSync.existsSync(parentPrompts)) { this.sharedPromptsDir = parentPrompts; } } async init() { await fs.mkdir(this.promptsDir, { recursive: true }); await fs.mkdir(this.executionsDir, { recursive: true }); await this.loadTemplates(); } async loadTemplates() { try { // Load from .pit/prompts directory const files = await fs.readdir(this.promptsDir); for (const file of files) { if (file.endsWith('.json')) { const content = await fs.readFile(path.join(this.promptsDir, file), 'utf-8'); const template = JSON.parse(content); this.templates.set(template.id, template); } else if (file.endsWith('.md')) { const template = await this.loadMarkdownTemplate(path.join(this.promptsDir, file)); if (template) { this.templates.set(template.id, template); } } } // Load from shared prompts directory if it exists if (this.sharedPromptsDir) { const sharedFiles = await fs.readdir(this.sharedPromptsDir); for (const file of sharedFiles) { if (file.endsWith('.md')) { const template = await this.loadMarkdownTemplate(path.join(this.sharedPromptsDir, file)); if (template) { this.templates.set(template.id, template); } } } } } catch (error) { console.error('Failed to load prompt templates:', error); } } async loadMarkdownTemplate(filepath) { try { const content = await fs.readFile(filepath, 'utf-8'); // Parse YAML frontmatter if (content.startsWith('---\n')) { const parts = content.split('---\n', 3); if (parts.length >= 3) { const metadata = yaml.load(parts[1]); const promptContent = parts[2].trim(); return { id: metadata.id || path.basename(filepath, '.md'), name: metadata.name || metadata.id, version: metadata.version || '1.0.0', content: promptContent, variables: metadata.variables || [], metadata: metadata }; } } } catch (error) { console.error(`Error loading markdown template ${filepath}:`, error); } return null; } async saveTemplate(template) { const filename = `${template.id}.json`; const filepath = path.join(this.promptsDir, filename); template.metadata.modified = new Date(); template.version = this.generateVersion(template); await fs.writeFile(filepath, JSON.stringify(template, null, 2)); this.templates.set(template.id, template); return template.version; } async trackExecution(execution, responseContent, responseMetadata) { const executionId = execution.executionId || this.generateExecutionId(); const filename = `${executionId}.json`; const filepath = path.join(this.executionsDir, filename); // Create cross-language compatible format const executionData = { version: '1.0', prompt: { id: executionId, templateId: execution.templateId, templateVersion: execution.templateVersion, language: execution.language || 'typescript', content: { template: '', // Not stored to save space variables: Object.keys(execution.variables), expanded: execution.expandedPrompt }, execution: { timestamp: execution.timestamp.toISOString(), provider: execution.provider, model: execution.model, responseHash: execution.responseHash, variables: execution.variables } }, response: responseContent ? { content: responseContent, metadata: responseMetadata || {} } : undefined }; await fs.writeFile(filepath, JSON.stringify(executionData, null, 2)); return executionId; } async getTemplate(id) { return this.templates.get(id) || null; } async getTemplateHistory(id) { // In a real implementation, this would retrieve from version control const current = this.templates.get(id); return current ? [current] : []; } async expandTemplate(templateId, variables) { const template = this.templates.get(templateId); if (!template) { throw new Error(`Template ${templateId} not found`); } let expanded = template.content; for (const [key, value] of Object.entries(variables)) { const placeholder = `{{${key}}}`; expanded = expanded.replace(new RegExp(placeholder, 'g'), String(value)); } return expanded; } async diffTemplates(id1, version1, id2, version2) { // Simple diff implementation - in production, use a proper diff library const template1 = await this.getTemplate(id1); const template2 = await this.getTemplate(id2); if (!template1 || !template2) { throw new Error('One or both templates not found'); } const lines1 = template1.content.split('\n'); const lines2 = template2.content.split('\n'); let diff = `--- ${id1} (${version1})\n+++ ${id2} (${version2})\n`; const maxLines = Math.max(lines1.length, lines2.length); for (let i = 0; i < maxLines; i++) { if (lines1[i] !== lines2[i]) { if (lines1[i] !== undefined) { diff += `- ${lines1[i]}\n`; } if (lines2[i] !== undefined) { diff += `+ ${lines2[i]}\n`; } } } return diff; } generateVersion(template) { const hash = crypto.createHash('sha256'); hash.update(template.content); hash.update(JSON.stringify(template.variables)); return hash.digest('hex').substring(0, 8); } generateExecutionId() { return `exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } async getExecutionsByTemplate(templateId) { const executions = []; try { const files = await fs.readdir(this.executionsDir); for (const file of files) { if (file.endsWith('.json')) { const content = await fs.readFile(path.join(this.executionsDir, file), 'utf-8'); const data = JSON.parse(content); // Handle cross-language format if (data.prompt?.templateId === templateId) { executions.push(data); } } } } catch (error) { console.error('Failed to load executions:', error); } return executions.sort((a, b) => { const timeA = new Date(a.prompt?.execution?.timestamp || 0).getTime(); const timeB = new Date(b.prompt?.execution?.timestamp || 0).getTime(); return timeB - timeA; }); } } exports.PromptTracker = PromptTracker; //# sourceMappingURL=prompt-tracker.js.map