@midscene/core 1.10.2-beta-20260706032158.0 → 1.10.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/dist/es/agent/agent.mjs +40 -1
- package/dist/es/agent/agent.mjs.map +1 -1
- package/dist/es/agent/metrics.mjs +81 -0
- package/dist/es/agent/metrics.mjs.map +1 -0
- package/dist/es/agent/task-builder.mjs +1 -1
- package/dist/es/agent/task-builder.mjs.map +1 -1
- package/dist/es/agent/utils.mjs +1 -1
- package/dist/es/ai-model/connectivity/run-connectivity-test.mjs +9 -3
- package/dist/es/ai-model/connectivity/run-connectivity-test.mjs.map +1 -1
- package/dist/es/ai-model/inspect.mjs +3 -3
- package/dist/es/ai-model/inspect.mjs.map +1 -1
- package/dist/es/ai-model/llm-planning.mjs +1 -1
- package/dist/es/ai-model/llm-planning.mjs.map +1 -1
- package/dist/es/ai-model/model-adapter/resolve.mjs +2 -2
- package/dist/es/ai-model/model-adapter/resolve.mjs.map +1 -1
- package/dist/es/ai-model/models/default.mjs +2 -1
- package/dist/es/ai-model/models/default.mjs.map +1 -1
- package/dist/es/ai-model/models/doubao.mjs +38 -60
- package/dist/es/ai-model/models/doubao.mjs.map +1 -1
- package/dist/es/ai-model/models/gemini.mjs +4 -15
- package/dist/es/ai-model/models/gemini.mjs.map +1 -1
- package/dist/es/ai-model/models/glm.mjs +4 -0
- package/dist/es/ai-model/models/glm.mjs.map +1 -1
- package/dist/es/ai-model/models/gpt.mjs +5 -1
- package/dist/es/ai-model/models/gpt.mjs.map +1 -1
- package/dist/es/ai-model/models/kimi.mjs +4 -0
- package/dist/es/ai-model/models/kimi.mjs.map +1 -1
- package/dist/es/ai-model/models/mimo.mjs +3 -2
- package/dist/es/ai-model/models/mimo.mjs.map +1 -1
- package/dist/es/ai-model/models/qwen.mjs.map +1 -1
- package/dist/es/ai-model/models/ui-tars/adapter.mjs +2 -41
- package/dist/es/ai-model/models/ui-tars/adapter.mjs.map +1 -1
- package/dist/es/ai-model/models/utils/intent.mjs +6 -0
- package/dist/es/ai-model/models/utils/intent.mjs.map +1 -0
- package/dist/es/ai-model/prompt/describe.mjs +31 -34
- package/dist/es/ai-model/prompt/describe.mjs.map +1 -1
- package/dist/es/ai-model/prompt/extraction.mjs +15 -9
- package/dist/es/ai-model/prompt/extraction.mjs.map +1 -1
- package/dist/es/ai-model/prompt/llm-planning.mjs +19 -19
- package/dist/es/ai-model/prompt/llm-planning.mjs.map +1 -1
- package/dist/es/ai-model/prompt/locate-grounding-rules.mjs +7 -3
- package/dist/es/ai-model/prompt/locate-grounding-rules.mjs.map +1 -1
- package/dist/es/ai-model/prompt/recorder-metadata-generator.mjs +2 -1
- package/dist/es/ai-model/prompt/recorder-metadata-generator.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/index.mjs +40 -19
- package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/json.mjs +31 -28
- package/dist/es/ai-model/service-caller/json.mjs.map +1 -1
- package/dist/es/device/index.mjs +2 -4
- package/dist/es/device/index.mjs.map +1 -1
- package/dist/es/dump/html-utils.mjs +63 -1
- package/dist/es/dump/html-utils.mjs.map +1 -1
- package/dist/es/dump/screenshot-restoration.mjs +6 -0
- package/dist/es/dump/screenshot-restoration.mjs.map +1 -1
- package/dist/es/element-describer.mjs +36 -18
- package/dist/es/element-describer.mjs.map +1 -1
- package/dist/es/index.mjs +2 -2
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/report-generator.mjs +28 -1
- package/dist/es/report-generator.mjs.map +1 -1
- package/dist/es/report-markdown.mjs +300 -35
- package/dist/es/report-markdown.mjs.map +1 -1
- package/dist/es/report.mjs +29 -1
- package/dist/es/report.mjs.map +1 -1
- package/dist/es/service/index.mjs +101 -25
- package/dist/es/service/index.mjs.map +1 -1
- package/dist/es/service/utils.mjs +65 -1
- package/dist/es/service/utils.mjs.map +1 -1
- package/dist/es/types.mjs.map +1 -1
- package/dist/es/utils.mjs +2 -2
- package/dist/lib/agent/agent.js +40 -1
- package/dist/lib/agent/agent.js.map +1 -1
- package/dist/lib/agent/metrics.js +115 -0
- package/dist/lib/agent/metrics.js.map +1 -0
- package/dist/lib/agent/task-builder.js +1 -1
- package/dist/lib/agent/task-builder.js.map +1 -1
- package/dist/lib/agent/utils.js +1 -1
- package/dist/lib/ai-model/connectivity/run-connectivity-test.js +9 -3
- package/dist/lib/ai-model/connectivity/run-connectivity-test.js.map +1 -1
- package/dist/lib/ai-model/inspect.js +3 -3
- package/dist/lib/ai-model/inspect.js.map +1 -1
- package/dist/lib/ai-model/llm-planning.js +1 -1
- package/dist/lib/ai-model/llm-planning.js.map +1 -1
- package/dist/lib/ai-model/model-adapter/resolve.js +1 -1
- package/dist/lib/ai-model/model-adapter/resolve.js.map +1 -1
- package/dist/lib/ai-model/models/default.js +2 -1
- package/dist/lib/ai-model/models/default.js.map +1 -1
- package/dist/lib/ai-model/models/doubao.js +38 -69
- package/dist/lib/ai-model/models/doubao.js.map +1 -1
- package/dist/lib/ai-model/models/gemini.js +4 -15
- package/dist/lib/ai-model/models/gemini.js.map +1 -1
- package/dist/lib/ai-model/models/glm.js +4 -0
- package/dist/lib/ai-model/models/glm.js.map +1 -1
- package/dist/lib/ai-model/models/gpt.js +5 -1
- package/dist/lib/ai-model/models/gpt.js.map +1 -1
- package/dist/lib/ai-model/models/kimi.js +4 -0
- package/dist/lib/ai-model/models/kimi.js.map +1 -1
- package/dist/lib/ai-model/models/mimo.js +3 -2
- package/dist/lib/ai-model/models/mimo.js.map +1 -1
- package/dist/lib/ai-model/models/qwen.js.map +1 -1
- package/dist/lib/ai-model/models/ui-tars/adapter.js +1 -40
- package/dist/lib/ai-model/models/ui-tars/adapter.js.map +1 -1
- package/dist/lib/ai-model/models/utils/intent.js +40 -0
- package/dist/lib/ai-model/models/utils/intent.js.map +1 -0
- package/dist/lib/ai-model/prompt/describe.js +31 -34
- package/dist/lib/ai-model/prompt/describe.js.map +1 -1
- package/dist/lib/ai-model/prompt/extraction.js +14 -8
- package/dist/lib/ai-model/prompt/extraction.js.map +1 -1
- package/dist/lib/ai-model/prompt/llm-planning.js +19 -19
- package/dist/lib/ai-model/prompt/llm-planning.js.map +1 -1
- package/dist/lib/ai-model/prompt/locate-grounding-rules.js +7 -3
- package/dist/lib/ai-model/prompt/locate-grounding-rules.js.map +1 -1
- package/dist/lib/ai-model/prompt/recorder-metadata-generator.js +4 -3
- package/dist/lib/ai-model/prompt/recorder-metadata-generator.js.map +1 -1
- package/dist/lib/ai-model/service-caller/index.js +44 -23
- package/dist/lib/ai-model/service-caller/index.js.map +1 -1
- package/dist/lib/ai-model/service-caller/json.js +33 -33
- package/dist/lib/ai-model/service-caller/json.js.map +1 -1
- package/dist/lib/device/index.js +2 -4
- package/dist/lib/device/index.js.map +1 -1
- package/dist/lib/dump/html-utils.js +65 -0
- package/dist/lib/dump/html-utils.js.map +1 -1
- package/dist/lib/dump/screenshot-restoration.js +6 -0
- package/dist/lib/dump/screenshot-restoration.js.map +1 -1
- package/dist/lib/element-describer.js +37 -22
- package/dist/lib/element-describer.js.map +1 -1
- package/dist/lib/index.js +1 -4
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/report-generator.js +27 -0
- package/dist/lib/report-generator.js.map +1 -1
- package/dist/lib/report-markdown.js +300 -35
- package/dist/lib/report-markdown.js.map +1 -1
- package/dist/lib/report.js +28 -0
- package/dist/lib/report.js.map +1 -1
- package/dist/lib/service/index.js +99 -23
- package/dist/lib/service/index.js.map +1 -1
- package/dist/lib/service/utils.js +98 -1
- package/dist/lib/service/utils.js.map +1 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils.js +2 -2
- package/dist/types/agent/agent.d.ts +15 -2
- package/dist/types/agent/index.d.ts +1 -0
- package/dist/types/agent/metrics.d.ts +48 -0
- package/dist/types/ai-model/model-adapter/types.d.ts +8 -0
- package/dist/types/ai-model/models/doubao.d.ts +1 -4
- package/dist/types/ai-model/models/gemini.d.ts +1 -1
- package/dist/types/ai-model/models/registry.d.ts +1 -1
- package/dist/types/ai-model/models/utils/intent.d.ts +2 -0
- package/dist/types/ai-model/service-caller/index.d.ts +8 -3
- package/dist/types/ai-model/service-caller/json.d.ts +19 -2
- package/dist/types/device/device-options.d.ts +0 -28
- package/dist/types/device/index.d.ts +0 -5
- package/dist/types/dump/html-utils.d.ts +2 -0
- package/dist/types/dump/screenshot-restoration.d.ts +1 -1
- package/dist/types/element-describer.d.ts +3 -6
- package/dist/types/index.d.ts +2 -2
- package/dist/types/report-generator.d.ts +6 -0
- package/dist/types/service/index.d.ts +1 -1
- package/dist/types/service/utils.d.ts +21 -2
- package/dist/types/types.d.ts +12 -2
- package/package.json +3 -3
|
@@ -24,10 +24,9 @@ var __webpack_require__ = {};
|
|
|
24
24
|
var __webpack_exports__ = {};
|
|
25
25
|
__webpack_require__.r(__webpack_exports__);
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
-
verifyElementByServiceLocate: ()=>verifyElementByServiceLocate,
|
|
28
|
-
verifyLocator: ()=>verifyLocator,
|
|
29
27
|
describeElementAtPoint: ()=>describeElementAtPoint,
|
|
30
|
-
verifyElementDescriptionAtPoint: ()=>verifyElementDescriptionAtPoint
|
|
28
|
+
verifyElementDescriptionAtPoint: ()=>verifyElementDescriptionAtPoint,
|
|
29
|
+
verifyLocator: ()=>verifyLocator
|
|
31
30
|
});
|
|
32
31
|
const utils_namespaceObject = require("@midscene/shared/utils");
|
|
33
32
|
const utils_js_namespaceObject = require("./agent/utils.js");
|
|
@@ -80,6 +79,7 @@ const createScreenshotBoundLocatorContext = async (center, opt)=>{
|
|
|
80
79
|
async function verifyLocator(runtime, prompt, locateOpt, expectCenter, verifyLocateOption) {
|
|
81
80
|
return locateAndVerify(runtime, prompt, expectCenter, {
|
|
82
81
|
centerDistanceThreshold: verifyLocateOption?.centerDistanceThreshold,
|
|
82
|
+
deepLocate: verifyLocateOption?.deepLocate,
|
|
83
83
|
uiContext: locateOpt?.uiContext
|
|
84
84
|
});
|
|
85
85
|
}
|
|
@@ -101,25 +101,37 @@ async function describeElementAtPoint(runtime, center, opt) {
|
|
|
101
101
|
let success = false;
|
|
102
102
|
let retryCount = 0;
|
|
103
103
|
let resultPrompt = '';
|
|
104
|
+
const autoRetryDeepDescribe = opt?.deepDescribe === void 0;
|
|
105
|
+
const autoRetryDeepLocate = opt?.deepLocate === void 0;
|
|
106
|
+
let deepDescribe = opt?.deepDescribe || false;
|
|
104
107
|
let deepLocate = opt?.deepLocate || false;
|
|
105
108
|
let verifyResult;
|
|
106
109
|
let lastError;
|
|
107
110
|
let failureStage;
|
|
108
111
|
while(!success && retryCount < retryLimit){
|
|
109
|
-
if (retryCount >=
|
|
112
|
+
if (retryCount >= 1 && autoRetryDeepDescribe) deepDescribe = true;
|
|
113
|
+
if (retryCount >= 1 && autoRetryDeepLocate) deepLocate = true;
|
|
114
|
+
const describeModelRuntime = runtime.describeModelRuntime;
|
|
115
|
+
const locateModelRuntime = runtime.locateModelRuntime;
|
|
116
|
+
const retryRuntime = {
|
|
117
|
+
...runtime,
|
|
118
|
+
describeModelRuntime,
|
|
119
|
+
locateModelRuntime
|
|
120
|
+
};
|
|
110
121
|
const describeOpt = screenshotContext ? {
|
|
111
|
-
|
|
122
|
+
deepDescribe,
|
|
112
123
|
context: screenshotContext
|
|
113
124
|
} : {
|
|
114
|
-
|
|
125
|
+
deepDescribe
|
|
115
126
|
};
|
|
116
127
|
let text;
|
|
117
128
|
try {
|
|
118
|
-
text = await
|
|
129
|
+
text = await retryRuntime.service.describe(targetCenter, retryRuntime.describeModelRuntime, describeOpt);
|
|
119
130
|
} catch (error) {
|
|
120
131
|
return {
|
|
121
132
|
prompt: resultPrompt,
|
|
122
133
|
deepLocate,
|
|
134
|
+
deepDescribe,
|
|
123
135
|
verifyResult,
|
|
124
136
|
success: false,
|
|
125
137
|
error: errorMessage(error),
|
|
@@ -129,6 +141,7 @@ async function describeElementAtPoint(runtime, center, opt) {
|
|
|
129
141
|
if (!text.description) return {
|
|
130
142
|
prompt: resultPrompt,
|
|
131
143
|
deepLocate,
|
|
144
|
+
deepDescribe,
|
|
132
145
|
verifyResult,
|
|
133
146
|
success: false,
|
|
134
147
|
error: `failed to describe element at [${targetCenter}]`,
|
|
@@ -138,44 +151,50 @@ async function describeElementAtPoint(runtime, center, opt) {
|
|
|
138
151
|
if (!verifyPrompt) {
|
|
139
152
|
opt?.onProgress?.({
|
|
140
153
|
prompt: resultPrompt,
|
|
154
|
+
deepDescribe,
|
|
141
155
|
deepLocate
|
|
142
156
|
});
|
|
143
157
|
success = true;
|
|
144
158
|
break;
|
|
145
159
|
}
|
|
146
160
|
try {
|
|
147
|
-
|
|
161
|
+
const candidateVerifyResult = await verifyLocator(retryRuntime, resultPrompt, locateOpt, targetCenter, {
|
|
162
|
+
...opt,
|
|
163
|
+
deepLocate
|
|
164
|
+
});
|
|
148
165
|
verifyResult = applyLocatorVerifyFn(opt?.locatorVerifyFn, {
|
|
149
166
|
prompt: resultPrompt,
|
|
150
167
|
expectCenter: targetCenter,
|
|
151
|
-
deepLocate,
|
|
152
168
|
retryCount,
|
|
153
|
-
verifyResult
|
|
169
|
+
verifyResult: candidateVerifyResult
|
|
154
170
|
});
|
|
155
171
|
opt?.onProgress?.({
|
|
156
172
|
prompt: resultPrompt,
|
|
173
|
+
deepDescribe,
|
|
157
174
|
deepLocate,
|
|
158
175
|
verifyResult
|
|
159
176
|
});
|
|
160
|
-
if (verifyResult.pass)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
failureStage = 'verify';
|
|
164
|
-
retryCount++;
|
|
177
|
+
if (verifyResult.pass) {
|
|
178
|
+
success = true;
|
|
179
|
+
break;
|
|
165
180
|
}
|
|
181
|
+
lastError = void 0;
|
|
182
|
+
failureStage = 'verify';
|
|
166
183
|
} catch (error) {
|
|
167
184
|
lastError = errorMessage(error);
|
|
168
185
|
failureStage = 'verify';
|
|
169
186
|
opt?.onProgress?.({
|
|
170
187
|
prompt: resultPrompt,
|
|
188
|
+
deepDescribe,
|
|
171
189
|
deepLocate
|
|
172
190
|
});
|
|
173
|
-
retryCount++;
|
|
174
191
|
}
|
|
192
|
+
retryCount++;
|
|
175
193
|
}
|
|
176
194
|
return {
|
|
177
195
|
prompt: resultPrompt,
|
|
178
196
|
deepLocate,
|
|
197
|
+
deepDescribe,
|
|
179
198
|
verifyResult,
|
|
180
199
|
success,
|
|
181
200
|
error: success || !verifyPrompt ? void 0 : lastError || 'describeElementAtPoint verify failed',
|
|
@@ -187,9 +206,6 @@ async function verifyElementDescriptionAtPoint(runtime, description, center, opt
|
|
|
187
206
|
const { locateOpt, targetCenter } = await createScreenshotBoundLocatorContext(center, opt);
|
|
188
207
|
return verifyLocator(runtime, description, locateOpt, targetCenter, opt);
|
|
189
208
|
}
|
|
190
|
-
async function verifyElementByServiceLocate(runtime, description, center, opt) {
|
|
191
|
-
return locateAndVerify(runtime, description, center, opt);
|
|
192
|
-
}
|
|
193
209
|
async function locateAndVerify(runtime, description, center, opt) {
|
|
194
210
|
(0, utils_namespaceObject.assert)(description?.trim(), "description must not be empty");
|
|
195
211
|
const { screenshotContext, targetCenter } = await createScreenshotBoundLocatorContext(center, opt);
|
|
@@ -204,15 +220,14 @@ async function locateAndVerify(runtime, description, center, opt) {
|
|
|
204
220
|
context
|
|
205
221
|
} : {}, runtime.locateModelRuntime, opt?.abortSignal);
|
|
206
222
|
(0, utils_namespaceObject.assert)(locateResult.element, `Element not found: ${description}`);
|
|
207
|
-
|
|
223
|
+
const verifyResult = buildLocateValidatorResult(targetCenter, locateResult.element, opt);
|
|
224
|
+
return verifyResult;
|
|
208
225
|
}
|
|
209
226
|
exports.describeElementAtPoint = __webpack_exports__.describeElementAtPoint;
|
|
210
|
-
exports.verifyElementByServiceLocate = __webpack_exports__.verifyElementByServiceLocate;
|
|
211
227
|
exports.verifyElementDescriptionAtPoint = __webpack_exports__.verifyElementDescriptionAtPoint;
|
|
212
228
|
exports.verifyLocator = __webpack_exports__.verifyLocator;
|
|
213
229
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
214
230
|
"describeElementAtPoint",
|
|
215
|
-
"verifyElementByServiceLocate",
|
|
216
231
|
"verifyElementDescriptionAtPoint",
|
|
217
232
|
"verifyLocator"
|
|
218
233
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element-describer.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/element-describer.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { ModelRuntime } from '@/ai-model/models';\nimport { assert } from '@midscene/shared/utils';\nimport { createScreenshotBoundUIContext } from './agent/utils';\nimport type Service from './service';\nimport type {\n AgentDescribeElementAtPointResult,\n LocateOption,\n LocateResultElement,\n LocateValidatorResult,\n LocatorValidatorOption,\n Rect,\n Size,\n UIContext,\n} from './types';\nimport { buildDetailedLocateParam } from './yaml/utils';\n\nexport type DescribeElementCoordinateSpace = 'screenshot' | 'logical';\n\nexport type LocatorVerifyFn = (input: {\n prompt: string;\n expectCenter: [number, number];\n deepLocate: boolean;\n retryCount: number;\n verifyResult: LocateValidatorResult;\n}) => LocateValidatorResult | boolean;\n\nexport type DescribeElementAtPointOptions = {\n verifyPrompt?: boolean;\n retryLimit?: number;\n deepLocate?: boolean;\n locatorVerifyFn?: LocatorVerifyFn;\n screenshotBase64?: string;\n screenshotSize?: Size;\n coordinateSpace?: DescribeElementCoordinateSpace;\n logicalSize?: Size;\n onProgress?: (progress: {\n prompt?: string;\n deepLocate?: boolean;\n verifyResult?: LocateValidatorResult;\n }) => void;\n} & LocatorValidatorOption;\n\ntype ScreenshotBoundContextOptions = {\n screenshotBase64?: string;\n screenshotSize?: Size;\n coordinateSpace?: DescribeElementCoordinateSpace;\n logicalSize?: Size;\n};\n\nexport type VerifyElementDescriptionAtPointOptions =\n ScreenshotBoundContextOptions & LocatorValidatorOption;\n\nexport type VerifyElementByServiceLocateOptions =\n VerifyElementDescriptionAtPointOptions &\n Pick<LocateOption, 'cacheable' | 'deepLocate' | 'xpath'> & {\n abortSignal?: AbortSignal;\n };\n\nexport type ElementDescriberRuntime = {\n service: Pick<Service, 'describe' | 'locate'>;\n describeModelRuntime: ModelRuntime;\n locateModelRuntime: ModelRuntime;\n};\n\nconst distanceOfTwoPoints = (p1: [number, number], p2: [number, number]) => {\n const [x1, y1] = p1;\n const [x2, y2] = p2;\n return Math.round(Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2));\n};\n\nconst includedInRect = (point: [number, number], rect: Rect) => {\n const [x, y] = point;\n const { left, top, width, height } = rect;\n return x >= left && x <= left + width && y >= top && y <= top + height;\n};\n\nconst buildLocateValidatorResult = (\n expectCenter: [number, number],\n located: Pick<LocateResultElement, 'center' | 'rect'>,\n verifyLocateOption?: LocatorValidatorOption,\n): LocateValidatorResult => {\n const distance = distanceOfTwoPoints(expectCenter, located.center);\n const included = includedInRect(expectCenter, located.rect);\n const pass =\n distance <= (verifyLocateOption?.centerDistanceThreshold || 20) || included;\n return {\n pass,\n rect: located.rect,\n center: located.center,\n centerDistance: distance,\n includedInRect: included,\n };\n};\n\nfunction assertPositiveSize(\n size: Size | undefined,\n label: string,\n): asserts size is Size {\n assert(\n size &&\n Number.isFinite(size.width) &&\n Number.isFinite(size.height) &&\n size.width > 0 &&\n size.height > 0,\n `${label} must include positive width and height`,\n );\n}\n\nconst mapPointToScreenshotSpace = (\n center: [number, number],\n screenshotSize: Size,\n opt: ScreenshotBoundContextOptions,\n): [number, number] => {\n const coordinateSpace = opt.coordinateSpace || 'screenshot';\n if (coordinateSpace === 'screenshot') {\n return center;\n }\n\n assertPositiveSize(\n opt.logicalSize,\n 'logicalSize is required when coordinateSpace is logical',\n );\n return [\n (center[0] * screenshotSize.width) / opt.logicalSize.width,\n (center[1] * screenshotSize.height) / opt.logicalSize.height,\n ];\n};\n\nconst createScreenshotBoundLocatorContext = async (\n center: [number, number],\n opt?: ScreenshotBoundContextOptions,\n): Promise<{\n screenshotContext?: UIContext;\n locateOpt?: LocateOption;\n targetCenter: [number, number];\n}> => {\n const screenshotContext = opt?.screenshotBase64\n ? await createScreenshotBoundUIContext(opt.screenshotBase64, opt)\n : undefined;\n const targetCenter = screenshotContext\n ? mapPointToScreenshotSpace(center, screenshotContext.shotSize, opt || {})\n : center;\n return {\n screenshotContext,\n locateOpt: screenshotContext ? { uiContext: screenshotContext } : undefined,\n targetCenter,\n };\n};\n\nexport async function verifyLocator(\n runtime: Pick<ElementDescriberRuntime, 'service' | 'locateModelRuntime'>,\n prompt: string,\n locateOpt: LocateOption | undefined,\n expectCenter: [number, number],\n verifyLocateOption?: LocatorValidatorOption,\n): Promise<LocateValidatorResult> {\n return locateAndVerify(runtime, prompt, expectCenter, {\n centerDistanceThreshold: verifyLocateOption?.centerDistanceThreshold,\n uiContext: locateOpt?.uiContext,\n });\n}\n\nfunction applyLocatorVerifyFn(\n locatorVerifyFn: LocatorVerifyFn | undefined,\n input: Parameters<LocatorVerifyFn>[0],\n): LocateValidatorResult {\n if (!locatorVerifyFn) {\n return input.verifyResult;\n }\n const customResult = locatorVerifyFn(input);\n if (typeof customResult === 'boolean') {\n return {\n ...input.verifyResult,\n pass: customResult,\n };\n }\n return customResult;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport async function describeElementAtPoint(\n runtime: ElementDescriberRuntime,\n center: [number, number],\n opt?: DescribeElementAtPointOptions,\n): Promise<AgentDescribeElementAtPointResult> {\n const { verifyPrompt = true, retryLimit = 3 } = opt || {};\n const { screenshotContext, locateOpt, targetCenter } =\n await createScreenshotBoundLocatorContext(center, opt);\n\n let success = false;\n let retryCount = 0;\n let resultPrompt = '';\n let deepLocate = opt?.deepLocate || false;\n let verifyResult: LocateValidatorResult | undefined;\n let lastError: string | undefined;\n let failureStage: AgentDescribeElementAtPointResult['failureStage'];\n\n while (!success && retryCount < retryLimit) {\n if (retryCount >= 2) {\n deepLocate = true;\n }\n const describeOpt = screenshotContext\n ? { deepLocate, context: screenshotContext }\n : { deepLocate };\n\n let text: Awaited<\n ReturnType<ElementDescriberRuntime['service']['describe']>\n >;\n try {\n text = await runtime.service.describe(\n targetCenter,\n runtime.describeModelRuntime,\n describeOpt,\n );\n } catch (error) {\n return {\n prompt: resultPrompt,\n deepLocate,\n verifyResult,\n success: false,\n error: errorMessage(error),\n failureStage: 'describe',\n };\n }\n if (!text.description) {\n return {\n prompt: resultPrompt,\n deepLocate,\n verifyResult,\n success: false,\n error: `failed to describe element at [${targetCenter}]`,\n failureStage: 'describe',\n };\n }\n resultPrompt = text.description;\n\n if (!verifyPrompt) {\n opt?.onProgress?.({ prompt: resultPrompt, deepLocate });\n success = true;\n break;\n }\n\n try {\n verifyResult = await verifyLocator(\n runtime,\n resultPrompt,\n locateOpt,\n targetCenter,\n opt,\n );\n verifyResult = applyLocatorVerifyFn(opt?.locatorVerifyFn, {\n prompt: resultPrompt,\n expectCenter: targetCenter,\n deepLocate,\n retryCount,\n verifyResult,\n });\n opt?.onProgress?.({ prompt: resultPrompt, deepLocate, verifyResult });\n if (verifyResult.pass) {\n success = true;\n } else {\n lastError = undefined;\n failureStage = 'verify';\n retryCount++;\n }\n } catch (error) {\n lastError = errorMessage(error);\n failureStage = 'verify';\n opt?.onProgress?.({ prompt: resultPrompt, deepLocate });\n retryCount++;\n }\n }\n\n return {\n prompt: resultPrompt,\n deepLocate,\n verifyResult,\n success,\n error:\n success || !verifyPrompt\n ? undefined\n : lastError || 'describeElementAtPoint verify failed',\n failureStage: success ? undefined : failureStage,\n };\n}\n\nexport async function verifyElementDescriptionAtPoint(\n runtime: ElementDescriberRuntime,\n description: string,\n center: [number, number],\n opt?: VerifyElementDescriptionAtPointOptions,\n): Promise<LocateValidatorResult> {\n assert(description?.trim(), 'description must not be empty');\n const { locateOpt, targetCenter } = await createScreenshotBoundLocatorContext(\n center,\n opt,\n );\n\n return verifyLocator(runtime, description, locateOpt, targetCenter, opt);\n}\n\nexport async function verifyElementByServiceLocate(\n runtime: Pick<ElementDescriberRuntime, 'service' | 'locateModelRuntime'>,\n description: string,\n center: [number, number],\n opt?: VerifyElementByServiceLocateOptions,\n): Promise<LocateValidatorResult> {\n return locateAndVerify(runtime, description, center, opt);\n}\n\nasync function locateAndVerify(\n runtime: Pick<ElementDescriberRuntime, 'service' | 'locateModelRuntime'>,\n description: string,\n center: [number, number],\n opt?: VerifyElementByServiceLocateOptions & { uiContext?: UIContext },\n): Promise<LocateValidatorResult> {\n assert(description?.trim(), 'description must not be empty');\n const { screenshotContext, targetCenter } =\n await createScreenshotBoundLocatorContext(center, opt);\n const context = opt?.uiContext || screenshotContext;\n const locateParam = buildDetailedLocateParam(description, {\n cacheable: opt?.cacheable,\n deepLocate: opt?.deepLocate,\n xpath: opt?.xpath,\n });\n assert(locateParam, 'cannot get locate param for service locate');\n\n const locateResult = await runtime.service.locate(\n locateParam,\n context ? { context } : {},\n runtime.locateModelRuntime,\n opt?.abortSignal,\n );\n assert(locateResult.element, `Element not found: ${description}`);\n return buildLocateValidatorResult(targetCenter, locateResult.element, opt);\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","distanceOfTwoPoints","p1","p2","x1","y1","x2","y2","Math","includedInRect","point","rect","x","y","left","top","width","height","buildLocateValidatorResult","expectCenter","located","verifyLocateOption","distance","included","pass","assertPositiveSize","size","label","assert","Number","mapPointToScreenshotSpace","center","screenshotSize","opt","coordinateSpace","createScreenshotBoundLocatorContext","screenshotContext","createScreenshotBoundUIContext","undefined","targetCenter","verifyLocator","runtime","prompt","locateOpt","locateAndVerify","applyLocatorVerifyFn","locatorVerifyFn","input","customResult","errorMessage","error","Error","String","describeElementAtPoint","verifyPrompt","retryLimit","success","retryCount","resultPrompt","deepLocate","verifyResult","lastError","failureStage","describeOpt","text","verifyElementDescriptionAtPoint","description","verifyElementByServiceLocate","context","locateParam","buildDetailedLocateParam","locateResult"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"element-describer.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/element-describer.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { ModelRuntime } from '@/ai-model/models';\nimport { assert } from '@midscene/shared/utils';\nimport { createScreenshotBoundUIContext } from './agent/utils';\nimport type Service from './service';\nimport type {\n AgentDescribeElementAtPointResult,\n LocateOption,\n LocateResultElement,\n LocateValidatorResult,\n LocatorValidatorOption,\n Rect,\n Size,\n UIContext,\n} from './types';\nimport { buildDetailedLocateParam } from './yaml/utils';\n\nexport type DescribeElementCoordinateSpace = 'screenshot' | 'logical';\n\nexport type LocatorVerifyFn = (input: {\n prompt: string;\n expectCenter: [number, number];\n retryCount: number;\n verifyResult: LocateValidatorResult;\n}) => LocateValidatorResult | boolean;\n\nexport type DescribeElementAtPointOptions = {\n verifyPrompt?: boolean;\n retryLimit?: number;\n deepDescribe?: boolean;\n deepLocate?: boolean;\n locatorVerifyFn?: LocatorVerifyFn;\n screenshotBase64?: string;\n screenshotSize?: Size;\n coordinateSpace?: DescribeElementCoordinateSpace;\n logicalSize?: Size;\n onProgress?: (progress: {\n prompt?: string;\n deepDescribe?: boolean;\n deepLocate?: boolean;\n verifyResult?: LocateValidatorResult;\n }) => void;\n} & LocatorValidatorOption;\n\ntype ScreenshotBoundContextOptions = {\n screenshotBase64?: string;\n screenshotSize?: Size;\n coordinateSpace?: DescribeElementCoordinateSpace;\n logicalSize?: Size;\n};\n\nexport type VerifyElementDescriptionAtPointOptions =\n ScreenshotBoundContextOptions & LocatorValidatorOption;\n\ntype LocateAndVerifyOptions = VerifyElementDescriptionAtPointOptions &\n Pick<LocateOption, 'cacheable' | 'deepLocate' | 'xpath'> & {\n abortSignal?: AbortSignal;\n };\n\nexport type ElementDescriberRuntime = {\n service: Pick<Service, 'describe' | 'locate'>;\n describeModelRuntime: ModelRuntime;\n locateModelRuntime: ModelRuntime;\n};\n\ntype ServiceDescribeOptions = NonNullable<\n Parameters<ElementDescriberRuntime['service']['describe']>[2]\n>;\n\nconst distanceOfTwoPoints = (p1: [number, number], p2: [number, number]) => {\n const [x1, y1] = p1;\n const [x2, y2] = p2;\n return Math.round(Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2));\n};\n\nconst includedInRect = (point: [number, number], rect: Rect) => {\n const [x, y] = point;\n const { left, top, width, height } = rect;\n return x >= left && x <= left + width && y >= top && y <= top + height;\n};\n\nconst buildLocateValidatorResult = (\n expectCenter: [number, number],\n located: Pick<LocateResultElement, 'center' | 'rect'>,\n verifyLocateOption?: LocatorValidatorOption,\n): LocateValidatorResult => {\n const distance = distanceOfTwoPoints(expectCenter, located.center);\n const included = includedInRect(expectCenter, located.rect);\n const pass =\n distance <= (verifyLocateOption?.centerDistanceThreshold || 20) || included;\n return {\n pass,\n rect: located.rect,\n center: located.center,\n centerDistance: distance,\n includedInRect: included,\n };\n};\n\nfunction assertPositiveSize(\n size: Size | undefined,\n label: string,\n): asserts size is Size {\n assert(\n size &&\n Number.isFinite(size.width) &&\n Number.isFinite(size.height) &&\n size.width > 0 &&\n size.height > 0,\n `${label} must include positive width and height`,\n );\n}\n\nconst mapPointToScreenshotSpace = (\n center: [number, number],\n screenshotSize: Size,\n opt: ScreenshotBoundContextOptions,\n): [number, number] => {\n const coordinateSpace = opt.coordinateSpace || 'screenshot';\n if (coordinateSpace === 'screenshot') {\n return center;\n }\n\n assertPositiveSize(\n opt.logicalSize,\n 'logicalSize is required when coordinateSpace is logical',\n );\n return [\n (center[0] * screenshotSize.width) / opt.logicalSize.width,\n (center[1] * screenshotSize.height) / opt.logicalSize.height,\n ];\n};\n\nconst createScreenshotBoundLocatorContext = async (\n center: [number, number],\n opt?: ScreenshotBoundContextOptions,\n): Promise<{\n screenshotContext?: UIContext;\n locateOpt?: LocateOption;\n targetCenter: [number, number];\n}> => {\n const screenshotContext = opt?.screenshotBase64\n ? await createScreenshotBoundUIContext(opt.screenshotBase64, opt)\n : undefined;\n const targetCenter = screenshotContext\n ? mapPointToScreenshotSpace(center, screenshotContext.shotSize, opt || {})\n : center;\n return {\n screenshotContext,\n locateOpt: screenshotContext ? { uiContext: screenshotContext } : undefined,\n targetCenter,\n };\n};\n\nexport async function verifyLocator(\n runtime: Pick<ElementDescriberRuntime, 'service' | 'locateModelRuntime'>,\n prompt: string,\n locateOpt: LocateOption | undefined,\n expectCenter: [number, number],\n verifyLocateOption?: LocatorValidatorOption &\n Pick<LocateOption, 'deepLocate'>,\n): Promise<LocateValidatorResult> {\n return locateAndVerify(runtime, prompt, expectCenter, {\n centerDistanceThreshold: verifyLocateOption?.centerDistanceThreshold,\n deepLocate: verifyLocateOption?.deepLocate,\n uiContext: locateOpt?.uiContext,\n });\n}\n\nfunction applyLocatorVerifyFn(\n locatorVerifyFn: LocatorVerifyFn | undefined,\n input: Parameters<LocatorVerifyFn>[0],\n): LocateValidatorResult {\n if (!locatorVerifyFn) {\n return input.verifyResult;\n }\n const customResult = locatorVerifyFn(input);\n if (typeof customResult === 'boolean') {\n return {\n ...input.verifyResult,\n pass: customResult,\n };\n }\n return customResult;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport async function describeElementAtPoint(\n runtime: ElementDescriberRuntime,\n center: [number, number],\n opt?: DescribeElementAtPointOptions,\n): Promise<AgentDescribeElementAtPointResult> {\n const { verifyPrompt = true, retryLimit = 3 } = opt || {};\n const { screenshotContext, locateOpt, targetCenter } =\n await createScreenshotBoundLocatorContext(center, opt);\n\n let success = false;\n let retryCount = 0;\n let resultPrompt = '';\n const autoRetryDeepDescribe = opt?.deepDescribe === undefined;\n const autoRetryDeepLocate = opt?.deepLocate === undefined;\n let deepDescribe = opt?.deepDescribe || false;\n let deepLocate = opt?.deepLocate || false;\n let verifyResult: LocateValidatorResult | undefined;\n let lastError: string | undefined;\n let failureStage: AgentDescribeElementAtPointResult['failureStage'];\n\n while (!success && retryCount < retryLimit) {\n if (retryCount >= 1 && autoRetryDeepDescribe) {\n deepDescribe = true;\n }\n if (retryCount >= 1 && autoRetryDeepLocate) {\n deepLocate = true;\n }\n const describeModelRuntime = runtime.describeModelRuntime;\n const locateModelRuntime = runtime.locateModelRuntime;\n const retryRuntime: ElementDescriberRuntime = {\n ...runtime,\n describeModelRuntime,\n locateModelRuntime,\n };\n const describeOpt: ServiceDescribeOptions = screenshotContext\n ? {\n deepDescribe,\n context: screenshotContext,\n }\n : {\n deepDescribe,\n };\n let text: Awaited<\n ReturnType<ElementDescriberRuntime['service']['describe']>\n >;\n try {\n text = await retryRuntime.service.describe(\n targetCenter,\n retryRuntime.describeModelRuntime,\n describeOpt,\n );\n } catch (error) {\n return {\n prompt: resultPrompt,\n deepLocate,\n deepDescribe,\n verifyResult,\n success: false,\n error: errorMessage(error),\n failureStage: 'describe',\n };\n }\n if (!text.description) {\n return {\n prompt: resultPrompt,\n deepLocate,\n deepDescribe,\n verifyResult,\n success: false,\n error: `failed to describe element at [${targetCenter}]`,\n failureStage: 'describe',\n };\n }\n resultPrompt = text.description;\n if (!verifyPrompt) {\n opt?.onProgress?.({\n prompt: resultPrompt,\n deepDescribe,\n deepLocate,\n });\n success = true;\n break;\n }\n\n try {\n const candidateVerifyResult = await verifyLocator(\n retryRuntime,\n resultPrompt,\n locateOpt,\n targetCenter,\n {\n ...opt,\n deepLocate,\n },\n );\n verifyResult = applyLocatorVerifyFn(opt?.locatorVerifyFn, {\n prompt: resultPrompt,\n expectCenter: targetCenter,\n retryCount,\n verifyResult: candidateVerifyResult,\n });\n opt?.onProgress?.({\n prompt: resultPrompt,\n deepDescribe,\n deepLocate,\n verifyResult,\n });\n if (verifyResult.pass) {\n success = true;\n break;\n }\n lastError = undefined;\n failureStage = 'verify';\n } catch (error) {\n lastError = errorMessage(error);\n failureStage = 'verify';\n opt?.onProgress?.({\n prompt: resultPrompt,\n deepDescribe,\n deepLocate,\n });\n }\n retryCount++;\n }\n\n return {\n prompt: resultPrompt,\n deepLocate,\n deepDescribe,\n verifyResult,\n success,\n error:\n success || !verifyPrompt\n ? undefined\n : lastError || 'describeElementAtPoint verify failed',\n failureStage: success ? undefined : failureStage,\n };\n}\n\nexport async function verifyElementDescriptionAtPoint(\n runtime: ElementDescriberRuntime,\n description: string,\n center: [number, number],\n opt?: VerifyElementDescriptionAtPointOptions,\n): Promise<LocateValidatorResult> {\n assert(description?.trim(), 'description must not be empty');\n const { locateOpt, targetCenter } = await createScreenshotBoundLocatorContext(\n center,\n opt,\n );\n\n return verifyLocator(runtime, description, locateOpt, targetCenter, opt);\n}\n\nasync function locateAndVerify(\n runtime: Pick<ElementDescriberRuntime, 'service' | 'locateModelRuntime'>,\n description: string,\n center: [number, number],\n opt?: LocateAndVerifyOptions & {\n uiContext?: UIContext;\n },\n): Promise<LocateValidatorResult> {\n assert(description?.trim(), 'description must not be empty');\n const { screenshotContext, targetCenter } =\n await createScreenshotBoundLocatorContext(center, opt);\n const context = opt?.uiContext || screenshotContext;\n const locateParam = buildDetailedLocateParam(description, {\n cacheable: opt?.cacheable,\n deepLocate: opt?.deepLocate,\n xpath: opt?.xpath,\n });\n assert(locateParam, 'cannot get locate param for service locate');\n\n const locateResult = await runtime.service.locate(\n locateParam,\n context ? { context } : {},\n runtime.locateModelRuntime,\n opt?.abortSignal,\n );\n assert(locateResult.element, `Element not found: ${description}`);\n const verifyResult = buildLocateValidatorResult(\n targetCenter,\n locateResult.element,\n opt,\n );\n return verifyResult;\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","distanceOfTwoPoints","p1","p2","x1","y1","x2","y2","Math","includedInRect","point","rect","x","y","left","top","width","height","buildLocateValidatorResult","expectCenter","located","verifyLocateOption","distance","included","pass","assertPositiveSize","size","label","assert","Number","mapPointToScreenshotSpace","center","screenshotSize","opt","coordinateSpace","createScreenshotBoundLocatorContext","screenshotContext","createScreenshotBoundUIContext","undefined","targetCenter","verifyLocator","runtime","prompt","locateOpt","locateAndVerify","applyLocatorVerifyFn","locatorVerifyFn","input","customResult","errorMessage","error","Error","String","describeElementAtPoint","verifyPrompt","retryLimit","success","retryCount","resultPrompt","autoRetryDeepDescribe","autoRetryDeepLocate","deepDescribe","deepLocate","verifyResult","lastError","failureStage","describeModelRuntime","locateModelRuntime","retryRuntime","describeOpt","text","candidateVerifyResult","verifyElementDescriptionAtPoint","description","context","locateParam","buildDetailedLocateParam","locateResult"],"mappings":"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"}
|
package/dist/lib/index.js
CHANGED
|
@@ -46,10 +46,9 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
46
46
|
getTaskSearchArea: ()=>task_service_dump_js_namespaceObject.getTaskSearchArea,
|
|
47
47
|
parseDumpScriptAttributes: ()=>external_dump_index_js_namespaceObject.parseDumpScriptAttributes,
|
|
48
48
|
splitReportHtmlByExecution: ()=>external_report_js_namespaceObject.splitReportHtmlByExecution,
|
|
49
|
-
|
|
49
|
+
z: ()=>external_zod_namespaceObject.z,
|
|
50
50
|
generateDumpScriptTag: ()=>external_dump_index_js_namespaceObject.generateDumpScriptTag,
|
|
51
51
|
SizeSchema: ()=>external_ai_model_index_js_namespaceObject.SizeSchema,
|
|
52
|
-
z: ()=>external_zod_namespaceObject.z,
|
|
53
52
|
default: ()=>src,
|
|
54
53
|
getVersion: ()=>external_utils_js_namespaceObject.getVersion,
|
|
55
54
|
getMidsceneLocationSchema: ()=>external_ai_model_index_js_namespaceObject.getMidsceneLocationSchema,
|
|
@@ -151,7 +150,6 @@ exports.runConnectivityTest = __webpack_exports__.runConnectivityTest;
|
|
|
151
150
|
exports.splitReportFile = __webpack_exports__.splitReportFile;
|
|
152
151
|
exports.splitReportHtmlByExecution = __webpack_exports__.splitReportHtmlByExecution;
|
|
153
152
|
exports.unescapeContent = __webpack_exports__.unescapeContent;
|
|
154
|
-
exports.verifyElementByServiceLocate = __webpack_exports__.verifyElementByServiceLocate;
|
|
155
153
|
exports.verifyElementDescriptionAtPoint = __webpack_exports__.verifyElementDescriptionAtPoint;
|
|
156
154
|
exports.verifyLocator = __webpack_exports__.verifyLocator;
|
|
157
155
|
exports.z = __webpack_exports__.z;
|
|
@@ -203,7 +201,6 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
203
201
|
"splitReportFile",
|
|
204
202
|
"splitReportHtmlByExecution",
|
|
205
203
|
"unescapeContent",
|
|
206
|
-
"verifyElementByServiceLocate",
|
|
207
204
|
"verifyElementDescriptionAtPoint",
|
|
208
205
|
"verifyLocator",
|
|
209
206
|
"z"
|
package/dist/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/index.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { z } from 'zod';\nimport Service from './service/index';\nimport { TaskRunner } from './task-runner';\nimport { getVersion } from './utils';\n\nexport {\n plan,\n AiLocateElement,\n runConnectivityTest,\n getMidsceneLocationSchema,\n PointSchema,\n SizeSchema,\n RectSchema,\n TMultimodalPromptSchema,\n TUserPromptSchema,\n type TMultimodalPrompt,\n type TUserPrompt,\n type ConnectivityTestConfig,\n type ConnectivityTestResult,\n} from './ai-model/index';\n\nexport {\n MIDSCENE_MODEL_NAME,\n type CreateOpenAIClientFn,\n} from '@midscene/shared/env';\n\nexport type * from './types';\nexport {\n ServiceError,\n ExecutionDump,\n ReportActionDump,\n GroupedActionDump,\n type IExecutionDump,\n type IReportActionDump,\n type IGroupedActionDump,\n type ReportMeta,\n type GroupMeta,\n} from './types';\n\nexport { z };\n\nexport default Service;\nexport { TaskRunner, Service, getVersion };\n\nexport type {\n MidsceneYamlScript,\n MidsceneYamlTask,\n MidsceneYamlFlowItem,\n MidsceneYamlConfigResult,\n MidsceneYamlConfig,\n MidsceneYamlScriptWebEnv,\n MidsceneYamlScriptAndroidEnv,\n MidsceneYamlScriptIOSEnv,\n MidsceneYamlScriptEnv,\n LocateOption,\n DetailedLocateParam,\n} from './yaml';\n\nexport {\n Agent,\n type AgentOpt,\n type AiActOptions,\n type GherkinStepKeyword,\n type RunGherkinScenarioOptions,\n createAgent,\n} from './agent';\nexport {\n describeElementAtPoint,\n verifyElementDescriptionAtPoint,\n
|
|
1
|
+
{"version":3,"file":"index.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/index.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { z } from 'zod';\nimport Service from './service/index';\nimport { TaskRunner } from './task-runner';\nimport { getVersion } from './utils';\n\nexport {\n plan,\n AiLocateElement,\n runConnectivityTest,\n getMidsceneLocationSchema,\n PointSchema,\n SizeSchema,\n RectSchema,\n TMultimodalPromptSchema,\n TUserPromptSchema,\n type TMultimodalPrompt,\n type TUserPrompt,\n type ConnectivityTestConfig,\n type ConnectivityTestResult,\n} from './ai-model/index';\n\nexport {\n MIDSCENE_MODEL_NAME,\n type CreateOpenAIClientFn,\n} from '@midscene/shared/env';\n\nexport type * from './types';\nexport {\n ServiceError,\n ExecutionDump,\n ReportActionDump,\n GroupedActionDump,\n type IExecutionDump,\n type IReportActionDump,\n type IGroupedActionDump,\n type ReportMeta,\n type GroupMeta,\n} from './types';\n\nexport { z };\n\nexport default Service;\nexport { TaskRunner, Service, getVersion };\n\nexport type {\n MidsceneYamlScript,\n MidsceneYamlTask,\n MidsceneYamlFlowItem,\n MidsceneYamlConfigResult,\n MidsceneYamlConfig,\n MidsceneYamlScriptWebEnv,\n MidsceneYamlScriptAndroidEnv,\n MidsceneYamlScriptIOSEnv,\n MidsceneYamlScriptEnv,\n LocateOption,\n DetailedLocateParam,\n} from './yaml';\n\nexport {\n Agent,\n type AgentOpt,\n type AiActOptions,\n type GherkinStepKeyword,\n type MidsceneUsageMetrics,\n type RunGherkinScenarioOptions,\n type UsageBucket,\n createAgent,\n} from './agent';\nexport {\n describeElementAtPoint,\n verifyElementDescriptionAtPoint,\n verifyLocator,\n type DescribeElementAtPointOptions,\n type DescribeElementCoordinateSpace,\n type ElementDescriberRuntime,\n type VerifyElementDescriptionAtPointOptions,\n} from './element-describer';\n\n// Dump utilities\nexport {\n restoreImageReferences,\n escapeContent,\n unescapeContent,\n parseImageScripts,\n parseDumpScript,\n parseDumpScriptAttributes,\n generateImageScriptTag,\n generateDumpScriptTag,\n deriveTaskStatus,\n deriveCaseStatus,\n} from './dump';\nexport type { TaskStatusFields, DerivedTaskStatus } from './dump';\nexport {\n getTaskSearchArea,\n getTaskServiceDump,\n} from './dump/task-service-dump';\n\n// Report generator\nexport type { IReportGenerator } from './report-generator';\nexport { ReportGenerator, nullReportGenerator } from './report-generator';\nexport {\n collectDedupedExecutions,\n ReportMergingTool,\n dedupeExecutionsKeepLatest,\n splitReportHtmlByExecution,\n} from './report';\nexport {\n createReportCliCommands,\n reportFileToMarkdown,\n splitReportFile,\n mergeReportFiles,\n type ConsumeReportFileAction,\n type ReportFileToMarkdownOptions,\n type ReportCliCommandDefinition,\n type ReportCliCommandEntry,\n type SplitReportFileOptions,\n type MergeReportFilesOptions,\n type MergeReportFilesResult,\n} from './report-cli';\n\n// ScreenshotItem\nexport { ScreenshotItem } from './screenshot-item';\nexport { ScreenshotStore, type ScreenshotRef } from './dump/screenshot-store';\n\nexport {\n executionToMarkdown,\n reportToMarkdown,\n type ExecutionMarkdownOptions,\n type ExecutionMarkdownResult,\n type ReportMarkdownResult,\n type MarkdownAttachment,\n} from './report-markdown';\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","Service"],"mappings":";;;IACAA,oBAAoB,CAAC,GAAG,CAACC;QACxB,IAAIC,SAASD,UAAUA,OAAO,UAAU,GACvC,IAAOA,MAAM,CAAC,UAAU,GACxB,IAAOA;QACRD,oBAAoB,CAAC,CAACE,QAAQ;YAAE,GAAGA;QAAO;QAC1C,OAAOA;IACR;;;ICPAF,oBAAoB,CAAC,GAAG,CAAC,UAASG;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGH,oBAAoB,CAAC,CAACG,YAAYC,QAAQ,CAACJ,oBAAoB,CAAC,CAAC,UAASI,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAJ,oBAAoB,CAAC,GAAG,CAACM,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFP,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOQ,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACmCA,YAAeI"}
|
|
@@ -77,6 +77,7 @@ class ReportGenerator {
|
|
|
77
77
|
onExecutionUpdate(execution, reportMeta, attributes) {
|
|
78
78
|
this.lastExecution = execution;
|
|
79
79
|
this.lastReportMeta = reportMeta;
|
|
80
|
+
this.executionsByKey.set(this.getExecutionCommentKey(execution), execution);
|
|
80
81
|
this.mergeReportAttributes(attributes);
|
|
81
82
|
this.writeQueue = this.writeQueue.then(async ()=>{
|
|
82
83
|
if (this.destroyed) return;
|
|
@@ -91,6 +92,7 @@ class ReportGenerator {
|
|
|
91
92
|
await this.flush();
|
|
92
93
|
this.destroyed = true;
|
|
93
94
|
if (!this.initialized) return;
|
|
95
|
+
await this.appendAgentReportComment();
|
|
94
96
|
return this.reportPath;
|
|
95
97
|
}
|
|
96
98
|
getReportPath() {
|
|
@@ -169,10 +171,31 @@ class ReportGenerator {
|
|
|
169
171
|
}
|
|
170
172
|
await (0, promises_namespaceObject.appendFile)(this.reportPath, `\n${(0, html_utils_js_namespaceObject.generateDumpScriptTag)(serialized, this.getDumpScriptAttributes())}`);
|
|
171
173
|
}
|
|
174
|
+
async appendAgentReportComment() {
|
|
175
|
+
if (this.agentCommentWritten || !this.lastReportMeta || 0 === this.executionsByKey.size) return;
|
|
176
|
+
const reportDump = new external_types_js_namespaceObject.ReportActionDump({
|
|
177
|
+
sdkVersion: this.lastReportMeta.sdkVersion,
|
|
178
|
+
groupName: this.lastReportMeta.groupName,
|
|
179
|
+
groupDescription: this.lastReportMeta.groupDescription,
|
|
180
|
+
modelBriefs: this.lastReportMeta.modelBriefs,
|
|
181
|
+
deviceType: this.lastReportMeta.deviceType,
|
|
182
|
+
executions: Array.from(this.executionsByKey.values())
|
|
183
|
+
});
|
|
184
|
+
await (0, promises_namespaceObject.appendFile)(this.reportPath, `\n${(0, html_utils_js_namespaceObject.generateAgentReportComment)(reportDump)}`);
|
|
185
|
+
this.agentCommentWritten = true;
|
|
186
|
+
}
|
|
172
187
|
getExecutionLogKey(execution) {
|
|
173
188
|
if (!execution.id) throw new Error('ReportGenerator: execution.id is required for persisting execution dumps');
|
|
174
189
|
return `id:${execution.id}`;
|
|
175
190
|
}
|
|
191
|
+
getExecutionCommentKey(execution) {
|
|
192
|
+
if (execution.id) return `id:${execution.id}`;
|
|
193
|
+
const existingKey = this.executionCommentKeyByObject.get(execution);
|
|
194
|
+
if (existingKey) return existingKey;
|
|
195
|
+
const key = `no-id:${this.executionCommentKeyIndex++}`;
|
|
196
|
+
this.executionCommentKeyByObject.set(execution, key);
|
|
197
|
+
return key;
|
|
198
|
+
}
|
|
176
199
|
async persistExecutionDumpToFile(execution, singleDump) {
|
|
177
200
|
const dir = (0, external_node_path_namespaceObject.dirname)(this.reportPath);
|
|
178
201
|
if (!(0, external_node_fs_namespaceObject.existsSync)(dir)) (0, external_node_fs_namespaceObject.mkdirSync)(dir, {
|
|
@@ -202,7 +225,11 @@ class ReportGenerator {
|
|
|
202
225
|
_define_property(this, "initialized", false);
|
|
203
226
|
_define_property(this, "lastExecution", void 0);
|
|
204
227
|
_define_property(this, "lastReportMeta", void 0);
|
|
228
|
+
_define_property(this, "executionsByKey", new Map());
|
|
229
|
+
_define_property(this, "executionCommentKeyByObject", new WeakMap());
|
|
230
|
+
_define_property(this, "executionCommentKeyIndex", 0);
|
|
205
231
|
_define_property(this, "reportAttributes", {});
|
|
232
|
+
_define_property(this, "agentCommentWritten", false);
|
|
206
233
|
_define_property(this, "writeQueue", Promise.resolve());
|
|
207
234
|
_define_property(this, "destroyed", false);
|
|
208
235
|
this.reportPath = options.reportPath;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-generator.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/report-generator.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/*\n * PERF INVARIANT — DO NOT reintroduce sync fs APIs (writeFileSync /\n * appendFileSync) in this file's write paths. `ReportGenerator` runs on\n * the Electron main event loop during agent execution, and a single\n * progress tick appends a multi-MB ExecutionDump payload. Sync I/O here\n * blocked the loop for 20+ seconds per run, freezing IPC, scrcpy and\n * every renderer round-trip. Always use `fs/promises`. See commit\n * 6a25e05c and `report-generator-async-contract.test.ts`.\n */\nimport { existsSync, mkdirSync, readdirSync } from 'node:fs';\nimport {\n appendFile as appendFileAsync,\n writeFile as writeFileAsync,\n} from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport {\n MIDSCENE_REPORT_QUIET,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { ifInBrowser, logMsg, uuid } from '@midscene/shared/utils';\nimport {\n DATA_SCREENSHOT_MODE_ATTR,\n generateDumpScriptTag,\n generateImageScriptTag,\n getBaseUrlFixScript,\n} from './dump/html-utils';\nimport { ScreenshotStore } from './dump/screenshot-store';\nimport {\n type ExecutionDump,\n ReportActionDump,\n type ReportAttributes,\n type ReportMeta,\n type ScreenshotMode,\n} from './types';\nimport { getReportTpl } from './utils';\n\nexport interface IReportGenerator {\n /**\n * Write or update a single execution.\n * Each call appends a new dump script tag. The frontend deduplicates\n * executions with the same id/name, keeping only the last one.\n *\n * @param execution Current execution's full data\n * @param reportMeta Report-level metadata (groupName, sdkVersion, etc.)\n */\n onExecutionUpdate(\n execution: ExecutionDump,\n reportMeta: ReportMeta,\n attributes?: ReportAttributes,\n ): void;\n\n /**\n * @deprecated Use onExecutionUpdate instead. Kept for backward compatibility.\n */\n onDumpUpdate?(dump: ReportActionDump): void;\n\n /**\n * Wait for all queued write operations to complete.\n */\n flush(): Promise<void>;\n\n /**\n * Finalize the report. Calls flush() internally.\n */\n finalize(): Promise<string | undefined>;\n\n getReportPath(): string | undefined;\n}\n\nexport const nullReportGenerator: IReportGenerator = {\n onExecutionUpdate: () => {},\n flush: async () => {},\n finalize: async () => undefined,\n getReportPath: () => undefined,\n};\n\nexport function assertReportGenerationOptions(opts: {\n generateReport?: boolean;\n persistExecutionDump?: boolean;\n}): void {\n if (opts.generateReport === false && opts.persistExecutionDump === true) {\n throw new Error(\n 'persistExecutionDump cannot be true when generateReport is false',\n );\n }\n}\n\nexport class ReportGenerator implements IReportGenerator {\n private reportPath: string;\n private screenshotMode: ScreenshotMode;\n private shouldPersistExecutionDump: boolean;\n private autoPrint: boolean;\n private firstWriteDone = false;\n private executionLogIndex = 0;\n private executionLogFileIndexByExecutionKey = new Map<string, number>();\n\n // Unique identifier for this report stream — used as data-group-id\n private readonly reportStreamId: string;\n\n // Tracks screenshots already written to disk (by id) to avoid duplicates\n private screenshotStore: ScreenshotStore;\n private initialized = false;\n\n // Tracks the last execution + groupMeta for re-writing on finalize\n private lastExecution?: ExecutionDump;\n private lastReportMeta?: ReportMeta;\n private reportAttributes: Record<string, string> = {};\n\n // write queue for serial execution\n private writeQueue: Promise<void> = Promise.resolve();\n private destroyed = false;\n\n constructor(options: {\n reportPath: string;\n screenshotMode: ScreenshotMode;\n persistExecutionDump?: boolean;\n autoPrint?: boolean;\n reuseExistingReport?: boolean;\n }) {\n this.reportPath = options.reportPath;\n this.screenshotMode = options.screenshotMode;\n this.shouldPersistExecutionDump = options.persistExecutionDump ?? false;\n this.autoPrint = options.autoPrint ?? true;\n this.reportStreamId = uuid();\n this.screenshotStore = new ScreenshotStore({\n mode: this.screenshotMode === 'inline' ? 'inline' : 'directory',\n reportPath: this.reportPath,\n screenshotsDir: join(dirname(this.reportPath), 'screenshots'),\n writeInlineImage: async (id, base64) => {\n await appendFileAsync(\n this.reportPath,\n `\\n${generateImageScriptTag(id, base64)}`,\n );\n },\n alsoWriteFileCopy: this.shouldPersistExecutionDump,\n });\n if (options.reuseExistingReport) {\n this.hydrateStateFromExistingReport();\n }\n }\n\n static create(\n reportFileName: string,\n opts: {\n generateReport?: boolean;\n persistExecutionDump?: boolean;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n autoPrintReportMsg?: boolean;\n reuseExistingReport?: boolean;\n },\n ): IReportGenerator {\n assertReportGenerationOptions(opts);\n validateReportFileName(reportFileName);\n if (opts.generateReport === false) return nullReportGenerator;\n\n // In browser environment, file system is not available\n if (ifInBrowser) return nullReportGenerator;\n\n const reportRootDir = getMidsceneRunSubDir('report');\n const outputDir = join(reportRootDir, reportFileName);\n const reportPath =\n opts.outputFormat === 'html-and-external-assets'\n ? join(outputDir, 'index.html')\n : join(reportRootDir, ensureHtmlFileName(reportFileName));\n return new ReportGenerator({\n reportPath,\n screenshotMode:\n opts.outputFormat === 'html-and-external-assets'\n ? 'directory'\n : 'inline',\n persistExecutionDump: opts.persistExecutionDump,\n autoPrint: opts.autoPrintReportMsg,\n reuseExistingReport: opts.reuseExistingReport,\n });\n }\n\n onExecutionUpdate(\n execution: ExecutionDump,\n reportMeta: ReportMeta,\n attributes?: ReportAttributes,\n ): void {\n this.lastExecution = execution;\n this.lastReportMeta = reportMeta;\n this.mergeReportAttributes(attributes);\n this.writeQueue = this.writeQueue.then(async () => {\n if (this.destroyed) return;\n await this.doWriteExecution(execution, reportMeta);\n });\n }\n\n async flush(): Promise<void> {\n await this.writeQueue;\n }\n\n async finalize(): Promise<string | undefined> {\n // Re-write the last execution to capture any final state changes\n if (this.lastExecution && this.lastReportMeta) {\n this.onExecutionUpdate(this.lastExecution, this.lastReportMeta);\n }\n await this.flush();\n this.destroyed = true;\n\n if (!this.initialized) {\n // No executions were ever written — no file exists\n return undefined;\n }\n\n return this.reportPath;\n }\n\n getReportPath(): string | undefined {\n return this.reportPath;\n }\n\n private printReportPath(): void {\n if (!this.autoPrint || !this.reportPath) return;\n if (globalConfigManager.getEnvConfigInBoolean(MIDSCENE_REPORT_QUIET))\n return;\n\n if (this.screenshotMode === 'directory') {\n logMsg(\n `Midscene - report file updated: npx serve ${dirname(this.reportPath)}`,\n );\n } else {\n logMsg(`Midscene - report file updated: ${this.reportPath}`);\n }\n }\n\n private async doWriteExecution(\n execution: ExecutionDump,\n reportMeta: ReportMeta,\n ): Promise<void> {\n const singleDump = this.wrapAsReportDump(execution, reportMeta);\n\n if (this.screenshotMode === 'inline') {\n await this.writeInlineExecution(execution, singleDump);\n } else {\n await this.writeDirectoryExecution(execution, singleDump);\n }\n\n if (this.shouldPersistExecutionDump) {\n await this.persistExecutionDumpToFile(execution, singleDump);\n }\n\n if (!this.firstWriteDone) {\n this.firstWriteDone = true;\n this.printReportPath();\n }\n }\n\n private mergeReportAttributes(attributes?: ReportAttributes): void {\n if (!attributes) {\n return;\n }\n\n for (const [key, value] of Object.entries(attributes)) {\n if (value === undefined || value === null) {\n continue;\n }\n this.reportAttributes[key] = String(value);\n }\n }\n\n private hydrateStateFromExistingReport(): void {\n if (!existsSync(this.reportPath)) {\n return;\n }\n\n // Reuse existing report file and append new updates instead of rewriting.\n this.initialized = true;\n\n if (!this.shouldPersistExecutionDump) {\n return;\n }\n\n const reportDir = dirname(this.reportPath);\n const existingExecutionIndices = readdirSync(reportDir)\n .map((name) => /^(\\d+)\\.execution\\.json$/.exec(name)?.[1])\n .filter((index): index is string => Boolean(index))\n .map((index) => Number.parseInt(index, 10))\n .filter((index) => Number.isFinite(index));\n\n if (existingExecutionIndices.length > 0) {\n this.executionLogIndex = Math.max(...existingExecutionIndices);\n }\n }\n\n private getDumpScriptAttributes(): Record<string, string> {\n return {\n 'data-group-id': this.reportStreamId,\n // Self-describe how this report file stores screenshots so consumers\n // (merge/delete) never have to guess the mode from the filesystem.\n [DATA_SCREENSHOT_MODE_ATTR]: this.screenshotMode,\n ...this.reportAttributes,\n };\n }\n\n /**\n * Wrap an ExecutionDump + ReportMeta into a single-execution ReportActionDump.\n */\n private wrapAsReportDump(\n execution: ExecutionDump,\n reportMeta: ReportMeta,\n ): ReportActionDump {\n return new ReportActionDump({\n sdkVersion: reportMeta.sdkVersion,\n groupName: reportMeta.groupName,\n groupDescription: reportMeta.groupDescription,\n modelBriefs: reportMeta.modelBriefs,\n deviceType: reportMeta.deviceType,\n executions: [execution],\n });\n }\n\n /**\n * Append-only inline mode: write new screenshots and a dump tag on every call.\n * The frontend deduplicates executions with the same id/name (keeps last).\n * Duplicate dump JSON is acceptable; only screenshots are deduplicated.\n *\n * All writes go through `fs/promises` so they run on libuv's thread pool\n * rather than blocking the Node event loop. A long agent run previously\n * appended multi-MB dumps (screenshots + serialized tasks) per progress\n * tick on the main thread, starving IPC and UI for >10s per stall.\n */\n private async writeInlineExecution(\n execution: ExecutionDump,\n singleDump: ReportActionDump,\n ): Promise<void> {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Initialize: write HTML template once\n if (!this.initialized) {\n await writeFileAsync(this.reportPath, getReportTpl());\n this.initialized = true;\n }\n\n // Append new screenshots (skip already-written ones)\n for (const screenshot of execution.collectScreenshots()) {\n await this.screenshotStore.persist(screenshot);\n }\n\n // Append dump tag (always — frontend keeps only last per execution id)\n const serialized = singleDump.serialize();\n await appendFileAsync(\n this.reportPath,\n `\\n${generateDumpScriptTag(serialized, this.getDumpScriptAttributes())}`,\n );\n }\n\n private async writeDirectoryExecution(\n execution: ExecutionDump,\n singleDump: ReportActionDump,\n ): Promise<void> {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n for (const screenshot of execution.collectScreenshots()) {\n await this.screenshotStore.persist(screenshot);\n }\n\n // 2. Append dump tag (always — frontend keeps only last per execution id)\n const serialized = singleDump.serialize();\n\n if (!this.initialized) {\n await writeFileAsync(\n this.reportPath,\n `${getReportTpl()}${getBaseUrlFixScript()}`,\n );\n this.initialized = true;\n }\n\n await appendFileAsync(\n this.reportPath,\n `\\n${generateDumpScriptTag(serialized, this.getDumpScriptAttributes())}`,\n );\n }\n\n private getExecutionLogKey(execution: ExecutionDump): string {\n if (!execution.id) {\n throw new Error(\n 'ReportGenerator: execution.id is required for persisting execution dumps',\n );\n }\n return `id:${execution.id}`;\n }\n\n private async persistExecutionDumpToFile(\n execution: ExecutionDump,\n singleDump: ReportActionDump,\n ): Promise<void> {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const executionLogKey = this.getExecutionLogKey(execution);\n let fileIndex =\n this.executionLogFileIndexByExecutionKey.get(executionLogKey);\n if (!fileIndex) {\n this.executionLogIndex += 1;\n fileIndex = this.executionLogIndex;\n this.executionLogFileIndexByExecutionKey.set(executionLogKey, fileIndex);\n }\n\n const fileName = `${fileIndex}.execution.json`;\n const filePath = join(dirname(this.reportPath), fileName);\n await writeFileAsync(filePath, singleDump.serialize(2), 'utf-8');\n }\n}\n\nfunction ensureHtmlFileName(reportFileName: string): string {\n return reportFileName.endsWith('.html')\n ? reportFileName\n : `${reportFileName}.html`;\n}\n\nfunction validateReportFileName(reportFileName: string): void {\n if (!reportFileName?.trim()) {\n throw new Error('reportFileName must be a non-empty string');\n }\n\n if (/[\\\\/]/.test(reportFileName)) {\n throw new Error(\n 'reportFileName must not contain path separators (`/` or `\\\\\\\\`)',\n );\n }\n\n if (/[:*?\"<>|]/.test(reportFileName)) {\n throw new Error(\n 'reportFileName contains illegal filename characters: : * ? \" < > |',\n );\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","nullReportGenerator","undefined","assertReportGenerationOptions","opts","Error","ReportGenerator","reportFileName","validateReportFileName","ifInBrowser","reportRootDir","getMidsceneRunSubDir","outputDir","join","reportPath","ensureHtmlFileName","execution","reportMeta","attributes","globalConfigManager","MIDSCENE_REPORT_QUIET","logMsg","dirname","singleDump","value","String","existsSync","reportDir","existingExecutionIndices","readdirSync","name","index","Boolean","Number","Math","DATA_SCREENSHOT_MODE_ATTR","ReportActionDump","dir","mkdirSync","writeFileAsync","getReportTpl","screenshot","serialized","appendFileAsync","generateDumpScriptTag","getBaseUrlFixScript","executionLogKey","fileIndex","fileName","filePath","options","Map","Promise","uuid","ScreenshotStore","id","base64","generateImageScriptTag"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"report-generator.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/report-generator.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/*\n * PERF INVARIANT — DO NOT reintroduce sync fs APIs (writeFileSync /\n * appendFileSync) in this file's write paths. `ReportGenerator` runs on\n * the Electron main event loop during agent execution, and a single\n * progress tick appends a multi-MB ExecutionDump payload. Sync I/O here\n * blocked the loop for 20+ seconds per run, freezing IPC, scrcpy and\n * every renderer round-trip. Always use `fs/promises`. See commit\n * 6a25e05c and `report-generator-async-contract.test.ts`.\n */\nimport { existsSync, mkdirSync, readdirSync } from 'node:fs';\nimport {\n appendFile as appendFileAsync,\n writeFile as writeFileAsync,\n} from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport {\n MIDSCENE_REPORT_QUIET,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { ifInBrowser, logMsg, uuid } from '@midscene/shared/utils';\nimport {\n DATA_SCREENSHOT_MODE_ATTR,\n generateAgentReportComment,\n generateDumpScriptTag,\n generateImageScriptTag,\n getBaseUrlFixScript,\n} from './dump/html-utils';\nimport { ScreenshotStore } from './dump/screenshot-store';\nimport {\n type ExecutionDump,\n ReportActionDump,\n type ReportAttributes,\n type ReportMeta,\n type ScreenshotMode,\n} from './types';\nimport { getReportTpl } from './utils';\n\nexport interface IReportGenerator {\n /**\n * Write or update a single execution.\n * Each call appends a new dump script tag. The frontend deduplicates\n * executions with the same id/name, keeping only the last one.\n *\n * @param execution Current execution's full data\n * @param reportMeta Report-level metadata (groupName, sdkVersion, etc.)\n */\n onExecutionUpdate(\n execution: ExecutionDump,\n reportMeta: ReportMeta,\n attributes?: ReportAttributes,\n ): void;\n\n /**\n * @deprecated Use onExecutionUpdate instead. Kept for backward compatibility.\n */\n onDumpUpdate?(dump: ReportActionDump): void;\n\n /**\n * Wait for all queued write operations to complete.\n */\n flush(): Promise<void>;\n\n /**\n * Finalize the report. Calls flush() internally.\n */\n finalize(): Promise<string | undefined>;\n\n getReportPath(): string | undefined;\n}\n\nexport const nullReportGenerator: IReportGenerator = {\n onExecutionUpdate: () => {},\n flush: async () => {},\n finalize: async () => undefined,\n getReportPath: () => undefined,\n};\n\nexport function assertReportGenerationOptions(opts: {\n generateReport?: boolean;\n persistExecutionDump?: boolean;\n}): void {\n if (opts.generateReport === false && opts.persistExecutionDump === true) {\n throw new Error(\n 'persistExecutionDump cannot be true when generateReport is false',\n );\n }\n}\n\nexport class ReportGenerator implements IReportGenerator {\n private reportPath: string;\n private screenshotMode: ScreenshotMode;\n private shouldPersistExecutionDump: boolean;\n private autoPrint: boolean;\n private firstWriteDone = false;\n private executionLogIndex = 0;\n private executionLogFileIndexByExecutionKey = new Map<string, number>();\n\n // Unique identifier for this report stream — used as data-group-id\n private readonly reportStreamId: string;\n\n // Tracks screenshots already written to disk (by id) to avoid duplicates\n private screenshotStore: ScreenshotStore;\n private initialized = false;\n\n // Tracks the last execution + groupMeta for re-writing on finalize\n private lastExecution?: ExecutionDump;\n private lastReportMeta?: ReportMeta;\n private executionsByKey = new Map<string, ExecutionDump>();\n private executionCommentKeyByObject = new WeakMap<ExecutionDump, string>();\n private executionCommentKeyIndex = 0;\n private reportAttributes: Record<string, string> = {};\n private agentCommentWritten = false;\n\n // write queue for serial execution\n private writeQueue: Promise<void> = Promise.resolve();\n private destroyed = false;\n\n constructor(options: {\n reportPath: string;\n screenshotMode: ScreenshotMode;\n persistExecutionDump?: boolean;\n autoPrint?: boolean;\n reuseExistingReport?: boolean;\n }) {\n this.reportPath = options.reportPath;\n this.screenshotMode = options.screenshotMode;\n this.shouldPersistExecutionDump = options.persistExecutionDump ?? false;\n this.autoPrint = options.autoPrint ?? true;\n this.reportStreamId = uuid();\n this.screenshotStore = new ScreenshotStore({\n mode: this.screenshotMode === 'inline' ? 'inline' : 'directory',\n reportPath: this.reportPath,\n screenshotsDir: join(dirname(this.reportPath), 'screenshots'),\n writeInlineImage: async (id, base64) => {\n await appendFileAsync(\n this.reportPath,\n `\\n${generateImageScriptTag(id, base64)}`,\n );\n },\n alsoWriteFileCopy: this.shouldPersistExecutionDump,\n });\n if (options.reuseExistingReport) {\n this.hydrateStateFromExistingReport();\n }\n }\n\n static create(\n reportFileName: string,\n opts: {\n generateReport?: boolean;\n persistExecutionDump?: boolean;\n outputFormat?: 'single-html' | 'html-and-external-assets';\n autoPrintReportMsg?: boolean;\n reuseExistingReport?: boolean;\n },\n ): IReportGenerator {\n assertReportGenerationOptions(opts);\n validateReportFileName(reportFileName);\n if (opts.generateReport === false) return nullReportGenerator;\n\n // In browser environment, file system is not available\n if (ifInBrowser) return nullReportGenerator;\n\n const reportRootDir = getMidsceneRunSubDir('report');\n const outputDir = join(reportRootDir, reportFileName);\n const reportPath =\n opts.outputFormat === 'html-and-external-assets'\n ? join(outputDir, 'index.html')\n : join(reportRootDir, ensureHtmlFileName(reportFileName));\n return new ReportGenerator({\n reportPath,\n screenshotMode:\n opts.outputFormat === 'html-and-external-assets'\n ? 'directory'\n : 'inline',\n persistExecutionDump: opts.persistExecutionDump,\n autoPrint: opts.autoPrintReportMsg,\n reuseExistingReport: opts.reuseExistingReport,\n });\n }\n\n onExecutionUpdate(\n execution: ExecutionDump,\n reportMeta: ReportMeta,\n attributes?: ReportAttributes,\n ): void {\n this.lastExecution = execution;\n this.lastReportMeta = reportMeta;\n this.executionsByKey.set(this.getExecutionCommentKey(execution), execution);\n this.mergeReportAttributes(attributes);\n this.writeQueue = this.writeQueue.then(async () => {\n if (this.destroyed) return;\n await this.doWriteExecution(execution, reportMeta);\n });\n }\n\n async flush(): Promise<void> {\n await this.writeQueue;\n }\n\n async finalize(): Promise<string | undefined> {\n // Re-write the last execution to capture any final state changes\n if (this.lastExecution && this.lastReportMeta) {\n this.onExecutionUpdate(this.lastExecution, this.lastReportMeta);\n }\n await this.flush();\n this.destroyed = true;\n\n if (!this.initialized) {\n // No executions were ever written — no file exists\n return undefined;\n }\n\n await this.appendAgentReportComment();\n return this.reportPath;\n }\n\n getReportPath(): string | undefined {\n return this.reportPath;\n }\n\n private printReportPath(): void {\n if (!this.autoPrint || !this.reportPath) return;\n if (globalConfigManager.getEnvConfigInBoolean(MIDSCENE_REPORT_QUIET))\n return;\n\n if (this.screenshotMode === 'directory') {\n logMsg(\n `Midscene - report file updated: npx serve ${dirname(this.reportPath)}`,\n );\n } else {\n logMsg(`Midscene - report file updated: ${this.reportPath}`);\n }\n }\n\n private async doWriteExecution(\n execution: ExecutionDump,\n reportMeta: ReportMeta,\n ): Promise<void> {\n const singleDump = this.wrapAsReportDump(execution, reportMeta);\n\n if (this.screenshotMode === 'inline') {\n await this.writeInlineExecution(execution, singleDump);\n } else {\n await this.writeDirectoryExecution(execution, singleDump);\n }\n\n if (this.shouldPersistExecutionDump) {\n await this.persistExecutionDumpToFile(execution, singleDump);\n }\n\n if (!this.firstWriteDone) {\n this.firstWriteDone = true;\n this.printReportPath();\n }\n }\n\n private mergeReportAttributes(attributes?: ReportAttributes): void {\n if (!attributes) {\n return;\n }\n\n for (const [key, value] of Object.entries(attributes)) {\n if (value === undefined || value === null) {\n continue;\n }\n this.reportAttributes[key] = String(value);\n }\n }\n\n private hydrateStateFromExistingReport(): void {\n if (!existsSync(this.reportPath)) {\n return;\n }\n\n // Reuse existing report file and append new updates instead of rewriting.\n this.initialized = true;\n\n if (!this.shouldPersistExecutionDump) {\n return;\n }\n\n const reportDir = dirname(this.reportPath);\n const existingExecutionIndices = readdirSync(reportDir)\n .map((name) => /^(\\d+)\\.execution\\.json$/.exec(name)?.[1])\n .filter((index): index is string => Boolean(index))\n .map((index) => Number.parseInt(index, 10))\n .filter((index) => Number.isFinite(index));\n\n if (existingExecutionIndices.length > 0) {\n this.executionLogIndex = Math.max(...existingExecutionIndices);\n }\n }\n\n private getDumpScriptAttributes(): Record<string, string> {\n return {\n 'data-group-id': this.reportStreamId,\n // Self-describe how this report file stores screenshots so consumers\n // (merge/delete) never have to guess the mode from the filesystem.\n [DATA_SCREENSHOT_MODE_ATTR]: this.screenshotMode,\n ...this.reportAttributes,\n };\n }\n\n /**\n * Wrap an ExecutionDump + ReportMeta into a single-execution ReportActionDump.\n */\n private wrapAsReportDump(\n execution: ExecutionDump,\n reportMeta: ReportMeta,\n ): ReportActionDump {\n return new ReportActionDump({\n sdkVersion: reportMeta.sdkVersion,\n groupName: reportMeta.groupName,\n groupDescription: reportMeta.groupDescription,\n modelBriefs: reportMeta.modelBriefs,\n deviceType: reportMeta.deviceType,\n executions: [execution],\n });\n }\n\n /**\n * Append-only inline mode: write new screenshots and a dump tag on every call.\n * The frontend deduplicates executions with the same id/name (keeps last).\n * Duplicate dump JSON is acceptable; only screenshots are deduplicated.\n *\n * All writes go through `fs/promises` so they run on libuv's thread pool\n * rather than blocking the Node event loop. A long agent run previously\n * appended multi-MB dumps (screenshots + serialized tasks) per progress\n * tick on the main thread, starving IPC and UI for >10s per stall.\n */\n private async writeInlineExecution(\n execution: ExecutionDump,\n singleDump: ReportActionDump,\n ): Promise<void> {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Initialize: write HTML template once\n if (!this.initialized) {\n await writeFileAsync(this.reportPath, getReportTpl());\n this.initialized = true;\n }\n\n // Append new screenshots (skip already-written ones)\n for (const screenshot of execution.collectScreenshots()) {\n await this.screenshotStore.persist(screenshot);\n }\n\n // Append dump tag (always — frontend keeps only last per execution id)\n const serialized = singleDump.serialize();\n await appendFileAsync(\n this.reportPath,\n `\\n${generateDumpScriptTag(serialized, this.getDumpScriptAttributes())}`,\n );\n }\n\n private async writeDirectoryExecution(\n execution: ExecutionDump,\n singleDump: ReportActionDump,\n ): Promise<void> {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n for (const screenshot of execution.collectScreenshots()) {\n await this.screenshotStore.persist(screenshot);\n }\n\n // 2. Append dump tag (always — frontend keeps only last per execution id)\n const serialized = singleDump.serialize();\n\n if (!this.initialized) {\n await writeFileAsync(\n this.reportPath,\n `${getReportTpl()}${getBaseUrlFixScript()}`,\n );\n this.initialized = true;\n }\n\n await appendFileAsync(\n this.reportPath,\n `\\n${generateDumpScriptTag(serialized, this.getDumpScriptAttributes())}`,\n );\n }\n\n private async appendAgentReportComment(): Promise<void> {\n if (\n this.agentCommentWritten ||\n !this.lastReportMeta ||\n this.executionsByKey.size === 0\n ) {\n return;\n }\n\n const reportDump = new ReportActionDump({\n sdkVersion: this.lastReportMeta.sdkVersion,\n groupName: this.lastReportMeta.groupName,\n groupDescription: this.lastReportMeta.groupDescription,\n modelBriefs: this.lastReportMeta.modelBriefs,\n deviceType: this.lastReportMeta.deviceType,\n executions: Array.from(this.executionsByKey.values()),\n });\n await appendFileAsync(\n this.reportPath,\n `\\n${generateAgentReportComment(reportDump)}`,\n );\n this.agentCommentWritten = true;\n }\n\n private getExecutionLogKey(execution: ExecutionDump): string {\n if (!execution.id) {\n throw new Error(\n 'ReportGenerator: execution.id is required for persisting execution dumps',\n );\n }\n return `id:${execution.id}`;\n }\n\n private getExecutionCommentKey(execution: ExecutionDump): string {\n if (execution.id) {\n return `id:${execution.id}`;\n }\n\n const existingKey = this.executionCommentKeyByObject.get(execution);\n if (existingKey) {\n return existingKey;\n }\n\n const key = `no-id:${this.executionCommentKeyIndex++}`;\n this.executionCommentKeyByObject.set(execution, key);\n return key;\n }\n\n private async persistExecutionDumpToFile(\n execution: ExecutionDump,\n singleDump: ReportActionDump,\n ): Promise<void> {\n const dir = dirname(this.reportPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const executionLogKey = this.getExecutionLogKey(execution);\n let fileIndex =\n this.executionLogFileIndexByExecutionKey.get(executionLogKey);\n if (!fileIndex) {\n this.executionLogIndex += 1;\n fileIndex = this.executionLogIndex;\n this.executionLogFileIndexByExecutionKey.set(executionLogKey, fileIndex);\n }\n\n const fileName = `${fileIndex}.execution.json`;\n const filePath = join(dirname(this.reportPath), fileName);\n await writeFileAsync(filePath, singleDump.serialize(2), 'utf-8');\n }\n}\n\nfunction ensureHtmlFileName(reportFileName: string): string {\n return reportFileName.endsWith('.html')\n ? reportFileName\n : `${reportFileName}.html`;\n}\n\nfunction validateReportFileName(reportFileName: string): void {\n if (!reportFileName?.trim()) {\n throw new Error('reportFileName must be a non-empty string');\n }\n\n if (/[\\\\/]/.test(reportFileName)) {\n throw new Error(\n 'reportFileName must not contain path separators (`/` or `\\\\\\\\`)',\n );\n }\n\n if (/[:*?\"<>|]/.test(reportFileName)) {\n throw new Error(\n 'reportFileName contains illegal filename characters: : * ? \" < > |',\n );\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","nullReportGenerator","undefined","assertReportGenerationOptions","opts","Error","ReportGenerator","reportFileName","validateReportFileName","ifInBrowser","reportRootDir","getMidsceneRunSubDir","outputDir","join","reportPath","ensureHtmlFileName","execution","reportMeta","attributes","globalConfigManager","MIDSCENE_REPORT_QUIET","logMsg","dirname","singleDump","value","String","existsSync","reportDir","existingExecutionIndices","readdirSync","name","index","Boolean","Number","Math","DATA_SCREENSHOT_MODE_ATTR","ReportActionDump","dir","mkdirSync","writeFileAsync","getReportTpl","screenshot","serialized","appendFileAsync","generateDumpScriptTag","getBaseUrlFixScript","reportDump","Array","generateAgentReportComment","existingKey","executionLogKey","fileIndex","fileName","filePath","options","Map","WeakMap","Promise","uuid","ScreenshotStore","id","base64","generateImageScriptTag"],"mappings":"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"}
|