UNPKG

ai-sdk-guardrails

Version:

Input and output guardrails middleware for Vercel AI SDK.

1,756 lines 56 kB
import {
  extractContent
} from "./chunk-WC2PXTRI.js";
import {
  GuardrailTimeoutError,
  GuardrailsInputError,
  GuardrailsOutputError
} from "./chunk-F7POYYOU.js";

// src/spec.ts
import { z } from "zod";
var GuardrailSpec = class {
  constructor(name, description, mediaType, configSchema, checkFn, ctxRequirements, metadata) {
    this.name = name;
    this.description = description;
    this.mediaType = mediaType;
    this.configSchema = configSchema;
    this.checkFn = checkFn;
    this.ctxRequirements = ctxRequirements;
    this.metadata = metadata;
  }
  name;
  description;
  mediaType;
  configSchema;
  checkFn;
  ctxRequirements;
  metadata;
  /**
   * Return a JSON schema-like representation for tooling/SDKs.
   */
  schema() {
    return this.configSchema._def;
  }
  /**
   * Instantiate the guardrail with validated configuration.
   */
  instantiate(config) {
    const validated = this.configSchema instanceof z.ZodType ? this.configSchema.parse(config ?? {}) : config;
    return new ConfiguredGuardrail(this, validated);
  }
};
var ConfiguredGuardrail = class {
  constructor(spec, config) {
    this.spec = spec;
    this.config = config;
  }
  spec;
  config;
  async ensureAsync(fn, ...args) {
    const result = fn(...args);
    if (result instanceof Promise) {
      return await result;
    }
    return result;
  }
  async run(context, input) {
    const startedAt = Date.now();
    try {
      const validatedContext = this.spec.ctxRequirements ? this.spec.ctxRequirements.parse(context) : context;
      const result = await this.ensureAsync(
        this.spec.checkFn,
        validatedContext,
        input,
        this.config
      );
      const info = result.info || {};
      if (!result.info) {
        info.guardrailName = this.spec.name;
        info.mediaType = this.spec.mediaType;
      }
      return {
        ...result,
        info: {
          ...info,
          guardrailName: this.spec.name,
          mediaType: this.spec.mediaType
        },
        context: {
          guardrailName: this.spec.name,
          guardrailVersion: this.spec.metadata?.version,
          executedAt: /* @__PURE__ */ new Date(),
          executionTimeMs: Date.now() - startedAt,
          ...result.context
        }
      };
    } catch (error) {
      return {
        tripwireTriggered: false,
        executionFailed: true,
        originalException: error instanceof Error ? error : new Error(String(error)),
        info: {
          guardrailName: this.spec.name,
          mediaType: this.spec.mediaType,
          error: error instanceof Error ? error.message : String(error)
        },
        message: error instanceof Error ? error.message : "Guardrail execution failed",
        severity: "high",
        context: {
          guardrailName: this.spec.name,
          executedAt: /* @__PURE__ */ new Date(),
          executionTimeMs: Date.now() - startedAt
        }
      };
    }
  }
};

// src/registry.ts
import { z as z2 } from "zod";
var NO_CONFIG = z2.object({});
var NO_CONTEXT = z2.object({});
var GuardrailRegistry = class {
  specs = /* @__PURE__ */ new Map();
  registerSpec(spec) {
    this.specs.set(spec.name, spec);
  }
  register(name, checkFn, description, mediaType = "text/plain", configSchema, ctxRequirements, metadata) {
    const spec = new GuardrailSpec(
      name,
      description,
      mediaType,
      configSchema || NO_CONFIG,
      checkFn,
      ctxRequirements || NO_CONTEXT,
      metadata
    );
    this.registerSpec(
      spec
    );
  }
  get(name) {
    return this.specs.get(name);
  }
  has(name) {
    return this.specs.has(name);
  }
  remove(name) {
    return this.specs.delete(name);
  }
  size() {
    return this.specs.size;
  }
  all() {
    return [...this.specs.values()];
  }
  list() {
    return this.all();
  }
  metadata() {
    return this.all().map((spec) => ({
      name: spec.name,
      description: spec.description,
      mediaType: spec.mediaType,
      hasConfig: spec.configSchema !== NO_CONFIG,
      hasContext: spec.ctxRequirements !== NO_CONTEXT,
      metadata: spec.metadata
    }));
  }
};
var defaultRegistry = new GuardrailRegistry();
function createRegistry() {
  return new GuardrailRegistry();
}

