ff-automationv2 2.2.29 → 2.2.30
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/ai/llmcalls/llmAction.js +49 -13
- package/dist/ai/llmcalls/parseLlmOputput.js +5 -5
- package/dist/ai/llmprompts/promptRegistry.js +4 -0
- package/dist/ai/llmprompts/systemPrompts/actionExtractorPrompt.js +39 -11
- package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtactors.js +6 -6
- package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtractor_Mob.js +32 -0
- package/dist/ai/llmprompts/systemPrompts/mobileKeywordExtractor.js +17 -8
- package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.d.ts +1 -0
- package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.js +22 -0
- package/dist/ai/llmprompts/systemPrompts/verifyActionExtractorPrompt.js +3 -1
- package/dist/ai/llmprompts/systemPrompts/visionPrompt.js +14 -6
- package/dist/ai/llmprompts/systemPrompts/visionPromptMobile.js +3 -0
- package/dist/ai/llmprompts/userPrompts/userPrompt.js +1 -0
- package/dist/automation/actions/executor.d.ts +4 -0
- package/dist/automation/actions/executor.js +20 -0
- package/dist/automation/actions/interaction/clear/clear.js +1 -1
- package/dist/automation/actions/interaction/clear/clearAndEnter.js +1 -1
- package/dist/automation/actions/interaction/click/click.js +10 -3
- package/dist/automation/actions/interaction/click/clickNtimes.js +1 -1
- package/dist/automation/actions/interaction/click/doubleClick.js +1 -1
- package/dist/automation/actions/interaction/click/rightClick.js +1 -1
- package/dist/automation/actions/interaction/elementlessActions/getOtp.d.ts +2 -0
- package/dist/automation/actions/interaction/elementlessActions/getOtp.js +101 -0
- package/dist/automation/actions/interaction/enterActions/enterInput.js +11 -6
- package/dist/automation/actions/interaction/enterActions/enterInputAndPress.js +2 -2
- package/dist/automation/actions/interaction/enterActions/enterusingJs.js +2 -2
- package/dist/automation/actions/interaction/enterActions/waitAndEnter.js +1 -1
- package/dist/automation/actions/interaction/upload/uploadfile.js +1 -1
- package/dist/automation/actions/interaction/verify/VerifyNavigateURL.js +38 -11
- package/dist/automation/actions/interface/FireFlinkResponseSchema.d.ts +12 -0
- package/dist/automation/actions/interface/FireFlinkResponseSchema.js +19 -3
- package/dist/automation/actions/interface/getOtpInterface.d.ts +15 -0
- package/dist/automation/actions/interface/getOtpInterface.js +2 -0
- package/dist/automation/browserSession/initiateBrowserSession.d.ts +1 -1
- package/dist/automation/browserSession/initiateBrowserSession.js +15 -7
- package/dist/automation/driverState.d.ts +2 -0
- package/dist/automation/driverState.js +4 -0
- package/dist/automation/mobileSession/initiateMobileSession.d.ts +4 -5
- package/dist/automation/mobileSession/initiateMobileSession.js +83 -19
- package/dist/core/constants/allAction.js +5 -1
- package/dist/core/constants/supportedActions.js +5 -2
- package/dist/core/interfaces/actionInterface.d.ts +4 -0
- package/dist/core/interfaces/browserConfigurationInterface.d.ts +0 -4
- package/dist/core/interfaces/browserConfigurationInterface.js +0 -1
- package/dist/core/interfaces/executionDetails.d.ts +6 -3
- package/dist/core/interfaces/fireflinkScriptPayloadInterface.d.ts +22 -16
- package/dist/core/interfaces/llmResponseInterface.d.ts +1 -0
- package/dist/core/interfaces/promptInterface.d.ts +1 -0
- package/dist/core/main/SessionManager.d.ts +9 -0
- package/dist/core/main/SessionManager.js +23 -0
- package/dist/core/main/actionHandlerFactory.js +261 -64
- package/dist/core/main/executionContext.d.ts +7 -1
- package/dist/core/main/executionContext.js +93 -3
- package/dist/core/main/runAutomationScript.d.ts +1 -0
- package/dist/core/main/runAutomationScript.js +912 -304
- package/dist/core/main/stepProcessor.js +7 -2
- package/dist/core/types/browserType.d.ts +3 -3
- package/dist/core/types/browserType.js +2 -2
- package/dist/core/types/messageType.d.ts +13 -0
- package/dist/core/types/messageType.js +15 -0
- package/dist/core/types/promptType.d.ts +2 -1
- package/dist/core/types/promptType.js +1 -0
- package/dist/domAnalysis/searchBest.js +15 -16
- package/dist/domAnalysis/simplifyAndFlatten.js +6 -4
- package/dist/fireflinkData/fireflinkLocators/getListOfLocators.d.ts +3 -0
- package/dist/fireflinkData/fireflinkLocators/getListOfLocators.js +23 -15
- package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.d.ts +3 -3
- package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.js +134 -118
- package/dist/fireflinkData/fireflinkLocators/types/locator.d.ts +11 -1
- package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.d.ts +1 -1
- package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.js +35 -9
- package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.d.ts +10 -10
- package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.js +56 -59
- package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.d.ts +1 -1
- package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.js +53 -29
- package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.d.ts +8 -8
- package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.js +113 -190
- package/dist/fireflinkData/fireflinkLocators/utils/xpath.d.ts +17 -26
- package/dist/fireflinkData/fireflinkLocators/utils/xpath.js +314 -786
- package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.d.ts +68 -70
- package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.js +498 -517
- package/dist/fireflinkData/fireflinkScript/appendScriptData.d.ts +1 -1
- package/dist/fireflinkData/fireflinkScript/appendScriptData.js +5 -8
- package/dist/fireflinkData/fireflinkScript/scriptGenrationData.d.ts +2 -2
- package/dist/fireflinkData/fireflinkScript/scriptGenrationData.js +17 -27
- package/dist/llmConfig/llmConfiguration.js +13 -6
- package/dist/service/api/fireflinkApi.service.d.ts +1 -1
- package/dist/service/api/fireflinkApi.service.js +1 -2
- package/dist/service/fireflink.service.d.ts +3 -3
- package/dist/service/fireflink.service.js +23 -21
- package/dist/service/kafka/fireflinkKafka.service.d.ts +1 -2
- package/dist/service/kafka/fireflinkKafka.service.js +6 -4
- package/dist/tests/test12.d.ts +0 -1
- package/dist/tests/test12.js +65 -78
- package/dist/tests/testkaf.d.ts +0 -1
- package/dist/tests/testkaf.js +51 -55
- package/dist/utils/InstancesDetails/getInstancesInfo.js +1 -1
- package/dist/utils/browserCap/capability.d.ts +5 -1
- package/dist/utils/browserCap/capability.js +91 -15
- package/dist/utils/helpers/domSanitizer.d.ts +1 -0
- package/dist/utils/helpers/domSanitizer.js +9 -0
- package/dist/utils/helpers/enterActionHelper.js +23 -4
- package/dist/utils/helpers/xpathcreation.js +2 -2
- package/dist/utils/javascript/jsFindElement.d.ts +1 -1
- package/dist/utils/javascript/jsFindElement.js +2 -2
- package/dist/utils/newTab/newTabTracker.js +18 -6
- package/dist/utils/workers/LocatorWorkerInterface.d.ts +22 -0
- package/dist/utils/workers/LocatorWorkerInterface.js +2 -0
- package/dist/utils/workers/LocatorWorkerPool.d.ts +13 -0
- package/dist/utils/workers/LocatorWorkerPool.js +89 -0
- package/dist/utils/workers/locatorWorker.d.ts +1 -0
- package/dist/utils/workers/locatorWorker.js +44 -0
- package/package.json +3 -1
|
@@ -5,7 +5,6 @@ require("../../utils/sslConfig/apiCallPatch.js");
|
|
|
5
5
|
const platformContext_js_1 = require("../../utils/helpers/platformContext.js");
|
|
6
6
|
const llmConfiguration_js_1 = require("../../llmConfig/llmConfiguration.js");
|
|
7
7
|
const llmAction_js_1 = require("../../ai/llmcalls/llmAction.js");
|
|
8
|
-
const executionContext_js_1 = require("./executionContext.js");
|
|
9
8
|
const actionHandlerFactory_js_1 = require("../../core/main/actionHandlerFactory.js");
|
|
10
9
|
const stepProcessor_js_1 = require("./stepProcessor.js");
|
|
11
10
|
const fireflinkApi_service_js_1 = require("../../service/api/fireflinkApi.service.js");
|
|
@@ -29,8 +28,11 @@ const sameActionsHelper_js_1 = require("../../utils/helpers/sameActionsHelper.js
|
|
|
29
28
|
const node_console_1 = require("node:console");
|
|
30
29
|
const annotatedScreenshotMobile_js_1 = require("../../imageAnalysisMobile/annotatedScreenshotMobile.js");
|
|
31
30
|
const toon_1 = require("@toon-format/toon");
|
|
31
|
+
const messageType_js_1 = require("../types/messageType.js");
|
|
32
32
|
const platformSyntax_js_1 = require("../../utils/helpers/platformSyntax.js");
|
|
33
|
-
|
|
33
|
+
const driverState_js_1 = require("../../automation/driverState.js");
|
|
34
|
+
const SessionManager_js_1 = require("./SessionManager.js");
|
|
35
|
+
const domSanitizer_js_1 = require("../../utils/helpers/domSanitizer.js");
|
|
34
36
|
class AutomationRunner {
|
|
35
37
|
constructor() {
|
|
36
38
|
this.KafkaPayload = {};
|
|
@@ -41,43 +43,68 @@ class AutomationRunner {
|
|
|
41
43
|
static updateSessionTerminationInfo(testCaseId) {
|
|
42
44
|
AutomationRunner.sessionTerminationDetails[testCaseId] = true;
|
|
43
45
|
}
|
|
44
|
-
|
|
46
|
+
static normalizeScriptType(scriptType) {
|
|
47
|
+
const rawValue = (scriptType ?? "Web").trim();
|
|
48
|
+
if (!rawValue) {
|
|
49
|
+
return "Web";
|
|
50
|
+
}
|
|
51
|
+
const value = rawValue.toLowerCase();
|
|
52
|
+
if (value.includes("web") && value.includes("android")) {
|
|
53
|
+
return "Web";
|
|
54
|
+
}
|
|
55
|
+
if (value.includes("android") && value.includes("ios")) {
|
|
56
|
+
return "Android";
|
|
57
|
+
}
|
|
58
|
+
if (value.includes("android")) {
|
|
59
|
+
return "Android";
|
|
60
|
+
}
|
|
61
|
+
if (value.includes("ios")) {
|
|
62
|
+
return "iOS";
|
|
63
|
+
}
|
|
64
|
+
if (value.includes("web")) {
|
|
65
|
+
return "Web";
|
|
66
|
+
}
|
|
67
|
+
return "Web";
|
|
68
|
+
}
|
|
69
|
+
async cleanup(context, domInfo, extractedRelevantDom, stepProcessor, fireflinkService, request, platform) {
|
|
45
70
|
try {
|
|
46
71
|
logData_js_1.logger.info("Starting cleanup process...");
|
|
47
72
|
domInfo = null;
|
|
48
73
|
extractedRelevantDom = null;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
ios: async () => {
|
|
59
|
-
if (driver?.sessionId) {
|
|
60
|
-
logData_js_1.logger.info("iOS session is not deleted");
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
web: async () => {
|
|
64
|
-
if (request.isCloud) {
|
|
65
|
-
if (driver?.sessionId) {
|
|
66
|
-
await driver.deleteSession();
|
|
67
|
-
}
|
|
68
|
-
logData_js_1.logger.info("Cloud session closed");
|
|
69
|
-
}
|
|
70
|
-
if (driver?.sessionId) {
|
|
71
|
-
logData_js_1.logger.info("Still browser session is active, session id :", driver.sessionId);
|
|
72
|
-
}
|
|
74
|
+
try {
|
|
75
|
+
if (context?.session) {
|
|
76
|
+
const webDriver = await context.session.getCurrentDriver().catch(() => null);
|
|
77
|
+
if (webDriver?.sessionId) {
|
|
78
|
+
if (request.isCloud) {
|
|
79
|
+
await webDriver.deleteSession();
|
|
80
|
+
logData_js_1.logger.info("Cloud web session deleted successfully");
|
|
73
81
|
}
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
else {
|
|
83
|
+
logData_js_1.logger.info("Local web session kept alive.");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
76
86
|
}
|
|
77
|
-
|
|
78
|
-
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
logData_js_1.logger.error("Error closing Web session:", err);
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
if (context?.mobileSession) {
|
|
93
|
+
const mobileDriver = await context.mobileSession.getCurrentDriver().catch(() => null);
|
|
94
|
+
if (mobileDriver?.sessionId) {
|
|
95
|
+
if (platform === "ios") {
|
|
96
|
+
logData_js_1.logger.info("iOS session is not deleted");
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
await mobileDriver.deleteSession();
|
|
100
|
+
logData_js_1.logger.info("Mobile session deleted successfully");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
79
103
|
}
|
|
80
104
|
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
logData_js_1.logger.error("Error closing Mobile session:", err);
|
|
107
|
+
}
|
|
81
108
|
if (stepProcessor) {
|
|
82
109
|
stepProcessor.llm = null;
|
|
83
110
|
}
|
|
@@ -95,7 +122,12 @@ class AutomationRunner {
|
|
|
95
122
|
async run(request) {
|
|
96
123
|
const usedElementNames = [];
|
|
97
124
|
(0, logData_js_1.initLogger)(request.sessionPath);
|
|
125
|
+
request.type = request.platform;
|
|
126
|
+
request.platform = AutomationRunner.normalizeScriptType(request.platform);
|
|
98
127
|
logData_js_1.logger.info("User Given Step", request.userStory);
|
|
128
|
+
const data = JSON.parse(request.scriptName);
|
|
129
|
+
const hasMoreSteps = data.hasMoreSteps;
|
|
130
|
+
request.scriptName = data.automationScriptName;
|
|
99
131
|
if (request.isTerminate)
|
|
100
132
|
return AutomationRunner.updateSessionTerminationInfo(request.testCaseId);
|
|
101
133
|
AutomationRunner.sessionTerminationDetails[request.testCaseId] = request.isTerminate;
|
|
@@ -103,7 +135,10 @@ class AutomationRunner {
|
|
|
103
135
|
const fireflinkServiceInstance = new fireflink_service_js_1.fireflinkService(apiService, request.broker, request.sslConfig);
|
|
104
136
|
const instanceDetails = await fireflinkServiceInstance.runGetInstancesDetails(request.projectId, request.token, request.serverHost, request.licenseId);
|
|
105
137
|
const aiInfo = (0, getInstancesInfo_js_1.getAiInstanceInfo)(instanceDetails.responseObject);
|
|
106
|
-
|
|
138
|
+
let context = SessionManager_js_1.SessionManager.get(request);
|
|
139
|
+
if (!context) {
|
|
140
|
+
context = SessionManager_js_1.SessionManager.create(request);
|
|
141
|
+
}
|
|
107
142
|
const configProvider = new llmConfiguration_js_1.ServiceProviderProviderConfiguration();
|
|
108
143
|
const provider = await configProvider.getProvider(aiInfo);
|
|
109
144
|
let domInfo = null;
|
|
@@ -112,20 +147,27 @@ class AutomationRunner {
|
|
|
112
147
|
const llm = new llmAction_js_1.llmAction(aiInfo.apiKey, provider, aiInfo.model, aiInfo.visionApiKey, aiInfo.accountType, aiInfo.enterpriseConfigFile, aiInfo.serviceProvider);
|
|
113
148
|
let preCapturedDomInfo = null;
|
|
114
149
|
const stepProcessor = new stepProcessor_js_1.StepProcessor(llm);
|
|
115
|
-
|
|
150
|
+
let platform = context.activePlatform;
|
|
116
151
|
(0, platformContext_js_1.setPlatform)(platform);
|
|
117
152
|
const actionHandlers = (0, actionHandlerFactory_js_1.createActionHandlers)(context);
|
|
118
153
|
const domProcessor = new getRelaventElements_js_1.DomProcessingEngine();
|
|
119
154
|
let stepCount = 1;
|
|
120
155
|
const listOfSteps = request.userStory.map(step => String(step));
|
|
121
156
|
let driver;
|
|
122
|
-
if (listOfSteps.length == 0) {
|
|
157
|
+
if (listOfSteps.length == 0 && request?.aiExecutionAction !== "stopExecution") {
|
|
123
158
|
logData_js_1.logger.info(listOfSteps);
|
|
124
159
|
throw new Error("No executable manual steps were returned by the LLM.");
|
|
125
160
|
}
|
|
126
|
-
|
|
161
|
+
if (aiInfo.serviceProvider === "DefaultFireFlink") {
|
|
162
|
+
logData_js_1.logger.info('Service Provider --> DefaultFireFlink');
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
logData_js_1.logger.info(`Service Provider --> ${aiInfo.serviceProvider} and Model --> ${aiInfo.model}`);
|
|
166
|
+
}
|
|
127
167
|
const start_time = new Date().getTime();
|
|
128
|
-
for (const step of listOfSteps) {
|
|
168
|
+
for (const [index, step] of listOfSteps.entries()) {
|
|
169
|
+
platform = context.activePlatform;
|
|
170
|
+
(0, platformContext_js_1.setPlatform)(platform);
|
|
129
171
|
let stepResult;
|
|
130
172
|
let stepResultVision;
|
|
131
173
|
let stepAction;
|
|
@@ -135,10 +177,70 @@ class AutomationRunner {
|
|
|
135
177
|
let frameAction;
|
|
136
178
|
let iframeDomHtml = null;
|
|
137
179
|
let doc;
|
|
180
|
+
let pageDOM;
|
|
138
181
|
let beforeHandles = null;
|
|
182
|
+
let baseStepActionBeforeFallback;
|
|
183
|
+
const topic = request.topic;
|
|
184
|
+
const produceLiveLog = async (message) => {
|
|
185
|
+
await fireflinkServiceInstance.produceMessageToKafka(request.kafkaMessageKey, {
|
|
186
|
+
topic: topic, message: {
|
|
187
|
+
topic: "",
|
|
188
|
+
service: "",
|
|
189
|
+
chatId: "",
|
|
190
|
+
aiPromptPayload: {
|
|
191
|
+
display: false,
|
|
192
|
+
message: "",
|
|
193
|
+
messageId: "",
|
|
194
|
+
branchId: "",
|
|
195
|
+
userId: request.userId,
|
|
196
|
+
scriptId: "",
|
|
197
|
+
scriptType: "",
|
|
198
|
+
type: "logs",
|
|
199
|
+
sessionId: "",
|
|
200
|
+
licenseId: request.licenseId,
|
|
201
|
+
projectId: request.projectId,
|
|
202
|
+
liveLogs: {
|
|
203
|
+
executionId: request.kafkaMessageKey,
|
|
204
|
+
message,
|
|
205
|
+
messageType: messageType_js_1.MessageType.LiveLog.retry,
|
|
206
|
+
},
|
|
207
|
+
attachment: [],
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
};
|
|
139
212
|
try {
|
|
213
|
+
if (request?.aiExecutionAction === "stopExecution") {
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
140
216
|
if (AutomationRunner.getSessionTerminationInfo(request.testCaseId)) {
|
|
141
217
|
logData_js_1.logger.info(`Execution terminated successfully. Script: ${request.scriptName}, Test Case ID: ${request.testCaseId}`);
|
|
218
|
+
await fireflinkServiceInstance.produceMessageToKafka(request.kafkaMessageKey, {
|
|
219
|
+
topic: topic, message: {
|
|
220
|
+
topic: "",
|
|
221
|
+
service: "",
|
|
222
|
+
chatId: "",
|
|
223
|
+
aiPromptPayload: {
|
|
224
|
+
display: false,
|
|
225
|
+
message: "",
|
|
226
|
+
messageId: "",
|
|
227
|
+
branchId: "",
|
|
228
|
+
userId: request.userId,
|
|
229
|
+
scriptId: "",
|
|
230
|
+
scriptType: "",
|
|
231
|
+
type: "logs",
|
|
232
|
+
sessionId: "",
|
|
233
|
+
licenseId: request.licenseId,
|
|
234
|
+
projectId: request.projectId,
|
|
235
|
+
liveLogs: {
|
|
236
|
+
executionId: request.kafkaMessageKey,
|
|
237
|
+
message: "Execution terminated by the user",
|
|
238
|
+
messageType: messageType_js_1.MessageType.LiveLog.Termination,
|
|
239
|
+
},
|
|
240
|
+
attachment: [],
|
|
241
|
+
},
|
|
242
|
+
}
|
|
243
|
+
});
|
|
142
244
|
break;
|
|
143
245
|
}
|
|
144
246
|
logData_js_1.logger.info(`Processing step ${stepCount}: ${step}`);
|
|
@@ -151,7 +253,48 @@ class AutomationRunner {
|
|
|
151
253
|
args: { priorAndNextSteps },
|
|
152
254
|
input: { currentStep: step }
|
|
153
255
|
});
|
|
256
|
+
if (platform === "android" || platform === "ios") {
|
|
257
|
+
if (!driver) {
|
|
258
|
+
await context.initializeMobileDriver(result.response.keywords);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
await fireflinkServiceInstance.produceMessageToKafka(request.kafkaMessageKey, {
|
|
262
|
+
topic: topic, message: {
|
|
263
|
+
topic: "",
|
|
264
|
+
service: "",
|
|
265
|
+
chatId: "",
|
|
266
|
+
aiPromptPayload: {
|
|
267
|
+
display: false,
|
|
268
|
+
message: "",
|
|
269
|
+
messageId: "",
|
|
270
|
+
branchId: "",
|
|
271
|
+
userId: request.userId,
|
|
272
|
+
scriptId: "",
|
|
273
|
+
scriptType: "",
|
|
274
|
+
type: "logs",
|
|
275
|
+
sessionId: "",
|
|
276
|
+
licenseId: request.licenseId,
|
|
277
|
+
projectId: request.projectId,
|
|
278
|
+
liveLogs: {
|
|
279
|
+
executionId: request.kafkaMessageKey,
|
|
280
|
+
message: result.response.liveLog,
|
|
281
|
+
messageType: messageType_js_1.MessageType.LiveLog.Ongoing,
|
|
282
|
+
},
|
|
283
|
+
attachment: [],
|
|
284
|
+
},
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
logData_js_1.logger.info(`Message produced to Kafka topic - ${JSON.stringify({ messageType: messageType_js_1.MessageType.LiveLog.Ongoing })}`);
|
|
154
288
|
const action = result.response.action;
|
|
289
|
+
if (request.scenario && action === 'enter') {
|
|
290
|
+
const currentUserStoryStep = request.userStory[index];
|
|
291
|
+
if (currentUserStoryStep &&
|
|
292
|
+
currentUserStoryStep.length > 1 &&
|
|
293
|
+
typeof currentUserStoryStep[1] === 'string' &&
|
|
294
|
+
currentUserStoryStep[1].trim() == '') {
|
|
295
|
+
throw new Error(`Input is missing for the given step: ${currentUserStoryStep?.[0]}. Please provide the input.`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
155
298
|
if (action === 'notwebopenaction') {
|
|
156
299
|
throw new Error(`Selected platform is invalid for the step: ${step}`);
|
|
157
300
|
}
|
|
@@ -161,7 +304,85 @@ class AutomationRunner {
|
|
|
161
304
|
let handler = actionHandlers[action];
|
|
162
305
|
if (supportedActions_js_1.INPUTLESS_ACTIONS.includes(action)) {
|
|
163
306
|
logData_js_1.logger.info(result.response.keywords);
|
|
164
|
-
await handler({ keywords: result.response.keywords, step: step });
|
|
307
|
+
await handler({ keywords: result.response.keywords, step: step, driverSession: request.kafkaMessageKey });
|
|
308
|
+
stepCount++;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (action === "getOtp") {
|
|
312
|
+
stepResult = await stepProcessor.getLLMResponse({
|
|
313
|
+
platform: platform,
|
|
314
|
+
type: promptType_js_1.PromptType.FF_INSPECTOR,
|
|
315
|
+
args: {
|
|
316
|
+
stepAction: "getOtp",
|
|
317
|
+
extractedDomJson: null,
|
|
318
|
+
priorAndNextSteps,
|
|
319
|
+
isAlert: false,
|
|
320
|
+
isDrag: false
|
|
321
|
+
},
|
|
322
|
+
input: { currentStep: step }
|
|
323
|
+
});
|
|
324
|
+
const otpAction = platform === "android" || platform === "ios"
|
|
325
|
+
? sameActionsHelper_js_1.sameActionHelper[stepResult.response.nlpName] ||
|
|
326
|
+
stepResult.response.nlpName
|
|
327
|
+
: stepResult.response.nlpName;
|
|
328
|
+
handler = actionHandlers[otpAction];
|
|
329
|
+
await handler({
|
|
330
|
+
selector: stepResult.response.inputText,
|
|
331
|
+
timeFrom: stepResult.response.timeFrom,
|
|
332
|
+
waitTime: stepResult.response.waitTime,
|
|
333
|
+
activity: stepResult.response.activity,
|
|
334
|
+
otpExtractor: async (smsBody) => {
|
|
335
|
+
const llmRes = await stepProcessor.getLLMResponse({
|
|
336
|
+
platform: platform,
|
|
337
|
+
type: promptType_js_1.PromptType.OTP_EXTRACTOR,
|
|
338
|
+
args: {},
|
|
339
|
+
input: { smsBody }
|
|
340
|
+
});
|
|
341
|
+
if (llmRes.response?.otp) {
|
|
342
|
+
context.extractedOtp = llmRes.response.otp;
|
|
343
|
+
}
|
|
344
|
+
return llmRes.response;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
stepCount++;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (action === "getOtp") {
|
|
351
|
+
stepResult = await stepProcessor.getLLMResponse({
|
|
352
|
+
platform: platform,
|
|
353
|
+
type: promptType_js_1.PromptType.FF_INSPECTOR,
|
|
354
|
+
args: {
|
|
355
|
+
stepAction: "getOtp",
|
|
356
|
+
extractedDomJson: null,
|
|
357
|
+
priorAndNextSteps,
|
|
358
|
+
isAlert: false,
|
|
359
|
+
isDrag: false
|
|
360
|
+
},
|
|
361
|
+
input: { currentStep: step }
|
|
362
|
+
});
|
|
363
|
+
const otpAction = platform === "android" || platform === "ios"
|
|
364
|
+
? sameActionsHelper_js_1.sameActionHelper[stepResult.response.nlpName] ||
|
|
365
|
+
stepResult.response.nlpName
|
|
366
|
+
: stepResult.response.nlpName;
|
|
367
|
+
handler = actionHandlers[otpAction];
|
|
368
|
+
await handler({
|
|
369
|
+
selector: stepResult.response.inputText,
|
|
370
|
+
timeFrom: stepResult.response.timeFrom,
|
|
371
|
+
waitTime: stepResult.response.waitTime,
|
|
372
|
+
activity: stepResult.response.activity,
|
|
373
|
+
otpExtractor: async (smsBody) => {
|
|
374
|
+
const llmRes = await stepProcessor.getLLMResponse({
|
|
375
|
+
platform: platform,
|
|
376
|
+
type: promptType_js_1.PromptType.OTP_EXTRACTOR,
|
|
377
|
+
args: {},
|
|
378
|
+
input: { smsBody }
|
|
379
|
+
});
|
|
380
|
+
if (llmRes.response?.otp) {
|
|
381
|
+
context.extractedOtp = llmRes.response.otp;
|
|
382
|
+
}
|
|
383
|
+
return llmRes.response;
|
|
384
|
+
}
|
|
385
|
+
});
|
|
165
386
|
stepCount++;
|
|
166
387
|
continue;
|
|
167
388
|
}
|
|
@@ -222,13 +443,15 @@ class AutomationRunner {
|
|
|
222
443
|
logData_js_1.logger.info("Using pre-captured DOM from previous toaster detection");
|
|
223
444
|
domInfo = preCapturedDomInfo;
|
|
224
445
|
preCapturedDomInfo = null;
|
|
446
|
+
const parser = new jsdom_1.JSDOM((0, domSanitizer_js_1.sanitizeWebDom)(domInfo.dom));
|
|
447
|
+
doc = parser.window.document;
|
|
225
448
|
}
|
|
226
449
|
else {
|
|
227
450
|
try {
|
|
228
451
|
if (platform === "web") {
|
|
229
452
|
domInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOM)(driver);
|
|
230
453
|
logData_js_1.logger.saveDOM(domInfo.dom, `annotated-dom-${stepCount}`);
|
|
231
|
-
const parser = new jsdom_1.JSDOM(domInfo.dom);
|
|
454
|
+
const parser = new jsdom_1.JSDOM((0, domSanitizer_js_1.sanitizeWebDom)(domInfo.dom));
|
|
232
455
|
doc = parser.window.document;
|
|
233
456
|
}
|
|
234
457
|
else {
|
|
@@ -239,34 +462,6 @@ class AutomationRunner {
|
|
|
239
462
|
});
|
|
240
463
|
doc = parser.window.document;
|
|
241
464
|
}
|
|
242
|
-
if (platform === "web") {
|
|
243
|
-
extractedRelevantDom = await domProcessor.webProcess({
|
|
244
|
-
keywords: result.response.keywords,
|
|
245
|
-
rawDom: domInfo.dom,
|
|
246
|
-
stepCount: stepCount,
|
|
247
|
-
stepAction: action,
|
|
248
|
-
step: step,
|
|
249
|
-
platform: platform,
|
|
250
|
-
driver: driver
|
|
251
|
-
});
|
|
252
|
-
toonDom = (0, toon_1.encode)(extractedRelevantDom || []);
|
|
253
|
-
// logger.saveJSON(extractedRelevantDom, `relevant-dom-${stepCount}`);
|
|
254
|
-
logData_js_1.logger.saveText(toonDom, `relevant-dom-toon-${stepCount}`);
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
257
|
-
extractedRelevantDom = await domProcessor.mobileProcess({
|
|
258
|
-
keywords: result.response.keywords,
|
|
259
|
-
rawDom: domInfo.dom,
|
|
260
|
-
stepCount: stepCount,
|
|
261
|
-
stepAction: action,
|
|
262
|
-
step: step,
|
|
263
|
-
platform: platform,
|
|
264
|
-
driver: driver
|
|
265
|
-
});
|
|
266
|
-
toonDom = (0, toon_1.encode)(extractedRelevantDom || []);
|
|
267
|
-
// logger.saveJSON(extractedRelevantDom, `relevant-dom-Mob-${stepCount}`);
|
|
268
|
-
logData_js_1.logger.saveText(toonDom, `relevant-dom-toon-Mob-${stepCount}`);
|
|
269
|
-
}
|
|
270
465
|
}
|
|
271
466
|
catch (error) {
|
|
272
467
|
if (action == "verify") {
|
|
@@ -277,6 +472,44 @@ class AutomationRunner {
|
|
|
277
472
|
}
|
|
278
473
|
}
|
|
279
474
|
}
|
|
475
|
+
try {
|
|
476
|
+
if (platform === "web") {
|
|
477
|
+
extractedRelevantDom = await domProcessor.webProcess({
|
|
478
|
+
keywords: result.response.keywords,
|
|
479
|
+
rawDom: domInfo.dom,
|
|
480
|
+
stepCount: stepCount,
|
|
481
|
+
stepAction: action,
|
|
482
|
+
step: step,
|
|
483
|
+
platform: platform,
|
|
484
|
+
driver: driver
|
|
485
|
+
});
|
|
486
|
+
toonDom = (0, toon_1.encode)(extractedRelevantDom || []);
|
|
487
|
+
// logger.saveJSON(extractedRelevantDom, `relevant-dom-${stepCount}`);
|
|
488
|
+
logData_js_1.logger.saveText(toonDom, `relevant-dom-toon-${stepCount}`);
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
extractedRelevantDom = await domProcessor.mobileProcess({
|
|
492
|
+
keywords: result.response.keywords,
|
|
493
|
+
rawDom: domInfo.dom,
|
|
494
|
+
stepCount: stepCount,
|
|
495
|
+
stepAction: action,
|
|
496
|
+
step: step,
|
|
497
|
+
platform: platform,
|
|
498
|
+
driver: driver
|
|
499
|
+
});
|
|
500
|
+
toonDom = (0, toon_1.encode)(extractedRelevantDom || []);
|
|
501
|
+
// logger.saveJSON(extractedRelevantDom, `relevant-dom-Mob-${stepCount}`);
|
|
502
|
+
logData_js_1.logger.saveText(toonDom, `relevant-dom-toon-Mob-${stepCount}`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
catch (error) {
|
|
506
|
+
if (action == "verify") {
|
|
507
|
+
extractedRelevantDom = null;
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
throw error;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
280
513
|
if (action == "verify") {
|
|
281
514
|
stepResult = await stepProcessor.getLLMResponse({
|
|
282
515
|
platform: platform,
|
|
@@ -344,7 +577,7 @@ class AutomationRunner {
|
|
|
344
577
|
platform: platform,
|
|
345
578
|
type: promptType_js_1.PromptType.FF_INSPECTOR,
|
|
346
579
|
args: {
|
|
347
|
-
stepAction: action,
|
|
580
|
+
stepAction: action === "enterOtp" ? "enter" : action,
|
|
348
581
|
extractedDomJson: toonDom,
|
|
349
582
|
priorAndNextSteps,
|
|
350
583
|
isAlert: false,
|
|
@@ -358,6 +591,9 @@ class AutomationRunner {
|
|
|
358
591
|
else {
|
|
359
592
|
stepAction = stepResult.response.nlpName;
|
|
360
593
|
}
|
|
594
|
+
if ((action === "enterOtp" || stepAction === "enterOtp") && context.extractedOtp) {
|
|
595
|
+
stepResult.response.inputText = context.extractedOtp;
|
|
596
|
+
}
|
|
361
597
|
}
|
|
362
598
|
}
|
|
363
599
|
if (platform === "android" || platform === "ios") {
|
|
@@ -370,6 +606,9 @@ class AutomationRunner {
|
|
|
370
606
|
stepCount++;
|
|
371
607
|
continue;
|
|
372
608
|
}
|
|
609
|
+
if (platform === "web") {
|
|
610
|
+
beforeHandles = await driver.getWindowHandles();
|
|
611
|
+
}
|
|
373
612
|
if (supportedActions_js_1.ELEMENTLESS_ACTION.includes(stepAction)) {
|
|
374
613
|
let currentDriver = null;
|
|
375
614
|
let beforeHandles = null;
|
|
@@ -381,6 +620,26 @@ class AutomationRunner {
|
|
|
381
620
|
currentDriver = await context.mobileSession.getCurrentDriver();
|
|
382
621
|
}
|
|
383
622
|
handler = actionHandlers[stepAction];
|
|
623
|
+
if (stepAction == "getOtp") {
|
|
624
|
+
await handler({
|
|
625
|
+
selector: stepResult.response.inputText,
|
|
626
|
+
activity: stepResult.response.activity,
|
|
627
|
+
otpExtractor: async (smsBody) => {
|
|
628
|
+
const llmRes = await stepProcessor.getLLMResponse({
|
|
629
|
+
platform: platform,
|
|
630
|
+
type: promptType_js_1.PromptType.OTP_EXTRACTOR,
|
|
631
|
+
args: {},
|
|
632
|
+
input: { smsBody }
|
|
633
|
+
});
|
|
634
|
+
if (llmRes.response?.otp) {
|
|
635
|
+
context.extractedOtp = llmRes.response.otp;
|
|
636
|
+
}
|
|
637
|
+
return llmRes.response;
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
stepCount++;
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
384
643
|
await handler({
|
|
385
644
|
value: stepResult.response.inputText,
|
|
386
645
|
selector: stepResult.response.attributeValue,
|
|
@@ -393,260 +652,425 @@ class AutomationRunner {
|
|
|
393
652
|
stepCount++;
|
|
394
653
|
continue;
|
|
395
654
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
handler = actionHandlers[stepAction];
|
|
399
|
-
const fireflinkIndex1 = stepResult.response.drag;
|
|
400
|
-
const ele1 = doc.querySelector(`[ff-inspect="${fireflinkIndex1}"]`);
|
|
401
|
-
const selector1 = ele1?.getAttribute("ff-xpath");
|
|
402
|
-
const fireflinkIndex2 = stepResult.response.drop;
|
|
403
|
-
const ele2 = doc.querySelector(`[ff-inspect="${fireflinkIndex2}"]`);
|
|
404
|
-
const selector2 = ele2?.getAttribute("ff-xpath");
|
|
405
|
-
if (!selector2 && !selector1) {
|
|
406
|
-
throw new Error(`Unable to resolve xpath for ${fireflinkIndex2}`);
|
|
407
|
-
}
|
|
408
|
-
else if (fireflinkIndex2 == "Fire-Flink-0" && fireflinkIndex1 == "Fire-Flink-0") {
|
|
409
|
-
throw new Error(`Unable to find element for ${step}`);
|
|
410
|
-
}
|
|
411
|
-
await handler({
|
|
412
|
-
selector1: selector1,
|
|
413
|
-
selector2: selector2,
|
|
414
|
-
fireflinkIndex1: fireflinkIndex1,
|
|
415
|
-
fireflinkIndex2: fireflinkIndex2,
|
|
416
|
-
pageDOM: domInfo.dom,
|
|
417
|
-
elementName1: stepResult.response.drag_element_name,
|
|
418
|
-
elementName2: stepResult.response.drop_element_name,
|
|
419
|
-
elementType1: stepResult.response.drag_element_type,
|
|
420
|
-
elementType2: stepResult.response.drop_element_type
|
|
421
|
-
});
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
fireflinkIndex = stepResult.response.attributeValue;
|
|
425
|
-
if (fireflinkIndex == "Fire-Flink-0") {
|
|
426
|
-
logData_js_1.logger.error(`element not found for step "${step}"`);
|
|
427
|
-
throw new Error(`element not found for step "${step}"`, { cause: node_console_1.error });
|
|
428
|
-
}
|
|
429
|
-
if (platform === "web") {
|
|
430
|
-
const ele = doc.querySelector(`[ff-inspect="${fireflinkIndex}"]`);
|
|
431
|
-
if (ele) {
|
|
432
|
-
selector = ele.getAttribute("ff-xpath") || "";
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
const result = (0, xpathcreation_js_1.getWebXPathByFFIndex)(domInfo.dom, fireflinkIndex);
|
|
436
|
-
selector = result.xpathPath;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
else {
|
|
440
|
-
const result = await (0, xpathcreation_js_1.getFFIndexAndXPath)(domInfo.dom, fireflinkIndex);
|
|
441
|
-
selector = result.xpathPath;
|
|
442
|
-
}
|
|
443
|
-
if (!selector) {
|
|
444
|
-
logData_js_1.logger.info(`Unable to resolve xpath for ${fireflinkIndex}`);
|
|
445
|
-
throw new Error(`Unable to resolve xpath for ${fireflinkIndex}`, { cause: node_console_1.error });
|
|
446
|
-
}
|
|
447
|
-
if (platform === "web") {
|
|
448
|
-
beforeHandles = await driver.getWindowHandles();
|
|
449
|
-
}
|
|
450
|
-
if (selector.includes("shadow")) {
|
|
451
|
-
stepAction = stepAction + "_shadow";
|
|
452
|
-
logData_js_1.logger.info(stepAction);
|
|
453
|
-
}
|
|
454
|
-
else if (selector.includes("iframe")) {
|
|
455
|
-
frameAction = "switchToDefaultContent";
|
|
456
|
-
handler = actionHandlers[frameAction];
|
|
457
|
-
await handler({
|
|
458
|
-
driver: driver,
|
|
459
|
-
});
|
|
460
|
-
const result_if = await driver.executeAsyncScript(jsFindElement_js_1.Find_element_by_ff_js_script, [fireflinkIndex]);
|
|
461
|
-
if (!result_if?.success) {
|
|
462
|
-
logData_js_1.logger.info("Not found");
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
const { xpath_if, frames, iframe_dom_html } = result_if;
|
|
466
|
-
selector = xpath_if;
|
|
467
|
-
iframeDomHtml = iframe_dom_html;
|
|
468
|
-
frameAction = "switchToFrame";
|
|
469
|
-
handler = actionHandlers[frameAction];
|
|
470
|
-
await handler({
|
|
471
|
-
selector: selector,
|
|
472
|
-
frames: frames,
|
|
473
|
-
elementName: result.response.elementName,
|
|
474
|
-
elementType: stepResult.response.elementType,
|
|
475
|
-
pageDOM: domInfo.dom,
|
|
476
|
-
fireflinkIndex
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
if (selector.includes('svg')) {
|
|
480
|
-
const match = /svg\[(\d+)\]/.exec(selector);
|
|
481
|
-
const svgIndex = match ? match[1] : "1";
|
|
482
|
-
selector = selector.replace(/svg\[\d+\]/, `*[name()='svg'][${svgIndex}]`);
|
|
483
|
-
}
|
|
484
|
-
handler = actionHandlers[stepAction];
|
|
485
|
-
if (iframeDomHtml != null) {
|
|
486
|
-
domInfo = iframeDomHtml;
|
|
487
|
-
}
|
|
488
|
-
else {
|
|
489
|
-
domInfo = domInfo.dom;
|
|
490
|
-
}
|
|
491
|
-
// logger.info(`xpath ------>: ${selector}`)
|
|
492
|
-
await handler({
|
|
493
|
-
nlpName: stepResult.response.nlpName,
|
|
494
|
-
selector: selector,
|
|
495
|
-
value: stepResult.response.inputText,
|
|
496
|
-
fireflinkIndex,
|
|
497
|
-
pageDOM: domInfo,
|
|
498
|
-
elementName: result.response.elementName,
|
|
499
|
-
elementType: stepResult.response.elementType,
|
|
500
|
-
numOfScrolls: stepResult.response.numOfScrolls,
|
|
501
|
-
direction: stepResult.response.direction,
|
|
502
|
-
stepIndex: stepCount,
|
|
503
|
-
filteredSteps: listOfSteps,
|
|
504
|
-
attributeType: stepResult.response.attributeType,
|
|
505
|
-
});
|
|
506
|
-
if (platform === "web") {
|
|
507
|
-
if (await (0, isAlertPresent_js_1.isAlertPresent)(driver) != true) {
|
|
508
|
-
if (action === "click") {
|
|
509
|
-
await driver.executeScript(jsForToaster_js_1.TOAST_WATCHER_JS, []);
|
|
510
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
511
|
-
const postClickToastDetected = await driver.executeScript("return window.__toastDetected === true;", []);
|
|
512
|
-
if (postClickToastDetected) {
|
|
513
|
-
logData_js_1.logger.info(`Toast detected after click`);
|
|
514
|
-
preCapturedDomInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOM)(driver);
|
|
515
|
-
logData_js_1.logger.saveDOM(preCapturedDomInfo.dom, `toaster-dom-${stepCount}`);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
await (0, newTabTracker_js_1.newTabTracker)(driver, action, beforeHandles, context.scriptAppender);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
catch (error) {
|
|
523
|
-
logData_js_1.logger.error(`execution failed for step "${step}": ${error} and going for vision`);
|
|
655
|
+
baseStepActionBeforeFallback = stepAction;
|
|
656
|
+
for (let fallbackAttempt = 1; fallbackAttempt <= 2; fallbackAttempt++) {
|
|
524
657
|
try {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
658
|
+
if (fallbackAttempt > 1) {
|
|
659
|
+
logData_js_1.logger.info(`Waiting 5 seconds before retrying step "${step}". Attempt ${fallbackAttempt}`);
|
|
660
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
661
|
+
logData_js_1.logger.info(`Retrying step "${step}" after vision fallback failure. Attempt ${fallbackAttempt}`);
|
|
662
|
+
// if (result.response.liveLog) {
|
|
663
|
+
// await produceLiveLog(result.response.liveLog);
|
|
664
|
+
// }
|
|
665
|
+
stepAction = baseStepActionBeforeFallback;
|
|
666
|
+
selector = "";
|
|
667
|
+
xpath = "";
|
|
668
|
+
iframeDomHtml = null;
|
|
669
|
+
beforeHandles = null;
|
|
670
|
+
if (platform === "web") {
|
|
671
|
+
domInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOM)(driver);
|
|
672
|
+
logData_js_1.logger.saveDOM(domInfo.dom, `annotated-dom-retry-${stepCount}`);
|
|
673
|
+
const parser = new jsdom_1.JSDOM((0, domSanitizer_js_1.sanitizeWebDom)(domInfo.dom));
|
|
674
|
+
doc = parser.window.document;
|
|
538
675
|
}
|
|
539
676
|
else {
|
|
540
|
-
|
|
677
|
+
domInfo = await (0, jsForAttributeInjection_js_2.getAnnotatedDOMForMobile)(driver);
|
|
678
|
+
logData_js_1.logger.saveDOM(domInfo.dom, `annotated-dom-Mob-retry-${stepCount}`);
|
|
679
|
+
const parser = new jsdom_1.JSDOM(domInfo.dom, {
|
|
680
|
+
contentType: "text/xml"
|
|
681
|
+
});
|
|
682
|
+
doc = parser.window.document;
|
|
541
683
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
priorAndNextSteps
|
|
551
|
-
},
|
|
552
|
-
input: { currentStep: step, annotatedScreenshot: annotatedScreenshot.primary },
|
|
553
|
-
isVision: true
|
|
554
|
-
});
|
|
555
|
-
if (stepResultVision.response.fireflinkIndex == "Fire-Flink-0") {
|
|
556
|
-
stepResultVision = await stepProcessor.getLLMResponse({
|
|
684
|
+
let retryToonDom;
|
|
685
|
+
if (platform === "web") {
|
|
686
|
+
extractedRelevantDom = await domProcessor.webProcess({
|
|
687
|
+
keywords: result.response.keywords,
|
|
688
|
+
rawDom: domInfo.dom,
|
|
689
|
+
stepCount: stepCount,
|
|
690
|
+
stepAction: action,
|
|
691
|
+
step: step,
|
|
557
692
|
platform: platform,
|
|
558
|
-
|
|
693
|
+
driver: driver
|
|
694
|
+
});
|
|
695
|
+
retryToonDom = (0, toon_1.encode)(extractedRelevantDom || []);
|
|
696
|
+
logData_js_1.logger.saveText(retryToonDom, `relevant-dom-toon-retry-${stepCount}`);
|
|
697
|
+
}
|
|
698
|
+
else {
|
|
699
|
+
extractedRelevantDom = await domProcessor.mobileProcess({
|
|
700
|
+
keywords: result.response.keywords,
|
|
701
|
+
rawDom: domInfo.dom,
|
|
702
|
+
stepCount: stepCount,
|
|
703
|
+
stepAction: action,
|
|
704
|
+
step: step,
|
|
705
|
+
platform: platform,
|
|
706
|
+
driver: driver
|
|
707
|
+
});
|
|
708
|
+
retryToonDom = (0, toon_1.encode)(extractedRelevantDom || []);
|
|
709
|
+
logData_js_1.logger.saveText(retryToonDom, `relevant-dom-toon-Mob-retry-${stepCount}`);
|
|
710
|
+
}
|
|
711
|
+
if (action == "verify") {
|
|
712
|
+
stepResult = await stepProcessor.getLLMResponse({
|
|
713
|
+
platform: platform,
|
|
714
|
+
type: promptType_js_1.PromptType.VERIFY_PROMPT,
|
|
559
715
|
args: {
|
|
560
|
-
|
|
716
|
+
extractedDomJson: retryToonDom,
|
|
717
|
+
priorAndNextSteps,
|
|
561
718
|
},
|
|
562
|
-
input: { currentStep: step
|
|
563
|
-
isVision: true
|
|
719
|
+
input: { currentStep: step }
|
|
564
720
|
});
|
|
721
|
+
stepAction = stepResult.response.nlpName;
|
|
722
|
+
}
|
|
723
|
+
else if (action == "get") {
|
|
724
|
+
stepResult = await stepProcessor.getLLMResponse({
|
|
725
|
+
platform: platform,
|
|
726
|
+
type: promptType_js_1.PromptType.GET_PROMPT,
|
|
727
|
+
args: {
|
|
728
|
+
extractedDomJson: retryToonDom,
|
|
729
|
+
priorAndNextSteps,
|
|
730
|
+
},
|
|
731
|
+
input: { currentStep: step }
|
|
732
|
+
});
|
|
733
|
+
stepAction = stepResult.response.nlpName;
|
|
734
|
+
}
|
|
735
|
+
else if (action == "wait") {
|
|
736
|
+
stepResult = await stepProcessor.getLLMResponse({
|
|
737
|
+
platform: platform,
|
|
738
|
+
type: promptType_js_1.PromptType.WAIT_ACTION_EXTRACTOR_PROMPT,
|
|
739
|
+
args: {
|
|
740
|
+
extractedDomJson: retryToonDom,
|
|
741
|
+
priorAndNextSteps,
|
|
742
|
+
},
|
|
743
|
+
input: { currentStep: step }
|
|
744
|
+
});
|
|
745
|
+
stepAction = stepResult.response.nlpName;
|
|
746
|
+
}
|
|
747
|
+
else if (action == "combined") {
|
|
748
|
+
stepResult = await stepProcessor.getLLMResponse({
|
|
749
|
+
platform: platform,
|
|
750
|
+
type: promptType_js_1.PromptType.COMBINED_ACTION_EXTRACTOR_PROMPT,
|
|
751
|
+
args: {
|
|
752
|
+
extractedDomJson: retryToonDom,
|
|
753
|
+
priorAndNextSteps,
|
|
754
|
+
},
|
|
755
|
+
input: { currentStep: step }
|
|
756
|
+
});
|
|
757
|
+
stepAction = stepResult.response.nlpName;
|
|
758
|
+
}
|
|
759
|
+
else if (action == "drag_and_drop") {
|
|
760
|
+
stepResult = await stepProcessor.getLLMResponse({
|
|
761
|
+
platform: platform,
|
|
762
|
+
type: promptType_js_1.PromptType.FF_INSPECTOR,
|
|
763
|
+
args: {
|
|
764
|
+
extractedDomJson: retryToonDom,
|
|
765
|
+
priorAndNextSteps,
|
|
766
|
+
isDrag: true,
|
|
767
|
+
isAlert: false
|
|
768
|
+
},
|
|
769
|
+
input: { currentStep: step }
|
|
770
|
+
});
|
|
771
|
+
stepAction = stepResult.response.nlpName;
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
stepResult = await stepProcessor.getLLMResponse({
|
|
775
|
+
platform: platform,
|
|
776
|
+
type: promptType_js_1.PromptType.FF_INSPECTOR,
|
|
777
|
+
args: {
|
|
778
|
+
stepAction: action,
|
|
779
|
+
extractedDomJson: retryToonDom,
|
|
780
|
+
priorAndNextSteps,
|
|
781
|
+
isAlert: false,
|
|
782
|
+
isDrag: false
|
|
783
|
+
},
|
|
784
|
+
input: { currentStep: step }
|
|
785
|
+
});
|
|
786
|
+
stepAction = platform == "web"
|
|
787
|
+
? stepResult.response.action
|
|
788
|
+
: stepResult.response.nlpName;
|
|
789
|
+
}
|
|
790
|
+
if (platform === "android" || platform === "ios") {
|
|
791
|
+
stepAction = sameActionsHelper_js_1.sameActionHelper[stepAction] || stepAction;
|
|
565
792
|
}
|
|
566
793
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
794
|
+
if (stepAction == "Builtin_DragAndDropToElement") {
|
|
795
|
+
handler = actionHandlers[stepAction];
|
|
796
|
+
const fireflinkIndex1 = stepResult.response.drag;
|
|
797
|
+
const ele1 = doc.querySelector(`[ff-inspect="${fireflinkIndex1}"]`);
|
|
798
|
+
const selector1 = ele1?.getAttribute("ff-xpath");
|
|
799
|
+
const fireflinkIndex2 = stepResult.response.drop;
|
|
800
|
+
const ele2 = doc.querySelector(`[ff-inspect="${fireflinkIndex2}"]`);
|
|
801
|
+
const selector2 = ele2?.getAttribute("ff-xpath");
|
|
802
|
+
if (!selector2 && !selector1) {
|
|
803
|
+
throw new Error(`Unable to resolve xpath for ${fireflinkIndex2}`);
|
|
804
|
+
}
|
|
805
|
+
else if (fireflinkIndex2 == "Fire-Flink-0" && fireflinkIndex1 == "Fire-Flink-0") {
|
|
806
|
+
throw new Error(`Unable to find element for ${step}`);
|
|
807
|
+
}
|
|
808
|
+
await handler({
|
|
809
|
+
selector1: selector1,
|
|
810
|
+
selector2: selector2,
|
|
811
|
+
fireflinkIndex1: fireflinkIndex1,
|
|
812
|
+
fireflinkIndex2: fireflinkIndex2,
|
|
813
|
+
pageDOM: domInfo.dom,
|
|
814
|
+
elementName1: stepResult.response.drag_element_name,
|
|
815
|
+
elementName2: stepResult.response.drop_element_name,
|
|
816
|
+
elementType1: stepResult.response.drag_element_type,
|
|
817
|
+
elementType2: stepResult.response.drop_element_type
|
|
576
818
|
});
|
|
819
|
+
continue;
|
|
577
820
|
}
|
|
578
|
-
fireflinkIndex =
|
|
579
|
-
logData_js_1.logger.info(`fireflinkIndex: ${fireflinkIndex}`);
|
|
821
|
+
fireflinkIndex = stepResult.response.attributeValue;
|
|
580
822
|
if (fireflinkIndex == "Fire-Flink-0") {
|
|
581
|
-
logData_js_1.logger.error(`
|
|
582
|
-
|
|
583
|
-
context.scriptAppender.setErrorNLP(stepAction);
|
|
584
|
-
}
|
|
585
|
-
throw new Error(`vision unable to find element for step "${step}"`, { cause: error });
|
|
823
|
+
logData_js_1.logger.error(`element not found for step "${step}"`);
|
|
824
|
+
throw new Error(`element not found for step "${step}"`, { cause: node_console_1.error });
|
|
586
825
|
}
|
|
587
|
-
if (platform
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
826
|
+
if (platform === "web") {
|
|
827
|
+
if (!doc) {
|
|
828
|
+
logData_js_1.logger.info("doc is undefined. Rebuilding document from domInfo.");
|
|
829
|
+
if (!domInfo || !domInfo.dom) {
|
|
830
|
+
domInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOM)(driver);
|
|
831
|
+
}
|
|
832
|
+
const parser = new jsdom_1.JSDOM((0, domSanitizer_js_1.sanitizeWebDom)(domInfo.dom));
|
|
833
|
+
doc = parser.window.document;
|
|
592
834
|
}
|
|
593
|
-
const { x1, y1, x2, y2 } = box;
|
|
594
|
-
const boundsStr = `[${x1},${y1}][${x2},${y2}]`;
|
|
595
|
-
const result = (0, xpathcreation_js_1.getFFIndexAndXPath)(domInfo.dom, boundsStr, platform);
|
|
596
|
-
xpath = result.xpathPath;
|
|
597
|
-
fireflinkIndex = result.ffInspector ?? fireflinkIndex;
|
|
598
|
-
}
|
|
599
|
-
else {
|
|
600
835
|
const ele = doc.querySelector(`[ff-inspect="${fireflinkIndex}"]`);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
836
|
+
if (ele) {
|
|
837
|
+
selector = ele.getAttribute("ff-xpath") || "";
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
const result = (0, xpathcreation_js_1.getWebXPathByFFIndex)(domInfo.dom, fireflinkIndex);
|
|
841
|
+
selector = result.xpathPath;
|
|
605
842
|
}
|
|
606
|
-
}
|
|
607
|
-
if (iframeDomHtml != null) {
|
|
608
|
-
domInfo = iframeDomHtml;
|
|
609
843
|
}
|
|
610
844
|
else {
|
|
611
|
-
|
|
845
|
+
const result = await (0, xpathcreation_js_1.getFFIndexAndXPath)(domInfo.dom, fireflinkIndex);
|
|
846
|
+
selector = result.xpathPath;
|
|
612
847
|
}
|
|
848
|
+
if (!selector) {
|
|
849
|
+
logData_js_1.logger.info(`Unable to resolve xpath for ${fireflinkIndex}`);
|
|
850
|
+
throw new Error(`Unable to resolve xpath for ${fireflinkIndex}`, { cause: node_console_1.error });
|
|
851
|
+
}
|
|
852
|
+
if (selector.includes("shadow")) {
|
|
853
|
+
stepAction = stepAction + "_shadow";
|
|
854
|
+
logData_js_1.logger.info(stepAction);
|
|
855
|
+
}
|
|
856
|
+
else if (selector.includes("iframe")) {
|
|
857
|
+
frameAction = "switchToDefaultContent";
|
|
858
|
+
handler = actionHandlers[frameAction];
|
|
859
|
+
await handler({
|
|
860
|
+
driver: driver,
|
|
861
|
+
});
|
|
862
|
+
const result_if = await driver.executeAsyncScript(jsFindElement_js_1.Find_element_by_ff_js_script, [fireflinkIndex]);
|
|
863
|
+
if (!result_if?.success) {
|
|
864
|
+
logData_js_1.logger.info("Not found");
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
const { xpath_if, frames, iframe_dom_html } = result_if;
|
|
868
|
+
selector = xpath_if;
|
|
869
|
+
iframeDomHtml = iframe_dom_html;
|
|
870
|
+
frameAction = "switchToFrame";
|
|
871
|
+
handler = actionHandlers[frameAction];
|
|
872
|
+
await handler({
|
|
873
|
+
selector: selector,
|
|
874
|
+
frames: frames,
|
|
875
|
+
elementName: result.response.elementName,
|
|
876
|
+
elementType: stepResult.response.elementType,
|
|
877
|
+
pageDOM: domInfo.dom,
|
|
878
|
+
fireflinkIndex
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
if (selector.includes('svg')) {
|
|
882
|
+
const match = /svg\[(\d+)\]/.exec(selector);
|
|
883
|
+
const svgIndex = match ? match[1] : "1";
|
|
884
|
+
selector = selector.replace(/svg\[\d+\]/, `*[name()='svg'][${svgIndex}]`);
|
|
885
|
+
}
|
|
886
|
+
pageDOM = iframeDomHtml ?? domInfo.dom;
|
|
613
887
|
handler = actionHandlers[stepAction];
|
|
888
|
+
// logger.info(`xpath ------>: ${selector}`)
|
|
614
889
|
await handler({
|
|
615
|
-
|
|
890
|
+
nlpName: stepResult.response.nlpName,
|
|
891
|
+
selector: selector,
|
|
616
892
|
value: stepResult.response.inputText,
|
|
617
893
|
fireflinkIndex,
|
|
618
|
-
pageDOM:
|
|
894
|
+
pageDOM: pageDOM,
|
|
619
895
|
elementName: result.response.elementName,
|
|
620
896
|
elementType: stepResult.response.elementType,
|
|
897
|
+
numOfScrolls: stepResult.response.numOfScrolls,
|
|
898
|
+
direction: stepResult.response.direction,
|
|
621
899
|
stepIndex: stepCount,
|
|
622
|
-
filteredSteps: listOfSteps
|
|
900
|
+
filteredSteps: listOfSteps,
|
|
901
|
+
attributeType: stepResult.response.attributeType,
|
|
623
902
|
});
|
|
624
|
-
if (
|
|
625
|
-
if (
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
903
|
+
if (platform === "web") {
|
|
904
|
+
if (await (0, isAlertPresent_js_1.isAlertPresent)(driver) != true) {
|
|
905
|
+
if (action === "click") {
|
|
906
|
+
await driver.executeScript(jsForToaster_js_1.TOAST_WATCHER_JS, []);
|
|
907
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
908
|
+
const postClickToastDetected = await driver.executeScript("return window.__toastDetected === true;", []);
|
|
909
|
+
if (postClickToastDetected) {
|
|
910
|
+
logData_js_1.logger.info(`Toast detected after click`);
|
|
911
|
+
preCapturedDomInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOM)(driver);
|
|
912
|
+
logData_js_1.logger.saveDOM(preCapturedDomInfo.dom, `toaster-dom-${stepCount}`);
|
|
913
|
+
}
|
|
633
914
|
}
|
|
634
915
|
}
|
|
916
|
+
if (beforeHandles?.length > 0) {
|
|
917
|
+
await (0, newTabTracker_js_1.newTabTracker)(driver, action, beforeHandles, context.scriptAppender);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
if (fallbackAttempt === 2) {
|
|
921
|
+
await produceLiveLog("Retry successful. Moving on to the next step.");
|
|
635
922
|
}
|
|
923
|
+
break;
|
|
636
924
|
}
|
|
637
925
|
catch (error) {
|
|
638
|
-
logData_js_1.logger.error(`
|
|
639
|
-
|
|
926
|
+
logData_js_1.logger.error(`execution failed for step "${step}": ${error} and going for vision`);
|
|
927
|
+
try {
|
|
928
|
+
let annotatedScreenshot;
|
|
929
|
+
let bounds;
|
|
930
|
+
if (action === "scroll") {
|
|
931
|
+
throw new Error(`Scroll action failed element not found`, { cause: error });
|
|
932
|
+
}
|
|
933
|
+
if (platform === "web") {
|
|
934
|
+
annotatedScreenshot = await (0, generateAnnotatedScreenshots_js_1.generateAnnotatedScreenshots)(driver);
|
|
935
|
+
}
|
|
936
|
+
else {
|
|
937
|
+
domInfo = await (0, jsForAttributeInjection_js_2.getAnnotatedDOMForMobile)(driver);
|
|
938
|
+
let VissionResult;
|
|
939
|
+
if (platform === "android") {
|
|
940
|
+
VissionResult = await (0, annotatedScreenshotMobile_js_1.annotateScreenshot)(driver, domInfo.dom);
|
|
941
|
+
}
|
|
942
|
+
else {
|
|
943
|
+
VissionResult = await (0, annotatedScreenshotMobile_js_1.annotateIosScreenshot)(driver, domInfo.dom);
|
|
944
|
+
}
|
|
945
|
+
annotatedScreenshot = VissionResult.boxedImageBuffer;
|
|
946
|
+
bounds = VissionResult.boxes;
|
|
947
|
+
}
|
|
948
|
+
if (platform == "web") {
|
|
949
|
+
stepResultVision = await stepProcessor.getLLMResponse({
|
|
950
|
+
platform: platform,
|
|
951
|
+
type: promptType_js_1.PromptType.VISION_PROMPT,
|
|
952
|
+
args: {
|
|
953
|
+
priorAndNextSteps
|
|
954
|
+
},
|
|
955
|
+
input: { currentStep: step, annotatedScreenshot: annotatedScreenshot.primary },
|
|
956
|
+
isVision: true
|
|
957
|
+
});
|
|
958
|
+
if (stepResultVision.response.fireflinkIndex == "Fire-Flink-0") {
|
|
959
|
+
stepResultVision = await stepProcessor.getLLMResponse({
|
|
960
|
+
platform: platform,
|
|
961
|
+
type: promptType_js_1.PromptType.VISION_PROMPT,
|
|
962
|
+
args: {
|
|
963
|
+
priorAndNextSteps
|
|
964
|
+
},
|
|
965
|
+
input: { currentStep: step, annotatedScreenshot: annotatedScreenshot.secondary },
|
|
966
|
+
isVision: true
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
else {
|
|
971
|
+
stepResultVision = await stepProcessor.getLLMResponse({
|
|
972
|
+
platform: platform,
|
|
973
|
+
type: promptType_js_1.PromptType.VISION_PROMPT,
|
|
974
|
+
args: {
|
|
975
|
+
priorAndNextSteps
|
|
976
|
+
},
|
|
977
|
+
input: { currentStep: step, annotatedScreenshot: annotatedScreenshot },
|
|
978
|
+
isVision: true
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
fireflinkIndex = stepResultVision.response.fireflinkIndex;
|
|
982
|
+
logData_js_1.logger.info(`fireflinkIndex: ${fireflinkIndex}`);
|
|
983
|
+
if (fireflinkIndex == "Fire-Flink-0") {
|
|
984
|
+
logData_js_1.logger.error(`vision unable to find element for step "${step}"`);
|
|
985
|
+
if (platform === "web") {
|
|
986
|
+
context.scriptAppender.setErrorNLP(stepAction);
|
|
987
|
+
}
|
|
988
|
+
throw new Error(`vision unable to find element for step "${step}"`, { cause: error });
|
|
989
|
+
}
|
|
990
|
+
if (platform == "android" || platform == "ios") {
|
|
991
|
+
const index = Number(fireflinkIndex.split("-").pop());
|
|
992
|
+
const box = bounds[index - 1];
|
|
993
|
+
if (!box) {
|
|
994
|
+
throw new Error(`No bounds found for index ${index}`, { cause: error });
|
|
995
|
+
}
|
|
996
|
+
const { x1, y1, x2, y2 } = box;
|
|
997
|
+
const boundsStr = `[${x1},${y1}][${x2},${y2}]`;
|
|
998
|
+
const result = (0, xpathcreation_js_1.getFFIndexAndXPath)(domInfo.dom, boundsStr, platform);
|
|
999
|
+
xpath = result.xpathPath;
|
|
1000
|
+
fireflinkIndex = result.ffInspector ?? fireflinkIndex;
|
|
1001
|
+
}
|
|
1002
|
+
else {
|
|
1003
|
+
if (!domInfo || !domInfo.dom || !doc) {
|
|
1004
|
+
logData_js_1.logger.info("Re-fetching annotated DOM for vision fallback");
|
|
1005
|
+
domInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOM)(driver);
|
|
1006
|
+
const parser = new jsdom_1.JSDOM((0, domSanitizer_js_1.sanitizeWebDom)(domInfo.dom));
|
|
1007
|
+
doc = parser.window.document;
|
|
1008
|
+
}
|
|
1009
|
+
const ele = doc.querySelector(`[ff-inspect="${fireflinkIndex}"]`);
|
|
1010
|
+
if (ele) {
|
|
1011
|
+
xpath = ele.getAttribute("ff-xpath") || "";
|
|
1012
|
+
}
|
|
1013
|
+
else {
|
|
1014
|
+
const result = (0, xpathcreation_js_1.getWebXPathByFFIndex)(domInfo.dom, fireflinkIndex);
|
|
1015
|
+
xpath = result.xpathPath;
|
|
1016
|
+
}
|
|
1017
|
+
if (!xpath) {
|
|
1018
|
+
context.scriptAppender.setErrorNLP(stepAction);
|
|
1019
|
+
throw new Error(`Unable to resolve xpath for ${fireflinkIndex}`, { cause: error });
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
pageDOM = iframeDomHtml ?? domInfo.dom;
|
|
1023
|
+
handler = actionHandlers[stepAction];
|
|
1024
|
+
await handler({
|
|
1025
|
+
selector: xpath,
|
|
1026
|
+
value: stepResult.response.inputText,
|
|
1027
|
+
fireflinkIndex,
|
|
1028
|
+
pageDOM: pageDOM,
|
|
1029
|
+
elementName: result.response.elementName,
|
|
1030
|
+
elementType: stepResult.response.elementType,
|
|
1031
|
+
stepIndex: stepCount,
|
|
1032
|
+
filteredSteps: listOfSteps
|
|
1033
|
+
});
|
|
1034
|
+
if (platform === "web") {
|
|
1035
|
+
if (await (0, isAlertPresent_js_1.isAlertPresent)(driver) != true) {
|
|
1036
|
+
if (action === "click") {
|
|
1037
|
+
await driver.executeScript(jsForToaster_js_1.TOAST_WATCHER_JS, []);
|
|
1038
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
1039
|
+
const postClickToastDetected = await driver.executeScript("return window.__toastDetected === true;", []);
|
|
1040
|
+
if (postClickToastDetected) {
|
|
1041
|
+
logData_js_1.logger.info(`Toast detected after click`);
|
|
1042
|
+
preCapturedDomInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOM)(driver);
|
|
1043
|
+
logData_js_1.logger.saveDOM(preCapturedDomInfo.dom, `toaster-dom-${stepCount}`);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (beforeHandles?.length > 0) {
|
|
1048
|
+
await (0, newTabTracker_js_1.newTabTracker)(driver, action, beforeHandles, context.scriptAppender);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
if (fallbackAttempt === 2) {
|
|
1052
|
+
await produceLiveLog("Retry successful. Moving on to the next step.");
|
|
1053
|
+
}
|
|
1054
|
+
break;
|
|
1055
|
+
}
|
|
1056
|
+
catch (error) {
|
|
1057
|
+
logData_js_1.logger.error(`vision execution failed for step "${step}": ${error}`);
|
|
1058
|
+
if (fallbackAttempt < 2) {
|
|
1059
|
+
await produceLiveLog("Step failed to execute. Waiting a few seconds before reattempting the same step.");
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
throw error;
|
|
1063
|
+
}
|
|
640
1064
|
}
|
|
641
1065
|
}
|
|
1066
|
+
baseStepActionBeforeFallback = stepAction;
|
|
642
1067
|
domInfo = null;
|
|
643
1068
|
extractedRelevantDom = null;
|
|
644
1069
|
stepCount++;
|
|
645
1070
|
}
|
|
646
1071
|
catch (error) {
|
|
647
1072
|
logData_js_1.logger.error(`Error executing step "${step}":`, error);
|
|
648
|
-
if (error
|
|
649
|
-
error.error === "Rate Limit Exceeded (429)") {
|
|
1073
|
+
if (error?.error) {
|
|
650
1074
|
errorInfo.error = error.error;
|
|
651
1075
|
errorInfo.errorDescription = error.errorDescription;
|
|
652
1076
|
if (context.scriptAppender.getErrorNLP()) {
|
|
@@ -667,48 +1091,232 @@ class AutomationRunner {
|
|
|
667
1091
|
}
|
|
668
1092
|
logData_js_1.logger.info('execution time->', new Date().getTime() - start_time);
|
|
669
1093
|
const payload = {
|
|
670
|
-
scriptName: request.scriptName,
|
|
671
|
-
version: request.version,
|
|
1094
|
+
scriptName: request.scriptName ?? "SCRIPT_NAME",
|
|
672
1095
|
type: request.type,
|
|
673
|
-
scriptType: request.
|
|
1096
|
+
scriptType: request.type,
|
|
674
1097
|
projectId: request.projectId,
|
|
675
1098
|
testCaseId: request.testCaseId,
|
|
676
|
-
promptId: request.promptId,
|
|
677
1099
|
pageDetails: request.pageDetails,
|
|
678
|
-
generatedBy: request.generatedBy,
|
|
679
|
-
webSocketId: request.webSocketId,
|
|
680
1100
|
licenseType: request.licenseType,
|
|
681
1101
|
licenseId: request.licenseId,
|
|
682
1102
|
userId: request.userId,
|
|
683
1103
|
projectType: request.projectType,
|
|
684
|
-
// serviceProvider: aiInfo.serviceProvider,
|
|
685
|
-
// model: aiInfo.model,
|
|
686
1104
|
platform: (0, platformSyntax_js_1.getPlatformSyntax)(platform),
|
|
687
1105
|
tokensConsumed: (await stepProcessor.getResultTokenUsage()).totalTokens,
|
|
688
|
-
...(errorInfo && Object.keys(errorInfo).length > 0
|
|
689
|
-
? { error: errorInfo }
|
|
690
|
-
: {})
|
|
691
1106
|
};
|
|
1107
|
+
this.KafkaPayload.topic = request.topic;
|
|
1108
|
+
let keepSessionAlive = false;
|
|
692
1109
|
try {
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
1110
|
+
if ((errorInfo && Object.keys(errorInfo).length > 0)) {
|
|
1111
|
+
await fireflinkServiceInstance.produceMessageToKafka(request.kafkaMessageKey, {
|
|
1112
|
+
topic: this.KafkaPayload.topic, message: {
|
|
1113
|
+
topic: "",
|
|
1114
|
+
service: "",
|
|
1115
|
+
chatId: "",
|
|
1116
|
+
aiPromptPayload: {
|
|
1117
|
+
display: false,
|
|
1118
|
+
message: "",
|
|
1119
|
+
messageId: "",
|
|
1120
|
+
branchId: "",
|
|
1121
|
+
userId: request.userId,
|
|
1122
|
+
scriptId: "",
|
|
1123
|
+
scriptType: "",
|
|
1124
|
+
type: "logs",
|
|
1125
|
+
sessionId: "",
|
|
1126
|
+
licenseId: request.licenseId,
|
|
1127
|
+
projectId: request.projectId,
|
|
1128
|
+
liveLogs: {
|
|
1129
|
+
executionId: request.kafkaMessageKey,
|
|
1130
|
+
message: errorInfo.errorDescription ?? "errorDescription unknown",
|
|
1131
|
+
messageType: messageType_js_1.MessageType.LiveLog.Error,
|
|
1132
|
+
},
|
|
1133
|
+
attachment: [],
|
|
1134
|
+
},
|
|
1135
|
+
}
|
|
1136
|
+
});
|
|
1137
|
+
logData_js_1.logger.info(`Message produced to Kafka topic - ${JSON.stringify({ messageType: messageType_js_1.MessageType.LiveLog.Error })}`);
|
|
1138
|
+
await context.scriptAppender.waitForAllSteps();
|
|
1139
|
+
if (driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey]) {
|
|
1140
|
+
driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey].push(...context.scriptAppender.getData());
|
|
1141
|
+
}
|
|
1142
|
+
else {
|
|
1143
|
+
driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey] = context.scriptAppender.getData();
|
|
1144
|
+
}
|
|
1145
|
+
context.scriptAppender.reset();
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
else {
|
|
1149
|
+
if (request?.aiExecutionAction === "stopExecution") {
|
|
1150
|
+
await fireflinkServiceInstance.produceMessageToKafka(request.kafkaMessageKey, {
|
|
1151
|
+
topic: this.KafkaPayload.topic, message: {
|
|
1152
|
+
topic: "",
|
|
1153
|
+
service: "",
|
|
1154
|
+
chatId: "",
|
|
1155
|
+
aiPromptPayload: {
|
|
1156
|
+
display: false,
|
|
1157
|
+
message: "",
|
|
1158
|
+
messageId: "",
|
|
1159
|
+
branchId: "",
|
|
1160
|
+
userId: request.userId,
|
|
1161
|
+
scriptId: "",
|
|
1162
|
+
scriptType: "",
|
|
1163
|
+
type: "logs",
|
|
1164
|
+
sessionId: "",
|
|
1165
|
+
licenseId: request.licenseId,
|
|
1166
|
+
projectId: request.projectId,
|
|
1167
|
+
liveLogs: {
|
|
1168
|
+
executionId: request.kafkaMessageKey,
|
|
1169
|
+
message: "Execution stopped",
|
|
1170
|
+
messageType: messageType_js_1.MessageType.LiveLog.ExecutionStopped,
|
|
1171
|
+
},
|
|
1172
|
+
attachment: [],
|
|
1173
|
+
},
|
|
1174
|
+
}
|
|
1175
|
+
});
|
|
1176
|
+
logData_js_1.logger.info(`Message produced to Kafka topic - ${JSON.stringify({ messageType: messageType_js_1.MessageType.LiveLog.ExecutionStopped })}`);
|
|
1177
|
+
}
|
|
1178
|
+
else if (hasMoreSteps) {
|
|
1179
|
+
keepSessionAlive = true;
|
|
1180
|
+
await fireflinkServiceInstance.produceMessageToKafka(request.kafkaMessageKey, {
|
|
1181
|
+
topic: this.KafkaPayload.topic, message: {
|
|
1182
|
+
topic: "",
|
|
1183
|
+
service: "",
|
|
1184
|
+
chatId: "",
|
|
1185
|
+
aiPromptPayload: {
|
|
1186
|
+
display: false,
|
|
1187
|
+
message: "",
|
|
1188
|
+
messageId: "",
|
|
1189
|
+
branchId: "",
|
|
1190
|
+
userId: request.userId,
|
|
1191
|
+
scriptId: "",
|
|
1192
|
+
scriptType: "",
|
|
1193
|
+
type: "logs",
|
|
1194
|
+
sessionId: "",
|
|
1195
|
+
licenseId: request.licenseId,
|
|
1196
|
+
projectId: request.projectId,
|
|
1197
|
+
liveLogs: {
|
|
1198
|
+
executionId: request.kafkaMessageKey,
|
|
1199
|
+
message: "Invoke the generate_script_from_scenario tool with the remaining test steps to continue the automation execution from where it left off.",
|
|
1200
|
+
messageType: messageType_js_1.MessageType.nextBatch,
|
|
1201
|
+
},
|
|
1202
|
+
attachment: [],
|
|
1203
|
+
},
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
1206
|
+
logData_js_1.logger.info(`Message produced to Kafka topic - ${JSON.stringify({ messageType: messageType_js_1.MessageType.nextBatch })}`);
|
|
1207
|
+
await context.scriptAppender.waitForAllSteps();
|
|
1208
|
+
if (driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey]) {
|
|
1209
|
+
driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey].push(...context.scriptAppender.getData());
|
|
1210
|
+
}
|
|
1211
|
+
else {
|
|
1212
|
+
driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey] = context.scriptAppender.getData();
|
|
1213
|
+
}
|
|
1214
|
+
context.scriptAppender.reset();
|
|
1215
|
+
}
|
|
1216
|
+
else {
|
|
1217
|
+
await fireflinkServiceInstance.produceMessageToKafka(request.kafkaMessageKey, {
|
|
1218
|
+
topic: this.KafkaPayload.topic, message: {
|
|
1219
|
+
topic: "",
|
|
1220
|
+
service: "",
|
|
1221
|
+
chatId: "",
|
|
1222
|
+
aiPromptPayload: {
|
|
1223
|
+
display: false,
|
|
1224
|
+
message: "",
|
|
1225
|
+
messageId: "",
|
|
1226
|
+
branchId: "",
|
|
1227
|
+
userId: request.userId,
|
|
1228
|
+
scriptId: "",
|
|
1229
|
+
scriptType: "",
|
|
1230
|
+
type: "logs",
|
|
1231
|
+
sessionId: "",
|
|
1232
|
+
licenseId: request.licenseId,
|
|
1233
|
+
projectId: request.projectId,
|
|
1234
|
+
liveLogs: {
|
|
1235
|
+
executionId: request.kafkaMessageKey,
|
|
1236
|
+
message: "Execution completed",
|
|
1237
|
+
messageType: messageType_js_1.MessageType.LiveLog.Completed,
|
|
1238
|
+
},
|
|
1239
|
+
attachment: [],
|
|
1240
|
+
},
|
|
1241
|
+
}
|
|
1242
|
+
});
|
|
1243
|
+
logData_js_1.logger.info(`Message produced to Kafka topic - ${JSON.stringify({ messageType: messageType_js_1.MessageType.LiveLog.Completed })}`);
|
|
1244
|
+
await context.scriptAppender.waitForAllSteps();
|
|
1245
|
+
if (driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey]) {
|
|
1246
|
+
driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey].push(...context.scriptAppender.getData());
|
|
1247
|
+
}
|
|
1248
|
+
else {
|
|
1249
|
+
driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey] = context.scriptAppender.getData();
|
|
1250
|
+
}
|
|
1251
|
+
context.scriptAppender.reset();
|
|
1252
|
+
}
|
|
1253
|
+
// Intermediate batches must only emit nextBatch. Sending AutomationScriptMetaData
|
|
1254
|
+
// here races the chat consumer and is treated as a finished execution.
|
|
1255
|
+
if (!keepSessionAlive) {
|
|
1256
|
+
this.KafkaPayload.message = {
|
|
1257
|
+
...payload,
|
|
1258
|
+
executionId: request.kafkaMessageKey,
|
|
1259
|
+
liveLogs: messageType_js_1.MessageType.AutomationScriptMetaData,
|
|
1260
|
+
stepData: driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey],
|
|
1261
|
+
serverHost: request.serverHost,
|
|
1262
|
+
messageType: messageType_js_1.MessageType.AutomationScriptMetaData
|
|
1263
|
+
};
|
|
1264
|
+
// logger.info(` ${JSON.stringify(context.scriptAppender.getData(), null, 2)}`);
|
|
1265
|
+
await fireflinkServiceInstance.produceMessageToKafka(request.kafkaMessageKey, {
|
|
1266
|
+
topic: this.KafkaPayload.topic, message: {
|
|
1267
|
+
topic: "",
|
|
1268
|
+
service: "",
|
|
1269
|
+
chatId: "",
|
|
1270
|
+
aiPromptPayload: {
|
|
1271
|
+
display: false,
|
|
1272
|
+
message: "",
|
|
1273
|
+
messageId: "",
|
|
1274
|
+
branchId: "",
|
|
1275
|
+
userId: request.userId,
|
|
1276
|
+
scriptId: "",
|
|
1277
|
+
scriptType: "",
|
|
1278
|
+
type: "logs",
|
|
1279
|
+
sessionId: "",
|
|
1280
|
+
licenseId: request.licenseId,
|
|
1281
|
+
projectId: request.projectId,
|
|
1282
|
+
liveLogs: {
|
|
1283
|
+
executionId: request.kafkaMessageKey,
|
|
1284
|
+
message: this.KafkaPayload,
|
|
1285
|
+
messageType: messageType_js_1.MessageType.AutomationScriptMetaData,
|
|
1286
|
+
},
|
|
1287
|
+
attachment: [],
|
|
1288
|
+
},
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
const stepDataArr = this.KafkaPayload.message.stepData;
|
|
1292
|
+
const lastStep = Array.isArray(stepDataArr) && stepDataArr.length > 0
|
|
1293
|
+
? stepDataArr[stepDataArr.length - 1]
|
|
1294
|
+
: null;
|
|
1295
|
+
const closeStepNames = new Set([
|
|
1296
|
+
"CloseBrowser",
|
|
1297
|
+
"IOS_CloseApp",
|
|
1298
|
+
"MOB_CloseApp",
|
|
1299
|
+
]);
|
|
1300
|
+
if (lastStep && closeStepNames.has(lastStep.nlpName)) {
|
|
1301
|
+
SessionManager_js_1.SessionManager.remove(request);
|
|
1302
|
+
delete driverState_js_1.UserSessionAutomationTestCase[request.kafkaMessageKey];
|
|
1303
|
+
logData_js_1.logger.info("Deletion happened.");
|
|
1304
|
+
}
|
|
1305
|
+
logData_js_1.logger.info(`Final Message produced to Kafka topic ${JSON.stringify(this.KafkaPayload, null, 2)} successfully.`);
|
|
1306
|
+
}
|
|
1307
|
+
else {
|
|
1308
|
+
logData_js_1.logger.info("nextBatch produced; session kept alive for remaining steps.");
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
704
1311
|
}
|
|
705
1312
|
catch (error) {
|
|
706
1313
|
logData_js_1.logger.error("Failed to produce message :", logData_js_1.logger.getError(error));
|
|
707
1314
|
throw new Error("Failed to produce message :", { cause: error });
|
|
708
1315
|
}
|
|
709
1316
|
finally {
|
|
710
|
-
|
|
711
|
-
|
|
1317
|
+
if (!keepSessionAlive) {
|
|
1318
|
+
await this.cleanup(context, domInfo, extractedRelevantDom, stepProcessor, fireflinkServiceInstance, request, platform);
|
|
1319
|
+
}
|
|
712
1320
|
}
|
|
713
1321
|
}
|
|
714
1322
|
}
|