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.
Files changed (113) hide show
  1. package/dist/ai/llmcalls/llmAction.js +49 -13
  2. package/dist/ai/llmcalls/parseLlmOputput.js +5 -5
  3. package/dist/ai/llmprompts/promptRegistry.js +4 -0
  4. package/dist/ai/llmprompts/systemPrompts/actionExtractorPrompt.js +39 -11
  5. package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtactors.js +6 -6
  6. package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtractor_Mob.js +32 -0
  7. package/dist/ai/llmprompts/systemPrompts/mobileKeywordExtractor.js +17 -8
  8. package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.d.ts +1 -0
  9. package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.js +22 -0
  10. package/dist/ai/llmprompts/systemPrompts/verifyActionExtractorPrompt.js +3 -1
  11. package/dist/ai/llmprompts/systemPrompts/visionPrompt.js +14 -6
  12. package/dist/ai/llmprompts/systemPrompts/visionPromptMobile.js +3 -0
  13. package/dist/ai/llmprompts/userPrompts/userPrompt.js +1 -0
  14. package/dist/automation/actions/executor.d.ts +4 -0
  15. package/dist/automation/actions/executor.js +20 -0
  16. package/dist/automation/actions/interaction/clear/clear.js +1 -1
  17. package/dist/automation/actions/interaction/clear/clearAndEnter.js +1 -1
  18. package/dist/automation/actions/interaction/click/click.js +10 -3
  19. package/dist/automation/actions/interaction/click/clickNtimes.js +1 -1
  20. package/dist/automation/actions/interaction/click/doubleClick.js +1 -1
  21. package/dist/automation/actions/interaction/click/rightClick.js +1 -1
  22. package/dist/automation/actions/interaction/elementlessActions/getOtp.d.ts +2 -0
  23. package/dist/automation/actions/interaction/elementlessActions/getOtp.js +101 -0
  24. package/dist/automation/actions/interaction/enterActions/enterInput.js +11 -6
  25. package/dist/automation/actions/interaction/enterActions/enterInputAndPress.js +2 -2
  26. package/dist/automation/actions/interaction/enterActions/enterusingJs.js +2 -2
  27. package/dist/automation/actions/interaction/enterActions/waitAndEnter.js +1 -1
  28. package/dist/automation/actions/interaction/upload/uploadfile.js +1 -1
  29. package/dist/automation/actions/interaction/verify/VerifyNavigateURL.js +38 -11
  30. package/dist/automation/actions/interface/FireFlinkResponseSchema.d.ts +12 -0
  31. package/dist/automation/actions/interface/FireFlinkResponseSchema.js +19 -3
  32. package/dist/automation/actions/interface/getOtpInterface.d.ts +15 -0
  33. package/dist/automation/actions/interface/getOtpInterface.js +2 -0
  34. package/dist/automation/browserSession/initiateBrowserSession.d.ts +1 -1
  35. package/dist/automation/browserSession/initiateBrowserSession.js +15 -7
  36. package/dist/automation/driverState.d.ts +2 -0
  37. package/dist/automation/driverState.js +4 -0
  38. package/dist/automation/mobileSession/initiateMobileSession.d.ts +4 -5
  39. package/dist/automation/mobileSession/initiateMobileSession.js +83 -19
  40. package/dist/core/constants/allAction.js +5 -1
  41. package/dist/core/constants/supportedActions.js +5 -2
  42. package/dist/core/interfaces/actionInterface.d.ts +4 -0
  43. package/dist/core/interfaces/browserConfigurationInterface.d.ts +0 -4
  44. package/dist/core/interfaces/browserConfigurationInterface.js +0 -1
  45. package/dist/core/interfaces/executionDetails.d.ts +6 -3
  46. package/dist/core/interfaces/fireflinkScriptPayloadInterface.d.ts +22 -16
  47. package/dist/core/interfaces/llmResponseInterface.d.ts +1 -0
  48. package/dist/core/interfaces/promptInterface.d.ts +1 -0
  49. package/dist/core/main/SessionManager.d.ts +9 -0
  50. package/dist/core/main/SessionManager.js +23 -0
  51. package/dist/core/main/actionHandlerFactory.js +261 -64
  52. package/dist/core/main/executionContext.d.ts +7 -1
  53. package/dist/core/main/executionContext.js +93 -3
  54. package/dist/core/main/runAutomationScript.d.ts +1 -0
  55. package/dist/core/main/runAutomationScript.js +912 -304
  56. package/dist/core/main/stepProcessor.js +7 -2
  57. package/dist/core/types/browserType.d.ts +3 -3
  58. package/dist/core/types/browserType.js +2 -2
  59. package/dist/core/types/messageType.d.ts +13 -0
  60. package/dist/core/types/messageType.js +15 -0
  61. package/dist/core/types/promptType.d.ts +2 -1
  62. package/dist/core/types/promptType.js +1 -0
  63. package/dist/domAnalysis/searchBest.js +15 -16
  64. package/dist/domAnalysis/simplifyAndFlatten.js +6 -4
  65. package/dist/fireflinkData/fireflinkLocators/getListOfLocators.d.ts +3 -0
  66. package/dist/fireflinkData/fireflinkLocators/getListOfLocators.js +23 -15
  67. package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.d.ts +3 -3
  68. package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.js +134 -118
  69. package/dist/fireflinkData/fireflinkLocators/types/locator.d.ts +11 -1
  70. package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.d.ts +1 -1
  71. package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.js +35 -9
  72. package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.d.ts +10 -10
  73. package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.js +56 -59
  74. package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.d.ts +1 -1
  75. package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.js +53 -29
  76. package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.d.ts +8 -8
  77. package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.js +113 -190
  78. package/dist/fireflinkData/fireflinkLocators/utils/xpath.d.ts +17 -26
  79. package/dist/fireflinkData/fireflinkLocators/utils/xpath.js +314 -786
  80. package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.d.ts +68 -70
  81. package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.js +498 -517
  82. package/dist/fireflinkData/fireflinkScript/appendScriptData.d.ts +1 -1
  83. package/dist/fireflinkData/fireflinkScript/appendScriptData.js +5 -8
  84. package/dist/fireflinkData/fireflinkScript/scriptGenrationData.d.ts +2 -2
  85. package/dist/fireflinkData/fireflinkScript/scriptGenrationData.js +17 -27
  86. package/dist/llmConfig/llmConfiguration.js +13 -6
  87. package/dist/service/api/fireflinkApi.service.d.ts +1 -1
  88. package/dist/service/api/fireflinkApi.service.js +1 -2
  89. package/dist/service/fireflink.service.d.ts +3 -3
  90. package/dist/service/fireflink.service.js +23 -21
  91. package/dist/service/kafka/fireflinkKafka.service.d.ts +1 -2
  92. package/dist/service/kafka/fireflinkKafka.service.js +6 -4
  93. package/dist/tests/test12.d.ts +0 -1
  94. package/dist/tests/test12.js +65 -78
  95. package/dist/tests/testkaf.d.ts +0 -1
  96. package/dist/tests/testkaf.js +51 -55
  97. package/dist/utils/InstancesDetails/getInstancesInfo.js +1 -1
  98. package/dist/utils/browserCap/capability.d.ts +5 -1
  99. package/dist/utils/browserCap/capability.js +91 -15
  100. package/dist/utils/helpers/domSanitizer.d.ts +1 -0
  101. package/dist/utils/helpers/domSanitizer.js +9 -0
  102. package/dist/utils/helpers/enterActionHelper.js +23 -4
  103. package/dist/utils/helpers/xpathcreation.js +2 -2
  104. package/dist/utils/javascript/jsFindElement.d.ts +1 -1
  105. package/dist/utils/javascript/jsFindElement.js +2 -2
  106. package/dist/utils/newTab/newTabTracker.js +18 -6
  107. package/dist/utils/workers/LocatorWorkerInterface.d.ts +22 -0
  108. package/dist/utils/workers/LocatorWorkerInterface.js +2 -0
  109. package/dist/utils/workers/LocatorWorkerPool.d.ts +13 -0
  110. package/dist/utils/workers/LocatorWorkerPool.js +89 -0
  111. package/dist/utils/workers/locatorWorker.d.ts +1 -0
  112. package/dist/utils/workers/locatorWorker.js +44 -0
  113. 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
- // import { encode } from '@toon-format/toon';
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
- async cleanup(context, domInfo, extractedRelevantDom, stepProcessor, fireflinkService, request, platform, driver) {
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
- if ((context?.session) || (context?.mobileSession)) {
50
- try {
51
- const platformHandlers = {
52
- android: async () => {
53
- if (driver?.sessionId) {
54
- await driver.deleteSession();
55
- logData_js_1.logger.info("Android session deleted successfully");
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
- await (platformHandlers[platform] ?? platformHandlers.web)();
82
+ else {
83
+ logData_js_1.logger.info("Local web session kept alive.");
84
+ }
85
+ }
76
86
  }
77
- catch {
78
- logData_js_1.logger.error("Browser session is deactivated");
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
- const context = new executionContext_js_1.ExecutionContext(request);
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
- const platform = request.platform.toLocaleLowerCase();
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
- logData_js_1.logger.info(`Service Provider --> ${aiInfo.serviceProvider} & Model --> ${aiInfo.model} `);
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
- try {
397
- if (stepAction == "Builtin_DragAndDropToElement") {
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
- let annotatedScreenshot;
526
- let bounds;
527
- if (action === "scroll") {
528
- throw new Error(`Scroll action failed element not found`, { cause: error });
529
- }
530
- if (platform === "web") {
531
- annotatedScreenshot = await (0, generateAnnotatedScreenshots_js_1.generateAnnotatedScreenshots)(driver);
532
- }
533
- else {
534
- domInfo = await (0, jsForAttributeInjection_js_2.getAnnotatedDOMForMobile)(driver);
535
- let VissionResult;
536
- if (platform === "android") {
537
- VissionResult = await (0, annotatedScreenshotMobile_js_1.annotateScreenshot)(driver, domInfo.dom);
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
- VissionResult = await (0, annotatedScreenshotMobile_js_1.annotateIosScreenshot)(driver, domInfo.dom);
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
- annotatedScreenshot = VissionResult.boxedImageBuffer;
543
- bounds = VissionResult.boxes;
544
- }
545
- if (platform == "web") {
546
- stepResultVision = await stepProcessor.getLLMResponse({
547
- platform: platform,
548
- type: promptType_js_1.PromptType.VISION_PROMPT,
549
- args: {
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
- type: promptType_js_1.PromptType.VISION_PROMPT,
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
- priorAndNextSteps
716
+ extractedDomJson: retryToonDom,
717
+ priorAndNextSteps,
561
718
  },
562
- input: { currentStep: step, annotatedScreenshot: annotatedScreenshot.secondary },
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
- else {
568
- stepResultVision = await stepProcessor.getLLMResponse({
569
- platform: platform,
570
- type: promptType_js_1.PromptType.VISION_PROMPT,
571
- args: {
572
- priorAndNextSteps
573
- },
574
- input: { currentStep: step, annotatedScreenshot: annotatedScreenshot },
575
- isVision: true
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 = stepResultVision.response.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(`vision unable to find element for step "${step}"`);
582
- if (platform === "web") {
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 == "android" || platform == "ios") {
588
- const index = Number(fireflinkIndex.split("-").pop());
589
- const box = bounds[index - 1];
590
- if (!box) {
591
- throw new Error(`No bounds found for index ${index}`, { cause: error });
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
- xpath = ele.getAttribute("ff-xpath");
602
- if (!xpath) {
603
- context.scriptAppender.setErrorNLP(stepAction);
604
- throw new Error(`Unable to resolve xpath for ${fireflinkIndex}`, { cause: error });
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
- domInfo = domInfo.dom;
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
- selector: xpath,
890
+ nlpName: stepResult.response.nlpName,
891
+ selector: selector,
616
892
  value: stepResult.response.inputText,
617
893
  fireflinkIndex,
618
- pageDOM: domInfo,
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 (await (0, isAlertPresent_js_1.isAlertPresent)(driver) != true) {
625
- if (action === "click") {
626
- await driver.executeScript(jsForToaster_js_1.TOAST_WATCHER_JS, []);
627
- await new Promise(resolve => setTimeout(resolve, 100));
628
- const postClickToastDetected = await driver.executeScript("return window.__toastDetected === true;", []);
629
- if (postClickToastDetected) {
630
- logData_js_1.logger.info(`Toast detected after click`);
631
- preCapturedDomInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOM)(driver);
632
- logData_js_1.logger.saveDOM(preCapturedDomInfo.dom, `toaster-dom-${stepCount}`);
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(`vision execution failed for step "${step}": ${error}`);
639
- throw error;
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.error === "Context Length Exceeded (400)" ||
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.scriptType,
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
- // logger.info('payload', payload)
694
- await context.scriptAppender.waitForAllSteps();
695
- this.KafkaPayload.topic = `Topic-FIREFLINK-api-requests-${request.env}`;
696
- this.KafkaPayload.message = {
697
- ...payload,
698
- stepData: context.scriptAppender.getData(),
699
- serverHost: request.serverHost
700
- };
701
- // delete payload.tokensConsumed;
702
- logData_js_1.logger.info(await fireflinkServiceInstance.produceMessageToKafka(this.KafkaPayload));
703
- logData_js_1.logger.info(`Message produced to Kafka topic ${JSON.stringify(this.KafkaPayload, null, 2)} successfully.`);
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
- await this.cleanup(context, domInfo, extractedRelevantDom, stepProcessor, fireflinkServiceInstance, request, platform, (await context.session.getCurrentDriver().catch(() => null)) ??
711
- (await context.mobileSession.getCurrentDriver().catch(() => null)));
1317
+ if (!keepSessionAlive) {
1318
+ await this.cleanup(context, domInfo, extractedRelevantDom, stepProcessor, fireflinkServiceInstance, request, platform);
1319
+ }
712
1320
  }
713
1321
  }
714
1322
  }