Skip to content
Merged
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
2 changes: 2 additions & 0 deletions src/sentry/seer/autofix/autofix_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ def trigger_autofix_explorer(
stopping_point: AutofixStoppingPoint | None = None,
intelligence_level: Literal["low", "medium", "high"] = "low",
user_context: str | None = None,
insert_index: int | None = None,
) -> int:
"""
Start or continue an Explorer-based autofix run.
Expand Down Expand Up @@ -247,6 +248,7 @@ def trigger_autofix_explorer(
prompt_metadata=prompt_metadata,
artifact_key=artifact_key,
artifact_schema=artifact_schema,
insert_index=insert_index,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

insert_index silently ignored when run_id is absent

Low Severity

When a caller provides insert_index without run_id, the parameter is silently dropped because trigger_autofix_explorer only passes insert_index to client.continue_run() in the else branch (existing run), not to client.start_run(). The endpoint has no validation to reject this combination — unlike open_pr and coding_agent_handoff, which explicitly check that run_id is present. A retry-from-step request missing run_id would quietly start a brand-new run instead of truncating and retrying.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f299f7a. Configure here.

)

payload = {
Expand Down
5 changes: 5 additions & 0 deletions src/sentry/seer/endpoints/group_ai_autofix.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ class ExplorerAutofixRequestSerializer(CamelSnakeSerializer):
required=False,
help_text="Optional repository name for which to create the pull request. Do not pass a repository name to create pull requests in all relevant repositories.",
)
insert_index = serializers.IntegerField(
required=False,
help_text="Block index to insert at. When provided, truncates blocks after this point for retry-from-step.",
)

def validate(self, data: dict[str, Any]) -> dict[str, Any]:
stopping_point = data.get("stopping_point", None)
Expand Down Expand Up @@ -289,6 +293,7 @@ def _post_explorer(self, request: Request, group: Group) -> Response:
run_id=run_id,
intelligence_level=data["intelligence_level"],
user_context=data.get("user_context"),
insert_index=data.get("insert_index"),
)
return Response({"run_id": run_id}, status=status.HTTP_202_ACCEPTED)
except SeerPermissionError as e:
Expand Down
29 changes: 29 additions & 0 deletions tests/sentry/seer/endpoints/test_group_ai_autofix.py
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,35 @@ def test_stopping_point(self, mock_trigger_explorer):
run_id=None,
intelligence_level="low",
user_context=None,
insert_index=None,
)

@patch("sentry.seer.endpoints.group_ai_autofix.trigger_autofix_explorer")
def test_insert_index_passed_through(self, mock_trigger_explorer):
"""POST passes insert_index to trigger_autofix_explorer for retry-from-step."""
for flag in EXPLORER_FLAGS:
mock_trigger_explorer.reset_mock()
group = self.create_group()
mock_trigger_explorer.return_value = 123

self.login_as(user=self.user)
with self.feature(flag):
response = self.client.post(
self._get_url(group.id, mode="explorer"),
data={"step": "solution", "run_id": 42, "insert_index": 3},
format="json",
)

assert response.status_code == 202, f"Failed for {flag}: {response.data}"
mock_trigger_explorer.assert_called_once_with(
group=group,
step=AutofixStep.SOLUTION,
referrer=AutofixReferrer.GROUP_AUTOFIX_ENDPOINT,
stopping_point=None,
run_id=42,
intelligence_level="low",
user_context=None,
insert_index=3,
)

@patch("sentry.seer.autofix.autofix._call_autofix")
Expand Down
Loading