@midscene/core 0.27.3-beta-20250825120123.0 → 0.27.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import { Insight } from "../index.mjs";
2
2
  import js_yaml from "js-yaml";
3
3
  import { groupedActionDumpFileExt, reportHTMLContent, stringifyDumpData, writeLogFile } from "../utils.mjs";
4
4
  import { ScriptPlayer, buildDetailedLocateParam, parseYamlScript } from "../yaml/index.mjs";
5
- import { getAIConfigInBoolean, globalConfigManger, vlLocateMode } from "@midscene/shared/env";
5
+ import { MIDSCENE_CACHE, globalConfigManager, vlLocateMode } from "@midscene/shared/env";
6
6
  import { getDebug } from "@midscene/shared/logger";
7
7
  import { assert } from "@midscene/shared/utils";
8
8
  import { TaskCache } from "./task-cache.mjs";
@@ -501,10 +501,11 @@ class Agent {
501
501
  groupName: 'Midscene Report',
502
502
  groupDescription: ''
503
503
  }, opts || {});
504
- if ('function' == typeof (null == opts ? void 0 : opts.modelConfig)) globalConfigManger.registerModelConfigFn(null == opts ? void 0 : opts.modelConfig);
504
+ if ((null == opts ? void 0 : opts.modelConfig) && 'function' != typeof (null == opts ? void 0 : opts.modelConfig)) throw new Error(`opts.modelConfig must be one of function or undefined, but got ${typeof (null == opts ? void 0 : opts.modelConfig)}`);
505
+ globalConfigManager.init(null == opts ? void 0 : opts.modelConfig);
505
506
  this.onTaskStartTip = this.opts.onTaskStartTip;
506
507
  this.insight = new Insight(async (action)=>this.getUIContext(action));
