feat(CUB-19): implement AgentStatus SignalR hub for real-time updates
- Add AgentStatusHub with typed IAgentStatusClient interface
- Hub at /hubs/agent-status (matches design spec)
- Fleet group + per-agent group subscription
- AgentStatusChanged and AgentTaskProgress push events
- Extension methods for server-side push via IHubContext
- Add GatewayEventBridgeService background service
- Connects to OpenClaw Gateway WebSocket (v3 protocol)
- Handles challenge → connect → hello-ok handshake
- Bridges sessions.changed, session.message, session.tool events
- Translates Gateway session status to AgentStatus enum
- Maintains in-memory fleet state for snapshot queries
- Add REST API controllers
- GET /api/agents — fleet status snapshot
- GET /api/agents/{agentId} — single agent status
- GET /api/logs/{agentId} — agent session logs (stub)
- POST /api/command/stop/{agentId} — stop agent
- POST /api/command/restart/{agentId} — restart agent
- POST /api/command/steer/{agentId} — inject message
- Add models matching TypeScript spec interfaces
- AgentStatusUpdate, TaskProgressUpdate, AgentCardData
- AgentStatus enum (active/idle/thinking/error)
- Configure CORS with credentials for SignalR WebSocket
- Configure Swagger/OpenAPI with XML doc comments
- Agent role map matching frontend AGENT_ROLES constant
This commit is contained in:
92
backend/ControlCenter/Hubs/Models/AgentStatusModels.cs
Normal file
92
backend/ControlCenter/Hubs/Models/AgentStatusModels.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
namespace ControlCenter;
|
||||
|
||||
/// <summary>
|
||||
/// Agent operational status derived from OpenClaw Gateway session activity.
|
||||
/// Maps to the frontend AgentStatus type: 'active' | 'idle' | 'thinking' | 'error'.
|
||||
/// </summary>
|
||||
public enum AgentStatus
|
||||
{
|
||||
/// <summary>Agent is currently processing a turn.</summary>
|
||||
Active,
|
||||
|
||||
/// <summary>Agent completed its last turn; no active work.</summary>
|
||||
Idle,
|
||||
|
||||
/// <summary>LLM call in flight; tokens streaming.</summary>
|
||||
Thinking,
|
||||
|
||||
/// <summary>Agent encountered an unhandled error.</summary>
|
||||
Error
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extended lifecycle status including offline — not all agents have active sessions.
|
||||
/// Used internally; clients only see <see cref="AgentStatus"/> (offline maps to idle).
|
||||
/// </summary>
|
||||
public enum AgentLifecycleStatus
|
||||
{
|
||||
Active,
|
||||
Idle,
|
||||
Thinking,
|
||||
Error,
|
||||
Offline
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushed to SignalR clients when an agent's status changes.
|
||||
/// Matches the TypeScript <c>AgentStatusUpdate</c> interface from the design spec.
|
||||
/// </summary>
|
||||
/// <param name="AgentId">Agent identifier, e.g. "otto", "dex".</param>
|
||||
/// <param name="DisplayName">Human-readable name, e.g. "Otto".</param>
|
||||
/// <param name="Role">Role description, e.g. "Orchestrator Agent".</param>
|
||||
/// <param name="Status">Current operational status.</param>
|
||||
/// <param name="CurrentTask">Description of the current task, if any.</param>
|
||||
/// <param name="SessionKey">Full session key, e.g. "agent:otto:telegram:direct:8787451565".</param>
|
||||
/// <param name="Channel">Channel the agent is operating on, e.g. "telegram".</param>
|
||||
/// <param name="LastActivity">ISO 8601 timestamp of last activity.</param>
|
||||
/// <param name="ErrorMessage">Error message when status is 'error'.</param>
|
||||
public record AgentStatusUpdate(
|
||||
string AgentId,
|
||||
string DisplayName,
|
||||
string Role,
|
||||
string Status,
|
||||
string? CurrentTask,
|
||||
string SessionKey,
|
||||
string Channel,
|
||||
string LastActivity,
|
||||
string? ErrorMessage = null
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Pushed to SignalR clients when an agent's task progress updates.
|
||||
/// Matches the TypeScript <c>TaskProgressUpdate</c> interface from the design spec.
|
||||
/// </summary>
|
||||
/// <param name="AgentId">Agent identifier.</param>
|
||||
/// <param name="TaskDescription">Description of the current task.</param>
|
||||
/// <param name="Progress">Task progress percentage (0–100), if trackable.</param>
|
||||
/// <param name="Elapsed">Elapsed time string, e.g. "04m 12s".</param>
|
||||
public record TaskProgressUpdate(
|
||||
string AgentId,
|
||||
string TaskDescription,
|
||||
int? Progress,
|
||||
string? Elapsed
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Snapshot of an agent's full card data, sent on initial connection
|
||||
/// or when the fleet state is requested.
|
||||
/// Matches the TypeScript <c>AgentCardData</c> interface from the design spec.
|
||||
/// </summary>
|
||||
public record AgentCardData(
|
||||
string Id,
|
||||
string DisplayName,
|
||||
string Role,
|
||||
string Status,
|
||||
string? CurrentTask,
|
||||
int? TaskProgress,
|
||||
string? TaskElapsed,
|
||||
string SessionKey,
|
||||
string Channel,
|
||||
string LastActivity,
|
||||
string? ErrorMessage
|
||||
);
|
||||
Reference in New Issue
Block a user