feat(dashboard): AgentModal live working feed & thinking stream
CI - Build & Test / Backend (.NET) (push) Failing after 24s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 15s
CI - Build & Test / Security Check (push) Successful in 2s

This commit is contained in:
2026-06-11 16:13:28 +02:00
parent c29740a466
commit b1888bd8ef
4 changed files with 180 additions and 25 deletions
@@ -343,6 +343,23 @@ public class DashboardController(
}
}
/// <summary>
/// Returns the most recent activity entries (assistant messages) for a specific agent.
/// </summary>
[HttpGet("agents/{id}/activity")]
public async Task<List<AgentActivityEntry>> GetAgentActivity(string id, [FromQuery] int limit = 5)
{
try
{
return await gateway.GetAgentActivityAsync(id, Math.Clamp(limit, 1, 20));
}
catch (Exception ex)
{
logger.LogWarning(ex, "GetAgentActivity failed for {AgentId}", id);
return new List<AgentActivityEntry>();
}
}
/// <summary>
/// Returns the list of available models that can be assigned to agents.
/// Reads from OpenClaw config dynamically, falls back to hardcoded list.
+5
View File
@@ -104,3 +104,8 @@ public sealed record UpdateDashboardTaskRequest(
public sealed record UpdateDashboardTaskStatusRequest(
string Status
);
public sealed record AgentActivityEntry(
string Time,
string Text
);
+38
View File
@@ -953,6 +953,44 @@ public sealed class OpenClawGatewayClient(HttpClient httpClient, IConfiguration
return Math.Clamp(totalQueuePressure + agentPressure, 0, 100);
}
/// <summary>
/// Fetches the most recent assistant activity (last N messages) for a specific agent.
/// Returns entries with timestamp and truncated content text.
/// Falls back to an empty list if the session is unreachable.
/// </summary>
public async Task<List<AgentActivityEntry>> GetAgentActivityAsync(string agentId, int limit = 5)
{
var entries = new List<AgentActivityEntry>();
try
{
var sessionKey = $"agent:{agentId}:main";
var messages = await GetSessionHistoryAsync(sessionKey, Math.Clamp(limit * 2, 1, 100));
foreach (var msg in messages)
{
if (!string.Equals(msg.Role, "assistant", StringComparison.OrdinalIgnoreCase))
continue;
if (string.IsNullOrWhiteSpace(msg.Content))
continue;
if (msg.Content == "REPLY_SKIP" || msg.Content == "ANNOUNCE_SKIP")
continue;
// Truncate content to first 200 chars for compact display
var text = msg.Content.Length > 200
? msg.Content[..200] + "…"
: msg.Content;
var ts = ParseTimestamp(msg.Timestamp);
var timeAgo = FormatTimeAgo(ts);
entries.Add(new AgentActivityEntry(timeAgo, text));
}
}
catch
{
// Return empty list if gateway is unreachable
}
return entries.Take(Math.Clamp(limit, 1, 20)).ToList();
}
/// <summary>
/// Returns the list of available models by reading from the OpenClaw config,
/// with fallback to hardcoded list.