35915ff0cb
- Remove all REST endpoints, replace with WebSocket message-based API
- Add WebSocket gateway with Hub and Client for connection management
- Add WebSocket handlers for Task, Agent, and Orchestrator services
- Add task subscription support for real-time ACP notifications
- Update all documentation to reflect WebSocket-first architecture
- Replace docs/openapi.yaml with docs/asyncapi.yaml
- Update e2e tests to use WebSocket via websocat
WebSocket endpoint: ws://localhost:8080/ws
Message format: {id, type, action, payload, timestamp}
Available actions:
- Board: board.list, board.create, board.get, board.update, board.delete
- Column: column.list, column.create, column.get
- Task: task.list, task.create, task.get, task.update, task.delete,
task.move, task.state, task.subscribe, task.unsubscribe
- Agent: agent.list, agent.launch, agent.status, agent.logs, agent.stop,
agent.prompt, agent.cancel, agent.session, agent.types
- Orchestrator: orchestrator.status, orchestrator.queue, orchestrator.trigger,
orchestrator.start, orchestrator.stop, orchestrator.prompt,
orchestrator.complete
- Health: health.check
132 lines
3.4 KiB
Go
132 lines
3.4 KiB
Go
// Package websocket provides WebSocket message types and protocol definitions.
|
|
package websocket
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
)
|
|
|
|
// MessageType represents the type of WebSocket message
|
|
type MessageType string
|
|
|
|
const (
|
|
MessageTypeRequest MessageType = "request"
|
|
MessageTypeResponse MessageType = "response"
|
|
MessageTypeNotification MessageType = "notification"
|
|
MessageTypeError MessageType = "error"
|
|
)
|
|
|
|
// Message is the base envelope for all WebSocket messages
|
|
type Message struct {
|
|
ID string `json:"id,omitempty"`
|
|
Type MessageType `json:"type"`
|
|
Action string `json:"action"`
|
|
Payload json.RawMessage `json:"payload"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
}
|
|
|
|
// Request represents a client request message
|
|
type Request struct {
|
|
ID string `json:"id"`
|
|
Type MessageType `json:"type"`
|
|
Action string `json:"action"`
|
|
Payload json.RawMessage `json:"payload"`
|
|
}
|
|
|
|
// Response represents a server response message
|
|
type Response struct {
|
|
ID string `json:"id"`
|
|
Type MessageType `json:"type"`
|
|
Action string `json:"action"`
|
|
Payload json.RawMessage `json:"payload,omitempty"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
}
|
|
|
|
// Notification represents a server push notification
|
|
type Notification struct {
|
|
Type MessageType `json:"type"`
|
|
Action string `json:"action"`
|
|
Payload json.RawMessage `json:"payload"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
}
|
|
|
|
// ErrorPayload represents an error response payload
|
|
type ErrorPayload struct {
|
|
Code string `json:"code"`
|
|
Message string `json:"message"`
|
|
Details map[string]interface{} `json:"details,omitempty"`
|
|
}
|
|
|
|
// NewRequest creates a new request message
|
|
func NewRequest(id, action string, payload interface{}) (*Message, error) {
|
|
data, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Message{
|
|
ID: id,
|
|
Type: MessageTypeRequest,
|
|
Action: action,
|
|
Payload: data,
|
|
Timestamp: time.Now().UTC(),
|
|
}, nil
|
|
}
|
|
|
|
// NewResponse creates a new response message
|
|
func NewResponse(id, action string, payload interface{}) (*Message, error) {
|
|
data, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Message{
|
|
ID: id,
|
|
Type: MessageTypeResponse,
|
|
Action: action,
|
|
Payload: data,
|
|
Timestamp: time.Now().UTC(),
|
|
}, nil
|
|
}
|
|
|
|
// NewNotification creates a new notification message
|
|
func NewNotification(action string, payload interface{}) (*Message, error) {
|
|
data, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Message{
|
|
Type: MessageTypeNotification,
|
|
Action: action,
|
|
Payload: data,
|
|
Timestamp: time.Now().UTC(),
|
|
}, nil
|
|
}
|
|
|
|
// NewError creates a new error response message
|
|
func NewError(id, action, code, message string, details map[string]interface{}) (*Message, error) {
|
|
payload := ErrorPayload{
|
|
Code: code,
|
|
Message: message,
|
|
Details: details,
|
|
}
|
|
data, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Message{
|
|
ID: id,
|
|
Type: MessageTypeError,
|
|
Action: action,
|
|
Payload: data,
|
|
Timestamp: time.Now().UTC(),
|
|
}, nil
|
|
}
|
|
|
|
// ParsePayload parses the payload into the given struct
|
|
func (m *Message) ParsePayload(v interface{}) error {
|
|
if m.Payload == nil {
|
|
return nil
|
|
}
|
|
return json.Unmarshal(m.Payload, v)
|
|
}
|
|
|