Skip to content

Conversation

@roaga
Copy link
Member

@roaga roaga commented Jan 7, 2026

Add generic coding agent handoff functionality for explorer-based autofix to reach parity with legacy version

This enables both manual (via API) and automatic (via completion hook) triggers for launching coding agents from explorer autofix runs.

(sorry for long diff but a lot is tests)

Add generic coding agent handoff functionality for explorer-based autofix:

- Add `launch_coding_agents` method to `SeerExplorerClient` for triggering
  third-party coding agents (e.g., Cursor) with prompt and repos
- Add `trigger_coding_agent_handoff` function in autofix_agent.py that
  extracts state/artifacts and calls the client method
- Add `generate_autofix_handoff_prompt` to create prompts from artifacts
- Add `coding_agent_handoff` step to autofix endpoint for manual triggers
- Add `ExplorerCodingAgentState` type and `coding_agents` field to state
- Include `coding_agents` in autofix API response

This enables both manual (via API) and future automatic (via completion hook)
triggers for launching coding agents from explorer autofix runs.
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Jan 7, 2026
run_id=run_id,
integration_id=integration_id,
)
return Response(result, status=202)

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information flows to this location and may be exposed to an external user.

Copilot Autofix

AI 8 days ago

General fix: avoid sending raw exception messages from HTTPError/ApiError back to the client. Instead, log the full exception (with stack trace and context) on the server, and return a generic, high-level error message to the caller. This preserves debuggability while preventing information exposure.

Best targeted fix: adjust launch_coding_agents in src/sentry/seer/explorer/coding_agent_handoff.py so that when we append to failures, we no longer include str(e). Instead, we should provide a generic message such as "Failed to launch coding agent" and optionally a coarse, non-sensitive reason (like the HTTP status code) if desired. We should keep logger.exception(...) as-is to ensure that the full exception (including stack trace and URL/response details) is captured in logs but not sent to users. This change preserves the existing API shape ({"successes": [...], "failures": [...]}) while scrubbing sensitive content.

Concretely:

  • In launch_coding_agents, in the except (HTTPError, ApiError) as e: block, modify the failures.append({...}) call to use a generic message and remove str(e).
  • No changes are needed in group_ai_autofix._post_explorer or trigger_coding_agent_handoff because they can continue to forward the successes/failures structure; only the contents of error_message need to be sanitized.
  • No new imports or helper methods are required.

Suggested changeset 1
src/sentry/seer/explorer/coding_agent_handoff.py
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/sentry/seer/explorer/coding_agent_handoff.py b/src/sentry/seer/explorer/coding_agent_handoff.py
--- a/src/sentry/seer/explorer/coding_agent_handoff.py
+++ b/src/sentry/seer/explorer/coding_agent_handoff.py
@@ -105,10 +105,11 @@
                     "repo_name": repo_name,
                 },
             )
+            # Do not expose raw exception details to the client; return a generic message instead.
             failures.append(
                 {
                     "repo_name": repo_name,
-                    "error_message": str(e),
+                    "error_message": "Failed to launch coding agent for this repository.",
                 }
             )
             continue
EOF
@@ -105,10 +105,11 @@
"repo_name": repo_name,
},
)
# Do not expose raw exception details to the client; return a generic message instead.
failures.append(
{
"repo_name": repo_name,
"error_message": str(e),
"error_message": "Failed to launch coding agent for this repository.",
}
)
continue
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
Copy link
Member

Choose a reason for hiding this comment

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

is this a concern?

Replace str(e) with generic error message to prevent exposing
sensitive internal details (URLs, response bodies, headers) from
HTTPError/ApiError exceptions. The full exception is still logged
server-side via logger.exception() for debugging.
@roaga roaga marked this pull request as ready for review January 9, 2026 23:15
@roaga roaga requested a review from a team as a code owner January 9, 2026 23:15
Change early return error from 'error' to 'error_message' for
consistency with per-repo failure objects from launch_coding_agents.
Copy link
Member

@aliu39 aliu39 left a comment

Choose a reason for hiding this comment

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

flow lgtm

run_id=run_id,
integration_id=integration_id,
)
return Response(result, status=202)
Copy link
Member

Choose a reason for hiding this comment

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

is this a concern?

return None

# Check project preferences
group = Group.objects.get(id=group_id)

This comment was marked as outdated.

"failures": [{"error_message": "No repositories found in run state"}],
}

prompt = generate_autofix_handoff_prompt(state)
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing validation that run belongs to the specified group

Medium Severity

The trigger_coding_agent_handoff function fetches a run by run_id without validating that it belongs to the specified group. The client.get_run(run_id) call ignores the category_value set on the client and fetches any run from the organization. If a user calls the API endpoint with a run_id from a different group, the function would generate a prompt from the wrong issue's artifacts and target the wrong repositories, while using the current group's title for branch naming. The run's state.metadata.get("group_id") should be validated to match group.id after fetching. The automatic handoff in on_completion_hook correctly uses the group_id from run metadata, making this an inconsistency.

Fix in Cursor Fix in Web

if solution and solution.data:
parts.append("## Proposed Solution")
if "one_line_summary" in solution.data:
parts.append(solution.data["one_line_summary"])
Copy link
Contributor

Choose a reason for hiding this comment

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

Prompt generation crashes if artifact data contains null values

Medium Severity

The generate_autofix_handoff_prompt function directly appends values from root_cause.data and solution.data to the parts list without checking if they're strings. If data["one_line_description"] or data["one_line_summary"] is None (the key exists but value is null), the function appends None to parts. Then "\n\n".join(parts) crashes with a TypeError because join requires all elements to be strings. Since Artifact.data is typed as dict[str, Any], null values are valid.

Fix in Cursor Fix in Web

@roaga roaga merged commit 80b4f0c into master Jan 12, 2026
65 of 66 checks passed
@roaga roaga deleted the explorer/coding-agent-handoff-be branch January 12, 2026 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants