Files
stack/docs/scratchpads/173-websocket-gateway.md
Jason Woltje 12abdfe81d feat(#93): implement agent spawn via federation
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>
2026-02-03 14:37:06 -06:00

120 lines
4.1 KiB
Markdown

# 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
1. **Extend WebSocketGateway** with job event emission methods
2. **Add subscription management** for job-specific and workspace-level job subscriptions
3. **Implement message handlers** for:
- `subscribe:job` - Subscribe to specific job events
- `subscribe:workspace:jobs` - Subscribe to all jobs in workspace
- `unsubscribe:job` - Unsubscribe from job
- `unsubscribe:workspace:jobs` - Unsubscribe from workspace jobs
4. **Add emit methods** for:
- `job:created` - New job created
- `job:status` - Job status change
- `job:progress` - Progress update (0-100%)
- `step:started` - Step started
- `step:completed` - Step completed
- `step:output` - Step output chunk
5. **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
1. Write tests for subscription handlers (RED)
2. Implement subscription handlers (GREEN)
3. Write tests for emit methods (RED)
4. Implement emit methods (GREEN)
5. Wire JobEventsService integration (if needed)
6. Refactor and cleanup
## Progress
- [x] Read existing WebSocket gateway implementation
- [x] Read JobEventsService and event types
- [x] Create scratchpad
- [x] Write tests for job event emit methods (TDD RED phase)
- [x] Implement job event emit methods (TDD GREEN phase)
- [x] All tests passing (22/22 tests)
- [x] TypeScript type checking passes for websocket module
- [x] Linting passes for websocket module
- [x] Run quality gates
- [x] 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
```typescript
// 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
1. **Reuse existing WebSocketGateway** - extend rather than create new gateway
2. **Follow workspace-scoped room pattern** - consistent with existing implementation
3. **Support both job-specific and workspace-level subscriptions** - flexibility for UI
4. **Emit on database event creation** - JobEventsService is source of truth
5. **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