molecule-core/docs/api-protocol/websocket-events.md
Hongming Wang 24fec62d7f initial commit — Molecule AI platform
Forked clean from public hackathon repo (Starfire-AgentTeam, BSL 1.1)
with full rebrand to Molecule AI under github.com/Molecule-AI/molecule-monorepo.

Brand: Starfire → Molecule AI.
Slug: starfire / agent-molecule → molecule.
Env vars: STARFIRE_* → MOLECULE_*.
Go module: github.com/agent-molecule/platform → github.com/Molecule-AI/molecule-monorepo/platform.
Python packages: starfire_plugin → molecule_plugin, starfire_agent → molecule_agent.
DB: agentmolecule → molecule.

History truncated; see public repo for prior commits and contributor
attribution. Verified green: go test -race ./... (platform), pytest
(workspace-template 1129 + sdk 132), vitest (canvas 352), build (mcp).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 11:55:37 -07:00

336 lines
7.4 KiB
Markdown

# WebSocket Events
The canvas subscribes to the platform's WebSocket at `/ws` and receives real-time structure events as JSON messages.
## Message Format
Every WebSocket message has this structure:
```json
{
"event": "EVENT_TYPE",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": { ... }
}
```
## Event Reference
### WORKSPACE_PROVISIONING
Workspace is being spun up. Canvas shows a spinner on the node.
```json
{
"event": "WORKSPACE_PROVISIONING",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"name": "Vancouver SEO Agent",
"tier": 1,
"config": "seo-agent"
}
}
```
### WORKSPACE_ONLINE
First heartbeat received, or workspace returned from offline.
```json
{
"event": "WORKSPACE_ONLINE",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"url": "http://ws-abc-123:8000",
"agent_card": {
"name": "Vancouver SEO Agent",
"version": "1.0.0",
"skills": ["generate-seo-page", "audit-seo-page"],
"capabilities": { "streaming": true }
}
}
}
```
### WORKSPACE_OFFLINE
Heartbeat TTL expired. Node turns gray.
```json
{
"event": "WORKSPACE_OFFLINE",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:01:00Z",
"payload": {}
}
```
### WORKSPACE_PROVISION_FAILED
Provisioning timed out or errored. Node turns red with retry button.
```json
{
"event": "WORKSPACE_PROVISION_FAILED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:03:00Z",
"payload": {
"reason": "provisioning timeout -- no heartbeat received"
}
}
```
### WORKSPACE_DEGRADED
Workspace is online but experiencing errors. Node shows warning indicator.
```json
{
"event": "WORKSPACE_DEGRADED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:05:00Z",
"payload": {
"error_rate": 0.87,
"sample_error": "anthropic API rate limit exceeded"
}
}
```
### WORKSPACE_REMOVED
User deleted the workspace. Node removed from canvas.
```json
{
"event": "WORKSPACE_REMOVED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:10:00Z",
"payload": {
"forwarded_to": null
}
}
```
### AGENT_REPLACED
AI model swapped inside a workspace.
```json
{
"event": "AGENT_REPLACED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"old_model": "anthropic:claude-sonnet-4-6",
"new_model": "openai:gpt-4o"
}
}
```
### AGENT_CARD_UPDATED
Workspace republished its Agent Card (new skill added, description changed, capabilities changed). The platform broadcasts this to all peer workspaces (siblings, children, parent) so they can rebuild their system prompts.
```json
{
"event": "AGENT_CARD_UPDATED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"agent_card": {
"name": "Vancouver SEO Agent",
"version": "1.1.0",
"skills": ["generate-seo-page", "audit-seo-page", "monitor-rankings"],
"capabilities": { "streaming": true }
}
}
}
```
### WORKSPACE_EXPANDED
Workspace expanded into a team of sub-workspaces.
```json
{
"event": "WORKSPACE_EXPANDED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"sub_workspace_ids": [
"ws-frontend-001",
"ws-backend-001",
"ws-qa-001"
]
}
}
```
### WORKSPACE_COLLAPSED
Team collapsed back to a single agent. Sub-workspaces are stopped and removed.
```json
{
"event": "WORKSPACE_COLLAPSED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"removed_sub_workspace_ids": [
"ws-frontend-001",
"ws-backend-001",
"ws-qa-001"
]
}
}
```
### WORKSPACE_MOVED
Workspace moved to a new parent (dragged into a different team on canvas).
```json
{
"event": "WORKSPACE_MOVED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"old_parent_id": "ws-team-a",
"new_parent_id": "ws-team-b"
}
}
```
### AGENT_ASSIGNED
A new AI agent assigned to a workspace (first time or after removal).
```json
{
"event": "AGENT_ASSIGNED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"agent_id": "agent-xyz-789",
"model": "anthropic:claude-sonnet-4-6"
}
}
```
### AGENT_REMOVED
Agent removed from a workspace (workspace becomes empty).
```json
{
"event": "AGENT_REMOVED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"agent_id": "agent-xyz-789",
"reason": "user removed"
}
}
```
### AGENT_MOVED
Agent moved from one workspace to another.
```json
{
"event": "AGENT_MOVED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"agent_id": "agent-xyz-789",
"from_workspace_id": "ws-abc-123",
"to_workspace_id": "ws-def-456"
}
}
```
### TASK_UPDATED
Agent's current task changed (via heartbeat). WebSocket-only — not persisted to `structure_events`.
```json
{
"event": "TASK_UPDATED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"current_task": "Analyzing quarterly report",
"active_tasks": 2
}
}
```
Canvas shows the current task as an amber banner on the workspace node and side panel header. Only broadcast when the task actually changes (not on every heartbeat).
### ACTIVITY_LOGGED
New activity log entry created (A2A communication, webhook-triggered task ingress, agent log, error). WebSocket-only — not persisted to `structure_events` (stored in `activity_logs` table instead).
```json
{
"event": "ACTIVITY_LOGGED",
"workspace_id": "ws-abc-123",
"timestamp": "2026-03-30T12:00:00Z",
"payload": {
"activity_type": "a2a_receive",
"method": "message/send",
"summary": "message/send → ws-abc-123",
"status": "ok",
"source_id": "ws-def-456",
"target_id": "ws-abc-123",
"duration_ms": 1500
}
}
```
Canvas ActivityTab uses this event as a refresh hint. The event is informational — the full activity details (request/response bodies) are fetched via `GET /workspaces/:id/activity`.
## Subscribers
Both canvas clients and workspace agents subscribe to the same WebSocket endpoint (`/ws`):
| Subscriber | Identifies via | Receives | Purpose |
|------------|---------------|----------|---------|
| Canvas client | No header (unrestricted) | All events | UI updates |
| Workspace agent | `X-Workspace-ID` header | Filtered — only events about reachable peers | System prompt rebuilds |
The platform filters server-side using `CanCommunicate()` — each workspace only receives events about workspaces it can talk to.
## Event Flow
```
Structure change occurs
|
v
Platform writes event to structure_events (Postgres)
|
v
Platform publishes to Redis pub/sub (events:broadcast)
|
v
WebSocket handler receives from Redis
|
v
WebSocket pushes JSON to subscribers (filtered per workspace)
|
+-> Canvas clients: update Zustand state -> React Flow re-renders
+-> Workspace agents: rebuild system prompt if peer changed
```
## Related Docs
- [Canvas UI](../frontend/canvas.md) — How events drive the UI
- [Event Log](../architecture/event-log.md) — Persistent event storage
- [Registry & Heartbeat](./registry-and-heartbeat.md) — Events from registration
- [Provisioner](../architecture/provisioner.md) — Events from provisioning
- [Communication Rules](./communication-rules.md) — Hierarchy-based peer broadcasting