// src/enhanced-runtime.ts
async function runGuardrails(input, bundle, context = {}, options = {}) {
  const {
    raiseGuardrailErrors = false,
    parallelExecution = true,
    timeoutMs,
    globalTimeoutMs,
    signal
  } = options;
  const startTime = Date.now();
  const guardrails = await instantiateGuardrails(bundle);
  if (signal?.aborted) {
    throw new Error("Guardrails execution aborted");
  }
  let results;
  if (parallelExecution) {
    const promises = guardrails.map(
      (guardrail) => runSingleGuardrail(guardrail, context, input, timeoutMs, signal)
    );
    results = globalTimeoutMs ? await Promise.race([
      Promise.all(promises),
      rejectAfter(
        globalTimeoutMs,
        `Global timeout of ${globalTimeoutMs}ms exceeded`
      )
    ]) : await Promise.all(promises);
  } else {
    results = [];
    for (const guardrail of guardrails) {
      if (globalTimeoutMs) {
        const elapsed = Date.now() - startTime;
        const remaining = globalTimeoutMs - elapsed;
        if (remaining <= 0) {
          throw new Error(`Global timeout of ${globalTimeoutMs}ms exceeded`);
        }
      }
      if (signal?.aborted) {
        throw new Error("Guardrails execution aborted");
      }
      const result = await runSingleGuardrail(
        guardrail,
        context,
        input,
        timeoutMs,
        signal
      );
      results.push(result);
      if (result.tripwireTriggered && result.severity === "critical") {
        break;
      }
    }
  }
  if (raiseGuardrailErrors) {
    const executionFailures = results.filter((r) => r.executionFailed);
    if (executionFailures.length > 0) {
      const firstFailure = executionFailures[0];
      if (firstFailure.originalException) {
        throw firstFailure.originalException;
      }
      throw new Error(firstFailure.message || "Guardrail execution failed");
    }
  }
  const totalExecutionTimeMs = Date.now() - startTime;
  const triggeredCount = results.filter((r) => r.tripwireTriggered).length;
  const failedCount = results.filter((r) => r.executionFailed).length;
  const successCount = results.length - failedCount;
  return {
    blocked: triggeredCount > 0,
    results,
    metadata: {
      totalExecutionTimeMs,
      triggeredCount,
      failedCount,
      successCount
    }
  };
}
async function runSingleGuardrail(guardrail, context, input, timeoutMs, signal) {
  try {
    if (signal?.aborted) {
      throw new Error("Execution aborted");
    }
    if (timeoutMs) {
      return await Promise.race([
        guardrail.run(context, input),
        rejectAfter(timeoutMs, `Guardrail timeout after ${timeoutMs}ms`)
      ]);
    }
    return await guardrail.run(context, input);
  } catch (error) {
    return {
      tripwireTriggered: false,
      executionFailed: true,
      originalException: error instanceof Error ? error : new Error(String(error)),
      info: {
        guardrailName: guardrail.spec.name,
        mediaType: guardrail.spec.mediaType,
        error: error instanceof Error ? error.message : String(error)
      },
      message: `Guardrail execution failed: ${error instanceof Error ? error.message : String(error)}`,
      severity: "high",
      context: {
        guardrailName: guardrail.spec.name,
        executedAt: /* @__PURE__ */ new Date()
      }
    };
  }
}
async function instantiateGuardrails(bundle) {
  const guardrails = [];
  for (const config of bundle.guardrails) {
    const spec = defaultRegistry.get(config.name);
    if (!spec) {
      throw new Error(`Guardrail '${config.name}' not found in registry`);
    }
    try {
      const guardrail = spec.instantiate(
        config.config || {}
      );
      guardrails.push(guardrail);
    } catch (error) {
      throw new Error(
        `Failed to instantiate guardrail '${config.name}': ${error instanceof Error ? error.message : String(error)}`,
        { cause: error }
      );
    }
  }
  return guardrails;
}
async function loadPipelineConfig(config) {
  if (typeof config === "string") {
    if (config.includes(".json") || config.includes(".yaml") || config.includes("/")) {
      const fs = await import("fs/promises");
      const content = await fs.readFile(config, "utf8");
      if (config.endsWith(".yaml") || config.endsWith(".yml")) {
        throw new Error("YAML support not yet implemented");
      }
      return JSON.parse(content);
    }
    return JSON.parse(config);
  }
  return config;
}
function loadGuardrailBundle(config) {
  const guardrails = [];
  const bundle = typeof config === "object" && config !== null && !Array.isArray(config) ? config : void 0;
  if (Array.isArray(config)) {
    guardrails.push(...config);
  } else if (bundle && Array.isArray(bundle.guardrails)) {
    guardrails.push(...bundle.guardrails);
  } else {
    throw new Error("Invalid guardrail bundle format");
  }
  for (const guardrail of guardrails) {
    if (!guardrail.name || typeof guardrail.name !== "string") {
      throw new Error("Invalid guardrail config: missing or invalid name");
    }
    if (guardrail.config !== void 0 && typeof guardrail.config !== "object") {
      throw new Error(`Invalid config for guardrail '${guardrail.name}'`);
    }
  }
  return {
    version: bundle?.version || 1,
    stageName: bundle?.stageName,
    guardrails
  };
}
async function checkPlainText(text, bundle, context, options) {
  const result = await runGuardrails(text, bundle, context, options);
  if (result.blocked) {
    const triggeredGuardrails = result.results.filter((r) => r.tripwireTriggered).map((r) => r.message || "Guardrail triggered").join(", ");
    const error = new Error(
      `Content validation failed: ${result.metadata?.triggeredCount} violation(s) detected: ${triggeredGuardrails}`
    );
    throw Object.assign(error, {
      guardrailResults: result.results.filter((r) => r.tripwireTriggered)
    });
  }
}
function rejectAfter(ms, message) {
  return new Promise(
    (_resolve, reject) => setTimeout(() => reject(new Error(message)), ms)
  );
}
async function runStageGuardrails(input, pipeline, stage, context = {}, options) {
  const bundle = pipeline[stage];
  if (!bundle) {
    return null;
  }
  return await runGuardrails(input, bundle, context, options);
}
function validatePipelineConfig(config) {
  const errors = [];
  if (config.version && typeof config.version !== "number") {
    errors.push("Pipeline version must be a number");
  }
  const stages = ["pre_flight", "input", "output"];
  for (const stage of stages) {
    const bundle = config[stage];
    if (bundle) {
      try {
        loadGuardrailBundle(bundle);
      } catch (error) {
        errors.push(
          `Invalid ${stage} bundle: ${error instanceof Error ? error.message : String(error)}`
        );
      }
    }
  }
  return errors;
}
var configUtils = {
  loadPipelineConfig,
  loadGuardrailBundle,
  validatePipelineConfig
};
var runtimeUtils = {
  runGuardrails,
  runStageGuardrails,
  checkPlainText,
  instantiateGuardrails
};

// src/adapters/spec-adapter.ts
import { z as z3 } from "zod";
function guardrailToSpec(guardrail, options) {
  return new GuardrailSpec(
    guardrail.name,
    guardrail.description || `Guardrail: ${guardrail.name}`,
    "text/plain",
    z3.unknown(),
    // Legacy guardrails don't expose config schemas
    async (context, input) => {
      const result = await guardrail.execute(input);
      return result;
    },
    void 0,
    {
      engine: "custom",
      version: guardrail.version,
      tags: guardrail.tags,
      category: "security",
      ...options?.metadata
    }
  );
}
function outputGuardrailToSpec(guardrail, options) {
  return new GuardrailSpec(
    guardrail.name,
    guardrail.description || `Output guardrail: ${guardrail.name}`,
    "text/plain",
    z3.unknown(),
    // Placeholder schema for legacy guardrails
    async (context, input) => {
      const accumulatedText = context._accumulatedText;
      const result = await guardrail.execute(
        input,
        accumulatedText
      );
      return result;
    },
    void 0,
    {
      engine: "custom",
      version: guardrail.version,
      tags: guardrail.tags,
      category: "security",
      ...options?.metadata
    }
  );
}
function registerGuardrails(guardrails, options) {
  const prefix = options?.prefix || "";
  for (const guardrail of guardrails) {
    const isInput = "execute" in guardrail && guardrail.execute.length === 1;
    const spec = isInput ? guardrailToSpec(guardrail) : outputGuardrailToSpec(guardrail);
    const name = prefix ? `${prefix}-${guardrail.name}` : guardrail.name;
    const prefixedSpec = new GuardrailSpec(
      name,
      spec.description,
      spec.mediaType,
      spec.configSchema,
      spec.checkFn,
      spec.ctxRequirements,
      spec.metadata
    );
    defaultRegistry.registerSpec(prefixedSpec);
  }
}

