using System; using System.Linq; using UnityEngine; using LLM.Editor.Core; using LLM.Editor.Data; using System.Threading; using LLM.Editor.Commands; using System.Threading.Tasks; using System.Collections.Generic; using LLM.Editor.Tests.Integration; namespace LLM.Editor.Client { /// /// A mock client that simulates an LLM response for testing purposes. /// It now discovers and runs test cases from C# classes that implement IDummyTestCase. /// public class DummyApiClient : ILlmApiClient { private static List _testCases; private static bool _testCasesLoaded; private IDummyTestCase _activeTestCase; private int _activeResponseStep; public static List GetTestCases() { if (!_testCasesLoaded) { DiscoverTestCases(); } return _testCases; } private static void DiscoverTestCases() { _testCases = new List(); var testCaseType = typeof(IDummyTestCase); var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { try { var types = assembly.GetTypes(); foreach (var type in types) { if (testCaseType.IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract) { var instance = (IDummyTestCase)Activator.CreateInstance(type); _testCases.Add(instance); } } } catch (Exception e) { Debug.LogWarning($"[DummyApiClient] Could not inspect assembly {assembly.FullName} for test cases: {e.Message}"); } } _testCases = _testCases.OrderBy(tc => tc.TriggerPhrase).ToList(); _testCasesLoaded = true; Debug.Log($"[DummyApiClient] Discovered {_testCases.Count} C# test cases."); } public Task Initialize() { // Dummy client needs no async initialization. return Task.FromResult(true); } public async Task SendPrompt(string prompt, List stagedContext, CancellationToken cancellationToken = default) { if (!_testCasesLoaded) DiscoverTestCases(); _activeTestCase = _testCases.FirstOrDefault( c => prompt.Equals(c.TriggerPhrase, StringComparison.Ordinal) ); // Simulate network delay await Task.Delay(500, cancellationToken); if (cancellationToken.IsCancellationRequested) return; if (_activeTestCase != null) { Debug.Log($"[DummyApiClient] Triggered test case for: '{_activeTestCase.TriggerPhrase}'"); _activeResponseStep = 0; ExecuteStep(); } else { DisplayError("No test case was triggered by your prompt."); } } public async Task SendFollowUp(string detailedContext, CancellationToken cancellationToken = default) { // Simulate network delay await Task.Delay(500, cancellationToken); if (cancellationToken.IsCancellationRequested) return; if (_activeTestCase != null) { _activeResponseStep++; Debug.Log($"[DummyApiClient] Executing follow-up step #{_activeResponseStep + 1} for test case: '{_activeTestCase.TriggerPhrase}'"); ExecuteStep(); } else { Debug.LogWarning("[DummyApiClient] Received a follow-up call, but no active test case was found."); DisplayError("No active test case for follow-up."); } } public string GetAuthToken() { return "dummy-token"; } private void ExecuteStep() { var commandSteps = _activeTestCase?.GetCommandSteps(); if (commandSteps == null || _activeResponseStep >= commandSteps.Count) { Debug.Log("[DummyApiClient] Test case finished or has no more steps."); _activeTestCase = null; // End the test case return; } var commands = commandSteps[_activeResponseStep]; CommandExecutor.SetQueue(commands, _activeTestCase.TriggerPhrase); } private void DisplayError(string message) { var commandData = new CommandData { commandName = nameof(DisplayMessageCommand), jsonData = new Newtonsoft.Json.Linq.JObject { ["outcome"] = "Error", ["message"] = $"[Dummy Client Error] {message}" } }; CommandExecutor.SetQueue(new List { commandData }, "Error"); } } }