simplify: remove workflow_dispatch/schedule from create-prompt

- Remove workflow_dispatch and schedule event handling from create-prompt
  since agent mode doesn't use the standard prompt generation flow
- Enforce mode compatibility at selection time in the registry instead
  of runtime validation in tag mode
- Add explanatory comment in agent mode about why prompt file is needed
- Update tests to reflect simplified event handling

This reduces code duplication and makes the separation between tag mode
(entity-based events) and agent mode (automation events) clearer.
This commit is contained in:
km-anthropic
2025-07-29 10:15:22 -07:00
parent 859e93f18e
commit 26d6ecc65d
8 changed files with 64 additions and 144 deletions

View File

@@ -350,24 +350,6 @@ export function prepareContext(
}; };
break; break;
case "workflow_dispatch":
eventData = {
eventName: "workflow_dispatch",
isPR: false,
...(baseBranch && { baseBranch }),
...(claudeBranch && { claudeBranch }),
};
break;
case "schedule":
eventData = {
eventName: "schedule",
isPR: false,
...(baseBranch && { baseBranch }),
...(claudeBranch && { claudeBranch }),
};
break;
default: default:
throw new Error(`Unsupported event type: ${eventName}`); throw new Error(`Unsupported event type: ${eventName}`);
} }
@@ -430,18 +412,6 @@ export function getEventTypeAndContext(envVars: PreparedContext): {
: `pull request event`, : `pull request event`,
}; };
case "workflow_dispatch":
return {
eventType: "WORKFLOW_DISPATCH",
triggerContext: `workflow dispatch event`,
};
case "schedule":
return {
eventType: "SCHEDULE",
triggerContext: `scheduled automation event`,
};
default: default:
throw new Error(`Unexpected event type`); throw new Error(`Unexpected event type`);
} }

View File

@@ -88,20 +88,6 @@ type PullRequestEvent = {
baseBranch?: string; baseBranch?: string;
}; };
type WorkflowDispatchEvent = {
eventName: "workflow_dispatch";
isPR?: false;
baseBranch?: string;
claudeBranch?: string;
};
type ScheduleEvent = {
eventName: "schedule";
isPR?: false;
baseBranch?: string;
claudeBranch?: string;
};
// Union type for all possible event types // Union type for all possible event types
export type EventData = export type EventData =
| PullRequestReviewCommentEvent | PullRequestReviewCommentEvent
@@ -111,9 +97,7 @@ export type EventData =
| IssueOpenedEvent | IssueOpenedEvent
| IssueAssignedEvent | IssueAssignedEvent
| IssueLabeledEvent | IssueLabeledEvent
| PullRequestEvent | PullRequestEvent;
| WorkflowDispatchEvent
| ScheduleEvent;
// Combined type with separate eventData field // Combined type with separate eventData field
export type PreparedContext = CommonFields & { export type PreparedContext = CommonFields & {

View File

@@ -34,7 +34,7 @@ async function run() {
} }
// Step 4: Get mode and check trigger conditions // Step 4: Get mode and check trigger conditions
const mode = getMode(context.inputs.mode); const mode = getMode(context.inputs.mode, context);
const containsTrigger = mode.shouldTrigger(context); const containsTrigger = mode.shouldTrigger(context);
// Set output for action.yml to check // Set output for action.yml to check

View File

@@ -53,7 +53,10 @@ export const agentMode: Mode = {
recursive: true, recursive: true,
}); });
// Write the prompt - either override_prompt, direct_prompt, or a minimal default // Write the prompt file - the base action requires a prompt_file parameter,
// so we must create this file even though agent mode typically uses
// override_prompt or direct_prompt. If neither is provided, we write
// a minimal prompt with just the repository information.
const promptContent = const promptContent =
context.inputs.overridePrompt || context.inputs.overridePrompt ||
context.inputs.directPrompt || context.inputs.directPrompt ||

View File

@@ -13,6 +13,7 @@
import type { Mode, ModeName } from "./types"; import type { Mode, ModeName } from "./types";
import { tagMode } from "./tag"; import { tagMode } from "./tag";
import { agentMode } from "./agent"; import { agentMode } from "./agent";
import type { ParsedGitHubContext } from "../github/context";
export const DEFAULT_MODE = "tag" as const; export const DEFAULT_MODE = "tag" as const;
export const VALID_MODES = ["tag", "agent"] as const; export const VALID_MODES = ["tag", "agent"] as const;
@@ -27,12 +28,13 @@ const modes = {
} as const satisfies Record<ModeName, Mode>; } as const satisfies Record<ModeName, Mode>;
/** /**
* Retrieves a mode by name. * Retrieves a mode by name and validates it can handle the event type.
* @param name The mode name to retrieve * @param name The mode name to retrieve
* @param context The GitHub context to validate against
* @returns The requested mode * @returns The requested mode
* @throws Error if the mode is not found * @throws Error if the mode is not found or cannot handle the event
*/ */
export function getMode(name: ModeName): Mode { export function getMode(name: ModeName, context: ParsedGitHubContext): Mode {
const mode = modes[name]; const mode = modes[name];
if (!mode) { if (!mode) {
const validModes = VALID_MODES.join("', '"); const validModes = VALID_MODES.join("', '");
@@ -40,6 +42,18 @@ export function getMode(name: ModeName): Mode {
`Invalid mode '${name}'. Valid modes are: '${validModes}'. Please check your workflow configuration.`, `Invalid mode '${name}'. Valid modes are: '${validModes}'. Please check your workflow configuration.`,
); );
} }
// Validate mode can handle the event type
if (
name === "tag" &&
(context.eventName === "workflow_dispatch" ||
context.eventName === "schedule")
) {
throw new Error(
`Tag mode cannot handle ${context.eventName} events. Use 'agent' mode for automation events.`,
);
}
return mode; return mode;
} }

