// Package controller provides the business logic coordination layer for the agent module. package controller import ( "context" "github.com/kandev/kandev/internal/agent/dto" "github.com/kandev/kandev/internal/agent/lifecycle" "github.com/kandev/kandev/internal/agent/registry" ) // Controller coordinates agent business logic type Controller struct { lifecycle *lifecycle.Manager registry *registry.Registry } // NewController creates a new agent controller func NewController(lm *lifecycle.Manager, reg *registry.Registry) *Controller { return &Controller{ lifecycle: lm, registry: reg, } } // ListAgents returns all agent instances func (c *Controller) ListAgents(ctx context.Context, req dto.ListAgentsRequest) (dto.ListAgentsResponse, error) { if c.lifecycle == nil { return dto.ListAgentsResponse{}, ErrLifecycleManagerNotAvailable } agents := c.lifecycle.ListExecutions() resp := dto.ListAgentsResponse{ Agents: make([]dto.AgentDTO, 0, len(agents)), Total: len(agents), } for _, a := range agents { agent := dto.FromAgentExecution(&dto.AgentExecutionData{ ID: a.ID, TaskID: a.TaskID, AgentProfileID: a.AgentProfileID, ContainerID: a.ContainerID, Status: string(a.Status), StartedAt: a.StartedAt, FinishedAt: a.FinishedAt, ExitCode: a.ExitCode, ErrorMessage: a.ErrorMessage, }) resp.Agents = append(resp.Agents, agent) } return resp, nil } // LaunchAgent launches a new agent instance func (c *Controller) LaunchAgent(ctx context.Context, req dto.LaunchAgentRequest) (dto.LaunchAgentResponse, error) { if c.lifecycle == nil { return dto.LaunchAgentResponse{}, ErrLifecycleManagerNotAvailable } launchReq := &lifecycle.LaunchRequest{ TaskID: req.TaskID, AgentProfileID: req.AgentProfileID, WorkspacePath: req.WorkspacePath, Env: req.Env, } execution, err := c.lifecycle.Launch(ctx, launchReq) if err != nil { return dto.LaunchAgentResponse{}, err } return dto.LaunchAgentResponse{ Success: true, AgentID: execution.ID, TaskID: req.TaskID, }, nil } // GetAgentStatus returns the status of a specific agent func (c *Controller) GetAgentStatus(ctx context.Context, req dto.GetAgentStatusRequest) (dto.AgentDTO, error) { if c.lifecycle == nil { return dto.AgentDTO{}, ErrLifecycleManagerNotAvailable } agent, found := c.lifecycle.GetExecution(req.AgentID) if !found { return dto.AgentDTO{}, ErrAgentNotFound } return dto.FromAgentExecution(&dto.AgentExecutionData{ ID: agent.ID, TaskID: agent.TaskID, AgentProfileID: agent.AgentProfileID, ContainerID: agent.ContainerID, Status: string(agent.Status), StartedAt: agent.StartedAt, FinishedAt: agent.FinishedAt, ExitCode: agent.ExitCode, ErrorMessage: agent.ErrorMessage, }), nil } // GetAgentLogs returns logs for a specific agent func (c *Controller) GetAgentLogs(ctx context.Context, req dto.GetAgentLogsRequest) (dto.GetAgentLogsResponse, error) { if c.lifecycle == nil { return dto.GetAgentLogsResponse{}, ErrLifecycleManagerNotAvailable } _, found := c.lifecycle.GetExecution(req.AgentID) if !found { return dto.GetAgentLogsResponse{}, ErrAgentNotFound } // Note: Log retrieval requires Docker client access which is not available here return dto.GetAgentLogsResponse{ AgentID: req.AgentID, Logs: []string{}, Message: "Use HTTP API for full log retrieval", }, nil } // StopAgent stops a running agent func (c *Controller) StopAgent(ctx context.Context, req dto.StopAgentRequest) (dto.SuccessResponse, error) { if c.lifecycle == nil { return dto.SuccessResponse{}, ErrLifecycleManagerNotAvailable } if err := c.lifecycle.StopAgent(ctx, req.AgentID, false); err != nil { return dto.SuccessResponse{}, err } return dto.SuccessResponse{Success: true}, nil } // ListAgentTypes returns all available agent types func (c *Controller) ListAgentTypes(ctx context.Context, req dto.ListAgentTypesRequest) (dto.ListAgentTypesResponse, error) { if c.registry == nil { return dto.ListAgentTypesResponse{}, ErrRegistryNotAvailable } types := c.registry.List() resp := dto.ListAgentTypesResponse{ Types: make([]dto.AgentTypeDTO, 0, len(types)), Total: len(types), } for _, t := range types { var image string if rt := t.Runtime(); rt != nil { image = rt.Image } resp.Types = append(resp.Types, dto.FromAgentType(&dto.AgentTypeData{ ID: t.ID(), Name: t.Name(), Description: t.Description(), Image: image, Enabled: t.Enabled(), })) } return resp, nil }