mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
refactor: use task data model for notifications (#20590)
Updates coder/internal#973 Updates coder/internal#974
This commit is contained in:
+42
-54
@@ -461,67 +461,55 @@ func (api *API) enqueueAITaskStateNotification(
|
||||
return
|
||||
}
|
||||
|
||||
workspaceBuild, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspace.ID)
|
||||
if err != nil {
|
||||
api.Logger.Warn(ctx, "failed to get workspace build", slog.Error(err))
|
||||
if !workspace.TaskID.Valid {
|
||||
// Workspace has no task ID, do nothing.
|
||||
return
|
||||
}
|
||||
|
||||
// Confirm Workspace Agent App is an AI Task
|
||||
if workspaceBuild.HasAITask.Valid && workspaceBuild.HasAITask.Bool &&
|
||||
workspaceBuild.AITaskSidebarAppID.Valid && workspaceBuild.AITaskSidebarAppID.UUID == appID {
|
||||
// Skip if the latest persisted state equals the new state (no new transition)
|
||||
if len(latestAppStatus) > 0 && latestAppStatus[0].State == database.WorkspaceAppStatusState(newAppStatus) {
|
||||
return
|
||||
}
|
||||
task, err := api.Database.GetTaskByID(ctx, workspace.TaskID.UUID)
|
||||
if err != nil {
|
||||
api.Logger.Warn(ctx, "failed to get task", slog.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
// Skip the initial "Working" notification when task first starts.
|
||||
// This is obvious to the user since they just created the task.
|
||||
// We still notify on first "Idle" status and all subsequent transitions.
|
||||
if len(latestAppStatus) == 0 && newAppStatus == codersdk.WorkspaceAppStatusStateWorking {
|
||||
return
|
||||
}
|
||||
if !task.WorkspaceAppID.Valid || task.WorkspaceAppID.UUID != appID {
|
||||
// Non-task app, do nothing.
|
||||
return
|
||||
}
|
||||
|
||||
// Use the task prompt as the "task" label, fallback to workspace name
|
||||
parameters, err := api.Database.GetWorkspaceBuildParameters(ctx, workspaceBuild.ID)
|
||||
if err != nil {
|
||||
api.Logger.Warn(ctx, "failed to get workspace build parameters", slog.Error(err))
|
||||
return
|
||||
}
|
||||
taskName := workspace.Name
|
||||
for _, param := range parameters {
|
||||
if param.Name == codersdk.AITaskPromptParameterName {
|
||||
taskName = param.Value
|
||||
}
|
||||
}
|
||||
// Skip if the latest persisted state equals the new state (no new transition)
|
||||
if len(latestAppStatus) > 0 && latestAppStatus[0].State == database.WorkspaceAppStatusState(newAppStatus) {
|
||||
return
|
||||
}
|
||||
|
||||
// As task prompt may be particularly long, truncate it to 160 characters for notifications.
|
||||
if len(taskName) > 160 {
|
||||
taskName = strutil.Truncate(taskName, 160, strutil.TruncateWithEllipsis, strutil.TruncateWithFullWords)
|
||||
}
|
||||
// Skip the initial "Working" notification when task first starts.
|
||||
// This is obvious to the user since they just created the task.
|
||||
// We still notify on first "Idle" status and all subsequent transitions.
|
||||
if len(latestAppStatus) == 0 && newAppStatus == codersdk.WorkspaceAppStatusStateWorking {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := api.NotificationsEnqueuer.EnqueueWithData(
|
||||
// nolint:gocritic // Need notifier actor to enqueue notifications
|
||||
dbauthz.AsNotifier(ctx),
|
||||
workspace.OwnerID,
|
||||
notificationTemplate,
|
||||
map[string]string{
|
||||
"task": taskName,
|
||||
"workspace": workspace.Name,
|
||||
},
|
||||
map[string]any{
|
||||
// Use a 1-minute bucketed timestamp to bypass per-day dedupe,
|
||||
// allowing identical content to resend within the same day
|
||||
// (but not more than once every 10s).
|
||||
"dedupe_bypass_ts": api.Clock.Now().UTC().Truncate(time.Minute),
|
||||
},
|
||||
"api-workspace-agent-app-status",
|
||||
// Associate this notification with related entities
|
||||
workspace.ID, workspace.OwnerID, workspace.OrganizationID, appID,
|
||||
); err != nil {
|
||||
api.Logger.Warn(ctx, "failed to notify of task state", slog.Error(err))
|
||||
return
|
||||
}
|
||||
if _, err := api.NotificationsEnqueuer.EnqueueWithData(
|
||||
// nolint:gocritic // Need notifier actor to enqueue notifications
|
||||
dbauthz.AsNotifier(ctx),
|
||||
workspace.OwnerID,
|
||||
notificationTemplate,
|
||||
map[string]string{
|
||||
"task": task.Name,
|
||||
"workspace": workspace.Name,
|
||||
},
|
||||
map[string]any{
|
||||
// Use a 1-minute bucketed timestamp to bypass per-day dedupe,
|
||||
// allowing identical content to resend within the same day
|
||||
// (but not more than once every 10s).
|
||||
"dedupe_bypass_ts": api.Clock.Now().UTC().Truncate(time.Minute),
|
||||
},
|
||||
"api-workspace-agent-app-status",
|
||||
// Associate this notification with related entities
|
||||
workspace.ID, workspace.OwnerID, workspace.OrganizationID, appID,
|
||||
); err != nil {
|
||||
api.Logger.Warn(ctx, "failed to notify of task state", slog.Error(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user