@midscene/core 1.10.8-beta-20260723115348.0 → 1.10.8

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 (86) hide show
  1. package/dist/es/agent/agent.mjs +66 -26
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/file-chooser.mjs +82 -0
  4. package/dist/es/agent/file-chooser.mjs.map +1 -0
  5. package/dist/es/agent/prompt-context.mjs +12 -1
  6. package/dist/es/agent/prompt-context.mjs.map +1 -1
  7. package/dist/es/agent/task-builder.mjs +11 -2
  8. package/dist/es/agent/task-builder.mjs.map +1 -1
  9. package/dist/es/agent/tasks.mjs +4 -16
  10. package/dist/es/agent/tasks.mjs.map +1 -1
  11. package/dist/es/agent/ui-utils.mjs +1 -0
  12. package/dist/es/agent/ui-utils.mjs.map +1 -1
  13. package/dist/es/agent/utils.mjs +1 -1
  14. package/dist/es/ai-model/inspect.mjs +1 -1
  15. package/dist/es/ai-model/inspect.mjs.map +1 -1
  16. package/dist/es/ai-model/llm-planning.mjs +2 -1
  17. package/dist/es/ai-model/llm-planning.mjs.map +1 -1
  18. package/dist/es/ai-model/model-adapter/chat-completion.mjs +3 -1
  19. package/dist/es/ai-model/model-adapter/chat-completion.mjs.map +1 -1
  20. package/dist/es/ai-model/models/kimi.mjs +35 -0
  21. package/dist/es/ai-model/models/kimi.mjs.map +1 -1
  22. package/dist/es/ai-model/prompt/extraction.mjs +4 -2
  23. package/dist/es/ai-model/prompt/extraction.mjs.map +1 -1
  24. package/dist/es/ai-model/service-caller/codex-app-server.mjs +22 -14
  25. package/dist/es/ai-model/service-caller/codex-app-server.mjs.map +1 -1
  26. package/dist/es/ai-model/service-caller/index.mjs +15 -14
  27. package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
  28. package/dist/es/ai-model/workflows/planning/custom-planning.mjs.map +1 -1
  29. package/dist/es/device/index.mjs +21 -1
  30. package/dist/es/device/index.mjs.map +1 -1
  31. package/dist/es/report.mjs +1 -0
  32. package/dist/es/report.mjs.map +1 -1
  33. package/dist/es/types.mjs.map +1 -1
  34. package/dist/es/utils.mjs +2 -2
  35. package/dist/es/yaml/utils.mjs +9 -1
  36. package/dist/es/yaml/utils.mjs.map +1 -1
  37. package/dist/lib/agent/agent.js +63 -23
  38. package/dist/lib/agent/agent.js.map +1 -1
  39. package/dist/lib/agent/file-chooser.js +125 -0
  40. package/dist/lib/agent/file-chooser.js.map +1 -0
  41. package/dist/lib/agent/prompt-context.js +14 -0
  42. package/dist/lib/agent/prompt-context.js.map +1 -1
  43. package/dist/lib/agent/task-builder.js +11 -2
  44. package/dist/lib/agent/task-builder.js.map +1 -1
  45. package/dist/lib/agent/tasks.js +6 -18
  46. package/dist/lib/agent/tasks.js.map +1 -1
  47. package/dist/lib/agent/ui-utils.js +1 -0
  48. package/dist/lib/agent/ui-utils.js.map +1 -1
  49. package/dist/lib/agent/utils.js +1 -1
  50. package/dist/lib/ai-model/inspect.js +1 -1
  51. package/dist/lib/ai-model/inspect.js.map +1 -1
  52. package/dist/lib/ai-model/llm-planning.js +2 -1
  53. package/dist/lib/ai-model/llm-planning.js.map +1 -1
  54. package/dist/lib/ai-model/model-adapter/chat-completion.js +3 -1
  55. package/dist/lib/ai-model/model-adapter/chat-completion.js.map +1 -1
  56. package/dist/lib/ai-model/models/kimi.js +35 -0
  57. package/dist/lib/ai-model/models/kimi.js.map +1 -1
  58. package/dist/lib/ai-model/prompt/extraction.js +4 -2
  59. package/dist/lib/ai-model/prompt/extraction.js.map +1 -1
  60. package/dist/lib/ai-model/service-caller/codex-app-server.js +22 -14
  61. package/dist/lib/ai-model/service-caller/codex-app-server.js.map +1 -1
  62. package/dist/lib/ai-model/service-caller/index.js +15 -14
  63. package/dist/lib/ai-model/service-caller/index.js.map +1 -1
  64. package/dist/lib/ai-model/workflows/planning/custom-planning.js.map +1 -1
  65. package/dist/lib/device/index.js +27 -1
  66. package/dist/lib/device/index.js.map +1 -1
  67. package/dist/lib/report.js +1 -0
  68. package/dist/lib/report.js.map +1 -1
  69. package/dist/lib/types.js.map +1 -1
  70. package/dist/lib/utils.js +2 -2
  71. package/dist/lib/yaml/utils.js +9 -1
  72. package/dist/lib/yaml/utils.js.map +1 -1
  73. package/dist/types/agent/agent.d.ts +5 -2
  74. package/dist/types/agent/file-chooser.d.ts +19 -0
  75. package/dist/types/agent/prompt-context.d.ts +1 -0
  76. package/dist/types/agent/tasks.d.ts +1 -1
  77. package/dist/types/ai-model/model-adapter/types.d.ts +9 -0
  78. package/dist/types/ai-model/models/kimi.d.ts +18 -0
  79. package/dist/types/ai-model/models/registry.d.ts +18 -0
  80. package/dist/types/ai-model/prompt/extraction.d.ts +1 -1
  81. package/dist/types/ai-model/service-caller/codex-app-server.d.ts +5 -1
  82. package/dist/types/device/device-options.d.ts +7 -0
  83. package/dist/types/device/index.d.ts +11 -0
  84. package/dist/types/types.d.ts +6 -4
  85. package/dist/types/yaml.d.ts +9 -1
  86. package/package.json +2 -2
