Files
tutti/services/tuttid/api/daemon_tutti_mode_execution.go
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

203 lines
7.4 KiB
Go

package api
import (
"context"
"errors"
"time"
tuttigenerated "github.com/tutti-os/tutti/services/tuttid/api/generated"
"github.com/tutti-os/tutti/services/tuttid/apierrors"
executionbiz "github.com/tutti-os/tutti/services/tuttid/biz/tuttimodeexecution"
tuttimodeexecutionservice "github.com/tutti-os/tutti/services/tuttid/service/tuttimodeexecution"
)
type TuttiModeExecutionService interface {
Archive(context.Context, tuttimodeexecutionservice.ArchiveInput) (executionbiz.ArchiveOperation, error)
GetArchive(context.Context, string, string) (executionbiz.ArchiveOperation, error)
}
func (api DaemonAPI) CancelTuttiModeExecution(
ctx context.Context,
request tuttigenerated.CancelTuttiModeExecutionRequestObject,
) (tuttigenerated.CancelTuttiModeExecutionResponseObject, error) {
if api.IssueExecutionService == nil {
return tuttigenerated.CancelTuttiModeExecution503JSONResponse{
ServiceUnavailableErrorJSONResponse: serviceUnavailableError(
apierrors.ServiceUnavailable("issue_execution_service_unavailable"),
),
}, nil
}
canceled, err := api.IssueExecutionService.CancelTuttiModeIssueExecution(
ctx,
string(request.WorkspaceID),
string(request.IssueID),
)
if err != nil {
return cancelTuttiModeExecutionError(err), nil
}
return tuttigenerated.CancelTuttiModeExecution200JSONResponse{
CanceledRunCount: canceled,
}, nil
}
func (api DaemonAPI) ArchiveTuttiModeExecution(
ctx context.Context,
request tuttigenerated.ArchiveTuttiModeExecutionRequestObject,
) (tuttigenerated.ArchiveTuttiModeExecutionResponseObject, error) {
if api.TuttiModeExecutionService == nil {
return tuttigenerated.ArchiveTuttiModeExecution503JSONResponse{
ServiceUnavailableErrorJSONResponse: serviceUnavailableError(
apierrors.ServiceUnavailable("tutti_mode_execution_service_unavailable"),
),
}, nil
}
if request.Body == nil {
return tuttigenerated.ArchiveTuttiModeExecution400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(
apierrors.InvalidRequest(apierrors.ReasonMalformedRequest),
),
}, nil
}
operation, err := api.TuttiModeExecutionService.Archive(ctx, tuttimodeexecutionservice.ArchiveInput{
WorkspaceID: string(request.WorkspaceID), IssueID: string(request.IssueID),
RequestID: request.Body.RequestId, RequestedBy: authenticatedLocalOperatorActorID,
Reason: request.Body.Reason,
})
if err != nil && operation.OperationID == "" {
return archiveTuttiModeExecutionError(err), nil
}
return tuttigenerated.ArchiveTuttiModeExecution200JSONResponse(
generatedTuttiModeArchiveOperation(operation),
), nil
}
func cancelTuttiModeExecutionError(
err error,
) tuttigenerated.CancelTuttiModeExecutionResponseObject {
protocolErr := apierrors.Classify(err)
switch protocolErr.Code {
case tuttigenerated.InvalidRequest:
return tuttigenerated.CancelTuttiModeExecution400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(protocolErr),
}
case tuttigenerated.WorkspaceIssueResourceNotFound:
return tuttigenerated.CancelTuttiModeExecution404JSONResponse{
WorkspaceIssueResourceNotFoundErrorJSONResponse: workspaceIssueResourceNotFoundError(protocolErr),
}
case tuttigenerated.ServiceUnavailable:
return tuttigenerated.CancelTuttiModeExecution503JSONResponse{
ServiceUnavailableErrorJSONResponse: serviceUnavailableError(protocolErr),
}
default:
return tuttigenerated.CancelTuttiModeExecution502JSONResponse{
WorkspaceOperationErrorJSONResponse: workspaceOperationError(protocolErr),
}
}
}
func (api DaemonAPI) GetTuttiModeArchiveOperation(
ctx context.Context,
request tuttigenerated.GetTuttiModeArchiveOperationRequestObject,
) (tuttigenerated.GetTuttiModeArchiveOperationResponseObject, error) {
if api.TuttiModeExecutionService == nil {
return tuttigenerated.GetTuttiModeArchiveOperation503JSONResponse{
ServiceUnavailableErrorJSONResponse: serviceUnavailableError(
apierrors.ServiceUnavailable("tutti_mode_execution_service_unavailable"),
),
}, nil
}
operation, err := api.TuttiModeExecutionService.GetArchive(
ctx, string(request.WorkspaceID), request.Params.OperationId,
)
if err != nil {
if errors.Is(err, executionbiz.ErrExecutionNotFound) {
protocolErr := apierrors.New(
apierrors.StatusWorkspaceIssueNotFound,
tuttigenerated.WorkspaceIssueResourceNotFound,
apierrors.ReasonWorkspaceIssueNotFound,
apierrors.WithCause(err),
)
return tuttigenerated.GetTuttiModeArchiveOperation404JSONResponse{
WorkspaceIssueResourceNotFoundErrorJSONResponse: workspaceIssueResourceNotFoundError(protocolErr),
}, nil
}
return tuttigenerated.GetTuttiModeArchiveOperation502JSONResponse{
WorkspaceOperationErrorJSONResponse: workspaceOperationError(apierrors.Classify(err)),
}, nil
}
if operation.IssueID != string(request.IssueID) {
protocolErr := apierrors.New(
apierrors.StatusWorkspaceIssueNotFound,
tuttigenerated.WorkspaceIssueResourceNotFound,
apierrors.ReasonWorkspaceIssueNotFound,
apierrors.WithCause(executionbiz.ErrExecutionNotFound),
)
return tuttigenerated.GetTuttiModeArchiveOperation404JSONResponse{
WorkspaceIssueResourceNotFoundErrorJSONResponse: workspaceIssueResourceNotFoundError(protocolErr),
}, nil
}
return tuttigenerated.GetTuttiModeArchiveOperation200JSONResponse(
generatedTuttiModeArchiveOperation(operation),
), nil
}
func generatedTuttiModeArchiveOperation(
operation executionbiz.ArchiveOperation,
) tuttigenerated.TuttiModeArchiveOperation {
return tuttigenerated.TuttiModeArchiveOperation{
WorkspaceId: operation.WorkspaceID, ExecutionId: operation.ExecutionID,
IssueId: operation.IssueID, OperationId: operation.OperationID,
RequestId: operation.RequestID,
Status: tuttigenerated.TuttiModeArchiveOperationStatus(operation.Status),
RequestedBy: operation.RequestedBy, Reason: operation.Reason,
AttemptCount: operation.AttemptCount, LastError: operation.LastError,
CreatedAtUnixMs: operation.CreatedAt.UnixMilli(),
UpdatedAtUnixMs: operation.UpdatedAt.UnixMilli(),
CompletedAtUnixMs: archiveOperationUnixMilli(operation.CompletedAt),
}
}
func archiveOperationUnixMilli(value time.Time) int64 {
if value.IsZero() {
return 0
}
return value.UnixMilli()
}
func archiveTuttiModeExecutionError(
err error,
) tuttigenerated.ArchiveTuttiModeExecutionResponseObject {
if errors.Is(err, executionbiz.ErrInvalidExecution) {
return tuttigenerated.ArchiveTuttiModeExecution400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(apierrors.Classify(err)),
}
}
if errors.Is(err, executionbiz.ErrExecutionNotFound) {
protocolErr := apierrors.New(
apierrors.StatusWorkspaceIssueNotFound,
tuttigenerated.WorkspaceIssueResourceNotFound,
apierrors.ReasonWorkspaceIssueNotFound,
apierrors.WithCause(err),
)
return tuttigenerated.ArchiveTuttiModeExecution404JSONResponse{
WorkspaceIssueResourceNotFoundErrorJSONResponse: workspaceIssueResourceNotFoundError(protocolErr),
}
}
if errors.Is(err, executionbiz.ErrExecutionConflict) {
protocolErr := apierrors.New(
apierrors.StatusWorkspaceIssueExists,
tuttigenerated.TuttiModeArchiveConflict,
"tutti_archive_request_conflict",
apierrors.WithCause(err),
)
return tuttigenerated.ArchiveTuttiModeExecution409JSONResponse{
TuttiModeArchiveConflictErrorJSONResponse: tuttigenerated.TuttiModeArchiveConflictErrorJSONResponse(
protocolErrorResponse(protocolErr),
),
}
}
return tuttigenerated.ArchiveTuttiModeExecution502JSONResponse{
WorkspaceOperationErrorJSONResponse: workspaceOperationError(apierrors.Classify(err)),
}
}