Files
tutti/services/tuttid/api/daemon_agent_plan_decisions.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

108 lines
4.1 KiB
Go

package api
import (
"context"
"errors"
"strings"
agentactivitybiz "github.com/tutti-os/tutti/packages/agent/store-sqlite"
tuttigenerated "github.com/tutti-os/tutti/services/tuttid/api/generated"
"github.com/tutti-os/tutti/services/tuttid/apierrors"
agentservice "github.com/tutti-os/tutti/services/tuttid/service/agent"
)
type agentPlanDecisionService interface {
SubmitPlanDecision(context.Context, string, string, string, string, agentservice.SubmitPlanDecisionInput) (agentactivitybiz.RuntimeOperation, error)
}
func (api DaemonAPI) SubmitWorkspaceAgentPlanDecision(
ctx context.Context,
request tuttigenerated.SubmitWorkspaceAgentPlanDecisionRequestObject,
) (tuttigenerated.SubmitWorkspaceAgentPlanDecisionResponseObject, error) {
service, ok := api.AgentSessionService.(agentPlanDecisionService)
if !ok {
return tuttigenerated.SubmitWorkspaceAgentPlanDecision503JSONResponse{
ServiceUnavailableErrorJSONResponse: agentSessionServiceUnavailableError(),
}, nil
}
if request.Body == nil {
return tuttigenerated.SubmitWorkspaceAgentPlanDecision400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(apierrors.EmptyBody(apierrors.WithDeveloperMessage("empty body"))),
}, nil
}
operation, err := service.SubmitPlanDecision(
ctx,
string(request.WorkspaceID),
string(request.AgentSessionID),
string(request.TurnID),
string(request.RequestID),
agentservice.SubmitPlanDecisionInput{
PromptKind: string(request.Body.PromptKind),
Action: string(request.Body.Action),
IdempotencyKey: request.Body.IdempotencyKey,
},
)
if err != nil {
return writeSubmitWorkspaceAgentPlanDecisionError(err), nil
}
if !isRendererEngineCommandOrigin(
request.Params.XTuttiAgentCommandOrigin,
) {
api.recordAgentStimulus(ctx, "plan.decision", string(request.WorkspaceID), string(request.AgentSessionID), map[string]any{
"turnId": string(request.TurnID),
"requestId": string(request.RequestID),
"promptKind": request.Body.PromptKind,
"action": request.Body.Action,
"idempotencyKey": request.Body.IdempotencyKey,
})
}
return tuttigenerated.SubmitWorkspaceAgentPlanDecision200JSONResponse{
Operation: generatedPlanDecisionOperation(operation),
}, nil
}
func generatedPlanDecisionOperation(operation agentactivitybiz.RuntimeOperation) tuttigenerated.WorkspaceAgentPlanDecisionOperation {
result := tuttigenerated.WorkspaceAgentPlanDecisionOperation{
OperationId: operation.OperationID,
WorkspaceId: operation.WorkspaceID,
AgentSessionId: operation.AgentSessionID,
TurnId: operation.TurnID,
RequestId: operation.RequestID,
IdempotencyKey: payloadStringValue(operation.Payload, "idempotencyKey"),
Status: tuttigenerated.WorkspaceAgentPlanDecisionOperationStatus(operation.Status),
}
if value := strings.TrimSpace(operation.Result); value != "" {
result.Result = &value
}
if value := strings.TrimSpace(operation.LastError); value != "" {
result.Error = &value
}
return result
}
func writeSubmitWorkspaceAgentPlanDecisionError(err error) tuttigenerated.SubmitWorkspaceAgentPlanDecisionResponseObject {
protocolErr := apierrors.Classify(err)
if errors.Is(err, agentactivitybiz.ErrRuntimeOperationConflict) || errors.Is(err, agentactivitybiz.ErrRuntimeOperationSubjectState) {
return tuttigenerated.SubmitWorkspaceAgentPlanDecision409JSONResponse(protocolErrorResponse(protocolErr))
}
switch protocolErr.Code {
case tuttigenerated.InvalidRequest:
return tuttigenerated.SubmitWorkspaceAgentPlanDecision400JSONResponse{
InvalidRequestErrorJSONResponse: invalidRequestError(protocolErr),
}
case tuttigenerated.WorkspaceNotFound:
return tuttigenerated.SubmitWorkspaceAgentPlanDecision404JSONResponse{
WorkspaceNotFoundErrorJSONResponse: workspaceNotFoundError(protocolErr),
}
default:
return tuttigenerated.SubmitWorkspaceAgentPlanDecision502JSONResponse{
WorkspaceOperationErrorJSONResponse: workspaceOperationError(protocolErr),
}
}
}
func payloadStringValue(payload map[string]any, key string) string {
value, _ := payload[key].(string)
return strings.TrimSpace(value)
}