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
@@ -351,8 +351,8 @@ var ScriptPlayer = class {
351
351
  var import_js_yaml = __toESM(require("js-yaml"));
352
352
 
353
353
  // src/yaml/utils.ts
354
- var import_utils2 = require("misoai-shared/utils");
355
354
  var import_js_yaml2 = __toESM(require("js-yaml"));
355
+ var import_utils2 = require("misoai-shared/utils");
356
356
  function interpolateEnvVars(content) {
357
357
  return content.replace(/\$\{([^}]+)\}/g, (_, envVar) => {
358
358
  const value = process.env[envVar.trim()];
@@ -498,13 +498,13 @@ function paramStr(task) {
498
498
  }
499
499
 
500
500
  // src/common/utils.ts
501
+ var import_dayjs = __toESM(require("dayjs"));
501
502
  var import_ai_model = require("misoai-core/ai-model");
502
503
  var import_utils3 = require("misoai-core/utils");
503
504
  var import_env = require("misoai-shared/env");
504
505
  var import_extractor = require("misoai-shared/extractor");
505
506
  var import_img = require("misoai-shared/img");
506
507
  var import_utils4 = require("misoai-shared/utils");
507
- var import_dayjs = __toESM(require("dayjs"));
508
508
 
509
509
  // src/web-element.ts
510
510
  var WebElementInfo = class {
@@ -673,8 +673,12 @@ var WorkflowMemory = class {
673
673
  const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
674
674
  workflow.memory = [...memory];
675
675
  workflow.metadata.totalSteps = workflow.steps.length;
676
- workflow.metadata.completedSteps = workflow.steps.filter((s) => s.status === "completed").length;
677
- workflow.metadata.failedSteps = workflow.steps.filter((s) => s.status === "failed").length;
676
+ workflow.metadata.completedSteps = workflow.steps.filter(
677
+ (s) => s.status === "completed"
678
+ ).length;
679
+ workflow.metadata.failedSteps = workflow.steps.filter(
680
+ (s) => s.status === "failed"
681
+ ).length;
678
682
  this.workflows.set(workflowId, workflow);
679
683
  this.enforceRetentionPolicy();
680
684
  }
@@ -685,7 +689,9 @@ var WorkflowMemory = class {
685
689
  const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
686
690
  workflow.context = { ...workflow.context, ...context };
687
691
  if (context.currentStep) {
688
- const existingStep = workflow.steps.find((s) => s.stepName === context.currentStep);
692
+ const existingStep = workflow.steps.find(
693
+ (s) => s.stepName === context.currentStep
694
+ );
689
695
  if (!existingStep) {
690
696
  workflow.steps.push({
691
697
  stepId: `step_${workflow.steps.length + 1}`,
@@ -730,7 +736,9 @@ var WorkflowMemory = class {
730
736
  enforceRetentionPolicy() {
731
737
  const maxWorkflows = 10;
732
738
  if (this.workflows.size > maxWorkflows) {
733
- const sortedWorkflows = Array.from(this.workflows.entries()).sort(([, a], [, b]) => (b.metadata.endTime || b.metadata.startTime) - (a.metadata.endTime || a.metadata.startTime));
739
+ const sortedWorkflows = Array.from(this.workflows.entries()).sort(
740
+ ([, a], [, b]) => (b.metadata.endTime || b.metadata.startTime) - (a.metadata.endTime || a.metadata.startTime)
741
+ );
734
742
  const toDelete = sortedWorkflows.slice(maxWorkflows);
735
743
  toDelete.forEach(([workflowId]) => this.workflows.delete(workflowId));
736
744
  }
@@ -1469,7 +1477,9 @@ var PageTaskExecutor = class {
1469
1477
  */
1470
1478
  getPersistentExecutor() {
1471
1479
  if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
1472
- const previousMemory = this.workflowMemory.getWorkflowMemory(this.sessionContext.workflowId);
1480
+ const previousMemory = this.workflowMemory.getWorkflowMemory(
1481
+ this.sessionContext.workflowId
1482
+ );
1473
1483
  this.persistentExecutor = new import_misoai_core.Executor("Persistent Task Executor", {
1474
1484
  onTaskStart: this.onTaskStartCallback,
1475
1485
  initialMemory: previousMemory
@@ -1498,7 +1508,9 @@ var PageTaskExecutor = class {
1498
1508
  if (this.persistentExecutor) {
1499
1509
  this.persistentExecutor.clearMemory();
1500
1510
  }
1501
- this.workflowMemory.clearWorkflow(this.sessionContext.workflowId || "default");
1511
+ this.workflowMemory.clearWorkflow(
1512
+ this.sessionContext.workflowId || "default"
1513
+ );
1502
1514
  }
1503
1515
  /**
1504
1516
  * Mevcut hafızayı döndürür
@@ -1510,7 +1522,9 @@ var PageTaskExecutor = class {
1510
1522
  * İş akışı hafızasını döndürür
1511
1523
  */
1512
1524
  getWorkflowMemory() {
1513
- return this.workflowMemory.getWorkflowData(this.sessionContext.workflowId || "default");
1525
+ return this.workflowMemory.getWorkflowData(
1526
+ this.sessionContext.workflowId || "default"
1527
+ );
1514
1528
  }
1515
1529
  /**
1516
1530
  * Hafıza istatistiklerini döndürür
@@ -1518,7 +1532,13 @@ var PageTaskExecutor = class {
1518
1532
  getMemoryStats() {
1519
1533
  return this.persistentExecutor?.getMemoryStats() || {
1520
1534
  totalItems: 0,
1521
- analytics: { totalTasks: 0, memoryHits: 0, memoryMisses: 0, averageMemorySize: 0, memoryEffectiveness: 0 },
1535
+ analytics: {
1536
+ totalTasks: 0,
1537
+ memoryHits: 0,
1538
+ memoryMisses: 0,
1539
+ averageMemorySize: 0,
1540
+ memoryEffectiveness: 0
1541
+ },
1522
1542
  config: this.memoryConfig
1523
1543
  };
1524
1544
  }
@@ -1554,11 +1574,14 @@ var PageTaskExecutor = class {
1554
1574
  let taskExecutor;
1555
1575
  if (useMemory) {
1556
1576
  taskExecutor = this.getPersistentExecutor();
1557
- this.workflowMemory.updateWorkflowContext({
1558
- currentStep: title,
1559
- pageInfo: this.sessionContext.pageInfo,
1560
- timestamp: Date.now()
1561
- }, this.sessionContext.workflowId || "default");
1577
+ this.workflowMemory.updateWorkflowContext(
1578
+ {
1579
+ currentStep: title,
1580
+ pageInfo: this.sessionContext.pageInfo,
1581
+ timestamp: Date.now()
1582
+ },
1583
+ this.sessionContext.workflowId || "default"
1584
+ );
1562
1585
  } else {
1563
1586
  taskExecutor = new import_misoai_core.Executor(title, {
1564
1587
  onTaskStart: this.onTaskStartCallback
@@ -1856,9 +1879,15 @@ var PageTaskExecutor = class {
1856
1879
  }
1857
1880
  async waitFor(assertion, opt) {
1858
1881
  const description = `waitFor: ${assertion}`;
1859
- const taskExecutor = new import_misoai_core.Executor(taskTitleStr("WaitFor", description), {
1860
- onTaskStart: this.onTaskStartCallback
1861
- });
1882
+ const useMemory = true;
1883
+ let taskExecutor;
1884
+ if (useMemory) {
1885
+ taskExecutor = this.getPersistentExecutor();
1886
+ } else {
1887
+ taskExecutor = new import_misoai_core.Executor(taskTitleStr("WaitFor", description), {
1888
+ onTaskStart: this.onTaskStartCallback
1889
+ });
1890
+ }
1862
1891
  const { timeoutMs, checkIntervalMs } = opt;
1863
1892
  (0, import_utils6.assert)(assertion, "No assertion for waitFor");
1864
1893
  (0, import_utils6.assert)(timeoutMs, "No timeoutMs for waitFor");
@@ -1913,6 +1942,25 @@ var PageTaskExecutor = class {
1913
1942
  `waitFor timeout: ${errorThought}`
1914
1943
  );
1915
1944
  }
1945
+ /**
1946
+ * Hafızaya yeni bir öğe ekler
1947
+ */
1948
+ addToMemory(memoryItem) {
1949
+ if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
1950
+ const previousMemory = this.workflowMemory.getWorkflowMemory(
1951
+ this.sessionContext.workflowId
1952
+ );
1953
+ this.persistentExecutor = new import_misoai_core.Executor("Persistent Task Executor", {
1954
+ onTaskStart: this.onTaskStartCallback,
1955
+ initialMemory: previousMemory
1956
+ });
1957
+ }
1958
+ this.persistentExecutor.memoryStore?.add(memoryItem);
1959
+ this.persistentExecutor.memoryAnalytics?.recordMemoryOperation(
1960
+ "add",
1961
+ memoryItem
1962
+ );
1963
+ }
1916
1964
  };
1917
1965
 
1918
1966
  // src/common/plan-builder.ts
@@ -2000,14 +2048,14 @@ function buildPlans(type, locateParam, param) {
2000
2048
  var import_node_assert = __toESM(require("assert"));
2001
2049
  var import_node_fs2 = require("fs");
2002
2050
  var import_node_path2 = require("path");
2051
+ var import_js_yaml3 = __toESM(require("js-yaml"));
2003
2052
  var import_common2 = require("misoai-shared/common");
2004
2053
  var import_logger3 = require("misoai-shared/logger");
2005
2054
  var import_utils9 = require("misoai-shared/utils");
2006
- var import_js_yaml3 = __toESM(require("js-yaml"));
2007
2055
  var import_semver = __toESM(require("semver"));
2008
2056
 
2009
2057
  // package.json
2010
- var version = "1.5.8";
2058
+ var version = "1.6.1";
2011
2059
 
2012
2060
  // src/common/task-cache.ts
2013
2061
  var debug3 = (0, import_logger3.getDebug)("cache");
@@ -2218,7 +2266,10 @@ var PageAgent = class {
2218
2266
  }
2219
2267
  this.taskExecutor = new PageTaskExecutor(this.page, this.insight, {
2220
2268
  taskCache: this.taskCache,
2221
- onTaskStart: this.callbackOnTaskStartTip.bind(this)
2269
+ onTaskStart: this.callbackOnTaskStartTip.bind(this),
2270
+ memoryConfig: opts?.memoryConfig,
2271
+ sessionId: opts?.sessionId,
2272
+ workflowId: opts?.workflowId
2222
2273
  });
2223
2274
  this.dump = this.resetDump();
2224
2275
  this.reportFileName = reportFileName(
@@ -2299,22 +2350,28 @@ var PageAgent = class {
2299
2350
  const allThoughts = executor.tasks.filter((task) => task.thought).map((task) => task.thought);
2300
2351
  const allLocates = executor.tasks.filter((task) => task.locate).map((task) => task.locate);
2301
2352
  const allPlans = executor.tasks.filter((task) => task.param?.plans).map((task) => task.param?.plans);
2302
- const planningTasks = executor.tasks.filter((task) => task.type === "Planning");
2303
- const insightTasks = executor.tasks.filter((task) => task.type === "Insight");
2353
+ const planningTasks = executor.tasks.filter(
2354
+ (task) => task.type === "Planning"
2355
+ );
2356
+ const insightTasks = executor.tasks.filter(
2357
+ (task) => task.type === "Insight"
2358
+ );
2304
2359
  const actionTasks = executor.tasks.filter((task) => task.type === "Action");
2305
2360
  const planning = planningTasks.length > 0 ? {
2306
2361
  type: "Planning",
2307
- description: `Planning for task execution`,
2362
+ description: "Planning for task execution",
2308
2363
  steps: planningTasks.map((task) => task.thought || "Planning step")
2309
2364
  } : void 0;
2310
2365
  const insight = insightTasks.length > 0 ? {
2311
2366
  type: "Insight",
2312
- description: `Insight for task execution`,
2313
- elements: insightTasks.map((task) => task.thought || "Insight element")
2367
+ description: "Insight for task execution",
2368
+ elements: insightTasks.map(
2369
+ (task) => task.thought || "Insight element"
2370
+ )
2314
2371
  } : void 0;
2315
2372
  const action = actionTasks.length > 0 ? {
2316
2373
  type: "Action",
2317
- description: `Action for task execution`,
2374
+ description: "Action for task execution",
2318
2375
  result: lastTask?.output
2319
2376
  } : void 0;
2320
2377
  const actionDetails = executor.tasks.map((task) => ({
@@ -2648,7 +2705,10 @@ ${memoryContext}` : void 0;
2648
2705
  }
2649
2706
  const memoryContext = this.getMemoryAsContext();
2650
2707
  const assertionWithContext = currentUrl ? `For the page at URL "${currentUrl}", ${assertion}` : assertion;
2651
- const { output, executor } = await this.taskExecutor.assert(assertionWithContext, memoryContext);
2708
+ const { output, executor } = await this.taskExecutor.assert(
2709
+ assertionWithContext,
2710
+ memoryContext
2711
+ );
2652
2712
  const metadata = this.afterTaskRunning(executor, true);
2653
2713
  if (output && opt?.keepRawResponse) {
2654
2714
  return {
@@ -2669,6 +2729,7 @@ ${reasonMsg}`);
2669
2729
  }
2670
2730
  async aiCaptcha(options) {
2671
2731
  const { deepThink = false, autoDetectComplexity = true } = options || {};
2732
+ const memoryContext = this.getMemoryAsContext();
2672
2733
  let shouldUseDeepThink = deepThink;
2673
2734
  if (autoDetectComplexity && !deepThink) {
2674
2735
  const context = await this.getUIContext();
@@ -2686,7 +2747,10 @@ A complex CAPTCHA typically has one or more of these characteristics:
2686
2747
  Return only "complex" or "simple" based on your analysis.
2687
2748
  `;
2688
2749
  const complexityMsgs = [
2689
- { role: "system", content: "You are an AI assistant that analyzes screenshots to determine CAPTCHA complexity." },
2750
+ {
2751
+ role: "system",
2752
+ content: "You are an AI assistant that analyzes screenshots to determine CAPTCHA complexity."
2753
+ },
2690
2754
  {
2691
2755
  role: "user",
2692
2756
  content: [
@@ -2710,7 +2774,12 @@ Return only "complex" or "simple" based on your analysis.
2710
2774
  );
2711
2775
  const responseText = typeof complexityResult.content === "string" ? complexityResult.content.toLowerCase() : JSON.stringify(complexityResult.content).toLowerCase();
2712
2776
  shouldUseDeepThink = responseText.includes("complex");
2713
- debug4("CAPTCHA complexity analysis:", responseText, "Using deep think:", shouldUseDeepThink);
2777
+ debug4(
2778
+ "CAPTCHA complexity analysis:",
2779
+ responseText,
2780
+ "Using deep think:",
2781
+ shouldUseDeepThink
2782
+ );
2714
2783
  } catch (error) {
2715
2784
  debug4("Failed to analyze CAPTCHA complexity:", error);
2716
2785
  }
@@ -2727,7 +2796,9 @@ Return only "complex" or "simple" based on your analysis.
2727
2796
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
2728
2797
  } else if (action.type === "input" && action.value) {
2729
2798
  if (action.target) {
2730
- await this.aiInput(action.value, action.target, { deepThink: shouldUseDeepThink });
2799
+ await this.aiInput(action.value, action.target, {
2800
+ deepThink: shouldUseDeepThink
2801
+ });
2731
2802
  }
2732
2803
  } else if (action.type === "verify" && action.target) {
2733
2804
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
@@ -2739,7 +2810,9 @@ Return only "complex" or "simple" based on your analysis.
2739
2810
  if (action.coordinates) {
2740
2811
  const x = action.coordinates[0];
2741
2812
  const y = action.coordinates[1];
2742
- await this.aiTap(`element at coordinates (${x}, ${y})`, { deepThink: shouldUseDeepThink });
2813
+ await this.aiTap(`element at coordinates (${x}, ${y})`, {
2814
+ deepThink: shouldUseDeepThink
2815
+ });
2743
2816
  } else if (action.target) {
2744
2817
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
2745
2818
  }
@@ -2749,6 +2822,26 @@ Return only "complex" or "simple" based on your analysis.
2749
2822
  }
2750
2823
  }
2751
2824
  await new Promise((resolve2) => setTimeout(resolve2, 3e3));
2825
+ const captchaMemoryItem = {
2826
+ id: `captcha_${Date.now()}`,
2827
+ timestamp: Date.now(),
2828
+ taskType: "Action",
2829
+ summary: `Solved ${captchaResult.captchaType} CAPTCHA: ${captchaResult.thought}`,
2830
+ context: {
2831
+ url: await this.page.url?.() || "",
2832
+ captchaType: captchaResult.captchaType,
2833
+ actions: captchaResult.actions,
2834
+ deepThink: actualDeepThink
2835
+ },
2836
+ metadata: {
2837
+ executionTime: Date.now() - Date.now(),
2838
+ // Will be updated
2839
+ success: true,
2840
+ confidence: 0.9
2841
+ },
2842
+ tags: ["captcha", "action", captchaResult.captchaType]
2843
+ };
2844
+ this.taskExecutor.addToMemory(captchaMemoryItem);
2752
2845
  const metadata = {
2753
2846
  status: "finished",
2754
2847
  usage,
@@ -2765,10 +2858,15 @@ Return only "complex" or "simple" based on your analysis.
2765
2858
  }
2766
2859
  async aiWaitFor(assertion, opt) {
2767
2860
  const startTime = Date.now();
2768
- const { executor } = await this.taskExecutor.waitFor(assertion, {
2861
+ const memoryContext = this.getMemoryAsContext();
2862
+ const assertionWithContext = memoryContext ? `${assertion}
2863
+
2864
+ Previous workflow steps:
2865
+ ${memoryContext}` : assertion;
2866
+ const { executor } = await this.taskExecutor.waitFor(assertionWithContext, {
2769
2867
  timeoutMs: opt?.timeoutMs || 15 * 1e3,
2770
2868
  checkIntervalMs: opt?.checkIntervalMs || 3 * 1e3,
2771
- assertion
2869
+ assertion: assertionWithContext
2772
2870
  });
2773
2871
  const metadata = {
2774
2872
  status: executor.isInErrorState() ? "failed" : "finished",
@@ -2866,25 +2964,27 @@ ${errors}`);
2866
2964
  const executionDump = {
2867
2965
  name: screenshotTitle,
2868
2966
  description: content,
2869
- tasks: [{
2870
- type: "Screenshot",
2871
- subType: "log",
2872
- status: "finished",
2873
- executor: null,
2874
- param: {
2875
- title: screenshotTitle,
2876
- content
2877
- },
2878
- output: {
2879
- screenshot
2880
- },
2881
- thought: `Logged screenshot: ${screenshotTitle}`,
2882
- timing: {
2883
- start: Date.now(),
2884
- end: Date.now(),
2885
- cost: 0
2967
+ tasks: [
2968
+ {
2969
+ type: "Screenshot",
2970
+ subType: "log",
2971
+ status: "finished",
2972
+ executor: null,
2973
+ param: {
2974
+ title: screenshotTitle,
2975
+ content
2976
+ },
2977
+ output: {
2978
+ screenshot
2979
+ },
2980
+ thought: `Logged screenshot: ${screenshotTitle}`,
2981
+ timing: {
2982
+ start: Date.now(),
2983
+ end: Date.now(),
2984
+ cost: 0
2985
+ }
2886
2986
  }
2887
- }],
2987
+ ],
2888
2988
  sdkVersion: "1.0.0",
2889
2989
  logTime: Date.now(),
2890
2990
  model_name: "screenshot"
@@ -2936,7 +3036,9 @@ ${errors}`);
2936
3036
  totalTasks: stats.analytics.totalTasks,
2937
3037
  memoryHits: stats.analytics.memoryHits,
2938
3038
  memoryMisses: stats.analytics.memoryMisses,
2939
- memoryEffectiveness: Math.round(stats.analytics.memoryEffectiveness * 100),
3039
+ memoryEffectiveness: Math.round(
3040
+ stats.analytics.memoryEffectiveness * 100
3041
+ ),
2940
3042
  averageMemorySize: Math.round(stats.analytics.averageMemorySize * 100) / 100
2941
3043
  },
2942
3044
  config: stats.config,
@@ -3000,7 +3102,9 @@ ${errors}`);
3000
3102
  calculateSuccessRate(memory) {
3001
3103
  if (memory.length === 0)
3002
3104
  return 0;
3003
- const successCount = memory.filter((item) => item.metadata?.success !== false).length;
3105
+ const successCount = memory.filter(
3106
+ (item) => item.metadata?.success !== false
3107
+ ).length;
3004
3108
  return Math.round(successCount / memory.length * 100);
3005
3109
  }
3006
3110
  calculateAverageExecutionTime(memory) {