Simplify agent mode and re-add additional_permissions input

- Agent mode now only triggers when explicit prompt is provided
- Removed automatic triggering for workflow_dispatch/schedule without prompt
- Re-added additional_permissions input for requesting GitHub permissions
- Fixed TypeScript types for mock context helpers to properly handle partial inputs
- Updated documentation to reflect simplified mode behavior
This commit is contained in:
km-anthropic
2025-08-08 14:00:31 -07:00
parent e2aee89b4a
commit 1b4fc382c8
8 changed files with 75 additions and 41 deletions

View File

@@ -53,7 +53,7 @@ Execution steps:
#### Mode System (`src/modes/`)
- **Tag Mode** (`tag/`): Responds to `@claude` mentions and issue assignments
- **Agent Mode** (`agent/`): Automated execution for workflow_dispatch and schedule events only
- **Agent Mode** (`agent/`): Direct execution when explicit prompt is provided
- Extensible registry pattern in `modes/registry.ts`
#### GitHub Integration (`src/github/`)
@@ -118,7 +118,7 @@ src/
- Modes implement `Mode` interface with `shouldTrigger()` and `prepare()` methods
- Registry validates mode compatibility with GitHub event types
- Agent mode only works with workflow_dispatch and schedule events
- Agent mode triggers when explicit prompt is provided
### Comment Threading

View File

@@ -65,6 +65,10 @@ inputs:
description: "Additional arguments to pass directly to Claude CLI"
required: false
default: ""
additional_permissions:
description: "Additional GitHub permissions to request (e.g., 'actions: read')"
required: false
default: ""
use_sticky_comment:
description: "Use just one comment to deliver issue/PR comments"
required: false
@@ -119,6 +123,7 @@ runs:
USE_STICKY_COMMENT: ${{ inputs.use_sticky_comment }}
DEFAULT_WORKFLOW_TOKEN: ${{ github.token }}
USE_COMMIT_SIGNING: ${{ inputs.use_commit_signing }}
ADDITIONAL_PERMISSIONS: ${{ inputs.additional_permissions }}
- name: Install Base Action Dependencies
if: steps.prepare.outputs.contains_trigger == 'true'

View File

@@ -25,19 +25,19 @@ The traditional implementation mode that responds to @claude mentions, issue ass
**Note: Agent mode is currently in active development and may undergo breaking changes.**
For automation with workflow_dispatch and scheduled events only.
For direct automation when an explicit prompt is provided.
- **Triggers**: Only works with `workflow_dispatch` and `schedule` events - does NOT work with PR/issue events
- **Features**: Perfect for scheduled tasks, works with `override_prompt`
- **Use case**: Maintenance tasks, automated reporting, scheduled checks
- **Triggers**: Works with any event when `prompt` input is provided
- **Features**: Direct execution without @claude mentions, no tracking comments
- **Use case**: Automated PR reviews, scheduled tasks, workflow automation
```yaml
- uses: anthropics/claude-code-action@beta
with:
mode: agent
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
override_prompt: |
prompt: |
Check for outdated dependencies and create an issue if any are found.
# Mode is auto-detected when prompt is provided
```
### Experimental Review Mode

View File

