/**
 * Agent and Workflow Exposure as MCP Tools
 *
 * Enables exposing NeuroLink agents and workflows as MCP tools,
 * allowing external MCP clients to invoke complex AI operations
 * through the standardized MCP protocol.
 *
 * @module mcp/agentExposure
 * @since 8.39.0
 */
import { logger } from "../utils/logger.js";
import { withTimeout } from "../utils/async/withTimeout.js";
import { ErrorFactory } from "../utils/errorHandling.js";
/**
 * Expose an agent as an MCP tool
 */
export function exposeAgentAsTool(agent, options = {}) {
    const { prefix = "agent", defaultAnnotations = {}, includeMetadataInDescription = true, nameTransformer = (name) => name.toLowerCase().replace(/\s+/g, "_"), wrapWithContext = true, executionTimeout = 300000, // 5 minutes default
    enableLogging = true, } = options;
    // Generate tool name
    const baseName = nameTransformer(agent.name);
    const toolName = prefix ? `${prefix}_${baseName}` : baseName;
    // Build description
    let description = agent.description;
    if (includeMetadataInDescription && agent.metadata) {
        const metaParts = [];
        if (agent.metadata.version) {
            metaParts.push(`v${agent.metadata.version}`);
        }
        if (agent.metadata.category) {
            metaParts.push(`category: ${agent.metadata.category}`);
        }
        if (agent.metadata.estimatedDuration) {
            metaParts.push(`~${agent.metadata.estimatedDuration}ms`);
        }
        if (metaParts.length > 0) {
            description += ` [${metaParts.join(", ")}]`;
        }
    }
    // Build annotations
    const annotations = {
        ...defaultAnnotations,
        complexity: defaultAnnotations.complexity ?? "complex",
        estimatedDuration: agent.metadata?.estimatedDuration ?? defaultAnnotations.estimatedDuration,
        costHint: agent.metadata?.costHint ?? defaultAnnotations.costHint,
        tags: [
            ...(defaultAnnotations.tags ?? []),
            "agent",
            ...(agent.metadata?.tags ?? []),
        ],
    };
    // Build input schema with agent context
    const inputSchema = agent.inputSchema ?? {
        type: "object",
        properties: {},
    };
    // Create execution wrapper
    const execute = async (params, context) => {
        const startTime = Date.now();
        if (enableLogging) {
            logger.debug(`[AgentExposure] Executing agent '${agent.id}' as tool '${toolName}'`);
        }
        try {
            // Execute agent with context wrapper if enabled
            const existingConfig = context?.config && typeof context.config === "object"
                ? context.config
                : {};
            const executionContext = wrapWithContext
                ? {
                    ...context,
                    config: {
                        ...existingConfig,
                        sourceType: "mcp-exposed-agent",
                        agentId: agent.id,
                        toolName,
                    },
                }
                : (context ?? {});
            const result = await withTimeout(agent.execute(params, executionContext), executionTimeout);
            const duration = Date.now() - startTime;
            if (enableLogging) {
                logger.debug(`[AgentExposure] Agent '${agent.id}' completed in ${duration}ms`);
            }
            return {
                success: true,
                data: result,
                metadata: {
                    agentId: agent.id,
                    toolName,
                    executionTime: duration,
                    sourceType: "agent",
                },
            };
        }
        catch (error) {
            const duration = Date.now() - startTime;
            const agentError = error instanceof Error
                ? error
                : ErrorFactory.toolExecutionFailed(toolName, new Error(String(error)));
            if (enableLogging) {
                logger.error(`[AgentExposure] Agent '${agent.id}' failed after ${duration}ms: ${agentError.message}`);
            }
            return {
                success: false,
                error: agentError.message,
                metadata: {
                    agentId: agent.id,
                    toolName,
                    executionTime: duration,
                    sourceType: "agent",
                },
            };
        }
    };
    const tool = {
        name: toolName,
        description,
        inputSchema,
        outputSchema: agent.outputSchema,
        annotations,
        execute,
        metadata: {
            sourceType: "agent",
            sourceId: agent.id,
            originalName: agent.name,
            ...agent.metadata,
        },
    };
    return {
        tool,
        sourceType: "agent",
        sourceId: agent.id,
        toolName,
    };
}
/**
 * Expose a workflow as an MCP tool
 */
