-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
feat(explorer): add coding agent handoff support to explorer client #105872
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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.
| run_id=run_id, | ||
| integration_id=integration_id, | ||
| ) | ||
| return Response(result, status=202) |
Check warning
Code scanning / CodeQL
Information exposure through an exception Medium
Show autofix suggestion
Hide autofix suggestion
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 theexcept (HTTPError, ApiError) as e:block, modify thefailures.append({...})call to use a generic message and removestr(e). - No changes are needed in
group_ai_autofix._post_explorerortrigger_coding_agent_handoffbecause they can continue to forward thesuccesses/failuresstructure; only the contents oferror_messageneed to be sanitized. - No new imports or helper methods are required.
-
Copy modified line R108 -
Copy modified line R112
| @@ -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 |
There was a problem hiding this comment.
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.
Change early return error from 'error' to 'error_message' for consistency with per-repo failure objects from launch_coding_agents.
aliu39
left a comment
There was a problem hiding this 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this a concern?
| "failures": [{"error_message": "No repositories found in run state"}], | ||
| } | ||
|
|
||
| prompt = generate_autofix_handoff_prompt(state) |
There was a problem hiding this comment.
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.
| if solution and solution.data: | ||
| parts.append("## Proposed Solution") | ||
| if "one_line_summary" in solution.data: | ||
| parts.append(solution.data["one_line_summary"]) |
There was a problem hiding this comment.
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.
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)