prompt-version-manager
Version:
Centralized prompt management system for Human Behavior AI agents
360 lines • 13.5 kB
JavaScript
;
/**
* Chain tracking decorator and context manager for TypeScript.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChainTracker = exports.ChainContext = void 0;
exports.getChainManager = getChainManager;
exports.chainContext = chainContext;
exports.trackedLLM = trackedLLM;
exports.trackedLLMCall = trackedLLMCall;
const manager_1 = require("./manager");
const registry_1 = require("../providers/registry");
// Global chain manager instance
let _chainManager = null;
function getChainManager() {
if (!_chainManager) {
_chainManager = new manager_1.ChainManager();
}
return _chainManager;
}
// Context variables for tracking current chain
let _currentChainId = null;
let _currentNodeId = null;
class ChainContext {
manager;
chainId;
oldChainId;
constructor(name, description, chainId) {
this.manager = getChainManager();
this.oldChainId = _currentChainId;
// Create or get chain
if (chainId && this.manager['activeChains'].has(chainId)) {
this.chainId = chainId;
}
else {
this.chainId = this.manager.createChain(name, description, chainId);
}
// Set context
_currentChainId = this.chainId;
}
async start() {
try {
// Start chain
this.manager.startChain(this.chainId);
return this.chainId;
}
catch (error) {
// Restore context on error
_currentChainId = this.oldChainId;
throw error;
}
}
async complete() {
try {
// Complete chain
this.manager.completeChain(this.chainId);
}
finally {
// Restore context
_currentChainId = this.oldChainId;
}
}
async fail(error) {
try {
// Fail chain
this.manager.failChain(this.chainId, error);
}
finally {
// Restore context
_currentChainId = this.oldChainId;
}
}
getChainId() {
return this.chainId;
}
}
exports.ChainContext = ChainContext;
async function chainContext(name, description, chainId, fn) {
const context = new ChainContext(name, description, chainId);
try {
const actualChainId = await context.start();
const result = await fn(actualChainId);
await context.complete();
return result;
}
catch (error) {
await context.fail(error instanceof Error ? error.message : String(error));
throw error;
}
}
function trackedLLM(options) {
return function (_target, _propertyName, descriptor) {
const method = descriptor.value;
descriptor.value = async function (...args) {
// Get current chain context
if (_currentChainId === null) {
// No chain context, execute normally
return await method.apply(null, args);
}
const manager = getChainManager();
// Resolve dependency node IDs from tags
const depNodeIds = [];
if (options.dependencies) {
const chain = manager.getChain(_currentChainId);
for (const depTag of options.dependencies) {
// Find node ID for this tag
let depNodeId = null;
for (const [nid, node] of Object.entries(chain.nodes)) {
if (node.tag === depTag) {
depNodeId = nid;
break;
}
}
if (depNodeId === null) {
throw new Error(`Dependency node with tag '${depTag}' not found`);
}
depNodeIds.push(depNodeId);
}
}
// Extract model from function arguments
const model = args[0];
if (!model) {
throw new Error('Model must be specified for tracked LLM calls');
}
// Get provider for model
const providerObj = registry_1.registry.getProviderForModel(model);
const providerName = providerObj.name;
// Add node to chain
const actualNodeId = manager.addNode(_currentChainId, options.tag, model, providerName, options.language || 'typescript', depNodeIds, options.nodeId);
// Set node context
const oldNodeId = _currentNodeId;
_currentNodeId = actualNodeId;
try {
// Start node execution
manager.startNode(_currentChainId, actualNodeId);
// Execute function
const result = await method.apply(null, args);
// Complete node with result
if (result && typeof result === 'object' && 'content' in result) {
manager.completeNode(_currentChainId, actualNodeId, result);
}
else {
// If function doesn't return LLMResponse, create a placeholder
const placeholderResponse = {
content: String(result),
tokens: { input: 0, output: 0, total: 0 },
model,
provider: providerName,
latency: 0.0,
cost: 0.0,
timestamp: new Date()
};
manager.completeNode(_currentChainId, actualNodeId, placeholderResponse);
}
return result;
}
catch (error) {
// Fail node
manager.failNode(_currentChainId, actualNodeId, error instanceof Error ? error.message : String(error));
throw error;
}
finally {
// Restore context
_currentNodeId = oldNodeId;
}
};
};
}
async function trackedLLMCall(model, messages, options) {
// Get current chain context
if (_currentChainId === null) {
// No chain context, execute normally
return await registry_1.registry.chatCompletion(model, messages, options);
}
const manager = getChainManager();
// Resolve dependency node IDs from tags
const depNodeIds = [];
if (options.dependencies) {
const chain = manager.getChain(_currentChainId);
for (const depTag of options.dependencies) {
// Find node ID for this tag
let depNodeId = null;
for (const [nid, node] of Object.entries(chain.nodes)) {
if (node.tag === depTag) {
depNodeId = nid;
break;
}
}
if (depNodeId === null) {
throw new Error(`Dependency node with tag '${depTag}' not found`);
}
depNodeIds.push(depNodeId);
}
}
// Get provider for model
const providerObj = registry_1.registry.getProviderForModel(model);
const providerName = providerObj.name;
// Add node to chain
const actualNodeId = manager.addNode(_currentChainId, options.tag, model, providerName, options.language || 'typescript', depNodeIds, options.nodeId);
// Set node context
const oldNodeId = _currentNodeId;
_currentNodeId = actualNodeId;
try {
// Start node execution
manager.startNode(_currentChainId, actualNodeId);
// Execute LLM call
const result = await registry_1.registry.chatCompletion(model, messages, options);
// Complete node with result
manager.completeNode(_currentChainId, actualNodeId, result);
return result;
}
catch (error) {
// Fail node
manager.failNode(_currentChainId, actualNodeId, error instanceof Error ? error.message : String(error));
throw error;
}
finally {
// Restore context
_currentNodeId = oldNodeId;
}
}
class ChainTracker {
manager;
constructor(repoPath = '.pvm') {
this.manager = new manager_1.ChainManager(repoPath);
}
async createChain(name, description) {
return this.manager.createChain(name, description);
}
async addLLMNode(chainId, tag, model, dependencies, language = 'typescript') {
const providerObj = registry_1.registry.getProviderForModel(model);
const providerName = providerObj.name;
return this.manager.addNode(chainId, tag, model, providerName, language, dependencies);
}
async executeNode(chainId, nodeId, messages, options = {}) {
const chain = this.manager.getChain(chainId);
if (!chain.nodes[nodeId]) {
throw new Error(`Node ${nodeId} not found in chain ${chainId}`);
}
const node = chain.nodes[nodeId];
// Start node execution
this.manager.startNode(chainId, nodeId);
try {
// Execute LLM call
const response = await registry_1.registry.chatCompletion(node.model, messages, options);
// Complete node
this.manager.completeNode(chainId, nodeId, response);
return response;
}
catch (error) {
// Fail node
this.manager.failNode(chainId, nodeId, error instanceof Error ? error.message : String(error));
throw error;
}
}
async executeChain(chainId, inputs) {
const chain = this.manager.getChain(chainId);
const results = {};
this.manager.startChain(chainId);
try {
// Keep executing ready nodes until chain is complete
while (true) {
const readyNodes = this.manager.getReadyNodes(chainId);
if (readyNodes.length === 0) {
// Check if chain is complete
const allCompleted = Object.values(chain.nodes).every(node => ['completed', 'failed'].includes(node.status));
if (allCompleted) {
break;
}
else {
// No ready nodes but chain not complete - deadlock
throw new Error('Chain execution deadlocked - no ready nodes but chain incomplete');
}
}
// Execute ready nodes in parallel
const tasks = readyNodes.map(async (nodeId) => {
const node = chain.nodes[nodeId];
// Get input messages for this node
let nodeInputs = inputs[node.tag];
if (!Array.isArray(nodeInputs)) {
nodeInputs = [{ role: 'user', content: String(nodeInputs) }];
}
const messages = nodeInputs.map((msg) => typeof msg === 'object' && 'role' in msg ? msg : { role: 'user', content: String(msg) });
try {
const result = await this.executeNode(chainId, nodeId, messages);
results[node.tag] = result;
}
catch (error) {
console.error(`Node ${node.tag} failed: ${error}`);
// Continue with other nodes
}
});
// Wait for all tasks to complete
await Promise.all(tasks);
}
this.manager.completeChain(chainId);
return results;
}
catch (error) {
this.manager.failChain(chainId, error instanceof Error ? error.message : String(error));
throw error;
}
}
getChainVisualization(chainId) {
const chain = this.manager.getChain(chainId);
const nodes = [];
const edges = [];
for (const [nodeId, node] of Object.entries(chain.nodes)) {
nodes.push({
id: nodeId,
tag: node.tag,
model: node.model,
provider: node.provider,
language: node.language,
status: node.status,
cost: node.result?.cost || 0,
tokens: node.result?.tokens.total || 0,
latency: node.result?.latency || 0
});
// Add edges for dependencies
for (const depId of node.dependencies) {
edges.push({
from: depId,
to: nodeId
});
}
}
return {
chainId,
name: chain.name,
status: chain.status,
nodes,
edges,
stats: this.manager.getChainStats(chainId)
};
}
/**
* Track a single execution step with metrics
*/
async trackExecution(stepId, metrics) {
// For compatibility with market research pipeline
// This could be enhanced to integrate with chain tracking
console.log(`Tracking execution ${stepId}:`, metrics);
}
/**
* Get accumulated metrics for all tracked executions
*/
getMetrics() {
// Basic implementation for compatibility
return {
totalExecutions: 0,
successfulExecutions: 0,
failedExecutions: 0,
totalCost: 0,
totalTokens: { input: 0, output: 0, total: 0 }
};
}
}
exports.ChainTracker = ChainTracker;
//# sourceMappingURL=tracker.js.map