@donggui/core 1.5.4-donggui.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +9 -0
- package/dist/es/agent/agent.mjs +709 -0
- package/dist/es/agent/agent.mjs.map +1 -0
- package/dist/es/agent/common.mjs +0 -0
- package/dist/es/agent/execution-session.mjs +41 -0
- package/dist/es/agent/execution-session.mjs.map +1 -0
- package/dist/es/agent/index.mjs +6 -0
- package/dist/es/agent/task-builder.mjs +330 -0
- package/dist/es/agent/task-builder.mjs.map +1 -0
- package/dist/es/agent/task-cache.mjs +186 -0
- package/dist/es/agent/task-cache.mjs.map +1 -0
- package/dist/es/agent/tasks.mjs +422 -0
- package/dist/es/agent/tasks.mjs.map +1 -0
- package/dist/es/agent/ui-utils.mjs +91 -0
- package/dist/es/agent/ui-utils.mjs.map +1 -0
- package/dist/es/agent/utils.mjs +198 -0
- package/dist/es/agent/utils.mjs.map +1 -0
- package/dist/es/ai-model/auto-glm/actions.mjs +224 -0
- package/dist/es/ai-model/auto-glm/actions.mjs.map +1 -0
- package/dist/es/ai-model/auto-glm/index.mjs +6 -0
- package/dist/es/ai-model/auto-glm/parser.mjs +239 -0
- package/dist/es/ai-model/auto-glm/parser.mjs.map +1 -0
- package/dist/es/ai-model/auto-glm/planning.mjs +71 -0
- package/dist/es/ai-model/auto-glm/planning.mjs.map +1 -0
- package/dist/es/ai-model/auto-glm/prompt.mjs +222 -0
- package/dist/es/ai-model/auto-glm/prompt.mjs.map +1 -0
- package/dist/es/ai-model/auto-glm/util.mjs +9 -0
- package/dist/es/ai-model/auto-glm/util.mjs.map +1 -0
- package/dist/es/ai-model/conversation-history.mjs +195 -0
- package/dist/es/ai-model/conversation-history.mjs.map +1 -0
- package/dist/es/ai-model/index.mjs +11 -0
- package/dist/es/ai-model/inspect.mjs +386 -0
- package/dist/es/ai-model/inspect.mjs.map +1 -0
- package/dist/es/ai-model/llm-planning.mjs +233 -0
- package/dist/es/ai-model/llm-planning.mjs.map +1 -0
- package/dist/es/ai-model/prompt/common.mjs +7 -0
- package/dist/es/ai-model/prompt/common.mjs.map +1 -0
- package/dist/es/ai-model/prompt/describe.mjs +66 -0
- package/dist/es/ai-model/prompt/describe.mjs.map +1 -0
- package/dist/es/ai-model/prompt/extraction.mjs +129 -0
- package/dist/es/ai-model/prompt/extraction.mjs.map +1 -0
- package/dist/es/ai-model/prompt/llm-locator.mjs +51 -0
- package/dist/es/ai-model/prompt/llm-locator.mjs.map +1 -0
- package/dist/es/ai-model/prompt/llm-planning.mjs +364 -0
- package/dist/es/ai-model/prompt/llm-planning.mjs.map +1 -0
- package/dist/es/ai-model/prompt/llm-section-locator.mjs +44 -0
- package/dist/es/ai-model/prompt/llm-section-locator.mjs.map +1 -0
- package/dist/es/ai-model/prompt/order-sensitive-judge.mjs +35 -0
- package/dist/es/ai-model/prompt/order-sensitive-judge.mjs.map +1 -0
- package/dist/es/ai-model/prompt/playwright-generator.mjs +117 -0
- package/dist/es/ai-model/prompt/playwright-generator.mjs.map +1 -0
- package/dist/es/ai-model/prompt/ui-tars-planning.mjs +36 -0
- package/dist/es/ai-model/prompt/ui-tars-planning.mjs.map +1 -0
- package/dist/es/ai-model/prompt/util.mjs +59 -0
- package/dist/es/ai-model/prompt/util.mjs.map +1 -0
- package/dist/es/ai-model/prompt/yaml-generator.mjs +219 -0
- package/dist/es/ai-model/prompt/yaml-generator.mjs.map +1 -0
- package/dist/es/ai-model/service-caller/index.mjs +466 -0
- package/dist/es/ai-model/service-caller/index.mjs.map +1 -0
- package/dist/es/ai-model/ui-tars-planning.mjs +249 -0
- package/dist/es/ai-model/ui-tars-planning.mjs.map +1 -0
- package/dist/es/common.mjs +371 -0
- package/dist/es/common.mjs.map +1 -0
- package/dist/es/device/device-options.mjs +0 -0
- package/dist/es/device/index.mjs +300 -0
- package/dist/es/device/index.mjs.map +1 -0
- package/dist/es/dump/html-utils.mjs +211 -0
- package/dist/es/dump/html-utils.mjs.map +1 -0
- package/dist/es/dump/image-restoration.mjs +43 -0
- package/dist/es/dump/image-restoration.mjs.map +1 -0
- package/dist/es/dump/index.mjs +3 -0
- package/dist/es/index.mjs +15 -0
- package/dist/es/index.mjs.map +1 -0
- package/dist/es/report-generator.mjs +134 -0
- package/dist/es/report-generator.mjs.map +1 -0
- package/dist/es/report.mjs +111 -0
- package/dist/es/report.mjs.map +1 -0
- package/dist/es/screenshot-item.mjs +105 -0
- package/dist/es/screenshot-item.mjs.map +1 -0
- package/dist/es/service/index.mjs +256 -0
- package/dist/es/service/index.mjs.map +1 -0
- package/dist/es/service/utils.mjs +15 -0
- package/dist/es/service/utils.mjs.map +1 -0
- package/dist/es/skill/index.mjs +38 -0
- package/dist/es/skill/index.mjs.map +1 -0
- package/dist/es/task-runner.mjs +258 -0
- package/dist/es/task-runner.mjs.map +1 -0
- package/dist/es/task-timing.mjs +12 -0
- package/dist/es/task-timing.mjs.map +1 -0
- package/dist/es/tree.mjs +13 -0
- package/dist/es/tree.mjs.map +1 -0
- package/dist/es/types.mjs +196 -0
- package/dist/es/types.mjs.map +1 -0
- package/dist/es/utils.mjs +218 -0
- package/dist/es/utils.mjs.map +1 -0
- package/dist/es/yaml/builder.mjs +13 -0
- package/dist/es/yaml/builder.mjs.map +1 -0
- package/dist/es/yaml/index.mjs +4 -0
- package/dist/es/yaml/player.mjs +418 -0
- package/dist/es/yaml/player.mjs.map +1 -0
- package/dist/es/yaml/utils.mjs +73 -0
- package/dist/es/yaml/utils.mjs.map +1 -0
- package/dist/es/yaml.mjs +0 -0
- package/dist/lib/agent/agent.js +757 -0
- package/dist/lib/agent/agent.js.map +1 -0
- package/dist/lib/agent/common.js +5 -0
- package/dist/lib/agent/execution-session.js +75 -0
- package/dist/lib/agent/execution-session.js.map +1 -0
- package/dist/lib/agent/index.js +81 -0
- package/dist/lib/agent/index.js.map +1 -0
- package/dist/lib/agent/task-builder.js +367 -0
- package/dist/lib/agent/task-builder.js.map +1 -0
- package/dist/lib/agent/task-cache.js +238 -0
- package/dist/lib/agent/task-cache.js.map +1 -0
- package/dist/lib/agent/tasks.js +465 -0
- package/dist/lib/agent/tasks.js.map +1 -0
- package/dist/lib/agent/ui-utils.js +143 -0
- package/dist/lib/agent/ui-utils.js.map +1 -0
- package/dist/lib/agent/utils.js +275 -0
- package/dist/lib/agent/utils.js.map +1 -0
- package/dist/lib/ai-model/auto-glm/actions.js +258 -0
- package/dist/lib/ai-model/auto-glm/actions.js.map +1 -0
- package/dist/lib/ai-model/auto-glm/index.js +66 -0
- package/dist/lib/ai-model/auto-glm/index.js.map +1 -0
- package/dist/lib/ai-model/auto-glm/parser.js +282 -0
- package/dist/lib/ai-model/auto-glm/parser.js.map +1 -0
- package/dist/lib/ai-model/auto-glm/planning.js +105 -0
- package/dist/lib/ai-model/auto-glm/planning.js.map +1 -0
- package/dist/lib/ai-model/auto-glm/prompt.js +259 -0
- package/dist/lib/ai-model/auto-glm/prompt.js.map +1 -0
- package/dist/lib/ai-model/auto-glm/util.js +46 -0
- package/dist/lib/ai-model/auto-glm/util.js.map +1 -0
- package/dist/lib/ai-model/conversation-history.js +229 -0
- package/dist/lib/ai-model/conversation-history.js.map +1 -0
- package/dist/lib/ai-model/index.js +125 -0
- package/dist/lib/ai-model/index.js.map +1 -0
- package/dist/lib/ai-model/inspect.js +429 -0
- package/dist/lib/ai-model/inspect.js.map +1 -0
- package/dist/lib/ai-model/llm-planning.js +270 -0
- package/dist/lib/ai-model/llm-planning.js.map +1 -0
- package/dist/lib/ai-model/prompt/common.js +41 -0
- package/dist/lib/ai-model/prompt/common.js.map +1 -0
- package/dist/lib/ai-model/prompt/describe.js +100 -0
- package/dist/lib/ai-model/prompt/describe.js.map +1 -0
- package/dist/lib/ai-model/prompt/extraction.js +169 -0
- package/dist/lib/ai-model/prompt/extraction.js.map +1 -0
- package/dist/lib/ai-model/prompt/llm-locator.js +88 -0
- package/dist/lib/ai-model/prompt/llm-locator.js.map +1 -0
- package/dist/lib/ai-model/prompt/llm-planning.js +401 -0
- package/dist/lib/ai-model/prompt/llm-planning.js.map +1 -0
- package/dist/lib/ai-model/prompt/llm-section-locator.js +81 -0
- package/dist/lib/ai-model/prompt/llm-section-locator.js.map +1 -0
- package/dist/lib/ai-model/prompt/order-sensitive-judge.js +72 -0
- package/dist/lib/ai-model/prompt/order-sensitive-judge.js.map +1 -0
- package/dist/lib/ai-model/prompt/playwright-generator.js +178 -0
- package/dist/lib/ai-model/prompt/playwright-generator.js.map +1 -0
- package/dist/lib/ai-model/prompt/ui-tars-planning.js +73 -0
- package/dist/lib/ai-model/prompt/ui-tars-planning.js.map +1 -0
- package/dist/lib/ai-model/prompt/util.js +105 -0
- package/dist/lib/ai-model/prompt/util.js.map +1 -0
- package/dist/lib/ai-model/prompt/yaml-generator.js +280 -0
- package/dist/lib/ai-model/prompt/yaml-generator.js.map +1 -0
- package/dist/lib/ai-model/service-caller/index.js +531 -0
- package/dist/lib/ai-model/service-caller/index.js.map +1 -0
- package/dist/lib/ai-model/ui-tars-planning.js +283 -0
- package/dist/lib/ai-model/ui-tars-planning.js.map +1 -0
- package/dist/lib/common.js +480 -0
- package/dist/lib/common.js.map +1 -0
- package/dist/lib/device/device-options.js +20 -0
- package/dist/lib/device/device-options.js.map +1 -0
- package/dist/lib/device/index.js +418 -0
- package/dist/lib/device/index.js.map +1 -0
- package/dist/lib/dump/html-utils.js +281 -0
- package/dist/lib/dump/html-utils.js.map +1 -0
- package/dist/lib/dump/image-restoration.js +77 -0
- package/dist/lib/dump/image-restoration.js.map +1 -0
- package/dist/lib/dump/index.js +60 -0
- package/dist/lib/dump/index.js.map +1 -0
- package/dist/lib/index.js +146 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/report-generator.js +172 -0
- package/dist/lib/report-generator.js.map +1 -0
- package/dist/lib/report.js +145 -0
- package/dist/lib/report.js.map +1 -0
- package/dist/lib/screenshot-item.js +139 -0
- package/dist/lib/screenshot-item.js.map +1 -0
- package/dist/lib/service/index.js +290 -0
- package/dist/lib/service/index.js.map +1 -0
- package/dist/lib/service/utils.js +49 -0
- package/dist/lib/service/utils.js.map +1 -0
- package/dist/lib/skill/index.js +72 -0
- package/dist/lib/skill/index.js.map +1 -0
- package/dist/lib/task-runner.js +295 -0
- package/dist/lib/task-runner.js.map +1 -0
- package/dist/lib/task-timing.js +46 -0
- package/dist/lib/task-timing.js.map +1 -0
- package/dist/lib/tree.js +53 -0
- package/dist/lib/tree.js.map +1 -0
- package/dist/lib/types.js +285 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utils.js +297 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/yaml/builder.js +57 -0
- package/dist/lib/yaml/builder.js.map +1 -0
- package/dist/lib/yaml/index.js +81 -0
- package/dist/lib/yaml/index.js.map +1 -0
- package/dist/lib/yaml/player.js +452 -0
- package/dist/lib/yaml/player.js.map +1 -0
- package/dist/lib/yaml/utils.js +126 -0
- package/dist/lib/yaml/utils.js.map +1 -0
- package/dist/lib/yaml.js +20 -0
- package/dist/lib/yaml.js.map +1 -0
- package/dist/types/agent/agent.d.ts +190 -0
- package/dist/types/agent/common.d.ts +0 -0
- package/dist/types/agent/execution-session.d.ts +36 -0
- package/dist/types/agent/index.d.ts +10 -0
- package/dist/types/agent/task-builder.d.ts +34 -0
- package/dist/types/agent/task-cache.d.ts +48 -0
- package/dist/types/agent/tasks.d.ts +70 -0
- package/dist/types/agent/ui-utils.d.ts +14 -0
- package/dist/types/agent/utils.d.ts +29 -0
- package/dist/types/ai-model/auto-glm/actions.d.ts +77 -0
- package/dist/types/ai-model/auto-glm/index.d.ts +6 -0
- package/dist/types/ai-model/auto-glm/parser.d.ts +18 -0
- package/dist/types/ai-model/auto-glm/planning.d.ts +10 -0
- package/dist/types/ai-model/auto-glm/prompt.d.ts +27 -0
- package/dist/types/ai-model/auto-glm/util.d.ts +13 -0
- package/dist/types/ai-model/conversation-history.d.ts +105 -0
- package/dist/types/ai-model/index.d.ts +14 -0
- package/dist/types/ai-model/inspect.d.ts +58 -0
- package/dist/types/ai-model/llm-planning.d.ts +19 -0
- package/dist/types/ai-model/prompt/common.d.ts +2 -0
- package/dist/types/ai-model/prompt/describe.d.ts +1 -0
- package/dist/types/ai-model/prompt/extraction.d.ts +7 -0
- package/dist/types/ai-model/prompt/llm-locator.d.ts +3 -0
- package/dist/types/ai-model/prompt/llm-planning.d.ts +10 -0
- package/dist/types/ai-model/prompt/llm-section-locator.d.ts +3 -0
- package/dist/types/ai-model/prompt/order-sensitive-judge.d.ts +2 -0
- package/dist/types/ai-model/prompt/playwright-generator.d.ts +26 -0
- package/dist/types/ai-model/prompt/ui-tars-planning.d.ts +2 -0
- package/dist/types/ai-model/prompt/util.d.ts +33 -0
- package/dist/types/ai-model/prompt/yaml-generator.d.ts +100 -0
- package/dist/types/ai-model/service-caller/index.d.ts +49 -0
- package/dist/types/ai-model/ui-tars-planning.d.ts +72 -0
- package/dist/types/common.d.ts +288 -0
- package/dist/types/device/device-options.d.ts +142 -0
- package/dist/types/device/index.d.ts +2315 -0
- package/dist/types/dump/html-utils.d.ts +52 -0
- package/dist/types/dump/image-restoration.d.ts +6 -0
- package/dist/types/dump/index.d.ts +5 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/report-generator.d.ts +48 -0
- package/dist/types/report.d.ts +15 -0
- package/dist/types/screenshot-item.d.ts +66 -0
- package/dist/types/service/index.d.ts +23 -0
- package/dist/types/service/utils.d.ts +2 -0
- package/dist/types/skill/index.d.ts +25 -0
- package/dist/types/task-runner.d.ts +48 -0
- package/dist/types/task-timing.d.ts +8 -0
- package/dist/types/tree.d.ts +4 -0
- package/dist/types/types.d.ts +645 -0
- package/dist/types/utils.d.ts +40 -0
- package/dist/types/yaml/builder.d.ts +2 -0
- package/dist/types/yaml/index.d.ts +4 -0
- package/dist/types/yaml/player.d.ts +34 -0
- package/dist/types/yaml/utils.d.ts +9 -0
- package/dist/types/yaml.d.ts +203 -0
- package/package.json +111 -0
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
import { ScreenshotItem } from "../screenshot-item.mjs";
|
|
2
|
+
import service from "../service/index.mjs";
|
|
3
|
+
import { ExecutionDump, GroupedActionDump } from "../types.mjs";
|
|
4
|
+
import { isAutoGLM, isUITars } from "../ai-model/auto-glm/util.mjs";
|
|
5
|
+
import js_yaml from "js-yaml";
|
|
6
|
+
import { ReportGenerator } from "../report-generator.mjs";
|
|
7
|
+
import { getVersion, processCacheConfig, reportHTMLContent } from "../utils.mjs";
|
|
8
|
+
import { ScriptPlayer, buildDetailedLocateParam, parseYamlScript } from "../yaml/index.mjs";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
import { MIDSCENE_REPLANNING_CYCLE_LIMIT, ModelConfigManager, globalConfigManager, globalModelConfigManager } from "@midscene/shared/env";
|
|
12
|
+
import { getDebug } from "@midscene/shared/logger";
|
|
13
|
+
import { assert, ifInBrowser, uuid } from "@midscene/shared/utils";
|
|
14
|
+
import { defineActionSleep } from "../device/index.mjs";
|
|
15
|
+
import { TaskCache } from "./task-cache.mjs";
|
|
16
|
+
import { TaskExecutionError, TaskExecutor, locatePlanForLocate, withFileChooser } from "./tasks.mjs";
|
|
17
|
+
import { locateParamStr, paramStr, taskTitleStr, typeStr } from "./ui-utils.mjs";
|
|
18
|
+
import { commonContextParser, getReportFileName, parsePrompt } from "./utils.mjs";
|
|
19
|
+
function _define_property(obj, key, value) {
|
|
20
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
21
|
+
value: value,
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true
|
|
25
|
+
});
|
|
26
|
+
else obj[key] = value;
|
|
27
|
+
return obj;
|
|
28
|
+
}
|
|
29
|
+
const debug = getDebug('agent');
|
|
30
|
+
const distanceOfTwoPoints = (p1, p2)=>{
|
|
31
|
+
const [x1, y1] = p1;
|
|
32
|
+
const [x2, y2] = p2;
|
|
33
|
+
return Math.round(Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2));
|
|
34
|
+
};
|
|
35
|
+
const includedInRect = (point, rect)=>{
|
|
36
|
+
const [x, y] = point;
|
|
37
|
+
const { left, top, width, height } = rect;
|
|
38
|
+
return x >= left && x <= left + width && y >= top && y <= top + height;
|
|
39
|
+
};
|
|
40
|
+
const defaultServiceExtractOption = {
|
|
41
|
+
domIncluded: false,
|
|
42
|
+
screenshotIncluded: true
|
|
43
|
+
};
|
|
44
|
+
const CACHE_STRATEGIES = [
|
|
45
|
+
'read-only',
|
|
46
|
+
'read-write',
|
|
47
|
+
'write-only'
|
|
48
|
+
];
|
|
49
|
+
const isValidCacheStrategy = (strategy)=>CACHE_STRATEGIES.some((value)=>value === strategy);
|
|
50
|
+
const CACHE_STRATEGY_VALUES = CACHE_STRATEGIES.map((value)=>`"${value}"`).join(', ');
|
|
51
|
+
const legacyScrollTypeMap = {
|
|
52
|
+
once: 'singleAction',
|
|
53
|
+
untilBottom: 'scrollToBottom',
|
|
54
|
+
untilTop: 'scrollToTop',
|
|
55
|
+
untilRight: 'scrollToRight',
|
|
56
|
+
untilLeft: 'scrollToLeft'
|
|
57
|
+
};
|
|
58
|
+
const normalizeScrollType = (scrollType)=>{
|
|
59
|
+
if (!scrollType) return scrollType;
|
|
60
|
+
if (scrollType in legacyScrollTypeMap) return legacyScrollTypeMap[scrollType];
|
|
61
|
+
return scrollType;
|
|
62
|
+
};
|
|
63
|
+
const defaultReplanningCycleLimit = 20;
|
|
64
|
+
const defaultVlmUiTarsReplanningCycleLimit = 40;
|
|
65
|
+
const defaultAutoGlmReplanningCycleLimit = 100;
|
|
66
|
+
class Agent {
|
|
67
|
+
get onDumpUpdate() {
|
|
68
|
+
return this.dumpUpdateListeners[0];
|
|
69
|
+
}
|
|
70
|
+
set onDumpUpdate(callback) {
|
|
71
|
+
this.dumpUpdateListeners = [];
|
|
72
|
+
if (callback) this.dumpUpdateListeners.push(callback);
|
|
73
|
+
}
|
|
74
|
+
get aiActContext() {
|
|
75
|
+
return this.opts.aiActContext ?? this.opts.aiActionContext;
|
|
76
|
+
}
|
|
77
|
+
get page() {
|
|
78
|
+
return this.interface;
|
|
79
|
+
}
|
|
80
|
+
ensureVLModelWarning() {
|
|
81
|
+
if (!this.hasWarnedNonVLModel && 'puppeteer' !== this.interface.interfaceType && 'playwright' !== this.interface.interfaceType && 'static' !== this.interface.interfaceType && 'chrome-extension-proxy' !== this.interface.interfaceType && 'page-over-chrome-extension-bridge' !== this.interface.interfaceType) {
|
|
82
|
+
this.modelConfigManager.throwErrorIfNonVLModel();
|
|
83
|
+
this.hasWarnedNonVLModel = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
resolveReplanningCycleLimit(modelConfigForPlanning) {
|
|
87
|
+
if (void 0 !== this.opts.replanningCycleLimit) return this.opts.replanningCycleLimit;
|
|
88
|
+
return isUITars(modelConfigForPlanning.modelFamily) ? defaultVlmUiTarsReplanningCycleLimit : isAutoGLM(modelConfigForPlanning.modelFamily) ? defaultAutoGlmReplanningCycleLimit : defaultReplanningCycleLimit;
|
|
89
|
+
}
|
|
90
|
+
async getActionSpace() {
|
|
91
|
+
return this.fullActionSpace;
|
|
92
|
+
}
|
|
93
|
+
async getUIContext(action) {
|
|
94
|
+
this.ensureVLModelWarning();
|
|
95
|
+
if (this.frozenUIContext) {
|
|
96
|
+
debug('Using frozen page context for action:', action);
|
|
97
|
+
return this.frozenUIContext;
|
|
98
|
+
}
|
|
99
|
+
const context = await commonContextParser(this.interface, {
|
|
100
|
+
uploadServerUrl: this.modelConfigManager.getUploadTestServerUrl(),
|
|
101
|
+
screenshotShrinkFactor: this.opts.screenshotShrinkFactor
|
|
102
|
+
});
|
|
103
|
+
return context;
|
|
104
|
+
}
|
|
105
|
+
async _snapshotContext() {
|
|
106
|
+
return await this.getUIContext('locate');
|
|
107
|
+
}
|
|
108
|
+
async setAIActionContext(prompt) {
|
|
109
|
+
await this.setAIActContext(prompt);
|
|
110
|
+
}
|
|
111
|
+
async setAIActContext(prompt) {
|
|
112
|
+
if (this.aiActContext) console.warn('aiActContext is already set, and it is called again, will override the previous setting');
|
|
113
|
+
this.opts.aiActContext = prompt;
|
|
114
|
+
this.opts.aiActionContext = prompt;
|
|
115
|
+
}
|
|
116
|
+
resetDump() {
|
|
117
|
+
this.dump = new GroupedActionDump({
|
|
118
|
+
sdkVersion: getVersion(),
|
|
119
|
+
groupName: this.opts.groupName,
|
|
120
|
+
groupDescription: this.opts.groupDescription,
|
|
121
|
+
executions: [],
|
|
122
|
+
modelBriefs: [],
|
|
123
|
+
deviceType: this.interface.interfaceType
|
|
124
|
+
});
|
|
125
|
+
this.executionDumpIndexByRunner = new WeakMap();
|
|
126
|
+
return this.dump;
|
|
127
|
+
}
|
|
128
|
+
appendExecutionDump(execution, runner) {
|
|
129
|
+
const currentDump = this.dump;
|
|
130
|
+
if (runner) {
|
|
131
|
+
const existingIndex = this.executionDumpIndexByRunner.get(runner);
|
|
132
|
+
if (void 0 !== existingIndex) {
|
|
133
|
+
currentDump.executions[existingIndex] = execution;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
currentDump.executions.push(execution);
|
|
137
|
+
this.executionDumpIndexByRunner.set(runner, currentDump.executions.length - 1);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
currentDump.executions.push(execution);
|
|
141
|
+
}
|
|
142
|
+
dumpDataString(opt) {
|
|
143
|
+
this.dump.groupName = this.opts.groupName;
|
|
144
|
+
this.dump.groupDescription = this.opts.groupDescription;
|
|
145
|
+
if (ifInBrowser || opt?.inlineScreenshots) return this.dump.serializeWithInlineScreenshots();
|
|
146
|
+
return this.dump.serialize();
|
|
147
|
+
}
|
|
148
|
+
reportHTMLString(opt) {
|
|
149
|
+
return reportHTMLContent(this.dumpDataString(opt));
|
|
150
|
+
}
|
|
151
|
+
writeOutActionDumps() {
|
|
152
|
+
this.reportGenerator.onDumpUpdate(this.dump);
|
|
153
|
+
this.reportFile = this.reportGenerator.getReportPath();
|
|
154
|
+
}
|
|
155
|
+
async callbackOnTaskStartTip(task) {
|
|
156
|
+
const param = paramStr(task);
|
|
157
|
+
const tip = param ? `${typeStr(task)} - ${param}` : typeStr(task);
|
|
158
|
+
if (this.onTaskStartTip) await this.onTaskStartTip(tip);
|
|
159
|
+
}
|
|
160
|
+
wrapActionInActionSpace(name) {
|
|
161
|
+
return async (param)=>await this.callActionInActionSpace(name, param);
|
|
162
|
+
}
|
|
163
|
+
async callActionInActionSpace(type, opt) {
|
|
164
|
+
debug('callActionInActionSpace', type, ',', opt);
|
|
165
|
+
const actionPlan = {
|
|
166
|
+
type: type,
|
|
167
|
+
param: opt || {},
|
|
168
|
+
thought: ''
|
|
169
|
+
};
|
|
170
|
+
debug('actionPlan', actionPlan);
|
|
171
|
+
const plans = [
|
|
172
|
+
actionPlan
|
|
173
|
+
].filter(Boolean);
|
|
174
|
+
const title = taskTitleStr(type, locateParamStr(opt?.locate || {}));
|
|
175
|
+
const defaultIntentModelConfig = this.modelConfigManager.getModelConfig('default');
|
|
176
|
+
const modelConfigForPlanning = this.modelConfigManager.getModelConfig('planning');
|
|
177
|
+
const { output } = await this.taskExecutor.runPlans(title, plans, modelConfigForPlanning, defaultIntentModelConfig);
|
|
178
|
+
return output;
|
|
179
|
+
}
|
|
180
|
+
async aiTap(locatePrompt, opt) {
|
|
181
|
+
assert(locatePrompt, 'missing locate prompt for tap');
|
|
182
|
+
const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
|
|
183
|
+
const fileChooserAccept = opt?.fileChooserAccept ? this.normalizeFileInput(opt.fileChooserAccept) : void 0;
|
|
184
|
+
return withFileChooser(this.interface, fileChooserAccept, async ()=>this.callActionInActionSpace('Tap', {
|
|
185
|
+
locate: detailedLocateParam
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
async aiRightClick(locatePrompt, opt) {
|
|
189
|
+
assert(locatePrompt, 'missing locate prompt for right click');
|
|
190
|
+
const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
|
|
191
|
+
return this.callActionInActionSpace('RightClick', {
|
|
192
|
+
locate: detailedLocateParam
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
async aiDoubleClick(locatePrompt, opt) {
|
|
196
|
+
assert(locatePrompt, 'missing locate prompt for double click');
|
|
197
|
+
const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
|
|
198
|
+
return this.callActionInActionSpace('DoubleClick', {
|
|
199
|
+
locate: detailedLocateParam
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
async aiHover(locatePrompt, opt) {
|
|
203
|
+
assert(locatePrompt, 'missing locate prompt for hover');
|
|
204
|
+
const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
|
|
205
|
+
return this.callActionInActionSpace('Hover', {
|
|
206
|
+
locate: detailedLocateParam
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
async aiInput(locatePromptOrValue, locatePromptOrOpt, optOrUndefined) {
|
|
210
|
+
let value;
|
|
211
|
+
let locatePrompt;
|
|
212
|
+
let opt;
|
|
213
|
+
if ('object' == typeof locatePromptOrOpt && null !== locatePromptOrOpt && 'value' in locatePromptOrOpt) {
|
|
214
|
+
locatePrompt = locatePromptOrValue;
|
|
215
|
+
const optWithValue = locatePromptOrOpt;
|
|
216
|
+
value = optWithValue.value;
|
|
217
|
+
opt = optWithValue;
|
|
218
|
+
} else {
|
|
219
|
+
value = locatePromptOrValue;
|
|
220
|
+
locatePrompt = locatePromptOrOpt;
|
|
221
|
+
opt = {
|
|
222
|
+
...optOrUndefined,
|
|
223
|
+
value
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
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');
|
|
227
|
+
assert(locatePrompt, 'missing locate prompt for input');
|
|
228
|
+
const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
|
|
229
|
+
const stringValue = 'number' == typeof value ? String(value) : value;
|
|
230
|
+
const mode = opt?.mode === 'append' ? 'typeOnly' : opt?.mode;
|
|
231
|
+
return this.callActionInActionSpace('Input', {
|
|
232
|
+
...opt || {},
|
|
233
|
+
value: stringValue,
|
|
234
|
+
locate: detailedLocateParam,
|
|
235
|
+
mode
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
async aiKeyboardPress(locatePromptOrKeyName, locatePromptOrOpt, optOrUndefined) {
|
|
239
|
+
let keyName;
|
|
240
|
+
let locatePrompt;
|
|
241
|
+
let opt;
|
|
242
|
+
if ('object' == typeof locatePromptOrOpt && null !== locatePromptOrOpt && 'keyName' in locatePromptOrOpt) {
|
|
243
|
+
locatePrompt = locatePromptOrKeyName;
|
|
244
|
+
opt = locatePromptOrOpt;
|
|
245
|
+
} else {
|
|
246
|
+
keyName = locatePromptOrKeyName;
|
|
247
|
+
locatePrompt = locatePromptOrOpt;
|
|
248
|
+
opt = {
|
|
249
|
+
...optOrUndefined || {},
|
|
250
|
+
keyName
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
assert(opt?.keyName, 'missing keyName for keyboard press');
|
|
254
|
+
const detailedLocateParam = locatePrompt ? buildDetailedLocateParam(locatePrompt, opt) : void 0;
|
|
255
|
+
return this.callActionInActionSpace('KeyboardPress', {
|
|
256
|
+
...opt || {},
|
|
257
|
+
locate: detailedLocateParam
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
async aiScroll(locatePromptOrScrollParam, locatePromptOrOpt, optOrUndefined) {
|
|
261
|
+
let scrollParam;
|
|
262
|
+
let locatePrompt;
|
|
263
|
+
let opt;
|
|
264
|
+
if ('object' == typeof locatePromptOrOpt && ('direction' in locatePromptOrOpt || 'scrollType' in locatePromptOrOpt || 'distance' in locatePromptOrOpt)) {
|
|
265
|
+
locatePrompt = locatePromptOrScrollParam;
|
|
266
|
+
opt = locatePromptOrOpt;
|
|
267
|
+
} else {
|
|
268
|
+
scrollParam = locatePromptOrScrollParam;
|
|
269
|
+
locatePrompt = locatePromptOrOpt;
|
|
270
|
+
opt = {
|
|
271
|
+
...optOrUndefined || {},
|
|
272
|
+
...scrollParam || {}
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
if (opt) {
|
|
276
|
+
const normalizedScrollType = normalizeScrollType(opt.scrollType);
|
|
277
|
+
if (normalizedScrollType !== opt.scrollType) opt = {
|
|
278
|
+
...opt || {},
|
|
279
|
+
scrollType: normalizedScrollType
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
const detailedLocateParam = buildDetailedLocateParam(locatePrompt || '', opt);
|
|
283
|
+
return this.callActionInActionSpace('Scroll', {
|
|
284
|
+
...opt || {},
|
|
285
|
+
locate: detailedLocateParam
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
async aiAct(taskPrompt, opt) {
|
|
289
|
+
const fileChooserAccept = opt?.fileChooserAccept ? this.normalizeFileInput(opt.fileChooserAccept) : void 0;
|
|
290
|
+
const abortSignal = opt?.abortSignal;
|
|
291
|
+
if (abortSignal?.aborted) throw new Error(`aiAct aborted: ${abortSignal.reason || 'signal already aborted'}`);
|
|
292
|
+
const runAiAct = async ()=>{
|
|
293
|
+
const modelConfigForPlanning = this.modelConfigManager.getModelConfig('planning');
|
|
294
|
+
const defaultIntentModelConfig = this.modelConfigManager.getModelConfig('default');
|
|
295
|
+
const deepThink = opt?.deepThink === 'unset' ? void 0 : opt?.deepThink;
|
|
296
|
+
const deepLocate = opt?.deepLocate;
|
|
297
|
+
const noIndividualLocateModel = modelConfigForPlanning.modelName === defaultIntentModelConfig.modelName && modelConfigForPlanning.openaiBaseURL === defaultIntentModelConfig.openaiBaseURL;
|
|
298
|
+
const includeBboxInPlanning = !deepThink && noIndividualLocateModel && !deepLocate;
|
|
299
|
+
debug('setting includeBboxInPlanning to', includeBboxInPlanning, {
|
|
300
|
+
deepThink,
|
|
301
|
+
noIndividualLocateModel,
|
|
302
|
+
deepLocate
|
|
303
|
+
});
|
|
304
|
+
if (deepLocate && includeBboxInPlanning) console.warn('deepLocate option is ignored when includeBboxInPlanning is true (same model for planning and default intent without deepThink). Locate is already done during planning.');
|
|
305
|
+
const cacheable = opt?.cacheable;
|
|
306
|
+
const replanningCycleLimit = this.resolveReplanningCycleLimit(modelConfigForPlanning);
|
|
307
|
+
const isVlmUiTars = isUITars(modelConfigForPlanning.modelFamily);
|
|
308
|
+
const isAutoGlm = isAutoGLM(modelConfigForPlanning.modelFamily);
|
|
309
|
+
const matchedCache = isVlmUiTars || isAutoGlm || false === cacheable ? void 0 : this.taskCache?.matchPlanCache(taskPrompt);
|
|
310
|
+
if (matchedCache && this.taskCache?.isCacheResultUsed && matchedCache.cacheContent?.yamlWorkflow?.trim()) {
|
|
311
|
+
await this.taskExecutor.loadYamlFlowAsPlanning(taskPrompt, matchedCache.cacheContent.yamlWorkflow);
|
|
312
|
+
debug('matched cache, will call .runYaml to run the action');
|
|
313
|
+
const yaml = matchedCache.cacheContent.yamlWorkflow;
|
|
314
|
+
await this.runYaml(yaml);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const imagesIncludeCount = deepThink ? 2 : 1;
|
|
318
|
+
const { output: actionOutput } = await this.taskExecutor.action(taskPrompt, modelConfigForPlanning, defaultIntentModelConfig, includeBboxInPlanning, this.aiActContext, cacheable, replanningCycleLimit, imagesIncludeCount, deepThink, fileChooserAccept, includeBboxInPlanning ? void 0 : deepLocate, abortSignal);
|
|
319
|
+
if (this.taskCache && actionOutput?.yamlFlow && false !== cacheable) {
|
|
320
|
+
const yamlContent = {
|
|
321
|
+
tasks: [
|
|
322
|
+
{
|
|
323
|
+
name: taskPrompt,
|
|
324
|
+
flow: actionOutput.yamlFlow
|
|
325
|
+
}
|
|
326
|
+
]
|
|
327
|
+
};
|
|
328
|
+
const yamlFlowStr = js_yaml.dump(yamlContent);
|
|
329
|
+
this.taskCache.updateOrAppendCacheRecord({
|
|
330
|
+
type: 'plan',
|
|
331
|
+
prompt: taskPrompt,
|
|
332
|
+
yamlWorkflow: yamlFlowStr
|
|
333
|
+
}, matchedCache);
|
|
334
|
+
}
|
|
335
|
+
return actionOutput?.output;
|
|
336
|
+
};
|
|
337
|
+
return await runAiAct();
|
|
338
|
+
}
|
|
339
|
+
async aiAction(taskPrompt, opt) {
|
|
340
|
+
return this.aiAct(taskPrompt, opt);
|
|
341
|
+
}
|
|
342
|
+
async aiQuery(demand, opt = defaultServiceExtractOption) {
|
|
343
|
+
const modelConfig = this.modelConfigManager.getModelConfig('insight');
|
|
344
|
+
const { output } = await this.taskExecutor.createTypeQueryExecution('Query', demand, modelConfig, opt);
|
|
345
|
+
return output;
|
|
346
|
+
}
|
|
347
|
+
async aiBoolean(prompt, opt = defaultServiceExtractOption) {
|
|
348
|
+
const modelConfig = this.modelConfigManager.getModelConfig('insight');
|
|
349
|
+
const { textPrompt, multimodalPrompt } = parsePrompt(prompt);
|
|
350
|
+
const { output } = await this.taskExecutor.createTypeQueryExecution('Boolean', textPrompt, modelConfig, opt, multimodalPrompt);
|
|
351
|
+
return output;
|
|
352
|
+
}
|
|
353
|
+
async aiNumber(prompt, opt = defaultServiceExtractOption) {
|
|
354
|
+
const modelConfig = this.modelConfigManager.getModelConfig('insight');
|
|
355
|
+
const { textPrompt, multimodalPrompt } = parsePrompt(prompt);
|
|
356
|
+
const { output } = await this.taskExecutor.createTypeQueryExecution('Number', textPrompt, modelConfig, opt, multimodalPrompt);
|
|
357
|
+
return output;
|
|
358
|
+
}
|
|
359
|
+
async aiString(prompt, opt = defaultServiceExtractOption) {
|
|
360
|
+
const modelConfig = this.modelConfigManager.getModelConfig('insight');
|
|
361
|
+
const { textPrompt, multimodalPrompt } = parsePrompt(prompt);
|
|
362
|
+
const { output } = await this.taskExecutor.createTypeQueryExecution('String', textPrompt, modelConfig, opt, multimodalPrompt);
|
|
363
|
+
return output;
|
|
364
|
+
}
|
|
365
|
+
async aiAsk(prompt, opt = defaultServiceExtractOption) {
|
|
366
|
+
return this.aiString(prompt, opt);
|
|
367
|
+
}
|
|
368
|
+
async describeElementAtPoint(center, opt) {
|
|
369
|
+
const { verifyPrompt = true, retryLimit = 3 } = opt || {};
|
|
370
|
+
let success = false;
|
|
371
|
+
let retryCount = 0;
|
|
372
|
+
let resultPrompt = '';
|
|
373
|
+
let deepLocate = opt?.deepLocate || false;
|
|
374
|
+
let verifyResult;
|
|
375
|
+
while(!success && retryCount < retryLimit){
|
|
376
|
+
if (retryCount >= 2) deepLocate = true;
|
|
377
|
+
debug('aiDescribe', center, 'verifyPrompt', verifyPrompt, 'retryCount', retryCount, 'deepLocate', deepLocate);
|
|
378
|
+
const modelConfig = this.modelConfigManager.getModelConfig('insight');
|
|
379
|
+
const text = await this.service.describe(center, modelConfig, {
|
|
380
|
+
deepLocate
|
|
381
|
+
});
|
|
382
|
+
debug('aiDescribe text', text);
|
|
383
|
+
assert(text.description, `failed to describe element at [${center}]`);
|
|
384
|
+
resultPrompt = text.description;
|
|
385
|
+
verifyResult = await this.verifyLocator(resultPrompt, void 0, center, opt);
|
|
386
|
+
if (verifyResult.pass) success = true;
|
|
387
|
+
else retryCount++;
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
prompt: resultPrompt,
|
|
391
|
+
deepLocate,
|
|
392
|
+
verifyResult
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
async verifyLocator(prompt, locateOpt, expectCenter, verifyLocateOption) {
|
|
396
|
+
debug('verifyLocator', prompt, locateOpt, expectCenter, verifyLocateOption);
|
|
397
|
+
const { center: verifyCenter, rect: verifyRect } = await this.aiLocate(prompt, locateOpt);
|
|
398
|
+
const distance = distanceOfTwoPoints(expectCenter, verifyCenter);
|
|
399
|
+
const included = includedInRect(expectCenter, verifyRect);
|
|
400
|
+
const pass = distance <= (verifyLocateOption?.centerDistanceThreshold || 20) || included;
|
|
401
|
+
const verifyResult = {
|
|
402
|
+
pass,
|
|
403
|
+
rect: verifyRect,
|
|
404
|
+
center: verifyCenter,
|
|
405
|
+
centerDistance: distance
|
|
406
|
+
};
|
|
407
|
+
debug('aiDescribe verifyResult', verifyResult);
|
|
408
|
+
return verifyResult;
|
|
409
|
+
}
|
|
410
|
+
async aiLocate(prompt, opt) {
|
|
411
|
+
const locateParam = buildDetailedLocateParam(prompt, opt);
|
|
412
|
+
assert(locateParam, 'cannot get locate param for aiLocate');
|
|
413
|
+
const locatePlan = locatePlanForLocate(locateParam);
|
|
414
|
+
const plans = [
|
|
415
|
+
locatePlan
|
|
416
|
+
];
|
|
417
|
+
const defaultIntentModelConfig = this.modelConfigManager.getModelConfig('default');
|
|
418
|
+
const modelConfigForPlanning = this.modelConfigManager.getModelConfig('planning');
|
|
419
|
+
const { output } = await this.taskExecutor.runPlans(taskTitleStr('Locate', locateParamStr(locateParam)), plans, modelConfigForPlanning, defaultIntentModelConfig);
|
|
420
|
+
const { element } = output;
|
|
421
|
+
return {
|
|
422
|
+
rect: element?.rect,
|
|
423
|
+
center: element?.center,
|
|
424
|
+
dpr: element?.dpr
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
async aiAssert(assertion, msg, opt) {
|
|
428
|
+
const modelConfig = this.modelConfigManager.getModelConfig('insight');
|
|
429
|
+
const serviceOpt = {
|
|
430
|
+
domIncluded: opt?.domIncluded ?? defaultServiceExtractOption.domIncluded,
|
|
431
|
+
screenshotIncluded: opt?.screenshotIncluded ?? defaultServiceExtractOption.screenshotIncluded
|
|
432
|
+
};
|
|
433
|
+
const { textPrompt, multimodalPrompt } = parsePrompt(assertion);
|
|
434
|
+
const assertionText = 'string' == typeof assertion ? assertion : assertion.prompt;
|
|
435
|
+
try {
|
|
436
|
+
const { output, thought } = await this.taskExecutor.createTypeQueryExecution('Assert', textPrompt, modelConfig, serviceOpt, multimodalPrompt);
|
|
437
|
+
const pass = Boolean(output);
|
|
438
|
+
const message = pass ? void 0 : `Assertion failed: ${msg || assertionText}\nReason: ${thought || '(no_reason)'}`;
|
|
439
|
+
if (opt?.keepRawResponse) return {
|
|
440
|
+
pass,
|
|
441
|
+
thought,
|
|
442
|
+
message
|
|
443
|
+
};
|
|
444
|
+
if (!pass) throw new Error(message);
|
|
445
|
+
} catch (error) {
|
|
446
|
+
if (error instanceof TaskExecutionError) {
|
|
447
|
+
const errorTask = error.errorTask;
|
|
448
|
+
const thought = errorTask?.thought;
|
|
449
|
+
const rawError = errorTask?.error;
|
|
450
|
+
const rawMessage = errorTask?.errorMessage || (rawError instanceof Error ? rawError.message : rawError ? String(rawError) : void 0);
|
|
451
|
+
const reason = thought || rawMessage || '(no_reason)';
|
|
452
|
+
const message = `Assertion failed: ${msg || assertionText}\nReason: ${reason}`;
|
|
453
|
+
if (opt?.keepRawResponse) return {
|
|
454
|
+
pass: false,
|
|
455
|
+
thought,
|
|
456
|
+
message
|
|
457
|
+
};
|
|
458
|
+
throw new Error(message, {
|
|
459
|
+
cause: rawError ?? error
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
throw error;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
async aiWaitFor(assertion, opt) {
|
|
466
|
+
const modelConfig = this.modelConfigManager.getModelConfig('insight');
|
|
467
|
+
await this.taskExecutor.waitFor(assertion, {
|
|
468
|
+
...opt,
|
|
469
|
+
timeoutMs: opt?.timeoutMs || 15000,
|
|
470
|
+
checkIntervalMs: opt?.checkIntervalMs || 3000
|
|
471
|
+
}, modelConfig);
|
|
472
|
+
}
|
|
473
|
+
async ai(...args) {
|
|
474
|
+
return this.aiAct(...args);
|
|
475
|
+
}
|
|
476
|
+
async runYaml(yamlScriptContent) {
|
|
477
|
+
const script = parseYamlScript(yamlScriptContent, 'yaml');
|
|
478
|
+
const player = new ScriptPlayer(script, async ()=>({
|
|
479
|
+
agent: this,
|
|
480
|
+
freeFn: []
|
|
481
|
+
}));
|
|
482
|
+
await player.run();
|
|
483
|
+
if ('error' === player.status) {
|
|
484
|
+
const errors = player.taskStatusList.filter((task)=>'error' === task.status).map((task)=>`task - ${task.name}: ${task.error?.message}`).join('\n');
|
|
485
|
+
throw new Error(`Error(s) occurred in running yaml script:\n${errors}`);
|
|
486
|
+
}
|
|
487
|
+
return {
|
|
488
|
+
result: player.result
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
async evaluateJavaScript(script) {
|
|
492
|
+
assert(this.interface.evaluateJavaScript, 'evaluateJavaScript is not supported in current agent');
|
|
493
|
+
return this.interface.evaluateJavaScript(script);
|
|
494
|
+
}
|
|
495
|
+
addDumpUpdateListener(listener) {
|
|
496
|
+
this.dumpUpdateListeners.push(listener);
|
|
497
|
+
return ()=>{
|
|
498
|
+
this.removeDumpUpdateListener(listener);
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
removeDumpUpdateListener(listener) {
|
|
502
|
+
const index = this.dumpUpdateListeners.indexOf(listener);
|
|
503
|
+
if (index > -1) this.dumpUpdateListeners.splice(index, 1);
|
|
504
|
+
}
|
|
505
|
+
clearDumpUpdateListeners() {
|
|
506
|
+
this.dumpUpdateListeners = [];
|
|
507
|
+
}
|
|
508
|
+
async destroy() {
|
|
509
|
+
if (this.destroyed) return;
|
|
510
|
+
await this.reportGenerator.flush();
|
|
511
|
+
await this.reportGenerator.finalize(this.dump);
|
|
512
|
+
this.reportFile = this.reportGenerator.getReportPath();
|
|
513
|
+
await this.interface.destroy?.();
|
|
514
|
+
this.resetDump();
|
|
515
|
+
this.destroyed = true;
|
|
516
|
+
}
|
|
517
|
+
async recordToReport(title, opt) {
|
|
518
|
+
const base64 = await this.interface.screenshotBase64();
|
|
519
|
+
const now = Date.now();
|
|
520
|
+
const screenshot = ScreenshotItem.create(base64, now);
|
|
521
|
+
const recorder = [
|
|
522
|
+
{
|
|
523
|
+
type: 'screenshot',
|
|
524
|
+
ts: now,
|
|
525
|
+
screenshot
|
|
526
|
+
}
|
|
527
|
+
];
|
|
528
|
+
const task = {
|
|
529
|
+
taskId: uuid(),
|
|
530
|
+
type: 'Log',
|
|
531
|
+
subType: 'Screenshot',
|
|
532
|
+
status: 'finished',
|
|
533
|
+
recorder,
|
|
534
|
+
timing: {
|
|
535
|
+
start: now,
|
|
536
|
+
end: now,
|
|
537
|
+
cost: 0
|
|
538
|
+
},
|
|
539
|
+
param: {
|
|
540
|
+
content: opt?.content || ''
|
|
541
|
+
},
|
|
542
|
+
executor: async ()=>{}
|
|
543
|
+
};
|
|
544
|
+
const executionDump = new ExecutionDump({
|
|
545
|
+
logTime: now,
|
|
546
|
+
name: `Log - ${title || 'untitled'}`,
|
|
547
|
+
description: opt?.content || '',
|
|
548
|
+
tasks: [
|
|
549
|
+
task
|
|
550
|
+
]
|
|
551
|
+
});
|
|
552
|
+
this.appendExecutionDump(executionDump);
|
|
553
|
+
const dumpString = this.dumpDataString();
|
|
554
|
+
for (const listener of this.dumpUpdateListeners)try {
|
|
555
|
+
listener(dumpString);
|
|
556
|
+
} catch (error) {
|
|
557
|
+
console.error('Error in onDumpUpdate listener', error);
|
|
558
|
+
}
|
|
559
|
+
this.writeOutActionDumps();
|
|
560
|
+
await this.reportGenerator.flush();
|
|
561
|
+
}
|
|
562
|
+
async logScreenshot(title, opt) {
|
|
563
|
+
await this.recordToReport(title, opt);
|
|
564
|
+
}
|
|
565
|
+
_unstableLogContent() {
|
|
566
|
+
const { groupName, groupDescription, executions } = this.dump;
|
|
567
|
+
return {
|
|
568
|
+
groupName,
|
|
569
|
+
groupDescription,
|
|
570
|
+
executions: executions || []
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
async freezePageContext() {
|
|
574
|
+
debug('Freezing page context');
|
|
575
|
+
const context = await this._snapshotContext();
|
|
576
|
+
context._isFrozen = true;
|
|
577
|
+
this.frozenUIContext = context;
|
|
578
|
+
debug('Page context frozen successfully');
|
|
579
|
+
}
|
|
580
|
+
async unfreezePageContext() {
|
|
581
|
+
debug('Unfreezing page context');
|
|
582
|
+
this.frozenUIContext = void 0;
|
|
583
|
+
debug('Page context unfrozen successfully');
|
|
584
|
+
}
|
|
585
|
+
processCacheConfig(opts) {
|
|
586
|
+
if (true === opts.cache) throw new Error('cache: true requires an explicit cache ID. Please provide:\nExample: cache: { id: "my-cache-id" }');
|
|
587
|
+
if (opts.cache && 'object' == typeof opts.cache && null !== opts.cache && !opts.cache.id) throw new Error('cache configuration requires an explicit id.\nExample: cache: { id: "my-cache-id" }');
|
|
588
|
+
const cacheConfig = processCacheConfig(opts.cache, opts.cacheId || opts.testId || 'default');
|
|
589
|
+
if (!cacheConfig) return null;
|
|
590
|
+
if ('object' == typeof cacheConfig && null !== cacheConfig) {
|
|
591
|
+
const id = cacheConfig.id;
|
|
592
|
+
const rawStrategy = cacheConfig.strategy;
|
|
593
|
+
let strategyValue;
|
|
594
|
+
if (void 0 === rawStrategy) strategyValue = 'read-write';
|
|
595
|
+
else if ('string' == typeof rawStrategy) strategyValue = rawStrategy;
|
|
596
|
+
else throw new Error(`cache.strategy must be a string when provided, but received type ${typeof rawStrategy}`);
|
|
597
|
+
if (!isValidCacheStrategy(strategyValue)) throw new Error(`cache.strategy must be one of ${CACHE_STRATEGY_VALUES}, but received "${strategyValue}"`);
|
|
598
|
+
const isReadOnly = 'read-only' === strategyValue;
|
|
599
|
+
const isWriteOnly = 'write-only' === strategyValue;
|
|
600
|
+
return {
|
|
601
|
+
id,
|
|
602
|
+
enabled: !isWriteOnly,
|
|
603
|
+
readOnly: isReadOnly,
|
|
604
|
+
writeOnly: isWriteOnly
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
return null;
|
|
608
|
+
}
|
|
609
|
+
normalizeFilePaths(files) {
|
|
610
|
+
if (ifInBrowser) throw new Error('File chooser is not supported in browser environment');
|
|
611
|
+
return files.map((file)=>{
|
|
612
|
+
const absolutePath = resolve(file);
|
|
613
|
+
if (!existsSync(absolutePath)) throw new Error(`File not found: ${file}`);
|
|
614
|
+
return absolutePath;
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
normalizeFileInput(files) {
|
|
618
|
+
const filesArray = Array.isArray(files) ? files : [
|
|
619
|
+
files
|
|
620
|
+
];
|
|
621
|
+
return this.normalizeFilePaths(filesArray);
|
|
622
|
+
}
|
|
623
|
+
async flushCache(options) {
|
|
624
|
+
if (!this.taskCache) throw new Error('Cache is not configured');
|
|
625
|
+
this.taskCache.flushCacheToFile(options);
|
|
626
|
+
}
|
|
627
|
+
constructor(interfaceInstance, opts){
|
|
628
|
+
_define_property(this, "interface", void 0);
|
|
629
|
+
_define_property(this, "service", void 0);
|
|
630
|
+
_define_property(this, "dump", void 0);
|
|
631
|
+
_define_property(this, "reportFile", void 0);
|
|
632
|
+
_define_property(this, "reportFileName", void 0);
|
|
633
|
+
_define_property(this, "taskExecutor", void 0);
|
|
634
|
+
_define_property(this, "opts", void 0);
|
|
635
|
+
_define_property(this, "dryMode", false);
|
|
636
|
+
_define_property(this, "onTaskStartTip", void 0);
|
|
637
|
+
_define_property(this, "taskCache", void 0);
|
|
638
|
+
_define_property(this, "dumpUpdateListeners", []);
|
|
639
|
+
_define_property(this, "destroyed", false);
|
|
640
|
+
_define_property(this, "modelConfigManager", void 0);
|
|
641
|
+
_define_property(this, "frozenUIContext", void 0);
|
|
642
|
+
_define_property(this, "hasWarnedNonVLModel", false);
|
|
643
|
+
_define_property(this, "executionDumpIndexByRunner", new WeakMap());
|
|
644
|
+
_define_property(this, "fullActionSpace", void 0);
|
|
645
|
+
_define_property(this, "reportGenerator", void 0);
|
|
646
|
+
this.interface = interfaceInstance;
|
|
647
|
+
const envReplanningCycleLimit = globalConfigManager.getEnvConfigValueAsNumber(MIDSCENE_REPLANNING_CYCLE_LIMIT);
|
|
648
|
+
this.opts = Object.assign({
|
|
649
|
+
generateReport: true,
|
|
650
|
+
autoPrintReportMsg: true,
|
|
651
|
+
groupName: 'Midscene Report',
|
|
652
|
+
groupDescription: ''
|
|
653
|
+
}, opts || {}, opts?.replanningCycleLimit !== void 0 || void 0 === envReplanningCycleLimit || Number.isNaN(envReplanningCycleLimit) ? {} : {
|
|
654
|
+
replanningCycleLimit: envReplanningCycleLimit
|
|
655
|
+
});
|
|
656
|
+
const resolvedAiActContext = this.opts.aiActContext ?? this.opts.aiActionContext;
|
|
657
|
+
if (void 0 !== resolvedAiActContext) {
|
|
658
|
+
this.opts.aiActContext = resolvedAiActContext;
|
|
659
|
+
this.opts.aiActionContext ??= resolvedAiActContext;
|
|
660
|
+
}
|
|
661
|
+
if (opts?.modelConfig && ('object' != typeof opts?.modelConfig || Array.isArray(opts.modelConfig))) throw new Error(`opts.modelConfig must be a plain object map of env keys to values, but got ${typeof opts?.modelConfig}`);
|
|
662
|
+
const hasCustomConfig = opts?.modelConfig || opts?.createOpenAIClient;
|
|
663
|
+
this.modelConfigManager = hasCustomConfig ? new ModelConfigManager(opts?.modelConfig, opts?.createOpenAIClient) : globalModelConfigManager;
|
|
664
|
+
this.onTaskStartTip = this.opts.onTaskStartTip;
|
|
665
|
+
this.service = new service(async ()=>this.getUIContext());
|
|
666
|
+
const cacheConfigObj = this.processCacheConfig(opts || {});
|
|
667
|
+
if (cacheConfigObj) this.taskCache = new TaskCache(cacheConfigObj.id, cacheConfigObj.enabled, void 0, {
|
|
668
|
+
readOnly: cacheConfigObj.readOnly,
|
|
669
|
+
writeOnly: cacheConfigObj.writeOnly
|
|
670
|
+
});
|
|
671
|
+
const baseActionSpace = this.interface.actionSpace();
|
|
672
|
+
this.fullActionSpace = [
|
|
673
|
+
...baseActionSpace,
|
|
674
|
+
defineActionSleep()
|
|
675
|
+
];
|
|
676
|
+
this.taskExecutor = new TaskExecutor(this.interface, this.service, {
|
|
677
|
+
taskCache: this.taskCache,
|
|
678
|
+
onTaskStart: this.callbackOnTaskStartTip.bind(this),
|
|
679
|
+
replanningCycleLimit: this.opts.replanningCycleLimit,
|
|
680
|
+
waitAfterAction: this.opts.waitAfterAction,
|
|
681
|
+
useDeviceTimestamp: this.opts.useDeviceTimestamp,
|
|
682
|
+
actionSpace: this.fullActionSpace,
|
|
683
|
+
hooks: {
|
|
684
|
+
onTaskUpdate: (runner)=>{
|
|
685
|
+
const executionDump = runner.dump();
|
|
686
|
+
this.appendExecutionDump(executionDump, runner);
|
|
687
|
+
const dumpString = this.dumpDataString();
|
|
688
|
+
for (const listener of this.dumpUpdateListeners)try {
|
|
689
|
+
listener(dumpString, executionDump);
|
|
690
|
+
} catch (error) {
|
|
691
|
+
console.error('Error in onDumpUpdate listener', error);
|
|
692
|
+
}
|
|
693
|
+
this.writeOutActionDumps();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
this.dump = this.resetDump();
|
|
698
|
+
this.reportFileName = opts?.reportFileName || getReportFileName(opts?.testId || this.interface.interfaceType || 'web');
|
|
699
|
+
this.reportGenerator = ReportGenerator.create(this.reportFileName, {
|
|
700
|
+
generateReport: this.opts.generateReport,
|
|
701
|
+
outputFormat: this.opts.outputFormat,
|
|
702
|
+
autoPrintReportMsg: this.opts.autoPrintReportMsg
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
const createAgent = (interfaceInstance, opts)=>new Agent(interfaceInstance, opts);
|
|
707
|
+
export { Agent, createAgent };
|
|
708
|
+
|
|
709
|
+
//# sourceMappingURL=agent.mjs.map
|