/**
 * SemanticKernelAdapter -- Orchestrator adapter for Microsoft Semantic Kernel.
 *
 * Hook surface: Semantic Kernel's IFunctionInvocationFilter interface. The
 * adapter provides a filter class the customer registers with the Kernel:
 *
 *   const adapter = new SemanticKernelAdapter(config);
 *   adapter.initialize(orchConfig);
 *   const filter = adapter.toFunctionInvocationFilter();
 *   kernel.functionInvocationFilters.push(filter);
 *
 * Planner lifecycle: plan creation, plan execution, and per-step auditing
 * are intercepted at both the InvokePromptAsync and InvokeFunctionAsync paths.
 * In older SK versions, InvokePromptAsync synthesises a prompt at runtime and
 * bypasses function-level filters. The adapter intercepts both paths
 * explicitly so neither is missed.
 *
 * Kernel memory access governance: memory reads through the kernel are gated
 * through the same policy dispatch as function invocations.
 *
 * Skill-to-skill delegation: SK's plugin/function invocation chaining maps
 * onto the DelegationDecision contract. When function A invokes function B,
 * that constitutes a skill-to-skill delegation and fires preDelegation.
 *
 * DEFERRED-SK-TS-BINDING: Verify TypeScript binding filter registration API
 * at implementation time. The C# binding uses:
 *   kernel.FunctionInvocationFilters.Add(filter)
 * The TS binding (as of 2026-04-22) uses:
 *   kernel.functionInvocationFilters.push(filter)
 * Confirm method name and array vs AddRange pattern before going to prod.
 *
 * No live Semantic Kernel SDK installed. All framework surfaces are shims.
 * Tests use in-process fakes only.
 *
 * Spec: P3-ORCH-01, Section 2.8, AC 16-17
 * @connexum/ai-governance
 */
import * as crypto from 'crypto';
import { BaseOrchestratorAdapter } from './base.js';
import { OrchestratorError, } from './index.js';
import { ActionDecisionType } from '../adapters/index.js';
// ---------------------------------------------------------------------------
// SKGovernanceFilter -- IFunctionInvocationFilter implementation
// ---------------------------------------------------------------------------
/**
 * Semantic Kernel function invocation filter.
 *
 * Mirrors the IFunctionInvocationFilter interface from the TS SK binding.
 *
 * DEFERRED-SK-TS-BINDING: Confirm the exact method signature matches the
 * TS binding release. The C# interface uses InvokeAsync(context, next);
 * the TS interface may differ.
 */
