@sqaitech/core 0.30.13 → 0.30.15
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.
- package/dist/es/agent/utils.mjs +1 -1
- package/dist/es/ai-model/service-caller/index.mjs +1 -1
- package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
- package/dist/es/insight/index.mjs +1 -1
- package/dist/es/insight/index.mjs.map +1 -1
- package/dist/es/utils.mjs +3 -3
- package/dist/es/utils.mjs.map +1 -1
- package/dist/lib/agent/utils.js +1 -1
- package/dist/lib/ai-model/service-caller/index.js +1 -1
- package/dist/lib/ai-model/service-caller/index.js.map +1 -1
- package/dist/lib/insight/index.js +1 -1
- package/dist/lib/insight/index.js.map +1 -1
- package/dist/lib/utils.js +3 -3
- package/dist/lib/utils.js.map +1 -1
- package/package.json +3 -3
package/dist/es/utils.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","sources":["webpack://@sqaitech/core/./src/utils.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\r\nimport * as fs from 'node:fs';\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\r\nimport { tmpdir } from 'node:os';\r\nimport * as path from 'node:path';\r\nimport {\r\n defaultRunDirName,\r\n getMidsceneRunSubDir,\r\n} from '@sqaitech/shared/common';\r\nimport {\r\n SQAI_CACHE,\r\n SQAI_DEBUG_MODE,\r\n globalConfigManager,\r\n} from '@sqaitech/shared/env';\r\nimport { getRunningPkgInfo } from '@sqaitech/shared/node';\r\nimport { assert, logMsg } from '@sqaitech/shared/utils';\r\nimport {\r\n escapeScriptTag,\r\n ifInBrowser,\r\n ifInWorker,\r\n uuid,\r\n} from '@sqaitech/shared/utils';\r\nimport type { Cache, Rect, ReportDumpWithAttributes } from './types';\r\n\r\nlet logEnvReady = false;\r\n\r\nexport { appendFileSync } from 'node:fs';\r\n\r\nexport const groupedActionDumpFileExt = 'web-dump.json';\r\n\r\n/**\r\n * Process cache configuration with environment variable support and backward compatibility.\r\n *\r\n * @param cache - The original cache configuration\r\n * @param cacheId - The cache ID to use as:\r\n * 1. Fallback ID when cache is true or cache object has no ID\r\n * 2. Legacy cacheId when cache is undefined (requires SQAI_CACHE env var)\r\n * @returns Processed cache configuration\r\n */\r\nexport function processCacheConfig(\r\n cache: Cache | undefined,\r\n cacheId: string,\r\n): Cache | undefined {\r\n // 1. New cache object configuration (highest priority)\r\n if (cache !== undefined) {\r\n if (cache === false) {\r\n return undefined; // Completely disable cache\r\n }\r\n\r\n if (cache === true) {\r\n // Auto-generate ID using cacheId for CLI/YAML scenarios\r\n // Agent will validate and reject this later if needed\r\n return { id: cacheId };\r\n }\r\n\r\n // cache is object configuration\r\n if (typeof cache === 'object' && cache !== null) {\r\n // Auto-generate ID using cacheId when missing (for CLI/YAML scenarios)\r\n if (!cache.id) {\r\n return { ...cache, id: cacheId };\r\n }\r\n return cache;\r\n }\r\n }\r\n\r\n // 2. Backward compatibility: support old cacheId (requires environment variable)\r\n // When cache is undefined, check if legacy cacheId mode is enabled via env var\r\n const envEnabled = globalConfigManager.getEnvConfigInBoolean(SQAI_CACHE);\r\n\r\n if (envEnabled && cacheId) {\r\n return { id: cacheId };\r\n }\r\n\r\n // 3. No cache configuration\r\n return undefined;\r\n}\r\n\r\nconst reportInitializedMap = new Map<string, boolean>();\r\n\r\ndeclare const __DEV_REPORT_PATH__: string;\r\n\r\nexport function getReportTpl() {\r\n if (typeof __DEV_REPORT_PATH__ === 'string' && __DEV_REPORT_PATH__) {\r\n return fs.readFileSync(__DEV_REPORT_PATH__, 'utf-8');\r\n }\r\n const reportTpl = 'REPLACE_ME_WITH_REPORT_HTML';\r\n\r\n return reportTpl;\r\n}\r\n\r\n/**\r\n * high performance, insert script before </html> in HTML file\r\n * only truncate and append, no temporary file\r\n */\r\nexport function insertScriptBeforeClosingHtml(\r\n filePath: string,\r\n scriptContent: string,\r\n): void {\r\n const htmlEndTag = '</html>';\r\n const stat = fs.statSync(filePath);\r\n\r\n const readSize = Math.min(stat.size, 4096);\r\n const start = Math.max(0, stat.size - readSize);\r\n const buffer = Buffer.alloc(stat.size - start);\r\n const fd = fs.openSync(filePath, 'r');\r\n fs.readSync(fd, buffer, 0, buffer.length, start);\r\n fs.closeSync(fd);\r\n\r\n const tailStr = buffer.toString('utf8');\r\n const htmlEndIdx = tailStr.lastIndexOf(htmlEndTag);\r\n if (htmlEndIdx === -1) {\r\n throw new Error(`No </html> found in file:${filePath}`);\r\n }\r\n\r\n // calculate the correct byte position: char position to byte position\r\n const beforeHtmlInTail = tailStr.slice(0, htmlEndIdx);\r\n const htmlEndPos = start + Buffer.byteLength(beforeHtmlInTail, 'utf8');\r\n\r\n // truncate to </html> before\r\n fs.truncateSync(filePath, htmlEndPos);\r\n // append script and </html>\r\n fs.appendFileSync(filePath, `${scriptContent}\\n${htmlEndTag}\\n`);\r\n}\r\n\r\nexport function reportHTMLContent(\r\n dumpData: string | ReportDumpWithAttributes,\r\n reportPath?: string,\r\n appendReport?: boolean,\r\n withTpl = true, // whether return with report template, default = true\r\n): string {\r\n let tpl = '';\r\n if (withTpl) {\r\n tpl = getReportTpl();\r\n\r\n if (!tpl) {\r\n console.warn('reportTpl is not set, will not write report');\r\n return '';\r\n }\r\n }\r\n // if reportPath is set, it means we are in write to file mode\r\n const writeToFile = reportPath && !ifInBrowser;\r\n let dumpContent = '';\r\n\r\n if (typeof dumpData === 'string') {\r\n // do not use template string here, will cause bundle error\r\n dumpContent =\r\n // biome-ignore lint/style/useTemplate: <explanation>\r\n '<script type=\"SQAI_web_dump\" type=\"application/json\">\\n' +\r\n escapeScriptTag(dumpData) +\r\n '\\n</script>';\r\n } else {\r\n const { dumpString, attributes } = dumpData;\r\n const attributesArr = Object.keys(attributes || {}).map((key) => {\r\n return `${key}=\"${encodeURIComponent(attributes![key])}\"`;\r\n });\r\n\r\n dumpContent =\r\n // do not use template string here, will cause bundle error\r\n // biome-ignore lint/style/useTemplate: <explanation>\r\n '<script type=\"SQAI_web_dump\" type=\"application/json\" ' +\r\n attributesArr.join(' ') +\r\n '>\\n' +\r\n escapeScriptTag(dumpString) +\r\n '\\n</script>';\r\n }\r\n\r\n if (writeToFile) {\r\n if (!appendReport) {\r\n writeFileSync(reportPath!, tpl + dumpContent, { flag: 'w' });\r\n return reportPath!;\r\n }\r\n\r\n if (!reportInitializedMap.get(reportPath!)) {\r\n writeFileSync(reportPath!, tpl, { flag: 'w' });\r\n reportInitializedMap.set(reportPath!, true);\r\n }\r\n\r\n insertScriptBeforeClosingHtml(reportPath!, dumpContent);\r\n return reportPath!;\r\n }\r\n\r\n return tpl + dumpContent;\r\n}\r\n\r\nexport function writeDumpReport(\r\n fileName: string,\r\n dumpData: string | ReportDumpWithAttributes,\r\n appendReport?: boolean,\r\n): string | null {\r\n if (ifInBrowser || ifInWorker) {\r\n console.log('will not write report in browser');\r\n return null;\r\n }\r\n\r\n const reportPath = path.join(\r\n getMidsceneRunSubDir('report'),\r\n `${fileName}.html`,\r\n );\r\n\r\n reportHTMLContent(dumpData, reportPath, appendReport);\r\n\r\n if (process.env.SQAI_DEBUG_LOG_JSON) {\r\n const jsonPath = `${reportPath}.json`;\r\n let data;\r\n\r\n if (typeof dumpData === 'string') {\r\n data = JSON.parse(dumpData) as ReportDumpWithAttributes;\r\n } else {\r\n data = dumpData;\r\n }\r\n\r\n writeFileSync(jsonPath, JSON.stringify(data, null, 2), {\r\n flag: appendReport ? 'a' : 'w',\r\n });\r\n\r\n logMsg(`Midscene - dump file written: ${jsonPath}`);\r\n }\r\n\r\n return reportPath;\r\n}\r\n\r\nexport function writeLogFile(opts: {\r\n fileName: string;\r\n fileExt: string;\r\n fileContent: string | ReportDumpWithAttributes;\r\n type: 'dump' | 'cache' | 'report' | 'tmp';\r\n generateReport?: boolean;\r\n appendReport?: boolean;\r\n}) {\r\n if (ifInBrowser || ifInWorker) {\r\n return '/mock/report.html';\r\n }\r\n const { fileName, fileExt, fileContent, type = 'dump' } = opts;\r\n const targetDir = getMidsceneRunSubDir(type);\r\n // Ensure directory exists\r\n if (!logEnvReady) {\r\n assert(targetDir, 'logDir should be set before writing dump file');\r\n\r\n // gitIgnore in the parent directory\r\n const gitIgnorePath = path.join(targetDir, '../../.gitignore');\r\n const gitPath = path.join(targetDir, '../../.git');\r\n let gitIgnoreContent = '';\r\n\r\n if (existsSync(gitPath)) {\r\n // if the git path exists, we need to add the log folder to the git ignore file\r\n if (existsSync(gitIgnorePath)) {\r\n gitIgnoreContent = readFileSync(gitIgnorePath, 'utf-8');\r\n }\r\n\r\n // ignore the log folder\r\n if (!gitIgnoreContent.includes(`${defaultRunDirName}/`)) {\r\n writeFileSync(\r\n gitIgnorePath,\r\n `${gitIgnoreContent}\\n# Midscene.js dump files\\n${defaultRunDirName}/dump\\n${defaultRunDirName}/report\\n${defaultRunDirName}/tmp\\n${defaultRunDirName}/log\\n`,\r\n 'utf-8',\r\n );\r\n }\r\n }\r\n\r\n logEnvReady = true;\r\n }\r\n\r\n const filePath = path.join(targetDir, `${fileName}.${fileExt}`);\r\n\r\n if (type !== 'dump') {\r\n // do not write dump file any more\r\n writeFileSync(filePath, JSON.stringify(fileContent));\r\n }\r\n\r\n if (opts?.generateReport) {\r\n return writeDumpReport(fileName, fileContent, opts.appendReport);\r\n }\r\n\r\n return filePath;\r\n}\r\n\r\nexport function getTmpDir(): string | null {\r\n try {\r\n const runningPkgInfo = getRunningPkgInfo();\r\n if (!runningPkgInfo) {\r\n return null;\r\n }\r\n const { name } = runningPkgInfo;\r\n const tmpPath = path.join(tmpdir(), name);\r\n mkdirSync(tmpPath, { recursive: true });\r\n return tmpPath;\r\n } catch (e) {\r\n return null;\r\n }\r\n}\r\n\r\nexport function getTmpFile(fileExtWithoutDot: string): string | null {\r\n if (ifInBrowser || ifInWorker) {\r\n return null;\r\n }\r\n const tmpDir = getTmpDir();\r\n const filename = `${uuid()}.${fileExtWithoutDot}`;\r\n return path.join(tmpDir!, filename);\r\n}\r\n\r\nexport function overlapped(container: Rect, target: Rect) {\r\n // container and the target have some part overlapped\r\n return (\r\n container.left < target.left + target.width &&\r\n container.left + container.width > target.left &&\r\n container.top < target.top + target.height &&\r\n container.top + container.height > target.top\r\n );\r\n}\r\n\r\nexport async function sleep(ms: number) {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nexport function replacerForPageObject(_key: string, value: any) {\r\n if (value && value.constructor?.name === 'Page') {\r\n return '[Page object]';\r\n }\r\n if (value && value.constructor?.name === 'Browser') {\r\n return '[Browser object]';\r\n }\r\n return value;\r\n}\r\n\r\nexport function stringifyDumpData(data: any, indents?: number) {\r\n return JSON.stringify(data, replacerForPageObject, indents);\r\n}\r\n\r\ndeclare const __VERSION__: string;\r\n\r\nexport function getVersion() {\r\n return __VERSION__;\r\n}\r\n\r\nfunction debugLog(...message: any[]) {\r\n // always read from process.env, and cannot be override by modelConfig, overrideAIConfig, etc.\r\n // also avoid circular dependency\r\n const debugMode = process.env[SQAI_DEBUG_MODE];\r\n if (debugMode) {\r\n console.log('[Midscene]', ...message);\r\n }\r\n}\r\n\r\nlet lastReportedRepoUrl = '';\r\nexport function uploadTestInfoToServer({\r\n testUrl,\r\n serverUrl,\r\n}: { testUrl: string; serverUrl?: string }) {\r\n let repoUrl = '';\r\n let userEmail = '';\r\n\r\n try {\r\n repoUrl = execSync('git config --get remote.origin.url').toString().trim();\r\n userEmail = execSync('git config --get user.email').toString().trim();\r\n } catch (error) {\r\n debugLog('Failed to get git info:', error);\r\n }\r\n\r\n // Only upload test info if:\r\n // 1. Server URL is configured AND\r\n // 2. Either:\r\n // - We have a repo URL that's different from last reported one (to avoid duplicate reports)\r\n // - OR we don't have a repo URL but have a test URL (for non-git environments)\r\n if (\r\n serverUrl &&\r\n ((repoUrl && repoUrl !== lastReportedRepoUrl) || (!repoUrl && testUrl))\r\n ) {\r\n debugLog('Uploading test info to server', {\r\n serverUrl,\r\n repoUrl,\r\n testUrl,\r\n userEmail,\r\n });\r\n\r\n fetch(serverUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n repo_url: repoUrl,\r\n test_url: testUrl,\r\n user_email: userEmail,\r\n }),\r\n })\r\n .then((response) => response.json())\r\n .then((data) => {\r\n debugLog('Successfully uploaded test info to server:', data);\r\n })\r\n .catch((error) =>\r\n debugLog('Failed to upload test info to server:', error),\r\n );\r\n lastReportedRepoUrl = repoUrl;\r\n }\r\n}\r\n"],"names":["logEnvReady","groupedActionDumpFileExt","processCacheConfig","cache","cacheId","undefined","envEnabled","globalConfigManager","SQAI_CACHE","reportInitializedMap","Map","getReportTpl","reportTpl","insertScriptBeforeClosingHtml","filePath","scriptContent","htmlEndTag","stat","fs","readSize","Math","start","buffer","Buffer","fd","tailStr","htmlEndIdx","Error","beforeHtmlInTail","htmlEndPos","reportHTMLContent","dumpData","reportPath","appendReport","withTpl","tpl","console","writeToFile","ifInBrowser","dumpContent","escapeScriptTag","dumpString","attributes","attributesArr","Object","key","encodeURIComponent","writeFileSync","writeDumpReport","fileName","ifInWorker","path","getMidsceneRunSubDir","process","jsonPath","data","JSON","logMsg","writeLogFile","opts","fileExt","fileContent","type","targetDir","assert","gitIgnorePath","gitPath","gitIgnoreContent","existsSync","readFileSync","defaultRunDirName","getTmpDir","runningPkgInfo","getRunningPkgInfo","name","tmpPath","tmpdir","mkdirSync","e","getTmpFile","fileExtWithoutDot","tmpDir","filename","uuid","overlapped","container","target","sleep","ms","Promise","resolve","setTimeout","replacerForPageObject","_key","value","_value_constructor","_value_constructor1","stringifyDumpData","indents","getVersion","__VERSION__","debugLog","message","debugMode","SQAI_DEBUG_MODE","lastReportedRepoUrl","uploadTestInfoToServer","testUrl","serverUrl","repoUrl","userEmail","execSync","error","fetch","response"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.mjs","sources":["webpack://@sqaitech/core/./src/utils.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\r\nimport * as fs from 'node:fs';\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\r\nimport { tmpdir } from 'node:os';\r\nimport * as path from 'node:path';\r\nimport {\r\n defaultRunDirName,\r\n getMidsceneRunSubDir,\r\n} from '@sqaitech/shared/common';\r\nimport {\r\n SQAI_CACHE,\r\n SQAI_DEBUG_MODE,\r\n globalConfigManager,\r\n} from '@sqaitech/shared/env';\r\nimport { getRunningPkgInfo } from '@sqaitech/shared/node';\r\nimport { assert, logMsg } from '@sqaitech/shared/utils';\r\nimport {\r\n escapeScriptTag,\r\n ifInBrowser,\r\n ifInWorker,\r\n uuid,\r\n} from '@sqaitech/shared/utils';\r\nimport type { Cache, Rect, ReportDumpWithAttributes } from './types';\r\n\r\nlet logEnvReady = false;\r\n\r\nexport { appendFileSync } from 'node:fs';\r\n\r\nexport const groupedActionDumpFileExt = 'web-dump.json';\r\n\r\n/**\r\n * Process cache configuration with environment variable support and backward compatibility.\r\n *\r\n * @param cache - The original cache configuration\r\n * @param cacheId - The cache ID to use as:\r\n * 1. Fallback ID when cache is true or cache object has no ID\r\n * 2. Legacy cacheId when cache is undefined (requires SQAI_CACHE env var)\r\n * @returns Processed cache configuration\r\n */\r\nexport function processCacheConfig(\r\n cache: Cache | undefined,\r\n cacheId: string,\r\n): Cache | undefined {\r\n // 1. New cache object configuration (highest priority)\r\n if (cache !== undefined) {\r\n if (cache === false) {\r\n return undefined; // Completely disable cache\r\n }\r\n\r\n if (cache === true) {\r\n // Auto-generate ID using cacheId for CLI/YAML scenarios\r\n // Agent will validate and reject this later if needed\r\n return { id: cacheId };\r\n }\r\n\r\n // cache is object configuration\r\n if (typeof cache === 'object' && cache !== null) {\r\n // Auto-generate ID using cacheId when missing (for CLI/YAML scenarios)\r\n if (!cache.id) {\r\n return { ...cache, id: cacheId };\r\n }\r\n return cache;\r\n }\r\n }\r\n\r\n // 2. Backward compatibility: support old cacheId (requires environment variable)\r\n // When cache is undefined, check if legacy cacheId mode is enabled via env var\r\n const envEnabled = globalConfigManager.getEnvConfigInBoolean(SQAI_CACHE);\r\n\r\n if (envEnabled && cacheId) {\r\n return { id: cacheId };\r\n }\r\n\r\n // 3. No cache configuration\r\n return undefined;\r\n}\r\n\r\nconst reportInitializedMap = new Map<string, boolean>();\r\n\r\ndeclare const __DEV_REPORT_PATH__: string;\r\n\r\nexport function getReportTpl() {\r\n if (typeof __DEV_REPORT_PATH__ === 'string' && __DEV_REPORT_PATH__) {\r\n return fs.readFileSync(__DEV_REPORT_PATH__, 'utf-8');\r\n }\r\n const reportTpl = 'REPLACE_ME_WITH_REPORT_HTML';\r\n\r\n return reportTpl;\r\n}\r\n\r\n/**\r\n * high performance, insert script before </html> in HTML file\r\n * only truncate and append, no temporary file\r\n */\r\nexport function insertScriptBeforeClosingHtml(\r\n filePath: string,\r\n scriptContent: string,\r\n): void {\r\n const htmlEndTag = '</html>';\r\n const stat = fs.statSync(filePath);\r\n\r\n const readSize = Math.min(stat.size, 4096);\r\n const start = Math.max(0, stat.size - readSize);\r\n const buffer = Buffer.alloc(stat.size - start);\r\n const fd = fs.openSync(filePath, 'r');\r\n fs.readSync(fd, buffer, 0, buffer.length, start);\r\n fs.closeSync(fd);\r\n\r\n const tailStr = buffer.toString('utf8');\r\n const htmlEndIdx = tailStr.lastIndexOf(htmlEndTag);\r\n if (htmlEndIdx === -1) {\r\n throw new Error(`No </html> found in file:${filePath}`);\r\n }\r\n\r\n // calculate the correct byte position: char position to byte position\r\n const beforeHtmlInTail = tailStr.slice(0, htmlEndIdx);\r\n const htmlEndPos = start + Buffer.byteLength(beforeHtmlInTail, 'utf8');\r\n\r\n // truncate to </html> before\r\n fs.truncateSync(filePath, htmlEndPos);\r\n // append script and </html>\r\n fs.appendFileSync(filePath, `${scriptContent}\\n${htmlEndTag}\\n`);\r\n}\r\n\r\nexport function reportHTMLContent(\r\n dumpData: string | ReportDumpWithAttributes,\r\n reportPath?: string,\r\n appendReport?: boolean,\r\n withTpl = true, // whether return with report template, default = true\r\n): string {\r\n let tpl = '';\r\n if (withTpl) {\r\n tpl = getReportTpl();\r\n\r\n if (!tpl) {\r\n console.warn('reportTpl is not set, will not write report');\r\n return '';\r\n }\r\n }\r\n // if reportPath is set, it means we are in write to file mode\r\n const writeToFile = reportPath && !ifInBrowser;\r\n let dumpContent = '';\r\n\r\n if (typeof dumpData === 'string') {\r\n // do not use template string here, will cause bundle error\r\n dumpContent =\r\n // biome-ignore lint/style/useTemplate: <explanation>\r\n '<script type=\"SQAI_web_dump\" type=\"application/json\">\\n' +\r\n escapeScriptTag(dumpData) +\r\n '\\n</script>';\r\n } else {\r\n const { dumpString, attributes } = dumpData;\r\n const attributesArr = Object.keys(attributes || {}).map((key) => {\r\n return `${key}=\"${encodeURIComponent(attributes![key])}\"`;\r\n });\r\n\r\n dumpContent =\r\n // do not use template string here, will cause bundle error\r\n // biome-ignore lint/style/useTemplate: <explanation>\r\n '<script type=\"SQAI_web_dump\" type=\"application/json\" ' +\r\n attributesArr.join(' ') +\r\n '>\\n' +\r\n escapeScriptTag(dumpString) +\r\n '\\n</script>';\r\n }\r\n\r\n if (writeToFile) {\r\n if (!appendReport) {\r\n writeFileSync(reportPath!, tpl + dumpContent, { flag: 'w' });\r\n return reportPath!;\r\n }\r\n\r\n if (!reportInitializedMap.get(reportPath!)) {\r\n writeFileSync(reportPath!, tpl, { flag: 'w' });\r\n reportInitializedMap.set(reportPath!, true);\r\n }\r\n\r\n insertScriptBeforeClosingHtml(reportPath!, dumpContent);\r\n return reportPath!;\r\n }\r\n\r\n return tpl + dumpContent;\r\n}\r\n\r\nexport function writeDumpReport(\r\n fileName: string,\r\n dumpData: string | ReportDumpWithAttributes,\r\n appendReport?: boolean,\r\n): string | null {\r\n if (ifInBrowser || ifInWorker) {\r\n console.log('will not write report in browser');\r\n return null;\r\n }\r\n\r\n const reportPath = path.join(\r\n getMidsceneRunSubDir('report'),\r\n `${fileName}.html`,\r\n );\r\n\r\n reportHTMLContent(dumpData, reportPath, appendReport);\r\n\r\n if (process.env.SQAI_DEBUG_LOG_JSON) {\r\n const jsonPath = `${reportPath}.json`;\r\n let data;\r\n\r\n if (typeof dumpData === 'string') {\r\n data = JSON.parse(dumpData) as ReportDumpWithAttributes;\r\n } else {\r\n data = dumpData;\r\n }\r\n\r\n writeFileSync(jsonPath, JSON.stringify(data, null, 2), {\r\n flag: appendReport ? 'a' : 'w',\r\n });\r\n\r\n logMsg(`Midscene - dump file written: ${jsonPath}`);\r\n }\r\n\r\n return reportPath;\r\n}\r\n\r\nexport function writeLogFile(opts: {\r\n fileName: string;\r\n fileExt: string;\r\n fileContent: string | ReportDumpWithAttributes;\r\n type: 'dump' | 'cache' | 'report' | 'tmp';\r\n generateReport?: boolean;\r\n appendReport?: boolean;\r\n}) {\r\n if (ifInBrowser || ifInWorker) {\r\n return '/mock/report.html';\r\n }\r\n const { fileName, fileExt, fileContent, type = 'dump' } = opts;\r\n const targetDir = getMidsceneRunSubDir(type);\r\n // Ensure directory exists\r\n if (!logEnvReady) {\r\n assert(targetDir, 'logDir should be set before writing dump file');\r\n\r\n // gitIgnore in the parent directory\r\n const gitIgnorePath = path.join(targetDir, '../../.gitignore');\r\n const gitPath = path.join(targetDir, '../../.git');\r\n let gitIgnoreContent = '';\r\n\r\n if (existsSync(gitPath)) {\r\n // if the git path exists, we need to add the log folder to the git ignore file\r\n if (existsSync(gitIgnorePath)) {\r\n gitIgnoreContent = readFileSync(gitIgnorePath, 'utf-8');\r\n }\r\n\r\n // ignore the log folder\r\n if (!gitIgnoreContent.includes(`${defaultRunDirName}/`)) {\r\n writeFileSync(\r\n gitIgnorePath,\r\n `${gitIgnoreContent}\\n# Midscene.js dump files\\n${defaultRunDirName}/dump\\n${defaultRunDirName}/report\\n${defaultRunDirName}/tmp\\n${defaultRunDirName}/log\\n`,\r\n 'utf-8',\r\n );\r\n }\r\n }\r\n\r\n logEnvReady = true;\r\n }\r\n\r\n const filePath = path.join(targetDir, `${fileName}.${fileExt}`);\r\n\r\n if (type !== 'dump') {\r\n // do not write dump file any more\r\n writeFileSync(filePath, JSON.stringify(fileContent));\r\n }\r\n\r\n if (opts?.generateReport) {\r\n return writeDumpReport(fileName, fileContent, opts.appendReport);\r\n }\r\n\r\n return filePath;\r\n}\r\n\r\nexport function getTmpDir(): string | null {\r\n try {\r\n const runningPkgInfo = getRunningPkgInfo();\r\n if (!runningPkgInfo) {\r\n return null;\r\n }\r\n const { name } = runningPkgInfo;\r\n const tmpPath = path.join(tmpdir(), name);\r\n mkdirSync(tmpPath, { recursive: true });\r\n return tmpPath;\r\n } catch (e) {\r\n return null;\r\n }\r\n}\r\n\r\nexport function getTmpFile(fileExtWithoutDot: string): string | null {\r\n if (ifInBrowser || ifInWorker) {\r\n return null;\r\n }\r\n const tmpDir = getTmpDir();\r\n const filename = `${uuid()}.${fileExtWithoutDot}`;\r\n return path.join(tmpDir!, filename);\r\n}\r\n\r\nexport function overlapped(container: Rect, target: Rect) {\r\n // container and the target have some part overlapped\r\n return (\r\n container.left < target.left + target.width &&\r\n container.left + container.width > target.left &&\r\n container.top < target.top + target.height &&\r\n container.top + container.height > target.top\r\n );\r\n}\r\n\r\nexport async function sleep(ms: number) {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nexport function replacerForPageObject(_key: string, value: any) {\r\n if (value && value.constructor?.name === 'Page') {\r\n return '[Page object]';\r\n }\r\n if (value && value.constructor?.name === 'Browser') {\r\n return '[Browser object]';\r\n }\r\n return value;\r\n}\r\n\r\nexport function stringifyDumpData(data: any, indents?: number) {\r\n return JSON.stringify(data, replacerForPageObject, indents);\r\n}\r\n\r\ndeclare const __VERSION__: string;\r\n\r\nexport function getVersion() {\r\n return __VERSION__;\r\n}\r\n\r\nfunction debugLog(...message: any[]) {\r\n // always read from process.env, and cannot be override by modelConfig, overrideAIConfig, etc.\r\n // also avoid circular dependency\r\n const debugMode = process.env[SQAI_DEBUG_MODE];\r\n if (debugMode) {\r\n console.log('[SQAI]', ...message);\r\n }\r\n}\r\n\r\nlet lastReportedRepoUrl = '';\r\nexport function uploadTestInfoToServer({\r\n testUrl,\r\n serverUrl,\r\n}: { testUrl: string; serverUrl?: string }) {\r\n let repoUrl = '';\r\n let userEmail = '';\r\n\r\n try {\r\n repoUrl = execSync('git config --get remote.origin.url').toString().trim();\r\n userEmail = execSync('git config --get user.email').toString().trim();\r\n } catch (error) {\r\n debugLog('Failed to get git info:', error);\r\n }\r\n\r\n // Only upload test info if:\r\n // 1. Server URL is configured AND\r\n // 2. Either:\r\n // - We have a repo URL that's different from last reported one (to avoid duplicate reports)\r\n // - OR we don't have a repo URL but have a test URL (for non-git environments)\r\n if (\r\n serverUrl &&\r\n ((repoUrl && repoUrl !== lastReportedRepoUrl) || (!repoUrl && testUrl))\r\n ) {\r\n debugLog('Uploading test info to server', {\r\n serverUrl,\r\n repoUrl,\r\n testUrl,\r\n userEmail,\r\n });\r\n\r\n fetch(serverUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n repo_url: repoUrl,\r\n test_url: testUrl,\r\n user_email: userEmail,\r\n }),\r\n })\r\n .then((response) => response.json())\r\n .then((data) => {\r\n debugLog('Successfully uploaded test info to server:', data);\r\n })\r\n .catch((error) =>\r\n debugLog('Failed to upload test info to server:', error),\r\n );\r\n lastReportedRepoUrl = repoUrl;\r\n }\r\n}\r\n"],"names":["logEnvReady","groupedActionDumpFileExt","processCacheConfig","cache","cacheId","undefined","envEnabled","globalConfigManager","SQAI_CACHE","reportInitializedMap","Map","getReportTpl","reportTpl","insertScriptBeforeClosingHtml","filePath","scriptContent","htmlEndTag","stat","fs","readSize","Math","start","buffer","Buffer","fd","tailStr","htmlEndIdx","Error","beforeHtmlInTail","htmlEndPos","reportHTMLContent","dumpData","reportPath","appendReport","withTpl","tpl","console","writeToFile","ifInBrowser","dumpContent","escapeScriptTag","dumpString","attributes","attributesArr","Object","key","encodeURIComponent","writeFileSync","writeDumpReport","fileName","ifInWorker","path","getMidsceneRunSubDir","process","jsonPath","data","JSON","logMsg","writeLogFile","opts","fileExt","fileContent","type","targetDir","assert","gitIgnorePath","gitPath","gitIgnoreContent","existsSync","readFileSync","defaultRunDirName","getTmpDir","runningPkgInfo","getRunningPkgInfo","name","tmpPath","tmpdir","mkdirSync","e","getTmpFile","fileExtWithoutDot","tmpDir","filename","uuid","overlapped","container","target","sleep","ms","Promise","resolve","setTimeout","replacerForPageObject","_key","value","_value_constructor","_value_constructor1","stringifyDumpData","indents","getVersion","__VERSION__","debugLog","message","debugMode","SQAI_DEBUG_MODE","lastReportedRepoUrl","uploadTestInfoToServer","testUrl","serverUrl","repoUrl","userEmail","execSync","error","fetch","response"],"mappings":";;;;;;;;AAwBA,IAAIA,cAAc;AAIX,MAAMC,2BAA2B;AAWjC,SAASC,mBACdC,KAAwB,EACxBC,OAAe;IAGf,IAAID,AAAUE,WAAVF,OAAqB;QACvB,IAAIA,AAAU,UAAVA,OACF;QAGF,IAAIA,AAAU,SAAVA,OAGF,OAAO;YAAE,IAAIC;QAAQ;QAIvB,IAAI,AAAiB,YAAjB,OAAOD,SAAsBA,AAAU,SAAVA,OAAgB;YAE/C,IAAI,CAACA,MAAM,EAAE,EACX,OAAO;gBAAE,GAAGA,KAAK;gBAAE,IAAIC;YAAQ;YAEjC,OAAOD;QACT;IACF;IAIA,MAAMG,aAAaC,oBAAoB,qBAAqB,CAACC;IAE7D,IAAIF,cAAcF,SAChB,OAAO;QAAE,IAAIA;IAAQ;AAKzB;AAEA,MAAMK,uBAAuB,IAAIC;AAI1B,SAASC;IAId,MAAMC,YAAY;IAElB,OAAOA;AACT;AAMO,SAASC,8BACdC,QAAgB,EAChBC,aAAqB;IAErB,MAAMC,aAAa;IACnB,MAAMC,OAAOC,SAAYJ;IAEzB,MAAMK,WAAWC,KAAK,GAAG,CAACH,KAAK,IAAI,EAAE;IACrC,MAAMI,QAAQD,KAAK,GAAG,CAAC,GAAGH,KAAK,IAAI,GAAGE;IACtC,MAAMG,SAASC,OAAO,KAAK,CAACN,KAAK,IAAI,GAAGI;IACxC,MAAMG,KAAKN,SAAYJ,UAAU;IACjCI,SAAYM,IAAIF,QAAQ,GAAGA,OAAO,MAAM,EAAED;IAC1CH,UAAaM;IAEb,MAAMC,UAAUH,OAAO,QAAQ,CAAC;IAChC,MAAMI,aAAaD,QAAQ,WAAW,CAACT;IACvC,IAAIU,AAAe,OAAfA,YACF,MAAM,IAAIC,MAAM,CAAC,gCAAyB,EAAEb,UAAU;IAIxD,MAAMc,mBAAmBH,QAAQ,KAAK,CAAC,GAAGC;IAC1C,MAAMG,aAAaR,QAAQE,OAAO,UAAU,CAACK,kBAAkB;IAG/DV,aAAgBJ,UAAUe;IAE1BX,eAAkBJ,UAAU,GAAGC,cAAc,EAAE,EAAEC,WAAW,EAAE,CAAC;AACjE;AAEO,SAASc,kBACdC,QAA2C,EAC3CC,UAAmB,EACnBC,YAAsB,EACtBC,UAAU,IAAI;IAEd,IAAIC,MAAM;IACV,IAAID,SAAS;QACXC,MAAMxB;QAEN,IAAI,CAACwB,KAAK;YACRC,QAAQ,IAAI,CAAC;YACb,OAAO;QACT;IACF;IAEA,MAAMC,cAAcL,cAAc,CAACM;IACnC,IAAIC,cAAc;IAElB,IAAI,AAAoB,YAApB,OAAOR,UAETQ,cAEE,4DACAC,gBAAgBT,YAChB;SACG;QACL,MAAM,EAAEU,UAAU,EAAEC,UAAU,EAAE,GAAGX;QACnC,MAAMY,gBAAgBC,OAAO,IAAI,CAACF,cAAc,CAAC,GAAG,GAAG,CAAC,CAACG,MAChD,GAAGA,IAAI,EAAE,EAAEC,mBAAmBJ,UAAW,CAACG,IAAI,EAAE,CAAC,CAAC;QAG3DN,cAGE,0DACAI,cAAc,IAAI,CAAC,OACnB,QACAH,gBAAgBC,cAChB;IACJ;IAEA,IAAIJ,aAAa;QACf,IAAI,CAACJ,cAAc;YACjBc,cAAcf,YAAaG,MAAMI,aAAa;gBAAE,MAAM;YAAI;YAC1D,OAAOP;QACT;QAEA,IAAI,CAACvB,qBAAqB,GAAG,CAACuB,aAAc;YAC1Ce,cAAcf,YAAaG,KAAK;gBAAE,MAAM;YAAI;YAC5C1B,qBAAqB,GAAG,CAACuB,YAAa;QACxC;QAEAnB,8BAA8BmB,YAAaO;QAC3C,OAAOP;IACT;IAEA,OAAOG,MAAMI;AACf;AAEO,SAASS,gBACdC,QAAgB,EAChBlB,QAA2C,EAC3CE,YAAsB;IAEtB,IAAIK,eAAeY,YAAY;QAC7Bd,QAAQ,GAAG,CAAC;QACZ,OAAO;IACT;IAEA,MAAMJ,aAAamB,KACjBC,qBAAqB,WACrB,GAAGH,SAAS,KAAK,CAAC;IAGpBnB,kBAAkBC,UAAUC,YAAYC;IAExC,IAAIoB,QAAQ,GAAG,CAAC,mBAAmB,EAAE;QACnC,MAAMC,WAAW,GAAGtB,WAAW,KAAK,CAAC;QACrC,IAAIuB;QAGFA,OADE,AAAoB,YAApB,OAAOxB,WACFyB,KAAK,KAAK,CAACzB,YAEXA;QAGTgB,cAAcO,UAAUE,KAAK,SAAS,CAACD,MAAM,MAAM,IAAI;YACrD,MAAMtB,eAAe,MAAM;QAC7B;QAEAwB,OAAO,CAAC,8BAA8B,EAAEH,UAAU;IACpD;IAEA,OAAOtB;AACT;AAEO,SAAS0B,aAAaC,IAO5B;IACC,IAAIrB,eAAeY,YACjB,OAAO;IAET,MAAM,EAAED,QAAQ,EAAEW,OAAO,EAAEC,WAAW,EAAEC,OAAO,MAAM,EAAE,GAAGH;IAC1D,MAAMI,YAAYX,qBAAqBU;IAEvC,IAAI,CAAC9D,aAAa;QAChBgE,OAAOD,WAAW;QAGlB,MAAME,gBAAgBd,KAAUY,WAAW;QAC3C,MAAMG,UAAUf,KAAUY,WAAW;QACrC,IAAII,mBAAmB;QAEvB,IAAIC,WAAWF,UAAU;YAEvB,IAAIE,WAAWH,gBACbE,mBAAmBE,aAAaJ,eAAe;YAIjD,IAAI,CAACE,iBAAiB,QAAQ,CAAC,GAAGG,kBAAkB,CAAC,CAAC,GACpDvB,cACEkB,eACA,GAAGE,iBAAiB,4BAA4B,EAAEG,kBAAkB,OAAO,EAAEA,kBAAkB,SAAS,EAAEA,kBAAkB,MAAM,EAAEA,kBAAkB,MAAM,CAAC,EAC7J;QAGN;QAEAtE,cAAc;IAChB;IAEA,MAAMc,WAAWqC,KAAUY,WAAW,GAAGd,SAAS,CAAC,EAAEW,SAAS;IAE9D,IAAIE,AAAS,WAATA,MAEFf,cAAcjC,UAAU0C,KAAK,SAAS,CAACK;IAGzC,IAAIF,QAAAA,OAAAA,KAAAA,IAAAA,KAAM,cAAc,EACtB,OAAOX,gBAAgBC,UAAUY,aAAaF,KAAK,YAAY;IAGjE,OAAO7C;AACT;AAEO,SAASyD;IACd,IAAI;QACF,MAAMC,iBAAiBC;QACvB,IAAI,CAACD,gBACH,OAAO;QAET,MAAM,EAAEE,IAAI,EAAE,GAAGF;QACjB,MAAMG,UAAUxB,KAAUyB,UAAUF;QACpCG,UAAUF,SAAS;YAAE,WAAW;QAAK;QACrC,OAAOA;IACT,EAAE,OAAOG,GAAG;QACV,OAAO;IACT;AACF;AAEO,SAASC,WAAWC,iBAAyB;IAClD,IAAI1C,eAAeY,YACjB,OAAO;IAET,MAAM+B,SAASV;IACf,MAAMW,WAAW,GAAGC,OAAO,CAAC,EAAEH,mBAAmB;IACjD,OAAO7B,KAAU8B,QAASC;AAC5B;AAEO,SAASE,WAAWC,SAAe,EAAEC,MAAY;IAEtD,OACED,UAAU,IAAI,GAAGC,OAAO,IAAI,GAAGA,OAAO,KAAK,IAC3CD,UAAU,IAAI,GAAGA,UAAU,KAAK,GAAGC,OAAO,IAAI,IAC9CD,UAAU,GAAG,GAAGC,OAAO,GAAG,GAAGA,OAAO,MAAM,IAC1CD,UAAU,GAAG,GAAGA,UAAU,MAAM,GAAGC,OAAO,GAAG;AAEjD;AAEO,eAAeC,MAAMC,EAAU;IACpC,OAAO,IAAIC,QAAQ,CAACC,UAAYC,WAAWD,SAASF;AACtD;AAEO,SAASI,sBAAsBC,IAAY,EAAEC,KAAU;QAC/CC,oBAGAC;IAHb,IAAIF,SAASC,AAAAA,SAAAA,CAAAA,qBAAAA,MAAM,WAAW,AAAD,IAAhBA,KAAAA,IAAAA,mBAAmB,IAAI,AAAD,MAAM,QACvC,OAAO;IAET,IAAID,SAASE,AAAAA,SAAAA,CAAAA,sBAAAA,MAAM,WAAW,AAAD,IAAhBA,KAAAA,IAAAA,oBAAmB,IAAI,AAAD,MAAM,WACvC,OAAO;IAET,OAAOF;AACT;AAEO,SAASG,kBAAkB1C,IAAS,EAAE2C,OAAgB;IAC3D,OAAO1C,KAAK,SAAS,CAACD,MAAMqC,uBAAuBM;AACrD;AAIO,SAASC;IACd,OAAOC;AACT;AAEA,SAASC,SAAS,GAAGC,OAAc;IAGjC,MAAMC,YAAYlD,QAAQ,GAAG,CAACmD,gBAAgB;IAC9C,IAAID,WACFnE,QAAQ,GAAG,CAAC,aAAakE;AAE7B;AAEA,IAAIG,sBAAsB;AACnB,SAASC,uBAAuB,EACrCC,OAAO,EACPC,SAAS,EAC+B;IACxC,IAAIC,UAAU;IACd,IAAIC,YAAY;IAEhB,IAAI;QACFD,UAAUE,SAAS,sCAAsC,QAAQ,GAAG,IAAI;QACxED,YAAYC,SAAS,+BAA+B,QAAQ,GAAG,IAAI;IACrE,EAAE,OAAOC,OAAO;QACdX,SAAS,2BAA2BW;IACtC;IAOA,IACEJ,aACEC,CAAAA,WAAWA,YAAYJ,uBAAyB,CAACI,WAAWF,OAAM,GACpE;QACAN,SAAS,iCAAiC;YACxCO;YACAC;YACAF;YACAG;QACF;QAEAG,MAAML,WAAW;YACf,QAAQ;YACR,SAAS;gBACP,gBAAgB;YAClB;YACA,MAAMpD,KAAK,SAAS,CAAC;gBACnB,UAAUqD;gBACV,UAAUF;gBACV,YAAYG;YACd;QACF,GACG,IAAI,CAAC,CAACI,WAAaA,SAAS,IAAI,IAChC,IAAI,CAAC,CAAC3D;YACL8C,SAAS,8CAA8C9C;QACzD,GACC,KAAK,CAAC,CAACyD,QACNX,SAAS,yCAAyCW;QAEtDP,sBAAsBI;IACxB;AACF"}
|
package/dist/lib/agent/utils.js
CHANGED
|
@@ -190,7 +190,7 @@ function trimContextByViewport(execution) {
|
|
|
190
190
|
}) : execution.tasks
|
|
191
191
|
};
|
|
192
192
|
}
|
|
193
|
-
const getMidsceneVersion = ()=>"0.30.
|
|
193
|
+
const getMidsceneVersion = ()=>"0.30.14";
|
|
194
194
|
const parsePrompt = (prompt)=>{
|
|
195
195
|
if ('string' == typeof prompt) return {
|
|
196
196
|
textPrompt: prompt,
|
|
@@ -361,7 +361,7 @@ var __webpack_exports__ = {};
|
|
|
361
361
|
};
|
|
362
362
|
} catch (e) {
|
|
363
363
|
console.error(' call AI error', e);
|
|
364
|
-
const newError = new Error(`failed to call ${isStreaming ? 'streaming ' : ''}AI model service: ${e.message}. Trouble shooting: https://
|
|
364
|
+
const newError = new Error(`failed to call ${isStreaming ? 'streaming ' : ''}AI model service: ${e.message}. Trouble shooting: https://sqai.tech/model-provider.html`, {
|
|
365
365
|
cause: e
|
|
366
366
|
});
|
|
367
367
|
throw newError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-model\\service-caller\\index.js","sources":["webpack://@sqaitech/core/webpack/runtime/compat_get_default_export","webpack://@sqaitech/core/webpack/runtime/define_property_getters","webpack://@sqaitech/core/webpack/runtime/has_own_property","webpack://@sqaitech/core/webpack/runtime/make_namespace_object","webpack://@sqaitech/core/./src/ai-model/service-caller/index.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { AIResponseFormat, type AIUsageInfo } from '@/types';\r\nimport type { CodeGenerationChunk, StreamingCallback } from '@/types';\r\nimport { Anthropic } from '@anthropic-ai/sdk';\r\nimport {\r\n DefaultAzureCredential,\r\n getBearerTokenProvider,\r\n} from '@azure/identity';\r\nimport {\r\n type IModelConfig,\r\n SQAI_API_TYPE,\r\n SQAI_LANGSMITH_DEBUG,\r\n OPENAI_MAX_TOKENS,\r\n type TVlModeTypes,\r\n type UITarsModelVersion,\r\n globalConfigManager,\r\n} from '@sqaitech/shared/env';\r\n\r\nimport { parseBase64 } from '@sqaitech/shared/img';\r\nimport { getDebug } from '@sqaitech/shared/logger';\r\nimport { assert } from '@sqaitech/shared/utils';\r\nimport { ifInBrowser } from '@sqaitech/shared/utils';\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\nimport { jsonrepair } from 'jsonrepair';\r\nimport OpenAI, { AzureOpenAI } from 'openai';\r\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\r\nimport type { Stream } from 'openai/streaming';\r\nimport { SocksProxyAgent } from 'socks-proxy-agent';\r\nimport { AIActionType, type AIArgs } from '../common';\r\nimport { assertSchema } from '../prompt/assertion';\r\nimport { locatorSchema } from '../prompt/llm-locator';\r\nimport { planSchema } from '../prompt/llm-planning';\r\n\r\nasync function createChatClient({\r\n AIActionTypeValue,\r\n modelConfig,\r\n}: {\r\n AIActionTypeValue: AIActionType;\r\n modelConfig: IModelConfig;\r\n}): Promise<{\r\n completion: OpenAI.Chat.Completions;\r\n style: 'openai' | 'anthropic';\r\n modelName: string;\r\n modelDescription: string;\r\n uiTarsVersion?: UITarsModelVersion;\r\n vlMode: TVlModeTypes | undefined;\r\n}> {\r\n const {\r\n socksProxy,\r\n httpProxy,\r\n modelName,\r\n openaiBaseURL,\r\n openaiApiKey,\r\n openaiExtraConfig,\r\n openaiUseAzureDeprecated,\r\n useAzureOpenai,\r\n azureOpenaiScope,\r\n azureOpenaiKey,\r\n azureOpenaiEndpoint,\r\n azureOpenaiApiVersion,\r\n azureOpenaiDeployment,\r\n azureExtraConfig,\r\n useAnthropicSdk,\r\n anthropicApiKey,\r\n modelDescription,\r\n uiTarsModelVersion: uiTarsVersion,\r\n vlMode,\r\n } = modelConfig;\r\n\r\n let openai: OpenAI | AzureOpenAI | undefined;\r\n\r\n let proxyAgent = undefined;\r\n const debugProxy = getDebug('ai:call:proxy');\r\n if (httpProxy) {\r\n debugProxy('using http proxy', httpProxy);\r\n proxyAgent = new HttpsProxyAgent(httpProxy);\r\n } else if (socksProxy) {\r\n debugProxy('using socks proxy', socksProxy);\r\n proxyAgent = new SocksProxyAgent(socksProxy);\r\n }\r\n\r\n if (openaiUseAzureDeprecated) {\r\n // this is deprecated\r\n openai = new AzureOpenAI({\r\n baseURL: openaiBaseURL,\r\n apiKey: openaiApiKey,\r\n httpAgent: proxyAgent,\r\n ...openaiExtraConfig,\r\n dangerouslyAllowBrowser: true,\r\n }) as OpenAI;\r\n } else if (useAzureOpenai) {\r\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\r\n // keyless authentication\r\n let tokenProvider: any = undefined;\r\n if (azureOpenaiScope) {\r\n assert(\r\n !ifInBrowser,\r\n 'Azure OpenAI is not supported in browser with Midscene.',\r\n );\r\n const credential = new DefaultAzureCredential();\r\n\r\n tokenProvider = getBearerTokenProvider(credential, azureOpenaiScope);\r\n\r\n openai = new AzureOpenAI({\r\n azureADTokenProvider: tokenProvider,\r\n endpoint: azureOpenaiEndpoint,\r\n apiVersion: azureOpenaiApiVersion,\r\n deployment: azureOpenaiDeployment,\r\n ...openaiExtraConfig,\r\n ...azureExtraConfig,\r\n });\r\n } else {\r\n // endpoint, apiKey, apiVersion, deployment\r\n openai = new AzureOpenAI({\r\n apiKey: azureOpenaiKey,\r\n endpoint: azureOpenaiEndpoint,\r\n apiVersion: azureOpenaiApiVersion,\r\n deployment: azureOpenaiDeployment,\r\n dangerouslyAllowBrowser: true,\r\n ...openaiExtraConfig,\r\n ...azureExtraConfig,\r\n });\r\n }\r\n } else if (!useAnthropicSdk) {\r\n openai = new OpenAI({\r\n baseURL: openaiBaseURL,\r\n apiKey: openaiApiKey,\r\n httpAgent: proxyAgent,\r\n ...openaiExtraConfig,\r\n defaultHeaders: {\r\n ...(openaiExtraConfig?.defaultHeaders || {}),\r\n [SQAI_API_TYPE]: AIActionTypeValue.toString(),\r\n },\r\n dangerouslyAllowBrowser: true,\r\n });\r\n }\r\n\r\n if (\r\n openai &&\r\n globalConfigManager.getEnvConfigInBoolean(SQAI_LANGSMITH_DEBUG)\r\n ) {\r\n if (ifInBrowser) {\r\n throw new Error('langsmith is not supported in browser');\r\n }\r\n console.log('DEBUGGING MODE: langsmith wrapper enabled');\r\n const { wrapOpenAI } = await import('langsmith/wrappers');\r\n openai = wrapOpenAI(openai);\r\n }\r\n\r\n if (typeof openai !== 'undefined') {\r\n return {\r\n completion: openai.chat.completions,\r\n style: 'openai',\r\n modelName,\r\n modelDescription,\r\n uiTarsVersion,\r\n vlMode,\r\n };\r\n }\r\n\r\n // Anthropic\r\n if (useAnthropicSdk) {\r\n openai = new Anthropic({\r\n apiKey: anthropicApiKey,\r\n httpAgent: proxyAgent,\r\n dangerouslyAllowBrowser: true,\r\n }) as any;\r\n }\r\n\r\n if (typeof openai !== 'undefined' && (openai as any).messages) {\r\n return {\r\n completion: (openai as any).messages,\r\n style: 'anthropic',\r\n modelName,\r\n modelDescription,\r\n uiTarsVersion,\r\n vlMode,\r\n };\r\n }\r\n\r\n throw new Error('Openai SDK or Anthropic SDK is not initialized');\r\n}\r\n\r\nexport async function callAI(\r\n messages: ChatCompletionMessageParam[],\r\n AIActionTypeValue: AIActionType,\r\n modelConfig: IModelConfig,\r\n options?: {\r\n stream?: boolean;\r\n onChunk?: StreamingCallback;\r\n },\r\n): Promise<{ content: string; usage?: AIUsageInfo; isStreamed: boolean }> {\r\n const {\r\n completion,\r\n style,\r\n modelName,\r\n modelDescription,\r\n uiTarsVersion,\r\n vlMode,\r\n } = await createChatClient({\r\n AIActionTypeValue,\r\n modelConfig,\r\n });\r\n\r\n const responseFormat = getResponseFormat(modelName, AIActionTypeValue);\r\n\r\n const maxTokens = globalConfigManager.getEnvConfigValue(OPENAI_MAX_TOKENS);\r\n const debugCall = getDebug('ai:call');\r\n const debugProfileStats = getDebug('ai:profile:stats');\r\n const debugProfileDetail = getDebug('ai:profile:detail');\r\n\r\n const startTime = Date.now();\r\n\r\n const isStreaming = options?.stream && options?.onChunk;\r\n let content: string | undefined;\r\n let accumulated = '';\r\n let usage: OpenAI.CompletionUsage | undefined;\r\n let timeCost: number | undefined;\r\n\r\n const commonConfig = {\r\n temperature: vlMode === 'vlm-ui-tars' ? 0.0 : 0.1,\r\n stream: !!isStreaming,\r\n max_tokens:\r\n typeof maxTokens === 'number'\r\n ? maxTokens\r\n : Number.parseInt(maxTokens || '2048', 10),\r\n ...(vlMode === 'qwen-vl' || vlMode === 'qwen3-vl' // qwen specific config\r\n ? {\r\n vl_high_resolution_images: true,\r\n }\r\n : {}),\r\n };\r\n\r\n try {\r\n if (style === 'openai') {\r\n debugCall(\r\n `sending ${isStreaming ? 'streaming ' : ''}request to ${modelName}`,\r\n );\r\n\r\n if (isStreaming) {\r\n const stream = (await completion.create(\r\n {\r\n model: modelName,\r\n messages,\r\n response_format: responseFormat,\r\n ...commonConfig,\r\n },\r\n {\r\n stream: true,\r\n },\r\n )) as Stream<OpenAI.Chat.Completions.ChatCompletionChunk> & {\r\n _request_id?: string | null;\r\n };\r\n\r\n for await (const chunk of stream) {\r\n const content = chunk.choices?.[0]?.delta?.content || '';\r\n const reasoning_content =\r\n (chunk.choices?.[0]?.delta as any)?.reasoning_content || '';\r\n\r\n // Check for usage info in any chunk (OpenAI provides usage in separate chunks)\r\n if (chunk.usage) {\r\n usage = chunk.usage;\r\n }\r\n\r\n if (content || reasoning_content) {\r\n accumulated += content;\r\n const chunkData: CodeGenerationChunk = {\r\n content,\r\n reasoning_content,\r\n accumulated,\r\n isComplete: false,\r\n usage: undefined,\r\n };\r\n options.onChunk!(chunkData);\r\n }\r\n\r\n // Check if stream is complete\r\n if (chunk.choices?.[0]?.finish_reason) {\r\n timeCost = Date.now() - startTime;\r\n\r\n // If usage is not available from the stream, provide a basic usage info\r\n if (!usage) {\r\n // Estimate token counts based on content length (rough approximation)\r\n const estimatedTokens = Math.max(\r\n 1,\r\n Math.floor(accumulated.length / 4),\r\n );\r\n usage = {\r\n prompt_tokens: estimatedTokens,\r\n completion_tokens: estimatedTokens,\r\n total_tokens: estimatedTokens * 2,\r\n };\r\n }\r\n\r\n // Send final chunk\r\n const finalChunk: CodeGenerationChunk = {\r\n content: '',\r\n accumulated,\r\n reasoning_content: '',\r\n isComplete: true,\r\n usage: {\r\n prompt_tokens: usage.prompt_tokens ?? 0,\r\n completion_tokens: usage.completion_tokens ?? 0,\r\n total_tokens: usage.total_tokens ?? 0,\r\n time_cost: timeCost ?? 0,\r\n model_name: modelName,\r\n model_description: modelDescription,\r\n intent: modelConfig.intent,\r\n },\r\n };\r\n options.onChunk!(finalChunk);\r\n break;\r\n }\r\n }\r\n content = accumulated;\r\n debugProfileStats(\r\n `streaming model, ${modelName}, mode, ${vlMode || 'default'}, cost-ms, ${timeCost}`,\r\n );\r\n } else {\r\n const result = await completion.create({\r\n model: modelName,\r\n messages,\r\n response_format: responseFormat,\r\n ...commonConfig,\r\n } as any);\r\n timeCost = Date.now() - startTime;\r\n\r\n debugProfileStats(\r\n `model, ${modelName}, mode, ${vlMode || 'default'}, ui-tars-version, ${uiTarsVersion}, 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 || ''}`,\r\n );\r\n\r\n debugProfileDetail(\r\n `model usage detail: ${JSON.stringify(result.usage)}`,\r\n );\r\n\r\n assert(\r\n result.choices,\r\n `invalid response from LLM service: ${JSON.stringify(result)}`,\r\n );\r\n content = result.choices[0].message.content!;\r\n usage = result.usage;\r\n }\r\n\r\n debugCall(`response: ${content}`);\r\n assert(content, 'empty content');\r\n } else if (style === 'anthropic') {\r\n const convertImageContent = (content: any) => {\r\n if (content.type === 'image_url') {\r\n const imgBase64 = content.image_url.url;\r\n assert(imgBase64, 'image_url is required');\r\n const { mimeType, body } = parseBase64(content.image_url.url);\r\n return {\r\n source: {\r\n type: 'base64',\r\n media_type: mimeType,\r\n data: body,\r\n },\r\n type: 'image',\r\n };\r\n }\r\n return content;\r\n };\r\n\r\n if (isStreaming) {\r\n const stream = (await completion.create({\r\n model: modelName,\r\n system: 'You are a versatile professional in software UI automation',\r\n messages: messages.map((m) => ({\r\n role: 'user',\r\n content: Array.isArray(m.content)\r\n ? (m.content as any).map(convertImageContent)\r\n : m.content,\r\n })),\r\n response_format: responseFormat,\r\n ...commonConfig,\r\n } as any)) as any;\r\n\r\n for await (const chunk of stream) {\r\n const content = chunk.delta?.text || '';\r\n if (content) {\r\n accumulated += content;\r\n const chunkData: CodeGenerationChunk = {\r\n content,\r\n accumulated,\r\n reasoning_content: '',\r\n isComplete: false,\r\n usage: undefined,\r\n };\r\n options.onChunk!(chunkData);\r\n }\r\n\r\n // Check if stream is complete\r\n if (chunk.type === 'message_stop') {\r\n timeCost = Date.now() - startTime;\r\n const anthropicUsage = chunk.usage;\r\n\r\n // Send final chunk\r\n const finalChunk: CodeGenerationChunk = {\r\n content: '',\r\n accumulated,\r\n reasoning_content: '',\r\n isComplete: true,\r\n usage: anthropicUsage\r\n ? {\r\n prompt_tokens: anthropicUsage.input_tokens ?? 0,\r\n completion_tokens: anthropicUsage.output_tokens ?? 0,\r\n total_tokens:\r\n (anthropicUsage.input_tokens ?? 0) +\r\n (anthropicUsage.output_tokens ?? 0),\r\n time_cost: timeCost ?? 0,\r\n model_name: modelName,\r\n model_description: modelDescription,\r\n intent: modelConfig.intent,\r\n }\r\n : undefined,\r\n };\r\n options.onChunk!(finalChunk);\r\n break;\r\n }\r\n }\r\n content = accumulated;\r\n } else {\r\n const result = await completion.create({\r\n model: modelName,\r\n system: 'You are a versatile professional in software UI automation',\r\n messages: messages.map((m) => ({\r\n role: 'user',\r\n content: Array.isArray(m.content)\r\n ? (m.content as any).map(convertImageContent)\r\n : m.content,\r\n })),\r\n response_format: responseFormat,\r\n ...commonConfig,\r\n } as any);\r\n timeCost = Date.now() - startTime;\r\n content = (result as any).content[0].text as string;\r\n usage = result.usage;\r\n }\r\n\r\n assert(content, 'empty content');\r\n }\r\n // Ensure we always have usage info for streaming responses\r\n if (isStreaming && !usage) {\r\n // Estimate token counts based on content length (rough approximation)\r\n const estimatedTokens = Math.max(\r\n 1,\r\n Math.floor((content || '').length / 4),\r\n );\r\n usage = {\r\n prompt_tokens: estimatedTokens,\r\n completion_tokens: estimatedTokens,\r\n total_tokens: estimatedTokens * 2,\r\n };\r\n }\r\n\r\n return {\r\n content: content || '',\r\n usage: usage\r\n ? {\r\n prompt_tokens: usage.prompt_tokens ?? 0,\r\n completion_tokens: usage.completion_tokens ?? 0,\r\n total_tokens: usage.total_tokens ?? 0,\r\n time_cost: timeCost ?? 0,\r\n model_name: modelName,\r\n model_description: modelDescription,\r\n intent: modelConfig.intent,\r\n }\r\n : undefined,\r\n isStreamed: !!isStreaming,\r\n };\r\n } catch (e: any) {\r\n console.error(' call AI error', e);\r\n const newError = new Error(\r\n `failed to call ${isStreaming ? 'streaming ' : ''}AI model service: ${e.message}. Trouble shooting: https://midscenejs.com/model-provider.html`,\r\n {\r\n cause: e,\r\n },\r\n );\r\n throw newError;\r\n }\r\n}\r\n\r\nexport const getResponseFormat = (\r\n modelName: string,\r\n AIActionTypeValue: AIActionType,\r\n):\r\n | OpenAI.ChatCompletionCreateParams['response_format']\r\n | OpenAI.ResponseFormatJSONObject => {\r\n let responseFormat:\r\n | OpenAI.ChatCompletionCreateParams['response_format']\r\n | OpenAI.ResponseFormatJSONObject\r\n | undefined;\r\n\r\n if (modelName.includes('gpt-4')) {\r\n switch (AIActionTypeValue) {\r\n case AIActionType.ASSERT:\r\n responseFormat = assertSchema;\r\n break;\r\n case AIActionType.INSPECT_ELEMENT:\r\n responseFormat = locatorSchema;\r\n break;\r\n case AIActionType.PLAN:\r\n responseFormat = planSchema;\r\n break;\r\n case AIActionType.EXTRACT_DATA:\r\n case AIActionType.DESCRIBE_ELEMENT:\r\n responseFormat = { type: AIResponseFormat.JSON };\r\n break;\r\n case AIActionType.TEXT:\r\n // No response format for plain text - return as-is\r\n responseFormat = undefined;\r\n break;\r\n }\r\n }\r\n\r\n // gpt-4o-2024-05-13 only supports json_object response format\r\n // Skip for plain text to allow string output\r\n if (\r\n modelName === 'gpt-4o-2024-05-13' &&\r\n AIActionTypeValue !== AIActionType.TEXT\r\n ) {\r\n responseFormat = { type: AIResponseFormat.JSON };\r\n }\r\n\r\n return responseFormat;\r\n};\r\n\r\nexport async function callAIWithObjectResponse<T>(\r\n messages: ChatCompletionMessageParam[],\r\n AIActionTypeValue: AIActionType,\r\n modelConfig: IModelConfig,\r\n): Promise<{ content: T; usage?: AIUsageInfo }> {\r\n const response = await callAI(messages, AIActionTypeValue, modelConfig);\r\n assert(response, 'empty response');\r\n const vlMode = modelConfig.vlMode;\r\n const jsonContent = safeParseJson(response.content, vlMode);\r\n return { content: jsonContent, usage: response.usage };\r\n}\r\n\r\nexport async function callAIWithStringResponse(\r\n msgs: AIArgs,\r\n AIActionTypeValue: AIActionType,\r\n modelConfig: IModelConfig,\r\n): Promise<{ content: string; usage?: AIUsageInfo }> {\r\n const { content, usage } = await callAI(msgs, AIActionTypeValue, modelConfig);\r\n return { content, usage };\r\n}\r\n\r\nexport function extractJSONFromCodeBlock(response: string) {\r\n try {\r\n // First, try to match a JSON object directly in the response\r\n const jsonMatch = response.match(/^\\s*(\\{[\\s\\S]*\\})\\s*$/);\r\n if (jsonMatch) {\r\n return jsonMatch[1];\r\n }\r\n\r\n // If no direct JSON object is found, try to extract JSON from a code block\r\n const codeBlockMatch = response.match(\r\n /```(?:json)?\\s*(\\{[\\s\\S]*?\\})\\s*```/,\r\n );\r\n if (codeBlockMatch) {\r\n return codeBlockMatch[1];\r\n }\r\n\r\n // If no code block is found, try to find a JSON-like structure in the text\r\n const jsonLikeMatch = response.match(/\\{[\\s\\S]*\\}/);\r\n if (jsonLikeMatch) {\r\n return jsonLikeMatch[0];\r\n }\r\n } catch {}\r\n // If no JSON-like structure is found, return the original response\r\n return response;\r\n}\r\n\r\nexport function preprocessDoubaoBboxJson(input: string) {\r\n if (input.includes('bbox')) {\r\n // when its values like 940 445 969 490, replace all /\\d+\\s+\\d+/g with /$1,$2/g\r\n while (/\\d+\\s+\\d+/.test(input)) {\r\n input = input.replace(/(\\d+)\\s+(\\d+)/g, '$1,$2');\r\n }\r\n }\r\n return input;\r\n}\r\n\r\nexport function safeParseJson(input: string, vlMode: TVlModeTypes | undefined) {\r\n const cleanJsonString = extractJSONFromCodeBlock(input);\r\n // match the point\r\n if (cleanJsonString?.match(/\\((\\d+),(\\d+)\\)/)) {\r\n return cleanJsonString\r\n .match(/\\((\\d+),(\\d+)\\)/)\r\n ?.slice(1)\r\n .map(Number);\r\n }\r\n try {\r\n return JSON.parse(cleanJsonString);\r\n } catch {}\r\n try {\r\n return JSON.parse(jsonrepair(cleanJsonString));\r\n } catch (e) {}\r\n\r\n if (vlMode === 'doubao-vision' || vlMode === 'vlm-ui-tars') {\r\n const jsonString = preprocessDoubaoBboxJson(cleanJsonString);\r\n return JSON.parse(jsonrepair(jsonString));\r\n }\r\n throw Error(`failed to parse json response: ${input}`);\r\n}\r\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","createChatClient","AIActionTypeValue","modelConfig","socksProxy","httpProxy","modelName","openaiBaseURL","openaiApiKey","openaiExtraConfig","openaiUseAzureDeprecated","useAzureOpenai","azureOpenaiScope","azureOpenaiKey","azureOpenaiEndpoint","azureOpenaiApiVersion","azureOpenaiDeployment","azureExtraConfig","useAnthropicSdk","anthropicApiKey","modelDescription","uiTarsVersion","vlMode","openai","proxyAgent","debugProxy","getDebug","HttpsProxyAgent","SocksProxyAgent","AzureOpenAI","tokenProvider","assert","ifInBrowser","credential","DefaultAzureCredential","getBearerTokenProvider","OpenAI","SQAI_API_TYPE","globalConfigManager","SQAI_LANGSMITH_DEBUG","Error","console","wrapOpenAI","Anthropic","callAI","messages","options","completion","style","responseFormat","getResponseFormat","maxTokens","OPENAI_MAX_TOKENS","debugCall","debugProfileStats","debugProfileDetail","startTime","Date","isStreaming","content","accumulated","usage","timeCost","commonConfig","Number","stream","chunk","_chunk_choices__delta","_chunk_choices__delta1","_chunk_choices_2","reasoning_content","chunkData","undefined","estimatedTokens","Math","finalChunk","_result_usage","_result_usage1","_result_usage2","result","JSON","convertImageContent","imgBase64","mimeType","body","parseBase64","m","Array","_chunk_delta","anthropicUsage","e","newError","AIActionType","assertSchema","locatorSchema","planSchema","AIResponseFormat","callAIWithObjectResponse","response","jsonContent","safeParseJson","callAIWithStringResponse","msgs","extractJSONFromCodeBlock","jsonMatch","codeBlockMatch","jsonLikeMatch","preprocessDoubaoBboxJson","input","cleanJsonString","_cleanJsonString_match","jsonrepair","jsonString"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai-model\\service-caller\\index.js","sources":["webpack://@sqaitech/core/webpack/runtime/compat_get_default_export","webpack://@sqaitech/core/webpack/runtime/define_property_getters","webpack://@sqaitech/core/webpack/runtime/has_own_property","webpack://@sqaitech/core/webpack/runtime/make_namespace_object","webpack://@sqaitech/core/./src/ai-model/service-caller/index.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { AIResponseFormat, type AIUsageInfo } from '@/types';\r\nimport type { CodeGenerationChunk, StreamingCallback } from '@/types';\r\nimport { Anthropic } from '@anthropic-ai/sdk';\r\nimport {\r\n DefaultAzureCredential,\r\n getBearerTokenProvider,\r\n} from '@azure/identity';\r\nimport {\r\n type IModelConfig,\r\n SQAI_API_TYPE,\r\n SQAI_LANGSMITH_DEBUG,\r\n OPENAI_MAX_TOKENS,\r\n type TVlModeTypes,\r\n type UITarsModelVersion,\r\n globalConfigManager,\r\n} from '@sqaitech/shared/env';\r\n\r\nimport { parseBase64 } from '@sqaitech/shared/img';\r\nimport { getDebug } from '@sqaitech/shared/logger';\r\nimport { assert } from '@sqaitech/shared/utils';\r\nimport { ifInBrowser } from '@sqaitech/shared/utils';\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\nimport { jsonrepair } from 'jsonrepair';\r\nimport OpenAI, { AzureOpenAI } from 'openai';\r\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\r\nimport type { Stream } from 'openai/streaming';\r\nimport { SocksProxyAgent } from 'socks-proxy-agent';\r\nimport { AIActionType, type AIArgs } from '../common';\r\nimport { assertSchema } from '../prompt/assertion';\r\nimport { locatorSchema } from '../prompt/llm-locator';\r\nimport { planSchema } from '../prompt/llm-planning';\r\n\r\nasync function createChatClient({\r\n AIActionTypeValue,\r\n modelConfig,\r\n}: {\r\n AIActionTypeValue: AIActionType;\r\n modelConfig: IModelConfig;\r\n}): Promise<{\r\n completion: OpenAI.Chat.Completions;\r\n style: 'openai' | 'anthropic';\r\n modelName: string;\r\n modelDescription: string;\r\n uiTarsVersion?: UITarsModelVersion;\r\n vlMode: TVlModeTypes | undefined;\r\n}> {\r\n const {\r\n socksProxy,\r\n httpProxy,\r\n modelName,\r\n openaiBaseURL,\r\n openaiApiKey,\r\n openaiExtraConfig,\r\n openaiUseAzureDeprecated,\r\n useAzureOpenai,\r\n azureOpenaiScope,\r\n azureOpenaiKey,\r\n azureOpenaiEndpoint,\r\n azureOpenaiApiVersion,\r\n azureOpenaiDeployment,\r\n azureExtraConfig,\r\n useAnthropicSdk,\r\n anthropicApiKey,\r\n modelDescription,\r\n uiTarsModelVersion: uiTarsVersion,\r\n vlMode,\r\n } = modelConfig;\r\n\r\n let openai: OpenAI | AzureOpenAI | undefined;\r\n\r\n let proxyAgent = undefined;\r\n const debugProxy = getDebug('ai:call:proxy');\r\n if (httpProxy) {\r\n debugProxy('using http proxy', httpProxy);\r\n proxyAgent = new HttpsProxyAgent(httpProxy);\r\n } else if (socksProxy) {\r\n debugProxy('using socks proxy', socksProxy);\r\n proxyAgent = new SocksProxyAgent(socksProxy);\r\n }\r\n\r\n if (openaiUseAzureDeprecated) {\r\n // this is deprecated\r\n openai = new AzureOpenAI({\r\n baseURL: openaiBaseURL,\r\n apiKey: openaiApiKey,\r\n httpAgent: proxyAgent,\r\n ...openaiExtraConfig,\r\n dangerouslyAllowBrowser: true,\r\n }) as OpenAI;\r\n } else if (useAzureOpenai) {\r\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\r\n // keyless authentication\r\n let tokenProvider: any = undefined;\r\n if (azureOpenaiScope) {\r\n assert(\r\n !ifInBrowser,\r\n 'Azure OpenAI is not supported in browser with Midscene.',\r\n );\r\n const credential = new DefaultAzureCredential();\r\n\r\n tokenProvider = getBearerTokenProvider(credential, azureOpenaiScope);\r\n\r\n openai = new AzureOpenAI({\r\n azureADTokenProvider: tokenProvider,\r\n endpoint: azureOpenaiEndpoint,\r\n apiVersion: azureOpenaiApiVersion,\r\n deployment: azureOpenaiDeployment,\r\n ...openaiExtraConfig,\r\n ...azureExtraConfig,\r\n });\r\n } else {\r\n // endpoint, apiKey, apiVersion, deployment\r\n openai = new AzureOpenAI({\r\n apiKey: azureOpenaiKey,\r\n endpoint: azureOpenaiEndpoint,\r\n apiVersion: azureOpenaiApiVersion,\r\n deployment: azureOpenaiDeployment,\r\n dangerouslyAllowBrowser: true,\r\n ...openaiExtraConfig,\r\n ...azureExtraConfig,\r\n });\r\n }\r\n } else if (!useAnthropicSdk) {\r\n openai = new OpenAI({\r\n baseURL: openaiBaseURL,\r\n apiKey: openaiApiKey,\r\n httpAgent: proxyAgent,\r\n ...openaiExtraConfig,\r\n defaultHeaders: {\r\n ...(openaiExtraConfig?.defaultHeaders || {}),\r\n [SQAI_API_TYPE]: AIActionTypeValue.toString(),\r\n },\r\n dangerouslyAllowBrowser: true,\r\n });\r\n }\r\n\r\n if (\r\n openai &&\r\n globalConfigManager.getEnvConfigInBoolean(SQAI_LANGSMITH_DEBUG)\r\n ) {\r\n if (ifInBrowser) {\r\n throw new Error('langsmith is not supported in browser');\r\n }\r\n console.log('DEBUGGING MODE: langsmith wrapper enabled');\r\n const { wrapOpenAI } = await import('langsmith/wrappers');\r\n openai = wrapOpenAI(openai);\r\n }\r\n\r\n if (typeof openai !== 'undefined') {\r\n return {\r\n completion: openai.chat.completions,\r\n style: 'openai',\r\n modelName,\r\n modelDescription,\r\n uiTarsVersion,\r\n vlMode,\r\n };\r\n }\r\n\r\n // Anthropic\r\n if (useAnthropicSdk) {\r\n openai = new Anthropic({\r\n apiKey: anthropicApiKey,\r\n httpAgent: proxyAgent,\r\n dangerouslyAllowBrowser: true,\r\n }) as any;\r\n }\r\n\r\n if (typeof openai !== 'undefined' && (openai as any).messages) {\r\n return {\r\n completion: (openai as any).messages,\r\n style: 'anthropic',\r\n modelName,\r\n modelDescription,\r\n uiTarsVersion,\r\n vlMode,\r\n };\r\n }\r\n\r\n throw new Error('Openai SDK or Anthropic SDK is not initialized');\r\n}\r\n\r\nexport async function callAI(\r\n messages: ChatCompletionMessageParam[],\r\n AIActionTypeValue: AIActionType,\r\n modelConfig: IModelConfig,\r\n options?: {\r\n stream?: boolean;\r\n onChunk?: StreamingCallback;\r\n },\r\n): Promise<{ content: string; usage?: AIUsageInfo; isStreamed: boolean }> {\r\n const {\r\n completion,\r\n style,\r\n modelName,\r\n modelDescription,\r\n uiTarsVersion,\r\n vlMode,\r\n } = await createChatClient({\r\n AIActionTypeValue,\r\n modelConfig,\r\n });\r\n\r\n const responseFormat = getResponseFormat(modelName, AIActionTypeValue);\r\n\r\n const maxTokens = globalConfigManager.getEnvConfigValue(OPENAI_MAX_TOKENS);\r\n const debugCall = getDebug('ai:call');\r\n const debugProfileStats = getDebug('ai:profile:stats');\r\n const debugProfileDetail = getDebug('ai:profile:detail');\r\n\r\n const startTime = Date.now();\r\n\r\n const isStreaming = options?.stream && options?.onChunk;\r\n let content: string | undefined;\r\n let accumulated = '';\r\n let usage: OpenAI.CompletionUsage | undefined;\r\n let timeCost: number | undefined;\r\n\r\n const commonConfig = {\r\n temperature: vlMode === 'vlm-ui-tars' ? 0.0 : 0.1,\r\n stream: !!isStreaming,\r\n max_tokens:\r\n typeof maxTokens === 'number'\r\n ? maxTokens\r\n : Number.parseInt(maxTokens || '2048', 10),\r\n ...(vlMode === 'qwen-vl' || vlMode === 'qwen3-vl' // qwen specific config\r\n ? {\r\n vl_high_resolution_images: true,\r\n }\r\n : {}),\r\n };\r\n\r\n try {\r\n if (style === 'openai') {\r\n debugCall(\r\n `sending ${isStreaming ? 'streaming ' : ''}request to ${modelName}`,\r\n );\r\n\r\n if (isStreaming) {\r\n const stream = (await completion.create(\r\n {\r\n model: modelName,\r\n messages,\r\n response_format: responseFormat,\r\n ...commonConfig,\r\n },\r\n {\r\n stream: true,\r\n },\r\n )) as Stream<OpenAI.Chat.Completions.ChatCompletionChunk> & {\r\n _request_id?: string | null;\r\n };\r\n\r\n for await (const chunk of stream) {\r\n const content = chunk.choices?.[0]?.delta?.content || '';\r\n const reasoning_content =\r\n (chunk.choices?.[0]?.delta as any)?.reasoning_content || '';\r\n\r\n // Check for usage info in any chunk (OpenAI provides usage in separate chunks)\r\n if (chunk.usage) {\r\n usage = chunk.usage;\r\n }\r\n\r\n if (content || reasoning_content) {\r\n accumulated += content;\r\n const chunkData: CodeGenerationChunk = {\r\n content,\r\n reasoning_content,\r\n accumulated,\r\n isComplete: false,\r\n usage: undefined,\r\n };\r\n options.onChunk!(chunkData);\r\n }\r\n\r\n // Check if stream is complete\r\n if (chunk.choices?.[0]?.finish_reason) {\r\n timeCost = Date.now() - startTime;\r\n\r\n // If usage is not available from the stream, provide a basic usage info\r\n if (!usage) {\r\n // Estimate token counts based on content length (rough approximation)\r\n const estimatedTokens = Math.max(\r\n 1,\r\n Math.floor(accumulated.length / 4),\r\n );\r\n usage = {\r\n prompt_tokens: estimatedTokens,\r\n completion_tokens: estimatedTokens,\r\n total_tokens: estimatedTokens * 2,\r\n };\r\n }\r\n\r\n // Send final chunk\r\n const finalChunk: CodeGenerationChunk = {\r\n content: '',\r\n accumulated,\r\n reasoning_content: '',\r\n isComplete: true,\r\n usage: {\r\n prompt_tokens: usage.prompt_tokens ?? 0,\r\n completion_tokens: usage.completion_tokens ?? 0,\r\n total_tokens: usage.total_tokens ?? 0,\r\n time_cost: timeCost ?? 0,\r\n model_name: modelName,\r\n model_description: modelDescription,\r\n intent: modelConfig.intent,\r\n },\r\n };\r\n options.onChunk!(finalChunk);\r\n break;\r\n }\r\n }\r\n content = accumulated;\r\n debugProfileStats(\r\n `streaming model, ${modelName}, mode, ${vlMode || 'default'}, cost-ms, ${timeCost}`,\r\n );\r\n } else {\r\n const result = await completion.create({\r\n model: modelName,\r\n messages,\r\n response_format: responseFormat,\r\n ...commonConfig,\r\n } as any);\r\n timeCost = Date.now() - startTime;\r\n\r\n debugProfileStats(\r\n `model, ${modelName}, mode, ${vlMode || 'default'}, ui-tars-version, ${uiTarsVersion}, 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 || ''}`,\r\n );\r\n\r\n debugProfileDetail(\r\n `model usage detail: ${JSON.stringify(result.usage)}`,\r\n );\r\n\r\n assert(\r\n result.choices,\r\n `invalid response from LLM service: ${JSON.stringify(result)}`,\r\n );\r\n content = result.choices[0].message.content!;\r\n usage = result.usage;\r\n }\r\n\r\n debugCall(`response: ${content}`);\r\n assert(content, 'empty content');\r\n } else if (style === 'anthropic') {\r\n const convertImageContent = (content: any) => {\r\n if (content.type === 'image_url') {\r\n const imgBase64 = content.image_url.url;\r\n assert(imgBase64, 'image_url is required');\r\n const { mimeType, body } = parseBase64(content.image_url.url);\r\n return {\r\n source: {\r\n type: 'base64',\r\n media_type: mimeType,\r\n data: body,\r\n },\r\n type: 'image',\r\n };\r\n }\r\n return content;\r\n };\r\n\r\n if (isStreaming) {\r\n const stream = (await completion.create({\r\n model: modelName,\r\n system: 'You are a versatile professional in software UI automation',\r\n messages: messages.map((m) => ({\r\n role: 'user',\r\n content: Array.isArray(m.content)\r\n ? (m.content as any).map(convertImageContent)\r\n : m.content,\r\n })),\r\n response_format: responseFormat,\r\n ...commonConfig,\r\n } as any)) as any;\r\n\r\n for await (const chunk of stream) {\r\n const content = chunk.delta?.text || '';\r\n if (content) {\r\n accumulated += content;\r\n const chunkData: CodeGenerationChunk = {\r\n content,\r\n accumulated,\r\n reasoning_content: '',\r\n isComplete: false,\r\n usage: undefined,\r\n };\r\n options.onChunk!(chunkData);\r\n }\r\n\r\n // Check if stream is complete\r\n if (chunk.type === 'message_stop') {\r\n timeCost = Date.now() - startTime;\r\n const anthropicUsage = chunk.usage;\r\n\r\n // Send final chunk\r\n const finalChunk: CodeGenerationChunk = {\r\n content: '',\r\n accumulated,\r\n reasoning_content: '',\r\n isComplete: true,\r\n usage: anthropicUsage\r\n ? {\r\n prompt_tokens: anthropicUsage.input_tokens ?? 0,\r\n completion_tokens: anthropicUsage.output_tokens ?? 0,\r\n total_tokens:\r\n (anthropicUsage.input_tokens ?? 0) +\r\n (anthropicUsage.output_tokens ?? 0),\r\n time_cost: timeCost ?? 0,\r\n model_name: modelName,\r\n model_description: modelDescription,\r\n intent: modelConfig.intent,\r\n }\r\n : undefined,\r\n };\r\n options.onChunk!(finalChunk);\r\n break;\r\n }\r\n }\r\n content = accumulated;\r\n } else {\r\n const result = await completion.create({\r\n model: modelName,\r\n system: 'You are a versatile professional in software UI automation',\r\n messages: messages.map((m) => ({\r\n role: 'user',\r\n content: Array.isArray(m.content)\r\n ? (m.content as any).map(convertImageContent)\r\n : m.content,\r\n })),\r\n response_format: responseFormat,\r\n ...commonConfig,\r\n } as any);\r\n timeCost = Date.now() - startTime;\r\n content = (result as any).content[0].text as string;\r\n usage = result.usage;\r\n }\r\n\r\n assert(content, 'empty content');\r\n }\r\n // Ensure we always have usage info for streaming responses\r\n if (isStreaming && !usage) {\r\n // Estimate token counts based on content length (rough approximation)\r\n const estimatedTokens = Math.max(\r\n 1,\r\n Math.floor((content || '').length / 4),\r\n );\r\n usage = {\r\n prompt_tokens: estimatedTokens,\r\n completion_tokens: estimatedTokens,\r\n total_tokens: estimatedTokens * 2,\r\n };\r\n }\r\n\r\n return {\r\n content: content || '',\r\n usage: usage\r\n ? {\r\n prompt_tokens: usage.prompt_tokens ?? 0,\r\n completion_tokens: usage.completion_tokens ?? 0,\r\n total_tokens: usage.total_tokens ?? 0,\r\n time_cost: timeCost ?? 0,\r\n model_name: modelName,\r\n model_description: modelDescription,\r\n intent: modelConfig.intent,\r\n }\r\n : undefined,\r\n isStreamed: !!isStreaming,\r\n };\r\n } catch (e: any) {\r\n console.error(' call AI error', e);\r\n const newError = new Error(\r\n `failed to call ${isStreaming ? 'streaming ' : ''}AI model service: ${e.message}. Trouble shooting: https://sqai.tech/model-provider.html`,\r\n {\r\n cause: e,\r\n },\r\n );\r\n throw newError;\r\n }\r\n}\r\n\r\nexport const getResponseFormat = (\r\n modelName: string,\r\n AIActionTypeValue: AIActionType,\r\n):\r\n | OpenAI.ChatCompletionCreateParams['response_format']\r\n | OpenAI.ResponseFormatJSONObject => {\r\n let responseFormat:\r\n | OpenAI.ChatCompletionCreateParams['response_format']\r\n | OpenAI.ResponseFormatJSONObject\r\n | undefined;\r\n\r\n if (modelName.includes('gpt-4')) {\r\n switch (AIActionTypeValue) {\r\n case AIActionType.ASSERT:\r\n responseFormat = assertSchema;\r\n break;\r\n case AIActionType.INSPECT_ELEMENT:\r\n responseFormat = locatorSchema;\r\n break;\r\n case AIActionType.PLAN:\r\n responseFormat = planSchema;\r\n break;\r\n case AIActionType.EXTRACT_DATA:\r\n case AIActionType.DESCRIBE_ELEMENT:\r\n responseFormat = { type: AIResponseFormat.JSON };\r\n break;\r\n case AIActionType.TEXT:\r\n // No response format for plain text - return as-is\r\n responseFormat = undefined;\r\n break;\r\n }\r\n }\r\n\r\n // gpt-4o-2024-05-13 only supports json_object response format\r\n // Skip for plain text to allow string output\r\n if (\r\n modelName === 'gpt-4o-2024-05-13' &&\r\n AIActionTypeValue !== AIActionType.TEXT\r\n ) {\r\n responseFormat = { type: AIResponseFormat.JSON };\r\n }\r\n\r\n return responseFormat;\r\n};\r\n\r\nexport async function callAIWithObjectResponse<T>(\r\n messages: ChatCompletionMessageParam[],\r\n AIActionTypeValue: AIActionType,\r\n modelConfig: IModelConfig,\r\n): Promise<{ content: T; usage?: AIUsageInfo }> {\r\n const response = await callAI(messages, AIActionTypeValue, modelConfig);\r\n assert(response, 'empty response');\r\n const vlMode = modelConfig.vlMode;\r\n const jsonContent = safeParseJson(response.content, vlMode);\r\n return { content: jsonContent, usage: response.usage };\r\n}\r\n\r\nexport async function callAIWithStringResponse(\r\n msgs: AIArgs,\r\n AIActionTypeValue: AIActionType,\r\n modelConfig: IModelConfig,\r\n): Promise<{ content: string; usage?: AIUsageInfo }> {\r\n const { content, usage } = await callAI(msgs, AIActionTypeValue, modelConfig);\r\n return { content, usage };\r\n}\r\n\r\nexport function extractJSONFromCodeBlock(response: string) {\r\n try {\r\n // First, try to match a JSON object directly in the response\r\n const jsonMatch = response.match(/^\\s*(\\{[\\s\\S]*\\})\\s*$/);\r\n if (jsonMatch) {\r\n return jsonMatch[1];\r\n }\r\n\r\n // If no direct JSON object is found, try to extract JSON from a code block\r\n const codeBlockMatch = response.match(\r\n /```(?:json)?\\s*(\\{[\\s\\S]*?\\})\\s*```/,\r\n );\r\n if (codeBlockMatch) {\r\n return codeBlockMatch[1];\r\n }\r\n\r\n // If no code block is found, try to find a JSON-like structure in the text\r\n const jsonLikeMatch = response.match(/\\{[\\s\\S]*\\}/);\r\n if (jsonLikeMatch) {\r\n return jsonLikeMatch[0];\r\n }\r\n } catch {}\r\n // If no JSON-like structure is found, return the original response\r\n return response;\r\n}\r\n\r\nexport function preprocessDoubaoBboxJson(input: string) {\r\n if (input.includes('bbox')) {\r\n // when its values like 940 445 969 490, replace all /\\d+\\s+\\d+/g with /$1,$2/g\r\n while (/\\d+\\s+\\d+/.test(input)) {\r\n input = input.replace(/(\\d+)\\s+(\\d+)/g, '$1,$2');\r\n }\r\n }\r\n return input;\r\n}\r\n\r\nexport function safeParseJson(input: string, vlMode: TVlModeTypes | undefined) {\r\n const cleanJsonString = extractJSONFromCodeBlock(input);\r\n // match the point\r\n if (cleanJsonString?.match(/\\((\\d+),(\\d+)\\)/)) {\r\n return cleanJsonString\r\n .match(/\\((\\d+),(\\d+)\\)/)\r\n ?.slice(1)\r\n .map(Number);\r\n }\r\n try {\r\n return JSON.parse(cleanJsonString);\r\n } catch {}\r\n try {\r\n return JSON.parse(jsonrepair(cleanJsonString));\r\n } catch (e) {}\r\n\r\n if (vlMode === 'doubao-vision' || vlMode === 'vlm-ui-tars') {\r\n const jsonString = preprocessDoubaoBboxJson(cleanJsonString);\r\n return JSON.parse(jsonrepair(jsonString));\r\n }\r\n throw Error(`failed to parse json response: ${input}`);\r\n}\r\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","createChatClient","AIActionTypeValue","modelConfig","socksProxy","httpProxy","modelName","openaiBaseURL","openaiApiKey","openaiExtraConfig","openaiUseAzureDeprecated","useAzureOpenai","azureOpenaiScope","azureOpenaiKey","azureOpenaiEndpoint","azureOpenaiApiVersion","azureOpenaiDeployment","azureExtraConfig","useAnthropicSdk","anthropicApiKey","modelDescription","uiTarsVersion","vlMode","openai","proxyAgent","debugProxy","getDebug","HttpsProxyAgent","SocksProxyAgent","AzureOpenAI","tokenProvider","assert","ifInBrowser","credential","DefaultAzureCredential","getBearerTokenProvider","OpenAI","SQAI_API_TYPE","globalConfigManager","SQAI_LANGSMITH_DEBUG","Error","console","wrapOpenAI","Anthropic","callAI","messages","options","completion","style","responseFormat","getResponseFormat","maxTokens","OPENAI_MAX_TOKENS","debugCall","debugProfileStats","debugProfileDetail","startTime","Date","isStreaming","content","accumulated","usage","timeCost","commonConfig","Number","stream","chunk","_chunk_choices__delta","_chunk_choices__delta1","_chunk_choices_2","reasoning_content","chunkData","undefined","estimatedTokens","Math","finalChunk","_result_usage","_result_usage1","_result_usage2","result","JSON","convertImageContent","imgBase64","mimeType","body","parseBase64","m","Array","_chunk_delta","anthropicUsage","e","newError","AIActionType","assertSchema","locatorSchema","planSchema","AIResponseFormat","callAIWithObjectResponse","response","jsonContent","safeParseJson","callAIWithStringResponse","msgs","extractJSONFromCodeBlock","jsonMatch","codeBlockMatch","jsonLikeMatch","preprocessDoubaoBboxJson","input","cleanJsonString","_cleanJsonString_match","jsonrepair","jsonString"],"mappings":"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"}
|
|
@@ -60,7 +60,7 @@ class Insight {
|
|
|
60
60
|
if (query.deepThink || globalDeepThinkSwitch) searchAreaPrompt = query.prompt;
|
|
61
61
|
const { vlMode } = modelConfig;
|
|
62
62
|
if (searchAreaPrompt && !vlMode) {
|
|
63
|
-
console.warn('The "deepThink" feature is not supported with multimodal LLM. Please config VL model for
|
|
63
|
+
console.warn('The "deepThink" feature is not supported with multimodal LLM. Please config VL model for SQAI. https://sqai.tech/choose-a-model');
|
|
64
64
|
searchAreaPrompt = void 0;
|
|
65
65
|
}
|
|
66
66
|
const context = (null == opt ? void 0 : opt.context) || await this.contextRetrieverFn('locate');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insight\\index.js","sources":["webpack://@sqaitech/core/webpack/runtime/define_property_getters","webpack://@sqaitech/core/webpack/runtime/has_own_property","webpack://@sqaitech/core/webpack/runtime/make_namespace_object","webpack://@sqaitech/core/./src/insight/index.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { AIActionType, type AIArgs, expandSearchArea } from '@/ai-model/common';\r\nimport {\r\n AiExtractElementInfo,\r\n AiLocateElement,\r\n callAIWithObjectResponse,\r\n} from '@/ai-model/index';\r\nimport { AiLocateSection } from '@/ai-model/inspect';\r\nimport { elementDescriberInstruction } from '@/ai-model/prompt/describe';\r\nimport type {\r\n AIDescribeElementResponse,\r\n AIUsageInfo,\r\n BaseElement,\r\n DetailedLocateParam,\r\n DumpSubscriber,\r\n InsightAction,\r\n InsightExtractOption,\r\n InsightExtractParam,\r\n InsightTaskInfo,\r\n LocateResult,\r\n PartialInsightDumpFromSDK,\r\n Rect,\r\n UIContext,\r\n} from '@/types';\r\nimport {\r\n type IModelConfig,\r\n SQAI_FORCE_DEEP_THINK,\r\n globalConfigManager,\r\n} from '@sqaitech/shared/env';\r\nimport { compositeElementInfoImg, cropByRect } from '@sqaitech/shared/img';\r\nimport { getDebug } from '@sqaitech/shared/logger';\r\nimport { assert } from '@sqaitech/shared/utils';\r\nimport type { TMultimodalPrompt } from '../ai-model/common';\r\nimport { emitInsightDump } from './utils';\r\n\r\nexport interface LocateOpts {\r\n context?: UIContext<BaseElement>;\r\n}\r\n\r\nexport type AnyValue<T> = {\r\n [K in keyof T]: unknown extends T[K] ? any : T[K];\r\n};\r\n\r\ninterface InsightOptions {\r\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\r\n aiVendorFn?: typeof callAIWithObjectResponse;\r\n}\r\n\r\nconst debug = getDebug('ai:insight');\r\nexport default class Insight<\r\n ElementType extends BaseElement = BaseElement,\r\n ContextType extends UIContext<ElementType> = UIContext<ElementType>,\r\n> {\r\n contextRetrieverFn: (\r\n action: InsightAction,\r\n ) => Promise<ContextType> | ContextType;\r\n\r\n aiVendorFn: Exclude<InsightOptions['aiVendorFn'], undefined> =\r\n callAIWithObjectResponse;\r\n\r\n onceDumpUpdatedFn?: DumpSubscriber;\r\n\r\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\r\n\r\n constructor(\r\n context:\r\n | ContextType\r\n | ((action: InsightAction) => Promise<ContextType> | ContextType),\r\n opt?: InsightOptions,\r\n ) {\r\n assert(context, 'context is required for Insight');\r\n if (typeof context === 'function') {\r\n this.contextRetrieverFn = context;\r\n } else {\r\n this.contextRetrieverFn = () => Promise.resolve(context);\r\n }\r\n\r\n // just for unit test, aiVendorFn is callAIWithObjectResponse by default\r\n if (typeof opt?.aiVendorFn !== 'undefined') {\r\n this.aiVendorFn = opt.aiVendorFn;\r\n }\r\n if (typeof opt?.taskInfo !== 'undefined') {\r\n this.taskInfo = opt.taskInfo;\r\n }\r\n }\r\n\r\n async locate(\r\n query: DetailedLocateParam,\r\n opt: LocateOpts,\r\n modelConfig: IModelConfig,\r\n ): Promise<LocateResult> {\r\n const queryPrompt = typeof query === 'string' ? query : query.prompt;\r\n assert(queryPrompt, 'query is required for locate');\r\n const dumpSubscriber = this.onceDumpUpdatedFn;\r\n this.onceDumpUpdatedFn = undefined;\r\n\r\n assert(typeof query === 'object', 'query should be an object for locate');\r\n\r\n const globalDeepThinkSwitch = globalConfigManager.getEnvConfigInBoolean(\r\n SQAI_FORCE_DEEP_THINK,\r\n );\r\n if (globalDeepThinkSwitch) {\r\n debug('globalDeepThinkSwitch', globalDeepThinkSwitch);\r\n }\r\n let searchAreaPrompt;\r\n if (query.deepThink || globalDeepThinkSwitch) {\r\n searchAreaPrompt = query.prompt;\r\n }\r\n\r\n const { vlMode } = modelConfig;\r\n\r\n if (searchAreaPrompt && !vlMode) {\r\n console.warn(\r\n 'The \"deepThink\" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/choose-a-model',\r\n );\r\n searchAreaPrompt = undefined;\r\n }\r\n\r\n const context = opt?.context || (await this.contextRetrieverFn('locate'));\r\n\r\n let searchArea: Rect | undefined = undefined;\r\n let searchAreaRawResponse: string | undefined = undefined;\r\n let searchAreaUsage: AIUsageInfo | undefined = undefined;\r\n let searchAreaResponse:\r\n | Awaited<ReturnType<typeof AiLocateSection>>\r\n | undefined = undefined;\r\n if (searchAreaPrompt) {\r\n searchAreaResponse = await AiLocateSection({\r\n context,\r\n sectionDescription: searchAreaPrompt,\r\n modelConfig,\r\n });\r\n assert(\r\n searchAreaResponse.rect,\r\n `cannot find search area for \"${searchAreaPrompt}\"${\r\n searchAreaResponse.error ? `: ${searchAreaResponse.error}` : ''\r\n }`,\r\n );\r\n searchAreaRawResponse = searchAreaResponse.rawResponse;\r\n searchAreaUsage = searchAreaResponse.usage;\r\n searchArea = searchAreaResponse.rect;\r\n }\r\n\r\n const startTime = Date.now();\r\n const {\r\n parseResult,\r\n rect,\r\n elementById,\r\n rawResponse,\r\n usage,\r\n isOrderSensitive,\r\n } = await AiLocateElement({\r\n callAIFn: this.aiVendorFn,\r\n context,\r\n targetElementDescription: queryPrompt,\r\n searchConfig: searchAreaResponse,\r\n modelConfig,\r\n });\r\n\r\n const timeCost = Date.now() - startTime;\r\n const taskInfo: InsightTaskInfo = {\r\n ...(this.taskInfo ? this.taskInfo : {}),\r\n durationMs: timeCost,\r\n rawResponse: JSON.stringify(rawResponse),\r\n formatResponse: JSON.stringify(parseResult),\r\n usage,\r\n searchArea,\r\n searchAreaRawResponse,\r\n searchAreaUsage,\r\n };\r\n\r\n let errorLog: string | undefined;\r\n if (parseResult.errors?.length) {\r\n errorLog = `AI model failed to locate: \\n${parseResult.errors.join('\\n')}`;\r\n }\r\n\r\n const dumpData: PartialInsightDumpFromSDK = {\r\n type: 'locate',\r\n userQuery: {\r\n element: queryPrompt,\r\n },\r\n matchedElement: [],\r\n matchedRect: rect,\r\n data: null,\r\n taskInfo,\r\n deepThink: !!searchArea,\r\n error: errorLog,\r\n };\r\n\r\n const elements: BaseElement[] = [];\r\n (parseResult.elements || []).forEach((item) => {\r\n if ('id' in item) {\r\n const element = elementById(item?.id);\r\n\r\n if (!element) {\r\n console.warn(\r\n `locate: cannot find element id=${item.id}. Maybe an unstable response from AI model`,\r\n );\r\n return;\r\n }\r\n elements.push(element);\r\n }\r\n });\r\n\r\n emitInsightDump(\r\n {\r\n ...dumpData,\r\n matchedElement: elements,\r\n },\r\n dumpSubscriber,\r\n );\r\n\r\n if (errorLog) {\r\n throw new Error(errorLog);\r\n }\r\n\r\n assert(\r\n elements.length <= 1,\r\n `locate: multiple elements found, length = ${elements.length}`,\r\n );\r\n\r\n if (elements.length === 1) {\r\n return {\r\n element: {\r\n id: elements[0]!.id,\r\n indexId: elements[0]!.indexId,\r\n center: elements[0]!.center,\r\n rect: elements[0]!.rect,\r\n xpaths: elements[0]!.xpaths || [],\r\n attributes: elements[0]!.attributes,\r\n isOrderSensitive,\r\n },\r\n rect,\r\n };\r\n }\r\n return {\r\n element: null,\r\n rect,\r\n };\r\n }\r\n\r\n async extract<T>(\r\n dataDemand: InsightExtractParam,\r\n modelConfig: IModelConfig,\r\n opt?: InsightExtractOption,\r\n multimodalPrompt?: TMultimodalPrompt,\r\n ): Promise<{\r\n data: T;\r\n thought?: string;\r\n usage?: AIUsageInfo;\r\n }> {\r\n assert(\r\n typeof dataDemand === 'object' || typeof dataDemand === 'string',\r\n `dataDemand should be object or string, but get ${typeof dataDemand}`,\r\n );\r\n const dumpSubscriber = this.onceDumpUpdatedFn;\r\n this.onceDumpUpdatedFn = undefined;\r\n\r\n const context = await this.contextRetrieverFn('extract');\r\n\r\n const startTime = Date.now();\r\n\r\n const { parseResult, usage } = await AiExtractElementInfo<T>({\r\n context,\r\n dataQuery: dataDemand,\r\n multimodalPrompt,\r\n extractOption: opt,\r\n modelConfig,\r\n });\r\n\r\n const timeCost = Date.now() - startTime;\r\n const taskInfo: InsightTaskInfo = {\r\n ...(this.taskInfo ? this.taskInfo : {}),\r\n durationMs: timeCost,\r\n rawResponse: JSON.stringify(parseResult),\r\n };\r\n\r\n let errorLog: string | undefined;\r\n if (parseResult.errors?.length) {\r\n errorLog = `AI response error: \\n${parseResult.errors.join('\\n')}`;\r\n }\r\n\r\n const dumpData: PartialInsightDumpFromSDK = {\r\n type: 'extract',\r\n userQuery: {\r\n dataDemand,\r\n },\r\n matchedElement: [],\r\n data: null,\r\n taskInfo,\r\n error: errorLog,\r\n };\r\n\r\n const { data, thought } = parseResult || {};\r\n\r\n // 4\r\n emitInsightDump(\r\n {\r\n ...dumpData,\r\n data,\r\n },\r\n dumpSubscriber,\r\n );\r\n\r\n if (errorLog && !data && !opt?.doNotThrowError) {\r\n throw new Error(errorLog);\r\n }\r\n\r\n return {\r\n data,\r\n thought,\r\n usage,\r\n };\r\n }\r\n\r\n async describe(\r\n target: Rect | [number, number],\r\n modelConfig: IModelConfig,\r\n opt?: {\r\n deepThink?: boolean;\r\n },\r\n ): Promise<Pick<AIDescribeElementResponse, 'description'>> {\r\n assert(target, 'target is required for insight.describe');\r\n const context = await this.contextRetrieverFn('describe');\r\n const { screenshotBase64, size } = context;\r\n assert(screenshotBase64, 'screenshot is required for insight.describe');\r\n // The result of the \"describe\" function will be used for positioning, so essentially it is a form of grounding.\r\n const { vlMode } = modelConfig;\r\n const systemPrompt = elementDescriberInstruction();\r\n\r\n // Convert [x,y] center point to Rect if needed\r\n const defaultRectSize = 30;\r\n const targetRect: Rect = Array.isArray(target)\r\n ? {\r\n left: Math.floor(target[0] - defaultRectSize / 2),\r\n top: Math.floor(target[1] - defaultRectSize / 2),\r\n width: defaultRectSize,\r\n height: defaultRectSize,\r\n }\r\n : target;\r\n\r\n let imagePayload = await compositeElementInfoImg({\r\n inputImgBase64: screenshotBase64,\r\n size,\r\n elementsPositionInfo: [\r\n {\r\n rect: targetRect,\r\n },\r\n ],\r\n borderThickness: 3,\r\n });\r\n\r\n if (opt?.deepThink) {\r\n const searchArea = expandSearchArea(targetRect, context.size, vlMode);\r\n debug('describe: set searchArea', searchArea);\r\n const croppedResult = await cropByRect(\r\n imagePayload,\r\n searchArea,\r\n vlMode === 'qwen-vl',\r\n );\r\n imagePayload = croppedResult.imageBase64;\r\n }\r\n\r\n const msgs: AIArgs = [\r\n { role: 'system', content: systemPrompt },\r\n {\r\n role: 'user',\r\n content: [\r\n {\r\n type: 'image_url',\r\n image_url: {\r\n url: imagePayload,\r\n detail: 'high',\r\n },\r\n },\r\n ],\r\n },\r\n ];\r\n\r\n const callAIFn = this\r\n .aiVendorFn as typeof callAIWithObjectResponse<AIDescribeElementResponse>;\r\n\r\n const res = await callAIFn(\r\n msgs,\r\n AIActionType.DESCRIBE_ELEMENT,\r\n modelConfig,\r\n );\r\n\r\n const { content } = res;\r\n assert(!content.error, `describe failed: ${content.error}`);\r\n assert(content.description, 'failed to describe the element');\r\n return content;\r\n }\r\n}\r\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","debug","getDebug","Insight","query","opt","modelConfig","_parseResult_errors","queryPrompt","assert","dumpSubscriber","undefined","globalDeepThinkSwitch","globalConfigManager","SQAI_FORCE_DEEP_THINK","searchAreaPrompt","vlMode","console","context","searchArea","searchAreaRawResponse","searchAreaUsage","searchAreaResponse","AiLocateSection","startTime","Date","parseResult","rect","elementById","rawResponse","usage","isOrderSensitive","AiLocateElement","timeCost","taskInfo","JSON","errorLog","dumpData","elements","item","element","emitInsightDump","Error","dataDemand","multimodalPrompt","AiExtractElementInfo","data","thought","target","screenshotBase64","size","systemPrompt","elementDescriberInstruction","defaultRectSize","targetRect","Array","Math","imagePayload","compositeElementInfoImg","expandSearchArea","croppedResult","cropByRect","msgs","callAIFn","res","AIActionType","content","callAIWithObjectResponse","Promise"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;;;;;;;;;;;;;;;ACyCA,MAAMI,QAAQC,AAAAA,IAAAA,uBAAAA,QAAAA,AAAAA,EAAS;AACR,MAAMC;IAqCnB,MAAM,OACJC,KAA0B,EAC1BC,GAAe,EACfC,WAAyB,EACF;YAkFnBC;QAjFJ,MAAMC,cAAc,AAAiB,YAAjB,OAAOJ,QAAqBA,QAAQA,MAAM,MAAM;QACpEK,IAAAA,sBAAAA,MAAAA,AAAAA,EAAOD,aAAa;QACpB,MAAME,iBAAiB,IAAI,CAAC,iBAAiB;QAC7C,IAAI,CAAC,iBAAiB,GAAGC;QAEzBF,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,AAAiB,YAAjB,OAAOL,OAAoB;QAElC,MAAMQ,wBAAwBC,oBAAAA,mBAAAA,CAAAA,qBAAyC,CACrEC,oBAAAA,qBAAqBA;QAEvB,IAAIF,uBACFX,MAAM,yBAAyBW;QAEjC,IAAIG;QACJ,IAAIX,MAAM,SAAS,IAAIQ,uBACrBG,mBAAmBX,MAAM,MAAM;QAGjC,MAAM,EAAEY,MAAM,EAAE,GAAGV;QAEnB,IAAIS,oBAAoB,CAACC,QAAQ;YAC/BC,QAAQ,IAAI,CACV;YAEFF,mBAAmBJ;QACrB;QAEA,MAAMO,UAAUb,AAAAA,CAAAA,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,OAAO,AAAD,KAAM,MAAM,IAAI,CAAC,kBAAkB,CAAC;QAE/D,IAAIc;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QAGJ,IAAIP,kBAAkB;YACpBO,qBAAqB,MAAMC,AAAAA,IAAAA,2BAAAA,eAAAA,AAAAA,EAAgB;gBACzCL;gBACA,oBAAoBH;gBACpBT;YACF;YACAG,IAAAA,sBAAAA,MAAAA,AAAAA,EACEa,mBAAmB,IAAI,EACvB,CAAC,6BAA6B,EAAEP,iBAAiB,CAAC,EAChDO,mBAAmB,KAAK,GAAG,CAAC,EAAE,EAAEA,mBAAmB,KAAK,EAAE,GAAG,IAC7D;YAEJF,wBAAwBE,mBAAmB,WAAW;YACtDD,kBAAkBC,mBAAmB,KAAK;YAC1CH,aAAaG,mBAAmB,IAAI;QACtC;QAEA,MAAME,YAAYC,KAAK,GAAG;QAC1B,MAAM,EACJC,WAAW,EACXC,IAAI,EACJC,WAAW,EACXC,WAAW,EACXC,KAAK,EACLC,gBAAgB,EACjB,GAAG,MAAMC,AAAAA,IAAAA,yBAAAA,eAAAA,AAAAA,EAAgB;YACxB,UAAU,IAAI,CAAC,UAAU;YACzBd;YACA,0BAA0BV;YAC1B,cAAcc;YACdhB;QACF;QAEA,MAAM2B,WAAWR,KAAK,GAAG,KAAKD;QAC9B,MAAMU,WAA4B;YAChC,GAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YACtC,YAAYD;YACZ,aAAaE,KAAK,SAAS,CAACN;YAC5B,gBAAgBM,KAAK,SAAS,CAACT;YAC/BI;YACAX;YACAC;YACAC;QACF;QAEA,IAAIe;QACJ,IAAI,QAAA7B,CAAAA,sBAAAA,YAAY,MAAM,AAAD,IAAjBA,KAAAA,IAAAA,oBAAoB,MAAM,EAC5B6B,WAAW,CAAC,6BAA6B,EAAEV,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO;QAG5E,MAAMW,WAAsC;YAC1C,MAAM;YACN,WAAW;gBACT,SAAS7B;YACX;YACA,gBAAgB,EAAE;YAClB,aAAamB;YACb,MAAM;YACNO;YACA,WAAW,CAAC,CAACf;YACb,OAAOiB;QACT;QAEA,MAAME,WAA0B,EAAE;QACjCZ,CAAAA,YAAY,QAAQ,IAAI,EAAC,EAAG,OAAO,CAAC,CAACa;YACpC,IAAI,QAAQA,MAAM;gBAChB,MAAMC,UAAUZ,YAAYW,QAAAA,OAAAA,KAAAA,IAAAA,KAAM,EAAE;gBAEpC,IAAI,CAACC,SAAS,YACZvB,QAAQ,IAAI,CACV,CAAC,+BAA+B,EAAEsB,KAAK,EAAE,CAAC,0CAA0C,CAAC;gBAIzFD,SAAS,IAAI,CAACE;YAChB;QACF;QAEAC,IAAAA,kCAAAA,eAAAA,AAAAA,EACE;YACE,GAAGJ,QAAQ;YACX,gBAAgBC;QAClB,GACA5B;QAGF,IAAI0B,UACF,MAAM,IAAIM,MAAMN;QAGlB3B,IAAAA,sBAAAA,MAAAA,AAAAA,EACE6B,SAAS,MAAM,IAAI,GACnB,CAAC,0CAA0C,EAAEA,SAAS,MAAM,EAAE;QAGhE,IAAIA,AAAoB,MAApBA,SAAS,MAAM,EACjB,OAAO;YACL,SAAS;gBACP,IAAIA,QAAQ,CAAC,EAAE,CAAE,EAAE;gBACnB,SAASA,QAAQ,CAAC,EAAE,CAAE,OAAO;gBAC7B,QAAQA,QAAQ,CAAC,EAAE,CAAE,MAAM;gBAC3B,MAAMA,QAAQ,CAAC,EAAE,CAAE,IAAI;gBACvB,QAAQA,QAAQ,CAAC,EAAE,CAAE,MAAM,IAAI,EAAE;gBACjC,YAAYA,QAAQ,CAAC,EAAE,CAAE,UAAU;gBACnCP;YACF;YACAJ;QACF;QAEF,OAAO;YACL,SAAS;YACTA;QACF;IACF;IAEA,MAAM,QACJgB,UAA+B,EAC/BrC,WAAyB,EACzBD,GAA0B,EAC1BuC,gBAAoC,EAKnC;YA4BGrC;QA3BJE,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,AAAsB,YAAtB,OAAOkC,cAA2B,AAAsB,YAAtB,OAAOA,YACzC,CAAC,+CAA+C,EAAE,OAAOA,YAAY;QAEvE,MAAMjC,iBAAiB,IAAI,CAAC,iBAAiB;QAC7C,IAAI,CAAC,iBAAiB,GAAGC;QAEzB,MAAMO,UAAU,MAAM,IAAI,CAAC,kBAAkB,CAAC;QAE9C,MAAMM,YAAYC,KAAK,GAAG;QAE1B,MAAM,EAAEC,WAAW,EAAEI,KAAK,EAAE,GAAG,MAAMe,AAAAA,IAAAA,yBAAAA,oBAAAA,AAAAA,EAAwB;YAC3D3B;YACA,WAAWyB;YACXC;YACA,eAAevC;YACfC;QACF;QAEA,MAAM2B,WAAWR,KAAK,GAAG,KAAKD;QAC9B,MAAMU,WAA4B;YAChC,GAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YACtC,YAAYD;YACZ,aAAaE,KAAK,SAAS,CAACT;QAC9B;QAEA,IAAIU;QACJ,IAAI,QAAA7B,CAAAA,sBAAAA,YAAY,MAAM,AAAD,IAAjBA,KAAAA,IAAAA,oBAAoB,MAAM,EAC5B6B,WAAW,CAAC,qBAAqB,EAAEV,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO;QAGpE,MAAMW,WAAsC;YAC1C,MAAM;YACN,WAAW;gBACTM;YACF;YACA,gBAAgB,EAAE;YAClB,MAAM;YACNT;YACA,OAAOE;QACT;QAEA,MAAM,EAAEU,IAAI,EAAEC,OAAO,EAAE,GAAGrB,eAAe,CAAC;QAG1Ce,IAAAA,kCAAAA,eAAAA,AAAAA,EACE;YACE,GAAGJ,QAAQ;YACXS;QACF,GACApC;QAGF,IAAI0B,YAAY,CAACU,QAAQ,CAACzC,CAAAA,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,eAAe,AAAD,GAC3C,MAAM,IAAIqC,MAAMN;QAGlB,OAAO;YACLU;YACAC;YACAjB;QACF;IACF;IAEA,MAAM,SACJkB,MAA+B,EAC/B1C,WAAyB,EACzBD,GAEC,EACwD;QACzDI,IAAAA,sBAAAA,MAAAA,AAAAA,EAAOuC,QAAQ;QACf,MAAM9B,UAAU,MAAM,IAAI,CAAC,kBAAkB,CAAC;QAC9C,MAAM,EAAE+B,gBAAgB,EAAEC,IAAI,EAAE,GAAGhC;QACnCT,IAAAA,sBAAAA,MAAAA,AAAAA,EAAOwC,kBAAkB;QAEzB,MAAM,EAAEjC,MAAM,EAAE,GAAGV;QACnB,MAAM6C,eAAeC,AAAAA,IAAAA,4BAAAA,2BAAAA,AAAAA;QAGrB,MAAMC,kBAAkB;QACxB,MAAMC,aAAmBC,MAAM,OAAO,CAACP,UACnC;YACE,MAAMQ,KAAK,KAAK,CAACR,MAAM,CAAC,EAAE,GAAGK,kBAAkB;YAC/C,KAAKG,KAAK,KAAK,CAACR,MAAM,CAAC,EAAE,GAAGK,kBAAkB;YAC9C,OAAOA;YACP,QAAQA;QACV,IACAL;QAEJ,IAAIS,eAAe,MAAMC,AAAAA,IAAAA,oBAAAA,uBAAAA,AAAAA,EAAwB;YAC/C,gBAAgBT;YAChBC;YACA,sBAAsB;gBACpB;oBACE,MAAMI;gBACR;aACD;YACD,iBAAiB;QACnB;QAEA,IAAIjD,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,SAAS,EAAE;YAClB,MAAMc,aAAawC,AAAAA,IAAAA,0BAAAA,gBAAAA,AAAAA,EAAiBL,YAAYpC,QAAQ,IAAI,EAAEF;YAC9Df,MAAM,4BAA4BkB;YAClC,MAAMyC,gBAAgB,MAAMC,AAAAA,IAAAA,oBAAAA,UAAAA,AAAAA,EAC1BJ,cACAtC,YACAH,AAAW,cAAXA;YAEFyC,eAAeG,cAAc,WAAW;QAC1C;QAEA,MAAME,OAAe;YACnB;gBAAE,MAAM;gBAAU,SAASX;YAAa;YACxC;gBACE,MAAM;gBACN,SAAS;oBACP;wBACE,MAAM;wBACN,WAAW;4BACT,KAAKM;4BACL,QAAQ;wBACV;oBACF;iBACD;YACH;SACD;QAED,MAAMM,WAAW,IAAI,CAClB,UAAU;QAEb,MAAMC,MAAM,MAAMD,SAChBD,MACAG,0BAAAA,YAAAA,CAAAA,gBAA6B,EAC7B3D;QAGF,MAAM,EAAE4D,OAAO,EAAE,GAAGF;QACpBvD,IAAAA,sBAAAA,MAAAA,AAAAA,EAAO,CAACyD,QAAQ,KAAK,EAAE,CAAC,iBAAiB,EAAEA,QAAQ,KAAK,EAAE;QAC1DzD,IAAAA,sBAAAA,MAAAA,AAAAA,EAAOyD,QAAQ,WAAW,EAAE;QAC5B,OAAOA;IACT;IAxUA,YACEhD,OAEmE,EACnEb,GAAoB,CACpB;QAhBF;QAIA,qCACE8D,yBAAAA,wBAAwBA;QAE1B;QAEA;QAQE1D,IAAAA,sBAAAA,MAAAA,AAAAA,EAAOS,SAAS;QAChB,IAAI,AAAmB,cAAnB,OAAOA,SACT,IAAI,CAAC,kBAAkB,GAAGA;aAE1B,IAAI,CAAC,kBAAkB,GAAG,IAAMkD,QAAQ,OAAO,CAAClD;QAIlD,IAAI,AAA2B,WAApBb,CAAAA,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,UAAU,AAAD,GACvB,IAAI,CAAC,UAAU,GAAGA,IAAI,UAAU;QAElC,IAAI,AAAyB,WAAlBA,CAAAA,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,QAAQ,AAAD,GACrB,IAAI,CAAC,QAAQ,GAAGA,IAAI,QAAQ;IAEhC;AAqTF"}
|
|
1
|
+
{"version":3,"file":"insight\\index.js","sources":["webpack://@sqaitech/core/webpack/runtime/define_property_getters","webpack://@sqaitech/core/webpack/runtime/has_own_property","webpack://@sqaitech/core/webpack/runtime/make_namespace_object","webpack://@sqaitech/core/./src/insight/index.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { AIActionType, type AIArgs, expandSearchArea } from '@/ai-model/common';\r\nimport {\r\n AiExtractElementInfo,\r\n AiLocateElement,\r\n callAIWithObjectResponse,\r\n} from '@/ai-model/index';\r\nimport { AiLocateSection } from '@/ai-model/inspect';\r\nimport { elementDescriberInstruction } from '@/ai-model/prompt/describe';\r\nimport type {\r\n AIDescribeElementResponse,\r\n AIUsageInfo,\r\n BaseElement,\r\n DetailedLocateParam,\r\n DumpSubscriber,\r\n InsightAction,\r\n InsightExtractOption,\r\n InsightExtractParam,\r\n InsightTaskInfo,\r\n LocateResult,\r\n PartialInsightDumpFromSDK,\r\n Rect,\r\n UIContext,\r\n} from '@/types';\r\nimport {\r\n type IModelConfig,\r\n SQAI_FORCE_DEEP_THINK,\r\n globalConfigManager,\r\n} from '@sqaitech/shared/env';\r\nimport { compositeElementInfoImg, cropByRect } from '@sqaitech/shared/img';\r\nimport { getDebug } from '@sqaitech/shared/logger';\r\nimport { assert } from '@sqaitech/shared/utils';\r\nimport type { TMultimodalPrompt } from '../ai-model/common';\r\nimport { emitInsightDump } from './utils';\r\n\r\nexport interface LocateOpts {\r\n context?: UIContext<BaseElement>;\r\n}\r\n\r\nexport type AnyValue<T> = {\r\n [K in keyof T]: unknown extends T[K] ? any : T[K];\r\n};\r\n\r\ninterface InsightOptions {\r\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\r\n aiVendorFn?: typeof callAIWithObjectResponse;\r\n}\r\n\r\nconst debug = getDebug('ai:insight');\r\nexport default class Insight<\r\n ElementType extends BaseElement = BaseElement,\r\n ContextType extends UIContext<ElementType> = UIContext<ElementType>,\r\n> {\r\n contextRetrieverFn: (\r\n action: InsightAction,\r\n ) => Promise<ContextType> | ContextType;\r\n\r\n aiVendorFn: Exclude<InsightOptions['aiVendorFn'], undefined> =\r\n callAIWithObjectResponse;\r\n\r\n onceDumpUpdatedFn?: DumpSubscriber;\r\n\r\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\r\n\r\n constructor(\r\n context:\r\n | ContextType\r\n | ((action: InsightAction) => Promise<ContextType> | ContextType),\r\n opt?: InsightOptions,\r\n ) {\r\n assert(context, 'context is required for Insight');\r\n if (typeof context === 'function') {\r\n this.contextRetrieverFn = context;\r\n } else {\r\n this.contextRetrieverFn = () => Promise.resolve(context);\r\n }\r\n\r\n // just for unit test, aiVendorFn is callAIWithObjectResponse by default\r\n if (typeof opt?.aiVendorFn !== 'undefined') {\r\n this.aiVendorFn = opt.aiVendorFn;\r\n }\r\n if (typeof opt?.taskInfo !== 'undefined') {\r\n this.taskInfo = opt.taskInfo;\r\n }\r\n }\r\n\r\n async locate(\r\n query: DetailedLocateParam,\r\n opt: LocateOpts,\r\n modelConfig: IModelConfig,\r\n ): Promise<LocateResult> {\r\n const queryPrompt = typeof query === 'string' ? query : query.prompt;\r\n assert(queryPrompt, 'query is required for locate');\r\n const dumpSubscriber = this.onceDumpUpdatedFn;\r\n this.onceDumpUpdatedFn = undefined;\r\n\r\n assert(typeof query === 'object', 'query should be an object for locate');\r\n\r\n const globalDeepThinkSwitch = globalConfigManager.getEnvConfigInBoolean(\r\n SQAI_FORCE_DEEP_THINK,\r\n );\r\n if (globalDeepThinkSwitch) {\r\n debug('globalDeepThinkSwitch', globalDeepThinkSwitch);\r\n }\r\n let searchAreaPrompt;\r\n if (query.deepThink || globalDeepThinkSwitch) {\r\n searchAreaPrompt = query.prompt;\r\n }\r\n\r\n const { vlMode } = modelConfig;\r\n\r\n if (searchAreaPrompt && !vlMode) {\r\n console.warn(\r\n 'The \"deepThink\" feature is not supported with multimodal LLM. Please config VL model for SQAI. https://sqai.tech/choose-a-model',\r\n );\r\n searchAreaPrompt = undefined;\r\n }\r\n\r\n const context = opt?.context || (await this.contextRetrieverFn('locate'));\r\n\r\n let searchArea: Rect | undefined = undefined;\r\n let searchAreaRawResponse: string | undefined = undefined;\r\n let searchAreaUsage: AIUsageInfo | undefined = undefined;\r\n let searchAreaResponse:\r\n | Awaited<ReturnType<typeof AiLocateSection>>\r\n | undefined = undefined;\r\n if (searchAreaPrompt) {\r\n searchAreaResponse = await AiLocateSection({\r\n context,\r\n sectionDescription: searchAreaPrompt,\r\n modelConfig,\r\n });\r\n assert(\r\n searchAreaResponse.rect,\r\n `cannot find search area for \"${searchAreaPrompt}\"${\r\n searchAreaResponse.error ? `: ${searchAreaResponse.error}` : ''\r\n }`,\r\n );\r\n searchAreaRawResponse = searchAreaResponse.rawResponse;\r\n searchAreaUsage = searchAreaResponse.usage;\r\n searchArea = searchAreaResponse.rect;\r\n }\r\n\r\n const startTime = Date.now();\r\n const {\r\n parseResult,\r\n rect,\r\n elementById,\r\n rawResponse,\r\n usage,\r\n isOrderSensitive,\r\n } = await AiLocateElement({\r\n callAIFn: this.aiVendorFn,\r\n context,\r\n targetElementDescription: queryPrompt,\r\n searchConfig: searchAreaResponse,\r\n modelConfig,\r\n });\r\n\r\n const timeCost = Date.now() - startTime;\r\n const taskInfo: InsightTaskInfo = {\r\n ...(this.taskInfo ? this.taskInfo : {}),\r\n durationMs: timeCost,\r\n rawResponse: JSON.stringify(rawResponse),\r\n formatResponse: JSON.stringify(parseResult),\r\n usage,\r\n searchArea,\r\n searchAreaRawResponse,\r\n searchAreaUsage,\r\n };\r\n\r\n let errorLog: string | undefined;\r\n if (parseResult.errors?.length) {\r\n errorLog = `AI model failed to locate: \\n${parseResult.errors.join('\\n')}`;\r\n }\r\n\r\n const dumpData: PartialInsightDumpFromSDK = {\r\n type: 'locate',\r\n userQuery: {\r\n element: queryPrompt,\r\n },\r\n matchedElement: [],\r\n matchedRect: rect,\r\n data: null,\r\n taskInfo,\r\n deepThink: !!searchArea,\r\n error: errorLog,\r\n };\r\n\r\n const elements: BaseElement[] = [];\r\n (parseResult.elements || []).forEach((item) => {\r\n if ('id' in item) {\r\n const element = elementById(item?.id);\r\n\r\n if (!element) {\r\n console.warn(\r\n `locate: cannot find element id=${item.id}. Maybe an unstable response from AI model`,\r\n );\r\n return;\r\n }\r\n elements.push(element);\r\n }\r\n });\r\n\r\n emitInsightDump(\r\n {\r\n ...dumpData,\r\n matchedElement: elements,\r\n },\r\n dumpSubscriber,\r\n );\r\n\r\n if (errorLog) {\r\n throw new Error(errorLog);\r\n }\r\n\r\n assert(\r\n elements.length <= 1,\r\n `locate: multiple elements found, length = ${elements.length}`,\r\n );\r\n\r\n if (elements.length === 1) {\r\n return {\r\n element: {\r\n id: elements[0]!.id,\r\n indexId: elements[0]!.indexId,\r\n center: elements[0]!.center,\r\n rect: elements[0]!.rect,\r\n xpaths: elements[0]!.xpaths || [],\r\n attributes: elements[0]!.attributes,\r\n isOrderSensitive,\r\n },\r\n rect,\r\n };\r\n }\r\n return {\r\n element: null,\r\n rect,\r\n };\r\n }\r\n\r\n async extract<T>(\r\n dataDemand: InsightExtractParam,\r\n modelConfig: IModelConfig,\r\n opt?: InsightExtractOption,\r\n multimodalPrompt?: TMultimodalPrompt,\r\n ): Promise<{\r\n data: T;\r\n thought?: string;\r\n usage?: AIUsageInfo;\r\n }> {\r\n assert(\r\n typeof dataDemand === 'object' || typeof dataDemand === 'string',\r\n `dataDemand should be object or string, but get ${typeof dataDemand}`,\r\n );\r\n const dumpSubscriber = this.onceDumpUpdatedFn;\r\n this.onceDumpUpdatedFn = undefined;\r\n\r\n const context = await this.contextRetrieverFn('extract');\r\n\r\n const startTime = Date.now();\r\n\r\n const { parseResult, usage } = await AiExtractElementInfo<T>({\r\n context,\r\n dataQuery: dataDemand,\r\n multimodalPrompt,\r\n extractOption: opt,\r\n modelConfig,\r\n });\r\n\r\n const timeCost = Date.now() - startTime;\r\n const taskInfo: InsightTaskInfo = {\r\n ...(this.taskInfo ? this.taskInfo : {}),\r\n durationMs: timeCost,\r\n rawResponse: JSON.stringify(parseResult),\r\n };\r\n\r\n let errorLog: string | undefined;\r\n if (parseResult.errors?.length) {\r\n errorLog = `AI response error: \\n${parseResult.errors.join('\\n')}`;\r\n }\r\n\r\n const dumpData: PartialInsightDumpFromSDK = {\r\n type: 'extract',\r\n userQuery: {\r\n dataDemand,\r\n },\r\n matchedElement: [],\r\n data: null,\r\n taskInfo,\r\n error: errorLog,\r\n };\r\n\r\n const { data, thought } = parseResult || {};\r\n\r\n // 4\r\n emitInsightDump(\r\n {\r\n ...dumpData,\r\n data,\r\n },\r\n dumpSubscriber,\r\n );\r\n\r\n if (errorLog && !data && !opt?.doNotThrowError) {\r\n throw new Error(errorLog);\r\n }\r\n\r\n return {\r\n data,\r\n thought,\r\n usage,\r\n };\r\n }\r\n\r\n async describe(\r\n target: Rect | [number, number],\r\n modelConfig: IModelConfig,\r\n opt?: {\r\n deepThink?: boolean;\r\n },\r\n ): Promise<Pick<AIDescribeElementResponse, 'description'>> {\r\n assert(target, 'target is required for insight.describe');\r\n const context = await this.contextRetrieverFn('describe');\r\n const { screenshotBase64, size } = context;\r\n assert(screenshotBase64, 'screenshot is required for insight.describe');\r\n // The result of the \"describe\" function will be used for positioning, so essentially it is a form of grounding.\r\n const { vlMode } = modelConfig;\r\n const systemPrompt = elementDescriberInstruction();\r\n\r\n // Convert [x,y] center point to Rect if needed\r\n const defaultRectSize = 30;\r\n const targetRect: Rect = Array.isArray(target)\r\n ? {\r\n left: Math.floor(target[0] - defaultRectSize / 2),\r\n top: Math.floor(target[1] - defaultRectSize / 2),\r\n width: defaultRectSize,\r\n height: defaultRectSize,\r\n }\r\n : target;\r\n\r\n let imagePayload = await compositeElementInfoImg({\r\n inputImgBase64: screenshotBase64,\r\n size,\r\n elementsPositionInfo: [\r\n {\r\n rect: targetRect,\r\n },\r\n ],\r\n borderThickness: 3,\r\n });\r\n\r\n if (opt?.deepThink) {\r\n const searchArea = expandSearchArea(targetRect, context.size, vlMode);\r\n debug('describe: set searchArea', searchArea);\r\n const croppedResult = await cropByRect(\r\n imagePayload,\r\n searchArea,\r\n vlMode === 'qwen-vl',\r\n );\r\n imagePayload = croppedResult.imageBase64;\r\n }\r\n\r\n const msgs: AIArgs = [\r\n { role: 'system', content: systemPrompt },\r\n {\r\n role: 'user',\r\n content: [\r\n {\r\n type: 'image_url',\r\n image_url: {\r\n url: imagePayload,\r\n detail: 'high',\r\n },\r\n },\r\n ],\r\n },\r\n ];\r\n\r\n const callAIFn = this\r\n .aiVendorFn as typeof callAIWithObjectResponse<AIDescribeElementResponse>;\r\n\r\n const res = await callAIFn(\r\n msgs,\r\n AIActionType.DESCRIBE_ELEMENT,\r\n modelConfig,\r\n );\r\n\r\n const { content } = res;\r\n assert(!content.error, `describe failed: ${content.error}`);\r\n assert(content.description, 'failed to describe the element');\r\n return content;\r\n }\r\n}\r\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","debug","getDebug","Insight","query","opt","modelConfig","_parseResult_errors","queryPrompt","assert","dumpSubscriber","undefined","globalDeepThinkSwitch","globalConfigManager","SQAI_FORCE_DEEP_THINK","searchAreaPrompt","vlMode","console","context","searchArea","searchAreaRawResponse","searchAreaUsage","searchAreaResponse","AiLocateSection","startTime","Date","parseResult","rect","elementById","rawResponse","usage","isOrderSensitive","AiLocateElement","timeCost","taskInfo","JSON","errorLog","dumpData","elements","item","element","emitInsightDump","Error","dataDemand","multimodalPrompt","AiExtractElementInfo","data","thought","target","screenshotBase64","size","systemPrompt","elementDescriberInstruction","defaultRectSize","targetRect","Array","Math","imagePayload","compositeElementInfoImg","expandSearchArea","croppedResult","cropByRect","msgs","callAIFn","res","AIActionType","content","callAIWithObjectResponse","Promise"],"mappings":"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"}
|