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:
72
backend/ControlCenter/Program.cs
Normal file
72
backend/ControlCenter/Program.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.Reflection;
|
||||
using ControlCenter.Hubs;
|
||||
using ControlCenter.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// ── API Services ───────────────────────────────────────────
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new()
|
||||
{
|
||||
Title = "Control Center API",
|
||||
Version = "v1",
|
||||
Description = "OpenClaw Control Center — Command Hub backend with SignalR real-time updates"
|
||||
});
|
||||
|
||||
// Include XML doc comments in Swagger output
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
if (File.Exists(xmlPath))
|
||||
{
|
||||
c.IncludeXmlComments(xmlPath);
|
||||
}
|
||||
});
|
||||
|
||||
// ── CORS (kiosk + remote browser) ─────────────────────────
|
||||
// The Control Center frontend runs on a different origin than the backend.
|
||||
// SignalR requires credentials for WebSocket transport, so we use
|
||||
// specific origins rather than AllowAnyOrigin.
|
||||
var corsOrigins = builder.Configuration.GetSection("Cors:AllowedOrigins")
|
||||
.Get<string[]>() ?? new[] { "http://localhost:4200", "http://localhost:5000" };
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddDefaultPolicy(policy =>
|
||||
{
|
||||
policy.WithOrigins(corsOrigins)
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials(); // Required for SignalR WebSocket
|
||||
});
|
||||
});
|
||||
|
||||
// ── SignalR (real-time agent status updates) ───────────────
|
||||
builder.Services.AddSignalR();
|
||||
|
||||
// ── Gateway Bridge Service ────────────────────────────────
|
||||
// Background service that connects to the OpenClaw Gateway WebSocket
|
||||
// and bridges events to the AgentStatus SignalR hub.
|
||||
builder.Services.AddSingleton<GatewayEventBridgeService>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<GatewayEventBridgeService>());
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// ── Middleware ──────────────────────────────────────────────
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseCors();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
|
||||
// ── Hub Endpoints ───────────────────────────────────────────
|
||||
// Agent status hub at /hubs/agent-status (matches the design spec)
|
||||
app.MapHub<AgentStatusHub>("/hubs/agent-status");
|
||||
|
||||
app.Run();
|
||||
Reference in New Issue
Block a user