@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.
- package/dist/es/agent/agent.mjs +66 -26
- package/dist/es/agent/agent.mjs.map +1 -1
- package/dist/es/agent/file-chooser.mjs +82 -0
- package/dist/es/agent/file-chooser.mjs.map +1 -0
- package/dist/es/agent/prompt-context.mjs +12 -1
- package/dist/es/agent/prompt-context.mjs.map +1 -1
- package/dist/es/agent/task-builder.mjs +11 -2
- package/dist/es/agent/task-builder.mjs.map +1 -1
- package/dist/es/agent/tasks.mjs +4 -16
- package/dist/es/agent/tasks.mjs.map +1 -1
- package/dist/es/agent/ui-utils.mjs +1 -0
- package/dist/es/agent/ui-utils.mjs.map +1 -1
- package/dist/es/agent/utils.mjs +1 -1
- package/dist/es/ai-model/inspect.mjs +1 -1
- package/dist/es/ai-model/inspect.mjs.map +1 -1
- package/dist/es/ai-model/llm-planning.mjs +2 -1
- package/dist/es/ai-model/llm-planning.mjs.map +1 -1
- package/dist/es/ai-model/model-adapter/chat-completion.mjs +3 -1
- package/dist/es/ai-model/model-adapter/chat-completion.mjs.map +1 -1
- package/dist/es/ai-model/models/kimi.mjs +35 -0
- package/dist/es/ai-model/models/kimi.mjs.map +1 -1
- package/dist/es/ai-model/prompt/extraction.mjs +4 -2
- package/dist/es/ai-model/prompt/extraction.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/codex-app-server.mjs +22 -14
- package/dist/es/ai-model/service-caller/codex-app-server.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/index.mjs +15 -14
- package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
- package/dist/es/ai-model/workflows/planning/custom-planning.mjs.map +1 -1
- package/dist/es/device/index.mjs +21 -1
- package/dist/es/device/index.mjs.map +1 -1
- package/dist/es/report.mjs +1 -0
- package/dist/es/report.mjs.map +1 -1
- package/dist/es/types.mjs.map +1 -1
- package/dist/es/utils.mjs +2 -2
- package/dist/es/yaml/utils.mjs +9 -1
- package/dist/es/yaml/utils.mjs.map +1 -1
- package/dist/lib/agent/agent.js +63 -23
- package/dist/lib/agent/agent.js.map +1 -1
- package/dist/lib/agent/file-chooser.js +125 -0
- package/dist/lib/agent/file-chooser.js.map +1 -0
- package/dist/lib/agent/prompt-context.js +14 -0
- package/dist/lib/agent/prompt-context.js.map +1 -1
- package/dist/lib/agent/task-builder.js +11 -2
- package/dist/lib/agent/task-builder.js.map +1 -1
- package/dist/lib/agent/tasks.js +6 -18
- package/dist/lib/agent/tasks.js.map +1 -1
- package/dist/lib/agent/ui-utils.js +1 -0
- package/dist/lib/agent/ui-utils.js.map +1 -1
- package/dist/lib/agent/utils.js +1 -1
- package/dist/lib/ai-model/inspect.js +1 -1
- package/dist/lib/ai-model/inspect.js.map +1 -1
- package/dist/lib/ai-model/llm-planning.js +2 -1
- package/dist/lib/ai-model/llm-planning.js.map +1 -1
- package/dist/lib/ai-model/model-adapter/chat-completion.js +3 -1
- package/dist/lib/ai-model/model-adapter/chat-completion.js.map +1 -1
- package/dist/lib/ai-model/models/kimi.js +35 -0
- package/dist/lib/ai-model/models/kimi.js.map +1 -1
- package/dist/lib/ai-model/prompt/extraction.js +4 -2
- package/dist/lib/ai-model/prompt/extraction.js.map +1 -1
- package/dist/lib/ai-model/service-caller/codex-app-server.js +22 -14
- package/dist/lib/ai-model/service-caller/codex-app-server.js.map +1 -1
- package/dist/lib/ai-model/service-caller/index.js +15 -14
- package/dist/lib/ai-model/service-caller/index.js.map +1 -1
- package/dist/lib/ai-model/workflows/planning/custom-planning.js.map +1 -1
- package/dist/lib/device/index.js +27 -1
- package/dist/lib/device/index.js.map +1 -1
- package/dist/lib/report.js +1 -0
- package/dist/lib/report.js.map +1 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils.js +2 -2
- package/dist/lib/yaml/utils.js +9 -1
- package/dist/lib/yaml/utils.js.map +1 -1
- package/dist/types/agent/agent.d.ts +5 -2
- package/dist/types/agent/file-chooser.d.ts +19 -0
- package/dist/types/agent/prompt-context.d.ts +1 -0
- package/dist/types/agent/tasks.d.ts +1 -1
- package/dist/types/ai-model/model-adapter/types.d.ts +9 -0
- package/dist/types/ai-model/models/kimi.d.ts +18 -0
- package/dist/types/ai-model/models/registry.d.ts +18 -0
- package/dist/types/ai-model/prompt/extraction.d.ts +1 -1
- package/dist/types/ai-model/service-caller/codex-app-server.d.ts +5 -1
- package/dist/types/device/device-options.d.ts +7 -0
- package/dist/types/device/index.d.ts +11 -0
- package/dist/types/types.d.ts +6 -4
- package/dist/types/yaml.d.ts +9 -1
- package/package.json +2 -2
package/dist/es/yaml/utils.mjs
CHANGED
|
@@ -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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"}
|
package/dist/lib/agent/agent.js
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
-
...
|
|
335
|
+
...restParams,
|
|
335
336
|
value: stringValue,
|
|
336
|
-
locate:
|
|
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
|
|
357
|
+
const { locateParam, restParams } = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParamAndRestParams)(locatePrompt || '', opt);
|
|
357
358
|
await this.callActionInActionSpace('KeyboardPress', {
|
|
358
|
-
...
|
|
359
|
-
locate:
|
|
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
|
|
389
|
+
const { locateParam, restParams } = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParamAndRestParams)(locatePrompt || '', opt);
|
|
389
390
|
await this.callActionInActionSpace('Scroll', {
|
|
390
|
-
...
|
|
391
|
-
locate:
|
|
391
|
+
...restParams,
|
|
392
|
+
locate: locateParam
|
|
392
393
|
});
|
|
393
394
|
}
|
|
394
395
|
async aiPinch(locatePrompt, opt) {
|
|
395
|
-
const
|
|
396
|
+
const { locateParam, restParams } = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParamAndRestParams)(locatePrompt || '', opt);
|
|
396
397
|
await this.callActionInActionSpace('Pinch', {
|
|
397
|
-
...
|
|
398
|
-
locate:
|
|
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
|
|
404
|
+
const { locateParam, restParams } = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParamAndRestParams)(locatePrompt, opt);
|
|
404
405
|
await this.callActionInActionSpace('LongPress', {
|
|
405
|
-
...
|
|
406
|
-
locate:
|
|
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,
|
|
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
|
-
|
|
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.
|
|
582
|
+
return this.aiAssertWithUIContext(assertion, void 0, msg, opt);
|
|
555
583
|
}
|
|
556
|
-
async
|
|
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
|
|
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, {
|