@midscene/core 1.8.5-beta-20260525120212.0 → 1.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/es/agent/agent.mjs +5 -21
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/task-cache.mjs.map +1 -1
  4. package/dist/es/agent/tasks.mjs +8 -17
  5. package/dist/es/agent/tasks.mjs.map +1 -1
  6. package/dist/es/agent/ui-utils.mjs +1 -2
  7. package/dist/es/agent/ui-utils.mjs.map +1 -1
  8. package/dist/es/agent/utils.mjs +1 -1
  9. package/dist/es/ai-model/auto-glm/planning.mjs +3 -8
  10. package/dist/es/ai-model/auto-glm/planning.mjs.map +1 -1
  11. package/dist/es/ai-model/inspect.mjs +59 -7
  12. package/dist/es/ai-model/inspect.mjs.map +1 -1
  13. package/dist/es/ai-model/llm-planning.mjs +3 -6
  14. package/dist/es/ai-model/llm-planning.mjs.map +1 -1
  15. package/dist/es/ai-model/ui-tars-planning.mjs +2 -6
  16. package/dist/es/ai-model/ui-tars-planning.mjs.map +1 -1
  17. package/dist/es/common.mjs +2 -49
  18. package/dist/es/common.mjs.map +1 -1
  19. package/dist/es/types.mjs.map +1 -1
  20. package/dist/es/utils.mjs +2 -2
  21. package/dist/es/yaml/player.mjs +4 -8
  22. package/dist/es/yaml/player.mjs.map +1 -1
  23. package/dist/lib/agent/agent.js +4 -20
  24. package/dist/lib/agent/agent.js.map +1 -1
  25. package/dist/lib/agent/task-cache.js.map +1 -1
  26. package/dist/lib/agent/tasks.js +7 -16
  27. package/dist/lib/agent/tasks.js.map +1 -1
  28. package/dist/lib/agent/ui-utils.js +2 -3
  29. package/dist/lib/agent/ui-utils.js.map +1 -1
  30. package/dist/lib/agent/utils.js +1 -1
  31. package/dist/lib/ai-model/auto-glm/planning.js +3 -8
  32. package/dist/lib/ai-model/auto-glm/planning.js.map +1 -1
  33. package/dist/lib/ai-model/inspect.js +57 -5
  34. package/dist/lib/ai-model/inspect.js.map +1 -1
  35. package/dist/lib/ai-model/llm-planning.js +3 -6
  36. package/dist/lib/ai-model/llm-planning.js.map +1 -1
  37. package/dist/lib/ai-model/ui-tars-planning.js +2 -6
  38. package/dist/lib/ai-model/ui-tars-planning.js.map +1 -1
  39. package/dist/lib/common.js +10 -66
  40. package/dist/lib/common.js.map +1 -1
  41. package/dist/lib/types.js.map +1 -1
  42. package/dist/lib/utils.js +2 -2
  43. package/dist/lib/yaml/player.js +4 -8
  44. package/dist/lib/yaml/player.js.map +1 -1
  45. package/dist/types/agent/agent.d.ts +4 -4
  46. package/dist/types/agent/task-cache.d.ts +2 -2
  47. package/dist/types/agent/tasks.d.ts +2 -7
  48. package/dist/types/agent/ui-utils.d.ts +1 -2
  49. package/dist/types/ai-model/auto-glm/planning.d.ts +1 -4
  50. package/dist/types/ai-model/llm-planning.d.ts +1 -4
  51. package/dist/types/ai-model/ui-tars-planning.d.ts +1 -4
  52. package/dist/types/common.d.ts +1 -4
  53. package/dist/types/types.d.ts +1 -2
  54. package/dist/types/yaml.d.ts +3 -4
  55. package/package.json +5 -7
  56. package/dist/es/agent/run-markdown.mjs +0 -62
  57. package/dist/es/agent/run-markdown.mjs.map +0 -1
  58. package/dist/lib/agent/run-markdown.js +0 -96
  59. package/dist/lib/agent/run-markdown.js.map +0 -1
  60. package/dist/types/agent/run-markdown.d.ts +0 -6
@@ -7,13 +7,11 @@ import { ReportGenerator, assertReportGenerationOptions } from "../report-genera
7
7
  import { getVersion, processCacheConfig, reportHTMLContent } from "../utils.mjs";
8
8
  import { ScriptPlayer, buildDetailedLocateParam, parseYamlScript } from "../yaml/index.mjs";
9
9
  import { existsSync } from "node:fs";
10
- import { readFile } from "node:fs/promises";
11
- import { basename, resolve as external_node_path_resolve } from "node:path";
10
+ import { resolve as external_node_path_resolve } from "node:path";
12
11
  import { MIDSCENE_REPLANNING_CYCLE_LIMIT, ModelConfigManager, globalConfigManager, globalModelConfigManager } from "@midscene/shared/env";
13
12
  import { getDebug } from "@midscene/shared/logger";
14
13
  import { assert, ifInBrowser, uuid } from "@midscene/shared/utils";
15
14
  import { defineActionSleep } from "../device/index.mjs";
16
- import { markdownToAiActPrompt } from "./run-markdown.mjs";
17
15
  import { TaskCache } from "./task-cache.mjs";
18
16
  import { TaskExecutionError, TaskExecutor, locatePlanForLocate, withFileChooser } from "./tasks.mjs";
19
17
  import { locateParamStr, paramStr, taskTitleStr, typeStr } from "./ui-utils.mjs";
@@ -343,9 +341,6 @@ class Agent {
343
341
  });
344
342
  }