// src/adapters/parallel-runtime-adapter.ts
async function executeInputGuardrailsWithEnhancedRuntime(guardrails, context, options = {}) {
  const specs = guardrails.filter((g) => g.enabled !== false).map((g) => guardrailToSpec(g));
  const bundle = {
    version: 1,
    stageName: "input",
    guardrails: specs.map((spec) => ({
      name: spec.name,
      config: {}
    }))
  };
  const tempRegistry = /* @__PURE__ */ new Map();
  for (const spec of specs) tempRegistry.set(spec.name, spec);
  const originalGet = defaultRegistry.get.bind(defaultRegistry);
  defaultRegistry.get = (name) => tempRegistry.get(name) || originalGet(name);
  try {
    const result = await runGuardrails(
      context,
      bundle,
      {},
      {
        parallelExecution: options.parallel ?? true,
        timeoutMs: options.timeout,
        raiseGuardrailErrors: !options.continueOnFailure,
        signal: options.signal
      }
    );
    defaultRegistry.get = originalGet;
    return result.results.map((r, index) => {
      const guardrail = guardrails[index];
      const guardrailName = guardrail?.name || "unknown";
      return {
        tripwireTriggered: r.tripwireTriggered,
        message: r.message,
        severity: r.severity,
        suggestion: r.suggestion,
        metadata: r.metadata || {},
        context: r.context?.guardrailName ? {
          guardrailName: r.context.guardrailName,
          guardrailVersion: r.context.guardrailVersion,
          executedAt: r.context.executedAt || /* @__PURE__ */ new Date(),
          executionTimeMs: r.context.executionTimeMs,
          environment: r.context.environment
        } : {
          guardrailName,
          executedAt: /* @__PURE__ */ new Date(),
          executionTimeMs: r.context?.executionTimeMs,
          environment: r.context?.environment
        }
      };
    });
  } catch (error) {
    defaultRegistry.get = originalGet;
    throw error;
  }
}
async function executeOutputGuardrailsWithEnhancedRuntime(guardrails, context, options = {}) {
  const specs = guardrails.filter((g) => g.enabled !== false).map(
    (g) => outputGuardrailToSpec(g)
  );
  const bundle = {
    version: 1,
    stageName: "output",
    guardrails: specs.map((spec) => ({
      name: spec.name,
      config: {}
    }))
  };
  const tempRegistry = /* @__PURE__ */ new Map();
  for (const spec of specs) tempRegistry.set(spec.name, spec);
  const originalGet = defaultRegistry.get.bind(defaultRegistry);
  defaultRegistry.get = (name) => tempRegistry.get(name) || originalGet(name);
  try {
    const runtimeContext = options.accumulatedText ? { _accumulatedText: options.accumulatedText } : {};
    const result = await runGuardrails(context, bundle, runtimeContext, {
      parallelExecution: options.parallel ?? true,
      timeoutMs: options.timeout,
      raiseGuardrailErrors: !options.continueOnFailure,
      signal: options.signal
    });
    defaultRegistry.get = originalGet;
    return result.results.map((r, index) => {
      const guardrail = guardrails[index];
      const guardrailName = guardrail?.name || "unknown";
      return {
        tripwireTriggered: r.tripwireTriggered,
        message: r.message,
        severity: r.severity,
        suggestion: r.suggestion,
        metadata: r.metadata || {},
        context: r.context?.guardrailName ? {
          guardrailName: r.context.guardrailName,
          guardrailVersion: r.context.guardrailVersion,
          executedAt: r.context.executedAt || /* @__PURE__ */ new Date(),
          executionTimeMs: r.context.executionTimeMs,
          environment: r.context.environment
        } : {
          guardrailName,
          executedAt: /* @__PURE__ */ new Date(),
          executionTimeMs: r.context?.executionTimeMs,
          environment: r.context?.environment
        }
      };
    });
  } catch (error) {
    defaultRegistry.get = originalGet;
    throw error;
  }
}
var V1_ENHANCED_RUNTIME_ENABLED = process.env.GUARDRAILS_ENHANCED_RUNTIME !== "false" && process.env.NODE_ENV !== "test";

