feat: enhance mode routing with track_progress and context preservation (#506)

* feat: enhance mode routing with track_progress and context preservation

This PR implements enhanced mode routing to address two critical v1 migration issues:
1. Lost GitHub context when using custom prompts in tag mode
2. Missing tracking comments for automatic PR reviews

Changes:
- Add track_progress input to force tag mode with tracking comments for PR/issue events
- Support custom prompt injection in tag mode via <custom_instructions> section
- Inject GitHub context as environment variables in agent mode
- Validate track_progress usage (only allowed for PR/issue events)
- Comprehensive test coverage for new routing logic

Event Routing:
- Comment events: Default to tag mode, switch to agent with explicit prompt
- PR/Issue events: Default to agent mode, switch to tag mode with track_progress
- Custom prompts can now be used in tag mode without losing context

This ensures backward compatibility while solving context preservation and tracking visibility issues reported in discussions #490 and #491.

* formatting

* fix: address review comments

- Simplify track_progress description to be more general
- Move import to top of types.ts file

* revert: keep detailed track_progress description

The original description provides clarity about which specific event actions are supported.

* fix: add GitHub CI MCP tools to tag mode allowed list

Claude was trying to use CI status tools but they weren't in the
allowed list for tag mode, causing permission errors. This fix adds
the CI tools so Claude can check workflow status when reviewing PRs.

* fix: provide explicit git base branch reference to prevent PR review errors

- Tell Claude to use 'origin/{baseBranch}' instead of assuming 'main'
- Add explicit instructions for git diff/log commands with correct base branch
- Fixes 'fatal: ambiguous argument main..HEAD' error in fork environments
- Claude was autonomously running git diff main..HEAD when reviewing PRs

* fix prompt generation

* ci pass

---------

Co-authored-by: Ashwin Bhat <ashwin@anthropic.com>
This commit is contained in:
kashyap murali
2025-08-28 17:58:32 -07:00
committed by GitHub
parent 0c127307fa
commit c041f89493
12 changed files with 414 additions and 27 deletions

View File

@@ -3,31 +3,65 @@ import {
isEntityContext,
isIssueCommentEvent,
isPullRequestReviewCommentEvent,
isPullRequestEvent,
isIssuesEvent,
isPullRequestReviewEvent,
} from "../github/context";
import { checkContainsTrigger } from "../github/validation/trigger";
export type AutoDetectedMode = "tag" | "agent";
export function detectMode(context: GitHubContext): AutoDetectedMode {
// If prompt is provided, use agent mode for direct execution
if (context.inputs?.prompt) {
return "agent";
// Validate track_progress usage
if (context.inputs.trackProgress) {
validateTrackProgressEvent(context);
}
// Check for @claude mentions (tag mode)
// If track_progress is set for PR/issue events, force tag mode
if (context.inputs.trackProgress && isEntityContext(context)) {
if (isPullRequestEvent(context) || isIssuesEvent(context)) {
return "tag";
}
}
// Comment events (current behavior - unchanged)
if (isEntityContext(context)) {
if (
isIssueCommentEvent(context) ||
isPullRequestReviewCommentEvent(context)
isPullRequestReviewCommentEvent(context) ||
isPullRequestReviewEvent(context)
) {
// If prompt is provided on comment events, use agent mode
if (context.inputs.prompt) {
return "agent";
}
// Default to tag mode if @claude mention found
if (checkContainsTrigger(context)) {
return "tag";
}
}
}
if (context.eventName === "issues") {
if (checkContainsTrigger(context)) {
return "tag";
// Issue events
if (isEntityContext(context) && isIssuesEvent(context)) {
// Check for @claude mentions or labels/assignees
if (checkContainsTrigger(context)) {
return "tag";
}
}
// PR events (opened, synchronize, etc.)
if (isEntityContext(context) && isPullRequestEvent(context)) {
const supportedActions = [
"opened",
"synchronize",
"ready_for_review",
"reopened",
];
if (context.eventAction && supportedActions.includes(context.eventAction)) {
// If prompt is provided, use agent mode (default for automation)
if (context.inputs.prompt) {
return "agent";
}
}
}
@@ -47,6 +81,33 @@ export function getModeDescription(mode: AutoDetectedMode): string {
}
}
function validateTrackProgressEvent(context: GitHubContext): void {
// track_progress is only valid for pull_request and issue events
const validEvents = ["pull_request", "issues"];
if (!validEvents.includes(context.eventName)) {
throw new Error(
`track_progress is only supported for pull_request and issue events. ` +
`Current event: ${context.eventName}`,
);
}
// Additionally validate PR actions
if (context.eventName === "pull_request" && context.eventAction) {
const validActions = [
"opened",
"synchronize",
"ready_for_review",
"reopened",
];
if (!validActions.includes(context.eventAction)) {
throw new Error(
`track_progress for pull_request events is only supported for actions: ` +
`${validActions.join(", ")}. Current action: ${context.eventAction}`,
);
}
}
}
export function shouldUseTrackingComment(mode: AutoDetectedMode): boolean {
return mode === "tag";
}