Repository: giselles-ai/giselle
Pull request #958: Show the Web Page in the toolbar (with feature flag)
Author: login: shige
Created: 2025-05-26T08:55:20Z | Merged: 2025-05-27T04:36:26Z

## Summary
Show the Web Page in the toolbar (with feature flag)

<img width="375" alt="image" src="https://github.com/user-attachments/assets/6f9cf8e6-0b22-46bf-abbd-553a4f170ae2" />

## Related Issue
https://github.com/giselles-ai/giselle/issues/957

## Changes
- Add webPageFileNodeFlag
- Append "webPage" to FileCategory data-type
- Add WebPageFileIcon
- Show the Web Page in the toolbar (with feature flag)

## Testing
1. Enable webPageFileNodeFlag
2. View in the app workspaces
3. Show the toolbar


## Other Information
This pr is only complete up to the point where the web page node icon appears in the toolbar.
I will create the rest of the implementation in a separate PR.

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

## Summary by CodeRabbit

- **New Features**
  - Added a feature flag to enable support for "Web Page" as a file type.
  - Integrated "Web Page" option into file node category selection in the toolbar.
  - Introduced a new icon representing web page files.
  - Rendered a dedicated icon for "Web Page" in file and node icon components.
  - Extended file content handling to recognize "webPage" category.
- **Enhancements**
  - Expanded file category options to include "Web Page" for better file organization and selection.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/apps/playground/app/workspaces/[workspaceId]/layout.tsx b/apps/playground/app/workspaces/[workspaceId]/layout.tsx
