Skip to content

Commit ee0d827

Browse files
add LLM implementation for Android, Desktop, iOS
refactor existing logic to be reused
1 parent 30f3d0a commit ee0d827

File tree

61 files changed

+1456
-748
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1456
-748
lines changed

Bellatrix.LLM/Bellatrix.LLM.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<ItemGroup>
1010
<ProjectReference Include="..\src\Bellatrix.Core\Bellatrix.Core.csproj" />
1111
<ProjectReference Include="..\src\Bellatrix.KeyVault\Bellatrix.KeyVault.csproj" />
12+
<ProjectReference Include="..\src\Bellatrix.Plugins.Screenshots\Bellatrix.Plugins.Screenshots.csproj" />
1213
</ItemGroup>
1314

1415
<ItemGroup>

src/Bellatrix.Web/llm/assertions/AiAssert.cs renamed to Bellatrix.LLM/assertions/AiAssert.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,20 @@
1616
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
1717
using Bellatrix.Assertions;
1818
using Bellatrix.LLM;
19+
using Bellatrix.LLM.Skills;
1920
using Microsoft.SemanticKernel;
20-
using System;
2121

22-
namespace Bellatrix.Web.LLM.assertions;
22+
namespace Bellatrix;
2323
public static class AiAssert
2424
{
2525
public static void AssertByPrompt(string assertInstruction)
2626
{
27-
var browser = ServicesCollection.Current.Resolve<BrowserService>();
28-
browser.WaitForAjax();
29-
browser.WaitUntilReady();
30-
var summaryJson = browser.GetPageSummaryJson();
27+
var snapshotProvider = ServicesCollection.Current.Resolve<IViewSnapshotProvider>();
28+
var appSnapshot = snapshotProvider.GetCurrentViewSnapshot();
3129

32-
var result = SemanticKernelService.Kernel.InvokeAsync("Assertions", "EvaluateAssertion", new()
30+
var result = SemanticKernelService.Kernel.InvokeAsync(nameof(AssertionSkill), nameof(AssertionSkill.EvaluateAssertion), new()
3331
{
34-
["htmlSummary"] = summaryJson,
32+
["htmlSummary"] = appSnapshot,
3533
["assertInstruction"] = assertInstruction
3634
}).Result;
3735

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// <copyright file="AiValidator.cs" company="Automate The Planet Ltd.">
2+
// Copyright 2025 Automate The Planet Ltd.
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// You may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
// Unless required by applicable law or agreed to in writing, software
7+
// distributed under the License is distributed on an "AS IS" BASIS,
8+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
// See the License for the specific language governing permissions and
10+
// limitations under the License.
11+
// </copyright>
12+
// <author>Anton Angelov</author>
13+
// <site>https://bellatrix.solutions/</site>
14+
// <note>This file is part of an academic research project exploring autonomous test agents using LLMs and Semantic Kernel.
15+
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
16+
using Bellatrix.LLM;
17+
using Bellatrix.LLM.Settings;
18+
using Bellatrix.LLM.Skills;
19+
using Microsoft.SemanticKernel;
20+
21+
namespace Bellatrix;
22+
23+
public static class AiValidator
24+
{
25+
public static void ValidateByPrompt(string assertInstruction, int? timeout = null, int? sleepInterval = null)
26+
{
27+
var snapshotProvider = ServicesCollection.Current.Resolve<IViewSnapshotProvider>();
28+
29+
var settings = ConfigurationService.GetSection<LargeLanguageModelsSettings>();
30+
var effectiveTimeout = timeout ?? settings.ValidationsTimeout;
31+
var effectiveSleep = sleepInterval ?? settings.SleepInterval;
32+
33+
var verdict = string.Empty;
34+
35+
void WaitForAssertionToPass()
36+
{
37+
Utilities.Wait.Until(
38+
condition: () =>
39+
{
40+
try
41+
{
42+
var appSnapshot = snapshotProvider.GetCurrentViewSnapshot();
43+
44+
var result = SemanticKernelService.Kernel.InvokeAsync(nameof(AssertionSkill), nameof(AssertionSkill.EvaluateAssertion), new()
45+
{
46+
["htmlSummary"] = appSnapshot,
47+
["assertInstruction"] = assertInstruction
48+
}).Result;
49+
50+
var fullPrompt = result.GetValue<string>();
51+
verdict = SemanticKernelService.Kernel.InvokePromptAsync(fullPrompt).Result.GetValue<string>()?.Trim();
52+
53+
return !string.IsNullOrWhiteSpace(verdict) &&
54+
verdict.Contains("PASS", StringComparison.OrdinalIgnoreCase);
55+
}
56+
catch
57+
{
58+
return false;
59+
}
60+
},
61+
timeoutInSeconds: effectiveTimeout,
62+
exceptionMessage: $"❌ AI validation failed: {assertInstruction} within timeout ({effectiveTimeout}s).\n - {verdict}",
63+
retryRateDelay: effectiveSleep * 1000
64+
);
65+
}
66+
67+
WaitForAssertionToPass();
68+
Console.WriteLine("✅ AI Validate passed: " + assertInstruction);
69+
}
70+
}
71+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// <copyright file="IViewSnapshotProvider.cs" company="Automate The Planet Ltd.">
2+
// Copyright 2025 Automate The Planet Ltd.
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// You may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
// Unless required by applicable law or agreed to in writing, software
7+
// distributed under the License is distributed on an "AS IS" BASIS,
8+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
// See the License for the specific language governing permissions and
10+
// limitations under the License.
11+
// </copyright>
12+
// <author>Anton Angelov</author>
13+
// <site>https://bellatrix.solutions/</site>
14+
// <note>This file is part of an academic research project exploring autonomous test agents using LLMs and Semantic Kernel.
15+
// The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation.
16+
// Please cite or credit appropriately if reusing in academic or commercial work.</note>
17+
namespace Bellatrix.LLM;
18+
19+
public interface IViewSnapshotProvider
20+
{
21+
/// <summary>
22+
/// Returns a structured JSON summary of the current view (DOM or UI tree), including all visible, interactable elements.
23+
/// Should recursively traverse all nested contexts (e.g., shadow DOM, mobile hierarchy, desktop tree).
24+
/// </summary>
25+
/// <returns>JSON string summarizing the current view.</returns>
26+
string GetCurrentViewSnapshot();
27+
}

Bellatrix.LLM/embeddingsPythonServerInstructions.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ Configuration needed:
4343
"memoryIndex": "PageObjects",
4444
"resetIndexEverytime": false,
4545
"locatorRetryAttempts": 3,
46+
"validationsTimeout": 5,
47+
"sleepInterval": 1,
4648
"enableSelfHealing": true,
4749
"enableSmartFailureAnalysis": true,
4850
}

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

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,19 @@
1919
using Bellatrix.Plugins;
2020
using Bellatrix.Plugins.Screenshots.Plugins;
2121
using Bellatrix.Plugins.Screenshots;
22-
using System;
23-
using System.Threading;
24-
using Bellatrix.LLM;
2522

26-
namespace Bellatrix.Web.LLM.plugins;
23+
namespace Bellatrix.LLM.Plugins;
2724
public class SmartFailureAnalysisPlugin : Plugin, IScreenshotPlugin
2825
{
2926
private readonly IScreenshotOutputProvider _screenshotOutputProvider;
30-
private readonly BrowserService _browserService;
27+
private readonly IViewSnapshotProvider _viewSnapshotProvider;
3128
private static ThreadLocal<string> _screenshotPath = new ThreadLocal<string>();
3229

3330

3431
public SmartFailureAnalysisPlugin()
3532
{
3633
_screenshotOutputProvider = ServicesCollection.Current.Resolve<IScreenshotOutputProvider>();
37-
_browserService = ServicesCollection.Current.Resolve<BrowserService>();
34+
_viewSnapshotProvider = ServicesCollection.Current.Resolve<IViewSnapshotProvider>();
3835
}
3936

4037
public static void Add()
@@ -66,8 +63,8 @@ protected override void PreTestCleanup(object sender, PluginEventArgs e)
6663
if (e.TestOutcome == TestOutcome.Passed)
6764
{
6865
var log = Logger.GetLogs();
69-
var summary = _browserService.GetPageSummaryJson();
70-
SmartFailureAnalyzer.SaveTestPass(e.TestFullName, log, summary);
66+
var snapshot = _viewSnapshotProvider.GetCurrentViewSnapshot();
67+
SmartFailureAnalyzer.SaveTestPass(e.TestFullName, log, snapshot);
7168
}
7269
else
7370
{
@@ -81,14 +78,14 @@ private void RunFailureAnalysisAsync(PluginEventArgs e)
8178
try
8279
{
8380
var log = Logger.GetLogs(); // flushless BDD log
84-
var pageSummary = _browserService.GetPageSummaryJson(); // live page state
81+
var snapshot = _viewSnapshotProvider.GetCurrentViewSnapshot(); // live page state
8582

8683
diagnosis = SmartFailureAnalyzer.Diagnose(
8784
e.TestFullName,
8885
e.Exception?.ToString() ?? "No exception captured.",
8986
log,
90-
pageSummary,
91-
_screenshotPath.Value);
87+
snapshot,
88+
_screenshotPath.Value ?? string.Empty);
9289

9390

9491
}

Bellatrix.LLM/services/LocatorSelfHealingService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public static string TryHeal(string failingLocator, string newestVersionViewSumm
6666
return null;
6767
}
6868

69-
var prompt = SemanticKernelService.Kernel.InvokeAsync("Locator", "HealBrokenLocator", new()
69+
var prompt = SemanticKernelService.Kernel.InvokeAsync("LocatorSkill", "HealBrokenLocator", new()
7070
{
7171
["failedLocator"] = failingLocator,
7272
["oldViewummary"] = known.ViewSummary,

Bellatrix.LLM/services/PageObjectsIndexer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public static void IndexAllPageObjects(string folderName = "Pages", string memor
5858
try
5959
{
6060
// Step 1: Generate SK prompt
61-
var summaryPrompt = kernel.InvokeAsync("PageSummarizer", "SummarizePageObjectCode", new()
61+
var summaryPrompt = kernel.InvokeAsync("PageObjectSummarizerSkill", "SummarizePageObjectCode", new()
6262
{
6363
["code"] = combinedCode
6464
}).Result.GetValue<string>();

Bellatrix.LLM/services/SmartFailureAnalyzer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using Bellatrix.KeyVault;
1818
using Bellatrix.LLM.Cache;
1919
using Bellatrix.LLM.Settings;
20+
using Bellatrix.LLM.Skills;
2021
using Microsoft.SemanticKernel;
2122

2223
namespace Bellatrix.LLM;
@@ -95,7 +96,7 @@ public static string Diagnose(string testName, string exceptionDetails, string c
9596
}
9697

9798
var prompt = SemanticKernelService.Kernel
98-
.InvokeAsync("FailureAnalyzer", "GenerateFailureDiagnosis", arguments).Result;
99+
.InvokeAsync(nameof(FailureAnalyzerSkill), "GenerateFailureDiagnosis", arguments).Result;
99100

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

Bellatrix.LLM/settings/LargeLanguageModelsSettings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ public class LargeLanguageModelsSettings
3030
public string MemoryIndex { get; set; }
3131
public bool ResetIndexEverytime { get; set; }
3232
public int LocatorRetryAttempts { get; set; }
33+
public int ValidationsTimeout { get; set; } = 5;
34+
public int SleepInterval { get; set; } = 1;
3335
}

0 commit comments

Comments
 (0)