// src/guardrails/internal.ts
var ENABLE_PERFORMANCE_TRACKING = process.env.NODE_ENV === "development" || process.env.GUARDRAILS_PERFORMANCE_TRACKING === "true";
var USE_ENHANCED_RUNTIME = process.env.GUARDRAILS_USE_ENHANCED_RUNTIME !== "false" && process.env.NODE_ENV !== "test";
function extractTextFromContent(content) {
  return content.filter((part) => part.type === "text").map((part) => part.text || "").join("");
}
var normalizedContextCache = /* @__PURE__ */ new WeakMap();
var TimeoutControllerPool = class {
  static controllers = [];
  static MAX_POOL_SIZE = 20;
  static acquire() {
    const controller = this.controllers.pop();
    if (controller && !controller.signal.aborted) {
      return controller;
    }
    return new AbortController();
  }
  static release(controller) {
    if (!controller.signal.aborted && this.controllers.length < this.MAX_POOL_SIZE) {
      this.controllers.push(controller);
    }
  }
  static clear() {
    this.controllers = [];
  }
};
function guardrailErrorResult(guardrailName, error, extra) {
  const errMsg = error instanceof Error ? error.message : String(error);
  const result = {
    tripwireTriggered: true,
    message: extra?.message ?? `Guardrail execution failed: ${errMsg}`,
    severity: "critical",
    metadata: extra?.metadata ?? { error: errMsg },
    info: {
      guardrailName,
      executionFailed: true,
      error: extra?.infoError ?? errMsg
    }
  };
  if (extra?.context) {
    result.context = extra.context;
  }
  return result;
}
var PRIORITY_ORDER = { critical: 4, high: 3, medium: 2, low: 1 };
function prepareGuardrails(guardrails) {
  return guardrails.filter((g) => g.enabled !== false).toSorted(
    (a, b) => (PRIORITY_ORDER[b.priority || "medium"] || 2) - (PRIORITY_ORDER[a.priority || "medium"] || 2)
  );
}
function createConditionalContext(guardrailName, guardrailVersion, executionTimeMs, existingContext) {
  if (!ENABLE_PERFORMANCE_TRACKING) {
    return {
      guardrailName,
      ...existingContext
    };
  }
  return {
    guardrailName,
    guardrailVersion,
    executedAt: /* @__PURE__ */ new Date(),
    executionTimeMs,
    ...existingContext
  };
}
function checkStreamStopCondition(stopConfig, violations) {
  if (stopConfig === true) {
    const criticalViolations = violations.filter(
      (v) => v.summary.blockedResults.some(
        (r) => (r.severity ?? "medium") === "critical"
      )
    );
    return violations.length >= 2 || criticalViolations.length > 0;
  }
  if (typeof stopConfig === "number") {
    return violations.length >= stopConfig;
  }
  if (typeof stopConfig === "function") {
    return stopConfig(violations);
  }
  return false;
}
async function executeWithOptimizedTimeout(execution, timeoutMs, errorMessage) {
  const controller = TimeoutControllerPool.acquire();
  let timeoutId;
  try {
    const timeoutPromise = new Promise((_, reject) => {
      timeoutId = setTimeout(() => {
        controller.abort();
        reject(new Error(errorMessage));
      }, timeoutMs);
    });
    const result = await Promise.race([
      execution(controller.signal),
      timeoutPromise
    ]);
    return result;
  } finally {
    if (timeoutId) {
      clearTimeout(timeoutId);
    }
    TimeoutControllerPool.release(controller);
  }
}
function makeInvokeWithTimeout(invoke, timeoutMs) {
  return (guardrail) => executeWithOptimizedTimeout(
    (signal) => invoke(guardrail, signal),
    timeoutMs,
    `Guardrail ${guardrail.name} timed out after ${timeoutMs}ms`
  ).catch((error) => {
    if (error.message.includes("timed out")) {
      throw new GuardrailTimeoutError(guardrail.name, timeoutMs);
    }
    throw error;
  });
}
async function executeSequential(guardrails, invokeWithTimeout, opts) {
  const { continueOnFailure, logLevel, logger, label } = opts;
  const results = [];
  for (const guardrail of guardrails) {
    try {
      const result = await invokeWithTimeout(guardrail);
      results.push(result);
      if (result.tripwireTriggered) {
        if (logLevel !== "none") {
          logger.warn(
            `${label} guardrail "${guardrail.name}" triggered: ${result.message}`
          );
        }
        if (!continueOnFailure) {
          break;
        }
      }
    } catch (error) {
      if (logLevel !== "none") {
        logger.error(
          `Error executing ${label.toLowerCase()} guardrail "${guardrail.name}":`,
          error
        );
      }
      results.push(guardrailErrorResult(guardrail.name, error));
      if (!continueOnFailure) {
        break;
      }
    }
  }
  return results;
}
async function executeParallelPerGuardrail(guardrails, invokeWithTimeout, label, logLevel, logger) {
  return Promise.all(
    guardrails.map(async (guardrail) => {
      try {
        const result = await invokeWithTimeout(guardrail);
        if (result.tripwireTriggered && logLevel !== "none") {
          logger.warn(
            `${label} guardrail "${guardrail.name}" triggered: ${result.message}`
          );
        }
        return result;
      } catch (error) {
        if (logLevel !== "none") {
          logger.error(
            `Error executing ${label.toLowerCase()} guardrail "${guardrail.name}":`,
            error
          );
        }
        return guardrailErrorResult(guardrail.name, error);
      }
    })
  );
}
async function executeBatchInputGuardrails(guardrails, normalizedContext, timeoutMs, logLevel, logger) {
  if (guardrails.length === 0) return [];
  return executeWithOptimizedTimeout(
    async (signal) => {
      const results = await Promise.allSettled(
        guardrails.map(async (guardrail) => {
          try {
            return await guardrail.execute(normalizedContext, { signal });
          } catch (error) {
            if (logLevel !== "none") {
              logger.error(
                `Error executing input guardrail "${guardrail.name}":`,
                error
              );
            }
            return guardrailErrorResult(guardrail.name, error);
          }
        })
      );
      return results.map((result, index) => {
        const guardrail = guardrails[index];
        if (result.status === "fulfilled") {
          const guardResult = result.value;
          if (guardResult.tripwireTriggered && logLevel !== "none") {
            logger.warn(
              `Input guardrail "${guardrail.name}" triggered: ${guardResult.message}`
            );
          }
          return guardResult;
        }
        if (logLevel !== "none") {
          logger.error(
            `Input guardrail "${guardrail.name}" failed:`,
            result.reason
          );
        }
        return guardrailErrorResult(guardrail.name, result.reason);
      });
    },
    timeoutMs,
    `Batch guardrail execution timed out after ${timeoutMs}ms`
  ).catch((error) => {
    if (error.message.includes("timed out")) {
      return guardrails.map(
        (guardrail) => guardrailErrorResult(guardrail.name, error, {
          message: `Guardrail timed out after ${timeoutMs}ms`,
          metadata: { timeout: true },
          infoError: "Timeout"
        })
      );
    }
    throw error;
  });
}
function normalizeGuardrailContext(params) {
  const cached = normalizedContextCache.get(params);
  if (cached) {
    return cached;
  }
  const promptMessages = Array.isArray(params.prompt) ? params.prompt : [];
  const systemMessage = promptMessages.find((msg) => msg.role === "system");
  const system = systemMessage && Array.isArray(systemMessage.content) ? extractTextFromContent(systemMessage.content) : "";
  const messages = promptMessages.filter((msg) => msg.role !== "system").map((msg) => ({
    role: msg.role,
    content: msg.content && Array.isArray(msg.content) ? extractTextFromContent(msg.content) : ""
  }));
  const prompt = messages.length === 1 && messages[0]?.role === "user" ? messages[0].content : messages.map((m) => m.content).join(" ");
  const normalized = {
    prompt,
    messages,
    system,
    maxOutputTokens: params.maxOutputTokens,
    temperature: params.temperature,
    modelParams: {
      topP: params.topP,
      topK: params.topK,
      frequencyPenalty: params.frequencyPenalty,
      presencePenalty: params.presencePenalty,
      seed: params.seed,
      stopSequences: params.stopSequences
    }
  };
  normalizedContextCache.set(params, normalized);
  return normalized;
}
function toNormalizedGuardrailContext(params) {
  const candidate = params;
  if (typeof candidate.prompt === "string" && Array.isArray(candidate.messages)) {
    return params;
  }
  return normalizeGuardrailContext(params);
}
function createExecutionSummary(results, startTime) {
  const endTime = Date.now();
  const totalExecutionTime = endTime - startTime;
  const blockedResults = results.filter((r) => r.tripwireTriggered);
  const execTimes = results.map((r) => r.context?.executionTimeMs).filter((t) => typeof t === "number");
  const avgTime = execTimes.length > 0 ? execTimes.reduce((a, b) => a + b, 0) / execTimes.length : 0;
  const stats = {
    passed: results.filter((r) => !r.tripwireTriggered).length,
    blocked: blockedResults.length,
    failed: results.filter(
      (r) => r.severity === "critical" && r.tripwireTriggered
    ).length,
    averageExecutionTime: avgTime
  };
  return {
    allResults: results,
    blockedResults,
    totalExecutionTime,
    guardrailsExecuted: results.length,
    stats
  };
}
async function executeInputGuardrails(guardrails, params, options = {}) {
  const {
    parallel = true,
    timeout = 3e4,
    // 30 seconds
    continueOnFailure = true,
    logLevel = "warn",
    logger = console
  } = options;
  const enabledGuardrails = prepareGuardrails(guardrails);
  const invokeWithTimeout = makeInvokeWithTimeout(
    (guardrail, signal) => Promise.resolve(
      guardrail.execute(toNormalizedGuardrailContext(params), { signal })
    ),
    timeout
  );
  if (!parallel) {
    return executeSequential(enabledGuardrails, invokeWithTimeout, {
      continueOnFailure,
      logLevel,
      logger,
      label: "Input"
    });
  }
  const runFallback = () => executeBatchInputGuardrails(
    enabledGuardrails,
    toNormalizedGuardrailContext(params),
    timeout,
    logLevel,
    logger
  );
  if (USE_ENHANCED_RUNTIME) {
    try {
      return await executeInputGuardrailsWithEnhancedRuntime(
        enabledGuardrails,
        toNormalizedGuardrailContext(params),
        { parallel: true, timeout, continueOnFailure }
      );
    } catch {
      return runFallback();
    }
  }
  return runFallback();
}
async function executeOutputGuardrails(guardrails, params, options = {}) {
  const {
    parallel = true,
    timeout = 3e4,
    // 30 seconds
    continueOnFailure = true,
    logLevel = "warn",
    logger = console,
    accumulatedText
  } = options;
  const enabledGuardrails = prepareGuardrails(guardrails);
  const invokeWithTimeout = makeInvokeWithTimeout(
    (guardrail, signal) => Promise.resolve(guardrail.execute(params, accumulatedText, { signal })),
    timeout
  );
  if (!parallel) {
    return executeSequential(enabledGuardrails, invokeWithTimeout, {
      continueOnFailure,
      logLevel,
      logger,
      label: "Output"
    });
  }
  const runFallback = () => executeParallelPerGuardrail(
    enabledGuardrails,
    invokeWithTimeout,
    "Output",
    logLevel,
    logger
  );
  if (USE_ENHANCED_RUNTIME) {
    try {
      return await executeOutputGuardrailsWithEnhancedRuntime(
        enabledGuardrails,
        params,
        { parallel: true, timeout, continueOnFailure, accumulatedText }
      );
    } catch {
      return runFallback();
    }
  }
  return runFallback();
}

