Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0fc305832 | |||
| c120155170 |
@@ -62,81 +62,96 @@ public sealed class OpenClawGatewayClient(HttpClient httpClient, IConfiguration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts useful data from a tool response that may embed JSON in content[0].text.
|
||||||
|
/// Returns the unwrapped "details" object if present, otherwise the raw result.
|
||||||
|
/// </summary>
|
||||||
|
private static JsonNode? ExtractToolData(JsonNode? result)
|
||||||
|
{
|
||||||
|
if (result is null) return null;
|
||||||
|
// Some tools return { details: {...}, content: [...] }
|
||||||
|
if (result["details"] is JsonNode details && details is not JsonValue)
|
||||||
|
return details;
|
||||||
|
// Some tools wrap in content[0].text as JSON string
|
||||||
|
if (result["content"] is JsonArray content && content.Count > 0)
|
||||||
|
{
|
||||||
|
var text = content[0]?["text"]?.GetValue<string>();
|
||||||
|
if (!string.IsNullOrWhiteSpace(text))
|
||||||
|
{
|
||||||
|
try { return JsonNode.Parse(text); }
|
||||||
|
catch { /* fall through */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<List<DashboardAgentInfo>> GetAgentsAsync()
|
public async Task<List<DashboardAgentInfo>> GetAgentsAsync()
|
||||||
{
|
{
|
||||||
var agents = new List<DashboardAgentInfo>();
|
var agents = new List<DashboardAgentInfo>();
|
||||||
|
var seenIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
// Get sessions list (active agents/sessions)
|
// Get sessions list
|
||||||
var sessionsResult = await InvokeToolAsync("sessions_list");
|
var sessionsResult = await InvokeToolAsync("sessions_list");
|
||||||
if (sessionsResult is not null)
|
var sessionsData = ExtractToolData(sessionsResult);
|
||||||
{
|
|
||||||
var sessions = sessionsResult.AsArray();
|
|
||||||
if (sessions is not null)
|
|
||||||
{
|
|
||||||
foreach (var session in sessions)
|
|
||||||
{
|
|
||||||
if (session is null) continue;
|
|
||||||
var id = session["sessionKey"]?.GetValue<string>() ?? session["id"]?.GetValue<string>() ?? "";
|
|
||||||
var name = session["name"]?.GetValue<string>() ?? id;
|
|
||||||
var model = session["model"]?.GetValue<string>() ?? "";
|
|
||||||
var status = session["status"]?.GetValue<string>() ?? "";
|
|
||||||
var isActive = status.Equals("active", StringComparison.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
agents.Add(new DashboardAgentInfo(
|
if (sessionsData is JsonObject so)
|
||||||
Id: id,
|
{
|
||||||
Name: name,
|
// sessions_list returns { agents: [...], sessions: {...} }
|
||||||
Role: DeriveRole(id),
|
// Try agents array first (from gateway call)
|
||||||
Model: model,
|
if (so["agents"] is JsonArray agentArray)
|
||||||
IsActive: isActive,
|
{
|
||||||
CurrentTask: session["currentTask"]?.GetValue<string>()
|
foreach (var a in agentArray)
|
||||||
));
|
{
|
||||||
|
if (a is null) continue;
|
||||||
|
var id = a["agentId"]?.GetValue<string>() ?? "";
|
||||||
|
if (string.IsNullOrWhiteSpace(id) || !seenIds.Add(id)) continue;
|
||||||
|
var name = a["name"]?.GetValue<string>() ?? id;
|
||||||
|
var model = "GPT-5.4"; // default, overridden if available
|
||||||
|
var isActive = false;
|
||||||
|
var currentTask = (string?)null;
|
||||||
|
|
||||||
|
// Check if agent has recent sessions (active indicator)
|
||||||
|
if (a["sessions"] is JsonObject sess && sess["recent"] is JsonArray recent && recent.Count > 0)
|
||||||
|
{
|
||||||
|
var age = recent[0]?["age"]?.GetValue<long>() ?? long.MaxValue;
|
||||||
|
isActive = age < 300_000; // active if session < 5 min ago
|
||||||
|
currentTask = recent[0]?["key"]?.GetValue<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
agents.Add(new DashboardAgentInfo(id, name, DeriveRole(id), model, isActive, currentTask));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also get subagents list
|
// Also get subagents list
|
||||||
var subagentsResult = await InvokeToolAsync("subagents", new { action = "list" });
|
var subResult = await InvokeToolAsync("subagents", new { action = "list" });
|
||||||
if (subagentsResult is not null && subagentsResult is JsonArray subArray)
|
var subData = ExtractToolData(subResult);
|
||||||
|
|
||||||
|
if (subData is JsonArray subArray)
|
||||||
{
|
{
|
||||||
foreach (var sub in subArray)
|
foreach (var s in subArray)
|
||||||
{
|
{
|
||||||
if (sub is null) continue;
|
if (s is null) continue;
|
||||||
var id = sub["id"]?.GetValue<string>() ?? "";
|
var id = s["id"]?.GetValue<string>() ?? s["agentId"]?.GetValue<string>() ?? "";
|
||||||
if (agents.Any(a => a.Id == id)) continue;
|
if (string.IsNullOrWhiteSpace(id) || !seenIds.Add(id)) continue;
|
||||||
|
var name = s["name"]?.GetValue<string>() ?? id;
|
||||||
|
var status = s["status"]?.GetValue<string>() ?? "";
|
||||||
|
var isActive = status is "active" or "running";
|
||||||
|
var currentTask = s["task"]?.GetValue<string>() ?? s["currentTask"]?.GetValue<string>();
|
||||||
|
|
||||||
var name = sub["name"]?.GetValue<string>() ?? id;
|
agents.Add(new DashboardAgentInfo(id, name, DeriveRole(id), "", isActive, currentTask));
|
||||||
var model = sub["model"]?.GetValue<string>() ?? "";
|
|
||||||
var status = sub["status"]?.GetValue<string>() ?? "";
|
|
||||||
var isActive = status.Equals("active", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
status.Equals("running", StringComparison.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
agents.Add(new DashboardAgentInfo(
|
|
||||||
Id: id,
|
|
||||||
Name: name,
|
|
||||||
Role: DeriveRole(id),
|
|
||||||
Model: model,
|
|
||||||
IsActive: isActive,
|
|
||||||
CurrentTask: sub["currentTask"]?.GetValue<string>()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return agents.Count > 0 ? agents : new List<DashboardAgentInfo>();
|
return agents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<MessageEntry>> GetSessionHistoryAsync(string sessionKey, int limit = 50, int offset = 0)
|
public async Task<List<MessageEntry>> GetSessionHistoryAsync(string sessionKey, int limit = 50, int offset = 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await InvokeToolAsync("sessions_history", new
|
var result = await InvokeToolAsync("sessions_history", new { sessionKey, limit, offset });
|
||||||
{
|
if (result is null) return new List<MessageEntry>();
|
||||||
sessionKey,
|
|
||||||
limit,
|
|
||||||
offset
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result is null)
|
|
||||||
return new List<MessageEntry>();
|
|
||||||
|
|
||||||
var messages = new List<MessageEntry>();
|
var messages = new List<MessageEntry>();
|
||||||
var array = result as JsonArray ?? result.AsArray();
|
var array = result as JsonArray ?? result.AsArray();
|
||||||
@@ -167,19 +182,13 @@ public sealed class OpenClawGatewayClient(HttpClient httpClient, IConfiguration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await InvokeToolAsync("sessions_send", new
|
var result = await InvokeToolAsync("sessions_send", new { sessionKey, message });
|
||||||
{
|
if (result is null) return new ChatResponse(false, null, "Gateway nicht erreichbar");
|
||||||
sessionKey,
|
|
||||||
message
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result is null)
|
var ok = result["ok"]?.GetValue<bool>() ?? false;
|
||||||
return new ChatResponse(false, null, "Gateway nicht erreichbar");
|
|
||||||
|
|
||||||
var ok = result["ok"]?.GetValue<bool>() ?? result["success"]?.GetValue<bool>() ?? false;
|
|
||||||
var reply = result["reply"]?.GetValue<string>()
|
var reply = result["reply"]?.GetValue<string>()
|
||||||
?? result["response"]?.GetValue<string>()
|
?? result["response"]?.GetValue<string>()
|
||||||
?? result["content"]?.GetValue<string>();
|
?? result["content"]?[0]?["text"]?.GetValue<string>();
|
||||||
var error = result["error"]?.GetValue<string>();
|
var error = result["error"]?.GetValue<string>();
|
||||||
|
|
||||||
return new ChatResponse(ok, reply, error);
|
return new ChatResponse(ok, reply, error);
|
||||||
@@ -195,23 +204,24 @@ public sealed class OpenClawGatewayClient(HttpClient httpClient, IConfiguration
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await InvokeToolAsync("cron", new { action = "list" });
|
var result = await InvokeToolAsync("cron", new { action = "list" });
|
||||||
if (result is null)
|
var data = ExtractToolData(result);
|
||||||
return new List<QueueItem>();
|
if (data is null) return new List<QueueItem>();
|
||||||
|
|
||||||
var items = new List<QueueItem>();
|
var items = new List<QueueItem>();
|
||||||
var array = result as JsonArray ?? result.AsArray();
|
var jobs = data["jobs"] as JsonArray ?? data.AsArray();
|
||||||
if (array is null) return items;
|
if (jobs is null) return items;
|
||||||
|
|
||||||
foreach (var entry in array)
|
foreach (var j in jobs)
|
||||||
{
|
{
|
||||||
if (entry is null) continue;
|
if (j is null) continue;
|
||||||
var id = entry["id"]?.GetValue<string>() ?? "";
|
var id = j["id"]?.GetValue<string>() ?? "";
|
||||||
var name = entry["name"]?.GetValue<string>() ?? id;
|
var name = j["name"]?.GetValue<string>() ?? id;
|
||||||
var status = entry["status"]?.GetValue<string>() ?? "unknown";
|
var status = j["state"]?["lastStatus"]?.GetValue<string>()
|
||||||
|
?? j["status"]?.GetValue<string>()
|
||||||
|
?? "unknown";
|
||||||
|
|
||||||
items.Add(new QueueItem(id, name, status));
|
items.Add(new QueueItem(id, name, status));
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -227,35 +237,48 @@ public sealed class OpenClawGatewayClient(HttpClient httpClient, IConfiguration
|
|||||||
var activeAgents = 0;
|
var activeAgents = 0;
|
||||||
var pendingTasks = 0;
|
var pendingTasks = 0;
|
||||||
|
|
||||||
|
// Step 1: Health check (no auth needed)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Check gateway health
|
|
||||||
using var pingRequest = new HttpRequestMessage(HttpMethod.Get, "/health");
|
using var pingRequest = new HttpRequestMessage(HttpMethod.Get, "/health");
|
||||||
ApplyAuth(pingRequest);
|
|
||||||
using var pingResponse = await httpClient.SendAsync(pingRequest);
|
using var pingResponse = await httpClient.SendAsync(pingRequest);
|
||||||
gatewayOk = pingResponse.IsSuccessStatusCode;
|
gatewayOk = pingResponse.IsSuccessStatusCode;
|
||||||
|
|
||||||
if (gatewayOk)
|
|
||||||
{
|
|
||||||
// Get session status
|
|
||||||
var sessionResult = await InvokeToolAsync("session_status");
|
|
||||||
if (sessionResult is not null)
|
|
||||||
{
|
|
||||||
irisStatus = sessionResult["status"]?.GetValue<string>() ?? "Active";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get agents for active count
|
|
||||||
var agents = await GetAgentsAsync();
|
|
||||||
activeAgents = agents.Count(a => a.IsActive);
|
|
||||||
|
|
||||||
// Get queue/cron for pending tasks
|
|
||||||
var queue = await GetQueueAsync();
|
|
||||||
pendingTasks = queue.Count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
gatewayOk = false;
|
// gatewayOk stays false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gatewayOk)
|
||||||
|
{
|
||||||
|
// Step 2: Session status
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sessionResult = await InvokeToolAsync("session_status");
|
||||||
|
if (sessionResult is not null)
|
||||||
|
{
|
||||||
|
irisStatus = sessionResult["status"]?.GetValue<string>()
|
||||||
|
?? sessionResult["sessionKey"]?.GetValue<string>()
|
||||||
|
?? "Active";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
// Step 3: Active agents
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var agents = await GetAgentsAsync();
|
||||||
|
activeAgents = agents.Count(a => a.IsActive);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
// Step 4: Queue items
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var queue = await GetQueueAsync();
|
||||||
|
pendingTasks = queue.Count;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DashboardStatus(gatewayOk, irisStatus, activeAgents, pendingTasks);
|
return new DashboardStatus(gatewayOk, irisStatus, activeAgents, pendingTasks);
|
||||||
@@ -267,6 +290,8 @@ public sealed class OpenClawGatewayClient(HttpClient httpClient, IConfiguration
|
|||||||
"programmer" => "Developer",
|
"programmer" => "Developer",
|
||||||
"reviewer" => "Reviewer",
|
"reviewer" => "Reviewer",
|
||||||
"architekt" => "Architect",
|
"architekt" => "Architect",
|
||||||
|
"executor" => "Executor",
|
||||||
|
"researcher" => "Researcher",
|
||||||
"main" => "Assistant",
|
"main" => "Assistant",
|
||||||
_ => "Custom"
|
_ => "Custom"
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user