Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 41 additions & 27 deletions ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -7164,38 +7164,52 @@ func sendAITokenLimitAlert(ctx context.Context, execution WorkflowExecution, ful
}
}

if len(admins) == 0 {
admins = append(admins, "support@shuffler.io")
} else {
if !ArrayContains(admins, "support@shuffler.io") {
admins = append(admins, "support@shuffler.io")
}
}
aiPercentage := float64(monthlyTokensUsed) / float64(tokenLimit) * 100

cacheKey := generateAlertCacheKey(billingOrgId, "agent_token_limit_exceeded", admins)
if !checkAndSetAlertCache(ctx, cacheKey) {
log.Printf("[DEBUG] Skipping duplicate AI token limit alert for org %s - already sent recently", billingOrgId)
pctCacheKey := generateAlertCacheKey(billingOrgId, fmt.Sprintf("ai_token_pct_%d", int64(100)), admins)
if !checkAndSetAlertCache(ctx, pctCacheKey) {
log.Printf("[DEBUG] Skipping duplicate AI token alert for org %s, threshold %d%% - already sent recently", billingOrgId, int64(aiPercentage))
return
}

subject := fmt.Sprintf("AI Agent Token Limit Exceeded for Org %s", orgName)
message := fmt.Sprintf(`Dear Team,

Your organization <strong>%s</strong> (ID: %s) has exceeded the monthly AI Agent token limit of <strong>%d</strong> tokens.

<strong>Current usage:</strong> %d tokens.

As a result, your AI Agent runs will be temporarily blocked until the start of the next billing cycle.
If you need to increase your token limit, please reach out to us at <a href="mailto:support@shuffler.io">support@shuffler.io</a>.

Best regards,
The Shuffler Team`, orgName, billingOrgId, tokenLimit, monthlyTokensUsed)

errMail := sendMailSendgrid(admins, subject, message, false, []string{})
if errMail != nil {
log.Printf("[ERROR] Failed sending AI token limit alert email to %v for org %s: %s", admins, billingOrgId, errMail)
totalAppExecutions := int64(0)
appRunsLimit := int64(0)
orgStats, statsErr := GetOrgStatistics(ctx, billingOrgId)
if statsErr == nil && orgStats != nil {
totalAppExecutions = orgStats.MonthlyAppExecutions + orgStats.MonthlyChildAppExecutions
}
if fullOrg != nil {
appRunsLimit = fullOrg.SyncFeatures.AppExecutions.Limit
}

subjectLine := fmt.Sprintf("%d%% of your AI token limit", int64(aiPercentage))
Subject := fmt.Sprintf("[Shuffle]: You've reached %s for your tenant %s", subjectLine, orgName)
AiRecommendation := "Tip: <a href=\"https://shuffler.io/admin?tab=app_auth\" style=\"color: #FF8444; text-decoration: none; font-weight: bold;\">Connect your own AI provider app</a> to use your own keys and bypass the AI token limit entirely."
substitutions := map[string]interface{}{
"app_runs_usage": totalAppExecutions,
"app_runs_limit": appRunsLimit,
"subject_string": subjectLine,
"ai_tokens_usage": monthlyTokensUsed,
"ai_tokens_limit": tokenLimit,
"org_name": orgName,
"org_id": billingOrgId,
"admin_email": orgName,
"app_runs_usage_percentage": int64(aiPercentage),
"ai_recommendation": AiRecommendation,
}

err := sendMailSendgridV2(
[]string{"support@shuffler.io"},
Subject,
substitutions,
false,
"d-3678d48b2b7144feb4b0b4cff7045016",
admins,
)
if err != nil {
log.Printf("[ERROR] Failed sending AI token alert email to %v for org %s: %s", admins, billingOrgId, err)
} else {
log.Printf("[INFO] Sent AI token limit alert email to %v of org %s", admins, billingOrgId)
log.Printf("[INFO] Sent AI token %d%% alert email to %v of org %s", int64(aiPercentage), admins, billingOrgId)
}
}

Expand Down
51 changes: 21 additions & 30 deletions stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -1660,27 +1660,12 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
if int64(AlertThreshold.Count) < totalAppExecutions && !sendAlert && shouldSendAlert {

allAdmins := []string{}
firstAdmin := ""
allShufflerEmails := true

for _, user := range org.Users {
if user.Role == "admin" {
allAdmins = append(allAdmins, user.Username)

if firstAdmin == "" && !strings.Contains(user.Username, "shuffler.io") {
firstAdmin = user.Username
}

if !strings.Contains(user.Username, "shuffler.io") {
allShufflerEmails = false
}
}
}

if allShufflerEmails && firstAdmin == "" && len(allAdmins) > 0 {
firstAdmin = allAdmins[0]
}

if !ArrayContains(allAdmins, "chris@shuffler.io") {
allAdmins = append(allAdmins, "chris@shuffler.io")
}
Expand All @@ -1694,17 +1679,20 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
continue
}

Subject := fmt.Sprintf("[Shuffle]: You've reached the app-runs threshold limit for your account %s", firstAdmin)

AppRunsPercentage := float64(totalAppExecutions) / float64(org.SyncFeatures.AppExecutions.Limit) * 100
appRunsUsagePercentageStr := fmt.Sprintf("%d%% of your app runs limit", int64(AppRunsPercentage))
Subject := fmt.Sprintf("[Shuffle]: You've reached %s for your tenant %s", appRunsUsagePercentageStr, org.Name)

substitutions := map[string]interface{}{
"app_runs_usage": totalAppExecutions,
"app_runs_limit": org.SyncFeatures.AppExecutions.Limit,
"app_runs_usage_percentage": int64(AppRunsPercentage),
"subject_string": appRunsUsagePercentageStr,
"ai_tokens_usage": orgStatistics.MonthlyAgentTokens,
"ai_tokens_limit": org.SyncFeatures.AgentTokens.Limit,
"org_name": org.Name,
"org_id": org.Id,
"admin_email": firstAdmin,
"admin_email": org.Name,
"app_runs_usage_percentage": int64(AppRunsPercentage),
}

err = sendMailSendgridV2(
Expand Down Expand Up @@ -1858,7 +1846,10 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
}

// send mail use different subject line as it will sent only to the team
Subject := fmt.Sprintf("[Shuffle]: You've reached the app-runs threshold limit for your account %s", firstAdmin)
totalAppExecutions := validationOrgStatistics.MonthlyAppExecutions + validationOrgStatistics.MonthlyChildAppExecutions
AppRunsPercentage := float64(totalAppExecutions) / float64(validationOrg.SyncFeatures.AppExecutions.Limit) * 100
appRunsUsagePercentageStr := fmt.Sprintf("%d%% of your app runs limit", int64(AppRunsPercentage))
Subject := fmt.Sprintf("[Shuffle]: You've reached %s for your account %s", appRunsUsagePercentageStr, firstAdmin)
leadInfo := ""
if validationOrg.LeadInfo.POV {
leadInfo = "POC"
Expand All @@ -1873,7 +1864,7 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
}

if len(leadInfo) > 0 && (currentThreshold > 100) {
Subject = fmt.Sprintf("[Shuffle] %s: You've reached the app-runs threshold limit for your account %s", leadInfo, firstAdmin)
Subject = fmt.Sprintf("[Shuffle] %s: You've reached %s for your account %s", leadInfo, appRunsUsagePercentageStr, firstAdmin)
}

if len(leadInfo) == 0 && !ArrayContains(newEmailList, "jay@shuffler.io") {
Expand All @@ -1888,16 +1879,16 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
if !checkAndSetAlertCache(ctx, cacheKey) {
log.Printf("[DEBUG] Skipping duplicate percentage threshold alert for org %s, threshold %d%% - alert sent within last minute", validationOrg.Id, currentThreshold)
} else {
totalAppExecutions := validationOrgStatistics.MonthlyAppExecutions + validationOrgStatistics.MonthlyChildAppExecutions
AppRunsPercentage := float64(totalAppExecutions) / float64(validationOrg.SyncFeatures.AppExecutions.Limit) * 100

substitutions := map[string]interface{}{
"app_runs_usage": totalAppExecutions,
"app_runs_limit": validationOrg.SyncFeatures.AppExecutions.Limit,
"app_runs_usage_percentage": int64(AppRunsPercentage),
"subject_string": appRunsUsagePercentageStr,
"ai_tokens_usage": validationOrgStatistics.MonthlyAgentTokens,
"ai_tokens_limit": validationOrg.SyncFeatures.AgentTokens.Limit,
"org_name": validationOrg.Name,
"org_id": validationOrg.Id,
"admin_email": firstAdmin,
"app_runs_usage_percentage": int64(AppRunsPercentage),
}

if currentThreshold > 100 {
Expand Down Expand Up @@ -1927,20 +1918,20 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
log.Printf("[DEBUG] Skipping duplicate second alert for org %s, threshold %d%% - alert sent within last minute", validationOrg.Id, currentThreshold)
} else {
if len(leadInfo) > 0 {
Subject = fmt.Sprintf("[Shuffle] %s: You've reached the app-runs threshold limit for your account %s", leadInfo, firstAdmin)
Subject = fmt.Sprintf("[Shuffle] %s: You've reached %s for your account %s", leadInfo, appRunsUsagePercentageStr, firstAdmin)
}

totalAppExecutions := validationOrgStatistics.MonthlyAppExecutions + validationOrgStatistics.MonthlyChildAppExecutions
AppRunsPercentage := float64(totalAppExecutions) / float64(validationOrg.SyncFeatures.AppExecutions.Limit) * 100

substitutions := map[string]interface{}{
"app_runs_usage": totalAppExecutions,
"app_runs_limit": validationOrg.SyncFeatures.AppExecutions.Limit,
"app_runs_usage_percentage": int64(AppRunsPercentage),
"subject_string": appRunsUsagePercentageStr,
"ai_tokens_usage": validationOrgStatistics.MonthlyAgentTokens,
"ai_tokens_limit": validationOrg.SyncFeatures.AgentTokens.Limit,
"org_name": validationOrg.Name,
"org_id": validationOrg.Id,
"admin_email": firstAdmin,
"lead_info": leadInfo,
"app_runs_usage_percentage": int64(AppRunsPercentage),
}

log.Printf("[DEBUG] Sending second alert mail for child org %s to parent org %s (2)", validationOrg.Name, validationOrg.Name)
Expand Down
Loading