Files
nexus/backend/Services/DashboardService.cs
T

223 lines
7.4 KiB
C#

using Nexus.Api.Models;
namespace Nexus.Api.Services;
public sealed class DashboardService(
IOpenClawGatewayClient gateway,
ITaskService taskService,
ILogger<DashboardService> logger) : IDashboardService
{
public async Task<DashboardStatus> GetStatusAsync()
{
try
{
return await gateway.GetStatusAsync();
}
catch (Exception ex)
{
logger.LogWarning(ex, "Dashboard status check failed");
return new DashboardStatus(false, "Offline", 0, 0);
}
}
public async Task<List<DashboardAgentInfo>> GetAgentsAsync()
{
try
{
return await gateway.GetAgentsAsync();
}
catch (Exception ex)
{
logger.LogWarning(ex, "Dashboard agents fetch failed");
return [];
}
}
public async Task<List<FeedEntry>> GetOperationsAsync(int limit, string? agentFilter)
{
try
{
var entries = await gateway.GetAllAgentOperationsAsync(Math.Clamp(limit, 1, 100));
if (!string.IsNullOrWhiteSpace(agentFilter))
{
entries = entries
.Where(e => string.Equals(e.AgentId, agentFilter, StringComparison.OrdinalIgnoreCase)
|| string.Equals(e.Agent, agentFilter, StringComparison.OrdinalIgnoreCase))
.ToList();
}
return entries;
}
catch (Exception ex)
{
logger.LogWarning(ex, "Dashboard operations fetch failed");
return [];
}
}
public async Task<ChatResponse> SendChatAsync(string agentId, string message)
{
try
{
return await gateway.SendChatMessageAsync(agentId, message);
}
catch (Exception ex)
{
logger.LogWarning(ex, "Dashboard chat send failed");
return new ChatResponse(false, null, "Gateway nicht erreichbar");
}
}
public async Task<List<MessageEntry>> GetMessagesAsync(string? sessionKey, int limit, int offset)
{
try
{
var key = string.IsNullOrWhiteSpace(sessionKey) ? "agent:iris:main" : sessionKey.Trim();
var messages = await gateway.GetSessionHistoryAsync(key, Math.Clamp(limit, 1, 200), Math.Max(0, offset));
return messages
.Where(m => string.Equals(m.Role, "user", StringComparison.OrdinalIgnoreCase)
|| string.Equals(m.Role, "assistant", StringComparison.OrdinalIgnoreCase))
.ToList();
}
catch (Exception ex)
{
logger.LogWarning(ex, "Dashboard messages fetch failed");
return [];
}
}
public async Task<List<QueueItem>> GetQueueAsync(CancellationToken ct)
{
try
{
var cronTask = gateway.GetQueueAsync();
var tasksTask = taskService.GetOpenAsync(ct);
await Task.WhenAll(cronTask, tasksTask);
var merged = new List<QueueItem>(cronTask.Result);
foreach (var t in tasksTask.Result)
{
merged.Add(new QueueItem("task-" + t.Id, t.Title, t.State, NormalizePriority(t.Priority), "task", "--"));
}
return merged
.OrderBy(q => PriorityOrder.GetValueOrDefault(q.Priority, 99))
.ToList();
}
catch (Exception ex)
{
logger.LogWarning(ex, "Dashboard queue fetch failed");
return [];
}
}
public async Task<GatewayRuntimeInfo> GetGatewayInfoAsync(CancellationToken ct)
{
try
{
return await gateway.GetGatewayInfoAsync(ct);
}
catch (Exception ex)
{
logger.LogWarning(ex, "Gateway info fetch failed");
return new GatewayRuntimeInfo(false, "unknown", null, null, false, false, "error", DateTimeOffset.UtcNow, "Gateway nicht erreichbar", "Gateway nicht erreichbar");
}
}
public async Task<QueueDeleteResult> DeleteQueueItemAsync(string id, string? source, CancellationToken ct)
{
if (string.Equals(source, "cron", StringComparison.OrdinalIgnoreCase))
{
var ok = await gateway.DeleteCronJobAsync(id);
return new QueueDeleteResult(ok ? QueueDeleteOutcome.Deleted : QueueDeleteOutcome.GatewayError);
}
if (string.Equals(source, "task", StringComparison.OrdinalIgnoreCase) || id.StartsWith("task-"))
{
if (!id.StartsWith("task-")) return new QueueDeleteResult(QueueDeleteOutcome.InvalidTaskId);
if (!Guid.TryParse(id["task-".Length..], out var guid))
return new QueueDeleteResult(QueueDeleteOutcome.InvalidTaskId);
var result = await taskService.CompleteViaQueueAsync(guid, ct);
return result.Outcome switch
{
TaskOperationOutcome.NotFound => new QueueDeleteResult(QueueDeleteOutcome.TaskNotFound),
_ => new QueueDeleteResult(QueueDeleteOutcome.Deleted)
};
}
var deleted = await gateway.DeleteCronJobAsync(id);
return new QueueDeleteResult(deleted ? QueueDeleteOutcome.Deleted : QueueDeleteOutcome.NotFound);
}
public async Task<QueuePriorityResult> CycleQueuePriorityAsync(string id, CancellationToken ct)
{
if (!id.StartsWith("task-"))
return new QueuePriorityResult(QueuePriorityOutcome.Ignored);
if (!Guid.TryParse(id["task-".Length..], out var guid))
return new QueuePriorityResult(QueuePriorityOutcome.InvalidTaskId);
var result = await taskService.CyclePriorityAsync(guid, ct);
return result.Outcome switch
{
TaskOperationOutcome.NotFound => new QueuePriorityResult(QueuePriorityOutcome.TaskNotFound),
_ => new QueuePriorityResult(QueuePriorityOutcome.Updated, result.Task?.Priority)
};
}
public async Task<AgentModelInfo?> GetAgentModelAsync(string agentId)
{
try
{
return await gateway.GetAgentModelAsync(agentId);
}
catch (Exception ex)
{
logger.LogWarning(ex, "GetAgentModel failed for {AgentId}", agentId);
return null;
}
}
public async Task<bool> SetAgentModelAsync(string agentId, string model)
{
try
{
return await gateway.SetAgentModelAsync(agentId, model);
}
catch (Exception ex)
{
logger.LogWarning(ex, "SetAgentModel failed for {AgentId}", agentId);
return false;
}
}
public async Task<List<AgentActivityEntry>> GetAgentActivityAsync(string agentId, int limit)
{
try
{
return await gateway.GetAgentActivityAsync(agentId, Math.Clamp(limit, 1, 20));
}
catch (Exception ex)
{
logger.LogWarning(ex, "GetAgentActivity failed for {AgentId}", agentId);
return [];
}
}
public List<ModelOption> GetAvailableModels() => gateway.GetAvailableModels();
private static string NormalizePriority(string priority) => priority.ToLowerInvariant() switch
{
"high" or "critical" or "urgent" => "high",
"low" or "minor" => "low",
_ => "medium"
};
private static readonly Dictionary<string, int> PriorityOrder = new(StringComparer.OrdinalIgnoreCase)
{
["high"] = 0, ["medium"] = 1, ["low"] = 2
};
}