import { o as logger } from "./logger-CfDSdx1q.js";
import { W as VERSION, t as fetchWithProxy } from "./fetch-CHx36OdV.js";
import { t as invariant } from "./invariant-vgHWClmd.js";
import { s as getUserEmail } from "./accounts-Dz-Gsg_B.js";
import { o as createEmptyTokenUsage, r as accumulateResponseTokenUsage } from "./tokenUsageUtils-BcRzoYR7.js";
import { c as neverGenerateRemote, i as getRemoteGenerationUrl, n as getRemoteGenerationExplicitlyDisabledError, r as getRemoteGenerationHeaders } from "./remoteGeneration-BNr30mu3.js";
import { o as getSessionId } from "./util-BlwVF-50.js";
import { i as throwIfTargetPromptExceedsMaxChars } from "./promptLength-VChEPvhr.js";
import { n as renderPrompt } from "./server/index.js";
import chalk from "chalk";
import dedent from "dedent";
import async from "async";
//#region src/redteam/providers/bestOfN.ts
var BestOfNProvider = class {
	config;
	id() {
		return "promptfoo:redteam:best-of-n";
	}
	constructor(options = {}) {
		if (neverGenerateRemote()) throw new Error(getRemoteGenerationExplicitlyDisabledError("Best-of-N strategy"));
		invariant(typeof options.injectVar === "string", "Expected injectVar to be set");
		this.config = {
			injectVar: options.injectVar,
			maxConcurrency: options.maxConcurrency || 3,
			nSteps: options.nSteps,
			maxCandidatesPerStep: options.maxCandidatesPerStep
		};
	}
	async callApi(_prompt, context, options) {
		logger.debug("[Best-of-N] callApi context", { context });
		invariant(context?.originalProvider, "Expected originalProvider to be set");
		invariant(context?.vars, "Expected vars to be set");
		const targetProvider = context.originalProvider;
		const targetTokenUsage = createEmptyTokenUsage();
		const sessionIds = [];
		try {
			const data = await (await fetchWithProxy(getRemoteGenerationUrl(), {
				method: "POST",
				headers: getRemoteGenerationHeaders(),
				body: JSON.stringify({
					task: "jailbreak:best-of-n",
					prompt: context.vars[this.config.injectVar],
					nSteps: this.config.nSteps,
					maxCandidatesPerStep: this.config.maxCandidatesPerStep,
					version: VERSION,
					email: getUserEmail()
				})
			}, options?.abortSignal)).json();
			invariant(Array.isArray(data.modifiedPrompts), "Expected modifiedPrompts array in response");
			logger.debug(dedent`
          ${chalk.bold.green("Best-of-N candidates:")}
          ${chalk.cyan(JSON.stringify(data.modifiedPrompts, null, 2))}
        `);
			let successfulResponse = null;
			let lastResponse = null;
			let currentStep = 0;
			await async.eachLimit(data.modifiedPrompts, this.config.maxConcurrency, async (candidatePrompt) => {
				if (successfulResponse) return;
				if (typeof candidatePrompt !== "string") {
					logger.warn("[Best-of-N] Skipping non-string candidate prompt from remote generation", {
						component: "Best-of-N",
						event: "SkippingCandidatePrompt",
						reason: "non-string",
						candidatePromptType: typeof candidatePrompt
					});
					return;
				}
				const unsafeCandidateScheme = /^\s*(file:\/\/|package:)/i.exec(candidatePrompt)?.[1].toLowerCase();
				if (unsafeCandidateScheme) {
					const schemeLabel = unsafeCandidateScheme.startsWith("file") ? "file://" : "package:";
					logger.warn(`[Best-of-N] Skipping unsafe ${schemeLabel} candidate prompt from remote generation`, {
						component: "Best-of-N",
						event: "SkippingCandidatePrompt",
						reason: schemeLabel === "file://" ? "unsafe-file-protocol" : "unsafe-package-protocol"
					});
					return;
				}
				const targetVars = {
					...context.vars,
					[this.config.injectVar]: candidatePrompt
				};
				const renderedPrompt = await renderPrompt(context.prompt, targetVars, context.filters, targetProvider, [this.config.injectVar]);
				try {
					throwIfTargetPromptExceedsMaxChars(renderedPrompt);
					const response = await targetProvider.callApi(renderedPrompt, context, options);
					const sessionId = getSessionId(response, context);
					if (sessionId) sessionIds.push(sessionId);
					lastResponse = response;
					accumulateResponseTokenUsage(targetTokenUsage, response);
					currentStep++;
					if (!response.error) {
						successfulResponse = response;
						successfulResponse.prompt = candidatePrompt;
						successfulResponse.metadata = {
							...successfulResponse.metadata,
							redteamFinalPrompt: candidatePrompt,
							step: currentStep
						};
						return false;
					}
				} catch (err) {
					logger.debug(`[Best-of-N] Candidate failed: ${err}`);
					lastResponse = { error: String(err) };
					currentStep++;
				}
			});
			if (successfulResponse) {
				successfulResponse.tokenUsage = targetTokenUsage;
				return successfulResponse;
			}
			if (lastResponse) {
				lastResponse.tokenUsage = targetTokenUsage;
				lastResponse.metadata = {
					...lastResponse.metadata ?? {},
					sessionIds
				};
			}
			return lastResponse || {
				error: "All candidates failed",
				metadata: { sessionIds }
			};
		} catch (err) {
			if (err instanceof Error && err.name === "AbortError") throw err;
			logger.error(`[Best-of-N] Error: ${err}`);
			return {
				error: String(err),
				metadata: { sessionIds }
			};
		}
	}
};
//#endregion
export { BestOfNProvider as default };

//# sourceMappingURL=bestOfN-BMFAX495.js.map