"use strict";
/**
 * HaystackAdapter -- Orchestrator adapter for Haystack Agents (deepset).
 *
 * Hook surface: Haystack from deepset is a Pipeline-based framework where agents
 * are Nodes connected by Edges. Our adapter hooks at the Pipeline execution
 * boundary. Customers wire the adapter:
 *
 *   const adapter = new HaystackAdapter(cfg);
 *   adapter.initialize(orchCfg);
 *
 *   // At pipeline start:
 *   await adapter.pipelineStart(pipelineId, pipelineName, contextSnapshot);
 *
 *   // Before each node execution:
 *   await adapter.nodeStart(pipelineId, nodeId, nodeType, inputs);
 *
 *   // After each node execution:
 *   await adapter.nodeEnd(pipelineId, nodeId, nodeType, outputs);
 *
 *   // Before a PromptNode LLM invocation (per-backend):
 *   await adapter.promptNodeCall(pipelineId, nodeId, backendId, model, prompt);
 *
 *   // After a PromptNode result:
 *   await adapter.promptNodeResult(pipelineId, nodeId, backendId, result);
 *
 *   // When running in eval mode:
 *   await adapter.evalStep(pipelineId, evalSetId, metricName, result);
 *
 *   // At pipeline end:
 *   await adapter.pipelineEnd(pipelineId, outcome);
 *
 * Haystack-specific considerations:
 *   - Pipeline-based execution: our adapter hooks at the Pipeline execution boundary.
 *   - Evaluation is a first-class concept; governance events capture eval-stage
 *     metadata (which eval set, which metric) when agents run in eval mode.
 *     Eval-mode events write to a SEPARATE eval audit path, not the production chain.
 *   - Document retrieval via Haystack's Retriever node has the same ingress PHI
 *     classification story as LlamaIndex.
 *   - PromptNode can route to multiple LLM backends per pipeline run. Each backend
 *     invocation is surfaced as a distinct canonical event so provider-compliance
 *     checks fire per-backend.
 *   - European deployment default: GDPR pack is bound unless explicitly disabled.
 *     EU-specific data classes (right to erasure, DPIA records) surface in audit events.
 *
 * Regulatory positioning: HIPAA + GDPR dual-regulated buyer. German maintainer.
 * Natural fit for healthcare-fintech cross-border deployments.
 *
 * No live Haystack Python SDK installed. All framework surfaces are shims.
 * DEFERRED-HAYSTACK-V1-API: Verify exact hook surface when Haystack v2 stabilises
 * its TypeScript event-bus API (beta as of 2026-04-23).
 *
 * Pentest gate:
 *   PT-ADAPT-HAYSTACK-1: multi-backend pipeline with one non-BAA provider blocks
 *     the full pipeline when HIPAA binding is active.
 *   PT-ADAPT-HAYSTACK-2: GDPR right-to-erasure request surfaces on the audit chain.
 *   PT-ADAPT-HAYSTACK-3: eval-mode agent writes to the eval audit path, not the
 *     production chain.
 *
 * Spec: P3-SUB-ADAPT-05
 * @connexum/ai-governance
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.HaystackAdapter = exports.HAYSTACK_BAA_BACKENDS = exports.HaystackGdprErasureRequestEvent = exports.HaystackNonBaaProviderError = exports.HaystackUnboundDataError = void 0;
const crypto = __importStar(require("crypto"));
const base_1 = require("./base");
const index_1 = require("./index");
const index_2 = require("../adapters/index");
const index_3 = require("../errors/index");
Object.defineProperty(exports, "HaystackUnboundDataError", { enumerable: true, get: function () { return index_3.HaystackUnboundDataError; } });
/**
 * Thrown when a multi-backend pipeline includes a provider that has no BAA
 * agreement, under an active HIPAA binding.
 */
