prompt-version-manager
Version:
Centralized prompt management system for Human Behavior AI agents
344 lines • 12.9 kB
JavaScript
"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.VisualizationDashboard = void 0;
const blessed = __importStar(require("blessed"));
const versioning_1 = require("../core/versioning");
const manager_1 = require("../chains/manager");
const tracker_1 = require("../chains/tracker");
const contrib = __importStar(require("blessed-contrib"));
class VisualizationDashboard {
screen;
grid;
versioning;
chainManager;
chainTracker;
refreshInterval;
intervalId;
// Dashboard widgets
costChart;
tokenChart;
providerChart;
chainFlow;
commitLog;
diffView;
metricsTable;
statusBar;
constructor(options) {
this.versioning = new versioning_1.VersioningOperations(options.repoPath);
this.chainManager = new manager_1.ChainManager(options.repoPath);
this.chainTracker = new tracker_1.ChainTracker(options.repoPath);
this.refreshInterval = options.refreshInterval || 5000;
// Initialize blessed screen
this.screen = blessed.screen({
smartCSR: true,
title: 'PVM Visualization Dashboard',
fullUnicode: true
});
// Create grid layout
this.grid = new contrib.grid({ rows: 12, cols: 12, screen: this.screen });
this.setupWidgets();
this.setupKeyBindings();
}
setupWidgets() {
// Cost Chart (Top Left) - 4x6
this.costChart = this.grid.set(0, 0, 4, 6, contrib.line, {
style: {
line: 'yellow',
text: 'green',
baseline: 'black'
},
label: '💰 Cost Analysis Over Time',
showLegend: true,
legend: { width: 20 }
});
// Token Usage Chart (Top Right) - 4x6
this.tokenChart = this.grid.set(0, 6, 4, 6, contrib.bar, {
label: '📊 Token Usage by Provider',
barWidth: 6,
barSpacing: 2,
xOffset: 2,
maxHeight: 100
});
// Provider Performance Donut (Middle Left) - 4x4
this.providerChart = this.grid.set(4, 0, 4, 4, contrib.donut, {
label: '🎯 Provider Distribution',
radius: 10,
arcWidth: 3,
remainColor: 'black',
yPadding: 2
});
// Chain Flow Visualization (Middle Center) - 4x8
this.chainFlow = this.grid.set(4, 4, 4, 8, blessed.box, {
label: '🔗 Chain Flow Visualization',
scrollable: true,
alwaysScroll: true,
mouse: true,
keys: true,
vi: true,
style: {
fg: 'white',
border: { fg: 'cyan' }
}
});
// Commit Log (Bottom Left) - 4x6
this.commitLog = this.grid.set(8, 0, 4, 6, blessed.list, {
label: '📝 Commit History',
mouse: true,
keys: true,
vi: true,
style: {
fg: 'white',
selected: { bg: 'blue', fg: 'white' },
border: { fg: 'green' }
}
});
// Diff View (Bottom Right) - 4x6
this.diffView = this.grid.set(8, 6, 4, 6, blessed.box, {
label: '🔍 Commit Diff View',
scrollable: true,
alwaysScroll: true,
mouse: true,
keys: true,
vi: true,
style: {
fg: 'white',
border: { fg: 'magenta' }
}
});
// Metrics Table (Status bar at bottom)
this.statusBar = blessed.box({
bottom: 0,
left: 0,
width: '100%',
height: 1,
style: {
fg: 'white',
bg: 'blue'
},
content: ' Loading dashboard... Press q to quit, r to refresh, arrow keys to navigate '
});
this.screen.append(this.statusBar);
}
setupKeyBindings() {
this.screen.key(['q', 'C-c'], () => {
this.stop();
process.exit(0);
});
this.screen.key(['r'], () => {
this.refresh();
});
this.commitLog.on('select', (item, index) => {
this.showCommitDiff(index);
});
}
async start() {
await this.versioning.init();
await this.refresh();
// Start auto-refresh
this.intervalId = setInterval(() => {
this.refresh().catch(console.error);
}, this.refreshInterval);
this.screen.render();
}
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
}
}
async refresh() {
try {
await this.updateCostChart();
await this.updateTokenChart();
await this.updateProviderChart();
await this.updateChainFlow();
await this.updateCommitLog();
this.statusBar.setContent(` Last updated: ${new Date().toLocaleTimeString()} | Press q to quit, r to refresh `);
this.screen.render();
}
catch (error) {
this.statusBar.setContent(` Error: ${error} `);
this.screen.render();
}
}
async updateCostChart() {
// Get historical metrics from chain tracker
const metrics = await this.getHistoricalMetrics();
const data = {
title: 'Cost Over Time',
x: metrics.map((_, i) => i.toString()),
y: metrics.map(m => m.totalCost * 100), // Convert to cents for better visualization
style: { line: 'yellow' }
};
this.costChart.setData([data]);
}
async updateTokenChart() {
const latestMetrics = await this.getLatestMetrics();
if (!latestMetrics)
return;
const providers = Object.keys(latestMetrics.providerBreakdown);
const data = providers.map(provider => latestMetrics.providerBreakdown[provider].tokens.total);
this.tokenChart.setData({
titles: providers,
data: data
});
}
async updateProviderChart() {
const latestMetrics = await this.getLatestMetrics();
if (!latestMetrics)
return;
const data = [];
let colorIndex = 0;
const colors = ['yellow', 'cyan', 'green', 'magenta', 'red'];
for (const [provider, stats] of Object.entries(latestMetrics.providerBreakdown)) {
data.push({
percent: Math.round((stats.requests / latestMetrics.totalSteps) * 100),
label: provider,
color: colors[colorIndex++ % colors.length]
});
}
this.providerChart.setData(data);
}
async updateChainFlow() {
const chains = await this.chainManager.listChains();
if (chains.length === 0) {
this.chainFlow.setContent('No chains found');
return;
}
const latestChain = chains[chains.length - 1];
const nodes = await this.chainManager.getChainNodes(latestChain.id);
let flowContent = '';
let indent = 0;
for (const node of nodes) {
const status = node.status === 'completed' ? '✅' :
node.status === 'failed' ? '❌' : '🔄';
flowContent += `${' '.repeat(indent)}${status} ${node.name || node.id}\n`;
flowContent += `${' '.repeat(indent)} └─ Model: ${node.model}\n`;
flowContent += `${' '.repeat(indent)} └─ Tokens: ${node.metrics?.tokens.total || 0}\n`;
flowContent += `${' '.repeat(indent)} └─ Duration: ${node.metrics?.latency || 0}ms\n\n`;
if (node.children && node.children.length > 0) {
indent++;
}
}
this.chainFlow.setContent(flowContent);
}
async updateCommitLog() {
const commits = await this.versioning.log({ limit: 20 });
const items = commits.map(commit => `${commit.hash.substring(0, 8)} - ${commit.message} (${new Date(commit.timestamp).toLocaleString()})`);
this.commitLog.setItems(items);
}
async showCommitDiff(index) {
const commits = await this.versioning.log({ limit: 20 });
if (index >= commits.length)
return;
const commit = commits[index];
// Get diff between this commit and its parent
let diffContent = `Commit: ${commit.hash}\n`;
diffContent += `Author: ${commit.author}\n`;
diffContent += `Date: ${new Date(commit.timestamp).toLocaleString()}\n`;
diffContent += `Message: ${commit.message}\n\n`;
if (commit.parent) {
try {
const parentCommit = await this.versioning.storage.getObject(commit.parent);
const currentPrompt = await this.versioning.storage.getObject(commit.prompt);
diffContent += '=== Prompt Changes ===\n';
diffContent += this.generateDiff(JSON.stringify(parentCommit, null, 2), JSON.stringify(currentPrompt, null, 2));
}
catch (error) {
diffContent += 'Unable to generate diff';
}
}
else {
diffContent += 'Initial commit - no parent to compare';
}
this.diffView.setContent(diffContent);
this.screen.render();
}
generateDiff(oldContent, newContent) {
const oldLines = oldContent.split('\n');
const newLines = newContent.split('\n');
let diff = '';
// Simple line-by-line diff
const maxLines = Math.max(oldLines.length, newLines.length);
for (let i = 0; i < maxLines; i++) {
if (i >= oldLines.length) {
diff += `{green-fg}+ ${newLines[i]}{/green-fg}\n`;
}
else if (i >= newLines.length) {
diff += `{red-fg}- ${oldLines[i]}{/red-fg}\n`;
}
else if (oldLines[i] !== newLines[i]) {
diff += `{red-fg}- ${oldLines[i]}{/red-fg}\n`;
diff += `{green-fg}+ ${newLines[i]}{/green-fg}\n`;
}
}
return diff;
}
async getHistoricalMetrics() {
// In a real implementation, this would fetch from a metrics store
// For now, generate sample data
const metrics = [];
for (let i = 0; i < 10; i++) {
metrics.push({
chainId: `chain-${i}`,
totalSteps: 5,
successfulSteps: Math.floor(Math.random() * 5) + 1,
failedSteps: 0,
totalTokens: {
input: Math.floor(Math.random() * 1000) + 500,
output: Math.floor(Math.random() * 1000) + 500,
total: Math.floor(Math.random() * 2000) + 1000
},
totalCost: Math.random() * 0.5,
totalDuration: Math.floor(Math.random() * 60000) + 30000,
providerBreakdown: {}
});
}
return metrics;
}
async getLatestMetrics() {
const metrics = await this.getHistoricalMetrics();
return metrics[metrics.length - 1] || null;
}
}
exports.VisualizationDashboard = VisualizationDashboard;
// CLI entry point
if (require.main === module) {
const dashboard = new VisualizationDashboard({
repoPath: process.env.PVM_REPO_PATH || './pvm-data'
});
dashboard.start().catch(console.error);
}
//# sourceMappingURL=dashboard.js.map