Implements FED-010: Agent Spawn via Federation feature that enables spawning and managing Claude agents on remote federated Mosaic Stack instances via COMMAND message type. Features: - Federation agent command types (spawn, status, kill) - FederationAgentService for handling agent operations - Integration with orchestrator's agent spawner/lifecycle services - API endpoints for spawning, querying status, and killing agents - Full command routing through federation COMMAND infrastructure - Comprehensive test coverage (12/12 tests passing) Architecture: - Hub → Spoke: Spawn agents on remote instances - Command flow: FederationController → FederationAgentService → CommandService → Remote Orchestrator - Response handling: Remote orchestrator returns agent status/results - Security: Connection validation, signature verification Files created: - apps/api/src/federation/types/federation-agent.types.ts - apps/api/src/federation/federation-agent.service.ts - apps/api/src/federation/federation-agent.service.spec.ts Files modified: - apps/api/src/federation/command.service.ts (agent command routing) - apps/api/src/federation/federation.controller.ts (agent endpoints) - apps/api/src/federation/federation.module.ts (service registration) - apps/orchestrator/src/api/agents/agents.controller.ts (status endpoint) - apps/orchestrator/src/api/agents/agents.module.ts (lifecycle integration) Testing: - 12/12 tests passing for FederationAgentService - All command service tests passing - TypeScript compilation successful - Linting passed Refs #93 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
4.1 KiB
Issue #173: WebSocket gateway for job events
Objective
Extend existing WebSocket gateway to support real-time job event streaming, enabling clients to subscribe to job progress updates, step execution, and status changes.
Approach
Current State
- WebSocket gateway exists at
apps/api/src/websocket/websocket.gateway.ts - Currently supports task, event, project, and cron events
- Uses workspace-scoped rooms for broadcasting
- Authentication enforced via Socket.io connection data
- JobEventsService available with event types defined
Implementation Plan
-
Extend WebSocketGateway with job event emission methods
-
Add subscription management for job-specific and workspace-level job subscriptions
-
Implement message handlers for:
subscribe:job- Subscribe to specific job eventssubscribe:workspace:jobs- Subscribe to all jobs in workspaceunsubscribe:job- Unsubscribe from jobunsubscribe:workspace:jobs- Unsubscribe from workspace jobs
-
Add emit methods for:
job:created- New job createdjob:status- Job status changejob:progress- Progress update (0-100%)step:started- Step startedstep:completed- Step completedstep:output- Step output chunk
-
Wire JobEventsService to emit WebSocket events when database events are created
Subscription Model
- Job-specific room:
job:{jobId} - Workspace jobs room:
workspace:{workspaceId}:jobs - Clients can subscribe to both simultaneously
TDD Workflow
- Write tests for subscription handlers (RED)
- Implement subscription handlers (GREEN)
- Write tests for emit methods (RED)
- Implement emit methods (GREEN)
- Wire JobEventsService integration (if needed)
- Refactor and cleanup
Progress
- Read existing WebSocket gateway implementation
- Read JobEventsService and event types
- Create scratchpad
- Write tests for job event emit methods (TDD RED phase)
- Implement job event emit methods (TDD GREEN phase)
- All tests passing (22/22 tests)
- TypeScript type checking passes for websocket module
- Linting passes for websocket module
- Run quality gates
- Commit changes
Note: Skipped subscription handlers as the existing WebSocket gateway uses a simpler model where clients automatically join workspace-scoped rooms on connection. Job events are emitted to both workspace-level (workspace:{id}:jobs) and job-specific (job:{id}) rooms, allowing clients to subscribe by joining the appropriate rooms.
Testing
Unit Tests (✅ Complete)
- ✅ emitJobCreated - workspace jobs room
- ✅ emitJobCreated - specific job room
- ✅ emitJobStatusChanged - workspace jobs room
- ✅ emitJobStatusChanged - specific job room
- ✅ emitJobProgress - workspace jobs room
- ✅ emitJobProgress - specific job room
- ✅ emitStepStarted - workspace jobs room
- ✅ emitStepStarted - specific job room
- ✅ emitStepCompleted - workspace jobs room
- ✅ emitStepCompleted - specific job room
- ✅ emitStepOutput - workspace jobs room
- ✅ emitStepOutput - specific job room
Integration Tests (Future work)
- End-to-end subscription flow
- Multiple client subscriptions
- Event propagation from JobEventsService
Notes
Event Types from event-types.ts
// Job lifecycle
(JOB_CREATED, JOB_QUEUED, JOB_STARTED, JOB_COMPLETED, JOB_FAILED, JOB_CANCELLED);
// Step lifecycle
(STEP_STARTED, STEP_PROGRESS, STEP_OUTPUT, STEP_COMPLETED, STEP_FAILED);
// AI events
(AI_TOOL_CALLED, AI_TOKENS_USED, AI_ARTIFACT_CREATED);
// Gate events
(GATE_STARTED, GATE_PASSED, GATE_FAILED);
Design Decisions
- Reuse existing WebSocketGateway - extend rather than create new gateway
- Follow workspace-scoped room pattern - consistent with existing implementation
- Support both job-specific and workspace-level subscriptions - flexibility for UI
- Emit on database event creation - JobEventsService is source of truth
- Keep events immutable - events are append-only in database
Potential Issues
- Need to ensure JobEventsService can access WebSocketGateway (circular dependency?)
- May need EventEmitter pattern or direct injection