@midscene/core 1.10.2 → 1.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/es/agent/agent.mjs +40 -1
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/metrics.mjs +81 -0
  4. package/dist/es/agent/metrics.mjs.map +1 -0
  5. package/dist/es/agent/task-builder.mjs +1 -1
  6. package/dist/es/agent/task-builder.mjs.map +1 -1
  7. package/dist/es/agent/utils.mjs +1 -1
  8. package/dist/es/ai-model/connectivity/run-connectivity-test.mjs +9 -3
  9. package/dist/es/ai-model/connectivity/run-connectivity-test.mjs.map +1 -1
  10. package/dist/es/ai-model/inspect.mjs +3 -3
  11. package/dist/es/ai-model/inspect.mjs.map +1 -1
  12. package/dist/es/ai-model/model-adapter/resolve.mjs +2 -2
  13. package/dist/es/ai-model/model-adapter/resolve.mjs.map +1 -1
  14. package/dist/es/ai-model/models/doubao.mjs +38 -60
  15. package/dist/es/ai-model/models/doubao.mjs.map +1 -1
  16. package/dist/es/ai-model/models/glm.mjs +4 -0
  17. package/dist/es/ai-model/models/glm.mjs.map +1 -1
  18. package/dist/es/ai-model/models/gpt.mjs +5 -1
  19. package/dist/es/ai-model/models/gpt.mjs.map +1 -1
  20. package/dist/es/ai-model/models/kimi.mjs +4 -0
  21. package/dist/es/ai-model/models/kimi.mjs.map +1 -1
  22. package/dist/es/ai-model/models/mimo.mjs +3 -2
  23. package/dist/es/ai-model/models/mimo.mjs.map +1 -1
  24. package/dist/es/ai-model/models/qwen.mjs.map +1 -1
  25. package/dist/es/ai-model/models/ui-tars/adapter.mjs +2 -41
  26. package/dist/es/ai-model/models/ui-tars/adapter.mjs.map +1 -1
  27. package/dist/es/ai-model/models/utils/intent.mjs +6 -0
  28. package/dist/es/ai-model/models/utils/intent.mjs.map +1 -0
  29. package/dist/es/ai-model/prompt/extraction.mjs +9 -3
  30. package/dist/es/ai-model/prompt/extraction.mjs.map +1 -1
  31. package/dist/es/ai-model/prompt/recorder-metadata-generator.mjs +2 -1
  32. package/dist/es/ai-model/prompt/recorder-metadata-generator.mjs.map +1 -1
  33. package/dist/es/ai-model/service-caller/index.mjs +40 -19
  34. package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
  35. package/dist/es/ai-model/service-caller/json.mjs +31 -28
  36. package/dist/es/ai-model/service-caller/json.mjs.map +1 -1
  37. package/dist/es/dump/html-utils.mjs +63 -1
  38. package/dist/es/dump/html-utils.mjs.map +1 -1
  39. package/dist/es/dump/screenshot-restoration.mjs +6 -0
  40. package/dist/es/dump/screenshot-restoration.mjs.map +1 -1
  41. package/dist/es/index.mjs.map +1 -1
  42. package/dist/es/report-generator.mjs +28 -1
  43. package/dist/es/report-generator.mjs.map +1 -1
  44. package/dist/es/report-markdown.mjs +300 -35
  45. package/dist/es/report-markdown.mjs.map +1 -1
  46. package/dist/es/report.mjs +29 -1
  47. package/dist/es/report.mjs.map +1 -1
  48. package/dist/es/service/index.mjs +3 -3
  49. package/dist/es/service/index.mjs.map +1 -1
  50. package/dist/es/types.mjs.map +1 -1
  51. package/dist/es/utils.mjs +2 -2
  52. package/dist/lib/agent/agent.js +40 -1
  53. package/dist/lib/agent/agent.js.map +1 -1
  54. package/dist/lib/agent/metrics.js +115 -0
  55. package/dist/lib/agent/metrics.js.map +1 -0
  56. package/dist/lib/agent/task-builder.js +1 -1
  57. package/dist/lib/agent/task-builder.js.map +1 -1
  58. package/dist/lib/agent/utils.js +1 -1
  59. package/dist/lib/ai-model/connectivity/run-connectivity-test.js +9 -3
  60. package/dist/lib/ai-model/connectivity/run-connectivity-test.js.map +1 -1
  61. package/dist/lib/ai-model/inspect.js +3 -3
  62. package/dist/lib/ai-model/inspect.js.map +1 -1
  63. package/dist/lib/ai-model/model-adapter/resolve.js +1 -1
  64. package/dist/lib/ai-model/model-adapter/resolve.js.map +1 -1
  65. package/dist/lib/ai-model/models/doubao.js +38 -69
  66. package/dist/lib/ai-model/models/doubao.js.map +1 -1
  67. package/dist/lib/ai-model/models/glm.js +4 -0
  68. package/dist/lib/ai-model/models/glm.js.map +1 -1
  69. package/dist/lib/ai-model/models/gpt.js +5 -1
  70. package/dist/lib/ai-model/models/gpt.js.map +1 -1
  71. package/dist/lib/ai-model/models/kimi.js +4 -0
  72. package/dist/lib/ai-model/models/kimi.js.map +1 -1
  73. package/dist/lib/ai-model/models/mimo.js +3 -2
  74. package/dist/lib/ai-model/models/mimo.js.map +1 -1
  75. package/dist/lib/ai-model/models/qwen.js.map +1 -1
  76. package/dist/lib/ai-model/models/ui-tars/adapter.js +1 -40
  77. package/dist/lib/ai-model/models/ui-tars/adapter.js.map +1 -1
  78. package/dist/lib/ai-model/models/utils/intent.js +40 -0
  79. package/dist/lib/ai-model/models/utils/intent.js.map +1 -0
  80. package/dist/lib/ai-model/prompt/extraction.js +8 -2
  81. package/dist/lib/ai-model/prompt/extraction.js.map +1 -1
  82. package/dist/lib/ai-model/prompt/recorder-metadata-generator.js +4 -3
  83. package/dist/lib/ai-model/prompt/recorder-metadata-generator.js.map +1 -1
  84. package/dist/lib/ai-model/service-caller/index.js +44 -23
  85. package/dist/lib/ai-model/service-caller/index.js.map +1 -1
  86. package/dist/lib/ai-model/service-caller/json.js +33 -33
  87. package/dist/lib/ai-model/service-caller/json.js.map +1 -1
  88. package/dist/lib/dump/html-utils.js +65 -0
  89. package/dist/lib/dump/html-utils.js.map +1 -1
  90. package/dist/lib/dump/screenshot-restoration.js +6 -0
  91. package/dist/lib/dump/screenshot-restoration.js.map +1 -1
  92. package/dist/lib/index.js.map +1 -1
  93. package/dist/lib/report-generator.js +27 -0
  94. package/dist/lib/report-generator.js.map +1 -1
  95. package/dist/lib/report-markdown.js +300 -35
  96. package/dist/lib/report-markdown.js.map +1 -1
  97. package/dist/lib/report.js +28 -0
  98. package/dist/lib/report.js.map +1 -1
  99. package/dist/lib/service/index.js +3 -3
  100. package/dist/lib/service/index.js.map +1 -1
  101. package/dist/lib/types.js.map +1 -1
  102. package/dist/lib/utils.js +2 -2
  103. package/dist/types/agent/agent.d.ts +15 -0
  104. package/dist/types/agent/index.d.ts +1 -0
  105. package/dist/types/agent/metrics.d.ts +48 -0
  106. package/dist/types/ai-model/model-adapter/types.d.ts +8 -0
  107. package/dist/types/ai-model/models/doubao.d.ts +1 -4
  108. package/dist/types/ai-model/models/utils/intent.d.ts +2 -0
  109. package/dist/types/ai-model/service-caller/index.d.ts +8 -3
  110. package/dist/types/ai-model/service-caller/json.d.ts +19 -2
  111. package/dist/types/dump/html-utils.d.ts +2 -0
  112. package/dist/types/dump/screenshot-restoration.d.ts +1 -1
  113. package/dist/types/index.d.ts +1 -1
  114. package/dist/types/report-generator.d.ts +6 -0
  115. package/dist/types/types.d.ts +11 -2
  116. package/package.json +3 -3