@@ -1,6 +1,7 @@
1
1
  import { getDebug } from "@midscene/shared/logger";
2
2
  import { assert } from "@midscene/shared/utils";
3
3
  import js_yaml from "js-yaml";
4
+ import { buildLocatePromptWithContext } from "../agent/prompt-context.mjs";
4
5
  const debugUtils = getDebug('yaml:utils');
5
6
  const topLevelTasksPattern = /^tasks\s*:/;
6
7
  const topLevelYamlKeyPattern = /^[^\s#][^:]*:/;
@@ -140,6 +141,9 @@ function buildDetailedLocateParam(locatePrompt, opt) {
140
141
  prompt = prompt || opt.prompt;
141
142
  }
142
143
  if (!prompt) return void debugUtils('no prompt, will return undefined in buildDetailedLocateParam', opt);
144
+ const promptDisplay = 'string' == typeof prompt ? prompt : prompt.prompt;
145
+ const context = opt?.context?.trim() || void 0;
146
+ prompt = buildLocatePromptWithContext(prompt, opt?.context);
143
147
  const multimodalPrompt = extractMultimodalPrompt(opt);
144
148
  if (multimodalPrompt) prompt = 'string' == typeof prompt ? {
145
149
  prompt,
@@ -150,6 +154,10 @@ function buildDetailedLocateParam(locatePrompt, opt) {
150
154
  };
151
155
  return {
152
156
  prompt,
157
+ ...context ? {
158
+ promptDisplay,
159
+ context
160
+ } : {},
153
161
  deepLocate,
154
162
  cacheable,
155
163
  xpath
@@ -163,7 +171,7 @@ function buildDetailedLocateParamAndRestParams(locatePrompt, opt, excludeKeys =
163
171
  const allKeys = Object.keys(opt);
164
172
  const locateParamKeys = Object.keys(locateParam || {});
165
173
  const multimodalPromptKeys = 'object' == typeof locateParam?.prompt && locateParam?.prompt !== null ? Object.keys(multimodalPrompt || {}) : [];
166
- for (const key of allKeys)if (!locateParamKeys.includes(key) && !multimodalPromptKeys.includes(key) && !excludeKeys.includes(key) && 'locate' !== key) restParams[key] = opt[key];
174
+ for (const key of allKeys)if (!locateParamKeys.includes(key) && 'context' !== key && 'deepThink' !== key && !multimodalPromptKeys.includes(key) && !excludeKeys.includes(key) && 'locate' !== key) restParams[key] = opt[key];
167
175
  }
168
176
  return {
169
177
  locateParam,
@@ -1 +1 @@
1
- {"version":3,"file":"yaml/utils.mjs","sources":["../../../src/yaml/utils.ts"],"sourcesContent":["import type { TMultimodalPrompt, TUserPrompt } from '@/common';\nimport type {\n DetailedLocateParam,\n LocateOption,\n MidsceneYamlScript,\n MidsceneYamlScriptWebEnv,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\n\nconst debugUtils = getDebug('yaml:utils');\n\nconst topLevelTasksPattern = /^tasks\\s*:/;\nconst topLevelYamlKeyPattern = /^[^\\s#][^:]*:/;\n\nexport type WebTargetSource = 'page' | 'browser' | 'web' | 'target';\n\nexport type ResolvedWebTarget = {\n source: WebTargetSource;\n target: Partial<MidsceneYamlScriptWebEnv> & { mode: 'page' | 'browser' };\n mode: 'page' | 'browser';\n};\n\nexport type WebTargetConfig = Partial<\n Record<WebTargetSource, Partial<MidsceneYamlScriptWebEnv>>\n>;\n\nconst webTargetSources: WebTargetSource[] = [\n 'page',\n 'browser',\n 'web',\n 'target',\n];\n\nexport function resolveWebTarget(\n config: WebTargetConfig,\n): ResolvedWebTarget | undefined {\n const entries = webTargetSources\n .map((source) => [source, config[source]] as const)\n .filter(\n (\n entry,\n ): entry is readonly [\n WebTargetSource,\n Partial<MidsceneYamlScriptWebEnv>,\n ] => typeof entry[1] !== 'undefined',\n );\n\n if (entries.length === 0) {\n return undefined;\n }\n\n if (entries.length > 1) {\n const specifiedTargets = entries.map(([source]) => source);\n throw new Error(\n `[midscene] Only one web target can be specified, but found multiple: ${specifiedTargets.join(\n ', ',\n )}. Please specify only one of: page, browser, web, or target.`,\n );\n }\n\n const [source, target] = entries[0];\n const explicitMode = target.mode;\n if (\n typeof explicitMode !== 'undefined' &&\n explicitMode !== 'page' &&\n explicitMode !== 'browser'\n ) {\n throw new Error(\n `[midscene] web target mode must be either \"page\" or \"browser\", but got \"${explicitMode}\".`,\n );\n }\n\n if (source === 'page' && explicitMode === 'browser') {\n throw new Error(\n '[midscene] page target cannot use mode: browser. Use browser: instead.',\n );\n }\n\n if (source === 'browser' && explicitMode === 'page') {\n throw new Error(\n '[midscene] browser target cannot use mode: page. Use page: instead.',\n );\n }\n\n const mode =\n source === 'page'\n ? 'page'\n : source === 'browser'\n ? 'browser'\n : (explicitMode ?? 'page');\n\n if (mode === 'page' && target.autoFollowNewPage) {\n throw new Error(\n '[midscene] autoFollowNewPage requires browser mode. Use browser: or web.mode: browser.',\n );\n }\n\n if (\n mode === 'browser' &&\n typeof target.forceSameTabNavigation !== 'undefined'\n ) {\n throw new Error(\n '[midscene] forceSameTabNavigation cannot be used in browser mode. Use page: or web.mode: page when same-tab navigation is required.',\n );\n }\n\n return {\n source,\n mode,\n target: {\n ...target,\n mode,\n },\n };\n}\n\nfunction interpolateEnvVarRefs(\n value: string,\n keepUnresolvedRefs = false,\n): string {\n let result = '';\n let lastIndex = 0;\n let searchFrom = 0;\n\n while (searchFrom < value.length) {\n const start = value.indexOf('${', searchFrom);\n if (start === -1) {\n break;\n }\n\n const end = value.indexOf('}', start + 2);\n if (end === -1) {\n break;\n }\n\n const rawName = value.slice(start + 2, end);\n if (!rawName) {\n searchFrom = end + 1;\n continue;\n }\n\n result += value.slice(lastIndex, start);\n const envVar = rawName.trim();\n const envValue = process.env[envVar];\n if (envValue === undefined) {\n if (keepUnresolvedRefs) {\n result += value.slice(start, end + 1);\n } else {\n throw new Error(`Environment variable \"${envVar}\" is not defined`);\n }\n } else {\n result += envValue;\n }\n lastIndex = end + 1;\n searchFrom = end + 1;\n }\n\n return result + value.slice(lastIndex);\n}\n\nconst multimodalLocateOptionFieldMap: Record<keyof TMultimodalPrompt, true> = {\n images: true,\n convertHttpImage2Base64: true,\n};\n\nconst multimodalLocateOptionKeys = Object.keys(\n multimodalLocateOptionFieldMap,\n) as Array<keyof TMultimodalPrompt>;\n\nfunction extractMultimodalPrompt(\n opt?: LocateOption,\n): Partial<TMultimodalPrompt> | undefined {\n if (typeof opt !== 'object' || opt === null) {\n return undefined;\n }\n\n const entries = multimodalLocateOptionKeys\n .map((key) => [key, opt[key]] as const)\n .filter(([, value]) => value !== undefined);\n\n return entries.length\n ? (Object.fromEntries(entries) as Partial<TMultimodalPrompt>)\n : undefined;\n}\n\nexport function interpolateEnvVars(content: string): string {\n // Process line by line to skip commented lines\n const lines = content.split('\\n');\n const processedLines = lines.map((line) => {\n // Check if the line is a YAML comment (starts with # after optional whitespace)\n const trimmedLine = line.trimStart();\n if (trimmedLine.startsWith('#')) {\n // Skip interpolation for comment lines\n return line;\n }\n\n // Process environment variables for non-comment lines\n return interpolateEnvVarRefs(line);\n });\n\n return processedLines.join('\\n');\n}\n\nfunction interpolateYamlScriptEnvVars(content: string): string {\n let inTopLevelTasksBlock = false;\n\n return content\n .split('\\n')\n .map((line) => {\n const trimmedLine = line.trimStart();\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n return line;\n }\n\n const indentSize = line.length - trimmedLine.length;\n if (indentSize === 0) {\n if (topLevelTasksPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = true;\n return line;\n }\n\n if (topLevelYamlKeyPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = false;\n }\n }\n\n return interpolateEnvVarRefs(line, inTopLevelTasksBlock);\n })\n .join('\\n');\n}\n\nexport function parseYamlScript(\n content: string,\n filePath?: string,\n): MidsceneYamlScript {\n let processedContent = content;\n if (content.indexOf('android') !== -1 && content.match(/deviceId:\\s*(\\d+)/)) {\n let matchedDeviceId;\n processedContent = content.replace(\n /deviceId:\\s*(\\d+)/g,\n (match, deviceId) => {\n matchedDeviceId = deviceId;\n return `deviceId: '${deviceId}'`;\n },\n );\n console.warn(\n `please use string-style deviceId in yaml script, for example: deviceId: \"${matchedDeviceId}\"`,\n );\n }\n const interpolatedContent = interpolateYamlScriptEnvVars(processedContent);\n const obj = yaml.load(interpolatedContent, {\n schema: yaml.JSON_SCHEMA,\n }) as MidsceneYamlScript;\n\n const pathTip = filePath ? `, failed to load ${filePath}` : '';\n resolveWebTarget(obj);\n assert(obj.tasks, `property \"tasks\" is required in yaml script ${pathTip}`);\n assert(\n Array.isArray(obj.tasks),\n `property \"tasks\" must be an array in yaml script, but got ${obj.tasks}`,\n );\n return obj;\n}\n\nexport function buildDetailedLocateParam(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n): DetailedLocateParam | undefined {\n debugUtils('will call buildDetailedLocateParam', locatePrompt, opt);\n // Normalize object-form TUserPrompt: when the object only contains a\n // `prompt` string (no multimodal fields like `images`), unwrap it to\n // avoid double nesting like { prompt: { prompt: '...' } }.\n let normalizedLocatePrompt: TUserPrompt = locatePrompt;\n if (\n typeof locatePrompt === 'object' &&\n locatePrompt !== null &&\n 'prompt' in locatePrompt\n ) {\n const { prompt: innerPrompt, ...rest } = locatePrompt;\n const hasMultimodalFields = Object.keys(rest).length > 0;\n normalizedLocatePrompt = hasMultimodalFields ? locatePrompt : innerPrompt;\n }\n\n let prompt = normalizedLocatePrompt || opt?.prompt || (opt as any)?.locate; // as a shortcut\n let deepLocate = false;\n let cacheable = true;\n let xpath = undefined;\n\n if (typeof opt === 'object' && opt !== null) {\n // Backward-compatible: accept `deepThink` as a deprecated alias for `deepLocate`.\n // All downstream code works on `deepLocate` only; the compatibility resolution\n // is intentionally kept here at the entry point so it does not bleed through\n // the rest of the call stack.\n deepLocate = opt.deepLocate ?? opt.deepThink ?? false;\n cacheable = opt.cacheable ?? true;\n xpath = opt.xpath;\n if (locatePrompt && opt.prompt && locatePrompt !== opt.prompt) {\n console.warn(\n 'conflict prompt for item',\n locatePrompt,\n opt,\n 'maybe you put the prompt in the wrong place',\n );\n }\n prompt = prompt || opt.prompt;\n }\n\n if (!prompt) {\n debugUtils(\n 'no prompt, will return undefined in buildDetailedLocateParam',\n opt,\n );\n return undefined;\n }\n\n const multimodalPrompt = extractMultimodalPrompt(opt);\n if (multimodalPrompt) {\n prompt =\n typeof prompt === 'string'\n ? {\n prompt,\n ...multimodalPrompt,\n }\n : {\n ...prompt,\n ...multimodalPrompt,\n };\n }\n\n return {\n prompt,\n deepLocate,\n cacheable,\n xpath,\n };\n}\n\nexport function buildDetailedLocateParamAndRestParams(\n locatePrompt: TUserPrompt,\n opt: LocateOption | undefined,\n excludeKeys: string[] = [],\n): {\n locateParam: DetailedLocateParam | undefined;\n restParams: Record<string, any>;\n} {\n const multimodalPrompt = extractMultimodalPrompt(opt);\n const locateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n // Extract all keys from opt except the ones already included in locateParam\n const restParams: Record<string, any> = {};\n\n if (typeof opt === 'object' && opt !== null) {\n // Get all keys from opt\n const allKeys = Object.keys(opt);\n\n // Keys already included in locateParam: prompt, deepLocate, cacheable, xpath\n const locateParamKeys = Object.keys(locateParam || {});\n const multimodalPromptKeys =\n typeof locateParam?.prompt === 'object' && locateParam?.prompt !== null\n ? Object.keys(multimodalPrompt || {})\n : [];\n\n // Extract all other keys\n for (const key of allKeys) {\n if (\n !locateParamKeys.includes(key) &&\n !multimodalPromptKeys.includes(key) &&\n !excludeKeys.includes(key) &&\n key !== 'locate'\n ) {\n restParams[key] = opt[key as keyof LocateOption];\n }\n }\n }\n\n return {\n locateParam,\n restParams,\n };\n}\n"],"names":["debugUtils","getDebug","topLevelTasksPattern","topLevelYamlKeyPattern","webTargetSources","resolveWebTarget","config","entries","source","entry","specifiedTargets","Error","target","explicitMode","mode","interpolateEnvVarRefs","value","keepUnresolvedRefs","result","lastIndex","searchFrom","start","end","rawName","envVar","envValue","process","undefined","multimodalLocateOptionFieldMap","multimodalLocateOptionKeys","Object","extractMultimodalPrompt","opt","key","interpolateEnvVars","content","lines","processedLines","line","trimmedLine","interpolateYamlScriptEnvVars","inTopLevelTasksBlock","indentSize","parseYamlScript","filePath","processedContent","matchedDeviceId","match","deviceId","console","interpolatedContent","obj","yaml","pathTip","assert","Array","buildDetailedLocateParam","locatePrompt","normalizedLocatePrompt","innerPrompt","rest","hasMultimodalFields","prompt","deepLocate","cacheable","xpath","multimodalPrompt","buildDetailedLocateParamAndRestParams","excludeKeys","locateParam","restParams","allKeys","locateParamKeys","multimodalPromptKeys"],"mappings":"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"}
1
+ {"version":3,"file":"yaml/utils.mjs","sources":["../../../src/yaml/utils.ts"],"sourcesContent":["import type { TMultimodalPrompt, TUserPrompt } from '@/common';\nimport type {\n DetailedLocateParam,\n LocateOption,\n MidsceneYamlScript,\n MidsceneYamlScriptWebEnv,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\nimport { buildLocatePromptWithContext } from '../agent/prompt-context';\n\nconst debugUtils = getDebug('yaml:utils');\n\nconst topLevelTasksPattern = /^tasks\\s*:/;\nconst topLevelYamlKeyPattern = /^[^\\s#][^:]*:/;\n\nexport type WebTargetSource = 'page' | 'browser' | 'web' | 'target';\n\nexport type ResolvedWebTarget = {\n source: WebTargetSource;\n target: Partial<MidsceneYamlScriptWebEnv> & { mode: 'page' | 'browser' };\n mode: 'page' | 'browser';\n};\n\nexport type WebTargetConfig = Partial<\n Record<WebTargetSource, Partial<MidsceneYamlScriptWebEnv>>\n>;\n\nconst webTargetSources: WebTargetSource[] = [\n 'page',\n 'browser',\n 'web',\n 'target',\n];\n\nexport function resolveWebTarget(\n config: WebTargetConfig,\n): ResolvedWebTarget | undefined {\n const entries = webTargetSources\n .map((source) => [source, config[source]] as const)\n .filter(\n (\n entry,\n ): entry is readonly [\n WebTargetSource,\n Partial<MidsceneYamlScriptWebEnv>,\n ] => typeof entry[1] !== 'undefined',\n );\n\n if (entries.length === 0) {\n return undefined;\n }\n\n if (entries.length > 1) {\n const specifiedTargets = entries.map(([source]) => source);\n throw new Error(\n `[midscene] Only one web target can be specified, but found multiple: ${specifiedTargets.join(\n ', ',\n )}. Please specify only one of: page, browser, web, or target.`,\n );\n }\n\n const [source, target] = entries[0];\n const explicitMode = target.mode;\n if (\n typeof explicitMode !== 'undefined' &&\n explicitMode !== 'page' &&\n explicitMode !== 'browser'\n ) {\n throw new Error(\n `[midscene] web target mode must be either \"page\" or \"browser\", but got \"${explicitMode}\".`,\n );\n }\n\n if (source === 'page' && explicitMode === 'browser') {\n throw new Error(\n '[midscene] page target cannot use mode: browser. Use browser: instead.',\n );\n }\n\n if (source === 'browser' && explicitMode === 'page') {\n throw new Error(\n '[midscene] browser target cannot use mode: page. Use page: instead.',\n );\n }\n\n const mode =\n source === 'page'\n ? 'page'\n : source === 'browser'\n ? 'browser'\n : (explicitMode ?? 'page');\n\n if (mode === 'page' && target.autoFollowNewPage) {\n throw new Error(\n '[midscene] autoFollowNewPage requires browser mode. Use browser: or web.mode: browser.',\n );\n }\n\n if (\n mode === 'browser' &&\n typeof target.forceSameTabNavigation !== 'undefined'\n ) {\n throw new Error(\n '[midscene] forceSameTabNavigation cannot be used in browser mode. Use page: or web.mode: page when same-tab navigation is required.',\n );\n }\n\n return {\n source,\n mode,\n target: {\n ...target,\n mode,\n },\n };\n}\n\nfunction interpolateEnvVarRefs(\n value: string,\n keepUnresolvedRefs = false,\n): string {\n let result = '';\n let lastIndex = 0;\n let searchFrom = 0;\n\n while (searchFrom < value.length) {\n const start = value.indexOf('${', searchFrom);\n if (start === -1) {\n break;\n }\n\n const end = value.indexOf('}', start + 2);\n if (end === -1) {\n break;\n }\n\n const rawName = value.slice(start + 2, end);\n if (!rawName) {\n searchFrom = end + 1;\n continue;\n }\n\n result += value.slice(lastIndex, start);\n const envVar = rawName.trim();\n const envValue = process.env[envVar];\n if (envValue === undefined) {\n if (keepUnresolvedRefs) {\n result += value.slice(start, end + 1);\n } else {\n throw new Error(`Environment variable \"${envVar}\" is not defined`);\n }\n } else {\n result += envValue;\n }\n lastIndex = end + 1;\n searchFrom = end + 1;\n }\n\n return result + value.slice(lastIndex);\n}\n\nconst multimodalLocateOptionFieldMap: Record<keyof TMultimodalPrompt, true> = {\n images: true,\n convertHttpImage2Base64: true,\n};\n\nconst multimodalLocateOptionKeys = Object.keys(\n multimodalLocateOptionFieldMap,\n) as Array<keyof TMultimodalPrompt>;\n\nfunction extractMultimodalPrompt(\n opt?: LocateOption,\n): Partial<TMultimodalPrompt> | undefined {\n if (typeof opt !== 'object' || opt === null) {\n return undefined;\n }\n\n const entries = multimodalLocateOptionKeys\n .map((key) => [key, opt[key]] as const)\n .filter(([, value]) => value !== undefined);\n\n return entries.length\n ? (Object.fromEntries(entries) as Partial<TMultimodalPrompt>)\n : undefined;\n}\n\nexport function interpolateEnvVars(content: string): string {\n // Process line by line to skip commented lines\n const lines = content.split('\\n');\n const processedLines = lines.map((line) => {\n // Check if the line is a YAML comment (starts with # after optional whitespace)\n const trimmedLine = line.trimStart();\n if (trimmedLine.startsWith('#')) {\n // Skip interpolation for comment lines\n return line;\n }\n\n // Process environment variables for non-comment lines\n return interpolateEnvVarRefs(line);\n });\n\n return processedLines.join('\\n');\n}\n\nfunction interpolateYamlScriptEnvVars(content: string): string {\n let inTopLevelTasksBlock = false;\n\n return content\n .split('\\n')\n .map((line) => {\n const trimmedLine = line.trimStart();\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n return line;\n }\n\n const indentSize = line.length - trimmedLine.length;\n if (indentSize === 0) {\n if (topLevelTasksPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = true;\n return line;\n }\n\n if (topLevelYamlKeyPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = false;\n }\n }\n\n return interpolateEnvVarRefs(line, inTopLevelTasksBlock);\n })\n .join('\\n');\n}\n\nexport function parseYamlScript(\n content: string,\n filePath?: string,\n): MidsceneYamlScript {\n let processedContent = content;\n if (content.indexOf('android') !== -1 && content.match(/deviceId:\\s*(\\d+)/)) {\n let matchedDeviceId;\n processedContent = content.replace(\n /deviceId:\\s*(\\d+)/g,\n (match, deviceId) => {\n matchedDeviceId = deviceId;\n return `deviceId: '${deviceId}'`;\n },\n );\n console.warn(\n `please use string-style deviceId in yaml script, for example: deviceId: \"${matchedDeviceId}\"`,\n );\n }\n const interpolatedContent = interpolateYamlScriptEnvVars(processedContent);\n const obj = yaml.load(interpolatedContent, {\n schema: yaml.JSON_SCHEMA,\n }) as MidsceneYamlScript;\n\n const pathTip = filePath ? `, failed to load ${filePath}` : '';\n resolveWebTarget(obj);\n assert(obj.tasks, `property \"tasks\" is required in yaml script ${pathTip}`);\n assert(\n Array.isArray(obj.tasks),\n `property \"tasks\" must be an array in yaml script, but got ${obj.tasks}`,\n );\n return obj;\n}\n\nexport function buildDetailedLocateParam(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n): DetailedLocateParam | undefined {\n debugUtils('will call buildDetailedLocateParam', locatePrompt, opt);\n // Normalize object-form TUserPrompt: when the object only contains a\n // `prompt` string (no multimodal fields like `images`), unwrap it to\n // avoid double nesting like { prompt: { prompt: '...' } }.\n let normalizedLocatePrompt: TUserPrompt = locatePrompt;\n if (\n typeof locatePrompt === 'object' &&\n locatePrompt !== null &&\n 'prompt' in locatePrompt\n ) {\n const { prompt: innerPrompt, ...rest } = locatePrompt;\n const hasMultimodalFields = Object.keys(rest).length > 0;\n normalizedLocatePrompt = hasMultimodalFields ? locatePrompt : innerPrompt;\n }\n\n let prompt = normalizedLocatePrompt || opt?.prompt || (opt as any)?.locate; // as a shortcut\n let deepLocate = false;\n let cacheable = true;\n let xpath = undefined;\n\n if (typeof opt === 'object' && opt !== null) {\n // Backward-compatible: accept `deepThink` as a deprecated alias for `deepLocate`.\n // All downstream code works on `deepLocate` only; the compatibility resolution\n // is intentionally kept here at the entry point so it does not bleed through\n // the rest of the call stack.\n deepLocate = opt.deepLocate ?? opt.deepThink ?? false;\n cacheable = opt.cacheable ?? true;\n xpath = opt.xpath;\n if (locatePrompt && opt.prompt && locatePrompt !== opt.prompt) {\n console.warn(\n 'conflict prompt for item',\n locatePrompt,\n opt,\n 'maybe you put the prompt in the wrong place',\n );\n }\n prompt = prompt || opt.prompt;\n }\n\n if (!prompt) {\n debugUtils(\n 'no prompt, will return undefined in buildDetailedLocateParam',\n opt,\n );\n return undefined;\n }\n\n const promptDisplay = typeof prompt === 'string' ? prompt : prompt.prompt;\n const context = opt?.context?.trim() || undefined;\n prompt = buildLocatePromptWithContext(prompt, opt?.context);\n\n const multimodalPrompt = extractMultimodalPrompt(opt);\n if (multimodalPrompt) {\n prompt =\n typeof prompt === 'string'\n ? {\n prompt,\n ...multimodalPrompt,\n }\n : {\n ...prompt,\n ...multimodalPrompt,\n };\n }\n\n return {\n prompt,\n ...(context ? { promptDisplay, context } : {}),\n deepLocate,\n cacheable,\n xpath,\n };\n}\n\nexport function buildDetailedLocateParamAndRestParams(\n locatePrompt: TUserPrompt,\n opt: LocateOption | undefined,\n excludeKeys: string[] = [],\n): {\n locateParam: DetailedLocateParam | undefined;\n restParams: Record<string, any>;\n} {\n const multimodalPrompt = extractMultimodalPrompt(opt);\n const locateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n // Extract all keys from opt except the ones already included in locateParam\n const restParams: Record<string, any> = {};\n\n if (typeof opt === 'object' && opt !== null) {\n // Get all keys from opt\n const allKeys = Object.keys(opt);\n\n // `context` has already been merged into the locate prompt.\n const locateParamKeys = Object.keys(locateParam || {});\n const multimodalPromptKeys =\n typeof locateParam?.prompt === 'object' && locateParam?.prompt !== null\n ? Object.keys(multimodalPrompt || {})\n : [];\n\n // Extract all other keys\n for (const key of allKeys) {\n if (\n !locateParamKeys.includes(key) &&\n key !== 'context' &&\n key !== 'deepThink' &&\n !multimodalPromptKeys.includes(key) &&\n !excludeKeys.includes(key) &&\n key !== 'locate'\n ) {\n restParams[key] = opt[key as keyof LocateOption];\n }\n }\n }\n\n return {\n locateParam,\n restParams,\n };\n}\n"],"names":["debugUtils","getDebug","topLevelTasksPattern","topLevelYamlKeyPattern","webTargetSources","resolveWebTarget","config","entries","source","entry","specifiedTargets","Error","target","explicitMode","mode","interpolateEnvVarRefs","value","keepUnresolvedRefs","result","lastIndex","searchFrom","start","end","rawName","envVar","envValue","process","undefined","multimodalLocateOptionFieldMap","multimodalLocateOptionKeys","Object","extractMultimodalPrompt","opt","key","interpolateEnvVars","content","lines","processedLines","line","trimmedLine","interpolateYamlScriptEnvVars","inTopLevelTasksBlock","indentSize","parseYamlScript","filePath","processedContent","matchedDeviceId","match","deviceId","console","interpolatedContent","obj","yaml","pathTip","assert","Array","buildDetailedLocateParam","locatePrompt","normalizedLocatePrompt","innerPrompt","rest","hasMultimodalFields","prompt","deepLocate","cacheable","xpath","promptDisplay","context","buildLocatePromptWithContext","multimodalPrompt","buildDetailedLocateParamAndRestParams","excludeKeys","locateParam","restParams","allKeys","locateParamKeys","multimodalPromptKeys"],"mappings":"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"}
@@ -54,6 +54,7 @@ const logger_namespaceObject = require("@midscene/shared/logger");
54
54
  const utils_namespaceObject = require("@midscene/shared/utils");
55
55
  const external_device_index_js_namespaceObject = require("../device/index.js");
56
56
  const external_cache_config_js_namespaceObject = require("./cache-config.js");
57
+ const external_file_chooser_js_namespaceObject = require("./file-chooser.js");
57
58
  const external_metrics_js_namespaceObject = require("./metrics.js");
58
59
  const external_progress_index_js_namespaceObject = require("./progress/index.js");
59
60
  const external_prompt_context_js_namespaceObject = require("./prompt-context.js");
@@ -154,7 +155,7 @@ class Agent {
154
155
  openFrameSource: async ()=>await this.interface.openFrameSource?.() ?? void 0,
155
156
  screenshot: ()=>this.interface.screenshotBase64(),
156
157
  captureRepresentative: ()=>this.getUIContext('assert'),
157
- runAssert: (assertion, uiContext, msg, assertOpt)=>this.aiAssertWithContext(assertion, uiContext, msg, assertOpt),
158
+ runAssert: (assertion, uiContext, msg, assertOpt)=>this.aiAssertWithUIContext(assertion, uiContext, msg, assertOpt),
158
159
  runBoolean: (prompt, uiContext, boolOpt)=>this.aiBooleanWithContext(prompt, uiContext, boolOpt),
159
160
  onStopped: ()=>{
160
161
  this.activeObserver = null;
@@ -327,13 +328,13 @@ class Agent {
327
328
  }
328
329
  (0, utils_namespaceObject.assert)('string' == typeof value || 'number' == typeof value, 'input value must be a string or number, use empty string if you want to clear the input');
329
330
  (0, utils_namespaceObject.assert)(locatePrompt, 'missing locate prompt for input');
330
- const detailedLocateParam = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParam)(locatePrompt, opt);
331
+ const { locateParam, restParams } = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParamAndRestParams)(locatePrompt, opt);
331
332
  const stringValue = 'number' == typeof value ? String(value) : value;
332
333
  const mode = opt?.mode === 'append' ? 'typeOnly' : opt?.mode;
333
334
  await this.callActionInActionSpace('Input', {
334
- ...opt || {},
335
+ ...restParams,
335
336
  value: stringValue,
336
- locate: detailedLocateParam,
337
+ locate: locateParam,
337
338
  mode
338
339
  });
339
340
  }
@@ -353,10 +354,10 @@ class Agent {
353
354
  };
354
355
  }
355
356
  (0, utils_namespaceObject.assert)(opt?.keyName, 'missing keyName for keyboard press');
356
- const detailedLocateParam = locatePrompt ? (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParam)(locatePrompt, opt) : void 0;
357
+ const { locateParam, restParams } = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParamAndRestParams)(locatePrompt || '', opt);
357
358
  await this.callActionInActionSpace('KeyboardPress', {
358
- ...opt || {},
359
- locate: detailedLocateParam
359
+ ...restParams,
360
+ locate: locateParam
360
361
  });
361
362
  }
