using UnityEditor;
using UnityEngine;
using LLM.Editor.Data;
using LLM.Editor.Helper;
using LLM.Editor.Analysis;
using JetBrains.Annotations;
using System.Collections.Generic;
namespace LLM.Editor.Commands
{
///
/// The master "tool" command. It receives a batch of data requests from the LLM,
/// dispatches them to the appropriate Context Providers, and aggregates the results.
///
[UsedImplicitly]
public class GatherContextCommand : ICommand
{
private readonly GatherContextParams _params;
public GatherContextCommand(string jsonParams)
{
_params = jsonParams?.FromJson();
}
public CommandOutcome Execute(CommandContext context)
{
if (_params?.requests == null || _params.requests.Count == 0)
{
Debug.LogError("[GatherContextCommand] No requests found in parameters.");
return CommandOutcome.Error;
}
var results = new Dictionary();
foreach (var request in _params.requests)
{
var targetObject = ResolveIdentifier(request.subjectIdentifier);
var provider = ContextProviderRegistry.GetProvider(request.dataType);
if (provider == null)
{
Debug.LogWarning($"[GatherContextCommand] No context provider found for dataType '{request.dataType}'. Skipping request for key '{request.contextKey}'.");
results[request.contextKey] = $"Error: No provider for dataType '{request.dataType}'";
continue;
}
// The qualifier is now passed as a JToken, which can be either a string or a complex object.
// The provider itself will handle the specific type it expects. For most providers, this
// will just be a string. For GetDataFromPath, it will be a PathRequest object.
var qualifierString = request.qualifier?.Type == Newtonsoft.Json.Linq.JTokenType.String
? request.qualifier.ToString()
: request.qualifier?.ToString(Newtonsoft.Json.Formatting.None);
var contextData = provider.GetContext(targetObject, qualifierString);
results[request.contextKey] = contextData;
}
var aggregatedContextJson = results.ToJson(true);
context.CurrentSubject = aggregatedContextJson;
Debug.Log($"[GatherContextCommand] Successfully gathered context for {_params.requests.Count} request(s). Pausing for next API call.");
Debug.Log($"Aggregated Context:\n{aggregatedContextJson}");
return CommandOutcome.AwaitingNextTurn;
}
///
/// Resolves an identifier string to a Unity Object.
/// The identifier can be an InstanceID, a GUID, or an asset path.
///
private static Object ResolveIdentifier(string identifier)
{
if (string.IsNullOrEmpty(identifier)) return null;
// Priority 1: Try parsing as an InstanceID for scene objects
if (int.TryParse(identifier, out var instanceId))
{
var obj = EditorUtility.InstanceIDToObject(instanceId);
if (obj) return obj;
}
// Priority 2: Try resolving as a GUID for project assets
var path = AssetDatabase.GUIDToAssetPath(identifier);
if (!string.IsNullOrEmpty(path))
{
return AssetDatabase.LoadAssetAtPath