UNPKG

prompt-version-manager

Version:

Centralized prompt management system for Human Behavior AI agents

360 lines 13.5 kB
"use strict"; /** * 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