362
363
  async aiScroll(locatePromptOrScrollParam, locatePromptOrOpt, optOrUndefined) {
@@ -385,25 +386,25 @@ class Agent {
385
386
  scrollType: normalizedScrollType
386
387
  };
387
388
  }
388
- const detailedLocateParam = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParam)(locatePrompt || '', opt);
389
+ const { locateParam, restParams } = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParamAndRestParams)(locatePrompt || '', opt);
389
390
  await this.callActionInActionSpace('Scroll', {
390
- ...opt || {},
391
- locate: detailedLocateParam
391
+ ...restParams,
392
+ locate: locateParam
392
393
  });
393
394
  }
394
395
  async aiPinch(locatePrompt, opt) {
395
- const detailedLocateParam = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParam)(locatePrompt || '', opt);
396
+ const { locateParam, restParams } = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParamAndRestParams)(locatePrompt || '', opt);
396
397
  await this.callActionInActionSpace('Pinch', {
397
- ...opt,
398
- locate: detailedLocateParam
398
+ ...restParams,
399
+ locate: locateParam
399
400
  });
400
401
  }
401
402
  async aiLongPress(locatePrompt, opt) {
402
403
  (0, utils_namespaceObject.assert)(locatePrompt, 'missing locate prompt for long press');
403
- const detailedLocateParam = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParam)(locatePrompt, opt);
404
+ const { locateParam, restParams } = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParamAndRestParams)(locatePrompt, opt);
404
405
  await this.callActionInActionSpace('LongPress', {
405
- ...opt || {},
406
- locate: detailedLocateParam
406
+ ...restParams,
407
+ locate: locateParam
407
408
  });