@@ -1,23 +1,22 @@
import * as core from "@actions/core";
import { mkdir, writeFile } from "fs/promises";
import type { Mode, ModeOptions, ModeResult } from "../types";
import { isAutomationContext } from "../../github/context";
import type { PreparedContext } from "../../create-prompt/types";
/**
* Agent mode implementation.
*
* This mode is specifically designed for automation events (workflow_dispatch and schedule).
* It bypasses the standard trigger checking and comment tracking used by tag mode,
* making it ideal for scheduled tasks and manual workflow runs.
* This mode runs whenever an explicit prompt is provided in the workflow configuration.
* It bypasses the standard @claude mention checking and comment tracking used by tag mode,
* providing direct access to Claude Code for automation workflows.
*/
export const agentMode: Mode = {
name: "agent",
description: "Automation mode for workflow_dispatch and schedule events",
description: "Direct automation mode for explicit prompts",
shouldTrigger(context) {
// Only trigger for automation events
return isAutomationContext(context);
// Only trigger when an explicit prompt is provided
return !!context.inputs?.prompt;
},
prepareContext(context) {
@@ -41,7 +40,7 @@ export const agentMode: Mode = {
},
async prepare({ context }: ModeOptions): Promise<ModeResult> {
// Agent mode handles automation events (workflow_dispatch, schedule) only
// Agent mode handles automation events and any event with explicit prompts
// TODO: handle by createPrompt (similar to tag and review modes)
// Create prompt directory

View File

@@ -9,13 +9,7 @@ import { checkContainsTrigger } from "../github/validation/trigger";
export type AutoDetectedMode = "tag" | "agent";
export function detectMode(context: GitHubContext): AutoDetectedMode {
// If prompt is provided, always use agent mode
// Reasoning: When users provide explicit instructions via the prompt parameter,
// they want Claude to execute those instructions immediately without waiting for
// @claude mentions or other triggers. This aligns with the v1.0 philosophy where
// Claude Code handles everything - the GitHub Action is just a thin wrapper that
// passes through prompts directly to Claude Code for native handling (including
// slash commands). This provides the most direct and flexible interaction model.
// If prompt is provided, use agent mode for direct execution
if (context.inputs?.prompt) {
return "agent";
}
@@ -38,7 +32,7 @@ export function detectMode(context: GitHubContext): AutoDetectedMode {
}
}
// Default to agent mode for everything else
// Default to agent mode (which won't trigger without a prompt)
return "agent";
}
@@ -47,7 +41,7 @@ export function getModeDescription(mode: AutoDetectedMode): string {
case "tag":
return "Interactive mode triggered by @claude mentions";
case "agent":
return "General automation mode for all events";
return "Direct automation mode for explicit prompts";
default:
return "Unknown mode";
}

View File

@@ -26,7 +26,7 @@ export type ModeData = {
*
* Current modes include:
* - 'tag': Interactive mode triggered by @claude mentions
* - 'agent': General automation mode for all events (default)
* - 'agent': Direct automation mode triggered by explicit prompts
*/
export type Mode = {
name: ModeName;

View File

@@ -27,8 +27,12 @@ const defaultRepository = {
full_name: "test-owner/test-repo",
};
type MockContextOverrides = Omit<Partial<ParsedGitHubContext>, 'inputs'> & {
inputs?: Partial<ParsedGitHubContext['inputs']>;
};
export const createMockContext = (
overrides: Partial<ParsedGitHubContext> = {},
overrides: MockContextOverrides = {},
): ParsedGitHubContext => {
const baseContext: ParsedGitHubContext = {
runId: "1234567890",
@@ -42,15 +46,19 @@ export const createMockContext = (
inputs: defaultInputs,
};
if (overrides.inputs) {
overrides.inputs = { ...defaultInputs, ...overrides.inputs };
}
const mergedInputs = overrides.inputs
? { ...defaultInputs, ...overrides.inputs }
: defaultInputs;
return { ...baseContext, ...overrides };
return { ...baseContext, ...overrides, inputs: mergedInputs };
};
type MockAutomationOverrides = Omit<Partial<AutomationContext>, 'inputs'> & {
inputs?: Partial<AutomationContext['inputs']>;
};
export const createMockAutomationContext = (
overrides: Partial<AutomationContext> = {},
overrides: MockAutomationOverrides = {},
): AutomationContext => {
const baseContext: AutomationContext = {
runId: "1234567890",
@@ -62,7 +70,11 @@ export const createMockAutomationContext = (
inputs: defaultInputs,
};
return { ...baseContext, ...overrides };
const mergedInputs = overrides.inputs
? { ...defaultInputs, ...overrides.inputs }
: defaultInputs;
return { ...baseContext, ...overrides, inputs: mergedInputs };
};
export const mockIssueOpenedContext: ParsedGitHubContext = {

View File

@@ -15,7 +15,7 @@ describe("Agent Mode", () => {
test("agent mode has correct properties", () => {
expect(agentMode.name).toBe("agent");
expect(agentMode.description).toBe(
"Automation mode for workflow_dispatch and schedule events",
"Direct automation mode for explicit prompts",
);
expect(agentMode.shouldCreateTrackingComment()).toBe(false);
expect(agentMode.getAllowedTools()).toEqual([]);
@@ -31,19 +31,19 @@ describe("Agent Mode", () => {
expect(Object.keys(context)).toEqual(["mode", "githubContext"]);
});
test("agent mode only triggers for workflow_dispatch and schedule events", () => {
// Should trigger for automation events
test("agent mode only triggers when prompt is provided", () => {
// Should NOT trigger for automation events without prompt
const workflowDispatchContext = createMockAutomationContext({
eventName: "workflow_dispatch",
});
expect(agentMode.shouldTrigger(workflowDispatchContext)).toBe(true);
expect(agentMode.shouldTrigger(workflowDispatchContext)).toBe(false);
const scheduleContext = createMockAutomationContext({
eventName: "schedule",
});
expect(agentMode.shouldTrigger(scheduleContext)).toBe(true);
expect(agentMode.shouldTrigger(scheduleContext)).toBe(false);
// Should NOT trigger for entity events
// Should NOT trigger for entity events without prompt
const entityEvents = [
"issue_comment",
"pull_request",
@@ -52,8 +52,32 @@ describe("Agent Mode", () => {
] as const;
entityEvents.forEach((eventName) => {
const context = createMockContext({ eventName });
expect(agentMode.shouldTrigger(context)).toBe(false);
const contextNoPrompt = createMockContext({ eventName });
expect(agentMode.shouldTrigger(contextNoPrompt)).toBe(false);
});
// Should trigger for ANY event when prompt is provided
const allEvents = [
"workflow_dispatch",
"schedule",
"issue_comment",
"pull_request",
"pull_request_review",
"issues",
] as const;
allEvents.forEach((eventName) => {
const contextWithPrompt =
eventName === "workflow_dispatch" || eventName === "schedule"
? createMockAutomationContext({
eventName,
inputs: { prompt: "Do something" },
})
: createMockContext({
eventName,
inputs: { prompt: "Do something" },
});
expect(agentMode.shouldTrigger(contextWithPrompt)).toBe(true);
});
});
});