// lib/config/defineConfig.ts
function defineConfig(config) {
  return config;
}

// lib/debug.ts
import fs from "fs";
import path from "path";
var isBrowser = typeof window !== "undefined";
var CONFIG_FILENAME = "agent-health.config.json";
var serverDebugEnabled = false;
if (!isBrowser) {
  try {
    const configPath = path.join(process.cwd(), CONFIG_FILENAME);
    if (fs.existsSync(configPath)) {
      const content = fs.readFileSync(configPath, "utf-8");
      const config = JSON.parse(content) || {};
      serverDebugEnabled = config.debug === true;
    } else if (process.env?.DEBUG === "true") {
      serverDebugEnabled = true;
    }
  } catch (err) {
    if (process.env?.DEBUG === "true") {
      serverDebugEnabled = true;
    }
  }
}
function isDebugEnabled() {
  if (isBrowser) {
    try {
      return localStorage.getItem("agenteval_debug") === "true";
    } catch {
      return false;
    }
  }
  return serverDebugEnabled;
}
function debug(module2, ...args) {
  if (isDebugEnabled()) {
    console.debug(`[${module2}]`, ...args);
  }
}

// services/traces/spanCategorization.ts
import {
  ATTR_GEN_AI_OPERATION_NAME,
  ATTR_GEN_AI_AGENT_NAME,
  ATTR_GEN_AI_PROVIDER_NAME,
  ATTR_GEN_AI_REQUEST_MODEL,
  ATTR_GEN_AI_TOOL_NAME,
  ATTR_GEN_AI_SYSTEM,
  GEN_AI_OPERATION_NAME_VALUE_CREATE_AGENT,
  GEN_AI_OPERATION_NAME_VALUE_INVOKE_AGENT,
  GEN_AI_OPERATION_NAME_VALUE_CHAT,
  GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION,
  GEN_AI_OPERATION_NAME_VALUE_GENERATE_CONTENT,
  GEN_AI_OPERATION_NAME_VALUE_EXECUTE_TOOL
} from "@opentelemetry/semantic-conventions/incubating";

// services/traces/toolSimilarity.ts
import { ATTR_GEN_AI_TOOL_NAME as ATTR_GEN_AI_TOOL_NAME2 } from "@opentelemetry/semantic-conventions/incubating";

// services/traces/traceComparison.ts
import {
  ATTR_GEN_AI_OPERATION_NAME as ATTR_GEN_AI_OPERATION_NAME2,
  ATTR_GEN_AI_AGENT_NAME as ATTR_GEN_AI_AGENT_NAME2,
  ATTR_GEN_AI_REQUEST_MODEL as ATTR_GEN_AI_REQUEST_MODEL2,
  ATTR_GEN_AI_TOOL_NAME as ATTR_GEN_AI_TOOL_NAME3
} from "@opentelemetry/semantic-conventions/incubating";

// services/traces/flowTransform.ts
import dagre2 from "dagre";
import { MarkerType as MarkerType2 } from "@xyflow/react";

// services/traces/executionOrderTransform.ts
import { MarkerType } from "@xyflow/react";
import dagre from "dagre";
import {
  ATTR_GEN_AI_OPERATION_NAME as ATTR_GEN_AI_OPERATION_NAME3,
  GEN_AI_OPERATION_NAME_VALUE_INVOKE_AGENT as GEN_AI_OPERATION_NAME_VALUE_INVOKE_AGENT2,
  GEN_AI_OPERATION_NAME_VALUE_CREATE_AGENT as GEN_AI_OPERATION_NAME_VALUE_CREATE_AGENT2
} from "@opentelemetry/semantic-conventions/incubating";

// services/traces/traceStats.ts
import { ATTR_GEN_AI_TOOL_NAME as ATTR_GEN_AI_TOOL_NAME4 } from "@opentelemetry/semantic-conventions/incubating";

// services/traces/index.ts
function getApiBaseUrl() {
  const isServerSide = typeof window === "undefined";
  if (isServerSide) {
    const port = process.env?.AGENT_HEALTH_PORT || "4001";
    return `http://localhost:${port}`;
  }
  return "";
}
async function fetchTraces(params) {
  const response = await fetch(`${getApiBaseUrl()}/api/traces`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(params)
  });
  if (!response.ok) {
    const error = await response.json().catch(() => ({ error: "Unknown error" }));
    throw new Error(error.error || `HTTP ${response.status}`);
  }
  return response.json();
}
async function fetchTracesByRunIds(runIds) {
  return fetchTraces({ runIds });
}

// services/connectors/base/BaseConnector.ts
var BaseConnector = class {
  /**
   * Build HTTP headers from auth configuration
   * @param auth Authentication configuration
   * @returns Headers object ready for fetch/axios
   */
  buildAuthHeaders(auth) {
    const headers = {};
    switch (auth.type) {
      case "basic":
        if (auth.username && auth.password) {
          const credentials = Buffer.from(`${auth.username}:${auth.password}`).toString("base64");
          headers["Authorization"] = `Basic ${credentials}`;
        }
        break;
      case "bearer":
        if (auth.token) {
          headers["Authorization"] = `Bearer ${auth.token}`;
        }
        break;
      case "api-key":
        if (auth.token) {
          headers["X-API-Key"] = auth.token;
          headers["x-api-key"] = auth.token;
        }
        break;
      case "aws-sigv4":
        console.warn("[BaseConnector] AWS SigV4 auth requires runtime signing");
        break;
      case "none":
      default:
        break;
    }
    if (auth.headers) {
      Object.assign(headers, auth.headers);
    }
    return headers;
  }
  /**
   * Build environment variables from auth configuration
   * Used by subprocess connectors
   */
  buildAuthEnv(auth) {
    const env = {};
    if (auth.type === "aws-sigv4") {
      if (auth.awsRegion) env["AWS_REGION"] = auth.awsRegion;
      if (auth.awsAccessKeyId) env["AWS_ACCESS_KEY_ID"] = auth.awsAccessKeyId;
      if (auth.awsSecretAccessKey) env["AWS_SECRET_ACCESS_KEY"] = auth.awsSecretAccessKey;
      if (auth.awsSessionToken) env["AWS_SESSION_TOKEN"] = auth.awsSessionToken;
    }
    return env;
  }
  /**
   * Generate a unique ID for trajectory steps
   */
  generateId() {
    return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
  }
  /**
   * Create a trajectory step with common fields
   */
  createStep(type, content, extra) {
    return {
      id: this.generateId(),
      timestamp: Date.now(),
      type,
      content,
      ...extra
    };
  }
  /**
   * Default health check implementation
   * Subclasses can override for protocol-specific checks
   */
  async healthCheck(endpoint, auth) {
    try {
      const headers = this.buildAuthHeaders(auth);
      const response = await fetch(endpoint, {
        method: "HEAD",
        headers
      });
      return response.ok;
    } catch (error) {
      console.error(`[${this.type}] Health check failed:`, error);
      return false;
    }
  }
  /**
   * Log debug message with connector type prefix
   */
  debug(message, ...args) {
    debug(this.type, message, ...args);
  }
  /**
   * Log error message with connector type prefix
   */
  error(message, ...args) {
    console.error(`[${this.type}] ${message}`, ...args);
  }
};

// types/agui.ts
import { EventType } from "@ag-ui/core";
var AGUIEventType = EventType;

