using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using LLM.Editor.Commands;
using LLM.Editor.Data;
using UnityEditor;
using UnityEngine;
namespace LLM.Editor.Core
{
///
/// Responsible for finding and executing commands from the session queue.
///
[InitializeOnLoad]
public static class CommandExecutor
{
private static List _commandQueue;
private static CommandContext _currentContext;
public static Action OnQueueUpdated;
public static event Action OnContextReadyForNextTurn;
static CommandExecutor()
{
// This will run when the editor loads, including after a recompile.
EditorApplication.delayCall += Initialize;
}
private static void Initialize()
{
Debug.Log("[CommandExecutor] Initializing...");
if (SessionManager.HasActiveSession())
{
_commandQueue = SessionManager.LoadCommandQueue();
if (!_commandQueue.Any())
{
SessionManager.EndSession();
return;
}
Debug.Log($"[CommandExecutor] Resuming session with {_commandQueue.Count} command(s) in queue.");
_currentContext = new CommandContext();
OnQueueUpdated?.Invoke();
}
else
{
_commandQueue = new List();
}
}
public static void SetQueue(List commands)
{
_commandQueue = commands;
_currentContext = new CommandContext();
SessionManager.SaveCommandQueue(_commandQueue);
OnQueueUpdated?.Invoke();
Debug.Log($"[CommandExecutor] Queue {_commandQueue.Count} contents:");
foreach (var command in commands)
{
Debug.Log($"[CommandExecutor]: {command.commandName}");
}
Debug.Log("[CommandExecutor] Queue set.");
}
private static void ClearQueue()
{
_commandQueue.Clear();
SessionManager.SaveCommandQueue(_commandQueue);
OnQueueUpdated?.Invoke();
}
public static bool HasPendingCommands() => _commandQueue != null;// && _commandQueue.Any();
public static CommandData GetNextCommand() => HasPendingCommands() ? _commandQueue.First() : null;
public static void ExecuteNextCommand()
{
if (!HasPendingCommands())
{
Debug.LogWarning("[CommandExecutor] No commands to execute.");
return;
}
var commandData = _commandQueue.First();
try
{
var commandInstance = CreateCommandInstance(commandData);
if (commandInstance != null)
{
Debug.Log($"[CommandExecutor] Executing: {commandData.commandName}");
var outcome = commandInstance.Execute(_currentContext);
switch (outcome)
{
// Decide what to do based on the outcome
case CommandOutcome.Success:
// The command succeeded, so we can remove it and continue.
_commandQueue.RemoveAt(0);
break;
case CommandOutcome.Error:
Debug.LogError($"[CommandExecutor] Command '{commandData.commandName}' failed. Clearing remaining command queue.");
ClearQueue();
break;
case CommandOutcome.AwaitingNextTurn:
{
// The command has gathered context and is waiting for the next API call.
// The queue is paused. The command remains at the top of the queue.
Debug.Log("[CommandExecutor] Pausing queue. Awaiting next turn with LLM.");
// Check if the command produced detailed context to send back.
if (_currentContext.CurrentSubject is string detailedContextJson)
{
OnContextReadyForNextTurn?.Invoke(detailedContextJson);
}
break;
}
}
}
else
{
Debug.LogError($"[CommandExecutor] Could not create instance for command: {commandData.commandName}");
ClearQueue(); // Clear queue on critical error
}
}
catch(Exception e)
{
Debug.LogError($"[CommandExecutor] Failed to execute command '{commandData.commandName}'");
Debug.LogException(e);
ClearQueue();
}
// Save the modified queue
SessionManager.SaveCommandQueue(_commandQueue);
OnQueueUpdated?.Invoke();
}
private static ICommand CreateCommandInstance(CommandData data)
{
// Use reflection to find the command class in the Commands namespace
// This makes the system extensible without needing a giant switch statement.
var commandClassName = data.commandName.EndsWith("Command") ? data.commandName : $"{data.commandName}Command";
var type = Assembly.GetExecutingAssembly().GetTypes()
.FirstOrDefault(t => t.Namespace == "LLM.Editor.Commands" && t.Name == commandClassName);
if (type != null)
{
// Assumes commands have a constructor that takes a single string (the JSON parameters)
var jsonString = data.jsonData?.ToString() ?? "{}";
return (ICommand)Activator.CreateInstance(type, jsonString);
}
Debug.LogError($"[CommandExecutor] Command type '{commandClassName}' not found.");
return null;
}
}
}