// src/guardrails/retry-helpers.ts
var SEVERITY_ORDER = {
  low: 1,
  medium: 2,
  high: 3,
  critical: 4
};
function findGuardrailForResult(result, guardrails) {
  const name = result.context?.guardrailName ?? result.info?.guardrailName;
  return guardrails.find((g) => g.name === name);
}
function getInstructionFromResult(result, guardrail, context) {
  if (guardrail?.getRetryInstruction) {
    const instruction = guardrail.getRetryInstruction({ ...context, result });
    if (typeof instruction === "string") {
      return { message: instruction };
    }
    return instruction ?? void 0;
  }
  if (result.message) {
    const suggestionPart = result.suggestion ? `. ${result.suggestion}` : "";
    return {
      message: `Please try again. The previous response was blocked: ${result.message}${suggestionPart}`
    };
  }
  return void 0;
}
function selectBlockedResults(summary, strategy) {
  const { blockedResults } = summary;
  if (blockedResults.length === 0) return [];
  switch (strategy) {
    case "first": {
      return [blockedResults[0]];
    }
    case "all": {
      return blockedResults;
    }
    default: {
      const sorted = [...blockedResults].toSorted((a, b) => {
        const severityA = SEVERITY_ORDER[a.severity ?? "medium"] ?? 2;
        const severityB = SEVERITY_ORDER[b.severity ?? "medium"] ?? 2;
        return severityB - severityA;
      });
      return [sorted[0]];
    }
  }
}
function combineInstructions(instructions) {
  if (instructions.length === 0) {
    return { message: "Please try again with a different approach." };
  }
  if (instructions.length === 1) {
    return instructions[0];
  }
  const combinedMessage = instructions.map((inst, i) => `${i + 1}. ${inst.message}`).join("\n");
  const tempAdjustments = instructions.map((i) => i.temperatureAdjustment).filter((t) => t !== void 0);
  const avgTempAdjustment = tempAdjustments.length > 0 ? tempAdjustments.reduce((a, b) => a + b, 0) / tempAdjustments.length : void 0;
  return {
    message: `Please address the following issues:
${combinedMessage}`,
    temperatureAdjustment: avgTempAdjustment,
    context: { combinedFrom: instructions.length }
  };
}
function createDefaultBuildRetryParams(options) {
  const {
    outputGuardrails,
    multipleBlockedStrategy = "highest-severity",
    attempt,
    maxRetries
  } = options;
  return ({ summary, originalParams, lastParams }) => {
    const selectedResults = selectBlockedResults(
      summary,
      multipleBlockedStrategy
    );
    const instructionContext = { attempt, maxRetries };
    const instructions = [];
    for (const result of selectedResults) {
      const guardrail = findGuardrailForResult(result, outputGuardrails);
      const instruction = getInstructionFromResult(
        result,
        guardrail,
        instructionContext
      );
      if (instruction) {
        instructions.push(instruction);
      }
    }
    const finalInstruction = combineInstructions(instructions);
    let newTemperature = lastParams.temperature ?? 0.7;
    if (finalInstruction.temperatureAdjustment !== void 0) {
      newTemperature = Math.max(
        0,
        Math.min(1, newTemperature + finalInstruction.temperatureAdjustment)
      );
    }
    const existingPrompt = Array.isArray(lastParams.prompt) ? lastParams.prompt : Array.isArray(originalParams.prompt) ? originalParams.prompt : [];
    return {
      ...lastParams,
      temperature: newTemperature,
      prompt: [
        ...existingPrompt,
        {
          role: "user",
          content: [{ type: "text", text: finalInstruction.message }]
        }
      ]
    };
  };
}
function resolveRetryConfig(globalRetry, blockedGuardrails) {
  let maxRetries = globalRetry?.maxRetries ?? 0;
  let backoffMs = globalRetry?.backoffMs ?? 0;
  if (maxRetries === 0) {
    for (const guardrail of blockedGuardrails) {
      if (guardrail.retry?.maxRetries !== void 0) {
        maxRetries = Math.max(maxRetries, guardrail.retry.maxRetries);
      }
      if (guardrail.retry?.backoffMs !== void 0 && backoffMs === 0) {
        backoffMs = guardrail.retry.backoffMs;
      }
    }
  }
  return { maxRetries, backoffMs };
}

