UNPKG

mcp-ai-agent-guidelines

Version:

A comprehensive Model Context Protocol server providing advanced tools, resources, and prompts for implementing AI agent best practices

170 lines 5.58 kB
/** * Agent-to-Agent (A2A) Context Management * * Provides context propagation, state management, and execution tracing * for tool-to-tool invocation chains within the MCP server. * * Key Features: * - Correlation ID tracking for distributed tracing * - Recursion depth guards to prevent infinite loops * - Shared state management across tool invocations * - Execution audit trail for observability * - Timeout enforcement per step and total chain */ /** * Default configuration for A2A contexts */ export const A2A_DEFAULTS = { /** Default maximum recursion depth */ MAX_DEPTH: 10, /** Default per-tool timeout (30 seconds) */ DEFAULT_TIMEOUT_MS: 30000, /** Default total chain timeout (5 minutes) */ DEFAULT_CHAIN_TIMEOUT_MS: 300000, }; /** * Create a new A2A context for a top-level tool invocation * * @param correlationId - Optional correlation ID (generated if not provided) * @param config - Optional configuration overrides * @returns A new A2A context */ export function createA2AContext(correlationId, config) { return { correlationId: correlationId || generateCorrelationId(), depth: 0, maxDepth: config?.maxDepth ?? A2A_DEFAULTS.MAX_DEPTH, sharedState: new Map(), executionLog: [], timeoutMs: config?.timeoutMs ?? A2A_DEFAULTS.DEFAULT_TIMEOUT_MS, chainStartTime: new Date(), chainTimeoutMs: config?.chainTimeoutMs ?? A2A_DEFAULTS.DEFAULT_CHAIN_TIMEOUT_MS, }; } /** * Create a child context for a nested tool invocation * * @param parent - Parent context * @param toolName - Name of the calling tool * @returns A new child context * @throws Error if maximum depth would be exceeded */ export function createChildContext(parent, toolName) { const newDepth = parent.depth + 1; if (newDepth > parent.maxDepth) { throw new Error(`Maximum recursion depth (${parent.maxDepth}) exceeded. ` + `Current depth: ${newDepth}, Parent: ${toolName}`); } return { ...parent, parentToolName: toolName, depth: newDepth, // Share the same state and log references sharedState: parent.sharedState, executionLog: parent.executionLog, }; } /** * Add an execution log entry to the context * * @param context - A2A context * @param entry - Execution log entry to add */ export function addExecutionLogEntry(context, entry) { context.executionLog.push({ ...entry, timestamp: new Date(), depth: context.depth, }); } /** * Check if the chain has exceeded its total timeout * * @param context - A2A context * @returns true if chain has timed out */ export function hasChainTimedOut(context) { if (!context.chainTimeoutMs) { return false; } const elapsed = Date.now() - context.chainStartTime.getTime(); return elapsed > context.chainTimeoutMs; } /** * Get remaining time in milliseconds for the chain * * @param context - A2A context * @returns Remaining time in milliseconds (undefined if no timeout set) */ export function getRemainingChainTime(context) { if (!context.chainTimeoutMs) { return undefined; } const elapsed = Date.now() - context.chainStartTime.getTime(); const remaining = context.chainTimeoutMs - elapsed; return Math.max(0, remaining); } /** * Generate a unique correlation ID * * Format: a2a_<timestamp>_<random> */ function generateCorrelationId() { const timestamp = Date.now().toString(36); const random = Math.random().toString(36).substring(2, 10); return `a2a_${timestamp}_${random}`; } /** * Create a hash of input parameters for deduplication * * @param input - Input parameters * @returns Hash string * * @remarks * This is a demonstration implementation using a simple string-based hash. * For production deployments, replace with a proper hashing library like * `crypto.createHash('sha256')` for better collision resistance and performance * with large inputs. * * @example * ```typescript * // Production implementation: * import { createHash } from 'crypto'; * const hash = createHash('sha256').update(JSON.stringify(input)).digest('hex'); * ``` */ export function hashInput(input) { // Simple hash implementation using JSON stringification // NOTE: This is a demonstration implementation with potential collisions const str = JSON.stringify(input) || ""; let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = (hash << 5) - hash + char; hash = hash & hash; // Convert to 32-bit integer } return hash.toString(36); } /** * Get execution summary from context * * @param context - A2A context * @returns Execution summary */ export function getExecutionSummary(context) { const totalDurationMs = context.executionLog.reduce((sum, entry) => sum + entry.durationMs, 0); const successCount = context.executionLog.filter((entry) => entry.status === "success").length; const errorCount = context.executionLog.filter((entry) => entry.status === "error").length; const skippedCount = context.executionLog.filter((entry) => entry.status === "skipped").length; const maxDepthReached = Math.max(...context.executionLog.map((entry) => entry.depth), 0); return { correlationId: context.correlationId, totalDurationMs, toolCount: context.executionLog.length, successCount, errorCount, skippedCount, maxDepthReached, }; } //# sourceMappingURL=a2a-context.js.map