export class SKGovernanceFilter {
    adapter;
    constructor(adapter) {
        this.adapter = adapter;
    }
    /**
     * Called before a function is invoked (IFunctionInvocationFilter.OnFunctionInvokingAsync).
     * Returns false to block the invocation. Throws OrchestratorError on denial.
     */
    async onFunctionInvoking(ctx) {
        return this.adapter.handleFunctionInvoking(ctx);
    }
    /**
     * Called after a function is invoked (IFunctionInvocationFilter.OnFunctionInvokedAsync).
     * Audit hook.
     */
    async onFunctionInvoked(ctx, result) {
        return this.adapter.handleFunctionInvoked(ctx, result);
    }
}
// ---------------------------------------------------------------------------
// SemanticKernelAdapter
// ---------------------------------------------------------------------------
export class SemanticKernelAdapter extends BaseOrchestratorAdapter {
    adapterId = 'semantic-kernel';
    orchestratorId = 'semantic-kernel';
    skConfig;
    constructor(config) {
        super();
        this.skConfig = config;
    }
    // ---------------------------------------------------------------------------
    // toFunctionInvocationFilter -- public factory
    // ---------------------------------------------------------------------------
    /**
     * Return an SKGovernanceFilter wired to this adapter.
     * Customers register the filter with their Kernel instance:
     *   kernel.functionInvocationFilters.push(adapter.toFunctionInvocationFilter());
     */
    toFunctionInvocationFilter() {
        this.assertInitialized();
        return new SKGovernanceFilter(this);
    }
    // ---------------------------------------------------------------------------
    // Internal filter dispatchers
    // ---------------------------------------------------------------------------
    /**
     * Governance check before function invocation.
     *
     * Intercepts both paths:
     *   1. InvokeFunctionAsync -- standard function-level path (all SK versions)
     *   2. InvokePromptAsync -- prompt synthesis path (ctx.isPromptInvocation == true)
     *      Older SK versions bypass function-level filters on this path;
     *      the adapter handles it explicitly here.
     *
     * Memory reads are gated as a separate class of operation.
     *
     * Sensitive functions (by fullyQualifiedName) are routed to the
     * human-reviewer tier.
     */
    async handleFunctionInvoking(ctx) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        if (this.isCircuitOpen()) {
            const reason = 'Circuit breaker is open; function invocation denied';
            this.emitCanonical('orchestrator:task-denied', {
                invocationId: ctx.invocationId,
                fullyQualifiedName: ctx.fullyQualifiedName,
                reason,
            });
            this.recordFailure();
            return { type: ActionDecisionType.DENY, reason, auditId };
        }
        // Plugin allowlist
        if (!this.skConfig.allowedPlugins.includes(ctx.pluginName)) {
            const reason = `Plugin "${ctx.pluginName}" is not in the allowed plugin list`;
            this.emitCanonical('orchestrator:task-denied', {
                invocationId: ctx.invocationId,
                pluginName: ctx.pluginName,
                functionName: ctx.functionName,
                reason,
            });
            this.recordFailure();
            return { type: ActionDecisionType.DENY, reason, auditId };
        }
        // Memory access governance
        if (ctx.isMemoryRead ||
            this.skConfig.memoryPluginNames.includes(ctx.pluginName)) {
            const tier = 'security-reviewer';
            const queueId = this.config.reviewerQueues[tier];
            if (!queueId) {
                // Fail closed: no security-reviewer queue for memory access
                const reason = `Memory read via "${ctx.fullyQualifiedName}" requires security-reviewer tier ` +
                    'but no queue binding exists';
                this.emitCanonical('orchestrator:task-denied', {
                    invocationId: ctx.invocationId,
                    fullyQualifiedName: ctx.fullyQualifiedName,
                    isMemoryRead: true,
                    reason,
                });
                this.recordFailure();
                return { type: ActionDecisionType.DENY, reason, auditId };
            }
            this.emitCanonical('orchestrator:reviewer-routed', {
                invocationId: ctx.invocationId,
                fullyQualifiedName: ctx.fullyQualifiedName,
                isMemoryRead: true,
                tier,
                queueId,
            });
            return {
                type: ActionDecisionType.REQUIRE_APPROVAL,
                reason: `Memory read via "${ctx.fullyQualifiedName}" routed to security-reviewer`,
                auditId,
                metadata: { reviewerTier: tier, isMemoryRead: true },
            };
        }
        // Sensitive function check
        if (this.skConfig.sensitiveFunctions.includes(ctx.fullyQualifiedName)) {
            const tier = 'human-reviewer';
            const queueId = this.config.reviewerQueues[tier];
            if (!queueId) {
                const reason = `Sensitive function "${ctx.fullyQualifiedName}" requires ` +
                    'human-reviewer tier but no queue binding exists';
                this.emitCanonical('orchestrator:task-denied', {
                    invocationId: ctx.invocationId,
                    fullyQualifiedName: ctx.fullyQualifiedName,
                    reason,
                });
                this.recordFailure();
                return { type: ActionDecisionType.DENY, reason, auditId };
            }
            this.emitCanonical('orchestrator:reviewer-routed', {
                invocationId: ctx.invocationId,
                fullyQualifiedName: ctx.fullyQualifiedName,
                tier,
                queueId,
                isPromptInvocation: ctx.isPromptInvocation,
            });
            return {
                type: ActionDecisionType.REQUIRE_APPROVAL,
                reason: `Function "${ctx.fullyQualifiedName}" requires human-reviewer approval`,
                auditId,
                metadata: {
                    reviewerTier: tier,
                    isPromptInvocation: ctx.isPromptInvocation,
                },
            };
        }
        this.emitCanonical('orchestrator:task-approved', {
            invocationId: ctx.invocationId,
            fullyQualifiedName: ctx.fullyQualifiedName,
            isPromptInvocation: ctx.isPromptInvocation,
        });
        this.recordSuccess();
        return {
            type: ActionDecisionType.ALLOW,
            reason: `Function "${ctx.fullyQualifiedName}" approved`,
            auditId,
        };
    }
    /** Audit hook after function invocation. */
    async handleFunctionInvoked(ctx, result) {
        this.assertInitialized();
        this.emitCanonical('orchestrator:plan-step-end', {
            invocationId: ctx.invocationId,
            fullyQualifiedName: ctx.fullyQualifiedName,
            success: result.success,
            durationMs: result.durationMs,
        });
    }
    /**
     * Planner governance: intercept plan creation and emit audit events.
     * Each step in the plan emits plan-step-begin / plan-step-end pairs
     * via the existing traversePlanTree or inline here for SK-specific plans.
     */
    async handlePlannerExecution(plannerCtx) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        this.emitCanonical('orchestrator:plan-proposed', {
            planId: plannerCtx.planId,
            goal: plannerCtx.goal,
            plannerType: plannerCtx.plannerType,
            stepCount: plannerCtx.steps.length,
        });
        const maxSteps = this.skConfig.maxPlanSteps;
        if (maxSteps !== undefined && plannerCtx.steps.length > maxSteps) {
            const reason = `SK plan has ${plannerCtx.steps.length} steps, exceeding the maximum of ${maxSteps}`;
            this.emitCanonical('orchestrator:plan-denied', {
                planId: plannerCtx.planId,
                reason,
            });
            return { type: ActionDecisionType.DENY, reason, auditId };
        }
        // Audit each plan step
        for (const step of plannerCtx.steps) {
            this.emitCanonical('orchestrator:plan-step-begin', {
                planId: plannerCtx.planId,
                stepIndex: step.stepIndex,
                pluginName: step.pluginName,
                functionName: step.functionName,
            });
        }
        this.emitCanonical('orchestrator:plan-approved', {
            planId: plannerCtx.planId,
            stepCount: plannerCtx.steps.length,
        });
        return {
            type: ActionDecisionType.ALLOW,
            reason: `SK plan "${plannerCtx.planId}" approved (${plannerCtx.steps.length} steps)`,
            auditId,
        };
    }
    /**
     * Skill-to-skill delegation governance.
     * When a SK function invokes another function, this constitutes a
     * skill-to-skill delegation mapped to the DelegationDecision contract.
     */
    async handleSkillDelegation(event) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        const delegationCtx = {
            delegationId: event.delegationId,
            fromAgent: {
                name: `${event.callerPlugin}.${event.callerFunction}`,
                role: event.callerPlugin,
                sessionId: event.delegationId,
            },
            toAgent: {
                name: `${event.targetPlugin}.${event.targetFunction}`,
                role: event.targetPlugin,
                sessionId: event.delegationId,
            },
            task: `Skill delegation: ${event.callerPlugin}.${event.callerFunction} -> ` +
                `${event.targetPlugin}.${event.targetFunction}`,
            permissions: [`${event.targetPlugin}.${event.targetFunction}`],
            timestamp: new Date(event.timestamp),
        };
        return this.preDelegation(delegationCtx);
    }
    // ---------------------------------------------------------------------------
    // OrchestratorAdapter surface -- workflow lifecycle
    // ---------------------------------------------------------------------------
    async startWorkflow(ctx) {
        const auditId = crypto.randomUUID();
        this.emitCanonical('orchestrator:workflow-start', {
            workflowId: ctx.workflowId,
            name: ctx.name,
            initiator: ctx.initiator.name,
        });
        return { type: 'ALLOW', reason: 'Semantic Kernel workflow started', auditId };
    }
    async stepWorkflow(ctx) {
        const auditId = crypto.randomUUID();
        this.emitCanonical('orchestrator:plan-step-begin', {
            workflowId: ctx.workflowId,
            stepId: ctx.stepId,
            stepIndex: ctx.stepIndex,
        });
        if (this.isCircuitOpen()) {
            this.emitCanonical('orchestrator:circuit-breaker-tripped', {
                workflowId: ctx.workflowId,
                stepId: ctx.stepId,
            });
            return { type: 'DENY', reason: 'Circuit breaker is open', auditId };
        }
        return { type: 'ALLOW', reason: 'Step permitted', auditId };
    }
    async completeWorkflow(ctx, result) {
        this.emitCanonical('orchestrator:workflow-complete', {
            workflowId: ctx.workflowId,
            success: result.success,
            summary: result.summary,
        });
    }
    // ---------------------------------------------------------------------------
    // Task / plan / delegation surfaces
    // ---------------------------------------------------------------------------
    async preTask(task) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        if (this.isCircuitOpen()) {
            const reason = 'Circuit breaker is open; task denied';
            this.emitCanonical('orchestrator:task-denied', { taskId: task.taskId, reason });
            return { type: ActionDecisionType.DENY, reason, auditId };
        }
        this.emitCanonical('orchestrator:task-approved', { taskId: task.taskId });
        return {
            type: ActionDecisionType.ALLOW,
            reason: `Task "${task.taskId}" approved via SemanticKernelAdapter`,
            auditId,
        };
    }
    async postTask(task, result) {
        this.emitCanonical('orchestrator:plan-step-end', { taskId: task.taskId, result });
    }
    async prePlan(plan) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        this.emitCanonical('orchestrator:plan-proposed', { planId: plan.planId });
        const maxSteps = this.skConfig.maxPlanSteps;
        if (maxSteps !== undefined && plan.steps.length > maxSteps) {
            const reason = `Plan has ${plan.steps.length} steps, exceeding the maximum of ${maxSteps}`;
            this.emitCanonical('orchestrator:plan-denied', { planId: plan.planId, reason });
            return { type: ActionDecisionType.DENY, reason, auditId };
        }
        try {
            this.validatePlanStructure(plan);
        }
        catch (err) {
            const reason = err instanceof Error ? err.message : String(err);
            this.emitCanonical('orchestrator:plan-denied', { planId: plan.planId, reason });
            return { type: ActionDecisionType.DENY, reason, auditId };
        }
        this.emitCanonical('orchestrator:plan-approved', { planId: plan.planId });
        return { type: ActionDecisionType.ALLOW, reason: 'Plan approved', auditId };
    }
    async postPlan(plan, result) {
        this.emitCanonical('orchestrator:workflow-complete', { planId: plan.planId, result });
    }
    async preDelegation(d) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        const restricted = d.permissions.filter((p) => this.skConfig.sensitiveFunctions.includes(p));
        if (restricted.length > 0) {
            const reason = `Skill delegation includes sensitive functions: ${restricted.join(', ')}`;
            this.emitCanonical('orchestrator:delegation-denied', {
                delegationId: d.delegationId,
                from: d.fromAgent.name,
                to: d.toAgent.name,
                restricted,
            });
            return {
                type: ActionDecisionType.DENY,
                reason,
                restrictedPermissions: restricted,
                auditId,
            };
        }
        this.emitCanonical('orchestrator:delegation-approved', {
            delegationId: d.delegationId,
            from: d.fromAgent.name,
            to: d.toAgent.name,
        });
        return {
            type: ActionDecisionType.ALLOW,
            reason: `Skill delegation from "${d.fromAgent.name}" to "${d.toAgent.name}" approved`,
            auditId,
        };
    }
    async postDelegation(d, result) {
        this.emitCanonical('orchestrator:delegation-approved', {
            delegationId: d.delegationId,
            result,
        });
    }
    async invokeRoleEdge(edge) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        this.emitCanonical('orchestrator:role-edge-invoked', {
            edgeId: edge.edgeId,
            fromRole: edge.fromRole,
            toRole: edge.toRole,
        });
        return { type: 'ALLOW', reason: 'SK role edge permitted', auditId };
    }
    // ---------------------------------------------------------------------------
    // Error translation
    // ---------------------------------------------------------------------------
    translateError(raw) {
        if (raw instanceof OrchestratorError)
            return raw;
        const message = raw instanceof Error ? raw.message : String(raw);
        if (message.includes('KernelFunctionNotFound') || message.includes('function not found')) {
            return new OrchestratorError({
                message: `Semantic Kernel function not found: ${message}`,
                code: 'SK_FUNCTION_NOT_FOUND',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
                raw,
            });
        }
        if (message.includes('PlanningException') || message.includes('planning')) {
            return new OrchestratorError({
                message: `Semantic Kernel planning error: ${message}`,
                code: 'SK_PLANNING_ERROR',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
                raw,
            });
        }
        if (message.includes('MemoryException') || message.includes('memory')) {
            return new OrchestratorError({
                message: `Semantic Kernel memory error: ${message}`,
                code: 'SK_MEMORY_ERROR',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
                raw,
            });
        }
        if (message.includes('timeout') || message.includes('Timeout')) {
            return new OrchestratorError({
                message: `Semantic Kernel invocation timeout: ${message}`,
                code: 'SK_TIMEOUT',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
                raw,
            });
        }
        return new OrchestratorError({
            message,
            code: 'SK_ERROR',
            orchestratorId: this.orchestratorId,
            adapterId: this.adapterId,
            raw,
        });
    }
    // ---------------------------------------------------------------------------
    // Capabilities
    // ---------------------------------------------------------------------------
    getOrchestratorCapabilities() {
        return {
            workflowGovernance: true,
            taskGovernance: true,
            planGovernance: true,
            delegationGovernance: true,
            roleEdgeGovernance: true,
            parallelExecution: false,
            nestedPlans: true,
            circuitBreaker: true,
        };
    }
}
//# sourceMappingURL=semantic-kernel.js.map