// src/guardrails/generate-result-sync.ts
function joinTextFromContent(content) {
  if (!Array.isArray(content)) {
    return void 0;
  }
  const parts = content.filter(
    (part) => typeof part === "object" && part !== null && part.type === "text" && typeof part.text === "string"
  ).map((part) => part.text);
  return parts.length > 0 ? parts.join("") : void 0;
}
function snapshotGenerateResultText(result) {
  const record = result;
  return {
    text: typeof record.text === "string" ? record.text : void 0,
    contentJoined: joinTextFromContent(record.content)
  };
}
function syncGenerateResultTextAfterGuardrails(result, before) {
  const record = result;
  const afterContent = joinTextFromContent(record.content);
  const afterText = typeof record.text === "string" ? record.text : void 0;
  const textChanged = afterText !== void 0 && afterText !== before.text;
  const contentChanged = afterContent !== void 0 && afterContent !== before.contentJoined;
  if (textChanged && !contentChanged && afterText !== void 0) {
    record.content = [{ type: "text", text: afterText }];
    record.text = afterText;
    return result;
  }
  if (contentChanged && afterContent !== void 0) {
    record.text = afterContent;
    return result;
  }
  if (afterContent !== void 0) {
    record.text = afterContent;
  } else if (afterText !== void 0) {
    record.content = [{ type: "text", text: afterText }];
  }
  return result;
}

