Skip to content

Commit 30f3d0a

Browse files
refactor LLM services, namespaces, add documentation
add version 1.0 of Desktop LLM logic
1 parent e2dcb86 commit 30f3d0a

31 files changed

+926
-80
lines changed

Bellatrix.LLM/SemanticKernelService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
1717
using Bellatrix.KeyVault;
18-
using Bellatrix.LLM.settings;
18+
using Bellatrix.LLM.Settings;
1919
using Microsoft.KernelMemory;
2020
using Microsoft.SemanticKernel;
2121
using System.Collections.Concurrent;

Bellatrix.LLM/cache/LocatorCacheDbContext.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
1717

18-
using Bellatrix.LLM.cache;
1918
using Microsoft.EntityFrameworkCore;
2019

2120
namespace Bellatrix.LLM.Cache;

Bellatrix.LLM/cache/SelfHealingLocatorEntry.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// <note>This file is part of an academic research project exploring autonomous test agents using LLMs and Semantic Kernel.
1515
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
17-
namespace Bellatrix.LLM.cache;
17+
namespace Bellatrix.LLM.Cache;
1818
public class SelfHealingLocatorEntry
1919
{
2020
public int Id { get; set; }

Bellatrix.LLM/cache/SmartTestExecutionEntry.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// <note>This file is part of an academic research project exploring autonomous test agents using LLMs and Semantic Kernel.
1515
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
17-
namespace Bellatrix.LLM.cache;
17+
namespace Bellatrix.LLM.Cache;
1818
public class SmartTestExecutionEntry
1919
{
2020
public int Id { get; set; }

src/Bellatrix.Web/llm/plugins/SmartTestFailureException.cs renamed to Bellatrix.LLM/plugins/SmartTestFailureException.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@
1414
// <note>This file is part of an academic research project exploring autonomous test agents using LLMs and Semantic Kernel.
1515
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
17-
using System;
18-
19-
namespace Bellatrix.Web.LLM.Plugins;
17+
namespace Bellatrix.LLM.Plugins;
2018
public class SmartTestFailureException : Exception
2119
{
2220
public SmartTestFailureException(string aiSummary, string fullAnalysis, Exception originalException)

src/Bellatrix.Web/llm/services/LocatorCacheService.cs renamed to Bellatrix.LLM/services/LocatorCacheService.cs

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,23 @@
1717

1818
using Bellatrix.KeyVault;
1919
using Bellatrix.LLM.Cache;
20-
using Bellatrix.LLM.settings;
21-
using OpenQA.Selenium;
22-
using System;
20+
using Bellatrix.LLM.Settings;
2321
using System.Collections.Concurrent;
24-
using System.Linq;
2522

26-
namespace Bellatrix.Web.LLM.services;
23+
namespace Bellatrix.LLM;
24+
25+
/// <summary>
26+
/// A shared locator cache service for AI-assisted test automation.
27+
/// It stores and retrieves XPath selectors for natural language instructions,
28+
/// scoped by application location (e.g., URL or screen ID).
29+
/// Useful for enabling cross-platform support (Web, Android, iOS, Desktop).
30+
/// </summary>
2731
public static class LocatorCacheService
2832
{
2933
private static readonly ConcurrentDictionary<string, string> _cache = new();
3034
private static readonly string _project;
3135
private static readonly LocatorCacheDbContext _db;
32-
private static IWebDriver _driver => ServicesCollection.Current.Resolve<IWebDriver>();
36+
3337
static LocatorCacheService()
3438
{
3539
var settings = ConfigurationService.GetSection<LargeLanguageModelsSettings>();
@@ -47,19 +51,30 @@ static LocatorCacheService()
4751
}
4852
}
4953

50-
public static By TryGetCached(string instruction)
54+
/// <summary>
55+
/// Attempts to retrieve a cached XPath for the given instruction and location.
56+
/// </summary>
57+
/// <param name="location">The app location (URL, screen ID, etc.)</param>
58+
/// <param name="instruction">The natural language instruction used for element lookup.</param>
59+
/// <returns>The XPath selector if cached, otherwise null.</returns>
60+
public static string TryGetCached(string location, string instruction)
5161
{
52-
var key = $"{_driver.Url}|{instruction}";
53-
return _cache.TryGetValue(key, out var xpath) ? By.XPath(xpath) : null;
62+
var key = $"{location}|{instruction}";
63+
return _cache.TryGetValue(key, out var xpath) ? xpath : null;
5464
}
5565

56-
public static void Remove(string instruction)
66+
/// <summary>
67+
/// Removes the cached entry (if any) for the given instruction and location.
68+
/// </summary>
69+
/// <param name="location">The app location.</param>
70+
/// <param name="instruction">The instruction key to remove.</param>
71+
public static void Remove(string location, string instruction)
5772
{
58-
var key = $"{_driver.Url}|{instruction}";
73+
var key = $"{location}|{instruction}";
5974
_cache.TryRemove(key, out _);
6075

6176
var dbEntry = _db.LocatorCache.FirstOrDefault(x =>
62-
x.Project == _project && x.AppLocation == _driver.Url && x.Instruction == instruction);
77+
x.Project == _project && x.AppLocation == location && x.Instruction == instruction);
6378

6479
if (dbEntry != null)
6580
{
@@ -68,38 +83,47 @@ public static void Remove(string instruction)
6883
}
6984
}
7085

71-
public static void Update(string instruction, string xpath)
86+
/// <summary>
87+
/// Updates or inserts a new cached XPath selector for a given instruction and location.
88+
/// </summary>
89+
/// <param name="location">The app location.</param>
90+
/// <param name="instruction">The natural language instruction used for lookup.</param>
91+
/// <param name="xpath">The XPath selector to store.</param>
92+
public static void Update(string location, string instruction, string xpath)
7293
{
73-
var key = $"{_driver.Url}|{instruction}";
94+
var key = $"{location}|{instruction}";
7495
_cache[key] = xpath;
7596

7697
var existing = _db.LocatorCache.FirstOrDefault(x =>
77-
x.Project == _project && x.AppLocation == _driver.Url && x.Instruction == instruction);
98+
x.Project == _project && x.AppLocation == location && x.Instruction == instruction);
7899

79100
if (existing != null)
80101
{
81102
existing.XPath = xpath;
82103
existing.LastValidated = DateTime.UtcNow;
83-
84-
_db.LocatorCache.Update(existing); // <== ensure it's attached + marked as modified
104+
_db.LocatorCache.Update(existing);
85105
}
86106
else
87107
{
88108
var entry = new LocatorCacheEntry
89109
{
90110
Project = _project,
91-
AppLocation = _driver.Url,
111+
AppLocation = location,
92112
Instruction = instruction,
93113
XPath = xpath
94114
};
95-
96115
_db.LocatorCache.Add(entry);
97116
}
98117

99118
_db.SaveChanges();
100119
}
120+
121+
/// <summary>
122+
/// Disposes the database context when no longer needed.
123+
/// </summary>
101124
public static void Dispose()
102125
{
103126
_db?.Dispose();
104127
}
105128
}
129+

