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
231 lines
14 KiB
Go
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"),
|
|
)))
|
|
}
|