// src/guardrails/middleware-factories.ts
var emptyV4Usage = {
  inputTokens: {
    total: 0,
    noCache: void 0,
    cacheRead: void 0,
    cacheWrite: void 0
  },
  outputTokens: {
    total: 0,
    text: void 0,
    reasoning: void 0
  }
};
var finishReasonStop = {
  unified: "stop",
  raw: void 0
};
var finishReasonOther = {
  unified: "other",
  raw: void 0
};
function inputGuardrailsMiddleware(config) {
  const {
    inputGuardrails,
    context,
    executionOptions = {},
    onInputBlocked,
    throwOnBlocked = false
  } = config;
  return {
    specificationVersion: "v4",
    transformParams: async ({
      params
    }) => {
      const baseContext = normalizeGuardrailContext(params);
      const guardrailContext = context ? { ...baseContext, requestContext: context } : baseContext;
      const executionStartTime = Date.now();
      const inputResults = await executeInputGuardrails(
        inputGuardrails,
        guardrailContext,
        executionOptions
      );
      const blockedResults = inputResults.filter((r) => r.tripwireTriggered);
      if (blockedResults.length > 0) {
        if (onInputBlocked) {
          const executionSummary = createExecutionSummary(
            inputResults,
            executionStartTime
          );
          onInputBlocked(executionSummary, guardrailContext);
        }
        if (throwOnBlocked) {
          const blockedGuardrails = blockedResults.map((r) => ({
            name: r.context?.guardrailName || "unknown",
            message: r.message || "Blocked",
            severity: r.severity || "medium"
          }));
          throw new GuardrailsInputError(blockedGuardrails);
        }
        const enhancedParams = params;
        enhancedParams.guardrailsBlocked = blockedResults;
        return enhancedParams;
      }
      return params;
    },
    wrapGenerate: async ({
      doGenerate,
      params
    }) => {
      const paramsWithGuardrails = params;
      if (paramsWithGuardrails.guardrailsBlocked) {
        const blockedResults = paramsWithGuardrails.guardrailsBlocked;
        const blockedMessage = blockedResults.map((r) => r.message).join(", ");
        const blockedText = `[Input blocked: ${blockedMessage}]`;
        return {
          text: blockedText,
          content: [{ type: "text", text: blockedText }],
          finishReason: finishReasonOther,
          usage: emptyV4Usage,
          warnings: [],
          rawCall: { rawPrompt: params.prompt, rawSettings: {} },
          response: { headers: {} }
        };
      }
      return doGenerate();
    },
    wrapStream: async ({
      doStream,
      params
    }) => {
      const paramsWithGuardrails = params;
      if (paramsWithGuardrails.guardrailsBlocked) {
        const blockedResults = paramsWithGuardrails.guardrailsBlocked;
        const blockedMessage = blockedResults.map((r) => r.message).join(", ");
        const stream = new ReadableStream({
          start(controller) {
            controller.enqueue({
              type: "text-delta",
              id: "1",
              delta: `[Input blocked: ${blockedMessage}]`
            });
            controller.enqueue({
              type: "finish",
              finishReason: finishReasonOther,
              usage: emptyV4Usage
            });
            controller.close();
          }
        });
        return { stream };
      }
      return doStream();
    }
  };
}
function outputGuardrailsMiddleware(config) {
  const {
    outputGuardrails,
    context,
    executionOptions = {},
    onOutputBlocked,
    throwOnBlocked = false,
    replaceOnBlocked = true,
    streamMode = "buffer",
    retry,
    stopOnGuardrailViolation
  } = config;
  return {
    specificationVersion: "v4",
    wrapGenerate: async ({
      doGenerate,
      params,
      model
    }) => {
      const result = await doGenerate();
      const resultTextBeforeGuardrails = snapshotGenerateResultText(result);
      const baseContext = normalizeGuardrailContext(params);
      const guardrailContext = context ? { ...baseContext, requestContext: context } : baseContext;
      const aiResult = result;
      const outputContext = {
        input: guardrailContext,
        result: aiResult
      };
      const startTime = Date.now();
      const outputResults = await executeOutputGuardrails(
        outputGuardrails,
        outputContext,
        executionOptions
      );
      const executionSummary = createExecutionSummary(
        outputResults,
        startTime
      );
      if (executionSummary.blockedResults.length > 0) {
        const blockedGuardrailObjects = executionSummary.blockedResults.map(
          (r) => outputGuardrails.find(
            (g) => g.name === (r.context?.guardrailName ?? r.info?.guardrailName)
          )
        ).filter((g) => g !== void 0);
        const effectiveRetry = resolveRetryConfig(
          retry,
          blockedGuardrailObjects
        );
        if (effectiveRetry.maxRetries > 0 && (retry?.onlyWhen ? retry.onlyWhen(executionSummary) : true)) {
          const maxRetries = effectiveRetry.maxRetries;
          let lastParams = params;
          let lastResult = result;
          for (let attempt = 1; attempt <= maxRetries; attempt++) {
            const wait = typeof effectiveRetry.backoffMs === "function" ? effectiveRetry.backoffMs(attempt) : effectiveRetry.backoffMs ?? 0;
            if (wait && wait > 0) {
              await new Promise((r) => setTimeout(r, wait));
            }
            const buildRetryParams = retry?.buildRetryParams ?? createDefaultBuildRetryParams({
              outputGuardrails,
              multipleBlockedStrategy: retry?.multipleBlockedStrategy ?? "highest-severity",
              attempt,
              maxRetries
            });
            const nextParams = buildRetryParams({
              summary: executionSummary,
              originalParams: params,
              lastParams,
              lastResult
            });
            const retryRaw = await model.doGenerate(nextParams);
            const retryTextBeforeGuardrails = snapshotGenerateResultText(retryRaw);
            const retryResult = retryRaw;
            const retryContext = {
              input: normalizeGuardrailContext(nextParams),
              result: retryResult
            };
            const retryStart = Date.now();
            const retryResults = await executeOutputGuardrails(
              outputGuardrails,
              retryContext,
              executionOptions
            );
            const retrySummary = createExecutionSummary(
              retryResults,
              retryStart
            );
            if (retrySummary.blockedResults.length === 0) {
              return syncGenerateResultTextAfterGuardrails(
                retryRaw,
                retryTextBeforeGuardrails
              );
            }
            lastParams = nextParams;
            lastResult = retryResult;
          }
        }
        if (onOutputBlocked) {
          onOutputBlocked(executionSummary, guardrailContext, result);
        }
        if (throwOnBlocked) {
          const blockedGuardrails = executionSummary.blockedResults.map(
            (r) => ({
              name: r.context?.guardrailName || "unknown",
              message: r.message || "Blocked",
              severity: r.severity || "medium"
            })
          );
          throw new GuardrailsOutputError(blockedGuardrails);
        }
        if (replaceOnBlocked) {
          const blockedMessage = executionSummary.blockedResults.map((r) => r.message).join(", ");
          const blockedText = `[Output blocked: ${blockedMessage}]`;
          const replaced = {
            ...result,
            text: blockedText,
            content: [{ type: "text", text: blockedText }]
          };
          return replaced;
        }
      }
      return syncGenerateResultTextAfterGuardrails(
        result,
        resultTextBeforeGuardrails
      );
    },
    wrapStream: async ({
      doStream,
      params,
      model
    }) => {
      const streamResult = await doStream();
      if (streamMode === "buffer") {
        let accumulatedText2 = "";
        let streamUsage;
        let streamFinishReason;
        const blockedChunks = [];
        const transformStream2 = new TransformStream({
          transform(chunk) {
            if (chunk.type === "text-delta") {
              const anyChunk = chunk;
              accumulatedText2 += anyChunk.delta ?? anyChunk.textDelta ?? "";
            } else if (chunk.type === "finish") {
              streamUsage = chunk.usage;
              streamFinishReason = chunk.finishReason;
            }
            blockedChunks.push(chunk);
          },
          async flush(controller) {
            const baseContext = normalizeGuardrailContext(params);
            const guardrailContext = context ? { ...baseContext, requestContext: context } : baseContext;
            const streamedResult = {
              text: accumulatedText2,
              content: [{ type: "text", text: accumulatedText2 }],
              usage: streamUsage,
              finishReason: streamFinishReason
            };
            const streamedTextBeforeGuardrails = snapshotGenerateResultText(streamedResult);
            const outputContext = {
              input: guardrailContext,
              result: streamedResult
            };
            const startTime = Date.now();
            const outputResults = await executeOutputGuardrails(
              outputGuardrails,
              outputContext,
              {
                ...executionOptions,
                accumulatedText: accumulatedText2
              }
            );
            const executionSummary = createExecutionSummary(
              outputResults,
              startTime
            );
            if (executionSummary.blockedResults.length > 0) {
              const blockedGuardrailObjects = executionSummary.blockedResults.map(
                (r) => outputGuardrails.find(
                  (g) => g.name === (r.context?.guardrailName ?? r.info?.guardrailName)
                )
              ).filter((g) => g !== void 0);
              const effectiveRetry = resolveRetryConfig(
                retry,
                blockedGuardrailObjects
              );
              if (effectiveRetry.maxRetries > 0 && (retry?.onlyWhen ? retry.onlyWhen(executionSummary) : true)) {
                const maxRetries = effectiveRetry.maxRetries;
                let lastParams = params;
                let lastResult = {
                  text: accumulatedText2
                };
                for (let attempt = 1; attempt <= maxRetries; attempt++) {
                  const wait = typeof effectiveRetry.backoffMs === "function" ? effectiveRetry.backoffMs(attempt) : effectiveRetry.backoffMs ?? 0;
                  if (wait && wait > 0) {
                    await new Promise((r) => setTimeout(r, wait));
                  }
                  const buildRetryParams = retry?.buildRetryParams ?? createDefaultBuildRetryParams({
                    outputGuardrails,
                    multipleBlockedStrategy: retry?.multipleBlockedStrategy ?? "highest-severity",
                    attempt,
                    maxRetries
                  });
                  const nextParams = buildRetryParams({
                    summary: executionSummary,
                    originalParams: params,
                    lastParams,
                    lastResult
                  });
                  const retryResult = await model.doGenerate(
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    nextParams
                  );
                  const retryContext = {
                    input: normalizeGuardrailContext(nextParams),
                    result: retryResult
                  };
                  const retryStart = Date.now();
                  const retryResults = await executeOutputGuardrails(
                    outputGuardrails,
                    retryContext,
                    executionOptions
                  );
                  const retrySummary = createExecutionSummary(
                    retryResults,
                    retryStart
                  );
                  if (retrySummary.blockedResults.length === 0) {
                    const { text: repairedText } = extractContent(
                      retryResult
                    );
                    controller.enqueue({
                      type: "text-delta",
                      id: "1",
                      delta: repairedText
                    });
                    controller.enqueue({
                      type: "finish",
                      finishReason: finishReasonStop,
                      usage: emptyV4Usage
                    });
                    return;
                  }
                  lastParams = nextParams;
                  lastResult = retryResult;
                }
              }
              if (onOutputBlocked) {
                onOutputBlocked(
                  executionSummary,
                  guardrailContext,
                  streamedResult
                );
              }
              if (throwOnBlocked) {
                controller.error(
                  new Error(
                    `Output guardrails blocked response: ${executionSummary.blockedResults.map((r) => r.message).join(", ")}`
                  )
                );
                return;
              }
              if (replaceOnBlocked) {
                const blockedMessage = executionSummary.blockedResults.map((r) => r.message).join(", ");
                controller.enqueue({
                  type: "text-delta",
                  id: "1",
                  delta: `[Output blocked: ${blockedMessage}]`
                });
                controller.enqueue({
                  type: "finish",
                  finishReason: finishReasonOther,
                  usage: emptyV4Usage
                });
              } else {
                for (const chunk of blockedChunks) {
                  controller.enqueue(chunk);
                }
              }
            } else {
              syncGenerateResultTextAfterGuardrails(
                streamedResult,
                streamedTextBeforeGuardrails
              );
              const finalText = typeof streamedResult.text === "string" ? streamedResult.text : accumulatedText2;
              if (finalText === accumulatedText2) {
                for (const chunk of blockedChunks) {
                  controller.enqueue(chunk);
                }
              } else {
                controller.enqueue({
                  type: "text-delta",
                  id: "1",
                  delta: finalText
                });
                controller.enqueue({
                  type: "finish",
                  finishReason: streamFinishReason ?? finishReasonStop,
                  usage: streamUsage ?? emptyV4Usage
                });
              }
            }
          }
        });
        return {
          stream: streamResult.stream.pipeThrough(
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            transformStream2
          )
        };
      }
      let accumulatedText = "";
      let blocked = false;
      let chunkIndex = 0;
      const streamViolationHistory = [];
      const transformStream = new TransformStream({
        async transform(chunk, controller) {
          if (blocked) {
            return;
          }
          if (chunk.type === "text-delta") {
            const anyChunk = chunk;
            accumulatedText += anyChunk.delta ?? anyChunk.textDelta ?? "";
            chunkIndex++;
            const baseContext = normalizeGuardrailContext(params);
            const guardrailContext = context ? { ...baseContext, requestContext: context } : baseContext;
            const outputContext = {
              input: guardrailContext,
              result: { text: accumulatedText }
            };
            const startTime = Date.now();
            const outputResults = await executeOutputGuardrails(
              outputGuardrails,
              outputContext,
              {
                ...executionOptions,
                accumulatedText
              }
            );
            const executionSummary = createExecutionSummary(
              outputResults,
              startTime
            );
            if (executionSummary.blockedResults.length > 0) {
              streamViolationHistory.push({
                chunkIndex,
                summary: executionSummary
              });
              const shouldStopEarly = stopOnGuardrailViolation && checkStreamStopCondition(
                stopOnGuardrailViolation,
                streamViolationHistory
              );
              if (shouldStopEarly) {
                blocked = true;
              }
              if (blocked) {
                if (onOutputBlocked) {
                  onOutputBlocked(executionSummary, guardrailContext, {
                    text: accumulatedText
                  });
                }
                if (throwOnBlocked) {
                  controller.error(
                    new Error(
                      `Output guardrails blocked response: ${executionSummary.blockedResults.map((r) => r.message).join(", ")}`
                    )
                  );
                  return;
                }
                if (replaceOnBlocked) {
                  const blockedMessage = executionSummary.blockedResults.map((r) => r.message).join(", ");
                  controller.enqueue({
                    type: "text-delta",
                    id: "1",
                    delta: `[Output blocked: ${blockedMessage}]`
                  });
                  controller.enqueue({
                    type: "finish",
                    finishReason: finishReasonOther,
                    usage: emptyV4Usage
                  });
                  return;
                }
              }
            }
            controller.enqueue(chunk);
          } else {
            controller.enqueue(chunk);
          }
        }
      });
      return {
        stream: streamResult.stream.pipeThrough(
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          transformStream
        )
      };
    }
  };
}

