mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-22 22:44:13 +08:00
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:
@@ -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
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user