diff --git a/src/seer/app.py b/src/seer/app.py index d57df5589..840466129 100644 --- a/src/seer/app.py +++ b/src/seer/app.py @@ -11,6 +11,7 @@ AutofixEndpointResponse, AutofixPrIdRequest, AutofixRequest, + AutofixStateOptions, AutofixStateRequest, AutofixStateResponse, AutofixUpdateRequest, @@ -213,6 +214,11 @@ def get_autofix_state_endpoint(data: AutofixStateRequest) -> AutofixStateRespons if state: check_and_mark_if_timed_out(state) + with state.update() as cur: + if not cur.options: + cur.options = AutofixStateOptions() + cur.options.iterative_feedback = True # Enable iterative feedback even on older runs + return AutofixStateResponse( group_id=data.group_id, state=state.get().model_dump(mode="json") if state else None ) diff --git a/src/seer/automation/autofix/event_manager.py b/src/seer/automation/autofix/event_manager.py index a2ae2cb79..527f62c30 100644 --- a/src/seer/automation/autofix/event_manager.py +++ b/src/seer/automation/autofix/event_manager.py @@ -120,9 +120,15 @@ def set_selected_root_cause(self, selection: RootCauseSelection): cur.status = AutofixStatus.PROCESSING - def send_planning_start(self, is_update: bool = False): + def send_planning_start(self, is_update: bool = False, is_retry: bool = False): with self.state.update() as cur: + if is_retry: + last_step = cur.steps[-1] + if last_step.key == self.plan_step.key: + del cur.steps[-1] + plan_step = cur.last_or_add(self.plan_step) + plan_step.status = AutofixStatus.PROCESSING if is_update: diff --git a/src/seer/automation/autofix/models.py b/src/seer/automation/autofix/models.py index f78493b47..3b4eb91a4 100644 --- a/src/seer/automation/autofix/models.py +++ b/src/seer/automation/autofix/models.py @@ -175,6 +175,10 @@ class CodebaseState(BaseModel): file_changes: list[FileChange] = [] +class AutofixStateOptions(BaseModel): + iterative_feedback: bool | None = False + + class AutofixGroupState(BaseModel): run_id: int = -1 steps: list[Step] = Field(default_factory=list) @@ -190,6 +194,7 @@ class AutofixGroupState(BaseModel): completed_at: datetime.datetime | None = None signals: list[str] = Field(default_factory=list) actor_ids: list[int] = Field(default_factory=list) + options: AutofixStateOptions | None = Field(default=AutofixStateOptions()) class AutofixStateRequest(BaseModel): @@ -259,6 +264,7 @@ class AutofixRootCauseUpdatePayload(BaseModel): cause_id: int | None = None fix_id: int | None = None custom_root_cause: str | None = None + is_retry: bool | None = False class AutofixCreatePrUpdatePayload(BaseModel): diff --git a/src/seer/automation/autofix/tasks.py b/src/seer/automation/autofix/tasks.py index b352be27b..51f722f71 100644 --- a/src/seer/automation/autofix/tasks.py +++ b/src/seer/automation/autofix/tasks.py @@ -123,11 +123,11 @@ def run_autofix_execution(request: AutofixUpdateRequest): with state.update() as cur: cur.mark_triggered() - event_manager = AutofixEventManager(state) - event_manager.send_planning_start() - payload = cast(AutofixRootCauseUpdatePayload, request.payload) + event_manager = AutofixEventManager(state) + event_manager.send_planning_start(is_retry=payload.is_retry or False) + try: root_cause: CustomRootCauseSelection | SuggestedFixRootCauseSelection | None = None if payload.custom_root_cause: