misoai-web 1.5.9 → 1.6.1

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 (60) hide show
  1. package/dist/es/agent.js +158 -54
  2. package/dist/es/agent.js.map +1 -1
  3. package/dist/es/bridge-mode-browser.js +3 -3
  4. package/dist/es/bridge-mode-browser.js.map +1 -1
  5. package/dist/es/bridge-mode.js +160 -56
  6. package/dist/es/bridge-mode.js.map +1 -1
  7. package/dist/es/chrome-extension.js +159 -55
  8. package/dist/es/chrome-extension.js.map +1 -1
  9. package/dist/es/index.js +159 -55
  10. package/dist/es/index.js.map +1 -1
  11. package/dist/es/midscene-playground.js +161 -57
  12. package/dist/es/midscene-playground.js.map +1 -1
  13. package/dist/es/midscene-server.js +4 -4
  14. package/dist/es/midscene-server.js.map +1 -1
  15. package/dist/es/playground.js +158 -54
  16. package/dist/es/playground.js.map +1 -1
  17. package/dist/es/playwright-report.js +1 -1
  18. package/dist/es/playwright-report.js.map +1 -1
  19. package/dist/es/playwright.js +159 -55
  20. package/dist/es/playwright.js.map +1 -1
  21. package/dist/es/puppeteer-agent-launcher.js +158 -54
  22. package/dist/es/puppeteer-agent-launcher.js.map +1 -1
  23. package/dist/es/puppeteer.js +158 -54
  24. package/dist/es/puppeteer.js.map +1 -1
  25. package/dist/es/utils.js +1 -1
  26. package/dist/es/utils.js.map +1 -1
  27. package/dist/es/yaml.js +1 -1
  28. package/dist/es/yaml.js.map +1 -1
  29. package/dist/lib/agent.js +158 -54
  30. package/dist/lib/agent.js.map +1 -1
  31. package/dist/lib/bridge-mode-browser.js +3 -3
  32. package/dist/lib/bridge-mode-browser.js.map +1 -1
  33. package/dist/lib/bridge-mode.js +160 -56
  34. package/dist/lib/bridge-mode.js.map +1 -1
  35. package/dist/lib/chrome-extension.js +159 -55
  36. package/dist/lib/chrome-extension.js.map +1 -1
  37. package/dist/lib/index.js +159 -55
  38. package/dist/lib/index.js.map +1 -1
  39. package/dist/lib/midscene-playground.js +161 -57
  40. package/dist/lib/midscene-playground.js.map +1 -1
  41. package/dist/lib/midscene-server.js +4 -4
  42. package/dist/lib/midscene-server.js.map +1 -1
  43. package/dist/lib/playground.js +158 -54
  44. package/dist/lib/playground.js.map +1 -1
  45. package/dist/lib/playwright-report.js +1 -1
  46. package/dist/lib/playwright-report.js.map +1 -1
  47. package/dist/lib/playwright.js +159 -55
  48. package/dist/lib/playwright.js.map +1 -1
  49. package/dist/lib/puppeteer-agent-launcher.js +158 -54
  50. package/dist/lib/puppeteer-agent-launcher.js.map +1 -1
  51. package/dist/lib/puppeteer.js +158 -54
  52. package/dist/lib/puppeteer.js.map +1 -1
  53. package/dist/lib/utils.js +1 -1
  54. package/dist/lib/utils.js.map +1 -1
  55. package/dist/lib/yaml.js +1 -1
  56. package/dist/lib/yaml.js.map +1 -1
  57. package/dist/types/agent.d.ts +8 -1
  58. package/dist/types/index.d.ts +1 -1
  59. package/dist/types/playwright.d.ts +1 -1
  60. package/package.json +18 -54
@@ -344,8 +344,8 @@ var ScriptPlayer = class {
344
344
  var import_js_yaml = __toESM(require("js-yaml"));
345
345
 
346
346
  // src/yaml/utils.ts
347
- var import_utils2 = require("misoai-shared/utils");
348
347
  var import_js_yaml2 = __toESM(require("js-yaml"));
348
+ var import_utils2 = require("misoai-shared/utils");
349
349
  function interpolateEnvVars(content) {
350
350
  return content.replace(/\$\{([^}]+)\}/g, (_, envVar) => {
351
351
  const value = process.env[envVar.trim()];
@@ -491,13 +491,13 @@ function paramStr(task) {
491
491
  }
492
492
 
493
493
  // src/common/utils.ts
494
+ var import_dayjs = __toESM(require("dayjs"));
494
495
  var import_ai_model = require("misoai-core/ai-model");
495
496
  var import_utils3 = require("misoai-core/utils");
496
497
  var import_env = require("misoai-shared/env");
497
498
  var import_extractor = require("misoai-shared/extractor");
498
499
  var import_img = require("misoai-shared/img");
499
500
  var import_utils4 = require("misoai-shared/utils");
500
- var import_dayjs = __toESM(require("dayjs"));
501
501
 
502
502
  // src/web-element.ts
503
503
  var WebElementInfo = class {
@@ -666,8 +666,12 @@ var WorkflowMemory = class {
666
666
  const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
667
667
  workflow.memory = [...memory];
668
668
  workflow.metadata.totalSteps = workflow.steps.length;
669
- workflow.metadata.completedSteps = workflow.steps.filter((s) => s.status === "completed").length;
670
- workflow.metadata.failedSteps = workflow.steps.filter((s) => s.status === "failed").length;
669
+ workflow.metadata.completedSteps = workflow.steps.filter(
670
+ (s) => s.status === "completed"
671
+ ).length;
672
+ workflow.metadata.failedSteps = workflow.steps.filter(
673
+ (s) => s.status === "failed"
674
+ ).length;
671
675
  this.workflows.set(workflowId, workflow);
672
676
  this.enforceRetentionPolicy();
673
677
  }
@@ -678,7 +682,9 @@ var WorkflowMemory = class {
678
682
  const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
679
683
  workflow.context = { ...workflow.context, ...context };
680
684
  if (context.currentStep) {
681
- const existingStep = workflow.steps.find((s) => s.stepName === context.currentStep);
685
+ const existingStep = workflow.steps.find(
686
+ (s) => s.stepName === context.currentStep
687
+ );
682
688
  if (!existingStep) {
683
689
  workflow.steps.push({
684
690
  stepId: `step_${workflow.steps.length + 1}`,
@@ -723,7 +729,9 @@ var WorkflowMemory = class {
723
729
  enforceRetentionPolicy() {
724
730
  const maxWorkflows = 10;
725
731
  if (this.workflows.size > maxWorkflows) {
726
- const sortedWorkflows = Array.from(this.workflows.entries()).sort(([, a], [, b]) => (b.metadata.endTime || b.metadata.startTime) - (a.metadata.endTime || a.metadata.startTime));
732
+ const sortedWorkflows = Array.from(this.workflows.entries()).sort(
733
+ ([, a], [, b]) => (b.metadata.endTime || b.metadata.startTime) - (a.metadata.endTime || a.metadata.startTime)
734
+ );
727
735
  const toDelete = sortedWorkflows.slice(maxWorkflows);
728
736
  toDelete.forEach(([workflowId]) => this.workflows.delete(workflowId));
729
737
  }
@@ -1462,7 +1470,9 @@ var PageTaskExecutor = class {
1462
1470
  */
1463
1471
  getPersistentExecutor() {
1464
1472
  if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
1465
- const previousMemory = this.workflowMemory.getWorkflowMemory(this.sessionContext.workflowId);
1473
+ const previousMemory = this.workflowMemory.getWorkflowMemory(
1474
+ this.sessionContext.workflowId
1475
+ );
1466
1476
  this.persistentExecutor = new import_misoai_core.Executor("Persistent Task Executor", {
1467
1477
  onTaskStart: this.onTaskStartCallback,
1468
1478
  initialMemory: previousMemory
@@ -1491,7 +1501,9 @@ var PageTaskExecutor = class {
1491
1501
  if (this.persistentExecutor) {
1492
1502
  this.persistentExecutor.clearMemory();
1493
1503
  }
1494
- this.workflowMemory.clearWorkflow(this.sessionContext.workflowId || "default");
1504
+ this.workflowMemory.clearWorkflow(
1505
+ this.sessionContext.workflowId || "default"
1506
+ );
1495
1507
  }
1496
1508
  /**
1497
1509
  * Mevcut hafızayı döndürür
@@ -1503,7 +1515,9 @@ var PageTaskExecutor = class {
1503
1515
  * İş akışı hafızasını döndürür
1504
1516
  */
1505
1517
  getWorkflowMemory() {
1506
- return this.workflowMemory.getWorkflowData(this.sessionContext.workflowId || "default");
1518
+ return this.workflowMemory.getWorkflowData(
1519
+ this.sessionContext.workflowId || "default"
1520
+ );
1507
1521
  }
1508
1522
  /**
1509
1523
  * Hafıza istatistiklerini döndürür
@@ -1511,7 +1525,13 @@ var PageTaskExecutor = class {
1511
1525
  getMemoryStats() {
1512
1526
  return this.persistentExecutor?.getMemoryStats() || {
1513
1527
  totalItems: 0,
1514
- analytics: { totalTasks: 0, memoryHits: 0, memoryMisses: 0, averageMemorySize: 0, memoryEffectiveness: 0 },
1528
+ analytics: {
1529
+ totalTasks: 0,
1530
+ memoryHits: 0,
1531
+ memoryMisses: 0,
1532
+ averageMemorySize: 0,
1533
+ memoryEffectiveness: 0
1534
+ },
1515
1535
  config: this.memoryConfig
1516
1536
  };
1517
1537
  }
@@ -1547,11 +1567,14 @@ var PageTaskExecutor = class {
1547
1567
  let taskExecutor;
1548
1568
  if (useMemory) {
1549
1569
  taskExecutor = this.getPersistentExecutor();
1550
- this.workflowMemory.updateWorkflowContext({
1551
- currentStep: title,
1552
- pageInfo: this.sessionContext.pageInfo,
1553
- timestamp: Date.now()
1554
- }, this.sessionContext.workflowId || "default");
1570
+ this.workflowMemory.updateWorkflowContext(
1571
+ {
1572
+ currentStep: title,
1573
+ pageInfo: this.sessionContext.pageInfo,
1574
+ timestamp: Date.now()
1575
+ },
1576
+ this.sessionContext.workflowId || "default"
1577
+ );
1555
1578
  } else {
1556
1579
  taskExecutor = new import_misoai_core.Executor(title, {
1557
1580
  onTaskStart: this.onTaskStartCallback
@@ -1849,9 +1872,15 @@ var PageTaskExecutor = class {
1849
1872
  }
1850
1873
  async waitFor(assertion, opt) {
1851
1874
  const description = `waitFor: ${assertion}`;
1852
- const taskExecutor = new import_misoai_core.Executor(taskTitleStr("WaitFor", description), {
1853
- onTaskStart: this.onTaskStartCallback
1854
- });
1875
+ const useMemory = true;
1876
+ let taskExecutor;
1877
+ if (useMemory) {
1878
+ taskExecutor = this.getPersistentExecutor();
1879
+ } else {
1880
+ taskExecutor = new import_misoai_core.Executor(taskTitleStr("WaitFor", description), {
1881
+ onTaskStart: this.onTaskStartCallback
1882
+ });
1883
+ }
1855
1884
  const { timeoutMs, checkIntervalMs } = opt;
1856
1885
  (0, import_utils6.assert)(assertion, "No assertion for waitFor");
1857
1886
  (0, import_utils6.assert)(timeoutMs, "No timeoutMs for waitFor");
@@ -1906,6 +1935,25 @@ var PageTaskExecutor = class {
1906
1935
  `waitFor timeout: ${errorThought}`
1907
1936
  );
1908
1937
  }
1938
+ /**
1939
+ * Hafızaya yeni bir öğe ekler
1940
+ */
1941
+ addToMemory(memoryItem) {
1942
+ if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
1943
+ const previousMemory = this.workflowMemory.getWorkflowMemory(
1944
+ this.sessionContext.workflowId
1945
+ );
1946
+ this.persistentExecutor = new import_misoai_core.Executor("Persistent Task Executor", {
1947
+ onTaskStart: this.onTaskStartCallback,
1948
+ initialMemory: previousMemory
1949
+ });
1950
+ }
1951
+ this.persistentExecutor.memoryStore?.add(memoryItem);
1952
+ this.persistentExecutor.memoryAnalytics?.recordMemoryOperation(
1953
+ "add",
1954
+ memoryItem
1955
+ );
1956
+ }
1909
1957
  };
1910
1958
 
1911
1959
  // src/common/plan-builder.ts
@@ -1993,14 +2041,14 @@ function buildPlans(type, locateParam, param) {
1993
2041
  var import_node_assert = __toESM(require("assert"));
1994
2042
  var import_node_fs2 = require("fs");
1995
2043
  var import_node_path2 = require("path");
2044
+ var import_js_yaml3 = __toESM(require("js-yaml"));
1996
2045
  var import_common2 = require("misoai-shared/common");
1997
2046
  var import_logger3 = require("misoai-shared/logger");
1998
2047
  var import_utils9 = require("misoai-shared/utils");
1999
- var import_js_yaml3 = __toESM(require("js-yaml"));
2000
2048
  var import_semver = __toESM(require("semver"));
2001
2049
 
2002
2050
  // package.json
2003
- var version = "1.5.8";
2051
+ var version = "1.6.1";
2004
2052
 
2005
2053
  // src/common/task-cache.ts
2006
2054
  var debug3 = (0, import_logger3.getDebug)("cache");
@@ -2211,7 +2259,10 @@ var PageAgent = class {
2211
2259
  }
2212
2260
  this.taskExecutor = new PageTaskExecutor(this.page, this.insight, {
2213
2261
  taskCache: this.taskCache,
2214
- onTaskStart: this.callbackOnTaskStartTip.bind(this)
2262
+ onTaskStart: this.callbackOnTaskStartTip.bind(this),
2263
+ memoryConfig: opts?.memoryConfig,
2264
+ sessionId: opts?.sessionId,
2265
+ workflowId: opts?.workflowId
2215
2266
  });
2216
2267
  this.dump = this.resetDump();
2217
2268
  this.reportFileName = reportFileName(
@@ -2292,22 +2343,28 @@ var PageAgent = class {
2292
2343
  const allThoughts = executor.tasks.filter((task) => task.thought).map((task) => task.thought);
2293
2344
  const allLocates = executor.tasks.filter((task) => task.locate).map((task) => task.locate);
2294
2345
  const allPlans = executor.tasks.filter((task) => task.param?.plans).map((task) => task.param?.plans);
2295
- const planningTasks = executor.tasks.filter((task) => task.type === "Planning");
2296
- const insightTasks = executor.tasks.filter((task) => task.type === "Insight");
2346
+ const planningTasks = executor.tasks.filter(
2347
+ (task) => task.type === "Planning"
2348
+ );
2349
+ const insightTasks = executor.tasks.filter(
2350
+ (task) => task.type === "Insight"
2351
+ );
2297
2352
  const actionTasks = executor.tasks.filter((task) => task.type === "Action");
2298
2353
  const planning = planningTasks.length > 0 ? {
2299
2354
  type: "Planning",
2300
- description: `Planning for task execution`,
2355
+ description: "Planning for task execution",
2301
2356
  steps: planningTasks.map((task) => task.thought || "Planning step")
2302
2357
  } : void 0;
2303
2358
  const insight = insightTasks.length > 0 ? {
2304
2359
  type: "Insight",
2305
- description: `Insight for task execution`,
2306
- elements: insightTasks.map((task) => task.thought || "Insight element")
2360
+ description: "Insight for task execution",
2361
+ elements: insightTasks.map(
2362
+ (task) => task.thought || "Insight element"
2363
+ )
2307
2364
  } : void 0;
2308
2365
  const action = actionTasks.length > 0 ? {
2309
2366
  type: "Action",
2310
- description: `Action for task execution`,
2367
+ description: "Action for task execution",
2311
2368
  result: lastTask?.output
2312
2369
  } : void 0;
2313
2370
  const actionDetails = executor.tasks.map((task) => ({
@@ -2641,7 +2698,10 @@ ${memoryContext}` : void 0;
2641
2698
  }
2642
2699
  const memoryContext = this.getMemoryAsContext();
2643
2700
  const assertionWithContext = currentUrl ? `For the page at URL "${currentUrl}", ${assertion}` : assertion;
2644
- const { output, executor } = await this.taskExecutor.assert(assertionWithContext, memoryContext);
2701
+ const { output, executor } = await this.taskExecutor.assert(
2702
+ assertionWithContext,
2703
+ memoryContext
2704
+ );
2645
2705
  const metadata = this.afterTaskRunning(executor, true);
2646
2706
  if (output && opt?.keepRawResponse) {
2647
2707
  return {
@@ -2662,6 +2722,7 @@ ${reasonMsg}`);
2662
2722
  }
2663
2723
  async aiCaptcha(options) {
2664
2724
  const { deepThink = false, autoDetectComplexity = true } = options || {};
2725
+ const memoryContext = this.getMemoryAsContext();
2665
2726
  let shouldUseDeepThink = deepThink;
2666
2727
  if (autoDetectComplexity && !deepThink) {
2667
2728
  const context = await this.getUIContext();
@@ -2679,7 +2740,10 @@ A complex CAPTCHA typically has one or more of these characteristics:
2679
2740
  Return only "complex" or "simple" based on your analysis.
2680
2741
  `;
2681
2742
  const complexityMsgs = [
2682
- { role: "system", content: "You are an AI assistant that analyzes screenshots to determine CAPTCHA complexity." },
2743
+ {
2744
+ role: "system",
2745
+ content: "You are an AI assistant that analyzes screenshots to determine CAPTCHA complexity."
2746
+ },
2683
2747
  {
2684
2748
  role: "user",
2685
2749
  content: [
@@ -2703,7 +2767,12 @@ Return only "complex" or "simple" based on your analysis.
2703
2767
  );
2704
2768
  const responseText = typeof complexityResult.content === "string" ? complexityResult.content.toLowerCase() : JSON.stringify(complexityResult.content).toLowerCase();
2705
2769
  shouldUseDeepThink = responseText.includes("complex");
2706
- debug4("CAPTCHA complexity analysis:", responseText, "Using deep think:", shouldUseDeepThink);
2770
+ debug4(
2771
+ "CAPTCHA complexity analysis:",
2772
+ responseText,
2773
+ "Using deep think:",
2774
+ shouldUseDeepThink
2775
+ );
2707
2776
  } catch (error) {
2708
2777
  debug4("Failed to analyze CAPTCHA complexity:", error);
2709
2778
  }
@@ -2720,7 +2789,9 @@ Return only "complex" or "simple" based on your analysis.
2720
2789
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
2721
2790
  } else if (action.type === "input" && action.value) {
2722
2791
  if (action.target) {
2723
- await this.aiInput(action.value, action.target, { deepThink: shouldUseDeepThink });
2792
+ await this.aiInput(action.value, action.target, {
2793
+ deepThink: shouldUseDeepThink
2794
+ });
2724
2795
  }
2725
2796
  } else if (action.type === "verify" && action.target) {
2726
2797
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
@@ -2732,7 +2803,9 @@ Return only "complex" or "simple" based on your analysis.
2732
2803
  if (action.coordinates) {
2733
2804
  const x = action.coordinates[0];
2734
2805
  const y = action.coordinates[1];
2735
- await this.aiTap(`element at coordinates (${x}, ${y})`, { deepThink: shouldUseDeepThink });
2806
+ await this.aiTap(`element at coordinates (${x}, ${y})`, {
2807
+ deepThink: shouldUseDeepThink
2808
+ });
2736
2809
  } else if (action.target) {
2737
2810
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
2738
2811
  }
@@ -2742,6 +2815,26 @@ Return only "complex" or "simple" based on your analysis.
2742
2815
  }
2743
2816
  }
2744
2817
  await new Promise((resolve2) => setTimeout(resolve2, 3e3));
2818
+ const captchaMemoryItem = {
2819
+ id: `captcha_${Date.now()}`,
2820
+ timestamp: Date.now(),
2821
+ taskType: "Action",
2822
+ summary: `Solved ${captchaResult.captchaType} CAPTCHA: ${captchaResult.thought}`,
2823
+ context: {
2824
+ url: await this.page.url?.() || "",
2825
+ captchaType: captchaResult.captchaType,
2826
+ actions: captchaResult.actions,
2827
+ deepThink: actualDeepThink
2828
+ },
2829
+ metadata: {
2830
+ executionTime: Date.now() - Date.now(),
2831
+ // Will be updated
2832
+ success: true,
2833
+ confidence: 0.9
2834
+ },
2835
+ tags: ["captcha", "action", captchaResult.captchaType]
2836
+ };
2837
+ this.taskExecutor.addToMemory(captchaMemoryItem);
2745
2838
  const metadata = {
2746
2839
  status: "finished",
2747
2840
  usage,
@@ -2758,10 +2851,15 @@ Return only "complex" or "simple" based on your analysis.
2758
2851
  }
2759
2852
  async aiWaitFor(assertion, opt) {
2760
2853
  const startTime = Date.now();
2761
- const { executor } = await this.taskExecutor.waitFor(assertion, {
2854
+ const memoryContext = this.getMemoryAsContext();
2855
+ const assertionWithContext = memoryContext ? `${assertion}
2856
+
2857
+ Previous workflow steps:
2858
+ ${memoryContext}` : assertion;
2859
+ const { executor } = await this.taskExecutor.waitFor(assertionWithContext, {
2762
2860
  timeoutMs: opt?.timeoutMs || 15 * 1e3,
2763
2861
  checkIntervalMs: opt?.checkIntervalMs || 3 * 1e3,
2764
- assertion
2862
+ assertion: assertionWithContext
2765
2863
  });
2766
2864
  const metadata = {
2767
2865
  status: executor.isInErrorState() ? "failed" : "finished",
@@ -2859,25 +2957,27 @@ ${errors}`);
2859
2957
  const executionDump = {
2860
2958
  name: screenshotTitle,
2861
2959
  description: content,
2862
- tasks: [{
2863
- type: "Screenshot",
2864
- subType: "log",
2865
- status: "finished",
2866
- executor: null,
2867
- param: {
2868
- title: screenshotTitle,
2869
- content
2870
- },
2871
- output: {
2872
- screenshot
2873
- },
2874
- thought: `Logged screenshot: ${screenshotTitle}`,
2875
- timing: {
2876
- start: Date.now(),
2877
- end: Date.now(),
2878
- cost: 0
2960
+ tasks: [
2961
+ {
2962
+ type: "Screenshot",
2963
+ subType: "log",
2964
+ status: "finished",
2965
+ executor: null,
2966
+ param: {
2967
+ title: screenshotTitle,
2968
+ content
2969
+ },
2970
+ output: {
2971
+ screenshot
2972
+ },
2973
+ thought: `Logged screenshot: ${screenshotTitle}`,
2974
+ timing: {
2975
+ start: Date.now(),
2976
+ end: Date.now(),
2977
+ cost: 0
2978
+ }
2879
2979
  }
2880
- }],
2980
+ ],
2881
2981
  sdkVersion: "1.0.0",
2882
2982
  logTime: Date.now(),
2883
2983
  model_name: "screenshot"
@@ -2929,7 +3029,9 @@ ${errors}`);
2929
3029
  totalTasks: stats.analytics.totalTasks,
2930
3030
  memoryHits: stats.analytics.memoryHits,
2931
3031
  memoryMisses: stats.analytics.memoryMisses,
2932
- memoryEffectiveness: Math.round(stats.analytics.memoryEffectiveness * 100),
3032
+ memoryEffectiveness: Math.round(
3033
+ stats.analytics.memoryEffectiveness * 100
3034
+ ),
2933
3035
  averageMemorySize: Math.round(stats.analytics.averageMemorySize * 100) / 100
2934
3036
  },
2935
3037
  config: stats.config,
@@ -2993,7 +3095,9 @@ ${errors}`);
2993
3095
  calculateSuccessRate(memory) {
2994
3096
  if (memory.length === 0)
2995
3097
  return 0;
2996
- const successCount = memory.filter((item) => item.metadata?.success !== false).length;
3098
+ const successCount = memory.filter(
3099
+ (item) => item.metadata?.success !== false
3100
+ ).length;
2997
3101
  return Math.round(successCount / memory.length * 100);
2998
3102
  }
2999
3103
  calculateAverageExecutionTime(memory) {