index 806ab56b89..f3f1d68965 100644
--- a/apps/playground/app/workspaces/[workspaceId]/layout.tsx
+++ b/apps/playground/app/workspaces/[workspaceId]/layout.tsx
@@ -16,6 +16,7 @@ export default async function Layout({
 			featureFlag={{
 				flowNode: true,
 				runV2: true,
+				webPageFileNode: true,
 			}}
 		>
 			{children}
diff --git a/apps/studio.giselles.ai/app/workspaces/[workspaceId]/layout.tsx b/apps/studio.giselles.ai/app/workspaces/[workspaceId]/layout.tsx
index 5518c7db61..2922c602aa 100644
--- a/apps/studio.giselles.ai/app/workspaces/[workspaceId]/layout.tsx
+++ b/apps/studio.giselles.ai/app/workspaces/[workspaceId]/layout.tsx
@@ -1,5 +1,5 @@
 import { db } from "@/drizzle";
-import { flowNodeFlag, runV2Flag } from "@/flags";
+import { flowNodeFlag, runV2Flag, webPageFileNodeFlag } from "@/flags";
 import { getGitHubIntegrationState } from "@/packages/lib/github";
 import { getUsageLimitsForTeam } from "@/packages/lib/usage-limits";
 import { fetchCurrentUser } from "@/services/accounts";
@@ -35,7 +35,7 @@ export default async function Layout({
 	const usageLimits = await getUsageLimitsForTeam(currentTeam);
 	const flowNode = await flowNodeFlag();
 	const runV2 = await runV2Flag();
-
+	const webPageFileNode = await webPageFileNodeFlag();
 	return (
 		<WorkspaceProvider
 			workspaceId={workspaceId}
@@ -60,6 +60,7 @@ export default async function Layout({
 			featureFlag={{
 				flowNode,
 				runV2,
+				webPageFileNode,
 			}}
 		>
 			{children}
diff --git a/apps/studio.giselles.ai/flags.ts b/apps/studio.giselles.ai/flags.ts
index b74f389141..7728286824 100644
--- a/apps/studio.giselles.ai/flags.ts
+++ b/apps/studio.giselles.ai/flags.ts
@@ -116,3 +116,16 @@ export const githubVectorStoreFlag = flag<boolean>({
 		{ value: true, label: "Enable" },
 	],
 });
+
+export const webPageFileNodeFlag = flag<boolean>({
+	key: "web-page-file-node",
+	async decide() {
+		return takeLocalEnv("WEB_PAGE_FILE_NODE_FLAG");
+	},
+	description: "Enable Web Page File Node",
+	defaultValue: false,
+	options: [
+		{ value: false, label: "disable" },
+		{ value: true, label: "Enable" },
+	],
+});
diff --git a/internal-packages/workflow-designer-ui/src/editor/properties-panel/file-node-properties-panel/index.tsx b/internal-packages/workflow-designer-ui/src/editor/properties-panel/file-node-properties-panel/index.tsx
index 27883918f5..19613bc827 100644
--- a/internal-packages/workflow-designer-ui/src/editor/properties-panel/file-node-properties-panel/index.tsx
+++ b/internal-packages/workflow-designer-ui/src/editor/properties-panel/file-node-properties-panel/index.tsx
@@ -22,6 +22,10 @@ const fileType: Record<FileCategory, FileTypeConfig> = {
 		label: "Image",
 		maxSize: 1024 * 1024,
 	},
+	webPage: {
+		accept: ["text/html", "text/markdown"],
+		label: "Web Page",
+	},
 };
 
 export function FileNodePropertiesPanel({ node }: { node: FileNode }) {
diff --git a/internal-packages/workflow-designer-ui/src/editor/tool/toolbar/components/icons.tsx b/internal-packages/workflow-designer-ui/src/editor/tool/toolbar/components/icons.tsx
index ccae6a1f11..73e43b051b 100644
--- a/internal-packages/workflow-designer-ui/src/editor/tool/toolbar/components/icons.tsx
+++ b/internal-packages/workflow-designer-ui/src/editor/tool/toolbar/components/icons.tsx
@@ -19,5 +19,6 @@ export {
 	UploadIcon,
 	VideoIcon,
 	WilliIcon,
+	WebPageFileIcon,
 } from "../../../../icons";
 export { ImageGenerationNodeIcon } from "../../../../icons/node";
diff --git a/internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx b/internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
index f40eb41f2e..55452c4cdc 100644
--- a/internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
+++ b/internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
@@ -52,6 +52,7 @@ import {
 	TriggerIcon,
 	UploadIcon,
 	VideoIcon,
+	WebPageFileIcon,
 	WilliIcon,
 } from "./components";
 import {
@@ -83,7 +84,7 @@ export function Toolbar() {
 	const [selectedCategory, setSelectedCategory] = useState<string>("All");
 	const { llmProviders } = useWorkflowDesigner();
 	const limits = useUsageLimits();
-	const { flowNode } = useFeatureFlag();
+	const { flowNode, webPageFileNode } = useFeatureFlag();
 	const languageModelAvailable = (languageModel: LanguageModel) => {
 		if (limits === undefined) {
 			return true;
@@ -930,6 +931,12 @@ export function Toolbar() {
 													<TextFileIcon className="w-[20px] h-[20px]" />
 													<p className="text-[14px]">Text</p>
 												</ToggleGroup.Item>
+												{webPageFileNode && (
+													<ToggleGroup.Item value="webPage" data-tool>
+														<WebPageFileIcon className="w-[20px] h-[20px]" />
+														<p className="text-[14px]">Web Page</p>
+													</ToggleGroup.Item>
+												)}
 												{/* <ToggleGroup.Item value="addGitHubNode" data-tool>
 													<GitHubIcon className="w-[20px] h-[20px]" />
 													<p className="text-[14px]">GitHub</p>
diff --git a/internal-packages/workflow-designer-ui/src/icons/content-type-icon.tsx b/internal-packages/workflow-designer-ui/src/icons/content-type-icon.tsx
index 4a553a1c1e..4a2bc057ac 100644
--- a/internal-packages/workflow-designer-ui/src/icons/content-type-icon.tsx
+++ b/internal-packages/workflow-designer-ui/src/icons/content-type-icon.tsx
@@ -18,6 +18,7 @@ import { PictureIcon } from "./picture";
 import { RecraftIcon } from "./recraft";
 import { StableDiffusionIcon } from "./stable-diffusion";
 import { TextFileIcon } from "./text-file";
+import { WebPageFileIcon } from "./web-page-file";
 
 interface TextNodeIconProps extends SVGProps<SVGSVGElement> {
 	contentType: "text";
@@ -109,6 +110,8 @@ export function ContentTypeIcon({
 					return <TextFileIcon {...props} />;
 				case "image":
 					return <PictureIcon {...props} />;
+				case "webPage":
+					return <WebPageFileIcon {...props} />;
 				default: {
 					const _exhaustiveCheck: never = fileCategory;
 					throw new Error(`Unhandled FileCategory: ${_exhaustiveCheck}`);
diff --git a/internal-packages/workflow-designer-ui/src/icons/index.ts b/internal-packages/workflow-designer-ui/src/icons/index.ts
index a77f164107..909a38e7f2 100644
--- a/internal-packages/workflow-designer-ui/src/icons/index.ts
+++ b/internal-packages/workflow-designer-ui/src/icons/index.ts
@@ -44,3 +44,4 @@ export { AudioIcon } from "./audio";
 export { VideoIcon } from "./video";
 export { GenerateImageIcon } from "./generate-image";
 export * from "./trigger";
+export * from "./web-page-file";
diff --git a/internal-packages/workflow-designer-ui/src/icons/node/file-node.tsx b/internal-packages/workflow-designer-ui/src/icons/node/file-node.tsx
index ef14a6cbaf..1cf347a001 100644
--- a/internal-packages/workflow-designer-ui/src/icons/node/file-node.tsx
+++ b/internal-packages/workflow-designer-ui/src/icons/node/file-node.tsx
@@ -3,6 +3,7 @@ import type { SVGProps } from "react";
 import { PdfFileIcon } from "../pdf-file";
 import { PictureIcon } from "../picture";
 import { TextFileIcon } from "../text-file";
+import { WebPageFileIcon } from "../web-page-file";
 
 export function FileNodeIcon({
 	node,
@@ -17,6 +18,8 @@ export function FileNodeIcon({
 			return <TextFileIcon {...props} />;
 		case "image":
 			return <PictureIcon {...props} />;
+		case "webPage":
+			return <WebPageFileIcon {...props} />;
 		default: {
 			const _exhaustiveCheck: never = node.content.category;
 			throw new Error(`Unhandled node type: ${_exhaustiveCheck}`);
diff --git a/internal-packages/workflow-designer-ui/src/icons/node/index.tsx b/internal-packages/workflow-designer-ui/src/icons/node/index.tsx
index 6d0aa02964..b635c5b1a2 100644
--- a/internal-packages/workflow-designer-ui/src/icons/node/index.tsx
+++ b/internal-packages/workflow-designer-ui/src/icons/node/index.tsx
@@ -15,6 +15,7 @@ import { RecraftIcon } from "../recraft";
 import { StableDiffusionIcon } from "../stable-diffusion";
 import { TextFileIcon } from "../text-file";
 import { TriggerIcon } from "../trigger";
+import { WebPageFileIcon } from "../web-page-file";
 export * from "./file-node";
 export * from "./image-generation-node";
 export * from "./text-generation-node";
@@ -123,6 +124,8 @@ export function NodeIcon({
 							return <TextFileIcon {...props} data-content-type-icon />;
 						case "image":
 							return <PictureIcon {...props} data-content-type-icon />;
+						case "webPage":
+							return <WebPageFileIcon {...props} data-content-type-icon />;
 						default: {
 							const _exhaustiveCheck: never = node.content.category;
 							throw new Error(`Unhandled node type: ${_exhaustiveCheck}`);
diff --git a/internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx b/internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx
new file mode 100644
index 0000000000..6aaf09e4a1
--- /dev/null
+++ b/internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx
@@ -0,0 +1,23 @@
+import type { FC, SVGProps } from "react";
+
+export const WebPageFileIcon: FC<SVGProps<SVGSVGElement>> = (props) => (
+	<svg
+		xmlns="http://www.w3.org/2000/svg"
+		width="24"
+		height="24"
+		viewBox="0 0 24 24"
+		fill="none"
+		stroke="currentColor"
+		strokeWidth="2"
+		strokeLinecap="round"
+		strokeLinejoin="round"
+		className="lucide lucide-panels-top-left-icon lucide-panels-top-left"
+		role="img"
+		aria-label="Web Page File"
+		{...props}
+	>
+		<rect width="18" height="18" x="3" y="3" rx="2" />
+		<path d="M3 9h18" />
+		<path d="M9 21V9" />
+	</svg>
+);
diff --git a/packages/data-type/src/node/variables/file.ts b/packages/data-type/src/node/variables/file.ts
index 094b621a30..215209ea11 100644
--- a/packages/data-type/src/node/variables/file.ts
+++ b/packages/data-type/src/node/variables/file.ts
@@ -76,7 +76,7 @@ export const FileData = z.union([
 ]);
 export type FileData = z.infer<typeof FileData>;
 
-export const FileCategory = z.enum(["pdf", "text", "image"]);
+export const FileCategory = z.enum(["pdf", "text", "image", "webPage"]);
 export type FileCategory = z.infer<typeof FileCategory>;
 export const FileContent = z.object({
 	type: z.literal("file"),
diff --git a/packages/giselle-engine/src/core/generations/utils.ts b/packages/giselle-engine/src/core/generations/utils.ts
index 307fe117d9..17907415a6 100644
--- a/packages/giselle-engine/src/core/generations/utils.ts
+++ b/packages/giselle-engine/src/core/generations/utils.ts
@@ -163,7 +163,8 @@ async function buildGenerationMessageForTextGeneration(
 						break;
 					}
 					case "image":
-					case "pdf": {
+					case "pdf":
+					case "webPage": {
 						const fileContents = await getFileContents(
 							contextNode.content,
 							fileResolver,
@@ -477,6 +478,7 @@ async function getFileContents(
 			switch (fileContent.category) {
 				case "pdf":
 				case "text":
+				case "webPage":
 					return {
 						type: "file",
 						data,
@@ -589,7 +591,8 @@ async function buildGenerationMessageForImageGeneration(
 				switch (contextNode.content.category) {
 					case "text":
 					case "image":
-					case "pdf": {
+					case "pdf":
+					case "webPage": {
 						const fileContents = await getFileContents(
 							contextNode.content,
 							fileResolver,
diff --git a/packages/workspace/src/react/feature-flag.ts b/packages/workspace/src/react/feature-flag.ts
index ed8a2e6fb4..68510d63dc 100644
--- a/packages/workspace/src/react/feature-flag.ts
+++ b/packages/workspace/src/react/feature-flag.ts
@@ -3,6 +3,7 @@ import { createContext, useContext } from "react";
 export interface FeatureFlagContextValue {
 	flowNode: boolean;
 	runV2: boolean;
+	webPageFileNode: boolean;
 }
 export const FeatureFlagContext = createContext<
 	FeatureFlagContextValue | undefined
diff --git a/packages/workspace/src/react/workspace.tsx b/packages/workspace/src/react/workspace.tsx
index 1eed921e87..2592135ba2 100644
--- a/packages/workspace/src/react/workspace.tsx
+++ b/packages/workspace/src/react/workspace.tsx
@@ -62,6 +62,7 @@ export function WorkspaceProvider({
 									value={{
 										flowNode: featureFlag?.flowNode ?? false,
 										runV2: featureFlag?.runV2 ?? false,
+										webPageFileNode: featureFlag?.webPageFileNode ?? false,
 									}}
 								>
 									{children}


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T08:56:45Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

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

<details>
<summary>internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx (1)</summary><blockquote>

`3-23`: **Consider simplifying className and verifying icon design clarity.**

The component is well-structured, but there are a couple of suggestions:

1. The className appears verbose with potential redundancy: `"lucide lucide-panels-top-left-icon lucide-panels-top-left"`
2. The icon design (panels/layout) might not immediately convey "web page" to users



Consider this diff to simplify the className:

```diff
-		className="lucide lucide-panels-top-left-icon lucide-panels-top-left"
+		className="lucide lucide-panels-top-left"
```

Additionally, consider if the current icon design effectively represents a "web page" or if a more web-specific icon (like a browser window or document with URL) would be clearer for users.

</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 68083935c00438ad1d1a409bf0f8dbd506f4bc2a and d12b771cf02fb6a8971c0fa271d6800e767d43e5.

</details>

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

* `apps/playground/app/workspaces/[workspaceId]/layout.tsx` (1 hunks)
* `apps/studio.giselles.ai/app/workspaces/[workspaceId]/layout.tsx` (3 hunks)
* `apps/studio.giselles.ai/flags.ts` (1 hunks)
* `internal-packages/workflow-designer-ui/src/editor/tool/toolbar/components/icons.tsx` (1 hunks)
* `internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx` (3 hunks)
* `internal-packages/workflow-designer-ui/src/icons/index.ts` (1 hunks)
* `internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx` (1 hunks)
* `packages/data-type/src/node/variables/file.ts` (1 hunks)
* `packages/workspace/src/react/feature-flag.ts` (1 hunks)
* `packages/workspace/src/react/workspace.tsx` (1 hunks)

</details>

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

<details>
<summary>packages/workspace/src/react/feature-flag.ts (1)</summary>

`6-6`: **LGTM! Feature flag property added correctly.**

The addition of `webPageFileNode` follows the established pattern and maintains consistency with existing feature flags in the interface.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/icons/index.ts (1)</summary>

`47-47`: **LGTM! Export added correctly.**

The export statement follows the established pattern and properly exposes the web-page-file module.

</details>
<details>
<summary>apps/studio.giselles.ai/app/workspaces/[workspaceId]/layout.tsx (3)</summary>

`2-2`: **LGTM! Import added consistently.**

The `webPageFileNodeFlag` import follows the established pattern and maintains consistency with other feature flag imports.

---

`38-38`: **LGTM! Feature flag fetching implemented correctly.**

The async fetching of the `webPageFileNode` flag follows the same pattern as other feature flags in the component.

---

`63-63`: **LGTM! Feature flag properly passed to provider.**

The `webPageFileNode` property is correctly added to the `featureFlag` object, maintaining consistency with the existing implementation pattern.

</details>
<details>
<summary>packages/workspace/src/react/workspace.tsx (1)</summary>

`65-65`: **LGTM! Feature flag properly integrated into context.**

The `webPageFileNode` property is correctly added to the context value with appropriate default handling, following the established pattern of other feature flags.

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

`120-131`: **LGTM! Clean feature flag implementation.**

The new `webPageFileNodeFlag` follows the established pattern perfectly, with consistent naming conventions, proper environment variable handling, and appropriate default configuration.

</details>
<details>
<summary>packages/data-type/src/node/variables/file.ts (1)</summary>

`79-79`: **LGTM! Clean enum extension.**

The addition of "webPage" to the FileCategory enum is backward-compatible and follows the existing naming convention.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx (1)</summary>

`1-2`: **LGTM! Proper imports and typing.**

The component uses appropriate TypeScript types and React imports.

</details>
<details>
<summary>apps/playground/app/workspaces/[workspaceId]/layout.tsx (1)</summary>

`19-19`: **LGTM! Appropriate for playground environment.**

Adding the hardcoded `webPageFileNode: true` flag is suitable for the playground environment, allowing easy testing of the new feature. The difference from the studio app's async flag fetching is appropriate given the playground context.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/editor/tool/toolbar/components/icons.tsx (1)</summary>

`22-23`: **Confirm upstream availability of `WebPageFileIcon` before exporting**

`WebPageFileIcon` is added to the re-export list, which is great, but please double-check that:

1. `internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx` really exists and exports `WebPageFileIcon` as a **named** export.
2. `../../../../icons/index.ts` (the barrel file behind this relative path) also re-exports it.  

Missing either of these will cause a run-time “undefined export” error once someone tries to render the icon.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx (1)</summary>

`55-56`: **Import looks good**  

The icon is correctly imported from the components barrel file and will tree-shake like the others.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T09:00:47Z
user: login: shige
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-26T12:13:05Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T12:13:31Z
user: login: shige
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-26T12:13:47Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T12:15:05Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

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

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

`479-487`: _⚠️ Potential issue_

**Potential MIME-type / content-type mismatch for HTML files**

`getFileContents` returns the raw `Uint8Array` for `"webPage"` without transformation.  
When the upstream model provider receives a `FilePart` tagged `mimeType: "text/html"`, but the body is a binary blob (including markup & potential scripts), it may:

1. Reject the request.  
2. Count the entire byte size toward the token limit (very expensive).  
3. Accurately parse it, but leak unintended tags / scripts into the prompt.

Before returning, you may want to:

* Strip HTML tags (e.g., with `cheerio` or a simple DOM parser).  
* Or convert to plain text Markdown.  
* Or, if binary blobs are intended, set an explicit `mimeType` such as `application/octet-stream`.

Failing to normalise may lead to unpredictable prompt behaviour or an inflated token count.

---

`166-175`: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Consider treating `webPage` files as human-readable text instead of opaque attachments**

`webPage` is grouped with `image`/`pdf` and is therefore replaced by a generic “N-th attached files” placeholder.  
For most HTML / Markdown pages, the textual content is actually the most valuable context for an LLM, while the binary representation is often noisy and token-hungry.  Storing it as an attachment means the model never “sees” the page contents unless it has file-preview capabilities (which many providers don’t).

If the intent is to let the LLM read the page, mirror the logic used for the `"text"` branch:

```diff
-       case "image":
-       case "pdf":
-       case "webPage": {
+       case "image":
+       case "pdf": {
            …
         }
+       case "webPage": {
+           const fileContents = await getFileContents(
+               contextNode.content,
+               fileResolver,
+           );
+           userMessage = userMessage.replace(
+               replaceKeyword,
+               fileContents
+                   .map((fc) =>
+                       fc.type === "file" && fc.data instanceof Uint8Array
+                           ? new TextDecoder().decode(fc.data)
+                           : "",
+                   )
+                   .join("\n"),
+           );
+           break;
+       }
```

At minimum, document why the current behaviour is desired so that future maintainers don’t assume it’s an oversight.

---

🏁 Script executed:

```shell
#!/bin/bash
# Locate and inspect file handling logic in utils.ts
UTILS_PATH=$(fd utils.ts -t f | grep "packages/giselle-engine/src/core/generations/utils.ts" || true)
echo "utils.ts path: $UTILS_PATH"

# Show lines around the file-type switch (lines 140–200)
if [ -n "$UTILS_PATH" ]; then
  echo "----- utils.ts (lines 140–200) -----"
  sed -n '140,200p' "$UTILS_PATH"
fi

# Show the 'text' branch for comparison
echo "----- 'text' case in utils.ts -----"
rg -n 'case "text"' "$UTILS_PATH" --context 5
```

Length of output: 4033

---

🏁 Script executed:

```shell
#!/bin/bash
# Search for getFileContents implementation
echo "Searching for getFileContents definition..."
rg -n "function getFileContents" -t ts || rg -n "getFileContents\s*=" -t ts

# Search for FileContent type/interface
echo "Searching for FileContent interface/type..."
rg -n "interface FileContent" -t ts || rg -n "type FileContent" -t ts
```

Length of output: 466

---

🏁 Script executed:

```shell
#!/bin/bash
# Display FileContent interface definition and surrounding context
FILE_TYPES_PATH=$(fd types.ts -t f | grep "apps/studio.giselles.ai/packages/types.ts" || true)
echo "types.ts path: $FILE_TYPES_PATH"
if [ -n "$FILE_TYPES_PATH" ]; then
  echo "----- FileContent interface (lines 80–140) -----"
  sed -n '80,140p' "$FILE_TYPES_PATH"
fi
```

Length of output: 1776

---

🏁 Script executed:

```shell
#!/bin/bash
# Locate and inspect getFilesDescription definition and usage
rg -n "getFilesDescription" -t ts packages/giselle-engine/src/core/generations/utils.ts --context 10
```

Length of output: 2133

---

🏁 Script executed:

```shell
#!/bin/bash
# Display implementation of getFileContents
sed -n '440,550p' packages/giselle-engine/src/core/generations/utils.ts
```

Length of output: 2982

---

🏁 Script executed:

```shell
#!/bin/bash
# Display imports at the top of utils.ts to see DataContent and FilePart/ImagePart definitions
echo "----- utils.ts imports (lines 1–50) -----"
sed -n '1,50p' packages/giselle-engine/src/core/generations/utils.ts

# Search for where DataContent is defined or imported across the repo
echo "----- DataContent references -----"
rg -n "DataContent" -t ts
```

Length of output: 7492

---



</details>

**Handle `webPage` attachments as inline text or document the rationale**

In `packages/giselle-engine/src/core/generations/utils.ts`, the two `switch` blocks that currently treat `"webPage"` like `"pdf"`/`"image"` only inject a generic placeholder and push the raw FilePart to `attachedFiles`. If your intent is to make page contents visible to the LLM, mirror the `"text"` branch’s decoding logic; otherwise, add a comment explaining why HTML pages are excluded from inline parsing.

Locations to update:
- Around lines 164–182 in the first `switch (contextNode.content.category)` block  
- Around lines 592–611 in the second `switch (contextNode.content.category)` block  

Proposed diff (apply to both blocks):
```diff
-       case "image":
-       case "pdf":
-       case "webPage": {
+       case "image":
+       case "pdf": {
            …
            break;
+       }
+       case "webPage": {
+           const fileContents = await getFileContents(
+               contextNode.content,
+               fileResolver,
+           );
+           userMessage = userMessage.replace(
+               replaceKeyword,
+               fileContents
+                   .map((fc) => {
+                       if (fc.type !== "file" || !(fc.data instanceof Uint8Array)) {
+                           return null;
+                       }
+                       const text = new TextDecoder().decode(fc.data);
+                       return `<File name=${fc.filename}>${text}</File>`;
+                   })
+                   .filter((line): line is string => line !== null)
+                   .join("\n"),
+           );
+           break;
+       }
```

If you choose to keep the current behavior, please add a comment above each `case "webPage"` block explaining why web pages remain opaque attachments.

</blockquote></details>

</blockquote></details>

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

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

`592-596`: **Duplicate switch-case lists hint at rising maintenance cost**

`"pdf"` and `"webPage"` now appear in three separate `switch` statements in this file.  
Every future file-category addition will require edits in multiple places, increasing the chance of an omission.

A small refactor could eliminate the duplication:

```ts
const TEXT_LIKE: FileCategory[] = ["text"];
const ATTACHMENT_LIKE: FileCategory[] = ["image", "pdf", "webPage"];

if (TEXT_LIKE.includes(contextNode.content.category)) { … }
else if (ATTACHMENT_LIKE.includes(contextNode.content.category)) { … }
```

This keeps business rules explicit while reducing repetition.

</blockquote></details>
<details>
<summary>internal-packages/workflow-designer-ui/src/editor/properties-panel/file-node-properties-panel/index.tsx (1)</summary><blockquote>

`25-28`: **MIME-type overlap may confuse end-users**

Both `"text"` and `"webPage"` now accept `"text/markdown"`.  
If a user uploads a Markdown file, it’s ambiguous which category should be chosen, potentially leading to inconsistent behaviour between the toolbar (feature-flag-gated) and the properties panel (always enabled).

Verify that:

* The node creation UI cannot create a `"webPage"` node while the feature flag is off.  
* The backend logic distinguishes between Markdown intended as “plain text” versus “web page”.

Consider narrowing the `"webPage"` accept list to just `"text/html"` unless Markdown is a deliberate requirement.

</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 d12b771cf02fb6a8971c0fa271d6800e767d43e5 and 8b2d28dc540ed61ee39ff31acdf81c3900bdbe77.

</details>

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

* `internal-packages/workflow-designer-ui/src/editor/properties-panel/file-node-properties-panel/index.tsx` (1 hunks)
* `internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx` (3 hunks)
* `internal-packages/workflow-designer-ui/src/icons/content-type-icon.tsx` (2 hunks)
* `internal-packages/workflow-designer-ui/src/icons/node/file-node.tsx` (2 hunks)
* `internal-packages/workflow-designer-ui/src/icons/node/index.tsx` (2 hunks)
* `packages/giselle-engine/src/core/generations/utils.ts` (3 hunks)

</details>

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

<details>
<summary>🧠 Learnings (1)</summary>

<details>
<summary>📓 Common learnings</summary>

```
Learnt from: shige
PR: giselles-ai/giselle#958
File: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx:87-88
Timestamp: 2025-05-26T12:15:04.431Z
Learning: In feature flag implementations, flag functions are typically named with "Flag" suffix (e.g., `webPageFileNodeFlag`), while the resolved boolean values that flow through context use the base name without "Flag" suffix (e.g., `webPageFileNode`). This is a valid naming convention where the function and its resolved value have different but related names.
```

</details>

</details>

</details>

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

* GitHub Check: check

</details>

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

<details>
<summary>internal-packages/workflow-designer-ui/src/icons/node/file-node.tsx (1)</summary>

`21-23`: **Nice, exhaustive handling of the new `webPage` category**

The new icon is wired into the switch with type-safety preserved.  
No concerns here.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/icons/content-type-icon.tsx (1)</summary>

`21-21`: **LGTM! Consistent implementation following established patterns.**

The import and switch case addition for "webPage" correctly follows the same pattern used for other file categories. The exhaustive type checking ensures all FileCategory values are handled.




Also applies to: 113-114

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/icons/node/index.tsx (1)</summary>

`18-18`: **LGTM! Proper implementation consistent with existing file categories.**

The import and switch case for "webPage" correctly follow the established pattern, including the `data-content-type-icon` attribute used by other file categories.




Also applies to: 127-128

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx (3)</summary>

`55-55`: **LGTM! Proper import addition.**

The `WebPageFileIcon` import is correctly added to the existing import list.

---

`87-87`: **LGTM! Feature flag usage follows established naming convention.**

The destructuring of `webPageFileNode` from `useFeatureFlag()` is consistent with the learned pattern where flag functions use "Flag" suffix but resolved values use the base name.

---

`934-939`: **LGTM! Feature-gated toggle implementation follows established patterns.**

The conditional rendering properly gates the Web Page toggle behind the `webPageFileNode` feature flag. The implementation follows the same pattern as other file category toggles, with correct icon, label, and value that matches the FileCategory enum.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T12:21:07Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

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

<details>
<summary>internal-packages/workflow-designer-ui/src/editor/properties-panel/file-node-properties-panel/index.tsx (1)</summary><blockquote>

`25-28`: **Good configuration for web page file type.**

The `webPage` configuration appropriately supports HTML and Markdown content with clear labeling. The MIME types `"text/html"` and `"text/markdown"` are well-suited for web page content.

Consider whether a `maxSize` limit should be specified for web page files, similar to the image configuration, to prevent potential issues with extremely large files.

</blockquote></details>
<details>
<summary>internal-packages/workflow-designer-ui/src/icons/node/index.tsx (1)</summary><blockquote>

`18-18`: **Consider deduplicating the ever-growing icon switch**

The new `webPage` case works, but both the import list and the nested `switch` now have 15-plus entries.  
As this list keeps expanding, maintenance and merge conflicts will get harder.

A light refactor could replace the `switch` with a simple map:

```tsx diff
- case "file":
-   switch (node.content.category) {
-     case "pdf":      return <PdfFileIcon … />
-     case "text":     return <TextFileIcon … />
-     case "image":    return <PictureIcon … />
-     case "webPage":  return <WebPageFileIcon … />
-   }
+ case "file": {
+   const iconByCategory: Record<FileCategory, JSX.Element> = {
+     pdf:      <PdfFileIcon … />,
+     text:     <TextFileIcon … />,
+     image:    <PictureIcon … />,
+     webPage:  <WebPageFileIcon … />,
+   };
+   return iconByCategory[node.content.category];
+ }
```

Benefits: fewer lines, no exhaustiveness boiler-plate, and adding future categories is a one-liner.



Also applies to: 127-129

</blockquote></details>
<details>
<summary>internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx (1)</summary><blockquote>

`934-938`: **Avoid hard-coding enum literals to prevent future drift**

`ToggleGroup.Item` uses the string `"webPage"` directly:

```tsx
<ToggleGroup.Item value="webPage" …>
```

Just like the earlier `"pdf" | "image" | "text"` literals, this works today, but
it couples UI code to the exact casing of `FileCategory`.

A safer, self-documenting pattern is to reuse the enum values:

```tsx diff
- <ToggleGroup.Item value="webPage" data-tool>
+ <ToggleGroup.Item value={FileCategory.Values.webPage} data-tool>
```

(…and similarly for the other three literals.)

This eliminates a whole class of runtime enum-parse crashes if the canonical
name ever changes.

</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 68083935c00438ad1d1a409bf0f8dbd506f4bc2a and 8b2d28dc540ed61ee39ff31acdf81c3900bdbe77.

</details>

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

* `apps/playground/app/workspaces/[workspaceId]/layout.tsx` (1 hunks)
* `apps/studio.giselles.ai/app/workspaces/[workspaceId]/layout.tsx` (3 hunks)
* `apps/studio.giselles.ai/flags.ts` (1 hunks)
* `internal-packages/workflow-designer-ui/src/editor/properties-panel/file-node-properties-panel/index.tsx` (1 hunks)
* `internal-packages/workflow-designer-ui/src/editor/tool/toolbar/components/icons.tsx` (1 hunks)
* `internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx` (3 hunks)
* `internal-packages/workflow-designer-ui/src/icons/content-type-icon.tsx` (2 hunks)
* `internal-packages/workflow-designer-ui/src/icons/index.ts` (1 hunks)
* `internal-packages/workflow-designer-ui/src/icons/node/file-node.tsx` (2 hunks)
* `internal-packages/workflow-designer-ui/src/icons/node/index.tsx` (2 hunks)
* `internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx` (1 hunks)
* `packages/data-type/src/node/variables/file.ts` (1 hunks)
* `packages/giselle-engine/src/core/generations/utils.ts` (3 hunks)
* `packages/workspace/src/react/feature-flag.ts` (1 hunks)
* `packages/workspace/src/react/workspace.tsx` (1 hunks)

</details>

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

<details>
<summary>🧠 Learnings (2)</summary>

<details>
<summary>📓 Common learnings</summary>

```
Learnt from: shige
PR: giselles-ai/giselle#958
File: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx:87-88
Timestamp: 2025-05-26T12:15:04.431Z
Learning: In feature flag implementations, flag functions are typically named with "Flag" suffix (e.g., `webPageFileNodeFlag`), while the resolved boolean values that flow through context use the base name without "Flag" suffix (e.g., `webPageFileNode`). This is a valid naming convention where the function and its resolved value have different but related names.
```

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

```
Learnt from: shige
PR: giselles-ai/giselle#958
File: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx:87-88
Timestamp: 2025-05-26T12:15:04.431Z
Learning: In feature flag implementations, flag functions are typically named with "Flag" suffix (e.g., `webPageFileNodeFlag`), while the resolved boolean values that flow through context use the base name without "Flag" suffix (e.g., `webPageFileNode`). This is a valid naming convention where the function and its resolved value have different but related names.
```

</details>

</details>

</details>

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

<details>
<summary>apps/playground/app/workspaces/[workspaceId]/layout.tsx (1)</summary>

`19-19`: **LGTM: Feature flag addition follows playground pattern.**

The hardcoded `true` value is appropriate for the playground environment, consistent with how `flowNode` and `runV2` are handled. This enables testing of the web page file node feature in the playground environment.

</details>
<details>
<summary>apps/studio.giselles.ai/app/workspaces/[workspaceId]/layout.tsx (3)</summary>

`2-2`: **LGTM: Proper feature flag import.**

The import follows the established naming convention where the flag function uses the "Flag" suffix (`webPageFileNodeFlag`).

---

`38-38`: **LGTM: Consistent flag fetching pattern.**

The async flag fetching follows the same pattern as existing flags (`flowNode` and `runV2`), maintaining consistency in the codebase.

---

`63-63`: **LGTM: Proper feature flag integration.**

The resolved boolean value correctly uses the base name `webPageFileNode` (without "Flag" suffix) as established in the naming convention, and is properly integrated into the feature flag object.

</details>
<details>
<summary>packages/workspace/src/react/feature-flag.ts (1)</summary>

`6-6`: **LGTM: Proper interface extension.**

The addition of `webPageFileNode: boolean` correctly extends the feature flag context interface, maintaining type safety and following the established pattern of other feature flags.

</details>
<details>
<summary>packages/workspace/src/react/workspace.tsx (1)</summary>

`65-65`: **LGTM: Proper context value integration.**

The feature flag is correctly integrated into the context value with appropriate null coalescing fallback to `false`, maintaining consistency with the existing `flowNode` and `runV2` flags.

</details>
<details>
<summary>packages/data-type/src/node/variables/file.ts (1)</summary>

`79-79`: **LGTM! Clean enum extension for web page support.**

The addition of "webPage" to the `FileCategory` enum is correctly implemented and follows the established pattern. This additive change supports the new feature without breaking existing functionality.

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

`120-131`: **Excellent implementation following established patterns.**

The `webPageFileNodeFlag` implementation is consistent with existing feature flags in the codebase. The naming convention, structure, and configuration all follow the established patterns correctly. The use of `takeLocalEnv` with the appropriate environment variable key is proper.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx (1)</summary>

`1-23`: **Excellent icon component implementation.**

The `WebPageFileIcon` component is well-implemented with:
- Proper TypeScript typing
- Good accessibility attributes (`role="img"` and `aria-label`)
- Correct prop spreading for customization
- Appropriate SVG design representing a web page layout

The implementation follows React best practices and maintains consistency with the existing icon component patterns.

</details>
<details>
<summary>packages/giselle-engine/src/core/generations/utils.ts (3)</summary>

`166-167`: **Good implementation following established patterns.**

The addition of "webPage" case alongside "pdf" is consistent and appropriate, as both are text-based content types that can be processed similarly in generation messages.

---

`481-481`: **Consistent file content handling.**

The "webPage" case correctly returns a `FilePart` similar to "text" and "pdf" categories, maintaining consistency in the file processing logic.

---

`594-595`: <details>
<summary>✅ Verification successful</summary>

**Verify FileCategory type definition includes "webPage".**

The implementation correctly handles "webPage" in the image generation message building. Ensure that the `FileCategory` type definition has been updated to include "webPage" to maintain type safety.



---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Verify that FileCategory type includes "webPage"
# Expected: Should find "webPage" in the FileCategory enum/type definition

ast-grep --pattern 'export $_ FileCategory = {
  $$$
}'

# Also search for enum definitions
ast-grep --pattern 'enum FileCategory {
  $$$
}'

# Search with ripgrep as backup
rg -A 10 "FileCategory.*=" --type typescript
```

Length of output: 190

---

I couldn’t locate the `FileCategory` definition with the previous patterns. Let’s search more broadly across all `.ts` files to pinpoint its declaration and verify whether `"webPage"` is included:

---

🏁 Script executed:

```shell
#!/bin/bash
# 1. Look specifically for a type alias named FileCategory
rg -n "export type FileCategory" -g "*.ts" || true

# 2. Look for an enum named FileCategory as a fallback
rg -n "enum FileCategory" -g "*.ts" || true

# 3. Show all occurrences of FileCategory with a few lines of context
rg -n "FileCategory" -g "*.ts" -C3 || true
```

Length of output: 2246

---



</details>

**Confirmed: FileCategory includes “webPage”**

The `FileCategory` z.enum in `packages/data-type/src/node/variables/file.ts` already lists `"webPage"` alongside the other categories, so the type definition is up to date and no further changes are needed.

• packages/data-type/src/node/variables/file.ts:79 – `export const FileCategory = z.enum(["pdf", "text", "image", "webPage"]);`

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/icons/index.ts (1)</summary>

`47-47`: **LGTM! Clean addition following established patterns.**

The export follows the same pattern as other icon modules in the file.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/editor/tool/toolbar/components/icons.tsx (1)</summary>

`22-22`: **Clean export addition maintaining good organization.**

The WebPageFileIcon is properly added to the export list, maintaining the alphabetical organization of the exports.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/icons/node/file-node.tsx (2)</summary>

`6-6`: **Proper import following established patterns.**

The import statement correctly follows the relative path pattern used by other icon imports in this file.

---

`21-22`: <details>
<summary>✅ Verification successful</summary>

**Excellent implementation following established patterns.**

The "webPage" case follows the exact same pattern as other file types, properly spreading props to the WebPageFileIcon component. The exhaustive type checking ensures type safety when new file categories are added.



---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Verify WebPageFileIcon component exists and is properly implemented
# Expected: Should find the WebPageFileIcon component definition

fd "web-page-file.tsx" --type f --exec cat {}

# Also verify it's a valid React component
ast-grep --pattern 'export function WebPageFileIcon($_) {
  $$$
}'
```

Length of output: 670

---



</details>

**Verification complete: WebPageFileIcon implementation is correct**

- Confirmed `WebPageFileIcon` is defined in `internal-packages/workflow-designer-ui/src/icons/node/web-page-file.tsx` as an `FC<SVGProps<SVGSVGElement>>` that spreads `props` onto the `<svg>`.
- The `case "webPage": return <WebPageFileIcon {...props} />;` in `file-node.tsx` matches the established pattern for other file types.
- No breaking changes detected; props and type safety are maintained.

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/icons/content-type-icon.tsx (1)</summary>

`21-21`: **Support for `webPage` category is wired correctly – just double-check re-exports**

The new `WebPageFileIcon` import and the additional `"webPage"` branch in the `file`-category switch look consistent with the existing pattern (PDF, text, image).  
Nothing else is required here, provided that `WebPageFileIcon` is:

1. exported from `internal-packages/workflow-designer-ui/src/icons/index.ts`, and  
2. included in any barrel exports that downstream packages rely on.

If either export is forgotten, consumers doing `import { WebPageFileIcon } from "@giselle-sdk/icons"` may break at compile time.




Also applies to: 113-115

</details>
<details>
<summary>internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx (1)</summary>

`87-88`: **Feature-flag wiring looks correct**

`webPageFileNode` is pulled from `useFeatureFlag()` in line with the established
“function ends with `Flag`, resolved boolean drops the suffix” convention recorded earlier.  
👍 No action needed.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T12:23:52Z
user: login: toyamarinyon
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-27T04:11:57Z

Review comments:
diff_hunk: @@ -930,6 +931,12 @@ export function Toolbar() {
 													<TextFileIcon className="w-[20px] h-[20px]" />
 													<p className="text-[14px]">Text</p>
 												</ToggleGroup.Item>
+												{webPageFileNode && (
+													<ToggleGroup.Item value="webpage" data-tool>
+														<WebPageFileIcon className="w-[20px] h-[20px]" />
+														<p className="text-[14px]">Web Page</p>
+													</ToggleGroup.Item>
+												)}
path: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Enum value / casing mismatch may crash `FileCategory.parse`**

`ToggleGroup.Item` passes `"webpage"`:

```tsx
<ToggleGroup.Item value="webpage" …>
```

Later, the callback runs:

```ts
fileNode(FileCategory.parse(fileCategory))
```

If the newly-added enum literal was declared as `"webPage"` (camel-case, as hinted in the PR summary), `zod` will throw and break the toolbar on selection.

```diff
- <ToggleGroup.Item value="webpage" data-tool>
+ <ToggleGroup.Item value="webPage" data-tool>
```

or (safer, avoids hard-coding):

```diff
- <ToggleGroup.Item value="webpage" data-tool>
+ <ToggleGroup.Item value={FileCategory.Values.webPage} data-tool>
```

Please align the string literal with the actual `FileCategory` value to prevent run-time exceptions.

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

```
In internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
around lines 934 to 939, the value passed to ToggleGroup.Item is "webpage",
which may not match the actual FileCategory enum value if it is defined as
"webPage" or another casing. This mismatch can cause FileCategory.parse to throw
an error at runtime. Fix this by aligning the string literal with the exact enum
value defined in FileCategory, either by using the enum directly or ensuring the
string matches the enum's casing to prevent runtime exceptions.
```

</details>

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

✅ Addressed in commits 030043f to 8b2d28d

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-26T09:00:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -83,7 +84,7 @@ export function Toolbar() {
 	const [selectedCategory, setSelectedCategory] = useState<string>("All");
 	const { llmProviders } = useWorkflowDesigner();
 	const limits = useUsageLimits();
-	const { flowNode } = useFeatureFlag();
+	const { flowNode, webPageFileNode } = useFeatureFlag();
 	const languageModelAvailable = (languageModel: LanguageModel) => {
path: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Feature-flag name likely mismatched with back-end definition**

`useFeatureFlag()` is destructured as:

```ts
const { flowNode, webPageFileNode } = useFeatureFlag();
```

The PR description says the flag is called **`webPageFileNodeFlag`**.  
If the flag service really exposes `webPageFileNodeFlag`, this destructure will return `undefined`, so the Web Page option in the UI will never appear.

```diff
- const { flowNode, webPageFileNode } = useFeatureFlag();
+ const { flowNode, webPageFileNodeFlag: webPageFileNode } = useFeatureFlag();
```

Please confirm the canonical flag key in the flags registry and align the name here (or in the registry) to avoid a silent feature toggle failure.

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

```
In internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
around lines 87 to 88, the destructuring of useFeatureFlag() assigns flowNode
and webPageFileNode, but the PR indicates the actual feature flag is named
webPageFileNodeFlag. If the flag service uses webPageFileNodeFlag, the current
destructure will result in undefined values, causing the Web Page option to not
appear. Confirm the exact flag key in the registry and update the destructure to
match that name, ensuring the feature toggle works as intended.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-26T09:00:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -930,6 +931,12 @@ export function Toolbar() {
 													<TextFileIcon className="w-[20px] h-[20px]" />
 													<p className="text-[14px]">Text</p>
 												</ToggleGroup.Item>
+												{webPageFileNode && (
+													<ToggleGroup.Item value="webpage" data-tool>
+														<WebPageFileIcon className="w-[20px] h-[20px]" />
+														<p className="text-[14px]">Web Page</p>
+													</ToggleGroup.Item>
+												)}
path: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
user: login: shige
body: fixed: 8b2d28dc540ed61ee39ff31acdf81c3900bdbe77
created_at: 2025-05-26T12:13:05Z
author_association: MEMBER
diff_hunk: @@ -930,6 +931,12 @@ export function Toolbar() {
 													<TextFileIcon className="w-[20px] h-[20px]" />
 													<p className="text-[14px]">Text</p>
 												</ToggleGroup.Item>
+												{webPageFileNode && (
+													<ToggleGroup.Item value="webpage" data-tool>
+														<WebPageFileIcon className="w-[20px] h-[20px]" />
+														<p className="text-[14px]">Web Page</p>
+													</ToggleGroup.Item>
+												)}
path: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
user: login: coderabbitai[bot]
body: @shige Thank you for the quick fix! 🎉 The enum value mismatch issue has been resolved with that commit. The FileCategory.parse should now work correctly without throwing runtime exceptions when the Web Page option is selected from the toolbar.


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

<!-- <rawResChunk><answer>@shige Thank you for the quick fix! 🎉 The enum value mismatch issue has been resolved with that commit. The FileCategory.parse should now work correctly without throwing runtime exceptions when the Web Page option is selected from the toolbar.</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-26T12:13:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -83,7 +84,7 @@ export function Toolbar() {
 	const [selectedCategory, setSelectedCategory] = useState<string>("All");
 	const { llmProviders } = useWorkflowDesigner();
 	const limits = useUsageLimits();
-	const { flowNode } = useFeatureFlag();
+	const { flowNode, webPageFileNode } = useFeatureFlag();
 	const languageModelAvailable = (languageModel: LanguageModel) => {
path: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
user: login: shige
body: There is nothing wrong with this comment.
created_at: 2025-05-26T12:13:47Z
author_association: MEMBER
diff_hunk: @@ -83,7 +84,7 @@ export function Toolbar() {
 	const [selectedCategory, setSelectedCategory] = useState<string>("All");
 	const { llmProviders } = useWorkflowDesigner();
 	const limits = useUsageLimits();
-	const { flowNode } = useFeatureFlag();
+	const { flowNode, webPageFileNode } = useFeatureFlag();
 	const languageModelAvailable = (languageModel: LanguageModel) => {
path: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

@shige Thanks for confirming the comment is valid. Let me investigate the feature flag naming to verify if there's indeed a mismatch that could cause the Web Page option to not appear.

---

🏁 Script executed:
```
#!/bin/bash
# Check the actual flag definition in flags.ts
echo "=== Flag definition in flags.ts ==="
rg -A 5 -B 2 "webPageFileNodeFlag" apps/studio.giselles.ai/flags.ts

echo -e "\n=== Feature flag context interface ==="
rg -A 3 -B 2 "webPageFileNode" packages/workspace/src/react/feature-flag.ts

echo -e "\n=== How the flag is passed to context in workspace.tsx ==="
rg -A 2 -B 2 "webPageFileNode" packages/workspace/src/react/workspace.tsx

echo -e "\n=== How the flag is fetched in layout.tsx ==="
rg -A 3 -B 3 "webPageFileNodeFlag\|webPageFileNode" apps/studio.giselles.ai/app/workspaces/\[workspaceId\]/layout.tsx

echo -e "\n=== How the flag is used in toolbar.tsx ==="
rg -A 2 -B 2 "webPageFileNode" internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
```

Length of output: 1975

---

🏁 Script executed:
```
#!/bin/bash
# Let's check the layout.tsx file more specifically to see how the flag is imported and used
echo "=== Complete layout.tsx content around flag usage ==="
rg -A 10 -B 5 "webPage" apps/studio.giselles.ai/app/workspaces/\[workspaceId\]/layout.tsx

echo -e "\n=== Check imports in layout.tsx ==="
rg -A 5 "from.*flags" apps/studio.giselles.ai/app/workspaces/\[workspaceId\]/layout.tsx

echo -e "\n=== Check if there's a FeatureFlag type definition ==="
rg -A 5 -B 5 "FeatureFlag.*=" packages/workspace/src/react/workspace.tsx

echo -e "\n=== Check what gets passed as featureFlag prop ==="
rg -A 8 -B 3 "featureFlag.*:" apps/studio.giselles.ai/app/workspaces/\[workspaceId\]/layout.tsx
```

Length of output: 2377

---



</details>

After investigating the complete data flow, I can confirm that **the code is actually correct** and the CodeRabbit comment was a false positive.

Here's the proper data flow:

1. **Flag definition**: `webPageFileNodeFlag` (function) in `flags.ts`
2. **Layout.tsx**: `const webPageFileNode = await webPageFileNodeFlag();` (resolves to boolean)
3. **Context**: `webPageFileNode: featureFlag?.webPageFileNode ?? false` (maps boolean)
4. **Toolbar**: `const { webPageFileNode } = useFeatureFlag();` (destructures boolean)

The naming convention is consistent:
- `webPageFileNodeFlag` = the flag function/definition
- `webPageFileNode` = the resolved boolean value that flows through the system

The feature should work correctly as implemented. The flag function returns a boolean that gets properly passed through the context to the UI component.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

<no_relevant_code_snippets>

</details>



---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: shige
PR: giselles-ai/giselle#958
File: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx:87-88
Timestamp: 2025-05-26T12:15:04.431Z
Learning: In feature flag implementations, flag functions are typically named with "Flag" suffix (e.g., `webPageFileNodeFlag`), while the resolved boolean values that flow through context use the base name without "Flag" suffix (e.g., `webPageFileNode`). This is a valid naming convention where the function and its resolved value have different but related names.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>


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

<!-- <rawResChunk><answer><details>
<summary>🧩 Analysis chain</summary>

@shige Thanks for confirming the comment is valid. Let me investigate the feature flag naming to verify if there's indeed a mismatch that could cause the Web Page option to not appear.

---

🏁 Script executed:
```
#!/bin/bash
# Check the actual flag definition in flags.ts
echo "=== Flag definition in flags.ts ==="
rg -A 5 -B 2 "webPageFileNodeFlag" apps/studio.giselles.ai/flags.ts

echo -e "\n=== Feature flag context interface ==="
rg -A 3 -B 2 "webPageFileNode" packages/workspace/src/react/feature-flag.ts

echo -e "\n=== How the flag is passed to context in workspace.tsx ==="
rg -A 2 -B 2 "webPageFileNode" packages/workspace/src/react/workspace.tsx

echo -e "\n=== How the flag is fetched in layout.tsx ==="
rg -A 3 -B 3 "webPageFileNodeFlag\|webPageFileNode" apps/studio.giselles.ai/app/workspaces/\[workspaceId\]/layout.tsx

echo -e "\n=== How the flag is used in toolbar.tsx ==="
rg -A 2 -B 2 "webPageFileNode" internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx
```

Length of output: 1975

---

🏁 Script executed:
```
#!/bin/bash
# Let's check the layout.tsx file more specifically to see how the flag is imported and used
echo "=== Complete layout.tsx content around flag usage ==="
rg -A 10 -B 5 "webPage" apps/studio.giselles.ai/app/workspaces/\[workspaceId\]/layout.tsx

echo -e "\n=== Check imports in layout.tsx ==="
rg -A 5 "from.*flags" apps/studio.giselles.ai/app/workspaces/\[workspaceId\]/layout.tsx

echo -e "\n=== Check if there's a FeatureFlag type definition ==="
rg -A 5 -B 5 "FeatureFlag.*=" packages/workspace/src/react/workspace.tsx

echo -e "\n=== Check what gets passed as featureFlag prop ==="
rg -A 8 -B 3 "featureFlag.*:" apps/studio.giselles.ai/app/workspaces/\[workspaceId\]/layout.tsx
```

Length of output: 2377

---



</details>

After investigating the complete data flow, I can confirm that **the code is actually correct** and the CodeRabbit comment was a false positive.

Here's the proper data flow:

1. **Flag definition**: `webPageFileNodeFlag` (function) in `flags.ts`
2. **Layout.tsx**: `const webPageFileNode = await webPageFileNodeFlag();` (resolves to boolean)
3. **Context**: `webPageFileNode: featureFlag?.webPageFileNode ?? false` (maps boolean)
4. **Toolbar**: `const { webPageFileNode } = useFeatureFlag();` (destructures boolean)

The naming convention is consistent:
- `webPageFileNodeFlag` = the flag function/definition
- `webPageFileNode` = the resolved boolean value that flows through the system

The feature should work correctly as implemented. The flag function returns a boolean that gets properly passed through the context to the UI component.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

<no_relevant_code_snippets>

</details>



---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: shige
PR: giselles-ai/giselle#958
File: internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx:87-88
Timestamp: 2025-05-26T12:15:04.431Z
Learning: In feature flag implementations, flag functions are typically named with "Flag" suffix (e.g., `webPageFileNodeFlag`), while the resolved boolean values that flow through context use the base name without "Flag" suffix (e.g., `webPageFileNode`). This is a valid naming convention where the function and its resolved value have different but related names.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

</answer></rawResChunk> -->

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

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-05-26T08:55:27Z
body: ###  ⚠️  No Changeset found

Latest commit: 8b2d28dc540ed61ee39ff31acdf81c3900bdbe77

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/show-web-page-file-node-in-toolbar-with-flag?filename=.changeset/swift-apples-search.md&value=---%0A%22%40fake-scope%2Ffake-pkg%22%3A%20patch%0A---%0A%0AShow%20the%20Web%20Page%20in%20the%20toolbar%20(with%20feature%20flag)%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-26T08:55:36Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

A new feature flag `webPageFileNode` is added across multiple packages to support conditional rendering and categorization of web page file nodes. The update propagates this flag through feature flag systems, context definitions, UI components, icon exports, and enum extensions, all in an additive manner without affecting existing logic.

## Changes

| File(s) / Path(s)                                                                                   | Change Summary                                                                                                  |
|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| apps/playground/app/workspaces/[workspaceId]/layout.tsx<br>apps/studio.giselles.ai/app/workspaces/[workspaceId]/layout.tsx | Added the `webPageFileNode` feature flag to the `WorkspaceProvider`'s feature flag configuration.               |
| apps/studio.giselles.ai/flags.ts                                                                    | Added `webPageFileNodeFlag` feature flag with environment-based logic and metadata.                             |
| internal-packages/workflow-designer-ui/src/editor/tool/toolbar/components/icons.tsx<br>internal-packages/workflow-designer-ui/src/icons/web-page-file.tsx<br>internal-packages/workflow-designer-ui/src/icons/index.ts | Added and exported new `WebPageFileIcon` for use in the UI toolbar and made it available in the icon index.     |
| internal-packages/workflow-designer-ui/src/editor/tool/toolbar/toolbar.tsx                          | Added a conditional toggle group item for "Web Page" in the file node toolbar, shown when the feature flag is enabled. |
| packages/data-type/src/node/variables/file.ts                                                       | Added "webPage" to the `FileCategory` enum to support categorizing files as web pages.                          |
| packages/workspace/src/react/feature-flag.ts                                                        | Added `webPageFileNode` property to the `FeatureFlagContextValue` interface.                                    |
| packages/workspace/src/react/workspace.tsx                                                          | Passed the `webPageFileNode` flag into the feature flag context in `WorkspaceProvider`.                         |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant Toolbar
    participant FeatureFlagContext
    participant WorkspaceProvider

    User->>Toolbar: Open file node type selection
    Toolbar->>FeatureFlagContext: Check webPageFileNode flag
    alt webPageFileNode enabled
        Toolbar->>User: Show "Web Page" option with icon
        User->>Toolbar: Select "Web Page"
        Toolbar->>WorkspaceProvider: Set file node category to "webPage"
    else webPageFileNode disabled
        Toolbar->>User: "Web Page" option not shown
    end
```

## Poem

> 🐇  
> A flag for web pages, now in the mix,  
> With icons and enums, we’re adding new tricks.  
> The toolbar shines bright with a webby new face,  
> Feature flags guide us, we hop at our pace.  
> Hooray for the code—let’s browse and explore,  
> With each little toggle, we open a door!  
> 🌐✨

<!-- 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=958):

- 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: vercel[bot]
created_at: 2025-05-26T09:10:43Z
body: [vc]: #05s+wScLSU3MKMHtxzeDP5lDoypPB0JaLSV5K3wU6DU=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJnaXNlbGxlIiwicm9vdERpcmVjdG9yeSI6ImFwcHMvc3R1ZGlvLmdpc2VsbGVzLmFpIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6Imdpc2VsbGUtZ2l0LXNob3ctd2ViLXBhZ2UtZmlsZS1ub2RlLWluLXRvb2xiYXItYjc4YjE5LXIwNi1lZGdlLnZlcmNlbC5hcHAifSwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3IwNi1lZGdlL2dpc2VsbGUvQmNMMXFLcjV0OXFaQ052M04zTlhTcWdzTWdkcSIsInByZXZpZXdVcmwiOiJnaXNlbGxlLWdpdC1zaG93LXdlYi1wYWdlLWZpbGUtbm9kZS1pbi10b29sYmFyLWI3OGIxOS1yMDYtZWRnZS52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIn0seyJuYW1lIjoiZ2lzZWxsZS1wbGF5Z3JvdW5kIiwicm9vdERpcmVjdG9yeSI6ImFwcHMvcGxheWdyb3VuZCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJnaXNlbGxlLXBsYXlncm91bmQtZ2l0LXNob3ctd2ViLXBhZ2UtZmlsZS1ub2RlLTRkZDgwNC1yMDYtZWRnZS52ZXJjZWwuYXBwIn0sImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9yMDYtZWRnZS9naXNlbGxlLXBsYXlncm91bmQvRlNmOEtpTnZZdTFyUXk3b0xrZHRCRUYzQVZSWCIsInByZXZpZXdVcmwiOiJnaXNlbGxlLXBsYXlncm91bmQtZ2l0LXNob3ctd2ViLXBhZ2UtZmlsZS1ub2RlLTRkZDgwNC1yMDYtZWRnZS52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIn1dfQ==
**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/BcL1qKr5t9qZCNv3N3NXSqgsMgdq)) | [Visit Preview](https://giselle-git-show-web-page-file-node-in-toolbar-b78b19-r06-edge.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/giselle-git-show-web-page-file-node-in-toolbar-b78b19-r06-edge.vercel.app?via=pr-comment-feedback-link) | May 26, 2025 0:16am |
| **giselle-playground** | ✅ Ready ([Inspect](https://vercel.com/r06-edge/giselle-playground/FSf8KiNvYu1rQy7oLkdtBEF3AVRX)) | [Visit Preview](https://giselle-playground-git-show-web-page-file-node-4dd804-r06-edge.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/giselle-playground-git-show-web-page-file-node-4dd804-r06-edge.vercel.app?via=pr-comment-feedback-link) | May 26, 2025 0:16am |



author_association: NONE
user: login: shige
created_at: 2025-05-26T12:19:17Z
body: @coderabbitai full review
author_association: MEMBER
user: login: coderabbitai[bot]
created_at: 2025-05-26T12:19:21Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
<details>
<summary>✅ Actions performed</summary>

Full review triggered.

</details>
author_association: CONTRIBUTOR
user: login: shige
created_at: 2025-05-26T12:25:48Z
body: @toyamarinyon Could you please review this pr when you have a moment?
author_association: MEMBER
user: login: shige
created_at: 2025-05-27T04:36:13Z
body: Thank you! 🚀 
author_association: MEMBER