// services/agent/sseStream.ts
var SSEClient = class {
  constructor() {
    this.abortController = null;
  }
  /**
   * Start consuming SSE stream from the agent endpoint
   */
  async consume(options) {
    const {
      url,
      method = "POST",
      headers = {},
      body,
      onEvent,
      onError,
      onComplete,
      completeOnRunEnd = false,
      idleTimeoutMs = 12e4
      // 2 minute idle timeout by default (LLM agents can be slow)
    } = options;
    this.abortController = new AbortController();
    debug("SSE", "Connecting to", url);
    debug("SSE", "Method:", method);
    debug("SSE", "Headers:", headers);
    debug("SSE", "Payload:", body ? JSON.stringify(body, null, 2).substring(0, 500) : "none");
    debug("SSE", "Timeout:", idleTimeoutMs, "ms");
    try {
      const requestConfig = {
        method,
        headers: {
          "Content-Type": "application/json",
          Accept: "text/event-stream",
          ...headers
        },
        body: body ? JSON.stringify(body) : void 0,
        signal: this.abortController.signal
      };
      debug("SSE", "Request config:", JSON.stringify(requestConfig, null, 2).substring(0, 500));
      const response = await fetch(url, requestConfig);
      debug("SSE", "Response received:", response.status, response.statusText);
      if (!response.ok) {
        let errorBody = "";
        try {
          errorBody = await response.text();
          debug("SSE", "Error response body:", errorBody.substring(0, 500));
        } catch {
          debug("SSE", "Could not read error response body");
        }
        throw new Error(`HTTP ${response.status}: ${response.statusText}${errorBody ? ` - ${errorBody}` : ""}`);
      }
      if (!response.body) {
        throw new Error("Response body is null");
      }
      console.info("[SSE] Connected to agent endpoint, streaming events...");
      debug("SSE", "Response status:", response.status);
      debug("SSE", "Content-Type:", response.headers.get("content-type"));
      const completionReason = await this.processStream(response.body, onEvent, completeOnRunEnd, idleTimeoutMs);
      console.info(`[SSE] Stream completed: ${completionReason}`);
      debug("SSE", `Stream completed: ${completionReason}`);
      onComplete?.();
    } catch (error) {
      if (error instanceof Error) {
        if (error.name === "AbortError") {
          debug("SSE", "Stream aborted (expected after run completion)");
          onComplete?.();
        } else {
          console.error("[SSE] Stream error:", error.message);
          console.error("[SSE] Debug mode is:", isDebugEnabled() ? "ENABLED \u2705" : "DISABLED \u274C");
          const errorDetails = {
            name: error.name,
            message: error.message,
            stack: error.stack,
            cause: error.cause,
            url,
            method,
            headers
          };
          debug("SSE", "Error details:", errorDetails);
          if (error.message.includes("fetch failed")) {
            debug("SSE", '\u{1F4A1} Diagnostic: "fetch failed" typically means:');
            debug("SSE", "   - Connection refused (endpoint not running)");
            debug("SSE", "   - DNS resolution failed (invalid hostname)");
            debug("SSE", "   - Network unreachable (firewall/VPN issues)");
            debug("SSE", "   - SSL/TLS certificate issues (self-signed cert)");
            debug("SSE", `   Check if ${url} is accessible`);
          } else if (error.message.includes("timeout")) {
            debug("SSE", "\u{1F4A1} Diagnostic: Request timed out - endpoint may be slow or unresponsive");
          } else if (error.message.includes("ENOTFOUND")) {
            debug("SSE", "\u{1F4A1} Diagnostic: DNS lookup failed - hostname not found");
          } else if (error.message.includes("ECONNREFUSED")) {
            debug("SSE", "\u{1F4A1} Diagnostic: Connection refused - service not listening on this port");
          }
          onError?.(error);
        }
      } else {
        console.error("[SSE] Unknown error:", error);
        debug("SSE", "Unknown error details:", error);
        onError?.(new Error("Unknown error occurred"));
      }
    }
  }
  /**
   * Process the ReadableStream and parse SSE events
   * @returns Reason for stream completion
   */
  async processStream(stream, onEvent, completeOnRunEnd = false, idleTimeoutMs = 12e4) {
    const reader = stream.getReader();
    const decoder = new TextDecoder();
    let buffer = "";
    let lastEventTime = Date.now();
    let eventCount = 0;
    let idleCheckInterval = null;
    const idleTimeoutPromise = new Promise((resolve2) => {
      idleCheckInterval = setInterval(() => {
        const idleTime = Date.now() - lastEventTime;
        if (eventCount > 0 && idleTime > idleTimeoutMs) {
          debug("SSE", `Idle timeout: no events for ${idleTime}ms (threshold: ${idleTimeoutMs}ms)`);
          this.abort();
          resolve2("idle_timeout");
        }
      }, 1e3);
    });
    try {
      const streamPromise = (async () => {
        while (true) {
          const { done, value } = await reader.read();
          if (done) {
            return "connection_closed";
          }
          lastEventTime = Date.now();
          buffer += decoder.decode(value, { stream: true });
          const lines = buffer.split("\n");
          buffer = lines.pop() || "";
          for (const line of lines) {
            if (line.startsWith("data: ")) {
              const data = line.slice(6);
              if (data.trim()) {
                debug("SSE", "Raw event:", data.substring(0, 200) + (data.length > 200 ? "..." : ""));
                try {
                  const event = JSON.parse(data);
                  debug("SSE", "Parsed event:", event.type);
                  eventCount++;
                  if (eventCount % 10 === 0) {
                    console.info(`[SSE] Processed ${eventCount} events...`);
                  }
                  onEvent(event);
                  if (completeOnRunEnd && (event.type === AGUIEventType.RUN_FINISHED || event.type === AGUIEventType.RUN_ERROR)) {
                    debug("SSE", `Received ${event.type}, completing stream`);
                    this.abort();
                    return `event:${event.type}`;
                  }
                } catch (parseError) {
                  console.error("[SSE] Parse error:", parseError);
                  debug("SSE", "Failed data:", data);
                }
              }
            }
          }
        }
      })();
      const reason = await Promise.race([streamPromise, idleTimeoutPromise]);
      return reason;
    } finally {
      if (idleCheckInterval) {
        clearInterval(idleCheckInterval);
      }
      reader.releaseLock();
    }
  }
  /**
   * Abort the current stream connection
   */
  abort() {
    this.abortController?.abort();
  }
};
async function consumeSSEStream(url, payload, onEvent, headers, options) {
  const client = new SSEClient();
  return new Promise((resolve2, reject) => {
    client.consume({
      url,
      method: "POST",
      headers,
      body: payload,
      onEvent,
      onError: (error) => reject(error),
      onComplete: () => resolve2(),
      // Enable auto-completion on RUN_FINISHED/RUN_ERROR events
      // This prevents hanging when the agent doesn't close the connection
      completeOnRunEnd: true,
      idleTimeoutMs: options?.idleTimeoutMs
    });
  });
}

// services/agent/payloadBuilder.ts
var DEFAULT_PPL_TOOL = {
  name: "execute_ppl_query",
  description: "Update the query bar with a PPL query and optionally execute it",
  parameters: {
    type: "object",
    properties: {
      query: {
        type: "string",
        description: "The PPL query to set in the query bar"
      },
      autoExecute: {
        type: "boolean",
        description: "Whether to automatically execute the query (default: true)"
      },
      description: {
        type: "string",
        description: "Optional description of what the query does"
      }
    },
    required: ["query"]
  }
};
function generateId(prefix) {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substring(2, 11);
  return `${prefix}-${timestamp}-${random}`;
}
function buildAgentPayload(testCase, modelId, threadId, runId) {
  const tools = testCase.tools || [DEFAULT_PPL_TOOL];
  return {
    threadId: threadId || generateId("thread"),
    runId: runId || generateId("run"),
    messages: [
      {
        id: generateId("msg"),
        role: "user",
        content: testCase.initialPrompt
      }
    ],
    tools,
    context: testCase.context || [],
    state: {},
    forwardedProps: {}
  };
}

