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

231 lines
14 KiB
Go

package api
import (
"context"
"errors"
"net/http"
tuttigenerated "github.com/tutti-os/tutti/services/tuttid/api/generated"
"github.com/tutti-os/tutti/services/tuttid/apierrors"
automationrulebiz "github.com/tutti-os/tutti/services/tuttid/biz/automationrule"
workspacedata "github.com/tutti-os/tutti/services/tuttid/data/workspace"
automationruleservice "github.com/tutti-os/tutti/services/tuttid/service/automationrule"
)
type AutomationRuleService interface {
ListRules(context.Context, string) ([]automationrulebiz.Rule, error)
GetRule(context.Context, string, string) (automationrulebiz.Rule, error)
CreateRule(context.Context, automationruleservice.PutRuleInput) (automationrulebiz.Rule, error)
UpdateRule(context.Context, automationruleservice.PutRuleInput) (automationrulebiz.Rule, error)
DeleteRule(context.Context, string, string) error
GetSessionOverride(context.Context, string, string) (automationrulebiz.SessionOverride, bool, error)
SetSessionOverride(context.Context, automationrulebiz.SessionOverride) (automationrulebiz.SessionOverride, error)
}
func (api DaemonAPI) ListAutomationRules(ctx context.Context, request tuttigenerated.ListAutomationRulesRequestObject) (tuttigenerated.ListAutomationRulesResponseObject, error) {
if api.AutomationRuleService == nil {
return tuttigenerated.ListAutomationRules503JSONResponse{ServiceUnavailableErrorJSONResponse: automationRuleServiceUnavailable()}, nil
}
rules, err := api.AutomationRuleService.ListRules(ctx, request.WorkspaceID)
if err != nil {
return tuttigenerated.ListAutomationRules502JSONResponse{WorkspaceOperationErrorJSONResponse: workspaceOperationError(apierrors.WorkspaceOperationFailed(apierrors.WithCause(err)))}, nil
}
response := tuttigenerated.ListAutomationRulesResponse{Rules: make([]tuttigenerated.AutomationRule, 0, len(rules))}
for _, rule := range rules {
response.Rules = append(response.Rules, generatedAutomationRule(rule))
}
return tuttigenerated.ListAutomationRules200JSONResponse(response), nil
}
func (api DaemonAPI) CreateAutomationRule(ctx context.Context, request tuttigenerated.CreateAutomationRuleRequestObject) (tuttigenerated.CreateAutomationRuleResponseObject, error) {
if !api.automationRulesWritesEnabled(ctx) {
return tuttigenerated.CreateAutomationRule400JSONResponse{InvalidRequestErrorJSONResponse: automationRulesWriteDisabledError()}, nil
}
if api.AutomationRuleService == nil {
return tuttigenerated.CreateAutomationRule503JSONResponse{ServiceUnavailableErrorJSONResponse: automationRuleServiceUnavailable()}, nil
}
if request.Body == nil {
return tuttigenerated.CreateAutomationRule400JSONResponse{InvalidRequestErrorJSONResponse: invalidRequestError(apierrors.EmptyBody())}, nil
}
rule, err := api.AutomationRuleService.CreateRule(ctx, automationRulePutInput(request.WorkspaceID, "", *request.Body))
if err != nil {
return createAutomationRuleError(err), nil
}
return tuttigenerated.CreateAutomationRule201JSONResponse(generatedAutomationRule(rule)), nil
}
func (api DaemonAPI) GetAutomationRule(ctx context.Context, request tuttigenerated.GetAutomationRuleRequestObject) (tuttigenerated.GetAutomationRuleResponseObject, error) {
if api.AutomationRuleService == nil {
return tuttigenerated.GetAutomationRule503JSONResponse{ServiceUnavailableErrorJSONResponse: automationRuleServiceUnavailable()}, nil
}
rule, err := api.AutomationRuleService.GetRule(ctx, request.WorkspaceID, request.AutomationRuleID)
if err != nil {
if errors.Is(err, workspacedata.ErrAutomationRuleNotFound) {
return tuttigenerated.GetAutomationRule404JSONResponse{WorkspaceNotFoundErrorJSONResponse: automationRuleNotFoundError()}, nil
}
return tuttigenerated.GetAutomationRule502JSONResponse{WorkspaceOperationErrorJSONResponse: workspaceOperationError(apierrors.WorkspaceOperationFailed(apierrors.WithCause(err)))}, nil
}
return tuttigenerated.GetAutomationRule200JSONResponse(generatedAutomationRule(rule)), nil
}
func (api DaemonAPI) UpdateAutomationRule(ctx context.Context, request tuttigenerated.UpdateAutomationRuleRequestObject) (tuttigenerated.UpdateAutomationRuleResponseObject, error) {
if !api.automationRulesWritesEnabled(ctx) {
return tuttigenerated.UpdateAutomationRule400JSONResponse{InvalidRequestErrorJSONResponse: automationRulesWriteDisabledError()}, nil
}
if api.AutomationRuleService == nil {
return tuttigenerated.UpdateAutomationRule503JSONResponse{ServiceUnavailableErrorJSONResponse: automationRuleServiceUnavailable()}, nil
}
if request.Body == nil {
return tuttigenerated.UpdateAutomationRule400JSONResponse{InvalidRequestErrorJSONResponse: invalidRequestError(apierrors.EmptyBody())}, nil
}
rule, err := api.AutomationRuleService.UpdateRule(ctx, automationRulePutInput(request.WorkspaceID, request.AutomationRuleID, *request.Body))
if err != nil {
if errors.Is(err, workspacedata.ErrAutomationRuleNotFound) {
return tuttigenerated.UpdateAutomationRule404JSONResponse{WorkspaceNotFoundErrorJSONResponse: automationRuleNotFoundError()}, nil
}
if errors.Is(err, automationruleservice.ErrInvalidRuleInput) {
return tuttigenerated.UpdateAutomationRule400JSONResponse{InvalidRequestErrorJSONResponse: invalidAutomationRuleRequest(err)}, nil
}
return tuttigenerated.UpdateAutomationRule502JSONResponse{WorkspaceOperationErrorJSONResponse: workspaceOperationError(apierrors.WorkspaceOperationFailed(apierrors.WithCause(err)))}, nil
}
return tuttigenerated.UpdateAutomationRule200JSONResponse(generatedAutomationRule(rule)), nil
}
func (api DaemonAPI) DeleteAutomationRule(ctx context.Context, request tuttigenerated.DeleteAutomationRuleRequestObject) (tuttigenerated.DeleteAutomationRuleResponseObject, error) {
if !api.automationRulesWritesEnabled(ctx) {
return tuttigenerated.DeleteAutomationRule400JSONResponse{InvalidRequestErrorJSONResponse: automationRulesWriteDisabledError()}, nil
}
if api.AutomationRuleService == nil {
return tuttigenerated.DeleteAutomationRule503JSONResponse{ServiceUnavailableErrorJSONResponse: automationRuleServiceUnavailable()}, nil
}
if err := api.AutomationRuleService.DeleteRule(ctx, request.WorkspaceID, request.AutomationRuleID); err != nil {
if errors.Is(err, workspacedata.ErrAutomationRuleNotFound) {
return tuttigenerated.DeleteAutomationRule404JSONResponse{WorkspaceNotFoundErrorJSONResponse: automationRuleNotFoundError()}, nil
}
return tuttigenerated.DeleteAutomationRule502JSONResponse{WorkspaceOperationErrorJSONResponse: workspaceOperationError(apierrors.WorkspaceOperationFailed(apierrors.WithCause(err)))}, nil
}
return tuttigenerated.DeleteAutomationRule200JSONResponse{AutomationRuleId: request.AutomationRuleID}, nil
}
func (api DaemonAPI) GetAgentSessionAutomationRuleOverride(ctx context.Context, request tuttigenerated.GetAgentSessionAutomationRuleOverrideRequestObject) (tuttigenerated.GetAgentSessionAutomationRuleOverrideResponseObject, error) {
if api.AutomationRuleService == nil {
return tuttigenerated.GetAgentSessionAutomationRuleOverride503JSONResponse{ServiceUnavailableErrorJSONResponse: automationRuleServiceUnavailable()}, nil
}
override, ok, err := api.AutomationRuleService.GetSessionOverride(ctx, request.WorkspaceID, request.AgentSessionID)
if err != nil {
return tuttigenerated.GetAgentSessionAutomationRuleOverride502JSONResponse{WorkspaceOperationErrorJSONResponse: workspaceOperationError(apierrors.WorkspaceOperationFailed(apierrors.WithCause(err)))}, nil
}
if !ok {
override = automationrulebiz.SessionOverride{WorkspaceID: request.WorkspaceID, AgentSessionID: request.AgentSessionID}
}
return tuttigenerated.GetAgentSessionAutomationRuleOverride200JSONResponse(generatedAutomationRuleOverride(override)), nil
}
func (api DaemonAPI) SetAgentSessionAutomationRuleOverride(ctx context.Context, request tuttigenerated.SetAgentSessionAutomationRuleOverrideRequestObject) (tuttigenerated.SetAgentSessionAutomationRuleOverrideResponseObject, error) {
if !api.automationRulesWritesEnabled(ctx) {
return tuttigenerated.SetAgentSessionAutomationRuleOverride400JSONResponse{InvalidRequestErrorJSONResponse: automationRulesWriteDisabledError()}, nil
}
if api.AutomationRuleService == nil {
return tuttigenerated.SetAgentSessionAutomationRuleOverride503JSONResponse{ServiceUnavailableErrorJSONResponse: automationRuleServiceUnavailable()}, nil
}
if request.Body == nil {
return tuttigenerated.SetAgentSessionAutomationRuleOverride400JSONResponse{InvalidRequestErrorJSONResponse: invalidRequestError(apierrors.EmptyBody())}, nil
}
override, err := api.AutomationRuleService.SetSessionOverride(ctx, automationrulebiz.SessionOverride{
WorkspaceID: request.WorkspaceID, AgentSessionID: request.AgentSessionID,
Disabled: request.Body.Disabled, RuleIDs: append([]string(nil), request.Body.RuleIds...),
})
if err != nil {
switch {
case errors.Is(err, workspacedata.ErrAutomationRuleNotFound):
return tuttigenerated.SetAgentSessionAutomationRuleOverride404JSONResponse{WorkspaceNotFoundErrorJSONResponse: automationRuleNotFoundError()}, nil
case errors.Is(err, automationruleservice.ErrInvalidRuleInput):
return tuttigenerated.SetAgentSessionAutomationRuleOverride400JSONResponse{InvalidRequestErrorJSONResponse: invalidAutomationRuleRequest(err)}, nil
}
return tuttigenerated.SetAgentSessionAutomationRuleOverride502JSONResponse{WorkspaceOperationErrorJSONResponse: workspaceOperationError(apierrors.WorkspaceOperationFailed(apierrors.WithCause(err)))}, nil
}
return tuttigenerated.SetAgentSessionAutomationRuleOverride200JSONResponse(generatedAutomationRuleOverride(override)), nil
}
func automationRulePutInput(workspaceID string, ruleID string, body tuttigenerated.PutAutomationRuleRequest) automationruleservice.PutRuleInput {
return automationruleservice.PutRuleInput{
WorkspaceID: workspaceID, RuleID: ruleID, Name: body.Name, Enabled: body.Enabled,
Trigger: automationrulebiz.Trigger(body.Trigger),
SourceWorkspaceAgentID: stringValue(body.SourceWorkspaceAgentId),
Target: automationrulebiz.Target{
Kind: automationrulebiz.TargetKind(body.Target.Kind), WorkspaceAgentID: stringValue(body.Target.WorkspaceAgentId),
ModelPlanID: stringValue(body.Target.ModelPlanId), Model: stringValue(body.Target.Model),
RequiredCapabilities: append([]string(nil), body.Target.RequiredCapabilities...),
},
Permissions: automationrulebiz.PermissionPolicy{
PermissionModeID: stringValue(body.Permissions.PermissionModeId), AllowedTools: append([]string(nil), body.Permissions.AllowedTools...),
},
Budget: automationrulebiz.Budget{
MaxRunsPerSession: body.Budget.MaxRunsPerSession, MaxTotalTokensPerSession: body.Budget.MaxTotalTokensPerSession,
},
Prompt: body.Prompt,
}
}
func generatedAutomationRule(rule automationrulebiz.Rule) tuttigenerated.AutomationRule {
result := tuttigenerated.AutomationRule{
Id: rule.ID, WorkspaceId: rule.WorkspaceID, Name: rule.Name, Enabled: rule.Enabled,
Trigger: tuttigenerated.AutomationRuleTrigger(rule.Trigger), Prompt: rule.Prompt,
Target: tuttigenerated.AutomationRuleTarget{
Kind: tuttigenerated.AutomationRuleTargetKind(rule.Target.Kind), RequiredCapabilities: append([]string{}, rule.Target.RequiredCapabilities...),
},
Permissions: tuttigenerated.AutomationRulePermissions{AllowedTools: append([]string{}, rule.Permissions.AllowedTools...)},
Budget: tuttigenerated.AutomationRuleBudget{MaxRunsPerSession: rule.Budget.MaxRunsPerSession, MaxTotalTokensPerSession: rule.Budget.MaxTotalTokensPerSession},
CreatedAt: rule.CreatedAt, UpdatedAt: rule.UpdatedAt,
}
if rule.SourceWorkspaceAgentID != "" {
result.SourceWorkspaceAgentId = stringPointer(rule.SourceWorkspaceAgentID)
}
if rule.Target.WorkspaceAgentID != "" {
result.Target.WorkspaceAgentId = stringPointer(rule.Target.WorkspaceAgentID)
}
if rule.Target.ModelPlanID != "" {
result.Target.ModelPlanId = stringPointer(rule.Target.ModelPlanID)
}
if rule.Target.Model != "" {
result.Target.Model = stringPointer(rule.Target.Model)
}
if rule.Permissions.PermissionModeID != "" {
result.Permissions.PermissionModeId = stringPointer(rule.Permissions.PermissionModeID)
}
return result
}
func generatedAutomationRuleOverride(override automationrulebiz.SessionOverride) tuttigenerated.AgentSessionAutomationRuleOverride {
result := tuttigenerated.AgentSessionAutomationRuleOverride{
WorkspaceId: override.WorkspaceID, AgentSessionId: override.AgentSessionID,
Disabled: override.Disabled, RuleIds: append([]string{}, override.RuleIDs...),
}
if !override.UpdatedAt.IsZero() {
updatedAt := override.UpdatedAt
result.UpdatedAt = &updatedAt
}
return result
}
func createAutomationRuleError(err error) tuttigenerated.CreateAutomationRuleResponseObject {
if errors.Is(err, automationruleservice.ErrInvalidRuleInput) {
return tuttigenerated.CreateAutomationRule400JSONResponse{InvalidRequestErrorJSONResponse: invalidAutomationRuleRequest(err)}
}
return tuttigenerated.CreateAutomationRule502JSONResponse{WorkspaceOperationErrorJSONResponse: workspaceOperationError(apierrors.WorkspaceOperationFailed(apierrors.WithCause(err)))}
}
func invalidAutomationRuleRequest(err error) tuttigenerated.InvalidRequestErrorJSONResponse {
return invalidRequestError(apierrors.InvalidRequest("invalid_automation_rule", apierrors.WithDeveloperMessage(err.Error())))
}
func automationRuleServiceUnavailable() tuttigenerated.ServiceUnavailableErrorJSONResponse {
return serviceUnavailableError(apierrors.ServiceUnavailable("automation_rule_service_unavailable", apierrors.WithDeveloperMessage("automation rule service is unavailable")))
}
func automationRuleNotFoundError() tuttigenerated.WorkspaceNotFoundErrorJSONResponse {
return tuttigenerated.WorkspaceNotFoundErrorJSONResponse(protocolErrorResponse(apierrors.New(
http.StatusNotFound, tuttigenerated.AutomationRuleNotFound, "automation_rule_not_found", apierrors.WithDeveloperMessage("automation rule not found"),
)))
}