feat: add agent mode for automation scenarios

- Add agent mode that always triggers without checking for mentions
- Implement Mode interface with support for mode-specific tool configuration
- Add getAllowedTools() and getDisallowedTools() methods to Mode interface
- Simplify tests by combining related test cases
- Update documentation and examples to include agent mode
- Fix TypeScript imports to prevent circular dependencies

Agent mode is designed for automation and workflow_dispatch scenarios
where Claude should always run without requiring trigger phrases.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
km-anthropic
2025-07-24 00:01:40 -07:00
parent 9cf75f75b9
commit 3fef2d3f20
11 changed files with 356 additions and 54 deletions

View File

@@ -840,14 +840,29 @@ export async function createPrompt(
const hasActionsReadPermission =
context.inputs.additionalPermissions.get("actions") === "read" &&
context.isPR;
// Get mode-specific tools
const modeAllowedTools = mode.getAllowedTools();
const modeDisallowedTools = mode.getDisallowedTools();
// Combine with existing allowed tools
const combinedAllowedTools = [
...context.inputs.allowedTools,
...modeAllowedTools,
];
const combinedDisallowedTools = [
...context.inputs.disallowedTools,
...modeDisallowedTools,
];
const allAllowedTools = buildAllowedToolsString(
context.inputs.allowedTools,
combinedAllowedTools,
hasActionsReadPermission,
context.inputs.useCommitSigning,
);
const allDisallowedTools = buildDisallowedToolsString(
context.inputs.disallowedTools,
context.inputs.allowedTools,
combinedDisallowedTools,
combinedAllowedTools,
);
core.exportVariable("ALLOWED_TOOLS", allAllowedTools);

View File

@@ -55,7 +55,7 @@ async function run() {
await checkHumanActor(octokit.rest, context);
// Step 6: Create initial tracking comment (mode-aware)
// Some modes (e.g., future review/freeform modes) may not need tracking comments
// Some modes (e.g., agent mode) may not need tracking comments
let commentId: number | undefined;
let commentData:
| Awaited<ReturnType<typeof createInitialComment>>

View File

@@ -7,9 +7,8 @@ import type {
PullRequestReviewEvent,
PullRequestReviewCommentEvent,
} from "@octokit/webhooks-types";
import type { ModeName } from "../modes/registry";
import { DEFAULT_MODE } from "../modes/registry";
import { isValidMode } from "../modes/registry";
import type { ModeName } from "../modes/types";
import { DEFAULT_MODE, isValidMode } from "../modes/registry";
export type ParsedGitHubContext = {
runId: string;

42
src/modes/agent/index.ts Normal file
View File

@@ -0,0 +1,42 @@
import type { Mode } from "../types";
/**
* Agent mode implementation.
*
* This mode is designed for automation and workflow_dispatch scenarios.
* It always triggers (no checking), allows highly flexible configurations,
* and works well with override_prompt for custom workflows.
*
* In the future, this mode could restrict certain tools for safety in automation contexts,
* e.g., disallowing WebSearch or limiting file system operations.
*/
export const agentMode: Mode = {
name: "agent",
description: "Automation mode that always runs without trigger checking",
shouldTrigger() {
return true;
},
prepareContext(context, data) {
return {
mode: "agent",
githubContext: context,
commentId: data?.commentId,
baseBranch: data?.baseBranch,
claudeBranch: data?.claudeBranch,
};
},
getAllowedTools() {
return [];
},
getDisallowedTools() {
return [];
},
shouldCreateTrackingComment() {
return true;
},
};

View File

@@ -5,17 +5,17 @@
*
* To add a new mode:
* 1. Add the mode name to VALID_MODES below
* 2. Create the mode implementation in a new directory (e.g., src/modes/review/)
* 2. Create the mode implementation in a new directory (e.g., src/modes/new-mode/)
* 3. Import and add it to the modes object below
* 4. Update action.yml description to mention the new mode
*/
import type { Mode } from "./types";
import { tagMode } from "./tag/index";
import type { Mode, ModeName } from "./types";
import { tagMode } from "./tag";
import { agentMode } from "./agent";
export const DEFAULT_MODE = "tag" as const;
export const VALID_MODES = ["tag"] as const;
export type ModeName = (typeof VALID_MODES)[number];
export const VALID_MODES = ["tag", "agent"] as const;
/**
* All available modes.
@@ -23,6 +23,7 @@ export type ModeName = (typeof VALID_MODES)[number];
*/
const modes = {
tag: tagMode,
agent: agentMode,
} as const satisfies Record<ModeName, Mode>;
/**

View File

@@ -1,5 +1,6 @@
import type { ParsedGitHubContext } from "../github/context";
import type { ModeName } from "./registry";
export type ModeName = "tag" | "agent";
export type ModeContext = {
mode: ModeName;
@@ -20,9 +21,9 @@ export type ModeData = {
* Each mode defines its own behavior for trigger detection, prompt generation,
* and tracking comment creation.
*
* Future modes might include:
* - 'review': Optimized for code reviews without tracking comments
* - 'freeform': For automation with no trigger checking
* Current modes include:
* - 'tag': Traditional implementation triggered by mentions/assignments
* - 'agent': For automation with no trigger checking
*/
export type Mode = {
name: ModeName;
@@ -39,13 +40,12 @@ export type Mode = {
prepareContext(context: ParsedGitHubContext, data?: ModeData): ModeContext;
/**
* Returns additional tools that should be allowed for this mode
* (base GitHub tools are always included)
* Returns the list of tools that should be allowed for this mode
*/
getAllowedTools(): string[];
/**
* Returns tools that should be disallowed for this mode
* Returns the list of tools that should be disallowed for this mode
*/
getDisallowedTools(): string[];