// services/agent/aguiConverter.ts
import { v4 as uuidv4 } from "uuid";
var AGUIToTrajectoryConverter = class {
  constructor() {
    this.currentTextMessage = null;
    this.activeTools = /* @__PURE__ */ new Map();
    this.hasEmittedAction = false;
    this.runFinished = false;
    this.pendingTextIsResponse = false;
    this.runId = null;
    this.threadId = null;
    // Thinking state tracking
    this.isThinking = false;
    this.currentThinkingMessage = null;
  }
  /**
   * Process a single AG UI event and convert it to TrajectoryStep(s)
   * Returns an array of steps (usually 0 or 1, sometimes more)
   */
  processEvent(event) {
    debug("Converter", `Event: ${event.type}`, JSON.stringify(event).substring(0, 300));
    let steps = [];
    switch (event.type) {
      case AGUIEventType.RUN_STARTED:
        steps = this.handleRunStarted(event);
        break;
      case AGUIEventType.RUN_FINISHED:
        steps = this.handleRunFinished(event);
        break;
      case AGUIEventType.RUN_ERROR:
        steps = this.handleRunError(event);
        break;
      case AGUIEventType.TEXT_MESSAGE_START:
        steps = this.handleTextMessageStart(event);
        break;
      case AGUIEventType.TEXT_MESSAGE_CONTENT:
        steps = this.handleTextMessageContent(event);
        break;
      case AGUIEventType.TEXT_MESSAGE_END:
        steps = this.handleTextMessageEnd(event);
        break;
      case AGUIEventType.ACTIVITY_SNAPSHOT:
        steps = this.handleActivitySnapshot(event);
        break;
      case AGUIEventType.ACTIVITY_DELTA:
        steps = this.handleActivityDelta(event);
        break;
      case AGUIEventType.TOOL_CALL_START:
        steps = this.handleToolCallStart(event);
        break;
      case AGUIEventType.TOOL_CALL_ARGS:
        steps = this.handleToolCallArgs(event);
        break;
      case AGUIEventType.TOOL_CALL_END:
        steps = this.handleToolCallEnd(event);
        break;
      case AGUIEventType.TOOL_CALL_RESULT:
        steps = this.handleToolCallResult(event);
        break;
      // Thinking events - extended reasoning from the model
      case AGUIEventType.THINKING_START:
        steps = this.handleThinkingStart(event);
        break;
      case AGUIEventType.THINKING_END:
        steps = this.handleThinkingEnd(event);
        break;
      case AGUIEventType.THINKING_TEXT_MESSAGE_START:
        steps = this.handleThinkingTextMessageStart(event);
        break;
      case AGUIEventType.THINKING_TEXT_MESSAGE_CONTENT:
        steps = this.handleThinkingTextMessageContent(event);
        break;
      case AGUIEventType.THINKING_TEXT_MESSAGE_END:
        steps = this.handleThinkingTextMessageEnd(event);
        break;
      default:
        debug("Converter", `Skipped unhandled event: ${event.type}`);
        break;
    }
    if (steps.length > 0) {
      debug("Converter", `Generated ${steps.length} step(s):`, steps.map((s) => `${s.type}${s.toolName ? `:${s.toolName}` : ""}`).join(", "));
    }
    return steps;
  }
  handleRunStarted(event) {
    this.runId = event.runId;
    this.threadId = event.threadId;
    debug("Converter", `Run started - runId: ${this.runId}, threadId: ${this.threadId}`);
    this.currentTextMessage = null;
    this.activeTools.clear();
    this.hasEmittedAction = false;
    this.runFinished = false;
    this.pendingTextIsResponse = false;
    this.isThinking = false;
    this.currentThinkingMessage = null;
    return [];
  }
  getRunId() {
    return this.runId;
  }
  getThreadId() {
    return this.threadId;
  }
  handleRunFinished(event) {
    this.runFinished = true;
    if (this.currentTextMessage) {
      this.pendingTextIsResponse = true;
    }
    return [];
  }
  handleRunError(event) {
    console.error("[Converter] Run error:", event.message);
    return [{
      id: uuidv4(),
      timestamp: event.timestamp,
      type: "tool_result",
      content: `Error: ${event.message}`,
      status: "FAILURE" /* FAILURE */
    }];
  }
  handleTextMessageStart(event) {
    debug("Converter", `Text message start: ${event.messageId}`);
    this.currentTextMessage = {
      messageId: event.messageId,
      startTime: event.timestamp,
      content: ""
    };
    return [];
  }
  handleTextMessageContent(event) {
    if (this.currentTextMessage && this.currentTextMessage.messageId === event.messageId) {
      this.currentTextMessage.content += event.delta;
    }
    return [];
  }
  handleTextMessageEnd(event) {
    if (!this.currentTextMessage || this.currentTextMessage.messageId !== event.messageId) {
      debug("Converter", `Text end for unknown message: ${event.messageId}`);
      return [];
    }
    const latencyMs = event.timestamp - this.currentTextMessage.startTime;
    const content = this.currentTextMessage.content.trim();
    let stepType;
    if (this.pendingTextIsResponse || this.runFinished) {
      stepType = "response";
    } else {
      stepType = "assistant";
    }
    debug("Converter", `Classification: ${stepType} (runFinished=${this.runFinished}, pendingResponse=${this.pendingTextIsResponse}, hasAction=${this.hasEmittedAction})`);
    if (stepType === "assistant" && content.length === 0) {
      debug("Converter", "Skipping empty assistant message");
      this.currentTextMessage = null;
      return [];
    }
    const step = {
      id: uuidv4(),
      timestamp: event.timestamp,
      type: stepType,
      content,
      latencyMs
    };
    this.currentTextMessage = null;
    return [step];
  }
  handleActivitySnapshot(event) {
    const toolName = this.extractToolName(event.content.title);
    const toolArgs = this.parseToolArgs(event.content.description);
    const actionStepId = uuidv4();
    this.activeTools.set(event.messageId, {
      messageId: event.messageId,
      toolName,
      toolArgs,
      argsAccumulator: "",
      startTime: event.timestamp,
      actionStepId
    });
    this.hasEmittedAction = true;
    debug("Converter", `Tool action: ${toolName}`, toolArgs);
    return [{
      id: actionStepId,
      timestamp: event.timestamp,
      type: "action",
      content: `Calling ${toolName}...`,
      toolName,
      toolArgs
    }];
  }
  handleActivityDelta(event) {
    const toolState = this.activeTools.get(event.messageId);
    if (!toolState) return [];
    const isCompletion = event.patch.some(
      (op) => op.path === "/icon" && (op.value === "CheckCircle" || op.value === "Check")
    );
    if (!isCompletion) return [];
    const descriptionPatch = event.patch.find((op) => op.path === "/description");
    const resultContent = descriptionPatch?.value || "Tool execution completed";
    const latencyMs = event.timestamp - toolState.startTime;
    this.activeTools.delete(event.messageId);
    return [{
      id: uuidv4(),
      timestamp: event.timestamp,
      type: "tool_result",
      content: resultContent,
      status: "SUCCESS" /* SUCCESS */,
      latencyMs
    }];
  }
  handleToolCallStart(event) {
    const actionStepId = uuidv4();
    this.activeTools.set(event.toolCallId, {
      messageId: event.toolCallId,
      toolName: event.toolCallName,
      toolArgs: {},
      argsAccumulator: "",
      // Will accumulate delta strings
      startTime: event.timestamp,
      actionStepId
    });
    this.hasEmittedAction = true;
    debug("Converter", `Tool call started: ${event.toolCallName} (${event.toolCallId})`);
    return [];
  }
  handleToolCallArgs(event) {
    const toolState = this.activeTools.get(event.toolCallId);
    if (toolState) {
      toolState.argsAccumulator += event.delta;
      debug("Converter", `Tool args delta accumulated (${toolState.argsAccumulator.length} chars total)`);
    }
    return [];
  }
  /**
   * Handle TOOL_CALL_END - emits the action step with complete args
   * This is called when the agent is done sending tool call arguments
   * and expects the client to execute the tool
   */
  handleToolCallEnd(event) {
    const toolState = this.activeTools.get(event.toolCallId);
    if (!toolState) {
      debug("Converter", `Tool call end for unknown tool: ${event.toolCallId}`);
      return [];
    }
    let parsedArgs = {};
    if (toolState.argsAccumulator) {
      try {
        parsedArgs = JSON.parse(toolState.argsAccumulator);
        debug("Converter", `Tool args parsed: ${JSON.stringify(parsedArgs).substring(0, 200)}`);
      } catch {
        parsedArgs = { _raw: toolState.argsAccumulator };
      }
    }
    toolState.toolArgs = parsedArgs;
    const latencyMs = event.timestamp - toolState.startTime;
    const actionStep = {
      id: toolState.actionStepId,
      timestamp: toolState.startTime,
      type: "action",
      content: `Calling ${toolState.toolName}...`,
      toolName: toolState.toolName,
      toolArgs: parsedArgs,
      latencyMs
    };
    debug("Converter", `Tool call end: ${toolState.toolName} - action step emitted with args`);
    toolState.actionStepId = "";
    return [actionStep];
  }
  handleToolCallResult(event) {
    const toolState = this.activeTools.get(event.toolCallId);
    if (!toolState) return [];
    const latencyMs = event.timestamp - toolState.startTime;
    const steps = [];
    const actionAlreadyEmitted = !toolState.actionStepId;
    if (!actionAlreadyEmitted) {
      let parsedArgs = {};
      if (toolState.argsAccumulator) {
        try {
          parsedArgs = JSON.parse(toolState.argsAccumulator);
          debug("Converter", `Tool args parsed: ${JSON.stringify(parsedArgs).substring(0, 200)}`);
        } catch {
          parsedArgs = { _raw: toolState.argsAccumulator };
        }
      }
      toolState.toolArgs = parsedArgs;
      steps.push({
        id: toolState.actionStepId,
        timestamp: toolState.startTime,
        type: "action",
        content: `Calling ${toolState.toolName}...`,
        toolName: toolState.toolName,
        toolArgs: parsedArgs
      });
    }
    let resultContent;
    try {
      const parsed = JSON.parse(event.content);
      resultContent = typeof parsed === "string" ? parsed : JSON.stringify(parsed, null, 2);
    } catch (e) {
      resultContent = event.content;
    }
    steps.push({
      id: uuidv4(),
      timestamp: event.timestamp,
      type: "tool_result",
      content: resultContent,
      status: "SUCCESS" /* SUCCESS */,
      latencyMs
    });
    this.activeTools.delete(event.toolCallId);
    debug("Converter", `Tool call result: ${toolState.toolName} -> ${steps.length} steps emitted (action already emitted: ${actionAlreadyEmitted})`);
    return steps;
  }
  // ============ THINKING Event Handlers ============
  handleThinkingStart(event) {
    this.isThinking = true;
    debug("Converter", "Thinking started");
    return [];
  }
  handleThinkingEnd(event) {
    this.isThinking = false;
    debug("Converter", "Thinking ended");
    return [];
  }
  handleThinkingTextMessageStart(event) {
    this.currentThinkingMessage = {
      startTime: event.timestamp || Date.now(),
      content: ""
    };
    debug("Converter", "Thinking text message started");
    return [];
  }
  handleThinkingTextMessageContent(event) {
    if (this.currentThinkingMessage) {
      this.currentThinkingMessage.content += event.delta;
    }
    return [];
  }
  handleThinkingTextMessageEnd(event) {
    if (!this.currentThinkingMessage) {
      debug("Converter", "Thinking text end with no active thinking message");
      return [];
    }
    const content = this.currentThinkingMessage.content.trim();
    if (content.length === 0) {
      debug("Converter", "Skipping empty thinking message");
      this.currentThinkingMessage = null;
      return [];
    }
    const latencyMs = (event.timestamp || Date.now()) - this.currentThinkingMessage.startTime;
    const step = {
      id: uuidv4(),
      timestamp: this.currentThinkingMessage.startTime,
      type: "thinking",
      content,
      latencyMs
    };
    debug("Converter", `Thinking message completed: ${content.length} chars`);
    this.currentThinkingMessage = null;
    return [step];
  }
  extractToolName(title) {
    const runningMatch = title.match(/^Running\s+(.+)$/);
    if (runningMatch) return runningMatch[1];
    const completedMatch = title.match(/^(.+)\s+completed$/i);
    if (completedMatch) return completedMatch[1];
    return title;
  }
  parseToolArgs(description) {
    try {
      const args = {};
      const pairs = description.match(/(\w+):\s*("(?:[^"]|\\")*"|\w+)/g);
      if (pairs) {
        pairs.forEach((pair) => {
          const [key, rawValue] = pair.split(":").map((s) => s.trim());
          let value = rawValue;
          if (rawValue.startsWith('"') && rawValue.endsWith('"')) {
            value = rawValue.slice(1, -1);
          } else if (rawValue === "true") {
            value = true;
          } else if (rawValue === "false") {
            value = false;
          } else if (!isNaN(Number(rawValue))) {
            value = Number(rawValue);
          }
          args[key] = value;
        });
        return args;
      }
      return { description };
    } catch (e) {
      return { description };
    }
  }
};
function computeTrajectoryFromRawEvents(rawEvents) {
  const converter = new AGUIToTrajectoryConverter();
  const trajectory = [];
  for (const event of rawEvents) {
    const steps = converter.processEvent(event);
    trajectory.push(...steps);
  }
  trajectory.sort((a, b) => a.timestamp - b.timestamp);
  return trajectory;
}