View File

@@ -53,17 +53,6 @@ export const tagMode: Mode = {
}: ModeOptions): Promise<ModeResult> { }: ModeOptions): Promise<ModeResult> {
// Tag mode handles entity-based events (issues, PRs, comments) // Tag mode handles entity-based events (issues, PRs, comments)
// Validate this mode can handle the event
if (
context.eventName === "workflow_dispatch" ||
context.eventName === "schedule"
) {
throw new Error(
`Tag mode cannot handle ${context.eventName} events. ` +
`Use 'agent' mode for automation events.`,
);
}
// Check if actor is human // Check if actor is human
await checkHumanActor(octokit.rest, context); await checkHumanActor(octokit.rest, context);

View File

@@ -3,23 +3,60 @@ import { getMode, isValidMode } from "../../src/modes/registry";
import type { ModeName } from "../../src/modes/types"; import type { ModeName } from "../../src/modes/types";
import { tagMode } from "../../src/modes/tag"; import { tagMode } from "../../src/modes/tag";
import { agentMode } from "../../src/modes/agent"; import { agentMode } from "../../src/modes/agent";
import { createMockContext } from "../mockContext";
describe("Mode Registry", () => { describe("Mode Registry", () => {
test("getMode returns tag mode by default", () => { const mockContext = createMockContext({
const mode = getMode("tag"); eventName: "issue_comment",
});
const mockWorkflowDispatchContext = createMockContext({
eventName: "workflow_dispatch",
});
const mockScheduleContext = createMockContext({
eventName: "schedule",
});
test("getMode returns tag mode for standard events", () => {
const mode = getMode("tag", mockContext);
expect(mode).toBe(tagMode); expect(mode).toBe(tagMode);
expect(mode.name).toBe("tag"); expect(mode.name).toBe("tag");
}); });
test("getMode returns agent mode", () => { test("getMode returns agent mode", () => {
const mode = getMode("agent"); const mode = getMode("agent", mockContext);
expect(mode).toBe(agentMode);
expect(mode.name).toBe("agent");
});
test("getMode throws error for tag mode with workflow_dispatch event", () => {
expect(() => getMode("tag", mockWorkflowDispatchContext)).toThrow(
"Tag mode cannot handle workflow_dispatch events. Use 'agent' mode for automation events.",
);
});
test("getMode throws error for tag mode with schedule event", () => {
expect(() => getMode("tag", mockScheduleContext)).toThrow(
"Tag mode cannot handle schedule events. Use 'agent' mode for automation events.",
);
});
test("getMode allows agent mode for workflow_dispatch event", () => {
const mode = getMode("agent", mockWorkflowDispatchContext);
expect(mode).toBe(agentMode);
expect(mode.name).toBe("agent");
});
test("getMode allows agent mode for schedule event", () => {
const mode = getMode("agent", mockScheduleContext);
expect(mode).toBe(agentMode); expect(mode).toBe(agentMode);
expect(mode.name).toBe("agent"); expect(mode.name).toBe("agent");
}); });
test("getMode throws error for invalid mode", () => { test("getMode throws error for invalid mode", () => {
const invalidMode = "invalid" as unknown as ModeName; const invalidMode = "invalid" as unknown as ModeName;
expect(() => getMode(invalidMode)).toThrow( expect(() => getMode(invalidMode, mockContext)).toThrow(
"Invalid mode 'invalid'. Valid modes are: 'tag', 'agent'. Please check your workflow configuration.", "Invalid mode 'invalid'. Valid modes are: 'tag', 'agent'. Please check your workflow configuration.",
); );
}); });

View File

@@ -29,83 +29,6 @@ describe("parseEnvVarsWithContext", () => {
process.env = originalEnv; process.env = originalEnv;
}); });
describe("workflow_dispatch event", () => {
beforeEach(() => {
process.env = {
...BASE_ENV,
BASE_BRANCH: "main",
};
});
test("should parse workflow_dispatch event correctly", () => {
const mockWorkflowDispatchContext = createMockContext({
eventName: "workflow_dispatch",
payload: {
inputs: {
task: "Run automated task",
},
repository: {
name: "test-repo",
owner: {
login: "test-owner",
},
},
sender: {
login: "test-user",
},
workflow: "test.yml",
},
});
const result = prepareContext(
mockWorkflowDispatchContext,
"",
"main",
undefined,
);
expect(result.repository).toBe("test-owner/test-repo");
expect(result.eventData.eventName).toBe("workflow_dispatch");
expect(result.eventData.isPR).toBe(false);
expect(result.eventData.baseBranch).toBe("main");
// triggerUsername is not extracted for workflow_dispatch events
expect(result.triggerUsername).toBeUndefined();
});
});
describe("schedule event", () => {
beforeEach(() => {
process.env = {
...BASE_ENV,
BASE_BRANCH: "main",
};
});
test("should parse schedule event correctly", () => {
const mockScheduleContext = createMockContext({
eventName: "schedule",
payload: {
schedule: "0 0 * * *",
repository: {
name: "test-repo",
owner: {
login: "test-owner",
},
},
},
});
const result = prepareContext(mockScheduleContext, "", "main", undefined);
expect(result.repository).toBe("test-owner/test-repo");
expect(result.eventData.eventName).toBe("schedule");
expect(result.eventData.isPR).toBe(false);
expect(result.eventData.baseBranch).toBe("main");
// triggerUsername is not extracted for schedule events
expect(result.triggerUsername).toBeUndefined();
});
});
describe("issue_comment event", () => { describe("issue_comment event", () => {
describe("on issue", () => { describe("on issue", () => {
beforeEach(() => { beforeEach(() => {