408
409
  }
409
410
  async aiClearInput(locatePrompt, opt) {
@@ -459,7 +460,7 @@ class Agent {
459
460
  }
460
461
  }
461
462
  const imagesIncludeCount = deepThink ? 2 : 1;
462
- const { output: actionOutput } = await this.taskExecutor.action(taskPrompt, planningModel, defaultModel, includeLocateInPlanning, aiActContext, cacheable, replanningCycleLimit, imagesIncludeCount, deepThink, fileChooserAccept, deepLocate, abortSignal, internalReportDisplay);
463
+ const { output: actionOutput } = await this.taskExecutor.action(taskPrompt, planningModel, defaultModel, includeLocateInPlanning, aiActContext, cacheable, replanningCycleLimit, imagesIncludeCount, deepThink, void 0, deepLocate, abortSignal, internalReportDisplay);
463
464
  if (this.taskCache && false !== cacheable) {
464
465
  const yamlFlow = cachedYamlFailed ? [] : actionOutput?.yamlFlow;
465
466
  if (!cachedYamlFailed && !yamlFlow?.length) return actionOutput?.output;
@@ -481,7 +482,34 @@ class Agent {
481
482
  }
482
483
  return actionOutput?.output;
483
484
  };
484
- return await runAiAct();
485
+ const fileChooserAccepter = this.interface.registerFileChooserListener ? new external_file_chooser_js_namespaceObject.FileChooserAccepter(this.interface) : void 0;
486
+ this.activeFileChooserAccepter = fileChooserAccepter;
487
+ this.activeFileChooserAllowedDir = opt?.fileChooserAllowedDir ? (0, external_node_path_namespaceObject.resolve)(opt.fileChooserAllowedDir) : void 0;
488
+ let aiActError;
489
+ let fileChooserHandlingError;
490
+ let result;
491
+ try {
492
+ if (fileChooserAccept?.length) {
493
+ if (!fileChooserAccepter) throw new Error(`File upload is not supported on ${this.interface.interfaceType}`);
494
+ await fileChooserAccepter.register(fileChooserAccept);
495
+ }
496
+ result = await runAiAct();
497
+ } catch (error) {
498
+ aiActError = {
499
+ error
500
+ };
501
+ } finally{
502
+ this.activeFileChooserAccepter = void 0;
503
+ this.activeFileChooserAllowedDir = void 0;
504
+ try {
505
+ fileChooserHandlingError = await fileChooserAccepter?.clear();
506
+ } catch (error) {
507
+ warn(`Failed to clear file chooser registration: ${error}`);
508
+ }
509
+ }
510
+ if (aiActError) throw aiActError.error;
511
+ if (fileChooserHandlingError) throw fileChooserHandlingError;
512
+ return result;
485
513
  }
