{"version":3,"file":"ai-model/service-caller/json.mjs","sources":["../../../../src/ai-model/service-caller/json.ts"],"sourcesContent":["import { jsonrepair } from 'jsonrepair';\n\nexport function extractJSONFromCodeBlock(response: string) {\n  try {\n    // First, try to match a JSON object directly in the response\n    const jsonMatch = response.match(/^\\s*(\\{[\\s\\S]*\\})\\s*$/);\n    if (jsonMatch) {\n      return jsonMatch[1];\n    }\n\n    // If no direct JSON object is found, try to extract JSON from a code block\n    const codeBlockMatch = response.match(\n      /```(?:json)?\\s*(\\{[\\s\\S]*?\\})\\s*```/,\n    );\n    if (codeBlockMatch) {\n      return codeBlockMatch[1];\n    }\n\n    // If no code block is found, try to find a JSON-like structure in the text\n    const jsonLikeMatch = response.match(/\\{[\\s\\S]*\\}/);\n    if (jsonLikeMatch) {\n      return jsonLikeMatch[0];\n    }\n  } catch {}\n  // If no JSON-like structure is found, return the original response\n  return response;\n}\n\nexport type JsonParserSource =\n  | 'generic-object'\n  | 'planning-action-param'\n  | 'locate'\n  | 'section-locator';\n\nexport interface JsonParserContext {\n  source: JsonParserSource;\n  preserveStringValueKeys?: string[];\n}\n\nexport type JsonParser = (raw: string, context?: JsonParserContext) => unknown;\n\n/**\n * Normalize a parsed JSON object by trimming whitespace from:\n * 1. All object keys (e.g., \" prompt \" -> \"prompt\")\n * 2. All string values (e.g., \" Tap \" -> \"Tap\")\n * This handles LLM output that may include leading/trailing spaces.\n */\nfunction normalizeJsonObject(\n  obj: any,\n  context: Pick<JsonParserContext, 'preserveStringValueKeys'> = {},\n): any {\n  // Handle null and undefined\n  if (obj === null || obj === undefined) {\n    return obj;\n  }\n\n  // Handle arrays - recursively normalize each element\n  if (Array.isArray(obj)) {\n    return obj.map((item) => normalizeJsonObject(item, context));\n  }\n\n  // Handle objects\n  if (typeof obj === 'object') {\n    const normalized: any = {};\n\n    for (const [key, value] of Object.entries(obj)) {\n      // Trim the key to remove leading/trailing spaces\n      const trimmedKey = key.trim();\n      const preserveStringValue =\n        context.preserveStringValueKeys?.includes(trimmedKey) ?? false;\n\n      const normalizedValue =\n        typeof value === 'string'\n          ? preserveStringValue\n            ? value\n            : value.trim()\n          : normalizeJsonObject(value, context);\n\n      normalized[trimmedKey] = normalizedValue;\n    }\n\n    return normalized;\n  }\n\n  // Handle primitive strings\n  if (typeof obj === 'string') {\n    return obj.trim();\n  }\n\n  // Return other primitives as-is\n  return obj;\n}\n\nconst parseNormalJson = (\n  input: string,\n  rawResponse: string,\n  context?: JsonParserContext,\n) => {\n  if (input?.match(/\\((\\d+),(\\d+)\\)/)) {\n    return input\n      .match(/\\((\\d+),(\\d+)\\)/)\n      ?.slice(1)\n      .map(Number);\n  }\n\n  let parsed: any;\n  let lastError: unknown;\n  try {\n    parsed = JSON.parse(input);\n    return normalizeJsonObject(parsed, context);\n  } catch (error) {\n    lastError = error;\n  }\n  try {\n    parsed = JSON.parse(jsonrepair(input));\n    return normalizeJsonObject(parsed, context);\n  } catch (error) {\n    lastError = error;\n  }\n\n  return { parsed: undefined, lastError, rawResponse };\n};\n\nexport function safeParseJson(raw: string, context?: JsonParserContext) {\n  const cleanJsonString = extractJSONFromCodeBlock(raw);\n  const result = parseNormalJson(cleanJsonString, raw, context);\n  if (\n    result &&\n    typeof result === 'object' &&\n    'parsed' in result &&\n    result.parsed === undefined\n  ) {\n    throw Error(\n      `failed to parse LLM response into JSON. Error - ${String(\n        result.lastError ?? 'unknown error',\n      )}. Response - \\n ${raw}`,\n    );\n  }\n  return result;\n}\n\nexport const normalJsonParser: JsonParser = safeParseJson;\n"],"names":["extractJSONFromCodeBlock","response","jsonMatch","codeBlockMatch","jsonLikeMatch","normalizeJsonObject","obj","context","Array","item","normalized","key","value","Object","trimmedKey","preserveStringValue","normalizedValue","parseNormalJson","input","rawResponse","Number","parsed","lastError","JSON","error","jsonrepair","undefined","safeParseJson","raw","cleanJsonString","result","Error","String","normalJsonParser"],"mappings":";AAEO,SAASA,yBAAyBC,QAAgB;IACvD,IAAI;QAEF,MAAMC,YAAYD,SAAS,KAAK,CAAC;QACjC,IAAIC,WACF,OAAOA,SAAS,CAAC,EAAE;QAIrB,MAAMC,iBAAiBF,SAAS,KAAK,CACnC;QAEF,IAAIE,gBACF,OAAOA,cAAc,CAAC,EAAE;QAI1B,MAAMC,gBAAgBH,SAAS,KAAK,CAAC;QACrC,IAAIG,eACF,OAAOA,aAAa,CAAC,EAAE;IAE3B,EAAE,OAAM,CAAC;IAET,OAAOH;AACT;AAqBA,SAASI,oBACPC,GAAQ,EACRC,UAA8D,CAAC,CAAC;IAGhE,IAAID,QAAAA,KACF,OAAOA;IAIT,IAAIE,MAAM,OAAO,CAACF,MAChB,OAAOA,IAAI,GAAG,CAAC,CAACG,OAASJ,oBAAoBI,MAAMF;IAIrD,IAAI,AAAe,YAAf,OAAOD,KAAkB;QAC3B,MAAMI,aAAkB,CAAC;QAEzB,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAO,OAAO,CAACP,KAAM;YAE9C,MAAMQ,aAAaH,IAAI,IAAI;YAC3B,MAAMI,sBACJR,QAAQ,uBAAuB,EAAE,SAASO,eAAe;YAE3D,MAAME,kBACJ,AAAiB,YAAjB,OAAOJ,QACHG,sBACEH,QACAA,MAAM,IAAI,KACZP,oBAAoBO,OAAOL;YAEjCG,UAAU,CAACI,WAAW,GAAGE;QAC3B;QAEA,OAAON;IACT;IAGA,IAAI,AAAe,YAAf,OAAOJ,KACT,OAAOA,IAAI,IAAI;IAIjB,OAAOA;AACT;AAEA,MAAMW,kBAAkB,CACtBC,OACAC,aACAZ;IAEA,IAAIW,OAAO,MAAM,oBACf,OAAOA,MACJ,KAAK,CAAC,oBACL,MAAM,GACP,IAAIE;IAGT,IAAIC;IACJ,IAAIC;IACJ,IAAI;QACFD,SAASE,KAAK,KAAK,CAACL;QACpB,OAAOb,oBAAoBgB,QAAQd;IACrC,EAAE,OAAOiB,OAAO;QACdF,YAAYE;IACd;IACA,IAAI;QACFH,SAASE,KAAK,KAAK,CAACE,WAAWP;QAC/B,OAAOb,oBAAoBgB,QAAQd;IACrC,EAAE,OAAOiB,OAAO;QACdF,YAAYE;IACd;IAEA,OAAO;QAAE,QAAQE;QAAWJ;QAAWH;IAAY;AACrD;AAEO,SAASQ,cAAcC,GAAW,EAAErB,OAA2B;IACpE,MAAMsB,kBAAkB7B,yBAAyB4B;IACjD,MAAME,SAASb,gBAAgBY,iBAAiBD,KAAKrB;IACrD,IACEuB,UACA,AAAkB,YAAlB,OAAOA,UACP,YAAYA,UACZA,AAAkBJ,WAAlBI,OAAO,MAAM,EAEb,MAAMC,MACJ,CAAC,gDAAgD,EAAEC,OACjDF,OAAO,SAAS,IAAI,iBACpB,gBAAgB,EAAEF,KAAK;IAG7B,OAAOE;AACT;AAEO,MAAMG,mBAA+BN"}