345
343
  async aiAct(taskPrompt, opt) {
346
- const internalReportDisplay = opt?._internalReportDisplay;
347
- const taskPromptText = 'string' == typeof taskPrompt ? taskPrompt : taskPrompt.prompt;
348
- const reportPrompt = internalReportDisplay?.prompt || taskPromptText;
349
344
  const fileChooserAccept = opt?.fileChooserAccept ? this.normalizeFileInput(opt.fileChooserAccept) : void 0;
350
345
  const abortSignal = opt?.abortSignal;
351
346
  if (abortSignal?.aborted) throw new Error(`aiAct aborted: ${abortSignal.reason || 'signal already aborted'}`);
@@ -365,19 +360,19 @@ class Agent {
365
360
  const isAutoGlm = isAutoGLM(modelConfigForPlanning.modelFamily);
366
361
  const matchedCache = isVlmUiTars || isAutoGlm || false === cacheable ? void 0 : this.taskCache?.matchPlanCache(taskPrompt);
367
362
  if (matchedCache?.cacheUsable && this.taskCache?.isCacheResultUsed && matchedCache.cacheContent?.yamlWorkflow?.trim()) {
368
- await this.taskExecutor.loadYamlFlowAsPlanning(taskPrompt, matchedCache.cacheContent.yamlWorkflow, internalReportDisplay);
363
+ await this.taskExecutor.loadYamlFlowAsPlanning(taskPrompt, matchedCache.cacheContent.yamlWorkflow);
369
364
  debug('matched cache, will call .runYaml to run the action');
370
365
  const yaml = matchedCache.cacheContent.yamlWorkflow;
371
366
  await this.runYaml(yaml);
372
367
  return;
373
368
  }
374
369
  const imagesIncludeCount = deepThink ? 2 : 1;
375
- const { output: actionOutput } = await this.taskExecutor.action(taskPrompt, modelConfigForPlanning, this.modelConfigManager.getModelConfig('default'), includeBboxInPlanning, this.aiActContext, cacheable, replanningCycleLimit, imagesIncludeCount, deepThink, fileChooserAccept, deepLocate, abortSignal, internalReportDisplay);
370
+ const { output: actionOutput } = await this.taskExecutor.action(taskPrompt, modelConfigForPlanning, this.modelConfigManager.getModelConfig('default'), includeBboxInPlanning, this.aiActContext, cacheable, replanningCycleLimit, imagesIncludeCount, deepThink, fileChooserAccept, deepLocate, abortSignal);
376
371
  if (this.taskCache && actionOutput?.yamlFlow?.length && false !== cacheable) {
377
372
  const yamlContent = {
378
373
  tasks: [
379
374
  {
380
- name: reportPrompt,
375
+ name: taskPrompt,
381
376
  flow: actionOutput.yamlFlow
382
377
  }
383
378
  ]
@@ -393,17 +388,6 @@ class Agent {
393
388
  };
394
389
  return await runAiAct();
395
390
  }
396
- async runMarkdown(markdownPath, opt) {
397
- const markdown = await readFile(markdownPath, 'utf-8');
398
- const { prompt } = await markdownToAiActPrompt(markdown, markdownPath);
399
- return this.aiAct(prompt, {
400
- ...opt,
401
- _internalReportDisplay: {
402
- type: 'Markdown',
403
- prompt: basename(markdownPath)
404
- }
405
- });
406
- }
407
391
  async aiAction(taskPrompt, opt) {
408
392
  return this.aiAct(taskPrompt, opt);
409
393
  }
@@ -583,7 +567,7 @@ class Agent {
583
567
  this.destroyed = true;
584
568
  }
585
569
  async recordToReport(title, opt) {
586
- const base64 = await this.interface.screenshotBase64();
570
+ const base64 = opt?.screenshotBase64 ?? await this.interface.screenshotBase64();
587
571
  const now = Date.now();
588
572
  const screenshot = ScreenshotItem.create(base64, now);
589
573
  const recorder = [
@@ -1 +1 @@
1
- {"version":3,"file":"agent/agent.mjs","sources":["../../../src/agent/agent.ts"],"sourcesContent":["import { isAutoGLM, isUITars } from '@/ai-model/auto-glm/util';\nimport yaml from 'js-yaml';\nimport type { TUserPrompt } from '../ai-model/index';\nimport { ScreenshotItem } from '../screenshot-item';\nimport Service from '../service/index';\n// Import types and values directly from their source files to avoid circular dependency\n// DO NOT import from '../index' as it creates a circular dependency:\n// index.ts -> agent/index.ts -> agent/agent.ts -> index.ts\nimport {\n type ActionParam,\n type ActionReturn,\n type AgentAssertOpt,\n type AgentDescribeElementAtPointResult,\n type AgentOpt,\n type AgentWaitForOpt,\n type CacheConfig,\n type DeepThinkOption,\n type DeviceAction,\n ExecutionDump,\n type ExecutionRecorderItem,\n type ExecutionTask,\n type ExecutionTaskLog,\n type LocateOption,\n type LocateResultElement,\n type LocateValidatorResult,\n type LocatorValidatorOption,\n type OnTaskStartTip,\n type PlanningAction,\n type Rect,\n ReportActionDump,\n type ReportMeta,\n type ScrollParam,\n type ServiceAction,\n type ServiceExtractOption,\n type ServiceExtractParam,\n type TestStatus,\n type UIContext,\n} from '../types';\nimport type { MidsceneYamlScript } from '../yaml';\n\nimport type { IReportGenerator } from '@/report-generator';\nimport {\n ReportGenerator,\n assertReportGenerationOptions,\n} from '@/report-generator';\nimport { getVersion, processCacheConfig, reportHTMLContent } from '@/utils';\nimport {\n ScriptPlayer,\n buildDetailedLocateParam,\n parseYamlScript,\n} from '../yaml/index';\n\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport type { AbstractInterface } from '@/device';\nimport type { TaskRunner } from '@/task-runner';\nimport {\n type IModelConfig,\n MIDSCENE_REPLANNING_CYCLE_LIMIT,\n ModelConfigManager,\n globalConfigManager,\n globalModelConfigManager,\n} from '@midscene/shared/env';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser, uuid } from '@midscene/shared/utils';\nimport { defineActionSleep } from '../device';\nimport { markdownToAiActPrompt } from './run-markdown';\nimport { TaskCache } from './task-cache';\nimport {\n TaskExecutionError,\n TaskExecutor,\n locatePlanForLocate,\n withFileChooser,\n} from './tasks';\nimport {\n type TaskTitleType,\n locateParamStr,\n paramStr,\n taskTitleStr,\n typeStr,\n} from './ui-utils';\nimport { commonContextParser, getReportFileName, parsePrompt } 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 defaultServiceExtractOption: ServiceExtractOption = {\n domIncluded: false,\n screenshotIncluded: true,\n};\n\ntype CacheStrategy = NonNullable<CacheConfig['strategy']>;\n\nconst CACHE_STRATEGIES: readonly CacheStrategy[] = [\n 'read-only',\n 'read-write',\n 'write-only',\n];\n\nconst isValidCacheStrategy = (strategy: string): strategy is CacheStrategy =>\n CACHE_STRATEGIES.some((value) => value === strategy);\n\nconst CACHE_STRATEGY_VALUES = CACHE_STRATEGIES.map(\n (value) => `\"${value}\"`,\n).join(', ');\n\nconst legacyScrollTypeMap = {\n once: 'singleAction',\n untilBottom: 'scrollToBottom',\n untilTop: 'scrollToTop',\n untilRight: 'scrollToRight',\n untilLeft: 'scrollToLeft',\n} as const;\n\ntype LegacyScrollType = keyof typeof legacyScrollTypeMap;\n\nconst normalizeScrollType = (\n scrollType: ScrollParam['scrollType'] | LegacyScrollType | undefined,\n): ScrollParam['scrollType'] | undefined => {\n if (!scrollType) {\n return scrollType;\n }\n\n if (scrollType in legacyScrollTypeMap) {\n return legacyScrollTypeMap[scrollType as LegacyScrollType];\n }\n\n return scrollType as ScrollParam['scrollType'];\n};\n\nconst defaultReplanningCycleLimit = 20;\nconst defaultVlmUiTarsReplanningCycleLimit = 40;\nconst defaultAutoGlmReplanningCycleLimit = 100;\n\nexport type AiActOptions = {\n cacheable?: boolean;\n fileChooserAccept?: string | string[];\n deepThink?: DeepThinkOption;\n deepLocate?: boolean;\n abortSignal?: AbortSignal;\n};\n\ntype AiActInternalOptions = AiActOptions & {\n _internalReportDisplay?: {\n type?: TaskTitleType;\n prompt?: string;\n };\n};\n\nexport class Agent<\n InterfaceType extends AbstractInterface = AbstractInterface,\n> {\n interface: InterfaceType;\n\n service: Service;\n\n dump: ReportActionDump;\n\n reportFile?: string | null;\n\n reportFileName?: string;\n\n taskExecutor: TaskExecutor;\n\n opts: AgentOpt;\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 private dumpUpdateListeners: Array<\n (dump: string, executionDump?: ExecutionDump) => void\n > = [];\n\n get onDumpUpdate():\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined {\n return this.dumpUpdateListeners[0];\n }\n\n set onDumpUpdate(callback:\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined) {\n // Clear existing listeners\n this.dumpUpdateListeners = [];\n // Add callback to array if provided\n if (callback) {\n this.dumpUpdateListeners.push(callback);\n }\n }\n\n destroyed = false;\n\n modelConfigManager: ModelConfigManager;\n\n /**\n * Frozen page context for consistent AI operations\n */\n private frozenUIContext?: UIContext;\n\n private get aiActContext(): string | undefined {\n return this.opts.aiActContext ?? this.opts.aiActionContext;\n }\n\n /**\n * Flag to track if VL model warning has been shown\n */\n private hasWarnedNonVLModel = false;\n\n private executionDumpIndexByRunner = new WeakMap<TaskRunner, number>();\n\n private fullActionSpace: DeviceAction[];\n\n private reportGenerator: IReportGenerator;\n\n // @deprecated use .interface instead\n get page() {\n return this.interface;\n }\n\n /**\n * Ensures VL model warning is shown once when needed\n */\n private ensureVLModelWarning() {\n if (\n !this.hasWarnedNonVLModel &&\n this.interface.interfaceType !== 'puppeteer' &&\n this.interface.interfaceType !== 'playwright' &&\n this.interface.interfaceType !== 'static' &&\n this.interface.interfaceType !== 'chrome-extension-proxy' &&\n this.interface.interfaceType !== 'page-over-chrome-extension-bridge'\n ) {\n this.modelConfigManager.throwErrorIfNonVLModel();\n this.hasWarnedNonVLModel = true;\n }\n }\n\n private resolveReplanningCycleLimit(\n modelConfigForPlanning: IModelConfig,\n ): number {\n if (this.opts.replanningCycleLimit !== undefined) {\n return this.opts.replanningCycleLimit;\n }\n\n return isUITars(modelConfigForPlanning.modelFamily)\n ? defaultVlmUiTarsReplanningCycleLimit\n : isAutoGLM(modelConfigForPlanning.modelFamily)\n ? defaultAutoGlmReplanningCycleLimit\n : defaultReplanningCycleLimit;\n }\n\n constructor(interfaceInstance: InterfaceType, opts?: AgentOpt) {\n this.interface = interfaceInstance;\n\n const envReplanningCycleLimit =\n globalConfigManager.getEnvConfigValueAsNumber(\n MIDSCENE_REPLANNING_CYCLE_LIMIT,\n );\n\n this.opts = Object.assign(\n {\n generateReport: true,\n persistExecutionDump: false,\n autoPrintReportMsg: true,\n groupName: 'Midscene Report',\n groupDescription: '',\n },\n opts || {},\n opts?.replanningCycleLimit === undefined &&\n envReplanningCycleLimit !== undefined &&\n !Number.isNaN(envReplanningCycleLimit)\n ? { replanningCycleLimit: envReplanningCycleLimit }\n : {},\n );\n assertReportGenerationOptions(this.opts);\n\n const resolvedAiActContext =\n this.opts.aiActContext ?? this.opts.aiActionContext;\n if (resolvedAiActContext !== undefined) {\n this.opts.aiActContext = resolvedAiActContext;\n this.opts.aiActionContext ??= resolvedAiActContext;\n }\n\n if (\n opts?.modelConfig &&\n (typeof opts?.modelConfig !== 'object' || Array.isArray(opts.modelConfig))\n ) {\n throw new Error(\n `opts.modelConfig must be a plain object map of env keys to values, but got ${typeof opts?.modelConfig}`,\n );\n }\n // Create ModelConfigManager if modelConfig or createOpenAIClient is provided\n // Otherwise, use the global config manager\n const hasCustomConfig = opts?.modelConfig || opts?.createOpenAIClient;\n this.modelConfigManager = hasCustomConfig\n ? new ModelConfigManager(opts?.modelConfig, opts?.createOpenAIClient)\n : globalModelConfigManager;\n\n this.onTaskStartTip = this.opts.onTaskStartTip;\n\n this.service = new Service(async () => {\n return this.getUIContext();\n });\n\n // Process cache configuration\n const cacheConfigObj = this.processCacheConfig(opts || {});\n if (cacheConfigObj) {\n this.taskCache = new TaskCache(\n cacheConfigObj.id,\n cacheConfigObj.enabled,\n undefined, // cacheFilePath\n {\n readOnly: cacheConfigObj.readOnly,\n writeOnly: cacheConfigObj.writeOnly,\n },\n );\n }\n\n const baseActionSpace = this.interface.actionSpace();\n this.fullActionSpace = [...baseActionSpace, defineActionSleep()];\n\n this.taskExecutor = new TaskExecutor(this.interface, this.service, {\n taskCache: this.taskCache,\n onTaskStart: this.callbackOnTaskStartTip.bind(this),\n replanningCycleLimit: this.opts.replanningCycleLimit,\n waitAfterAction: this.opts.waitAfterAction,\n useDeviceTime: this.opts.useDeviceTime,\n actionSpace: this.fullActionSpace,\n hooks: {\n onTaskUpdate: async (runner) => {\n const executionDump = runner.dump();\n this.appendExecutionDump(executionDump, runner);\n\n // Persist report updates before notifying listeners so screenshot\n // payloads can be released from memory and serialized as references.\n this.writeOutActionDumps(executionDump);\n await this.reportGenerator.flush();\n\n // Call all registered dump update listeners\n const dumpString = this.dumpDataString();\n for (const listener of this.dumpUpdateListeners) {\n try {\n listener(dumpString, executionDump);\n } catch (error) {\n console.error('Error in onDumpUpdate listener', error);\n }\n }\n },\n },\n });\n this.dump = this.resetDump();\n this.reportFileName =\n opts?.reportFileName ||\n // Keep deprecated testId behavior for generated report names until it is\n // fully removed from the public API.\n getReportFileName(opts?.testId || this.interface.interfaceType || 'web');\n\n this.reportGenerator = ReportGenerator.create(this.reportFileName!, {\n generateReport: this.opts.generateReport,\n persistExecutionDump: this.opts.persistExecutionDump,\n outputFormat: this.opts.outputFormat,\n autoPrintReportMsg: this.opts.autoPrintReportMsg,\n reuseExistingReport:\n this.opts.reportAttributes?.['data-group-id'] === this.reportFileName,\n });\n }\n\n async getActionSpace(): Promise<DeviceAction[]> {\n return this.fullActionSpace;\n }\n\n private static readonly CONTEXT_RETRY_MAX = 3;\n private static readonly CONTEXT_RETRY_DELAY_MS = 1500;\n\n /**\n * Override in subclasses to indicate which errors are transient and should\n * trigger an automatic retry when building the UI context.\n * Returns `false` by default (no retry).\n */\n protected isRetryableContextError(_error: unknown): boolean {\n return false;\n }\n\n async getUIContext(action?: ServiceAction): Promise<UIContext> {\n // Check VL model configuration when UI context is first needed\n this.ensureVLModelWarning();\n\n // If page context is frozen, return the frozen context for all actions\n if (this.frozenUIContext) {\n debug('Using frozen page context for action:', action);\n return this.frozenUIContext;\n }\n\n const { modelFamily } = this.modelConfigManager.getModelConfig('default');\n\n const maxRetries = Agent.CONTEXT_RETRY_MAX;\n for (let attempt = 0; ; attempt++) {\n try {\n return await commonContextParser(this.interface, {\n uploadServerUrl: this.modelConfigManager.getUploadTestServerUrl(),\n screenshotShrinkFactor: this.opts.screenshotShrinkFactor,\n modelFamily,\n });\n } catch (error) {\n if (attempt < maxRetries && this.isRetryableContextError(error)) {\n debug(\n `retryable context error (attempt ${attempt + 1}/${maxRetries}), retrying in ${Agent.CONTEXT_RETRY_DELAY_MS}ms: ${error}`,\n );\n await new Promise((resolve) =>\n setTimeout(resolve, Agent.CONTEXT_RETRY_DELAY_MS),\n );\n continue;\n }\n throw error;\n }\n }\n }\n\n async _snapshotContext(): Promise<UIContext> {\n return await this.getUIContext('locate');\n }\n\n /**\n * @deprecated Use {@link setAIActContext} instead.\n */\n async setAIActionContext(prompt: string) {\n await this.setAIActContext(prompt);\n }\n\n async setAIActContext(prompt: string) {\n if (this.aiActContext) {\n console.warn(\n 'aiActContext is already set, and it is called again, will override the previous setting',\n );\n }\n this.opts.aiActContext = prompt;\n this.opts.aiActionContext = prompt;\n }\n\n resetDump() {\n this.dump = new ReportActionDump({\n sdkVersion: getVersion(),\n groupName: this.opts.groupName!,\n groupDescription: this.opts.groupDescription,\n executions: [],\n modelBriefs: [],\n deviceType: this.interface.interfaceType,\n });\n this.executionDumpIndexByRunner = new WeakMap<TaskRunner, number>();\n\n return this.dump;\n }\n\n appendExecutionDump(execution: ExecutionDump, runner?: TaskRunner) {\n const currentDump = this.dump;\n if (runner) {\n const existingIndex = this.executionDumpIndexByRunner.get(runner);\n if (existingIndex !== undefined) {\n currentDump.executions[existingIndex] = execution;\n return;\n }\n currentDump.executions.push(execution);\n this.executionDumpIndexByRunner.set(\n runner,\n currentDump.executions.length - 1,\n );\n return;\n }\n currentDump.executions.push(execution);\n }\n\n dumpDataString(opt?: { inlineScreenshots?: boolean }) {\n // update dump info\n this.dump.groupName = this.opts.groupName!;\n this.dump.groupDescription = this.opts.groupDescription;\n // In browser environment, use inline screenshots since file system is not available\n if (ifInBrowser || opt?.inlineScreenshots) {\n return this.dump.serializeWithInlineScreenshots();\n }\n return this.dump.serialize();\n }\n\n reportHTMLString(opt?: { inlineScreenshots?: boolean }) {\n // dumpDataString() handles browser environment with inline screenshots\n return reportHTMLContent(this.dumpDataString(opt));\n }\n\n private lastExecutionDump?: ExecutionDump;\n\n writeOutActionDumps(executionDump?: ExecutionDump) {\n const exec = executionDump || this.lastExecutionDump;\n if (exec) {\n this.lastExecutionDump = exec;\n this.reportGenerator.onExecutionUpdate(\n exec,\n this.getReportMeta(),\n this.opts.reportAttributes,\n );\n }\n this.reportFile = this.reportGenerator.getReportPath();\n }\n\n private getReportMeta(): ReportMeta {\n return {\n groupName: this.dump.groupName,\n groupDescription: this.dump.groupDescription,\n sdkVersion: this.dump.sdkVersion,\n modelBriefs: this.dump.modelBriefs,\n deviceType: this.dump.deviceType,\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 wrapActionInActionSpace<T extends DeviceAction>(\n name: string,\n ): (param: ActionParam<T>) => Promise<ActionReturn<T>> {\n return async (param: ActionParam<T>) => {\n return await this.callActionInActionSpace<ActionReturn<T>>(name, param);\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);\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 // assume all operation in action space is related to locating\n const defaultIntentModelConfig =\n this.modelConfigManager.getModelConfig('default');\n const modelConfigForPlanning =\n this.modelConfigManager.getModelConfig('planning');\n\n const { output } = await this.taskExecutor.runPlans(\n title,\n plans,\n modelConfigForPlanning,\n defaultIntentModelConfig,\n );\n return output;\n }\n\n async aiTap(\n locatePrompt: TUserPrompt,\n opt?: LocateOption & { fileChooserAccept?: string | string[] },\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for tap');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n const fileChooserAccept = opt?.fileChooserAccept\n ? this.normalizeFileInput(opt.fileChooserAccept)\n : undefined;\n\n await withFileChooser(this.interface, fileChooserAccept, async () => {\n await this.callActionInActionSpace('Tap', {\n locate: detailedLocateParam,\n });\n });\n }\n\n async aiRightClick(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for right click');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await this.callActionInActionSpace('RightClick', {\n locate: detailedLocateParam,\n });\n }\n\n async aiDoubleClick(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for double click');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await this.callActionInActionSpace('DoubleClick', {\n locate: detailedLocateParam,\n });\n }\n\n async aiHover(locatePrompt: TUserPrompt, opt?: LocateOption): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for hover');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await 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 | number } & {\n autoDismissKeyboard?: boolean;\n } & { mode?: 'replace' | 'clear' | 'typeOnly' | 'append' },\n ): Promise<void>;\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 | number,\n locatePrompt: TUserPrompt,\n opt?: LocateOption & { autoDismissKeyboard?: boolean } & {\n mode?: 'replace' | 'clear' | 'typeOnly' | 'append';\n }, // AndroidDeviceInputOpt &\n ): Promise<void>;\n\n // Implementation\n async aiInput(\n locatePromptOrValue: TUserPrompt | string | number,\n locatePromptOrOpt:\n | TUserPrompt\n | (LocateOption & { value: string | number } & {\n autoDismissKeyboard?: boolean;\n } & { mode?: 'replace' | 'clear' | 'typeOnly' | 'append' }) // AndroidDeviceInputOpt &\n | undefined,\n optOrUndefined?: LocateOption, // AndroidDeviceInputOpt &\n ) {\n let value: string | number;\n let locatePrompt: TUserPrompt;\n let opt:\n | (LocateOption & { value: string | number } & {\n autoDismissKeyboard?: boolean;\n } & { mode?: 'replace' | 'clear' | 'typeOnly' | 'append' }) // 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 | number;\n autoDismissKeyboard?: boolean;\n };\n value = optWithValue.value;\n opt = optWithValue;\n } else {\n // Legacy signature: aiInput(value, locatePrompt, opt)\n value = locatePromptOrValue as string | number;\n locatePrompt = locatePromptOrOpt as TUserPrompt;\n opt = {\n ...optOrUndefined,\n value,\n };\n }\n\n assert(\n typeof value === 'string' || typeof value === 'number',\n 'input value must be a string or number, 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 // Convert value to string to ensure consistency\n const stringValue = typeof value === 'number' ? String(value) : value;\n\n // backward compat: convert deprecated 'append' to 'typeOnly'\n const mode = opt?.mode === 'append' ? 'typeOnly' : opt?.mode;\n\n await this.callActionInActionSpace('Input', {\n ...(opt || {}),\n value: stringValue,\n locate: detailedLocateParam,\n mode,\n });\n }\n\n // New signature\n async aiKeyboardPress(\n locatePrompt: TUserPrompt,\n opt: LocateOption & { keyName: string },\n ): Promise<void>;\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<void>;\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 await 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<void>;\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<void>;\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 const isLocatePromptLike = (value: unknown): value is TUserPrompt => {\n if (\n typeof value === 'string' ||\n typeof value === 'undefined' ||\n value === null\n ) {\n return true;\n }\n\n return typeof value === 'object' && value !== null && 'prompt' in value;\n };\n\n // Check if using new signature (first param is locatePrompt, second is options)\n if (\n isLocatePromptLike(locatePromptOrScrollParam) &&\n typeof locatePromptOrOpt === 'object' &&\n locatePromptOrOpt !== null\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 if (opt) {\n const normalizedScrollType = normalizeScrollType(\n (opt as ScrollParam).scrollType as\n | ScrollParam['scrollType']\n | LegacyScrollType\n | undefined,\n );\n\n if (normalizedScrollType !== (opt as ScrollParam).scrollType) {\n (opt as ScrollParam) = {\n ...(opt || {}),\n scrollType: normalizedScrollType as ScrollParam['scrollType'],\n };\n }\n }\n\n const detailedLocateParam = buildDetailedLocateParam(\n locatePrompt || '',\n opt,\n );\n\n await this.callActionInActionSpace('Scroll', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n async aiPinch(\n locatePrompt: TUserPrompt | undefined,\n opt: LocateOption & {\n direction: 'in' | 'out';\n distance?: number;\n duration?: number;\n },\n ): Promise<void> {\n const detailedLocateParam = buildDetailedLocateParam(\n locatePrompt || '',\n opt,\n );\n\n await this.callActionInActionSpace('Pinch', {\n ...opt,\n locate: detailedLocateParam,\n });\n }\n\n async aiLongPress(\n locatePrompt: TUserPrompt,\n opt?: LocateOption & { duration?: number },\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for long press');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await this.callActionInActionSpace('LongPress', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n async aiClearInput(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for clear input');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await this.callActionInActionSpace('ClearInput', {\n locate: detailedLocateParam,\n });\n }\n\n async aiAct(\n taskPrompt: TUserPrompt,\n opt?: AiActOptions,\n ): Promise<string | undefined> {\n const internalReportDisplay = (opt as AiActInternalOptions | undefined)\n ?._internalReportDisplay;\n const taskPromptText =\n typeof taskPrompt === 'string' ? taskPrompt : taskPrompt.prompt;\n const reportPrompt = internalReportDisplay?.prompt || taskPromptText;\n const fileChooserAccept = opt?.fileChooserAccept\n ? this.normalizeFileInput(opt.fileChooserAccept)\n : undefined;\n\n const abortSignal = opt?.abortSignal;\n if (abortSignal?.aborted) {\n throw new Error(\n `aiAct aborted: ${abortSignal.reason || 'signal already aborted'}`,\n );\n }\n\n const runAiAct = async () => {\n const modelConfigForPlanning =\n this.modelConfigManager.getModelConfig('planning');\n // Controls the aiAct planning mode, such as sub-goal prompts and bbox strategy.\n const deepThink = opt?.deepThink === true;\n\n const deepLocate = opt?.deepLocate;\n\n const noIndividualLocateModel = modelConfigForPlanning.slot === 'default';\n\n const includeBboxInPlanning = !deepThink && noIndividualLocateModel;\n\n debug('setting includeBboxInPlanning to', includeBboxInPlanning, {\n deepThink,\n noIndividualLocateModel,\n });\n\n const cacheable = opt?.cacheable;\n const replanningCycleLimit = this.resolveReplanningCycleLimit(\n modelConfigForPlanning,\n );\n // if vlm-ui-tars or auto-glm, plan cache is not used\n const isVlmUiTars = isUITars(modelConfigForPlanning.modelFamily);\n const isAutoGlm = isAutoGLM(modelConfigForPlanning.modelFamily);\n const matchedCache =\n isVlmUiTars || isAutoGlm || cacheable === false\n ? undefined\n : this.taskCache?.matchPlanCache(taskPrompt);\n if (\n matchedCache?.cacheUsable &&\n this.taskCache?.isCacheResultUsed &&\n matchedCache.cacheContent?.yamlWorkflow?.trim()\n ) {\n // log into report file\n await this.taskExecutor.loadYamlFlowAsPlanning(\n taskPrompt,\n matchedCache.cacheContent.yamlWorkflow,\n internalReportDisplay,\n );\n\n debug('matched cache, will call .runYaml to run the action');\n const yaml = matchedCache.cacheContent.yamlWorkflow;\n await this.runYaml(yaml);\n return;\n }\n\n // If cache matched but is not executable, fall through to normal execution\n const imagesIncludeCount: number = deepThink ? 2 : 1;\n const { output: actionOutput } = await this.taskExecutor.action(\n taskPrompt,\n modelConfigForPlanning,\n this.modelConfigManager.getModelConfig('default'),\n includeBboxInPlanning,\n this.aiActContext,\n cacheable,\n replanningCycleLimit,\n imagesIncludeCount,\n deepThink,\n fileChooserAccept,\n deepLocate,\n abortSignal,\n internalReportDisplay,\n );\n\n // update cache\n if (\n this.taskCache &&\n actionOutput?.yamlFlow?.length &&\n cacheable !== false\n ) {\n const yamlContent: MidsceneYamlScript = {\n tasks: [\n {\n name: reportPrompt,\n flow: actionOutput.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 return actionOutput?.output;\n };\n\n return await runAiAct();\n }\n\n async runMarkdown(\n markdownPath: string,\n opt?: AiActOptions,\n ): Promise<string | undefined> {\n const markdown = await readFile(markdownPath, 'utf-8');\n const { prompt } = await markdownToAiActPrompt(markdown, markdownPath);\n return this.aiAct(prompt, {\n ...opt,\n _internalReportDisplay: {\n type: 'Markdown',\n prompt: basename(markdownPath),\n },\n } as AiActOptions);\n }\n\n /**\n * @deprecated Use {@link Agent.aiAct} instead.\n */\n async aiAction(taskPrompt: TUserPrompt, opt?: AiActOptions) {\n return this.aiAct(taskPrompt, opt);\n }\n\n async aiQuery<ReturnType = any>(\n demand: ServiceExtractParam,\n opt: ServiceExtractOption = defaultServiceExtractOption,\n ): Promise<ReturnType> {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n const { output } = await this.taskExecutor.createTypeQueryExecution(\n 'Query',\n demand,\n modelConfig,\n opt,\n );\n return output as ReturnType;\n }\n\n async aiBoolean(\n prompt: TUserPrompt,\n opt: ServiceExtractOption = defaultServiceExtractOption,\n ): Promise<boolean> {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output } = await this.taskExecutor.createTypeQueryExecution(\n 'Boolean',\n textPrompt,\n modelConfig,\n opt,\n multimodalPrompt,\n );\n return output as boolean;\n }\n\n async aiNumber(\n prompt: TUserPrompt,\n opt: ServiceExtractOption = defaultServiceExtractOption,\n ): Promise<number> {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output } = await this.taskExecutor.createTypeQueryExecution(\n 'Number',\n textPrompt,\n modelConfig,\n opt,\n multimodalPrompt,\n );\n return output as number;\n }\n\n async aiString(\n prompt: TUserPrompt,\n opt: ServiceExtractOption = defaultServiceExtractOption,\n ): Promise<string> {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output } = await this.taskExecutor.createTypeQueryExecution(\n 'String',\n textPrompt,\n modelConfig,\n opt,\n multimodalPrompt,\n );\n return output as string;\n }\n\n async aiAsk(\n prompt: TUserPrompt,\n opt: ServiceExtractOption = defaultServiceExtractOption,\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 deepLocate?: 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 deepLocate = opt?.deepLocate || false;\n let verifyResult: LocateValidatorResult | undefined;\n\n while (!success && retryCount < retryLimit) {\n if (retryCount >= 2) {\n deepLocate = true;\n }\n debug(\n 'aiDescribe',\n center,\n 'verifyPrompt',\n verifyPrompt,\n 'retryCount',\n retryCount,\n 'deepLocate',\n deepLocate,\n );\n // use same intent as aiLocate\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const text = await this.service.describe(center, modelConfig, {\n deepLocate,\n });\n debug('aiDescribe text', text);\n assert(text.description, `failed to describe element at [${center}]`);\n resultPrompt = text.description;\n\n // Don't pass deepLocate to verification locate — the description was generated\n // from a cropped view (deepLocate describe), but verification should use regular\n // locate on the full screenshot to confirm the description works universally.\n // Passing deepLocate here would trigger AiLocateSection with an element-level\n // description as a section prompt, which is semantically incorrect.\n verifyResult = await this.verifyLocator(\n resultPrompt,\n 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 deepLocate,\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 /**\n * Locate an element and return both its center point and an approximate rect.\n *\n * - In most locate flows, `rect` represents the matched element boundary.\n * - Some models only support point grounding instead of boundary grounding.\n * In those cases (for example, AutoGLM), `rect` falls back to a small 8x8\n * box centered on the located point.\n *\n * Because `rect` may vary with the underlying model capability, avoid relying\n * on it too heavily for strict boundary semantics. If you need a stable click\n * target, prefer `center`.\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 defaultIntentModelConfig =\n this.modelConfigManager.getModelConfig('default');\n const modelConfigForPlanning =\n this.modelConfigManager.getModelConfig('planning');\n\n const { output } = await this.taskExecutor.runPlans(\n taskTitleStr('Locate', locateParamStr(locateParam)),\n plans,\n modelConfigForPlanning,\n defaultIntentModelConfig,\n );\n\n const { element } = output;\n\n return {\n rect: element?.rect,\n center: element?.center,\n dpr: element?.dpr,\n } as Pick<LocateResultElement, 'rect' | 'center'>;\n }\n\n async aiAssert(\n assertion: TUserPrompt,\n msg?: string,\n opt?: AgentAssertOpt & ServiceExtractOption,\n ) {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const serviceOpt: ServiceExtractOption = {\n domIncluded: opt?.domIncluded ?? defaultServiceExtractOption.domIncluded,\n screenshotIncluded:\n opt?.screenshotIncluded ??\n defaultServiceExtractOption.screenshotIncluded,\n };\n\n const { textPrompt, multimodalPrompt } = parsePrompt(assertion);\n const assertionText =\n typeof assertion === 'string' ? assertion : assertion.prompt;\n\n try {\n const { output, thought } =\n await this.taskExecutor.createTypeQueryExecution<boolean>(\n 'Assert',\n textPrompt,\n modelConfig,\n serviceOpt,\n multimodalPrompt,\n );\n\n const pass = Boolean(output);\n const message = pass\n ? undefined\n : `Assertion failed: ${msg || assertionText}\\nReason: ${thought || '(no_reason)'}`;\n\n if (opt?.keepRawResponse) {\n return {\n pass,\n thought,\n message,\n };\n }\n\n if (!pass) {\n throw new Error(message);\n }\n } catch (error) {\n if (error instanceof TaskExecutionError) {\n const errorTask = error.errorTask;\n const thought = errorTask?.thought;\n const rawError = errorTask?.error;\n const rawMessage =\n errorTask?.errorMessage ||\n (rawError instanceof Error\n ? rawError.message\n : rawError\n ? String(rawError)\n : undefined);\n const reason = thought || rawMessage || '(no_reason)';\n const message = `Assertion failed: ${msg || assertionText}\\nReason: ${reason}`;\n\n if (opt?.keepRawResponse) {\n return {\n pass: false,\n thought,\n message,\n };\n }\n\n throw new Error(message, {\n cause: rawError ?? error,\n });\n }\n\n throw error;\n }\n }\n\n async aiWaitFor(assertion: TUserPrompt, opt?: AgentWaitForOpt) {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n await this.taskExecutor.waitFor(\n assertion,\n {\n ...opt,\n timeoutMs: opt?.timeoutMs || 15 * 1000,\n checkIntervalMs: opt?.checkIntervalMs || 3 * 1000,\n },\n modelConfig,\n );\n }\n\n async ai(...args: Parameters<typeof this.aiAct>) {\n return this.aiAct(...args);\n }\n\n async runYaml(yamlScriptContent: string): Promise<{\n result: Record<string, any>;\n }> {\n const script = parseYamlScript(yamlScriptContent, 'yaml');\n const player = new ScriptPlayer(script, async () => {\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.interface.evaluateJavaScript,\n 'evaluateJavaScript is not supported in current agent',\n );\n return this.interface.evaluateJavaScript(script);\n }\n\n /**\n * Add a dump update listener\n * @param listener Listener function\n * @returns A remove function that can be called to remove this listener\n */\n addDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): () => void {\n this.dumpUpdateListeners.push(listener);\n\n // Return remove function\n return () => {\n this.removeDumpUpdateListener(listener);\n };\n }\n\n /**\n * Remove a dump update listener\n * @param listener The listener function to remove\n */\n removeDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): void {\n const index = this.dumpUpdateListeners.indexOf(listener);\n if (index > -1) {\n this.dumpUpdateListeners.splice(index, 1);\n }\n }\n\n /**\n * Clear all dump update listeners\n */\n clearDumpUpdateListeners(): void {\n this.dumpUpdateListeners = [];\n }\n\n async destroy() {\n // Early return if already destroyed\n if (this.destroyed) {\n return;\n }\n\n // Wait for all queued write operations to complete\n await this.reportGenerator.flush();\n\n const finalPath = await this.reportGenerator.finalize();\n this.reportFile = finalPath;\n\n await this.interface.destroy?.();\n this.resetDump(); // reset dump to release memory\n this.destroyed = true;\n }\n\n async recordToReport(\n title?: string,\n opt?: {\n content: string;\n },\n ) {\n // 1. screenshot\n const base64 = await this.interface.screenshotBase64();\n const now = Date.now();\n const screenshot = ScreenshotItem.create(base64, now);\n // 2. build recorder\n const recorder: ExecutionRecorderItem[] = [\n {\n type: 'screenshot',\n ts: now,\n screenshot,\n },\n ];\n // 3. build ExecutionTaskLog\n const task: ExecutionTaskLog = {\n taskId: uuid(),\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 = new ExecutionDump({\n id: uuid(),\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 this.writeOutActionDumps(executionDump);\n await this.reportGenerator.flush();\n\n // Call all registered dump update listeners\n const dumpString = this.dumpDataString();\n for (const listener of this.dumpUpdateListeners) {\n try {\n listener(dumpString);\n } catch (error) {\n console.error('Error in onDumpUpdate listener', error);\n }\n }\n }\n\n /**\n * @deprecated Use {@link Agent.recordToReport} instead.\n */\n async logScreenshot(\n title?: string,\n opt?: {\n content: string;\n },\n ) {\n await this.recordToReport(title, opt);\n }\n\n _unstableLogContent() {\n const { groupName, groupDescription, executions } = this.dump;\n return {\n groupName,\n groupDescription,\n executions: executions || [],\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.frozenUIContext = 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.frozenUIContext = undefined;\n debug('Page context unfrozen successfully');\n }\n\n /**\n * Process cache configuration and return normalized cache settings\n */\n private processCacheConfig(opts: AgentOpt): {\n id: string;\n enabled: boolean;\n readOnly: boolean;\n writeOnly: boolean;\n } | null {\n // Validate original cache config before processing\n // Agent requires explicit IDs - don't allow auto-generation\n if (opts.cache === true) {\n throw new Error(\n 'cache: true requires an explicit cache ID. Please provide:\\n' +\n 'Example: cache: { id: \"my-cache-id\" }',\n );\n }\n\n // Check if cache config object is missing ID\n if (\n opts.cache &&\n typeof opts.cache === 'object' &&\n opts.cache !== null &&\n !opts.cache.id\n ) {\n throw new Error(\n 'cache configuration requires an explicit id.\\n' +\n 'Example: cache: { id: \"my-cache-id\" }',\n );\n }\n\n // Use the unified utils function to process cache configuration\n const cacheConfig = processCacheConfig(\n opts.cache,\n opts.cacheId || 'default',\n );\n\n if (!cacheConfig) {\n return null;\n }\n\n // Handle cache configuration object\n if (typeof cacheConfig === 'object' && cacheConfig !== null) {\n const id = cacheConfig.id;\n const rawStrategy = cacheConfig.strategy as unknown;\n let strategyValue: string;\n\n if (rawStrategy === undefined) {\n strategyValue = 'read-write';\n } else if (typeof rawStrategy === 'string') {\n strategyValue = rawStrategy;\n } else {\n throw new Error(\n `cache.strategy must be a string when provided, but received type ${typeof rawStrategy}`,\n );\n }\n\n if (!isValidCacheStrategy(strategyValue)) {\n throw new Error(\n `cache.strategy must be one of ${CACHE_STRATEGY_VALUES}, but received \"${strategyValue}\"`,\n );\n }\n\n const isReadOnly = strategyValue === 'read-only';\n const isWriteOnly = strategyValue === 'write-only';\n\n return {\n id,\n enabled: !isWriteOnly,\n readOnly: isReadOnly,\n writeOnly: isWriteOnly,\n };\n }\n\n return null;\n }\n\n private normalizeFilePaths(files: string[]): string[] {\n if (ifInBrowser) {\n throw new Error('File chooser is not supported in browser environment');\n }\n\n return files.map((file) => {\n const absolutePath = resolve(file);\n if (!existsSync(absolutePath)) {\n throw new Error(\n `File not found: ${file}. Resolved to: ${absolutePath}. Current working directory: ${process.cwd()}`,\n );\n }\n return absolutePath;\n });\n }\n\n private normalizeFileInput(files: string | string[]): string[] {\n const filesArray = Array.isArray(files) ? files : [files];\n return this.normalizeFilePaths(filesArray);\n }\n\n /**\n * Manually flush cache to file\n * @param options - Optional configuration\n * @param options.cleanUnused - If true, removes unused cache records before flushing\n */\n async flushCache(options?: { cleanUnused?: boolean }): Promise<void> {\n if (!this.taskCache) {\n throw new Error('Cache is not configured');\n }\n\n this.taskCache.flushCacheToFile(options);\n }\n}\n\nexport const createAgent = (\n interfaceInstance: AbstractInterface,\n opts?: AgentOpt,\n) => {\n return new Agent(interfaceInstance, opts);\n};\n"],"names":["debug","getDebug","distanceOfTwoPoints","p1","p2","x1","y1","x2","y2","Math","includedInRect","point","rect","x","y","left","top","width","height","defaultServiceExtractOption","CACHE_STRATEGIES","isValidCacheStrategy","strategy","value","CACHE_STRATEGY_VALUES","legacyScrollTypeMap","normalizeScrollType","scrollType","defaultReplanningCycleLimit","defaultVlmUiTarsReplanningCycleLimit","defaultAutoGlmReplanningCycleLimit","Agent","callback","modelConfigForPlanning","undefined","isUITars","isAutoGLM","_error","action","modelFamily","maxRetries","attempt","commonContextParser","error","Promise","resolve","setTimeout","prompt","console","ReportActionDump","getVersion","WeakMap","execution","runner","currentDump","existingIndex","opt","ifInBrowser","reportHTMLContent","executionDump","exec","task","param","paramStr","tip","typeStr","name","type","actionPlan","plans","Boolean","title","taskTitleStr","locateParamStr","defaultIntentModelConfig","output","locatePrompt","assert","detailedLocateParam","buildDetailedLocateParam","fileChooserAccept","withFileChooser","locatePromptOrValue","locatePromptOrOpt","optOrUndefined","optWithValue","stringValue","String","mode","locatePromptOrKeyName","keyName","locatePromptOrScrollParam","scrollParam","isLocatePromptLike","normalizedScrollType","taskPrompt","internalReportDisplay","taskPromptText","reportPrompt","abortSignal","Error","runAiAct","deepThink","deepLocate","noIndividualLocateModel","includeBboxInPlanning","cacheable","replanningCycleLimit","isVlmUiTars","isAutoGlm","matchedCache","yaml","imagesIncludeCount","actionOutput","yamlContent","yamlFlowStr","markdownPath","markdown","readFile","markdownToAiActPrompt","basename","demand","modelConfig","textPrompt","multimodalPrompt","parsePrompt","center","verifyPrompt","retryLimit","success","retryCount","resultPrompt","verifyResult","text","locateOpt","expectCenter","verifyLocateOption","verifyCenter","verifyRect","distance","included","pass","locateParam","locatePlan","locatePlanForLocate","element","assertion","msg","serviceOpt","assertionText","thought","message","TaskExecutionError","errorTask","rawError","rawMessage","reason","args","yamlScriptContent","script","parseYamlScript","player","ScriptPlayer","errors","listener","index","finalPath","base64","now","Date","screenshot","ScreenshotItem","recorder","uuid","ExecutionDump","dumpString","groupName","groupDescription","executions","context","opts","cacheConfig","processCacheConfig","id","rawStrategy","strategyValue","isReadOnly","isWriteOnly","files","file","absolutePath","existsSync","process","filesArray","Array","options","interfaceInstance","envReplanningCycleLimit","globalConfigManager","MIDSCENE_REPLANNING_CYCLE_LIMIT","Object","Number","assertReportGenerationOptions","resolvedAiActContext","hasCustomConfig","ModelConfigManager","globalModelConfigManager","Service","cacheConfigObj","TaskCache","baseActionSpace","defineActionSleep","TaskExecutor","getReportFileName","ReportGenerator","createAgent"],"mappings":"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"}
1
+ {"version":3,"file":"agent/agent.mjs","sources":["../../../src/agent/agent.ts"],"sourcesContent":["import { isAutoGLM, isUITars } from '@/ai-model/auto-glm/util';\nimport yaml from 'js-yaml';\nimport type { TUserPrompt } from '../ai-model/index';\nimport { ScreenshotItem } from '../screenshot-item';\nimport Service from '../service/index';\n// Import types and values directly from their source files to avoid circular dependency\n// DO NOT import from '../index' as it creates a circular dependency:\n// index.ts -> agent/index.ts -> agent/agent.ts -> index.ts\nimport {\n type ActionParam,\n type ActionReturn,\n type AgentAssertOpt,\n type AgentDescribeElementAtPointResult,\n type AgentOpt,\n type AgentWaitForOpt,\n type CacheConfig,\n type DeepThinkOption,\n type DeviceAction,\n ExecutionDump,\n type ExecutionRecorderItem,\n type ExecutionTask,\n type ExecutionTaskLog,\n type LocateOption,\n type LocateResultElement,\n type LocateValidatorResult,\n type LocatorValidatorOption,\n type OnTaskStartTip,\n type PlanningAction,\n type Rect,\n ReportActionDump,\n type ReportMeta,\n type ScrollParam,\n type ServiceAction,\n type ServiceExtractOption,\n type ServiceExtractParam,\n type TestStatus,\n type UIContext,\n} from '../types';\nimport type { MidsceneYamlScript } from '../yaml';\n\nimport type { IReportGenerator } from '@/report-generator';\nimport {\n ReportGenerator,\n assertReportGenerationOptions,\n} from '@/report-generator';\nimport { getVersion, processCacheConfig, reportHTMLContent } from '@/utils';\nimport {\n ScriptPlayer,\n buildDetailedLocateParam,\n parseYamlScript,\n} from '../yaml/index';\n\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { AbstractInterface } from '@/device';\nimport type { TaskRunner } from '@/task-runner';\nimport {\n type IModelConfig,\n MIDSCENE_REPLANNING_CYCLE_LIMIT,\n ModelConfigManager,\n globalConfigManager,\n globalModelConfigManager,\n} from '@midscene/shared/env';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser, uuid } from '@midscene/shared/utils';\nimport { defineActionSleep } from '../device';\nimport { TaskCache } from './task-cache';\nimport {\n TaskExecutionError,\n TaskExecutor,\n locatePlanForLocate,\n withFileChooser,\n} from './tasks';\nimport { locateParamStr, paramStr, taskTitleStr, typeStr } from './ui-utils';\nimport { commonContextParser, getReportFileName, parsePrompt } 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 defaultServiceExtractOption: ServiceExtractOption = {\n domIncluded: false,\n screenshotIncluded: true,\n};\n\ntype CacheStrategy = NonNullable<CacheConfig['strategy']>;\n\nconst CACHE_STRATEGIES: readonly CacheStrategy[] = [\n 'read-only',\n 'read-write',\n 'write-only',\n];\n\nconst isValidCacheStrategy = (strategy: string): strategy is CacheStrategy =>\n CACHE_STRATEGIES.some((value) => value === strategy);\n\nconst CACHE_STRATEGY_VALUES = CACHE_STRATEGIES.map(\n (value) => `\"${value}\"`,\n).join(', ');\n\nconst legacyScrollTypeMap = {\n once: 'singleAction',\n untilBottom: 'scrollToBottom',\n untilTop: 'scrollToTop',\n untilRight: 'scrollToRight',\n untilLeft: 'scrollToLeft',\n} as const;\n\ntype LegacyScrollType = keyof typeof legacyScrollTypeMap;\n\nconst normalizeScrollType = (\n scrollType: ScrollParam['scrollType'] | LegacyScrollType | undefined,\n): ScrollParam['scrollType'] | undefined => {\n if (!scrollType) {\n return scrollType;\n }\n\n if (scrollType in legacyScrollTypeMap) {\n return legacyScrollTypeMap[scrollType as LegacyScrollType];\n }\n\n return scrollType as ScrollParam['scrollType'];\n};\n\nconst defaultReplanningCycleLimit = 20;\nconst defaultVlmUiTarsReplanningCycleLimit = 40;\nconst defaultAutoGlmReplanningCycleLimit = 100;\n\nexport type AiActOptions = {\n cacheable?: boolean;\n fileChooserAccept?: string | string[];\n deepThink?: DeepThinkOption;\n deepLocate?: boolean;\n abortSignal?: AbortSignal;\n};\n\nexport class Agent<\n InterfaceType extends AbstractInterface = AbstractInterface,\n> {\n interface: InterfaceType;\n\n service: Service;\n\n dump: ReportActionDump;\n\n reportFile?: string | null;\n\n reportFileName?: string;\n\n taskExecutor: TaskExecutor;\n\n opts: AgentOpt;\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 private dumpUpdateListeners: Array<\n (dump: string, executionDump?: ExecutionDump) => void\n > = [];\n\n get onDumpUpdate():\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined {\n return this.dumpUpdateListeners[0];\n }\n\n set onDumpUpdate(callback:\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined) {\n // Clear existing listeners\n this.dumpUpdateListeners = [];\n // Add callback to array if provided\n if (callback) {\n this.dumpUpdateListeners.push(callback);\n }\n }\n\n destroyed = false;\n\n modelConfigManager: ModelConfigManager;\n\n /**\n * Frozen page context for consistent AI operations\n */\n private frozenUIContext?: UIContext;\n\n private get aiActContext(): string | undefined {\n return this.opts.aiActContext ?? this.opts.aiActionContext;\n }\n\n /**\n * Flag to track if VL model warning has been shown\n */\n private hasWarnedNonVLModel = false;\n\n private executionDumpIndexByRunner = new WeakMap<TaskRunner, number>();\n\n private fullActionSpace: DeviceAction[];\n\n private reportGenerator: IReportGenerator;\n\n // @deprecated use .interface instead\n get page() {\n return this.interface;\n }\n\n /**\n * Ensures VL model warning is shown once when needed\n */\n private ensureVLModelWarning() {\n if (\n !this.hasWarnedNonVLModel &&\n this.interface.interfaceType !== 'puppeteer' &&\n this.interface.interfaceType !== 'playwright' &&\n this.interface.interfaceType !== 'static' &&\n this.interface.interfaceType !== 'chrome-extension-proxy' &&\n this.interface.interfaceType !== 'page-over-chrome-extension-bridge'\n ) {\n this.modelConfigManager.throwErrorIfNonVLModel();\n this.hasWarnedNonVLModel = true;\n }\n }\n\n private resolveReplanningCycleLimit(\n modelConfigForPlanning: IModelConfig,\n ): number {\n if (this.opts.replanningCycleLimit !== undefined) {\n return this.opts.replanningCycleLimit;\n }\n\n return isUITars(modelConfigForPlanning.modelFamily)\n ? defaultVlmUiTarsReplanningCycleLimit\n : isAutoGLM(modelConfigForPlanning.modelFamily)\n ? defaultAutoGlmReplanningCycleLimit\n : defaultReplanningCycleLimit;\n }\n\n constructor(interfaceInstance: InterfaceType, opts?: AgentOpt) {\n this.interface = interfaceInstance;\n\n const envReplanningCycleLimit =\n globalConfigManager.getEnvConfigValueAsNumber(\n MIDSCENE_REPLANNING_CYCLE_LIMIT,\n );\n\n this.opts = Object.assign(\n {\n generateReport: true,\n persistExecutionDump: false,\n autoPrintReportMsg: true,\n groupName: 'Midscene Report',\n groupDescription: '',\n },\n opts || {},\n opts?.replanningCycleLimit === undefined &&\n envReplanningCycleLimit !== undefined &&\n !Number.isNaN(envReplanningCycleLimit)\n ? { replanningCycleLimit: envReplanningCycleLimit }\n : {},\n );\n assertReportGenerationOptions(this.opts);\n\n const resolvedAiActContext =\n this.opts.aiActContext ?? this.opts.aiActionContext;\n if (resolvedAiActContext !== undefined) {\n this.opts.aiActContext = resolvedAiActContext;\n this.opts.aiActionContext ??= resolvedAiActContext;\n }\n\n if (\n opts?.modelConfig &&\n (typeof opts?.modelConfig !== 'object' || Array.isArray(opts.modelConfig))\n ) {\n throw new Error(\n `opts.modelConfig must be a plain object map of env keys to values, but got ${typeof opts?.modelConfig}`,\n );\n }\n // Create ModelConfigManager if modelConfig or createOpenAIClient is provided\n // Otherwise, use the global config manager\n const hasCustomConfig = opts?.modelConfig || opts?.createOpenAIClient;\n this.modelConfigManager = hasCustomConfig\n ? new ModelConfigManager(opts?.modelConfig, opts?.createOpenAIClient)\n : globalModelConfigManager;\n\n this.onTaskStartTip = this.opts.onTaskStartTip;\n\n this.service = new Service(async () => {\n return this.getUIContext();\n });\n\n // Process cache configuration\n const cacheConfigObj = this.processCacheConfig(opts || {});\n if (cacheConfigObj) {\n this.taskCache = new TaskCache(\n cacheConfigObj.id,\n cacheConfigObj.enabled,\n undefined, // cacheFilePath\n {\n readOnly: cacheConfigObj.readOnly,\n writeOnly: cacheConfigObj.writeOnly,\n },\n );\n }\n\n const baseActionSpace = this.interface.actionSpace();\n this.fullActionSpace = [...baseActionSpace, defineActionSleep()];\n\n this.taskExecutor = new TaskExecutor(this.interface, this.service, {\n taskCache: this.taskCache,\n onTaskStart: this.callbackOnTaskStartTip.bind(this),\n replanningCycleLimit: this.opts.replanningCycleLimit,\n waitAfterAction: this.opts.waitAfterAction,\n useDeviceTime: this.opts.useDeviceTime,\n actionSpace: this.fullActionSpace,\n hooks: {\n onTaskUpdate: async (runner) => {\n const executionDump = runner.dump();\n this.appendExecutionDump(executionDump, runner);\n\n // Persist report updates before notifying listeners so screenshot\n // payloads can be released from memory and serialized as references.\n this.writeOutActionDumps(executionDump);\n await this.reportGenerator.flush();\n\n // Call all registered dump update listeners\n const dumpString = this.dumpDataString();\n for (const listener of this.dumpUpdateListeners) {\n try {\n listener(dumpString, executionDump);\n } catch (error) {\n console.error('Error in onDumpUpdate listener', error);\n }\n }\n },\n },\n });\n this.dump = this.resetDump();\n this.reportFileName =\n opts?.reportFileName ||\n // Keep deprecated testId behavior for generated report names until it is\n // fully removed from the public API.\n getReportFileName(opts?.testId || this.interface.interfaceType || 'web');\n\n this.reportGenerator = ReportGenerator.create(this.reportFileName!, {\n generateReport: this.opts.generateReport,\n persistExecutionDump: this.opts.persistExecutionDump,\n outputFormat: this.opts.outputFormat,\n autoPrintReportMsg: this.opts.autoPrintReportMsg,\n reuseExistingReport:\n this.opts.reportAttributes?.['data-group-id'] === this.reportFileName,\n });\n }\n\n async getActionSpace(): Promise<DeviceAction[]> {\n return this.fullActionSpace;\n }\n\n private static readonly CONTEXT_RETRY_MAX = 3;\n private static readonly CONTEXT_RETRY_DELAY_MS = 1500;\n\n /**\n * Override in subclasses to indicate which errors are transient and should\n * trigger an automatic retry when building the UI context.\n * Returns `false` by default (no retry).\n */\n protected isRetryableContextError(_error: unknown): boolean {\n return false;\n }\n\n async getUIContext(action?: ServiceAction): Promise<UIContext> {\n // Check VL model configuration when UI context is first needed\n this.ensureVLModelWarning();\n\n // If page context is frozen, return the frozen context for all actions\n if (this.frozenUIContext) {\n debug('Using frozen page context for action:', action);\n return this.frozenUIContext;\n }\n\n const { modelFamily } = this.modelConfigManager.getModelConfig('default');\n\n const maxRetries = Agent.CONTEXT_RETRY_MAX;\n for (let attempt = 0; ; attempt++) {\n try {\n return await commonContextParser(this.interface, {\n uploadServerUrl: this.modelConfigManager.getUploadTestServerUrl(),\n screenshotShrinkFactor: this.opts.screenshotShrinkFactor,\n modelFamily,\n });\n } catch (error) {\n if (attempt < maxRetries && this.isRetryableContextError(error)) {\n debug(\n `retryable context error (attempt ${attempt + 1}/${maxRetries}), retrying in ${Agent.CONTEXT_RETRY_DELAY_MS}ms: ${error}`,\n );\n await new Promise((resolve) =>\n setTimeout(resolve, Agent.CONTEXT_RETRY_DELAY_MS),\n );\n continue;\n }\n throw error;\n }\n }\n }\n\n async _snapshotContext(): Promise<UIContext> {\n return await this.getUIContext('locate');\n }\n\n /**\n * @deprecated Use {@link setAIActContext} instead.\n */\n async setAIActionContext(prompt: string) {\n await this.setAIActContext(prompt);\n }\n\n async setAIActContext(prompt: string) {\n if (this.aiActContext) {\n console.warn(\n 'aiActContext is already set, and it is called again, will override the previous setting',\n );\n }\n this.opts.aiActContext = prompt;\n this.opts.aiActionContext = prompt;\n }\n\n resetDump() {\n this.dump = new ReportActionDump({\n sdkVersion: getVersion(),\n groupName: this.opts.groupName!,\n groupDescription: this.opts.groupDescription,\n executions: [],\n modelBriefs: [],\n deviceType: this.interface.interfaceType,\n });\n this.executionDumpIndexByRunner = new WeakMap<TaskRunner, number>();\n\n return this.dump;\n }\n\n appendExecutionDump(execution: ExecutionDump, runner?: TaskRunner) {\n const currentDump = this.dump;\n if (runner) {\n const existingIndex = this.executionDumpIndexByRunner.get(runner);\n if (existingIndex !== undefined) {\n currentDump.executions[existingIndex] = execution;\n return;\n }\n currentDump.executions.push(execution);\n this.executionDumpIndexByRunner.set(\n runner,\n currentDump.executions.length - 1,\n );\n return;\n }\n currentDump.executions.push(execution);\n }\n\n dumpDataString(opt?: { inlineScreenshots?: boolean }) {\n // update dump info\n this.dump.groupName = this.opts.groupName!;\n this.dump.groupDescription = this.opts.groupDescription;\n // In browser environment, use inline screenshots since file system is not available\n if (ifInBrowser || opt?.inlineScreenshots) {\n return this.dump.serializeWithInlineScreenshots();\n }\n return this.dump.serialize();\n }\n\n reportHTMLString(opt?: { inlineScreenshots?: boolean }) {\n // dumpDataString() handles browser environment with inline screenshots\n return reportHTMLContent(this.dumpDataString(opt));\n }\n\n private lastExecutionDump?: ExecutionDump;\n\n writeOutActionDumps(executionDump?: ExecutionDump) {\n const exec = executionDump || this.lastExecutionDump;\n if (exec) {\n this.lastExecutionDump = exec;\n this.reportGenerator.onExecutionUpdate(\n exec,\n this.getReportMeta(),\n this.opts.reportAttributes,\n );\n }\n this.reportFile = this.reportGenerator.getReportPath();\n }\n\n private getReportMeta(): ReportMeta {\n return {\n groupName: this.dump.groupName,\n groupDescription: this.dump.groupDescription,\n sdkVersion: this.dump.sdkVersion,\n modelBriefs: this.dump.modelBriefs,\n deviceType: this.dump.deviceType,\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 wrapActionInActionSpace<T extends DeviceAction>(\n name: string,\n ): (param: ActionParam<T>) => Promise<ActionReturn<T>> {\n return async (param: ActionParam<T>) => {\n return await this.callActionInActionSpace<ActionReturn<T>>(name, param);\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);\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 // assume all operation in action space is related to locating\n const defaultIntentModelConfig =\n this.modelConfigManager.getModelConfig('default');\n const modelConfigForPlanning =\n this.modelConfigManager.getModelConfig('planning');\n\n const { output } = await this.taskExecutor.runPlans(\n title,\n plans,\n modelConfigForPlanning,\n defaultIntentModelConfig,\n );\n return output;\n }\n\n async aiTap(\n locatePrompt: TUserPrompt,\n opt?: LocateOption & { fileChooserAccept?: string | string[] },\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for tap');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n const fileChooserAccept = opt?.fileChooserAccept\n ? this.normalizeFileInput(opt.fileChooserAccept)\n : undefined;\n\n await withFileChooser(this.interface, fileChooserAccept, async () => {\n await this.callActionInActionSpace('Tap', {\n locate: detailedLocateParam,\n });\n });\n }\n\n async aiRightClick(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for right click');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await this.callActionInActionSpace('RightClick', {\n locate: detailedLocateParam,\n });\n }\n\n async aiDoubleClick(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for double click');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await this.callActionInActionSpace('DoubleClick', {\n locate: detailedLocateParam,\n });\n }\n\n async aiHover(locatePrompt: TUserPrompt, opt?: LocateOption): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for hover');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await 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 | number } & {\n autoDismissKeyboard?: boolean;\n } & { mode?: 'replace' | 'clear' | 'typeOnly' | 'append' },\n ): Promise<void>;\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 | number,\n locatePrompt: TUserPrompt,\n opt?: LocateOption & { autoDismissKeyboard?: boolean } & {\n mode?: 'replace' | 'clear' | 'typeOnly' | 'append';\n }, // AndroidDeviceInputOpt &\n ): Promise<void>;\n\n // Implementation\n async aiInput(\n locatePromptOrValue: TUserPrompt | string | number,\n locatePromptOrOpt:\n | TUserPrompt\n | (LocateOption & { value: string | number } & {\n autoDismissKeyboard?: boolean;\n } & { mode?: 'replace' | 'clear' | 'typeOnly' | 'append' }) // AndroidDeviceInputOpt &\n | undefined,\n optOrUndefined?: LocateOption, // AndroidDeviceInputOpt &\n ) {\n let value: string | number;\n let locatePrompt: TUserPrompt;\n let opt:\n | (LocateOption & { value: string | number } & {\n autoDismissKeyboard?: boolean;\n } & { mode?: 'replace' | 'clear' | 'typeOnly' | 'append' }) // 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 | number;\n autoDismissKeyboard?: boolean;\n };\n value = optWithValue.value;\n opt = optWithValue;\n } else {\n // Legacy signature: aiInput(value, locatePrompt, opt)\n value = locatePromptOrValue as string | number;\n locatePrompt = locatePromptOrOpt as TUserPrompt;\n opt = {\n ...optOrUndefined,\n value,\n };\n }\n\n assert(\n typeof value === 'string' || typeof value === 'number',\n 'input value must be a string or number, 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 // Convert value to string to ensure consistency\n const stringValue = typeof value === 'number' ? String(value) : value;\n\n // backward compat: convert deprecated 'append' to 'typeOnly'\n const mode = opt?.mode === 'append' ? 'typeOnly' : opt?.mode;\n\n await this.callActionInActionSpace('Input', {\n ...(opt || {}),\n value: stringValue,\n locate: detailedLocateParam,\n mode,\n });\n }\n\n // New signature\n async aiKeyboardPress(\n locatePrompt: TUserPrompt,\n opt: LocateOption & { keyName: string },\n ): Promise<void>;\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<void>;\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 await 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<void>;\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<void>;\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 const isLocatePromptLike = (value: unknown): value is TUserPrompt => {\n if (\n typeof value === 'string' ||\n typeof value === 'undefined' ||\n value === null\n ) {\n return true;\n }\n\n return typeof value === 'object' && value !== null && 'prompt' in value;\n };\n\n // Check if using new signature (first param is locatePrompt, second is options)\n if (\n isLocatePromptLike(locatePromptOrScrollParam) &&\n typeof locatePromptOrOpt === 'object' &&\n locatePromptOrOpt !== null\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 if (opt) {\n const normalizedScrollType = normalizeScrollType(\n (opt as ScrollParam).scrollType as\n | ScrollParam['scrollType']\n | LegacyScrollType\n | undefined,\n );\n\n if (normalizedScrollType !== (opt as ScrollParam).scrollType) {\n (opt as ScrollParam) = {\n ...(opt || {}),\n scrollType: normalizedScrollType as ScrollParam['scrollType'],\n };\n }\n }\n\n const detailedLocateParam = buildDetailedLocateParam(\n locatePrompt || '',\n opt,\n );\n\n await this.callActionInActionSpace('Scroll', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n async aiPinch(\n locatePrompt: TUserPrompt | undefined,\n opt: LocateOption & {\n direction: 'in' | 'out';\n distance?: number;\n duration?: number;\n },\n ): Promise<void> {\n const detailedLocateParam = buildDetailedLocateParam(\n locatePrompt || '',\n opt,\n );\n\n await this.callActionInActionSpace('Pinch', {\n ...opt,\n locate: detailedLocateParam,\n });\n }\n\n async aiLongPress(\n locatePrompt: TUserPrompt,\n opt?: LocateOption & { duration?: number },\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for long press');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await this.callActionInActionSpace('LongPress', {\n ...(opt || {}),\n locate: detailedLocateParam,\n });\n }\n\n async aiClearInput(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n ): Promise<void> {\n assert(locatePrompt, 'missing locate prompt for clear input');\n\n const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n await this.callActionInActionSpace('ClearInput', {\n locate: detailedLocateParam,\n });\n }\n\n async aiAct(\n taskPrompt: string,\n opt?: AiActOptions,\n ): Promise<string | undefined> {\n const fileChooserAccept = opt?.fileChooserAccept\n ? this.normalizeFileInput(opt.fileChooserAccept)\n : undefined;\n\n const abortSignal = opt?.abortSignal;\n if (abortSignal?.aborted) {\n throw new Error(\n `aiAct aborted: ${abortSignal.reason || 'signal already aborted'}`,\n );\n }\n\n const runAiAct = async () => {\n const modelConfigForPlanning =\n this.modelConfigManager.getModelConfig('planning');\n // Controls the aiAct planning mode, such as sub-goal prompts and bbox strategy.\n const deepThink = opt?.deepThink === true;\n\n const deepLocate = opt?.deepLocate;\n\n const noIndividualLocateModel = modelConfigForPlanning.slot === 'default';\n\n const includeBboxInPlanning = !deepThink && noIndividualLocateModel;\n\n debug('setting includeBboxInPlanning to', includeBboxInPlanning, {\n deepThink,\n noIndividualLocateModel,\n });\n\n const cacheable = opt?.cacheable;\n const replanningCycleLimit = this.resolveReplanningCycleLimit(\n modelConfigForPlanning,\n );\n // if vlm-ui-tars or auto-glm, plan cache is not used\n const isVlmUiTars = isUITars(modelConfigForPlanning.modelFamily);\n const isAutoGlm = isAutoGLM(modelConfigForPlanning.modelFamily);\n const matchedCache =\n isVlmUiTars || isAutoGlm || cacheable === false\n ? undefined\n : this.taskCache?.matchPlanCache(taskPrompt);\n if (\n matchedCache?.cacheUsable &&\n this.taskCache?.isCacheResultUsed &&\n matchedCache.cacheContent?.yamlWorkflow?.trim()\n ) {\n // log into report file\n await this.taskExecutor.loadYamlFlowAsPlanning(\n taskPrompt,\n matchedCache.cacheContent.yamlWorkflow,\n );\n\n debug('matched cache, will call .runYaml to run the action');\n const yaml = matchedCache.cacheContent.yamlWorkflow;\n await this.runYaml(yaml);\n return;\n }\n\n // If cache matched but is not executable, fall through to normal execution\n const imagesIncludeCount: number = deepThink ? 2 : 1;\n const { output: actionOutput } = await this.taskExecutor.action(\n taskPrompt,\n modelConfigForPlanning,\n this.modelConfigManager.getModelConfig('default'),\n includeBboxInPlanning,\n this.aiActContext,\n cacheable,\n replanningCycleLimit,\n imagesIncludeCount,\n deepThink,\n fileChooserAccept,\n deepLocate,\n abortSignal,\n );\n\n // update cache\n if (\n this.taskCache &&\n actionOutput?.yamlFlow?.length &&\n cacheable !== false\n ) {\n const yamlContent: MidsceneYamlScript = {\n tasks: [\n {\n name: taskPrompt,\n flow: actionOutput.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 return actionOutput?.output;\n };\n\n return await runAiAct();\n }\n\n /**\n * @deprecated Use {@link Agent.aiAct} instead.\n */\n async aiAction(taskPrompt: string, opt?: AiActOptions) {\n return this.aiAct(taskPrompt, opt);\n }\n\n async aiQuery<ReturnType = any>(\n demand: ServiceExtractParam,\n opt: ServiceExtractOption = defaultServiceExtractOption,\n ): Promise<ReturnType> {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n const { output } = await this.taskExecutor.createTypeQueryExecution(\n 'Query',\n demand,\n modelConfig,\n opt,\n );\n return output as ReturnType;\n }\n\n async aiBoolean(\n prompt: TUserPrompt,\n opt: ServiceExtractOption = defaultServiceExtractOption,\n ): Promise<boolean> {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output } = await this.taskExecutor.createTypeQueryExecution(\n 'Boolean',\n textPrompt,\n modelConfig,\n opt,\n multimodalPrompt,\n );\n return output as boolean;\n }\n\n async aiNumber(\n prompt: TUserPrompt,\n opt: ServiceExtractOption = defaultServiceExtractOption,\n ): Promise<number> {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output } = await this.taskExecutor.createTypeQueryExecution(\n 'Number',\n textPrompt,\n modelConfig,\n opt,\n multimodalPrompt,\n );\n return output as number;\n }\n\n async aiString(\n prompt: TUserPrompt,\n opt: ServiceExtractOption = defaultServiceExtractOption,\n ): Promise<string> {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const { textPrompt, multimodalPrompt } = parsePrompt(prompt);\n const { output } = await this.taskExecutor.createTypeQueryExecution(\n 'String',\n textPrompt,\n modelConfig,\n opt,\n multimodalPrompt,\n );\n return output as string;\n }\n\n async aiAsk(\n prompt: TUserPrompt,\n opt: ServiceExtractOption = defaultServiceExtractOption,\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 deepLocate?: 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 deepLocate = opt?.deepLocate || false;\n let verifyResult: LocateValidatorResult | undefined;\n\n while (!success && retryCount < retryLimit) {\n if (retryCount >= 2) {\n deepLocate = true;\n }\n debug(\n 'aiDescribe',\n center,\n 'verifyPrompt',\n verifyPrompt,\n 'retryCount',\n retryCount,\n 'deepLocate',\n deepLocate,\n );\n // use same intent as aiLocate\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const text = await this.service.describe(center, modelConfig, {\n deepLocate,\n });\n debug('aiDescribe text', text);\n assert(text.description, `failed to describe element at [${center}]`);\n resultPrompt = text.description;\n\n // Don't pass deepLocate to verification locate — the description was generated\n // from a cropped view (deepLocate describe), but verification should use regular\n // locate on the full screenshot to confirm the description works universally.\n // Passing deepLocate here would trigger AiLocateSection with an element-level\n // description as a section prompt, which is semantically incorrect.\n verifyResult = await this.verifyLocator(\n resultPrompt,\n 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 deepLocate,\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 /**\n * Locate an element and return both its center point and an approximate rect.\n *\n * - In most locate flows, `rect` represents the matched element boundary.\n * - Some models only support point grounding instead of boundary grounding.\n * In those cases (for example, AutoGLM), `rect` falls back to a small 8x8\n * box centered on the located point.\n *\n * Because `rect` may vary with the underlying model capability, avoid relying\n * on it too heavily for strict boundary semantics. If you need a stable click\n * target, prefer `center`.\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 defaultIntentModelConfig =\n this.modelConfigManager.getModelConfig('default');\n const modelConfigForPlanning =\n this.modelConfigManager.getModelConfig('planning');\n\n const { output } = await this.taskExecutor.runPlans(\n taskTitleStr('Locate', locateParamStr(locateParam)),\n plans,\n modelConfigForPlanning,\n defaultIntentModelConfig,\n );\n\n const { element } = output;\n\n return {\n rect: element?.rect,\n center: element?.center,\n dpr: element?.dpr,\n } as Pick<LocateResultElement, 'rect' | 'center'>;\n }\n\n async aiAssert(\n assertion: TUserPrompt,\n msg?: string,\n opt?: AgentAssertOpt & ServiceExtractOption,\n ) {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n\n const serviceOpt: ServiceExtractOption = {\n domIncluded: opt?.domIncluded ?? defaultServiceExtractOption.domIncluded,\n screenshotIncluded:\n opt?.screenshotIncluded ??\n defaultServiceExtractOption.screenshotIncluded,\n };\n\n const { textPrompt, multimodalPrompt } = parsePrompt(assertion);\n const assertionText =\n typeof assertion === 'string' ? assertion : assertion.prompt;\n\n try {\n const { output, thought } =\n await this.taskExecutor.createTypeQueryExecution<boolean>(\n 'Assert',\n textPrompt,\n modelConfig,\n serviceOpt,\n multimodalPrompt,\n );\n\n const pass = Boolean(output);\n const message = pass\n ? undefined\n : `Assertion failed: ${msg || assertionText}\\nReason: ${thought || '(no_reason)'}`;\n\n if (opt?.keepRawResponse) {\n return {\n pass,\n thought,\n message,\n };\n }\n\n if (!pass) {\n throw new Error(message);\n }\n } catch (error) {\n if (error instanceof TaskExecutionError) {\n const errorTask = error.errorTask;\n const thought = errorTask?.thought;\n const rawError = errorTask?.error;\n const rawMessage =\n errorTask?.errorMessage ||\n (rawError instanceof Error\n ? rawError.message\n : rawError\n ? String(rawError)\n : undefined);\n const reason = thought || rawMessage || '(no_reason)';\n const message = `Assertion failed: ${msg || assertionText}\\nReason: ${reason}`;\n\n if (opt?.keepRawResponse) {\n return {\n pass: false,\n thought,\n message,\n };\n }\n\n throw new Error(message, {\n cause: rawError ?? error,\n });\n }\n\n throw error;\n }\n }\n\n async aiWaitFor(assertion: TUserPrompt, opt?: AgentWaitForOpt) {\n const modelConfig = this.modelConfigManager.getModelConfig('insight');\n await this.taskExecutor.waitFor(\n assertion,\n {\n ...opt,\n timeoutMs: opt?.timeoutMs || 15 * 1000,\n checkIntervalMs: opt?.checkIntervalMs || 3 * 1000,\n },\n modelConfig,\n );\n }\n\n async ai(...args: Parameters<typeof this.aiAct>) {\n return this.aiAct(...args);\n }\n\n async runYaml(yamlScriptContent: string): Promise<{\n result: Record<string, any>;\n }> {\n const script = parseYamlScript(yamlScriptContent, 'yaml');\n const player = new ScriptPlayer(script, async () => {\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.interface.evaluateJavaScript,\n 'evaluateJavaScript is not supported in current agent',\n );\n return this.interface.evaluateJavaScript(script);\n }\n\n /**\n * Add a dump update listener\n * @param listener Listener function\n * @returns A remove function that can be called to remove this listener\n */\n addDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): () => void {\n this.dumpUpdateListeners.push(listener);\n\n // Return remove function\n return () => {\n this.removeDumpUpdateListener(listener);\n };\n }\n\n /**\n * Remove a dump update listener\n * @param listener The listener function to remove\n */\n removeDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): void {\n const index = this.dumpUpdateListeners.indexOf(listener);\n if (index > -1) {\n this.dumpUpdateListeners.splice(index, 1);\n }\n }\n\n /**\n * Clear all dump update listeners\n */\n clearDumpUpdateListeners(): void {\n this.dumpUpdateListeners = [];\n }\n\n async destroy() {\n // Early return if already destroyed\n if (this.destroyed) {\n return;\n }\n\n // Wait for all queued write operations to complete\n await this.reportGenerator.flush();\n\n const finalPath = await this.reportGenerator.finalize();\n this.reportFile = finalPath;\n\n await this.interface.destroy?.();\n this.resetDump(); // reset dump to release memory\n this.destroyed = true;\n }\n\n async recordToReport(\n title?: string,\n opt?: {\n content?: string;\n screenshotBase64?: string;\n },\n ) {\n // 1. screenshot\n const base64 =\n opt?.screenshotBase64 ?? (await this.interface.screenshotBase64());\n const now = Date.now();\n const screenshot = ScreenshotItem.create(base64, now);\n // 2. build recorder\n const recorder: ExecutionRecorderItem[] = [\n {\n type: 'screenshot',\n ts: now,\n screenshot,\n },\n ];\n // 3. build ExecutionTaskLog\n const task: ExecutionTaskLog = {\n taskId: uuid(),\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 = new ExecutionDump({\n id: uuid(),\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 this.writeOutActionDumps(executionDump);\n await this.reportGenerator.flush();\n\n // Call all registered dump update listeners\n const dumpString = this.dumpDataString();\n for (const listener of this.dumpUpdateListeners) {\n try {\n listener(dumpString);\n } catch (error) {\n console.error('Error in onDumpUpdate listener', error);\n }\n }\n }\n\n /**\n * @deprecated Use {@link Agent.recordToReport} instead.\n */\n async logScreenshot(\n title?: string,\n opt?: {\n content: string;\n },\n ) {\n await this.recordToReport(title, opt);\n }\n\n _unstableLogContent() {\n const { groupName, groupDescription, executions } = this.dump;\n return {\n groupName,\n groupDescription,\n executions: executions || [],\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.frozenUIContext = 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.frozenUIContext = undefined;\n debug('Page context unfrozen successfully');\n }\n\n /**\n * Process cache configuration and return normalized cache settings\n */\n private processCacheConfig(opts: AgentOpt): {\n id: string;\n enabled: boolean;\n readOnly: boolean;\n writeOnly: boolean;\n } | null {\n // Validate original cache config before processing\n // Agent requires explicit IDs - don't allow auto-generation\n if (opts.cache === true) {\n throw new Error(\n 'cache: true requires an explicit cache ID. Please provide:\\n' +\n 'Example: cache: { id: \"my-cache-id\" }',\n );\n }\n\n // Check if cache config object is missing ID\n if (\n opts.cache &&\n typeof opts.cache === 'object' &&\n opts.cache !== null &&\n !opts.cache.id\n ) {\n throw new Error(\n 'cache configuration requires an explicit id.\\n' +\n 'Example: cache: { id: \"my-cache-id\" }',\n );\n }\n\n // Use the unified utils function to process cache configuration\n const cacheConfig = processCacheConfig(\n opts.cache,\n opts.cacheId || 'default',\n );\n\n if (!cacheConfig) {\n return null;\n }\n\n // Handle cache configuration object\n if (typeof cacheConfig === 'object' && cacheConfig !== null) {\n const id = cacheConfig.id;\n const rawStrategy = cacheConfig.strategy as unknown;\n let strategyValue: string;\n\n if (rawStrategy === undefined) {\n strategyValue = 'read-write';\n } else if (typeof rawStrategy === 'string') {\n strategyValue = rawStrategy;\n } else {\n throw new Error(\n `cache.strategy must be a string when provided, but received type ${typeof rawStrategy}`,\n );\n }\n\n if (!isValidCacheStrategy(strategyValue)) {\n throw new Error(\n `cache.strategy must be one of ${CACHE_STRATEGY_VALUES}, but received \"${strategyValue}\"`,\n );\n }\n\n const isReadOnly = strategyValue === 'read-only';\n const isWriteOnly = strategyValue === 'write-only';\n\n return {\n id,\n enabled: !isWriteOnly,\n readOnly: isReadOnly,\n writeOnly: isWriteOnly,\n };\n }\n\n return null;\n }\n\n private normalizeFilePaths(files: string[]): string[] {\n if (ifInBrowser) {\n throw new Error('File chooser is not supported in browser environment');\n }\n\n return files.map((file) => {\n const absolutePath = resolve(file);\n if (!existsSync(absolutePath)) {\n throw new Error(\n `File not found: ${file}. Resolved to: ${absolutePath}. Current working directory: ${process.cwd()}`,\n );\n }\n return absolutePath;\n });\n }\n\n private normalizeFileInput(files: string | string[]): string[] {\n const filesArray = Array.isArray(files) ? files : [files];\n return this.normalizeFilePaths(filesArray);\n }\n\n /**\n * Manually flush cache to file\n * @param options - Optional configuration\n * @param options.cleanUnused - If true, removes unused cache records before flushing\n */\n async flushCache(options?: { cleanUnused?: boolean }): Promise<void> {\n if (!this.taskCache) {\n throw new Error('Cache is not configured');\n }\n\n this.taskCache.flushCacheToFile(options);\n }\n}\n\nexport const createAgent = (\n interfaceInstance: AbstractInterface,\n opts?: AgentOpt,\n) => {\n return new Agent(interfaceInstance, opts);\n};\n"],"names":["debug","getDebug","distanceOfTwoPoints","p1","p2","x1","y1","x2","y2","Math","includedInRect","point","rect","x","y","left","top","width","height","defaultServiceExtractOption","CACHE_STRATEGIES","isValidCacheStrategy","strategy","value","CACHE_STRATEGY_VALUES","legacyScrollTypeMap","normalizeScrollType","scrollType","defaultReplanningCycleLimit","defaultVlmUiTarsReplanningCycleLimit","defaultAutoGlmReplanningCycleLimit","Agent","callback","modelConfigForPlanning","undefined","isUITars","isAutoGLM","_error","action","modelFamily","maxRetries","attempt","commonContextParser","error","Promise","resolve","setTimeout","prompt","console","ReportActionDump","getVersion","WeakMap","execution","runner","currentDump","existingIndex","opt","ifInBrowser","reportHTMLContent","executionDump","exec","task","param","paramStr","tip","typeStr","name","type","actionPlan","plans","Boolean","title","taskTitleStr","locateParamStr","defaultIntentModelConfig","output","locatePrompt","assert","detailedLocateParam","buildDetailedLocateParam","fileChooserAccept","withFileChooser","locatePromptOrValue","locatePromptOrOpt","optOrUndefined","optWithValue","stringValue","String","mode","locatePromptOrKeyName","keyName","locatePromptOrScrollParam","scrollParam","isLocatePromptLike","normalizedScrollType","taskPrompt","abortSignal","Error","runAiAct","deepThink","deepLocate","noIndividualLocateModel","includeBboxInPlanning","cacheable","replanningCycleLimit","isVlmUiTars","isAutoGlm","matchedCache","yaml","imagesIncludeCount","actionOutput","yamlContent","yamlFlowStr","demand","modelConfig","textPrompt","multimodalPrompt","parsePrompt","center","verifyPrompt","retryLimit","success","retryCount","resultPrompt","verifyResult","text","locateOpt","expectCenter","verifyLocateOption","verifyCenter","verifyRect","distance","included","pass","locateParam","locatePlan","locatePlanForLocate","element","assertion","msg","serviceOpt","assertionText","thought","message","TaskExecutionError","errorTask","rawError","rawMessage","reason","args","yamlScriptContent","script","parseYamlScript","player","ScriptPlayer","errors","listener","index","finalPath","base64","now","Date","screenshot","ScreenshotItem","recorder","uuid","ExecutionDump","dumpString","groupName","groupDescription","executions","context","opts","cacheConfig","processCacheConfig","id","rawStrategy","strategyValue","isReadOnly","isWriteOnly","files","file","absolutePath","existsSync","process","filesArray","Array","options","interfaceInstance","envReplanningCycleLimit","globalConfigManager","MIDSCENE_REPLANNING_CYCLE_LIMIT","Object","Number","assertReportGenerationOptions","resolvedAiActContext","hasCustomConfig","ModelConfigManager","globalModelConfigManager","Service","cacheConfigObj","TaskCache","baseActionSpace","defineActionSleep","TaskExecutor","getReportFileName","ReportGenerator","createAgent"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4EA,MAAMA,QAAQC,SAAS;AAEvB,MAAMC,sBAAsB,CAACC,IAAsBC;IACjD,MAAM,CAACC,IAAIC,GAAG,GAAGH;IACjB,MAAM,CAACI,IAAIC,GAAG,GAAGJ;IACjB,OAAOK,KAAK,KAAK,CAACA,KAAK,IAAI,CAAEJ,AAAAA,CAAAA,KAAKE,EAAC,KAAM,IAAKD,AAAAA,CAAAA,KAAKE,EAAC,KAAM;AAC5D;AAEA,MAAME,iBAAiB,CAACC,OAAyBC;IAC/C,MAAM,CAACC,GAAGC,EAAE,GAAGH;IACf,MAAM,EAAEI,IAAI,EAAEC,GAAG,EAAEC,KAAK,EAAEC,MAAM,EAAE,GAAGN;IACrC,OAAOC,KAAKE,QAAQF,KAAKE,OAAOE,SAASH,KAAKE,OAAOF,KAAKE,MAAME;AAClE;AAEA,MAAMC,8BAAoD;IACxD,aAAa;IACb,oBAAoB;AACtB;AAIA,MAAMC,mBAA6C;IACjD;IACA;IACA;CACD;AAED,MAAMC,uBAAuB,CAACC,WAC5BF,iBAAiB,IAAI,CAAC,CAACG,QAAUA,UAAUD;AAE7C,MAAME,wBAAwBJ,iBAAiB,GAAG,CAChD,CAACG,QAAU,CAAC,CAAC,EAAEA,MAAM,CAAC,CAAC,EACvB,IAAI,CAAC;AAEP,MAAME,sBAAsB;IAC1B,MAAM;IACN,aAAa;IACb,UAAU;IACV,YAAY;IACZ,WAAW;AACb;AAIA,MAAMC,sBAAsB,CAC1BC;IAEA,IAAI,CAACA,YACH,OAAOA;IAGT,IAAIA,cAAcF,qBAChB,OAAOA,mBAAmB,CAACE,WAA+B;IAG5D,OAAOA;AACT;AAEA,MAAMC,8BAA8B;AACpC,MAAMC,uCAAuC;AAC7C,MAAMC,qCAAqC;AAUpC,MAAMC;IA8BX,IAAI,eAEU;QACZ,OAAO,IAAI,CAAC,mBAAmB,CAAC,EAAE;IACpC;IAEA,IAAI,aAAaC,QAEJ,EAAE;QAEb,IAAI,CAAC,mBAAmB,GAAG,EAAE;QAE7B,IAAIA,UACF,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAACA;IAElC;IAWA,IAAY,eAAmC;QAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,eAAe;IAC5D;IAcA,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,SAAS;IACvB;IAKQ,uBAAuB;QAC7B,IACE,CAAC,IAAI,CAAC,mBAAmB,IACzB,AAAiC,gBAAjC,IAAI,CAAC,SAAS,CAAC,aAAa,IAC5B,AAAiC,iBAAjC,IAAI,CAAC,SAAS,CAAC,aAAa,IAC5B,AAAiC,aAAjC,IAAI,CAAC,SAAS,CAAC,aAAa,IAC5B,AAAiC,6BAAjC,IAAI,CAAC,SAAS,CAAC,aAAa,IAC5B,AAAiC,wCAAjC,IAAI,CAAC,SAAS,CAAC,aAAa,EAC5B;YACA,IAAI,CAAC,kBAAkB,CAAC,sBAAsB;YAC9C,IAAI,CAAC,mBAAmB,GAAG;QAC7B;IACF;IAEQ,4BACNC,sBAAoC,EAC5B;QACR,IAAI,AAAmCC,WAAnC,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAChC,OAAO,IAAI,CAAC,IAAI,CAAC,oBAAoB;QAGvC,OAAOC,SAASF,uBAAuB,WAAW,IAC9CJ,uCACAO,UAAUH,uBAAuB,WAAW,IAC1CH,qCACAF;IACR;IAsHA,MAAM,iBAA0C;QAC9C,OAAO,IAAI,CAAC,eAAe;IAC7B;IAUU,wBAAwBS,MAAe,EAAW;QAC1D,OAAO;IACT;IAEA,MAAM,aAAaC,MAAsB,EAAsB;QAE7D,IAAI,CAAC,oBAAoB;QAGzB,IAAI,IAAI,CAAC,eAAe,EAAE;YACxBtC,MAAM,yCAAyCsC;YAC/C,OAAO,IAAI,CAAC,eAAe;QAC7B;QAEA,MAAM,EAAEC,WAAW,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QAE/D,MAAMC,aAAaT,MAAM,iBAAiB;QAC1C,IAAK,IAAIU,UAAU,IAAKA,UACtB,IAAI;YACF,OAAO,MAAMC,oBAAoB,IAAI,CAAC,SAAS,EAAE;gBAC/C,iBAAiB,IAAI,CAAC,kBAAkB,CAAC,sBAAsB;gBAC/D,wBAAwB,IAAI,CAAC,IAAI,CAAC,sBAAsB;gBACxDH;YACF;QACF,EAAE,OAAOI,OAAO;YACd,IAAIF,UAAUD,cAAc,IAAI,CAAC,uBAAuB,CAACG,QAAQ;gBAC/D3C,MACE,CAAC,iCAAiC,EAAEyC,UAAU,EAAE,CAAC,EAAED,WAAW,eAAe,EAAET,MAAM,sBAAsB,CAAC,IAAI,EAAEY,OAAO;gBAE3H,MAAM,IAAIC,QAAQ,CAACC,UACjBC,WAAWD,SAASd,MAAM,sBAAsB;gBAElD;YACF;YACA,MAAMY;QACR;IAEJ;IAEA,MAAM,mBAAuC;QAC3C,OAAO,MAAM,IAAI,CAAC,YAAY,CAAC;IACjC;IAKA,MAAM,mBAAmBI,MAAc,EAAE;QACvC,MAAM,IAAI,CAAC,eAAe,CAACA;IAC7B;IAEA,MAAM,gBAAgBA,MAAc,EAAE;QACpC,IAAI,IAAI,CAAC,YAAY,EACnBC,QAAQ,IAAI,CACV;QAGJ,IAAI,CAAC,IAAI,CAAC,YAAY,GAAGD;QACzB,IAAI,CAAC,IAAI,CAAC,eAAe,GAAGA;IAC9B;IAEA,YAAY;QACV,IAAI,CAAC,IAAI,GAAG,IAAIE,iBAAiB;YAC/B,YAAYC;YACZ,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS;YAC9B,kBAAkB,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAC5C,YAAY,EAAE;YACd,aAAa,EAAE;YACf,YAAY,IAAI,CAAC,SAAS,CAAC,aAAa;QAC1C;QACA,IAAI,CAAC,0BAA0B,GAAG,IAAIC;QAEtC,OAAO,IAAI,CAAC,IAAI;IAClB;IAEA,oBAAoBC,SAAwB,EAAEC,MAAmB,EAAE;QACjE,MAAMC,cAAc,IAAI,CAAC,IAAI;QAC7B,IAAID,QAAQ;YACV,MAAME,gBAAgB,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAACF;YAC1D,IAAIE,AAAkBrB,WAAlBqB,eAA6B;gBAC/BD,YAAY,UAAU,CAACC,cAAc,GAAGH;gBACxC;YACF;YACAE,YAAY,UAAU,CAAC,IAAI,CAACF;YAC5B,IAAI,CAAC,0BAA0B,CAAC,GAAG,CACjCC,QACAC,YAAY,UAAU,CAAC,MAAM,GAAG;YAElC;QACF;QACAA,YAAY,UAAU,CAAC,IAAI,CAACF;IAC9B;IAEA,eAAeI,GAAqC,EAAE;QAEpD,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS;QACzC,IAAI,CAAC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB;QAEvD,IAAIC,eAAeD,KAAK,mBACtB,OAAO,IAAI,CAAC,IAAI,CAAC,8BAA8B;QAEjD,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS;IAC5B;IAEA,iBAAiBA,GAAqC,EAAE;QAEtD,OAAOE,kBAAkB,IAAI,CAAC,cAAc,CAACF;IAC/C;IAIA,oBAAoBG,aAA6B,EAAE;QACjD,MAAMC,OAAOD,iBAAiB,IAAI,CAAC,iBAAiB;QACpD,IAAIC,MAAM;YACR,IAAI,CAAC,iBAAiB,GAAGA;YACzB,IAAI,CAAC,eAAe,CAAC,iBAAiB,CACpCA,MACA,IAAI,CAAC,aAAa,IAClB,IAAI,CAAC,IAAI,CAAC,gBAAgB;QAE9B;QACA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,aAAa;IACtD;IAEQ,gBAA4B;QAClC,OAAO;YACL,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS;YAC9B,kBAAkB,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAC5C,YAAY,IAAI,CAAC,IAAI,CAAC,UAAU;YAChC,aAAa,IAAI,CAAC,IAAI,CAAC,WAAW;YAClC,YAAY,IAAI,CAAC,IAAI,CAAC,UAAU;QAClC;IACF;IAEA,MAAc,uBAAuBC,IAAmB,EAAE;QACxD,MAAMC,QAAQC,SAASF;QACvB,MAAMG,MAAMF,QAAQ,GAAGG,QAAQJ,MAAM,GAAG,EAAEC,OAAO,GAAGG,QAAQJ;QAE5D,IAAI,IAAI,CAAC,cAAc,EACrB,MAAM,IAAI,CAAC,cAAc,CAACG;IAE9B;IAEA,wBACEE,IAAY,EACyC;QACrD,OAAO,OAAOJ,QACL,MAAM,IAAI,CAAC,uBAAuB,CAAkBI,MAAMJ;IAErE;IAEA,MAAM,wBACJK,IAAY,EACZX,GAAO,EACP;QACAxD,MAAM,2BAA2BmE,MAAM,KAAKX;QAE5C,MAAMY,aAAgC;YACpC,MAAMD;YACN,OAAQX,OAAe,CAAC;YACxB,SAAS;QACX;QACAxD,MAAM,cAAcoE;QAEpB,MAAMC,QAA0B;YAACD;SAAW,CAAC,MAAM,CACjDE;QAGF,MAAMC,QAAQC,aACZL,MACAM,eAAgBjB,KAAa,UAAU,CAAC;QAI1C,MAAMkB,2BACJ,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QACzC,MAAMzC,yBACJ,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QAEzC,MAAM,EAAE0C,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CACjDJ,OACAF,OACApC,wBACAyC;QAEF,OAAOC;IACT;IAEA,MAAM,MACJC,YAAyB,EACzBpB,GAA8D,EAC/C;QACfqB,OAAOD,cAAc;QAErB,MAAME,sBAAsBC,yBAAyBH,cAAcpB;QAEnE,MAAMwB,oBAAoBxB,KAAK,oBAC3B,IAAI,CAAC,kBAAkB,CAACA,IAAI,iBAAiB,IAC7CtB;QAEJ,MAAM+C,gBAAgB,IAAI,CAAC,SAAS,EAAED,mBAAmB;YACvD,MAAM,IAAI,CAAC,uBAAuB,CAAC,OAAO;gBACxC,QAAQF;YACV;QACF;IACF;IAEA,MAAM,aACJF,YAAyB,EACzBpB,GAAkB,EACH;QACfqB,OAAOD,cAAc;QAErB,MAAME,sBAAsBC,yBAAyBH,cAAcpB;QAEnE,MAAM,IAAI,CAAC,uBAAuB,CAAC,cAAc;YAC/C,QAAQsB;QACV;IACF;IAEA,MAAM,cACJF,YAAyB,EACzBpB,GAAkB,EACH;QACfqB,OAAOD,cAAc;QAErB,MAAME,sBAAsBC,yBAAyBH,cAAcpB;QAEnE,MAAM,IAAI,CAAC,uBAAuB,CAAC,eAAe;YAChD,QAAQsB;QACV;IACF;IAEA,MAAM,QAAQF,YAAyB,EAAEpB,GAAkB,EAAiB;QAC1EqB,OAAOD,cAAc;QAErB,MAAME,sBAAsBC,yBAAyBH,cAAcpB;QAEnE,MAAM,IAAI,CAAC,uBAAuB,CAAC,SAAS;YAC1C,QAAQsB;QACV;IACF;IAuBA,MAAM,QACJI,mBAAkD,EAClDC,iBAKa,EACbC,cAA6B,EAC7B;QACA,IAAI7D;QACJ,IAAIqD;QACJ,IAAIpB;QAOJ,IACE,AAA6B,YAA7B,OAAO2B,qBACPA,AAAsB,SAAtBA,qBACA,WAAWA,mBACX;YAEAP,eAAeM;YACf,MAAMG,eAAeF;YAKrB5D,QAAQ8D,aAAa,KAAK;YAC1B7B,MAAM6B;QACR,OAAO;YAEL9D,QAAQ2D;YACRN,eAAeO;YACf3B,MAAM;gBACJ,GAAG4B,cAAc;gBACjB7D;YACF;QACF;QAEAsD,OACE,AAAiB,YAAjB,OAAOtD,SAAsB,AAAiB,YAAjB,OAAOA,OACpC;QAEFsD,OAAOD,cAAc;QAErB,MAAME,sBAAsBC,yBAAyBH,cAAcpB;QAGnE,MAAM8B,cAAc,AAAiB,YAAjB,OAAO/D,QAAqBgE,OAAOhE,SAASA;QAGhE,MAAMiE,OAAOhC,KAAK,SAAS,WAAW,aAAaA,KAAK;QAExD,MAAM,IAAI,CAAC,uBAAuB,CAAC,SAAS;YAC1C,GAAIA,OAAO,CAAC,CAAC;YACb,OAAO8B;YACP,QAAQR;YACRU;QACF;IACF;IAmBA,MAAM,gBACJC,qBAA2C,EAC3CN,iBAGa,EACbC,cAA6B,EAC7B;QACA,IAAIM;QACJ,IAAId;QACJ,IAAIpB;QAGJ,IACE,AAA6B,YAA7B,OAAO2B,qBACPA,AAAsB,SAAtBA,qBACA,aAAaA,mBACb;YAEAP,eAAea;YACfjC,MAAM2B;QAGR,OAAO;YAELO,UAAUD;YACVb,eAAeO;YACf3B,MAAM;gBACJ,GAAI4B,kBAAkB,CAAC,CAAC;gBACxBM;YACF;QACF;QAEAb,OAAOrB,KAAK,SAAS;QAErB,MAAMsB,sBAAsBF,eACxBG,yBAAyBH,cAAcpB,OACvCtB;QAEJ,MAAM,IAAI,CAAC,uBAAuB,CAAC,iBAAiB;YAClD,GAAIsB,OAAO,CAAC,CAAC;YACb,QAAQsB;QACV;IACF;IAmBA,MAAM,SACJa,yBAAgE,EAChER,iBAAyE,EACzEC,cAA6B,EAC7B;QACA,IAAIQ;QACJ,IAAIhB;QACJ,IAAIpB;QAEJ,MAAMqC,qBAAqB,CAACtE;YAC1B,IACE,AAAiB,YAAjB,OAAOA,SAEPA,QADOA,OAGP,OAAO;YAGT,OAAO,AAAiB,YAAjB,OAAOA,SAAsBA,AAAU,SAAVA,SAAkB,YAAYA;QACpE;QAGA,IACEsE,mBAAmBF,8BACnB,AAA6B,YAA7B,OAAOR,qBACPA,AAAsB,SAAtBA,mBACA;YAEAP,eAAee;YACfnC,MAAM2B;QACR,OAAO;YAELS,cAAcD;YACdf,eAAeO;YACf3B,MAAM;gBACJ,GAAI4B,kBAAkB,CAAC,CAAC;gBACxB,GAAIQ,eAAe,CAAC,CAAC;YACvB;QACF;QAEA,IAAIpC,KAAK;YACP,MAAMsC,uBAAuBpE,oBAC1B8B,IAAoB,UAAU;YAMjC,IAAIsC,yBAA0BtC,IAAoB,UAAU,EACzDA,MAAsB;gBACrB,GAAIA,OAAO,CAAC,CAAC;gBACb,YAAYsC;YACd;QAEJ;QAEA,MAAMhB,sBAAsBC,yBAC1BH,gBAAgB,IAChBpB;QAGF,MAAM,IAAI,CAAC,uBAAuB,CAAC,UAAU;YAC3C,GAAIA,OAAO,CAAC,CAAC;YACb,QAAQsB;QACV;IACF;IAEA,MAAM,QACJF,YAAqC,EACrCpB,GAIC,EACc;QACf,MAAMsB,sBAAsBC,yBAC1BH,gBAAgB,IAChBpB;QAGF,MAAM,IAAI,CAAC,uBAAuB,CAAC,SAAS;YAC1C,GAAGA,GAAG;YACN,QAAQsB;QACV;IACF;IAEA,MAAM,YACJF,YAAyB,EACzBpB,GAA0C,EAC3B;QACfqB,OAAOD,cAAc;QAErB,MAAME,sBAAsBC,yBAAyBH,cAAcpB;QAEnE,MAAM,IAAI,CAAC,uBAAuB,CAAC,aAAa;YAC9C,GAAIA,OAAO,CAAC,CAAC;YACb,QAAQsB;QACV;IACF;IAEA,MAAM,aACJF,YAAyB,EACzBpB,GAAkB,EACH;QACfqB,OAAOD,cAAc;QAErB,MAAME,sBAAsBC,yBAAyBH,cAAcpB;QAEnE,MAAM,IAAI,CAAC,uBAAuB,CAAC,cAAc;YAC/C,QAAQsB;QACV;IACF;IAEA,MAAM,MACJiB,UAAkB,EAClBvC,GAAkB,EACW;QAC7B,MAAMwB,oBAAoBxB,KAAK,oBAC3B,IAAI,CAAC,kBAAkB,CAACA,IAAI,iBAAiB,IAC7CtB;QAEJ,MAAM8D,cAAcxC,KAAK;QACzB,IAAIwC,aAAa,SACf,MAAM,IAAIC,MACR,CAAC,eAAe,EAAED,YAAY,MAAM,IAAI,0BAA0B;QAItE,MAAME,WAAW;YACf,MAAMjE,yBACJ,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;YAEzC,MAAMkE,YAAY3C,KAAK,cAAc;YAErC,MAAM4C,aAAa5C,KAAK;YAExB,MAAM6C,0BAA0BpE,AAAgC,cAAhCA,uBAAuB,IAAI;YAE3D,MAAMqE,wBAAwB,CAACH,aAAaE;YAE5CrG,MAAM,oCAAoCsG,uBAAuB;gBAC/DH;gBACAE;YACF;YAEA,MAAME,YAAY/C,KAAK;YACvB,MAAMgD,uBAAuB,IAAI,CAAC,2BAA2B,CAC3DvE;YAGF,MAAMwE,cAActE,SAASF,uBAAuB,WAAW;YAC/D,MAAMyE,YAAYtE,UAAUH,uBAAuB,WAAW;YAC9D,MAAM0E,eACJF,eAAeC,aAAaH,AAAc,UAAdA,YACxBrE,SACA,IAAI,CAAC,SAAS,EAAE,eAAe6D;YACrC,IACEY,cAAc,eACd,IAAI,CAAC,SAAS,EAAE,qBAChBA,aAAa,YAAY,EAAE,cAAc,QACzC;gBAEA,MAAM,IAAI,CAAC,YAAY,CAAC,sBAAsB,CAC5CZ,YACAY,aAAa,YAAY,CAAC,YAAY;gBAGxC3G,MAAM;gBACN,MAAM4G,OAAOD,aAAa,YAAY,CAAC,YAAY;gBACnD,MAAM,IAAI,CAAC,OAAO,CAACC;gBACnB;YACF;YAGA,MAAMC,qBAA6BV,YAAY,IAAI;YACnD,MAAM,EAAE,QAAQW,YAAY,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAC7Df,YACA9D,wBACA,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,YACvCqE,uBACA,IAAI,CAAC,YAAY,EACjBC,WACAC,sBACAK,oBACAV,WACAnB,mBACAoB,YACAJ;YAIF,IACE,IAAI,CAAC,SAAS,IACdc,cAAc,UAAU,UACxBP,AAAc,UAAdA,WACA;gBACA,MAAMQ,cAAkC;oBACtC,OAAO;wBACL;4BACE,MAAMhB;4BACN,MAAMe,aAAa,QAAQ;wBAC7B;qBACD;gBACH;gBACA,MAAME,cAAcJ,QAAAA,IAAS,CAACG;gBAC9B,IAAI,CAAC,SAAS,CAAC,yBAAyB,CACtC;oBACE,MAAM;oBACN,QAAQhB;oBACR,cAAciB;gBAChB,GACAL;YAEJ;YAEA,OAAOG,cAAc;QACvB;QAEA,OAAO,MAAMZ;IACf;IAKA,MAAM,SAASH,UAAkB,EAAEvC,GAAkB,EAAE;QACrD,OAAO,IAAI,CAAC,KAAK,CAACuC,YAAYvC;IAChC;IAEA,MAAM,QACJyD,MAA2B,EAC3BzD,MAA4BrC,2BAA2B,EAClC;QACrB,MAAM+F,cAAc,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QAC3D,MAAM,EAAEvC,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,wBAAwB,CACjE,SACAsC,QACAC,aACA1D;QAEF,OAAOmB;IACT;IAEA,MAAM,UACJ5B,MAAmB,EACnBS,MAA4BrC,2BAA2B,EACrC;QAClB,MAAM+F,cAAc,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QAE3D,MAAM,EAAEC,UAAU,EAAEC,gBAAgB,EAAE,GAAGC,YAAYtE;QACrD,MAAM,EAAE4B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,wBAAwB,CACjE,WACAwC,YACAD,aACA1D,KACA4D;QAEF,OAAOzC;IACT;IAEA,MAAM,SACJ5B,MAAmB,EACnBS,MAA4BrC,2BAA2B,EACtC;QACjB,MAAM+F,cAAc,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QAE3D,MAAM,EAAEC,UAAU,EAAEC,gBAAgB,EAAE,GAAGC,YAAYtE;QACrD,MAAM,EAAE4B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,wBAAwB,CACjE,UACAwC,YACAD,aACA1D,KACA4D;QAEF,OAAOzC;IACT;IAEA,MAAM,SACJ5B,MAAmB,EACnBS,MAA4BrC,2BAA2B,EACtC;QACjB,MAAM+F,cAAc,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QAE3D,MAAM,EAAEC,UAAU,EAAEC,gBAAgB,EAAE,GAAGC,YAAYtE;QACrD,MAAM,EAAE4B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,wBAAwB,CACjE,UACAwC,YACAD,aACA1D,KACA4D;QAEF,OAAOzC;IACT;IAEA,MAAM,MACJ5B,MAAmB,EACnBS,MAA4BrC,2BAA2B,EACtC;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC4B,QAAQS;IAC/B;IAEA,MAAM,uBACJ8D,MAAwB,EACxB9D,GAI0B,EACkB;QAC5C,MAAM,EAAE+D,eAAe,IAAI,EAAEC,aAAa,CAAC,EAAE,GAAGhE,OAAO,CAAC;QAExD,IAAIiE,UAAU;QACd,IAAIC,aAAa;QACjB,IAAIC,eAAe;QACnB,IAAIvB,aAAa5C,KAAK,cAAc;QACpC,IAAIoE;QAEJ,MAAO,CAACH,WAAWC,aAAaF,WAAY;YAC1C,IAAIE,cAAc,GAChBtB,aAAa;YAEfpG,MACE,cACAsH,QACA,gBACAC,cACA,cACAG,YACA,cACAtB;YAGF,MAAMc,cAAc,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;YAE3D,MAAMW,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAACP,QAAQJ,aAAa;gBAC5Dd;YACF;YACApG,MAAM,mBAAmB6H;YACzBhD,OAAOgD,KAAK,WAAW,EAAE,CAAC,+BAA+B,EAAEP,OAAO,CAAC,CAAC;YACpEK,eAAeE,KAAK,WAAW;YAO/BD,eAAe,MAAM,IAAI,CAAC,aAAa,CACrCD,cACAzF,QACAoF,QACA9D;YAEF,IAAIoE,aAAa,IAAI,EACnBH,UAAU;iBAEVC;QAEJ;QAEA,OAAO;YACL,QAAQC;YACRvB;YACAwB;QACF;IACF;IAEA,MAAM,cACJ7E,MAAc,EACd+E,SAAmC,EACnCC,YAA8B,EAC9BC,kBAA2C,EACX;QAChChI,MAAM,iBAAiB+C,QAAQ+E,WAAWC,cAAcC;QAExD,MAAM,EAAE,QAAQC,YAAY,EAAE,MAAMC,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CACpEnF,QACA+E;QAEF,MAAMK,WAAWjI,oBAAoB6H,cAAcE;QACnD,MAAMG,WAAW1H,eAAeqH,cAAcG;QAC9C,MAAMG,OACJF,YAAaH,CAAAA,oBAAoB,2BAA2B,EAAC,KAC7DI;QACF,MAAMR,eAAe;YACnBS;YACA,MAAMH;YACN,QAAQD;YACR,gBAAgBE;QAClB;QACAnI,MAAM,2BAA2B4H;QACjC,OAAOA;IACT;IAcA,MAAM,SAAS7E,MAAmB,EAAES,GAAkB,EAAE;QACtD,MAAM8E,cAAcvD,yBAAyBhC,QAAQS;QACrDqB,OAAOyD,aAAa;QACpB,MAAMC,aAAaC,oBAAoBF;QACvC,MAAMjE,QAAQ;YAACkE;SAAW;QAC1B,MAAM7D,2BACJ,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QACzC,MAAMzC,yBACJ,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QAEzC,MAAM,EAAE0C,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CACjDH,aAAa,UAAUC,eAAe6D,eACtCjE,OACApC,wBACAyC;QAGF,MAAM,EAAE+D,OAAO,EAAE,GAAG9D;QAEpB,OAAO;YACL,MAAM8D,SAAS;YACf,QAAQA,SAAS;YACjB,KAAKA,SAAS;QAChB;IACF;IAEA,MAAM,SACJC,SAAsB,EACtBC,GAAY,EACZnF,GAA2C,EAC3C;QACA,MAAM0D,cAAc,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QAE3D,MAAM0B,aAAmC;YACvC,aAAapF,KAAK,eAAerC,4BAA4B,WAAW;YACxE,oBACEqC,KAAK,sBACLrC,4BAA4B,kBAAkB;QAClD;QAEA,MAAM,EAAEgG,UAAU,EAAEC,gBAAgB,EAAE,GAAGC,YAAYqB;QACrD,MAAMG,gBACJ,AAAqB,YAArB,OAAOH,YAAyBA,YAAYA,UAAU,MAAM;QAE9D,IAAI;YACF,MAAM,EAAE/D,MAAM,EAAEmE,OAAO,EAAE,GACvB,MAAM,IAAI,CAAC,YAAY,CAAC,wBAAwB,CAC9C,UACA3B,YACAD,aACA0B,YACAxB;YAGJ,MAAMiB,OAAO/D,QAAQK;YACrB,MAAMoE,UAAUV,OACZnG,SACA,CAAC,kBAAkB,EAAEyG,OAAOE,cAAc,UAAU,EAAEC,WAAW,eAAe;YAEpF,IAAItF,KAAK,iBACP,OAAO;gBACL6E;gBACAS;gBACAC;YACF;YAGF,IAAI,CAACV,MACH,MAAM,IAAIpC,MAAM8C;QAEpB,EAAE,OAAOpG,OAAO;YACd,IAAIA,iBAAiBqG,oBAAoB;gBACvC,MAAMC,YAAYtG,MAAM,SAAS;gBACjC,MAAMmG,UAAUG,WAAW;gBAC3B,MAAMC,WAAWD,WAAW;gBAC5B,MAAME,aACJF,WAAW,gBACVC,CAAAA,oBAAoBjD,QACjBiD,SAAS,OAAO,GAChBA,WACE3D,OAAO2D,YACPhH,MAAQ;gBAChB,MAAMkH,SAASN,WAAWK,cAAc;gBACxC,MAAMJ,UAAU,CAAC,kBAAkB,EAAEJ,OAAOE,cAAc,UAAU,EAAEO,QAAQ;gBAE9E,IAAI5F,KAAK,iBACP,OAAO;oBACL,MAAM;oBACNsF;oBACAC;gBACF;gBAGF,MAAM,IAAI9C,MAAM8C,SAAS;oBACvB,OAAOG,YAAYvG;gBACrB;YACF;YAEA,MAAMA;QACR;IACF;IAEA,MAAM,UAAU+F,SAAsB,EAAElF,GAAqB,EAAE;QAC7D,MAAM0D,cAAc,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;QAC3D,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAC7BwB,WACA;YACE,GAAGlF,GAAG;YACN,WAAWA,KAAK,aAAa;YAC7B,iBAAiBA,KAAK,mBAAmB;QAC3C,GACA0D;IAEJ;IAEA,MAAM,GAAG,GAAGmC,IAAmC,EAAE;QAC/C,OAAO,IAAI,CAAC,KAAK,IAAIA;IACvB;IAEA,MAAM,QAAQC,iBAAyB,EAEpC;QACD,MAAMC,SAASC,gBAAgBF,mBAAmB;QAClD,MAAMG,SAAS,IAAIC,aAAaH,QAAQ,UAC/B;gBAAE,OAAO,IAAI;gBAAE,QAAQ,EAAE;YAAC;QAEnC,MAAME,OAAO,GAAG;QAEhB,IAAIA,AAAkB,YAAlBA,OAAO,MAAM,EAAc;YAC7B,MAAME,SAASF,OAAO,cAAc,CACjC,MAAM,CAAC,CAAC5F,OAASA,AAAgB,YAAhBA,KAAK,MAAM,EAC5B,GAAG,CAAC,CAACA,OACG,CAAC,OAAO,EAAEA,KAAK,IAAI,CAAC,EAAE,EAAEA,KAAK,KAAK,EAAE,SAAS,EAErD,IAAI,CAAC;YACR,MAAM,IAAIoC,MAAM,CAAC,2CAA2C,EAAE0D,QAAQ;QACxE;QAEA,OAAO;YACL,QAAQF,OAAO,MAAM;QACvB;IACF;IAEA,MAAM,mBAAmBF,MAAc,EAAE;QACvC1E,OACE,IAAI,CAAC,SAAS,CAAC,kBAAkB,EACjC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC0E;IAC3C;IAOA,sBACEK,QAA+D,EACnD;QACZ,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAACA;QAG9B,OAAO;YACL,IAAI,CAAC,wBAAwB,CAACA;QAChC;IACF;IAMA,yBACEA,QAA+D,EACzD;QACN,MAAMC,QAAQ,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAACD;QAC/C,IAAIC,QAAQ,IACV,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAACA,OAAO;IAE3C;IAKA,2BAAiC;QAC/B,IAAI,CAAC,mBAAmB,GAAG,EAAE;IAC/B;IAEA,MAAM,UAAU;QAEd,IAAI,IAAI,CAAC,SAAS,EAChB;QAIF,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK;QAEhC,MAAMC,YAAY,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ;QACrD,IAAI,CAAC,UAAU,GAAGA;QAElB,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO;QAC5B,IAAI,CAAC,SAAS;QACd,IAAI,CAAC,SAAS,GAAG;IACnB;IAEA,MAAM,eACJvF,KAAc,EACdf,GAGC,EACD;QAEA,MAAMuG,SACJvG,KAAK,oBAAqB,MAAM,IAAI,CAAC,SAAS,CAAC,gBAAgB;QACjE,MAAMwG,MAAMC,KAAK,GAAG;QACpB,MAAMC,aAAaC,eAAe,MAAM,CAACJ,QAAQC;QAEjD,MAAMI,WAAoC;YACxC;gBACE,MAAM;gBACN,IAAIJ;gBACJE;YACF;SACD;QAED,MAAMrG,OAAyB;YAC7B,QAAQwG;YACR,MAAM;YACN,SAAS;YACT,QAAQ;YACRD;YACA,QAAQ;gBACN,OAAOJ;gBACP,KAAKA;gBACL,MAAM;YACR;YACA,OAAO;gBACL,SAASxG,KAAK,WAAW;YAC3B;YACA,UAAU,WAAa;QACzB;QAEA,MAAMG,gBAAgB,IAAI2G,cAAc;YACtC,IAAID;YACJ,SAASL;YACT,MAAM,CAAC,MAAM,EAAEzF,SAAS,YAAY;YACpC,aAAaf,KAAK,WAAW;YAC7B,OAAO;gBAACK;aAAK;QACf;QAEA,IAAI,CAAC,mBAAmB,CAACF;QAEzB,IAAI,CAAC,mBAAmB,CAACA;QACzB,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK;QAGhC,MAAM4G,aAAa,IAAI,CAAC,cAAc;QACtC,KAAK,MAAMX,YAAY,IAAI,CAAC,mBAAmB,CAC7C,IAAI;YACFA,SAASW;QACX,EAAE,OAAO5H,OAAO;YACdK,QAAQ,KAAK,CAAC,kCAAkCL;QAClD;IAEJ;IAKA,MAAM,cACJ4B,KAAc,EACdf,GAEC,EACD;QACA,MAAM,IAAI,CAAC,cAAc,CAACe,OAAOf;IACnC;IAEA,sBAAsB;QACpB,MAAM,EAAEgH,SAAS,EAAEC,gBAAgB,EAAEC,UAAU,EAAE,GAAG,IAAI,CAAC,IAAI;QAC7D,OAAO;YACLF;YACAC;YACA,YAAYC,cAAc,EAAE;QAC9B;IACF;IAMA,MAAM,oBAAmC;QACvC1K,MAAM;QACN,MAAM2K,UAAU,MAAM,IAAI,CAAC,gBAAgB;QAE3CA,QAAQ,SAAS,GAAG;QACpB,IAAI,CAAC,eAAe,GAAGA;QACvB3K,MAAM;IACR;IAKA,MAAM,sBAAqC;QACzCA,MAAM;QACN,IAAI,CAAC,eAAe,GAAGkC;QACvBlC,MAAM;IACR;IAKQ,mBAAmB4K,IAAc,EAKhC;QAGP,IAAIA,AAAe,SAAfA,KAAK,KAAK,EACZ,MAAM,IAAI3E,MACR;QAMJ,IACE2E,KAAK,KAAK,IACV,AAAsB,YAAtB,OAAOA,KAAK,KAAK,IACjBA,AAAe,SAAfA,KAAK,KAAK,IACV,CAACA,KAAK,KAAK,CAAC,EAAE,EAEd,MAAM,IAAI3E,MACR;QAMJ,MAAM4E,cAAcC,mBAClBF,KAAK,KAAK,EACVA,KAAK,OAAO,IAAI;QAGlB,IAAI,CAACC,aACH,OAAO;QAIT,IAAI,AAAuB,YAAvB,OAAOA,eAA4BA,AAAgB,SAAhBA,aAAsB;YAC3D,MAAME,KAAKF,YAAY,EAAE;YACzB,MAAMG,cAAcH,YAAY,QAAQ;YACxC,IAAII;YAEJ,IAAID,AAAgB9I,WAAhB8I,aACFC,gBAAgB;iBACX,IAAI,AAAuB,YAAvB,OAAOD,aAChBC,gBAAgBD;iBAEhB,MAAM,IAAI/E,MACR,CAAC,iEAAiE,EAAE,OAAO+E,aAAa;YAI5F,IAAI,CAAC3J,qBAAqB4J,gBACxB,MAAM,IAAIhF,MACR,CAAC,8BAA8B,EAAEzE,sBAAsB,gBAAgB,EAAEyJ,cAAc,CAAC,CAAC;YAI7F,MAAMC,aAAaD,AAAkB,gBAAlBA;YACnB,MAAME,cAAcF,AAAkB,iBAAlBA;YAEpB,OAAO;gBACLF;gBACA,SAAS,CAACI;gBACV,UAAUD;gBACV,WAAWC;YACb;QACF;QAEA,OAAO;IACT;IAEQ,mBAAmBC,KAAe,EAAY;QACpD,IAAI3H,aACF,MAAM,IAAIwC,MAAM;QAGlB,OAAOmF,MAAM,GAAG,CAAC,CAACC;YAChB,MAAMC,eAAezI,2BAAQwI;YAC7B,IAAI,CAACE,WAAWD,eACd,MAAM,IAAIrF,MACR,CAAC,gBAAgB,EAAEoF,KAAK,eAAe,EAAEC,aAAa,6BAA6B,EAAEE,QAAQ,GAAG,IAAI;YAGxG,OAAOF;QACT;IACF;IAEQ,mBAAmBF,KAAwB,EAAY;QAC7D,MAAMK,aAAaC,MAAM,OAAO,CAACN,SAASA,QAAQ;YAACA;SAAM;QACzD,OAAO,IAAI,CAAC,kBAAkB,CAACK;IACjC;IAOA,MAAM,WAAWE,OAAmC,EAAiB;QACnE,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,MAAM,IAAI1F,MAAM;QAGlB,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC0F;IAClC;IA70CA,YAAYC,iBAAgC,EAAEhB,IAAe,CAAE;QAxG/D;QAEA;QAEA;QAEA;QAEA;QAEA;QAEA;QAKA,kCAAU;QAEV;QAEA;QAEA,uBAAQ,uBAEJ,EAAE;QAmBN,oCAAY;QAEZ;QAKA,uBAAQ,mBAAR;QASA,uBAAQ,uBAAsB;QAE9B,uBAAQ,8BAA6B,IAAIzH;QAEzC,uBAAQ,mBAAR;QAEA,uBAAQ,mBAAR;QAkRA,uBAAQ,qBAAR;QA3OE,IAAI,CAAC,SAAS,GAAGyI;QAEjB,MAAMC,0BACJC,oBAAoB,yBAAyB,CAC3CC;QAGJ,IAAI,CAAC,IAAI,GAAGC,OAAO,MAAM,CACvB;YACE,gBAAgB;YAChB,sBAAsB;YACtB,oBAAoB;YACpB,WAAW;YACX,kBAAkB;QACpB,GACApB,QAAQ,CAAC,GACTA,MAAM,yBAAyB1I,UAC7B2J,AAA4B3J,WAA5B2J,2BACCI,OAAO,KAAK,CAACJ,2BAEZ,CAAC,IADD;YAAE,sBAAsBA;QAAwB;QAGtDK,8BAA8B,IAAI,CAAC,IAAI;QAEvC,MAAMC,uBACJ,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,eAAe;QACrD,IAAIA,AAAyBjK,WAAzBiK,sBAAoC;YACtC,IAAI,CAAC,IAAI,CAAC,YAAY,GAAGA;YACzB,IAAI,CAAC,IAAI,CAAC,eAAe,KAAKA;QAChC;QAEA,IACEvB,MAAM,eACL,CAA6B,YAA7B,OAAOA,MAAM,eAA4Bc,MAAM,OAAO,CAACd,KAAK,WAAW,IAExE,MAAM,IAAI3E,MACR,CAAC,2EAA2E,EAAE,OAAO2E,MAAM,aAAa;QAK5G,MAAMwB,kBAAkBxB,MAAM,eAAeA,MAAM;QACnD,IAAI,CAAC,kBAAkB,GAAGwB,kBACtB,IAAIC,mBAAmBzB,MAAM,aAAaA,MAAM,sBAChD0B;QAEJ,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc;QAE9C,IAAI,CAAC,OAAO,GAAG,IAAIC,QAAQ,UAClB,IAAI,CAAC,YAAY;QAI1B,MAAMC,iBAAiB,IAAI,CAAC,kBAAkB,CAAC5B,QAAQ,CAAC;QACxD,IAAI4B,gBACF,IAAI,CAAC,SAAS,GAAG,IAAIC,UACnBD,eAAe,EAAE,EACjBA,eAAe,OAAO,EACtBtK,QACA;YACE,UAAUsK,eAAe,QAAQ;YACjC,WAAWA,eAAe,SAAS;QACrC;QAIJ,MAAME,kBAAkB,IAAI,CAAC,SAAS,CAAC,WAAW;QAClD,IAAI,CAAC,eAAe,GAAG;eAAIA;YAAiBC;SAAoB;QAEhE,IAAI,CAAC,YAAY,GAAG,IAAIC,aAAa,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE;YACjE,WAAW,IAAI,CAAC,SAAS;YACzB,aAAa,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI;YAClD,sBAAsB,IAAI,CAAC,IAAI,CAAC,oBAAoB;YACpD,iBAAiB,IAAI,CAAC,IAAI,CAAC,eAAe;YAC1C,eAAe,IAAI,CAAC,IAAI,CAAC,aAAa;YACtC,aAAa,IAAI,CAAC,eAAe;YACjC,OAAO;gBACL,cAAc,OAAOvJ;oBACnB,MAAMM,gBAAgBN,OAAO,IAAI;oBACjC,IAAI,CAAC,mBAAmB,CAACM,eAAeN;oBAIxC,IAAI,CAAC,mBAAmB,CAACM;oBACzB,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK;oBAGhC,MAAM4G,aAAa,IAAI,CAAC,cAAc;oBACtC,KAAK,MAAMX,YAAY,IAAI,CAAC,mBAAmB,CAC7C,IAAI;wBACFA,SAASW,YAAY5G;oBACvB,EAAE,OAAOhB,OAAO;wBACdK,QAAQ,KAAK,CAAC,kCAAkCL;oBAClD;gBAEJ;YACF;QACF;QACA,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS;QAC1B,IAAI,CAAC,cAAc,GACjBiI,MAAM,kBAGNiC,kBAAkBjC,MAAM,UAAU,IAAI,CAAC,SAAS,CAAC,aAAa,IAAI;QAEpE,IAAI,CAAC,eAAe,GAAGkC,gBAAgB,MAAM,CAAC,IAAI,CAAC,cAAc,EAAG;YAClE,gBAAgB,IAAI,CAAC,IAAI,CAAC,cAAc;YACxC,sBAAsB,IAAI,CAAC,IAAI,CAAC,oBAAoB;YACpD,cAAc,IAAI,CAAC,IAAI,CAAC,YAAY;YACpC,oBAAoB,IAAI,CAAC,IAAI,CAAC,kBAAkB;YAChD,qBACE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,gBAAgB,KAAK,IAAI,CAAC,cAAc;QACzE;IACF;AA4tCF;AAttCE,iBAnOW/K,OAmOa,qBAAoB;AAC5C,iBApOWA,OAoOa,0BAAyB;AAutC5C,MAAMgL,cAAc,CACzBnB,mBACAhB,OAEO,IAAI7I,MAAM6J,mBAAmBhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"agent/task-cache.mjs","sources":["../../../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 '@/ai-model';\nimport type { ElementCacheFeature } from '@/types';\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: TUserPrompt;\n yamlWorkflow: string;\n}\n\nexport interface LocateCache {\n type: 'locate';\n prompt: TUserPrompt;\n cache?: ElementCacheFeature;\n /** @deprecated kept for backward compatibility */\n xpaths?: string[];\n}\n\nexport interface MatchCacheResult<T extends PlanningCache | LocateCache> {\n cacheContent: T;\n cacheUsable: boolean;\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 readOnlyMode: boolean; // a flag to indicate if the cache is in read-only mode\n\n writeOnlyMode: boolean; // a flag to indicate if the cache is in write-only mode\n\n private matchedCacheIndices: Set<string> = new Set(); // Track matched records\n\n constructor(\n cacheId: string,\n isCacheResultUsed: boolean,\n cacheFilePath?: string,\n options: { readOnly?: boolean; writeOnly?: boolean } = {},\n ) {\n assert(cacheId, 'cacheId is required');\n let safeCacheId = replaceIllegalPathCharsAndSpace(cacheId);\n const cacheMaxFilenameLength =\n globalConfigManager.getEnvConfigValueAsNumber(\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 const readOnlyMode = Boolean(options?.readOnly);\n const writeOnlyMode = Boolean(options?.writeOnly);\n\n if (readOnlyMode && writeOnlyMode) {\n throw new Error('TaskCache cannot be both read-only and write-only');\n }\n\n this.isCacheResultUsed = writeOnlyMode ? false : isCacheResultUsed;\n this.readOnlyMode = readOnlyMode;\n this.writeOnlyMode = writeOnlyMode;\n\n let cacheContent;\n if (this.cacheFilePath && !this.writeOnlyMode) {\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.isCacheResultUsed\n ? this.cache.caches.length\n : 0;\n }\n\n matchCache(\n prompt: TUserPrompt,\n type: 'plan' | 'locate',\n ): MatchCacheResult<PlanningCache | LocateCache> | undefined {\n if (!this.isCacheResultUsed) {\n return undefined;\n }\n // Find the first unused matching cache\n const promptStr =\n typeof prompt === 'string' ? prompt : JSON.stringify(prompt);\n for (let i = 0; i < this.cacheOriginalLength; i++) {\n const item = this.cache.caches[i];\n const key = `${type}:${promptStr}:${i}`;\n if (\n item.type === type &&\n isDeepStrictEqual(item.prompt, prompt) &&\n !this.matchedCacheIndices.has(key)\n ) {\n if (item.type === 'locate') {\n const locateItem = item as LocateCache;\n if (!locateItem.cache && Array.isArray(locateItem.xpaths)) {\n locateItem.cache = { xpaths: locateItem.xpaths };\n }\n if ('xpaths' in locateItem) {\n locateItem.xpaths = undefined;\n }\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 cacheUsable: true,\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\n if (this.readOnlyMode) {\n debug(\n 'read-only mode, cache updated in memory but not flushed to file',\n );\n return;\n }\n\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(\n prompt: TUserPrompt,\n ): MatchCacheResult<PlanningCache> | undefined {\n const result = this.matchCache(prompt, 'plan') as\n | MatchCacheResult<PlanningCache>\n | undefined;\n if (!result) return undefined;\n // Guard against stale cache files written before the write-side fix\n const yamlWorkflow = result.cacheContent.yamlWorkflow;\n if (!yamlWorkflow?.trim()) {\n debug(\n 'plan cache matched but yamlWorkflow is empty, treat as cache miss',\n );\n return {\n ...result,\n cacheUsable: false,\n };\n }\n try {\n const parsed = yaml.load(yamlWorkflow) as any;\n const hasNonEmptyFlow = parsed?.tasks?.some(\n (task: any) => Array.isArray(task.flow) && task.flow.length > 0,\n );\n if (!hasNonEmptyFlow) {\n debug('plan cache matched but flow is empty, treat as cache miss');\n return {\n ...result,\n cacheUsable: false,\n };\n }\n } catch {\n debug(\n 'plan cache matched but yamlWorkflow is invalid, treat as cache miss',\n );\n return {\n ...result,\n cacheUsable: false,\n };\n }\n return result;\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\n if (this.readOnlyMode) {\n debug('read-only mode, cache appended to memory but not flushed to file');\n return;\n }\n\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(options?: { cleanUnused?: boolean }) {\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 // Clean unused caches if requested\n if (options?.cleanUnused) {\n // Skip cleaning in write-only mode or when cache is not used\n if (this.isCacheResultUsed) {\n const originalLength = this.cache.caches.length;\n\n // Collect indices of used caches\n const usedIndices = new Set<number>();\n for (const key of this.matchedCacheIndices) {\n // key format: \"type:prompt:index\"\n const parts = key.split(':');\n const index = Number.parseInt(parts[parts.length - 1], 10);\n if (!Number.isNaN(index)) {\n usedIndices.add(index);\n }\n }\n\n // Filter: keep used caches and newly added caches\n this.cache.caches = this.cache.caches.filter((_, index) => {\n const isUsed = usedIndices.has(index);\n const isNew = index >= this.cacheOriginalLength;\n return isUsed || isNew;\n });\n\n const removedCount = originalLength - this.cache.caches.length;\n if (removedCount > 0) {\n debug('cleaned %d unused cache record(s)', removedCount);\n } else {\n debug('no unused cache to clean');\n }\n } else {\n debug('skip cleaning: cache is not used for reading');\n }\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 // Create a sorted copy for writing to disk while keeping in-memory order unchanged\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, { lineWidth: -1 });\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 const locateCache = cache as LocateCache;\n locateCache.cache = newRecord.cache;\n if ('xpaths' in locateCache) {\n locateCache.xpaths = undefined;\n }\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","promptStr","JSON","i","item","key","isDeepStrictEqual","locateItem","Array","undefined","cb","result","yamlWorkflow","parsed","yaml","hasNonEmptyFlow","task","cache","cacheFile","assert","existsSync","jsonTypeCacheFile","console","data","readFileSync","jsonData","version","getMidsceneVersion","semver","err","options","originalLength","usedIndices","Set","parts","index","Number","_","isUsed","isNew","removedCount","dir","dirname","mkdirSync","sortedCaches","a","b","cacheToWrite","yamlData","writeFileSync","newRecord","cachedRecord","locateCache","cacheId","isCacheResultUsed","cacheFilePath","safeCacheId","replaceIllegalPathCharsAndSpace","cacheMaxFilenameLength","globalConfigManager","MIDSCENE_CACHE_MAX_FILENAME_LENGTH","Buffer","prefix","hash","generateHashId","ifInBrowser","ifInWorker","join","getMidsceneRunSubDir","readOnlyMode","Boolean","writeOnlyMode","Error","cacheContent"],"mappings":"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"}
1
+ {"version":3,"file":"agent/task-cache.mjs","sources":["../../../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 '@/ai-model';\nimport type { ElementCacheFeature } from '@/types';\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 cache?: ElementCacheFeature;\n /** @deprecated kept for backward compatibility */\n xpaths?: string[];\n}\n\nexport interface MatchCacheResult<T extends PlanningCache | LocateCache> {\n cacheContent: T;\n cacheUsable: boolean;\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 readOnlyMode: boolean; // a flag to indicate if the cache is in read-only mode\n\n writeOnlyMode: boolean; // a flag to indicate if the cache is in write-only mode\n\n private matchedCacheIndices: Set<string> = new Set(); // Track matched records\n\n constructor(\n cacheId: string,\n isCacheResultUsed: boolean,\n cacheFilePath?: string,\n options: { readOnly?: boolean; writeOnly?: boolean } = {},\n ) {\n assert(cacheId, 'cacheId is required');\n let safeCacheId = replaceIllegalPathCharsAndSpace(cacheId);\n const cacheMaxFilenameLength =\n globalConfigManager.getEnvConfigValueAsNumber(\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 const readOnlyMode = Boolean(options?.readOnly);\n const writeOnlyMode = Boolean(options?.writeOnly);\n\n if (readOnlyMode && writeOnlyMode) {\n throw new Error('TaskCache cannot be both read-only and write-only');\n }\n\n this.isCacheResultUsed = writeOnlyMode ? false : isCacheResultUsed;\n this.readOnlyMode = readOnlyMode;\n this.writeOnlyMode = writeOnlyMode;\n\n let cacheContent;\n if (this.cacheFilePath && !this.writeOnlyMode) {\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.isCacheResultUsed\n ? this.cache.caches.length\n : 0;\n }\n\n matchCache(\n prompt: TUserPrompt,\n type: 'plan' | 'locate',\n ): MatchCacheResult<PlanningCache | LocateCache> | undefined {\n if (!this.isCacheResultUsed) {\n return undefined;\n }\n // Find the first unused matching cache\n const promptStr =\n typeof prompt === 'string' ? prompt : JSON.stringify(prompt);\n for (let i = 0; i < this.cacheOriginalLength; i++) {\n const item = this.cache.caches[i];\n const key = `${type}:${promptStr}:${i}`;\n if (\n item.type === type &&\n isDeepStrictEqual(item.prompt, prompt) &&\n !this.matchedCacheIndices.has(key)\n ) {\n if (item.type === 'locate') {\n const locateItem = item as LocateCache;\n if (!locateItem.cache && Array.isArray(locateItem.xpaths)) {\n locateItem.cache = { xpaths: locateItem.xpaths };\n }\n if ('xpaths' in locateItem) {\n locateItem.xpaths = undefined;\n }\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 cacheUsable: true,\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\n if (this.readOnlyMode) {\n debug(\n 'read-only mode, cache updated in memory but not flushed to file',\n );\n return;\n }\n\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 const result = this.matchCache(prompt, 'plan') as\n | MatchCacheResult<PlanningCache>\n | undefined;\n if (!result) return undefined;\n // Guard against stale cache files written before the write-side fix\n const yamlWorkflow = result.cacheContent.yamlWorkflow;\n if (!yamlWorkflow?.trim()) {\n debug(\n 'plan cache matched but yamlWorkflow is empty, treat as cache miss',\n );\n return {\n ...result,\n cacheUsable: false,\n };\n }\n try {\n const parsed = yaml.load(yamlWorkflow) as any;\n const hasNonEmptyFlow = parsed?.tasks?.some(\n (task: any) => Array.isArray(task.flow) && task.flow.length > 0,\n );\n if (!hasNonEmptyFlow) {\n debug('plan cache matched but flow is empty, treat as cache miss');\n return {\n ...result,\n cacheUsable: false,\n };\n }\n } catch {\n debug(\n 'plan cache matched but yamlWorkflow is invalid, treat as cache miss',\n );\n return {\n ...result,\n cacheUsable: false,\n };\n }\n return result;\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\n if (this.readOnlyMode) {\n debug('read-only mode, cache appended to memory but not flushed to file');\n return;\n }\n\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(options?: { cleanUnused?: boolean }) {\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 // Clean unused caches if requested\n if (options?.cleanUnused) {\n // Skip cleaning in write-only mode or when cache is not used\n if (this.isCacheResultUsed) {\n const originalLength = this.cache.caches.length;\n\n // Collect indices of used caches\n const usedIndices = new Set<number>();\n for (const key of this.matchedCacheIndices) {\n // key format: \"type:prompt:index\"\n const parts = key.split(':');\n const index = Number.parseInt(parts[parts.length - 1], 10);\n if (!Number.isNaN(index)) {\n usedIndices.add(index);\n }\n }\n\n // Filter: keep used caches and newly added caches\n this.cache.caches = this.cache.caches.filter((_, index) => {\n const isUsed = usedIndices.has(index);\n const isNew = index >= this.cacheOriginalLength;\n return isUsed || isNew;\n });\n\n const removedCount = originalLength - this.cache.caches.length;\n if (removedCount > 0) {\n debug('cleaned %d unused cache record(s)', removedCount);\n } else {\n debug('no unused cache to clean');\n }\n } else {\n debug('skip cleaning: cache is not used for reading');\n }\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 // Create a sorted copy for writing to disk while keeping in-memory order unchanged\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, { lineWidth: -1 });\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 const locateCache = cache as LocateCache;\n locateCache.cache = newRecord.cache;\n if ('xpaths' in locateCache) {\n locateCache.xpaths = undefined;\n }\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","promptStr","JSON","i","item","key","isDeepStrictEqual","locateItem","Array","undefined","cb","result","yamlWorkflow","parsed","yaml","hasNonEmptyFlow","task","cache","cacheFile","assert","existsSync","jsonTypeCacheFile","console","data","readFileSync","jsonData","version","getMidsceneVersion","semver","err","options","originalLength","usedIndices","Set","parts","index","Number","_","isUsed","isNew","removedCount","dir","dirname","mkdirSync","sortedCaches","a","b","cacheToWrite","yamlData","writeFileSync","newRecord","cachedRecord","locateCache","cacheId","isCacheResultUsed","cacheFilePath","safeCacheId","replaceIllegalPathCharsAndSpace","cacheMaxFilenameLength","globalConfigManager","MIDSCENE_CACHE_MAX_FILENAME_LENGTH","Buffer","prefix","hash","generateHashId","ifInBrowser","ifInWorker","join","getMidsceneRunSubDir","readOnlyMode","Boolean","writeOnlyMode","Error","cacheContent"],"mappings":"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"}