mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
This does ~95% of the backend work required to integrate the AI work. Most left to integrate from the tasks branch is just frontend, which will be a lot smaller I believe. The real difference between this branch and that one is the abstraction -- this now attaches statuses to apps, and returns the latest status reported as part of a workspace. This change enables us to have a similar UX to in the tasks branch, but for agents other than Claude Code as well. Any app can report status now.
73 lines
2.4 KiB
Go
73 lines
2.4 KiB
Go
package wspubsub
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
// WorkspaceEventChannel can be used to subscribe to events for
|
|
// workspaces owned by the provided user ID.
|
|
func WorkspaceEventChannel(ownerID uuid.UUID) string {
|
|
return fmt.Sprintf("workspace_owner:%s", ownerID)
|
|
}
|
|
|
|
func HandleWorkspaceEvent(cb func(ctx context.Context, payload WorkspaceEvent, err error)) func(ctx context.Context, message []byte, err error) {
|
|
return func(ctx context.Context, message []byte, err error) {
|
|
if err != nil {
|
|
cb(ctx, WorkspaceEvent{}, xerrors.Errorf("workspace event pubsub: %w", err))
|
|
return
|
|
}
|
|
var payload WorkspaceEvent
|
|
if err := json.Unmarshal(message, &payload); err != nil {
|
|
cb(ctx, WorkspaceEvent{}, xerrors.Errorf("unmarshal workspace event"))
|
|
return
|
|
}
|
|
if err := payload.Validate(); err != nil {
|
|
cb(ctx, payload, xerrors.Errorf("validate workspace event"))
|
|
return
|
|
}
|
|
cb(ctx, payload, err)
|
|
}
|
|
}
|
|
|
|
type WorkspaceEvent struct {
|
|
Kind WorkspaceEventKind `json:"kind"`
|
|
WorkspaceID uuid.UUID `json:"workspace_id" format:"uuid"`
|
|
// AgentID is only set for WorkspaceEventKindAgent* events
|
|
// (excluding AgentTimeout)
|
|
AgentID *uuid.UUID `json:"agent_id,omitempty" format:"uuid"`
|
|
}
|
|
|
|
type WorkspaceEventKind string
|
|
|
|
const (
|
|
WorkspaceEventKindStateChange WorkspaceEventKind = "state_change"
|
|
WorkspaceEventKindStatsUpdate WorkspaceEventKind = "stats_update"
|
|
WorkspaceEventKindMetadataUpdate WorkspaceEventKind = "mtd_update"
|
|
WorkspaceEventKindAppHealthUpdate WorkspaceEventKind = "app_health"
|
|
|
|
WorkspaceEventKindAgentLifecycleUpdate WorkspaceEventKind = "agt_lifecycle_update"
|
|
WorkspaceEventKindAgentConnectionUpdate WorkspaceEventKind = "agt_connection_update"
|
|
WorkspaceEventKindAgentFirstLogs WorkspaceEventKind = "agt_first_logs"
|
|
WorkspaceEventKindAgentLogsOverflow WorkspaceEventKind = "agt_logs_overflow"
|
|
WorkspaceEventKindAgentTimeout WorkspaceEventKind = "agt_timeout"
|
|
WorkspaceEventKindAgentAppStatusUpdate WorkspaceEventKind = "agt_app_status_update"
|
|
)
|
|
|
|
func (w *WorkspaceEvent) Validate() error {
|
|
if w.WorkspaceID == uuid.Nil {
|
|
return xerrors.New("workspaceID must be set")
|
|
}
|
|
if w.Kind == "" {
|
|
return xerrors.New("kind must be set")
|
|
}
|
|
if w.Kind == WorkspaceEventKindAgentLifecycleUpdate && w.AgentID == nil {
|
|
return xerrors.New("agentID must be set for Agent events")
|
|
}
|
|
return nil
|
|
}
|