mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(coderd): gate AI task notifications on agent ready state (#20690)
Relates to https://github.com/coder/internal/issues/1098 Currently AgentAPI waits for only 2 seconds worth of identical terminal screen snapshots before deciding a task has entered a "stable" state. We interpret this as becoming "idle", resulting in a notification being triggered. This behavior is not ideal and is ultimately the root cause of our spammy notifications. Unfortunately, until we move AgentAPI to either use the Claude Code SDK (or ACP wrapper around it), we are unable to easily fix the root cause. This PR instead waits until the agent is ready before it will send state change notifications. This will at least resolve _some_ of the complaints about task state notifications being too spammy. --- 🤖 PR was written by Claude Sonnet 4.5 using [Coder Mux](https://github.com/coder/cmux) and reviewed by a human 👩
This commit is contained in:
@@ -428,7 +428,7 @@ func (api *API) patchWorkspaceAgentAppStatus(rw http.ResponseWriter, r *http.Req
|
||||
})
|
||||
|
||||
// Notify on state change to Working/Idle for AI tasks
|
||||
api.enqueueAITaskStateNotification(ctx, app.ID, latestAppStatus, req.State, workspace)
|
||||
api.enqueueAITaskStateNotification(ctx, app.ID, latestAppStatus, req.State, workspace, workspaceAgent)
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, nil)
|
||||
}
|
||||
@@ -437,13 +437,15 @@ func (api *API) patchWorkspaceAgentAppStatus(rw http.ResponseWriter, r *http.Req
|
||||
// transitions to Working or Idle.
|
||||
// No-op if:
|
||||
// - the workspace agent app isn't configured as an AI task,
|
||||
// - the new state equals the latest persisted state.
|
||||
// - the new state equals the latest persisted state,
|
||||
// - the workspace agent is not ready (still starting up).
|
||||
func (api *API) enqueueAITaskStateNotification(
|
||||
ctx context.Context,
|
||||
appID uuid.UUID,
|
||||
latestAppStatus []database.WorkspaceAppStatus,
|
||||
newAppStatus codersdk.WorkspaceAppStatusState,
|
||||
workspace database.Workspace,
|
||||
agent database.WorkspaceAgent,
|
||||
) {
|
||||
// Select notification template based on the new state
|
||||
var notificationTemplate uuid.UUID
|
||||
@@ -466,6 +468,18 @@ func (api *API) enqueueAITaskStateNotification(
|
||||
return
|
||||
}
|
||||
|
||||
// Only send notifications when the agent is ready. We want to skip
|
||||
// any state transitions that occur whilst the workspace is starting
|
||||
// up as it doesn't make sense to receive them.
|
||||
if agent.LifecycleState != database.WorkspaceAgentLifecycleStateReady {
|
||||
api.Logger.Debug(ctx, "skipping AI task notification because agent is not ready",
|
||||
slog.F("agent_id", agent.ID),
|
||||
slog.F("lifecycle_state", agent.LifecycleState),
|
||||
slog.F("new_app_status", 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))
|
||||
|
||||
Reference in New Issue
Block a user