@@ -45,13 +45,19 @@ function parseXMLExtractionResponse(xmlString) {
45
45
  if (!dataJsonStr) throw new Error('Missing required field: data-json');
46
46
  let data;
47
47
  try {
48
- data = (0, json_js_namespaceObject.safeParseJson)(dataJsonStr);
48
+ data = (0, json_js_namespaceObject.parseModelResponseJson)(dataJsonStr, {
49
+ source: 'generic-object',
50
+ requireObject: false
51
+ });
49
52
  } catch (e) {
50
53
  throw new Error(`Failed to parse data-json: ${e}`);
51
54
  }
52
55
  let errors;
53
56
  if (errorsStr) try {
54
- const parsedErrors = (0, json_js_namespaceObject.safeParseJson)(errorsStr);
57
+ const parsedErrors = (0, json_js_namespaceObject.parseModelResponseJson)(errorsStr, {
58
+ source: 'generic-object',
59
+ requireObject: false
60
+ });
55
61
  if (Array.isArray(parsedErrors)) errors = parsedErrors;
56
62
  } catch (e) {}
57
63
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/prompt/extraction.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../src/ai-model/prompt/extraction.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { AIDataExtractionResponse, ServiceExtractParam } from '@/types';\nimport { getPreferredLanguage } from '@midscene/shared/env';\nimport { safeParseJson } from '../service-caller/json';\nimport { extractXMLTag } from './util';\n\nexport function buildTypeQueryDemandValue(\n type: 'Boolean' | 'Number' | 'String' | 'Assert' | 'WaitFor',\n demand: ServiceExtractParam,\n) {\n const currentScreenshotConstraint =\n 'based on the current screenshot and its contents if provided, unless the user explicitly asks to compare with reference images';\n\n if (type === 'Assert') {\n return `Boolean, ${currentScreenshotConstraint}, whether the following statement is true: ${demand}`;\n }\n\n if (type === 'WaitFor') {\n return `Boolean, the user wants to do some 'wait for' operation. ${currentScreenshotConstraint}, please check whether the following statement is true: ${demand}`;\n }\n\n return `${type}, ${currentScreenshotConstraint}, ${demand}`;\n}\n\n/**\n * Parse XML response from LLM and convert to AIDataExtractionResponse\n */\nexport function parseXMLExtractionResponse<T>(\n xmlString: string,\n): AIDataExtractionResponse<T> {\n // Keep the internal field named `thought`, but ask models to emit\n // <observation>. Gemini may only return <thought>-named content when\n // thinking summaries are enabled.\n const thought = extractXMLTag(xmlString, 'observation');\n const dataJsonStr = extractXMLTag(xmlString, 'data-json');\n const errorsStr = extractXMLTag(xmlString, 'errors');\n\n // Parse data-json (required)\n if (!dataJsonStr) {\n throw new Error('Missing required field: data-json');\n }\n\n let data: T;\n try {\n data = safeParseJson(dataJsonStr) as T;\n } catch (e) {\n throw new Error(`Failed to parse data-json: ${e}`);\n }\n\n // Parse errors (optional)\n let errors: string[] | undefined;\n if (errorsStr) {\n try {\n const parsedErrors = safeParseJson(errorsStr);\n if (Array.isArray(parsedErrors)) {\n errors = parsedErrors;\n }\n } catch (e) {\n // If errors parsing fails, just ignore it\n }\n }\n\n return {\n ...(thought ? { thought } : {}),\n data,\n ...(errors && errors.length > 0 ? { errors } : {}),\n };\n}\n\nexport function systemPromptToExtract(options?: {\n screenshotIncluded?: boolean;\n referenceImagesIncluded?: boolean;\n}) {\n const preferredLanguage = getPreferredLanguage();\n const screenshotIncluded = options?.screenshotIncluded ?? true;\n const referenceImagesIncluded = options?.referenceImagesIncluded ?? false;\n\n const contextPrompts = [\n \"The user will give you data requirements in <DATA_DEMAND>. You need to understand the user's requirements and extract the data satisfying the <DATA_DEMAND>.\",\n ];\n\n if (screenshotIncluded) {\n contextPrompts.push(\n 'The user will provide a current screenshot to evaluate, and may provide its contents. Base your answer on the current screenshot and its contents when provided. Treat them as the primary source of truth for what is currently visible or true.',\n );\n } else {\n contextPrompts.push(\n 'The user will not provide a current screenshot. Use only the supplied page contents and other inputs, and do not infer unsupported visual details.',\n );\n }\n\n if (referenceImagesIncluded) {\n const referenceImagesPrompt =\n 'Reference images are supporting context only unless <DATA_DEMAND> explicitly asks for comparison, matching, or reasoning about them.';\n contextPrompts.push(\n screenshotIncluded\n ? `${referenceImagesPrompt} Do not conclude that something exists in the current screenshot solely because it appears in a reference image; when they conflict, trust the current screenshot and its contents.`\n : `${referenceImagesPrompt} Do not treat reference images as direct evidence of the current state unless the demand explicitly asks you to use them that way.`,\n );\n }\n const contextPrompt = contextPrompts.join('\\n\\n');\n\n return `\nYou are a versatile professional in software UI design and testing. Your outstanding contributions will impact the user experience of billions of users.\n\n${contextPrompt}\n\nIf a key specifies a JSON data type (such as Number, String, Boolean, Object, Array), ensure the returned value strictly matches that data type.\n\nWhen DATA_DEMAND is a JSON object, the keys in your response must exactly match the keys in DATA_DEMAND. Do not rename, translate, or substitute any key.\n\n\nReturn in the following XML format:\n<observation>brief evidence observed for the extraction, less than 300 words. Use ${preferredLanguage} in this field.</observation>\n<data-json>the extracted data as JSON. Make sure both the value and scheme meet the DATA_DEMAND. If you want to write some description in this field, use the same language as the DATA_DEMAND.</data-json>\n<errors>optional error messages as JSON array, e.g., [\"error1\", \"error2\"]</errors>\n\n# Example 1\nFor example, if the DATA_DEMAND is:\n\n<DATA_DEMAND>\n{\n \"name\": \"name shows on the left panel, string\",\n \"age\": \"age shows on the right panel, number\",\n \"isAdmin\": \"if the user is admin, boolean\"\n}\n</DATA_DEMAND>\n\nBy viewing the screenshot and page contents, you can extract the following data:\n\n<observation>According to the screenshot, i can see ...</observation>\n<data-json>\n{\n \"name\": \"John\",\n \"age\": 30,\n \"isAdmin\": true\n}\n</data-json>\n\n# Example 2\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\nthe todo items list, string[]\n</DATA_DEMAND>\n\nBy viewing the screenshot and page contents, you can extract the following data:\n\n<observation>According to the screenshot, i can see ...</observation>\n<data-json>\n[\"todo 1\", \"todo 2\", \"todo 3\"]\n</data-json>\n\n# Example 3\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\nthe page title, string\n</DATA_DEMAND>\n\nBy viewing the screenshot and page contents, you can extract the following data:\n\n<observation>According to the screenshot, i can see ...</observation>\n<data-json>\n\"todo list\"\n</data-json>\n\n# Example 4\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\n{\n \"StatementIsTruthy\": \"Boolean, is it currently the SMS page?\"\n}\n</DATA_DEMAND>\n\nBy viewing the screenshot and page contents, you can extract the following data:\n\n<observation>According to the screenshot, i can see ...</observation>\n<data-json>\n{ \"StatementIsTruthy\": true }\n</data-json>\n`;\n}\n\nexport const extractDataQueryPrompt = (\n pageDescription: string,\n dataQuery: string | Record<string, string>,\n) => {\n let dataQueryText = '';\n if (typeof dataQuery === 'string') {\n dataQueryText = dataQuery;\n } else {\n dataQueryText = JSON.stringify(dataQuery, null, 2);\n }\n\n return `\n<PageDescription>\n${pageDescription}\n</PageDescription>\n\n<DATA_DEMAND>\n${dataQueryText}\n</DATA_DEMAND>\n `;\n};\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","buildTypeQueryDemandValue","type","demand","currentScreenshotConstraint","parseXMLExtractionResponse","xmlString","thought","extractXMLTag","dataJsonStr","errorsStr","Error","data","safeParseJson","e","errors","parsedErrors","Array","systemPromptToExtract","options","preferredLanguage","getPreferredLanguage","screenshotIncluded","referenceImagesIncluded","contextPrompts","referenceImagesPrompt","contextPrompt","extractDataQueryPrompt","pageDescription","dataQuery","dataQueryText","JSON"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/prompt/extraction.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../src/ai-model/prompt/extraction.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { AIDataExtractionResponse, ServiceExtractParam } from '@/types';\nimport { getPreferredLanguage } from '@midscene/shared/env';\nimport { parseModelResponseJson } from '../service-caller/json';\nimport { extractXMLTag } from './util';\n\nexport function buildTypeQueryDemandValue(\n type: 'Boolean' | 'Number' | 'String' | 'Assert' | 'WaitFor',\n demand: ServiceExtractParam,\n) {\n const currentScreenshotConstraint =\n 'based on the current screenshot and its contents if provided, unless the user explicitly asks to compare with reference images';\n\n if (type === 'Assert') {\n return `Boolean, ${currentScreenshotConstraint}, whether the following statement is true: ${demand}`;\n }\n\n if (type === 'WaitFor') {\n return `Boolean, the user wants to do some 'wait for' operation. ${currentScreenshotConstraint}, please check whether the following statement is true: ${demand}`;\n }\n\n return `${type}, ${currentScreenshotConstraint}, ${demand}`;\n}\n\n/**\n * Parse XML response from LLM and convert to AIDataExtractionResponse\n */\nexport function parseXMLExtractionResponse<T>(\n xmlString: string,\n): AIDataExtractionResponse<T> {\n // Keep the internal field named `thought`, but ask models to emit\n // <observation>. Gemini may only return <thought>-named content when\n // thinking summaries are enabled.\n const thought = extractXMLTag(xmlString, 'observation');\n const dataJsonStr = extractXMLTag(xmlString, 'data-json');\n const errorsStr = extractXMLTag(xmlString, 'errors');\n\n // Parse data-json (required)\n if (!dataJsonStr) {\n throw new Error('Missing required field: data-json');\n }\n\n let data: T;\n try {\n data = parseModelResponseJson(dataJsonStr, {\n source: 'generic-object',\n requireObject: false,\n }) as T;\n } catch (e) {\n throw new Error(`Failed to parse data-json: ${e}`);\n }\n\n // Parse errors (optional)\n let errors: string[] | undefined;\n if (errorsStr) {\n try {\n const parsedErrors = parseModelResponseJson(errorsStr, {\n source: 'generic-object',\n requireObject: false,\n });\n if (Array.isArray(parsedErrors)) {\n errors = parsedErrors;\n }\n } catch (e) {\n // If errors parsing fails, just ignore it\n }\n }\n\n return {\n ...(thought ? { thought } : {}),\n data,\n ...(errors && errors.length > 0 ? { errors } : {}),\n };\n}\n\nexport function systemPromptToExtract(options?: {\n screenshotIncluded?: boolean;\n referenceImagesIncluded?: boolean;\n}) {\n const preferredLanguage = getPreferredLanguage();\n const screenshotIncluded = options?.screenshotIncluded ?? true;\n const referenceImagesIncluded = options?.referenceImagesIncluded ?? false;\n\n const contextPrompts = [\n \"The user will give you data requirements in <DATA_DEMAND>. You need to understand the user's requirements and extract the data satisfying the <DATA_DEMAND>.\",\n ];\n\n if (screenshotIncluded) {\n contextPrompts.push(\n 'The user will provide a current screenshot to evaluate, and may provide its contents. Base your answer on the current screenshot and its contents when provided. Treat them as the primary source of truth for what is currently visible or true.',\n );\n } else {\n contextPrompts.push(\n 'The user will not provide a current screenshot. Use only the supplied page contents and other inputs, and do not infer unsupported visual details.',\n );\n }\n\n if (referenceImagesIncluded) {\n const referenceImagesPrompt =\n 'Reference images are supporting context only unless <DATA_DEMAND> explicitly asks for comparison, matching, or reasoning about them.';\n contextPrompts.push(\n screenshotIncluded\n ? `${referenceImagesPrompt} Do not conclude that something exists in the current screenshot solely because it appears in a reference image; when they conflict, trust the current screenshot and its contents.`\n : `${referenceImagesPrompt} Do not treat reference images as direct evidence of the current state unless the demand explicitly asks you to use them that way.`,\n );\n }\n const contextPrompt = contextPrompts.join('\\n\\n');\n\n return `\nYou are a versatile professional in software UI design and testing. Your outstanding contributions will impact the user experience of billions of users.\n\n${contextPrompt}\n\nIf a key specifies a JSON data type (such as Number, String, Boolean, Object, Array), ensure the returned value strictly matches that data type.\n\nWhen DATA_DEMAND is a JSON object, the keys in your response must exactly match the keys in DATA_DEMAND. Do not rename, translate, or substitute any key.\n\n\nReturn in the following XML format:\n<observation>brief evidence observed for the extraction, less than 300 words. Use ${preferredLanguage} in this field.</observation>\n<data-json>the extracted data as JSON. Make sure both the value and scheme meet the DATA_DEMAND. If you want to write some description in this field, use the same language as the DATA_DEMAND.</data-json>\n<errors>optional error messages as JSON array, e.g., [\"error1\", \"error2\"]</errors>\n\n# Example 1\nFor example, if the DATA_DEMAND is:\n\n<DATA_DEMAND>\n{\n \"name\": \"name shows on the left panel, string\",\n \"age\": \"age shows on the right panel, number\",\n \"isAdmin\": \"if the user is admin, boolean\"\n}\n</DATA_DEMAND>\n\nBy viewing the screenshot and page contents, you can extract the following data:\n\n<observation>According to the screenshot, i can see ...</observation>\n<data-json>\n{\n \"name\": \"John\",\n \"age\": 30,\n \"isAdmin\": true\n}\n</data-json>\n\n# Example 2\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\nthe todo items list, string[]\n</DATA_DEMAND>\n\nBy viewing the screenshot and page contents, you can extract the following data:\n\n<observation>According to the screenshot, i can see ...</observation>\n<data-json>\n[\"todo 1\", \"todo 2\", \"todo 3\"]\n</data-json>\n\n# Example 3\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\nthe page title, string\n</DATA_DEMAND>\n\nBy viewing the screenshot and page contents, you can extract the following data:\n\n<observation>According to the screenshot, i can see ...</observation>\n<data-json>\n\"todo list\"\n</data-json>\n\n# Example 4\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\n{\n \"StatementIsTruthy\": \"Boolean, is it currently the SMS page?\"\n}\n</DATA_DEMAND>\n\nBy viewing the screenshot and page contents, you can extract the following data:\n\n<observation>According to the screenshot, i can see ...</observation>\n<data-json>\n{ \"StatementIsTruthy\": true }\n</data-json>\n`;\n}\n\nexport const extractDataQueryPrompt = (\n pageDescription: string,\n dataQuery: string | Record<string, string>,\n) => {\n let dataQueryText = '';\n if (typeof dataQuery === 'string') {\n dataQueryText = dataQuery;\n } else {\n dataQueryText = JSON.stringify(dataQuery, null, 2);\n }\n\n return `\n<PageDescription>\n${pageDescription}\n</PageDescription>\n\n<DATA_DEMAND>\n${dataQueryText}\n</DATA_DEMAND>\n `;\n};\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","buildTypeQueryDemandValue","type","demand","currentScreenshotConstraint","parseXMLExtractionResponse","xmlString","thought","extractXMLTag","dataJsonStr","errorsStr","Error","data","parseModelResponseJson","e","errors","parsedErrors","Array","systemPromptToExtract","options","preferredLanguage","getPreferredLanguage","screenshotIncluded","referenceImagesIncluded","contextPrompts","referenceImagesPrompt","contextPrompt","extractDataQueryPrompt","pageDescription","dataQuery","dataQueryText","JSON"],"mappings":"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"}
@@ -27,7 +27,8 @@ __webpack_require__.d(__webpack_exports__, {
27
27
  generateRecorderSessionMetadata: ()=>generateRecorderSessionMetadata
28
28
  });
29
29
  const recorder_namespaceObject = require("@midscene/shared/recorder");
30
- const index_js_namespaceObject = require("../service-caller/index.js");
30
+ const index_js_namespaceObject = require("../models/index.js");
31
+ const external_service_caller_index_js_namespaceObject = require("../service-caller/index.js");
31
32
  const external_recorder_generation_common_js_namespaceObject = require("./recorder-generation-common.js");
32
33
  function summarizeRecorderEvents(input) {
33
34
  const events = input.events;
@@ -90,7 +91,7 @@ Respond with a JSON object containing exactly "title" and "description".`
90
91
  url: screenshot
91
92
  }
92
93
  });
93
- const response = await (0, index_js_namespaceObject.callAIWithObjectResponse)([
94
+ const response = await (0, external_service_caller_index_js_namespaceObject.callAIWithObjectResponse)([
94
95
  {
95
96
  role: 'system',
96
97
  content: "You generate clear, task-oriented titles and descriptions for recorded automation sessions."
@@ -99,7 +100,7 @@ Respond with a JSON object containing exactly "title" and "description".`
99
100
  role: 'user',
100
101
  content: messageContent
101
102
  }
102
- ], modelConfig);
103
+ ], (0, index_js_namespaceObject.getModelRuntime)(modelConfig));
103
104
  return {
104
105
  title: normalizeMetadataValue(response.content.title),
105
106
  description: normalizeMetadataValue(response.content.description)
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/prompt/recorder-metadata-generator.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../src/ai-model/prompt/recorder-metadata-generator.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { IModelConfig } from '@midscene/shared/env';\nimport {\n type MidsceneRecorderEvent,\n type MidsceneRecorderTarget,\n getMidsceneRecorderEventDescription,\n getMidsceneRecorderScreenshotsForLLM,\n getMidsceneRecorderSemantic,\n} from '@midscene/shared/recorder';\nimport { callAIWithObjectResponse } from '../service-caller/index';\nimport { compactRecorderSemanticForGeneration } from './recorder-generation-common';\n\nexport interface RecorderMetadataGenerationInput {\n target: MidsceneRecorderTarget;\n events: MidsceneRecorderEvent[];\n fallbackName?: string;\n maxScreenshots?: number;\n}\n\nexport interface RecorderGeneratedMetadata {\n title?: string;\n description?: string;\n}\n\nfunction summarizeRecorderEvents(input: RecorderMetadataGenerationInput) {\n const events = input.events;\n const navigationEvents = events.filter(\n (event) => event.type === 'navigation',\n );\n const clickEvents = events.filter((event) => event.type === 'click');\n const inputEvents = events.filter((event) => event.type === 'input');\n const scrollEvents = events.filter((event) => event.type === 'scroll');\n const urls = navigationEvents\n .map((event) => event.url)\n .filter((url): url is string => Boolean(url));\n const titles = navigationEvents\n .map((event) => event.title)\n .filter((title): title is string => Boolean(title));\n\n return {\n platform: input.target.platformId,\n target: input.target,\n fallbackName: input.fallbackName,\n pageCount: navigationEvents.length,\n pageTitles: titles.slice(0, 5),\n urls: urls.slice(0, 5),\n clickCount: clickEvents.length,\n inputCount: inputEvents.length,\n scrollCount: scrollEvents.length,\n totalActions: events.length,\n firstUrl: urls[0] || input.target.values.url || '',\n lastUrl: urls[urls.length - 1] || '',\n events: events.slice(0, 20).map((event) => ({\n type: event.type,\n actionType: event.actionType,\n url: event.url,\n title: event.title,\n value: event.value,\n description: getMidsceneRecorderEventDescription(event),\n semantic: compactRecorderSemanticForGeneration(\n getMidsceneRecorderSemantic(event),\n ),\n })),\n };\n}\n\nfunction normalizeMetadataValue(value: unknown) {\n return typeof value === 'string' ? value.trim() : '';\n}\n\nexport async function generateRecorderSessionMetadata(\n input: RecorderMetadataGenerationInput,\n modelConfig: IModelConfig,\n): Promise<RecorderGeneratedMetadata> {\n if (!input?.events?.length) {\n throw new Error('generateRecorderSessionMetadata: events are required.');\n }\n if (!modelConfig?.modelName) {\n throw new Error(\n 'generateRecorderSessionMetadata: modelConfig.modelName is required.',\n );\n }\n\n const summary = summarizeRecorderEvents(input);\n const screenshots = getMidsceneRecorderScreenshotsForLLM(\n input.events,\n input.maxScreenshots ?? 1,\n );\n const messageContent: any[] = [\n {\n type: 'text',\n text: `Generate a concise title (5-7 words) and brief description (1-2 sentences) for a Studio recording of user actions.\n\nThe recording can target Web, Android, iOS, HarmonyOS, or Computer. Do not assume it is a browser session unless the platform is web.\nDescribe what the user did or accomplished. The description should use the user as the subject, preferably starting with \"The user ...\". Do not start the description with \"The session ...\".\nThe title should be action-oriented and highlight the main task accomplished.\n\nSummary:\n${JSON.stringify(summary, null, 2)}\n\nRespond with a JSON object containing exactly \"title\" and \"description\".`,\n },\n ];\n\n for (const screenshot of screenshots) {\n messageContent.push({\n type: 'image_url',\n image_url: { url: screenshot },\n });\n }\n\n const response = await callAIWithObjectResponse<{\n title?: string;\n description?: string;\n }>(\n [\n {\n role: 'system',\n content:\n 'You generate clear, task-oriented titles and descriptions for recorded automation sessions.',\n },\n {\n role: 'user',\n content: messageContent,\n },\n ],\n modelConfig,\n );\n\n return {\n title: normalizeMetadataValue(response.content.title),\n description: normalizeMetadataValue(response.content.description),\n };\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","summarizeRecorderEvents","input","events","navigationEvents","event","clickEvents","inputEvents","scrollEvents","urls","url","Boolean","titles","title","getMidsceneRecorderEventDescription","compactRecorderSemanticForGeneration","getMidsceneRecorderSemantic","normalizeMetadataValue","value","generateRecorderSessionMetadata","modelConfig","Error","summary","screenshots","getMidsceneRecorderScreenshotsForLLM","messageContent","JSON","screenshot","response","callAIWithObjectResponse"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/prompt/recorder-metadata-generator.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../src/ai-model/prompt/recorder-metadata-generator.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { IModelConfig } from '@midscene/shared/env';\nimport {\n type MidsceneRecorderEvent,\n type MidsceneRecorderTarget,\n getMidsceneRecorderEventDescription,\n getMidsceneRecorderScreenshotsForLLM,\n getMidsceneRecorderSemantic,\n} from '@midscene/shared/recorder';\nimport { getModelRuntime } from '../models';\nimport { callAIWithObjectResponse } from '../service-caller/index';\nimport { compactRecorderSemanticForGeneration } from './recorder-generation-common';\n\nexport interface RecorderMetadataGenerationInput {\n target: MidsceneRecorderTarget;\n events: MidsceneRecorderEvent[];\n fallbackName?: string;\n maxScreenshots?: number;\n}\n\nexport interface RecorderGeneratedMetadata {\n title?: string;\n description?: string;\n}\n\nfunction summarizeRecorderEvents(input: RecorderMetadataGenerationInput) {\n const events = input.events;\n const navigationEvents = events.filter(\n (event) => event.type === 'navigation',\n );\n const clickEvents = events.filter((event) => event.type === 'click');\n const inputEvents = events.filter((event) => event.type === 'input');\n const scrollEvents = events.filter((event) => event.type === 'scroll');\n const urls = navigationEvents\n .map((event) => event.url)\n .filter((url): url is string => Boolean(url));\n const titles = navigationEvents\n .map((event) => event.title)\n .filter((title): title is string => Boolean(title));\n\n return {\n platform: input.target.platformId,\n target: input.target,\n fallbackName: input.fallbackName,\n pageCount: navigationEvents.length,\n pageTitles: titles.slice(0, 5),\n urls: urls.slice(0, 5),\n clickCount: clickEvents.length,\n inputCount: inputEvents.length,\n scrollCount: scrollEvents.length,\n totalActions: events.length,\n firstUrl: urls[0] || input.target.values.url || '',\n lastUrl: urls[urls.length - 1] || '',\n events: events.slice(0, 20).map((event) => ({\n type: event.type,\n actionType: event.actionType,\n url: event.url,\n title: event.title,\n value: event.value,\n description: getMidsceneRecorderEventDescription(event),\n semantic: compactRecorderSemanticForGeneration(\n getMidsceneRecorderSemantic(event),\n ),\n })),\n };\n}\n\nfunction normalizeMetadataValue(value: unknown) {\n return typeof value === 'string' ? value.trim() : '';\n}\n\nexport async function generateRecorderSessionMetadata(\n input: RecorderMetadataGenerationInput,\n modelConfig: IModelConfig,\n): Promise<RecorderGeneratedMetadata> {\n if (!input?.events?.length) {\n throw new Error('generateRecorderSessionMetadata: events are required.');\n }\n if (!modelConfig?.modelName) {\n throw new Error(\n 'generateRecorderSessionMetadata: modelConfig.modelName is required.',\n );\n }\n\n const summary = summarizeRecorderEvents(input);\n const screenshots = getMidsceneRecorderScreenshotsForLLM(\n input.events,\n input.maxScreenshots ?? 1,\n );\n const messageContent: any[] = [\n {\n type: 'text',\n text: `Generate a concise title (5-7 words) and brief description (1-2 sentences) for a Studio recording of user actions.\n\nThe recording can target Web, Android, iOS, HarmonyOS, or Computer. Do not assume it is a browser session unless the platform is web.\nDescribe what the user did or accomplished. The description should use the user as the subject, preferably starting with \"The user ...\". Do not start the description with \"The session ...\".\nThe title should be action-oriented and highlight the main task accomplished.\n\nSummary:\n${JSON.stringify(summary, null, 2)}\n\nRespond with a JSON object containing exactly \"title\" and \"description\".`,\n },\n ];\n\n for (const screenshot of screenshots) {\n messageContent.push({\n type: 'image_url',\n image_url: { url: screenshot },\n });\n }\n\n const response = await callAIWithObjectResponse<{\n title?: string;\n description?: string;\n }>(\n [\n {\n role: 'system',\n content:\n 'You generate clear, task-oriented titles and descriptions for recorded automation sessions.',\n },\n {\n role: 'user',\n content: messageContent,\n },\n ],\n getModelRuntime(modelConfig),\n );\n\n return {\n title: normalizeMetadataValue(response.content.title),\n description: normalizeMetadataValue(response.content.description),\n };\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","summarizeRecorderEvents","input","events","navigationEvents","event","clickEvents","inputEvents","scrollEvents","urls","url","Boolean","titles","title","getMidsceneRecorderEventDescription","compactRecorderSemanticForGeneration","getMidsceneRecorderSemantic","normalizeMetadataValue","value","generateRecorderSessionMetadata","modelConfig","Error","summary","screenshots","getMidsceneRecorderScreenshotsForLLM","messageContent","JSON","screenshot","response","callAIWithObjectResponse","getModelRuntime"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;ACkBA,SAASI,wBAAwBC,KAAsC;IACrE,MAAMC,SAASD,MAAM,MAAM;IAC3B,MAAME,mBAAmBD,OAAO,MAAM,CACpC,CAACE,QAAUA,AAAe,iBAAfA,MAAM,IAAI;IAEvB,MAAMC,cAAcH,OAAO,MAAM,CAAC,CAACE,QAAUA,AAAe,YAAfA,MAAM,IAAI;IACvD,MAAME,cAAcJ,OAAO,MAAM,CAAC,CAACE,QAAUA,AAAe,YAAfA,MAAM,IAAI;IACvD,MAAMG,eAAeL,OAAO,MAAM,CAAC,CAACE,QAAUA,AAAe,aAAfA,MAAM,IAAI;IACxD,MAAMI,OAAOL,iBACV,GAAG,CAAC,CAACC,QAAUA,MAAM,GAAG,EACxB,MAAM,CAAC,CAACK,MAAuBC,QAAQD;IAC1C,MAAME,SAASR,iBACZ,GAAG,CAAC,CAACC,QAAUA,MAAM,KAAK,EAC1B,MAAM,CAAC,CAACQ,QAA2BF,QAAQE;IAE9C,OAAO;QACL,UAAUX,MAAM,MAAM,CAAC,UAAU;QACjC,QAAQA,MAAM,MAAM;QACpB,cAAcA,MAAM,YAAY;QAChC,WAAWE,iBAAiB,MAAM;QAClC,YAAYQ,OAAO,KAAK,CAAC,GAAG;QAC5B,MAAMH,KAAK,KAAK,CAAC,GAAG;QACpB,YAAYH,YAAY,MAAM;QAC9B,YAAYC,YAAY,MAAM;QAC9B,aAAaC,aAAa,MAAM;QAChC,cAAcL,OAAO,MAAM;QAC3B,UAAUM,IAAI,CAAC,EAAE,IAAIP,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI;QAChD,SAASO,IAAI,CAACA,KAAK,MAAM,GAAG,EAAE,IAAI;QAClC,QAAQN,OAAO,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,CAACE,QAAW;gBAC1C,MAAMA,MAAM,IAAI;gBAChB,YAAYA,MAAM,UAAU;gBAC5B,KAAKA,MAAM,GAAG;gBACd,OAAOA,MAAM,KAAK;gBAClB,OAAOA,MAAM,KAAK;gBAClB,aAAaS,AAAAA,IAAAA,yBAAAA,mCAAAA,AAAAA,EAAoCT;gBACjD,UAAUU,AAAAA,IAAAA,uDAAAA,oCAAAA,AAAAA,EACRC,AAAAA,IAAAA,yBAAAA,2BAAAA,AAAAA,EAA4BX;YAEhC;IACF;AACF;AAEA,SAASY,uBAAuBC,KAAc;IAC5C,OAAO,AAAiB,YAAjB,OAAOA,QAAqBA,MAAM,IAAI,KAAK;AACpD;AAEO,eAAeC,gCACpBjB,KAAsC,EACtCkB,WAAyB;IAEzB,IAAI,CAAClB,OAAO,QAAQ,QAClB,MAAM,IAAImB,MAAM;IAElB,IAAI,CAACD,aAAa,WAChB,MAAM,IAAIC,MACR;IAIJ,MAAMC,UAAUrB,wBAAwBC;IACxC,MAAMqB,cAAcC,AAAAA,IAAAA,yBAAAA,oCAAAA,AAAAA,EAClBtB,MAAM,MAAM,EACZA,MAAM,cAAc,IAAI;IAE1B,MAAMuB,iBAAwB;QAC5B;YACE,MAAM;YACN,MAAM,CAAC;;;;;;;AAOb,EAAEC,KAAK,SAAS,CAACJ,SAAS,MAAM,GAAG;;wEAEqC,CAAC;QACrE;KACD;IAED,KAAK,MAAMK,cAAcJ,YACvBE,eAAe,IAAI,CAAC;QAClB,MAAM;QACN,WAAW;YAAE,KAAKE;QAAW;IAC/B;IAGF,MAAMC,WAAW,MAAMC,AAAAA,IAAAA,iDAAAA,wBAAAA,AAAAA,EAIrB;QACE;YACE,MAAM;YACN,SACE;QACJ;QACA;YACE,MAAM;YACN,SAASJ;QACX;KACD,EACDK,AAAAA,IAAAA,yBAAAA,eAAAA,AAAAA,EAAgBV;IAGlB,OAAO;QACL,OAAOH,uBAAuBW,SAAS,OAAO,CAAC,KAAK;QACpD,aAAaX,uBAAuBW,SAAS,OAAO,CAAC,WAAW;IAClE;AACF"}
@@ -35,11 +35,11 @@ __webpack_require__.r(__webpack_exports__);
35
35
  __webpack_require__.d(__webpack_exports__, {
36
36
  callAIWithObjectResponse: ()=>callAIWithObjectResponse,
37
37
  extractJSONFromCodeBlock: ()=>external_json_js_namespaceObject.extractJSONFromCodeBlock,
38
- normalJsonParser: ()=>external_json_js_namespaceObject.normalJsonParser,
39
- safeParseJson: ()=>external_json_js_namespaceObject.safeParseJson,
40
38
  callAI: ()=>callAI,
39
+ parseModelResponseJson: ()=>external_json_js_namespaceObject.parseModelResponseJson,
41
40
  createChatClient: ()=>createChatClient,
42
41
  AIResponseParseError: ()=>AIResponseParseError,
42
+ INTERNAL_CALL_ID_FIELD: ()=>INTERNAL_CALL_ID_FIELD,
43
43
  callAIWithStringResponse: ()=>callAIWithStringResponse
44
44
  });
45
45
  const env_namespaceObject = require("@midscene/shared/env");
@@ -47,7 +47,6 @@ const logger_namespaceObject = require("@midscene/shared/logger");
47
47
  const utils_namespaceObject = require("@midscene/shared/utils");
48
48
  const external_openai_namespaceObject = require("openai");
49
49
  var external_openai_default = /*#__PURE__*/ __webpack_require__.n(external_openai_namespaceObject);
50
- const index_js_namespaceObject = require("../models/index.js");
51
50
  const external_codex_app_server_js_namespaceObject = require("./codex-app-server.js");
52
51
  const external_openai_error_js_namespaceObject = require("./openai-error.js");
53
52
  const external_request_timeout_js_namespaceObject = require("./request-timeout.js");
@@ -71,6 +70,12 @@ class AIResponseParseError extends Error {
71
70
  this.rawChoiceMessage = rawChoiceMessage;
72
71
  }
73
72
  }
73
+ const INTERNAL_CALL_ID_FIELD = '_midscene_call_id';
74
+ let internalCallIdCounter = 0;
75
+ function nextInternalCallId() {
76
+ internalCallIdCounter += 1;
77
+ return `call_${internalCallIdCounter}`;
78
+ }
74
79
  function stringifyForDebug(value) {
75
80
  try {
76
81
  return JSON.stringify(value);
@@ -213,12 +218,20 @@ async function createChatClient({ modelConfig }) {
213
218
  }
214
219
  async function callAI(messages, modelRuntime, options) {
215
220
  const { config: modelConfig, adapter } = modelRuntime;
216
- if ((0, external_codex_app_server_js_namespaceObject.isCodexAppServerProvider)(modelConfig.openaiBaseURL)) return (0, external_codex_app_server_js_namespaceObject.callAIWithCodexAppServer)(messages, modelConfig, {
217
- stream: options?.stream,
218
- onChunk: options?.onChunk,
219
- reasoningEnabled: modelConfig.reasoningEnabled,
220
- abortSignal: options?.abortSignal
221
- });
221
+ const internalCallId = nextInternalCallId();
222
+ if ((0, external_codex_app_server_js_namespaceObject.isCodexAppServerProvider)(modelConfig.openaiBaseURL)) {
223
+ const codexResult = await (0, external_codex_app_server_js_namespaceObject.callAIWithCodexAppServer)(messages, modelConfig, {
224
+ stream: options?.stream,
225
+ onChunk: options?.onChunk,
226
+ reasoningEnabled: modelConfig.reasoningEnabled,
227
+ abortSignal: options?.abortSignal
228
+ });
229
+ if (codexResult.usage) {
230
+ codexResult.usage[INTERNAL_CALL_ID_FIELD] = internalCallId;
231
+ if (modelRuntime.onUsage) modelRuntime.onUsage(codexResult.usage);
232
+ }
233
+ return codexResult;
234
+ }
222
235
  const { completion, modelName, modelDescription, modelFamily, openAIErrorResponseContext } = await createChatClient({
223
236
  modelConfig
224
237
  });
@@ -254,6 +267,7 @@ async function callAI(messages, modelRuntime, options) {
254
267
  let timeCost;
255
268
  let requestId;
256
269
  let responseModelName;
270
+ let usageReported = false;
257
271
  const hasUsableText = (value)=>'string' == typeof value && value.trim().length > 0;
258
272
  const resolveContentWithReasoningFallback = (contentValue, reasoningContent)=>{
259
273
  if (!hasUsableText(contentValue) && adapter.chatCompletion.useReasoningAsContentFallback && hasUsableText(reasoningContent)) {
@@ -277,7 +291,8 @@ async function callAI(messages, modelRuntime, options) {
277
291
  response_model_name: responseModelName,
278
292
  slot: modelConfig.slot,
279
293
  intent: void 0,
280
- request_id: requestId ?? void 0
294
+ request_id: requestId ?? void 0,
295
+ [INTERNAL_CALL_ID_FIELD]: internalCallId
281
296
  };
282
297
  };
283
298
  const requestConfig = {
@@ -351,12 +366,17 @@ async function callAI(messages, modelRuntime, options) {
351
366
  }
352
367
  const finalAccumulated = resolveContentWithReasoningFallback(accumulated, accumulatedReasoning);
353
368
  accumulated = finalAccumulated || '';
369
+ const finalUsage = buildUsageInfo(usage, requestId);
370
+ if (finalUsage && modelRuntime.onUsage) {
371
+ modelRuntime.onUsage(finalUsage);
372
+ usageReported = true;
373
+ }
354
374
  const finalChunk = {
355
375
  content: '',
356
376
  accumulated,
357
377
  reasoning_content: '',
358
378
  isComplete: true,
359
- usage: buildUsageInfo(usage, requestId)
379
+ usage: finalUsage
360
380
  };
361
381
  options.onChunk(finalChunk);
362
382
  break;
@@ -396,7 +416,11 @@ async function callAI(messages, modelRuntime, options) {
396
416
  requestId = result._request_id;
397
417
  responseModelName = result.model;
398
418
  content = resolveContentWithReasoningFallback(content, accumulatedReasoning);
399
- if (!hasUsableText(content)) throw new AIResponseParseError('empty content from AI model', JSON.stringify(result), buildUsageInfo(usage, requestId), rawChoiceMessage);
419
+ if (!hasUsableText(content)) {
420
+ const errorUsage = buildUsageInfo(usage, requestId);
421
+ if (errorUsage && modelRuntime.onUsage) modelRuntime.onUsage(errorUsage);
422
+ throw new AIResponseParseError('empty content from AI model', content || '', errorUsage, rawChoiceMessage);
423
+ }
400
424
  break;
401
425
  } catch (error) {
402
426
  lastError = toError(error);
@@ -430,11 +454,13 @@ async function callAI(messages, modelRuntime, options) {
430
454
  total_tokens: 2 * estimatedTokens
431
455
  };
432
456
  }
457
+ const finalUsage = buildUsageInfo(usage, requestId);
458
+ if (!usageReported && finalUsage && modelRuntime.onUsage) modelRuntime.onUsage(finalUsage);
433
459
  return {
434
460
  content: content || '',
435
461
  reasoning_content: accumulatedReasoning || void 0,
436
462
  rawChoiceMessage,
437
- usage: buildUsageInfo(usage, requestId),
463
+ usage: finalUsage,
438
464
  isStreamed: !!isStreaming
439
465
  };
440
466
  } catch (e) {
@@ -446,8 +472,7 @@ async function callAI(messages, modelRuntime, options) {
446
472
  throw newError;
447
473
  }
448
474
  }
449
- async function callAIWithObjectResponse(messages, model, options) {
450
- const modelRuntime = resolveCompatibleModelRuntime(model);
475
+ async function callAIWithObjectResponse(messages, modelRuntime, options) {
451
476
  const { config: modelConfig, adapter } = modelRuntime;
452
477
  const response = await callAI(messages, modelRuntime, {
453
478
  abortSignal: options?.abortSignal
@@ -471,10 +496,6 @@ async function callAIWithObjectResponse(messages, model, options) {
471
496
  rawChoiceMessage: response.rawChoiceMessage
472
497
  };
473
498
  }
474
- function resolveCompatibleModelRuntime(model) {
475
- if ('config' in model && 'adapter' in model) return model;
476
- return (0, index_js_namespaceObject.getModelRuntime)(model);
477
- }
478
499
  async function callAIWithStringResponse(msgs, modelRuntime, options) {
479
500
  const { content, usage, rawChoiceMessage } = await callAI(msgs, modelRuntime, options);
480
501
  return {
@@ -484,22 +505,22 @@ async function callAIWithStringResponse(msgs, modelRuntime, options) {
484
505
  };
485
506
  }
486
507
  exports.AIResponseParseError = __webpack_exports__.AIResponseParseError;
508
+ exports.INTERNAL_CALL_ID_FIELD = __webpack_exports__.INTERNAL_CALL_ID_FIELD;
487
509
  exports.callAI = __webpack_exports__.callAI;
488
510
  exports.callAIWithObjectResponse = __webpack_exports__.callAIWithObjectResponse;
489
511
  exports.callAIWithStringResponse = __webpack_exports__.callAIWithStringResponse;
490
512
  exports.createChatClient = __webpack_exports__.createChatClient;
491
513
  exports.extractJSONFromCodeBlock = __webpack_exports__.extractJSONFromCodeBlock;
492
- exports.normalJsonParser = __webpack_exports__.normalJsonParser;
493
- exports.safeParseJson = __webpack_exports__.safeParseJson;
514
+ exports.parseModelResponseJson = __webpack_exports__.parseModelResponseJson;
494
515
  for(var __rspack_i in __webpack_exports__)if (-1 === [
495
516
  "AIResponseParseError",
517
+ "INTERNAL_CALL_ID_FIELD",
496
518
  "callAI",
497
519
  "callAIWithObjectResponse",
498
520
  "callAIWithStringResponse",
499
521
  "createChatClient",
500
522
  "extractJSONFromCodeBlock",
501
- "normalJsonParser",
502
- "safeParseJson"
523
+ "parseModelResponseJson"
503
524
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
504
525
  Object.defineProperty(exports, '__esModule', {
505
526
  value: true
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/service-caller/index.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../src/ai-model/service-caller/index.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { AIUsageInfo } from '@/types';\nimport type { CodeGenerationChunk, StreamingCallback } from '@/types';\n\n// Error class that preserves usage and rawResponse when AI call parsing fails\nexport class AIResponseParseError extends Error {\n usage?: AIUsageInfo;\n /**\n * Adapter-extracted content used by Midscene for parsing. This is not the\n * full provider response or choices[0].message.\n */\n rawResponse: string;\n rawChoiceMessage?: unknown;\n\n constructor(\n message: string,\n rawResponse: string,\n usage?: AIUsageInfo,\n rawChoiceMessage?: unknown,\n ) {\n super(message);\n this.name = 'AIResponseParseError';\n this.rawResponse = rawResponse;\n this.usage = usage;\n this.rawChoiceMessage = rawChoiceMessage;\n }\n}\nimport {\n type IModelConfig,\n MIDSCENE_LANGFUSE_DEBUG,\n MIDSCENE_LANGSMITH_DEBUG,\n type TModelFamily,\n globalConfigManager,\n} from '@midscene/shared/env';\n\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser } from '@midscene/shared/utils';\nimport OpenAI from 'openai';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport type { Stream } from 'openai/streaming';\nimport { type ModelRuntime, getModelRuntime } from '../models';\nimport type { AIArgs } from '../types';\nimport {\n callAIWithCodexAppServer,\n isCodexAppServerProvider,\n} from './codex-app-server';\nimport type { JsonParserSource } from './json';\nimport {\n type OpenAIErrorResponseContext,\n formatOpenAIAPIErrorDetails,\n wrapOpenAICompatibleFetch,\n} from './openai-error';\nimport {\n buildRequestAbortSignal,\n isHardTimeoutError,\n resolveEffectiveTimeoutMs,\n} from './request-timeout';\nexport {\n extractJSONFromCodeBlock,\n normalJsonParser,\n safeParseJson,\n} from './json';\nexport type { JsonParser } from './json';\n\nfunction stringifyForDebug(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch (_error) {\n return String(value);\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nfunction normalizeRetryCount(retryCount: unknown): number {\n if (typeof retryCount !== 'number' || !Number.isFinite(retryCount)) {\n return 1;\n }\n\n return Math.max(0, Math.floor(retryCount));\n}\n\nfunction appendAIRequestFailureSummary<T extends Error>(\n error: T,\n attemptErrors: Array<{ attempt: number; error: unknown }>,\n maxAttempts: number,\n): T {\n const failedAttempts = attemptErrors.length;\n const retries = Math.max(0, failedAttempts - 1);\n const retryLabel = retries === 1 ? 'retry' : 'retries';\n const originalMessage = error.message;\n const previousAttemptErrors = attemptErrors.slice(0, -1);\n\n error.message = `AI model request failed after ${retries} ${retryLabel} (${failedAttempts}/${maxAttempts} attempts). Last error: ${originalMessage}`;\n\n if (previousAttemptErrors.length === 0) {\n return error;\n }\n\n const details = previousAttemptErrors\n .map(\n ({ attempt, error }) => `Attempt ${attempt}: ${getErrorMessage(error)}`,\n )\n .join('\\n');\n\n error.message = `${error.message}\\nPrevious AI call attempt errors:\\n${details}`;\n return error;\n}\n\nexport async function createChatClient({\n modelConfig,\n}: {\n modelConfig: IModelConfig;\n}): Promise<{\n completion: OpenAI.Chat.Completions;\n modelName: string;\n modelDescription: string;\n modelFamily: TModelFamily | undefined;\n openAIErrorResponseContext: OpenAIErrorResponseContext;\n}> {\n const {\n socksProxy,\n httpProxy,\n modelName,\n openaiBaseURL,\n openaiApiKey,\n openaiExtraConfig,\n modelDescription,\n modelFamily,\n createOpenAIClient,\n timeout,\n } = modelConfig;\n\n let proxyAgent: any = undefined;\n const warnClient = getDebug('ai:call', { console: true });\n const debugProxy = getDebug('ai:call:proxy');\n const warnProxy = getDebug('ai:call:proxy', { console: true });\n\n // Helper function to sanitize proxy URL for logging (remove credentials)\n // Uses URL API instead of regex to avoid ReDoS vulnerabilities\n const sanitizeProxyUrl = (url: string): string => {\n try {\n const parsed = new URL(url);\n if (parsed.username) {\n // Keep username for debugging, hide password for security\n parsed.password = '****';\n return parsed.href;\n }\n return url;\n } catch {\n // If URL parsing fails, return original URL (will be caught later)\n return url;\n }\n };\n\n if (httpProxy) {\n debugProxy('using http proxy', sanitizeProxyUrl(httpProxy));\n if (ifInBrowser) {\n warnProxy(\n 'HTTP proxy is configured but not supported in browser environment',\n );\n } else {\n // Dynamic import with variable to avoid bundler static analysis\n const moduleName = 'undici';\n const { ProxyAgent } = await import(moduleName);\n proxyAgent = new ProxyAgent({\n uri: httpProxy,\n // Note: authentication is handled via the URI (e.g., http://user:pass@proxy.com:8080)\n });\n }\n } else if (socksProxy) {\n debugProxy('using socks proxy', sanitizeProxyUrl(socksProxy));\n if (ifInBrowser) {\n warnProxy(\n 'SOCKS proxy is configured but not supported in browser environment',\n );\n } else {\n try {\n // Dynamic import with variable to avoid bundler static analysis\n const moduleName = 'fetch-socks';\n const { socksDispatcher } = await import(moduleName);\n // Parse SOCKS proxy URL (e.g., socks5://127.0.0.1:1080)\n const proxyUrl = new URL(socksProxy);\n\n // Validate hostname\n if (!proxyUrl.hostname) {\n throw new Error('SOCKS proxy URL must include a valid hostname');\n }\n\n // Validate and parse port\n const port = Number.parseInt(proxyUrl.port, 10);\n if (!proxyUrl.port || Number.isNaN(port)) {\n throw new Error('SOCKS proxy URL must include a valid port');\n }\n\n // Parse SOCKS version from protocol\n const protocol = proxyUrl.protocol.replace(':', '');\n const socksType =\n protocol === 'socks4' ? 4 : protocol === 'socks5' ? 5 : 5;\n\n proxyAgent = socksDispatcher({\n type: socksType,\n host: proxyUrl.hostname,\n port,\n ...(proxyUrl.username\n ? {\n userId: decodeURIComponent(proxyUrl.username),\n password: decodeURIComponent(proxyUrl.password || ''),\n }\n : {}),\n });\n debugProxy('socks proxy configured successfully', {\n type: socksType,\n host: proxyUrl.hostname,\n port: port,\n });\n } catch (error) {\n warnProxy('Failed to configure SOCKS proxy:', error);\n throw new Error(\n `Invalid SOCKS proxy URL: ${socksProxy}. Expected format: socks4://host:port, socks5://host:port, or with authentication: socks5://user:pass@host:port`,\n );\n }\n }\n }\n\n const effectiveTimeoutMs = resolveEffectiveTimeoutMs({ timeout });\n const openAIErrorResponseContext: OpenAIErrorResponseContext = {};\n const openAIOptions = {\n baseURL: openaiBaseURL,\n apiKey: openaiApiKey,\n // Use fetchOptions.dispatcher for fetch-based SDK instead of httpAgent\n // Note: Type assertion needed due to undici version mismatch between dependencies\n ...(proxyAgent ? { fetchOptions: { dispatcher: proxyAgent as any } } : {}),\n ...openaiExtraConfig,\n fetch: wrapOpenAICompatibleFetch(openAIErrorResponseContext),\n // Midscene already handles retries in callAI(), so disable SDK-level retries\n // to avoid duplicate attempts and duplicated backoff latency.\n maxRetries: 0,\n // When disabled (timeoutMs === null) fall through to the SDK default so\n // only the caller-provided abortSignal can cancel the request.\n ...(effectiveTimeoutMs !== null ? { timeout: effectiveTimeoutMs } : {}),\n dangerouslyAllowBrowser: true,\n };\n\n const baseOpenAI = new OpenAI(openAIOptions);\n\n let openai: OpenAI = baseOpenAI;\n\n // LangSmith wrapper\n if (\n openai &&\n globalConfigManager.getEnvConfigInBoolean(MIDSCENE_LANGSMITH_DEBUG)\n ) {\n if (ifInBrowser) {\n throw new Error('langsmith is not supported in browser');\n }\n warnClient('DEBUGGING MODE: langsmith wrapper enabled');\n // Use variable to prevent static analysis by bundlers\n const langsmithModule = 'langsmith/wrappers';\n const { wrapOpenAI } = await import(langsmithModule);\n openai = wrapOpenAI(openai);\n }\n\n // Langfuse wrapper\n if (\n openai &&\n globalConfigManager.getEnvConfigInBoolean(MIDSCENE_LANGFUSE_DEBUG)\n ) {\n if (ifInBrowser) {\n throw new Error('langfuse is not supported in browser');\n }\n warnClient('DEBUGGING MODE: langfuse wrapper enabled');\n // Use variable to prevent static analysis by bundlers\n const langfuseModule = '@langfuse/openai';\n const { observeOpenAI } = await import(langfuseModule);\n openai = observeOpenAI(openai);\n }\n\n if (createOpenAIClient) {\n const wrappedClient = await createOpenAIClient(baseOpenAI, openAIOptions);\n\n if (wrappedClient) {\n openai = wrappedClient as OpenAI;\n }\n }\n\n return {\n completion: openai.chat.completions,\n modelName,\n modelDescription,\n modelFamily,\n openAIErrorResponseContext,\n };\n}\n\ninterface CallAIOptions {\n stream?: boolean;\n onChunk?: StreamingCallback;\n abortSignal?: AbortSignal;\n requiresOriginalImageDetail?: boolean;\n}\n\nexport async function callAI(\n messages: ChatCompletionMessageParam[],\n modelRuntime: ModelRuntime,\n options?: CallAIOptions,\n): Promise<{\n content: string;\n reasoning_content?: string;\n rawChoiceMessage?: unknown;\n usage?: AIUsageInfo;\n isStreamed: boolean;\n}> {\n const { config: modelConfig, adapter } = modelRuntime;\n\n if (isCodexAppServerProvider(modelConfig.openaiBaseURL)) {\n return callAIWithCodexAppServer(messages, modelConfig, {\n stream: options?.stream,\n onChunk: options?.onChunk,\n reasoningEnabled: modelConfig.reasoningEnabled,\n abortSignal: options?.abortSignal,\n });\n }\n\n const {\n completion,\n modelName,\n modelDescription,\n modelFamily,\n openAIErrorResponseContext,\n } = await createChatClient({\n modelConfig,\n });\n const effectiveTimeoutMs = resolveEffectiveTimeoutMs(modelConfig);\n\n const extraBody = modelConfig.extraBody;\n\n const debugCall = getDebug('ai:call');\n const warnCall = getDebug('ai:call', { console: true });\n const debugProfileStats = getDebug('ai:profile:stats');\n const debugProfileDetail = getDebug('ai:profile:detail');\n\n const startTime = Date.now();\n\n const isStreaming = options?.stream && options?.onChunk;\n const chatCompletionInput = {\n intent: modelConfig.intent,\n userConfig: {\n temperature: modelConfig.temperature,\n reasoningEnabled: modelConfig.reasoningEnabled,\n reasoningEffort: modelConfig.reasoningEffort,\n reasoningBudget: modelConfig.reasoningBudget,\n },\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n };\n const { config: adapterChatCompletionParams } =\n adapter.chatCompletion.buildChatCompletionParams(chatCompletionInput);\n debugCall(\n `adapter chat completion params: ${stringifyForDebug({\n config: adapterChatCompletionParams,\n })}`,\n );\n let content: string | undefined;\n let accumulated = '';\n let accumulatedReasoning = '';\n let rawChoiceMessage: unknown;\n let usage: OpenAI.CompletionUsage | undefined;\n let timeCost: number | undefined;\n let requestId: string | null | undefined;\n let responseModelName: string | undefined;\n\n const hasUsableText = (value: string | null | undefined): value is string =>\n typeof value === 'string' && value.trim().length > 0;\n\n const resolveContentWithReasoningFallback = (\n contentValue: string | undefined,\n reasoningContent: string,\n ) => {\n if (\n !hasUsableText(contentValue) &&\n adapter.chatCompletion.useReasoningAsContentFallback &&\n hasUsableText(reasoningContent)\n ) {\n warnCall('empty content from AI model, using reasoning content');\n return reasoningContent;\n }\n\n return contentValue;\n };\n\n const buildUsageInfo = (\n usageData?: OpenAI.CompletionUsage,\n requestId?: string | null,\n ) => {\n if (!usageData) return undefined;\n\n const cachedInputTokens = (\n usageData as { prompt_tokens_details?: { cached_tokens?: number } }\n )?.prompt_tokens_details?.cached_tokens;\n\n return {\n ...usageData,\n prompt_tokens: usageData.prompt_tokens ?? 0,\n completion_tokens: usageData.completion_tokens ?? 0,\n total_tokens: usageData.total_tokens ?? 0,\n cached_input: cachedInputTokens ?? 0,\n time_cost: timeCost ?? 0,\n model_name: modelName,\n model_description: modelDescription,\n response_model_name: responseModelName,\n slot: modelConfig.slot,\n // Agent task layers fill semantic intent after the raw model call.\n intent: undefined,\n request_id: requestId ?? undefined,\n } satisfies AIUsageInfo;\n };\n\n const requestConfig = {\n ...adapterChatCompletionParams,\n ...(extraBody ?? {}),\n };\n const temperature = requestConfig.temperature;\n\n const imageDetail =\n adapter.chatCompletion.resolveImageDetail(chatCompletionInput);\n\n // Some adapters request original image detail to preserve screenshot\n // resolution for localization-sensitive tasks.\n const messagesWithImageDetail: ChatCompletionMessageParam[] = (() => {\n if (!imageDetail) {\n return messages;\n }\n\n return messages.map((msg) => {\n if (!Array.isArray(msg.content)) {\n return msg;\n }\n\n const content = msg.content.map((part) => {\n if (part && part.type === 'image_url' && part.image_url?.url) {\n return {\n ...part,\n image_url: {\n ...part.image_url,\n detail: imageDetail,\n },\n };\n }\n return part;\n });\n\n return {\n ...msg,\n content,\n } as ChatCompletionMessageParam;\n });\n })();\n\n try {\n debugCall(\n `sending ${isStreaming ? 'streaming ' : ''}request to ${modelName}`,\n );\n\n if (isStreaming) {\n const { signal: streamSignal, cleanup: cleanupStreamSignal } =\n buildRequestAbortSignal(effectiveTimeoutMs, options?.abortSignal);\n try {\n const stream = (await completion.create(\n {\n model: modelName,\n messages: messagesWithImageDetail,\n ...requestConfig,\n stream: true,\n },\n {\n stream: true,\n signal: streamSignal,\n },\n )) as Stream<OpenAI.Chat.Completions.ChatCompletionChunk> & {\n _request_id?: string | null;\n };\n\n requestId = stream._request_id;\n\n for await (const chunk of stream) {\n const parsedChunk = adapter.chatCompletion.extractContentAndReasoning(\n chunk.choices?.[0]?.delta,\n );\n const content = parsedChunk.content || '';\n const reasoning_content = parsedChunk.reasoning_content || '';\n\n // Check for usage info in any chunk (OpenAI provides usage in separate chunks)\n if (chunk.usage) {\n usage = chunk.usage;\n }\n if (chunk.model) {\n responseModelName = chunk.model;\n }\n\n if (content || reasoning_content) {\n accumulated += content;\n accumulatedReasoning += reasoning_content;\n const chunkData: CodeGenerationChunk = {\n content,\n reasoning_content,\n accumulated,\n isComplete: false,\n usage: undefined,\n };\n options.onChunk!(chunkData);\n }\n\n // Check if stream is complete\n if (chunk.choices?.[0]?.finish_reason) {\n timeCost = Date.now() - startTime;\n\n // If usage is not available from the stream, provide a basic usage info\n if (!usage) {\n // Estimate token counts based on content length (rough approximation)\n const estimatedTokens = Math.max(\n 1,\n Math.floor(accumulated.length / 4),\n );\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: estimatedTokens * 2,\n };\n }\n\n const finalAccumulated = resolveContentWithReasoningFallback(\n accumulated,\n accumulatedReasoning,\n );\n accumulated = finalAccumulated || '';\n\n // Send final chunk\n const finalChunk: CodeGenerationChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: buildUsageInfo(usage, requestId),\n };\n options.onChunk!(finalChunk);\n break;\n }\n }\n } finally {\n cleanupStreamSignal();\n }\n content = accumulated;\n debugProfileStats(\n `streaming model, ${modelName}, mode, ${modelFamily || 'default'}, cost-ms, ${timeCost}, temperature, ${temperature ?? ''}`,\n );\n } else {\n // Non-streaming with retry logic\n const retryCount = normalizeRetryCount(modelConfig.retryCount);\n const retryInterval = modelConfig.retryInterval ?? 2000;\n const maxAttempts = retryCount + 1; // retryCount=1 means 2 total attempts (1 initial + 1 retry)\n\n let lastError: Error | undefined;\n const attemptErrors: Array<{ attempt: number; error: unknown }> = [];\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const { signal: attemptSignal, cleanup: cleanupAttemptSignal } =\n buildRequestAbortSignal(effectiveTimeoutMs, options?.abortSignal);\n try {\n const result = await completion.create(\n {\n model: modelName,\n messages: messagesWithImageDetail,\n ...requestConfig,\n stream: false,\n } as any,\n { signal: attemptSignal },\n );\n\n timeCost = Date.now() - startTime;\n\n debugProfileStats(\n `model, ${modelName}, mode, ${modelFamily || 'default'}, prompt-tokens, ${result.usage?.prompt_tokens || ''}, completion-tokens, ${result.usage?.completion_tokens || ''}, total-tokens, ${result.usage?.total_tokens || ''}, cost-ms, ${timeCost}, requestId, ${result._request_id || ''}, temperature, ${temperature ?? ''}`,\n );\n\n debugProfileDetail(\n `model usage detail: ${JSON.stringify(result.usage)}`,\n );\n\n if (!result.choices) {\n throw new Error(\n `invalid response from LLM service: ${JSON.stringify(result)}`,\n );\n }\n\n rawChoiceMessage = result.choices[0].message;\n const parsedMessage =\n adapter.chatCompletion.extractContentAndReasoning(\n result.choices[0].message,\n );\n content = parsedMessage.content;\n accumulatedReasoning = parsedMessage.reasoning_content;\n usage = result.usage;\n requestId = result._request_id;\n responseModelName = result.model;\n\n content = resolveContentWithReasoningFallback(\n content,\n accumulatedReasoning,\n );\n\n if (!hasUsableText(content)) {\n throw new AIResponseParseError(\n 'empty content from AI model',\n JSON.stringify(result),\n buildUsageInfo(usage, requestId),\n rawChoiceMessage,\n );\n }\n\n break; // Success, exit retry loop\n } catch (error) {\n lastError = toError(error);\n attemptErrors.push({ attempt, error });\n const wasHardTimeout = isHardTimeoutError(lastError);\n if (wasHardTimeout) {\n warnCall(\n `AI call hit hard timeout (${effectiveTimeoutMs}ms, attempt ${attempt}/${maxAttempts}, model ${modelName}, slot ${modelConfig.slot})`,\n );\n }\n // Do not retry if the request was aborted by the caller\n if (options?.abortSignal?.aborted) {\n break;\n }\n if (attempt < maxAttempts) {\n warnCall(\n `AI call failed (attempt ${attempt}/${maxAttempts}), retrying in ${retryInterval}ms... Error: ${lastError.message}`,\n );\n await new Promise((resolve) => setTimeout(resolve, retryInterval));\n }\n } finally {\n cleanupAttemptSignal();\n }\n }\n\n if (!content) {\n assert(\n lastError,\n 'AI model request failed without recording an attempt error',\n );\n throw appendAIRequestFailureSummary(\n lastError,\n attemptErrors,\n maxAttempts,\n );\n }\n }\n\n debugCall(`response reasoning content: ${accumulatedReasoning}`);\n debugCall(`response content: ${content}`);\n\n // Ensure we always have usage info for streaming responses\n if (isStreaming && !usage) {\n // Estimate token counts based on content length (rough approximation)\n const estimatedTokens = Math.max(\n 1,\n Math.floor((content || '').length / 4),\n );\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: estimatedTokens * 2,\n } as OpenAI.CompletionUsage;\n }\n\n return {\n content: content || '',\n reasoning_content: accumulatedReasoning || undefined,\n rawChoiceMessage,\n usage: buildUsageInfo(usage, requestId),\n isStreamed: !!isStreaming,\n };\n } catch (e: any) {\n warnCall('call AI error', e);\n\n if (e instanceof AIResponseParseError) {\n throw e;\n }\n\n const newError = new Error(\n `failed to call ${isStreaming ? 'streaming ' : ''}AI model service (${modelName}): ${e.message}${formatOpenAIAPIErrorDetails(e, openAIErrorResponseContext)}\\nTrouble shooting: https://midscenejs.com/model-provider.html`,\n {\n cause: e,\n },\n );\n throw newError;\n }\n}\n\nexport async function callAIWithObjectResponse<T>(\n messages: ChatCompletionMessageParam[],\n // Keep IModelConfig compatibility for midscene-example/connectivity-test/tests/connectivity.test.ts; internal workflow callers should pass ModelRuntime instead.\n model: IModelConfig | ModelRuntime,\n options?: {\n abortSignal?: AbortSignal;\n jsonParserSource?: JsonParserSource;\n },\n): Promise<{\n // TODO: `content` is a misleading name here because this is already the parsed object response. Consider renaming it to `object` or `data`.\n content: T;\n contentString: string;\n usage?: AIUsageInfo;\n reasoning_content?: string;\n rawChoiceMessage?: unknown;\n}> {\n const modelRuntime = resolveCompatibleModelRuntime(model);\n const { config: modelConfig, adapter } = modelRuntime;\n const response = await callAI(messages, modelRuntime, {\n abortSignal: options?.abortSignal,\n });\n assert(response, 'empty response');\n let jsonContent: unknown;\n try {\n jsonContent = adapter.jsonParser(response.content, {\n source: options?.jsonParserSource ?? 'generic-object',\n });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new AIResponseParseError(\n errorMessage,\n response.content,\n response.usage,\n );\n }\n if (typeof jsonContent !== 'object') {\n throw new AIResponseParseError(\n `failed to parse json response from model (${modelConfig.modelName}): ${response.content}`,\n response.content,\n response.usage,\n response.rawChoiceMessage,\n );\n }\n return {\n content: jsonContent as T,\n contentString: response.content,\n usage: response.usage,\n reasoning_content: response.reasoning_content,\n rawChoiceMessage: response.rawChoiceMessage,\n };\n}\n\nfunction resolveCompatibleModelRuntime(\n model: IModelConfig | ModelRuntime,\n): ModelRuntime {\n if ('config' in model && 'adapter' in model) {\n return model;\n }\n\n return getModelRuntime(model);\n}\n\nexport async function callAIWithStringResponse(\n msgs: AIArgs,\n modelRuntime: ModelRuntime,\n options?: Pick<CallAIOptions, 'abortSignal' | 'requiresOriginalImageDetail'>,\n): Promise<{\n content: string;\n usage?: AIUsageInfo;\n rawChoiceMessage?: unknown;\n}> {\n const { content, usage, rawChoiceMessage } = await callAI(\n msgs,\n modelRuntime,\n options,\n );\n return { content, usage, rawChoiceMessage };\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","AIResponseParseError","Error","message","rawResponse","usage","rawChoiceMessage","stringifyForDebug","value","JSON","_error","String","getErrorMessage","error","toError","normalizeRetryCount","retryCount","Number","Math","appendAIRequestFailureSummary","attemptErrors","maxAttempts","failedAttempts","retries","retryLabel","originalMessage","previousAttemptErrors","details","attempt","createChatClient","modelConfig","socksProxy","httpProxy","modelName","openaiBaseURL","openaiApiKey","openaiExtraConfig","modelDescription","modelFamily","createOpenAIClient","timeout","proxyAgent","warnClient","getDebug","debugProxy","warnProxy","sanitizeProxyUrl","url","parsed","URL","ifInBrowser","moduleName","ProxyAgent","socksDispatcher","proxyUrl","port","protocol","socksType","decodeURIComponent","effectiveTimeoutMs","resolveEffectiveTimeoutMs","openAIErrorResponseContext","openAIOptions","wrapOpenAICompatibleFetch","baseOpenAI","OpenAI","openai","globalConfigManager","MIDSCENE_LANGSMITH_DEBUG","langsmithModule","wrapOpenAI","MIDSCENE_LANGFUSE_DEBUG","langfuseModule","observeOpenAI","wrappedClient","callAI","messages","modelRuntime","options","adapter","isCodexAppServerProvider","callAIWithCodexAppServer","completion","extraBody","debugCall","warnCall","debugProfileStats","debugProfileDetail","startTime","Date","isStreaming","chatCompletionInput","adapterChatCompletionParams","content","accumulated","accumulatedReasoning","timeCost","requestId","responseModelName","hasUsableText","resolveContentWithReasoningFallback","contentValue","reasoningContent","buildUsageInfo","usageData","cachedInputTokens","undefined","requestConfig","temperature","imageDetail","messagesWithImageDetail","msg","Array","part","streamSignal","cleanupStreamSignal","buildRequestAbortSignal","stream","chunk","parsedChunk","reasoning_content","chunkData","estimatedTokens","finalAccumulated","finalChunk","retryInterval","lastError","attemptSignal","cleanupAttemptSignal","result","parsedMessage","wasHardTimeout","isHardTimeoutError","Promise","resolve","setTimeout","assert","e","newError","formatOpenAIAPIErrorDetails","callAIWithObjectResponse","model","resolveCompatibleModelRuntime","response","jsonContent","errorMessage","getModelRuntime","callAIWithStringResponse","msgs"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/service-caller/index.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../src/ai-model/service-caller/index.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { AIUsageInfo } from '@/types';\nimport type { CodeGenerationChunk, StreamingCallback } from '@/types';\n\n// Error class that preserves usage and rawResponse when AI call parsing fails\nexport class AIResponseParseError extends Error {\n usage?: AIUsageInfo;\n /**\n * Adapter-extracted content used by Midscene for parsing. This is not the\n * full provider response or choices[0].message.\n */\n rawResponse: string;\n rawChoiceMessage?: unknown;\n\n constructor(\n message: string,\n rawResponse: string,\n usage?: AIUsageInfo,\n rawChoiceMessage?: unknown,\n ) {\n super(message);\n this.name = 'AIResponseParseError';\n this.rawResponse = rawResponse;\n this.usage = usage;\n this.rawChoiceMessage = rawChoiceMessage;\n }\n}\nimport {\n type IModelConfig,\n MIDSCENE_LANGFUSE_DEBUG,\n MIDSCENE_LANGSMITH_DEBUG,\n type TModelFamily,\n globalConfigManager,\n} from '@midscene/shared/env';\n\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser } from '@midscene/shared/utils';\nimport OpenAI from 'openai';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport type { Stream } from 'openai/streaming';\nimport type { ModelRuntime } from '../models';\nimport type { AIArgs } from '../types';\nimport {\n callAIWithCodexAppServer,\n isCodexAppServerProvider,\n} from './codex-app-server';\nimport type { JsonParserSource } from './json';\nimport {\n type OpenAIErrorResponseContext,\n formatOpenAIAPIErrorDetails,\n wrapOpenAICompatibleFetch,\n} from './openai-error';\nimport {\n buildRequestAbortSignal,\n isHardTimeoutError,\n resolveEffectiveTimeoutMs,\n} from './request-timeout';\nexport {\n extractJSONFromCodeBlock,\n parseModelResponseJson,\n} from './json';\nexport type { JsonParser } from './json';\n\n/**\n * Internal field name stamped onto every AIUsageInfo shaped by callAI().\n * Used for cross-path dedup when the provider does not return a request_id.\n */\nexport const INTERNAL_CALL_ID_FIELD = '_midscene_call_id';\n\nlet internalCallIdCounter = 0;\nfunction nextInternalCallId(): string {\n internalCallIdCounter += 1;\n return `call_${internalCallIdCounter}`;\n}\n\nfunction stringifyForDebug(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch (_error) {\n return String(value);\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nfunction normalizeRetryCount(retryCount: unknown): number {\n if (typeof retryCount !== 'number' || !Number.isFinite(retryCount)) {\n return 1;\n }\n\n return Math.max(0, Math.floor(retryCount));\n}\n\nfunction appendAIRequestFailureSummary<T extends Error>(\n error: T,\n attemptErrors: Array<{ attempt: number; error: unknown }>,\n maxAttempts: number,\n): T {\n const failedAttempts = attemptErrors.length;\n const retries = Math.max(0, failedAttempts - 1);\n const retryLabel = retries === 1 ? 'retry' : 'retries';\n const originalMessage = error.message;\n const previousAttemptErrors = attemptErrors.slice(0, -1);\n\n error.message = `AI model request failed after ${retries} ${retryLabel} (${failedAttempts}/${maxAttempts} attempts). Last error: ${originalMessage}`;\n\n if (previousAttemptErrors.length === 0) {\n return error;\n }\n\n const details = previousAttemptErrors\n .map(\n ({ attempt, error }) => `Attempt ${attempt}: ${getErrorMessage(error)}`,\n )\n .join('\\n');\n\n error.message = `${error.message}\\nPrevious AI call attempt errors:\\n${details}`;\n return error;\n}\n\nexport async function createChatClient({\n modelConfig,\n}: {\n modelConfig: IModelConfig;\n}): Promise<{\n completion: OpenAI.Chat.Completions;\n modelName: string;\n modelDescription: string;\n modelFamily: TModelFamily | undefined;\n openAIErrorResponseContext: OpenAIErrorResponseContext;\n}> {\n const {\n socksProxy,\n httpProxy,\n modelName,\n openaiBaseURL,\n openaiApiKey,\n openaiExtraConfig,\n modelDescription,\n modelFamily,\n createOpenAIClient,\n timeout,\n } = modelConfig;\n\n let proxyAgent: any = undefined;\n const warnClient = getDebug('ai:call', { console: true });\n const debugProxy = getDebug('ai:call:proxy');\n const warnProxy = getDebug('ai:call:proxy', { console: true });\n\n // Helper function to sanitize proxy URL for logging (remove credentials)\n // Uses URL API instead of regex to avoid ReDoS vulnerabilities\n const sanitizeProxyUrl = (url: string): string => {\n try {\n const parsed = new URL(url);\n if (parsed.username) {\n // Keep username for debugging, hide password for security\n parsed.password = '****';\n return parsed.href;\n }\n return url;\n } catch {\n // If URL parsing fails, return original URL (will be caught later)\n return url;\n }\n };\n\n if (httpProxy) {\n debugProxy('using http proxy', sanitizeProxyUrl(httpProxy));\n if (ifInBrowser) {\n warnProxy(\n 'HTTP proxy is configured but not supported in browser environment',\n );\n } else {\n // Dynamic import with variable to avoid bundler static analysis\n const moduleName = 'undici';\n const { ProxyAgent } = await import(moduleName);\n proxyAgent = new ProxyAgent({\n uri: httpProxy,\n // Note: authentication is handled via the URI (e.g., http://user:pass@proxy.com:8080)\n });\n }\n } else if (socksProxy) {\n debugProxy('using socks proxy', sanitizeProxyUrl(socksProxy));\n if (ifInBrowser) {\n warnProxy(\n 'SOCKS proxy is configured but not supported in browser environment',\n );\n } else {\n try {\n // Dynamic import with variable to avoid bundler static analysis\n const moduleName = 'fetch-socks';\n const { socksDispatcher } = await import(moduleName);\n // Parse SOCKS proxy URL (e.g., socks5://127.0.0.1:1080)\n const proxyUrl = new URL(socksProxy);\n\n // Validate hostname\n if (!proxyUrl.hostname) {\n throw new Error('SOCKS proxy URL must include a valid hostname');\n }\n\n // Validate and parse port\n const port = Number.parseInt(proxyUrl.port, 10);\n if (!proxyUrl.port || Number.isNaN(port)) {\n throw new Error('SOCKS proxy URL must include a valid port');\n }\n\n // Parse SOCKS version from protocol\n const protocol = proxyUrl.protocol.replace(':', '');\n const socksType =\n protocol === 'socks4' ? 4 : protocol === 'socks5' ? 5 : 5;\n\n proxyAgent = socksDispatcher({\n type: socksType,\n host: proxyUrl.hostname,\n port,\n ...(proxyUrl.username\n ? {\n userId: decodeURIComponent(proxyUrl.username),\n password: decodeURIComponent(proxyUrl.password || ''),\n }\n : {}),\n });\n debugProxy('socks proxy configured successfully', {\n type: socksType,\n host: proxyUrl.hostname,\n port: port,\n });\n } catch (error) {\n warnProxy('Failed to configure SOCKS proxy:', error);\n throw new Error(\n `Invalid SOCKS proxy URL: ${socksProxy}. Expected format: socks4://host:port, socks5://host:port, or with authentication: socks5://user:pass@host:port`,\n );\n }\n }\n }\n\n const effectiveTimeoutMs = resolveEffectiveTimeoutMs({ timeout });\n const openAIErrorResponseContext: OpenAIErrorResponseContext = {};\n const openAIOptions = {\n baseURL: openaiBaseURL,\n apiKey: openaiApiKey,\n // Use fetchOptions.dispatcher for fetch-based SDK instead of httpAgent\n // Note: Type assertion needed due to undici version mismatch between dependencies\n ...(proxyAgent ? { fetchOptions: { dispatcher: proxyAgent as any } } : {}),\n ...openaiExtraConfig,\n fetch: wrapOpenAICompatibleFetch(openAIErrorResponseContext),\n // Midscene already handles retries in callAI(), so disable SDK-level retries\n // to avoid duplicate attempts and duplicated backoff latency.\n maxRetries: 0,\n // When disabled (timeoutMs === null) fall through to the SDK default so\n // only the caller-provided abortSignal can cancel the request.\n ...(effectiveTimeoutMs !== null ? { timeout: effectiveTimeoutMs } : {}),\n dangerouslyAllowBrowser: true,\n };\n\n const baseOpenAI = new OpenAI(openAIOptions);\n\n let openai: OpenAI = baseOpenAI;\n\n // LangSmith wrapper\n if (\n openai &&\n globalConfigManager.getEnvConfigInBoolean(MIDSCENE_LANGSMITH_DEBUG)\n ) {\n if (ifInBrowser) {\n throw new Error('langsmith is not supported in browser');\n }\n warnClient('DEBUGGING MODE: langsmith wrapper enabled');\n // Use variable to prevent static analysis by bundlers\n const langsmithModule = 'langsmith/wrappers';\n const { wrapOpenAI } = await import(langsmithModule);\n openai = wrapOpenAI(openai);\n }\n\n // Langfuse wrapper\n if (\n openai &&\n globalConfigManager.getEnvConfigInBoolean(MIDSCENE_LANGFUSE_DEBUG)\n ) {\n if (ifInBrowser) {\n throw new Error('langfuse is not supported in browser');\n }\n warnClient('DEBUGGING MODE: langfuse wrapper enabled');\n // Use variable to prevent static analysis by bundlers\n const langfuseModule = '@langfuse/openai';\n const { observeOpenAI } = await import(langfuseModule);\n openai = observeOpenAI(openai);\n }\n\n if (createOpenAIClient) {\n const wrappedClient = await createOpenAIClient(baseOpenAI, openAIOptions);\n\n if (wrappedClient) {\n openai = wrappedClient as OpenAI;\n }\n }\n\n return {\n completion: openai.chat.completions,\n modelName,\n modelDescription,\n modelFamily,\n openAIErrorResponseContext,\n };\n}\n\ninterface CallAIOptions {\n stream?: boolean;\n onChunk?: StreamingCallback;\n abortSignal?: AbortSignal;\n requiresOriginalImageDetail?: boolean;\n}\n\nexport async function callAI(\n messages: ChatCompletionMessageParam[],\n modelRuntime: ModelRuntime,\n options?: CallAIOptions,\n): Promise<{\n content: string;\n reasoning_content?: string;\n rawChoiceMessage?: unknown;\n usage?: AIUsageInfo;\n isStreamed: boolean;\n}> {\n const { config: modelConfig, adapter } = modelRuntime;\n\n // Stable internal ID for this call, used by the agent to deduplicate usage\n // across the onUsage callback and the task-dump-based collectUsageMetrics()\n // path when the provider does not return a request_id.\n const internalCallId = nextInternalCallId();\n\n if (isCodexAppServerProvider(modelConfig.openaiBaseURL)) {\n const codexResult = await callAIWithCodexAppServer(messages, modelConfig, {\n stream: options?.stream,\n onChunk: options?.onChunk,\n reasoningEnabled: modelConfig.reasoningEnabled,\n abortSignal: options?.abortSignal,\n });\n if (codexResult.usage) {\n (codexResult.usage as any)[INTERNAL_CALL_ID_FIELD] = internalCallId;\n if (modelRuntime.onUsage) {\n modelRuntime.onUsage(codexResult.usage);\n }\n }\n return codexResult;\n }\n\n const {\n completion,\n modelName,\n modelDescription,\n modelFamily,\n openAIErrorResponseContext,\n } = await createChatClient({\n modelConfig,\n });\n const effectiveTimeoutMs = resolveEffectiveTimeoutMs(modelConfig);\n\n const extraBody = modelConfig.extraBody;\n\n const debugCall = getDebug('ai:call');\n const warnCall = getDebug('ai:call', { console: true });\n const debugProfileStats = getDebug('ai:profile:stats');\n const debugProfileDetail = getDebug('ai:profile:detail');\n\n const startTime = Date.now();\n\n const isStreaming = options?.stream && options?.onChunk;\n const chatCompletionInput = {\n intent: modelConfig.intent,\n userConfig: {\n temperature: modelConfig.temperature,\n reasoningEnabled: modelConfig.reasoningEnabled,\n reasoningEffort: modelConfig.reasoningEffort,\n reasoningBudget: modelConfig.reasoningBudget,\n },\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n };\n const { config: adapterChatCompletionParams } =\n adapter.chatCompletion.buildChatCompletionParams(chatCompletionInput);\n debugCall(\n `adapter chat completion params: ${stringifyForDebug({\n config: adapterChatCompletionParams,\n })}`,\n );\n let content: string | undefined;\n let accumulated = '';\n let accumulatedReasoning = '';\n let rawChoiceMessage: unknown;\n let usage: OpenAI.CompletionUsage | undefined;\n let timeCost: number | undefined;\n let requestId: string | null | undefined;\n let responseModelName: string | undefined;\n // Tracks whether onUsage has already been fired for this call (e.g. from\n // the streaming final-chunk handler), so the final return does not double-fire.\n let usageReported = false;\n\n const hasUsableText = (value: string | null | undefined): value is string =>\n typeof value === 'string' && value.trim().length > 0;\n\n const resolveContentWithReasoningFallback = (\n contentValue: string | undefined,\n reasoningContent: string,\n ) => {\n if (\n !hasUsableText(contentValue) &&\n adapter.chatCompletion.useReasoningAsContentFallback &&\n hasUsableText(reasoningContent)\n ) {\n warnCall('empty content from AI model, using reasoning content');\n return reasoningContent;\n }\n\n return contentValue;\n };\n\n const buildUsageInfo = (\n usageData?: OpenAI.CompletionUsage,\n requestId?: string | null,\n ) => {\n if (!usageData) return undefined;\n\n const cachedInputTokens = (\n usageData as { prompt_tokens_details?: { cached_tokens?: number } }\n )?.prompt_tokens_details?.cached_tokens;\n\n return {\n ...usageData,\n prompt_tokens: usageData.prompt_tokens ?? 0,\n completion_tokens: usageData.completion_tokens ?? 0,\n total_tokens: usageData.total_tokens ?? 0,\n cached_input: cachedInputTokens ?? 0,\n time_cost: timeCost ?? 0,\n model_name: modelName,\n model_description: modelDescription,\n response_model_name: responseModelName,\n slot: modelConfig.slot,\n // Left undefined at the raw call layer. The agent's onUsage callback\n // fills it from modelConfig.slot for metrics collection, and task\n // layers use withUsageIntent() to stamp a more specific semantic\n // intent (e.g. 'planning', 'insight') when attaching usage to tasks.\n intent: undefined,\n request_id: requestId ?? undefined,\n // Internal stable ID for cross-path dedup when request_id is absent.\n [INTERNAL_CALL_ID_FIELD]: internalCallId,\n } satisfies AIUsageInfo;\n };\n\n const requestConfig = {\n ...adapterChatCompletionParams,\n ...(extraBody ?? {}),\n };\n const temperature = requestConfig.temperature;\n\n const imageDetail =\n adapter.chatCompletion.resolveImageDetail(chatCompletionInput);\n\n // Some adapters request original image detail to preserve screenshot\n // resolution for localization-sensitive tasks.\n const messagesWithImageDetail: ChatCompletionMessageParam[] = (() => {\n if (!imageDetail) {\n return messages;\n }\n\n return messages.map((msg) => {\n if (!Array.isArray(msg.content)) {\n return msg;\n }\n\n const content = msg.content.map((part) => {\n if (part && part.type === 'image_url' && part.image_url?.url) {\n return {\n ...part,\n image_url: {\n ...part.image_url,\n detail: imageDetail,\n },\n };\n }\n return part;\n });\n\n return {\n ...msg,\n content,\n } as ChatCompletionMessageParam;\n });\n })();\n\n try {\n debugCall(\n `sending ${isStreaming ? 'streaming ' : ''}request to ${modelName}`,\n );\n\n if (isStreaming) {\n const { signal: streamSignal, cleanup: cleanupStreamSignal } =\n buildRequestAbortSignal(effectiveTimeoutMs, options?.abortSignal);\n try {\n const stream = (await completion.create(\n {\n model: modelName,\n messages: messagesWithImageDetail,\n ...requestConfig,\n stream: true,\n },\n {\n stream: true,\n signal: streamSignal,\n },\n )) as Stream<OpenAI.Chat.Completions.ChatCompletionChunk> & {\n _request_id?: string | null;\n };\n\n requestId = stream._request_id;\n\n for await (const chunk of stream) {\n const parsedChunk = adapter.chatCompletion.extractContentAndReasoning(\n chunk.choices?.[0]?.delta,\n );\n const content = parsedChunk.content || '';\n const reasoning_content = parsedChunk.reasoning_content || '';\n\n // Check for usage info in any chunk (OpenAI provides usage in separate chunks)\n if (chunk.usage) {\n usage = chunk.usage;\n }\n if (chunk.model) {\n responseModelName = chunk.model;\n }\n\n if (content || reasoning_content) {\n accumulated += content;\n accumulatedReasoning += reasoning_content;\n const chunkData: CodeGenerationChunk = {\n content,\n reasoning_content,\n accumulated,\n isComplete: false,\n usage: undefined,\n };\n options.onChunk!(chunkData);\n }\n\n // Check if stream is complete\n if (chunk.choices?.[0]?.finish_reason) {\n timeCost = Date.now() - startTime;\n\n // If usage is not available from the stream, provide a basic usage info\n if (!usage) {\n // Estimate token counts based on content length (rough approximation)\n const estimatedTokens = Math.max(\n 1,\n Math.floor(accumulated.length / 4),\n );\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: estimatedTokens * 2,\n };\n }\n\n const finalAccumulated = resolveContentWithReasoningFallback(\n accumulated,\n accumulatedReasoning,\n );\n accumulated = finalAccumulated || '';\n\n // Send final chunk\n const finalUsage = buildUsageInfo(usage, requestId);\n if (finalUsage && modelRuntime.onUsage) {\n modelRuntime.onUsage(finalUsage);\n usageReported = true;\n }\n const finalChunk: CodeGenerationChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: finalUsage,\n };\n options.onChunk!(finalChunk);\n break;\n }\n }\n } finally {\n cleanupStreamSignal();\n }\n content = accumulated;\n debugProfileStats(\n `streaming model, ${modelName}, mode, ${modelFamily || 'default'}, cost-ms, ${timeCost}, temperature, ${temperature ?? ''}`,\n );\n } else {\n // Non-streaming with retry logic\n const retryCount = normalizeRetryCount(modelConfig.retryCount);\n const retryInterval = modelConfig.retryInterval ?? 2000;\n const maxAttempts = retryCount + 1; // retryCount=1 means 2 total attempts (1 initial + 1 retry)\n\n let lastError: Error | undefined;\n const attemptErrors: Array<{ attempt: number; error: unknown }> = [];\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const { signal: attemptSignal, cleanup: cleanupAttemptSignal } =\n buildRequestAbortSignal(effectiveTimeoutMs, options?.abortSignal);\n try {\n const result = await completion.create(\n {\n model: modelName,\n messages: messagesWithImageDetail,\n ...requestConfig,\n stream: false,\n } as any,\n { signal: attemptSignal },\n );\n\n timeCost = Date.now() - startTime;\n\n debugProfileStats(\n `model, ${modelName}, mode, ${modelFamily || 'default'}, prompt-tokens, ${result.usage?.prompt_tokens || ''}, completion-tokens, ${result.usage?.completion_tokens || ''}, total-tokens, ${result.usage?.total_tokens || ''}, cost-ms, ${timeCost}, requestId, ${result._request_id || ''}, temperature, ${temperature ?? ''}`,\n );\n\n debugProfileDetail(\n `model usage detail: ${JSON.stringify(result.usage)}`,\n );\n\n if (!result.choices) {\n throw new Error(\n `invalid response from LLM service: ${JSON.stringify(result)}`,\n );\n }\n\n rawChoiceMessage = result.choices[0].message;\n const parsedMessage =\n adapter.chatCompletion.extractContentAndReasoning(\n result.choices[0].message,\n );\n content = parsedMessage.content;\n accumulatedReasoning = parsedMessage.reasoning_content;\n usage = result.usage;\n requestId = result._request_id;\n responseModelName = result.model;\n\n content = resolveContentWithReasoningFallback(\n content,\n accumulatedReasoning,\n );\n\n if (!hasUsableText(content)) {\n const errorUsage = buildUsageInfo(usage, requestId);\n if (errorUsage && modelRuntime.onUsage) {\n modelRuntime.onUsage(errorUsage);\n }\n throw new AIResponseParseError(\n 'empty content from AI model',\n content || '',\n errorUsage,\n rawChoiceMessage,\n );\n }\n\n break; // Success, exit retry loop\n } catch (error) {\n lastError = toError(error);\n attemptErrors.push({ attempt, error });\n const wasHardTimeout = isHardTimeoutError(lastError);\n if (wasHardTimeout) {\n warnCall(\n `AI call hit hard timeout (${effectiveTimeoutMs}ms, attempt ${attempt}/${maxAttempts}, model ${modelName}, slot ${modelConfig.slot})`,\n );\n }\n // Do not retry if the request was aborted by the caller\n if (options?.abortSignal?.aborted) {\n break;\n }\n if (attempt < maxAttempts) {\n warnCall(\n `AI call failed (attempt ${attempt}/${maxAttempts}), retrying in ${retryInterval}ms... Error: ${lastError.message}`,\n );\n await new Promise((resolve) => setTimeout(resolve, retryInterval));\n }\n } finally {\n cleanupAttemptSignal();\n }\n }\n\n if (!content) {\n assert(\n lastError,\n 'AI model request failed without recording an attempt error',\n );\n throw appendAIRequestFailureSummary(\n lastError,\n attemptErrors,\n maxAttempts,\n );\n }\n }\n\n debugCall(`response reasoning content: ${accumulatedReasoning}`);\n debugCall(`response content: ${content}`);\n\n // Ensure we always have usage info for streaming responses\n if (isStreaming && !usage) {\n // Estimate token counts based on content length (rough approximation)\n const estimatedTokens = Math.max(\n 1,\n Math.floor((content || '').length / 4),\n );\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: estimatedTokens * 2,\n } as OpenAI.CompletionUsage;\n }\n\n const finalUsage = buildUsageInfo(usage, requestId);\n // Report usage to the runtime-level collector if not already reported\n // (e.g. from the streaming final-chunk handler).\n if (!usageReported && finalUsage && modelRuntime.onUsage) {\n modelRuntime.onUsage(finalUsage);\n }\n\n return {\n content: content || '',\n reasoning_content: accumulatedReasoning || undefined,\n rawChoiceMessage,\n usage: finalUsage,\n isStreamed: !!isStreaming,\n };\n } catch (e: any) {\n warnCall('call AI error', e);\n\n if (e instanceof AIResponseParseError) {\n throw e;\n }\n\n const newError = new Error(\n `failed to call ${isStreaming ? 'streaming ' : ''}AI model service (${modelName}): ${e.message}${formatOpenAIAPIErrorDetails(e, openAIErrorResponseContext)}\\nTrouble shooting: https://midscenejs.com/model-provider.html`,\n {\n cause: e,\n },\n );\n throw newError;\n }\n}\n\nexport async function callAIWithObjectResponse<T>(\n messages: ChatCompletionMessageParam[],\n modelRuntime: ModelRuntime,\n options?: {\n abortSignal?: AbortSignal;\n jsonParserSource?: JsonParserSource;\n },\n): Promise<{\n // TODO: `content` is a misleading name here because this is already the parsed object response. Consider renaming it to `object` or `data`.\n content: T;\n contentString: string;\n usage?: AIUsageInfo;\n reasoning_content?: string;\n rawChoiceMessage?: unknown;\n}> {\n const { config: modelConfig, adapter } = modelRuntime;\n const response = await callAI(messages, modelRuntime, {\n abortSignal: options?.abortSignal,\n });\n assert(response, 'empty response');\n let jsonContent: unknown;\n try {\n jsonContent = adapter.jsonParser(response.content, {\n source: options?.jsonParserSource ?? 'generic-object',\n });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new AIResponseParseError(\n errorMessage,\n response.content,\n response.usage,\n );\n }\n if (typeof jsonContent !== 'object') {\n throw new AIResponseParseError(\n `failed to parse json response from model (${modelConfig.modelName}): ${response.content}`,\n response.content,\n response.usage,\n response.rawChoiceMessage,\n );\n }\n return {\n content: jsonContent as T,\n contentString: response.content,\n usage: response.usage,\n reasoning_content: response.reasoning_content,\n rawChoiceMessage: response.rawChoiceMessage,\n };\n}\n\nexport async function callAIWithStringResponse(\n msgs: AIArgs,\n modelRuntime: ModelRuntime,\n options?: Pick<CallAIOptions, 'abortSignal' | 'requiresOriginalImageDetail'>,\n): Promise<{\n content: string;\n usage?: AIUsageInfo;\n rawChoiceMessage?: unknown;\n}> {\n const { content, usage, rawChoiceMessage } = await callAI(\n msgs,\n modelRuntime,\n options,\n );\n return { content, usage, rawChoiceMessage };\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","AIResponseParseError","Error","message","rawResponse","usage","rawChoiceMessage","INTERNAL_CALL_ID_FIELD","internalCallIdCounter","nextInternalCallId","stringifyForDebug","value","JSON","_error","String","getErrorMessage","error","toError","normalizeRetryCount","retryCount","Number","Math","appendAIRequestFailureSummary","attemptErrors","maxAttempts","failedAttempts","retries","retryLabel","originalMessage","previousAttemptErrors","details","attempt","createChatClient","modelConfig","socksProxy","httpProxy","modelName","openaiBaseURL","openaiApiKey","openaiExtraConfig","modelDescription","modelFamily","createOpenAIClient","timeout","proxyAgent","warnClient","getDebug","debugProxy","warnProxy","sanitizeProxyUrl","url","parsed","URL","ifInBrowser","moduleName","ProxyAgent","socksDispatcher","proxyUrl","port","protocol","socksType","decodeURIComponent","effectiveTimeoutMs","resolveEffectiveTimeoutMs","openAIErrorResponseContext","openAIOptions","wrapOpenAICompatibleFetch","baseOpenAI","OpenAI","openai","globalConfigManager","MIDSCENE_LANGSMITH_DEBUG","langsmithModule","wrapOpenAI","MIDSCENE_LANGFUSE_DEBUG","langfuseModule","observeOpenAI","wrappedClient","callAI","messages","modelRuntime","options","adapter","internalCallId","isCodexAppServerProvider","codexResult","callAIWithCodexAppServer","completion","extraBody","debugCall","warnCall","debugProfileStats","debugProfileDetail","startTime","Date","isStreaming","chatCompletionInput","adapterChatCompletionParams","content","accumulated","accumulatedReasoning","timeCost","requestId","responseModelName","usageReported","hasUsableText","resolveContentWithReasoningFallback","contentValue","reasoningContent","buildUsageInfo","usageData","cachedInputTokens","undefined","requestConfig","temperature","imageDetail","messagesWithImageDetail","msg","Array","part","streamSignal","cleanupStreamSignal","buildRequestAbortSignal","stream","chunk","parsedChunk","reasoning_content","chunkData","estimatedTokens","finalAccumulated","finalUsage","finalChunk","retryInterval","lastError","attemptSignal","cleanupAttemptSignal","result","parsedMessage","errorUsage","wasHardTimeout","isHardTimeoutError","Promise","resolve","setTimeout","assert","e","newError","formatOpenAIAPIErrorDetails","callAIWithObjectResponse","response","jsonContent","errorMessage","callAIWithStringResponse","msgs"],"mappings":"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"}