// services/connectors/agui/AGUIStreamingConnector.ts
var AGUIStreamingConnector = class extends BaseConnector {
  constructor() {
    super(...arguments);
    this.type = "agui-streaming";
    this.name = "AG-UI Streaming";
    this.supportsStreaming = true;
  }
  /**
   * Build AG-UI payload from standard request
   */
  buildPayload(request) {
    return buildAgentPayload(
      request.testCase,
      request.modelId,
      request.threadId,
      request.runId
    );
  }
  /**
   * Execute the request using SSE streaming
   */
  async execute(endpoint, request, auth, onProgress, onRawEvent) {
    const hasPrebuiltPayload = !!request.payload;
    const payload = request.payload || this.buildPayload(request);
    const headers = this.buildAuthHeaders(auth);
    const trajectory = [];
    const rawEvents = [];
    const converter = new AGUIToTrajectoryConverter();
    this.debug("Executing AG-UI streaming request");
    await consumeSSEStream(
      endpoint,
      payload,
      (event) => {
        rawEvents.push(event);
        onRawEvent?.(event);
        const steps = converter.processEvent(event);
        steps.forEach((step) => {
          trajectory.push(step);
          onProgress?.(step);
        });
      },
      headers
    );
    const runId = converter.getRunId();
    this.debug("Stream completed. RunId:", runId, "Steps:", trajectory.length);
    return {
      trajectory,
      runId,
      rawEvents,
      metadata: {
        threadId: converter.getThreadId()
      }
    };
  }
  /**
   * Parse raw AG-UI events into trajectory steps
   * Used for re-processing stored raw events
   */
  parseResponse(rawEvents) {
    return computeTrajectoryFromRawEvents(rawEvents);
  }
  /**
   * Health check for AG-UI endpoint
   * Tries to connect without sending a full request
   */
  async healthCheck(endpoint, auth) {
    try {
      const headers = this.buildAuthHeaders(auth);
      const response = await fetch(endpoint, {
        method: "OPTIONS",
        headers
      });
      return true;
    } catch (error) {
      this.error("Health check failed:", error);
      return false;
    }
  }
};
var aguiStreamingConnector = new AGUIStreamingConnector();

// services/connectors/rest/RESTConnector.ts
var RESTConnector = class extends BaseConnector {
  constructor() {
    super(...arguments);
    this.type = "rest";
    this.name = "REST API";
    this.supportsStreaming = false;
  }
  /**
   * Build generic REST payload
   * Can be customized via connectorConfig
   */
  buildPayload(request) {
    return {
      prompt: request.testCase.initialPrompt,
      context: request.testCase.context,
      model: request.modelId,
      tools: request.testCase.tools
    };
  }
  /**
   * Execute REST request
   */
  async execute(endpoint, request, auth, onProgress, onRawEvent) {
    const payload = request.payload || this.buildPayload(request);
    const headers = this.buildAuthHeaders(auth);
    this.debug("Executing REST request");
    this.debug("Endpoint:", endpoint);
    this.debug("Payload:", JSON.stringify(payload).substring(0, 500));
    const response = await fetch(endpoint, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        ...headers
      },
      body: JSON.stringify(payload)
    });
    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`REST request failed: ${response.status} - ${errorText}`);
    }
    const data = await response.json();
    onRawEvent?.(data);
    const trajectory = this.parseResponse(data);
    trajectory.forEach((step) => onProgress?.(step));
    return {
      trajectory,
      runId: data.runId || data.id || null,
      rawEvents: [data],
      metadata: {
        status: response.status,
        responseHeaders: Object.fromEntries(response.headers.entries())
      }
    };
  }
  /**
   * Parse REST response into trajectory steps
   * This is a generic implementation - subclass for specific APIs
   */
  parseResponse(data) {
    const steps = [];
    if (data.thinking) {
      steps.push(this.createStep("thinking", data.thinking));
    }
    if (data.toolCalls && Array.isArray(data.toolCalls)) {
      for (const call of data.toolCalls) {
        steps.push(this.createStep("action", `Calling ${call.name}...`, {
          toolName: call.name,
          toolArgs: call.args || call.input
        }));
        if (call.result !== void 0) {
          steps.push(this.createStep(
            "tool_result",
            typeof call.result === "string" ? call.result : JSON.stringify(call.result),
            { status: "SUCCESS" }
          ));
        }
      }
    }
    const responseContent = data.response || data.content || data.answer || data.text || data.message;
    if (responseContent) {
      steps.push(this.createStep(
        "response",
        typeof responseContent === "string" ? responseContent : JSON.stringify(responseContent)
      ));
    }
    if (data.inference_results) {
      const outputs = data.inference_results[0]?.output || [];
      for (const output of outputs) {
        if (output.name === "response") {
          const content = output.dataAsMap?.response || output.result;
          if (content) {
            steps.push(this.createStep("response", content));
          }
        }
      }
    }
    if (steps.length === 0 && data) {
      steps.push(this.createStep("response", JSON.stringify(data, null, 2)));
    }
    return steps;
  }
};
var restConnector = new RESTConnector();

