package service import ( "log/slog" "codespace/internal/acp" "codespace/internal/model" "codespace/internal/process" "codespace/internal/workspace" ) // AcpService wraps the low-level acp.Service with logging and model mapping. type AcpService struct { svc acp.Service lg *slog.Logger } // NewAcpService creates an AcpService. // If lg is nil, slog.Default() is used. func NewAcpService(processes process.Manager, workspaces workspace.Manager, lg *slog.Logger) *AcpService { if lg == nil { lg = slog.Default() } return &AcpService{svc: acp.NewService(processes, workspaces, lg), lg: lg} } // Status returns the ACP status for the workspace. func (s *AcpService) Status(workspaceID string) (model.AcpStatusResponse, error) { status, err := s.svc.Status(workspaceID) if err != nil { s.lg.Error("acp status failed", "workspace_id", workspaceID, "error", err) return model.AcpStatusResponse{}, err } return model.AcpStatusResponse{ WorkspaceID: status.WorkspaceID, Ready: status.Ready, SessionID: status.SessionID, Running: status.Running, PID: status.PID, Error: status.Error, }, nil } // History returns the ACP conversation history for the workspace. func (s *AcpService) History(workspaceID string) (model.AcpHistoryResponse, error) { hist, err := s.svc.History(workspaceID) if err != nil { s.lg.Error("acp history failed", "workspace_id", workspaceID, "error", err) return model.AcpHistoryResponse{}, err } messages := make([]model.AcpMessage, len(hist.Messages)) for i, m := range hist.Messages { messages[i] = model.AcpMessage{Role: m.Role, Text: m.Text, Time: m.Time} } return model.AcpHistoryResponse{SessionID: hist.SessionID, Messages: messages}, nil } // Prompt sends a prompt to the agent and returns its response. func (s *AcpService) Prompt(workspaceID string, content string) (model.AcpPromptResponse, error) { res, err := s.svc.Prompt(workspaceID, content) if err != nil { s.lg.Error("acp prompt failed", "workspace_id", workspaceID, "error", err) return model.AcpPromptResponse{}, err } return model.AcpPromptResponse{ SessionID: res.SessionID, StopReason: res.StopReason, Text: res.Text, }, nil } // Cancel interrupts an in-flight prompt. func (s *AcpService) Cancel(workspaceID string) error { if err := s.svc.Cancel(workspaceID); err != nil { s.lg.Error("acp cancel failed", "workspace_id", workspaceID, "error", err) return err } return nil } // EnsureReady ensures the ACP process is started and initialized. func (s *AcpService) EnsureReady(workspaceID string) error { if err := s.svc.EnsureReady(workspaceID); err != nil { s.lg.Error("acp ensure ready failed", "workspace_id", workspaceID, "error", err) return err } return nil }