{"version":3,"sources":["../src/client-sdk/services/experiments/experiments-api.service.ts"],"sourcesContent":["import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n  createLangWatchApiClient,\n  type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport {\n  extractStatusFromResponse,\n  formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport interface ExperimentRunStartResponse {\n  runId: string;\n  status: \"running\";\n  total: number;\n  runUrl?: string;\n}\n\nexport type ExperimentRunStatusResponse =\n  paths[\"/api/experiments/runs/{runId}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\n/**\n * Summary entry returned by `GET /api/experiments`. Mirrors\n * `experimentSummarySchema` from the control-plane Hono route. Hand-written\n * because the route is not yet exposed via the generated OpenAPI types.\n */\nexport interface ExperimentSummary {\n  id: string;\n  slug: string;\n  name: string | null;\n  type: string;\n  workflowId: string | null;\n  createdAt: string;\n  updatedAt: string;\n  runsCount: number;\n  lastRunAt: string | null;\n}\n\nexport interface ExperimentListPagination {\n  page: number;\n  pageSize: number;\n  totalHits: number;\n  hasMore: boolean;\n}\n\nexport interface ExperimentListResponse {\n  experiments: ExperimentSummary[];\n  pagination: ExperimentListPagination;\n}\n\n/**\n * Per-run entry returned by `GET /api/experiments/runs?experimentSlug=...`.\n * Mirrors `ExperimentRun` from the control plane.\n */\nexport interface ExperimentRunSummaryEntry {\n  experimentId: string;\n  runId: string;\n  workflowVersion: {\n    id: string;\n    version: string;\n    commitMessage: string;\n    author: { name: string | null; image: string | null } | null;\n  } | null;\n  timestamps: {\n    createdAt: number;\n    updatedAt: number;\n    finishedAt?: number | null;\n    stoppedAt?: number | null;\n  };\n  progress?: number | null;\n  total?: number | null;\n  summary: {\n    datasetCost?: number;\n    evaluationsCost?: number;\n    datasetAverageCost?: number;\n    datasetAverageDuration?: number;\n    evaluationsAverageCost?: number;\n    evaluationsAverageDuration?: number;\n    evaluations: Record<\n      string,\n      { name: string; averageScore: number | null; averagePassed?: number }\n    >;\n  };\n}\n\nexport interface ExperimentRunsListResponse {\n  experimentId: string;\n  experimentSlug: string;\n  runs: ExperimentRunSummaryEntry[];\n  pagination: ExperimentListPagination;\n}\n\n/**\n * Per-row results for a completed experiment run.\n *\n * Mirrors `ExperimentRunWithItems` from the control plane\n * (`langwatch/src/server/experiments-v3/services/types.ts`). Hand-written\n * because the `/runs/{runId}/results` route is not yet exposed via the\n * generated OpenAPI types.\n */\nexport interface ExperimentRunDatasetEntry {\n  index: number;\n  targetId?: string | null;\n  entry: Record<string, unknown>;\n  predicted?: Record<string, unknown>;\n  cost?: number | null;\n  duration?: number | null;\n  error?: string | null;\n  traceId?: string | null;\n}\n\nexport interface ExperimentRunEvaluation {\n  evaluator: string;\n  name?: string | null;\n  targetId?: string | null;\n  status: \"processed\" | \"skipped\" | \"error\";\n  index: number;\n  score?: number | null;\n  label?: string | null;\n  passed?: boolean | null;\n  details?: string | null;\n  cost?: number | null;\n  duration?: number | null;\n  inputs?: Record<string, unknown> | null;\n}\n\nexport interface ExperimentRunResultsResponse {\n  experimentId: string;\n  runId: string;\n  projectId: string;\n  workflowVersionId?: string | null;\n  progress?: number | null;\n  total?: number | null;\n  dataset: ExperimentRunDatasetEntry[];\n  evaluations: ExperimentRunEvaluation[];\n  timestamps: {\n    createdAt: number;\n    updatedAt: number;\n    finishedAt?: number | null;\n    stoppedAt?: number | null;\n  };\n}\n\nexport class ExperimentsApiServiceError extends Error {\n  constructor(\n    message: string,\n    public readonly operation: string,\n    public readonly originalError?: unknown,\n  ) {\n    super(message);\n    this.name = \"ExperimentsApiServiceError\";\n  }\n}\n\nexport class ExperimentsApiService {\n  private readonly apiClient: LangwatchApiClient;\n\n  constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n    this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n  }\n\n  private handleApiError(operation: string, error: unknown): never {\n    const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n      status: extractStatusFromResponse(error),\n    } });\n    throw new ExperimentsApiServiceError(message, operation, error);\n  }\n\n  private async getUndeclaredEndpoint<T>({\n    path,\n    operation,\n  }: {\n    path: string;\n    operation: string;\n  }): Promise<T> {\n    type UntypedClient = {\n      GET: (\n        path: string,\n        init?: { parseAs?: \"json\" },\n      ) => Promise<{ data?: unknown; error?: unknown; response: Response }>;\n    };\n\n    let result: { data?: unknown; error?: unknown; response: Response };\n    try {\n      result = await (this.apiClient as unknown as UntypedClient).GET(path, {\n        parseAs: \"json\",\n      });\n    } catch (error) {\n      this.handleApiError(operation, error);\n    }\n\n    if (result.error) this.handleApiError(operation, result.error);\n    return result.data as T;\n  }\n\n  async startRun(slug: string): Promise<ExperimentRunStartResponse> {\n    const { data, error } = await this.apiClient.POST(\n      \"/api/experiments/{slug}/run\",\n      {\n        params: { path: { slug } },\n      },\n    );\n    if (error) this.handleApiError(`start experiment run for \"${slug}\"`, error);\n    return data as unknown as ExperimentRunStartResponse;\n  }\n\n  async getRunStatus(runId: string): Promise<ExperimentRunStatusResponse> {\n    const { data, error } = await this.apiClient.GET(\n      \"/api/experiments/runs/{runId}\",\n      {\n        params: { path: { runId } },\n      },\n    );\n    if (error) this.handleApiError(`get run status for \"${runId}\"`, error);\n    return data;\n  }\n\n  /**\n   * List experiments for the current project.\n   *\n   * Hits `GET /api/experiments` through the configured API client transport.\n   * The route is not yet declared in generated OpenAPI types, so the path is\n   * dispatched through a narrow untyped helper.\n   */\n  async listExperiments({\n    pageSize,\n    page,\n  }: {\n    pageSize?: number;\n    page?: number;\n  } = {}): Promise<ExperimentListResponse> {\n    const search = new URLSearchParams();\n    if (pageSize !== undefined) search.set(\"pageSize\", String(pageSize));\n    if (page !== undefined) search.set(\"page\", String(page));\n    const qs = search.toString();\n    return this.getUndeclaredEndpoint<ExperimentListResponse>({\n      path: `/api/experiments${qs ? `?${qs}` : \"\"}`,\n      operation: \"list experiments\",\n    });\n  }\n\n  /**\n   * List experiment runs for an experiment slug.\n   *\n   * Hits `GET /api/experiments/runs?experimentSlug=...` through the\n   * configured API client transport because the route is not yet declared in\n   * the generated OpenAPI.\n   */\n  async listRuns({\n    experimentSlug,\n    pageSize,\n    page,\n  }: {\n    experimentSlug: string;\n    pageSize?: number;\n    page?: number;\n  }): Promise<ExperimentRunsListResponse> {\n    const search = new URLSearchParams();\n    search.set(\"experimentSlug\", experimentSlug);\n    if (pageSize !== undefined) search.set(\"pageSize\", String(pageSize));\n    if (page !== undefined) search.set(\"page\", String(page));\n    return this.getUndeclaredEndpoint<ExperimentRunsListResponse>({\n      path: `/api/experiments/runs?${search.toString()}`,\n      operation: `list runs for experiment \"${experimentSlug}\"`,\n    });\n  }\n\n  /**\n   * Fetch per-row results for a completed experiment run.\n   *\n   * Hits `GET /api/experiments/runs/{runId}/results` through the\n   * configured API client transport because the route is not yet declared in\n   * the generated OpenAPI `paths`.\n   */\n  async getRunResults({\n    runId,\n    experimentSlug,\n  }: {\n    runId: string;\n    experimentSlug?: string;\n  }): Promise<ExperimentRunResultsResponse> {\n    const search = new URLSearchParams();\n    if (experimentSlug) search.set(\"experimentSlug\", experimentSlug);\n    const qs = search.toString() ? `?${search.toString()}` : \"\";\n    const body = await this.getUndeclaredEndpoint<\n      ExperimentRunResultsResponse | null\n    >({\n      path: `/api/experiments/runs/${encodeURIComponent(runId)}/results${qs}`,\n      operation: `get run results for \"${runId}\"`,\n    });\n    if (body === null) {\n      this.handleApiError(`get run results for \"${runId}\"`, {\n        response: { status: 404 },\n        data: { error: `Run not found: ${runId}` },\n      });\n    }\n    return body;\n  }\n}\n"],"mappings":";;;;;;;;;AA+IO,IAAM,6BAAN,cAAyC,MAAM;AAAA,EACpD,YACE,SACgB,WACA,eAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,wBAAN,MAA4B;AAAA,EAGjC,YAAY,QAAqD;AA7JnE;AA8JI,SAAK,aAAY,sCAAQ,uBAAR,YAA8B,yBAAyB;AAAA,EAC1E;AAAA,EAEQ,eAAe,WAAmB,OAAuB;AAC/D,UAAM,UAAU,2BAA2B,EAAE,WAAsB,OAAc,SAAS;AAAA,MACxF,QAAQ,0BAA0B,KAAK;AAAA,IACzC,EAAE,CAAC;AACH,UAAM,IAAI,2BAA2B,SAAS,WAAW,KAAK;AAAA,EAChE;AAAA,EAEA,MAAc,sBAAyB;AAAA,IACrC;AAAA,IACA;AAAA,EACF,GAGe;AAQb,QAAI;AACJ,QAAI;AACF,eAAS,MAAO,KAAK,UAAuC,IAAI,MAAM;AAAA,QACpE,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,OAAO;AACd,WAAK,eAAe,WAAW,KAAK;AAAA,IACtC;AAEA,QAAI,OAAO,MAAO,MAAK,eAAe,WAAW,OAAO,KAAK;AAC7D,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,SAAS,MAAmD;AAChE,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,UAAU;AAAA,MAC3C;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE;AAAA,MAC3B;AAAA,IACF;AACA,QAAI,MAAO,MAAK,eAAe,6BAA6B,IAAI,KAAK,KAAK;AAC1E,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aAAa,OAAqD;AACtE,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,UAAU;AAAA,MAC3C;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE;AAAA,MAC5B;AAAA,IACF;AACA,QAAI,MAAO,MAAK,eAAe,uBAAuB,KAAK,KAAK,KAAK;AACrE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,EACF,IAGI,CAAC,GAAoC;AACvC,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,aAAa,OAAW,QAAO,IAAI,YAAY,OAAO,QAAQ,CAAC;AACnE,QAAI,SAAS,OAAW,QAAO,IAAI,QAAQ,OAAO,IAAI,CAAC;AACvD,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,KAAK,sBAA8C;AAAA,MACxD,MAAM,mBAAmB,KAAK,IAAI,EAAE,KAAK,EAAE;AAAA,MAC3C,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,SAAS;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIwC;AACtC,UAAM,SAAS,IAAI,gBAAgB;AACnC,WAAO,IAAI,kBAAkB,cAAc;AAC3C,QAAI,aAAa,OAAW,QAAO,IAAI,YAAY,OAAO,QAAQ,CAAC;AACnE,QAAI,SAAS,OAAW,QAAO,IAAI,QAAQ,OAAO,IAAI,CAAC;AACvD,WAAO,KAAK,sBAAkD;AAAA,MAC5D,MAAM,yBAAyB,OAAO,SAAS,CAAC;AAAA,MAChD,WAAW,6BAA6B,cAAc;AAAA,IACxD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,cAAc;AAAA,IAClB;AAAA,IACA;AAAA,EACF,GAG0C;AACxC,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,eAAgB,QAAO,IAAI,kBAAkB,cAAc;AAC/D,UAAM,KAAK,OAAO,SAAS,IAAI,IAAI,OAAO,SAAS,CAAC,KAAK;AACzD,UAAM,OAAO,MAAM,KAAK,sBAEtB;AAAA,MACA,MAAM,yBAAyB,mBAAmB,KAAK,CAAC,WAAW,EAAE;AAAA,MACrE,WAAW,wBAAwB,KAAK;AAAA,IAC1C,CAAC;AACD,QAAI,SAAS,MAAM;AACjB,WAAK,eAAe,wBAAwB,KAAK,KAAK;AAAA,QACpD,UAAU,EAAE,QAAQ,IAAI;AAAA,QACxB,MAAM,EAAE,OAAO,kBAAkB,KAAK,GAAG;AAAA,MAC3C,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;","names":[]}