// services/connectors/subprocess/SubprocessConnector.ts
import { spawn } from "child_process";
var DEFAULT_SUBPROCESS_CONFIG = {
  command: "",
  args: [],
  env: {},
  inputMode: "stdin",
  outputParser: "text",
  timeout: 3e5
  // 5 minutes
};
var SubprocessConnector = class extends BaseConnector {
  constructor(config) {
    super();
    this.type = "subprocess";
    this.name = "Subprocess (CLI)";
    this.supportsStreaming = true;
    /** Buffer of clean stdout lines accumulated during streaming.
     *  Used by onBeforeStreamEnd() to emit a consolidated `response` step. */
    this.streamBuffer = [];
    this.config = { ...DEFAULT_SUBPROCESS_CONFIG, ...config };
  }
  /**
   * Build input for the subprocess
   */
  buildPayload(request) {
    let prompt = request.testCase.initialPrompt;
    if (request.testCase.context && request.testCase.context.length > 0) {
      const contextStr = request.testCase.context.map((c) => `${c.description}: ${c.value}`).join("\n");
      prompt = `Context:
${contextStr}

Question: ${prompt}`;
    }
    return prompt;
  }
  /**
   * Execute subprocess and capture output
   */
  async execute(endpoint, request, auth, onProgress, onRawEvent) {
    this.debug("========== execute() STARTED ==========");
    this.streamBuffer = [];
    const cfgOverride = request.connectorConfig || {};
    if (cfgOverride.command !== void 0) this.config.command = cfgOverride.command;
    if (cfgOverride.args !== void 0) this.config.args = cfgOverride.args;
    if (cfgOverride.env !== void 0) this.config.env = { ...this.config.env || {}, ...cfgOverride.env };
    if (cfgOverride.inputMode !== void 0) this.config.inputMode = cfgOverride.inputMode;
    if (cfgOverride.outputParser !== void 0) this.config.outputParser = cfgOverride.outputParser;
    if (cfgOverride.timeout !== void 0) this.config.timeout = cfgOverride.timeout;
    if (cfgOverride.workingDir !== void 0) this.config.workingDir = cfgOverride.workingDir;
    const command = endpoint || this.config.command;
    const args = this.config.args || [];
    const input = request.payload || this.buildPayload(request);
    const runId = `subprocess-${Date.now()}`;
    this.debug("Command:", command);
    this.debug("Args:", args);
    this.debug("Input mode:", this.config.inputMode);
    this.debug("Output parser:", this.config.outputParser);
    this.debug("Timeout:", this.config.timeout);
    this.debug("Input (first 500 chars):", input.substring(0, 500));
    this.debug("Working dir:", this.config.workingDir || process.cwd());
    this.debug("Run ID:", runId);
    const env = {
      ...process.env,
      ...this.buildAuthEnv(auth),
      ...this.config.env,
      AGENT_EVAL_RUN_ID: runId
    };
    return new Promise((resolve2, reject) => {
      const trajectory = [];
      const rawOutput = [];
      let stdout = "";
      let stderr = "";
      let settled = false;
      const shellQuote = (s) => `'${String(s).replace(/'/g, `'\\''`)}'`;
      const finalArgs = this.config.inputMode === "arg" ? [...args, shellQuote(input)] : args;
      this.debug("Spawning process...");
      this.debug("Full command:", command, finalArgs.join(" "));
      const proc = spawn(command, finalArgs, {
        env,
        cwd: this.config.workingDir,
        shell: true
      });
      this.debug("Process spawned, PID:", proc.pid);
      const timeoutId = setTimeout(() => {
        if (settled) return;
        settled = true;
        this.debug("TIMEOUT reached, killing process");
        proc.kill("SIGTERM");
        reject(new Error(`Subprocess timed out after ${this.config.timeout}ms`));
      }, this.config.timeout);
      if (this.config.inputMode === "stdin") {
        this.debug("Writing input to stdin...");
        proc.stdin.write(input);
        proc.stdin.end();
        this.debug("stdin closed");
      }
      proc.stdout.on("data", (data) => {
        const chunk = data.toString();
        this.debug("stdout received:", chunk.length, "bytes");
        this.debug("stdout preview:", chunk.substring(0, 200));
        stdout += chunk;
        rawOutput.push({ type: "stdout", data: chunk, timestamp: Date.now() });
        onRawEvent?.({ type: "stdout", data: chunk });
        if (this.config.outputParser === "streaming") {
          this.parseStreamingOutput(chunk, trajectory, onProgress);
        }
      });
      proc.stderr.on("data", (data) => {
        const chunk = data.toString();
        this.debug("stderr received:", chunk.length, "bytes");
        this.debug("stderr:", chunk);
        stderr += chunk;
        rawOutput.push({ type: "stderr", data: chunk, timestamp: Date.now() });
        onRawEvent?.({ type: "stderr", data: chunk });
        if (this.config.outputParser === "streaming") {
          this.parseStderrChunk(chunk, trajectory, onProgress);
        }
      });
      proc.on("close", (code2, signal) => {
        this.debug("Process closed with code:", code2, "signal:", signal);
        clearTimeout(timeoutId);
        if (settled) return;
        settled = true;
        if (code2 !== 0) {
          this.debug("Non-zero exit code:", code2);
          this.error(`Process exited with code ${code2}`);
          this.error("stderr:", stderr);
        }
        if (this.config.outputParser === "streaming") {
          this.onBeforeStreamEnd(trajectory, onProgress);
          if (code2 !== 0 && trajectory.length === 0) {
            const errorContent = stderr.trim() ? `Error: Process exited with code ${code2}. ${stderr.trim()}` : `Error: Process exited with code ${code2}`;
            const errorStep = this.createStep("tool_result", errorContent, {
              status: "FAILURE" /* FAILURE */
            });
            trajectory.push(errorStep);
            onProgress?.(errorStep);
          }
        }
        const finalTrajectory = this.config.outputParser === "streaming" ? trajectory : this.parseResponse({ stdout, stderr, exitCode: code2 });
        if (this.config.outputParser !== "streaming") {
          finalTrajectory.forEach((step) => onProgress?.(step));
        }
        this.debug("Resolving with trajectory of", finalTrajectory.length, "steps");
        resolve2({
          trajectory: finalTrajectory,
          runId,
          rawEvents: rawOutput,
          metadata: {
            command,
            args: finalArgs,
            exitCode: code2,
            stderr: stderr || void 0
          }
        });
      });
      proc.on("error", (error) => {
        this.debug("ERROR event:", error.message);
        clearTimeout(timeoutId);
        if (settled) return;
        settled = true;
        let errorMsg = `Failed to spawn subprocess: ${error.message}`;
        if (error.message.includes("ENOENT")) {
          errorMsg = `Command '${command}' not found. Is it installed and in PATH?`;
          console.error(`[Subprocess] ENOENT error - command '${command}' not found in PATH`);
        } else if (error.message.includes("EACCES")) {
          errorMsg = `Permission denied executing '${command}'. Check file permissions.`;
          console.error(`[Subprocess] EACCES error - permission denied for '${command}'`);
        } else if (error.message.includes("EPERM")) {
          errorMsg = `Operation not permitted for '${command}'. May require elevated privileges.`;
          console.error(`[Subprocess] EPERM error - operation not permitted`);
        }
        reject(new Error(errorMsg));
      });
    });
    this.debug("========== execute() COMPLETED ==========");
  }
  /**
   * Parse a stderr chunk in streaming mode. Default is a no-op.
   *
   * Override in subclasses for CLIs that carry tool-event markers on stderr.
   * Implementations should buffer partial lines (chunks rarely align with
   * line boundaries) and emit steps via `onProgress` AND push them onto
   * `trajectory` so they appear in the final response.
   */
  parseStderrChunk(_chunk, _trajectory, _onProgress) {
  }
  /**
   * Parse streaming output and emit steps in real-time.
   *
   * For plain-text CLIs (Kiro etc.) we:
   *   1. strip ANSI escape codes (color, cursor moves, spinner frames)
   *   2. drop lines that are empty / pure control characters / spinner glyphs
   *   3. emit each surviving line as an `assistant` step immediately
   *   4. buffer the cleaned text so `onBeforeStreamEnd()` can emit a final
   *      `response` step containing the full coherent answer (good for the
   *      judge) — without losing the live stream.
   */
  parseStreamingOutput(chunk, trajectory, onProgress) {
    const stripped = chunk.replace(/\x1b\][^\x07\x1b]*(\x07|\x1b\\)/g, "").replace(/\x1b\[[0-9;?]*[A-Za-z]/g, "").replace(/\x1b[=>NOP\\]/g, "").replace(/\r/g, "\n");
    const lines = stripped.split("\n");
    for (const raw of lines) {
      const line = raw.replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "").trim();
      if (!line) continue;
      if (/^[⠁-⣿\s]+$/.test(line)) continue;
      if (line.length < 2 && !/[A-Za-z0-9]/.test(line)) continue;
      this.streamBuffer.push(line);
      const step = this.createStep("assistant", line);
      trajectory.push(step);
      onProgress?.(step);
    }
  }
  /**
   * On stream end: emit a consolidated `response` step containing the full
   * clean output. Streaming gave the user real-time visibility; this final
   * step gives the judge a single coherent answer to grade against.
   */
  onBeforeStreamEnd(trajectory, onProgress) {
    if (this.streamBuffer.length > 0) {
      const finalText = this.streamBuffer.join("\n").trim();
      this.streamBuffer = [];
      if (finalText) {
        const step = this.createStep("response", finalText);
        trajectory.push(step);
        onProgress?.(step);
      }
    }
  }
  /**
   * Parse final subprocess output
   */
  parseResponse(data) {
    const steps = [];
    if (this.config.outputParser === "json") {
      try {
        const parsed = JSON.parse(data.stdout);
        return this.parseJsonOutput(parsed);
      } catch {
        this.debug("Failed to parse JSON output, falling back to text");
      }
    }
    if (data.stdout.trim() && data.exitCode === 0) {
      steps.push(this.createStep("response", data.stdout.trim()));
    }
    if (data.exitCode !== 0) {
      const errorContent = data.stderr.trim() ? `Error: Process exited with code ${data.exitCode}. ${data.stderr.trim()}` : data.stdout.trim() ? `Error: Process exited with code ${data.exitCode}. stdout: ${data.stdout.trim()}` : `Error: Process exited with code ${data.exitCode} (no output)`;
      steps.push(this.createStep("tool_result", errorContent, {
        status: "FAILURE" /* FAILURE */
      }));
    }
    return steps;
  }
  /**
   * Parse JSON output into trajectory steps
   */
  parseJsonOutput(data) {
    const steps = [];
    if (data.thinking) {
      steps.push(this.createStep("thinking", data.thinking));
    }
    if (data.steps && Array.isArray(data.steps)) {
      for (const step of data.steps) {
        steps.push(this.createStep(step.type || "assistant", step.content, {
          toolName: step.toolName,
          toolArgs: step.toolArgs
        }));
      }
    }
    if (data.response || data.answer || data.content) {
      steps.push(this.createStep("response", data.response || data.answer || data.content));
    }
    return steps;
  }
  /**
   * Health check - verify command exists
   */
  async healthCheck(endpoint, auth) {
    const command = endpoint || this.config.command;
    if (!command) return false;
    return new Promise((resolve2) => {
      const proc = spawn("which", [command], { shell: true });
      proc.on("close", (code2) => resolve2(code2 === 0));
      proc.on("error", () => resolve2(false));
    });
  }
};
var subprocessConnector = new SubprocessConnector();

// services/connectors/claude-code/ClaudeCodeConnector.ts
var CLAUDE_CODE_DEFAULT_CONFIG = {
  command: "claude",
  args: ["--print", "--verbose", "--output-format", "stream-json"],
  // Structured JSON output (--verbose required with stream-json)
  env: {
    // These can be overridden by agent config or environment
    DISABLE_PROMPT_CACHING: "1",
    DISABLE_ERROR_REPORTING: "1"
    // Note: DISABLE_TELEMETRY removed - telemetry enabled by default
    // Configure OTEL_EXPORTER_OTLP_ENDPOINT in .env to send traces
  },
  inputMode: "stdin",
  outputParser: "streaming",
  timeout: 6e5
  // 10 minutes for Claude Code
};
var ClaudeCodeConnector = class extends SubprocessConnector {
  constructor(config) {
    super({ ...CLAUDE_CODE_DEFAULT_CONFIG, ...config });
    this.type = "claude-code";
    this.name = "Claude Code CLI";
    this.outputBuffer = "";
    this.thinkingBuffer = "";
    this.textBuffer = "";
    this.isInThinking = false;
  }
  /**
   * Build prompt for Claude Code
   * Structures the input to get the best RCA results
   */
  buildPayload(request) {
    const parts = [];
    if (request.testCase.context && request.testCase.context.length > 0) {
      parts.push("## Context");
      for (const ctx of request.testCase.context) {
        parts.push(`**${ctx.description}:**`);
        parts.push(ctx.value);
        parts.push("");
      }
    }
    parts.push("## Task");
    parts.push(request.testCase.initialPrompt);
    return parts.join("\n");
  }
  /**
   * Parse Claude Code streaming output (stream-json format)
   * Each line is a JSON object with type and content
   */
  parseStreamingOutput(chunk, trajectory, onProgress) {
    this.outputBuffer += chunk;
    const lines = this.outputBuffer.split("\n");
    this.outputBuffer = lines.pop() || "";
    for (const line of lines) {
      const trimmed = line.trim();
      if (!trimmed) continue;
      try {
        const event = JSON.parse(trimmed);
        const steps = this.parseJsonEvent(event);
        for (const step of steps) {
          trajectory.push(step);
          onProgress?.(step);
        }
      } catch {
        if (trimmed) {
          const step = this.createStep("assistant", trimmed);
          trajectory.push(step);
          onProgress?.(step);
        }
      }
    }
  }
  /**
   * Parse a single JSON event from stream-json output
   */
  parseJsonEvent(event) {
    const steps = [];
    if (event.type === "assistant" && event.message?.content) {
      for (const block of event.message.content) {
        if (block.type === "thinking" && block.thinking) {
          steps.push(this.createStep("thinking", block.thinking));
        } else if (block.type === "text" && block.text) {
          steps.push(this.createStep("assistant", block.text));
        } else if (block.type === "tool_use") {
          steps.push(this.createStep("action", JSON.stringify(block.input || {}), {
            toolName: block.name,
            toolArgs: block.input
          }));
        }
      }
    } else if (event.type === "user" && event.message?.content) {
      for (const block of event.message.content) {
        if (block.type === "tool_result") {
          const content = typeof block.content === "string" ? block.content : JSON.stringify(block.content);
          steps.push(
            this.createStep("tool_result", content, {
              status: block.is_error ? "FAILURE" /* FAILURE */ : "SUCCESS" /* SUCCESS */
            })
          );
        } else if (block.type === "text" && block.text) {
          steps.push(this.createStep("assistant", block.text));
        }
      }
    } else if (event.type === "content_block_delta") {
      if (event.delta?.type === "thinking_delta" && event.delta.thinking) {
        this.thinkingBuffer += event.delta.thinking;
      } else if (event.delta?.type === "text_delta" && event.delta.text) {
        this.textBuffer += event.delta.text;
      }
    } else if (event.type === "content_block_stop") {
      if (this.thinkingBuffer) {
        steps.push(this.createStep("thinking", this.thinkingBuffer));
        this.thinkingBuffer = "";
      }
      if (this.textBuffer) {
        steps.push(this.createStep("assistant", this.textBuffer));
        this.textBuffer = "";
      }
    } else if (event.type === "result" && event.result) {
      steps.push(this.createStep(
        "response",
        typeof event.result === "string" ? event.result : JSON.stringify(event.result)
      ));
    }
    return steps;
  }
  /**
   * Parse final output for Claude Code
   */
  parseResponse(data) {
    const steps = [];
    let content = data.stdout;
    const thinkingMatches = content.matchAll(/<thinking>([\s\S]*?)<\/thinking>/g);
    for (const match of thinkingMatches) {
      const thinking = match[1].trim();
      if (thinking) {
        steps.push(this.createStep("thinking", thinking));
      }
      content = content.replace(match[0], "");
    }
    const response = content.trim();
    if (response) {
      steps.push(this.createStep("response", response));
    }
    if (data.exitCode !== 0 && data.stderr.trim()) {
      steps.push(this.createStep("tool_result", `Error: ${data.stderr.trim()}`, {
        status: "FAILURE" /* FAILURE */
      }));
    }
    return steps;
  }
  /**
   * Reset state for new execution
   */
  resetState() {
    this.outputBuffer = "";
    this.thinkingBuffer = "";
    this.textBuffer = "";
    this.isInThinking = false;
  }
  /**
   * Flush remaining buffers when the subprocess stream ends.
   */
  onBeforeStreamEnd(trajectory, onProgress) {
    if (this.outputBuffer.trim()) {
      try {
        const event = JSON.parse(this.outputBuffer.trim());
        const steps = this.parseJsonEvent(event);
        for (const step of steps) {
          trajectory.push(step);
          onProgress?.(step);
        }
      } catch {
        const step = this.createStep("assistant", this.outputBuffer.trim());
        trajectory.push(step);
        onProgress?.(step);
      }
      this.outputBuffer = "";
    }
    if (this.thinkingBuffer) {
      const step = this.createStep("thinking", this.thinkingBuffer);
      trajectory.push(step);
      onProgress?.(step);
      this.thinkingBuffer = "";
    }
    if (this.textBuffer) {
      const step = this.createStep("response", this.textBuffer);
      trajectory.push(step);
      onProgress?.(step);
      this.textBuffer = "";
    }
  }
  /**
   * Build CLI args from ClaudeCodeConnectorConfig
   */
  buildConfigArgs(config) {
    const args = [];
    if (config.dangerouslySkipPermissions) {
      args.push("--dangerously-skip-permissions");
    }
    if (config.systemPrompt) {
      args.push("--system-prompt", config.systemPrompt);
    } else if (config.appendSystemPrompt) {
      args.push("--append-system-prompt", config.appendSystemPrompt);
    }
    if (config.allowedTools?.length) {
      args.push("--allowed-tools", ...config.allowedTools);
    }
    if (config.disallowedTools?.length) {
      args.push("--disallowed-tools", ...config.disallowedTools);
    }
    if (config.mcpConfigPath) {
      args.push("--mcp-config", config.mcpConfigPath);
    } else if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
      args.push("--mcp-config", JSON.stringify({ mcpServers: config.mcpServers }));
    }
    if (config.strictMcpConfig) {
      args.push("--strict-mcp-config");
    }
    if (config.additionalArgs) {
      args.push(...config.additionalArgs);
    }
    return args;
  }
  /**
   * Override execute to reset state and apply connectorConfig
   */
  async execute(endpoint, request, auth, onProgress, onRawEvent) {
    this.debug("========== execute() STARTED ==========");
    this.debug("Endpoint:", endpoint);
    this.debug("Test case:", request.testCase.name);
    this.debug("Config:", this["config"]);
    this.resetState();
    const originalEnv = this.config.env ? structuredClone(this.config.env) : {};
    const originalArgs = this.config.args ? [...this.config.args] : [];
    const originalInputMode = this.config.inputMode;
    const originalTimeout = this.config.timeout;
    const originalWorkingDir = this.config.workingDir;
    const ccConfig = request.connectorConfig;
    if (ccConfig) {
      this.debug("Applying connectorConfig:", Object.keys(ccConfig));
      if (ccConfig.env) {
        this.config.env = { ...this.config.env, ...ccConfig.env };
      }
      if (ccConfig.usePromptArg) {
        this.config.inputMode = "arg";
      }
      if (ccConfig.timeout !== void 0) {
        this.config.timeout = ccConfig.timeout;
      }
      if (ccConfig.workingDir) {
        this.config.workingDir = ccConfig.workingDir;
      }
    }
    if (this.config.env?.CLAUDE_CODE_USE_BEDROCK === "1") {
      this.config.env = { ...this.config.env, ANTHROPIC_API_KEY: "" };
      this.debug("Bedrock mode: cleared ANTHROPIC_API_KEY to bypass credit check");
    }
    if (request.modelId) {
      this.config.args = [...this.config.args || [], "--model", request.modelId];
      this.debug("Model flag added:", request.modelId);
    }
    if (ccConfig) {
      const configArgs = this.buildConfigArgs(ccConfig);
      if (configArgs.length > 0) {
        this.config.args = [...this.config.args || [], ...configArgs];
        this.debug("Config args added:", configArgs);
      }
    }
    try {
      this.debug("State reset, calling super.execute()...");
      const result = await super.execute(endpoint, request, auth, onProgress, onRawEvent);
      this.debug("super.execute() returned with", result.trajectory.length, "steps");
      this.debug("========== execute() COMPLETED ==========");
      return result;
    } finally {
      this.config.env = originalEnv;
      this.config.args = originalArgs;
      this.config.inputMode = originalInputMode;
      this.config.timeout = originalTimeout;
      this.config.workingDir = originalWorkingDir;
    }
  }
  /**
   * Health check - verify claude command exists
   */
  async healthCheck(endpoint, auth) {
    return super.healthCheck(endpoint || "claude", auth);
  }
};
var claudeCodeConnector = new ClaudeCodeConnector();

// services/connectors/mock/MockConnector.ts
var MockConnector = class extends BaseConnector {
  constructor() {
    super(...arguments);
    this.type = "mock";
    this.name = "Demo Agent (Mock)";
    this.supportsStreaming = true;
  }
  /**
   * Build payload - not used for mock but required by interface
   */
  buildPayload(request) {
    return {
      question: request.testCase.initialPrompt,
      context: request.testCase.context
    };
  }
  /**
   * Execute mock request - generates realistic trajectory with delays
   */
  async execute(endpoint, request, auth, onProgress, onRawEvent) {
    const trajectory = [];
    const rawEvents = [];
    const runId = `mock-run-${Date.now()}`;
    const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
    this.debug("Generating mock trajectory for:", request.testCase.name);
    const emitStep = (step) => {
      trajectory.push(step);
      onProgress?.(step);
      rawEvents.push({ type: "MOCK_STEP", step });
      onRawEvent?.({ type: "MOCK_STEP", step });
    };
    await sleep(100);
    emitStep(this.createStep(
      "assistant",
      "I need to investigate this issue. Let me start by checking the cluster health and then drill down into specific metrics."
    ));
    await sleep(300);
    emitStep(this.createStep(
      "action",
      "Calling opensearch_cluster_health...",
      {
        toolName: "opensearch_cluster_health",
        toolArgs: { local: true }
      }
    ));
    await sleep(500);
    emitStep(this.createStep(
      "tool_result",
      JSON.stringify({ status: "yellow", number_of_nodes: 3, unassigned_shards: 0 }, null, 2),
      {
        status: "SUCCESS",
        latencyMs: 500
      }
    ));
    await sleep(300);
    emitStep(this.createStep(
      "assistant",
      "The cluster is in yellow state. Let me check the node stats to identify which node might be causing issues."
    ));
    await sleep(300);
    emitStep(this.createStep(
      "action",
      "Calling opensearch_nodes_stats...",
      {
        toolName: "opensearch_nodes_stats",
        toolArgs: { metric: "jvm,os" }
      }
    ));
    await sleep(600);
    emitStep(this.createStep(
      "tool_result",
      "Node-1: CPU 12%, JVM Heap 45%\nNode-2: CPU 15%, JVM Heap 52%\nNode-3: CPU 98%, JVM Heap 89% (Data Node)",
      {
        status: "SUCCESS",
        latencyMs: 600
      }
    ));
    await sleep(400);
    emitStep(this.createStep(
      "response",
      `## Root Cause Analysis Complete

**Finding:** High CPU utilization detected on Node-3 (98% CPU, 89% JVM Heap)

**Root Cause:** Node-3 is experiencing resource exhaustion, likely due to:
1. Heavy indexing or search operations
2. Garbage collection pressure from high heap usage
3. Possible hot spot in shard distribution

**Recommendations:**
1. Check hot threads on Node-3 using \`_nodes/Node-3/hot_threads\`
2. Review shard distribution and consider rebalancing
3. Monitor GC logs for long pauses
4. Consider scaling horizontally if load persists`
    ));
    this.debug("Mock trajectory completed. Steps:", trajectory.length);
    return {
      trajectory,
      runId,
      rawEvents,
      metadata: {
        mock: true,
        testCaseId: request.testCase.id,
        testCaseName: request.testCase.name
      }
    };
  }
  /**
   * Parse raw events - for mock, just extract steps from our custom format
   */
  parseResponse(rawEvents) {
    return rawEvents.filter((e) => e.type === "MOCK_STEP" && e.step).map((e) => e.step);
  }
  /**
   * Health check - mock is always "healthy"
   */
  async healthCheck(endpoint, auth) {
    return true;
  }
};
var mockConnector = new MockConnector();

// services/connectors/registry.ts
var DEFAULT_CONNECTOR_TYPE = "agui-streaming";
var ConnectorRegistryImpl = class {
  constructor() {
    this.connectors = /* @__PURE__ */ new Map();
  }
  /**
   * Register a connector implementation
   * @throws Error if connector with same type is already registered
   */
  register(connector) {
    if (this.connectors.has(connector.type)) {
      console.warn(
        `[ConnectorRegistry] Overwriting existing connector for type: ${connector.type}`
      );
    }
    this.connectors.set(connector.type, connector);
  }
  /**
   * Get a connector by protocol type
   */
  get(type) {
    return this.connectors.get(type);
  }
  /**
   * Get all registered connectors
   */
  getAll() {
    return Array.from(this.connectors.values());
  }
  /**
   * Check if a connector is registered
   */
  has(type) {
    return this.connectors.has(type);
  }
  /**
   * Get connector for an agent config
   * Handles backwards compatibility with legacy configs
   *
   * Resolution order:
   * 1. If endpoint starts with 'mock://', use mock connector
   * 2. If connectorType is specified, use that
   * 3. Default to 'agui-streaming'
   */
  getForAgent(agent) {
    if (agent.endpoint.startsWith("mock://")) {
      const mockConnector2 = this.get("mock");
      if (mockConnector2) {
        return mockConnector2;
      }
      console.warn("[ConnectorRegistry] Mock connector not registered, falling back to default");
    }
    const connectorType = agent.connectorType ?? DEFAULT_CONNECTOR_TYPE;
    const connector = this.get(connectorType);
    if (!connector) {
      console.error(
        `[ConnectorRegistry] Connector not found for type: ${connectorType}, falling back to ${DEFAULT_CONNECTOR_TYPE}`
      );
      const defaultConnector = this.get(DEFAULT_CONNECTOR_TYPE);
      if (!defaultConnector) {
        throw new Error(
          `No connector registered for type '${connectorType}' and no default connector available`
        );
      }
      return defaultConnector;
    }
    return connector;
  }
  /**
   * Clear all registered connectors (useful for testing)
   */
  clear() {
    this.connectors.clear();
  }
  /**
   * Get list of registered connector types
   */
  getRegisteredTypes() {
    return Array.from(this.connectors.keys());
  }
};
var connectorRegistry = new ConnectorRegistryImpl();
function registerConnector(connector) {
  connectorRegistry.register(connector);
}

// lib/testCases/define.ts
var registries = /* @__PURE__ */ new Map();
var activeFile = null;
var DEFAULT_KEY = "__default__";
var describeStack = [];
var experimentalWarningEmitted = false;
function emitExperimentalWarningOnce() {
  if (experimentalWarningEmitted) return;
  experimentalWarningEmitted = true;
  if (process.env.AGENT_HEALTH_SUPPRESS_EXPERIMENTAL === "1") return;
  console.warn(
    "[agent-health] The code-based test SDK (test()/judge()/expect()) is experimental. The API may change in a minor release without a deprecation cycle. Pin your @opensearch-project/agent-health version, or set AGENT_HEALTH_SUPPRESS_EXPERIMENTAL=1 to silence this notice."
  );
}
function setActiveFile(filePath2) {
  activeFile = filePath2;
  if (!registries.has(filePath2)) {
    registries.set(filePath2, []);
  }
}
function test(name, optionsOrBody, maybeBody) {
  emitExperimentalWarningOnce();
  let options;
  let evaluate;
  if (typeof optionsOrBody === "function") {
    options = {};
    evaluate = optionsOrBody;
  } else {
    options = optionsOrBody ?? {};
    evaluate = maybeBody;
  }
  if (!name || typeof name !== "string") {
    throw new Error("test() requires a name (the first argument)");
  }
  if (typeof evaluate !== "function") {
    throw new Error(`test("${name}") requires a body function`);
  }
  const key = activeFile ?? DEFAULT_KEY;
  if (!registries.has(key)) {
    registries.set(key, []);
  }
  const registry = registries.get(key);
  const benchmarkPath = describeStack.length > 0 ? describeStack.join(" > ") : void 0;
  if (registry.some((t) => t.name === name && t.benchmarkPath === benchmarkPath)) {
    const fileLabel = activeFile ? ` in ${activeFile}` : "";
    const groupLabel = benchmarkPath ? ` (in describe "${benchmarkPath}")` : "";
    throw new Error(
      `Duplicate test name "${name}"${groupLabel}${fileLabel}. Test names must be unique within their describe block. Move one of the tests to a different describe() or rename it.`
    );
  }
  registry.push({
    name,
    options,
    evaluate,
    sourceFile: activeFile ?? void 0,
    benchmarkPath
  });
}
function describe(name, fn) {
  emitExperimentalWarningOnce();
  if (!name || typeof name !== "string") {
    throw new Error("describe() requires a name (the first argument)");
  }
  if (typeof fn !== "function") {
    throw new Error(`describe("${name}") requires a body function`);
  }
  describeStack.push(name);
  try {
    const result = fn();
    if (result && typeof result.then === "function") {
      throw new Error(
        `describe("${name}") body returned a Promise. describe blocks must be synchronous \u2014 use test() inside, not await.`
      );
    }
  } finally {
    describeStack.pop();
  }
}
function getRegisteredTests(filePath2) {
  if (filePath2) return [...registries.get(filePath2) ?? []];
  return [...registries.values()].flatMap((r) => [...r]);
}
function clearRegistry(filePath2) {
  if (filePath2) {
    registries.delete(filePath2);
  } else {
    registries.clear();
  }
  activeFile = null;
}

// lib/testCases/loader.ts
import { createHash } from "crypto";
import { readFileSync } from "fs";
import { resolve, dirname } from "path";
import { pathToFileURL } from "url";
import { createRequire, Module as NodeModule } from "module";

// lib/matchers/session.ts
var activeSession = null;
function recordVerdict(result) {
  if (!activeSession) return;
  activeSession.results.push(result);
}

// lib/testCases/judge.ts
var judgeCalledInCurrentEval = false;
function wasJudgeCalled() {
  return judgeCalledInCurrentEval;
}
function resetJudgeFlag() {
  judgeCalledInCurrentEval = false;
}
function isTrajectory(x) {
  return Array.isArray(x);
}
function isResultLike(x) {
  return typeof x === "object" && x !== null && "trajectory" in x;
}
async function judge(resultOrTrajectory, claimOrClaims, options) {
  judgeCalledInCurrentEval = true;
  const trajectory = isTrajectory(resultOrTrajectory) ? resultOrTrajectory : isResultLike(resultOrTrajectory) ? resultOrTrajectory.trajectory ?? [] : [];
  const claims = Array.isArray(claimOrClaims) ? claimOrClaims : [claimOrClaims];
  const serverUrl = options?.serverUrl ?? `http://localhost:${process.env.AGENT_HEALTH_PORT ?? "4001"}`;
  const description = claims.length === 1 ? `judge: ${claims[0]}` : `judge: ${claims.length} claims`;
  const startedAt = Date.now();
  let response;
  try {
    response = await fetch(`${serverUrl}/api/judge`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        trajectory,
        expectedOutcomes: claims,
        expectedTrajectory: [],
        model: options?.model
      })
    });
  } catch (err) {
    const errMsg = err?.message || String(err);
    recordVerdict({
      description,
      pass: false,
      method: "llm-judge",
      durationMs: Date.now() - startedAt,
      errorMessage: `Judge request failed: ${errMsg}`,
      reasoning: ""
    });
    throw new Error(`Judge request failed: ${errMsg}`);
  }
  if (!response.ok) {
    const text = await response.text();
    recordVerdict({
      description,
      pass: false,
      method: "llm-judge",
      durationMs: Date.now() - startedAt,
      errorMessage: `Judge HTTP ${response.status}: ${text}`,
      reasoning: ""
    });
    throw new Error(`Judge request failed (${response.status}): ${text}`);
  }
  const result = await response.json();
  const verdict = {
    passFailStatus: result.passFailStatus ?? "failed",
    accuracy: result.metrics?.accuracy ?? 0,
    reasoning: result.llmJudgeReasoning ?? ""
  };
  recordVerdict({
    description,
    pass: verdict.passFailStatus === "passed",
    method: "llm-judge",
    durationMs: Date.now() - startedAt,
    score: typeof verdict.accuracy === "number" ? verdict.accuracy / 100 : void 0,
    reasoning: verdict.reasoning,
    model: options?.model,
    errorMessage: verdict.passFailStatus === "failed" ? verdict.reasoning : void 0
  });
  if (verdict.passFailStatus === "failed") {
    throw new Error(`LLM Judge: FAILED (accuracy: ${verdict.accuracy})
${verdict.reasoning}`);
  }
  return verdict;
}

// lib/matchers/expect.ts
import * as chai from "chai";
var pluginsInstalled = false;
function ensurePluginsInstalled() {
  if (pluginsInstalled) return;
  pluginsInstalled = true;
  const Assertion2 = chai.Assertion;
  const utils = chai.util;
  const originalAssert = Assertion2.prototype.assert;
  Assertion2.prototype.assert = function(expr, msg, negateMsg, expected, actual, showDiff) {
    const negate = utils.flag(this, "negate");
    const ok = negate ? !expr : !!expr;
    const description = describeAssertion(this, expr, msg, negateMsg, expected, actual, utils);
    try {
      const result = originalAssert.call(this, expr, msg, negateMsg, expected, actual, showDiff);
      if (description) {
        recordVerdict({
          description,
          pass: true,
          method: "code-assertion",
          actual: safeClone(actual ?? utils.flag(this, "object")),
          expected: safeClone(expected)
        });
      }
      return result;
    } catch (err) {
      if (description) {
        recordVerdict({
          description,
          pass: false,
          method: "code-assertion",
          actual: safeClone(actual ?? utils.flag(this, "object")),
          expected: safeClone(expected),
          errorMessage: err?.message || String(err)
        });
      }
      throw err;
    }
  };
  Assertion2.addMethod("haveCalledTool", function(toolName, argsPartial) {
    const trajectory = utils.flag(this, "object");
    if (!Array.isArray(trajectory)) {
      this.assert(false, "expected an array of TrajectoryStep", "", toolName, trajectory);
      return;
    }
    const matches = trajectory.filter((step) => step?.type === "action" && step?.toolName === toolName);
    let hit = matches[0];
    if (argsPartial && matches.length > 0) {
      hit = matches.find((s) => isSupersetOf(s.toolArgs ?? s.input, argsPartial));
    }
    const argsLabel = argsPartial ? ` with args ${JSON.stringify(argsPartial)}` : "";
    this.assert(
      !!hit,
      `expected trajectory to have called tool '${toolName}'${argsLabel}`,
      `expected trajectory to NOT have called tool '${toolName}'${argsLabel}`,
      toolName,
      matches.map((m2) => ({ toolName: m2.toolName, toolArgs: m2.toolArgs ?? m2.input }))
    );
  });
  Assertion2.addMethod("haveStepsOfType", function(type) {
    const trajectory = utils.flag(this, "object");
    const arr = Array.isArray(trajectory) ? trajectory : [];
    const found = arr.filter((s) => s?.type === type);
    this.assert(
      found.length > 0,
      `expected trajectory to have at least one step of type '${type}'`,
      `expected trajectory to have NO steps of type '${type}' but found ${found.length}`,
      type,
      arr.map((s) => s?.type)
    );
  });
  Assertion2.addMethod("haveOutputMatching", function(pattern) {
    const text = utils.flag(this, "object");
    const str = typeof text === "string" ? text : "";
    const re = pattern instanceof RegExp ? pattern : new RegExp(escapeRegex(String(pattern)));
    this.assert(
      re.test(str),
      `expected output to match ${re}`,
      `expected output to NOT match ${re}`,
      pattern,
      str
    );
  });
  Assertion2.addMethod("haveCompletedWithin", function(thresholdMs) {
    const obj = utils.flag(this, "object");
    const duration = obj?.durationMs ?? 0;
    this.assert(
      duration <= thresholdMs,
      `expected to have completed within ${thresholdMs}ms (took ${duration}ms)`,
      `expected to have NOT completed within ${thresholdMs}ms`,
      thresholdMs,
      duration
    );
  });
}
ensurePluginsInstalled();
var expect2 = chai.expect;
function describeAssertion(ctx, _expr, msg, negateMsg, expected, actual, utils) {
  const rawMsg = typeof msg === "function" ? msg() : msg;
  const rawNeg = typeof negateMsg === "function" ? negateMsg() : negateMsg;
  const template = rawMsg || rawNeg || "";
  if (!template) return "";
  const obj = utils.flag(ctx, "object");
  const resolved = template.replace(/#\{this\}/g, () => safeInspect(obj, utils)).replace(/#\{act\}/g, () => safeInspect(actual, utils)).replace(/#\{exp\}/g, () => safeInspect(expected, utils));
  return shortDescription(resolved);
}
function safeInspect(v, utils) {
  try {
    const str = utils.objDisplay && typeof utils.objDisplay === "function" ? utils.objDisplay(v) : utils.inspect ? utils.inspect(v) : String(v);
    if (typeof str !== "string") return String(v);
    return str.length > 60 ? `${str.slice(0, 57)}\u2026` : str;
  } catch {
    return String(v);
  }
}
function shortDescription(msg) {
  const trimmed = msg.replace(/^expected\s+/i, "");
  return trimmed.length > 120 ? `${trimmed.slice(0, 117)}\u2026` : trimmed;
}
function safeClone(v) {
  if (v === void 0 || v === null) return v;
  if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") return v;
  try {
    const s = JSON.stringify(v);
    if (s && s.length < 2e3) return JSON.parse(s);
    return s ? `${s.slice(0, 1997)}...` : "[unserializable]";
  } catch {
    return "[circular]";
  }
}
function isSupersetOf(actual, expected) {
  if (typeof actual !== "object" || actual === null) return false;
  for (const [k, v] of Object.entries(expected)) {
    if (!(k in actual)) return false;
    if (typeof v === "object" && v !== null) {
      if (!isSupersetOf(actual[k], v)) return false;
    } else if (actual[k] !== v) {
      return false;
    }
  }
  return true;
}
function escapeRegex(s) {
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

// lib/testCases/loader.ts
var CODE_EXTENSIONS = [".ts", ".js", ".mjs"];
function isCodeFile(filename) {
  const lower = filename.toLowerCase();
  return CODE_EXTENSIONS.some((ext) => lower.endsWith(ext));
}
function computeTestCaseHash(tc) {
  const content = JSON.stringify({
    name: tc.name,
    prompt: tc.options.prompt,
    context: tc.options.context,
    labels: tc.options.labels,
    description: tc.options.description
  });
  return createHash("sha256").update(content).digest("hex");
}
async function loadTestCasesFromModule(filePath) {
  const absPath = resolve(filePath);
  clearRegistry(absPath);
  setActiveFile(absPath);
  let module;
  if (absPath.endsWith(".js")) {
    const code = readFileSync(absPath, "utf-8");
    const fileDir = dirname(absPath);
    const Module = NodeModule;
    const m = new Module(absPath);
    m.filename = absPath;
    m.paths = Module._nodeModulePaths(fileDir);
    const fileRequire = createRequire(absPath);
    const isDefineId = (id) => {
      const normalized = id.replace(/\\/g, "/").replace(/\.js$/, "");
      return normalized === "lib/testCases/define" || normalized.endsWith("/lib/testCases/define");
    };
    const isPackageName = (id) => id === "@opensearch-project/agent-health" || id === "@opensearch/agent-health" || id === "agent-health";
    const sdkExports = {
      test,
      describe,
      judge,
      wasJudgeCalled,
      resetJudgeFlag,
      // Pre-resolved matcher API — must be a direct import (not a runtime
      // require) so it works in bundled ESM contexts (CLI, server) where
      // the synthetic CJS `require` isn't available at module-top scope.
      expect: expect2
    };
    const wrappedRequire = (id) => {
      if (isDefineId(id) || isPackageName(id)) {
        return sdkExports;
      }
      try {
        const resolved = fileRequire.resolve(id);
        const normalized = resolved.replace(/\\/g, "/");
        if (normalized.endsWith("/lib/testCases/define.js") || normalized.endsWith("/lib/testCases/define")) {
          return sdkExports;
        }
      } catch {
      }
      return fileRequire(id);
    };
    wrappedRequire.resolve = fileRequire.resolve;
    const wrapper = `(function(exports, require, module, __filename, __dirname) { ${code}
});`;
    const compiledFn = eval(wrapper);
    compiledFn(m.exports, wrappedRequire, m, absPath, fileDir);
    module = m.exports;
  } else {
    try {
      const fileUrl = pathToFileURL(absPath).href;
      module = await import(fileUrl);
    } catch (err) {
      if (err.code === "ERR_UNKNOWN_FILE_EXTENSION" && absPath.endsWith(".ts")) {
        throw new Error(
          `Cannot import TypeScript file: ${filePath}
Install tsx as a dependency: npm install tsx
Or pre-compile .eval.ts to .eval.js before running.`
        );
      }
      throw new Error(`Failed to import module: ${filePath}
${err.message}`);
    }
  }
  const testCases = getRegisteredTests(absPath);
  if (testCases.length === 0) {
    throw new Error(
      `Module ${filePath} has no test cases. Register tests with test(name, options?, body) inside the file.`
    );
  }
  const loaded = testCases.map((tc) => ({
    ...tc,
    hash: computeTestCaseHash(tc)
  }));
  const benchmarks = /* @__PURE__ */ new Map();
  for (const tc of loaded) {
    if (tc.benchmarkPath) {
      const list = benchmarks.get(tc.benchmarkPath) ?? [];
      list.push(tc.name);
      benchmarks.set(tc.benchmarkPath, list);
    }
  }
  return { testCases: loaded, filePath: absPath, benchmarks };
}
export {
  AGUIStreamingConnector,
  BaseConnector,
  ClaudeCodeConnector,
  MockConnector,
  RESTConnector,
  SubprocessConnector,
  connectorRegistry,
  defineConfig,
  describe,
  expect2 as expect,
  fetchTracesByRunIds as fetchTraces,
  judge,
  registerConnector,
  test
};