class HaystackNonBaaProviderError extends Error {
    pipelineId;
    backendId;
    constructor(pipelineId, backendId) {
        super(`Haystack pipeline "${pipelineId}" PromptNode routes to backend "${backendId}" ` +
            'which has no BAA agreement. HIPAA pack binding is active. ' +
            'Multi-backend pipeline blocked -- all backends must be BAA-covered under HIPAA.');
        this.name = 'HaystackNonBaaProviderError';
        this.pipelineId = pipelineId;
        this.backendId = backendId;
    }
}
exports.HaystackNonBaaProviderError = HaystackNonBaaProviderError;
/**
 * Emitted when a GDPR right-to-erasure (Article 17) request surfaces on the
 * audit chain during a pipeline run. This is not a blocking error but an
 * audit-priority event requiring compliance officer action.
 */
class HaystackGdprErasureRequestEvent extends Error {
    pipelineId;
    subjectId;
    constructor(pipelineId, subjectId) {
        super(`Haystack pipeline "${pipelineId}" encountered a GDPR Art. 17 right-to-erasure ` +
            `request for subject "${subjectId}". Surfaced to audit chain and compliance queue. ` +
            'Processing pipeline is PAUSED pending erasure confirmation.');
        this.name = 'HaystackGdprErasureRequestEvent';
        this.pipelineId = pipelineId;
        this.subjectId = subjectId;
    }
}
exports.HaystackGdprErasureRequestEvent = HaystackGdprErasureRequestEvent;
// ---------------------------------------------------------------------------
// BAA-covered backend registry
// ---------------------------------------------------------------------------
/**
 * Backend provider IDs with documented HIPAA BAA coverage.
 * A backend NOT in this set triggers HaystackNonBaaProviderError under HIPAA.
 *
 * DEFERRED-HAYSTACK-V1-API: Vera / Legal must verify BAA status per provider
 * before any production HIPAA deployment. This list is a known-good starting point.
 */