486
514
  async runMarkdown(markdownPath, opt) {
487
515
  const markdown = await (0, promises_namespaceObject.readFile)(markdownPath, 'utf-8');
@@ -551,16 +579,18 @@ class Agent {
551
579
  };
552
580
  }
553
581
  async aiAssert(assertion, msg, opt) {
554
- return this.aiAssertWithContext(assertion, void 0, msg, opt);
582
+ return this.aiAssertWithUIContext(assertion, void 0, msg, opt);
555
583
  }
556
- async aiAssertWithContext(assertion, uiContext, msg, opt) {
584
+ async aiAssertWithUIContext(assertion, uiContext, msg, opt) {
557
585
  const modelRuntime = this.resolveModelRuntime('insight');
558
586
  const serviceOpt = {
559
587
  domIncluded: opt?.domIncluded ?? defaultServiceExtractOption.domIncluded,
560
- screenshotIncluded: opt?.screenshotIncluded ?? defaultServiceExtractOption.screenshotIncluded
588
+ screenshotIncluded: opt?.screenshotIncluded ?? defaultServiceExtractOption.screenshotIncluded,
589
+ ...opt?.context !== void 0 ? {
590
+ context: opt.context
591
+ } : {}
561
592
  };
562
- const assertionWithContext = (0, external_prompt_context_js_namespaceObject.buildPromptWithContext)(assertion, opt?.context);
563
- const { textPrompt, multimodalPrompt } = (0, external_utils_js_namespaceObject_1.parsePrompt)(assertionWithContext);
593
+ const { textPrompt, multimodalPrompt } = (0, external_utils_js_namespaceObject_1.parsePrompt)(assertion);
564
594
  const assertionText = 'string' == typeof assertion ? assertion : assertion.prompt;
565
595
  const executionOptions = {
566
596
  abortSignal: opt?.abortSignal,
@@ -858,6 +888,8 @@ class Agent {
858
888
  _define_property(this, "activeObserver", null);
859
889
  _define_property(this, "executionDumpIndexByRunner", new WeakMap());
860
890
  _define_property(this, "fullActionSpace", void 0);
891
+ _define_property(this, "activeFileChooserAccepter", void 0);
892
+ _define_property(this, "activeFileChooserAllowedDir", void 0);
861
893
  _define_property(this, "reportGenerator", void 0);
862
894
  _define_property(this, "lastExecutionDump", void 0);
863
895
  this.interface = interfaceInstance;
@@ -886,8 +918,16 @@ class Agent {
886
918
  cacheDir: cacheConfigObj.cacheDir
887
919
  });
888
920
  const baseActionSpace = this.interface.actionSpace();
921
+ const fileChooserActions = this.interface.registerFileChooserListener ? [
922
+ (0, external_device_index_js_namespaceObject.defineActionRegisterFileChooserAccept)(async (files)=>{
923
+ if (!this.activeFileChooserAccepter) throw new Error('RegisterFileChooserAccept can only be used while aiAct is running');
924
+ if (!this.activeFileChooserAllowedDir) throw new Error('RegisterFileChooserAccept requires aiAct option fileChooserAllowedDir');
925
+ await this.activeFileChooserAccepter.registerFromAllowedDir(files, this.activeFileChooserAllowedDir);
926
+ })
927
+ ] : [];
889
928
  this.fullActionSpace = [
890
929
  ...baseActionSpace,
930
+ ...fileChooserActions,
891
931
  (0, external_device_index_js_namespaceObject.defineActionSleep)()
892
932
  ];
893
933
  this.taskExecutor = new external_tasks_js_namespaceObject.TaskExecutor(this.interface, this.service, {