Skip to content

refactor: improve analyze_issue_with_seer readability and error handling #355

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

Merged
merged 1 commit into from
Jul 7, 2025

Conversation

dcramer
Copy link
Member

@dcramer dcramer commented Jul 7, 2025

  • Extract helper functions for status checks and guidance messages
  • Add terminal status checking to avoid unnecessary polling
  • Add human intervention status detection with contextual guidance
  • Improve status display names with new statuses (PROCESSING, IN_PROGRESS)
  • Add better error recovery message when analysis state is lost
  • Use consistent naming (autofixState instead of currentState)
  • Simplify repeated terminal status checks with helper function

🤖 Generated with Claude Code

Copy link
Contributor

seer-by-sentry bot commented Jul 7, 2025

On it! We are reviewing the PR and will provide feedback shortly.

Copy link
Contributor

seer-by-sentry bot commented Jul 7, 2025

PR Description

This pull request enhances the Seer AI Analysis tool within the MCP server by improving code readability, maintainability, and error handling. The primary goal is to refactor the analyze_issue_with_seer tool handler to reduce code duplication and provide more informative feedback to the user during the analysis process.

Click to see more

Key Technical Changes

The key technical changes include: 1) Extraction of three utility functions: isTerminalStatus, isHumanInterventionStatus, and getHumanInterventionGuidance to encapsulate status checking and guidance message retrieval. 2) Replacement of the currentState variable with autofixState for improved clarity. 3) Enhancement of error messages to include retry instructions with the appropriate command for re-triggering the analysis. 4) Usage of the getStatusDisplayName helper function for consistent status display formatting.

Architecture Decisions

The architectural decisions involve adopting a functional approach by extracting reusable utility functions. This promotes separation of concerns and improves the overall structure of the analyze_issue_with_seer handler. The use of helper functions makes the code more modular and easier to test.

Dependencies and Interactions

This pull request primarily interacts with the SentryApiService to fetch and start autofix analyses. It also depends on the parseIssueParams function for parsing issue identifiers from URLs or explicit parameters. The changes do not introduce any new external dependencies.

Risk Considerations

The primary risk is the potential for unexpected behavior due to changes in status handling logic. Thorough testing is required to ensure that the new utility functions correctly identify terminal and human intervention statuses. Additionally, the accuracy of the retry instructions should be verified to prevent user confusion. There is also a risk that the polling logic might not handle all possible status transitions correctly, requiring careful monitoring in production.

Notable Implementation Details

A notable implementation detail is the use of template literals to construct the retry command in the error message. This allows for dynamic generation of the command based on whether the issue is identified by URL or by organization slug and issue ID. The SEER_TIMEOUT and SEER_POLLING_INTERVAL constants control the analysis timeout and polling frequency, respectively, and should be tuned based on performance considerations.

Comment on lines +91 to +98
return [
"COMPLETED",
"FAILED",
"ERROR",
"CANCELLED",
"NEED_MORE_INFORMATION",
"WAITING_FOR_USER_RESPONSE",
].includes(status);
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using a const assertion or enum for the terminal statuses array to prevent accidental mutations and improve type safety. This will also make it easier to maintain and reference these statuses elsewhere in the codebase.

Suggested change
return [
"COMPLETED",
"FAILED",
"ERROR",
"CANCELLED",
"NEED_MORE_INFORMATION",
"WAITING_FOR_USER_RESPONSE",
].includes(status);
const TERMINAL_STATUSES = [
"COMPLETED",
"FAILED",
"ERROR",
"CANCELLED",
"NEED_MORE_INFORMATION",
"WAITING_FOR_USER_RESPONSE",
] as const;
function isTerminalStatus(status: string): boolean {
return TERMINAL_STATUSES.includes(status as typeof TERMINAL_STATUSES[number]);
}

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines +105 to +110
return (
status === "NEED_MORE_INFORMATION" || status === "WAITING_FOR_USER_RESPONSE"
);
}