src/Bellatrix.Web/llm/services/LocatorSelfHealingService.cs renamed to Bellatrix.LLM/services/LocatorSelfHealingService.cs

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,24 @@
1515
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
1717
using Bellatrix.KeyVault;
18-
using Bellatrix.LLM;
19-
using Bellatrix.LLM.cache;
2018
using Bellatrix.LLM.Cache;
21-
using Bellatrix.LLM.settings;
19+
using Bellatrix.LLM.Settings;
2220
using Microsoft.SemanticKernel;
23-
using OpenQA.Selenium;
24-
using System;
25-
using System.Linq;
2621

27-
namespace Bellatrix.Web.LLM.services;
22+
namespace Bellatrix.LLM;
23+
/// <summary>
24+
/// Provides self-healing capabilities for UI locators by leveraging AI and a local cache of previously validated locators.
25+
/// This service enables autonomous test agents to recover from locator failures by suggesting new working locators
26+
/// based on historical data and semantic analysis of UI changes.
27+
/// </summary>
2828
public static class LocatorSelfHealingService
2929
{
3030
private static readonly LocatorCacheDbContext _db;
3131
private static readonly string _project;
32+
33+
/// <summary>
34+
/// Static constructor initializes the local cache database context and project name from configuration and secrets.
35+
/// </summary>
3236
static LocatorSelfHealingService()
3337
{
3438
var settings = ConfigurationService.GetSection<LargeLanguageModelsSettings>();
@@ -37,7 +41,20 @@ static LocatorSelfHealingService()
3741
_project = settings.LocalCacheProjectName;
3842
}
3943

40-
public static FindXpathStrategy TryHeal(string failingLocator, string newestVersionViewSummary, string appLocation = "")
44+
/// <summary>
45+
/// Attempts to heal a failing locator by leveraging AI and previously cached locator data.
46+
/// The method queries the local cache for a known valid locator matching the failing one and, if found,
47+
/// uses Semantic Kernel to generate a suggestion for a new working locator based on the differences between
48+
/// the old and new view summaries. The returned string is an XPath expression representing the healed locator,
49+
/// or null if no suggestion could be generated.
50+
/// </summary>
51+
/// <param name="failingLocator">The locator that is currently failing.</param>
52+
/// <param name="newestVersionViewSummary">The latest view summary of the application.</param>
53+
/// <param name="appLocation">Optional application location context.</param>
54+
/// <returns>
55+
/// The suggested healed XPath locator as a string, or null if healing is not possible.
56+
/// </returns>
57+
public static string TryHeal(string failingLocator, string newestVersionViewSummary, string appLocation = "")
4158
{
4259
var known = _db.SelfHealingLocators.FirstOrDefault(x =>
4360
x.Project == _project && x.AppLocation == appLocation &&
@@ -58,18 +75,26 @@ public static FindXpathStrategy TryHeal(string failingLocator, string newestVers
5875

5976
var suggestion = SemanticKernelService.Kernel.InvokePromptAsync(prompt).Result.GetValue<string>()?.Trim();
6077

61-
Console.WriteLine("🧠 AI Healing Suggestion:");
62-
Console.WriteLine($"❌ Failed: {failingLocator}");
63-
Console.WriteLine($"✅ Suggest: {suggestion}");
78+
Logger.LogWarning("🧠 AI Healing Suggestion:");
79+
Logger.LogError($"❌ Failed: {failingLocator}");
80+
Logger.LogWarning($"✅ Suggest: {suggestion}");
6481

6582
if (!string.IsNullOrWhiteSpace(suggestion))
6683
{
67-
return new FindXpathStrategy(suggestion);
84+
return suggestion;
6885
}
6986

7087
return null;
7188
}
7289

90+
/// <summary>
91+
/// Saves or updates a working locator and its associated view summary in the local cache.
92+
/// If the locator already exists for the given project and application location, its data is updated;
93+
/// otherwise, a new entry is created.
94+
/// </summary>
95+
/// <param name="locator">The working locator to save.</param>
96+
/// <param name="viewSummary">The view summary associated with the locator.</param>
97+
/// <param name="appLocation">Optional application location context.</param>
7398
public static void SaveWorkingLocator(string locator, string viewSummary, string appLocation = "")
7499
{
75100
var currentSummary = viewSummary;
@@ -100,6 +125,10 @@ public static void SaveWorkingLocator(string locator, string viewSummary, string
100125
_db.SaveChanges();
101126
}
102127

128+
/// <summary>
129+
/// Removes all self-healing locator entries for the current project from the local cache.
130+
/// This is useful for cleanup or resetting the cache for a specific project.
131+
/// </summary>
103132
public static void ClearProjectEntries()
104133
{
105134
var entriesToDelete = _db.SelfHealingLocators
@@ -110,14 +139,17 @@ public static void ClearProjectEntries()
110139
{
111140
_db.SelfHealingLocators.RemoveRange(entriesToDelete);
112141
_db.SaveChanges();
113-
Console.WriteLine($"🗑️ Deleted {entriesToDelete.Count} self-healing locator entries for project: {_project}");
142+
Logger.LogInformation($"🗑️ Deleted {entriesToDelete.Count} self-healing locator entries for project: {_project}");
114143
}
115144
else
116145
{
117-
Console.WriteLine($"ℹ️ No entries found for project: {_project}");
146+
Logger.LogInformation($"ℹ️ No entries found for project: {_project}");
118147
}
119148
}
120149

150+
/// <summary>
151+
/// Disposes the local cache database context and releases any associated resources.
152+
/// </summary>
121153
public static void Dispose()
122154
{
123155
_db?.Dispose();

src/Bellatrix.Web/llm/services/PageObjectsIndexer.cs renamed to Bellatrix.LLM/services/PageObjectsIndexer.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,9 @@
1414
// <note>This file is part of an academic research project exploring autonomous test agents using LLMs and Semantic Kernel.
1515
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
17-
using Bellatrix.LLM;
1817
using Microsoft.SemanticKernel;
19-
using System;
20-
using System.IO;
21-
using System.Linq;
2218

23-
namespace Bellatrix.Web.LLM.services;
19+
namespace Bellatrix.LLM;
2420

2521
public static class PageObjectsIndexer
2622
{

src/Bellatrix.Web/llm/services/SmartFailureAnalyzer.cs renamed to Bellatrix.LLM/services/SmartFailureAnalyzer.cs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,15 @@
1515
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
1717
using Bellatrix.KeyVault;
18-
using Bellatrix.LLM;
19-
using Bellatrix.LLM.cache;
2018
using Bellatrix.LLM.Cache;
21-
using Bellatrix.LLM.settings;
19+
using Bellatrix.LLM.Settings;
2220
using Microsoft.SemanticKernel;
23-
using System;
24-
using System.Collections.Generic;
25-
using System.IO;
26-
using System.Linq;
2721

28-
namespace Bellatrix.Web.LLM.services;
22+
namespace Bellatrix.LLM;
23+
/// <summary>
24+
/// Provides smart analysis and diagnosis of test failures using historical test execution data and LLM-powered reasoning.
25+
/// Responsible for saving successful test executions, diagnosing failures by comparing with previous passes, and extracting summaries from AI-generated reports.
26+
/// </summary>
2927
public static class SmartFailureAnalyzer
3028
{
3129
private static readonly LocatorCacheDbContext _db;
@@ -39,6 +37,12 @@ static SmartFailureAnalyzer()
3937
_project = settings.LocalCacheProjectName;
4038
}
4139

40+
/// <summary>
41+
/// Saves a successful test execution to the local cache database, after filtering the log.
42+
/// </summary>
43+
/// <param name="testName">The full name of the test.</param>
44+
/// <param name="fullLog">The complete log output from the test run.</param>
45+
/// <param name="summaryJson">A JSON summary of the page state or test context.</param>
4246
public static void SaveTestPass(string testName, string fullLog, string summaryJson)
4347
{
4448
var cleaned = FilterLog(fullLog);
@@ -55,6 +59,16 @@ public static void SaveTestPass(string testName, string fullLog, string summaryJ
5559
_db.SaveChanges();
5660
}
5761

62+
/// <summary>
63+
/// Diagnoses a test failure by comparing the current failing log and summary with the most recent passing execution.
64+
/// Uses an LLM to generate a diagnosis and recommended actions.
65+
/// </summary>
66+
/// <param name="testName">The full name of the test.</param>
67+
/// <param name="exceptionDetails">Details of the exception thrown during the test failure.</param>
68+
/// <param name="currentLog">The log output from the failing test run.</param>
69+
/// <param name="currentSummary">A summary of the current page or test state.</param>
70+
/// <param name="screenshotFilePath">Optional file path to a screenshot of the failure.</param>
71+
/// <returns>A string containing the AI-generated diagnosis and recommendations.</returns>
5872
public static string Diagnose(string testName, string exceptionDetails, string currentLog, string currentSummary, string screenshotFilePath)
5973
{
6074
var lastPass = _db.SmartTestExecutions
@@ -88,6 +102,14 @@ public static string Diagnose(string testName, string exceptionDetails, string c
88102
return suggestion;
89103
}
90104

105+
/// <summary>
106+
/// Extracts a summary and the main body from an AI-generated report.
107+
/// The summary is everything up to the "Recommended Actions" section; the body is the rest.
108+
/// </summary>
109+
/// <param name="fullText">The full AI-generated report text.</param>
110+
/// <returns>
111+
/// A tuple where the first item is the summary (string), and the second item is the body (string).
112+
/// </returns>
91113
public static (string Summary, string Body) ExtractSummaryAndBody(string fullText)
92114
{
93115
if (string.IsNullOrWhiteSpace(fullText))
@@ -125,7 +147,11 @@ public static (string Summary, string Body) ExtractSummaryAndBody(string fullTex
125147
);
126148
}
127149

128-
150+
/// <summary>
151+
/// Filters out lines from the test log that start with specific emoji markers (warnings, AI, pass/fail indicators).
152+
/// </summary>
153+
/// <param name="fullLog">The complete log output from the test run.</param>
154+
/// <returns>The filtered log as a string, with unwanted lines removed.</returns>
129155
public static string FilterLog(string fullLog) =>
130156
string.Join(Environment.NewLine, fullLog
131157
.Split(Environment.NewLine)

Bellatrix.LLM/settings/LargeLanguageModelsSettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
1717
using SemanticKernelWebDriverPoC;
1818

19-
namespace Bellatrix.LLM.settings;
19+
namespace Bellatrix.LLM.Settings;
2020
public class LargeLanguageModelsSettings
2121
{
2222
public List<ModelSettings> ModelSettings { get; set; }

0 commit comments

Comments
 (0)