{"version":3,"sources":["../src/errors.ts","../src/cassette/cassette-store.ts","../src/adapters/detect.ts","../src/cassette/cassette-hash.ts","../src/cassette/cassette-match.ts","../src/adapters/anthropic.ts","../src/adapters/openai.ts","../src/adapters/http.ts","../src/eval/evaluator.ts","../src/eval/baseline.ts","../src/harness.ts","../src/metrics/exact-match.ts","../src/metrics/contains.ts","../src/metrics/regex.ts","../src/metrics/json-schema.ts","../src/metrics/similarity.ts","../src/metrics/llm-judge.ts","../src/metrics/custom.ts","../src/metrics/tool-called.ts","../src/metrics/json-path.ts","../src/metrics/not-empty.ts","../src/metrics/word-count.ts","../src/metrics/index.ts","../src/cassette/scrubbers.ts"],"names":["fs","yaml","path","createHash","interaction","normalizeRequest","interceptCreate","path2","fs2","path3","Ajv"],"mappings":"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","file":"index.cjs","sourcesContent":["export class HarnessError extends Error {\n  constructor(message: string) {\n    super(message)\n    this.name = 'HarnessError'\n  }\n}\n\nexport class CassetteMissError extends HarnessError {\n  constructor(public readonly hash: string) {\n    super(\n      `No cassette interaction found for request hash \"${hash}\". ` +\n        `Run with mode: 'record' to capture the interaction.`,\n    )\n    this.name = 'CassetteMissError'\n  }\n}\n\nexport class CassetteOverwriteError extends HarnessError {\n  constructor(public readonly hash: string) {\n    super(\n      `A cassette interaction with hash \"${hash}\" already exists and noOverwrite is true.`,\n    )\n    this.name = 'CassetteOverwriteError'\n  }\n}\n\nexport class CassetteWriteError extends HarnessError {\n  constructor(\n    public readonly filePath: string,\n    cause: unknown,\n  ) {\n    super(\n      `Failed to write cassette file at \"${filePath}\": ${cause instanceof Error ? cause.message : String(cause)}`,\n    )\n    this.name = 'CassetteWriteError'\n  }\n}\n\nexport class UnsupportedClientError extends HarnessError {\n  constructor() {\n    super(\n      'Unsupported client type. Pass an Anthropic or OpenAI client instance to harness.wrap().',\n    )\n    this.name = 'UnsupportedClientError'\n  }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as yaml from 'js-yaml'\nimport type { CassetteFile, CassetteInteraction } from '../types.js'\nimport { CassetteWriteError } from '../errors.js'\n\nexport class CassetteStore {\n  private filePath: string\n  private data: CassetteFile | null = null\n\n  constructor(filePath: string) {\n    this.filePath = filePath\n  }\n\n  get path(): string {\n    return this.filePath\n  }\n\n  load(): CassetteFile {\n    if (this.data !== null) return this.data\n    if (!fs.existsSync(this.filePath)) {\n      this.data = { version: 1, interactions: [] }\n    } else {\n      const raw = fs.readFileSync(this.filePath, 'utf-8')\n      this.data = yaml.load(raw) as CassetteFile\n      if (!this.data || !Array.isArray(this.data.interactions)) {\n        this.data = { version: 1, interactions: [] }\n      }\n    }\n    return this.data\n  }\n\n  findById(id: string): CassetteInteraction | undefined {\n    return this.load().interactions.find((i) => i.id === id)\n  }\n\n  append(interaction: CassetteInteraction): void {\n    const data = this.load()\n    const existingIndex = data.interactions.findIndex((i) => i.id === interaction.id)\n    if (existingIndex >= 0) {\n      data.interactions[existingIndex] = interaction\n    } else {\n      data.interactions.push(interaction)\n    }\n    this.flush()\n  }\n\n  private flush(): void {\n    const dir = path.dirname(this.filePath)\n    try {\n      if (!fs.existsSync(dir)) {\n        fs.mkdirSync(dir, { recursive: true })\n      }\n      fs.writeFileSync(this.filePath, yaml.dump(this.data, { sortKeys: true, lineWidth: 120 }))\n    } catch (err) {\n      throw new CassetteWriteError(this.filePath, err)\n    }\n  }\n}\n","export function isAnthropicClient(client: unknown): boolean {\n  if (typeof client !== 'object' || client === null) return false\n  const c = client as Record<string, unknown>\n  if (typeof c['messages'] !== 'object' || c['messages'] === null) return false\n  const messages = c['messages'] as Record<string, unknown>\n  return typeof messages['create'] === 'function'\n}\n\nexport function isOpenAIClient(client: unknown): boolean {\n  if (typeof client !== 'object' || client === null) return false\n  const c = client as Record<string, unknown>\n  if (typeof c['chat'] !== 'object' || c['chat'] === null) return false\n  const chat = c['chat'] as Record<string, unknown>\n  if (typeof chat['completions'] !== 'object' || chat['completions'] === null) return false\n  const completions = chat['completions'] as Record<string, unknown>\n  return typeof completions['create'] === 'function'\n}\n","import { createHash } from 'node:crypto'\nimport type { CassetteRequest } from '../types.js'\n\n/**\n * Recursively sorts all object keys alphabetically.\n * This ensures deterministic JSON serialization matching Python's json.dumps(sort_keys=True).\n */\nfunction sortKeys(value: unknown): unknown {\n  if (value === null || typeof value !== 'object') return value\n  if (Array.isArray(value)) return value.map(sortKeys)\n  const sorted: Record<string, unknown> = {}\n  for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n    sorted[key] = sortKeys((value as Record<string, unknown>)[key])\n  }\n  return sorted\n}\n\n/**\n * Builds the canonical object used for hashing.\n * Must be kept in sync with Python's llm_test_harness.cassette.hash.build_canonical().\n */\nfunction buildCanonical(req: CassetteRequest): unknown {\n  return {\n    messages: req.messages.map((m) => ({ content: m.content, role: m.role })),\n    model: req.model,\n    params: {\n      max_tokens: req.params.max_tokens ?? null,\n      stop: req.params.stop ?? null,\n      temperature: req.params.temperature ?? null,\n      top_p: req.params.top_p ?? null,\n    },\n    provider: req.provider,\n    system: req.system ?? null,\n    tools: req.tools\n      ? [...req.tools]\n          .sort((a, b) => a.name.localeCompare(b.name))\n          .map((t) => ({ description: t.description ?? null, name: t.name }))\n      : null,\n  }\n}\n\n/**\n * Produces a deterministic SHA-256 hash for a cassette request.\n * The hash uniquely identifies a request for record/replay matching.\n */\nexport function hashRequest(req: CassetteRequest): string {\n  const canonical = sortKeys(buildCanonical(req))\n  const json = JSON.stringify(canonical)\n  return 'sha256:' + createHash('sha256').update(json, 'utf8').digest('hex')\n}\n","import type { CassetteInteraction, CassetteRequest } from '../types.js'\nimport type { CassetteStore } from './cassette-store.js'\nimport { hashRequest } from './cassette-hash.js'\nimport { CassetteMissError } from '../errors.js'\n\nexport function findInteraction(\n  store: CassetteStore,\n  req: CassetteRequest,\n): CassetteInteraction | undefined {\n  const hash = hashRequest(req)\n  return store.findById(hash)\n}\n\nexport function requireInteraction(\n  store: CassetteStore,\n  req: CassetteRequest,\n): CassetteInteraction {\n  const hash = hashRequest(req)\n  const interaction = store.findById(hash)\n  if (!interaction) throw new CassetteMissError(hash)\n  return interaction\n}\n","import type { CassetteInteraction, CassetteRequest, ResolvedHarnessConfig } from '../types.js'\nimport type { CassetteStore } from '../cassette/cassette-store.js'\nimport { hashRequest } from '../cassette/cassette-hash.js'\nimport { findInteraction } from '../cassette/cassette-match.js'\nimport { CassetteMissError, CassetteOverwriteError } from '../errors.js'\n\n// Minimal type definitions for Anthropic SDK shapes, kept local to avoid\n// hard-coding the SDK version in the public API.\n\ninterface AnthropicMessageParam {\n  role: 'user' | 'assistant'\n  content: string | Array<{ type: string; text?: string; [key: string]: unknown }>\n}\n\ninterface AnthropicCreateParams {\n  model: string\n  max_tokens: number\n  messages: AnthropicMessageParam[]\n  system?: string | Array<{ type: string; text: string }>\n  temperature?: number\n  top_p?: number\n  stop_sequences?: string[]\n  stream?: boolean\n  tools?: Array<{ name: string; description?: string; input_schema: Record<string, unknown> }>\n  [key: string]: unknown\n}\n\ninterface AnthropicMessage {\n  id: string\n  type: 'message'\n  role: 'assistant'\n  content: Array<{ type: string; text?: string; [key: string]: unknown }>\n  model: string\n  stop_reason: string | null\n  stop_sequence: string | null\n  usage: { input_tokens: number; output_tokens: number }\n}\n\nfunction normalizeSystem(system: AnthropicCreateParams['system']): string | null {\n  if (!system) return null\n  if (typeof system === 'string') return system\n  return system\n    .filter((b) => b.type === 'text')\n    .map((b) => b.text ?? '')\n    .join('\\n')\n}\n\nfunction normalizeContent(\n  content: AnthropicMessageParam['content'],\n): string {\n  if (typeof content === 'string') return content\n  return content\n    .filter((b) => b.type === 'text')\n    .map((b) => b.text ?? '')\n    .join('\\n')\n}\n\nfunction normalizeRequest(params: AnthropicCreateParams): CassetteRequest {\n  return {\n    provider: 'anthropic',\n    model: params.model,\n    system: normalizeSystem(params.system),\n    messages: params.messages.map((m) => ({\n      role: m.role,\n      content: normalizeContent(m.content),\n    })),\n    params: {\n      max_tokens: params.max_tokens ?? null,\n      temperature: params.temperature ?? null,\n      top_p: params.top_p ?? null,\n      stop: params.stop_sequences ?? null,\n    },\n    tools: params.tools\n      ? params.tools.map((t) => ({ name: t.name, description: t.description ?? null }))\n      : null,\n  }\n}\n\nfunction buildAnthropicResponse(\n  interaction: CassetteInteraction,\n  originalModel: string,\n): AnthropicMessage {\n  const { response, request, metadata } = interaction\n  const content = (response.content ?? []).map((b) => {\n    if (b.type === 'text') return { type: 'text' as const, text: b.text ?? '' }\n    if (b.type === 'tool_use') {\n      return { type: 'tool_use' as const, id: b.id ?? '', name: b.name ?? '', input: b.input ?? {} }\n    }\n    return { type: 'tool_result' as const }\n  })\n\n  return {\n    id: metadata.provider_request_id ?? `replayed_${interaction.id.slice(0, 16)}`,\n    type: 'message',\n    role: 'assistant',\n    content,\n    model: request.model ?? originalModel,\n    stop_reason: response.stop_reason ?? null,\n    stop_sequence: null,\n    usage: {\n      input_tokens: response.usage?.input_tokens ?? 0,\n      output_tokens: response.usage?.output_tokens ?? 0,\n    },\n  }\n}\n\nasync function interceptCreate(\n  params: AnthropicCreateParams,\n  originalFn: (params: AnthropicCreateParams) => Promise<AnthropicMessage>,\n  store: CassetteStore,\n  config: ResolvedHarnessConfig,\n): Promise<AnthropicMessage> {\n  // Pass streaming through without cassette interception\n  if (params.stream === true) {\n    return originalFn(params)\n  }\n\n  const req = normalizeRequest(params)\n  const hash = hashRequest(req)\n\n  if (config.mode === 'replay' || config.mode === 'hybrid') {\n    const interaction = findInteraction(store, req)\n    if (interaction) {\n      return buildAnthropicResponse(interaction, params.model)\n    }\n    if (config.mode === 'replay') {\n      throw new CassetteMissError(hash)\n    }\n  }\n\n  if (config.mode === 'passthrough') {\n    return originalFn(params)\n  }\n\n  // record or hybrid-miss: call real API\n  const start = Date.now()\n  const response = await originalFn(params)\n  const durationMs = Date.now() - start\n\n  const interaction: CassetteInteraction = {\n    id: hash,\n    request: req,\n    response: {\n      type: 'message',\n      content: response.content.map((b) => {\n        if (b.type === 'text') return { type: 'text' as const, text: b.text ?? '' }\n        if (b.type === 'tool_use') {\n          return {\n            type: 'tool_use' as const,\n            id: (b as { id?: string }).id,\n            name: (b as { name?: string }).name,\n            input: (b as { input?: Record<string, unknown> }).input ?? {},\n          }\n        }\n        return { type: 'tool_result' as const }\n      }),\n      usage: {\n        input_tokens: response.usage.input_tokens,\n        output_tokens: response.usage.output_tokens,\n      },\n      stop_reason: response.stop_reason ?? undefined,\n    },\n    metadata: {\n      recorded_at: new Date().toISOString(),\n      duration_ms: durationMs,\n      provider_request_id: response.id,\n    },\n  }\n\n  const final = config.onBeforeRecord(interaction)\n\n  if (config.noOverwrite && store.findById(hash) !== undefined) {\n    throw new CassetteOverwriteError(hash)\n  }\n\n  store.append(final)\n  return response\n}\n\nexport function wrapAnthropicClient<T extends object>(\n  client: T,\n  store: CassetteStore,\n  config: ResolvedHarnessConfig,\n): T {\n  return new Proxy(client, {\n    get(target, prop, receiver) {\n      if (prop === 'messages') {\n        const originalMessages = Reflect.get(target, prop, target) as Record<string, unknown>\n        return new Proxy(originalMessages, {\n          get(msgTarget, msgProp) {\n            if (msgProp === 'create') {\n              return (params: AnthropicCreateParams) =>\n                interceptCreate(\n                  params,\n                  (p) =>\n                    (msgTarget['create'] as (p: AnthropicCreateParams) => Promise<AnthropicMessage>).call(\n                      msgTarget,\n                      p,\n                    ),\n                  store,\n                  config,\n                )\n            }\n            return Reflect.get(msgTarget, msgProp, msgTarget)\n          },\n        })\n      }\n      return Reflect.get(target, prop, receiver)\n    },\n  })\n}\n","import type { CassetteInteraction, CassetteRequest, ResolvedHarnessConfig } from '../types.js'\nimport type { CassetteStore } from '../cassette/cassette-store.js'\nimport { hashRequest } from '../cassette/cassette-hash.js'\nimport { findInteraction } from '../cassette/cassette-match.js'\nimport { CassetteMissError, CassetteOverwriteError } from '../errors.js'\n\n// Minimal type definitions for the OpenAI SDK shapes.\n\ninterface OpenAIMessage {\n  role: 'system' | 'user' | 'assistant' | 'tool'\n  content: string | null\n  tool_calls?: Array<{\n    id: string\n    type: 'function'\n    function: { name: string; arguments: string }\n  }>\n}\n\ninterface OpenAITool {\n  type: 'function'\n  function: {\n    name: string\n    description?: string\n    parameters?: Record<string, unknown>\n  }\n}\n\ninterface OpenAICreateParams {\n  model: string\n  messages: OpenAIMessage[]\n  max_tokens?: number | null\n  temperature?: number | null\n  top_p?: number | null\n  stop?: string | string[] | null\n  stream?: boolean\n  tools?: OpenAITool[]\n  [key: string]: unknown\n}\n\ninterface OpenAIChatCompletion {\n  id: string\n  object: 'chat.completion'\n  created: number\n  model: string\n  choices: Array<{\n    index: number\n    message: { role: 'assistant'; content: string | null; tool_calls?: unknown[] }\n    finish_reason: string | null\n    logprobs: null\n  }>\n  usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number }\n}\n\nfunction normalizeRequest(params: OpenAICreateParams): CassetteRequest {\n  // Extract system message from messages array (OpenAI embeds it as role='system')\n  const systemMsg = params.messages.find((m) => m.role === 'system')\n  const nonSystemMsgs = params.messages.filter((m) => m.role !== 'system')\n\n  return {\n    provider: 'openai',\n    model: params.model,\n    system: systemMsg?.content ?? null,\n    messages: nonSystemMsgs\n      .filter((m) => m.role === 'user' || m.role === 'assistant')\n      .map((m) => ({ role: m.role as 'user' | 'assistant', content: m.content ?? '' })),\n    params: {\n      max_tokens: params.max_tokens ?? null,\n      temperature: params.temperature ?? null,\n      top_p: params.top_p ?? null,\n      stop: params.stop ?? null,\n    },\n    tools: params.tools\n      ? params.tools.map((t) => ({\n          name: t.function.name,\n          description: t.function.description ?? null,\n        }))\n      : null,\n  }\n}\n\nfunction buildOpenAIResponse(interaction: CassetteInteraction): OpenAIChatCompletion {\n  const { response, metadata } = interaction\n  const textContent = response.content?.[0]?.text ?? ''\n\n  return {\n    id: metadata.provider_request_id ?? `replayed_${interaction.id.slice(0, 16)}`,\n    object: 'chat.completion',\n    created: Math.floor(new Date(metadata.recorded_at).getTime() / 1000),\n    model: interaction.request.model,\n    choices: [\n      {\n        index: 0,\n        message: { role: 'assistant', content: textContent },\n        finish_reason: response.finish_reason ?? response.stop_reason ?? 'stop',\n        logprobs: null,\n      },\n    ],\n    usage: {\n      prompt_tokens: response.usage?.input_tokens ?? 0,\n      completion_tokens: response.usage?.output_tokens ?? 0,\n      total_tokens:\n        response.usage?.total_tokens ??\n        (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0),\n    },\n  }\n}\n\nasync function interceptCreate(\n  params: OpenAICreateParams,\n  originalFn: (params: OpenAICreateParams) => Promise<OpenAIChatCompletion>,\n  store: CassetteStore,\n  config: ResolvedHarnessConfig,\n): Promise<OpenAIChatCompletion> {\n  if (params.stream === true) {\n    return originalFn(params)\n  }\n\n  const req = normalizeRequest(params)\n  const hash = hashRequest(req)\n\n  if (config.mode === 'replay' || config.mode === 'hybrid') {\n    const interaction = findInteraction(store, req)\n    if (interaction) {\n      return buildOpenAIResponse(interaction)\n    }\n    if (config.mode === 'replay') {\n      throw new CassetteMissError(hash)\n    }\n  }\n\n  if (config.mode === 'passthrough') {\n    return originalFn(params)\n  }\n\n  const start = Date.now()\n  const response = await originalFn(params)\n  const durationMs = Date.now() - start\n\n  const firstChoice = response.choices[0]\n  const interaction: CassetteInteraction = {\n    id: hash,\n    request: req,\n    response: {\n      type: 'message',\n      content: firstChoice?.message.content\n        ? [{ type: 'text', text: firstChoice.message.content }]\n        : [],\n      usage: {\n        input_tokens: response.usage.prompt_tokens,\n        output_tokens: response.usage.completion_tokens,\n        total_tokens: response.usage.total_tokens,\n      },\n      finish_reason: firstChoice?.finish_reason ?? undefined,\n    },\n    metadata: {\n      recorded_at: new Date().toISOString(),\n      duration_ms: durationMs,\n      provider_request_id: response.id,\n    },\n  }\n\n  const final = config.onBeforeRecord(interaction)\n\n  if (config.noOverwrite && store.findById(hash) !== undefined) {\n    throw new CassetteOverwriteError(hash)\n  }\n\n  store.append(final)\n  return response\n}\n\nexport function wrapOpenAIClient<T extends object>(\n  client: T,\n  store: CassetteStore,\n  config: ResolvedHarnessConfig,\n): T {\n  return new Proxy(client, {\n    get(target, prop, receiver) {\n      if (prop === 'chat') {\n        const originalChat = Reflect.get(target, prop, target) as Record<string, unknown>\n        return new Proxy(originalChat, {\n          get(chatTarget, chatProp) {\n            if (chatProp === 'completions') {\n              const originalCompletions = Reflect.get(chatTarget, chatProp, chatTarget) as Record<\n                string,\n                unknown\n              >\n              return new Proxy(originalCompletions, {\n                get(compTarget, compProp) {\n                  if (compProp === 'create') {\n                    return (params: OpenAICreateParams) =>\n                      interceptCreate(\n                        params,\n                        (p) =>\n                          (\n                            compTarget['create'] as (\n                              p: OpenAICreateParams,\n                            ) => Promise<OpenAIChatCompletion>\n                          ).call(compTarget, p),\n                        store,\n                        config,\n                      )\n                  }\n                  return Reflect.get(compTarget, compProp, compTarget)\n                },\n              })\n            }\n            return Reflect.get(chatTarget, chatProp, chatTarget)\n          },\n        })\n      }\n      return Reflect.get(target, prop, receiver)\n    },\n  })\n}\n","import type { CassetteInteraction, CassetteRequest, Provider, ResolvedHarnessConfig } from '../types.js'\nimport type { CassetteStore } from '../cassette/cassette-store.js'\nimport { hashRequest } from '../cassette/cassette-hash.js'\nimport { findInteraction } from '../cassette/cassette-match.js'\nimport { CassetteMissError, CassetteOverwriteError } from '../errors.js'\n\nconst PROVIDER_HOSTNAMES: Record<string, Provider> = {\n  'api.anthropic.com': 'anthropic',\n  'api.openai.com': 'openai',\n}\n\nfunction hostnameToProvider(url: string): Provider | null {\n  try {\n    const hostname = new URL(url).hostname\n    return PROVIDER_HOSTNAMES[hostname] ?? null\n  } catch {\n    return null\n  }\n}\n\nfunction normalizeHttpRequest(\n  provider: Provider,\n  body: Record<string, unknown>,\n): CassetteRequest {\n  const messages = (body['messages'] as Array<{ role: string; content: string }> | undefined) ?? []\n  const systemMsg = messages.find((m) => m.role === 'system')\n  const nonSystem = messages.filter((m) => m.role !== 'system')\n\n  return {\n    provider,\n    model: String(body['model'] ?? ''),\n    system:\n      typeof body['system'] === 'string'\n        ? body['system']\n        : (systemMsg?.content ?? null),\n    messages: nonSystem\n      .filter((m) => m.role === 'user' || m.role === 'assistant')\n      .map((m) => ({ role: m.role as 'user' | 'assistant', content: m.content ?? '' })),\n    params: {\n      max_tokens: (body['max_tokens'] as number | undefined) ?? null,\n      temperature: (body['temperature'] as number | undefined) ?? null,\n      top_p: (body['top_p'] as number | undefined) ?? null,\n      stop:\n        (body['stop'] as string | string[] | undefined) ??\n        (body['stop_sequences'] as string[] | undefined) ??\n        null,\n    },\n    tools: null,\n  }\n}\n\nfunction buildFakeResponse(interaction: CassetteInteraction, provider: Provider): unknown {\n  const { response, metadata } = interaction\n  const text = response.content?.[0]?.text ?? ''\n\n  if (provider === 'anthropic') {\n    return {\n      id: metadata.provider_request_id ?? `replayed_${interaction.id.slice(0, 16)}`,\n      type: 'message',\n      role: 'assistant',\n      content: [{ type: 'text', text }],\n      model: interaction.request.model,\n      stop_reason: response.stop_reason ?? 'end_turn',\n      stop_sequence: null,\n      usage: {\n        input_tokens: response.usage?.input_tokens ?? 0,\n        output_tokens: response.usage?.output_tokens ?? 0,\n      },\n    }\n  }\n\n  return {\n    id: metadata.provider_request_id ?? `replayed_${interaction.id.slice(0, 16)}`,\n    object: 'chat.completion',\n    created: Math.floor(new Date(metadata.recorded_at).getTime() / 1000),\n    model: interaction.request.model,\n    choices: [\n      {\n        index: 0,\n        message: { role: 'assistant', content: text },\n        finish_reason: response.finish_reason ?? 'stop',\n        logprobs: null,\n      },\n    ],\n    usage: {\n      prompt_tokens: response.usage?.input_tokens ?? 0,\n      completion_tokens: response.usage?.output_tokens ?? 0,\n      total_tokens: response.usage?.total_tokens ?? 0,\n    },\n  }\n}\n\nexport function createFetchInterceptor(\n  store: CassetteStore,\n  config: ResolvedHarnessConfig,\n): { intercept: () => void; restore: () => void } {\n  const originalFetch = globalThis.fetch\n\n  const interceptedFetch = async (\n    input: string | URL | Request,\n    init?: RequestInit,\n  ): Promise<Response> => {\n    const url = input instanceof Request ? input.url : String(input)\n    const provider = hostnameToProvider(url)\n\n    if (!provider || config.mode === 'passthrough') {\n      return originalFetch(input, init)\n    }\n\n    const body: Record<string, unknown> = init?.body\n      ? (JSON.parse(init.body as string) as Record<string, unknown>)\n      : {}\n    const req = normalizeHttpRequest(provider, body)\n    const hash = hashRequest(req)\n\n    if (config.mode === 'replay' || config.mode === 'hybrid') {\n      const interaction = findInteraction(store, req)\n      if (interaction) {\n        return new Response(JSON.stringify(buildFakeResponse(interaction, provider)), {\n          status: 200,\n          headers: { 'Content-Type': 'application/json' },\n        })\n      }\n      if (config.mode === 'replay') {\n        throw new CassetteMissError(hash)\n      }\n    }\n\n    const start = Date.now()\n    const realResponse = await originalFetch(input, init)\n    const durationMs = Date.now() - start\n    const responseBody = (await realResponse.json()) as Record<string, unknown>\n\n    const interaction: CassetteInteraction = {\n      id: hash,\n      request: req,\n      response: {\n        type: 'message',\n        content: [{ type: 'text', text: String(responseBody['content'] ?? '') }],\n        usage: {\n          input_tokens: (responseBody['usage'] as Record<string, number> | undefined)?.['input_tokens'] ?? 0,\n          output_tokens: (responseBody['usage'] as Record<string, number> | undefined)?.['output_tokens'] ?? 0,\n        },\n        stop_reason: String(responseBody['stop_reason'] ?? 'end_turn'),\n      },\n      metadata: {\n        recorded_at: new Date().toISOString(),\n        duration_ms: durationMs,\n        provider_request_id: String(responseBody['id'] ?? ''),\n      },\n    }\n\n    const final = config.onBeforeRecord(interaction)\n\n    if (config.noOverwrite && store.findById(hash) !== undefined) {\n      throw new CassetteOverwriteError(hash)\n    }\n\n    store.append(final)\n\n    return new Response(JSON.stringify(responseBody), {\n      status: 200,\n      headers: { 'Content-Type': 'application/json' },\n    })\n  }\n\n  return {\n    intercept: () => {\n      globalThis.fetch = interceptedFetch as typeof globalThis.fetch\n    },\n    restore: () => {\n      globalThis.fetch = originalFetch\n    },\n  }\n}\n","import type { EvalResult, MetricFn, MetricScore } from '../types.js'\n\nexport async function runEval(text: string, metrics: MetricFn[]): Promise<EvalResult> {\n  if (metrics.length === 0) {\n    return { pass: true, passRate: 1, scores: [] }\n  }\n\n  const scores: MetricScore[] = await Promise.all(\n    metrics.map((m) => Promise.resolve(m.evaluate(text))),\n  )\n\n  const passed = scores.filter((s) => s.pass).length\n  const passRate = passed / scores.length\n  const pass = passRate === 1\n\n  return { pass, passRate, scores }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { EvalResult, BaselineSnapshot, RegressionResult, RegressionDetail } from '../types.js'\nimport { HarnessError } from '../errors.js'\n\nfunction baselinesDir(cassettesDir: string): string {\n  return path.join(cassettesDir, '.baselines')\n}\n\nfunction baselinePath(cassettesDir: string, testName: string): string {\n  return path.join(baselinesDir(cassettesDir), `${testName}.json`)\n}\n\nexport function saveBaseline(\n  testName: string,\n  result: EvalResult,\n  cassettesDir: string,\n): void {\n  const snapshot: BaselineSnapshot = {\n    version: 1,\n    createdAt: new Date().toISOString(),\n    testName,\n    entries: result.scores.map((s) => ({\n      metricName: s.name,\n      score: s.score,\n      pass: s.pass,\n    })),\n  }\n\n  const dir = baselinesDir(cassettesDir)\n  if (!fs.existsSync(dir)) {\n    fs.mkdirSync(dir, { recursive: true })\n  }\n\n  fs.writeFileSync(baselinePath(cassettesDir, testName), JSON.stringify(snapshot, null, 2))\n}\n\nexport function compareBaseline(\n  testName: string,\n  result: EvalResult,\n  cassettesDir: string,\n  threshold = 0,\n): RegressionResult {\n  const filePath = baselinePath(cassettesDir, testName)\n  if (!fs.existsSync(filePath)) {\n    throw new HarnessError(\n      `No baseline found for \"${testName}\". Call saveBaseline() first.`,\n    )\n  }\n\n  const snapshot: BaselineSnapshot = JSON.parse(fs.readFileSync(filePath, 'utf-8'))\n  const regressions: RegressionDetail[] = []\n  const improvements: RegressionDetail[] = []\n\n  for (const entry of snapshot.entries) {\n    const current = result.scores.find((s) => s.name === entry.metricName)\n    if (!current) continue\n\n    const delta = current.score - entry.score\n    if (delta < -threshold) {\n      regressions.push({\n        metricName: entry.metricName,\n        baseline: entry.score,\n        current: current.score,\n        delta,\n      })\n    } else if (delta > threshold) {\n      improvements.push({\n        metricName: entry.metricName,\n        baseline: entry.score,\n        current: current.score,\n        delta,\n      })\n    }\n  }\n\n  return {\n    hasRegression: regressions.length > 0,\n    regressions,\n    improvements,\n  }\n}\n","import * as path from 'node:path'\nimport type {\n  HarnessConfig,\n  ResolvedHarnessConfig,\n  CassetteInteraction,\n  EvalResult,\n  MetricFn,\n  RegressionResult,\n} from './types.js'\nimport { UnsupportedClientError } from './errors.js'\nimport { CassetteStore } from './cassette/cassette-store.js'\nimport { isAnthropicClient, isOpenAIClient } from './adapters/detect.js'\nimport { wrapAnthropicClient } from './adapters/anthropic.js'\nimport { wrapOpenAIClient } from './adapters/openai.js'\nimport { createFetchInterceptor } from './adapters/http.js'\nimport { runEval } from './eval/evaluator.js'\nimport { saveBaseline, compareBaseline } from './eval/baseline.js'\n\nfunction resolveConfig(config: HarnessConfig): ResolvedHarnessConfig {\n  return {\n    cassettesDir: config.cassettesDir,\n    cassetteName: config.cassetteName ?? 'cassette',\n    mode: config.mode ?? 'replay',\n    noOverwrite: config.noOverwrite ?? false,\n    onBeforeRecord: config.onBeforeRecord ?? ((i: CassetteInteraction) => i),\n  }\n}\n\nexport class Harness {\n  private config: ResolvedHarnessConfig\n  private store: CassetteStore\n\n  constructor(config: HarnessConfig) {\n    this.config = resolveConfig(config)\n    this.store = new CassetteStore(\n      path.join(this.config.cassettesDir, this.config.cassetteName + '.yml'),\n    )\n  }\n\n  get cassettePath(): string {\n    return this.store.path\n  }\n\n  /**\n   * Wraps an Anthropic or OpenAI client with cassette record/replay interception.\n   * The returned object is a transparent Proxy — all methods work identically.\n   */\n  wrap<T extends object>(client: T): T {\n    if (isAnthropicClient(client)) {\n      return wrapAnthropicClient(client, this.store, this.config)\n    }\n    if (isOpenAIClient(client)) {\n      return wrapOpenAIClient(client, this.store, this.config)\n    }\n    throw new UnsupportedClientError()\n  }\n\n  /**\n   * Monkey-patches globalThis.fetch to intercept calls to known LLM API hostnames.\n   * Returns a cleanup function that restores the original fetch.\n   *\n   * @example\n   * const restore = harness.interceptFetch()\n   * try { ... } finally { restore() }\n   */\n  interceptFetch(): () => void {\n    const { intercept, restore } = createFetchInterceptor(this.store, this.config)\n    intercept()\n    return restore\n  }\n\n  /**\n   * Evaluates LLM output text against one or more metrics.\n   */\n  async evaluate(text: string, metrics: MetricFn[]): Promise<EvalResult> {\n    return runEval(text, metrics)\n  }\n\n  /**\n   * Saves the current EvalResult as a named baseline snapshot.\n   * Stored at <cassettesDir>/.baselines/<testName>.json\n   */\n  saveBaseline(testName: string, result: EvalResult): void {\n    saveBaseline(testName, result, this.config.cassettesDir)\n  }\n\n  /**\n   * Compares an EvalResult against a saved baseline, returning regression details.\n   * A regression is detected when current.score < baseline.score - threshold.\n   */\n  compareBaseline(testName: string, result: EvalResult, threshold = 0): RegressionResult {\n    return compareBaseline(testName, result, this.config.cassettesDir, threshold)\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\n\nexport class ExactMatch implements MetricFn {\n  readonly name = 'ExactMatch'\n\n  constructor(\n    private expected: string,\n    private caseSensitive = true,\n  ) {}\n\n  evaluate(text: string): MetricScore {\n    const a = this.caseSensitive ? text : text.toLowerCase()\n    const b = this.caseSensitive ? this.expected : this.expected.toLowerCase()\n    const pass = a === b\n    return { name: this.name, pass, score: pass ? 1 : 0 }\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\n\nexport class Contains implements MetricFn {\n  readonly name = 'Contains'\n\n  constructor(\n    private substring: string,\n    private caseSensitive = true,\n  ) {}\n\n  evaluate(text: string): MetricScore {\n    const haystack = this.caseSensitive ? text : text.toLowerCase()\n    const needle = this.caseSensitive ? this.substring : this.substring.toLowerCase()\n    const pass = haystack.includes(needle)\n    return { name: this.name, pass, score: pass ? 1 : 0 }\n  }\n}\n\nexport class ContainsAll implements MetricFn {\n  readonly name = 'ContainsAll'\n\n  constructor(\n    private substrings: string[],\n    private caseSensitive = true,\n  ) {}\n\n  evaluate(text: string): MetricScore {\n    const haystack = this.caseSensitive ? text : text.toLowerCase()\n    const found = this.substrings.filter((s) => {\n      const needle = this.caseSensitive ? s : s.toLowerCase()\n      return haystack.includes(needle)\n    })\n    const score = this.substrings.length === 0 ? 1 : found.length / this.substrings.length\n    const pass = score === 1\n    const missing = this.substrings.filter((s) => {\n      const needle = this.caseSensitive ? s : s.toLowerCase()\n      return !haystack.includes(needle)\n    })\n    return {\n      name: this.name,\n      pass,\n      score,\n      reason: missing.length > 0 ? `Missing: ${missing.map((s) => `\"${s}\"`).join(', ')}` : undefined,\n    }\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\n\nexport class Regex implements MetricFn {\n  readonly name = 'Regex'\n  private pattern: RegExp\n\n  constructor(pattern: RegExp | string, flags?: string) {\n    this.pattern = pattern instanceof RegExp ? pattern : new RegExp(pattern, flags)\n  }\n\n  evaluate(text: string): MetricScore {\n    const pass = this.pattern.test(text)\n    return { name: this.name, pass, score: pass ? 1 : 0 }\n  }\n}\n","import Ajv from 'ajv'\nimport type { MetricFn, MetricScore } from '../types.js'\n\nconst ajv = new Ajv({ allErrors: true })\n\nexport class JSONSchema implements MetricFn {\n  readonly name = 'JSONSchema'\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  private validate: ReturnType<typeof ajv.compile>\n\n  constructor(schema: Record<string, unknown>) {\n    this.validate = ajv.compile(schema)\n  }\n\n  evaluate(text: string): MetricScore {\n    let parsed: unknown\n    try {\n      parsed = JSON.parse(text)\n    } catch {\n      return { name: this.name, pass: false, score: 0, reason: 'Output is not valid JSON' }\n    }\n\n    const valid = this.validate(parsed)\n    if (valid) {\n      return { name: this.name, pass: true, score: 1 }\n    }\n\n    const reason = this.validate.errors\n      ?.map((e) => `${e.instancePath || '(root)'} ${e.message}`)\n      .join('; ')\n    return { name: this.name, pass: false, score: 0, reason }\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\n\nfunction levenshtein(a: string, b: string): number {\n  const m = a.length\n  const n = b.length\n  const dp: number[][] = []\n\n  for (let i = 0; i <= m; i++) {\n    dp[i] = []\n    for (let j = 0; j <= n; j++) {\n      if (i === 0) {\n        dp[i]![j] = j\n      } else if (j === 0) {\n        dp[i]![j] = i\n      } else if (a[i - 1] === b[j - 1]) {\n        dp[i]![j] = dp[i - 1]![j - 1]!\n      } else {\n        dp[i]![j] = 1 + Math.min(dp[i - 1]![j]!, dp[i]![j - 1]!, dp[i - 1]![j - 1]!)\n      }\n    }\n  }\n\n  return dp[m]![n]!\n}\n\n/**\n * Normalized Levenshtein similarity: 1 - (editDistance / maxLength).\n * Returns 1 for identical strings, 0 for maximally different strings.\n */\nexport function normalizedSimilarity(a: string, b: string): number {\n  if (a === b) return 1\n  const maxLen = Math.max(a.length, b.length)\n  if (maxLen === 0) return 1\n  return 1 - levenshtein(a, b) / maxLen\n}\n\nexport class Similarity implements MetricFn {\n  readonly name = 'Similarity'\n\n  constructor(\n    private reference: string,\n    private threshold = 0.8,\n  ) {}\n\n  evaluate(text: string): MetricScore {\n    const score = normalizedSimilarity(text, this.reference)\n    const pass = score >= this.threshold\n    return {\n      name: this.name,\n      pass,\n      score,\n      reason: pass\n        ? undefined\n        : `Similarity ${score.toFixed(3)} is below threshold ${this.threshold}`,\n    }\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\nimport { isAnthropicClient, isOpenAIClient } from '../adapters/detect.js'\nimport { HarnessError } from '../errors.js'\n\nexport interface LLMJudgeOptions {\n  rubric: string\n  client: object\n  model?: string\n  threshold?: number\n}\n\nfunction buildJudgePrompt(rubric: string, text: string): string {\n  return `You are an objective evaluator. Rate the following output on a scale from 0.0 to 1.0 based on the rubric provided.\n\nRubric: ${rubric}\n\nOutput to evaluate:\n\"\"\"\n${text}\n\"\"\"\n\nRespond with ONLY a JSON object in this exact format, no other text:\n{\"score\": <float between 0.0 and 1.0>, \"reason\": \"<brief explanation>\"}`\n}\n\nfunction parseJudgeResponse(raw: string): { score: number; reason: string } {\n  const jsonMatch = raw.match(/\\{[^{}]*\\}/)\n  if (!jsonMatch) return { score: 0, reason: `Could not parse judge response: ${raw}` }\n  try {\n    const parsed = JSON.parse(jsonMatch[0]) as Record<string, unknown>\n    const score = Math.max(0, Math.min(1, Number(parsed['score']) || 0))\n    return { score, reason: String(parsed['reason'] ?? '') }\n  } catch {\n    return { score: 0, reason: `Invalid JSON from judge: ${raw}` }\n  }\n}\n\nasync function callAnthropicJudge(\n  client: object,\n  model: string,\n  prompt: string,\n): Promise<string> {\n  const anthropicClient = client as {\n    messages: {\n      create: (params: unknown) => Promise<{\n        content: Array<{ type: string; text?: string }>\n      }>\n    }\n  }\n  const response = await anthropicClient.messages.create({\n    model,\n    max_tokens: 200,\n    temperature: 0,\n    messages: [{ role: 'user', content: prompt }],\n  })\n  return response.content[0]?.text ?? ''\n}\n\nasync function callOpenAIJudge(\n  client: object,\n  model: string,\n  prompt: string,\n): Promise<string> {\n  const openaiClient = client as {\n    chat: {\n      completions: {\n        create: (params: unknown) => Promise<{\n          choices: Array<{ message: { content: string | null } }>\n        }>\n      }\n    }\n  }\n  const response = await openaiClient.chat.completions.create({\n    model,\n    max_tokens: 200,\n    temperature: 0,\n    messages: [{ role: 'user', content: prompt }],\n  })\n  return response.choices[0]?.message.content ?? ''\n}\n\nexport class LLMJudge implements MetricFn {\n  readonly name = 'LLMJudge'\n\n  constructor(private options: LLMJudgeOptions) {}\n\n  async evaluate(text: string): Promise<MetricScore> {\n    const { rubric, client, threshold = 0.7 } = this.options\n    const prompt = buildJudgePrompt(rubric, text)\n\n    let raw: string\n    if (isAnthropicClient(client)) {\n      raw = await callAnthropicJudge(client, this.options.model ?? 'claude-haiku-4-5-20251001', prompt)\n    } else if (isOpenAIClient(client)) {\n      raw = await callOpenAIJudge(client, this.options.model ?? 'gpt-4o-mini', prompt)\n    } else {\n      throw new HarnessError('LLMJudge requires a wrapped Anthropic or OpenAI client')\n    }\n\n    const { score, reason } = parseJudgeResponse(raw)\n    return {\n      name: this.name,\n      pass: score >= threshold,\n      score,\n      reason,\n    }\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\n\nexport class Custom implements MetricFn {\n  constructor(\n    readonly name: string,\n    private fn: (text: string) => MetricScore | Promise<MetricScore>,\n  ) {}\n\n  evaluate(text: string): MetricScore | Promise<MetricScore> {\n    return this.fn(text)\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\n\ninterface ContentBlock {\n  type?: string\n  name?: string\n  input?: unknown\n}\n\n/**\n * Asserts that the LLM response included a tool call with the given name.\n *\n * Pass the response content as JSON:\n * @example\n * const text = JSON.stringify(response.content)\n * harness.evaluate(text, [Metrics.toolCalled('search')])\n *\n * Optionally verify the tool input contains a substring:\n * @example\n * Metrics.toolCalled('search', { inputContains: 'Paris' })\n */\nexport class ToolCalled implements MetricFn {\n  readonly name: string\n  private toolName: string\n  private inputContains?: string\n\n  constructor(toolName: string, options?: { inputContains?: string }) {\n    this.toolName = toolName\n    this.inputContains = options?.inputContains\n    this.name = `ToolCalled(${toolName})`\n  }\n\n  evaluate(text: string): MetricScore {\n    let blocks: ContentBlock[]\n    try {\n      const parsed = JSON.parse(text)\n      blocks = Array.isArray(parsed) ? parsed : [parsed]\n    } catch {\n      return {\n        name: this.name,\n        pass: false,\n        score: 0,\n        reason: 'Input is not valid JSON',\n      }\n    }\n\n    const toolBlock = blocks.find(\n      (b) => b.type === 'tool_use' && b.name === this.toolName,\n    )\n\n    if (!toolBlock) {\n      const found = blocks.filter((b) => b.type === 'tool_use').map((b) => b.name)\n      return {\n        name: this.name,\n        pass: false,\n        score: 0,\n        reason: found.length\n          ? `Tool \"${this.toolName}\" not called. Calls found: ${found.join(', ')}`\n          : `No tool calls found in response`,\n      }\n    }\n\n    if (this.inputContains) {\n      const inputStr = JSON.stringify(toolBlock.input ?? '')\n      if (!inputStr.includes(this.inputContains)) {\n        return {\n          name: this.name,\n          pass: false,\n          score: 0.5,\n          reason: `Tool \"${this.toolName}\" was called but input does not contain \"${this.inputContains}\"`,\n        }\n      }\n    }\n\n    return { name: this.name, pass: true, score: 1 }\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\n\n/**\n * Resolves a dot-notation path (e.g. \"user.address.city\") in a nested object.\n * Array indices are supported: \"items.0.name\"\n */\nfunction resolvePath(obj: unknown, path: string): { found: true; value: unknown } | { found: false } {\n  const parts = path.split('.')\n  let current: unknown = obj\n  for (const part of parts) {\n    if (current === null || current === undefined) return { found: false }\n    if (typeof current !== 'object' && !Array.isArray(current)) return { found: false }\n    current = (current as Record<string, unknown>)[part]\n    if (current === undefined) return { found: false }\n  }\n  return { found: true, value: current }\n}\n\n/**\n * Asserts that parsed JSON at `path` equals `expected`.\n *\n * @example\n * // Response: '{\"user\": {\"name\": \"Alice\", \"age\": 30}}'\n * Metrics.jsonPath('user.name', 'Alice')\n * Metrics.jsonPath('user.age', 30)\n */\nexport class JsonPath implements MetricFn {\n  readonly name: string\n  private path: string\n  private expected: unknown\n\n  constructor(path: string, expected: unknown) {\n    this.path = path\n    this.expected = expected\n    this.name = `JsonPath(${path})`\n  }\n\n  evaluate(text: string): MetricScore {\n    let parsed: unknown\n    try {\n      parsed = JSON.parse(text)\n    } catch {\n      return {\n        name: this.name,\n        pass: false,\n        score: 0,\n        reason: 'Input is not valid JSON',\n      }\n    }\n\n    const result = resolvePath(parsed, this.path)\n    if (!result.found) {\n      return {\n        name: this.name,\n        pass: false,\n        score: 0,\n        reason: `Path \"${this.path}\" not found in JSON`,\n      }\n    }\n\n    const actual = result.value\n    const pass = JSON.stringify(actual) === JSON.stringify(this.expected)\n    return {\n      name: this.name,\n      pass,\n      score: pass ? 1 : 0,\n      reason: pass ? undefined : `Expected ${JSON.stringify(this.expected)}, got ${JSON.stringify(actual)}`,\n    }\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\n\n/**\n * Asserts the response is not empty or whitespace-only.\n * Simple but surprisingly useful as a baseline sanity check.\n *\n * @example\n * Metrics.notEmpty()\n * Metrics.notEmpty({ minLength: 10 })\n */\nexport class NotEmpty implements MetricFn {\n  readonly name = 'NotEmpty'\n  private minLength: number\n\n  constructor(options?: { minLength?: number }) {\n    this.minLength = options?.minLength ?? 1\n  }\n\n  evaluate(text: string): MetricScore {\n    const trimmed = text.trim()\n    const pass = trimmed.length >= this.minLength\n    return {\n      name: this.name,\n      pass,\n      score: pass ? 1 : 0,\n      reason: pass\n        ? undefined\n        : this.minLength === 1\n          ? 'Response is empty'\n          : `Response length ${trimmed.length} is below minimum ${this.minLength}`,\n    }\n  }\n}\n","import type { MetricFn, MetricScore } from '../types.js'\n\n/**\n * Asserts the response falls within a word count range.\n * Useful for checking verbosity (LLMs can be too brief or too verbose).\n *\n * @example\n * Metrics.wordCount({ min: 20 })         // at least 20 words\n * Metrics.wordCount({ max: 100 })        // no more than 100 words\n * Metrics.wordCount({ min: 10, max: 50}) // between 10 and 50 words\n */\nexport class WordCount implements MetricFn {\n  readonly name: string\n  private min: number\n  private max: number\n\n  constructor(options: { min?: number; max?: number }) {\n    this.min = options.min ?? 0\n    this.max = options.max ?? Infinity\n    this.name = `WordCount(${this.min}-${this.max === Infinity ? '∞' : this.max})`\n  }\n\n  evaluate(text: string): MetricScore {\n    const count = text.trim() === '' ? 0 : text.trim().split(/\\s+/).length\n    const pass = count >= this.min && count <= this.max\n\n    let reason: string | undefined\n    if (!pass) {\n      if (count < this.min) reason = `${count} words is below minimum ${this.min}`\n      else reason = `${count} words exceeds maximum ${this.max}`\n    }\n\n    return { name: this.name, pass, score: pass ? 1 : 0, reason }\n  }\n}\n","import { ExactMatch } from './exact-match.js'\nimport { Contains, ContainsAll } from './contains.js'\nimport { Regex } from './regex.js'\nimport { JSONSchema } from './json-schema.js'\nimport { Similarity } from './similarity.js'\nimport { LLMJudge } from './llm-judge.js'\nimport type { LLMJudgeOptions } from './llm-judge.js'\nimport { Custom } from './custom.js'\nimport { ToolCalled } from './tool-called.js'\nimport { JsonPath } from './json-path.js'\nimport { NotEmpty } from './not-empty.js'\nimport { WordCount } from './word-count.js'\nimport type { MetricFn, MetricScore } from '../types.js'\n\nexport {\n  ExactMatch,\n  Contains,\n  ContainsAll,\n  Regex,\n  JSONSchema,\n  Similarity,\n  LLMJudge,\n  Custom,\n  ToolCalled,\n  JsonPath,\n  NotEmpty,\n  WordCount,\n}\nexport type { LLMJudgeOptions }\n\nexport const Metrics = {\n  exactMatch(expected: string, caseSensitive = true): MetricFn {\n    return new ExactMatch(expected, caseSensitive)\n  },\n\n  contains(substring: string, caseSensitive = true): MetricFn {\n    return new Contains(substring, caseSensitive)\n  },\n\n  containsAll(substrings: string[], caseSensitive = true): MetricFn {\n    return new ContainsAll(substrings, caseSensitive)\n  },\n\n  regex(pattern: RegExp | string, flags?: string): MetricFn {\n    return new Regex(pattern, flags)\n  },\n\n  jsonSchema(schema: Record<string, unknown>): MetricFn {\n    return new JSONSchema(schema)\n  },\n\n  similarity(reference: string, threshold = 0.8): MetricFn {\n    return new Similarity(reference, threshold)\n  },\n\n  llmJudge(options: LLMJudgeOptions): MetricFn {\n    return new LLMJudge(options)\n  },\n\n  custom(name: string, fn: (text: string) => MetricScore | Promise<MetricScore>): MetricFn {\n    return new Custom(name, fn)\n  },\n\n  /**\n   * Assert the LLM called a specific tool.\n   * Pass `JSON.stringify(response.content)` as the evaluated text.\n   * @example\n   * Metrics.toolCalled('search')\n   * Metrics.toolCalled('search', { inputContains: 'Paris' })\n   */\n  toolCalled(toolName: string, options?: { inputContains?: string }): MetricFn {\n    return new ToolCalled(toolName, options)\n  },\n\n  /**\n   * Assert a value at a dot-notation path in the parsed JSON response.\n   * @example\n   * Metrics.jsonPath('user.name', 'Alice')\n   * Metrics.jsonPath('items.0.id', 42)\n   */\n  jsonPath(path: string, expected: unknown): MetricFn {\n    return new JsonPath(path, expected)\n  },\n\n  /**\n   * Assert the response is not empty. Optionally enforce a minimum character length.\n   * @example\n   * Metrics.notEmpty()\n   * Metrics.notEmpty({ minLength: 20 })\n   */\n  notEmpty(options?: { minLength?: number }): MetricFn {\n    return new NotEmpty(options)\n  },\n\n  /**\n   * Assert the response word count is within a range.\n   * @example\n   * Metrics.wordCount({ min: 10, max: 200 })\n   * Metrics.wordCount({ max: 50 }) // enforce conciseness\n   */\n  wordCount(options: { min?: number; max?: number }): MetricFn {\n    return new WordCount(options)\n  },\n}\n","import type { CassetteInteraction, CassetteMessage } from '../types.js'\n\ntype Scrubber = (interaction: CassetteInteraction) => CassetteInteraction\n\nconst REDACTED = '[REDACTED]'\n\n// Patterns for common secrets\nconst PATTERNS: Record<string, RegExp> = {\n  anthropicKey: /sk-ant-[A-Za-z0-9\\-_]{20,}/g,\n  openaiKey: /sk-[A-Za-z0-9]{20,}/g,\n  bearerToken: /Bearer\\s+[A-Za-z0-9\\-_\\.]{20,}/gi,\n  email: /[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}/g,\n  uuid: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,\n  ipv4: /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g,\n}\n\nfunction scrubString(value: string, pattern: RegExp, replacement: string): string {\n  return value.replace(pattern, replacement)\n}\n\nfunction scrubMessages(messages: CassetteMessage[], pattern: RegExp, replacement: string): CassetteMessage[] {\n  return messages.map((m) => ({\n    ...m,\n    content: typeof m.content === 'string' ? scrubString(m.content, pattern, replacement) : m.content,\n  }))\n}\n\nfunction scrubInteraction(interaction: CassetteInteraction, pattern: RegExp, replacement: string): CassetteInteraction {\n  return {\n    ...interaction,\n    request: {\n      ...interaction.request,\n      system: interaction.request.system\n        ? scrubString(interaction.request.system, pattern, replacement)\n        : interaction.request.system,\n      messages: scrubMessages(interaction.request.messages, pattern, replacement),\n    },\n    response: {\n      ...interaction.response,\n      content: interaction.response.content?.map((b) => ({\n        ...b,\n        text: b.text ? scrubString(b.text, pattern, replacement) : b.text,\n      })),\n    },\n  }\n}\n\n/**\n * Scrubbers are composable helpers for use with `onBeforeRecord`.\n *\n * @example\n * const harness = new Harness({\n *   cassettesDir: './cassettes',\n *   mode: 'record',\n *   onBeforeRecord: Scrubbers.standard(),\n * })\n */\nexport const Scrubbers = {\n  /** Redact Anthropic and OpenAI API keys */\n  apiKey(): Scrubber {\n    return (i) => {\n      let out = scrubInteraction(i, PATTERNS.anthropicKey!, REDACTED)\n      out = scrubInteraction(out, PATTERNS.openaiKey!, REDACTED)\n      out = scrubInteraction(out, PATTERNS.bearerToken!, `Bearer ${REDACTED}`)\n      return out\n    }\n  },\n\n  /** Redact email addresses */\n  email(replacement = REDACTED): Scrubber {\n    return (i) => scrubInteraction(i, PATTERNS.email!, replacement)\n  },\n\n  /** Redact UUIDs */\n  uuid(replacement = '00000000-0000-0000-0000-000000000000'): Scrubber {\n    return (i) => scrubInteraction(i, PATTERNS.uuid!, replacement)\n  },\n\n  /** Redact IPv4 addresses */\n  ipAddress(replacement = '0.0.0.0'): Scrubber {\n    return (i) => scrubInteraction(i, PATTERNS.ipv4!, replacement)\n  },\n\n  /** Redact any custom pattern */\n  custom(pattern: RegExp, replacement = REDACTED): Scrubber {\n    return (i) => scrubInteraction(i, pattern, replacement)\n  },\n\n  /**\n   * Combine multiple scrubbers into one — applied left to right.\n   * @example\n   * Scrubbers.combine(Scrubbers.apiKey(), Scrubbers.email())\n   */\n  combine(...scrubbers: Scrubber[]): Scrubber {\n    return (i) => scrubbers.reduce((acc, s) => s(acc), i)\n  },\n\n  /**\n   * Standard preset: redacts API keys, bearer tokens, emails, UUIDs.\n   * Good starting point for most projects.\n   */\n  standard(): Scrubber {\n    return Scrubbers.combine(\n      Scrubbers.apiKey(),\n      Scrubbers.email(),\n      Scrubbers.uuid(),\n    )\n  },\n}\n"]}