@midscene/android-playground 0.26.3 → 0.26.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"static/js/index.4829cb37.js","sources":["webpack://android-playground/../../packages/shared/dist/es/utils.mjs","webpack://android-playground/../../packages/shared/dist/es/env.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/store/store.mjs","webpack://android-playground/../../packages/shared/dist/es/common.mjs","webpack://android-playground/../../packages/shared/dist/es/logger.mjs","webpack://android-playground/../../packages/shared/dist/es/img/transform.mjs","webpack://android-playground/../../packages/shared/dist/es/us-keyboard-layout.mjs","webpack://android-playground/../../packages/shared/dist/es/extractor/tree.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/ui-utils.mjs","webpack://android-playground/../../packages/core/dist/es/ai-model.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/task-cache.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/utils.mjs","webpack://android-playground/../../packages/core/dist/es/index.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/tasks.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/plan-builder.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/agent.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/playground-utils.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/useServerValid.mjs","webpack://android-playground/../../packages/visualizer/dist/es/utils.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/replay-scripts.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/color.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/logo.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/env-config.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/store/history.mjs","webpack://android-playground/../../packages/visualizer/dist/es/icons/setting.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/shiny-text.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/playground-constants.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/ConfigSelector.mjs","webpack://android-playground/../../packages/visualizer/dist/es/icons/close.mjs","webpack://android-playground/../../packages/visualizer/dist/es/icons/history.mjs","webpack://android-playground/../../packages/visualizer/dist/es/icons/magnifying-glass.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/HistorySelector.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/PromptInput.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/blackboard.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/pixi-loader.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/player.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/PlaygroundResult.mjs","webpack://android-playground/./src/adb-device/index.tsx","webpack://android-playground/./src/icons/linked.svg","webpack://android-playground/./src/icons/screenshot.svg","webpack://android-playground/./src/icons/unlink.svg","webpack://android-playground/./src/scrcpy-player/index.tsx","webpack://android-playground/./src/App.tsx","webpack://android-playground/./src/index.tsx","webpack://android-playground/webpack/runtime/compat_get_default_export","webpack://android-playground/webpack/runtime/create_fake_namespace_object","webpack://android-playground/webpack/runtime/define_property_getters","webpack://android-playground/webpack/runtime/ensure_chunk","webpack://android-playground/webpack/runtime/get javascript chunk filename","webpack://android-playground/webpack/runtime/get mini-css chunk filename","webpack://android-playground/webpack/runtime/get_full_hash","webpack://android-playground/webpack/runtime/global","webpack://android-playground/webpack/runtime/has_own_property","webpack://android-playground/webpack/runtime/load_script","webpack://android-playground/webpack/runtime/make_namespace_object","webpack://android-playground/webpack/runtime/node_module_decorator","webpack://android-playground/webpack/runtime/on_chunk_loaded","webpack://android-playground/webpack/runtime/public_path","webpack://android-playground/webpack/runtime/rspack_version","webpack://android-playground/webpack/runtime/jsonp_chunk_loading","webpack://android-playground/webpack/runtime/rspack_unique_id"],"sourcesContent":["import { sha256 } from \"js-sha256\";\nvar _process_versions;\nconst ifInBrowser = 'undefined' != typeof window;\nconst ifInWorker = 'undefined' != typeof WorkerGlobalScope;\nconst ifInNode = 'undefined' != typeof process && (null == (_process_versions = process.versions) ? void 0 : _process_versions.node);\nfunction uuid() {\n return Math.random().toString(36).substring(2, 15);\n}\nconst hashMap = {};\nfunction generateHashId(rect, content = '') {\n const combined = JSON.stringify({\n content,\n rect\n });\n let sliceLength = 5;\n let slicedHash = '';\n const hashHex = sha256.create().update(combined).hex();\n const toLetters = (hex)=>hex.split('').map((char)=>{\n const code = Number.parseInt(char, 16);\n return String.fromCharCode(97 + code % 26);\n }).join('');\n const hashLetters = toLetters(hashHex);\n while(sliceLength < hashLetters.length - 1){\n slicedHash = hashLetters.slice(0, sliceLength);\n if (hashMap[slicedHash] && hashMap[slicedHash] !== combined) {\n sliceLength++;\n continue;\n }\n hashMap[slicedHash] = combined;\n break;\n }\n return slicedHash;\n}\nfunction assert(condition, message) {\n if (!condition) throw new Error(message || 'Assertion failed');\n}\nfunction getGlobalScope() {\n if ('undefined' != typeof window) return window;\n if ('undefined' != typeof globalThis) return globalThis;\n if ('undefined' != typeof self) return self;\n}\nlet isMcp = false;\nfunction setIsMcp(value) {\n isMcp = value;\n}\nfunction logMsg(...message) {\n if (!isMcp) console.log(...message);\n}\nasync function repeat(times, fn) {\n for(let i = 0; i < times; i++)await fn(i);\n}\nconst utils_REGEXP_LT = /</g;\nconst utils_REGEXP_GT = />/g;\nconst REGEXP_LT_ESCAPE = '__midscene_lt__';\nconst REGEXP_GT_ESCAPE = '__midscene_gt__';\nconst escapeScriptTag = (html)=>html.replace(utils_REGEXP_LT, REGEXP_LT_ESCAPE).replace(utils_REGEXP_GT, REGEXP_GT_ESCAPE);\nconst antiEscapeScriptTag = (html)=>{\n const REGEXP_LT = new RegExp(REGEXP_LT_ESCAPE, 'g');\n const REGEXP_GT = new RegExp(REGEXP_GT_ESCAPE, 'g');\n return html.replace(REGEXP_LT, '<').replace(REGEXP_GT, '>');\n};\nexport { antiEscapeScriptTag, assert, escapeScriptTag, generateHashId, getGlobalScope, ifInBrowser, ifInNode, ifInWorker, logMsg, repeat, setIsMcp, uuid };\n","const MIDSCENE_OPENAI_INIT_CONFIG_JSON = 'MIDSCENE_OPENAI_INIT_CONFIG_JSON';\nconst MIDSCENE_MODEL_NAME = 'MIDSCENE_MODEL_NAME';\nconst MIDSCENE_LANGSMITH_DEBUG = 'MIDSCENE_LANGSMITH_DEBUG';\nconst MIDSCENE_DEBUG_AI_PROFILE = 'MIDSCENE_DEBUG_AI_PROFILE';\nconst MIDSCENE_DEBUG_AI_RESPONSE = 'MIDSCENE_DEBUG_AI_RESPONSE';\nconst MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG = 'MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG';\nconst MIDSCENE_DEBUG_MODE = 'MIDSCENE_DEBUG_MODE';\nconst MIDSCENE_MCP_USE_PUPPETEER_MODE = 'MIDSCENE_MCP_USE_PUPPETEER_MODE';\nconst MIDSCENE_MCP_ANDROID_MODE = 'MIDSCENE_MCP_ANDROID_MODE';\nconst MIDSCENE_FORCE_DEEP_THINK = 'MIDSCENE_FORCE_DEEP_THINK';\nconst MIDSCENE_OPENAI_SOCKS_PROXY = 'MIDSCENE_OPENAI_SOCKS_PROXY';\nconst MIDSCENE_OPENAI_HTTP_PROXY = 'MIDSCENE_OPENAI_HTTP_PROXY';\nconst OPENAI_API_KEY = 'OPENAI_API_KEY';\nconst OPENAI_BASE_URL = 'OPENAI_BASE_URL';\nconst OPENAI_MAX_TOKENS = 'OPENAI_MAX_TOKENS';\nconst MIDSCENE_ADB_PATH = 'MIDSCENE_ADB_PATH';\nconst MIDSCENE_ADB_REMOTE_HOST = 'MIDSCENE_ADB_REMOTE_HOST';\nconst MIDSCENE_ADB_REMOTE_PORT = 'MIDSCENE_ADB_REMOTE_PORT';\nconst MIDSCENE_ANDROID_IME_STRATEGY = 'MIDSCENE_ANDROID_IME_STRATEGY';\nconst MIDSCENE_CACHE = 'MIDSCENE_CACHE';\nconst MIDSCENE_USE_VLM_UI_TARS = 'MIDSCENE_USE_VLM_UI_TARS';\nconst MIDSCENE_USE_QWEN_VL = 'MIDSCENE_USE_QWEN_VL';\nconst MIDSCENE_USE_DOUBAO_VISION = 'MIDSCENE_USE_DOUBAO_VISION';\nconst MIDSCENE_USE_GEMINI = 'MIDSCENE_USE_GEMINI';\nconst MIDSCENE_USE_VL_MODEL = 'MIDSCENE_USE_VL_MODEL';\nconst MATCH_BY_POSITION = 'MATCH_BY_POSITION';\nconst MIDSCENE_API_TYPE = 'MIDSCENE-API-TYPE';\nconst MIDSCENE_REPORT_TAG_NAME = 'MIDSCENE_REPORT_TAG_NAME';\nconst MIDSCENE_REPLANNING_CYCLE_LIMIT = 'MIDSCENE_REPLANNING_CYCLE_LIMIT';\nconst MIDSCENE_PREFERRED_LANGUAGE = 'MIDSCENE_PREFERRED_LANGUAGE';\nconst MIDSCENE_USE_AZURE_OPENAI = 'MIDSCENE_USE_AZURE_OPENAI';\nconst MIDSCENE_AZURE_OPENAI_SCOPE = 'MIDSCENE_AZURE_OPENAI_SCOPE';\nconst MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON = 'MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON';\nconst MIDSCENE_CACHE_MAX_FILENAME_LENGTH = 'MIDSCENE_CACHE_MAX_FILENAME_LENGTH';\nconst AZURE_OPENAI_ENDPOINT = 'AZURE_OPENAI_ENDPOINT';\nconst AZURE_OPENAI_KEY = 'AZURE_OPENAI_KEY';\nconst AZURE_OPENAI_API_VERSION = 'AZURE_OPENAI_API_VERSION';\nconst AZURE_OPENAI_DEPLOYMENT = 'AZURE_OPENAI_DEPLOYMENT';\nconst MIDSCENE_USE_ANTHROPIC_SDK = 'MIDSCENE_USE_ANTHROPIC_SDK';\nconst ANTHROPIC_API_KEY = 'ANTHROPIC_API_KEY';\nconst MIDSCENE_RUN_DIR = 'MIDSCENE_RUN_DIR';\nconst OPENAI_USE_AZURE = 'OPENAI_USE_AZURE';\nconst allConfigFromEnv = ()=>({\n [MIDSCENE_MCP_ANDROID_MODE]: process.env[MIDSCENE_MCP_ANDROID_MODE] || void 0,\n [MIDSCENE_OPENAI_INIT_CONFIG_JSON]: process.env[MIDSCENE_OPENAI_INIT_CONFIG_JSON] || void 0,\n [MIDSCENE_MODEL_NAME]: process.env[MIDSCENE_MODEL_NAME] || void 0,\n [MIDSCENE_DEBUG_MODE]: process.env[MIDSCENE_DEBUG_MODE] || void 0,\n [MIDSCENE_FORCE_DEEP_THINK]: process.env[MIDSCENE_FORCE_DEEP_THINK] || void 0,\n [MIDSCENE_LANGSMITH_DEBUG]: process.env[MIDSCENE_LANGSMITH_DEBUG] || void 0,\n [MIDSCENE_DEBUG_AI_PROFILE]: process.env[MIDSCENE_DEBUG_AI_PROFILE] || void 0,\n [MIDSCENE_DEBUG_AI_RESPONSE]: process.env[MIDSCENE_DEBUG_AI_RESPONSE] || void 0,\n [MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG]: process.env[MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG] || void 0,\n [OPENAI_API_KEY]: process.env[OPENAI_API_KEY] || void 0,\n [OPENAI_BASE_URL]: process.env[OPENAI_BASE_URL] || void 0,\n [OPENAI_MAX_TOKENS]: process.env[OPENAI_MAX_TOKENS] || void 0,\n [OPENAI_USE_AZURE]: process.env[OPENAI_USE_AZURE] || void 0,\n [MIDSCENE_ADB_PATH]: process.env[MIDSCENE_ADB_PATH] || void 0,\n [MIDSCENE_ADB_REMOTE_HOST]: process.env[MIDSCENE_ADB_REMOTE_HOST] || void 0,\n [MIDSCENE_ADB_REMOTE_PORT]: process.env[MIDSCENE_ADB_REMOTE_PORT] || void 0,\n [MIDSCENE_ANDROID_IME_STRATEGY]: process.env[MIDSCENE_ANDROID_IME_STRATEGY] || void 0,\n [MIDSCENE_CACHE]: process.env[MIDSCENE_CACHE] || void 0,\n [MATCH_BY_POSITION]: process.env[MATCH_BY_POSITION] || void 0,\n [MIDSCENE_REPORT_TAG_NAME]: process.env[MIDSCENE_REPORT_TAG_NAME] || void 0,\n [MIDSCENE_OPENAI_SOCKS_PROXY]: process.env[MIDSCENE_OPENAI_SOCKS_PROXY] || void 0,\n [MIDSCENE_OPENAI_HTTP_PROXY]: process.env[MIDSCENE_OPENAI_HTTP_PROXY] || void 0,\n [MIDSCENE_USE_AZURE_OPENAI]: process.env[MIDSCENE_USE_AZURE_OPENAI] || void 0,\n [MIDSCENE_AZURE_OPENAI_SCOPE]: process.env[MIDSCENE_AZURE_OPENAI_SCOPE] || void 0,\n [MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON]: process.env[MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON] || void 0,\n [MIDSCENE_USE_ANTHROPIC_SDK]: process.env[MIDSCENE_USE_ANTHROPIC_SDK] || void 0,\n [MIDSCENE_USE_VLM_UI_TARS]: process.env[MIDSCENE_USE_VLM_UI_TARS] || void 0,\n [MIDSCENE_USE_QWEN_VL]: process.env[MIDSCENE_USE_QWEN_VL] || void 0,\n [MIDSCENE_USE_DOUBAO_VISION]: process.env[MIDSCENE_USE_DOUBAO_VISION] || void 0,\n [MIDSCENE_USE_GEMINI]: process.env[MIDSCENE_USE_GEMINI] || void 0,\n [MIDSCENE_USE_VL_MODEL]: process.env[MIDSCENE_USE_VL_MODEL] || void 0,\n [ANTHROPIC_API_KEY]: process.env[ANTHROPIC_API_KEY] || void 0,\n [AZURE_OPENAI_ENDPOINT]: process.env[AZURE_OPENAI_ENDPOINT] || void 0,\n [AZURE_OPENAI_KEY]: process.env[AZURE_OPENAI_KEY] || void 0,\n [AZURE_OPENAI_API_VERSION]: process.env[AZURE_OPENAI_API_VERSION] || void 0,\n [AZURE_OPENAI_DEPLOYMENT]: process.env[AZURE_OPENAI_DEPLOYMENT] || void 0,\n [MIDSCENE_MCP_USE_PUPPETEER_MODE]: process.env[MIDSCENE_MCP_USE_PUPPETEER_MODE] || void 0,\n [MIDSCENE_RUN_DIR]: process.env[MIDSCENE_RUN_DIR] || void 0,\n [MIDSCENE_PREFERRED_LANGUAGE]: process.env[MIDSCENE_PREFERRED_LANGUAGE] || void 0,\n [MIDSCENE_REPLANNING_CYCLE_LIMIT]: process.env[MIDSCENE_REPLANNING_CYCLE_LIMIT] || void 0,\n [MIDSCENE_CACHE_MAX_FILENAME_LENGTH]: process.env[MIDSCENE_CACHE_MAX_FILENAME_LENGTH] || void 0\n });\nconst getGlobalConfig = ()=>{\n if (!globalThis.midsceneGlobalConfig) globalThis.midsceneGlobalConfig = allConfigFromEnv();\n const envConfig = allConfigFromEnv();\n if (globalThis.midsceneGlobalConfigOverride) {\n const { newConfig, extendMode } = globalThis.midsceneGlobalConfigOverride;\n globalThis.midsceneGlobalConfig = extendMode ? {\n ...envConfig,\n ...newConfig\n } : {\n ...newConfig\n };\n } else globalThis.midsceneGlobalConfig = envConfig;\n return globalThis.midsceneGlobalConfig;\n};\nvar env_UITarsModelVersion = /*#__PURE__*/ function(UITarsModelVersion) {\n UITarsModelVersion[\"V1_0\"] = \"1.0\";\n UITarsModelVersion[\"V1_5\"] = \"1.5\";\n UITarsModelVersion[\"DOUBAO_1_5_15B\"] = \"doubao-1.5-15B\";\n UITarsModelVersion[\"DOUBAO_1_5_20B\"] = \"doubao-1.5-20B\";\n return UITarsModelVersion;\n}({});\nconst uiTarsModelVersion = ()=>{\n if ('vlm-ui-tars' !== vlLocateMode()) return false;\n const versionConfig = getAIConfig(MIDSCENE_USE_VLM_UI_TARS);\n if ('1' === versionConfig || 1 === versionConfig) return \"1.0\";\n if ('DOUBAO' === versionConfig || 'DOUBAO-1.5' === versionConfig) return \"doubao-1.5-20B\";\n return `${versionConfig}`;\n};\nconst vlLocateMode = ()=>{\n const enabledModes = [\n getAIConfigInBoolean(MIDSCENE_USE_DOUBAO_VISION) && 'MIDSCENE_USE_DOUBAO_VISION',\n getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL) && 'MIDSCENE_USE_QWEN_VL',\n getAIConfigInBoolean(MIDSCENE_USE_VLM_UI_TARS) && 'MIDSCENE_USE_VLM_UI_TARS',\n getAIConfigInBoolean(MIDSCENE_USE_GEMINI) && 'MIDSCENE_USE_GEMINI'\n ].filter(Boolean);\n if (enabledModes.length > 1) throw new Error(`Only one vision mode can be enabled at a time. Currently enabled modes: ${enabledModes.join(', ')}. Please disable all but one mode.`);\n if (getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL)) return 'qwen-vl';\n if (getAIConfigInBoolean(MIDSCENE_USE_DOUBAO_VISION)) return 'doubao-vision';\n if (getAIConfigInBoolean(MIDSCENE_USE_GEMINI)) return 'gemini';\n if (getAIConfigInBoolean(MIDSCENE_USE_VL_MODEL)) return 'vl-model';\n if (getAIConfigInBoolean(MIDSCENE_USE_VLM_UI_TARS)) return 'vlm-ui-tars';\n return false;\n};\nconst getAIConfig = (configKey)=>{\n if (configKey === MATCH_BY_POSITION) throw new Error('MATCH_BY_POSITION is deprecated, use MIDSCENE_USE_VL_MODEL instead');\n const value = getGlobalConfig()[configKey];\n if ('string' == typeof value) return value.trim();\n return value;\n};\nconst getAIConfigInBoolean = (configKey)=>{\n const config = getAIConfig(configKey) || '';\n if (/^(true|1)$/i.test(config)) return true;\n if (/^(false|0)$/i.test(config)) return false;\n return !!config.trim();\n};\nconst getAIConfigInNumber = (configKey)=>{\n const config = getAIConfig(configKey) || '';\n return Number(config);\n};\nconst getAIConfigInJson = (configKey)=>{\n const config = getAIConfig(configKey);\n try {\n return config ? JSON.parse(config) : void 0;\n } catch (error) {\n throw new Error(`Failed to parse json config: ${configKey}. ${error.message}`, {\n cause: error\n });\n }\n};\nconst overrideAIConfig = (newConfig, extendMode = false)=>{\n var _globalThis_midsceneGlobalConfigOverride;\n for(const key in newConfig){\n if ('string' != typeof key) throw new Error(`Failed to override AI config, invalid key: ${key}`);\n if ('object' == typeof newConfig[key]) throw new Error(`Failed to override AI config, invalid value for key: ${key}, value: ${newConfig[key]}`);\n }\n const savedNewConfig = extendMode ? {\n ...null == (_globalThis_midsceneGlobalConfigOverride = globalThis.midsceneGlobalConfigOverride) ? void 0 : _globalThis_midsceneGlobalConfigOverride.newConfig,\n ...newConfig\n } : newConfig;\n globalThis.midsceneGlobalConfigOverride = {\n newConfig: savedNewConfig,\n extendMode\n };\n};\nconst getPreferredLanguage = ()=>{\n if (getAIConfig(MIDSCENE_PREFERRED_LANGUAGE)) return getAIConfig(MIDSCENE_PREFERRED_LANGUAGE);\n const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n const isChina = 'Asia/Shanghai' === timeZone;\n return isChina ? 'Chinese' : 'English';\n};\nexport { ANTHROPIC_API_KEY, AZURE_OPENAI_API_VERSION, AZURE_OPENAI_DEPLOYMENT, AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_KEY, MATCH_BY_POSITION, MIDSCENE_ADB_PATH, MIDSCENE_ADB_REMOTE_HOST, MIDSCENE_ADB_REMOTE_PORT, MIDSCENE_ANDROID_IME_STRATEGY, MIDSCENE_API_TYPE, MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_AZURE_OPENAI_SCOPE, MIDSCENE_CACHE, MIDSCENE_CACHE_MAX_FILENAME_LENGTH, MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG, MIDSCENE_DEBUG_AI_PROFILE, MIDSCENE_DEBUG_AI_RESPONSE, MIDSCENE_DEBUG_MODE, MIDSCENE_FORCE_DEEP_THINK, MIDSCENE_LANGSMITH_DEBUG, MIDSCENE_MCP_ANDROID_MODE, MIDSCENE_MCP_USE_PUPPETEER_MODE, MIDSCENE_MODEL_NAME, MIDSCENE_OPENAI_HTTP_PROXY, MIDSCENE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_OPENAI_SOCKS_PROXY, MIDSCENE_PREFERRED_LANGUAGE, MIDSCENE_REPLANNING_CYCLE_LIMIT, MIDSCENE_REPORT_TAG_NAME, MIDSCENE_RUN_DIR, MIDSCENE_USE_ANTHROPIC_SDK, MIDSCENE_USE_AZURE_OPENAI, MIDSCENE_USE_DOUBAO_VISION, MIDSCENE_USE_GEMINI, MIDSCENE_USE_QWEN_VL, MIDSCENE_USE_VLM_UI_TARS, MIDSCENE_USE_VL_MODEL, OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MAX_TOKENS, OPENAI_USE_AZURE, env_UITarsModelVersion as UITarsModelVersion, allConfigFromEnv, getAIConfig, getAIConfigInBoolean, getAIConfigInJson, getAIConfigInNumber, getPreferredLanguage, overrideAIConfig, uiTarsModelVersion, vlLocateMode };\n","import { create } from \"zustand\";\nvar __webpack_require__ = {};\n(()=>{\n __webpack_require__.d = (exports, definition)=>{\n for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {\n enumerable: true,\n get: definition[key]\n });\n };\n})();\n(()=>{\n __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);\n})();\n(()=>{\n __webpack_require__.r = (exports)=>{\n if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {\n value: 'Module'\n });\n Object.defineProperty(exports, '__esModule', {\n value: true\n });\n };\n})();\nvar external_zustand_namespaceObject = {};\n__webpack_require__.r(external_zustand_namespaceObject);\n__webpack_require__.d(external_zustand_namespaceObject, {\n create: ()=>create\n});\nconst { create: store_create } = external_zustand_namespaceObject;\nconst useBlackboardPreference = store_create((set)=>({\n markerVisible: true,\n elementsVisible: true,\n setMarkerVisible: (visible)=>{\n set({\n markerVisible: visible\n });\n },\n setTextsVisible: (visible)=>{\n set({\n elementsVisible: visible\n });\n }\n }));\nconst CONFIG_KEY = 'midscene-env-config';\nconst SERVICE_MODE_KEY = 'midscene-service-mode';\nconst TRACKING_ACTIVE_TAB_KEY = 'midscene-tracking-active-tab';\nconst DEEP_THINK_KEY = 'midscene-deep-think';\nconst getConfigStringFromLocalStorage = ()=>{\n const configString = localStorage.getItem(CONFIG_KEY);\n return configString || '';\n};\nconst parseConfig = (configString)=>{\n const lines = configString.split('\\n');\n const config = {};\n lines.forEach((line)=>{\n const trimmed = line.trim();\n if (trimmed.startsWith('#')) return;\n const cleanLine = trimmed.replace(/^export\\s+/i, '').replace(/;$/, '').trim();\n const match = cleanLine.match(/^(\\w+)=(.*)$/);\n if (match) {\n const [, key, value] = match;\n let parsedValue = value.trim();\n if (parsedValue.startsWith(\"'\") && parsedValue.endsWith(\"'\") || parsedValue.startsWith('\"') && parsedValue.endsWith('\"')) parsedValue = parsedValue.slice(1, -1);\n config[key] = parsedValue;\n }\n });\n return config;\n};\nconst useEnvConfig = store_create((set, get)=>{\n const configString = getConfigStringFromLocalStorage();\n const config = parseConfig(configString);\n const ifInExtension = window.location.href.startsWith('chrome-extension');\n const savedServiceMode = localStorage.getItem(SERVICE_MODE_KEY);\n const savedForceSameTabNavigation = 'false' !== localStorage.getItem(TRACKING_ACTIVE_TAB_KEY);\n const savedDeepThink = 'true' === localStorage.getItem(DEEP_THINK_KEY);\n return {\n serviceMode: ifInExtension ? 'In-Browser-Extension' : savedServiceMode || 'Server',\n setServiceMode: (serviceMode)=>{\n if (ifInExtension) throw new Error('serviceMode cannot be set in extension');\n set({\n serviceMode\n });\n localStorage.setItem(SERVICE_MODE_KEY, serviceMode);\n },\n config,\n configString,\n setConfig: (config)=>set({\n config\n }),\n loadConfig: (configString)=>{\n const config = parseConfig(configString);\n set({\n config,\n configString\n });\n localStorage.setItem(CONFIG_KEY, configString);\n },\n syncFromStorage: ()=>{\n const latestConfigString = getConfigStringFromLocalStorage();\n const latestConfig = parseConfig(latestConfigString);\n set({\n config: latestConfig,\n configString: latestConfigString\n });\n },\n forceSameTabNavigation: savedForceSameTabNavigation,\n setForceSameTabNavigation: (forceSameTabNavigation)=>{\n set({\n forceSameTabNavigation\n });\n localStorage.setItem(TRACKING_ACTIVE_TAB_KEY, forceSameTabNavigation.toString());\n },\n deepThink: savedDeepThink,\n setDeepThink: (deepThink)=>{\n set({\n deepThink\n });\n localStorage.setItem(DEEP_THINK_KEY, deepThink.toString());\n },\n popupTab: 'playground',\n setPopupTab: (tab)=>{\n set({\n popupTab: tab\n });\n }\n };\n});\nexport { useBlackboardPreference, useEnvConfig };\n","import { existsSync, mkdirSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport node_path from \"node:path\";\nimport { MIDSCENE_RUN_DIR, getAIConfig } from \"./env.mjs\";\nimport { ifInNode } from \"./utils.mjs\";\nconst defaultRunDirName = 'midscene_run';\nconst getMidsceneRunDir = ()=>{\n if (!ifInNode) return '';\n return getAIConfig(MIDSCENE_RUN_DIR) || defaultRunDirName;\n};\nconst getMidsceneRunBaseDir = ()=>{\n if (!ifInNode) return '';\n let basePath = node_path.resolve(process.cwd(), getMidsceneRunDir());\n if (!existsSync(basePath)) try {\n mkdirSync(basePath, {\n recursive: true\n });\n } catch (error) {\n basePath = node_path.join(tmpdir(), defaultRunDirName);\n mkdirSync(basePath, {\n recursive: true\n });\n }\n return basePath;\n};\nconst getMidsceneRunSubDir = (subdir)=>{\n if (!ifInNode) return '';\n const basePath = getMidsceneRunBaseDir();\n const logPath = node_path.join(basePath, subdir);\n if (!existsSync(logPath)) mkdirSync(logPath, {\n recursive: true\n });\n return logPath;\n};\nexport { defaultRunDirName, getMidsceneRunBaseDir, getMidsceneRunDir, getMidsceneRunSubDir };\n","import node_fs from \"node:fs\";\nimport node_path from \"node:path\";\nimport node_util from \"node:util\";\nimport debug from \"debug\";\nimport { getMidsceneRunSubDir } from \"./common.mjs\";\nimport { ifInNode } from \"./utils.mjs\";\nconst topicPrefix = 'midscene';\nconst logStreams = new Map();\nconst debugInstances = new Map();\nfunction getLogStream(topic) {\n const topicFileName = topic.replace(/:/g, '-');\n if (!logStreams.has(topicFileName)) {\n const logFile = node_path.join(getMidsceneRunSubDir('log'), `${topicFileName}.log`);\n const stream = node_fs.createWriteStream(logFile, {\n flags: 'a'\n });\n logStreams.set(topicFileName, stream);\n }\n return logStreams.get(topicFileName);\n}\nfunction writeLogToFile(topic, message) {\n if (!ifInNode) return;\n const stream = getLogStream(topic);\n const now = new Date();\n const isoDate = now.toLocaleDateString('sv-SE');\n const isoTime = now.toLocaleTimeString('sv-SE');\n const milliseconds = now.getMilliseconds().toString().padStart(3, '0');\n const timezoneOffsetMinutes = now.getTimezoneOffset();\n const sign = timezoneOffsetMinutes <= 0 ? '+' : '-';\n const hours = Math.floor(Math.abs(timezoneOffsetMinutes) / 60).toString().padStart(2, '0');\n const minutes = (Math.abs(timezoneOffsetMinutes) % 60).toString().padStart(2, '0');\n const timezoneString = `${sign}${hours}:${minutes}`;\n const localISOTime = `${isoDate}T${isoTime}.${milliseconds}${timezoneString}`;\n stream.write(`[${localISOTime}] ${message}\\n`);\n}\nfunction getDebug(topic) {\n const fullTopic = `${topicPrefix}:${topic}`;\n if (!debugInstances.has(fullTopic)) {\n const debugFn = debug(fullTopic);\n const wrapper = (...args)=>{\n if (ifInNode) {\n const message = node_util.format(...args);\n writeLogToFile(topic, message);\n }\n debugFn(...args);\n };\n debugInstances.set(fullTopic, wrapper);\n }\n return debugInstances.get(fullTopic);\n}\nfunction enableDebug(topic) {\n if (ifInNode) return;\n debug.enable(`${topicPrefix}:${topic}`);\n}\nfunction cleanupLogStreams() {\n if (!ifInNode) return;\n for (const stream of logStreams.values())stream.end();\n logStreams.clear();\n debugInstances.clear();\n}\nexport { cleanupLogStreams, enableDebug, getDebug };\n","import node_assert from \"node:assert\";\nimport { Buffer } from \"node:buffer\";\nimport { readFileSync } from \"node:fs\";\nimport node_path from \"node:path\";\nimport { getDebug } from \"../logger.mjs\";\nimport { ifInNode } from \"../utils.mjs\";\nimport get_jimp from \"./get-jimp.mjs\";\nimport get_photon from \"./get-photon.mjs\";\nimport get_sharp from \"./get-sharp.mjs\";\nconst imgDebug = getDebug('img');\nasync function saveBase64Image(options) {\n const { base64Data, outputPath } = options;\n const base64Image = base64Data.split(';base64,').pop() || base64Data;\n const imageBuffer = Buffer.from(base64Image, 'base64');\n const Jimp = await get_jimp();\n const image = await Jimp.read(imageBuffer);\n await image.writeAsync(outputPath);\n}\nasync function transformImgPathToBase64(inputPath) {\n const Jimp = await get_jimp();\n const image = await Jimp.read(inputPath);\n const buffer = await image.getBufferAsync(Jimp.MIME_JPEG);\n const res = buffer.toString('base64');\n return res;\n}\nasync function resizeImg(inputData, newSize) {\n if ('string' == typeof inputData) throw Error('inputData is base64, use resizeImgBase64 instead');\n node_assert(newSize && newSize.width > 0 && newSize.height > 0, 'newSize must be positive');\n const resizeStartTime = Date.now();\n imgDebug(`resizeImg start, target size: ${newSize.width}x${newSize.height}`);\n if (ifInNode) try {\n const Sharp = await get_sharp();\n const metadata = await Sharp(inputData).metadata();\n const { width: originalWidth, height: originalHeight } = metadata;\n if (!originalWidth || !originalHeight) throw Error('Undefined width or height from the input image.');\n if (newSize.width === originalWidth && newSize.height === originalHeight) return inputData;\n const resizedBuffer = await Sharp(inputData).resize(newSize.width, newSize.height).jpeg({\n quality: 90\n }).toBuffer();\n const resizeEndTime = Date.now();\n imgDebug(`resizeImg done (Sharp), target size: ${newSize.width}x${newSize.height}, cost: ${resizeEndTime - resizeStartTime}ms`);\n return resizedBuffer;\n } catch (error) {\n imgDebug('Sharp failed, falling back to Photon:', error);\n }\n const { PhotonImage, SamplingFilter, resize } = await get_photon();\n const inputBytes = new Uint8Array(inputData);\n const inputImage = PhotonImage.new_from_byteslice(inputBytes);\n const originalWidth = inputImage.get_width();\n const originalHeight = inputImage.get_height();\n if (!originalWidth || !originalHeight) {\n inputImage.free();\n throw Error('Undefined width or height from the input image.');\n }\n if (newSize.width === originalWidth && newSize.height === originalHeight) {\n inputImage.free();\n return inputData;\n }\n const outputImage = resize(inputImage, newSize.width, newSize.height, SamplingFilter.CatmullRom);\n const outputBytes = outputImage.get_bytes_jpeg(90);\n const resizedBuffer = Buffer.from(outputBytes);\n inputImage.free();\n outputImage.free();\n const resizeEndTime = Date.now();\n imgDebug(`resizeImg done (Photon), target size: ${newSize.width}x${newSize.height}, cost: ${resizeEndTime - resizeStartTime}ms`);\n return resizedBuffer;\n}\nasync function bufferFromBase64(base64) {\n const splitFlag = ';base64,';\n const dataSplitted = base64.split(splitFlag);\n if (2 !== dataSplitted.length) throw Error('Invalid base64 data');\n const res = Buffer.from(dataSplitted[1], 'base64');\n return res;\n}\nasync function resizeImgBase64(inputBase64, newSize) {\n const splitFlag = ';base64,';\n const dataSplitted = inputBase64.split(splitFlag);\n if (2 !== dataSplitted.length) throw Error('Invalid base64 data');\n const imageBuffer = Buffer.from(dataSplitted[1], 'base64');\n const buffer = await resizeImg(imageBuffer, newSize);\n const content = buffer.toString('base64');\n const res = `${dataSplitted[0]}${splitFlag}${content}`;\n return res;\n}\nfunction zoomForGPT4o(originalWidth, originalHeight) {\n const maxWidth = 2048;\n const maxHeight = 768;\n let newWidth = originalWidth;\n let newHeight = originalHeight;\n const aspectRatio = originalWidth / originalHeight;\n if (originalWidth > maxWidth) {\n newWidth = maxWidth;\n newHeight = newWidth / aspectRatio;\n }\n if (newHeight > maxHeight) {\n newHeight = maxHeight;\n newWidth = newHeight * aspectRatio;\n }\n return {\n width: Math.round(newWidth),\n height: Math.round(newHeight)\n };\n}\nasync function jimpFromBase64(base64) {\n const Jimp = await get_jimp();\n const imageBuffer = await bufferFromBase64(base64);\n return Jimp.read(imageBuffer);\n}\nasync function paddingToMatchBlock(image, blockSize = 28) {\n const { width, height } = image.bitmap;\n const targetWidth = Math.ceil(width / blockSize) * blockSize;\n const targetHeight = Math.ceil(height / blockSize) * blockSize;\n if (targetWidth === width && targetHeight === height) return image;\n const Jimp = await get_jimp();\n const paddedImage = new Jimp(targetWidth, targetHeight, 0xffffffff);\n paddedImage.composite(image, 0, 0);\n return paddedImage;\n}\nasync function paddingToMatchBlockByBase64(imageBase64, blockSize = 28) {\n const jimpImage = await jimpFromBase64(imageBase64);\n const paddedImage = await paddingToMatchBlock(jimpImage, blockSize);\n return jimpToBase64(paddedImage);\n}\nasync function cropByRect(imageBase64, rect, paddingImage) {\n const jimpImage = await jimpFromBase64(imageBase64);\n const { left, top, width, height } = rect;\n jimpImage.crop(left, top, width, height);\n if (paddingImage) {\n const paddedImage = await paddingToMatchBlock(jimpImage);\n return jimpToBase64(paddedImage);\n }\n return jimpToBase64(jimpImage);\n}\nasync function jimpToBase64(image) {\n const Jimp = await get_jimp();\n return image.getBase64Async(Jimp.MIME_JPEG);\n}\nconst httpImg2Base64 = async (url)=>{\n const response = await fetch(url);\n if (!response.ok) throw new Error(`Failed to fetch image: ${url}`);\n const contentType = response.headers.get('content-type');\n if (!contentType) throw new Error(`Failed to fetch image: ${url}`);\n node_assert(contentType.startsWith('image/'), `The url ${url} is not a image, because of content-type in header is ${contentType}.`);\n const buffer = Buffer.from(await response.arrayBuffer());\n return `data:${contentType};base64,${buffer.toString('base64')}`;\n};\nconst localImg2Base64 = (imgPath, withoutHeader = false)=>{\n const body = readFileSync(imgPath).toString('base64');\n if (withoutHeader) return body;\n const type = node_path.extname(imgPath).slice(1);\n const finalType = 'svg' === type ? 'svg+xml' : type || 'jpg';\n return `data:image/${finalType};base64,${body}`;\n};\nconst preProcessImageUrl = async (url, convertHttpImage2Base64)=>{\n if (url.startsWith('data:')) return url;\n if (!(url.startsWith('http://') || url.startsWith('https://'))) return await localImg2Base64(url);\n if (!convertHttpImage2Base64) return url;\n return await httpImg2Base64(url);\n};\nexport { bufferFromBase64, cropByRect, httpImg2Base64, jimpFromBase64, jimpToBase64, localImg2Base64, paddingToMatchBlock, paddingToMatchBlockByBase64, preProcessImageUrl, resizeImg, resizeImgBase64, saveBase64Image, transformImgPathToBase64, zoomForGPT4o };\n","/*! For license information please see us-keyboard-layout.mjs.LICENSE.txt */\n/**\n * @license\n * Copyright 2017 Google Inc.\n * SPDX-License-Identifier: Apache-2.0\n */ const _keyDefinitions = {\n 0: {\n keyCode: 48,\n key: '0',\n code: 'Digit0'\n },\n 1: {\n keyCode: 49,\n key: '1',\n code: 'Digit1'\n },\n 2: {\n keyCode: 50,\n key: '2',\n code: 'Digit2'\n },\n 3: {\n keyCode: 51,\n key: '3',\n code: 'Digit3'\n },\n 4: {\n keyCode: 52,\n key: '4',\n code: 'Digit4'\n },\n 5: {\n keyCode: 53,\n key: '5',\n code: 'Digit5'\n },\n 6: {\n keyCode: 54,\n key: '6',\n code: 'Digit6'\n },\n 7: {\n keyCode: 55,\n key: '7',\n code: 'Digit7'\n },\n 8: {\n keyCode: 56,\n key: '8',\n code: 'Digit8'\n },\n 9: {\n keyCode: 57,\n key: '9',\n code: 'Digit9'\n },\n Power: {\n key: 'Power',\n code: 'Power'\n },\n Eject: {\n key: 'Eject',\n code: 'Eject'\n },\n Abort: {\n keyCode: 3,\n code: 'Abort',\n key: 'Cancel'\n },\n Help: {\n keyCode: 6,\n code: 'Help',\n key: 'Help'\n },\n Backspace: {\n keyCode: 8,\n code: 'Backspace',\n key: 'Backspace'\n },\n Tab: {\n keyCode: 9,\n code: 'Tab',\n key: 'Tab'\n },\n Numpad5: {\n keyCode: 12,\n shiftKeyCode: 101,\n key: 'Clear',\n code: 'Numpad5',\n shiftKey: '5',\n location: 3\n },\n NumpadEnter: {\n keyCode: 13,\n code: 'NumpadEnter',\n key: 'Enter',\n text: '\\r',\n location: 3\n },\n Enter: {\n keyCode: 13,\n code: 'Enter',\n key: 'Enter',\n text: '\\r'\n },\n '\\r': {\n keyCode: 13,\n code: 'Enter',\n key: 'Enter',\n text: '\\r'\n },\n '\\n': {\n keyCode: 13,\n code: 'Enter',\n key: 'Enter',\n text: '\\r'\n },\n ShiftLeft: {\n keyCode: 16,\n code: 'ShiftLeft',\n key: 'Shift',\n location: 1\n },\n ShiftRight: {\n keyCode: 16,\n code: 'ShiftRight',\n key: 'Shift',\n location: 2\n },\n ControlLeft: {\n keyCode: 17,\n code: 'ControlLeft',\n key: 'Control',\n location: 1\n },\n ControlRight: {\n keyCode: 17,\n code: 'ControlRight',\n key: 'Control',\n location: 2\n },\n AltLeft: {\n keyCode: 18,\n code: 'AltLeft',\n key: 'Alt',\n location: 1\n },\n AltRight: {\n keyCode: 18,\n code: 'AltRight',\n key: 'Alt',\n location: 2\n },\n Pause: {\n keyCode: 19,\n code: 'Pause',\n key: 'Pause'\n },\n CapsLock: {\n keyCode: 20,\n code: 'CapsLock',\n key: 'CapsLock'\n },\n Escape: {\n keyCode: 27,\n code: 'Escape',\n key: 'Escape'\n },\n Convert: {\n keyCode: 28,\n code: 'Convert',\n key: 'Convert'\n },\n NonConvert: {\n keyCode: 29,\n code: 'NonConvert',\n key: 'NonConvert'\n },\n Space: {\n keyCode: 32,\n code: 'Space',\n key: ' '\n },\n Numpad9: {\n keyCode: 33,\n shiftKeyCode: 105,\n key: 'PageUp',\n code: 'Numpad9',\n shiftKey: '9',\n location: 3\n },\n PageUp: {\n keyCode: 33,\n code: 'PageUp',\n key: 'PageUp'\n },\n Numpad3: {\n keyCode: 34,\n shiftKeyCode: 99,\n key: 'PageDown',\n code: 'Numpad3',\n shiftKey: '3',\n location: 3\n },\n PageDown: {\n keyCode: 34,\n code: 'PageDown',\n key: 'PageDown'\n },\n End: {\n keyCode: 35,\n code: 'End',\n key: 'End'\n },\n Numpad1: {\n keyCode: 35,\n shiftKeyCode: 97,\n key: 'End',\n code: 'Numpad1',\n shiftKey: '1',\n location: 3\n },\n Home: {\n keyCode: 36,\n code: 'Home',\n key: 'Home'\n },\n Numpad7: {\n keyCode: 36,\n shiftKeyCode: 103,\n key: 'Home',\n code: 'Numpad7',\n shiftKey: '7',\n location: 3\n },\n ArrowLeft: {\n keyCode: 37,\n code: 'ArrowLeft',\n key: 'ArrowLeft'\n },\n Numpad4: {\n keyCode: 37,\n shiftKeyCode: 100,\n key: 'ArrowLeft',\n code: 'Numpad4',\n shiftKey: '4',\n location: 3\n },\n Numpad8: {\n keyCode: 38,\n shiftKeyCode: 104,\n key: 'ArrowUp',\n code: 'Numpad8',\n shiftKey: '8',\n location: 3\n },\n ArrowUp: {\n keyCode: 38,\n code: 'ArrowUp',\n key: 'ArrowUp'\n },\n ArrowRight: {\n keyCode: 39,\n code: 'ArrowRight',\n key: 'ArrowRight'\n },\n Numpad6: {\n keyCode: 39,\n shiftKeyCode: 102,\n key: 'ArrowRight',\n code: 'Numpad6',\n shiftKey: '6',\n location: 3\n },\n Numpad2: {\n keyCode: 40,\n shiftKeyCode: 98,\n key: 'ArrowDown',\n code: 'Numpad2',\n shiftKey: '2',\n location: 3\n },\n ArrowDown: {\n keyCode: 40,\n code: 'ArrowDown',\n key: 'ArrowDown'\n },\n Select: {\n keyCode: 41,\n code: 'Select',\n key: 'Select'\n },\n Open: {\n keyCode: 43,\n code: 'Open',\n key: 'Execute'\n },\n PrintScreen: {\n keyCode: 44,\n code: 'PrintScreen',\n key: 'PrintScreen'\n },\n Insert: {\n keyCode: 45,\n code: 'Insert',\n key: 'Insert'\n },\n Numpad0: {\n keyCode: 45,\n shiftKeyCode: 96,\n key: 'Insert',\n code: 'Numpad0',\n shiftKey: '0',\n location: 3\n },\n Delete: {\n keyCode: 46,\n code: 'Delete',\n key: 'Delete'\n },\n NumpadDecimal: {\n keyCode: 46,\n shiftKeyCode: 110,\n code: 'NumpadDecimal',\n key: '\\u0000',\n shiftKey: '.',\n location: 3\n },\n Digit0: {\n keyCode: 48,\n code: 'Digit0',\n shiftKey: ')',\n key: '0'\n },\n Digit1: {\n keyCode: 49,\n code: 'Digit1',\n shiftKey: '!',\n key: '1'\n },\n Digit2: {\n keyCode: 50,\n code: 'Digit2',\n shiftKey: '@',\n key: '2'\n },\n Digit3: {\n keyCode: 51,\n code: 'Digit3',\n shiftKey: '#',\n key: '3'\n },\n Digit4: {\n keyCode: 52,\n code: 'Digit4',\n shiftKey: '$',\n key: '4'\n },\n Digit5: {\n keyCode: 53,\n code: 'Digit5',\n shiftKey: '%',\n key: '5'\n },\n Digit6: {\n keyCode: 54,\n code: 'Digit6',\n shiftKey: '^',\n key: '6'\n },\n Digit7: {\n keyCode: 55,\n code: 'Digit7',\n shiftKey: '&',\n key: '7'\n },\n Digit8: {\n keyCode: 56,\n code: 'Digit8',\n shiftKey: '*',\n key: '8'\n },\n Digit9: {\n keyCode: 57,\n code: 'Digit9',\n shiftKey: '(',\n key: '9'\n },\n KeyA: {\n keyCode: 65,\n code: 'KeyA',\n shiftKey: 'A',\n key: 'a'\n },\n KeyB: {\n keyCode: 66,\n code: 'KeyB',\n shiftKey: 'B',\n key: 'b'\n },\n KeyC: {\n keyCode: 67,\n code: 'KeyC',\n shiftKey: 'C',\n key: 'c'\n },\n KeyD: {\n keyCode: 68,\n code: 'KeyD',\n shiftKey: 'D',\n key: 'd'\n },\n KeyE: {\n keyCode: 69,\n code: 'KeyE',\n shiftKey: 'E',\n key: 'e'\n },\n KeyF: {\n keyCode: 70,\n code: 'KeyF',\n shiftKey: 'F',\n key: 'f'\n },\n KeyG: {\n keyCode: 71,\n code: 'KeyG',\n shiftKey: 'G',\n key: 'g'\n },\n KeyH: {\n keyCode: 72,\n code: 'KeyH',\n shiftKey: 'H',\n key: 'h'\n },\n KeyI: {\n keyCode: 73,\n code: 'KeyI',\n shiftKey: 'I',\n key: 'i'\n },\n KeyJ: {\n keyCode: 74,\n code: 'KeyJ',\n shiftKey: 'J',\n key: 'j'\n },\n KeyK: {\n keyCode: 75,\n code: 'KeyK',\n shiftKey: 'K',\n key: 'k'\n },\n KeyL: {\n keyCode: 76,\n code: 'KeyL',\n shiftKey: 'L',\n key: 'l'\n },\n KeyM: {\n keyCode: 77,\n code: 'KeyM',\n shiftKey: 'M',\n key: 'm'\n },\n KeyN: {\n keyCode: 78,\n code: 'KeyN',\n shiftKey: 'N',\n key: 'n'\n },\n KeyO: {\n keyCode: 79,\n code: 'KeyO',\n shiftKey: 'O',\n key: 'o'\n },\n KeyP: {\n keyCode: 80,\n code: 'KeyP',\n shiftKey: 'P',\n key: 'p'\n },\n KeyQ: {\n keyCode: 81,\n code: 'KeyQ',\n shiftKey: 'Q',\n key: 'q'\n },\n KeyR: {\n keyCode: 82,\n code: 'KeyR',\n shiftKey: 'R',\n key: 'r'\n },\n KeyS: {\n keyCode: 83,\n code: 'KeyS',\n shiftKey: 'S',\n key: 's'\n },\n KeyT: {\n keyCode: 84,\n code: 'KeyT',\n shiftKey: 'T',\n key: 't'\n },\n KeyU: {\n keyCode: 85,\n code: 'KeyU',\n shiftKey: 'U',\n key: 'u'\n },\n KeyV: {\n keyCode: 86,\n code: 'KeyV',\n shiftKey: 'V',\n key: 'v'\n },\n KeyW: {\n keyCode: 87,\n code: 'KeyW',\n shiftKey: 'W',\n key: 'w'\n },\n KeyX: {\n keyCode: 88,\n code: 'KeyX',\n shiftKey: 'X',\n key: 'x'\n },\n KeyY: {\n keyCode: 89,\n code: 'KeyY',\n shiftKey: 'Y',\n key: 'y'\n },\n KeyZ: {\n keyCode: 90,\n code: 'KeyZ',\n shiftKey: 'Z',\n key: 'z'\n },\n MetaLeft: {\n keyCode: 91,\n code: 'MetaLeft',\n key: 'Meta',\n location: 1\n },\n MetaRight: {\n keyCode: 92,\n code: 'MetaRight',\n key: 'Meta',\n location: 2\n },\n ContextMenu: {\n keyCode: 93,\n code: 'ContextMenu',\n key: 'ContextMenu'\n },\n NumpadMultiply: {\n keyCode: 106,\n code: 'NumpadMultiply',\n key: '*',\n location: 3\n },\n NumpadAdd: {\n keyCode: 107,\n code: 'NumpadAdd',\n key: '+',\n location: 3\n },\n NumpadSubtract: {\n keyCode: 109,\n code: 'NumpadSubtract',\n key: '-',\n location: 3\n },\n NumpadDivide: {\n keyCode: 111,\n code: 'NumpadDivide',\n key: '/',\n location: 3\n },\n F1: {\n keyCode: 112,\n code: 'F1',\n key: 'F1'\n },\n F2: {\n keyCode: 113,\n code: 'F2',\n key: 'F2'\n },\n F3: {\n keyCode: 114,\n code: 'F3',\n key: 'F3'\n },\n F4: {\n keyCode: 115,\n code: 'F4',\n key: 'F4'\n },\n F5: {\n keyCode: 116,\n code: 'F5',\n key: 'F5'\n },\n F6: {\n keyCode: 117,\n code: 'F6',\n key: 'F6'\n },\n F7: {\n keyCode: 118,\n code: 'F7',\n key: 'F7'\n },\n F8: {\n keyCode: 119,\n code: 'F8',\n key: 'F8'\n },\n F9: {\n keyCode: 120,\n code: 'F9',\n key: 'F9'\n },\n F10: {\n keyCode: 121,\n code: 'F10',\n key: 'F10'\n },\n F11: {\n keyCode: 122,\n code: 'F11',\n key: 'F11'\n },\n F12: {\n keyCode: 123,\n code: 'F12',\n key: 'F12'\n },\n F13: {\n keyCode: 124,\n code: 'F13',\n key: 'F13'\n },\n F14: {\n keyCode: 125,\n code: 'F14',\n key: 'F14'\n },\n F15: {\n keyCode: 126,\n code: 'F15',\n key: 'F15'\n },\n F16: {\n keyCode: 127,\n code: 'F16',\n key: 'F16'\n },\n F17: {\n keyCode: 128,\n code: 'F17',\n key: 'F17'\n },\n F18: {\n keyCode: 129,\n code: 'F18',\n key: 'F18'\n },\n F19: {\n keyCode: 130,\n code: 'F19',\n key: 'F19'\n },\n F20: {\n keyCode: 131,\n code: 'F20',\n key: 'F20'\n },\n F21: {\n keyCode: 132,\n code: 'F21',\n key: 'F21'\n },\n F22: {\n keyCode: 133,\n code: 'F22',\n key: 'F22'\n },\n F23: {\n keyCode: 134,\n code: 'F23',\n key: 'F23'\n },\n F24: {\n keyCode: 135,\n code: 'F24',\n key: 'F24'\n },\n NumLock: {\n keyCode: 144,\n code: 'NumLock',\n key: 'NumLock'\n },\n ScrollLock: {\n keyCode: 145,\n code: 'ScrollLock',\n key: 'ScrollLock'\n },\n AudioVolumeMute: {\n keyCode: 173,\n code: 'AudioVolumeMute',\n key: 'AudioVolumeMute'\n },\n AudioVolumeDown: {\n keyCode: 174,\n code: 'AudioVolumeDown',\n key: 'AudioVolumeDown'\n },\n AudioVolumeUp: {\n keyCode: 175,\n code: 'AudioVolumeUp',\n key: 'AudioVolumeUp'\n },\n MediaTrackNext: {\n keyCode: 176,\n code: 'MediaTrackNext',\n key: 'MediaTrackNext'\n },\n MediaTrackPrevious: {\n keyCode: 177,\n code: 'MediaTrackPrevious',\n key: 'MediaTrackPrevious'\n },\n MediaStop: {\n keyCode: 178,\n code: 'MediaStop',\n key: 'MediaStop'\n },\n MediaPlayPause: {\n keyCode: 179,\n code: 'MediaPlayPause',\n key: 'MediaPlayPause'\n },\n Semicolon: {\n keyCode: 186,\n code: 'Semicolon',\n shiftKey: ':',\n key: ';'\n },\n Equal: {\n keyCode: 187,\n code: 'Equal',\n shiftKey: '+',\n key: '='\n },\n NumpadEqual: {\n keyCode: 187,\n code: 'NumpadEqual',\n key: '=',\n location: 3\n },\n Comma: {\n keyCode: 188,\n code: 'Comma',\n shiftKey: '<',\n key: ','\n },\n Minus: {\n keyCode: 189,\n code: 'Minus',\n shiftKey: '_',\n key: '-'\n },\n Period: {\n keyCode: 190,\n code: 'Period',\n shiftKey: '>',\n key: '.'\n },\n Slash: {\n keyCode: 191,\n code: 'Slash',\n shiftKey: '?',\n key: '/'\n },\n Backquote: {\n keyCode: 192,\n code: 'Backquote',\n shiftKey: '~',\n key: '`'\n },\n BracketLeft: {\n keyCode: 219,\n code: 'BracketLeft',\n shiftKey: '{',\n key: '['\n },\n Backslash: {\n keyCode: 220,\n code: 'Backslash',\n shiftKey: '|',\n key: '\\\\'\n },\n BracketRight: {\n keyCode: 221,\n code: 'BracketRight',\n shiftKey: '}',\n key: ']'\n },\n Quote: {\n keyCode: 222,\n code: 'Quote',\n shiftKey: '\"',\n key: \"'\"\n },\n AltGraph: {\n keyCode: 225,\n code: 'AltGraph',\n key: 'AltGraph'\n },\n Props: {\n keyCode: 247,\n code: 'Props',\n key: 'CrSel'\n },\n Cancel: {\n keyCode: 3,\n key: 'Cancel',\n code: 'Abort'\n },\n Clear: {\n keyCode: 12,\n key: 'Clear',\n code: 'Numpad5',\n location: 3\n },\n Shift: {\n keyCode: 16,\n key: 'Shift',\n code: 'ShiftLeft',\n location: 1\n },\n Control: {\n keyCode: 17,\n key: 'Control',\n code: 'ControlLeft',\n location: 1\n },\n Alt: {\n keyCode: 18,\n key: 'Alt',\n code: 'AltLeft',\n location: 1\n },\n Accept: {\n keyCode: 30,\n key: 'Accept'\n },\n ModeChange: {\n keyCode: 31,\n key: 'ModeChange'\n },\n ' ': {\n keyCode: 32,\n key: ' ',\n code: 'Space'\n },\n Print: {\n keyCode: 42,\n key: 'Print'\n },\n Execute: {\n keyCode: 43,\n key: 'Execute',\n code: 'Open'\n },\n '\\u0000': {\n keyCode: 46,\n key: '\\u0000',\n code: 'NumpadDecimal',\n location: 3\n },\n a: {\n keyCode: 65,\n key: 'a',\n code: 'KeyA'\n },\n b: {\n keyCode: 66,\n key: 'b',\n code: 'KeyB'\n },\n c: {\n keyCode: 67,\n key: 'c',\n code: 'KeyC'\n },\n d: {\n keyCode: 68,\n key: 'd',\n code: 'KeyD'\n },\n e: {\n keyCode: 69,\n key: 'e',\n code: 'KeyE'\n },\n f: {\n keyCode: 70,\n key: 'f',\n code: 'KeyF'\n },\n g: {\n keyCode: 71,\n key: 'g',\n code: 'KeyG'\n },\n h: {\n keyCode: 72,\n key: 'h',\n code: 'KeyH'\n },\n i: {\n keyCode: 73,\n key: 'i',\n code: 'KeyI'\n },\n j: {\n keyCode: 74,\n key: 'j',\n code: 'KeyJ'\n },\n k: {\n keyCode: 75,\n key: 'k',\n code: 'KeyK'\n },\n l: {\n keyCode: 76,\n key: 'l',\n code: 'KeyL'\n },\n m: {\n keyCode: 77,\n key: 'm',\n code: 'KeyM'\n },\n n: {\n keyCode: 78,\n key: 'n',\n code: 'KeyN'\n },\n o: {\n keyCode: 79,\n key: 'o',\n code: 'KeyO'\n },\n p: {\n keyCode: 80,\n key: 'p',\n code: 'KeyP'\n },\n q: {\n keyCode: 81,\n key: 'q',\n code: 'KeyQ'\n },\n r: {\n keyCode: 82,\n key: 'r',\n code: 'KeyR'\n },\n s: {\n keyCode: 83,\n key: 's',\n code: 'KeyS'\n },\n t: {\n keyCode: 84,\n key: 't',\n code: 'KeyT'\n },\n u: {\n keyCode: 85,\n key: 'u',\n code: 'KeyU'\n },\n v: {\n keyCode: 86,\n key: 'v',\n code: 'KeyV'\n },\n w: {\n keyCode: 87,\n key: 'w',\n code: 'KeyW'\n },\n x: {\n keyCode: 88,\n key: 'x',\n code: 'KeyX'\n },\n y: {\n keyCode: 89,\n key: 'y',\n code: 'KeyY'\n },\n z: {\n keyCode: 90,\n key: 'z',\n code: 'KeyZ'\n },\n Meta: {\n keyCode: 91,\n key: 'Meta',\n code: 'MetaLeft',\n location: 1\n },\n '*': {\n keyCode: 106,\n key: '*',\n code: 'NumpadMultiply',\n location: 3\n },\n '+': {\n keyCode: 107,\n key: '+',\n code: 'NumpadAdd',\n location: 3\n },\n '-': {\n keyCode: 109,\n key: '-',\n code: 'NumpadSubtract',\n location: 3\n },\n '/': {\n keyCode: 111,\n key: '/',\n code: 'NumpadDivide',\n location: 3\n },\n ';': {\n keyCode: 186,\n key: ';',\n code: 'Semicolon'\n },\n '=': {\n keyCode: 187,\n key: '=',\n code: 'Equal'\n },\n ',': {\n keyCode: 188,\n key: ',',\n code: 'Comma'\n },\n '.': {\n keyCode: 190,\n key: '.',\n code: 'Period'\n },\n '`': {\n keyCode: 192,\n key: '`',\n code: 'Backquote'\n },\n '[': {\n keyCode: 219,\n key: '[',\n code: 'BracketLeft'\n },\n '\\\\': {\n keyCode: 220,\n key: '\\\\',\n code: 'Backslash'\n },\n ']': {\n keyCode: 221,\n key: ']',\n code: 'BracketRight'\n },\n \"'\": {\n keyCode: 222,\n key: \"'\",\n code: 'Quote'\n },\n Attn: {\n keyCode: 246,\n key: 'Attn'\n },\n CrSel: {\n keyCode: 247,\n key: 'CrSel',\n code: 'Props'\n },\n ExSel: {\n keyCode: 248,\n key: 'ExSel'\n },\n EraseEof: {\n keyCode: 249,\n key: 'EraseEof'\n },\n Play: {\n keyCode: 250,\n key: 'Play'\n },\n ZoomOut: {\n keyCode: 251,\n key: 'ZoomOut'\n },\n ')': {\n keyCode: 48,\n key: ')',\n code: 'Digit0'\n },\n '!': {\n keyCode: 49,\n key: '!',\n code: 'Digit1'\n },\n '@': {\n keyCode: 50,\n key: '@',\n code: 'Digit2'\n },\n '#': {\n keyCode: 51,\n key: '#',\n code: 'Digit3'\n },\n $: {\n keyCode: 52,\n key: '$',\n code: 'Digit4'\n },\n '%': {\n keyCode: 53,\n key: '%',\n code: 'Digit5'\n },\n '^': {\n keyCode: 54,\n key: '^',\n code: 'Digit6'\n },\n '&': {\n keyCode: 55,\n key: '&',\n code: 'Digit7'\n },\n '(': {\n keyCode: 57,\n key: '(',\n code: 'Digit9'\n },\n A: {\n keyCode: 65,\n key: 'A',\n code: 'KeyA'\n },\n B: {\n keyCode: 66,\n key: 'B',\n code: 'KeyB'\n },\n C: {\n keyCode: 67,\n key: 'C',\n code: 'KeyC'\n },\n D: {\n keyCode: 68,\n key: 'D',\n code: 'KeyD'\n },\n E: {\n keyCode: 69,\n key: 'E',\n code: 'KeyE'\n },\n F: {\n keyCode: 70,\n key: 'F',\n code: 'KeyF'\n },\n G: {\n keyCode: 71,\n key: 'G',\n code: 'KeyG'\n },\n H: {\n keyCode: 72,\n key: 'H',\n code: 'KeyH'\n },\n I: {\n keyCode: 73,\n key: 'I',\n code: 'KeyI'\n },\n J: {\n keyCode: 74,\n key: 'J',\n code: 'KeyJ'\n },\n K: {\n keyCode: 75,\n key: 'K',\n code: 'KeyK'\n },\n L: {\n keyCode: 76,\n key: 'L',\n code: 'KeyL'\n },\n M: {\n keyCode: 77,\n key: 'M',\n code: 'KeyM'\n },\n N: {\n keyCode: 78,\n key: 'N',\n code: 'KeyN'\n },\n O: {\n keyCode: 79,\n key: 'O',\n code: 'KeyO'\n },\n P: {\n keyCode: 80,\n key: 'P',\n code: 'KeyP'\n },\n Q: {\n keyCode: 81,\n key: 'Q',\n code: 'KeyQ'\n },\n R: {\n keyCode: 82,\n key: 'R',\n code: 'KeyR'\n },\n S: {\n keyCode: 83,\n key: 'S',\n code: 'KeyS'\n },\n T: {\n keyCode: 84,\n key: 'T',\n code: 'KeyT'\n },\n U: {\n keyCode: 85,\n key: 'U',\n code: 'KeyU'\n },\n V: {\n keyCode: 86,\n key: 'V',\n code: 'KeyV'\n },\n W: {\n keyCode: 87,\n key: 'W',\n code: 'KeyW'\n },\n X: {\n keyCode: 88,\n key: 'X',\n code: 'KeyX'\n },\n Y: {\n keyCode: 89,\n key: 'Y',\n code: 'KeyY'\n },\n Z: {\n keyCode: 90,\n key: 'Z',\n code: 'KeyZ'\n },\n ':': {\n keyCode: 186,\n key: ':',\n code: 'Semicolon'\n },\n '<': {\n keyCode: 188,\n key: '<',\n code: 'Comma'\n },\n _: {\n keyCode: 189,\n key: '_',\n code: 'Minus'\n },\n '>': {\n keyCode: 190,\n key: '>',\n code: 'Period'\n },\n '?': {\n keyCode: 191,\n key: '?',\n code: 'Slash'\n },\n '~': {\n keyCode: 192,\n key: '~',\n code: 'Backquote'\n },\n '{': {\n keyCode: 219,\n key: '{',\n code: 'BracketLeft'\n },\n '|': {\n keyCode: 220,\n key: '|',\n code: 'Backslash'\n },\n '}': {\n keyCode: 221,\n key: '}',\n code: 'BracketRight'\n },\n '\"': {\n keyCode: 222,\n key: '\"',\n code: 'Quote'\n },\n SoftLeft: {\n key: 'SoftLeft',\n code: 'SoftLeft',\n location: 4\n },\n SoftRight: {\n key: 'SoftRight',\n code: 'SoftRight',\n location: 4\n },\n Camera: {\n keyCode: 44,\n key: 'Camera',\n code: 'Camera',\n location: 4\n },\n Call: {\n key: 'Call',\n code: 'Call',\n location: 4\n },\n EndCall: {\n keyCode: 95,\n key: 'EndCall',\n code: 'EndCall',\n location: 4\n },\n VolumeDown: {\n keyCode: 182,\n key: 'VolumeDown',\n code: 'VolumeDown',\n location: 4\n },\n VolumeUp: {\n keyCode: 183,\n key: 'VolumeUp',\n code: 'VolumeUp',\n location: 4\n }\n};\nconst lowerCaseKeyDefinitions = Object.entries(_keyDefinitions).reduce((acc, [key, definition])=>{\n const lowerKey = key.toLowerCase();\n if (lowerKey !== key) acc[lowerKey] = definition;\n return acc;\n}, {});\nconst getKeyDefinition = (key)=>{\n const lowerKey = key.toLowerCase();\n if (lowerCaseKeyDefinitions[lowerKey]) return lowerCaseKeyDefinitions[lowerKey].key;\n return key;\n};\nconst isMac = 'undefined' != typeof window ? /Mac|iPod|iPhone|iPad/.test(window.navigator.platform) : 'darwin' === process.platform;\nconst keyMap = {\n return: _keyDefinitions.Enter.key,\n enter: _keyDefinitions.Enter.key,\n ctrl: isMac ? _keyDefinitions.Meta.key : _keyDefinitions.Control.key,\n shift: _keyDefinitions.Shift.key,\n alt: _keyDefinitions.Alt.key,\n space: _keyDefinitions.Space.key,\n 'page down': _keyDefinitions.PageDown.key,\n pagedown: _keyDefinitions.PageDown.key,\n 'page up': _keyDefinitions.PageUp.key,\n pageup: _keyDefinitions.PageUp.key\n};\nfunction transformHotkeyInput(keyInput) {\n if (keyMap[keyInput.toLowerCase()]) return [\n getKeyDefinition(keyMap[keyInput.toLowerCase()])\n ];\n return keyInput.split(' ').map((key)=>getKeyDefinition(keyMap[key.toLowerCase()] || key));\n}\nexport { _keyDefinitions, getKeyDefinition, isMac, transformHotkeyInput };\n","function truncateText(text, maxLength = 150) {\n if (void 0 === text) return '';\n if ('object' == typeof text) text = JSON.stringify(text);\n if ('number' == typeof text) return text.toString();\n if ('string' == typeof text && text.length > maxLength) return `${text.slice(0, maxLength)}...`;\n if ('string' == typeof text) return text.trim();\n return '';\n}\nfunction trimAttributes(attributes, truncateTextLength) {\n const tailorAttributes = Object.keys(attributes).reduce((res, currentKey)=>{\n const attributeVal = attributes[currentKey];\n if ('style' === currentKey || 'htmlTagName' === currentKey || 'nodeType' === currentKey) return res;\n res[currentKey] = truncateText(attributeVal, truncateTextLength);\n return res;\n }, {});\n return tailorAttributes;\n}\nconst nodeSizeThreshold = 4;\nfunction descriptionOfTree(tree, truncateTextLength, filterNonTextContent = false, visibleOnly = true) {\n const attributesString = (kv)=>Object.entries(kv).map(([key, value])=>`${key}=\"${truncateText(value, truncateTextLength)}\"`).join(' ');\n function buildContentTree(node, indent = 0, visibleOnly = true) {\n let before = '';\n let contentWithIndent = '';\n let after = '';\n let emptyNode = true;\n const indentStr = ' '.repeat(indent);\n let children = '';\n for(let i = 0; i < (node.children || []).length; i++){\n const childContent = buildContentTree(node.children[i], indent + 1, visibleOnly);\n if (childContent) children += `\\n${childContent}`;\n }\n if (node.node && node.node.rect.width > nodeSizeThreshold && node.node.rect.height > nodeSizeThreshold && (!filterNonTextContent || filterNonTextContent && node.node.content) && (!visibleOnly || visibleOnly && node.node.isVisible)) {\n var _node_node_attributes;\n emptyNode = false;\n let nodeTypeString;\n nodeTypeString = (null == (_node_node_attributes = node.node.attributes) ? void 0 : _node_node_attributes.htmlTagName) ? node.node.attributes.htmlTagName.replace(/[<>]/g, '') : node.node.attributes.nodeType.replace(/\\sNode$/, '').toLowerCase();\n const markerId = node.node.indexId;\n const markerIdString = markerId ? `markerId=\"${markerId}\"` : '';\n const rectAttribute = node.node.rect ? {\n left: node.node.rect.left,\n top: node.node.rect.top,\n width: node.node.rect.width,\n height: node.node.rect.height\n } : {};\n before = `<${nodeTypeString} id=\"${node.node.id}\" ${markerIdString} ${attributesString(trimAttributes(node.node.attributes || {}, truncateTextLength))} ${attributesString(rectAttribute)}>`;\n const content = truncateText(node.node.content, truncateTextLength);\n contentWithIndent = content ? `\\n${indentStr} ${content}` : '';\n after = `</${nodeTypeString}>`;\n } else if (!filterNonTextContent) {\n if (!children.trim().startsWith('<>')) {\n before = '<>';\n contentWithIndent = '';\n after = '</>';\n }\n }\n if (emptyNode && !children.trim()) return '';\n const result = `${indentStr}${before}${contentWithIndent}${children}\\n${indentStr}${after}`;\n if (result.trim()) return result;\n return '';\n }\n const result = buildContentTree(tree, 0, visibleOnly);\n return result.replace(/^\\s*\\n/gm, '');\n}\nfunction treeToList(tree) {\n const result = [];\n function dfs(node) {\n if (node.node) result.push(node.node);\n for (const child of node.children)dfs(child);\n }\n dfs(tree);\n return result;\n}\nfunction traverseTree(tree, onNode) {\n function dfs(node) {\n if (node.node) node.node = onNode(node.node);\n for (const child of node.children)dfs(child);\n }\n dfs(tree);\n return tree;\n}\nexport { descriptionOfTree, traverseTree, treeToList, trimAttributes, truncateText };\n","function typeStr(task) {\n return task.subType && 'Plan' !== task.subType ? `${task.type} / ${task.subType || ''}` : task.type;\n}\nfunction getKeyCommands(value) {\n const keys = Array.isArray(value) ? value : [\n value\n ];\n return keys.reduce((acc, k)=>{\n const includeMeta = keys.includes('Meta') || keys.includes('Control');\n if (includeMeta && ('a' === k || 'A' === k)) return acc.concat([\n {\n key: k,\n command: 'SelectAll'\n }\n ]);\n if (includeMeta && ('c' === k || 'C' === k)) return acc.concat([\n {\n key: k,\n command: 'Copy'\n }\n ]);\n if (includeMeta && ('v' === k || 'V' === k)) return acc.concat([\n {\n key: k,\n command: 'Paste'\n }\n ]);\n return acc.concat([\n {\n key: k\n }\n ]);\n }, []);\n}\nfunction locateParamStr(locate) {\n if (!locate) return '';\n if ('string' == typeof locate) return locate;\n return 'string' == typeof locate.prompt ? locate.prompt : locate.prompt.prompt;\n}\nfunction scrollParamStr(scrollParam) {\n if (!scrollParam) return '';\n return `${scrollParam.direction || 'down'}, ${scrollParam.scrollType || 'once'}, ${scrollParam.distance || 'distance-not-set'}`;\n}\nfunction pullParamStr(pullParam) {\n if (!pullParam) return '';\n const parts = [];\n parts.push(`direction: ${pullParam.direction || 'down'}`);\n if (pullParam.distance) parts.push(`distance: ${pullParam.distance}`);\n if (pullParam.duration) parts.push(`duration: ${pullParam.duration}ms`);\n return parts.join(', ');\n}\nfunction taskTitleStr(type, prompt) {\n if (prompt) return `${type} - ${prompt}`;\n return type;\n}\nfunction paramStr(task) {\n let value;\n if ('Planning' === task.type) {\n var _task_param;\n value = null == task ? void 0 : null == (_task_param = task.param) ? void 0 : _task_param.userInstruction;\n }\n if ('Insight' === task.type) {\n var _task_param1, _task_param2, _task_param3, _task_param4;\n value = (null == task ? void 0 : null == (_task_param1 = task.param) ? void 0 : _task_param1.prompt) || (null == task ? void 0 : null == (_task_param2 = task.param) ? void 0 : _task_param2.id) || (null == task ? void 0 : null == (_task_param3 = task.param) ? void 0 : _task_param3.dataDemand) || (null == task ? void 0 : null == (_task_param4 = task.param) ? void 0 : _task_param4.assertion);\n }\n if ('Action' === task.type) {\n var _task_param5, _task_param6, _task_param7, _task_param8;\n const locate = null == task ? void 0 : task.locate;\n const locateStr = locate ? locateParamStr(locate) : '';\n value = task.thought || '';\n if ('number' == typeof (null == task ? void 0 : null == (_task_param5 = task.param) ? void 0 : _task_param5.timeMs)) {\n var _task_param9;\n value = `${null == task ? void 0 : null == (_task_param9 = task.param) ? void 0 : _task_param9.timeMs}ms`;\n } else if ('string' == typeof (null == task ? void 0 : null == (_task_param6 = task.param) ? void 0 : _task_param6.scrollType)) value = scrollParamStr(null == task ? void 0 : task.param);\n else if ('string' == typeof (null == task ? void 0 : null == (_task_param7 = task.param) ? void 0 : _task_param7.direction) && (null == task ? void 0 : task.subType) === 'AndroidPull') value = pullParamStr(null == task ? void 0 : task.param);\n else if (void 0 !== (null == task ? void 0 : null == (_task_param8 = task.param) ? void 0 : _task_param8.value)) {\n var _task_param10;\n value = null == task ? void 0 : null == (_task_param10 = task.param) ? void 0 : _task_param10.value;\n }\n if (locateStr) value = value ? `${locateStr} - ${value}` : locateStr;\n }\n if (void 0 === value) return '';\n return 'string' == typeof value ? value : JSON.stringify(value, void 0, 2);\n}\nconst limitOpenNewTabScript = `\nif (!window.__MIDSCENE_NEW_TAB_INTERCEPTOR_INITIALIZED__) {\n window.__MIDSCENE_NEW_TAB_INTERCEPTOR_INITIALIZED__ = true;\n\n // Intercept the window.open method (only once)\n window.open = function(url) {\n console.log('Blocked window.open:', url);\n window.location.href = url;\n return null;\n };\n\n // Block all a tag clicks with target=\"_blank\" (only once)\n document.addEventListener('click', function(e) {\n const target = e.target.closest('a');\n if (target && target.target === '_blank') {\n e.preventDefault();\n console.log('Blocked new tab:', target.href);\n window.location.href = target.href;\n target.removeAttribute('target');\n }\n }, true);\n}\n`;\nexport { getKeyCommands, limitOpenNewTabScript, locateParamStr, paramStr, pullParamStr, scrollParamStr, taskTitleStr, typeStr };\n\n//# sourceMappingURL=ui-utils.mjs.map","import { Anthropic } from \"@anthropic-ai/sdk\";\nimport { DefaultAzureCredential, getBearerTokenProvider } from \"@azure/identity\";\nimport { ANTHROPIC_API_KEY, AZURE_OPENAI_API_VERSION, AZURE_OPENAI_DEPLOYMENT, AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_KEY, MIDSCENE_API_TYPE, MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_AZURE_OPENAI_SCOPE, MIDSCENE_DEBUG_AI_PROFILE, MIDSCENE_DEBUG_AI_RESPONSE, MIDSCENE_LANGSMITH_DEBUG, MIDSCENE_MODEL_NAME, MIDSCENE_OPENAI_HTTP_PROXY, MIDSCENE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_OPENAI_SOCKS_PROXY, MIDSCENE_USE_ANTHROPIC_SDK, MIDSCENE_USE_AZURE_OPENAI, MIDSCENE_USE_QWEN_VL, MIDSCENE_USE_VLM_UI_TARS, OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MAX_TOKENS, OPENAI_USE_AZURE, UITarsModelVersion, getAIConfig, getAIConfigInBoolean, getAIConfigInJson, getPreferredLanguage, uiTarsModelVersion, vlLocateMode } from \"@midscene/shared/env\";\nimport { enableDebug, getDebug } from \"@midscene/shared/logger\";\nimport { assert, ifInBrowser } from \"@midscene/shared/utils\";\nimport { HttpsProxyAgent } from \"https-proxy-agent\";\nimport { jsonrepair } from \"jsonrepair\";\nimport openai_0, { AzureOpenAI } from \"openai\";\nimport { SocksProxyAgent } from \"socks-proxy-agent\";\nimport { NodeType, PLAYWRIGHT_EXAMPLE_CODE, YAML_EXAMPLE_CODE } from \"@midscene/shared/constants\";\nimport { descriptionOfTree, generateElementByPosition, treeToList } from \"@midscene/shared/extractor\";\nimport { compositeElementInfoImg, cropByRect, imageInfoOfBase64, paddingToMatchBlockByBase64, preProcessImageUrl, resizeImgBase64 } from \"@midscene/shared/img\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport node_assert from \"node:assert\";\nimport { transformHotkeyInput } from \"@midscene/shared/us-keyboard-layout\";\nimport { actionParser } from \"@ui-tars/action-parser\";\nvar types_AIResponseFormat = /*#__PURE__*/ function(AIResponseFormat) {\n AIResponseFormat[\"JSON\"] = \"json_object\";\n AIResponseFormat[\"TEXT\"] = \"text\";\n return AIResponseFormat;\n}({});\nvar common_AIActionType = /*#__PURE__*/ function(AIActionType) {\n AIActionType[AIActionType[\"ASSERT\"] = 0] = \"ASSERT\";\n AIActionType[AIActionType[\"INSPECT_ELEMENT\"] = 1] = \"INSPECT_ELEMENT\";\n AIActionType[AIActionType[\"EXTRACT_DATA\"] = 2] = \"EXTRACT_DATA\";\n AIActionType[AIActionType[\"PLAN\"] = 3] = \"PLAN\";\n AIActionType[AIActionType[\"DESCRIBE_ELEMENT\"] = 4] = \"DESCRIBE_ELEMENT\";\n return AIActionType;\n}({});\nasync function callAiFn(msgs, AIActionTypeValue) {\n const jsonObject = await callToGetJSONObject(msgs, AIActionTypeValue);\n return {\n content: jsonObject.content,\n usage: jsonObject.usage\n };\n}\nconst defaultBboxSize = 20;\nconst debugInspectUtils = getDebug('ai:common');\nfunction fillBboxParam(locate, width, height) {\n if (locate.bbox_2d && !(null == locate ? void 0 : locate.bbox)) {\n locate.bbox = locate.bbox_2d;\n delete locate.bbox_2d;\n }\n if (null == locate ? void 0 : locate.bbox) locate.bbox = adaptBbox(locate.bbox, width, height);\n return locate;\n}\nfunction adaptQwenBbox(bbox) {\n if (bbox.length < 2) {\n const msg = `invalid bbox data for qwen-vl mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n }\n const result = [\n Math.round(bbox[0]),\n Math.round(bbox[1]),\n 'number' == typeof bbox[2] ? Math.round(bbox[2]) : Math.round(bbox[0] + defaultBboxSize),\n 'number' == typeof bbox[3] ? Math.round(bbox[3]) : Math.round(bbox[1] + defaultBboxSize)\n ];\n return result;\n}\nfunction adaptDoubaoBbox(bbox, width, height) {\n assert(width > 0 && height > 0, 'width and height must be greater than 0 in doubao mode');\n if ('string' == typeof bbox) {\n assert(/^(\\d+)\\s(\\d+)\\s(\\d+)\\s(\\d+)$/.test(bbox.trim()), `invalid bbox data string for doubao-vision mode: ${bbox}`);\n const splitted = bbox.split(' ');\n if (4 === splitted.length) return [\n Math.round(Number(splitted[0]) * width / 1000),\n Math.round(Number(splitted[1]) * height / 1000),\n Math.round(Number(splitted[2]) * width / 1000),\n Math.round(Number(splitted[3]) * height / 1000)\n ];\n throw new Error(`invalid bbox data string for doubao-vision mode: ${bbox}`);\n }\n if (Array.isArray(bbox) && Array.isArray(bbox[0])) bbox = bbox[0];\n let bboxList = [];\n if (Array.isArray(bbox) && 'string' == typeof bbox[0]) bbox.forEach((item)=>{\n if ('string' == typeof item && item.includes(',')) {\n const [x, y] = item.split(',');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else if ('string' == typeof item && item.includes(' ')) {\n const [x, y] = item.split(' ');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else bboxList.push(Number(item));\n });\n else bboxList = bbox;\n if (4 === bboxList.length || 5 === bboxList.length) return [\n Math.round(bboxList[0] * width / 1000),\n Math.round(bboxList[1] * height / 1000),\n Math.round(bboxList[2] * width / 1000),\n Math.round(bboxList[3] * height / 1000)\n ];\n if (6 === bboxList.length || 2 === bboxList.length || 3 === bboxList.length || 7 === bboxList.length) return [\n Math.max(0, Math.round(bboxList[0] * width / 1000) - defaultBboxSize / 2),\n Math.max(0, Math.round(bboxList[1] * height / 1000) - defaultBboxSize / 2),\n Math.min(width, Math.round(bboxList[0] * width / 1000) + defaultBboxSize / 2),\n Math.min(height, Math.round(bboxList[1] * height / 1000) + defaultBboxSize / 2)\n ];\n if (8 === bbox.length) return [\n Math.round(bboxList[0] * width / 1000),\n Math.round(bboxList[1] * height / 1000),\n Math.round(bboxList[4] * width / 1000),\n Math.round(bboxList[5] * height / 1000)\n ];\n const msg = `invalid bbox data for doubao-vision mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n}\nfunction adaptBbox(bbox, width, height) {\n if ('doubao-vision' === vlLocateMode() || 'vlm-ui-tars' === vlLocateMode()) return adaptDoubaoBbox(bbox, width, height);\n if ('gemini' === vlLocateMode()) return adaptGeminiBbox(bbox, width, height);\n return adaptQwenBbox(bbox);\n}\nfunction adaptGeminiBbox(bbox, width, height) {\n const left = Math.round(bbox[1] * width / 1000);\n const top = Math.round(bbox[0] * height / 1000);\n const right = Math.round(bbox[3] * width / 1000);\n const bottom = Math.round(bbox[2] * height / 1000);\n return [\n left,\n top,\n right,\n bottom\n ];\n}\nfunction adaptBboxToRect(bbox, width, height, offsetX = 0, offsetY = 0) {\n debugInspectUtils('adaptBboxToRect', bbox, width, height, offsetX, offsetY);\n const [left, top, right, bottom] = adaptBbox(bbox, width, height);\n const rect = {\n left: left + offsetX,\n top: top + offsetY,\n width: right - left,\n height: bottom - top\n };\n debugInspectUtils('adaptBboxToRect, result=', rect);\n return rect;\n}\nlet warned = false;\nfunction warnGPT4oSizeLimit(size) {\n var _getModelName;\n if (warned) return;\n if (null == (_getModelName = getModelName()) ? void 0 : _getModelName.toLowerCase().includes('gpt-4o')) {\n const warningMsg = `GPT-4o has a maximum image input size of 2000x768 or 768x2000, but got ${size.width}x${size.height}. Please set your page to a smaller resolution. Otherwise, the result may be inaccurate.`;\n if (Math.max(size.width, size.height) > 2000 || Math.min(size.width, size.height) > 768) {\n console.warn(warningMsg);\n warned = true;\n }\n } else if (size.width > 1800 || size.height > 1800) {\n console.warn(`The image size seems too large (${size.width}x${size.height}). It may lead to more token usage, slower response, and inaccurate result.`);\n warned = true;\n }\n}\nfunction mergeRects(rects) {\n const minLeft = Math.min(...rects.map((r)=>r.left));\n const minTop = Math.min(...rects.map((r)=>r.top));\n const maxRight = Math.max(...rects.map((r)=>r.left + r.width));\n const maxBottom = Math.max(...rects.map((r)=>r.top + r.height));\n return {\n left: minLeft,\n top: minTop,\n width: maxRight - minLeft,\n height: maxBottom - minTop\n };\n}\nfunction expandSearchArea(rect, screenSize) {\n const minEdgeSize = 'doubao-vision' === vlLocateMode() ? 500 : 300;\n const defaultPadding = 160;\n const paddingSizeHorizontal = rect.width < minEdgeSize ? Math.ceil((minEdgeSize - rect.width) / 2) : defaultPadding;\n const paddingSizeVertical = rect.height < minEdgeSize ? Math.ceil((minEdgeSize - rect.height) / 2) : defaultPadding;\n rect.left = Math.max(0, rect.left - paddingSizeHorizontal);\n rect.width = Math.min(rect.width + 2 * paddingSizeHorizontal, screenSize.width - rect.left);\n rect.top = Math.max(0, rect.top - paddingSizeVertical);\n rect.height = Math.min(rect.height + 2 * paddingSizeVertical, screenSize.height - rect.top);\n return rect;\n}\nasync function markupImageForLLM(screenshotBase64, tree, size) {\n const elementsInfo = treeToList(tree);\n const elementsPositionInfoWithoutText = elementsInfo.filter((elementInfo)=>{\n if (elementInfo.attributes.nodeType === NodeType.TEXT) return false;\n return true;\n });\n const imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n elementsPositionInfo: elementsPositionInfoWithoutText,\n size\n });\n return imagePayload;\n}\nfunction buildYamlFlowFromPlans(plans, sleep) {\n const flow = [];\n for (const plan of plans){\n var _plan_locate;\n const type = plan.type;\n const locate = null == (_plan_locate = plan.locate) ? void 0 : _plan_locate.prompt;\n if ('Tap' === type) flow.push({\n aiTap: locate\n });\n else if ('Hover' === type) flow.push({\n aiHover: locate\n });\n else if ('Input' === type) {\n const param = plan.param;\n flow.push({\n aiInput: param.value,\n locate\n });\n } else if ('KeyboardPress' === type) {\n const param = plan.param;\n flow.push({\n aiKeyboardPress: param.value,\n locate\n });\n } else if ('Scroll' === type) {\n const param = plan.param;\n flow.push({\n aiScroll: null,\n locate,\n direction: param.direction,\n scrollType: param.scrollType,\n distance: param.distance\n });\n } else if ('Sleep' === type) {\n const param = plan.param;\n flow.push({\n sleep: param.timeMs\n });\n } else 'AndroidBackButton' === type || 'AndroidHomeButton' === type || 'AndroidRecentAppsButton' === type || 'AndroidLongPress' === type || 'AndroidPull' === type || 'Error' === type || 'Assert' === type || 'AssertWithoutThrow' === type || 'Finished' === type || console.warn(`Cannot convert action ${type} to yaml flow. This should be a bug of Midscene.`);\n }\n if (sleep) flow.push({\n sleep: sleep\n });\n return flow;\n}\nconst defaultAssertionPrompt = 'You are a senior testing engineer. User will give an assertion and a screenshot of a page. By carefully viewing the screenshot, please tell whether the assertion is truthy.';\nconst defaultAssertionResponseJsonFormat = `Return in the following JSON format:\n{\n pass: boolean, // whether the assertion is truthy\n thought: string | null, // string, if the result is falsy, give the reason why it is falsy. Otherwise, put null.\n}`;\nconst getUiTarsAssertionResponseJsonFormat = ()=>`## Output Json String Format\n\\`\\`\\`\n\"{\n \"pass\": <<is a boolean value from the enum [true, false], true means the assertion is truthy>>, \n \"thought\": \"<<is a string, give the reason why the assertion is falsy or truthy. Otherwise.>>\"\n}\"\n\\`\\`\\`\n\n## Rules **MUST** follow\n- Make sure to return **only** the JSON, with **no additional** text or explanations.\n- Use ${getPreferredLanguage()} in \\`thought\\` part.\n- You **MUST** strictly follow up the **Output Json String Format**.`;\nfunction systemPromptToAssert(model) {\n return `${defaultAssertionPrompt}\n\n${model.isUITars ? getUiTarsAssertionResponseJsonFormat() : defaultAssertionResponseJsonFormat}`;\n}\nconst assertSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'assert',\n strict: true,\n schema: {\n type: 'object',\n properties: {\n pass: {\n type: 'boolean',\n description: 'Whether the assertion passed or failed'\n },\n thought: {\n type: [\n 'string',\n 'null'\n ],\n description: 'The thought process behind the assertion'\n }\n },\n required: [\n 'pass',\n 'thought'\n ],\n additionalProperties: false\n }\n }\n};\nfunction bboxDescription(vlMode) {\n if ('gemini' === vlMode) return '2d bounding box as [ymin, xmin, ymax, xmax]';\n return '2d bounding box as [xmin, ymin, xmax, ymax]';\n}\nfunction systemPromptToLocateElement(vlMode) {\n if (vlMode) {\n const bboxComment = bboxDescription(vlMode);\n return `\n## Role:\nYou are an expert in software testing.\n\n## Objective:\n- Identify elements in screenshots and text that match the user's description.\n- Give the coordinates of the element that matches the user's description best in the screenshot.\n- Determine whether the user's description is order-sensitive (e.g., contains phrases like 'the third item in the list', 'the last button', etc.).\n\n## Output Format:\n\\`\\`\\`json\n{\n \"bbox\": [number, number, number, number], // ${bboxComment}\n \"errors\"?: string[],\n \"isOrderSensitive\": boolean // Whether the targetElementDescription is order-sensitive (true/false)\n}\n\\`\\`\\`\n\nFields:\n* \\`bbox\\` is the bounding box of the element that matches the user's description best in the screenshot\n* \\`isOrderSensitive\\` is a boolean indicating whether the user's description is order-sensitive (true/false)\n* \\`errors\\` is an optional array of error messages (if any)\n\nOrder-sensitive means the description contains phrases like:\n- \"the third item in the list\"\n- \"the last button\"\n- \"the first input box\"\n- \"the second row\"\n\nNot order-sensitive means the description is like:\n- \"confirm button\"\n- \"search box\"\n- \"password input\"\n\nFor example, when an element is found and the description is order-sensitive:\n\\`\\`\\`json\n{\n \"bbox\": [100, 100, 200, 200],\n \"isOrderSensitive\": true,\n \"errors\": []\n}\n\\`\\`\\`\n\nWhen no element is found and the description is not order-sensitive:\n\\`\\`\\`json\n{\n \"bbox\": [],\n \"isOrderSensitive\": false,\n \"errors\": [\"I can see ..., but {some element} is not found\"]\n}\n\\`\\`\\`\n`;\n }\n return `\n## Role:\nYou are an expert in software page image (2D) and page element text analysis.\n\n## Objective:\n- Identify elements in screenshots and text that match the user's description.\n- Return JSON data containing the selection reason and element ID.\n- Determine whether the user's description is order-sensitive (e.g., contains phrases like 'the third item in the list', 'the last button', etc.).\n\n## Skills:\n- Image analysis and recognition\n- Multilingual text understanding\n- Software UI design and testing\n\n## Workflow:\n1. Receive the user's element description, screenshot, and element description information. Note that the text may contain non-English characters (e.g., Chinese), indicating that the application may be non-English.\n2. Based on the user's description, locate the target element ID in the list of element descriptions and the screenshot.\n3. Found the required number of elements\n4. Return JSON data containing the selection reason and element ID.\n5. Judge whether the user's description is order-sensitive (see below for definition and examples).\n\n## Constraints:\n- Strictly adhere to the specified location when describing the required element; do not select elements from other locations.\n- Elements in the image with NodeType other than \"TEXT Node\" have been highlighted to identify the element among multiple non-text elements.\n- Accurately identify element information based on the user's description and return the corresponding element ID from the element description information, not extracted from the image.\n- If no elements are found, the \"elements\" array should be empty.\n- The returned data must conform to the specified JSON format.\n- The returned value id information must use the id from element info (important: **use id not indexId, id is hash content**)\n\n## Order-Sensitive Definition:\n- If the description contains phrases like \"the third item in the list\", \"the last button\", \"the first input box\", \"the second row\", etc., it is order-sensitive (isOrderSensitive = true).\n- If the description is like \"confirm button\", \"search box\", \"password input\", etc., it is not order-sensitive (isOrderSensitive = false).\n\n## Output Format:\n\nPlease return the result in JSON format as follows:\n\n\\`\\`\\`json\n{\n \"elements\": [\n // If no matching elements are found, return an empty array []\n {\n \"reason\": \"PLACEHOLDER\", // The thought process for finding the element, replace PLACEHOLDER with your thought process\n \"text\": \"PLACEHOLDER\", // Replace PLACEHOLDER with the text of elementInfo, if none, leave empty\n \"id\": \"PLACEHOLDER\" // Replace PLACEHOLDER with the ID (important: **use id not indexId, id is hash content**) of elementInfo\n }\n // More elements...\n ],\n \"isOrderSensitive\": true, // or false, depending on the user's description\n \"errors\": [] // Array of strings containing any error messages\n}\n\\`\\`\\`\n\n## Example:\nExample 1:\nInput Example:\n\\`\\`\\`json\n// Description: \"Shopping cart icon in the upper right corner\"\n{\n \"description\": \"PLACEHOLDER\", // Description of the target element\n \"screenshot\": \"path/screenshot.png\",\n \"text\": '{\n \"pageSize\": {\n \"width\": 400, // Width of the page\n \"height\": 905 // Height of the page\n },\n \"elementInfos\": [\n {\n \"id\": \"1231\", // ID of the element\n \"indexId\": \"0\", // Index of the element\\u{FF0C}The image is labeled to the left of the element\n \"attributes\": { // Attributes of the element\n \"nodeType\": \"IMG Node\", // Type of element, types include: TEXT Node, IMG Node, BUTTON Node, INPUT Node\n \"src\": \"https://ap-southeast-3.m\",\n \"class\": \".img\"\n },\n \"content\": \"\", // Text content of the element\n \"rect\": {\n \"left\": 280, // Distance from the left side of the page\n \"top\": 8, // Distance from the top of the page\n \"width\": 44, // Width of the element\n \"height\": 44 // Height of the element\n }\n },\n {\n \"id\": \"66551\", // ID of the element\n \"indexId\": \"1\", // Index of the element,The image is labeled to the left of the element\n \"attributes\": { // Attributes of the element\n \"nodeType\": \"IMG Node\", // Type of element, types include: TEXT Node, IMG Node, BUTTON Node, INPUT Node\n \"src\": \"data:image/png;base64,iVBORw0KGgoAAAANSU...\",\n \"class\": \".icon\"\n },\n \"content\": \"\", // Text content of the element\n \"rect\": {\n \"left\": 350, // Distance from the left side of the page\n \"top\": 16, // Distance from the top of the page\n \"width\": 25, // Width of the element\n \"height\": 25 // Height of the element\n }\n },\n ...\n {\n \"id\": \"12344\",\n \"indexId\": \"2\", // Index of the element\\u{FF0C}The image is labeled to the left of the element\n \"attributes\": {\n \"nodeType\": \"TEXT Node\",\n \"class\": \".product-name\"\n },\n \"center\": [\n 288,\n 834\n ],\n \"content\": \"Mango Drink\",\n \"rect\": {\n \"left\": 188,\n \"top\": 827,\n \"width\": 199,\n \"height\": 13\n }\n },\n ...\n ]\n }\n '\n}\n\\`\\`\\`\nOutput Example:\n\\`\\`\\`json\n{\n \"elements\": [\n {\n // Describe the reason for finding this element, replace with actual value in practice\n \"reason\": \"Reason for finding element 4: It is located in the upper right corner, is an image type, and according to the screenshot, it is a shopping cart icon button\",\n \"text\": \"\",\n // ID(**use id not indexId**) of this element, replace with actual value in practice, **use id not indexId**\n \"id\": \"1231\"\n }\n ],\n \"isOrderSensitive\": true,\n \"errors\": []\n}\n\\`\\`\\`\n \n `;\n}\nconst locatorSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'find_elements',\n strict: true,\n schema: {\n type: 'object',\n properties: {\n elements: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n reason: {\n type: 'string',\n description: 'Reason for finding this element'\n },\n text: {\n type: 'string',\n description: 'Text content of the element'\n },\n id: {\n type: 'string',\n description: 'ID of this element'\n }\n },\n required: [\n 'reason',\n 'text',\n 'id'\n ],\n additionalProperties: false\n },\n description: 'List of found elements'\n },\n isOrderSensitive: {\n type: 'boolean',\n description: \"Whether the targetElementDescription is order-sensitive (true/false)\"\n },\n errors: {\n type: 'array',\n items: {\n type: 'string'\n },\n description: 'List of error messages, if any'\n }\n },\n required: [\n 'elements',\n 'isOrderSensitive',\n 'errors'\n ],\n additionalProperties: false\n }\n }\n};\nconst findElementPrompt = new PromptTemplate({\n template: `\nHere is the item user want to find:\n=====================================\n{targetElementDescription}\n=====================================\n\n{pageDescription}\n `,\n inputVariables: [\n \"pageDescription\",\n \"targetElementDescription\"\n ]\n});\nconst vlCoTLog = '\"what_the_user_wants_to_do_next_by_instruction\": string, // What the user wants to do according to the instruction and previous logs. ';\nconst vlCurrentLog = '\"log\": string, // Log what the next one action (ONLY ONE!) you can do according to the screenshot and the instruction. The typical log looks like \"Now i want to use action \\'{ action-type }\\' to do .. first\". If no action should be done, log the reason. \". Use the same language as the user\\'s instruction.';\nconst llmCurrentLog = '\"log\": string, // Log what the next actions you can do according to the screenshot and the instruction. The typical log looks like \"Now i want to use action \\'{ action-type }\\' to do ..\". If no action should be done, log the reason. \". Use the same language as the user\\'s instruction.';\nconst commonOutputFields = `\"error\"?: string, // Error messages about unexpected situations, if any. Only think it is an error when the situation is not foreseeable according to the instruction. Use the same language as the user's instruction.\n \"more_actions_needed_by_instruction\": boolean, // Consider if there is still more action(s) to do after the action in \"Log\" is done, according to the instruction. If so, set this field to true. Otherwise, set it to false.`;\nconst vlLocateParam = (required)=>`locate${required ? '' : '?'}: {bbox: [number, number, number, number], prompt: string }`;\nconst llmLocateParam = (required)=>`locate${required ? '' : '?'}: {\"id\": string, \"prompt\": string}`;\nconst descriptionForAction = (action, locatorScheme)=>{\n const tab = ' ';\n let locateParam = '';\n if ('required' === action.location) locateParam = locatorScheme;\n else if ('optional' === action.location) locateParam = `${locatorScheme} | null`;\n else if (false === action.location) locateParam = '';\n const locatorParam = locateParam ? `- ${locateParam}` : '';\n if (action.whatToLocate) if (locateParam) locateParam += ` // ${action.whatToLocate}`;\n else console.warn(`whatToLocate is provided for action ${action.name}, but location is not required or optional. The whatToLocate will be ignored.`);\n let paramSchema = '';\n if (action.paramSchema) paramSchema = `- param: ${action.paramSchema}`;\n if (action.paramDescription) {\n node_assert(paramSchema, `paramSchema is required when paramDescription is provided for action ${action.name}, but got ${action.paramSchema}`);\n paramSchema += ` // ${action.paramDescription}`;\n }\n const fields = [\n paramSchema,\n locatorParam\n ].filter(Boolean);\n return `- ${action.name}, ${action.description}\n${tab}- type: \"${action.name}\"\n${tab}${fields.join(`\\n${tab}`)}\n`.trim();\n};\nconst systemTemplateOfVLPlanning = ({ actionSpace, vlMode })=>{\n const actionNameList = actionSpace.map((action)=>action.name).join(', ');\n const actionDescriptionList = actionSpace.map((action)=>descriptionForAction(action, vlLocateParam('required' === action.location)));\n const actionList = actionDescriptionList.join('\\n');\n return `\nTarget: User will give you a screenshot, an instruction and some previous logs indicating what have been done. Please tell what the next one action is (or null if no action should be done) to do the tasks the instruction requires. \n\nRestriction:\n- Don't give extra actions or plans beyond the instruction. ONLY plan for what the instruction requires. For example, don't try to submit the form if the instruction is only to fill something.\n- Always give ONLY ONE action in \\`log\\` field (or null if no action should be done), instead of multiple actions. Supported actions are ${actionNameList}.\n- Don't repeat actions in the previous logs.\n- Bbox is the bounding box of the element to be located. It's an array of 4 numbers, representing ${bboxDescription(vlMode)}.\n\nSupporting actions:\n${actionList}\n\nField description:\n* The \\`prompt\\` field inside the \\`locate\\` field is a short description that could be used to locate the element.\n\nReturn in JSON format:\n{\n ${vlCoTLog}\n ${vlCurrentLog}\n ${commonOutputFields}\n \"action\": \n {\n // one of the supporting actions\n } | null,\n ,\n \"sleep\"?: number, // The sleep time after the action, in milliseconds.\n}\n\nFor example, when the instruction is \"click 'Confirm' button, and click 'Yes' in popup\" and the log is \"I will use action Tap to click 'Confirm' button\", by viewing the screenshot and previous logs, you should consider: We have already clicked the 'Confirm' button, so next we should find and click 'Yes' in popup.\n\nthis and output the JSON:\n\n{\n \"what_the_user_wants_to_do_next_by_instruction\": \"We have already clicked the 'Confirm' button, so next we should find and click 'Yes' in popup\",\n \"log\": \"I will use action Tap to click 'Yes' in popup\",\n \"more_actions_needed_by_instruction\": false,\n \"action\": {\n \"type\": \"Tap\",\n \"locate\": {\n \"bbox\": [100, 100, 200, 200],\n \"prompt\": \"The 'Yes' button in popup\"\n }\n }\n}\n`;\n};\nconst systemTemplateOfLLM = ({ actionSpace })=>{\n const actionNameList = actionSpace.map((action)=>action.name).join(' / ');\n const actionDescriptionList = actionSpace.map((action)=>descriptionForAction(action, llmLocateParam('required' === action.location)));\n const actionList = actionDescriptionList.join('\\n');\n return `\n## Role\n\nYou are a versatile professional in software UI automation. Your outstanding contributions will impact the user experience of billions of users.\n\n## Objective\n\n- Decompose the instruction user asked into a series of actions\n- Locate the target element if possible\n- If the instruction cannot be accomplished, give a further plan.\n\n## Workflow\n\n1. Receive the screenshot, element description of screenshot(if any), user's instruction and previous logs.\n2. Decompose the user's task into a sequence of feasible actions, and place it in the \\`actions\\` field. There are different types of actions (${actionNameList}). The \"About the action\" section below will give you more details.\n3. Consider whether the user's instruction will be accomplished after the actions you composed.\n- If the instruction is accomplished, set \\`more_actions_needed_by_instruction\\` to false.\n- If more actions are needed, set \\`more_actions_needed_by_instruction\\` to true. Get ready to hand over to the next talent people like you. Carefully log what have been done in the \\`log\\` field, he or she will continue the task according to your logs.\n4. If the task is not feasible on this page, set \\`error\\` field to the reason.\n\n## Constraints\n\n- All the actions you composed MUST be feasible, which means all the action fields can be filled with the page context information you get. If not, don't plan this action.\n- Trust the \"What have been done\" field about the task (if any), don't repeat actions in it.\n- Respond only with valid JSON. Do not write an introduction or summary or markdown prefix like \\`\\`\\`json\\`\\`\\`.\n- If the screenshot and the instruction are totally irrelevant, set reason in the \\`error\\` field.\n\n## About the \\`actions\\` field\n\nThe \\`locate\\` param is commonly used in the \\`param\\` field of the action, means to locate the target element to perform the action, it conforms to the following scheme:\n\ntype LocateParam = {\n \"id\": string, // the id of the element found. It should either be the id marked with a rectangle in the screenshot or the id described in the description.\n \"prompt\"?: string // the description of the element to find. It can only be omitted when locate is null.\n} | null // If it's not on the page, the LocateParam should be null\n\n## Supported actions\n\nEach action has a \\`type\\` and corresponding \\`param\\`. To be detailed:\n${actionList}\n\n`.trim();\n};\nconst outputTemplate = `\n## Output JSON Format:\n\nThe JSON format is as follows:\n\n{\n \"actions\": [\n // ... some actions\n ],\n ${llmCurrentLog}\n ${commonOutputFields}\n}\n\n## Examples\n\n### Example: Decompose a task\n\nWhen you received the following information:\n\n* Instruction: 'Click the language switch button, wait 1s, click \"English\"'\n* Logs: null\n* Page Context (screenshot and description) shows: There is a language switch button, and the \"English\" option is not shown in the screenshot now.\n\nBy viewing the page screenshot and description, you should consider this and output the JSON:\n\n* The user intent is: tap the switch button, sleep, and tap the 'English' option\n* The language switch button is shown in the screenshot, and can be located by the page description or the id marked with a rectangle. So we can plan a Tap action to do this.\n* Plan a Sleep action to wait for 1 second to ensure the language options are displayed.\n* The \"English\" option button is not shown in the screenshot now, it means it may only show after the previous actions are finished. So don't plan any action to do this.\n* Log what these action do: Click the language switch button to open the language options. Wait for 1 second.\n* The task cannot be accomplished (because the last tapping action is not finished yet), so the \\`more_actions_needed_by_instruction\\` field is true. The \\`error\\` field is null.\n\n{\n \"actions\":[\n {\n \"thought\": \"Click the language switch button to open the language options.\",\n \"type\": \"Tap\", \n \"param\": null,\n \"locate\": { id: \"c81c4e9a33\", prompt: \"The language switch button\" }},\n },\n {\n \"thought\": \"Wait for 1 second to ensure the language options are displayed.\",\n \"type\": \"Sleep\",\n \"param\": { \"timeMs\": 1000 },\n }\n ],\n \"error\": null,\n \"more_actions_needed_by_instruction\": true,\n \"log\": \"Click the language switch button to open the language options. Wait for 1 second\",\n}\n\n### Example: What NOT to do\nWrong output:\n{\n \"actions\":[\n {\n \"thought\": \"Click the language switch button to open the language options.\",\n \"type\": \"Tap\",\n \"param\": null,\n \"locate\": {\n { \"id\": \"c81c4e9a33\" }, // WRONG: prompt is missing, this is not a valid LocateParam\n }\n },\n {\n \"thought\": \"Click the English option\",\n \"type\": \"Tap\", \n \"param\": null,\n \"locate\": null, // This means the 'English' option is not shown in the screenshot, the task cannot be accomplished\n }\n ],\n \"more_actions_needed_by_instruction\": false, // WRONG: should be true\n \"log\": \"Click the language switch button to open the language options\",\n}\n`;\nasync function systemPromptToTaskPlanning({ actionSpace, vlMode }) {\n if (vlMode) return systemTemplateOfVLPlanning({\n actionSpace,\n vlMode\n });\n return `${systemTemplateOfLLM({\n actionSpace\n })}\\n\\n${outputTemplate}`;\n}\nconst planSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'action_items',\n strict: false,\n schema: {\n type: 'object',\n strict: false,\n properties: {\n actions: {\n type: 'array',\n items: {\n type: 'object',\n strict: false,\n properties: {\n thought: {\n type: 'string',\n description: 'Reasons for generating this task, and why this task is feasible on this page'\n },\n type: {\n type: 'string',\n description: 'Type of action'\n },\n param: {\n anyOf: [\n {\n type: 'null'\n },\n {\n type: 'object',\n additionalProperties: true\n }\n ],\n description: 'Parameter of the action'\n },\n locate: {\n type: [\n 'object',\n 'null'\n ],\n properties: {\n id: {\n type: 'string'\n },\n prompt: {\n type: 'string'\n }\n },\n required: [\n 'id',\n 'prompt'\n ],\n additionalProperties: false,\n description: 'Location information for the target element'\n }\n },\n required: [\n 'thought',\n 'type',\n 'param',\n 'locate'\n ],\n additionalProperties: false\n },\n description: 'List of actions to be performed'\n },\n more_actions_needed_by_instruction: {\n type: 'boolean',\n description: 'If all the actions described in the instruction have been covered by this action and logs, set this field to false.'\n },\n log: {\n type: 'string',\n description: 'Log what these planned actions do. Do not include further actions that have not been planned.'\n },\n error: {\n type: [\n 'string',\n 'null'\n ],\n description: 'Error messages about unexpected situations'\n }\n },\n required: [\n 'actions',\n 'more_actions_needed_by_instruction',\n 'log',\n 'error'\n ],\n additionalProperties: false\n }\n }\n};\nconst generateTaskBackgroundContext = (userInstruction, log, userActionContext)=>{\n if (log) return `\nHere is the user's instruction:\n\n<instruction>\n <high_priority_knowledge>\n ${userActionContext}\n </high_priority_knowledge>\n\n ${userInstruction}\n</instruction>\n\nThese are the logs from previous executions, which indicate what was done in the previous actions.\nDo NOT repeat these actions.\n<previous_logs>\n${log}\n</previous_logs>\n`;\n return `\nHere is the user's instruction:\n<instruction>\n <high_priority_knowledge>\n ${userActionContext}\n </high_priority_knowledge>\n\n ${userInstruction}\n</instruction>\n`;\n};\nconst automationUserPrompt = (vlMode)=>{\n if (vlMode) return new PromptTemplate({\n template: '{taskBackgroundContext}',\n inputVariables: [\n 'taskBackgroundContext'\n ]\n });\n return new PromptTemplate({\n template: `\npageDescription:\n=====================================\n{pageDescription}\n=====================================\n\n{taskBackgroundContext}`,\n inputVariables: [\n \"pageDescription\",\n 'taskBackgroundContext'\n ]\n });\n};\nfunction checkAIConfig() {\n const openaiKey = getAIConfig(OPENAI_API_KEY);\n const azureConfig = getAIConfig(MIDSCENE_USE_AZURE_OPENAI);\n const anthropicKey = getAIConfig(ANTHROPIC_API_KEY);\n const initConfigJson = getAIConfig(MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n if (openaiKey) return true;\n if (azureConfig) return true;\n if (anthropicKey) return true;\n return Boolean(initConfigJson);\n}\nlet debugConfigInitialized = false;\nfunction initDebugConfig() {\n if (debugConfigInitialized) return;\n const shouldPrintTiming = getAIConfigInBoolean(MIDSCENE_DEBUG_AI_PROFILE);\n let debugConfig = '';\n if (shouldPrintTiming) {\n console.warn('MIDSCENE_DEBUG_AI_PROFILE is deprecated, use DEBUG=midscene:ai:profile instead');\n debugConfig = 'ai:profile';\n }\n const shouldPrintAIResponse = getAIConfigInBoolean(MIDSCENE_DEBUG_AI_RESPONSE);\n if (shouldPrintAIResponse) {\n console.warn('MIDSCENE_DEBUG_AI_RESPONSE is deprecated, use DEBUG=midscene:ai:response instead');\n debugConfig = debugConfig ? 'ai:*' : 'ai:call';\n }\n if (debugConfig) enableDebug(debugConfig);\n debugConfigInitialized = true;\n}\nconst defaultModel = 'gpt-4o';\nfunction getModelName() {\n let modelName = defaultModel;\n const nameInConfig = getAIConfig(MIDSCENE_MODEL_NAME);\n if (nameInConfig) modelName = nameInConfig;\n return modelName;\n}\nasync function createChatClient({ AIActionTypeValue }) {\n initDebugConfig();\n let openai;\n const extraConfig = getAIConfigInJson(MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n const socksProxy = getAIConfig(MIDSCENE_OPENAI_SOCKS_PROXY);\n const httpProxy = getAIConfig(MIDSCENE_OPENAI_HTTP_PROXY);\n let proxyAgent;\n const debugProxy = getDebug('ai:call:proxy');\n if (httpProxy) {\n debugProxy('using http proxy', httpProxy);\n proxyAgent = new HttpsProxyAgent(httpProxy);\n } else if (socksProxy) {\n debugProxy('using socks proxy', socksProxy);\n proxyAgent = new SocksProxyAgent(socksProxy);\n }\n if (getAIConfig(OPENAI_USE_AZURE)) openai = new AzureOpenAI({\n baseURL: getAIConfig(OPENAI_BASE_URL),\n apiKey: getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n dangerouslyAllowBrowser: true\n });\n else if (getAIConfig(MIDSCENE_USE_AZURE_OPENAI)) {\n const extraAzureConfig = getAIConfigInJson(MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON);\n const scope = getAIConfig(MIDSCENE_AZURE_OPENAI_SCOPE);\n let tokenProvider;\n if (scope) {\n assert(!ifInBrowser, 'Azure OpenAI is not supported in browser with Midscene.');\n const credential = new DefaultAzureCredential();\n assert(scope, 'MIDSCENE_AZURE_OPENAI_SCOPE is required');\n tokenProvider = getBearerTokenProvider(credential, scope);\n openai = new AzureOpenAI({\n azureADTokenProvider: tokenProvider,\n endpoint: getAIConfig(AZURE_OPENAI_ENDPOINT),\n apiVersion: getAIConfig(AZURE_OPENAI_API_VERSION),\n deployment: getAIConfig(AZURE_OPENAI_DEPLOYMENT),\n ...extraConfig,\n ...extraAzureConfig\n });\n } else openai = new AzureOpenAI({\n apiKey: getAIConfig(AZURE_OPENAI_KEY),\n endpoint: getAIConfig(AZURE_OPENAI_ENDPOINT),\n apiVersion: getAIConfig(AZURE_OPENAI_API_VERSION),\n deployment: getAIConfig(AZURE_OPENAI_DEPLOYMENT),\n dangerouslyAllowBrowser: true,\n ...extraConfig,\n ...extraAzureConfig\n });\n } else if (!getAIConfig(MIDSCENE_USE_ANTHROPIC_SDK)) {\n const baseURL = getAIConfig(OPENAI_BASE_URL);\n if ('string' == typeof baseURL) {\n if (!/^https?:\\/\\//.test(baseURL)) throw new Error(`OPENAI_BASE_URL must be a valid URL starting with http:// or https://, but got: ${baseURL}\\nPlease check your config.`);\n }\n openai = new openai_0({\n baseURL: getAIConfig(OPENAI_BASE_URL),\n apiKey: getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n defaultHeaders: {\n ...(null == extraConfig ? void 0 : extraConfig.defaultHeaders) || {},\n [MIDSCENE_API_TYPE]: AIActionTypeValue.toString()\n },\n dangerouslyAllowBrowser: true\n });\n }\n if (openai && getAIConfigInBoolean(MIDSCENE_LANGSMITH_DEBUG)) {\n if (ifInBrowser) throw new Error('langsmith is not supported in browser');\n console.log('DEBUGGING MODE: langsmith wrapper enabled');\n const { wrapOpenAI } = await import(\"langsmith/wrappers\");\n openai = wrapOpenAI(openai);\n }\n if (void 0 !== openai) return {\n completion: openai.chat.completions,\n style: 'openai'\n };\n if (getAIConfig(MIDSCENE_USE_ANTHROPIC_SDK)) {\n const apiKey = getAIConfig(ANTHROPIC_API_KEY);\n assert(apiKey, 'ANTHROPIC_API_KEY is required');\n openai = new Anthropic({\n apiKey,\n httpAgent: proxyAgent,\n dangerouslyAllowBrowser: true\n });\n }\n if (void 0 !== openai && openai.messages) return {\n completion: openai.messages,\n style: 'anthropic'\n };\n throw new Error('Openai SDK or Anthropic SDK is not initialized');\n}\nasync function service_caller_call(messages, AIActionTypeValue, responseFormat, options) {\n assert(checkAIConfig(), 'Cannot find config for AI model service. If you are using a self-hosted model without validating the API key, please set `OPENAI_API_KEY` to any non-null value. https://midscenejs.com/model-provider.html');\n const { completion, style } = await createChatClient({\n AIActionTypeValue\n });\n const maxTokens = getAIConfig(OPENAI_MAX_TOKENS);\n const debugCall = getDebug('ai:call');\n const debugProfileStats = getDebug('ai:profile:stats');\n const debugProfileDetail = getDebug('ai:profile:detail');\n const startTime = Date.now();\n const model = getModelName();\n const isStreaming = (null == options ? void 0 : options.stream) && (null == options ? void 0 : options.onChunk);\n let content;\n let accumulated = '';\n let usage;\n let timeCost;\n const commonConfig = {\n temperature: 'vlm-ui-tars' === vlLocateMode() ? 0.0 : 0.1,\n stream: !!isStreaming,\n max_tokens: 'number' == typeof maxTokens ? maxTokens : Number.parseInt(maxTokens || '2048', 10),\n ...'qwen-vl' === vlLocateMode() ? {\n vl_high_resolution_images: true\n } : {}\n };\n try {\n if ('openai' === style) {\n debugCall(`sending ${isStreaming ? 'streaming ' : ''}request to ${model}`);\n if (isStreaming) {\n const stream = await completion.create({\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig\n }, {\n stream: true\n });\n for await (const chunk of stream){\n var _chunk_choices__delta, _chunk_choices_, _chunk_choices, _chunk_choices__delta1, _chunk_choices_1, _chunk_choices1, _chunk_choices_2, _chunk_choices2;\n const content = (null == (_chunk_choices = chunk.choices) ? void 0 : null == (_chunk_choices_ = _chunk_choices[0]) ? void 0 : null == (_chunk_choices__delta = _chunk_choices_.delta) ? void 0 : _chunk_choices__delta.content) || '';\n const reasoning_content = (null == (_chunk_choices1 = chunk.choices) ? void 0 : null == (_chunk_choices_1 = _chunk_choices1[0]) ? void 0 : null == (_chunk_choices__delta1 = _chunk_choices_1.delta) ? void 0 : _chunk_choices__delta1.reasoning_content) || '';\n if (chunk.usage) usage = chunk.usage;\n if (content || reasoning_content) {\n accumulated += content;\n const chunkData = {\n content,\n reasoning_content,\n accumulated,\n isComplete: false,\n usage: void 0\n };\n options.onChunk(chunkData);\n }\n if (null == (_chunk_choices2 = chunk.choices) ? void 0 : null == (_chunk_choices_2 = _chunk_choices2[0]) ? void 0 : _chunk_choices_2.finish_reason) {\n timeCost = Date.now() - startTime;\n if (!usage) {\n const estimatedTokens = Math.max(1, Math.floor(accumulated.length / 4));\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: 2 * estimatedTokens\n };\n }\n const finalChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: {\n prompt_tokens: usage.prompt_tokens ?? 0,\n completion_tokens: usage.completion_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n time_cost: timeCost ?? 0\n }\n };\n options.onChunk(finalChunk);\n break;\n }\n }\n content = accumulated;\n debugProfileStats(`streaming model, ${model}, mode, ${vlLocateMode() || 'default'}, cost-ms, ${timeCost}`);\n } else {\n var _result_usage, _result_usage1, _result_usage2;\n const result = await completion.create({\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig\n });\n timeCost = Date.now() - startTime;\n debugProfileStats(`model, ${model}, mode, ${vlLocateMode() || 'default'}, ui-tars-version, ${uiTarsModelVersion()}, prompt-tokens, ${(null == (_result_usage = result.usage) ? void 0 : _result_usage.prompt_tokens) || ''}, completion-tokens, ${(null == (_result_usage1 = result.usage) ? void 0 : _result_usage1.completion_tokens) || ''}, total-tokens, ${(null == (_result_usage2 = result.usage) ? void 0 : _result_usage2.total_tokens) || ''}, cost-ms, ${timeCost}, requestId, ${result._request_id || ''}`);\n debugProfileDetail(`model usage detail: ${JSON.stringify(result.usage)}`);\n assert(result.choices, `invalid response from LLM service: ${JSON.stringify(result)}`);\n content = result.choices[0].message.content;\n usage = result.usage;\n }\n debugCall(`response: ${content}`);\n assert(content, 'empty content');\n } else if ('anthropic' === style) {\n const convertImageContent = (content)=>{\n if ('image_url' === content.type) {\n const imgBase64 = content.image_url.url;\n assert(imgBase64, 'image_url is required');\n return {\n source: {\n type: 'base64',\n media_type: imgBase64.includes('data:image/png;base64,') ? 'image/png' : 'image/jpeg',\n data: imgBase64.split(',')[1]\n },\n type: 'image'\n };\n }\n return content;\n };\n if (isStreaming) {\n const stream = await completion.create({\n model,\n system: 'You are a versatile professional in software UI automation',\n messages: messages.map((m)=>({\n role: 'user',\n content: Array.isArray(m.content) ? m.content.map(convertImageContent) : m.content\n })),\n response_format: responseFormat,\n ...commonConfig\n });\n for await (const chunk of stream){\n var _chunk_delta;\n const content = (null == (_chunk_delta = chunk.delta) ? void 0 : _chunk_delta.text) || '';\n if (content) {\n accumulated += content;\n const chunkData = {\n content,\n accumulated,\n reasoning_content: '',\n isComplete: false,\n usage: void 0\n };\n options.onChunk(chunkData);\n }\n if ('message_stop' === chunk.type) {\n timeCost = Date.now() - startTime;\n const anthropicUsage = chunk.usage;\n const finalChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: anthropicUsage ? {\n prompt_tokens: anthropicUsage.input_tokens ?? 0,\n completion_tokens: anthropicUsage.output_tokens ?? 0,\n total_tokens: (anthropicUsage.input_tokens ?? 0) + (anthropicUsage.output_tokens ?? 0),\n time_cost: timeCost ?? 0\n } : void 0\n };\n options.onChunk(finalChunk);\n break;\n }\n }\n content = accumulated;\n } else {\n const result = await completion.create({\n model,\n system: 'You are a versatile professional in software UI automation',\n messages: messages.map((m)=>({\n role: 'user',\n content: Array.isArray(m.content) ? m.content.map(convertImageContent) : m.content\n })),\n response_format: responseFormat,\n ...commonConfig\n });\n timeCost = Date.now() - startTime;\n content = result.content[0].text;\n usage = result.usage;\n }\n assert(content, 'empty content');\n }\n if (isStreaming && !usage) {\n const estimatedTokens = Math.max(1, Math.floor((content || '').length / 4));\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: 2 * estimatedTokens\n };\n }\n return {\n content: content || '',\n usage: usage ? {\n prompt_tokens: usage.prompt_tokens ?? 0,\n completion_tokens: usage.completion_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n time_cost: timeCost ?? 0\n } : void 0,\n isStreamed: !!isStreaming\n };\n } catch (e) {\n console.error(' call AI error', e);\n const newError = new Error(`failed to call ${isStreaming ? 'streaming ' : ''}AI model service: ${e.message}. Trouble shooting: https://midscenejs.com/model-provider.html`, {\n cause: e\n });\n throw newError;\n }\n}\nasync function callToGetJSONObject(messages, AIActionTypeValue) {\n let responseFormat;\n const model = getModelName();\n if (model.includes('gpt-4')) switch(AIActionTypeValue){\n case common_AIActionType.ASSERT:\n responseFormat = assertSchema;\n break;\n case common_AIActionType.INSPECT_ELEMENT:\n responseFormat = locatorSchema;\n break;\n case common_AIActionType.PLAN:\n responseFormat = planSchema;\n break;\n case common_AIActionType.EXTRACT_DATA:\n case common_AIActionType.DESCRIBE_ELEMENT:\n responseFormat = {\n type: types_AIResponseFormat.JSON\n };\n break;\n }\n if ('gpt-4o-2024-05-13' === model) responseFormat = {\n type: types_AIResponseFormat.JSON\n };\n const response = await service_caller_call(messages, AIActionTypeValue, responseFormat);\n assert(response, 'empty response');\n const jsonContent = safeParseJson(response.content);\n return {\n content: jsonContent,\n usage: response.usage\n };\n}\nasync function callAiFnWithStringResponse(msgs, AIActionTypeValue) {\n const { content, usage } = await service_caller_call(msgs, AIActionTypeValue);\n return {\n content,\n usage\n };\n}\nfunction extractJSONFromCodeBlock(response) {\n try {\n const jsonMatch = response.match(/^\\s*(\\{[\\s\\S]*\\})\\s*$/);\n if (jsonMatch) return jsonMatch[1];\n const codeBlockMatch = response.match(/```(?:json)?\\s*(\\{[\\s\\S]*?\\})\\s*```/);\n if (codeBlockMatch) return codeBlockMatch[1];\n const jsonLikeMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonLikeMatch) return jsonLikeMatch[0];\n } catch {}\n return response;\n}\nfunction preprocessDoubaoBboxJson(input) {\n if (input.includes('bbox')) while(/\\d+\\s+\\d+/.test(input))input = input.replace(/(\\d+)\\s+(\\d+)/g, '$1,$2');\n return input;\n}\nfunction safeParseJson(input) {\n const cleanJsonString = extractJSONFromCodeBlock(input);\n if (null == cleanJsonString ? void 0 : cleanJsonString.match(/\\((\\d+),(\\d+)\\)/)) {\n var _cleanJsonString_match;\n return null == (_cleanJsonString_match = cleanJsonString.match(/\\((\\d+),(\\d+)\\)/)) ? void 0 : _cleanJsonString_match.slice(1).map(Number);\n }\n try {\n return JSON.parse(cleanJsonString);\n } catch {}\n try {\n return JSON.parse(jsonrepair(cleanJsonString));\n } catch (e) {}\n if ('doubao-vision' === vlLocateMode() || 'vlm-ui-tars' === vlLocateMode()) {\n const jsonString = preprocessDoubaoBboxJson(cleanJsonString);\n return JSON.parse(jsonrepair(jsonString));\n }\n throw Error(`failed to parse json response: ${input}`);\n}\nfunction describeSize(size) {\n return `${size.width} x ${size.height}`;\n}\nconst distanceThreshold = 16;\nfunction elementByPositionWithElementInfo(treeRoot, position, options) {\n const requireStrictDistance = (null == options ? void 0 : options.requireStrictDistance) ?? true;\n const filterPositionElements = (null == options ? void 0 : options.filterPositionElements) ?? false;\n assert(void 0 !== position, 'position is required for query');\n const matchingElements = [];\n function dfs(node) {\n if (null == node ? void 0 : node.node) {\n const item = node.node;\n if (item.rect.left <= position.x && position.x <= item.rect.left + item.rect.width && item.rect.top <= position.y && position.y <= item.rect.top + item.rect.height) {\n var _item_attributes;\n if (!(filterPositionElements && (null == (_item_attributes = item.attributes) ? void 0 : _item_attributes.nodeType) === NodeType.POSITION) && item.isVisible) matchingElements.push(item);\n }\n }\n for (const child of node.children)dfs(child);\n }\n dfs(treeRoot);\n if (0 === matchingElements.length) return;\n const element = matchingElements.reduce((smallest, current)=>{\n const smallestArea = smallest.rect.width * smallest.rect.height;\n const currentArea = current.rect.width * current.rect.height;\n return currentArea < smallestArea ? current : smallest;\n });\n const distanceToCenter = distance({\n x: element.center[0],\n y: element.center[1]\n }, position);\n if (requireStrictDistance) return distanceToCenter <= distanceThreshold ? element : void 0;\n return element;\n}\nfunction distance(point1, point2) {\n return Math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2);\n}\nasync function describeUserPage(context, opt) {\n const { screenshotBase64 } = context;\n let width;\n let height;\n if (context.size) ({ width, height } = context.size);\n else {\n const imgSize = await imageInfoOfBase64(screenshotBase64);\n ({ width, height } = imgSize);\n }\n const treeRoot = context.tree;\n const idElementMap = {};\n const flatElements = treeToList(treeRoot);\n if ((null == opt ? void 0 : opt.domIncluded) === true && flatElements.length >= 5000) console.warn('The number of elements is too large, it may cause the prompt to be too long, please use domIncluded: \"visible-only\" to reduce the number of elements');\n flatElements.forEach((element)=>{\n idElementMap[element.id] = element;\n if (void 0 !== element.indexId) idElementMap[`${element.indexId}`] = element;\n });\n let pageDescription = '';\n const visibleOnly = (null == opt ? void 0 : opt.visibleOnly) ?? (null == opt ? void 0 : opt.domIncluded) === 'visible-only';\n if ((null == opt ? void 0 : opt.domIncluded) || !vlLocateMode()) {\n const contentTree = await descriptionOfTree(treeRoot, null == opt ? void 0 : opt.truncateTextLength, null == opt ? void 0 : opt.filterNonTextContent, visibleOnly);\n const sizeDescription = describeSize({\n width,\n height\n });\n pageDescription = `The size of the page: ${sizeDescription} \\n The page elements tree:\\n${contentTree}`;\n }\n return {\n description: pageDescription,\n elementById (idOrIndexId) {\n assert(void 0 !== idOrIndexId, 'id is required for query');\n const item = idElementMap[`${idOrIndexId}`];\n return item;\n },\n elementByPosition (position, size) {\n return elementByPositionWithElementInfo(treeRoot, position);\n },\n insertElementByPosition (position) {\n const element = generateElementByPosition(position);\n treeRoot.children.push({\n node: element,\n children: []\n });\n flatElements.push(element);\n idElementMap[element.id] = element;\n return element;\n },\n size: {\n width,\n height\n }\n };\n}\nconst getScreenshotsForLLM = (events, maxScreenshots = 1)=>{\n const eventsWithScreenshots = events.filter((event)=>event.screenshotBefore || event.screenshotAfter || event.screenshotWithBox);\n const sortedEvents = [\n ...eventsWithScreenshots\n ].sort((a, b)=>{\n if ('navigation' === a.type && 'navigation' !== b.type) return -1;\n if ('navigation' !== a.type && 'navigation' === b.type) return 1;\n if ('click' === a.type && 'click' !== b.type) return -1;\n if ('click' !== a.type && 'click' === b.type) return 1;\n return 0;\n });\n const screenshots = [];\n for (const event of sortedEvents){\n const screenshot = event.screenshotWithBox || event.screenshotAfter || event.screenshotBefore;\n if (screenshot && !screenshots.includes(screenshot)) {\n screenshots.push(screenshot);\n if (screenshots.length >= maxScreenshots) break;\n }\n }\n return screenshots;\n};\nconst filterEventsByType = (events)=>({\n navigationEvents: events.filter((event)=>'navigation' === event.type),\n clickEvents: events.filter((event)=>'click' === event.type),\n inputEvents: events.filter((event)=>'input' === event.type),\n scrollEvents: events.filter((event)=>'scroll' === event.type)\n });\nconst createEventCounts = (filteredEvents, totalEvents)=>({\n navigation: filteredEvents.navigationEvents.length,\n click: filteredEvents.clickEvents.length,\n input: filteredEvents.inputEvents.length,\n scroll: filteredEvents.scrollEvents.length,\n total: totalEvents\n });\nconst extractInputDescriptions = (inputEvents)=>inputEvents.map((event)=>({\n description: event.elementDescription || '',\n value: event.value || ''\n })).filter((item)=>item.description && item.value);\nconst processEventsForLLM = (events)=>events.map((event)=>({\n type: event.type,\n timestamp: event.timestamp,\n url: event.url,\n title: event.title,\n elementDescription: event.elementDescription,\n value: event.value,\n pageInfo: event.pageInfo,\n elementRect: event.elementRect\n }));\nconst prepareEventSummary = (events, options = {})=>{\n const filteredEvents = filterEventsByType(events);\n const eventCounts = createEventCounts(filteredEvents, events.length);\n const startUrl = filteredEvents.navigationEvents.length > 0 ? filteredEvents.navigationEvents[0].url || '' : '';\n const clickDescriptions = filteredEvents.clickEvents.map((event)=>event.elementDescription).filter((desc)=>Boolean(desc)).slice(0, 10);\n const inputDescriptions = extractInputDescriptions(filteredEvents.inputEvents).slice(0, 10);\n const urls = filteredEvents.navigationEvents.map((e)=>e.url).filter((url)=>Boolean(url)).slice(0, 5);\n const processedEvents = processEventsForLLM(events);\n return {\n testName: options.testName || 'Automated test from recorded events',\n startUrl,\n eventCounts,\n urls,\n clickDescriptions,\n inputDescriptions,\n events: processedEvents\n };\n};\nconst createMessageContent = (promptText, screenshots = [], includeScreenshots = true)=>{\n const messageContent = [\n {\n type: 'text',\n text: promptText\n }\n ];\n if (includeScreenshots && screenshots.length > 0) {\n messageContent.unshift({\n type: 'text',\n text: 'Here are screenshots from the recording session to help you understand the context:'\n });\n screenshots.forEach((screenshot)=>{\n messageContent.push({\n type: 'image_url',\n image_url: {\n url: screenshot\n }\n });\n });\n }\n return messageContent;\n};\nconst validateEvents = (events)=>{\n if (!events.length) throw new Error('No events provided for test generation');\n};\nconst generateYamlTest = async (events, options = {})=>{\n try {\n validateEvents(events);\n const summary = prepareEventSummary(events, {\n testName: options.testName,\n maxScreenshots: options.maxScreenshots || 3\n });\n const yamlSummary = {\n ...summary,\n includeTimestamps: options.includeTimestamps || false\n };\n const screenshots = getScreenshotsForLLM(events, options.maxScreenshots || 3);\n const prompt = [\n {\n role: 'system',\n content: `You are an expert in Midscene.js YAML test generation. Generate clean, accurate YAML following these rules: ${YAML_EXAMPLE_CODE}`\n },\n {\n role: 'user',\n content: `Generate YAML test for Midscene.js automation from recorded browser events.\n\nEvent Summary:\n${JSON.stringify(yamlSummary, null, 2)}\n\nConvert events:\n- navigation \\u{2192} target.url\n- click \\u{2192} aiTap with element description\n- input \\u{2192} aiInput with value and locate\n- scroll \\u{2192} aiScroll with appropriate direction\n- Add aiAssert for important state changes\n\nRespond with YAML only, no explanations.`\n }\n ];\n if (screenshots.length > 0) {\n prompt.push({\n role: 'user',\n content: 'Here are screenshots from the recording session to help you understand the context:'\n });\n prompt.push({\n role: 'user',\n content: screenshots.map((screenshot)=>({\n type: 'image_url',\n image_url: {\n url: screenshot\n }\n }))\n });\n }\n const response = await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA);\n if ((null == response ? void 0 : response.content) && 'string' == typeof response.content) return response.content;\n throw new Error('Failed to generate YAML test configuration');\n } catch (error) {\n throw new Error(`Failed to generate YAML test: ${error}`);\n }\n};\nconst generateYamlTestStream = async (events, options = {})=>{\n try {\n validateEvents(events);\n const summary = prepareEventSummary(events, {\n testName: options.testName,\n maxScreenshots: options.maxScreenshots || 3\n });\n const yamlSummary = {\n ...summary,\n includeTimestamps: options.includeTimestamps || false\n };\n const screenshots = getScreenshotsForLLM(events, options.maxScreenshots || 3);\n const prompt = [\n {\n role: 'system',\n content: `You are an expert in Midscene.js YAML test generation. Generate clean, accurate YAML following these rules: ${YAML_EXAMPLE_CODE}`\n },\n {\n role: 'user',\n content: `Generate YAML test for Midscene.js automation from recorded browser events.\n\nEvent Summary:\n${JSON.stringify(yamlSummary, null, 2)}\n\nConvert events:\n- navigation \\u{2192} target.url\n- click \\u{2192} aiTap with element description\n- input \\u{2192} aiInput with value and locate\n- scroll \\u{2192} aiScroll with appropriate direction\n- Add aiAssert for important state changes\n\nRespond with YAML only, no explanations.`\n }\n ];\n if (screenshots.length > 0) {\n prompt.push({\n role: 'user',\n content: 'Here are screenshots from the recording session to help you understand the context:'\n });\n prompt.push({\n role: 'user',\n content: screenshots.map((screenshot)=>({\n type: 'image_url',\n image_url: {\n url: screenshot\n }\n }))\n });\n }\n if (options.stream && options.onChunk) return await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA, void 0, {\n stream: true,\n onChunk: options.onChunk\n });\n {\n const response = await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA);\n if ((null == response ? void 0 : response.content) && 'string' == typeof response.content) return {\n content: response.content,\n usage: response.usage,\n isStreamed: false\n };\n throw new Error('Failed to generate YAML test configuration');\n }\n } catch (error) {\n throw new Error(`Failed to generate YAML test: ${error}`);\n }\n};\nfunction systemPromptToExtract() {\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\nThe user will give you a screenshot, the contents of it (optional), and some data requirements in <DATA_DEMAND>. You need to extract the data according to the <DATA_DEMAND>.\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\nIf the user provides multiple reference images, please carefully review the reference images with the screenshot and provide the correct answer for <DATA_DEMAND>.\n\nIf the user requests reasons to be provided, please provide the thought field in response, less then 100 words.\n\nReturn in the following JSON format:\n{\n thought: string, // the thought process of the extraction, less then 100 words, not required by default.\n data: any, // the extracted data. 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.\n errors: [], // string[], error message if any\n}\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{\n data: {\n name: \"John\",\n age: 30,\n isAdmin: true\n },\n}\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{\n data: [\"todo 1\", \"todo 2\", \"todo 3\"],\n}\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{\n data: \"todo list\",\n}\n\n# Example 4\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\n{\n \"result\": \"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{\n data: { result: true },\n}\n`;\n}\nconst extractDataQueryPrompt = async (pageDescription, dataQuery)=>{\n let dataQueryText = '';\n dataQueryText = 'string' == typeof dataQuery ? dataQuery : JSON.stringify(dataQuery, null, 2);\n const extractDataPrompt = new PromptTemplate({\n template: `\n<PageDescription>\n{pageDescription}\n</PageDescription>\n\n<DATA_DEMAND>\n{dataQuery}\n</DATA_DEMAND>\n `,\n inputVariables: [\n \"pageDescription\",\n 'dataQuery'\n ]\n });\n return await extractDataPrompt.format({\n pageDescription,\n dataQuery: dataQueryText\n });\n};\nfunction systemPromptToLocateSection(vlMode) {\n return `\nYou goal is to find out one section containing the target element in the screenshot, put it in the \\`bbox\\` field. If the user describe the target element with some reference elements, you should also find the section containing the reference elements, put it in the \\`references_bbox\\` field.\n\nUsually, it should be approximately an area not more than 300x300px. Changes of the size are allowed if there are many elements to cover.\n\nreturn in this JSON format:\n\\`\\`\\`json\n{\n \"bbox\": [number, number, number, number],\n \"references_bbox\"?: [\n [number, number, number, number],\n [number, number, number, number],\n ...\n ],\n \"error\"?: string\n}\n\\`\\`\\`\n\nIn which, all the numbers in the \\`bbox\\` and \\`references_bbox\\` represent ${bboxDescription(vlMode)}.\n\nFor example, if the user describe the target element as \"the delete button on the second row with title 'Peter'\", you should put the bounding box of the delete button in the \\`bbox\\` field, and the bounding box of the second row in the \\`references_bbox\\` field.\n\nthe return value should be like this:\n\\`\\`\\`json\n{\n \"bbox\": [100, 100, 200, 200],\n \"references_bbox\": [[100, 100, 200, 200]]\n}\n\\`\\`\\`\n`;\n}\nconst sectionLocatorInstruction = new PromptTemplate({\n template: `Here is the target element user interested in:\n<targetDescription>\n{sectionDescription}\n</targetDescription>\n `,\n inputVariables: [\n \"sectionDescription\"\n ]\n});\nconst debugInspect = getDebug('ai:inspect');\nconst debugSection = getDebug('ai:section');\nconst extraTextFromUserPrompt = (prompt)=>{\n if ('string' == typeof prompt) return prompt;\n return prompt.prompt;\n};\nconst promptsToChatParam = async (multimodalPrompt)=>{\n var _multimodalPrompt_images;\n const msgs = [];\n if (null == multimodalPrompt ? void 0 : null == (_multimodalPrompt_images = multimodalPrompt.images) ? void 0 : _multimodalPrompt_images.length) {\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: 'Next, I will provide all the reference images.'\n }\n ]\n });\n for (const item of multimodalPrompt.images){\n const base64 = await preProcessImageUrl(item.url, !!multimodalPrompt.convertHttpImage2Base64);\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: `reference image ${item.name}:`\n }\n ]\n });\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: base64,\n detail: 'high'\n }\n }\n ]\n });\n }\n }\n return msgs;\n};\nasync function AiLocateElement(options) {\n const { context, targetElementDescription, callAI } = options;\n const { screenshotBase64 } = context;\n const { description, elementById, insertElementByPosition } = await describeUserPage(context);\n assert(targetElementDescription, \"cannot find the target element description\");\n const userInstructionPrompt = await findElementPrompt.format({\n pageDescription: description,\n targetElementDescription: extraTextFromUserPrompt(targetElementDescription)\n });\n const systemPrompt = systemPromptToLocateElement(vlLocateMode());\n let imagePayload = screenshotBase64;\n if (options.searchConfig) {\n assert(options.searchConfig.rect, 'searchArea is provided but its rect cannot be found. Failed to locate element');\n assert(options.searchConfig.imageBase64, 'searchArea is provided but its imageBase64 cannot be found. Failed to locate element');\n imagePayload = options.searchConfig.imageBase64;\n } else if ('qwen-vl' === vlLocateMode()) imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n else if (!vlLocateMode()) imagePayload = await markupImageForLLM(screenshotBase64, context.tree, context.size);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: userInstructionPrompt\n }\n ]\n }\n ];\n if ('string' != typeof targetElementDescription) {\n const addOns = await promptsToChatParam({\n images: targetElementDescription.images,\n convertHttpImage2Base64: targetElementDescription.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const callAIFn = callAI || callToGetJSONObject;\n const res = await callAIFn(msgs, common_AIActionType.INSPECT_ELEMENT);\n const rawResponse = JSON.stringify(res.content);\n let resRect;\n let matchedElements = 'elements' in res.content ? res.content.elements : [];\n let errors = 'errors' in res.content ? res.content.errors : [];\n try {\n if ('bbox' in res.content && Array.isArray(res.content.bbox)) {\n var _options_searchConfig_rect, _options_searchConfig, _options_searchConfig_rect1, _options_searchConfig1, _options_searchConfig_rect2, _options_searchConfig2, _options_searchConfig_rect3, _options_searchConfig3;\n resRect = adaptBboxToRect(res.content.bbox, (null == (_options_searchConfig = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect = _options_searchConfig.rect) ? void 0 : _options_searchConfig_rect.width) || context.size.width, (null == (_options_searchConfig1 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect1 = _options_searchConfig1.rect) ? void 0 : _options_searchConfig_rect1.height) || context.size.height, null == (_options_searchConfig2 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect2 = _options_searchConfig2.rect) ? void 0 : _options_searchConfig_rect2.left, null == (_options_searchConfig3 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect3 = _options_searchConfig3.rect) ? void 0 : _options_searchConfig_rect3.top);\n debugInspect('resRect', resRect);\n const rectCenter = {\n x: resRect.left + resRect.width / 2,\n y: resRect.top + resRect.height / 2\n };\n let element = elementByPositionWithElementInfo(context.tree, rectCenter);\n const distanceToCenter = element ? distance({\n x: element.center[0],\n y: element.center[1]\n }, rectCenter) : 0;\n if (!element || distanceToCenter > distanceThreshold) element = insertElementByPosition(rectCenter);\n if (element) {\n matchedElements = [\n element\n ];\n errors = [];\n }\n }\n } catch (e) {\n const msg = e instanceof Error ? `Failed to parse bbox: ${e.message}` : 'unknown error in locate';\n if (errors && (null == errors ? void 0 : errors.length) !== 0) errors.push(`(${msg})`);\n else errors = [\n msg\n ];\n }\n return {\n rect: resRect,\n parseResult: {\n elements: matchedElements,\n errors\n },\n rawResponse,\n elementById,\n usage: res.usage,\n isOrderSensitive: 'object' == typeof res.content && null !== res.content && 'isOrderSensitive' in res.content ? res.content.isOrderSensitive : void 0\n };\n}\nasync function AiLocateSection(options) {\n const { context, sectionDescription } = options;\n const { screenshotBase64 } = context;\n const systemPrompt = systemPromptToLocateSection(vlLocateMode());\n const sectionLocatorInstructionText = await sectionLocatorInstruction.format({\n sectionDescription: extraTextFromUserPrompt(sectionDescription)\n });\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: sectionLocatorInstructionText\n }\n ]\n }\n ];\n if ('string' != typeof sectionDescription) {\n const addOns = await promptsToChatParam({\n images: sectionDescription.images,\n convertHttpImage2Base64: sectionDescription.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const result = await callAiFn(msgs, common_AIActionType.EXTRACT_DATA);\n let sectionRect;\n const sectionBbox = result.content.bbox;\n if (sectionBbox) {\n const targetRect = adaptBboxToRect(sectionBbox, context.size.width, context.size.height);\n debugSection('original targetRect %j', targetRect);\n const referenceBboxList = result.content.references_bbox || [];\n debugSection('referenceBboxList %j', referenceBboxList);\n const referenceRects = referenceBboxList.filter((bbox)=>Array.isArray(bbox)).map((bbox)=>adaptBboxToRect(bbox, context.size.width, context.size.height));\n debugSection('referenceRects %j', referenceRects);\n const mergedRect = mergeRects([\n targetRect,\n ...referenceRects\n ]);\n debugSection('mergedRect %j', mergedRect);\n sectionRect = expandSearchArea(mergedRect, context.size);\n debugSection('expanded sectionRect %j', sectionRect);\n }\n let imageBase64 = screenshotBase64;\n if (sectionRect) imageBase64 = await cropByRect(screenshotBase64, sectionRect, getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL));\n return {\n rect: sectionRect,\n imageBase64,\n error: result.content.error,\n rawResponse: JSON.stringify(result.content),\n usage: result.usage\n };\n}\nasync function AiExtractElementInfo(options) {\n var _options_extractOption;\n const { dataQuery, context, extractOption, multimodalPrompt } = options;\n const systemPrompt = systemPromptToExtract();\n const { screenshotBase64 } = context;\n const { description, elementById } = await describeUserPage(context, {\n truncateTextLength: 200,\n filterNonTextContent: false,\n visibleOnly: false,\n domIncluded: null == extractOption ? void 0 : extractOption.domIncluded\n });\n const extractDataPromptText = await extractDataQueryPrompt(description, dataQuery);\n const userContent = [];\n if ((null == extractOption ? void 0 : extractOption.screenshotIncluded) !== false) userContent.push({\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n });\n userContent.push({\n type: 'text',\n text: extractDataPromptText\n });\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: userContent\n }\n ];\n if (null == (_options_extractOption = options.extractOption) ? void 0 : _options_extractOption.returnThought) msgs.push({\n role: 'user',\n content: 'Please provide reasons.'\n });\n if (multimodalPrompt) {\n const addOns = await promptsToChatParam({\n images: multimodalPrompt.images,\n convertHttpImage2Base64: multimodalPrompt.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const result = await callAiFn(msgs, common_AIActionType.EXTRACT_DATA);\n return {\n parseResult: result.content,\n elementById,\n usage: result.usage\n };\n}\nasync function AiAssert(options) {\n const { assertion, context } = options;\n assert(assertion, 'assertion should not be empty');\n const { screenshotBase64 } = context;\n const systemPrompt = systemPromptToAssert({\n isUITars: getAIConfigInBoolean(MIDSCENE_USE_VLM_UI_TARS)\n });\n const assertionText = extraTextFromUserPrompt(assertion);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: `\nHere is the assertion. Please tell whether it is truthy according to the screenshot.\n=====================================\n${assertionText}\n=====================================\n `\n }\n ]\n }\n ];\n if ('string' != typeof assertion) {\n const addOns = await promptsToChatParam({\n images: assertion.images,\n convertHttpImage2Base64: assertion.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const { content: assertResult, usage } = await callAiFn(msgs, common_AIActionType.ASSERT);\n return {\n content: assertResult,\n usage\n };\n}\nasync function llm_planning_plan(userInstruction, opts) {\n var _planFromAI_action;\n const { callAI, context } = opts || {};\n const { screenshotBase64, size } = context;\n const { description: pageDescription, elementById } = await describeUserPage(context);\n const systemPrompt = await systemPromptToTaskPlanning({\n actionSpace: opts.actionSpace,\n vlMode: vlLocateMode()\n });\n const taskBackgroundContextText = generateTaskBackgroundContext(userInstruction, opts.log, opts.actionContext);\n const userInstructionPrompt = await automationUserPrompt(vlLocateMode()).format({\n pageDescription,\n taskBackgroundContext: taskBackgroundContextText\n });\n let imagePayload = screenshotBase64;\n if ('qwen-vl' === vlLocateMode()) imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n else if (!vlLocateMode()) imagePayload = await markupImageForLLM(screenshotBase64, context.tree, context.size);\n warnGPT4oSizeLimit(size);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: userInstructionPrompt\n }\n ]\n }\n ];\n const call = callAI || callAiFn;\n const { content, usage } = await call(msgs, common_AIActionType.PLAN);\n const rawResponse = JSON.stringify(content, void 0, 2);\n const planFromAI = content;\n const actions = ((null == (_planFromAI_action = planFromAI.action) ? void 0 : _planFromAI_action.type) ? [\n planFromAI.action\n ] : planFromAI.actions) || [];\n const returnValue = {\n ...planFromAI,\n actions,\n rawResponse,\n usage,\n yamlFlow: buildYamlFlowFromPlans(actions, planFromAI.sleep)\n };\n assert(planFromAI, \"can't get plans from AI\");\n if (vlLocateMode()) {\n actions.forEach((action)=>{\n if (action.locate) try {\n action.locate = fillBboxParam(action.locate, size.width, size.height);\n } catch (e) {\n throw new Error(`Failed to fill locate param: ${planFromAI.error} (${e instanceof Error ? e.message : 'unknown error'})`, {\n cause: e\n });\n }\n });\n assert(!planFromAI.error, `Failed to plan actions: ${planFromAI.error}`);\n } else actions.forEach((action)=>{\n var _action_locate;\n if (null == (_action_locate = action.locate) ? void 0 : _action_locate.id) {\n const element = elementById(action.locate.id);\n if (element) action.locate.id = element.id;\n }\n });\n if (0 === actions.length && returnValue.more_actions_needed_by_instruction && !returnValue.sleep) console.warn('No actions planned for the prompt, but model said more actions are needed:', userInstruction);\n return returnValue;\n}\nfunction getUiTarsPlanningPrompt() {\n const preferredLanguage = getPreferredLanguage();\n return `\nYou are a GUI agent. You are given a task and your action history, with screenshots. You need to perform the next action to complete the task. \n\n## Output Format\n\\`\\`\\`\nThought: ...\nAction: ...\n\\`\\`\\`\n\n## Action Space\n\nclick(start_box='[x1, y1, x2, y2]')\nleft_double(start_box='[x1, y1, x2, y2]')\nright_single(start_box='[x1, y1, x2, y2]')\ndrag(start_box='[x1, y1, x2, y2]', end_box='[x3, y3, x4, y4]')\nhotkey(key='')\ntype(content='xxx') # Use escape characters \\\\', \\\\\\\", and \\\\n in content part to ensure we can parse the content in normal python string format. If you want to submit your input, use \\\\n at the end of content. \nscroll(start_box='[x1, y1, x2, y2]', direction='down or up or right or left')\nwait() #Sleep for 5s and take a screenshot to check for any changes.\nfinished(content='xxx') # Use escape characters \\\\', \\\\\", and \\\\n in content part to ensure we can parse the content in normal python string format.\n\n\n## Note\n- Use ${preferredLanguage} in \\`Thought\\` part.\n- Write a small plan and finally summarize your next action (with its target element) in one sentence in \\`Thought\\` part.\n\n## User Instruction\n`;\n}\nconst getSummary = (prediction)=>prediction.replace(/Reflection:[\\s\\S]*?(?=Action_Summary:|Action:|$)/g, '').trim();\nconst debug = getDebug('ui-tars-planning');\nconst bboxSize = 10;\nconst pointToBbox = (point, width, height)=>[\n Math.round(Math.max(point.x - bboxSize / 2, 0)),\n Math.round(Math.max(point.y - bboxSize / 2, 0)),\n Math.round(Math.min(point.x + bboxSize / 2, width)),\n Math.round(Math.min(point.y + bboxSize / 2, height))\n ];\nasync function vlmPlanning(options) {\n const { conversationHistory, userInstruction, size } = options;\n const systemPrompt = getUiTarsPlanningPrompt() + userInstruction;\n const res = await service_caller_call([\n {\n role: 'user',\n content: systemPrompt\n },\n ...conversationHistory\n ], common_AIActionType.INSPECT_ELEMENT);\n const convertedText = convertBboxToCoordinates(res.content);\n const modelVer = uiTarsModelVersion();\n const { parsed } = actionParser({\n prediction: convertedText,\n factor: [\n 1000,\n 1000\n ],\n screenContext: {\n width: size.width,\n height: size.height\n },\n modelVer: modelVer || void 0\n });\n debug('modelVer', modelVer, 'parsed', JSON.stringify(parsed));\n const transformActions = [];\n parsed.forEach((action)=>{\n if ('click' === action.action_type) {\n assert(action.action_inputs.start_box, 'start_box is required');\n const point = getPoint(action.action_inputs.start_box, size);\n transformActions.push({\n type: 'Locate',\n param: {},\n locate: {\n prompt: action.thought || '',\n bbox: pointToBbox({\n x: point[0],\n y: point[1]\n }, size.width, size.height)\n }\n });\n transformActions.push({\n type: 'Tap',\n locate: {\n prompt: action.thought || '',\n bbox: pointToBbox({\n x: point[0],\n y: point[1]\n }, size.width, size.height)\n },\n param: action.thought || ''\n });\n } else if ('drag' === action.action_type) {\n assert(action.action_inputs.start_box, 'start_box is required');\n assert(action.action_inputs.end_box, 'end_box is required');\n const startPoint = getPoint(action.action_inputs.start_box, size);\n const endPoint = getPoint(action.action_inputs.end_box, size);\n transformActions.push({\n type: 'Drag',\n param: {\n start_box: {\n x: startPoint[0],\n y: startPoint[1]\n },\n end_box: {\n x: endPoint[0],\n y: endPoint[1]\n }\n },\n locate: null,\n thought: action.thought || ''\n });\n } else if ('type' === action.action_type) transformActions.push({\n type: 'Input',\n param: {\n value: action.action_inputs.content\n },\n locate: null,\n thought: action.thought || ''\n });\n else if ('scroll' === action.action_type) transformActions.push({\n type: 'Scroll',\n param: {\n direction: action.action_inputs.direction\n },\n locate: null,\n thought: action.thought || ''\n });\n else if ('finished' === action.action_type) transformActions.push({\n type: 'Finished',\n param: {},\n locate: null,\n thought: action.thought || ''\n });\n else if ('hotkey' === action.action_type) if (action.action_inputs.key) {\n const keys = transformHotkeyInput(action.action_inputs.key);\n transformActions.push({\n type: 'KeyboardPress',\n param: {\n value: keys\n },\n locate: null,\n thought: action.thought || ''\n });\n } else console.warn('No key found in action: hotkey. Will not perform action.');\n else if ('wait' === action.action_type) transformActions.push({\n type: 'Sleep',\n param: {\n timeMs: 1000\n },\n locate: null,\n thought: action.thought || ''\n });\n else if ('androidBackButton' === action.action_type) transformActions.push({\n type: 'AndroidBackButton',\n param: {},\n locate: null,\n thought: action.thought || ''\n });\n else if ('androidHomeButton' === action.action_type) transformActions.push({\n type: 'AndroidHomeButton',\n param: {},\n locate: null,\n thought: action.thought || ''\n });\n else if ('androidRecentAppsButton' === action.action_type) transformActions.push({\n type: 'AndroidRecentAppsButton',\n param: {}\n });\n else if ('androidLongPress' === action.action_type) {\n assert(action.action_inputs.start_coords, 'start_coords is required for androidLongPress');\n const point = action.action_inputs.start_coords;\n transformActions.push({\n type: 'AndroidLongPress',\n param: {\n x: point[0],\n y: point[1],\n duration: 1000\n },\n locate: null,\n thought: action.thought || ''\n });\n } else if ('androidPull' === action.action_type) {\n const pullDirection = action.action_inputs.direction || 'down';\n const startPoint = action.action_inputs.start_coords ? {\n x: action.action_inputs.start_coords[0],\n y: action.action_inputs.start_coords[1]\n } : void 0;\n transformActions.push({\n type: 'AndroidPull',\n param: {\n direction: pullDirection,\n startPoint,\n distance: action.action_inputs.distance,\n duration: action.action_inputs.duration || 500\n },\n locate: null,\n thought: action.thought || ''\n });\n }\n });\n if (0 === transformActions.length) throw new Error(`No actions found, response: ${res.content}`, {\n cause: {\n prediction: res.content,\n parsed\n }\n });\n return {\n actions: transformActions,\n actionsFromModel: parsed,\n action_summary: getSummary(res.content),\n usage: res.usage,\n rawResponse: JSON.stringify(res.content, void 0, 2)\n };\n}\nfunction convertBboxToCoordinates(text) {\n const pattern = /<bbox>(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)<\\/bbox>/g;\n function replaceMatch(match, x1, y1, x2, y2) {\n const x1Num = Number.parseInt(x1, 10);\n const y1Num = Number.parseInt(y1, 10);\n const x2Num = Number.parseInt(x2, 10);\n const y2Num = Number.parseInt(y2, 10);\n const x = Math.floor((x1Num + x2Num) / 2);\n const y = Math.floor((y1Num + y2Num) / 2);\n return `(${x},${y})`;\n }\n const cleanedText = text.replace(/\\[EOS\\]/g, '');\n return cleanedText.replace(pattern, replaceMatch).trim();\n}\nfunction getPoint(startBox, size) {\n const [x, y] = JSON.parse(startBox);\n return [\n x * size.width,\n y * size.height\n ];\n}\nasync function resizeImageForUiTars(imageBase64, size) {\n if ('vlm-ui-tars' === vlLocateMode() && uiTarsModelVersion() === UITarsModelVersion.V1_5) {\n debug('ui-tars-v1.5, will check image size', size);\n const currentPixels = size.width * size.height;\n const maxPixels = 12845056;\n if (currentPixels > maxPixels) {\n const resizeFactor = Math.sqrt(maxPixels / currentPixels);\n const newWidth = Math.floor(size.width * resizeFactor);\n const newHeight = Math.floor(size.height * resizeFactor);\n debug('resize image for ui-tars, new width: %s, new height: %s', newWidth, newHeight);\n const resizedImage = await resizeImgBase64(imageBase64, {\n width: newWidth,\n height: newHeight\n });\n return resizedImage;\n }\n }\n return imageBase64;\n}\nconst generatePlaywrightTest = async (events, options = {})=>{\n validateEvents(events);\n const summary = prepareEventSummary(events, {\n testName: options.testName,\n maxScreenshots: options.maxScreenshots || 3\n });\n const playwrightSummary = {\n ...summary,\n waitForNetworkIdle: false !== options.waitForNetworkIdle,\n waitForNetworkIdleTimeout: options.waitForNetworkIdleTimeout || 2000,\n viewportSize: options.viewportSize || {\n width: 1280,\n height: 800\n }\n };\n const screenshots = getScreenshotsForLLM(events, options.maxScreenshots || 3);\n const promptText = `Generate a Playwright test using @midscene/web/playwright that reproduces this recorded browser session. The test should be based on the following events and follow the structure of the example provided. Make the test descriptive with appropriate assertions and validations.\n\nEvent Summary:\n${JSON.stringify(playwrightSummary, null, 2)}\n\nGenerated code should:\n1. Import required dependencies\n2. Set up the test with proper configuration\n3. Include a beforeEach hook to navigate to the starting URL\n4. Implement a test that uses Midscene AI methods (aiTap, aiInput, aiAssert, etc.)\n5. Include appropriate assertions and validations\n6. Follow best practices for Playwright tests\n7. Be ready to execute without further modification\n\nRespond ONLY with the complete Playwright test code, no explanations.`;\n const messageContent = createMessageContent(promptText, screenshots, false !== options.includeScreenshots);\n const systemPrompt = `You are an expert test automation engineer specializing in Playwright and Midscene. \nYour task is to generate a complete, executable Playwright test using @midscene/web/playwright that reproduces a recorded browser session.\n\n${PLAYWRIGHT_EXAMPLE_CODE}`;\n const prompt = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: messageContent\n }\n ];\n const response = await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA);\n if ((null == response ? void 0 : response.content) && 'string' == typeof response.content) return response.content;\n throw new Error('Failed to generate Playwright test code');\n};\nconst generatePlaywrightTestStream = async (events, options = {})=>{\n validateEvents(events);\n const summary = prepareEventSummary(events, {\n testName: options.testName,\n maxScreenshots: options.maxScreenshots || 3\n });\n const playwrightSummary = {\n ...summary,\n waitForNetworkIdle: false !== options.waitForNetworkIdle,\n waitForNetworkIdleTimeout: options.waitForNetworkIdleTimeout || 2000,\n viewportSize: options.viewportSize || {\n width: 1280,\n height: 800\n }\n };\n const screenshots = getScreenshotsForLLM(events, options.maxScreenshots || 3);\n const promptText = `Generate a Playwright test using @midscene/web/playwright that reproduces this recorded browser session. The test should be based on the following events and follow the structure of the example provided. Make the test descriptive with appropriate assertions and validations.\n\nEvent Summary:\n${JSON.stringify(playwrightSummary, null, 2)}\n\nGenerated code should:\n1. Import required dependencies\n2. Set up the test with proper configuration\n3. Include a beforeEach hook to navigate to the starting URL\n4. Implement a test that uses Midscene AI methods (aiTap, aiInput, aiAssert, etc.)\n5. Include appropriate assertions and validations\n6. Follow best practices for Playwright tests\n7. Be ready to execute without further modification\n8. can't wrap this test code in markdown code block\n\nRespond ONLY with the complete Playwright test code, no explanations.`;\n const messageContent = createMessageContent(promptText, screenshots, false !== options.includeScreenshots);\n const systemPrompt = `You are an expert test automation engineer specializing in Playwright and Midscene. \nYour task is to generate a complete, executable Playwright test using @midscene/web/playwright that reproduces a recorded browser session.\n\n${PLAYWRIGHT_EXAMPLE_CODE}`;\n const prompt = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: messageContent\n }\n ];\n if (options.stream && options.onChunk) return await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA, void 0, {\n stream: true,\n onChunk: options.onChunk\n });\n {\n const response = await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA);\n if ((null == response ? void 0 : response.content) && 'string' == typeof response.content) return {\n content: response.content,\n usage: response.usage,\n isStreamed: false\n };\n throw new Error('Failed to generate Playwright test code');\n }\n};\nexport { common_AIActionType as AIActionType, AiAssert, AiExtractElementInfo, AiLocateElement, AiLocateSection, adaptBboxToRect, service_caller_call as callAi, callAiFn, callAiFnWithStringResponse, callToGetJSONObject, describeUserPage, elementByPositionWithElementInfo, generatePlaywrightTest, generatePlaywrightTestStream, generateYamlTest, generateYamlTestStream, llm_planning_plan as plan, resizeImageForUiTars, systemPromptToLocateElement, vlmPlanning };\n\n//# sourceMappingURL=ai-model.mjs.map","import node_assert from \"node:assert\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { getMidsceneRunSubDir } from \"@midscene/shared/common\";\nimport { MIDSCENE_CACHE_MAX_FILENAME_LENGTH, getAIConfigInNumber } from \"@midscene/shared/env\";\nimport { getDebug } from \"@midscene/shared/logger\";\nimport { generateHashId, ifInBrowser, ifInWorker } from \"@midscene/shared/utils\";\nimport js_yaml from \"js-yaml\";\nimport semver from \"semver\";\nimport { getMidsceneVersion, replaceIllegalPathCharsAndSpace } from \"./utils.mjs\";\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst DEFAULT_CACHE_MAX_FILENAME_LENGTH = 200;\nconst debug = getDebug('cache');\nconst lowestSupportedMidsceneVersion = '0.16.10';\nconst cacheFileExt = '.cache.yaml';\nclass TaskCache {\n matchCache(prompt, type) {\n for(let i = 0; i < this.cacheOriginalLength; i++){\n const item = this.cache.caches[i];\n const promptStr = 'string' == typeof prompt ? prompt : JSON.stringify(prompt);\n const key = `${type}:${promptStr}:${i}`;\n if (item.type === type && isDeepStrictEqual(item.prompt, prompt) && !this.matchedCacheIndices.has(key)) {\n this.matchedCacheIndices.add(key);\n debug('cache found and marked as used, type: %s, prompt: %s, index: %d', type, prompt, i);\n return {\n cacheContent: item,\n updateFn: (cb)=>{\n debug('will call updateFn to update cache, type: %s, prompt: %s, index: %d', type, prompt, i);\n cb(item);\n debug('cache updated, will flush to file, type: %s, prompt: %s, index: %d', type, prompt, i);\n this.flushCacheToFile();\n }\n };\n }\n }\n debug('no unused cache found, type: %s, prompt: %s', type, prompt);\n }\n matchPlanCache(prompt) {\n return this.matchCache(prompt, 'plan');\n }\n matchLocateCache(prompt) {\n return this.matchCache(prompt, 'locate');\n }\n appendCache(cache) {\n debug('will append cache', cache);\n this.cache.caches.push(cache);\n this.flushCacheToFile();\n }\n loadCacheFromFile() {\n const cacheFile = this.cacheFilePath;\n node_assert(cacheFile, 'cache file path is required');\n if (!existsSync(cacheFile)) return void debug('no cache file found, path: %s', cacheFile);\n const jsonTypeCacheFile = cacheFile.replace(cacheFileExt, '.json');\n if (existsSync(jsonTypeCacheFile) && this.isCacheResultUsed) return void console.warn(`An outdated cache file from an earlier version of Midscene has been detected. Since version 0.17, we have implemented an improved caching strategy. Please delete the old file located at: ${jsonTypeCacheFile}.`);\n try {\n const data = readFileSync(cacheFile, 'utf8');\n const jsonData = js_yaml.load(data);\n const version = getMidsceneVersion();\n if (!version) return void debug('no midscene version info, will not read cache from file');\n if (semver.lt(jsonData.midsceneVersion, lowestSupportedMidsceneVersion) && !jsonData.midsceneVersion.includes('beta')) return void console.warn(`You are using an old version of Midscene cache file, and we cannot match any info from it. Starting from Midscene v0.17, we changed our strategy to use xpath for cache info, providing better performance.\\nPlease delete the existing cache and rebuild it. Sorry for the inconvenience.\\ncache file: ${cacheFile}`);\n debug('cache loaded from file, path: %s, cache version: %s, record length: %s', cacheFile, jsonData.midsceneVersion, jsonData.caches.length);\n jsonData.midsceneVersion = getMidsceneVersion();\n return jsonData;\n } catch (err) {\n debug('cache file exists but load failed, path: %s, error: %s', cacheFile, err);\n return;\n }\n }\n flushCacheToFile() {\n const version = getMidsceneVersion();\n if (!version) return void debug('no midscene version info, will not write cache to file');\n if (!this.cacheFilePath) return void debug('no cache file path, will not write cache to file');\n try {\n const dir = dirname(this.cacheFilePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, {\n recursive: true\n });\n debug('created cache directory: %s', dir);\n }\n const sortedCaches = [\n ...this.cache.caches\n ].sort((a, b)=>{\n if ('plan' === a.type && 'locate' === b.type) return -1;\n if ('locate' === a.type && 'plan' === b.type) return 1;\n return 0;\n });\n const cacheToWrite = {\n ...this.cache,\n caches: sortedCaches\n };\n const yamlData = js_yaml.dump(cacheToWrite);\n writeFileSync(this.cacheFilePath, yamlData);\n debug('cache flushed to file: %s', this.cacheFilePath);\n } catch (err) {\n debug('write cache to file failed, path: %s, error: %s', this.cacheFilePath, err);\n }\n }\n updateOrAppendCacheRecord(newRecord, cachedRecord) {\n if (cachedRecord) if ('plan' === newRecord.type) cachedRecord.updateFn((cache)=>{\n cache.yamlWorkflow = newRecord.yamlWorkflow;\n });\n else cachedRecord.updateFn((cache)=>{\n cache.xpaths = newRecord.xpaths;\n });\n else this.appendCache(newRecord);\n }\n constructor(cacheId, isCacheResultUsed, cacheFilePath){\n _define_property(this, \"cacheId\", void 0);\n _define_property(this, \"cacheFilePath\", void 0);\n _define_property(this, \"cache\", void 0);\n _define_property(this, \"isCacheResultUsed\", void 0);\n _define_property(this, \"cacheOriginalLength\", void 0);\n _define_property(this, \"matchedCacheIndices\", new Set());\n node_assert(cacheId, 'cacheId is required');\n let safeCacheId = replaceIllegalPathCharsAndSpace(cacheId);\n const cacheMaxFilenameLength = getAIConfigInNumber(MIDSCENE_CACHE_MAX_FILENAME_LENGTH) || DEFAULT_CACHE_MAX_FILENAME_LENGTH;\n if (Buffer.byteLength(safeCacheId, 'utf8') > cacheMaxFilenameLength) {\n const prefix = safeCacheId.slice(0, 32);\n const hash = generateHashId(void 0, safeCacheId);\n safeCacheId = `${prefix}-${hash}`;\n }\n this.cacheId = safeCacheId;\n this.cacheFilePath = ifInBrowser || ifInWorker ? void 0 : cacheFilePath || join(getMidsceneRunSubDir('cache'), `${this.cacheId}${cacheFileExt}`);\n this.isCacheResultUsed = isCacheResultUsed;\n let cacheContent;\n if (this.cacheFilePath) cacheContent = this.loadCacheFromFile();\n if (!cacheContent) cacheContent = {\n midsceneVersion: getMidsceneVersion(),\n cacheId: this.cacheId,\n caches: []\n };\n this.cache = cacheContent;\n this.cacheOriginalLength = this.cache.caches.length;\n }\n}\nexport { TaskCache, cacheFileExt, debug };\n\n//# sourceMappingURL=task-cache.mjs.map","import { elementByPositionWithElementInfo } from \"@midscene/core/ai-model\";\nimport { sleep, uploadTestInfoToServer } from \"@midscene/core/utils\";\nimport { MIDSCENE_REPORT_TAG_NAME, getAIConfig } from \"@midscene/shared/env\";\nimport { generateElementByPosition, getNodeFromCacheList, traverseTree } from \"@midscene/shared/extractor\";\nimport { resizeImgBase64 } from \"@midscene/shared/img\";\nimport { getDebug } from \"@midscene/shared/logger\";\nimport { assert, logMsg, uuid } from \"@midscene/shared/utils\";\nimport dayjs from \"dayjs\";\nimport { WebElementInfo } from \"../web-element.mjs\";\nimport { debug as external_task_cache_mjs_debug } from \"./task-cache.mjs\";\nimport { getKeyCommands } from \"./ui-utils.mjs\";\nconst utils_debug = getDebug('tool:profile');\nasync function parseContextFromWebPage(page, _opt) {\n assert(page, 'page is required');\n if (page._forceUsePageContext) return await page._forceUsePageContext();\n utils_debug('Getting page URL');\n const url = await page.url();\n utils_debug('URL end');\n utils_debug('Uploading test info to server');\n uploadTestInfoToServer({\n testUrl: url\n });\n utils_debug('UploadTestInfoToServer end');\n let screenshotBase64;\n let tree;\n utils_debug('Starting parallel operations: screenshot and element tree');\n await Promise.all([\n page.screenshotBase64().then((base64)=>{\n screenshotBase64 = base64;\n utils_debug('ScreenshotBase64 end');\n }),\n page.getElementsNodeTree().then(async (treeRoot)=>{\n tree = treeRoot;\n utils_debug('GetElementsNodeTree end');\n })\n ]);\n utils_debug('ParseContextFromWebPage end');\n utils_debug('Traversing element tree');\n const webTree = traverseTree(tree, (elementInfo)=>{\n const { rect, id, content, attributes, indexId, isVisible } = elementInfo;\n return new WebElementInfo({\n rect,\n id,\n content,\n attributes,\n indexId,\n isVisible\n });\n });\n utils_debug('TraverseTree end');\n assert(screenshotBase64, 'screenshotBase64 is required');\n const size = await page.size();\n utils_debug(`size: ${size.width}x${size.height} dpr: ${size.dpr}`);\n if (size.dpr && size.dpr > 1) {\n utils_debug('Resizing screenshot for high DPR display');\n screenshotBase64 = await resizeImgBase64(screenshotBase64, {\n width: size.width,\n height: size.height\n });\n utils_debug('ResizeImgBase64 end');\n }\n return {\n tree: webTree,\n size,\n screenshotBase64: screenshotBase64,\n url\n };\n}\nfunction getReportFileName(tag = 'web') {\n const reportTagName = getAIConfig(MIDSCENE_REPORT_TAG_NAME);\n const dateTimeInFileName = dayjs().format('YYYY-MM-DD_HH-mm-ss');\n const uniqueId = uuid().substring(0, 8);\n return `${reportTagName || tag}-${dateTimeInFileName}-${uniqueId}`;\n}\nfunction printReportMsg(filepath) {\n logMsg(`Midscene - report file updated: ${filepath}`);\n}\nfunction getCurrentExecutionFile(trace) {\n const error = new Error();\n const stackTrace = trace || error.stack;\n const pkgDir = process.cwd() || '';\n if (stackTrace) {\n const stackLines = stackTrace.split('\\n');\n for (const line of stackLines)if (line.includes('.spec.') || line.includes('.test.') || line.includes('.ts') || line.includes('.js')) {\n const match = line.match(/(?:at\\s+)?(.*?\\.(?:spec|test)\\.[jt]s)/);\n if (null == match ? void 0 : match[1]) {\n const targetFileName = match[1].replace(pkgDir, '').trim().replace('at ', '');\n return targetFileName;\n }\n }\n }\n return false;\n}\nconst testFileIndex = new Map();\nfunction generateCacheId(fileName) {\n let taskFile = fileName || getCurrentExecutionFile();\n if (!taskFile) {\n taskFile = uuid();\n console.warn('Midscene - using random UUID for cache id. Cache may be invalid.');\n }\n if (testFileIndex.has(taskFile)) {\n const currentIndex = testFileIndex.get(taskFile);\n if (void 0 !== currentIndex) testFileIndex.set(taskFile, currentIndex + 1);\n } else testFileIndex.set(taskFile, 1);\n return `${taskFile}-${testFileIndex.get(taskFile)}`;\n}\nconst ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED = 'NOT_IMPLEMENTED_AS_DESIGNED';\nfunction replaceIllegalPathCharsAndSpace(str) {\n return str.replace(/[:*?\"<>| ]/g, '-');\n}\nfunction forceClosePopup(page, debug) {\n page.on('popup', async (popup)=>{\n if (!popup) return void console.warn('got a popup event, but the popup is not ready yet, skip');\n const url = await popup.url();\n console.log(`Popup opened: ${url}`);\n if (popup.isClosed()) debug(`popup is already closed, skip close ${url}`);\n else try {\n await popup.close();\n } catch (error) {\n debug(`failed to close popup ${url}, error: ${error}`);\n }\n if (page.isClosed()) debug(`page is already closed, skip goto ${url}`);\n else try {\n await page.goto(url);\n } catch (error) {\n debug(`failed to goto ${url}, error: ${error}`);\n }\n });\n}\nfunction matchElementFromPlan(planLocateParam, tree) {\n if (!planLocateParam) return;\n if (planLocateParam.id) return getNodeFromCacheList(planLocateParam.id);\n if (planLocateParam.bbox) {\n const centerPosition = {\n x: Math.floor((planLocateParam.bbox[0] + planLocateParam.bbox[2]) / 2),\n y: Math.floor((planLocateParam.bbox[1] + planLocateParam.bbox[3]) / 2)\n };\n let element = elementByPositionWithElementInfo(tree, centerPosition);\n if (!element) element = generateElementByPosition(centerPosition);\n return element;\n }\n}\nasync function matchElementFromCache(taskExecutor, xpaths, cachePrompt, cacheable) {\n try {\n var _taskExecutor_taskCache;\n if ((null == xpaths ? void 0 : xpaths.length) && (null == (_taskExecutor_taskCache = taskExecutor.taskCache) ? void 0 : _taskExecutor_taskCache.isCacheResultUsed) && false !== cacheable) for(let i = 0; i < xpaths.length; i++){\n const element = await taskExecutor.page.getElementInfoByXpath(xpaths[i]);\n if (null == element ? void 0 : element.id) {\n external_task_cache_mjs_debug('cache hit, prompt: %s', cachePrompt);\n external_task_cache_mjs_debug('found a new element with same xpath, xpath: %s, id: %s', xpaths[i], null == element ? void 0 : element.id);\n return element;\n }\n }\n } catch (error) {\n external_task_cache_mjs_debug('get element info by xpath error: ', error);\n }\n}\nfunction trimContextByViewport(execution) {\n function filterVisibleTree(node) {\n if (!node) return null;\n const filteredChildren = Array.isArray(node.children) ? node.children.map(filterVisibleTree).filter((child)=>null !== child) : [];\n if (node.node && true === node.node.isVisible) return {\n ...node,\n children: filteredChildren\n };\n if (filteredChildren.length > 0) return {\n node: null,\n children: filteredChildren\n };\n return null;\n }\n return {\n ...execution,\n tasks: Array.isArray(execution.tasks) ? execution.tasks.map((task)=>{\n var _task_pageContext;\n const newTask = {\n ...task\n };\n if (null == (_task_pageContext = task.pageContext) ? void 0 : _task_pageContext.tree) newTask.pageContext = {\n ...task.pageContext,\n tree: filterVisibleTree(task.pageContext.tree) || {\n node: null,\n children: []\n }\n };\n return newTask;\n }) : execution.tasks\n };\n}\nconst getMidsceneVersion = ()=>\"0.26.3\";\nconst parsePrompt = (prompt)=>{\n if ('string' == typeof prompt) return {\n textPrompt: prompt,\n multimodalPrompt: void 0\n };\n return {\n textPrompt: prompt.prompt,\n multimodalPrompt: prompt.images ? {\n images: prompt.images,\n convertHttpImage2Base64: !!prompt.convertHttpImage2Base64\n } : void 0\n };\n};\nconst commonWebActionsForWebPage = (page)=>[\n {\n name: 'Tap',\n description: 'Tap the element',\n location: 'required',\n call: async (context)=>{\n const { element } = context;\n assert(element, 'Element not found, cannot tap');\n await page.mouse.click(element.center[0], element.center[1], {\n button: 'left'\n });\n }\n },\n {\n name: 'RightClick',\n description: 'Right click the element',\n location: 'required',\n call: async (context)=>{\n const { element } = context;\n assert(element, 'Element not found, cannot right click');\n await page.mouse.click(element.center[0], element.center[1], {\n button: 'right'\n });\n }\n },\n {\n name: 'Hover',\n description: 'Move the mouse to the element',\n location: 'required',\n call: async (context)=>{\n const { element } = context;\n assert(element, 'Element not found, cannot hover');\n await page.mouse.move(element.center[0], element.center[1]);\n }\n },\n {\n name: 'Input',\n description: 'Replace the input field with a new value',\n paramSchema: '{ value: string }',\n paramDescription: '`value` is the final that should be filled in the input box. No matter what modifications are required, just provide the final value to replace the existing input value. Giving a blank string means clear the input field.',\n location: 'required',\n whatToLocate: 'The input field to be filled',\n call: async (context, param)=>{\n const { element } = context;\n if (element) {\n await page.clearInput(element);\n if (!param || !param.value) return;\n }\n await page.keyboard.type(param.value);\n }\n },\n {\n name: 'KeyboardPress',\n description: 'Press a key',\n paramSchema: '{ value: string }',\n paramDescription: 'The key to be pressed',\n location: false,\n call: async (context, param)=>{\n const keys = getKeyCommands(param.value);\n await page.keyboard.press(keys);\n }\n },\n {\n name: 'Scroll',\n description: 'Scroll the page or an element',\n paramSchema: '{ direction: \"down\"(default) | \"up\" | \"right\" | \"left\", scrollType: \"once\" (default) | \"untilBottom\" | \"untilTop\" | \"untilRight\" | \"untilLeft\", distance: number | null }',\n paramDescription: 'The direction to scroll, the scroll type, and the distance to scroll. The distance is the number of pixels to scroll. If not specified, use `down` direction, `once` scroll type, and `null` distance.',\n location: 'optional',\n whatToLocate: 'The element to be scrolled',\n call: async (context, param)=>{\n const { element } = context;\n const startingPoint = element ? {\n left: element.center[0],\n top: element.center[1]\n } : void 0;\n const scrollToEventName = null == param ? void 0 : param.scrollType;\n if ('untilTop' === scrollToEventName) await page.scrollUntilTop(startingPoint);\n else if ('untilBottom' === scrollToEventName) await page.scrollUntilBottom(startingPoint);\n else if ('untilRight' === scrollToEventName) await page.scrollUntilRight(startingPoint);\n else if ('untilLeft' === scrollToEventName) await page.scrollUntilLeft(startingPoint);\n else if ('once' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);\n else {\n if ((null == param ? void 0 : param.direction) !== 'down' && param && param.direction) if ('up' === param.direction) await page.scrollUp(param.distance || void 0, startingPoint);\n else if ('left' === param.direction) await page.scrollLeft(param.distance || void 0, startingPoint);\n else if ('right' === param.direction) await page.scrollRight(param.distance || void 0, startingPoint);\n else throw new Error(`Unknown scroll direction: ${param.direction}`);\n else await page.scrollDown((null == param ? void 0 : param.distance) || void 0, startingPoint);\n await sleep(500);\n }\n }\n }\n ];\nexport { ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED, commonWebActionsForWebPage, forceClosePopup, generateCacheId, getCurrentExecutionFile, getMidsceneVersion, getReportFileName, matchElementFromCache, matchElementFromPlan, parseContextFromWebPage, parsePrompt, printReportMsg, replaceIllegalPathCharsAndSpace, trimContextByViewport };\n\n//# sourceMappingURL=utils.mjs.map","import \"node:child_process\";\nimport \"node:fs\";\nimport \"node:os\";\nimport \"node:path\";\nimport \"@midscene/shared/common\";\nimport { ANTHROPIC_API_KEY, AZURE_OPENAI_API_VERSION, AZURE_OPENAI_DEPLOYMENT, AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_KEY, MIDSCENE_API_TYPE, MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_AZURE_OPENAI_SCOPE, MIDSCENE_DEBUG_AI_PROFILE, MIDSCENE_DEBUG_AI_RESPONSE, MIDSCENE_FORCE_DEEP_THINK, MIDSCENE_LANGSMITH_DEBUG, MIDSCENE_MODEL_NAME, MIDSCENE_OPENAI_HTTP_PROXY, MIDSCENE_OPENAI_INIT_CONFIG_JSON as env_MIDSCENE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_OPENAI_SOCKS_PROXY, MIDSCENE_USE_ANTHROPIC_SDK, MIDSCENE_USE_AZURE_OPENAI, MIDSCENE_USE_QWEN_VL, MIDSCENE_USE_VLM_UI_TARS, OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MAX_TOKENS, OPENAI_USE_AZURE, getAIConfig as env_getAIConfig, getAIConfigInBoolean, getAIConfigInJson as env_getAIConfigInJson, getPreferredLanguage as env_getPreferredLanguage, uiTarsModelVersion as env_uiTarsModelVersion, vlLocateMode as env_vlLocateMode } from \"@midscene/shared/env\";\nimport \"@midscene/shared/node\";\nimport { assert as utils_assert, ifInBrowser as utils_ifInBrowser, uuid as utils_uuid } from \"@midscene/shared/utils\";\nimport { Anthropic } from \"@anthropic-ai/sdk\";\nimport { DefaultAzureCredential, getBearerTokenProvider } from \"@azure/identity\";\nimport { enableDebug, getDebug } from \"@midscene/shared/logger\";\nimport { HttpsProxyAgent } from \"https-proxy-agent\";\nimport { jsonrepair } from \"jsonrepair\";\nimport openai_0, { AzureOpenAI } from \"openai\";\nimport { SocksProxyAgent } from \"socks-proxy-agent\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport node_assert from \"node:assert\";\nimport { NodeType } from \"@midscene/shared/constants\";\nimport { descriptionOfTree, generateElementByPosition, treeToList } from \"@midscene/shared/extractor\";\nimport { compositeElementInfoImg, cropByRect, imageInfoOfBase64, paddingToMatchBlockByBase64, preProcessImageUrl } from \"@midscene/shared/img\";\nimport \"@midscene/shared/us-keyboard-layout\";\nimport \"@ui-tars/action-parser\";\nnew Map();\nfunction getVersion() {\n return \"0.26.3\";\n}\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nclass Executor {\n markTaskAsPending(task) {\n return {\n status: 'pending',\n ...task\n };\n }\n async append(task) {\n var _this_latestErrorTask, _this_latestErrorTask1;\n utils_assert('error' !== this.status, `executor is in error state, cannot append task\\nerror=${null == (_this_latestErrorTask = this.latestErrorTask()) ? void 0 : _this_latestErrorTask.error}\\n${null == (_this_latestErrorTask1 = this.latestErrorTask()) ? void 0 : _this_latestErrorTask1.errorStack}`);\n if (Array.isArray(task)) this.tasks.push(...task.map((item)=>this.markTaskAsPending(item)));\n else this.tasks.push(this.markTaskAsPending(task));\n if ('running' !== this.status) this.status = 'pending';\n }\n async flush() {\n if ('init' === this.status && this.tasks.length > 0) console.warn('illegal state for executor, status is init but tasks are not empty');\n utils_assert('running' !== this.status, 'executor is already running');\n utils_assert('completed' !== this.status, 'executor is already completed');\n utils_assert('error' !== this.status, 'executor is in error state');\n const nextPendingIndex = this.tasks.findIndex((task)=>'pending' === task.status);\n if (nextPendingIndex < 0) return;\n this.status = 'running';\n let taskIndex = nextPendingIndex;\n let successfullyCompleted = true;\n let previousFindOutput;\n while(taskIndex < this.tasks.length){\n const task = this.tasks[taskIndex];\n utils_assert('pending' === task.status, `task status should be pending, but got: ${task.status}`);\n task.timing = {\n start: Date.now()\n };\n try {\n task.status = 'running';\n try {\n if (this.onTaskStart) await this.onTaskStart(task);\n } catch (e) {\n console.error('error in onTaskStart', e);\n }\n utils_assert([\n 'Insight',\n 'Action',\n 'Planning'\n ].indexOf(task.type) >= 0, `unsupported task type: ${task.type}`);\n const { executor, param } = task;\n utils_assert(executor, `executor is required for task type: ${task.type}`);\n let returnValue;\n const executorContext = {\n task,\n element: null == previousFindOutput ? void 0 : previousFindOutput.element\n };\n if ('Insight' === task.type) {\n utils_assert('Locate' === task.subType || 'Query' === task.subType || 'Assert' === task.subType || 'Boolean' === task.subType || 'Number' === task.subType || 'String' === task.subType, `unsupported insight subType: ${task.subType}`);\n returnValue = await task.executor(param, executorContext);\n if ('Locate' === task.subType) previousFindOutput = null == returnValue ? void 0 : returnValue.output;\n } else if ('Action' === task.type || 'Planning' === task.type) returnValue = await task.executor(param, executorContext);\n else {\n console.warn(`unsupported task type: ${task.type}, will try to execute it directly`);\n returnValue = await task.executor(param, executorContext);\n }\n Object.assign(task, returnValue);\n task.status = 'finished';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n taskIndex++;\n } catch (e) {\n successfullyCompleted = false;\n task.error = e;\n task.errorMessage = (null == e ? void 0 : e.message) || ('string' == typeof e ? e : 'error-without-message');\n task.errorStack = e.stack;\n task.status = 'failed';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n break;\n }\n }\n for(let i = taskIndex + 1; i < this.tasks.length; i++)this.tasks[i].status = 'cancelled';\n if (successfullyCompleted) this.status = 'completed';\n else this.status = 'error';\n if (this.tasks.length) {\n const outputIndex = Math.min(taskIndex, this.tasks.length - 1);\n const { thought, output } = this.tasks[outputIndex];\n return {\n thought,\n output\n };\n }\n }\n isInErrorState() {\n return 'error' === this.status;\n }\n latestErrorTask() {\n if ('error' !== this.status) return null;\n const errorTaskIndex = this.tasks.findIndex((task)=>'failed' === task.status);\n if (errorTaskIndex >= 0) return this.tasks[errorTaskIndex];\n return null;\n }\n dump() {\n let modelDescription = '';\n if (env_vlLocateMode()) {\n const uiTarsModelVer = env_uiTarsModelVersion();\n modelDescription = uiTarsModelVer ? `UI-TARS=${uiTarsModelVer}` : `${env_vlLocateMode()} mode`;\n }\n const dumpData = {\n sdkVersion: getVersion(),\n model_name: env_getAIConfig(MIDSCENE_MODEL_NAME) || '',\n model_description: modelDescription,\n logTime: Date.now(),\n name: this.name,\n tasks: this.tasks\n };\n return dumpData;\n }\n constructor(name, options){\n _define_property(this, \"name\", void 0);\n _define_property(this, \"tasks\", void 0);\n _define_property(this, \"status\", void 0);\n _define_property(this, \"onTaskStart\", void 0);\n this.status = (null == options ? void 0 : options.tasks) && options.tasks.length > 0 ? 'pending' : 'init';\n this.name = name;\n this.tasks = ((null == options ? void 0 : options.tasks) || []).map((item)=>this.markTaskAsPending(item));\n this.onTaskStart = null == options ? void 0 : options.onTaskStart;\n }\n}\nvar types_AIResponseFormat = /*#__PURE__*/ function(AIResponseFormat) {\n AIResponseFormat[\"JSON\"] = \"json_object\";\n AIResponseFormat[\"TEXT\"] = \"text\";\n return AIResponseFormat;\n}({});\nconst defaultAssertionPrompt = 'You are a senior testing engineer. User will give an assertion and a screenshot of a page. By carefully viewing the screenshot, please tell whether the assertion is truthy.';\nconst defaultAssertionResponseJsonFormat = `Return in the following JSON format:\n{\n pass: boolean, // whether the assertion is truthy\n thought: string | null, // string, if the result is falsy, give the reason why it is falsy. Otherwise, put null.\n}`;\nconst getUiTarsAssertionResponseJsonFormat = ()=>`## Output Json String Format\n\\`\\`\\`\n\"{\n \"pass\": <<is a boolean value from the enum [true, false], true means the assertion is truthy>>, \n \"thought\": \"<<is a string, give the reason why the assertion is falsy or truthy. Otherwise.>>\"\n}\"\n\\`\\`\\`\n\n## Rules **MUST** follow\n- Make sure to return **only** the JSON, with **no additional** text or explanations.\n- Use ${env_getPreferredLanguage()} in \\`thought\\` part.\n- You **MUST** strictly follow up the **Output Json String Format**.`;\nfunction systemPromptToAssert(model) {\n return `${defaultAssertionPrompt}\n\n${model.isUITars ? getUiTarsAssertionResponseJsonFormat() : defaultAssertionResponseJsonFormat}`;\n}\nconst assertSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'assert',\n strict: true,\n schema: {\n type: 'object',\n properties: {\n pass: {\n type: 'boolean',\n description: 'Whether the assertion passed or failed'\n },\n thought: {\n type: [\n 'string',\n 'null'\n ],\n description: 'The thought process behind the assertion'\n }\n },\n required: [\n 'pass',\n 'thought'\n ],\n additionalProperties: false\n }\n }\n};\nfunction bboxDescription(vlMode) {\n if ('gemini' === vlMode) return '2d bounding box as [ymin, xmin, ymax, xmax]';\n return '2d bounding box as [xmin, ymin, xmax, ymax]';\n}\nfunction systemPromptToLocateElement(vlMode) {\n if (vlMode) {\n const bboxComment = bboxDescription(vlMode);\n return `\n## Role:\nYou are an expert in software testing.\n\n## Objective:\n- Identify elements in screenshots and text that match the user's description.\n- Give the coordinates of the element that matches the user's description best in the screenshot.\n- Determine whether the user's description is order-sensitive (e.g., contains phrases like 'the third item in the list', 'the last button', etc.).\n\n## Output Format:\n\\`\\`\\`json\n{\n \"bbox\": [number, number, number, number], // ${bboxComment}\n \"errors\"?: string[],\n \"isOrderSensitive\": boolean // Whether the targetElementDescription is order-sensitive (true/false)\n}\n\\`\\`\\`\n\nFields:\n* \\`bbox\\` is the bounding box of the element that matches the user's description best in the screenshot\n* \\`isOrderSensitive\\` is a boolean indicating whether the user's description is order-sensitive (true/false)\n* \\`errors\\` is an optional array of error messages (if any)\n\nOrder-sensitive means the description contains phrases like:\n- \"the third item in the list\"\n- \"the last button\"\n- \"the first input box\"\n- \"the second row\"\n\nNot order-sensitive means the description is like:\n- \"confirm button\"\n- \"search box\"\n- \"password input\"\n\nFor example, when an element is found and the description is order-sensitive:\n\\`\\`\\`json\n{\n \"bbox\": [100, 100, 200, 200],\n \"isOrderSensitive\": true,\n \"errors\": []\n}\n\\`\\`\\`\n\nWhen no element is found and the description is not order-sensitive:\n\\`\\`\\`json\n{\n \"bbox\": [],\n \"isOrderSensitive\": false,\n \"errors\": [\"I can see ..., but {some element} is not found\"]\n}\n\\`\\`\\`\n`;\n }\n return `\n## Role:\nYou are an expert in software page image (2D) and page element text analysis.\n\n## Objective:\n- Identify elements in screenshots and text that match the user's description.\n- Return JSON data containing the selection reason and element ID.\n- Determine whether the user's description is order-sensitive (e.g., contains phrases like 'the third item in the list', 'the last button', etc.).\n\n## Skills:\n- Image analysis and recognition\n- Multilingual text understanding\n- Software UI design and testing\n\n## Workflow:\n1. Receive the user's element description, screenshot, and element description information. Note that the text may contain non-English characters (e.g., Chinese), indicating that the application may be non-English.\n2. Based on the user's description, locate the target element ID in the list of element descriptions and the screenshot.\n3. Found the required number of elements\n4. Return JSON data containing the selection reason and element ID.\n5. Judge whether the user's description is order-sensitive (see below for definition and examples).\n\n## Constraints:\n- Strictly adhere to the specified location when describing the required element; do not select elements from other locations.\n- Elements in the image with NodeType other than \"TEXT Node\" have been highlighted to identify the element among multiple non-text elements.\n- Accurately identify element information based on the user's description and return the corresponding element ID from the element description information, not extracted from the image.\n- If no elements are found, the \"elements\" array should be empty.\n- The returned data must conform to the specified JSON format.\n- The returned value id information must use the id from element info (important: **use id not indexId, id is hash content**)\n\n## Order-Sensitive Definition:\n- If the description contains phrases like \"the third item in the list\", \"the last button\", \"the first input box\", \"the second row\", etc., it is order-sensitive (isOrderSensitive = true).\n- If the description is like \"confirm button\", \"search box\", \"password input\", etc., it is not order-sensitive (isOrderSensitive = false).\n\n## Output Format:\n\nPlease return the result in JSON format as follows:\n\n\\`\\`\\`json\n{\n \"elements\": [\n // If no matching elements are found, return an empty array []\n {\n \"reason\": \"PLACEHOLDER\", // The thought process for finding the element, replace PLACEHOLDER with your thought process\n \"text\": \"PLACEHOLDER\", // Replace PLACEHOLDER with the text of elementInfo, if none, leave empty\n \"id\": \"PLACEHOLDER\" // Replace PLACEHOLDER with the ID (important: **use id not indexId, id is hash content**) of elementInfo\n }\n // More elements...\n ],\n \"isOrderSensitive\": true, // or false, depending on the user's description\n \"errors\": [] // Array of strings containing any error messages\n}\n\\`\\`\\`\n\n## Example:\nExample 1:\nInput Example:\n\\`\\`\\`json\n// Description: \"Shopping cart icon in the upper right corner\"\n{\n \"description\": \"PLACEHOLDER\", // Description of the target element\n \"screenshot\": \"path/screenshot.png\",\n \"text\": '{\n \"pageSize\": {\n \"width\": 400, // Width of the page\n \"height\": 905 // Height of the page\n },\n \"elementInfos\": [\n {\n \"id\": \"1231\", // ID of the element\n \"indexId\": \"0\", // Index of the element\\u{FF0C}The image is labeled to the left of the element\n \"attributes\": { // Attributes of the element\n \"nodeType\": \"IMG Node\", // Type of element, types include: TEXT Node, IMG Node, BUTTON Node, INPUT Node\n \"src\": \"https://ap-southeast-3.m\",\n \"class\": \".img\"\n },\n \"content\": \"\", // Text content of the element\n \"rect\": {\n \"left\": 280, // Distance from the left side of the page\n \"top\": 8, // Distance from the top of the page\n \"width\": 44, // Width of the element\n \"height\": 44 // Height of the element\n }\n },\n {\n \"id\": \"66551\", // ID of the element\n \"indexId\": \"1\", // Index of the element,The image is labeled to the left of the element\n \"attributes\": { // Attributes of the element\n \"nodeType\": \"IMG Node\", // Type of element, types include: TEXT Node, IMG Node, BUTTON Node, INPUT Node\n \"src\": \"data:image/png;base64,iVBORw0KGgoAAAANSU...\",\n \"class\": \".icon\"\n },\n \"content\": \"\", // Text content of the element\n \"rect\": {\n \"left\": 350, // Distance from the left side of the page\n \"top\": 16, // Distance from the top of the page\n \"width\": 25, // Width of the element\n \"height\": 25 // Height of the element\n }\n },\n ...\n {\n \"id\": \"12344\",\n \"indexId\": \"2\", // Index of the element\\u{FF0C}The image is labeled to the left of the element\n \"attributes\": {\n \"nodeType\": \"TEXT Node\",\n \"class\": \".product-name\"\n },\n \"center\": [\n 288,\n 834\n ],\n \"content\": \"Mango Drink\",\n \"rect\": {\n \"left\": 188,\n \"top\": 827,\n \"width\": 199,\n \"height\": 13\n }\n },\n ...\n ]\n }\n '\n}\n\\`\\`\\`\nOutput Example:\n\\`\\`\\`json\n{\n \"elements\": [\n {\n // Describe the reason for finding this element, replace with actual value in practice\n \"reason\": \"Reason for finding element 4: It is located in the upper right corner, is an image type, and according to the screenshot, it is a shopping cart icon button\",\n \"text\": \"\",\n // ID(**use id not indexId**) of this element, replace with actual value in practice, **use id not indexId**\n \"id\": \"1231\"\n }\n ],\n \"isOrderSensitive\": true,\n \"errors\": []\n}\n\\`\\`\\`\n \n `;\n}\nconst locatorSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'find_elements',\n strict: true,\n schema: {\n type: 'object',\n properties: {\n elements: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n reason: {\n type: 'string',\n description: 'Reason for finding this element'\n },\n text: {\n type: 'string',\n description: 'Text content of the element'\n },\n id: {\n type: 'string',\n description: 'ID of this element'\n }\n },\n required: [\n 'reason',\n 'text',\n 'id'\n ],\n additionalProperties: false\n },\n description: 'List of found elements'\n },\n isOrderSensitive: {\n type: 'boolean',\n description: \"Whether the targetElementDescription is order-sensitive (true/false)\"\n },\n errors: {\n type: 'array',\n items: {\n type: 'string'\n },\n description: 'List of error messages, if any'\n }\n },\n required: [\n 'elements',\n 'isOrderSensitive',\n 'errors'\n ],\n additionalProperties: false\n }\n }\n};\nconst findElementPrompt = new PromptTemplate({\n template: `\nHere is the item user want to find:\n=====================================\n{targetElementDescription}\n=====================================\n\n{pageDescription}\n `,\n inputVariables: [\n \"pageDescription\",\n \"targetElementDescription\"\n ]\n});\nconst vlCoTLog = '\"what_the_user_wants_to_do_next_by_instruction\": string, // What the user wants to do according to the instruction and previous logs. ';\nconst vlCurrentLog = '\"log\": string, // Log what the next one action (ONLY ONE!) you can do according to the screenshot and the instruction. The typical log looks like \"Now i want to use action \\'{ action-type }\\' to do .. first\". If no action should be done, log the reason. \". Use the same language as the user\\'s instruction.';\nconst llmCurrentLog = '\"log\": string, // Log what the next actions you can do according to the screenshot and the instruction. The typical log looks like \"Now i want to use action \\'{ action-type }\\' to do ..\". If no action should be done, log the reason. \". Use the same language as the user\\'s instruction.';\nconst commonOutputFields = `\"error\"?: string, // Error messages about unexpected situations, if any. Only think it is an error when the situation is not foreseeable according to the instruction. Use the same language as the user's instruction.\n \"more_actions_needed_by_instruction\": boolean, // Consider if there is still more action(s) to do after the action in \"Log\" is done, according to the instruction. If so, set this field to true. Otherwise, set it to false.`;\nconst vlLocateParam = (required)=>`locate${required ? '' : '?'}: {bbox: [number, number, number, number], prompt: string }`;\nconst llmLocateParam = (required)=>`locate${required ? '' : '?'}: {\"id\": string, \"prompt\": string}`;\nconst descriptionForAction = (action, locatorScheme)=>{\n const tab = ' ';\n let locateParam = '';\n if ('required' === action.location) locateParam = locatorScheme;\n else if ('optional' === action.location) locateParam = `${locatorScheme} | null`;\n else if (false === action.location) locateParam = '';\n const locatorParam = locateParam ? `- ${locateParam}` : '';\n if (action.whatToLocate) if (locateParam) locateParam += ` // ${action.whatToLocate}`;\n else console.warn(`whatToLocate is provided for action ${action.name}, but location is not required or optional. The whatToLocate will be ignored.`);\n let paramSchema = '';\n if (action.paramSchema) paramSchema = `- param: ${action.paramSchema}`;\n if (action.paramDescription) {\n node_assert(paramSchema, `paramSchema is required when paramDescription is provided for action ${action.name}, but got ${action.paramSchema}`);\n paramSchema += ` // ${action.paramDescription}`;\n }\n const fields = [\n paramSchema,\n locatorParam\n ].filter(Boolean);\n return `- ${action.name}, ${action.description}\n${tab}- type: \"${action.name}\"\n${tab}${fields.join(`\\n${tab}`)}\n`.trim();\n};\nconst systemTemplateOfVLPlanning = ({ actionSpace, vlMode })=>{\n const actionNameList = actionSpace.map((action)=>action.name).join(', ');\n const actionDescriptionList = actionSpace.map((action)=>descriptionForAction(action, vlLocateParam('required' === action.location)));\n const actionList = actionDescriptionList.join('\\n');\n return `\nTarget: User will give you a screenshot, an instruction and some previous logs indicating what have been done. Please tell what the next one action is (or null if no action should be done) to do the tasks the instruction requires. \n\nRestriction:\n- Don't give extra actions or plans beyond the instruction. ONLY plan for what the instruction requires. For example, don't try to submit the form if the instruction is only to fill something.\n- Always give ONLY ONE action in \\`log\\` field (or null if no action should be done), instead of multiple actions. Supported actions are ${actionNameList}.\n- Don't repeat actions in the previous logs.\n- Bbox is the bounding box of the element to be located. It's an array of 4 numbers, representing ${bboxDescription(vlMode)}.\n\nSupporting actions:\n${actionList}\n\nField description:\n* The \\`prompt\\` field inside the \\`locate\\` field is a short description that could be used to locate the element.\n\nReturn in JSON format:\n{\n ${vlCoTLog}\n ${vlCurrentLog}\n ${commonOutputFields}\n \"action\": \n {\n // one of the supporting actions\n } | null,\n ,\n \"sleep\"?: number, // The sleep time after the action, in milliseconds.\n}\n\nFor example, when the instruction is \"click 'Confirm' button, and click 'Yes' in popup\" and the log is \"I will use action Tap to click 'Confirm' button\", by viewing the screenshot and previous logs, you should consider: We have already clicked the 'Confirm' button, so next we should find and click 'Yes' in popup.\n\nthis and output the JSON:\n\n{\n \"what_the_user_wants_to_do_next_by_instruction\": \"We have already clicked the 'Confirm' button, so next we should find and click 'Yes' in popup\",\n \"log\": \"I will use action Tap to click 'Yes' in popup\",\n \"more_actions_needed_by_instruction\": false,\n \"action\": {\n \"type\": \"Tap\",\n \"locate\": {\n \"bbox\": [100, 100, 200, 200],\n \"prompt\": \"The 'Yes' button in popup\"\n }\n }\n}\n`;\n};\nconst systemTemplateOfLLM = ({ actionSpace })=>{\n const actionNameList = actionSpace.map((action)=>action.name).join(' / ');\n const actionDescriptionList = actionSpace.map((action)=>descriptionForAction(action, llmLocateParam('required' === action.location)));\n const actionList = actionDescriptionList.join('\\n');\n return `\n## Role\n\nYou are a versatile professional in software UI automation. Your outstanding contributions will impact the user experience of billions of users.\n\n## Objective\n\n- Decompose the instruction user asked into a series of actions\n- Locate the target element if possible\n- If the instruction cannot be accomplished, give a further plan.\n\n## Workflow\n\n1. Receive the screenshot, element description of screenshot(if any), user's instruction and previous logs.\n2. Decompose the user's task into a sequence of feasible actions, and place it in the \\`actions\\` field. There are different types of actions (${actionNameList}). The \"About the action\" section below will give you more details.\n3. Consider whether the user's instruction will be accomplished after the actions you composed.\n- If the instruction is accomplished, set \\`more_actions_needed_by_instruction\\` to false.\n- If more actions are needed, set \\`more_actions_needed_by_instruction\\` to true. Get ready to hand over to the next talent people like you. Carefully log what have been done in the \\`log\\` field, he or she will continue the task according to your logs.\n4. If the task is not feasible on this page, set \\`error\\` field to the reason.\n\n## Constraints\n\n- All the actions you composed MUST be feasible, which means all the action fields can be filled with the page context information you get. If not, don't plan this action.\n- Trust the \"What have been done\" field about the task (if any), don't repeat actions in it.\n- Respond only with valid JSON. Do not write an introduction or summary or markdown prefix like \\`\\`\\`json\\`\\`\\`.\n- If the screenshot and the instruction are totally irrelevant, set reason in the \\`error\\` field.\n\n## About the \\`actions\\` field\n\nThe \\`locate\\` param is commonly used in the \\`param\\` field of the action, means to locate the target element to perform the action, it conforms to the following scheme:\n\ntype LocateParam = {\n \"id\": string, // the id of the element found. It should either be the id marked with a rectangle in the screenshot or the id described in the description.\n \"prompt\"?: string // the description of the element to find. It can only be omitted when locate is null.\n} | null // If it's not on the page, the LocateParam should be null\n\n## Supported actions\n\nEach action has a \\`type\\` and corresponding \\`param\\`. To be detailed:\n${actionList}\n\n`.trim();\n};\nconst outputTemplate = `\n## Output JSON Format:\n\nThe JSON format is as follows:\n\n{\n \"actions\": [\n // ... some actions\n ],\n ${llmCurrentLog}\n ${commonOutputFields}\n}\n\n## Examples\n\n### Example: Decompose a task\n\nWhen you received the following information:\n\n* Instruction: 'Click the language switch button, wait 1s, click \"English\"'\n* Logs: null\n* Page Context (screenshot and description) shows: There is a language switch button, and the \"English\" option is not shown in the screenshot now.\n\nBy viewing the page screenshot and description, you should consider this and output the JSON:\n\n* The user intent is: tap the switch button, sleep, and tap the 'English' option\n* The language switch button is shown in the screenshot, and can be located by the page description or the id marked with a rectangle. So we can plan a Tap action to do this.\n* Plan a Sleep action to wait for 1 second to ensure the language options are displayed.\n* The \"English\" option button is not shown in the screenshot now, it means it may only show after the previous actions are finished. So don't plan any action to do this.\n* Log what these action do: Click the language switch button to open the language options. Wait for 1 second.\n* The task cannot be accomplished (because the last tapping action is not finished yet), so the \\`more_actions_needed_by_instruction\\` field is true. The \\`error\\` field is null.\n\n{\n \"actions\":[\n {\n \"thought\": \"Click the language switch button to open the language options.\",\n \"type\": \"Tap\", \n \"param\": null,\n \"locate\": { id: \"c81c4e9a33\", prompt: \"The language switch button\" }},\n },\n {\n \"thought\": \"Wait for 1 second to ensure the language options are displayed.\",\n \"type\": \"Sleep\",\n \"param\": { \"timeMs\": 1000 },\n }\n ],\n \"error\": null,\n \"more_actions_needed_by_instruction\": true,\n \"log\": \"Click the language switch button to open the language options. Wait for 1 second\",\n}\n\n### Example: What NOT to do\nWrong output:\n{\n \"actions\":[\n {\n \"thought\": \"Click the language switch button to open the language options.\",\n \"type\": \"Tap\",\n \"param\": null,\n \"locate\": {\n { \"id\": \"c81c4e9a33\" }, // WRONG: prompt is missing, this is not a valid LocateParam\n }\n },\n {\n \"thought\": \"Click the English option\",\n \"type\": \"Tap\", \n \"param\": null,\n \"locate\": null, // This means the 'English' option is not shown in the screenshot, the task cannot be accomplished\n }\n ],\n \"more_actions_needed_by_instruction\": false, // WRONG: should be true\n \"log\": \"Click the language switch button to open the language options\",\n}\n`;\nasync function systemPromptToTaskPlanning({ actionSpace, vlMode }) {\n if (vlMode) return systemTemplateOfVLPlanning({\n actionSpace,\n vlMode\n });\n return `${systemTemplateOfLLM({\n actionSpace\n })}\\n\\n${outputTemplate}`;\n}\nconst planSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'action_items',\n strict: false,\n schema: {\n type: 'object',\n strict: false,\n properties: {\n actions: {\n type: 'array',\n items: {\n type: 'object',\n strict: false,\n properties: {\n thought: {\n type: 'string',\n description: 'Reasons for generating this task, and why this task is feasible on this page'\n },\n type: {\n type: 'string',\n description: 'Type of action'\n },\n param: {\n anyOf: [\n {\n type: 'null'\n },\n {\n type: 'object',\n additionalProperties: true\n }\n ],\n description: 'Parameter of the action'\n },\n locate: {\n type: [\n 'object',\n 'null'\n ],\n properties: {\n id: {\n type: 'string'\n },\n prompt: {\n type: 'string'\n }\n },\n required: [\n 'id',\n 'prompt'\n ],\n additionalProperties: false,\n description: 'Location information for the target element'\n }\n },\n required: [\n 'thought',\n 'type',\n 'param',\n 'locate'\n ],\n additionalProperties: false\n },\n description: 'List of actions to be performed'\n },\n more_actions_needed_by_instruction: {\n type: 'boolean',\n description: 'If all the actions described in the instruction have been covered by this action and logs, set this field to false.'\n },\n log: {\n type: 'string',\n description: 'Log what these planned actions do. Do not include further actions that have not been planned.'\n },\n error: {\n type: [\n 'string',\n 'null'\n ],\n description: 'Error messages about unexpected situations'\n }\n },\n required: [\n 'actions',\n 'more_actions_needed_by_instruction',\n 'log',\n 'error'\n ],\n additionalProperties: false\n }\n }\n};\nconst generateTaskBackgroundContext = (userInstruction, log, userActionContext)=>{\n if (log) return `\nHere is the user's instruction:\n\n<instruction>\n <high_priority_knowledge>\n ${userActionContext}\n </high_priority_knowledge>\n\n ${userInstruction}\n</instruction>\n\nThese are the logs from previous executions, which indicate what was done in the previous actions.\nDo NOT repeat these actions.\n<previous_logs>\n${log}\n</previous_logs>\n`;\n return `\nHere is the user's instruction:\n<instruction>\n <high_priority_knowledge>\n ${userActionContext}\n </high_priority_knowledge>\n\n ${userInstruction}\n</instruction>\n`;\n};\nconst automationUserPrompt = (vlMode)=>{\n if (vlMode) return new PromptTemplate({\n template: '{taskBackgroundContext}',\n inputVariables: [\n 'taskBackgroundContext'\n ]\n });\n return new PromptTemplate({\n template: `\npageDescription:\n=====================================\n{pageDescription}\n=====================================\n\n{taskBackgroundContext}`,\n inputVariables: [\n \"pageDescription\",\n 'taskBackgroundContext'\n ]\n });\n};\nfunction checkAIConfig() {\n const openaiKey = env_getAIConfig(OPENAI_API_KEY);\n const azureConfig = env_getAIConfig(MIDSCENE_USE_AZURE_OPENAI);\n const anthropicKey = env_getAIConfig(ANTHROPIC_API_KEY);\n const initConfigJson = env_getAIConfig(env_MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n if (openaiKey) return true;\n if (azureConfig) return true;\n if (anthropicKey) return true;\n return Boolean(initConfigJson);\n}\nlet debugConfigInitialized = false;\nfunction initDebugConfig() {\n if (debugConfigInitialized) return;\n const shouldPrintTiming = getAIConfigInBoolean(MIDSCENE_DEBUG_AI_PROFILE);\n let debugConfig = '';\n if (shouldPrintTiming) {\n console.warn('MIDSCENE_DEBUG_AI_PROFILE is deprecated, use DEBUG=midscene:ai:profile instead');\n debugConfig = 'ai:profile';\n }\n const shouldPrintAIResponse = getAIConfigInBoolean(MIDSCENE_DEBUG_AI_RESPONSE);\n if (shouldPrintAIResponse) {\n console.warn('MIDSCENE_DEBUG_AI_RESPONSE is deprecated, use DEBUG=midscene:ai:response instead');\n debugConfig = debugConfig ? 'ai:*' : 'ai:call';\n }\n if (debugConfig) enableDebug(debugConfig);\n debugConfigInitialized = true;\n}\nconst defaultModel = 'gpt-4o';\nfunction getModelName() {\n let modelName = defaultModel;\n const nameInConfig = env_getAIConfig(MIDSCENE_MODEL_NAME);\n if (nameInConfig) modelName = nameInConfig;\n return modelName;\n}\nasync function createChatClient({ AIActionTypeValue }) {\n initDebugConfig();\n let openai;\n const extraConfig = env_getAIConfigInJson(env_MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n const socksProxy = env_getAIConfig(MIDSCENE_OPENAI_SOCKS_PROXY);\n const httpProxy = env_getAIConfig(MIDSCENE_OPENAI_HTTP_PROXY);\n let proxyAgent;\n const debugProxy = getDebug('ai:call:proxy');\n if (httpProxy) {\n debugProxy('using http proxy', httpProxy);\n proxyAgent = new HttpsProxyAgent(httpProxy);\n } else if (socksProxy) {\n debugProxy('using socks proxy', socksProxy);\n proxyAgent = new SocksProxyAgent(socksProxy);\n }\n if (env_getAIConfig(OPENAI_USE_AZURE)) openai = new AzureOpenAI({\n baseURL: env_getAIConfig(OPENAI_BASE_URL),\n apiKey: env_getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n dangerouslyAllowBrowser: true\n });\n else if (env_getAIConfig(MIDSCENE_USE_AZURE_OPENAI)) {\n const extraAzureConfig = env_getAIConfigInJson(MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON);\n const scope = env_getAIConfig(MIDSCENE_AZURE_OPENAI_SCOPE);\n let tokenProvider;\n if (scope) {\n utils_assert(!utils_ifInBrowser, 'Azure OpenAI is not supported in browser with Midscene.');\n const credential = new DefaultAzureCredential();\n utils_assert(scope, 'MIDSCENE_AZURE_OPENAI_SCOPE is required');\n tokenProvider = getBearerTokenProvider(credential, scope);\n openai = new AzureOpenAI({\n azureADTokenProvider: tokenProvider,\n endpoint: env_getAIConfig(AZURE_OPENAI_ENDPOINT),\n apiVersion: env_getAIConfig(AZURE_OPENAI_API_VERSION),\n deployment: env_getAIConfig(AZURE_OPENAI_DEPLOYMENT),\n ...extraConfig,\n ...extraAzureConfig\n });\n } else openai = new AzureOpenAI({\n apiKey: env_getAIConfig(AZURE_OPENAI_KEY),\n endpoint: env_getAIConfig(AZURE_OPENAI_ENDPOINT),\n apiVersion: env_getAIConfig(AZURE_OPENAI_API_VERSION),\n deployment: env_getAIConfig(AZURE_OPENAI_DEPLOYMENT),\n dangerouslyAllowBrowser: true,\n ...extraConfig,\n ...extraAzureConfig\n });\n } else if (!env_getAIConfig(MIDSCENE_USE_ANTHROPIC_SDK)) {\n const baseURL = env_getAIConfig(OPENAI_BASE_URL);\n if ('string' == typeof baseURL) {\n if (!/^https?:\\/\\//.test(baseURL)) throw new Error(`OPENAI_BASE_URL must be a valid URL starting with http:// or https://, but got: ${baseURL}\\nPlease check your config.`);\n }\n openai = new openai_0({\n baseURL: env_getAIConfig(OPENAI_BASE_URL),\n apiKey: env_getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n defaultHeaders: {\n ...(null == extraConfig ? void 0 : extraConfig.defaultHeaders) || {},\n [MIDSCENE_API_TYPE]: AIActionTypeValue.toString()\n },\n dangerouslyAllowBrowser: true\n });\n }\n if (openai && getAIConfigInBoolean(MIDSCENE_LANGSMITH_DEBUG)) {\n if (utils_ifInBrowser) throw new Error('langsmith is not supported in browser');\n console.log('DEBUGGING MODE: langsmith wrapper enabled');\n const { wrapOpenAI } = await import(\"langsmith/wrappers\");\n openai = wrapOpenAI(openai);\n }\n if (void 0 !== openai) return {\n completion: openai.chat.completions,\n style: 'openai'\n };\n if (env_getAIConfig(MIDSCENE_USE_ANTHROPIC_SDK)) {\n const apiKey = env_getAIConfig(ANTHROPIC_API_KEY);\n utils_assert(apiKey, 'ANTHROPIC_API_KEY is required');\n openai = new Anthropic({\n apiKey,\n httpAgent: proxyAgent,\n dangerouslyAllowBrowser: true\n });\n }\n if (void 0 !== openai && openai.messages) return {\n completion: openai.messages,\n style: 'anthropic'\n };\n throw new Error('Openai SDK or Anthropic SDK is not initialized');\n}\nasync function service_caller_call(messages, AIActionTypeValue, responseFormat, options) {\n utils_assert(checkAIConfig(), 'Cannot find config for AI model service. If you are using a self-hosted model without validating the API key, please set `OPENAI_API_KEY` to any non-null value. https://midscenejs.com/model-provider.html');\n const { completion, style } = await createChatClient({\n AIActionTypeValue\n });\n const maxTokens = env_getAIConfig(OPENAI_MAX_TOKENS);\n const debugCall = getDebug('ai:call');\n const debugProfileStats = getDebug('ai:profile:stats');\n const debugProfileDetail = getDebug('ai:profile:detail');\n const startTime = Date.now();\n const model = getModelName();\n const isStreaming = (null == options ? void 0 : options.stream) && (null == options ? void 0 : options.onChunk);\n let content;\n let accumulated = '';\n let usage;\n let timeCost;\n const commonConfig = {\n temperature: 'vlm-ui-tars' === env_vlLocateMode() ? 0.0 : 0.1,\n stream: !!isStreaming,\n max_tokens: 'number' == typeof maxTokens ? maxTokens : Number.parseInt(maxTokens || '2048', 10),\n ...'qwen-vl' === env_vlLocateMode() ? {\n vl_high_resolution_images: true\n } : {}\n };\n try {\n if ('openai' === style) {\n debugCall(`sending ${isStreaming ? 'streaming ' : ''}request to ${model}`);\n if (isStreaming) {\n const stream = await completion.create({\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig\n }, {\n stream: true\n });\n for await (const chunk of stream){\n var _chunk_choices__delta, _chunk_choices_, _chunk_choices, _chunk_choices__delta1, _chunk_choices_1, _chunk_choices1, _chunk_choices_2, _chunk_choices2;\n const content = (null == (_chunk_choices = chunk.choices) ? void 0 : null == (_chunk_choices_ = _chunk_choices[0]) ? void 0 : null == (_chunk_choices__delta = _chunk_choices_.delta) ? void 0 : _chunk_choices__delta.content) || '';\n const reasoning_content = (null == (_chunk_choices1 = chunk.choices) ? void 0 : null == (_chunk_choices_1 = _chunk_choices1[0]) ? void 0 : null == (_chunk_choices__delta1 = _chunk_choices_1.delta) ? void 0 : _chunk_choices__delta1.reasoning_content) || '';\n if (chunk.usage) usage = chunk.usage;\n if (content || reasoning_content) {\n accumulated += content;\n const chunkData = {\n content,\n reasoning_content,\n accumulated,\n isComplete: false,\n usage: void 0\n };\n options.onChunk(chunkData);\n }\n if (null == (_chunk_choices2 = chunk.choices) ? void 0 : null == (_chunk_choices_2 = _chunk_choices2[0]) ? void 0 : _chunk_choices_2.finish_reason) {\n timeCost = Date.now() - startTime;\n if (!usage) {\n const estimatedTokens = Math.max(1, Math.floor(accumulated.length / 4));\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: 2 * estimatedTokens\n };\n }\n const finalChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: {\n prompt_tokens: usage.prompt_tokens ?? 0,\n completion_tokens: usage.completion_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n time_cost: timeCost ?? 0\n }\n };\n options.onChunk(finalChunk);\n break;\n }\n }\n content = accumulated;\n debugProfileStats(`streaming model, ${model}, mode, ${env_vlLocateMode() || 'default'}, cost-ms, ${timeCost}`);\n } else {\n var _result_usage, _result_usage1, _result_usage2;\n const result = await completion.create({\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig\n });\n timeCost = Date.now() - startTime;\n debugProfileStats(`model, ${model}, mode, ${env_vlLocateMode() || 'default'}, ui-tars-version, ${env_uiTarsModelVersion()}, prompt-tokens, ${(null == (_result_usage = result.usage) ? void 0 : _result_usage.prompt_tokens) || ''}, completion-tokens, ${(null == (_result_usage1 = result.usage) ? void 0 : _result_usage1.completion_tokens) || ''}, total-tokens, ${(null == (_result_usage2 = result.usage) ? void 0 : _result_usage2.total_tokens) || ''}, cost-ms, ${timeCost}, requestId, ${result._request_id || ''}`);\n debugProfileDetail(`model usage detail: ${JSON.stringify(result.usage)}`);\n utils_assert(result.choices, `invalid response from LLM service: ${JSON.stringify(result)}`);\n content = result.choices[0].message.content;\n usage = result.usage;\n }\n debugCall(`response: ${content}`);\n utils_assert(content, 'empty content');\n } else if ('anthropic' === style) {\n const convertImageContent = (content)=>{\n if ('image_url' === content.type) {\n const imgBase64 = content.image_url.url;\n utils_assert(imgBase64, 'image_url is required');\n return {\n source: {\n type: 'base64',\n media_type: imgBase64.includes('data:image/png;base64,') ? 'image/png' : 'image/jpeg',\n data: imgBase64.split(',')[1]\n },\n type: 'image'\n };\n }\n return content;\n };\n if (isStreaming) {\n const stream = await completion.create({\n model,\n system: 'You are a versatile professional in software UI automation',\n messages: messages.map((m)=>({\n role: 'user',\n content: Array.isArray(m.content) ? m.content.map(convertImageContent) : m.content\n })),\n response_format: responseFormat,\n ...commonConfig\n });\n for await (const chunk of stream){\n var _chunk_delta;\n const content = (null == (_chunk_delta = chunk.delta) ? void 0 : _chunk_delta.text) || '';\n if (content) {\n accumulated += content;\n const chunkData = {\n content,\n accumulated,\n reasoning_content: '',\n isComplete: false,\n usage: void 0\n };\n options.onChunk(chunkData);\n }\n if ('message_stop' === chunk.type) {\n timeCost = Date.now() - startTime;\n const anthropicUsage = chunk.usage;\n const finalChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: anthropicUsage ? {\n prompt_tokens: anthropicUsage.input_tokens ?? 0,\n completion_tokens: anthropicUsage.output_tokens ?? 0,\n total_tokens: (anthropicUsage.input_tokens ?? 0) + (anthropicUsage.output_tokens ?? 0),\n time_cost: timeCost ?? 0\n } : void 0\n };\n options.onChunk(finalChunk);\n break;\n }\n }\n content = accumulated;\n } else {\n const result = await completion.create({\n model,\n system: 'You are a versatile professional in software UI automation',\n messages: messages.map((m)=>({\n role: 'user',\n content: Array.isArray(m.content) ? m.content.map(convertImageContent) : m.content\n })),\n response_format: responseFormat,\n ...commonConfig\n });\n timeCost = Date.now() - startTime;\n content = result.content[0].text;\n usage = result.usage;\n }\n utils_assert(content, 'empty content');\n }\n if (isStreaming && !usage) {\n const estimatedTokens = Math.max(1, Math.floor((content || '').length / 4));\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: 2 * estimatedTokens\n };\n }\n return {\n content: content || '',\n usage: usage ? {\n prompt_tokens: usage.prompt_tokens ?? 0,\n completion_tokens: usage.completion_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n time_cost: timeCost ?? 0\n } : void 0,\n isStreamed: !!isStreaming\n };\n } catch (e) {\n console.error(' call AI error', e);\n const newError = new Error(`failed to call ${isStreaming ? 'streaming ' : ''}AI model service: ${e.message}. Trouble shooting: https://midscenejs.com/model-provider.html`, {\n cause: e\n });\n throw newError;\n }\n}\nasync function callToGetJSONObject(messages, AIActionTypeValue) {\n let responseFormat;\n const model = getModelName();\n if (model.includes('gpt-4')) switch(AIActionTypeValue){\n case common_AIActionType.ASSERT:\n responseFormat = assertSchema;\n break;\n case common_AIActionType.INSPECT_ELEMENT:\n responseFormat = locatorSchema;\n break;\n case common_AIActionType.PLAN:\n responseFormat = planSchema;\n break;\n case common_AIActionType.EXTRACT_DATA:\n case common_AIActionType.DESCRIBE_ELEMENT:\n responseFormat = {\n type: types_AIResponseFormat.JSON\n };\n break;\n }\n if ('gpt-4o-2024-05-13' === model) responseFormat = {\n type: types_AIResponseFormat.JSON\n };\n const response = await service_caller_call(messages, AIActionTypeValue, responseFormat);\n utils_assert(response, 'empty response');\n const jsonContent = safeParseJson(response.content);\n return {\n content: jsonContent,\n usage: response.usage\n };\n}\nfunction extractJSONFromCodeBlock(response) {\n try {\n const jsonMatch = response.match(/^\\s*(\\{[\\s\\S]*\\})\\s*$/);\n if (jsonMatch) return jsonMatch[1];\n const codeBlockMatch = response.match(/```(?:json)?\\s*(\\{[\\s\\S]*?\\})\\s*```/);\n if (codeBlockMatch) return codeBlockMatch[1];\n const jsonLikeMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonLikeMatch) return jsonLikeMatch[0];\n } catch {}\n return response;\n}\nfunction preprocessDoubaoBboxJson(input) {\n if (input.includes('bbox')) while(/\\d+\\s+\\d+/.test(input))input = input.replace(/(\\d+)\\s+(\\d+)/g, '$1,$2');\n return input;\n}\nfunction safeParseJson(input) {\n const cleanJsonString = extractJSONFromCodeBlock(input);\n if (null == cleanJsonString ? void 0 : cleanJsonString.match(/\\((\\d+),(\\d+)\\)/)) {\n var _cleanJsonString_match;\n return null == (_cleanJsonString_match = cleanJsonString.match(/\\((\\d+),(\\d+)\\)/)) ? void 0 : _cleanJsonString_match.slice(1).map(Number);\n }\n try {\n return JSON.parse(cleanJsonString);\n } catch {}\n try {\n return JSON.parse(jsonrepair(cleanJsonString));\n } catch (e) {}\n if ('doubao-vision' === env_vlLocateMode() || 'vlm-ui-tars' === env_vlLocateMode()) {\n const jsonString = preprocessDoubaoBboxJson(cleanJsonString);\n return JSON.parse(jsonrepair(jsonString));\n }\n throw Error(`failed to parse json response: ${input}`);\n}\nvar common_AIActionType = /*#__PURE__*/ function(AIActionType) {\n AIActionType[AIActionType[\"ASSERT\"] = 0] = \"ASSERT\";\n AIActionType[AIActionType[\"INSPECT_ELEMENT\"] = 1] = \"INSPECT_ELEMENT\";\n AIActionType[AIActionType[\"EXTRACT_DATA\"] = 2] = \"EXTRACT_DATA\";\n AIActionType[AIActionType[\"PLAN\"] = 3] = \"PLAN\";\n AIActionType[AIActionType[\"DESCRIBE_ELEMENT\"] = 4] = \"DESCRIBE_ELEMENT\";\n return AIActionType;\n}({});\nasync function callAiFn(msgs, AIActionTypeValue) {\n const jsonObject = await callToGetJSONObject(msgs, AIActionTypeValue);\n return {\n content: jsonObject.content,\n usage: jsonObject.usage\n };\n}\nconst defaultBboxSize = 20;\nconst debugInspectUtils = getDebug('ai:common');\nfunction fillBboxParam(locate, width, height) {\n if (locate.bbox_2d && !(null == locate ? void 0 : locate.bbox)) {\n locate.bbox = locate.bbox_2d;\n delete locate.bbox_2d;\n }\n if (null == locate ? void 0 : locate.bbox) locate.bbox = adaptBbox(locate.bbox, width, height);\n return locate;\n}\nfunction adaptQwenBbox(bbox) {\n if (bbox.length < 2) {\n const msg = `invalid bbox data for qwen-vl mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n }\n const result = [\n Math.round(bbox[0]),\n Math.round(bbox[1]),\n 'number' == typeof bbox[2] ? Math.round(bbox[2]) : Math.round(bbox[0] + defaultBboxSize),\n 'number' == typeof bbox[3] ? Math.round(bbox[3]) : Math.round(bbox[1] + defaultBboxSize)\n ];\n return result;\n}\nfunction adaptDoubaoBbox(bbox, width, height) {\n utils_assert(width > 0 && height > 0, 'width and height must be greater than 0 in doubao mode');\n if ('string' == typeof bbox) {\n utils_assert(/^(\\d+)\\s(\\d+)\\s(\\d+)\\s(\\d+)$/.test(bbox.trim()), `invalid bbox data string for doubao-vision mode: ${bbox}`);\n const splitted = bbox.split(' ');\n if (4 === splitted.length) return [\n Math.round(Number(splitted[0]) * width / 1000),\n Math.round(Number(splitted[1]) * height / 1000),\n Math.round(Number(splitted[2]) * width / 1000),\n Math.round(Number(splitted[3]) * height / 1000)\n ];\n throw new Error(`invalid bbox data string for doubao-vision mode: ${bbox}`);\n }\n if (Array.isArray(bbox) && Array.isArray(bbox[0])) bbox = bbox[0];\n let bboxList = [];\n if (Array.isArray(bbox) && 'string' == typeof bbox[0]) bbox.forEach((item)=>{\n if ('string' == typeof item && item.includes(',')) {\n const [x, y] = item.split(',');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else if ('string' == typeof item && item.includes(' ')) {\n const [x, y] = item.split(' ');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else bboxList.push(Number(item));\n });\n else bboxList = bbox;\n if (4 === bboxList.length || 5 === bboxList.length) return [\n Math.round(bboxList[0] * width / 1000),\n Math.round(bboxList[1] * height / 1000),\n Math.round(bboxList[2] * width / 1000),\n Math.round(bboxList[3] * height / 1000)\n ];\n if (6 === bboxList.length || 2 === bboxList.length || 3 === bboxList.length || 7 === bboxList.length) return [\n Math.max(0, Math.round(bboxList[0] * width / 1000) - defaultBboxSize / 2),\n Math.max(0, Math.round(bboxList[1] * height / 1000) - defaultBboxSize / 2),\n Math.min(width, Math.round(bboxList[0] * width / 1000) + defaultBboxSize / 2),\n Math.min(height, Math.round(bboxList[1] * height / 1000) + defaultBboxSize / 2)\n ];\n if (8 === bbox.length) return [\n Math.round(bboxList[0] * width / 1000),\n Math.round(bboxList[1] * height / 1000),\n Math.round(bboxList[4] * width / 1000),\n Math.round(bboxList[5] * height / 1000)\n ];\n const msg = `invalid bbox data for doubao-vision mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n}\nfunction adaptBbox(bbox, width, height) {\n if ('doubao-vision' === env_vlLocateMode() || 'vlm-ui-tars' === env_vlLocateMode()) return adaptDoubaoBbox(bbox, width, height);\n if ('gemini' === env_vlLocateMode()) return adaptGeminiBbox(bbox, width, height);\n return adaptQwenBbox(bbox);\n}\nfunction adaptGeminiBbox(bbox, width, height) {\n const left = Math.round(bbox[1] * width / 1000);\n const top = Math.round(bbox[0] * height / 1000);\n const right = Math.round(bbox[3] * width / 1000);\n const bottom = Math.round(bbox[2] * height / 1000);\n return [\n left,\n top,\n right,\n bottom\n ];\n}\nfunction adaptBboxToRect(bbox, width, height, offsetX = 0, offsetY = 0) {\n debugInspectUtils('adaptBboxToRect', bbox, width, height, offsetX, offsetY);\n const [left, top, right, bottom] = adaptBbox(bbox, width, height);\n const rect = {\n left: left + offsetX,\n top: top + offsetY,\n width: right - left,\n height: bottom - top\n };\n debugInspectUtils('adaptBboxToRect, result=', rect);\n return rect;\n}\nlet warned = false;\nfunction warnGPT4oSizeLimit(size) {\n var _getModelName;\n if (warned) return;\n if (null == (_getModelName = getModelName()) ? void 0 : _getModelName.toLowerCase().includes('gpt-4o')) {\n const warningMsg = `GPT-4o has a maximum image input size of 2000x768 or 768x2000, but got ${size.width}x${size.height}. Please set your page to a smaller resolution. Otherwise, the result may be inaccurate.`;\n if (Math.max(size.width, size.height) > 2000 || Math.min(size.width, size.height) > 768) {\n console.warn(warningMsg);\n warned = true;\n }\n } else if (size.width > 1800 || size.height > 1800) {\n console.warn(`The image size seems too large (${size.width}x${size.height}). It may lead to more token usage, slower response, and inaccurate result.`);\n warned = true;\n }\n}\nfunction mergeRects(rects) {\n const minLeft = Math.min(...rects.map((r)=>r.left));\n const minTop = Math.min(...rects.map((r)=>r.top));\n const maxRight = Math.max(...rects.map((r)=>r.left + r.width));\n const maxBottom = Math.max(...rects.map((r)=>r.top + r.height));\n return {\n left: minLeft,\n top: minTop,\n width: maxRight - minLeft,\n height: maxBottom - minTop\n };\n}\nfunction expandSearchArea(rect, screenSize) {\n const minEdgeSize = 'doubao-vision' === env_vlLocateMode() ? 500 : 300;\n const defaultPadding = 160;\n const paddingSizeHorizontal = rect.width < minEdgeSize ? Math.ceil((minEdgeSize - rect.width) / 2) : defaultPadding;\n const paddingSizeVertical = rect.height < minEdgeSize ? Math.ceil((minEdgeSize - rect.height) / 2) : defaultPadding;\n rect.left = Math.max(0, rect.left - paddingSizeHorizontal);\n rect.width = Math.min(rect.width + 2 * paddingSizeHorizontal, screenSize.width - rect.left);\n rect.top = Math.max(0, rect.top - paddingSizeVertical);\n rect.height = Math.min(rect.height + 2 * paddingSizeVertical, screenSize.height - rect.top);\n return rect;\n}\nasync function markupImageForLLM(screenshotBase64, tree, size) {\n const elementsInfo = treeToList(tree);\n const elementsPositionInfoWithoutText = elementsInfo.filter((elementInfo)=>{\n if (elementInfo.attributes.nodeType === NodeType.TEXT) return false;\n return true;\n });\n const imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n elementsPositionInfo: elementsPositionInfoWithoutText,\n size\n });\n return imagePayload;\n}\nfunction buildYamlFlowFromPlans(plans, sleep) {\n const flow = [];\n for (const plan of plans){\n var _plan_locate;\n const type = plan.type;\n const locate = null == (_plan_locate = plan.locate) ? void 0 : _plan_locate.prompt;\n if ('Tap' === type) flow.push({\n aiTap: locate\n });\n else if ('Hover' === type) flow.push({\n aiHover: locate\n });\n else if ('Input' === type) {\n const param = plan.param;\n flow.push({\n aiInput: param.value,\n locate\n });\n } else if ('KeyboardPress' === type) {\n const param = plan.param;\n flow.push({\n aiKeyboardPress: param.value,\n locate\n });\n } else if ('Scroll' === type) {\n const param = plan.param;\n flow.push({\n aiScroll: null,\n locate,\n direction: param.direction,\n scrollType: param.scrollType,\n distance: param.distance\n });\n } else if ('Sleep' === type) {\n const param = plan.param;\n flow.push({\n sleep: param.timeMs\n });\n } else 'AndroidBackButton' === type || 'AndroidHomeButton' === type || 'AndroidRecentAppsButton' === type || 'AndroidLongPress' === type || 'AndroidPull' === type || 'Error' === type || 'Assert' === type || 'AssertWithoutThrow' === type || 'Finished' === type || console.warn(`Cannot convert action ${type} to yaml flow. This should be a bug of Midscene.`);\n }\n if (sleep) flow.push({\n sleep: sleep\n });\n return flow;\n}\nfunction describeSize(size) {\n return `${size.width} x ${size.height}`;\n}\nconst distanceThreshold = 16;\nfunction elementByPositionWithElementInfo(treeRoot, position, options) {\n const requireStrictDistance = (null == options ? void 0 : options.requireStrictDistance) ?? true;\n const filterPositionElements = (null == options ? void 0 : options.filterPositionElements) ?? false;\n utils_assert(void 0 !== position, 'position is required for query');\n const matchingElements = [];\n function dfs(node) {\n if (null == node ? void 0 : node.node) {\n const item = node.node;\n if (item.rect.left <= position.x && position.x <= item.rect.left + item.rect.width && item.rect.top <= position.y && position.y <= item.rect.top + item.rect.height) {\n var _item_attributes;\n if (!(filterPositionElements && (null == (_item_attributes = item.attributes) ? void 0 : _item_attributes.nodeType) === NodeType.POSITION) && item.isVisible) matchingElements.push(item);\n }\n }\n for (const child of node.children)dfs(child);\n }\n dfs(treeRoot);\n if (0 === matchingElements.length) return;\n const element = matchingElements.reduce((smallest, current)=>{\n const smallestArea = smallest.rect.width * smallest.rect.height;\n const currentArea = current.rect.width * current.rect.height;\n return currentArea < smallestArea ? current : smallest;\n });\n const distanceToCenter = distance({\n x: element.center[0],\n y: element.center[1]\n }, position);\n if (requireStrictDistance) return distanceToCenter <= distanceThreshold ? element : void 0;\n return element;\n}\nfunction distance(point1, point2) {\n return Math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2);\n}\nasync function describeUserPage(context, opt) {\n const { screenshotBase64 } = context;\n let width;\n let height;\n if (context.size) ({ width, height } = context.size);\n else {\n const imgSize = await imageInfoOfBase64(screenshotBase64);\n ({ width, height } = imgSize);\n }\n const treeRoot = context.tree;\n const idElementMap = {};\n const flatElements = treeToList(treeRoot);\n if ((null == opt ? void 0 : opt.domIncluded) === true && flatElements.length >= 5000) console.warn('The number of elements is too large, it may cause the prompt to be too long, please use domIncluded: \"visible-only\" to reduce the number of elements');\n flatElements.forEach((element)=>{\n idElementMap[element.id] = element;\n if (void 0 !== element.indexId) idElementMap[`${element.indexId}`] = element;\n });\n let pageDescription = '';\n const visibleOnly = (null == opt ? void 0 : opt.visibleOnly) ?? (null == opt ? void 0 : opt.domIncluded) === 'visible-only';\n if ((null == opt ? void 0 : opt.domIncluded) || !env_vlLocateMode()) {\n const contentTree = await descriptionOfTree(treeRoot, null == opt ? void 0 : opt.truncateTextLength, null == opt ? void 0 : opt.filterNonTextContent, visibleOnly);\n const sizeDescription = describeSize({\n width,\n height\n });\n pageDescription = `The size of the page: ${sizeDescription} \\n The page elements tree:\\n${contentTree}`;\n }\n return {\n description: pageDescription,\n elementById (idOrIndexId) {\n utils_assert(void 0 !== idOrIndexId, 'id is required for query');\n const item = idElementMap[`${idOrIndexId}`];\n return item;\n },\n elementByPosition (position, size) {\n return elementByPositionWithElementInfo(treeRoot, position);\n },\n insertElementByPosition (position) {\n const element = generateElementByPosition(position);\n treeRoot.children.push({\n node: element,\n children: []\n });\n flatElements.push(element);\n idElementMap[element.id] = element;\n return element;\n },\n size: {\n width,\n height\n }\n };\n}\nfunction systemPromptToExtract() {\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\nThe user will give you a screenshot, the contents of it (optional), and some data requirements in <DATA_DEMAND>. You need to extract the data according to the <DATA_DEMAND>.\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\nIf the user provides multiple reference images, please carefully review the reference images with the screenshot and provide the correct answer for <DATA_DEMAND>.\n\nIf the user requests reasons to be provided, please provide the thought field in response, less then 100 words.\n\nReturn in the following JSON format:\n{\n thought: string, // the thought process of the extraction, less then 100 words, not required by default.\n data: any, // the extracted data. 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.\n errors: [], // string[], error message if any\n}\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{\n data: {\n name: \"John\",\n age: 30,\n isAdmin: true\n },\n}\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{\n data: [\"todo 1\", \"todo 2\", \"todo 3\"],\n}\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{\n data: \"todo list\",\n}\n\n# Example 4\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\n{\n \"result\": \"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{\n data: { result: true },\n}\n`;\n}\nconst extractDataQueryPrompt = async (pageDescription, dataQuery)=>{\n let dataQueryText = '';\n dataQueryText = 'string' == typeof dataQuery ? dataQuery : JSON.stringify(dataQuery, null, 2);\n const extractDataPrompt = new PromptTemplate({\n template: `\n<PageDescription>\n{pageDescription}\n</PageDescription>\n\n<DATA_DEMAND>\n{dataQuery}\n</DATA_DEMAND>\n `,\n inputVariables: [\n \"pageDescription\",\n 'dataQuery'\n ]\n });\n return await extractDataPrompt.format({\n pageDescription,\n dataQuery: dataQueryText\n });\n};\nfunction systemPromptToLocateSection(vlMode) {\n return `\nYou goal is to find out one section containing the target element in the screenshot, put it in the \\`bbox\\` field. If the user describe the target element with some reference elements, you should also find the section containing the reference elements, put it in the \\`references_bbox\\` field.\n\nUsually, it should be approximately an area not more than 300x300px. Changes of the size are allowed if there are many elements to cover.\n\nreturn in this JSON format:\n\\`\\`\\`json\n{\n \"bbox\": [number, number, number, number],\n \"references_bbox\"?: [\n [number, number, number, number],\n [number, number, number, number],\n ...\n ],\n \"error\"?: string\n}\n\\`\\`\\`\n\nIn which, all the numbers in the \\`bbox\\` and \\`references_bbox\\` represent ${bboxDescription(vlMode)}.\n\nFor example, if the user describe the target element as \"the delete button on the second row with title 'Peter'\", you should put the bounding box of the delete button in the \\`bbox\\` field, and the bounding box of the second row in the \\`references_bbox\\` field.\n\nthe return value should be like this:\n\\`\\`\\`json\n{\n \"bbox\": [100, 100, 200, 200],\n \"references_bbox\": [[100, 100, 200, 200]]\n}\n\\`\\`\\`\n`;\n}\nconst sectionLocatorInstruction = new PromptTemplate({\n template: `Here is the target element user interested in:\n<targetDescription>\n{sectionDescription}\n</targetDescription>\n `,\n inputVariables: [\n \"sectionDescription\"\n ]\n});\nconst debugInspect = getDebug('ai:inspect');\nconst debugSection = getDebug('ai:section');\nconst extraTextFromUserPrompt = (prompt)=>{\n if ('string' == typeof prompt) return prompt;\n return prompt.prompt;\n};\nconst promptsToChatParam = async (multimodalPrompt)=>{\n var _multimodalPrompt_images;\n const msgs = [];\n if (null == multimodalPrompt ? void 0 : null == (_multimodalPrompt_images = multimodalPrompt.images) ? void 0 : _multimodalPrompt_images.length) {\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: 'Next, I will provide all the reference images.'\n }\n ]\n });\n for (const item of multimodalPrompt.images){\n const base64 = await preProcessImageUrl(item.url, !!multimodalPrompt.convertHttpImage2Base64);\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: `reference image ${item.name}:`\n }\n ]\n });\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: base64,\n detail: 'high'\n }\n }\n ]\n });\n }\n }\n return msgs;\n};\nasync function AiLocateElement(options) {\n const { context, targetElementDescription, callAI } = options;\n const { screenshotBase64 } = context;\n const { description, elementById, insertElementByPosition } = await describeUserPage(context);\n utils_assert(targetElementDescription, \"cannot find the target element description\");\n const userInstructionPrompt = await findElementPrompt.format({\n pageDescription: description,\n targetElementDescription: extraTextFromUserPrompt(targetElementDescription)\n });\n const systemPrompt = systemPromptToLocateElement(env_vlLocateMode());\n let imagePayload = screenshotBase64;\n if (options.searchConfig) {\n utils_assert(options.searchConfig.rect, 'searchArea is provided but its rect cannot be found. Failed to locate element');\n utils_assert(options.searchConfig.imageBase64, 'searchArea is provided but its imageBase64 cannot be found. Failed to locate element');\n imagePayload = options.searchConfig.imageBase64;\n } else if ('qwen-vl' === env_vlLocateMode()) imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n else if (!env_vlLocateMode()) imagePayload = await markupImageForLLM(screenshotBase64, context.tree, context.size);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: userInstructionPrompt\n }\n ]\n }\n ];\n if ('string' != typeof targetElementDescription) {\n const addOns = await promptsToChatParam({\n images: targetElementDescription.images,\n convertHttpImage2Base64: targetElementDescription.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const callAIFn = callAI || callToGetJSONObject;\n const res = await callAIFn(msgs, common_AIActionType.INSPECT_ELEMENT);\n const rawResponse = JSON.stringify(res.content);\n let resRect;\n let matchedElements = 'elements' in res.content ? res.content.elements : [];\n let errors = 'errors' in res.content ? res.content.errors : [];\n try {\n if ('bbox' in res.content && Array.isArray(res.content.bbox)) {\n var _options_searchConfig_rect, _options_searchConfig, _options_searchConfig_rect1, _options_searchConfig1, _options_searchConfig_rect2, _options_searchConfig2, _options_searchConfig_rect3, _options_searchConfig3;\n resRect = adaptBboxToRect(res.content.bbox, (null == (_options_searchConfig = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect = _options_searchConfig.rect) ? void 0 : _options_searchConfig_rect.width) || context.size.width, (null == (_options_searchConfig1 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect1 = _options_searchConfig1.rect) ? void 0 : _options_searchConfig_rect1.height) || context.size.height, null == (_options_searchConfig2 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect2 = _options_searchConfig2.rect) ? void 0 : _options_searchConfig_rect2.left, null == (_options_searchConfig3 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect3 = _options_searchConfig3.rect) ? void 0 : _options_searchConfig_rect3.top);\n debugInspect('resRect', resRect);\n const rectCenter = {\n x: resRect.left + resRect.width / 2,\n y: resRect.top + resRect.height / 2\n };\n let element = elementByPositionWithElementInfo(context.tree, rectCenter);\n const distanceToCenter = element ? distance({\n x: element.center[0],\n y: element.center[1]\n }, rectCenter) : 0;\n if (!element || distanceToCenter > distanceThreshold) element = insertElementByPosition(rectCenter);\n if (element) {\n matchedElements = [\n element\n ];\n errors = [];\n }\n }\n } catch (e) {\n const msg = e instanceof Error ? `Failed to parse bbox: ${e.message}` : 'unknown error in locate';\n if (errors && (null == errors ? void 0 : errors.length) !== 0) errors.push(`(${msg})`);\n else errors = [\n msg\n ];\n }\n return {\n rect: resRect,\n parseResult: {\n elements: matchedElements,\n errors\n },\n rawResponse,\n elementById,\n usage: res.usage,\n isOrderSensitive: 'object' == typeof res.content && null !== res.content && 'isOrderSensitive' in res.content ? res.content.isOrderSensitive : void 0\n };\n}\nasync function AiLocateSection(options) {\n const { context, sectionDescription } = options;\n const { screenshotBase64 } = context;\n const systemPrompt = systemPromptToLocateSection(env_vlLocateMode());\n const sectionLocatorInstructionText = await sectionLocatorInstruction.format({\n sectionDescription: extraTextFromUserPrompt(sectionDescription)\n });\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: sectionLocatorInstructionText\n }\n ]\n }\n ];\n if ('string' != typeof sectionDescription) {\n const addOns = await promptsToChatParam({\n images: sectionDescription.images,\n convertHttpImage2Base64: sectionDescription.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const result = await callAiFn(msgs, common_AIActionType.EXTRACT_DATA);\n let sectionRect;\n const sectionBbox = result.content.bbox;\n if (sectionBbox) {\n const targetRect = adaptBboxToRect(sectionBbox, context.size.width, context.size.height);\n debugSection('original targetRect %j', targetRect);\n const referenceBboxList = result.content.references_bbox || [];\n debugSection('referenceBboxList %j', referenceBboxList);\n const referenceRects = referenceBboxList.filter((bbox)=>Array.isArray(bbox)).map((bbox)=>adaptBboxToRect(bbox, context.size.width, context.size.height));\n debugSection('referenceRects %j', referenceRects);\n const mergedRect = mergeRects([\n targetRect,\n ...referenceRects\n ]);\n debugSection('mergedRect %j', mergedRect);\n sectionRect = expandSearchArea(mergedRect, context.size);\n debugSection('expanded sectionRect %j', sectionRect);\n }\n let imageBase64 = screenshotBase64;\n if (sectionRect) imageBase64 = await cropByRect(screenshotBase64, sectionRect, getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL));\n return {\n rect: sectionRect,\n imageBase64,\n error: result.content.error,\n rawResponse: JSON.stringify(result.content),\n usage: result.usage\n };\n}\nasync function AiExtractElementInfo(options) {\n var _options_extractOption;\n const { dataQuery, context, extractOption, multimodalPrompt } = options;\n const systemPrompt = systemPromptToExtract();\n const { screenshotBase64 } = context;\n const { description, elementById } = await describeUserPage(context, {\n truncateTextLength: 200,\n filterNonTextContent: false,\n visibleOnly: false,\n domIncluded: null == extractOption ? void 0 : extractOption.domIncluded\n });\n const extractDataPromptText = await extractDataQueryPrompt(description, dataQuery);\n const userContent = [];\n if ((null == extractOption ? void 0 : extractOption.screenshotIncluded) !== false) userContent.push({\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n });\n userContent.push({\n type: 'text',\n text: extractDataPromptText\n });\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: userContent\n }\n ];\n if (null == (_options_extractOption = options.extractOption) ? void 0 : _options_extractOption.returnThought) msgs.push({\n role: 'user',\n content: 'Please provide reasons.'\n });\n if (multimodalPrompt) {\n const addOns = await promptsToChatParam({\n images: multimodalPrompt.images,\n convertHttpImage2Base64: multimodalPrompt.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const result = await callAiFn(msgs, common_AIActionType.EXTRACT_DATA);\n return {\n parseResult: result.content,\n elementById,\n usage: result.usage\n };\n}\nasync function AiAssert(options) {\n const { assertion, context } = options;\n utils_assert(assertion, 'assertion should not be empty');\n const { screenshotBase64 } = context;\n const systemPrompt = systemPromptToAssert({\n isUITars: getAIConfigInBoolean(MIDSCENE_USE_VLM_UI_TARS)\n });\n const assertionText = extraTextFromUserPrompt(assertion);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: `\nHere is the assertion. Please tell whether it is truthy according to the screenshot.\n=====================================\n${assertionText}\n=====================================\n `\n }\n ]\n }\n ];\n if ('string' != typeof assertion) {\n const addOns = await promptsToChatParam({\n images: assertion.images,\n convertHttpImage2Base64: assertion.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const { content: assertResult, usage } = await callAiFn(msgs, common_AIActionType.ASSERT);\n return {\n content: assertResult,\n usage\n };\n}\nasync function llm_planning_plan(userInstruction, opts) {\n var _planFromAI_action;\n const { callAI, context } = opts || {};\n const { screenshotBase64, size } = context;\n const { description: pageDescription, elementById } = await describeUserPage(context);\n const systemPrompt = await systemPromptToTaskPlanning({\n actionSpace: opts.actionSpace,\n vlMode: env_vlLocateMode()\n });\n const taskBackgroundContextText = generateTaskBackgroundContext(userInstruction, opts.log, opts.actionContext);\n const userInstructionPrompt = await automationUserPrompt(env_vlLocateMode()).format({\n pageDescription,\n taskBackgroundContext: taskBackgroundContextText\n });\n let imagePayload = screenshotBase64;\n if ('qwen-vl' === env_vlLocateMode()) imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n else if (!env_vlLocateMode()) imagePayload = await markupImageForLLM(screenshotBase64, context.tree, context.size);\n warnGPT4oSizeLimit(size);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: userInstructionPrompt\n }\n ]\n }\n ];\n const call = callAI || callAiFn;\n const { content, usage } = await call(msgs, common_AIActionType.PLAN);\n const rawResponse = JSON.stringify(content, void 0, 2);\n const planFromAI = content;\n const actions = ((null == (_planFromAI_action = planFromAI.action) ? void 0 : _planFromAI_action.type) ? [\n planFromAI.action\n ] : planFromAI.actions) || [];\n const returnValue = {\n ...planFromAI,\n actions,\n rawResponse,\n usage,\n yamlFlow: buildYamlFlowFromPlans(actions, planFromAI.sleep)\n };\n utils_assert(planFromAI, \"can't get plans from AI\");\n if (env_vlLocateMode()) {\n actions.forEach((action)=>{\n if (action.locate) try {\n action.locate = fillBboxParam(action.locate, size.width, size.height);\n } catch (e) {\n throw new Error(`Failed to fill locate param: ${planFromAI.error} (${e instanceof Error ? e.message : 'unknown error'})`, {\n cause: e\n });\n }\n });\n utils_assert(!planFromAI.error, `Failed to plan actions: ${planFromAI.error}`);\n } else actions.forEach((action)=>{\n var _action_locate;\n if (null == (_action_locate = action.locate) ? void 0 : _action_locate.id) {\n const element = elementById(action.locate.id);\n if (element) action.locate.id = element.id;\n }\n });\n if (0 === actions.length && returnValue.more_actions_needed_by_instruction && !returnValue.sleep) console.warn('No actions planned for the prompt, but model said more actions are needed:', userInstruction);\n return returnValue;\n}\ngetDebug('ui-tars-planning');\nconst elementDescriberInstruction = ()=>`\nDescribe the element in the red rectangle for precise identification. Use ${env_getPreferredLanguage()}.\n\nCRITICAL REQUIREMENTS:\n1. UNIQUENESS: The description must uniquely identify this element on the current page\n2. UNIVERSALITY: Use generic, reusable selectors that work across different contexts\n3. PRECISION: Be specific enough to distinguish from similar elements\n\nDESCRIPTION STRUCTURE:\n1. Element type (button, input, link, div, etc.)\n2. Primary identifier (in order of preference):\n - Unique text content: \"with text 'Login'\"\n - Unique attribute: \"with aria-label 'Search'\"\n - Unique class/ID: \"with class 'primary-button'\"\n - Unique position: \"in header navigation\"\n3. Secondary identifiers (if needed for uniqueness):\n - Visual features: \"blue background\", \"with icon\"\n - Relative position: \"below search bar\", \"in sidebar\"\n - Parent context: \"in login form\", \"in main menu\"\n\nGUIDELINES:\n- Keep description under 25 words\n- Prioritize semantic identifiers over visual ones\n- Use consistent terminology across similar elements\n- Avoid page-specific or temporary content\n- Don't mention the red rectangle or selection box\n- Focus on stable, reusable characteristics\n\nEXAMPLES:\n- \"Login button with text 'Sign In'\"\n- \"Search input with placeholder 'Enter keywords'\"\n- \"Navigation link with text 'Home' in header\"\n- \"Submit button in contact form\"\n- \"Menu icon with aria-label 'Open menu'\"\n\nReturn JSON:\n{\n \"description\": \"unique element identifier\",\n \"error\"?: \"error message if any\"\n}`;\nfunction emitInsightDump(data, dumpSubscriber) {\n const baseData = {\n sdkVersion: getVersion(),\n logTime: Date.now(),\n model_name: env_getAIConfig(MIDSCENE_MODEL_NAME) || ''\n };\n const finalData = {\n logId: utils_uuid(),\n ...baseData,\n ...data\n };\n null == dumpSubscriber || dumpSubscriber(finalData);\n}\nfunction insight_define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst insight_debug = getDebug('ai:insight');\nclass Insight {\n async locate(query, opt) {\n var _parseResult_errors;\n const { callAI } = opt || {};\n const queryPrompt = 'string' == typeof query ? query : query.prompt;\n utils_assert(queryPrompt, 'query is required for locate');\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = void 0;\n utils_assert('object' == typeof query, 'query should be an object for locate');\n const globalDeepThinkSwitch = getAIConfigInBoolean(MIDSCENE_FORCE_DEEP_THINK);\n if (globalDeepThinkSwitch) insight_debug('globalDeepThinkSwitch', globalDeepThinkSwitch);\n let searchAreaPrompt;\n if (query.deepThink || globalDeepThinkSwitch) searchAreaPrompt = query.prompt;\n if (searchAreaPrompt && !env_vlLocateMode()) {\n console.warn('The \"deepThink\" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/choose-a-model');\n searchAreaPrompt = void 0;\n }\n const context = (null == opt ? void 0 : opt.context) || await this.contextRetrieverFn('locate');\n let searchArea;\n let searchAreaRawResponse;\n let searchAreaUsage;\n let searchAreaResponse;\n if (searchAreaPrompt) {\n searchAreaResponse = await AiLocateSection({\n context,\n sectionDescription: searchAreaPrompt\n });\n utils_assert(searchAreaResponse.rect, `cannot find search area for \"${searchAreaPrompt}\"${searchAreaResponse.error ? `: ${searchAreaResponse.error}` : ''}`);\n searchAreaRawResponse = searchAreaResponse.rawResponse;\n searchAreaUsage = searchAreaResponse.usage;\n searchArea = searchAreaResponse.rect;\n }\n const startTime = Date.now();\n const { parseResult, rect, elementById, rawResponse, usage, isOrderSensitive } = await AiLocateElement({\n callAI: callAI || this.aiVendorFn,\n context,\n targetElementDescription: queryPrompt,\n searchConfig: searchAreaResponse\n });\n const timeCost = Date.now() - startTime;\n const taskInfo = {\n ...this.taskInfo ? this.taskInfo : {},\n durationMs: timeCost,\n rawResponse: JSON.stringify(rawResponse),\n formatResponse: JSON.stringify(parseResult),\n usage,\n searchArea,\n searchAreaRawResponse,\n searchAreaUsage\n };\n let errorLog;\n if (null == (_parseResult_errors = parseResult.errors) ? void 0 : _parseResult_errors.length) errorLog = `AI model failed to locate: \\n${parseResult.errors.join('\\n')}`;\n const dumpData = {\n type: 'locate',\n userQuery: {\n element: queryPrompt\n },\n matchedElement: [],\n matchedRect: rect,\n data: null,\n taskInfo,\n deepThink: !!searchArea,\n error: errorLog\n };\n const elements = [];\n (parseResult.elements || []).forEach((item)=>{\n if ('id' in item) {\n const element = elementById(null == item ? void 0 : item.id);\n if (!element) return void console.warn(`locate: cannot find element id=${item.id}. Maybe an unstable response from AI model`);\n elements.push(element);\n }\n });\n emitInsightDump({\n ...dumpData,\n matchedElement: elements\n }, dumpSubscriber);\n if (errorLog) throw new Error(errorLog);\n utils_assert(elements.length <= 1, `locate: multiple elements found, length = ${elements.length}`);\n if (1 === elements.length) return {\n element: {\n id: elements[0].id,\n indexId: elements[0].indexId,\n center: elements[0].center,\n rect: elements[0].rect,\n xpaths: elements[0].xpaths || [],\n attributes: elements[0].attributes,\n isOrderSensitive\n },\n rect\n };\n return {\n element: null,\n rect\n };\n }\n async extract(dataDemand, opt, multimodalPrompt) {\n var _parseResult_errors;\n utils_assert('object' == typeof dataDemand || 'string' == typeof dataDemand, `dataDemand should be object or string, but get ${typeof dataDemand}`);\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = void 0;\n const context = await this.contextRetrieverFn('extract');\n const startTime = Date.now();\n const { parseResult, usage } = await AiExtractElementInfo({\n context,\n dataQuery: dataDemand,\n multimodalPrompt,\n extractOption: opt\n });\n const timeCost = Date.now() - startTime;\n const taskInfo = {\n ...this.taskInfo ? this.taskInfo : {},\n durationMs: timeCost,\n rawResponse: JSON.stringify(parseResult)\n };\n let errorLog;\n if (null == (_parseResult_errors = parseResult.errors) ? void 0 : _parseResult_errors.length) errorLog = `AI response error: \\n${parseResult.errors.join('\\n')}`;\n const dumpData = {\n type: 'extract',\n userQuery: {\n dataDemand\n },\n matchedElement: [],\n data: null,\n taskInfo,\n error: errorLog\n };\n const { data, thought } = parseResult || {};\n emitInsightDump({\n ...dumpData,\n data\n }, dumpSubscriber);\n if (errorLog && !data) throw new Error(errorLog);\n return {\n data,\n thought,\n usage\n };\n }\n async assert(assertion) {\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = void 0;\n const context = await this.contextRetrieverFn('assert');\n const startTime = Date.now();\n const assertResult = await AiAssert({\n assertion,\n context\n });\n const timeCost = Date.now() - startTime;\n const taskInfo = {\n ...this.taskInfo ? this.taskInfo : {},\n durationMs: timeCost,\n rawResponse: JSON.stringify(assertResult.content)\n };\n const { thought, pass } = assertResult.content;\n const dumpData = {\n type: 'assert',\n userQuery: {\n assertion\n },\n matchedElement: [],\n data: null,\n taskInfo,\n assertionPass: pass,\n assertionThought: thought,\n error: pass ? void 0 : thought\n };\n emitInsightDump(dumpData, dumpSubscriber);\n return {\n pass,\n thought,\n usage: assertResult.usage\n };\n }\n async describe(target, opt) {\n utils_assert(target, 'target is required for insight.describe');\n const context = await this.contextRetrieverFn('describe');\n const { screenshotBase64, size } = context;\n utils_assert(screenshotBase64, 'screenshot is required for insight.describe');\n const systemPrompt = elementDescriberInstruction();\n const defaultRectSize = 30;\n const targetRect = Array.isArray(target) ? {\n left: Math.floor(target[0] - defaultRectSize / 2),\n top: Math.floor(target[1] - defaultRectSize / 2),\n width: defaultRectSize,\n height: defaultRectSize\n } : target;\n let imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n size,\n elementsPositionInfo: [\n {\n rect: targetRect\n }\n ],\n borderThickness: 3\n });\n if (null == opt ? void 0 : opt.deepThink) {\n const searchArea = expandSearchArea(targetRect, context.size);\n insight_debug('describe: set searchArea', searchArea);\n imagePayload = await cropByRect(imagePayload, searchArea, getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL));\n }\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n }\n ]\n }\n ];\n const callAIFn = this.aiVendorFn || callToGetJSONObject;\n const res = await callAIFn(msgs, common_AIActionType.DESCRIBE_ELEMENT);\n const { content } = res;\n utils_assert(!content.error, `describe failed: ${content.error}`);\n utils_assert(content.description, 'failed to describe the element');\n return content;\n }\n constructor(context, opt){\n insight_define_property(this, \"contextRetrieverFn\", void 0);\n insight_define_property(this, \"aiVendorFn\", callAiFn);\n insight_define_property(this, \"onceDumpUpdatedFn\", void 0);\n insight_define_property(this, \"taskInfo\", void 0);\n utils_assert(context, 'context is required for Insight');\n if ('function' == typeof context) this.contextRetrieverFn = context;\n else this.contextRetrieverFn = ()=>Promise.resolve(context);\n if (void 0 !== (null == opt ? void 0 : opt.aiVendorFn)) this.aiVendorFn = opt.aiVendorFn;\n if (void 0 !== (null == opt ? void 0 : opt.taskInfo)) this.taskInfo = opt.taskInfo;\n }\n}\nconst src = Insight;\nexport { AiAssert, AiLocateElement, Executor, Insight, MIDSCENE_MODEL_NAME, src as default, describeUserPage, env_getAIConfig as getAIConfig, getVersion, llm_planning_plan as plan };\n\n//# sourceMappingURL=index.mjs.map","import { Executor, plan as core_plan } from \"@midscene/core\";\nimport { elementByPositionWithElementInfo, resizeImageForUiTars, vlmPlanning } from \"@midscene/core/ai-model\";\nimport { sleep as utils_sleep } from \"@midscene/core/utils\";\nimport { NodeType } from \"@midscene/shared/constants\";\nimport { MIDSCENE_REPLANNING_CYCLE_LIMIT, getAIConfigInNumber } from \"@midscene/shared/env\";\nimport { getDebug } from \"@midscene/shared/logger\";\nimport { assert } from \"@midscene/shared/utils\";\nimport { taskTitleStr } from \"./ui-utils.mjs\";\nimport { matchElementFromCache, matchElementFromPlan, parsePrompt } from \"./utils.mjs\";\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst debug = getDebug('device-task-executor');\nconst defaultReplanningCycleLimit = 10;\nclass PageTaskExecutor {\n async recordScreenshot(timing) {\n const base64 = await this.page.screenshotBase64();\n const item = {\n type: 'screenshot',\n ts: Date.now(),\n screenshot: base64,\n timing\n };\n return item;\n }\n async getElementXpath(pageContext, element) {\n var _element_attributes;\n let elementId = null == element ? void 0 : element.id;\n if ((null == element ? void 0 : element.isOrderSensitive) !== void 0) {\n const xpaths = await this.page.getXpathsByPoint({\n left: element.center[0],\n top: element.center[1]\n }, null == element ? void 0 : element.isOrderSensitive);\n return xpaths;\n }\n if ((null == element ? void 0 : null == (_element_attributes = element.attributes) ? void 0 : _element_attributes.nodeType) === NodeType.POSITION) {\n await this.insight.contextRetrieverFn('locate');\n const info = elementByPositionWithElementInfo(pageContext.tree, {\n x: element.center[0],\n y: element.center[1]\n }, {\n requireStrictDistance: false,\n filterPositionElements: true\n });\n if (null == info ? void 0 : info.id) elementId = info.id;\n else debug('no element id found for position node, will not update cache', element);\n }\n if (!elementId) return;\n try {\n const result = await this.page.getXpathsById(elementId);\n return result;\n } catch (error) {\n debug('getXpathsById error: ', error);\n }\n }\n prependExecutorWithScreenshot(taskApply, appendAfterExecution = false) {\n const taskWithScreenshot = {\n ...taskApply,\n executor: async (param, context, ...args)=>{\n const recorder = [];\n const { task } = context;\n task.recorder = recorder;\n const shot = await this.recordScreenshot(`before ${task.type}`);\n recorder.push(shot);\n const result = await taskApply.executor(param, context, ...args);\n if ('Action' === taskApply.type) await Promise.all([\n (async ()=>{\n await utils_sleep(100);\n if (this.page.waitUntilNetworkIdle) try {\n await this.page.waitUntilNetworkIdle();\n } catch (error) {}\n })(),\n utils_sleep(200)\n ]);\n if (appendAfterExecution) {\n const shot2 = await this.recordScreenshot('after Action');\n recorder.push(shot2);\n }\n return result;\n }\n };\n return taskWithScreenshot;\n }\n async convertPlanToExecutable(plans, opts) {\n const tasks = [];\n for (const plan of plans)if ('Locate' === plan.type) {\n var _plan_locate, _plan_locate1;\n if (null === plan.locate || (null == (_plan_locate = plan.locate) ? void 0 : _plan_locate.id) === null || (null == (_plan_locate1 = plan.locate) ? void 0 : _plan_locate1.id) === 'null') continue;\n const taskFind = {\n type: 'Insight',\n subType: 'Locate',\n param: plan.locate ? {\n ...plan.locate,\n cacheable: null == opts ? void 0 : opts.cacheable\n } : void 0,\n thought: plan.thought,\n locate: plan.locate,\n executor: async (param, taskContext)=>{\n var _this_taskCache, _locateCacheRecord_cacheContent;\n const { task } = taskContext;\n assert((null == param ? void 0 : param.prompt) || (null == param ? void 0 : param.id) || (null == param ? void 0 : param.bbox), 'No prompt or id or position or bbox to locate');\n let insightDump;\n let usage;\n const dumpCollector = (dump)=>{\n var _dump_taskInfo;\n insightDump = dump;\n usage = null == dump ? void 0 : null == (_dump_taskInfo = dump.taskInfo) ? void 0 : _dump_taskInfo.usage;\n task.log = {\n dump: insightDump\n };\n task.usage = usage;\n };\n this.insight.onceDumpUpdatedFn = dumpCollector;\n const shotTime = Date.now();\n const pageContext = await this.insight.contextRetrieverFn('locate');\n task.pageContext = pageContext;\n const recordItem = {\n type: 'screenshot',\n ts: shotTime,\n screenshot: pageContext.screenshotBase64,\n timing: 'before Insight'\n };\n task.recorder = [\n recordItem\n ];\n const elementFromXpath = param.xpath ? await this.page.getElementInfoByXpath(param.xpath) : void 0;\n const userExpectedPathHitFlag = !!elementFromXpath;\n const cachePrompt = param.prompt;\n const locateCacheRecord = null == (_this_taskCache = this.taskCache) ? void 0 : _this_taskCache.matchLocateCache(cachePrompt);\n const xpaths = null == locateCacheRecord ? void 0 : null == (_locateCacheRecord_cacheContent = locateCacheRecord.cacheContent) ? void 0 : _locateCacheRecord_cacheContent.xpaths;\n const elementFromCache = userExpectedPathHitFlag ? null : await matchElementFromCache(this, xpaths, cachePrompt, param.cacheable);\n const cacheHitFlag = !!elementFromCache;\n const elementFromPlan = userExpectedPathHitFlag || cacheHitFlag ? void 0 : matchElementFromPlan(param, pageContext.tree);\n const planHitFlag = !!elementFromPlan;\n const elementFromAiLocate = userExpectedPathHitFlag || cacheHitFlag || planHitFlag ? void 0 : (await this.insight.locate(param, {\n context: pageContext\n })).element;\n const aiLocateHitFlag = !!elementFromAiLocate;\n const element = elementFromXpath || elementFromCache || elementFromPlan || elementFromAiLocate;\n let currentXpaths;\n if (element && this.taskCache && !cacheHitFlag && (null == param ? void 0 : param.cacheable) !== false) {\n const elementXpaths = await this.getElementXpath(pageContext, element);\n if (null == elementXpaths ? void 0 : elementXpaths.length) {\n currentXpaths = elementXpaths;\n this.taskCache.updateOrAppendCacheRecord({\n type: 'locate',\n prompt: cachePrompt,\n xpaths: elementXpaths\n }, locateCacheRecord);\n } else debug('no xpaths found, will not update cache', cachePrompt, elementXpaths);\n }\n if (!element) throw new Error(`Element not found: ${param.prompt}`);\n let hitBy;\n if (userExpectedPathHitFlag) hitBy = {\n from: 'User expected path',\n context: {\n xpath: param.xpath\n }\n };\n else if (cacheHitFlag) hitBy = {\n from: 'Cache',\n context: {\n xpathsFromCache: xpaths,\n xpathsToSave: currentXpaths\n }\n };\n else if (planHitFlag) hitBy = {\n from: 'Planning',\n context: {\n id: null == elementFromPlan ? void 0 : elementFromPlan.id,\n bbox: null == elementFromPlan ? void 0 : elementFromPlan.bbox\n }\n };\n else if (aiLocateHitFlag) hitBy = {\n from: 'AI model',\n context: {\n prompt: param.prompt\n }\n };\n return {\n output: {\n element\n },\n pageContext,\n hitBy\n };\n }\n };\n tasks.push(taskFind);\n } else if ('Assert' === plan.type || 'AssertWithoutThrow' === plan.type) {\n const assertPlan = plan;\n const taskAssert = {\n type: 'Insight',\n subType: 'Assert',\n param: assertPlan.param,\n thought: assertPlan.thought,\n locate: assertPlan.locate,\n executor: async (param, taskContext)=>{\n const { task } = taskContext;\n let insightDump;\n const dumpCollector = (dump)=>{\n insightDump = dump;\n };\n this.insight.onceDumpUpdatedFn = dumpCollector;\n const shotTime = Date.now();\n const pageContext = await this.insight.contextRetrieverFn('assert');\n task.pageContext = pageContext;\n const recordItem = {\n type: 'screenshot',\n ts: shotTime,\n screenshot: pageContext.screenshotBase64,\n timing: 'before Insight'\n };\n task.recorder = [\n recordItem\n ];\n const assertion = await this.insight.assert(assertPlan.param.assertion);\n if (!assertion.pass) {\n if ('Assert' === plan.type) {\n task.output = assertion;\n task.log = {\n dump: insightDump\n };\n throw new Error(assertion.thought || 'Assertion failed without reason');\n }\n task.error = new Error(assertion.thought);\n }\n return {\n output: assertion,\n pageContext,\n log: {\n dump: insightDump\n },\n usage: assertion.usage\n };\n }\n };\n tasks.push(taskAssert);\n } else if ('Error' === plan.type) {\n var _plan_param;\n const taskActionError = {\n type: 'Action',\n subType: 'Error',\n param: plan.param,\n thought: plan.thought || (null == (_plan_param = plan.param) ? void 0 : _plan_param.thought),\n locate: plan.locate,\n executor: async ()=>{\n var _plan_param;\n throw new Error((null == plan ? void 0 : plan.thought) || (null == (_plan_param = plan.param) ? void 0 : _plan_param.thought) || 'error without thought');\n }\n };\n tasks.push(taskActionError);\n } else if ('Finished' === plan.type) {\n const taskActionFinished = {\n type: 'Action',\n subType: 'Finished',\n param: null,\n thought: plan.thought,\n locate: plan.locate,\n executor: async (param)=>{}\n };\n tasks.push(taskActionFinished);\n } else if ('Sleep' === plan.type) {\n const taskActionSleep = {\n type: 'Action',\n subType: 'Sleep',\n param: plan.param,\n thought: plan.thought,\n locate: plan.locate,\n executor: async (taskParam)=>{\n await utils_sleep((null == taskParam ? void 0 : taskParam.timeMs) || 3000);\n }\n };\n tasks.push(taskActionSleep);\n } else if ('Drag' === plan.type) {\n const taskActionDrag = {\n type: 'Action',\n subType: 'Drag',\n param: plan.param,\n thought: plan.thought,\n locate: plan.locate,\n executor: async (taskParam)=>{\n assert((null == taskParam ? void 0 : taskParam.start_box) && (null == taskParam ? void 0 : taskParam.end_box), 'No start_box or end_box to drag');\n await this.page.mouse.drag(taskParam.start_box, taskParam.end_box);\n }\n };\n tasks.push(taskActionDrag);\n } else {\n const planType = plan.type;\n const task = {\n type: 'Action',\n subType: planType,\n thought: plan.thought,\n param: plan.param,\n executor: async (param, context)=>{\n var _context_element;\n debug('executing action', planType, param, `context.element.center: ${null == (_context_element = context.element) ? void 0 : _context_element.center}`);\n const actionSpace = await this.page.actionSpace();\n const action = actionSpace.find((action)=>action.name === planType);\n if (!action) throw new Error(`Action type '${planType}' not found`);\n const actionFn = action.call.bind(this.page);\n return await actionFn(context, param);\n }\n };\n tasks.push(task);\n }\n const wrappedTasks = tasks.map((task, index)=>{\n if ('Action' === task.type) return this.prependExecutorWithScreenshot(task, index === tasks.length - 1);\n return task;\n });\n return {\n tasks: wrappedTasks\n };\n }\n async setupPlanningContext(executorContext) {\n const shotTime = Date.now();\n const pageContext = await this.insight.contextRetrieverFn('locate');\n const recordItem = {\n type: 'screenshot',\n ts: shotTime,\n screenshot: pageContext.screenshotBase64,\n timing: 'before Planning'\n };\n executorContext.task.recorder = [\n recordItem\n ];\n executorContext.task.pageContext = pageContext;\n return {\n pageContext\n };\n }\n async loadYamlFlowAsPlanning(userInstruction, yamlString) {\n const taskExecutor = new Executor(taskTitleStr('Action', userInstruction), {\n onTaskStart: this.onTaskStartCallback\n });\n const task = {\n type: 'Planning',\n subType: 'LoadYaml',\n locate: null,\n param: {\n userInstruction\n },\n executor: async (param, executorContext)=>{\n await this.setupPlanningContext(executorContext);\n return {\n output: {\n actions: [],\n more_actions_needed_by_instruction: false,\n log: '',\n yamlString\n },\n cache: {\n hit: true\n }\n };\n }\n };\n await taskExecutor.append(task);\n await taskExecutor.flush();\n return {\n executor: taskExecutor\n };\n }\n planningTaskFromPrompt(userInstruction, log, actionContext) {\n const task = {\n type: 'Planning',\n subType: 'Plan',\n locate: null,\n param: {\n userInstruction,\n log\n },\n executor: async (param, executorContext)=>{\n const startTime = Date.now();\n const { pageContext } = await this.setupPlanningContext(executorContext);\n assert(this.page.actionSpace, 'actionSpace for device is not implemented');\n const actionSpace = await this.page.actionSpace();\n debug('actionSpace for page is:', actionSpace.map((action)=>action.name).join(', '));\n assert(Array.isArray(actionSpace), 'actionSpace must be an array');\n if (0 === actionSpace.length) console.warn(`ActionSpace for ${this.page.pageType} is empty. This may lead to unexpected behavior.`);\n const planResult = await core_plan(param.userInstruction, {\n context: pageContext,\n log: param.log,\n actionContext,\n pageType: this.page.pageType,\n actionSpace\n });\n const { actions, log, more_actions_needed_by_instruction, error, usage, rawResponse, sleep } = planResult;\n executorContext.task.log = {\n ...executorContext.task.log || {},\n rawResponse\n };\n executorContext.task.usage = usage;\n let stopCollecting = false;\n let bboxCollected = false;\n let planParsingError = '';\n const finalActions = (actions || []).reduce((acc, planningAction)=>{\n if (stopCollecting) return acc;\n if (planningAction.locate) {\n if (bboxCollected && planningAction.locate.bbox) delete planningAction.locate.bbox;\n if (planningAction.locate.bbox) bboxCollected = true;\n acc.push({\n type: 'Locate',\n locate: planningAction.locate,\n param: null,\n thought: planningAction.locate.prompt\n });\n } else if ([\n 'Tap',\n 'Hover',\n 'Input'\n ].includes(planningAction.type)) {\n planParsingError = `invalid planning response: ${JSON.stringify(planningAction)}`;\n stopCollecting = true;\n return acc;\n }\n acc.push(planningAction);\n return acc;\n }, []);\n if (sleep) {\n const timeNow = Date.now();\n const timeRemaining = sleep - (timeNow - startTime);\n if (timeRemaining > 0) finalActions.push({\n type: 'Sleep',\n param: {\n timeMs: timeRemaining\n },\n locate: null\n });\n }\n if (0 === finalActions.length) assert(!more_actions_needed_by_instruction || sleep, error ? `Failed to plan: ${error}` : planParsingError || 'No plan found');\n return {\n output: {\n actions: finalActions,\n more_actions_needed_by_instruction,\n log,\n yamlFlow: planResult.yamlFlow\n },\n cache: {\n hit: false\n },\n pageContext\n };\n }\n };\n return task;\n }\n planningTaskToGoal(userInstruction) {\n const task = {\n type: 'Planning',\n subType: 'Plan',\n locate: null,\n param: {\n userInstruction\n },\n executor: async (param, executorContext)=>{\n var _actions_;\n const { pageContext } = await this.setupPlanningContext(executorContext);\n const imagePayload = await resizeImageForUiTars(pageContext.screenshotBase64, pageContext.size);\n this.appendConversationHistory({\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload\n }\n }\n ]\n });\n const planResult = await vlmPlanning({\n userInstruction: param.userInstruction,\n conversationHistory: this.conversationHistory,\n size: pageContext.size\n });\n const { actions, action_summary, usage } = planResult;\n executorContext.task.log = {\n ...executorContext.task.log || {},\n rawResponse: planResult.rawResponse\n };\n executorContext.task.usage = usage;\n this.appendConversationHistory({\n role: 'assistant',\n content: action_summary\n });\n return {\n output: {\n actions,\n thought: null == (_actions_ = actions[0]) ? void 0 : _actions_.thought,\n actionType: actions[0].type,\n more_actions_needed_by_instruction: true,\n log: '',\n yamlFlow: planResult.yamlFlow\n },\n cache: {\n hit: false\n }\n };\n }\n };\n return task;\n }\n async runPlans(title, plans, opts) {\n const taskExecutor = new Executor(title, {\n onTaskStart: this.onTaskStartCallback\n });\n const { tasks } = await this.convertPlanToExecutable(plans, opts);\n await taskExecutor.append(tasks);\n const result = await taskExecutor.flush();\n const { output } = result;\n return {\n output,\n executor: taskExecutor\n };\n }\n async action(userPrompt, actionContext, opts) {\n const taskExecutor = new Executor(taskTitleStr('Action', userPrompt), {\n onTaskStart: this.onTaskStartCallback\n });\n let planningTask = this.planningTaskFromPrompt(userPrompt, void 0, actionContext);\n let replanCount = 0;\n const logList = [];\n const yamlFlow = [];\n const replanningCycleLimit = getAIConfigInNumber(MIDSCENE_REPLANNING_CYCLE_LIMIT) || defaultReplanningCycleLimit;\n while(planningTask){\n if (replanCount > replanningCycleLimit) {\n const errorMsg = 'Replanning too many times, please split the task into multiple steps';\n return this.appendErrorPlan(taskExecutor, errorMsg);\n }\n await taskExecutor.append(planningTask);\n const result = await taskExecutor.flush();\n const planResult = null == result ? void 0 : result.output;\n if (taskExecutor.isInErrorState()) return {\n output: planResult,\n executor: taskExecutor\n };\n const plans = planResult.actions || [];\n yamlFlow.push(...planResult.yamlFlow || []);\n let executables;\n try {\n executables = await this.convertPlanToExecutable(plans, opts);\n taskExecutor.append(executables.tasks);\n } catch (error) {\n return this.appendErrorPlan(taskExecutor, `Error converting plans to executable tasks: ${error}, plans: ${JSON.stringify(plans)}`);\n }\n await taskExecutor.flush();\n if (taskExecutor.isInErrorState()) return {\n output: void 0,\n executor: taskExecutor\n };\n if (null == planResult ? void 0 : planResult.log) logList.push(planResult.log);\n if (!planResult.more_actions_needed_by_instruction) {\n planningTask = null;\n break;\n }\n planningTask = this.planningTaskFromPrompt(userPrompt, logList.length > 0 ? `- ${logList.join('\\n- ')}` : void 0, actionContext);\n replanCount++;\n }\n return {\n output: {\n yamlFlow\n },\n executor: taskExecutor\n };\n }\n async actionToGoal(userPrompt, opts) {\n const taskExecutor = new Executor(taskTitleStr('Action', userPrompt), {\n onTaskStart: this.onTaskStartCallback\n });\n this.conversationHistory = [];\n const isCompleted = false;\n let currentActionNumber = 0;\n const maxActionNumber = 40;\n const yamlFlow = [];\n while(!isCompleted && currentActionNumber < maxActionNumber){\n currentActionNumber++;\n const planningTask = this.planningTaskToGoal(userPrompt);\n await taskExecutor.append(planningTask);\n const result = await taskExecutor.flush();\n if (taskExecutor.isInErrorState()) return {\n output: void 0,\n executor: taskExecutor\n };\n if (!result) throw new Error('result of taskExecutor.flush() is undefined in function actionToGoal');\n const { output } = result;\n const plans = output.actions;\n yamlFlow.push(...output.yamlFlow || []);\n let executables;\n try {\n executables = await this.convertPlanToExecutable(plans, opts);\n taskExecutor.append(executables.tasks);\n } catch (error) {\n return this.appendErrorPlan(taskExecutor, `Error converting plans to executable tasks: ${error}, plans: ${JSON.stringify(plans)}`);\n }\n await taskExecutor.flush();\n if (taskExecutor.isInErrorState()) return {\n output: void 0,\n executor: taskExecutor\n };\n if ('Finished' === plans[0].type) break;\n }\n return {\n output: {\n yamlFlow\n },\n executor: taskExecutor\n };\n }\n async createTypeQueryTask(type, demand, opt, multimodalPrompt) {\n const taskExecutor = new Executor(taskTitleStr(type, 'string' == typeof demand ? demand : JSON.stringify(demand)), {\n onTaskStart: this.onTaskStartCallback\n });\n const queryTask = {\n type: 'Insight',\n subType: type,\n locate: null,\n param: {\n dataDemand: multimodalPrompt ? {\n demand,\n multimodalPrompt\n } : demand\n },\n executor: async (param, taskContext)=>{\n const { task } = taskContext;\n let insightDump;\n const dumpCollector = (dump)=>{\n insightDump = dump;\n };\n this.insight.onceDumpUpdatedFn = dumpCollector;\n const shotTime = Date.now();\n const pageContext = await this.insight.contextRetrieverFn('extract');\n task.pageContext = pageContext;\n const recordItem = {\n type: 'screenshot',\n ts: shotTime,\n screenshot: pageContext.screenshotBase64,\n timing: 'before Extract'\n };\n task.recorder = [\n recordItem\n ];\n const ifTypeRestricted = 'Query' !== type;\n let demandInput = demand;\n if (ifTypeRestricted) demandInput = {\n result: `${type}, ${demand}`\n };\n const { data, usage, thought } = await this.insight.extract(demandInput, opt, multimodalPrompt);\n let outputResult = data;\n if (ifTypeRestricted) {\n assert((null == data ? void 0 : data.result) !== void 0, 'No result in query data');\n outputResult = data.result;\n }\n return {\n output: outputResult,\n log: {\n dump: insightDump\n },\n usage,\n thought\n };\n }\n };\n await taskExecutor.append(this.prependExecutorWithScreenshot(queryTask));\n const result = await taskExecutor.flush();\n if (!result) throw new Error('result of taskExecutor.flush() is undefined in function createTypeQueryTask');\n const { output, thought } = result;\n return {\n output,\n thought,\n executor: taskExecutor\n };\n }\n async query(demand, opt) {\n return this.createTypeQueryTask('Query', demand, opt);\n }\n async boolean(prompt, opt) {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n return this.createTypeQueryTask('Boolean', textPrompt, opt, multimodalPrompt);\n }\n async number(prompt, opt) {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n return this.createTypeQueryTask('Number', textPrompt, opt, multimodalPrompt);\n }\n async string(prompt, opt) {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n return this.createTypeQueryTask('String', textPrompt, opt, multimodalPrompt);\n }\n async assert(assertion, opt) {\n const { textPrompt, multimodalPrompt } = parsePrompt(assertion);\n return await this.createTypeQueryTask('Assert', textPrompt, opt, multimodalPrompt);\n }\n appendConversationHistory(conversationHistory) {\n if ('user' === conversationHistory.role) {\n const userImgItems = this.conversationHistory.filter((item)=>'user' === item.role);\n if (userImgItems.length >= 4 && 'user' === conversationHistory.role) {\n const firstUserImgIndex = this.conversationHistory.findIndex((item)=>'user' === item.role);\n if (firstUserImgIndex >= 0) this.conversationHistory.splice(firstUserImgIndex, 1);\n }\n }\n this.conversationHistory.push(conversationHistory);\n }\n async appendErrorPlan(taskExecutor, errorMsg) {\n const errorPlan = {\n type: 'Error',\n param: {\n thought: errorMsg\n },\n locate: null\n };\n const { tasks } = await this.convertPlanToExecutable([\n errorPlan\n ]);\n await taskExecutor.append(this.prependExecutorWithScreenshot(tasks[0]));\n await taskExecutor.flush();\n return {\n output: void 0,\n executor: taskExecutor\n };\n }\n async waitFor(assertion, opt) {\n const description = `waitFor: ${assertion}`;\n const taskExecutor = new Executor(taskTitleStr('WaitFor', description), {\n onTaskStart: this.onTaskStartCallback\n });\n const { timeoutMs, checkIntervalMs } = opt;\n assert(assertion, 'No assertion for waitFor');\n assert(timeoutMs, 'No timeoutMs for waitFor');\n assert(checkIntervalMs, 'No checkIntervalMs for waitFor');\n const overallStartTime = Date.now();\n let startTime = Date.now();\n let errorThought = '';\n while(Date.now() - overallStartTime < timeoutMs){\n startTime = Date.now();\n const assertPlan = {\n type: 'AssertWithoutThrow',\n param: {\n assertion\n },\n locate: null\n };\n const { tasks: assertTasks } = await this.convertPlanToExecutable([\n assertPlan\n ]);\n await taskExecutor.append(this.prependExecutorWithScreenshot(assertTasks[0]));\n const result = await taskExecutor.flush();\n if (!result) throw new Error('result of taskExecutor.flush() is undefined in function waitFor');\n const { output } = result;\n if (null == output ? void 0 : output.pass) return {\n output: void 0,\n executor: taskExecutor\n };\n errorThought = (null == output ? void 0 : output.thought) || `unknown error when waiting for assertion: ${assertion}`;\n const now = Date.now();\n if (now - startTime < checkIntervalMs) {\n const timeRemaining = checkIntervalMs - (now - startTime);\n const sleepPlan = {\n type: 'Sleep',\n param: {\n timeMs: timeRemaining\n },\n locate: null\n };\n const { tasks: sleepTasks } = await this.convertPlanToExecutable([\n sleepPlan\n ]);\n await taskExecutor.append(this.prependExecutorWithScreenshot(sleepTasks[0]));\n await taskExecutor.flush();\n }\n }\n return this.appendErrorPlan(taskExecutor, `waitFor timeout: ${errorThought}`);\n }\n constructor(page, insight, opts){\n _define_property(this, \"page\", void 0);\n _define_property(this, \"insight\", void 0);\n _define_property(this, \"taskCache\", void 0);\n _define_property(this, \"conversationHistory\", []);\n _define_property(this, \"onTaskStartCallback\", void 0);\n this.page = page;\n this.insight = insight;\n this.taskCache = opts.taskCache;\n this.onTaskStartCallback = null == opts ? void 0 : opts.onTaskStart;\n }\n}\nexport { PageTaskExecutor };\n\n//# sourceMappingURL=tasks.mjs.map","import { getDebug } from \"@midscene/shared/logger\";\nimport { assert } from \"@midscene/shared/utils\";\nconst debug = getDebug('plan-builder');\nfunction buildPlans(type, locateParam, param) {\n let returnPlans = [];\n const locatePlan = locateParam ? {\n type: 'Locate',\n locate: locateParam,\n param: locateParam,\n thought: ''\n } : null;\n if ('Tap' === type || 'Hover' === type || 'RightClick' === type) {\n assert(locateParam, `missing locate info for action \"${type}\"`);\n assert(locatePlan, `missing locate info for action \"${type}\"`);\n const tapPlan = {\n type,\n param: null,\n thought: '',\n locate: locateParam\n };\n returnPlans = [\n locatePlan,\n tapPlan\n ];\n }\n if ('Input' === type || 'KeyboardPress' === type) {\n if ('Input' === type) assert(locateParam, `missing locate info for action \"${type}\"`);\n assert(param, `missing param for action \"${type}\"`);\n const inputPlan = {\n type,\n param: param,\n thought: '',\n locate: locateParam\n };\n returnPlans = locatePlan ? [\n locatePlan,\n inputPlan\n ] : [\n inputPlan\n ];\n }\n if ('Scroll' === type) {\n assert(param, `missing param for action \"${type}\"`);\n const scrollPlan = {\n type,\n param: param,\n thought: '',\n locate: locateParam\n };\n returnPlans = locatePlan ? [\n locatePlan,\n scrollPlan\n ] : [\n scrollPlan\n ];\n }\n if ('Sleep' === type) {\n assert(param, `missing param for action \"${type}\"`);\n const sleepPlan = {\n type,\n param: param,\n thought: '',\n locate: null\n };\n returnPlans = [\n sleepPlan\n ];\n }\n if ('Locate' === type) {\n assert(locateParam, `missing locate info for action \"${type}\"`);\n const locatePlan = {\n type,\n param: locateParam,\n locate: locateParam,\n thought: ''\n };\n returnPlans = [\n locatePlan\n ];\n }\n if (returnPlans) {\n debug('buildPlans', returnPlans);\n return returnPlans;\n }\n throw new Error(`Not supported type: ${type}`);\n}\nexport { buildPlans };\n\n//# sourceMappingURL=plan-builder.mjs.map","import { Insight } from \"@midscene/core\";\nimport js_yaml from \"js-yaml\";\nimport { ScriptPlayer, parseYamlScript } from \"../yaml/index.mjs\";\nimport { groupedActionDumpFileExt, reportHTMLContent, stringifyDumpData, writeLogFile } from \"@midscene/core/utils\";\nimport { DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT } from \"@midscene/shared/constants\";\nimport { getAIConfigInBoolean, vlLocateMode } from \"@midscene/shared/env\";\nimport { getDebug } from \"@midscene/shared/logger\";\nimport { assert } from \"@midscene/shared/utils\";\nimport { PageTaskExecutor } from \"./tasks.mjs\";\nimport { buildPlans } from \"./plan-builder.mjs\";\nimport { TaskCache } from \"./task-cache.mjs\";\nimport { locateParamStr, paramStr, scrollParamStr, taskTitleStr, typeStr } from \"./ui-utils.mjs\";\nimport { getReportFileName, parseContextFromWebPage, printReportMsg, trimContextByViewport } from \"./utils.mjs\";\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst debug = getDebug('web-integration');\nconst distanceOfTwoPoints = (p1, p2)=>{\n const [x1, y1] = p1;\n const [x2, y2] = p2;\n return Math.round(Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2));\n};\nconst includedInRect = (point, rect)=>{\n const [x, y] = point;\n const { left, top, width, height } = rect;\n return x >= left && x <= left + width && y >= top && y <= top + height;\n};\nconst defaultInsightExtractOption = {\n domIncluded: false,\n screenshotIncluded: true\n};\nclass PageAgent {\n async getUIContext(action) {\n if (this.frozenPageContext) {\n debug('Using frozen page context for action:', action);\n return this.frozenPageContext;\n }\n if (action && ('extract' === action || 'assert' === action)) return await parseContextFromWebPage(this.page, {\n ignoreMarker: true\n });\n return await parseContextFromWebPage(this.page, {\n ignoreMarker: !!vlLocateMode()\n });\n }\n async _snapshotContext() {\n return await this.getUIContext('locate');\n }\n async setAIActionContext(prompt) {\n this.opts.aiActionContext = prompt;\n }\n resetDump() {\n this.dump = {\n groupName: this.opts.groupName,\n groupDescription: this.opts.groupDescription,\n executions: []\n };\n return this.dump;\n }\n appendExecutionDump(execution) {\n const trimmedExecution = trimContextByViewport(execution);\n const currentDump = this.dump;\n currentDump.executions.push(trimmedExecution);\n }\n dumpDataString() {\n this.dump.groupName = this.opts.groupName;\n this.dump.groupDescription = this.opts.groupDescription;\n return stringifyDumpData(this.dump);\n }\n reportHTMLString() {\n return reportHTMLContent(this.dumpDataString());\n }\n writeOutActionDumps() {\n if (this.destroyed) throw new Error('PageAgent has been destroyed. Cannot update report file.');\n const { generateReport, autoPrintReportMsg } = this.opts;\n this.reportFile = writeLogFile({\n fileName: this.reportFileName,\n fileExt: groupedActionDumpFileExt,\n fileContent: this.dumpDataString(),\n type: 'dump',\n generateReport\n });\n debug('writeOutActionDumps', this.reportFile);\n if (generateReport && autoPrintReportMsg && this.reportFile) printReportMsg(this.reportFile);\n }\n async callbackOnTaskStartTip(task) {\n const param = paramStr(task);\n const tip = param ? `${typeStr(task)} - ${param}` : typeStr(task);\n if (this.onTaskStartTip) await this.onTaskStartTip(tip);\n }\n async afterTaskRunning(executor, doNotThrowError = false) {\n this.appendExecutionDump(executor.dump());\n try {\n var _this_onDumpUpdate, _this;\n await (null == (_this_onDumpUpdate = (_this = this).onDumpUpdate) ? void 0 : _this_onDumpUpdate.call(_this, this.dumpDataString()));\n } catch (error) {\n console.error('Error in onDumpUpdate', error);\n }\n this.writeOutActionDumps();\n if (executor.isInErrorState() && !doNotThrowError) {\n const errorTask = executor.latestErrorTask();\n throw new Error(`${null == errorTask ? void 0 : errorTask.errorMessage}\\n${null == errorTask ? void 0 : errorTask.errorStack}`, {\n cause: null == errorTask ? void 0 : errorTask.error\n });\n }\n }\n buildDetailedLocateParam(locatePrompt, opt) {\n assert(locatePrompt, 'missing locate prompt');\n if ('object' == typeof opt && null !== opt) {\n const prompt = locatePrompt;\n const deepThink = opt.deepThink ?? false;\n const cacheable = opt.cacheable ?? true;\n const xpath = opt.xpath;\n return {\n prompt,\n deepThink,\n cacheable,\n xpath\n };\n }\n return {\n prompt: locatePrompt\n };\n }\n async aiTap(locatePrompt, opt) {\n const detailedLocateParam = this.buildDetailedLocateParam(locatePrompt, opt);\n const plans = buildPlans('Tap', detailedLocateParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Tap', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiRightClick(locatePrompt, opt) {\n const detailedLocateParam = this.buildDetailedLocateParam(locatePrompt, opt);\n const plans = buildPlans('RightClick', detailedLocateParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('RightClick', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiHover(locatePrompt, opt) {\n const detailedLocateParam = this.buildDetailedLocateParam(locatePrompt, opt);\n const plans = buildPlans('Hover', detailedLocateParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Hover', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiInput(value, locatePrompt, opt) {\n assert('string' == typeof value, 'input value must be a string, use empty string if you want to clear the input');\n assert(locatePrompt, 'missing locate prompt for input');\n const detailedLocateParam = this.buildDetailedLocateParam(locatePrompt, opt);\n const plans = buildPlans('Input', detailedLocateParam, {\n value,\n autoDismissKeyboard: null == opt ? void 0 : opt.autoDismissKeyboard\n });\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Input', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiKeyboardPress(keyName, locatePrompt, opt) {\n assert(keyName, 'missing keyName for keyboard press');\n const detailedLocateParam = locatePrompt ? this.buildDetailedLocateParam(locatePrompt, opt) : void 0;\n const plans = buildPlans('KeyboardPress', detailedLocateParam, {\n value: keyName\n });\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('KeyboardPress', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiScroll(scrollParam, locatePrompt, opt) {\n const detailedLocateParam = locatePrompt ? this.buildDetailedLocateParam(locatePrompt, opt) : void 0;\n const plans = buildPlans('Scroll', detailedLocateParam, scrollParam);\n const paramInTitle = locatePrompt ? `${locateParamStr(detailedLocateParam)} - ${scrollParamStr(scrollParam)}` : scrollParamStr(scrollParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Scroll', paramInTitle), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiAction(taskPrompt, opt) {\n var _this_taskCache, _this_taskCache1;\n const cacheable = null == opt ? void 0 : opt.cacheable;\n const isVlmUiTars = 'vlm-ui-tars' === vlLocateMode();\n const matchedCache = isVlmUiTars || false === cacheable ? void 0 : null == (_this_taskCache = this.taskCache) ? void 0 : _this_taskCache.matchPlanCache(taskPrompt);\n if (matchedCache && (null == (_this_taskCache1 = this.taskCache) ? void 0 : _this_taskCache1.isCacheResultUsed)) {\n var _matchedCache_cacheContent, _matchedCache_cacheContent1;\n const { executor } = await this.taskExecutor.loadYamlFlowAsPlanning(taskPrompt, null == (_matchedCache_cacheContent = matchedCache.cacheContent) ? void 0 : _matchedCache_cacheContent.yamlWorkflow);\n await await this.afterTaskRunning(executor);\n debug('matched cache, will call .runYaml to run the action');\n const yaml = null == (_matchedCache_cacheContent1 = matchedCache.cacheContent) ? void 0 : _matchedCache_cacheContent1.yamlWorkflow;\n return this.runYaml(yaml);\n }\n const { output, executor } = await (isVlmUiTars ? this.taskExecutor.actionToGoal(taskPrompt, {\n cacheable\n }) : this.taskExecutor.action(taskPrompt, this.opts.aiActionContext, {\n cacheable\n }));\n if (this.taskCache && (null == output ? void 0 : output.yamlFlow) && false !== cacheable) {\n const yamlContent = {\n tasks: [\n {\n name: taskPrompt,\n flow: output.yamlFlow\n }\n ]\n };\n const yamlFlowStr = js_yaml.dump(yamlContent);\n this.taskCache.updateOrAppendCacheRecord({\n type: 'plan',\n prompt: taskPrompt,\n yamlWorkflow: yamlFlowStr\n }, matchedCache);\n }\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiQuery(demand, opt = defaultInsightExtractOption) {\n const { output, executor } = await this.taskExecutor.query(demand, opt);\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiBoolean(prompt, opt = defaultInsightExtractOption) {\n const { output, executor } = await this.taskExecutor.boolean(prompt, opt);\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiNumber(prompt, opt = defaultInsightExtractOption) {\n const { output, executor } = await this.taskExecutor.number(prompt, opt);\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiString(prompt, opt = defaultInsightExtractOption) {\n const { output, executor } = await this.taskExecutor.string(prompt, opt);\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiAsk(prompt, opt = defaultInsightExtractOption) {\n return this.aiString(prompt, opt);\n }\n async describeElementAtPoint(center, opt) {\n const { verifyPrompt = true, retryLimit = 3 } = opt || {};\n let success = false;\n let retryCount = 0;\n let resultPrompt = '';\n let deepThink = (null == opt ? void 0 : opt.deepThink) || false;\n let verifyResult;\n while(!success && retryCount < retryLimit){\n if (retryCount >= 2) deepThink = true;\n debug('aiDescribe', center, 'verifyPrompt', verifyPrompt, 'retryCount', retryCount, 'deepThink', deepThink);\n const text = await this.insight.describe(center, {\n deepThink\n });\n debug('aiDescribe text', text);\n assert(text.description, `failed to describe element at [${center}]`);\n resultPrompt = text.description;\n verifyResult = await this.verifyLocator(resultPrompt, deepThink ? {\n deepThink: true\n } : void 0, center, opt);\n if (verifyResult.pass) success = true;\n else retryCount++;\n }\n return {\n prompt: resultPrompt,\n deepThink,\n verifyResult\n };\n }\n async verifyLocator(prompt, locateOpt, expectCenter, verifyLocateOption) {\n debug('verifyLocator', prompt, locateOpt, expectCenter, verifyLocateOption);\n const { center: verifyCenter, rect: verifyRect } = await this.aiLocate(prompt, locateOpt);\n const distance = distanceOfTwoPoints(expectCenter, verifyCenter);\n const included = includedInRect(expectCenter, verifyRect);\n const pass = distance <= ((null == verifyLocateOption ? void 0 : verifyLocateOption.centerDistanceThreshold) || 20) || included;\n const verifyResult = {\n pass,\n rect: verifyRect,\n center: verifyCenter,\n centerDistance: distance\n };\n debug('aiDescribe verifyResult', verifyResult);\n return verifyResult;\n }\n async aiLocate(prompt, opt) {\n const detailedLocateParam = this.buildDetailedLocateParam(prompt, opt);\n const plans = buildPlans('Locate', detailedLocateParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Locate', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n const { element } = output;\n return {\n rect: null == element ? void 0 : element.rect,\n center: null == element ? void 0 : element.center,\n scale: (await this.page.size()).dpr\n };\n }\n async aiAssert(assertion, msg, opt) {\n const { output, executor, thought } = await this.taskExecutor.assert(assertion, {\n returnThought: true\n });\n await this.afterTaskRunning(executor, true);\n if (null == opt ? void 0 : opt.keepRawResponse) return {\n pass: output,\n thought\n };\n if (!output) {\n var _executor_latestErrorTask;\n const errMsg = msg || `Assertion failed: ${assertion}`;\n const reasonMsg = `Reason: ${thought || (null == (_executor_latestErrorTask = executor.latestErrorTask()) ? void 0 : _executor_latestErrorTask.error) || '(no_reason)'}`;\n throw new Error(`${errMsg}\\n${reasonMsg}`);\n }\n }\n async aiWaitFor(assertion, opt) {\n const { executor } = await this.taskExecutor.waitFor(assertion, {\n timeoutMs: (null == opt ? void 0 : opt.timeoutMs) || 15000,\n checkIntervalMs: (null == opt ? void 0 : opt.checkIntervalMs) || 3000,\n assertion\n });\n await this.afterTaskRunning(executor, true);\n if (executor.isInErrorState()) {\n const errorTask = executor.latestErrorTask();\n throw new Error(`${null == errorTask ? void 0 : errorTask.error}\\n${null == errorTask ? void 0 : errorTask.errorStack}`);\n }\n }\n async ai(taskPrompt, type = 'action') {\n if ('action' === type) return this.aiAction(taskPrompt);\n if ('query' === type) return this.aiQuery(taskPrompt);\n if ('assert' === type) return this.aiAssert(taskPrompt);\n if ('tap' === type) return this.aiTap(taskPrompt);\n if ('rightClick' === type) return this.aiRightClick(taskPrompt);\n throw new Error(`Unknown type: ${type}, only support 'action', 'query', 'assert', 'tap', 'rightClick'`);\n }\n async runYaml(yamlScriptContent) {\n const script = parseYamlScript(yamlScriptContent, 'yaml', true);\n const player = new ScriptPlayer(script, async (target)=>({\n agent: this,\n freeFn: []\n }));\n await player.run();\n if ('error' === player.status) {\n const errors = player.taskStatusList.filter((task)=>'error' === task.status).map((task)=>{\n var _task_error;\n return `task - ${task.name}: ${null == (_task_error = task.error) ? void 0 : _task_error.message}`;\n }).join('\\n');\n throw new Error(`Error(s) occurred in running yaml script:\\n${errors}`);\n }\n return {\n result: player.result\n };\n }\n async evaluateJavaScript(script) {\n assert(this.page.evaluateJavaScript, 'evaluateJavaScript is not supported in current agent');\n return this.page.evaluateJavaScript(script);\n }\n async destroy() {\n await this.page.destroy();\n this.resetDump();\n this.destroyed = true;\n }\n async logScreenshot(title, opt) {\n const base64 = await this.page.screenshotBase64();\n const now = Date.now();\n const recorder = [\n {\n type: 'screenshot',\n ts: now,\n screenshot: base64\n }\n ];\n const task = {\n type: 'Log',\n subType: 'Screenshot',\n status: 'finished',\n recorder,\n timing: {\n start: now,\n end: now,\n cost: 0\n },\n param: {\n content: (null == opt ? void 0 : opt.content) || ''\n },\n executor: async ()=>{}\n };\n const executionDump = {\n sdkVersion: '',\n logTime: now,\n model_name: '',\n model_description: '',\n name: `Log - ${title || 'untitled'}`,\n description: (null == opt ? void 0 : opt.content) || '',\n tasks: [\n task\n ]\n };\n this.appendExecutionDump(executionDump);\n try {\n var _this_onDumpUpdate, _this;\n null == (_this_onDumpUpdate = (_this = this).onDumpUpdate) || _this_onDumpUpdate.call(_this, this.dumpDataString());\n } catch (error) {\n console.error('Failed to update dump', error);\n }\n this.writeOutActionDumps();\n }\n _unstableLogContent() {\n const { groupName, groupDescription, executions } = this.dump;\n const newExecutions = Array.isArray(executions) ? executions.map((execution)=>{\n const { tasks, ...restExecution } = execution;\n let newTasks = tasks;\n if (Array.isArray(tasks)) newTasks = tasks.map((task)=>{\n const { pageContext, log, ...restTask } = task;\n return restTask;\n });\n return {\n ...restExecution,\n ...newTasks ? {\n tasks: newTasks\n } : {}\n };\n }) : [];\n return {\n groupName,\n groupDescription,\n executions: newExecutions\n };\n }\n async freezePageContext() {\n debug('Freezing page context');\n const context = await this._snapshotContext();\n context._isFrozen = true;\n this.frozenPageContext = context;\n debug('Page context frozen successfully');\n }\n async unfreezePageContext() {\n debug('Unfreezing page context');\n this.frozenPageContext = void 0;\n debug('Page context unfrozen successfully');\n }\n constructor(page, opts){\n _define_property(this, \"page\", void 0);\n _define_property(this, \"insight\", void 0);\n _define_property(this, \"dump\", void 0);\n _define_property(this, \"reportFile\", void 0);\n _define_property(this, \"reportFileName\", void 0);\n _define_property(this, \"taskExecutor\", void 0);\n _define_property(this, \"opts\", void 0);\n _define_property(this, \"dryMode\", false);\n _define_property(this, \"onTaskStartTip\", void 0);\n _define_property(this, \"taskCache\", void 0);\n _define_property(this, \"onDumpUpdate\", void 0);\n _define_property(this, \"destroyed\", false);\n _define_property(this, \"frozenPageContext\", void 0);\n this.page = page;\n this.opts = Object.assign({\n generateReport: true,\n autoPrintReportMsg: true,\n groupName: 'Midscene Report',\n groupDescription: ''\n }, opts || {});\n if ('puppeteer' === this.page.pageType || 'playwright' === this.page.pageType) {\n this.page.waitForNavigationTimeout = this.opts.waitForNavigationTimeout ?? DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT;\n this.page.waitForNetworkIdleTimeout = this.opts.waitForNetworkIdleTimeout ?? DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT;\n }\n this.onTaskStartTip = this.opts.onTaskStartTip;\n this.insight = new Insight(async (action)=>this.getUIContext(action));\n if ((null == opts ? void 0 : opts.cacheId) && 'android' !== this.page.pageType) this.taskCache = new TaskCache(opts.cacheId, getAIConfigInBoolean('MIDSCENE_CACHE'));\n this.taskExecutor = new PageTaskExecutor(this.page, this.insight, {\n taskCache: this.taskCache,\n onTaskStart: this.callbackOnTaskStartTip.bind(this)\n });\n this.dump = this.resetDump();\n this.reportFileName = (null == opts ? void 0 : opts.reportFileName) || getReportFileName((null == opts ? void 0 : opts.testId) || this.page.pageType || 'web');\n }\n}\nexport { PageAgent };\n\n//# sourceMappingURL=agent.mjs.map","import { PLAYGROUND_SERVER_PORT } from \"@midscene/shared/constants\";\nimport { ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED, StaticPage, StaticPageAgent } from \"@midscene/web/playground\";\nconst serverBase = `http://localhost:${PLAYGROUND_SERVER_PORT}`;\nconst checkServerStatus = async ()=>{\n try {\n const res = await fetch(`${serverBase}/status`);\n return 200 === res.status;\n } catch (e) {\n return false;\n }\n};\nconst requestPlaygroundServer = async function(context, type, prompt) {\n let { requestId, deepThink } = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : {};\n const payload = {\n context,\n type,\n prompt\n };\n if (requestId) payload.requestId = requestId;\n if (deepThink) payload.deepThink = deepThink;\n const res = await fetch(`${serverBase}/execute`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload)\n });\n return res.json();\n};\nconst overrideServerConfig = async (aiConfig)=>fetch(`${serverBase}/config`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n aiConfig\n })\n });\nconst cancelTask = async (requestId)=>{\n try {\n const res = await fetch(`${serverBase}/cancel/${requestId}`);\n return res.json();\n } catch (error) {\n console.error('Failed to cancel task:', error);\n return {\n error: 'Failed to cancel task'\n };\n }\n};\nconst getTaskProgress = async (requestId)=>{\n try {\n const response = await fetch(`${serverBase}/task-progress/${requestId}`);\n return await response.json();\n } catch (error) {\n console.error('Failed to poll task progress:', error);\n return {\n tip: null\n };\n }\n};\nconst actionNameForType = (type)=>{\n if ('aiAction' === type) return 'Action';\n if ('aiQuery' === type) return 'Query';\n if ('aiAssert' === type) return 'Assert';\n if ('aiTap' === type) return 'Tap';\n return type;\n};\nconst staticAgentFromContext = (context)=>{\n const page = new StaticPage(context);\n return new StaticPageAgent(page);\n};\nconst formatErrorMessage = (e)=>{\n const errorMessage = (null == e ? void 0 : e.message) || '';\n if (errorMessage.includes('of different extension')) return 'Conflicting extension detected. Please disable the suspicious plugins and refresh the page. Guide: https://midscenejs.com/quick-experience.html#faq';\n if (!(null == errorMessage ? void 0 : errorMessage.includes(ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED))) return errorMessage;\n return 'Unknown error';\n};\nconst getPlaceholderForType = (type)=>{\n if ('aiQuery' === type) return 'What do you want to query?';\n if ('aiAssert' === type) return 'What do you want to assert?';\n return 'What do you want to do?';\n};\nconst blankResult = {\n result: null,\n dump: null,\n reportHTML: null,\n error: null\n};\nexport { actionNameForType, blankResult, cancelTask, checkServerStatus, formatErrorMessage, getPlaceholderForType, getTaskProgress, overrideServerConfig, requestPlaygroundServer, serverBase, staticAgentFromContext };\n","import { useEffect, useState } from \"react\";\nimport { useEnvConfig } from \"../store/store.mjs\";\nimport { checkServerStatus } from \"./playground-utils.mjs\";\nconst useServerValid = function() {\n let shouldRun = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : true;\n const [serverValid, setServerValid] = useState(true);\n const { serviceMode } = useEnvConfig();\n useEffect(()=>{\n let interruptFlag = false;\n if (!shouldRun) return;\n Promise.resolve((async ()=>{\n while(!interruptFlag){\n const status = await checkServerStatus();\n status ? setServerValid(true) : setServerValid(false);\n await new Promise((resolve)=>setTimeout(resolve, 1000));\n }\n })());\n return ()=>{\n interruptFlag = true;\n };\n }, [\n serviceMode,\n shouldRun\n ]);\n return serverValid;\n};\nexport { useServerValid };\n","import dayjs from \"dayjs\";\nfunction insightDumpToExecutionDump(insightDump) {\n const insightToTask = (insightDump)=>{\n var _insightDump_taskInfo, _insightDump_taskInfo1;\n const task = {\n type: 'Insight',\n subType: 'locate' === insightDump.type ? 'Locate' : 'Query',\n status: insightDump.error ? 'failed' : 'finished',\n locate: null,\n param: {\n ...insightDump.userQuery.element ? {\n query: insightDump.userQuery\n } : {},\n ...insightDump.userQuery.dataDemand ? {\n dataDemand: insightDump.userQuery.dataDemand\n } : {},\n insight: {}\n },\n log: {\n dump: insightDump\n },\n timing: {\n end: insightDump.logTime,\n cost: null == (_insightDump_taskInfo = insightDump.taskInfo) ? void 0 : _insightDump_taskInfo.durationMs,\n start: insightDump.logTime - (null == (_insightDump_taskInfo1 = insightDump.taskInfo) ? void 0 : _insightDump_taskInfo1.durationMs)\n },\n executor: ()=>{}\n };\n return task;\n };\n if (!Array.isArray(insightDump)) {\n const result = {\n sdkVersion: insightDump.sdkVersion,\n logTime: insightDump.logTime,\n model_name: insightDump.model_name,\n name: 'Insight',\n tasks: [\n insightToTask(insightDump)\n ]\n };\n return result;\n }\n const result = {\n sdkVersion: insightDump[0].sdkVersion,\n logTime: insightDump[0].logTime,\n model_name: insightDump[0].model_name,\n name: 'Insight',\n tasks: insightDump.map(insightToTask)\n };\n return result;\n}\nfunction timeStr(timestamp) {\n return timestamp ? dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss') : '-';\n}\nfunction filterBase64Value(input) {\n return input.replace(/data:image\\/[^\"]+\"/g, 'data:image...\"');\n}\nconst mousePointer = 'data:image/png;base64,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';\nconst mouseLoading = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAhGVYSWZNTQAqAAAACAAFARIAAwAAAAEAAQAAARoABQAAAAEAAABKARsABQAAAAEAAABSASgAAwAAAAEAAgAAh2kABAAAAAEAAABaAAAAAAAAAEgAAAABAAAASAAAAAEAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAYKADAAQAAAABAAAAYAAAAABaCTJNAAAACXBIWXMAAAsTAAALEwEAmpwYAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgoZXuEHAAAZfUlEQVR4Ae1da5Ac1XXue7tnHzMrYSMMEqyMYB/CCOyEhTjxH9YYk0p4GEsBJxTgFNjalYDEruCHMAkjEsd2gsu4AD1DUrYpUoZgy4iEAhNbqiRQDpIxGAGSdnmYt4wgknZmd2em++b7TnfPzvZ0z660u3rNXGmnu2/f53fOPffccx9tWQ3XQKCBwEFAwFiWOgjZNLKIQ8BkLR3nf7j6mcss+0grcxWW5HipSMD5ZumpxxyJlWIdqio3jR4zwpksNOSNUfdbLq/5ZZ2/n9fq+jffOLFlGss+I0mRcYb7O1fl+zuu5z3rYLK9zkwxz7TLZRZUZS2Phc8v6zhLGbXC0WpJCT6uZX1m1pqB+4RAqNiMIHiAiYblHlreeUGLUo/YWln5krfBuN7ftK178ddMdibKPW0twBiInAD8kWULF4KDbkqn7C2tjlpS9IxhhZDZZXuXdh9Hrsoepv2C8qwbUVRruOgV0yl9qdL66Vx/11/nb+hs91uDpVnXA6RzVbRpIYBwhoLIAefn+zr/xDXuf6MBrEQlyEXkdDQI/LesT2lV+ghvbtk2fZVgelNxFDEsO4C+COmcP1IyLK2TL7gUoSrdpG41RevxfF/XYoZTqCvrPJU8w7hTJkDYLFmJXF9Xv6esu1tsdRwy0MZjPRQLqiGC3CZbpbSyV5ilPamQm8KCHKorC6iymwA5GcL0pZu0wn0J5SH2Nu5NvuCVUPb5tm09kO/v+jLLKuWfBiJMqSmF4O9Z3tFpe2p9Jm335vMi2j2/AuO43HM0CWG9Aw5anl49cL9UPmgarNShcKHYHOrr+mSTbT0KccmyxzGmC9FkQ/yQqx6ybe+vWu56cUeIwYGWPS6jSaUlzRayfN/nOxfZrvr3TJPuzefcQhCZ6UaJK60AHHYcuoTFUvFDDD7LSpEiV+V9AQxSy9nQI4i/l27WF3muepB191tyr1MrYq13tbNMiLmFIgTNdmRZ9/kQME8026qbzRSQNyVECbyVGkW/0Kz1n+be7ryCniRE7Tgz9zbMO7es68J0k/3HwyUDCVrT8bXKj3rFlK0Xatt6XDAAFsSkZsyEl/tdeXL+2eu2FpkxWutPIDJnFfxmW4sLwDiWm3aUhrDdPeqZzZC0m6VMWb93TijfzHrfEuSt3F35orcRHZSGrCcmbBXSMmIKQCKkCq7xEH42MSAWxITYxISv6TUBwcfHlc4TGQ2R8433IPT7VnSuSTIzjFxEJilUzBpxzbvo4a5Jv9v8sLp/WyiuwnCH5EqVUrQatMShtzp6taXWQv3sHEVn5RohQi0mRb8GpvLMsFH6krbVOx4LMZpsZSZNAJH5aGq55aeeozy9GXo9wKeKKVpOfH7KKkHmO6MFzwLnr8jMbb+NoouB0SRQ70PI/RUlruxI74Nmc+Gcjq8qS33Nr6OhVlFD5TSuo7XtkgjaOzez6sUnQ6wqski8nRQBWKjL0eFygAVtcgNk/mng5loFo8gxUEf1qGv+x1M6S+5gKchxK1ei7ws6v8SSHeQXZAjrMozigxH60NJTz8Qg7F4w0BkQTyWwComQhJeLutqo6wtQsy9tWb19e6hdTVSNpATL8ULuGLnu1O6SpzdmHN2NAiWDzzEMBioouEa4DWn3mMtVIB9D7i8nfpjehHUe+twpJyjHXoe6XAIlg6KWeCVh5kJ02bmCt8PT7iWzV7+0PUynVjVryTfh1pAjXFd/G6omwafsTmqS5HwLBdEYBd+TzqSvJPjbLlvUdKSAz/KLagmtpu2fXno7nUtfIXVBnQKBKXVkuIiz2VIyKdWtjb1x73WnzfFV1NpaXk0CWBAVzISjP9xcBPWLXJCkbonYSbdolSu6/4CB1lXqtmdybIqLDpMONwJYzUdptRC96gfP5FgXqRPqhkhSz4TITr5kCplWu8v2ikskzAQml6TmVLb80f7BITgGTzRxMvPqOPBHj+q1NqMJjnjfals78FVmHmoYUpAj9KeyDkN9nd/MtOiv5EeAhI9CNRZBPfFin1Hm6szqwQ21RFFsCwgjDC1fMBeJ3E66+9bkGPDJEZD5BH+44IMPKvmWUfgfobiXix2qqKwTGSs3itaNwQ8CsG5J9fNgBZ4Fs90dxFBEUYLdqIoAzGjlIj9hbVI3YfA0v+DW6HRRCJH5AB9NVTjfytLAlTiQKVfuSLmRuqBOLG/bmsGvDJfQv0HJwGMSATREUSmdUu3EUOp5vz9HIvcVP5JoxXNZ9OT6Tj0bw/Mn8wU2QglRFRa+yERD7nkbMqsHPs1QJCACJhVMEjpSf0JxZG78cCa/L39PS0pdOiLm9tixkAhsmLIVzNrnZNa+uCWULJX1r2oBbC7U+wHjTQIjZDsiJINfdF/2RqylTJTxjlbwWb9QHFG5wGj+M6MlsxlMyjoX+T7iMJYLpYBawXfENhJmvIpECjEARoLXpB39aTQjgl+tcvqdrjPqeszh2ln/MvBbDsE5WItmcLQ9UxztvKGzWUwpRq1l/dDciVFcq4dqaizHVosL/Z2/K2EjxsdyCxDRAQDNF9tbQavr0OkmO3Su7IdgLlkxa83gz2ToDX0/OcLR9abrjoFRqtfptTv/FQO0LLBI7A/QOlxihcHT1ytQKEuU8k1ov8j1d3y+2dbrMKwORU85TJCAR6tmrmgehVbwhxWJ1tWtMCy4nlIjP6dzFzA5NpAYZaYWQCAtbFj4YNjLK22uSa8a/GEYl+8lsHQuMJLtuXbRseD+Pgo1po2fKPjSLmDS56vb+BuKLd7XkwMwhq1A5DosvLmS2c0ZP2Ag6JSxQE8A8KmspD1PrTBfWPA+xoUtTLD3qXW5/5BqGu3GbE8PVSgAXC37adOH+oVpu4cya3eKcc2CelXOrM5uVgb1Tc9rfhhM/iub+p/PuFEkaKbgZM+H86N2B1+eHoyQfQLc54MI9j7P70oMU4o6emKlAHsHtRb34ACsJsA1GrBenmnRFdUyuw2ouN+A2C7SNI36R5lS4JIBnLGuJz6hwqKJJtWrfH/3SZgs+QtOGcLLJwxDjjnTmkI6lvVYZs3Oh6T5Bbb9sSD1dxcOWj3jPA10NtBkAydAjUdD6QK0Frz6RKW/5qiVHp5yz8cExAmQV3RVCcAD5mVDxVRkv4Rq/FhhK5i9bsc7rjEP+GKoGj9iSvwxgzYfxk0x1JGJtRXIImX0xylP4KLNh34GEXndljlxQGT/0WRqYMWm4sIBVlvR+Q/0j7t8JSZWNHNtFCyX5kuSH7CXXnxvX+cfQFtazNVJCc5L+dL+lw3g4xESkfzP2/eBV29ubhIJHjcoVZi6ZK95ItdSkXASMqXUQkypzQom2KPih52vjUmJnNHu7cyemcUXo459A0li22YzzNWctHIIVQQRhY6aXvNTRsnIWID0lOm2U2WqRQlQam2xofKY+9tWv/SMgJ+tSjiSTx0+Bup4c1PhVXAsbERlPCvBoKJaSLfaXHHxO3whoaD9tFN9jSIvMcWkBKp5agufn9u2qK5VT8Ek5gfYYVSMqdfvvDYMPDfEBBEvEEdziQi61LNp9tH55R3zgfxHS/AEzNHBFz0dTEVSDO1iCqcv+kBcJ52UX535bxO5j0HZsxgv7UF/6wC/8WIIfA5pQuF0rJVLZ7CgBTM3xjoFK70IVrQRcGkJfQc9p/RfPpqbGgSYgK1c29oLNEc1BU50VhDMjyU9NG1/aNQuztEFS50GGZ9CmjA/VBNA++pnrm3Vy28hUYVxg1BqgjLU52vOegHbtlU7fwXo30z5+uh4vCDSEabU2mxnisY5A/h6FxgZocVqNqAf45unBNFsL5Mcn2B9Qh1ba8FmZa8vxpW1xceuiqkZVxNzrHP5BDrhWKObnwGoSckEou0Wj22bGuD7yNT4DUS0Mb+gqIETRSc+gkqTACcmTb5ATikmAjpskgSCyfr4xBq+4xAwyrecjfMc/4ANRAW0AnOyT6iYpsI+BBNfReW9KVFvaYif8RBWP60MvLRtngeu8fsNwNGU+uD+0zmZNgSc4yU7WxB6bW3Z6SDdxmUCBG4JmNS4akTQE3AjkQI/XFrYAj4IKx4FfZWjFgVXShn9qtzFhBH/xs8YAgFGBdd+C57cZRnriDn+nahtrecliaAgstsyd+5rTAXPjU44Fs4xzxCjY3QbMUsigGK/C9P1PO7uiJdTFWm+Pfh889hj4246EUALqKUmSVbmhNZ2WvcabhIIhMJ8ROdOQnDuM45zhuNbjNre1J5ntoMIdFVhA5tD6j373Q8FAQKpJOEbP3EIBChCc5yP146MY6PhEMafOVOvYk5YjdDgmewMtoun/FNOqkiUHKve32CLXx6werHQhh0F9lqQ99/wTRbVLcD3UbajvLkC6MrY5Ood6/H1DzCC5jgP3E9raKLDK9kb/rpvb6sOx7gkDvbFtFe/bfjEIhDOsSvrXFqSRdusDog5dmqV5llcMGSoDhD6eJxEBoF6xCNIPHzZuCYjAB3/eJEsUXO0RDFGrMxK/a/GDMIjwuaxqyEM9h9LD7FQ4r2/x++uk/NtvAkxMlYHORcMHiOEMGeGV8D+dYyE1Vs0+OA5LqByxRhntQ9/buEp/nbTCdXWuiUCAFTE6LfXLOQk1/uMWDkDe0IMKrbRr+gmY+3Kj7hvYFEWJ2Wis11KViJa1jzPds9gGps29TZaQQyY9Nq6tIcrIazZTd4FgH0RDv/g43gJD9mEd5jmdfOYms9jRkzvQaA3/EURVa2AEmw0nXGakMxZTK39zNei88b0bjgg0PPeVmFgbKs/A5v0iAnniMcTAKopO2f8e67JTr2puaQODecJnGXFCNEWAHJhoh5nPSBGj/nzBS2yOSGaKGPWuRPxM7ZD6MzkfhUmamANXDequ17YHYgT8xhOumJ7oRiSdlPGE+boIl8Zc2bOUceIfzZC1XLgOr4JMMkv7foo0PoktuwSSRFJFagQW9v134mBUwjgKvMO3uyRUQGDjHfcD1BKtzgLQLlPjX/VeIoi4GpzVqbFng3dhwdYjRc/IAk3cYy43nvQg55nXFypA1km19+5Bbs4erCRgHKrSs5To0KnvmskZXXNuWNgbzTjxrOPQK6v88EWR12MqVyK84jCYnCgh81lnk+k1wx8jPsrNI9oYVQopnfiBW+rwKcnNSqcEHV8U8H8EZ/rdWsS6x514VrZERz6CsMmwWeQCPjgdPK6PzT+uaSBRQ463GKktfef9Iy2GQno/0Ct5ZI6tWRff8fxXNmLxxrBK2LWyS127d6Is5RYW+HkSLW5WY876H+DyfjvyjusI6JkEXJh996rwPPHrb42RDEUddRf4cxiR9vd8jJcAxMNWUfP/u7SsUNfY3V/Hw9DEzSawCvY2ivLPIm9NBPZGY9AOAPrVvQBDE6ohTB8CBzP/Cymm20cz+VdKH51vk4IAPmHvmYpbqKHvoawhVf/+GYYd75Hn1BsCQGeC9b7ZJzRV/DuKR6+gWt1K4BaxfPf4Jbv4zG+FEOSOb3q0AX9Jw/7Q/94UXCqVkwfis4XYgPMvTVftO+rRIqcLk6oCcIM9XVcjV17d0M2OTBDU8qXwwRBeRQL94u9m3l3wO8LyAnVLSYIfnRfgo3aL0D246RF6RWjeFGSGLzH+Xne0syawfXhpngiIy1AIAqoaTveZoT314JGk5KAluYBp0jwWOwQv1m8slVE8kMexb8EkdUbmdP5JUiMTjlZoJpZGcSQYfH+6XTr6D30sLKbytKlTABfnPQ6rXe99AqCrJdl6clcTSOdh10gWZyo9WfcN8YDLCTxOviRjRjYogtt8Dw0/W9U9JvVtYcM8bVScxc3b8i+4gpcywRgzPBgPdPsPQh16Sc8EwLecSoVRY5PRWX6WKDwAIvqEhxdPgIgzsAz+A4CwLm7WcwHsUv7WXGv2VGqUDLbcHjT9+lBRuc1dOMIQE9m0Pbdl962jPd3AeWi2pDEhWeK5+sjg3Pzx47+kIcYsSUczWMD1k0kxVU4sEl7d2NUuwDcz30VUZuPQAmMBF+sQfl7FZywIuBV/FQRgAMzEoEnPGHXzL3pVoe9esK6IGXjYwc8TfzS4Vx+DdNF05BDLCryOCpuqe2xbqzMcFt+DcTvJfmiS26OAx/exsvAJA3Zf2fb6p33ImLs5pYqAkC0GGtRr3S/yHAdrKQFaERN8JXMWYCIw5FcHjQjfeVQf8e35F326CKCqNqoE+vGOrKuvsoZe6QDg8HmD7WzZF41uvR1esipvMQ24gToiJ88+rIO3wfAtnpHmX9LUEnDqEIeOTO0cWwlYYawwpJPoy/HoU4/CrEMwaq8VrWA8GU4yJq1ZucD6IVvxd5WEqsYvo9cRQHjwa48VzNsCSKOgmPQIuGPiMdKscM6yZmhPLzWZ9sk5i36WKnvCfhBv5FU4UQCVEZIO9a3h0fcndCKOGHDTifOsUCKh5pmUvaX8e2wHxh0VkJIaElxEQ5nPzkXjkoFT0hEXaROPLCVstz/iyt+Cf1hKjfs/hxm+y9KgCQyBbFrEkC0GnAwevC9JeVejGPKdmDQwU5nnCpVURLJDpqBB6PelflM/l6qazzgLhy4VIQ9LG+BsBw6K2o1GIfHU0pdUKcJON/D2XAOTg7e4dpmKedMRPTEyP3Kik9AHz+oNEVww/4dXw/tCJMP0BRehgi7lof7MTUWipoWMq7qkCoLdijuw3oybw4wQYo+qtnU9OBFrJLwIvgag9O9mM762Kz1A9tqyX2mH7qkBMP35Wtovygs7z4HH274GeR7GxokW0KM8akcTQ525dcooEOvaNk98I/hQCRMrxzyEN3IuIVmdVh2fXEph/DdzFE+i8SxDnCvVUcXvSM/8LMP5wksaVu786eTBZ/pT5oADBx+niO3rONSTOvjcCJLY7BG7qglymSgAtFlQTQNgBR9bXMHN4l4g27NdHnP68F2UaB4UDnKt552LppaUB7+Jej5Ulr5tBXAh3gyS+Sgbn7gaD+O8Nw/AgArRPCPajyu42J8J/L7MMOGH/GpRQSKG7EIshvjoX9Iai2PPpNq8GVADCvLFRszI54o35G+1DkkOmf3OMHEOQ68WAbD2TE0NqJIDCdhwzJGruFXM4ZwANNV6XcGN0oLQhxEmrR4rZVBJL/qR378TGGMAPk3GxyTNCQfiyj6cfB1DUTAi8cwTXdby6qBR8cCofToJ7ZijWXPuq2l/alMZRrhPQnL1XxcUMaONfTffUPnbM5vc4oVOS7mRBPnOibRopmEiFbMob+AVbZXZ1bteDJMd3+vB0QA4SQsw2NTk4+ZaetH0JG7+X0tFCBVqxBEHZkSWIerxzBUtzCXuhG98sP4Gt8v0+t2/qIyPsWeFaw4szhxdEvAXUgA/8ucJmXi08qAa7mSG0SsFAdcWMa1TbK8xqi/5SIDMV6xQJjtQ2oOYuGppitSHadGiJZziXwvhmU8QGaZKLOaJQllqHzK0FXr8OWIj+eHgahvM6klkpgu4eKfpulbo4/Ijbh7UaCfwu/XQOLZvQX96AfkGDD4HKDjomJZ18qllVxmjwVmXOM0MurKSg8kWy5HzSz81mulUViOiaiWy3dieHTnFE6PnBIBWOCQCGzSLUXrO/D5LO0gWHxE7YFEmEwe0uFBeDqtPGkKNOTkNjQU8vH/4W8QjLkLz5u5a58bx7l3mdtnuYOTmwi5j41bqbibBxp7O+xXPch4IdBtRxnmyfpWiBiu8uNCM7zjBrrJlI3V9O1huEFBb+XAlGMjirewL2GgA3GTLUDNtEMiMBA1CX51A810Po7zZQ0J7kStwU/f5zL2JQxvIw3cMQWIKaBFcYUE+Ukpvmc4qsGsA15Q9LH/VnKePDeWcG8Dl9dLd4NFxghEdZJxJ1ceKbsxtAjTKInv2F5B0wzilxmP91NxLPy0OIGGPxA/8tkOz/ka1Dk5JTaYKyVIzG+yeTI8/sD3kip+KJ+D2NGEgsB+DL9GIHwQd//zZQoGDKCpKoDw9yLvda2rBzaT6/lyqpzPNOgmC4YfehK/la1haFnXFdgSflOToxaBISlWQlBqDWwmkYsfhKBPYwXYXHHYFbaWIl32S5wV5MQU50aYY2Xd+DwdbhrLP1YcFjQ0NxjMFWMFxdWA6jq0iI+QEPzKNlhZ1qUi1oyUYaw0k7pzKdYw+lX+DJcsSljPqVnODkp9MEcylc42qRQzVnlwkQx6wqbKEwLzw81XwrsPo+IeHmDKtY38CId0t9iNFpBixsoUgMCehqVj30R+sLgaEMDz9VM4UO92rgwJFicI14fMxADT7Wa6slLeyqbL/VPplHs5+P+zaPMnQ85+kCIeX2qiLk4U2LFiBwP+yhJ/ytVmuoSd1xTn0ZswAsTXkMQX5fgxVwVyYZpa/Zv3mNvBslUdFAJIhaRF9NqVzZhmAKD8l3h/HtgSp/fq99tQQw24UU7q4hp7caLdsKzR8lY+E2C68Mp7Ao7d0MoBk1sKyHOcggB7QPNBAH8nFyVzXSzD0eHduI96+r4z91tZgZnLpSLlJC0iz/OrcZQjqt+OzuFiEOR0mAf8g6KACs60YAsRx0ITRsou3EodwNC4gVkST9RcfU/eoDPFJkSEewP3TwDix9ySeWf2+sHHJbHgh+tjuUQzm/WJVvluJu+lnDOZQa20Q27jIoDKlmHwIcyCW5znYijgKu9kaCYnQaP8PXDsGSgwW0URQM7nWUc8bgegQ1002/Gep1QR7NfxnnbkRzA0eIs7QbkZUfbDBQUq532I5yb+H8lGaZooTb2GAAAAAElFTkSuQmCC';\nexport { filterBase64Value, insightDumpToExecutionDump, mouseLoading, mousePointer, timeStr };\n","'use client';\nimport \"./player.css\";\nimport { mousePointer } from \"../utils.mjs\";\nimport { paramStr, typeStr } from \"@midscene/web/ui-utils\";\nimport { treeToList } from \"@midscene/shared/extractor\";\nconst stillDuration = 900;\nconst actionSpinningPointerDuration = 300;\nconst stillAfterInsightDuration = 300;\nconst locateDuration = 800;\nconst actionDuration = 1000;\nconst clearInsightDuration = 200;\nconst cameraStateForRect = (rect, imageWidth, imageHeight)=>{\n const canvasRatio = imageWidth / imageHeight;\n const rectRatio = rect.width / rect.height;\n let rectWidthOnPage;\n rectWidthOnPage = rectRatio >= canvasRatio ? rect.width : rect.height / imageHeight * imageWidth;\n const cameraPaddingRatio = rectWidthOnPage > 400 ? 0.1 : rectWidthOnPage > 50 ? 0.2 : 0.3;\n const cameraWidth = Math.min(imageWidth, rectWidthOnPage + imageWidth * cameraPaddingRatio * 2);\n const cameraHeight = imageHeight / imageWidth * cameraWidth;\n let left = Math.min(rect.left - imageWidth * cameraPaddingRatio, imageWidth - cameraWidth);\n left = Math.max(left, 0);\n let top = Math.min(rect.top - imageHeight * cameraPaddingRatio, imageHeight - cameraHeight);\n top = Math.max(top, 0);\n return {\n left: Math.round(left),\n top: Math.round(top),\n width: Math.round(cameraWidth)\n };\n};\nconst mergeTwoCameraState = (cameraState1, cameraState2)=>{\n const newLeft = Math.min(cameraState1.left, cameraState2.left);\n const newTop = Math.min(cameraState1.top, cameraState2.top);\n const newRight = Math.max(cameraState1.left + cameraState1.width, cameraState2.left + cameraState2.width);\n const newWidth = newRight - newLeft;\n return {\n left: newLeft,\n top: newTop,\n width: newWidth\n };\n};\nconst allScriptsFromDump = (dump)=>{\n let width;\n let height;\n let sdkVersion;\n let modelName;\n let modelDescription;\n dump.executions.forEach((execution)=>{\n if (execution.sdkVersion) sdkVersion = execution.sdkVersion;\n if (execution.model_name) modelName = execution.model_name;\n if (execution.model_description) modelDescription = execution.model_description;\n execution.tasks.forEach((task)=>{\n var _insightTask_pageContext_size, _insightTask_pageContext;\n const insightTask = task;\n if (null == (_insightTask_pageContext = insightTask.pageContext) ? void 0 : null == (_insightTask_pageContext_size = _insightTask_pageContext.size) ? void 0 : _insightTask_pageContext_size.width) {\n width = insightTask.pageContext.size.width;\n height = insightTask.pageContext.size.height;\n }\n });\n });\n if (!width || !height) {\n console.warn('width or height is missing in dump file');\n return {\n scripts: [],\n sdkVersion,\n modelName,\n modelDescription\n };\n }\n const allScripts = [];\n dump.executions.forEach((execution)=>{\n const scripts = generateAnimationScripts(execution, -1, width, height);\n if (scripts) allScripts.push(...scripts);\n });\n const allScriptsWithoutIntermediateDoneFrame = allScripts.filter((script, index)=>{\n if (index !== allScripts.length - 1 && 'Done' === script.title) return false;\n return true;\n });\n return {\n scripts: allScriptsWithoutIntermediateDoneFrame,\n width,\n height,\n sdkVersion,\n modelName,\n modelDescription\n };\n};\nconst generateAnimationScripts = (execution, task, imageWidth, imageHeight)=>{\n if (!execution || !execution.tasks.length) return null;\n if (0 === imageWidth || 0 === imageHeight) return null;\n let tasksIncluded = [];\n if (-1 === task) tasksIncluded = execution.tasks;\n else {\n const startIndex = execution.tasks.findIndex((t)=>t === task);\n if (-1 === startIndex) {\n console.error(\"task not found, cannot generate animation scripts\");\n return null;\n }\n if (startIndex === execution.tasks.length - 1) return null;\n for(let i = startIndex; i < execution.tasks.length; i++){\n if (i > startIndex && 'Planning' === execution.tasks[i].type) break;\n tasksIncluded.push(execution.tasks[i]);\n }\n }\n if (0 === tasksIncluded.length) return null;\n const fullPageCameraState = cameraStateForRect({\n left: 0,\n top: 0,\n width: imageWidth,\n height: imageHeight\n }, imageWidth, imageHeight);\n const pointerScript = (img, title, subTitle)=>({\n type: 'pointer',\n img,\n duration: 0,\n title,\n subTitle\n });\n const scripts = [];\n let insightCameraState;\n let currentCameraState = fullPageCameraState;\n let insightOnTop = false;\n const taskCount = tasksIncluded.length;\n let initSubTitle = '';\n let errorStateFlag = false;\n tasksIncluded.forEach((task, index)=>{\n if (errorStateFlag) return;\n if (0 === index) initSubTitle = paramStr(task);\n if ('Planning' === task.type) {\n const planningTask = task;\n if (planningTask.recorder && planningTask.recorder.length > 0) {\n var _planningTask_recorder_, _planningTask_recorder;\n scripts.push({\n type: 'img',\n img: null == (_planningTask_recorder = planningTask.recorder) ? void 0 : null == (_planningTask_recorder_ = _planningTask_recorder[0]) ? void 0 : _planningTask_recorder_.screenshot,\n camera: 0 === index ? fullPageCameraState : void 0,\n duration: stillDuration,\n title: typeStr(task),\n subTitle: paramStr(task)\n });\n }\n } else if ('Insight' === task.type && 'Locate' === task.subType) {\n var _insightTask_output;\n const insightTask = task;\n const resultElement = null == (_insightTask_output = insightTask.output) ? void 0 : _insightTask_output.element;\n const title = typeStr(task);\n const subTitle = paramStr(task);\n if (null == resultElement ? void 0 : resultElement.rect) insightCameraState = {\n ...cameraStateForRect(resultElement.rect, imageWidth, imageHeight),\n pointerLeft: resultElement.center[0],\n pointerTop: resultElement.center[1]\n };\n const context = insightTask.pageContext;\n if (null == context ? void 0 : context.screenshotBase64) {\n var _insightTask_log, _insightTask_output1, _insightDump_taskInfo;\n const insightDump = null == (_insightTask_log = insightTask.log) ? void 0 : _insightTask_log.dump;\n const insightContentLength = context.tree ? treeToList(context.tree).length : 0;\n if (context.screenshotBase64) scripts.push({\n type: 'img',\n img: context.screenshotBase64,\n duration: stillAfterInsightDuration,\n title,\n subTitle\n });\n let cameraState;\n cameraState = currentCameraState === fullPageCameraState ? void 0 : insightCameraState ? mergeTwoCameraState(currentCameraState, insightCameraState) : void 0;\n scripts.push({\n type: 'insight',\n img: context.screenshotBase64,\n context: context,\n camera: cameraState,\n highlightElement: (null == (_insightTask_output1 = insightTask.output) ? void 0 : _insightTask_output1.element) || void 0,\n searchArea: null == insightDump ? void 0 : null == (_insightDump_taskInfo = insightDump.taskInfo) ? void 0 : _insightDump_taskInfo.searchArea,\n duration: insightContentLength > 20 ? locateDuration : 0.5 * locateDuration,\n insightCameraDuration: locateDuration,\n title,\n subTitle\n });\n scripts.push({\n type: 'sleep',\n duration: stillAfterInsightDuration,\n title,\n subTitle\n });\n insightOnTop = true;\n }\n } else if ('Action' === task.type && 'FalsyConditionStatement' !== task.subType) {\n var _task_recorder_, _task_recorder, _task_recorder_1, _task_recorder1;\n const title = typeStr(task);\n const subTitle = paramStr(task);\n scripts.push(pointerScript(mousePointer, title, subTitle));\n currentCameraState = null != insightCameraState ? insightCameraState : fullPageCameraState;\n scripts.push({\n type: 'img',\n img: null == (_task_recorder = task.recorder) ? void 0 : null == (_task_recorder_ = _task_recorder[0]) ? void 0 : _task_recorder_.screenshot,\n duration: actionDuration,\n camera: 'Sleep' === task.subType ? fullPageCameraState : insightCameraState,\n title,\n subTitle\n });\n if (insightOnTop) {\n scripts.push({\n type: 'clear-insight',\n duration: clearInsightDuration,\n title,\n subTitle\n });\n insightOnTop = false;\n }\n const imgStillDuration = index < taskCount - 1 ? stillDuration : 0;\n if (null == (_task_recorder1 = task.recorder) ? void 0 : null == (_task_recorder_1 = _task_recorder1[1]) ? void 0 : _task_recorder_1.screenshot) {\n var _task_recorder_2, _task_recorder2;\n scripts.push({\n type: 'spinning-pointer',\n duration: actionSpinningPointerDuration,\n title,\n subTitle\n });\n scripts.push(pointerScript(mousePointer, title, subTitle));\n scripts.push({\n type: 'img',\n img: null == (_task_recorder2 = task.recorder) ? void 0 : null == (_task_recorder_2 = _task_recorder2[1]) ? void 0 : _task_recorder_2.screenshot,\n duration: imgStillDuration,\n title,\n subTitle\n });\n } else scripts.push({\n type: 'sleep',\n duration: imgStillDuration,\n title,\n subTitle\n });\n } else {\n var _task_recorder_3, _task_recorder3;\n const title = typeStr(task);\n const subTitle = paramStr(task);\n const screenshot = null == (_task_recorder3 = task.recorder) ? void 0 : null == (_task_recorder_3 = _task_recorder3[task.recorder.length - 1]) ? void 0 : _task_recorder_3.screenshot;\n if (screenshot) scripts.push({\n type: 'img',\n img: screenshot,\n duration: stillDuration,\n camera: fullPageCameraState,\n title,\n subTitle\n });\n }\n if ('finished' !== task.status) {\n errorStateFlag = true;\n const errorTitle = typeStr(task);\n const errorMsg = task.errorMessage || 'unknown error';\n const errorSubTitle = errorMsg.indexOf('NOT_IMPLEMENTED_AS_DESIGNED') > 0 ? 'Further actions cannot be performed in the current environment' : errorMsg;\n scripts.push({\n type: 'img',\n img: task.recorder && task.recorder.length > 0 ? task.recorder[task.recorder.length - 1].screenshot : '',\n camera: fullPageCameraState,\n duration: stillDuration,\n title: errorTitle,\n subTitle: errorSubTitle\n });\n return;\n }\n });\n if (!errorStateFlag) scripts.push({\n title: 'Done',\n subTitle: initSubTitle,\n type: 'img',\n duration: stillDuration,\n camera: fullPageCameraState\n });\n return scripts;\n};\nexport { allScriptsFromDump, cameraStateForRect, generateAnimationScripts, mergeTwoCameraState };\n","const elementColor = [\n '#01204E'\n];\nconst highlightColorForSearchArea = '#028391';\nconst highlightColorForElement = '#fd5907';\nfunction djb2Hash(str) {\n if (!str) str = 'unnamed';\n let hash = 5381;\n for(let i = 0; i < str.length; i++)hash = (hash << 5) + hash + str.charCodeAt(i);\n return hash >>> 0;\n}\nfunction colorForName(name) {\n const hashNumber = djb2Hash(name);\n return elementColor[hashNumber % elementColor.length];\n}\nfunction highlightColorForType(type) {\n if ('searchArea' === type) return highlightColorForSearchArea;\n return highlightColorForElement;\n}\nfunction globalThemeConfig() {\n return {\n token: {\n colorPrimary: '#2B83FF'\n },\n components: {\n Layout: {\n headerHeight: 60,\n headerPadding: '0 30px',\n headerBg: '#FFF',\n bodyBg: '#FFF'\n }\n }\n };\n}\nexport { colorForName, globalThemeConfig, highlightColorForType };\n","import { jsx } from \"react/jsx-runtime\";\nimport \"./logo.css\";\nconst LogoUrl = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/vhaeh7vhabf/Midscene.png';\nconst Logo = (param)=>{\n let { hideLogo = false } = param;\n if (hideLogo) return null;\n return /*#__PURE__*/ jsx(\"div\", {\n className: \"logo\",\n children: /*#__PURE__*/ jsx(\"a\", {\n href: \"https://midscenejs.com/\",\n target: \"_blank\",\n rel: \"noreferrer\",\n children: /*#__PURE__*/ jsx(\"img\", {\n alt: \"Midscene_logo\",\n src: \"https://lf3-static.bytednsdoc.com/obj/eden-cn/vhaeh7vhabf/Midscene.png\"\n })\n })\n });\n};\nexport { Logo, LogoUrl };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport { SettingOutlined } from \"@ant-design/icons\";\nimport { Input, Modal, Tooltip } from \"antd\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useEnvConfig } from \"./store/store.mjs\";\nfunction EnvConfig(param) {\n let { showTooltipWhenEmpty = true, showModelName = true, tooltipPlacement = 'bottom', mode = 'icon' } = param;\n const { config, configString, loadConfig, syncFromStorage } = useEnvConfig();\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [tempConfigString, setTempConfigString] = useState(configString);\n const midsceneModelName = config.MIDSCENE_MODEL_NAME;\n const componentRef = useRef(null);\n const showModal = (e)=>{\n syncFromStorage();\n setIsModalOpen(true);\n e.preventDefault();\n e.stopPropagation();\n };\n const handleOk = ()=>{\n setIsModalOpen(false);\n loadConfig(tempConfigString);\n };\n const handleCancel = ()=>{\n setIsModalOpen(false);\n };\n useEffect(()=>{\n if (isModalOpen) setTempConfigString(configString);\n }, [\n isModalOpen,\n configString\n ]);\n return /*#__PURE__*/ jsxs(\"div\", {\n style: {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '10px',\n alignItems: 'center',\n height: '100%',\n minHeight: '32px'\n },\n ref: componentRef,\n children: [\n showModelName ? midsceneModelName : null,\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Please set up your environment variables before using.\",\n placement: tooltipPlacement,\n align: {\n offset: [\n -10,\n 5\n ]\n },\n getPopupContainer: ()=>componentRef.current,\n open: isModalOpen ? false : showTooltipWhenEmpty ? 0 === Object.keys(config).length : void 0,\n children: 'icon' === mode ? /*#__PURE__*/ jsx(SettingOutlined, {\n onClick: showModal\n }) : /*#__PURE__*/ jsx(\"span\", {\n onClick: showModal,\n style: {\n color: '#006AFF',\n cursor: 'pointer'\n },\n children: \"set up\"\n })\n }),\n /*#__PURE__*/ jsxs(Modal, {\n title: \"Model Env Config\",\n open: isModalOpen,\n onOk: handleOk,\n onCancel: handleCancel,\n okText: \"Save\",\n style: {\n width: '800px',\n height: '100%',\n marginTop: '10%'\n },\n destroyOnClose: true,\n maskClosable: true,\n centered: true,\n children: [\n /*#__PURE__*/ jsx(Input.TextArea, {\n rows: 7,\n placeholder: 'OPENAI_API_KEY=sk-...\\nMIDSCENE_MODEL_NAME=gpt-4o-2024-08-06\\n...',\n value: tempConfigString,\n onChange: (e)=>setTempConfigString(e.target.value),\n style: {\n whiteSpace: 'nowrap',\n wordWrap: 'break-word'\n }\n }),\n /*#__PURE__*/ jsxs(\"div\", {\n children: [\n /*#__PURE__*/ jsx(\"p\", {\n children: \"The format is KEY=VALUE and separated by new lines.\"\n }),\n /*#__PURE__*/ jsxs(\"p\", {\n children: [\n \"These data will be saved \",\n /*#__PURE__*/ jsx(\"strong\", {\n children: \"locally in your browser\"\n }),\n \".\"\n ]\n })\n ]\n })\n ]\n })\n ]\n });\n}\nexport { EnvConfig };\n","import { create } from \"zustand\";\nvar __webpack_require__ = {};\n(()=>{\n __webpack_require__.d = (exports, definition)=>{\n for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {\n enumerable: true,\n get: definition[key]\n });\n };\n})();\n(()=>{\n __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);\n})();\n(()=>{\n __webpack_require__.r = (exports)=>{\n if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {\n value: 'Module'\n });\n Object.defineProperty(exports, '__esModule', {\n value: true\n });\n };\n})();\nvar external_zustand_namespaceObject = {};\n__webpack_require__.r(external_zustand_namespaceObject);\n__webpack_require__.d(external_zustand_namespaceObject, {\n create: ()=>create\n});\nconst { create: history_create } = external_zustand_namespaceObject;\nconst HISTORY_KEY = 'midscene-prompt-history';\nconst getHistoryFromLocalStorage = ()=>{\n const historyString = localStorage.getItem(HISTORY_KEY);\n return historyString ? JSON.parse(historyString) : [];\n};\nconst useHistoryStore = history_create((set, get)=>({\n history: getHistoryFromLocalStorage(),\n clearHistory: ()=>{\n set({\n history: []\n });\n localStorage.removeItem(HISTORY_KEY);\n },\n addHistory: (historyItem)=>{\n const newHistory = [\n historyItem,\n ...get().history.filter((h)=>h.prompt !== historyItem.prompt)\n ];\n while(newHistory.length > 10)newHistory.pop();\n set({\n history: newHistory\n });\n localStorage.setItem(HISTORY_KEY, JSON.stringify(newHistory));\n }\n }));\nexport { useHistoryStore };\n","import { jsx } from \"react/jsx-runtime\";\nimport \"react\";\nconst SvgSetting = (props)=>/*#__PURE__*/ jsx(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 27,\n height: 27,\n fill: \"none\",\n viewBox: \"0 0 27 27\",\n ...props,\n children: /*#__PURE__*/ jsx(\"path\", {\n stroke: \"#000\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeOpacity: 0.85,\n strokeWidth: 1.333,\n d: \"M19.527 8.855h-2M14.86 7.522v2.667M14.86 8.855H7.527M10.194 13.522H7.527M12.86 12.189v2.666M20.193 13.522H12.86M19.527 18.189h-2M14.86 16.855v2.667M14.86 18.189H7.527\"\n })\n });\nconst setting = SvgSetting;\nexport { setting as default };\n","import { jsx } from \"react/jsx-runtime\";\nimport \"./shiny-text.css\";\nconst ShinyText = (param)=>{\n let { text, disabled = false, speed = 5, className = '' } = param;\n const style = {\n '--animation-duration': `${speed}s`\n };\n return /*#__PURE__*/ jsx(\"div\", {\n className: `shiny-text ${disabled ? 'disabled' : ''} ${className}`,\n style: style,\n children: text\n });\n};\nconst shiny_text = ShinyText;\nexport { shiny_text as default };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport { Alert } from \"antd\";\nimport shiny_text from \"../shiny-text.mjs\";\nimport \"./index.css\";\nconst errorMessageServerNotReady = /*#__PURE__*/ jsxs(\"span\", {\n children: [\n \"Don't worry, just one more step to launch the playground server.\",\n /*#__PURE__*/ jsx(\"br\", {}),\n \"Please run one of the commands under the midscene project directory:\",\n /*#__PURE__*/ jsx(\"br\", {}),\n \"a. \",\n /*#__PURE__*/ jsx(\"strong\", {\n children: \"npx midscene-playground\"\n }),\n /*#__PURE__*/ jsx(\"br\", {}),\n \"b. \",\n /*#__PURE__*/ jsx(\"strong\", {\n children: \"npx --yes @midscene/web\"\n })\n ]\n});\nconst serverLaunchTip = function() {\n let notReadyMessage = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : errorMessageServerNotReady;\n return /*#__PURE__*/ jsx(\"div\", {\n className: \"server-tip\",\n children: /*#__PURE__*/ jsx(Alert, {\n message: \"Playground Server Not Ready\",\n description: notReadyMessage,\n type: \"warning\"\n })\n });\n};\nconst emptyResultTip = /*#__PURE__*/ jsx(\"div\", {\n className: \"result-empty-tip\",\n style: {\n textAlign: 'center'\n },\n children: /*#__PURE__*/ jsx(shiny_text, {\n disabled: true,\n text: \"The result will be shown here\"\n })\n});\nconst trackingTip = 'limit popup to current tab';\nconst deepThinkTip = 'deep think';\nexport { deepThinkTip, emptyResultTip, errorMessageServerNotReady, serverLaunchTip, trackingTip };\n","import { jsx } from \"react/jsx-runtime\";\nimport { Checkbox, Dropdown } from \"antd\";\nimport setting from \"../../icons/setting.mjs\";\nimport { useEnvConfig } from \"../store/store.mjs\";\nimport { deepThinkTip, trackingTip } from \"./playground-constants.mjs\";\nimport \"./index.css\";\nconst ConfigSelector = (param)=>{\n let { showDeepThinkOption = false, enableTracking = false } = param;\n const forceSameTabNavigation = useEnvConfig((state)=>state.forceSameTabNavigation);\n const setForceSameTabNavigation = useEnvConfig((state)=>state.setForceSameTabNavigation);\n const deepThink = useEnvConfig((state)=>state.deepThink);\n const setDeepThink = useEnvConfig((state)=>state.setDeepThink);\n if (!enableTracking && !showDeepThinkOption) return null;\n const configItems = buildConfigItems();\n return /*#__PURE__*/ jsx(\"div\", {\n className: \"selector-trigger\",\n children: /*#__PURE__*/ jsx(Dropdown, {\n menu: {\n items: configItems\n },\n trigger: [\n 'click'\n ],\n children: /*#__PURE__*/ jsx(setting, {\n width: 24,\n height: 24\n })\n })\n });\n function buildConfigItems() {\n const items = [];\n if (enableTracking) items.push({\n label: /*#__PURE__*/ jsx(Checkbox, {\n onChange: (e)=>setForceSameTabNavigation(e.target.checked),\n checked: forceSameTabNavigation,\n children: trackingTip\n }),\n key: 'track-config'\n });\n if (showDeepThinkOption) items.push({\n label: /*#__PURE__*/ jsx(Checkbox, {\n onChange: (e)=>{\n setDeepThink(e.target.checked);\n },\n checked: deepThink,\n children: deepThinkTip\n }),\n key: 'deep-think-config'\n });\n return items;\n }\n};\nexport { ConfigSelector };\n","import { jsx } from \"react/jsx-runtime\";\nimport \"react\";\nconst SvgClose = (props)=>/*#__PURE__*/ jsx(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 18,\n height: 16,\n fill: \"none\",\n viewBox: \"0 0 18 16\",\n ...props,\n children: /*#__PURE__*/ jsx(\"path\", {\n stroke: \"#333\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeWidth: 1.333,\n d: \"m3.124 2.667 11.162 10.666M3.124 13.333 14.286 2.667\"\n })\n });\nconst icons_close = SvgClose;\nexport { icons_close as default };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport \"react\";\nconst SvgHistory = (props)=>/*#__PURE__*/ jsxs(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 25,\n height: 25,\n fill: \"none\",\n viewBox: \"0 0 25 25\",\n ...props,\n children: [\n /*#__PURE__*/ jsx(\"path\", {\n stroke: \"#000\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeOpacity: 0.85,\n strokeWidth: 1.33,\n d: \"M6.63 9.021c-2.862 6.126 2.197 10.501 6.063 10.501a7 7 0 1 0-6.063-10.5\"\n }),\n /*#__PURE__*/ jsx(\"path\", {\n stroke: \"#000\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeOpacity: 0.85,\n strokeWidth: 1.33,\n d: \"M12.695 8.322v4.203l2.967 2.968\"\n })\n ]\n });\nconst icons_history = SvgHistory;\nexport { icons_history as default };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport \"react\";\nconst SvgMagnifyingGlass = (props)=>/*#__PURE__*/ jsxs(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 19,\n height: 19,\n fill: \"none\",\n viewBox: \"0 0 19 19\",\n ...props,\n children: [\n /*#__PURE__*/ jsxs(\"g\", {\n stroke: \"#000\",\n strokeLinejoin: \"round\",\n strokeOpacity: 0.65,\n strokeWidth: 1.5,\n clipPath: \"url(#magnifying-glass_svg__a)\",\n children: [\n /*#__PURE__*/ jsx(\"path\", {\n d: \"M8.397 14.29a6.375 6.375 0 1 0 0-12.75 6.375 6.375 0 0 0 0 12.75Z\"\n }),\n /*#__PURE__*/ jsx(\"path\", {\n strokeLinecap: \"round\",\n d: \"M10.519 5.42a3 3 0 0 0-2.122-.88 3 3 0 0 0-2.121.88M12.98 12.499l3.182 3.182\"\n })\n ]\n }),\n /*#__PURE__*/ jsx(\"defs\", {\n children: /*#__PURE__*/ jsx(\"clipPath\", {\n id: \"magnifying-glass_svg__a\",\n children: /*#__PURE__*/ jsx(\"path\", {\n fill: \"#fff\",\n d: \"M.522.04h18v18h-18z\"\n })\n })\n })\n ]\n });\nconst magnifying_glass = SvgMagnifyingGlass;\nexport { magnifying_glass as default };\n","import { Fragment, jsx, jsxs } from \"react/jsx-runtime\";\nimport { Button, Input, Modal, Typography } from \"antd\";\nimport { useMemo, useState } from \"react\";\nimport icons_close from \"../../icons/close.mjs\";\nimport icons_history from \"../../icons/history.mjs\";\nimport magnifying_glass from \"../../icons/magnifying-glass.mjs\";\nimport { useHistoryStore } from \"../store/history.mjs\";\nimport \"./index.css\";\nconst { Text } = Typography;\nconst HistorySelector = (param)=>{\n let { onSelect } = param;\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [searchText, setSearchText] = useState('');\n const history = useHistoryStore((state)=>state.history);\n const clearHistory = useHistoryStore((state)=>state.clearHistory);\n const groupedHistory = useMemo(()=>{\n const now = Date.now();\n const sevenDaysAgo = now - 604800000;\n const oneYearAgo = now - 31536000000;\n const filteredHistory = history.filter((item)=>item.prompt.toLowerCase().includes(searchText.toLowerCase()));\n const groups = {\n recent7Days: filteredHistory.filter((item)=>item.timestamp >= sevenDaysAgo),\n recent1Year: filteredHistory.filter((item)=>item.timestamp < sevenDaysAgo && item.timestamp >= oneYearAgo),\n older: filteredHistory.filter((item)=>item.timestamp < oneYearAgo)\n };\n return groups;\n }, [\n history,\n searchText\n ]);\n const handleHistoryClick = (item)=>{\n onSelect(item);\n setIsModalOpen(false);\n };\n const handleClearHistory = ()=>{\n clearHistory();\n setSearchText('');\n setIsModalOpen(false);\n };\n const renderHistoryGroup = (title, items)=>{\n if (0 === items.length) return null;\n return /*#__PURE__*/ jsxs(\"div\", {\n className: \"history-group\",\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"history-group-title\",\n children: title\n }),\n items.map((item, index)=>/*#__PURE__*/ jsx(\"div\", {\n className: \"history-item\",\n onClick: ()=>handleHistoryClick(item),\n children: item.prompt\n }, `${item.timestamp}-${index}`))\n ]\n }, title);\n };\n return /*#__PURE__*/ jsxs(Fragment, {\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"selector-trigger\",\n onClick: ()=>setIsModalOpen(true),\n children: /*#__PURE__*/ jsx(icons_history, {\n width: 24,\n height: 24\n })\n }),\n /*#__PURE__*/ jsx(Modal, {\n open: isModalOpen,\n onCancel: ()=>setIsModalOpen(false),\n footer: null,\n width: \"100%\",\n closable: false,\n centered: false,\n transitionName: \"\",\n maskTransitionName: \"\",\n style: {\n margin: 0,\n padding: 0,\n maxWidth: 'none',\n top: 'auto',\n bottom: 0\n },\n styles: {\n wrapper: {\n alignItems: 'flex-end',\n justifyContent: 'center',\n paddingBottom: 0,\n display: 'flex'\n },\n body: {\n height: '70vh',\n padding: 0,\n margin: 0\n },\n content: {\n height: '70vh',\n borderRadius: '12px 12px 0 0',\n margin: 0,\n padding: 0,\n marginBottom: 0,\n position: 'fixed',\n bottom: 0,\n left: 0,\n right: 0\n }\n },\n maskClosable: true,\n destroyOnClose: true,\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"history-modal-container\",\n children: [\n /*#__PURE__*/ jsxs(\"div\", {\n className: \"history-modal-header\",\n children: [\n /*#__PURE__*/ jsxs(Text, {\n strong: true,\n style: {\n fontSize: '16px'\n },\n children: [\n \"History (\",\n history.length,\n \")\"\n ]\n }),\n /*#__PURE__*/ jsx(Button, {\n size: \"small\",\n type: \"text\",\n icon: /*#__PURE__*/ jsx(icons_close, {\n width: 16,\n height: 16\n }),\n onClick: ()=>setIsModalOpen(false),\n className: \"close-button\"\n })\n ]\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"history-search-section\",\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"search-input-wrapper\",\n children: [\n /*#__PURE__*/ jsx(Input, {\n placeholder: \"Search\",\n value: searchText,\n onChange: (e)=>setSearchText(e.target.value),\n prefix: /*#__PURE__*/ jsx(magnifying_glass, {\n width: 18,\n height: 18\n }),\n className: \"search-input\",\n allowClear: true\n }),\n /*#__PURE__*/ jsx(Button, {\n type: \"link\",\n onClick: handleClearHistory,\n className: \"clear-button\",\n disabled: 0 === history.length,\n children: \"Clear\"\n })\n ]\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"history-content\",\n children: 0 === history.length ? /*#__PURE__*/ jsx(\"div\", {\n className: \"no-results\",\n children: /*#__PURE__*/ jsx(Text, {\n type: \"secondary\",\n children: \"No history record\"\n })\n }) : /*#__PURE__*/ jsxs(Fragment, {\n children: [\n renderHistoryGroup('Last 7 days', groupedHistory.recent7Days),\n renderHistoryGroup('Last 1 year', groupedHistory.recent1Year),\n renderHistoryGroup('Earlier', groupedHistory.older),\n searchText && 0 === groupedHistory.recent7Days.length && 0 === groupedHistory.recent1Year.length && 0 === groupedHistory.older.length && /*#__PURE__*/ jsx(\"div\", {\n className: \"no-results\",\n children: /*#__PURE__*/ jsx(Text, {\n type: \"secondary\",\n children: \"No matching history record\"\n })\n })\n ]\n })\n })\n ]\n })\n })\n ]\n });\n};\nexport { HistorySelector };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport { BorderOutlined, SendOutlined } from \"@ant-design/icons\";\nimport { Button, Form, Input, Radio, Space, Tooltip } from \"antd\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useHistoryStore } from \"../store/history.mjs\";\nimport { ConfigSelector } from \"./ConfigSelector.mjs\";\nimport { HistorySelector } from \"./HistorySelector.mjs\";\nimport { actionNameForType, getPlaceholderForType } from \"./playground-utils.mjs\";\nimport \"./index.css\";\nconst { TextArea } = Input;\nconst PromptInput = (param)=>{\n let { runButtonEnabled, form, serviceMode, selectedType, dryMode, stoppable, loading, onRun, onStop, clearPromptAfterRun = true } = param;\n const [hoveringSettings, setHoveringSettings] = useState(false);\n const [promptValue, setPromptValue] = useState('');\n const placeholder = getPlaceholderForType(selectedType);\n const textAreaRef = useRef(null);\n const history = useHistoryStore((state)=>state.history);\n const addHistory = useHistoryStore((state)=>state.addHistory);\n const lastHistory = history[0];\n useEffect(()=>{\n if (lastHistory) {\n form.setFieldsValue({\n type: lastHistory.type || 'aiAction',\n prompt: lastHistory.prompt || ''\n });\n setPromptValue(lastHistory.prompt || '');\n } else {\n form.setFieldsValue({\n type: 'aiAction',\n prompt: ''\n });\n setPromptValue('');\n }\n }, []);\n const handleSelectHistory = useCallback((historyItem)=>{\n form.setFieldsValue({\n prompt: historyItem.prompt,\n type: historyItem.type\n });\n setPromptValue(historyItem.prompt);\n }, [\n form\n ]);\n const handlePromptChange = useCallback((e)=>{\n const value = e.target.value;\n setPromptValue(value);\n form.setFieldValue('prompt', value);\n }, [\n form\n ]);\n const isRunButtonEnabled = runButtonEnabled && promptValue.trim().length > 0;\n const handleRunWithHistory = useCallback(()=>{\n const values = form.getFieldsValue();\n if (values.prompt) addHistory({\n type: values.type,\n prompt: values.prompt,\n timestamp: Date.now()\n });\n onRun();\n if (clearPromptAfterRun) {\n setPromptValue('');\n form.setFieldValue('prompt', '');\n }\n }, [\n form,\n addHistory,\n onRun\n ]);\n const handleKeyDown = useCallback((e)=>{\n if ('Enter' === e.key && e.metaKey && isRunButtonEnabled) {\n handleRunWithHistory();\n e.preventDefault();\n e.stopPropagation();\n } else if ('Enter' === e.key) setTimeout(()=>{\n if (textAreaRef.current) {\n const textarea = textAreaRef.current.resizableTextArea.textArea;\n const selectionStart = textarea.selectionStart;\n const value = textarea.value;\n const lastNewlineIndex = value.lastIndexOf('\\n');\n const isAtLastLine = -1 === lastNewlineIndex || selectionStart > lastNewlineIndex;\n if (isAtLastLine) textarea.scrollTop = textarea.scrollHeight;\n }\n }, 0);\n }, [\n handleRunWithHistory,\n isRunButtonEnabled\n ]);\n const handleMouseEnter = useCallback(()=>{\n setHoveringSettings(true);\n }, []);\n const handleMouseLeave = useCallback(()=>{\n setHoveringSettings(false);\n }, []);\n const renderActionButton = useCallback(()=>{\n const runButton = (text)=>/*#__PURE__*/ jsx(Button, {\n type: \"primary\",\n icon: /*#__PURE__*/ jsx(SendOutlined, {}),\n style: {\n borderRadius: 20,\n zIndex: 999\n },\n onClick: handleRunWithHistory,\n disabled: !isRunButtonEnabled,\n loading: loading,\n children: text\n });\n if (dryMode) return 'aiAction' === selectedType ? /*#__PURE__*/ jsx(Tooltip, {\n title: \"Start executing until some interaction actions need to be performed. You can see the process of planning and locating.\",\n children: runButton('Dry Run')\n }) : runButton('Run');\n if (stoppable) return /*#__PURE__*/ jsx(Button, {\n icon: /*#__PURE__*/ jsx(BorderOutlined, {}),\n onClick: onStop,\n style: {\n borderRadius: 20,\n zIndex: 999\n },\n children: \"Stop\"\n });\n return runButton('Run');\n }, [\n dryMode,\n loading,\n handleRunWithHistory,\n onStop,\n isRunButtonEnabled,\n selectedType,\n stoppable\n ]);\n return /*#__PURE__*/ jsxs(\"div\", {\n className: \"prompt-input-wrapper\",\n children: [\n /*#__PURE__*/ jsxs(Space, {\n className: \"mode-radio-group-wrapper\",\n children: [\n /*#__PURE__*/ jsx(Form.Item, {\n name: \"type\",\n style: {\n margin: 0\n },\n children: /*#__PURE__*/ jsxs(Radio.Group, {\n buttonStyle: \"solid\",\n disabled: !runButtonEnabled,\n className: \"mode-radio-group\",\n children: [\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Auto Planning: plan the steps and execute\",\n children: /*#__PURE__*/ jsx(Radio.Button, {\n value: \"aiAction\",\n children: actionNameForType('aiAction')\n })\n }),\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Extract data directly from the UI\",\n children: /*#__PURE__*/ jsx(Radio.Button, {\n value: \"aiQuery\",\n children: actionNameForType('aiQuery')\n })\n }),\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Understand the UI and determine if the assertion is true\",\n children: /*#__PURE__*/ jsx(Radio.Button, {\n value: \"aiAssert\",\n children: actionNameForType('aiAssert')\n })\n }),\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Instant Action: click something\",\n children: /*#__PURE__*/ jsx(Radio.Button, {\n value: \"aiTap\",\n children: actionNameForType('aiTap')\n })\n })\n ]\n })\n }),\n /*#__PURE__*/ jsxs(\"div\", {\n className: \"action-icons\",\n children: [\n /*#__PURE__*/ jsx(HistorySelector, {\n onSelect: handleSelectHistory\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: hoveringSettings ? 'settings-wrapper settings-wrapper-hover' : 'settings-wrapper',\n onMouseEnter: handleMouseEnter,\n onMouseLeave: handleMouseLeave,\n children: /*#__PURE__*/ jsx(ConfigSelector, {\n enableTracking: 'In-Browser-Extension' === serviceMode,\n showDeepThinkOption: 'aiTap' === selectedType\n })\n })\n ]\n })\n ]\n }),\n /*#__PURE__*/ jsxs(\"div\", {\n className: `main-side-console-input ${!runButtonEnabled ? 'disabled' : ''} ${loading ? 'loading' : ''}`,\n children: [\n /*#__PURE__*/ jsx(Form.Item, {\n name: \"prompt\",\n style: {\n margin: 0\n },\n children: /*#__PURE__*/ jsx(TextArea, {\n className: \"main-side-console-input-textarea\",\n disabled: !runButtonEnabled,\n rows: 4,\n placeholder: placeholder,\n autoFocus: true,\n onKeyDown: handleKeyDown,\n onChange: handlePromptChange,\n value: promptValue,\n ref: textAreaRef\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"form-controller-wrapper\",\n children: renderActionButton()\n })\n ]\n })\n ]\n });\n};\nexport { PromptInput };\n","'use client';\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nimport \"pixi.js/unsafe-eval\";\nimport { Checkbox } from \"antd\";\nimport { Application, Container, Graphics, Rectangle, Sprite, Text, Texture } from \"pixi.js\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { colorForName, highlightColorForType } from \"./color.mjs\";\nimport \"./blackboard.css\";\nimport { treeToList } from \"@midscene/shared/extractor\";\nimport { DropShadowFilter } from \"pixi-filters\";\nimport { useBlackboardPreference } from \"./store/store.mjs\";\nconst itemFillAlpha = 0.4;\nconst highlightAlpha = 0.4;\nconst pointRadius = 10;\nconst pointMarkForItem = (point, type)=>{\n const [x, y] = point;\n const themeColor = highlightColorForType('element');\n const graphics = new Graphics();\n graphics.beginFill(themeColor, itemFillAlpha);\n graphics.drawCircle(x, y, pointRadius);\n graphics.endFill();\n return graphics;\n};\nconst rectMarkForItem = (rect, name, type)=>{\n const { left, top, width, height } = rect;\n let themeColor;\n themeColor = 'element' === type ? colorForName(name) : 'searchArea' === type ? highlightColorForType('searchArea') : highlightColorForType('element');\n const alpha = 'highlight' === type ? highlightAlpha : itemFillAlpha;\n const graphics = new Graphics();\n graphics.beginFill(themeColor, alpha);\n graphics.lineStyle(1, themeColor, 1);\n graphics.drawRect(left, top, width, height);\n graphics.endFill();\n const dropShadowFilter = new DropShadowFilter({\n blur: 2,\n quality: 3,\n alpha: 0.4,\n offset: {\n x: 4,\n y: 4\n },\n color: 0x333333\n });\n graphics.filters = [\n dropShadowFilter\n ];\n const nameFontSize = 18;\n if (!name) return [\n graphics\n ];\n const texts = new Text(name, {\n fontSize: nameFontSize,\n fill: 0x0\n });\n texts.x = left;\n texts.y = Math.max(top - (nameFontSize + 4), 0);\n return [\n graphics,\n texts\n ];\n};\nconst Blackboard = (props)=>{\n const highlightElements = props.highlightElements || [];\n const highlightIds = highlightElements.map((e)=>e.id);\n const highlightRect = props.highlightRect;\n const highlightPoints = props.highlightPoints;\n const context = props.uiContext;\n const { size, screenshotBase64 } = context;\n const screenWidth = size.width;\n const screenHeight = size.height;\n const domRef = useRef(null);\n const app = useMemo(()=>new Application(), []);\n const [appInitialed, setAppInitialed] = useState(false);\n const highlightContainer = useMemo(()=>new Container(), []);\n const elementMarkContainer = useMemo(()=>new Container(), []);\n const [hoverElement, setHoverElement] = useState(null);\n const pixiBgRef = useRef(void 0);\n const { markerVisible, setMarkerVisible, elementsVisible, setTextsVisible } = useBlackboardPreference();\n useEffect(()=>{\n Promise.resolve((async ()=>{\n if (!domRef.current || !screenWidth) return;\n await app.init({\n width: screenWidth,\n height: screenHeight,\n background: 0xffffff\n });\n const canvasEl = domRef.current;\n domRef.current.appendChild(app.canvas);\n const { clientWidth } = domRef.current.parentElement;\n const targetHeight = 0.6 * window.innerHeight;\n const viewportRatio = clientWidth / targetHeight;\n if (screenWidth / screenHeight <= viewportRatio) {\n const ratio = targetHeight / screenHeight;\n canvasEl.style.width = `${Math.floor(screenWidth * ratio)}px`;\n canvasEl.style.height = `${Math.floor(screenHeight * ratio)}px`;\n }\n app.stage.addChild(highlightContainer);\n app.stage.addChild(elementMarkContainer);\n setAppInitialed(true);\n })());\n return ()=>{\n console.log('will destroy');\n try {\n app.destroy(true, {\n children: true,\n texture: true\n });\n } catch (e) {\n console.warn('destroy failed', e);\n }\n };\n }, [\n app,\n screenWidth,\n screenHeight\n ]);\n useEffect(()=>{\n if (!appInitialed) return;\n app.stage.eventMode = 'static';\n app.stage.hitArea = new Rectangle(0, 0, screenWidth, screenHeight);\n const clickHandler = (event)=>{\n var _props_onCanvasClick;\n console.log('pixi click', event);\n const { x, y } = event.data.global;\n null == (_props_onCanvasClick = props.onCanvasClick) || _props_onCanvasClick.call(props, [\n Math.round(x),\n Math.round(y)\n ]);\n };\n app.stage.on('click', clickHandler);\n return ()=>{\n var _app_stage;\n null == app || null == (_app_stage = app.stage) || _app_stage.off('click');\n };\n }, [\n appInitialed,\n props.onCanvasClick,\n screenWidth,\n screenHeight\n ]);\n useEffect(()=>{\n if (!appInitialed) return;\n const img = new Image();\n img.onload = ()=>{\n if (!app.stage) return;\n const screenshotTexture = Texture.from(img);\n const backgroundSprite = new Sprite(screenshotTexture);\n backgroundSprite.x = 0;\n backgroundSprite.y = 0;\n backgroundSprite.width = screenWidth;\n backgroundSprite.height = screenHeight;\n backgroundSprite.eventMode = 'passive';\n app.stage.addChildAt(backgroundSprite, 0);\n pixiBgRef.current = backgroundSprite;\n };\n img.onerror = (e)=>{\n console.error('load screenshot failed', e);\n };\n img.src = screenshotBase64;\n }, [\n app.stage,\n appInitialed,\n screenWidth,\n screenHeight\n ]);\n const { highlightElementRects } = useMemo(()=>{\n const highlightElementRects = [];\n highlightContainer.removeChildren();\n elementMarkContainer.removeChildren();\n highlightContainer.eventMode = 'passive';\n elementMarkContainer.eventMode = 'passive';\n if (highlightRect) {\n const [graphics] = rectMarkForItem(highlightRect, 'Search Area', 'searchArea');\n highlightContainer.addChild(graphics);\n }\n if (highlightElements.length) highlightElements.forEach((element)=>{\n const { rect, content, id } = element;\n const [graphics] = rectMarkForItem(rect, content, 'highlight');\n highlightContainer.addChild(graphics);\n });\n if (null == highlightPoints ? void 0 : highlightPoints.length) highlightPoints.forEach((point)=>{\n const graphics = pointMarkForItem(point, 'highlightPoint');\n highlightContainer.addChild(graphics);\n });\n const elements = treeToList(context.tree);\n elements.forEach((element)=>{\n const { rect, content, id } = element;\n const ifHighlight = highlightIds.includes(id) || (null == hoverElement ? void 0 : hoverElement.id) === id;\n if (ifHighlight) return;\n const [graphics] = rectMarkForItem(rect, content, 'element');\n elementMarkContainer.addChild(graphics);\n });\n elementMarkContainer.visible = elementsVisible;\n return {\n highlightElementRects\n };\n }, [\n app,\n appInitialed,\n highlightElements,\n context.tree,\n hoverElement,\n highlightRect,\n highlightPoints\n ]);\n const onSetElementsVisible = (e)=>{\n setTextsVisible(e.target.checked);\n elementMarkContainer.visible = e.target.checked;\n };\n let bottomTipA = null;\n if (1 === highlightElementRects.length) bottomTipA = /*#__PURE__*/ jsx(\"div\", {\n className: \"bottom-tip\",\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"bottom-tip-item\",\n children: [\n \"Element: \",\n JSON.stringify(highlightElementRects[0])\n ]\n })\n });\n else if (highlightElementRects.length > 1) bottomTipA = /*#__PURE__*/ jsx(\"div\", {\n className: \"bottom-tip\",\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"bottom-tip-item\",\n children: [\n \"Element: \",\n JSON.stringify(highlightElementRects)\n ]\n })\n });\n return /*#__PURE__*/ jsxs(\"div\", {\n className: \"blackboard\",\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"blackboard-main-content\",\n style: {\n width: '100%'\n },\n ref: domRef\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"blackboard-filter\",\n style: {\n display: props.hideController ? 'none' : 'block'\n },\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"overlay-control\",\n children: /*#__PURE__*/ jsx(Checkbox, {\n checked: elementsVisible,\n onChange: onSetElementsVisible,\n children: \"Elements\"\n })\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"bottom-tip\",\n style: {\n display: props.hideController ? 'none' : 'block'\n },\n children: bottomTipA\n })\n ]\n });\n};\nconst blackboard = Blackboard;\nexport { Blackboard, blackboard as default, pointMarkForItem, rectMarkForItem };\n","import \"pixi.js/unsafe-eval\";\nimport { Assets } from \"pixi.js\";\nconst globalTextureMap = new Map();\nconst loadTexture = async (img)=>{\n if (globalTextureMap.has(img)) return;\n return Assets.load(img).then((texture)=>{\n globalTextureMap.set(img, texture);\n });\n};\nconst getTextureFromCache = (name)=>globalTextureMap.get(name);\nconst getTexture = async (name)=>{\n if (globalTextureMap.has(name)) return globalTextureMap.get(name);\n await loadTexture(name);\n return globalTextureMap.get(name);\n};\nexport { getTexture, getTextureFromCache, loadTexture };\n","'use client';\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nimport \"pixi.js/unsafe-eval\";\nimport { Application, Container, Sprite } from \"pixi.js\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport \"./player.css\";\nimport { mouseLoading, mousePointer } from \"../utils.mjs\";\nimport { CaretRightOutlined, DownloadOutlined, ExportOutlined, LoadingOutlined } from \"@ant-design/icons\";\nimport { treeToList } from \"@midscene/shared/extractor\";\nimport { Spin, Tooltip } from \"antd\";\nimport { rectMarkForItem } from \"./blackboard.mjs\";\nimport { getTextureFromCache, loadTexture } from \"./pixi-loader.mjs\";\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst canvasPaddingLeft = 0;\nconst canvasPaddingTop = 0;\nconst cubicBezier = (t, p0, p1, p2, p3)=>{\n const t2 = 1 - t;\n return p0 * t2 * t2 * t2 + 3 * p1 * t * t2 * t2 + 3 * p2 * t * t * t2 + p3 * t * t * t;\n};\nconst cubicImage = (t)=>linear(t);\nconst cubicInsightElement = (t)=>cubicBezier(t, 0, 0.5, 0.5, 1);\nconst cubicMouse = (t)=>linear(t);\nconst linear = (t)=>t;\nconst sleep = (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));\nconst ERROR_FRAME_CANCEL = 'frame cancel (this is an error on purpose)';\nconst frameKit = ()=>{\n let cancelFlag = false;\n return {\n frame: (callback)=>{\n if (cancelFlag) throw new Error(ERROR_FRAME_CANCEL);\n requestAnimationFrame(()=>{\n if (cancelFlag) throw new Error(ERROR_FRAME_CANCEL);\n callback(performance.now());\n });\n },\n timeout: (callback, ms)=>{\n if (cancelFlag) throw new Error(ERROR_FRAME_CANCEL);\n setTimeout(()=>{\n if (cancelFlag) throw new Error(ERROR_FRAME_CANCEL);\n callback();\n }, ms);\n },\n cancel: ()=>{\n cancelFlag = true;\n }\n };\n};\nconst singleElementFadeInDuration = 80;\nconst LAYER_ORDER_IMG = 0;\nconst LAYER_ORDER_INSIGHT = 1;\nconst LAYER_ORDER_POINTER = 2;\nconst LAYER_ORDER_SPINNING_POINTER = 3;\nconst downloadReport = (content)=>{\n const blob = new Blob([\n content\n ], {\n type: 'text/html'\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'midscene_report.html';\n a.click();\n};\nclass RecordingSession {\n start() {\n const stream = this.canvas.captureStream(60);\n const mediaRecorder = new MediaRecorder(stream, {\n mimeType: 'video/webm'\n });\n mediaRecorder.ondataavailable = (event)=>{\n if (event.data.size > 0) this.chunks.push(event.data);\n };\n this.mediaRecorder = mediaRecorder;\n this.recording = true;\n return this.mediaRecorder.start();\n }\n stop() {\n var _this_mediaRecorder;\n if (!this.recording || !this.mediaRecorder) return void console.warn('not recording');\n this.mediaRecorder.onstop = ()=>{\n const blob = new Blob(this.chunks, {\n type: 'video/webm'\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'midscene_replay.webm';\n a.click();\n URL.revokeObjectURL(url);\n };\n null == (_this_mediaRecorder = this.mediaRecorder) || _this_mediaRecorder.stop();\n this.recording = false;\n this.mediaRecorder = null;\n }\n constructor(canvas){\n _define_property(this, \"canvas\", void 0);\n _define_property(this, \"mediaRecorder\", null);\n _define_property(this, \"chunks\", void 0);\n _define_property(this, \"recording\", false);\n this.canvas = canvas;\n this.chunks = [];\n }\n}\nfunction Player(props) {\n var _scripts_;\n const [titleText, setTitleText] = useState('');\n const [subTitleText, setSubTitleText] = useState('');\n const scripts = null == props ? void 0 : props.replayScripts;\n const imageWidth = (null == props ? void 0 : props.imageWidth) || 1920;\n const imageHeight = (null == props ? void 0 : props.imageHeight) || 1080;\n const fitMode = (null == props ? void 0 : props.fitMode) || 'height';\n const currentImg = useRef((null == scripts ? void 0 : null == (_scripts_ = scripts[0]) ? void 0 : _scripts_.img) || null);\n const divContainerRef = useRef(null);\n const app = useMemo(()=>new Application(), []);\n const pointerSprite = useRef(null);\n const spinningPointerSprite = useRef(null);\n const [replayMark, setReplayMark] = useState(0);\n const triggerReplay = ()=>{\n setReplayMark(Date.now());\n };\n const windowContentContainer = useMemo(()=>{\n const container = new Container();\n return container;\n }, []);\n const insightMarkContainer = useMemo(()=>{\n const container = new Container();\n container.zIndex = LAYER_ORDER_INSIGHT;\n return container;\n }, []);\n const basicCameraState = {\n left: 0,\n top: 0,\n width: imageWidth,\n pointerLeft: Math.round(imageWidth / 2),\n pointerTop: Math.round(imageHeight / 2)\n };\n const [animationProgress, setAnimationProgress] = useState(-1);\n const cancelFlag = useRef(false);\n useEffect(()=>{\n cancelFlag.current = false;\n return ()=>{\n cancelFlag.current = true;\n };\n }, []);\n const cameraState = useRef({\n ...basicCameraState\n });\n const repaintImage = async ()=>{\n const imgToUpdate = currentImg.current;\n if (!imgToUpdate) return void console.warn('no image to update');\n if (!getTextureFromCache(imgToUpdate)) {\n console.warn('image not loaded', imgToUpdate);\n await loadTexture(imgToUpdate);\n }\n const texture = getTextureFromCache(imgToUpdate);\n if (!texture) throw new Error('texture not found');\n const sprite = Sprite.from(texture);\n if (!sprite) throw new Error('sprite not found');\n const mainImgLabel = 'main-img';\n const child = windowContentContainer.getChildByLabel(mainImgLabel);\n if (child) windowContentContainer.removeChild(child);\n sprite.label = mainImgLabel;\n sprite.zIndex = LAYER_ORDER_IMG;\n sprite.width = imageWidth;\n sprite.height = imageHeight;\n windowContentContainer.addChild(sprite);\n };\n const spinningPointer = (frame)=>{\n var _pointerSprite_current, _pointerSprite_current1;\n if (!spinningPointerSprite.current) {\n spinningPointerSprite.current = Sprite.from(mouseLoading);\n spinningPointerSprite.current.zIndex = LAYER_ORDER_SPINNING_POINTER;\n spinningPointerSprite.current.anchor.set(0.5, 0.5);\n spinningPointerSprite.current.scale.set(0.5);\n spinningPointerSprite.current.label = 'spinning-pointer';\n }\n spinningPointerSprite.current.x = (null == (_pointerSprite_current = pointerSprite.current) ? void 0 : _pointerSprite_current.x) || 0;\n spinningPointerSprite.current.y = (null == (_pointerSprite_current1 = pointerSprite.current) ? void 0 : _pointerSprite_current1.y) || 0;\n windowContentContainer.addChild(spinningPointerSprite.current);\n let startTime;\n let isCancelled = false;\n const animate = (currentTime)=>{\n if (isCancelled) return;\n if (!startTime) startTime = currentTime;\n const elapsedTime = currentTime - startTime;\n const progress = (Math.sin(elapsedTime / 500 - Math.PI / 2) + 1) / 2;\n const rotation = progress * Math.PI * 2;\n if (spinningPointerSprite.current) spinningPointerSprite.current.rotation = rotation;\n frame(animate);\n };\n frame(animate);\n const stopFn = ()=>{\n if (spinningPointerSprite.current) windowContentContainer.removeChild(spinningPointerSprite.current);\n isCancelled = true;\n };\n return stopFn;\n };\n const updatePointer = async (img, x, y)=>{\n var _pointerSprite_current, _pointerSprite_current1;\n if (!getTextureFromCache(img)) {\n console.warn('image not loaded', img);\n await loadTexture(img);\n }\n const texture = getTextureFromCache(img);\n if (!texture) throw new Error('texture not found');\n const sprite = Sprite.from(texture);\n let targetX = null == (_pointerSprite_current = pointerSprite.current) ? void 0 : _pointerSprite_current.x;\n let targetY = null == (_pointerSprite_current1 = pointerSprite.current) ? void 0 : _pointerSprite_current1.y;\n if ('number' == typeof x) targetX = x;\n if ('number' == typeof y) targetY = y;\n if (void 0 === targetX || void 0 === targetY) return void console.warn('invalid pointer position', x, y);\n if (pointerSprite.current) {\n const pointer = windowContentContainer.getChildByLabel('pointer');\n if (pointer) windowContentContainer.removeChild(pointer);\n }\n pointerSprite.current = sprite;\n pointerSprite.current.x = targetX;\n pointerSprite.current.y = targetY;\n pointerSprite.current.label = 'pointer';\n pointerSprite.current.zIndex = LAYER_ORDER_POINTER;\n windowContentContainer.addChild(pointerSprite.current);\n };\n const updateCamera = (state)=>{\n cameraState.current = state;\n const newScale = Math.max(1, imageWidth / state.width);\n windowContentContainer.scale.set(newScale);\n windowContentContainer.x = Math.round(canvasPaddingLeft - state.left * newScale);\n windowContentContainer.y = Math.round(canvasPaddingTop - state.top * newScale);\n const pointer = windowContentContainer.getChildByLabel('pointer');\n if (pointer) {\n pointer.scale.set(1 / newScale);\n if ('number' == typeof state.pointerLeft && 'number' == typeof state.pointerTop) {\n pointer.x = state.pointerLeft;\n pointer.y = state.pointerTop;\n }\n }\n };\n const cameraAnimation = async (targetState, duration, frame)=>{\n const currentState = {\n ...cameraState.current\n };\n const startLeft = currentState.left;\n const startTop = currentState.top;\n const startPointerLeft = currentState.pointerLeft;\n const startPointerTop = currentState.pointerTop;\n const startScale = currentState.width / imageWidth;\n const startTime = performance.now();\n const shouldMovePointer = 'number' == typeof targetState.pointerLeft && 'number' == typeof targetState.pointerTop && (targetState.pointerLeft !== startPointerLeft || targetState.pointerTop !== startPointerTop);\n const pointerMoveDuration = shouldMovePointer ? 0.375 * duration : 0;\n const cameraMoveStart = pointerMoveDuration;\n const cameraMoveDuration = duration - pointerMoveDuration;\n await new Promise((resolve)=>{\n const animate = (currentTime)=>{\n const nextState = {\n ...cameraState.current\n };\n const elapsedTime = currentTime - startTime;\n if (shouldMovePointer) if (elapsedTime <= pointerMoveDuration) {\n const rawMouseProgress = Math.min(elapsedTime / pointerMoveDuration, 1);\n const mouseProgress = cubicMouse(rawMouseProgress);\n nextState.pointerLeft = startPointerLeft + (targetState.pointerLeft - startPointerLeft) * mouseProgress;\n nextState.pointerTop = startPointerTop + (targetState.pointerTop - startPointerTop) * mouseProgress;\n } else {\n nextState.pointerLeft = targetState.pointerLeft;\n nextState.pointerTop = targetState.pointerTop;\n }\n if (elapsedTime > cameraMoveStart) {\n const cameraElapsedTime = elapsedTime - cameraMoveStart;\n const rawCameraProgress = Math.min(cameraElapsedTime / cameraMoveDuration, 1);\n const cameraProgress = cubicImage(rawCameraProgress);\n const targetScale = targetState.width / imageWidth;\n const progressScale = startScale + (targetScale - startScale) * cameraProgress;\n const progressWidth = imageWidth * progressScale;\n const progressHeight = imageHeight * progressScale;\n nextState.width = progressWidth;\n const progressLeft = startLeft + (targetState.left - startLeft) * cameraProgress;\n const progressTop = startTop + (targetState.top - startTop) * cameraProgress;\n const horizontalExceed = progressLeft + progressWidth - imageWidth;\n const verticalExceed = progressTop + progressHeight - imageHeight;\n nextState.left = horizontalExceed > 0 ? progressLeft + horizontalExceed : progressLeft;\n nextState.top = verticalExceed > 0 ? progressTop + verticalExceed : progressTop;\n }\n updateCamera(nextState);\n if (elapsedTime < duration) frame(animate);\n else resolve();\n };\n frame(animate);\n });\n };\n const fadeInGraphics = function(graphics, duration, frame) {\n let targetAlpha = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : 1;\n return new Promise((resolve)=>{\n const startTime = performance.now();\n const animate = (currentTime)=>{\n const elapsedTime = currentTime - startTime;\n const progress = Math.min(elapsedTime / duration, 1);\n graphics.alpha = 0 === targetAlpha ? 1 - linear(progress) : linear(progress);\n if (elapsedTime < duration) frame(animate);\n else resolve();\n };\n frame(animate);\n });\n };\n const fadeOutItem = async (graphics, duration, frame)=>fadeInGraphics(graphics, duration, frame, 0);\n const insightElementsAnimation = async (elements, highlightElements, searchArea, duration, frame)=>{\n insightMarkContainer.removeChildren();\n const elementsToAdd = [\n ...elements\n ];\n const totalLength = elementsToAdd.length;\n let childrenCount = 0;\n await new Promise((resolve)=>{\n const startTime = performance.now();\n const animate = (currentTime)=>{\n const elapsedTime = currentTime - startTime;\n const progress = cubicInsightElement(Math.min(elapsedTime / duration, 1));\n const elementsToAddNow = Math.floor(progress * totalLength);\n while(childrenCount < elementsToAddNow){\n const randomIndex = Math.floor(Math.random() * elementsToAdd.length);\n const element = elementsToAdd.splice(randomIndex, 1)[0];\n if (element) {\n const [insightMarkGraphic] = rectMarkForItem(element.rect, element.content, 'element');\n insightMarkGraphic.alpha = 0;\n insightMarkContainer.addChild(insightMarkGraphic);\n childrenCount++;\n fadeInGraphics(insightMarkGraphic, singleElementFadeInDuration, frame);\n }\n }\n if (elapsedTime < duration) frame(animate);\n else {\n while(elementsToAdd.length > 0){\n const randomIndex = Math.floor(Math.random() * elementsToAdd.length);\n const element = elementsToAdd.splice(randomIndex, 1)[0];\n const [insightMarkGraphic] = rectMarkForItem(element.rect, element.content, 'element');\n insightMarkGraphic.alpha = 1;\n insightMarkContainer.addChild(insightMarkGraphic);\n }\n if (searchArea) {\n const [searchAreaGraphic] = rectMarkForItem(searchArea, 'Search Area', 'searchArea');\n searchAreaGraphic.alpha = 1;\n insightMarkContainer.addChild(searchAreaGraphic);\n }\n highlightElements.map((element)=>{\n const [insightMarkGraphic] = rectMarkForItem(element.rect, element.content || '', 'highlight');\n insightMarkGraphic.alpha = 1;\n insightMarkContainer.addChild(insightMarkGraphic);\n });\n resolve();\n }\n };\n frame(animate);\n });\n };\n const init = async ()=>{\n if (!divContainerRef.current || !scripts) return;\n await app.init({\n width: imageWidth,\n height: imageHeight,\n background: 0xf4f4f4,\n autoDensity: true,\n antialias: true\n });\n if (!divContainerRef.current) return;\n divContainerRef.current.appendChild(app.canvas);\n windowContentContainer.x = 0;\n windowContentContainer.y = 0;\n app.stage.addChild(windowContentContainer);\n insightMarkContainer.x = 0;\n insightMarkContainer.y = 0;\n windowContentContainer.addChild(insightMarkContainer);\n };\n const [isRecording, setIsRecording] = useState(false);\n const recorderSessionRef = useRef(null);\n const handleExport = ()=>{\n if (recorderSessionRef.current) return void console.warn('recorderSession exists');\n if (!app.canvas) return void console.warn('canvas is not initialized');\n recorderSessionRef.current = new RecordingSession(app.canvas);\n setIsRecording(true);\n triggerReplay();\n };\n const play = ()=>{\n let cancelFn;\n Promise.resolve((async ()=>{\n if (!app) throw new Error('app is not initialized');\n if (!scripts) throw new Error(\"scripts is required\");\n const { frame, cancel, timeout } = frameKit();\n cancelFn = cancel;\n const allImages = scripts.filter((item)=>!!item.img).map((item)=>item.img);\n await Promise.all([\n ...allImages,\n mouseLoading,\n mousePointer\n ].map(loadTexture));\n insightMarkContainer.removeChildren();\n await updatePointer(mousePointer, imageWidth / 2, imageHeight / 2);\n await repaintImage();\n await updateCamera({\n ...basicCameraState\n });\n const totalDuration = scripts.reduce((acc, item)=>acc + item.duration + (item.camera && item.insightCameraDuration ? item.insightCameraDuration : 0), 0);\n const progressUpdateInterval = 200;\n const startTime = performance.now();\n setAnimationProgress(0);\n const updateProgress = ()=>{\n const progress = Math.min((performance.now() - startTime) / totalDuration, 1);\n setAnimationProgress(progress);\n if (progress < 1) return timeout(updateProgress, progressUpdateInterval);\n };\n frame(updateProgress);\n if (recorderSessionRef.current) recorderSessionRef.current.start();\n for(const index in scripts){\n const item = scripts[index];\n setTitleText(item.title || '');\n setSubTitleText(item.subTitle || '');\n if ('sleep' === item.type) await sleep(item.duration);\n else if ('insight' === item.type) {\n var _item_context;\n if (!item.img) throw new Error('img is required');\n currentImg.current = item.img;\n await repaintImage();\n const elements = (null == (_item_context = item.context) ? void 0 : _item_context.tree) ? treeToList(item.context.tree) : [];\n const highlightElements = item.highlightElement ? [\n item.highlightElement\n ] : [];\n await insightElementsAnimation(elements, highlightElements, item.searchArea, item.duration, frame);\n if (item.camera) {\n if (!item.insightCameraDuration) throw new Error('insightCameraDuration is required');\n await cameraAnimation(item.camera, item.insightCameraDuration, frame);\n }\n } else if ('clear-insight' === item.type) {\n await fadeOutItem(insightMarkContainer, item.duration, frame);\n insightMarkContainer.removeChildren();\n insightMarkContainer.alpha = 1;\n } else if ('img' === item.type) {\n if (item.img && item.img !== currentImg.current) {\n currentImg.current = item.img;\n await repaintImage();\n }\n if (item.camera) await cameraAnimation(item.camera, item.duration, frame);\n else await sleep(item.duration);\n } else if ('pointer' === item.type) {\n if (!item.img) throw new Error('pointer img is required');\n await updatePointer(item.img);\n } else if ('spinning-pointer' === item.type) {\n const stop = spinningPointer(frame);\n await sleep(item.duration);\n stop();\n }\n }\n if (recorderSessionRef.current) {\n recorderSessionRef.current.stop();\n recorderSessionRef.current = null;\n setIsRecording(false);\n }\n })().catch((e)=>{\n console.error('player error', e);\n }));\n return ()=>{\n null == cancelFn || cancelFn();\n };\n };\n useEffect(()=>{\n Promise.resolve((async ()=>{\n await init();\n if (divContainerRef.current && imageWidth && imageHeight) {\n const aspectRatio = imageWidth / imageHeight;\n divContainerRef.current.style.setProperty('--canvas-aspect-ratio', aspectRatio.toString());\n divContainerRef.current.setAttribute('data-fit-mode', fitMode);\n const playerContainer = divContainerRef.current.closest('.player-container');\n if (playerContainer) playerContainer.setAttribute('data-fit-mode', fitMode);\n }\n triggerReplay();\n })());\n return ()=>{\n try {\n app.destroy(true, {\n children: true,\n texture: true\n });\n } catch (e) {\n console.warn('destroy failed', e);\n }\n };\n }, [\n imageWidth,\n imageHeight,\n fitMode\n ]);\n useEffect(()=>{\n if (replayMark) return play();\n }, [\n replayMark\n ]);\n const [mouseOverStatusIcon, setMouseOverStatusIcon] = useState(false);\n const progressString = Math.round(100 * animationProgress);\n const transitionStyle = 0 === animationProgress ? 'none' : '0.3s';\n const canReplayNow = 1 === animationProgress;\n useEffect(()=>{\n if (canReplayNow) {\n const listener = (event)=>{\n if (' ' === event.key) triggerReplay();\n };\n window.addEventListener('keydown', listener);\n return ()=>{\n window.removeEventListener('keydown', listener);\n };\n }\n }, [\n canReplayNow\n ]);\n let statusIconElement;\n let statusOnClick = ()=>{};\n if (animationProgress < 1) statusIconElement = /*#__PURE__*/ jsx(Spin, {\n indicator: /*#__PURE__*/ jsx(LoadingOutlined, {\n spin: true,\n color: \"#333\"\n }),\n size: \"default\"\n });\n else if (mouseOverStatusIcon) {\n statusIconElement = /*#__PURE__*/ jsx(Spin, {\n indicator: /*#__PURE__*/ jsx(CaretRightOutlined, {\n color: \"#333\"\n }),\n size: \"default\"\n });\n statusOnClick = ()=>triggerReplay();\n } else statusIconElement = /*#__PURE__*/ jsx(Spin, {\n indicator: /*#__PURE__*/ jsx(CaretRightOutlined, {\n color: \"#333\"\n }),\n size: \"default\"\n });\n return /*#__PURE__*/ jsxs(\"div\", {\n className: \"player-container\",\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"canvas-container\",\n ref: divContainerRef\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"player-timeline-wrapper\",\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"player-timeline\",\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"player-timeline-progress\",\n style: {\n width: `${progressString}%`,\n transition: transitionStyle\n }\n })\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"player-tools-wrapper\",\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"player-tools\",\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"player-control\",\n children: [\n /*#__PURE__*/ jsxs(\"div\", {\n className: \"status-text\",\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"title\",\n children: titleText\n }),\n /*#__PURE__*/ jsx(Tooltip, {\n title: subTitleText,\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"subtitle\",\n children: subTitleText\n })\n })\n ]\n }),\n isRecording ? null : /*#__PURE__*/ jsx(\"div\", {\n className: \"status-icon\",\n onMouseEnter: ()=>setMouseOverStatusIcon(true),\n onMouseLeave: ()=>setMouseOverStatusIcon(false),\n onClick: statusOnClick,\n children: statusIconElement\n }),\n (null == props ? void 0 : props.reportFileContent) ? /*#__PURE__*/ jsx(Tooltip, {\n title: \"Download Report\",\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"status-icon\",\n onMouseEnter: ()=>setMouseOverStatusIcon(true),\n onMouseLeave: ()=>setMouseOverStatusIcon(false),\n onClick: ()=>downloadReport(props.reportFileContent),\n children: /*#__PURE__*/ jsx(DownloadOutlined, {\n color: \"#333\"\n })\n })\n }) : null,\n /*#__PURE__*/ jsx(Tooltip, {\n title: isRecording ? 'Generating...' : 'Export Video',\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"status-icon\",\n onClick: isRecording ? void 0 : handleExport,\n style: {\n opacity: isRecording ? 0.5 : 1,\n cursor: isRecording ? 'not-allowed' : 'pointer'\n },\n children: isRecording ? /*#__PURE__*/ jsx(Spin, {\n size: \"default\",\n percent: progressString\n }) : /*#__PURE__*/ jsx(ExportOutlined, {})\n })\n })\n ]\n })\n })\n })\n ]\n });\n}\nexport { Player };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport { LoadingOutlined } from \"@ant-design/icons\";\nimport { Spin } from \"antd\";\nimport { Player } from \"../player.mjs\";\nimport shiny_text from \"../shiny-text.mjs\";\nimport { emptyResultTip, serverLaunchTip } from \"./playground-constants.mjs\";\nimport \"./index.css\";\nconst PlaygroundResultView = (param)=>{\n let { result, loading, serverValid, serviceMode, replayScriptsInfo, replayCounter, loadingProgressText, verticalMode = false, notReadyMessage, fitMode } = param;\n let resultWrapperClassName = 'result-wrapper';\n if (verticalMode) resultWrapperClassName += ' vertical-mode-result';\n if (replayScriptsInfo && verticalMode) resultWrapperClassName += ' result-wrapper-compact';\n let resultDataToShow = emptyResultTip;\n if (serverValid || 'Server' !== serviceMode) {\n if (loading) resultDataToShow = /*#__PURE__*/ jsxs(\"div\", {\n className: \"loading-container\",\n children: [\n /*#__PURE__*/ jsx(Spin, {\n spinning: loading,\n indicator: /*#__PURE__*/ jsx(LoadingOutlined, {\n spin: true\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"loading-progress-text loading-progress-text-progress\",\n children: /*#__PURE__*/ jsx(shiny_text, {\n text: loadingProgressText,\n speed: 3\n })\n })\n ]\n });\n else if (replayScriptsInfo) resultDataToShow = /*#__PURE__*/ jsx(Player, {\n replayScripts: replayScriptsInfo.scripts,\n imageWidth: replayScriptsInfo.width,\n imageHeight: replayScriptsInfo.height,\n reportFileContent: ('In-Browser-Extension' === serviceMode || 'Server' === serviceMode) && (null == result ? void 0 : result.reportHTML) ? null == result ? void 0 : result.reportHTML : null,\n fitMode: fitMode\n }, replayCounter);\n else if (null == result ? void 0 : result.error) resultDataToShow = /*#__PURE__*/ jsx(\"pre\", {\n children: null == result ? void 0 : result.error\n });\n else if ((null == result ? void 0 : result.result) !== void 0) resultDataToShow = 'string' == typeof (null == result ? void 0 : result.result) ? /*#__PURE__*/ jsx(\"pre\", {\n children: null == result ? void 0 : result.result\n }) : /*#__PURE__*/ jsx(\"pre\", {\n children: JSON.stringify(null == result ? void 0 : result.result, null, 2)\n });\n } else resultDataToShow = serverLaunchTip(notReadyMessage);\n return /*#__PURE__*/ jsx(\"div\", {\n className: resultWrapperClassName,\n style: {\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n flex: '1 1 auto'\n },\n children: resultDataToShow\n });\n};\nexport { PlaygroundResultView };\n","import './index.less';\nimport { MobileOutlined } from '@ant-design/icons';\nimport { useServerValid } from '@midscene/visualizer';\nimport { Button, Divider, Dropdown, message } from 'antd';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { RefObject } from 'react';\nimport type { Socket } from 'socket.io-client';\nimport type { ScrcpyRefMethods } from '../scrcpy-player';\n\n// status dot indicator\nconst onlineStatus = (color: string) => (\n <span\n className=\"status-dot\"\n style={{\n color: color,\n }}\n >\n ●\n </span>\n);\n\nexport interface Device {\n id: string;\n name: string;\n status: string;\n}\n\nexport interface AdbDeviceProps {\n devices: Device[];\n loadingDevices: boolean;\n selectedDeviceId: string | null;\n onDeviceSelect: (deviceId: string) => void;\n socketRef: React.RefObject<Socket | null>;\n scrcpyPlayerRef: RefObject<ScrcpyRefMethods>;\n}\n\nconst AdbDevice: React.FC<AdbDeviceProps> = ({\n devices,\n loadingDevices: _loadingDevices,\n selectedDeviceId,\n onDeviceSelect,\n socketRef,\n scrcpyPlayerRef,\n}) => {\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const lastSelectedDeviceRef = useRef<string | null>(null);\n const [messageApi, contextHolder] = message.useMessage();\n const serverValid = useServerValid(true);\n\n // handle device selection\n const handleDeviceSelect = useCallback(\n (deviceId: string) => {\n if (deviceId === lastSelectedDeviceRef.current) {\n return;\n }\n\n // check socket connection status\n if (!socketRef.current || !socketRef.current.connected) {\n return;\n }\n\n // close dropdown\n setDropdownOpen(false);\n\n // call the parent component's device selection handler\n onDeviceSelect(deviceId);\n\n // update the last selected device id\n lastSelectedDeviceRef.current = deviceId;\n },\n [onDeviceSelect, socketRef],\n );\n\n // disconnect device\n const disconnectDevice = useCallback(() => {\n // call ScrcpyPlayer's disconnectDevice method\n if (scrcpyPlayerRef.current) {\n scrcpyPlayerRef.current.disconnectDevice();\n messageApi.info('Device disconnected');\n }\n }, [scrcpyPlayerRef, messageApi]);\n\n // check if selected device is offline\n const isSelectedDeviceOffline = selectedDeviceId\n ? devices.find((d) => d.id === selectedDeviceId)?.status.toLowerCase() !==\n 'device'\n : false;\n\n // automatically unlink when device goes offline\n useEffect(() => {\n if (isSelectedDeviceOffline && selectedDeviceId) {\n disconnectDevice();\n }\n }, [isSelectedDeviceOffline, selectedDeviceId, disconnectDevice, messageApi]);\n\n return (\n <div className=\"device-header\">\n {contextHolder}\n <div className=\"device-title-container\">\n <h2 className=\"device-title\">Device</h2>\n <Dropdown\n trigger={['click']}\n placement=\"bottomLeft\"\n open={dropdownOpen}\n onOpenChange={setDropdownOpen}\n dropdownRender={() => (\n <div className=\"device-dropdown\">\n <div className=\"dropdown-header\">\n <span className=\"dropdown-title\">Devices list</span>\n </div>\n <div className=\"device-list\">\n {devices.map((device) => (\n <div\n key={device.id}\n onClick={() => {\n if (device.status.toLowerCase() === 'device') {\n handleDeviceSelect(device.id);\n }\n }}\n className={`device-list-item ${\n device.status.toLowerCase() === 'device' &&\n selectedDeviceId === device.id\n ? 'selected'\n : ''\n } ${\n device.status.toLowerCase() !== 'device' ? 'offline' : ''\n }`}\n >\n <div className=\"device-item-content\">\n <div className=\"device-item-icon-container\">\n <MobileOutlined className=\"device-item-icon\" />\n </div>\n <div className=\"device-item-info\">\n <div className=\"device-item-name\">\n {device.name || device.id}\n </div>\n <div className=\"device-item-status\">\n <div className=\"status-badge\">\n {device.status.toLowerCase() === 'device' ? (\n <>\n {onlineStatus('#52c41a')}\n <span className=\"status-text\">Online</span>\n </>\n ) : (\n <>\n {onlineStatus('#f5222d')}\n <span className=\"status-text\">Offline</span>\n </>\n )}\n </div>\n <Divider type=\"vertical\" className=\"status-divider\" />\n <div className=\"device-id-container\">\n Device ID: {device.id}\n </div>\n </div>\n </div>\n {device.status.toLowerCase() === 'device' &&\n selectedDeviceId === device.id && (\n <div className=\"current-device-indicator\">\n Current device\n </div>\n )}\n </div>\n </div>\n ))}\n {devices.length === 0 && (\n <div className=\"device-list-empty\">No devices found</div>\n )}\n </div>\n </div>\n )}\n >\n <Button className=\"device-dropdown-button\">\n <div className=\"device-icon-container\">\n <MobileOutlined className=\"device-icon\" />\n {selectedDeviceId && serverValid && (\n <div className=\"status-indicator\">\n {devices\n .find((d) => d.id === selectedDeviceId)\n ?.status.toLowerCase() === 'device' ? (\n <>{onlineStatus('#52c41a')}</>\n ) : (\n <>{onlineStatus('#f5222d')}</>\n )}\n </div>\n )}\n </div>\n {selectedDeviceId && !isSelectedDeviceOffline && serverValid ? (\n <span className=\"device-name\">\n {devices.find((d) => d.id === selectedDeviceId)?.name ||\n selectedDeviceId}\n </span>\n ) : (\n <span className=\"device-name no-device\">No device</span>\n )}\n <span className=\"dropdown-arrow\">▼</span>\n </Button>\n </Dropdown>\n </div>\n </div>\n );\n};\n\nexport default AdbDevice;\n","import * as React from \"react\";\nconst SvgLinked = props => <svg xmlns=\"http://www.w3.org/2000/svg\" width={16} height={16} fill=\"none\" viewBox=\"0 0 16 16\" {...props}><path fill=\"#000\" fillOpacity={0.25} fillRule=\"evenodd\" d=\"M9.68 2c1.2-1.2 3.2-1.28 4.4-.08s1.12 3.2-.08 4.4l-2.16 2.16c-.24.24-.56.24-.8 0s-.24-.56 0-.8l2.16-2.16c.8-.8.8-2.08.08-2.8s-2-.72-2.8.08L8.32 4.96c-.24.24-.56.24-.8 0s-.24-.56 0-.8zM5.6 13.2l2.16-2.16c.24-.24.56-.24.8 0s.24.56 0 .8L6.4 14c-1.2 1.2-3.12 1.36-4.4.08-1.36-1.28-1.2-3.2.08-4.4l2.16-2.16c.24-.24.56-.24.8 0s.24.56 0 .8l-2.16 2.16c-.8.8-.88 2-.08 2.8s2 .72 2.8-.08m4.64-8.24c.24-.24.64-.24.96 0 .24.24.24.64 0 .96L5.92 11.2c-.24.24-.64.24-.96 0-.24-.24-.24-.64 0-.96z\" clipRule=\"evenodd\" /></svg>;\nexport default SvgLinked;","import * as React from \"react\";\nconst SvgScreenshot = props => <svg xmlns=\"http://www.w3.org/2000/svg\" width={16} height={16} fill=\"none\" viewBox=\"0 0 16 16\" {...props}><g fill=\"#606266\" clipPath=\"url(#screenshot_svg__a)\"><path d=\"m4.883 2.663-.858 2.001h-2.69v8.673h13.341V4.664H11.32l-.859-2zm-1.738.667.858-2.001h7.338l.858 2.001h2.477a1.334 1.334 0 0 1 1.334 1.334v8.673a1.335 1.335 0 0 1-1.334 1.334H1.334A1.334 1.334 0 0 1 0 13.337V4.664A1.334 1.334 0 0 1 1.334 3.33z\" /><path d=\"M8.005 10.001a1.334 1.334 0 1 0 0-2.668 1.334 1.334 0 0 0 0 2.668m0 1.335a2.668 2.668 0 1 1 0-5.337 2.668 2.668 0 0 1 0 5.337m3.336-6.004h.667q.667 0 .667.667 0 .666-.667.667h-.667q-.667 0-.667-.667t.667-.667\" /></g><defs><clipPath id=\"screenshot_svg__a\"><path fill=\"#fff\" d=\"M0 0h16v16H0z\" /></clipPath></defs></svg>;\nexport default SvgScreenshot;","import * as React from \"react\";\nconst SvgUnlink = props => <svg xmlns=\"http://www.w3.org/2000/svg\" width={16} height={16} fill=\"none\" viewBox=\"0 0 16 16\" {...props}><path fill=\"#FF4550\" d=\"M14.08 1.92C12.88.72 10.88.8 9.68 2L7.52 4.16c-.24.24-.24.56 0 .8s.56.24.8 0l2.16-2.16c.8-.8 2.08-.8 2.8-.08s.72 2-.08 2.8l-2.16 2.16c-.24.24-.24.56 0 .8s.56.24.8 0L14 6.32c1.2-1.2 1.28-3.2.08-4.4m-6.32 9.12L5.6 13.2c-.8.8-2 .88-2.8.08s-.72-2 .08-2.8l2.16-2.16c.24-.24.24-.56 0-.8s-.56-.24-.8 0L2.08 9.68C.8 10.88.64 12.8 2 14.08c1.28 1.28 3.2 1.12 4.4-.08l2.16-2.16c.24-.24.24-.56 0-.8s-.56-.24-.8 0M5.92 4.96c-.24-.24-.64-.24-.96 0-.24.24-.24.64 0 .96l5.28 5.28c.24.24.64.24.96 0 .24-.24.24-.64 0-.96z\" /></svg>;\nexport default SvgUnlink;","import { InfoCircleOutlined } from '@ant-design/icons';\nimport { useServerValid } from '@midscene/visualizer';\nimport { ScrcpyVideoCodecId } from '@yume-chan/scrcpy';\nimport { WebCodecsVideoDecoder } from '@yume-chan/scrcpy-decoder-webcodecs';\nimport {\n BitmapVideoFrameRenderer,\n WebGLVideoFrameRenderer,\n} from '@yume-chan/scrcpy-decoder-webcodecs';\nimport {\n Button,\n Card,\n Col,\n Divider,\n Row,\n Spin,\n Tooltip,\n Typography,\n message,\n} from 'antd';\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport type { Socket } from 'socket.io-client';\nimport { io } from 'socket.io-client';\nimport LinkedIcon from '../icons/linked.svg?react';\nimport ScreenshotIcon from '../icons/screenshot.svg?react';\nimport UnlinkIcon from '../icons/unlink.svg?react';\nimport './index.less';\n\nconst { Text } = Typography;\n\ninterface ScrcpyProps {\n serverUrl?: string;\n maxSize?: number;\n autoConnect?: boolean;\n autoReconnect?: boolean;\n reconnectInterval?: number;\n onConnectionStatusChange?: (status: boolean) => void;\n}\n\ninterface VideoMetadata {\n codec?: string;\n width?: number;\n height?: number;\n [key: string]: any;\n}\n\nexport interface ScrcpyRefMethods {\n disconnectDevice: () => void;\n}\n\nexport const ScrcpyPlayer = forwardRef<ScrcpyRefMethods, ScrcpyProps>(\n (\n {\n serverUrl,\n maxSize = 1024,\n autoConnect = true,\n autoReconnect = true,\n reconnectInterval = 5000,\n onConnectionStatusChange,\n },\n ref,\n ) => {\n const [connecting, setConnecting] = useState(false);\n const [connected, setConnected] = useState(false);\n const [screenInfo, setScreenInfo] = useState<{\n width: number;\n height: number;\n } | null>(null);\n const [deviceId, setDeviceId] = useState<string>('');\n\n const socketRef = useRef<Socket | null>(null);\n const videoContainerRef = useRef<HTMLDivElement>(null);\n const videoElementRef = useRef<HTMLCanvasElement | null>(null);\n const decoderRef = useRef<any>(null);\n const reconnectTimerRef = useRef<NodeJS.Timeout | null>(null);\n const metadataTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const serverValid = useServerValid(true);\n // create a safe remove child nodes tool function\n const safeRemoveChildNodes = useCallback((parent: Element | null) => {\n if (!parent) return;\n\n try {\n // use a safer way to clear child nodes\n while (parent.firstChild) {\n try {\n parent.removeChild(parent.firstChild);\n } catch (e) {\n console.warn('Failed to remove child, skipping:', e);\n // if remove failed, set it to null to avoid trying to remove again\n if (parent.firstChild) {\n parent.innerHTML = '';\n break;\n }\n }\n }\n } catch (e) {\n console.error('Error clearing container:', e);\n // last resort - directly reset HTML\n try {\n parent.innerHTML = '';\n } catch (innerErr) {\n console.error('Failed to reset innerHTML:', innerErr);\n }\n }\n }, []);\n\n // update canvas size to fit container\n const updateCanvasSize = useCallback(() => {\n if (!videoElementRef.current || !videoContainerRef.current || !screenInfo)\n return;\n\n const container = videoContainerRef.current;\n const canvas = videoElementRef.current;\n const containerWidth = container.clientWidth;\n const containerHeight = container.clientHeight;\n const { width: originalWidth, height: originalHeight } = screenInfo;\n\n // leave 20px padding on top and bottom\n const paddingVertical = 40; // padding on top and bottom, each 20px\n const availableHeight = containerHeight - paddingVertical;\n\n // calculate the size fit to container, keep the aspect ratio\n const aspectRatio = originalWidth / originalHeight;\n let targetWidth = containerWidth;\n let targetHeight = containerWidth / aspectRatio;\n\n if (targetHeight > availableHeight) {\n targetHeight = availableHeight;\n targetWidth = availableHeight * aspectRatio;\n }\n\n // update canvas properties and styles\n canvas.width = originalWidth;\n canvas.height = originalHeight;\n canvas.style.width = `${targetWidth}px`;\n canvas.style.height = `${targetHeight}px`;\n canvas.style.marginTop = '20px';\n canvas.style.marginBottom = '20px';\n }, [screenInfo]);\n\n // listen window size change\n useEffect(() => {\n const handleResize = () => {\n updateCanvasSize();\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [updateCanvasSize]);\n\n // when screenInfo updates, adjust the size\n useEffect(() => {\n updateCanvasSize();\n }, [screenInfo, updateCanvasSize]);\n\n // create and initialize renderer\n const createVideoFrameRenderer = async () => {\n // use WebGL renderer first, if not supported, fallback to Bitmap renderer\n if (WebGLVideoFrameRenderer.isSupported) {\n const renderer = new WebGLVideoFrameRenderer();\n return {\n renderer,\n element: renderer.canvas as HTMLCanvasElement,\n };\n }\n\n const renderer = new BitmapVideoFrameRenderer();\n return {\n renderer,\n element: renderer.canvas as HTMLCanvasElement,\n };\n };\n\n // create and initialize decoder\n const createDecoder = async (codecId: ScrcpyVideoCodecId) => {\n // check if WebCodecs API is supported\n if (!WebCodecsVideoDecoder.isSupported) {\n throw new Error(\n 'Current browser does not support WebCodecs API, please use the latest version of Chrome/Edge browser',\n );\n }\n\n // create renderer\n const { renderer, element } = await createVideoFrameRenderer();\n videoElementRef.current = element;\n\n // add video element to page\n if (videoContainerRef.current) {\n const canvasWrapper =\n videoContainerRef.current.querySelector('.canvas-wrapper');\n if (canvasWrapper) {\n // safely clear container\n safeRemoveChildNodes(canvasWrapper);\n canvasWrapper.appendChild(videoElementRef.current);\n }\n }\n\n // create decoder\n return new WebCodecsVideoDecoder({\n codec: codecId,\n renderer: renderer,\n });\n };\n\n // setup video stream processing\n const setupVideoStream = (_metadata: VideoMetadata) => {\n // for tracking if the configuration frame has been received\n let configurationPacketSent = false;\n let pendingDataPackets: any[] = [];\n\n // create transform stream to convert data to Uint8Array\n const transformStream = new TransformStream({\n transform(chunk: any, controller: any) {\n // convert array to Uint8Array\n const packet = {\n type: chunk.type,\n data: new Uint8Array(chunk.data),\n timestamp: chunk.timestamp,\n };\n\n // for configuration frame, we should handle it first\n if (packet.type === 'configuration') {\n controller.enqueue(packet);\n configurationPacketSent = true;\n\n // after sending the configuration frame, send all pending data frames\n if (pendingDataPackets.length > 0) {\n pendingDataPackets.forEach((p) => controller.enqueue(p));\n pendingDataPackets = [];\n }\n } else if (packet.type === 'data') {\n // if the configuration frame has not been received, cache the data frame\n if (!configurationPacketSent) {\n pendingDataPackets.push(packet);\n } else {\n controller.enqueue(packet);\n }\n } else {\n // other types of frames are passed directly\n controller.enqueue(packet);\n }\n },\n });\n\n // create a readable stream to receive video data from the server\n const videoStream = new ReadableStream({\n start(controller) {\n // for tracking if the stream has been closed\n let streamClosed = false;\n\n // receive video data\n const videoDataHandler = (data: any) => {\n // check if the stream has been closed\n if (streamClosed) return;\n\n try {\n controller.enqueue(data);\n } catch (error) {\n console.error(\n 'error occurred while enqueuing video data:',\n error,\n );\n // if an error occurs, mark the stream as closed and clean up\n streamClosed = true;\n cleanupHandlers();\n }\n };\n\n // handle error\n const errorHandler = (error: any) => {\n console.error('stream error:', error);\n if (!streamClosed) {\n controller.error(new Error(error.message));\n streamClosed = true;\n cleanupHandlers();\n }\n };\n\n // handle disconnection\n const disconnectHandler = () => {\n if (!streamClosed) {\n controller.close();\n streamClosed = true;\n cleanupHandlers();\n }\n };\n\n // clean up all event handlers\n const cleanupHandlers = () => {\n if (socketRef.current) {\n socketRef.current.off('video-data', videoDataHandler);\n socketRef.current.off('error', errorHandler);\n socketRef.current.off('disconnect', disconnectHandler);\n }\n };\n\n // register event handlers\n if (socketRef.current) {\n socketRef.current.on('video-data', videoDataHandler);\n socketRef.current.on('error', errorHandler);\n socketRef.current.on('disconnect', disconnectHandler);\n }\n\n // clean up when the stream is cancelled\n return () => {\n streamClosed = true;\n cleanupHandlers();\n };\n },\n });\n\n // handle video stream\n return videoStream.pipeThrough(transformStream);\n };\n\n // screenshot feature\n const takeScreenshot = async () => {\n if (!decoderRef.current) return;\n\n try {\n const blob = await decoderRef.current.snapshot();\n if (blob) {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `screenshot_${new Date().toISOString().replace(/:/g, '-')}.png`;\n a.click();\n URL.revokeObjectURL(url);\n }\n } catch (error) {\n console.error('screenshot failed:', error);\n alert('screenshot failed');\n }\n };\n\n // disconnect device\n const disconnectDevice = useCallback(() => {\n // dispose decoder resources\n if (decoderRef.current) {\n try {\n decoderRef.current.dispose();\n decoderRef.current = null;\n } catch (error) {\n console.error('Error disposing decoder:', error);\n }\n }\n\n // clear video container\n if (videoContainerRef.current) {\n const canvasWrapper =\n videoContainerRef.current.querySelector('.canvas-wrapper');\n safeRemoveChildNodes(canvasWrapper);\n }\n\n // disconnect socket\n if (socketRef.current) {\n socketRef.current.disconnect();\n socketRef.current = null;\n }\n\n // clean up timers\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current);\n reconnectTimerRef.current = null;\n }\n\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n\n // reset status\n setConnected(false);\n setConnecting(false);\n setScreenInfo(null);\n }, [safeRemoveChildNodes]);\n\n // Expose methods to parent component\n useImperativeHandle(\n ref,\n () => ({\n disconnectDevice,\n }),\n [disconnectDevice],\n );\n\n // connect device\n const connectDevice = useCallback(async () => {\n try {\n // always clean up previous resources, ensure clean state\n disconnectDevice();\n\n // ensure status reset\n setConnected(false);\n setConnecting(true);\n setScreenInfo(null);\n\n // short delay to ensure resources are cleaned\n await new Promise((resolve) => setTimeout(resolve, 150));\n\n // ensure the component is still mounted and has a valid server URL\n if (!serverUrl) {\n console.error('Cannot connect: missing server URL');\n setConnecting(false);\n onConnectionStatusChange?.(false);\n return;\n }\n\n // setup metadata timeout check\n const setupMetadataTimeout = () => {\n // clear previous timeout\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n\n // setup new timeout check\n metadataTimeoutRef.current = setTimeout(() => {\n if (socketRef.current?.connected) {\n try {\n socketRef.current.emit('connect-device', {\n maxSize,\n });\n\n // setup metadata timeout check again\n setupMetadataTimeout();\n } catch (err) {\n console.error('Failed to request connection:', err);\n onConnectionStatusChange?.(false); // notify connection request failed\n message.error(\n 'connection request failed, please refresh the page',\n );\n }\n } else {\n onConnectionStatusChange?.(false); // notify connection status change\n\n try {\n if (socketRef.current) {\n setTimeout(() => {\n // reconnect after a short delay\n if (socketRef.current) {\n socketRef.current.connect();\n }\n }, 500);\n }\n } catch (err) {\n console.error('Failed to reconnect:', err);\n message.error('reconnection failed, please refresh the page');\n }\n }\n }, 5000);\n };\n\n // connect to server\n if (!socketRef.current) {\n try {\n socketRef.current = io(serverUrl, {\n withCredentials: true,\n reconnection: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n timeout: 10000,\n });\n\n // notify parent component after connection is successful\n socketRef.current.on('connect', () => {\n onConnectionStatusChange?.(true);\n\n // get device id from socket\n if (socketRef.current?.id) {\n setDeviceId(socketRef.current.id);\n }\n\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current);\n reconnectTimerRef.current = null;\n }\n\n socketRef.current?.emit('connect-device', {\n maxSize,\n });\n\n // setup metadata timeout check\n setupMetadataTimeout();\n });\n\n // handle video metadata\n socketRef.current.on(\n 'video-metadata',\n async (metadata: VideoMetadata) => {\n try {\n // clear metadata timeout\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n\n // if there is already a decoder, clean it first\n if (decoderRef.current) {\n try {\n decoderRef.current.dispose();\n decoderRef.current = null;\n } catch (error) {\n console.error('Error disposing old decoder:', error);\n }\n }\n\n // clean video container\n if (videoContainerRef.current) {\n const canvasWrapper =\n videoContainerRef.current.querySelector(\n '.canvas-wrapper',\n );\n safeRemoveChildNodes(canvasWrapper);\n }\n\n // ensure the metadata object exists, and set the default codec\n // convert string to ScrcpyVideoCodecId enum\n const codecId = metadata?.codec\n ? (metadata.codec as unknown as ScrcpyVideoCodecId)\n : ScrcpyVideoCodecId.H264;\n\n // create decoder\n decoderRef.current = await createDecoder(codecId);\n\n // ensure the decoder is created successfully\n if (!decoderRef.current) {\n throw new Error('Failed to create decoder');\n }\n\n // listen to size change event\n decoderRef.current.sizeChanged(\n ({ width, height }: { width: number; height: number }) => {\n setScreenInfo({ width, height });\n },\n );\n\n // setup video stream processing\n const videoStream = setupVideoStream(metadata);\n\n // pass the video stream to the decoder\n videoStream\n .pipeTo(decoderRef.current.writable)\n .catch((error: Error) => {\n console.error('video stream processing error:', error);\n onConnectionStatusChange?.(false);\n });\n\n // update UI status\n setConnected(true);\n setConnecting(false);\n // video metadata received successfully, device connected\n onConnectionStatusChange?.(true);\n } catch (error: any) {\n console.error('Failed to initialize decoder:', error);\n setConnecting(false);\n onConnectionStatusChange?.(false);\n }\n },\n );\n\n // handle error\n socketRef.current.on('error', (error: Error) => {\n console.error('server error:', error);\n message.error('server error');\n setConnecting(false);\n onConnectionStatusChange?.(false);\n\n // clear metadata timeout\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n });\n\n // handle disconnection event\n socketRef.current.on('disconnect', () => {\n setConnected(false);\n onConnectionStatusChange?.(false);\n\n // clear metadata timeout\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n\n // clean up video container\n if (decoderRef.current) {\n decoderRef.current.dispose();\n decoderRef.current = null;\n }\n\n if (videoContainerRef.current) {\n // safely clear container\n safeRemoveChildNodes(\n videoContainerRef.current.querySelector('.canvas-wrapper'),\n );\n }\n\n if (autoReconnect && !reconnectTimerRef.current) {\n reconnectTimerRef.current = setTimeout(() => {\n reconnectTimerRef.current = null;\n connectDevice();\n }, reconnectInterval);\n }\n });\n } catch (error: any) {\n console.error('Failed to create socket connection:', error);\n setConnecting(false);\n onConnectionStatusChange?.(false);\n\n if (autoReconnect && !reconnectTimerRef.current) {\n reconnectTimerRef.current = setTimeout(() => {\n reconnectTimerRef.current = null;\n connectDevice();\n }, reconnectInterval);\n }\n }\n } else {\n if (!socketRef.current.connected) {\n socketRef.current.connect();\n } else {\n socketRef.current.emit('connect-device', {\n maxSize,\n });\n\n // setup metadata timeout check\n setupMetadataTimeout();\n }\n }\n } catch (error: any) {\n setConnecting(false);\n onConnectionStatusChange?.(false);\n console.error(`Failed to connect: ${error.message}`);\n message.error('connection failed');\n\n if (autoReconnect && !reconnectTimerRef.current) {\n reconnectTimerRef.current = setTimeout(() => {\n reconnectTimerRef.current = null;\n connectDevice();\n }, reconnectInterval);\n }\n }\n }, [\n serverUrl,\n maxSize,\n autoReconnect,\n reconnectInterval,\n onConnectionStatusChange,\n disconnectDevice,\n ]);\n\n // detect autoConnect change, connect device when autoConnect is true\n useEffect(() => {\n if (autoConnect && !connected && !connecting) {\n // only trigger connection when not connected and not connecting\n const timer = setTimeout(() => {\n connectDevice();\n }, 300);\n\n return () => clearTimeout(timer);\n }\n }, [autoConnect, connected, connecting, connectDevice]);\n\n // resource cleanup useEffect\n useEffect(() => {\n // return cleanup function, called when component unmounts\n return () => {\n onConnectionStatusChange?.(false);\n\n // dispose decoder\n if (decoderRef.current) {\n try {\n decoderRef.current.dispose();\n decoderRef.current = null;\n } catch (error) {\n console.error('Error disposing decoder during unmount:', error);\n }\n }\n\n // clean video container\n if (videoContainerRef.current) {\n try {\n const canvasWrapper =\n videoContainerRef.current.querySelector('.canvas-wrapper');\n if (canvasWrapper) {\n // safely clear content instead of removing node\n canvasWrapper.innerHTML = '';\n }\n } catch (error) {\n console.error(\n 'Error clearing canvas wrapper during unmount:',\n error,\n );\n }\n }\n\n // disconnect socket connection\n if (socketRef.current) {\n socketRef.current.disconnect();\n socketRef.current = null;\n }\n\n // clean up all timers\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current);\n reconnectTimerRef.current = null;\n }\n\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n };\n }, [onConnectionStatusChange]);\n\n return (\n <div className=\"scrcpy-container\">\n <Card>\n {connected && (\n <div className=\"header-bar\">\n <div className=\"header-left\">\n <Text style={{ fontWeight: 600, fontSize: 12 }}>\n Screen Projection\n </Text>\n <Tooltip\n placement=\"bottom\"\n title={`Device ID: ${deviceId || 'Unknown'}`}\n >\n <InfoCircleOutlined />\n </Tooltip>\n </div>\n <div className=\"screen-info\">\n <Text type=\"secondary\">\n size : {screenInfo?.width}×{screenInfo?.height}\n </Text>\n </div>\n <div className=\"header-right\">\n <Tooltip placement=\"bottom\" title=\"Screenshot\">\n <Button icon={<ScreenshotIcon />} onClick={takeScreenshot} />\n </Tooltip>\n <Divider\n type=\"vertical\"\n style={{\n margin: '0 16px',\n }}\n />\n <Tooltip placement=\"bottom\" title=\"Connect Device\">\n <Button\n disabled={connected}\n style={{\n backgroundColor: '#fff',\n }}\n icon={<LinkedIcon />}\n onClick={connectDevice}\n />\n </Tooltip>\n {connected && (\n <>\n <Divider\n type=\"vertical\"\n style={{\n margin: '0 16px',\n }}\n />\n <Tooltip title=\"Disconnect Device\">\n <Button\n icon={<UnlinkIcon />}\n onClick={disconnectDevice}\n />\n </Tooltip>\n </>\n )}\n </div>\n </div>\n )}\n <Row gutter={[16, 16]}>\n <Col span={24}>\n <div className=\"video-section\">\n <div ref={videoContainerRef} className=\"video-container\">\n <div className=\"canvas-wrapper\" />\n {!connected && serverValid && (\n <div className=\"empty-state\">\n <div className=\"empty-state-icon\">📱</div>\n <div className=\"empty-state-text\">\n {connecting\n ? 'Connecting to device...'\n : 'No device connected'}\n </div>\n {!connecting && (\n <Button\n type=\"primary\"\n onClick={() => {\n connectDevice();\n }}\n >\n Connect now\n </Button>\n )}\n {connecting && (\n <div className=\"loading-spinner\">\n <Spin size=\"large\" />\n </div>\n )}\n </div>\n )}\n {!serverValid && (\n <span>Please launch playground server!</span>\n )}\n </div>\n </div>\n </Col>\n </Row>\n </Card>\n </div>\n );\n },\n);\n\nexport default ScrcpyPlayer;\n","import './App.less';\nimport { SCRCPY_SERVER_PORT } from '@midscene/shared/constants';\nimport { overrideAIConfig } from '@midscene/shared/env';\nimport {\n EnvConfig,\n Logo,\n type PlaygroundResult,\n PlaygroundResultView,\n PromptInput,\n type ReplayScriptsInfo,\n allScriptsFromDump,\n cancelTask,\n getTaskProgress,\n globalThemeConfig,\n overrideServerConfig,\n requestPlaygroundServer,\n useEnvConfig,\n useServerValid,\n} from '@midscene/visualizer';\nimport { Col, ConfigProvider, Form, Layout, Row, message } from 'antd';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { type Socket, io } from 'socket.io-client';\nimport AdbDevice from './adb-device';\nimport ScrcpyPlayer, { type ScrcpyRefMethods } from './scrcpy-player';\n\nimport './adb-device/index.less';\n\nconst { Content } = Layout;\nconst SERVER_URL = `http://localhost:${SCRCPY_SERVER_PORT}`;\n\nexport default function App() {\n const [form] = Form.useForm();\n const selectedType = Form.useWatch('type', form);\n const [loading, setLoading] = useState(false);\n const [selectedDeviceId, setSelectedDeviceId] = useState<string | null>(null);\n const [connectToDevice, setConnectToDevice] = useState(false);\n const [devices, setDevices] = useState<\n { id: string; name: string; status: string }[]\n >([]);\n const [loadingDevices, setLoadingDevices] = useState(true);\n const lastSelectedDeviceRef = useRef<string | null>(null);\n const [messageApi, contextHolder] = message.useMessage();\n const [connectionReady, setConnectionReady] = useState(false);\n const [result, setResult] = useState<PlaygroundResult | null>({\n result: undefined,\n dump: null,\n reportHTML: null,\n error: null,\n });\n const [replayCounter, setReplayCounter] = useState(0);\n const [replayScriptsInfo, setReplayScriptsInfo] =\n useState<ReplayScriptsInfo | null>(null);\n const { config, deepThink } = useEnvConfig();\n const [loadingProgressText, setLoadingProgressText] = useState('');\n const currentRequestIdRef = useRef<string | null>(null);\n const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const configAlreadySet = Object.keys(config || {}).length >= 1;\n const serverValid = useServerValid(true);\n\n // Socket connection and device management\n const socketRef = useRef<Socket | null>(null);\n // Add a ref to ScrcpyPlayer\n const scrcpyPlayerRef = useRef<ScrcpyRefMethods>(null);\n\n // clear the polling interval\n const clearPollingInterval = useCallback(() => {\n if (pollIntervalRef.current) {\n clearInterval(pollIntervalRef.current);\n pollIntervalRef.current = null;\n }\n }, []);\n\n // connect to device server\n useEffect(() => {\n const socket = io(SERVER_URL, {\n withCredentials: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n timeout: 5000,\n });\n\n socket.on('connect', () => {\n socket.emit('get-devices');\n });\n\n socket.on('disconnect', (_reason: string) => {\n setLoadingDevices(true);\n });\n\n socket.on(\n 'devices-list',\n (data: {\n devices: { id: string; name: string; status: string }[];\n currentDeviceId: string | null;\n }) => {\n setDevices(data.devices);\n if (data.currentDeviceId) {\n setSelectedDeviceId(data.currentDeviceId);\n\n if (data.devices.length === 1) {\n handleDeviceSelect(data.devices[0].id, true);\n }\n }\n setLoadingDevices(false);\n },\n );\n\n socket.on('global-device-switched', (data: { deviceId: string }) => {\n setSelectedDeviceId(data.deviceId);\n });\n\n socket.on('connect_error', (error: Error) => {\n console.error('Socket.IO connection error:', error);\n messageApi.error(\n 'Waiting for device server connection, please try again later',\n );\n setLoadingDevices(false);\n });\n\n socket.on('error', (error: Error) => {\n console.error('Socket.IO error:', error);\n messageApi.error(\n `Error occurred while communicating with the server: ${error.message || 'Unknown error'}`,\n );\n });\n\n socketRef.current = socket;\n\n // request device list periodically\n const timer = setTimeout(() => {\n if (socket.connected) {\n socket.emit('get-devices');\n }\n }, 2000);\n\n return () => {\n clearTimeout(timer);\n socket.disconnect();\n };\n }, [messageApi]);\n\n // switch device\n const handleDeviceSelect = useCallback(\n (deviceId: string, silent = false) => {\n if (deviceId === lastSelectedDeviceRef.current) {\n return;\n }\n\n if (!socketRef.current || !socketRef.current.connected) {\n messageApi.warning(\n 'Waiting for device server connection, please try again later',\n );\n return;\n }\n\n // disconnect current connection and reset related status\n setConnectToDevice(false);\n setConnectionReady(false);\n\n // clean current session status\n setResult(null);\n setReplayScriptsInfo(null);\n setLoading(false);\n clearPollingInterval();\n\n // use a short delay to ensure resources are cleaned\n setTimeout(() => {\n // then set the new device id\n setSelectedDeviceId(deviceId);\n lastSelectedDeviceRef.current = deviceId;\n\n setLoadingDevices(true);\n if (socketRef.current) {\n socketRef.current.emit('switch-device', deviceId);\n\n const timeoutId = setTimeout(() => {\n setLoadingDevices(false);\n messageApi.error('Device switch timeout, please try again');\n }, 10000);\n\n socketRef.current.once('device-switched', () => {\n clearTimeout(timeoutId);\n setLoadingDevices(false);\n\n // after device switched, trigger new device connection\n setTimeout(() => {\n setConnectToDevice(true);\n if (!silent) {\n messageApi.success(`Device selected: ${deviceId}`);\n }\n }, 500); // add delay to ensure enough time for switch\n });\n\n socketRef.current.once('error', (error: Error) => {\n clearTimeout(timeoutId);\n setLoadingDevices(false);\n messageApi.error(`Device switch failed: ${error.message}`);\n });\n } else {\n setLoadingDevices(false);\n messageApi.error('Socket connection lost, please refresh the page');\n }\n }, 500); // add delay to ensure enough time for switch\n },\n [messageApi, clearPollingInterval],\n );\n\n // start polling task progress\n const startPollingProgress = useCallback(\n (requestId: string) => {\n clearPollingInterval();\n\n // set polling interval to 500ms\n pollIntervalRef.current = setInterval(async () => {\n try {\n const data = await getTaskProgress(requestId);\n\n if (data.tip) {\n setLoadingProgressText(data.tip);\n }\n } catch (error) {\n console.error('Failed to poll task progress:', error);\n }\n }, 500);\n },\n [clearPollingInterval],\n );\n\n // clean up the polling when the component unmounts\n useEffect(() => {\n return () => {\n clearPollingInterval();\n };\n }, [clearPollingInterval]);\n\n // listen to the connection status change\n const handleConnectionStatusChange = useCallback(\n (status: boolean) => {\n setConnectionReady(status);\n\n // if the connection is ready and there is a selected device but not connected, try to connect\n if (status && selectedDeviceId && !connectToDevice) {\n setTimeout(() => {\n setConnectToDevice(true);\n }, 100);\n }\n },\n [selectedDeviceId],\n );\n\n // reset the connection flag\n useEffect(() => {\n if (connectToDevice) {\n // reset the connection flag, so that it can be triggered again\n const timer = setTimeout(() => {\n // only reset connectToDevice when the device is not switched\n // this ensures that the connection status is not reset during device switch\n if (selectedDeviceId === lastSelectedDeviceRef.current) {\n setConnectToDevice(false);\n }\n }, 800); // add delay to ensure enough time for connection\n\n return () => clearTimeout(timer);\n }\n }, [connectToDevice, selectedDeviceId]);\n\n // Override AI configuration\n useEffect(() => {\n overrideAIConfig(config);\n overrideServerConfig(config);\n }, [config]);\n\n // handle run button click\n const handleRun = useCallback(async () => {\n if (!selectedDeviceId) {\n messageApi.warning('Please select a device first');\n return;\n }\n\n if (!connectionReady) {\n messageApi.warning(\n 'Waiting for connection establishment, please try again later',\n );\n return;\n }\n\n setLoading(true);\n setResult(null);\n setReplayScriptsInfo(null);\n setLoadingProgressText('');\n\n const { type, prompt } = form.getFieldsValue();\n\n const thisRunningId = Date.now().toString();\n\n currentRequestIdRef.current = thisRunningId;\n\n // start polling progress immediately\n startPollingProgress(thisRunningId);\n\n try {\n const res = await requestPlaygroundServer(\n selectedDeviceId,\n type,\n prompt,\n {\n requestId: thisRunningId,\n deepThink,\n },\n );\n\n // stop polling\n clearPollingInterval();\n\n setResult(res);\n setLoading(false);\n\n if (!res) {\n throw new Error('server returned empty response');\n }\n\n // handle the special case of aiAction type, extract script information\n if (res?.dump && !['aiQuery', 'aiAssert'].includes(type)) {\n const info = allScriptsFromDump(res.dump);\n setReplayScriptsInfo(info);\n setReplayCounter((c) => c + 1);\n } else {\n setReplayScriptsInfo(null);\n }\n messageApi.success('Command executed');\n } catch (error) {\n clearPollingInterval();\n setLoading(false);\n console.error('execute command error:', error);\n messageApi.error(\n `Command execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n }, [\n selectedDeviceId,\n messageApi,\n connectionReady,\n form,\n startPollingProgress,\n clearPollingInterval,\n deepThink,\n ]);\n\n const resetResult = () => {\n setResult(null);\n setReplayScriptsInfo(null);\n setLoading(false);\n };\n\n // handle stop button click\n const handleStop = useCallback(async () => {\n clearPollingInterval();\n setLoading(false);\n resetResult();\n if (currentRequestIdRef.current) {\n await cancelTask(currentRequestIdRef.current);\n }\n messageApi.info('Operation stopped');\n }, [messageApi, clearPollingInterval]);\n\n return (\n <ConfigProvider theme={globalThemeConfig()}>\n {contextHolder}\n <Layout className=\"app-container playground-container vertical-mode\">\n <Content className=\"app-content\">\n <div className=\"app-grid-layout\">\n <Row className=\"app-grid-layout\">\n {/* left panel: PromptInput */}\n <Col className=\"app-panel left-panel\">\n <div className=\"panel-content left-panel-content\">\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '10px',\n }}\n >\n <Logo />\n <EnvConfig />\n </div>\n <h2>Command input</h2>\n <Form form={form} className=\"command-form\">\n <div className=\"form-content\">\n <div className=\"command-input-wrapper\">\n <PromptInput\n runButtonEnabled={\n !!selectedDeviceId && configAlreadySet\n }\n form={form}\n serviceMode=\"Server\"\n selectedType={selectedType}\n dryMode={false}\n stoppable={loading}\n loading={loading}\n onRun={handleRun}\n onStop={handleStop}\n />\n </div>\n <div\n className=\"result-container\"\n style={\n result\n ? {}\n : {\n border: '1px solid #0000001f',\n borderRadius: '8px',\n }\n }\n >\n <PlaygroundResultView\n result={result}\n loading={loading}\n serverValid={serverValid}\n serviceMode=\"Server\"\n replayScriptsInfo={replayScriptsInfo}\n replayCounter={replayCounter}\n loadingProgressText={loadingProgressText}\n verticalMode={false}\n notReadyMessage={\n <span>\n Don&apos;t worry, just one more step to launch the\n playground server.\n <br />\n <strong>\n npx --yes @midscene/android-playground\n </strong>\n </span>\n }\n />\n </div>\n </div>\n </Form>\n </div>\n </Col>\n\n {/* right panel: ScrcpyPlayer */}\n <Col className=\"app-panel right-panel\">\n <div className=\"panel-content right-panel-content\">\n <AdbDevice\n devices={devices}\n loadingDevices={loadingDevices}\n selectedDeviceId={selectedDeviceId}\n onDeviceSelect={handleDeviceSelect}\n socketRef={socketRef}\n scrcpyPlayerRef={scrcpyPlayerRef}\n />\n <ScrcpyPlayer\n ref={scrcpyPlayerRef}\n serverUrl={SERVER_URL}\n autoConnect={connectToDevice}\n onConnectionStatusChange={handleConnectionStatusChange}\n />\n </div>\n </Col>\n </Row>\n </div>\n </Content>\n </Layout>\n </ConfigProvider>\n );\n}\n","import ReactDOM from 'react-dom/client';\nimport App from './App';\n\nconst rootEl = document.getElementById('root');\nif (rootEl) {\n const root = ReactDOM.createRoot(rootEl);\n root.render(<App />);\n}\n","// 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","var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);\nvar leafPrototypes;\n// create a fake namespace object\n// mode & 1: value is a module id, require it\n// mode & 2: merge all properties of value into the ns\n// mode & 4: return value when already ns object\n// mode & 16: return value when it's Promise-like\n// mode & 8|1: behave like require\n__webpack_require__.t = function(value, mode) {\n\tif(mode & 1) value = this(value);\n\tif(mode & 8) return value;\n\tif(typeof value === 'object' && value) {\n\t\tif((mode & 4) && value.__esModule) return value;\n\t\tif((mode & 16) && typeof value.then === 'function') return value;\n\t}\n\tvar ns = Object.create(null);\n __webpack_require__.r(ns);\n\tvar def = {};\n\tleafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];\n\tfor(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {\n\t\tObject.getOwnPropertyNames(current).forEach((key) => { def[key] = () => (value[key]) });\n\t}\n\tdef['default'] = () => (value);\n\t__webpack_require__.d(ns, def);\n\treturn ns;\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__.f = {};\n// This file contains only the entry chunk.\n// The chunk loading function for additional chunks\n__webpack_require__.e = (chunkId) => {\n\treturn Promise.all(\n\t\tObject.keys(__webpack_require__.f).reduce((promises, key) => {\n\t\t\t__webpack_require__.f[key](chunkId, promises);\n\t\t\treturn promises;\n\t\t}, [])\n\t);\n};","// This function allow to reference chunks\n__webpack_require__.u = (chunkId) => {\n // return url for filenames not based on template\n \n // return url for filenames based on template\n return \"static/js/async/\" + chunkId + \".\" + {\"166\": \"834644b5\",\"173\": \"f2381e64\",\"212\": \"850ade70\",\"290\": \"06d1055a\",\"329\": \"261bc4a1\",\"364\": \"d88c3cff\",\"544\": \"18ac9afb\",\"582\": \"8f4b5264\",\"624\": \"8a1fe2e8\",\"644\": \"910ce3d0\",\"702\": \"1f38a17e\",\"975\": \"693266d2\",\"983\": \"b98b40af\",}[chunkId] + \".js\"\n}","// This function allow to reference chunks\n__webpack_require__.miniCssF = (chunkId) => {\n // return url for filenames not based on template\n \n // return url for filenames based on template\n return \"\" + chunkId + \".css\"\n}","__webpack_require__.h = () => (\"d403efbb08d1b74f\")","__webpack_require__.g = (() => {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","var inProgress = {};\n\nvar dataWebpackPrefix = \"android-playground:\";\n// loadScript function to load a script via script tag\n__webpack_require__.l = function (url, done, key, chunkId) {\n\tif (inProgress[url]) {\n\t\tinProgress[url].push(done);\n\t\treturn;\n\t}\n\tvar script, needAttach;\n\tif (key !== undefined) {\n\t\tvar scripts = document.getElementsByTagName(\"script\");\n\t\tfor (var i = 0; i < scripts.length; i++) {\n\t\t\tvar s = scripts[i];\n\t\t\tif (s.getAttribute(\"src\") == url || s.getAttribute(\"data-webpack\") == dataWebpackPrefix + key) {\n\t\t\t\tscript = s;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tif (!script) {\n\t\tneedAttach = true;\n\t\t\n script = document.createElement('script');\n \n\t\tscript.charset = 'utf-8';\n\t\tscript.timeout = 120;\n\t\tif (__webpack_require__.nc) {\n\t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n\t\t}\n\t\tscript.setAttribute(\"data-webpack\", dataWebpackPrefix + key);\n\t\t\n\t\tscript.src = url;\n\t\t\n \n\t}\n\tinProgress[url] = [done];\n\tvar onScriptComplete = function (prev, event) {\n\t\tscript.onerror = script.onload = null;\n\t\tclearTimeout(timeout);\n\t\tvar doneFns = inProgress[url];\n\t\tdelete inProgress[url];\n\t\tscript.parentNode && script.parentNode.removeChild(script);\n\t\tdoneFns &&\n\t\t\tdoneFns.forEach(function (fn) {\n\t\t\t\treturn fn(event);\n\t\t\t});\n\t\tif (prev) return prev(event);\n\t};\n\tvar timeout = setTimeout(\n\t\tonScriptComplete.bind(null, undefined, {\n\t\t\ttype: 'timeout',\n\t\t\ttarget: script\n\t\t}),\n\t\t120000\n\t);\n\tscript.onerror = onScriptComplete.bind(null, script.onerror);\n\tscript.onload = onScriptComplete.bind(null, script.onload);\n\tneedAttach && document.head.appendChild(script);\n};\n","// 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};","__webpack_require__.nmd = (module) => {\n module.paths = [];\n if (!module.children) module.children = [];\n return module;\n};","var deferred = [];\n__webpack_require__.O = (result, chunkIds, fn, priority) => {\n\tif (chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor (var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--)\n\t\t\tdeferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar [chunkIds, fn, priority] = deferred[i];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif (\n\t\t\t\t(priority & (1 === 0) || notFulfilled >= priority) &&\n\t\t\t\tObject.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))\n\t\t\t) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif (priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif (fulfilled) {\n\t\t\tdeferred.splice(i--, 1);\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};\n","__webpack_require__.p = \"/\";","__webpack_require__.rv = () => (\"1.3.12\")","__webpack_require__.b = document.baseURI || self.location.href;\n\n // object to store loaded and loading chunks\n // undefined = chunk not loaded, null = chunk preloaded/prefetched\n // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\n var installedChunks = {\"980\": 0,};\n \n __webpack_require__.f.j = function (chunkId, promises) {\n // JSONP chunk loading for javascript\nvar installedChunkData = __webpack_require__.o(installedChunks, chunkId)\n\t? installedChunks[chunkId]\n\t: undefined;\nif (installedChunkData !== 0) {\n\t// 0 means \"already installed\".\n\n\t// a Promise means \"currently loading\".\n\tif (installedChunkData) {\n\t\tpromises.push(installedChunkData[2]);\n\t} else {\n\t\tif (true) {\n\t\t\t// setup Promise in chunk cache\n\t\t\tvar promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));\n\t\t\tpromises.push((installedChunkData[2] = promise));\n\n\t\t\t// start chunk loading\n\t\t\tvar url = __webpack_require__.p + __webpack_require__.u(chunkId);\n\t\t\t// create error before stack unwound to get useful stacktrace later\n\t\t\tvar error = new Error();\n\t\t\tvar loadingEnded = function (event) {\n\t\t\t\tif (__webpack_require__.o(installedChunks, chunkId)) {\n\t\t\t\t\tinstalledChunkData = installedChunks[chunkId];\n\t\t\t\t\tif (installedChunkData !== 0) installedChunks[chunkId] = undefined;\n\t\t\t\t\tif (installedChunkData) {\n\t\t\t\t\t\tvar errorType =\n\t\t\t\t\t\t\tevent && (event.type === 'load' ? 'missing' : event.type);\n\t\t\t\t\t\tvar realSrc = event && event.target && event.target.src;\n\t\t\t\t\t\terror.message =\n\t\t\t\t\t\t\t'Loading chunk ' +\n\t\t\t\t\t\t\tchunkId +\n\t\t\t\t\t\t\t' failed.\\n(' +\n\t\t\t\t\t\t\terrorType +\n\t\t\t\t\t\t\t': ' +\n\t\t\t\t\t\t\trealSrc +\n\t\t\t\t\t\t\t')';\n\t\t\t\t\t\terror.name = 'ChunkLoadError';\n\t\t\t\t\t\terror.type = errorType;\n\t\t\t\t\t\terror.request = realSrc;\n\t\t\t\t\t\tinstalledChunkData[1](error);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\t__webpack_require__.l(url, loadingEnded, \"chunk-\" + chunkId, chunkId);\n\t\t} \n\t}\n}\n\n }\n __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = (parentChunkLoadingFunction, data) => {\n\tvar [chunkIds, moreModules, runtime] = data;\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif (chunkIds.some((id) => (installedChunks[id] !== 0))) {\n\t\tfor (moduleId in moreModules) {\n\t\t\tif (__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif (runtime) var result = runtime(__webpack_require__);\n\t}\n\tif (parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor (; i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif (\n\t\t\t__webpack_require__.o(installedChunks, chunkId) &&\n\t\t\tinstalledChunks[chunkId]\n\t\t) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n};\n\nvar chunkLoadingGlobal = self[\"webpackChunkandroid_playground\"] = self[\"webpackChunkandroid_playground\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));\n","__webpack_require__.ruid = \"bundler=rspack@1.3.12\";\n"],"names":["M","globalThis","e","Error","Object","Symbol","localStorage","t","window","Map","Date","i","Math","JSON","fetch","arguments","console","Promise","setTimeout","a","s","c","p","requestAnimationFrame","performance","Blob","URL","document","MediaRecorder","r","onlineStatus","color","_devices_find","_devices_find1","_devices_find2","devices","_loadingDevices","selectedDeviceId","onDeviceSelect","socketRef","scrcpyPlayerRef","dropdownOpen","setDropdownOpen","useState","lastSelectedDeviceRef","useRef","messageApi","contextHolder","message","serverValid","useServerValid","handleDeviceSelect","useCallback","deviceId","disconnectDevice","isSelectedDeviceOffline","d","useEffect","Dropdown","device","MobileOutlined","Divider","Button","props","Text","Typography","ScrcpyPlayer","forwardRef","ref","serverUrl","maxSize","autoConnect","autoReconnect","reconnectInterval","onConnectionStatusChange","connecting","setConnecting","connected","setConnected","screenInfo","setScreenInfo","setDeviceId","videoContainerRef","videoElementRef","decoderRef","reconnectTimerRef","metadataTimeoutRef","safeRemoveChildNodes","parent","innerErr","updateCanvasSize","container","canvas","containerWidth","containerHeight","originalWidth","originalHeight","availableHeight","aspectRatio","targetWidth","targetHeight","handleResize","createVideoFrameRenderer","WebGLVideoFrameRenderer","renderer","BitmapVideoFrameRenderer","createDecoder","codecId","WebCodecsVideoDecoder","element","canvasWrapper","setupVideoStream","_metadata","configurationPacketSent","pendingDataPackets","transformStream","TransformStream","chunk","controller","packet","Uint8Array","videoStream","ReadableStream","streamClosed","videoDataHandler","data","error","cleanupHandlers","errorHandler","disconnectHandler","takeScreenshot","blob","url","alert","clearTimeout","useImperativeHandle","connectDevice","resolve","setupMetadataTimeout","_socketRef_current","err","io","_socketRef_current1","metadata","ScrcpyVideoCodecId","width","height","timer","Card","Tooltip","InfoCircleOutlined","ScreenshotIcon","LinkedIcon","UnlinkIcon","Row","Col","Spin","Content","Layout","SERVER_URL","rootEl","root","ReactDOM","form","Form","selectedType","loading","setLoading","setSelectedDeviceId","connectToDevice","setConnectToDevice","setDevices","loadingDevices","setLoadingDevices","connectionReady","setConnectionReady","result","setResult","undefined","replayCounter","setReplayCounter","replayScriptsInfo","setReplayScriptsInfo","config","deepThink","useEnvConfig","loadingProgressText","setLoadingProgressText","currentRequestIdRef","pollIntervalRef","configAlreadySet","clearPollingInterval","clearInterval","socket","_reason","silent","timeoutId","startPollingProgress","requestId","setInterval","getTaskProgress","handleConnectionStatusChange","status","overrideAIConfig","overrideServerConfig","handleRun","type","prompt","thisRunningId","res","requestPlaygroundServer","info","allScriptsFromDump","resetResult","handleStop","cancelTask","ConfigProvider","Logo","EnvConfig","PromptInput","PlaygroundResultView","AdbDevice","App","Function","self"],"mappings":"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EAAQ,CAAC,EAAE,EAAa,EAAE,EAAe,CAAC,CAC7E,EAAO,KAAK,CAAC,CAAC,CAAC,EAAE,EAAa,EAAE,EAAE;AAAU,CAAC,CACjD,EAQ+B,EADC,SAAgB,IAAI,IAGxC,KAAW,EACf,EAEJ,CACA,OAAO,GAAe,GAAG,CAAC,EAC9B,+DCxCiB,GAAS,mCCJtB,IAAM,GAAkB,CACxB,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,MAAO,CACH,IAAK,QACL,KAAM,OACV,EACA,MAAO,CACH,IAAK,QACL,KAAM,OACV,EACA,MAAO,CACH,QAAS,EACT,KAAM,QACN,IAAK,QACT,EACA,KAAM,CACF,QAAS,EACT,KAAM,OACN,IAAK,MACT,EACA,UAAW,CACP,QAAS,EACT,KAAM,YACN,IAAK,WACT,EACA,IAAK,CACD,QAAS,EACT,KAAM,MACN,IAAK,KACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,QACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,YAAa,CACT,QAAS,GACT,KAAM,cACN,IAAK,QACL,KAAM,KACN,SAAU,CACd,EACA,MAAO,CACH,QAAS,GACT,KAAM,QACN,IAAK,QACL,KAAM,IACV,EACA,KAAM,CACF,QAAS,GACT,KAAM,QACN,IAAK,QACL,KAAM,IACV,EACA,KAAM,CACF,QAAS,GACT,KAAM,QACN,IAAK,QACL,KAAM,IACV,EACA,UAAW,CACP,QAAS,GACT,KAAM,YACN,IAAK,QACL,SAAU,CACd,EACA,WAAY,CACR,QAAS,GACT,KAAM,aACN,IAAK,QACL,SAAU,CACd,EACA,YAAa,CACT,QAAS,GACT,KAAM,cACN,IAAK,UACL,SAAU,CACd,EACA,aAAc,CACV,QAAS,GACT,KAAM,eACN,IAAK,UACL,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,KAAM,UACN,IAAK,MACL,SAAU,CACd,EACA,SAAU,CACN,QAAS,GACT,KAAM,WACN,IAAK,MACL,SAAU,CACd,EACA,MAAO,CACH,QAAS,GACT,KAAM,QACN,IAAK,OACT,EACA,SAAU,CACN,QAAS,GACT,KAAM,WACN,IAAK,UACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,QAAS,CACL,QAAS,GACT,KAAM,UACN,IAAK,SACT,EACA,WAAY,CACR,QAAS,GACT,KAAM,aACN,IAAK,YACT,EACA,MAAO,CACH,QAAS,GACT,KAAM,QACN,IAAK,GACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,SACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,GACd,IAAK,WACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,SAAU,CACN,QAAS,GACT,KAAM,WACN,IAAK,UACT,EACA,IAAK,CACD,QAAS,GACT,KAAM,MACN,IAAK,KACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,GACd,IAAK,MACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,IAAK,MACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,OACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,UAAW,CACP,QAAS,GACT,KAAM,YACN,IAAK,WACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,YACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,UACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,KAAM,UACN,IAAK,SACT,EACA,WAAY,CACR,QAAS,GACT,KAAM,aACN,IAAK,YACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,aACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,aAAc,GACd,IAAK,YACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,UAAW,CACP,QAAS,GACT,KAAM,YACN,IAAK,WACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,IAAK,SACT,EACA,YAAa,CACT,QAAS,GACT,KAAM,cACN,IAAK,aACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,GACd,IAAK,SACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,cAAe,CACX,QAAS,GACT,aAAc,IACd,KAAM,gBACN,IAAK,KACL,SAAU,IACV,SAAU,CACd,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,SAAU,CACN,QAAS,GACT,KAAM,WACN,IAAK,OACL,SAAU,CACd,EACA,UAAW,CACP,QAAS,GACT,KAAM,YACN,IAAK,OACL,SAAU,CACd,EACA,YAAa,CACT,QAAS,GACT,KAAM,cACN,IAAK,aACT,EACA,eAAgB,CACZ,QAAS,IACT,KAAM,iBACN,IAAK,IACL,SAAU,CACd,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,IAAK,IACL,SAAU,CACd,EACA,eAAgB,CACZ,QAAS,IACT,KAAM,iBACN,IAAK,IACL,SAAU,CACd,EACA,aAAc,CACV,QAAS,IACT,KAAM,eACN,IAAK,IACL,SAAU,CACd,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,QAAS,CACL,QAAS,IACT,KAAM,UACN,IAAK,SACT,EACA,WAAY,CACR,QAAS,IACT,KAAM,aACN,IAAK,YACT,EACA,gBAAiB,CACb,QAAS,IACT,KAAM,kBACN,IAAK,iBACT,EACA,gBAAiB,CACb,QAAS,IACT,KAAM,kBACN,IAAK,iBACT,EACA,cAAe,CACX,QAAS,IACT,KAAM,gBACN,IAAK,eACT,EACA,eAAgB,CACZ,QAAS,IACT,KAAM,iBACN,IAAK,gBACT,EACA,mBAAoB,CAChB,QAAS,IACT,KAAM,qBACN,IAAK,oBACT,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,IAAK,WACT,EACA,eAAgB,CACZ,QAAS,IACT,KAAM,iBACN,IAAK,gBACT,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,SAAU,IACV,IAAK,GACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,YAAa,CACT,QAAS,IACT,KAAM,cACN,IAAK,IACL,SAAU,CACd,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,IACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,SAAU,IACV,IAAK,GACT,EACA,YAAa,CACT,QAAS,IACT,KAAM,cACN,SAAU,IACV,IAAK,GACT,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,SAAU,IACV,IAAK,IACT,EACA,aAAc,CACV,QAAS,IACT,KAAM,eACN,SAAU,IACV,IAAK,GACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,SAAU,CACN,QAAS,IACT,KAAM,WACN,IAAK,UACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,IAAK,OACT,EACA,OAAQ,CACJ,QAAS,EACT,IAAK,SACL,KAAM,OACV,EACA,MAAO,CACH,QAAS,GACT,IAAK,QACL,KAAM,UACN,SAAU,CACd,EACA,MAAO,CACH,QAAS,GACT,IAAK,QACL,KAAM,YACN,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,IAAK,UACL,KAAM,cACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,GACT,IAAK,MACL,KAAM,UACN,SAAU,CACd,EACA,OAAQ,CACJ,QAAS,GACT,IAAK,QACT,EACA,WAAY,CACR,QAAS,GACT,IAAK,YACT,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,OACV,EACA,MAAO,CACH,QAAS,GACT,IAAK,OACT,EACA,QAAS,CACL,QAAS,GACT,IAAK,UACL,KAAM,MACV,EACA,KAAU,CACN,QAAS,GACT,IAAK,KACL,KAAM,gBACN,SAAU,CACd,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,KAAM,CACF,QAAS,GACT,IAAK,OACL,KAAM,WACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,iBACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,YACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,iBACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,eACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,WACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,OACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,OACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,WACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,aACV,EACA,KAAM,CACF,QAAS,IACT,IAAK,KACL,KAAM,WACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,cACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,OACV,EACA,KAAM,CACF,QAAS,IACT,IAAK,MACT,EACA,MAAO,CACH,QAAS,IACT,IAAK,QACL,KAAM,OACV,EACA,MAAO,CACH,QAAS,IACT,IAAK,OACT,EACA,SAAU,CACN,QAAS,IACT,IAAK,UACT,EACA,KAAM,CACF,QAAS,IACT,IAAK,MACT,EACA,QAAS,CACL,QAAS,IACT,IAAK,SACT,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,WACV,EACA,IAAK,CACD,QAAS,IACT,IAAK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"}
1
+ {"version":3,"file":"static/js/index.62964904.js","sources":["webpack://android-playground/../../packages/shared/dist/es/utils.mjs","webpack://android-playground/../../packages/shared/dist/es/env.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/store/store.mjs","webpack://android-playground/../../packages/shared/dist/es/common.mjs","webpack://android-playground/../../packages/shared/dist/es/logger.mjs","webpack://android-playground/../../packages/shared/dist/es/img/transform.mjs","webpack://android-playground/../../packages/shared/dist/es/us-keyboard-layout.mjs","webpack://android-playground/../../packages/shared/dist/es/extractor/tree.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/ui-utils.mjs","webpack://android-playground/../../packages/core/dist/es/ai-model.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/task-cache.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/utils.mjs","webpack://android-playground/../../packages/core/dist/es/index.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/tasks.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/plan-builder.mjs","webpack://android-playground/../../packages/web-integration/dist/es/common/agent.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/playground-utils.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/useServerValid.mjs","webpack://android-playground/../../packages/visualizer/dist/es/utils.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/replay-scripts.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/color.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/logo.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/env-config.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/store/history.mjs","webpack://android-playground/../../packages/visualizer/dist/es/icons/setting.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/shiny-text.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/playground-constants.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/ConfigSelector.mjs","webpack://android-playground/../../packages/visualizer/dist/es/icons/close.mjs","webpack://android-playground/../../packages/visualizer/dist/es/icons/history.mjs","webpack://android-playground/../../packages/visualizer/dist/es/icons/magnifying-glass.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/HistorySelector.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/PromptInput.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/blackboard.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/pixi-loader.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/player.mjs","webpack://android-playground/../../packages/visualizer/dist/es/component/playground/PlaygroundResult.mjs","webpack://android-playground/./src/adb-device/index.tsx","webpack://android-playground/./src/icons/linked.svg","webpack://android-playground/./src/icons/screenshot.svg","webpack://android-playground/./src/icons/unlink.svg","webpack://android-playground/./src/scrcpy-player/index.tsx","webpack://android-playground/./src/App.tsx","webpack://android-playground/./src/index.tsx","webpack://android-playground/webpack/runtime/compat_get_default_export","webpack://android-playground/webpack/runtime/create_fake_namespace_object","webpack://android-playground/webpack/runtime/define_property_getters","webpack://android-playground/webpack/runtime/ensure_chunk","webpack://android-playground/webpack/runtime/get javascript chunk filename","webpack://android-playground/webpack/runtime/get mini-css chunk filename","webpack://android-playground/webpack/runtime/get_full_hash","webpack://android-playground/webpack/runtime/global","webpack://android-playground/webpack/runtime/has_own_property","webpack://android-playground/webpack/runtime/load_script","webpack://android-playground/webpack/runtime/make_namespace_object","webpack://android-playground/webpack/runtime/node_module_decorator","webpack://android-playground/webpack/runtime/on_chunk_loaded","webpack://android-playground/webpack/runtime/public_path","webpack://android-playground/webpack/runtime/rspack_version","webpack://android-playground/webpack/runtime/jsonp_chunk_loading","webpack://android-playground/webpack/runtime/rspack_unique_id"],"sourcesContent":["import { sha256 } from \"js-sha256\";\nvar _process_versions;\nconst ifInBrowser = 'undefined' != typeof window;\nconst ifInWorker = 'undefined' != typeof WorkerGlobalScope;\nconst ifInNode = 'undefined' != typeof process && (null == (_process_versions = process.versions) ? void 0 : _process_versions.node);\nfunction uuid() {\n return Math.random().toString(36).substring(2, 15);\n}\nconst hashMap = {};\nfunction generateHashId(rect, content = '') {\n const combined = JSON.stringify({\n content,\n rect\n });\n let sliceLength = 5;\n let slicedHash = '';\n const hashHex = sha256.create().update(combined).hex();\n const toLetters = (hex)=>hex.split('').map((char)=>{\n const code = Number.parseInt(char, 16);\n return String.fromCharCode(97 + code % 26);\n }).join('');\n const hashLetters = toLetters(hashHex);\n while(sliceLength < hashLetters.length - 1){\n slicedHash = hashLetters.slice(0, sliceLength);\n if (hashMap[slicedHash] && hashMap[slicedHash] !== combined) {\n sliceLength++;\n continue;\n }\n hashMap[slicedHash] = combined;\n break;\n }\n return slicedHash;\n}\nfunction assert(condition, message) {\n if (!condition) throw new Error(message || 'Assertion failed');\n}\nfunction getGlobalScope() {\n if ('undefined' != typeof window) return window;\n if ('undefined' != typeof globalThis) return globalThis;\n if ('undefined' != typeof self) return self;\n}\nlet isMcp = false;\nfunction setIsMcp(value) {\n isMcp = value;\n}\nfunction logMsg(...message) {\n if (!isMcp) console.log(...message);\n}\nasync function repeat(times, fn) {\n for(let i = 0; i < times; i++)await fn(i);\n}\nconst utils_REGEXP_LT = /</g;\nconst utils_REGEXP_GT = />/g;\nconst REGEXP_LT_ESCAPE = '__midscene_lt__';\nconst REGEXP_GT_ESCAPE = '__midscene_gt__';\nconst escapeScriptTag = (html)=>html.replace(utils_REGEXP_LT, REGEXP_LT_ESCAPE).replace(utils_REGEXP_GT, REGEXP_GT_ESCAPE);\nconst antiEscapeScriptTag = (html)=>{\n const REGEXP_LT = new RegExp(REGEXP_LT_ESCAPE, 'g');\n const REGEXP_GT = new RegExp(REGEXP_GT_ESCAPE, 'g');\n return html.replace(REGEXP_LT, '<').replace(REGEXP_GT, '>');\n};\nexport { antiEscapeScriptTag, assert, escapeScriptTag, generateHashId, getGlobalScope, ifInBrowser, ifInNode, ifInWorker, logMsg, repeat, setIsMcp, uuid };\n","const MIDSCENE_OPENAI_INIT_CONFIG_JSON = 'MIDSCENE_OPENAI_INIT_CONFIG_JSON';\nconst MIDSCENE_MODEL_NAME = 'MIDSCENE_MODEL_NAME';\nconst MIDSCENE_LANGSMITH_DEBUG = 'MIDSCENE_LANGSMITH_DEBUG';\nconst MIDSCENE_DEBUG_AI_PROFILE = 'MIDSCENE_DEBUG_AI_PROFILE';\nconst MIDSCENE_DEBUG_AI_RESPONSE = 'MIDSCENE_DEBUG_AI_RESPONSE';\nconst MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG = 'MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG';\nconst MIDSCENE_DEBUG_MODE = 'MIDSCENE_DEBUG_MODE';\nconst MIDSCENE_MCP_USE_PUPPETEER_MODE = 'MIDSCENE_MCP_USE_PUPPETEER_MODE';\nconst MIDSCENE_MCP_ANDROID_MODE = 'MIDSCENE_MCP_ANDROID_MODE';\nconst MIDSCENE_FORCE_DEEP_THINK = 'MIDSCENE_FORCE_DEEP_THINK';\nconst MIDSCENE_OPENAI_SOCKS_PROXY = 'MIDSCENE_OPENAI_SOCKS_PROXY';\nconst MIDSCENE_OPENAI_HTTP_PROXY = 'MIDSCENE_OPENAI_HTTP_PROXY';\nconst OPENAI_API_KEY = 'OPENAI_API_KEY';\nconst OPENAI_BASE_URL = 'OPENAI_BASE_URL';\nconst OPENAI_MAX_TOKENS = 'OPENAI_MAX_TOKENS';\nconst MIDSCENE_ADB_PATH = 'MIDSCENE_ADB_PATH';\nconst MIDSCENE_ADB_REMOTE_HOST = 'MIDSCENE_ADB_REMOTE_HOST';\nconst MIDSCENE_ADB_REMOTE_PORT = 'MIDSCENE_ADB_REMOTE_PORT';\nconst MIDSCENE_ANDROID_IME_STRATEGY = 'MIDSCENE_ANDROID_IME_STRATEGY';\nconst MIDSCENE_CACHE = 'MIDSCENE_CACHE';\nconst MIDSCENE_USE_VLM_UI_TARS = 'MIDSCENE_USE_VLM_UI_TARS';\nconst MIDSCENE_USE_QWEN_VL = 'MIDSCENE_USE_QWEN_VL';\nconst MIDSCENE_USE_DOUBAO_VISION = 'MIDSCENE_USE_DOUBAO_VISION';\nconst MIDSCENE_USE_GEMINI = 'MIDSCENE_USE_GEMINI';\nconst MIDSCENE_USE_VL_MODEL = 'MIDSCENE_USE_VL_MODEL';\nconst MATCH_BY_POSITION = 'MATCH_BY_POSITION';\nconst MIDSCENE_API_TYPE = 'MIDSCENE-API-TYPE';\nconst MIDSCENE_REPORT_TAG_NAME = 'MIDSCENE_REPORT_TAG_NAME';\nconst MIDSCENE_REPLANNING_CYCLE_LIMIT = 'MIDSCENE_REPLANNING_CYCLE_LIMIT';\nconst MIDSCENE_PREFERRED_LANGUAGE = 'MIDSCENE_PREFERRED_LANGUAGE';\nconst MIDSCENE_USE_AZURE_OPENAI = 'MIDSCENE_USE_AZURE_OPENAI';\nconst MIDSCENE_AZURE_OPENAI_SCOPE = 'MIDSCENE_AZURE_OPENAI_SCOPE';\nconst MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON = 'MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON';\nconst MIDSCENE_CACHE_MAX_FILENAME_LENGTH = 'MIDSCENE_CACHE_MAX_FILENAME_LENGTH';\nconst AZURE_OPENAI_ENDPOINT = 'AZURE_OPENAI_ENDPOINT';\nconst AZURE_OPENAI_KEY = 'AZURE_OPENAI_KEY';\nconst AZURE_OPENAI_API_VERSION = 'AZURE_OPENAI_API_VERSION';\nconst AZURE_OPENAI_DEPLOYMENT = 'AZURE_OPENAI_DEPLOYMENT';\nconst MIDSCENE_USE_ANTHROPIC_SDK = 'MIDSCENE_USE_ANTHROPIC_SDK';\nconst ANTHROPIC_API_KEY = 'ANTHROPIC_API_KEY';\nconst MIDSCENE_RUN_DIR = 'MIDSCENE_RUN_DIR';\nconst OPENAI_USE_AZURE = 'OPENAI_USE_AZURE';\nconst allConfigFromEnv = ()=>({\n [MIDSCENE_MCP_ANDROID_MODE]: process.env[MIDSCENE_MCP_ANDROID_MODE] || void 0,\n [MIDSCENE_OPENAI_INIT_CONFIG_JSON]: process.env[MIDSCENE_OPENAI_INIT_CONFIG_JSON] || void 0,\n [MIDSCENE_MODEL_NAME]: process.env[MIDSCENE_MODEL_NAME] || void 0,\n [MIDSCENE_DEBUG_MODE]: process.env[MIDSCENE_DEBUG_MODE] || void 0,\n [MIDSCENE_FORCE_DEEP_THINK]: process.env[MIDSCENE_FORCE_DEEP_THINK] || void 0,\n [MIDSCENE_LANGSMITH_DEBUG]: process.env[MIDSCENE_LANGSMITH_DEBUG] || void 0,\n [MIDSCENE_DEBUG_AI_PROFILE]: process.env[MIDSCENE_DEBUG_AI_PROFILE] || void 0,\n [MIDSCENE_DEBUG_AI_RESPONSE]: process.env[MIDSCENE_DEBUG_AI_RESPONSE] || void 0,\n [MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG]: process.env[MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG] || void 0,\n [OPENAI_API_KEY]: process.env[OPENAI_API_KEY] || void 0,\n [OPENAI_BASE_URL]: process.env[OPENAI_BASE_URL] || void 0,\n [OPENAI_MAX_TOKENS]: process.env[OPENAI_MAX_TOKENS] || void 0,\n [OPENAI_USE_AZURE]: process.env[OPENAI_USE_AZURE] || void 0,\n [MIDSCENE_ADB_PATH]: process.env[MIDSCENE_ADB_PATH] || void 0,\n [MIDSCENE_ADB_REMOTE_HOST]: process.env[MIDSCENE_ADB_REMOTE_HOST] || void 0,\n [MIDSCENE_ADB_REMOTE_PORT]: process.env[MIDSCENE_ADB_REMOTE_PORT] || void 0,\n [MIDSCENE_ANDROID_IME_STRATEGY]: process.env[MIDSCENE_ANDROID_IME_STRATEGY] || void 0,\n [MIDSCENE_CACHE]: process.env[MIDSCENE_CACHE] || void 0,\n [MATCH_BY_POSITION]: process.env[MATCH_BY_POSITION] || void 0,\n [MIDSCENE_REPORT_TAG_NAME]: process.env[MIDSCENE_REPORT_TAG_NAME] || void 0,\n [MIDSCENE_OPENAI_SOCKS_PROXY]: process.env[MIDSCENE_OPENAI_SOCKS_PROXY] || void 0,\n [MIDSCENE_OPENAI_HTTP_PROXY]: process.env[MIDSCENE_OPENAI_HTTP_PROXY] || void 0,\n [MIDSCENE_USE_AZURE_OPENAI]: process.env[MIDSCENE_USE_AZURE_OPENAI] || void 0,\n [MIDSCENE_AZURE_OPENAI_SCOPE]: process.env[MIDSCENE_AZURE_OPENAI_SCOPE] || void 0,\n [MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON]: process.env[MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON] || void 0,\n [MIDSCENE_USE_ANTHROPIC_SDK]: process.env[MIDSCENE_USE_ANTHROPIC_SDK] || void 0,\n [MIDSCENE_USE_VLM_UI_TARS]: process.env[MIDSCENE_USE_VLM_UI_TARS] || void 0,\n [MIDSCENE_USE_QWEN_VL]: process.env[MIDSCENE_USE_QWEN_VL] || void 0,\n [MIDSCENE_USE_DOUBAO_VISION]: process.env[MIDSCENE_USE_DOUBAO_VISION] || void 0,\n [MIDSCENE_USE_GEMINI]: process.env[MIDSCENE_USE_GEMINI] || void 0,\n [MIDSCENE_USE_VL_MODEL]: process.env[MIDSCENE_USE_VL_MODEL] || void 0,\n [ANTHROPIC_API_KEY]: process.env[ANTHROPIC_API_KEY] || void 0,\n [AZURE_OPENAI_ENDPOINT]: process.env[AZURE_OPENAI_ENDPOINT] || void 0,\n [AZURE_OPENAI_KEY]: process.env[AZURE_OPENAI_KEY] || void 0,\n [AZURE_OPENAI_API_VERSION]: process.env[AZURE_OPENAI_API_VERSION] || void 0,\n [AZURE_OPENAI_DEPLOYMENT]: process.env[AZURE_OPENAI_DEPLOYMENT] || void 0,\n [MIDSCENE_MCP_USE_PUPPETEER_MODE]: process.env[MIDSCENE_MCP_USE_PUPPETEER_MODE] || void 0,\n [MIDSCENE_RUN_DIR]: process.env[MIDSCENE_RUN_DIR] || void 0,\n [MIDSCENE_PREFERRED_LANGUAGE]: process.env[MIDSCENE_PREFERRED_LANGUAGE] || void 0,\n [MIDSCENE_REPLANNING_CYCLE_LIMIT]: process.env[MIDSCENE_REPLANNING_CYCLE_LIMIT] || void 0,\n [MIDSCENE_CACHE_MAX_FILENAME_LENGTH]: process.env[MIDSCENE_CACHE_MAX_FILENAME_LENGTH] || void 0\n });\nconst getGlobalConfig = ()=>{\n if (!globalThis.midsceneGlobalConfig) globalThis.midsceneGlobalConfig = allConfigFromEnv();\n const envConfig = allConfigFromEnv();\n if (globalThis.midsceneGlobalConfigOverride) {\n const { newConfig, extendMode } = globalThis.midsceneGlobalConfigOverride;\n globalThis.midsceneGlobalConfig = extendMode ? {\n ...envConfig,\n ...newConfig\n } : {\n ...newConfig\n };\n } else globalThis.midsceneGlobalConfig = envConfig;\n return globalThis.midsceneGlobalConfig;\n};\nvar env_UITarsModelVersion = /*#__PURE__*/ function(UITarsModelVersion) {\n UITarsModelVersion[\"V1_0\"] = \"1.0\";\n UITarsModelVersion[\"V1_5\"] = \"1.5\";\n UITarsModelVersion[\"DOUBAO_1_5_15B\"] = \"doubao-1.5-15B\";\n UITarsModelVersion[\"DOUBAO_1_5_20B\"] = \"doubao-1.5-20B\";\n return UITarsModelVersion;\n}({});\nconst uiTarsModelVersion = ()=>{\n if ('vlm-ui-tars' !== vlLocateMode()) return false;\n const versionConfig = getAIConfig(MIDSCENE_USE_VLM_UI_TARS);\n if ('1' === versionConfig || 1 === versionConfig) return \"1.0\";\n if ('DOUBAO' === versionConfig || 'DOUBAO-1.5' === versionConfig) return \"doubao-1.5-20B\";\n return `${versionConfig}`;\n};\nconst vlLocateMode = ()=>{\n const enabledModes = [\n getAIConfigInBoolean(MIDSCENE_USE_DOUBAO_VISION) && 'MIDSCENE_USE_DOUBAO_VISION',\n getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL) && 'MIDSCENE_USE_QWEN_VL',\n getAIConfigInBoolean(MIDSCENE_USE_VLM_UI_TARS) && 'MIDSCENE_USE_VLM_UI_TARS',\n getAIConfigInBoolean(MIDSCENE_USE_GEMINI) && 'MIDSCENE_USE_GEMINI'\n ].filter(Boolean);\n if (enabledModes.length > 1) throw new Error(`Only one vision mode can be enabled at a time. Currently enabled modes: ${enabledModes.join(', ')}. Please disable all but one mode.`);\n if (getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL)) return 'qwen-vl';\n if (getAIConfigInBoolean(MIDSCENE_USE_DOUBAO_VISION)) return 'doubao-vision';\n if (getAIConfigInBoolean(MIDSCENE_USE_GEMINI)) return 'gemini';\n if (getAIConfigInBoolean(MIDSCENE_USE_VL_MODEL)) return 'vl-model';\n if (getAIConfigInBoolean(MIDSCENE_USE_VLM_UI_TARS)) return 'vlm-ui-tars';\n return false;\n};\nconst getAIConfig = (configKey)=>{\n if (configKey === MATCH_BY_POSITION) throw new Error('MATCH_BY_POSITION is deprecated, use MIDSCENE_USE_VL_MODEL instead');\n const value = getGlobalConfig()[configKey];\n if ('string' == typeof value) return value.trim();\n return value;\n};\nconst getAIConfigInBoolean = (configKey)=>{\n const config = getAIConfig(configKey) || '';\n if (/^(true|1)$/i.test(config)) return true;\n if (/^(false|0)$/i.test(config)) return false;\n return !!config.trim();\n};\nconst getAIConfigInNumber = (configKey)=>{\n const config = getAIConfig(configKey) || '';\n return Number(config);\n};\nconst getAIConfigInJson = (configKey)=>{\n const config = getAIConfig(configKey);\n try {\n return config ? JSON.parse(config) : void 0;\n } catch (error) {\n throw new Error(`Failed to parse json config: ${configKey}. ${error.message}`, {\n cause: error\n });\n }\n};\nconst overrideAIConfig = (newConfig, extendMode = false)=>{\n var _globalThis_midsceneGlobalConfigOverride;\n for(const key in newConfig){\n if ('string' != typeof key) throw new Error(`Failed to override AI config, invalid key: ${key}`);\n if ('object' == typeof newConfig[key]) throw new Error(`Failed to override AI config, invalid value for key: ${key}, value: ${newConfig[key]}`);\n }\n const savedNewConfig = extendMode ? {\n ...null == (_globalThis_midsceneGlobalConfigOverride = globalThis.midsceneGlobalConfigOverride) ? void 0 : _globalThis_midsceneGlobalConfigOverride.newConfig,\n ...newConfig\n } : newConfig;\n globalThis.midsceneGlobalConfigOverride = {\n newConfig: savedNewConfig,\n extendMode\n };\n};\nconst getPreferredLanguage = ()=>{\n if (getAIConfig(MIDSCENE_PREFERRED_LANGUAGE)) return getAIConfig(MIDSCENE_PREFERRED_LANGUAGE);\n const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n const isChina = 'Asia/Shanghai' === timeZone;\n return isChina ? 'Chinese' : 'English';\n};\nexport { ANTHROPIC_API_KEY, AZURE_OPENAI_API_VERSION, AZURE_OPENAI_DEPLOYMENT, AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_KEY, MATCH_BY_POSITION, MIDSCENE_ADB_PATH, MIDSCENE_ADB_REMOTE_HOST, MIDSCENE_ADB_REMOTE_PORT, MIDSCENE_ANDROID_IME_STRATEGY, MIDSCENE_API_TYPE, MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_AZURE_OPENAI_SCOPE, MIDSCENE_CACHE, MIDSCENE_CACHE_MAX_FILENAME_LENGTH, MIDSCENE_DANGEROUSLY_PRINT_ALL_CONFIG, MIDSCENE_DEBUG_AI_PROFILE, MIDSCENE_DEBUG_AI_RESPONSE, MIDSCENE_DEBUG_MODE, MIDSCENE_FORCE_DEEP_THINK, MIDSCENE_LANGSMITH_DEBUG, MIDSCENE_MCP_ANDROID_MODE, MIDSCENE_MCP_USE_PUPPETEER_MODE, MIDSCENE_MODEL_NAME, MIDSCENE_OPENAI_HTTP_PROXY, MIDSCENE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_OPENAI_SOCKS_PROXY, MIDSCENE_PREFERRED_LANGUAGE, MIDSCENE_REPLANNING_CYCLE_LIMIT, MIDSCENE_REPORT_TAG_NAME, MIDSCENE_RUN_DIR, MIDSCENE_USE_ANTHROPIC_SDK, MIDSCENE_USE_AZURE_OPENAI, MIDSCENE_USE_DOUBAO_VISION, MIDSCENE_USE_GEMINI, MIDSCENE_USE_QWEN_VL, MIDSCENE_USE_VLM_UI_TARS, MIDSCENE_USE_VL_MODEL, OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MAX_TOKENS, OPENAI_USE_AZURE, env_UITarsModelVersion as UITarsModelVersion, allConfigFromEnv, getAIConfig, getAIConfigInBoolean, getAIConfigInJson, getAIConfigInNumber, getPreferredLanguage, overrideAIConfig, uiTarsModelVersion, vlLocateMode };\n","import { create } from \"zustand\";\nvar __webpack_require__ = {};\n(()=>{\n __webpack_require__.d = (exports, definition)=>{\n for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {\n enumerable: true,\n get: definition[key]\n });\n };\n})();\n(()=>{\n __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);\n})();\n(()=>{\n __webpack_require__.r = (exports)=>{\n if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {\n value: 'Module'\n });\n Object.defineProperty(exports, '__esModule', {\n value: true\n });\n };\n})();\nvar external_zustand_namespaceObject = {};\n__webpack_require__.r(external_zustand_namespaceObject);\n__webpack_require__.d(external_zustand_namespaceObject, {\n create: ()=>create\n});\nconst { create: store_create } = external_zustand_namespaceObject;\nconst useBlackboardPreference = store_create((set)=>({\n markerVisible: true,\n elementsVisible: true,\n setMarkerVisible: (visible)=>{\n set({\n markerVisible: visible\n });\n },\n setTextsVisible: (visible)=>{\n set({\n elementsVisible: visible\n });\n }\n }));\nconst CONFIG_KEY = 'midscene-env-config';\nconst SERVICE_MODE_KEY = 'midscene-service-mode';\nconst TRACKING_ACTIVE_TAB_KEY = 'midscene-tracking-active-tab';\nconst DEEP_THINK_KEY = 'midscene-deep-think';\nconst getConfigStringFromLocalStorage = ()=>{\n const configString = localStorage.getItem(CONFIG_KEY);\n return configString || '';\n};\nconst parseConfig = (configString)=>{\n const lines = configString.split('\\n');\n const config = {};\n lines.forEach((line)=>{\n const trimmed = line.trim();\n if (trimmed.startsWith('#')) return;\n const cleanLine = trimmed.replace(/^export\\s+/i, '').replace(/;$/, '').trim();\n const match = cleanLine.match(/^(\\w+)=(.*)$/);\n if (match) {\n const [, key, value] = match;\n let parsedValue = value.trim();\n if (parsedValue.startsWith(\"'\") && parsedValue.endsWith(\"'\") || parsedValue.startsWith('\"') && parsedValue.endsWith('\"')) parsedValue = parsedValue.slice(1, -1);\n config[key] = parsedValue;\n }\n });\n return config;\n};\nconst useEnvConfig = store_create((set, get)=>{\n const configString = getConfigStringFromLocalStorage();\n const config = parseConfig(configString);\n const ifInExtension = window.location.href.startsWith('chrome-extension');\n const savedServiceMode = localStorage.getItem(SERVICE_MODE_KEY);\n const savedForceSameTabNavigation = 'false' !== localStorage.getItem(TRACKING_ACTIVE_TAB_KEY);\n const savedDeepThink = 'true' === localStorage.getItem(DEEP_THINK_KEY);\n return {\n serviceMode: ifInExtension ? 'In-Browser-Extension' : savedServiceMode || 'Server',\n setServiceMode: (serviceMode)=>{\n if (ifInExtension) throw new Error('serviceMode cannot be set in extension');\n set({\n serviceMode\n });\n localStorage.setItem(SERVICE_MODE_KEY, serviceMode);\n },\n config,\n configString,\n setConfig: (config)=>set({\n config\n }),\n loadConfig: (configString)=>{\n const config = parseConfig(configString);\n set({\n config,\n configString\n });\n localStorage.setItem(CONFIG_KEY, configString);\n },\n syncFromStorage: ()=>{\n const latestConfigString = getConfigStringFromLocalStorage();\n const latestConfig = parseConfig(latestConfigString);\n set({\n config: latestConfig,\n configString: latestConfigString\n });\n },\n forceSameTabNavigation: savedForceSameTabNavigation,\n setForceSameTabNavigation: (forceSameTabNavigation)=>{\n set({\n forceSameTabNavigation\n });\n localStorage.setItem(TRACKING_ACTIVE_TAB_KEY, forceSameTabNavigation.toString());\n },\n deepThink: savedDeepThink,\n setDeepThink: (deepThink)=>{\n set({\n deepThink\n });\n localStorage.setItem(DEEP_THINK_KEY, deepThink.toString());\n },\n popupTab: 'playground',\n setPopupTab: (tab)=>{\n set({\n popupTab: tab\n });\n }\n };\n});\nexport { useBlackboardPreference, useEnvConfig };\n","import { existsSync, mkdirSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport node_path from \"node:path\";\nimport { MIDSCENE_RUN_DIR, getAIConfig } from \"./env.mjs\";\nimport { ifInNode } from \"./utils.mjs\";\nconst defaultRunDirName = 'midscene_run';\nconst getMidsceneRunDir = ()=>{\n if (!ifInNode) return '';\n return getAIConfig(MIDSCENE_RUN_DIR) || defaultRunDirName;\n};\nconst getMidsceneRunBaseDir = ()=>{\n if (!ifInNode) return '';\n let basePath = node_path.resolve(process.cwd(), getMidsceneRunDir());\n if (!existsSync(basePath)) try {\n mkdirSync(basePath, {\n recursive: true\n });\n } catch (error) {\n basePath = node_path.join(tmpdir(), defaultRunDirName);\n mkdirSync(basePath, {\n recursive: true\n });\n }\n return basePath;\n};\nconst getMidsceneRunSubDir = (subdir)=>{\n if (!ifInNode) return '';\n const basePath = getMidsceneRunBaseDir();\n const logPath = node_path.join(basePath, subdir);\n if (!existsSync(logPath)) mkdirSync(logPath, {\n recursive: true\n });\n return logPath;\n};\nexport { defaultRunDirName, getMidsceneRunBaseDir, getMidsceneRunDir, getMidsceneRunSubDir };\n","import node_fs from \"node:fs\";\nimport node_path from \"node:path\";\nimport node_util from \"node:util\";\nimport debug from \"debug\";\nimport { getMidsceneRunSubDir } from \"./common.mjs\";\nimport { ifInNode } from \"./utils.mjs\";\nconst topicPrefix = 'midscene';\nconst logStreams = new Map();\nconst debugInstances = new Map();\nfunction getLogStream(topic) {\n const topicFileName = topic.replace(/:/g, '-');\n if (!logStreams.has(topicFileName)) {\n const logFile = node_path.join(getMidsceneRunSubDir('log'), `${topicFileName}.log`);\n const stream = node_fs.createWriteStream(logFile, {\n flags: 'a'\n });\n logStreams.set(topicFileName, stream);\n }\n return logStreams.get(topicFileName);\n}\nfunction writeLogToFile(topic, message) {\n if (!ifInNode) return;\n const stream = getLogStream(topic);\n const now = new Date();\n const isoDate = now.toLocaleDateString('sv-SE');\n const isoTime = now.toLocaleTimeString('sv-SE');\n const milliseconds = now.getMilliseconds().toString().padStart(3, '0');\n const timezoneOffsetMinutes = now.getTimezoneOffset();\n const sign = timezoneOffsetMinutes <= 0 ? '+' : '-';\n const hours = Math.floor(Math.abs(timezoneOffsetMinutes) / 60).toString().padStart(2, '0');\n const minutes = (Math.abs(timezoneOffsetMinutes) % 60).toString().padStart(2, '0');\n const timezoneString = `${sign}${hours}:${minutes}`;\n const localISOTime = `${isoDate}T${isoTime}.${milliseconds}${timezoneString}`;\n stream.write(`[${localISOTime}] ${message}\\n`);\n}\nfunction getDebug(topic) {\n const fullTopic = `${topicPrefix}:${topic}`;\n if (!debugInstances.has(fullTopic)) {\n const debugFn = debug(fullTopic);\n const wrapper = (...args)=>{\n if (ifInNode) {\n const message = node_util.format(...args);\n writeLogToFile(topic, message);\n }\n debugFn(...args);\n };\n debugInstances.set(fullTopic, wrapper);\n }\n return debugInstances.get(fullTopic);\n}\nfunction enableDebug(topic) {\n if (ifInNode) return;\n debug.enable(`${topicPrefix}:${topic}`);\n}\nfunction cleanupLogStreams() {\n if (!ifInNode) return;\n for (const stream of logStreams.values())stream.end();\n logStreams.clear();\n debugInstances.clear();\n}\nexport { cleanupLogStreams, enableDebug, getDebug };\n","import node_assert from \"node:assert\";\nimport { Buffer } from \"node:buffer\";\nimport { readFileSync } from \"node:fs\";\nimport node_path from \"node:path\";\nimport { getDebug } from \"../logger.mjs\";\nimport { ifInNode } from \"../utils.mjs\";\nimport get_jimp from \"./get-jimp.mjs\";\nimport get_photon from \"./get-photon.mjs\";\nimport get_sharp from \"./get-sharp.mjs\";\nconst imgDebug = getDebug('img');\nasync function saveBase64Image(options) {\n const { base64Data, outputPath } = options;\n const base64Image = base64Data.split(';base64,').pop() || base64Data;\n const imageBuffer = Buffer.from(base64Image, 'base64');\n const Jimp = await get_jimp();\n const image = await Jimp.read(imageBuffer);\n await image.writeAsync(outputPath);\n}\nasync function transformImgPathToBase64(inputPath) {\n const Jimp = await get_jimp();\n const image = await Jimp.read(inputPath);\n const buffer = await image.getBufferAsync(Jimp.MIME_JPEG);\n const res = buffer.toString('base64');\n return res;\n}\nasync function resizeImg(inputData, newSize) {\n if ('string' == typeof inputData) throw Error('inputData is base64, use resizeImgBase64 instead');\n node_assert(newSize && newSize.width > 0 && newSize.height > 0, 'newSize must be positive');\n const resizeStartTime = Date.now();\n imgDebug(`resizeImg start, target size: ${newSize.width}x${newSize.height}`);\n if (ifInNode) try {\n const Sharp = await get_sharp();\n const metadata = await Sharp(inputData).metadata();\n const { width: originalWidth, height: originalHeight } = metadata;\n if (!originalWidth || !originalHeight) throw Error('Undefined width or height from the input image.');\n if (newSize.width === originalWidth && newSize.height === originalHeight) return inputData;\n const resizedBuffer = await Sharp(inputData).resize(newSize.width, newSize.height).jpeg({\n quality: 90\n }).toBuffer();\n const resizeEndTime = Date.now();\n imgDebug(`resizeImg done (Sharp), target size: ${newSize.width}x${newSize.height}, cost: ${resizeEndTime - resizeStartTime}ms`);\n return resizedBuffer;\n } catch (error) {\n imgDebug('Sharp failed, falling back to Photon:', error);\n }\n const { PhotonImage, SamplingFilter, resize } = await get_photon();\n const inputBytes = new Uint8Array(inputData);\n const inputImage = PhotonImage.new_from_byteslice(inputBytes);\n const originalWidth = inputImage.get_width();\n const originalHeight = inputImage.get_height();\n if (!originalWidth || !originalHeight) {\n inputImage.free();\n throw Error('Undefined width or height from the input image.');\n }\n if (newSize.width === originalWidth && newSize.height === originalHeight) {\n inputImage.free();\n return inputData;\n }\n const outputImage = resize(inputImage, newSize.width, newSize.height, SamplingFilter.CatmullRom);\n const outputBytes = outputImage.get_bytes_jpeg(90);\n const resizedBuffer = Buffer.from(outputBytes);\n inputImage.free();\n outputImage.free();\n const resizeEndTime = Date.now();\n imgDebug(`resizeImg done (Photon), target size: ${newSize.width}x${newSize.height}, cost: ${resizeEndTime - resizeStartTime}ms`);\n return resizedBuffer;\n}\nasync function bufferFromBase64(base64) {\n const splitFlag = ';base64,';\n const dataSplitted = base64.split(splitFlag);\n if (2 !== dataSplitted.length) throw Error('Invalid base64 data');\n const res = Buffer.from(dataSplitted[1], 'base64');\n return res;\n}\nasync function resizeImgBase64(inputBase64, newSize) {\n const splitFlag = ';base64,';\n const dataSplitted = inputBase64.split(splitFlag);\n if (2 !== dataSplitted.length) throw Error('Invalid base64 data');\n const imageBuffer = Buffer.from(dataSplitted[1], 'base64');\n const buffer = await resizeImg(imageBuffer, newSize);\n const content = buffer.toString('base64');\n const res = `${dataSplitted[0]}${splitFlag}${content}`;\n return res;\n}\nfunction zoomForGPT4o(originalWidth, originalHeight) {\n const maxWidth = 2048;\n const maxHeight = 768;\n let newWidth = originalWidth;\n let newHeight = originalHeight;\n const aspectRatio = originalWidth / originalHeight;\n if (originalWidth > maxWidth) {\n newWidth = maxWidth;\n newHeight = newWidth / aspectRatio;\n }\n if (newHeight > maxHeight) {\n newHeight = maxHeight;\n newWidth = newHeight * aspectRatio;\n }\n return {\n width: Math.round(newWidth),\n height: Math.round(newHeight)\n };\n}\nasync function jimpFromBase64(base64) {\n const Jimp = await get_jimp();\n const imageBuffer = await bufferFromBase64(base64);\n return Jimp.read(imageBuffer);\n}\nasync function paddingToMatchBlock(image, blockSize = 28) {\n const { width, height } = image.bitmap;\n const targetWidth = Math.ceil(width / blockSize) * blockSize;\n const targetHeight = Math.ceil(height / blockSize) * blockSize;\n if (targetWidth === width && targetHeight === height) return image;\n const Jimp = await get_jimp();\n const paddedImage = new Jimp(targetWidth, targetHeight, 0xffffffff);\n paddedImage.composite(image, 0, 0);\n return paddedImage;\n}\nasync function paddingToMatchBlockByBase64(imageBase64, blockSize = 28) {\n const jimpImage = await jimpFromBase64(imageBase64);\n const paddedImage = await paddingToMatchBlock(jimpImage, blockSize);\n return jimpToBase64(paddedImage);\n}\nasync function cropByRect(imageBase64, rect, paddingImage) {\n const jimpImage = await jimpFromBase64(imageBase64);\n const { left, top, width, height } = rect;\n jimpImage.crop(left, top, width, height);\n if (paddingImage) {\n const paddedImage = await paddingToMatchBlock(jimpImage);\n return jimpToBase64(paddedImage);\n }\n return jimpToBase64(jimpImage);\n}\nasync function jimpToBase64(image) {\n const Jimp = await get_jimp();\n return image.getBase64Async(Jimp.MIME_JPEG);\n}\nconst httpImg2Base64 = async (url)=>{\n const response = await fetch(url);\n if (!response.ok) throw new Error(`Failed to fetch image: ${url}`);\n const contentType = response.headers.get('content-type');\n if (!contentType) throw new Error(`Failed to fetch image: ${url}`);\n node_assert(contentType.startsWith('image/'), `The url ${url} is not a image, because of content-type in header is ${contentType}.`);\n const buffer = Buffer.from(await response.arrayBuffer());\n return `data:${contentType};base64,${buffer.toString('base64')}`;\n};\nconst localImg2Base64 = (imgPath, withoutHeader = false)=>{\n const body = readFileSync(imgPath).toString('base64');\n if (withoutHeader) return body;\n const type = node_path.extname(imgPath).slice(1);\n const finalType = 'svg' === type ? 'svg+xml' : type || 'jpg';\n return `data:image/${finalType};base64,${body}`;\n};\nconst preProcessImageUrl = async (url, convertHttpImage2Base64)=>{\n if (url.startsWith('data:')) return url;\n if (!(url.startsWith('http://') || url.startsWith('https://'))) return await localImg2Base64(url);\n if (!convertHttpImage2Base64) return url;\n return await httpImg2Base64(url);\n};\nexport { bufferFromBase64, cropByRect, httpImg2Base64, jimpFromBase64, jimpToBase64, localImg2Base64, paddingToMatchBlock, paddingToMatchBlockByBase64, preProcessImageUrl, resizeImg, resizeImgBase64, saveBase64Image, transformImgPathToBase64, zoomForGPT4o };\n","/*! For license information please see us-keyboard-layout.mjs.LICENSE.txt */\n/**\n * @license\n * Copyright 2017 Google Inc.\n * SPDX-License-Identifier: Apache-2.0\n */ const _keyDefinitions = {\n 0: {\n keyCode: 48,\n key: '0',\n code: 'Digit0'\n },\n 1: {\n keyCode: 49,\n key: '1',\n code: 'Digit1'\n },\n 2: {\n keyCode: 50,\n key: '2',\n code: 'Digit2'\n },\n 3: {\n keyCode: 51,\n key: '3',\n code: 'Digit3'\n },\n 4: {\n keyCode: 52,\n key: '4',\n code: 'Digit4'\n },\n 5: {\n keyCode: 53,\n key: '5',\n code: 'Digit5'\n },\n 6: {\n keyCode: 54,\n key: '6',\n code: 'Digit6'\n },\n 7: {\n keyCode: 55,\n key: '7',\n code: 'Digit7'\n },\n 8: {\n keyCode: 56,\n key: '8',\n code: 'Digit8'\n },\n 9: {\n keyCode: 57,\n key: '9',\n code: 'Digit9'\n },\n Power: {\n key: 'Power',\n code: 'Power'\n },\n Eject: {\n key: 'Eject',\n code: 'Eject'\n },\n Abort: {\n keyCode: 3,\n code: 'Abort',\n key: 'Cancel'\n },\n Help: {\n keyCode: 6,\n code: 'Help',\n key: 'Help'\n },\n Backspace: {\n keyCode: 8,\n code: 'Backspace',\n key: 'Backspace'\n },\n Tab: {\n keyCode: 9,\n code: 'Tab',\n key: 'Tab'\n },\n Numpad5: {\n keyCode: 12,\n shiftKeyCode: 101,\n key: 'Clear',\n code: 'Numpad5',\n shiftKey: '5',\n location: 3\n },\n NumpadEnter: {\n keyCode: 13,\n code: 'NumpadEnter',\n key: 'Enter',\n text: '\\r',\n location: 3\n },\n Enter: {\n keyCode: 13,\n code: 'Enter',\n key: 'Enter',\n text: '\\r'\n },\n '\\r': {\n keyCode: 13,\n code: 'Enter',\n key: 'Enter',\n text: '\\r'\n },\n '\\n': {\n keyCode: 13,\n code: 'Enter',\n key: 'Enter',\n text: '\\r'\n },\n ShiftLeft: {\n keyCode: 16,\n code: 'ShiftLeft',\n key: 'Shift',\n location: 1\n },\n ShiftRight: {\n keyCode: 16,\n code: 'ShiftRight',\n key: 'Shift',\n location: 2\n },\n ControlLeft: {\n keyCode: 17,\n code: 'ControlLeft',\n key: 'Control',\n location: 1\n },\n ControlRight: {\n keyCode: 17,\n code: 'ControlRight',\n key: 'Control',\n location: 2\n },\n AltLeft: {\n keyCode: 18,\n code: 'AltLeft',\n key: 'Alt',\n location: 1\n },\n AltRight: {\n keyCode: 18,\n code: 'AltRight',\n key: 'Alt',\n location: 2\n },\n Pause: {\n keyCode: 19,\n code: 'Pause',\n key: 'Pause'\n },\n CapsLock: {\n keyCode: 20,\n code: 'CapsLock',\n key: 'CapsLock'\n },\n Escape: {\n keyCode: 27,\n code: 'Escape',\n key: 'Escape'\n },\n Convert: {\n keyCode: 28,\n code: 'Convert',\n key: 'Convert'\n },\n NonConvert: {\n keyCode: 29,\n code: 'NonConvert',\n key: 'NonConvert'\n },\n Space: {\n keyCode: 32,\n code: 'Space',\n key: ' '\n },\n Numpad9: {\n keyCode: 33,\n shiftKeyCode: 105,\n key: 'PageUp',\n code: 'Numpad9',\n shiftKey: '9',\n location: 3\n },\n PageUp: {\n keyCode: 33,\n code: 'PageUp',\n key: 'PageUp'\n },\n Numpad3: {\n keyCode: 34,\n shiftKeyCode: 99,\n key: 'PageDown',\n code: 'Numpad3',\n shiftKey: '3',\n location: 3\n },\n PageDown: {\n keyCode: 34,\n code: 'PageDown',\n key: 'PageDown'\n },\n End: {\n keyCode: 35,\n code: 'End',\n key: 'End'\n },\n Numpad1: {\n keyCode: 35,\n shiftKeyCode: 97,\n key: 'End',\n code: 'Numpad1',\n shiftKey: '1',\n location: 3\n },\n Home: {\n keyCode: 36,\n code: 'Home',\n key: 'Home'\n },\n Numpad7: {\n keyCode: 36,\n shiftKeyCode: 103,\n key: 'Home',\n code: 'Numpad7',\n shiftKey: '7',\n location: 3\n },\n ArrowLeft: {\n keyCode: 37,\n code: 'ArrowLeft',\n key: 'ArrowLeft'\n },\n Numpad4: {\n keyCode: 37,\n shiftKeyCode: 100,\n key: 'ArrowLeft',\n code: 'Numpad4',\n shiftKey: '4',\n location: 3\n },\n Numpad8: {\n keyCode: 38,\n shiftKeyCode: 104,\n key: 'ArrowUp',\n code: 'Numpad8',\n shiftKey: '8',\n location: 3\n },\n ArrowUp: {\n keyCode: 38,\n code: 'ArrowUp',\n key: 'ArrowUp'\n },\n ArrowRight: {\n keyCode: 39,\n code: 'ArrowRight',\n key: 'ArrowRight'\n },\n Numpad6: {\n keyCode: 39,\n shiftKeyCode: 102,\n key: 'ArrowRight',\n code: 'Numpad6',\n shiftKey: '6',\n location: 3\n },\n Numpad2: {\n keyCode: 40,\n shiftKeyCode: 98,\n key: 'ArrowDown',\n code: 'Numpad2',\n shiftKey: '2',\n location: 3\n },\n ArrowDown: {\n keyCode: 40,\n code: 'ArrowDown',\n key: 'ArrowDown'\n },\n Select: {\n keyCode: 41,\n code: 'Select',\n key: 'Select'\n },\n Open: {\n keyCode: 43,\n code: 'Open',\n key: 'Execute'\n },\n PrintScreen: {\n keyCode: 44,\n code: 'PrintScreen',\n key: 'PrintScreen'\n },\n Insert: {\n keyCode: 45,\n code: 'Insert',\n key: 'Insert'\n },\n Numpad0: {\n keyCode: 45,\n shiftKeyCode: 96,\n key: 'Insert',\n code: 'Numpad0',\n shiftKey: '0',\n location: 3\n },\n Delete: {\n keyCode: 46,\n code: 'Delete',\n key: 'Delete'\n },\n NumpadDecimal: {\n keyCode: 46,\n shiftKeyCode: 110,\n code: 'NumpadDecimal',\n key: '\\u0000',\n shiftKey: '.',\n location: 3\n },\n Digit0: {\n keyCode: 48,\n code: 'Digit0',\n shiftKey: ')',\n key: '0'\n },\n Digit1: {\n keyCode: 49,\n code: 'Digit1',\n shiftKey: '!',\n key: '1'\n },\n Digit2: {\n keyCode: 50,\n code: 'Digit2',\n shiftKey: '@',\n key: '2'\n },\n Digit3: {\n keyCode: 51,\n code: 'Digit3',\n shiftKey: '#',\n key: '3'\n },\n Digit4: {\n keyCode: 52,\n code: 'Digit4',\n shiftKey: '$',\n key: '4'\n },\n Digit5: {\n keyCode: 53,\n code: 'Digit5',\n shiftKey: '%',\n key: '5'\n },\n Digit6: {\n keyCode: 54,\n code: 'Digit6',\n shiftKey: '^',\n key: '6'\n },\n Digit7: {\n keyCode: 55,\n code: 'Digit7',\n shiftKey: '&',\n key: '7'\n },\n Digit8: {\n keyCode: 56,\n code: 'Digit8',\n shiftKey: '*',\n key: '8'\n },\n Digit9: {\n keyCode: 57,\n code: 'Digit9',\n shiftKey: '(',\n key: '9'\n },\n KeyA: {\n keyCode: 65,\n code: 'KeyA',\n shiftKey: 'A',\n key: 'a'\n },\n KeyB: {\n keyCode: 66,\n code: 'KeyB',\n shiftKey: 'B',\n key: 'b'\n },\n KeyC: {\n keyCode: 67,\n code: 'KeyC',\n shiftKey: 'C',\n key: 'c'\n },\n KeyD: {\n keyCode: 68,\n code: 'KeyD',\n shiftKey: 'D',\n key: 'd'\n },\n KeyE: {\n keyCode: 69,\n code: 'KeyE',\n shiftKey: 'E',\n key: 'e'\n },\n KeyF: {\n keyCode: 70,\n code: 'KeyF',\n shiftKey: 'F',\n key: 'f'\n },\n KeyG: {\n keyCode: 71,\n code: 'KeyG',\n shiftKey: 'G',\n key: 'g'\n },\n KeyH: {\n keyCode: 72,\n code: 'KeyH',\n shiftKey: 'H',\n key: 'h'\n },\n KeyI: {\n keyCode: 73,\n code: 'KeyI',\n shiftKey: 'I',\n key: 'i'\n },\n KeyJ: {\n keyCode: 74,\n code: 'KeyJ',\n shiftKey: 'J',\n key: 'j'\n },\n KeyK: {\n keyCode: 75,\n code: 'KeyK',\n shiftKey: 'K',\n key: 'k'\n },\n KeyL: {\n keyCode: 76,\n code: 'KeyL',\n shiftKey: 'L',\n key: 'l'\n },\n KeyM: {\n keyCode: 77,\n code: 'KeyM',\n shiftKey: 'M',\n key: 'm'\n },\n KeyN: {\n keyCode: 78,\n code: 'KeyN',\n shiftKey: 'N',\n key: 'n'\n },\n KeyO: {\n keyCode: 79,\n code: 'KeyO',\n shiftKey: 'O',\n key: 'o'\n },\n KeyP: {\n keyCode: 80,\n code: 'KeyP',\n shiftKey: 'P',\n key: 'p'\n },\n KeyQ: {\n keyCode: 81,\n code: 'KeyQ',\n shiftKey: 'Q',\n key: 'q'\n },\n KeyR: {\n keyCode: 82,\n code: 'KeyR',\n shiftKey: 'R',\n key: 'r'\n },\n KeyS: {\n keyCode: 83,\n code: 'KeyS',\n shiftKey: 'S',\n key: 's'\n },\n KeyT: {\n keyCode: 84,\n code: 'KeyT',\n shiftKey: 'T',\n key: 't'\n },\n KeyU: {\n keyCode: 85,\n code: 'KeyU',\n shiftKey: 'U',\n key: 'u'\n },\n KeyV: {\n keyCode: 86,\n code: 'KeyV',\n shiftKey: 'V',\n key: 'v'\n },\n KeyW: {\n keyCode: 87,\n code: 'KeyW',\n shiftKey: 'W',\n key: 'w'\n },\n KeyX: {\n keyCode: 88,\n code: 'KeyX',\n shiftKey: 'X',\n key: 'x'\n },\n KeyY: {\n keyCode: 89,\n code: 'KeyY',\n shiftKey: 'Y',\n key: 'y'\n },\n KeyZ: {\n keyCode: 90,\n code: 'KeyZ',\n shiftKey: 'Z',\n key: 'z'\n },\n MetaLeft: {\n keyCode: 91,\n code: 'MetaLeft',\n key: 'Meta',\n location: 1\n },\n MetaRight: {\n keyCode: 92,\n code: 'MetaRight',\n key: 'Meta',\n location: 2\n },\n ContextMenu: {\n keyCode: 93,\n code: 'ContextMenu',\n key: 'ContextMenu'\n },\n NumpadMultiply: {\n keyCode: 106,\n code: 'NumpadMultiply',\n key: '*',\n location: 3\n },\n NumpadAdd: {\n keyCode: 107,\n code: 'NumpadAdd',\n key: '+',\n location: 3\n },\n NumpadSubtract: {\n keyCode: 109,\n code: 'NumpadSubtract',\n key: '-',\n location: 3\n },\n NumpadDivide: {\n keyCode: 111,\n code: 'NumpadDivide',\n key: '/',\n location: 3\n },\n F1: {\n keyCode: 112,\n code: 'F1',\n key: 'F1'\n },\n F2: {\n keyCode: 113,\n code: 'F2',\n key: 'F2'\n },\n F3: {\n keyCode: 114,\n code: 'F3',\n key: 'F3'\n },\n F4: {\n keyCode: 115,\n code: 'F4',\n key: 'F4'\n },\n F5: {\n keyCode: 116,\n code: 'F5',\n key: 'F5'\n },\n F6: {\n keyCode: 117,\n code: 'F6',\n key: 'F6'\n },\n F7: {\n keyCode: 118,\n code: 'F7',\n key: 'F7'\n },\n F8: {\n keyCode: 119,\n code: 'F8',\n key: 'F8'\n },\n F9: {\n keyCode: 120,\n code: 'F9',\n key: 'F9'\n },\n F10: {\n keyCode: 121,\n code: 'F10',\n key: 'F10'\n },\n F11: {\n keyCode: 122,\n code: 'F11',\n key: 'F11'\n },\n F12: {\n keyCode: 123,\n code: 'F12',\n key: 'F12'\n },\n F13: {\n keyCode: 124,\n code: 'F13',\n key: 'F13'\n },\n F14: {\n keyCode: 125,\n code: 'F14',\n key: 'F14'\n },\n F15: {\n keyCode: 126,\n code: 'F15',\n key: 'F15'\n },\n F16: {\n keyCode: 127,\n code: 'F16',\n key: 'F16'\n },\n F17: {\n keyCode: 128,\n code: 'F17',\n key: 'F17'\n },\n F18: {\n keyCode: 129,\n code: 'F18',\n key: 'F18'\n },\n F19: {\n keyCode: 130,\n code: 'F19',\n key: 'F19'\n },\n F20: {\n keyCode: 131,\n code: 'F20',\n key: 'F20'\n },\n F21: {\n keyCode: 132,\n code: 'F21',\n key: 'F21'\n },\n F22: {\n keyCode: 133,\n code: 'F22',\n key: 'F22'\n },\n F23: {\n keyCode: 134,\n code: 'F23',\n key: 'F23'\n },\n F24: {\n keyCode: 135,\n code: 'F24',\n key: 'F24'\n },\n NumLock: {\n keyCode: 144,\n code: 'NumLock',\n key: 'NumLock'\n },\n ScrollLock: {\n keyCode: 145,\n code: 'ScrollLock',\n key: 'ScrollLock'\n },\n AudioVolumeMute: {\n keyCode: 173,\n code: 'AudioVolumeMute',\n key: 'AudioVolumeMute'\n },\n AudioVolumeDown: {\n keyCode: 174,\n code: 'AudioVolumeDown',\n key: 'AudioVolumeDown'\n },\n AudioVolumeUp: {\n keyCode: 175,\n code: 'AudioVolumeUp',\n key: 'AudioVolumeUp'\n },\n MediaTrackNext: {\n keyCode: 176,\n code: 'MediaTrackNext',\n key: 'MediaTrackNext'\n },\n MediaTrackPrevious: {\n keyCode: 177,\n code: 'MediaTrackPrevious',\n key: 'MediaTrackPrevious'\n },\n MediaStop: {\n keyCode: 178,\n code: 'MediaStop',\n key: 'MediaStop'\n },\n MediaPlayPause: {\n keyCode: 179,\n code: 'MediaPlayPause',\n key: 'MediaPlayPause'\n },\n Semicolon: {\n keyCode: 186,\n code: 'Semicolon',\n shiftKey: ':',\n key: ';'\n },\n Equal: {\n keyCode: 187,\n code: 'Equal',\n shiftKey: '+',\n key: '='\n },\n NumpadEqual: {\n keyCode: 187,\n code: 'NumpadEqual',\n key: '=',\n location: 3\n },\n Comma: {\n keyCode: 188,\n code: 'Comma',\n shiftKey: '<',\n key: ','\n },\n Minus: {\n keyCode: 189,\n code: 'Minus',\n shiftKey: '_',\n key: '-'\n },\n Period: {\n keyCode: 190,\n code: 'Period',\n shiftKey: '>',\n key: '.'\n },\n Slash: {\n keyCode: 191,\n code: 'Slash',\n shiftKey: '?',\n key: '/'\n },\n Backquote: {\n keyCode: 192,\n code: 'Backquote',\n shiftKey: '~',\n key: '`'\n },\n BracketLeft: {\n keyCode: 219,\n code: 'BracketLeft',\n shiftKey: '{',\n key: '['\n },\n Backslash: {\n keyCode: 220,\n code: 'Backslash',\n shiftKey: '|',\n key: '\\\\'\n },\n BracketRight: {\n keyCode: 221,\n code: 'BracketRight',\n shiftKey: '}',\n key: ']'\n },\n Quote: {\n keyCode: 222,\n code: 'Quote',\n shiftKey: '\"',\n key: \"'\"\n },\n AltGraph: {\n keyCode: 225,\n code: 'AltGraph',\n key: 'AltGraph'\n },\n Props: {\n keyCode: 247,\n code: 'Props',\n key: 'CrSel'\n },\n Cancel: {\n keyCode: 3,\n key: 'Cancel',\n code: 'Abort'\n },\n Clear: {\n keyCode: 12,\n key: 'Clear',\n code: 'Numpad5',\n location: 3\n },\n Shift: {\n keyCode: 16,\n key: 'Shift',\n code: 'ShiftLeft',\n location: 1\n },\n Control: {\n keyCode: 17,\n key: 'Control',\n code: 'ControlLeft',\n location: 1\n },\n Alt: {\n keyCode: 18,\n key: 'Alt',\n code: 'AltLeft',\n location: 1\n },\n Accept: {\n keyCode: 30,\n key: 'Accept'\n },\n ModeChange: {\n keyCode: 31,\n key: 'ModeChange'\n },\n ' ': {\n keyCode: 32,\n key: ' ',\n code: 'Space'\n },\n Print: {\n keyCode: 42,\n key: 'Print'\n },\n Execute: {\n keyCode: 43,\n key: 'Execute',\n code: 'Open'\n },\n '\\u0000': {\n keyCode: 46,\n key: '\\u0000',\n code: 'NumpadDecimal',\n location: 3\n },\n a: {\n keyCode: 65,\n key: 'a',\n code: 'KeyA'\n },\n b: {\n keyCode: 66,\n key: 'b',\n code: 'KeyB'\n },\n c: {\n keyCode: 67,\n key: 'c',\n code: 'KeyC'\n },\n d: {\n keyCode: 68,\n key: 'd',\n code: 'KeyD'\n },\n e: {\n keyCode: 69,\n key: 'e',\n code: 'KeyE'\n },\n f: {\n keyCode: 70,\n key: 'f',\n code: 'KeyF'\n },\n g: {\n keyCode: 71,\n key: 'g',\n code: 'KeyG'\n },\n h: {\n keyCode: 72,\n key: 'h',\n code: 'KeyH'\n },\n i: {\n keyCode: 73,\n key: 'i',\n code: 'KeyI'\n },\n j: {\n keyCode: 74,\n key: 'j',\n code: 'KeyJ'\n },\n k: {\n keyCode: 75,\n key: 'k',\n code: 'KeyK'\n },\n l: {\n keyCode: 76,\n key: 'l',\n code: 'KeyL'\n },\n m: {\n keyCode: 77,\n key: 'm',\n code: 'KeyM'\n },\n n: {\n keyCode: 78,\n key: 'n',\n code: 'KeyN'\n },\n o: {\n keyCode: 79,\n key: 'o',\n code: 'KeyO'\n },\n p: {\n keyCode: 80,\n key: 'p',\n code: 'KeyP'\n },\n q: {\n keyCode: 81,\n key: 'q',\n code: 'KeyQ'\n },\n r: {\n keyCode: 82,\n key: 'r',\n code: 'KeyR'\n },\n s: {\n keyCode: 83,\n key: 's',\n code: 'KeyS'\n },\n t: {\n keyCode: 84,\n key: 't',\n code: 'KeyT'\n },\n u: {\n keyCode: 85,\n key: 'u',\n code: 'KeyU'\n },\n v: {\n keyCode: 86,\n key: 'v',\n code: 'KeyV'\n },\n w: {\n keyCode: 87,\n key: 'w',\n code: 'KeyW'\n },\n x: {\n keyCode: 88,\n key: 'x',\n code: 'KeyX'\n },\n y: {\n keyCode: 89,\n key: 'y',\n code: 'KeyY'\n },\n z: {\n keyCode: 90,\n key: 'z',\n code: 'KeyZ'\n },\n Meta: {\n keyCode: 91,\n key: 'Meta',\n code: 'MetaLeft',\n location: 1\n },\n '*': {\n keyCode: 106,\n key: '*',\n code: 'NumpadMultiply',\n location: 3\n },\n '+': {\n keyCode: 107,\n key: '+',\n code: 'NumpadAdd',\n location: 3\n },\n '-': {\n keyCode: 109,\n key: '-',\n code: 'NumpadSubtract',\n location: 3\n },\n '/': {\n keyCode: 111,\n key: '/',\n code: 'NumpadDivide',\n location: 3\n },\n ';': {\n keyCode: 186,\n key: ';',\n code: 'Semicolon'\n },\n '=': {\n keyCode: 187,\n key: '=',\n code: 'Equal'\n },\n ',': {\n keyCode: 188,\n key: ',',\n code: 'Comma'\n },\n '.': {\n keyCode: 190,\n key: '.',\n code: 'Period'\n },\n '`': {\n keyCode: 192,\n key: '`',\n code: 'Backquote'\n },\n '[': {\n keyCode: 219,\n key: '[',\n code: 'BracketLeft'\n },\n '\\\\': {\n keyCode: 220,\n key: '\\\\',\n code: 'Backslash'\n },\n ']': {\n keyCode: 221,\n key: ']',\n code: 'BracketRight'\n },\n \"'\": {\n keyCode: 222,\n key: \"'\",\n code: 'Quote'\n },\n Attn: {\n keyCode: 246,\n key: 'Attn'\n },\n CrSel: {\n keyCode: 247,\n key: 'CrSel',\n code: 'Props'\n },\n ExSel: {\n keyCode: 248,\n key: 'ExSel'\n },\n EraseEof: {\n keyCode: 249,\n key: 'EraseEof'\n },\n Play: {\n keyCode: 250,\n key: 'Play'\n },\n ZoomOut: {\n keyCode: 251,\n key: 'ZoomOut'\n },\n ')': {\n keyCode: 48,\n key: ')',\n code: 'Digit0'\n },\n '!': {\n keyCode: 49,\n key: '!',\n code: 'Digit1'\n },\n '@': {\n keyCode: 50,\n key: '@',\n code: 'Digit2'\n },\n '#': {\n keyCode: 51,\n key: '#',\n code: 'Digit3'\n },\n $: {\n keyCode: 52,\n key: '$',\n code: 'Digit4'\n },\n '%': {\n keyCode: 53,\n key: '%',\n code: 'Digit5'\n },\n '^': {\n keyCode: 54,\n key: '^',\n code: 'Digit6'\n },\n '&': {\n keyCode: 55,\n key: '&',\n code: 'Digit7'\n },\n '(': {\n keyCode: 57,\n key: '(',\n code: 'Digit9'\n },\n A: {\n keyCode: 65,\n key: 'A',\n code: 'KeyA'\n },\n B: {\n keyCode: 66,\n key: 'B',\n code: 'KeyB'\n },\n C: {\n keyCode: 67,\n key: 'C',\n code: 'KeyC'\n },\n D: {\n keyCode: 68,\n key: 'D',\n code: 'KeyD'\n },\n E: {\n keyCode: 69,\n key: 'E',\n code: 'KeyE'\n },\n F: {\n keyCode: 70,\n key: 'F',\n code: 'KeyF'\n },\n G: {\n keyCode: 71,\n key: 'G',\n code: 'KeyG'\n },\n H: {\n keyCode: 72,\n key: 'H',\n code: 'KeyH'\n },\n I: {\n keyCode: 73,\n key: 'I',\n code: 'KeyI'\n },\n J: {\n keyCode: 74,\n key: 'J',\n code: 'KeyJ'\n },\n K: {\n keyCode: 75,\n key: 'K',\n code: 'KeyK'\n },\n L: {\n keyCode: 76,\n key: 'L',\n code: 'KeyL'\n },\n M: {\n keyCode: 77,\n key: 'M',\n code: 'KeyM'\n },\n N: {\n keyCode: 78,\n key: 'N',\n code: 'KeyN'\n },\n O: {\n keyCode: 79,\n key: 'O',\n code: 'KeyO'\n },\n P: {\n keyCode: 80,\n key: 'P',\n code: 'KeyP'\n },\n Q: {\n keyCode: 81,\n key: 'Q',\n code: 'KeyQ'\n },\n R: {\n keyCode: 82,\n key: 'R',\n code: 'KeyR'\n },\n S: {\n keyCode: 83,\n key: 'S',\n code: 'KeyS'\n },\n T: {\n keyCode: 84,\n key: 'T',\n code: 'KeyT'\n },\n U: {\n keyCode: 85,\n key: 'U',\n code: 'KeyU'\n },\n V: {\n keyCode: 86,\n key: 'V',\n code: 'KeyV'\n },\n W: {\n keyCode: 87,\n key: 'W',\n code: 'KeyW'\n },\n X: {\n keyCode: 88,\n key: 'X',\n code: 'KeyX'\n },\n Y: {\n keyCode: 89,\n key: 'Y',\n code: 'KeyY'\n },\n Z: {\n keyCode: 90,\n key: 'Z',\n code: 'KeyZ'\n },\n ':': {\n keyCode: 186,\n key: ':',\n code: 'Semicolon'\n },\n '<': {\n keyCode: 188,\n key: '<',\n code: 'Comma'\n },\n _: {\n keyCode: 189,\n key: '_',\n code: 'Minus'\n },\n '>': {\n keyCode: 190,\n key: '>',\n code: 'Period'\n },\n '?': {\n keyCode: 191,\n key: '?',\n code: 'Slash'\n },\n '~': {\n keyCode: 192,\n key: '~',\n code: 'Backquote'\n },\n '{': {\n keyCode: 219,\n key: '{',\n code: 'BracketLeft'\n },\n '|': {\n keyCode: 220,\n key: '|',\n code: 'Backslash'\n },\n '}': {\n keyCode: 221,\n key: '}',\n code: 'BracketRight'\n },\n '\"': {\n keyCode: 222,\n key: '\"',\n code: 'Quote'\n },\n SoftLeft: {\n key: 'SoftLeft',\n code: 'SoftLeft',\n location: 4\n },\n SoftRight: {\n key: 'SoftRight',\n code: 'SoftRight',\n location: 4\n },\n Camera: {\n keyCode: 44,\n key: 'Camera',\n code: 'Camera',\n location: 4\n },\n Call: {\n key: 'Call',\n code: 'Call',\n location: 4\n },\n EndCall: {\n keyCode: 95,\n key: 'EndCall',\n code: 'EndCall',\n location: 4\n },\n VolumeDown: {\n keyCode: 182,\n key: 'VolumeDown',\n code: 'VolumeDown',\n location: 4\n },\n VolumeUp: {\n keyCode: 183,\n key: 'VolumeUp',\n code: 'VolumeUp',\n location: 4\n }\n};\nconst lowerCaseKeyDefinitions = Object.entries(_keyDefinitions).reduce((acc, [key, definition])=>{\n const lowerKey = key.toLowerCase();\n if (lowerKey !== key) acc[lowerKey] = definition;\n return acc;\n}, {});\nconst getKeyDefinition = (key)=>{\n const lowerKey = key.toLowerCase();\n if (lowerCaseKeyDefinitions[lowerKey]) return lowerCaseKeyDefinitions[lowerKey].key;\n return key;\n};\nconst isMac = 'undefined' != typeof window ? /Mac|iPod|iPhone|iPad/.test(window.navigator.platform) : 'darwin' === process.platform;\nconst keyMap = {\n return: _keyDefinitions.Enter.key,\n enter: _keyDefinitions.Enter.key,\n ctrl: isMac ? _keyDefinitions.Meta.key : _keyDefinitions.Control.key,\n shift: _keyDefinitions.Shift.key,\n alt: _keyDefinitions.Alt.key,\n space: _keyDefinitions.Space.key,\n 'page down': _keyDefinitions.PageDown.key,\n pagedown: _keyDefinitions.PageDown.key,\n 'page up': _keyDefinitions.PageUp.key,\n pageup: _keyDefinitions.PageUp.key\n};\nfunction transformHotkeyInput(keyInput) {\n if (keyMap[keyInput.toLowerCase()]) return [\n getKeyDefinition(keyMap[keyInput.toLowerCase()])\n ];\n return keyInput.split(' ').map((key)=>getKeyDefinition(keyMap[key.toLowerCase()] || key));\n}\nexport { _keyDefinitions, getKeyDefinition, isMac, transformHotkeyInput };\n","function truncateText(text, maxLength = 150) {\n if (void 0 === text) return '';\n if ('object' == typeof text) text = JSON.stringify(text);\n if ('number' == typeof text) return text.toString();\n if ('string' == typeof text && text.length > maxLength) return `${text.slice(0, maxLength)}...`;\n if ('string' == typeof text) return text.trim();\n return '';\n}\nfunction trimAttributes(attributes, truncateTextLength) {\n const tailorAttributes = Object.keys(attributes).reduce((res, currentKey)=>{\n const attributeVal = attributes[currentKey];\n if ('style' === currentKey || 'htmlTagName' === currentKey || 'nodeType' === currentKey) return res;\n res[currentKey] = truncateText(attributeVal, truncateTextLength);\n return res;\n }, {});\n return tailorAttributes;\n}\nconst nodeSizeThreshold = 4;\nfunction descriptionOfTree(tree, truncateTextLength, filterNonTextContent = false, visibleOnly = true) {\n const attributesString = (kv)=>Object.entries(kv).map(([key, value])=>`${key}=\"${truncateText(value, truncateTextLength)}\"`).join(' ');\n function buildContentTree(node, indent = 0, visibleOnly = true) {\n let before = '';\n let contentWithIndent = '';\n let after = '';\n let emptyNode = true;\n const indentStr = ' '.repeat(indent);\n let children = '';\n for(let i = 0; i < (node.children || []).length; i++){\n const childContent = buildContentTree(node.children[i], indent + 1, visibleOnly);\n if (childContent) children += `\\n${childContent}`;\n }\n if (node.node && node.node.rect.width > nodeSizeThreshold && node.node.rect.height > nodeSizeThreshold && (!filterNonTextContent || filterNonTextContent && node.node.content) && (!visibleOnly || visibleOnly && node.node.isVisible)) {\n var _node_node_attributes;\n emptyNode = false;\n let nodeTypeString;\n nodeTypeString = (null == (_node_node_attributes = node.node.attributes) ? void 0 : _node_node_attributes.htmlTagName) ? node.node.attributes.htmlTagName.replace(/[<>]/g, '') : node.node.attributes.nodeType.replace(/\\sNode$/, '').toLowerCase();\n const markerId = node.node.indexId;\n const markerIdString = markerId ? `markerId=\"${markerId}\"` : '';\n const rectAttribute = node.node.rect ? {\n left: node.node.rect.left,\n top: node.node.rect.top,\n width: node.node.rect.width,\n height: node.node.rect.height\n } : {};\n before = `<${nodeTypeString} id=\"${node.node.id}\" ${markerIdString} ${attributesString(trimAttributes(node.node.attributes || {}, truncateTextLength))} ${attributesString(rectAttribute)}>`;\n const content = truncateText(node.node.content, truncateTextLength);\n contentWithIndent = content ? `\\n${indentStr} ${content}` : '';\n after = `</${nodeTypeString}>`;\n } else if (!filterNonTextContent) {\n if (!children.trim().startsWith('<>')) {\n before = '<>';\n contentWithIndent = '';\n after = '</>';\n }\n }\n if (emptyNode && !children.trim()) return '';\n const result = `${indentStr}${before}${contentWithIndent}${children}\\n${indentStr}${after}`;\n if (result.trim()) return result;\n return '';\n }\n const result = buildContentTree(tree, 0, visibleOnly);\n return result.replace(/^\\s*\\n/gm, '');\n}\nfunction treeToList(tree) {\n const result = [];\n function dfs(node) {\n if (node.node) result.push(node.node);\n for (const child of node.children)dfs(child);\n }\n dfs(tree);\n return result;\n}\nfunction traverseTree(tree, onNode) {\n function dfs(node) {\n if (node.node) node.node = onNode(node.node);\n for (const child of node.children)dfs(child);\n }\n dfs(tree);\n return tree;\n}\nexport { descriptionOfTree, traverseTree, treeToList, trimAttributes, truncateText };\n","function typeStr(task) {\n return task.subType && 'Plan' !== task.subType ? `${task.type} / ${task.subType || ''}` : task.type;\n}\nfunction getKeyCommands(value) {\n const keys = Array.isArray(value) ? value : [\n value\n ];\n return keys.reduce((acc, k)=>{\n const includeMeta = keys.includes('Meta') || keys.includes('Control');\n if (includeMeta && ('a' === k || 'A' === k)) return acc.concat([\n {\n key: k,\n command: 'SelectAll'\n }\n ]);\n if (includeMeta && ('c' === k || 'C' === k)) return acc.concat([\n {\n key: k,\n command: 'Copy'\n }\n ]);\n if (includeMeta && ('v' === k || 'V' === k)) return acc.concat([\n {\n key: k,\n command: 'Paste'\n }\n ]);\n return acc.concat([\n {\n key: k\n }\n ]);\n }, []);\n}\nfunction locateParamStr(locate) {\n if (!locate) return '';\n if ('string' == typeof locate) return locate;\n return 'string' == typeof locate.prompt ? locate.prompt : locate.prompt.prompt;\n}\nfunction scrollParamStr(scrollParam) {\n if (!scrollParam) return '';\n return `${scrollParam.direction || 'down'}, ${scrollParam.scrollType || 'once'}, ${scrollParam.distance || 'distance-not-set'}`;\n}\nfunction pullParamStr(pullParam) {\n if (!pullParam) return '';\n const parts = [];\n parts.push(`direction: ${pullParam.direction || 'down'}`);\n if (pullParam.distance) parts.push(`distance: ${pullParam.distance}`);\n if (pullParam.duration) parts.push(`duration: ${pullParam.duration}ms`);\n return parts.join(', ');\n}\nfunction taskTitleStr(type, prompt) {\n if (prompt) return `${type} - ${prompt}`;\n return type;\n}\nfunction paramStr(task) {\n let value;\n if ('Planning' === task.type) {\n var _task_param;\n value = null == task ? void 0 : null == (_task_param = task.param) ? void 0 : _task_param.userInstruction;\n }\n if ('Insight' === task.type) {\n var _task_param1, _task_param2, _task_param3, _task_param4;\n value = (null == task ? void 0 : null == (_task_param1 = task.param) ? void 0 : _task_param1.prompt) || (null == task ? void 0 : null == (_task_param2 = task.param) ? void 0 : _task_param2.id) || (null == task ? void 0 : null == (_task_param3 = task.param) ? void 0 : _task_param3.dataDemand) || (null == task ? void 0 : null == (_task_param4 = task.param) ? void 0 : _task_param4.assertion);\n }\n if ('Action' === task.type) {\n var _task_param5, _task_param6, _task_param7, _task_param8;\n const locate = null == task ? void 0 : task.locate;\n const locateStr = locate ? locateParamStr(locate) : '';\n value = task.thought || '';\n if ('number' == typeof (null == task ? void 0 : null == (_task_param5 = task.param) ? void 0 : _task_param5.timeMs)) {\n var _task_param9;\n value = `${null == task ? void 0 : null == (_task_param9 = task.param) ? void 0 : _task_param9.timeMs}ms`;\n } else if ('string' == typeof (null == task ? void 0 : null == (_task_param6 = task.param) ? void 0 : _task_param6.scrollType)) value = scrollParamStr(null == task ? void 0 : task.param);\n else if ('string' == typeof (null == task ? void 0 : null == (_task_param7 = task.param) ? void 0 : _task_param7.direction) && (null == task ? void 0 : task.subType) === 'AndroidPull') value = pullParamStr(null == task ? void 0 : task.param);\n else if (void 0 !== (null == task ? void 0 : null == (_task_param8 = task.param) ? void 0 : _task_param8.value)) {\n var _task_param10;\n value = null == task ? void 0 : null == (_task_param10 = task.param) ? void 0 : _task_param10.value;\n }\n if (locateStr) value = value ? `${locateStr} - ${value}` : locateStr;\n }\n if (void 0 === value) return '';\n return 'string' == typeof value ? value : JSON.stringify(value, void 0, 2);\n}\nconst limitOpenNewTabScript = `\nif (!window.__MIDSCENE_NEW_TAB_INTERCEPTOR_INITIALIZED__) {\n window.__MIDSCENE_NEW_TAB_INTERCEPTOR_INITIALIZED__ = true;\n\n // Intercept the window.open method (only once)\n window.open = function(url) {\n console.log('Blocked window.open:', url);\n window.location.href = url;\n return null;\n };\n\n // Block all a tag clicks with target=\"_blank\" (only once)\n document.addEventListener('click', function(e) {\n const target = e.target.closest('a');\n if (target && target.target === '_blank') {\n e.preventDefault();\n console.log('Blocked new tab:', target.href);\n window.location.href = target.href;\n target.removeAttribute('target');\n }\n }, true);\n}\n`;\nexport { getKeyCommands, limitOpenNewTabScript, locateParamStr, paramStr, pullParamStr, scrollParamStr, taskTitleStr, typeStr };\n\n//# sourceMappingURL=ui-utils.mjs.map","import { Anthropic } from \"@anthropic-ai/sdk\";\nimport { DefaultAzureCredential, getBearerTokenProvider } from \"@azure/identity\";\nimport { ANTHROPIC_API_KEY, AZURE_OPENAI_API_VERSION, AZURE_OPENAI_DEPLOYMENT, AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_KEY, MIDSCENE_API_TYPE, MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_AZURE_OPENAI_SCOPE, MIDSCENE_DEBUG_AI_PROFILE, MIDSCENE_DEBUG_AI_RESPONSE, MIDSCENE_LANGSMITH_DEBUG, MIDSCENE_MODEL_NAME, MIDSCENE_OPENAI_HTTP_PROXY, MIDSCENE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_OPENAI_SOCKS_PROXY, MIDSCENE_USE_ANTHROPIC_SDK, MIDSCENE_USE_AZURE_OPENAI, MIDSCENE_USE_QWEN_VL, MIDSCENE_USE_VLM_UI_TARS, OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MAX_TOKENS, OPENAI_USE_AZURE, UITarsModelVersion, getAIConfig, getAIConfigInBoolean, getAIConfigInJson, getPreferredLanguage, uiTarsModelVersion, vlLocateMode } from \"@midscene/shared/env\";\nimport { enableDebug, getDebug } from \"@midscene/shared/logger\";\nimport { assert, ifInBrowser } from \"@midscene/shared/utils\";\nimport { HttpsProxyAgent } from \"https-proxy-agent\";\nimport { jsonrepair } from \"jsonrepair\";\nimport openai_0, { AzureOpenAI } from \"openai\";\nimport { SocksProxyAgent } from \"socks-proxy-agent\";\nimport { NodeType, PLAYWRIGHT_EXAMPLE_CODE, YAML_EXAMPLE_CODE } from \"@midscene/shared/constants\";\nimport { descriptionOfTree, generateElementByPosition, treeToList } from \"@midscene/shared/extractor\";\nimport { compositeElementInfoImg, cropByRect, imageInfoOfBase64, paddingToMatchBlockByBase64, preProcessImageUrl, resizeImgBase64 } from \"@midscene/shared/img\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport node_assert from \"node:assert\";\nimport { transformHotkeyInput } from \"@midscene/shared/us-keyboard-layout\";\nimport { actionParser } from \"@ui-tars/action-parser\";\nvar types_AIResponseFormat = /*#__PURE__*/ function(AIResponseFormat) {\n AIResponseFormat[\"JSON\"] = \"json_object\";\n AIResponseFormat[\"TEXT\"] = \"text\";\n return AIResponseFormat;\n}({});\nvar common_AIActionType = /*#__PURE__*/ function(AIActionType) {\n AIActionType[AIActionType[\"ASSERT\"] = 0] = \"ASSERT\";\n AIActionType[AIActionType[\"INSPECT_ELEMENT\"] = 1] = \"INSPECT_ELEMENT\";\n AIActionType[AIActionType[\"EXTRACT_DATA\"] = 2] = \"EXTRACT_DATA\";\n AIActionType[AIActionType[\"PLAN\"] = 3] = \"PLAN\";\n AIActionType[AIActionType[\"DESCRIBE_ELEMENT\"] = 4] = \"DESCRIBE_ELEMENT\";\n return AIActionType;\n}({});\nasync function callAiFn(msgs, AIActionTypeValue) {\n const jsonObject = await callToGetJSONObject(msgs, AIActionTypeValue);\n return {\n content: jsonObject.content,\n usage: jsonObject.usage\n };\n}\nconst defaultBboxSize = 20;\nconst debugInspectUtils = getDebug('ai:common');\nfunction fillBboxParam(locate, width, height) {\n if (locate.bbox_2d && !(null == locate ? void 0 : locate.bbox)) {\n locate.bbox = locate.bbox_2d;\n delete locate.bbox_2d;\n }\n if (null == locate ? void 0 : locate.bbox) locate.bbox = adaptBbox(locate.bbox, width, height);\n return locate;\n}\nfunction adaptQwenBbox(bbox) {\n if (bbox.length < 2) {\n const msg = `invalid bbox data for qwen-vl mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n }\n const result = [\n Math.round(bbox[0]),\n Math.round(bbox[1]),\n 'number' == typeof bbox[2] ? Math.round(bbox[2]) : Math.round(bbox[0] + defaultBboxSize),\n 'number' == typeof bbox[3] ? Math.round(bbox[3]) : Math.round(bbox[1] + defaultBboxSize)\n ];\n return result;\n}\nfunction adaptDoubaoBbox(bbox, width, height) {\n assert(width > 0 && height > 0, 'width and height must be greater than 0 in doubao mode');\n if ('string' == typeof bbox) {\n assert(/^(\\d+)\\s(\\d+)\\s(\\d+)\\s(\\d+)$/.test(bbox.trim()), `invalid bbox data string for doubao-vision mode: ${bbox}`);\n const splitted = bbox.split(' ');\n if (4 === splitted.length) return [\n Math.round(Number(splitted[0]) * width / 1000),\n Math.round(Number(splitted[1]) * height / 1000),\n Math.round(Number(splitted[2]) * width / 1000),\n Math.round(Number(splitted[3]) * height / 1000)\n ];\n throw new Error(`invalid bbox data string for doubao-vision mode: ${bbox}`);\n }\n if (Array.isArray(bbox) && Array.isArray(bbox[0])) bbox = bbox[0];\n let bboxList = [];\n if (Array.isArray(bbox) && 'string' == typeof bbox[0]) bbox.forEach((item)=>{\n if ('string' == typeof item && item.includes(',')) {\n const [x, y] = item.split(',');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else if ('string' == typeof item && item.includes(' ')) {\n const [x, y] = item.split(' ');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else bboxList.push(Number(item));\n });\n else bboxList = bbox;\n if (4 === bboxList.length || 5 === bboxList.length) return [\n Math.round(bboxList[0] * width / 1000),\n Math.round(bboxList[1] * height / 1000),\n Math.round(bboxList[2] * width / 1000),\n Math.round(bboxList[3] * height / 1000)\n ];\n if (6 === bboxList.length || 2 === bboxList.length || 3 === bboxList.length || 7 === bboxList.length) return [\n Math.max(0, Math.round(bboxList[0] * width / 1000) - defaultBboxSize / 2),\n Math.max(0, Math.round(bboxList[1] * height / 1000) - defaultBboxSize / 2),\n Math.min(width, Math.round(bboxList[0] * width / 1000) + defaultBboxSize / 2),\n Math.min(height, Math.round(bboxList[1] * height / 1000) + defaultBboxSize / 2)\n ];\n if (8 === bbox.length) return [\n Math.round(bboxList[0] * width / 1000),\n Math.round(bboxList[1] * height / 1000),\n Math.round(bboxList[4] * width / 1000),\n Math.round(bboxList[5] * height / 1000)\n ];\n const msg = `invalid bbox data for doubao-vision mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n}\nfunction adaptBbox(bbox, width, height) {\n if ('doubao-vision' === vlLocateMode() || 'vlm-ui-tars' === vlLocateMode()) return adaptDoubaoBbox(bbox, width, height);\n if ('gemini' === vlLocateMode()) return adaptGeminiBbox(bbox, width, height);\n return adaptQwenBbox(bbox);\n}\nfunction adaptGeminiBbox(bbox, width, height) {\n const left = Math.round(bbox[1] * width / 1000);\n const top = Math.round(bbox[0] * height / 1000);\n const right = Math.round(bbox[3] * width / 1000);\n const bottom = Math.round(bbox[2] * height / 1000);\n return [\n left,\n top,\n right,\n bottom\n ];\n}\nfunction adaptBboxToRect(bbox, width, height, offsetX = 0, offsetY = 0) {\n debugInspectUtils('adaptBboxToRect', bbox, width, height, offsetX, offsetY);\n const [left, top, right, bottom] = adaptBbox(bbox, width, height);\n const rect = {\n left: left + offsetX,\n top: top + offsetY,\n width: right - left,\n height: bottom - top\n };\n debugInspectUtils('adaptBboxToRect, result=', rect);\n return rect;\n}\nlet warned = false;\nfunction warnGPT4oSizeLimit(size) {\n var _getModelName;\n if (warned) return;\n if (null == (_getModelName = getModelName()) ? void 0 : _getModelName.toLowerCase().includes('gpt-4o')) {\n const warningMsg = `GPT-4o has a maximum image input size of 2000x768 or 768x2000, but got ${size.width}x${size.height}. Please set your page to a smaller resolution. Otherwise, the result may be inaccurate.`;\n if (Math.max(size.width, size.height) > 2000 || Math.min(size.width, size.height) > 768) {\n console.warn(warningMsg);\n warned = true;\n }\n } else if (size.width > 1800 || size.height > 1800) {\n console.warn(`The image size seems too large (${size.width}x${size.height}). It may lead to more token usage, slower response, and inaccurate result.`);\n warned = true;\n }\n}\nfunction mergeRects(rects) {\n const minLeft = Math.min(...rects.map((r)=>r.left));\n const minTop = Math.min(...rects.map((r)=>r.top));\n const maxRight = Math.max(...rects.map((r)=>r.left + r.width));\n const maxBottom = Math.max(...rects.map((r)=>r.top + r.height));\n return {\n left: minLeft,\n top: minTop,\n width: maxRight - minLeft,\n height: maxBottom - minTop\n };\n}\nfunction expandSearchArea(rect, screenSize) {\n const minEdgeSize = 'doubao-vision' === vlLocateMode() ? 500 : 300;\n const defaultPadding = 160;\n const paddingSizeHorizontal = rect.width < minEdgeSize ? Math.ceil((minEdgeSize - rect.width) / 2) : defaultPadding;\n const paddingSizeVertical = rect.height < minEdgeSize ? Math.ceil((minEdgeSize - rect.height) / 2) : defaultPadding;\n rect.left = Math.max(0, rect.left - paddingSizeHorizontal);\n rect.width = Math.min(rect.width + 2 * paddingSizeHorizontal, screenSize.width - rect.left);\n rect.top = Math.max(0, rect.top - paddingSizeVertical);\n rect.height = Math.min(rect.height + 2 * paddingSizeVertical, screenSize.height - rect.top);\n return rect;\n}\nasync function markupImageForLLM(screenshotBase64, tree, size) {\n const elementsInfo = treeToList(tree);\n const elementsPositionInfoWithoutText = elementsInfo.filter((elementInfo)=>{\n if (elementInfo.attributes.nodeType === NodeType.TEXT) return false;\n return true;\n });\n const imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n elementsPositionInfo: elementsPositionInfoWithoutText,\n size\n });\n return imagePayload;\n}\nfunction buildYamlFlowFromPlans(plans, sleep) {\n const flow = [];\n for (const plan of plans){\n var _plan_locate;\n const type = plan.type;\n const locate = null == (_plan_locate = plan.locate) ? void 0 : _plan_locate.prompt;\n if ('Tap' === type) flow.push({\n aiTap: locate\n });\n else if ('Hover' === type) flow.push({\n aiHover: locate\n });\n else if ('Input' === type) {\n const param = plan.param;\n flow.push({\n aiInput: param.value,\n locate\n });\n } else if ('KeyboardPress' === type) {\n const param = plan.param;\n flow.push({\n aiKeyboardPress: param.value,\n locate\n });\n } else if ('Scroll' === type) {\n const param = plan.param;\n flow.push({\n aiScroll: null,\n locate,\n direction: param.direction,\n scrollType: param.scrollType,\n distance: param.distance\n });\n } else if ('Sleep' === type) {\n const param = plan.param;\n flow.push({\n sleep: param.timeMs\n });\n } else 'AndroidBackButton' === type || 'AndroidHomeButton' === type || 'AndroidRecentAppsButton' === type || 'AndroidLongPress' === type || 'AndroidPull' === type || 'Error' === type || 'Assert' === type || 'AssertWithoutThrow' === type || 'Finished' === type || console.warn(`Cannot convert action ${type} to yaml flow. This should be a bug of Midscene.`);\n }\n if (sleep) flow.push({\n sleep: sleep\n });\n return flow;\n}\nconst defaultAssertionPrompt = 'You are a senior testing engineer. User will give an assertion and a screenshot of a page. By carefully viewing the screenshot, please tell whether the assertion is truthy.';\nconst defaultAssertionResponseJsonFormat = `Return in the following JSON format:\n{\n pass: boolean, // whether the assertion is truthy\n thought: string | null, // string, if the result is falsy, give the reason why it is falsy. Otherwise, put null.\n}`;\nconst getUiTarsAssertionResponseJsonFormat = ()=>`## Output Json String Format\n\\`\\`\\`\n\"{\n \"pass\": <<is a boolean value from the enum [true, false], true means the assertion is truthy>>, \n \"thought\": \"<<is a string, give the reason why the assertion is falsy or truthy. Otherwise.>>\"\n}\"\n\\`\\`\\`\n\n## Rules **MUST** follow\n- Make sure to return **only** the JSON, with **no additional** text or explanations.\n- Use ${getPreferredLanguage()} in \\`thought\\` part.\n- You **MUST** strictly follow up the **Output Json String Format**.`;\nfunction systemPromptToAssert(model) {\n return `${defaultAssertionPrompt}\n\n${model.isUITars ? getUiTarsAssertionResponseJsonFormat() : defaultAssertionResponseJsonFormat}`;\n}\nconst assertSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'assert',\n strict: true,\n schema: {\n type: 'object',\n properties: {\n pass: {\n type: 'boolean',\n description: 'Whether the assertion passed or failed'\n },\n thought: {\n type: [\n 'string',\n 'null'\n ],\n description: 'The thought process behind the assertion'\n }\n },\n required: [\n 'pass',\n 'thought'\n ],\n additionalProperties: false\n }\n }\n};\nfunction bboxDescription(vlMode) {\n if ('gemini' === vlMode) return '2d bounding box as [ymin, xmin, ymax, xmax]';\n return '2d bounding box as [xmin, ymin, xmax, ymax]';\n}\nfunction systemPromptToLocateElement(vlMode) {\n if (vlMode) {\n const bboxComment = bboxDescription(vlMode);\n return `\n## Role:\nYou are an expert in software testing.\n\n## Objective:\n- Identify elements in screenshots and text that match the user's description.\n- Give the coordinates of the element that matches the user's description best in the screenshot.\n- Determine whether the user's description is order-sensitive (e.g., contains phrases like 'the third item in the list', 'the last button', etc.).\n\n## Output Format:\n\\`\\`\\`json\n{\n \"bbox\": [number, number, number, number], // ${bboxComment}\n \"errors\"?: string[],\n \"isOrderSensitive\": boolean // Whether the targetElementDescription is order-sensitive (true/false)\n}\n\\`\\`\\`\n\nFields:\n* \\`bbox\\` is the bounding box of the element that matches the user's description best in the screenshot\n* \\`isOrderSensitive\\` is a boolean indicating whether the user's description is order-sensitive (true/false)\n* \\`errors\\` is an optional array of error messages (if any)\n\nOrder-sensitive means the description contains phrases like:\n- \"the third item in the list\"\n- \"the last button\"\n- \"the first input box\"\n- \"the second row\"\n\nNot order-sensitive means the description is like:\n- \"confirm button\"\n- \"search box\"\n- \"password input\"\n\nFor example, when an element is found and the description is order-sensitive:\n\\`\\`\\`json\n{\n \"bbox\": [100, 100, 200, 200],\n \"isOrderSensitive\": true,\n \"errors\": []\n}\n\\`\\`\\`\n\nWhen no element is found and the description is not order-sensitive:\n\\`\\`\\`json\n{\n \"bbox\": [],\n \"isOrderSensitive\": false,\n \"errors\": [\"I can see ..., but {some element} is not found\"]\n}\n\\`\\`\\`\n`;\n }\n return `\n## Role:\nYou are an expert in software page image (2D) and page element text analysis.\n\n## Objective:\n- Identify elements in screenshots and text that match the user's description.\n- Return JSON data containing the selection reason and element ID.\n- Determine whether the user's description is order-sensitive (e.g., contains phrases like 'the third item in the list', 'the last button', etc.).\n\n## Skills:\n- Image analysis and recognition\n- Multilingual text understanding\n- Software UI design and testing\n\n## Workflow:\n1. Receive the user's element description, screenshot, and element description information. Note that the text may contain non-English characters (e.g., Chinese), indicating that the application may be non-English.\n2. Based on the user's description, locate the target element ID in the list of element descriptions and the screenshot.\n3. Found the required number of elements\n4. Return JSON data containing the selection reason and element ID.\n5. Judge whether the user's description is order-sensitive (see below for definition and examples).\n\n## Constraints:\n- Strictly adhere to the specified location when describing the required element; do not select elements from other locations.\n- Elements in the image with NodeType other than \"TEXT Node\" have been highlighted to identify the element among multiple non-text elements.\n- Accurately identify element information based on the user's description and return the corresponding element ID from the element description information, not extracted from the image.\n- If no elements are found, the \"elements\" array should be empty.\n- The returned data must conform to the specified JSON format.\n- The returned value id information must use the id from element info (important: **use id not indexId, id is hash content**)\n\n## Order-Sensitive Definition:\n- If the description contains phrases like \"the third item in the list\", \"the last button\", \"the first input box\", \"the second row\", etc., it is order-sensitive (isOrderSensitive = true).\n- If the description is like \"confirm button\", \"search box\", \"password input\", etc., it is not order-sensitive (isOrderSensitive = false).\n\n## Output Format:\n\nPlease return the result in JSON format as follows:\n\n\\`\\`\\`json\n{\n \"elements\": [\n // If no matching elements are found, return an empty array []\n {\n \"reason\": \"PLACEHOLDER\", // The thought process for finding the element, replace PLACEHOLDER with your thought process\n \"text\": \"PLACEHOLDER\", // Replace PLACEHOLDER with the text of elementInfo, if none, leave empty\n \"id\": \"PLACEHOLDER\" // Replace PLACEHOLDER with the ID (important: **use id not indexId, id is hash content**) of elementInfo\n }\n // More elements...\n ],\n \"isOrderSensitive\": true, // or false, depending on the user's description\n \"errors\": [] // Array of strings containing any error messages\n}\n\\`\\`\\`\n\n## Example:\nExample 1:\nInput Example:\n\\`\\`\\`json\n// Description: \"Shopping cart icon in the upper right corner\"\n{\n \"description\": \"PLACEHOLDER\", // Description of the target element\n \"screenshot\": \"path/screenshot.png\",\n \"text\": '{\n \"pageSize\": {\n \"width\": 400, // Width of the page\n \"height\": 905 // Height of the page\n },\n \"elementInfos\": [\n {\n \"id\": \"1231\", // ID of the element\n \"indexId\": \"0\", // Index of the element\\u{FF0C}The image is labeled to the left of the element\n \"attributes\": { // Attributes of the element\n \"nodeType\": \"IMG Node\", // Type of element, types include: TEXT Node, IMG Node, BUTTON Node, INPUT Node\n \"src\": \"https://ap-southeast-3.m\",\n \"class\": \".img\"\n },\n \"content\": \"\", // Text content of the element\n \"rect\": {\n \"left\": 280, // Distance from the left side of the page\n \"top\": 8, // Distance from the top of the page\n \"width\": 44, // Width of the element\n \"height\": 44 // Height of the element\n }\n },\n {\n \"id\": \"66551\", // ID of the element\n \"indexId\": \"1\", // Index of the element,The image is labeled to the left of the element\n \"attributes\": { // Attributes of the element\n \"nodeType\": \"IMG Node\", // Type of element, types include: TEXT Node, IMG Node, BUTTON Node, INPUT Node\n \"src\": \"data:image/png;base64,iVBORw0KGgoAAAANSU...\",\n \"class\": \".icon\"\n },\n \"content\": \"\", // Text content of the element\n \"rect\": {\n \"left\": 350, // Distance from the left side of the page\n \"top\": 16, // Distance from the top of the page\n \"width\": 25, // Width of the element\n \"height\": 25 // Height of the element\n }\n },\n ...\n {\n \"id\": \"12344\",\n \"indexId\": \"2\", // Index of the element\\u{FF0C}The image is labeled to the left of the element\n \"attributes\": {\n \"nodeType\": \"TEXT Node\",\n \"class\": \".product-name\"\n },\n \"center\": [\n 288,\n 834\n ],\n \"content\": \"Mango Drink\",\n \"rect\": {\n \"left\": 188,\n \"top\": 827,\n \"width\": 199,\n \"height\": 13\n }\n },\n ...\n ]\n }\n '\n}\n\\`\\`\\`\nOutput Example:\n\\`\\`\\`json\n{\n \"elements\": [\n {\n // Describe the reason for finding this element, replace with actual value in practice\n \"reason\": \"Reason for finding element 4: It is located in the upper right corner, is an image type, and according to the screenshot, it is a shopping cart icon button\",\n \"text\": \"\",\n // ID(**use id not indexId**) of this element, replace with actual value in practice, **use id not indexId**\n \"id\": \"1231\"\n }\n ],\n \"isOrderSensitive\": true,\n \"errors\": []\n}\n\\`\\`\\`\n \n `;\n}\nconst locatorSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'find_elements',\n strict: true,\n schema: {\n type: 'object',\n properties: {\n elements: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n reason: {\n type: 'string',\n description: 'Reason for finding this element'\n },\n text: {\n type: 'string',\n description: 'Text content of the element'\n },\n id: {\n type: 'string',\n description: 'ID of this element'\n }\n },\n required: [\n 'reason',\n 'text',\n 'id'\n ],\n additionalProperties: false\n },\n description: 'List of found elements'\n },\n isOrderSensitive: {\n type: 'boolean',\n description: \"Whether the targetElementDescription is order-sensitive (true/false)\"\n },\n errors: {\n type: 'array',\n items: {\n type: 'string'\n },\n description: 'List of error messages, if any'\n }\n },\n required: [\n 'elements',\n 'isOrderSensitive',\n 'errors'\n ],\n additionalProperties: false\n }\n }\n};\nconst findElementPrompt = new PromptTemplate({\n template: `\nHere is the item user want to find:\n=====================================\n{targetElementDescription}\n=====================================\n\n{pageDescription}\n `,\n inputVariables: [\n \"pageDescription\",\n \"targetElementDescription\"\n ]\n});\nconst vlCoTLog = '\"what_the_user_wants_to_do_next_by_instruction\": string, // What the user wants to do according to the instruction and previous logs. ';\nconst vlCurrentLog = '\"log\": string, // Log what the next one action (ONLY ONE!) you can do according to the screenshot and the instruction. The typical log looks like \"Now i want to use action \\'{ action-type }\\' to do .. first\". If no action should be done, log the reason. \". Use the same language as the user\\'s instruction.';\nconst llmCurrentLog = '\"log\": string, // Log what the next actions you can do according to the screenshot and the instruction. The typical log looks like \"Now i want to use action \\'{ action-type }\\' to do ..\". If no action should be done, log the reason. \". Use the same language as the user\\'s instruction.';\nconst commonOutputFields = `\"error\"?: string, // Error messages about unexpected situations, if any. Only think it is an error when the situation is not foreseeable according to the instruction. Use the same language as the user's instruction.\n \"more_actions_needed_by_instruction\": boolean, // Consider if there is still more action(s) to do after the action in \"Log\" is done, according to the instruction. If so, set this field to true. Otherwise, set it to false.`;\nconst vlLocateParam = (required)=>`locate${required ? '' : '?'}: {bbox: [number, number, number, number], prompt: string }`;\nconst llmLocateParam = (required)=>`locate${required ? '' : '?'}: {\"id\": string, \"prompt\": string}`;\nconst descriptionForAction = (action, locatorScheme)=>{\n const tab = ' ';\n let locateParam = '';\n if ('required' === action.location) locateParam = locatorScheme;\n else if ('optional' === action.location) locateParam = `${locatorScheme} | null`;\n else if (false === action.location) locateParam = '';\n const locatorParam = locateParam ? `- ${locateParam}` : '';\n if (action.whatToLocate) if (locateParam) locateParam += ` // ${action.whatToLocate}`;\n else console.warn(`whatToLocate is provided for action ${action.name}, but location is not required or optional. The whatToLocate will be ignored.`);\n let paramSchema = '';\n if (action.paramSchema) paramSchema = `- param: ${action.paramSchema}`;\n if (action.paramDescription) {\n node_assert(paramSchema, `paramSchema is required when paramDescription is provided for action ${action.name}, but got ${action.paramSchema}`);\n paramSchema += ` // ${action.paramDescription}`;\n }\n const fields = [\n paramSchema,\n locatorParam\n ].filter(Boolean);\n return `- ${action.name}, ${action.description}\n${tab}- type: \"${action.name}\"\n${tab}${fields.join(`\\n${tab}`)}\n`.trim();\n};\nconst systemTemplateOfVLPlanning = ({ actionSpace, vlMode })=>{\n const actionNameList = actionSpace.map((action)=>action.name).join(', ');\n const actionDescriptionList = actionSpace.map((action)=>descriptionForAction(action, vlLocateParam('required' === action.location)));\n const actionList = actionDescriptionList.join('\\n');\n return `\nTarget: User will give you a screenshot, an instruction and some previous logs indicating what have been done. Please tell what the next one action is (or null if no action should be done) to do the tasks the instruction requires. \n\nRestriction:\n- Don't give extra actions or plans beyond the instruction. ONLY plan for what the instruction requires. For example, don't try to submit the form if the instruction is only to fill something.\n- Always give ONLY ONE action in \\`log\\` field (or null if no action should be done), instead of multiple actions. Supported actions are ${actionNameList}.\n- Don't repeat actions in the previous logs.\n- Bbox is the bounding box of the element to be located. It's an array of 4 numbers, representing ${bboxDescription(vlMode)}.\n\nSupporting actions:\n${actionList}\n\nField description:\n* The \\`prompt\\` field inside the \\`locate\\` field is a short description that could be used to locate the element.\n\nReturn in JSON format:\n{\n ${vlCoTLog}\n ${vlCurrentLog}\n ${commonOutputFields}\n \"action\": \n {\n // one of the supporting actions\n } | null,\n ,\n \"sleep\"?: number, // The sleep time after the action, in milliseconds.\n}\n\nFor example, when the instruction is \"click 'Confirm' button, and click 'Yes' in popup\" and the log is \"I will use action Tap to click 'Confirm' button\", by viewing the screenshot and previous logs, you should consider: We have already clicked the 'Confirm' button, so next we should find and click 'Yes' in popup.\n\nthis and output the JSON:\n\n{\n \"what_the_user_wants_to_do_next_by_instruction\": \"We have already clicked the 'Confirm' button, so next we should find and click 'Yes' in popup\",\n \"log\": \"I will use action Tap to click 'Yes' in popup\",\n \"more_actions_needed_by_instruction\": false,\n \"action\": {\n \"type\": \"Tap\",\n \"locate\": {\n \"bbox\": [100, 100, 200, 200],\n \"prompt\": \"The 'Yes' button in popup\"\n }\n }\n}\n`;\n};\nconst systemTemplateOfLLM = ({ actionSpace })=>{\n const actionNameList = actionSpace.map((action)=>action.name).join(' / ');\n const actionDescriptionList = actionSpace.map((action)=>descriptionForAction(action, llmLocateParam('required' === action.location)));\n const actionList = actionDescriptionList.join('\\n');\n return `\n## Role\n\nYou are a versatile professional in software UI automation. Your outstanding contributions will impact the user experience of billions of users.\n\n## Objective\n\n- Decompose the instruction user asked into a series of actions\n- Locate the target element if possible\n- If the instruction cannot be accomplished, give a further plan.\n\n## Workflow\n\n1. Receive the screenshot, element description of screenshot(if any), user's instruction and previous logs.\n2. Decompose the user's task into a sequence of feasible actions, and place it in the \\`actions\\` field. There are different types of actions (${actionNameList}). The \"About the action\" section below will give you more details.\n3. Consider whether the user's instruction will be accomplished after the actions you composed.\n- If the instruction is accomplished, set \\`more_actions_needed_by_instruction\\` to false.\n- If more actions are needed, set \\`more_actions_needed_by_instruction\\` to true. Get ready to hand over to the next talent people like you. Carefully log what have been done in the \\`log\\` field, he or she will continue the task according to your logs.\n4. If the task is not feasible on this page, set \\`error\\` field to the reason.\n\n## Constraints\n\n- All the actions you composed MUST be feasible, which means all the action fields can be filled with the page context information you get. If not, don't plan this action.\n- Trust the \"What have been done\" field about the task (if any), don't repeat actions in it.\n- Respond only with valid JSON. Do not write an introduction or summary or markdown prefix like \\`\\`\\`json\\`\\`\\`.\n- If the screenshot and the instruction are totally irrelevant, set reason in the \\`error\\` field.\n\n## About the \\`actions\\` field\n\nThe \\`locate\\` param is commonly used in the \\`param\\` field of the action, means to locate the target element to perform the action, it conforms to the following scheme:\n\ntype LocateParam = {\n \"id\": string, // the id of the element found. It should either be the id marked with a rectangle in the screenshot or the id described in the description.\n \"prompt\"?: string // the description of the element to find. It can only be omitted when locate is null.\n} | null // If it's not on the page, the LocateParam should be null\n\n## Supported actions\n\nEach action has a \\`type\\` and corresponding \\`param\\`. To be detailed:\n${actionList}\n\n`.trim();\n};\nconst outputTemplate = `\n## Output JSON Format:\n\nThe JSON format is as follows:\n\n{\n \"actions\": [\n // ... some actions\n ],\n ${llmCurrentLog}\n ${commonOutputFields}\n}\n\n## Examples\n\n### Example: Decompose a task\n\nWhen you received the following information:\n\n* Instruction: 'Click the language switch button, wait 1s, click \"English\"'\n* Logs: null\n* Page Context (screenshot and description) shows: There is a language switch button, and the \"English\" option is not shown in the screenshot now.\n\nBy viewing the page screenshot and description, you should consider this and output the JSON:\n\n* The user intent is: tap the switch button, sleep, and tap the 'English' option\n* The language switch button is shown in the screenshot, and can be located by the page description or the id marked with a rectangle. So we can plan a Tap action to do this.\n* Plan a Sleep action to wait for 1 second to ensure the language options are displayed.\n* The \"English\" option button is not shown in the screenshot now, it means it may only show after the previous actions are finished. So don't plan any action to do this.\n* Log what these action do: Click the language switch button to open the language options. Wait for 1 second.\n* The task cannot be accomplished (because the last tapping action is not finished yet), so the \\`more_actions_needed_by_instruction\\` field is true. The \\`error\\` field is null.\n\n{\n \"actions\":[\n {\n \"thought\": \"Click the language switch button to open the language options.\",\n \"type\": \"Tap\", \n \"param\": null,\n \"locate\": { id: \"c81c4e9a33\", prompt: \"The language switch button\" }},\n },\n {\n \"thought\": \"Wait for 1 second to ensure the language options are displayed.\",\n \"type\": \"Sleep\",\n \"param\": { \"timeMs\": 1000 },\n }\n ],\n \"error\": null,\n \"more_actions_needed_by_instruction\": true,\n \"log\": \"Click the language switch button to open the language options. Wait for 1 second\",\n}\n\n### Example: What NOT to do\nWrong output:\n{\n \"actions\":[\n {\n \"thought\": \"Click the language switch button to open the language options.\",\n \"type\": \"Tap\",\n \"param\": null,\n \"locate\": {\n { \"id\": \"c81c4e9a33\" }, // WRONG: prompt is missing, this is not a valid LocateParam\n }\n },\n {\n \"thought\": \"Click the English option\",\n \"type\": \"Tap\", \n \"param\": null,\n \"locate\": null, // This means the 'English' option is not shown in the screenshot, the task cannot be accomplished\n }\n ],\n \"more_actions_needed_by_instruction\": false, // WRONG: should be true\n \"log\": \"Click the language switch button to open the language options\",\n}\n`;\nasync function systemPromptToTaskPlanning({ actionSpace, vlMode }) {\n if (vlMode) return systemTemplateOfVLPlanning({\n actionSpace,\n vlMode\n });\n return `${systemTemplateOfLLM({\n actionSpace\n })}\\n\\n${outputTemplate}`;\n}\nconst planSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'action_items',\n strict: false,\n schema: {\n type: 'object',\n strict: false,\n properties: {\n actions: {\n type: 'array',\n items: {\n type: 'object',\n strict: false,\n properties: {\n thought: {\n type: 'string',\n description: 'Reasons for generating this task, and why this task is feasible on this page'\n },\n type: {\n type: 'string',\n description: 'Type of action'\n },\n param: {\n anyOf: [\n {\n type: 'null'\n },\n {\n type: 'object',\n additionalProperties: true\n }\n ],\n description: 'Parameter of the action'\n },\n locate: {\n type: [\n 'object',\n 'null'\n ],\n properties: {\n id: {\n type: 'string'\n },\n prompt: {\n type: 'string'\n }\n },\n required: [\n 'id',\n 'prompt'\n ],\n additionalProperties: false,\n description: 'Location information for the target element'\n }\n },\n required: [\n 'thought',\n 'type',\n 'param',\n 'locate'\n ],\n additionalProperties: false\n },\n description: 'List of actions to be performed'\n },\n more_actions_needed_by_instruction: {\n type: 'boolean',\n description: 'If all the actions described in the instruction have been covered by this action and logs, set this field to false.'\n },\n log: {\n type: 'string',\n description: 'Log what these planned actions do. Do not include further actions that have not been planned.'\n },\n error: {\n type: [\n 'string',\n 'null'\n ],\n description: 'Error messages about unexpected situations'\n }\n },\n required: [\n 'actions',\n 'more_actions_needed_by_instruction',\n 'log',\n 'error'\n ],\n additionalProperties: false\n }\n }\n};\nconst generateTaskBackgroundContext = (userInstruction, log, userActionContext)=>{\n if (log) return `\nHere is the user's instruction:\n\n<instruction>\n <high_priority_knowledge>\n ${userActionContext}\n </high_priority_knowledge>\n\n ${userInstruction}\n</instruction>\n\nThese are the logs from previous executions, which indicate what was done in the previous actions.\nDo NOT repeat these actions.\n<previous_logs>\n${log}\n</previous_logs>\n`;\n return `\nHere is the user's instruction:\n<instruction>\n <high_priority_knowledge>\n ${userActionContext}\n </high_priority_knowledge>\n\n ${userInstruction}\n</instruction>\n`;\n};\nconst automationUserPrompt = (vlMode)=>{\n if (vlMode) return new PromptTemplate({\n template: '{taskBackgroundContext}',\n inputVariables: [\n 'taskBackgroundContext'\n ]\n });\n return new PromptTemplate({\n template: `\npageDescription:\n=====================================\n{pageDescription}\n=====================================\n\n{taskBackgroundContext}`,\n inputVariables: [\n \"pageDescription\",\n 'taskBackgroundContext'\n ]\n });\n};\nfunction checkAIConfig() {\n const openaiKey = getAIConfig(OPENAI_API_KEY);\n const azureConfig = getAIConfig(MIDSCENE_USE_AZURE_OPENAI);\n const anthropicKey = getAIConfig(ANTHROPIC_API_KEY);\n const initConfigJson = getAIConfig(MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n if (openaiKey) return true;\n if (azureConfig) return true;\n if (anthropicKey) return true;\n return Boolean(initConfigJson);\n}\nlet debugConfigInitialized = false;\nfunction initDebugConfig() {\n if (debugConfigInitialized) return;\n const shouldPrintTiming = getAIConfigInBoolean(MIDSCENE_DEBUG_AI_PROFILE);\n let debugConfig = '';\n if (shouldPrintTiming) {\n console.warn('MIDSCENE_DEBUG_AI_PROFILE is deprecated, use DEBUG=midscene:ai:profile instead');\n debugConfig = 'ai:profile';\n }\n const shouldPrintAIResponse = getAIConfigInBoolean(MIDSCENE_DEBUG_AI_RESPONSE);\n if (shouldPrintAIResponse) {\n console.warn('MIDSCENE_DEBUG_AI_RESPONSE is deprecated, use DEBUG=midscene:ai:response instead');\n debugConfig = debugConfig ? 'ai:*' : 'ai:call';\n }\n if (debugConfig) enableDebug(debugConfig);\n debugConfigInitialized = true;\n}\nconst defaultModel = 'gpt-4o';\nfunction getModelName() {\n let modelName = defaultModel;\n const nameInConfig = getAIConfig(MIDSCENE_MODEL_NAME);\n if (nameInConfig) modelName = nameInConfig;\n return modelName;\n}\nasync function createChatClient({ AIActionTypeValue }) {\n initDebugConfig();\n let openai;\n const extraConfig = getAIConfigInJson(MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n const socksProxy = getAIConfig(MIDSCENE_OPENAI_SOCKS_PROXY);\n const httpProxy = getAIConfig(MIDSCENE_OPENAI_HTTP_PROXY);\n let proxyAgent;\n const debugProxy = getDebug('ai:call:proxy');\n if (httpProxy) {\n debugProxy('using http proxy', httpProxy);\n proxyAgent = new HttpsProxyAgent(httpProxy);\n } else if (socksProxy) {\n debugProxy('using socks proxy', socksProxy);\n proxyAgent = new SocksProxyAgent(socksProxy);\n }\n if (getAIConfig(OPENAI_USE_AZURE)) openai = new AzureOpenAI({\n baseURL: getAIConfig(OPENAI_BASE_URL),\n apiKey: getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n dangerouslyAllowBrowser: true\n });\n else if (getAIConfig(MIDSCENE_USE_AZURE_OPENAI)) {\n const extraAzureConfig = getAIConfigInJson(MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON);\n const scope = getAIConfig(MIDSCENE_AZURE_OPENAI_SCOPE);\n let tokenProvider;\n if (scope) {\n assert(!ifInBrowser, 'Azure OpenAI is not supported in browser with Midscene.');\n const credential = new DefaultAzureCredential();\n assert(scope, 'MIDSCENE_AZURE_OPENAI_SCOPE is required');\n tokenProvider = getBearerTokenProvider(credential, scope);\n openai = new AzureOpenAI({\n azureADTokenProvider: tokenProvider,\n endpoint: getAIConfig(AZURE_OPENAI_ENDPOINT),\n apiVersion: getAIConfig(AZURE_OPENAI_API_VERSION),\n deployment: getAIConfig(AZURE_OPENAI_DEPLOYMENT),\n ...extraConfig,\n ...extraAzureConfig\n });\n } else openai = new AzureOpenAI({\n apiKey: getAIConfig(AZURE_OPENAI_KEY),\n endpoint: getAIConfig(AZURE_OPENAI_ENDPOINT),\n apiVersion: getAIConfig(AZURE_OPENAI_API_VERSION),\n deployment: getAIConfig(AZURE_OPENAI_DEPLOYMENT),\n dangerouslyAllowBrowser: true,\n ...extraConfig,\n ...extraAzureConfig\n });\n } else if (!getAIConfig(MIDSCENE_USE_ANTHROPIC_SDK)) {\n const baseURL = getAIConfig(OPENAI_BASE_URL);\n if ('string' == typeof baseURL) {\n if (!/^https?:\\/\\//.test(baseURL)) throw new Error(`OPENAI_BASE_URL must be a valid URL starting with http:// or https://, but got: ${baseURL}\\nPlease check your config.`);\n }\n openai = new openai_0({\n baseURL: getAIConfig(OPENAI_BASE_URL),\n apiKey: getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n defaultHeaders: {\n ...(null == extraConfig ? void 0 : extraConfig.defaultHeaders) || {},\n [MIDSCENE_API_TYPE]: AIActionTypeValue.toString()\n },\n dangerouslyAllowBrowser: true\n });\n }\n if (openai && getAIConfigInBoolean(MIDSCENE_LANGSMITH_DEBUG)) {\n if (ifInBrowser) throw new Error('langsmith is not supported in browser');\n console.log('DEBUGGING MODE: langsmith wrapper enabled');\n const { wrapOpenAI } = await import(\"langsmith/wrappers\");\n openai = wrapOpenAI(openai);\n }\n if (void 0 !== openai) return {\n completion: openai.chat.completions,\n style: 'openai'\n };\n if (getAIConfig(MIDSCENE_USE_ANTHROPIC_SDK)) {\n const apiKey = getAIConfig(ANTHROPIC_API_KEY);\n assert(apiKey, 'ANTHROPIC_API_KEY is required');\n openai = new Anthropic({\n apiKey,\n httpAgent: proxyAgent,\n dangerouslyAllowBrowser: true\n });\n }\n if (void 0 !== openai && openai.messages) return {\n completion: openai.messages,\n style: 'anthropic'\n };\n throw new Error('Openai SDK or Anthropic SDK is not initialized');\n}\nasync function service_caller_call(messages, AIActionTypeValue, responseFormat, options) {\n assert(checkAIConfig(), 'Cannot find config for AI model service. If you are using a self-hosted model without validating the API key, please set `OPENAI_API_KEY` to any non-null value. https://midscenejs.com/model-provider.html');\n const { completion, style } = await createChatClient({\n AIActionTypeValue\n });\n const maxTokens = getAIConfig(OPENAI_MAX_TOKENS);\n const debugCall = getDebug('ai:call');\n const debugProfileStats = getDebug('ai:profile:stats');\n const debugProfileDetail = getDebug('ai:profile:detail');\n const startTime = Date.now();\n const model = getModelName();\n const isStreaming = (null == options ? void 0 : options.stream) && (null == options ? void 0 : options.onChunk);\n let content;\n let accumulated = '';\n let usage;\n let timeCost;\n const commonConfig = {\n temperature: 'vlm-ui-tars' === vlLocateMode() ? 0.0 : 0.1,\n stream: !!isStreaming,\n max_tokens: 'number' == typeof maxTokens ? maxTokens : Number.parseInt(maxTokens || '2048', 10),\n ...'qwen-vl' === vlLocateMode() ? {\n vl_high_resolution_images: true\n } : {}\n };\n try {\n if ('openai' === style) {\n debugCall(`sending ${isStreaming ? 'streaming ' : ''}request to ${model}`);\n if (isStreaming) {\n const stream = await completion.create({\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig\n }, {\n stream: true\n });\n for await (const chunk of stream){\n var _chunk_choices__delta, _chunk_choices_, _chunk_choices, _chunk_choices__delta1, _chunk_choices_1, _chunk_choices1, _chunk_choices_2, _chunk_choices2;\n const content = (null == (_chunk_choices = chunk.choices) ? void 0 : null == (_chunk_choices_ = _chunk_choices[0]) ? void 0 : null == (_chunk_choices__delta = _chunk_choices_.delta) ? void 0 : _chunk_choices__delta.content) || '';\n const reasoning_content = (null == (_chunk_choices1 = chunk.choices) ? void 0 : null == (_chunk_choices_1 = _chunk_choices1[0]) ? void 0 : null == (_chunk_choices__delta1 = _chunk_choices_1.delta) ? void 0 : _chunk_choices__delta1.reasoning_content) || '';\n if (chunk.usage) usage = chunk.usage;\n if (content || reasoning_content) {\n accumulated += content;\n const chunkData = {\n content,\n reasoning_content,\n accumulated,\n isComplete: false,\n usage: void 0\n };\n options.onChunk(chunkData);\n }\n if (null == (_chunk_choices2 = chunk.choices) ? void 0 : null == (_chunk_choices_2 = _chunk_choices2[0]) ? void 0 : _chunk_choices_2.finish_reason) {\n timeCost = Date.now() - startTime;\n if (!usage) {\n const estimatedTokens = Math.max(1, Math.floor(accumulated.length / 4));\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: 2 * estimatedTokens\n };\n }\n const finalChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: {\n prompt_tokens: usage.prompt_tokens ?? 0,\n completion_tokens: usage.completion_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n time_cost: timeCost ?? 0\n }\n };\n options.onChunk(finalChunk);\n break;\n }\n }\n content = accumulated;\n debugProfileStats(`streaming model, ${model}, mode, ${vlLocateMode() || 'default'}, cost-ms, ${timeCost}`);\n } else {\n var _result_usage, _result_usage1, _result_usage2;\n const result = await completion.create({\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig\n });\n timeCost = Date.now() - startTime;\n debugProfileStats(`model, ${model}, mode, ${vlLocateMode() || 'default'}, ui-tars-version, ${uiTarsModelVersion()}, prompt-tokens, ${(null == (_result_usage = result.usage) ? void 0 : _result_usage.prompt_tokens) || ''}, completion-tokens, ${(null == (_result_usage1 = result.usage) ? void 0 : _result_usage1.completion_tokens) || ''}, total-tokens, ${(null == (_result_usage2 = result.usage) ? void 0 : _result_usage2.total_tokens) || ''}, cost-ms, ${timeCost}, requestId, ${result._request_id || ''}`);\n debugProfileDetail(`model usage detail: ${JSON.stringify(result.usage)}`);\n assert(result.choices, `invalid response from LLM service: ${JSON.stringify(result)}`);\n content = result.choices[0].message.content;\n usage = result.usage;\n }\n debugCall(`response: ${content}`);\n assert(content, 'empty content');\n } else if ('anthropic' === style) {\n const convertImageContent = (content)=>{\n if ('image_url' === content.type) {\n const imgBase64 = content.image_url.url;\n assert(imgBase64, 'image_url is required');\n return {\n source: {\n type: 'base64',\n media_type: imgBase64.includes('data:image/png;base64,') ? 'image/png' : 'image/jpeg',\n data: imgBase64.split(',')[1]\n },\n type: 'image'\n };\n }\n return content;\n };\n if (isStreaming) {\n const stream = await completion.create({\n model,\n system: 'You are a versatile professional in software UI automation',\n messages: messages.map((m)=>({\n role: 'user',\n content: Array.isArray(m.content) ? m.content.map(convertImageContent) : m.content\n })),\n response_format: responseFormat,\n ...commonConfig\n });\n for await (const chunk of stream){\n var _chunk_delta;\n const content = (null == (_chunk_delta = chunk.delta) ? void 0 : _chunk_delta.text) || '';\n if (content) {\n accumulated += content;\n const chunkData = {\n content,\n accumulated,\n reasoning_content: '',\n isComplete: false,\n usage: void 0\n };\n options.onChunk(chunkData);\n }\n if ('message_stop' === chunk.type) {\n timeCost = Date.now() - startTime;\n const anthropicUsage = chunk.usage;\n const finalChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: anthropicUsage ? {\n prompt_tokens: anthropicUsage.input_tokens ?? 0,\n completion_tokens: anthropicUsage.output_tokens ?? 0,\n total_tokens: (anthropicUsage.input_tokens ?? 0) + (anthropicUsage.output_tokens ?? 0),\n time_cost: timeCost ?? 0\n } : void 0\n };\n options.onChunk(finalChunk);\n break;\n }\n }\n content = accumulated;\n } else {\n const result = await completion.create({\n model,\n system: 'You are a versatile professional in software UI automation',\n messages: messages.map((m)=>({\n role: 'user',\n content: Array.isArray(m.content) ? m.content.map(convertImageContent) : m.content\n })),\n response_format: responseFormat,\n ...commonConfig\n });\n timeCost = Date.now() - startTime;\n content = result.content[0].text;\n usage = result.usage;\n }\n assert(content, 'empty content');\n }\n if (isStreaming && !usage) {\n const estimatedTokens = Math.max(1, Math.floor((content || '').length / 4));\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: 2 * estimatedTokens\n };\n }\n return {\n content: content || '',\n usage: usage ? {\n prompt_tokens: usage.prompt_tokens ?? 0,\n completion_tokens: usage.completion_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n time_cost: timeCost ?? 0\n } : void 0,\n isStreamed: !!isStreaming\n };\n } catch (e) {\n console.error(' call AI error', e);\n const newError = new Error(`failed to call ${isStreaming ? 'streaming ' : ''}AI model service: ${e.message}. Trouble shooting: https://midscenejs.com/model-provider.html`, {\n cause: e\n });\n throw newError;\n }\n}\nasync function callToGetJSONObject(messages, AIActionTypeValue) {\n let responseFormat;\n const model = getModelName();\n if (model.includes('gpt-4')) switch(AIActionTypeValue){\n case common_AIActionType.ASSERT:\n responseFormat = assertSchema;\n break;\n case common_AIActionType.INSPECT_ELEMENT:\n responseFormat = locatorSchema;\n break;\n case common_AIActionType.PLAN:\n responseFormat = planSchema;\n break;\n case common_AIActionType.EXTRACT_DATA:\n case common_AIActionType.DESCRIBE_ELEMENT:\n responseFormat = {\n type: types_AIResponseFormat.JSON\n };\n break;\n }\n if ('gpt-4o-2024-05-13' === model) responseFormat = {\n type: types_AIResponseFormat.JSON\n };\n const response = await service_caller_call(messages, AIActionTypeValue, responseFormat);\n assert(response, 'empty response');\n const jsonContent = safeParseJson(response.content);\n return {\n content: jsonContent,\n usage: response.usage\n };\n}\nasync function callAiFnWithStringResponse(msgs, AIActionTypeValue) {\n const { content, usage } = await service_caller_call(msgs, AIActionTypeValue);\n return {\n content,\n usage\n };\n}\nfunction extractJSONFromCodeBlock(response) {\n try {\n const jsonMatch = response.match(/^\\s*(\\{[\\s\\S]*\\})\\s*$/);\n if (jsonMatch) return jsonMatch[1];\n const codeBlockMatch = response.match(/```(?:json)?\\s*(\\{[\\s\\S]*?\\})\\s*```/);\n if (codeBlockMatch) return codeBlockMatch[1];\n const jsonLikeMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonLikeMatch) return jsonLikeMatch[0];\n } catch {}\n return response;\n}\nfunction preprocessDoubaoBboxJson(input) {\n if (input.includes('bbox')) while(/\\d+\\s+\\d+/.test(input))input = input.replace(/(\\d+)\\s+(\\d+)/g, '$1,$2');\n return input;\n}\nfunction safeParseJson(input) {\n const cleanJsonString = extractJSONFromCodeBlock(input);\n if (null == cleanJsonString ? void 0 : cleanJsonString.match(/\\((\\d+),(\\d+)\\)/)) {\n var _cleanJsonString_match;\n return null == (_cleanJsonString_match = cleanJsonString.match(/\\((\\d+),(\\d+)\\)/)) ? void 0 : _cleanJsonString_match.slice(1).map(Number);\n }\n try {\n return JSON.parse(cleanJsonString);\n } catch {}\n try {\n return JSON.parse(jsonrepair(cleanJsonString));\n } catch (e) {}\n if ('doubao-vision' === vlLocateMode() || 'vlm-ui-tars' === vlLocateMode()) {\n const jsonString = preprocessDoubaoBboxJson(cleanJsonString);\n return JSON.parse(jsonrepair(jsonString));\n }\n throw Error(`failed to parse json response: ${input}`);\n}\nfunction describeSize(size) {\n return `${size.width} x ${size.height}`;\n}\nconst distanceThreshold = 16;\nfunction elementByPositionWithElementInfo(treeRoot, position, options) {\n const requireStrictDistance = (null == options ? void 0 : options.requireStrictDistance) ?? true;\n const filterPositionElements = (null == options ? void 0 : options.filterPositionElements) ?? false;\n assert(void 0 !== position, 'position is required for query');\n const matchingElements = [];\n function dfs(node) {\n if (null == node ? void 0 : node.node) {\n const item = node.node;\n if (item.rect.left <= position.x && position.x <= item.rect.left + item.rect.width && item.rect.top <= position.y && position.y <= item.rect.top + item.rect.height) {\n var _item_attributes;\n if (!(filterPositionElements && (null == (_item_attributes = item.attributes) ? void 0 : _item_attributes.nodeType) === NodeType.POSITION) && item.isVisible) matchingElements.push(item);\n }\n }\n for (const child of node.children)dfs(child);\n }\n dfs(treeRoot);\n if (0 === matchingElements.length) return;\n const element = matchingElements.reduce((smallest, current)=>{\n const smallestArea = smallest.rect.width * smallest.rect.height;\n const currentArea = current.rect.width * current.rect.height;\n return currentArea < smallestArea ? current : smallest;\n });\n const distanceToCenter = distance({\n x: element.center[0],\n y: element.center[1]\n }, position);\n if (requireStrictDistance) return distanceToCenter <= distanceThreshold ? element : void 0;\n return element;\n}\nfunction distance(point1, point2) {\n return Math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2);\n}\nasync function describeUserPage(context, opt) {\n const { screenshotBase64 } = context;\n let width;\n let height;\n if (context.size) ({ width, height } = context.size);\n else {\n const imgSize = await imageInfoOfBase64(screenshotBase64);\n ({ width, height } = imgSize);\n }\n const treeRoot = context.tree;\n const idElementMap = {};\n const flatElements = treeToList(treeRoot);\n if ((null == opt ? void 0 : opt.domIncluded) === true && flatElements.length >= 5000) console.warn('The number of elements is too large, it may cause the prompt to be too long, please use domIncluded: \"visible-only\" to reduce the number of elements');\n flatElements.forEach((element)=>{\n idElementMap[element.id] = element;\n if (void 0 !== element.indexId) idElementMap[`${element.indexId}`] = element;\n });\n let pageDescription = '';\n const visibleOnly = (null == opt ? void 0 : opt.visibleOnly) ?? (null == opt ? void 0 : opt.domIncluded) === 'visible-only';\n if ((null == opt ? void 0 : opt.domIncluded) || !vlLocateMode()) {\n const contentTree = await descriptionOfTree(treeRoot, null == opt ? void 0 : opt.truncateTextLength, null == opt ? void 0 : opt.filterNonTextContent, visibleOnly);\n const sizeDescription = describeSize({\n width,\n height\n });\n pageDescription = `The size of the page: ${sizeDescription} \\n The page elements tree:\\n${contentTree}`;\n }\n return {\n description: pageDescription,\n elementById (idOrIndexId) {\n assert(void 0 !== idOrIndexId, 'id is required for query');\n const item = idElementMap[`${idOrIndexId}`];\n return item;\n },\n elementByPosition (position, size) {\n return elementByPositionWithElementInfo(treeRoot, position);\n },\n insertElementByPosition (position) {\n const element = generateElementByPosition(position);\n treeRoot.children.push({\n node: element,\n children: []\n });\n flatElements.push(element);\n idElementMap[element.id] = element;\n return element;\n },\n size: {\n width,\n height\n }\n };\n}\nconst getScreenshotsForLLM = (events, maxScreenshots = 1)=>{\n const eventsWithScreenshots = events.filter((event)=>event.screenshotBefore || event.screenshotAfter || event.screenshotWithBox);\n const sortedEvents = [\n ...eventsWithScreenshots\n ].sort((a, b)=>{\n if ('navigation' === a.type && 'navigation' !== b.type) return -1;\n if ('navigation' !== a.type && 'navigation' === b.type) return 1;\n if ('click' === a.type && 'click' !== b.type) return -1;\n if ('click' !== a.type && 'click' === b.type) return 1;\n return 0;\n });\n const screenshots = [];\n for (const event of sortedEvents){\n const screenshot = event.screenshotWithBox || event.screenshotAfter || event.screenshotBefore;\n if (screenshot && !screenshots.includes(screenshot)) {\n screenshots.push(screenshot);\n if (screenshots.length >= maxScreenshots) break;\n }\n }\n return screenshots;\n};\nconst filterEventsByType = (events)=>({\n navigationEvents: events.filter((event)=>'navigation' === event.type),\n clickEvents: events.filter((event)=>'click' === event.type),\n inputEvents: events.filter((event)=>'input' === event.type),\n scrollEvents: events.filter((event)=>'scroll' === event.type)\n });\nconst createEventCounts = (filteredEvents, totalEvents)=>({\n navigation: filteredEvents.navigationEvents.length,\n click: filteredEvents.clickEvents.length,\n input: filteredEvents.inputEvents.length,\n scroll: filteredEvents.scrollEvents.length,\n total: totalEvents\n });\nconst extractInputDescriptions = (inputEvents)=>inputEvents.map((event)=>({\n description: event.elementDescription || '',\n value: event.value || ''\n })).filter((item)=>item.description && item.value);\nconst processEventsForLLM = (events)=>events.map((event)=>({\n type: event.type,\n timestamp: event.timestamp,\n url: event.url,\n title: event.title,\n elementDescription: event.elementDescription,\n value: event.value,\n pageInfo: event.pageInfo,\n elementRect: event.elementRect\n }));\nconst prepareEventSummary = (events, options = {})=>{\n const filteredEvents = filterEventsByType(events);\n const eventCounts = createEventCounts(filteredEvents, events.length);\n const startUrl = filteredEvents.navigationEvents.length > 0 ? filteredEvents.navigationEvents[0].url || '' : '';\n const clickDescriptions = filteredEvents.clickEvents.map((event)=>event.elementDescription).filter((desc)=>Boolean(desc)).slice(0, 10);\n const inputDescriptions = extractInputDescriptions(filteredEvents.inputEvents).slice(0, 10);\n const urls = filteredEvents.navigationEvents.map((e)=>e.url).filter((url)=>Boolean(url)).slice(0, 5);\n const processedEvents = processEventsForLLM(events);\n return {\n testName: options.testName || 'Automated test from recorded events',\n startUrl,\n eventCounts,\n urls,\n clickDescriptions,\n inputDescriptions,\n events: processedEvents\n };\n};\nconst createMessageContent = (promptText, screenshots = [], includeScreenshots = true)=>{\n const messageContent = [\n {\n type: 'text',\n text: promptText\n }\n ];\n if (includeScreenshots && screenshots.length > 0) {\n messageContent.unshift({\n type: 'text',\n text: 'Here are screenshots from the recording session to help you understand the context:'\n });\n screenshots.forEach((screenshot)=>{\n messageContent.push({\n type: 'image_url',\n image_url: {\n url: screenshot\n }\n });\n });\n }\n return messageContent;\n};\nconst validateEvents = (events)=>{\n if (!events.length) throw new Error('No events provided for test generation');\n};\nconst generateYamlTest = async (events, options = {})=>{\n try {\n validateEvents(events);\n const summary = prepareEventSummary(events, {\n testName: options.testName,\n maxScreenshots: options.maxScreenshots || 3\n });\n const yamlSummary = {\n ...summary,\n includeTimestamps: options.includeTimestamps || false\n };\n const screenshots = getScreenshotsForLLM(events, options.maxScreenshots || 3);\n const prompt = [\n {\n role: 'system',\n content: `You are an expert in Midscene.js YAML test generation. Generate clean, accurate YAML following these rules: ${YAML_EXAMPLE_CODE}`\n },\n {\n role: 'user',\n content: `Generate YAML test for Midscene.js automation from recorded browser events.\n\nEvent Summary:\n${JSON.stringify(yamlSummary, null, 2)}\n\nConvert events:\n- navigation \\u{2192} target.url\n- click \\u{2192} aiTap with element description\n- input \\u{2192} aiInput with value and locate\n- scroll \\u{2192} aiScroll with appropriate direction\n- Add aiAssert for important state changes\n\nRespond with YAML only, no explanations.`\n }\n ];\n if (screenshots.length > 0) {\n prompt.push({\n role: 'user',\n content: 'Here are screenshots from the recording session to help you understand the context:'\n });\n prompt.push({\n role: 'user',\n content: screenshots.map((screenshot)=>({\n type: 'image_url',\n image_url: {\n url: screenshot\n }\n }))\n });\n }\n const response = await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA);\n if ((null == response ? void 0 : response.content) && 'string' == typeof response.content) return response.content;\n throw new Error('Failed to generate YAML test configuration');\n } catch (error) {\n throw new Error(`Failed to generate YAML test: ${error}`);\n }\n};\nconst generateYamlTestStream = async (events, options = {})=>{\n try {\n validateEvents(events);\n const summary = prepareEventSummary(events, {\n testName: options.testName,\n maxScreenshots: options.maxScreenshots || 3\n });\n const yamlSummary = {\n ...summary,\n includeTimestamps: options.includeTimestamps || false\n };\n const screenshots = getScreenshotsForLLM(events, options.maxScreenshots || 3);\n const prompt = [\n {\n role: 'system',\n content: `You are an expert in Midscene.js YAML test generation. Generate clean, accurate YAML following these rules: ${YAML_EXAMPLE_CODE}`\n },\n {\n role: 'user',\n content: `Generate YAML test for Midscene.js automation from recorded browser events.\n\nEvent Summary:\n${JSON.stringify(yamlSummary, null, 2)}\n\nConvert events:\n- navigation \\u{2192} target.url\n- click \\u{2192} aiTap with element description\n- input \\u{2192} aiInput with value and locate\n- scroll \\u{2192} aiScroll with appropriate direction\n- Add aiAssert for important state changes\n\nRespond with YAML only, no explanations.`\n }\n ];\n if (screenshots.length > 0) {\n prompt.push({\n role: 'user',\n content: 'Here are screenshots from the recording session to help you understand the context:'\n });\n prompt.push({\n role: 'user',\n content: screenshots.map((screenshot)=>({\n type: 'image_url',\n image_url: {\n url: screenshot\n }\n }))\n });\n }\n if (options.stream && options.onChunk) return await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA, void 0, {\n stream: true,\n onChunk: options.onChunk\n });\n {\n const response = await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA);\n if ((null == response ? void 0 : response.content) && 'string' == typeof response.content) return {\n content: response.content,\n usage: response.usage,\n isStreamed: false\n };\n throw new Error('Failed to generate YAML test configuration');\n }\n } catch (error) {\n throw new Error(`Failed to generate YAML test: ${error}`);\n }\n};\nfunction systemPromptToExtract() {\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\nThe user will give you a screenshot, the contents of it (optional), and some data requirements in <DATA_DEMAND>. You need to extract the data according to the <DATA_DEMAND>.\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\nIf the user provides multiple reference images, please carefully review the reference images with the screenshot and provide the correct answer for <DATA_DEMAND>.\n\nIf the user requests reasons to be provided, please provide the thought field in response, less then 100 words.\n\nReturn in the following JSON format:\n{\n thought: string, // the thought process of the extraction, less then 100 words, not required by default.\n data: any, // the extracted data. 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.\n errors: [], // string[], error message if any\n}\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{\n data: {\n name: \"John\",\n age: 30,\n isAdmin: true\n },\n}\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{\n data: [\"todo 1\", \"todo 2\", \"todo 3\"],\n}\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{\n data: \"todo list\",\n}\n\n# Example 4\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\n{\n \"result\": \"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{\n data: { result: true },\n}\n`;\n}\nconst extractDataQueryPrompt = async (pageDescription, dataQuery)=>{\n let dataQueryText = '';\n dataQueryText = 'string' == typeof dataQuery ? dataQuery : JSON.stringify(dataQuery, null, 2);\n const extractDataPrompt = new PromptTemplate({\n template: `\n<PageDescription>\n{pageDescription}\n</PageDescription>\n\n<DATA_DEMAND>\n{dataQuery}\n</DATA_DEMAND>\n `,\n inputVariables: [\n \"pageDescription\",\n 'dataQuery'\n ]\n });\n return await extractDataPrompt.format({\n pageDescription,\n dataQuery: dataQueryText\n });\n};\nfunction systemPromptToLocateSection(vlMode) {\n return `\nYou goal is to find out one section containing the target element in the screenshot, put it in the \\`bbox\\` field. If the user describe the target element with some reference elements, you should also find the section containing the reference elements, put it in the \\`references_bbox\\` field.\n\nUsually, it should be approximately an area not more than 300x300px. Changes of the size are allowed if there are many elements to cover.\n\nreturn in this JSON format:\n\\`\\`\\`json\n{\n \"bbox\": [number, number, number, number],\n \"references_bbox\"?: [\n [number, number, number, number],\n [number, number, number, number],\n ...\n ],\n \"error\"?: string\n}\n\\`\\`\\`\n\nIn which, all the numbers in the \\`bbox\\` and \\`references_bbox\\` represent ${bboxDescription(vlMode)}.\n\nFor example, if the user describe the target element as \"the delete button on the second row with title 'Peter'\", you should put the bounding box of the delete button in the \\`bbox\\` field, and the bounding box of the second row in the \\`references_bbox\\` field.\n\nthe return value should be like this:\n\\`\\`\\`json\n{\n \"bbox\": [100, 100, 200, 200],\n \"references_bbox\": [[100, 100, 200, 200]]\n}\n\\`\\`\\`\n`;\n}\nconst sectionLocatorInstruction = new PromptTemplate({\n template: `Here is the target element user interested in:\n<targetDescription>\n{sectionDescription}\n</targetDescription>\n `,\n inputVariables: [\n \"sectionDescription\"\n ]\n});\nconst debugInspect = getDebug('ai:inspect');\nconst debugSection = getDebug('ai:section');\nconst extraTextFromUserPrompt = (prompt)=>{\n if ('string' == typeof prompt) return prompt;\n return prompt.prompt;\n};\nconst promptsToChatParam = async (multimodalPrompt)=>{\n var _multimodalPrompt_images;\n const msgs = [];\n if (null == multimodalPrompt ? void 0 : null == (_multimodalPrompt_images = multimodalPrompt.images) ? void 0 : _multimodalPrompt_images.length) {\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: 'Next, I will provide all the reference images.'\n }\n ]\n });\n for (const item of multimodalPrompt.images){\n const base64 = await preProcessImageUrl(item.url, !!multimodalPrompt.convertHttpImage2Base64);\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: `reference image ${item.name}:`\n }\n ]\n });\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: base64,\n detail: 'high'\n }\n }\n ]\n });\n }\n }\n return msgs;\n};\nasync function AiLocateElement(options) {\n const { context, targetElementDescription, callAI } = options;\n const { screenshotBase64 } = context;\n const { description, elementById, insertElementByPosition } = await describeUserPage(context);\n assert(targetElementDescription, \"cannot find the target element description\");\n const userInstructionPrompt = await findElementPrompt.format({\n pageDescription: description,\n targetElementDescription: extraTextFromUserPrompt(targetElementDescription)\n });\n const systemPrompt = systemPromptToLocateElement(vlLocateMode());\n let imagePayload = screenshotBase64;\n if (options.searchConfig) {\n assert(options.searchConfig.rect, 'searchArea is provided but its rect cannot be found. Failed to locate element');\n assert(options.searchConfig.imageBase64, 'searchArea is provided but its imageBase64 cannot be found. Failed to locate element');\n imagePayload = options.searchConfig.imageBase64;\n } else if ('qwen-vl' === vlLocateMode()) imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n else if (!vlLocateMode()) imagePayload = await markupImageForLLM(screenshotBase64, context.tree, context.size);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: userInstructionPrompt\n }\n ]\n }\n ];\n if ('string' != typeof targetElementDescription) {\n const addOns = await promptsToChatParam({\n images: targetElementDescription.images,\n convertHttpImage2Base64: targetElementDescription.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const callAIFn = callAI || callToGetJSONObject;\n const res = await callAIFn(msgs, common_AIActionType.INSPECT_ELEMENT);\n const rawResponse = JSON.stringify(res.content);\n let resRect;\n let matchedElements = 'elements' in res.content ? res.content.elements : [];\n let errors = 'errors' in res.content ? res.content.errors : [];\n try {\n if ('bbox' in res.content && Array.isArray(res.content.bbox)) {\n var _options_searchConfig_rect, _options_searchConfig, _options_searchConfig_rect1, _options_searchConfig1, _options_searchConfig_rect2, _options_searchConfig2, _options_searchConfig_rect3, _options_searchConfig3;\n resRect = adaptBboxToRect(res.content.bbox, (null == (_options_searchConfig = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect = _options_searchConfig.rect) ? void 0 : _options_searchConfig_rect.width) || context.size.width, (null == (_options_searchConfig1 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect1 = _options_searchConfig1.rect) ? void 0 : _options_searchConfig_rect1.height) || context.size.height, null == (_options_searchConfig2 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect2 = _options_searchConfig2.rect) ? void 0 : _options_searchConfig_rect2.left, null == (_options_searchConfig3 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect3 = _options_searchConfig3.rect) ? void 0 : _options_searchConfig_rect3.top);\n debugInspect('resRect', resRect);\n const rectCenter = {\n x: resRect.left + resRect.width / 2,\n y: resRect.top + resRect.height / 2\n };\n let element = elementByPositionWithElementInfo(context.tree, rectCenter);\n const distanceToCenter = element ? distance({\n x: element.center[0],\n y: element.center[1]\n }, rectCenter) : 0;\n if (!element || distanceToCenter > distanceThreshold) element = insertElementByPosition(rectCenter);\n if (element) {\n matchedElements = [\n element\n ];\n errors = [];\n }\n }\n } catch (e) {\n const msg = e instanceof Error ? `Failed to parse bbox: ${e.message}` : 'unknown error in locate';\n if (errors && (null == errors ? void 0 : errors.length) !== 0) errors.push(`(${msg})`);\n else errors = [\n msg\n ];\n }\n return {\n rect: resRect,\n parseResult: {\n elements: matchedElements,\n errors\n },\n rawResponse,\n elementById,\n usage: res.usage,\n isOrderSensitive: 'object' == typeof res.content && null !== res.content && 'isOrderSensitive' in res.content ? res.content.isOrderSensitive : void 0\n };\n}\nasync function AiLocateSection(options) {\n const { context, sectionDescription } = options;\n const { screenshotBase64 } = context;\n const systemPrompt = systemPromptToLocateSection(vlLocateMode());\n const sectionLocatorInstructionText = await sectionLocatorInstruction.format({\n sectionDescription: extraTextFromUserPrompt(sectionDescription)\n });\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: sectionLocatorInstructionText\n }\n ]\n }\n ];\n if ('string' != typeof sectionDescription) {\n const addOns = await promptsToChatParam({\n images: sectionDescription.images,\n convertHttpImage2Base64: sectionDescription.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const result = await callAiFn(msgs, common_AIActionType.EXTRACT_DATA);\n let sectionRect;\n const sectionBbox = result.content.bbox;\n if (sectionBbox) {\n const targetRect = adaptBboxToRect(sectionBbox, context.size.width, context.size.height);\n debugSection('original targetRect %j', targetRect);\n const referenceBboxList = result.content.references_bbox || [];\n debugSection('referenceBboxList %j', referenceBboxList);\n const referenceRects = referenceBboxList.filter((bbox)=>Array.isArray(bbox)).map((bbox)=>adaptBboxToRect(bbox, context.size.width, context.size.height));\n debugSection('referenceRects %j', referenceRects);\n const mergedRect = mergeRects([\n targetRect,\n ...referenceRects\n ]);\n debugSection('mergedRect %j', mergedRect);\n sectionRect = expandSearchArea(mergedRect, context.size);\n debugSection('expanded sectionRect %j', sectionRect);\n }\n let imageBase64 = screenshotBase64;\n if (sectionRect) imageBase64 = await cropByRect(screenshotBase64, sectionRect, getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL));\n return {\n rect: sectionRect,\n imageBase64,\n error: result.content.error,\n rawResponse: JSON.stringify(result.content),\n usage: result.usage\n };\n}\nasync function AiExtractElementInfo(options) {\n var _options_extractOption;\n const { dataQuery, context, extractOption, multimodalPrompt } = options;\n const systemPrompt = systemPromptToExtract();\n const { screenshotBase64 } = context;\n const { description, elementById } = await describeUserPage(context, {\n truncateTextLength: 200,\n filterNonTextContent: false,\n visibleOnly: false,\n domIncluded: null == extractOption ? void 0 : extractOption.domIncluded\n });\n const extractDataPromptText = await extractDataQueryPrompt(description, dataQuery);\n const userContent = [];\n if ((null == extractOption ? void 0 : extractOption.screenshotIncluded) !== false) userContent.push({\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n });\n userContent.push({\n type: 'text',\n text: extractDataPromptText\n });\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: userContent\n }\n ];\n if (null == (_options_extractOption = options.extractOption) ? void 0 : _options_extractOption.returnThought) msgs.push({\n role: 'user',\n content: 'Please provide reasons.'\n });\n if (multimodalPrompt) {\n const addOns = await promptsToChatParam({\n images: multimodalPrompt.images,\n convertHttpImage2Base64: multimodalPrompt.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const result = await callAiFn(msgs, common_AIActionType.EXTRACT_DATA);\n return {\n parseResult: result.content,\n elementById,\n usage: result.usage\n };\n}\nasync function AiAssert(options) {\n const { assertion, context } = options;\n assert(assertion, 'assertion should not be empty');\n const { screenshotBase64 } = context;\n const systemPrompt = systemPromptToAssert({\n isUITars: getAIConfigInBoolean(MIDSCENE_USE_VLM_UI_TARS)\n });\n const assertionText = extraTextFromUserPrompt(assertion);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: `\nHere is the assertion. Please tell whether it is truthy according to the screenshot.\n=====================================\n${assertionText}\n=====================================\n `\n }\n ]\n }\n ];\n if ('string' != typeof assertion) {\n const addOns = await promptsToChatParam({\n images: assertion.images,\n convertHttpImage2Base64: assertion.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const { content: assertResult, usage } = await callAiFn(msgs, common_AIActionType.ASSERT);\n return {\n content: assertResult,\n usage\n };\n}\nasync function llm_planning_plan(userInstruction, opts) {\n var _planFromAI_action;\n const { callAI, context } = opts || {};\n const { screenshotBase64, size } = context;\n const { description: pageDescription, elementById } = await describeUserPage(context);\n const systemPrompt = await systemPromptToTaskPlanning({\n actionSpace: opts.actionSpace,\n vlMode: vlLocateMode()\n });\n const taskBackgroundContextText = generateTaskBackgroundContext(userInstruction, opts.log, opts.actionContext);\n const userInstructionPrompt = await automationUserPrompt(vlLocateMode()).format({\n pageDescription,\n taskBackgroundContext: taskBackgroundContextText\n });\n let imagePayload = screenshotBase64;\n if ('qwen-vl' === vlLocateMode()) imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n else if (!vlLocateMode()) imagePayload = await markupImageForLLM(screenshotBase64, context.tree, context.size);\n warnGPT4oSizeLimit(size);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: userInstructionPrompt\n }\n ]\n }\n ];\n const call = callAI || callAiFn;\n const { content, usage } = await call(msgs, common_AIActionType.PLAN);\n const rawResponse = JSON.stringify(content, void 0, 2);\n const planFromAI = content;\n const actions = ((null == (_planFromAI_action = planFromAI.action) ? void 0 : _planFromAI_action.type) ? [\n planFromAI.action\n ] : planFromAI.actions) || [];\n const returnValue = {\n ...planFromAI,\n actions,\n rawResponse,\n usage,\n yamlFlow: buildYamlFlowFromPlans(actions, planFromAI.sleep)\n };\n assert(planFromAI, \"can't get plans from AI\");\n if (vlLocateMode()) {\n actions.forEach((action)=>{\n if (action.locate) try {\n action.locate = fillBboxParam(action.locate, size.width, size.height);\n } catch (e) {\n throw new Error(`Failed to fill locate param: ${planFromAI.error} (${e instanceof Error ? e.message : 'unknown error'})`, {\n cause: e\n });\n }\n });\n assert(!planFromAI.error, `Failed to plan actions: ${planFromAI.error}`);\n } else actions.forEach((action)=>{\n var _action_locate;\n if (null == (_action_locate = action.locate) ? void 0 : _action_locate.id) {\n const element = elementById(action.locate.id);\n if (element) action.locate.id = element.id;\n }\n });\n if (0 === actions.length && returnValue.more_actions_needed_by_instruction && !returnValue.sleep) console.warn('No actions planned for the prompt, but model said more actions are needed:', userInstruction);\n return returnValue;\n}\nfunction getUiTarsPlanningPrompt() {\n const preferredLanguage = getPreferredLanguage();\n return `\nYou are a GUI agent. You are given a task and your action history, with screenshots. You need to perform the next action to complete the task. \n\n## Output Format\n\\`\\`\\`\nThought: ...\nAction: ...\n\\`\\`\\`\n\n## Action Space\n\nclick(start_box='[x1, y1, x2, y2]')\nleft_double(start_box='[x1, y1, x2, y2]')\nright_single(start_box='[x1, y1, x2, y2]')\ndrag(start_box='[x1, y1, x2, y2]', end_box='[x3, y3, x4, y4]')\nhotkey(key='')\ntype(content='xxx') # Use escape characters \\\\', \\\\\\\", and \\\\n in content part to ensure we can parse the content in normal python string format. If you want to submit your input, use \\\\n at the end of content. \nscroll(start_box='[x1, y1, x2, y2]', direction='down or up or right or left')\nwait() #Sleep for 5s and take a screenshot to check for any changes.\nfinished(content='xxx') # Use escape characters \\\\', \\\\\", and \\\\n in content part to ensure we can parse the content in normal python string format.\n\n\n## Note\n- Use ${preferredLanguage} in \\`Thought\\` part.\n- Write a small plan and finally summarize your next action (with its target element) in one sentence in \\`Thought\\` part.\n\n## User Instruction\n`;\n}\nconst getSummary = (prediction)=>prediction.replace(/Reflection:[\\s\\S]*?(?=Action_Summary:|Action:|$)/g, '').trim();\nconst debug = getDebug('ui-tars-planning');\nconst bboxSize = 10;\nconst pointToBbox = (point, width, height)=>[\n Math.round(Math.max(point.x - bboxSize / 2, 0)),\n Math.round(Math.max(point.y - bboxSize / 2, 0)),\n Math.round(Math.min(point.x + bboxSize / 2, width)),\n Math.round(Math.min(point.y + bboxSize / 2, height))\n ];\nasync function vlmPlanning(options) {\n const { conversationHistory, userInstruction, size } = options;\n const systemPrompt = getUiTarsPlanningPrompt() + userInstruction;\n const res = await service_caller_call([\n {\n role: 'user',\n content: systemPrompt\n },\n ...conversationHistory\n ], common_AIActionType.INSPECT_ELEMENT);\n const convertedText = convertBboxToCoordinates(res.content);\n const modelVer = uiTarsModelVersion();\n const { parsed } = actionParser({\n prediction: convertedText,\n factor: [\n 1000,\n 1000\n ],\n screenContext: {\n width: size.width,\n height: size.height\n },\n modelVer: modelVer || void 0\n });\n debug('modelVer', modelVer, 'parsed', JSON.stringify(parsed));\n const transformActions = [];\n parsed.forEach((action)=>{\n if ('click' === action.action_type) {\n assert(action.action_inputs.start_box, 'start_box is required');\n const point = getPoint(action.action_inputs.start_box, size);\n transformActions.push({\n type: 'Locate',\n param: {},\n locate: {\n prompt: action.thought || '',\n bbox: pointToBbox({\n x: point[0],\n y: point[1]\n }, size.width, size.height)\n }\n });\n transformActions.push({\n type: 'Tap',\n locate: {\n prompt: action.thought || '',\n bbox: pointToBbox({\n x: point[0],\n y: point[1]\n }, size.width, size.height)\n },\n param: action.thought || ''\n });\n } else if ('drag' === action.action_type) {\n assert(action.action_inputs.start_box, 'start_box is required');\n assert(action.action_inputs.end_box, 'end_box is required');\n const startPoint = getPoint(action.action_inputs.start_box, size);\n const endPoint = getPoint(action.action_inputs.end_box, size);\n transformActions.push({\n type: 'Drag',\n param: {\n start_box: {\n x: startPoint[0],\n y: startPoint[1]\n },\n end_box: {\n x: endPoint[0],\n y: endPoint[1]\n }\n },\n locate: null,\n thought: action.thought || ''\n });\n } else if ('type' === action.action_type) transformActions.push({\n type: 'Input',\n param: {\n value: action.action_inputs.content\n },\n locate: null,\n thought: action.thought || ''\n });\n else if ('scroll' === action.action_type) transformActions.push({\n type: 'Scroll',\n param: {\n direction: action.action_inputs.direction\n },\n locate: null,\n thought: action.thought || ''\n });\n else if ('finished' === action.action_type) transformActions.push({\n type: 'Finished',\n param: {},\n locate: null,\n thought: action.thought || ''\n });\n else if ('hotkey' === action.action_type) if (action.action_inputs.key) {\n const keys = transformHotkeyInput(action.action_inputs.key);\n transformActions.push({\n type: 'KeyboardPress',\n param: {\n value: keys\n },\n locate: null,\n thought: action.thought || ''\n });\n } else console.warn('No key found in action: hotkey. Will not perform action.');\n else if ('wait' === action.action_type) transformActions.push({\n type: 'Sleep',\n param: {\n timeMs: 1000\n },\n locate: null,\n thought: action.thought || ''\n });\n else if ('androidBackButton' === action.action_type) transformActions.push({\n type: 'AndroidBackButton',\n param: {},\n locate: null,\n thought: action.thought || ''\n });\n else if ('androidHomeButton' === action.action_type) transformActions.push({\n type: 'AndroidHomeButton',\n param: {},\n locate: null,\n thought: action.thought || ''\n });\n else if ('androidRecentAppsButton' === action.action_type) transformActions.push({\n type: 'AndroidRecentAppsButton',\n param: {}\n });\n else if ('androidLongPress' === action.action_type) {\n assert(action.action_inputs.start_coords, 'start_coords is required for androidLongPress');\n const point = action.action_inputs.start_coords;\n transformActions.push({\n type: 'AndroidLongPress',\n param: {\n x: point[0],\n y: point[1],\n duration: 1000\n },\n locate: null,\n thought: action.thought || ''\n });\n } else if ('androidPull' === action.action_type) {\n const pullDirection = action.action_inputs.direction || 'down';\n const startPoint = action.action_inputs.start_coords ? {\n x: action.action_inputs.start_coords[0],\n y: action.action_inputs.start_coords[1]\n } : void 0;\n transformActions.push({\n type: 'AndroidPull',\n param: {\n direction: pullDirection,\n startPoint,\n distance: action.action_inputs.distance,\n duration: action.action_inputs.duration || 500\n },\n locate: null,\n thought: action.thought || ''\n });\n }\n });\n if (0 === transformActions.length) throw new Error(`No actions found, response: ${res.content}`, {\n cause: {\n prediction: res.content,\n parsed\n }\n });\n return {\n actions: transformActions,\n actionsFromModel: parsed,\n action_summary: getSummary(res.content),\n usage: res.usage,\n rawResponse: JSON.stringify(res.content, void 0, 2)\n };\n}\nfunction convertBboxToCoordinates(text) {\n const pattern = /<bbox>(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)<\\/bbox>/g;\n function replaceMatch(match, x1, y1, x2, y2) {\n const x1Num = Number.parseInt(x1, 10);\n const y1Num = Number.parseInt(y1, 10);\n const x2Num = Number.parseInt(x2, 10);\n const y2Num = Number.parseInt(y2, 10);\n const x = Math.floor((x1Num + x2Num) / 2);\n const y = Math.floor((y1Num + y2Num) / 2);\n return `(${x},${y})`;\n }\n const cleanedText = text.replace(/\\[EOS\\]/g, '');\n return cleanedText.replace(pattern, replaceMatch).trim();\n}\nfunction getPoint(startBox, size) {\n const [x, y] = JSON.parse(startBox);\n return [\n x * size.width,\n y * size.height\n ];\n}\nasync function resizeImageForUiTars(imageBase64, size) {\n if ('vlm-ui-tars' === vlLocateMode() && uiTarsModelVersion() === UITarsModelVersion.V1_5) {\n debug('ui-tars-v1.5, will check image size', size);\n const currentPixels = size.width * size.height;\n const maxPixels = 12845056;\n if (currentPixels > maxPixels) {\n const resizeFactor = Math.sqrt(maxPixels / currentPixels);\n const newWidth = Math.floor(size.width * resizeFactor);\n const newHeight = Math.floor(size.height * resizeFactor);\n debug('resize image for ui-tars, new width: %s, new height: %s', newWidth, newHeight);\n const resizedImage = await resizeImgBase64(imageBase64, {\n width: newWidth,\n height: newHeight\n });\n return resizedImage;\n }\n }\n return imageBase64;\n}\nconst generatePlaywrightTest = async (events, options = {})=>{\n validateEvents(events);\n const summary = prepareEventSummary(events, {\n testName: options.testName,\n maxScreenshots: options.maxScreenshots || 3\n });\n const playwrightSummary = {\n ...summary,\n waitForNetworkIdle: false !== options.waitForNetworkIdle,\n waitForNetworkIdleTimeout: options.waitForNetworkIdleTimeout || 2000,\n viewportSize: options.viewportSize || {\n width: 1280,\n height: 800\n }\n };\n const screenshots = getScreenshotsForLLM(events, options.maxScreenshots || 3);\n const promptText = `Generate a Playwright test using @midscene/web/playwright that reproduces this recorded browser session. The test should be based on the following events and follow the structure of the example provided. Make the test descriptive with appropriate assertions and validations.\n\nEvent Summary:\n${JSON.stringify(playwrightSummary, null, 2)}\n\nGenerated code should:\n1. Import required dependencies\n2. Set up the test with proper configuration\n3. Include a beforeEach hook to navigate to the starting URL\n4. Implement a test that uses Midscene AI methods (aiTap, aiInput, aiAssert, etc.)\n5. Include appropriate assertions and validations\n6. Follow best practices for Playwright tests\n7. Be ready to execute without further modification\n\nRespond ONLY with the complete Playwright test code, no explanations.`;\n const messageContent = createMessageContent(promptText, screenshots, false !== options.includeScreenshots);\n const systemPrompt = `You are an expert test automation engineer specializing in Playwright and Midscene. \nYour task is to generate a complete, executable Playwright test using @midscene/web/playwright that reproduces a recorded browser session.\n\n${PLAYWRIGHT_EXAMPLE_CODE}`;\n const prompt = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: messageContent\n }\n ];\n const response = await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA);\n if ((null == response ? void 0 : response.content) && 'string' == typeof response.content) return response.content;\n throw new Error('Failed to generate Playwright test code');\n};\nconst generatePlaywrightTestStream = async (events, options = {})=>{\n validateEvents(events);\n const summary = prepareEventSummary(events, {\n testName: options.testName,\n maxScreenshots: options.maxScreenshots || 3\n });\n const playwrightSummary = {\n ...summary,\n waitForNetworkIdle: false !== options.waitForNetworkIdle,\n waitForNetworkIdleTimeout: options.waitForNetworkIdleTimeout || 2000,\n viewportSize: options.viewportSize || {\n width: 1280,\n height: 800\n }\n };\n const screenshots = getScreenshotsForLLM(events, options.maxScreenshots || 3);\n const promptText = `Generate a Playwright test using @midscene/web/playwright that reproduces this recorded browser session. The test should be based on the following events and follow the structure of the example provided. Make the test descriptive with appropriate assertions and validations.\n\nEvent Summary:\n${JSON.stringify(playwrightSummary, null, 2)}\n\nGenerated code should:\n1. Import required dependencies\n2. Set up the test with proper configuration\n3. Include a beforeEach hook to navigate to the starting URL\n4. Implement a test that uses Midscene AI methods (aiTap, aiInput, aiAssert, etc.)\n5. Include appropriate assertions and validations\n6. Follow best practices for Playwright tests\n7. Be ready to execute without further modification\n8. can't wrap this test code in markdown code block\n\nRespond ONLY with the complete Playwright test code, no explanations.`;\n const messageContent = createMessageContent(promptText, screenshots, false !== options.includeScreenshots);\n const systemPrompt = `You are an expert test automation engineer specializing in Playwright and Midscene. \nYour task is to generate a complete, executable Playwright test using @midscene/web/playwright that reproduces a recorded browser session.\n\n${PLAYWRIGHT_EXAMPLE_CODE}`;\n const prompt = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: messageContent\n }\n ];\n if (options.stream && options.onChunk) return await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA, void 0, {\n stream: true,\n onChunk: options.onChunk\n });\n {\n const response = await service_caller_call(prompt, common_AIActionType.EXTRACT_DATA);\n if ((null == response ? void 0 : response.content) && 'string' == typeof response.content) return {\n content: response.content,\n usage: response.usage,\n isStreamed: false\n };\n throw new Error('Failed to generate Playwright test code');\n }\n};\nexport { common_AIActionType as AIActionType, AiAssert, AiExtractElementInfo, AiLocateElement, AiLocateSection, adaptBboxToRect, service_caller_call as callAi, callAiFn, callAiFnWithStringResponse, callToGetJSONObject, describeUserPage, elementByPositionWithElementInfo, generatePlaywrightTest, generatePlaywrightTestStream, generateYamlTest, generateYamlTestStream, llm_planning_plan as plan, resizeImageForUiTars, systemPromptToLocateElement, vlmPlanning };\n\n//# sourceMappingURL=ai-model.mjs.map","import node_assert from \"node:assert\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { getMidsceneRunSubDir } from \"@midscene/shared/common\";\nimport { MIDSCENE_CACHE_MAX_FILENAME_LENGTH, getAIConfigInNumber } from \"@midscene/shared/env\";\nimport { getDebug } from \"@midscene/shared/logger\";\nimport { generateHashId, ifInBrowser, ifInWorker } from \"@midscene/shared/utils\";\nimport js_yaml from \"js-yaml\";\nimport semver from \"semver\";\nimport { getMidsceneVersion, replaceIllegalPathCharsAndSpace } from \"./utils.mjs\";\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst DEFAULT_CACHE_MAX_FILENAME_LENGTH = 200;\nconst debug = getDebug('cache');\nconst lowestSupportedMidsceneVersion = '0.16.10';\nconst cacheFileExt = '.cache.yaml';\nclass TaskCache {\n matchCache(prompt, type) {\n for(let i = 0; i < this.cacheOriginalLength; i++){\n const item = this.cache.caches[i];\n const promptStr = 'string' == typeof prompt ? prompt : JSON.stringify(prompt);\n const key = `${type}:${promptStr}:${i}`;\n if (item.type === type && isDeepStrictEqual(item.prompt, prompt) && !this.matchedCacheIndices.has(key)) {\n this.matchedCacheIndices.add(key);\n debug('cache found and marked as used, type: %s, prompt: %s, index: %d', type, prompt, i);\n return {\n cacheContent: item,\n updateFn: (cb)=>{\n debug('will call updateFn to update cache, type: %s, prompt: %s, index: %d', type, prompt, i);\n cb(item);\n debug('cache updated, will flush to file, type: %s, prompt: %s, index: %d', type, prompt, i);\n this.flushCacheToFile();\n }\n };\n }\n }\n debug('no unused cache found, type: %s, prompt: %s', type, prompt);\n }\n matchPlanCache(prompt) {\n return this.matchCache(prompt, 'plan');\n }\n matchLocateCache(prompt) {\n return this.matchCache(prompt, 'locate');\n }\n appendCache(cache) {\n debug('will append cache', cache);\n this.cache.caches.push(cache);\n this.flushCacheToFile();\n }\n loadCacheFromFile() {\n const cacheFile = this.cacheFilePath;\n node_assert(cacheFile, 'cache file path is required');\n if (!existsSync(cacheFile)) return void debug('no cache file found, path: %s', cacheFile);\n const jsonTypeCacheFile = cacheFile.replace(cacheFileExt, '.json');\n if (existsSync(jsonTypeCacheFile) && this.isCacheResultUsed) return void console.warn(`An outdated cache file from an earlier version of Midscene has been detected. Since version 0.17, we have implemented an improved caching strategy. Please delete the old file located at: ${jsonTypeCacheFile}.`);\n try {\n const data = readFileSync(cacheFile, 'utf8');\n const jsonData = js_yaml.load(data);\n const version = getMidsceneVersion();\n if (!version) return void debug('no midscene version info, will not read cache from file');\n if (semver.lt(jsonData.midsceneVersion, lowestSupportedMidsceneVersion) && !jsonData.midsceneVersion.includes('beta')) return void console.warn(`You are using an old version of Midscene cache file, and we cannot match any info from it. Starting from Midscene v0.17, we changed our strategy to use xpath for cache info, providing better performance.\\nPlease delete the existing cache and rebuild it. Sorry for the inconvenience.\\ncache file: ${cacheFile}`);\n debug('cache loaded from file, path: %s, cache version: %s, record length: %s', cacheFile, jsonData.midsceneVersion, jsonData.caches.length);\n jsonData.midsceneVersion = getMidsceneVersion();\n return jsonData;\n } catch (err) {\n debug('cache file exists but load failed, path: %s, error: %s', cacheFile, err);\n return;\n }\n }\n flushCacheToFile() {\n const version = getMidsceneVersion();\n if (!version) return void debug('no midscene version info, will not write cache to file');\n if (!this.cacheFilePath) return void debug('no cache file path, will not write cache to file');\n try {\n const dir = dirname(this.cacheFilePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, {\n recursive: true\n });\n debug('created cache directory: %s', dir);\n }\n const sortedCaches = [\n ...this.cache.caches\n ].sort((a, b)=>{\n if ('plan' === a.type && 'locate' === b.type) return -1;\n if ('locate' === a.type && 'plan' === b.type) return 1;\n return 0;\n });\n const cacheToWrite = {\n ...this.cache,\n caches: sortedCaches\n };\n const yamlData = js_yaml.dump(cacheToWrite);\n writeFileSync(this.cacheFilePath, yamlData);\n debug('cache flushed to file: %s', this.cacheFilePath);\n } catch (err) {\n debug('write cache to file failed, path: %s, error: %s', this.cacheFilePath, err);\n }\n }\n updateOrAppendCacheRecord(newRecord, cachedRecord) {\n if (cachedRecord) if ('plan' === newRecord.type) cachedRecord.updateFn((cache)=>{\n cache.yamlWorkflow = newRecord.yamlWorkflow;\n });\n else cachedRecord.updateFn((cache)=>{\n cache.xpaths = newRecord.xpaths;\n });\n else this.appendCache(newRecord);\n }\n constructor(cacheId, isCacheResultUsed, cacheFilePath){\n _define_property(this, \"cacheId\", void 0);\n _define_property(this, \"cacheFilePath\", void 0);\n _define_property(this, \"cache\", void 0);\n _define_property(this, \"isCacheResultUsed\", void 0);\n _define_property(this, \"cacheOriginalLength\", void 0);\n _define_property(this, \"matchedCacheIndices\", new Set());\n node_assert(cacheId, 'cacheId is required');\n let safeCacheId = replaceIllegalPathCharsAndSpace(cacheId);\n const cacheMaxFilenameLength = getAIConfigInNumber(MIDSCENE_CACHE_MAX_FILENAME_LENGTH) || DEFAULT_CACHE_MAX_FILENAME_LENGTH;\n if (Buffer.byteLength(safeCacheId, 'utf8') > cacheMaxFilenameLength) {\n const prefix = safeCacheId.slice(0, 32);\n const hash = generateHashId(void 0, safeCacheId);\n safeCacheId = `${prefix}-${hash}`;\n }\n this.cacheId = safeCacheId;\n this.cacheFilePath = ifInBrowser || ifInWorker ? void 0 : cacheFilePath || join(getMidsceneRunSubDir('cache'), `${this.cacheId}${cacheFileExt}`);\n this.isCacheResultUsed = isCacheResultUsed;\n let cacheContent;\n if (this.cacheFilePath) cacheContent = this.loadCacheFromFile();\n if (!cacheContent) cacheContent = {\n midsceneVersion: getMidsceneVersion(),\n cacheId: this.cacheId,\n caches: []\n };\n this.cache = cacheContent;\n this.cacheOriginalLength = this.cache.caches.length;\n }\n}\nexport { TaskCache, cacheFileExt, debug };\n\n//# sourceMappingURL=task-cache.mjs.map","import { elementByPositionWithElementInfo } from \"@midscene/core/ai-model\";\nimport { sleep, uploadTestInfoToServer } from \"@midscene/core/utils\";\nimport { MIDSCENE_REPORT_TAG_NAME, getAIConfig } from \"@midscene/shared/env\";\nimport { generateElementByPosition, getNodeFromCacheList, traverseTree } from \"@midscene/shared/extractor\";\nimport { resizeImgBase64 } from \"@midscene/shared/img\";\nimport { getDebug } from \"@midscene/shared/logger\";\nimport { assert, logMsg, uuid } from \"@midscene/shared/utils\";\nimport dayjs from \"dayjs\";\nimport { WebElementInfo } from \"../web-element.mjs\";\nimport { debug as external_task_cache_mjs_debug } from \"./task-cache.mjs\";\nimport { getKeyCommands } from \"./ui-utils.mjs\";\nconst utils_debug = getDebug('tool:profile');\nasync function parseContextFromWebPage(page, _opt) {\n assert(page, 'page is required');\n if (page._forceUsePageContext) return await page._forceUsePageContext();\n utils_debug('Getting page URL');\n const url = await page.url();\n utils_debug('URL end');\n utils_debug('Uploading test info to server');\n uploadTestInfoToServer({\n testUrl: url\n });\n utils_debug('UploadTestInfoToServer end');\n let screenshotBase64;\n let tree;\n utils_debug('Starting parallel operations: screenshot and element tree');\n await Promise.all([\n page.screenshotBase64().then((base64)=>{\n screenshotBase64 = base64;\n utils_debug('ScreenshotBase64 end');\n }),\n page.getElementsNodeTree().then(async (treeRoot)=>{\n tree = treeRoot;\n utils_debug('GetElementsNodeTree end');\n })\n ]);\n utils_debug('ParseContextFromWebPage end');\n utils_debug('Traversing element tree');\n const webTree = traverseTree(tree, (elementInfo)=>{\n const { rect, id, content, attributes, indexId, isVisible } = elementInfo;\n return new WebElementInfo({\n rect,\n id,\n content,\n attributes,\n indexId,\n isVisible\n });\n });\n utils_debug('TraverseTree end');\n assert(screenshotBase64, 'screenshotBase64 is required');\n const size = await page.size();\n utils_debug(`size: ${size.width}x${size.height} dpr: ${size.dpr}`);\n if (size.dpr && size.dpr > 1) {\n utils_debug('Resizing screenshot for high DPR display');\n screenshotBase64 = await resizeImgBase64(screenshotBase64, {\n width: size.width,\n height: size.height\n });\n utils_debug('ResizeImgBase64 end');\n }\n return {\n tree: webTree,\n size,\n screenshotBase64: screenshotBase64,\n url\n };\n}\nfunction getReportFileName(tag = 'web') {\n const reportTagName = getAIConfig(MIDSCENE_REPORT_TAG_NAME);\n const dateTimeInFileName = dayjs().format('YYYY-MM-DD_HH-mm-ss');\n const uniqueId = uuid().substring(0, 8);\n return `${reportTagName || tag}-${dateTimeInFileName}-${uniqueId}`;\n}\nfunction printReportMsg(filepath) {\n logMsg(`Midscene - report file updated: ${filepath}`);\n}\nfunction getCurrentExecutionFile(trace) {\n const error = new Error();\n const stackTrace = trace || error.stack;\n const pkgDir = process.cwd() || '';\n if (stackTrace) {\n const stackLines = stackTrace.split('\\n');\n for (const line of stackLines)if (line.includes('.spec.') || line.includes('.test.') || line.includes('.ts') || line.includes('.js')) {\n const match = line.match(/(?:at\\s+)?(.*?\\.(?:spec|test)\\.[jt]s)/);\n if (null == match ? void 0 : match[1]) {\n const targetFileName = match[1].replace(pkgDir, '').trim().replace('at ', '');\n return targetFileName;\n }\n }\n }\n return false;\n}\nconst testFileIndex = new Map();\nfunction generateCacheId(fileName) {\n let taskFile = fileName || getCurrentExecutionFile();\n if (!taskFile) {\n taskFile = uuid();\n console.warn('Midscene - using random UUID for cache id. Cache may be invalid.');\n }\n if (testFileIndex.has(taskFile)) {\n const currentIndex = testFileIndex.get(taskFile);\n if (void 0 !== currentIndex) testFileIndex.set(taskFile, currentIndex + 1);\n } else testFileIndex.set(taskFile, 1);\n return `${taskFile}-${testFileIndex.get(taskFile)}`;\n}\nconst ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED = 'NOT_IMPLEMENTED_AS_DESIGNED';\nfunction replaceIllegalPathCharsAndSpace(str) {\n return str.replace(/[:*?\"<>| ]/g, '-');\n}\nfunction forceClosePopup(page, debug) {\n page.on('popup', async (popup)=>{\n if (!popup) return void console.warn('got a popup event, but the popup is not ready yet, skip');\n const url = await popup.url();\n console.log(`Popup opened: ${url}`);\n if (popup.isClosed()) debug(`popup is already closed, skip close ${url}`);\n else try {\n await popup.close();\n } catch (error) {\n debug(`failed to close popup ${url}, error: ${error}`);\n }\n if (page.isClosed()) debug(`page is already closed, skip goto ${url}`);\n else try {\n await page.goto(url);\n } catch (error) {\n debug(`failed to goto ${url}, error: ${error}`);\n }\n });\n}\nfunction matchElementFromPlan(planLocateParam, tree) {\n if (!planLocateParam) return;\n if (planLocateParam.id) return getNodeFromCacheList(planLocateParam.id);\n if (planLocateParam.bbox) {\n const centerPosition = {\n x: Math.floor((planLocateParam.bbox[0] + planLocateParam.bbox[2]) / 2),\n y: Math.floor((planLocateParam.bbox[1] + planLocateParam.bbox[3]) / 2)\n };\n let element = elementByPositionWithElementInfo(tree, centerPosition);\n if (!element) element = generateElementByPosition(centerPosition);\n return element;\n }\n}\nasync function matchElementFromCache(taskExecutor, xpaths, cachePrompt, cacheable) {\n try {\n var _taskExecutor_taskCache;\n if ((null == xpaths ? void 0 : xpaths.length) && (null == (_taskExecutor_taskCache = taskExecutor.taskCache) ? void 0 : _taskExecutor_taskCache.isCacheResultUsed) && false !== cacheable) for(let i = 0; i < xpaths.length; i++){\n const element = await taskExecutor.page.getElementInfoByXpath(xpaths[i]);\n if (null == element ? void 0 : element.id) {\n external_task_cache_mjs_debug('cache hit, prompt: %s', cachePrompt);\n external_task_cache_mjs_debug('found a new element with same xpath, xpath: %s, id: %s', xpaths[i], null == element ? void 0 : element.id);\n return element;\n }\n }\n } catch (error) {\n external_task_cache_mjs_debug('get element info by xpath error: ', error);\n }\n}\nfunction trimContextByViewport(execution) {\n function filterVisibleTree(node) {\n if (!node) return null;\n const filteredChildren = Array.isArray(node.children) ? node.children.map(filterVisibleTree).filter((child)=>null !== child) : [];\n if (node.node && true === node.node.isVisible) return {\n ...node,\n children: filteredChildren\n };\n if (filteredChildren.length > 0) return {\n node: null,\n children: filteredChildren\n };\n return null;\n }\n return {\n ...execution,\n tasks: Array.isArray(execution.tasks) ? execution.tasks.map((task)=>{\n var _task_pageContext;\n const newTask = {\n ...task\n };\n if (null == (_task_pageContext = task.pageContext) ? void 0 : _task_pageContext.tree) newTask.pageContext = {\n ...task.pageContext,\n tree: filterVisibleTree(task.pageContext.tree) || {\n node: null,\n children: []\n }\n };\n return newTask;\n }) : execution.tasks\n };\n}\nconst getMidsceneVersion = ()=>\"0.26.4\";\nconst parsePrompt = (prompt)=>{\n if ('string' == typeof prompt) return {\n textPrompt: prompt,\n multimodalPrompt: void 0\n };\n return {\n textPrompt: prompt.prompt,\n multimodalPrompt: prompt.images ? {\n images: prompt.images,\n convertHttpImage2Base64: !!prompt.convertHttpImage2Base64\n } : void 0\n };\n};\nconst commonWebActionsForWebPage = (page)=>[\n {\n name: 'Tap',\n description: 'Tap the element',\n location: 'required',\n call: async (context)=>{\n const { element } = context;\n assert(element, 'Element not found, cannot tap');\n await page.mouse.click(element.center[0], element.center[1], {\n button: 'left'\n });\n }\n },\n {\n name: 'RightClick',\n description: 'Right click the element',\n location: 'required',\n call: async (context)=>{\n const { element } = context;\n assert(element, 'Element not found, cannot right click');\n await page.mouse.click(element.center[0], element.center[1], {\n button: 'right'\n });\n }\n },\n {\n name: 'Hover',\n description: 'Move the mouse to the element',\n location: 'required',\n call: async (context)=>{\n const { element } = context;\n assert(element, 'Element not found, cannot hover');\n await page.mouse.move(element.center[0], element.center[1]);\n }\n },\n {\n name: 'Input',\n description: 'Replace the input field with a new value',\n paramSchema: '{ value: string }',\n paramDescription: '`value` is the final that should be filled in the input box. No matter what modifications are required, just provide the final value to replace the existing input value. Giving a blank string means clear the input field.',\n location: 'required',\n whatToLocate: 'The input field to be filled',\n call: async (context, param)=>{\n const { element } = context;\n if (element) {\n await page.clearInput(element);\n if (!param || !param.value) return;\n }\n await page.keyboard.type(param.value);\n }\n },\n {\n name: 'KeyboardPress',\n description: 'Press a key',\n paramSchema: '{ value: string }',\n paramDescription: 'The key to be pressed',\n location: false,\n call: async (context, param)=>{\n const keys = getKeyCommands(param.value);\n await page.keyboard.press(keys);\n }\n },\n {\n name: 'Scroll',\n description: 'Scroll the page or an element',\n paramSchema: '{ direction: \"down\"(default) | \"up\" | \"right\" | \"left\", scrollType: \"once\" (default) | \"untilBottom\" | \"untilTop\" | \"untilRight\" | \"untilLeft\", distance: number | null }',\n paramDescription: 'The direction to scroll, the scroll type, and the distance to scroll. The distance is the number of pixels to scroll. If not specified, use `down` direction, `once` scroll type, and `null` distance.',\n location: 'optional',\n whatToLocate: 'The element to be scrolled',\n call: async (context, param)=>{\n const { element } = context;\n const startingPoint = element ? {\n left: element.center[0],\n top: element.center[1]\n } : void 0;\n const scrollToEventName = null == param ? void 0 : param.scrollType;\n if ('untilTop' === scrollToEventName) await page.scrollUntilTop(startingPoint);\n else if ('untilBottom' === scrollToEventName) await page.scrollUntilBottom(startingPoint);\n else if ('untilRight' === scrollToEventName) await page.scrollUntilRight(startingPoint);\n else if ('untilLeft' === scrollToEventName) await page.scrollUntilLeft(startingPoint);\n else if ('once' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);\n else {\n if ((null == param ? void 0 : param.direction) !== 'down' && param && param.direction) if ('up' === param.direction) await page.scrollUp(param.distance || void 0, startingPoint);\n else if ('left' === param.direction) await page.scrollLeft(param.distance || void 0, startingPoint);\n else if ('right' === param.direction) await page.scrollRight(param.distance || void 0, startingPoint);\n else throw new Error(`Unknown scroll direction: ${param.direction}`);\n else await page.scrollDown((null == param ? void 0 : param.distance) || void 0, startingPoint);\n await sleep(500);\n }\n }\n }\n ];\nexport { ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED, commonWebActionsForWebPage, forceClosePopup, generateCacheId, getCurrentExecutionFile, getMidsceneVersion, getReportFileName, matchElementFromCache, matchElementFromPlan, parseContextFromWebPage, parsePrompt, printReportMsg, replaceIllegalPathCharsAndSpace, trimContextByViewport };\n\n//# sourceMappingURL=utils.mjs.map","import \"node:child_process\";\nimport \"node:fs\";\nimport \"node:os\";\nimport \"node:path\";\nimport \"@midscene/shared/common\";\nimport { ANTHROPIC_API_KEY, AZURE_OPENAI_API_VERSION, AZURE_OPENAI_DEPLOYMENT, AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_KEY, MIDSCENE_API_TYPE, MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_AZURE_OPENAI_SCOPE, MIDSCENE_DEBUG_AI_PROFILE, MIDSCENE_DEBUG_AI_RESPONSE, MIDSCENE_FORCE_DEEP_THINK, MIDSCENE_LANGSMITH_DEBUG, MIDSCENE_MODEL_NAME, MIDSCENE_OPENAI_HTTP_PROXY, MIDSCENE_OPENAI_INIT_CONFIG_JSON as env_MIDSCENE_OPENAI_INIT_CONFIG_JSON, MIDSCENE_OPENAI_SOCKS_PROXY, MIDSCENE_USE_ANTHROPIC_SDK, MIDSCENE_USE_AZURE_OPENAI, MIDSCENE_USE_QWEN_VL, MIDSCENE_USE_VLM_UI_TARS, OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MAX_TOKENS, OPENAI_USE_AZURE, getAIConfig as env_getAIConfig, getAIConfigInBoolean, getAIConfigInJson as env_getAIConfigInJson, getPreferredLanguage as env_getPreferredLanguage, uiTarsModelVersion as env_uiTarsModelVersion, vlLocateMode as env_vlLocateMode } from \"@midscene/shared/env\";\nimport \"@midscene/shared/node\";\nimport { assert as utils_assert, ifInBrowser as utils_ifInBrowser, uuid as utils_uuid } from \"@midscene/shared/utils\";\nimport { Anthropic } from \"@anthropic-ai/sdk\";\nimport { DefaultAzureCredential, getBearerTokenProvider } from \"@azure/identity\";\nimport { enableDebug, getDebug } from \"@midscene/shared/logger\";\nimport { HttpsProxyAgent } from \"https-proxy-agent\";\nimport { jsonrepair } from \"jsonrepair\";\nimport openai_0, { AzureOpenAI } from \"openai\";\nimport { SocksProxyAgent } from \"socks-proxy-agent\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\nimport node_assert from \"node:assert\";\nimport { NodeType } from \"@midscene/shared/constants\";\nimport { descriptionOfTree, generateElementByPosition, treeToList } from \"@midscene/shared/extractor\";\nimport { compositeElementInfoImg, cropByRect, imageInfoOfBase64, paddingToMatchBlockByBase64, preProcessImageUrl } from \"@midscene/shared/img\";\nimport \"@midscene/shared/us-keyboard-layout\";\nimport \"@ui-tars/action-parser\";\nnew Map();\nfunction getVersion() {\n return \"0.26.4\";\n}\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nclass Executor {\n markTaskAsPending(task) {\n return {\n status: 'pending',\n ...task\n };\n }\n async append(task) {\n var _this_latestErrorTask, _this_latestErrorTask1;\n utils_assert('error' !== this.status, `executor is in error state, cannot append task\\nerror=${null == (_this_latestErrorTask = this.latestErrorTask()) ? void 0 : _this_latestErrorTask.error}\\n${null == (_this_latestErrorTask1 = this.latestErrorTask()) ? void 0 : _this_latestErrorTask1.errorStack}`);\n if (Array.isArray(task)) this.tasks.push(...task.map((item)=>this.markTaskAsPending(item)));\n else this.tasks.push(this.markTaskAsPending(task));\n if ('running' !== this.status) this.status = 'pending';\n }\n async flush() {\n if ('init' === this.status && this.tasks.length > 0) console.warn('illegal state for executor, status is init but tasks are not empty');\n utils_assert('running' !== this.status, 'executor is already running');\n utils_assert('completed' !== this.status, 'executor is already completed');\n utils_assert('error' !== this.status, 'executor is in error state');\n const nextPendingIndex = this.tasks.findIndex((task)=>'pending' === task.status);\n if (nextPendingIndex < 0) return;\n this.status = 'running';\n let taskIndex = nextPendingIndex;\n let successfullyCompleted = true;\n let previousFindOutput;\n while(taskIndex < this.tasks.length){\n const task = this.tasks[taskIndex];\n utils_assert('pending' === task.status, `task status should be pending, but got: ${task.status}`);\n task.timing = {\n start: Date.now()\n };\n try {\n task.status = 'running';\n try {\n if (this.onTaskStart) await this.onTaskStart(task);\n } catch (e) {\n console.error('error in onTaskStart', e);\n }\n utils_assert([\n 'Insight',\n 'Action',\n 'Planning'\n ].indexOf(task.type) >= 0, `unsupported task type: ${task.type}`);\n const { executor, param } = task;\n utils_assert(executor, `executor is required for task type: ${task.type}`);\n let returnValue;\n const executorContext = {\n task,\n element: null == previousFindOutput ? void 0 : previousFindOutput.element\n };\n if ('Insight' === task.type) {\n utils_assert('Locate' === task.subType || 'Query' === task.subType || 'Assert' === task.subType || 'Boolean' === task.subType || 'Number' === task.subType || 'String' === task.subType, `unsupported insight subType: ${task.subType}`);\n returnValue = await task.executor(param, executorContext);\n if ('Locate' === task.subType) previousFindOutput = null == returnValue ? void 0 : returnValue.output;\n } else if ('Action' === task.type || 'Planning' === task.type) returnValue = await task.executor(param, executorContext);\n else {\n console.warn(`unsupported task type: ${task.type}, will try to execute it directly`);\n returnValue = await task.executor(param, executorContext);\n }\n Object.assign(task, returnValue);\n task.status = 'finished';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n taskIndex++;\n } catch (e) {\n successfullyCompleted = false;\n task.error = e;\n task.errorMessage = (null == e ? void 0 : e.message) || ('string' == typeof e ? e : 'error-without-message');\n task.errorStack = e.stack;\n task.status = 'failed';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n break;\n }\n }\n for(let i = taskIndex + 1; i < this.tasks.length; i++)this.tasks[i].status = 'cancelled';\n if (successfullyCompleted) this.status = 'completed';\n else this.status = 'error';\n if (this.tasks.length) {\n const outputIndex = Math.min(taskIndex, this.tasks.length - 1);\n const { thought, output } = this.tasks[outputIndex];\n return {\n thought,\n output\n };\n }\n }\n isInErrorState() {\n return 'error' === this.status;\n }\n latestErrorTask() {\n if ('error' !== this.status) return null;\n const errorTaskIndex = this.tasks.findIndex((task)=>'failed' === task.status);\n if (errorTaskIndex >= 0) return this.tasks[errorTaskIndex];\n return null;\n }\n dump() {\n let modelDescription = '';\n if (env_vlLocateMode()) {\n const uiTarsModelVer = env_uiTarsModelVersion();\n modelDescription = uiTarsModelVer ? `UI-TARS=${uiTarsModelVer}` : `${env_vlLocateMode()} mode`;\n }\n const dumpData = {\n sdkVersion: getVersion(),\n model_name: env_getAIConfig(MIDSCENE_MODEL_NAME) || '',\n model_description: modelDescription,\n logTime: Date.now(),\n name: this.name,\n tasks: this.tasks\n };\n return dumpData;\n }\n constructor(name, options){\n _define_property(this, \"name\", void 0);\n _define_property(this, \"tasks\", void 0);\n _define_property(this, \"status\", void 0);\n _define_property(this, \"onTaskStart\", void 0);\n this.status = (null == options ? void 0 : options.tasks) && options.tasks.length > 0 ? 'pending' : 'init';\n this.name = name;\n this.tasks = ((null == options ? void 0 : options.tasks) || []).map((item)=>this.markTaskAsPending(item));\n this.onTaskStart = null == options ? void 0 : options.onTaskStart;\n }\n}\nvar types_AIResponseFormat = /*#__PURE__*/ function(AIResponseFormat) {\n AIResponseFormat[\"JSON\"] = \"json_object\";\n AIResponseFormat[\"TEXT\"] = \"text\";\n return AIResponseFormat;\n}({});\nconst defaultAssertionPrompt = 'You are a senior testing engineer. User will give an assertion and a screenshot of a page. By carefully viewing the screenshot, please tell whether the assertion is truthy.';\nconst defaultAssertionResponseJsonFormat = `Return in the following JSON format:\n{\n pass: boolean, // whether the assertion is truthy\n thought: string | null, // string, if the result is falsy, give the reason why it is falsy. Otherwise, put null.\n}`;\nconst getUiTarsAssertionResponseJsonFormat = ()=>`## Output Json String Format\n\\`\\`\\`\n\"{\n \"pass\": <<is a boolean value from the enum [true, false], true means the assertion is truthy>>, \n \"thought\": \"<<is a string, give the reason why the assertion is falsy or truthy. Otherwise.>>\"\n}\"\n\\`\\`\\`\n\n## Rules **MUST** follow\n- Make sure to return **only** the JSON, with **no additional** text or explanations.\n- Use ${env_getPreferredLanguage()} in \\`thought\\` part.\n- You **MUST** strictly follow up the **Output Json String Format**.`;\nfunction systemPromptToAssert(model) {\n return `${defaultAssertionPrompt}\n\n${model.isUITars ? getUiTarsAssertionResponseJsonFormat() : defaultAssertionResponseJsonFormat}`;\n}\nconst assertSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'assert',\n strict: true,\n schema: {\n type: 'object',\n properties: {\n pass: {\n type: 'boolean',\n description: 'Whether the assertion passed or failed'\n },\n thought: {\n type: [\n 'string',\n 'null'\n ],\n description: 'The thought process behind the assertion'\n }\n },\n required: [\n 'pass',\n 'thought'\n ],\n additionalProperties: false\n }\n }\n};\nfunction bboxDescription(vlMode) {\n if ('gemini' === vlMode) return '2d bounding box as [ymin, xmin, ymax, xmax]';\n return '2d bounding box as [xmin, ymin, xmax, ymax]';\n}\nfunction systemPromptToLocateElement(vlMode) {\n if (vlMode) {\n const bboxComment = bboxDescription(vlMode);\n return `\n## Role:\nYou are an expert in software testing.\n\n## Objective:\n- Identify elements in screenshots and text that match the user's description.\n- Give the coordinates of the element that matches the user's description best in the screenshot.\n- Determine whether the user's description is order-sensitive (e.g., contains phrases like 'the third item in the list', 'the last button', etc.).\n\n## Output Format:\n\\`\\`\\`json\n{\n \"bbox\": [number, number, number, number], // ${bboxComment}\n \"errors\"?: string[],\n \"isOrderSensitive\": boolean // Whether the targetElementDescription is order-sensitive (true/false)\n}\n\\`\\`\\`\n\nFields:\n* \\`bbox\\` is the bounding box of the element that matches the user's description best in the screenshot\n* \\`isOrderSensitive\\` is a boolean indicating whether the user's description is order-sensitive (true/false)\n* \\`errors\\` is an optional array of error messages (if any)\n\nOrder-sensitive means the description contains phrases like:\n- \"the third item in the list\"\n- \"the last button\"\n- \"the first input box\"\n- \"the second row\"\n\nNot order-sensitive means the description is like:\n- \"confirm button\"\n- \"search box\"\n- \"password input\"\n\nFor example, when an element is found and the description is order-sensitive:\n\\`\\`\\`json\n{\n \"bbox\": [100, 100, 200, 200],\n \"isOrderSensitive\": true,\n \"errors\": []\n}\n\\`\\`\\`\n\nWhen no element is found and the description is not order-sensitive:\n\\`\\`\\`json\n{\n \"bbox\": [],\n \"isOrderSensitive\": false,\n \"errors\": [\"I can see ..., but {some element} is not found\"]\n}\n\\`\\`\\`\n`;\n }\n return `\n## Role:\nYou are an expert in software page image (2D) and page element text analysis.\n\n## Objective:\n- Identify elements in screenshots and text that match the user's description.\n- Return JSON data containing the selection reason and element ID.\n- Determine whether the user's description is order-sensitive (e.g., contains phrases like 'the third item in the list', 'the last button', etc.).\n\n## Skills:\n- Image analysis and recognition\n- Multilingual text understanding\n- Software UI design and testing\n\n## Workflow:\n1. Receive the user's element description, screenshot, and element description information. Note that the text may contain non-English characters (e.g., Chinese), indicating that the application may be non-English.\n2. Based on the user's description, locate the target element ID in the list of element descriptions and the screenshot.\n3. Found the required number of elements\n4. Return JSON data containing the selection reason and element ID.\n5. Judge whether the user's description is order-sensitive (see below for definition and examples).\n\n## Constraints:\n- Strictly adhere to the specified location when describing the required element; do not select elements from other locations.\n- Elements in the image with NodeType other than \"TEXT Node\" have been highlighted to identify the element among multiple non-text elements.\n- Accurately identify element information based on the user's description and return the corresponding element ID from the element description information, not extracted from the image.\n- If no elements are found, the \"elements\" array should be empty.\n- The returned data must conform to the specified JSON format.\n- The returned value id information must use the id from element info (important: **use id not indexId, id is hash content**)\n\n## Order-Sensitive Definition:\n- If the description contains phrases like \"the third item in the list\", \"the last button\", \"the first input box\", \"the second row\", etc., it is order-sensitive (isOrderSensitive = true).\n- If the description is like \"confirm button\", \"search box\", \"password input\", etc., it is not order-sensitive (isOrderSensitive = false).\n\n## Output Format:\n\nPlease return the result in JSON format as follows:\n\n\\`\\`\\`json\n{\n \"elements\": [\n // If no matching elements are found, return an empty array []\n {\n \"reason\": \"PLACEHOLDER\", // The thought process for finding the element, replace PLACEHOLDER with your thought process\n \"text\": \"PLACEHOLDER\", // Replace PLACEHOLDER with the text of elementInfo, if none, leave empty\n \"id\": \"PLACEHOLDER\" // Replace PLACEHOLDER with the ID (important: **use id not indexId, id is hash content**) of elementInfo\n }\n // More elements...\n ],\n \"isOrderSensitive\": true, // or false, depending on the user's description\n \"errors\": [] // Array of strings containing any error messages\n}\n\\`\\`\\`\n\n## Example:\nExample 1:\nInput Example:\n\\`\\`\\`json\n// Description: \"Shopping cart icon in the upper right corner\"\n{\n \"description\": \"PLACEHOLDER\", // Description of the target element\n \"screenshot\": \"path/screenshot.png\",\n \"text\": '{\n \"pageSize\": {\n \"width\": 400, // Width of the page\n \"height\": 905 // Height of the page\n },\n \"elementInfos\": [\n {\n \"id\": \"1231\", // ID of the element\n \"indexId\": \"0\", // Index of the element\\u{FF0C}The image is labeled to the left of the element\n \"attributes\": { // Attributes of the element\n \"nodeType\": \"IMG Node\", // Type of element, types include: TEXT Node, IMG Node, BUTTON Node, INPUT Node\n \"src\": \"https://ap-southeast-3.m\",\n \"class\": \".img\"\n },\n \"content\": \"\", // Text content of the element\n \"rect\": {\n \"left\": 280, // Distance from the left side of the page\n \"top\": 8, // Distance from the top of the page\n \"width\": 44, // Width of the element\n \"height\": 44 // Height of the element\n }\n },\n {\n \"id\": \"66551\", // ID of the element\n \"indexId\": \"1\", // Index of the element,The image is labeled to the left of the element\n \"attributes\": { // Attributes of the element\n \"nodeType\": \"IMG Node\", // Type of element, types include: TEXT Node, IMG Node, BUTTON Node, INPUT Node\n \"src\": \"data:image/png;base64,iVBORw0KGgoAAAANSU...\",\n \"class\": \".icon\"\n },\n \"content\": \"\", // Text content of the element\n \"rect\": {\n \"left\": 350, // Distance from the left side of the page\n \"top\": 16, // Distance from the top of the page\n \"width\": 25, // Width of the element\n \"height\": 25 // Height of the element\n }\n },\n ...\n {\n \"id\": \"12344\",\n \"indexId\": \"2\", // Index of the element\\u{FF0C}The image is labeled to the left of the element\n \"attributes\": {\n \"nodeType\": \"TEXT Node\",\n \"class\": \".product-name\"\n },\n \"center\": [\n 288,\n 834\n ],\n \"content\": \"Mango Drink\",\n \"rect\": {\n \"left\": 188,\n \"top\": 827,\n \"width\": 199,\n \"height\": 13\n }\n },\n ...\n ]\n }\n '\n}\n\\`\\`\\`\nOutput Example:\n\\`\\`\\`json\n{\n \"elements\": [\n {\n // Describe the reason for finding this element, replace with actual value in practice\n \"reason\": \"Reason for finding element 4: It is located in the upper right corner, is an image type, and according to the screenshot, it is a shopping cart icon button\",\n \"text\": \"\",\n // ID(**use id not indexId**) of this element, replace with actual value in practice, **use id not indexId**\n \"id\": \"1231\"\n }\n ],\n \"isOrderSensitive\": true,\n \"errors\": []\n}\n\\`\\`\\`\n \n `;\n}\nconst locatorSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'find_elements',\n strict: true,\n schema: {\n type: 'object',\n properties: {\n elements: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n reason: {\n type: 'string',\n description: 'Reason for finding this element'\n },\n text: {\n type: 'string',\n description: 'Text content of the element'\n },\n id: {\n type: 'string',\n description: 'ID of this element'\n }\n },\n required: [\n 'reason',\n 'text',\n 'id'\n ],\n additionalProperties: false\n },\n description: 'List of found elements'\n },\n isOrderSensitive: {\n type: 'boolean',\n description: \"Whether the targetElementDescription is order-sensitive (true/false)\"\n },\n errors: {\n type: 'array',\n items: {\n type: 'string'\n },\n description: 'List of error messages, if any'\n }\n },\n required: [\n 'elements',\n 'isOrderSensitive',\n 'errors'\n ],\n additionalProperties: false\n }\n }\n};\nconst findElementPrompt = new PromptTemplate({\n template: `\nHere is the item user want to find:\n=====================================\n{targetElementDescription}\n=====================================\n\n{pageDescription}\n `,\n inputVariables: [\n \"pageDescription\",\n \"targetElementDescription\"\n ]\n});\nconst vlCoTLog = '\"what_the_user_wants_to_do_next_by_instruction\": string, // What the user wants to do according to the instruction and previous logs. ';\nconst vlCurrentLog = '\"log\": string, // Log what the next one action (ONLY ONE!) you can do according to the screenshot and the instruction. The typical log looks like \"Now i want to use action \\'{ action-type }\\' to do .. first\". If no action should be done, log the reason. \". Use the same language as the user\\'s instruction.';\nconst llmCurrentLog = '\"log\": string, // Log what the next actions you can do according to the screenshot and the instruction. The typical log looks like \"Now i want to use action \\'{ action-type }\\' to do ..\". If no action should be done, log the reason. \". Use the same language as the user\\'s instruction.';\nconst commonOutputFields = `\"error\"?: string, // Error messages about unexpected situations, if any. Only think it is an error when the situation is not foreseeable according to the instruction. Use the same language as the user's instruction.\n \"more_actions_needed_by_instruction\": boolean, // Consider if there is still more action(s) to do after the action in \"Log\" is done, according to the instruction. If so, set this field to true. Otherwise, set it to false.`;\nconst vlLocateParam = (required)=>`locate${required ? '' : '?'}: {bbox: [number, number, number, number], prompt: string }`;\nconst llmLocateParam = (required)=>`locate${required ? '' : '?'}: {\"id\": string, \"prompt\": string}`;\nconst descriptionForAction = (action, locatorScheme)=>{\n const tab = ' ';\n let locateParam = '';\n if ('required' === action.location) locateParam = locatorScheme;\n else if ('optional' === action.location) locateParam = `${locatorScheme} | null`;\n else if (false === action.location) locateParam = '';\n const locatorParam = locateParam ? `- ${locateParam}` : '';\n if (action.whatToLocate) if (locateParam) locateParam += ` // ${action.whatToLocate}`;\n else console.warn(`whatToLocate is provided for action ${action.name}, but location is not required or optional. The whatToLocate will be ignored.`);\n let paramSchema = '';\n if (action.paramSchema) paramSchema = `- param: ${action.paramSchema}`;\n if (action.paramDescription) {\n node_assert(paramSchema, `paramSchema is required when paramDescription is provided for action ${action.name}, but got ${action.paramSchema}`);\n paramSchema += ` // ${action.paramDescription}`;\n }\n const fields = [\n paramSchema,\n locatorParam\n ].filter(Boolean);\n return `- ${action.name}, ${action.description}\n${tab}- type: \"${action.name}\"\n${tab}${fields.join(`\\n${tab}`)}\n`.trim();\n};\nconst systemTemplateOfVLPlanning = ({ actionSpace, vlMode })=>{\n const actionNameList = actionSpace.map((action)=>action.name).join(', ');\n const actionDescriptionList = actionSpace.map((action)=>descriptionForAction(action, vlLocateParam('required' === action.location)));\n const actionList = actionDescriptionList.join('\\n');\n return `\nTarget: User will give you a screenshot, an instruction and some previous logs indicating what have been done. Please tell what the next one action is (or null if no action should be done) to do the tasks the instruction requires. \n\nRestriction:\n- Don't give extra actions or plans beyond the instruction. ONLY plan for what the instruction requires. For example, don't try to submit the form if the instruction is only to fill something.\n- Always give ONLY ONE action in \\`log\\` field (or null if no action should be done), instead of multiple actions. Supported actions are ${actionNameList}.\n- Don't repeat actions in the previous logs.\n- Bbox is the bounding box of the element to be located. It's an array of 4 numbers, representing ${bboxDescription(vlMode)}.\n\nSupporting actions:\n${actionList}\n\nField description:\n* The \\`prompt\\` field inside the \\`locate\\` field is a short description that could be used to locate the element.\n\nReturn in JSON format:\n{\n ${vlCoTLog}\n ${vlCurrentLog}\n ${commonOutputFields}\n \"action\": \n {\n // one of the supporting actions\n } | null,\n ,\n \"sleep\"?: number, // The sleep time after the action, in milliseconds.\n}\n\nFor example, when the instruction is \"click 'Confirm' button, and click 'Yes' in popup\" and the log is \"I will use action Tap to click 'Confirm' button\", by viewing the screenshot and previous logs, you should consider: We have already clicked the 'Confirm' button, so next we should find and click 'Yes' in popup.\n\nthis and output the JSON:\n\n{\n \"what_the_user_wants_to_do_next_by_instruction\": \"We have already clicked the 'Confirm' button, so next we should find and click 'Yes' in popup\",\n \"log\": \"I will use action Tap to click 'Yes' in popup\",\n \"more_actions_needed_by_instruction\": false,\n \"action\": {\n \"type\": \"Tap\",\n \"locate\": {\n \"bbox\": [100, 100, 200, 200],\n \"prompt\": \"The 'Yes' button in popup\"\n }\n }\n}\n`;\n};\nconst systemTemplateOfLLM = ({ actionSpace })=>{\n const actionNameList = actionSpace.map((action)=>action.name).join(' / ');\n const actionDescriptionList = actionSpace.map((action)=>descriptionForAction(action, llmLocateParam('required' === action.location)));\n const actionList = actionDescriptionList.join('\\n');\n return `\n## Role\n\nYou are a versatile professional in software UI automation. Your outstanding contributions will impact the user experience of billions of users.\n\n## Objective\n\n- Decompose the instruction user asked into a series of actions\n- Locate the target element if possible\n- If the instruction cannot be accomplished, give a further plan.\n\n## Workflow\n\n1. Receive the screenshot, element description of screenshot(if any), user's instruction and previous logs.\n2. Decompose the user's task into a sequence of feasible actions, and place it in the \\`actions\\` field. There are different types of actions (${actionNameList}). The \"About the action\" section below will give you more details.\n3. Consider whether the user's instruction will be accomplished after the actions you composed.\n- If the instruction is accomplished, set \\`more_actions_needed_by_instruction\\` to false.\n- If more actions are needed, set \\`more_actions_needed_by_instruction\\` to true. Get ready to hand over to the next talent people like you. Carefully log what have been done in the \\`log\\` field, he or she will continue the task according to your logs.\n4. If the task is not feasible on this page, set \\`error\\` field to the reason.\n\n## Constraints\n\n- All the actions you composed MUST be feasible, which means all the action fields can be filled with the page context information you get. If not, don't plan this action.\n- Trust the \"What have been done\" field about the task (if any), don't repeat actions in it.\n- Respond only with valid JSON. Do not write an introduction or summary or markdown prefix like \\`\\`\\`json\\`\\`\\`.\n- If the screenshot and the instruction are totally irrelevant, set reason in the \\`error\\` field.\n\n## About the \\`actions\\` field\n\nThe \\`locate\\` param is commonly used in the \\`param\\` field of the action, means to locate the target element to perform the action, it conforms to the following scheme:\n\ntype LocateParam = {\n \"id\": string, // the id of the element found. It should either be the id marked with a rectangle in the screenshot or the id described in the description.\n \"prompt\"?: string // the description of the element to find. It can only be omitted when locate is null.\n} | null // If it's not on the page, the LocateParam should be null\n\n## Supported actions\n\nEach action has a \\`type\\` and corresponding \\`param\\`. To be detailed:\n${actionList}\n\n`.trim();\n};\nconst outputTemplate = `\n## Output JSON Format:\n\nThe JSON format is as follows:\n\n{\n \"actions\": [\n // ... some actions\n ],\n ${llmCurrentLog}\n ${commonOutputFields}\n}\n\n## Examples\n\n### Example: Decompose a task\n\nWhen you received the following information:\n\n* Instruction: 'Click the language switch button, wait 1s, click \"English\"'\n* Logs: null\n* Page Context (screenshot and description) shows: There is a language switch button, and the \"English\" option is not shown in the screenshot now.\n\nBy viewing the page screenshot and description, you should consider this and output the JSON:\n\n* The user intent is: tap the switch button, sleep, and tap the 'English' option\n* The language switch button is shown in the screenshot, and can be located by the page description or the id marked with a rectangle. So we can plan a Tap action to do this.\n* Plan a Sleep action to wait for 1 second to ensure the language options are displayed.\n* The \"English\" option button is not shown in the screenshot now, it means it may only show after the previous actions are finished. So don't plan any action to do this.\n* Log what these action do: Click the language switch button to open the language options. Wait for 1 second.\n* The task cannot be accomplished (because the last tapping action is not finished yet), so the \\`more_actions_needed_by_instruction\\` field is true. The \\`error\\` field is null.\n\n{\n \"actions\":[\n {\n \"thought\": \"Click the language switch button to open the language options.\",\n \"type\": \"Tap\", \n \"param\": null,\n \"locate\": { id: \"c81c4e9a33\", prompt: \"The language switch button\" }},\n },\n {\n \"thought\": \"Wait for 1 second to ensure the language options are displayed.\",\n \"type\": \"Sleep\",\n \"param\": { \"timeMs\": 1000 },\n }\n ],\n \"error\": null,\n \"more_actions_needed_by_instruction\": true,\n \"log\": \"Click the language switch button to open the language options. Wait for 1 second\",\n}\n\n### Example: What NOT to do\nWrong output:\n{\n \"actions\":[\n {\n \"thought\": \"Click the language switch button to open the language options.\",\n \"type\": \"Tap\",\n \"param\": null,\n \"locate\": {\n { \"id\": \"c81c4e9a33\" }, // WRONG: prompt is missing, this is not a valid LocateParam\n }\n },\n {\n \"thought\": \"Click the English option\",\n \"type\": \"Tap\", \n \"param\": null,\n \"locate\": null, // This means the 'English' option is not shown in the screenshot, the task cannot be accomplished\n }\n ],\n \"more_actions_needed_by_instruction\": false, // WRONG: should be true\n \"log\": \"Click the language switch button to open the language options\",\n}\n`;\nasync function systemPromptToTaskPlanning({ actionSpace, vlMode }) {\n if (vlMode) return systemTemplateOfVLPlanning({\n actionSpace,\n vlMode\n });\n return `${systemTemplateOfLLM({\n actionSpace\n })}\\n\\n${outputTemplate}`;\n}\nconst planSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'action_items',\n strict: false,\n schema: {\n type: 'object',\n strict: false,\n properties: {\n actions: {\n type: 'array',\n items: {\n type: 'object',\n strict: false,\n properties: {\n thought: {\n type: 'string',\n description: 'Reasons for generating this task, and why this task is feasible on this page'\n },\n type: {\n type: 'string',\n description: 'Type of action'\n },\n param: {\n anyOf: [\n {\n type: 'null'\n },\n {\n type: 'object',\n additionalProperties: true\n }\n ],\n description: 'Parameter of the action'\n },\n locate: {\n type: [\n 'object',\n 'null'\n ],\n properties: {\n id: {\n type: 'string'\n },\n prompt: {\n type: 'string'\n }\n },\n required: [\n 'id',\n 'prompt'\n ],\n additionalProperties: false,\n description: 'Location information for the target element'\n }\n },\n required: [\n 'thought',\n 'type',\n 'param',\n 'locate'\n ],\n additionalProperties: false\n },\n description: 'List of actions to be performed'\n },\n more_actions_needed_by_instruction: {\n type: 'boolean',\n description: 'If all the actions described in the instruction have been covered by this action and logs, set this field to false.'\n },\n log: {\n type: 'string',\n description: 'Log what these planned actions do. Do not include further actions that have not been planned.'\n },\n error: {\n type: [\n 'string',\n 'null'\n ],\n description: 'Error messages about unexpected situations'\n }\n },\n required: [\n 'actions',\n 'more_actions_needed_by_instruction',\n 'log',\n 'error'\n ],\n additionalProperties: false\n }\n }\n};\nconst generateTaskBackgroundContext = (userInstruction, log, userActionContext)=>{\n if (log) return `\nHere is the user's instruction:\n\n<instruction>\n <high_priority_knowledge>\n ${userActionContext}\n </high_priority_knowledge>\n\n ${userInstruction}\n</instruction>\n\nThese are the logs from previous executions, which indicate what was done in the previous actions.\nDo NOT repeat these actions.\n<previous_logs>\n${log}\n</previous_logs>\n`;\n return `\nHere is the user's instruction:\n<instruction>\n <high_priority_knowledge>\n ${userActionContext}\n </high_priority_knowledge>\n\n ${userInstruction}\n</instruction>\n`;\n};\nconst automationUserPrompt = (vlMode)=>{\n if (vlMode) return new PromptTemplate({\n template: '{taskBackgroundContext}',\n inputVariables: [\n 'taskBackgroundContext'\n ]\n });\n return new PromptTemplate({\n template: `\npageDescription:\n=====================================\n{pageDescription}\n=====================================\n\n{taskBackgroundContext}`,\n inputVariables: [\n \"pageDescription\",\n 'taskBackgroundContext'\n ]\n });\n};\nfunction checkAIConfig() {\n const openaiKey = env_getAIConfig(OPENAI_API_KEY);\n const azureConfig = env_getAIConfig(MIDSCENE_USE_AZURE_OPENAI);\n const anthropicKey = env_getAIConfig(ANTHROPIC_API_KEY);\n const initConfigJson = env_getAIConfig(env_MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n if (openaiKey) return true;\n if (azureConfig) return true;\n if (anthropicKey) return true;\n return Boolean(initConfigJson);\n}\nlet debugConfigInitialized = false;\nfunction initDebugConfig() {\n if (debugConfigInitialized) return;\n const shouldPrintTiming = getAIConfigInBoolean(MIDSCENE_DEBUG_AI_PROFILE);\n let debugConfig = '';\n if (shouldPrintTiming) {\n console.warn('MIDSCENE_DEBUG_AI_PROFILE is deprecated, use DEBUG=midscene:ai:profile instead');\n debugConfig = 'ai:profile';\n }\n const shouldPrintAIResponse = getAIConfigInBoolean(MIDSCENE_DEBUG_AI_RESPONSE);\n if (shouldPrintAIResponse) {\n console.warn('MIDSCENE_DEBUG_AI_RESPONSE is deprecated, use DEBUG=midscene:ai:response instead');\n debugConfig = debugConfig ? 'ai:*' : 'ai:call';\n }\n if (debugConfig) enableDebug(debugConfig);\n debugConfigInitialized = true;\n}\nconst defaultModel = 'gpt-4o';\nfunction getModelName() {\n let modelName = defaultModel;\n const nameInConfig = env_getAIConfig(MIDSCENE_MODEL_NAME);\n if (nameInConfig) modelName = nameInConfig;\n return modelName;\n}\nasync function createChatClient({ AIActionTypeValue }) {\n initDebugConfig();\n let openai;\n const extraConfig = env_getAIConfigInJson(env_MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n const socksProxy = env_getAIConfig(MIDSCENE_OPENAI_SOCKS_PROXY);\n const httpProxy = env_getAIConfig(MIDSCENE_OPENAI_HTTP_PROXY);\n let proxyAgent;\n const debugProxy = getDebug('ai:call:proxy');\n if (httpProxy) {\n debugProxy('using http proxy', httpProxy);\n proxyAgent = new HttpsProxyAgent(httpProxy);\n } else if (socksProxy) {\n debugProxy('using socks proxy', socksProxy);\n proxyAgent = new SocksProxyAgent(socksProxy);\n }\n if (env_getAIConfig(OPENAI_USE_AZURE)) openai = new AzureOpenAI({\n baseURL: env_getAIConfig(OPENAI_BASE_URL),\n apiKey: env_getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n dangerouslyAllowBrowser: true\n });\n else if (env_getAIConfig(MIDSCENE_USE_AZURE_OPENAI)) {\n const extraAzureConfig = env_getAIConfigInJson(MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON);\n const scope = env_getAIConfig(MIDSCENE_AZURE_OPENAI_SCOPE);\n let tokenProvider;\n if (scope) {\n utils_assert(!utils_ifInBrowser, 'Azure OpenAI is not supported in browser with Midscene.');\n const credential = new DefaultAzureCredential();\n utils_assert(scope, 'MIDSCENE_AZURE_OPENAI_SCOPE is required');\n tokenProvider = getBearerTokenProvider(credential, scope);\n openai = new AzureOpenAI({\n azureADTokenProvider: tokenProvider,\n endpoint: env_getAIConfig(AZURE_OPENAI_ENDPOINT),\n apiVersion: env_getAIConfig(AZURE_OPENAI_API_VERSION),\n deployment: env_getAIConfig(AZURE_OPENAI_DEPLOYMENT),\n ...extraConfig,\n ...extraAzureConfig\n });\n } else openai = new AzureOpenAI({\n apiKey: env_getAIConfig(AZURE_OPENAI_KEY),\n endpoint: env_getAIConfig(AZURE_OPENAI_ENDPOINT),\n apiVersion: env_getAIConfig(AZURE_OPENAI_API_VERSION),\n deployment: env_getAIConfig(AZURE_OPENAI_DEPLOYMENT),\n dangerouslyAllowBrowser: true,\n ...extraConfig,\n ...extraAzureConfig\n });\n } else if (!env_getAIConfig(MIDSCENE_USE_ANTHROPIC_SDK)) {\n const baseURL = env_getAIConfig(OPENAI_BASE_URL);\n if ('string' == typeof baseURL) {\n if (!/^https?:\\/\\//.test(baseURL)) throw new Error(`OPENAI_BASE_URL must be a valid URL starting with http:// or https://, but got: ${baseURL}\\nPlease check your config.`);\n }\n openai = new openai_0({\n baseURL: env_getAIConfig(OPENAI_BASE_URL),\n apiKey: env_getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n defaultHeaders: {\n ...(null == extraConfig ? void 0 : extraConfig.defaultHeaders) || {},\n [MIDSCENE_API_TYPE]: AIActionTypeValue.toString()\n },\n dangerouslyAllowBrowser: true\n });\n }\n if (openai && getAIConfigInBoolean(MIDSCENE_LANGSMITH_DEBUG)) {\n if (utils_ifInBrowser) throw new Error('langsmith is not supported in browser');\n console.log('DEBUGGING MODE: langsmith wrapper enabled');\n const { wrapOpenAI } = await import(\"langsmith/wrappers\");\n openai = wrapOpenAI(openai);\n }\n if (void 0 !== openai) return {\n completion: openai.chat.completions,\n style: 'openai'\n };\n if (env_getAIConfig(MIDSCENE_USE_ANTHROPIC_SDK)) {\n const apiKey = env_getAIConfig(ANTHROPIC_API_KEY);\n utils_assert(apiKey, 'ANTHROPIC_API_KEY is required');\n openai = new Anthropic({\n apiKey,\n httpAgent: proxyAgent,\n dangerouslyAllowBrowser: true\n });\n }\n if (void 0 !== openai && openai.messages) return {\n completion: openai.messages,\n style: 'anthropic'\n };\n throw new Error('Openai SDK or Anthropic SDK is not initialized');\n}\nasync function service_caller_call(messages, AIActionTypeValue, responseFormat, options) {\n utils_assert(checkAIConfig(), 'Cannot find config for AI model service. If you are using a self-hosted model without validating the API key, please set `OPENAI_API_KEY` to any non-null value. https://midscenejs.com/model-provider.html');\n const { completion, style } = await createChatClient({\n AIActionTypeValue\n });\n const maxTokens = env_getAIConfig(OPENAI_MAX_TOKENS);\n const debugCall = getDebug('ai:call');\n const debugProfileStats = getDebug('ai:profile:stats');\n const debugProfileDetail = getDebug('ai:profile:detail');\n const startTime = Date.now();\n const model = getModelName();\n const isStreaming = (null == options ? void 0 : options.stream) && (null == options ? void 0 : options.onChunk);\n let content;\n let accumulated = '';\n let usage;\n let timeCost;\n const commonConfig = {\n temperature: 'vlm-ui-tars' === env_vlLocateMode() ? 0.0 : 0.1,\n stream: !!isStreaming,\n max_tokens: 'number' == typeof maxTokens ? maxTokens : Number.parseInt(maxTokens || '2048', 10),\n ...'qwen-vl' === env_vlLocateMode() ? {\n vl_high_resolution_images: true\n } : {}\n };\n try {\n if ('openai' === style) {\n debugCall(`sending ${isStreaming ? 'streaming ' : ''}request to ${model}`);\n if (isStreaming) {\n const stream = await completion.create({\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig\n }, {\n stream: true\n });\n for await (const chunk of stream){\n var _chunk_choices__delta, _chunk_choices_, _chunk_choices, _chunk_choices__delta1, _chunk_choices_1, _chunk_choices1, _chunk_choices_2, _chunk_choices2;\n const content = (null == (_chunk_choices = chunk.choices) ? void 0 : null == (_chunk_choices_ = _chunk_choices[0]) ? void 0 : null == (_chunk_choices__delta = _chunk_choices_.delta) ? void 0 : _chunk_choices__delta.content) || '';\n const reasoning_content = (null == (_chunk_choices1 = chunk.choices) ? void 0 : null == (_chunk_choices_1 = _chunk_choices1[0]) ? void 0 : null == (_chunk_choices__delta1 = _chunk_choices_1.delta) ? void 0 : _chunk_choices__delta1.reasoning_content) || '';\n if (chunk.usage) usage = chunk.usage;\n if (content || reasoning_content) {\n accumulated += content;\n const chunkData = {\n content,\n reasoning_content,\n accumulated,\n isComplete: false,\n usage: void 0\n };\n options.onChunk(chunkData);\n }\n if (null == (_chunk_choices2 = chunk.choices) ? void 0 : null == (_chunk_choices_2 = _chunk_choices2[0]) ? void 0 : _chunk_choices_2.finish_reason) {\n timeCost = Date.now() - startTime;\n if (!usage) {\n const estimatedTokens = Math.max(1, Math.floor(accumulated.length / 4));\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: 2 * estimatedTokens\n };\n }\n const finalChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: {\n prompt_tokens: usage.prompt_tokens ?? 0,\n completion_tokens: usage.completion_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n time_cost: timeCost ?? 0\n }\n };\n options.onChunk(finalChunk);\n break;\n }\n }\n content = accumulated;\n debugProfileStats(`streaming model, ${model}, mode, ${env_vlLocateMode() || 'default'}, cost-ms, ${timeCost}`);\n } else {\n var _result_usage, _result_usage1, _result_usage2;\n const result = await completion.create({\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig\n });\n timeCost = Date.now() - startTime;\n debugProfileStats(`model, ${model}, mode, ${env_vlLocateMode() || 'default'}, ui-tars-version, ${env_uiTarsModelVersion()}, prompt-tokens, ${(null == (_result_usage = result.usage) ? void 0 : _result_usage.prompt_tokens) || ''}, completion-tokens, ${(null == (_result_usage1 = result.usage) ? void 0 : _result_usage1.completion_tokens) || ''}, total-tokens, ${(null == (_result_usage2 = result.usage) ? void 0 : _result_usage2.total_tokens) || ''}, cost-ms, ${timeCost}, requestId, ${result._request_id || ''}`);\n debugProfileDetail(`model usage detail: ${JSON.stringify(result.usage)}`);\n utils_assert(result.choices, `invalid response from LLM service: ${JSON.stringify(result)}`);\n content = result.choices[0].message.content;\n usage = result.usage;\n }\n debugCall(`response: ${content}`);\n utils_assert(content, 'empty content');\n } else if ('anthropic' === style) {\n const convertImageContent = (content)=>{\n if ('image_url' === content.type) {\n const imgBase64 = content.image_url.url;\n utils_assert(imgBase64, 'image_url is required');\n return {\n source: {\n type: 'base64',\n media_type: imgBase64.includes('data:image/png;base64,') ? 'image/png' : 'image/jpeg',\n data: imgBase64.split(',')[1]\n },\n type: 'image'\n };\n }\n return content;\n };\n if (isStreaming) {\n const stream = await completion.create({\n model,\n system: 'You are a versatile professional in software UI automation',\n messages: messages.map((m)=>({\n role: 'user',\n content: Array.isArray(m.content) ? m.content.map(convertImageContent) : m.content\n })),\n response_format: responseFormat,\n ...commonConfig\n });\n for await (const chunk of stream){\n var _chunk_delta;\n const content = (null == (_chunk_delta = chunk.delta) ? void 0 : _chunk_delta.text) || '';\n if (content) {\n accumulated += content;\n const chunkData = {\n content,\n accumulated,\n reasoning_content: '',\n isComplete: false,\n usage: void 0\n };\n options.onChunk(chunkData);\n }\n if ('message_stop' === chunk.type) {\n timeCost = Date.now() - startTime;\n const anthropicUsage = chunk.usage;\n const finalChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: anthropicUsage ? {\n prompt_tokens: anthropicUsage.input_tokens ?? 0,\n completion_tokens: anthropicUsage.output_tokens ?? 0,\n total_tokens: (anthropicUsage.input_tokens ?? 0) + (anthropicUsage.output_tokens ?? 0),\n time_cost: timeCost ?? 0\n } : void 0\n };\n options.onChunk(finalChunk);\n break;\n }\n }\n content = accumulated;\n } else {\n const result = await completion.create({\n model,\n system: 'You are a versatile professional in software UI automation',\n messages: messages.map((m)=>({\n role: 'user',\n content: Array.isArray(m.content) ? m.content.map(convertImageContent) : m.content\n })),\n response_format: responseFormat,\n ...commonConfig\n });\n timeCost = Date.now() - startTime;\n content = result.content[0].text;\n usage = result.usage;\n }\n utils_assert(content, 'empty content');\n }\n if (isStreaming && !usage) {\n const estimatedTokens = Math.max(1, Math.floor((content || '').length / 4));\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: 2 * estimatedTokens\n };\n }\n return {\n content: content || '',\n usage: usage ? {\n prompt_tokens: usage.prompt_tokens ?? 0,\n completion_tokens: usage.completion_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n time_cost: timeCost ?? 0\n } : void 0,\n isStreamed: !!isStreaming\n };\n } catch (e) {\n console.error(' call AI error', e);\n const newError = new Error(`failed to call ${isStreaming ? 'streaming ' : ''}AI model service: ${e.message}. Trouble shooting: https://midscenejs.com/model-provider.html`, {\n cause: e\n });\n throw newError;\n }\n}\nasync function callToGetJSONObject(messages, AIActionTypeValue) {\n let responseFormat;\n const model = getModelName();\n if (model.includes('gpt-4')) switch(AIActionTypeValue){\n case common_AIActionType.ASSERT:\n responseFormat = assertSchema;\n break;\n case common_AIActionType.INSPECT_ELEMENT:\n responseFormat = locatorSchema;\n break;\n case common_AIActionType.PLAN:\n responseFormat = planSchema;\n break;\n case common_AIActionType.EXTRACT_DATA:\n case common_AIActionType.DESCRIBE_ELEMENT:\n responseFormat = {\n type: types_AIResponseFormat.JSON\n };\n break;\n }\n if ('gpt-4o-2024-05-13' === model) responseFormat = {\n type: types_AIResponseFormat.JSON\n };\n const response = await service_caller_call(messages, AIActionTypeValue, responseFormat);\n utils_assert(response, 'empty response');\n const jsonContent = safeParseJson(response.content);\n return {\n content: jsonContent,\n usage: response.usage\n };\n}\nfunction extractJSONFromCodeBlock(response) {\n try {\n const jsonMatch = response.match(/^\\s*(\\{[\\s\\S]*\\})\\s*$/);\n if (jsonMatch) return jsonMatch[1];\n const codeBlockMatch = response.match(/```(?:json)?\\s*(\\{[\\s\\S]*?\\})\\s*```/);\n if (codeBlockMatch) return codeBlockMatch[1];\n const jsonLikeMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonLikeMatch) return jsonLikeMatch[0];\n } catch {}\n return response;\n}\nfunction preprocessDoubaoBboxJson(input) {\n if (input.includes('bbox')) while(/\\d+\\s+\\d+/.test(input))input = input.replace(/(\\d+)\\s+(\\d+)/g, '$1,$2');\n return input;\n}\nfunction safeParseJson(input) {\n const cleanJsonString = extractJSONFromCodeBlock(input);\n if (null == cleanJsonString ? void 0 : cleanJsonString.match(/\\((\\d+),(\\d+)\\)/)) {\n var _cleanJsonString_match;\n return null == (_cleanJsonString_match = cleanJsonString.match(/\\((\\d+),(\\d+)\\)/)) ? void 0 : _cleanJsonString_match.slice(1).map(Number);\n }\n try {\n return JSON.parse(cleanJsonString);\n } catch {}\n try {\n return JSON.parse(jsonrepair(cleanJsonString));\n } catch (e) {}\n if ('doubao-vision' === env_vlLocateMode() || 'vlm-ui-tars' === env_vlLocateMode()) {\n const jsonString = preprocessDoubaoBboxJson(cleanJsonString);\n return JSON.parse(jsonrepair(jsonString));\n }\n throw Error(`failed to parse json response: ${input}`);\n}\nvar common_AIActionType = /*#__PURE__*/ function(AIActionType) {\n AIActionType[AIActionType[\"ASSERT\"] = 0] = \"ASSERT\";\n AIActionType[AIActionType[\"INSPECT_ELEMENT\"] = 1] = \"INSPECT_ELEMENT\";\n AIActionType[AIActionType[\"EXTRACT_DATA\"] = 2] = \"EXTRACT_DATA\";\n AIActionType[AIActionType[\"PLAN\"] = 3] = \"PLAN\";\n AIActionType[AIActionType[\"DESCRIBE_ELEMENT\"] = 4] = \"DESCRIBE_ELEMENT\";\n return AIActionType;\n}({});\nasync function callAiFn(msgs, AIActionTypeValue) {\n const jsonObject = await callToGetJSONObject(msgs, AIActionTypeValue);\n return {\n content: jsonObject.content,\n usage: jsonObject.usage\n };\n}\nconst defaultBboxSize = 20;\nconst debugInspectUtils = getDebug('ai:common');\nfunction fillBboxParam(locate, width, height) {\n if (locate.bbox_2d && !(null == locate ? void 0 : locate.bbox)) {\n locate.bbox = locate.bbox_2d;\n delete locate.bbox_2d;\n }\n if (null == locate ? void 0 : locate.bbox) locate.bbox = adaptBbox(locate.bbox, width, height);\n return locate;\n}\nfunction adaptQwenBbox(bbox) {\n if (bbox.length < 2) {\n const msg = `invalid bbox data for qwen-vl mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n }\n const result = [\n Math.round(bbox[0]),\n Math.round(bbox[1]),\n 'number' == typeof bbox[2] ? Math.round(bbox[2]) : Math.round(bbox[0] + defaultBboxSize),\n 'number' == typeof bbox[3] ? Math.round(bbox[3]) : Math.round(bbox[1] + defaultBboxSize)\n ];\n return result;\n}\nfunction adaptDoubaoBbox(bbox, width, height) {\n utils_assert(width > 0 && height > 0, 'width and height must be greater than 0 in doubao mode');\n if ('string' == typeof bbox) {\n utils_assert(/^(\\d+)\\s(\\d+)\\s(\\d+)\\s(\\d+)$/.test(bbox.trim()), `invalid bbox data string for doubao-vision mode: ${bbox}`);\n const splitted = bbox.split(' ');\n if (4 === splitted.length) return [\n Math.round(Number(splitted[0]) * width / 1000),\n Math.round(Number(splitted[1]) * height / 1000),\n Math.round(Number(splitted[2]) * width / 1000),\n Math.round(Number(splitted[3]) * height / 1000)\n ];\n throw new Error(`invalid bbox data string for doubao-vision mode: ${bbox}`);\n }\n if (Array.isArray(bbox) && Array.isArray(bbox[0])) bbox = bbox[0];\n let bboxList = [];\n if (Array.isArray(bbox) && 'string' == typeof bbox[0]) bbox.forEach((item)=>{\n if ('string' == typeof item && item.includes(',')) {\n const [x, y] = item.split(',');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else if ('string' == typeof item && item.includes(' ')) {\n const [x, y] = item.split(' ');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else bboxList.push(Number(item));\n });\n else bboxList = bbox;\n if (4 === bboxList.length || 5 === bboxList.length) return [\n Math.round(bboxList[0] * width / 1000),\n Math.round(bboxList[1] * height / 1000),\n Math.round(bboxList[2] * width / 1000),\n Math.round(bboxList[3] * height / 1000)\n ];\n if (6 === bboxList.length || 2 === bboxList.length || 3 === bboxList.length || 7 === bboxList.length) return [\n Math.max(0, Math.round(bboxList[0] * width / 1000) - defaultBboxSize / 2),\n Math.max(0, Math.round(bboxList[1] * height / 1000) - defaultBboxSize / 2),\n Math.min(width, Math.round(bboxList[0] * width / 1000) + defaultBboxSize / 2),\n Math.min(height, Math.round(bboxList[1] * height / 1000) + defaultBboxSize / 2)\n ];\n if (8 === bbox.length) return [\n Math.round(bboxList[0] * width / 1000),\n Math.round(bboxList[1] * height / 1000),\n Math.round(bboxList[4] * width / 1000),\n Math.round(bboxList[5] * height / 1000)\n ];\n const msg = `invalid bbox data for doubao-vision mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n}\nfunction adaptBbox(bbox, width, height) {\n if ('doubao-vision' === env_vlLocateMode() || 'vlm-ui-tars' === env_vlLocateMode()) return adaptDoubaoBbox(bbox, width, height);\n if ('gemini' === env_vlLocateMode()) return adaptGeminiBbox(bbox, width, height);\n return adaptQwenBbox(bbox);\n}\nfunction adaptGeminiBbox(bbox, width, height) {\n const left = Math.round(bbox[1] * width / 1000);\n const top = Math.round(bbox[0] * height / 1000);\n const right = Math.round(bbox[3] * width / 1000);\n const bottom = Math.round(bbox[2] * height / 1000);\n return [\n left,\n top,\n right,\n bottom\n ];\n}\nfunction adaptBboxToRect(bbox, width, height, offsetX = 0, offsetY = 0) {\n debugInspectUtils('adaptBboxToRect', bbox, width, height, offsetX, offsetY);\n const [left, top, right, bottom] = adaptBbox(bbox, width, height);\n const rect = {\n left: left + offsetX,\n top: top + offsetY,\n width: right - left,\n height: bottom - top\n };\n debugInspectUtils('adaptBboxToRect, result=', rect);\n return rect;\n}\nlet warned = false;\nfunction warnGPT4oSizeLimit(size) {\n var _getModelName;\n if (warned) return;\n if (null == (_getModelName = getModelName()) ? void 0 : _getModelName.toLowerCase().includes('gpt-4o')) {\n const warningMsg = `GPT-4o has a maximum image input size of 2000x768 or 768x2000, but got ${size.width}x${size.height}. Please set your page to a smaller resolution. Otherwise, the result may be inaccurate.`;\n if (Math.max(size.width, size.height) > 2000 || Math.min(size.width, size.height) > 768) {\n console.warn(warningMsg);\n warned = true;\n }\n } else if (size.width > 1800 || size.height > 1800) {\n console.warn(`The image size seems too large (${size.width}x${size.height}). It may lead to more token usage, slower response, and inaccurate result.`);\n warned = true;\n }\n}\nfunction mergeRects(rects) {\n const minLeft = Math.min(...rects.map((r)=>r.left));\n const minTop = Math.min(...rects.map((r)=>r.top));\n const maxRight = Math.max(...rects.map((r)=>r.left + r.width));\n const maxBottom = Math.max(...rects.map((r)=>r.top + r.height));\n return {\n left: minLeft,\n top: minTop,\n width: maxRight - minLeft,\n height: maxBottom - minTop\n };\n}\nfunction expandSearchArea(rect, screenSize) {\n const minEdgeSize = 'doubao-vision' === env_vlLocateMode() ? 500 : 300;\n const defaultPadding = 160;\n const paddingSizeHorizontal = rect.width < minEdgeSize ? Math.ceil((minEdgeSize - rect.width) / 2) : defaultPadding;\n const paddingSizeVertical = rect.height < minEdgeSize ? Math.ceil((minEdgeSize - rect.height) / 2) : defaultPadding;\n rect.left = Math.max(0, rect.left - paddingSizeHorizontal);\n rect.width = Math.min(rect.width + 2 * paddingSizeHorizontal, screenSize.width - rect.left);\n rect.top = Math.max(0, rect.top - paddingSizeVertical);\n rect.height = Math.min(rect.height + 2 * paddingSizeVertical, screenSize.height - rect.top);\n return rect;\n}\nasync function markupImageForLLM(screenshotBase64, tree, size) {\n const elementsInfo = treeToList(tree);\n const elementsPositionInfoWithoutText = elementsInfo.filter((elementInfo)=>{\n if (elementInfo.attributes.nodeType === NodeType.TEXT) return false;\n return true;\n });\n const imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n elementsPositionInfo: elementsPositionInfoWithoutText,\n size\n });\n return imagePayload;\n}\nfunction buildYamlFlowFromPlans(plans, sleep) {\n const flow = [];\n for (const plan of plans){\n var _plan_locate;\n const type = plan.type;\n const locate = null == (_plan_locate = plan.locate) ? void 0 : _plan_locate.prompt;\n if ('Tap' === type) flow.push({\n aiTap: locate\n });\n else if ('Hover' === type) flow.push({\n aiHover: locate\n });\n else if ('Input' === type) {\n const param = plan.param;\n flow.push({\n aiInput: param.value,\n locate\n });\n } else if ('KeyboardPress' === type) {\n const param = plan.param;\n flow.push({\n aiKeyboardPress: param.value,\n locate\n });\n } else if ('Scroll' === type) {\n const param = plan.param;\n flow.push({\n aiScroll: null,\n locate,\n direction: param.direction,\n scrollType: param.scrollType,\n distance: param.distance\n });\n } else if ('Sleep' === type) {\n const param = plan.param;\n flow.push({\n sleep: param.timeMs\n });\n } else 'AndroidBackButton' === type || 'AndroidHomeButton' === type || 'AndroidRecentAppsButton' === type || 'AndroidLongPress' === type || 'AndroidPull' === type || 'Error' === type || 'Assert' === type || 'AssertWithoutThrow' === type || 'Finished' === type || console.warn(`Cannot convert action ${type} to yaml flow. This should be a bug of Midscene.`);\n }\n if (sleep) flow.push({\n sleep: sleep\n });\n return flow;\n}\nfunction describeSize(size) {\n return `${size.width} x ${size.height}`;\n}\nconst distanceThreshold = 16;\nfunction elementByPositionWithElementInfo(treeRoot, position, options) {\n const requireStrictDistance = (null == options ? void 0 : options.requireStrictDistance) ?? true;\n const filterPositionElements = (null == options ? void 0 : options.filterPositionElements) ?? false;\n utils_assert(void 0 !== position, 'position is required for query');\n const matchingElements = [];\n function dfs(node) {\n if (null == node ? void 0 : node.node) {\n const item = node.node;\n if (item.rect.left <= position.x && position.x <= item.rect.left + item.rect.width && item.rect.top <= position.y && position.y <= item.rect.top + item.rect.height) {\n var _item_attributes;\n if (!(filterPositionElements && (null == (_item_attributes = item.attributes) ? void 0 : _item_attributes.nodeType) === NodeType.POSITION) && item.isVisible) matchingElements.push(item);\n }\n }\n for (const child of node.children)dfs(child);\n }\n dfs(treeRoot);\n if (0 === matchingElements.length) return;\n const element = matchingElements.reduce((smallest, current)=>{\n const smallestArea = smallest.rect.width * smallest.rect.height;\n const currentArea = current.rect.width * current.rect.height;\n return currentArea < smallestArea ? current : smallest;\n });\n const distanceToCenter = distance({\n x: element.center[0],\n y: element.center[1]\n }, position);\n if (requireStrictDistance) return distanceToCenter <= distanceThreshold ? element : void 0;\n return element;\n}\nfunction distance(point1, point2) {\n return Math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2);\n}\nasync function describeUserPage(context, opt) {\n const { screenshotBase64 } = context;\n let width;\n let height;\n if (context.size) ({ width, height } = context.size);\n else {\n const imgSize = await imageInfoOfBase64(screenshotBase64);\n ({ width, height } = imgSize);\n }\n const treeRoot = context.tree;\n const idElementMap = {};\n const flatElements = treeToList(treeRoot);\n if ((null == opt ? void 0 : opt.domIncluded) === true && flatElements.length >= 5000) console.warn('The number of elements is too large, it may cause the prompt to be too long, please use domIncluded: \"visible-only\" to reduce the number of elements');\n flatElements.forEach((element)=>{\n idElementMap[element.id] = element;\n if (void 0 !== element.indexId) idElementMap[`${element.indexId}`] = element;\n });\n let pageDescription = '';\n const visibleOnly = (null == opt ? void 0 : opt.visibleOnly) ?? (null == opt ? void 0 : opt.domIncluded) === 'visible-only';\n if ((null == opt ? void 0 : opt.domIncluded) || !env_vlLocateMode()) {\n const contentTree = await descriptionOfTree(treeRoot, null == opt ? void 0 : opt.truncateTextLength, null == opt ? void 0 : opt.filterNonTextContent, visibleOnly);\n const sizeDescription = describeSize({\n width,\n height\n });\n pageDescription = `The size of the page: ${sizeDescription} \\n The page elements tree:\\n${contentTree}`;\n }\n return {\n description: pageDescription,\n elementById (idOrIndexId) {\n utils_assert(void 0 !== idOrIndexId, 'id is required for query');\n const item = idElementMap[`${idOrIndexId}`];\n return item;\n },\n elementByPosition (position, size) {\n return elementByPositionWithElementInfo(treeRoot, position);\n },\n insertElementByPosition (position) {\n const element = generateElementByPosition(position);\n treeRoot.children.push({\n node: element,\n children: []\n });\n flatElements.push(element);\n idElementMap[element.id] = element;\n return element;\n },\n size: {\n width,\n height\n }\n };\n}\nfunction systemPromptToExtract() {\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\nThe user will give you a screenshot, the contents of it (optional), and some data requirements in <DATA_DEMAND>. You need to extract the data according to the <DATA_DEMAND>.\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\nIf the user provides multiple reference images, please carefully review the reference images with the screenshot and provide the correct answer for <DATA_DEMAND>.\n\nIf the user requests reasons to be provided, please provide the thought field in response, less then 100 words.\n\nReturn in the following JSON format:\n{\n thought: string, // the thought process of the extraction, less then 100 words, not required by default.\n data: any, // the extracted data. 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.\n errors: [], // string[], error message if any\n}\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{\n data: {\n name: \"John\",\n age: 30,\n isAdmin: true\n },\n}\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{\n data: [\"todo 1\", \"todo 2\", \"todo 3\"],\n}\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{\n data: \"todo list\",\n}\n\n# Example 4\nIf the DATA_DEMAND is:\n\n<DATA_DEMAND>\n{\n \"result\": \"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{\n data: { result: true },\n}\n`;\n}\nconst extractDataQueryPrompt = async (pageDescription, dataQuery)=>{\n let dataQueryText = '';\n dataQueryText = 'string' == typeof dataQuery ? dataQuery : JSON.stringify(dataQuery, null, 2);\n const extractDataPrompt = new PromptTemplate({\n template: `\n<PageDescription>\n{pageDescription}\n</PageDescription>\n\n<DATA_DEMAND>\n{dataQuery}\n</DATA_DEMAND>\n `,\n inputVariables: [\n \"pageDescription\",\n 'dataQuery'\n ]\n });\n return await extractDataPrompt.format({\n pageDescription,\n dataQuery: dataQueryText\n });\n};\nfunction systemPromptToLocateSection(vlMode) {\n return `\nYou goal is to find out one section containing the target element in the screenshot, put it in the \\`bbox\\` field. If the user describe the target element with some reference elements, you should also find the section containing the reference elements, put it in the \\`references_bbox\\` field.\n\nUsually, it should be approximately an area not more than 300x300px. Changes of the size are allowed if there are many elements to cover.\n\nreturn in this JSON format:\n\\`\\`\\`json\n{\n \"bbox\": [number, number, number, number],\n \"references_bbox\"?: [\n [number, number, number, number],\n [number, number, number, number],\n ...\n ],\n \"error\"?: string\n}\n\\`\\`\\`\n\nIn which, all the numbers in the \\`bbox\\` and \\`references_bbox\\` represent ${bboxDescription(vlMode)}.\n\nFor example, if the user describe the target element as \"the delete button on the second row with title 'Peter'\", you should put the bounding box of the delete button in the \\`bbox\\` field, and the bounding box of the second row in the \\`references_bbox\\` field.\n\nthe return value should be like this:\n\\`\\`\\`json\n{\n \"bbox\": [100, 100, 200, 200],\n \"references_bbox\": [[100, 100, 200, 200]]\n}\n\\`\\`\\`\n`;\n}\nconst sectionLocatorInstruction = new PromptTemplate({\n template: `Here is the target element user interested in:\n<targetDescription>\n{sectionDescription}\n</targetDescription>\n `,\n inputVariables: [\n \"sectionDescription\"\n ]\n});\nconst debugInspect = getDebug('ai:inspect');\nconst debugSection = getDebug('ai:section');\nconst extraTextFromUserPrompt = (prompt)=>{\n if ('string' == typeof prompt) return prompt;\n return prompt.prompt;\n};\nconst promptsToChatParam = async (multimodalPrompt)=>{\n var _multimodalPrompt_images;\n const msgs = [];\n if (null == multimodalPrompt ? void 0 : null == (_multimodalPrompt_images = multimodalPrompt.images) ? void 0 : _multimodalPrompt_images.length) {\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: 'Next, I will provide all the reference images.'\n }\n ]\n });\n for (const item of multimodalPrompt.images){\n const base64 = await preProcessImageUrl(item.url, !!multimodalPrompt.convertHttpImage2Base64);\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: `reference image ${item.name}:`\n }\n ]\n });\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: base64,\n detail: 'high'\n }\n }\n ]\n });\n }\n }\n return msgs;\n};\nasync function AiLocateElement(options) {\n const { context, targetElementDescription, callAI } = options;\n const { screenshotBase64 } = context;\n const { description, elementById, insertElementByPosition } = await describeUserPage(context);\n utils_assert(targetElementDescription, \"cannot find the target element description\");\n const userInstructionPrompt = await findElementPrompt.format({\n pageDescription: description,\n targetElementDescription: extraTextFromUserPrompt(targetElementDescription)\n });\n const systemPrompt = systemPromptToLocateElement(env_vlLocateMode());\n let imagePayload = screenshotBase64;\n if (options.searchConfig) {\n utils_assert(options.searchConfig.rect, 'searchArea is provided but its rect cannot be found. Failed to locate element');\n utils_assert(options.searchConfig.imageBase64, 'searchArea is provided but its imageBase64 cannot be found. Failed to locate element');\n imagePayload = options.searchConfig.imageBase64;\n } else if ('qwen-vl' === env_vlLocateMode()) imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n else if (!env_vlLocateMode()) imagePayload = await markupImageForLLM(screenshotBase64, context.tree, context.size);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: userInstructionPrompt\n }\n ]\n }\n ];\n if ('string' != typeof targetElementDescription) {\n const addOns = await promptsToChatParam({\n images: targetElementDescription.images,\n convertHttpImage2Base64: targetElementDescription.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const callAIFn = callAI || callToGetJSONObject;\n const res = await callAIFn(msgs, common_AIActionType.INSPECT_ELEMENT);\n const rawResponse = JSON.stringify(res.content);\n let resRect;\n let matchedElements = 'elements' in res.content ? res.content.elements : [];\n let errors = 'errors' in res.content ? res.content.errors : [];\n try {\n if ('bbox' in res.content && Array.isArray(res.content.bbox)) {\n var _options_searchConfig_rect, _options_searchConfig, _options_searchConfig_rect1, _options_searchConfig1, _options_searchConfig_rect2, _options_searchConfig2, _options_searchConfig_rect3, _options_searchConfig3;\n resRect = adaptBboxToRect(res.content.bbox, (null == (_options_searchConfig = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect = _options_searchConfig.rect) ? void 0 : _options_searchConfig_rect.width) || context.size.width, (null == (_options_searchConfig1 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect1 = _options_searchConfig1.rect) ? void 0 : _options_searchConfig_rect1.height) || context.size.height, null == (_options_searchConfig2 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect2 = _options_searchConfig2.rect) ? void 0 : _options_searchConfig_rect2.left, null == (_options_searchConfig3 = options.searchConfig) ? void 0 : null == (_options_searchConfig_rect3 = _options_searchConfig3.rect) ? void 0 : _options_searchConfig_rect3.top);\n debugInspect('resRect', resRect);\n const rectCenter = {\n x: resRect.left + resRect.width / 2,\n y: resRect.top + resRect.height / 2\n };\n let element = elementByPositionWithElementInfo(context.tree, rectCenter);\n const distanceToCenter = element ? distance({\n x: element.center[0],\n y: element.center[1]\n }, rectCenter) : 0;\n if (!element || distanceToCenter > distanceThreshold) element = insertElementByPosition(rectCenter);\n if (element) {\n matchedElements = [\n element\n ];\n errors = [];\n }\n }\n } catch (e) {\n const msg = e instanceof Error ? `Failed to parse bbox: ${e.message}` : 'unknown error in locate';\n if (errors && (null == errors ? void 0 : errors.length) !== 0) errors.push(`(${msg})`);\n else errors = [\n msg\n ];\n }\n return {\n rect: resRect,\n parseResult: {\n elements: matchedElements,\n errors\n },\n rawResponse,\n elementById,\n usage: res.usage,\n isOrderSensitive: 'object' == typeof res.content && null !== res.content && 'isOrderSensitive' in res.content ? res.content.isOrderSensitive : void 0\n };\n}\nasync function AiLocateSection(options) {\n const { context, sectionDescription } = options;\n const { screenshotBase64 } = context;\n const systemPrompt = systemPromptToLocateSection(env_vlLocateMode());\n const sectionLocatorInstructionText = await sectionLocatorInstruction.format({\n sectionDescription: extraTextFromUserPrompt(sectionDescription)\n });\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: sectionLocatorInstructionText\n }\n ]\n }\n ];\n if ('string' != typeof sectionDescription) {\n const addOns = await promptsToChatParam({\n images: sectionDescription.images,\n convertHttpImage2Base64: sectionDescription.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const result = await callAiFn(msgs, common_AIActionType.EXTRACT_DATA);\n let sectionRect;\n const sectionBbox = result.content.bbox;\n if (sectionBbox) {\n const targetRect = adaptBboxToRect(sectionBbox, context.size.width, context.size.height);\n debugSection('original targetRect %j', targetRect);\n const referenceBboxList = result.content.references_bbox || [];\n debugSection('referenceBboxList %j', referenceBboxList);\n const referenceRects = referenceBboxList.filter((bbox)=>Array.isArray(bbox)).map((bbox)=>adaptBboxToRect(bbox, context.size.width, context.size.height));\n debugSection('referenceRects %j', referenceRects);\n const mergedRect = mergeRects([\n targetRect,\n ...referenceRects\n ]);\n debugSection('mergedRect %j', mergedRect);\n sectionRect = expandSearchArea(mergedRect, context.size);\n debugSection('expanded sectionRect %j', sectionRect);\n }\n let imageBase64 = screenshotBase64;\n if (sectionRect) imageBase64 = await cropByRect(screenshotBase64, sectionRect, getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL));\n return {\n rect: sectionRect,\n imageBase64,\n error: result.content.error,\n rawResponse: JSON.stringify(result.content),\n usage: result.usage\n };\n}\nasync function AiExtractElementInfo(options) {\n var _options_extractOption;\n const { dataQuery, context, extractOption, multimodalPrompt } = options;\n const systemPrompt = systemPromptToExtract();\n const { screenshotBase64 } = context;\n const { description, elementById } = await describeUserPage(context, {\n truncateTextLength: 200,\n filterNonTextContent: false,\n visibleOnly: false,\n domIncluded: null == extractOption ? void 0 : extractOption.domIncluded\n });\n const extractDataPromptText = await extractDataQueryPrompt(description, dataQuery);\n const userContent = [];\n if ((null == extractOption ? void 0 : extractOption.screenshotIncluded) !== false) userContent.push({\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n });\n userContent.push({\n type: 'text',\n text: extractDataPromptText\n });\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: userContent\n }\n ];\n if (null == (_options_extractOption = options.extractOption) ? void 0 : _options_extractOption.returnThought) msgs.push({\n role: 'user',\n content: 'Please provide reasons.'\n });\n if (multimodalPrompt) {\n const addOns = await promptsToChatParam({\n images: multimodalPrompt.images,\n convertHttpImage2Base64: multimodalPrompt.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const result = await callAiFn(msgs, common_AIActionType.EXTRACT_DATA);\n return {\n parseResult: result.content,\n elementById,\n usage: result.usage\n };\n}\nasync function AiAssert(options) {\n const { assertion, context } = options;\n utils_assert(assertion, 'assertion should not be empty');\n const { screenshotBase64 } = context;\n const systemPrompt = systemPromptToAssert({\n isUITars: getAIConfigInBoolean(MIDSCENE_USE_VLM_UI_TARS)\n });\n const assertionText = extraTextFromUserPrompt(assertion);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: `\nHere is the assertion. Please tell whether it is truthy according to the screenshot.\n=====================================\n${assertionText}\n=====================================\n `\n }\n ]\n }\n ];\n if ('string' != typeof assertion) {\n const addOns = await promptsToChatParam({\n images: assertion.images,\n convertHttpImage2Base64: assertion.convertHttpImage2Base64\n });\n msgs.push(...addOns);\n }\n const { content: assertResult, usage } = await callAiFn(msgs, common_AIActionType.ASSERT);\n return {\n content: assertResult,\n usage\n };\n}\nasync function llm_planning_plan(userInstruction, opts) {\n var _planFromAI_action;\n const { callAI, context } = opts || {};\n const { screenshotBase64, size } = context;\n const { description: pageDescription, elementById } = await describeUserPage(context);\n const systemPrompt = await systemPromptToTaskPlanning({\n actionSpace: opts.actionSpace,\n vlMode: env_vlLocateMode()\n });\n const taskBackgroundContextText = generateTaskBackgroundContext(userInstruction, opts.log, opts.actionContext);\n const userInstructionPrompt = await automationUserPrompt(env_vlLocateMode()).format({\n pageDescription,\n taskBackgroundContext: taskBackgroundContextText\n });\n let imagePayload = screenshotBase64;\n if ('qwen-vl' === env_vlLocateMode()) imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n else if (!env_vlLocateMode()) imagePayload = await markupImageForLLM(screenshotBase64, context.tree, context.size);\n warnGPT4oSizeLimit(size);\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n },\n {\n type: 'text',\n text: userInstructionPrompt\n }\n ]\n }\n ];\n const call = callAI || callAiFn;\n const { content, usage } = await call(msgs, common_AIActionType.PLAN);\n const rawResponse = JSON.stringify(content, void 0, 2);\n const planFromAI = content;\n const actions = ((null == (_planFromAI_action = planFromAI.action) ? void 0 : _planFromAI_action.type) ? [\n planFromAI.action\n ] : planFromAI.actions) || [];\n const returnValue = {\n ...planFromAI,\n actions,\n rawResponse,\n usage,\n yamlFlow: buildYamlFlowFromPlans(actions, planFromAI.sleep)\n };\n utils_assert(planFromAI, \"can't get plans from AI\");\n if (env_vlLocateMode()) {\n actions.forEach((action)=>{\n if (action.locate) try {\n action.locate = fillBboxParam(action.locate, size.width, size.height);\n } catch (e) {\n throw new Error(`Failed to fill locate param: ${planFromAI.error} (${e instanceof Error ? e.message : 'unknown error'})`, {\n cause: e\n });\n }\n });\n utils_assert(!planFromAI.error, `Failed to plan actions: ${planFromAI.error}`);\n } else actions.forEach((action)=>{\n var _action_locate;\n if (null == (_action_locate = action.locate) ? void 0 : _action_locate.id) {\n const element = elementById(action.locate.id);\n if (element) action.locate.id = element.id;\n }\n });\n if (0 === actions.length && returnValue.more_actions_needed_by_instruction && !returnValue.sleep) console.warn('No actions planned for the prompt, but model said more actions are needed:', userInstruction);\n return returnValue;\n}\ngetDebug('ui-tars-planning');\nconst elementDescriberInstruction = ()=>`\nDescribe the element in the red rectangle for precise identification. Use ${env_getPreferredLanguage()}.\n\nCRITICAL REQUIREMENTS:\n1. UNIQUENESS: The description must uniquely identify this element on the current page\n2. UNIVERSALITY: Use generic, reusable selectors that work across different contexts\n3. PRECISION: Be specific enough to distinguish from similar elements\n\nDESCRIPTION STRUCTURE:\n1. Element type (button, input, link, div, etc.)\n2. Primary identifier (in order of preference):\n - Unique text content: \"with text 'Login'\"\n - Unique attribute: \"with aria-label 'Search'\"\n - Unique class/ID: \"with class 'primary-button'\"\n - Unique position: \"in header navigation\"\n3. Secondary identifiers (if needed for uniqueness):\n - Visual features: \"blue background\", \"with icon\"\n - Relative position: \"below search bar\", \"in sidebar\"\n - Parent context: \"in login form\", \"in main menu\"\n\nGUIDELINES:\n- Keep description under 25 words\n- Prioritize semantic identifiers over visual ones\n- Use consistent terminology across similar elements\n- Avoid page-specific or temporary content\n- Don't mention the red rectangle or selection box\n- Focus on stable, reusable characteristics\n\nEXAMPLES:\n- \"Login button with text 'Sign In'\"\n- \"Search input with placeholder 'Enter keywords'\"\n- \"Navigation link with text 'Home' in header\"\n- \"Submit button in contact form\"\n- \"Menu icon with aria-label 'Open menu'\"\n\nReturn JSON:\n{\n \"description\": \"unique element identifier\",\n \"error\"?: \"error message if any\"\n}`;\nfunction emitInsightDump(data, dumpSubscriber) {\n const baseData = {\n sdkVersion: getVersion(),\n logTime: Date.now(),\n model_name: env_getAIConfig(MIDSCENE_MODEL_NAME) || ''\n };\n const finalData = {\n logId: utils_uuid(),\n ...baseData,\n ...data\n };\n null == dumpSubscriber || dumpSubscriber(finalData);\n}\nfunction insight_define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst insight_debug = getDebug('ai:insight');\nclass Insight {\n async locate(query, opt) {\n var _parseResult_errors;\n const { callAI } = opt || {};\n const queryPrompt = 'string' == typeof query ? query : query.prompt;\n utils_assert(queryPrompt, 'query is required for locate');\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = void 0;\n utils_assert('object' == typeof query, 'query should be an object for locate');\n const globalDeepThinkSwitch = getAIConfigInBoolean(MIDSCENE_FORCE_DEEP_THINK);\n if (globalDeepThinkSwitch) insight_debug('globalDeepThinkSwitch', globalDeepThinkSwitch);\n let searchAreaPrompt;\n if (query.deepThink || globalDeepThinkSwitch) searchAreaPrompt = query.prompt;\n if (searchAreaPrompt && !env_vlLocateMode()) {\n console.warn('The \"deepThink\" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/choose-a-model');\n searchAreaPrompt = void 0;\n }\n const context = (null == opt ? void 0 : opt.context) || await this.contextRetrieverFn('locate');\n let searchArea;\n let searchAreaRawResponse;\n let searchAreaUsage;\n let searchAreaResponse;\n if (searchAreaPrompt) {\n searchAreaResponse = await AiLocateSection({\n context,\n sectionDescription: searchAreaPrompt\n });\n utils_assert(searchAreaResponse.rect, `cannot find search area for \"${searchAreaPrompt}\"${searchAreaResponse.error ? `: ${searchAreaResponse.error}` : ''}`);\n searchAreaRawResponse = searchAreaResponse.rawResponse;\n searchAreaUsage = searchAreaResponse.usage;\n searchArea = searchAreaResponse.rect;\n }\n const startTime = Date.now();\n const { parseResult, rect, elementById, rawResponse, usage, isOrderSensitive } = await AiLocateElement({\n callAI: callAI || this.aiVendorFn,\n context,\n targetElementDescription: queryPrompt,\n searchConfig: searchAreaResponse\n });\n const timeCost = Date.now() - startTime;\n const taskInfo = {\n ...this.taskInfo ? this.taskInfo : {},\n durationMs: timeCost,\n rawResponse: JSON.stringify(rawResponse),\n formatResponse: JSON.stringify(parseResult),\n usage,\n searchArea,\n searchAreaRawResponse,\n searchAreaUsage\n };\n let errorLog;\n if (null == (_parseResult_errors = parseResult.errors) ? void 0 : _parseResult_errors.length) errorLog = `AI model failed to locate: \\n${parseResult.errors.join('\\n')}`;\n const dumpData = {\n type: 'locate',\n userQuery: {\n element: queryPrompt\n },\n matchedElement: [],\n matchedRect: rect,\n data: null,\n taskInfo,\n deepThink: !!searchArea,\n error: errorLog\n };\n const elements = [];\n (parseResult.elements || []).forEach((item)=>{\n if ('id' in item) {\n const element = elementById(null == item ? void 0 : item.id);\n if (!element) return void console.warn(`locate: cannot find element id=${item.id}. Maybe an unstable response from AI model`);\n elements.push(element);\n }\n });\n emitInsightDump({\n ...dumpData,\n matchedElement: elements\n }, dumpSubscriber);\n if (errorLog) throw new Error(errorLog);\n utils_assert(elements.length <= 1, `locate: multiple elements found, length = ${elements.length}`);\n if (1 === elements.length) return {\n element: {\n id: elements[0].id,\n indexId: elements[0].indexId,\n center: elements[0].center,\n rect: elements[0].rect,\n xpaths: elements[0].xpaths || [],\n attributes: elements[0].attributes,\n isOrderSensitive\n },\n rect\n };\n return {\n element: null,\n rect\n };\n }\n async extract(dataDemand, opt, multimodalPrompt) {\n var _parseResult_errors;\n utils_assert('object' == typeof dataDemand || 'string' == typeof dataDemand, `dataDemand should be object or string, but get ${typeof dataDemand}`);\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = void 0;\n const context = await this.contextRetrieverFn('extract');\n const startTime = Date.now();\n const { parseResult, usage } = await AiExtractElementInfo({\n context,\n dataQuery: dataDemand,\n multimodalPrompt,\n extractOption: opt\n });\n const timeCost = Date.now() - startTime;\n const taskInfo = {\n ...this.taskInfo ? this.taskInfo : {},\n durationMs: timeCost,\n rawResponse: JSON.stringify(parseResult)\n };\n let errorLog;\n if (null == (_parseResult_errors = parseResult.errors) ? void 0 : _parseResult_errors.length) errorLog = `AI response error: \\n${parseResult.errors.join('\\n')}`;\n const dumpData = {\n type: 'extract',\n userQuery: {\n dataDemand\n },\n matchedElement: [],\n data: null,\n taskInfo,\n error: errorLog\n };\n const { data, thought } = parseResult || {};\n emitInsightDump({\n ...dumpData,\n data\n }, dumpSubscriber);\n if (errorLog && !data) throw new Error(errorLog);\n return {\n data,\n thought,\n usage\n };\n }\n async assert(assertion) {\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = void 0;\n const context = await this.contextRetrieverFn('assert');\n const startTime = Date.now();\n const assertResult = await AiAssert({\n assertion,\n context\n });\n const timeCost = Date.now() - startTime;\n const taskInfo = {\n ...this.taskInfo ? this.taskInfo : {},\n durationMs: timeCost,\n rawResponse: JSON.stringify(assertResult.content)\n };\n const { thought, pass } = assertResult.content;\n const dumpData = {\n type: 'assert',\n userQuery: {\n assertion\n },\n matchedElement: [],\n data: null,\n taskInfo,\n assertionPass: pass,\n assertionThought: thought,\n error: pass ? void 0 : thought\n };\n emitInsightDump(dumpData, dumpSubscriber);\n return {\n pass,\n thought,\n usage: assertResult.usage\n };\n }\n async describe(target, opt) {\n utils_assert(target, 'target is required for insight.describe');\n const context = await this.contextRetrieverFn('describe');\n const { screenshotBase64, size } = context;\n utils_assert(screenshotBase64, 'screenshot is required for insight.describe');\n const systemPrompt = elementDescriberInstruction();\n const defaultRectSize = 30;\n const targetRect = Array.isArray(target) ? {\n left: Math.floor(target[0] - defaultRectSize / 2),\n top: Math.floor(target[1] - defaultRectSize / 2),\n width: defaultRectSize,\n height: defaultRectSize\n } : target;\n let imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n size,\n elementsPositionInfo: [\n {\n rect: targetRect\n }\n ],\n borderThickness: 3\n });\n if (null == opt ? void 0 : opt.deepThink) {\n const searchArea = expandSearchArea(targetRect, context.size);\n insight_debug('describe: set searchArea', searchArea);\n imagePayload = await cropByRect(imagePayload, searchArea, getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL));\n }\n const msgs = [\n {\n role: 'system',\n content: systemPrompt\n },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high'\n }\n }\n ]\n }\n ];\n const callAIFn = this.aiVendorFn || callToGetJSONObject;\n const res = await callAIFn(msgs, common_AIActionType.DESCRIBE_ELEMENT);\n const { content } = res;\n utils_assert(!content.error, `describe failed: ${content.error}`);\n utils_assert(content.description, 'failed to describe the element');\n return content;\n }\n constructor(context, opt){\n insight_define_property(this, \"contextRetrieverFn\", void 0);\n insight_define_property(this, \"aiVendorFn\", callAiFn);\n insight_define_property(this, \"onceDumpUpdatedFn\", void 0);\n insight_define_property(this, \"taskInfo\", void 0);\n utils_assert(context, 'context is required for Insight');\n if ('function' == typeof context) this.contextRetrieverFn = context;\n else this.contextRetrieverFn = ()=>Promise.resolve(context);\n if (void 0 !== (null == opt ? void 0 : opt.aiVendorFn)) this.aiVendorFn = opt.aiVendorFn;\n if (void 0 !== (null == opt ? void 0 : opt.taskInfo)) this.taskInfo = opt.taskInfo;\n }\n}\nconst src = Insight;\nexport { AiAssert, AiLocateElement, Executor, Insight, MIDSCENE_MODEL_NAME, src as default, describeUserPage, env_getAIConfig as getAIConfig, getVersion, llm_planning_plan as plan };\n\n//# sourceMappingURL=index.mjs.map","import { Executor, plan as core_plan } from \"@midscene/core\";\nimport { elementByPositionWithElementInfo, resizeImageForUiTars, vlmPlanning } from \"@midscene/core/ai-model\";\nimport { sleep as utils_sleep } from \"@midscene/core/utils\";\nimport { NodeType } from \"@midscene/shared/constants\";\nimport { MIDSCENE_REPLANNING_CYCLE_LIMIT, getAIConfigInNumber } from \"@midscene/shared/env\";\nimport { getDebug } from \"@midscene/shared/logger\";\nimport { assert } from \"@midscene/shared/utils\";\nimport { taskTitleStr } from \"./ui-utils.mjs\";\nimport { matchElementFromCache, matchElementFromPlan, parsePrompt } from \"./utils.mjs\";\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst debug = getDebug('device-task-executor');\nconst defaultReplanningCycleLimit = 10;\nclass PageTaskExecutor {\n async recordScreenshot(timing) {\n const base64 = await this.page.screenshotBase64();\n const item = {\n type: 'screenshot',\n ts: Date.now(),\n screenshot: base64,\n timing\n };\n return item;\n }\n async getElementXpath(pageContext, element) {\n var _element_attributes;\n let elementId = null == element ? void 0 : element.id;\n if ((null == element ? void 0 : element.isOrderSensitive) !== void 0) {\n const xpaths = await this.page.getXpathsByPoint({\n left: element.center[0],\n top: element.center[1]\n }, null == element ? void 0 : element.isOrderSensitive);\n return xpaths;\n }\n if ((null == element ? void 0 : null == (_element_attributes = element.attributes) ? void 0 : _element_attributes.nodeType) === NodeType.POSITION) {\n await this.insight.contextRetrieverFn('locate');\n const info = elementByPositionWithElementInfo(pageContext.tree, {\n x: element.center[0],\n y: element.center[1]\n }, {\n requireStrictDistance: false,\n filterPositionElements: true\n });\n if (null == info ? void 0 : info.id) elementId = info.id;\n else debug('no element id found for position node, will not update cache', element);\n }\n if (!elementId) return;\n try {\n const result = await this.page.getXpathsById(elementId);\n return result;\n } catch (error) {\n debug('getXpathsById error: ', error);\n }\n }\n prependExecutorWithScreenshot(taskApply, appendAfterExecution = false) {\n const taskWithScreenshot = {\n ...taskApply,\n executor: async (param, context, ...args)=>{\n const recorder = [];\n const { task } = context;\n task.recorder = recorder;\n const shot = await this.recordScreenshot(`before ${task.type}`);\n recorder.push(shot);\n const result = await taskApply.executor(param, context, ...args);\n if ('Action' === taskApply.type) await Promise.all([\n (async ()=>{\n await utils_sleep(100);\n if (this.page.waitUntilNetworkIdle) try {\n await this.page.waitUntilNetworkIdle();\n } catch (error) {}\n })(),\n utils_sleep(200)\n ]);\n if (appendAfterExecution) {\n const shot2 = await this.recordScreenshot('after Action');\n recorder.push(shot2);\n }\n return result;\n }\n };\n return taskWithScreenshot;\n }\n async convertPlanToExecutable(plans, opts) {\n const tasks = [];\n for (const plan of plans)if ('Locate' === plan.type) {\n var _plan_locate, _plan_locate1;\n if (null === plan.locate || (null == (_plan_locate = plan.locate) ? void 0 : _plan_locate.id) === null || (null == (_plan_locate1 = plan.locate) ? void 0 : _plan_locate1.id) === 'null') continue;\n const taskFind = {\n type: 'Insight',\n subType: 'Locate',\n param: plan.locate ? {\n ...plan.locate,\n cacheable: null == opts ? void 0 : opts.cacheable\n } : void 0,\n thought: plan.thought,\n locate: plan.locate,\n executor: async (param, taskContext)=>{\n var _this_taskCache, _locateCacheRecord_cacheContent;\n const { task } = taskContext;\n assert((null == param ? void 0 : param.prompt) || (null == param ? void 0 : param.id) || (null == param ? void 0 : param.bbox), 'No prompt or id or position or bbox to locate');\n let insightDump;\n let usage;\n const dumpCollector = (dump)=>{\n var _dump_taskInfo;\n insightDump = dump;\n usage = null == dump ? void 0 : null == (_dump_taskInfo = dump.taskInfo) ? void 0 : _dump_taskInfo.usage;\n task.log = {\n dump: insightDump\n };\n task.usage = usage;\n };\n this.insight.onceDumpUpdatedFn = dumpCollector;\n const shotTime = Date.now();\n const pageContext = await this.insight.contextRetrieverFn('locate');\n task.pageContext = pageContext;\n const recordItem = {\n type: 'screenshot',\n ts: shotTime,\n screenshot: pageContext.screenshotBase64,\n timing: 'before Insight'\n };\n task.recorder = [\n recordItem\n ];\n const elementFromXpath = param.xpath ? await this.page.getElementInfoByXpath(param.xpath) : void 0;\n const userExpectedPathHitFlag = !!elementFromXpath;\n const cachePrompt = param.prompt;\n const locateCacheRecord = null == (_this_taskCache = this.taskCache) ? void 0 : _this_taskCache.matchLocateCache(cachePrompt);\n const xpaths = null == locateCacheRecord ? void 0 : null == (_locateCacheRecord_cacheContent = locateCacheRecord.cacheContent) ? void 0 : _locateCacheRecord_cacheContent.xpaths;\n const elementFromCache = userExpectedPathHitFlag ? null : await matchElementFromCache(this, xpaths, cachePrompt, param.cacheable);\n const cacheHitFlag = !!elementFromCache;\n const elementFromPlan = userExpectedPathHitFlag || cacheHitFlag ? void 0 : matchElementFromPlan(param, pageContext.tree);\n const planHitFlag = !!elementFromPlan;\n const elementFromAiLocate = userExpectedPathHitFlag || cacheHitFlag || planHitFlag ? void 0 : (await this.insight.locate(param, {\n context: pageContext\n })).element;\n const aiLocateHitFlag = !!elementFromAiLocate;\n const element = elementFromXpath || elementFromCache || elementFromPlan || elementFromAiLocate;\n let currentXpaths;\n if (element && this.taskCache && !cacheHitFlag && (null == param ? void 0 : param.cacheable) !== false) {\n const elementXpaths = await this.getElementXpath(pageContext, element);\n if (null == elementXpaths ? void 0 : elementXpaths.length) {\n currentXpaths = elementXpaths;\n this.taskCache.updateOrAppendCacheRecord({\n type: 'locate',\n prompt: cachePrompt,\n xpaths: elementXpaths\n }, locateCacheRecord);\n } else debug('no xpaths found, will not update cache', cachePrompt, elementXpaths);\n }\n if (!element) throw new Error(`Element not found: ${param.prompt}`);\n let hitBy;\n if (userExpectedPathHitFlag) hitBy = {\n from: 'User expected path',\n context: {\n xpath: param.xpath\n }\n };\n else if (cacheHitFlag) hitBy = {\n from: 'Cache',\n context: {\n xpathsFromCache: xpaths,\n xpathsToSave: currentXpaths\n }\n };\n else if (planHitFlag) hitBy = {\n from: 'Planning',\n context: {\n id: null == elementFromPlan ? void 0 : elementFromPlan.id,\n bbox: null == elementFromPlan ? void 0 : elementFromPlan.bbox\n }\n };\n else if (aiLocateHitFlag) hitBy = {\n from: 'AI model',\n context: {\n prompt: param.prompt\n }\n };\n return {\n output: {\n element\n },\n pageContext,\n hitBy\n };\n }\n };\n tasks.push(taskFind);\n } else if ('Assert' === plan.type || 'AssertWithoutThrow' === plan.type) {\n const assertPlan = plan;\n const taskAssert = {\n type: 'Insight',\n subType: 'Assert',\n param: assertPlan.param,\n thought: assertPlan.thought,\n locate: assertPlan.locate,\n executor: async (param, taskContext)=>{\n const { task } = taskContext;\n let insightDump;\n const dumpCollector = (dump)=>{\n insightDump = dump;\n };\n this.insight.onceDumpUpdatedFn = dumpCollector;\n const shotTime = Date.now();\n const pageContext = await this.insight.contextRetrieverFn('assert');\n task.pageContext = pageContext;\n const recordItem = {\n type: 'screenshot',\n ts: shotTime,\n screenshot: pageContext.screenshotBase64,\n timing: 'before Insight'\n };\n task.recorder = [\n recordItem\n ];\n const assertion = await this.insight.assert(assertPlan.param.assertion);\n if (!assertion.pass) {\n if ('Assert' === plan.type) {\n task.output = assertion;\n task.log = {\n dump: insightDump\n };\n throw new Error(assertion.thought || 'Assertion failed without reason');\n }\n task.error = new Error(assertion.thought);\n }\n return {\n output: assertion,\n pageContext,\n log: {\n dump: insightDump\n },\n usage: assertion.usage\n };\n }\n };\n tasks.push(taskAssert);\n } else if ('Error' === plan.type) {\n var _plan_param;\n const taskActionError = {\n type: 'Action',\n subType: 'Error',\n param: plan.param,\n thought: plan.thought || (null == (_plan_param = plan.param) ? void 0 : _plan_param.thought),\n locate: plan.locate,\n executor: async ()=>{\n var _plan_param;\n throw new Error((null == plan ? void 0 : plan.thought) || (null == (_plan_param = plan.param) ? void 0 : _plan_param.thought) || 'error without thought');\n }\n };\n tasks.push(taskActionError);\n } else if ('Finished' === plan.type) {\n const taskActionFinished = {\n type: 'Action',\n subType: 'Finished',\n param: null,\n thought: plan.thought,\n locate: plan.locate,\n executor: async (param)=>{}\n };\n tasks.push(taskActionFinished);\n } else if ('Sleep' === plan.type) {\n const taskActionSleep = {\n type: 'Action',\n subType: 'Sleep',\n param: plan.param,\n thought: plan.thought,\n locate: plan.locate,\n executor: async (taskParam)=>{\n await utils_sleep((null == taskParam ? void 0 : taskParam.timeMs) || 3000);\n }\n };\n tasks.push(taskActionSleep);\n } else if ('Drag' === plan.type) {\n const taskActionDrag = {\n type: 'Action',\n subType: 'Drag',\n param: plan.param,\n thought: plan.thought,\n locate: plan.locate,\n executor: async (taskParam)=>{\n assert((null == taskParam ? void 0 : taskParam.start_box) && (null == taskParam ? void 0 : taskParam.end_box), 'No start_box or end_box to drag');\n await this.page.mouse.drag(taskParam.start_box, taskParam.end_box);\n }\n };\n tasks.push(taskActionDrag);\n } else {\n const planType = plan.type;\n const task = {\n type: 'Action',\n subType: planType,\n thought: plan.thought,\n param: plan.param,\n executor: async (param, context)=>{\n var _context_element;\n debug('executing action', planType, param, `context.element.center: ${null == (_context_element = context.element) ? void 0 : _context_element.center}`);\n const actionSpace = await this.page.actionSpace();\n const action = actionSpace.find((action)=>action.name === planType);\n if (!action) throw new Error(`Action type '${planType}' not found`);\n const actionFn = action.call.bind(this.page);\n return await actionFn(context, param);\n }\n };\n tasks.push(task);\n }\n const wrappedTasks = tasks.map((task, index)=>{\n if ('Action' === task.type) return this.prependExecutorWithScreenshot(task, index === tasks.length - 1);\n return task;\n });\n return {\n tasks: wrappedTasks\n };\n }\n async setupPlanningContext(executorContext) {\n const shotTime = Date.now();\n const pageContext = await this.insight.contextRetrieverFn('locate');\n const recordItem = {\n type: 'screenshot',\n ts: shotTime,\n screenshot: pageContext.screenshotBase64,\n timing: 'before Planning'\n };\n executorContext.task.recorder = [\n recordItem\n ];\n executorContext.task.pageContext = pageContext;\n return {\n pageContext\n };\n }\n async loadYamlFlowAsPlanning(userInstruction, yamlString) {\n const taskExecutor = new Executor(taskTitleStr('Action', userInstruction), {\n onTaskStart: this.onTaskStartCallback\n });\n const task = {\n type: 'Planning',\n subType: 'LoadYaml',\n locate: null,\n param: {\n userInstruction\n },\n executor: async (param, executorContext)=>{\n await this.setupPlanningContext(executorContext);\n return {\n output: {\n actions: [],\n more_actions_needed_by_instruction: false,\n log: '',\n yamlString\n },\n cache: {\n hit: true\n }\n };\n }\n };\n await taskExecutor.append(task);\n await taskExecutor.flush();\n return {\n executor: taskExecutor\n };\n }\n planningTaskFromPrompt(userInstruction, log, actionContext) {\n const task = {\n type: 'Planning',\n subType: 'Plan',\n locate: null,\n param: {\n userInstruction,\n log\n },\n executor: async (param, executorContext)=>{\n const startTime = Date.now();\n const { pageContext } = await this.setupPlanningContext(executorContext);\n assert(this.page.actionSpace, 'actionSpace for device is not implemented');\n const actionSpace = await this.page.actionSpace();\n debug('actionSpace for page is:', actionSpace.map((action)=>action.name).join(', '));\n assert(Array.isArray(actionSpace), 'actionSpace must be an array');\n if (0 === actionSpace.length) console.warn(`ActionSpace for ${this.page.pageType} is empty. This may lead to unexpected behavior.`);\n const planResult = await core_plan(param.userInstruction, {\n context: pageContext,\n log: param.log,\n actionContext,\n pageType: this.page.pageType,\n actionSpace\n });\n const { actions, log, more_actions_needed_by_instruction, error, usage, rawResponse, sleep } = planResult;\n executorContext.task.log = {\n ...executorContext.task.log || {},\n rawResponse\n };\n executorContext.task.usage = usage;\n let stopCollecting = false;\n let bboxCollected = false;\n let planParsingError = '';\n const finalActions = (actions || []).reduce((acc, planningAction)=>{\n if (stopCollecting) return acc;\n if (planningAction.locate) {\n if (bboxCollected && planningAction.locate.bbox) delete planningAction.locate.bbox;\n if (planningAction.locate.bbox) bboxCollected = true;\n acc.push({\n type: 'Locate',\n locate: planningAction.locate,\n param: null,\n thought: planningAction.locate.prompt\n });\n } else if ([\n 'Tap',\n 'Hover',\n 'Input'\n ].includes(planningAction.type)) {\n planParsingError = `invalid planning response: ${JSON.stringify(planningAction)}`;\n stopCollecting = true;\n return acc;\n }\n acc.push(planningAction);\n return acc;\n }, []);\n if (sleep) {\n const timeNow = Date.now();\n const timeRemaining = sleep - (timeNow - startTime);\n if (timeRemaining > 0) finalActions.push({\n type: 'Sleep',\n param: {\n timeMs: timeRemaining\n },\n locate: null\n });\n }\n if (0 === finalActions.length) assert(!more_actions_needed_by_instruction || sleep, error ? `Failed to plan: ${error}` : planParsingError || 'No plan found');\n return {\n output: {\n actions: finalActions,\n more_actions_needed_by_instruction,\n log,\n yamlFlow: planResult.yamlFlow\n },\n cache: {\n hit: false\n },\n pageContext\n };\n }\n };\n return task;\n }\n planningTaskToGoal(userInstruction) {\n const task = {\n type: 'Planning',\n subType: 'Plan',\n locate: null,\n param: {\n userInstruction\n },\n executor: async (param, executorContext)=>{\n var _actions_;\n const { pageContext } = await this.setupPlanningContext(executorContext);\n const imagePayload = await resizeImageForUiTars(pageContext.screenshotBase64, pageContext.size);\n this.appendConversationHistory({\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload\n }\n }\n ]\n });\n const planResult = await vlmPlanning({\n userInstruction: param.userInstruction,\n conversationHistory: this.conversationHistory,\n size: pageContext.size\n });\n const { actions, action_summary, usage } = planResult;\n executorContext.task.log = {\n ...executorContext.task.log || {},\n rawResponse: planResult.rawResponse\n };\n executorContext.task.usage = usage;\n this.appendConversationHistory({\n role: 'assistant',\n content: action_summary\n });\n return {\n output: {\n actions,\n thought: null == (_actions_ = actions[0]) ? void 0 : _actions_.thought,\n actionType: actions[0].type,\n more_actions_needed_by_instruction: true,\n log: '',\n yamlFlow: planResult.yamlFlow\n },\n cache: {\n hit: false\n }\n };\n }\n };\n return task;\n }\n async runPlans(title, plans, opts) {\n const taskExecutor = new Executor(title, {\n onTaskStart: this.onTaskStartCallback\n });\n const { tasks } = await this.convertPlanToExecutable(plans, opts);\n await taskExecutor.append(tasks);\n const result = await taskExecutor.flush();\n const { output } = result;\n return {\n output,\n executor: taskExecutor\n };\n }\n async action(userPrompt, actionContext, opts) {\n const taskExecutor = new Executor(taskTitleStr('Action', userPrompt), {\n onTaskStart: this.onTaskStartCallback\n });\n let planningTask = this.planningTaskFromPrompt(userPrompt, void 0, actionContext);\n let replanCount = 0;\n const logList = [];\n const yamlFlow = [];\n const replanningCycleLimit = getAIConfigInNumber(MIDSCENE_REPLANNING_CYCLE_LIMIT) || defaultReplanningCycleLimit;\n while(planningTask){\n if (replanCount > replanningCycleLimit) {\n const errorMsg = 'Replanning too many times, please split the task into multiple steps';\n return this.appendErrorPlan(taskExecutor, errorMsg);\n }\n await taskExecutor.append(planningTask);\n const result = await taskExecutor.flush();\n const planResult = null == result ? void 0 : result.output;\n if (taskExecutor.isInErrorState()) return {\n output: planResult,\n executor: taskExecutor\n };\n const plans = planResult.actions || [];\n yamlFlow.push(...planResult.yamlFlow || []);\n let executables;\n try {\n executables = await this.convertPlanToExecutable(plans, opts);\n taskExecutor.append(executables.tasks);\n } catch (error) {\n return this.appendErrorPlan(taskExecutor, `Error converting plans to executable tasks: ${error}, plans: ${JSON.stringify(plans)}`);\n }\n await taskExecutor.flush();\n if (taskExecutor.isInErrorState()) return {\n output: void 0,\n executor: taskExecutor\n };\n if (null == planResult ? void 0 : planResult.log) logList.push(planResult.log);\n if (!planResult.more_actions_needed_by_instruction) {\n planningTask = null;\n break;\n }\n planningTask = this.planningTaskFromPrompt(userPrompt, logList.length > 0 ? `- ${logList.join('\\n- ')}` : void 0, actionContext);\n replanCount++;\n }\n return {\n output: {\n yamlFlow\n },\n executor: taskExecutor\n };\n }\n async actionToGoal(userPrompt, opts) {\n const taskExecutor = new Executor(taskTitleStr('Action', userPrompt), {\n onTaskStart: this.onTaskStartCallback\n });\n this.conversationHistory = [];\n const isCompleted = false;\n let currentActionNumber = 0;\n const maxActionNumber = 40;\n const yamlFlow = [];\n while(!isCompleted && currentActionNumber < maxActionNumber){\n currentActionNumber++;\n const planningTask = this.planningTaskToGoal(userPrompt);\n await taskExecutor.append(planningTask);\n const result = await taskExecutor.flush();\n if (taskExecutor.isInErrorState()) return {\n output: void 0,\n executor: taskExecutor\n };\n if (!result) throw new Error('result of taskExecutor.flush() is undefined in function actionToGoal');\n const { output } = result;\n const plans = output.actions;\n yamlFlow.push(...output.yamlFlow || []);\n let executables;\n try {\n executables = await this.convertPlanToExecutable(plans, opts);\n taskExecutor.append(executables.tasks);\n } catch (error) {\n return this.appendErrorPlan(taskExecutor, `Error converting plans to executable tasks: ${error}, plans: ${JSON.stringify(plans)}`);\n }\n await taskExecutor.flush();\n if (taskExecutor.isInErrorState()) return {\n output: void 0,\n executor: taskExecutor\n };\n if ('Finished' === plans[0].type) break;\n }\n return {\n output: {\n yamlFlow\n },\n executor: taskExecutor\n };\n }\n async createTypeQueryTask(type, demand, opt, multimodalPrompt) {\n const taskExecutor = new Executor(taskTitleStr(type, 'string' == typeof demand ? demand : JSON.stringify(demand)), {\n onTaskStart: this.onTaskStartCallback\n });\n const queryTask = {\n type: 'Insight',\n subType: type,\n locate: null,\n param: {\n dataDemand: multimodalPrompt ? {\n demand,\n multimodalPrompt\n } : demand\n },\n executor: async (param, taskContext)=>{\n const { task } = taskContext;\n let insightDump;\n const dumpCollector = (dump)=>{\n insightDump = dump;\n };\n this.insight.onceDumpUpdatedFn = dumpCollector;\n const shotTime = Date.now();\n const pageContext = await this.insight.contextRetrieverFn('extract');\n task.pageContext = pageContext;\n const recordItem = {\n type: 'screenshot',\n ts: shotTime,\n screenshot: pageContext.screenshotBase64,\n timing: 'before Extract'\n };\n task.recorder = [\n recordItem\n ];\n const ifTypeRestricted = 'Query' !== type;\n let demandInput = demand;\n if (ifTypeRestricted) {\n const returnType = 'Assert' === type ? 'Boolean' : type;\n demandInput = {\n result: `${returnType}, ${demand}`\n };\n }\n const { data, usage, thought } = await this.insight.extract(demandInput, opt, multimodalPrompt);\n let outputResult = data;\n if (ifTypeRestricted) {\n assert((null == data ? void 0 : data.result) !== void 0, 'No result in query data');\n outputResult = data.result;\n }\n return {\n output: outputResult,\n log: {\n dump: insightDump\n },\n usage,\n thought\n };\n }\n };\n await taskExecutor.append(this.prependExecutorWithScreenshot(queryTask));\n const result = await taskExecutor.flush();\n if (!result) throw new Error('result of taskExecutor.flush() is undefined in function createTypeQueryTask');\n const { output, thought } = result;\n return {\n output,\n thought,\n executor: taskExecutor\n };\n }\n async query(demand, opt) {\n return this.createTypeQueryTask('Query', demand, opt);\n }\n async boolean(prompt, opt) {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n return this.createTypeQueryTask('Boolean', textPrompt, opt, multimodalPrompt);\n }\n async number(prompt, opt) {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n return this.createTypeQueryTask('Number', textPrompt, opt, multimodalPrompt);\n }\n async string(prompt, opt) {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n return this.createTypeQueryTask('String', textPrompt, opt, multimodalPrompt);\n }\n async assert(assertion, opt) {\n const { textPrompt, multimodalPrompt } = parsePrompt(assertion);\n return await this.createTypeQueryTask('Assert', textPrompt, opt, multimodalPrompt);\n }\n appendConversationHistory(conversationHistory) {\n if ('user' === conversationHistory.role) {\n const userImgItems = this.conversationHistory.filter((item)=>'user' === item.role);\n if (userImgItems.length >= 4 && 'user' === conversationHistory.role) {\n const firstUserImgIndex = this.conversationHistory.findIndex((item)=>'user' === item.role);\n if (firstUserImgIndex >= 0) this.conversationHistory.splice(firstUserImgIndex, 1);\n }\n }\n this.conversationHistory.push(conversationHistory);\n }\n async appendErrorPlan(taskExecutor, errorMsg) {\n const errorPlan = {\n type: 'Error',\n param: {\n thought: errorMsg\n },\n locate: null\n };\n const { tasks } = await this.convertPlanToExecutable([\n errorPlan\n ]);\n await taskExecutor.append(this.prependExecutorWithScreenshot(tasks[0]));\n await taskExecutor.flush();\n return {\n output: void 0,\n executor: taskExecutor\n };\n }\n async waitFor(assertion, opt) {\n const description = `waitFor: ${assertion}`;\n const taskExecutor = new Executor(taskTitleStr('WaitFor', description), {\n onTaskStart: this.onTaskStartCallback\n });\n const { timeoutMs, checkIntervalMs } = opt;\n assert(assertion, 'No assertion for waitFor');\n assert(timeoutMs, 'No timeoutMs for waitFor');\n assert(checkIntervalMs, 'No checkIntervalMs for waitFor');\n const overallStartTime = Date.now();\n let startTime = Date.now();\n let errorThought = '';\n while(Date.now() - overallStartTime < timeoutMs){\n startTime = Date.now();\n const assertPlan = {\n type: 'AssertWithoutThrow',\n param: {\n assertion\n },\n locate: null\n };\n const { tasks: assertTasks } = await this.convertPlanToExecutable([\n assertPlan\n ]);\n await taskExecutor.append(this.prependExecutorWithScreenshot(assertTasks[0]));\n const result = await taskExecutor.flush();\n if (!result) throw new Error('result of taskExecutor.flush() is undefined in function waitFor');\n const { output } = result;\n if (null == output ? void 0 : output.pass) return {\n output: void 0,\n executor: taskExecutor\n };\n errorThought = (null == output ? void 0 : output.thought) || `unknown error when waiting for assertion: ${assertion}`;\n const now = Date.now();\n if (now - startTime < checkIntervalMs) {\n const timeRemaining = checkIntervalMs - (now - startTime);\n const sleepPlan = {\n type: 'Sleep',\n param: {\n timeMs: timeRemaining\n },\n locate: null\n };\n const { tasks: sleepTasks } = await this.convertPlanToExecutable([\n sleepPlan\n ]);\n await taskExecutor.append(this.prependExecutorWithScreenshot(sleepTasks[0]));\n await taskExecutor.flush();\n }\n }\n return this.appendErrorPlan(taskExecutor, `waitFor timeout: ${errorThought}`);\n }\n constructor(page, insight, opts){\n _define_property(this, \"page\", void 0);\n _define_property(this, \"insight\", void 0);\n _define_property(this, \"taskCache\", void 0);\n _define_property(this, \"conversationHistory\", []);\n _define_property(this, \"onTaskStartCallback\", void 0);\n this.page = page;\n this.insight = insight;\n this.taskCache = opts.taskCache;\n this.onTaskStartCallback = null == opts ? void 0 : opts.onTaskStart;\n }\n}\nexport { PageTaskExecutor };\n\n//# sourceMappingURL=tasks.mjs.map","import { getDebug } from \"@midscene/shared/logger\";\nimport { assert } from \"@midscene/shared/utils\";\nconst debug = getDebug('plan-builder');\nfunction buildPlans(type, locateParam, param) {\n let returnPlans = [];\n const locatePlan = locateParam ? {\n type: 'Locate',\n locate: locateParam,\n param: locateParam,\n thought: ''\n } : null;\n if ('Tap' === type || 'Hover' === type || 'RightClick' === type) {\n assert(locateParam, `missing locate info for action \"${type}\"`);\n assert(locatePlan, `missing locate info for action \"${type}\"`);\n const tapPlan = {\n type,\n param: null,\n thought: '',\n locate: locateParam\n };\n returnPlans = [\n locatePlan,\n tapPlan\n ];\n }\n if ('Input' === type || 'KeyboardPress' === type) {\n if ('Input' === type) assert(locateParam, `missing locate info for action \"${type}\"`);\n assert(param, `missing param for action \"${type}\"`);\n const inputPlan = {\n type,\n param: param,\n thought: '',\n locate: locateParam\n };\n returnPlans = locatePlan ? [\n locatePlan,\n inputPlan\n ] : [\n inputPlan\n ];\n }\n if ('Scroll' === type) {\n assert(param, `missing param for action \"${type}\"`);\n const scrollPlan = {\n type,\n param: param,\n thought: '',\n locate: locateParam\n };\n returnPlans = locatePlan ? [\n locatePlan,\n scrollPlan\n ] : [\n scrollPlan\n ];\n }\n if ('Sleep' === type) {\n assert(param, `missing param for action \"${type}\"`);\n const sleepPlan = {\n type,\n param: param,\n thought: '',\n locate: null\n };\n returnPlans = [\n sleepPlan\n ];\n }\n if ('Locate' === type) {\n assert(locateParam, `missing locate info for action \"${type}\"`);\n const locatePlan = {\n type,\n param: locateParam,\n locate: locateParam,\n thought: ''\n };\n returnPlans = [\n locatePlan\n ];\n }\n if (returnPlans) {\n debug('buildPlans', returnPlans);\n return returnPlans;\n }\n throw new Error(`Not supported type: ${type}`);\n}\nexport { buildPlans };\n\n//# sourceMappingURL=plan-builder.mjs.map","import { Insight } from \"@midscene/core\";\nimport js_yaml from \"js-yaml\";\nimport { ScriptPlayer, parseYamlScript } from \"../yaml/index.mjs\";\nimport { groupedActionDumpFileExt, reportHTMLContent, stringifyDumpData, writeLogFile } from \"@midscene/core/utils\";\nimport { DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT } from \"@midscene/shared/constants\";\nimport { getAIConfigInBoolean, vlLocateMode } from \"@midscene/shared/env\";\nimport { getDebug } from \"@midscene/shared/logger\";\nimport { assert } from \"@midscene/shared/utils\";\nimport { PageTaskExecutor } from \"./tasks.mjs\";\nimport { buildPlans } from \"./plan-builder.mjs\";\nimport { TaskCache } from \"./task-cache.mjs\";\nimport { locateParamStr, paramStr, scrollParamStr, taskTitleStr, typeStr } from \"./ui-utils.mjs\";\nimport { getReportFileName, parseContextFromWebPage, printReportMsg, trimContextByViewport } from \"./utils.mjs\";\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst debug = getDebug('web-integration');\nconst distanceOfTwoPoints = (p1, p2)=>{\n const [x1, y1] = p1;\n const [x2, y2] = p2;\n return Math.round(Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2));\n};\nconst includedInRect = (point, rect)=>{\n const [x, y] = point;\n const { left, top, width, height } = rect;\n return x >= left && x <= left + width && y >= top && y <= top + height;\n};\nconst defaultInsightExtractOption = {\n domIncluded: false,\n screenshotIncluded: true\n};\nclass PageAgent {\n async getUIContext(action) {\n if (this.frozenPageContext) {\n debug('Using frozen page context for action:', action);\n return this.frozenPageContext;\n }\n if (action && ('extract' === action || 'assert' === action)) return await parseContextFromWebPage(this.page, {\n ignoreMarker: true\n });\n return await parseContextFromWebPage(this.page, {\n ignoreMarker: !!vlLocateMode()\n });\n }\n async _snapshotContext() {\n return await this.getUIContext('locate');\n }\n async setAIActionContext(prompt) {\n this.opts.aiActionContext = prompt;\n }\n resetDump() {\n this.dump = {\n groupName: this.opts.groupName,\n groupDescription: this.opts.groupDescription,\n executions: []\n };\n return this.dump;\n }\n appendExecutionDump(execution) {\n const trimmedExecution = trimContextByViewport(execution);\n const currentDump = this.dump;\n currentDump.executions.push(trimmedExecution);\n }\n dumpDataString() {\n this.dump.groupName = this.opts.groupName;\n this.dump.groupDescription = this.opts.groupDescription;\n return stringifyDumpData(this.dump);\n }\n reportHTMLString() {\n return reportHTMLContent(this.dumpDataString());\n }\n writeOutActionDumps() {\n if (this.destroyed) throw new Error('PageAgent has been destroyed. Cannot update report file.');\n const { generateReport, autoPrintReportMsg } = this.opts;\n this.reportFile = writeLogFile({\n fileName: this.reportFileName,\n fileExt: groupedActionDumpFileExt,\n fileContent: this.dumpDataString(),\n type: 'dump',\n generateReport\n });\n debug('writeOutActionDumps', this.reportFile);\n if (generateReport && autoPrintReportMsg && this.reportFile) printReportMsg(this.reportFile);\n }\n async callbackOnTaskStartTip(task) {\n const param = paramStr(task);\n const tip = param ? `${typeStr(task)} - ${param}` : typeStr(task);\n if (this.onTaskStartTip) await this.onTaskStartTip(tip);\n }\n async afterTaskRunning(executor, doNotThrowError = false) {\n this.appendExecutionDump(executor.dump());\n try {\n var _this_onDumpUpdate, _this;\n await (null == (_this_onDumpUpdate = (_this = this).onDumpUpdate) ? void 0 : _this_onDumpUpdate.call(_this, this.dumpDataString()));\n } catch (error) {\n console.error('Error in onDumpUpdate', error);\n }\n this.writeOutActionDumps();\n if (executor.isInErrorState() && !doNotThrowError) {\n const errorTask = executor.latestErrorTask();\n throw new Error(`${null == errorTask ? void 0 : errorTask.errorMessage}\\n${null == errorTask ? void 0 : errorTask.errorStack}`, {\n cause: null == errorTask ? void 0 : errorTask.error\n });\n }\n }\n buildDetailedLocateParam(locatePrompt, opt) {\n assert(locatePrompt, 'missing locate prompt');\n if ('object' == typeof opt && null !== opt) {\n const prompt = locatePrompt;\n const deepThink = opt.deepThink ?? false;\n const cacheable = opt.cacheable ?? true;\n const xpath = opt.xpath;\n return {\n prompt,\n deepThink,\n cacheable,\n xpath\n };\n }\n return {\n prompt: locatePrompt\n };\n }\n async aiTap(locatePrompt, opt) {\n const detailedLocateParam = this.buildDetailedLocateParam(locatePrompt, opt);\n const plans = buildPlans('Tap', detailedLocateParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Tap', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiRightClick(locatePrompt, opt) {\n const detailedLocateParam = this.buildDetailedLocateParam(locatePrompt, opt);\n const plans = buildPlans('RightClick', detailedLocateParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('RightClick', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiHover(locatePrompt, opt) {\n const detailedLocateParam = this.buildDetailedLocateParam(locatePrompt, opt);\n const plans = buildPlans('Hover', detailedLocateParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Hover', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiInput(value, locatePrompt, opt) {\n assert('string' == typeof value, 'input value must be a string, use empty string if you want to clear the input');\n assert(locatePrompt, 'missing locate prompt for input');\n const detailedLocateParam = this.buildDetailedLocateParam(locatePrompt, opt);\n const plans = buildPlans('Input', detailedLocateParam, {\n value,\n autoDismissKeyboard: null == opt ? void 0 : opt.autoDismissKeyboard\n });\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Input', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiKeyboardPress(keyName, locatePrompt, opt) {\n assert(keyName, 'missing keyName for keyboard press');\n const detailedLocateParam = locatePrompt ? this.buildDetailedLocateParam(locatePrompt, opt) : void 0;\n const plans = buildPlans('KeyboardPress', detailedLocateParam, {\n value: keyName\n });\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('KeyboardPress', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiScroll(scrollParam, locatePrompt, opt) {\n const detailedLocateParam = locatePrompt ? this.buildDetailedLocateParam(locatePrompt, opt) : void 0;\n const plans = buildPlans('Scroll', detailedLocateParam, scrollParam);\n const paramInTitle = locatePrompt ? `${locateParamStr(detailedLocateParam)} - ${scrollParamStr(scrollParam)}` : scrollParamStr(scrollParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Scroll', paramInTitle), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiAction(taskPrompt, opt) {\n var _this_taskCache, _this_taskCache1;\n const cacheable = null == opt ? void 0 : opt.cacheable;\n const isVlmUiTars = 'vlm-ui-tars' === vlLocateMode();\n const matchedCache = isVlmUiTars || false === cacheable ? void 0 : null == (_this_taskCache = this.taskCache) ? void 0 : _this_taskCache.matchPlanCache(taskPrompt);\n if (matchedCache && (null == (_this_taskCache1 = this.taskCache) ? void 0 : _this_taskCache1.isCacheResultUsed)) {\n var _matchedCache_cacheContent, _matchedCache_cacheContent1;\n const { executor } = await this.taskExecutor.loadYamlFlowAsPlanning(taskPrompt, null == (_matchedCache_cacheContent = matchedCache.cacheContent) ? void 0 : _matchedCache_cacheContent.yamlWorkflow);\n await await this.afterTaskRunning(executor);\n debug('matched cache, will call .runYaml to run the action');\n const yaml = null == (_matchedCache_cacheContent1 = matchedCache.cacheContent) ? void 0 : _matchedCache_cacheContent1.yamlWorkflow;\n return this.runYaml(yaml);\n }\n const { output, executor } = await (isVlmUiTars ? this.taskExecutor.actionToGoal(taskPrompt, {\n cacheable\n }) : this.taskExecutor.action(taskPrompt, this.opts.aiActionContext, {\n cacheable\n }));\n if (this.taskCache && (null == output ? void 0 : output.yamlFlow) && false !== cacheable) {\n const yamlContent = {\n tasks: [\n {\n name: taskPrompt,\n flow: output.yamlFlow\n }\n ]\n };\n const yamlFlowStr = js_yaml.dump(yamlContent);\n this.taskCache.updateOrAppendCacheRecord({\n type: 'plan',\n prompt: taskPrompt,\n yamlWorkflow: yamlFlowStr\n }, matchedCache);\n }\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiQuery(demand, opt = defaultInsightExtractOption) {\n const { output, executor } = await this.taskExecutor.query(demand, opt);\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiBoolean(prompt, opt = defaultInsightExtractOption) {\n const { output, executor } = await this.taskExecutor.boolean(prompt, opt);\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiNumber(prompt, opt = defaultInsightExtractOption) {\n const { output, executor } = await this.taskExecutor.number(prompt, opt);\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiString(prompt, opt = defaultInsightExtractOption) {\n const { output, executor } = await this.taskExecutor.string(prompt, opt);\n await this.afterTaskRunning(executor);\n return output;\n }\n async aiAsk(prompt, opt = defaultInsightExtractOption) {\n return this.aiString(prompt, opt);\n }\n async describeElementAtPoint(center, opt) {\n const { verifyPrompt = true, retryLimit = 3 } = opt || {};\n let success = false;\n let retryCount = 0;\n let resultPrompt = '';\n let deepThink = (null == opt ? void 0 : opt.deepThink) || false;\n let verifyResult;\n while(!success && retryCount < retryLimit){\n if (retryCount >= 2) deepThink = true;\n debug('aiDescribe', center, 'verifyPrompt', verifyPrompt, 'retryCount', retryCount, 'deepThink', deepThink);\n const text = await this.insight.describe(center, {\n deepThink\n });\n debug('aiDescribe text', text);\n assert(text.description, `failed to describe element at [${center}]`);\n resultPrompt = text.description;\n verifyResult = await this.verifyLocator(resultPrompt, deepThink ? {\n deepThink: true\n } : void 0, center, opt);\n if (verifyResult.pass) success = true;\n else retryCount++;\n }\n return {\n prompt: resultPrompt,\n deepThink,\n verifyResult\n };\n }\n async verifyLocator(prompt, locateOpt, expectCenter, verifyLocateOption) {\n debug('verifyLocator', prompt, locateOpt, expectCenter, verifyLocateOption);\n const { center: verifyCenter, rect: verifyRect } = await this.aiLocate(prompt, locateOpt);\n const distance = distanceOfTwoPoints(expectCenter, verifyCenter);\n const included = includedInRect(expectCenter, verifyRect);\n const pass = distance <= ((null == verifyLocateOption ? void 0 : verifyLocateOption.centerDistanceThreshold) || 20) || included;\n const verifyResult = {\n pass,\n rect: verifyRect,\n center: verifyCenter,\n centerDistance: distance\n };\n debug('aiDescribe verifyResult', verifyResult);\n return verifyResult;\n }\n async aiLocate(prompt, opt) {\n const detailedLocateParam = this.buildDetailedLocateParam(prompt, opt);\n const plans = buildPlans('Locate', detailedLocateParam);\n const { executor, output } = await this.taskExecutor.runPlans(taskTitleStr('Locate', locateParamStr(detailedLocateParam)), plans, {\n cacheable: null == opt ? void 0 : opt.cacheable\n });\n await this.afterTaskRunning(executor);\n const { element } = output;\n return {\n rect: null == element ? void 0 : element.rect,\n center: null == element ? void 0 : element.center,\n scale: (await this.page.size()).dpr\n };\n }\n async aiAssert(assertion, msg, opt) {\n const { output, executor, thought } = await this.taskExecutor.assert(assertion, {\n returnThought: true\n });\n await this.afterTaskRunning(executor, true);\n if (null == opt ? void 0 : opt.keepRawResponse) return {\n pass: output,\n thought\n };\n if (!output) {\n var _executor_latestErrorTask;\n const errMsg = msg || `Assertion failed: ${assertion}`;\n const reasonMsg = `Reason: ${thought || (null == (_executor_latestErrorTask = executor.latestErrorTask()) ? void 0 : _executor_latestErrorTask.error) || '(no_reason)'}`;\n throw new Error(`${errMsg}\\n${reasonMsg}`);\n }\n }\n async aiWaitFor(assertion, opt) {\n const { executor } = await this.taskExecutor.waitFor(assertion, {\n timeoutMs: (null == opt ? void 0 : opt.timeoutMs) || 15000,\n checkIntervalMs: (null == opt ? void 0 : opt.checkIntervalMs) || 3000,\n assertion\n });\n await this.afterTaskRunning(executor, true);\n if (executor.isInErrorState()) {\n const errorTask = executor.latestErrorTask();\n throw new Error(`${null == errorTask ? void 0 : errorTask.error}\\n${null == errorTask ? void 0 : errorTask.errorStack}`);\n }\n }\n async ai(taskPrompt, type = 'action') {\n if ('action' === type) return this.aiAction(taskPrompt);\n if ('query' === type) return this.aiQuery(taskPrompt);\n if ('assert' === type) return this.aiAssert(taskPrompt);\n if ('tap' === type) return this.aiTap(taskPrompt);\n if ('rightClick' === type) return this.aiRightClick(taskPrompt);\n throw new Error(`Unknown type: ${type}, only support 'action', 'query', 'assert', 'tap', 'rightClick'`);\n }\n async runYaml(yamlScriptContent) {\n const script = parseYamlScript(yamlScriptContent, 'yaml', true);\n const player = new ScriptPlayer(script, async (target)=>({\n agent: this,\n freeFn: []\n }));\n await player.run();\n if ('error' === player.status) {\n const errors = player.taskStatusList.filter((task)=>'error' === task.status).map((task)=>{\n var _task_error;\n return `task - ${task.name}: ${null == (_task_error = task.error) ? void 0 : _task_error.message}`;\n }).join('\\n');\n throw new Error(`Error(s) occurred in running yaml script:\\n${errors}`);\n }\n return {\n result: player.result\n };\n }\n async evaluateJavaScript(script) {\n assert(this.page.evaluateJavaScript, 'evaluateJavaScript is not supported in current agent');\n return this.page.evaluateJavaScript(script);\n }\n async destroy() {\n await this.page.destroy();\n this.resetDump();\n this.destroyed = true;\n }\n async logScreenshot(title, opt) {\n const base64 = await this.page.screenshotBase64();\n const now = Date.now();\n const recorder = [\n {\n type: 'screenshot',\n ts: now,\n screenshot: base64\n }\n ];\n const task = {\n type: 'Log',\n subType: 'Screenshot',\n status: 'finished',\n recorder,\n timing: {\n start: now,\n end: now,\n cost: 0\n },\n param: {\n content: (null == opt ? void 0 : opt.content) || ''\n },\n executor: async ()=>{}\n };\n const executionDump = {\n sdkVersion: '',\n logTime: now,\n model_name: '',\n model_description: '',\n name: `Log - ${title || 'untitled'}`,\n description: (null == opt ? void 0 : opt.content) || '',\n tasks: [\n task\n ]\n };\n this.appendExecutionDump(executionDump);\n try {\n var _this_onDumpUpdate, _this;\n null == (_this_onDumpUpdate = (_this = this).onDumpUpdate) || _this_onDumpUpdate.call(_this, this.dumpDataString());\n } catch (error) {\n console.error('Failed to update dump', error);\n }\n this.writeOutActionDumps();\n }\n _unstableLogContent() {\n const { groupName, groupDescription, executions } = this.dump;\n const newExecutions = Array.isArray(executions) ? executions.map((execution)=>{\n const { tasks, ...restExecution } = execution;\n let newTasks = tasks;\n if (Array.isArray(tasks)) newTasks = tasks.map((task)=>{\n const { pageContext, log, ...restTask } = task;\n return restTask;\n });\n return {\n ...restExecution,\n ...newTasks ? {\n tasks: newTasks\n } : {}\n };\n }) : [];\n return {\n groupName,\n groupDescription,\n executions: newExecutions\n };\n }\n async freezePageContext() {\n debug('Freezing page context');\n const context = await this._snapshotContext();\n context._isFrozen = true;\n this.frozenPageContext = context;\n debug('Page context frozen successfully');\n }\n async unfreezePageContext() {\n debug('Unfreezing page context');\n this.frozenPageContext = void 0;\n debug('Page context unfrozen successfully');\n }\n constructor(page, opts){\n _define_property(this, \"page\", void 0);\n _define_property(this, \"insight\", void 0);\n _define_property(this, \"dump\", void 0);\n _define_property(this, \"reportFile\", void 0);\n _define_property(this, \"reportFileName\", void 0);\n _define_property(this, \"taskExecutor\", void 0);\n _define_property(this, \"opts\", void 0);\n _define_property(this, \"dryMode\", false);\n _define_property(this, \"onTaskStartTip\", void 0);\n _define_property(this, \"taskCache\", void 0);\n _define_property(this, \"onDumpUpdate\", void 0);\n _define_property(this, \"destroyed\", false);\n _define_property(this, \"frozenPageContext\", void 0);\n this.page = page;\n this.opts = Object.assign({\n generateReport: true,\n autoPrintReportMsg: true,\n groupName: 'Midscene Report',\n groupDescription: ''\n }, opts || {});\n if ('puppeteer' === this.page.pageType || 'playwright' === this.page.pageType) {\n this.page.waitForNavigationTimeout = this.opts.waitForNavigationTimeout ?? DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT;\n this.page.waitForNetworkIdleTimeout = this.opts.waitForNetworkIdleTimeout ?? DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT;\n }\n this.onTaskStartTip = this.opts.onTaskStartTip;\n this.insight = new Insight(async (action)=>this.getUIContext(action));\n if ((null == opts ? void 0 : opts.cacheId) && 'android' !== this.page.pageType) this.taskCache = new TaskCache(opts.cacheId, getAIConfigInBoolean('MIDSCENE_CACHE'));\n this.taskExecutor = new PageTaskExecutor(this.page, this.insight, {\n taskCache: this.taskCache,\n onTaskStart: this.callbackOnTaskStartTip.bind(this)\n });\n this.dump = this.resetDump();\n this.reportFileName = (null == opts ? void 0 : opts.reportFileName) || getReportFileName((null == opts ? void 0 : opts.testId) || this.page.pageType || 'web');\n }\n}\nexport { PageAgent };\n\n//# sourceMappingURL=agent.mjs.map","import { PLAYGROUND_SERVER_PORT } from \"@midscene/shared/constants\";\nimport { ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED, StaticPage, StaticPageAgent } from \"@midscene/web/playground\";\nconst serverBase = `http://localhost:${PLAYGROUND_SERVER_PORT}`;\nconst checkServerStatus = async ()=>{\n try {\n const res = await fetch(`${serverBase}/status`);\n return 200 === res.status;\n } catch (e) {\n return false;\n }\n};\nconst requestPlaygroundServer = async function(context, type, prompt) {\n let { requestId, deepThink } = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : {};\n const payload = {\n context,\n type,\n prompt\n };\n if (requestId) payload.requestId = requestId;\n if (deepThink) payload.deepThink = deepThink;\n const res = await fetch(`${serverBase}/execute`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload)\n });\n return res.json();\n};\nconst overrideServerConfig = async (aiConfig)=>fetch(`${serverBase}/config`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n aiConfig\n })\n });\nconst cancelTask = async (requestId)=>{\n try {\n const res = await fetch(`${serverBase}/cancel/${requestId}`);\n return res.json();\n } catch (error) {\n console.error('Failed to cancel task:', error);\n return {\n error: 'Failed to cancel task'\n };\n }\n};\nconst getTaskProgress = async (requestId)=>{\n try {\n const response = await fetch(`${serverBase}/task-progress/${requestId}`);\n return await response.json();\n } catch (error) {\n console.error('Failed to poll task progress:', error);\n return {\n tip: null\n };\n }\n};\nconst actionNameForType = (type)=>{\n if ('aiAction' === type) return 'Action';\n if ('aiQuery' === type) return 'Query';\n if ('aiAssert' === type) return 'Assert';\n if ('aiTap' === type) return 'Tap';\n return type;\n};\nconst staticAgentFromContext = (context)=>{\n const page = new StaticPage(context);\n return new StaticPageAgent(page);\n};\nconst formatErrorMessage = (e)=>{\n const errorMessage = (null == e ? void 0 : e.message) || '';\n if (errorMessage.includes('of different extension')) return 'Conflicting extension detected. Please disable the suspicious plugins and refresh the page. Guide: https://midscenejs.com/quick-experience.html#faq';\n if (!(null == errorMessage ? void 0 : errorMessage.includes(ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED))) return errorMessage;\n return 'Unknown error';\n};\nconst getPlaceholderForType = (type)=>{\n if ('aiQuery' === type) return 'What do you want to query?';\n if ('aiAssert' === type) return 'What do you want to assert?';\n return 'What do you want to do?';\n};\nconst blankResult = {\n result: null,\n dump: null,\n reportHTML: null,\n error: null\n};\nexport { actionNameForType, blankResult, cancelTask, checkServerStatus, formatErrorMessage, getPlaceholderForType, getTaskProgress, overrideServerConfig, requestPlaygroundServer, serverBase, staticAgentFromContext };\n","import { useEffect, useState } from \"react\";\nimport { useEnvConfig } from \"../store/store.mjs\";\nimport { checkServerStatus } from \"./playground-utils.mjs\";\nconst useServerValid = function() {\n let shouldRun = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : true;\n const [serverValid, setServerValid] = useState(true);\n const { serviceMode } = useEnvConfig();\n useEffect(()=>{\n let interruptFlag = false;\n if (!shouldRun) return;\n Promise.resolve((async ()=>{\n while(!interruptFlag){\n const status = await checkServerStatus();\n status ? setServerValid(true) : setServerValid(false);\n await new Promise((resolve)=>setTimeout(resolve, 1000));\n }\n })());\n return ()=>{\n interruptFlag = true;\n };\n }, [\n serviceMode,\n shouldRun\n ]);\n return serverValid;\n};\nexport { useServerValid };\n","import dayjs from \"dayjs\";\nfunction insightDumpToExecutionDump(insightDump) {\n const insightToTask = (insightDump)=>{\n var _insightDump_taskInfo, _insightDump_taskInfo1;\n const task = {\n type: 'Insight',\n subType: 'locate' === insightDump.type ? 'Locate' : 'Query',\n status: insightDump.error ? 'failed' : 'finished',\n locate: null,\n param: {\n ...insightDump.userQuery.element ? {\n query: insightDump.userQuery\n } : {},\n ...insightDump.userQuery.dataDemand ? {\n dataDemand: insightDump.userQuery.dataDemand\n } : {},\n insight: {}\n },\n log: {\n dump: insightDump\n },\n timing: {\n end: insightDump.logTime,\n cost: null == (_insightDump_taskInfo = insightDump.taskInfo) ? void 0 : _insightDump_taskInfo.durationMs,\n start: insightDump.logTime - (null == (_insightDump_taskInfo1 = insightDump.taskInfo) ? void 0 : _insightDump_taskInfo1.durationMs)\n },\n executor: ()=>{}\n };\n return task;\n };\n if (!Array.isArray(insightDump)) {\n const result = {\n sdkVersion: insightDump.sdkVersion,\n logTime: insightDump.logTime,\n model_name: insightDump.model_name,\n name: 'Insight',\n tasks: [\n insightToTask(insightDump)\n ]\n };\n return result;\n }\n const result = {\n sdkVersion: insightDump[0].sdkVersion,\n logTime: insightDump[0].logTime,\n model_name: insightDump[0].model_name,\n name: 'Insight',\n tasks: insightDump.map(insightToTask)\n };\n return result;\n}\nfunction timeStr(timestamp) {\n return timestamp ? dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss') : '-';\n}\nfunction filterBase64Value(input) {\n return input.replace(/data:image\\/[^\"]+\"/g, 'data:image...\"');\n}\nconst mousePointer = 'data:image/png;base64,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';\nconst mouseLoading = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAhGVYSWZNTQAqAAAACAAFARIAAwAAAAEAAQAAARoABQAAAAEAAABKARsABQAAAAEAAABSASgAAwAAAAEAAgAAh2kABAAAAAEAAABaAAAAAAAAAEgAAAABAAAASAAAAAEAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAYKADAAQAAAABAAAAYAAAAABaCTJNAAAACXBIWXMAAAsTAAALEwEAmpwYAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgoZXuEHAAAZfUlEQVR4Ae1da5Ac1XXue7tnHzMrYSMMEqyMYB/CCOyEhTjxH9YYk0p4GEsBJxTgFNjalYDEruCHMAkjEsd2gsu4AD1DUrYpUoZgy4iEAhNbqiRQDpIxGAGSdnmYt4wgknZmd2em++b7TnfPzvZ0z660u3rNXGmnu2/f53fOPffccx9tWQ3XQKCBwEFAwFiWOgjZNLKIQ8BkLR3nf7j6mcss+0grcxWW5HipSMD5ZumpxxyJlWIdqio3jR4zwpksNOSNUfdbLq/5ZZ2/n9fq+jffOLFlGss+I0mRcYb7O1fl+zuu5z3rYLK9zkwxz7TLZRZUZS2Phc8v6zhLGbXC0WpJCT6uZX1m1pqB+4RAqNiMIHiAiYblHlreeUGLUo/YWln5krfBuN7ftK178ddMdibKPW0twBiInAD8kWULF4KDbkqn7C2tjlpS9IxhhZDZZXuXdh9Hrsoepv2C8qwbUVRruOgV0yl9qdL66Vx/11/nb+hs91uDpVnXA6RzVbRpIYBwhoLIAefn+zr/xDXuf6MBrEQlyEXkdDQI/LesT2lV+ghvbtk2fZVgelNxFDEsO4C+COmcP1IyLK2TL7gUoSrdpG41RevxfF/XYoZTqCvrPJU8w7hTJkDYLFmJXF9Xv6esu1tsdRwy0MZjPRQLqiGC3CZbpbSyV5ilPamQm8KCHKorC6iymwA5GcL0pZu0wn0J5SH2Nu5NvuCVUPb5tm09kO/v+jLLKuWfBiJMqSmF4O9Z3tFpe2p9Jm335vMi2j2/AuO43HM0CWG9Aw5anl49cL9UPmgarNShcKHYHOrr+mSTbT0KccmyxzGmC9FkQ/yQqx6ybe+vWu56cUeIwYGWPS6jSaUlzRayfN/nOxfZrvr3TJPuzefcQhCZ6UaJK60AHHYcuoTFUvFDDD7LSpEiV+V9AQxSy9nQI4i/l27WF3muepB191tyr1MrYq13tbNMiLmFIgTNdmRZ9/kQME8026qbzRSQNyVECbyVGkW/0Kz1n+be7ryCniRE7Tgz9zbMO7es68J0k/3HwyUDCVrT8bXKj3rFlK0Xatt6XDAAFsSkZsyEl/tdeXL+2eu2FpkxWutPIDJnFfxmW4sLwDiWm3aUhrDdPeqZzZC0m6VMWb93TijfzHrfEuSt3F35orcRHZSGrCcmbBXSMmIKQCKkCq7xEH42MSAWxITYxISv6TUBwcfHlc4TGQ2R8433IPT7VnSuSTIzjFxEJilUzBpxzbvo4a5Jv9v8sLp/WyiuwnCH5EqVUrQatMShtzp6taXWQv3sHEVn5RohQi0mRb8GpvLMsFH6krbVOx4LMZpsZSZNAJH5aGq55aeeozy9GXo9wKeKKVpOfH7KKkHmO6MFzwLnr8jMbb+NoouB0SRQ70PI/RUlruxI74Nmc+Gcjq8qS33Nr6OhVlFD5TSuo7XtkgjaOzez6sUnQ6wqski8nRQBWKjL0eFygAVtcgNk/mng5loFo8gxUEf1qGv+x1M6S+5gKchxK1ei7ws6v8SSHeQXZAjrMozigxH60NJTz8Qg7F4w0BkQTyWwComQhJeLutqo6wtQsy9tWb19e6hdTVSNpATL8ULuGLnu1O6SpzdmHN2NAiWDzzEMBioouEa4DWn3mMtVIB9D7i8nfpjehHUe+twpJyjHXoe6XAIlg6KWeCVh5kJ02bmCt8PT7iWzV7+0PUynVjVryTfh1pAjXFd/G6omwafsTmqS5HwLBdEYBd+TzqSvJPjbLlvUdKSAz/KLagmtpu2fXno7nUtfIXVBnQKBKXVkuIiz2VIyKdWtjb1x73WnzfFV1NpaXk0CWBAVzISjP9xcBPWLXJCkbonYSbdolSu6/4CB1lXqtmdybIqLDpMONwJYzUdptRC96gfP5FgXqRPqhkhSz4TITr5kCplWu8v2ikskzAQml6TmVLb80f7BITgGTzRxMvPqOPBHj+q1NqMJjnjfals78FVmHmoYUpAj9KeyDkN9nd/MtOiv5EeAhI9CNRZBPfFin1Hm6szqwQ21RFFsCwgjDC1fMBeJ3E66+9bkGPDJEZD5BH+44IMPKvmWUfgfobiXix2qqKwTGSs3itaNwQ8CsG5J9fNgBZ4Fs90dxFBEUYLdqIoAzGjlIj9hbVI3YfA0v+DW6HRRCJH5AB9NVTjfytLAlTiQKVfuSLmRuqBOLG/bmsGvDJfQv0HJwGMSATREUSmdUu3EUOp5vz9HIvcVP5JoxXNZ9OT6Tj0bw/Mn8wU2QglRFRa+yERD7nkbMqsHPs1QJCACJhVMEjpSf0JxZG78cCa/L39PS0pdOiLm9tixkAhsmLIVzNrnZNa+uCWULJX1r2oBbC7U+wHjTQIjZDsiJINfdF/2RqylTJTxjlbwWb9QHFG5wGj+M6MlsxlMyjoX+T7iMJYLpYBawXfENhJmvIpECjEARoLXpB39aTQjgl+tcvqdrjPqeszh2ln/MvBbDsE5WItmcLQ9UxztvKGzWUwpRq1l/dDciVFcq4dqaizHVosL/Z2/K2EjxsdyCxDRAQDNF9tbQavr0OkmO3Su7IdgLlkxa83gz2ToDX0/OcLR9abrjoFRqtfptTv/FQO0LLBI7A/QOlxihcHT1ytQKEuU8k1ov8j1d3y+2dbrMKwORU85TJCAR6tmrmgehVbwhxWJ1tWtMCy4nlIjP6dzFzA5NpAYZaYWQCAtbFj4YNjLK22uSa8a/GEYl+8lsHQuMJLtuXbRseD+Pgo1po2fKPjSLmDS56vb+BuKLd7XkwMwhq1A5DosvLmS2c0ZP2Ag6JSxQE8A8KmspD1PrTBfWPA+xoUtTLD3qXW5/5BqGu3GbE8PVSgAXC37adOH+oVpu4cya3eKcc2CelXOrM5uVgb1Tc9rfhhM/iub+p/PuFEkaKbgZM+H86N2B1+eHoyQfQLc54MI9j7P70oMU4o6emKlAHsHtRb34ACsJsA1GrBenmnRFdUyuw2ouN+A2C7SNI36R5lS4JIBnLGuJz6hwqKJJtWrfH/3SZgs+QtOGcLLJwxDjjnTmkI6lvVYZs3Oh6T5Bbb9sSD1dxcOWj3jPA10NtBkAydAjUdD6QK0Frz6RKW/5qiVHp5yz8cExAmQV3RVCcAD5mVDxVRkv4Rq/FhhK5i9bsc7rjEP+GKoGj9iSvwxgzYfxk0x1JGJtRXIImX0xylP4KLNh34GEXndljlxQGT/0WRqYMWm4sIBVlvR+Q/0j7t8JSZWNHNtFCyX5kuSH7CXXnxvX+cfQFtazNVJCc5L+dL+lw3g4xESkfzP2/eBV29ubhIJHjcoVZi6ZK95ItdSkXASMqXUQkypzQom2KPih52vjUmJnNHu7cyemcUXo459A0li22YzzNWctHIIVQQRhY6aXvNTRsnIWID0lOm2U2WqRQlQam2xofKY+9tWv/SMgJ+tSjiSTx0+Bup4c1PhVXAsbERlPCvBoKJaSLfaXHHxO3whoaD9tFN9jSIvMcWkBKp5agufn9u2qK5VT8Ek5gfYYVSMqdfvvDYMPDfEBBEvEEdziQi61LNp9tH55R3zgfxHS/AEzNHBFz0dTEVSDO1iCqcv+kBcJ52UX535bxO5j0HZsxgv7UF/6wC/8WIIfA5pQuF0rJVLZ7CgBTM3xjoFK70IVrQRcGkJfQc9p/RfPpqbGgSYgK1c29oLNEc1BU50VhDMjyU9NG1/aNQuztEFS50GGZ9CmjA/VBNA++pnrm3Vy28hUYVxg1BqgjLU52vOegHbtlU7fwXo30z5+uh4vCDSEabU2mxnisY5A/h6FxgZocVqNqAf45unBNFsL5Mcn2B9Qh1ba8FmZa8vxpW1xceuiqkZVxNzrHP5BDrhWKObnwGoSckEou0Wj22bGuD7yNT4DUS0Mb+gqIETRSc+gkqTACcmTb5ATikmAjpskgSCyfr4xBq+4xAwyrecjfMc/4ANRAW0AnOyT6iYpsI+BBNfReW9KVFvaYif8RBWP60MvLRtngeu8fsNwNGU+uD+0zmZNgSc4yU7WxB6bW3Z6SDdxmUCBG4JmNS4akTQE3AjkQI/XFrYAj4IKx4FfZWjFgVXShn9qtzFhBH/xs8YAgFGBdd+C57cZRnriDn+nahtrecliaAgstsyd+5rTAXPjU44Fs4xzxCjY3QbMUsigGK/C9P1PO7uiJdTFWm+Pfh889hj4246EUALqKUmSVbmhNZ2WvcabhIIhMJ8ROdOQnDuM45zhuNbjNre1J5ntoMIdFVhA5tD6j373Q8FAQKpJOEbP3EIBChCc5yP146MY6PhEMafOVOvYk5YjdDgmewMtoun/FNOqkiUHKve32CLXx6werHQhh0F9lqQ99/wTRbVLcD3UbajvLkC6MrY5Ood6/H1DzCC5jgP3E9raKLDK9kb/rpvb6sOx7gkDvbFtFe/bfjEIhDOsSvrXFqSRdusDog5dmqV5llcMGSoDhD6eJxEBoF6xCNIPHzZuCYjAB3/eJEsUXO0RDFGrMxK/a/GDMIjwuaxqyEM9h9LD7FQ4r2/x++uk/NtvAkxMlYHORcMHiOEMGeGV8D+dYyE1Vs0+OA5LqByxRhntQ9/buEp/nbTCdXWuiUCAFTE6LfXLOQk1/uMWDkDe0IMKrbRr+gmY+3Kj7hvYFEWJ2Wis11KViJa1jzPds9gGps29TZaQQyY9Nq6tIcrIazZTd4FgH0RDv/g43gJD9mEd5jmdfOYms9jRkzvQaA3/EURVa2AEmw0nXGakMxZTK39zNei88b0bjgg0PPeVmFgbKs/A5v0iAnniMcTAKopO2f8e67JTr2puaQODecJnGXFCNEWAHJhoh5nPSBGj/nzBS2yOSGaKGPWuRPxM7ZD6MzkfhUmamANXDequ17YHYgT8xhOumJ7oRiSdlPGE+boIl8Zc2bOUceIfzZC1XLgOr4JMMkv7foo0PoktuwSSRFJFagQW9v134mBUwjgKvMO3uyRUQGDjHfcD1BKtzgLQLlPjX/VeIoi4GpzVqbFng3dhwdYjRc/IAk3cYy43nvQg55nXFypA1km19+5Bbs4erCRgHKrSs5To0KnvmskZXXNuWNgbzTjxrOPQK6v88EWR12MqVyK84jCYnCgh81lnk+k1wx8jPsrNI9oYVQopnfiBW+rwKcnNSqcEHV8U8H8EZ/rdWsS6x514VrZERz6CsMmwWeQCPjgdPK6PzT+uaSBRQ463GKktfef9Iy2GQno/0Ct5ZI6tWRff8fxXNmLxxrBK2LWyS127d6Is5RYW+HkSLW5WY876H+DyfjvyjusI6JkEXJh996rwPPHrb42RDEUddRf4cxiR9vd8jJcAxMNWUfP/u7SsUNfY3V/Hw9DEzSawCvY2ivLPIm9NBPZGY9AOAPrVvQBDE6ohTB8CBzP/Cymm20cz+VdKH51vk4IAPmHvmYpbqKHvoawhVf/+GYYd75Hn1BsCQGeC9b7ZJzRV/DuKR6+gWt1K4BaxfPf4Jbv4zG+FEOSOb3q0AX9Jw/7Q/94UXCqVkwfis4XYgPMvTVftO+rRIqcLk6oCcIM9XVcjV17d0M2OTBDU8qXwwRBeRQL94u9m3l3wO8LyAnVLSYIfnRfgo3aL0D246RF6RWjeFGSGLzH+Xne0syawfXhpngiIy1AIAqoaTveZoT314JGk5KAluYBp0jwWOwQv1m8slVE8kMexb8EkdUbmdP5JUiMTjlZoJpZGcSQYfH+6XTr6D30sLKbytKlTABfnPQ6rXe99AqCrJdl6clcTSOdh10gWZyo9WfcN8YDLCTxOviRjRjYogtt8Dw0/W9U9JvVtYcM8bVScxc3b8i+4gpcywRgzPBgPdPsPQh16Sc8EwLecSoVRY5PRWX6WKDwAIvqEhxdPgIgzsAz+A4CwLm7WcwHsUv7WXGv2VGqUDLbcHjT9+lBRuc1dOMIQE9m0Pbdl962jPd3AeWi2pDEhWeK5+sjg3Pzx47+kIcYsSUczWMD1k0kxVU4sEl7d2NUuwDcz30VUZuPQAmMBF+sQfl7FZywIuBV/FQRgAMzEoEnPGHXzL3pVoe9esK6IGXjYwc8TfzS4Vx+DdNF05BDLCryOCpuqe2xbqzMcFt+DcTvJfmiS26OAx/exsvAJA3Zf2fb6p33ImLs5pYqAkC0GGtRr3S/yHAdrKQFaERN8JXMWYCIw5FcHjQjfeVQf8e35F326CKCqNqoE+vGOrKuvsoZe6QDg8HmD7WzZF41uvR1esipvMQ24gToiJ88+rIO3wfAtnpHmX9LUEnDqEIeOTO0cWwlYYawwpJPoy/HoU4/CrEMwaq8VrWA8GU4yJq1ZucD6IVvxd5WEqsYvo9cRQHjwa48VzNsCSKOgmPQIuGPiMdKscM6yZmhPLzWZ9sk5i36WKnvCfhBv5FU4UQCVEZIO9a3h0fcndCKOGHDTifOsUCKh5pmUvaX8e2wHxh0VkJIaElxEQ5nPzkXjkoFT0hEXaROPLCVstz/iyt+Cf1hKjfs/hxm+y9KgCQyBbFrEkC0GnAwevC9JeVejGPKdmDQwU5nnCpVURLJDpqBB6PelflM/l6qazzgLhy4VIQ9LG+BsBw6K2o1GIfHU0pdUKcJON/D2XAOTg7e4dpmKedMRPTEyP3Kik9AHz+oNEVww/4dXw/tCJMP0BRehgi7lof7MTUWipoWMq7qkCoLdijuw3oybw4wQYo+qtnU9OBFrJLwIvgag9O9mM762Kz1A9tqyX2mH7qkBMP35Wtovygs7z4HH274GeR7GxokW0KM8akcTQ525dcooEOvaNk98I/hQCRMrxzyEN3IuIVmdVh2fXEph/DdzFE+i8SxDnCvVUcXvSM/8LMP5wksaVu786eTBZ/pT5oADBx+niO3rONSTOvjcCJLY7BG7qglymSgAtFlQTQNgBR9bXMHN4l4g27NdHnP68F2UaB4UDnKt552LppaUB7+Jej5Ulr5tBXAh3gyS+Sgbn7gaD+O8Nw/AgArRPCPajyu42J8J/L7MMOGH/GpRQSKG7EIshvjoX9Iai2PPpNq8GVADCvLFRszI54o35G+1DkkOmf3OMHEOQ68WAbD2TE0NqJIDCdhwzJGruFXM4ZwANNV6XcGN0oLQhxEmrR4rZVBJL/qR378TGGMAPk3GxyTNCQfiyj6cfB1DUTAi8cwTXdby6qBR8cCofToJ7ZijWXPuq2l/alMZRrhPQnL1XxcUMaONfTffUPnbM5vc4oVOS7mRBPnOibRopmEiFbMob+AVbZXZ1bteDJMd3+vB0QA4SQsw2NTk4+ZaetH0JG7+X0tFCBVqxBEHZkSWIerxzBUtzCXuhG98sP4Gt8v0+t2/qIyPsWeFaw4szhxdEvAXUgA/8ucJmXi08qAa7mSG0SsFAdcWMa1TbK8xqi/5SIDMV6xQJjtQ2oOYuGppitSHadGiJZziXwvhmU8QGaZKLOaJQllqHzK0FXr8OWIj+eHgahvM6klkpgu4eKfpulbo4/Ijbh7UaCfwu/XQOLZvQX96AfkGDD4HKDjomJZ18qllVxmjwVmXOM0MurKSg8kWy5HzSz81mulUViOiaiWy3dieHTnFE6PnBIBWOCQCGzSLUXrO/D5LO0gWHxE7YFEmEwe0uFBeDqtPGkKNOTkNjQU8vH/4W8QjLkLz5u5a58bx7l3mdtnuYOTmwi5j41bqbibBxp7O+xXPch4IdBtRxnmyfpWiBiu8uNCM7zjBrrJlI3V9O1huEFBb+XAlGMjirewL2GgA3GTLUDNtEMiMBA1CX51A810Po7zZQ0J7kStwU/f5zL2JQxvIw3cMQWIKaBFcYUE+Ukpvmc4qsGsA15Q9LH/VnKePDeWcG8Dl9dLd4NFxghEdZJxJ1ceKbsxtAjTKInv2F5B0wzilxmP91NxLPy0OIGGPxA/8tkOz/ka1Dk5JTaYKyVIzG+yeTI8/sD3kip+KJ+D2NGEgsB+DL9GIHwQd//zZQoGDKCpKoDw9yLvda2rBzaT6/lyqpzPNOgmC4YfehK/la1haFnXFdgSflOToxaBISlWQlBqDWwmkYsfhKBPYwXYXHHYFbaWIl32S5wV5MQU50aYY2Xd+DwdbhrLP1YcFjQ0NxjMFWMFxdWA6jq0iI+QEPzKNlhZ1qUi1oyUYaw0k7pzKdYw+lX+DJcsSljPqVnODkp9MEcylc42qRQzVnlwkQx6wqbKEwLzw81XwrsPo+IeHmDKtY38CId0t9iNFpBixsoUgMCehqVj30R+sLgaEMDz9VM4UO92rgwJFicI14fMxADT7Wa6slLeyqbL/VPplHs5+P+zaPMnQ85+kCIeX2qiLk4U2LFiBwP+yhJ/ytVmuoSd1xTn0ZswAsTXkMQX5fgxVwVyYZpa/Zv3mNvBslUdFAJIhaRF9NqVzZhmAKD8l3h/HtgSp/fq99tQQw24UU7q4hp7caLdsKzR8lY+E2C68Mp7Ao7d0MoBk1sKyHOcggB7QPNBAH8nFyVzXSzD0eHduI96+r4z91tZgZnLpSLlJC0iz/OrcZQjqt+OzuFiEOR0mAf8g6KACs60YAsRx0ITRsou3EodwNC4gVkST9RcfU/eoDPFJkSEewP3TwDix9ySeWf2+sHHJbHgh+tjuUQzm/WJVvluJu+lnDOZQa20Q27jIoDKlmHwIcyCW5znYijgKu9kaCYnQaP8PXDsGSgwW0URQM7nWUc8bgegQ1002/Gep1QR7NfxnnbkRzA0eIs7QbkZUfbDBQUq532I5yb+H8lGaZooTb2GAAAAAElFTkSuQmCC';\nexport { filterBase64Value, insightDumpToExecutionDump, mouseLoading, mousePointer, timeStr };\n","'use client';\nimport \"./player.css\";\nimport { mousePointer } from \"../utils.mjs\";\nimport { paramStr, typeStr } from \"@midscene/web/ui-utils\";\nimport { treeToList } from \"@midscene/shared/extractor\";\nconst stillDuration = 900;\nconst actionSpinningPointerDuration = 300;\nconst stillAfterInsightDuration = 300;\nconst locateDuration = 800;\nconst actionDuration = 1000;\nconst clearInsightDuration = 200;\nconst cameraStateForRect = (rect, imageWidth, imageHeight)=>{\n const canvasRatio = imageWidth / imageHeight;\n const rectRatio = rect.width / rect.height;\n let rectWidthOnPage;\n rectWidthOnPage = rectRatio >= canvasRatio ? rect.width : rect.height / imageHeight * imageWidth;\n const cameraPaddingRatio = rectWidthOnPage > 400 ? 0.1 : rectWidthOnPage > 50 ? 0.2 : 0.3;\n const cameraWidth = Math.min(imageWidth, rectWidthOnPage + imageWidth * cameraPaddingRatio * 2);\n const cameraHeight = imageHeight / imageWidth * cameraWidth;\n let left = Math.min(rect.left - imageWidth * cameraPaddingRatio, imageWidth - cameraWidth);\n left = Math.max(left, 0);\n let top = Math.min(rect.top - imageHeight * cameraPaddingRatio, imageHeight - cameraHeight);\n top = Math.max(top, 0);\n return {\n left: Math.round(left),\n top: Math.round(top),\n width: Math.round(cameraWidth)\n };\n};\nconst mergeTwoCameraState = (cameraState1, cameraState2)=>{\n const newLeft = Math.min(cameraState1.left, cameraState2.left);\n const newTop = Math.min(cameraState1.top, cameraState2.top);\n const newRight = Math.max(cameraState1.left + cameraState1.width, cameraState2.left + cameraState2.width);\n const newWidth = newRight - newLeft;\n return {\n left: newLeft,\n top: newTop,\n width: newWidth\n };\n};\nconst allScriptsFromDump = (dump)=>{\n let width;\n let height;\n let sdkVersion;\n let modelName;\n let modelDescription;\n dump.executions.forEach((execution)=>{\n if (execution.sdkVersion) sdkVersion = execution.sdkVersion;\n if (execution.model_name) modelName = execution.model_name;\n if (execution.model_description) modelDescription = execution.model_description;\n execution.tasks.forEach((task)=>{\n var _insightTask_pageContext_size, _insightTask_pageContext;\n const insightTask = task;\n if (null == (_insightTask_pageContext = insightTask.pageContext) ? void 0 : null == (_insightTask_pageContext_size = _insightTask_pageContext.size) ? void 0 : _insightTask_pageContext_size.width) {\n width = insightTask.pageContext.size.width;\n height = insightTask.pageContext.size.height;\n }\n });\n });\n if (!width || !height) {\n console.warn('width or height is missing in dump file');\n return {\n scripts: [],\n sdkVersion,\n modelName,\n modelDescription\n };\n }\n const allScripts = [];\n dump.executions.forEach((execution)=>{\n const scripts = generateAnimationScripts(execution, -1, width, height);\n if (scripts) allScripts.push(...scripts);\n });\n const allScriptsWithoutIntermediateDoneFrame = allScripts.filter((script, index)=>{\n if (index !== allScripts.length - 1 && 'Done' === script.title) return false;\n return true;\n });\n return {\n scripts: allScriptsWithoutIntermediateDoneFrame,\n width,\n height,\n sdkVersion,\n modelName,\n modelDescription\n };\n};\nconst generateAnimationScripts = (execution, task, imageWidth, imageHeight)=>{\n if (!execution || !execution.tasks.length) return null;\n if (0 === imageWidth || 0 === imageHeight) return null;\n let tasksIncluded = [];\n if (-1 === task) tasksIncluded = execution.tasks;\n else {\n const startIndex = execution.tasks.findIndex((t)=>t === task);\n if (-1 === startIndex) {\n console.error(\"task not found, cannot generate animation scripts\");\n return null;\n }\n if (startIndex === execution.tasks.length - 1) return null;\n for(let i = startIndex; i < execution.tasks.length; i++){\n if (i > startIndex && 'Planning' === execution.tasks[i].type) break;\n tasksIncluded.push(execution.tasks[i]);\n }\n }\n if (0 === tasksIncluded.length) return null;\n const fullPageCameraState = cameraStateForRect({\n left: 0,\n top: 0,\n width: imageWidth,\n height: imageHeight\n }, imageWidth, imageHeight);\n const pointerScript = (img, title, subTitle)=>({\n type: 'pointer',\n img,\n duration: 0,\n title,\n subTitle\n });\n const scripts = [];\n let insightCameraState;\n let currentCameraState = fullPageCameraState;\n let insightOnTop = false;\n const taskCount = tasksIncluded.length;\n let initSubTitle = '';\n let errorStateFlag = false;\n tasksIncluded.forEach((task, index)=>{\n if (errorStateFlag) return;\n if (0 === index) initSubTitle = paramStr(task);\n if ('Planning' === task.type) {\n const planningTask = task;\n if (planningTask.recorder && planningTask.recorder.length > 0) {\n var _planningTask_recorder_, _planningTask_recorder;\n scripts.push({\n type: 'img',\n img: null == (_planningTask_recorder = planningTask.recorder) ? void 0 : null == (_planningTask_recorder_ = _planningTask_recorder[0]) ? void 0 : _planningTask_recorder_.screenshot,\n camera: 0 === index ? fullPageCameraState : void 0,\n duration: stillDuration,\n title: typeStr(task),\n subTitle: paramStr(task)\n });\n }\n } else if ('Insight' === task.type && 'Locate' === task.subType) {\n var _insightTask_output;\n const insightTask = task;\n const resultElement = null == (_insightTask_output = insightTask.output) ? void 0 : _insightTask_output.element;\n const title = typeStr(task);\n const subTitle = paramStr(task);\n if (null == resultElement ? void 0 : resultElement.rect) insightCameraState = {\n ...cameraStateForRect(resultElement.rect, imageWidth, imageHeight),\n pointerLeft: resultElement.center[0],\n pointerTop: resultElement.center[1]\n };\n const context = insightTask.pageContext;\n if (null == context ? void 0 : context.screenshotBase64) {\n var _insightTask_log, _insightTask_output1, _insightDump_taskInfo;\n const insightDump = null == (_insightTask_log = insightTask.log) ? void 0 : _insightTask_log.dump;\n const insightContentLength = context.tree ? treeToList(context.tree).length : 0;\n if (context.screenshotBase64) scripts.push({\n type: 'img',\n img: context.screenshotBase64,\n duration: stillAfterInsightDuration,\n title,\n subTitle\n });\n let cameraState;\n cameraState = currentCameraState === fullPageCameraState ? void 0 : insightCameraState ? mergeTwoCameraState(currentCameraState, insightCameraState) : void 0;\n scripts.push({\n type: 'insight',\n img: context.screenshotBase64,\n context: context,\n camera: cameraState,\n highlightElement: (null == (_insightTask_output1 = insightTask.output) ? void 0 : _insightTask_output1.element) || void 0,\n searchArea: null == insightDump ? void 0 : null == (_insightDump_taskInfo = insightDump.taskInfo) ? void 0 : _insightDump_taskInfo.searchArea,\n duration: insightContentLength > 20 ? locateDuration : 0.5 * locateDuration,\n insightCameraDuration: locateDuration,\n title,\n subTitle\n });\n scripts.push({\n type: 'sleep',\n duration: stillAfterInsightDuration,\n title,\n subTitle\n });\n insightOnTop = true;\n }\n } else if ('Action' === task.type && 'FalsyConditionStatement' !== task.subType) {\n var _task_recorder_, _task_recorder, _task_recorder_1, _task_recorder1;\n const title = typeStr(task);\n const subTitle = paramStr(task);\n scripts.push(pointerScript(mousePointer, title, subTitle));\n currentCameraState = null != insightCameraState ? insightCameraState : fullPageCameraState;\n scripts.push({\n type: 'img',\n img: null == (_task_recorder = task.recorder) ? void 0 : null == (_task_recorder_ = _task_recorder[0]) ? void 0 : _task_recorder_.screenshot,\n duration: actionDuration,\n camera: 'Sleep' === task.subType ? fullPageCameraState : insightCameraState,\n title,\n subTitle\n });\n if (insightOnTop) {\n scripts.push({\n type: 'clear-insight',\n duration: clearInsightDuration,\n title,\n subTitle\n });\n insightOnTop = false;\n }\n const imgStillDuration = index < taskCount - 1 ? stillDuration : 0;\n if (null == (_task_recorder1 = task.recorder) ? void 0 : null == (_task_recorder_1 = _task_recorder1[1]) ? void 0 : _task_recorder_1.screenshot) {\n var _task_recorder_2, _task_recorder2;\n scripts.push({\n type: 'spinning-pointer',\n duration: actionSpinningPointerDuration,\n title,\n subTitle\n });\n scripts.push(pointerScript(mousePointer, title, subTitle));\n scripts.push({\n type: 'img',\n img: null == (_task_recorder2 = task.recorder) ? void 0 : null == (_task_recorder_2 = _task_recorder2[1]) ? void 0 : _task_recorder_2.screenshot,\n duration: imgStillDuration,\n title,\n subTitle\n });\n } else scripts.push({\n type: 'sleep',\n duration: imgStillDuration,\n title,\n subTitle\n });\n } else {\n var _task_recorder_3, _task_recorder3;\n const title = typeStr(task);\n const subTitle = paramStr(task);\n const screenshot = null == (_task_recorder3 = task.recorder) ? void 0 : null == (_task_recorder_3 = _task_recorder3[task.recorder.length - 1]) ? void 0 : _task_recorder_3.screenshot;\n if (screenshot) scripts.push({\n type: 'img',\n img: screenshot,\n duration: stillDuration,\n camera: fullPageCameraState,\n title,\n subTitle\n });\n }\n if ('finished' !== task.status) {\n errorStateFlag = true;\n const errorTitle = typeStr(task);\n const errorMsg = task.errorMessage || 'unknown error';\n const errorSubTitle = errorMsg.indexOf('NOT_IMPLEMENTED_AS_DESIGNED') > 0 ? 'Further actions cannot be performed in the current environment' : errorMsg;\n scripts.push({\n type: 'img',\n img: task.recorder && task.recorder.length > 0 ? task.recorder[task.recorder.length - 1].screenshot : '',\n camera: fullPageCameraState,\n duration: stillDuration,\n title: errorTitle,\n subTitle: errorSubTitle\n });\n return;\n }\n });\n if (!errorStateFlag) scripts.push({\n title: 'Done',\n subTitle: initSubTitle,\n type: 'img',\n duration: stillDuration,\n camera: fullPageCameraState\n });\n return scripts;\n};\nexport { allScriptsFromDump, cameraStateForRect, generateAnimationScripts, mergeTwoCameraState };\n","const elementColor = [\n '#01204E'\n];\nconst highlightColorForSearchArea = '#028391';\nconst highlightColorForElement = '#fd5907';\nfunction djb2Hash(str) {\n if (!str) str = 'unnamed';\n let hash = 5381;\n for(let i = 0; i < str.length; i++)hash = (hash << 5) + hash + str.charCodeAt(i);\n return hash >>> 0;\n}\nfunction colorForName(name) {\n const hashNumber = djb2Hash(name);\n return elementColor[hashNumber % elementColor.length];\n}\nfunction highlightColorForType(type) {\n if ('searchArea' === type) return highlightColorForSearchArea;\n return highlightColorForElement;\n}\nfunction globalThemeConfig() {\n return {\n token: {\n colorPrimary: '#2B83FF'\n },\n components: {\n Layout: {\n headerHeight: 60,\n headerPadding: '0 30px',\n headerBg: '#FFF',\n bodyBg: '#FFF'\n }\n }\n };\n}\nexport { colorForName, globalThemeConfig, highlightColorForType };\n","import { jsx } from \"react/jsx-runtime\";\nimport \"./logo.css\";\nconst LogoUrl = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/vhaeh7vhabf/Midscene.png';\nconst Logo = (param)=>{\n let { hideLogo = false } = param;\n if (hideLogo) return null;\n return /*#__PURE__*/ jsx(\"div\", {\n className: \"logo\",\n children: /*#__PURE__*/ jsx(\"a\", {\n href: \"https://midscenejs.com/\",\n target: \"_blank\",\n rel: \"noreferrer\",\n children: /*#__PURE__*/ jsx(\"img\", {\n alt: \"Midscene_logo\",\n src: \"https://lf3-static.bytednsdoc.com/obj/eden-cn/vhaeh7vhabf/Midscene.png\"\n })\n })\n });\n};\nexport { Logo, LogoUrl };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport { SettingOutlined } from \"@ant-design/icons\";\nimport { Input, Modal, Tooltip } from \"antd\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useEnvConfig } from \"./store/store.mjs\";\nfunction EnvConfig(param) {\n let { showTooltipWhenEmpty = true, showModelName = true, tooltipPlacement = 'bottom', mode = 'icon' } = param;\n const { config, configString, loadConfig, syncFromStorage } = useEnvConfig();\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [tempConfigString, setTempConfigString] = useState(configString);\n const midsceneModelName = config.MIDSCENE_MODEL_NAME;\n const componentRef = useRef(null);\n const showModal = (e)=>{\n syncFromStorage();\n setIsModalOpen(true);\n e.preventDefault();\n e.stopPropagation();\n };\n const handleOk = ()=>{\n setIsModalOpen(false);\n loadConfig(tempConfigString);\n };\n const handleCancel = ()=>{\n setIsModalOpen(false);\n };\n useEffect(()=>{\n if (isModalOpen) setTempConfigString(configString);\n }, [\n isModalOpen,\n configString\n ]);\n return /*#__PURE__*/ jsxs(\"div\", {\n style: {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '10px',\n alignItems: 'center',\n height: '100%',\n minHeight: '32px'\n },\n ref: componentRef,\n children: [\n showModelName ? midsceneModelName : null,\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Please set up your environment variables before using.\",\n placement: tooltipPlacement,\n align: {\n offset: [\n -10,\n 5\n ]\n },\n getPopupContainer: ()=>componentRef.current,\n open: isModalOpen ? false : showTooltipWhenEmpty ? 0 === Object.keys(config).length : void 0,\n children: 'icon' === mode ? /*#__PURE__*/ jsx(SettingOutlined, {\n onClick: showModal\n }) : /*#__PURE__*/ jsx(\"span\", {\n onClick: showModal,\n style: {\n color: '#006AFF',\n cursor: 'pointer'\n },\n children: \"set up\"\n })\n }),\n /*#__PURE__*/ jsxs(Modal, {\n title: \"Model Env Config\",\n open: isModalOpen,\n onOk: handleOk,\n onCancel: handleCancel,\n okText: \"Save\",\n style: {\n width: '800px',\n height: '100%',\n marginTop: '10%'\n },\n destroyOnClose: true,\n maskClosable: true,\n centered: true,\n children: [\n /*#__PURE__*/ jsx(Input.TextArea, {\n rows: 7,\n placeholder: 'OPENAI_API_KEY=sk-...\\nMIDSCENE_MODEL_NAME=gpt-4o-2024-08-06\\n...',\n value: tempConfigString,\n onChange: (e)=>setTempConfigString(e.target.value),\n style: {\n whiteSpace: 'nowrap',\n wordWrap: 'break-word'\n }\n }),\n /*#__PURE__*/ jsxs(\"div\", {\n children: [\n /*#__PURE__*/ jsx(\"p\", {\n children: \"The format is KEY=VALUE and separated by new lines.\"\n }),\n /*#__PURE__*/ jsxs(\"p\", {\n children: [\n \"These data will be saved \",\n /*#__PURE__*/ jsx(\"strong\", {\n children: \"locally in your browser\"\n }),\n \".\"\n ]\n })\n ]\n })\n ]\n })\n ]\n });\n}\nexport { EnvConfig };\n","import { create } from \"zustand\";\nvar __webpack_require__ = {};\n(()=>{\n __webpack_require__.d = (exports, definition)=>{\n for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {\n enumerable: true,\n get: definition[key]\n });\n };\n})();\n(()=>{\n __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);\n})();\n(()=>{\n __webpack_require__.r = (exports)=>{\n if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {\n value: 'Module'\n });\n Object.defineProperty(exports, '__esModule', {\n value: true\n });\n };\n})();\nvar external_zustand_namespaceObject = {};\n__webpack_require__.r(external_zustand_namespaceObject);\n__webpack_require__.d(external_zustand_namespaceObject, {\n create: ()=>create\n});\nconst { create: history_create } = external_zustand_namespaceObject;\nconst HISTORY_KEY = 'midscene-prompt-history';\nconst getHistoryFromLocalStorage = ()=>{\n const historyString = localStorage.getItem(HISTORY_KEY);\n return historyString ? JSON.parse(historyString) : [];\n};\nconst useHistoryStore = history_create((set, get)=>({\n history: getHistoryFromLocalStorage(),\n clearHistory: ()=>{\n set({\n history: []\n });\n localStorage.removeItem(HISTORY_KEY);\n },\n addHistory: (historyItem)=>{\n const newHistory = [\n historyItem,\n ...get().history.filter((h)=>h.prompt !== historyItem.prompt)\n ];\n while(newHistory.length > 10)newHistory.pop();\n set({\n history: newHistory\n });\n localStorage.setItem(HISTORY_KEY, JSON.stringify(newHistory));\n }\n }));\nexport { useHistoryStore };\n","import { jsx } from \"react/jsx-runtime\";\nimport \"react\";\nconst SvgSetting = (props)=>/*#__PURE__*/ jsx(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 27,\n height: 27,\n fill: \"none\",\n viewBox: \"0 0 27 27\",\n ...props,\n children: /*#__PURE__*/ jsx(\"path\", {\n stroke: \"#000\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeOpacity: 0.85,\n strokeWidth: 1.333,\n d: \"M19.527 8.855h-2M14.86 7.522v2.667M14.86 8.855H7.527M10.194 13.522H7.527M12.86 12.189v2.666M20.193 13.522H12.86M19.527 18.189h-2M14.86 16.855v2.667M14.86 18.189H7.527\"\n })\n });\nconst setting = SvgSetting;\nexport { setting as default };\n","import { jsx } from \"react/jsx-runtime\";\nimport \"./shiny-text.css\";\nconst ShinyText = (param)=>{\n let { text, disabled = false, speed = 5, className = '' } = param;\n const style = {\n '--animation-duration': `${speed}s`\n };\n return /*#__PURE__*/ jsx(\"div\", {\n className: `shiny-text ${disabled ? 'disabled' : ''} ${className}`,\n style: style,\n children: text\n });\n};\nconst shiny_text = ShinyText;\nexport { shiny_text as default };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport { Alert } from \"antd\";\nimport shiny_text from \"../shiny-text.mjs\";\nimport \"./index.css\";\nconst errorMessageServerNotReady = /*#__PURE__*/ jsxs(\"span\", {\n children: [\n \"Don't worry, just one more step to launch the playground server.\",\n /*#__PURE__*/ jsx(\"br\", {}),\n \"Please run one of the commands under the midscene project directory:\",\n /*#__PURE__*/ jsx(\"br\", {}),\n \"a. \",\n /*#__PURE__*/ jsx(\"strong\", {\n children: \"npx midscene-playground\"\n }),\n /*#__PURE__*/ jsx(\"br\", {}),\n \"b. \",\n /*#__PURE__*/ jsx(\"strong\", {\n children: \"npx --yes @midscene/web\"\n })\n ]\n});\nconst serverLaunchTip = function() {\n let notReadyMessage = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : errorMessageServerNotReady;\n return /*#__PURE__*/ jsx(\"div\", {\n className: \"server-tip\",\n children: /*#__PURE__*/ jsx(Alert, {\n message: \"Playground Server Not Ready\",\n description: notReadyMessage,\n type: \"warning\"\n })\n });\n};\nconst emptyResultTip = /*#__PURE__*/ jsx(\"div\", {\n className: \"result-empty-tip\",\n style: {\n textAlign: 'center'\n },\n children: /*#__PURE__*/ jsx(shiny_text, {\n disabled: true,\n text: \"The result will be shown here\"\n })\n});\nconst trackingTip = 'limit popup to current tab';\nconst deepThinkTip = 'deep think';\nexport { deepThinkTip, emptyResultTip, errorMessageServerNotReady, serverLaunchTip, trackingTip };\n","import { jsx } from \"react/jsx-runtime\";\nimport { Checkbox, Dropdown } from \"antd\";\nimport setting from \"../../icons/setting.mjs\";\nimport { useEnvConfig } from \"../store/store.mjs\";\nimport { deepThinkTip, trackingTip } from \"./playground-constants.mjs\";\nimport \"./index.css\";\nconst ConfigSelector = (param)=>{\n let { showDeepThinkOption = false, enableTracking = false } = param;\n const forceSameTabNavigation = useEnvConfig((state)=>state.forceSameTabNavigation);\n const setForceSameTabNavigation = useEnvConfig((state)=>state.setForceSameTabNavigation);\n const deepThink = useEnvConfig((state)=>state.deepThink);\n const setDeepThink = useEnvConfig((state)=>state.setDeepThink);\n if (!enableTracking && !showDeepThinkOption) return null;\n const configItems = buildConfigItems();\n return /*#__PURE__*/ jsx(\"div\", {\n className: \"selector-trigger\",\n children: /*#__PURE__*/ jsx(Dropdown, {\n menu: {\n items: configItems\n },\n trigger: [\n 'click'\n ],\n children: /*#__PURE__*/ jsx(setting, {\n width: 24,\n height: 24\n })\n })\n });\n function buildConfigItems() {\n const items = [];\n if (enableTracking) items.push({\n label: /*#__PURE__*/ jsx(Checkbox, {\n onChange: (e)=>setForceSameTabNavigation(e.target.checked),\n checked: forceSameTabNavigation,\n children: trackingTip\n }),\n key: 'track-config'\n });\n if (showDeepThinkOption) items.push({\n label: /*#__PURE__*/ jsx(Checkbox, {\n onChange: (e)=>{\n setDeepThink(e.target.checked);\n },\n checked: deepThink,\n children: deepThinkTip\n }),\n key: 'deep-think-config'\n });\n return items;\n }\n};\nexport { ConfigSelector };\n","import { jsx } from \"react/jsx-runtime\";\nimport \"react\";\nconst SvgClose = (props)=>/*#__PURE__*/ jsx(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 18,\n height: 16,\n fill: \"none\",\n viewBox: \"0 0 18 16\",\n ...props,\n children: /*#__PURE__*/ jsx(\"path\", {\n stroke: \"#333\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeWidth: 1.333,\n d: \"m3.124 2.667 11.162 10.666M3.124 13.333 14.286 2.667\"\n })\n });\nconst icons_close = SvgClose;\nexport { icons_close as default };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport \"react\";\nconst SvgHistory = (props)=>/*#__PURE__*/ jsxs(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 25,\n height: 25,\n fill: \"none\",\n viewBox: \"0 0 25 25\",\n ...props,\n children: [\n /*#__PURE__*/ jsx(\"path\", {\n stroke: \"#000\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeOpacity: 0.85,\n strokeWidth: 1.33,\n d: \"M6.63 9.021c-2.862 6.126 2.197 10.501 6.063 10.501a7 7 0 1 0-6.063-10.5\"\n }),\n /*#__PURE__*/ jsx(\"path\", {\n stroke: \"#000\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeOpacity: 0.85,\n strokeWidth: 1.33,\n d: \"M12.695 8.322v4.203l2.967 2.968\"\n })\n ]\n });\nconst icons_history = SvgHistory;\nexport { icons_history as default };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport \"react\";\nconst SvgMagnifyingGlass = (props)=>/*#__PURE__*/ jsxs(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 19,\n height: 19,\n fill: \"none\",\n viewBox: \"0 0 19 19\",\n ...props,\n children: [\n /*#__PURE__*/ jsxs(\"g\", {\n stroke: \"#000\",\n strokeLinejoin: \"round\",\n strokeOpacity: 0.65,\n strokeWidth: 1.5,\n clipPath: \"url(#magnifying-glass_svg__a)\",\n children: [\n /*#__PURE__*/ jsx(\"path\", {\n d: \"M8.397 14.29a6.375 6.375 0 1 0 0-12.75 6.375 6.375 0 0 0 0 12.75Z\"\n }),\n /*#__PURE__*/ jsx(\"path\", {\n strokeLinecap: \"round\",\n d: \"M10.519 5.42a3 3 0 0 0-2.122-.88 3 3 0 0 0-2.121.88M12.98 12.499l3.182 3.182\"\n })\n ]\n }),\n /*#__PURE__*/ jsx(\"defs\", {\n children: /*#__PURE__*/ jsx(\"clipPath\", {\n id: \"magnifying-glass_svg__a\",\n children: /*#__PURE__*/ jsx(\"path\", {\n fill: \"#fff\",\n d: \"M.522.04h18v18h-18z\"\n })\n })\n })\n ]\n });\nconst magnifying_glass = SvgMagnifyingGlass;\nexport { magnifying_glass as default };\n","import { Fragment, jsx, jsxs } from \"react/jsx-runtime\";\nimport { Button, Input, Modal, Typography } from \"antd\";\nimport { useMemo, useState } from \"react\";\nimport icons_close from \"../../icons/close.mjs\";\nimport icons_history from \"../../icons/history.mjs\";\nimport magnifying_glass from \"../../icons/magnifying-glass.mjs\";\nimport { useHistoryStore } from \"../store/history.mjs\";\nimport \"./index.css\";\nconst { Text } = Typography;\nconst HistorySelector = (param)=>{\n let { onSelect } = param;\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [searchText, setSearchText] = useState('');\n const history = useHistoryStore((state)=>state.history);\n const clearHistory = useHistoryStore((state)=>state.clearHistory);\n const groupedHistory = useMemo(()=>{\n const now = Date.now();\n const sevenDaysAgo = now - 604800000;\n const oneYearAgo = now - 31536000000;\n const filteredHistory = history.filter((item)=>item.prompt.toLowerCase().includes(searchText.toLowerCase()));\n const groups = {\n recent7Days: filteredHistory.filter((item)=>item.timestamp >= sevenDaysAgo),\n recent1Year: filteredHistory.filter((item)=>item.timestamp < sevenDaysAgo && item.timestamp >= oneYearAgo),\n older: filteredHistory.filter((item)=>item.timestamp < oneYearAgo)\n };\n return groups;\n }, [\n history,\n searchText\n ]);\n const handleHistoryClick = (item)=>{\n onSelect(item);\n setIsModalOpen(false);\n };\n const handleClearHistory = ()=>{\n clearHistory();\n setSearchText('');\n setIsModalOpen(false);\n };\n const renderHistoryGroup = (title, items)=>{\n if (0 === items.length) return null;\n return /*#__PURE__*/ jsxs(\"div\", {\n className: \"history-group\",\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"history-group-title\",\n children: title\n }),\n items.map((item, index)=>/*#__PURE__*/ jsx(\"div\", {\n className: \"history-item\",\n onClick: ()=>handleHistoryClick(item),\n children: item.prompt\n }, `${item.timestamp}-${index}`))\n ]\n }, title);\n };\n return /*#__PURE__*/ jsxs(Fragment, {\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"selector-trigger\",\n onClick: ()=>setIsModalOpen(true),\n children: /*#__PURE__*/ jsx(icons_history, {\n width: 24,\n height: 24\n })\n }),\n /*#__PURE__*/ jsx(Modal, {\n open: isModalOpen,\n onCancel: ()=>setIsModalOpen(false),\n footer: null,\n width: \"100%\",\n closable: false,\n centered: false,\n transitionName: \"\",\n maskTransitionName: \"\",\n style: {\n margin: 0,\n padding: 0,\n maxWidth: 'none',\n top: 'auto',\n bottom: 0\n },\n styles: {\n wrapper: {\n alignItems: 'flex-end',\n justifyContent: 'center',\n paddingBottom: 0,\n display: 'flex'\n },\n body: {\n height: '70vh',\n padding: 0,\n margin: 0\n },\n content: {\n height: '70vh',\n borderRadius: '12px 12px 0 0',\n margin: 0,\n padding: 0,\n marginBottom: 0,\n position: 'fixed',\n bottom: 0,\n left: 0,\n right: 0\n }\n },\n maskClosable: true,\n destroyOnClose: true,\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"history-modal-container\",\n children: [\n /*#__PURE__*/ jsxs(\"div\", {\n className: \"history-modal-header\",\n children: [\n /*#__PURE__*/ jsxs(Text, {\n strong: true,\n style: {\n fontSize: '16px'\n },\n children: [\n \"History (\",\n history.length,\n \")\"\n ]\n }),\n /*#__PURE__*/ jsx(Button, {\n size: \"small\",\n type: \"text\",\n icon: /*#__PURE__*/ jsx(icons_close, {\n width: 16,\n height: 16\n }),\n onClick: ()=>setIsModalOpen(false),\n className: \"close-button\"\n })\n ]\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"history-search-section\",\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"search-input-wrapper\",\n children: [\n /*#__PURE__*/ jsx(Input, {\n placeholder: \"Search\",\n value: searchText,\n onChange: (e)=>setSearchText(e.target.value),\n prefix: /*#__PURE__*/ jsx(magnifying_glass, {\n width: 18,\n height: 18\n }),\n className: \"search-input\",\n allowClear: true\n }),\n /*#__PURE__*/ jsx(Button, {\n type: \"link\",\n onClick: handleClearHistory,\n className: \"clear-button\",\n disabled: 0 === history.length,\n children: \"Clear\"\n })\n ]\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"history-content\",\n children: 0 === history.length ? /*#__PURE__*/ jsx(\"div\", {\n className: \"no-results\",\n children: /*#__PURE__*/ jsx(Text, {\n type: \"secondary\",\n children: \"No history record\"\n })\n }) : /*#__PURE__*/ jsxs(Fragment, {\n children: [\n renderHistoryGroup('Last 7 days', groupedHistory.recent7Days),\n renderHistoryGroup('Last 1 year', groupedHistory.recent1Year),\n renderHistoryGroup('Earlier', groupedHistory.older),\n searchText && 0 === groupedHistory.recent7Days.length && 0 === groupedHistory.recent1Year.length && 0 === groupedHistory.older.length && /*#__PURE__*/ jsx(\"div\", {\n className: \"no-results\",\n children: /*#__PURE__*/ jsx(Text, {\n type: \"secondary\",\n children: \"No matching history record\"\n })\n })\n ]\n })\n })\n ]\n })\n })\n ]\n });\n};\nexport { HistorySelector };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport { BorderOutlined, SendOutlined } from \"@ant-design/icons\";\nimport { Button, Form, Input, Radio, Space, Tooltip } from \"antd\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useHistoryStore } from \"../store/history.mjs\";\nimport { ConfigSelector } from \"./ConfigSelector.mjs\";\nimport { HistorySelector } from \"./HistorySelector.mjs\";\nimport { actionNameForType, getPlaceholderForType } from \"./playground-utils.mjs\";\nimport \"./index.css\";\nconst { TextArea } = Input;\nconst PromptInput = (param)=>{\n let { runButtonEnabled, form, serviceMode, selectedType, dryMode, stoppable, loading, onRun, onStop, clearPromptAfterRun = true } = param;\n const [hoveringSettings, setHoveringSettings] = useState(false);\n const [promptValue, setPromptValue] = useState('');\n const placeholder = getPlaceholderForType(selectedType);\n const textAreaRef = useRef(null);\n const history = useHistoryStore((state)=>state.history);\n const addHistory = useHistoryStore((state)=>state.addHistory);\n const lastHistory = history[0];\n useEffect(()=>{\n if (lastHistory) {\n form.setFieldsValue({\n type: lastHistory.type || 'aiAction',\n prompt: lastHistory.prompt || ''\n });\n setPromptValue(lastHistory.prompt || '');\n } else {\n form.setFieldsValue({\n type: 'aiAction',\n prompt: ''\n });\n setPromptValue('');\n }\n }, []);\n const handleSelectHistory = useCallback((historyItem)=>{\n form.setFieldsValue({\n prompt: historyItem.prompt,\n type: historyItem.type\n });\n setPromptValue(historyItem.prompt);\n }, [\n form\n ]);\n const handlePromptChange = useCallback((e)=>{\n const value = e.target.value;\n setPromptValue(value);\n form.setFieldValue('prompt', value);\n }, [\n form\n ]);\n const isRunButtonEnabled = runButtonEnabled && promptValue.trim().length > 0;\n const handleRunWithHistory = useCallback(()=>{\n const values = form.getFieldsValue();\n if (values.prompt) addHistory({\n type: values.type,\n prompt: values.prompt,\n timestamp: Date.now()\n });\n onRun();\n if (clearPromptAfterRun) {\n setPromptValue('');\n form.setFieldValue('prompt', '');\n }\n }, [\n form,\n addHistory,\n onRun\n ]);\n const handleKeyDown = useCallback((e)=>{\n if ('Enter' === e.key && e.metaKey && isRunButtonEnabled) {\n handleRunWithHistory();\n e.preventDefault();\n e.stopPropagation();\n } else if ('Enter' === e.key) setTimeout(()=>{\n if (textAreaRef.current) {\n const textarea = textAreaRef.current.resizableTextArea.textArea;\n const selectionStart = textarea.selectionStart;\n const value = textarea.value;\n const lastNewlineIndex = value.lastIndexOf('\\n');\n const isAtLastLine = -1 === lastNewlineIndex || selectionStart > lastNewlineIndex;\n if (isAtLastLine) textarea.scrollTop = textarea.scrollHeight;\n }\n }, 0);\n }, [\n handleRunWithHistory,\n isRunButtonEnabled\n ]);\n const handleMouseEnter = useCallback(()=>{\n setHoveringSettings(true);\n }, []);\n const handleMouseLeave = useCallback(()=>{\n setHoveringSettings(false);\n }, []);\n const renderActionButton = useCallback(()=>{\n const runButton = (text)=>/*#__PURE__*/ jsx(Button, {\n type: \"primary\",\n icon: /*#__PURE__*/ jsx(SendOutlined, {}),\n style: {\n borderRadius: 20,\n zIndex: 999\n },\n onClick: handleRunWithHistory,\n disabled: !isRunButtonEnabled,\n loading: loading,\n children: text\n });\n if (dryMode) return 'aiAction' === selectedType ? /*#__PURE__*/ jsx(Tooltip, {\n title: \"Start executing until some interaction actions need to be performed. You can see the process of planning and locating.\",\n children: runButton('Dry Run')\n }) : runButton('Run');\n if (stoppable) return /*#__PURE__*/ jsx(Button, {\n icon: /*#__PURE__*/ jsx(BorderOutlined, {}),\n onClick: onStop,\n style: {\n borderRadius: 20,\n zIndex: 999\n },\n children: \"Stop\"\n });\n return runButton('Run');\n }, [\n dryMode,\n loading,\n handleRunWithHistory,\n onStop,\n isRunButtonEnabled,\n selectedType,\n stoppable\n ]);\n return /*#__PURE__*/ jsxs(\"div\", {\n className: \"prompt-input-wrapper\",\n children: [\n /*#__PURE__*/ jsxs(Space, {\n className: \"mode-radio-group-wrapper\",\n children: [\n /*#__PURE__*/ jsx(Form.Item, {\n name: \"type\",\n style: {\n margin: 0\n },\n children: /*#__PURE__*/ jsxs(Radio.Group, {\n buttonStyle: \"solid\",\n disabled: !runButtonEnabled,\n className: \"mode-radio-group\",\n children: [\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Auto Planning: plan the steps and execute\",\n children: /*#__PURE__*/ jsx(Radio.Button, {\n value: \"aiAction\",\n children: actionNameForType('aiAction')\n })\n }),\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Extract data directly from the UI\",\n children: /*#__PURE__*/ jsx(Radio.Button, {\n value: \"aiQuery\",\n children: actionNameForType('aiQuery')\n })\n }),\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Understand the UI and determine if the assertion is true\",\n children: /*#__PURE__*/ jsx(Radio.Button, {\n value: \"aiAssert\",\n children: actionNameForType('aiAssert')\n })\n }),\n /*#__PURE__*/ jsx(Tooltip, {\n title: \"Instant Action: click something\",\n children: /*#__PURE__*/ jsx(Radio.Button, {\n value: \"aiTap\",\n children: actionNameForType('aiTap')\n })\n })\n ]\n })\n }),\n /*#__PURE__*/ jsxs(\"div\", {\n className: \"action-icons\",\n children: [\n /*#__PURE__*/ jsx(HistorySelector, {\n onSelect: handleSelectHistory\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: hoveringSettings ? 'settings-wrapper settings-wrapper-hover' : 'settings-wrapper',\n onMouseEnter: handleMouseEnter,\n onMouseLeave: handleMouseLeave,\n children: /*#__PURE__*/ jsx(ConfigSelector, {\n enableTracking: 'In-Browser-Extension' === serviceMode,\n showDeepThinkOption: 'aiTap' === selectedType\n })\n })\n ]\n })\n ]\n }),\n /*#__PURE__*/ jsxs(\"div\", {\n className: `main-side-console-input ${!runButtonEnabled ? 'disabled' : ''} ${loading ? 'loading' : ''}`,\n children: [\n /*#__PURE__*/ jsx(Form.Item, {\n name: \"prompt\",\n style: {\n margin: 0\n },\n children: /*#__PURE__*/ jsx(TextArea, {\n className: \"main-side-console-input-textarea\",\n disabled: !runButtonEnabled,\n rows: 4,\n placeholder: placeholder,\n autoFocus: true,\n onKeyDown: handleKeyDown,\n onChange: handlePromptChange,\n value: promptValue,\n ref: textAreaRef\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"form-controller-wrapper\",\n children: renderActionButton()\n })\n ]\n })\n ]\n });\n};\nexport { PromptInput };\n","'use client';\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nimport \"pixi.js/unsafe-eval\";\nimport { Checkbox } from \"antd\";\nimport { Application, Container, Graphics, Rectangle, Sprite, Text, Texture } from \"pixi.js\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { colorForName, highlightColorForType } from \"./color.mjs\";\nimport \"./blackboard.css\";\nimport { treeToList } from \"@midscene/shared/extractor\";\nimport { DropShadowFilter } from \"pixi-filters\";\nimport { useBlackboardPreference } from \"./store/store.mjs\";\nconst itemFillAlpha = 0.4;\nconst highlightAlpha = 0.4;\nconst pointRadius = 10;\nconst pointMarkForItem = (point, type)=>{\n const [x, y] = point;\n const themeColor = highlightColorForType('element');\n const graphics = new Graphics();\n graphics.beginFill(themeColor, itemFillAlpha);\n graphics.drawCircle(x, y, pointRadius);\n graphics.endFill();\n return graphics;\n};\nconst rectMarkForItem = (rect, name, type)=>{\n const { left, top, width, height } = rect;\n let themeColor;\n themeColor = 'element' === type ? colorForName(name) : 'searchArea' === type ? highlightColorForType('searchArea') : highlightColorForType('element');\n const alpha = 'highlight' === type ? highlightAlpha : itemFillAlpha;\n const graphics = new Graphics();\n graphics.beginFill(themeColor, alpha);\n graphics.lineStyle(1, themeColor, 1);\n graphics.drawRect(left, top, width, height);\n graphics.endFill();\n const dropShadowFilter = new DropShadowFilter({\n blur: 2,\n quality: 3,\n alpha: 0.4,\n offset: {\n x: 4,\n y: 4\n },\n color: 0x333333\n });\n graphics.filters = [\n dropShadowFilter\n ];\n const nameFontSize = 18;\n if (!name) return [\n graphics\n ];\n const texts = new Text(name, {\n fontSize: nameFontSize,\n fill: 0x0\n });\n texts.x = left;\n texts.y = Math.max(top - (nameFontSize + 4), 0);\n return [\n graphics,\n texts\n ];\n};\nconst Blackboard = (props)=>{\n const highlightElements = props.highlightElements || [];\n const highlightIds = highlightElements.map((e)=>e.id);\n const highlightRect = props.highlightRect;\n const highlightPoints = props.highlightPoints;\n const context = props.uiContext;\n const { size, screenshotBase64 } = context;\n const screenWidth = size.width;\n const screenHeight = size.height;\n const domRef = useRef(null);\n const app = useMemo(()=>new Application(), []);\n const [appInitialed, setAppInitialed] = useState(false);\n const highlightContainer = useMemo(()=>new Container(), []);\n const elementMarkContainer = useMemo(()=>new Container(), []);\n const [hoverElement, setHoverElement] = useState(null);\n const pixiBgRef = useRef(void 0);\n const { markerVisible, setMarkerVisible, elementsVisible, setTextsVisible } = useBlackboardPreference();\n useEffect(()=>{\n Promise.resolve((async ()=>{\n if (!domRef.current || !screenWidth) return;\n await app.init({\n width: screenWidth,\n height: screenHeight,\n background: 0xffffff\n });\n const canvasEl = domRef.current;\n domRef.current.appendChild(app.canvas);\n const { clientWidth } = domRef.current.parentElement;\n const targetHeight = 0.6 * window.innerHeight;\n const viewportRatio = clientWidth / targetHeight;\n if (screenWidth / screenHeight <= viewportRatio) {\n const ratio = targetHeight / screenHeight;\n canvasEl.style.width = `${Math.floor(screenWidth * ratio)}px`;\n canvasEl.style.height = `${Math.floor(screenHeight * ratio)}px`;\n }\n app.stage.addChild(highlightContainer);\n app.stage.addChild(elementMarkContainer);\n setAppInitialed(true);\n })());\n return ()=>{\n console.log('will destroy');\n try {\n app.destroy(true, {\n children: true,\n texture: true\n });\n } catch (e) {\n console.warn('destroy failed', e);\n }\n };\n }, [\n app,\n screenWidth,\n screenHeight\n ]);\n useEffect(()=>{\n if (!appInitialed) return;\n app.stage.eventMode = 'static';\n app.stage.hitArea = new Rectangle(0, 0, screenWidth, screenHeight);\n const clickHandler = (event)=>{\n var _props_onCanvasClick;\n console.log('pixi click', event);\n const { x, y } = event.data.global;\n null == (_props_onCanvasClick = props.onCanvasClick) || _props_onCanvasClick.call(props, [\n Math.round(x),\n Math.round(y)\n ]);\n };\n app.stage.on('click', clickHandler);\n return ()=>{\n var _app_stage;\n null == app || null == (_app_stage = app.stage) || _app_stage.off('click');\n };\n }, [\n appInitialed,\n props.onCanvasClick,\n screenWidth,\n screenHeight\n ]);\n useEffect(()=>{\n if (!appInitialed) return;\n const img = new Image();\n img.onload = ()=>{\n if (!app.stage) return;\n const screenshotTexture = Texture.from(img);\n const backgroundSprite = new Sprite(screenshotTexture);\n backgroundSprite.x = 0;\n backgroundSprite.y = 0;\n backgroundSprite.width = screenWidth;\n backgroundSprite.height = screenHeight;\n backgroundSprite.eventMode = 'passive';\n app.stage.addChildAt(backgroundSprite, 0);\n pixiBgRef.current = backgroundSprite;\n };\n img.onerror = (e)=>{\n console.error('load screenshot failed', e);\n };\n img.src = screenshotBase64;\n }, [\n app.stage,\n appInitialed,\n screenWidth,\n screenHeight\n ]);\n const { highlightElementRects } = useMemo(()=>{\n const highlightElementRects = [];\n highlightContainer.removeChildren();\n elementMarkContainer.removeChildren();\n highlightContainer.eventMode = 'passive';\n elementMarkContainer.eventMode = 'passive';\n if (highlightRect) {\n const [graphics] = rectMarkForItem(highlightRect, 'Search Area', 'searchArea');\n highlightContainer.addChild(graphics);\n }\n if (highlightElements.length) highlightElements.forEach((element)=>{\n const { rect, content, id } = element;\n const [graphics] = rectMarkForItem(rect, content, 'highlight');\n highlightContainer.addChild(graphics);\n });\n if (null == highlightPoints ? void 0 : highlightPoints.length) highlightPoints.forEach((point)=>{\n const graphics = pointMarkForItem(point, 'highlightPoint');\n highlightContainer.addChild(graphics);\n });\n const elements = treeToList(context.tree);\n elements.forEach((element)=>{\n const { rect, content, id } = element;\n const ifHighlight = highlightIds.includes(id) || (null == hoverElement ? void 0 : hoverElement.id) === id;\n if (ifHighlight) return;\n const [graphics] = rectMarkForItem(rect, content, 'element');\n elementMarkContainer.addChild(graphics);\n });\n elementMarkContainer.visible = elementsVisible;\n return {\n highlightElementRects\n };\n }, [\n app,\n appInitialed,\n highlightElements,\n context.tree,\n hoverElement,\n highlightRect,\n highlightPoints\n ]);\n const onSetElementsVisible = (e)=>{\n setTextsVisible(e.target.checked);\n elementMarkContainer.visible = e.target.checked;\n };\n let bottomTipA = null;\n if (1 === highlightElementRects.length) bottomTipA = /*#__PURE__*/ jsx(\"div\", {\n className: \"bottom-tip\",\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"bottom-tip-item\",\n children: [\n \"Element: \",\n JSON.stringify(highlightElementRects[0])\n ]\n })\n });\n else if (highlightElementRects.length > 1) bottomTipA = /*#__PURE__*/ jsx(\"div\", {\n className: \"bottom-tip\",\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"bottom-tip-item\",\n children: [\n \"Element: \",\n JSON.stringify(highlightElementRects)\n ]\n })\n });\n return /*#__PURE__*/ jsxs(\"div\", {\n className: \"blackboard\",\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"blackboard-main-content\",\n style: {\n width: '100%'\n },\n ref: domRef\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"blackboard-filter\",\n style: {\n display: props.hideController ? 'none' : 'block'\n },\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"overlay-control\",\n children: /*#__PURE__*/ jsx(Checkbox, {\n checked: elementsVisible,\n onChange: onSetElementsVisible,\n children: \"Elements\"\n })\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"bottom-tip\",\n style: {\n display: props.hideController ? 'none' : 'block'\n },\n children: bottomTipA\n })\n ]\n });\n};\nconst blackboard = Blackboard;\nexport { Blackboard, blackboard as default, pointMarkForItem, rectMarkForItem };\n","import \"pixi.js/unsafe-eval\";\nimport { Assets } from \"pixi.js\";\nconst globalTextureMap = new Map();\nconst loadTexture = async (img)=>{\n if (globalTextureMap.has(img)) return;\n return Assets.load(img).then((texture)=>{\n globalTextureMap.set(img, texture);\n });\n};\nconst getTextureFromCache = (name)=>globalTextureMap.get(name);\nconst getTexture = async (name)=>{\n if (globalTextureMap.has(name)) return globalTextureMap.get(name);\n await loadTexture(name);\n return globalTextureMap.get(name);\n};\nexport { getTexture, getTextureFromCache, loadTexture };\n","'use client';\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nimport \"pixi.js/unsafe-eval\";\nimport { Application, Container, Sprite } from \"pixi.js\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport \"./player.css\";\nimport { mouseLoading, mousePointer } from \"../utils.mjs\";\nimport { CaretRightOutlined, DownloadOutlined, ExportOutlined, LoadingOutlined } from \"@ant-design/icons\";\nimport { treeToList } from \"@midscene/shared/extractor\";\nimport { Spin, Tooltip } from \"antd\";\nimport { rectMarkForItem } from \"./blackboard.mjs\";\nimport { getTextureFromCache, loadTexture } from \"./pixi-loader.mjs\";\nfunction _define_property(obj, key, value) {\n if (key in obj) Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n else obj[key] = value;\n return obj;\n}\nconst canvasPaddingLeft = 0;\nconst canvasPaddingTop = 0;\nconst cubicBezier = (t, p0, p1, p2, p3)=>{\n const t2 = 1 - t;\n return p0 * t2 * t2 * t2 + 3 * p1 * t * t2 * t2 + 3 * p2 * t * t * t2 + p3 * t * t * t;\n};\nconst cubicImage = (t)=>linear(t);\nconst cubicInsightElement = (t)=>cubicBezier(t, 0, 0.5, 0.5, 1);\nconst cubicMouse = (t)=>linear(t);\nconst linear = (t)=>t;\nconst sleep = (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));\nconst ERROR_FRAME_CANCEL = 'frame cancel (this is an error on purpose)';\nconst frameKit = ()=>{\n let cancelFlag = false;\n return {\n frame: (callback)=>{\n if (cancelFlag) throw new Error(ERROR_FRAME_CANCEL);\n requestAnimationFrame(()=>{\n if (cancelFlag) throw new Error(ERROR_FRAME_CANCEL);\n callback(performance.now());\n });\n },\n timeout: (callback, ms)=>{\n if (cancelFlag) throw new Error(ERROR_FRAME_CANCEL);\n setTimeout(()=>{\n if (cancelFlag) throw new Error(ERROR_FRAME_CANCEL);\n callback();\n }, ms);\n },\n cancel: ()=>{\n cancelFlag = true;\n }\n };\n};\nconst singleElementFadeInDuration = 80;\nconst LAYER_ORDER_IMG = 0;\nconst LAYER_ORDER_INSIGHT = 1;\nconst LAYER_ORDER_POINTER = 2;\nconst LAYER_ORDER_SPINNING_POINTER = 3;\nconst downloadReport = (content)=>{\n const blob = new Blob([\n content\n ], {\n type: 'text/html'\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'midscene_report.html';\n a.click();\n};\nclass RecordingSession {\n start() {\n const stream = this.canvas.captureStream(60);\n const mediaRecorder = new MediaRecorder(stream, {\n mimeType: 'video/webm'\n });\n mediaRecorder.ondataavailable = (event)=>{\n if (event.data.size > 0) this.chunks.push(event.data);\n };\n this.mediaRecorder = mediaRecorder;\n this.recording = true;\n return this.mediaRecorder.start();\n }\n stop() {\n var _this_mediaRecorder;\n if (!this.recording || !this.mediaRecorder) return void console.warn('not recording');\n this.mediaRecorder.onstop = ()=>{\n const blob = new Blob(this.chunks, {\n type: 'video/webm'\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'midscene_replay.webm';\n a.click();\n URL.revokeObjectURL(url);\n };\n null == (_this_mediaRecorder = this.mediaRecorder) || _this_mediaRecorder.stop();\n this.recording = false;\n this.mediaRecorder = null;\n }\n constructor(canvas){\n _define_property(this, \"canvas\", void 0);\n _define_property(this, \"mediaRecorder\", null);\n _define_property(this, \"chunks\", void 0);\n _define_property(this, \"recording\", false);\n this.canvas = canvas;\n this.chunks = [];\n }\n}\nfunction Player(props) {\n var _scripts_;\n const [titleText, setTitleText] = useState('');\n const [subTitleText, setSubTitleText] = useState('');\n const scripts = null == props ? void 0 : props.replayScripts;\n const imageWidth = (null == props ? void 0 : props.imageWidth) || 1920;\n const imageHeight = (null == props ? void 0 : props.imageHeight) || 1080;\n const fitMode = (null == props ? void 0 : props.fitMode) || 'height';\n const currentImg = useRef((null == scripts ? void 0 : null == (_scripts_ = scripts[0]) ? void 0 : _scripts_.img) || null);\n const divContainerRef = useRef(null);\n const app = useMemo(()=>new Application(), []);\n const pointerSprite = useRef(null);\n const spinningPointerSprite = useRef(null);\n const [replayMark, setReplayMark] = useState(0);\n const triggerReplay = ()=>{\n setReplayMark(Date.now());\n };\n const windowContentContainer = useMemo(()=>{\n const container = new Container();\n return container;\n }, []);\n const insightMarkContainer = useMemo(()=>{\n const container = new Container();\n container.zIndex = LAYER_ORDER_INSIGHT;\n return container;\n }, []);\n const basicCameraState = {\n left: 0,\n top: 0,\n width: imageWidth,\n pointerLeft: Math.round(imageWidth / 2),\n pointerTop: Math.round(imageHeight / 2)\n };\n const [animationProgress, setAnimationProgress] = useState(-1);\n const cancelFlag = useRef(false);\n useEffect(()=>{\n cancelFlag.current = false;\n return ()=>{\n cancelFlag.current = true;\n };\n }, []);\n const cameraState = useRef({\n ...basicCameraState\n });\n const repaintImage = async ()=>{\n const imgToUpdate = currentImg.current;\n if (!imgToUpdate) return void console.warn('no image to update');\n if (!getTextureFromCache(imgToUpdate)) {\n console.warn('image not loaded', imgToUpdate);\n await loadTexture(imgToUpdate);\n }\n const texture = getTextureFromCache(imgToUpdate);\n if (!texture) throw new Error('texture not found');\n const sprite = Sprite.from(texture);\n if (!sprite) throw new Error('sprite not found');\n const mainImgLabel = 'main-img';\n const child = windowContentContainer.getChildByLabel(mainImgLabel);\n if (child) windowContentContainer.removeChild(child);\n sprite.label = mainImgLabel;\n sprite.zIndex = LAYER_ORDER_IMG;\n sprite.width = imageWidth;\n sprite.height = imageHeight;\n windowContentContainer.addChild(sprite);\n };\n const spinningPointer = (frame)=>{\n var _pointerSprite_current, _pointerSprite_current1;\n if (!spinningPointerSprite.current) {\n spinningPointerSprite.current = Sprite.from(mouseLoading);\n spinningPointerSprite.current.zIndex = LAYER_ORDER_SPINNING_POINTER;\n spinningPointerSprite.current.anchor.set(0.5, 0.5);\n spinningPointerSprite.current.scale.set(0.5);\n spinningPointerSprite.current.label = 'spinning-pointer';\n }\n spinningPointerSprite.current.x = (null == (_pointerSprite_current = pointerSprite.current) ? void 0 : _pointerSprite_current.x) || 0;\n spinningPointerSprite.current.y = (null == (_pointerSprite_current1 = pointerSprite.current) ? void 0 : _pointerSprite_current1.y) || 0;\n windowContentContainer.addChild(spinningPointerSprite.current);\n let startTime;\n let isCancelled = false;\n const animate = (currentTime)=>{\n if (isCancelled) return;\n if (!startTime) startTime = currentTime;\n const elapsedTime = currentTime - startTime;\n const progress = (Math.sin(elapsedTime / 500 - Math.PI / 2) + 1) / 2;\n const rotation = progress * Math.PI * 2;\n if (spinningPointerSprite.current) spinningPointerSprite.current.rotation = rotation;\n frame(animate);\n };\n frame(animate);\n const stopFn = ()=>{\n if (spinningPointerSprite.current) windowContentContainer.removeChild(spinningPointerSprite.current);\n isCancelled = true;\n };\n return stopFn;\n };\n const updatePointer = async (img, x, y)=>{\n var _pointerSprite_current, _pointerSprite_current1;\n if (!getTextureFromCache(img)) {\n console.warn('image not loaded', img);\n await loadTexture(img);\n }\n const texture = getTextureFromCache(img);\n if (!texture) throw new Error('texture not found');\n const sprite = Sprite.from(texture);\n let targetX = null == (_pointerSprite_current = pointerSprite.current) ? void 0 : _pointerSprite_current.x;\n let targetY = null == (_pointerSprite_current1 = pointerSprite.current) ? void 0 : _pointerSprite_current1.y;\n if ('number' == typeof x) targetX = x;\n if ('number' == typeof y) targetY = y;\n if (void 0 === targetX || void 0 === targetY) return void console.warn('invalid pointer position', x, y);\n if (pointerSprite.current) {\n const pointer = windowContentContainer.getChildByLabel('pointer');\n if (pointer) windowContentContainer.removeChild(pointer);\n }\n pointerSprite.current = sprite;\n pointerSprite.current.x = targetX;\n pointerSprite.current.y = targetY;\n pointerSprite.current.label = 'pointer';\n pointerSprite.current.zIndex = LAYER_ORDER_POINTER;\n windowContentContainer.addChild(pointerSprite.current);\n };\n const updateCamera = (state)=>{\n cameraState.current = state;\n const newScale = Math.max(1, imageWidth / state.width);\n windowContentContainer.scale.set(newScale);\n windowContentContainer.x = Math.round(canvasPaddingLeft - state.left * newScale);\n windowContentContainer.y = Math.round(canvasPaddingTop - state.top * newScale);\n const pointer = windowContentContainer.getChildByLabel('pointer');\n if (pointer) {\n pointer.scale.set(1 / newScale);\n if ('number' == typeof state.pointerLeft && 'number' == typeof state.pointerTop) {\n pointer.x = state.pointerLeft;\n pointer.y = state.pointerTop;\n }\n }\n };\n const cameraAnimation = async (targetState, duration, frame)=>{\n const currentState = {\n ...cameraState.current\n };\n const startLeft = currentState.left;\n const startTop = currentState.top;\n const startPointerLeft = currentState.pointerLeft;\n const startPointerTop = currentState.pointerTop;\n const startScale = currentState.width / imageWidth;\n const startTime = performance.now();\n const shouldMovePointer = 'number' == typeof targetState.pointerLeft && 'number' == typeof targetState.pointerTop && (targetState.pointerLeft !== startPointerLeft || targetState.pointerTop !== startPointerTop);\n const pointerMoveDuration = shouldMovePointer ? 0.375 * duration : 0;\n const cameraMoveStart = pointerMoveDuration;\n const cameraMoveDuration = duration - pointerMoveDuration;\n await new Promise((resolve)=>{\n const animate = (currentTime)=>{\n const nextState = {\n ...cameraState.current\n };\n const elapsedTime = currentTime - startTime;\n if (shouldMovePointer) if (elapsedTime <= pointerMoveDuration) {\n const rawMouseProgress = Math.min(elapsedTime / pointerMoveDuration, 1);\n const mouseProgress = cubicMouse(rawMouseProgress);\n nextState.pointerLeft = startPointerLeft + (targetState.pointerLeft - startPointerLeft) * mouseProgress;\n nextState.pointerTop = startPointerTop + (targetState.pointerTop - startPointerTop) * mouseProgress;\n } else {\n nextState.pointerLeft = targetState.pointerLeft;\n nextState.pointerTop = targetState.pointerTop;\n }\n if (elapsedTime > cameraMoveStart) {\n const cameraElapsedTime = elapsedTime - cameraMoveStart;\n const rawCameraProgress = Math.min(cameraElapsedTime / cameraMoveDuration, 1);\n const cameraProgress = cubicImage(rawCameraProgress);\n const targetScale = targetState.width / imageWidth;\n const progressScale = startScale + (targetScale - startScale) * cameraProgress;\n const progressWidth = imageWidth * progressScale;\n const progressHeight = imageHeight * progressScale;\n nextState.width = progressWidth;\n const progressLeft = startLeft + (targetState.left - startLeft) * cameraProgress;\n const progressTop = startTop + (targetState.top - startTop) * cameraProgress;\n const horizontalExceed = progressLeft + progressWidth - imageWidth;\n const verticalExceed = progressTop + progressHeight - imageHeight;\n nextState.left = horizontalExceed > 0 ? progressLeft + horizontalExceed : progressLeft;\n nextState.top = verticalExceed > 0 ? progressTop + verticalExceed : progressTop;\n }\n updateCamera(nextState);\n if (elapsedTime < duration) frame(animate);\n else resolve();\n };\n frame(animate);\n });\n };\n const fadeInGraphics = function(graphics, duration, frame) {\n let targetAlpha = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : 1;\n return new Promise((resolve)=>{\n const startTime = performance.now();\n const animate = (currentTime)=>{\n const elapsedTime = currentTime - startTime;\n const progress = Math.min(elapsedTime / duration, 1);\n graphics.alpha = 0 === targetAlpha ? 1 - linear(progress) : linear(progress);\n if (elapsedTime < duration) frame(animate);\n else resolve();\n };\n frame(animate);\n });\n };\n const fadeOutItem = async (graphics, duration, frame)=>fadeInGraphics(graphics, duration, frame, 0);\n const insightElementsAnimation = async (elements, highlightElements, searchArea, duration, frame)=>{\n insightMarkContainer.removeChildren();\n const elementsToAdd = [\n ...elements\n ];\n const totalLength = elementsToAdd.length;\n let childrenCount = 0;\n await new Promise((resolve)=>{\n const startTime = performance.now();\n const animate = (currentTime)=>{\n const elapsedTime = currentTime - startTime;\n const progress = cubicInsightElement(Math.min(elapsedTime / duration, 1));\n const elementsToAddNow = Math.floor(progress * totalLength);\n while(childrenCount < elementsToAddNow){\n const randomIndex = Math.floor(Math.random() * elementsToAdd.length);\n const element = elementsToAdd.splice(randomIndex, 1)[0];\n if (element) {\n const [insightMarkGraphic] = rectMarkForItem(element.rect, element.content, 'element');\n insightMarkGraphic.alpha = 0;\n insightMarkContainer.addChild(insightMarkGraphic);\n childrenCount++;\n fadeInGraphics(insightMarkGraphic, singleElementFadeInDuration, frame);\n }\n }\n if (elapsedTime < duration) frame(animate);\n else {\n while(elementsToAdd.length > 0){\n const randomIndex = Math.floor(Math.random() * elementsToAdd.length);\n const element = elementsToAdd.splice(randomIndex, 1)[0];\n const [insightMarkGraphic] = rectMarkForItem(element.rect, element.content, 'element');\n insightMarkGraphic.alpha = 1;\n insightMarkContainer.addChild(insightMarkGraphic);\n }\n if (searchArea) {\n const [searchAreaGraphic] = rectMarkForItem(searchArea, 'Search Area', 'searchArea');\n searchAreaGraphic.alpha = 1;\n insightMarkContainer.addChild(searchAreaGraphic);\n }\n highlightElements.map((element)=>{\n const [insightMarkGraphic] = rectMarkForItem(element.rect, element.content || '', 'highlight');\n insightMarkGraphic.alpha = 1;\n insightMarkContainer.addChild(insightMarkGraphic);\n });\n resolve();\n }\n };\n frame(animate);\n });\n };\n const init = async ()=>{\n if (!divContainerRef.current || !scripts) return;\n await app.init({\n width: imageWidth,\n height: imageHeight,\n background: 0xf4f4f4,\n autoDensity: true,\n antialias: true\n });\n if (!divContainerRef.current) return;\n divContainerRef.current.appendChild(app.canvas);\n windowContentContainer.x = 0;\n windowContentContainer.y = 0;\n app.stage.addChild(windowContentContainer);\n insightMarkContainer.x = 0;\n insightMarkContainer.y = 0;\n windowContentContainer.addChild(insightMarkContainer);\n };\n const [isRecording, setIsRecording] = useState(false);\n const recorderSessionRef = useRef(null);\n const handleExport = ()=>{\n if (recorderSessionRef.current) return void console.warn('recorderSession exists');\n if (!app.canvas) return void console.warn('canvas is not initialized');\n recorderSessionRef.current = new RecordingSession(app.canvas);\n setIsRecording(true);\n triggerReplay();\n };\n const play = ()=>{\n let cancelFn;\n Promise.resolve((async ()=>{\n if (!app) throw new Error('app is not initialized');\n if (!scripts) throw new Error(\"scripts is required\");\n const { frame, cancel, timeout } = frameKit();\n cancelFn = cancel;\n const allImages = scripts.filter((item)=>!!item.img).map((item)=>item.img);\n await Promise.all([\n ...allImages,\n mouseLoading,\n mousePointer\n ].map(loadTexture));\n insightMarkContainer.removeChildren();\n await updatePointer(mousePointer, imageWidth / 2, imageHeight / 2);\n await repaintImage();\n await updateCamera({\n ...basicCameraState\n });\n const totalDuration = scripts.reduce((acc, item)=>acc + item.duration + (item.camera && item.insightCameraDuration ? item.insightCameraDuration : 0), 0);\n const progressUpdateInterval = 200;\n const startTime = performance.now();\n setAnimationProgress(0);\n const updateProgress = ()=>{\n const progress = Math.min((performance.now() - startTime) / totalDuration, 1);\n setAnimationProgress(progress);\n if (progress < 1) return timeout(updateProgress, progressUpdateInterval);\n };\n frame(updateProgress);\n if (recorderSessionRef.current) recorderSessionRef.current.start();\n for(const index in scripts){\n const item = scripts[index];\n setTitleText(item.title || '');\n setSubTitleText(item.subTitle || '');\n if ('sleep' === item.type) await sleep(item.duration);\n else if ('insight' === item.type) {\n var _item_context;\n if (!item.img) throw new Error('img is required');\n currentImg.current = item.img;\n await repaintImage();\n const elements = (null == (_item_context = item.context) ? void 0 : _item_context.tree) ? treeToList(item.context.tree) : [];\n const highlightElements = item.highlightElement ? [\n item.highlightElement\n ] : [];\n await insightElementsAnimation(elements, highlightElements, item.searchArea, item.duration, frame);\n if (item.camera) {\n if (!item.insightCameraDuration) throw new Error('insightCameraDuration is required');\n await cameraAnimation(item.camera, item.insightCameraDuration, frame);\n }\n } else if ('clear-insight' === item.type) {\n await fadeOutItem(insightMarkContainer, item.duration, frame);\n insightMarkContainer.removeChildren();\n insightMarkContainer.alpha = 1;\n } else if ('img' === item.type) {\n if (item.img && item.img !== currentImg.current) {\n currentImg.current = item.img;\n await repaintImage();\n }\n if (item.camera) await cameraAnimation(item.camera, item.duration, frame);\n else await sleep(item.duration);\n } else if ('pointer' === item.type) {\n if (!item.img) throw new Error('pointer img is required');\n await updatePointer(item.img);\n } else if ('spinning-pointer' === item.type) {\n const stop = spinningPointer(frame);\n await sleep(item.duration);\n stop();\n }\n }\n if (recorderSessionRef.current) {\n recorderSessionRef.current.stop();\n recorderSessionRef.current = null;\n setIsRecording(false);\n }\n })().catch((e)=>{\n console.error('player error', e);\n }));\n return ()=>{\n null == cancelFn || cancelFn();\n };\n };\n useEffect(()=>{\n Promise.resolve((async ()=>{\n await init();\n if (divContainerRef.current && imageWidth && imageHeight) {\n const aspectRatio = imageWidth / imageHeight;\n divContainerRef.current.style.setProperty('--canvas-aspect-ratio', aspectRatio.toString());\n divContainerRef.current.setAttribute('data-fit-mode', fitMode);\n const playerContainer = divContainerRef.current.closest('.player-container');\n if (playerContainer) playerContainer.setAttribute('data-fit-mode', fitMode);\n }\n triggerReplay();\n })());\n return ()=>{\n try {\n app.destroy(true, {\n children: true,\n texture: true\n });\n } catch (e) {\n console.warn('destroy failed', e);\n }\n };\n }, [\n imageWidth,\n imageHeight,\n fitMode\n ]);\n useEffect(()=>{\n if (replayMark) return play();\n }, [\n replayMark\n ]);\n const [mouseOverStatusIcon, setMouseOverStatusIcon] = useState(false);\n const progressString = Math.round(100 * animationProgress);\n const transitionStyle = 0 === animationProgress ? 'none' : '0.3s';\n const canReplayNow = 1 === animationProgress;\n useEffect(()=>{\n if (canReplayNow) {\n const listener = (event)=>{\n if (' ' === event.key) triggerReplay();\n };\n window.addEventListener('keydown', listener);\n return ()=>{\n window.removeEventListener('keydown', listener);\n };\n }\n }, [\n canReplayNow\n ]);\n let statusIconElement;\n let statusOnClick = ()=>{};\n if (animationProgress < 1) statusIconElement = /*#__PURE__*/ jsx(Spin, {\n indicator: /*#__PURE__*/ jsx(LoadingOutlined, {\n spin: true,\n color: \"#333\"\n }),\n size: \"default\"\n });\n else if (mouseOverStatusIcon) {\n statusIconElement = /*#__PURE__*/ jsx(Spin, {\n indicator: /*#__PURE__*/ jsx(CaretRightOutlined, {\n color: \"#333\"\n }),\n size: \"default\"\n });\n statusOnClick = ()=>triggerReplay();\n } else statusIconElement = /*#__PURE__*/ jsx(Spin, {\n indicator: /*#__PURE__*/ jsx(CaretRightOutlined, {\n color: \"#333\"\n }),\n size: \"default\"\n });\n return /*#__PURE__*/ jsxs(\"div\", {\n className: \"player-container\",\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"canvas-container\",\n ref: divContainerRef\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"player-timeline-wrapper\",\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"player-timeline\",\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"player-timeline-progress\",\n style: {\n width: `${progressString}%`,\n transition: transitionStyle\n }\n })\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"player-tools-wrapper\",\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"player-tools\",\n children: /*#__PURE__*/ jsxs(\"div\", {\n className: \"player-control\",\n children: [\n /*#__PURE__*/ jsxs(\"div\", {\n className: \"status-text\",\n children: [\n /*#__PURE__*/ jsx(\"div\", {\n className: \"title\",\n children: titleText\n }),\n /*#__PURE__*/ jsx(Tooltip, {\n title: subTitleText,\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"subtitle\",\n children: subTitleText\n })\n })\n ]\n }),\n isRecording ? null : /*#__PURE__*/ jsx(\"div\", {\n className: \"status-icon\",\n onMouseEnter: ()=>setMouseOverStatusIcon(true),\n onMouseLeave: ()=>setMouseOverStatusIcon(false),\n onClick: statusOnClick,\n children: statusIconElement\n }),\n (null == props ? void 0 : props.reportFileContent) ? /*#__PURE__*/ jsx(Tooltip, {\n title: \"Download Report\",\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"status-icon\",\n onMouseEnter: ()=>setMouseOverStatusIcon(true),\n onMouseLeave: ()=>setMouseOverStatusIcon(false),\n onClick: ()=>downloadReport(props.reportFileContent),\n children: /*#__PURE__*/ jsx(DownloadOutlined, {\n color: \"#333\"\n })\n })\n }) : null,\n /*#__PURE__*/ jsx(Tooltip, {\n title: isRecording ? 'Generating...' : 'Export Video',\n children: /*#__PURE__*/ jsx(\"div\", {\n className: \"status-icon\",\n onClick: isRecording ? void 0 : handleExport,\n style: {\n opacity: isRecording ? 0.5 : 1,\n cursor: isRecording ? 'not-allowed' : 'pointer'\n },\n children: isRecording ? /*#__PURE__*/ jsx(Spin, {\n size: \"default\",\n percent: progressString\n }) : /*#__PURE__*/ jsx(ExportOutlined, {})\n })\n })\n ]\n })\n })\n })\n ]\n });\n}\nexport { Player };\n","import { jsx, jsxs } from \"react/jsx-runtime\";\nimport { LoadingOutlined } from \"@ant-design/icons\";\nimport { Spin } from \"antd\";\nimport { Player } from \"../player.mjs\";\nimport shiny_text from \"../shiny-text.mjs\";\nimport { emptyResultTip, serverLaunchTip } from \"./playground-constants.mjs\";\nimport \"./index.css\";\nconst PlaygroundResultView = (param)=>{\n let { result, loading, serverValid, serviceMode, replayScriptsInfo, replayCounter, loadingProgressText, verticalMode = false, notReadyMessage, fitMode } = param;\n let resultWrapperClassName = 'result-wrapper';\n if (verticalMode) resultWrapperClassName += ' vertical-mode-result';\n if (replayScriptsInfo && verticalMode) resultWrapperClassName += ' result-wrapper-compact';\n let resultDataToShow = emptyResultTip;\n if (serverValid || 'Server' !== serviceMode) {\n if (loading) resultDataToShow = /*#__PURE__*/ jsxs(\"div\", {\n className: \"loading-container\",\n children: [\n /*#__PURE__*/ jsx(Spin, {\n spinning: loading,\n indicator: /*#__PURE__*/ jsx(LoadingOutlined, {\n spin: true\n })\n }),\n /*#__PURE__*/ jsx(\"div\", {\n className: \"loading-progress-text loading-progress-text-progress\",\n children: /*#__PURE__*/ jsx(shiny_text, {\n text: loadingProgressText,\n speed: 3\n })\n })\n ]\n });\n else if (replayScriptsInfo) resultDataToShow = /*#__PURE__*/ jsx(Player, {\n replayScripts: replayScriptsInfo.scripts,\n imageWidth: replayScriptsInfo.width,\n imageHeight: replayScriptsInfo.height,\n reportFileContent: ('In-Browser-Extension' === serviceMode || 'Server' === serviceMode) && (null == result ? void 0 : result.reportHTML) ? null == result ? void 0 : result.reportHTML : null,\n fitMode: fitMode\n }, replayCounter);\n else if (null == result ? void 0 : result.error) resultDataToShow = /*#__PURE__*/ jsx(\"pre\", {\n children: null == result ? void 0 : result.error\n });\n else if ((null == result ? void 0 : result.result) !== void 0) resultDataToShow = 'string' == typeof (null == result ? void 0 : result.result) ? /*#__PURE__*/ jsx(\"pre\", {\n children: null == result ? void 0 : result.result\n }) : /*#__PURE__*/ jsx(\"pre\", {\n children: JSON.stringify(null == result ? void 0 : result.result, null, 2)\n });\n } else resultDataToShow = serverLaunchTip(notReadyMessage);\n return /*#__PURE__*/ jsx(\"div\", {\n className: resultWrapperClassName,\n style: {\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n flex: '1 1 auto'\n },\n children: resultDataToShow\n });\n};\nexport { PlaygroundResultView };\n","import './index.less';\nimport { MobileOutlined } from '@ant-design/icons';\nimport { useServerValid } from '@midscene/visualizer';\nimport { Button, Divider, Dropdown, message } from 'antd';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { RefObject } from 'react';\nimport type { Socket } from 'socket.io-client';\nimport type { ScrcpyRefMethods } from '../scrcpy-player';\n\n// status dot indicator\nconst onlineStatus = (color: string) => (\n <span\n className=\"status-dot\"\n style={{\n color: color,\n }}\n >\n ●\n </span>\n);\n\nexport interface Device {\n id: string;\n name: string;\n status: string;\n}\n\nexport interface AdbDeviceProps {\n devices: Device[];\n loadingDevices: boolean;\n selectedDeviceId: string | null;\n onDeviceSelect: (deviceId: string) => void;\n socketRef: React.RefObject<Socket | null>;\n scrcpyPlayerRef: RefObject<ScrcpyRefMethods>;\n}\n\nconst AdbDevice: React.FC<AdbDeviceProps> = ({\n devices,\n loadingDevices: _loadingDevices,\n selectedDeviceId,\n onDeviceSelect,\n socketRef,\n scrcpyPlayerRef,\n}) => {\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const lastSelectedDeviceRef = useRef<string | null>(null);\n const [messageApi, contextHolder] = message.useMessage();\n const serverValid = useServerValid(true);\n\n // handle device selection\n const handleDeviceSelect = useCallback(\n (deviceId: string) => {\n if (deviceId === lastSelectedDeviceRef.current) {\n return;\n }\n\n // check socket connection status\n if (!socketRef.current || !socketRef.current.connected) {\n return;\n }\n\n // close dropdown\n setDropdownOpen(false);\n\n // call the parent component's device selection handler\n onDeviceSelect(deviceId);\n\n // update the last selected device id\n lastSelectedDeviceRef.current = deviceId;\n },\n [onDeviceSelect, socketRef],\n );\n\n // disconnect device\n const disconnectDevice = useCallback(() => {\n // call ScrcpyPlayer's disconnectDevice method\n if (scrcpyPlayerRef.current) {\n scrcpyPlayerRef.current.disconnectDevice();\n messageApi.info('Device disconnected');\n }\n }, [scrcpyPlayerRef, messageApi]);\n\n // check if selected device is offline\n const isSelectedDeviceOffline = selectedDeviceId\n ? devices.find((d) => d.id === selectedDeviceId)?.status.toLowerCase() !==\n 'device'\n : false;\n\n // automatically unlink when device goes offline\n useEffect(() => {\n if (isSelectedDeviceOffline && selectedDeviceId) {\n disconnectDevice();\n }\n }, [isSelectedDeviceOffline, selectedDeviceId, disconnectDevice, messageApi]);\n\n return (\n <div className=\"device-header\">\n {contextHolder}\n <div className=\"device-title-container\">\n <h2 className=\"device-title\">Device</h2>\n <Dropdown\n trigger={['click']}\n placement=\"bottomLeft\"\n open={dropdownOpen}\n onOpenChange={setDropdownOpen}\n dropdownRender={() => (\n <div className=\"device-dropdown\">\n <div className=\"dropdown-header\">\n <span className=\"dropdown-title\">Devices list</span>\n </div>\n <div className=\"device-list\">\n {devices.map((device) => (\n <div\n key={device.id}\n onClick={() => {\n if (device.status.toLowerCase() === 'device') {\n handleDeviceSelect(device.id);\n }\n }}\n className={`device-list-item ${\n device.status.toLowerCase() === 'device' &&\n selectedDeviceId === device.id\n ? 'selected'\n : ''\n } ${\n device.status.toLowerCase() !== 'device' ? 'offline' : ''\n }`}\n >\n <div className=\"device-item-content\">\n <div className=\"device-item-icon-container\">\n <MobileOutlined className=\"device-item-icon\" />\n </div>\n <div className=\"device-item-info\">\n <div className=\"device-item-name\">\n {device.name || device.id}\n </div>\n <div className=\"device-item-status\">\n <div className=\"status-badge\">\n {device.status.toLowerCase() === 'device' ? (\n <>\n {onlineStatus('#52c41a')}\n <span className=\"status-text\">Online</span>\n </>\n ) : (\n <>\n {onlineStatus('#f5222d')}\n <span className=\"status-text\">Offline</span>\n </>\n )}\n </div>\n <Divider type=\"vertical\" className=\"status-divider\" />\n <div className=\"device-id-container\">\n Device ID: {device.id}\n </div>\n </div>\n </div>\n {device.status.toLowerCase() === 'device' &&\n selectedDeviceId === device.id && (\n <div className=\"current-device-indicator\">\n Current device\n </div>\n )}\n </div>\n </div>\n ))}\n {devices.length === 0 && (\n <div className=\"device-list-empty\">No devices found</div>\n )}\n </div>\n </div>\n )}\n >\n <Button className=\"device-dropdown-button\">\n <div className=\"device-icon-container\">\n <MobileOutlined className=\"device-icon\" />\n {selectedDeviceId && serverValid && (\n <div className=\"status-indicator\">\n {devices\n .find((d) => d.id === selectedDeviceId)\n ?.status.toLowerCase() === 'device' ? (\n <>{onlineStatus('#52c41a')}</>\n ) : (\n <>{onlineStatus('#f5222d')}</>\n )}\n </div>\n )}\n </div>\n {selectedDeviceId && !isSelectedDeviceOffline && serverValid ? (\n <span className=\"device-name\">\n {devices.find((d) => d.id === selectedDeviceId)?.name ||\n selectedDeviceId}\n </span>\n ) : (\n <span className=\"device-name no-device\">No device</span>\n )}\n <span className=\"dropdown-arrow\">▼</span>\n </Button>\n </Dropdown>\n </div>\n </div>\n );\n};\n\nexport default AdbDevice;\n","import * as React from \"react\";\nconst SvgLinked = props => <svg xmlns=\"http://www.w3.org/2000/svg\" width={16} height={16} fill=\"none\" viewBox=\"0 0 16 16\" {...props}><path fill=\"#000\" fillOpacity={0.25} fillRule=\"evenodd\" d=\"M9.68 2c1.2-1.2 3.2-1.28 4.4-.08s1.12 3.2-.08 4.4l-2.16 2.16c-.24.24-.56.24-.8 0s-.24-.56 0-.8l2.16-2.16c.8-.8.8-2.08.08-2.8s-2-.72-2.8.08L8.32 4.96c-.24.24-.56.24-.8 0s-.24-.56 0-.8zM5.6 13.2l2.16-2.16c.24-.24.56-.24.8 0s.24.56 0 .8L6.4 14c-1.2 1.2-3.12 1.36-4.4.08-1.36-1.28-1.2-3.2.08-4.4l2.16-2.16c.24-.24.56-.24.8 0s.24.56 0 .8l-2.16 2.16c-.8.8-.88 2-.08 2.8s2 .72 2.8-.08m4.64-8.24c.24-.24.64-.24.96 0 .24.24.24.64 0 .96L5.92 11.2c-.24.24-.64.24-.96 0-.24-.24-.24-.64 0-.96z\" clipRule=\"evenodd\" /></svg>;\nexport default SvgLinked;","import * as React from \"react\";\nconst SvgScreenshot = props => <svg xmlns=\"http://www.w3.org/2000/svg\" width={16} height={16} fill=\"none\" viewBox=\"0 0 16 16\" {...props}><g fill=\"#606266\" clipPath=\"url(#screenshot_svg__a)\"><path d=\"m4.883 2.663-.858 2.001h-2.69v8.673h13.341V4.664H11.32l-.859-2zm-1.738.667.858-2.001h7.338l.858 2.001h2.477a1.334 1.334 0 0 1 1.334 1.334v8.673a1.335 1.335 0 0 1-1.334 1.334H1.334A1.334 1.334 0 0 1 0 13.337V4.664A1.334 1.334 0 0 1 1.334 3.33z\" /><path d=\"M8.005 10.001a1.334 1.334 0 1 0 0-2.668 1.334 1.334 0 0 0 0 2.668m0 1.335a2.668 2.668 0 1 1 0-5.337 2.668 2.668 0 0 1 0 5.337m3.336-6.004h.667q.667 0 .667.667 0 .666-.667.667h-.667q-.667 0-.667-.667t.667-.667\" /></g><defs><clipPath id=\"screenshot_svg__a\"><path fill=\"#fff\" d=\"M0 0h16v16H0z\" /></clipPath></defs></svg>;\nexport default SvgScreenshot;","import * as React from \"react\";\nconst SvgUnlink = props => <svg xmlns=\"http://www.w3.org/2000/svg\" width={16} height={16} fill=\"none\" viewBox=\"0 0 16 16\" {...props}><path fill=\"#FF4550\" d=\"M14.08 1.92C12.88.72 10.88.8 9.68 2L7.52 4.16c-.24.24-.24.56 0 .8s.56.24.8 0l2.16-2.16c.8-.8 2.08-.8 2.8-.08s.72 2-.08 2.8l-2.16 2.16c-.24.24-.24.56 0 .8s.56.24.8 0L14 6.32c1.2-1.2 1.28-3.2.08-4.4m-6.32 9.12L5.6 13.2c-.8.8-2 .88-2.8.08s-.72-2 .08-2.8l2.16-2.16c.24-.24.24-.56 0-.8s-.56-.24-.8 0L2.08 9.68C.8 10.88.64 12.8 2 14.08c1.28 1.28 3.2 1.12 4.4-.08l2.16-2.16c.24-.24.24-.56 0-.8s-.56-.24-.8 0M5.92 4.96c-.24-.24-.64-.24-.96 0-.24.24-.24.64 0 .96l5.28 5.28c.24.24.64.24.96 0 .24-.24.24-.64 0-.96z\" /></svg>;\nexport default SvgUnlink;","import { InfoCircleOutlined } from '@ant-design/icons';\nimport { useServerValid } from '@midscene/visualizer';\nimport { ScrcpyVideoCodecId } from '@yume-chan/scrcpy';\nimport { WebCodecsVideoDecoder } from '@yume-chan/scrcpy-decoder-webcodecs';\nimport {\n BitmapVideoFrameRenderer,\n WebGLVideoFrameRenderer,\n} from '@yume-chan/scrcpy-decoder-webcodecs';\nimport {\n Button,\n Card,\n Col,\n Divider,\n Row,\n Spin,\n Tooltip,\n Typography,\n message,\n} from 'antd';\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport type { Socket } from 'socket.io-client';\nimport { io } from 'socket.io-client';\nimport LinkedIcon from '../icons/linked.svg?react';\nimport ScreenshotIcon from '../icons/screenshot.svg?react';\nimport UnlinkIcon from '../icons/unlink.svg?react';\nimport './index.less';\n\nconst { Text } = Typography;\n\ninterface ScrcpyProps {\n serverUrl?: string;\n maxSize?: number;\n autoConnect?: boolean;\n autoReconnect?: boolean;\n reconnectInterval?: number;\n onConnectionStatusChange?: (status: boolean) => void;\n}\n\ninterface VideoMetadata {\n codec?: string;\n width?: number;\n height?: number;\n [key: string]: any;\n}\n\nexport interface ScrcpyRefMethods {\n disconnectDevice: () => void;\n}\n\nexport const ScrcpyPlayer = forwardRef<ScrcpyRefMethods, ScrcpyProps>(\n (\n {\n serverUrl,\n maxSize = 1024,\n autoConnect = true,\n autoReconnect = true,\n reconnectInterval = 5000,\n onConnectionStatusChange,\n },\n ref,\n ) => {\n const [connecting, setConnecting] = useState(false);\n const [connected, setConnected] = useState(false);\n const [screenInfo, setScreenInfo] = useState<{\n width: number;\n height: number;\n } | null>(null);\n const [deviceId, setDeviceId] = useState<string>('');\n\n const socketRef = useRef<Socket | null>(null);\n const videoContainerRef = useRef<HTMLDivElement>(null);\n const videoElementRef = useRef<HTMLCanvasElement | null>(null);\n const decoderRef = useRef<any>(null);\n const reconnectTimerRef = useRef<NodeJS.Timeout | null>(null);\n const metadataTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const serverValid = useServerValid(true);\n // create a safe remove child nodes tool function\n const safeRemoveChildNodes = useCallback((parent: Element | null) => {\n if (!parent) return;\n\n try {\n // use a safer way to clear child nodes\n while (parent.firstChild) {\n try {\n parent.removeChild(parent.firstChild);\n } catch (e) {\n console.warn('Failed to remove child, skipping:', e);\n // if remove failed, set it to null to avoid trying to remove again\n if (parent.firstChild) {\n parent.innerHTML = '';\n break;\n }\n }\n }\n } catch (e) {\n console.error('Error clearing container:', e);\n // last resort - directly reset HTML\n try {\n parent.innerHTML = '';\n } catch (innerErr) {\n console.error('Failed to reset innerHTML:', innerErr);\n }\n }\n }, []);\n\n // update canvas size to fit container\n const updateCanvasSize = useCallback(() => {\n if (!videoElementRef.current || !videoContainerRef.current || !screenInfo)\n return;\n\n const container = videoContainerRef.current;\n const canvas = videoElementRef.current;\n const containerWidth = container.clientWidth;\n const containerHeight = container.clientHeight;\n const { width: originalWidth, height: originalHeight } = screenInfo;\n\n // leave 20px padding on top and bottom\n const paddingVertical = 40; // padding on top and bottom, each 20px\n const availableHeight = containerHeight - paddingVertical;\n\n // calculate the size fit to container, keep the aspect ratio\n const aspectRatio = originalWidth / originalHeight;\n let targetWidth = containerWidth;\n let targetHeight = containerWidth / aspectRatio;\n\n if (targetHeight > availableHeight) {\n targetHeight = availableHeight;\n targetWidth = availableHeight * aspectRatio;\n }\n\n // update canvas properties and styles\n canvas.width = originalWidth;\n canvas.height = originalHeight;\n canvas.style.width = `${targetWidth}px`;\n canvas.style.height = `${targetHeight}px`;\n canvas.style.marginTop = '20px';\n canvas.style.marginBottom = '20px';\n }, [screenInfo]);\n\n // listen window size change\n useEffect(() => {\n const handleResize = () => {\n updateCanvasSize();\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [updateCanvasSize]);\n\n // when screenInfo updates, adjust the size\n useEffect(() => {\n updateCanvasSize();\n }, [screenInfo, updateCanvasSize]);\n\n // create and initialize renderer\n const createVideoFrameRenderer = async () => {\n // use WebGL renderer first, if not supported, fallback to Bitmap renderer\n if (WebGLVideoFrameRenderer.isSupported) {\n const renderer = new WebGLVideoFrameRenderer();\n return {\n renderer,\n element: renderer.canvas as HTMLCanvasElement,\n };\n }\n\n const renderer = new BitmapVideoFrameRenderer();\n return {\n renderer,\n element: renderer.canvas as HTMLCanvasElement,\n };\n };\n\n // create and initialize decoder\n const createDecoder = async (codecId: ScrcpyVideoCodecId) => {\n // check if WebCodecs API is supported\n if (!WebCodecsVideoDecoder.isSupported) {\n throw new Error(\n 'Current browser does not support WebCodecs API, please use the latest version of Chrome/Edge browser',\n );\n }\n\n // create renderer\n const { renderer, element } = await createVideoFrameRenderer();\n videoElementRef.current = element;\n\n // add video element to page\n if (videoContainerRef.current) {\n const canvasWrapper =\n videoContainerRef.current.querySelector('.canvas-wrapper');\n if (canvasWrapper) {\n // safely clear container\n safeRemoveChildNodes(canvasWrapper);\n canvasWrapper.appendChild(videoElementRef.current);\n }\n }\n\n // create decoder\n return new WebCodecsVideoDecoder({\n codec: codecId,\n renderer: renderer,\n });\n };\n\n // setup video stream processing\n const setupVideoStream = (_metadata: VideoMetadata) => {\n // for tracking if the configuration frame has been received\n let configurationPacketSent = false;\n let pendingDataPackets: any[] = [];\n\n // create transform stream to convert data to Uint8Array\n const transformStream = new TransformStream({\n transform(chunk: any, controller: any) {\n // convert array to Uint8Array\n const packet = {\n type: chunk.type,\n data: new Uint8Array(chunk.data),\n timestamp: chunk.timestamp,\n };\n\n // for configuration frame, we should handle it first\n if (packet.type === 'configuration') {\n controller.enqueue(packet);\n configurationPacketSent = true;\n\n // after sending the configuration frame, send all pending data frames\n if (pendingDataPackets.length > 0) {\n pendingDataPackets.forEach((p) => controller.enqueue(p));\n pendingDataPackets = [];\n }\n } else if (packet.type === 'data') {\n // if the configuration frame has not been received, cache the data frame\n if (!configurationPacketSent) {\n pendingDataPackets.push(packet);\n } else {\n controller.enqueue(packet);\n }\n } else {\n // other types of frames are passed directly\n controller.enqueue(packet);\n }\n },\n });\n\n // create a readable stream to receive video data from the server\n const videoStream = new ReadableStream({\n start(controller) {\n // for tracking if the stream has been closed\n let streamClosed = false;\n\n // receive video data\n const videoDataHandler = (data: any) => {\n // check if the stream has been closed\n if (streamClosed) return;\n\n try {\n controller.enqueue(data);\n } catch (error) {\n console.error(\n 'error occurred while enqueuing video data:',\n error,\n );\n // if an error occurs, mark the stream as closed and clean up\n streamClosed = true;\n cleanupHandlers();\n }\n };\n\n // handle error\n const errorHandler = (error: any) => {\n console.error('stream error:', error);\n if (!streamClosed) {\n controller.error(new Error(error.message));\n streamClosed = true;\n cleanupHandlers();\n }\n };\n\n // handle disconnection\n const disconnectHandler = () => {\n if (!streamClosed) {\n controller.close();\n streamClosed = true;\n cleanupHandlers();\n }\n };\n\n // clean up all event handlers\n const cleanupHandlers = () => {\n if (socketRef.current) {\n socketRef.current.off('video-data', videoDataHandler);\n socketRef.current.off('error', errorHandler);\n socketRef.current.off('disconnect', disconnectHandler);\n }\n };\n\n // register event handlers\n if (socketRef.current) {\n socketRef.current.on('video-data', videoDataHandler);\n socketRef.current.on('error', errorHandler);\n socketRef.current.on('disconnect', disconnectHandler);\n }\n\n // clean up when the stream is cancelled\n return () => {\n streamClosed = true;\n cleanupHandlers();\n };\n },\n });\n\n // handle video stream\n return videoStream.pipeThrough(transformStream);\n };\n\n // screenshot feature\n const takeScreenshot = async () => {\n if (!decoderRef.current) return;\n\n try {\n const blob = await decoderRef.current.snapshot();\n if (blob) {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `screenshot_${new Date().toISOString().replace(/:/g, '-')}.png`;\n a.click();\n URL.revokeObjectURL(url);\n }\n } catch (error) {\n console.error('screenshot failed:', error);\n alert('screenshot failed');\n }\n };\n\n // disconnect device\n const disconnectDevice = useCallback(() => {\n // dispose decoder resources\n if (decoderRef.current) {\n try {\n decoderRef.current.dispose();\n decoderRef.current = null;\n } catch (error) {\n console.error('Error disposing decoder:', error);\n }\n }\n\n // clear video container\n if (videoContainerRef.current) {\n const canvasWrapper =\n videoContainerRef.current.querySelector('.canvas-wrapper');\n safeRemoveChildNodes(canvasWrapper);\n }\n\n // disconnect socket\n if (socketRef.current) {\n socketRef.current.disconnect();\n socketRef.current = null;\n }\n\n // clean up timers\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current);\n reconnectTimerRef.current = null;\n }\n\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n\n // reset status\n setConnected(false);\n setConnecting(false);\n setScreenInfo(null);\n }, [safeRemoveChildNodes]);\n\n // Expose methods to parent component\n useImperativeHandle(\n ref,\n () => ({\n disconnectDevice,\n }),\n [disconnectDevice],\n );\n\n // connect device\n const connectDevice = useCallback(async () => {\n try {\n // always clean up previous resources, ensure clean state\n disconnectDevice();\n\n // ensure status reset\n setConnected(false);\n setConnecting(true);\n setScreenInfo(null);\n\n // short delay to ensure resources are cleaned\n await new Promise((resolve) => setTimeout(resolve, 150));\n\n // ensure the component is still mounted and has a valid server URL\n if (!serverUrl) {\n console.error('Cannot connect: missing server URL');\n setConnecting(false);\n onConnectionStatusChange?.(false);\n return;\n }\n\n // setup metadata timeout check\n const setupMetadataTimeout = () => {\n // clear previous timeout\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n\n // setup new timeout check\n metadataTimeoutRef.current = setTimeout(() => {\n if (socketRef.current?.connected) {\n try {\n socketRef.current.emit('connect-device', {\n maxSize,\n });\n\n // setup metadata timeout check again\n setupMetadataTimeout();\n } catch (err) {\n console.error('Failed to request connection:', err);\n onConnectionStatusChange?.(false); // notify connection request failed\n message.error(\n 'connection request failed, please refresh the page',\n );\n }\n } else {\n onConnectionStatusChange?.(false); // notify connection status change\n\n try {\n if (socketRef.current) {\n setTimeout(() => {\n // reconnect after a short delay\n if (socketRef.current) {\n socketRef.current.connect();\n }\n }, 500);\n }\n } catch (err) {\n console.error('Failed to reconnect:', err);\n message.error('reconnection failed, please refresh the page');\n }\n }\n }, 5000);\n };\n\n // connect to server\n if (!socketRef.current) {\n try {\n socketRef.current = io(serverUrl, {\n withCredentials: true,\n reconnection: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n timeout: 10000,\n });\n\n // notify parent component after connection is successful\n socketRef.current.on('connect', () => {\n onConnectionStatusChange?.(true);\n\n // get device id from socket\n if (socketRef.current?.id) {\n setDeviceId(socketRef.current.id);\n }\n\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current);\n reconnectTimerRef.current = null;\n }\n\n socketRef.current?.emit('connect-device', {\n maxSize,\n });\n\n // setup metadata timeout check\n setupMetadataTimeout();\n });\n\n // handle video metadata\n socketRef.current.on(\n 'video-metadata',\n async (metadata: VideoMetadata) => {\n try {\n // clear metadata timeout\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n\n // if there is already a decoder, clean it first\n if (decoderRef.current) {\n try {\n decoderRef.current.dispose();\n decoderRef.current = null;\n } catch (error) {\n console.error('Error disposing old decoder:', error);\n }\n }\n\n // clean video container\n if (videoContainerRef.current) {\n const canvasWrapper =\n videoContainerRef.current.querySelector(\n '.canvas-wrapper',\n );\n safeRemoveChildNodes(canvasWrapper);\n }\n\n // ensure the metadata object exists, and set the default codec\n // convert string to ScrcpyVideoCodecId enum\n const codecId = metadata?.codec\n ? (metadata.codec as unknown as ScrcpyVideoCodecId)\n : ScrcpyVideoCodecId.H264;\n\n // create decoder\n decoderRef.current = await createDecoder(codecId);\n\n // ensure the decoder is created successfully\n if (!decoderRef.current) {\n throw new Error('Failed to create decoder');\n }\n\n // listen to size change event\n decoderRef.current.sizeChanged(\n ({ width, height }: { width: number; height: number }) => {\n setScreenInfo({ width, height });\n },\n );\n\n // setup video stream processing\n const videoStream = setupVideoStream(metadata);\n\n // pass the video stream to the decoder\n videoStream\n .pipeTo(decoderRef.current.writable)\n .catch((error: Error) => {\n console.error('video stream processing error:', error);\n onConnectionStatusChange?.(false);\n });\n\n // update UI status\n setConnected(true);\n setConnecting(false);\n // video metadata received successfully, device connected\n onConnectionStatusChange?.(true);\n } catch (error: any) {\n console.error('Failed to initialize decoder:', error);\n setConnecting(false);\n onConnectionStatusChange?.(false);\n }\n },\n );\n\n // handle error\n socketRef.current.on('error', (error: Error) => {\n console.error('server error:', error);\n message.error('server error');\n setConnecting(false);\n onConnectionStatusChange?.(false);\n\n // clear metadata timeout\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n });\n\n // handle disconnection event\n socketRef.current.on('disconnect', () => {\n setConnected(false);\n onConnectionStatusChange?.(false);\n\n // clear metadata timeout\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n\n // clean up video container\n if (decoderRef.current) {\n decoderRef.current.dispose();\n decoderRef.current = null;\n }\n\n if (videoContainerRef.current) {\n // safely clear container\n safeRemoveChildNodes(\n videoContainerRef.current.querySelector('.canvas-wrapper'),\n );\n }\n\n if (autoReconnect && !reconnectTimerRef.current) {\n reconnectTimerRef.current = setTimeout(() => {\n reconnectTimerRef.current = null;\n connectDevice();\n }, reconnectInterval);\n }\n });\n } catch (error: any) {\n console.error('Failed to create socket connection:', error);\n setConnecting(false);\n onConnectionStatusChange?.(false);\n\n if (autoReconnect && !reconnectTimerRef.current) {\n reconnectTimerRef.current = setTimeout(() => {\n reconnectTimerRef.current = null;\n connectDevice();\n }, reconnectInterval);\n }\n }\n } else {\n if (!socketRef.current.connected) {\n socketRef.current.connect();\n } else {\n socketRef.current.emit('connect-device', {\n maxSize,\n });\n\n // setup metadata timeout check\n setupMetadataTimeout();\n }\n }\n } catch (error: any) {\n setConnecting(false);\n onConnectionStatusChange?.(false);\n console.error(`Failed to connect: ${error.message}`);\n message.error('connection failed');\n\n if (autoReconnect && !reconnectTimerRef.current) {\n reconnectTimerRef.current = setTimeout(() => {\n reconnectTimerRef.current = null;\n connectDevice();\n }, reconnectInterval);\n }\n }\n }, [\n serverUrl,\n maxSize,\n autoReconnect,\n reconnectInterval,\n onConnectionStatusChange,\n disconnectDevice,\n ]);\n\n // detect autoConnect change, connect device when autoConnect is true\n useEffect(() => {\n if (autoConnect && !connected && !connecting) {\n // only trigger connection when not connected and not connecting\n const timer = setTimeout(() => {\n connectDevice();\n }, 300);\n\n return () => clearTimeout(timer);\n }\n }, [autoConnect, connected, connecting, connectDevice]);\n\n // resource cleanup useEffect\n useEffect(() => {\n // return cleanup function, called when component unmounts\n return () => {\n onConnectionStatusChange?.(false);\n\n // dispose decoder\n if (decoderRef.current) {\n try {\n decoderRef.current.dispose();\n decoderRef.current = null;\n } catch (error) {\n console.error('Error disposing decoder during unmount:', error);\n }\n }\n\n // clean video container\n if (videoContainerRef.current) {\n try {\n const canvasWrapper =\n videoContainerRef.current.querySelector('.canvas-wrapper');\n if (canvasWrapper) {\n // safely clear content instead of removing node\n canvasWrapper.innerHTML = '';\n }\n } catch (error) {\n console.error(\n 'Error clearing canvas wrapper during unmount:',\n error,\n );\n }\n }\n\n // disconnect socket connection\n if (socketRef.current) {\n socketRef.current.disconnect();\n socketRef.current = null;\n }\n\n // clean up all timers\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current);\n reconnectTimerRef.current = null;\n }\n\n if (metadataTimeoutRef.current) {\n clearTimeout(metadataTimeoutRef.current);\n metadataTimeoutRef.current = null;\n }\n };\n }, [onConnectionStatusChange]);\n\n return (\n <div className=\"scrcpy-container\">\n <Card>\n {connected && (\n <div className=\"header-bar\">\n <div className=\"header-left\">\n <Text style={{ fontWeight: 600, fontSize: 12 }}>\n Screen Projection\n </Text>\n <Tooltip\n placement=\"bottom\"\n title={`Device ID: ${deviceId || 'Unknown'}`}\n >\n <InfoCircleOutlined />\n </Tooltip>\n </div>\n <div className=\"screen-info\">\n <Text type=\"secondary\">\n size : {screenInfo?.width}×{screenInfo?.height}\n </Text>\n </div>\n <div className=\"header-right\">\n <Tooltip placement=\"bottom\" title=\"Screenshot\">\n <Button icon={<ScreenshotIcon />} onClick={takeScreenshot} />\n </Tooltip>\n <Divider\n type=\"vertical\"\n style={{\n margin: '0 16px',\n }}\n />\n <Tooltip placement=\"bottom\" title=\"Connect Device\">\n <Button\n disabled={connected}\n style={{\n backgroundColor: '#fff',\n }}\n icon={<LinkedIcon />}\n onClick={connectDevice}\n />\n </Tooltip>\n {connected && (\n <>\n <Divider\n type=\"vertical\"\n style={{\n margin: '0 16px',\n }}\n />\n <Tooltip title=\"Disconnect Device\">\n <Button\n icon={<UnlinkIcon />}\n onClick={disconnectDevice}\n />\n </Tooltip>\n </>\n )}\n </div>\n </div>\n )}\n <Row gutter={[16, 16]}>\n <Col span={24}>\n <div className=\"video-section\">\n <div ref={videoContainerRef} className=\"video-container\">\n <div className=\"canvas-wrapper\" />\n {!connected && serverValid && (\n <div className=\"empty-state\">\n <div className=\"empty-state-icon\">📱</div>\n <div className=\"empty-state-text\">\n {connecting\n ? 'Connecting to device...'\n : 'No device connected'}\n </div>\n {!connecting && (\n <Button\n type=\"primary\"\n onClick={() => {\n connectDevice();\n }}\n >\n Connect now\n </Button>\n )}\n {connecting && (\n <div className=\"loading-spinner\">\n <Spin size=\"large\" />\n </div>\n )}\n </div>\n )}\n {!serverValid && (\n <span>Please launch playground server!</span>\n )}\n </div>\n </div>\n </Col>\n </Row>\n </Card>\n </div>\n );\n },\n);\n\nexport default ScrcpyPlayer;\n","import './App.less';\nimport { SCRCPY_SERVER_PORT } from '@midscene/shared/constants';\nimport { overrideAIConfig } from '@midscene/shared/env';\nimport {\n EnvConfig,\n Logo,\n type PlaygroundResult,\n PlaygroundResultView,\n PromptInput,\n type ReplayScriptsInfo,\n allScriptsFromDump,\n cancelTask,\n getTaskProgress,\n globalThemeConfig,\n overrideServerConfig,\n requestPlaygroundServer,\n useEnvConfig,\n useServerValid,\n} from '@midscene/visualizer';\nimport { Col, ConfigProvider, Form, Layout, Row, message } from 'antd';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { type Socket, io } from 'socket.io-client';\nimport AdbDevice from './adb-device';\nimport ScrcpyPlayer, { type ScrcpyRefMethods } from './scrcpy-player';\n\nimport './adb-device/index.less';\n\nconst { Content } = Layout;\nconst SERVER_URL = `http://localhost:${SCRCPY_SERVER_PORT}`;\n\nexport default function App() {\n const [form] = Form.useForm();\n const selectedType = Form.useWatch('type', form);\n const [loading, setLoading] = useState(false);\n const [selectedDeviceId, setSelectedDeviceId] = useState<string | null>(null);\n const [connectToDevice, setConnectToDevice] = useState(false);\n const [devices, setDevices] = useState<\n { id: string; name: string; status: string }[]\n >([]);\n const [loadingDevices, setLoadingDevices] = useState(true);\n const lastSelectedDeviceRef = useRef<string | null>(null);\n const [messageApi, contextHolder] = message.useMessage();\n const [connectionReady, setConnectionReady] = useState(false);\n const [result, setResult] = useState<PlaygroundResult | null>({\n result: undefined,\n dump: null,\n reportHTML: null,\n error: null,\n });\n const [replayCounter, setReplayCounter] = useState(0);\n const [replayScriptsInfo, setReplayScriptsInfo] =\n useState<ReplayScriptsInfo | null>(null);\n const { config, deepThink } = useEnvConfig();\n const [loadingProgressText, setLoadingProgressText] = useState('');\n const currentRequestIdRef = useRef<string | null>(null);\n const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const configAlreadySet = Object.keys(config || {}).length >= 1;\n const serverValid = useServerValid(true);\n\n // Socket connection and device management\n const socketRef = useRef<Socket | null>(null);\n // Add a ref to ScrcpyPlayer\n const scrcpyPlayerRef = useRef<ScrcpyRefMethods>(null);\n\n // clear the polling interval\n const clearPollingInterval = useCallback(() => {\n if (pollIntervalRef.current) {\n clearInterval(pollIntervalRef.current);\n pollIntervalRef.current = null;\n }\n }, []);\n\n // connect to device server\n useEffect(() => {\n const socket = io(SERVER_URL, {\n withCredentials: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n timeout: 5000,\n });\n\n socket.on('connect', () => {\n socket.emit('get-devices');\n });\n\n socket.on('disconnect', (_reason: string) => {\n setLoadingDevices(true);\n });\n\n socket.on(\n 'devices-list',\n (data: {\n devices: { id: string; name: string; status: string }[];\n currentDeviceId: string | null;\n }) => {\n setDevices(data.devices);\n if (data.currentDeviceId) {\n setSelectedDeviceId(data.currentDeviceId);\n\n if (data.devices.length === 1) {\n handleDeviceSelect(data.devices[0].id, true);\n }\n }\n setLoadingDevices(false);\n },\n );\n\n socket.on('global-device-switched', (data: { deviceId: string }) => {\n setSelectedDeviceId(data.deviceId);\n });\n\n socket.on('connect_error', (error: Error) => {\n console.error('Socket.IO connection error:', error);\n messageApi.error(\n 'Waiting for device server connection, please try again later',\n );\n setLoadingDevices(false);\n });\n\n socket.on('error', (error: Error) => {\n console.error('Socket.IO error:', error);\n messageApi.error(\n `Error occurred while communicating with the server: ${error.message || 'Unknown error'}`,\n );\n });\n\n socketRef.current = socket;\n\n // request device list periodically\n const timer = setTimeout(() => {\n if (socket.connected) {\n socket.emit('get-devices');\n }\n }, 2000);\n\n return () => {\n clearTimeout(timer);\n socket.disconnect();\n };\n }, [messageApi]);\n\n // switch device\n const handleDeviceSelect = useCallback(\n (deviceId: string, silent = false) => {\n if (deviceId === lastSelectedDeviceRef.current) {\n return;\n }\n\n if (!socketRef.current || !socketRef.current.connected) {\n messageApi.warning(\n 'Waiting for device server connection, please try again later',\n );\n return;\n }\n\n // disconnect current connection and reset related status\n setConnectToDevice(false);\n setConnectionReady(false);\n\n // clean current session status\n setResult(null);\n setReplayScriptsInfo(null);\n setLoading(false);\n clearPollingInterval();\n\n // use a short delay to ensure resources are cleaned\n setTimeout(() => {\n // then set the new device id\n setSelectedDeviceId(deviceId);\n lastSelectedDeviceRef.current = deviceId;\n\n setLoadingDevices(true);\n if (socketRef.current) {\n socketRef.current.emit('switch-device', deviceId);\n\n const timeoutId = setTimeout(() => {\n setLoadingDevices(false);\n messageApi.error('Device switch timeout, please try again');\n }, 10000);\n\n socketRef.current.once('device-switched', () => {\n clearTimeout(timeoutId);\n setLoadingDevices(false);\n\n // after device switched, trigger new device connection\n setTimeout(() => {\n setConnectToDevice(true);\n if (!silent) {\n messageApi.success(`Device selected: ${deviceId}`);\n }\n }, 500); // add delay to ensure enough time for switch\n });\n\n socketRef.current.once('error', (error: Error) => {\n clearTimeout(timeoutId);\n setLoadingDevices(false);\n messageApi.error(`Device switch failed: ${error.message}`);\n });\n } else {\n setLoadingDevices(false);\n messageApi.error('Socket connection lost, please refresh the page');\n }\n }, 500); // add delay to ensure enough time for switch\n },\n [messageApi, clearPollingInterval],\n );\n\n // start polling task progress\n const startPollingProgress = useCallback(\n (requestId: string) => {\n clearPollingInterval();\n\n // set polling interval to 500ms\n pollIntervalRef.current = setInterval(async () => {\n try {\n const data = await getTaskProgress(requestId);\n\n if (data.tip) {\n setLoadingProgressText(data.tip);\n }\n } catch (error) {\n console.error('Failed to poll task progress:', error);\n }\n }, 500);\n },\n [clearPollingInterval],\n );\n\n // clean up the polling when the component unmounts\n useEffect(() => {\n return () => {\n clearPollingInterval();\n };\n }, [clearPollingInterval]);\n\n // listen to the connection status change\n const handleConnectionStatusChange = useCallback(\n (status: boolean) => {\n setConnectionReady(status);\n\n // if the connection is ready and there is a selected device but not connected, try to connect\n if (status && selectedDeviceId && !connectToDevice) {\n setTimeout(() => {\n setConnectToDevice(true);\n }, 100);\n }\n },\n [selectedDeviceId],\n );\n\n // reset the connection flag\n useEffect(() => {\n if (connectToDevice) {\n // reset the connection flag, so that it can be triggered again\n const timer = setTimeout(() => {\n // only reset connectToDevice when the device is not switched\n // this ensures that the connection status is not reset during device switch\n if (selectedDeviceId === lastSelectedDeviceRef.current) {\n setConnectToDevice(false);\n }\n }, 800); // add delay to ensure enough time for connection\n\n return () => clearTimeout(timer);\n }\n }, [connectToDevice, selectedDeviceId]);\n\n // Override AI configuration\n useEffect(() => {\n overrideAIConfig(config);\n overrideServerConfig(config);\n }, [config]);\n\n // handle run button click\n const handleRun = useCallback(async () => {\n if (!selectedDeviceId) {\n messageApi.warning('Please select a device first');\n return;\n }\n\n if (!connectionReady) {\n messageApi.warning(\n 'Waiting for connection establishment, please try again later',\n );\n return;\n }\n\n setLoading(true);\n setResult(null);\n setReplayScriptsInfo(null);\n setLoadingProgressText('');\n\n const { type, prompt } = form.getFieldsValue();\n\n const thisRunningId = Date.now().toString();\n\n currentRequestIdRef.current = thisRunningId;\n\n // start polling progress immediately\n startPollingProgress(thisRunningId);\n\n try {\n const res = await requestPlaygroundServer(\n selectedDeviceId,\n type,\n prompt,\n {\n requestId: thisRunningId,\n deepThink,\n },\n );\n\n // stop polling\n clearPollingInterval();\n\n setResult(res);\n setLoading(false);\n\n if (!res) {\n throw new Error('server returned empty response');\n }\n\n // handle the special case of aiAction type, extract script information\n if (res?.dump && !['aiQuery', 'aiAssert'].includes(type)) {\n const info = allScriptsFromDump(res.dump);\n setReplayScriptsInfo(info);\n setReplayCounter((c) => c + 1);\n } else {\n setReplayScriptsInfo(null);\n }\n messageApi.success('Command executed');\n } catch (error) {\n clearPollingInterval();\n setLoading(false);\n console.error('execute command error:', error);\n messageApi.error(\n `Command execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n }, [\n selectedDeviceId,\n messageApi,\n connectionReady,\n form,\n startPollingProgress,\n clearPollingInterval,\n deepThink,\n ]);\n\n const resetResult = () => {\n setResult(null);\n setReplayScriptsInfo(null);\n setLoading(false);\n };\n\n // handle stop button click\n const handleStop = useCallback(async () => {\n clearPollingInterval();\n setLoading(false);\n resetResult();\n if (currentRequestIdRef.current) {\n await cancelTask(currentRequestIdRef.current);\n }\n messageApi.info('Operation stopped');\n }, [messageApi, clearPollingInterval]);\n\n return (\n <ConfigProvider theme={globalThemeConfig()}>\n {contextHolder}\n <Layout className=\"app-container playground-container vertical-mode\">\n <Content className=\"app-content\">\n <div className=\"app-grid-layout\">\n <Row className=\"app-grid-layout\">\n {/* left panel: PromptInput */}\n <Col className=\"app-panel left-panel\">\n <div className=\"panel-content left-panel-content\">\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '10px',\n }}\n >\n <Logo />\n <EnvConfig />\n </div>\n <h2>Command input</h2>\n <Form form={form} className=\"command-form\">\n <div className=\"form-content\">\n <div className=\"command-input-wrapper\">\n <PromptInput\n runButtonEnabled={\n !!selectedDeviceId && configAlreadySet\n }\n form={form}\n serviceMode=\"Server\"\n selectedType={selectedType}\n dryMode={false}\n stoppable={loading}\n loading={loading}\n onRun={handleRun}\n onStop={handleStop}\n />\n </div>\n <div\n className=\"result-container\"\n style={\n result\n ? {}\n : {\n border: '1px solid #0000001f',\n borderRadius: '8px',\n }\n }\n >\n <PlaygroundResultView\n result={result}\n loading={loading}\n serverValid={serverValid}\n serviceMode=\"Server\"\n replayScriptsInfo={replayScriptsInfo}\n replayCounter={replayCounter}\n loadingProgressText={loadingProgressText}\n verticalMode={false}\n notReadyMessage={\n <span>\n Don&apos;t worry, just one more step to launch the\n playground server.\n <br />\n <strong>\n npx --yes @midscene/android-playground\n </strong>\n </span>\n }\n />\n </div>\n </div>\n </Form>\n </div>\n </Col>\n\n {/* right panel: ScrcpyPlayer */}\n <Col className=\"app-panel right-panel\">\n <div className=\"panel-content right-panel-content\">\n <AdbDevice\n devices={devices}\n loadingDevices={loadingDevices}\n selectedDeviceId={selectedDeviceId}\n onDeviceSelect={handleDeviceSelect}\n socketRef={socketRef}\n scrcpyPlayerRef={scrcpyPlayerRef}\n />\n <ScrcpyPlayer\n ref={scrcpyPlayerRef}\n serverUrl={SERVER_URL}\n autoConnect={connectToDevice}\n onConnectionStatusChange={handleConnectionStatusChange}\n />\n </div>\n </Col>\n </Row>\n </div>\n </Content>\n </Layout>\n </ConfigProvider>\n );\n}\n","import ReactDOM from 'react-dom/client';\nimport App from './App';\n\nconst rootEl = document.getElementById('root');\nif (rootEl) {\n const root = ReactDOM.createRoot(rootEl);\n root.render(<App />);\n}\n","// 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","var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);\nvar leafPrototypes;\n// create a fake namespace object\n// mode & 1: value is a module id, require it\n// mode & 2: merge all properties of value into the ns\n// mode & 4: return value when already ns object\n// mode & 16: return value when it's Promise-like\n// mode & 8|1: behave like require\n__webpack_require__.t = function(value, mode) {\n\tif(mode & 1) value = this(value);\n\tif(mode & 8) return value;\n\tif(typeof value === 'object' && value) {\n\t\tif((mode & 4) && value.__esModule) return value;\n\t\tif((mode & 16) && typeof value.then === 'function') return value;\n\t}\n\tvar ns = Object.create(null);\n __webpack_require__.r(ns);\n\tvar def = {};\n\tleafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];\n\tfor(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {\n\t\tObject.getOwnPropertyNames(current).forEach((key) => { def[key] = () => (value[key]) });\n\t}\n\tdef['default'] = () => (value);\n\t__webpack_require__.d(ns, def);\n\treturn ns;\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__.f = {};\n// This file contains only the entry chunk.\n// The chunk loading function for additional chunks\n__webpack_require__.e = (chunkId) => {\n\treturn Promise.all(\n\t\tObject.keys(__webpack_require__.f).reduce((promises, key) => {\n\t\t\t__webpack_require__.f[key](chunkId, promises);\n\t\t\treturn promises;\n\t\t}, [])\n\t);\n};","// This function allow to reference chunks\n__webpack_require__.u = (chunkId) => {\n // return url for filenames not based on template\n \n // return url for filenames based on template\n return \"static/js/async/\" + chunkId + \".\" + {\"166\": \"834644b5\",\"173\": \"f2381e64\",\"212\": \"850ade70\",\"290\": \"06d1055a\",\"329\": \"261bc4a1\",\"364\": \"d88c3cff\",\"544\": \"18ac9afb\",\"582\": \"8f4b5264\",\"624\": \"8a1fe2e8\",\"644\": \"910ce3d0\",\"702\": \"1f38a17e\",\"975\": \"693266d2\",\"983\": \"b98b40af\",}[chunkId] + \".js\"\n}","// This function allow to reference chunks\n__webpack_require__.miniCssF = (chunkId) => {\n // return url for filenames not based on template\n \n // return url for filenames based on template\n return \"\" + chunkId + \".css\"\n}","__webpack_require__.h = () => (\"cc3ed5983b0709ce\")","__webpack_require__.g = (() => {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","var inProgress = {};\n\nvar dataWebpackPrefix = \"android-playground:\";\n// loadScript function to load a script via script tag\n__webpack_require__.l = function (url, done, key, chunkId) {\n\tif (inProgress[url]) {\n\t\tinProgress[url].push(done);\n\t\treturn;\n\t}\n\tvar script, needAttach;\n\tif (key !== undefined) {\n\t\tvar scripts = document.getElementsByTagName(\"script\");\n\t\tfor (var i = 0; i < scripts.length; i++) {\n\t\t\tvar s = scripts[i];\n\t\t\tif (s.getAttribute(\"src\") == url || s.getAttribute(\"data-webpack\") == dataWebpackPrefix + key) {\n\t\t\t\tscript = s;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tif (!script) {\n\t\tneedAttach = true;\n\t\t\n script = document.createElement('script');\n \n\t\tscript.charset = 'utf-8';\n\t\tscript.timeout = 120;\n\t\tif (__webpack_require__.nc) {\n\t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n\t\t}\n\t\tscript.setAttribute(\"data-webpack\", dataWebpackPrefix + key);\n\t\t\n\t\tscript.src = url;\n\t\t\n \n\t}\n\tinProgress[url] = [done];\n\tvar onScriptComplete = function (prev, event) {\n\t\tscript.onerror = script.onload = null;\n\t\tclearTimeout(timeout);\n\t\tvar doneFns = inProgress[url];\n\t\tdelete inProgress[url];\n\t\tscript.parentNode && script.parentNode.removeChild(script);\n\t\tdoneFns &&\n\t\t\tdoneFns.forEach(function (fn) {\n\t\t\t\treturn fn(event);\n\t\t\t});\n\t\tif (prev) return prev(event);\n\t};\n\tvar timeout = setTimeout(\n\t\tonScriptComplete.bind(null, undefined, {\n\t\t\ttype: 'timeout',\n\t\t\ttarget: script\n\t\t}),\n\t\t120000\n\t);\n\tscript.onerror = onScriptComplete.bind(null, script.onerror);\n\tscript.onload = onScriptComplete.bind(null, script.onload);\n\tneedAttach && document.head.appendChild(script);\n};\n","// 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};","__webpack_require__.nmd = (module) => {\n module.paths = [];\n if (!module.children) module.children = [];\n return module;\n};","var deferred = [];\n__webpack_require__.O = (result, chunkIds, fn, priority) => {\n\tif (chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor (var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--)\n\t\t\tdeferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar [chunkIds, fn, priority] = deferred[i];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif (\n\t\t\t\t(priority & (1 === 0) || notFulfilled >= priority) &&\n\t\t\t\tObject.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))\n\t\t\t) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif (priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif (fulfilled) {\n\t\t\tdeferred.splice(i--, 1);\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};\n","__webpack_require__.p = \"/\";","__webpack_require__.rv = () => (\"1.3.12\")","__webpack_require__.b = document.baseURI || self.location.href;\n\n // object to store loaded and loading chunks\n // undefined = chunk not loaded, null = chunk preloaded/prefetched\n // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\n var installedChunks = {\"980\": 0,};\n \n __webpack_require__.f.j = function (chunkId, promises) {\n // JSONP chunk loading for javascript\nvar installedChunkData = __webpack_require__.o(installedChunks, chunkId)\n\t? installedChunks[chunkId]\n\t: undefined;\nif (installedChunkData !== 0) {\n\t// 0 means \"already installed\".\n\n\t// a Promise means \"currently loading\".\n\tif (installedChunkData) {\n\t\tpromises.push(installedChunkData[2]);\n\t} else {\n\t\tif (true) {\n\t\t\t// setup Promise in chunk cache\n\t\t\tvar promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));\n\t\t\tpromises.push((installedChunkData[2] = promise));\n\n\t\t\t// start chunk loading\n\t\t\tvar url = __webpack_require__.p + __webpack_require__.u(chunkId);\n\t\t\t// create error before stack unwound to get useful stacktrace later\n\t\t\tvar error = new Error();\n\t\t\tvar loadingEnded = function (event) {\n\t\t\t\tif (__webpack_require__.o(installedChunks, chunkId)) {\n\t\t\t\t\tinstalledChunkData = installedChunks[chunkId];\n\t\t\t\t\tif (installedChunkData !== 0) installedChunks[chunkId] = undefined;\n\t\t\t\t\tif (installedChunkData) {\n\t\t\t\t\t\tvar errorType =\n\t\t\t\t\t\t\tevent && (event.type === 'load' ? 'missing' : event.type);\n\t\t\t\t\t\tvar realSrc = event && event.target && event.target.src;\n\t\t\t\t\t\terror.message =\n\t\t\t\t\t\t\t'Loading chunk ' +\n\t\t\t\t\t\t\tchunkId +\n\t\t\t\t\t\t\t' failed.\\n(' +\n\t\t\t\t\t\t\terrorType +\n\t\t\t\t\t\t\t': ' +\n\t\t\t\t\t\t\trealSrc +\n\t\t\t\t\t\t\t')';\n\t\t\t\t\t\terror.name = 'ChunkLoadError';\n\t\t\t\t\t\terror.type = errorType;\n\t\t\t\t\t\terror.request = realSrc;\n\t\t\t\t\t\tinstalledChunkData[1](error);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\t__webpack_require__.l(url, loadingEnded, \"chunk-\" + chunkId, chunkId);\n\t\t} \n\t}\n}\n\n }\n __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = (parentChunkLoadingFunction, data) => {\n\tvar [chunkIds, moreModules, runtime] = data;\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif (chunkIds.some((id) => (installedChunks[id] !== 0))) {\n\t\tfor (moduleId in moreModules) {\n\t\t\tif (__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif (runtime) var result = runtime(__webpack_require__);\n\t}\n\tif (parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor (; i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif (\n\t\t\t__webpack_require__.o(installedChunks, chunkId) &&\n\t\t\tinstalledChunks[chunkId]\n\t\t) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n};\n\nvar chunkLoadingGlobal = self[\"webpackChunkandroid_playground\"] = self[\"webpackChunkandroid_playground\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));\n","__webpack_require__.ruid = \"bundler=rspack@1.3.12\";\n"],"names":["M","globalThis","e","Error","Object","Symbol","localStorage","t","window","Map","Date","i","Math","JSON","fetch","arguments","console","Promise","setTimeout","a","s","c","p","requestAnimationFrame","performance","Blob","URL","document","MediaRecorder","r","onlineStatus","color","_devices_find","_devices_find1","_devices_find2","devices","_loadingDevices","selectedDeviceId","onDeviceSelect","socketRef","scrcpyPlayerRef","dropdownOpen","setDropdownOpen","useState","lastSelectedDeviceRef","useRef","messageApi","contextHolder","message","serverValid","useServerValid","handleDeviceSelect","useCallback","deviceId","disconnectDevice","isSelectedDeviceOffline","d","useEffect","Dropdown","device","MobileOutlined","Divider","Button","props","Text","Typography","ScrcpyPlayer","forwardRef","ref","serverUrl","maxSize","autoConnect","autoReconnect","reconnectInterval","onConnectionStatusChange","connecting","setConnecting","connected","setConnected","screenInfo","setScreenInfo","setDeviceId","videoContainerRef","videoElementRef","decoderRef","reconnectTimerRef","metadataTimeoutRef","safeRemoveChildNodes","parent","innerErr","updateCanvasSize","container","canvas","containerWidth","containerHeight","originalWidth","originalHeight","availableHeight","aspectRatio","targetWidth","targetHeight","handleResize","createVideoFrameRenderer","WebGLVideoFrameRenderer","renderer","BitmapVideoFrameRenderer","createDecoder","codecId","WebCodecsVideoDecoder","element","canvasWrapper","setupVideoStream","_metadata","configurationPacketSent","pendingDataPackets","transformStream","TransformStream","chunk","controller","packet","Uint8Array","videoStream","ReadableStream","streamClosed","videoDataHandler","data","error","cleanupHandlers","errorHandler","disconnectHandler","takeScreenshot","blob","url","alert","clearTimeout","useImperativeHandle","connectDevice","resolve","setupMetadataTimeout","_socketRef_current","err","io","_socketRef_current1","metadata","ScrcpyVideoCodecId","width","height","timer","Card","Tooltip","InfoCircleOutlined","ScreenshotIcon","LinkedIcon","UnlinkIcon","Row","Col","Spin","Content","Layout","SERVER_URL","rootEl","root","ReactDOM","form","Form","selectedType","loading","setLoading","setSelectedDeviceId","connectToDevice","setConnectToDevice","setDevices","loadingDevices","setLoadingDevices","connectionReady","setConnectionReady","result","setResult","undefined","replayCounter","setReplayCounter","replayScriptsInfo","setReplayScriptsInfo","config","deepThink","useEnvConfig","loadingProgressText","setLoadingProgressText","currentRequestIdRef","pollIntervalRef","configAlreadySet","clearPollingInterval","clearInterval","socket","_reason","silent","timeoutId","startPollingProgress","requestId","setInterval","getTaskProgress","handleConnectionStatusChange","status","overrideAIConfig","overrideServerConfig","handleRun","type","prompt","thisRunningId","res","requestPlaygroundServer","info","allScriptsFromDump","resetResult","handleStop","cancelTask","ConfigProvider","Logo","EnvConfig","PromptInput","PlaygroundResultView","AdbDevice","App","Function","self"],"mappings":"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EAAQ,CAAC,EAAE,EAAa,EAAE,EAAe,CAAC,CAC7E,EAAO,KAAK,CAAC,CAAC,CAAC,EAAE,EAAa,EAAE,EAAE;AAAU,CAAC,CACjD,EAQ+B,EADC,SAAgB,IAAI,IAGxC,KAAW,EACf,EAEJ,CACA,OAAO,GAAe,GAAG,CAAC,EAC9B,+DCxCiB,GAAS,mCCJtB,IAAM,GAAkB,CACxB,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,MAAO,CACH,IAAK,QACL,KAAM,OACV,EACA,MAAO,CACH,IAAK,QACL,KAAM,OACV,EACA,MAAO,CACH,QAAS,EACT,KAAM,QACN,IAAK,QACT,EACA,KAAM,CACF,QAAS,EACT,KAAM,OACN,IAAK,MACT,EACA,UAAW,CACP,QAAS,EACT,KAAM,YACN,IAAK,WACT,EACA,IAAK,CACD,QAAS,EACT,KAAM,MACN,IAAK,KACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,QACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,YAAa,CACT,QAAS,GACT,KAAM,cACN,IAAK,QACL,KAAM,KACN,SAAU,CACd,EACA,MAAO,CACH,QAAS,GACT,KAAM,QACN,IAAK,QACL,KAAM,IACV,EACA,KAAM,CACF,QAAS,GACT,KAAM,QACN,IAAK,QACL,KAAM,IACV,EACA,KAAM,CACF,QAAS,GACT,KAAM,QACN,IAAK,QACL,KAAM,IACV,EACA,UAAW,CACP,QAAS,GACT,KAAM,YACN,IAAK,QACL,SAAU,CACd,EACA,WAAY,CACR,QAAS,GACT,KAAM,aACN,IAAK,QACL,SAAU,CACd,EACA,YAAa,CACT,QAAS,GACT,KAAM,cACN,IAAK,UACL,SAAU,CACd,EACA,aAAc,CACV,QAAS,GACT,KAAM,eACN,IAAK,UACL,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,KAAM,UACN,IAAK,MACL,SAAU,CACd,EACA,SAAU,CACN,QAAS,GACT,KAAM,WACN,IAAK,MACL,SAAU,CACd,EACA,MAAO,CACH,QAAS,GACT,KAAM,QACN,IAAK,OACT,EACA,SAAU,CACN,QAAS,GACT,KAAM,WACN,IAAK,UACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,QAAS,CACL,QAAS,GACT,KAAM,UACN,IAAK,SACT,EACA,WAAY,CACR,QAAS,GACT,KAAM,aACN,IAAK,YACT,EACA,MAAO,CACH,QAAS,GACT,KAAM,QACN,IAAK,GACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,SACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,GACd,IAAK,WACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,SAAU,CACN,QAAS,GACT,KAAM,WACN,IAAK,UACT,EACA,IAAK,CACD,QAAS,GACT,KAAM,MACN,IAAK,KACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,GACd,IAAK,MACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,IAAK,MACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,OACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,UAAW,CACP,QAAS,GACT,KAAM,YACN,IAAK,WACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,YACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,UACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,KAAM,UACN,IAAK,SACT,EACA,WAAY,CACR,QAAS,GACT,KAAM,aACN,IAAK,YACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,IACd,IAAK,aACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,aAAc,GACd,IAAK,YACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,UAAW,CACP,QAAS,GACT,KAAM,YACN,IAAK,WACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,IAAK,SACT,EACA,YAAa,CACT,QAAS,GACT,KAAM,cACN,IAAK,aACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,QAAS,CACL,QAAS,GACT,aAAc,GACd,IAAK,SACL,KAAM,UACN,SAAU,IACV,SAAU,CACd,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,IAAK,QACT,EACA,cAAe,CACX,QAAS,GACT,aAAc,IACd,KAAM,gBACN,IAAK,KACL,SAAU,IACV,SAAU,CACd,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,GACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,KAAM,CACF,QAAS,GACT,KAAM,OACN,SAAU,IACV,IAAK,GACT,EACA,SAAU,CACN,QAAS,GACT,KAAM,WACN,IAAK,OACL,SAAU,CACd,EACA,UAAW,CACP,QAAS,GACT,KAAM,YACN,IAAK,OACL,SAAU,CACd,EACA,YAAa,CACT,QAAS,GACT,KAAM,cACN,IAAK,aACT,EACA,eAAgB,CACZ,QAAS,IACT,KAAM,iBACN,IAAK,IACL,SAAU,CACd,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,IAAK,IACL,SAAU,CACd,EACA,eAAgB,CACZ,QAAS,IACT,KAAM,iBACN,IAAK,IACL,SAAU,CACd,EACA,aAAc,CACV,QAAS,IACT,KAAM,eACN,IAAK,IACL,SAAU,CACd,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,GAAI,CACA,QAAS,IACT,KAAM,KACN,IAAK,IACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,IAAK,CACD,QAAS,IACT,KAAM,MACN,IAAK,KACT,EACA,QAAS,CACL,QAAS,IACT,KAAM,UACN,IAAK,SACT,EACA,WAAY,CACR,QAAS,IACT,KAAM,aACN,IAAK,YACT,EACA,gBAAiB,CACb,QAAS,IACT,KAAM,kBACN,IAAK,iBACT,EACA,gBAAiB,CACb,QAAS,IACT,KAAM,kBACN,IAAK,iBACT,EACA,cAAe,CACX,QAAS,IACT,KAAM,gBACN,IAAK,eACT,EACA,eAAgB,CACZ,QAAS,IACT,KAAM,iBACN,IAAK,gBACT,EACA,mBAAoB,CAChB,QAAS,IACT,KAAM,qBACN,IAAK,oBACT,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,IAAK,WACT,EACA,eAAgB,CACZ,QAAS,IACT,KAAM,iBACN,IAAK,gBACT,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,SAAU,IACV,IAAK,GACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,YAAa,CACT,QAAS,IACT,KAAM,cACN,IAAK,IACL,SAAU,CACd,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,OAAQ,CACJ,QAAS,IACT,KAAM,SACN,SAAU,IACV,IAAK,GACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,SAAU,IACV,IAAK,GACT,EACA,YAAa,CACT,QAAS,IACT,KAAM,cACN,SAAU,IACV,IAAK,GACT,EACA,UAAW,CACP,QAAS,IACT,KAAM,YACN,SAAU,IACV,IAAK,IACT,EACA,aAAc,CACV,QAAS,IACT,KAAM,eACN,SAAU,IACV,IAAK,GACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,SAAU,IACV,IAAK,GACT,EACA,SAAU,CACN,QAAS,IACT,KAAM,WACN,IAAK,UACT,EACA,MAAO,CACH,QAAS,IACT,KAAM,QACN,IAAK,OACT,EACA,OAAQ,CACJ,QAAS,EACT,IAAK,SACL,KAAM,OACV,EACA,MAAO,CACH,QAAS,GACT,IAAK,QACL,KAAM,UACN,SAAU,CACd,EACA,MAAO,CACH,QAAS,GACT,IAAK,QACL,KAAM,YACN,SAAU,CACd,EACA,QAAS,CACL,QAAS,GACT,IAAK,UACL,KAAM,cACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,GACT,IAAK,MACL,KAAM,UACN,SAAU,CACd,EACA,OAAQ,CACJ,QAAS,GACT,IAAK,QACT,EACA,WAAY,CACR,QAAS,GACT,IAAK,YACT,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,OACV,EACA,MAAO,CACH,QAAS,GACT,IAAK,OACT,EACA,QAAS,CACL,QAAS,GACT,IAAK,UACL,KAAM,MACV,EACA,KAAU,CACN,QAAS,GACT,IAAK,KACL,KAAM,gBACN,SAAU,CACd,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,KAAM,CACF,QAAS,GACT,IAAK,OACL,KAAM,WACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,iBACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,YACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,iBACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,eACN,SAAU,CACd,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,WACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,OACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,OACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,WACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,aACV,EACA,KAAM,CACF,QAAS,IACT,IAAK,KACL,KAAM,WACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,cACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,OACV,EACA,KAAM,CACF,QAAS,IACT,IAAK,MACT,EACA,MAAO,CACH,QAAS,IACT,IAAK,QACL,KAAM,OACV,EACA,MAAO,CACH,QAAS,IACT,IAAK,OACT,EACA,SAAU,CACN,QAAS,IACT,IAAK,UACT,EACA,KAAM,CACF,QAAS,IACT,IAAK,MACT,EACA,QAAS,CACL,QAAS,IACT,IAAK,SACT,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,IAAK,CACD,QAAS,GACT,IAAK,IACL,KAAM,QACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,EAAG,CACC,QAAS,GACT,IAAK,IACL,KAAM,MACV,EACA,IAAK,CACD,QAAS,IACT,IAAK,IACL,KAAM,WACV,EACA,IAAK,CACD,QAAS,IACT,IAAK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"}