Repository: giselles-ai/giselle
Pull request #919: Refactor trigger input processing to use typed parameters and webhook events
Author: login: toyamarinyon
Labels: name: codex
Created: 2025-05-22T07:12:22Z | Merged: 2025-05-26T01:16:24Z

## Summary

This PR refactors the trigger input processing system to replace generic payload handling with strongly-typed parameters and structured webhook events. This change improves type safety, eliminates ambiguous payload processing, and streamlines the flow execution pipeline.

## Key Changes

### 🔧 Type System Improvements
- **Replaced `GenerationInput` with `ParameterItem`**: Transitioned from generic key-value inputs to typed parameter items with specific handling for `text`, `multiline-text`, and `number` types
- **Introduced `GitHubWebhookEventInput`**: Added strongly-typed webhook event handling to replace generic payload inputs
- **Enhanced type safety**: Added exhaustive type checking for input types to prevent runtime errors

### 🌊 Flow Execution Refactoring
- **Standardized trigger inputs**: Converted from mixed payload/input system to consistent `triggerInputs` array structure
- **Streamlined GitHub webhook processing**: Direct webhook event processing without intermediate payload conversion
- **Improved trigger resolution**: Direct output generation from typed inputs instead of building parameter items

### 🔄 API Interface Changes
- **Updated `runFlow` signature**: Changed from `payload?: unknown` and `triggerInputs?: GenerationContextInput` to `triggerInputs?: GenerationContextInput[]`
- **Removed deprecated payload parameters**: Eliminated generic payload handling throughout the flow execution system
- **Enhanced webhook event processing**: GitHub events now use structured `github-webhook-event` input type

### 🎯 UI Component Updates
- **Enhanced trigger input dialog**: Updated form processing to handle typed inputs with proper type conversion
- **Improved parameter handling**: Added specific handling for different input types (text, multiline-text, number) with appropriate validation

## Technical Details

### Before
```typescript
// Generic payload handling
runFlow({
  triggerId: trigger.id,
  payload: githubEvent, // Untyped payload
});

// Mixed input types
const generationInputs: GenerationInput[] = [];
for (const [key, value] of formData.entries()) {
  generationInputs.push({
    type: "keyValue",
    name: key,
    value: value.toString(),
  });
}
```

### After
```typescript
// Structured webhook events
runFlow({
  triggerId: trigger.id,
  triggerInputs: [{
    type: "github-webhook-event",
    webhookEvent: event, // Typed webhook event
  }],
});

// Typed parameter items
const parameterItems: ParameterItem[] = [];
switch (input.type) {
  case "text":
  case "multiline-text":
    parameterItems.push({
      type: "string",
      name: input.name,
      value: formDataEntryValue,
    });
    break;
  case "number":
    parameterItems.push({
      type: "number", 
      name: input.name,
      value: Number.parseInt(formDataEntryValue),
    });
    break;
}
```

## Files Changed

- **`packages/data-type/src/generation/context.ts`**: Updated generation context types
- **`packages/giselle-engine/src/core/flows/`**: Refactored flow execution and trigger resolution
- **`packages/giselle-engine/src/core/github/`**: Enhanced GitHub webhook handling with typed events
- **`internal-packages/workflow-designer-ui/`**: Updated trigger input dialog with typed parameter processing

## Testing

- ✅ `pnpm build-sdk` - SDK builds successfully
- ⚠️ `pnpm check-types` - Network connectivity issues (ENOTFOUND registry.npmjs.org)
- ⚠️ `pnpm test` - Network connectivity issues (ENOTFOUND registry.npmjs.org)

## Migration Impact

This is a breaking change for:
- Components using the old `GenerationInput` type
- Flow execution systems expecting generic payload parameters
- Webhook handlers using untyped payload processing

The migration path involves:
1. Replace `GenerationInput` usage with `ParameterItem`
2. Update flow execution calls to use structured `triggerInputs` arrays
3. Migrate webhook handlers to use `GitHubWebhookEventInput` type

## Benefits

- **Improved Type Safety**: Eliminates runtime type errors through compile-time checking
- **Better Developer Experience**: Clear, typed interfaces for trigger input processing
- **Enhanced Maintainability**: Structured approach to webhook and parameter handling
- **Consistent API**: Unified trigger input processing across all trigger types

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Enhanced support for structured trigger inputs, allowing for both parameter-based and GitHub webhook event triggers.

- **Refactor**
  - Unified and streamlined handling of trigger inputs across the application, improving reliability and maintainability.
  - Manual and webhook-based triggers now use explicit, discriminated input types for greater clarity.
  - Updated internal logic to extract and process trigger data more consistently.
  - Simplified trigger resolution to focus on single output per event, improving event handling precision.
  - Improved flow execution by removing deprecated payload parameters and aligning input types.
  - Optimized parameter lookup and output construction for manual triggers.
  - Ensured fresh data retrieval by bypassing cache in generation fetching.

- **Chores**
  - Added a new development dependency for GitHub tooling.
  - Removed unused code and debugging statements for cleaner operation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/internal-packages/workflow-designer-ui/src/header/ui/trigger-input-dialog.tsx b/internal-packages/workflow-designer-ui/src/header/ui/trigger-input-dialog.tsx
index 22d1669df7..5890dc8778 100644
--- a/internal-packages/workflow-designer-ui/src/header/ui/trigger-input-dialog.tsx
+++ b/internal-packages/workflow-designer-ui/src/header/ui/trigger-input-dialog.tsx
@@ -1,10 +1,9 @@
 import type {
-	FlowTrigger,
 	Generation,
-	GenerationInput,
+	ParameterItem,
 	TriggerNode,
 } from "@giselle-sdk/data-type";
-import type { TriggerProvider, githubTriggers } from "@giselle-sdk/flow";
+import type { githubTriggers } from "@giselle-sdk/flow";
 import { useGenerationRunnerSystem } from "@giselle-sdk/giselle-engine/react";
 import { buildWorkflowFromNode } from "@giselle-sdk/workflow-utils";
 import { clsx } from "clsx/lite";
@@ -20,7 +19,6 @@ import {
 } from "react";
 import type { z } from "zod";
 import { useTrigger } from "../../hooks/use-trigger";