507
- if ((null == opts ? void 0 : opts.cacheId) && 'android' !== this.page.pageType) this.taskCache = new TaskCache(opts.cacheId, getAIConfigInBoolean('MIDSCENE_CACHE'));
508
+ if ((null == opts ? void 0 : opts.cacheId) && 'android' !== this.page.pageType) this.taskCache = new TaskCache(opts.cacheId, globalConfigManager.getEnvConfigInBoolean(MIDSCENE_CACHE));
508
509
  this.taskExecutor = new PageTaskExecutor(this.page, this.insight, {
509
510
  taskCache: this.taskCache,
510
511
  onTaskStart: this.callbackOnTaskStartTip.bind(this)
@@ -1 +1 @@
1
- {"version":3,"file":"agent/agent.mjs","sources":["webpack://@midscene/core/./src/agent/agent.ts"],"sourcesContent":["import {\n type AgentAssertOpt,\n type AgentDescribeElementAtPointResult,\n type AgentWaitForOpt,\n type DeviceAction,\n type ExecutionDump,\n type ExecutionRecorderItem,\n type ExecutionTask,\n type ExecutionTaskLog,\n type Executor,\n type GroupedActionDump,\n Insight,\n type InsightAction,\n type InsightExtractOption,\n type InsightExtractParam,\n type LocateOption,\n type LocateResultElement,\n type LocateValidatorResult,\n type LocatorValidatorOption,\n type MidsceneYamlScript,\n type OnTaskStartTip,\n type PlanningAction,\n type Rect,\n type ScrollParam,\n type TUserPrompt,\n type UIContext,\n} from '../index';\n\nimport yaml from 'js-yaml';\n\nimport {\n groupedActionDumpFileExt,\n reportHTMLContent,\n stringifyDumpData,\n writeLogFile,\n} from '@/utils';\nimport {\n ScriptPlayer,\n buildDetailedLocateParam,\n parseYamlScript,\n} from '../yaml/index';\n\nimport type { AbstractPage } from '@/device';\nimport {\n type IModelPreferences,\n type TModelConfigFn,\n getAIConfigInBoolean,\n globalConfigManger,\n vlLocateMode,\n} from '@midscene/shared/env';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\n// import type { AndroidDeviceInputOpt } from '../device';\nimport { TaskCache } from './task-cache';\nimport { PageTaskExecutor, locatePlanForLocate } from './tasks';\nimport { locateParamStr, paramStr, taskTitleStr, typeStr } from './ui-utils';\nimport {\n commonContextParser,\n getReportFileName,\n parsePrompt,\n printReportMsg,\n} from './utils';\nimport { trimContextByViewport } from './utils';\n\nconst debug = getDebug('agent');\n\nconst distanceOfTwoPoints = (p1: [number, number], p2: [number, number]) => {\n const [x1, y1] = p1;\n const [x2, y2] = p2;\n return Math.round(Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2));\n};\n\nconst includedInRect = (point: [number, number], rect: Rect) => {\n const [x, y] = point;\n const { left, top, width, height } = rect;\n return x >= left && x <= left + width && y >= top && y <= top + height;\n};\n\nconst defaultInsightExtractOption: InsightExtractOption = {\n domIncluded: false,\n screenshotIncluded: true,\n};\n\nexport interface PageAgentOpt {\n testId?: string;\n cacheId?: string;\n groupName?: string;\n groupDescription?: string;\n /* if auto generate report, default true */\n generateReport?: boolean;\n /* if auto print report msg, default true */\n autoPrintReportMsg?: boolean;\n onTaskStartTip?: OnTaskStartTip;\n aiActionContext?: string;\n /* custom report file name */\n reportFileName?: string;\n modelConfig?: TModelConfigFn;\n}\n\nexport class Agent<PageType extends AbstractPage = AbstractPage> {\n page: PageType;\n\n insight: Insight;\n\n dump: GroupedActionDump;\n\n reportFile?: string | null;\n\n reportFileName?: string;\n\n taskExecutor: PageTaskExecutor;\n\n opts: PageAgentOpt;\n\n /**\n * If true, the agent will not perform any actions\n */\n dryMode = false;\n\n onTaskStartTip?: OnTaskStartTip;\n\n taskCache?: TaskCache;\n\n onDumpUpdate?: (dump: string) => void;\n\n destroyed = false;\n\n /**\n * Frozen page context for consistent AI operations\n */\n private frozenPageContext?: UIContext;\n\n constructor(page: PageType, opts?: PageAgentOpt) {\n this.page = page;\n this.opts = Object.assign(\n {\n generateReport: true,\n autoPrintReportMsg: true,\n groupName: 'Midscene Report',\n groupDescription: '',\n },\n opts || {},\n );\n if (typeof opts?.modelConfig === 'function') {\n globalConfigManger.registerModelConfigFn(opts?.modelConfig);\n }\n\n this.onTaskStartTip = this.opts.onTaskStartTip;\n // get the parent browser of the puppeteer page\n // const browser = (this.page as PuppeteerWebPage).browser();\n\n this.insight = new Insight(async (action: InsightAction) => {\n return this.getUIContext(action);\n });\n\n if (opts?.cacheId && this.page.pageType !== 'android') {\n this.taskCache = new TaskCache(\n opts.cacheId,\n getAIConfigInBoolean('MIDSCENE_CACHE'), // if we should use cache to match the element\n );\n }\n\n this.taskExecutor = new PageTaskExecutor(this.page, this.insight, {\n taskCache: this.taskCache,\n onTaskStart: this.callbackOnTaskStartTip.bind(this),\n });\n this.dump = this.resetDump();\n this.reportFileName =\n opts?.reportFileName ||\n getReportFileName(opts?.testId || this.page.pageType || 'web');\n }\n\n async getActionSpace(): Promise<DeviceAction[]> {\n return this.page.actionSpace();\n }\n\n async getUIContext(action?: InsightAction): Promise<UIContext> {\n // If page context is frozen, return the frozen context for all actions\n if (this.frozenPageContext) {\n debug('Using frozen page context for action:', action);\n return this.frozenPageContext;\n }\n\n if (this.page.getContext) {\n debug('Using page.getContext for action:', action);\n return await this.page.getContext();\n } else {\n debug('Using commonContextParser for action:', action);\n return await commonContextParser(this.page);\n }\n }\n\n async _snapshotContext(): Promise<UIContext> {\n return await this.getUIContext('locate');\n }\n\n async setAIActionContext(prompt: string) {\n this.opts.aiActionContext = prompt;\n }\n\n resetDump() {\n this.dump = {\n groupName: this.opts.groupName!,\n groupDescription: this.opts.groupDescription,\n executions: [],\n modelBriefs: [],\n };\n\n return this.dump;\n }\n\n appendExecutionDump(execution: ExecutionDump) {\n // use trimContextByViewport to process execution\n const trimmedExecution = trimContextByViewport(execution);\n const currentDump = this.dump;\n currentDump.executions.push(trimmedExecution);\n }\n\n dumpDataString() {\n // update dump info\n this.dump.groupName = this.opts.groupName!;\n this.dump.groupDescription = this.opts.groupDescription;\n return stringifyDumpData(this.dump);\n }\n\n reportHTMLString() {\n return reportHTMLContent(this.dumpDataString());\n }\n\n writeOutActionDumps() {\n if (this.destroyed) {\n throw new Error(\n 'PageAgent has been destroyed. Cannot update report file.',\n );\n }\n const { generateReport, autoPrintReportMsg } = this.opts;\n this.reportFile = writeLogFile({\n fileName: this.reportFileName!,\n fileExt: groupedActionDumpFileExt,\n fileContent: this.dumpDataString(),\n type: 'dump',\n generateReport,\n });\n debug('writeOutActionDumps', this.reportFile);\n if (generateReport && autoPrintReportMsg && this.reportFile) {\n printReportMsg(this.reportFile);\n }\n }\n\n private async callbackOnTaskStartTip(task: ExecutionTask) {\n const param = paramStr(task);\n const tip = param ? `${typeStr(task)} - ${param}` : typeStr(task);\n\n if (this.onTaskStartTip) {\n await this.onTaskStartTip(tip);\n }\n }\n\n private async afterTaskRunning(executor: Executor, doNotThrowError = false) {\n this.appendExecutionDump(executor.dump());\n\n try {\n await this.onDumpUpdate?.(this.dumpDataString());\n } catch (error) {\n console.error('Error in onDumpUpdate', error);\n }\n\n this.writeOutActionDumps();\n\n if (executor.isInErrorState() && !doNotThrowError) {\n const errorTask = executor.latestErrorTask();\n throw new Error(`${errorTask?.errorMessage}\\n${errorTask?.errorStack}`, {\n cause: errorTask?.error,\n });\n }\n }\n\n async callActionInActionSpace<T = any>(\n type: string,\n opt?: T, // and all other action params\n ) {\n debug('callActionInActionSpace', type, ',', opt, ',', opt);\n\n const actionPlan: PlanningAction<T> = {\n type: type as any,\n param: (opt as any) || {},\n thought: '',\n };\n debug('actionPlan', actionPlan); // , ', in which the locateParam is', locateParam);\n\n const plans: PlanningAction[] = [actionPlan].filter(\n Boolean,\n ) as PlanningAction[];\n\n const title = taskTitleStr(\n type as any,\n locateParamStr((opt as any)?.locate || {}),\n );\n\n const { output, executor } = await this.taskExecutor.runPlans(title, plans);\n await this.afterTaskRunning(executor);\n return output;\n }\n\n async aiTap(locatePrompt: TUserPrompt, opt?: LocateOption) {\n assert(locatePrompt, 'missing locate prompt for tap');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n return this.callActionInActionSpace('Tap', {\n locate: detailedLocateParam,\n });\n }\n\n async aiRightClick(locatePrompt: TUserPrompt, opt?: LocateOption) {\n assert(locatePrompt, 'missing locate prompt for right click');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n return this.callActionInActionSpace('RightClick', {\n locate: detailedLocateParam,\n });\n }\n\n async aiHover(locatePrompt: TUserPrompt, opt?: LocateOption) {\n assert(locatePrompt, 'missing locate prompt for hover');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n return this.callActionInActionSpace('Hover', {\n locate: detailedLocateParam,\n });\n }\n\n // New signature, always use locatePrompt as the first param\n async aiInput(\n locatePrompt: TUserPrompt,\n opt: LocateOption & { value: string }, // AndroidDeviceInputOpt &\n ): Promise<any>;\n\n // Legacy signature - deprecated\n /**\n * @deprecated Use aiInput(locatePrompt, opt) instead where opt contains the value\n */\n async aiInput(\n value: string,\n locatePrompt: TUserPrompt,\n opt?: LocateOption, // AndroidDeviceInputOpt &\n ): Promise<any>;\n\n // Implementation\n async aiInput(\n locatePromptOrValue: TUserPrompt | string,\n locatePromptOrOpt:\n | TUserPrompt\n | (LocateOption & { value: string }) // AndroidDeviceInputOpt &\n | undefined,\n optOrUndefined?: LocateOption, // AndroidDeviceInputOpt &\n ) {\n let value: string;\n let locatePrompt: TUserPrompt;\n let opt:\n | (LocateOption & { value: string }) // AndroidDeviceInputOpt &\n | undefined;\n\n // Check if using new signature (first param is locatePrompt, second has value)\n if (\n typeof locatePromptOrOpt === 'object' &&\n locatePromptOrOpt !== null &&\n 'value' in locatePromptOrOpt\n ) {\n // New signature: aiInput(locatePrompt, opt)\n locatePrompt = locatePromptOrValue as TUserPrompt;\n const optWithValue = locatePromptOrOpt as LocateOption & {\n // AndroidDeviceInputOpt &\n value: string;\n };\n value = optWithValue.value;\n opt = optWithValue;\n } else {\n // Legacy signature: aiInput(value, locatePrompt, opt)\n value = locatePromptOrValue as string;\n locatePrompt = locatePromptOrOpt as TUserPrompt;\n opt = {\n ...optOrUndefined,\n value,\n };\n }\n\n assert(\n typeof value === 'string',\n 'input value must be a string, use empty string if you want to clear the input',\n );\n assert(locatePrompt, 'missing locate prompt for input');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n return this.callActionInActionSpace('Input', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n // New signature\n async aiKeyboardPress(\n locatePrompt: TUserPrompt,\n opt: LocateOption & { keyName: string },\n ): Promise<any>;\n\n // Legacy signature - deprecated\n /**\n * @deprecated Use aiKeyboardPress(locatePrompt, opt) instead where opt contains the keyName\n */\n async aiKeyboardPress(\n keyName: string,\n locatePrompt?: TUserPrompt,\n opt?: LocateOption,\n ): Promise<any>;\n\n // Implementation\n async aiKeyboardPress(\n locatePromptOrKeyName: TUserPrompt | string,\n locatePromptOrOpt:\n | TUserPrompt\n | (LocateOption & { keyName: string })\n | undefined,\n optOrUndefined?: LocateOption,\n ) {\n let keyName: string;\n let locatePrompt: TUserPrompt | undefined;\n let opt: (LocateOption & { keyName: string }) | undefined;\n\n // Check if using new signature (first param is locatePrompt, second has keyName)\n if (\n typeof locatePromptOrOpt === 'object' &&\n locatePromptOrOpt !== null &&\n 'keyName' in locatePromptOrOpt\n ) {\n // New signature: aiKeyboardPress(locatePrompt, opt)\n locatePrompt = locatePromptOrKeyName as TUserPrompt;\n opt = locatePromptOrOpt as LocateOption & {\n keyName: string;\n };\n } else {\n // Legacy signature: aiKeyboardPress(keyName, locatePrompt, opt)\n keyName = locatePromptOrKeyName as string;\n locatePrompt = locatePromptOrOpt as TUserPrompt | undefined;\n opt = {\n ...(optOrUndefined || {}),\n keyName,\n };\n }\n\n assert(opt?.keyName, 'missing keyName for keyboard press');\n\n const detailedLocateParam = locatePrompt\n ? buildDetailedLocateParam(locatePrompt, opt)\n : undefined;\n\n return this.callActionInActionSpace('KeyboardPress', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n // New signature\n async aiScroll(\n locatePrompt: TUserPrompt | undefined,\n opt: LocateOption & ScrollParam,\n ): Promise<any>;\n\n // Legacy signature - deprecated\n /**\n * @deprecated Use aiScroll(locatePrompt, opt) instead where opt contains the scroll parameters\n */\n async aiScroll(\n scrollParam: ScrollParam,\n locatePrompt?: TUserPrompt,\n opt?: LocateOption,\n ): Promise<any>;\n\n // Implementation\n async aiScroll(\n locatePromptOrScrollParam: TUserPrompt | ScrollParam | undefined,\n locatePromptOrOpt: TUserPrompt | (LocateOption & ScrollParam) | undefined,\n optOrUndefined?: LocateOption,\n ) {\n let scrollParam: ScrollParam;\n let locatePrompt: TUserPrompt | undefined;\n let opt: LocateOption | undefined;\n\n // Check if using new signature (first param is locatePrompt, second has scroll params)\n if (\n typeof locatePromptOrOpt === 'object' &&\n ('direction' in locatePromptOrOpt ||\n 'scrollType' in locatePromptOrOpt ||\n 'distance' in locatePromptOrOpt)\n ) {\n // New signature: aiScroll(locatePrompt, opt)\n locatePrompt = locatePromptOrScrollParam as TUserPrompt;\n opt = locatePromptOrOpt as LocateOption & ScrollParam;\n } else {\n // Legacy signature: aiScroll(scrollParam, locatePrompt, opt)\n scrollParam = locatePromptOrScrollParam as ScrollParam;\n locatePrompt = locatePromptOrOpt as TUserPrompt | undefined;\n opt = {\n ...(optOrUndefined || {}),\n ...(scrollParam || {}),\n };\n }\n\n const detailedLocateParam = buildDetailedLocateParam(\n locatePrompt || '',\n opt,\n );\n\n return this.callActionInActionSpace('Scroll', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n async aiAction(\n taskPrompt: string,\n opt?: {\n cacheable?: boolean;\n },\n ) {\n const modelPreferences: IModelPreferences = { intent: 'planning' };\n const cacheable = opt?.cacheable;\n // if vlm-ui-tars, plan cache is not used\n const isVlmUiTars = vlLocateMode(modelPreferences) === 'vlm-ui-tars';\n const matchedCache =\n isVlmUiTars || cacheable === false\n ? undefined\n : this.taskCache?.matchPlanCache(taskPrompt);\n if (matchedCache && this.taskCache?.isCacheResultUsed) {\n // log into report file\n const { executor } = await this.taskExecutor.loadYamlFlowAsPlanning(\n taskPrompt,\n matchedCache.cacheContent?.yamlWorkflow,\n );\n\n await await this.afterTaskRunning(executor);\n\n debug('matched cache, will call .runYaml to run the action');\n const yaml = matchedCache.cacheContent?.yamlWorkflow;\n return this.runYaml(yaml);\n }\n\n const { output, executor } = await (isVlmUiTars\n ? this.taskExecutor.actionToGoal(taskPrompt)\n : this.taskExecutor.action(taskPrompt, this.opts.aiActionContext));\n\n // update cache\n if (this.taskCache && output?.yamlFlow && cacheable !== false) {\n const yamlContent: MidsceneYamlScript = {\n tasks: [\n {\n name: taskPrompt,\n flow: output.yamlFlow,\n },\n ],\n };\n const yamlFlowStr = yaml.dump(yamlContent);\n this.taskCache.updateOrAppendCacheRecord(\n {\n type: 'plan',\n prompt: taskPrompt,\n yamlWorkflow: yamlFlowStr,\n },\n matchedCache,\n );\n }\n\n await this.afterTaskRunning(executor);\n return output;\n }\n\n async aiQuery<ReturnType = any>(\n demand: InsightExtractParam,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<ReturnType> {\n const { output, executor } =\n await this.taskExecutor.createTypeQueryExecution('Query', demand, opt);\n await this.afterTaskRunning(executor);\n return output as ReturnType;\n }\n\n async aiBoolean(\n prompt: TUserPrompt,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<boolean> {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output, executor } =\n await this.taskExecutor.createTypeQueryExecution(\n 'Boolean',\n textPrompt,\n opt,\n multimodalPrompt,\n );\n await this.afterTaskRunning(executor);\n return output as boolean;\n }\n\n async aiNumber(\n prompt: TUserPrompt,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<number> {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output, executor } =\n await this.taskExecutor.createTypeQueryExecution(\n 'Number',\n textPrompt,\n opt,\n multimodalPrompt,\n );\n await this.afterTaskRunning(executor);\n return output as number;\n }\n\n async aiString(\n prompt: TUserPrompt,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<string> {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output, executor } =\n await this.taskExecutor.createTypeQueryExecution(\n 'String',\n textPrompt,\n opt,\n multimodalPrompt,\n );\n await this.afterTaskRunning(executor);\n return output as string;\n }\n\n async aiAsk(\n prompt: TUserPrompt,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<string> {\n return this.aiString(prompt, opt);\n }\n\n async describeElementAtPoint(\n center: [number, number],\n opt?: {\n verifyPrompt?: boolean;\n retryLimit?: number;\n deepThink?: boolean;\n } & LocatorValidatorOption,\n ): Promise<AgentDescribeElementAtPointResult> {\n const { verifyPrompt = true, retryLimit = 3 } = opt || {};\n\n let success = false;\n let retryCount = 0;\n let resultPrompt = '';\n let deepThink = opt?.deepThink || false;\n let verifyResult: LocateValidatorResult | undefined;\n\n while (!success && retryCount < retryLimit) {\n if (retryCount >= 2) {\n deepThink = true;\n }\n debug(\n 'aiDescribe',\n center,\n 'verifyPrompt',\n verifyPrompt,\n 'retryCount',\n retryCount,\n 'deepThink',\n deepThink,\n );\n const text = await this.insight.describe(center, { deepThink });\n debug('aiDescribe text', text);\n assert(text.description, `failed to describe element at [${center}]`);\n resultPrompt = text.description;\n\n verifyResult = await this.verifyLocator(\n resultPrompt,\n deepThink ? { deepThink: true } : undefined,\n center,\n opt,\n );\n if (verifyResult.pass) {\n success = true;\n } else {\n retryCount++;\n }\n }\n\n return {\n prompt: resultPrompt,\n deepThink,\n verifyResult,\n };\n }\n\n async verifyLocator(\n prompt: string,\n locateOpt: LocateOption | undefined,\n expectCenter: [number, number],\n verifyLocateOption?: LocatorValidatorOption,\n ): Promise<LocateValidatorResult> {\n debug('verifyLocator', prompt, locateOpt, expectCenter, verifyLocateOption);\n\n const { center: verifyCenter, rect: verifyRect } = await this.aiLocate(\n prompt,\n locateOpt,\n );\n const distance = distanceOfTwoPoints(expectCenter, verifyCenter);\n const included = includedInRect(expectCenter, verifyRect);\n const pass =\n distance <= (verifyLocateOption?.centerDistanceThreshold || 20) ||\n included;\n const verifyResult = {\n pass,\n rect: verifyRect,\n center: verifyCenter,\n centerDistance: distance,\n };\n debug('aiDescribe verifyResult', verifyResult);\n return verifyResult;\n }\n\n async aiLocate(prompt: TUserPrompt, opt?: LocateOption) {\n const locateParam = buildDetailedLocateParam(prompt, opt);\n assert(locateParam, 'cannot get locate param for aiLocate');\n const locatePlan = locatePlanForLocate(locateParam);\n const plans = [locatePlan];\n const { executor, output } = await this.taskExecutor.runPlans(\n taskTitleStr('Locate', locateParamStr(locateParam)),\n plans,\n );\n await this.afterTaskRunning(executor);\n\n const { element } = output;\n\n return {\n rect: element?.rect,\n center: element?.center,\n scale: (await this.page.size()).dpr,\n } as Pick<LocateResultElement, 'rect' | 'center'> & {\n scale: number;\n };\n }\n\n async aiAssert(\n assertion: TUserPrompt,\n msg?: string,\n opt?: AgentAssertOpt & InsightExtractOption,\n ) {\n const insightOpt: InsightExtractOption = {\n domIncluded: opt?.domIncluded ?? defaultInsightExtractOption.domIncluded,\n screenshotIncluded:\n opt?.screenshotIncluded ??\n defaultInsightExtractOption.screenshotIncluded,\n returnThought: opt?.returnThought ?? true,\n isWaitForAssert: opt?.isWaitForAssert,\n doNotThrowError: opt?.doNotThrowError,\n };\n\n const { output, executor, thought } = await this.taskExecutor.assert(\n assertion,\n insightOpt,\n );\n await this.afterTaskRunning(executor, true);\n\n const message = output\n ? undefined\n : `Assertion failed: ${msg || assertion}\\nReason: ${\n thought || executor.latestErrorTask()?.error || '(no_reason)'\n }`;\n\n if (opt?.keepRawResponse) {\n return {\n pass: output,\n thought,\n message,\n };\n }\n\n if (!output) {\n throw new Error(message);\n }\n }\n\n async aiWaitFor(assertion: TUserPrompt, opt?: AgentWaitForOpt) {\n const { executor } = await this.taskExecutor.waitFor(assertion, {\n timeoutMs: opt?.timeoutMs || 15 * 1000,\n checkIntervalMs: opt?.checkIntervalMs || 3 * 1000,\n });\n await this.afterTaskRunning(executor, true);\n\n if (executor.isInErrorState()) {\n const errorTask = executor.latestErrorTask();\n throw new Error(`${errorTask?.error}\\n${errorTask?.errorStack}`);\n }\n }\n\n async ai(taskPrompt: string, type = 'action') {\n if (type === 'action') {\n return this.aiAction(taskPrompt);\n }\n if (type === 'query') {\n return this.aiQuery(taskPrompt);\n }\n\n if (type === 'assert') {\n return this.aiAssert(taskPrompt);\n }\n\n if (type === 'tap') {\n return this.aiTap(taskPrompt);\n }\n\n if (type === 'rightClick') {\n return this.aiRightClick(taskPrompt);\n }\n\n throw new Error(\n `Unknown type: ${type}, only support 'action', 'query', 'assert', 'tap', 'rightClick'`,\n );\n }\n\n async runYaml(yamlScriptContent: string): Promise<{\n result: Record<string, any>;\n }> {\n const script = parseYamlScript(yamlScriptContent, 'yaml', true);\n const player = new ScriptPlayer(script, async (target) => {\n return { agent: this, freeFn: [] };\n });\n await player.run();\n\n if (player.status === 'error') {\n const errors = player.taskStatusList\n .filter((task) => task.status === 'error')\n .map((task) => {\n return `task - ${task.name}: ${task.error?.message}`;\n })\n .join('\\n');\n throw new Error(`Error(s) occurred in running yaml script:\\n${errors}`);\n }\n\n return {\n result: player.result,\n };\n }\n\n async evaluateJavaScript(script: string) {\n assert(\n this.page.evaluateJavaScript,\n 'evaluateJavaScript is not supported in current agent',\n );\n return this.page.evaluateJavaScript(script);\n }\n\n async destroy() {\n await this.page.destroy();\n this.resetDump(); // reset dump to release memory\n this.destroyed = true;\n }\n\n async logScreenshot(\n title?: string,\n opt?: {\n content: string;\n },\n ) {\n // 1. screenshot\n const base64 = await this.page.screenshotBase64();\n const now = Date.now();\n // 2. build recorder\n const recorder: ExecutionRecorderItem[] = [\n {\n type: 'screenshot',\n ts: now,\n screenshot: base64,\n },\n ];\n // 3. build ExecutionTaskLog\n const task: ExecutionTaskLog = {\n type: 'Log',\n subType: 'Screenshot',\n status: 'finished',\n recorder,\n timing: {\n start: now,\n end: now,\n cost: 0,\n },\n param: {\n content: opt?.content || '',\n },\n executor: async () => {},\n };\n // 4. build ExecutionDump\n const executionDump: ExecutionDump = {\n sdkVersion: '',\n logTime: now,\n name: `Log - ${title || 'untitled'}`,\n description: opt?.content || '',\n tasks: [task],\n };\n // 5. append to execution dump\n this.appendExecutionDump(executionDump);\n\n try {\n this.onDumpUpdate?.(this.dumpDataString());\n } catch (error) {\n console.error('Failed to update dump', error);\n }\n\n this.writeOutActionDumps();\n }\n\n _unstableLogContent() {\n const { groupName, groupDescription, executions } = this.dump;\n const newExecutions = Array.isArray(executions)\n ? executions.map((execution: any) => {\n const { tasks, ...restExecution } = execution;\n let newTasks = tasks;\n if (Array.isArray(tasks)) {\n newTasks = tasks.map((task: any) => {\n // only remove pageContext and log from task\n const { pageContext, log, ...restTask } = task;\n return restTask;\n });\n }\n return { ...restExecution, ...(newTasks ? { tasks: newTasks } : {}) };\n })\n : [];\n return {\n groupName,\n groupDescription,\n executions: newExecutions,\n };\n }\n\n /**\n * Freezes the current page context to be reused in subsequent AI operations\n * This avoids recalculating page context for each operation\n */\n async freezePageContext(): Promise<void> {\n debug('Freezing page context');\n const context = await this._snapshotContext();\n // Mark the context as frozen\n context._isFrozen = true;\n this.frozenPageContext = context;\n debug('Page context frozen successfully');\n }\n\n /**\n * Unfreezes the page context, allowing AI operations to calculate context dynamically\n */\n async unfreezePageContext(): Promise<void> {\n debug('Unfreezing page context');\n this.frozenPageContext = undefined;\n debug('Page context unfrozen successfully');\n }\n}\n"],"names":["debug","getDebug","distanceOfTwoPoints","p1","p2","x1","y1","x2","y2","Math","includedInRect","point","rect","x","y","left","top","width","height","defaultInsightExtractOption","Agent","action","commonContextParser","prompt","execution","trimmedExecution","trimContextByViewport","currentDump","stringifyDumpData","reportHTMLContent","Error","generateReport","autoPrintReportMsg","writeLogFile","groupedActionDumpFileExt","printReportMsg","task","param","paramStr","tip","typeStr","executor","doNotThrowError","_this","error","console","errorTask","type","opt","actionPlan","plans","Boolean","title","taskTitleStr","locateParamStr","output","locatePrompt","assert","detailedLocateParam","buildDetailedLocateParam","locatePromptOrValue","locatePromptOrOpt","optOrUndefined","value","optWithValue","locatePromptOrKeyName","keyName","undefined","locatePromptOrScrollParam","scrollParam","taskPrompt","_this_taskCache","_this_taskCache1","modelPreferences","cacheable","isVlmUiTars","vlLocateMode","matchedCache","_matchedCache_cacheContent","_matchedCache_cacheContent1","yaml","yamlContent","yamlFlowStr","demand","textPrompt","multimodalPrompt","parsePrompt","center","verifyPrompt","retryLimit","success","retryCount","resultPrompt","deepThink","verifyResult","text","locateOpt","expectCenter","verifyLocateOption","verifyCenter","verifyRect","distance","included","pass","locateParam","locatePlan","locatePlanForLocate","element","assertion","msg","_executor_latestErrorTask","insightOpt","thought","message","yamlScriptContent","script","parseYamlScript","player","ScriptPlayer","target","errors","_task_error","base64","now","Date","recorder","executionDump","groupName","groupDescription","executions","newExecutions","Array","tasks","restExecution","newTasks","pageContext","log","restTask","context","page","opts","Object","globalConfigManger","Insight","TaskCache","getAIConfigInBoolean","PageTaskExecutor","getReportFileName"],"mappings":"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"}
1
+ {"version":3,"file":"agent/agent.mjs","sources":["webpack://@midscene/core/./src/agent/agent.ts"],"sourcesContent":["import {\n type AgentAssertOpt,\n type AgentDescribeElementAtPointResult,\n type AgentWaitForOpt,\n type DeviceAction,\n type ExecutionDump,\n type ExecutionRecorderItem,\n type ExecutionTask,\n type ExecutionTaskLog,\n type Executor,\n type GroupedActionDump,\n Insight,\n type InsightAction,\n type InsightExtractOption,\n type InsightExtractParam,\n type LocateOption,\n type LocateResultElement,\n type LocateValidatorResult,\n type LocatorValidatorOption,\n type MidsceneYamlScript,\n type OnTaskStartTip,\n type PlanningAction,\n type Rect,\n type ScrollParam,\n type TUserPrompt,\n type UIContext,\n} from '../index';\n\nimport yaml from 'js-yaml';\n\nimport {\n groupedActionDumpFileExt,\n reportHTMLContent,\n stringifyDumpData,\n writeLogFile,\n} from '@/utils';\nimport {\n ScriptPlayer,\n buildDetailedLocateParam,\n parseYamlScript,\n} from '../yaml/index';\n\nimport type { AbstractPage } from '@/device';\nimport {\n type IModelPreferences,\n MIDSCENE_CACHE,\n type TModelConfigFn,\n globalConfigManager,\n vlLocateMode,\n} from '@midscene/shared/env';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\n// import type { AndroidDeviceInputOpt } from '../device';\nimport { TaskCache } from './task-cache';\nimport { PageTaskExecutor, locatePlanForLocate } from './tasks';\nimport { locateParamStr, paramStr, taskTitleStr, typeStr } from './ui-utils';\nimport {\n commonContextParser,\n getReportFileName,\n parsePrompt,\n printReportMsg,\n} from './utils';\nimport { trimContextByViewport } from './utils';\n\nconst debug = getDebug('agent');\n\nconst distanceOfTwoPoints = (p1: [number, number], p2: [number, number]) => {\n const [x1, y1] = p1;\n const [x2, y2] = p2;\n return Math.round(Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2));\n};\n\nconst includedInRect = (point: [number, number], rect: Rect) => {\n const [x, y] = point;\n const { left, top, width, height } = rect;\n return x >= left && x <= left + width && y >= top && y <= top + height;\n};\n\nconst defaultInsightExtractOption: InsightExtractOption = {\n domIncluded: false,\n screenshotIncluded: true,\n};\n\nexport interface PageAgentOpt {\n testId?: string;\n cacheId?: string;\n groupName?: string;\n groupDescription?: string;\n /* if auto generate report, default true */\n generateReport?: boolean;\n /* if auto print report msg, default true */\n autoPrintReportMsg?: boolean;\n onTaskStartTip?: OnTaskStartTip;\n aiActionContext?: string;\n /* custom report file name */\n reportFileName?: string;\n modelConfig?: TModelConfigFn;\n}\n\nexport class Agent<PageType extends AbstractPage = AbstractPage> {\n page: PageType;\n\n insight: Insight;\n\n dump: GroupedActionDump;\n\n reportFile?: string | null;\n\n reportFileName?: string;\n\n taskExecutor: PageTaskExecutor;\n\n opts: PageAgentOpt;\n\n /**\n * If true, the agent will not perform any actions\n */\n dryMode = false;\n\n onTaskStartTip?: OnTaskStartTip;\n\n taskCache?: TaskCache;\n\n onDumpUpdate?: (dump: string) => void;\n\n destroyed = false;\n\n /**\n * Frozen page context for consistent AI operations\n */\n private frozenPageContext?: UIContext;\n\n constructor(page: PageType, opts?: PageAgentOpt) {\n this.page = page;\n this.opts = Object.assign(\n {\n generateReport: true,\n autoPrintReportMsg: true,\n groupName: 'Midscene Report',\n groupDescription: '',\n },\n opts || {},\n );\n if (opts?.modelConfig && typeof opts?.modelConfig !== 'function') {\n throw new Error(\n `opts.modelConfig must be one of function or undefined, but got ${typeof opts?.modelConfig}`,\n );\n }\n\n globalConfigManager.init(opts?.modelConfig);\n\n this.onTaskStartTip = this.opts.onTaskStartTip;\n // get the parent browser of the puppeteer page\n // const browser = (this.page as PuppeteerWebPage).browser();\n\n this.insight = new Insight(async (action: InsightAction) => {\n return this.getUIContext(action);\n });\n\n if (opts?.cacheId && this.page.pageType !== 'android') {\n this.taskCache = new TaskCache(\n opts.cacheId,\n globalConfigManager.getEnvConfigInBoolean(MIDSCENE_CACHE), // if we should use cache to match the element\n );\n }\n\n this.taskExecutor = new PageTaskExecutor(this.page, this.insight, {\n taskCache: this.taskCache,\n onTaskStart: this.callbackOnTaskStartTip.bind(this),\n });\n this.dump = this.resetDump();\n this.reportFileName =\n opts?.reportFileName ||\n getReportFileName(opts?.testId || this.page.pageType || 'web');\n }\n\n async getActionSpace(): Promise<DeviceAction[]> {\n return this.page.actionSpace();\n }\n\n async getUIContext(action?: InsightAction): Promise<UIContext> {\n // If page context is frozen, return the frozen context for all actions\n if (this.frozenPageContext) {\n debug('Using frozen page context for action:', action);\n return this.frozenPageContext;\n }\n\n if (this.page.getContext) {\n debug('Using page.getContext for action:', action);\n return await this.page.getContext();\n } else {\n debug('Using commonContextParser for action:', action);\n return await commonContextParser(this.page);\n }\n }\n\n async _snapshotContext(): Promise<UIContext> {\n return await this.getUIContext('locate');\n }\n\n async setAIActionContext(prompt: string) {\n this.opts.aiActionContext = prompt;\n }\n\n resetDump() {\n this.dump = {\n groupName: this.opts.groupName!,\n groupDescription: this.opts.groupDescription,\n executions: [],\n modelBriefs: [],\n };\n\n return this.dump;\n }\n\n appendExecutionDump(execution: ExecutionDump) {\n // use trimContextByViewport to process execution\n const trimmedExecution = trimContextByViewport(execution);\n const currentDump = this.dump;\n currentDump.executions.push(trimmedExecution);\n }\n\n dumpDataString() {\n // update dump info\n this.dump.groupName = this.opts.groupName!;\n this.dump.groupDescription = this.opts.groupDescription;\n return stringifyDumpData(this.dump);\n }\n\n reportHTMLString() {\n return reportHTMLContent(this.dumpDataString());\n }\n\n writeOutActionDumps() {\n if (this.destroyed) {\n throw new Error(\n 'PageAgent has been destroyed. Cannot update report file.',\n );\n }\n const { generateReport, autoPrintReportMsg } = this.opts;\n this.reportFile = writeLogFile({\n fileName: this.reportFileName!,\n fileExt: groupedActionDumpFileExt,\n fileContent: this.dumpDataString(),\n type: 'dump',\n generateReport,\n });\n debug('writeOutActionDumps', this.reportFile);\n if (generateReport && autoPrintReportMsg && this.reportFile) {\n printReportMsg(this.reportFile);\n }\n }\n\n private async callbackOnTaskStartTip(task: ExecutionTask) {\n const param = paramStr(task);\n const tip = param ? `${typeStr(task)} - ${param}` : typeStr(task);\n\n if (this.onTaskStartTip) {\n await this.onTaskStartTip(tip);\n }\n }\n\n private async afterTaskRunning(executor: Executor, doNotThrowError = false) {\n this.appendExecutionDump(executor.dump());\n\n try {\n await this.onDumpUpdate?.(this.dumpDataString());\n } catch (error) {\n console.error('Error in onDumpUpdate', error);\n }\n\n this.writeOutActionDumps();\n\n if (executor.isInErrorState() && !doNotThrowError) {\n const errorTask = executor.latestErrorTask();\n throw new Error(`${errorTask?.errorMessage}\\n${errorTask?.errorStack}`, {\n cause: errorTask?.error,\n });\n }\n }\n\n async callActionInActionSpace<T = any>(\n type: string,\n opt?: T, // and all other action params\n ) {\n debug('callActionInActionSpace', type, ',', opt, ',', opt);\n\n const actionPlan: PlanningAction<T> = {\n type: type as any,\n param: (opt as any) || {},\n thought: '',\n };\n debug('actionPlan', actionPlan); // , ', in which the locateParam is', locateParam);\n\n const plans: PlanningAction[] = [actionPlan].filter(\n Boolean,\n ) as PlanningAction[];\n\n const title = taskTitleStr(\n type as any,\n locateParamStr((opt as any)?.locate || {}),\n );\n\n const { output, executor } = await this.taskExecutor.runPlans(title, plans);\n await this.afterTaskRunning(executor);\n return output;\n }\n\n async aiTap(locatePrompt: TUserPrompt, opt?: LocateOption) {\n assert(locatePrompt, 'missing locate prompt for tap');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n return this.callActionInActionSpace('Tap', {\n locate: detailedLocateParam,\n });\n }\n\n async aiRightClick(locatePrompt: TUserPrompt, opt?: LocateOption) {\n assert(locatePrompt, 'missing locate prompt for right click');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n return this.callActionInActionSpace('RightClick', {\n locate: detailedLocateParam,\n });\n }\n\n async aiHover(locatePrompt: TUserPrompt, opt?: LocateOption) {\n assert(locatePrompt, 'missing locate prompt for hover');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n return this.callActionInActionSpace('Hover', {\n locate: detailedLocateParam,\n });\n }\n\n // New signature, always use locatePrompt as the first param\n async aiInput(\n locatePrompt: TUserPrompt,\n opt: LocateOption & { value: string }, // AndroidDeviceInputOpt &\n ): Promise<any>;\n\n // Legacy signature - deprecated\n /**\n * @deprecated Use aiInput(locatePrompt, opt) instead where opt contains the value\n */\n async aiInput(\n value: string,\n locatePrompt: TUserPrompt,\n opt?: LocateOption, // AndroidDeviceInputOpt &\n ): Promise<any>;\n\n // Implementation\n async aiInput(\n locatePromptOrValue: TUserPrompt | string,\n locatePromptOrOpt:\n | TUserPrompt\n | (LocateOption & { value: string }) // AndroidDeviceInputOpt &\n | undefined,\n optOrUndefined?: LocateOption, // AndroidDeviceInputOpt &\n ) {\n let value: string;\n let locatePrompt: TUserPrompt;\n let opt:\n | (LocateOption & { value: string }) // AndroidDeviceInputOpt &\n | undefined;\n\n // Check if using new signature (first param is locatePrompt, second has value)\n if (\n typeof locatePromptOrOpt === 'object' &&\n locatePromptOrOpt !== null &&\n 'value' in locatePromptOrOpt\n ) {\n // New signature: aiInput(locatePrompt, opt)\n locatePrompt = locatePromptOrValue as TUserPrompt;\n const optWithValue = locatePromptOrOpt as LocateOption & {\n // AndroidDeviceInputOpt &\n value: string;\n };\n value = optWithValue.value;\n opt = optWithValue;\n } else {\n // Legacy signature: aiInput(value, locatePrompt, opt)\n value = locatePromptOrValue as string;\n locatePrompt = locatePromptOrOpt as TUserPrompt;\n opt = {\n ...optOrUndefined,\n value,\n };\n }\n\n assert(\n typeof value === 'string',\n 'input value must be a string, use empty string if you want to clear the input',\n );\n assert(locatePrompt, 'missing locate prompt for input');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n return this.callActionInActionSpace('Input', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n // New signature\n async aiKeyboardPress(\n locatePrompt: TUserPrompt,\n opt: LocateOption & { keyName: string },\n ): Promise<any>;\n\n // Legacy signature - deprecated\n /**\n * @deprecated Use aiKeyboardPress(locatePrompt, opt) instead where opt contains the keyName\n */\n async aiKeyboardPress(\n keyName: string,\n locatePrompt?: TUserPrompt,\n opt?: LocateOption,\n ): Promise<any>;\n\n // Implementation\n async aiKeyboardPress(\n locatePromptOrKeyName: TUserPrompt | string,\n locatePromptOrOpt:\n | TUserPrompt\n | (LocateOption & { keyName: string })\n | undefined,\n optOrUndefined?: LocateOption,\n ) {\n let keyName: string;\n let locatePrompt: TUserPrompt | undefined;\n let opt: (LocateOption & { keyName: string }) | undefined;\n\n // Check if using new signature (first param is locatePrompt, second has keyName)\n if (\n typeof locatePromptOrOpt === 'object' &&\n locatePromptOrOpt !== null &&\n 'keyName' in locatePromptOrOpt\n ) {\n // New signature: aiKeyboardPress(locatePrompt, opt)\n locatePrompt = locatePromptOrKeyName as TUserPrompt;\n opt = locatePromptOrOpt as LocateOption & {\n keyName: string;\n };\n } else {\n // Legacy signature: aiKeyboardPress(keyName, locatePrompt, opt)\n keyName = locatePromptOrKeyName as string;\n locatePrompt = locatePromptOrOpt as TUserPrompt | undefined;\n opt = {\n ...(optOrUndefined || {}),\n keyName,\n };\n }\n\n assert(opt?.keyName, 'missing keyName for keyboard press');\n\n const detailedLocateParam = locatePrompt\n ? buildDetailedLocateParam(locatePrompt, opt)\n : undefined;\n\n return this.callActionInActionSpace('KeyboardPress', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n // New signature\n async aiScroll(\n locatePrompt: TUserPrompt | undefined,\n opt: LocateOption & ScrollParam,\n ): Promise<any>;\n\n // Legacy signature - deprecated\n /**\n * @deprecated Use aiScroll(locatePrompt, opt) instead where opt contains the scroll parameters\n */\n async aiScroll(\n scrollParam: ScrollParam,\n locatePrompt?: TUserPrompt,\n opt?: LocateOption,\n ): Promise<any>;\n\n // Implementation\n async aiScroll(\n locatePromptOrScrollParam: TUserPrompt | ScrollParam | undefined,\n locatePromptOrOpt: TUserPrompt | (LocateOption & ScrollParam) | undefined,\n optOrUndefined?: LocateOption,\n ) {\n let scrollParam: ScrollParam;\n let locatePrompt: TUserPrompt | undefined;\n let opt: LocateOption | undefined;\n\n // Check if using new signature (first param is locatePrompt, second has scroll params)\n if (\n typeof locatePromptOrOpt === 'object' &&\n ('direction' in locatePromptOrOpt ||\n 'scrollType' in locatePromptOrOpt ||\n 'distance' in locatePromptOrOpt)\n ) {\n // New signature: aiScroll(locatePrompt, opt)\n locatePrompt = locatePromptOrScrollParam as TUserPrompt;\n opt = locatePromptOrOpt as LocateOption & ScrollParam;\n } else {\n // Legacy signature: aiScroll(scrollParam, locatePrompt, opt)\n scrollParam = locatePromptOrScrollParam as ScrollParam;\n locatePrompt = locatePromptOrOpt as TUserPrompt | undefined;\n opt = {\n ...(optOrUndefined || {}),\n ...(scrollParam || {}),\n };\n }\n\n const detailedLocateParam = buildDetailedLocateParam(\n locatePrompt || '',\n opt,\n );\n\n return this.callActionInActionSpace('Scroll', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n async aiAction(\n taskPrompt: string,\n opt?: {\n cacheable?: boolean;\n },\n ) {\n const modelPreferences: IModelPreferences = { intent: 'planning' };\n const cacheable = opt?.cacheable;\n // if vlm-ui-tars, plan cache is not used\n const isVlmUiTars = vlLocateMode(modelPreferences) === 'vlm-ui-tars';\n const matchedCache =\n isVlmUiTars || cacheable === false\n ? undefined\n : this.taskCache?.matchPlanCache(taskPrompt);\n if (matchedCache && this.taskCache?.isCacheResultUsed) {\n // log into report file\n const { executor } = await this.taskExecutor.loadYamlFlowAsPlanning(\n taskPrompt,\n matchedCache.cacheContent?.yamlWorkflow,\n );\n\n await await this.afterTaskRunning(executor);\n\n debug('matched cache, will call .runYaml to run the action');\n const yaml = matchedCache.cacheContent?.yamlWorkflow;\n return this.runYaml(yaml);\n }\n\n const { output, executor } = await (isVlmUiTars\n ? this.taskExecutor.actionToGoal(taskPrompt)\n : this.taskExecutor.action(taskPrompt, this.opts.aiActionContext));\n\n // update cache\n if (this.taskCache && output?.yamlFlow && cacheable !== false) {\n const yamlContent: MidsceneYamlScript = {\n tasks: [\n {\n name: taskPrompt,\n flow: output.yamlFlow,\n },\n ],\n };\n const yamlFlowStr = yaml.dump(yamlContent);\n this.taskCache.updateOrAppendCacheRecord(\n {\n type: 'plan',\n prompt: taskPrompt,\n yamlWorkflow: yamlFlowStr,\n },\n matchedCache,\n );\n }\n\n await this.afterTaskRunning(executor);\n return output;\n }\n\n async aiQuery<ReturnType = any>(\n demand: InsightExtractParam,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<ReturnType> {\n const { output, executor } =\n await this.taskExecutor.createTypeQueryExecution('Query', demand, opt);\n await this.afterTaskRunning(executor);\n return output as ReturnType;\n }\n\n async aiBoolean(\n prompt: TUserPrompt,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<boolean> {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output, executor } =\n await this.taskExecutor.createTypeQueryExecution(\n 'Boolean',\n textPrompt,\n opt,\n multimodalPrompt,\n );\n await this.afterTaskRunning(executor);\n return output as boolean;\n }\n\n async aiNumber(\n prompt: TUserPrompt,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<number> {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output, executor } =\n await this.taskExecutor.createTypeQueryExecution(\n 'Number',\n textPrompt,\n opt,\n multimodalPrompt,\n );\n await this.afterTaskRunning(executor);\n return output as number;\n }\n\n async aiString(\n prompt: TUserPrompt,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<string> {\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output, executor } =\n await this.taskExecutor.createTypeQueryExecution(\n 'String',\n textPrompt,\n opt,\n multimodalPrompt,\n );\n await this.afterTaskRunning(executor);\n return output as string;\n }\n\n async aiAsk(\n prompt: TUserPrompt,\n opt: InsightExtractOption = defaultInsightExtractOption,\n ): Promise<string> {\n return this.aiString(prompt, opt);\n }\n\n async describeElementAtPoint(\n center: [number, number],\n opt?: {\n verifyPrompt?: boolean;\n retryLimit?: number;\n deepThink?: boolean;\n } & LocatorValidatorOption,\n ): Promise<AgentDescribeElementAtPointResult> {\n const { verifyPrompt = true, retryLimit = 3 } = opt || {};\n\n let success = false;\n let retryCount = 0;\n let resultPrompt = '';\n let deepThink = opt?.deepThink || false;\n let verifyResult: LocateValidatorResult | undefined;\n\n while (!success && retryCount < retryLimit) {\n if (retryCount >= 2) {\n deepThink = true;\n }\n debug(\n 'aiDescribe',\n center,\n 'verifyPrompt',\n verifyPrompt,\n 'retryCount',\n retryCount,\n 'deepThink',\n deepThink,\n );\n const text = await this.insight.describe(center, { deepThink });\n debug('aiDescribe text', text);\n assert(text.description, `failed to describe element at [${center}]`);\n resultPrompt = text.description;\n\n verifyResult = await this.verifyLocator(\n resultPrompt,\n deepThink ? { deepThink: true } : undefined,\n center,\n opt,\n );\n if (verifyResult.pass) {\n success = true;\n } else {\n retryCount++;\n }\n }\n\n return {\n prompt: resultPrompt,\n deepThink,\n verifyResult,\n };\n }\n\n async verifyLocator(\n prompt: string,\n locateOpt: LocateOption | undefined,\n expectCenter: [number, number],\n verifyLocateOption?: LocatorValidatorOption,\n ): Promise<LocateValidatorResult> {\n debug('verifyLocator', prompt, locateOpt, expectCenter, verifyLocateOption);\n\n const { center: verifyCenter, rect: verifyRect } = await this.aiLocate(\n prompt,\n locateOpt,\n );\n const distance = distanceOfTwoPoints(expectCenter, verifyCenter);\n const included = includedInRect(expectCenter, verifyRect);\n const pass =\n distance <= (verifyLocateOption?.centerDistanceThreshold || 20) ||\n included;\n const verifyResult = {\n pass,\n rect: verifyRect,\n center: verifyCenter,\n centerDistance: distance,\n };\n debug('aiDescribe verifyResult', verifyResult);\n return verifyResult;\n }\n\n async aiLocate(prompt: TUserPrompt, opt?: LocateOption) {\n const locateParam = buildDetailedLocateParam(prompt, opt);\n assert(locateParam, 'cannot get locate param for aiLocate');\n const locatePlan = locatePlanForLocate(locateParam);\n const plans = [locatePlan];\n const { executor, output } = await this.taskExecutor.runPlans(\n taskTitleStr('Locate', locateParamStr(locateParam)),\n plans,\n );\n await this.afterTaskRunning(executor);\n\n const { element } = output;\n\n return {\n rect: element?.rect,\n center: element?.center,\n scale: (await this.page.size()).dpr,\n } as Pick<LocateResultElement, 'rect' | 'center'> & {\n scale: number;\n };\n }\n\n async aiAssert(\n assertion: TUserPrompt,\n msg?: string,\n opt?: AgentAssertOpt & InsightExtractOption,\n ) {\n const insightOpt: InsightExtractOption = {\n domIncluded: opt?.domIncluded ?? defaultInsightExtractOption.domIncluded,\n screenshotIncluded:\n opt?.screenshotIncluded ??\n defaultInsightExtractOption.screenshotIncluded,\n returnThought: opt?.returnThought ?? true,\n isWaitForAssert: opt?.isWaitForAssert,\n doNotThrowError: opt?.doNotThrowError,\n };\n\n const { output, executor, thought } = await this.taskExecutor.assert(\n assertion,\n insightOpt,\n );\n await this.afterTaskRunning(executor, true);\n\n const message = output\n ? undefined\n : `Assertion failed: ${msg || assertion}\\nReason: ${\n thought || executor.latestErrorTask()?.error || '(no_reason)'\n }`;\n\n if (opt?.keepRawResponse) {\n return {\n pass: output,\n thought,\n message,\n };\n }\n\n if (!output) {\n throw new Error(message);\n }\n }\n\n async aiWaitFor(assertion: TUserPrompt, opt?: AgentWaitForOpt) {\n const { executor } = await this.taskExecutor.waitFor(assertion, {\n timeoutMs: opt?.timeoutMs || 15 * 1000,\n checkIntervalMs: opt?.checkIntervalMs || 3 * 1000,\n });\n await this.afterTaskRunning(executor, true);\n\n if (executor.isInErrorState()) {\n const errorTask = executor.latestErrorTask();\n throw new Error(`${errorTask?.error}\\n${errorTask?.errorStack}`);\n }\n }\n\n async ai(taskPrompt: string, type = 'action') {\n if (type === 'action') {\n return this.aiAction(taskPrompt);\n }\n if (type === 'query') {\n return this.aiQuery(taskPrompt);\n }\n\n if (type === 'assert') {\n return this.aiAssert(taskPrompt);\n }\n\n if (type === 'tap') {\n return this.aiTap(taskPrompt);\n }\n\n if (type === 'rightClick') {\n return this.aiRightClick(taskPrompt);\n }\n\n throw new Error(\n `Unknown type: ${type}, only support 'action', 'query', 'assert', 'tap', 'rightClick'`,\n );\n }\n\n async runYaml(yamlScriptContent: string): Promise<{\n result: Record<string, any>;\n }> {\n const script = parseYamlScript(yamlScriptContent, 'yaml', true);\n const player = new ScriptPlayer(script, async (target) => {\n return { agent: this, freeFn: [] };\n });\n await player.run();\n\n if (player.status === 'error') {\n const errors = player.taskStatusList\n .filter((task) => task.status === 'error')\n .map((task) => {\n return `task - ${task.name}: ${task.error?.message}`;\n })\n .join('\\n');\n throw new Error(`Error(s) occurred in running yaml script:\\n${errors}`);\n }\n\n return {\n result: player.result,\n };\n }\n\n async evaluateJavaScript(script: string) {\n assert(\n this.page.evaluateJavaScript,\n 'evaluateJavaScript is not supported in current agent',\n );\n return this.page.evaluateJavaScript(script);\n }\n\n async destroy() {\n await this.page.destroy();\n this.resetDump(); // reset dump to release memory\n this.destroyed = true;\n }\n\n async logScreenshot(\n title?: string,\n opt?: {\n content: string;\n },\n ) {\n // 1. screenshot\n const base64 = await this.page.screenshotBase64();\n const now = Date.now();\n // 2. build recorder\n const recorder: ExecutionRecorderItem[] = [\n {\n type: 'screenshot',\n ts: now,\n screenshot: base64,\n },\n ];\n // 3. build ExecutionTaskLog\n const task: ExecutionTaskLog = {\n type: 'Log',\n subType: 'Screenshot',\n status: 'finished',\n recorder,\n timing: {\n start: now,\n end: now,\n cost: 0,\n },\n param: {\n content: opt?.content || '',\n },\n executor: async () => {},\n };\n // 4. build ExecutionDump\n const executionDump: ExecutionDump = {\n sdkVersion: '',\n logTime: now,\n name: `Log - ${title || 'untitled'}`,\n description: opt?.content || '',\n tasks: [task],\n };\n // 5. append to execution dump\n this.appendExecutionDump(executionDump);\n\n try {\n this.onDumpUpdate?.(this.dumpDataString());\n } catch (error) {\n console.error('Failed to update dump', error);\n }\n\n this.writeOutActionDumps();\n }\n\n _unstableLogContent() {\n const { groupName, groupDescription, executions } = this.dump;\n const newExecutions = Array.isArray(executions)\n ? executions.map((execution: any) => {\n const { tasks, ...restExecution } = execution;\n let newTasks = tasks;\n if (Array.isArray(tasks)) {\n newTasks = tasks.map((task: any) => {\n // only remove pageContext and log from task\n const { pageContext, log, ...restTask } = task;\n return restTask;\n });\n }\n return { ...restExecution, ...(newTasks ? { tasks: newTasks } : {}) };\n })\n : [];\n return {\n groupName,\n groupDescription,\n executions: newExecutions,\n };\n }\n\n /**\n * Freezes the current page context to be reused in subsequent AI operations\n * This avoids recalculating page context for each operation\n */\n async freezePageContext(): Promise<void> {\n debug('Freezing page context');\n const context = await this._snapshotContext();\n // Mark the context as frozen\n context._isFrozen = true;\n this.frozenPageContext = context;\n debug('Page context frozen successfully');\n }\n\n /**\n * Unfreezes the page context, allowing AI operations to calculate context dynamically\n */\n async unfreezePageContext(): Promise<void> {\n debug('Unfreezing page context');\n this.frozenPageContext = undefined;\n debug('Page context unfrozen successfully');\n }\n}\n"],"names":["debug","getDebug","distanceOfTwoPoints","p1","p2","x1","y1","x2","y2","Math","includedInRect","point","rect","x","y","left","top","width","height","defaultInsightExtractOption","Agent","action","commonContextParser","prompt","execution","trimmedExecution","trimContextByViewport","currentDump","stringifyDumpData","reportHTMLContent","Error","generateReport","autoPrintReportMsg","writeLogFile","groupedActionDumpFileExt","printReportMsg","task","param","paramStr","tip","typeStr","executor","doNotThrowError","_this","error","console","errorTask","type","opt","actionPlan","plans","Boolean","title","taskTitleStr","locateParamStr","output","locatePrompt","assert","detailedLocateParam","buildDetailedLocateParam","locatePromptOrValue","locatePromptOrOpt","optOrUndefined","value","optWithValue","locatePromptOrKeyName","keyName","undefined","locatePromptOrScrollParam","scrollParam","taskPrompt","_this_taskCache","_this_taskCache1","modelPreferences","cacheable","isVlmUiTars","vlLocateMode","matchedCache","_matchedCache_cacheContent","_matchedCache_cacheContent1","yaml","yamlContent","yamlFlowStr","demand","textPrompt","multimodalPrompt","parsePrompt","center","verifyPrompt","retryLimit","success","retryCount","resultPrompt","deepThink","verifyResult","text","locateOpt","expectCenter","verifyLocateOption","verifyCenter","verifyRect","distance","included","pass","locateParam","locatePlan","locatePlanForLocate","element","assertion","msg","_executor_latestErrorTask","insightOpt","thought","message","yamlScriptContent","script","parseYamlScript","player","ScriptPlayer","target","errors","_task_error","base64","now","Date","recorder","executionDump","groupName","groupDescription","executions","newExecutions","Array","tasks","restExecution","newTasks","pageContext","log","restTask","context","page","opts","Object","globalConfigManager","Insight","TaskCache","MIDSCENE_CACHE","PageTaskExecutor","getReportFileName"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { isDeepStrictEqual } from "node:util";
5
5
  import { getMidsceneRunSubDir } from "@midscene/shared/common";
6
- import { MIDSCENE_CACHE_MAX_FILENAME_LENGTH, getAIConfigInNumber } from "@midscene/shared/env";
6
+ import { MIDSCENE_CACHE_MAX_FILENAME_LENGTH, globalConfigManager } from "@midscene/shared/env";
7
7
  import { getDebug } from "@midscene/shared/logger";
8
8
  import { generateHashId, ifInBrowser, ifInWorker, replaceIllegalPathCharsAndSpace } from "@midscene/shared/utils";
9
9
  import js_yaml from "js-yaml";
@@ -124,7 +124,7 @@ class TaskCache {
124
124
  _define_property(this, "matchedCacheIndices", new Set());
125
125
  node_assert(cacheId, 'cacheId is required');
126
126
  let safeCacheId = replaceIllegalPathCharsAndSpace(cacheId);
127
- const cacheMaxFilenameLength = getAIConfigInNumber(MIDSCENE_CACHE_MAX_FILENAME_LENGTH) || DEFAULT_CACHE_MAX_FILENAME_LENGTH;
127
+ const cacheMaxFilenameLength = globalConfigManager.getEnvConfigInNumber(MIDSCENE_CACHE_MAX_FILENAME_LENGTH) || DEFAULT_CACHE_MAX_FILENAME_LENGTH;
128
128
  if (Buffer.byteLength(safeCacheId, 'utf8') > cacheMaxFilenameLength) {
129
129
  const prefix = safeCacheId.slice(0, 32);
130
130
  const hash = generateHashId(void 0, safeCacheId);
@@ -1 +1 @@
1
- {"version":3,"file":"agent/task-cache.mjs","sources":["webpack://@midscene/core/./src/agent/task-cache.ts"],"sourcesContent":["import assert from 'node:assert';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { isDeepStrictEqual } from 'node:util';\nimport type { TUserPrompt } from '@/index';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport {\n MIDSCENE_CACHE_MAX_FILENAME_LENGTH,\n getAIConfigInNumber,\n} from '@midscene/shared/env';\nimport { getDebug } from '@midscene/shared/logger';\nimport { ifInBrowser, ifInWorker } from '@midscene/shared/utils';\nimport { generateHashId } from '@midscene/shared/utils';\nimport { replaceIllegalPathCharsAndSpace } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\nimport semver from 'semver';\nimport { getMidsceneVersion } from './utils';\n\nconst DEFAULT_CACHE_MAX_FILENAME_LENGTH = 200;\n\nexport const debug = getDebug('cache');\n\nexport interface PlanningCache {\n type: 'plan';\n prompt: string;\n yamlWorkflow: string;\n}\n\nexport interface LocateCache {\n type: 'locate';\n prompt: TUserPrompt;\n xpaths: string[];\n}\n\nexport interface MatchCacheResult<T extends PlanningCache | LocateCache> {\n cacheContent: T;\n updateFn: (cb: (cache: T) => void) => void;\n}\n\nexport type CacheFileContent = {\n midsceneVersion: string;\n cacheId: string;\n caches: Array<PlanningCache | LocateCache>;\n};\n\nconst lowestSupportedMidsceneVersion = '0.16.10';\nexport const cacheFileExt = '.cache.yaml';\n\nexport class TaskCache {\n cacheId: string;\n\n cacheFilePath?: string;\n\n cache: CacheFileContent;\n\n isCacheResultUsed: boolean; // a flag to indicate if the cache result should be used\n cacheOriginalLength: number;\n\n private matchedCacheIndices: Set<string> = new Set(); // Track matched records\n\n constructor(\n cacheId: string,\n isCacheResultUsed: boolean,\n cacheFilePath?: string,\n ) {\n assert(cacheId, 'cacheId is required');\n let safeCacheId = replaceIllegalPathCharsAndSpace(cacheId);\n const cacheMaxFilenameLength =\n getAIConfigInNumber(MIDSCENE_CACHE_MAX_FILENAME_LENGTH) ||\n DEFAULT_CACHE_MAX_FILENAME_LENGTH;\n if (Buffer.byteLength(safeCacheId, 'utf8') > cacheMaxFilenameLength) {\n const prefix = safeCacheId.slice(0, 32);\n const hash = generateHashId(undefined, safeCacheId);\n safeCacheId = `${prefix}-${hash}`;\n }\n this.cacheId = safeCacheId;\n\n this.cacheFilePath =\n ifInBrowser || ifInWorker\n ? undefined\n : cacheFilePath ||\n join(getMidsceneRunSubDir('cache'), `${this.cacheId}${cacheFileExt}`);\n this.isCacheResultUsed = isCacheResultUsed;\n\n let cacheContent;\n if (this.cacheFilePath) {\n cacheContent = this.loadCacheFromFile();\n }\n if (!cacheContent) {\n cacheContent = {\n midsceneVersion: getMidsceneVersion(),\n cacheId: this.cacheId,\n caches: [],\n };\n }\n this.cache = cacheContent;\n this.cacheOriginalLength = this.cache.caches.length;\n }\n\n matchCache(\n prompt: TUserPrompt,\n type: 'plan' | 'locate',\n ): MatchCacheResult<PlanningCache | LocateCache> | undefined {\n // Find the first unused matching cache\n for (let i = 0; i < this.cacheOriginalLength; i++) {\n const item = this.cache.caches[i];\n const promptStr =\n typeof prompt === 'string' ? prompt : JSON.stringify(prompt);\n const key = `${type}:${promptStr}:${i}`;\n if (\n item.type === type &&\n isDeepStrictEqual(item.prompt, prompt) &&\n !this.matchedCacheIndices.has(key)\n ) {\n this.matchedCacheIndices.add(key);\n debug(\n 'cache found and marked as used, type: %s, prompt: %s, index: %d',\n type,\n prompt,\n i,\n );\n return {\n cacheContent: item,\n updateFn: (cb: (cache: PlanningCache | LocateCache) => void) => {\n debug(\n 'will call updateFn to update cache, type: %s, prompt: %s, index: %d',\n type,\n prompt,\n i,\n );\n cb(item);\n debug(\n 'cache updated, will flush to file, type: %s, prompt: %s, index: %d',\n type,\n prompt,\n i,\n );\n this.flushCacheToFile();\n },\n };\n }\n }\n debug('no unused cache found, type: %s, prompt: %s', type, prompt);\n return undefined;\n }\n\n matchPlanCache(prompt: string): MatchCacheResult<PlanningCache> | undefined {\n return this.matchCache(prompt, 'plan') as\n | MatchCacheResult<PlanningCache>\n | undefined;\n }\n\n matchLocateCache(\n prompt: TUserPrompt,\n ): MatchCacheResult<LocateCache> | undefined {\n return this.matchCache(prompt, 'locate') as\n | MatchCacheResult<LocateCache>\n | undefined;\n }\n\n appendCache(cache: PlanningCache | LocateCache) {\n debug('will append cache', cache);\n this.cache.caches.push(cache);\n this.flushCacheToFile();\n }\n\n loadCacheFromFile() {\n const cacheFile = this.cacheFilePath;\n assert(cacheFile, 'cache file path is required');\n\n if (!existsSync(cacheFile)) {\n debug('no cache file found, path: %s', cacheFile);\n return undefined;\n }\n\n // detect old cache file\n const jsonTypeCacheFile = cacheFile.replace(cacheFileExt, '.json');\n if (existsSync(jsonTypeCacheFile) && this.isCacheResultUsed) {\n console.warn(\n `An outdated cache file from an earlier version of Midscene has been detected. Since version 0.17, we have implemented an improved caching strategy. Please delete the old file located at: ${jsonTypeCacheFile}.`,\n );\n return undefined;\n }\n\n try {\n const data = readFileSync(cacheFile, 'utf8');\n const jsonData = yaml.load(data) as CacheFileContent;\n\n const version = getMidsceneVersion();\n if (!version) {\n debug('no midscene version info, will not read cache from file');\n return undefined;\n }\n\n if (\n semver.lt(jsonData.midsceneVersion, lowestSupportedMidsceneVersion) &&\n !jsonData.midsceneVersion.includes('beta') // for internal test\n ) {\n console.warn(\n `You are using an old version of Midscene cache file, and we cannot match any info from it. Starting from Midscene v0.17, we changed our strategy to use xpath for cache info, providing better performance.\\nPlease delete the existing cache and rebuild it. Sorry for the inconvenience.\\ncache file: ${cacheFile}`,\n );\n return undefined;\n }\n\n debug(\n 'cache loaded from file, path: %s, cache version: %s, record length: %s',\n cacheFile,\n jsonData.midsceneVersion,\n jsonData.caches.length,\n );\n jsonData.midsceneVersion = getMidsceneVersion(); // update the version\n return jsonData;\n } catch (err) {\n debug(\n 'cache file exists but load failed, path: %s, error: %s',\n cacheFile,\n err,\n );\n return undefined;\n }\n }\n\n flushCacheToFile() {\n const version = getMidsceneVersion();\n if (!version) {\n debug('no midscene version info, will not write cache to file');\n return;\n }\n\n if (!this.cacheFilePath) {\n debug('no cache file path, will not write cache to file');\n return;\n }\n\n try {\n const dir = dirname(this.cacheFilePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n debug('created cache directory: %s', dir);\n }\n\n // Sort caches to ensure plan entries come before locate entries for better readability\n const sortedCaches = [...this.cache.caches].sort((a, b) => {\n if (a.type === 'plan' && b.type === 'locate') return -1;\n if (a.type === 'locate' && b.type === 'plan') return 1;\n return 0;\n });\n\n const cacheToWrite = {\n ...this.cache,\n caches: sortedCaches,\n };\n\n const yamlData = yaml.dump(cacheToWrite);\n writeFileSync(this.cacheFilePath, yamlData);\n debug('cache flushed to file: %s', this.cacheFilePath);\n } catch (err) {\n debug(\n 'write cache to file failed, path: %s, error: %s',\n this.cacheFilePath,\n err,\n );\n }\n }\n\n updateOrAppendCacheRecord(\n newRecord: PlanningCache | LocateCache,\n cachedRecord?: MatchCacheResult<PlanningCache | LocateCache>,\n ) {\n if (cachedRecord) {\n // update existing record\n if (newRecord.type === 'plan') {\n cachedRecord.updateFn((cache) => {\n (cache as PlanningCache).yamlWorkflow = newRecord.yamlWorkflow;\n });\n } else {\n cachedRecord.updateFn((cache) => {\n (cache as LocateCache).xpaths = newRecord.xpaths;\n });\n }\n } else {\n this.appendCache(newRecord);\n }\n }\n}\n"],"names":["DEFAULT_CACHE_MAX_FILENAME_LENGTH","debug","getDebug","lowestSupportedMidsceneVersion","cacheFileExt","TaskCache","prompt","type","i","item","promptStr","JSON","key","isDeepStrictEqual","cb","cache","cacheFile","assert","existsSync","jsonTypeCacheFile","console","data","readFileSync","jsonData","yaml","version","getMidsceneVersion","semver","err","dir","dirname","mkdirSync","sortedCaches","a","b","cacheToWrite","yamlData","writeFileSync","newRecord","cachedRecord","cacheId","isCacheResultUsed","cacheFilePath","Set","safeCacheId","replaceIllegalPathCharsAndSpace","cacheMaxFilenameLength","getAIConfigInNumber","MIDSCENE_CACHE_MAX_FILENAME_LENGTH","Buffer","prefix","hash","generateHashId","undefined","ifInBrowser","ifInWorker","join","getMidsceneRunSubDir","cacheContent"],"mappings":"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"}
1
+ {"version":3,"file":"agent/task-cache.mjs","sources":["webpack://@midscene/core/./src/agent/task-cache.ts"],"sourcesContent":["import assert from 'node:assert';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { isDeepStrictEqual } from 'node:util';\nimport type { TUserPrompt } from '@/index';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport {\n MIDSCENE_CACHE_MAX_FILENAME_LENGTH,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { getDebug } from '@midscene/shared/logger';\nimport { ifInBrowser, ifInWorker } from '@midscene/shared/utils';\nimport { generateHashId } from '@midscene/shared/utils';\nimport { replaceIllegalPathCharsAndSpace } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\nimport semver from 'semver';\nimport { getMidsceneVersion } from './utils';\n\nconst DEFAULT_CACHE_MAX_FILENAME_LENGTH = 200;\n\nexport const debug = getDebug('cache');\n\nexport interface PlanningCache {\n type: 'plan';\n prompt: string;\n yamlWorkflow: string;\n}\n\nexport interface LocateCache {\n type: 'locate';\n prompt: TUserPrompt;\n xpaths: string[];\n}\n\nexport interface MatchCacheResult<T extends PlanningCache | LocateCache> {\n cacheContent: T;\n updateFn: (cb: (cache: T) => void) => void;\n}\n\nexport type CacheFileContent = {\n midsceneVersion: string;\n cacheId: string;\n caches: Array<PlanningCache | LocateCache>;\n};\n\nconst lowestSupportedMidsceneVersion = '0.16.10';\nexport const cacheFileExt = '.cache.yaml';\n\nexport class TaskCache {\n cacheId: string;\n\n cacheFilePath?: string;\n\n cache: CacheFileContent;\n\n isCacheResultUsed: boolean; // a flag to indicate if the cache result should be used\n cacheOriginalLength: number;\n\n private matchedCacheIndices: Set<string> = new Set(); // Track matched records\n\n constructor(\n cacheId: string,\n isCacheResultUsed: boolean,\n cacheFilePath?: string,\n ) {\n assert(cacheId, 'cacheId is required');\n let safeCacheId = replaceIllegalPathCharsAndSpace(cacheId);\n const cacheMaxFilenameLength =\n globalConfigManager.getEnvConfigInNumber(\n MIDSCENE_CACHE_MAX_FILENAME_LENGTH,\n ) || DEFAULT_CACHE_MAX_FILENAME_LENGTH;\n if (Buffer.byteLength(safeCacheId, 'utf8') > cacheMaxFilenameLength) {\n const prefix = safeCacheId.slice(0, 32);\n const hash = generateHashId(undefined, safeCacheId);\n safeCacheId = `${prefix}-${hash}`;\n }\n this.cacheId = safeCacheId;\n\n this.cacheFilePath =\n ifInBrowser || ifInWorker\n ? undefined\n : cacheFilePath ||\n join(getMidsceneRunSubDir('cache'), `${this.cacheId}${cacheFileExt}`);\n this.isCacheResultUsed = isCacheResultUsed;\n\n let cacheContent;\n if (this.cacheFilePath) {\n cacheContent = this.loadCacheFromFile();\n }\n if (!cacheContent) {\n cacheContent = {\n midsceneVersion: getMidsceneVersion(),\n cacheId: this.cacheId,\n caches: [],\n };\n }\n this.cache = cacheContent;\n this.cacheOriginalLength = this.cache.caches.length;\n }\n\n matchCache(\n prompt: TUserPrompt,\n type: 'plan' | 'locate',\n ): MatchCacheResult<PlanningCache | LocateCache> | undefined {\n // Find the first unused matching cache\n for (let i = 0; i < this.cacheOriginalLength; i++) {\n const item = this.cache.caches[i];\n const promptStr =\n typeof prompt === 'string' ? prompt : JSON.stringify(prompt);\n const key = `${type}:${promptStr}:${i}`;\n if (\n item.type === type &&\n isDeepStrictEqual(item.prompt, prompt) &&\n !this.matchedCacheIndices.has(key)\n ) {\n this.matchedCacheIndices.add(key);\n debug(\n 'cache found and marked as used, type: %s, prompt: %s, index: %d',\n type,\n prompt,\n i,\n );\n return {\n cacheContent: item,\n updateFn: (cb: (cache: PlanningCache | LocateCache) => void) => {\n debug(\n 'will call updateFn to update cache, type: %s, prompt: %s, index: %d',\n type,\n prompt,\n i,\n );\n cb(item);\n debug(\n 'cache updated, will flush to file, type: %s, prompt: %s, index: %d',\n type,\n prompt,\n i,\n );\n this.flushCacheToFile();\n },\n };\n }\n }\n debug('no unused cache found, type: %s, prompt: %s', type, prompt);\n return undefined;\n }\n\n matchPlanCache(prompt: string): MatchCacheResult<PlanningCache> | undefined {\n return this.matchCache(prompt, 'plan') as\n | MatchCacheResult<PlanningCache>\n | undefined;\n }\n\n matchLocateCache(\n prompt: TUserPrompt,\n ): MatchCacheResult<LocateCache> | undefined {\n return this.matchCache(prompt, 'locate') as\n | MatchCacheResult<LocateCache>\n | undefined;\n }\n\n appendCache(cache: PlanningCache | LocateCache) {\n debug('will append cache', cache);\n this.cache.caches.push(cache);\n this.flushCacheToFile();\n }\n\n loadCacheFromFile() {\n const cacheFile = this.cacheFilePath;\n assert(cacheFile, 'cache file path is required');\n\n if (!existsSync(cacheFile)) {\n debug('no cache file found, path: %s', cacheFile);\n return undefined;\n }\n\n // detect old cache file\n const jsonTypeCacheFile = cacheFile.replace(cacheFileExt, '.json');\n if (existsSync(jsonTypeCacheFile) && this.isCacheResultUsed) {\n console.warn(\n `An outdated cache file from an earlier version of Midscene has been detected. Since version 0.17, we have implemented an improved caching strategy. Please delete the old file located at: ${jsonTypeCacheFile}.`,\n );\n return undefined;\n }\n\n try {\n const data = readFileSync(cacheFile, 'utf8');\n const jsonData = yaml.load(data) as CacheFileContent;\n\n const version = getMidsceneVersion();\n if (!version) {\n debug('no midscene version info, will not read cache from file');\n return undefined;\n }\n\n if (\n semver.lt(jsonData.midsceneVersion, lowestSupportedMidsceneVersion) &&\n !jsonData.midsceneVersion.includes('beta') // for internal test\n ) {\n console.warn(\n `You are using an old version of Midscene cache file, and we cannot match any info from it. Starting from Midscene v0.17, we changed our strategy to use xpath for cache info, providing better performance.\\nPlease delete the existing cache and rebuild it. Sorry for the inconvenience.\\ncache file: ${cacheFile}`,\n );\n return undefined;\n }\n\n debug(\n 'cache loaded from file, path: %s, cache version: %s, record length: %s',\n cacheFile,\n jsonData.midsceneVersion,\n jsonData.caches.length,\n );\n jsonData.midsceneVersion = getMidsceneVersion(); // update the version\n return jsonData;\n } catch (err) {\n debug(\n 'cache file exists but load failed, path: %s, error: %s',\n cacheFile,\n err,\n );\n return undefined;\n }\n }\n\n flushCacheToFile() {\n const version = getMidsceneVersion();\n if (!version) {\n debug('no midscene version info, will not write cache to file');\n return;\n }\n\n if (!this.cacheFilePath) {\n debug('no cache file path, will not write cache to file');\n return;\n }\n\n try {\n const dir = dirname(this.cacheFilePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n debug('created cache directory: %s', dir);\n }\n\n // Sort caches to ensure plan entries come before locate entries for better readability\n const sortedCaches = [...this.cache.caches].sort((a, b) => {\n if (a.type === 'plan' && b.type === 'locate') return -1;\n if (a.type === 'locate' && b.type === 'plan') return 1;\n return 0;\n });\n\n const cacheToWrite = {\n ...this.cache,\n caches: sortedCaches,\n };\n\n const yamlData = yaml.dump(cacheToWrite);\n writeFileSync(this.cacheFilePath, yamlData);\n debug('cache flushed to file: %s', this.cacheFilePath);\n } catch (err) {\n debug(\n 'write cache to file failed, path: %s, error: %s',\n this.cacheFilePath,\n err,\n );\n }\n }\n\n updateOrAppendCacheRecord(\n newRecord: PlanningCache | LocateCache,\n cachedRecord?: MatchCacheResult<PlanningCache | LocateCache>,\n ) {\n if (cachedRecord) {\n // update existing record\n if (newRecord.type === 'plan') {\n cachedRecord.updateFn((cache) => {\n (cache as PlanningCache).yamlWorkflow = newRecord.yamlWorkflow;\n });\n } else {\n cachedRecord.updateFn((cache) => {\n (cache as LocateCache).xpaths = newRecord.xpaths;\n });\n }\n } else {\n this.appendCache(newRecord);\n }\n }\n}\n"],"names":["DEFAULT_CACHE_MAX_FILENAME_LENGTH","debug","getDebug","lowestSupportedMidsceneVersion","cacheFileExt","TaskCache","prompt","type","i","item","promptStr","JSON","key","isDeepStrictEqual","cb","cache","cacheFile","assert","existsSync","jsonTypeCacheFile","console","data","readFileSync","jsonData","yaml","version","getMidsceneVersion","semver","err","dir","dirname","mkdirSync","sortedCaches","a","b","cacheToWrite","yamlData","writeFileSync","newRecord","cachedRecord","cacheId","isCacheResultUsed","cacheFilePath","Set","safeCacheId","replaceIllegalPathCharsAndSpace","cacheMaxFilenameLength","globalConfigManager","MIDSCENE_CACHE_MAX_FILENAME_LENGTH","Buffer","prefix","hash","generateHashId","undefined","ifInBrowser","ifInWorker","join","getMidsceneRunSubDir","cacheContent"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { elementByPositionWithElementInfo, findAllMidsceneLocatorField, resizeIm
2
2
  import { Executor, plan as external_index_mjs_plan } from "../index.mjs";
3
3
  import { sleep as external_utils_mjs_sleep } from "../utils.mjs";
4
4
  import { NodeType } from "@midscene/shared/constants";
5
- import { MIDSCENE_REPLANNING_CYCLE_LIMIT, getAIConfigInNumber } from "@midscene/shared/env";
5
+ import { MIDSCENE_REPLANNING_CYCLE_LIMIT, globalConfigManager } from "@midscene/shared/env";
6
6
  import { getDebug } from "@midscene/shared/logger";
7
7
  import { assert } from "@midscene/shared/utils";
8
8
  import { taskTitleStr } from "./ui-utils.mjs";
@@ -510,7 +510,7 @@ class PageTaskExecutor {
510
510
  let replanCount = 0;
511
511
  const logList = [];
512
512
  const yamlFlow = [];
513
- const replanningCycleLimit = getAIConfigInNumber(MIDSCENE_REPLANNING_CYCLE_LIMIT) || defaultReplanningCycleLimit;
513
+ const replanningCycleLimit = globalConfigManager.getEnvConfigInNumber(MIDSCENE_REPLANNING_CYCLE_LIMIT) || defaultReplanningCycleLimit;
514
514
  while(planningTask){
515
515
  if (replanCount > replanningCycleLimit) {
516
516
  const errorMsg = 'Replanning too many times, please split the task into multiple steps';