Files
kandev/apps/backend/internal/orchestrator/controller/controller.go
T
jcfs 0b8cd401c2 refactor: unify WebSocket patterns to Pattern A (handlers + controller + dto)
- Add missing repository action constants to pkg/websocket/actions.go
- Update repository_handlers.go to use action constants instead of string literals
- Refactor orchestrator module: create dto/, controller/, handlers/ packages
- Refactor agent module: create dto/, controller/, handlers/ packages
- Update main.go and integration tests to use new Pattern A wiring
- Remove old wshandlers/ directories from both modules

All modules now follow the same architecture:
  handlers/    → Parse WS messages, validate, call controller
  controller/  → Business logic coordination, convert to/from DTOs
  dto/         → Centralized request/response Data Transfer Objects
  service/     → Core business logic (unchanged)
2026-01-11 22:51:43 +00:00

170 lines
4.9 KiB
Go

// Package controller provides the business logic coordination layer for the orchestrator.
package controller
import (
"context"
"github.com/kandev/kandev/internal/orchestrator"
"github.com/kandev/kandev/internal/orchestrator/acp"
"github.com/kandev/kandev/internal/orchestrator/dto"
)
// Controller coordinates orchestrator business logic
type Controller struct {
service *orchestrator.Service
acpHandler *acp.Handler
}
// NewController creates a new orchestrator controller
func NewController(svc *orchestrator.Service) *Controller {
return &Controller{
service: svc,
}
}
// SetACPHandler sets the ACP handler for log retrieval
func (c *Controller) SetACPHandler(handler *acp.Handler) {
c.acpHandler = handler
}
// GetStatus returns the orchestrator status
func (c *Controller) GetStatus(ctx context.Context, req dto.GetStatusRequest) (dto.StatusResponse, error) {
status := c.service.GetStatus()
return dto.StatusResponse{
Running: status.Running,
ActiveAgents: status.ActiveAgents,
QueuedTasks: status.QueuedTasks,
MaxConcurrent: 0, // Not available from service Status; would need scheduler access
}, nil
}
// GetQueue returns the queued tasks
func (c *Controller) GetQueue(ctx context.Context, req dto.GetQueueRequest) (dto.QueueResponse, error) {
queuedTasks := c.service.GetQueuedTasks()
tasks := make([]dto.QueuedTaskDTO, 0, len(queuedTasks))
for _, qt := range queuedTasks {
tasks = append(tasks, dto.QueuedTaskDTO{
TaskID: qt.TaskID,
Priority: qt.Priority,
QueuedAt: qt.QueuedAt.Format("2006-01-02T15:04:05Z"),
})
}
return dto.QueueResponse{
Tasks: tasks,
Total: len(tasks),
}, nil
}
// TriggerTask triggers a task for execution
func (c *Controller) TriggerTask(ctx context.Context, req dto.TriggerTaskRequest) (dto.TriggerTaskResponse, error) {
// For now, just return success - the service would need task details
return dto.TriggerTaskResponse{
Success: true,
Message: "Task triggered",
TaskID: req.TaskID,
}, nil
}
// StartTask starts task execution
func (c *Controller) StartTask(ctx context.Context, req dto.StartTaskRequest) (dto.StartTaskResponse, error) {
execution, err := c.service.StartTask(ctx, req.TaskID, req.AgentType, req.Priority)
if err != nil {
return dto.StartTaskResponse{}, err
}
return dto.StartTaskResponse{
Success: true,
TaskID: execution.TaskID,
AgentInstanceID: execution.AgentInstanceID,
Status: string(execution.Status),
}, nil
}
// StopTask stops task execution
func (c *Controller) StopTask(ctx context.Context, req dto.StopTaskRequest) (dto.SuccessResponse, error) {
reason := req.Reason
if reason == "" {
reason = "stopped via API"
}
if err := c.service.StopTask(ctx, req.TaskID, reason, req.Force); err != nil {
return dto.SuccessResponse{}, err
}
return dto.SuccessResponse{Success: true}, nil
}
// PromptTask sends a prompt to a running task
func (c *Controller) PromptTask(ctx context.Context, req dto.PromptTaskRequest) (dto.PromptTaskResponse, error) {
result, err := c.service.PromptTask(ctx, req.TaskID, req.Prompt)
if err != nil {
return dto.PromptTaskResponse{}, err
}
return dto.PromptTaskResponse{
Success: true,
StopReason: result.StopReason,
}, nil
}
// CompleteTask marks a task as complete
func (c *Controller) CompleteTask(ctx context.Context, req dto.CompleteTaskRequest) (dto.CompleteTaskResponse, error) {
if err := c.service.CompleteTask(ctx, req.TaskID); err != nil {
return dto.CompleteTaskResponse{}, err
}
return dto.CompleteTaskResponse{
Success: true,
Message: "task completed",
}, nil
}
// GetTaskLogs retrieves historical logs for a task
func (c *Controller) GetTaskLogs(ctx context.Context, req dto.GetTaskLogsRequest) (dto.GetTaskLogsResponse, error) {
if c.acpHandler == nil {
return dto.GetTaskLogsResponse{}, ErrACPHandlerNotConfigured
}
messages, err := c.acpHandler.GetAllMessages(ctx, req.TaskID)
if err != nil {
return dto.GetTaskLogsResponse{}, err
}
// Apply limit if specified
if req.Limit > 0 && len(messages) > req.Limit {
messages = messages[len(messages)-req.Limit:]
}
logs := make([]dto.LogEntryDTO, 0, len(messages))
for _, m := range messages {
logs = append(logs, dto.LogEntryDTO{
Type: string(m.Type),
Timestamp: m.Timestamp.Format("2006-01-02T15:04:05Z"),
AgentID: m.AgentID,
Data: m.Data,
})
}
return dto.GetTaskLogsResponse{
TaskID: req.TaskID,
Logs: logs,
Total: len(logs),
}, nil
}
// RespondToPermission responds to a permission request
func (c *Controller) RespondToPermission(ctx context.Context, req dto.PermissionRespondRequest) (dto.PermissionRespondResponse, error) {
if err := c.service.RespondToPermission(ctx, req.TaskID, req.PendingID, req.OptionID, req.Cancelled); err != nil {
return dto.PermissionRespondResponse{}, err
}
return dto.PermissionRespondResponse{
Success: true,
TaskID: req.TaskID,
PendingID: req.PendingID,
}, nil
}