exports.HAYSTACK_BAA_BACKENDS = new Set([
    'openai', // Azure OpenAI with BAA (not direct OpenAI API)
    'azure-openai', // Azure OpenAI (BAA available via Microsoft)
    'bedrock', // AWS Bedrock (HIPAA BAA via AWS)
    'vertex-ai', // Google Vertex AI (HIPAA BAA via Google Cloud)
    'anthropic-vertex', // Anthropic via Vertex AI (inherits Google Cloud BAA)
    'azure-ml', // Azure ML (BAA via Microsoft)
]);
// ---------------------------------------------------------------------------
// HaystackAdapter
// ---------------------------------------------------------------------------
class HaystackAdapter extends base_1.BaseOrchestratorAdapter {
    adapterId = 'haystack';
    orchestratorId = 'haystack';
    haystackConfig;
    /** Active pipelines: pipelineId -> contextSnapshot */
    activePipelines = new Map();
    /** Per-pipeline node execution counters */
    nodeCounters = new Map();
    /** Per-pipeline backend call counters */
    backendCallCounters = new Map();
    /**
     * Separate eval audit buffer for eval-mode pipelines.
     * Eval events go here, not to the production canonicalEvents buffer.
     * This satisfies PT-ADAPT-HAYSTACK-3.
     */
    evalAuditEvents = [];
    constructor(config) {
        super();
        this.haystackConfig = {
            enforceAllBackendsBaa: true,
            gdprDefaultActive: true,
            pauseOnErasureRequest: true,
            enforcePackBinding: true,
            ...config,
        };
    }
    // ---------------------------------------------------------------------------
    // pipelineStart -- gate at Haystack pipeline execution start
    // ---------------------------------------------------------------------------
    /**
     * Called when a Haystack pipeline starts.
     *   1. Pipeline registration check
     *   2. Pack-binding resolver
     *   3. Multi-backend BAA check (all backends must be BAA-covered under HIPAA)
     *   4. GDPR default application
     *   5. Eval-mode routing (eval events -> eval audit path)
     *
     * Throws HaystackUnboundDataError or HaystackNonBaaProviderError if denied.
     */
    async pipelineStart(pipelineId, pipelineName, contextSnapshot) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        // -- Circuit breaker -------------------------------------------------------
        if (this.isCircuitOpen()) {
            const reason = 'Circuit breaker is open; Haystack pipeline denied';
            this.emitCanonical('orchestrator:task-denied', { pipelineId, pipelineName, reason });
            this.recordFailure();
            throw new index_1.OrchestratorError({
                message: reason,
                code: 'HAYSTACK_CIRCUIT_OPEN',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
            });
        }
        // -- Pipeline registration check ------------------------------------------
        const isRegistered = this.haystackConfig.registeredPipelines.length === 0
            ? false
            : this.haystackConfig.registeredPipelines.some((prefix) => pipelineId.startsWith(prefix));
        if (!isRegistered) {
            const reason = `Haystack pipeline "${pipelineId}" is not registered`;
            this.emitCanonical('orchestrator:task-denied', { pipelineId, pipelineName, reason });
            this.recordFailure();
            throw new index_1.OrchestratorError({
                message: reason,
                code: 'HAYSTACK_UNREGISTERED_PIPELINE',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
            });
        }
        // -- Pack-binding resolver -------------------------------------------------
        if (this.haystackConfig.enforcePackBinding !== false &&
            (!contextSnapshot.packBinding || contextSnapshot.packBinding.length === 0)) {
            this.emitCanonical('orchestrator:task-denied', {
                pipelineId,
                pipelineName,
                reason: 'Missing pack binding at Haystack pipelineStart',
            });
            this.recordFailure();
            throw new index_3.HaystackUnboundDataError(pipelineId, 'pipelineStart');
        }
        // -- Multi-backend BAA check (PT-ADAPT-HAYSTACK-1) -------------------------
        const hipaaActive = this.hasHipaaBinding(contextSnapshot.packBinding);
        if (hipaaActive && this.haystackConfig.enforceAllBackendsBaa !== false) {
            for (const backendId of contextSnapshot.backendIds) {
                const isApproved = this.haystackConfig.approvedBackends.includes(backendId);
                const hasBaa = exports.HAYSTACK_BAA_BACKENDS.has(backendId);
                if (!isApproved || !hasBaa) {
                    const reason = `Haystack pipeline "${pipelineId}" includes backend "${backendId}" ` +
                        `which is ${!isApproved ? 'not on the approved list' : 'not on the BAA-covered list'}. ` +
                        'HIPAA pack binding is active. All backends must have BAA coverage. ' +
                        'Entire pipeline blocked (enforceAllBackendsBaa=true).';
                    this.emitCanonical('orchestrator:task-denied', {
                        pipelineId,
                        pipelineName,
                        backendId,
                        approvedBackends: this.haystackConfig.approvedBackends,
                        baaBackends: [...exports.HAYSTACK_BAA_BACKENDS],
                        reason,
                    });
                    this.recordFailure();
                    throw new HaystackNonBaaProviderError(pipelineId, backendId);
                }
            }
        }
        // -- GDPR default application (European deployment assumption) -------------
        const gdprActive = contextSnapshot.gdprActive !== false &&
            this.haystackConfig.gdprDefaultActive !== false;
        // -- Register active pipeline ---------------------------------------------
        this.activePipelines.set(pipelineId, { ...contextSnapshot, gdprActive });
        this.nodeCounters.set(pipelineId, 0);
        this.backendCallCounters.set(pipelineId, 0);
        // -- Emit (eval-mode -> eval path; production -> canonical) ---------------
        if (contextSnapshot.isEvalMode) {
            this.evalAuditEvents.push({
                pipelineId,
                event: {
                    type: 'eval:pipeline-start',
                    pipelineId,
                    pipelineName,
                    packBinding: contextSnapshot.packBinding,
                    backendIds: contextSnapshot.backendIds,
                    gdprActive,
                    auditId,
                    timestamp: new Date().toISOString(),
                },
            });
        }
        else {
            this.emitCanonical('orchestrator:workflow-start', {
                pipelineId,
                pipelineName,
                packBinding: contextSnapshot.packBinding,
                backendIds: contextSnapshot.backendIds,
                gdprActive,
                hipaaActive,
                isEvalMode: false,
                auditId,
            });
        }
        this.recordSuccess();
        return {
            type: 'ALLOW',
            reason: `Haystack pipeline "${pipelineId}" approved (pack: ${contextSnapshot.packBinding.join(',')}, ` +
                `backends: ${contextSnapshot.backendIds.join(',')})`,
            auditId,
        };
    }
    // ---------------------------------------------------------------------------
    // nodeStart -- gate at Haystack node execution
    // ---------------------------------------------------------------------------
    /**
     * Called before each Haystack node executes.
     *   1. Active-pipeline check
     *   2. Node counter (runaway detection)
     *   3. Sensitive-node REQUIRE_APPROVAL routing
     *   4. Retriever node: PHI classification on inputs
     */
    async nodeStart(pipelineId, nodeId, nodeType, inputs) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        if (!this.activePipelines.has(pipelineId)) {
            const reason = `Haystack pipeline "${pipelineId}" called nodeStart without pipelineStart`;
            this.emitOrEval(pipelineId, 'orchestrator:task-denied', { pipelineId, nodeId, reason });
            throw new index_1.OrchestratorError({
                message: reason,
                code: 'HAYSTACK_NO_ACTIVE_PIPELINE',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
            });
        }
        // -- Node counter ----------------------------------------------------------
        const count = (this.nodeCounters.get(pipelineId) ?? 0) + 1;
        this.nodeCounters.set(pipelineId, count);
        const maxNodes = this.haystackConfig.maxNodesPerPipeline;
        if (maxNodes !== undefined && count > maxNodes) {
            const reason = `Haystack pipeline "${pipelineId}" exceeded maxNodesPerPipeline (${maxNodes}). Runaway suppressed.`;
            this.emitOrEval(pipelineId, 'orchestrator:task-denied', { pipelineId, nodeId, count, reason });
            this.recordFailure();
            return { type: index_2.ActionDecisionType.DENY, reason, auditId };
        }
        // -- Retriever node: PHI scan on documents --------------------------------
        if (nodeType === 'Retriever' && inputs.documents) {
            for (const doc of inputs.documents) {
                const content = typeof doc.content === 'string' ? doc.content : '';
                if (this.containsPhiPattern(content)) {
                    const snapshot = this.activePipelines.get(pipelineId);
                    const hipaaActive = this.hasHipaaBinding(snapshot.packBinding);
                    this.emitOrEval(pipelineId, 'orchestrator:task-denied', {
                        pipelineId,
                        nodeId,
                        nodeType,
                        docId: doc.id ?? 'unknown',
                        reason: `Haystack Retriever node "${nodeId}" input document contains PHI. ` +
                            `HIPAA active: ${hipaaActive}. Surfaced to compliance review.`,
                        layer: 'retriever-phi-scan',
                    });
                    if (hipaaActive) {
                        this.recordFailure();
                        return { type: index_2.ActionDecisionType.DENY, reason: 'PHI in retriever input under HIPAA binding', auditId };
                    }
                }
            }
        }
        // -- Sensitive-node approval routing --------------------------------------
        if (this.haystackConfig.sensitiveNodes.includes(nodeId)) {
            const tier = 'human-reviewer';
            const queueId = this.config.reviewerQueues[tier];
            if (!queueId) {
                const reason = `Haystack node "${nodeId}" is sensitive but no human-reviewer queue binding exists. Fail closed.`;
                this.emitOrEval(pipelineId, 'orchestrator:task-denied', { pipelineId, nodeId, reason });
                this.recordFailure();
                return { type: index_2.ActionDecisionType.DENY, reason, auditId };
            }
            this.emitOrEval(pipelineId, 'orchestrator:reviewer-routed', {
                pipelineId,
                nodeId,
                nodeType,
                tier,
                queueId,
                layer: 'haystack',
            });
            return {
                type: index_2.ActionDecisionType.REQUIRE_APPROVAL,
                reason: `Haystack node "${nodeId}" requires human-reviewer approval`,
                auditId,
                metadata: { reviewerTier: tier, layer: 'haystack', pipelineId, nodeId },
            };
        }
        // -- Approve ---------------------------------------------------------------
        this.emitOrEval(pipelineId, 'orchestrator:task-approved', {
            pipelineId,
            nodeId,
            nodeType,
            count,
            layer: 'haystack',
        });
        return {
            type: index_2.ActionDecisionType.ALLOW,
            reason: `Haystack node "${nodeId}" (${nodeType}) approved for pipeline "${pipelineId}"`,
            auditId,
        };
    }
    // ---------------------------------------------------------------------------
    // nodeEnd -- post-node audit + output classifier
    // ---------------------------------------------------------------------------
    async nodeEnd(pipelineId, nodeId, nodeType, outputs) {
        this.assertInitialized();
        const outputText = this.extractTextFromPayload(outputs);
        const hasSuspiciousOutput = this.containsPhiPattern(outputText);
        this.emitOrEval(pipelineId, 'orchestrator:plan-step-end', {
            pipelineId,
            nodeId,
            nodeType,
            suspiciousOutput: hasSuspiciousOutput,
            layer: 'haystack',
        });
        if (hasSuspiciousOutput) {
            this.emitOrEval(pipelineId, 'orchestrator:task-denied', {
                pipelineId,
                nodeId,
                nodeType,
                reason: `Haystack node "${nodeId}" output contains possible PHI/PAN. ` +
                    'Surfaced to compliance review queue.',
                layer: 'post-node-classifier',
            });
        }
    }
    // ---------------------------------------------------------------------------
    // promptNodeCall -- per-backend invocation gate (PT-ADAPT-HAYSTACK-1)
    // ---------------------------------------------------------------------------
    /**
     * Called before each PromptNode backend invocation.
     * Each backend invocation is a DISTINCT canonical event for per-backend
     * provider-compliance checks.
     *
     * Under a HIPAA binding, non-BAA backends block immediately.
     */
    async promptNodeCall(pipelineId, nodeId, backendId, model, call) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        if (!this.activePipelines.has(pipelineId)) {
            const reason = `Haystack pipeline "${pipelineId}" called promptNodeCall without pipelineStart`;
            this.emitOrEval(pipelineId, 'orchestrator:task-denied', { pipelineId, nodeId, backendId, reason });
            throw new index_1.OrchestratorError({
                message: reason,
                code: 'HAYSTACK_NO_ACTIVE_PIPELINE',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
            });
        }
        const snapshot = this.activePipelines.get(pipelineId);
        const hipaaActive = this.hasHipaaBinding(snapshot.packBinding);
        // -- Per-backend BAA check (per-invocation, not just at pipeline start) ---
        if (hipaaActive && !exports.HAYSTACK_BAA_BACKENDS.has(backendId)) {
            const reason = `Haystack PromptNode "${nodeId}" is invoking backend "${backendId}" ` +
                'which is not on the HIPAA BAA-covered backend list. ' +
                'Provider-compliance check fires per-backend invocation.';
            this.emitOrEval(pipelineId, 'orchestrator:task-denied', {
                pipelineId,
                nodeId,
                backendId,
                model,
                baaBackends: [...exports.HAYSTACK_BAA_BACKENDS],
                reason,
            });
            this.recordFailure();
            throw new HaystackNonBaaProviderError(pipelineId, backendId);
        }
        // -- Prompt PHI scan (egress guard) ----------------------------------------
        if (this.containsPhiPattern(call.prompt)) {
            const snapshot2 = this.activePipelines.get(pipelineId);
            const hipaa2 = this.hasHipaaBinding(snapshot2.packBinding);
            this.emitOrEval(pipelineId, 'orchestrator:task-denied', {
                pipelineId,
                nodeId,
                backendId,
                model,
                reason: `Haystack PromptNode "${nodeId}" prompt contains PHI/PAN before sending to backend "${backendId}". ` +
                    `HIPAA active: ${hipaa2}. Blocked at egress guard.`,
                layer: 'prompt-phi-egress',
            });
            this.recordFailure();
            return { type: index_2.ActionDecisionType.DENY, reason: `PHI detected in prompt sent to backend "${backendId}"`, auditId };
        }
        // Track backend calls
        const callCount = (this.backendCallCounters.get(pipelineId) ?? 0) + 1;
        this.backendCallCounters.set(pipelineId, callCount);
        this.emitOrEval(pipelineId, 'orchestrator:plan-step-begin', {
            pipelineId,
            nodeId,
            backendId,
            model,
            packBinding: snapshot.packBinding,
            hipaaActive,
            backendCallCount: callCount,
            layer: 'haystack-prompt-node',
        });
        return {
            type: index_2.ActionDecisionType.ALLOW,
            reason: `Haystack PromptNode "${nodeId}" backend "${backendId}" (model: ${model}) approved`,
            auditId,
        };
    }
    // ---------------------------------------------------------------------------
    // promptNodeResult -- per-backend result audit + output classifier
    // ---------------------------------------------------------------------------
    async promptNodeResult(pipelineId, nodeId, backendId, result) {
        this.assertInitialized();
        const hasExfil = this.containsPhiPattern(result.result);
        this.emitOrEval(pipelineId, 'orchestrator:plan-step-end', {
            pipelineId,
            nodeId,
            backendId,
            durationMs: result.durationMs ?? null,
            promptTokens: result.usage?.promptTokens ?? null,
            completionTokens: result.usage?.completionTokens ?? null,
            outputExfiltrationFlag: hasExfil,
            layer: 'haystack-prompt-result',
        });
        if (hasExfil) {
            this.emitOrEval(pipelineId, 'orchestrator:task-denied', {
                pipelineId,
                nodeId,
                backendId,
                reason: `Haystack PromptNode "${nodeId}" backend "${backendId}" result contains possible PHI/PAN. ` +
                    'Flagged for compliance review.',
                layer: 'post-prompt-classifier',
            });
        }
    }
    // ---------------------------------------------------------------------------
    // evalStep -- eval-mode governance (PT-ADAPT-HAYSTACK-3)
    // ---------------------------------------------------------------------------
    /**
     * Called when a Haystack eval-mode agent executes an evaluation step.
     * Eval events write to the SEPARATE eval audit path, not the production chain.
     * This ensures eval runs do not contaminate the production compliance audit trail.
     *
     * Returns the eval step metadata for test harness inspection.
     */
    async evalStep(pipelineId, evalSetId, metricName, result) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        const snapshot = this.activePipelines.get(pipelineId);
        // Always write eval events to the eval path
        this.evalAuditEvents.push({
            pipelineId,
            event: {
                type: 'eval:step',
                pipelineId,
                evalSetId,
                metricName,
                metricValue: result.metricValue,
                passed: result.passed,
                sampleCount: result.sampleResults?.length ?? null,
                packBinding: snapshot?.packBinding ?? [],
                auditId,
                timestamp: new Date().toISOString(),
            },
        });
        // Do NOT call emitCanonical -- eval events stay on eval path only
        // (This is the key invariant for PT-ADAPT-HAYSTACK-3)
        return { auditId, writtenToEvalPath: true };
    }
    /**
     * Get the eval audit events buffer (for testing and compliance officer review).
     * These are separate from production canonical events.
     */
    getEvalAuditEvents() {
        return [...this.evalAuditEvents];
    }
    // ---------------------------------------------------------------------------
    // gdprErasureRequest -- GDPR Art. 17 right-to-erasure surface
    // ---------------------------------------------------------------------------
    /**
     * Called when a pipeline encounters a GDPR Art. 17 right-to-erasure request.
     * Surfaces the request on the audit chain and optionally pauses the pipeline.
     *
     * This is one of the EU-specific data classes surfaced in audit events per
     * the Haystack European deployment assumption.
     *
     * Throws HaystackGdprErasureRequestEvent when pauseOnErasureRequest=true.
     */
    async gdprErasureRequest(pipelineId, subjectId, requestMetadata) {
        this.assertInitialized();
        const auditId = crypto.randomUUID();
        // Erasure requests always go to the production audit chain (not eval path)
        this.emitCanonical('orchestrator:reviewer-routed', {
            pipelineId,
            subjectId,
            requestType: 'gdpr-art17-erasure',
            euDataClass: 'ErasureRequest',
            requestMetadata: requestMetadata ?? null,
            gdprArticle: 'Art. 17 Right to Erasure (Right to be Forgotten)',
            auditId,
            layer: 'gdpr-erasure',
        });
        if (this.haystackConfig.pauseOnErasureRequest !== false) {
            throw new HaystackGdprErasureRequestEvent(pipelineId, subjectId);
        }
        return { auditId, paused: false };
    }
    // ---------------------------------------------------------------------------
    // pipelineEnd -- terminal audit event sealing
    // ---------------------------------------------------------------------------
    async pipelineEnd(pipelineId, outcome) {
        this.assertInitialized();
        const snapshot = this.activePipelines.get(pipelineId);
        const nodeCount = this.nodeCounters.get(pipelineId) ?? 0;
        const backendCalls = this.backendCallCounters.get(pipelineId) ?? 0;
        const isEvalMode = snapshot?.isEvalMode ?? false;
        if (isEvalMode) {
            this.evalAuditEvents.push({
                pipelineId,
                event: {
                    type: 'eval:pipeline-end',
                    pipelineId,
                    success: outcome.success,
                    summary: outcome.summary ?? (outcome.success ? 'Eval pipeline complete' : 'Eval pipeline failed'),
                    nodesExecuted: outcome.totalNodesExecuted ?? nodeCount,
                    backendCalls: outcome.totalBackendCalls ?? backendCalls,
                    error: outcome.error ?? null,
                    timestamp: new Date().toISOString(),
                },
            });
        }
        else {
            this.emitCanonical('orchestrator:workflow-complete', {
                pipelineId,
                success: outcome.success,
                summary: outcome.summary ?? (outcome.success ? 'Haystack pipeline complete' : 'Haystack pipeline failed'),
                durationMs: outcome.durationMs ?? null,
                error: outcome.error ?? null,
                nodesExecuted: outcome.totalNodesExecuted ?? nodeCount,
                backendCalls: outcome.totalBackendCalls ?? backendCalls,
                packBinding: snapshot?.packBinding ?? [],
            });
        }
        this.activePipelines.delete(pipelineId);
        this.nodeCounters.delete(pipelineId);
        this.backendCallCounters.delete(pipelineId);
        if (outcome.success) {
            this.recordSuccess();
        }
        else {
            this.recordFailure();
        }
    }
    // ---------------------------------------------------------------------------
    // Private helpers
    // ---------------------------------------------------------------------------
    /** Emit to eval path if in eval mode, otherwise to production canonical events. */
    emitOrEval(pipelineId, eventName, payload) {
        const snapshot = this.activePipelines.get(pipelineId);
        if (snapshot?.isEvalMode) {
            this.evalAuditEvents.push({
                pipelineId,
                event: { type: eventName, ...payload, timestamp: new Date().toISOString() },
            });
        }
        else {
            this.emitCanonical(eventName, payload);
        }
    }
    hasHipaaBinding(packBinding) {
        return packBinding.some((p) => p.toLowerCase().includes('hipaa') || p.toLowerCase().includes('hitech'));
    }
    extractTextFromPayload(payload) {
        const parts = [];
        if (typeof payload.result === 'string')
            parts.push(payload.result);
        if (typeof payload.query === 'string')
            parts.push(payload.query);
        if (typeof payload.prompt === 'string')
            parts.push(payload.prompt);
        if (Array.isArray(payload.documents)) {
            for (const doc of payload.documents) {
                if (typeof doc?.content === 'string')
                    parts.push(doc.content);
            }
        }
        return parts.join(' ');
    }
    containsPhiPattern(text) {
        if (/\b\d{3}[-\s]?\d{2}[-\s]?\d{4}\b/.test(text))
            return true;
        if (/\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{1,4}\b/.test(text))
            return true;
        if (/\b(patient_id|mrn|dob|date_of_birth|diagnosis|ssn|npi)\s*[:=]/i.test(text))
            return true;
        return false;
    }
    // ---------------------------------------------------------------------------
    // OrchestratorAdapter surface -- workflow lifecycle wrappers
    // ---------------------------------------------------------------------------
    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: 'Haystack 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,
            durationMs: result.durationMs,
        });
    }
    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: index_2.ActionDecisionType.DENY, reason, auditId };
        }
        this.emitCanonical('orchestrator:task-approved', {
            taskId: task.taskId,
            agentName: task.assignedAgent.name,
        });
        return { type: index_2.ActionDecisionType.ALLOW, reason: `Task "${task.taskId}" approved via HaystackAdapter`, 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 });
        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: index_2.ActionDecisionType.DENY, reason, auditId };
        }
        this.emitCanonical('orchestrator:plan-approved', { planId: plan.planId });
        return { type: index_2.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.haystackConfig.sensitiveNodes.includes(p));
        if (restricted.length > 0) {
            const reason = `Haystack delegation includes restricted permissions: ${restricted.join(', ')}`;
            this.emitCanonical('orchestrator:delegation-denied', {
                delegationId: d.delegationId,
                from: d.fromAgent.name,
                to: d.toAgent.name,
                restricted,
            });
            return { type: index_2.ActionDecisionType.DENY, reason, restrictedPermissions: restricted, auditId };
        }
        this.emitCanonical('orchestrator:delegation-approved', {
            delegationId: d.delegationId,
            from: d.fromAgent.name,
            to: d.toAgent.name,
        });
        return { type: index_2.ActionDecisionType.ALLOW, reason: 'Delegation 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: 'Haystack role edge permitted', auditId };
    }
    translateError(raw) {
        if (raw instanceof index_1.OrchestratorError)
            return raw;
        const message = raw instanceof Error ? raw.message : String(raw);
        if (message.includes('HaystackNonBaaProviderError') || message.includes('BAA-covered backend')) {
            return new index_1.OrchestratorError({
                message: `Haystack non-BAA provider: ${message}`,
                code: 'HAYSTACK_NON_BAA_PROVIDER',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
                raw,
            });
        }
        if (message.includes('HaystackGdprErasureRequestEvent') || message.includes('right-to-erasure')) {
            return new index_1.OrchestratorError({
                message: `Haystack GDPR erasure request: ${message}`,
                code: 'HAYSTACK_GDPR_ERASURE_REQUEST',
                orchestratorId: this.orchestratorId,
                adapterId: this.adapterId,
                raw,
            });
        }
        return new index_1.OrchestratorError({
            message,
            code: 'HAYSTACK_ERROR',
            orchestratorId: this.orchestratorId,
            adapterId: this.adapterId,
            raw,
        });
    }
    getOrchestratorCapabilities() {
        return {
            workflowGovernance: true,
            taskGovernance: true,
            planGovernance: true,
            delegationGovernance: true,
            roleEdgeGovernance: true,
            parallelExecution: true,
            nestedPlans: true,
            circuitBreaker: true,
        };
    }
}
exports.HaystackAdapter = HaystackAdapter;
//# sourceMappingURL=haystack.js.map