-import { triggerNodeDefaultName } from "../../utils";
 
 export function Button({
 	leftIcon: LeftIcon,
@@ -271,14 +269,36 @@ export function TriggerInputDialog({
 			const generations: Generation[] = [];
 			flow.jobs.map((job) =>
 				job.operations.map((operation) => {
-					const generationInputs: GenerationInput[] = [];
+					const parameterItems: ParameterItem[] = [];
 					if (operation.node.content.type === "trigger") {
 						const formData = new FormData(e.currentTarget);
-						for (const [key, value] of formData.entries()) {
-							generationInputs.push({
-								name: key,
-								value: value.toString(),
-							});
+						for (const input of inputs) {
+							const formDataEntryValue = formData.get(input.name);
+							if (typeof formDataEntryValue === "string") {
+								switch (input.type) {
+									case "text":
+									case "multiline-text":
+										parameterItems.push({
+											type: "string",
+											name: input.name,
+											value: formDataEntryValue,
+										});
+										break;
+									case "number":
+										parameterItems.push({
+											type: "number",
+											name: input.name,
+											value: Number.parseInt(formDataEntryValue),
+										});
+										break;
+									default: {
+										const _exhaustiveCheck: never = input.type;
+										throw new Error(
+											`Unhandled input type: ${_exhaustiveCheck}`,
+										);
+									}
+								}
+							}
 						}
 					}
 					generations.push(
@@ -287,7 +307,10 @@ export function TriggerInputDialog({
 								type: "workspace",
 								id: data.id,
 							},
-							inputs: generationInputs,
+							inputs:
+								parameterItems.length > 0
+									? [{ type: "parameters", items: parameterItems }]
+									: [],
 							...operation.generationTemplate,
 						}),
 					);
@@ -309,7 +332,7 @@ export function TriggerInputDialog({
 				);
 			}
 		},
-		[node.id, data, createGeneration, startGeneration],
+		[node.id, data, createGeneration, startGeneration, inputs],
 	);
 
 	if (isLoading || trigger === undefined) {
diff --git a/packages/data-mod/src/index.ts b/packages/data-mod/src/index.ts
index 028e50629e..640a1dd4cb 100644
--- a/packages/data-mod/src/index.ts
+++ b/packages/data-mod/src/index.ts
@@ -28,7 +28,6 @@ export function parseAndMod<T extends ZodSchema>(
 	}
 
 	if (prevError?.toString() === parseResult.error.toString()) {
-		console.log(JSON.stringify(data));
 		throw parseResult.error;
 	}
 
diff --git a/packages/data-type/package.json b/packages/data-type/package.json
index 5bc6da9362..7799982049 100644
--- a/packages/data-type/package.json
+++ b/packages/data-type/package.json
@@ -22,6 +22,7 @@
 		}
 	},
 	"devDependencies": {
+		"@giselle-sdk/github-tool": "workspace:^",
 		"@giselle-sdk/utils": "workspace:*",
 		"@giselle/giselle-sdk-tsconfig": "workspace:*",
 		"tsup": "catalog:",
diff --git a/packages/data-type/src/generation/context.ts b/packages/data-type/src/generation/context.ts
index 644f37e3d2..6ff45a0b1b 100644
--- a/packages/data-type/src/generation/context.ts
+++ b/packages/data-type/src/generation/context.ts
@@ -1,6 +1,7 @@
+import type { WebhookEvent } from "@giselle-sdk/github-tool";
 import { z } from "zod";
 import { Connection } from "../connection";
-import { Node, NodeBase, NodeId, OperationNode } from "../node";
+import { Node, NodeBase, OperationNode } from "../node";
 import { RunId } from "../run";
 import { WorkspaceId } from "../workspace";
 
@@ -39,11 +40,43 @@ export const GenerationOrigin = z.discriminatedUnion("type", [
 ]);
 export type GenerationOrigin = z.infer<typeof GenerationOrigin>;
 
-export const GenerationInput = z.object({
+export const StringParameterItem = z.object({
 	name: z.string(),
+	type: z.literal("string"),
 	value: z.string(),
 });
-export type GenerationInput = z.infer<typeof GenerationInput>;
+export type StringParameterItem = z.infer<typeof StringParameterItem>;
+
+export const NumberParameterItem = z.object({
+	name: z.string(),
+	type: z.literal("number"),
+	value: z.number(),
+});
+export type NumberParameterItem = z.infer<typeof NumberParameterItem>;
+
+export const ParameterItem = z.discriminatedUnion("type", [
+	StringParameterItem,
+	NumberParameterItem,
+]);
+export type ParameterItem = z.infer<typeof ParameterItem>;
+
+export const ParametersInput = z.object({
+	type: z.literal("parameters"),
+	items: z.array(ParameterItem),
+});
+export type ParametersInput = z.infer<typeof ParametersInput>;
+
+export const GitHubWebhookEventInput = z.object({
+	type: z.literal("github-webhook-event"),
+	webhookEvent: z.custom<WebhookEvent>(),
+});
+export type GitHubWebhookEventInput = z.infer<typeof GitHubWebhookEventInput>;
+
+export const GenerationContextInput = z.discriminatedUnion("type", [
+	ParametersInput,
+	GitHubWebhookEventInput,
+]);
+export type GenerationContextInput = z.infer<typeof GenerationContextInput>;
 
 export const GenerationContext = z.object({
 	operationNode: OperationNode,
@@ -51,7 +84,7 @@ export const GenerationContext = z.object({
 	sourceNodes: z.array(Node),
 	origin: GenerationOrigin,
 	inputs: z
-		.array(GenerationInput)
+		.array(GenerationContextInput)
 		.optional()
 		.describe(
 			"Inputs from node connections are represented in sourceNodes, while this represents inputs from the external environment. Mainly used with Trigger nodes.",
@@ -67,6 +100,6 @@ export const GenerationContextLike = z.object({
 	sourceNodes: z.array(z.any()),
 	connections: z.array(z.any()).default([]),
 	origin: GenerationOrigin,
-	inputs: z.array(GenerationInput).optional(),
+	inputs: z.array(GenerationContextInput).optional(),
 });
 export type GenerationContextLike = z.infer<typeof GenerationContextLike>;
diff --git a/packages/giselle-engine/src/core/flows/resolve-trigger.ts b/packages/giselle-engine/src/core/flows/resolve-trigger.ts
index ed2558ff74..b84ac2b5e1 100644
--- a/packages/giselle-engine/src/core/flows/resolve-trigger.ts
+++ b/packages/giselle-engine/src/core/flows/resolve-trigger.ts
@@ -1,7 +1,7 @@
 import {
 	type CompletedGeneration,
 	GenerationContext,
-	type GenerationInput,
+	type GenerationContextInput,
 	type GenerationOutput,
 	type QueuedGeneration,
 	isTriggerNode,
@@ -13,15 +13,13 @@ import {
 	setGenerationIndex,
 	setNodeGenerationIndex,
 } from "../generations/utils";
-import { buildTriggerInputs } from "../github/trigger-utils";
+import { resolveTrigger as resolveGitHubTrigger } from "../github/trigger-utils";
 import type { GiselleEngineContext } from "../types";
 import { getFlowTrigger } from "./utils";
 
 export async function resolveTrigger(args: {
 	context: GiselleEngineContext;
 	generation: QueuedGeneration;
-	/** @todo Make this more generic. Should use GenerationContextInput. */
-	githubWebhookEvent?: unknown;
 }) {
 	const operationNode = args.generation.context.operationNode;
 	if (!isTriggerNode(operationNode)) {
@@ -37,54 +35,60 @@ export async function resolveTrigger(args: {
 
 	const generationContext = GenerationContext.parse(args.generation.context);
 
-	let githubWebhookInputs: GenerationInput[] | null = null;
-	if (
-		args.githubWebhookEvent !== undefined &&
-		isWebhookEvent(args.githubWebhookEvent) &&
-		triggerData.configuration.provider === "github"
-	) {
-		githubWebhookInputs = buildTriggerInputs({
-			githubTrigger: githubTriggers[triggerData.configuration.event.id],
-			trigger: triggerData,
-			webhookEvent: args.githubWebhookEvent,
-		});
-	}
-
 	const outputs: GenerationOutput[] = [];
 	switch (triggerData.configuration.provider) {
 		case "github": {
-			const trigger = githubTriggers[triggerData.configuration.event.id];
-			const inputsToUse = githubWebhookInputs ?? generationContext.inputs ?? [];
-			for (const payload of trigger.event.payloads.keyof().options) {
-				const input = inputsToUse.find((i) => i.name === payload);
-				if (input === undefined) {
-					continue;
-				}
-				const output = operationNode.outputs.find(
-					(output) => output.accessor === payload,
-				);
-				if (output === undefined) {
-					continue;
-				}
-				outputs.push({
-					type: "generated-text",
-					outputId: output.id,
-					content: input.value,
+			const githubWebhookEventInput = generationContext.inputs?.find(
+				(input) => input.type === "github-webhook-event",
+			);
+			if (githubWebhookEventInput === undefined) {
+				throw new Error("Missing github-webhook-event input");
+			}
+			if (triggerData.configuration.provider !== "github") {
+				throw new Error("Invalid provider");
+			}
+			for (const output of operationNode.outputs) {
+				const resolveOutput = resolveGitHubTrigger({
+					output,
+					githubTrigger: githubTriggers[triggerData.configuration.event.id],
+					trigger: triggerData,
+					webhookEvent: githubWebhookEventInput.webhookEvent,
 				});
+				if (resolveOutput !== null) {
+					outputs.push(resolveOutput);
+				}
 			}
 			break;
 		}
 		case "manual": {
+			// Find ParametersInput once outside the loop
+			const parametersInput = generationContext.inputs?.find(
+				(i): i is GenerationContextInput & { type: "parameters" } =>
+					i.type === "parameters",
+			);
+
+			// Create Map of outputs by accessor for O(1) lookup
+			const outputsByAccessor = new Map(
+				operationNode.outputs.map((output) => [output.accessor, output]),
+			);
+
 			for (const parameter of triggerData.configuration.event.parameters) {
-				const input = generationContext.inputs?.find(
-					(input) => input.name === parameter.id,
-				);
-				if (input === undefined) {
+				let parameterValue: string | undefined;
+
+				if (parametersInput) {
+					const parameterItem = parametersInput.items.find(
+						(item) => item.name === parameter.id,
+					);
+					if (parameterItem) {
+						parameterValue = parameterItem.value.toString();
+					}
+				}
+
+				if (parameterValue === undefined) {
 					continue;
 				}
-				const output = operationNode.outputs.find(
-					(output) => output.accessor === parameter.id,
-				);
+
+				const output = outputsByAccessor.get(parameter.id);
 				if (output === undefined) {
 					continue;
 				}
@@ -92,7 +96,7 @@ export async function resolveTrigger(args: {
 				outputs.push({
 					type: "generated-text",
 					outputId: output.id,
-					content: input.value,
+					content: parameterValue,
 				});
 			}
 			break;
diff --git a/packages/giselle-engine/src/core/flows/run-flow.ts b/packages/giselle-engine/src/core/flows/run-flow.ts
index 0830fbc2a1..0f52848802 100644
--- a/packages/giselle-engine/src/core/flows/run-flow.ts
+++ b/packages/giselle-engine/src/core/flows/run-flow.ts
@@ -1,7 +1,7 @@
 import {
 	type FlowTriggerId,
+	type GenerationContextInput,
 	GenerationId,
-	type GenerationInput,
 	type QueuedGeneration,
 	RunId,
 } from "@giselle-sdk/data-type";
@@ -17,8 +17,7 @@ import { getFlowTrigger } from "./utils";
 export async function runFlow(args: {
 	triggerId: FlowTriggerId;
 	context: GiselleEngineContext;
-	triggerInputs?: GenerationInput[];
-	payload?: unknown;
+	triggerInputs?: GenerationContextInput[];
 }) {
 	const trigger = await getFlowTrigger({
 		storage: args.context.storage,
@@ -90,7 +89,6 @@ export async function runFlow(args: {
 						await resolveTrigger({
 							context: args.context,
 							generation,
-							githubWebhookEvent: args.payload,
 						});
 						break;
 					default: {
diff --git a/packages/giselle-engine/src/core/generations/get-generation.ts b/packages/giselle-engine/src/core/generations/get-generation.ts
index 69bc2fbb0a..8e9da0faec 100644
--- a/packages/giselle-engine/src/core/generations/get-generation.ts
+++ b/packages/giselle-engine/src/core/generations/get-generation.ts
@@ -9,5 +9,8 @@ export async function getGeneration(args: {
 	return await getGenerationInternal({
 		storage: args.context.storage,
 		generationId: args.generationId,
+		options: {
+			bypassingCache: true,
+		},
 	});
 }
diff --git a/packages/giselle-engine/src/core/github/event-handlers.test.ts b/packages/giselle-engine/src/core/github/event-handlers.test.ts
index ad44c97f96..4ebcbdf12f 100644
--- a/packages/giselle-engine/src/core/github/event-handlers.test.ts
+++ b/packages/giselle-engine/src/core/github/event-handlers.test.ts
@@ -629,7 +629,12 @@ describe("GitHub Event Handlers", () => {
 			expect(testDeps.runFlow).toHaveBeenCalledWith({
 				context: expect.anything(),
 				triggerId: mockFlowTriggerId,
-				payload: event,
+				triggerInputs: [
+					{
+						type: "github-webhook-event",
+						webhookEvent: event,
+					},
+				],
 			});
 		});
 
diff --git a/packages/giselle-engine/src/core/github/event-handlers.ts b/packages/giselle-engine/src/core/github/event-handlers.ts
index 069ff5edb2..21bff29f2b 100644
--- a/packages/giselle-engine/src/core/github/event-handlers.ts
+++ b/packages/giselle-engine/src/core/github/event-handlers.ts
@@ -265,7 +265,12 @@ export async function processEvent<TEventName extends WebhookEventName>(
 			await deps.runFlow({
 				context: args.context,
 				triggerId: args.trigger.id,
-				payload: args.event,
+				triggerInputs: [
+					{
+						type: "github-webhook-event",
+						webhookEvent: args.event,
+					},
+				],
 			});
 			return true;
 		}
diff --git a/packages/giselle-engine/src/core/github/handle-webhook.ts b/packages/giselle-engine/src/core/github/handle-webhook.ts
index e8645c6144..f143e35c3e 100644
--- a/packages/giselle-engine/src/core/github/handle-webhook.ts
+++ b/packages/giselle-engine/src/core/github/handle-webhook.ts
@@ -181,7 +181,6 @@ async function runRepositoryTrigger(args: {
 		runFlow({
 			context: args.context,
 			triggerId: args.trigger.id,
-			payload: args.githubEvent,
 		}),
 	]);
 }
diff --git a/packages/giselle-engine/src/core/github/trigger-utils.ts b/packages/giselle-engine/src/core/github/trigger-utils.ts
index b00eb9e067..8eb5a2b112 100644
--- a/packages/giselle-engine/src/core/github/trigger-utils.ts
+++ b/packages/giselle-engine/src/core/github/trigger-utils.ts
@@ -1,4 +1,9 @@
-import type { FlowTrigger, GenerationInput } from "@giselle-sdk/data-type";
+import type {
+	FlowTrigger,
+	GenerationContextInput,
+	GenerationOutput,
+	Output,
+} from "@giselle-sdk/data-type";
 import type { githubTriggers } from "@giselle-sdk/flow";
 import {
 	type WebhookEvent,
@@ -8,109 +13,126 @@ import {
 import { type GitHubEvent, GitHubEventType } from "./events";
 import { parseCommand } from "./utils";
 
-interface BuildTriggerInputsArgs {
+interface ResolveTriggerArgs {
+	output: Output;
 	githubTrigger: (typeof githubTriggers)[keyof typeof githubTriggers];
 	trigger: FlowTrigger;
 	webhookEvent: WebhookEvent;
 }
-export function buildTriggerInputs(
-	args: BuildTriggerInputsArgs,
-): GenerationInput[] | null {
-	const inputs: GenerationInput[] = [
-		...buildIssueCreatedInputs(args),
-		...buildIssueClosedInputs(args),
-		...buildIssueCommentInputs(args),
-		...buildPullRequestOpenedInputs(args),
-		...buildPullRequestReadyForReviewInputs(args),
-		...buildPullRequestClosedInputs(args),
-		...buildPullRequestCommentInputs(args),
-	];
-
-	return inputs.length > 0 ? inputs : null;
+export function resolveTrigger(args: ResolveTriggerArgs) {
+	return (
+		resolveIssueCreatedTrigger(args) ||
+		resolveIssueClosedTrigger(args) ||
+		resolveIssueCommentTrigger(args) ||
+		resolvePullRequestOpenedTrigger(args) ||
+		resolvePullRequestReadyForReviewTrigger(args) ||
+		resolvePullRequestClosedTrigger(args) ||
+		resolvePullRequestCommentTrigger(args)
+	);
 }
 
-function buildIssueCreatedInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueCreatedTrigger(args: ResolveTriggerArgs) {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issues.opened") ||
 		args.githubTrigger.event.id !== "github.issue.created"
 	) {
-		return [];
+		return null;
 	}
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildIssueClosedInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueClosedTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issues.closed") ||
 		args.githubTrigger.event.id !== "github.issue.closed"
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildIssueCommentInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueCommentTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issue_comment.created") ||
 		args.trigger.configuration.event.id !== "github.issue_comment.created" ||
 		args.githubTrigger.event.id !== "github.issue_comment.created"
 	) {
-		return [];
+		return null;
 	}
 
 	const command = parseCommand(args.webhookEvent.data.payload.comment.body);
@@ -118,189 +140,244 @@ function buildIssueCommentInputs(args: BuildTriggerInputsArgs) {
 		command === null ||
 		command.callsign !== args.trigger.configuration.event.conditions.callsign
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "body":
-				inputs.push({
-					name: "body",
-					value: command.content,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: command.content,
+				} satisfies GenerationOutput;
 			case "issueBody":
-				inputs.push({
-					name: "issueBody",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			case "issueTitle":
-				inputs.push({
-					name: "issueTitle",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildPullRequestOpenedInputs(args: BuildTriggerInputsArgs) {
+function resolvePullRequestOpenedTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "pull_request.opened") ||
 		args.githubTrigger.event.id !== "github.pull_request.opened"
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.pull_request.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.pull_request.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.pull_request.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.pull_request.body ?? "",
+				} satisfies GenerationOutput;
 			case "number":
-				inputs.push({
-					name: "number",
-					value: args.webhookEvent.data.payload.pull_request.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content:
+						args.webhookEvent.data.payload.pull_request.number.toString(),
+				} satisfies GenerationOutput;
 			case "pullRequestUrl":
-				inputs.push({
-					name: "pullRequestUrl",
-					value: args.webhookEvent.data.payload.pull_request.html_url,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.pull_request.html_url,
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildPullRequestReadyForReviewInputs(args: BuildTriggerInputsArgs) {
+function resolvePullRequestReadyForReviewTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "pull_request.ready_for_review") ||
 		args.githubTrigger.event.id !== "github.pull_request.ready_for_review"
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.pull_request.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.pull_request.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.pull_request.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.pull_request.body ?? "",
+				} satisfies GenerationOutput;
 			case "number":
-				inputs.push({
-					name: "number",
-					value: args.webhookEvent.data.payload.pull_request.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content:
+						args.webhookEvent.data.payload.pull_request.number.toString(),
+				} satisfies GenerationOutput;
 			case "pullRequestUrl":
-				inputs.push({
-					name: "pullRequestUrl",
-					value: args.webhookEvent.data.payload.pull_request.html_url,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.pull_request.html_url,
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildPullRequestClosedInputs(args: BuildTriggerInputsArgs) {
+function resolvePullRequestClosedTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "pull_request.closed") ||
 		args.githubTrigger.event.id !== "github.pull_request.closed"
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.pull_request.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.pull_request.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.pull_request.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.pull_request.body ?? "",
+				} satisfies GenerationOutput;
 			case "number":
-				inputs.push({
-					name: "number",
-					value: args.webhookEvent.data.payload.pull_request.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content:
+						args.webhookEvent.data.payload.pull_request.number.toString(),
+				} satisfies GenerationOutput;
 			case "pullRequestUrl":
-				inputs.push({
-					name: "pullRequestUrl",
-					value: args.webhookEvent.data.payload.pull_request.html_url,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.pull_request.html_url,
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildPullRequestCommentInputs(args: BuildTriggerInputsArgs) {
+function resolvePullRequestCommentTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issue_comment.created") ||
 		args.trigger.configuration.event.id !==
 			"github.pull_request_comment.created" ||
 		args.githubTrigger.event.id !== "github.pull_request_comment.created"
 	) {
-		return [];
+		return null;
 	}
 
 	if (args.webhookEvent.data.payload.issue?.pull_request === null) {
-		return [];
+		return null;
 	}
 
 	const command = parseCommand(args.webhookEvent.data.payload.comment.body);
@@ -308,41 +385,52 @@ function buildPullRequestCommentInputs(args: BuildTriggerInputsArgs) {
 		command === null ||
 		command.callsign !== args.trigger.configuration.event.conditions.callsign
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "body":
-				inputs.push({
-					name: "body",
-					value: command.content,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: command.content,
+				} satisfies GenerationOutput;
 			case "issueBody":
-				inputs.push({
-					name: "issueBody",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			case "issueTitle":
-				inputs.push({
-					name: "issueTitle",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
diff --git a/packages/giselle-engine/src/core/index.ts b/packages/giselle-engine/src/core/index.ts
index 5aa8a926ac..f822b47609 100644
--- a/packages/giselle-engine/src/core/index.ts
+++ b/packages/giselle-engine/src/core/index.ts
@@ -4,8 +4,8 @@ import type {
 	FlowTrigger,
 	FlowTriggerId,
 	Generation,
+	GenerationContextInput,
 	GenerationId,
-	GenerationInput,
 	GenerationOrigin,
 	NodeId,
 	OverrideNode,
@@ -225,8 +225,7 @@ export function GiselleEngine(config: GiselleEngineConfig) {
 		}) => executeAction({ ...args, context }),
 		runFlow: async (args: {
 			triggerId: FlowTriggerId;
-			triggerInputs?: GenerationInput[];
-			payload?: unknown;
+			triggerInputs?: GenerationContextInput[];
 		}) => runFlow({ ...args, context }),
 		handleGitHubWebhookV2: async (args: { request: Request }) =>
 			handleGitHubWebhookV2({ ...args, context }),
diff --git a/packages/giselle-engine/src/http/router.ts b/packages/giselle-engine/src/http/router.ts
index 65bb7edc68..b6669554ea 100644
--- a/packages/giselle-engine/src/http/router.ts
+++ b/packages/giselle-engine/src/http/router.ts
@@ -4,8 +4,8 @@ import {
 	FlowTrigger,
 	FlowTriggerId,
 	Generation,
+	GenerationContextInput,
 	GenerationId,
-	GenerationInput,
 	GenerationOrigin,
 	NodeId,
 	OverrideNode,
@@ -302,8 +302,7 @@ export const createJsonRouters = {
 		createHandler({
 			input: z.object({
 				triggerId: FlowTriggerId.schema,
-				triggerInputs: z.array(GenerationInput).optional(),
-				payload: z.unknown().optional(),
+				triggerInputs: z.array(GenerationContextInput).optional(),
 			}),
 			handler: async ({ input }) => {
 				await giselleEngine.runFlow(input);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 613a63a3fc..bb0f98f3f7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -832,6 +832,9 @@ importers:
         specifier: 'catalog:'
         version: 3.24.1
     devDependencies:
+      '@giselle-sdk/github-tool':
+        specifier: workspace:^
+        version: link:../github-tool
       '@giselle-sdk/utils':
         specifier: workspace:*
         version: link:../utils


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>packages/giselle-engine/src/core/flows/resolve-trigger.ts (1)</summary><blockquote>

`107-113`: _🛠️ Refactor suggestion_

**Preserve original `queuedAt` / `startedAt` timestamps**

Overwriting `queuedAt` and `startedAt` with `Date.now()` loses the true queue/start times and breaks latency metrics.  Only `completedAt` should be updated:

```diff
-		queuedAt: Date.now(),
-		startedAt: Date.now(),
+		queuedAt: args.generation.queuedAt,
+		startedAt: args.generation.startedAt ?? Date.now(),
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (4)</summary><blockquote>

<details>
<summary>packages/giselle-engine/src/core/flows/resolve-trigger.ts (2)</summary><blockquote>

`10-10`: **Remove unused `isWebhookEvent` import**

`isWebhookEvent` is imported but never referenced in this module, which will trip the linter/tsc `no-unused-vars` rule and bloats the bundle.

```diff
-import { isWebhookEvent } from "@giselle-sdk/github-tool";
```

---

`47-49`: **Drop redundant provider guard**

Inside the `"github"` switch arm we already know the provider *is* `"github"`, so the extra check adds dead code and an unnecessary branch.

```diff
-			if (triggerData.configuration.provider !== "github") {
-				throw new Error("Invalid provider");
-			}
```

</blockquote></details>
<details>
<summary>packages/giselle-engine/src/core/github/trigger-utils.ts (2)</summary><blockquote>

`1-6`: **Prune unused imports**

`GenerationContextInput`, `isWebhookEvent`, `GitHubEvent`, and `GitHubEventType` are not referenced after the refactor.  Keeping them increases maintenance burden and will trigger `no-unused-vars`.

```diff
-import type {
-	FlowTrigger,
-	GenerationContextInput,
-	GenerationOutput,
-	Output,
-} from "@giselle-sdk/data-type";
+import type { FlowTrigger, GenerationOutput, Output } from "@giselle-sdk/data-type";
@@
-import {
-	type WebhookEvent,
-	ensureWebhookEvent,
-	isWebhookEvent,
-} from "@giselle-sdk/github-tool";
+import { type WebhookEvent, ensureWebhookEvent } from "@giselle-sdk/github-tool";
-
-import { type GitHubEvent, GitHubEventType } from "./events";
```

---

`23-31`: **Short-circuit evaluation may call multiple resolvers**

Because every resolver that returns `null` still evaluates, the average case does more work than necessary.  
Consider switching on `args.githubTrigger.event.id` to invoke only the relevant resolver, improving perf and debuggability.  
(Not critical, but worth noting for high-throughput webhook ingestion.)

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between f138fdfec410b250c353de4f7cb895ebdcb2afb5 and 780dfd6e44c48f19a10acf66e31a44e813f81c1c.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `pnpm-lock.yaml` is excluded by `!**/pnpm-lock.yaml`

</details>

<details>
<summary>📒 Files selected for processing (12)</summary>

* `internal-packages/workflow-designer-ui/src/header/ui/trigger-input-dialog.tsx` (4 hunks)
* `packages/data-mod/src/index.ts` (0 hunks)
* `packages/data-type/package.json` (1 hunks)
* `packages/data-type/src/generation/context.ts` (3 hunks)
* `packages/giselle-engine/src/core/flows/resolve-trigger.ts` (4 hunks)
* `packages/giselle-engine/src/core/flows/run-flow.ts` (2 hunks)
* `packages/giselle-engine/src/core/generations/get-generation.ts` (1 hunks)
* `packages/giselle-engine/src/core/github/event-handlers.ts` (1 hunks)
* `packages/giselle-engine/src/core/github/handle-webhook.ts` (0 hunks)
* `packages/giselle-engine/src/core/github/trigger-utils.ts` (2 hunks)
* `packages/giselle-engine/src/core/index.ts` (2 hunks)
* `packages/giselle-engine/src/http/router.ts` (2 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (2)</summary>

* packages/data-mod/src/index.ts
* packages/giselle-engine/src/core/github/handle-webhook.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (4)</summary>

<details>
<summary>packages/giselle-engine/src/core/flows/run-flow.ts (1)</summary><blockquote>

<details>
<summary>packages/data-type/src/generation/context.ts (2)</summary>

* `GenerationContextInput` (75-78)
* `GenerationContextInput` (79-79)

</details>

</blockquote></details>
<details>
<summary>internal-packages/workflow-designer-ui/src/header/ui/trigger-input-dialog.tsx (1)</summary><blockquote>

<details>
<summary>packages/data-type/src/generation/context.ts (2)</summary>

* `ParameterItem` (57-60)
* `ParameterItem` (61-61)

</details>

</blockquote></details>
<details>
<summary>packages/giselle-engine/src/core/flows/resolve-trigger.ts (1)</summary><blockquote>

<details>
<summary>packages/data-type/src/generation/context.ts (2)</summary>

* `GenerationContextInput` (75-78)
* `GenerationContextInput` (79-79)

</details>

</blockquote></details>
<details>
<summary>packages/data-type/src/generation/context.ts (4)</summary><blockquote>

<details>
<summary>packages/github-tool/src/webhooks.ts (1)</summary>

* `WebhookEvent` (14-17)

</details>
<details>
<summary>packages/data-type/src/node/operations/index.ts (2)</summary>

* `OperationNode` (27-30)
* `OperationNode` (31-31)

</details>
<details>
<summary>apps/studio.giselles.ai/packages/types.ts (1)</summary>

* `Connection` (124-132)

</details>
<details>
<summary>packages/data-type/src/node/index.ts (2)</summary>

* `Node` (16-16)
* `Node` (17-17)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: codeql / languages (javascript) / Perform CodeQL for javascript
* GitHub Check: check

</details>

<details>
<summary>🔇 Additional comments (19)</summary><blockquote>

<details>
<summary>packages/data-type/package.json (1)</summary>

`25-25`: **Appropriate dependency addition**

Adding the GitHub tool dependency is aligned with the refactoring of webhook event handling and supports the transition to strongly-typed inputs.

</details>
<details>
<summary>packages/giselle-engine/src/core/generations/get-generation.ts (1)</summary>

`12-14`: **Good cache bypass implementation**

Setting `bypassingCache: true` ensures fresh generation data is fetched every time, which is crucial for the new input processing system to work reliably with the latest data.

</details>
<details>
<summary>packages/giselle-engine/src/http/router.ts (2)</summary>

`7-7`: **Good type replacement**

Replacing `GenerationInput` with `GenerationContextInput` improves type safety in import declarations.

---

`305-306`: **Properly updated schema for enhanced type safety**

The input schema correctly uses the new `GenerationContextInput` type and removes the deprecated `payload` field, aligning with the refactoring goal of using strongly-typed parameters.

</details>
<details>
<summary>packages/giselle-engine/src/core/github/event-handlers.ts (1)</summary>

`268-274`: **Well-structured webhook event handling**

The refactored code properly passes GitHub webhook events as structured, typed inputs instead of raw payloads. This implementation:

1. Uses a discriminated union with the "github-webhook-event" type
2. Maintains the original event data
3. Follows the new pattern of using the standardized `triggerInputs` array

This change significantly improves type safety and makes the code more explicit about the kind of data being processed.

</details>
<details>
<summary>packages/giselle-engine/src/core/index.ts (2)</summary>

`7-7`: **Appropriate type import change for the new input model.**

The change from importing `GenerationInput` to `GenerationContextInput` aligns with the larger refactoring effort to replace generic payload handling with strongly-typed parameters.

---

`228-228`: **Function signature properly updated to use the new input type.**

The `runFlow` function signature now correctly uses the new `GenerationContextInput` type, removing the deprecated payload parameter in favor of the structured trigger inputs array.

</details>
<details>
<summary>packages/giselle-engine/src/core/flows/run-flow.ts (3)</summary>

`3-3`: **Updated import to use the new typed input model.**

Importing `GenerationContextInput` instead of `GenerationInput` correctly aligns with the type system changes defined in `packages/data-type/src/generation/context.ts`.

---

`20-20`: **Function parameter type correctly updated.**

The `triggerInputs` parameter type has been properly updated to use the new `GenerationContextInput` discriminated union, improving type safety and removing ambiguity in payload processing.

---

`58-61`: **Existing code properly handles the new input types.**

The existing code using `args.triggerInputs ?? []` is correctly compatible with the new input type system without requiring changes to the implementation logic, which is a good sign of backward compatibility in the refactoring approach.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/header/ui/trigger-input-dialog.tsx (4)</summary>

`3-3`: **Updated import to use the new parameter type.**

Importing `ParameterItem` instead of `GenerationInput` aligns with the type system refactoring to use strongly-typed parameters instead of generic inputs.

---

`272-302`: **Input handling refactored to use typed parameter items.**

The form data processing has been properly refactored to create strongly-typed `ParameterItem` objects based on the input type (text, multiline-text, or number) with appropriate type discrimination and value conversion.


The switch statement correctly handles each input type:
1. Text and multiline-text inputs create string parameters
2. Number inputs parse the string value to an integer
3. An exhaustive check ensures all input types are handled

This implementation significantly improves type safety compared to the previous generic approach.

---

`310-313`: **Inputs properly wrapped in the new structure.**

The parameter items are now correctly wrapped in a `parameters` input object when present, matching the new `ParametersInput` type from the context schema. The conditional ensures an empty array is used when no parameters are provided.

---

`335-335`: **Dependency array correctly updated.**

The dependency array in `useCallback` now includes `inputs`, ensuring the callback is properly regenerated when the inputs change. This prevents potential stale closure issues.

</details>
<details>
<summary>packages/data-type/src/generation/context.ts (5)</summary>

`1-1`: **Import changes support the new model.**

The imports have been appropriately updated to include WebhookEvent type and necessary Node types to support the new input model structure.



Also applies to: 4-4

---

`43-62`: **Well-structured parameter type definitions.**

The new discriminated union structure for parameter items is well-designed:

1. `StringParameterItem` and `NumberParameterItem` each have their own schema with appropriate value types
2. Both share a common structure with `name` and `type` fields for identification 
3. The `ParameterItem` union uses the `type` field as the discriminator, enabling type-safe operations

This approach provides much better type safety and clarity compared to the previous generic model.

---

`63-68`: **Well-designed parameters input container.**

The `ParametersInput` type properly wraps an array of parameter items with a discriminating `type` field, making it clear when inputs represent parameters versus other input types.

---

`75-79`: **Clean discriminated union for all input types.**

The `GenerationContextInput` discriminated union neatly combines all possible input types, providing a structured way to handle different input scenarios with proper type discrimination.

---

`87-87`: **Consistent type usage in context schemas.**

Both `GenerationContext` and `GenerationContextLike` schemas have been updated to use the new `GenerationContextInput` type for inputs, ensuring consistency throughout the type system.



Also applies to: 103-103

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T09:44:08Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR replaces generic payload and key-value input handling with a strongly-typed `GenerationContextInput` system, introducing structured webhook events and parameter items.

- Swapped out `GenerationInput`/`payload` for `GenerationContextInput` in router, engine API, and flow execution.
- Added `GitHubWebhookEventInput` and updated event-handlers to send typed webhook events.
- Refactored `resolveTrigger` and the UI dialog to consume typed parameters and webhook inputs.

### Reviewed Changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.

<details>
<summary>Show a summary per file</summary>

| File | Description |
| ---- | ----------- |
| packages/giselle-engine/src/http/router.ts | Updated router schema to use `GenerationContextInput` instead of generic payload |
| packages/giselle-engine/src/core/index.ts | Refactored engine API to accept typed `triggerInputs` |
| packages/giselle-engine/src/core/github/handle-webhook.ts | Removed legacy `payload` forwarding in GitHub webhook trigger |
| packages/giselle-engine/src/core/github/event-handlers.ts | Now passes a `github-webhook-event` input array to `runFlow` |
| packages/giselle-engine/src/core/generations/get-generation.ts | Enabled a `bypassingCache` option for generation retrieval |
| packages/giselle-engine/src/core/flows/run-flow.ts | Adapted `runFlow` to propagate `GenerationContextInput` into queued generations |
| packages/giselle-engine/src/core/flows/resolve-trigger.ts | Streamlined trigger resolution to use new typed inputs and helper util |
| packages/data-type/src/generation/context.ts | Introduced `ParameterItem`, `ParametersInput`, and `GitHubWebhookEventInput` schemas |
| packages/data-type/package.json | Added dependency on `@giselle-sdk/github-tool` |
| packages/data-mod/src/index.ts | Removed debug `console.log` in parsing logic |
| internal-packages/workflow-designer-ui/src/header/ui/trigger-input-dialog.tsx | Updated the UI to build and send typed parameter items |
</details>


<details>
<summary>Files not reviewed (1)</summary>

* **pnpm-lock.yaml**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (2)</summary>

**packages/giselle-engine/src/core/github/handle-webhook.ts:182**
* The GitHub webhook handler no longer passes the event into `triggerInputs`, so the flow won’t receive the webhook data. Consider adding a `github-webhook-event` input object (e.g. `{ type: 'github-webhook-event', webhookEvent: args.githubEvent }`) to `triggerInputs` here.
```
runFlow({
```
**packages/data-type/src/generation/context.ts:73**
* [nitpick] The alias `PayloadInput` is misleading and unused; rename it to `GitHubWebhookEventInput` (or remove it) to match the schema constant and improve clarity.
```
export type PayloadInput = z.infer<typeof GitHubWebhookEventInput>;
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T09:44:17Z
user: login: shige
body: Thank you! ♻️ 

Please check the refactoring comments (e.g. removing console.log)!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-24T03:36:33Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>♻️ Duplicate comments (1)</summary><blockquote>

<details>
<summary>packages/giselle-engine/src/core/github/trigger-utils.ts (1)</summary><blockquote>

`34-435`: **Verify console.log statements were properly removed.**

Past review comments indicated stray `console.log` debugging statements needed removal. The current code appears clean, confirming this issue has been resolved.

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>packages/giselle-engine/src/core/github/trigger-utils.ts (1)</summary><blockquote>

`34-76`: **Consider reducing code duplication across resolver functions.**

While the consistent pattern across all resolver functions is good for maintainability, there's significant structural duplication. Each function follows the same template: event validation, payload iteration, accessor matching, and GenerationOutput creation.

Consider extracting a generic resolver helper function to reduce duplication:

```typescript
function createGenericResolver<T extends WebhookEvent>(
  eventType: T['type'],
  triggerId: string,
  payloadHandler: (payload: string, webhookEvent: T, output: Output) => GenerationOutput | null
) {
  return (args: ResolveTriggerArgs): GenerationOutput | null => {
    if (
      !ensureWebhookEvent(args.webhookEvent, eventType) ||
      args.githubTrigger.event.id !== triggerId
    ) {
      return null;
    }

    for (const payload of args.githubTrigger.event.payloads.keyof().options) {
      if (args.output.accessor !== payload) {
        continue;
      }
      return payloadHandler(payload, args.webhookEvent as T, args.output);
    }
    return null;
  };
}
```

This would significantly reduce the ~400 lines of repetitive code while maintaining the same functionality and type safety.



Also applies to: 79-124, 127-190, 193-248, 251-306, 309-364, 367-435

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9b305b26a9a00f6474d2c103ace68c6ccbea3d55 and 3b45b7f4cdebd5eb30e0217e7ba9fc8740f9bf4d.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `packages/data-type/src/generation/context.ts` (3 hunks)
* `packages/giselle-engine/src/core/flows/resolve-trigger.ts` (3 hunks)
* `packages/giselle-engine/src/core/github/trigger-utils.ts` (2 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* packages/giselle-engine/src/core/flows/resolve-trigger.ts
* packages/data-type/src/generation/context.ts

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: codeql / languages (javascript) / Perform CodeQL for javascript
* GitHub Check: check

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>packages/giselle-engine/src/core/github/trigger-utils.ts (2)</summary>

`1-6`: **LGTM! Type system improvements enhance code safety.**

The import changes align well with the broader refactoring to use strongly-typed `GenerationContextInput` and `GenerationOutput` instead of generic payloads, improving type safety across the system.

---

`22-32`: **Clean sequential resolution pattern.**

The `resolveTrigger` function uses a clean OR chain approach to return the first matching trigger result, which is both readable and efficient since each resolver returns early for non-matching triggers.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T00:53:35Z
user: login: toyamarinyon
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T00:56:47Z
user: login: toyamarinyon
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T00:56:56Z
user: login: toyamarinyon
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T00:57:07Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T00:57:12Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T00:57:19Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T00:57:29Z

Review comments:
diff_hunk: @@ -39,19 +40,51 @@ export const GenerationOrigin = z.discriminatedUnion("type", [
 ]);
 export type GenerationOrigin = z.infer<typeof GenerationOrigin>;
 
-export const GenerationInput = z.object({
+export const StringParameterItem = z.object({
 	name: z.string(),
+	type: z.literal("string"),
 	value: z.string(),
 });
-export type GenerationInput = z.infer<typeof GenerationInput>;
+export type StringParameterItem = z.infer<typeof StringParameterItem>;
+
+export const NumberParameterItem = z.object({
+	name: z.string(),
+	type: z.literal("number"),
+	value: z.number(),
+});
+export type NumberParameterItem = z.infer<typeof NumberParameterItem>;
+
+export const ParameterItem = z.discriminatedUnion("type", [
+	StringParameterItem,
+	NumberParameterItem,
+]);
+export type ParameterItem = z.infer<typeof ParameterItem>;
+
+export const ParametersInput = z.object({
+	type: z.literal("parameters"),
+	items: z.array(ParameterItem),
+});
+export type ParametersInput = z.infer<typeof ParametersInput>;
+
+export const GitHubWebhookEventInput = z.object({
+	type: z.literal("github-webhook-event"),
+	webhookEvent: z.custom<WebhookEvent>(),
+});
+export type PayloadInput = z.infer<typeof GitHubWebhookEventInput>;
+
path: packages/data-type/src/generation/context.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Structured webhook event input type.**

The `GitHubWebhookEventInput` type provides a dedicated structure for webhook events, using `z.custom<WebhookEvent>()` to ensure proper typing. However, there's a naming mismatch in the inferred type.


The inferred type is named `PayloadInput` but should be `GitHubWebhookEventInput` to match the schema name. Apply this fix:

```diff
-export type PayloadInput = z.infer<typeof GitHubWebhookEventInput>;
+export type GitHubWebhookEventInput = z.infer<typeof GitHubWebhookEventInput>;
```


> Committable suggestion skipped: line range outside the PR's diff.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In packages/data-type/src/generation/context.ts around lines 69 to 74, the
inferred type is named PayloadInput but should be renamed to
GitHubWebhookEventInput to match the schema name. Change the type alias from
PayloadInput to GitHubWebhookEventInput by updating the export type statement
accordingly.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commits 9f6dcff to 3b45b7f
created_at: 2025-05-23T09:44:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -37,51 +35,54 @@ export async function resolveTrigger(args: {
 
 	const generationContext = GenerationContext.parse(args.generation.context);
 
-	let githubWebhookInputs: GenerationInput[] | null = null;
-	if (
-		args.githubWebhookEvent !== undefined &&
-		isWebhookEvent(args.githubWebhookEvent) &&
-		triggerData.configuration.provider === "github"
-	) {
-		githubWebhookInputs = buildTriggerInputs({
-			githubTrigger: githubTriggers[triggerData.configuration.event.id],
-			trigger: triggerData,
-			webhookEvent: args.githubWebhookEvent,
-		});
-	}
-
 	const outputs: GenerationOutput[] = [];
 	switch (triggerData.configuration.provider) {
 		case "github": {
-			const trigger = githubTriggers[triggerData.configuration.event.id];
-			const inputsToUse = githubWebhookInputs ?? generationContext.inputs ?? [];
-			for (const payload of trigger.event.payloads.keyof().options) {
-				const input = inputsToUse.find((i) => i.name === payload);
-				if (input === undefined) {
-					continue;
-				}
-				const output = operationNode.outputs.find(
-					(output) => output.accessor === payload,
-				);
-				if (output === undefined) {
-					continue;
-				}
-				outputs.push({
-					type: "generated-text",
-					outputId: output.id,
-					content: input.value,
+			const githubWebhookEventInput = generationContext.inputs?.find(
+				(input) => input.type === "github-webhook-event",
+			);
+			if (githubWebhookEventInput === undefined) {
+				throw new Error("Missing github-webhook-event input");
+			}
+			if (triggerData.configuration.provider !== "github") {
+				throw new Error("Invalid provider");
+			}
+			for (const output of operationNode.outputs) {
+				const resolveOutput = resolveGitHubTrigger({
+					output,
+					githubTrigger: githubTriggers[triggerData.configuration.event.id],
+					trigger: triggerData,
+					webhookEvent: githubWebhookEventInput.webhookEvent,
 				});
+				if (resolveOutput !== null) {
+					outputs.push(resolveOutput);
+				}
 			}
 			break;
 		}
-		case "manual": {
+		case "manual":
 			for (const parameter of triggerData.configuration.event.parameters) {
-				const input = generationContext.inputs?.find(
-					(input) => input.name === parameter.id,
+				let parameterValue: string | undefined;
+
+				// Find parameter in ParametersInput
+				const parametersInput = generationContext.inputs?.find(
+					(i): i is GenerationContextInput & { type: "parameters" } =>
+						i.type === "parameters",
 				);
-				if (input === undefined) {
+
+				if (parametersInput) {
+					const parameterItem = parametersInput.items.find(
+						(item) => item.name === parameter.id,
+					);
+					if (parameterItem) {
+						parameterValue = parameterItem.value.toString();
+					}
+				}
+
path: packages/giselle-engine/src/core/flows/resolve-trigger.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Avoid `Array.find` inside the loop – compute `parametersInput` once**

`generationContext.inputs?.find(...)` is executed for every parameter, resulting in O(N²) behaviour in the worst case.  Resolve the `parametersInput` once before the loop and reuse it.

```diff
-	for (const parameter of triggerData.configuration.event.parameters) {
-		let parameterValue: string | undefined;
-
-		// Find parameter in ParametersInput
-		const parametersInput = generationContext.inputs?.find(
-			(i): i is GenerationContextInput & { type: "parameters" } =>
-				i.type === "parameters",
-		);
+	const parametersInput = generationContext.inputs?.find(
+		(i): i is GenerationContextInput & { type: "parameters" } =>
+			i.type === "parameters",
+	);
+
+	for (const parameter of triggerData.configuration.event.parameters) {
+		let parameterValue: string | undefined;
```
This keeps the loop O(N) and improves readability.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
// Resolve the parametersInput once before iterating
const parametersInput = generationContext.inputs?.find(
	(i): i is GenerationContextInput & { type: "parameters" } =>
		i.type === "parameters",
);

for (const parameter of triggerData.configuration.event.parameters) {
	let parameterValue: string | undefined;

	if (parametersInput) {
		const parameterItem = parametersInput.items.find(
			(item) => item.name === parameter.id,
		);
		if (parameterItem) {
			parameterValue = parameterItem.value.toString();
		}
	}

	// ...rest of loop logic...
}
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In packages/giselle-engine/src/core/flows/resolve-trigger.ts around lines 64 to
81, the code calls generationContext.inputs?.find(...) inside the loop for each
parameter, causing inefficient O(N²) complexity. To fix this, move the
computation of parametersInput outside and before the loop, so it is done only
once, then reuse parametersInput inside the loop to find parameterItem and
assign parameterValue. This change will improve performance and readability by
reducing redundant lookups.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commits 9f6dcff to 3b45b7f
created_at: 2025-05-23T09:44:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,341 +13,426 @@ import {
 import { type GitHubEvent, GitHubEventType } from "./events";
 import { parseCommand } from "./utils";
 
-interface BuildTriggerInputsArgs {
+interface ResolveTriggerArgs {
+	output: Output;
 	githubTrigger: (typeof githubTriggers)[keyof typeof githubTriggers];
 	trigger: FlowTrigger;
 	webhookEvent: WebhookEvent;
 }
-export function buildTriggerInputs(
-	args: BuildTriggerInputsArgs,
-): GenerationInput[] | null {
-	const inputs: GenerationInput[] = [
-		...buildIssueCreatedInputs(args),
-		...buildIssueClosedInputs(args),
-		...buildIssueCommentInputs(args),
-		...buildPullRequestOpenedInputs(args),
-		...buildPullRequestReadyForReviewInputs(args),
-		...buildPullRequestClosedInputs(args),
-		...buildPullRequestCommentInputs(args),
-	];
-
-	return inputs.length > 0 ? inputs : null;
+export function resolveTrigger(args: ResolveTriggerArgs) {
+	return (
+		resolveIssueCreatedTrigger(args) ||
+		resolveIssueClosedTrigger(args) ||
+		resolveIssueCommentTrigger(args) ||
+		resolvePullRequestOpenedTrigger(args) ||
+		resolvePullRequestReadyForReviewTrigger(args) ||
+		resolvePullRequestClosedTrigger(args) ||
+		resolvePullRequestCommentTrigger(args)
+	);
 }
 
-function buildIssueCreatedInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueCreatedTrigger(args: ResolveTriggerArgs) {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issues.opened") ||
 		args.githubTrigger.event.id !== "github.issue.created"
 	) {
-		return [];
+		return null;
 	}
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildIssueClosedInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueClosedTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issues.closed") ||
 		args.githubTrigger.event.id !== "github.issue.closed"
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildIssueCommentInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueCommentTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issue_comment.created") ||
 		args.trigger.configuration.event.id !== "github.issue_comment.created" ||
 		args.githubTrigger.event.id !== "github.issue_comment.created"
 	) {
-		return [];
+		return null;
 	}
 
 	const command = parseCommand(args.webhookEvent.data.payload.comment.body);
 	if (
 		command === null ||
 		command.callsign !== args.trigger.configuration.event.conditions.callsign
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
+	console.log(args.githubTrigger.event.payloads.keyof().options);
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
+		console.log(payload);
 		switch (payload) {
path: packages/giselle-engine/src/core/github/trigger-utils.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Remove stray `console.log` debugging statements**

Left-over logging creates noisy output in production and can leak PII from payloads.

```diff
-	console.log(args.githubTrigger.event.payloads.keyof().options);
...
-		console.log(payload);
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
		switch (payload) {
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In packages/giselle-engine/src/core/github/trigger-utils.ts around lines 146 to
149, remove the stray console.log statements used for debugging to prevent noisy
output and potential leakage of sensitive information in production. Delete both
console.log lines before the for loop and inside it to clean up the code.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commits 9f6dcff to 3b45b7f
created_at: 2025-05-23T09:44:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -37,51 +35,54 @@ export async function resolveTrigger(args: {
 
 	const generationContext = GenerationContext.parse(args.generation.context);
 
-	let githubWebhookInputs: GenerationInput[] | null = null;
-	if (
-		args.githubWebhookEvent !== undefined &&
-		isWebhookEvent(args.githubWebhookEvent) &&
-		triggerData.configuration.provider === "github"
-	) {
-		githubWebhookInputs = buildTriggerInputs({
-			githubTrigger: githubTriggers[triggerData.configuration.event.id],
-			trigger: triggerData,
-			webhookEvent: args.githubWebhookEvent,
-		});
-	}
-
 	const outputs: GenerationOutput[] = [];
 	switch (triggerData.configuration.provider) {
 		case "github": {
-			const trigger = githubTriggers[triggerData.configuration.event.id];
-			const inputsToUse = githubWebhookInputs ?? generationContext.inputs ?? [];
-			for (const payload of trigger.event.payloads.keyof().options) {
-				const input = inputsToUse.find((i) => i.name === payload);
-				if (input === undefined) {
-					continue;
-				}
-				const output = operationNode.outputs.find(
-					(output) => output.accessor === payload,
-				);
-				if (output === undefined) {
-					continue;
-				}
-				outputs.push({
-					type: "generated-text",
-					outputId: output.id,
-					content: input.value,
+			const githubWebhookEventInput = generationContext.inputs?.find(
+				(input) => input.type === "github-webhook-event",
+			);
+			if (githubWebhookEventInput === undefined) {
+				throw new Error("Missing github-webhook-event input");
+			}
+			if (triggerData.configuration.provider !== "github") {
+				throw new Error("Invalid provider");
+			}
path: packages/giselle-engine/src/core/flows/resolve-trigger.ts
user: login: Copilot
body: [nitpick] This provider check is redundant inside the `case 'github'`: the switch already guarantees the provider is GitHub. Consider removing this branch for simpler control flow.
```suggestion

```
created_at: 2025-05-23T09:44:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -9,5 +9,8 @@ export async function getGeneration(args: {
 	return await getGenerationInternal({
 		storage: args.context.storage,
 		generationId: args.generationId,
+		options: {
+			bypassingCache: true,
path: packages/giselle-engine/src/core/generations/get-generation.ts
user: login: Copilot
body: The new `bypassingCache` option isn’t documented; consider adding a JSDoc comment or README entry explaining its intended effect on cache behavior.
created_at: 2025-05-23T09:44:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -37,51 +35,54 @@ export async function resolveTrigger(args: {
 
 	const generationContext = GenerationContext.parse(args.generation.context);
 
-	let githubWebhookInputs: GenerationInput[] | null = null;
-	if (
-		args.githubWebhookEvent !== undefined &&
-		isWebhookEvent(args.githubWebhookEvent) &&
-		triggerData.configuration.provider === "github"
-	) {
-		githubWebhookInputs = buildTriggerInputs({
-			githubTrigger: githubTriggers[triggerData.configuration.event.id],
-			trigger: triggerData,
-			webhookEvent: args.githubWebhookEvent,
-		});
-	}
-
 	const outputs: GenerationOutput[] = [];
 	switch (triggerData.configuration.provider) {
 		case "github": {
-			const trigger = githubTriggers[triggerData.configuration.event.id];
-			const inputsToUse = githubWebhookInputs ?? generationContext.inputs ?? [];
-			for (const payload of trigger.event.payloads.keyof().options) {
-				const input = inputsToUse.find((i) => i.name === payload);
-				if (input === undefined) {
-					continue;
-				}
-				const output = operationNode.outputs.find(
-					(output) => output.accessor === payload,
-				);
-				if (output === undefined) {
-					continue;
-				}
-				outputs.push({
-					type: "generated-text",
-					outputId: output.id,
-					content: input.value,
+			const githubWebhookEventInput = generationContext.inputs?.find(
+				(input) => input.type === "github-webhook-event",
+			);
+			if (githubWebhookEventInput === undefined) {
+				throw new Error("Missing github-webhook-event input");
+			}
+			if (triggerData.configuration.provider !== "github") {
+				throw new Error("Invalid provider");
+			}
+			for (const output of operationNode.outputs) {
+				const resolveOutput = resolveGitHubTrigger({
+					output,
+					githubTrigger: githubTriggers[triggerData.configuration.event.id],
+					trigger: triggerData,
+					webhookEvent: githubWebhookEventInput.webhookEvent,
 				});
+				if (resolveOutput !== null) {
+					outputs.push(resolveOutput);
+				}
 			}
 			break;
 		}
-		case "manual": {
+		case "manual":
 			for (const parameter of triggerData.configuration.event.parameters) {
-				const input = generationContext.inputs?.find(
-					(input) => input.name === parameter.id,
+				let parameterValue: string | undefined;
+
+				// Find parameter in ParametersInput
+				const parametersInput = generationContext.inputs?.find(
+					(i): i is GenerationContextInput & { type: "parameters" } =>
+						i.type === "parameters",
 				);
-				if (input === undefined) {
+
+				if (parametersInput) {
+					const parameterItem = parametersInput.items.find(
+						(item) => item.name === parameter.id,
+					);
+					if (parameterItem) {
+						parameterValue = parameterItem.value.toString();
+					}
+				}
+
path: packages/giselle-engine/src/core/flows/resolve-trigger.ts
user: login: toyamarinyon
body: i've fixed with 3b45b7f4cdebd5eb30e0217e7ba9fc8740f9bf4d
created_at: 2025-05-26T00:56:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -39,19 +40,51 @@ export const GenerationOrigin = z.discriminatedUnion("type", [
 ]);
 export type GenerationOrigin = z.infer<typeof GenerationOrigin>;
 
-export const GenerationInput = z.object({
+export const StringParameterItem = z.object({
 	name: z.string(),
+	type: z.literal("string"),
 	value: z.string(),
 });
-export type GenerationInput = z.infer<typeof GenerationInput>;
+export type StringParameterItem = z.infer<typeof StringParameterItem>;
+
+export const NumberParameterItem = z.object({
+	name: z.string(),
+	type: z.literal("number"),
+	value: z.number(),
+});
+export type NumberParameterItem = z.infer<typeof NumberParameterItem>;
+
+export const ParameterItem = z.discriminatedUnion("type", [
+	StringParameterItem,
+	NumberParameterItem,
+]);
+export type ParameterItem = z.infer<typeof ParameterItem>;
+
+export const ParametersInput = z.object({
+	type: z.literal("parameters"),
+	items: z.array(ParameterItem),
+});
+export type ParametersInput = z.infer<typeof ParametersInput>;
+
+export const GitHubWebhookEventInput = z.object({
+	type: z.literal("github-webhook-event"),
+	webhookEvent: z.custom<WebhookEvent>(),
+});
+export type PayloadInput = z.infer<typeof GitHubWebhookEventInput>;
+
path: packages/data-type/src/generation/context.ts
user: login: toyamarinyon
body: I've fixed with 09aa86c1b72e54a4323292dcd204b048bffd3b24
created_at: 2025-05-26T00:56:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,341 +13,426 @@ import {
 import { type GitHubEvent, GitHubEventType } from "./events";
 import { parseCommand } from "./utils";
 
-interface BuildTriggerInputsArgs {
+interface ResolveTriggerArgs {
+	output: Output;
 	githubTrigger: (typeof githubTriggers)[keyof typeof githubTriggers];
 	trigger: FlowTrigger;
 	webhookEvent: WebhookEvent;
 }
-export function buildTriggerInputs(
-	args: BuildTriggerInputsArgs,
-): GenerationInput[] | null {
-	const inputs: GenerationInput[] = [
-		...buildIssueCreatedInputs(args),
-		...buildIssueClosedInputs(args),
-		...buildIssueCommentInputs(args),
-		...buildPullRequestOpenedInputs(args),
-		...buildPullRequestReadyForReviewInputs(args),
-		...buildPullRequestClosedInputs(args),
-		...buildPullRequestCommentInputs(args),
-	];
-
-	return inputs.length > 0 ? inputs : null;
+export function resolveTrigger(args: ResolveTriggerArgs) {
+	return (
+		resolveIssueCreatedTrigger(args) ||
+		resolveIssueClosedTrigger(args) ||
+		resolveIssueCommentTrigger(args) ||
+		resolvePullRequestOpenedTrigger(args) ||
+		resolvePullRequestReadyForReviewTrigger(args) ||
+		resolvePullRequestClosedTrigger(args) ||
+		resolvePullRequestCommentTrigger(args)
+	);
 }
 
-function buildIssueCreatedInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueCreatedTrigger(args: ResolveTriggerArgs) {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issues.opened") ||
 		args.githubTrigger.event.id !== "github.issue.created"
 	) {
-		return [];
+		return null;
 	}
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildIssueClosedInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueClosedTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issues.closed") ||
 		args.githubTrigger.event.id !== "github.issue.closed"
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildIssueCommentInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueCommentTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issue_comment.created") ||
 		args.trigger.configuration.event.id !== "github.issue_comment.created" ||
 		args.githubTrigger.event.id !== "github.issue_comment.created"
 	) {
-		return [];
+		return null;
 	}
 
 	const command = parseCommand(args.webhookEvent.data.payload.comment.body);
 	if (
 		command === null ||
 		command.callsign !== args.trigger.configuration.event.conditions.callsign
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
+	console.log(args.githubTrigger.event.payloads.keyof().options);
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
+		console.log(payload);
 		switch (payload) {
path: packages/giselle-engine/src/core/github/trigger-utils.ts
user: login: toyamarinyon
body: I've fixed with 9f6dcffa05375ca23377754f895af4cad2c3eda6
created_at: 2025-05-26T00:57:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -37,51 +35,54 @@ export async function resolveTrigger(args: {
 
 	const generationContext = GenerationContext.parse(args.generation.context);
 
-	let githubWebhookInputs: GenerationInput[] | null = null;
-	if (
-		args.githubWebhookEvent !== undefined &&
-		isWebhookEvent(args.githubWebhookEvent) &&
-		triggerData.configuration.provider === "github"
-	) {
-		githubWebhookInputs = buildTriggerInputs({
-			githubTrigger: githubTriggers[triggerData.configuration.event.id],
-			trigger: triggerData,
-			webhookEvent: args.githubWebhookEvent,
-		});
-	}
-
 	const outputs: GenerationOutput[] = [];
 	switch (triggerData.configuration.provider) {
 		case "github": {
-			const trigger = githubTriggers[triggerData.configuration.event.id];
-			const inputsToUse = githubWebhookInputs ?? generationContext.inputs ?? [];
-			for (const payload of trigger.event.payloads.keyof().options) {
-				const input = inputsToUse.find((i) => i.name === payload);
-				if (input === undefined) {
-					continue;
-				}
-				const output = operationNode.outputs.find(
-					(output) => output.accessor === payload,
-				);
-				if (output === undefined) {
-					continue;
-				}
-				outputs.push({
-					type: "generated-text",
-					outputId: output.id,
-					content: input.value,
+			const githubWebhookEventInput = generationContext.inputs?.find(
+				(input) => input.type === "github-webhook-event",
+			);
+			if (githubWebhookEventInput === undefined) {
+				throw new Error("Missing github-webhook-event input");
+			}
+			if (triggerData.configuration.provider !== "github") {
+				throw new Error("Invalid provider");
+			}
+			for (const output of operationNode.outputs) {
+				const resolveOutput = resolveGitHubTrigger({
+					output,
+					githubTrigger: githubTriggers[triggerData.configuration.event.id],
+					trigger: triggerData,
+					webhookEvent: githubWebhookEventInput.webhookEvent,
 				});
+				if (resolveOutput !== null) {
+					outputs.push(resolveOutput);
+				}
 			}
 			break;
 		}
-		case "manual": {
+		case "manual":
 			for (const parameter of triggerData.configuration.event.parameters) {
-				const input = generationContext.inputs?.find(
-					(input) => input.name === parameter.id,
+				let parameterValue: string | undefined;
+
+				// Find parameter in ParametersInput
+				const parametersInput = generationContext.inputs?.find(
+					(i): i is GenerationContextInput & { type: "parameters" } =>
+						i.type === "parameters",
 				);
-				if (input === undefined) {
+
+				if (parametersInput) {
+					const parameterItem = parametersInput.items.find(
+						(item) => item.name === parameter.id,
+					);
+					if (parameterItem) {
+						parameterValue = parameterItem.value.toString();
+					}
+				}
+
path: packages/giselle-engine/src/core/flows/resolve-trigger.ts
user: login: coderabbitai[bot]
body: @toyamarinyon Perfect! Thank you for addressing the performance optimization. Moving the `parametersInput` computation outside the loop eliminates the redundant lookups and improves the algorithm from O(N²) to O(N) complexity. 🚀


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@toyamarinyon Perfect! Thank you for addressing the performance optimization. Moving the `parametersInput` computation outside the loop eliminates the redundant lookups and improves the algorithm from O(N²) to O(N) complexity. 🚀</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-26T00:57:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -39,19 +40,51 @@ export const GenerationOrigin = z.discriminatedUnion("type", [
 ]);
 export type GenerationOrigin = z.infer<typeof GenerationOrigin>;
 
-export const GenerationInput = z.object({
+export const StringParameterItem = z.object({
 	name: z.string(),
+	type: z.literal("string"),
 	value: z.string(),
 });
-export type GenerationInput = z.infer<typeof GenerationInput>;
+export type StringParameterItem = z.infer<typeof StringParameterItem>;
+
+export const NumberParameterItem = z.object({
+	name: z.string(),
+	type: z.literal("number"),
+	value: z.number(),
+});
+export type NumberParameterItem = z.infer<typeof NumberParameterItem>;
+
+export const ParameterItem = z.discriminatedUnion("type", [
+	StringParameterItem,
+	NumberParameterItem,
+]);
+export type ParameterItem = z.infer<typeof ParameterItem>;
+
+export const ParametersInput = z.object({
+	type: z.literal("parameters"),
+	items: z.array(ParameterItem),
+});
+export type ParametersInput = z.infer<typeof ParametersInput>;
+
+export const GitHubWebhookEventInput = z.object({
+	type: z.literal("github-webhook-event"),
+	webhookEvent: z.custom<WebhookEvent>(),
+});
+export type PayloadInput = z.infer<typeof GitHubWebhookEventInput>;
+
path: packages/data-type/src/generation/context.ts
user: login: coderabbitai[bot]
body: @toyamarinyon Perfect! Thank you for fixing the type naming mismatch. The commit ensures that the inferred type name properly matches the schema name, maintaining consistency in the codebase. The `GitHubWebhookEventInput` type is now correctly aligned throughout the type definitions. ✅


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@toyamarinyon Perfect! Thank you for fixing the type naming mismatch. The commit ensures that the inferred type name properly matches the schema name, maintaining consistency in the codebase. The `GitHubWebhookEventInput` type is now correctly aligned throughout the type definitions. ✅</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-26T00:57:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,341 +13,426 @@ import {
 import { type GitHubEvent, GitHubEventType } from "./events";
 import { parseCommand } from "./utils";
 
-interface BuildTriggerInputsArgs {
+interface ResolveTriggerArgs {
+	output: Output;
 	githubTrigger: (typeof githubTriggers)[keyof typeof githubTriggers];
 	trigger: FlowTrigger;
 	webhookEvent: WebhookEvent;
 }
-export function buildTriggerInputs(
-	args: BuildTriggerInputsArgs,
-): GenerationInput[] | null {
-	const inputs: GenerationInput[] = [
-		...buildIssueCreatedInputs(args),
-		...buildIssueClosedInputs(args),
-		...buildIssueCommentInputs(args),
-		...buildPullRequestOpenedInputs(args),
-		...buildPullRequestReadyForReviewInputs(args),
-		...buildPullRequestClosedInputs(args),
-		...buildPullRequestCommentInputs(args),
-	];
-
-	return inputs.length > 0 ? inputs : null;
+export function resolveTrigger(args: ResolveTriggerArgs) {
+	return (
+		resolveIssueCreatedTrigger(args) ||
+		resolveIssueClosedTrigger(args) ||
+		resolveIssueCommentTrigger(args) ||
+		resolvePullRequestOpenedTrigger(args) ||
+		resolvePullRequestReadyForReviewTrigger(args) ||
+		resolvePullRequestClosedTrigger(args) ||
+		resolvePullRequestCommentTrigger(args)
+	);
 }
 
-function buildIssueCreatedInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueCreatedTrigger(args: ResolveTriggerArgs) {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issues.opened") ||
 		args.githubTrigger.event.id !== "github.issue.created"
 	) {
-		return [];
+		return null;
 	}
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildIssueClosedInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueClosedTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issues.closed") ||
 		args.githubTrigger.event.id !== "github.issue.closed"
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
 		switch (payload) {
 			case "title":
-				inputs.push({
-					name: "title",
-					value: args.webhookEvent.data.payload.issue.title,
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.title,
+				} satisfies GenerationOutput;
 			case "body":
-				inputs.push({
-					name: "body",
-					value: args.webhookEvent.data.payload.issue.body ?? "",
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.body ?? "",
+				} satisfies GenerationOutput;
 			case "issueNumber":
-				inputs.push({
-					name: "issueNumber",
-					value: args.webhookEvent.data.payload.issue.number.toString(),
-				});
-				break;
+				if (args.output.accessor !== payload) {
+					continue;
+				}
+				return {
+					type: "generated-text",
+					outputId: args.output.id,
+					content: args.webhookEvent.data.payload.issue.number.toString(),
+				} satisfies GenerationOutput;
 			default: {
 				const _exhaustiveCheck: never = payload;
 				throw new Error(`Unhandled payload id: ${_exhaustiveCheck}`);
 			}
 		}
 	}
-	return inputs;
+	return null;
 }
 
-function buildIssueCommentInputs(args: BuildTriggerInputsArgs) {
+function resolveIssueCommentTrigger(
+	args: ResolveTriggerArgs,
+): GenerationOutput | null {
 	if (
 		!ensureWebhookEvent(args.webhookEvent, "issue_comment.created") ||
 		args.trigger.configuration.event.id !== "github.issue_comment.created" ||
 		args.githubTrigger.event.id !== "github.issue_comment.created"
 	) {
-		return [];
+		return null;
 	}
 
 	const command = parseCommand(args.webhookEvent.data.payload.comment.body);
 	if (
 		command === null ||
 		command.callsign !== args.trigger.configuration.event.conditions.callsign
 	) {
-		return [];
+		return null;
 	}
 
-	const inputs: GenerationInput[] = [];
+	console.log(args.githubTrigger.event.payloads.keyof().options);
 	for (const payload of args.githubTrigger.event.payloads.keyof().options) {
+		console.log(payload);
 		switch (payload) {
path: packages/giselle-engine/src/core/github/trigger-utils.ts
user: login: coderabbitai[bot]
body: @toyamarinyon Perfect! Thank you for promptly removing those debugging statements. Clean code without stray console.log statements helps maintain production quality and prevents potential information leakage. 🐰

🐰
     /|   /|  
    (  ._. )
     o_(")(")


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@toyamarinyon Perfect! Thank you for promptly removing those debugging statements. Clean code without stray console.log statements helps maintain production quality and prevents potential information leakage. 🐰

🐰
     /|   /|  
    (  ._. )
     o_(")(")</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-26T00:57:29Z
author_association: CONTRIBUTOR

PR comments:
user: login: vercel[bot]
created_at: 2025-05-22T07:12:24Z
body: [vc]: #sZBYVzOyUGYd8OaGL6hzpYtEuRu35pOPJ7OvrBQ7SRA=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJnaXNlbGxlLXBsYXlncm91bmQiLCJyb290RGlyZWN0b3J5IjoiYXBwcy9wbGF5Z3JvdW5kIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3IwNi1lZGdlL2dpc2VsbGUtcGxheWdyb3VuZC80RHFNOUtqanE4VXoyZ0hEaEFmSDkyZGg3cnlWIiwicHJldmlld1VybCI6Imdpc2VsbGUtcGxheWdyb3VuZC1naXQtY29kZXgtZXh0ZW5kLWdlbmVyYXRpb25pLTQ1YTljMC1yMDYtZWRnZS52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6Imdpc2VsbGUtcGxheWdyb3VuZC1naXQtY29kZXgtZXh0ZW5kLWdlbmVyYXRpb25pLTQ1YTljMC1yMDYtZWRnZS52ZXJjZWwuYXBwIn19LHsibmFtZSI6Imdpc2VsbGUiLCJyb290RGlyZWN0b3J5IjoiYXBwcy9zdHVkaW8uZ2lzZWxsZXMuYWkiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vcjA2LWVkZ2UvZ2lzZWxsZS84RXpUY0s5NVhNVDhwUmh2TUJudlFUbUI4TUZEIiwicHJldmlld1VybCI6Imdpc2VsbGUtZ2l0LWNvZGV4LWV4dGVuZC1nZW5lcmF0aW9uaW5wdXQtdG8tc3VwLTgxOTVhOS1yMDYtZWRnZS52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6Imdpc2VsbGUtZ2l0LWNvZGV4LWV4dGVuZC1nZW5lcmF0aW9uaW5wdXQtdG8tc3VwLTgxOTVhOS1yMDYtZWRnZS52ZXJjZWwuYXBwIn19XX0=
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **giselle** | ✅ Ready ([Inspect](https://vercel.com/r06-edge/giselle/8EzTcK95XMT8pRhvMBnvQTmB8MFD)) | [Visit Preview](https://giselle-git-codex-extend-generationinput-to-sup-8195a9-r06-edge.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/giselle-git-codex-extend-generationinput-to-sup-8195a9-r06-edge.vercel.app?via=pr-comment-feedback-link) | May 26, 2025 0:55am |
| **giselle-playground** | ✅ Ready ([Inspect](https://vercel.com/r06-edge/giselle-playground/4DqM9Kjjq8Uz2gHDhAfH92dh7ryV)) | [Visit Preview](https://giselle-playground-git-codex-extend-generationi-45a9c0-r06-edge.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/giselle-playground-git-codex-extend-generationi-45a9c0-r06-edge.vercel.app?via=pr-comment-feedback-link) | May 26, 2025 0:55am |



author_association: NONE
user: login: changeset-bot[bot]
created_at: 2025-05-22T07:12:25Z
body: ###  ⚠️  No Changeset found

Latest commit: 3b45b7f4cdebd5eb30e0217e7ba9fc8740f9bf4d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**



[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/giselles-ai/giselle/new/codex/extend-generationinput-to-support-payload-and-event?filename=.changeset/young-spiders-relax.md&value=---%0A%22%40fake-scope%2Ffake-pkg%22%3A%20patch%0A---%0A%0ARefactor%20trigger%20input%20processing%20to%20use%20typed%20parameters%20and%20webhook%20events%0A)

<details><summary>💥 An error occurred when fetching the changed packages and changesets in this PR</summary>

```
Some errors occurred when validating the changesets config:
The package "playground" depends on the ignored package "giselle-sdk", but "playground" is not being ignored. Please add "playground" to the `ignore` option.
The package "studio.giselles.ai" depends on the ignored package "giselle-sdk", but "studio.giselles.ai" is not being ignored. Please add "studio.giselles.ai" to the `ignore` option.
The package "@giselle-internal/workflow-designer-ui" depends on the ignored package "giselle-sdk", but "@giselle-internal/workflow-designer-ui" is not being ignored. Please add "@giselle-internal/workflow-designer-ui" to the `ignore` option.
```

</details>

author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-05-22T07:12:28Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This change refactors trigger input handling across the workflow designer UI, core engine, and supporting packages. It introduces a structured, discriminated union schema for generation context inputs, centralizes GitHub webhook event extraction, unifies manual parameter handling, and updates function signatures and API schemas to use the new input model.

## Changes

| File(s)                                                                                              | Change Summary |
|----------------------------------------------------------------------------------------------------|----------------|
| internal-packages/workflow-designer-ui/src/header/ui/trigger-input-dialog.tsx                      | Refactored form data collection to use explicit `ParameterItem` objects based on input type; removed old input handling logic and unused variables. |
| packages/data-mod/src/index.ts                                                                     | Removed a debugging log statement for parse errors; no logic changes. |
| packages/data-type/package.json                                                                    | Added `@giselle-sdk/github-tool` as a new dev dependency. |
| packages/data-type/src/generation/context.ts                                                      | Replaced `GenerationInput` with a discriminated union: added `ParameterItem`, `ParametersInput`, `GitHubWebhookEventInput`, and updated all related schemas and types. |
| packages/giselle-engine/src/core/flows/resolve-trigger.ts                                          | Refactored to extract GitHub webhook events from `generationContext.inputs`, removed `githubWebhookEvent` parameter, unified manual parameter extraction, delegated GitHub trigger resolution to a helper function. |
| packages/giselle-engine/src/core/flows/run-flow.ts                                                 | Updated to use `GenerationContextInput[]` for `triggerInputs`, removed `payload` from arguments and internal calls. |
| packages/giselle-engine/src/core/generations/get-generation.ts                                     | Modified to always call `getGenerationInternal` with `{ bypassingCache: true }`. |
| packages/giselle-engine/src/core/github/event-handlers.ts                                          | Changed `runFlow` call to use a `triggerInputs` array with a `github-webhook-event` input instead of a direct `payload`. |
| packages/giselle-engine/src/core/github/handle-webhook.ts                                          | Removed `payload` from `runFlow` call in `runRepositoryTrigger`. |
| packages/giselle-engine/src/core/github/trigger-utils.ts                                           | Refactored trigger input resolution: replaced input array builders with single-output resolvers, updated function signatures and naming, centralized output logic. |
| packages/giselle-engine/src/core/index.ts                                                          | Updated `runFlow` signature to use `GenerationContextInput[]` and removed `payload` from arguments. |
| packages/giselle-engine/src/http/router.ts                                                         | Updated API schema for `runFlow` to use `GenerationContextInput[]` for `triggerInputs`, removed `payload` from schema and handler. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant UI as TriggerInputDialog
    participant Engine as GiselleEngine
    participant Flow as runFlow
    participant Trigger as resolveTrigger
    participant GitHub as resolveGitHubTrigger

    UI->>Engine: Submit form (inputs as ParameterItem[])
    Engine->>Flow: runFlow({ triggerInputs: [ParametersInput or GitHubWebhookEventInput] })
    Flow->>Trigger: resolveTrigger({ context, generation })
    alt GitHub Webhook Event
        Trigger->>GitHub: resolveGitHubTrigger(output, trigger, data, webhookEvent)
        GitHub-->>Trigger: GenerationOutput | null
    else Manual Trigger
        Trigger-->>Flow: Extract parameters from ParametersInput
    end
    Flow-->>Engine: Flow result
```

## Possibly related PRs

- **giselles-ai/giselle#942**: Adds a new function specifically for GitHub pull request comment triggers returning `GenerationInput` arrays; related as both modify how trigger inputs are represented and processed in GitHub trigger utilities.  
- **giselles-ai/giselle#938**: Adds a numeric `issueNumber` input field for GitHub issue triggers in the `TriggerInputDialog` and related schemas; related as both modify input handling in the dialog component but with different scopes.  
- **giselles-ai/giselle#921**: Introduces a strongly typed `githubWebhookEvent` parameter and modular GitHub webhook event handling in `resolveTrigger`; closely related as both refactor trigger input handling and event extraction.

## Suggested reviewers

- shige

## Poem

> In the warren of code, a new path we tread,  
> With triggers and inputs, all neatly rethread.  
> Webhooks and numbers, strings in a row—  
> Now rabbits can hop where clean data flows!  
> 🐇✨  
> Structured and tidy, our triggers delight,  
> Hopping through schemas, all day and all night.

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=giselles-ai/giselle&utm_content=919):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: toyamarinyon
created_at: 2025-05-23T10:20:16Z
body: I'll fix the test failed
author_association: CONTRIBUTOR
user: login: toyamarinyon
created_at: 2025-05-26T00:55:48Z
body: 📝 Since we are changing the structure of Generation, we will merge after the merge of https://github.com/giselles-ai/giselle/pull/947.
author_association: CONTRIBUTOR