@midscene/core 0.26.2-beta-20250812091127.0 → 0.26.3-beta-20250813021342.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/es/ai-model.mjs +2502 -0
  2. package/dist/es/ai-model.mjs.map +1 -0
  3. package/dist/es/index.mjs +2362 -0
  4. package/dist/es/index.mjs.map +1 -0
  5. package/dist/es/tree.mjs +2 -0
  6. package/dist/es/utils.mjs +188 -0
  7. package/dist/es/{chunk-WXNDYUNG.js.map → utils.mjs.map} +1 -1
  8. package/dist/lib/ai-model.js +2581 -3
  9. package/dist/lib/ai-model.js.map +1 -0
  10. package/dist/lib/index.js +2375 -493
  11. package/dist/lib/index.js.map +1 -1
  12. package/dist/lib/tree.js +42 -11
  13. package/dist/lib/tree.js.map +1 -1
  14. package/dist/lib/utils.js +257 -29
  15. package/dist/lib/utils.js.map +1 -0
  16. package/dist/types/ai-model.d.ts +505 -99
  17. package/dist/types/index.d.ts +1299 -53
  18. package/dist/types/tree.d.ts +11 -1
  19. package/dist/types/utils.d.ts +47 -33
  20. package/package.json +28 -12
  21. package/dist/es/ai-model.d.ts +0 -99
  22. package/dist/es/ai-model.js +0 -44
  23. package/dist/es/chunk-DDYIQHOA.js +0 -2883
  24. package/dist/es/chunk-DDYIQHOA.js.map +0 -1
  25. package/dist/es/chunk-WXNDYUNG.js +0 -265
  26. package/dist/es/index.d.ts +0 -53
  27. package/dist/es/index.js +0 -570
  28. package/dist/es/index.js.map +0 -1
  29. package/dist/es/llm-planning-4e0c16fe.d.ts +0 -106
  30. package/dist/es/tree.d.ts +0 -1
  31. package/dist/es/tree.js +0 -13
  32. package/dist/es/tree.js.map +0 -1
  33. package/dist/es/types-8a6be57c.d.ts +0 -577
  34. package/dist/es/utils.d.ts +0 -33
  35. package/dist/es/utils.js +0 -30
  36. package/dist/lib/ai-model.d.ts +0 -99
  37. package/dist/lib/chunk-DDYIQHOA.js +0 -2883
  38. package/dist/lib/chunk-DDYIQHOA.js.map +0 -1
  39. package/dist/lib/chunk-WXNDYUNG.js +0 -265
  40. package/dist/lib/chunk-WXNDYUNG.js.map +0 -1
  41. package/dist/lib/index.d.ts +0 -53
  42. package/dist/lib/llm-planning-4e0c16fe.d.ts +0 -106
  43. package/dist/lib/tree.d.ts +0 -1
  44. package/dist/lib/types-8a6be57c.d.ts +0 -577
  45. package/dist/lib/utils.d.ts +0 -33
  46. package/dist/types/llm-planning-4e0c16fe.d.ts +0 -106
  47. package/dist/types/types-8a6be57c.d.ts +0 -577
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["webpack://@midscene/core/./src/utils.ts","webpack://@midscene/core/./src/ai-model/action-executor.ts","webpack://@midscene/core/./src/types.ts","webpack://@midscene/core/./src/ai-model/prompt/assertion.ts","webpack://@midscene/core/./src/ai-model/prompt/common.ts","webpack://@midscene/core/./src/ai-model/prompt/llm-locator.ts","webpack://@midscene/core/./src/ai-model/prompt/llm-planning.ts","webpack://@midscene/core/./src/ai-model/service-caller/index.ts","webpack://@midscene/core/./src/ai-model/common.ts","webpack://@midscene/core/./src/ai-model/prompt/util.ts","webpack://@midscene/core/./src/ai-model/prompt/extraction.ts","webpack://@midscene/core/./src/ai-model/prompt/llm-section-locator.ts","webpack://@midscene/core/./src/ai-model/inspect.ts","webpack://@midscene/core/./src/ai-model/llm-planning.ts","webpack://@midscene/core/./src/ai-model/ui-tars-planning.ts","webpack://@midscene/core/./src/ai-model/prompt/describe.ts","webpack://@midscene/core/./src/insight/utils.ts","webpack://@midscene/core/./src/insight/index.ts","webpack://@midscene/core/./src/index.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport * as path from 'node:path';\nimport { dirname } from 'node:path';\nimport {\n defaultRunDirName,\n getMidsceneRunSubDir,\n} from '@midscene/shared/common';\nimport {\n MIDSCENE_DEBUG_MODE,\n MIDSCENE_OPENAI_INIT_CONFIG_JSON,\n getAIConfig,\n getAIConfigInJson,\n} from '@midscene/shared/env';\nimport { getRunningPkgInfo } from '@midscene/shared/node';\nimport { assert, logMsg } from '@midscene/shared/utils';\nimport {\n escapeScriptTag,\n ifInBrowser,\n ifInWorker,\n uuid,\n} from '@midscene/shared/utils';\nimport type { Rect, ReportDumpWithAttributes } from './types';\n\nlet logEnvReady = false;\n\nexport const groupedActionDumpFileExt = 'web-dump.json';\n\nconst reportInitializedMap = new Map<string, boolean>();\n\ndeclare const __DEV_REPORT_PATH__: string;\n\nfunction getReportTpl() {\n if (__DEV_REPORT_PATH__) {\n return fs.readFileSync(__DEV_REPORT_PATH__, 'utf-8');\n }\n const reportTpl = 'REPLACE_ME_WITH_REPORT_HTML';\n\n return reportTpl;\n}\n\n/**\n * high performance, insert script before </html> in HTML file\n * only truncate and append, no temporary file\n */\nexport function insertScriptBeforeClosingHtml(\n filePath: string,\n scriptContent: string,\n): void {\n const htmlEndTag = '</html>';\n const stat = fs.statSync(filePath);\n\n const readSize = Math.min(stat.size, 4096);\n const start = Math.max(0, stat.size - readSize);\n const buffer = Buffer.alloc(stat.size - start);\n const fd = fs.openSync(filePath, 'r');\n fs.readSync(fd, buffer, 0, buffer.length, start);\n fs.closeSync(fd);\n\n const tailStr = buffer.toString('utf8');\n const htmlEndIdx = tailStr.lastIndexOf(htmlEndTag);\n if (htmlEndIdx === -1) {\n throw new Error(`No </html> found in file:${filePath}`);\n }\n\n // calculate the correct byte position: char position to byte position\n const beforeHtmlInTail = tailStr.slice(0, htmlEndIdx);\n const htmlEndPos = start + Buffer.byteLength(beforeHtmlInTail, 'utf8');\n\n // truncate to </html> before\n fs.truncateSync(filePath, htmlEndPos);\n // append script and </html>\n fs.appendFileSync(filePath, `${scriptContent}\\n${htmlEndTag}\\n`);\n}\n\nexport function reportHTMLContent(\n dumpData: string | ReportDumpWithAttributes,\n reportPath?: string,\n appendReport?: boolean,\n): string {\n const tpl = getReportTpl();\n\n if (!tpl) {\n console.warn('reportTpl is not set, will not write report');\n return '';\n }\n\n // if reportPath is set, it means we are in write to file mode\n const writeToFile = reportPath && !ifInBrowser;\n let dumpContent = '';\n\n if (typeof dumpData === 'string') {\n // do not use template string here, will cause bundle error\n dumpContent =\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene_web_dump\" type=\"application/json\">\\n' +\n escapeScriptTag(dumpData) +\n '\\n</script>';\n } else {\n const { dumpString, attributes } = dumpData;\n const attributesArr = Object.keys(attributes || {}).map((key) => {\n return `${key}=\"${encodeURIComponent(attributes![key])}\"`;\n });\n\n dumpContent =\n // do not use template string here, will cause bundle error\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene_web_dump\" type=\"application/json\" ' +\n attributesArr.join(' ') +\n '>\\n' +\n escapeScriptTag(dumpString) +\n '\\n</script>';\n }\n\n if (writeToFile) {\n if (!appendReport) {\n writeFileSync(reportPath!, tpl + dumpContent, { flag: 'w' });\n return reportPath!;\n }\n\n if (!reportInitializedMap.get(reportPath!)) {\n writeFileSync(reportPath!, tpl, { flag: 'w' });\n reportInitializedMap.set(reportPath!, true);\n }\n\n insertScriptBeforeClosingHtml(reportPath!, dumpContent);\n return reportPath!;\n }\n\n return tpl + dumpContent;\n}\n\nexport function writeDumpReport(\n fileName: string,\n dumpData: string | ReportDumpWithAttributes,\n appendReport?: boolean,\n): string | null {\n if (ifInBrowser || ifInWorker) {\n console.log('will not write report in browser');\n return null;\n }\n\n const __dirname = dirname(__filename);\n const midscenePkgInfo = getRunningPkgInfo(__dirname);\n if (!midscenePkgInfo) {\n console.warn('midscenePkgInfo not found, will not write report');\n return null;\n }\n\n const reportPath = path.join(\n getMidsceneRunSubDir('report'),\n `${fileName}.html`,\n );\n\n reportHTMLContent(dumpData, reportPath, appendReport);\n\n if (process.env.MIDSCENE_DEBUG_LOG_JSON) {\n const jsonPath = `${reportPath}.json`;\n let data;\n\n if (typeof dumpData === 'string') {\n data = JSON.parse(dumpData) as ReportDumpWithAttributes;\n } else {\n data = dumpData;\n }\n\n writeFileSync(jsonPath, JSON.stringify(data, null, 2), {\n flag: appendReport ? 'a' : 'w',\n });\n\n logMsg(`Midscene - dump file written: ${jsonPath}`);\n }\n\n return reportPath;\n}\n\nexport function writeLogFile(opts: {\n fileName: string;\n fileExt: string;\n fileContent: string;\n type: 'dump' | 'cache' | 'report' | 'tmp';\n generateReport?: boolean;\n appendReport?: boolean;\n}) {\n if (ifInBrowser || ifInWorker) {\n return '/mock/report.html';\n }\n const { fileName, fileExt, fileContent, type = 'dump' } = opts;\n const targetDir = getMidsceneRunSubDir(type);\n // Ensure directory exists\n if (!logEnvReady) {\n assert(targetDir, 'logDir should be set before writing dump file');\n\n // gitIgnore in the parent directory\n const gitIgnorePath = path.join(targetDir, '../../.gitignore');\n const gitPath = path.join(targetDir, '../../.git');\n let gitIgnoreContent = '';\n\n if (existsSync(gitPath)) {\n // if the git path exists, we need to add the log folder to the git ignore file\n if (existsSync(gitIgnorePath)) {\n gitIgnoreContent = readFileSync(gitIgnorePath, 'utf-8');\n }\n\n // ignore the log folder\n if (!gitIgnoreContent.includes(`${defaultRunDirName}/`)) {\n writeFileSync(\n gitIgnorePath,\n `${gitIgnoreContent}\\n# Midscene.js dump files\\n${defaultRunDirName}/dump\\n${defaultRunDirName}/report\\n${defaultRunDirName}/tmp\\n${defaultRunDirName}/log\\n`,\n 'utf-8',\n );\n }\n }\n\n logEnvReady = true;\n }\n\n const filePath = path.join(targetDir, `${fileName}.${fileExt}`);\n\n if (type !== 'dump') {\n // do not write dump file any more\n writeFileSync(filePath, fileContent);\n }\n\n if (opts?.generateReport) {\n return writeDumpReport(fileName, fileContent, opts.appendReport);\n }\n\n return filePath;\n}\n\nexport function getTmpDir(): string | null {\n try {\n const runningPkgInfo = getRunningPkgInfo();\n if (!runningPkgInfo) {\n return null;\n }\n const { name } = runningPkgInfo;\n const tmpPath = path.join(tmpdir(), name);\n mkdirSync(tmpPath, { recursive: true });\n return tmpPath;\n } catch (e) {\n return null;\n }\n}\n\nexport function getTmpFile(fileExtWithoutDot: string): string | null {\n if (ifInBrowser || ifInWorker) {\n return null;\n }\n const tmpDir = getTmpDir();\n const filename = `${uuid()}.${fileExtWithoutDot}`;\n return path.join(tmpDir!, filename);\n}\n\nexport function overlapped(container: Rect, target: Rect) {\n // container and the target have some part overlapped\n return (\n container.left < target.left + target.width &&\n container.left + container.width > target.left &&\n container.top < target.top + target.height &&\n container.top + container.height > target.top\n );\n}\n\nexport async function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function replacerForPageObject(key: string, value: any) {\n if (value && value.constructor?.name === 'Page') {\n return '[Page object]';\n }\n if (value && value.constructor?.name === 'Browser') {\n return '[Browser object]';\n }\n return value;\n}\n\nexport function stringifyDumpData(data: any, indents?: number) {\n return JSON.stringify(data, replacerForPageObject, indents);\n}\n\ndeclare const __VERSION__: string;\n\nexport function getVersion() {\n return __VERSION__;\n}\n\nfunction debugLog(...message: any[]) {\n const debugMode = getAIConfig(MIDSCENE_DEBUG_MODE);\n if (debugMode) {\n console.log('[Midscene]', ...message);\n }\n}\n\nlet lastReportedRepoUrl = '';\nexport function uploadTestInfoToServer({ testUrl }: { testUrl: string }) {\n let repoUrl = '';\n let userEmail = '';\n\n const extraConfig = getAIConfigInJson(MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n const serverUrl = extraConfig?.REPORT_SERVER_URL;\n\n try {\n repoUrl = execSync('git config --get remote.origin.url').toString().trim();\n userEmail = execSync('git config --get user.email').toString().trim();\n } catch (error) {\n debugLog('Failed to get git info:', error);\n }\n\n // Only upload test info if:\n // 1. Server URL is configured AND\n // 2. Either:\n // - We have a repo URL that's different from last reported one (to avoid duplicate reports)\n // - OR we don't have a repo URL but have a test URL (for non-git environments)\n if (\n serverUrl &&\n ((repoUrl && repoUrl !== lastReportedRepoUrl) || (!repoUrl && testUrl))\n ) {\n debugLog('Uploading test info to server', {\n serverUrl,\n repoUrl,\n testUrl,\n userEmail,\n });\n\n fetch(serverUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n repo_url: repoUrl,\n test_url: testUrl,\n user_email: userEmail,\n }),\n })\n .then((response) => response.json())\n .then((data) => {\n debugLog('Successfully uploaded test info to server:', data);\n })\n .catch((error) =>\n debugLog('Failed to upload test info to server:', error),\n );\n lastReportedRepoUrl = repoUrl;\n }\n}\n","import type {\n ExecutionDump,\n ExecutionTask,\n ExecutionTaskApply,\n ExecutionTaskInsightLocateOutput,\n ExecutionTaskProgressOptions,\n ExecutionTaskReturn,\n ExecutorContext,\n} from '@/types';\nimport { getVersion } from '@/utils';\nimport {\n MIDSCENE_MODEL_NAME,\n getAIConfig,\n uiTarsModelVersion,\n vlLocateMode,\n} from '@midscene/shared/env';\nimport { assert } from '@midscene/shared/utils';\n\nexport class Executor {\n name: string;\n\n tasks: ExecutionTask[];\n\n // status of executor\n status: 'init' | 'pending' | 'running' | 'completed' | 'error';\n\n onTaskStart?: ExecutionTaskProgressOptions['onTaskStart'];\n\n constructor(\n name: string,\n options?: ExecutionTaskProgressOptions & {\n tasks?: ExecutionTaskApply[];\n },\n ) {\n this.status =\n options?.tasks && options.tasks.length > 0 ? 'pending' : 'init';\n this.name = name;\n this.tasks = (options?.tasks || []).map((item) =>\n this.markTaskAsPending(item),\n );\n this.onTaskStart = options?.onTaskStart;\n }\n\n private markTaskAsPending(task: ExecutionTaskApply): ExecutionTask {\n return {\n status: 'pending',\n ...task,\n };\n }\n\n async append(task: ExecutionTaskApply[] | ExecutionTaskApply): Promise<void> {\n assert(\n this.status !== 'error',\n `executor is in error state, cannot append task\\nerror=${this.latestErrorTask()?.error}\\n${this.latestErrorTask()?.errorStack}`,\n );\n if (Array.isArray(task)) {\n this.tasks.push(...task.map((item) => this.markTaskAsPending(item)));\n } else {\n this.tasks.push(this.markTaskAsPending(task));\n }\n if (this.status !== 'running') {\n this.status = 'pending';\n }\n }\n\n async flush(): Promise<{ output: any; thought?: string } | undefined> {\n if (this.status === 'init' && this.tasks.length > 0) {\n console.warn(\n 'illegal state for executor, status is init but tasks are not empty',\n );\n }\n\n assert(this.status !== 'running', 'executor is already running');\n assert(this.status !== 'completed', 'executor is already completed');\n assert(this.status !== 'error', 'executor is in error state');\n\n const nextPendingIndex = this.tasks.findIndex(\n (task) => task.status === 'pending',\n );\n if (nextPendingIndex < 0) {\n // all tasks are completed\n return;\n }\n\n this.status = 'running';\n let taskIndex = nextPendingIndex;\n let successfullyCompleted = true;\n\n let previousFindOutput: ExecutionTaskInsightLocateOutput | undefined;\n\n while (taskIndex < this.tasks.length) {\n const task = this.tasks[taskIndex];\n assert(\n task.status === 'pending',\n `task status should be pending, but got: ${task.status}`,\n );\n task.timing = {\n start: Date.now(),\n };\n try {\n task.status = 'running';\n try {\n if (this.onTaskStart) {\n await this.onTaskStart(task);\n }\n } catch (e) {\n console.error('error in onTaskStart', e);\n }\n assert(\n ['Insight', 'Action', 'Planning'].indexOf(task.type) >= 0,\n `unsupported task type: ${task.type}`,\n );\n\n const { executor, param } = task;\n assert(executor, `executor is required for task type: ${task.type}`);\n\n let returnValue;\n const executorContext: ExecutorContext = {\n task,\n element: previousFindOutput?.element,\n };\n\n if (task.type === 'Insight') {\n assert(\n task.subType === 'Locate' ||\n task.subType === 'Query' ||\n task.subType === 'Assert' ||\n task.subType === 'Boolean' ||\n task.subType === 'Number' ||\n task.subType === 'String',\n `unsupported insight subType: ${task.subType}`,\n );\n returnValue = await task.executor(param, executorContext);\n if (task.subType === 'Locate') {\n previousFindOutput = (\n returnValue as ExecutionTaskReturn<ExecutionTaskInsightLocateOutput>\n )?.output;\n }\n } else if (task.type === 'Action' || task.type === 'Planning') {\n returnValue = await task.executor(param, executorContext);\n } else {\n console.warn(\n `unsupported task type: ${task.type}, will try to execute it directly`,\n );\n returnValue = await task.executor(param, executorContext);\n }\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: any) {\n successfullyCompleted = false;\n task.error = e;\n task.errorMessage =\n e?.message || (typeof e === 'string' ? e : 'error-without-message');\n task.errorStack = e.stack;\n\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\n // set all remaining tasks as cancelled\n for (let i = taskIndex + 1; i < this.tasks.length; i++) {\n this.tasks[i].status = 'cancelled';\n }\n\n if (successfullyCompleted) {\n this.status = 'completed';\n } else {\n this.status = 'error';\n }\n\n if (this.tasks.length) {\n // return the last output\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\n isInErrorState(): boolean {\n return this.status === 'error';\n }\n\n latestErrorTask(): ExecutionTask | null {\n if (this.status !== 'error') {\n return null;\n }\n const errorTaskIndex = this.tasks.findIndex(\n (task) => task.status === 'failed',\n );\n if (errorTaskIndex >= 0) {\n return this.tasks[errorTaskIndex];\n }\n return null;\n }\n\n dump(): ExecutionDump {\n let modelDescription = '';\n\n if (vlLocateMode()) {\n const uiTarsModelVer = uiTarsModelVersion();\n if (uiTarsModelVer) {\n modelDescription = `UI-TARS=${uiTarsModelVer}`;\n } else {\n modelDescription = `${vlLocateMode()} mode`;\n }\n }\n const dumpData: ExecutionDump = {\n sdkVersion: getVersion(),\n model_name: 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}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { NodeType } from '@midscene/shared/constants';\nimport type {\n BaseElement,\n ElementTreeNode,\n Rect,\n Size,\n} from '@midscene/shared/types';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport type {\n DetailedLocateParam,\n MidsceneYamlFlowItem,\n scrollParam,\n} from './yaml';\n\nexport type {\n ElementTreeNode,\n BaseElement,\n Rect,\n Size,\n Point,\n} from '@midscene/shared/types';\nexport * from './yaml';\n\nexport type AIUsageInfo = Record<string, any> & {\n prompt_tokens: number | undefined;\n completion_tokens: number | undefined;\n total_tokens: number | undefined;\n time_cost: number | undefined;\n};\n\n/**\n * openai\n *\n */\nexport enum AIResponseFormat {\n JSON = 'json_object',\n TEXT = 'text',\n}\n\nexport type AISingleElementResponseById = {\n id: string;\n reason?: string;\n text?: string;\n xpaths?: string[];\n};\n\nexport type AISingleElementResponseByPosition = {\n position?: {\n x: number;\n y: number;\n };\n bbox?: [number, number, number, number];\n reason: string;\n text: string;\n};\n\nexport type AISingleElementResponse = AISingleElementResponseById;\nexport interface AIElementLocatorResponse {\n elements: {\n id: string;\n reason?: string;\n text?: string;\n xpaths?: string[];\n }[];\n bbox?: [number, number, number, number];\n isOrderSensitive?: boolean;\n errors?: string[];\n}\n\nexport interface AIElementCoordinatesResponse {\n bbox: [number, number, number, number];\n isOrderSensitive?: boolean;\n errors?: string[];\n}\n\nexport type AIElementResponse =\n | AIElementLocatorResponse\n | AIElementCoordinatesResponse;\n\nexport interface AIDataExtractionResponse<DataDemand> {\n data: DataDemand;\n errors?: string[];\n thought?: string;\n}\n\nexport interface AISectionLocatorResponse {\n bbox: [number, number, number, number];\n references_bbox?: [number, number, number, number][];\n error?: string;\n}\n\nexport interface AIAssertionResponse {\n pass: boolean;\n thought: string;\n}\n\nexport interface AIDescribeElementResponse {\n description: string;\n error?: string;\n}\n\nexport interface LocatorValidatorOption {\n centerDistanceThreshold?: number;\n}\n\nexport interface LocateValidatorResult {\n pass: boolean;\n rect: Rect;\n center: [number, number];\n centerDistance?: number;\n}\n\nexport interface AgentDescribeElementAtPointResult {\n prompt: string;\n deepThink: boolean;\n verifyResult?: LocateValidatorResult;\n}\n\n/**\n * context\n */\n\nexport abstract class UIContext<ElementType extends BaseElement = BaseElement> {\n abstract screenshotBase64: string;\n\n abstract tree: ElementTreeNode<ElementType>;\n\n abstract size: Size;\n}\n\n/**\n * insight\n */\n\nexport type CallAIFn = <T>(\n messages: ChatCompletionMessageParam[],\n) => Promise<T>;\n\nexport interface InsightOptions {\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\n aiVendorFn?: CallAIFn;\n}\n\nexport type EnsureObject<T> = { [K in keyof T]: any };\n\nexport type InsightAction = 'locate' | 'extract' | 'assert' | 'describe';\n\nexport type InsightExtractParam = string | Record<string, string>;\n\nexport type LocateResultElement = {\n id: string;\n indexId?: number;\n center: [number, number];\n rect: Rect;\n xpaths: string[];\n attributes: {\n nodeType: NodeType;\n [key: string]: string;\n };\n isOrderSensitive?: boolean;\n};\n\nexport interface LocateResult {\n element: LocateResultElement | null;\n rect?: Rect;\n}\n\nexport interface InsightTaskInfo {\n durationMs: number;\n formatResponse?: string;\n rawResponse?: string;\n usage?: AIUsageInfo;\n searchArea?: Rect;\n searchAreaRawResponse?: string;\n searchAreaUsage?: AIUsageInfo;\n}\n\nexport interface DumpMeta {\n sdkVersion: string;\n logTime: number;\n model_name: string;\n model_description?: string;\n}\n\nexport interface ReportDumpWithAttributes {\n dumpString: string;\n attributes?: Record<string, any>;\n}\n\nexport interface InsightDump extends DumpMeta {\n type: 'locate' | 'extract' | 'assert';\n logId: string;\n userQuery: {\n element?: TUserPrompt;\n dataDemand?: InsightExtractParam;\n assertion?: TUserPrompt;\n };\n matchedElement: BaseElement[];\n matchedRect?: Rect;\n deepThink?: boolean;\n data: any;\n assertionPass?: boolean;\n assertionThought?: string;\n taskInfo: InsightTaskInfo;\n error?: string;\n output?: any;\n}\n\nexport type PartialInsightDumpFromSDK = Omit<\n InsightDump,\n 'sdkVersion' | 'logTime' | 'logId' | 'model_name'\n>;\n\nexport type DumpSubscriber = (dump: InsightDump) => Promise<void> | void;\n\n// intermediate variables to optimize the return value by AI\nexport interface LiteUISection {\n name: string;\n description: string;\n sectionCharacteristics: string;\n textIds: string[];\n}\n\nexport type ElementById = (id: string) => BaseElement | null;\n\nexport type InsightAssertionResponse = AIAssertionResponse & {\n usage?: AIUsageInfo;\n};\n\n/**\n * agent\n */\n\nexport type OnTaskStartTip = (tip: string) => Promise<void> | void;\n\nexport interface AgentWaitForOpt {\n checkIntervalMs?: number;\n timeoutMs?: number;\n}\n\nexport interface AgentAssertOpt {\n keepRawResponse?: boolean;\n}\n\n/**\n * planning\n *\n */\n\nexport interface PlanningLocateParam extends DetailedLocateParam {\n id?: string;\n bbox?: [number, number, number, number];\n}\n\nexport interface PlanningAction<ParamType = any> {\n thought?: string;\n type:\n | 'Locate'\n | 'Tap'\n | 'RightClick'\n | 'Hover'\n | 'Drag'\n | 'Input'\n | 'KeyboardPress'\n | 'Scroll'\n | 'Error'\n | 'Assert'\n | 'AssertWithoutThrow'\n | 'Sleep'\n | 'Finished'\n | 'AndroidBackButton'\n | 'AndroidHomeButton'\n | 'AndroidRecentAppsButton'\n | 'AndroidLongPress'\n | 'AndroidPull';\n param: ParamType;\n locate?: PlanningLocateParam | null;\n}\n\nexport interface PlanningAIResponse {\n action?: PlanningAction; // this is the qwen mode\n actions?: PlanningAction[];\n more_actions_needed_by_instruction: boolean;\n log: string;\n sleep?: number;\n error?: string;\n usage?: AIUsageInfo;\n rawResponse?: string;\n yamlFlow?: MidsceneYamlFlowItem[];\n yamlString?: string;\n}\n\nexport type PlanningActionParamTap = null;\nexport type PlanningActionParamHover = null;\nexport type PlanningActionParamRightClick = null;\nexport interface PlanningActionParamInputOrKeyPress {\n value: string;\n autoDismissKeyboard?: boolean;\n}\n\nexport type PlanningActionParamScroll = scrollParam;\n\nexport interface PlanningActionParamAssert {\n assertion: TUserPrompt;\n}\n\nexport interface PlanningActionParamSleep {\n timeMs: number;\n}\n\nexport interface PlanningActionParamError {\n thought: string;\n}\n\nexport type PlanningActionParamWaitFor = AgentWaitForOpt & {\n assertion: string;\n};\n\nexport interface PlanningActionParamAndroidLongPress {\n x: number;\n y: number;\n duration?: number;\n}\n\nexport interface PlanningActionParamAndroidPull {\n direction: 'up' | 'down';\n startPoint?: { x: number; y: number };\n distance?: number;\n duration?: number;\n}\n/**\n * misc\n */\n\nexport interface Color {\n name: string;\n hex: string;\n}\n\nexport interface BaseAgentParserOpt {\n selector?: string;\n ignoreMarker?: boolean;\n}\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PuppeteerParserOpt extends BaseAgentParserOpt {}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PlaywrightParserOpt extends BaseAgentParserOpt {}\n\n/*\naction\n*/\nexport interface ExecutionTaskProgressOptions {\n onTaskStart?: (task: ExecutionTask) => Promise<void> | void;\n}\n\nexport interface ExecutionRecorderItem {\n type: 'screenshot';\n ts: number;\n screenshot?: string;\n timing?: string;\n}\n\nexport type ExecutionTaskType =\n | 'Planning'\n | 'Insight'\n | 'Action'\n | 'Assertion'\n | 'Log';\n\nexport interface ExecutorContext {\n task: ExecutionTask;\n element?: LocateResultElement | null;\n}\n\nexport interface ExecutionTaskApply<\n Type extends ExecutionTaskType = any,\n TaskParam = any,\n TaskOutput = any,\n TaskLog = any,\n> {\n type: Type;\n subType?: string;\n param?: TaskParam;\n thought?: string;\n locate?: PlanningLocateParam | null;\n pageContext?: UIContext;\n executor: (\n param: TaskParam,\n context: ExecutorContext,\n ) => // biome-ignore lint/suspicious/noConfusingVoidType: <explanation>\n | Promise<ExecutionTaskReturn<TaskOutput, TaskLog> | undefined | void>\n | undefined\n | void;\n}\n\nexport interface ExecutionTaskHitBy {\n from: string;\n context: Record<string, any>;\n}\n\nexport interface ExecutionTaskReturn<TaskOutput = unknown, TaskLog = unknown> {\n output?: TaskOutput;\n log?: TaskLog;\n recorder?: ExecutionRecorderItem[];\n hitBy?: ExecutionTaskHitBy;\n}\n\nexport type ExecutionTask<\n E extends ExecutionTaskApply<any, any, any> = ExecutionTaskApply<\n any,\n any,\n any\n >,\n> = E &\n ExecutionTaskReturn<\n E extends ExecutionTaskApply<any, any, infer TaskOutput, any>\n ? TaskOutput\n : unknown,\n E extends ExecutionTaskApply<any, any, any, infer TaskLog>\n ? TaskLog\n : unknown\n > & {\n status: 'pending' | 'running' | 'finished' | 'failed' | 'cancelled';\n error?: Error;\n errorMessage?: string;\n errorStack?: string;\n timing?: {\n start: number;\n end?: number;\n cost?: number;\n };\n usage?: AIUsageInfo;\n };\n\nexport interface ExecutionDump extends DumpMeta {\n name: string;\n description?: string;\n tasks: ExecutionTask[];\n}\n\n/*\ntask - insight-locate\n*/\nexport type ExecutionTaskInsightLocateParam = PlanningLocateParam;\n\nexport interface ExecutionTaskInsightLocateOutput {\n element: LocateResultElement | null;\n}\n\nexport interface ExecutionTaskInsightDumpLog {\n dump?: InsightDump;\n}\n\nexport type ExecutionTaskInsightLocateApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightLocateParam,\n ExecutionTaskInsightLocateOutput,\n ExecutionTaskInsightDumpLog\n>;\n\nexport type ExecutionTaskInsightLocate =\n ExecutionTask<ExecutionTaskInsightLocateApply>;\n\n/*\ntask - insight-query\n*/\nexport interface ExecutionTaskInsightQueryParam {\n dataDemand: InsightExtractParam;\n}\n\nexport interface ExecutionTaskInsightQueryOutput {\n data: any;\n}\n\nexport type ExecutionTaskInsightQueryApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightQueryParam,\n any,\n ExecutionTaskInsightDumpLog\n>;\n\nexport type ExecutionTaskInsightQuery =\n ExecutionTask<ExecutionTaskInsightQueryApply>;\n\n/*\ntask - assertion\n*/\nexport interface ExecutionTaskInsightAssertionParam {\n assertion: string;\n}\n\nexport type ExecutionTaskInsightAssertionApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightAssertionParam,\n InsightAssertionResponse,\n ExecutionTaskInsightDumpLog\n>;\n\nexport type ExecutionTaskInsightAssertion =\n ExecutionTask<ExecutionTaskInsightAssertionApply>;\n\n/*\ntask - action (i.e. interact) \n*/\nexport type ExecutionTaskActionApply<ActionParam = any> = ExecutionTaskApply<\n 'Action',\n ActionParam,\n void,\n void\n>;\n\nexport type ExecutionTaskAction = ExecutionTask<ExecutionTaskActionApply>;\n\n/*\ntask - Log\n*/\n\nexport type ExecutionTaskLogApply<\n LogParam = {\n content: string;\n },\n> = ExecutionTaskApply<'Log', LogParam, void, void>;\n\nexport type ExecutionTaskLog = ExecutionTask<ExecutionTaskLogApply>;\n\n/*\ntask - planning\n*/\n\nexport type ExecutionTaskPlanningApply = ExecutionTaskApply<\n 'Planning',\n {\n userInstruction: string;\n log?: string;\n },\n PlanningAIResponse\n>;\n\nexport type ExecutionTaskPlanning = ExecutionTask<ExecutionTaskPlanningApply>;\n\n/*\nGrouped dump\n*/\nexport interface GroupedActionDump {\n groupName: string;\n groupDescription?: string;\n executions: ExecutionDump[];\n}\n\nexport type PageType =\n | 'puppeteer'\n | 'playwright'\n | 'static'\n | 'chrome-extension-proxy'\n | 'android';\n\nexport interface StreamingCodeGenerationOptions {\n /** Whether to enable streaming output */\n stream?: boolean;\n /** Callback function to handle streaming chunks */\n onChunk?: StreamingCallback;\n /** Callback function to handle streaming completion */\n onComplete?: (finalCode: string) => void;\n /** Callback function to handle streaming errors */\n onError?: (error: Error) => void;\n}\n\nexport type StreamingCallback = (chunk: CodeGenerationChunk) => void;\n\nexport interface CodeGenerationChunk {\n /** The incremental content chunk */\n content: string;\n /** The reasoning content */\n reasoning_content: string;\n /** The accumulated content so far */\n accumulated: string;\n /** Whether this is the final chunk */\n isComplete: boolean;\n /** Token usage information if available */\n usage?: AIUsageInfo;\n}\n\nexport interface StreamingAIResponse {\n /** The final accumulated content */\n content: string;\n /** Token usage information */\n usage?: AIUsageInfo;\n /** Whether the response was streamed */\n isStreamed: boolean;\n}\n\nexport type TMultimodalPrompt = {\n /**\n * Support use image to inspect elements.\n * The \"images\" field is an object that uses image name as key and image url as value.\n * The image url can be a local path, a http link , or a base64 string.\n */\n images?: {\n name: string;\n url: string;\n }[];\n /**\n * By default, the image url in the \"images\" filed starts with `https://` or `http://` will be directly sent to the LLM.\n * In case the images are not accessible to the LLM (One common case is that image url is internal network only.), you can enable this option.\n * Then image will be download and convert to base64 format.\n */\n convertHttpImage2Base64?: boolean;\n};\n\nexport type TUserPrompt =\n | string\n | ({\n prompt: string;\n } & Partial<TMultimodalPrompt>);\n\nexport interface DeviceAction<ParamType = any> {\n name: string;\n description?: string;\n paramSchema?: string;\n paramDescription?: string;\n location?: 'required' | 'optional' | false;\n whatToLocate?: string; // what to locate if location is required or optional\n call: (param: ParamType) => Promise<void> | void;\n}\n","import { getPreferredLanguage } from '@midscene/shared/env';\nimport type { ResponseFormatJSONSchema } from 'openai/resources/index';\n\nconst defaultAssertionPrompt =\n '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.';\n\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}`;\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**.`;\n\nexport function systemPromptToAssert(model: { isUITars: boolean }) {\n return `${defaultAssertionPrompt}\n\n${model.isUITars ? getUiTarsAssertionResponseJsonFormat() : defaultAssertionResponseJsonFormat}`;\n}\n\nexport const assertSchema: ResponseFormatJSONSchema = {\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: ['string', 'null'],\n description: 'The thought process behind the assertion',\n },\n },\n required: ['pass', 'thought'],\n additionalProperties: false,\n },\n },\n};\n","import type { vlLocateMode } from '@midscene/shared/env';\nexport function bboxDescription(vlMode: ReturnType<typeof vlLocateMode>) {\n if (vlMode === 'gemini') {\n return '2d bounding box as [ymin, xmin, ymax, xmax]';\n }\n return '2d bounding box as [xmin, ymin, xmax, ymax]';\n}\n","import { PromptTemplate } from '@langchain/core/prompts';\nimport type { vlLocateMode } from '@midscene/shared/env';\nimport type { ResponseFormatJSONSchema } from 'openai/resources/index';\nimport { bboxDescription } from './common';\nexport function systemPromptToLocateElement(\n vlMode: ReturnType<typeof vlLocateMode>,\n) {\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\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,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,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}\n\nexport const locatorSchema: ResponseFormatJSONSchema = {\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: ['reason', 'text', 'id'],\n additionalProperties: false,\n },\n description: 'List of found elements',\n },\n isOrderSensitive: {\n type: 'boolean',\n description:\n '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: ['elements', 'isOrderSensitive', 'errors'],\n additionalProperties: false,\n },\n },\n};\n\nexport const findElementPrompt = new PromptTemplate({\n template: `\nHere is the item user want to find:\n=====================================\n{targetElementDescription}\n=====================================\n\n{pageDescription}\n `,\n inputVariables: ['pageDescription', 'targetElementDescription'],\n});\n","import assert from 'node:assert';\nimport type { DeviceAction } from '@/types';\nimport { PromptTemplate } from '@langchain/core/prompts';\nimport type { vlLocateMode } from '@midscene/shared/env';\nimport type { ResponseFormatJSONSchema } from 'openai/resources/index';\nimport { bboxDescription } from './common';\n\n// Note: put the log field first to trigger the CoT\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.`;\n\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: boolean) =>\n `locate${required ? '' : '?'}: {bbox: [number, number, number, number], prompt: string }`;\nconst llmLocateParam = (required: boolean) =>\n `locate${required ? '' : '?'}: {\"id\": string, \"prompt\": string}`;\n\nexport const descriptionForAction = (\n action: DeviceAction,\n locatorScheme: string,\n) => {\n const tab = ' ';\n let locateParam = '';\n if (action.location === 'required') {\n locateParam = locatorScheme;\n } else if (action.location === 'optional') {\n locateParam = `${locatorScheme} | null`;\n } else if (action.location === false) {\n locateParam = '';\n }\n const locatorParam = locateParam ? `- ${locateParam}` : '';\n\n if (action.whatToLocate) {\n if (!locateParam) {\n console.warn(\n `whatToLocate is provided for action ${action.name}, but location is not required or optional. The whatToLocate will be ignored.`,\n );\n } else {\n locateParam += ` // ${action.whatToLocate}`;\n }\n }\n\n let paramSchema = '';\n if (action.paramSchema) {\n paramSchema = `- param: ${action.paramSchema}`;\n }\n if (action.paramDescription) {\n assert(\n paramSchema,\n `paramSchema is required when paramDescription is provided for action ${action.name}, but got ${action.paramSchema}`,\n );\n paramSchema += ` // ${action.paramDescription}`;\n }\n\n const fields = [paramSchema, locatorParam].filter(Boolean);\n\n return `- ${action.name}, ${action.description}\n${tab}- type: \"${action.name}\"\n${tab}${fields.join(`\\n${tab}`)}\n`.trim();\n};\n\nconst systemTemplateOfVLPlanning = ({\n actionSpace,\n vlMode,\n}: {\n actionSpace: DeviceAction[];\n vlMode: ReturnType<typeof vlLocateMode>;\n}) => {\n const actionNameList = actionSpace.map((action) => action.name).join(', ');\n const actionDescriptionList = actionSpace.map((action) =>\n descriptionForAction(action, vlLocateParam(action.location === 'required')),\n );\n const actionList = actionDescriptionList.join('\\n');\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};\n\nconst systemTemplateOfLLM = ({\n actionSpace,\n}: { actionSpace: DeviceAction[] }) => {\n const actionNameList = actionSpace.map((action) => action.name).join(' / ');\n const actionDescriptionList = actionSpace.map((action) =>\n descriptionForAction(\n action,\n llmLocateParam(action.location === 'required'),\n ),\n );\n const actionList = actionDescriptionList.join('\\n');\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};\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`;\n\nexport async function systemPromptToTaskPlanning({\n actionSpace,\n vlMode,\n}: {\n actionSpace: DeviceAction[];\n vlMode: ReturnType<typeof vlLocateMode>;\n}) {\n if (vlMode) {\n return systemTemplateOfVLPlanning({ actionSpace, vlMode });\n }\n\n return `${systemTemplateOfLLM({ actionSpace })}\\n\\n${outputTemplate}`;\n}\n\nexport const planSchema: ResponseFormatJSONSchema = {\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:\n '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 { type: 'null' },\n {\n type: 'object',\n additionalProperties: true,\n },\n ],\n description: 'Parameter of the action',\n },\n locate: {\n type: ['object', 'null'],\n properties: {\n id: { type: 'string' },\n prompt: { type: 'string' },\n },\n required: ['id', 'prompt'],\n additionalProperties: false,\n description: 'Location information for the target element',\n },\n },\n required: ['thought', 'type', 'param', 'locate'],\n additionalProperties: false,\n },\n description: 'List of actions to be performed',\n },\n more_actions_needed_by_instruction: {\n type: 'boolean',\n description:\n '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:\n 'Log what these planned actions do. Do not include further actions that have not been planned.',\n },\n error: {\n type: ['string', 'null'],\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};\n\nexport const generateTaskBackgroundContext = (\n userInstruction: string,\n log?: string,\n userActionContext?: string,\n) => {\n if (log) {\n 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 }\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};\n\nexport const automationUserPrompt = (\n vlMode: ReturnType<typeof vlLocateMode>,\n) => {\n if (vlMode) {\n return new PromptTemplate({\n template: '{taskBackgroundContext}',\n inputVariables: ['taskBackgroundContext'],\n });\n }\n\n return new PromptTemplate({\n template: `\npageDescription:\n=====================================\n{pageDescription}\n=====================================\n\n{taskBackgroundContext}`,\n inputVariables: ['pageDescription', 'taskBackgroundContext'],\n });\n};\n","import { AIResponseFormat, type AIUsageInfo } from '@/types';\nimport type { CodeGenerationChunk, StreamingCallback } from '@/types';\nimport { Anthropic } from '@anthropic-ai/sdk';\nimport {\n DefaultAzureCredential,\n getBearerTokenProvider,\n} from '@azure/identity';\nimport {\n ANTHROPIC_API_KEY,\n AZURE_OPENAI_API_VERSION,\n AZURE_OPENAI_DEPLOYMENT,\n AZURE_OPENAI_ENDPOINT,\n AZURE_OPENAI_KEY,\n MIDSCENE_API_TYPE,\n MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON,\n MIDSCENE_AZURE_OPENAI_SCOPE,\n MIDSCENE_DEBUG_AI_PROFILE,\n MIDSCENE_DEBUG_AI_RESPONSE,\n MIDSCENE_LANGSMITH_DEBUG,\n MIDSCENE_MODEL_NAME,\n MIDSCENE_OPENAI_HTTP_PROXY,\n MIDSCENE_OPENAI_INIT_CONFIG_JSON,\n MIDSCENE_OPENAI_SOCKS_PROXY,\n MIDSCENE_USE_ANTHROPIC_SDK,\n MIDSCENE_USE_AZURE_OPENAI,\n OPENAI_API_KEY,\n OPENAI_BASE_URL,\n OPENAI_MAX_TOKENS,\n OPENAI_USE_AZURE,\n getAIConfig,\n getAIConfigInBoolean,\n getAIConfigInJson,\n uiTarsModelVersion,\n vlLocateMode,\n} from '@midscene/shared/env';\nimport { enableDebug, getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport { ifInBrowser } from '@midscene/shared/utils';\nimport { HttpsProxyAgent } from 'https-proxy-agent';\nimport { jsonrepair } from 'jsonrepair';\nimport OpenAI, { AzureOpenAI } from 'openai';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport type { Stream } from 'openai/streaming';\nimport { SocksProxyAgent } from 'socks-proxy-agent';\nimport { AIActionType, type AIArgs } from '../common';\nimport { assertSchema } from '../prompt/assertion';\nimport { locatorSchema } from '../prompt/llm-locator';\nimport { planSchema } from '../prompt/llm-planning';\n\nexport function 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\n if (openaiKey) return true;\n if (azureConfig) return true;\n if (anthropicKey) return true;\n\n return Boolean(initConfigJson);\n}\n\n// if debug config is initialized\nlet debugConfigInitialized = false;\n\nfunction initDebugConfig() {\n // if debug config is initialized, return\n if (debugConfigInitialized) return;\n\n const shouldPrintTiming = getAIConfigInBoolean(MIDSCENE_DEBUG_AI_PROFILE);\n let debugConfig = '';\n if (shouldPrintTiming) {\n console.warn(\n 'MIDSCENE_DEBUG_AI_PROFILE is deprecated, use DEBUG=midscene:ai:profile instead',\n );\n debugConfig = 'ai:profile';\n }\n const shouldPrintAIResponse = getAIConfigInBoolean(\n MIDSCENE_DEBUG_AI_RESPONSE,\n );\n if (shouldPrintAIResponse) {\n console.warn(\n 'MIDSCENE_DEBUG_AI_RESPONSE is deprecated, use DEBUG=midscene:ai:response instead',\n );\n if (debugConfig) {\n debugConfig = 'ai:*';\n } else {\n debugConfig = 'ai:call';\n }\n }\n if (debugConfig) {\n enableDebug(debugConfig);\n }\n\n // mark as initialized\n debugConfigInitialized = true;\n}\n\n// default model\nconst defaultModel = 'gpt-4o';\nexport function getModelName() {\n let modelName = defaultModel;\n const nameInConfig = getAIConfig(MIDSCENE_MODEL_NAME);\n if (nameInConfig) {\n modelName = nameInConfig;\n }\n return modelName;\n}\n\nasync function createChatClient({\n AIActionTypeValue,\n}: {\n AIActionTypeValue: AIActionType;\n}): Promise<{\n completion: OpenAI.Chat.Completions;\n style: 'openai' | 'anthropic';\n}> {\n initDebugConfig();\n let openai: OpenAI | AzureOpenAI | undefined;\n const extraConfig = getAIConfigInJson(MIDSCENE_OPENAI_INIT_CONFIG_JSON);\n\n const socksProxy = getAIConfig(MIDSCENE_OPENAI_SOCKS_PROXY);\n const httpProxy = getAIConfig(MIDSCENE_OPENAI_HTTP_PROXY);\n\n let proxyAgent = undefined;\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\n if (getAIConfig(OPENAI_USE_AZURE)) {\n // this is deprecated\n openai = new AzureOpenAI({\n baseURL: getAIConfig(OPENAI_BASE_URL),\n apiKey: getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n dangerouslyAllowBrowser: true,\n }) as OpenAI;\n } else if (getAIConfig(MIDSCENE_USE_AZURE_OPENAI)) {\n const extraAzureConfig = getAIConfigInJson(\n MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON,\n );\n\n // https://learn.microsoft.com/en-us/azure/ai-services/openai/chatgpt-quickstart?tabs=bash%2Cjavascript-key%2Ctypescript-keyless%2Cpython&pivots=programming-language-javascript#rest-api\n // keyless authentication\n const scope = getAIConfig(MIDSCENE_AZURE_OPENAI_SCOPE);\n let tokenProvider: any = undefined;\n if (scope) {\n assert(\n !ifInBrowser,\n 'Azure OpenAI is not supported in browser with Midscene.',\n );\n const credential = new DefaultAzureCredential();\n\n assert(scope, 'MIDSCENE_AZURE_OPENAI_SCOPE is required');\n tokenProvider = getBearerTokenProvider(credential, scope);\n\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 {\n // endpoint, apiKey, apiVersion, deployment\n 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 }\n } else if (!getAIConfig(MIDSCENE_USE_ANTHROPIC_SDK)) {\n const baseURL = getAIConfig(OPENAI_BASE_URL);\n if (typeof baseURL === 'string') {\n if (!/^https?:\\/\\//.test(baseURL)) {\n throw new Error(\n `OPENAI_BASE_URL must be a valid URL starting with http:// or https://, but got: ${baseURL}\\nPlease check your config.`,\n );\n }\n }\n\n openai = new OpenAI({\n baseURL: getAIConfig(OPENAI_BASE_URL),\n apiKey: getAIConfig(OPENAI_API_KEY),\n httpAgent: proxyAgent,\n ...extraConfig,\n defaultHeaders: {\n ...(extraConfig?.defaultHeaders || {}),\n [MIDSCENE_API_TYPE]: AIActionTypeValue.toString(),\n },\n dangerouslyAllowBrowser: true,\n });\n }\n\n if (openai && getAIConfigInBoolean(MIDSCENE_LANGSMITH_DEBUG)) {\n if (ifInBrowser) {\n throw new Error('langsmith is not supported in browser');\n }\n console.log('DEBUGGING MODE: langsmith wrapper enabled');\n const { wrapOpenAI } = await import('langsmith/wrappers');\n openai = wrapOpenAI(openai);\n }\n\n if (typeof openai !== 'undefined') {\n return {\n completion: openai.chat.completions,\n style: 'openai',\n };\n }\n\n // Anthropic\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 }) as any;\n }\n\n if (typeof openai !== 'undefined' && (openai as any).messages) {\n return {\n completion: (openai as any).messages,\n style: 'anthropic',\n };\n }\n\n throw new Error('Openai SDK or Anthropic SDK is not initialized');\n}\n\nexport async function call(\n messages: ChatCompletionMessageParam[],\n AIActionTypeValue: AIActionType,\n responseFormat?:\n | OpenAI.ChatCompletionCreateParams['response_format']\n | OpenAI.ResponseFormatJSONObject,\n options?: {\n stream?: boolean;\n onChunk?: StreamingCallback;\n },\n): Promise<{ content: string; usage?: AIUsageInfo; isStreamed: boolean }> {\n assert(\n checkAIConfig(),\n '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 );\n\n const { completion, style } = await createChatClient({\n AIActionTypeValue,\n });\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\n const startTime = Date.now();\n const model = getModelName();\n const isStreaming = options?.stream && options?.onChunk;\n let content: string | undefined;\n let accumulated = '';\n let usage: OpenAI.CompletionUsage | undefined;\n let timeCost: number | undefined;\n\n const commonConfig = {\n temperature: vlLocateMode() === 'vlm-ui-tars' ? 0.0 : 0.1,\n stream: !!isStreaming,\n max_tokens:\n typeof maxTokens === 'number'\n ? maxTokens\n : Number.parseInt(maxTokens || '2048', 10),\n ...(vlLocateMode() === 'qwen-vl' // qwen specific config\n ? {\n vl_high_resolution_images: true,\n }\n : {}),\n };\n\n try {\n if (style === 'openai') {\n debugCall(\n `sending ${isStreaming ? 'streaming ' : ''}request to ${model}`,\n );\n\n if (isStreaming) {\n const stream = (await completion.create(\n {\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig,\n },\n {\n stream: true,\n },\n )) as Stream<OpenAI.Chat.Completions.ChatCompletionChunk> & {\n _request_id?: string | null;\n };\n\n for await (const chunk of stream) {\n const content = chunk.choices?.[0]?.delta?.content || '';\n const reasoning_content =\n (chunk.choices?.[0]?.delta as any)?.reasoning_content || '';\n\n // Check for usage info in any chunk (OpenAI provides usage in separate chunks)\n if (chunk.usage) {\n usage = chunk.usage;\n }\n\n if (content || reasoning_content) {\n accumulated += content;\n const chunkData: CodeGenerationChunk = {\n content,\n reasoning_content,\n accumulated,\n isComplete: false,\n usage: undefined,\n };\n options.onChunk!(chunkData);\n }\n\n // Check if stream is complete\n if (chunk.choices?.[0]?.finish_reason) {\n timeCost = Date.now() - startTime;\n\n // If usage is not available from the stream, provide a basic usage info\n if (!usage) {\n // Estimate token counts based on content length (rough approximation)\n const estimatedTokens = Math.max(\n 1,\n Math.floor(accumulated.length / 4),\n );\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: estimatedTokens * 2,\n };\n }\n\n // Send final chunk\n const finalChunk: CodeGenerationChunk = {\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(\n `streaming model, ${model}, mode, ${vlLocateMode() || 'default'}, cost-ms, ${timeCost}`,\n );\n } else {\n const result = await completion.create({\n model,\n messages,\n response_format: responseFormat,\n ...commonConfig,\n } as any);\n timeCost = Date.now() - startTime;\n\n debugProfileStats(\n `model, ${model}, mode, ${vlLocateMode() || 'default'}, ui-tars-version, ${uiTarsModelVersion()}, prompt-tokens, ${result.usage?.prompt_tokens || ''}, completion-tokens, ${result.usage?.completion_tokens || ''}, total-tokens, ${result.usage?.total_tokens || ''}, cost-ms, ${timeCost}, requestId, ${result._request_id || ''}`,\n );\n\n debugProfileDetail(\n `model usage detail: ${JSON.stringify(result.usage)}`,\n );\n\n assert(\n result.choices,\n `invalid response from LLM service: ${JSON.stringify(result)}`,\n );\n content = result.choices[0].message.content!;\n usage = result.usage;\n }\n\n debugCall(`response: ${content}`);\n assert(content, 'empty content');\n } else if (style === 'anthropic') {\n const convertImageContent = (content: any) => {\n if (content.type === 'image_url') {\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,')\n ? 'image/png'\n : 'image/jpeg',\n data: imgBase64.split(',')[1],\n },\n type: 'image',\n };\n }\n return content;\n };\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)\n ? (m.content as any).map(convertImageContent)\n : m.content,\n })),\n response_format: responseFormat,\n ...commonConfig,\n } as any)) as any;\n\n for await (const chunk of stream) {\n const content = chunk.delta?.text || '';\n if (content) {\n accumulated += content;\n const chunkData: CodeGenerationChunk = {\n content,\n accumulated,\n reasoning_content: '',\n isComplete: false,\n usage: undefined,\n };\n options.onChunk!(chunkData);\n }\n\n // Check if stream is complete\n if (chunk.type === 'message_stop') {\n timeCost = Date.now() - startTime;\n const anthropicUsage = chunk.usage;\n\n // Send final chunk\n const finalChunk: CodeGenerationChunk = {\n content: '',\n accumulated,\n reasoning_content: '',\n isComplete: true,\n usage: anthropicUsage\n ? {\n prompt_tokens: anthropicUsage.input_tokens ?? 0,\n completion_tokens: anthropicUsage.output_tokens ?? 0,\n total_tokens:\n (anthropicUsage.input_tokens ?? 0) +\n (anthropicUsage.output_tokens ?? 0),\n time_cost: timeCost ?? 0,\n }\n : undefined,\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)\n ? (m.content as any).map(convertImageContent)\n : m.content,\n })),\n response_format: responseFormat,\n ...commonConfig,\n } as any);\n timeCost = Date.now() - startTime;\n content = (result as any).content[0].text as string;\n usage = result.usage;\n }\n\n assert(content, 'empty content');\n }\n // Ensure we always have usage info for streaming responses\n if (isStreaming && !usage) {\n // Estimate token counts based on content length (rough approximation)\n const estimatedTokens = Math.max(\n 1,\n Math.floor((content || '').length / 4),\n );\n usage = {\n prompt_tokens: estimatedTokens,\n completion_tokens: estimatedTokens,\n total_tokens: estimatedTokens * 2,\n };\n }\n\n return {\n content: content || '',\n usage: usage\n ? {\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 : undefined,\n isStreamed: !!isStreaming,\n };\n } catch (e: any) {\n console.error(' call AI error', e);\n const newError = new Error(\n `failed to call ${isStreaming ? 'streaming ' : ''}AI model service: ${e.message}. Trouble shooting: https://midscenejs.com/model-provider.html`,\n {\n cause: e,\n },\n );\n throw newError;\n }\n}\n\nexport async function callToGetJSONObject<T>(\n messages: ChatCompletionMessageParam[],\n AIActionTypeValue: AIActionType,\n): Promise<{ content: T; usage?: AIUsageInfo }> {\n let responseFormat:\n | OpenAI.ChatCompletionCreateParams['response_format']\n | OpenAI.ResponseFormatJSONObject\n | undefined;\n\n const model = getModelName();\n\n if (model.includes('gpt-4')) {\n switch (AIActionTypeValue) {\n case AIActionType.ASSERT:\n responseFormat = assertSchema;\n break;\n case AIActionType.INSPECT_ELEMENT:\n responseFormat = locatorSchema;\n break;\n case AIActionType.PLAN:\n responseFormat = planSchema;\n break;\n case AIActionType.EXTRACT_DATA:\n case AIActionType.DESCRIBE_ELEMENT:\n responseFormat = { type: AIResponseFormat.JSON };\n break;\n }\n }\n\n // gpt-4o-2024-05-13 only supports json_object response format\n if (model === 'gpt-4o-2024-05-13') {\n responseFormat = { type: AIResponseFormat.JSON };\n }\n\n const response = await call(messages, AIActionTypeValue, responseFormat);\n assert(response, 'empty response');\n const jsonContent = safeParseJson(response.content);\n return { content: jsonContent, usage: response.usage };\n}\n\nexport async function callAiFnWithStringResponse<T>(\n msgs: AIArgs,\n AIActionTypeValue: AIActionType,\n): Promise<{ content: string; usage?: AIUsageInfo }> {\n const { content, usage } = await call(msgs, AIActionTypeValue);\n return { content, usage };\n}\n\nexport function extractJSONFromCodeBlock(response: string) {\n try {\n // First, try to match a JSON object directly in the response\n const jsonMatch = response.match(/^\\s*(\\{[\\s\\S]*\\})\\s*$/);\n if (jsonMatch) {\n return jsonMatch[1];\n }\n\n // If no direct JSON object is found, try to extract JSON from a code block\n const codeBlockMatch = response.match(\n /```(?:json)?\\s*(\\{[\\s\\S]*?\\})\\s*```/,\n );\n if (codeBlockMatch) {\n return codeBlockMatch[1];\n }\n\n // If no code block is found, try to find a JSON-like structure in the text\n const jsonLikeMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonLikeMatch) {\n return jsonLikeMatch[0];\n }\n } catch {}\n // If no JSON-like structure is found, return the original response\n return response;\n}\n\nexport function preprocessDoubaoBboxJson(input: string) {\n if (input.includes('bbox')) {\n // when its values like 940 445 969 490, replace all /\\d+\\s+\\d+/g with /$1,$2/g\n while (/\\d+\\s+\\d+/.test(input)) {\n input = input.replace(/(\\d+)\\s+(\\d+)/g, '$1,$2');\n }\n }\n return input;\n}\n\nexport function safeParseJson(input: string) {\n const cleanJsonString = extractJSONFromCodeBlock(input);\n // match the point\n if (cleanJsonString?.match(/\\((\\d+),(\\d+)\\)/)) {\n return cleanJsonString\n .match(/\\((\\d+),(\\d+)\\)/)\n ?.slice(1)\n .map(Number);\n }\n try {\n return JSON.parse(cleanJsonString);\n } catch {}\n try {\n return JSON.parse(jsonrepair(cleanJsonString));\n } catch (e) {}\n\n if (vlLocateMode() === 'doubao-vision' || vlLocateMode() === 'vlm-ui-tars') {\n const jsonString = preprocessDoubaoBboxJson(cleanJsonString);\n return JSON.parse(jsonrepair(jsonString));\n }\n throw Error(`failed to parse json response: ${input}`);\n}\n","import type {\n AIUsageInfo,\n BaseElement,\n ElementTreeNode,\n MidsceneYamlFlowItem,\n PlanningAction,\n PlanningActionParamInputOrKeyPress,\n PlanningActionParamScroll,\n PlanningActionParamSleep,\n Rect,\n Size,\n} from '@/types';\nimport { assert } from '@midscene/shared/utils';\n\nimport type {\n ChatCompletionSystemMessageParam,\n ChatCompletionUserMessageParam,\n} from 'openai/resources/index';\nimport {\n call,\n callToGetJSONObject,\n getModelName,\n} from './service-caller/index';\n\nimport type { PlanningLocateParam } from '@/types';\nimport { NodeType } from '@midscene/shared/constants';\nimport { vlLocateMode } from '@midscene/shared/env';\nimport { treeToList } from '@midscene/shared/extractor';\nimport { compositeElementInfoImg } from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\n\nexport type AIArgs = [\n ChatCompletionSystemMessageParam,\n ...ChatCompletionUserMessageParam[],\n];\n\nexport enum AIActionType {\n ASSERT = 0,\n INSPECT_ELEMENT = 1,\n EXTRACT_DATA = 2,\n PLAN = 3,\n DESCRIBE_ELEMENT = 4,\n}\n\nexport async function callAiFn<T>(\n msgs: AIArgs,\n AIActionTypeValue: AIActionType,\n): Promise<{ content: T; usage?: AIUsageInfo }> {\n const jsonObject = await callToGetJSONObject<T>(msgs, AIActionTypeValue);\n\n return {\n content: jsonObject.content,\n usage: jsonObject.usage,\n };\n}\n\nconst defaultBboxSize = 20; // must be even number\nconst debugInspectUtils = getDebug('ai:common');\n\n// transform the param of locate from qwen mode\nexport function fillBboxParam(\n locate: PlanningLocateParam,\n width: number,\n height: number,\n) {\n // The Qwen model might have hallucinations of naming bbox as bbox_2d.\n if ((locate as any).bbox_2d && !locate?.bbox) {\n locate.bbox = (locate as any).bbox_2d;\n // biome-ignore lint/performance/noDelete: <explanation>\n delete (locate as any).bbox_2d;\n }\n\n if (locate?.bbox) {\n locate.bbox = adaptBbox(locate.bbox, width, height);\n }\n\n return locate;\n}\n\nexport function adaptQwenBbox(\n bbox: number[],\n): [number, number, number, number] {\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\n const result: [number, number, number, number] = [\n Math.round(bbox[0]),\n Math.round(bbox[1]),\n typeof bbox[2] === 'number'\n ? Math.round(bbox[2])\n : Math.round(bbox[0] + defaultBboxSize),\n typeof bbox[3] === 'number'\n ? Math.round(bbox[3])\n : Math.round(bbox[1] + defaultBboxSize),\n ];\n return result;\n}\n\nexport function adaptDoubaoBbox(\n bbox: string[] | number[] | string,\n width: number,\n height: number,\n): [number, number, number, number] {\n assert(\n width > 0 && height > 0,\n 'width and height must be greater than 0 in doubao mode',\n );\n\n if (typeof bbox === 'string') {\n assert(\n /^(\\d+)\\s(\\d+)\\s(\\d+)\\s(\\d+)$/.test(bbox.trim()),\n `invalid bbox data string for doubao-vision mode: ${bbox}`,\n );\n const splitted = bbox.split(' ');\n if (splitted.length === 4) {\n 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 }\n throw new Error(`invalid bbox data string for doubao-vision mode: ${bbox}`);\n }\n\n if (Array.isArray(bbox) && Array.isArray(bbox[0])) {\n bbox = bbox[0];\n }\n\n let bboxList: number[] = [];\n if (Array.isArray(bbox) && typeof bbox[0] === 'string') {\n bbox.forEach((item) => {\n if (typeof item === 'string' && item.includes(',')) {\n const [x, y] = item.split(',');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else if (typeof item === 'string' && item.includes(' ')) {\n const [x, y] = item.split(' ');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else {\n bboxList.push(Number(item));\n }\n });\n } else {\n bboxList = bbox as any;\n }\n\n if (bboxList.length === 4 || bboxList.length === 5) {\n 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 }\n\n // treat the bbox as a center point\n if (\n bboxList.length === 6 ||\n bboxList.length === 2 ||\n bboxList.length === 3 ||\n bboxList.length === 7\n ) {\n return [\n Math.max(\n 0,\n Math.round((bboxList[0] * width) / 1000) - defaultBboxSize / 2,\n ),\n Math.max(\n 0,\n Math.round((bboxList[1] * height) / 1000) - defaultBboxSize / 2,\n ),\n Math.min(\n width,\n Math.round((bboxList[0] * width) / 1000) + defaultBboxSize / 2,\n ),\n Math.min(\n height,\n Math.round((bboxList[1] * height) / 1000) + defaultBboxSize / 2,\n ),\n ];\n }\n\n if (bbox.length === 8) {\n 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 }\n\n const msg = `invalid bbox data for doubao-vision mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n}\n\nexport function adaptBbox(\n bbox: number[],\n width: number,\n height: number,\n): [number, number, number, number] {\n if (vlLocateMode() === 'doubao-vision' || vlLocateMode() === 'vlm-ui-tars') {\n return adaptDoubaoBbox(bbox, width, height);\n }\n\n if (vlLocateMode() === 'gemini') {\n return adaptGeminiBbox(bbox, width, height);\n }\n\n return adaptQwenBbox(bbox);\n}\n\nexport function adaptGeminiBbox(\n bbox: number[],\n width: number,\n height: number,\n): [number, number, number, number] {\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 [left, top, right, bottom];\n}\n\nexport function adaptBboxToRect(\n bbox: number[],\n width: number,\n height: number,\n offsetX = 0,\n offsetY = 0,\n): Rect {\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}\n\nlet warned = false;\nexport function warnGPT4oSizeLimit(size: Size) {\n if (warned) return;\n if (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\n if (\n Math.max(size.width, size.height) > 2000 ||\n Math.min(size.width, size.height) > 768\n ) {\n console.warn(warningMsg);\n warned = true;\n }\n } else if (size.width > 1800 || size.height > 1800) {\n console.warn(\n `The image size seems too large (${size.width}x${size.height}). It may lead to more token usage, slower response, and inaccurate result.`,\n );\n warned = true;\n }\n}\n\nexport function mergeRects(rects: Rect[]) {\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}\n\n// expand the search area to at least 300 x 300, or add a default padding\nexport function expandSearchArea(rect: Rect, screenSize: Size) {\n const minEdgeSize = vlLocateMode() === 'doubao-vision' ? 500 : 300;\n const defaultPadding = 160;\n\n const paddingSizeHorizontal =\n rect.width < minEdgeSize\n ? Math.ceil((minEdgeSize - rect.width) / 2)\n : defaultPadding;\n const paddingSizeVertical =\n rect.height < minEdgeSize\n ? Math.ceil((minEdgeSize - rect.height) / 2)\n : defaultPadding;\n rect.left = Math.max(0, rect.left - paddingSizeHorizontal);\n rect.width = Math.min(\n rect.width + paddingSizeHorizontal * 2,\n screenSize.width - rect.left,\n );\n rect.top = Math.max(0, rect.top - paddingSizeVertical);\n rect.height = Math.min(\n rect.height + paddingSizeVertical * 2,\n screenSize.height - rect.top,\n );\n return rect;\n}\n\nexport async function markupImageForLLM(\n screenshotBase64: string,\n tree: ElementTreeNode<BaseElement>,\n size: Size,\n) {\n const elementsInfo = treeToList(tree);\n const elementsPositionInfoWithoutText = elementsInfo!.filter(\n (elementInfo) => {\n if (elementInfo.attributes.nodeType === NodeType.TEXT) {\n return false;\n }\n return true;\n },\n );\n\n const imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n elementsPositionInfo: elementsPositionInfoWithoutText,\n size,\n });\n return imagePayload;\n}\n\nexport function buildYamlFlowFromPlans(\n plans: PlanningAction[],\n sleep?: number,\n): MidsceneYamlFlowItem[] {\n const flow: MidsceneYamlFlowItem[] = [];\n\n for (const plan of plans) {\n const type = plan.type;\n const locate = plan.locate?.prompt!; // TODO: check if locate is null\n\n if (type === 'Tap') {\n flow.push({\n aiTap: locate!,\n });\n } else if (type === 'Hover') {\n flow.push({\n aiHover: locate!,\n });\n } else if (type === 'Input') {\n const param = plan.param as PlanningActionParamInputOrKeyPress;\n flow.push({\n aiInput: param.value,\n locate,\n });\n } else if (type === 'KeyboardPress') {\n const param = plan.param as PlanningActionParamInputOrKeyPress;\n flow.push({\n aiKeyboardPress: param.value,\n locate,\n });\n } else if (type === 'Scroll') {\n const param = plan.param as PlanningActionParamScroll;\n flow.push({\n aiScroll: null,\n locate,\n direction: param.direction,\n scrollType: param.scrollType,\n distance: param.distance,\n });\n } else if (type === 'Sleep') {\n const param = plan.param as PlanningActionParamSleep;\n flow.push({\n sleep: param.timeMs,\n });\n } else if (\n type === 'AndroidBackButton' ||\n type === 'AndroidHomeButton' ||\n type === 'AndroidRecentAppsButton' ||\n type === 'AndroidLongPress' ||\n type === 'AndroidPull'\n ) {\n // not implemented in yaml yet\n } else if (\n type === 'Error' ||\n type === 'Assert' ||\n type === 'AssertWithoutThrow' ||\n type === 'Finished'\n ) {\n // do nothing\n } else {\n console.warn(\n `Cannot convert action ${type} to yaml flow. This should be a bug of Midscene.`,\n );\n }\n }\n\n if (sleep) {\n flow.push({\n sleep: sleep,\n });\n }\n\n return flow;\n}\n","import { imageInfoOfBase64 } from '@/image/index';\nimport type { BaseElement, ElementTreeNode, Size, UIContext } from '@/types';\nimport { NodeType } from '@midscene/shared/constants';\nimport { vlLocateMode } from '@midscene/shared/env';\nimport {\n descriptionOfTree,\n generateElementByPosition,\n treeToList,\n} from '@midscene/shared/extractor';\nimport { assert } from '@midscene/shared/utils';\n\nexport function describeSize(size: Size) {\n return `${size.width} x ${size.height}`;\n}\n\nexport function describeElement(\n elements: (Pick<BaseElement, 'rect' | 'content'> & { id: string })[],\n) {\n const sliceLength = 80;\n return elements\n .map((item) =>\n [\n item.id,\n item.rect.left,\n item.rect.top,\n item.rect.left + item.rect.width,\n item.rect.top + item.rect.height,\n item.content.length > sliceLength\n ? `${item.content.slice(0, sliceLength)}...`\n : item.content,\n ].join(', '),\n )\n .join('\\n');\n}\nexport const distanceThreshold = 16;\n\nexport function elementByPositionWithElementInfo(\n treeRoot: ElementTreeNode<BaseElement>,\n position: {\n x: number;\n y: number;\n },\n options?: {\n requireStrictDistance?: boolean;\n filterPositionElements?: boolean;\n },\n) {\n const requireStrictDistance = options?.requireStrictDistance ?? true;\n const filterPositionElements = options?.filterPositionElements ?? false;\n\n assert(typeof position !== 'undefined', 'position is required for query');\n\n const matchingElements: BaseElement[] = [];\n\n function dfs(node: ElementTreeNode<BaseElement>) {\n if (node?.node) {\n const item = node.node;\n if (\n item.rect.left <= position.x &&\n position.x <= item.rect.left + item.rect.width &&\n item.rect.top <= position.y &&\n position.y <= item.rect.top + item.rect.height\n ) {\n if (\n !(\n filterPositionElements &&\n item.attributes?.nodeType === NodeType.POSITION\n ) &&\n item.isVisible\n ) {\n matchingElements.push(item);\n }\n }\n }\n\n for (const child of node.children) {\n dfs(child);\n }\n }\n\n dfs(treeRoot);\n\n if (matchingElements.length === 0) {\n return undefined;\n }\n\n // Find the smallest element by area\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\n const distanceToCenter = distance(\n { x: element.center[0], y: element.center[1] },\n position,\n );\n\n if (requireStrictDistance) {\n return distanceToCenter <= distanceThreshold ? element : undefined;\n }\n\n return element;\n}\n\nexport function distance(\n point1: { x: number; y: number },\n point2: { x: number; y: number },\n) {\n return Math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2);\n}\n\nexport const samplePageDescription = `\nAnd the page is described as follows:\n====================\nThe size of the page: 1280 x 720\nSome of the elements are marked with a rectangle in the screenshot corresponding to the markerId, some are not.\n\nDescription of all the elements in screenshot:\n<div id=\"969f1637\" markerId=\"1\" left=\"100\" top=\"100\" width=\"100\" height=\"100\"> // The markerId indicated by the rectangle label in the screenshot\n <h4 id=\"b211ecb2\" markerId=\"5\" left=\"150\" top=\"150\" width=\"90\" height=\"60\">\n The username is accepted\n </h4>\n ...many more\n</div>\n====================\n`;\n\nexport async function describeUserPage<\n ElementType extends BaseElement = BaseElement,\n>(\n context: Omit<UIContext<ElementType>, 'describer'>,\n opt?: {\n truncateTextLength?: number;\n filterNonTextContent?: boolean;\n domIncluded?: boolean | 'visible-only';\n visibleOnly?: boolean;\n },\n) {\n const { screenshotBase64 } = context;\n let width: number;\n let height: number;\n\n if (context.size) {\n ({ width, height } = context.size);\n } else {\n const imgSize = await imageInfoOfBase64(screenshotBase64);\n ({ width, height } = imgSize);\n }\n\n const treeRoot = context.tree;\n // dfs tree, save the id and element info\n const idElementMap: Record<string, ElementType> = {};\n const flatElements: ElementType[] = treeToList(treeRoot);\n\n if (opt?.domIncluded === true && flatElements.length >= 5000) {\n console.warn(\n '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 );\n }\n\n flatElements.forEach((element) => {\n idElementMap[element.id] = element;\n if (typeof element.indexId !== 'undefined') {\n idElementMap[`${element.indexId}`] = element;\n }\n });\n\n let pageDescription = '';\n const visibleOnly = opt?.visibleOnly ?? opt?.domIncluded === 'visible-only';\n if (opt?.domIncluded || !vlLocateMode()) {\n // non-vl mode must provide the page description\n const contentTree = await descriptionOfTree(\n treeRoot,\n opt?.truncateTextLength,\n opt?.filterNonTextContent,\n visibleOnly,\n );\n\n // if match by position, don't need to provide the page description\n const sizeDescription = describeSize({ width, height });\n pageDescription = `The size of the page: ${sizeDescription} \\n The page elements tree:\\n${contentTree}`;\n }\n\n return {\n description: pageDescription,\n elementById(idOrIndexId: string) {\n assert(typeof idOrIndexId !== 'undefined', 'id is required for query');\n const item = idElementMap[`${idOrIndexId}`];\n return item;\n },\n elementByPosition(\n position: { x: number; y: number },\n size: { width: number; height: number },\n ) {\n return elementByPositionWithElementInfo(treeRoot, position);\n },\n insertElementByPosition(position: { x: number; y: number }) {\n const element = generateElementByPosition(position) as ElementType;\n\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: { width, height },\n };\n}\n","import { PromptTemplate } from '@langchain/core/prompts';\nimport type { ResponseFormatJSONSchema } from 'openai/resources/index';\n\nexport function 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}\n\nexport const extractDataQueryPrompt = async (\n pageDescription: string,\n dataQuery: string | Record<string, string>,\n) => {\n let dataQueryText = '';\n if (typeof dataQuery === 'string') {\n dataQueryText = dataQuery;\n } else {\n dataQueryText = JSON.stringify(dataQuery, null, 2);\n }\n const extractDataPrompt = new PromptTemplate({\n template: `\n<PageDescription>\n{pageDescription}\n</PageDescription>\n\n<DATA_DEMAND>\n{dataQuery}\n</DATA_DEMAND>\n `,\n inputVariables: ['pageDescription', 'dataQuery'],\n });\n\n return await extractDataPrompt.format({\n pageDescription,\n dataQuery: dataQueryText,\n });\n};\n\nexport const extractDataSchema: ResponseFormatJSONSchema = {\n type: 'json_schema',\n json_schema: {\n name: 'extract_data',\n strict: true,\n schema: {\n type: 'object',\n properties: {\n data: {\n type: 'object',\n description: 'The extracted data',\n },\n errors: {\n type: 'array',\n items: {\n type: 'string',\n },\n description: 'Error messages, if any',\n },\n },\n required: ['data', 'errors'],\n additionalProperties: false,\n },\n },\n};\n","import { PromptTemplate } from '@langchain/core/prompts';\nimport type { vlLocateMode } from '@midscene/shared/env';\nimport { bboxDescription } from './common';\n\nexport function systemPromptToLocateSection(\n vlMode: ReturnType<typeof vlLocateMode>,\n) {\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}\n\nexport const sectionLocatorInstruction = new PromptTemplate({\n template: `Here is the target element user interested in:\n<targetDescription>\n{sectionDescription}\n</targetDescription>\n `,\n inputVariables: ['sectionDescription'],\n});\n","import type {\n AIAssertionResponse,\n AIDataExtractionResponse,\n AIElementLocatorResponse,\n AIElementResponse,\n AISectionLocatorResponse,\n AIUsageInfo,\n BaseElement,\n ElementById,\n InsightExtractOption,\n Rect,\n ReferenceImage,\n TMultimodalPrompt,\n TUserPrompt,\n UIContext,\n} from '@/types';\nimport {\n MIDSCENE_USE_QWEN_VL,\n MIDSCENE_USE_VLM_UI_TARS,\n getAIConfigInBoolean,\n vlLocateMode,\n} from '@midscene/shared/env';\nimport {\n cropByRect,\n paddingToMatchBlockByBase64,\n preProcessImageUrl,\n} from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type {\n ChatCompletionSystemMessageParam,\n ChatCompletionUserMessageParam,\n} from 'openai/resources/index';\nimport {\n AIActionType,\n adaptBboxToRect,\n callAiFn,\n expandSearchArea,\n markupImageForLLM,\n mergeRects,\n} from './common';\nimport { systemPromptToAssert } from './prompt/assertion';\nimport {\n extractDataQueryPrompt,\n systemPromptToExtract,\n} from './prompt/extraction';\nimport {\n findElementPrompt,\n systemPromptToLocateElement,\n} from './prompt/llm-locator';\nimport {\n sectionLocatorInstruction,\n systemPromptToLocateSection,\n} from './prompt/llm-section-locator';\nimport {\n describeUserPage,\n distance,\n distanceThreshold,\n elementByPositionWithElementInfo,\n} from './prompt/util';\nimport { callToGetJSONObject } from './service-caller/index';\n\nexport type AIArgs = [\n ChatCompletionSystemMessageParam,\n ...ChatCompletionUserMessageParam[],\n];\n\nconst debugInspect = getDebug('ai:inspect');\nconst debugSection = getDebug('ai:section');\n\nconst extraTextFromUserPrompt = (prompt: TUserPrompt): string => {\n if (typeof prompt === 'string') {\n return prompt;\n } else {\n return prompt.prompt;\n }\n};\n\nconst promptsToChatParam = async (\n multimodalPrompt: TMultimodalPrompt,\n): Promise<ChatCompletionUserMessageParam[]> => {\n const msgs: ChatCompletionUserMessageParam[] = [];\n if (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\n for (const item of multimodalPrompt.images) {\n const base64 = await preProcessImageUrl(\n item.url,\n !!multimodalPrompt.convertHttpImage2Base64,\n );\n\n msgs.push({\n role: 'user',\n content: [\n {\n type: 'text',\n text: `reference image ${item.name}:`,\n },\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};\n\nexport async function AiLocateElement<\n ElementType extends BaseElement = BaseElement,\n>(options: {\n context: UIContext<ElementType>;\n targetElementDescription: TUserPrompt;\n referenceImage?: ReferenceImage;\n callAI?: typeof callAiFn<AIElementResponse | [number, number]>;\n searchConfig?: Awaited<ReturnType<typeof AiLocateSection>>;\n}): Promise<{\n parseResult: AIElementLocatorResponse;\n rect?: Rect;\n rawResponse: string;\n elementById: ElementById;\n usage?: AIUsageInfo;\n isOrderSensitive?: boolean;\n}> {\n const { context, targetElementDescription, callAI } = options;\n const { screenshotBase64 } = context;\n const { description, elementById, insertElementByPosition } =\n await describeUserPage(context);\n\n assert(\n targetElementDescription,\n 'cannot find the target element description',\n );\n\n const userInstructionPrompt = await findElementPrompt.format({\n pageDescription: description,\n targetElementDescription: extraTextFromUserPrompt(targetElementDescription),\n });\n const systemPrompt = systemPromptToLocateElement(vlLocateMode());\n\n let imagePayload = screenshotBase64;\n\n if (options.searchConfig) {\n assert(\n options.searchConfig.rect,\n 'searchArea is provided but its rect cannot be found. Failed to locate element',\n );\n assert(\n options.searchConfig.imageBase64,\n 'searchArea is provided but its imageBase64 cannot be found. Failed to locate element',\n );\n\n imagePayload = options.searchConfig.imageBase64;\n } else if (vlLocateMode() === 'qwen-vl') {\n imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n } else if (!vlLocateMode()) {\n imagePayload = await markupImageForLLM(\n screenshotBase64,\n context.tree,\n context.size,\n );\n }\n\n const msgs: AIArgs = [\n { role: 'system', content: systemPrompt },\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\n if (typeof targetElementDescription !== 'string') {\n const addOns = await promptsToChatParam({\n images: targetElementDescription.images,\n convertHttpImage2Base64: targetElementDescription.convertHttpImage2Base64,\n });\n msgs.push(...addOns);\n }\n\n const callAIFn =\n callAI || callToGetJSONObject<AIElementResponse | [number, number]>;\n\n const res = await callAIFn(msgs, AIActionType.INSPECT_ELEMENT);\n\n const rawResponse = JSON.stringify(res.content);\n\n let resRect: Rect | undefined;\n let matchedElements: AIElementLocatorResponse['elements'] =\n 'elements' in res.content ? res.content.elements : [];\n let errors: AIElementLocatorResponse['errors'] | undefined =\n 'errors' in res.content ? res.content.errors : [];\n try {\n if ('bbox' in res.content && Array.isArray(res.content.bbox)) {\n resRect = adaptBboxToRect(\n res.content.bbox,\n options.searchConfig?.rect?.width || context.size.width,\n options.searchConfig?.rect?.height || context.size.height,\n options.searchConfig?.rect?.left,\n options.searchConfig?.rect?.top,\n );\n debugInspect('resRect', resRect);\n\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\n const distanceToCenter = element\n ? distance({ x: element.center[0], y: element.center[1] }, rectCenter)\n : 0;\n\n if (!element || distanceToCenter > distanceThreshold) {\n element = insertElementByPosition(rectCenter);\n }\n\n if (element) {\n matchedElements = [element];\n errors = [];\n }\n }\n } catch (e) {\n const msg =\n e instanceof Error\n ? `Failed to parse bbox: ${e.message}`\n : 'unknown error in locate';\n if (!errors || errors?.length === 0) {\n errors = [msg];\n } else {\n errors.push(`(${msg})`);\n }\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:\n typeof res.content === 'object' &&\n res.content !== null &&\n 'isOrderSensitive' in res.content\n ? (res.content as any).isOrderSensitive\n : undefined,\n };\n}\n\nexport async function AiLocateSection(options: {\n context: UIContext<BaseElement>;\n sectionDescription: TUserPrompt;\n callAI?: typeof callAiFn<AISectionLocatorResponse>;\n}): Promise<{\n rect?: Rect;\n imageBase64?: string;\n error?: string;\n rawResponse: string;\n usage?: AIUsageInfo;\n}> {\n const { context, sectionDescription } = options;\n const { screenshotBase64 } = context;\n\n const systemPrompt = systemPromptToLocateSection(vlLocateMode());\n const sectionLocatorInstructionText = await sectionLocatorInstruction.format({\n sectionDescription: extraTextFromUserPrompt(sectionDescription),\n });\n const msgs: AIArgs = [\n { role: 'system', content: systemPrompt },\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\n if (typeof sectionDescription !== 'string') {\n const addOns = await promptsToChatParam({\n images: sectionDescription.images,\n convertHttpImage2Base64: sectionDescription.convertHttpImage2Base64,\n });\n msgs.push(...addOns);\n }\n\n const result = await callAiFn<AISectionLocatorResponse>(\n msgs,\n AIActionType.EXTRACT_DATA,\n );\n\n let sectionRect: Rect | undefined;\n const sectionBbox = result.content.bbox;\n if (sectionBbox) {\n const targetRect = adaptBboxToRect(\n sectionBbox,\n context.size.width,\n context.size.height,\n );\n debugSection('original targetRect %j', targetRect);\n\n const referenceBboxList = result.content.references_bbox || [];\n debugSection('referenceBboxList %j', referenceBboxList);\n\n const referenceRects = referenceBboxList\n .filter((bbox) => Array.isArray(bbox))\n .map((bbox) => {\n return adaptBboxToRect(bbox, context.size.width, context.size.height);\n });\n debugSection('referenceRects %j', referenceRects);\n\n // merge the sectionRect and referenceRects\n const mergedRect = mergeRects([targetRect, ...referenceRects]);\n debugSection('mergedRect %j', mergedRect);\n\n // expand search area to at least 200 x 200\n sectionRect = expandSearchArea(mergedRect, context.size);\n debugSection('expanded sectionRect %j', sectionRect);\n }\n\n let imageBase64 = screenshotBase64;\n if (sectionRect) {\n imageBase64 = await cropByRect(\n screenshotBase64,\n sectionRect,\n getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL),\n );\n }\n\n return {\n rect: sectionRect,\n imageBase64,\n error: result.content.error,\n rawResponse: JSON.stringify(result.content),\n usage: result.usage,\n };\n}\n\nexport async function AiExtractElementInfo<\n T,\n ElementType extends BaseElement = BaseElement,\n>(options: {\n dataQuery: string | Record<string, string>;\n multimodalPrompt?: TMultimodalPrompt;\n context: UIContext<ElementType>;\n extractOption?: InsightExtractOption;\n}) {\n const { dataQuery, context, extractOption, multimodalPrompt } = options;\n const systemPrompt = systemPromptToExtract();\n\n const { screenshotBase64 } = context;\n const { description, elementById } = await describeUserPage(context, {\n truncateTextLength: 200,\n filterNonTextContent: false,\n visibleOnly: false,\n domIncluded: extractOption?.domIncluded,\n });\n\n const extractDataPromptText = await extractDataQueryPrompt(\n description,\n dataQuery,\n );\n\n const userContent: ChatCompletionUserMessageParam['content'] = [];\n\n if (extractOption?.screenshotIncluded !== false) {\n userContent.push({\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high',\n },\n });\n }\n\n userContent.push({\n type: 'text',\n text: extractDataPromptText,\n });\n\n const msgs: AIArgs = [\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: userContent,\n },\n ];\n\n if (options.extractOption?.returnThought) {\n msgs.push({\n role: 'user',\n content: 'Please provide reasons.',\n });\n }\n\n if (multimodalPrompt) {\n const addOns = await promptsToChatParam({\n images: multimodalPrompt.images,\n convertHttpImage2Base64: multimodalPrompt.convertHttpImage2Base64,\n });\n msgs.push(...addOns);\n }\n\n const result = await callAiFn<AIDataExtractionResponse<T>>(\n msgs,\n AIActionType.EXTRACT_DATA,\n );\n return {\n parseResult: result.content,\n elementById,\n usage: result.usage,\n };\n}\n\nexport async function AiAssert<\n ElementType extends BaseElement = BaseElement,\n>(options: { assertion: TUserPrompt; context: UIContext<ElementType> }) {\n const { assertion, context } = options;\n\n assert(assertion, 'assertion should not be empty');\n\n const { screenshotBase64 } = context;\n\n const systemPrompt = systemPromptToAssert({\n isUITars: getAIConfigInBoolean(MIDSCENE_USE_VLM_UI_TARS),\n });\n\n const assertionText = extraTextFromUserPrompt(assertion);\n\n const msgs: AIArgs = [\n { role: 'system', content: systemPrompt },\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\n if (typeof assertion !== 'string') {\n const addOns = await promptsToChatParam({\n images: assertion.images,\n convertHttpImage2Base64: assertion.convertHttpImage2Base64,\n });\n msgs.push(...addOns);\n }\n\n const { content: assertResult, usage } = await callAiFn<AIAssertionResponse>(\n msgs,\n AIActionType.ASSERT,\n );\n return {\n content: assertResult,\n usage,\n };\n}\n","import type {\n DeviceAction,\n PageType,\n PlanningAIResponse,\n UIContext,\n} from '@/types';\nimport { vlLocateMode } from '@midscene/shared/env';\nimport { paddingToMatchBlockByBase64 } from '@midscene/shared/img';\nimport { assert } from '@midscene/shared/utils';\nimport {\n AIActionType,\n type AIArgs,\n buildYamlFlowFromPlans,\n callAiFn,\n fillBboxParam,\n markupImageForLLM,\n warnGPT4oSizeLimit,\n} from './common';\nimport {\n automationUserPrompt,\n generateTaskBackgroundContext,\n systemPromptToTaskPlanning,\n} from './prompt/llm-planning';\nimport { describeUserPage } from './prompt/util';\n\nexport async function plan(\n userInstruction: string,\n opts: {\n context: UIContext;\n pageType: PageType;\n actionSpace: DeviceAction[];\n callAI?: typeof callAiFn<PlanningAIResponse>;\n log?: string;\n actionContext?: string;\n },\n): Promise<PlanningAIResponse> {\n const { callAI, context } = opts || {};\n const { screenshotBase64, size } = context;\n const { description: pageDescription, elementById } =\n await describeUserPage(context);\n\n const systemPrompt = await systemPromptToTaskPlanning({\n actionSpace: opts.actionSpace,\n vlMode: vlLocateMode(),\n });\n const taskBackgroundContextText = generateTaskBackgroundContext(\n userInstruction,\n opts.log,\n opts.actionContext,\n );\n const userInstructionPrompt = await automationUserPrompt(\n vlLocateMode(),\n ).format({\n pageDescription,\n taskBackgroundContext: taskBackgroundContextText,\n });\n\n let imagePayload = screenshotBase64;\n if (vlLocateMode() === 'qwen-vl') {\n imagePayload = await paddingToMatchBlockByBase64(imagePayload);\n } else if (!vlLocateMode()) {\n imagePayload = await markupImageForLLM(\n screenshotBase64,\n context.tree,\n context.size,\n );\n }\n\n warnGPT4oSizeLimit(size);\n\n const msgs: AIArgs = [\n { role: 'system', content: systemPrompt },\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\n const call = callAI || callAiFn;\n const { content, usage } = await call(msgs, AIActionType.PLAN);\n const rawResponse = JSON.stringify(content, undefined, 2);\n const planFromAI = content;\n\n const actions =\n (planFromAI.action?.type ? [planFromAI.action] : planFromAI.actions) || [];\n const returnValue: PlanningAIResponse = {\n ...planFromAI,\n actions,\n rawResponse,\n usage,\n yamlFlow: buildYamlFlowFromPlans(actions, planFromAI.sleep),\n };\n\n assert(planFromAI, \"can't get plans from AI\");\n\n if (vlLocateMode()) {\n actions.forEach((action) => {\n if (action.locate) {\n try {\n action.locate = fillBboxParam(action.locate, size.width, size.height);\n } catch (e) {\n throw new Error(\n `Failed to fill locate param: ${planFromAI.error} (${\n e instanceof Error ? e.message : 'unknown error'\n })`,\n {\n cause: e,\n },\n );\n }\n }\n });\n // in Qwen-VL, error means error. In GPT-4o, error may mean more actions are needed.\n assert(!planFromAI.error, `Failed to plan actions: ${planFromAI.error}`);\n } else {\n actions.forEach((action) => {\n if (action.locate?.id) {\n // The model may return indexId, need to perform a query correction to avoid exceptions\n const element = elementById(action.locate.id);\n if (element) {\n action.locate.id = element.id;\n }\n }\n });\n }\n\n if (\n actions.length === 0 &&\n returnValue.more_actions_needed_by_instruction &&\n !returnValue.sleep\n ) {\n console.warn(\n 'No actions planned for the prompt, but model said more actions are needed:',\n userInstruction,\n );\n }\n\n return returnValue;\n}\n","import type {\n AIUsageInfo,\n MidsceneYamlFlowItem,\n PlanningAction,\n Size,\n} from '@/types';\nimport {\n UITarsModelVersion,\n uiTarsModelVersion,\n vlLocateMode,\n} from '@midscene/shared/env';\nimport { resizeImgBase64 } from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { transformHotkeyInput } from '@midscene/shared/us-keyboard-layout';\nimport { assert } from '@midscene/shared/utils';\nimport { actionParser } from '@ui-tars/action-parser';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport { AIActionType } from './common';\nimport { getSummary, getUiTarsPlanningPrompt } from './prompt/ui-tars-planning';\nimport { call } from './service-caller/index';\ntype ActionType =\n | 'click'\n | 'drag'\n | 'type'\n | 'hotkey'\n | 'finished'\n | 'scroll'\n | 'wait'\n | 'androidBackButton'\n | 'androidHomeButton'\n | 'androidRecentAppsButton'\n | 'androidLongPress'\n | 'androidPull';\n\nconst debug = getDebug('ui-tars-planning');\nconst bboxSize = 10;\nconst pointToBbox = (\n point: { x: number; y: number },\n width: number,\n height: number,\n): [number, number, number, number] => {\n return [\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 ];\n};\n\nexport async function vlmPlanning(options: {\n userInstruction: string;\n conversationHistory: ChatCompletionMessageParam[];\n size: { width: number; height: number };\n}): Promise<{\n actions: PlanningAction<any>[];\n actionsFromModel: ReturnType<typeof actionParser>['parsed'];\n action_summary: string;\n yamlFlow?: MidsceneYamlFlowItem[];\n usage?: AIUsageInfo;\n rawResponse?: string;\n}> {\n const { conversationHistory, userInstruction, size } = options;\n const systemPrompt = getUiTarsPlanningPrompt() + userInstruction;\n\n const res = await call(\n [\n {\n role: 'user',\n content: systemPrompt,\n },\n ...conversationHistory,\n ],\n AIActionType.INSPECT_ELEMENT,\n );\n const convertedText = convertBboxToCoordinates(res.content);\n\n const modelVer = uiTarsModelVersion();\n\n const { parsed } = actionParser({\n prediction: convertedText,\n factor: [1000, 1000],\n screenContext: {\n width: size.width,\n height: size.height,\n },\n modelVer: modelVer || undefined,\n });\n\n debug('modelVer', modelVer, 'parsed', JSON.stringify(parsed));\n\n const transformActions: PlanningAction[] = [];\n parsed.forEach((action) => {\n if (action.action_type === 'click') {\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], y: point[1] },\n size.width,\n size.height,\n ),\n },\n });\n transformActions.push({\n type: 'Tap',\n locate: {\n prompt: action.thought || '',\n bbox: pointToBbox(\n { x: point[0], y: point[1] },\n size.width,\n size.height,\n ),\n },\n param: action.thought || '',\n });\n } else if (action.action_type === 'drag') {\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: { x: startPoint[0], y: startPoint[1] },\n end_box: { x: endPoint[0], y: endPoint[1] },\n },\n locate: null,\n thought: action.thought || '',\n });\n } else if (action.action_type === 'type') {\n 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 (action.action_type === 'scroll') {\n 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 (action.action_type === 'finished') {\n transformActions.push({\n type: 'Finished',\n param: {},\n locate: null,\n thought: action.thought || '',\n });\n } else if (action.action_type === 'hotkey') {\n if (!action.action_inputs.key) {\n console.warn(\n 'No key found in action: hotkey. Will not perform action.',\n );\n } else {\n const keys = transformHotkeyInput(action.action_inputs.key);\n\n transformActions.push({\n type: 'KeyboardPress',\n param: {\n value: keys,\n },\n locate: null,\n thought: action.thought || '',\n });\n }\n } else if (action.action_type === 'wait') {\n transformActions.push({\n type: 'Sleep',\n param: {\n timeMs: 1000,\n },\n locate: null,\n thought: action.thought || '',\n });\n } else if (action.action_type === 'androidBackButton') {\n transformActions.push({\n type: 'AndroidBackButton',\n param: {},\n locate: null,\n thought: action.thought || '',\n });\n } else if (action.action_type === 'androidHomeButton') {\n transformActions.push({\n type: 'AndroidHomeButton',\n param: {},\n locate: null,\n thought: action.thought || '',\n });\n } else if (action.action_type === 'androidRecentAppsButton') {\n transformActions.push({\n type: 'AndroidRecentAppsButton',\n param: {},\n });\n } else if (action.action_type === 'androidLongPress') {\n assert(\n action.action_inputs.start_coords,\n 'start_coords is required for androidLongPress',\n );\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 (action.action_type === 'androidPull') {\n const pullDirection = action.action_inputs.direction || 'down';\n const startPoint = action.action_inputs.start_coords\n ? {\n x: action.action_inputs.start_coords[0],\n y: action.action_inputs.start_coords[1],\n }\n : undefined;\n\n transformActions.push({\n type: 'AndroidPull',\n param: {\n direction: pullDirection as 'up' | 'down',\n startPoint,\n distance: (action.action_inputs as any).distance,\n duration: (action.action_inputs as any).duration || 500,\n },\n locate: null,\n thought: action.thought || '',\n });\n }\n });\n\n if (transformActions.length === 0) {\n throw new Error(`No actions found, response: ${res.content}`, {\n cause: {\n prediction: res.content,\n parsed,\n },\n });\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, undefined, 2),\n };\n}\n\n/**\n * Converts bounding box notation to coordinate points\n * @param text - The text containing bbox tags to be converted\n * @returns The text with bbox tags replaced by coordinate points\n */\nfunction convertBboxToCoordinates(text: string): string {\n // Match the four numbers after <bbox>\n const pattern = /<bbox>(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)<\\/bbox>/g;\n\n function replaceMatch(\n match: string,\n x1: string,\n y1: string,\n x2: string,\n y2: string,\n ): string {\n // Convert strings to numbers and calculate center point\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\n // Use Math.floor to truncate and calculate center point\n const x = Math.floor((x1Num + x2Num) / 2);\n const y = Math.floor((y1Num + y2Num) / 2);\n\n // Return formatted coordinate string\n return `(${x},${y})`;\n }\n\n // Remove [EOS] and replace <bbox> coordinates\n const cleanedText = text.replace(/\\[EOS\\]/g, '');\n return cleanedText.replace(pattern, replaceMatch).trim();\n}\n\nfunction getPoint(startBox: string, size: { width: number; height: number }) {\n const [x, y] = JSON.parse(startBox);\n return [x * size.width, y * size.height];\n}\n\ninterface BaseAction {\n action_type: ActionType;\n action_inputs: Record<string, any>;\n reflection: string | null;\n thought: string | null;\n}\n\ninterface ClickAction extends BaseAction {\n action_type: 'click';\n action_inputs: {\n start_box: string; // JSON string of [x, y] coordinates\n };\n}\n\ninterface DragAction extends BaseAction {\n action_type: 'drag';\n action_inputs: {\n start_box: string; // JSON string of [x, y] coordinates\n end_box: string; // JSON string of [x, y] coordinates\n };\n}\n\ninterface WaitAction extends BaseAction {\n action_type: 'wait';\n action_inputs: {\n time: string; // JSON string of [x, y] coordinates\n };\n}\n\ninterface TypeAction extends BaseAction {\n action_type: 'type';\n action_inputs: {\n content: string;\n };\n}\n\ninterface HotkeyAction extends BaseAction {\n action_type: 'hotkey';\n action_inputs: {\n key: string;\n };\n}\n\ninterface ScrollAction extends BaseAction {\n action_type: 'scroll';\n action_inputs: {\n direction: 'up' | 'down';\n };\n}\n\ninterface FinishedAction extends BaseAction {\n action_type: 'finished';\n action_inputs: Record<string, never>;\n}\n\ninterface AndroidLongPressAction extends BaseAction {\n action_type: 'androidLongPress';\n action_inputs: {\n start_coords: [number, number]; // Coordinates for long press\n duration?: number; // Duration in milliseconds\n };\n}\n\nexport type Action =\n | ClickAction\n | DragAction\n | TypeAction\n | HotkeyAction\n | ScrollAction\n | FinishedAction\n | WaitAction\n | AndroidLongPressAction;\n\nexport async function resizeImageForUiTars(imageBase64: string, size: Size) {\n if (\n vlLocateMode() === 'vlm-ui-tars' &&\n uiTarsModelVersion() === UITarsModelVersion.V1_5\n ) {\n debug('ui-tars-v1.5, will check image size', size);\n const currentPixels = size.width * size.height;\n const maxPixels = 16384 * 28 * 28; //\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(\n 'resize image for ui-tars, new width: %s, new height: %s',\n newWidth,\n newHeight,\n );\n const resizedImage = await resizeImgBase64(imageBase64, {\n width: newWidth,\n height: newHeight,\n });\n return resizedImage;\n }\n }\n return imageBase64;\n}\n","import { getPreferredLanguage } from '@midscene/shared/env';\n\nexport const elementDescriberInstruction = () => {\n return `\nDescribe the element in the red rectangle for precise identification. Use ${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}`;\n};\n","import type {\n DumpMeta,\n DumpSubscriber,\n InsightDump,\n PartialInsightDumpFromSDK,\n} from '@/types';\nimport { getVersion } from '@/utils';\nimport { MIDSCENE_MODEL_NAME, getAIConfig } from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\n\nexport function emitInsightDump(\n data: PartialInsightDumpFromSDK,\n dumpSubscriber?: DumpSubscriber,\n) {\n const baseData: DumpMeta = {\n sdkVersion: getVersion(),\n logTime: Date.now(),\n model_name: getAIConfig(MIDSCENE_MODEL_NAME) || '',\n };\n const finalData: InsightDump = {\n logId: uuid(),\n ...baseData,\n ...data,\n };\n\n dumpSubscriber?.(finalData);\n}\n","import {\n AIActionType,\n type AIArgs,\n callAiFn,\n expandSearchArea,\n} from '@/ai-model/common';\nimport {\n AiExtractElementInfo,\n AiLocateElement,\n callToGetJSONObject,\n} from '@/ai-model/index';\nimport { AiAssert, AiLocateSection } from '@/ai-model/inspect';\nimport { elementDescriberInstruction } from '@/ai-model/prompt/describe';\nimport type {\n AIDescribeElementResponse,\n AIElementResponse,\n AIUsageInfo,\n BaseElement,\n DetailedLocateParam,\n DumpSubscriber,\n InsightAction,\n InsightAssertionResponse,\n InsightExtractOption,\n InsightExtractParam,\n InsightOptions,\n InsightTaskInfo,\n LocateResult,\n PartialInsightDumpFromSDK,\n Rect,\n TMultimodalPrompt,\n TUserPrompt,\n UIContext,\n} from '@/types';\nimport {\n MIDSCENE_FORCE_DEEP_THINK,\n MIDSCENE_USE_QWEN_VL,\n getAIConfigInBoolean,\n vlLocateMode,\n} from '@midscene/shared/env';\nimport { compositeElementInfoImg, cropByRect } from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport { emitInsightDump } from './utils';\n\nexport interface LocateOpts {\n context?: UIContext<BaseElement>;\n callAI?: typeof callAiFn<AIElementResponse>;\n}\n\nexport type AnyValue<T> = {\n [K in keyof T]: unknown extends T[K] ? any : T[K];\n};\n\nconst debug = getDebug('ai:insight');\nexport default class Insight<\n ElementType extends BaseElement = BaseElement,\n ContextType extends UIContext<ElementType> = UIContext<ElementType>,\n> {\n contextRetrieverFn: (\n action: InsightAction,\n ) => Promise<ContextType> | ContextType;\n\n aiVendorFn: (...args: Array<any>) => Promise<any> = callAiFn;\n\n onceDumpUpdatedFn?: DumpSubscriber;\n\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\n\n constructor(\n context:\n | ContextType\n | ((action: InsightAction) => Promise<ContextType> | ContextType),\n opt?: InsightOptions,\n ) {\n assert(context, 'context is required for Insight');\n if (typeof context === 'function') {\n this.contextRetrieverFn = context;\n } else {\n this.contextRetrieverFn = () => Promise.resolve(context);\n }\n\n if (typeof opt?.aiVendorFn !== 'undefined') {\n this.aiVendorFn = opt.aiVendorFn;\n }\n if (typeof opt?.taskInfo !== 'undefined') {\n this.taskInfo = opt.taskInfo;\n }\n }\n\n async locate(\n query: DetailedLocateParam,\n opt?: LocateOpts,\n ): Promise<LocateResult> {\n const { callAI } = opt || {};\n const queryPrompt = typeof query === 'string' ? query : query.prompt;\n assert(queryPrompt, 'query is required for locate');\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = undefined;\n\n assert(typeof query === 'object', 'query should be an object for locate');\n\n const globalDeepThinkSwitch = getAIConfigInBoolean(\n MIDSCENE_FORCE_DEEP_THINK,\n );\n if (globalDeepThinkSwitch) {\n debug('globalDeepThinkSwitch', globalDeepThinkSwitch);\n }\n let searchAreaPrompt;\n if (query.deepThink || globalDeepThinkSwitch) {\n searchAreaPrompt = query.prompt;\n }\n\n if (searchAreaPrompt && !vlLocateMode()) {\n console.warn(\n 'The \"deepThink\" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/choose-a-model',\n );\n searchAreaPrompt = undefined;\n }\n\n const context = opt?.context || (await this.contextRetrieverFn('locate'));\n\n let searchArea: Rect | undefined = undefined;\n let searchAreaRawResponse: string | undefined = undefined;\n let searchAreaUsage: AIUsageInfo | undefined = undefined;\n let searchAreaResponse:\n | Awaited<ReturnType<typeof AiLocateSection>>\n | undefined = undefined;\n if (searchAreaPrompt) {\n searchAreaResponse = await AiLocateSection({\n context,\n sectionDescription: searchAreaPrompt,\n });\n assert(\n searchAreaResponse.rect,\n `cannot find search area for \"${searchAreaPrompt}\"${\n searchAreaResponse.error ? `: ${searchAreaResponse.error}` : ''\n }`,\n );\n searchAreaRawResponse = searchAreaResponse.rawResponse;\n searchAreaUsage = searchAreaResponse.usage;\n searchArea = searchAreaResponse.rect;\n }\n\n const startTime = Date.now();\n const {\n parseResult,\n rect,\n elementById,\n rawResponse,\n usage,\n isOrderSensitive,\n } = await AiLocateElement({\n callAI: callAI || this.aiVendorFn,\n context,\n targetElementDescription: queryPrompt,\n searchConfig: searchAreaResponse,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: InsightTaskInfo = {\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\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `AI model failed to locate: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialInsightDumpFromSDK = {\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\n const elements: BaseElement[] = [];\n (parseResult.elements || []).forEach((item) => {\n if ('id' in item) {\n const element = elementById(item?.id);\n\n if (!element) {\n console.warn(\n `locate: cannot find element id=${item.id}. Maybe an unstable response from AI model`,\n );\n return;\n }\n elements.push(element);\n }\n });\n\n emitInsightDump(\n {\n ...dumpData,\n matchedElement: elements,\n },\n dumpSubscriber,\n );\n\n if (errorLog) {\n throw new Error(errorLog);\n }\n\n assert(\n elements.length <= 1,\n `locate: multiple elements found, length = ${elements.length}`,\n );\n\n if (elements.length === 1) {\n 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 }\n return {\n element: null,\n rect,\n };\n }\n\n async extract<T>(\n dataDemand: InsightExtractParam,\n opt?: InsightExtractOption,\n multimodalPrompt?: TMultimodalPrompt,\n ): Promise<{\n data: T;\n thought?: string;\n usage?: AIUsageInfo;\n }> {\n assert(\n typeof dataDemand === 'object' || typeof dataDemand === 'string',\n `dataDemand should be object or string, but get ${typeof dataDemand}`,\n );\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = undefined;\n\n const context = await this.contextRetrieverFn('extract');\n\n const startTime = Date.now();\n const { parseResult, usage } = await AiExtractElementInfo<T>({\n context,\n dataQuery: dataDemand,\n multimodalPrompt,\n extractOption: opt,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: InsightTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse: JSON.stringify(parseResult),\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `AI response error: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialInsightDumpFromSDK = {\n type: 'extract',\n userQuery: {\n dataDemand,\n },\n matchedElement: [],\n data: null,\n taskInfo,\n error: errorLog,\n };\n\n const { data, thought } = parseResult || {};\n\n // 4\n emitInsightDump(\n {\n ...dumpData,\n data,\n },\n dumpSubscriber,\n );\n\n if (errorLog && !data) {\n throw new Error(errorLog);\n }\n\n return {\n data,\n thought,\n usage,\n };\n }\n\n async assert(assertion: TUserPrompt): Promise<InsightAssertionResponse> {\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = undefined;\n\n const context = await this.contextRetrieverFn('assert');\n const startTime = Date.now();\n const assertResult = await AiAssert({\n assertion,\n context,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: InsightTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse: JSON.stringify(assertResult.content),\n };\n\n const { thought, pass } = assertResult.content;\n const dumpData: PartialInsightDumpFromSDK = {\n type: 'assert',\n userQuery: {\n assertion,\n },\n matchedElement: [],\n data: null,\n taskInfo,\n assertionPass: pass,\n assertionThought: thought,\n error: pass ? undefined : thought,\n };\n emitInsightDump(dumpData, dumpSubscriber);\n\n return {\n pass,\n thought,\n usage: assertResult.usage,\n };\n }\n async describe(\n target: Rect | [number, number],\n opt?: {\n deepThink?: boolean;\n },\n ): Promise<Pick<AIDescribeElementResponse, 'description'>> {\n assert(target, 'target is required for insight.describe');\n const context = await this.contextRetrieverFn('describe');\n const { screenshotBase64, size } = context;\n assert(screenshotBase64, 'screenshot is required for insight.describe');\n\n const systemPrompt = elementDescriberInstruction();\n\n // Convert [x,y] center point to Rect if needed\n const defaultRectSize = 30;\n const targetRect: Rect = Array.isArray(target)\n ? {\n left: Math.floor(target[0] - defaultRectSize / 2),\n top: Math.floor(target[1] - defaultRectSize / 2),\n width: defaultRectSize,\n height: defaultRectSize,\n }\n : target;\n\n let imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n size,\n elementsPositionInfo: [\n {\n rect: targetRect,\n },\n ],\n borderThickness: 3,\n });\n\n if (opt?.deepThink) {\n const searchArea = expandSearchArea(targetRect, context.size);\n debug('describe: set searchArea', searchArea);\n imagePayload = await cropByRect(\n imagePayload,\n searchArea,\n getAIConfigInBoolean(MIDSCENE_USE_QWEN_VL),\n );\n }\n\n const msgs: AIArgs = [\n { role: 'system', content: systemPrompt },\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\n const callAIFn =\n this.aiVendorFn || callToGetJSONObject<AIDescribeElementResponse>;\n\n const res = await callAIFn(msgs, AIActionType.DESCRIBE_ELEMENT);\n\n const { content } = res;\n assert(!content.error, `describe failed: ${content.error}`);\n assert(content.description, 'failed to describe the element');\n return content;\n }\n}\n","import { Executor } from './ai-model/action-executor';\nimport Insight from './insight/index';\nimport { getVersion } from './utils';\n\nexport {\n plan,\n describeUserPage,\n AiLocateElement,\n AiAssert,\n} from './ai-model/index';\n\nexport { getAIConfig, MIDSCENE_MODEL_NAME } from '@midscene/shared/env';\n\nexport type * from './types';\nexport default Insight;\nexport { Executor, Insight, getVersion };\n\nexport type {\n MidsceneYamlScript,\n MidsceneYamlTask,\n MidsceneYamlFlowItem,\n MidsceneYamlFlowItemAIRightClick,\n MidsceneYamlConfigResult,\n LocateOption,\n DetailedLocateParam,\n} from './yaml';\n"],"names":["Map","getVersion","__VERSION__","Executor","task","_this_latestErrorTask","_this_latestErrorTask1","assert","Array","item","console","nextPendingIndex","taskIndex","successfullyCompleted","previousFindOutput","Date","e","executor","param","returnValue","executorContext","Object","i","outputIndex","Math","thought","output","errorTaskIndex","modelDescription","vlLocateMode","uiTarsModelVer","uiTarsModelVersion","dumpData","getAIConfig","MIDSCENE_MODEL_NAME","name","options","AIResponseFormat","defaultAssertionPrompt","defaultAssertionResponseJsonFormat","getUiTarsAssertionResponseJsonFormat","getPreferredLanguage","systemPromptToAssert","model","assertSchema","bboxDescription","vlMode","systemPromptToLocateElement","bboxComment","locatorSchema","findElementPrompt","PromptTemplate","vlCoTLog","vlCurrentLog","llmCurrentLog","commonOutputFields","vlLocateParam","required","llmLocateParam","descriptionForAction","action","locatorScheme","tab","locateParam","locatorParam","paramSchema","fields","Boolean","systemTemplateOfVLPlanning","actionSpace","actionNameList","actionDescriptionList","actionList","systemTemplateOfLLM","outputTemplate","systemPromptToTaskPlanning","planSchema","generateTaskBackgroundContext","userInstruction","log","userActionContext","automationUserPrompt","checkAIConfig","openaiKey","OPENAI_API_KEY","azureConfig","MIDSCENE_USE_AZURE_OPENAI","anthropicKey","ANTHROPIC_API_KEY","initConfigJson","MIDSCENE_OPENAI_INIT_CONFIG_JSON","debugConfigInitialized","initDebugConfig","shouldPrintTiming","getAIConfigInBoolean","MIDSCENE_DEBUG_AI_PROFILE","debugConfig","shouldPrintAIResponse","MIDSCENE_DEBUG_AI_RESPONSE","enableDebug","defaultModel","getModelName","modelName","nameInConfig","createChatClient","AIActionTypeValue","openai","extraConfig","getAIConfigInJson","socksProxy","MIDSCENE_OPENAI_SOCKS_PROXY","httpProxy","MIDSCENE_OPENAI_HTTP_PROXY","proxyAgent","debugProxy","getDebug","HttpsProxyAgent","SocksProxyAgent","OPENAI_USE_AZURE","AzureOpenAI","OPENAI_BASE_URL","extraAzureConfig","MIDSCENE_AZURE_OPENAI_INIT_CONFIG_JSON","scope","MIDSCENE_AZURE_OPENAI_SCOPE","tokenProvider","ifInBrowser","credential","DefaultAzureCredential","getBearerTokenProvider","AZURE_OPENAI_ENDPOINT","AZURE_OPENAI_API_VERSION","AZURE_OPENAI_DEPLOYMENT","AZURE_OPENAI_KEY","MIDSCENE_USE_ANTHROPIC_SDK","baseURL","Error","OpenAI","MIDSCENE_API_TYPE","MIDSCENE_LANGSMITH_DEBUG","wrapOpenAI","apiKey","Anthropic","call","messages","responseFormat","completion","style","maxTokens","OPENAI_MAX_TOKENS","debugCall","debugProfileStats","debugProfileDetail","startTime","isStreaming","content","accumulated","usage","timeCost","commonConfig","Number","stream","chunk","_chunk_choices__delta","_chunk_choices__delta1","_chunk_choices_2","reasoning_content","chunkData","undefined","estimatedTokens","finalChunk","_result_usage","_result_usage1","_result_usage2","result","JSON","convertImageContent","imgBase64","m","_chunk_delta","anthropicUsage","newError","callToGetJSONObject","AIActionType","response","jsonContent","safeParseJson","extractJSONFromCodeBlock","jsonMatch","codeBlockMatch","jsonLikeMatch","preprocessDoubaoBboxJson","input","cleanJsonString","_cleanJsonString_match","jsonrepair","jsonString","callAiFn","msgs","jsonObject","defaultBboxSize","debugInspectUtils","fillBboxParam","locate","width","height","adaptBbox","adaptQwenBbox","bbox","msg","adaptDoubaoBbox","splitted","bboxList","x","y","adaptGeminiBbox","left","top","right","bottom","adaptBboxToRect","offsetX","offsetY","rect","warned","warnGPT4oSizeLimit","size","_getModelName","warningMsg","mergeRects","rects","minLeft","r","minTop","maxRight","maxBottom","expandSearchArea","screenSize","minEdgeSize","defaultPadding","paddingSizeHorizontal","paddingSizeVertical","markupImageForLLM","screenshotBase64","tree","elementsInfo","treeToList","elementsPositionInfoWithoutText","elementInfo","NodeType","imagePayload","compositeElementInfoImg","buildYamlFlowFromPlans","plans","sleep","flow","plan","_plan_locate","type","describeSize","distanceThreshold","elementByPositionWithElementInfo","treeRoot","position","requireStrictDistance","filterPositionElements","matchingElements","dfs","node","_item_attributes","child","element","smallest","current","smallestArea","currentArea","distanceToCenter","distance","point1","point2","describeUserPage","context","opt","imgSize","imageInfoOfBase64","idElementMap","flatElements","pageDescription","visibleOnly","contentTree","descriptionOfTree","sizeDescription","idOrIndexId","generateElementByPosition","systemPromptToExtract","extractDataQueryPrompt","dataQuery","dataQueryText","extractDataPrompt","systemPromptToLocateSection","sectionLocatorInstruction","debugInspect","debugSection","extraTextFromUserPrompt","prompt","promptsToChatParam","multimodalPrompt","_multimodalPrompt_images","base64","preProcessImageUrl","AiLocateElement","targetElementDescription","callAI","description","elementById","insertElementByPosition","userInstructionPrompt","systemPrompt","paddingToMatchBlockByBase64","addOns","callAIFn","res","rawResponse","resRect","matchedElements","errors","_options_searchConfig_rect","_options_searchConfig_rect1","_options_searchConfig_rect2","_options_searchConfig_rect3","rectCenter","AiLocateSection","sectionDescription","sectionLocatorInstructionText","sectionRect","sectionBbox","targetRect","referenceBboxList","referenceRects","mergedRect","imageBase64","cropByRect","MIDSCENE_USE_QWEN_VL","AiExtractElementInfo","_options_extractOption","extractOption","extractDataPromptText","userContent","AiAssert","assertion","MIDSCENE_USE_VLM_UI_TARS","assertionText","assertResult","opts","_planFromAI_action","taskBackgroundContextText","planFromAI","actions","_action_locate","elementDescriberInstruction","emitInsightDump","data","dumpSubscriber","baseData","finalData","uuid","debug","Insight","query","_parseResult_errors","queryPrompt","globalDeepThinkSwitch","MIDSCENE_FORCE_DEEP_THINK","searchAreaPrompt","searchArea","searchAreaRawResponse","searchAreaUsage","searchAreaResponse","parseResult","isOrderSensitive","taskInfo","errorLog","elements","dataDemand","pass","target","defaultRectSize","Promise"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { descriptionOfTree, trimAttributes, truncateText } from "@midscene/shared/extractor";
2
+ export { descriptionOfTree, trimAttributes, truncateText };