// src/guardrails.ts
import { wrapLanguageModel } from "ai";
async function runWithEnvelope(name, version, run) {
  const startTime = ENABLE_PERFORMANCE_TRACKING ? Date.now() : 0;
  try {
    const result = await run();
    const executionTime = ENABLE_PERFORMANCE_TRACKING ? Date.now() - startTime : void 0;
    return {
      ...result,
      context: createConditionalContext(
        name,
        version,
        executionTime,
        result.context
      )
    };
  } catch (error) {
    const executionTime = ENABLE_PERFORMANCE_TRACKING ? Date.now() - startTime : void 0;
    return guardrailErrorResult(name, error, {
      context: createConditionalContext(name, version, executionTime)
    });
  }
}
function defineInputGuardrail(guardrail) {
  const originalExecute = guardrail.execute;
  return {
    enabled: true,
    priority: "medium",
    version: "1.0.0",
    tags: [],
    ...guardrail,
    execute: (params, options) => runWithEnvelope(
      guardrail.name,
      guardrail.version,
      () => options === void 0 ? originalExecute(params) : originalExecute(params, options)
    )
  };
}
function defineOutputGuardrail(guardrail) {
  const originalExecute = guardrail.execute;
  return {
    enabled: true,
    priority: "medium",
    version: "1.0.0",
    tags: [],
    ...guardrail,
    execute: (params, options) => runWithEnvelope(
      guardrail.name,
      guardrail.version,
      () => options === void 0 ? originalExecute(params) : originalExecute(params, options)
    )
  };
}
function withGuardrails(config) {
  const {
    model,
    inputGuardrails = [],
    outputGuardrails = [],
    throwOnBlocked,
    replaceOnBlocked,
    streamMode,
    stopOnGuardrailViolation,
    executionOptions,
    onInputBlocked,
    onOutputBlocked,
    retry
  } = config;
  const middlewares = [];
  if (inputGuardrails.length > 0) {
    middlewares.push(
      inputGuardrailsMiddleware({
        inputGuardrails,
        throwOnBlocked,
        executionOptions,
        onInputBlocked
      })
    );
  }
  if (outputGuardrails.length > 0) {
    middlewares.push(
      outputGuardrailsMiddleware({
        outputGuardrails,
        throwOnBlocked,
        replaceOnBlocked,
        streamMode,
        stopOnGuardrailViolation,
        executionOptions,
        onOutputBlocked,
        retry
      })
    );
  }
  if (middlewares.length === 0) {
    return model;
  }
  return wrapLanguageModel({
    model,
    middleware: middlewares
  });
}
function createGuardrails(config) {
  return (model) => withGuardrails({ model, ...config });
}

export {
  GuardrailSpec,
  ConfiguredGuardrail,
  GuardrailRegistry,
  defaultRegistry,
  createRegistry,
  runGuardrails,
  instantiateGuardrails,
  loadPipelineConfig,
  loadGuardrailBundle,
  checkPlainText,
  runStageGuardrails,
  validatePipelineConfig,
  configUtils,
  runtimeUtils,
  registerGuardrails,
  normalizeGuardrailContext,
  executeInputGuardrails,
  executeOutputGuardrails,
  createDefaultBuildRetryParams,
  resolveRetryConfig,
  snapshotGenerateResultText,
  syncGenerateResultTextAfterGuardrails,
  inputGuardrailsMiddleware,
  outputGuardrailsMiddleware,
  defineInputGuardrail,
  defineOutputGuardrail,
  withGuardrails,
  createGuardrails
};