{"version":3,"sources":["../../src/services/FeedbackService.ts"],"sourcesContent":["import {\n  LLMRequestLogFeedback,\n  LLMRequestLogFeedbackPayload,\n  LLMRequestLogFeedbackResponse,\n  SearchFeedbackParams,\n  SearchFeedbackResponse,\n  LLMRequestLogFeedbackDetail\n} from '../types';\nimport { CollectionMethod } from '../utils/collector.js';\nimport { BaseService, BaseServiceConfig } from './BaseService.js';\n\nexport interface FeedbackServiceConfig extends BaseServiceConfig {}\n\nexport class FeedbackService extends BaseService {\n  constructor(config: FeedbackServiceConfig) {\n    super(config, '/api/v2/llm_request_log_feedbacks');\n  }\n\n  private normalizeSentiment(feedback: LLMRequestLogFeedback): LLMRequestLogFeedback {\n    if (feedback.sentiment !== undefined || feedback.like === undefined) { return feedback; }\n    const { like, ...rest } = feedback;\n    return { ...rest, sentiment: like ? 'like' : 'dislike' };\n  }\n\n  public async createFeedback(feedback: LLMRequestLogFeedback, collectionMethod?: CollectionMethod): Promise<LLMRequestLogFeedbackResponse | null> {\n    const normalized = this.normalizeSentiment(feedback);\n    const feedbackWithCollector = this.addCollectorToData(normalized, collectionMethod);\n\n    const payload: LLMRequestLogFeedbackPayload = {\n      llm_request_log_feedback: feedbackWithCollector\n    };\n\n    this.logFeedbackInfo(normalized);\n\n    const result = await this.sendRequest<LLMRequestLogFeedbackResponse>(\n      payload,\n      `✅ Successfully created feedback with ID: ${feedback.llm_request_log_id || 'N/A'}`\n    );\n\n    this.logSeparator();\n    return result;\n  }\n\n  /**\n   * Search feedback records. Requires the client's **private** API key — the public key used\n   * by `createFeedback` will 401 here.\n   *\n   * @param params Raw Ransack predicates (e.g. `sentiment_eq`, `explanation_cont`) plus `s`\n   *   (sort) and `page`/`per` (pagination). Wrapped as `q[<key>]` query params on the wire.\n   * @returns The `:summary` view of matching feedback records plus pagination metadata.\n   * @throws Error on network failure or a non-JSON body. A non-2xx response throws an error\n   *   whose `status` property holds the HTTP status code.\n   */\n  public async searchFeedback(params: SearchFeedbackParams = {}): Promise<SearchFeedbackResponse> {\n    const { page, per, ...predicates } = params;\n    const url = new URL(this.apiEndpoint);\n    for (const [key, value] of Object.entries(predicates)) {\n      if (value !== undefined) {\n        url.searchParams.set(`q[${key}]`, String(value));\n      }\n    }\n    if (page !== undefined) {\n      url.searchParams.set('page', String(page));\n    }\n    if (per !== undefined) {\n      url.searchParams.set('per', String(per));\n    }\n    return this.getJson<SearchFeedbackResponse>(url.toString(), 'Feedback');\n  }\n\n  /**\n   * Get a single feedback record by ID. Requires the client's **private** API key, same as\n   * {@link searchFeedback}.\n   *\n   * @param id The feedback record ID.\n   * @returns The `:with_partials` view: the full record, including `original_output`/\n   *   `revised_output`/`feedback_partials`.\n   * @throws Error if `id` is blank/whitespace-only or a bare dot-segment (`.`/`..`) — either would\n   *   otherwise silently resolve away to the `index` route or beyond, returning\n   *   `{ feedback: [...], pagination: {...} }` typed as a single record. Error on network failure\n   *   or a non-JSON body. A non-2xx response throws an error whose `status` property holds the\n   *   HTTP status code (e.g. 404 for an unknown ID).\n   */\n  public async getFeedback(id: string): Promise<LLMRequestLogFeedbackDetail> {\n    const url = this.buildResourceUrl(id, 'getFeedback: id must be a non-empty string');\n    return this.getJson<LLMRequestLogFeedbackDetail>(url.toString(), 'Feedback');\n  }\n\n  private logFeedbackInfo(feedback: LLMRequestLogFeedback): void {\n    if (!this.silent) {\n      console.log(`\\n📝 CREATING FEEDBACK for LLM Request Log ID: ${feedback.llm_request_log_id}`);\n      console.log(`🎭 Sentiment: ${feedback.sentiment ?? 'N/A'}`);\n      if (feedback.explanation) {\n        console.log(`💭 Explanation: ${feedback.explanation.substring(0, 100)}${feedback.explanation.length > 100 ? '...' : ''}`);\n      }\n      if (this.dryRun) {\n        console.log(`🚫 DRY RUN: API call will be skipped`);\n      } else {\n        console.log(`📤 Sending to: ${this.apiEndpoint}`);\n      }\n    }\n  }\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,yBAA+C;AAIxC,MAAM,wBAAwB,+BAAY;AAAA,EAC/C,YAAY,QAA+B;AACzC,UAAM,QAAQ,mCAAmC;AAAA,EACnD;AAAA,EAEQ,mBAAmB,UAAwD;AACjF,QAAI,SAAS,cAAc,UAAa,SAAS,SAAS,QAAW;AAAE,aAAO;AAAA,IAAU;AACxF,UAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAC1B,WAAO,EAAE,GAAG,MAAM,WAAW,OAAO,SAAS,UAAU;AAAA,EACzD;AAAA,EAEA,MAAa,eAAe,UAAiC,kBAAoF;AAC/I,UAAM,aAAa,KAAK,mBAAmB,QAAQ;AACnD,UAAM,wBAAwB,KAAK,mBAAmB,YAAY,gBAAgB;AAElF,UAAM,UAAwC;AAAA,MAC5C,0BAA0B;AAAA,IAC5B;AAEA,SAAK,gBAAgB,UAAU;AAE/B,UAAM,SAAS,MAAM,KAAK;AAAA,MACxB;AAAA,MACA,iDAA4C,SAAS,sBAAsB,KAAK;AAAA,IAClF;AAEA,SAAK,aAAa;AAClB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAa,eAAe,SAA+B,CAAC,GAAoC;AAC9F,UAAM,EAAE,MAAM,KAAK,GAAG,WAAW,IAAI;AACrC,UAAM,MAAM,IAAI,IAAI,KAAK,WAAW;AACpC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,UAAI,UAAU,QAAW;AACvB,YAAI,aAAa,IAAI,KAAK,GAAG,KAAK,OAAO,KAAK,CAAC;AAAA,MACjD;AAAA,IACF;AACA,QAAI,SAAS,QAAW;AACtB,UAAI,aAAa,IAAI,QAAQ,OAAO,IAAI,CAAC;AAAA,IAC3C;AACA,QAAI,QAAQ,QAAW;AACrB,UAAI,aAAa,IAAI,OAAO,OAAO,GAAG,CAAC;AAAA,IACzC;AACA,WAAO,KAAK,QAAgC,IAAI,SAAS,GAAG,UAAU;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAa,YAAY,IAAkD;AACzE,UAAM,MAAM,KAAK,iBAAiB,IAAI,4CAA4C;AAClF,WAAO,KAAK,QAAqC,IAAI,SAAS,GAAG,UAAU;AAAA,EAC7E;AAAA,EAEQ,gBAAgB,UAAuC;AAC7D,QAAI,CAAC,KAAK,QAAQ;AAChB,cAAQ,IAAI;AAAA,sDAAkD,SAAS,kBAAkB,EAAE;AAC3F,cAAQ,IAAI,wBAAiB,SAAS,aAAa,KAAK,EAAE;AAC1D,UAAI,SAAS,aAAa;AACxB,gBAAQ,IAAI,0BAAmB,SAAS,YAAY,UAAU,GAAG,GAAG,CAAC,GAAG,SAAS,YAAY,SAAS,MAAM,QAAQ,EAAE,EAAE;AAAA,MAC1H;AACA,UAAI,KAAK,QAAQ;AACf,gBAAQ,IAAI,6CAAsC;AAAA,MACpD,OAAO;AACL,gBAAQ,IAAI,yBAAkB,KAAK,WAAW,EAAE;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AACF;","names":[]}