export function exposeWorkflowAsTool(workflow, options = {}) {
    const { prefix = "workflow", defaultAnnotations = {}, includeMetadataInDescription = true, nameTransformer = (name) => name.toLowerCase().replace(/\s+/g, "_"), wrapWithContext = true, executionTimeout = 600000, // 10 minutes default for workflows
    enableLogging = true, } = options;
    // Generate tool name
    const baseName = nameTransformer(workflow.name);
    const toolName = prefix ? `${prefix}_${baseName}` : baseName;
    // Build description
    let description = workflow.description;
    if (includeMetadataInDescription) {
        const metaParts = [];
        if (workflow.metadata?.version) {
            metaParts.push(`v${workflow.metadata.version}`);
        }
        if (workflow.steps?.length) {
            metaParts.push(`${workflow.steps.length} steps`);
        }
        if (workflow.metadata?.estimatedDuration) {
            metaParts.push(`~${workflow.metadata.estimatedDuration}ms`);
        }
        if (metaParts.length > 0) {
            description += ` [${metaParts.join(", ")}]`;
        }
    }
    // Build annotations
    const annotations = {
        ...defaultAnnotations,
        complexity: defaultAnnotations.complexity ?? "complex",
        estimatedDuration: workflow.metadata?.estimatedDuration ??
            defaultAnnotations.estimatedDuration,
        idempotentHint: workflow.metadata?.idempotent ?? defaultAnnotations.idempotentHint,
        tags: [
            ...(defaultAnnotations.tags ?? []),
            "workflow",
            ...(workflow.metadata?.tags ?? []),
        ],
    };
    // Build input schema
    const inputSchema = workflow.inputSchema ?? {
        type: "object",
        properties: {},
    };
    // Create execution wrapper
    const execute = async (params, context) => {
        const startTime = Date.now();
        if (enableLogging) {
            logger.debug(`[WorkflowExposure] Executing workflow '${workflow.id}' as tool '${toolName}'`);
        }
        try {
            // Execute workflow with context wrapper if enabled
            const existingConfig = context?.config && typeof context.config === "object"
                ? context.config
                : {};
            const executionContext = wrapWithContext
                ? {
                    ...context,
                    config: {
                        ...existingConfig,
                        sourceType: "mcp-exposed-workflow",
                        workflowId: workflow.id,
                        toolName,
                    },
                }
                : (context ?? {});
            const result = await withTimeout(workflow.execute(params, executionContext), executionTimeout);
            const duration = Date.now() - startTime;
            if (enableLogging) {
                logger.debug(`[WorkflowExposure] Workflow '${workflow.id}' completed in ${duration}ms`);
            }
            return {
                success: true,
                data: result,
                metadata: {
                    workflowId: workflow.id,
                    toolName,
                    executionTime: duration,
                    sourceType: "workflow",
                    stepsCount: workflow.steps?.length,
                },
            };
        }
        catch (error) {
            const duration = Date.now() - startTime;
            const workflowError = error instanceof Error
                ? error
                : ErrorFactory.toolExecutionFailed(toolName, new Error(String(error)));
            if (enableLogging) {
                logger.error(`[WorkflowExposure] Workflow '${workflow.id}' failed after ${duration}ms: ${workflowError.message}`);
            }
            return {
                success: false,
                error: workflowError.message,
                metadata: {
                    workflowId: workflow.id,
                    toolName,
                    executionTime: duration,
                    sourceType: "workflow",
                },
            };
        }
    };
    const tool = {
        name: toolName,
        description,
        inputSchema,
        outputSchema: workflow.outputSchema,
        annotations,
        execute,
        metadata: {
            sourceType: "workflow",
            sourceId: workflow.id,
            originalName: workflow.name,
            steps: workflow.steps,
            ...workflow.metadata,
        },
    };
    return {
        tool,
        sourceType: "workflow",
        sourceId: workflow.id,
        toolName,
    };
}
/**
 * Batch expose agents as MCP tools
 */
export function exposeAgentsAsTools(agents, options = {}) {
    return agents.map((agent) => exposeAgentAsTool(agent, options));
}
/**
 * Batch expose workflows as MCP tools
 */
export function exposeWorkflowsAsTools(workflows, options = {}) {
    return workflows.map((workflow) => exposeWorkflowAsTool(workflow, options));
}
/**
 * Agent Exposure Manager
 *
 * Manages the lifecycle of exposed agents and workflows,
 * providing registration, lookup, and invocation capabilities.
 */
export class AgentExposureManager {
    exposedTools = new Map();
    options;
    constructor(options = {}) {
        this.options = options;
    }
    /**
     * Expose an agent and register it
     */
    exposeAgent(agent) {
        const result = exposeAgentAsTool(agent, this.options);
        this.exposedTools.set(result.toolName, result);
        return result.tool;
    }
    /**
     * Expose a workflow and register it
     */
    exposeWorkflow(workflow) {
        const result = exposeWorkflowAsTool(workflow, this.options);
        this.exposedTools.set(result.toolName, result);
        return result.tool;
    }
    /**
     * Get all exposed tools
     */
    getExposedTools() {
        return Array.from(this.exposedTools.values()).map((r) => r.tool);
    }
    /**
     * Get exposed tool by name
     */
    getExposedTool(toolName) {
        return this.exposedTools.get(toolName)?.tool;
    }
    /**
     * Get exposure result by tool name
     */
    getExposureResult(toolName) {
        return this.exposedTools.get(toolName);
    }
    /**
     * Get tools by source type
     */
    getToolsBySourceType(sourceType) {
        return Array.from(this.exposedTools.values())
            .filter((r) => r.sourceType === sourceType)
            .map((r) => r.tool);
    }
    /**
     * Remove exposed tool
     */
    unexpose(toolName) {
        return this.exposedTools.delete(toolName);
    }
    /**
     * Clear all exposed tools
     */
    clear() {
        this.exposedTools.clear();
    }
    /**
     * Get statistics
     */
    getStatistics() {
        const results = Array.from(this.exposedTools.values());
        return {
            totalExposed: results.length,
            exposedAgents: results.filter((r) => r.sourceType === "agent").length,
            exposedWorkflows: results.filter((r) => r.sourceType === "workflow")
                .length,
            toolNames: results.map((r) => r.toolName),
        };
    }
}
/**
 * Global agent exposure manager instance
 */
export const globalAgentExposureManager = new AgentExposureManager();
//# sourceMappingURL=agentExposure.js.map