#!/usr/bin/env node
import { c as logger } from "./logger-4ntIRWmf.js";
//#region src/redteam/shared/runtimeTransform.ts
/**
* Runtime transform utility for applying strategy transforms per-turn.
*
* This module enables multi-turn attack providers (Hydra, Crescendo, etc.)
* to apply layer transforms (audio, base64, etc.) to each turn's prompt
* before sending to the target.
*
* It reuses existing strategy implementations, avoiding code duplication.
*/
/**
* Applies strategy transforms to a prompt at runtime (per-turn).
* This is used by multi-turn attack providers to transform each turn's
* output before sending to the target.
*
* @param prompt - The text prompt to transform
* @param injectVar - The variable name used for injection (e.g., 'query')
* @param layerConfigs - Array of layer configurations to apply in order
* @param strategies - The loaded strategies array (to avoid circular imports)
* @param context - Optional context metadata to pass to layer strategies
* @returns TransformResult with transformed prompt and audio metadata
*
* @example
* ```typescript
* // In Hydra provider:
* const result = await applyRuntimeTransforms(
*   attackPrompt,
*   'query',
*   ['audio', 'base64'],
*   Strategies,
*   { evaluationId: context?.evaluationId, purpose: context?.test?.metadata?.purpose }
* );
* // result.prompt = transformed, result.audio = { data, format } if audio
* ```
*/
async function applyRuntimeTransforms(prompt, injectVar, layerConfigs, strategies, context) {
	const originalPrompt = prompt;
	if (!layerConfigs?.length) return {
		prompt,
		originalPrompt
	};
	logger.debug(`[RuntimeTransform] Applying ${layerConfigs.length} transforms to prompt`, {
		hasContext: !!context,
		hasEvaluationId: !!context?.evaluationId,
		hasPurpose: !!context?.purpose
	});
	let testCase = {
		vars: { [injectVar]: prompt },
		assert: [],
		metadata: {
			pluginId: "runtime-transform",
			evaluationId: context?.evaluationId,
			testCaseId: context?.testCaseId,
			purpose: context?.purpose,
			goal: context?.goal
		}
	};
	let audioApplied = false;
	let imageApplied = false;
	for (const layer of layerConfigs) {
		const layerId = typeof layer === "string" ? layer : layer.id;
		const layerConfig = typeof layer === "string" ? {} : layer.config || {};
		const strategy = strategies.find((s) => s.id === layerId);
		if (!strategy) {
			logger.warn(`[RuntimeTransform] Unknown layer strategy: ${layerId}, skipping`);
			continue;
		}
		logger.debug(`[RuntimeTransform] Applying layer: ${layerId}`);
		if (layerId === "audio") audioApplied = true;
		else if (layerId === "image") imageApplied = true;
		try {
			const transformed = (await strategy.action([testCase], injectVar, layerConfig))[0];
			if (transformed) testCase = {
				...transformed,
				metadata: {
					...testCase.metadata,
					...transformed.metadata,
					pluginId: testCase.metadata.pluginId
				}
			};
			else logger.warn(`[RuntimeTransform] Layer ${layerId} returned no test cases`);
		} catch (error) {
			const errorMsg = `Transform ${layerId} failed: ${error.message || "Unknown error"}`;
			logger.error(`[RuntimeTransform] ${errorMsg}`, { error });
			return {
				prompt: originalPrompt,
				originalPrompt,
				error: errorMsg
			};
		}
	}
	const transformedPrompt = String(testCase.vars?.[injectVar] ?? prompt);
	logger.debug(`[RuntimeTransform] Transform complete`, {
		originalLength: prompt.length,
		resultLength: transformedPrompt.length,
		layersApplied: layerConfigs.length,
		audioApplied,
		imageApplied
	});
	const displayVars = {};
	if (testCase.vars) {
		for (const [key, value] of Object.entries(testCase.vars)) if (key !== injectVar && typeof value === "string") displayVars[key] = value;
	}
	const result = {
		prompt: transformedPrompt,
		originalPrompt,
		...Object.keys(displayVars).length > 0 && { displayVars },
		metadata: testCase.metadata
	};
	const audioStorageKey = testCase.metadata?.audioStorageKey;
	const imageStorageKey = testCase.metadata?.imageStorageKey;
	if (audioApplied && transformedPrompt !== originalPrompt) {
		const dataUrlMatch = transformedPrompt.match(/^data:audio\/([^;]+);base64,(.+)$/);
		if (dataUrlMatch) result.audio = {
			data: dataUrlMatch[2],
			format: dataUrlMatch[1]
		};
		else result.audio = {
			data: transformedPrompt,
			format: "mp3"
		};
		if (audioStorageKey) logger.debug(`[RuntimeTransform] Audio stored to: ${audioStorageKey} (will be sanitized before DB save)`);
	}
	if (imageApplied && transformedPrompt !== originalPrompt) {
		const dataUrlMatch = transformedPrompt.match(/^data:image\/([^;]+);base64,(.+)$/);
		if (dataUrlMatch) result.image = {
			data: dataUrlMatch[2],
			format: dataUrlMatch[1]
		};
		else result.image = {
			data: transformedPrompt,
			format: "png"
		};
		if (imageStorageKey) logger.debug(`[RuntimeTransform] Image stored to: ${imageStorageKey} (will be sanitized before DB save)`);
	}
	return result;
}
//#endregion
export { applyRuntimeTransforms as t };

//# sourceMappingURL=runtimeTransform-DSR6tS6g.js.map