@midscene/core 1.12.10-beta-20260920031616.0 → 1.13.0
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 +103 -6
- package/dist/es/agent/agent.mjs.map +1 -1
- package/dist/es/agent/index.mjs +4 -3
- package/dist/es/agent/tasks.mjs +2 -2
- package/dist/es/agent/tasks.mjs.map +1 -1
- package/dist/es/agent/test-runner-nodes.mjs +291 -40
- package/dist/es/agent/test-runner-nodes.mjs.map +1 -1
- package/dist/es/agent/utils.mjs +1 -1
- package/dist/es/device/index.mjs +15 -2
- package/dist/es/device/index.mjs.map +1 -1
- package/dist/es/dump/html-utils.mjs +37 -4
- package/dist/es/dump/html-utils.mjs.map +1 -1
- package/dist/es/dump/screenshot-store.mjs +8 -1
- package/dist/es/dump/screenshot-store.mjs.map +1 -1
- package/dist/es/report-cli.mjs +9 -4
- package/dist/es/report-cli.mjs.map +1 -1
- package/dist/es/report-generator.mjs +117 -4
- package/dist/es/report-generator.mjs.map +1 -1
- package/dist/es/report-html-template.mjs +1 -1
- package/dist/es/report.mjs +190 -41
- package/dist/es/report.mjs.map +1 -1
- package/dist/es/test-run-report.mjs.map +1 -1
- package/dist/es/test-runner/engine/case-runner.mjs +52 -0
- package/dist/es/test-runner/engine/case-runner.mjs.map +1 -0
- package/dist/es/test-runner/engine/document-runtime.mjs +273 -0
- package/dist/es/test-runner/engine/document-runtime.mjs.map +1 -0
- package/dist/es/test-runner/engine/execute-step.mjs +177 -0
- package/dist/es/test-runner/engine/execute-step.mjs.map +1 -0
- package/dist/es/test-runner/engine/execution-failure.mjs +39 -0
- package/dist/es/test-runner/engine/execution-failure.mjs.map +1 -0
- package/dist/es/test-runner/engine/index.mjs +12 -0
- package/dist/es/test-runner/engine/project-runtime.mjs +142 -0
- package/dist/es/test-runner/engine/project-runtime.mjs.map +1 -0
- package/dist/es/test-runner/engine/registry.mjs +61 -0
- package/dist/es/test-runner/engine/registry.mjs.map +1 -0
- package/dist/es/test-runner/engine/resource-operations.mjs +211 -0
- package/dist/es/test-runner/engine/resource-operations.mjs.map +1 -0
- package/dist/es/test-runner/engine/run-collected-case.mjs +193 -0
- package/dist/es/test-runner/engine/run-collected-case.mjs.map +1 -0
- package/dist/es/test-runner/engine/run-workflow-document.mjs +155 -0
- package/dist/es/test-runner/engine/run-workflow-document.mjs.map +1 -0
- package/dist/es/test-runner/engine/scheduler.mjs +27 -0
- package/dist/es/test-runner/engine/scheduler.mjs.map +1 -0
- package/dist/es/test-runner/engine/scope-teardown.mjs +16 -0
- package/dist/es/test-runner/engine/scope-teardown.mjs.map +1 -0
- package/dist/es/test-runner/engine/types.mjs +0 -0
- package/dist/es/test-runner/errors.mjs +201 -0
- package/dist/es/test-runner/errors.mjs.map +1 -0
- package/dist/es/test-runner/execution-record.mjs +83 -0
- package/dist/es/test-runner/execution-record.mjs.map +1 -0
- package/dist/es/test-runner/index.mjs +12 -0
- package/dist/es/test-runner/node/define-node.mjs +44 -0
- package/dist/es/test-runner/node/define-node.mjs.map +1 -0
- package/dist/es/test-runner/node/index.mjs +2 -0
- package/dist/es/test-runner/node/types.mjs +0 -0
- package/dist/es/test-runner/parser/document-format.mjs +21 -0
- package/dist/es/test-runner/parser/document-format.mjs.map +1 -0
- package/dist/es/test-runner/parser/normalize.mjs +87 -0
- package/dist/es/test-runner/parser/normalize.mjs.map +1 -0
- package/dist/es/test-runner/parser/types.mjs +0 -0
- package/dist/es/test-runner/project.mjs +0 -0
- package/dist/es/test-runner/reporting/agent-report.mjs +23 -0
- package/dist/es/test-runner/reporting/agent-report.mjs.map +1 -0
- package/dist/es/test-runner/reporting/execution-record.mjs +73 -0
- package/dist/es/test-runner/reporting/execution-record.mjs.map +1 -0
- package/dist/es/test-runner/reporting/merge-report.mjs +231 -0
- package/dist/es/test-runner/reporting/merge-report.mjs.map +1 -0
- package/dist/es/test-runner/reporting/sanitize.mjs +162 -0
- package/dist/es/test-runner/reporting/sanitize.mjs.map +1 -0
- package/dist/es/test-runner/reporting/test-run-report.mjs +327 -0
- package/dist/es/test-runner/reporting/test-run-report.mjs.map +1 -0
- package/dist/es/test-runner/reporting/types.mjs +0 -0
- package/dist/es/utils.mjs +1 -1
- package/dist/es/yaml/execution-context.node.mjs +6 -0
- package/dist/es/yaml/execution-context.node.mjs.map +1 -0
- package/dist/es/yaml/execution-context.stub.mjs +8 -0
- package/dist/es/yaml/execution-context.stub.mjs.map +1 -0
- package/dist/es/yaml/execution-session.mjs +90 -0
- package/dist/es/yaml/execution-session.mjs.map +1 -0
- package/dist/es/yaml/index.mjs +2 -1
- package/dist/es/yaml/legacy-yaml-execution-record.mjs +47 -0
- package/dist/es/yaml/legacy-yaml-execution-record.mjs.map +1 -0
- package/dist/es/yaml/legacy-yaml-report.mjs +52 -0
- package/dist/es/yaml/legacy-yaml-report.mjs.map +1 -0
- package/dist/es/yaml/legacy-yaml-runtime.mjs +119 -0
- package/dist/es/yaml/legacy-yaml-runtime.mjs.map +1 -0
- package/dist/es/yaml/player-state.mjs +15 -0
- package/dist/es/yaml/player-state.mjs.map +1 -0
- package/dist/es/yaml/player.mjs +214 -348
- package/dist/es/yaml/player.mjs.map +1 -1
- package/dist/es/yaml/report-policy.mjs +7 -0
- package/dist/es/yaml/report-policy.mjs.map +1 -0
- package/dist/es/yaml/test-runner-compat.mjs +301 -0
- package/dist/es/yaml/test-runner-compat.mjs.map +1 -0
- package/dist/es/yaml/test-runner-nodes.mjs +147 -0
- package/dist/es/yaml/test-runner-nodes.mjs.map +1 -0
- package/dist/es/yaml/utils.mjs +12 -1
- package/dist/es/yaml/utils.mjs.map +1 -1
- package/dist/es/yaml-runtime.mjs +7 -0
- package/dist/es/yaml.mjs.map +1 -1
- package/dist/lib/agent/agent.js +103 -6
- package/dist/lib/agent/agent.js.map +1 -1
- package/dist/lib/agent/index.js +37 -3
- package/dist/lib/agent/tasks.js +2 -2
- package/dist/lib/agent/tasks.js.map +1 -1
- package/dist/lib/agent/test-runner-nodes.js +329 -45
- package/dist/lib/agent/test-runner-nodes.js.map +1 -1
- package/dist/lib/agent/utils.js +1 -1
- package/dist/lib/device/index.js +15 -2
- package/dist/lib/device/index.js.map +1 -1
- package/dist/lib/dump/html-utils.js +43 -4
- package/dist/lib/dump/html-utils.js.map +1 -1
- package/dist/lib/dump/screenshot-store.js +8 -1
- package/dist/lib/dump/screenshot-store.js.map +1 -1
- package/dist/lib/report-cli.js +8 -3
- package/dist/lib/report-cli.js.map +1 -1
- package/dist/lib/report-generator.js +114 -1
- package/dist/lib/report-generator.js.map +1 -1
- package/dist/lib/report-html-template.js +1 -1
- package/dist/lib/report.js +187 -38
- package/dist/lib/report.js.map +1 -1
- package/dist/lib/test-run-report.js.map +1 -1
- package/dist/lib/test-runner/engine/case-runner.js +89 -0
- package/dist/lib/test-runner/engine/case-runner.js.map +1 -0
- package/dist/lib/test-runner/engine/document-runtime.js +307 -0
- package/dist/lib/test-runner/engine/document-runtime.js.map +1 -0
- package/dist/lib/test-runner/engine/execute-step.js +211 -0
- package/dist/lib/test-runner/engine/execute-step.js.map +1 -0
- package/dist/lib/test-runner/engine/execution-failure.js +79 -0
- package/dist/lib/test-runner/engine/execution-failure.js.map +1 -0
- package/dist/lib/test-runner/engine/index.js +137 -0
- package/dist/lib/test-runner/engine/index.js.map +1 -0
- package/dist/lib/test-runner/engine/project-runtime.js +176 -0
- package/dist/lib/test-runner/engine/project-runtime.js.map +1 -0
- package/dist/lib/test-runner/engine/registry.js +95 -0
- package/dist/lib/test-runner/engine/registry.js.map +1 -0
- package/dist/lib/test-runner/engine/resource-operations.js +272 -0
- package/dist/lib/test-runner/engine/resource-operations.js.map +1 -0
- package/dist/lib/test-runner/engine/run-collected-case.js +227 -0
- package/dist/lib/test-runner/engine/run-collected-case.js.map +1 -0
- package/dist/lib/test-runner/engine/run-workflow-document.js +189 -0
- package/dist/lib/test-runner/engine/run-workflow-document.js.map +1 -0
- package/dist/lib/test-runner/engine/scheduler.js +64 -0
- package/dist/lib/test-runner/engine/scheduler.js.map +1 -0
- package/dist/lib/test-runner/engine/scope-teardown.js +50 -0
- package/dist/lib/test-runner/engine/scope-teardown.js.map +1 -0
- package/dist/lib/test-runner/engine/types.js +20 -0
- package/dist/lib/test-runner/engine/types.js.map +1 -0
- package/dist/lib/test-runner/errors.js +283 -0
- package/dist/lib/test-runner/errors.js.map +1 -0
- package/dist/lib/test-runner/execution-record.js +123 -0
- package/dist/lib/test-runner/execution-record.js.map +1 -0
- package/dist/lib/test-runner/index.js +137 -0
- package/dist/lib/test-runner/index.js.map +1 -0
- package/dist/lib/test-runner/node/define-node.js +78 -0
- package/dist/lib/test-runner/node/define-node.js.map +1 -0
- package/dist/lib/test-runner/node/index.js +67 -0
- package/dist/lib/test-runner/node/index.js.map +1 -0
- package/dist/lib/test-runner/node/types.js +20 -0
- package/dist/lib/test-runner/node/types.js.map +1 -0
- package/dist/lib/test-runner/parser/document-format.js +58 -0
- package/dist/lib/test-runner/parser/document-format.js.map +1 -0
- package/dist/lib/test-runner/parser/normalize.js +124 -0
- package/dist/lib/test-runner/parser/normalize.js.map +1 -0
- package/dist/lib/test-runner/parser/types.js +20 -0
- package/dist/lib/test-runner/parser/types.js.map +1 -0
- package/dist/lib/test-runner/project.js +20 -0
- package/dist/lib/test-runner/project.js.map +1 -0
- package/dist/lib/test-runner/reporting/agent-report.js +57 -0
- package/dist/lib/test-runner/reporting/agent-report.js.map +1 -0
- package/dist/lib/test-runner/reporting/execution-record.js +107 -0
- package/dist/lib/test-runner/reporting/execution-record.js.map +1 -0
- package/dist/lib/test-runner/reporting/merge-report.js +265 -0
- package/dist/lib/test-runner/reporting/merge-report.js.map +1 -0
- package/dist/lib/test-runner/reporting/sanitize.js +202 -0
- package/dist/lib/test-runner/reporting/sanitize.js.map +1 -0
- package/dist/lib/test-runner/reporting/test-run-report.js +364 -0
- package/dist/lib/test-runner/reporting/test-run-report.js.map +1 -0
- package/dist/lib/test-runner/reporting/types.js +20 -0
- package/dist/lib/test-runner/reporting/types.js.map +1 -0
- package/dist/lib/utils.js +1 -1
- package/dist/lib/yaml/execution-context.node.js +43 -0
- package/dist/lib/yaml/execution-context.node.js.map +1 -0
- package/dist/lib/yaml/execution-context.stub.js +45 -0
- package/dist/lib/yaml/execution-context.stub.js.map +1 -0
- package/dist/lib/yaml/execution-session.js +136 -0
- package/dist/lib/yaml/execution-session.js.map +1 -0
- package/dist/lib/yaml/index.js +49 -7
- package/dist/lib/yaml/legacy-yaml-execution-record.js +81 -0
- package/dist/lib/yaml/legacy-yaml-execution-record.js.map +1 -0
- package/dist/lib/yaml/legacy-yaml-report.js +86 -0
- package/dist/lib/yaml/legacy-yaml-report.js.map +1 -0
- package/dist/lib/yaml/legacy-yaml-runtime.js +156 -0
- package/dist/lib/yaml/legacy-yaml-runtime.js.map +1 -0
- package/dist/lib/yaml/player-state.js +52 -0
- package/dist/lib/yaml/player-state.js.map +1 -0
- package/dist/lib/yaml/player.js +213 -347
- package/dist/lib/yaml/player.js.map +1 -1
- package/dist/lib/yaml/report-policy.js +41 -0
- package/dist/lib/yaml/report-policy.js.map +1 -0
- package/dist/lib/yaml/test-runner-compat.js +344 -0
- package/dist/lib/yaml/test-runner-compat.js.map +1 -0
- package/dist/lib/yaml/test-runner-nodes.js +184 -0
- package/dist/lib/yaml/test-runner-nodes.js.map +1 -0
- package/dist/lib/yaml/utils.js +18 -1
- package/dist/lib/yaml/utils.js.map +1 -1
- package/dist/lib/yaml-runtime.js +67 -0
- package/dist/lib/yaml-runtime.js.map +1 -0
- package/dist/lib/yaml.js.map +1 -1
- package/dist/types/agent/agent.d.ts +14 -1
- package/dist/types/agent/agent.d.ts.map +1 -1
- package/dist/types/agent/index.d.ts +4 -3
- package/dist/types/agent/index.d.ts.map +1 -1
- package/dist/types/agent/tasks.d.ts +1 -1
- package/dist/types/agent/tasks.d.ts.map +1 -1
- package/dist/types/agent/test-runner-nodes.d.ts +226 -0
- package/dist/types/agent/test-runner-nodes.d.ts.map +1 -1
- package/dist/types/device/index.d.ts +1 -1
- package/dist/types/device/index.d.ts.map +1 -1
- package/dist/types/dump/html-utils.d.ts +4 -0
- package/dist/types/dump/html-utils.d.ts.map +1 -1
- package/dist/types/dump/screenshot-store.d.ts +2 -1
- package/dist/types/dump/screenshot-store.d.ts.map +1 -1
- package/dist/types/report-cli.d.ts.map +1 -1
- package/dist/types/report-generator.d.ts +10 -0
- package/dist/types/report-generator.d.ts.map +1 -1
- package/dist/types/report.d.ts +3 -1
- package/dist/types/report.d.ts.map +1 -1
- package/dist/types/test-run-report.d.ts +18 -2
- package/dist/types/test-run-report.d.ts.map +1 -1
- package/dist/types/test-runner/engine/case-runner.d.ts +13 -0
- package/dist/types/test-runner/engine/case-runner.d.ts.map +1 -0
- package/dist/types/test-runner/engine/document-runtime.d.ts +4 -0
- package/dist/types/test-runner/engine/document-runtime.d.ts.map +1 -0
- package/dist/types/test-runner/engine/execute-step.d.ts +17 -0
- package/dist/types/test-runner/engine/execute-step.d.ts.map +1 -0
- package/dist/types/test-runner/engine/execution-failure.d.ts +13 -0
- package/dist/types/test-runner/engine/execution-failure.d.ts.map +1 -0
- package/dist/types/test-runner/engine/index.d.ts +13 -0
- package/dist/types/test-runner/engine/index.d.ts.map +1 -0
- package/dist/types/test-runner/engine/project-runtime.d.ts +3 -0
- package/dist/types/test-runner/engine/project-runtime.d.ts.map +1 -0
- package/dist/types/test-runner/engine/registry.d.ts +12 -0
- package/dist/types/test-runner/engine/registry.d.ts.map +1 -0
- package/dist/types/test-runner/engine/resource-operations.d.ts +32 -0
- package/dist/types/test-runner/engine/resource-operations.d.ts.map +1 -0
- package/dist/types/test-runner/engine/run-collected-case.d.ts +4 -0
- package/dist/types/test-runner/engine/run-collected-case.d.ts.map +1 -0
- package/dist/types/test-runner/engine/run-workflow-document.d.ts +4 -0
- package/dist/types/test-runner/engine/run-workflow-document.d.ts.map +1 -0
- package/dist/types/test-runner/engine/scheduler.d.ts +12 -0
- package/dist/types/test-runner/engine/scheduler.d.ts.map +1 -0
- package/dist/types/test-runner/engine/scope-teardown.d.ts +3 -0
- package/dist/types/test-runner/engine/scope-teardown.d.ts.map +1 -0
- package/dist/types/test-runner/engine/types.d.ts +226 -0
- package/dist/types/test-runner/engine/types.d.ts.map +1 -0
- package/dist/types/test-runner/errors.d.ts +79 -0
- package/dist/types/test-runner/errors.d.ts.map +1 -0
- package/dist/types/test-runner/execution-record.d.ts +43 -0
- package/dist/types/test-runner/execution-record.d.ts.map +1 -0
- package/dist/types/test-runner/index.d.ts +20 -0
- package/dist/types/test-runner/index.d.ts.map +1 -0
- package/dist/types/test-runner/node/define-node.d.ts +4 -0
- package/dist/types/test-runner/node/define-node.d.ts.map +1 -0
- package/dist/types/test-runner/node/index.d.ts +3 -0
- package/dist/types/test-runner/node/index.d.ts.map +1 -0
- package/dist/types/test-runner/node/types.d.ts +66 -0
- package/dist/types/test-runner/node/types.d.ts.map +1 -0
- package/dist/types/test-runner/parser/document-format.d.ts +8 -0
- package/dist/types/test-runner/parser/document-format.d.ts.map +1 -0
- package/dist/types/test-runner/parser/normalize.d.ts +9 -0
- package/dist/types/test-runner/parser/normalize.d.ts.map +1 -0
- package/dist/types/test-runner/parser/types.d.ts +69 -0
- package/dist/types/test-runner/parser/types.d.ts.map +1 -0
- package/dist/types/test-runner/project.d.ts +75 -0
- package/dist/types/test-runner/project.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/agent-report.d.ts +9 -0
- package/dist/types/test-runner/reporting/agent-report.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/execution-record.d.ts +9 -0
- package/dist/types/test-runner/reporting/execution-record.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/merge-report.d.ts +15 -0
- package/dist/types/test-runner/reporting/merge-report.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/sanitize.d.ts +6 -0
- package/dist/types/test-runner/reporting/sanitize.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/test-run-report.d.ts +5 -0
- package/dist/types/test-runner/reporting/test-run-report.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/types.d.ts +34 -0
- package/dist/types/test-runner/reporting/types.d.ts.map +1 -0
- package/dist/types/yaml/execution-context.node.d.ts +4 -0
- package/dist/types/yaml/execution-context.node.d.ts.map +1 -0
- package/dist/types/yaml/execution-context.stub.d.ts +6 -0
- package/dist/types/yaml/execution-context.stub.d.ts.map +1 -0
- package/dist/types/yaml/execution-session.d.ts +17 -0
- package/dist/types/yaml/execution-session.d.ts.map +1 -0
- package/dist/types/yaml/index.d.ts +1 -1
- package/dist/types/yaml/index.d.ts.map +1 -1
- package/dist/types/yaml/legacy-yaml-execution-record.d.ts +24 -0
- package/dist/types/yaml/legacy-yaml-execution-record.d.ts.map +1 -0
- package/dist/types/yaml/legacy-yaml-report.d.ts +19 -0
- package/dist/types/yaml/legacy-yaml-report.d.ts.map +1 -0
- package/dist/types/yaml/legacy-yaml-runtime.d.ts +23 -0
- package/dist/types/yaml/legacy-yaml-runtime.d.ts.map +1 -0
- package/dist/types/yaml/player-state.d.ts +11 -0
- package/dist/types/yaml/player-state.d.ts.map +1 -0
- package/dist/types/yaml/player.d.ts +11 -3
- package/dist/types/yaml/player.d.ts.map +1 -1
- package/dist/types/yaml/report-policy.d.ts +4 -0
- package/dist/types/yaml/report-policy.d.ts.map +1 -0
- package/dist/types/yaml/test-runner-compat.d.ts +17 -0
- package/dist/types/yaml/test-runner-compat.d.ts.map +1 -0
- package/dist/types/yaml/test-runner-nodes.d.ts +6 -0
- package/dist/types/yaml/test-runner-nodes.d.ts.map +1 -0
- package/dist/types/yaml/utils.d.ts +9 -0
- package/dist/types/yaml/utils.d.ts.map +1 -1
- package/dist/types/yaml-runtime.d.ts +13 -0
- package/dist/types/yaml-runtime.d.ts.map +1 -0
- package/dist/types/yaml.d.ts +25 -7
- package/dist/types/yaml.d.ts.map +1 -1
- package/package.json +28 -2
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { assert } from "@midscene/shared/utils";
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
|
+
import { commonAgentTestRunnerNodeDefinitions } from "../agent/test-runner-nodes.mjs";
|
|
4
|
+
import { compileLegacyFlowItem } from "./test-runner-compat.mjs";
|
|
5
|
+
const legacyFinalizeNodeDefinition = {
|
|
6
|
+
name: 'Finalize',
|
|
7
|
+
inputSchema: z.strictObject({}),
|
|
8
|
+
execute: ()=>void 0
|
|
9
|
+
};
|
|
10
|
+
const legacyRunAdbShellNodeDefinition = {
|
|
11
|
+
name: 'runAdbShell',
|
|
12
|
+
inputSchema: z.strictObject({
|
|
13
|
+
command: z.string(),
|
|
14
|
+
timeout: z.number()
|
|
15
|
+
}),
|
|
16
|
+
async execute (agent, input) {
|
|
17
|
+
const androidAgent = agent;
|
|
18
|
+
const command = input.command;
|
|
19
|
+
const timeout = input.timeout;
|
|
20
|
+
const value = androidAgent.runAdbShell ? await androidAgent.runAdbShell(command, {
|
|
21
|
+
timeout
|
|
22
|
+
}) : await androidAgent.callActionInActionSpace('RunAdbShell', {
|
|
23
|
+
command,
|
|
24
|
+
timeout
|
|
25
|
+
});
|
|
26
|
+
return void 0 === value ? void 0 : {
|
|
27
|
+
data: value
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const legacyActionNodeDefinition = {
|
|
32
|
+
name: 'legacyAction',
|
|
33
|
+
inputSchema: z.strictObject({
|
|
34
|
+
flow: z.record(z.string(), z.unknown())
|
|
35
|
+
}),
|
|
36
|
+
async execute (agent, input, context) {
|
|
37
|
+
context.signal.throwIfAborted();
|
|
38
|
+
const actionSpace = await agent.getActionSpace();
|
|
39
|
+
context.signal.throwIfAborted();
|
|
40
|
+
const step = compileLegacyFlowItem(input.flow, actionSpace);
|
|
41
|
+
assert('legacyAction' !== step.node, `unknown flowItem in yaml: ${JSON.stringify(input.flow)}`);
|
|
42
|
+
const definition = legacyAgentTestRunnerNodeDefinitions.find((node)=>node.name === step.node);
|
|
43
|
+
assert(definition, `Unknown Agent Node: ${step.node}`);
|
|
44
|
+
const parsed = await definition.inputSchema.parseAsync(step.input);
|
|
45
|
+
context.signal.throwIfAborted();
|
|
46
|
+
return definition.execute(agent, parsed, context);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const legacyValidationErrorNodeDefinition = {
|
|
50
|
+
name: 'legacyValidationError',
|
|
51
|
+
inputSchema: z.strictObject({
|
|
52
|
+
message: z.string()
|
|
53
|
+
}),
|
|
54
|
+
execute (_agent, input) {
|
|
55
|
+
throw new Error(input.message);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const legacyPromptInputSchema = z.strictObject({
|
|
59
|
+
prompt: z.unknown(),
|
|
60
|
+
options: z.record(z.string(), z.unknown()).optional()
|
|
61
|
+
});
|
|
62
|
+
const legacyInputSchemas = new Map([
|
|
63
|
+
...[
|
|
64
|
+
'aiAct',
|
|
65
|
+
'aiTap',
|
|
66
|
+
'aiLocate',
|
|
67
|
+
'aiQuery',
|
|
68
|
+
'aiNumber',
|
|
69
|
+
'aiString',
|
|
70
|
+
'aiBoolean',
|
|
71
|
+
'aiAsk',
|
|
72
|
+
'aiWaitFor',
|
|
73
|
+
'aiScroll'
|
|
74
|
+
].map((name)=>[
|
|
75
|
+
name,
|
|
76
|
+
legacyPromptInputSchema
|
|
77
|
+
]),
|
|
78
|
+
[
|
|
79
|
+
'aiAssert',
|
|
80
|
+
legacyPromptInputSchema.extend({
|
|
81
|
+
message: z.unknown()
|
|
82
|
+
})
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
"javascript",
|
|
86
|
+
z.strictObject({
|
|
87
|
+
script: z.unknown()
|
|
88
|
+
})
|
|
89
|
+
],
|
|
90
|
+
[
|
|
91
|
+
'runGherkinScenario',
|
|
92
|
+
z.strictObject({
|
|
93
|
+
scenario: z.unknown(),
|
|
94
|
+
options: z.record(z.string(), z.unknown()).optional()
|
|
95
|
+
})
|
|
96
|
+
],
|
|
97
|
+
[
|
|
98
|
+
'sleep',
|
|
99
|
+
z.strictObject({
|
|
100
|
+
ms: z.number().positive()
|
|
101
|
+
})
|
|
102
|
+
],
|
|
103
|
+
[
|
|
104
|
+
'action',
|
|
105
|
+
z.strictObject({
|
|
106
|
+
name: z.string(),
|
|
107
|
+
params: z.unknown()
|
|
108
|
+
})
|
|
109
|
+
],
|
|
110
|
+
[
|
|
111
|
+
'recordToReport',
|
|
112
|
+
z.strictObject({
|
|
113
|
+
title: z.unknown(),
|
|
114
|
+
options: z.record(z.string(), z.unknown()).optional()
|
|
115
|
+
})
|
|
116
|
+
]
|
|
117
|
+
]);
|
|
118
|
+
const sharedDefinitions = new Map(commonAgentTestRunnerNodeDefinitions.map((definition)=>[
|
|
119
|
+
definition.name,
|
|
120
|
+
definition
|
|
121
|
+
]));
|
|
122
|
+
const legacyAgentTestRunnerNodeDefinitions = [
|
|
123
|
+
...Array.from(legacyInputSchemas, ([name, inputSchema])=>{
|
|
124
|
+
const definition = sharedDefinitions.get(name);
|
|
125
|
+
assert(definition, `Missing shared Agent Node for legacy YAML: ${name}`);
|
|
126
|
+
return {
|
|
127
|
+
...definition,
|
|
128
|
+
inputSchema
|
|
129
|
+
};
|
|
130
|
+
}),
|
|
131
|
+
legacyFinalizeNodeDefinition,
|
|
132
|
+
legacyRunAdbShellNodeDefinition,
|
|
133
|
+
legacyActionNodeDefinition,
|
|
134
|
+
legacyValidationErrorNodeDefinition
|
|
135
|
+
];
|
|
136
|
+
const insightNodes = new Set([
|
|
137
|
+
'aiBoolean',
|
|
138
|
+
'aiNumber',
|
|
139
|
+
'aiString',
|
|
140
|
+
'aiAsk'
|
|
141
|
+
]);
|
|
142
|
+
function getLegacyYamlResultData(node, output) {
|
|
143
|
+
return insightNodes.has(node) ? output.data.value : output.data;
|
|
144
|
+
}
|
|
145
|
+
export { getLegacyYamlResultData, legacyAgentTestRunnerNodeDefinitions };
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=test-runner-nodes.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yaml/test-runner-nodes.mjs","sources":["../../../src/yaml/test-runner-nodes.ts"],"sourcesContent":["import { assert } from '@midscene/shared/utils';\nimport { z } from 'zod/v4';\nimport {\n type AgentTestRunnerNodeDefinition,\n commonAgentTestRunnerNodeDefinitions,\n} from '../agent/test-runner-nodes';\nimport type { NodeResult } from '../test-runner/node/types';\nimport type { DeviceAction, MidsceneYamlFlowItem } from '../types';\nimport { compileLegacyFlowItem } from './test-runner-compat';\n\n/** Planning-only marker accepted by the old YAML grammar, not a native Test Node. */\nconst legacyFinalizeNodeDefinition: AgentTestRunnerNodeDefinition = {\n name: 'Finalize',\n inputSchema: z.strictObject({}),\n execute: () => undefined,\n};\n\nconst legacyRunAdbShellNodeDefinition: AgentTestRunnerNodeDefinition = {\n name: 'runAdbShell',\n inputSchema: z.strictObject({ command: z.string(), timeout: z.number() }),\n async execute(agent, input) {\n const androidAgent = agent as {\n runAdbShell?: (\n command: string,\n options: { timeout: number },\n ) => Promise<unknown>;\n callActionInActionSpace(\n name: string,\n params: Record<string, unknown>,\n ): Promise<unknown>;\n };\n const command = input.command as string;\n const timeout = input.timeout as number;\n const value = androidAgent.runAdbShell\n ? await androidAgent.runAdbShell(command, { timeout })\n : await androidAgent.callActionInActionSpace('RunAdbShell', {\n command,\n timeout,\n });\n return value === undefined ? undefined : { data: value };\n },\n};\n\n/** Only YAML hosts resolve shorthand; the shared Agent receives canonical params. */\nconst legacyActionNodeDefinition: AgentTestRunnerNodeDefinition = {\n name: 'legacyAction',\n inputSchema: z.strictObject({ flow: z.record(z.string(), z.unknown()) }),\n async execute(agent, input, context) {\n context.signal.throwIfAborted();\n const actionSpace = await (\n agent as {\n getActionSpace(): Promise<DeviceAction[]>;\n }\n ).getActionSpace();\n context.signal.throwIfAborted();\n const step = compileLegacyFlowItem(\n input.flow as MidsceneYamlFlowItem,\n actionSpace,\n );\n assert(\n step.node !== 'legacyAction',\n `unknown flowItem in yaml: ${JSON.stringify(input.flow)}`,\n );\n const definition = legacyAgentTestRunnerNodeDefinitions.find(\n (node) => node.name === step.node,\n );\n assert(definition, `Unknown Agent Node: ${step.node}`);\n const parsed = await definition.inputSchema.parseAsync(step.input);\n context.signal.throwIfAborted();\n return definition.execute(agent, parsed, context);\n },\n};\n\n/** Preserve the old task failure phase without adding native parser controls. */\nconst legacyValidationErrorNodeDefinition: AgentTestRunnerNodeDefinition = {\n name: 'legacyValidationError',\n inputSchema: z.strictObject({ message: z.string() }),\n execute(_agent, input) {\n throw new Error(input.message as string);\n },\n};\n\n// The old player checked YAML grammar, then passed options through to Agent.\n// Validate only the compiled envelope here: native field whitelists, positive\n// wait durations and nonempty image arrays must not narrow the legacy grammar.\n// compileLegacyFlowItem preserves the old checks at their task execution phase;\n// Agent/ActionSpace remain responsible for validating the business parameters.\nconst legacyPromptInputSchema = z.strictObject({\n prompt: z.unknown(),\n options: z.record(z.string(), z.unknown()).optional(),\n});\nconst legacyInputSchemas = new Map<string, z.ZodObject>([\n ...[\n 'aiAct',\n 'aiTap',\n 'aiLocate',\n 'aiQuery',\n 'aiNumber',\n 'aiString',\n 'aiBoolean',\n 'aiAsk',\n 'aiWaitFor',\n 'aiScroll',\n ].map((name): [string, z.ZodObject] => [name, legacyPromptInputSchema]),\n ['aiAssert', legacyPromptInputSchema.extend({ message: z.unknown() })],\n ['javascript', z.strictObject({ script: z.unknown() })],\n [\n 'runGherkinScenario',\n z.strictObject({\n scenario: z.unknown(),\n options: z.record(z.string(), z.unknown()).optional(),\n }),\n ],\n ['sleep', z.strictObject({ ms: z.number().positive() })],\n ['action', z.strictObject({ name: z.string(), params: z.unknown() })],\n [\n 'recordToReport',\n z.strictObject({\n title: z.unknown(),\n options: z.record(z.string(), z.unknown()).optional(),\n }),\n ],\n]);\nconst sharedDefinitions = new Map(\n commonAgentTestRunnerNodeDefinitions.map((definition) => [\n definition.name,\n definition,\n ]),\n);\nexport const legacyAgentTestRunnerNodeDefinitions: readonly AgentTestRunnerNodeDefinition[] =\n [\n ...Array.from(legacyInputSchemas, ([name, inputSchema]) => {\n const definition = sharedDefinitions.get(name);\n assert(definition, `Missing shared Agent Node for legacy YAML: ${name}`);\n return { ...definition, inputSchema };\n }),\n legacyFinalizeNodeDefinition,\n legacyRunAdbShellNodeDefinition,\n legacyActionNodeDefinition,\n legacyValidationErrorNodeDefinition,\n ];\n\nconst insightNodes = new Set(['aiBoolean', 'aiNumber', 'aiString', 'aiAsk']);\n\n/** Keep Test's { value } contract; only the legacy output view unwraps insights. */\nexport function getLegacyYamlResultData(\n node: string,\n output: NodeResult,\n): unknown {\n return insightNodes.has(node)\n ? (output.data as { value: unknown }).value\n : output.data;\n}\n"],"names":["legacyFinalizeNodeDefinition","z","undefined","legacyRunAdbShellNodeDefinition","agent","input","androidAgent","command","timeout","value","legacyActionNodeDefinition","context","actionSpace","step","compileLegacyFlowItem","assert","JSON","definition","legacyAgentTestRunnerNodeDefinitions","node","parsed","legacyValidationErrorNodeDefinition","_agent","Error","legacyPromptInputSchema","legacyInputSchemas","Map","name","sharedDefinitions","commonAgentTestRunnerNodeDefinitions","Array","inputSchema","insightNodes","Set","getLegacyYamlResultData","output"],"mappings":"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"}
|
package/dist/es/yaml/utils.mjs
CHANGED
|
@@ -38,6 +38,13 @@ function resolveWebTarget(config) {
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
+
function resolveYamlOutputConfig(script) {
|
|
42
|
+
const target = resolveWebTarget(script)?.target ?? script.android ?? script.ios ?? script.harmony ?? script.computer;
|
|
43
|
+
return {
|
|
44
|
+
output: target?.output ?? script.config?.output,
|
|
45
|
+
unstableLogContent: target?.unstableLogContent ?? script.config?.unstableLogContent
|
|
46
|
+
};
|
|
47
|
+
}
|
|
41
48
|
function interpolateEnvVarRefs(value, keepUnresolvedRefs = false) {
|
|
42
49
|
let result = '';
|
|
43
50
|
let lastIndex = 0;
|
|
@@ -102,6 +109,9 @@ function interpolateYamlScriptEnvVars(content) {
|
|
|
102
109
|
}).join('\n');
|
|
103
110
|
}
|
|
104
111
|
function parseYamlScript(content, filePath) {
|
|
112
|
+
return parseLegacyYamlScript(content, filePath);
|
|
113
|
+
}
|
|
114
|
+
function parseLegacyYamlScript(content, filePath, onConfig) {
|
|
105
115
|
let processedContent = content;
|
|
106
116
|
if (-1 !== content.indexOf('android') && content.match(/deviceId:\s*(\d+)/)) {
|
|
107
117
|
let matchedDeviceId;
|
|
@@ -115,6 +125,7 @@ function parseYamlScript(content, filePath) {
|
|
|
115
125
|
const obj = js_yaml.load(interpolatedContent, {
|
|
116
126
|
schema: js_yaml.JSON_SCHEMA
|
|
117
127
|
});
|
|
128
|
+
if (obj && 'object' == typeof obj && !Array.isArray(obj)) onConfig?.(obj);
|
|
118
129
|
const pathTip = filePath ? `, failed to load ${filePath}` : '';
|
|
119
130
|
resolveWebTarget(obj);
|
|
120
131
|
assert(obj.tasks, `property "tasks" is required in yaml script ${pathTip}`);
|
|
@@ -178,6 +189,6 @@ function buildDetailedLocateParamAndRestParams(locatePrompt, opt, excludeKeys =
|
|
|
178
189
|
restParams
|
|
179
190
|
};
|
|
180
191
|
}
|
|
181
|
-
export { buildDetailedLocateParam, buildDetailedLocateParamAndRestParams, interpolateEnvVars, parseYamlScript, resolveWebTarget };
|
|
192
|
+
export { buildDetailedLocateParam, buildDetailedLocateParamAndRestParams, interpolateEnvVars, parseLegacyYamlScript, parseYamlScript, resolveWebTarget, resolveYamlOutputConfig };
|
|
182
193
|
|
|
183
194
|
//# sourceMappingURL=utils.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml/utils.mjs","sources":["../../../src/yaml/utils.ts"],"sourcesContent":["import type { TMultimodalPrompt, TUserPrompt } from '@/common';\nimport type {\n DetailedLocateParam,\n LocateOption,\n MidsceneYamlScript,\n MidsceneYamlScriptWebEnv,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\nimport { buildLocatePromptWithContext } from '../agent/prompt-context';\n\nconst debugUtils = getDebug('yaml:utils');\n\nconst topLevelTasksPattern = /^tasks\\s*:/;\nconst topLevelYamlKeyPattern = /^[^\\s#][^:]*:/;\n\nexport type WebTargetSource = 'page' | 'browser' | 'web' | 'target';\n\nexport type ResolvedWebTarget = {\n source: WebTargetSource;\n target: Partial<MidsceneYamlScriptWebEnv> & { mode: 'page' | 'browser' };\n mode: 'page' | 'browser';\n};\n\nexport type WebTargetConfig = Partial<\n Record<WebTargetSource, Partial<MidsceneYamlScriptWebEnv>>\n>;\n\nconst webTargetSources: WebTargetSource[] = [\n 'page',\n 'browser',\n 'web',\n 'target',\n];\n\nexport function resolveWebTarget(\n config: WebTargetConfig,\n): ResolvedWebTarget | undefined {\n const entries = webTargetSources\n .map((source) => [source, config[source]] as const)\n .filter(\n (\n entry,\n ): entry is readonly [\n WebTargetSource,\n Partial<MidsceneYamlScriptWebEnv>,\n ] => typeof entry[1] !== 'undefined',\n );\n\n if (entries.length === 0) {\n return undefined;\n }\n\n if (entries.length > 1) {\n const specifiedTargets = entries.map(([source]) => source);\n throw new Error(\n `[midscene] Only one web target can be specified, but found multiple: ${specifiedTargets.join(\n ', ',\n )}. Please specify only one of: page, browser, web, or target.`,\n );\n }\n\n const [source, target] = entries[0];\n const explicitMode = target.mode;\n if (\n typeof explicitMode !== 'undefined' &&\n explicitMode !== 'page' &&\n explicitMode !== 'browser'\n ) {\n throw new Error(\n `[midscene] web target mode must be either \"page\" or \"browser\", but got \"${explicitMode}\".`,\n );\n }\n\n if (source === 'page' && explicitMode === 'browser') {\n throw new Error(\n '[midscene] page target cannot use mode: browser. Use browser: instead.',\n );\n }\n\n if (source === 'browser' && explicitMode === 'page') {\n throw new Error(\n '[midscene] browser target cannot use mode: page. Use page: instead.',\n );\n }\n\n const mode =\n source === 'page'\n ? 'page'\n : source === 'browser'\n ? 'browser'\n : (explicitMode ?? 'page');\n\n if (mode === 'page' && target.autoFollowNewPage) {\n throw new Error(\n '[midscene] autoFollowNewPage requires browser mode. Use browser: or web.mode: browser.',\n );\n }\n\n if (\n mode === 'browser' &&\n typeof target.forceSameTabNavigation !== 'undefined'\n ) {\n throw new Error(\n '[midscene] forceSameTabNavigation cannot be used in browser mode. Use page: or web.mode: page when same-tab navigation is required.',\n );\n }\n\n return {\n source,\n mode,\n target: {\n ...target,\n mode,\n },\n };\n}\n\nfunction interpolateEnvVarRefs(\n value: string,\n keepUnresolvedRefs = false,\n): string {\n let result = '';\n let lastIndex = 0;\n let searchFrom = 0;\n\n while (searchFrom < value.length) {\n const start = value.indexOf('${', searchFrom);\n if (start === -1) {\n break;\n }\n\n const end = value.indexOf('}', start + 2);\n if (end === -1) {\n break;\n }\n\n const rawName = value.slice(start + 2, end);\n if (!rawName) {\n searchFrom = end + 1;\n continue;\n }\n\n result += value.slice(lastIndex, start);\n const envVar = rawName.trim();\n const envValue = process.env[envVar];\n if (envValue === undefined) {\n if (keepUnresolvedRefs) {\n result += value.slice(start, end + 1);\n } else {\n throw new Error(`Environment variable \"${envVar}\" is not defined`);\n }\n } else {\n result += envValue;\n }\n lastIndex = end + 1;\n searchFrom = end + 1;\n }\n\n return result + value.slice(lastIndex);\n}\n\nconst multimodalLocateOptionFieldMap: Record<keyof TMultimodalPrompt, true> = {\n images: true,\n convertHttpImage2Base64: true,\n};\n\nconst multimodalLocateOptionKeys = Object.keys(\n multimodalLocateOptionFieldMap,\n) as Array<keyof TMultimodalPrompt>;\n\nfunction extractMultimodalPrompt(\n opt?: LocateOption,\n): Partial<TMultimodalPrompt> | undefined {\n if (typeof opt !== 'object' || opt === null) {\n return undefined;\n }\n\n const entries = multimodalLocateOptionKeys\n .map((key) => [key, opt[key]] as const)\n .filter(([, value]) => value !== undefined);\n\n return entries.length\n ? (Object.fromEntries(entries) as Partial<TMultimodalPrompt>)\n : undefined;\n}\n\nexport function interpolateEnvVars(content: string): string {\n // Process line by line to skip commented lines\n const lines = content.split('\\n');\n const processedLines = lines.map((line) => {\n // Check if the line is a YAML comment (starts with # after optional whitespace)\n const trimmedLine = line.trimStart();\n if (trimmedLine.startsWith('#')) {\n // Skip interpolation for comment lines\n return line;\n }\n\n // Process environment variables for non-comment lines\n return interpolateEnvVarRefs(line);\n });\n\n return processedLines.join('\\n');\n}\n\nfunction interpolateYamlScriptEnvVars(content: string): string {\n let inTopLevelTasksBlock = false;\n\n return content\n .split('\\n')\n .map((line) => {\n const trimmedLine = line.trimStart();\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n return line;\n }\n\n const indentSize = line.length - trimmedLine.length;\n if (indentSize === 0) {\n if (topLevelTasksPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = true;\n return line;\n }\n\n if (topLevelYamlKeyPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = false;\n }\n }\n\n return interpolateEnvVarRefs(line, inTopLevelTasksBlock);\n })\n .join('\\n');\n}\n\nexport function parseYamlScript(\n content: string,\n filePath?: string,\n): MidsceneYamlScript {\n let processedContent = content;\n if (content.indexOf('android') !== -1 && content.match(/deviceId:\\s*(\\d+)/)) {\n let matchedDeviceId;\n processedContent = content.replace(\n /deviceId:\\s*(\\d+)/g,\n (match, deviceId) => {\n matchedDeviceId = deviceId;\n return `deviceId: '${deviceId}'`;\n },\n );\n console.warn(\n `please use string-style deviceId in yaml script, for example: deviceId: \"${matchedDeviceId}\"`,\n );\n }\n const interpolatedContent = interpolateYamlScriptEnvVars(processedContent);\n const obj = yaml.load(interpolatedContent, {\n schema: yaml.JSON_SCHEMA,\n }) as MidsceneYamlScript;\n\n const pathTip = filePath ? `, failed to load ${filePath}` : '';\n resolveWebTarget(obj);\n assert(obj.tasks, `property \"tasks\" is required in yaml script ${pathTip}`);\n assert(\n Array.isArray(obj.tasks),\n `property \"tasks\" must be an array in yaml script, but got ${obj.tasks}`,\n );\n return obj;\n}\n\nexport function buildDetailedLocateParam(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n): DetailedLocateParam | undefined {\n debugUtils('will call buildDetailedLocateParam', locatePrompt, opt);\n // Normalize object-form TUserPrompt: when the object only contains a\n // `prompt` string (no multimodal fields like `images`), unwrap it to\n // avoid double nesting like { prompt: { prompt: '...' } }.\n let normalizedLocatePrompt: TUserPrompt = locatePrompt;\n if (\n typeof locatePrompt === 'object' &&\n locatePrompt !== null &&\n 'prompt' in locatePrompt\n ) {\n const { prompt: innerPrompt, ...rest } = locatePrompt;\n const hasMultimodalFields = Object.keys(rest).length > 0;\n normalizedLocatePrompt = hasMultimodalFields ? locatePrompt : innerPrompt;\n }\n\n let prompt = normalizedLocatePrompt || opt?.prompt || (opt as any)?.locate; // as a shortcut\n let deepLocate = false;\n let cacheable = true;\n let xpath = undefined;\n\n if (typeof opt === 'object' && opt !== null) {\n // Backward-compatible: accept `deepThink` as a deprecated alias for `deepLocate`.\n // All downstream code works on `deepLocate` only; the compatibility resolution\n // is intentionally kept here at the entry point so it does not bleed through\n // the rest of the call stack.\n deepLocate = opt.deepLocate ?? opt.deepThink ?? false;\n cacheable = opt.cacheable ?? true;\n xpath = opt.xpath;\n if (locatePrompt && opt.prompt && locatePrompt !== opt.prompt) {\n console.warn(\n 'conflict prompt for item',\n locatePrompt,\n opt,\n 'maybe you put the prompt in the wrong place',\n );\n }\n prompt = prompt || opt.prompt;\n }\n\n if (!prompt) {\n debugUtils(\n 'no prompt, will return undefined in buildDetailedLocateParam',\n opt,\n );\n return undefined;\n }\n\n const promptDisplay = typeof prompt === 'string' ? prompt : prompt.prompt;\n const context = opt?.context?.trim() || undefined;\n prompt = buildLocatePromptWithContext(prompt, opt?.context);\n\n const multimodalPrompt = extractMultimodalPrompt(opt);\n if (multimodalPrompt) {\n prompt =\n typeof prompt === 'string'\n ? {\n prompt,\n ...multimodalPrompt,\n }\n : {\n ...prompt,\n ...multimodalPrompt,\n };\n }\n\n return {\n prompt,\n ...(context ? { promptDisplay, context } : {}),\n deepLocate,\n cacheable,\n xpath,\n };\n}\n\nexport function buildDetailedLocateParamAndRestParams(\n locatePrompt: TUserPrompt,\n opt: LocateOption | undefined,\n excludeKeys: string[] = [],\n): {\n locateParam: DetailedLocateParam | undefined;\n restParams: Record<string, any>;\n} {\n const multimodalPrompt = extractMultimodalPrompt(opt);\n const locateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n // Extract all keys from opt except the ones already included in locateParam\n const restParams: Record<string, any> = {};\n\n if (typeof opt === 'object' && opt !== null) {\n // Get all keys from opt\n const allKeys = Object.keys(opt);\n\n // `context` has already been merged into the locate prompt.\n const locateParamKeys = Object.keys(locateParam || {});\n const multimodalPromptKeys =\n typeof locateParam?.prompt === 'object' && locateParam?.prompt !== null\n ? Object.keys(multimodalPrompt || {})\n : [];\n\n // Extract all other keys\n for (const key of allKeys) {\n if (\n !locateParamKeys.includes(key) &&\n key !== 'context' &&\n key !== 'deepThink' &&\n !multimodalPromptKeys.includes(key) &&\n !excludeKeys.includes(key) &&\n key !== 'locate'\n ) {\n restParams[key] = opt[key as keyof LocateOption];\n }\n }\n }\n\n return {\n locateParam,\n restParams,\n };\n}\n"],"names":["debugUtils","getDebug","topLevelTasksPattern","topLevelYamlKeyPattern","webTargetSources","resolveWebTarget","config","entries","source","entry","specifiedTargets","Error","target","explicitMode","mode","interpolateEnvVarRefs","value","keepUnresolvedRefs","result","lastIndex","searchFrom","start","end","rawName","envVar","envValue","process","undefined","multimodalLocateOptionFieldMap","multimodalLocateOptionKeys","Object","extractMultimodalPrompt","opt","key","interpolateEnvVars","content","lines","processedLines","line","trimmedLine","interpolateYamlScriptEnvVars","inTopLevelTasksBlock","indentSize","parseYamlScript","filePath","processedContent","matchedDeviceId","match","deviceId","console","interpolatedContent","obj","yaml","pathTip","assert","Array","buildDetailedLocateParam","locatePrompt","normalizedLocatePrompt","innerPrompt","rest","hasMultimodalFields","prompt","deepLocate","cacheable","xpath","promptDisplay","context","buildLocatePromptWithContext","multimodalPrompt","buildDetailedLocateParamAndRestParams","excludeKeys","locateParam","restParams","allKeys","locateParamKeys","multimodalPromptKeys"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"yaml/utils.mjs","sources":["../../../src/yaml/utils.ts"],"sourcesContent":["import type { TMultimodalPrompt, TUserPrompt } from '@/common';\nimport type {\n DetailedLocateParam,\n LocateOption,\n MidsceneYamlScript,\n MidsceneYamlScriptWebEnv,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\nimport { buildLocatePromptWithContext } from '../agent/prompt-context';\n\nconst debugUtils = getDebug('yaml:utils');\n\nconst topLevelTasksPattern = /^tasks\\s*:/;\nconst topLevelYamlKeyPattern = /^[^\\s#][^:]*:/;\n\nexport type WebTargetSource = 'page' | 'browser' | 'web' | 'target';\n\nexport type ResolvedWebTarget = {\n source: WebTargetSource;\n target: Partial<MidsceneYamlScriptWebEnv> & { mode: 'page' | 'browser' };\n mode: 'page' | 'browser';\n};\n\nexport type WebTargetConfig = Partial<\n Record<WebTargetSource, Partial<MidsceneYamlScriptWebEnv>>\n>;\n\nconst webTargetSources: WebTargetSource[] = [\n 'page',\n 'browser',\n 'web',\n 'target',\n];\n\nexport function resolveWebTarget(\n config: WebTargetConfig,\n): ResolvedWebTarget | undefined {\n const entries = webTargetSources\n .map((source) => [source, config[source]] as const)\n .filter(\n (\n entry,\n ): entry is readonly [\n WebTargetSource,\n Partial<MidsceneYamlScriptWebEnv>,\n ] => typeof entry[1] !== 'undefined',\n );\n\n if (entries.length === 0) {\n return undefined;\n }\n\n if (entries.length > 1) {\n const specifiedTargets = entries.map(([source]) => source);\n throw new Error(\n `[midscene] Only one web target can be specified, but found multiple: ${specifiedTargets.join(\n ', ',\n )}. Please specify only one of: page, browser, web, or target.`,\n );\n }\n\n const [source, target] = entries[0];\n const explicitMode = target.mode;\n if (\n typeof explicitMode !== 'undefined' &&\n explicitMode !== 'page' &&\n explicitMode !== 'browser'\n ) {\n throw new Error(\n `[midscene] web target mode must be either \"page\" or \"browser\", but got \"${explicitMode}\".`,\n );\n }\n\n if (source === 'page' && explicitMode === 'browser') {\n throw new Error(\n '[midscene] page target cannot use mode: browser. Use browser: instead.',\n );\n }\n\n if (source === 'browser' && explicitMode === 'page') {\n throw new Error(\n '[midscene] browser target cannot use mode: page. Use page: instead.',\n );\n }\n\n const mode =\n source === 'page'\n ? 'page'\n : source === 'browser'\n ? 'browser'\n : (explicitMode ?? 'page');\n\n if (mode === 'page' && target.autoFollowNewPage) {\n throw new Error(\n '[midscene] autoFollowNewPage requires browser mode. Use browser: or web.mode: browser.',\n );\n }\n\n if (\n mode === 'browser' &&\n typeof target.forceSameTabNavigation !== 'undefined'\n ) {\n throw new Error(\n '[midscene] forceSameTabNavigation cannot be used in browser mode. Use page: or web.mode: page when same-tab navigation is required.',\n );\n }\n\n return {\n source,\n mode,\n target: {\n ...target,\n mode,\n },\n };\n}\n\n/** Legacy output settings apply to every host, including native Test setup.\n * Target-local values keep their original priority; config supplies defaults.\n */\nexport function resolveYamlOutputConfig(\n script: Omit<MidsceneYamlScript, 'tasks'>,\n): {\n output?: string;\n unstableLogContent?: boolean | string;\n} {\n const target =\n resolveWebTarget(script)?.target ??\n script.android ??\n script.ios ??\n script.harmony ??\n script.computer;\n return {\n output: target?.output ?? script.config?.output,\n unstableLogContent:\n target?.unstableLogContent ?? script.config?.unstableLogContent,\n };\n}\n\nfunction interpolateEnvVarRefs(\n value: string,\n keepUnresolvedRefs = false,\n): string {\n let result = '';\n let lastIndex = 0;\n let searchFrom = 0;\n\n while (searchFrom < value.length) {\n const start = value.indexOf('${', searchFrom);\n if (start === -1) {\n break;\n }\n\n const end = value.indexOf('}', start + 2);\n if (end === -1) {\n break;\n }\n\n const rawName = value.slice(start + 2, end);\n if (!rawName) {\n searchFrom = end + 1;\n continue;\n }\n\n result += value.slice(lastIndex, start);\n const envVar = rawName.trim();\n const envValue = process.env[envVar];\n if (envValue === undefined) {\n if (keepUnresolvedRefs) {\n result += value.slice(start, end + 1);\n } else {\n throw new Error(`Environment variable \"${envVar}\" is not defined`);\n }\n } else {\n result += envValue;\n }\n lastIndex = end + 1;\n searchFrom = end + 1;\n }\n\n return result + value.slice(lastIndex);\n}\n\nconst multimodalLocateOptionFieldMap: Record<keyof TMultimodalPrompt, true> = {\n images: true,\n convertHttpImage2Base64: true,\n};\n\nconst multimodalLocateOptionKeys = Object.keys(\n multimodalLocateOptionFieldMap,\n) as Array<keyof TMultimodalPrompt>;\n\nfunction extractMultimodalPrompt(\n opt?: LocateOption,\n): Partial<TMultimodalPrompt> | undefined {\n if (typeof opt !== 'object' || opt === null) {\n return undefined;\n }\n\n const entries = multimodalLocateOptionKeys\n .map((key) => [key, opt[key]] as const)\n .filter(([, value]) => value !== undefined);\n\n return entries.length\n ? (Object.fromEntries(entries) as Partial<TMultimodalPrompt>)\n : undefined;\n}\n\nexport function interpolateEnvVars(content: string): string {\n // Process line by line to skip commented lines\n const lines = content.split('\\n');\n const processedLines = lines.map((line) => {\n // Check if the line is a YAML comment (starts with # after optional whitespace)\n const trimmedLine = line.trimStart();\n if (trimmedLine.startsWith('#')) {\n // Skip interpolation for comment lines\n return line;\n }\n\n // Process environment variables for non-comment lines\n return interpolateEnvVarRefs(line);\n });\n\n return processedLines.join('\\n');\n}\n\nfunction interpolateYamlScriptEnvVars(content: string): string {\n let inTopLevelTasksBlock = false;\n\n return content\n .split('\\n')\n .map((line) => {\n const trimmedLine = line.trimStart();\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n return line;\n }\n\n const indentSize = line.length - trimmedLine.length;\n if (indentSize === 0) {\n if (topLevelTasksPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = true;\n return line;\n }\n\n if (topLevelYamlKeyPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = false;\n }\n }\n\n return interpolateEnvVarRefs(line, inTopLevelTasksBlock);\n })\n .join('\\n');\n}\n\nexport function parseYamlScript(\n content: string,\n filePath?: string,\n): MidsceneYamlScript {\n return parseLegacyYamlScript(content, filePath);\n}\n\n/** Internal collection observer; the public parser keeps its original signature. */\nexport function parseLegacyYamlScript(\n content: string,\n filePath?: string,\n onConfig?: (config: Omit<MidsceneYamlScript, 'tasks'>) => void,\n): MidsceneYamlScript {\n let processedContent = content;\n if (content.indexOf('android') !== -1 && content.match(/deviceId:\\s*(\\d+)/)) {\n let matchedDeviceId;\n processedContent = content.replace(\n /deviceId:\\s*(\\d+)/g,\n (match, deviceId) => {\n matchedDeviceId = deviceId;\n return `deviceId: '${deviceId}'`;\n },\n );\n console.warn(\n `please use string-style deviceId in yaml script, for example: deviceId: \"${matchedDeviceId}\"`,\n );\n }\n const interpolatedContent = interpolateYamlScriptEnvVars(processedContent);\n const obj = yaml.load(interpolatedContent, {\n schema: yaml.JSON_SCHEMA,\n }) as MidsceneYamlScript;\n\n if (obj && typeof obj === 'object' && !Array.isArray(obj)) onConfig?.(obj);\n const pathTip = filePath ? `, failed to load ${filePath}` : '';\n resolveWebTarget(obj);\n assert(obj.tasks, `property \"tasks\" is required in yaml script ${pathTip}`);\n assert(\n Array.isArray(obj.tasks),\n `property \"tasks\" must be an array in yaml script, but got ${obj.tasks}`,\n );\n return obj;\n}\n\nexport function buildDetailedLocateParam(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n): DetailedLocateParam | undefined {\n debugUtils('will call buildDetailedLocateParam', locatePrompt, opt);\n // Normalize object-form TUserPrompt: when the object only contains a\n // `prompt` string (no multimodal fields like `images`), unwrap it to\n // avoid double nesting like { prompt: { prompt: '...' } }.\n let normalizedLocatePrompt: TUserPrompt = locatePrompt;\n if (\n typeof locatePrompt === 'object' &&\n locatePrompt !== null &&\n 'prompt' in locatePrompt\n ) {\n const { prompt: innerPrompt, ...rest } = locatePrompt;\n const hasMultimodalFields = Object.keys(rest).length > 0;\n normalizedLocatePrompt = hasMultimodalFields ? locatePrompt : innerPrompt;\n }\n\n let prompt = normalizedLocatePrompt || opt?.prompt || (opt as any)?.locate; // as a shortcut\n let deepLocate = false;\n let cacheable = true;\n let xpath = undefined;\n\n if (typeof opt === 'object' && opt !== null) {\n // Backward-compatible: accept `deepThink` as a deprecated alias for `deepLocate`.\n // All downstream code works on `deepLocate` only; the compatibility resolution\n // is intentionally kept here at the entry point so it does not bleed through\n // the rest of the call stack.\n deepLocate = opt.deepLocate ?? opt.deepThink ?? false;\n cacheable = opt.cacheable ?? true;\n xpath = opt.xpath;\n if (locatePrompt && opt.prompt && locatePrompt !== opt.prompt) {\n console.warn(\n 'conflict prompt for item',\n locatePrompt,\n opt,\n 'maybe you put the prompt in the wrong place',\n );\n }\n prompt = prompt || opt.prompt;\n }\n\n if (!prompt) {\n debugUtils(\n 'no prompt, will return undefined in buildDetailedLocateParam',\n opt,\n );\n return undefined;\n }\n\n const promptDisplay = typeof prompt === 'string' ? prompt : prompt.prompt;\n const context = opt?.context?.trim() || undefined;\n prompt = buildLocatePromptWithContext(prompt, opt?.context);\n\n const multimodalPrompt = extractMultimodalPrompt(opt);\n if (multimodalPrompt) {\n prompt =\n typeof prompt === 'string'\n ? {\n prompt,\n ...multimodalPrompt,\n }\n : {\n ...prompt,\n ...multimodalPrompt,\n };\n }\n\n return {\n prompt,\n ...(context ? { promptDisplay, context } : {}),\n deepLocate,\n cacheable,\n xpath,\n };\n}\n\nexport function buildDetailedLocateParamAndRestParams(\n locatePrompt: TUserPrompt,\n opt: LocateOption | undefined,\n excludeKeys: string[] = [],\n): {\n locateParam: DetailedLocateParam | undefined;\n restParams: Record<string, any>;\n} {\n const multimodalPrompt = extractMultimodalPrompt(opt);\n const locateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n // Extract all keys from opt except the ones already included in locateParam\n const restParams: Record<string, any> = {};\n\n if (typeof opt === 'object' && opt !== null) {\n // Get all keys from opt\n const allKeys = Object.keys(opt);\n\n // `context` has already been merged into the locate prompt.\n const locateParamKeys = Object.keys(locateParam || {});\n const multimodalPromptKeys =\n typeof locateParam?.prompt === 'object' && locateParam?.prompt !== null\n ? Object.keys(multimodalPrompt || {})\n : [];\n\n // Extract all other keys\n for (const key of allKeys) {\n if (\n !locateParamKeys.includes(key) &&\n key !== 'context' &&\n key !== 'deepThink' &&\n !multimodalPromptKeys.includes(key) &&\n !excludeKeys.includes(key) &&\n key !== 'locate'\n ) {\n restParams[key] = opt[key as keyof LocateOption];\n }\n }\n }\n\n return {\n locateParam,\n restParams,\n };\n}\n"],"names":["debugUtils","getDebug","topLevelTasksPattern","topLevelYamlKeyPattern","webTargetSources","resolveWebTarget","config","entries","source","entry","specifiedTargets","Error","target","explicitMode","mode","resolveYamlOutputConfig","script","interpolateEnvVarRefs","value","keepUnresolvedRefs","result","lastIndex","searchFrom","start","end","rawName","envVar","envValue","process","undefined","multimodalLocateOptionFieldMap","multimodalLocateOptionKeys","Object","extractMultimodalPrompt","opt","key","interpolateEnvVars","content","lines","processedLines","line","trimmedLine","interpolateYamlScriptEnvVars","inTopLevelTasksBlock","indentSize","parseYamlScript","filePath","parseLegacyYamlScript","onConfig","processedContent","matchedDeviceId","match","deviceId","console","interpolatedContent","obj","yaml","Array","pathTip","assert","buildDetailedLocateParam","locatePrompt","normalizedLocatePrompt","innerPrompt","rest","hasMultimodalFields","prompt","deepLocate","cacheable","xpath","promptDisplay","context","buildLocatePromptWithContext","multimodalPrompt","buildDetailedLocateParamAndRestParams","excludeKeys","locateParam","restParams","allKeys","locateParamKeys","multimodalPromptKeys"],"mappings":";;;;AAYA,MAAMA,aAAaC,SAAS;AAE5B,MAAMC,uBAAuB;AAC7B,MAAMC,yBAAyB;AAc/B,MAAMC,mBAAsC;IAC1C;IACA;IACA;IACA;CACD;AAEM,SAASC,iBACdC,MAAuB;IAEvB,MAAMC,UAAUH,iBACb,GAAG,CAAC,CAACI,SAAW;YAACA;YAAQF,MAAM,CAACE,OAAO;SAAC,EACxC,MAAM,CACL,CACEC,QAIG,AAAoB,WAAbA,KAAK,CAAC,EAAE;IAGxB,IAAIF,AAAmB,MAAnBA,QAAQ,MAAM,EAChB;IAGF,IAAIA,QAAQ,MAAM,GAAG,GAAG;QACtB,MAAMG,mBAAmBH,QAAQ,GAAG,CAAC,CAAC,CAACC,OAAO,GAAKA;QACnD,MAAM,IAAIG,MACR,CAAC,qEAAqE,EAAED,iBAAiB,IAAI,CAC3F,MACA,4DAA4D,CAAC;IAEnE;IAEA,MAAM,CAACF,QAAQI,OAAO,GAAGL,OAAO,CAAC,EAAE;IACnC,MAAMM,eAAeD,OAAO,IAAI;IAChC,IACE,AAAwB,WAAjBC,gBACPA,AAAiB,WAAjBA,gBACAA,AAAiB,cAAjBA,cAEA,MAAM,IAAIF,MACR,CAAC,wEAAwE,EAAEE,aAAa,EAAE,CAAC;IAI/F,IAAIL,AAAW,WAAXA,UAAqBK,AAAiB,cAAjBA,cACvB,MAAM,IAAIF,MACR;IAIJ,IAAIH,AAAW,cAAXA,UAAwBK,AAAiB,WAAjBA,cAC1B,MAAM,IAAIF,MACR;IAIJ,MAAMG,OACJN,AAAW,WAAXA,SACI,SACAA,AAAW,cAAXA,SACE,YACCK,gBAAgB;IAEzB,IAAIC,AAAS,WAATA,QAAmBF,OAAO,iBAAiB,EAC7C,MAAM,IAAID,MACR;IAIJ,IACEG,AAAS,cAATA,QACA,AAAyC,WAAlCF,OAAO,sBAAsB,EAEpC,MAAM,IAAID,MACR;IAIJ,OAAO;QACLH;QACAM;QACA,QAAQ;YACN,GAAGF,MAAM;YACTE;QACF;IACF;AACF;AAKO,SAASC,wBACdC,MAAyC;IAKzC,MAAMJ,SACJP,iBAAiBW,SAAS,UAC1BA,OAAO,OAAO,IACdA,OAAO,GAAG,IACVA,OAAO,OAAO,IACdA,OAAO,QAAQ;IACjB,OAAO;QACL,QAAQJ,QAAQ,UAAUI,OAAO,MAAM,EAAE;QACzC,oBACEJ,QAAQ,sBAAsBI,OAAO,MAAM,EAAE;IACjD;AACF;AAEA,SAASC,sBACPC,KAAa,EACbC,qBAAqB,KAAK;IAE1B,IAAIC,SAAS;IACb,IAAIC,YAAY;IAChB,IAAIC,aAAa;IAEjB,MAAOA,aAAaJ,MAAM,MAAM,CAAE;QAChC,MAAMK,QAAQL,MAAM,OAAO,CAAC,MAAMI;QAClC,IAAIC,AAAU,OAAVA,OACF;QAGF,MAAMC,MAAMN,MAAM,OAAO,CAAC,KAAKK,QAAQ;QACvC,IAAIC,AAAQ,OAARA,KACF;QAGF,MAAMC,UAAUP,MAAM,KAAK,CAACK,QAAQ,GAAGC;QACvC,IAAI,CAACC,SAAS;YACZH,aAAaE,MAAM;YACnB;QACF;QAEAJ,UAAUF,MAAM,KAAK,CAACG,WAAWE;QACjC,MAAMG,SAASD,QAAQ,IAAI;QAC3B,MAAME,WAAWC,QAAQ,GAAG,CAACF,OAAO;QACpC,IAAIC,AAAaE,WAAbF,UACF,IAAIR,oBACFC,UAAUF,MAAM,KAAK,CAACK,OAAOC,MAAM;aAEnC,MAAM,IAAIb,MAAM,CAAC,sBAAsB,EAAEe,OAAO,gBAAgB,CAAC;aAGnEN,UAAUO;QAEZN,YAAYG,MAAM;QAClBF,aAAaE,MAAM;IACrB;IAEA,OAAOJ,SAASF,MAAM,KAAK,CAACG;AAC9B;AAEA,MAAMS,iCAAwE;IAC5E,QAAQ;IACR,yBAAyB;AAC3B;AAEA,MAAMC,6BAA6BC,OAAO,IAAI,CAC5CF;AAGF,SAASG,wBACPC,GAAkB;IAElB,IAAI,AAAe,YAAf,OAAOA,OAAoBA,AAAQ,SAARA,KAC7B;IAGF,MAAM3B,UAAUwB,2BACb,GAAG,CAAC,CAACI,MAAQ;YAACA;YAAKD,GAAG,CAACC,IAAI;SAAC,EAC5B,MAAM,CAAC,CAAC,GAAGjB,MAAM,GAAKA,AAAUW,WAAVX;IAEzB,OAAOX,QAAQ,MAAM,GAChByB,OAAO,WAAW,CAACzB,WACpBsB;AACN;AAEO,SAASO,mBAAmBC,OAAe;IAEhD,MAAMC,QAAQD,QAAQ,KAAK,CAAC;IAC5B,MAAME,iBAAiBD,MAAM,GAAG,CAAC,CAACE;QAEhC,MAAMC,cAAcD,KAAK,SAAS;QAClC,IAAIC,YAAY,UAAU,CAAC,MAEzB,OAAOD;QAIT,OAAOvB,sBAAsBuB;IAC/B;IAEA,OAAOD,eAAe,IAAI,CAAC;AAC7B;AAEA,SAASG,6BAA6BL,OAAe;IACnD,IAAIM,uBAAuB;IAE3B,OAAON,QACJ,KAAK,CAAC,MACN,GAAG,CAAC,CAACG;QACJ,MAAMC,cAAcD,KAAK,SAAS;QAClC,IAAI,CAACC,eAAeA,YAAY,UAAU,CAAC,MACzC,OAAOD;QAGT,MAAMI,aAAaJ,KAAK,MAAM,GAAGC,YAAY,MAAM;QACnD,IAAIG,AAAe,MAAfA,YAAkB;YACpB,IAAI1C,qBAAqB,IAAI,CAACuC,cAAc;gBAC1CE,uBAAuB;gBACvB,OAAOH;YACT;YAEA,IAAIrC,uBAAuB,IAAI,CAACsC,cAC9BE,uBAAuB;QAE3B;QAEA,OAAO1B,sBAAsBuB,MAAMG;IACrC,GACC,IAAI,CAAC;AACV;AAEO,SAASE,gBACdR,OAAe,EACfS,QAAiB;IAEjB,OAAOC,sBAAsBV,SAASS;AACxC;AAGO,SAASC,sBACdV,OAAe,EACfS,QAAiB,EACjBE,QAA8D;IAE9D,IAAIC,mBAAmBZ;IACvB,IAAIA,AAA+B,OAA/BA,QAAQ,OAAO,CAAC,cAAqBA,QAAQ,KAAK,CAAC,sBAAsB;QAC3E,IAAIa;QACJD,mBAAmBZ,QAAQ,OAAO,CAChC,sBACA,CAACc,OAAOC;YACNF,kBAAkBE;YAClB,OAAO,CAAC,WAAW,EAAEA,SAAS,CAAC,CAAC;QAClC;QAEFC,QAAQ,IAAI,CACV,CAAC,yEAAyE,EAAEH,gBAAgB,CAAC,CAAC;IAElG;IACA,MAAMI,sBAAsBZ,6BAA6BO;IACzD,MAAMM,MAAMC,QAAAA,IAAS,CAACF,qBAAqB;QACzC,QAAQE,QAAAA,WAAgB;IAC1B;IAEA,IAAID,OAAO,AAAe,YAAf,OAAOA,OAAoB,CAACE,MAAM,OAAO,CAACF,MAAMP,WAAWO;IACtE,MAAMG,UAAUZ,WAAW,CAAC,iBAAiB,EAAEA,UAAU,GAAG;IAC5DzC,iBAAiBkD;IACjBI,OAAOJ,IAAI,KAAK,EAAE,CAAC,4CAA4C,EAAEG,SAAS;IAC1EC,OACEF,MAAM,OAAO,CAACF,IAAI,KAAK,GACvB,CAAC,0DAA0D,EAAEA,IAAI,KAAK,EAAE;IAE1E,OAAOA;AACT;AAEO,SAASK,yBACdC,YAAyB,EACzB3B,GAAkB;IAElBlC,WAAW,sCAAsC6D,cAAc3B;IAI/D,IAAI4B,yBAAsCD;IAC1C,IACE,AAAwB,YAAxB,OAAOA,gBACPA,AAAiB,SAAjBA,gBACA,YAAYA,cACZ;QACA,MAAM,EAAE,QAAQE,WAAW,EAAE,GAAGC,MAAM,GAAGH;QACzC,MAAMI,sBAAsBjC,OAAO,IAAI,CAACgC,MAAM,MAAM,GAAG;QACvDF,yBAAyBG,sBAAsBJ,eAAeE;IAChE;IAEA,IAAIG,SAASJ,0BAA0B5B,KAAK,UAAWA,KAAa;IACpE,IAAIiC,aAAa;IACjB,IAAIC,YAAY;IAChB,IAAIC;IAEJ,IAAI,AAAe,YAAf,OAAOnC,OAAoBA,AAAQ,SAARA,KAAc;QAK3CiC,aAAajC,IAAI,UAAU,IAAIA,IAAI,SAAS,IAAI;QAChDkC,YAAYlC,IAAI,SAAS,IAAI;QAC7BmC,QAAQnC,IAAI,KAAK;QACjB,IAAI2B,gBAAgB3B,IAAI,MAAM,IAAI2B,iBAAiB3B,IAAI,MAAM,EAC3DmB,QAAQ,IAAI,CACV,4BACAQ,cACA3B,KACA;QAGJgC,SAASA,UAAUhC,IAAI,MAAM;IAC/B;IAEA,IAAI,CAACgC,QAAQ,YACXlE,WACE,gEACAkC;IAKJ,MAAMoC,gBAAgB,AAAkB,YAAlB,OAAOJ,SAAsBA,SAASA,OAAO,MAAM;IACzE,MAAMK,UAAUrC,KAAK,SAAS,UAAUL;IACxCqC,SAASM,6BAA6BN,QAAQhC,KAAK;IAEnD,MAAMuC,mBAAmBxC,wBAAwBC;IACjD,IAAIuC,kBACFP,SACE,AAAkB,YAAlB,OAAOA,SACH;QACEA;QACA,GAAGO,gBAAgB;IACrB,IACA;QACE,GAAGP,MAAM;QACT,GAAGO,gBAAgB;IACrB;IAGR,OAAO;QACLP;QACA,GAAIK,UAAU;YAAED;YAAeC;QAAQ,IAAI,CAAC,CAAC;QAC7CJ;QACAC;QACAC;IACF;AACF;AAEO,SAASK,sCACdb,YAAyB,EACzB3B,GAA6B,EAC7ByC,cAAwB,EAAE;IAK1B,MAAMF,mBAAmBxC,wBAAwBC;IACjD,MAAM0C,cAAchB,yBAAyBC,cAAc3B;IAG3D,MAAM2C,aAAkC,CAAC;IAEzC,IAAI,AAAe,YAAf,OAAO3C,OAAoBA,AAAQ,SAARA,KAAc;QAE3C,MAAM4C,UAAU9C,OAAO,IAAI,CAACE;QAG5B,MAAM6C,kBAAkB/C,OAAO,IAAI,CAAC4C,eAAe,CAAC;QACpD,MAAMI,uBACJ,AAA+B,YAA/B,OAAOJ,aAAa,UAAuBA,aAAa,WAAW,OAC/D5C,OAAO,IAAI,CAACyC,oBAAoB,CAAC,KACjC,EAAE;QAGR,KAAK,MAAMtC,OAAO2C,QAChB,IACE,CAACC,gBAAgB,QAAQ,CAAC5C,QAC1BA,AAAQ,cAARA,OACAA,AAAQ,gBAARA,OACA,CAAC6C,qBAAqB,QAAQ,CAAC7C,QAC/B,CAACwC,YAAY,QAAQ,CAACxC,QACtBA,AAAQ,aAARA,KAEA0C,UAAU,CAAC1C,IAAI,GAAGD,GAAG,CAACC,IAA0B;IAGtD;IAEA,OAAO;QACLyC;QACAC;IACF;AACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { enterYamlAction, enterYamlExecution, runInYamlExecutionContext } from "./yaml/execution-session.mjs";
|
|
2
|
+
import { getLegacyYamlPlayerState } from "./yaml/player-state.mjs";
|
|
3
|
+
import { isYamlReportEnabled } from "./yaml/report-policy.mjs";
|
|
4
|
+
import { collectLegacyYamlDocument } from "./yaml/test-runner-compat.mjs";
|
|
5
|
+
import { parseLegacyYamlScript } from "./yaml/utils.mjs";
|
|
6
|
+
import { getLegacyYamlResultData, legacyAgentTestRunnerNodeDefinitions } from "./yaml/test-runner-nodes.mjs";
|
|
7
|
+
export { collectLegacyYamlDocument, enterYamlAction, enterYamlExecution, getLegacyYamlPlayerState, getLegacyYamlResultData, isYamlReportEnabled, legacyAgentTestRunnerNodeDefinitions, parseLegacyYamlScript, runInYamlExecutionContext };
|
package/dist/es/yaml.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml.mjs","sources":["../../src/yaml.ts"],"sourcesContent":["import type { TMultimodalPrompt, TUserPrompt } from './common';\nimport type {\n AndroidDeviceOpt,\n HarmonyDeviceOpt,\n IOSDeviceOpt,\n} from './device';\nimport type { AgentOpt, LocateResultElement, Rect } from './types';\nimport type { UIContext } from './types';\n\nexport interface LocateOption extends Partial<TMultimodalPrompt> {\n prompt?: TUserPrompt;\n /**\n * Additional facts, rules, or constraints for this AI call. It overrides\n * the matching API context and `aiContexts.default`; `''` disables inherited\n * user context for this call.\n */\n context?: string;\n deepLocate?: boolean; // only available in vl model\n /** @deprecated Use `deepLocate` instead. Kept for backward compatibility. */\n deepThink?: boolean; // alias for deepLocate\n cacheable?: boolean; // user can set this param to false to disable the cache for a single agent api\n xpath?: string; // only available in web\n uiContext?: UIContext;\n fileChooserAccept?: string | string[]; // file path(s) to upload when tapping triggers a file chooser\n}\n\nexport interface ServiceExtractOption {\n /**\n * Additional facts, decision rules, constraints, or output requirements for\n * this AI call. It overrides the matching API context and\n * `aiContexts.default`; `''` disables inherited user context for this call.\n */\n context?: string;\n domIncluded?: boolean | 'visible-only';\n screenshotIncluded?: boolean;\n [key: string]: unknown;\n}\n\nexport interface DetailedLocateParam\n extends Omit<\n LocateOption,\n 'context' | 'deepThink' | keyof TMultimodalPrompt\n > {\n prompt: TUserPrompt;\n /** Original prompt text used for user-facing reports. */\n promptDisplay?: string;\n /** Per-call AI guidance recorded in user-facing reports. */\n context?: string;\n}\n\nexport type ScrollType =\n | 'singleAction'\n | 'scrollToBottom'\n | 'scrollToTop'\n | 'scrollToRight'\n | 'scrollToLeft'\n // Legacy aliases kept for backward compatibility\n | 'once'\n | 'untilBottom'\n | 'untilTop'\n | 'untilRight'\n | 'untilLeft';\n\nexport type ActionScrollParam = {\n direction?: 'down' | 'up' | 'right' | 'left';\n scrollType?: ScrollType;\n distance?: number | null;\n locate?: LocateResultElement;\n};\n\nexport type ScrollParam = Omit<ActionScrollParam, 'locate'>;\n\nexport interface MidsceneYamlScript {\n // @deprecated\n target?: MidsceneYamlScriptWebEnv;\n\n page?: MidsceneYamlScriptWebEnv;\n browser?: MidsceneYamlScriptWebEnv;\n web?: MidsceneYamlScriptWebEnv;\n android?: MidsceneYamlScriptAndroidEnv;\n ios?: MidsceneYamlScriptIOSEnv;\n harmony?: MidsceneYamlScriptHarmonyEnv;\n computer?: MidsceneYamlScriptComputerEnv;\n\n interface?: MidsceneYamlScriptEnvGeneralInterface;\n config?: MidsceneYamlScriptConfig;\n agent?: MidsceneYamlScriptAgentOpt;\n\n tasks: MidsceneYamlTask[];\n}\n\nexport interface MidsceneYamlTask {\n name: string;\n flow: MidsceneYamlFlowItem[];\n continueOnError?: boolean;\n}\n\n/**\n * Agent configuration options that can be specified in YAML scripts.\n *\n * This type includes serializable fields from AgentOpt, excluding non-serializable\n * fields like functions and complex objects. All fields are optional.\n *\n * @remarks\n * - testId is deprecated; prefer reportFileName and cache.id\n * - These settings apply to all platforms (Web, Android, iOS, Generic Interface)\n * - modelConfig is configured through environment variables, not in YAML\n *\n * @example\n * ```yaml\n * agent:\n * reportFileName: \"checkout-report\"\n * groupName: \"E2E Test Suite\"\n * generateReport: true\n * replanningCycleLimit: 30\n * cache:\n * id: \"checkout-cache\"\n * strategy: \"read-write\"\n * ```\n */\nexport type MidsceneYamlScriptAgentOpt = Pick<\n AgentOpt,\n | 'testId' // deprecated, kept for backward compatibility\n | 'groupName'\n | 'groupDescription'\n | 'generateReport'\n | 'persistExecutionDump'\n | 'autoPrintReportMsg'\n | 'reportFileName'\n | 'replanningCycleLimit'\n | 'aiContexts'\n | 'aiActContext'\n | 'aiActionContext'\n | 'cache'\n | 'screenshotShrinkFactor'\n>;\n\nexport interface MidsceneYamlScriptConfig {\n output?: string;\n unstableLogContent?: boolean | string;\n}\n\nexport interface MidsceneYamlScriptEnvGeneralInterface {\n // this will work as `const {...} = import('...'); const interface = new ...(param)`\n module: string;\n export?: string;\n param?: Record<string, any>;\n}\n\nexport interface MidsceneYamlScriptWebEnv\n extends MidsceneYamlScriptConfig,\n MidsceneYamlScriptAgentOpt {\n mode?: 'page' | 'browser';\n\n // for web only\n serve?: string;\n url: string;\n\n // puppeteer only\n userAgent?: string;\n acceptInsecureCerts?: boolean;\n viewportWidth?: number;\n viewportHeight?: number;\n deviceScaleFactor?: number;\n waitForNetworkIdle?: {\n timeout?: number;\n continueOnNetworkIdleError?: boolean; // should continue if failed to wait for network idle, true for default\n };\n cookie?: string;\n\n /**\n * Extra HTTP headers sent with every request (Puppeteer only, not supported\n * in bridge mode). Useful when the server validates custom request headers.\n *\n * Header values must be strings. Quote values that YAML would otherwise parse\n * as a boolean or number (e.g. `true`, `false`, `123`), such as `\"true\"`.\n *\n * @example\n * ```yaml\n * web:\n * url: https://example.com\n * extraHTTPHeaders:\n * X-Custom-Token: my-token\n * Accept-Language: en-US\n * ```\n */\n extraHTTPHeaders?: Record<string, string>;\n\n forceSameTabNavigation?: boolean; // if limit the new tab to the current page, true for default in yaml script\n autoFollowNewPage?: boolean; // if use BrowserAgent to follow newly opened pages, false for default\n\n /**\n * Chrome download directory (Puppeteer only, not supported in bridge mode).\n *\n * Relative paths are resolved from the current working directory.\n *\n * @example\n * ```yaml\n * web:\n * url: https://example.com\n * downloadPath: ./downloads\n * ```\n */\n downloadPath?: string;\n\n /**\n * Custom Chrome launch arguments (Puppeteer only, not supported in bridge mode).\n *\n * Allows passing custom command-line arguments to Chrome/Chromium when launching the browser.\n * This is useful for testing scenarios that require specific browser configurations.\n *\n * ⚠️ Security Warning: Some arguments (e.g., --no-sandbox, --disable-web-security) may\n * reduce browser security. Use only in controlled testing environments.\n *\n * @example\n * ```yaml\n * web:\n * url: https://example.com\n * chromeArgs:\n * - '--disable-features=ThirdPartyCookiePhaseout'\n * - '--disable-features=SameSiteByDefaultCookies'\n * - '--window-size=1920,1080'\n * ```\n */\n chromeArgs?: string[];\n\n // bridge mode config\n bridgeMode?: false | 'newTabWithUrl' | 'currentTab';\n closeNewTabsAfterDisconnect?: boolean;\n\n /**\n * CDP (Chrome DevTools Protocol) endpoint URL.\n * When specified, connects to an existing Chrome browser via CDP instead of launching a new one.\n *\n * @example\n * ```yaml\n * web:\n * url: https://example.com\n * cdpEndpoint: ws://localhost:9222/devtools/browser/xxxx\n * ```\n */\n cdpEndpoint?: string;\n}\n\nexport interface MidsceneYamlScriptAndroidEnv\n extends MidsceneYamlScriptConfig,\n Omit<AndroidDeviceOpt, 'customActions'> {\n // The Android device ID to connect to, optional, will use the first device if not specified\n deviceId?: string;\n\n // The URL or app package to launch, optional, will use the current screen if not specified\n launch?: string;\n}\n\nexport interface MidsceneYamlScriptIOSEnv\n extends MidsceneYamlScriptConfig,\n Omit<IOSDeviceOpt, 'customActions'> {\n // The URL or app bundle ID to launch, optional, will use the current screen if not specified\n launch?: string;\n}\n\nexport interface MidsceneYamlScriptHarmonyEnv\n extends MidsceneYamlScriptConfig,\n Omit<HarmonyDeviceOpt, 'customActions'> {\n // The HarmonyOS device ID to connect to, optional, will use the first device if not specified\n deviceId?: string;\n\n // The bundle name, bundle/Ability target, or mapped app name to launch, optional,\n // will use the current screen if not specified\n launch?: string;\n\n // Custom mapping of app names to bundle names or explicit bundle/Ability targets;\n // user-provided mappings take precedence over defaults\n appNameMapping?: Record<string, string>;\n}\n\nexport interface MidsceneYamlScriptComputerEnv\n extends MidsceneYamlScriptConfig {\n // The display ID to use, optional, will use the primary display if not specified\n displayId?: string;\n}\n\nexport type MidsceneYamlScriptEnv =\n | MidsceneYamlScriptWebEnv\n | MidsceneYamlScriptAndroidEnv\n | MidsceneYamlScriptIOSEnv\n | MidsceneYamlScriptHarmonyEnv\n | MidsceneYamlScriptComputerEnv;\n\n/** Target sections that can be supplied as batch-wide YAML overrides. */\nexport type MidsceneYamlTargetKey = Exclude<\n keyof MidsceneYamlScript,\n 'config' | 'agent' | 'tasks'\n>;\n\nconst midsceneYamlTargetKeyMap = {\n target: true,\n page: true,\n browser: true,\n web: true,\n android: true,\n ios: true,\n harmony: true,\n computer: true,\n interface: true,\n} as const satisfies Record<MidsceneYamlTargetKey, true>;\n\nexport const midsceneYamlTargetKeys = Object.keys(\n midsceneYamlTargetKeyMap,\n) as MidsceneYamlTargetKey[];\n\n/**\n * Partial target settings applied to every script in a YAML batch.\n *\n * Batch settings are deep-merged over each script's target section, so every\n * nested target field is optional here even when a standalone script requires\n * it.\n */\nexport type MidsceneYamlTargetConfig = {\n [Target in MidsceneYamlTargetKey]?: Partial<\n NonNullable<MidsceneYamlScript[Target]>\n >;\n};\n\nexport interface MidsceneYamlFlowItemAIAction {\n // defined as aiAction for backward compatibility\n aiAction?: TUserPrompt | null;\n ai?: TUserPrompt | null; // this is the shortcut for aiAct\n aiAct?: TUserPrompt | null;\n instruction?: TUserPrompt;\n aiActionProgressTips?: string[];\n cacheable?: boolean;\n [key: string]: unknown;\n}\n\nexport interface MidsceneYamlFlowItemAIAssert extends ServiceExtractOption {\n aiAssert: string;\n errorMessage?: string;\n name?: string;\n}\n\nexport interface MidsceneYamlFlowItemAIWaitFor extends ServiceExtractOption {\n aiWaitFor: string;\n timeout?: number;\n}\n\nexport interface MidsceneYamlFlowItemRunGherkinScenario {\n runGherkinScenario: string;\n}\n\nexport interface MidsceneYamlFlowItemEvaluateJavaScript {\n javascript: string;\n name?: string;\n}\n\nexport interface MidsceneYamlFlowItemSleep {\n sleep: number;\n}\n\nexport interface MidsceneYamlFlowItemLogScreenshot {\n logScreenshot?: string; // optional, the title of the screenshot\n recordToReport?: string; // preferred key for record title\n content?: string;\n}\n\nexport type MidsceneYamlFlowItem =\n | MidsceneYamlFlowItemAIAction\n | MidsceneYamlFlowItemAIAssert\n | MidsceneYamlFlowItemAIWaitFor\n | MidsceneYamlFlowItemRunGherkinScenario\n | MidsceneYamlFlowItemEvaluateJavaScript\n | MidsceneYamlFlowItemSleep\n | MidsceneYamlFlowItemLogScreenshot;\n\nexport interface FreeFn {\n name: string;\n fn: () => void | Promise<void>;\n}\n\nexport interface ScriptPlayerTaskStatus extends MidsceneYamlTask {\n status: ScriptPlayerStatusValue;\n currentStep?: number;\n totalSteps: number;\n error?: Error;\n}\n\nexport type ScriptPlayerStatusValue = 'init' | 'running' | 'done' | 'error';\n\n// Index YAML file types for batch execution\nexport interface MidsceneYamlConfig extends MidsceneYamlTargetConfig {\n /** @deprecated Use `web`, `page`, or `browser` instead. */\n target?: Partial<MidsceneYamlScriptWebEnv>;\n concurrent?: number;\n continueOnError?: boolean;\n /**\n * Number of times to retry a failed yaml file before marking it as failed.\n * A value of 2 means each failing case is re-executed up to 2 extra times\n * (3 attempts in total). Only the cases that failed in the previous attempt\n * are retried. Defaults to 0 (no retry).\n */\n retry?: number;\n summary?: string;\n /**\n * Share one BrowserContext and Page across Puppeteer Web yaml files. This is\n * not supported by bridge mode or non-Web targets.\n */\n shareBrowserContext?: boolean;\n /**\n * A setup yaml file that runs before the main `files`. A setup failure aborts\n * the whole batch and the main files are marked as not executed. Puppeteer\n * Web setup requires `shareBrowserContext: true` to pass browser state to the\n * main files. Other targets run setup without browser-context sharing.\n */\n setup?: string;\n files: string[];\n headed?: boolean;\n keepWindow?: boolean;\n dotenvOverride?: boolean;\n dotenvDebug?: boolean;\n}\n\nexport interface MidsceneYamlConfigOutput {\n format?: 'json';\n path?: string;\n}\n\nexport type MidsceneYamlConfigResultType =\n | 'success'\n | 'failed'\n | 'partialFailed'\n | 'notExecuted';\n\nexport interface MidsceneYamlConfigAttempt {\n attempt: number;\n success: boolean;\n output?: string | null;\n report?: string | null;\n error?: string;\n duration?: number;\n resultType?: MidsceneYamlConfigResultType;\n}\n\nexport interface MidsceneYamlConfigResult {\n file: string;\n success: boolean;\n executed: boolean;\n output?: string | null;\n report?: string | null;\n retryReport?: string | null;\n attempts?: MidsceneYamlConfigAttempt[];\n error?: string;\n duration?: number;\n /**\n * Type of result:\n * - 'success': All tasks completed successfully\n * - 'failed': Execution failed (player error)\n * - 'partialFailed': Some tasks failed but execution continued (continueOnError)\n * - 'notExecuted': Not executed due to previous failures\n */\n resultType?: MidsceneYamlConfigResultType;\n}\n"],"names":["midsceneYamlTargetKeyMap","midsceneYamlTargetKeys","Object"],"mappings":"AAuSA,MAAMA,2BAA2B;IAC/B,QAAQ;IACR,MAAM;IACN,SAAS;IACT,KAAK;IACL,SAAS;IACT,KAAK;IACL,SAAS;IACT,UAAU;IACV,WAAW;AACb;AAEO,MAAMC,yBAAyBC,OAAO,IAAI,CAC/CF"}
|
|
1
|
+
{"version":3,"file":"yaml.mjs","sources":["../../src/yaml.ts"],"sourcesContent":["import type { TMultimodalPrompt, TUserPrompt } from './common';\nimport type {\n AndroidDeviceOpt,\n HarmonyDeviceOpt,\n IOSDeviceOpt,\n} from './device';\nimport type { WorkflowExecutionRecord } from './test-runner/execution-record';\nimport type { AgentOpt, LocateResultElement, Rect } from './types';\nimport type { UIContext } from './types';\n\nexport interface LocateOption extends Partial<TMultimodalPrompt> {\n prompt?: TUserPrompt;\n /**\n * Additional facts, rules, or constraints for this AI call. It overrides\n * the matching API context and `aiContexts.default`; `''` disables inherited\n * user context for this call.\n */\n context?: string;\n deepLocate?: boolean; // only available in vl model\n /** @deprecated Use `deepLocate` instead. Kept for backward compatibility. */\n deepThink?: boolean; // alias for deepLocate\n cacheable?: boolean; // user can set this param to false to disable the cache for a single agent api\n xpath?: string; // only available in web\n uiContext?: UIContext;\n fileChooserAccept?: string | string[]; // file path(s) to upload when tapping triggers a file chooser\n}\n\nexport interface ServiceExtractOption {\n /**\n * Additional facts, decision rules, constraints, or output requirements for\n * this AI call. It overrides the matching API context and\n * `aiContexts.default`; `''` disables inherited user context for this call.\n */\n context?: string;\n domIncluded?: boolean | 'visible-only';\n screenshotIncluded?: boolean;\n [key: string]: unknown;\n}\n\nexport interface DetailedLocateParam\n extends Omit<\n LocateOption,\n 'context' | 'deepThink' | keyof TMultimodalPrompt\n > {\n prompt: TUserPrompt;\n /** Original prompt text used for user-facing reports. */\n promptDisplay?: string;\n /** Per-call AI guidance recorded in user-facing reports. */\n context?: string;\n}\n\nexport type ScrollType =\n | 'singleAction'\n | 'scrollToBottom'\n | 'scrollToTop'\n | 'scrollToRight'\n | 'scrollToLeft'\n // Legacy aliases kept for backward compatibility\n | 'once'\n | 'untilBottom'\n | 'untilTop'\n | 'untilRight'\n | 'untilLeft';\n\nexport type ActionScrollParam = {\n direction?: 'down' | 'up' | 'right' | 'left';\n scrollType?: ScrollType;\n distance?: number | null;\n locate?: LocateResultElement;\n};\n\nexport type ScrollParam = Omit<ActionScrollParam, 'locate'>;\n\nexport interface MidsceneYamlScript {\n // @deprecated\n target?: MidsceneYamlScriptWebEnv;\n\n page?: MidsceneYamlScriptWebEnv;\n browser?: MidsceneYamlScriptWebEnv;\n web?: MidsceneYamlScriptWebEnv;\n android?: MidsceneYamlScriptAndroidEnv;\n ios?: MidsceneYamlScriptIOSEnv;\n harmony?: MidsceneYamlScriptHarmonyEnv;\n computer?: MidsceneYamlScriptComputerEnv;\n\n interface?: MidsceneYamlScriptEnvGeneralInterface;\n config?: MidsceneYamlScriptConfig;\n agent?: MidsceneYamlScriptAgentOpt;\n\n tasks: MidsceneYamlTask[];\n}\n\nexport interface MidsceneYamlTask {\n name: string;\n flow: MidsceneYamlFlowItem[];\n continueOnError?: boolean;\n}\n\n/**\n * Agent configuration options that can be specified in YAML scripts.\n *\n * This type includes serializable fields from AgentOpt, excluding non-serializable\n * fields like functions and complex objects. All fields are optional.\n *\n * @remarks\n * - testId is deprecated; prefer reportFileName and cache.id\n * - These settings apply to all platforms (Web, Android, iOS, Generic Interface)\n * - modelConfig is configured through environment variables, not in YAML\n *\n * @example\n * ```yaml\n * agent:\n * reportFileName: \"checkout-report\"\n * groupName: \"E2E Test Suite\"\n * generateReport: true\n * replanningCycleLimit: 30\n * cache:\n * id: \"checkout-cache\"\n * strategy: \"read-write\"\n * ```\n */\nexport type MidsceneYamlScriptAgentOpt = Pick<\n AgentOpt,\n | 'testId' // deprecated, kept for backward compatibility\n | 'groupName'\n | 'groupDescription'\n | 'generateReport'\n | 'outputFormat'\n | 'persistExecutionDump'\n | 'autoPrintReportMsg'\n | 'reportFileName'\n | 'replanningCycleLimit'\n | 'aiContexts'\n | 'aiActContext'\n | 'aiActionContext'\n | 'cache'\n | 'screenshotShrinkFactor'\n>;\n\nexport interface MidsceneYamlScriptConfig {\n output?: string;\n unstableLogContent?: boolean | string;\n}\n\nexport interface MidsceneYamlScriptEnvGeneralInterface {\n // this will work as `const {...} = import('...'); const interface = new ...(param)`\n module: string;\n export?: string;\n param?: Record<string, any>;\n}\n\nexport interface MidsceneYamlScriptWebEnv\n extends MidsceneYamlScriptConfig,\n MidsceneYamlScriptAgentOpt {\n mode?: 'page' | 'browser';\n\n // for web only\n serve?: string;\n url: string;\n\n // puppeteer only\n userAgent?: string;\n acceptInsecureCerts?: boolean;\n viewportWidth?: number;\n viewportHeight?: number;\n deviceScaleFactor?: number;\n waitForNetworkIdle?: {\n timeout?: number;\n continueOnNetworkIdleError?: boolean; // should continue if failed to wait for network idle, true for default\n };\n cookie?: string;\n\n /**\n * Extra HTTP headers sent with every request (Puppeteer only, not supported\n * in bridge mode). Useful when the server validates custom request headers.\n *\n * Header values must be strings. Quote values that YAML would otherwise parse\n * as a boolean or number (e.g. `true`, `false`, `123`), such as `\"true\"`.\n *\n * @example\n * ```yaml\n * web:\n * url: https://example.com\n * extraHTTPHeaders:\n * X-Custom-Token: my-token\n * Accept-Language: en-US\n * ```\n */\n extraHTTPHeaders?: Record<string, string>;\n\n forceSameTabNavigation?: boolean; // if limit the new tab to the current page, true for default in yaml script\n autoFollowNewPage?: boolean; // if use BrowserAgent to follow newly opened pages, false for default\n\n /**\n * Chrome download directory (Puppeteer only, not supported in bridge mode).\n *\n * Relative paths are resolved from the current working directory.\n *\n * @example\n * ```yaml\n * web:\n * url: https://example.com\n * downloadPath: ./downloads\n * ```\n */\n downloadPath?: string;\n\n /**\n * Custom Chrome launch arguments (Puppeteer only, not supported in bridge mode).\n *\n * Allows passing custom command-line arguments to Chrome/Chromium when launching the browser.\n * This is useful for testing scenarios that require specific browser configurations.\n *\n * ⚠️ Security Warning: Some arguments (e.g., --no-sandbox, --disable-web-security) may\n * reduce browser security. Use only in controlled testing environments.\n *\n * @example\n * ```yaml\n * web:\n * url: https://example.com\n * chromeArgs:\n * - '--disable-features=ThirdPartyCookiePhaseout'\n * - '--disable-features=SameSiteByDefaultCookies'\n * - '--window-size=1920,1080'\n * ```\n */\n chromeArgs?: string[];\n\n // bridge mode config\n bridgeMode?: false | 'newTabWithUrl' | 'currentTab';\n closeNewTabsAfterDisconnect?: boolean;\n\n /**\n * CDP (Chrome DevTools Protocol) endpoint URL.\n * When specified, connects to an existing Chrome browser via CDP instead of launching a new one.\n *\n * @example\n * ```yaml\n * web:\n * url: https://example.com\n * cdpEndpoint: ws://localhost:9222/devtools/browser/xxxx\n * ```\n */\n cdpEndpoint?: string;\n}\n\nexport interface MidsceneYamlScriptAndroidEnv\n extends MidsceneYamlScriptConfig,\n Omit<AndroidDeviceOpt, 'customActions'> {\n // The Android device ID to connect to, optional, will use the first device if not specified\n deviceId?: string;\n\n // The URL or app package to launch, optional, will use the current screen if not specified\n launch?: string;\n}\n\nexport interface MidsceneYamlScriptIOSEnv\n extends MidsceneYamlScriptConfig,\n Omit<IOSDeviceOpt, 'customActions'> {\n // The URL or app bundle ID to launch, optional, will use the current screen if not specified\n launch?: string;\n}\n\nexport interface MidsceneYamlScriptHarmonyEnv\n extends MidsceneYamlScriptConfig,\n Omit<HarmonyDeviceOpt, 'customActions'> {\n // The HarmonyOS device ID to connect to, optional, will use the first device if not specified\n deviceId?: string;\n\n // The bundle name, bundle/Ability target, or mapped app name to launch, optional,\n // will use the current screen if not specified\n launch?: string;\n\n // Custom mapping of app names to bundle names or explicit bundle/Ability targets;\n // user-provided mappings take precedence over defaults\n appNameMapping?: Record<string, string>;\n}\n\nexport interface MidsceneYamlScriptComputerEnv\n extends MidsceneYamlScriptConfig {\n // The display ID to use, optional, will use the primary display if not specified\n displayId?: string;\n}\n\nexport type MidsceneYamlScriptEnv =\n | MidsceneYamlScriptWebEnv\n | MidsceneYamlScriptAndroidEnv\n | MidsceneYamlScriptIOSEnv\n | MidsceneYamlScriptHarmonyEnv\n | MidsceneYamlScriptComputerEnv;\n\n/** Target sections that can be supplied as batch-wide YAML overrides. */\nexport type MidsceneYamlTargetKey = Exclude<\n keyof MidsceneYamlScript,\n 'config' | 'agent' | 'tasks'\n>;\n\nconst midsceneYamlTargetKeyMap = {\n target: true,\n page: true,\n browser: true,\n web: true,\n android: true,\n ios: true,\n harmony: true,\n computer: true,\n interface: true,\n} as const satisfies Record<MidsceneYamlTargetKey, true>;\n\nexport const midsceneYamlTargetKeys = Object.keys(\n midsceneYamlTargetKeyMap,\n) as MidsceneYamlTargetKey[];\n\n/**\n * Partial target settings applied to every script in a YAML batch.\n *\n * Batch settings are deep-merged over each script's target section, so every\n * nested target field is optional here even when a standalone script requires\n * it.\n */\nexport type MidsceneYamlTargetConfig = {\n [Target in MidsceneYamlTargetKey]?: Partial<\n NonNullable<MidsceneYamlScript[Target]>\n >;\n};\n\nexport interface MidsceneYamlFlowItemAIAction {\n // defined as aiAction for backward compatibility\n aiAction?: TUserPrompt | null;\n ai?: TUserPrompt | null; // this is the shortcut for aiAct\n aiAct?: TUserPrompt | null;\n instruction?: TUserPrompt;\n aiActionProgressTips?: string[];\n cacheable?: boolean;\n [key: string]: unknown;\n}\n\nexport interface MidsceneYamlFlowItemAIAssert extends ServiceExtractOption {\n aiAssert: string;\n errorMessage?: string;\n name?: string;\n}\n\nexport interface MidsceneYamlFlowItemAIWaitFor extends ServiceExtractOption {\n aiWaitFor: string;\n timeout?: number;\n}\n\nexport interface MidsceneYamlFlowItemRunGherkinScenario {\n runGherkinScenario: string;\n}\n\nexport interface MidsceneYamlFlowItemEvaluateJavaScript {\n javascript: string;\n name?: string;\n}\n\nexport interface MidsceneYamlFlowItemSleep {\n sleep: number;\n}\n\nexport interface MidsceneYamlFlowItemLogScreenshot {\n logScreenshot?: string; // optional, the title of the screenshot\n recordToReport?: string; // preferred key for record title\n content?: string;\n}\n\nexport type MidsceneYamlFlowItem =\n | MidsceneYamlFlowItemAIAction\n | MidsceneYamlFlowItemAIAssert\n | MidsceneYamlFlowItemAIWaitFor\n | MidsceneYamlFlowItemRunGherkinScenario\n | MidsceneYamlFlowItemEvaluateJavaScript\n | MidsceneYamlFlowItemSleep\n | MidsceneYamlFlowItemLogScreenshot;\n\nexport interface FreeFn {\n name: string;\n fn: () => void | Promise<void>;\n}\n\nexport interface ScriptPlayerTaskStatus extends MidsceneYamlTask {\n status: ScriptPlayerStatusValue;\n currentStep?: number;\n totalSteps: number;\n error?: Error;\n}\n\nexport type ScriptPlayerStatusValue = 'init' | 'running' | 'done' | 'error';\n\n// Index YAML file types for batch execution\nexport interface MidsceneYamlConfig extends MidsceneYamlTargetConfig {\n /** @deprecated Use `web`, `page`, or `browser` instead. */\n target?: Partial<MidsceneYamlScriptWebEnv>;\n concurrent?: number;\n continueOnError?: boolean;\n /**\n * Number of times to retry the complete YAML file after an execution\n * failure, including tasks that already passed. Defaults to 0 (no retry).\n */\n retry?: number;\n summary?: string;\n /**\n * Share one BrowserContext across Puppeteer Web YAML files, with a separate\n * Page per file. This is not supported by bridge mode or non-Web targets.\n */\n shareBrowserContext?: boolean;\n /**\n * A setup yaml file that runs before the main `files`. A setup failure aborts\n * the whole batch and the main files are marked as not executed. Puppeteer\n * Web setup requires `shareBrowserContext: true` to pass browser state to the\n * main files. Other targets run setup without browser-context sharing.\n */\n setup?: string;\n files: string[];\n headed?: boolean;\n keepWindow?: boolean;\n dotenvOverride?: boolean;\n dotenvDebug?: boolean;\n}\n\nexport interface MidsceneYamlConfigOutput {\n format?: 'json';\n path?: string;\n}\n\nexport type MidsceneYamlConfigResultType =\n | 'success'\n | 'failed'\n | 'partialFailed'\n | 'notExecuted';\n\nexport interface MidsceneYamlConfigAttempt {\n attempt: number;\n success: boolean;\n output?: string | null;\n report?: string | null;\n error?: string;\n duration?: number;\n resultType?: MidsceneYamlConfigResultType;\n /** Complete execution facts, persisted separately from the legacy summary. */\n executionRecordPath?: string;\n /** @internal Complete facts retained when the sidecar could not be published. */\n executionRecordFallback?: WorkflowExecutionRecord;\n /** @internal Infrastructure failures, separate from legacy execution status. */\n publicationErrors?: readonly unknown[];\n /** @internal Entry observation failed; action success remains unchanged. */\n observerErrors?: readonly unknown[];\n /** @internal Agent report generation or cleanup failed after execution. */\n infrastructureErrors?: readonly unknown[];\n}\n\nexport interface MidsceneYamlConfigResult {\n file: string;\n success: boolean;\n executed: boolean;\n output?: string | null;\n report?: string | null;\n retryReport?: string | null;\n attempts?: MidsceneYamlConfigAttempt[];\n executionRecordPath?: string;\n /** @internal Complete facts retained when the sidecar could not be published. */\n executionRecordFallback?: WorkflowExecutionRecord;\n /** @internal Infrastructure failures, separate from legacy execution status. */\n publicationErrors?: readonly unknown[];\n /** @internal Entry observation failed; action success remains unchanged. */\n observerErrors?: readonly unknown[];\n /** @internal Agent report generation or cleanup failed after execution. */\n infrastructureErrors?: readonly unknown[];\n error?: string;\n duration?: number;\n /**\n * Type of result:\n * - 'success': All tasks completed successfully\n * - 'failed': Execution failed (player error)\n * - 'partialFailed': Some tasks failed but execution continued (continueOnError)\n * - 'notExecuted': Not executed due to previous failures\n */\n resultType?: MidsceneYamlConfigResultType;\n}\n"],"names":["midsceneYamlTargetKeyMap","midsceneYamlTargetKeys","Object"],"mappings":"AAySA,MAAMA,2BAA2B;IAC/B,QAAQ;IACR,MAAM;IACN,SAAS;IACT,KAAK;IACL,SAAS;IACT,KAAK;IACL,SAAS;IACT,UAAU;IACV,WAAW;AACb;AAEO,MAAMC,yBAAyBC,OAAO,IAAI,CAC/CF"}
|
package/dist/lib/agent/agent.js
CHANGED
|
@@ -41,10 +41,15 @@ const service_caller_index_js_namespaceObject = require("../ai-model/service-cal
|
|
|
41
41
|
const external_constants_js_namespaceObject = require("../constants.js");
|
|
42
42
|
const external_js_yaml_namespaceObject = require("js-yaml");
|
|
43
43
|
var external_js_yaml_default = /*#__PURE__*/ __webpack_require__.n(external_js_yaml_namespaceObject);
|
|
44
|
+
const html_utils_js_namespaceObject = require("../dump/html-utils.js");
|
|
44
45
|
const external_screenshot_item_js_namespaceObject = require("../screenshot-item.js");
|
|
45
46
|
const external_service_index_js_namespaceObject = require("../service/index.js");
|
|
46
47
|
var external_service_index_js_default = /*#__PURE__*/ __webpack_require__.n(external_service_index_js_namespaceObject);
|
|
48
|
+
const resource_operations_js_namespaceObject = require("../test-runner/engine/resource-operations.js");
|
|
49
|
+
const agent_report_js_namespaceObject = require("../test-runner/reporting/agent-report.js");
|
|
50
|
+
const execution_record_js_namespaceObject = require("../test-runner/reporting/execution-record.js");
|
|
47
51
|
const external_types_js_namespaceObject = require("../types.js");
|
|
52
|
+
const execution_session_js_namespaceObject = require("../yaml/execution-session.js");
|
|
48
53
|
const external_report_generator_js_namespaceObject = require("../report-generator.js");
|
|
49
54
|
const external_utils_js_namespaceObject = require("../utils.js");
|
|
50
55
|
const external_yaml_index_js_namespaceObject = require("../yaml/index.js");
|
|
@@ -101,6 +106,60 @@ class Agent {
|
|
|
101
106
|
static getTestRunnerNodeDefinitions() {
|
|
102
107
|
return external_test_runner_nodes_js_namespaceObject.commonAgentTestRunnerNodeDefinitions;
|
|
103
108
|
}
|
|
109
|
+
_prepareForTestRunner() {
|
|
110
|
+
this.reportGenerator.enableSourceSnapshots?.();
|
|
111
|
+
}
|
|
112
|
+
async _createReportSource(scopeId) {
|
|
113
|
+
return this.reportGenerator.createSourceSnapshot?.(scopeId);
|
|
114
|
+
}
|
|
115
|
+
async _writeYamlExecutionReport(record) {
|
|
116
|
+
const existingIndex = this.yamlExecutionRecords.findIndex((entry)=>entry.runId === record.runId);
|
|
117
|
+
const recordIndex = existingIndex < 0 ? this.yamlExecutionRecords.length : existingIndex;
|
|
118
|
+
this.yamlExecutionRecords[recordIndex] = record;
|
|
119
|
+
try {
|
|
120
|
+
const path = await this.reportGenerator.writeRunnerReport?.(this.buildYamlReportInput(), this.yamlReportScopeId, this.getReportMeta());
|
|
121
|
+
this.reportFile = path ?? this.reportFile;
|
|
122
|
+
return path;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
this.yamlExecutionRecords[recordIndex] = Object.freeze({
|
|
125
|
+
...record,
|
|
126
|
+
status: 'failed',
|
|
127
|
+
reportError: error
|
|
128
|
+
});
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
buildYamlReportInput() {
|
|
133
|
+
const scopedRecords = this.yamlExecutionRecords.map((entry)=>({
|
|
134
|
+
...entry,
|
|
135
|
+
...entry.execution ? {
|
|
136
|
+
execution: {
|
|
137
|
+
document: {
|
|
138
|
+
...entry.execution.document,
|
|
139
|
+
reportScopeId: this.yamlReportScopeId
|
|
140
|
+
},
|
|
141
|
+
cases: entry.execution.cases.map((outcome)=>({
|
|
142
|
+
...outcome,
|
|
143
|
+
...outcome.run ? {
|
|
144
|
+
run: {
|
|
145
|
+
...outcome.run,
|
|
146
|
+
reportScopeId: this.yamlReportScopeId
|
|
147
|
+
}
|
|
148
|
+
} : {},
|
|
149
|
+
...outcome.attempts ? {
|
|
150
|
+
attempts: outcome.attempts.map((attempt)=>({
|
|
151
|
+
...attempt,
|
|
152
|
+
reportScopeId: this.yamlReportScopeId
|
|
153
|
+
}))
|
|
154
|
+
} : {}
|
|
155
|
+
}))
|
|
156
|
+
}
|
|
157
|
+
} : {}
|
|
158
|
+
}));
|
|
159
|
+
return (0, execution_record_js_namespaceObject.executionRecordsToReportInput)(scopedRecords, {
|
|
160
|
+
runId: this.yamlReportScopeId
|
|
161
|
+
});
|
|
162
|
+
}
|
|
104
163
|
get onDumpUpdate() {
|
|
105
164
|
return this.dumpUpdateListeners[0];
|
|
106
165
|
}
|
|
@@ -287,7 +346,21 @@ class Agent {
|
|
|
287
346
|
}
|
|
288
347
|
reportHTMLString(opt) {
|
|
289
348
|
if (external_constants_js_namespaceObject.IS_REPORT_BUILD) return '';
|
|
290
|
-
|
|
349
|
+
const dumpString = this.dumpDataString(opt);
|
|
350
|
+
if (!this.yamlExecutionRecords.length) return (0, external_utils_js_namespaceObject.reportHTMLContent)(dumpString);
|
|
351
|
+
const reportId = this.yamlReportScopeId;
|
|
352
|
+
const runnerDump = (0, agent_report_js_namespaceObject.buildAgentTestRunReportDump)(this.buildYamlReportInput(), this.dump, {
|
|
353
|
+
reportId,
|
|
354
|
+
scopeId: this.yamlReportScopeId,
|
|
355
|
+
sourcePath: this.reportFile ?? '<inline-agent-report>'
|
|
356
|
+
});
|
|
357
|
+
return `${(0, external_utils_js_namespaceObject.reportHTMLContent)({
|
|
358
|
+
dumpString,
|
|
359
|
+
attributes: {
|
|
360
|
+
'data-group-id': reportId,
|
|
361
|
+
'data-report-id': reportId
|
|
362
|
+
}
|
|
363
|
+
})}\n${(0, html_utils_js_namespaceObject.generateTestRunReportScriptTag)(runnerDump)}`;
|
|
291
364
|
}
|
|
292
365
|
writeOutActionDumps(executionDump) {
|
|
293
366
|
const exec = executionDump || this.lastExecutionDump;
|
|
@@ -297,6 +370,11 @@ class Agent {
|
|
|
297
370
|
}
|
|
298
371
|
this.reportFile = this.reportGenerator.getReportPath();
|
|
299
372
|
}
|
|
373
|
+
async flushReport() {
|
|
374
|
+
this.writeOutActionDumps();
|
|
375
|
+
await this.reportGenerator.flush();
|
|
376
|
+
return this.lastExecutionDump ? this.reportFile ?? void 0 : void 0;
|
|
377
|
+
}
|
|
300
378
|
getReportMeta() {
|
|
301
379
|
return {
|
|
302
380
|
groupName: this.dump.groupName,
|
|
@@ -316,9 +394,12 @@ class Agent {
|
|
|
316
394
|
}
|
|
317
395
|
async callActionInActionSpace(type, opt) {
|
|
318
396
|
debug('callActionInActionSpace', type, ',', opt);
|
|
397
|
+
const clonedActionParam = opt && 'object' == typeof opt && !Array.isArray(opt) ? {
|
|
398
|
+
...opt
|
|
399
|
+
} : opt || {};
|
|
319
400
|
const actionPlan = {
|
|
320
401
|
type: type,
|
|
321
|
-
param:
|
|
402
|
+
param: clonedActionParam,
|
|
322
403
|
thought: ''
|
|
323
404
|
};
|
|
324
405
|
debug('actionPlan', actionPlan);
|
|
@@ -482,7 +563,7 @@ class Agent {
|
|
|
482
563
|
const cachePrompt = (0, external_prompt_context_js_namespaceObject.buildPromptWithContext)(taskPrompt, aiActContext);
|
|
483
564
|
const effort = (()=>{
|
|
484
565
|
const resolvedEffort = opt?.effort ?? (opt?.deepThink === true ? 'deepThink' : 'balance');
|
|
485
|
-
if (opt?.effort !== void 0
|
|
566
|
+
if (opt?.effort !== void 0 && void 0 !== opt.deepThink) warn('When both "effort" and "deepThink" are provided, "effort" takes precedence.');
|
|
486
567
|
if ('fast' === resolvedEffort && 'custom' === planningModel.adapter.planning.kind) throw new Error(`The "fast" aiAct effort is not supported with custom planning adapters (modelFamily: ${planningModel.config.modelFamily ?? 'unknown'}).`);
|
|
487
568
|
if ('deepThink' === resolvedEffort && 'custom' === planningModel.adapter.planning.kind) {
|
|
488
569
|
warn(`The "deepThink" aiAct effort is not supported with custom planning adapters (modelFamily: ${planningModel.config.modelFamily ?? 'unknown'}). It will be ignored.`);
|
|
@@ -505,9 +586,20 @@ class Agent {
|
|
|
505
586
|
try {
|
|
506
587
|
await this.taskExecutor.loadYamlFlowAsPlanning(taskPrompt, yaml, internalReportDisplay);
|
|
507
588
|
debug('matched cache, will call .runYaml to run the action');
|
|
508
|
-
await
|
|
589
|
+
await (0, execution_session_js_namespaceObject.runInYamlExecutionContext)(async ()=>{
|
|
590
|
+
const replay = (0, execution_session_js_namespaceObject.enterYamlExecution)(this);
|
|
591
|
+
const leaveAction = abortSignal ? (0, execution_session_js_namespaceObject.enterYamlAction)(this, abortSignal) : void 0;
|
|
592
|
+
try {
|
|
593
|
+
await this.runYaml(yaml);
|
|
594
|
+
} finally{
|
|
595
|
+
leaveAction?.();
|
|
596
|
+
replay.finish();
|
|
597
|
+
}
|
|
598
|
+
});
|
|
509
599
|
return;
|
|
510
600
|
} catch (error) {
|
|
601
|
+
if (error instanceof execution_session_js_namespaceObject.YamlExecutionOwnershipError) throw error;
|
|
602
|
+
abortSignal?.throwIfAborted();
|
|
511
603
|
cachedYamlFailed = true;
|
|
512
604
|
warn(`cached aiAct plan failed, will replan and disable the stale cache: ${error instanceof Error ? error.message : String(error)}`);
|
|
513
605
|
}
|
|
@@ -635,6 +727,7 @@ class Agent {
|
|
|
635
727
|
return this.aiAct(...args);
|
|
636
728
|
}
|
|
637
729
|
async runYaml(yamlScriptContent) {
|
|
730
|
+
if (this.destroyed) throw new Error('Cannot run YAML using a destroyed Agent.');
|
|
638
731
|
const script = (0, external_yaml_index_js_namespaceObject.parseYamlScript)(yamlScriptContent, 'yaml');
|
|
639
732
|
const player = new external_yaml_index_js_namespaceObject.ScriptPlayer(script, async ()=>({
|
|
640
733
|
agent: this,
|
|
@@ -686,6 +779,7 @@ class Agent {
|
|
|
686
779
|
async destroy() {
|
|
687
780
|
if (this.destroyed) return;
|
|
688
781
|
this.destroyed = true;
|
|
782
|
+
await (0, resource_operations_js_namespaceObject.waitForResourceIdle)(this);
|
|
689
783
|
for (const observer of this.ownedObservers)try {
|
|
690
784
|
await observer.dispose();
|
|
691
785
|
} catch (error) {
|
|
@@ -705,8 +799,9 @@ class Agent {
|
|
|
705
799
|
this.resetDump();
|
|
706
800
|
if (interfaceDestroyError) throw interfaceDestroyError;
|
|
707
801
|
}
|
|
708
|
-
async sleep(ms) {
|
|
709
|
-
|
|
802
|
+
async sleep(ms, options) {
|
|
803
|
+
options?.abortSignal?.throwIfAborted();
|
|
804
|
+
await this.taskExecutor.sleep(ms, options?.abortSignal);
|
|
710
805
|
}
|
|
711
806
|
async recordToReport(title, opt) {
|
|
712
807
|
const now = Date.now();
|
|
@@ -870,6 +965,8 @@ class Agent {
|
|
|
870
965
|
_define_property(this, "dump", void 0);
|
|
871
966
|
_define_property(this, "reportFile", void 0);
|
|
872
967
|
_define_property(this, "reportFileName", void 0);
|
|
968
|
+
_define_property(this, "yamlReportScopeId", (0, utils_namespaceObject.uuid)());
|
|
969
|
+
_define_property(this, "yamlExecutionRecords", []);
|
|
873
970
|
_define_property(this, "taskExecutor", void 0);
|
|
874
971
|
_define_property(this, "opts", void 0);
|
|
875
972
|
_define_property(this, "dryMode", false);
|