/**
Copy link
Contributor

Choose a reason for hiding this comment

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

The function isHumanInterventionStatus is only checking for two specific statuses, but it might be more maintainable to define these statuses as constants and reuse them in both this function and getHumanInterventionGuidance.

Suggested change
return (
status === "NEED_MORE_INFORMATION" || status === "WAITING_FOR_USER_RESPONSE"
);
}
/**
const HUMAN_INTERVENTION_STATUSES = ["NEED_MORE_INFORMATION", "WAITING_FOR_USER_RESPONSE"] as const;
function isHumanInterventionStatus(status: string): boolean {
return HUMAN_INTERVENTION_STATUSES.includes(status as typeof HUMAN_INTERVENTION_STATUSES[number]);
}

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines +115 to 125
return "\nSeer needs additional information to continue the analysis. Please review the insights above and consider providing more context.\n";
}
if (status === "WAITING_FOR_USER_RESPONSE") {
return "\nSeer is waiting for your response to proceed. Please review the analysis and provide feedback.\n";
}
return "";
}

/**
* Creates a SentryApiService instance from server context with optional region override.
*
Copy link
Contributor

Choose a reason for hiding this comment

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

The guidance messages are hardcoded strings. Consider extracting these to constants or a configuration object to improve maintainability and make them easier to update or localize in the future.

Suggested change
return "\nSeer needs additional information to continue the analysis. Please review the insights above and consider providing more context.\n";
}
if (status === "WAITING_FOR_USER_RESPONSE") {
return "\nSeer is waiting for your response to proceed. Please review the analysis and provide feedback.\n";
}
return "";
}
/**
* Creates a SentryApiService instance from server context with optional region override.
*
const GUIDANCE_MESSAGES = {
NEED_MORE_INFORMATION: "\nSeer needs additional information to continue the analysis. Please review the insights above and consider providing more context.\n",
WAITING_FOR_USER_RESPONSE: "\nSeer is waiting for your response to proceed. Please review the analysis and provide feedback.\n"
} as const;
function getHumanInterventionGuidance(status: string): string {
if (status === "NEED_MORE_INFORMATION") {
return GUIDANCE_MESSAGES.NEED_MORE_INFORMATION;
}
if (status === "WAITING_FOR_USER_RESPONSE") {
return GUIDANCE_MESSAGES.WAITING_FOR_USER_RESPONSE;
}
return "";
}

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines +938 to 948
if (isTerminalStatus(status)) {
output += `## Analysis ${getStatusDisplayName(status)}\n\n`;

// Add all step outputs
for (const step of currentState.autofix.steps) {
for (const step of autofixState.autofix.steps) {
output += getOutputForAutofixStep(step);
output += "\n";
}

if (status !== "COMPLETED") {
Copy link
Contributor

Choose a reason for hiding this comment

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

The helper function name could be more descriptive. Consider renaming to buildRetryCommand or formatRetryInstruction to better reflect its purpose of generating retry instructions for the user.

Suggested change
if (isTerminalStatus(status)) {
output += `## Analysis ${getStatusDisplayName(status)}\n\n`;
// Add all step outputs
for (const step of currentState.autofix.steps) {
for (const step of autofixState.autofix.steps) {
output += getOutputForAutofixStep(step);
output += "\n";
}
if (status !== "COMPLETED") {
// Helper function to build retry command instruction
const buildRetryCommand = (params: { issueUrl?: string }, orgSlug: string, parsedIssueId: string) => {
let output = `Error: Analysis state lost. Please try again by running:\n`;
output += `\`\`\`\n`;
output += params.issueUrl
? `analyze_issue_with_seer(issueUrl="${params.issueUrl}")`
: `analyze_issue_with_seer(organizationSlug="${orgSlug}", issueId="${parsedIssueId}")`;
output += `\n\`\`\`\n`;
return output;
};
// Then use it in the handler:
if (!autofixState.autofix) {
output += buildRetryCommand(params, orgSlug, parsedIssueId!);
return output;
}

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link

codecov bot commented Jul 7, 2025

Codecov Report

Attention: Patch coverage is 34.61538% with 34 lines in your changes missing coverage. Please review.

Project coverage is 59.70%. Comparing base (98f29d1) to head (2e42853).
Report is 1 commits behind head on main.

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
packages/mcp-server/src/tools.ts 34.61% 34 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #355      +/-   ##
==========================================
+ Coverage   59.37%   59.70%   +0.32%     
==========================================
  Files          49       51       +2     
  Lines        6038     6159     +121     
  Branches      472      477       +5     
==========================================
+ Hits         3585     3677      +92     
- Misses       2453     2482      +29     
Flag Coverage Δ
evals 74.54% <ø> (?)
unittests 59.43% <34.61%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

cursor[bot]

This comment was marked as outdated.

- Extract helper functions for status checks and guidance messages
- Add terminal status checking to avoid unnecessary polling
- Add human intervention status detection with contextual guidance
- Improve status display names with new statuses (PROCESSING, IN_PROGRESS)
- Add better error recovery message when analysis state is lost
- Use consistent naming (autofixState instead of currentState)
- Simplify repeated terminal status checks with helper function

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copy link
Contributor

seer-by-sentry bot commented Jul 7, 2025

On it! We are reviewing the PR and will provide feedback shortly.

Copy link
Contributor

seer-by-sentry bot commented Jul 7, 2025

PR Description

This pull request enhances the Seer AI analysis tool within the MCP server by improving status handling, error messaging, and code maintainability. The primary goal is to provide users with clearer feedback on the analysis progress and to simplify the codebase for future development.

Click to see more

Key Technical Changes

Key changes include: 1) Addition of PROCESSING and IN_PROGRESS statuses to getStatusDisplayName for more informative status messages. 2) Introduction of isTerminalStatus to determine if an analysis has reached a final state. 3) Creation of getHumanInterventionGuidance to provide specific instructions for statuses requiring user input. 4) Refactoring of the analyze_issue_with_seer tool handler to utilize these new functions, reducing code duplication and improving readability. 5) Improved error messaging when the analysis state is lost, providing users with the exact command to retry the analysis.

Architecture Decisions

The architectural decisions involve encapsulating status-related logic into separate, reusable functions. This promotes a more modular design, making it easier to add or modify status handling in the future without affecting the core analysis logic. The use of helper functions also improves the overall readability and maintainability of the analyze_issue_with_seer function.

Dependencies and Interactions

This pull request primarily interacts with the Sentry API through the SentryApiService to fetch and update autofix states. It also relies on the parseIssueParams function to extract issue information from URLs or IDs. The changes do not introduce any new external dependencies.

Risk Considerations

The main risk is potential regressions in status handling due to the refactoring. Thorough testing is required to ensure that all status transitions are correctly handled and that the user receives accurate and timely feedback. Additionally, the new error message should be reviewed to ensure it is clear and helpful in all scenarios where the analysis state might be lost.

Notable Implementation Details

A notable implementation detail is the use of template literals to construct the retry command in the error message. This allows for dynamic generation of the command based on whether the user provided an issue URL or an organization slug and issue ID. Also, the isHumanInterventionStatus function is currently unused and might be considered for removal in the future if no use cases arise.

Comment on lines +87 to +94
/**
* Check if an autofix status is terminal (no more updates expected)
*/
function isTerminalStatus(status: string): boolean {
return [
"COMPLETED",
"FAILED",
"ERROR",
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider making the status constants an enum or constant array to ensure consistency and type safety. This would prevent typos and make it easier to maintain the status values across the codebase.

Suggested change
/**
* Check if an autofix status is terminal (no more updates expected)
*/
function isTerminalStatus(status: string): boolean {
return [
"COMPLETED",
"FAILED",
"ERROR",
// Define status constants for better maintainability
const TERMINAL_STATUSES = [
"COMPLETED",
"FAILED",
"ERROR",
"CANCELLED",
"NEED_MORE_INFORMATION",
"WAITING_FOR_USER_RESPONSE",
] as const;
function isTerminalStatus(status: string): boolean {
return TERMINAL_STATUSES.includes(status as any);
}

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines +100 to +106

/**
* Check if an autofix status requires human intervention
*/
function isHumanInterventionStatus(status: string): boolean {
return (
status === "NEED_MORE_INFORMATION" || status === "WAITING_FOR_USER_RESPONSE"
Copy link
Contributor

Choose a reason for hiding this comment

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

The isHumanInterventionStatus function is defined but never used in the codebase. Consider removing it or adding a comment explaining its intended future use to avoid dead code.

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines +111 to +119
* Get guidance message for human intervention states
*/
function getHumanInterventionGuidance(status: string): string {
if (status === "NEED_MORE_INFORMATION") {
return "\nSeer needs additional information to continue the analysis. Please review the insights above and consider providing more context.\n";
}
if (status === "WAITING_FOR_USER_RESPONSE") {
return "\nSeer is waiting for your response to proceed. Please review the analysis and provide feedback.\n";
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider making this function more robust by handling unknown status types with a default message or warning. This would improve error handling for future status additions.

Suggested change
* Get guidance message for human intervention states
*/
function getHumanInterventionGuidance(status: string): string {
if (status === "NEED_MORE_INFORMATION") {
return "\nSeer needs additional information to continue the analysis. Please review the insights above and consider providing more context.\n";
}
if (status === "WAITING_FOR_USER_RESPONSE") {
return "\nSeer is waiting for your response to proceed. Please review the analysis and provide feedback.\n";
}
function getHumanInterventionGuidance(status: string): string {
switch (status) {
case "NEED_MORE_INFORMATION":
return "\nSeer needs additional information to continue the analysis. Please review the insights above and consider providing more context.\n";
case "WAITING_FOR_USER_RESPONSE":
return "\nSeer is waiting for your response to proceed. Please review the analysis and provide feedback.\n";
default:
return "";
}
}

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines +926 to 933
if (!autofixState.autofix) {
output += `Error: Analysis state lost. Please try again by running:\n`;
output += `\`\`\`\n`;
output += params.issueUrl
? `analyze_issue_with_seer(issueUrl="${params.issueUrl}")`
: `analyze_issue_with_seer(organizationSlug="${orgSlug}", issueId="${parsedIssueId}")`;
output += `\n\`\`\`\n`;
return output;
Copy link
Contributor

Choose a reason for hiding this comment

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

Good improvement! This error message provides much clearer guidance to users on how to retry the operation. The conditional logic for showing the appropriate retry command is well implemented.

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines +938 to +939
// Check if completed (terminal state)
if (isTerminalStatus(status)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Excellent refactoring! Extracting the terminal status check into a reusable function improves code maintainability and reduces duplication. The logic is much cleaner now.

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines 946 to 948
}

if (status !== "COMPLETED") {
Copy link
Contributor

Choose a reason for hiding this comment

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

Good consolidation of the human intervention guidance logic. This removes code duplication and centralizes the guidance message generation.

Did we get this right? 👍 / 👎 to inform future reviews.

} else if (status === "WAITING_FOR_USER_RESPONSE") {
output += `\n\nSeer is waiting for your response to proceed. Please review the analysis and provide feedback.\n`;
}
output += getHumanInterventionGuidance(status);
Copy link
Contributor

Choose a reason for hiding this comment

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

The formatting of newlines appears inconsistent between implementations. The previous code at lines 927-929 used double newlines (\n\n) before the guidance message, while the new implementation relies on the single newlines included in the getHumanInterventionGuidance() function. This might result in different spacing in the output compared to the previous version. Consider either:

  1. Adding an additional newline before calling getHumanInterventionGuidance(status), or
  2. Removing the leading newline from the guidance messages in the helper function

This would ensure consistent formatting with the previous implementation.

Spotted by Diamond

Is this helpful? React 👍 or 👎 to let us know.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Bug: Inconsistent Newline Formatting in Guidance Messages

Inconsistent newline formatting for human intervention guidance messages. The getHumanInterventionGuidance helper function returns messages with leading and trailing newlines. However, the existing analysis path adds an extra newline after the guidance, while the polling loop path does not. This results in inconsistent spacing between the two output paths and alters the original formatting behavior.

packages/mcp-server/src/tools.ts#L912-L951

output += `\n**Status**: ${existingStatus}\n`;
output += getHumanInterventionGuidance(existingStatus);
output += "\n";
}
return output;
}
}
// Step 3: Poll until complete or timeout (only for non-terminal states)
const startTime = Date.now();
let lastStatus = "";
while (Date.now() - startTime < SEER_TIMEOUT) {
if (!autofixState.autofix) {
output += `Error: Analysis state lost. Please try again by running:\n`;
output += `\`\`\`\n`;
output += params.issueUrl
? `analyze_issue_with_seer(issueUrl="${params.issueUrl}")`
: `analyze_issue_with_seer(organizationSlug="${orgSlug}", issueId="${parsedIssueId}")`;
output += `\n\`\`\`\n`;
return output;
}
const status = autofixState.autofix.status;
// Check if completed (terminal state)
if (isTerminalStatus(status)) {
output += `## Analysis ${getStatusDisplayName(status)}\n\n`;
// Add all step outputs
for (const step of autofixState.autofix.steps) {
output += getOutputForAutofixStep(step);
output += "\n";
}
if (status !== "COMPLETED") {
output += `\n**Status**: ${status}\n`;
output += getHumanInterventionGuidance(status);
}

Fix in CursorFix in Web


Was this report helpful? Give feedback by reacting with 👍 or 👎

@dcramer dcramer merged commit 409f4a3 into main Jul 7, 2025
14 checks passed
@dcramer dcramer deleted the ref-analyze-tool branch July 7, 2025 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant